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