Belle II Software  release-05-01-25
B2A408-AllParticleCombiner.py
1 #!/usr/bin/env python3
2 
3 
26 
27 import basf2 as b2
28 from modularAnalysis import applyCuts
29 from modularAnalysis import buildRestOfEvent
30 from modularAnalysis import combineAllParticles
31 from modularAnalysis import fillParticleList
32 from modularAnalysis import inputMdst
33 from modularAnalysis import reconstructDecay
34 from modularAnalysis import matchMCTruth
35 from modularAnalysis import signalSideParticleFilter
36 from modularAnalysis import variablesToNtuple
37 from modularAnalysis import variableToSignalSideExtraInfo
38 from vertex import raveFit
39 from vertex import treeFit
40 from stdCharged import stdPi, stdK
41 from variables import variables
42 import variables.collections as vc
43 import variables.utils as vu
44 
45 # create path
46 my_path = b2.create_path()
47 
48 # load input ROOT file
49 inputMdst(environmentType='default',
50  filename=b2.find_file('ccbar_sample_to_test.root', 'examples', False),
51  path=my_path)
52 
53 # use standard final state particle lists
54 #
55 # creates "pi+:all" ParticleList (and c.c.)
56 stdPi('all', path=my_path)
57 # creates "pi+:loose" ParticleList (and c.c.)
58 stdPi('loose', path=my_path)
59 # creates "K+:loose" ParticleList (and c.c.)
60 stdK('loose', path=my_path)
61 
62 # reconstruct D0 -> K- pi+ decay
63 # keep only candidates with 1.8 < M(Kpi) < 1.9 GeV
64 reconstructDecay('D0:kpi -> K-:loose pi+:loose', '1.8 < M < 1.9', path=my_path)
65 
66 # perform D0 vertex fit
67 # reject candidates with C.L. value of the fit < 0.0
68 treeFit('D0:kpi', 0.0, path=my_path)
69 
70 # reconstruct D*+ -> D0 pi+ decay
71 # keep only candidates with Q = M(D0pi) - M(D0) - M(pi) < 20 MeV
72 reconstructDecay('D*+:all -> D0:kpi pi+:all', '0.0 <= Q < 0.02', path=my_path)
73 
74 # perform MC matching (MC truth association)
75 matchMCTruth('D*+:all', path=my_path)
76 
77 # perform D*+ vertex fit
78 # reject candidates with C.L. value of the fit < 0.0
79 treeFit('D*+:all', 0.0, path=my_path)
80 
81 # build rest of event
82 buildRestOfEvent('D*+:all', path=my_path)
83 
84 # define two new paths
85 roe_path = b2.create_path()
86 deadEndPath = b2.create_path()
87 
88 # execute roe path only if there is a signal particle in the event, otherwise stop processing
89 signalSideParticleFilter('D*+:all', '', roe_path, deadEndPath)
90 
91 # select all particles in the rest of the event
92 fillParticleList('pi+:fromPV', 'isInRestOfEvent == 1', path=roe_path)
93 
94 # perform MC matching for particles in the rest of the event
95 matchMCTruth('pi+:fromPV', path=roe_path)
96 
97 # define a list of weakly decaying particles
98 WeaklyDecayingParticleNames = ['KL0', 'KS0', 'D+', 'D0', 'D_s+', 'n0', 'Sigma-',
99  'Lambda0', 'Sigma+', 'Xi-', 'Omega-', 'Lambda_c+', 'Xi_c0', 'Xi_c+', 'Omega_c0']
100 WeaklyDecayingParticles = [
101  '130',
102  '310',
103  '411',
104  '421',
105  '431',
106  '2112',
107  '3112',
108  '3122',
109  '3222',
110  '3312',
111  '3334',
112  '4122',
113  '4132',
114  '4232',
115  '4332']
116 
117 # select particles which are not originating from a weak decay
118 PVParticlesCuts = ''
119 DepthOfDecayChain = 5
120 for i in range(0, DepthOfDecayChain):
121  PVParticlesCuts += '[genMotherPDG('
122  PVParticlesCuts += str(i)
123  PVParticlesCuts += ') == 10022'
124  for j in range(0, i):
125  for WeaklyDecayingParticle in WeaklyDecayingParticles:
126  PVParticlesCuts += ' and abs(genMotherPDG('
127  PVParticlesCuts += str(j)
128  PVParticlesCuts += ')) != '
129  PVParticlesCuts += WeaklyDecayingParticle
130  PVParticlesCuts += ']'
131  if i < (DepthOfDecayChain - 1):
132  PVParticlesCuts += ' or '
133 applyCuts('pi+:fromPV', PVParticlesCuts, path=roe_path)
134 
135 # combine all particles in the rest of the event and fit them to a common vertex
136 combineAllParticles(['pi+:fromPV'], 'vpho:PV', path=roe_path)
137 raveFit('vpho:PV', conf_level=0, constraint='iptube', path=roe_path)
138 
139 # save information about the calculated PV position
140 PVVtxDictionary = {'x': 'PVx',
141  'y': 'PVy',
142  'z': 'PVz',
143  'chiProb': 'PV_Pvalue',
144  'nParticlesInList(pi+:fromPV)': 'nPiPV'
145  }
146 variableToSignalSideExtraInfo('vpho:PV', PVVtxDictionary, path=roe_path)
147 variables.addAlias('PVXFit', 'extraInfo(PVx)')
148 variables.addAlias('PVYFit', 'extraInfo(PVy)')
149 variables.addAlias('PVZFit', 'extraInfo(PVz)')
150 variables.addAlias('PVFit_Pvalue', 'extraInfo(PV_Pvalue)')
151 variables.addAlias('nPiFromPV', 'extraInfo(nPiPV)')
152 
153 pv_vars = ['PVXFit', 'PVYFit', 'PVZFit', 'PVFit_Pvalue', 'nPiFromPV']
154 
155 # execute ROE path
156 my_path.for_each('RestOfEvent', 'RestOfEvents', roe_path)
157 
158 # Select variables that we want to store to ntuple
159 dstar_vars = vc.inv_mass + vc.mc_truth + pv_vars
160 
161 fs_hadron_vars = vu.create_aliases_for_selected(
162  vc.pid + vc.track + vc.mc_truth,
163  'D*+ -> [D0 -> ^K- ^pi+] ^pi+')
164 
165 d0_vars = vu.create_aliases_for_selected(
166  vc.inv_mass + vc.mc_truth,
167  'D*+ -> ^D0 pi+', 'D0')
168 
169 # Saving variables to ntuple
170 output_file = 'B2A408-AllParticleCombiner.root'
171 variablesToNtuple('D*+:all', dstar_vars + d0_vars + fs_hadron_vars,
172  filename=output_file, treename='dsttree', path=my_path)
173 
174 # Process the events
175 b2.process(my_path)
176 
177 # print out the summary
178 print(b2.statistics)
variablesToNtuple
Definition: variablesToNtuple.py:1
variables.utils
Definition: utils.py:1
treeFit
Definition: treeFit.py:1
variables.collections
Definition: collections.py:1