Belle II Software  release-06-00-14
registry.py
1 # !/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 from importlib import import_module
13 import pandas as pd
14 
15 from basf2 import B2ERROR
16 
17 from tabulate import tabulate
18 
19 
20 _RegisteredSkims = [
21  # --- WG0: Systematics ---
22  ("10000000", "systematics", "Random"),
23  # ("10600100", "systematics", "Systematics"), renamed to SystematicsDstar.
24  ("10600300", "systematics", "SystematicsTracking"),
25  ("10600400", "systematics", "Resonance"),
26  ("10600500", "systematics", "SystematicsRadMuMu"),
27  ("10600600", "systematics", "SystematicsEELL"),
28  ("10600700", "systematics", "SystematicsRadEE"),
29  ("10620200", "systematics", "SystematicsLambda"),
30  ("11640100", "systematics", "SystematicsPhiGamma"),
31  ("10600800", "systematics", "SystematicsFourLeptonFromHLTFlag"),
32  ("10600900", "systematics", "SystematicsRadMuMuFromHLTFlag"),
33  ("10611000", "systematics", "SystematicsJpsi"),
34  ("10611100", "systematics", "SystematicsKshort"),
35  ("10601200", "systematics", "SystematicsBhabha"),
36  ("10601300", "systematics", "SystematicsCombinedHadronic"),
37  ("10601400", "systematics", "SystematicsCombinedLowMulti"),
38  ("10601500", "systematics", "SystematicsDstar"),
39 
40  # --- WG1: SL + missing energy ---
41  ("11110100", "semileptonic", "PRsemileptonicUntagged"),
42  ("11130300", "leptonic", "LeptonicUntagged"),
43  ("11130301", "leptonic", "dilepton"),
44  ("11160200", "semileptonic", "SLUntagged"),
45  ("11160201", "semileptonic", "B0toDstarl_Kpi_Kpipi0_Kpipipi"),
46  ("11180100", "fei", "feiHadronicB0"),
47  ("11180200", "fei", "feiHadronicBplus"),
48  ("11180300", "fei", "feiSLB0"),
49  ("11180400", "fei", "feiSLBplus"),
50  ("11180500", "fei", "feiHadronic"),
51  ("11180600", "fei", "feiSL"),
52 
53  # --- WG2: Electroweak penguins ---
54  ("12160100", "ewp", "BtoXgamma"),
55  ("12160200", "ewp", "BtoXll"),
56  ("12160300", "ewp", "BtoXll_LFV"),
57  ("12160400", "ewp", "inclusiveBplusToKplusNuNu"),
58 
59  # --- WG3: Time-dependent CP violation ---
60  ("13160200", "tdcpv", "TDCPV_ccs"),
61  ("13160300", "tdcpv", "TDCPV_qqs"),
62 
63  # --- WG4: Charmed B decays ---
64  ("14120300", "btocharm", "BtoD0h_Kspi0"),
65  ("14120400", "btocharm", "BtoD0h_Kspipipi0"),
66  # B0 -> D-(k+ ""- pi-)pi+ # ("14140500", "", "BtoD0h_Kspi0pi0"),
67  # Add when skim script is ready
68  ("14120600", "btocharm", "B0toDpi_Kpipi"),
69  ("14120601", "btocharm", "B0toDpi_Kspi"), # B0 -> D-(Ks pi-)pi+
70  # B0 -> D*-(anti-D0 pi-)pi+ With anti-D0 -> k+ pi-
71  ("14120700", "btocharm", "B0toDstarPi_D0pi_Kpi"),
72  # merge B0 -> D*-(anti-D0 pi-)pi+ with anti-D0 -> k- pi+ pi+ pi-
73  # and anti-D0 -> K- pi+ pi0
74  ("14120800", "btocharm", "B0toDstarPi_D0pi_Kpipipi_Kpipi0"),
75  ("14121100", "btocharm", "B0toDrho_Kpipi"),
76  ("14121101", "btocharm", "B0toDrho_Kspi"),
77  ("14121200", "btocharm", "B0toDstarRho_D0pi_Kpi"),
78  ("14121201", "btocharm", "B0toDstarRho_D0pi_Kpipipi_Kpipi0"),
79  ("14140100", "btocharm", "BtoD0h_hh"),
80  ("14140101", "btocharm", "BtoD0h_Kpi"),
81  # B+ -> anti-D0/anti-D0* (K- pi+ pi+ pi-, K- ""+ pi0) h+
82  ("14140102", "btocharm", "BtoD0h_Kpipipi_Kpipi0"),
83  ("14140200", "btocharm", "BtoD0h_Kshh"),
84  ("14141000", "btocharm", "BtoD0rho_Kpi"),
85  ("14141001", "btocharm", "BtoD0rho_Kpipipi_Kpipi0"),
86  ("14141002", "btocharm", "B0toDD_Kpipi_Kspi"),
87  ("14141003", "btocharm", "B0toDstarD"),
88  ("14121300", "btocharm", "B0toD0Kpipi0_pi0"),
89 
90 
91  # --- WG5: Quarkonium ---
92  ("15410300", "quarkonium", "InclusiveLambda"),
93  ("15420100", "quarkonium", "BottomoniumEtabExclusive"),
94  ("15440100", "quarkonium", "BottomoniumUpsilon"),
95  # ("16460100", "quarkonium", "ISRpipicc"), Subset of 16460200, deleted.
96  ("16460200", "quarkonium", "CharmoniumPsi"),
97 
98  # --- WG7: Charm physics ---
99  ("17230100", "charm", "XToD0_D0ToHpJm"), # D0 -> K pi/pi pi/K K
100  # D0 -> pi0 pi0/Ks pi0/Ks Ks # ("17230100", "", "D0ToHpJm"),
101  # D0 -> K pi/pi pi/K K
102  ("17230200", "charm", "XToD0_D0ToNeutrals"),
103  ("17230300", "charm", "DstToD0Pi_D0ToRare"), # D0 -> g g/e e/mu mu
104  ("17230400", "charm", "XToDp_DpToKsHp"), # D+ -> Ks h+
105  ("17230500", "charm", "XToDp_DpToHpHmJp"), # D+ -> h+ h- j+
106  ("17230600", "charm", "LambdacTopHpJm"), # Lambda_c+ -> proton h- j+
107  ("17240100", "charm", "DstToD0Pi_D0ToHpJm"), # D* -> D0 -> K pi/pi pi/K K
108  # D* -> D0 -> K- pi+ pi0 (""+WS)
109  ("17240200", "charm", "DstToD0Pi_D0ToHpJmPi0"),
110  ("17240300", "charm", "DstToD0Pi_D0ToHpHmPi0"), # D* -> D0 -> h h pi0
111  # D* -> D0 -> Ks omega / Ks eta -> Ks pi+ pi- pi0
112  ("17240400", "charm", "DstToD0Pi_D0ToKsOmega"),
113  # D* -> D0 -> K- pi+ eta (""+WS)
114  ("17240500", "charm", "DstToD0Pi_D0ToHpJmEta"),
115  # D* -> D0 -> pi0 pi0/Ks pi0/Ks Ks
116  ("17240600", "charm", "DstToD0Pi_D0ToNeutrals"),
117  ("17240700", "charm", "DstToD0Pi_D0ToHpJmKs"), # D* -> D0 -> h h Ks
118  # D* -> D0 -> K- pi+ pi0 (""+WS)
119  ("17240800", "charm", "EarlyData_DstToD0Pi_D0ToHpJmPi0"),
120  ("17240900", "charm", "EarlyData_DstToD0Pi_D0ToHpHmPi0"), # D* -> D0 -> h h pi0
121  ("17241000", "charm", "DstToDpPi0_DpToHpPi0"), # D*+ -> D+ pi0, D+ -> h+ pi0
122  ("17241100", "charm", "DstToD0Pi_D0ToHpHmHpJm"), # D* -> D0 -> h h h j
123 
124  # --- WG8: Dark matter searches and tau physics ---
125  ("18020100", "dark", "SinglePhotonDark"),
126  ("18020200", "dark", "GammaGammaControlKLMDark"),
127  ("18020300", "dark", "ALP3Gamma"),
128  ("18020400", "dark", "EGammaControlDark"),
129  ("18000000", "dark", "InelasticDarkMatter"),
130  ("18000001", "dark", "RadBhabhaV0Control"),
131  ("18360100", "taupair", "TauLFV"),
132  ("18520100", "dark", "DimuonPlusMissingEnergy"),
133  ("18520200", "dark", "ElectronMuonPlusMissingEnergy"),
134  ("18520300", "dark", "DielectronPlusMissingEnergy"),
135  ("18520400", "dark", "LFVZpVisible"),
136  ("18130100", "dark", "BtoKplusLLP"),
137  ("18570600", "taupair", "TauGeneric"),
138  ("18570700", "taupair", "TauThrust"),
139  ("18530100", "lowMulti", "TwoTrackLeptonsForLuminosity"),
140  ("18520500", "lowMulti", "LowMassTwoTrack"),
141  ("18530200", "lowMulti", "SingleTagPseudoScalar"),
142 
143  # --- WG9: Charmless B decays ---
144  ("19120100", "btocharmless", "BtoPi0Pi0"),
145  ("19130201", "btocharmless", "BtoHadTracks"),
146  ("19130300", "btocharmless", "BtoHad1Pi0"),
147  ("19130310", "btocharmless", "BtoHad3Tracks1Pi0"),
148  ("19120400", "btocharmless", "BtoRhopRhom"),
149 ]
150 """
151 A list of all official registered skims and their skim code and parent module. Entries
152 must be of the form ``(code, module, name)``.
153 """
154 
155 
156 def _add_skim_registry_table(SkimRegistry):
157  """
158  Decorator to add a Sphinx table to the docstring of the skim registry.
159 
160  Inserts table wherever '<TABLE>' is in the docstring.
161  """
162 
163  df = pd.DataFrame(_RegisteredSkims, columns=["Skim code", "Module", "Skim name"])
164  df = df[["Module", "Skim name", "Skim code"]].sort_values(by=["Module", "Skim code"])
165  table = tabulate(df, showindex="never", tablefmt="grid", headers=df.columns)
166 
167  # Manual text manipulation (read: filthy hack) to make the table hierarchical
168  OriginalLines = table.split("\n")
169  header, OriginalLines, footer = OriginalLines[:2], OriginalLines[2:-1], OriginalLines[-1]
170  CurrentModule = ""
171  lines = []
172  lines.append("\n ".join(header))
173  for BorderLine, TextLine in zip(OriginalLines[::2], OriginalLines[1::2]):
174  segments = TextLine.split("|")
175  module = segments[1].lstrip().rstrip()
176  if CurrentModule == module:
177  segments[1] = " " * len(segments[1])
178  BorderLine = "|" + " " * len(segments[1]) + BorderLine.lstrip("+").lstrip("-")
179  else:
180  CurrentModule = module
181  lines.append(BorderLine)
182  lines.append("|".join(segments))
183  lines.append(footer)
184 
185  SkimRegistry.__doc__ = SkimRegistry.__doc__.replace("<TABLE>", "\n ".join(lines))
186 
187  return SkimRegistry
188 
189 
190 @_add_skim_registry_table
192  """
193  Class containing information on all official registered skims. This class also
194  contains helper functions for getting information from the registry. For
195  convenience, an instance of this class is provided: `skim.registry.Registry`.
196 
197  The table below lists all registered skims and their skim codes:
198 
199  <TABLE>
200  """
201  _registry = _RegisteredSkims
202 
203  def __init__(self):
204  self._codes_codes = [code for code, _, _ in self._registry_registry]
205  self._modules_modules = list({module for _, module, _ in self._registry_registry})
206  self._names_names = [names for _, _, names in self._registry_registry]
207 
208  @property
209  def names(self):
210  """A list of all registered skim names."""
211  return self._names_names
212 
213  @property
214  def codes(self):
215  """A list of all registered skim codes."""
216  return self._codes_codes
217 
218  @property
219  def modules(self):
220  """A list of all registered skim modules."""
221  return self._modules_modules
222 
223  def get_skim_module(self, SkimName):
224  """Retrieve the skim module name from the registry which contains the given
225  skim.
226 
227  Parameters:
228  SkimName (str): Name of the skim as it appears in the skim registry.
229 
230  Returns:
231  The name of the skim module which contains the skim.
232  """
233  lookup = {name: module for _, module, name in self._registry_registry}
234  try:
235  return lookup[SkimName]
236  except KeyError:
237  B2ERROR(
238  f"Unrecognised skim name {SkimName}. "
239  "Please add your skim to the list in `skim/scripts/skim/registry.py`."
240  )
241  raise LookupError(SkimName)
242 
243  def get_skims_in_module(self, SkimModule):
244  """Retrieve a list of the skims listed in the registry as existing in
245  the given skim module.
246 
247  Parameters:
248  SkimModule (str): The name of the module, *e.g.* ``btocharmless`` (not
249  ``skim.btocharmless`` or ``btocharmless.py``).
250 
251  Returns:
252  The skims listed in the registry as belonging to ``SkimModule``.
253  """
254  if SkimModule not in self.modulesmodules:
255  B2ERROR(f"Unrecognised skim module {SkimModule}.")
256  raise LookupError(SkimModule)
257 
258  ModuleLookup = {name: module for _, module, name in self._registry_registry}
259  NameLookup = {
260  module: [name for name in self.namesnames if ModuleLookup[name] == module]
261  for module in self.modulesmodules
262  }
263  return NameLookup[SkimModule]
264 
265  def get_skim_function(self, SkimName):
266  """Get the skim class constructor for the given skim.
267 
268  This is achieved by importing the module listed alongside the skim name in the
269  skim registry.
270 
271  Parameters:
272  SkimName (str): Name of the skim to be found.
273 
274  Returns:
275  The class constructor for the given skim.
276  """
277  ModuleName = self.get_skim_moduleget_skim_module(SkimName)
278  SkimModule = import_module(f"skim.WGs.{ModuleName}")
279  return getattr(SkimModule, SkimName)
280 
281  def encode_skim_name(self, SkimName):
282  """Find the 8 digit skim code assigned to the skim with the provided name.
283 
284  Parameters:
285  SkimName (str): Name of the corresponding skim as it appears in the skim registry.
286 
287  Returns:
288  8 digit skim code assigned to the given skim.
289  """
290  lookup = {name: code for code, _, name in self._registry_registry}
291  try:
292  return lookup[SkimName]
293  except KeyError:
294  B2ERROR(
295  f"Unrecognised skim name {SkimName}. "
296  "Please add your skim to the list in `skim/scripts/skim/registry.py`."
297  )
298  raise LookupError(SkimName)
299 
300  def decode_skim_code(self, SkimCode):
301  """Find the name of the skim which corresponds to the provided skim code.
302 
303  This is useful to determine the skim script used to produce a specific uDST
304  file, given the 8-digit code name of the file itself.
305 
306  Parameters:
307  SkimCode (str): 8 digit skim code assigned to some skim.
308 
309  Returns:
310  Name of the corresponding skim as it appears in the skim registry.
311  """
312  lookup = {code: name for code, _, name in self._registry_registry}
313  try:
314  return lookup[SkimCode]
315  except KeyError:
316  B2ERROR(
317  f"Unrecognised skim code {SkimCode}. "
318  "Please add your skim to the list in `skim/scripts/skim/registry.py`."
319  )
320  raise LookupError(SkimCode)
321 
322 
323 Registry = SkimRegistryClass()
324 """
325 An instance of `skim.registry.SkimRegistryClass`. Use this in your script to get
326 information from the registry.
327 
328  >>> from skim.registry import Registry
329  >>> Registry.encode_skim_name("SinglePhotonDark")
330  18020100
331 """
def decode_skim_code(self, SkimCode)
Definition: registry.py:300
def get_skims_in_module(self, SkimModule)
Definition: registry.py:243
def encode_skim_name(self, SkimName)
Definition: registry.py:281
def get_skim_module(self, SkimName)
Definition: registry.py:223
def get_skim_function(self, SkimName)
Definition: registry.py:265