Systematics Handling¶
In general most CP Algorithms will have to deal with systematics, be it that they add their own systematics or that their inputs are affected by systematics, or (quite likely) both.
For that every algorithm implements an internal loop over the systematics that affect that algorithm in particular. That gets configured automatically to run the minimal set of systematics the algorithm needs to process. In general all algorithms will just have a single systematics loop, and if an algorithm would need to run multiple systematics loops it should be split into multiple algorithms.
In practical terms the algorithms can generally be written in the same way as an algorithm without systematics, just with systematics handles instead of their non-systematics equivalent. The systematics handles will determine the list of systematics to run, the exact inputs to read and the outputs to write.
Note that for efficiency purposes it is preferred to write systematics output as individual decorations instead of systematics varied containers. The issue with systematics-varied containers is that they propagate the systematics to all algorithms reading that container, while systematics-varied decorations only propagate them to algorithms reading that decoration.
A systematic is assumed to be affecting the outputs of your algorithm if it either affects one of the inputs or is introduced by the algorithm itself. This is generally the safe and conservative thing to do. However, it can also add superfluous systematics, because either you read more inputs than you needed to create a given output, or because some input systematics may technically affect the output systematics but the effect is too tiny to be relevant. An example of the later are the e-gamma momentum systematics which technically change the pt of the object, but the change is too small to be meaningful.
User Configuration Level¶
The CommonServices block provides options for controlling systematics
evaluation. In most cases the defaults are sufficient, but the options
below allow fine-tuning when needed:
CommonServices:
runSystematics: True # Enable/disable systematics (default: True for MC)
filterSystematics: ".*JET.*" # Regex to filter systematics
onlySystematicsCategories: # Predefined categories
- jets
- electrons
systematicsHistogram: systematicsList # Write list of evaluated systematics
separateWeightSystematics: True # Separate histogram for weight systematics
Available Options¶
runSystematics: Enable or disable computation of systematic variations.
The default is None, which means systematics are run on MC but not on data.
Set to False to disable all systematics processing.
filterSystematics: A regex pattern to select which systematics to
evaluate. Only systematics whose names match the pattern are included. This
overrides onlySystematicsCategories if both are specified.
onlySystematicsCategories: A list of predefined category names to enable.
Available categories:
| Category | Systematics prefixes |
|---|---|
jets |
JET_ |
jer |
JET_JER |
electrons |
EG_, EL_ |
muons |
MUON_ |
photons |
EG_, PH_ |
taus |
TAUS_ |
met |
MET_ |
tracks |
TRK_ |
ftag |
FT_ |
event |
GEN_, PRW_ |
This is useful for partial ntuple productions or studies where you only need specific systematics.
systematicsHistogram: The name of a histogram to write containing the
list of evaluated systematics. This is helpful for downstream processing
frameworks that need to know which systematics were computed.
separateWeightSystematics: If systematicsHistogram is enabled, creates
an additional histogram containing only weight-based systematics. This helps
histogramming frameworks distinguish between systematics that require
recomputing observables and those that only change weights.
Systematics in Output¶
Variables affected by systematics appear in the output with a %SYS% suffix
that resolves to the systematic name. For example, jet pt might appear as:
jet_pt_NOSYS- nominal valuejet_pt_JET_JER_EffectiveNP_1__1up- varied by JER systematic
Variables unaffected by systematics (like eta) only appear once without
the %SYS% suffix.
Configuration Block Level¶
When developing configuration blocks, you work with container and decoration
names that include a %SYS% placeholder. The configuration system
automatically manages how these map to actual systematic variations.
The %SYS% Naming Convention¶
Container names in the configuration automatically get %SYS% appended:
# In a config block's makeAlgs method:
alg.taus = config.readName(self.containerName) # Returns "AnaTaus_%SYS%"
alg.tausOut = config.copyName(self.containerName) # Creates shallow copy with new name
The %SYS% suffix is resolved at runtime to the appropriate systematic name
(e.g., AnaTaus_NOSYS, AnaTaus_JET_JER_EffectiveNP_1__1up).
Container Access Methods¶
readName(containerName): Returns the current name of the container for
reading. Use this when your algorithm only needs to read the container.
copyName(containerName): Registers that a shallow copy will be made and
returns the new container name. Use this when your algorithm needs to modify
objects (e.g., applying calibrations).
The order matters: If your algorithm makes a shallow copy, you must
first call readName to get the existing name, before calling
copyName to register the copy and update the name.
Algorithm Level¶
Basic Systematics Handles¶
The list of systematics is managed via the SysListHandle, to which all
other systematics handles are connected. It also provides a list of
systematics to iterate over.
For reading a container one either uses a SysReadHandle or a
SysCopyHandle. The former will just read a const-qualified object,
while the later will provide a mutable object (unless the template
argument is const-qualified). The SysCopyHandle works internally by
retrieving an object, making a shallow copy and registering it in the
event store. It is typically because the underlying tool needs to
operate on a mutable object (and thereby needs a shallow copy), but it
can also be used if a shallow copy is needed for other reasons.
There is also a SysWriteHandle, but that is rarely used within the CP
Algorithms, as most algorithms either apply corrections to existing
objects or add extra decorations to them. Unlike the regular write
handles if you need to write both the object and its associated aux
store you do it with a single handle.
Note that unlike for Athena handles, there is no distinction between
Handle and HandleKey, but instead the handles provide the
functionality of both, and just return a pointer to the container
directly.
If you need to read or write a decoration that is affected by
systematics you need to do so via a SysReadDecorHandle or
SysWriteDecorHandle. Note that these always need to be connected to
the underlying container handle, and don't allow retrieving the
underlying container (unlike the Athena decoration handles).
Important: You have to initialize all the systematics handles
inside initialize.
Notes from the Developers¶
The basic idea of the systematics handling is that if you have an algorithm that works and doesn't have systematics handling, adding systematics support should be mostly a straightforward process of replacing existing interactions with the event store and adding a systematics list.
The systematics handle interface is based on the AsgTool::evtStore()
interface, not the AthenaMT data handles. In part that is because that
was the dominant interface in analysis at the time, but the AthenaMT
data handles are also far more complex to implement, and they also
provide a lot of extra behavior and guarantees that are likely to be
more hurtful than helpful in our use case.
While it is discouraged, it is possible to use the StoreGate data handles in the CP Algorithms, as long as they are run upstream of any systematics. Even if your algorithm doesn't introduce any systematics, if the object has systematics you have to switch to systematics handles.
The systematics handles anticipate to be used in AthenaMT eventually, but they don't support it yet. To add support for AthenaMT one would have to either layer the systematics handles on StoreGate data handles (preferred), or have to directly declare the data dependencies they introduce. This ought to be fairly straightforward, but the assumption is that the CP tools themselves likely still contain non thread-safe constructs internally.
The motivation for the copy handles is two-fold: For analysis it is
quite common to update objects, and it is quite tedious to do a manual
shallow copy each time. So something like an Athena UpdateHandle would
be ideal, and the copy handle is a multi-threading safe analogue. Also,
for adding momentum systematics it is necessary to do a shallow copy per
systematic (so that they each get their own pt in the aux-store). That
is much more practical if the handles do the copy. This was even more
important in the past when all systematics where implemented via shallow
copies.
Originally systematics were handled purely through shallow copies, including shallow copies for scale factor systematics, etc. While that worked technically the problem is that it means that systematics are tracked at the level of containers instead of decorations. That is far too coarse, e.g. electron pt would get any systematic that affects any systematic that affects any electron decoration, which if you apply overlap removal also includes things like the jet momentum systematics. So we switched most systematics to be differently named decorations on the same container. For some variables (particularly pt, etc.) that is not possible, since their name is hard-coded in the xAOD core classes, otherwise we'd likely switch completely to that mechanism.