Belle II Software development
B2A408-AllParticleCombiner.py
1#!/usr/bin/env python3
2
3
10
11
29
30import basf2 as b2
31from modularAnalysis import applyCuts
32from modularAnalysis import buildRestOfEvent
33from modularAnalysis import combineAllParticles
34from modularAnalysis import fillParticleList
35from modularAnalysis import inputMdst
36from modularAnalysis import reconstructDecay
37from modularAnalysis import matchMCTruth
38from modularAnalysis import signalSideParticleFilter
39from modularAnalysis import variablesToNtuple
40from modularAnalysis import variableToSignalSideExtraInfo
41from vertex import raveFit
42from vertex import treeFit
43from stdCharged import stdPi, stdK
44from variables import variables
45import variables.collections as vc
46import variables.utils as vu
47
48# create path
49my_path = b2.create_path()
50
51# load input ROOT file
52inputMdst(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.)
58stdPi('all', path=my_path)
59# creates "pi+:loose" ParticleList (and c.c.)
60stdPi('loose', path=my_path)
61# creates "K+:loose" ParticleList (and c.c.)
62stdK('loose', path=my_path)
63
64# reconstruct D0 -> K- pi+ decay
65# keep only candidates with 1.8 < M(Kpi) < 1.9 GeV
66reconstructDecay('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
70treeFit('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
74reconstructDecay('D*+:all -> D0:kpi pi+:all', '0.0 <= Q < 0.02', path=my_path)
75
76# perform MC matching (MC truth association)
77matchMCTruth('D*+:all', path=my_path)
78
79# perform D*+ vertex fit
80# reject candidates with C.L. value of the fit < 0.0
81treeFit('D*+:all', 0.0, path=my_path)
82
83# build rest of event
84buildRestOfEvent('D*+:all', path=my_path)
85
86# define two new paths
87roe_path = b2.create_path()
88deadEndPath = b2.create_path()
89
90# execute roe path only if there is a signal particle in the event, otherwise stop processing
91signalSideParticleFilter('D*+:all', '', roe_path, deadEndPath)
92
93# select all particles in the rest of the event
94fillParticleList('pi+:fromPV', 'isInRestOfEvent == 1', path=roe_path)
95
96# perform MC matching for particles in the rest of the event
97matchMCTruth('pi+:fromPV', path=roe_path)
98
99# define a list of weakly decaying particles
100WeaklyDecayingParticleNames = ['KL0', 'KS0', 'D+', 'D0', 'D_s+', 'n0', 'Sigma-',
101 'Lambda0', 'Sigma+', 'Xi-', 'Omega-', 'Lambda_c+', 'Xi_c0', 'Xi_c+', 'Omega_c0']
102WeaklyDecayingParticles = [
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
120PVParticlesCuts = ''
121DepthOfDecayChain = 5
122for 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 '
135applyCuts('pi+:fromPV', PVParticlesCuts, path=roe_path)
136
137# combine all particles in the rest of the event and fit them to a common vertex
138combineAllParticles(['pi+:fromPV'], 'vpho:PV', path=roe_path)
139raveFit('vpho:PV', conf_level=0, constraint='iptube', path=roe_path)
140
141# save information about the calculated PV position
142PVVtxDictionary = {'x': 'PVx',
143 'y': 'PVy',
144 'z': 'PVz',
145 'chiProb': 'PV_Pvalue',
146 'nParticlesInList(pi+:fromPV)': 'nPiPV'
147 }
148variableToSignalSideExtraInfo('vpho:PV', PVVtxDictionary, path=roe_path)
149variables.addAlias('PVXFit', 'extraInfo(PVx)')
150variables.addAlias('PVYFit', 'extraInfo(PVy)')
151variables.addAlias('PVZFit', 'extraInfo(PVz)')
152variables.addAlias('PVFit_Pvalue', 'extraInfo(PV_Pvalue)')
153variables.addAlias('nPiFromPV', 'extraInfo(nPiPV)')
154
155pv_vars = ['PVXFit', 'PVYFit', 'PVZFit', 'PVFit_Pvalue', 'nPiFromPV']
156
157# execute ROE path
158my_path.for_each('RestOfEvent', 'RestOfEvents', roe_path)
159
160# Select variables that we want to store to ntuple
161dstar_vars = vc.inv_mass + vc.mc_truth + pv_vars
162
163fs_hadron_vars = vu.create_aliases_for_selected(
164 vc.pid + vc.track + vc.mc_truth,
165 'D*+ -> [D0 -> ^K- ^pi+] ^pi+')
166
167d0_vars = vu.create_aliases_for_selected(
168 vc.inv_mass + vc.mc_truth,
169 'D*+ -> ^D0 pi+', 'D0')
170
171# Saving variables to ntuple
172output_file = 'B2A408-AllParticleCombiner.root'
173variablesToNtuple('D*+:all', dstar_vars + d0_vars + fs_hadron_vars,
174 filename=output_file, treename='dsttree', path=my_path)
175
176# Process the events
177b2.process(my_path)
178
179# print out the summary
180print(b2.statistics)