Belle II Software  release-08-01-10
stdCharged.py
1 #!/usr/bin/env python3
2 
3 
10 
11 import re
12 
13 import basf2 as b2
14 import modularAnalysis as ma
15 from variables import variables
16 import pdg
17 
18 from ROOT import Belle2
19 Const = 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 
33 def _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 
54 def 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 
130 def 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 
141 def 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 
152 def 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 
163 def 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
203  for the given working point.
204  In fact, the threshold value for the PID cut in such cases is set to NaN.
205 
206  .. warning::
207  At the moment, the only supported *binary* lepton identification is against the **pion** hypothesis.
208  This implies that, if binary classification is chosen, only :math:`\\pi` fake rate corrections will be added to the
209  resulting particle list.
210 
211  Parameters:
212  pdgId (int): the lepton pdg code.
213  working_point (str): name of the chosen working point that defines the content of the list. Choose among the above values.
214  method (str): the PID method: 'likelihood' or 'bdt'.
215  classification (str): the type of classifier: 'binary' (one-vs-pion) or 'global' (one-vs-all).
216  lid_weights_gt (str): the name identifier of the global tag with the recommended Data/MC correction weights.
217 
218  .. tip::
219  Please refer to the
220  `Lepton ID Confluence page <https://confluence.desy.de/display/BI/Lepton+ID+Performance>`_
221  for info about the recommended global tags.
222 
223  release (Optional[int]): the major release number of the data and MC campaigns considered.
224  If specified, it ensures the correct :math:`\\ell` ID variables are used.
225 
226  .. tip::
227  Please refer to the
228  `Lepton ID Confluence page <https://confluence.desy.de/display/BI/Lepton+ID+Performance>`_
229  for info about lepton identification variables and campaigns.
230 
231  channel_eff (Optional[str]): the channel used to derive the :math:`\\ell` ID efficiency corrections.
232  By default, 'combination' is set, meaning they are obtained by combining results
233  of several hadronic and low multiplicity channels, wherever they overlap.
234 
235  .. tip::
236  Please refer to the
237  `Lepton ID Confluence page <https://confluence.desy.de/display/BI/Lepton+ID+Performance>`_
238  for other possible choices (if any).
239 
240  channel_misid_pi (Optional[str]): the channel used to derive the :math:`\\pi` fake rate corrections.
241  channel_misid_K (Optional[str]): the channel used to derive the :math:`K` fake rate corrections.
242  inputListName (Optional[str]): the name of a pre-existing ``ParticleList`` object (defined as a full ``decayString``,
243  e.g. 'e-:my_input_electrons') of which the standard lepton list will be a subset.
244  For instance, users might want to apply a Bremsstrahlung correction to electrons first,
245  which modifies their 4-momentum, and only later define the subset passing the PID selection,
246  including the appropriate PID weights and uncertainties (which are :math:`p`-dependent).
247  By default, the standard lepton list is created from all ``Track`` objects in the event.
248 
249  .. warning::
250  Do **not** apply any PID selection on the input list, otherwise results could be biased.
251 
252  outputListLabel (Optional[str]): the name of the output lepton list label, i.e.,
253  the string that follows the particle identifier ('e-:', 'mu-:').
254  By default, it is assigned as:
255  ``'{method}_{classification}_{working_point}'``.
256 
257  trainingModeMulticlass (Optional[``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``]): enum identifier
258  of the multi-class (global PID) training mode.
259  See `modularAnalysis.applyChargedPidMVA` docs for available options.
260  trainingModeBinary (Optional[``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``]): enum identifier
261  of the classification (binary PID) training mode.
262  See `modularAnalysis.applyChargedPidMVA` docs for available options.
263  path (basf2.Path): modules are added to this path.
264 
265  Returns:
266  tuple(str, list(str)): the alias for the lepton ID variable, and the list of aliases for the weights.
267  """
268 
269  working_points = (
270  "FixedThresh05",
271  "FixedThresh09",
272  "FixedThresh095",
273  "FixedThresh099",
274  "UniformEff60",
275  "UniformEff70",
276  "UniformEff80",
277  "UniformEff90",
278  "UniformEff95",
279  "UniformPiFR5EM1",
280  "UniformPiFR1EM1",
281  "UniformPiFR5EM2",
282  "UniformPiFR1EM2",
283  "UniformPiFR5EM3",
284  "UniformPiFR1EM3",
285  )
286 
287  available_methods = ("likelihood", "bdt")
288  available_classificators = ("global", "binary")
289 
290  if working_point not in working_points:
291  b2.B2ERROR(f"The requested lepton list working point: {working_point} is not defined. \
292  Please refer to the stdLep and stdCharged documentation.")
293  return None
294 
295  if method not in available_methods:
296  b2.B2ERROR(f"method: {method}. Must be any of: {available_methods}.")
297  return None
298 
299  if classification not in available_classificators:
300  b2.B2ERROR(f"classification: {classification}. Must be any of: {available_classificators}.")
301  return None
302 
303  b2.B2INFO(f"Prepending GT with LID corrections: {lid_weights_gt}")
304  b2.conditions.prepend_globaltag(lid_weights_gt)
305 
306  # We stick to positive pdgId by convention.
307  # Anyway, the particle list will be filled for anti-particles too.
308  lepton = abs(pdgId)
309  lepton_name = pdg.to_name(lepton)
310  electron = Const.electron.getPDGCode()
311  muon = Const.muon.getPDGCode()
312  pion = Const.pion.getPDGCode()
313 
314  if lepton not in (electron, muon):
315  b2.B2ERROR(f"{pdgId} is not that of a light charged lepton.")
316  return None
317 
318  # Declare LID variables (as in the VariableManager), and aliases to match the naming scheme used in the payloads.
319  pid_variables = {
320  "likelihood": {
321  "global": {
322  "var": {
323  electron: "electronID",
324  muon: "muonID",
325  },
326  "alias": {
327  electron: "electronID",
328  muon: "muonID",
329  }
330  },
331  "binary": {
332  "var": {
333  electron: f"binaryPID({electron}, {pion})",
334  muon: f"binaryPID({muon}, {pion})",
335  },
336  "alias": {
337  electron: "binaryPID_e_pi",
338  muon: "binaryPID_mu_pi",
339  }
340  }
341  },
342  "bdt": {
343  "global": {
344  "var": {
345  lepton: f"pidChargedBDTScore({lepton}, ALL)",
346  },
347  "alias": {
348  lepton: re.sub(r"\W+", "", f"pidChargedBDTScore_{lepton_name}"),
349  }
350  },
351  "binary": {
352  "var": {
353  lepton: f"pidPairChargedBDTScore({lepton}, {pion}, ALL)",
354  },
355  "alias": {
356  lepton: re.sub(r"\W+", "", f"pidPairChargedBDTScore_{lepton_name}_pi"),
357  }
358  }
359  }
360  }
361 
362  # Depending on the release associated to the chosen LID recommendations GT,
363  # some variable names and aliases may need to be reset.
364  if int(release) in [5, 6]:
365  if lepton == electron:
366  b2.B2INFO(f"The likelihood-based electron ID in release {release} samples is defined w/o the SVD and the TOP")
367  pid_variables["likelihood"]["global"]["var"][electron] = "electronID_noSVD_noTOP"
368  pid_variables["likelihood"]["global"]["alias"][electron] = "electronID_noSVD_noTOP"
369  pid_variables["likelihood"]["binary"]["var"][electron] = f"binaryElectronID_noSVD_noTOP({pion})"
370  pid_variables["likelihood"]["binary"]["alias"][electron] = "binaryElectronID_noSVD_noTOP_pi"
371  else:
372  b2.B2INFO(f"The likelihood-based muon ID in release {release} samples is defined w/o the SVD")
373  pid_variables["likelihood"]["global"]["var"][muon] = "muonID_noSVD"
374  pid_variables["likelihood"]["global"]["alias"][muon] = "muonID_noSVD"
375  pid_variables["likelihood"]["binary"]["var"][muon] = f"binaryPID_noSVD({muon}, {pion})"
376  pid_variables["likelihood"]["binary"]["alias"][muon] = "binaryMuonID_noSVD_pi"
377 
378  # Create the aliases.
379  pid_var = pid_variables[method][classification]["var"][lepton]
380  pid_alias = pid_variables[method][classification]["alias"][lepton]
381  if pid_alias != pid_var:
382  variables.addAlias(pid_alias, pid_var)
383 
384  # Start creating the particle list, w/o any selection.
385  outputListName = f"{lepton_name}:{method}_{classification}_{working_point}"
386  if outputListLabel is not None:
387  outputListName = f"{lepton_name}:{outputListLabel}"
388 
389  if inputListName is None:
390  ma.fillParticleList(outputListName, "", path=path)
391  else:
392  b2.B2INFO(
393  f"The standard lepton list: '{outputListName}' will be created as a subset \
394  of the following ParticleList: '{inputListName}'")
395  ma.copyList(outputListName, inputListName, path=path)
396 
397  # Here we must run the BDT if requested.
398  if method == "bdt":
399  if classification == "global":
400  ma.applyChargedPidMVA(particleLists=[outputListName],
401  path=path,
402  trainingMode=trainingModeMulticlass)
403  elif classification == "binary":
404  ma.applyChargedPidMVA(particleLists=[outputListName],
405  path=path,
406  binaryHypoPDGCodes=(lepton, pion),
407  trainingMode=trainingModeBinary)
408 
409  # The names of the payloads w/ efficiency and mis-id corrections.
410  payload_eff = f"ParticleReweighting:{pid_alias}_eff_{channel_eff}_{working_point}"
411  payload_misid_pi = f"ParticleReweighting:{pid_alias}_misid_pi_{channel_misid_pi}_{working_point}"
412  payload_misid_K = f"ParticleReweighting:{pid_alias}_misid_K_{channel_misid_K}_{working_point}"
413 
414  # Configure weighting module(s).
415  path.add_module("ParticleWeighting",
416  particleList=outputListName,
417  tableName=payload_eff).set_name(f"ParticleWeighting_eff_{outputListName}")
418  path.add_module("ParticleWeighting",
419  particleList=outputListName,
420  tableName=payload_misid_pi).set_name(f"ParticleWeighting_misid_pi_{outputListName}")
421  if classification == "global":
422  path.add_module("ParticleWeighting",
423  particleList=outputListName,
424  tableName=payload_misid_K).set_name(f"ParticleWeighting_misid_K_{outputListName}")
425 
426  # Apply the PID selection cut, which is read from the efficiency payload.
427  # The '>=' handles extreme cases in which the variable and the threshold value are at a boundary of the PID variable range.
428  cut = f"[{pid_alias} >= extraInfo({payload_eff}_threshold)]"
429  ma.applyCuts(outputListName, cut, path=path)
430 
431  # Define convenience aliases for the nominal weight and up/dn variations.
432  weight_aliases_to_var = {
433  f"weight_{pid_alias}_eff_{working_point}": f"extraInfo({payload_eff}_data_MC_ratio)",
434  f"weight_{pid_alias}_misid_pi_{working_point}": f"extraInfo({payload_misid_pi}_data_MC_ratio)",
435  # These aliases are *absolute* variations.
436  f"weight_{pid_alias}_eff_{working_point}_stat_up": f"extraInfo({payload_eff}_data_MC_uncertainty_stat_up)",
437  f"weight_{pid_alias}_eff_{working_point}_stat_dn": f"extraInfo({payload_eff}_data_MC_uncertainty_stat_dn)",
438  f"weight_{pid_alias}_eff_{working_point}_sys_up": f"extraInfo({payload_eff}_data_MC_uncertainty_sys_up)",
439  f"weight_{pid_alias}_eff_{working_point}_sys_dn": f"extraInfo({payload_eff}_data_MC_uncertainty_sys_dn)",
440  f"weight_{pid_alias}_misid_pi_{working_point}_stat_up": f"extraInfo({payload_misid_pi}_data_MC_uncertainty_stat_up)",
441  f"weight_{pid_alias}_misid_pi_{working_point}_stat_dn": f"extraInfo({payload_misid_pi}_data_MC_uncertainty_stat_dn)",
442  f"weight_{pid_alias}_misid_pi_{working_point}_sys_up": f"extraInfo({payload_misid_pi}_data_MC_uncertainty_sys_up)",
443  f"weight_{pid_alias}_misid_pi_{working_point}_sys_dn": f"extraInfo({payload_misid_pi}_data_MC_uncertainty_sys_dn)",
444  # These aliases are *relative* variations, so they can be multiplied to the nominal
445  # to get the varied weight:
446  #
447  # w_rel_var_up = (1 + w_up/w_nominal)
448  # w_rel_var_dn = (1 - w_dn/w_nominal)
449  #
450  # w_var_up = w_nominal * w_rel_var_up
451  # w_var_dn = w_nominal * w_rel_var_dn
452  f"weight_{pid_alias}_eff_{working_point}_rel_stat_up":
453  f"formula(1+[extraInfo({payload_eff}_data_MC_uncertainty_stat_up)/extraInfo({payload_eff}_data_MC_ratio)])",
454  f"weight_{pid_alias}_eff_{working_point}_rel_stat_dn":
455  f"formula(1-[extraInfo({payload_eff}_data_MC_uncertainty_stat_dn)/extraInfo({payload_eff}_data_MC_ratio)])",
456  f"weight_{pid_alias}_eff_{working_point}_rel_sys_up":
457  f"formula(1+[extraInfo({payload_eff}_data_MC_uncertainty_sys_up)/extraInfo({payload_eff}_data_MC_ratio)])",
458  f"weight_{pid_alias}_eff_{working_point}_rel_sys_dn":
459  f"formula(1-[extraInfo({payload_eff}_data_MC_uncertainty_sys_dn)/extraInfo({payload_eff}_data_MC_ratio)])",
460  f"weight_{pid_alias}_misid_pi_{working_point}_rel_stat_up":
461  f"formula(1+[extraInfo({payload_misid_pi}_data_MC_uncertainty_stat_up)/extraInfo({payload_misid_pi}_data_MC_ratio)])",
462  f"weight_{pid_alias}_misid_pi_{working_point}_rel_stat_dn":
463  f"formula(1-[extraInfo({payload_misid_pi}_data_MC_uncertainty_stat_dn)/extraInfo({payload_misid_pi}_data_MC_ratio)])",
464  f"weight_{pid_alias}_misid_pi_{working_point}_rel_sys_up":
465  f"formula(1+[extraInfo({payload_misid_pi}_data_MC_uncertainty_sys_up)/extraInfo({payload_misid_pi}_data_MC_ratio)])",
466  f"weight_{pid_alias}_misid_pi_{working_point}_rel_sys_dn":
467  f"formula(1-[extraInfo({payload_misid_pi}_data_MC_uncertainty_sys_dn)/extraInfo({payload_misid_pi}_data_MC_ratio)])",
468  }
469  if classification == "global":
470  weight_aliases_to_var.update({
471  f"weight_{pid_alias}_misid_K_{working_point}": f"extraInfo({payload_misid_K}_data_MC_ratio)",
472  #
473  f"weight_{pid_alias}_misid_K_{working_point}_stat_up": f"extraInfo({payload_misid_K}_data_MC_uncertainty_stat_up)",
474  f"weight_{pid_alias}_misid_K_{working_point}_stat_dn": f"extraInfo({payload_misid_K}_data_MC_uncertainty_stat_dn)",
475  f"weight_{pid_alias}_misid_K_{working_point}_sys_up": f"extraInfo({payload_misid_K}_data_MC_uncertainty_sys_up)",
476  f"weight_{pid_alias}_misid_K_{working_point}_sys_dn": f"extraInfo({payload_misid_K}_data_MC_uncertainty_sys_dn)",
477  #
478  f"weight_{pid_alias}_misid_K_{working_point}_rel_stat_up":
479  f"formula(1+[extraInfo({payload_misid_K}_data_MC_uncertainty_stat_up)/extraInfo({payload_misid_K}_data_MC_ratio)])",
480  f"weight_{pid_alias}_misid_K_{working_point}_rel_stat_dn":
481  f"formula(1-[extraInfo({payload_misid_K}_data_MC_uncertainty_stat_dn)/extraInfo({payload_misid_K}_data_MC_ratio)])",
482  f"weight_{pid_alias}_misid_K_{working_point}_rel_sys_up":
483  f"formula(1+[extraInfo({payload_misid_K}_data_MC_uncertainty_sys_up)/extraInfo({payload_misid_K}_data_MC_ratio)])",
484  f"weight_{pid_alias}_misid_K_{working_point}_rel_sys_dn":
485  f"formula(1-[extraInfo({payload_misid_K}_data_MC_uncertainty_sys_dn)/extraInfo({payload_misid_K}_data_MC_ratio)])",
486  })
487 
488  for alias, var in weight_aliases_to_var.items():
489  variables.addAlias(alias, var)
490 
491  return pid_alias, list(weight_aliases_to_var.keys())
492 
493 
494 def stdE(listtype=_defaultlist,
495  method=None,
496  classification=None,
497  lid_weights_gt=None,
498  release=None,
499  channel_eff="combination",
500  channel_misid_pi="combination",
501  channel_misid_K="combination",
502  inputListName=None,
503  outputListLabel=None,
504  trainingModeMulticlass=_TrainingMode.c_Multiclass,
505  trainingModeBinary=_TrainingMode.c_Classification,
506  path=None):
507  """ Function to prepare one of several standardized types of electron lists.
508  See the documentation of `stdLep` for details.
509 
510  It also accepts any of the legacy definitions
511  for the ``listtype`` parameter (aka ``working_point`` in `stdLep`) to fall back to the `stdCharged` behaviour:
512 
513  * 'all'
514  * 'good'
515  * 'loosepid'
516  * 'loose'
517  * 'higheff'
518  * '95eff'
519  * '90eff'
520  * '85eff'
521 
522  Returns:
523  tuple(str, list(str)): the alias for the electron ID variable, and the list of aliases for the weights.
524  """
525 
526  if listtype in _stdnames + _effnames:
527  stdCharged("e", listtype, path)
528  return _pidnames[_chargednames.index("e")], None
529 
530  return stdLep(Const.electron.getPDGCode(), listtype, method, classification, lid_weights_gt,
531  release=release,
532  channel_eff=channel_eff,
533  channel_misid_pi=channel_misid_pi,
534  channel_misid_K=channel_misid_K,
535  inputListName=inputListName,
536  outputListLabel=outputListLabel,
537  trainingModeMulticlass=trainingModeMulticlass,
538  trainingModeBinary=trainingModeBinary,
539  path=path)
540 
541 
542 def stdMu(listtype=_defaultlist,
543  method=None,
544  classification=None,
545  lid_weights_gt=None,
546  release=None,
547  channel_eff="combination",
548  channel_misid_pi="combination",
549  channel_misid_K="combination",
550  inputListName=None,
551  outputListLabel=None,
552  trainingModeMulticlass=_TrainingMode.c_Multiclass,
553  trainingModeBinary=_TrainingMode.c_Classification,
554  path=None):
555  """ Function to prepare one of several standardized types of muon lists.
556  See the documentation of `stdLep` for details.
557 
558  It also accepts any of the legacy definitions
559  for the ``listtype`` parameter (aka ``working_point`` in `stdLep`) to fall back to the `stdCharged` behaviour:
560 
561  * 'all'
562  * 'good'
563  * 'loosepid'
564  * 'loose'
565  * 'higheff'
566  * '95eff'
567  * '90eff'
568  * '85eff'
569 
570  Returns:
571  tuple(str, list(str)): the alias for the muon ID variable, and the list of aliases for the weights.
572  """
573 
574  if listtype in _stdnames + _effnames:
575  stdCharged("mu", listtype, path)
576  return _pidnames[_chargednames.index("mu")], None
577 
578  return stdLep(Const.muon.getPDGCode(), listtype, method, classification, lid_weights_gt,
579  release=release,
580  channel_eff=channel_eff,
581  channel_misid_pi=channel_misid_pi,
582  channel_misid_K=channel_misid_K,
583  inputListName=inputListName,
584  outputListLabel=outputListLabel,
585  trainingModeMulticlass=trainingModeMulticlass,
586  trainingModeBinary=trainingModeBinary,
587  path=path)
588 
589 
590 def stdMostLikely(pidPriors=None, suffix='', custom_cuts='', path=None, writeOut=True):
591  """
592  Function to prepare most likely particle lists according to PID likelihood, refer to stdCharged for details
593 
594  @param pidPriors list of 6 float numbers used to reweight PID likelihoods, for e, mu, pi, K, p and d
595  @param suffix string added to the end of particle list names
596  @param custom_cuts custom selection cut string, if empty, standard track quality cuts will be applied
597  @param path modules are added to this path
598  @param writeOut whether RootOutput module should save the created ParticleList
599  """
600  # Here we need basic track quality cuts to be applied,
601  # otherwise, we get a lot of badly reconstructed particles,
602  # which will end up filled as a random type
603  args = ''
604  if pidPriors is not None:
605  args = str(pidPriors)[1:-1] # remove brackets
606  trackQuality = 'thetaInCDCAcceptance and nCDCHits>20'
607  if custom_cuts != '':
608  trackQuality = custom_cuts
609  for name in _chargednames:
610  ma.fillParticleList(f'{name}+:{_mostLikelyList}{suffix}',
611  f'pidIsMostLikely({args}) > 0 and {trackQuality}', writeOut=writeOut, path=path)
This class provides a set of constants for the framework.
Definition: Const.h:34
def to_name(pdg)
Definition: pdg.py:86