Belle II Software  release-08-01-10
copylists.py
1 #!/usr/bin/env python3
2 
3 
10 
11 import unittest
12 import uproot
13 import basf2 as b2
14 import b2test_utils as b2tu
15 import modularAnalysis as ma
16 from stdPi0s import stdPi0s
17 from stdV0s import stdKshorts
18 from variables import variables as vm
19 
20 
21 def 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 
30 def 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 
111 class 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_count("a"), self._count_count("b"))
122  self.assertEqual(self._count_count("a"), self._count_count("ab"))
123  self.assertEqual(self._count_count("b"), self._count_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_count("c"), self._count_count("d"))
129  self.assertEqual(self._count_count("c") + self._count_count("d"), self._count_count("cd"))
130 
132  """Merging two lists with daughters in a different order should not double count."""
133  self.assertEqual(self._count_count("e"), self._count_count("e"))
134  self.assertEqual(self._count_count("e"), self._count_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_count("g") + self._count_count("h"), self._count_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_count("KS") + self._count_count("pi0"), self._count_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_count("D0"), self._count_count("ignore"))
151  self.assertEqual(self._count_count("D0") + self._count_count("anti"), self._count_count("flavor"))
152 
153 
154 if __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