Main Athena settings / Flags

Last update: 27 Nov 2020 [History] [Edit]

Types of configuration settings

The Athena settings can be categorized as follows:

  1. Frequently changed settings (e.g. input file location)
  2. Settings affecting multiple components (e.g. if the input file is MC or RAW data)
  3. Settings of main components (e.g. number of threads)
  4. Settings specific to a single component changed only during debugging and in very special situations (a threshold for a single detector readout element)

Settings 1-3 are treated as main Athena settings are are called flags. They are defined in AthenaConfiguration.AllConfigFlags and are further categorized into domains like Input, Global, Calo

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 example below illustrates a typical code arrangement.

# main job definition file
from AthenaConfiguration.AllConfigFlags import ConfigFlags
ConfigFlags.Input.Files = ...
ConfigFlags.Domain.flagX= True
ConfigFlags.lock() # locking happens here

The driver scripts typically use command line parser(look for getArgumentParser) capable of reading the flag values from the command line. That is, in the command line you should be able to write Domain.flagX=True.

Main flags defining job input Exec.MaxEvents, Exec.SkipEvents and Input.Files are mapped to options --evtMax, --skipEvents, --filesInput correspondingly.

The 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.

Using flags in configuration fragments

The flags are passed to functions generating configuration always as a first argument. In the configuration fragment they can be used to drive settings of the component in any imaginable way.

...
def funCfg(flags): #
    ...
    if flags.Domain.flagX:
       # some setting that depends on flagX
    ...

For information flags can also be printed with flags.dump().

Redirecting flags

The flags are unchangeable in configuration fragments. However there are cases when the same set of components need to be configured with different settings. In such case the configuration fragments should obtain effectively a different set of flags. This is achieved as follows. The flags set should contain a clone for domain/subdomain under an alternative name (see how to do this below). For example: flags.Domain.flagX and flags.DomainAlt.flagX. In the configuration fragment then the rewiring can happen as follows:

def aCfg(flags):
    if flags.Domain.flagX: # this code depends only on the flag.Domain.FlagX
      ...

def bCfg(flags):

    x = aCfg(flags) # configure one set of components
    redirectedFlags = flags.cloneAndReplace("Domain", "DomainAlt")
    y = aCfg(redirectedFlags) # configure another set of components differently

Defining flags

Initial settings, dependent values

The simplest flag definition contains the name and the initial/default value.

flags.addFlag("Domain.SubDomain.flagX", value)

The nesting depth is not limited. And the type of the flag is not constrained.

The initial value can be replaced by a function. This is done for the flags for which the value depends on another flags value e.g.:

flags.addFlag("Domain.SubDomain.flagX",  lambda otherFlags: not otherFlags.AnyDomain.anyFlag )

In the above example the value of the flag 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 ConfigFlags 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 the loading of flags that are unnecessary to a given workflow.

Registration requires defining a function.

    def __detector():
        from AthenaConfiguration.DetectorConfigFlags import createDetectorConfigFlags
        return createDetectorConfigFlags()
    acf.addFlagsCategory( "Detector", __detector )

In the last line the 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 flag 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. See for an example how the flags defined in other packages are declared 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. So defined flags are then typically used in the flags redirection.