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 ma.fillParticleList("n0", "", path=pa)
45 ma.fillParticleList("anti-n0:2nd", "", path=pa)
46
47 # first test: check that merging two lists with
48 # identical daughters removes duplicates
49 ma.reconstructDecay("vpho:a -> K+", "", path=pa, allowChargeViolation=True)
50 ma.reconstructDecay("vpho:b -> K+", "", path=pa, allowChargeViolation=True)
51 ma.copyLists("vpho:ab", ["vpho:a", "vpho:b"], path=pa)
52 dump_3_v2nts(["a", "b", "ab"], path=pa)
53
54 # second test: check that two lists with different daughters (but from the
55 # same underlying mdst object) are included twice (as expected)
56 ma.reconstructDecay("vpho:c -> K+", "", path=pa, allowChargeViolation=True)
57 ma.reconstructDecay("vpho:d -> pi-", "", path=pa, allowChargeViolation=True)
58 ma.copyLists("vpho:cd", ["vpho:c", "vpho:d"], path=pa)
59 dump_3_v2nts(["c", "d", "cd"], path=pa)
60
61 # third test: check that two lists with the same daughters in different
62 # orders don't double count
63 # (they are different Belle2::Particles but we should match them)
64 ma.reconstructDecay("vpho:e -> K+ pi-", "", path=pa)
65 ma.reconstructDecay("vpho:f -> pi- K+", "", path=pa)
66 ma.copyLists("vpho:ef", ["vpho:e", "vpho:f"], path=pa)
67 dump_3_v2nts(["e", "f", "ef"], path=pa)
68
69 # fourth test: check that it is considered whose daughter a pi0 is when
70 # there are two charge-conjugated daughters
71 ma.reconstructDecay("tau+:pi -> pi+", "", dmID=0, path=pa)
72 ma.reconstructDecay("tau+:pipi0 -> pi+ pi0:all", "", dmID=1, path=pa)
73 # the pi0 is the daughter of the tau-
74 ma.reconstructDecay("vpho:g -> tau+:pi tau-:pipi0", "", path=pa, chargeConjugation=False)
75 # the pi0 is the daughter of the tau+
76 ma.reconstructDecay("vpho:h -> tau-:pi tau+:pipi0", "", path=pa, chargeConjugation=False)
77 # charge-conjugation has been turned off for the vpho lists above so the
78 # merged list should just be the sum
79 ma.copyLists("vpho:gh", ["vpho:g", "vpho:h"], path=pa)
80 dump_3_v2nts(["g", "h", "gh"], path=pa)
81
82 # fifth test: check that it is considered whose daughter self-conjugated
83 # particles are if there are two charge-conjugated daughters
84 ma.reconstructDecay("tau+:KS0 -> pi+ K_S0:merged", "", dmID=0, path=pa)
85 ma.reconstructDecay("tau+:pi0 -> pi+ pi0:all", "", dmID=1, path=pa)
86 # the pi0 is the daughter of the tau-
87 ma.reconstructDecay("vpho:KS -> tau+:KS0 tau-:pi0", "", path=pa, chargeConjugation=False)
88 # the pi0 is the daughter of the tau+
89 ma.reconstructDecay("vpho:pi0 -> tau-:KS0 tau+:pi0", "", path=pa, chargeConjugation=False)
90 # charge-conjugation has been turned off for the vpho lists above so the
91 # merged list should just be the sum
92 ma.copyLists("vpho:KSpi0", ["vpho:KS", "vpho:pi0"], path=pa)
93 dump_3_v2nts(["KS", "pi0", "KSpi0"], path=pa)
94
95 # sixth test: check that check of mother flavor can be turned off when identifying duplicates
96 ma.reconstructDecay("D0 -> K- pi+", "", dmID=0, chargeConjugation=False, path=pa)
97 ma.matchMCTruth("D0", path=pa)
98 ma.cutAndCopyList("D0:sig", "D0", "isSignal==1", path=pa)
99 ma.reconstructDecay("anti-D0:anti -> K- pi+", "", dmID=1, chargeConjugation=False, path=pa)
100 ma.matchMCTruth("anti-D0:anti", path=pa)
101 ma.cutAndCopyList("anti-D0:antisig", "anti-D0:anti", "isSignal==1", path=pa)
102 ma.mergeListsWithBestDuplicate("D0:ignore", ['D0', 'anti-D0:anti'], 'isSignal', path=pa,
103 preferLowest=False, ignoreMotherFlavor=True)
104 ma.copyLists("D0:flavor", ['D0', 'anti-D0:anti'], path=pa)
105 ma.variablesToNtuple("D0", ['isSignal', 'PDG'], treename="D0", path=pa)
106 ma.variablesToNtuple("anti-D0:anti", ['isSignal', 'PDG'], treename="anti", path=pa)
107 ma.variablesToNtuple("D0:ignore", ['isSignal', 'PDG'], treename="ignore", path=pa)
108 ma.variablesToNtuple("D0:flavor", ['isSignal', 'PDG'], treename="flavor", path=pa)
109
110 ma.reconstructDecay("vpho:n0 -> n0", "", path=pa)
111 ma.reconstructDecay("vpho:nbar -> anti-n0:2nd", "", path=pa)
112 ma.copyLists("vpho:allneutrons", ["vpho:n0", "vpho:nbar"], path=pa)
113 dump_3_v2nts(["n0", "nbar", "allneutrons"], path=pa)
114
115 b2tu.safe_process(pa, 1)
116
117
118class TestCopyLists(unittest.TestCase):
119 """Analyse the output of ``run_copylists``"""
120
121 def _count(self, listname):
122 """Open the ntuple output and count the number of entries in the list."""
123 df = uproot.open("ntuple.root")[listname].arrays(library="pd")
124 return len(df)
125
127 """Merging two lists with identical daughters should not double count."""
128 self.assertEqual(self._count("a"), self._count("b"))
129 self.assertEqual(self._count("a"), self._count("ab"))
130 self.assertEqual(self._count("b"), self._count("ab"))
131
133 """Merging two lists with different daughters but with the same mdst
134 object should include each of them twice."""
135 self.assertEqual(self._count("c"), self._count("d"))
136 self.assertEqual(self._count("c") + self._count("d"), self._count("cd"))
137
139 """Merging two lists with daughters in a different order should not double count."""
140 self.assertEqual(self._count("e"), self._count("e"))
141 self.assertEqual(self._count("e"), self._count("ef"))
142
144 """Self-conjugated particles can be daughters of both charge-conjugated mother particles.
145 Those multiple candidates are no duplicates and copying the particle list should not remove them."""
146 self.assertEqual(self._count("g") + self._count("h"), self._count("gh"))
147
149 """Different self-conjugated particles are daughters of charge-conjugated mother particles.
150 The two mother particles have the same amount of daughters."""
151 self.assertEqual(self._count("KS") + self._count("pi0"), self._count("KSpi0"))
152
154 """Particle lists can be merged ignoring the flavor of the mother particle. If both particle
155 lists decay into the same final state, the size of the combined list is identical to one
156 individual list. Otherwise, it's the sum of the two."""
157 self.assertEqual(self._count("D0"), self._count("ignore"))
158 self.assertEqual(self._count("D0") + self._count("anti"), self._count("flavor"))
159
160 def test_neutrons(self):
161 """Merging a neutron and anti-neutron list should keep only the candidates of the first list"""
162 self.assertEqual(self._count("n0"), self._count("nbar"))
163 self.assertEqual(self._count("n0"), self._count("allneutrons"))
164
165
166if __name__ == "__main__":
167 with b2tu.clean_working_directory():
168 run_copylists()
169 unittest.main()
def test_different_association_of_neutrals_same_number_of_daughters(self)
Definition: copylists.py:148
def test_neutrals_in_decays_to_charge_conjugated_daughters(self)
Definition: copylists.py:143
def test_different_daughter_order(self)
Definition: copylists.py:138
def test_merge_two_lists_with_different_mdst_objects(self)
Definition: copylists.py:132
def _count(self, listname)
Definition: copylists.py:121
def test_merge_two_lists_with_identical_daughters(self)
Definition: copylists.py:126
def test_ignore_mother_flavor(self)
Definition: copylists.py:153