Belle II Software  release-06-02-00
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  ("17241200", "charm", "DstToD0Pi_D0ToVGamma"), # D* -> D0 -> vgamma
124 
125  # --- WG8: Dark matter searches and tau physics ---
126  ("18020100", "dark", "SinglePhotonDark"),
127  ("18020200", "dark", "GammaGammaControlKLMDark"),
128  ("18020300", "dark", "ALP3Gamma"),
129  ("18020400", "dark", "EGammaControlDark"),
130  ("18000000", "dark", "InelasticDarkMatter"),
131  ("18000001", "dark", "RadBhabhaV0Control"),
132  ("18360100", "taupair", "TauLFV"),
133  ("18520100", "dark", "DimuonPlusMissingEnergy"),
134  ("18520200", "dark", "ElectronMuonPlusMissingEnergy"),
135  ("18520300", "dark", "DielectronPlusMissingEnergy"),
136  ("18520400", "dark", "LFVZpVisible"),
137  ("18130100", "dark", "BtoKplusLLP"),
138  ("18570600", "taupair", "TauGeneric"),
139  ("18570700", "taupair", "TauThrust"),
140  ("18530100", "lowMulti", "TwoTrackLeptonsForLuminosity"),
141  ("18520500", "lowMulti", "LowMassTwoTrack"),
142  ("18530200", "lowMulti", "SingleTagPseudoScalar"),
143  ("18020500", "dark", "InelasticDarkMatterWithDarkHiggs"),
144  ("18370100", "dark", "AA2uuuu"),
145 
146  # --- WG9: Charmless B decays ---
147  ("19120100", "btocharmless", "BtoPi0Pi0"),
148  ("19130201", "btocharmless", "BtoHadTracks"),
149  ("19130300", "btocharmless", "BtoHad1Pi0"),
150  ("19130310", "btocharmless", "BtoHad3Tracks1Pi0"),
151  ("19120400", "btocharmless", "BtoRhopRhom"),
152 ]
153 """
154 A list of all official registered skims and their skim code and parent module. Entries
155 must be of the form ``(code, module, name)``.
156 """
157 
158 
159 def _add_skim_registry_table(SkimRegistry):
160  """
161  Decorator to add a Sphinx table to the docstring of the skim registry.
162 
163  Inserts table wherever '<TABLE>' is in the docstring.
164  """
165 
166  df = pd.DataFrame(_RegisteredSkims, columns=["Skim code", "Module", "Skim name"])
167  df = df[["Module", "Skim name", "Skim code"]].sort_values(by=["Module", "Skim code"])
168  table = tabulate(df, showindex="never", tablefmt="grid", headers=df.columns)
169 
170  # Manual text manipulation (read: filthy hack) to make the table hierarchical
171  OriginalLines = table.split("\n")
172  header, OriginalLines, footer = OriginalLines[:2], OriginalLines[2:-1], OriginalLines[-1]
173  CurrentModule = ""
174  lines = []
175  lines.append("\n ".join(header))
176  for BorderLine, TextLine in zip(OriginalLines[::2], OriginalLines[1::2]):
177  segments = TextLine.split("|")
178  module = segments[1].lstrip().rstrip()
179  if CurrentModule == module:
180  segments[1] = " " * len(segments[1])
181  BorderLine = "|" + " " * len(segments[1]) + BorderLine.lstrip("+").lstrip("-")
182  else:
183  CurrentModule = module
184  lines.append(BorderLine)
185  lines.append("|".join(segments))
186  lines.append(footer)
187 
188  SkimRegistry.__doc__ = SkimRegistry.__doc__.replace("<TABLE>", "\n ".join(lines))
189 
190  return SkimRegistry
191 
192 
193 @_add_skim_registry_table
195  """
196  Class containing information on all official registered skims. This class also
197  contains helper functions for getting information from the registry. For
198  convenience, an instance of this class is provided: `skim.registry.Registry`.
199 
200  The table below lists all registered skims and their skim codes:
201 
202  <TABLE>
203  """
204  _registry = _RegisteredSkims
205 
206  def __init__(self):
207  self._codes_codes = [code for code, _, _ in self._registry_registry]
208  self._modules_modules = list({module for _, module, _ in self._registry_registry})
209  self._names_names = [names for _, _, names in self._registry_registry]
210 
211  @property
212  def names(self):
213  """A list of all registered skim names."""
214  return self._names_names
215 
216  @property
217  def codes(self):
218  """A list of all registered skim codes."""
219  return self._codes_codes
220 
221  @property
222  def modules(self):
223  """A list of all registered skim modules."""
224  return self._modules_modules
225 
226  def get_skim_module(self, SkimName):
227  """Retrieve the skim module name from the registry which contains the given
228  skim.
229 
230  Parameters:
231  SkimName (str): Name of the skim as it appears in the skim registry.
232 
233  Returns:
234  The name of the skim module which contains the skim.
235  """
236  lookup = {name: module for _, module, name in self._registry_registry}
237  try:
238  return lookup[SkimName]
239  except KeyError:
240  B2ERROR(
241  f"Unrecognised skim name {SkimName}. "
242  "Please add your skim to the list in `skim/scripts/skim/registry.py`."
243  )
244  raise LookupError(SkimName)
245 
246  def get_skims_in_module(self, SkimModule):
247  """Retrieve a list of the skims listed in the registry as existing in
248  the given skim module.
249 
250  Parameters:
251  SkimModule (str): The name of the module, *e.g.* ``btocharmless`` (not
252  ``skim.btocharmless`` or ``btocharmless.py``).
253 
254  Returns:
255  The skims listed in the registry as belonging to ``SkimModule``.
256  """
257  if SkimModule not in self.modulesmodules:
258  B2ERROR(f"Unrecognised skim module {SkimModule}.")
259  raise LookupError(SkimModule)
260 
261  ModuleLookup = {name: module for _, module, name in self._registry_registry}
262  NameLookup = {
263  module: [name for name in self.namesnames if ModuleLookup[name] == module]
264  for module in self.modulesmodules
265  }
266  return NameLookup[SkimModule]
267 
268  def get_skim_function(self, SkimName):
269  """Get the skim class constructor for the given skim.
270 
271  This is achieved by importing the module listed alongside the skim name in the
272  skim registry.
273 
274  Parameters:
275  SkimName (str): Name of the skim to be found.
276 
277  Returns:
278  The class constructor for the given skim.
279  """
280  ModuleName = self.get_skim_moduleget_skim_module(SkimName)
281  SkimModule = import_module(f"skim.WGs.{ModuleName}")
282  return getattr(SkimModule, SkimName)
283 
284  def encode_skim_name(self, SkimName):
285  """Find the 8 digit skim code assigned to the skim with the provided name.
286 
287  Parameters:
288  SkimName (str): Name of the corresponding skim as it appears in the skim registry.
289 
290  Returns:
291  8 digit skim code assigned to the given skim.
292  """
293  lookup = {name: code for code, _, name in self._registry_registry}
294  try:
295  return lookup[SkimName]
296  except KeyError:
297  B2ERROR(
298  f"Unrecognised skim name {SkimName}. "
299  "Please add your skim to the list in `skim/scripts/skim/registry.py`."
300  )
301  raise LookupError(SkimName)
302 
303  def decode_skim_code(self, SkimCode):
304  """Find the name of the skim which corresponds to the provided skim code.
305 
306  This is useful to determine the skim script used to produce a specific uDST
307  file, given the 8-digit code name of the file itself.
308 
309  Parameters:
310  SkimCode (str): 8 digit skim code assigned to some skim.
311 
312  Returns:
313  Name of the corresponding skim as it appears in the skim registry.
314  """
315  lookup = {code: name for code, _, name in self._registry_registry}
316  try:
317  return lookup[SkimCode]
318  except KeyError:
319  B2ERROR(
320  f"Unrecognised skim code {SkimCode}. "
321  "Please add your skim to the list in `skim/scripts/skim/registry.py`."
322  )
323  raise LookupError(SkimCode)
324 
325 
326 Registry = SkimRegistryClass()
327 """
328 An instance of `skim.registry.SkimRegistryClass`. Use this in your script to get
329 information from the registry.
330 
331  >>> from skim.registry import Registry
332  >>> Registry.encode_skim_name("SinglePhotonDark")
333  18020100
334 """
def decode_skim_code(self, SkimCode)
Definition: registry.py:303
def get_skims_in_module(self, SkimModule)
Definition: registry.py:246
def encode_skim_name(self, SkimName)
Definition: registry.py:284
def get_skim_module(self, SkimName)
Definition: registry.py:226
def get_skim_function(self, SkimName)
Definition: registry.py:268