Belle II Software  release-06-01-15
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 import pdg
16 
17 from ROOT import Belle2
18 Const = Belle2.Const
19 
20 # define arrays to interpret cut matrix
21 _chargednames = ['pi', 'K', 'p', 'e', 'mu']
22 _pidnames = ['pionID', 'kaonID', 'protonID', 'electronID', 'muonID']
23 _stdnames = ['all', 'loose', 'loosepid', 'good', 'higheff']
24 _effnames = ['95eff', '90eff', '85eff']
25 # default particle list for stdPi() and similar functions
26 _defaultlist = 'good'
27 _mostLikelyList = 'mostlikely'
28 
29 
30 def _stdChargedEffCuts(particletype, listtype):
31  """
32  Provides the PID cut corresponding to a given efficiency percentile
33 
34  @param particletype type of charged particle (pi, K, p, e, mu)
35  @param listtype efficiency percentile for the list (95eff, 90eff, 85eff)
36  """
37 
38  particleindex = _chargednames.index(particletype)
39  effindex = _effnames.index(listtype)
40 
41  # efficiency cuts = [.95,.90,.85] efficiency; values outside (0,1) mean the cut does not exist and an error will be thrown
42  effcuts = [[0.001, 0.019, 0.098],
43  [5e-6, 0.027, 0.167],
44  [0.000, 0.043, 0.251],
45  [0.093, 0.301, 0.709],
46  [0.187, 0.418, 0.909]]
47  #
48  return effcuts[particleindex][effindex]
49 
50 
51 def stdCharged(particletype, listtype, path):
52  """
53  Function to prepare one of several standardized types of charged particle lists:
54  - 'all' with no cuts on track
55  - 'good' high purity lists for data studies
56  - 'loosepid' loose selections for skimming, PID cut only
57  - 'loose' loose selections for skimming
58  - 'higheff' high efficiency list with loose global ID cut for data studies
59  - 'mostlikely' list with the highest PID likelihood
60  Also the following lists, which may or may not be available depending on the release
61  - '99eff' with 99% selection efficiency (calculated for 1<p<4 GeV) and good track (MC only)
62  - '95eff' with 95% selection efficiency (calculated for 1<p<4 GeV) and good track (MC only)
63  - '90eff' with 90% selection efficiency (calculated for 1<p<4 GeV) and good track (MC only)
64  - '85eff' with 85% selection efficiency (calculated for 1<p<4 GeV) and good track (MC only)
65 
66  @param particletype type of charged particle to make a list of
67  @param listtype name of standard list
68  @param path modules are added to this path
69  """
70 
71  # basic quality cut strings
72  trackQuality = 'thetaInCDCAcceptance and nCDCHits>20'
73  ipCut = 'dr < 0.5 and abs(dz) < 2'
74  goodTrack = trackQuality + ' and ' + ipCut
75 
76  if particletype not in _chargednames:
77  b2.B2ERROR("The requested list is not a standard charged particle. Use one of pi, K, e, mu, p.")
78 
79  if listtype == 'all':
80  ma.fillParticleList(particletype + '+:all', '', True, path=path)
81  elif listtype == 'good':
82  ma.fillParticleList(
83  particletype + '+:good',
84  _pidnames[_chargednames.index(particletype)] + ' > 0.5 and ' + goodTrack,
85  True,
86  path=path)
87  elif listtype == 'loose':
88  ma.fillParticleList(
89  particletype + '+:loose',
90  _pidnames[_chargednames.index(particletype)] + ' > 0.1 and ' + goodTrack,
91  True,
92  path=path)
93  elif listtype == 'loosepid':
94  ma.fillParticleList(
95  particletype + '+:loosepid',
96  _pidnames[_chargednames.index(particletype)] + ' > 0.1',
97  True,
98  path=path)
99  elif listtype == 'higheff':
100  ma.fillParticleList(
101  particletype + '+:higheff',
102  _pidnames[_chargednames.index(particletype)] + ' > 0.002 and ' + goodTrack,
103  True,
104  path=path)
105  elif listtype not in _effnames:
106  b2.B2ERROR("The requested list is not defined. Please refer to the stdCharged documentation.")
107  else:
108  pidcut = _stdChargedEffCuts(particletype, listtype)
109  if 0.0 < pidcut < 1.0:
110  ma.fillParticleList(
111  particletype +
112  '+:' +
113  listtype,
114  _pidnames[_chargednames.index(particletype)] +
115  ' > ' +
116  str(pidcut) +
117  ' and ' +
118  goodTrack,
119  True,
120  path=path)
121  else:
122  b2.B2ERROR('The requested standard particle list ' + particletype +
123  '+:' + listtype + ' is not available in this release.')
124 
125 
126 def stdPi(listtype=_defaultlist, path=None):
127  """
128  Function to prepare standard pion lists, refer to `stdCharged` for details
129 
130  @param listtype name of standard list
131  @param path modules are added to this path
132  """
133  stdCharged('pi', listtype, path)
134 
135 
136 def stdK(listtype=_defaultlist, path=None):
137  """
138  Function to prepare standard kaon lists, refer to `stdCharged` for details
139 
140  @param listtype name of standard list
141  @param path modules are added to this path
142  """
143  stdCharged('K', listtype, path)
144 
145 
146 def stdPr(listtype=_defaultlist, path=None):
147  """
148  Function to prepare standard proton lists, refer to `stdCharged` for details
149 
150  @param listtype name of standard list
151  @param path modules are added to this path
152  """
153  stdCharged('p', listtype, path)
154 
155 
156 def stdLep(pdgId, listtype, method, classification, path=None):
157  """
158  Function to prepare one of several standardized types of lepton (:math:`e,\\mu`) lists:
159 
160  * 'UniformEff60' 60% lepton efficiency list, uniform in a given multi-dimensional parametrisation.
161  * 'UniformEff70' 70% lepton efficiency list, uniform in a given multi-dimensional parametrisation.
162  * 'UniformEff80' 80% lepton efficiency list, uniform in a given multi-dimensional parametrisation.
163  * 'UniformEff90' 90% lepton efficiency list, uniform in a given multi-dimensional parametrisation.
164  * 'UniformEff95' 95% lepton efficiency list, uniform in a given multi-dimensional parametrisation.
165 
166 
167  The function will select particles according to the chosen ``listtype``, and decorate each candidate
168  with the nominal Data/MC :math:`\\ell` ID efficiency and :math:`\\pi,K` fake rate
169  correction factors and their stat, syst uncertainty, reading the info from the Conditions Database.
170 
171  Parameters:
172  pdgId (int): the lepton pdg code.
173  listtype (str): name of standard list. Choose among the above values.
174  method (str): the PID method: 'likelihood' or 'bdt'.
175  classification (str): the type of classifier: 'binary' (one-vs-pion) or 'global' (one-vs-all).
176  path (basf2.Path): modules are added to this path.
177  """
178 
179  std_lepton_list_names = (
180  "UniformEff60",
181  "UniformEff70",
182  "UniformEff80",
183  "UniformEff90",
184  "UniformEff95",
185  )
186 
187  available_methods = ("likelihood", "bdt")
188  available_classificators = ("global", "binary")
189 
190  # We stick to positive pdgId by convention.
191  # Anyway, the particle list will be filled for anti-particles too.
192  pdgId = abs(pdgId)
193 
194  if listtype not in std_lepton_list_names:
195  b2.B2ERROR("The requested lepton list is not defined. Please refer to the stdLep and stdCharged documentation.")
196  return
197 
198  if pdgId not in (Const.electron.getPDGCode(), Const.muon.getPDGCode()):
199  b2.B2ERROR(f"{pdgId} is not that of a light charged lepton.")
200  return
201 
202  if method not in available_methods:
203  b2.B2ERROR(f"method: {method}. Must be any of: {available_methods}.")
204  return
205  if classification not in available_classificators:
206  b2.B2ERROR(f"classification: {classification}. Must be any of: {available_classificators}.")
207  return
208 
209  pid_variables = {
210  "likelihood": {
211  # TEMP: use 'electronID_noTOP' for electrons to circumvent bug in TOP electron PDFs in release 5.
212  "global": "electronID_noTOP" if pdgId == Const.electron.getPDGCode() else "muonID",
213  # TEMP: use 'binaryPID_noTOP' for electrons to circumvent bug in TOP electron PDFs in release 5.
214  "binary": f"binaryPID_noTOP({pdgId}, {Const.pion.getPDGCode()})" if pdgId == Const.electron.getPDGCode() \
215  else f"binaryPID({pdgId}, {Const.pion.getPDGCode()})"
216  },
217  "bdt": {
218  "global": f"pidChargedBDTScore({pdgId}, ALL)",
219  "binary": f"pidPairChargedBDTScore({pdgId}, 211, ALL)"
220  }
221  }
222 
223  # Start creating the particle list, w/o any selection.
224  plistname = f"{pdg.to_name(pdgId)}:{listtype}"
225  ma.fillParticleList(plistname, "", path=path)
226 
227  # The PID variable name, as it appears in the VariableManager.
228  pid_var = pid_variables[method][classification]
229 
230  # Remove non-alphanumeric chars from the variable name, and strip last "_" if present.
231  # This is needed to match the name of the payload in the CDB.
232  pid_var_stripped = re.sub(r"[\W]+", "_", pid_var).rstrip("_")
233 
234  # The names of the payloads w/ efficiency and mis-id corrections.
235  payload_eff = f"ParticleReweighting:{pid_var_stripped}_eff_combination_{listtype}"
236  payload_misid_pi = f"ParticleReweighting:{pid_var_stripped}_misid_pi_combination_{listtype}"
237  payload_misid_K = f"ParticleReweighting:{pid_var_stripped}_misid_K_combination_{listtype}"
238 
239  # Configure weighting module(s).
240  reweighter_eff = path.add_module("ParticleWeighting",
241  particleList=plistname,
242  tableName=payload_eff).set_name(f"ParticleWeighting_eff_{plistname}")
243  reweighter_misid_pi = path.add_module("ParticleWeighting",
244  particleList=plistname,
245  tableName=payload_misid_pi).set_name(f"ParticleWeighting_misid_pi_{plistname}")
246  reweighter_misid_K = path.add_module("ParticleWeighting",
247  particleList=plistname,
248  tableName=payload_misid_K).set_name(f"ParticleWeighting_misid_K_{plistname}")
249 
250  # Apply the PID selection cut, which is read from the efficiency payload.
251  cut = f"{pid_var} > extraInfo({payload_eff}_threshold)"
252  ma.applyCuts(plistname, cut, path=path)
253 
254 
255 def stdE(listtype=_defaultlist, method=None, classification=None, path=None):
256  """ Function to prepare one of several standardized types of electron lists.
257  See the documentation of `stdLep` for details.
258 
259  It also accepts any of the legacy definitions
260  for the ``listtype`` parameter to fall back to the `stdCharged` behaviour:
261 
262  * 'all'
263  * 'good'
264  * 'loosepid'
265  * 'loose'
266  * 'higheff'
267  * '95eff'
268  * '90eff'
269  * '85eff'
270  """
271 
272  if listtype in _stdnames + _effnames:
273  stdCharged("e", listtype, path)
274  return
275 
276  stdLep(Const.electron.getPDGCode(), listtype, method, classification, path=path)
277 
278 
279 def stdMu(listtype=_defaultlist, method=None, classification=None, path=None):
280  """ Function to prepare one of several standardized types of muon lists.
281  See the documentation of `stdLep` for details.
282 
283  It also accepts any of the legacy definitions
284  for the ``listtype`` parameter to fall back to the `stdCharged` behaviour:
285 
286  * 'all'
287  * 'good'
288  * 'loosepid'
289  * 'loose'
290  * 'higheff'
291  * '95eff'
292  * '90eff'
293  * '85eff'
294  """
295 
296  if listtype in _stdnames + _effnames:
297  stdCharged("mu", listtype, path)
298  return
299 
300  stdLep(Const.muon.getPDGCode(), listtype, method, classification, path=path)
301 
302 
303 def stdMostLikely(pidPriors=None, suffix='', custom_cuts='', path=None):
304  """
305  Function to prepare most likely particle lists according to PID likelihood, refer to stdCharged for details
306 
307  @param pidPriors list of 6 float numbers used to reweight PID likelihoods
308  @param suffix string added to the end of particle list names
309  @param custom_cuts custom selection cut string, if empty, standard track quality cuts will be applied
310  @param path modules are added to this path
311  """
312  # Here we need basic track quality cuts to be applied,
313  # otherwise, we get a lot of badly reconstructed particles,
314  # which will end up filled as a random type
315  args = ''
316  if pidPriors is not None:
317  args = str(pidPriors)[1:-1] # remove brackets
318  trackQuality = 'thetaInCDCAcceptance and nCDCHits>20'
319  if custom_cuts != '':
320  trackQuality = custom_cuts
321  for name in _chargednames:
322  ma.fillParticleList(f'{name}+:{_mostLikelyList}{suffix}',
323  f'pidIsMostLikely({args}) > 0 and {trackQuality}', True, path=path)
This class provides a set of constants for the framework.
Definition: Const.h:34