Configuration Flags¶
Types of configuration settings¶
The Athena settings can be categorized as follows:
- Frequently changed settings (e.g. input file location)
- Settings affecting multiple components (e.g. if the input file is MC or RAW data)
- Settings of main components (e.g. number of threads)
- Settings specific to a single component changed only during debugging and in very special situations (a threshold for a single detector readout element)
Cases 1-3 are made configurable through flags.
They are defined in AthenaConfiguration.AllConfigFlags and are further categorized into domains/categories like
Input, Output, Calo, etc.
Using flags¶
Setting flag values¶
The flags are set at the start of the job definition. Then they should be locked for writing and can be used to drive the configuration. The flags instance is always local and usually called flags.
It needs to be initialised at the start of the job using initConfigFlags:
from AthenaConfiguration.AllConfigFlags import initConfigFlags
flags = initConfigFlags()
flags.Input.Files = ...
flags.Domain.flagX = True
flags.lock()
Flags have a default value that can depend on values of other flags (more on that below). However setting the flag value in one of the aforementioned ways makes the flag value independent of other flags and constant.
Some flags are filled directly from corresponding command line arguments, e.g. flags defining job input Exec.MaxEvents, Exec.SkipEvents and Input.Files are mapped to the command line options --evtMax, --skipEvents and --filesInput, respectively.
Using flags in configuration fragments¶
Flags should be passed to Cfg functions as the first argument (see conventions).
In the configuration fragment they can be used to drive settings of the component in any imaginable way.
def MyComponentCfg(flags):
...
if flags.Domain.flagX:
# some setting that depends on flagX
...
Redirecting flags¶
Once locked, flags are read-only. However there are cases when the same set of components need to be configured with different settings.
This can be achieved by duplicating a set of flags for a certain (sub)domain under an alternative name
(see how to do this below), e.g. flags.Domain.flagX and flags.DomainAlt.flagX.
In the configuration fragment these alternative flags can be mapped to their original name as follows:
def ComponentACfg(flags):
if flags.Domain.flagX: # this code depends only on the flag.Domain.FlagX
...
def ComponentBCfg(flags):
x = ComponentACfg(flags) # configure one set of components
redirectedFlags = flags.cloneAndReplace("Domain", "DomainAlt")
y = ComponentACfg(redirectedFlags) # configure another set of components differently
Flag existence¶
To check for the existence of a configuration flag or category use:
flags.hasCategory("Domain")
flags.hasFlag("Domain.flagX")
Note
The use of hasattr or the in operator is discouraged because it does not distinguish between
flags and categories and could lead to accidental matches.
Defining flags¶
Initial settings and dependent values¶
The simplest flag definition contains the name and the initial/default value.
flags.addFlag("Domain.SubDomain.flagX", value)
The initial value can be replaced by a function. This is done for the flags for which the value depends on another flag value, e.g.:
flags.addFlag("Domain.SubDomain.flagX",
lambda otherFlags: not otherFlags.AnyDomain.anyFlag)
flags.Domains.SubDomain.flagX is simply a logical function of another flag. But it can by any function of other flags or can use other sources of information to derive the value.
Once the flag value is set explicitly the function is not used anymore.
Dynamic flags loading¶
When the main flags (those defined in AthenaConfiguration.AllConfigFlags) are imported only a few of them are defined. Many other flags are available, they are grouped and are registered and will be provided if any flag in this domain will be needed (for either setting or for obtaining the value of it).
This is done to avoid loading of flags that are unnecessary for a given workflow.
Registration requires defining a function.
def __detector():
from AthenaConfiguration.DetectorConfigFlags import createDetectorConfigFlags
return createDetectorConfigFlags()
acf.addFlagsCategory("Detector", __detector)
Detector is the name of the flags domain and has to agree with the name of flags defined inside of createDetectorConfigFlags (otherwise automatic loading will miss them). The flags provided by this line are then available as
flags.Detector.....
One caveat in this approach is that the main flags definition file depends on a particular package. Such a dependency can be removed by adding an additional layer of protection.
Examples can be found in AllConfigFlags.
The flags that are loaded dynamically can have further subsets/subdomains that are loaded dynamically as well.
Loading with name change¶
During the dynamic loading the flag names can be prefixed. That is used in the situation when domain flags (with potentially different values) are present in the set of flags multiple times. The most prominent example are many flags for various tracking cuts that are loaded here and tracking cuts for different HLT signatures. In the first place such flags are defined without domain prefix. The prefix is determined at loading and can be varied as in the example. Flags defined in such a way are then typically used in the flags redirection.