PyConf
Wrappers for defining safe yet flexible configuration for Gaudi applications.
PyConf is broadly split in two parts:
Wrappers for creating data and control flow using composable
Algorithm
andTool
classes.Helpers for defining a configuration based on function call stacks that allow for changes to be configured deep down the stack.
To use algorithms and tools, don’t import them from Configurables
but instead
from PyConf.Algorithms
and PyConf.Tools
:
>>> from PyConf.Algorithms import MyGaudiAlgorithm
>>> from PyConf.Tools import MyTool
Any single Algorithm
or Tool
is immutable after instantiation, and hence
the data flow that produces its inputs is known once the Algorithm
or Tool
has been created. The outputs of algorithms are modeled with DataHandle
objects, which know the underlying C++ type of the data on the transient event
store. When instantiating a component, the types of the provided inputs must be
compatible with those expected by the component, otherwise an exception is
raised.
The control flow of an application is defined by linking
PyConf.control_flow.CompositeNode
instances. Each node has a particular
control flow mode, defined by PyConf.control_flow.NodeLogic
.
Application data flow is automatically deduced by PyConf and Gaudi. The user only needs to define the control flow. For each algorithm in the control flow, the scheduler ensures that algorithm’s data dependencies are met.
Idiomatically, the configuration of individual algorithms is done within small helper functions that are configured via arguments:
>>> @configurable
... def gec(threshold=9750):
... print('Applying threshold: {}'.format(threshold))
Rather than having to pass changes to default keyword arguments all the way
down a call stack, values can be bound to @configurable
functions and these
will override the defaults:
>>> def intermediate_step():
... gec()
...
>>> def run_application():
... with gec.bind(threshold=11000):
... intermediate_step()
...
>>> run_application()
Applying threshold: 11000
In this example, when the intermediate_step
function calls gec
, then value
of the threshold
that was bound to gec
inside run_application
,
1100, will be used instead of the default 9750. The power of this approach is
that the behaviour of gec
is unaffected outside of the with
context:
>>> gec()
Applying threshold: 9750
Usage of bind
in HLT1 and HLT2 lines is very rare, as individual lines do not
usually need to configure deep down the call stack, and can instead pass
changes to thresholds directly to the individual functions that create their
input particles.