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