Belle II Software development
copylists.py
1#!/usr/bin/env python3
2
3
10
11import unittest
12import uproot
13import basf2 as b2
14import b2test_utils as b2tu
15import modularAnalysis as ma
16from stdPi0s import stdPi0s
17from stdV0s import stdKshorts
18from variables import variables as vm
19
20
21def dump_3_v2nts(names_of_three_lists, path):
22 """Dump each of the three vpho lists into a VariablesToNtuple on path"""
23 first, second, third = names_of_three_lists
24 vs = ['d0_mdstIndex', 'd0_p']
25 ma.variablesToNtuple("vpho:" + first, vs, treename=first, path=path)
26 ma.variablesToNtuple("vpho:" + second, vs, treename=second, path=path)
27 ma.variablesToNtuple("vpho:" + third, vs, treename=third, path=path)
28
29
30def run_copylists():
31 """A simple basf2 analysis job to do some list copying"""
32
33 # aliases for useful for manual debugging
34 vm.addAlias("d0_mdstIndex", "daughter(0, mdstIndex)")
35 vm.addAlias("d0_p", "daughter(0, p)")
36
37 # analysis input
38 pa = b2.Path()
39 ma.inputMdst(b2.find_file("analysis/tests/mdst.root"), path=pa)
40 ma.fillParticleList("pi+", "", path=pa)
41 ma.fillParticleList("K+", "", path=pa)
42 stdPi0s('all', path=pa)
43 stdKshorts(path=pa)
44
45 # first test: check that merging two lists with
46 # identical daughters removes duplicates
47 ma.reconstructDecay("vpho:a -> K+", "", path=pa, allowChargeViolation=True)
48 ma.reconstructDecay("vpho:b -> K+", "", path=pa, allowChargeViolation=True)
49 ma.copyLists("vpho:ab", ["vpho:a", "vpho:b"], path=pa)
50 dump_3_v2nts(["a", "b", "ab"], path=pa)
51
52 # second test: check that two lists with different daughters (but from the
53 # same underlying mdst object) are included twice (as expected)
54 ma.reconstructDecay("vpho:c -> K+", "", path=pa, allowChargeViolation=True)
55 ma.reconstructDecay("vpho:d -> pi-", "", path=pa, allowChargeViolation=True)
56 ma.copyLists("vpho:cd", ["vpho:c", "vpho:d"], path=pa)
57 dump_3_v2nts(["c", "d", "cd"], path=pa)
58
59 # third test: check that two lists with the same daughters in different
60 # orders don't double count
61 # (they are different Belle2::Particles but we should match them)
62 ma.reconstructDecay("vpho:e -> K+ pi-", "", path=pa)
63 ma.reconstructDecay("vpho:f -> pi- K+", "", path=pa)
64 ma.copyLists("vpho:ef", ["vpho:e", "vpho:f"], path=pa)
65 dump_3_v2nts(["e", "f", "ef"], path=pa)
66
67 # fourth test: check that it is considered whose daughter a pi0 is when
68 # there are two charge-conjugated daughters
69 ma.reconstructDecay("tau+:pi -> pi+", "", dmID=0, path=pa)
70 ma.reconstructDecay("tau+:pipi0 -> pi+ pi0:all", "", dmID=1, path=pa)
71 # the pi0 is the daughter of the tau-
72 ma.reconstructDecay("vpho:g -> tau+:pi tau-:pipi0", "", path=pa, chargeConjugation=False)
73 # the pi0 is the daughter of the tau+
74 ma.reconstructDecay("vpho:h -> tau-:pi tau+:pipi0", "", path=pa, chargeConjugation=False)
75 # charge-conjugation has been turned off for the vpho lists above so the
76 # merged list should just be the sum
77 ma.copyLists("vpho:gh", ["vpho:g", "vpho:h"], path=pa)
78 dump_3_v2nts(["g", "h", "gh"], path=pa)
79
80 # fifth test: check that it is considered whose daughter self-conjugated
81 # particles are if there are two charge-conjugated daughters
82 ma.reconstructDecay("tau+:KS0 -> pi+ K_S0:merged", "", dmID=0, path=pa)
83 ma.reconstructDecay("tau+:pi0 -> pi+ pi0:all", "", dmID=1, path=pa)
84 # the pi0 is the daughter of the tau-
85 ma.reconstructDecay("vpho:KS -> tau+:KS0 tau-:pi0", "", path=pa, chargeConjugation=False)
86 # the pi0 is the daughter of the tau+
87 ma.reconstructDecay("vpho:pi0 -> tau-:KS0 tau+:pi0", "", path=pa, chargeConjugation=False)
88 # charge-conjugation has been turned off for the vpho lists above so the
89 # merged list should just be the sum
90 ma.copyLists("vpho:KSpi0", ["vpho:KS", "vpho:pi0"], path=pa)
91 dump_3_v2nts(["KS", "pi0", "KSpi0"], path=pa)
92
93 # sixth test: check that check of mother flavor can be turned off when identifying duplicates
94 ma.reconstructDecay("D0 -> K- pi+", "", dmID=0, chargeConjugation=False, path=pa)
95 ma.matchMCTruth("D0", path=pa)
96 ma.cutAndCopyList("D0:sig", "D0", "isSignal==1", path=pa)
97 ma.reconstructDecay("anti-D0:anti -> K- pi+", "", dmID=1, chargeConjugation=False, path=pa)
98 ma.matchMCTruth("anti-D0:anti", path=pa)
99 ma.cutAndCopyList("anti-D0:antisig", "anti-D0:anti", "isSignal==1", path=pa)
100 ma.mergeListsWithBestDuplicate("D0:ignore", ['D0', 'anti-D0:anti'], 'isSignal', path=pa,
101 preferLowest=False, ignoreMotherFlavor=True)
102 ma.copyLists("D0:flavor", ['D0', 'anti-D0:anti'], path=pa)
103 ma.variablesToNtuple("D0", ['isSignal', 'PDG'], treename="D0", path=pa)
104 ma.variablesToNtuple("anti-D0:anti", ['isSignal', 'PDG'], treename="anti", path=pa)
105 ma.variablesToNtuple("D0:ignore", ['isSignal', 'PDG'], treename="ignore", path=pa)
106 ma.variablesToNtuple("D0:flavor", ['isSignal', 'PDG'], treename="flavor", path=pa)
107
108 b2tu.safe_process(pa, 1)
109
110
111class TestCopyLists(unittest.TestCase):
112 """Analyse the output of ``run_copylists``"""
113
114 def _count(self, listname):
115 """Open the ntuple output and count the number of entries in the list."""
116 df = uproot.open("ntuple.root")[listname].arrays(library="pd")
117 return len(df)
118
120 """Merging two lists with identical daughters should not double count."""
121 self.assertEqual(self._count("a"), self._count("b"))
122 self.assertEqual(self._count("a"), self._count("ab"))
123 self.assertEqual(self._count("b"), self._count("ab"))
124
126 """Merging two lists with different daughters but with the same mdst
127 object should include each of them twice."""
128 self.assertEqual(self._count("c"), self._count("d"))
129 self.assertEqual(self._count("c") + self._count("d"), self._count("cd"))
130
132 """Merging two lists with daughters in a different order should not double count."""
133 self.assertEqual(self._count("e"), self._count("e"))
134 self.assertEqual(self._count("e"), self._count("ef"))
135
137 """Self-conjugated particles can be daughters of both charge-conjugated mother particles.
138 Those multiple candidates are no duplicates and copying the particle list should not remove them."""
139 self.assertEqual(self._count("g") + self._count("h"), self._count("gh"))
140
142 """Different self-conjugated particles are daughters of charge-conjugated mother particles.
143 The two mother particles have the same amount of daughters."""
144 self.assertEqual(self._count("KS") + self._count("pi0"), self._count("KSpi0"))
145
147 """Particle lists can be merged ignoring the flavor of the mother particle. If both particle
148 lists decay into the same final state, the size of the combined list is identical to one
149 individual list. Otherwise, it's the sum of the two."""
150 self.assertEqual(self._count("D0"), self._count("ignore"))
151 self.assertEqual(self._count("D0") + self._count("anti"), self._count("flavor"))
152
153
154if __name__ == "__main__":
155 with b2tu.clean_working_directory():
156 run_copylists()
157 unittest.main()
def test_different_association_of_neutrals_same_number_of_daughters(self)
Definition: copylists.py:141
def test_neutrals_in_decays_to_charge_conjugated_daughters(self)
Definition: copylists.py:136
def test_different_daughter_order(self)
Definition: copylists.py:131
def test_merge_two_lists_with_different_mdst_objects(self)
Definition: copylists.py:125
def _count(self, listname)
Definition: copylists.py:114
def test_merge_two_lists_with_identical_daughters(self)
Definition: copylists.py:119
def test_ignore_mother_flavor(self)
Definition: copylists.py:146