Belle II Software development
cdcdedx_calibration_utils.py
1
8
9import basf2
10from reconstruction import prepare_cdst_analysis
11import modularAnalysis as mA
12
13
14# radiative electron selection
15
16
17def make_electron_collection(path_electron):
18 # Add a TriggerSkim module to apply a specific trigger line
19 trg_bhabhaskim = path_electron.add_module(
20 "TriggerSkim",
21 triggerLines=[
22 "software_trigger_cut&skim&accept_radee",
23 "software_trigger_cut&skim&accept_bhabha_cdc",
24 ],
25 resultOnMissing=0,
26 )
27 trg_bhabhaskim.if_value("==0", basf2.Path(), basf2.AfterConditionPath.END)
28
29 prepare_cdst_analysis(path=path_electron)
30
31 # Add the CDCDedxCorrection module to correct dE/dx (no saturation)
32 path_electron.add_module(
33 'CDCDedxCorrection',
34 relativeCorrections=False, # Disable relative corrections
35 scaleCor=True,
36 runGain=True, # Enable run gain corrections
37 timeGain=True, # Enable injection time gain corrections
38 cosineCor=True, # Enable cosine corrections
39 wireGain=True, # Enable wire gain corrections
40 twoDCell=True, # Enable 2D cell corrections
41 oneDCell=True) # Enable 1D cell corrections
42
43 # Fill the particle list
44 mA.fillParticleList('e+:calib', ' ', path=path_electron)
45 return ['e+:calib']
46
47# ------------------------------------------------------------------------------------------------------------------
48
49# radiative muon selection
50
51
52def make_muon_collection(path_muon):
53
54 prepare_cdst_analysis(path=path_muon)
55
56 # Add the CDCDedxCorrection module to correct dE/dx (no saturation)
57 path_muon.add_module(
58 'CDCDedxCorrection',
59 relativeCorrections=False, # Disable relative corrections
60 scaleCor=True,
61 runGain=True, # Enable run gain corrections
62 timeGain=True, # Enable injection time gain corrections
63 cosineCor=True, # Enable cosine corrections
64 wireGain=True, # Enable wire gain corrections
65 twoDCell=True, # Enable 2D cell corrections
66 oneDCell=True) # Enable 1D cell corrections
67
68 # Creating a particle list with basic cuts
69 goodTrack = 'abs(dr) < 0.5 and abs(dz) < 0.5 and nCDCHits > 0'
70 goodTrack += ' and clusterE < 0.40 and clusterEoP < 0.40 and inCDCAcceptance==1'
71 goodTrack += ' and [[isPIDAvailableFrom(KLM) == 0 and clusterE < 0.25] or isPIDAvailableFrom(KLM) == 1]'
72
73 # Create a particle list for muons that satisfy the selection criteria
74 mA.fillParticleList('mu+:calib', goodTrack, path=path_muon)
75
76 # Define cuts for the track pair (mu+ and mu-)
77 track_cuts = ''
78 track_cuts += 'daughterProductOf(charge) < 0'
79 track_cuts += ' and daughterLowest(clusterE) <= 0.25'
80
81 # One of the muons is valid in KLM
82 track_cuts += ' and [daughter(0,isPIDAvailableFrom(KLM)) == 1 or daughter(1,isPIDAvailableFrom(KLM)) == 1]'
83
84 # Reconstruct the decay 'vpho -> mu+ mu-'
85 mA.reconstructDecay('vpho:mumu -> mu+:calib mu-:calib', track_cuts, path=path_muon)
86
87 # Apply event-level cuts to ensure there are exactly two cleaned tracks
88 event_cuts = '[nCleanedTracks('+goodTrack+') == 2]'
89 mA.applyEventCuts(event_cuts, path=path_muon)
90 radmumulist = ['vpho:mumu']
91
92 # Apply SkimFilter
93 skimfilter = basf2.register_module('SkimFilter')
94 skimfilter.param('particleLists', radmumulist)
95 path_muon.add_module(skimfilter)
96
97 filter_path = basf2.create_path()
98 skimfilter.if_value('=1', filter_path, basf2.AfterConditionPath.CONTINUE)
99
100 # Define additional cuts for the muon pair
101 cutonPairs = ''
102 mA.cutAndCopyList('mu+:cal', 'mu+:calib', cutonPairs, path=filter_path)
103
104 # Apply event-level cuts for the copied muons
105 event_cutscopy = '[nCleanedTracks('+goodTrack+') == 2]'
106 mA.applyEventCuts(event_cutscopy, path=filter_path)
107
108 return ['mu+:cal']
109
110# ------------------------------------------------------------------------------------------------------------------
111
112# proton selection
113
114
115def make_proton_collection(path_hadrons):
116
117 # Trigger Skim Module to apply the specified trigger lines
118 trg_skim = path_hadrons.add_module("TriggerSkim", triggerLines=["software_trigger_cut&skim&accept_lambda"])
119 trg_skim.if_value("==0", basf2.Path(), basf2.AfterConditionPath.END)
120
121 prepare_cdst_analysis(path=path_hadrons)
122
123 # Add the CDCDedxCorrection module to correct dE/dx (no saturation)
124 path_hadrons.add_module(
125 'CDCDedxCorrection',
126 relativeCorrections=False, # Disable relative corrections
127 scaleCor=True,
128 runGain=True, # Enable run gain corrections
129 timeGain=True, # Enable injection time gain corrections
130 cosineCor=True, # Enable cosine corrections
131 wireGain=True, # Enable wire gain corrections
132 twoDCell=True, # Enable 2D cell corrections
133 oneDCell=True) # Enable 1D cell corrections
134
135 # Define a selection criteria for good proton tracks
136 goodProtonTrack = 'dr< 0.50 and abs(dz)<0.50'
137 mA.fillParticleList("p+:calib", goodProtonTrack, path=path_hadrons)
138 return "p+:calib"
139
140# ------------------------------------------------------------------------------------------------------------------
141
142# pion kaon selection
143
144
145def make_pion_kaon_collection(path_hadrons):
146
147 # Add the TriggerSkim module to the path with specified trigger lines
148 trg_skim = path_hadrons.add_module(
149 "TriggerSkim",
150 triggerLines=[
151 "software_trigger_cut&skim&accept_dstar_1",
152 "software_trigger_cut&skim&accept_dstar_3"])
153
154 trg_skim.if_value("==0", basf2.Path(), basf2.AfterConditionPath.END)
155
156 prepare_cdst_analysis(path=path_hadrons)
157
158 # Add the CDCDedxCorrection module to correct dE/dx (no saturation)
159 path_hadrons.add_module(
160 'CDCDedxCorrection',
161 relativeCorrections=False, # Disable relative corrections
162 scaleCor=True,
163 runGain=True, # Enable run gain corrections
164 timeGain=True, # Enable injection time gain corrections
165 cosineCor=True, # Enable cosine corrections
166 wireGain=True, # Enable wire gain corrections
167 twoDCell=True, # Enable 2D cell corrections
168 oneDCell=True) # Enable 1D cell corrections
169
170 # Define cleaning criteria for the Kaon particle list
171 clean_K = 'dr < 1.00 and abs(dz) < 1.0 and inCDCAcceptance==1 '
172 clean_K += ' and [[cosTheta<-0.45 or cosTheta >= 0.80] or [[cosTheta>=-0.45 and cosTheta <= 0.80 and pt <= 0.50]'
173 clean_K += ' or [cosTheta>=-0.45 and cosTheta <= 0.80 and pt > 0.50 and pidProbabilityExpert(321, TOP) > 0.015 ]]]'
174
175 # Fill the cleaned Kaon list
176 mA.fillParticleList("K+:calib", clean_K, path=path_hadrons)
177
178 # Define cleaning criteria for the Pion particle list
179 clean_Pi = 'dr < 1.0 and abs(dz) < 1.0 and inCDCAcceptance==1 '
180 clean_Pi += ' and [[cosTheta<-0.45 or cosTheta > 0.80] or [[cosTheta>=-0.45 and cosTheta <= 0.80 and pt <= 0.50] '
181 clean_Pi += ' or [cosTheta>=-0.45 and cosTheta <= 0.80 and pt > 0.50 and pidProbabilityExpert(321, TOP) < 0.60 ]]]'
182
183 # Fill the cleaned Pion list
184 mA.fillParticleList("pi+:calib", clean_Pi, path=path_hadrons)
185
186 # -----------------------------------------------------------
187 # Reconstruction for the D0 -> K- pi+ decay
188 clean_Dz1 = 'abs(dM) < 0.020' # Mass difference of D0
189 clean_Dz1 += ' and [daughter(0,nCDCHits) > 30 or daughter(1, nCDCHits) > 30] '
190
191 mA.reconstructDecay('D0:cal1 -> K-:calib pi+:calib', clean_Dz1, path=path_hadrons)
192
193 # Reconstruction for the D0 -> K- pi+ pi+ pi- decay
194 clean_Dz2 = 'abs(dM) < 0.020' # Mass difference of D0
195 clean_Dz2 += ' and [daughter(0,nCDCHits) > 25 or daughter(1, nCDCHits) > 25 or daughter(2, nCDCHits) > 25 '
196 clean_Dz2 += ' or daughter(3, nCDCHits) > 25] '
197 mA.reconstructDecay('D0:cal2 -> K-:calib pi+:calib pi+:calib pi-:calib', clean_Dz2, path=path_hadrons)
198
199 # ------------------------------------------------------------
200 # Define cleaning for slow pions
201 clean_sPi = 'dr < 1.00 and abs(dz) < 1.00 and p < 1.5 and nCDCHits > 10 and inCDCAcceptance==1'
202 mA.fillParticleList("pi+:slow", clean_sPi, path=path_hadrons) # Fill the slow pion list
203
204 # ------------------------------------------------------------
205 # Reconstruct the first D*+ -> D0 [-> K- pi+] and slow pion decay
206 # tights are 0.0017 and 0.015
207 clean_Ds = 'useCMSFrame(p) > 1.5 and abs(formula(massDifference(0) - 0.14542)) < 0.00070 '
208 clean_Ds += ' and abs(dM) < 0.020' # Mass difference of D*
209 mA.reconstructDecay('D*+:cal1 -> D0:cal1 pi+:slow', clean_Ds, path=path_hadrons)
210
211 # Apply SkimFilter for the first D*+ decay
212 list_Ds1 = ['D*+:cal1']
213 skimf_Ds1 = basf2.register_module('SkimFilter')
214 skimf_Ds1.param('particleLists', list_Ds1)
215 path_hadrons.add_module(skimf_Ds1)
216 fpath_Ds1 = basf2.create_path()
217 skimf_Ds1.if_value('=1', fpath_Ds1, basf2.AfterConditionPath.CONTINUE)
218
219 # Reconstruct the second D*+ [-> D0 [-> K- pi+ pi+ pi- ] slow pion] decay and apply SkimFilter
220 mA.reconstructDecay('D*+:cal2 -> D0:cal2 pi+:slow', clean_Ds, path=path_hadrons)
221
222 list_Ds2 = ['D*+:cal2']
223 skimf_Ds2 = basf2.register_module('SkimFilter')
224 skimf_Ds2.param('particleLists', list_Ds2)
225 path_hadrons.add_module(skimf_Ds2)
226 fpath_Ds2 = basf2.create_path()
227 skimf_Ds2.if_value('=1', fpath_Ds2, basf2.AfterConditionPath.CONTINUE)
228
229 # ------------------------------------------------------------
230 # Add extra information to daughter particles for first D*+ decay
231 mA.variablesToDaughterExtraInfo('D*+:cal1', 'D*+ -> [D0 -> ^K- ^pi+ ] ^pi+', {'dM': 'l_Ds1dM'}, path=fpath_Ds1)
232 mA.variablesToDaughterExtraInfo('D*+:cal1', 'D*+ -> [D0 -> ^K- ^pi+ ] ^pi+', {'useCMSFrame(p)': 'l_Ds1p'}, path=fpath_Ds1)
233 mA.variablesToDaughterExtraInfo('D*+:cal1', 'D*+ -> [D0 -> ^K- ^pi+ ] ^pi+',
234 {'massDifference(0)': 'l_Ds1mDiff'}, path=fpath_Ds1)
235 mA.variablesToDaughterExtraInfo('D*+:cal1', 'D*+ -> [D0 -> ^K- ^pi+ ] ^pi+', {'daughter(0,dM)': 'l_Ds1_DzdM'}, path=fpath_Ds1)
236 mA.variablesToDaughterExtraInfo('D*+:cal1',
237 'D*+ -> [D0 -> ^K- ^pi+ ] ^pi+',
238 {'daughter(0,daughter(0,nCDCHits))': 'l_Ds1_Dz_Khits'},
239 path=fpath_Ds1)
240 mA.variablesToDaughterExtraInfo('D*+:cal1',
241 'D*+ -> [D0 -> ^K- ^pi+ ] ^pi+',
242 {'daughter(0,daughter(1,nCDCHits))': 'l_Ds1_Dz_Pihits'},
243 path=fpath_Ds1)
244
245 # Define the cut conditions for first D*+ mass difference, momentum, and decay parameters
246 cutonD1var = "abs(extraInfo(l_Ds1dM)) < 0.02" # D* mass difference
247 cutonD1var += " and extraInfo(l_Ds1p) > 1.5 " # D* momentum
248 cutonD1var += " and abs(formula(extraInfo(l_Ds1mDiff) - 0.14542)) < 0.0010" # \DeltaM
249 cutonD1var += " and abs(extraInfo(l_Ds1_DzdM)) < 0.02" # D0 mass difference
250 cutonD1var += " and [extraInfo(l_Ds1_Dz_Khits) > 30 or extraInfo(l_Ds1_Dz_Pihits) > 30]"
251
252 # Apply cuts and copy the filtered particles to new lists
253 mA.cutAndCopyList('K+:dst1', 'K+:calib', cutonD1var, path=fpath_Ds1)
254 mA.cutAndCopyList('pi+:dst1', 'pi+:calib', cutonD1var, path=fpath_Ds1)
255
256 # ------------------------------------------------------------
257 # Add extra information to daughter particles for second D*+ decay
258 mA.variablesToDaughterExtraInfo('D*+:cal2', 'D*+ -> [D0 -> ^K- ^pi+ ^pi+ ^pi-] ^pi+', {'dM': 'l_Ds2dM'}, path=fpath_Ds2)
259 mA.variablesToDaughterExtraInfo('D*+:cal2',
260 'D*+ -> [D0 -> ^K- ^pi+ ^pi+ ^pi-] ^pi+',
261 {'useCMSFrame(p)': 'l_Ds2p'},
262 path=fpath_Ds2)
263 mA.variablesToDaughterExtraInfo('D*+:cal2',
264 'D*+ -> [D0 -> ^K- ^pi+ ^pi+ ^pi-] ^pi+',
265 {'massDifference(0)': 'l_Ds2mDiff'},
266 path=fpath_Ds2)
267 mA.variablesToDaughterExtraInfo('D*+:cal2',
268 'D*+ -> [D0 -> ^K- ^pi+ ^pi+ ^pi-] ^pi+',
269 {'daughter(0,dM)': 'l_Ds2_DzdM'},
270 path=fpath_Ds2)
271 mA.variablesToDaughterExtraInfo('D*+:cal2',
272 'D*+ -> [D0 -> ^K- ^pi+ ^pi+ ^pi-] ^pi+',
273 {'daughter(0,daughter(0,nCDCHits))': 'l_Ds2_Dz_Khits'},
274 path=fpath_Ds2)
275 mA.variablesToDaughterExtraInfo('D*+:cal2',
276 'D*+ -> [D0 -> ^K- ^pi+ ^pi+ ^pi-] ^pi+',
277 {'daughter(0,daughter(1,nCDCHits))': 'l_Ds2_Dz_Pi1hits'},
278 path=fpath_Ds2)
279 mA.variablesToDaughterExtraInfo('D*+:cal2',
280 'D*+ -> [D0 -> ^K- ^pi+ ^pi+ ^pi-] ^pi+',
281 {'daughter(0,daughter(2,nCDCHits))': 'l_Ds2_Dz_Pi2hits'},
282 path=fpath_Ds2)
283 mA.variablesToDaughterExtraInfo('D*+:cal2',
284 'D*+ -> [D0 -> ^K- ^pi+ ^pi+ ^pi-] ^pi+',
285 {'daughter(0,daughter(3,nCDCHits))': 'l_Ds2_Dz_Pi3hits'},
286 path=fpath_Ds2)
287
288 # Define the cut conditions for second D*+ mass difference, momentum, and decay parameters
289 cutonD2var = "abs(extraInfo(l_Ds2dM)) < 0.02" # D* mass difference
290 cutonD2var += " and extraInfo(l_Ds2p) > 2.0" # D* momentum
291 cutonD2var += " and abs(formula(extraInfo(l_Ds2mDiff) - 0.14542)) < 0.0010" # \DeltaM
292 cutonD2var += " and abs(extraInfo(l_Ds2_DzdM)) < 0.02" # D0 mass difference
293 cutonD2var += " and [extraInfo(l_Ds2_Dz_Khits) > 25 or extraInfo(l_Ds2_Dz_Pi1hits) > 25 "
294 cutonD2var += " or extraInfo(l_Ds2_Dz_Pi2hits) > 25 or extraInfo(l_Ds2_Dz_Pi3hits) > 25]"
295
296 # Apply cuts and copy the filtered particles to new lists
297 mA.cutAndCopyList('K+:dst2', 'K+:calib', cutonD2var, path=fpath_Ds2)
298 mA.cutAndCopyList('pi+:dst2', 'pi+:calib', cutonD2var, path=fpath_Ds2)
299
300 pion_kaon_list = ['pi+:dst1', 'pi+:dst2', 'K+:dst1', 'K+:dst2']
301
302 return pion_kaon_list