Belle II Software  release-05-02-19
metamodules.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 """This file contains python modules that generally decorate other modules and paths
5 to serve a slightly changed purpose or circumstance.
6 
7 Note:
8  A great deal of the these modules are quite general purpose helper constructs,
9  which might be helpful in other parts of the BASF2, and might therefore be better
10  placed in the framework folder.
11 """
12 
13 import basf2
14 import ROOT
15 from ROOT import Belle2
16 
17 import cProfile
18 import pstats
19 
20 import logging
21 
22 from ROOT import Belle2
23 
24 
25 def get_logger():
26  return logging.getLogger(__name__)
27 
28 
29 class WrapperModule(basf2.Module):
30 
31  """Wrapping module base class that wraps a single module to slightly change its behaviour.
32 
33  The base implementation does nothing, but forward the relevant methods to the wrapped module.
34 
35  Note:
36  Implements the decorator/wrapper pattern.
37 
38  Attributes:
39  module (basf2.Module): The wrapped module instance.
40  """
41 
42  def __init__(self, module):
43  """Create a new wrapper module around the given module. This base implementation does not change anything,
44  so there is no reason to use this base implementation alone."""
45  super(WrapperModule, self).__init__()
46  name = self.compose_wrapped_module_name(module)
47 
48 
49  self.module = module
50 
51  # Forward the logging parameters
52  self.set_debug_level(self.module.logging.debug_level)
53  self.set_abort_level(self.module.logging.abort_level)
54 
55  if self.module.logging.log_level != basf2.LogLevel.default:
56  self.set_log_level(self.module.logging.log_level)
57  self.set_log_info(self.module.logging.log_level,
58  self.module.logging.get_info(self.module.logging.log_level))
59 
60  # Forward the name of this module to the C++ world
61  self.set_name(name)
62 
63  @property
64  def wrapper_name(self):
65  """Name of the wrapper class."""
66  return self.__class__.__name__
67 
68  @property
69  def param(self):
70  """Forwards the parameters"""
71  return self.module.param
72 
73  @property
74  def available_params(self):
75  """Forwards the avaiilable parameters"""
76  return self.module.available_params
77 
78  def compose_wrapped_module_name(self, module):
79  """Compose a name that indicates the wrapped module."""
80  return "{wrapper_name}({module_name})".format(module_name=module.name(),
81  wrapper_name=self.wrapper_name)
82 
83  def get_name(self):
84  """Forwards the name()."""
85  return self.name()
86 
87  def initialize(self):
88  """Initialize method of the module"""
89  self.module.initialize()
90 
91  def beginRun(self):
92  """Begin run method of the module"""
93  self.module.beginRun()
94 
95  def event(self):
96  """Event method of the module"""
97  self.module.event()
98 
99  def endRun(self):
100  """End run method of the module"""
101  self.module.endRun()
102 
103  def terminate(self):
104  """Terminate method of the module"""
105  self.module.terminate()
106 
107 
109 
110  """Wrapper module that evaluates the computational performance of python modules.
111 
112  Uses cProfile.
113 
114  Attributes:
115  module (basf2.Module): The wrapped module that should be profiled.
116  Should be a module written in Python, since the profile interacts
117  with the interpretor for the measurements, but cannot look into c++ implementations.
118 
119  output_file_name (str, optional): Path to the file where the profiling information
120  shall be stored. Defaults to profile.txt.
121 
122  profiler (cProfile.Profile): Profiler instance to manage and extract the profiling statistics.
123  """
124 
125 
126  default_output_file_name = "profile.txt"
127 
128  def __init__(self, module, output_file_name=None):
129  """Create a new PyProfilingModule wrapped around the given module
130  which outputs its results to the output_file_name of given (if not, to profile.txt)."""
131  super(PyProfilingModule, self).__init__(module)
132 
133 
135 
136  if output_file_name is not None:
137  self.output_file_name = output_file_name
138 
139  def initialize(self):
140  """Initialize method of the module"""
141 
142  self.profiler = cProfile.Profile()
143  super(PyProfilingModule, self).initialize()
144 
145  def event(self):
146  """Event method of the module"""
147  profiler = self.profiler
148  profiler.enable()
149  super(PyProfilingModule, self).event()
150  profiler.disable()
151 
152  def terminate(self):
153  """Terminate method of the module"""
154  super(PyProfilingModule, self).terminate()
155  sortby = 'cumulative'
156  with open(self.output_file_name, 'w') as profile_output_file:
157  profile_stats = pstats.Stats(self.profiler, stream=profile_output_file)
158  profile_stats.sort_stats(sortby)
159  profile_stats.print_stats()
160 
161 
163 
164  """Wrapper module to conditionally execute module and continue with the normal path afterwards.
165 
166  There are two ways to specify the condition.
167  One way is to override the condtion(self) method in a subclass.
168  The second way is to give a function as the second argument to the module constructor,
169  which is called each event.
170 
171  Attributes:
172  module (basf2.Module): The module executed, if the condition is met.
173 
174  condition (function() -> bool, optional): Function executed at each event to determine,
175  if the given module shall be executed.
176  If None call the condition method instead, which can be overridden by subclasses.
177 
178  """
179 
180  def __init__(self, module, condition=None):
181  """Initialisation method taking the module instance to be wrapped.
182 
183  Args:
184  module (basf2.Module): The module executed, if the condition is met.
185  condition (function() -> bool, optional): Function executed at each event to determine,
186  if the given module shall be executed.
187  If None call the condition method instead, which can be overridden by subclasses.
188  """
189 
190  super(IfModule, self).__init__(module)
191  if condition is not None:
192 
194  self.condition = condition
195 
196  def condition(self):
197  """Condition method called if not given a condition function during construction.
198 
199  Can be overridden by a concrete subclass to specify
200  under which condition the wrapped module should be executed.
201  It can also be shadowed by a condition function given to the constructor of this module.
202 
203  Returns:
204  bool: The indication if the wrapped module should be executed.
205  Always True in the base implementation
206  """
207  return True
208 
209  def event(self):
210  """Event method of the module
211 
212  Evaluates the condition and sets the return value of this module
213  to trigger the execution of the wrapped module.
214  """
215 
216  if self.condition():
217  super(IfModule, self).event()
218 
219 
220 def is_storearray_present(storearray_name,
221  storearray_durability=0):
222  """Checks if a StoreArray with name and durability is present in the DataStore.
223 
224  Only works during the event processing phase, but not on initialisation,
225  due to limitation of the python interface to the framework
226  """
227  storearray_list = Belle2.PyStoreArray.list(storearray_durability)
228  return storearray_name in storearray_list
229 
230 
232 
233  """Conditional execution of the wrapped module if a StoreArray is present.
234 
235  Attributes:
236  storearray_name (str): The name of the StoreArray which presence has to be checked.
237  storearray_durability (int): The durability of the StoreArray
238  storearray_is_present (bool): The flag whether the StoreArray is present.
239  Set during initialisation.
240  """
241 
242  def __init__(self,
243  module,
244  storearray_name,
245  storearray_durability=0):
246  """
247  Args:
248  module (basf2.Module): The module executed, if the condition is met.
249  storearray_name (str): The name of the StoreArray which presence has to be checked.
250  storearray_durability (int, optional): The durability of the StoreArray. Default 0.
251  """
252 
253  super(IfStoreArrayPresentModule, self).__init__(module)
254 
255 
256  self.storearray_name = storearray_name
257 
258 
259  self.storearray_durability = storearray_durability
260 
261 
262  self.storearray_is_present = None
263 
264  def initialize(self):
265  """Initialize the contianed module (only of the condition is true)."""
266  if self.condition():
267  super().initialize()
268 
269  def condition(self):
270  """Returns true if the StoreArray is present.
271 
272  Checks presence of the StoreArray once and remembers the result for all following events.
273  """
274  if self.storearray_is_present is None:
275  self.storearray_is_present = is_storearray_present(self.storearray_name,
277  return self.storearray_is_present
278 
279 
281 
282  """Conditional execution of the wrapped module based if a StoreArray is not present."""
283 
284  def condition(self):
285  """Returns false if the StoreArray is present.
286 
287  Checks presence of the StoreArray once and remembers the result for all following events.
288  """
289  return not IfStoreArrayPresentModule.condition(self)
290 
291 
293 
294  """Conditional execution of the wrapped module based on the presence of Monte Carlo information.
295  """
296 
297  def __init__(self, module):
298  """
299  Args:
300  module (basf2.Module): The module executed, if the condition is met.
301  """
302  super(IfMCParticlesPresentModule, self).__init__(module, "MCParticles")
303 
304 
305 class PathModule(basf2.Module):
306 
307  """Wrapper for a BASF2 path into a module such that
308  it can be passed around and added to a BASF2 path as a BASF2 module.
309 
310  The wrapper is implement in such a way that it unconditionally executes
311  the contained path by means of a positive return value.
312  The calling path is continued after the execution of the wrapped path.
313 
314  Attributes:
315  _path (basf2.Path): The wrapped execution path.
316  """
317 
318  def __init__(self, path=None, modules=None):
319  """Initialises the module with a path to be wrapped.
320 
321  May also give a list of modules that should be appended to the path.
322  If the path is omitted a new basf2.Path is constructed.
323 
324  Args:
325  path (basf2.Path): The execution path to be wrapped.
326  If no path is given create a new one.
327 
328  modules (iterable of basf2.Module): Module to be added to the path.
329  """
330 
331  super(PathModule, self).__init__()
332 
333  if path is None:
334  path = basf2.create_path()
335 
336 
337  self._path = path
338 
339  if modules:
340  for module in modules:
341  path.add_module(module)
342 
343  self.if_true(path, basf2.AfterConditionPath.CONTINUE)
344 
345  # Pass a telling name to the C++ world
346  if modules is None:
347  itemCount = 0
348  else:
349  itemCount = len(modules)
350  self.set_name("{path_module} ({items} modules):".format(path_module=self.__class__.__name__,
351  items=itemCount))
352 
353  def event(self):
354  """Event method of the module
355 
356  Sets the return value of this module to true and triggers the execution of the wrapped path.
357  """
358 
359  self.return_value(True)
tracking.metamodules.WrapperModule.module
module
The wrapped module.
Definition: metamodules.py:49
tracking.metamodules.IfStoreArrayPresentModule.storearray_durability
storearray_durability
Durability of the StoreArray to be checked (int).
Definition: metamodules.py:256
tracking.metamodules.WrapperModule.initialize
def initialize(self)
Definition: metamodules.py:87
tracking.metamodules.PyProfilingModule.event
def event(self)
Definition: metamodules.py:145
tracking.metamodules.IfStoreArrayNotPresentModule
Definition: metamodules.py:280
tracking.metamodules.WrapperModule
Definition: metamodules.py:29
tracking.metamodules.PathModule.__init__
def __init__(self, path=None, modules=None)
Definition: metamodules.py:318
tracking.metamodules.PyProfilingModule.initialize
def initialize(self)
Definition: metamodules.py:139
tracking.metamodules.WrapperModule.compose_wrapped_module_name
def compose_wrapped_module_name(self, module)
Definition: metamodules.py:78
tracking.metamodules.IfModule.__init__
def __init__(self, module, condition=None)
Definition: metamodules.py:180
tracking.metamodules.IfMCParticlesPresentModule.__init__
def __init__(self, module)
Definition: metamodules.py:297
tracking.metamodules.IfStoreArrayPresentModule
Definition: metamodules.py:231
Belle2::PyStoreArray::list
static std::vector< std::string > list(DataStore::EDurability durability=DataStore::EDurability::c_Event)
Return list of available arrays for given durability.
Definition: PyStoreArray.cc:21
tracking.metamodules.WrapperModule.terminate
def terminate(self)
Definition: metamodules.py:103
tracking.metamodules.IfStoreArrayPresentModule.initialize
def initialize(self)
Definition: metamodules.py:264
tracking.metamodules.PyProfilingModule.profiler
profiler
The used profiler instance.
Definition: metamodules.py:142
tracking.metamodules.IfStoreArrayPresentModule.__init__
def __init__(self, module, storearray_name, storearray_durability=0)
Definition: metamodules.py:242
tracking.metamodules.IfModule.event
def event(self)
Definition: metamodules.py:209
tracking.metamodules.WrapperModule.endRun
def endRun(self)
Definition: metamodules.py:99
tracking.metamodules.WrapperModule.param
def param(self)
Definition: metamodules.py:69
tracking.metamodules.WrapperModule.event
def event(self)
Definition: metamodules.py:95
tracking.metamodules.PathModule._path
_path
The contained path.
Definition: metamodules.py:337
tracking.metamodules.WrapperModule.get_name
def get_name(self)
Definition: metamodules.py:83
tracking.metamodules.PathModule
Definition: metamodules.py:305
tracking.metamodules.IfMCParticlesPresentModule
Definition: metamodules.py:292
tracking.metamodules.IfModule
Definition: metamodules.py:162
tracking.metamodules.PyProfilingModule.__init__
def __init__(self, module, output_file_name=None)
Definition: metamodules.py:128
tracking.metamodules.PyProfilingModule.output_file_name
output_file_name
The output file name the results will be written into.
Definition: metamodules.py:134
tracking.metamodules.PyProfilingModule
Definition: metamodules.py:108
tracking.metamodules.WrapperModule.wrapper_name
def wrapper_name(self)
Definition: metamodules.py:64
tracking.metamodules.WrapperModule.available_params
def available_params(self)
Definition: metamodules.py:74
tracking.metamodules.IfStoreArrayPresentModule.storearray_name
storearray_name
Name of the StoreArray to be checked (str).
Definition: metamodules.py:253
tracking.metamodules.WrapperModule.beginRun
def beginRun(self)
Definition: metamodules.py:91
tracking.metamodules.WrapperModule.__init__
def __init__(self, module)
Definition: metamodules.py:42
tracking.metamodules.IfModule.condition
condition
Condition function called at each event to determine if wrapped module should be executed.
Definition: metamodules.py:194
tracking.metamodules.PyProfilingModule.default_output_file_name
string default_output_file_name
The default name for output if none is given.
Definition: metamodules.py:126
tracking.metamodules.PyProfilingModule.terminate
def terminate(self)
Definition: metamodules.py:152
tracking.metamodules.PathModule.event
def event(self)
Definition: metamodules.py:353
tracking.metamodules.IfStoreArrayPresentModule.storearray_is_present
storearray_is_present
Flag that the StoreArray is present (bool).
Definition: metamodules.py:259