Belle II Software development
default_channels.py
1#!/usr/bin/env python3
2
3
10
11"""
12 Contains some example configurations of the FEI
13 Mostly you want to use get_default_channels,
14 which can return the configuration for common use-cases
15 - Hadronic tagging (hadronic = True)
16 - Semileptonic tagging (semileptonic = True)
17 - B+/B- (chargedB = True)
18 - B0/anti-B0 (neutralB = True)
19 - running on Belle 1 MC/data (convertedFromBelle = True)
20 - running a specific FEI which is optimized for a signal selection and uses ROEs (specific = True)
21 - run without semileptonic D channels (removeSLD = True )
22 - B mesons with a strange quark in Y(5S) runs (strangeB = True)
23
24 Another interesting configuration is given by get_fr_channels,
25 which will return a configuration which is equivalent to the original Full Reconstruction algorithm used by Belle
26"""
27
28import b2bii
29from fei import Particle, MVAConfiguration, PreCutConfiguration, PostCutConfiguration
30from basf2 import B2FATAL, B2INFO
31
32
33def get_default_channels(
34 B_extra_cut=None,
35 hadronic=True,
36 semileptonic=True,
37 KLong=False,
38 baryonic=True,
39 chargedB=True,
40 neutralB=True,
41 specific=False,
42 removeSLD=False,
43 usePIDNN=False,
44 strangeB=False):
45 """
46 returns list of Particle objects with all default channels for running
47 FEI on Upsilon(4S). For a training with analysis-specific signal selection,
48 adding a cut on nRemainingTracksInRestOfEvent is recommended.
49 @param B_extra_cut Additional user cut on recombination of tag-B-mesons
50 @param hadronic whether to include hadronic B decays (default is True)
51 @param semileptonic whether to include semileptonic B decays (default is True)
52 @param KLong whether to include K_long decays into the training (default is False)
53 @param baryonic whether to include baryons into the training (default is True)
54 @param chargedB whether to recombine charged B mesons (default is True)
55 @param neutralB whether to recombine neutral B mesons (default is True)
56 @param specific if True, this adds isInRestOfEvent cut to all FSP
57 @param removeSLD if True, removes semileptonic D modes from semileptonic B lists (default is False)
58 @param usePIDNN if True, PID probabilities calculated from PID neural network are used (default is False)
59 @param strangeB if True, reconstruct B_s mesons in Upsilon5S decays (default is False)
60 """
61 if strangeB is True:
62 B2INFO('Running 5S FEI')
63 if chargedB is False and neutralB is False and strangeB is False:
64 B2FATAL('No B-Mesons will be recombined, since chargedB==False and neutralB==False and strangeB==False was selected!'
65 ' Please reconfigure the arguments of get_default_channels() accordingly')
66 if hadronic is False and semileptonic is False:
67 if KLong is False:
68 B2FATAL('No B-Mesons will be recombined, since hadronic==False, semileptonic==False, and KLong==False were selected.'
69 ' Please reconfigure the arguments of get_default_channels() accordingly')
70
71 convertedFromBelle = b2bii.isB2BII()
72
73 if convertedFromBelle:
74 if usePIDNN:
75 B2FATAL("The PIDNN variables do not exist for b2bii.")
76 # Using Belle specific Variables for e-ID, mu-ID and K-ID
77 # atcPIDBelle(3,2) is used as K-ID
78 # atcPIDBelle(4,2) and atcPIDBelle(4,3) are used as pr-ID
79
80 chargedVariables = ['eIDBelle',
81 'atcPIDBelle(3,2)',
82 'atcPIDBelle(4,2)', 'atcPIDBelle(4,3)',
83 'muIDBelle'
84 ]
85 else:
86 if usePIDNN:
87 chargedVariables = ['electronIDNN', 'kaonIDNN', 'protonIDNN', 'muonIDNN']
88 else:
89 chargedVariables = ['electronID', 'kaonID', 'protonID', 'muonID']
90
91 chargedVariables += ['p', 'pt', 'pz', 'dr', 'dz', 'chiProb', 'extraInfo(preCut_rank)']
92
93 if specific:
94 charged_user_cut = '[dr < 2] and [abs(dz) < 4] and isInRestOfEvent > 0.5'
95 else:
96 charged_user_cut = '[dr < 2] and [abs(dz) < 4]'
97
98 pion = Particle('pi+',
99 MVAConfiguration(variables=chargedVariables,
100 target='isPrimarySignal'),
101 PreCutConfiguration(userCut=charged_user_cut,
102 bestCandidateMode='highest',
103 bestCandidateVariable="atcPIDBelle(2,3)" if convertedFromBelle
104 else ("pionIDNN" if usePIDNN else "pionID"),
105 bestCandidateCut=20),
106 PostCutConfiguration(bestCandidateCut=10, value=0.01))
107 pion.addChannel(['pi+:FSP'])
108
109 kaon = Particle('K+',
110 MVAConfiguration(variables=chargedVariables,
111 target='isPrimarySignal'),
112 PreCutConfiguration(userCut=charged_user_cut,
113 bestCandidateMode='highest',
114 bestCandidateVariable="atcPIDBelle(3,2)" if convertedFromBelle
115 else ("kaonIDNN" if usePIDNN else "kaonID"),
116 bestCandidateCut=20),
117 PostCutConfiguration(bestCandidateCut=10, value=0.01))
118 kaon.addChannel(['K+:FSP'])
119
120 proton = Particle('p+',
121 MVAConfiguration(variables=chargedVariables,
122 target='isPrimarySignal'),
123 PreCutConfiguration(userCut=charged_user_cut,
124 bestCandidateMode='highest',
125 bestCandidateVariable="atcPIDBelle(4,3)" if convertedFromBelle
126 else ("protonIDNN" if usePIDNN else "protonID"),
127 bestCandidateCut=20),
128 PostCutConfiguration(bestCandidateCut=10, value=0.01))
129 proton.addChannel(['p+:FSP'])
130
131 electron = Particle('e+',
132 MVAConfiguration(variables=chargedVariables,
133 target='isPrimarySignal'),
134 PreCutConfiguration(userCut=charged_user_cut,
135 bestCandidateMode='highest',
136 bestCandidateVariable="eIDBelle" if convertedFromBelle
137 else ("electronIDNN" if usePIDNN else "electronID"),
138 bestCandidateCut=10),
139 PostCutConfiguration(bestCandidateCut=5, value=0.01))
140 electron.addChannel(['e+:FSP'])
141
142 muon = Particle('mu+',
143 MVAConfiguration(variables=chargedVariables,
144 target='isPrimarySignal'),
145 PreCutConfiguration(userCut=charged_user_cut,
146 bestCandidateMode='highest',
147 bestCandidateVariable="muIDBelle" if convertedFromBelle
148 else ("muonIDNN" if usePIDNN else "muonID"),
149 bestCandidateCut=10),
150 PostCutConfiguration(bestCandidateCut=5, value=0.01))
151 muon.addChannel(['mu+:FSP'])
152
153 if convertedFromBelle:
154 gamma_cut = 'goodBelleGamma == 1 and clusterBelleQuality == 0'
155 else:
156 # Same as goodBelleGamma == 1
157 gamma_cut = '[[clusterReg == 1 and E > 0.10] or [clusterReg == 2 and E > 0.05] or [clusterReg == 3 and E > 0.15]]'
158 if specific:
159 gamma_cut += ' and isInRestOfEvent > 0.5'
160
161 gamma = Particle('gamma',
162 MVAConfiguration(variables=['clusterReg', 'clusterNHits', 'clusterTiming', 'extraInfo(preCut_rank)',
163 'clusterE9E25', 'pt', 'E', 'pz'],
164 target='isPrimarySignal'),
165 PreCutConfiguration(userCut=gamma_cut,
166 bestCandidateMode='highest',
167 bestCandidateVariable='E',
168 bestCandidateCut=40),
169 PostCutConfiguration(bestCandidateCut=20, value=0.01))
170 gamma.addChannel(['gamma:FSP'])
171 gamma.addChannel(['gamma:V0'],
172 MVAConfiguration(variables=['pt', 'E', 'pz', 'extraInfo(preCut_rank)'],
173 target='isPrimarySignal'),
174 PreCutConfiguration(userCut='',
175 bestCandidateMode='highest',
176 bestCandidateVariable='E',
177 bestCandidateCut=40))
178
179 if convertedFromBelle:
180
181 pi0_cut = '0.08 < InvM < 0.18'
182 if specific:
183 pi0_cut += ' and isInRestOfEvent > 0.5'
184
185 pi0 = Particle('pi0',
186 MVAConfiguration(variables=['InvM', 'extraInfo(preCut_rank)', 'chiProb', 'abs(BellePi0SigM)',
187 'daughterAngle(0,1)', 'pt', 'pz', 'E'],
188 target='isSignal'),
189 PreCutConfiguration(userCut=pi0_cut,
190 bestCandidateVariable='abs(BellePi0SigM)',
191 bestCandidateCut=20),
192 PostCutConfiguration(bestCandidateCut=10, value=0.01))
193 pi0.addChannel(['pi0:FSP'])
194
195 ks0_cut = '0.4 < M < 0.6'
196 if specific:
197 ks0_cut += ' and isInRestOfEvent > 0.5'
198
199 KS0 = Particle('K_S0',
200 MVAConfiguration(variables=['dr', 'dz', 'distance', 'significanceOfDistance', 'chiProb', 'M', 'abs(dM)',
201 'useCMSFrame(E)', 'daughterAngle(0,1)',
202 'cosAngleBetweenMomentumAndVertexVector',
203 'extraInfo(preCut_rank)', 'extraInfo(goodKs)', 'extraInfo(ksnbVLike)',
204 'extraInfo(ksnbNoLam)', 'extraInfo(ksnbStandard)'],
205 target='isSignal'),
206 PreCutConfiguration(userCut=ks0_cut,
207 bestCandidateVariable='abs(dM)',
208 bestCandidateCut=20),
209 PostCutConfiguration(bestCandidateCut=10, value=0.01))
210 KS0.addChannel(['K_S0:V0'])
211
212 Lam_cut = '0.9 < M < 1.3'
213 if specific:
214 Lam_cut += ' and isInRestOfEvent > 0.5'
215 L0 = Particle('Lambda0',
216 MVAConfiguration(variables=['dr', 'dz', 'distance', 'significanceOfDistance', 'chiProb', 'M', 'abs(dM)',
217 'useCMSFrame(E)', 'daughterAngle(0,1)',
218 'cosAngleBetweenMomentumAndVertexVector',
219 'extraInfo(preCut_rank)', 'extraInfo(goodLambda)', 'extraInfo(ksnbVLike)',
220 'extraInfo(ksnbNoLam)'],
221 target='isSignal'),
222 PreCutConfiguration(userCut=Lam_cut,
223 bestCandidateVariable='abs(dM)',
224 bestCandidateCut=20),
225 PostCutConfiguration(bestCandidateCut=10, value=0.01))
226 L0.addChannel(['Lambda0:V0'])
227
228 else:
229
230 pi0 = Particle('pi0',
231 MVAConfiguration(variables=['M', 'daughter({},extraInfo(SignalProbability))', 'extraInfo(preCut_rank)',
232 'daughterAngle(0,1)', 'pt', 'pz', 'E', 'abs(dM)'],
233 target='isSignal'),
234 PreCutConfiguration(userCut='0.08 < M < 0.18',
235 bestCandidateVariable='abs(dM)',
236 bestCandidateCut=20),
237 PostCutConfiguration(bestCandidateCut=10, value=0.01))
238 pi0.addChannel(['gamma', 'gamma'])
239
240 KS0 = Particle('K_S0',
241 MVAConfiguration(variables=['dr', 'dz', 'distance', 'significanceOfDistance', 'chiProb', 'M', 'abs(dM)',
242 'useCMSFrame(E)', 'daughterAngle(0,1)',
243 'daughter({},extraInfo(SignalProbability))',
244 'useRestFrame(daughter({}, p))', 'cosAngleBetweenMomentumAndVertexVector',
245 'daughter({}, dz)', 'daughter({}, dr)', 'extraInfo(preCut_rank)'],
246 target='isSignal'),
247 PreCutConfiguration(userCut='0.4 < M < 0.6',
248 bestCandidateVariable='abs(dM)',
249 bestCandidateCut=20),
250 PostCutConfiguration(bestCandidateCut=10, value=0.01))
251 KS0.addChannel(['pi+', 'pi-'])
252 KS0.addChannel(['pi0', 'pi0'])
253
254 ks0_cut = '0.4 < M < 0.6'
255 if specific:
256 ks0_cut += ' and isInRestOfEvent > 0.5'
257
258 KS0.addChannel(['K_S0:V0'],
259 MVAConfiguration(variables=['dr', 'dz', 'distance', 'significanceOfDistance', 'chiProb', 'M',
260 'useCMSFrame(E)', 'daughterAngle(0,1)', 'extraInfo(preCut_rank)', 'abs(dM)',
261 'useRestFrame(daughter({}, p))', 'cosAngleBetweenMomentumAndVertexVector',
262 'daughter({}, dz)', 'daughter({}, dr)'],
263 target='isSignal'),
264 PreCutConfiguration(userCut=ks0_cut,
265 bestCandidateVariable='abs(dM)',
266 bestCandidateCut=20))
267
268 L0 = Particle('Lambda0',
269 MVAConfiguration(variables=['dr', 'dz', 'distance', 'significanceOfDistance', 'chiProb', 'M', 'abs(dM)',
270 'useCMSFrame(E)', 'daughterAngle(0,1)',
271 'daughter({},extraInfo(SignalProbability))',
272 'useRestFrame(daughter({}, p))', 'cosAngleBetweenMomentumAndVertexVector',
273 'daughter({}, dz)', 'daughter({}, dr)', 'extraInfo(preCut_rank)'],
274 target='isSignal'),
275 PreCutConfiguration(userCut='0.9 < M < 1.3',
276 bestCandidateVariable='abs(dM)',
277 bestCandidateCut=20),
278 PostCutConfiguration(bestCandidateCut=10, value=0.01))
279 L0.addChannel(['p+', 'pi-'])
280
281 Lam_cut = '0.9 < M < 1.3'
282 if specific:
283 Lam_cut += ' and isInRestOfEvent > 0.5'
284
285 L0.addChannel(['Lambda0:V0'],
286 MVAConfiguration(variables=['dr', 'dz', 'distance', 'significanceOfDistance', 'chiProb', 'M',
287 'useCMSFrame(E)', 'daughterAngle(0,1)', 'extraInfo(preCut_rank)', 'abs(dM)',
288 'useRestFrame(daughter({}, p))', 'cosAngleBetweenMomentumAndVertexVector',
289 'daughter({}, dz)', 'daughter({}, dr)'],
290 target='isSignal'),
291 PreCutConfiguration(userCut=Lam_cut,
292 bestCandidateVariable='abs(dM)',
293 bestCandidateCut=20))
294 kl0_cut = ''
295 if specific:
296 kl0_cut += 'isInRestOfEvent > 0.5'
297
298 KL0 = Particle('K_L0',
299 MVAConfiguration(variables=['E', 'klmClusterTiming'],
300 target='isSignal'),
301 PreCutConfiguration(userCut=kl0_cut,
302 bestCandidateVariable='abs(dM)',
303 bestCandidateCut=20),
304 PostCutConfiguration(bestCandidateCut=10, value=0.01))
305 KL0.addChannel(['K_L0:FSP'])
306
307 SigmaP = Particle('Sigma+',
308 MVAConfiguration(variables=['dr', 'dz', 'distance', 'significanceOfDistance', 'chiProb', 'M', 'abs(dM)',
309 'useCMSFrame(E)', 'daughterAngle(0,1)',
310 'daughter({},extraInfo(SignalProbability))',
311 'useRestFrame(daughter({}, p))', 'cosAngleBetweenMomentumAndVertexVector',
312 'daughter({}, dz)', 'daughter({}, dr)', 'extraInfo(preCut_rank)'],
313 target='isSignal'),
314 PreCutConfiguration(userCut='1.0 < M < 1.4',
315 bestCandidateVariable='abs(dM)',
316 bestCandidateCut=20),
317 PostCutConfiguration(bestCandidateCut=10, value=0.01))
318 SigmaP.addChannel(['p+', 'pi0'])
319 # variables for D mesons and J/Psi
320 intermediate_vars = ['daughterProductOf(extraInfo(SignalProbability))', 'daughter({},extraInfo(SignalProbability))',
321 'chiProb', 'daughter({}, chiProb)', 'extraInfo(preCut_rank)', 'abs(dM)',
322 'useRestFrame(daughter({}, p))',
323 'useRestFrame(daughter({}, distance))',
324 'decayAngle({})', 'daughterAngle({},{})', 'cosAngleBetweenMomentumAndVertexVector',
325 'daughterInvariantMass({},{})', 'daughterInvariantMass({},{},{})', 'daughterInvariantMass({},{},{},{})',
326 'daughterInvariantMass({},{},{},{},{})', 'dQ', 'Q', 'dM', 'daughter({},extraInfo(decayModeID))']
327
328 # TODO if specific:
329 # We can not do this in the generic case (because this would heavily influence our performance on the unknown signal events
330 # but in the specific case this could work well
331 # intermediate_vars = ['nRemainingTracksInEvent']
332 LC = Particle('Lambda_c+',
333 MVAConfiguration(variables=intermediate_vars,
334 target='isSignal'),
335 PreCutConfiguration(userCut='2.2 < M < 2.4',
336 bestCandidateVariable='abs(dM)',
337 bestCandidateCut=20),
338 PostCutConfiguration(bestCandidateCut=10, value=0.001))
339 LC.addChannel(['p+', 'K-', 'pi+'])
340 LC.addChannel(['p+', 'pi-', 'pi+'])
341 LC.addChannel(['p+', 'K-', 'K+'])
342 LC.addChannel(['p+', 'K-', 'pi+', 'pi0'])
343 LC.addChannel(['p+', 'K-', 'pi+', 'pi0', 'pi0'])
344 LC.addChannel(['p+', 'pi+', 'pi+', 'pi-', 'pi-'])
345 LC.addChannel(['p+', 'K_S0'])
346 LC.addChannel(['p+', 'K_S0', 'pi0'])
347 LC.addChannel(['p+', 'K_S0', 'pi+', 'pi-'])
348 LC.addChannel(['Lambda0', 'pi+'])
349 LC.addChannel(['Lambda0', 'pi+', 'pi0'])
350 LC.addChannel(['Lambda0', 'pi+', 'pi-', 'pi+'])
351 LC.addChannel(['Lambda0', 'pi+', 'gamma'])
352 LC.addChannel(['Lambda0', 'pi+', 'pi0', 'gamma'])
353 LC.addChannel(['Lambda0', 'pi+', 'pi-', 'pi+', 'gamma'])
354 LC.addChannel(['Sigma+', 'pi+', 'pi-'])
355 LC.addChannel(['Sigma+', 'pi+', 'pi-', 'pi0'])
356 LC.addChannel(['Sigma+', 'pi0'])
357
358 D0 = Particle('D0',
359 MVAConfiguration(variables=intermediate_vars,
360 target='isSignal'),
361 PreCutConfiguration(userCut='1.7 < M < 1.95',
362 bestCandidateVariable='abs(dM)',
363 bestCandidateCut=20),
364 PostCutConfiguration(bestCandidateCut=10, value=0.001))
365 D0.addChannel(['K-', 'pi+'])
366 D0.addChannel(['K-', 'pi+', 'pi0'])
367 D0.addChannel(['K-', 'pi+', 'pi0', 'pi0'])
368 D0.addChannel(['K-', 'pi+', 'pi+', 'pi-'])
369 D0.addChannel(['K-', 'pi+', 'pi+', 'pi-', 'pi0'])
370 D0.addChannel(['pi-', 'pi+'])
371 D0.addChannel(['pi-', 'pi+', 'pi+', 'pi-'])
372 D0.addChannel(['pi-', 'pi+', 'pi0'])
373 D0.addChannel(['pi-', 'pi+', 'pi0', 'pi0'])
374 D0.addChannel(['K_S0', 'pi0'])
375 D0.addChannel(['K_S0', 'pi+', 'pi-'])
376 D0.addChannel(['K_S0', 'pi+', 'pi-', 'pi0'])
377 D0.addChannel(['K-', 'K+'])
378 D0.addChannel(['K-', 'K+', 'pi0'])
379 D0.addChannel(['K-', 'K+', 'K_S0'])
380
381 if not removeSLD and semileptonic:
382 D0_SL = Particle('D0:semileptonic',
383 MVAConfiguration(variables=intermediate_vars,
384 target='isSignalAcceptMissingNeutrino'),
385 PreCutConfiguration(userCut='',
386 bestCandidateMode='highest',
387 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
388 bestCandidateCut=20),
389 PostCutConfiguration(bestCandidateCut=10, value=0.001))
390
391 D0_SL.addChannel(['K-', 'e+'])
392 D0_SL.addChannel(['K-', 'mu+'])
393 D0_SL.addChannel(['K-', 'pi0', 'e+'])
394 D0_SL.addChannel(['K-', 'pi0', 'mu+'])
395 D0_SL.addChannel(['K_S0', 'pi-', 'e+'])
396 D0_SL.addChannel(['K_S0', 'pi-', 'mu+'])
397
398 if KLong:
399 D0_KL = Particle('D0:KL',
400 MVAConfiguration(variables=intermediate_vars,
401 target='isSignal'),
402 PreCutConfiguration(userCut='',
403 bestCandidateMode='highest',
404 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
405 bestCandidateCut=20),
406 PostCutConfiguration(bestCandidateCut=10, value=0.001))
407
408 D0_KL.addChannel(['K_L0', 'pi0'])
409 D0_KL.addChannel(['K_L0', 'pi+', 'pi-'])
410 D0_KL.addChannel(['K_L0', 'pi+', 'pi-', 'pi0'])
411 D0_KL.addChannel(['K-', 'K+', 'K_L0'])
412
413 DP = Particle('D+',
414 MVAConfiguration(variables=intermediate_vars,
415 target='isSignal'),
416 PreCutConfiguration(userCut='1.7 < M < 1.95',
417 bestCandidateVariable='abs(dM)',
418 bestCandidateCut=20),
419 PostCutConfiguration(bestCandidateCut=10, value=0.001))
420
421 DP.addChannel(['K-', 'pi+', 'pi+'])
422 DP.addChannel(['K-', 'pi+', 'pi+', 'pi0'])
423 DP.addChannel(['K-', 'K+', 'pi+'])
424 DP.addChannel(['K-', 'K+', 'pi+', 'pi0'])
425 DP.addChannel(['pi+', 'pi0'])
426 DP.addChannel(['pi+', 'pi+', 'pi-'])
427 DP.addChannel(['pi+', 'pi+', 'pi-', 'pi0'])
428 DP.addChannel(['K_S0', 'pi+'])
429 DP.addChannel(['K_S0', 'pi+', 'pi0'])
430 DP.addChannel(['K_S0', 'pi+', 'pi+', 'pi-'])
431 DP.addChannel(['K+', 'K_S0', 'K_S0'])
432
433 if not removeSLD and semileptonic:
434 DP_SL = Particle('D+:semileptonic',
435 MVAConfiguration(variables=intermediate_vars,
436 target='isSignalAcceptMissingNeutrino'),
437 PreCutConfiguration(userCut='',
438 bestCandidateMode='highest',
439 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
440 bestCandidateCut=20),
441 PostCutConfiguration(bestCandidateCut=10, value=0.001))
442
443 DP_SL.addChannel(['K_S0', 'e+'])
444 DP_SL.addChannel(['K_S0', 'mu+'])
445 DP_SL.addChannel(['K-', 'pi+', 'e+'])
446 DP_SL.addChannel(['K-', 'pi+', 'mu+'])
447
448 if KLong:
449 DP_KL = Particle('D+:KL',
450 MVAConfiguration(variables=intermediate_vars,
451 target='isSignal'),
452 PreCutConfiguration(userCut='',
453 bestCandidateMode='highest',
454 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
455 bestCandidateCut=20),
456 PostCutConfiguration(bestCandidateCut=10, value=0.001))
457
458 DP_KL.addChannel(['K_L0', 'pi+'])
459 DP_KL.addChannel(['K_L0', 'pi+', 'pi0'])
460 DP_KL.addChannel(['K_L0', 'pi+', 'pi+', 'pi-'])
461 DP_KL.addChannel(['K+', 'K_L0', 'K_S0'])
462 DP_KL.addChannel(['K+', 'K_L0', 'K_L0'])
463
464 Jpsi = Particle('J/psi',
465 MVAConfiguration(variables=intermediate_vars,
466 target='isSignal'),
467 PreCutConfiguration(userCut='2.6 < M < 3.7',
468 bestCandidateVariable='abs(dM)',
469 bestCandidateCut=20),
470 PostCutConfiguration(bestCandidateCut=10, value=0.001))
471
472 Jpsi.addChannel(['e+', 'e-'])
473 Jpsi.addChannel(['mu+', 'mu-'])
474
475 DSP = Particle('D*+',
476 MVAConfiguration(variables=intermediate_vars,
477 target='isSignal'),
478 PreCutConfiguration(userCut='0 < Q < 0.3',
479 bestCandidateVariable='abs(dQ)',
480 bestCandidateCut=20),
481 PostCutConfiguration(bestCandidateCut=10, value=0.001))
482
483 DSP.addChannel(['D0', 'pi+'])
484 DSP.addChannel(['D+', 'pi0'])
485 DSP.addChannel(['D+', 'gamma'])
486
487 if not removeSLD and semileptonic:
488 DSP_SL = Particle('D*+:semileptonic',
489 MVAConfiguration(variables=intermediate_vars,
490 target='isSignalAcceptMissingNeutrino'),
491 PreCutConfiguration(userCut='0 < Q < 0.3',
492 bestCandidateVariable='abs(dQ)',
493 bestCandidateCut=20),
494 PostCutConfiguration(bestCandidateCut=10, value=0.001))
495
496 DSP_SL.addChannel(['D0:semileptonic', 'pi+'])
497 DSP_SL.addChannel(['D+:semileptonic', 'pi0'])
498 DSP_SL.addChannel(['D+:semileptonic', 'gamma'])
499
500 if KLong:
501 DSP_KL = Particle('D*+:KL',
502 MVAConfiguration(variables=intermediate_vars,
503 target='isSignal'),
504 PreCutConfiguration(userCut='0 < Q < 0.3',
505 bestCandidateVariable='abs(dQ)',
506 bestCandidateCut=20),
507 PostCutConfiguration(bestCandidateCut=10, value=0.001))
508
509 DSP_KL.addChannel(['D0:KL', 'pi+'])
510 DSP_KL.addChannel(['D+:KL', 'pi0'])
511 DSP_KL.addChannel(['D+:KL', 'gamma'])
512
513 DS0 = Particle('D*0',
514 MVAConfiguration(variables=intermediate_vars,
515 target='isSignal'),
516 PreCutConfiguration(userCut='0 < Q < 0.3',
517 bestCandidateVariable='abs(dQ)',
518 bestCandidateCut=20),
519 PostCutConfiguration(bestCandidateCut=10, value=0.001))
520
521 DS0.addChannel(['D0', 'pi0'])
522 DS0.addChannel(['D0', 'gamma'])
523
524 if not removeSLD and semileptonic:
525 DS0_SL = Particle('D*0:semileptonic',
526 MVAConfiguration(variables=intermediate_vars,
527 target='isSignalAcceptMissingNeutrino'),
528 PreCutConfiguration(userCut='0 < Q < 0.3',
529 bestCandidateVariable='abs(dQ)',
530 bestCandidateCut=20),
531 PostCutConfiguration(bestCandidateCut=10, value=0.001))
532
533 DS0_SL.addChannel(['D0:semileptonic', 'pi0'])
534 DS0_SL.addChannel(['D0:semileptonic', 'gamma'])
535
536 if KLong:
537 DS0_KL = Particle('D*0:KL',
538 MVAConfiguration(variables=intermediate_vars,
539 target='isSignal'),
540 PreCutConfiguration(userCut='0 < Q < 0.3',
541 bestCandidateVariable='abs(dQ)',
542 bestCandidateCut=20),
543 PostCutConfiguration(bestCandidateCut=10, value=0.001))
544
545 DS0_KL.addChannel(['D0:KL', 'pi0'])
546 DS0_KL.addChannel(['D0:KL', 'gamma'])
547
548 DS = Particle('D_s+',
549 MVAConfiguration(variables=intermediate_vars,
550 target='isSignal'),
551 PreCutConfiguration(userCut='1.68 < M < 2.1',
552 bestCandidateVariable='abs(dM)',
553 bestCandidateCut=20),
554 PostCutConfiguration(bestCandidateCut=10, value=0.001))
555
556 DS.addChannel(['K+', 'K_S0'])
557 DS.addChannel(['K+', 'pi+', 'pi-'])
558 DS.addChannel(['K+', 'K-', 'pi+'])
559 DS.addChannel(['K+', 'K-', 'pi+', 'pi0'])
560 DS.addChannel(['K+', 'K_S0', 'pi+', 'pi-'])
561 DS.addChannel(['K-', 'K_S0', 'pi+', 'pi+'])
562 DS.addChannel(['K+', 'K-', 'pi+', 'pi+', 'pi-'])
563 DS.addChannel(['pi+', 'pi+', 'pi-'])
564 DS.addChannel(['K_S0', 'pi+'])
565 DS.addChannel(['K_S0', 'pi+', 'pi0'])
566
567 if KLong:
568 DS_KL = Particle('D_s+:KL',
569 MVAConfiguration(variables=intermediate_vars,
570 target='isSignal'),
571 PreCutConfiguration(userCut='',
572 bestCandidateMode='highest',
573 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
574 bestCandidateCut=20),
575 PostCutConfiguration(bestCandidateCut=10, value=0.001))
576
577 DS_KL.addChannel(['K+', 'K_L0'])
578 DS_KL.addChannel(['K+', 'K_L0', 'pi+', 'pi-'])
579 DS_KL.addChannel(['K-', 'K_L0', 'pi+', 'pi+'])
580 DS_KL.addChannel(['K_L0', 'pi+'])
581 DS_KL.addChannel(['K_L0', 'pi+', 'pi0'])
582
583 DSS = Particle('D_s*+',
584 MVAConfiguration(variables=intermediate_vars,
585 target='isSignal'),
586 PreCutConfiguration(userCut='0.0 < Q < 0.3',
587 bestCandidateVariable='abs(dQ)',
588 bestCandidateCut=20),
589 PostCutConfiguration(bestCandidateCut=10, value=0.001))
590
591 DSS.addChannel(['D_s+', 'gamma'])
592 DSS.addChannel(['D_s+', 'pi0'])
593
594 if KLong:
595 DSS_KL = Particle('D_s*+:KL',
596 MVAConfiguration(variables=intermediate_vars,
597 target='isSignal'),
598 PreCutConfiguration(userCut='0.0 < Q < 0.3',
599 bestCandidateVariable='abs(dQ)',
600 bestCandidateCut=20),
601 PostCutConfiguration(bestCandidateCut=10, value=0.001))
602
603 DSS_KL.addChannel(['D_s+:KL', 'gamma'])
604 DSS_KL.addChannel(['D_s+:KL', 'pi0'])
605
606 # note: these should not be correlated to Mbc (weak correlation of deltaE is OK)
607 B_vars = ['daughterProductOf(extraInfo(SignalProbability))', 'daughter({},extraInfo(SignalProbability))',
608 'chiProb', 'daughter({}, chiProb)', 'extraInfo(preCut_rank)',
609 'useRestFrame(daughter({}, p))',
610 'useRestFrame(daughter({}, distance))',
611 'decayAngle({})', 'daughterAngle({},{})', 'cosAngleBetweenMomentumAndVertexVector',
612 'dr', 'dz', 'dx', 'dy', 'distance', 'significanceOfDistance', 'deltaE', 'daughter({},extraInfo(decayModeID))']
613
614 hadronic_user_cut = 'Mbc > 5.2 and abs(deltaE) < 0.5'
615 if B_extra_cut is not None:
616 hadronic_user_cut += ' and [' + B_extra_cut + ']'
617
618 BP = Particle('B+',
619 MVAConfiguration(variables=B_vars,
620 target='isSignal'),
621 PreCutConfiguration(userCut=hadronic_user_cut,
622 bestCandidateMode='highest',
623 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
624 bestCandidateCut=20),
625 PostCutConfiguration(bestCandidateCut=20))
626
627 BP.addChannel(['anti-D0', 'pi+'])
628 BP.addChannel(['anti-D0', 'pi+', 'pi0'])
629 BP.addChannel(['anti-D0', 'pi+', 'pi0', 'pi0'])
630 BP.addChannel(['anti-D0', 'pi+', 'pi+', 'pi-'])
631 BP.addChannel(['anti-D0', 'pi+', 'pi+', 'pi-', 'pi0'])
632 BP.addChannel(['anti-D0', 'D+'])
633 BP.addChannel(['anti-D0', 'D+', 'K_S0'])
634 BP.addChannel(['anti-D*0', 'D+', 'K_S0'])
635 BP.addChannel(['anti-D0', 'D*+', 'K_S0'])
636 BP.addChannel(['anti-D*0', 'D*+', 'K_S0'])
637 BP.addChannel(['anti-D0', 'D0', 'K+'])
638 BP.addChannel(['anti-D*0', 'D0', 'K+'])
639 BP.addChannel(['anti-D0', 'D*0', 'K+'])
640 BP.addChannel(['anti-D*0', 'D*0', 'K+'])
641 BP.addChannel(['D_s+', 'anti-D0'])
642 BP.addChannel(['anti-D*0', 'pi+'])
643 BP.addChannel(['anti-D*0', 'pi+', 'pi0'])
644 BP.addChannel(['anti-D*0', 'pi+', 'pi0', 'pi0'])
645 BP.addChannel(['anti-D*0', 'pi+', 'pi+', 'pi-'])
646 BP.addChannel(['anti-D*0', 'pi+', 'pi+', 'pi-', 'pi0'])
647 BP.addChannel(['D_s*+', 'anti-D0'])
648 BP.addChannel(['D_s+', 'anti-D*0'])
649 BP.addChannel(['anti-D0', 'K+'])
650 BP.addChannel(['D-', 'pi+', 'pi+'])
651 BP.addChannel(['D-', 'pi+', 'pi+', 'pi0'])
652 BP.addChannel(['J/psi', 'K+'], preCutConfig=BP.preCutConfig._replace(noBackgroundSampling=True))
653 BP.addChannel(['J/psi', 'K+', 'pi+', 'pi-'])
654 BP.addChannel(['J/psi', 'K+', 'pi0'])
655 BP.addChannel(['J/psi', 'K_S0', 'pi+'])
656 if baryonic:
657 BP.addChannel(['anti-Lambda_c-', 'p+', 'pi+', 'pi0'])
658 BP.addChannel(['anti-Lambda_c-', 'p+', 'pi+', 'pi-', 'pi+'])
659 BP.addChannel(['anti-D0', 'p+', 'anti-p-', 'pi+'])
660 BP.addChannel(['anti-D*0', 'p+', 'anti-p-', 'pi+'])
661 BP.addChannel(['D+', 'p+', 'anti-p-', 'pi+', 'pi-'])
662 BP.addChannel(['D*+', 'p+', 'anti-p-', 'pi+', 'pi-'])
663 BP.addChannel(['anti-Lambda_c-', 'p+', 'pi+'])
664
665 B_SL_vars = ['daughterProductOf(extraInfo(SignalProbability))', 'daughter({},extraInfo(SignalProbability))',
666 'chiProb', 'daughter({}, chiProb)', 'extraInfo(preCut_rank)',
667 'useRestFrame(daughter({}, p))',
668 'useRestFrame(daughter({}, distance))',
669 'cosAngleBetweenMomentumAndVertexVector',
670 'dr', 'dz', 'dx', 'dy', 'distance', 'significanceOfDistance', 'daughter({},extraInfo(decayModeID))']
671
672 semileptonic_user_cut = ''
673 if B_extra_cut is not None:
674 semileptonic_user_cut += B_extra_cut
675
676 BP_SL = Particle('B+:semileptonic',
677 MVAConfiguration(variables=B_SL_vars,
678 target='isSignalAcceptMissingNeutrino'),
679 PreCutConfiguration(userCut=semileptonic_user_cut,
680 bestCandidateMode='highest',
681 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
682 bestCandidateCut=20),
683 PostCutConfiguration(bestCandidateCut=20))
684 BP_SL.addChannel(['anti-D0', 'e+'])
685 BP_SL.addChannel(['anti-D0', 'mu+'])
686 BP_SL.addChannel(['anti-D*0', 'e+'])
687 BP_SL.addChannel(['anti-D*0', 'mu+'])
688 BP_SL.addChannel(['D-', 'pi+', 'e+'])
689 BP_SL.addChannel(['D-', 'pi+', 'mu+'])
690 BP_SL.addChannel(['D*-', 'pi+', 'e+'])
691 BP_SL.addChannel(['D*-', 'pi+', 'mu+'])
692
693 if not removeSLD and semileptonic:
694 BP_SL.addChannel(['anti-D0:semileptonic', 'pi+'])
695 BP_SL.addChannel(['anti-D0:semileptonic', 'pi+', 'pi0'])
696 BP_SL.addChannel(['anti-D0:semileptonic', 'pi+', 'pi0', 'pi0'])
697 BP_SL.addChannel(['anti-D0:semileptonic', 'pi+', 'pi+', 'pi-'])
698 BP_SL.addChannel(['anti-D0:semileptonic', 'pi+', 'pi+', 'pi-', 'pi0'])
699 BP_SL.addChannel(['anti-D0:semileptonic', 'D+'])
700 BP_SL.addChannel(['anti-D0:semileptonic', 'D+', 'K_S0'])
701 BP_SL.addChannel(['anti-D*0:semileptonic', 'D+', 'K_S0'])
702 BP_SL.addChannel(['anti-D0:semileptonic', 'D*+', 'K_S0'])
703 BP_SL.addChannel(['anti-D*0:semileptonic', 'D*+', 'K_S0'])
704 BP_SL.addChannel(['anti-D0:semileptonic', 'D0', 'K+'])
705 BP_SL.addChannel(['anti-D*0:semileptonic', 'D0', 'K+'])
706 BP_SL.addChannel(['anti-D0:semileptonic', 'D*0', 'K+'])
707 BP_SL.addChannel(['anti-D*0:semileptonic', 'D*0', 'K+'])
708 BP_SL.addChannel(['anti-D0', 'D+:semileptonic'])
709 BP_SL.addChannel(['anti-D0', 'D+:semileptonic', 'K_S0'])
710 BP_SL.addChannel(['anti-D*0', 'D+:semileptonic', 'K_S0'])
711 BP_SL.addChannel(['anti-D0', 'D*+:semileptonic', 'K_S0'])
712 BP_SL.addChannel(['anti-D*0', 'D*+:semileptonic', 'K_S0'])
713 BP_SL.addChannel(['anti-D0', 'D0:semileptonic', 'K+'])
714 BP_SL.addChannel(['anti-D*0', 'D0:semileptonic', 'K+'])
715 BP_SL.addChannel(['anti-D0', 'D*0:semileptonic', 'K+'])
716 BP_SL.addChannel(['anti-D*0', 'D*0:semileptonic', 'K+'])
717 BP_SL.addChannel(['D_s+', 'anti-D0:semileptonic'])
718 BP_SL.addChannel(['anti-D*0:semileptonic', 'pi+'])
719 BP_SL.addChannel(['anti-D*0:semileptonic', 'pi+', 'pi0'])
720 BP_SL.addChannel(['anti-D*0:semileptonic', 'pi+', 'pi0', 'pi0'])
721 BP_SL.addChannel(['anti-D*0:semileptonic', 'pi+', 'pi+', 'pi-'])
722 BP_SL.addChannel(['anti-D*0:semileptonic', 'pi+', 'pi+', 'pi-', 'pi0'])
723 BP_SL.addChannel(['D_s*+', 'anti-D0:semileptonic'])
724 BP_SL.addChannel(['D_s+', 'anti-D*0:semileptonic'])
725 BP_SL.addChannel(['anti-D0:semileptonic', 'K+'])
726 BP_SL.addChannel(['D-:semileptonic', 'pi+', 'pi+'])
727 BP_SL.addChannel(['D-:semileptonic', 'pi+', 'pi+', 'pi0'])
728
729 if KLong:
730 BP_KL = Particle('B+:KL',
731 MVAConfiguration(variables=B_vars,
732 target='isSignal'),
733 PreCutConfiguration(userCut=semileptonic_user_cut,
734 bestCandidateMode='highest',
735 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
736 bestCandidateCut=20),
737 PostCutConfiguration(bestCandidateCut=20))
738 BP_KL.addChannel(['anti-D0:KL', 'pi+'])
739 BP_KL.addChannel(['anti-D0:KL', 'pi+', 'pi0'])
740 BP_KL.addChannel(['anti-D0:KL', 'pi+', 'pi0', 'pi0'])
741 BP_KL.addChannel(['anti-D0:KL', 'pi+', 'pi+', 'pi-'])
742 BP_KL.addChannel(['anti-D0:KL', 'pi+', 'pi+', 'pi-', 'pi0'])
743 BP_KL.addChannel(['anti-D0:KL', 'D+'])
744 BP_KL.addChannel(['anti-D0:KL', 'D+', 'K_S0'])
745 BP_KL.addChannel(['anti-D*0:KL', 'D+', 'K_S0'])
746 BP_KL.addChannel(['anti-D0:KL', 'D*+', 'K_S0'])
747 BP_KL.addChannel(['anti-D*0:KL', 'D*+', 'K_S0'])
748 BP_KL.addChannel(['anti-D0:KL', 'D0', 'K+'])
749 BP_KL.addChannel(['anti-D*0:KL', 'D0', 'K+'])
750 BP_KL.addChannel(['anti-D0:KL', 'D*0', 'K+'])
751 BP_KL.addChannel(['anti-D*0:KL', 'D*0', 'K+'])
752 BP_KL.addChannel(['anti-D0', 'D+:KL'])
753 BP_KL.addChannel(['anti-D0', 'D+:KL', 'K_S0'])
754 BP_KL.addChannel(['anti-D*0', 'D+:KL', 'K_S0'])
755 BP_KL.addChannel(['anti-D0', 'D*+:KL', 'K_S0'])
756 BP_KL.addChannel(['anti-D*0', 'D*+:KL', 'K_S0'])
757 BP_KL.addChannel(['anti-D0', 'D0:KL', 'K+'])
758 BP_KL.addChannel(['anti-D*0', 'D0:KL', 'K+'])
759 BP_KL.addChannel(['anti-D0', 'D*0:KL', 'K+'])
760 BP_KL.addChannel(['anti-D*0', 'D*0:KL', 'K+'])
761 BP_KL.addChannel(['D_s+', 'anti-D0:KL'])
762 BP_KL.addChannel(['D_s+:KL', 'anti-D0'])
763 BP_KL.addChannel(['anti-D*0:KL', 'pi+'])
764 BP_KL.addChannel(['anti-D*0:KL', 'pi+', 'pi0'])
765 BP_KL.addChannel(['anti-D*0:KL', 'pi+', 'pi0', 'pi0'])
766 BP_KL.addChannel(['anti-D*0:KL', 'pi+', 'pi+', 'pi-'])
767 BP_KL.addChannel(['anti-D*0:KL', 'pi+', 'pi+', 'pi-', 'pi0'])
768 BP_KL.addChannel(['D_s*+', 'anti-D0:KL'])
769 BP_KL.addChannel(['D_s+', 'anti-D*0:KL'])
770 BP_KL.addChannel(['D_s*+:KL', 'anti-D0'])
771 BP_KL.addChannel(['D_s+:KL', 'anti-D*0'])
772 BP_KL.addChannel(['anti-D0:KL', 'K+'])
773 BP_KL.addChannel(['D-:KL', 'pi+', 'pi+'])
774 BP_KL.addChannel(['D-:KL', 'pi+', 'pi+', 'pi0'])
775 BP_KL.addChannel(['anti-D0', 'D+', 'K_L0'])
776 BP_KL.addChannel(['anti-D*0', 'D+', 'K_L0'])
777 BP_KL.addChannel(['anti-D0', 'D*+', 'K_L0'])
778 BP_KL.addChannel(['anti-D*0', 'D*+', 'K_L0'])
779 BP_KL.addChannel(['J/psi', 'K_L0', 'pi+'])
780
781 B0 = Particle('B0',
782 MVAConfiguration(variables=B_vars,
783 target='isSignal'),
784 PreCutConfiguration(userCut=hadronic_user_cut,
785 bestCandidateMode='highest',
786 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
787 bestCandidateCut=20),
788 PostCutConfiguration(bestCandidateCut=20))
789 B0.addChannel(['D-', 'pi+'])
790 B0.addChannel(['D-', 'pi+', 'pi0'])
791 B0.addChannel(['D-', 'pi+', 'pi0', 'pi0'])
792 B0.addChannel(['D-', 'pi+', 'pi+', 'pi-'])
793 B0.addChannel(['D-', 'pi+', 'pi+', 'pi-', 'pi0'])
794 B0.addChannel(['anti-D0', 'pi+', 'pi-'])
795 B0.addChannel(['D-', 'D0', 'K+'])
796 B0.addChannel(['D-', 'D*0', 'K+'])
797 B0.addChannel(['D*-', 'D0', 'K+'])
798 B0.addChannel(['D*-', 'D*0', 'K+'])
799 B0.addChannel(['D-', 'D+', 'K_S0'])
800 B0.addChannel(['D*-', 'D+', 'K_S0'])
801 B0.addChannel(['D-', 'D*+', 'K_S0'])
802 B0.addChannel(['D*-', 'D*+', 'K_S0'])
803 B0.addChannel(['D_s+', 'D-'])
804 B0.addChannel(['D*-', 'pi+'])
805 B0.addChannel(['D*-', 'pi+', 'pi0'])
806 B0.addChannel(['D*-', 'pi+', 'pi0', 'pi0'])
807 B0.addChannel(['D*-', 'pi+', 'pi+', 'pi-'])
808 B0.addChannel(['D*-', 'pi+', 'pi+', 'pi-', 'pi0'])
809 B0.addChannel(['D_s*+', 'D-'])
810 B0.addChannel(['D_s+', 'D*-'])
811 B0.addChannel(['D_s*+', 'D*-'])
812 B0.addChannel(['J/psi', 'K_S0'], preCutConfig=B0.preCutConfig._replace(noBackgroundSampling=True))
813 B0.addChannel(['J/psi', 'K+', 'pi-'])
814 B0.addChannel(['J/psi', 'K_S0', 'pi+', 'pi-'])
815 if baryonic:
816 B0.addChannel(['anti-Lambda_c-', 'p+', 'pi+', 'pi-'])
817 B0.addChannel(['anti-D0', 'p+', 'anti-p-'])
818 B0.addChannel(['D-', 'p+', 'anti-p-', 'pi+'])
819 B0.addChannel(['D*-', 'p+', 'anti-p-', 'pi+'])
820 B0.addChannel(['anti-D0', 'p+', 'anti-p-', 'pi+', 'pi-'])
821 B0.addChannel(['anti-D*0', 'p+', 'anti-p-', 'pi+', 'pi-'])
822
823 B0_SL = Particle('B0:semileptonic',
824 MVAConfiguration(variables=B_SL_vars,
825 target='isSignalAcceptMissingNeutrino'),
826 PreCutConfiguration(userCut=semileptonic_user_cut,
827 bestCandidateMode='highest',
828 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
829 bestCandidateCut=20),
830 PostCutConfiguration(bestCandidateCut=20))
831 B0_SL.addChannel(['D-', 'e+'])
832 B0_SL.addChannel(['D-', 'mu+'])
833 B0_SL.addChannel(['D*-', 'e+'])
834 B0_SL.addChannel(['D*-', 'mu+'])
835 B0_SL.addChannel(['anti-D0', 'pi-', 'e+'])
836 B0_SL.addChannel(['anti-D0', 'pi-', 'mu+'])
837 B0_SL.addChannel(['anti-D*0', 'pi-', 'e+'])
838 B0_SL.addChannel(['anti-D*0', 'pi-', 'mu+'])
839
840 if not removeSLD and semileptonic:
841 B0_SL.addChannel(['D-:semileptonic', 'pi+'])
842 B0_SL.addChannel(['D-:semileptonic', 'pi+', 'pi0'])
843 B0_SL.addChannel(['D-:semileptonic', 'pi+', 'pi0', 'pi0'])
844 B0_SL.addChannel(['D-:semileptonic', 'pi+', 'pi+', 'pi-'])
845 B0_SL.addChannel(['D-:semileptonic', 'pi+', 'pi+', 'pi-', 'pi0'])
846 B0_SL.addChannel(['anti-D0:semileptonic', 'pi+', 'pi-'])
847 B0_SL.addChannel(['D-:semileptonic', 'D0', 'K+'])
848 B0_SL.addChannel(['D-:semileptonic', 'D*0', 'K+'])
849 B0_SL.addChannel(['D*-:semileptonic', 'D0', 'K+'])
850 B0_SL.addChannel(['D*-:semileptonic', 'D*0', 'K+'])
851 B0_SL.addChannel(['D-:semileptonic', 'D+', 'K_S0'])
852 B0_SL.addChannel(['D*-:semileptonic', 'D+', 'K_S0'])
853 B0_SL.addChannel(['D-:semileptonic', 'D*+', 'K_S0'])
854 B0_SL.addChannel(['D*-:semileptonic', 'D*+', 'K_S0'])
855 B0_SL.addChannel(['D-', 'D0:semileptonic', 'K+'])
856 B0_SL.addChannel(['D-', 'D*0:semileptonic', 'K+'])
857 B0_SL.addChannel(['D*-', 'D0:semileptonic', 'K+'])
858 B0_SL.addChannel(['D*-', 'D*0:semileptonic', 'K+'])
859 B0_SL.addChannel(['D-', 'D+:semileptonic', 'K_S0'])
860 B0_SL.addChannel(['D*-', 'D+:semileptonic', 'K_S0'])
861 B0_SL.addChannel(['D-', 'D*+:semileptonic', 'K_S0'])
862 B0_SL.addChannel(['D*-', 'D*+:semileptonic', 'K_S0'])
863 B0_SL.addChannel(['D_s+', 'D-:semileptonic'])
864 B0_SL.addChannel(['D*-:semileptonic', 'pi+'])
865 B0_SL.addChannel(['D*-:semileptonic', 'pi+', 'pi0'])
866 B0_SL.addChannel(['D*-:semileptonic', 'pi+', 'pi0', 'pi0'])
867 B0_SL.addChannel(['D*-:semileptonic', 'pi+', 'pi+', 'pi-'])
868 B0_SL.addChannel(['D*-:semileptonic', 'pi+', 'pi+', 'pi-', 'pi0'])
869 B0_SL.addChannel(['D_s*+', 'D-:semileptonic'])
870 B0_SL.addChannel(['D_s+', 'D*-:semileptonic'])
871 B0_SL.addChannel(['D_s*+', 'D*-:semileptonic'])
872
873 if KLong:
874 B0_KL = Particle('B0:KL',
875 MVAConfiguration(variables=B_vars,
876 target='isSignal'),
877 PreCutConfiguration(userCut=semileptonic_user_cut,
878 bestCandidateMode='highest',
879 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
880 bestCandidateCut=20),
881 PostCutConfiguration(bestCandidateCut=20))
882 B0_KL.addChannel(['D-:KL', 'pi+'])
883 B0_KL.addChannel(['D-:KL', 'pi+', 'pi0'])
884 B0_KL.addChannel(['D-:KL', 'pi+', 'pi0', 'pi0'])
885 B0_KL.addChannel(['D-:KL', 'pi+', 'pi+', 'pi-'])
886 B0_KL.addChannel(['D-:KL', 'pi+', 'pi+', 'pi-', 'pi0'])
887 B0_KL.addChannel(['anti-D0:KL', 'pi+', 'pi-'])
888 B0_KL.addChannel(['D-:KL', 'D0', 'K+'])
889 B0_KL.addChannel(['D-:KL', 'D*0', 'K+'])
890 B0_KL.addChannel(['D*-:KL', 'D0', 'K+'])
891 B0_KL.addChannel(['D*-:KL', 'D*0', 'K+'])
892 B0_KL.addChannel(['D-:KL', 'D+', 'K_S0'])
893 B0_KL.addChannel(['D*-:KL', 'D+', 'K_S0'])
894 B0_KL.addChannel(['D-:KL', 'D*+', 'K_S0'])
895 B0_KL.addChannel(['D*-:KL', 'D*+', 'K_S0'])
896 B0_KL.addChannel(['D-', 'D0:KL', 'K+'])
897 B0_KL.addChannel(['D-', 'D*0:KL', 'K+'])
898 B0_KL.addChannel(['D*-', 'D0:KL', 'K+'])
899 B0_KL.addChannel(['D*-', 'D*0:KL', 'K+'])
900 B0_KL.addChannel(['D-', 'D+:KL', 'K_S0'])
901 B0_KL.addChannel(['D*-', 'D+:KL', 'K_S0'])
902 B0_KL.addChannel(['D-', 'D*+:KL', 'K_S0'])
903 B0_KL.addChannel(['D*-', 'D*+:KL', 'K_S0'])
904 B0_KL.addChannel(['D_s+', 'D-:KL'])
905 B0_KL.addChannel(['D_s+:KL', 'D-'])
906 B0_KL.addChannel(['D*-:KL', 'pi+'])
907 B0_KL.addChannel(['D*-:KL', 'pi+', 'pi0'])
908 B0_KL.addChannel(['D*-:KL', 'pi+', 'pi0', 'pi0'])
909 B0_KL.addChannel(['D*-:KL', 'pi+', 'pi+', 'pi-'])
910 B0_KL.addChannel(['D*-:KL', 'pi+', 'pi+', 'pi-', 'pi0'])
911 B0_KL.addChannel(['D_s*+', 'D-:KL'])
912 B0_KL.addChannel(['D_s+', 'D*-:KL'])
913 B0_KL.addChannel(['D_s*+', 'D*-:KL'])
914 B0_KL.addChannel(['D_s*+:KL', 'D-'])
915 B0_KL.addChannel(['D_s+:KL', 'D*-'])
916 B0_KL.addChannel(['D_s*+:KL', 'D*-'])
917 B0_KL.addChannel(['D-', 'D+', 'K_L0'])
918 B0_KL.addChannel(['D*-', 'D+', 'K_L0'])
919 B0_KL.addChannel(['D-', 'D*+', 'K_L0'])
920 B0_KL.addChannel(['D*-', 'D*+', 'K_L0'])
921 B0_KL.addChannel(['J/psi', 'K_L0'])
922 B0_KL.addChannel(['J/psi', 'K_L0', 'pi+', 'pi-'])
923
924 # Use deltaE + Mbc - m_(B_s) instead of deltaE since Bs has only one peak here (vs. 3 in deltaE)
925 Bs_vars = ['formula(deltaE+Mbc-5.3669)' if x == 'deltaE' else x for x in B_vars]
926
927 hadronic_bs_user_cut = 'Mbc > 5.3 and abs(formula(deltaE+Mbc-5.3669)) < 0.5'
928 if B_extra_cut is not None:
929 hadronic_bs_user_cut += ' and [' + B_extra_cut + ']'
930
931 BS = Particle('B_s0',
932 MVAConfiguration(variables=Bs_vars,
933 target='isSignal'),
934 PreCutConfiguration(userCut=hadronic_bs_user_cut,
935 bestCandidateMode='highest',
936 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
937 bestCandidateCut=20),
938 PostCutConfiguration(bestCandidateCut=20))
939
940 # Override precut for some channels as this provides better performance
941 tight_precut = BS.preCutConfig._replace(userCut=hadronic_bs_user_cut + ' and abs(formula(deltaE+Mbc-5.3669)) < 0.1')
942
943 # D_s & D*
944 BS.addChannel(['D_s-', 'D_s+'], preCutConfig=tight_precut)
945 BS.addChannel(['D_s*+', 'D_s-'], preCutConfig=tight_precut)
946 BS.addChannel(['D_s*-', 'D_s+'], preCutConfig=tight_precut)
947 BS.addChannel(['D_s*+', 'D_s*-'], preCutConfig=tight_precut)
948 BS.addChannel(['D_s-', 'D+'], preCutConfig=tight_precut)
949 BS.addChannel(['D_s+', 'D*-'])
950 BS.addChannel(['D_s*+', 'D-'])
951 BS.addChannel(['D_s*+', 'D*-'])
952
953 # D_s
954 BS.addChannel(['D_s-', 'K+'])
955 BS.addChannel(['D_s+', 'K-'])
956 BS.addChannel(['D_s-', 'pi+'])
957 BS.addChannel(['D_s-', 'pi+', 'pi+', 'pi-'], preCutConfig=tight_precut)
958 BS.addChannel(['D_s-', 'D0', 'K+'], preCutConfig=tight_precut)
959 BS.addChannel(['D_s-', 'D+', 'K_S0'])
960 BS.addChannel(['D_s-', 'pi+', 'pi0'], preCutConfig=tight_precut) # rho+
961 BS.addChannel(['D_s-', 'D0', 'K+', 'pi0'], preCutConfig=tight_precut) # K*+
962 BS.addChannel(['D_s-', 'D0', 'K_S0', 'pi+']) # K*+
963 BS.addChannel(['D_s-', 'D+', 'K+', 'pi-']) # K*0
964 BS.addChannel(['D_s-', 'D+', 'K_S0', 'pi0']) # K*0
965 BS.addChannel(['D_s-', 'D*0', 'K+'], preCutConfig=tight_precut)
966 BS.addChannel(['D_s-', 'D*+', 'K_S0'])
967 BS.addChannel(['D_s-', 'D*0', 'K+', 'pi0']) # K*+
968 BS.addChannel(['D_s-', 'D*0', 'K_S0', 'pi+']) # K*+
969 BS.addChannel(['D_s-', 'D*+', 'K+', 'pi-']) # K*0
970 BS.addChannel(['D_s-', 'D*+', 'K_S0', 'pi0']) # K*0
971
972 # D_s*
973 BS.addChannel(['D_s*-', 'K+'])
974 BS.addChannel(['D_s*-', 'pi+'])
975 BS.addChannel(['D_s*-', 'D0', 'K+'], preCutConfig=tight_precut)
976 BS.addChannel(['D_s*-', 'D+', 'K_S0'])
977 BS.addChannel(['D_s*-', 'D*0', 'K+'], preCutConfig=tight_precut)
978 BS.addChannel(['D_s*-', 'D*+', 'K_S0'])
979 BS.addChannel(['D_s*-', 'pi+', 'pi+', 'pi-'], preCutConfig=tight_precut)
980 BS.addChannel(['D_s*-', 'pi+', 'pi0'], preCutConfig=tight_precut) # rho+
981 BS.addChannel(['D_s*-', 'D0', 'K+', 'pi0']) # K*+
982 BS.addChannel(['D_s*-', 'D0', 'K_S0', 'pi+']) # K*+
983 BS.addChannel(['D_s*-', 'D+', 'K+', 'pi-']) # K*0
984 BS.addChannel(['D_s*-', 'D+', 'K_S0', 'pi0']) # K*0
985 BS.addChannel(['D_s*-', 'D*0', 'K+', 'pi0']) # K*+
986 BS.addChannel(['D_s*-', 'D*0', 'K_S0', 'pi+']) # K*+
987 BS.addChannel(['D_s*-', 'D*+', 'K+', 'pi-']) # K*0
988 BS.addChannel(['D_s*-', 'D*+', 'K_S0', 'pi0']) # K*0
989
990 # J/Psi
991 BS.addChannel(['J/psi', 'K_S0'])
992 BS.addChannel(['J/psi', 'pi+', 'pi-'])
993 BS.addChannel(['J/psi', 'K+', 'K-'], preCutConfig=BS.preCutConfig._replace(noBackgroundSampling=True)) # Phi
994 BS.addChannel(['J/psi', 'K_S0', 'K-', 'pi+'])
995 BS.addChannel(['J/psi', 'K-', 'K+', 'pi0'])
996 BS.addChannel(['J/psi', 'pi-', 'pi+', 'pi0']) # Eta
997 BS.addChannel(['J/psi', 'pi+', 'pi-', 'pi-', 'pi+', 'pi0']) # Etaprime
998
999 # Other
1000 BS.addChannel(['anti-D*0', 'K_S0'])
1001 BS.addChannel(['anti-D0', 'K_S0'])
1002 BS.addChannel(['anti-D0', 'K-', 'pi+'])
1003
1004 particles = []
1005 particles.append(pion)
1006 particles.append(kaon)
1007 if baryonic:
1008 particles.append(proton)
1009 particles.append(muon)
1010 particles.append(electron)
1011 particles.append(gamma)
1012
1013 particles.append(pi0)
1014 particles.append(KS0)
1015 if baryonic:
1016 particles.append(L0)
1017 particles.append(SigmaP)
1018 particles.append(Jpsi)
1019
1020 particles.append(D0)
1021 particles.append(DP)
1022 particles.append(DS)
1023 if baryonic:
1024 particles.append(LC)
1025
1026 particles.append(DS0)
1027 particles.append(DSP)
1028 particles.append(DSS)
1029
1030 if hadronic:
1031 if neutralB:
1032 particles.append(B0)
1033 if chargedB:
1034 particles.append(BP)
1035
1036 if KLong:
1037 particles.append(KL0)
1038 particles.append(D0_KL)
1039 particles.append(DP_KL)
1040 particles.append(DS_KL)
1041 particles.append(DS0_KL)
1042 particles.append(DSP_KL)
1043 particles.append(DSS_KL)
1044 if neutralB:
1045 particles.append(B0_KL)
1046 if chargedB:
1047 particles.append(BP_KL)
1048
1049 if semileptonic:
1050 if not removeSLD:
1051 particles.append(D0_SL)
1052 particles.append(DP_SL)
1053 particles.append(DS0_SL)
1054 particles.append(DSP_SL)
1055 if neutralB:
1056 particles.append(B0_SL)
1057 if chargedB:
1058 particles.append(BP_SL)
1059
1060 if strangeB:
1061 particles.append(BS)
1062
1063 return particles
1064
1065
1066def get_unittest_channels(specific=False):
1067 chargedVariables = ['electronID', 'extraInfo(preCut_rank)',
1068 'kaonID', 'protonID', 'muonID',
1069 'p', 'pt', 'pz', 'dr', 'dz', 'chiProb']
1070
1071 specific_cut = ''
1072 if specific:
1073 specific_cut = ' and isInRestOfEvent > 0.5'
1074
1075 pion = Particle('pi+',
1076 MVAConfiguration(variables=chargedVariables,
1077 target='isPrimarySignal'),
1078 PreCutConfiguration(userCut='[dr < 2] and [abs(dz) < 4]' + specific_cut,
1079 bestCandidateMode='highest',
1080 bestCandidateVariable='pionID',
1081 bestCandidateCut=20),
1082 PostCutConfiguration(bestCandidateCut=10, value=0.01))
1083 pion.addChannel(['pi+:FSP'])
1084
1085 kaon = Particle('K+',
1086 MVAConfiguration(variables=chargedVariables,
1087 target='isPrimarySignal'),
1088 PreCutConfiguration(userCut='[dr < 2] and [abs(dz) < 4]' + specific_cut,
1089 bestCandidateMode='highest',
1090 bestCandidateVariable='kaonID',
1091 bestCandidateCut=20),
1092 PostCutConfiguration(bestCandidateCut=10, value=0.01))
1093 kaon.addChannel(['K+:FSP'])
1094
1095 muon = Particle('mu+',
1096 MVAConfiguration(variables=chargedVariables,
1097 target='isPrimarySignal'),
1098 PreCutConfiguration(userCut='[dr < 2] and [abs(dz) < 4]' + specific_cut,
1099 bestCandidateVariable='muonID',
1100 bestCandidateMode='highest',
1101 bestCandidateCut=10),
1102 PostCutConfiguration(bestCandidateCut=5, value=0.01))
1103 muon.addChannel(['mu+:FSP'])
1104
1105 gamma = Particle('gamma',
1106 MVAConfiguration(variables=['clusterReg', 'clusterNHits', 'clusterTiming', 'clusterE9E25',
1107 'pt', 'E', 'pz', 'extraInfo(preCut_rank)'],
1108 target='isPrimarySignal'),
1109 PreCutConfiguration(userCut='E > 0.05' + specific_cut,
1110 bestCandidateMode='highest',
1111 bestCandidateVariable='E',
1112 bestCandidateCut=40),
1113 PostCutConfiguration(bestCandidateCut=20, value=0.01))
1114 gamma.addChannel(['gamma:FSP'])
1115 gamma.addChannel(['gamma:V0'],
1116 MVAConfiguration(variables=['pt', 'E', 'pz'],
1117 target='isPrimarySignal'))
1118
1119 pi0 = Particle('pi0',
1120 MVAConfiguration(variables=['M', 'daughter({},extraInfo(SignalProbability))', 'extraInfo(preCut_rank)',
1121 'daughterAngle(0,1)', 'pt', 'pz', 'E', 'abs(dM)'],
1122 target='isSignal'),
1123 PreCutConfiguration(userCut='0.08 < M < 0.18',
1124 bestCandidateVariable='abs(dM)',
1125 bestCandidateCut=20),
1126 PostCutConfiguration(bestCandidateCut=10, value=0.01))
1127 pi0.addChannel(['gamma', 'gamma'])
1128
1129 intermediate_vars = ['daughterProductOf(extraInfo(SignalProbability))', 'daughter({},extraInfo(SignalProbability))',
1130 'chiProb', 'daughter({}, chiProb)', 'extraInfo(preCut_rank)', 'abs(dM)',
1131 'useRestFrame(daughter({}, p))',
1132 'useRestFrame(daughter({}, distance))',
1133 'decayAngle({})', 'daughterAngle({},{})', 'cosAngleBetweenMomentumAndVertexVector',
1134 'daughterInvariantMass({},{})', 'daughterInvariantMass({},{},{})', 'daughterInvariantMass({},{},{},{})',
1135 'daughterInvariantMass({},{},{},{},{})', 'dQ', 'Q', 'dM', 'daughter({},extraInfo(decayModeID))']
1136
1137 D0 = Particle('D0',
1138 MVAConfiguration(variables=intermediate_vars,
1139 target='isSignal'),
1140 PreCutConfiguration(userCut='1.7 < M < 1.95',
1141 bestCandidateVariable='abs(dM)',
1142 bestCandidateCut=20),
1143 PostCutConfiguration(bestCandidateCut=10, value=0.001))
1144 D0.addChannel(['K-', 'pi+'])
1145 D0.addChannel(['K-', 'pi+', 'pi0'])
1146 D0.addChannel(['pi-', 'pi+'])
1147
1148 D0_SL = Particle('D0:semileptonic',
1149 MVAConfiguration(variables=intermediate_vars,
1150 target='isSignalAcceptMissingNeutrino'),
1151 PreCutConfiguration(userCut='',
1152 bestCandidateMode='highest',
1153 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
1154 bestCandidateCut=20),
1155 PostCutConfiguration(bestCandidateCut=10, value=0.001))
1156
1157 D0_SL.addChannel(['K-', 'mu+'])
1158 D0_SL.addChannel(['K-', 'pi0', 'mu+'])
1159
1160 particles = [gamma, muon, pion, kaon, pi0, D0, D0_SL]
1161 return particles
1162
1163
1164def get_fr_channels(convertedFromBelle=False):
1165 """
1166 Get channels of original FR for comparison
1167 @param convertedFromBelle whether to use Belle variables which is necessary for b2bii converted data (default is False)
1168 """
1169
1170 if convertedFromBelle:
1171 # Using Belle specific Variables for e-ID, mu-ID and K-ID
1172 # atcPIDBelle(3,2) is used as K-ID
1173 # atcPIDBelle(4,2) and atcPIDBelle(4,3) are used as pr-ID
1174 chargedVariables = ['eIDBelle',
1175 'atcPIDBelle(3,2)',
1176 'atcPIDBelle(4,2)', 'atcPIDBelle(4,3)',
1177 'muIDBelle',
1178 'p', 'pt', 'pz', 'dr', 'dz', 'chiProb', 'extraInfo(preCut_rank)']
1179 else:
1180 chargedVariables = ['electronID', 'kaonID', 'protonID', 'muonID',
1181 'p', 'pt', 'pz', 'dr', 'dz', 'chiProb', 'extraInfo(preCut_rank)']
1182
1183 charged_user_cut = '[dr < 2] and [abs(dz) < 4]'
1184
1185 pion = Particle('pi+',
1186 MVAConfiguration(variables=chargedVariables,
1187 target='isPrimarySignal'),
1188 PreCutConfiguration(userCut=charged_user_cut,
1189 bestCandidateMode='highest',
1190 bestCandidateVariable='pionID' if not convertedFromBelle else 'atcPIDBelle(2,3)',
1191 bestCandidateCut=20),
1192 PostCutConfiguration(bestCandidateCut=10, value=0.01))
1193 pion.addChannel(['pi+:FSP'])
1194
1195 kaon = Particle('K+',
1196 MVAConfiguration(variables=chargedVariables,
1197 target='isPrimarySignal'),
1198 PreCutConfiguration(userCut=charged_user_cut,
1199 bestCandidateMode='highest',
1200 bestCandidateVariable='kaonID' if not convertedFromBelle else 'atcPIDBelle(3,2)',
1201 bestCandidateCut=20),
1202 PostCutConfiguration(bestCandidateCut=10, value=0.01))
1203 kaon.addChannel(['K+:FSP'])
1204
1205 electron = Particle('e+',
1206 MVAConfiguration(variables=chargedVariables,
1207 target='isPrimarySignal'),
1208 PreCutConfiguration(userCut=charged_user_cut,
1209 bestCandidateMode='highest',
1210 bestCandidateVariable='electronID' if not convertedFromBelle else 'eIDBelle',
1211 bestCandidateCut=10),
1212 PostCutConfiguration(bestCandidateCut=10, value=0.01))
1213 electron.addChannel(['e+:FSP'])
1214
1215 muon = Particle('mu+',
1216 MVAConfiguration(variables=chargedVariables,
1217 target='isPrimarySignal'),
1218 PreCutConfiguration(userCut=charged_user_cut,
1219 bestCandidateMode='highest',
1220 bestCandidateVariable='muonID' if not convertedFromBelle else 'muIDBelle',
1221 bestCandidateCut=10),
1222 PostCutConfiguration(bestCandidateCut=10, value=0.01))
1223 muon.addChannel(['mu+:FSP'])
1224
1225 high_energy_photon = '[[clusterReg == 1 and E > 0.10] or [clusterReg == 2 and E > 0.09] or [clusterReg == 3 and E > 0.16]]'
1226 gamma = Particle('gamma',
1227 MVAConfiguration(variables=['clusterReg', 'clusterNHits', 'clusterTiming', 'extraInfo(preCut_rank)',
1228 'clusterE9E25', 'pt', 'E', 'pz'],
1229 target='isPrimarySignal'),
1230 PreCutConfiguration(userCut=high_energy_photon if not convertedFromBelle else
1231 'goodBelleGamma == 1 and clusterBelleQuality == 0',
1232 bestCandidateMode='highest',
1233 bestCandidateVariable='E',
1234 bestCandidateCut=40),
1235 PostCutConfiguration(bestCandidateCut=20, value=0.01))
1236 gamma.addChannel(['gamma:FSP'])
1237 gamma.addChannel(['gamma:V0'],
1238 MVAConfiguration(variables=['pt', 'E', 'pz', 'extraInfo(preCut_rank)'],
1239 target='isPrimarySignal'),
1240 PreCutConfiguration(userCut='',
1241 bestCandidateMode='highest',
1242 bestCandidateVariable='E',
1243 bestCandidateCut=40))
1244
1245 if convertedFromBelle:
1246
1247 pi0 = Particle('pi0',
1248 MVAConfiguration(variables=['InvM', 'extraInfo(preCut_rank)', 'chiProb', 'abs(BellePi0SigM)',
1249 'daughterAngle(0,1)', 'pt', 'pz', 'E'],
1250 target='isSignal'),
1251 PreCutConfiguration(userCut='0.08 < InvM < 0.18',
1252 bestCandidateVariable='abs(BellePi0SigM)',
1253 bestCandidateCut=20),
1254 PostCutConfiguration(bestCandidateCut=10, value=0.01))
1255 pi0.addChannel(['pi0:FSP'])
1256
1257 KS0 = Particle('K_S0',
1258 MVAConfiguration(variables=['dr', 'dz', 'distance', 'significanceOfDistance', 'chiProb', 'M', 'abs(dM)',
1259 'useCMSFrame(E)', 'daughterAngle(0,1)',
1260 'cosAngleBetweenMomentumAndVertexVector',
1261 'extraInfo(preCut_rank)', 'extraInfo(goodKs)', 'extraInfo(ksnbVLike)',
1262 'extraInfo(ksnbNoLam)', 'extraInfo(ksnbStandard)'],
1263 target='isSignal'),
1264 PreCutConfiguration(userCut='0.4 < M < 0.6',
1265 bestCandidateVariable='abs(dM)',
1266 bestCandidateCut=20),
1267 PostCutConfiguration(bestCandidateCut=10, value=0.01))
1268 KS0.addChannel(['K_S0:V0'])
1269
1270 else:
1271
1272 pi0 = Particle('pi0',
1273 MVAConfiguration(variables=['M', 'daughter({},extraInfo(SignalProbability))', 'extraInfo(preCut_rank)',
1274 'daughterAngle(0,1)', 'pt', 'pz', 'E', 'abs(dM)'],
1275 target='isSignal'),
1276 PreCutConfiguration(userCut='0.08 < M < 0.18',
1277 bestCandidateVariable='abs(dM)',
1278 bestCandidateCut=20),
1279 PostCutConfiguration(bestCandidateCut=10, value=0.01))
1280 pi0.addChannel(['gamma', 'gamma'])
1281
1282 KS0 = Particle('K_S0',
1283 MVAConfiguration(variables=['dr', 'dz', 'distance', 'significanceOfDistance', 'chiProb', 'M', 'abs(dM)',
1284 'useCMSFrame(E)', 'daughterAngle(0,1)',
1285 'daughter({},extraInfo(SignalProbability))',
1286 'useRestFrame(daughter({}, p))', 'cosAngleBetweenMomentumAndVertexVector',
1287 'daughter({}, dz)', 'daughter({}, dr)', 'extraInfo(preCut_rank)'],
1288 target='isSignal'),
1289 PreCutConfiguration(userCut='0.4 < M < 0.6',
1290 bestCandidateVariable='abs(dM)',
1291 bestCandidateCut=20),
1292 PostCutConfiguration(bestCandidateCut=10, value=0.01))
1293 KS0.addChannel(['pi+', 'pi-'])
1294 KS0.addChannel(['pi0', 'pi0'])
1295 KS0.addChannel(['K_S0:V0'],
1296 MVAConfiguration(variables=['dr', 'dz', 'distance', 'significanceOfDistance', 'chiProb', 'M',
1297 'useCMSFrame(E)', 'daughterAngle(0,1)', 'extraInfo(preCut_rank)', 'abs(dM)',
1298 'useRestFrame(daughter({}, p))', 'cosAngleBetweenMomentumAndVertexVector',
1299 'daughter({}, dz)', 'daughter({}, dr)'],
1300 target='isSignal'))
1301
1302 # variables for D mesons and J/Psi
1303 intermediate_vars = ['daughterProductOf(extraInfo(SignalProbability))', 'daughter({},extraInfo(SignalProbability))',
1304 'chiProb', 'daughter({}, chiProb)', 'extraInfo(preCut_rank)', 'abs(dM)',
1305 'useRestFrame(daughter({}, p))',
1306 'useRestFrame(daughter({}, distance))',
1307 'decayAngle({})', 'daughterAngle({},{})', 'cosAngleBetweenMomentumAndVertexVector',
1308 'daughterInvariantMass({},{})', 'daughterInvariantMass({},{},{})', 'daughterInvariantMass({},{},{},{})',
1309 'daughterInvariantMass({},{},{},{},{})', 'dQ', 'Q', 'dM', 'daughter({},extraInfo(decayModeID))']
1310
1311 D0 = Particle('D0',
1312 MVAConfiguration(variables=intermediate_vars,
1313 target='isSignal'),
1314 PreCutConfiguration(userCut='1.7 < M < 1.95',
1315 bestCandidateVariable='abs(dM)',
1316 bestCandidateCut=20),
1317 PostCutConfiguration(bestCandidateCut=10, value=0.001))
1318 D0.addChannel(['K-', 'pi+'])
1319 D0.addChannel(['K-', 'pi+', 'pi0'])
1320 D0.addChannel(['K-', 'pi+', 'pi+', 'pi-'])
1321 D0.addChannel(['pi-', 'pi+'])
1322 D0.addChannel(['pi-', 'pi+', 'pi0'])
1323 D0.addChannel(['K_S0', 'pi0'])
1324 D0.addChannel(['K_S0', 'pi+', 'pi-'])
1325 D0.addChannel(['K_S0', 'pi+', 'pi-', 'pi0'])
1326 D0.addChannel(['K-', 'K+'])
1327 D0.addChannel(['K-', 'K+', 'K_S0'])
1328
1329 DP = Particle('D+',
1330 MVAConfiguration(variables=intermediate_vars,
1331 target='isSignal'),
1332 PreCutConfiguration(userCut='1.7 < M < 1.95',
1333 bestCandidateVariable='abs(dM)',
1334 bestCandidateCut=20),
1335 PostCutConfiguration(bestCandidateCut=10, value=0.001))
1336
1337 DP.addChannel(['K-', 'pi+', 'pi+'])
1338 DP.addChannel(['K-', 'pi+', 'pi+', 'pi0'])
1339 DP.addChannel(['K-', 'K+', 'pi+'])
1340 DP.addChannel(['K-', 'K+', 'pi+', 'pi0'])
1341 DP.addChannel(['K_S0', 'pi+'])
1342 DP.addChannel(['K_S0', 'pi+', 'pi0'])
1343 DP.addChannel(['K_S0', 'pi+', 'pi+', 'pi-'])
1344
1345 Jpsi = Particle('J/psi',
1346 MVAConfiguration(variables=intermediate_vars,
1347 target='isSignal'),
1348 PreCutConfiguration(userCut='2.5 < M < 3.7',
1349 bestCandidateVariable='abs(dM)',
1350 bestCandidateCut=20),
1351 PostCutConfiguration(bestCandidateCut=10, value=0.001))
1352
1353 Jpsi.addChannel(['e+', 'e-'])
1354 Jpsi.addChannel(['mu+', 'mu-'])
1355
1356 DSP = Particle('D*+',
1357 MVAConfiguration(variables=intermediate_vars,
1358 target='isSignal'),
1359 PreCutConfiguration(userCut='0 < Q < 0.3',
1360 bestCandidateVariable='abs(dQ)',
1361 bestCandidateCut=20),
1362 PostCutConfiguration(bestCandidateCut=10, value=0.001))
1363
1364 DSP.addChannel(['D0', 'pi+'])
1365 DSP.addChannel(['D+', 'pi0'])
1366
1367 DS0 = Particle('D*0',
1368 MVAConfiguration(variables=intermediate_vars,
1369 target='isSignal'),
1370 PreCutConfiguration(userCut='0 < Q < 0.3',
1371 bestCandidateVariable='abs(dQ)',
1372 bestCandidateCut=20),
1373 PostCutConfiguration(bestCandidateCut=10, value=0.001))
1374
1375 DS0.addChannel(['D0', 'pi0'])
1376 DS0.addChannel(['D0', 'gamma'])
1377
1378 DS = Particle('D_s+',
1379 MVAConfiguration(variables=intermediate_vars,
1380 target='isSignal'),
1381 PreCutConfiguration(userCut='1.68 < M < 2.1',
1382 bestCandidateVariable='abs(dM)',
1383 bestCandidateCut=20),
1384 PostCutConfiguration(bestCandidateCut=10, value=0.001))
1385
1386 DS.addChannel(['K+', 'K_S0'])
1387 DS.addChannel(['K+', 'pi+', 'pi-'])
1388 DS.addChannel(['K+', 'K-', 'pi+'])
1389 DS.addChannel(['K+', 'K-', 'pi+', 'pi0'])
1390 DS.addChannel(['K+', 'K_S0', 'pi+', 'pi-'])
1391 DS.addChannel(['K-', 'K_S0', 'pi+', 'pi+'])
1392 DS.addChannel(['K+', 'K-', 'pi+', 'pi+', 'pi-'])
1393 DS.addChannel(['pi+', 'pi+', 'pi-'])
1394
1395 DSS = Particle('D_s*+',
1396 MVAConfiguration(variables=intermediate_vars,
1397 target='isSignal'),
1398 PreCutConfiguration(userCut='0.0 < Q < 0.3',
1399 bestCandidateVariable='abs(dQ)',
1400 bestCandidateCut=20),
1401 PostCutConfiguration(bestCandidateCut=10, value=0.001))
1402
1403 DSS.addChannel(['D_s+', 'gamma'])
1404
1405 # note: these should not be correlated to Mbc (weak correlation of deltaE is OK)
1406 B_vars = ['daughterProductOf(extraInfo(SignalProbability))', 'daughter({},extraInfo(SignalProbability))',
1407 'chiProb', 'daughter({}, chiProb)', 'extraInfo(preCut_rank)',
1408 'useRestFrame(daughter({}, p))',
1409 'useRestFrame(daughter({}, distance))',
1410 'decayAngle({})', 'daughterAngle({},{})', 'cosAngleBetweenMomentumAndVertexVector',
1411 'dr', 'dz', 'dx', 'dy', 'distance', 'significanceOfDistance', 'deltaE', 'daughter({},extraInfo(decayModeID))']
1412
1413 hadronic_user_cut = 'Mbc > 5.2 and abs(deltaE) < 0.5'
1414
1415 BP = Particle('B+',
1416 MVAConfiguration(variables=B_vars,
1417 target='isSignal'),
1418 PreCutConfiguration(userCut=hadronic_user_cut,
1419 bestCandidateMode='highest',
1420 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
1421 bestCandidateCut=20),
1422 PostCutConfiguration(bestCandidateCut=20))
1423
1424 BP.addChannel(['anti-D0', 'pi+'])
1425 BP.addChannel(['anti-D0', 'pi+', 'pi0'])
1426 BP.addChannel(['anti-D0', 'pi+', 'pi+', 'pi-'])
1427 BP.addChannel(['anti-D0', 'D+'])
1428 BP.addChannel(['D_s+', 'anti-D0'])
1429 BP.addChannel(['anti-D*0', 'pi+'])
1430 BP.addChannel(['anti-D*0', 'pi+', 'pi0'])
1431 BP.addChannel(['anti-D*0', 'pi+', 'pi+', 'pi-'])
1432 BP.addChannel(['anti-D*0', 'pi+', 'pi+', 'pi-', 'pi0'])
1433 BP.addChannel(['D_s*+', 'anti-D0'])
1434 BP.addChannel(['D_s+', 'anti-D*0'])
1435 BP.addChannel(['anti-D0', 'K+'])
1436 BP.addChannel(['D-', 'pi+', 'pi+'])
1437 BP.addChannel(['J/psi', 'K+'])
1438 BP.addChannel(['J/psi', 'K+', 'pi+', 'pi-'])
1439 BP.addChannel(['J/psi', 'K+', 'pi0'])
1440 BP.addChannel(['J/psi', 'K_S0', 'pi+'])
1441
1442 B0 = Particle('B0',
1443 MVAConfiguration(variables=B_vars,
1444 target='isSignal'),
1445 PreCutConfiguration(userCut=hadronic_user_cut,
1446 bestCandidateMode='highest',
1447 bestCandidateVariable='daughterProductOf(extraInfo(SignalProbability))',
1448 bestCandidateCut=20),
1449 PostCutConfiguration(bestCandidateCut=20))
1450 B0.addChannel(['D-', 'pi+'])
1451 B0.addChannel(['D-', 'pi+', 'pi0'])
1452 B0.addChannel(['D-', 'pi+', 'pi+', 'pi-'])
1453 B0.addChannel(['anti-D0', 'pi0'])
1454 B0.addChannel(['D_s+', 'D-'])
1455 B0.addChannel(['D*-', 'pi+'])
1456 B0.addChannel(['D*-', 'pi+', 'pi0'])
1457 B0.addChannel(['D*-', 'pi+', 'pi+', 'pi-'])
1458 B0.addChannel(['D*-', 'pi+', 'pi+', 'pi-', 'pi0'])
1459 B0.addChannel(['D_s*+', 'D-'])
1460 B0.addChannel(['D_s+', 'D*-'])
1461 B0.addChannel(['D_s*+', 'D*-'])
1462 B0.addChannel(['J/psi', 'K_S0'])
1463 B0.addChannel(['J/psi', 'K+', 'pi-'])
1464 B0.addChannel(['J/psi', 'K_S0', 'pi+', 'pi-'])
1465
1466 particles = []
1467 particles.append(pion)
1468 particles.append(kaon)
1469 particles.append(muon)
1470 particles.append(electron)
1471 particles.append(gamma)
1472
1473 particles.append(pi0)
1474 particles.append(KS0)
1475 particles.append(Jpsi)
1476
1477 particles.append(D0)
1478 particles.append(DP)
1479 particles.append(DS)
1480
1481 particles.append(DS0)
1482 particles.append(DSP)
1483 particles.append(DSS)
1484
1485 particles.append(B0)
1486 particles.append(BP)
1487
1488 return particles
1489
1490
1491def get_mode_names(particle_name: str,
1492 hadronic=True,
1493 semileptonic=False,
1494 removeSLD=True,
1495 remove_list_labels=True,
1496 **channel_kwargs) -> list:
1497 """
1498 Get the ordered list of mode names for a given FEI particle name
1499
1500 Arguments:
1501 particle_name(str): the name of the particle, e.g. B0 or B+
1502 hadronic(bool): whether to include hadronic modes
1503 semileptonic(bool): whether to include semileptonic modes
1504 removeSLD(bool): whether to remove the semileptonic D and D* modes, should be True for FEI skim
1505 remove_list_labels(bool): whether to remove the generic and semileptonic labels from the mode names
1506 channel_kwargs: keyword arguments for get_default_channels
1507
1508 Returns:
1509 list(str): the list of mode names, or empty list if the particle was not found
1510 """
1511 if hadronic and semileptonic:
1512 B2INFO('Both semileptonic and hadronic arguments are set to True, set one of them to False for a more definite result.')
1513 if not hadronic and not semileptonic:
1514 B2INFO('Both semileptonic and hadronic arguments are set to False, set one of them to True for a more definite result.')
1515 return []
1516 channel_kwargs.update({'hadronic': hadronic,
1517 'semileptonic': semileptonic,
1518 'removeSLD': removeSLD
1519 })
1520 channels = get_default_channels(**channel_kwargs)
1521 modes = []
1522 conjugate_name = particle_name.replace('-', '+')
1523 for channel in channels:
1524 if channel.name == particle_name or channel.name == conjugate_name:
1525 modes += [d_channel.label.split(' ==> ')[1] for d_channel in channel.channels]
1526 if remove_list_labels:
1527 modes = [mode.replace(':generic', '').replace(':semileptonic', '') for mode in modes]
1528 return modes
def isB2BII()
Definition: b2bii.py:14