Belle II Software  release-05-02-19
skimExpertFunctions.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 from abc import ABC, abstractmethod
5 import subprocess
6 import json
7 import re
8 
9 import yaml
10 
11 import basf2 as b2
12 from modularAnalysis import applyCuts, removeParticlesNotInLists, skimOutputUdst, summaryOfLists
13 from skim.registry import Registry
14 
15 
16 def _get_test_sample_info(sampleName):
17  """Read in the YAML file of test samples (``skim/scripts/TestFiles.yaml``) and
18  return the info for a sample as a dict.
19  """
20 
21  with open(b2.find_file("skim/scripts/TestFiles.yaml")) as f:
22  skimTestFilesInfo = yaml.safe_load(f)
23 
24  try:
25  return skimTestFilesInfo[sampleName]
26  except KeyError:
27  msg = f"Sample {sampleName} not listed in skim/scripts/TestFiles.yaml."
28  b2.B2ERROR(msg)
29  raise KeyError(msg)
30 
31 
32 class _hashable_list(list):
33  """
34  Helper class for returning an hashable list.
35  """
36 
37  def __hash__(self):
38  """
39  The core method of this class.
40  """
41  return hash(tuple(self))
42 
43 
44 def get_test_file(sampleName):
45  """
46  Returns the KEKCC location of files used specifically for skim testing
47 
48  Args:
49  sampleName (str): Name of the sample. MC samples are named *e.g.* "MC12_chargedBGx1", "MC9_ccbarBGx0"
50  Returns:
51  sampleFileName (str): The path to the test file on KEKCC.
52  """
53  sampleInfo = _get_test_sample_info(sampleName)
54 
55  if "location" in sampleInfo and sampleInfo["location"] is not None:
56  return sampleInfo["location"]
57  else:
58  msg = f"No test file location listed for {sampleName} sample."
59  b2.B2ERROR(msg)
60  raise KeyError(msg)
61 
62 
63 def get_total_infiles(sampleName):
64  """
65  Returns the total number of input MDST files for a given sample. This is useful for resource estimate.
66 
67  Args:
68  sampleName (str): Name of the sample. MC samples are named *e.g.* "MC12_chargedBGx1", "MC9_ccbarBGx0"
69  Returns:
70  nInFiles (int): Total number of input files for sample.
71  """
72  sampleInfo = _get_test_sample_info(sampleName)
73 
74  if "total_input_files" in sampleInfo and sampleInfo["total_input_files"] is not None:
75  return sampleInfo["total_input_files"]
76  else:
77  msg = f"'total_input_files' not listed for {sampleName} sample."
78  raise KeyError(msg)
79 
80 
81 def get_events_per_file(sampleName):
82  """
83  Returns an estimate for the average number of events in an input MDST file of the given sample type.
84 
85  Args:
86  sampleName (str): Name of the sample. MC samples are named *e.g.* "MC12_chargedBGx1", "MC9_ccbarBGx0"
87  Returns:
88  nEventsPerFile (int): The average number of events in file of the given sample type.
89  """
90  sampleInfo = _get_test_sample_info(sampleName)
91 
92  if "average_events_per_file" in sampleInfo and sampleInfo["average_events_per_file"] is not None:
93  return sampleInfo["average_events_per_file"]
94  else:
95  msg = f"'average_events_per_file' not listed for {sampleName} sample."
96  raise KeyError(msg)
97 
98 
99 def add_skim(label, lists, path):
100  """
101  create uDST skim for given lists, saving into $label.udst.root
102  Particles not necessary for the given particle lists are not saved.
103 
104  Parameters:
105  label (str): the registered skim name
106  lists (list(str)): the list of ParticleList names that have been created by a skim list builder function
107  path (basf2.Path): modules are added to this path
108 
109  """
110  skimCode = Registry.encode_skim_name(label)
111  skimOutputUdst(skimCode, lists, path=path)
112  summaryOfLists(lists, path=path)
113 
114 
115 def setSkimLogging(path, additional_modules=[]):
116  """
117  Turns the log level to ERROR for several modules to decrease
118  the total size of the skim log files
119 
120  Parameters:
121  skim_path (basf2.Path): modules are added to this path
122  additional_modules (list(str)): an optional list of extra noisy module
123  names that should be silenced
124  """
125  noisy_modules = ['ParticleLoader', 'ParticleVertexFitter'] + additional_modules
126  for module in path.modules():
127  if module.type() in noisy_modules:
128  module.set_log_level(b2.LogLevel.ERROR)
129  return
130 
131 
132 def ifEventPasses(cut, conditional_path, path):
133  """
134  If the event passes the given ``cut`` proceed to process everything in ``conditional_path``.
135  Afterwards return here and continue processing with the next module.
136 
137  Arguments:
138  cut (str): selection criteria which needs to be fulfilled in order to continue with ``conditional_path``
139  conditional_path (basf2.Path): path to execute if the event fulfills the criteria ``cut``
140  path (basf2.Path): modules are added to this path
141  """
142  eselect = path.add_module("VariableToReturnValue", variable=f"passesEventCut({cut})")
143  eselect.if_value('=1', conditional_path, b2.AfterConditionPath.CONTINUE)
144 
145 
146 def get_eventN(fileName):
147  """
148  Returns the number of events in a specific file
149 
150  Arguments:
151  filename: Name of the file as clearly indicated in the argument's name.
152  """
153 
154  process = subprocess.Popen(['b2file-metadata-show', '--json', fileName], stdout=subprocess.PIPE)
155  out = process.communicate()[0]
156  if process.returncode == 0:
157  metadata = json.loads(out)
158  nevents = metadata['nEvents']
159  return nevents
160  else:
161  b2.B2ERROR("FILE INVALID OR NOT FOUND.")
162 
163 
164 def skimOutputMdst(skimDecayMode, path=None, skimParticleLists=[], outputParticleLists=[], includeArrays=[], *,
165  outputFile=None, dataDescription=None):
166  """
167  Create a new path for events that contain a non-empty particle list specified via skimParticleLists.
168  Write the accepted events as a mdst file, saving only particles from skimParticleLists
169  and from outputParticleLists. It outputs a .mdst file.
170  Additional Store Arrays and Relations to be stored can be specified via includeArrays
171  list argument.
172 
173  :param str skimDecayMode: Name of the skim. If no outputFile is given this is
174  also the name of the output filename. This name will be added to the
175  FileMetaData as an extra data description "skimDecayMode"
176  :param list(str) skimParticleLists: Names of the particle lists to skim for.
177  An event will be accepted if at least one of the particle lists is not empty
178  :param list(str) outputParticleLists: Names of the particle lists to store in
179  the output in addition to the ones in skimParticleLists
180  :param list(str) includeArrays: datastore arrays/objects to write to the output
181  file in addition to mdst and particle information
182  :param basf2.Path path: Path to add the skim output to. Defaults to the default analysis path
183  :param str outputFile: Name of the output file if different from the skim name
184  :param dict dataDescription: Additional data descriptions to add to the output file. For example {"mcEventType":"mixed"}
185  """
186  # Note: Keep this import! `skimExpertFunctions.py` a module used commonly throughout
187  # the skim package, and importing this up the top hijacks the argparser of any
188  # script which imports it.
189  from mdst import add_mdst_output
190 
191  # if no outputfile is specified, set it to the skim name
192  if outputFile is None:
193  outputFile = skimDecayMode
194 
195  # make sure the output filename has the correct extension
196  if not outputFile.endswith(".mdst.root"):
197  outputFile += ".mdst.root"
198 
199  skimfilter = b2.register_module('SkimFilter')
200  skimfilter.set_name('SkimFilter_' + skimDecayMode)
201  skimfilter.param('particleLists', skimParticleLists)
202  path.add_module(skimfilter)
203  filter_path = b2.create_path()
204  skimfilter.if_value('=1', filter_path, b2.AfterConditionPath.CONTINUE)
205 
206  # add_independent_path() is rather expensive, only do this for skimmed events
207  skim_path = b2.create_path()
208  saveParticleLists = skimParticleLists + outputParticleLists
209  removeParticlesNotInLists(saveParticleLists, path=skim_path)
210 
211  # set dataDescription: dictionary is mutable and thus not a good
212  # default argument.
213  if dataDescription is None:
214  dataDescription = {}
215 
216  dataDescription.setdefault("skimDecayMode", skimDecayMode)
217  add_mdst_output(skim_path, filename=outputFile)
218  filter_path.add_independent_path(skim_path, "skim_" + skimDecayMode)
219 
220 
221 def resolve_skim_modules(SkimsOrModules, *, LocalModule=None):
222  """
223  Produce an ordered list of skims, by expanding any Python skim module names into a
224  list of skims in that module. Also produce a dict of skims grouped by Python module.
225 
226  Raises:
227  RuntimeError: Raised if a skim is listed twice.
228  ValueError: Raised if ``LocalModule`` is passed and skims are normally expected
229  from more than one module.
230  """
231  skims = []
232 
233  for name in SkimsOrModules:
234  if name in Registry.names:
235  skims.append(name)
236  elif name in Registry.modules:
237  skims.extend(Registry.get_skims_in_module(name))
238 
239  duplicates = set([skim for skim in skims if skims.count(skim) > 1])
240  if duplicates:
241  raise RuntimeError(
242  f"Skim{'s'*(len(duplicates)>1)} requested more than once: {', '.join(duplicates)}"
243  )
244 
245  modules = sorted({Registry.get_skim_module(skim) for skim in skims})
246  if LocalModule:
247  if len(modules) > 1:
248  raise ValueError(
249  f"Local module {LocalModule} specified, but the combined skim expects "
250  "skims from more than one module. No steering file written."
251  )
252  modules = {LocalModule.rstrip(".py"): sorted(skims)}
253  else:
254  modules = {
255  f"skim.{module}": sorted(
256  [skim for skim in skims if Registry.get_skim_module(skim) == module]
257  )
258  for module in modules
259  }
260 
261  return skims, modules
262 
263 
264 class InitialiseSkimFlag(b2.Module):
265  """
266  *[Module for skim expert usage]* Create the EventExtraInfo DataStore object, and set
267  all required flag variables to zero.
268 
269  .. Note::
270 
271  Add this module to the path before adding any skims, so that the skim flags are
272  defined in the datastore for all events.
273  """
274 
275  def __init__(self, *skims):
276  """
277  Initialise module.
278 
279  Parameters:
280  skims (skimExpertFunctions.BaseSkim): Skim to initialise event flag for.
281  """
282 
283  from variables import variables as vm
284  from ROOT import Belle2
285 
286  super().__init__()
287  self.skims = skims
288  self.EventExtraInfo = Belle2.PyStoreObj("EventExtraInfo")
289 
290  # Create aliases for convenience
291  for skim in skims:
292  vm.addAlias(skim.flag, f"eventExtraInfo({skim.flag})")
293 
294  def initialize(self):
295  """
296  Register EventExtraInfo in datastore if it has not been registered already.
297  """
298  if not self.EventExtraInfo.isValid():
299  self.EventExtraInfo.registerInDataStore()
300 
301  def event(self):
302  """
303  Initialise flags to zero.
304  """
305 
306  self.EventExtraInfo.create()
307  for skim in self.skims:
308  self.EventExtraInfo.addExtraInfo(skim.flag, 0)
309 
310 
311 class UpdateSkimFlag(b2.Module):
312  """
313  *[Module for skim expert usage]* Update the skim flag to be 1 if there is at least
314  one candidate in any of the skim lists.
315 
316  .. Note::
317 
318  Add this module to the post-skim path of each skim in the combined skim, as the
319  skim lists are only guaranteed to exist on the conditional path (if a
320  conditional path was used).
321  """
322 
323  def __init__(self, skim):
324  """
325  Initialise module.
326 
327  Parameters:
328  skim (skimExpertFunctions.BaseSkim): Skim to update event flag for.
329  """
330 
331  from ROOT import Belle2
332 
333  super().__init__()
334  self.skim = skim
335  self.EventExtraInfo = Belle2.PyStoreObj("EventExtraInfo")
336 
337  def initialize(self):
338  """
339  Check EventExtraInfo has been registered previously. This registration should be
340  done by InitialiseSkimFlag.
341  """
342  self.EventExtraInfo.isRequired()
343 
344  def event(self):
345  """
346  Check if at least one skim list is non-empty; if so, update the skim flag to 1.
347  """
348 
349  from ROOT import Belle2
350 
351  ListObjects = [Belle2.PyStoreObj(lst) for lst in self.skim.SkimLists]
352 
353  # Check required skim lists have been built on this path
354  if any([not ListObj.isValid() for ListObj in ListObjects]):
355  b2.B2FATAL(
356  f"Error in UpdateSkimFlag for {self.skim}: particle lists not built. "
357  "Did you add this module to the pre-skim path rather than the post-skim path?"
358  )
359 
360  nCandidates = sum(ListObj.getListSize() for ListObj in ListObjects)
361 
362  # Override ExtraInfo flag if at least one candidate from any list passed
363  if nCandidates > 0:
364  self.EventExtraInfo.setExtraInfo(self.skim.flag, 1)
365 
366 
367 def _sphinxify_decay(decay_string):
368  """Format the given decay string by using LaTeX commands instead of plain-text.
369  Output is formatted for use with Sphinx (ReStructured Text).
370 
371  This is a utility function for autogenerating skim documentation.
372 
373  Parameters:
374  decay_string (str): A decay descriptor.
375 
376  Returns:
377  sphinxed_string (str): LaTeX version of the decay descriptor.
378  """
379 
380  decay_string = re.sub("^(B.):generic", "\\1_{\\\\text{had}}", decay_string)
381  decay_string = decay_string.replace(":generic", "")
382  decay_string = decay_string.replace(":semileptonic", "_{\\text{SL}}")
383  decay_string = decay_string.replace(":FSP", "_{FSP}")
384  decay_string = decay_string.replace(":V0", "_{V0}")
385  decay_string = re.sub("_[0-9]+", "", decay_string)
386  # Note: these are applied from top to bottom, so if you have
387  # both B0 and anti-B0, put anti-B0 first.
388  substitutes = [
389  ("==>", "\\to"),
390  ("->", "\\to"),
391  ("gamma", "\\gamma"),
392  ("p+", "p"),
393  ("anti-p-", "\\bar{p}"),
394  ("pi+", "\\pi^+"),
395  ("pi-", "\\pi^-"),
396  ("pi0", "\\pi^0"),
397  ("K_S0", "K^0_S"),
398  ("K_L0", "K^0_L"),
399  ("mu+", "\\mu^+"),
400  ("mu-", "\\mu^-"),
401  ("tau+", "\\tau^+"),
402  ("tau-", "\\tau^-"),
403  ("nu", "\\nu"),
404  ("K+", "K^+"),
405  ("K-", "K^-"),
406  ("e+", "e^+"),
407  ("e-", "e^-"),
408  ("J/psi", "J/\\psi"),
409  ("anti-Lambda_c-", "\\Lambda^{-}_{c}"),
410  ("anti-Sigma+", "\\overline{\\Sigma}^{+}"),
411  ("anti-Lambda0", "\\overline{\\Lambda}^{0}"),
412  ("anti-D0*", "\\overline{D}^{0*}"),
413  ("anti-D*0", "\\overline{D}^{0*}"),
414  ("anti-D0", "\\overline{D}^0"),
415  ("anti-B0", "\\overline{B}^0"),
416  ("Sigma+", "\\Sigma^{+}"),
417  ("Lambda_c+", "\\Lambda^{+}_{c}"),
418  ("Lambda0", "\\Lambda^{0}"),
419  ("D+", "D^+"),
420  ("D-", "D^-"),
421  ("D0", "D^0"),
422  ("D*+", "D^{+*}"),
423  ("D*-", "D^{-*}"),
424  ("D*0", "D^{0*}"),
425  ("D_s+", "D^+_s"),
426  ("D_s-", "D^-_s"),
427  ("D_s*+", "D^{+*}_s"),
428  ("D_s*-", "D^{-*}_s"),
429  ("B+", "B^+"),
430  ("B-", "B^-"),
431  ("B0", "B^0"),
432  ("B_s0", "B^0_s"),
433  ("K*0", "K^{0*}")]
434  tex_string = decay_string
435  for (key, value) in substitutes:
436  tex_string = tex_string.replace(key, value)
437  return f":math:`{tex_string}`"
438 
439 
440 def fancy_skim_header(SkimClass):
441  """Decorator to generate a fancy header to skim documentation and prepend it to the
442  docstring. Add this just above the definition of a skim.
443 
444  Also ensures the documentation of the template functions like `BaseSkim.build_lists`
445  is not repeated in every skim documentation.
446 
447  .. code-block:: python
448 
449  @fancy_skim_header
450  class MySkimName(BaseSkim):
451  # docstring here describing your skim, and explaining cuts.
452  """
453  SkimName = SkimClass.__name__
454  SkimCode = Registry.encode_skim_name(SkimName)
455  authors = SkimClass.__authors__ or ["(no authors listed)"]
456  description = SkimClass.__description__ or "(no description)"
457  contact = SkimClass.__contact__ or "(no contact listed)"
458  category = SkimClass.__category__ or "(no category listed)"
459 
460  if isinstance(authors, str):
461  # If we were given a string, split it up at: commas, "and", "&", and newlines
462  authors = re.split(r",\s+and\s+|\s+and\s+|,\s+&\s+|\s+&\s+|,\s+|\s*\n\s*", authors)
463  # Strip any remaining whitespace either side of an author's name
464  authors = [re.sub(r"^\s+|\s+$", "", author) for author in authors]
465 
466  if isinstance(category, list):
467  category = ", ".join(category)
468 
469  # If the contact is of the form "NAME <EMAIL>" or "NAME (EMAIL)", then make it a link
470  match = re.match("([^<>()`]+) [<(]([^<>()`]+@[^<>()`]+)[>)]", contact)
471  if match:
472  name, email = match[1], match[2]
473  contact = f"`{name} <mailto:{email}>`_"
474 
475  header = f"""
476  Note:
477  * **Skim description**: {description}
478  * **Skim name**: {SkimName}
479  * **Skim LFN code**: {SkimCode}
480  * **Category**: {category}
481  * **Author{"s"*(len(authors) > 1)}**: {", ".join(authors)}
482  * **Contact**: {contact}
483  """
484 
485  if SkimClass.ApplyHLTHadronCut:
486  HLTLine = "*This skim includes a selection on the HLT flag* ``hlt_hadron``."
487  header = f"{header.rstrip()}\n\n {HLTLine}\n"
488 
489  if SkimClass.__doc__:
490  SkimClass.__doc__ = header + "\n\n" + SkimClass.__doc__.lstrip("\n")
491  else:
492  # Handle case where docstring is empty, or was not redefined
493  SkimClass.__doc__ = header
494 
495  # If documentation of template functions not redefined, make sure BaseSkim docstring is not repeated
496  SkimClass.load_standard_lists.__doc__ = SkimClass.load_standard_lists.__doc__ or ""
497  SkimClass.build_lists.__doc__ = SkimClass.build_lists.__doc__ or ""
498  SkimClass.validation_histograms.__doc__ = SkimClass.validation_histograms.__doc__ or ""
499  SkimClass.additional_setup.__doc__ = SkimClass.additional_setup.__doc__ or ""
500 
501  return SkimClass
502 
503 
504 class BaseSkim(ABC):
505  """Base class for skims. Initialises a skim name, and creates template functions
506  required for each skim.
507 
508  See `writing-skims` for information on how to use this to define a new skim.
509  """
510 
511  NoisyModules = None
512  """List of module types to be silenced. This may be necessary in certain skims in
513  order to keep log file sizes small.
514 
515  .. tip::
516  The elements of this list should be the module *type*, which is not necessarily
517  the same as the module name. The module type can be inspected in Python via
518  ``module.type()``.
519 
520  .. seealso::
521  This attribute is used by `BaseSkim.set_skim_logging`.
522  """
523 
524  TestFiles = [get_test_file("MC13_mixedBGx1")]
525  """Location of an MDST file to test the skim on. Defaults to an MC13 mixed BGx1
526  sample. If you want to use a different test file for your skim, set it using
527  `get_test_file`.
528  """
529 
530  MergeDataStructures = {}
531  """Dict of ``str -> function`` pairs to determine if any special data structures
532  should be merged when combining skims. Currently, this is only used to merge FEI
533  config parameters when running multiple FEI skims at once, so that it can be run
534  just once with all the necessary arguments."""
535 
536  ApplyHLTHadronCut = False
537  """If this property is set to True, then the HLT selection for ``hlt_hadron`` will
538  be applied to the skim lists when the skim is added to the path.
539  """
540 
541  produce_on_tau_samples = True
542  """If this property is set to False, then ``b2skim-prod`` will not produce data
543  production requests for this skim on taupair MC samples. This decision may be made
544  for one of two reasons:
545 
546  * The retention rate of the skim on taupair samples is basically zero, so there is
547  no point producing the skim for these samples.
548 
549  * The retention rate of the skim on taupair samples is too high (>20%), so the
550  production system may struggle to handle the jobs.
551  """
552 
553  @property
554  @abstractmethod
555  def __description__(self):
556  pass
557 
558  @property
559  @abstractmethod
560  def __category__(self):
561  pass
562 
563  @property
564  @abstractmethod
565  def __authors__(self):
566  pass
567 
568  @property
569  @abstractmethod
570  def __contact__(self):
571  pass
572 
573  @property
574  def code(self):
575  """Eight-digit code assigned to this skim in the registry."""
576  return Registry.encode_skim_name(self.name)
577 
578  def __init__(self, *, OutputFileName=None, additionalDataDescription=None, udstOutput=True, validation=False):
579  """Initialise the BaseSkim class.
580 
581  Parameters:
582  OutputFileName (str): Name to give output uDST files. If none given, then
583  defaults to eight-number skim code.
584  additionalDataDescription (dict): additional data description to be added to the output file metadata.
585  udstOutput (bool): If True, add uDST output to the path.
586  validation (bool): If True, build lists and write validation histograms
587  instead of writing uDSTs.
588  """
589  self.name = self.__class__.__name__
590  self.OutputFileName = OutputFileName
591  self.additionalDataDescription = additionalDataDescription
592  self._udstOutput = udstOutput
593  self._validation = validation
594  self.SkimLists = []
595 
596  if self.NoisyModules is None:
597  self.NoisyModules = []
598 
599  def load_standard_lists(self, path):
600  """
601  Load any standard lists. This code will be run before any
602  `BaseSkim.additional_setup` and `BaseSkim.build_lists`.
603 
604  Note:
605  This is separated into its own function so that when skims are combined, any
606  standard lists used by two skims can be loaded just once.
607 
608  Parameters:
609  path (basf2.Path): Skim path to be processed.
610  """
611 
612  def additional_setup(self, path):
613  """
614  Perform any setup steps necessary before running the skim. This may include:
615 
616  * applying event-level cuts using `ifEventPasses`,
617  * adding the `MCMatcherParticles` module to the path,
618  * running the FEI.
619 
620  Warning:
621  Standard particle lists should *not* be loaded in here. This should be done
622  by overriding the method `BaseSkim.load_standard_lists`. This is crucial for
623  avoiding loading lists twice when combining skims for production.
624 
625  Parameters:
626  path (basf2.Path): Skim path to be processed.
627  """
628 
629  # Abstract method to ensure that it is overridden whenever `BaseSkim` is inherited
630  @abstractmethod
631  def build_lists(self, path):
632  """Create the skim lists to be saved in the output uDST. This function is where
633  the main skim cuts should be applied. At the end of this method, the attribute
634  ``SkimLists`` must be set so it can be used by `output_udst`.
635 
636  Parameters:
637  path (basf2.Path): Skim path to be processed.
638  """
639 
640  def validation_histograms(self, path):
641  """Create validation histograms for the skim.
642 
643  Parameters:
644  path (basf2.Path): Skim path to be processed.
645  """
646 
647  # Everything beyond this point can remain as-is when defining a skim
648  def __call__(self, path, *, udstOutput=None, validation=None):
649  """Produce the skim particle lists and write uDST file.
650 
651  Parameters:
652  path (basf2.Path): Skim path to be processed.
653  udstOutput (bool): [DEPRECATED ARGUMENT] If True, add uDST output to the path.
654  validation (bool): [DEPRECATED ARGUMENT] If True, build lists and write
655  validation histograms instead of writing uDSTs.
656  """
657  # Deprecation warning. All configuration should be done during initialisation.
658  warning = (
659  "Passing the `{arg}` argument to `BaseSkim.__call__` is deprecated. "
660  "Please pass all configuration parameters to the initialisation of "
661  "the skim object."
662  )
663  if udstOutput is not None:
664  b2.B2WARNING(warning.format(arg="udstOutput"))
665  self._udstOutput = udstOutput
666  if validation is not None:
667  b2.B2WARNING(warning.format(arg="validation"))
668  self._validation = validation
669 
670  self._MainPath = path
671 
672  self.initialise_skim_flag(path)
673  self.load_standard_lists(path)
674  self.additional_setup(path)
675  # At this point, BaseSkim.skim_event_cuts may have been run, so pass
676  # self._ConditionalPath for the path if it is not None (otherwise just pass the
677  # regular path)
678  self.build_lists(self._ConditionalPath or path)
680 
681  self.update_skim_flag(self._ConditionalPath or path)
682 
683  if self._udstOutput:
684  self.output_udst(self._ConditionalPath or path)
685 
686  if self._validation:
687  if self._method_unchanged("validation_histograms"):
688  b2.B2FATAL(f"No validation histograms defined for {self} skim.")
689  self.validation_histograms(self._ConditionalPath or path)
690 
691  self.set_skim_logging()
692 
693  @property
694  def postskim_path(self):
695  """
696  Return the skim path.
697 
698  * If `BaseSkim.skim_event_cuts` has been run, then the skim lists will only be
699  created on a conditional path, so subsequent modules should be added to the
700  conditional path.
701 
702  * If `BaseSkim.skim_event_cuts` has not been run, then the main analysis path is
703  returned.
704  """
705 
706  if not self._MainPath:
707  raise ValueError("Skim has not been added to the path yet!")
708  return self._ConditionalPath or self._MainPath
709 
710  _MainPath = None
711  """Main analysis path."""
712 
713  _ConditionalPath = None
714  """Conditional path to be set by `BaseSkim.skim_event_cuts` if event-level cuts are applied."""
715 
716  def skim_event_cuts(self, cut, *, path):
717  """Apply event-level cuts in a skim-safe way.
718 
719  Parameters:
720  cut (str): Event-level cut to be applied.
721  path (basf2.Path): Skim path to be processed.
722 
723  Returns:
724  ConditionalPath (basf2.Path): Path on which the rest of this skim should be
725  processed. On this path, only events which passed the event-level cut
726  will be processed further.
727 
728  .. Tip::
729  If running this function in `BaseSkim.additional_setup` or
730  `BaseSkim.build_lists`, redefine the ``path`` to the path returned by
731  `BaseSkim.skim_event_cuts`, *e.g.*
732 
733  .. code-block:: python
734 
735  def build_lists(self, path):
736  path = self.skim_event_cuts("nTracks>4", path=path)
737  # rest of skim list building...
738 
739  .. Note::
740  The motivation for using this function over `applyEventCuts` is that
741  `applyEventCuts` completely removes events from processing. If we combine
742  multiple skims in a single steering file (which is done in production), and
743  the first has a set of event-level cuts, then all the remaining skims will
744  never even see those events.
745 
746  Internally, this function creates a new path, which is only processed for
747  events passing the event-level cut. To avoid issues around particles not
748  being available on the main path (leading to noisy error logs), we need to
749  add the rest of the skim to this path. So this new path is assigned to the
750  attribute ``BaseSkim._ConditionalPath``, and ``BaseSkim.__call__`` will run
751  all remaining methods on this path.
752  """
753  if self._ConditionalPath is not None:
754  b2.B2FATAL(
755  "BaseSkim.skim_event_cuts cannot be run twice in one skim. "
756  "Please join your event-level cut strings into a single string."
757  )
758 
759  ConditionalPath = b2.Path()
760  self._ConditionalPath = ConditionalPath
761 
762  eselect = path.add_module("VariableToReturnValue", variable=f"passesEventCut({cut})")
763  eselect.if_value('=1', ConditionalPath, b2.AfterConditionPath.CONTINUE)
764 
765  return ConditionalPath
766 
767  @property
768  def flag(self):
769  """
770  Event-level variable indicating whether an event passes the skim or not. To use
771  the skim flag without writing uDST output, use the argument ``udstOutput=False``
772  when instantiating the skim class.
773  """
774  return f"passes_{self}"
775 
776  def initialise_skim_flag(self, path):
777  """
778  Add the module `skimExpertFunctions.InitialiseSkimFlag` to the path, which
779  initialises flag for this skim to zero.
780  """
781  path.add_module(InitialiseSkimFlag(self))
782 
783  def update_skim_flag(self, path):
784  """
785  Add the module `skimExpertFunctions.InitialiseSkimFlag` to the path, which
786  initialises flag for this skim to zero.
787 
788  .. Warning::
789 
790  If a conditional path has been created before this, then this function
791  *must* run on the conditional path, since the skim lists are not guaranteed
792  to exist for all events on the main path.
793  """
794  path.add_module(UpdateSkimFlag(self))
795 
797  """
798  Get the list of skim particle list names, without creating the particle lists on
799  the current path.
800  """
801  DummyPath = b2.Path()
802 
803  OriginalSkimListsValue = self.SkimLists
804  self.build_lists(DummyPath)
805  SkimLists = self.SkimLists
806  self.SkimLists = OriginalSkimListsValue
807 
808  return SkimLists
809 
810  def _method_unchanged(self, method):
811  """Check if the method of the class is the same as in its parent class, or if it has
812  been overridden.
813 
814  Useful for determining if *e.g.* `validation_histograms` has been defined for a
815  particular skim.
816  """
817  cls = self.__class__
818  ParentsWithAttr = [parent for parent in cls.__mro__[1:] if hasattr(parent, method)]
819 
820  if ParentsWithAttr:
821  # Look for oldest ancestor which as that attribute, to handle inheritance.
822  # In the case of `validation_histograms`, this will be `BaseSkim`.
823  OldestParentWithAttr = ParentsWithAttr[-1]
824  return getattr(cls, method) == getattr(OldestParentWithAttr, method)
825  else:
826  return False
827 
828  def __str__(self):
829  return self.name
830 
831  def __name__(self):
832  return self.name
833 
834  def set_skim_logging(self):
835  """Turns the log level to ERROR for selected modules to decrease the total size
836  of the skim log files. Additional modules can be silenced by setting the attribute
837  `NoisyModules` for an individual skim.
838 
839  Parameters:
840  path (basf2.Path): Skim path to be processed.
841 
842  .. warning::
843 
844  This method works by inspecting the modules added to the path, and setting
845  the log level to ERROR. This method should be called *after* all
846  skim-related modules are added to the path.
847  """
848  b2.set_log_level(b2.LogLevel.INFO)
849 
850  NoisyModules = ["ParticleLoader", "ParticleVertexFitter"] + self.NoisyModules
851 
852  # Set log level of modules on both main path and conditional path
853  paths = filter(None, (self._MainPath, self._ConditionalPath))
854  modules = [module for path in paths for module in path.modules()]
855 
856  for module in modules:
857  if module.type() in set(NoisyModules):
858  module.set_log_level(b2.LogLevel.ERROR)
859 
860  def output_udst(self, path):
861  """Write the skim particle lists to an output uDST and print a summary of the
862  skim list statistics.
863 
864  Parameters:
865  path (basf2.Path): Skim path to be processed.
866  """
867 
868  # Make a fuss if self.SkimLists is empty
869  if len(self.SkimLists) == 0:
870  b2.B2FATAL(
871  f"No skim list names defined in self.SkimLists for {self} skim!"
872  )
873 
874  skimOutputUdst(
875  skimDecayMode=self.code,
876  skimParticleLists=self.SkimLists,
877  outputFile=self.OutputFileName,
878  dataDescription=self.additionalDataDescription,
879  path=path,
880  )
881  summaryOfLists(self.SkimLists, path=path)
882 
884  """Apply the ``hlt_hadron`` selection if the property ``ApplyHLTHadronCut`` is True.
885 
886  Parameters:
887  path (basf2.Path): Skim path to be processed.
888  """
889  hlt_hadron = "SoftwareTriggerResult(software_trigger_cut&skim&accept_hadron)"
890  if self.ApplyHLTHadronCut:
891  for SkimList in self.SkimLists:
892  applyCuts(SkimList, f"{hlt_hadron}==1", path=path)
893 
894 
896  """Class for creating combined skims which can be run using similar-looking methods
897  to `BaseSkim` objects.
898 
899  A steering file which combines skims can be as simple as the following:
900 
901  .. code-block:: python
902 
903  import basf2 as b2
904  import modularAnalysis as ma
905  from skim.foo import OneSkim, TwoSkim, RedSkim, BlueSkim
906 
907  path = b2.Path()
908  ma.inputMdstList("default", [], path=path)
909  skims = CombinedSkim(OneSkim(), TwoSkim(), RedSkim(), BlueSkim())
910  skims(path) # load standard lists, create skim lists, and save to uDST
911  path.process()
912 
913  When skims are combined using this class, the `BaseSkim.NoisyModules` lists of each
914  skim are combined and all silenced.
915 
916  The heavy-lifting functions `additional_setup`, `build_lists` and `output_udst` are
917  modified to loop over the corresponding functions of each invididual skim. The
918  `load_standard_lists` method is also modified to load all required lists, without
919  accidentally loading a list twice.
920 
921  Calling an instance of the `CombinedSkim` class will load all the required particle
922  lists, then run all the setup steps, then the list building functions, and then all
923  the output steps.
924  """
925 
926  __authors__ = ["Phil Grace"]
927  __description__ = None
928  __category__ = "combined"
929  __contact__ = None
930 
931  def __init__(
932  self,
933  *skims,
934  NoisyModules=None,
935  additionalDataDescription=None,
936  udstOutput=None,
937  mdstOutput=False,
938  mdst_kwargs=None,
939  CombinedSkimName="CombinedSkim",
940  OutputFileName=None,
941  ):
942  """Initialise the CombinedSkim class.
943 
944  Parameters:
945  *skims (BaseSkim): One or more (instantiated) skim objects.
946  NoisyModules (list(str)): Additional modules to silence.
947  additionalDataDescription (dict): Overrides corresponding setting of all individual skims.
948  udstOutput (bool): Overrides corresponding setting of all individual skims.
949  mdstOutput (bool): Write a single MDST output file containing events which
950  pass any of the skims in this combined skim.
951  mdst_kwargs (dict): kwargs to be passed to `mdst.add_mdst_output`. Only used
952  if ``mdstOutput`` is True.
953  CombinedSkimName (str): Sets output of ``__str__`` method of this combined skim.
954  OutputFileName (str): If mdstOutput=True, this option sets the name of the combined output file.
955  If mdstOutput=False, this option does nothing.
956  """
957 
958  if NoisyModules is None:
959  NoisyModules = []
960  # Check that we were passed only BaseSkim objects
961  if not all([isinstance(skim, BaseSkim) for skim in skims]):
962  raise NotImplementedError(
963  "Must pass only `BaseSkim` type objects to `CombinedSkim`."
964  )
965 
966  self.Skims = skims
967  self.name = CombinedSkimName
968  for skim in self:
969  skim.NoisyModules += NoisyModules
970  self.TestFiles = list({f for skim in skims for f in skim.TestFiles})
971 
972  # empty but needed for functions inherited from baseSkim to work
973  self.SkimLists = []
974 
975  if additionalDataDescription is not None:
976  for skim in self:
977  skim.additionalDataDescription = additionalDataDescription
978 
979  self._udstOutput = udstOutput
980  if udstOutput is not None:
981  for skim in self:
982  skim._udstOutput = udstOutput
983 
984  self._mdstOutput = mdstOutput
985  self.mdst_kwargs = mdst_kwargs or {}
986  self.mdst_kwargs.update(OutputFileName=OutputFileName)
987 
988  self.merge_data_structures()
989 
990  def __str__(self):
991  return self.name
992 
993  def __name__(self):
994  return self.name
995 
996  def __call__(self, path):
997  for skim in self:
998  skim._MainPath = path
999 
1000  self.initialise_skim_flag(path)
1001  self.load_standard_lists(path)
1002  self.additional_setup(path)
1003  self.build_lists(path)
1005  self.update_skim_flag(path)
1007  self.output_udst(path)
1008  self.output_mdst_if_any_flag_passes(path=path, **self.mdst_kwargs)
1009  self.set_skim_logging()
1010 
1011  def __iter__(self):
1012  yield from self.Skims
1013 
1014  def load_standard_lists(self, path):
1015  """Add all required standard list loading to the path.
1016 
1017  Note:
1018  To avoid loading standard lists twice, this function creates dummy paths
1019  that are passed through ``load_standard_lists`` for each skim. These dummy
1020  paths are then inspected, and a list of unique module-parameter combinations
1021  is added to the main skim path.
1022 
1023  Parameters:
1024  path (basf2.Path): Skim path to be processed.
1025  """
1026  ModulesAndParams = []
1027  for skim in self:
1028  DummyPath = b2.Path()
1029  skim.load_standard_lists(DummyPath)
1030 
1031  # Create a hashable data object to store the information about which
1032  # standard lists have been added to the path.
1033  ModulesAndParams.extend(tuple([
1034  (
1035  module.type(),
1036  tuple(sorted(
1037  (param.name, _hashable_list(param.values) if isinstance(param.values, list) else param.values)
1038  for param in module.available_params()
1039  if param.values != param.default
1040  )),
1041  )
1042  for module in DummyPath.modules()
1043  ]))
1044 
1045  # Take this data structure and convert it to a dict. This removes any duplicate entries.
1046  ModulesAndParams = dict.fromkeys(ModulesAndParams)
1047 
1048  # Add the (now unique) module+param combinations to the main path
1049  for module, params in ModulesAndParams:
1050  path.add_module(module, **dict(params))
1051 
1052  def additional_setup(self, path):
1053  """Run the `BaseSkim.additional_setup` function of each skim.
1054 
1055  Parameters:
1056  path (basf2.Path): Skim path to be processed.
1057  """
1058  for skim in self:
1059  skim.additional_setup(path)
1060 
1061  def build_lists(self, path):
1062  """Run the `BaseSkim.build_lists` function of each skim.
1063 
1064  Parameters:
1065  path (basf2.Path): Skim path to be processed.
1066  """
1067  for skim in self:
1068  skim.build_lists(skim._ConditionalPath or path)
1069 
1070  def output_udst(self, path):
1071  """Run the `BaseSkim.output_udst` function of each skim.
1072 
1073  Parameters:
1074  path (basf2.Path): Skim path to be processed.
1075  """
1076  for skim in self:
1077  if skim._udstOutput:
1078  skim.output_udst(skim._ConditionalPath or path)
1079 
1080  def output_mdst_if_any_flag_passes(self, *, path, **kwargs):
1081  """
1082  Add MDST output to the path if the event passes any of the skim flags.
1083  EventExtraInfo is included in the MDST output so that the flags are available in
1084  the output.
1085 
1086  The ``CombinedSkimName`` parameter in the `CombinedSkim` initialisation is used
1087  for the output filename if ``filename`` is not included in kwargs.
1088 
1089  Parameters:
1090  path (basf2.Path): Skim path to be processed.
1091  **kwargs: Passed on to `mdst.add_mdst_output`.
1092  """
1093  from mdst import add_mdst_output
1094 
1095  if not self._mdstOutput:
1096  return
1097 
1098  sum_flags = " + ".join(f"eventExtraInfo({f})" for f in self.flags)
1099  variable = f"formula({sum_flags})"
1100 
1101  passes_flag_path = b2.Path()
1102  passes_flag = path.add_module("VariableToReturnValue", variable=variable)
1103  passes_flag.if_value(">0", passes_flag_path, b2.AfterConditionPath.CONTINUE)
1104 
1105  filename = kwargs.get("filename", kwargs.get("OutputFileName", self.name))
1106 
1107  if filename is None:
1108  filename = self.name
1109 
1110  if not filename.endswith(".mdst.root"):
1111  filename += ".mdst.root"
1112 
1113  kwargs["filename"] = filename
1114 
1115  if "OutputFileName" in kwargs.keys():
1116  del kwargs["OutputFileName"]
1117 
1118  kwargs.setdefault("dataDescription", {})
1119 
1120  # If the combinedSkim is not in the registry getting the code will throw a LookupError.
1121  # There is no requirement that a combinedSkim with single MDST output is
1122  # registered so set the skimDecayMode to ``None`` if no code is defined.
1123  try:
1124  skim_code = self.code
1125  except LookupError:
1126  skim_code = None
1127  kwargs["dataDescription"].setdefault("skimDecayMode", skim_code)
1128 
1129  try:
1130  kwargs["additionalBranches"] += ["EventExtraInfo"]
1131  except KeyError:
1132  kwargs["additionalBranches"] = ["EventExtraInfo"]
1133 
1134  add_mdst_output(path=passes_flag_path, **kwargs)
1135 
1137  """Run the `BaseSkim.apply_hlt_hadron_cut_if_required` function for each skim.
1138 
1139  Parameters:
1140  path (basf2.Path): Skim path to be processed.
1141  """
1142  for skim in self:
1143  skim.apply_hlt_hadron_cut_if_required(skim._ConditionalPath or path)
1144 
1145  def set_skim_logging(self):
1146  """Run `BaseSkim.set_skim_logging` for each skim."""
1147  for skim in self:
1148  skim.set_skim_logging()
1149 
1150  @property
1151  def flags(self):
1152  """
1153  List of flags for each skim in combined skim.
1154  """
1155  return [skim.flag for skim in self]
1156 
1157  @property
1158  def flag(self):
1159  """
1160  Event-level variable indicating whether an event passes the combinedSkim or not.
1161  """
1162  return f"passes_{self}"
1163 
1164  def initialise_skim_flag(self, path):
1165  """
1166  Add the module `skimExpertFunctions.InitialiseSkimFlag` to the path, to
1167  initialise flags for each skim.
1168  """
1169  path.add_module(InitialiseSkimFlag(*self))
1170 
1171  def update_skim_flag(self, path):
1172  """
1173  Add the module `skimExpertFunctions.InitialiseSkimFlag` to the conditional path
1174  of each skims.
1175  """
1176  for skim in self:
1177  skim.postskim_path.add_module(UpdateSkimFlag(skim))
1178 
1179  @property
1180  def produce_on_tau_samples(self):
1181  """
1182  Corresponding value of this attribute for each individual skim.
1183 
1184  Raises:
1185  RuntimeError: Raised if the individual skims in combined skim contain a mix
1186  of True and False for this property.
1187  """
1188  produce_on_tau = [skim.produce_on_tau_samples for skim in self]
1189  if all(produce_on_tau):
1190  return True
1191  elif all(not TauBool for TauBool in produce_on_tau):
1192  return False
1193  else:
1194  raise RuntimeError(
1195  "The individual skims in the combined skim contain a mix of True and "
1196  "False for the attribute `produce_on_tau_samples`.\n"
1197  " It is unclear what should be done in this situation."
1198  "Please reorganise the combined skims to address this.\n"
1199  " Skims included in the problematic combined skim: "
1200  f"{', '.join(skim.name for skim in self)}"
1201  )
1202 
1204  """Read the values of `BaseSkim.MergeDataStructures` and merge data structures
1205  accordingly.
1206 
1207  For example, if ``MergeDataStructures`` has the value ``{"FEIChannelArgs":
1208  _merge_boolean_dicts.__func__}``, then ``_merge_boolean_dicts`` is run on all
1209  input skims with the attribute ``FEIChannelArgs``, and the value of
1210  ``FEIChannelArgs`` for that skim is set to the result.
1211 
1212  In the FEI skims, this is used to merge configs which are passed to a cached
1213  function, thus allowing us to apply the FEI once with all the required particles
1214  available.
1215  """
1216  for iSkim, skim in enumerate(self.Skims):
1217  for attribute, MergingFunction in skim.MergeDataStructures.items():
1218  SkimsWithAttribute = [skim for skim in self if hasattr(skim, attribute)]
1219  setattr(
1220  self.Skims[iSkim],
1221  attribute,
1222  MergingFunction(*[getattr(skim, attribute) for skim in SkimsWithAttribute])
1223  )
1224 
1226  """Check for duplicate particle list names.
1227 
1228  .. Note::
1229 
1230  Skims cannot be relied on to define their particle list names in advance, so
1231  this function can only be run after `build_lists` is run.
1232  """
1233  ParticleListLists = [skim.SkimLists for skim in self]
1234  ParticleLists = [lst for L in ParticleListLists for lst in L]
1235  DuplicatedParticleLists = {
1236  ParticleList
1237  for ParticleList in ParticleLists
1238  if ParticleLists.count(ParticleList) > 1
1239  }
1240  if DuplicatedParticleLists:
1241  raise ValueError(
1242  f"Non-unique output particle list names in combined skim! "
1243  f"{', '.join(DuplicatedParticleLists)}"
1244  )
skimExpertFunctions.CombinedSkim.flag
def flag(self)
Definition: skimExpertFunctions.py:1158
skimExpertFunctions.CombinedSkim.initialise_skim_flag
def initialise_skim_flag(self, path)
Definition: skimExpertFunctions.py:1164
skimExpertFunctions.BaseSkim.skim_event_cuts
def skim_event_cuts(self, cut, *path)
Definition: skimExpertFunctions.py:716
skimExpertFunctions.BaseSkim.ApplyHLTHadronCut
bool ApplyHLTHadronCut
Definition: skimExpertFunctions.py:536
skimExpertFunctions.UpdateSkimFlag
Definition: skimExpertFunctions.py:311
skimExpertFunctions.BaseSkim.validation_histograms
def validation_histograms(self, path)
Definition: skimExpertFunctions.py:640
skimExpertFunctions.BaseSkim.TestFiles
list TestFiles
Definition: skimExpertFunctions.py:524
skimExpertFunctions.UpdateSkimFlag.initialize
def initialize(self)
Definition: skimExpertFunctions.py:337
skimExpertFunctions.CombinedSkim.merge_data_structures
def merge_data_structures(self)
Definition: skimExpertFunctions.py:1203
skimExpertFunctions.InitialiseSkimFlag
Definition: skimExpertFunctions.py:264
skimExpertFunctions._hashable_list
Definition: skimExpertFunctions.py:32
skimExpertFunctions.CombinedSkim._check_duplicate_list_names
def _check_duplicate_list_names(self)
Definition: skimExpertFunctions.py:1225
skimExpertFunctions.BaseSkim._method_unchanged
def _method_unchanged(self, method)
Definition: skimExpertFunctions.py:810
skimExpertFunctions.CombinedSkim.output_mdst_if_any_flag_passes
def output_mdst_if_any_flag_passes(self, *path, **kwargs)
Definition: skimExpertFunctions.py:1080
skimExpertFunctions.BaseSkim.get_skim_list_names
def get_skim_list_names(self)
Definition: skimExpertFunctions.py:796
skimExpertFunctions.BaseSkim.code
def code(self)
Definition: skimExpertFunctions.py:574
skimExpertFunctions.InitialiseSkimFlag.EventExtraInfo
EventExtraInfo
Definition: skimExpertFunctions.py:288
skimExpertFunctions.InitialiseSkimFlag.__init__
def __init__(self, *skims)
Definition: skimExpertFunctions.py:275
skimExpertFunctions.UpdateSkimFlag.skim
skim
Definition: skimExpertFunctions.py:334
skimExpertFunctions.BaseSkim.name
name
Definition: skimExpertFunctions.py:589
skimExpertFunctions.InitialiseSkimFlag.skims
skims
Definition: skimExpertFunctions.py:287
skimExpertFunctions.BaseSkim.OutputFileName
OutputFileName
Definition: skimExpertFunctions.py:590
Belle2::filter
std::map< ExpRun, std::pair< double, double > > filter(const std::map< ExpRun, std::pair< double, double >> &runs, double cut, std::map< ExpRun, std::pair< double, double >> &runsRemoved)
filter events to remove runs shorter than cut, it stores removed runs in runsRemoved
Definition: Splitter.cc:43
Belle2::PyStoreObj
a (simplified) python wrapper for StoreObjPtr.
Definition: PyStoreObj.h:69
skimExpertFunctions.BaseSkim.set_skim_logging
def set_skim_logging(self)
Definition: skimExpertFunctions.py:834
skimExpertFunctions.UpdateSkimFlag.event
def event(self)
Definition: skimExpertFunctions.py:344
skimExpertFunctions.BaseSkim._MainPath
_MainPath
Definition: skimExpertFunctions.py:710
skimExpertFunctions.BaseSkim.__init__
def __init__(self, *OutputFileName=None, additionalDataDescription=None, udstOutput=True, validation=False)
Definition: skimExpertFunctions.py:578
removeParticlesNotInLists
Definition: removeParticlesNotInLists.py:1
skimExpertFunctions.CombinedSkim.mdst_kwargs
mdst_kwargs
Definition: skimExpertFunctions.py:975
skimExpertFunctions.BaseSkim.additional_setup
def additional_setup(self, path)
Definition: skimExpertFunctions.py:612
skimExpertFunctions.BaseSkim.flag
def flag(self)
Definition: skimExpertFunctions.py:768
skimExpertFunctions.UpdateSkimFlag.EventExtraInfo
EventExtraInfo
Definition: skimExpertFunctions.py:335
skimExpertFunctions.CombinedSkim.additional_setup
def additional_setup(self, path)
Definition: skimExpertFunctions.py:1052
skimExpertFunctions.BaseSkim._validation
_validation
Definition: skimExpertFunctions.py:593
skimExpertFunctions.BaseSkim
Definition: skimExpertFunctions.py:504
skimExpertFunctions.BaseSkim.postskim_path
def postskim_path(self)
Definition: skimExpertFunctions.py:694
skimExpertFunctions.CombinedSkim.Skims
Skims
Definition: skimExpertFunctions.py:956
skimExpertFunctions.CombinedSkim.build_lists
def build_lists(self, path)
Definition: skimExpertFunctions.py:1061
skimExpertFunctions.BaseSkim.build_lists
def build_lists(self, path)
Definition: skimExpertFunctions.py:631
skimExpertFunctions._hashable_list.__hash__
def __hash__(self)
Definition: skimExpertFunctions.py:37
skimExpertFunctions.BaseSkim.__call__
def __call__(self, path, *udstOutput=None, validation=None)
Definition: skimExpertFunctions.py:648
skimExpertFunctions.CombinedSkim._mdstOutput
_mdstOutput
Definition: skimExpertFunctions.py:974
skimExpertFunctions.BaseSkim.apply_hlt_hadron_cut_if_required
def apply_hlt_hadron_cut_if_required(self, path)
Definition: skimExpertFunctions.py:883
skimExpertFunctions.InitialiseSkimFlag.initialize
def initialize(self)
Definition: skimExpertFunctions.py:294
skim.registry
Definition: registry.py:1
skimExpertFunctions.BaseSkim.load_standard_lists
def load_standard_lists(self, path)
Definition: skimExpertFunctions.py:599
skimExpertFunctions.BaseSkim._udstOutput
_udstOutput
Definition: skimExpertFunctions.py:592
skimExpertFunctions.CombinedSkim.apply_hlt_hadron_cut_if_required
def apply_hlt_hadron_cut_if_required(self, path)
Definition: skimExpertFunctions.py:1136
skimExpertFunctions.BaseSkim.NoisyModules
NoisyModules
Definition: skimExpertFunctions.py:511
skimExpertFunctions.CombinedSkim.flags
def flags(self)
Definition: skimExpertFunctions.py:1151
skimExpertFunctions.BaseSkim.update_skim_flag
def update_skim_flag(self, path)
Definition: skimExpertFunctions.py:783
skimExpertFunctions.InitialiseSkimFlag.event
def event(self)
Definition: skimExpertFunctions.py:301
skimExpertFunctions.UpdateSkimFlag.__init__
def __init__(self, skim)
Definition: skimExpertFunctions.py:323
skimExpertFunctions.CombinedSkim.set_skim_logging
def set_skim_logging(self)
Definition: skimExpertFunctions.py:1145
skimExpertFunctions.BaseSkim.additionalDataDescription
additionalDataDescription
Definition: skimExpertFunctions.py:591
skimExpertFunctions.CombinedSkim.output_udst
def output_udst(self, path)
Definition: skimExpertFunctions.py:1070
skimExpertFunctions.CombinedSkim
Definition: skimExpertFunctions.py:895
skimExpertFunctions.BaseSkim.initialise_skim_flag
def initialise_skim_flag(self, path)
Definition: skimExpertFunctions.py:776
skimExpertFunctions.BaseSkim._ConditionalPath
_ConditionalPath
Definition: skimExpertFunctions.py:713
skimExpertFunctions.CombinedSkim.__init__
def __init__(self, *skims, NoisyModules=None, additionalDataDescription=None, udstOutput=None, mdstOutput=False, mdst_kwargs=None, CombinedSkimName="CombinedSkim", OutputFileName=None)
Definition: skimExpertFunctions.py:931
skimExpertFunctions.CombinedSkim.update_skim_flag
def update_skim_flag(self, path)
Definition: skimExpertFunctions.py:1171
skimExpertFunctions.BaseSkim.SkimLists
SkimLists
Definition: skimExpertFunctions.py:594
skimExpertFunctions.CombinedSkim.load_standard_lists
def load_standard_lists(self, path)
Definition: skimExpertFunctions.py:1014
skimExpertFunctions.BaseSkim.output_udst
def output_udst(self, path)
Definition: skimExpertFunctions.py:860