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