Belle II Software development
stdCharged.py
1#!/usr/bin/env python3
2
3
10
11import re
12
13import basf2 as b2
14import modularAnalysis as ma
15from variables import variables
16import pdg
17
18from ROOT import Belle2
19Const = Belle2.Const
20_TrainingMode = Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode
21
22
23# define arrays to interpret cut matrix
24_chargednames = ['pi', 'K', 'p', 'e', 'mu']
25_pidnames = ['pionID', 'kaonID', 'protonID', 'electronID', 'muonID']
26_stdnames = ['all', 'loose', 'loosepid', 'good', 'higheff']
27_effnames = ['95eff', '90eff', '85eff']
28# default particle list for stdPi() and similar functions
29_defaultlist = 'good'
30_mostLikelyList = 'mostlikely'
31
32
33def _stdChargedEffCuts(particletype, listtype):
34 """
35 Provides the PID cut corresponding to a given efficiency percentile
36
37 @param particletype type of charged particle (pi, K, p, e, mu)
38 @param listtype efficiency percentile for the list (95eff, 90eff, 85eff)
39 """
40
41 particleindex = _chargednames.index(particletype)
42 effindex = _effnames.index(listtype)
43
44 # efficiency cuts = [.95,.90,.85] efficiency; values outside (0,1) mean the cut does not exist and an error will be thrown
45 effcuts = [[0.001, 0.019, 0.098],
46 [5e-6, 0.027, 0.167],
47 [0.000, 0.043, 0.251],
48 [0.093, 0.301, 0.709],
49 [0.187, 0.418, 0.909]]
50 #
51 return effcuts[particleindex][effindex]
52
53
54def stdCharged(particletype, listtype, path, writeOut=True):
55 """
56 Function to prepare one of several standardized types of charged particle lists:
57 - 'all' with no cuts on track
58 - 'good' high purity lists for data studies
59 - 'loosepid' loose selections for skimming, PID cut only
60 - 'loose' loose selections for skimming
61 - 'higheff' high efficiency list with loose global ID cut for data studies
62 - 'mostlikely' list with the highest PID likelihood
63 Also the following lists, which may or may not be available depending on the release
64 - '99eff' with 99% selection efficiency (calculated for 1<p<4 GeV) and good track (MC only)
65 - '95eff' with 95% selection efficiency (calculated for 1<p<4 GeV) and good track (MC only)
66 - '90eff' with 90% selection efficiency (calculated for 1<p<4 GeV) and good track (MC only)
67 - '85eff' with 85% selection efficiency (calculated for 1<p<4 GeV) and good track (MC only)
68
69 @param particletype type of charged particle to make a list of
70 @param listtype name of standard list
71 @param path modules are added to this path
72 @param writeOut whether RootOutput module should save the created ParticleList
73 """
74
75 # basic quality cut strings
76 trackQuality = 'thetaInCDCAcceptance and nCDCHits>20'
77 ipCut = 'dr < 0.5 and abs(dz) < 2'
78 goodTrack = trackQuality + ' and ' + ipCut
79
80 if particletype not in _chargednames:
81 b2.B2ERROR("The requested list is not a standard charged particle. Use one of pi, K, e, mu, p.")
82
83 if listtype == 'all':
84 ma.fillParticleList(particletype + '+:all', '', writeOut=writeOut, path=path)
85 elif listtype == 'good':
86 ma.fillParticleList(
87 particletype + '+:good',
88 _pidnames[_chargednames.index(particletype)] + ' > 0.5 and ' + goodTrack,
89 writeOut=writeOut,
90 path=path)
91 elif listtype == 'loose':
92 ma.fillParticleList(
93 particletype + '+:loose',
94 _pidnames[_chargednames.index(particletype)] + ' > 0.1 and ' + goodTrack,
95 writeOut=writeOut,
96 path=path)
97 elif listtype == 'loosepid':
98 ma.fillParticleList(
99 particletype + '+:loosepid',
100 _pidnames[_chargednames.index(particletype)] + ' > 0.1',
101 writeOut=writeOut,
102 path=path)
103 elif listtype == 'higheff':
104 ma.fillParticleList(
105 particletype + '+:higheff',
106 _pidnames[_chargednames.index(particletype)] + ' > 0.002 and ' + goodTrack,
107 writeOut=writeOut,
108 path=path)
109 elif listtype not in _effnames:
110 b2.B2ERROR("The requested list is not defined. Please refer to the stdCharged documentation.")
111 else:
112 pidcut = _stdChargedEffCuts(particletype, listtype)
113 if 0.0 < pidcut < 1.0:
114 ma.fillParticleList(
115 particletype +
116 '+:' +
117 listtype,
118 _pidnames[_chargednames.index(particletype)] +
119 ' > ' +
120 str(pidcut) +
121 ' and ' +
122 goodTrack,
123 writeOut=writeOut,
124 path=path)
125 else:
126 b2.B2ERROR('The requested standard particle list ' + particletype +
127 '+:' + listtype + ' is not available in this release.')
128
129
130def stdPi(listtype=_defaultlist, path=None, writeOut=True):
131 """
132 Function to prepare standard pion lists, refer to `stdCharged` for details
133
134 @param listtype name of standard list
135 @param path modules are added to this path
136 @param writeOut whether RootOutput module should save the created ParticleList
137 """
138 stdCharged('pi', listtype, path, writeOut)
139
140
141def stdK(listtype=_defaultlist, path=None, writeOut=True):
142 """
143 Function to prepare standard kaon lists, refer to `stdCharged` for details
144
145 @param listtype name of standard list
146 @param path modules are added to this path
147 @param writeOut whether RootOutput module should save the created ParticleList
148 """
149 stdCharged('K', listtype, path, writeOut)
150
151
152def stdPr(listtype=_defaultlist, path=None, writeOut=True):
153 """
154 Function to prepare standard proton lists, refer to `stdCharged` for details
155
156 @param listtype name of standard list
157 @param path modules are added to this path
158 @param writeOut whether RootOutput module should save the created ParticleList
159 """
160 stdCharged('p', listtype, path, writeOut)
161
162
163def stdLep(pdgId,
164 working_point,
165 method,
166 classification,
167 lid_weights_gt,
168 release=None,
169 channel_eff="combination",
170 channel_misid_pi="combination",
171 channel_misid_K="combination",
172 inputListName=None,
173 outputListLabel=None,
174 trainingModeMulticlass=_TrainingMode.c_Multiclass,
175 trainingModeBinary=_TrainingMode.c_Classification,
176 path=None):
177 """
178 Function to prepare one of several standardized types of lepton (:math:`e,\\mu`) lists, with the following working points:
179
180 * 'FixedThresh05', PID cut of > 0.5 for each particle in the list.
181 * 'FixedThresh09', PID cut of > 0.9 for each particle in the list.
182 * 'FixedThresh095', PID cut of > 0.95 for each particle in the list.
183 * 'FixedThresh099', PID cut of > 0.99 for each particle in the list.
184 * 'UniformEff60' 60% lepton efficiency list, uniform in a given multi-dimensional parametrisation.
185 * 'UniformEff70' 70% lepton efficiency list, uniform in a given multi-dimensional parametrisation.
186 * 'UniformEff80' 80% lepton efficiency list, uniform in a given multi-dimensional parametrisation.
187 * 'UniformEff90' 90% lepton efficiency list, uniform in a given multi-dimensional parametrisation.
188 * 'UniformEff95' 95% lepton efficiency list, uniform in a given multi-dimensional parametrisation.
189 * 'UniformPiFR5EM1' 50% pion to lepton fake rate, uniform in a given multi-dimensional parametrisation.
190 * 'UniformPiFR1EM1' 10% pion to lepton fake rate, uniform in a given multi-dimensional parametrisation.
191 * 'UniformPiFR5EM2' 5% pion to lepton fake rate, uniform in a given multi-dimensional parametrisation.
192 * 'UniformPiFR1EM2' 1% pion to lepton fake rate, uniform in a given multi-dimensional parametrisation.
193 * 'UniformPiFR5EM3' 0.5% pion to lepton fake rate, uniform in a given multi-dimensional parametrisation.
194 * 'UniformPiFR1EM3' 0.1% pion to lepton fake rate, uniform in a given multi-dimensional parametrisation.
195
196 The function creates a ``ParticleList``, selecting particles according to the chosen ``working_point``,
197 and decorates each candidate in the list with the nominal Data/MC :math:`\\ell` ID efficiency and
198 :math:`\\pi,K` fake rate correction factors and their stat, syst uncertainty, reading the info
199 from the Conditions Database (CDB) according to the chosen input global tag (GT).
200
201 .. note::
202 Particles will **not** be selected if they are outside the Data/MC *efficiency* corrections' phase space coverage for the given working point.
203 In fact, the threshold value for the PID cut in such cases is set to NaN.
204
205 .. warning::
206 At the moment, the only supported *binary* lepton identification is against the **pion** hypothesis.
207 This implies that, if binary classification is chosen, only :math:`\\pi` fake rate corrections will be added to the
208 resulting particle list.
209
210 Parameters:
211 pdgId (int): the lepton pdg code.
212 working_point (str): name of the chosen working point that defines the content of the list. Choose among the above values.
213 method (str): the PID method: 'likelihood' or 'bdt'.
214 classification (str): the type of classifier: 'binary' (one-vs-pion) or 'global' (one-vs-all).
215 lid_weights_gt (str): the name identifier of the global tag with the recommended Data/MC correction weights.
216
217 .. tip::
218 Please refer to the
219 `Charged PID XWiki page <https://xwiki.desy.de/xwiki/rest/p/fab3e>`_
220 for info about the recommended global tags.
221
222 release (Optional[int]): the major release number of the data and MC campaigns considered.
223 If specified, it ensures the correct :math:`\\ell` ID variables are used.
224
225 .. tip::
226 Please refer to the
227 `Charged PID XWiki page <https://xwiki.desy.de/xwiki/rest/p/fab3e>`_
228 for info about lepton identification variables and campaigns.
229
230 channel_eff (Optional[str]): the channel used to derive the :math:`\\ell` ID efficiency corrections.
231 By default, 'combination' is set, meaning they are obtained by combining results
232 of several hadronic and low multiplicity channels, wherever they overlap.
233
234 .. tip::
235 Please refer to the
236 `Charged PID XWiki page <https://xwiki.desy.de/xwiki/rest/p/fab3e>`_
237 for other possible choices (if any).
238
239 channel_misid_pi (Optional[str]): the channel used to derive the :math:`\\pi` fake rate corrections.
240 channel_misid_K (Optional[str]): the channel used to derive the :math:`K` fake rate corrections.
241 inputListName (Optional[str]): the name of a pre-existing ``ParticleList`` object (defined as a full ``decayString``,
242 e.g. 'e-:my_input_electrons') of which the standard lepton list will be a subset.
243 For instance, users might want to apply a Bremsstrahlung correction to electrons first,
244 which modifies their 4-momentum, and only later define the subset passing the PID selection,
245 including the appropriate PID weights and uncertainties (which are :math:`p`-dependent).
246 By default, the standard lepton list is created from all ``Track`` objects in the event.
247
248 .. warning::
249 Do **not** apply any PID selection on the input list, otherwise results could be biased.
250
251 outputListLabel (Optional[str]): the name of the output lepton list label, i.e.,
252 the string that follows the particle identifier ('e-:', 'mu-:').
253 By default, it is assigned as:
254 ``'{method}_{classification}_{working_point}'``.
255
256 trainingModeMulticlass (Optional[``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``]): enum identifier
257 of the multi-class (global PID) training mode.
258 See `modularAnalysis.applyChargedPidMVA` docs for available options.
259 trainingModeBinary (Optional[``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``]): enum identifier
260 of the classification (binary PID) training mode.
261 See `modularAnalysis.applyChargedPidMVA` docs for available options.
262 path (basf2.Path): modules are added to this path.
263
264 Returns:
265 tuple(str, list(str)): the alias for the lepton ID variable, and the list of aliases for the weights.
266 """
267
268 working_points = (
269 "FixedThresh05",
270 "FixedThresh09",
271 "FixedThresh095",
272 "FixedThresh099",
273 "UniformEff60",
274 "UniformEff70",
275 "UniformEff80",
276 "UniformEff90",
277 "UniformEff95",
278 "UniformPiFR5EM1",
279 "UniformPiFR1EM1",
280 "UniformPiFR5EM2",
281 "UniformPiFR1EM2",
282 "UniformPiFR5EM3",
283 "UniformPiFR1EM3",
284 )
285
286 available_methods = ("likelihood", "bdt")
287 available_classificators = ("global", "binary")
288
289 if working_point not in working_points:
290 b2.B2ERROR(f"The requested lepton list working point: {working_point} is not defined. \
291 Please refer to the stdLep and stdCharged documentation.")
292 return None
293
294 if method not in available_methods:
295 b2.B2ERROR(f"method: {method}. Must be any of: {available_methods}.")
296 return None
297
298 if classification not in available_classificators:
299 b2.B2ERROR(f"classification: {classification}. Must be any of: {available_classificators}.")
300 return None
301
302 b2.B2INFO(f"Prepending GT with LID corrections: {lid_weights_gt}")
303 b2.conditions.prepend_globaltag(lid_weights_gt)
304
305 # We stick to positive pdgId by convention.
306 # Anyway, the particle list will be filled for anti-particles too.
307 lepton = abs(pdgId)
308 lepton_name = pdg.to_name(lepton)
309 electron = Const.electron.getPDGCode()
310 muon = Const.muon.getPDGCode()
311 pion = Const.pion.getPDGCode()
312
313 if lepton not in (electron, muon):
314 b2.B2ERROR(f"{pdgId} is not that of a light charged lepton.")
315 return None
316
317 # Declare LID variables (as in the VariableManager), and aliases to match the naming scheme used in the payloads.
318 pid_variables = {
319 "likelihood": {
320 "global": {
321 "var": {
322 electron: "electronID",
323 muon: "muonID",
324 },
325 "alias": {
326 electron: "electronID",
327 muon: "muonID",
328 }
329 },
330 "binary": {
331 "var": {
332 electron: f"binaryPID({electron}, {pion})",
333 muon: f"binaryPID({muon}, {pion})",
334 },
335 "alias": {
336 electron: "binaryPID_e_pi",
337 muon: "binaryPID_mu_pi",
338 }
339 }
340 },
341 "bdt": {
342 "global": {
343 "var": {
344 lepton: f"pidChargedBDTScore({lepton}, ALL)",
345 },
346 "alias": {
347 lepton: re.sub(r"\W+", "", f"pidChargedBDTScore_{lepton_name}"),
348 }
349 },
350 "binary": {
351 "var": {
352 lepton: f"pidPairChargedBDTScore({lepton}, {pion}, ALL)",
353 },
354 "alias": {
355 lepton: re.sub(r"\W+", "", f"pidPairChargedBDTScore_{lepton_name}_pi"),
356 }
357 }
358 }
359 }
360
361 # Depending on the release associated to the chosen LID recommendations GT,
362 # some variable names and aliases may need to be reset.
363 if int(release) in [5, 6]:
364 if lepton == electron:
365 b2.B2INFO(f"The likelihood-based electron ID in release {release} samples is defined w/o the SVD and the TOP")
366 pid_variables["likelihood"]["global"]["var"][electron] = "electronID_noSVD_noTOP"
367 pid_variables["likelihood"]["global"]["alias"][electron] = "electronID_noSVD_noTOP"
368 pid_variables["likelihood"]["binary"]["var"][electron] = f"binaryElectronID_noSVD_noTOP({pion})"
369 pid_variables["likelihood"]["binary"]["alias"][electron] = "binaryElectronID_noSVD_noTOP_pi"
370 else:
371 b2.B2INFO(f"The likelihood-based muon ID in release {release} samples is defined w/o the SVD")
372 pid_variables["likelihood"]["global"]["var"][muon] = "muonID_noSVD"
373 pid_variables["likelihood"]["global"]["alias"][muon] = "muonID_noSVD"
374 pid_variables["likelihood"]["binary"]["var"][muon] = f"binaryPID_noSVD({muon}, {pion})"
375 pid_variables["likelihood"]["binary"]["alias"][muon] = "binaryMuonID_noSVD_pi"
376
377 # Create the aliases.
378 pid_var = pid_variables[method][classification]["var"][lepton]
379 pid_alias = pid_variables[method][classification]["alias"][lepton]
380 if pid_alias != pid_var:
381 variables.addAlias(pid_alias, pid_var)
382
383 # Start creating the particle list, w/o any selection.
384 outputListName = f"{lepton_name}:{method}_{classification}_{working_point}"
385 if outputListLabel is not None:
386 outputListName = f"{lepton_name}:{outputListLabel}"
387
388 if inputListName is None:
389 ma.fillParticleList(outputListName, "", path=path)
390 else:
391 b2.B2INFO(
392 f"The standard lepton list: '{outputListName}' will be created as a subset \
393 of the following ParticleList: '{inputListName}'")
394 ma.copyList(outputListName, inputListName, path=path)
395
396 # Here we must run the BDT if requested.
397 if method == "bdt":
398 if classification == "global":
399 ma.applyChargedPidMVA(particleLists=[outputListName],
400 path=path,
401 trainingMode=trainingModeMulticlass)
402 elif classification == "binary":
403 ma.applyChargedPidMVA(particleLists=[outputListName],
404 path=path,
405 binaryHypoPDGCodes=(lepton, pion),
406 trainingMode=trainingModeBinary)
407
408 # The names of the payloads w/ efficiency and mis-id corrections.
409 payload_eff = f"ParticleReweighting:{pid_alias}_eff_{channel_eff}_{working_point}"
410 payload_misid_pi = f"ParticleReweighting:{pid_alias}_misid_pi_{channel_misid_pi}_{working_point}"
411
412 # Configure weighting module(s).
413 path.add_module("ParticleWeighting",
414 particleList=outputListName,
415 tableName=payload_eff).set_name(f"ParticleWeighting_eff_{outputListName}")
416 path.add_module("ParticleWeighting",
417 particleList=outputListName,
418 tableName=payload_misid_pi,
419 allowToSkip=True).set_name(f"ParticleWeighting_misid_pi_{outputListName}")
420
421 if classification == "global":
422 payload_misid_K = f"ParticleReweighting:{pid_alias}_misid_K_{channel_misid_K}_{working_point}"
423 path.add_module("ParticleWeighting",
424 particleList=outputListName,
425 tableName=payload_misid_K,
426 allowToSkip=True).set_name(f"ParticleWeighting_misid_K_{outputListName}")
427
428 # Apply the PID selection cut, which is read from the efficiency payload.
429 # The '>=' handles extreme cases in which the variable and the threshold value are at a boundary of the PID variable range.
430 cut = f"[{pid_alias} >= extraInfo({payload_eff}_threshold)]"
431 ma.applyCuts(outputListName, cut, path=path)
432
433 # Define convenience aliases for the nominal weight and up/dn variations.
434 weight_aliases_to_var = {
435 f"weight_{pid_alias}_eff_{working_point}": f"extraInfo({payload_eff}_data_MC_ratio)",
436 f"weight_{pid_alias}_misid_pi_{working_point}": f"extraInfo({payload_misid_pi}_data_MC_ratio)",
437 # These aliases are *absolute* variations.
438 f"weight_{pid_alias}_eff_{working_point}_stat_up": f"extraInfo({payload_eff}_data_MC_uncertainty_stat_up)",
439 f"weight_{pid_alias}_eff_{working_point}_stat_dn": f"extraInfo({payload_eff}_data_MC_uncertainty_stat_dn)",
440 f"weight_{pid_alias}_eff_{working_point}_sys_up": f"extraInfo({payload_eff}_data_MC_uncertainty_sys_up)",
441 f"weight_{pid_alias}_eff_{working_point}_sys_dn": f"extraInfo({payload_eff}_data_MC_uncertainty_sys_dn)",
442 f"weight_{pid_alias}_misid_pi_{working_point}_stat_up": f"extraInfo({payload_misid_pi}_data_MC_uncertainty_stat_up)",
443 f"weight_{pid_alias}_misid_pi_{working_point}_stat_dn": f"extraInfo({payload_misid_pi}_data_MC_uncertainty_stat_dn)",
444 f"weight_{pid_alias}_misid_pi_{working_point}_sys_up": f"extraInfo({payload_misid_pi}_data_MC_uncertainty_sys_up)",
445 f"weight_{pid_alias}_misid_pi_{working_point}_sys_dn": f"extraInfo({payload_misid_pi}_data_MC_uncertainty_sys_dn)",
446 # These aliases are *relative* variations, so they can be multiplied to the nominal
447 # to get the varied weight:
448 #
449 # w_rel_var_up = (1 + w_up/w_nominal)
450 # w_rel_var_dn = (1 - w_dn/w_nominal)
451 #
452 # w_var_up = w_nominal * w_rel_var_up
453 # w_var_dn = w_nominal * w_rel_var_dn
454 f"weight_{pid_alias}_eff_{working_point}_rel_stat_up":
455 f"formula(1+[extraInfo({payload_eff}_data_MC_uncertainty_stat_up)/extraInfo({payload_eff}_data_MC_ratio)])",
456 f"weight_{pid_alias}_eff_{working_point}_rel_stat_dn":
457 f"formula(1-[extraInfo({payload_eff}_data_MC_uncertainty_stat_dn)/extraInfo({payload_eff}_data_MC_ratio)])",
458 f"weight_{pid_alias}_eff_{working_point}_rel_sys_up":
459 f"formula(1+[extraInfo({payload_eff}_data_MC_uncertainty_sys_up)/extraInfo({payload_eff}_data_MC_ratio)])",
460 f"weight_{pid_alias}_eff_{working_point}_rel_sys_dn":
461 f"formula(1-[extraInfo({payload_eff}_data_MC_uncertainty_sys_dn)/extraInfo({payload_eff}_data_MC_ratio)])",
462 f"weight_{pid_alias}_misid_pi_{working_point}_rel_stat_up":
463 f"formula(1+[extraInfo({payload_misid_pi}_data_MC_uncertainty_stat_up)/extraInfo({payload_misid_pi}_data_MC_ratio)])",
464 f"weight_{pid_alias}_misid_pi_{working_point}_rel_stat_dn":
465 f"formula(1-[extraInfo({payload_misid_pi}_data_MC_uncertainty_stat_dn)/extraInfo({payload_misid_pi}_data_MC_ratio)])",
466 f"weight_{pid_alias}_misid_pi_{working_point}_rel_sys_up":
467 f"formula(1+[extraInfo({payload_misid_pi}_data_MC_uncertainty_sys_up)/extraInfo({payload_misid_pi}_data_MC_ratio)])",
468 f"weight_{pid_alias}_misid_pi_{working_point}_rel_sys_dn":
469 f"formula(1-[extraInfo({payload_misid_pi}_data_MC_uncertainty_sys_dn)/extraInfo({payload_misid_pi}_data_MC_ratio)])",
470 }
471 if classification == "global":
472 weight_aliases_to_var.update({
473 f"weight_{pid_alias}_misid_K_{working_point}": f"extraInfo({payload_misid_K}_data_MC_ratio)",
474 #
475 f"weight_{pid_alias}_misid_K_{working_point}_stat_up": f"extraInfo({payload_misid_K}_data_MC_uncertainty_stat_up)",
476 f"weight_{pid_alias}_misid_K_{working_point}_stat_dn": f"extraInfo({payload_misid_K}_data_MC_uncertainty_stat_dn)",
477 f"weight_{pid_alias}_misid_K_{working_point}_sys_up": f"extraInfo({payload_misid_K}_data_MC_uncertainty_sys_up)",
478 f"weight_{pid_alias}_misid_K_{working_point}_sys_dn": f"extraInfo({payload_misid_K}_data_MC_uncertainty_sys_dn)",
479 #
480 f"weight_{pid_alias}_misid_K_{working_point}_rel_stat_up":
481 f"formula(1+[extraInfo({payload_misid_K}_data_MC_uncertainty_stat_up)/extraInfo({payload_misid_K}_data_MC_ratio)])",
482 f"weight_{pid_alias}_misid_K_{working_point}_rel_stat_dn":
483 f"formula(1-[extraInfo({payload_misid_K}_data_MC_uncertainty_stat_dn)/extraInfo({payload_misid_K}_data_MC_ratio)])",
484 f"weight_{pid_alias}_misid_K_{working_point}_rel_sys_up":
485 f"formula(1+[extraInfo({payload_misid_K}_data_MC_uncertainty_sys_up)/extraInfo({payload_misid_K}_data_MC_ratio)])",
486 f"weight_{pid_alias}_misid_K_{working_point}_rel_sys_dn":
487 f"formula(1-[extraInfo({payload_misid_K}_data_MC_uncertainty_sys_dn)/extraInfo({payload_misid_K}_data_MC_ratio)])",
488 })
489
490 for alias, var in weight_aliases_to_var.items():
491 variables.addAlias(alias, var)
492
493 return pid_alias, list(weight_aliases_to_var.keys())
494
495
496def stdE(listtype=_defaultlist,
497 method=None,
498 classification=None,
499 lid_weights_gt=None,
500 release=None,
501 channel_eff="combination",
502 channel_misid_pi="combination",
503 channel_misid_K="combination",
504 inputListName=None,
505 outputListLabel=None,
506 trainingModeMulticlass=_TrainingMode.c_Multiclass,
507 trainingModeBinary=_TrainingMode.c_Classification,
508 path=None):
509 """ Function to prepare one of several standardized types of electron lists.
510 See the documentation of `stdLep` for details.
511
512 It also accepts any of the legacy definitions
513 for the ``listtype`` parameter (aka ``working_point`` in `stdLep`) to fall back to the `stdCharged` behaviour:
514
515 * 'all'
516 * 'good'
517 * 'loosepid'
518 * 'loose'
519 * 'higheff'
520 * '95eff'
521 * '90eff'
522 * '85eff'
523
524 Returns:
525 tuple(str, list(str)): the alias for the electron ID variable, and the list of aliases for the weights.
526 """
527
528 if listtype in _stdnames + _effnames:
529 stdCharged("e", listtype, path)
530 return _pidnames[_chargednames.index("e")], None
531
532 return stdLep(Const.electron.getPDGCode(), listtype, method, classification, lid_weights_gt,
533 release=release,
534 channel_eff=channel_eff,
535 channel_misid_pi=channel_misid_pi,
536 channel_misid_K=channel_misid_K,
537 inputListName=inputListName,
538 outputListLabel=outputListLabel,
539 trainingModeMulticlass=trainingModeMulticlass,
540 trainingModeBinary=trainingModeBinary,
541 path=path)
542
543
544def stdMu(listtype=_defaultlist,
545 method=None,
546 classification=None,
547 lid_weights_gt=None,
548 release=None,
549 channel_eff="combination",
550 channel_misid_pi="combination",
551 channel_misid_K="combination",
552 inputListName=None,
553 outputListLabel=None,
554 trainingModeMulticlass=_TrainingMode.c_Multiclass,
555 trainingModeBinary=_TrainingMode.c_Classification,
556 path=None):
557 """ Function to prepare one of several standardized types of muon lists.
558 See the documentation of `stdLep` for details.
559
560 It also accepts any of the legacy definitions
561 for the ``listtype`` parameter (aka ``working_point`` in `stdLep`) to fall back to the `stdCharged` behaviour:
562
563 * 'all'
564 * 'good'
565 * 'loosepid'
566 * 'loose'
567 * 'higheff'
568 * '95eff'
569 * '90eff'
570 * '85eff'
571
572 Returns:
573 tuple(str, list(str)): the alias for the muon ID variable, and the list of aliases for the weights.
574 """
575
576 if listtype in _stdnames + _effnames:
577 stdCharged("mu", listtype, path)
578 return _pidnames[_chargednames.index("mu")], None
579
580 return stdLep(Const.muon.getPDGCode(), listtype, method, classification, lid_weights_gt,
581 release=release,
582 channel_eff=channel_eff,
583 channel_misid_pi=channel_misid_pi,
584 channel_misid_K=channel_misid_K,
585 inputListName=inputListName,
586 outputListLabel=outputListLabel,
587 trainingModeMulticlass=trainingModeMulticlass,
588 trainingModeBinary=trainingModeBinary,
589 path=path)
590
591
592def stdMostLikely(pidPriors=None, suffix='', custom_cuts='', path=None, writeOut=True):
593 """
594 Function to prepare most likely particle lists according to PID likelihood, refer to stdCharged for details
595
596 @param pidPriors list of 6 float numbers used to reweight PID likelihoods, for e, mu, pi, K, p and d
597 @param suffix string added to the end of particle list names
598 @param custom_cuts custom selection cut string, if empty, standard track quality cuts will be applied
599 @param path modules are added to this path
600 @param writeOut whether RootOutput module should save the created ParticleList
601 """
602 # Here we need basic track quality cuts to be applied,
603 # otherwise, we get a lot of badly reconstructed particles,
604 # which will end up filled as a random type
605 args = ''
606 if pidPriors is not None:
607 args = str(pidPriors)[1:-1] # remove brackets
608 trackQuality = 'thetaInCDCAcceptance and nCDCHits>20'
609 if custom_cuts != '':
610 trackQuality = custom_cuts
611 for name in _chargednames:
612 ma.fillParticleList(f'{name}+:{_mostLikelyList}{suffix}',
613 f'pidIsMostLikely({args}) > 0 and {trackQuality}', writeOut=writeOut, path=path)
614
This class provides a set of constants for the framework.
Definition: Const.h:34
def to_name(pdg)
Definition: pdg.py:87