Systematics¶
Handling systematic uncertainties is one of the core capabilities of the framework. The system is designed so that shape and weight systematics can be included without linearly multiplying the execution time, thanks to the caching system described in Architecture Overview.
How Systematics Work¶
Systematics are handled through dynamic parameters.
A module can declare that it has a parameter with multiple possible values – for example, a JEC correction module might declare a jec_systematic parameter with values central, up, and down.
When a downstream module (typically a histogram builder) requests a “multi-run,” the framework:
Collects the
ParameterSpecfrom all modules in the pipeline.Uses the
RunBuilderto determine which parameter combinations to execute.Re-runs the pipeline once for each combination, producing a set of event collections.
Passes all event collections to the requesting module (a
PureResultModule), which aggregates them into a single result with avariationaxis.
![digraph systematics {
rankdir=LR;
bgcolor="transparent";
node [shape=box, style="rounded,filled", fillcolor="#f8fafc", color="#cbd5e1", fontname="Helvetica", penwidth=1.5];
edge [color="#64748b", fontname="Helvetica", fontsize=10, penwidth=1.2];
InputChunk [shape=oval, fillcolor="#f1f5f9", label="Input Chunk\n(TrackedColumns)"];
RunBuilder [shape=diamond, fillcolor="#fef3c7", color="#fcd34d", label="RunBuilder\nGenerates Variations"];
PipelineCentral [label="Pipeline (Central)", fillcolor="#e0f2fe", color="#7dd3fc"];
PipelineJECUp [label="Pipeline (JEC Up)", fillcolor="#fee2e2", color="#fca5a5"];
PipelineJECDn [label="Pipeline (JEC Down)", fillcolor="#dcfce7", color="#86efac"];
HistogramBuilder [label="HistogramBuilder\n(PureResultModule)", fillcolor="#f3e8ff", color="#d8b4fe"];
FinalResult [shape=note, fillcolor="#ffffff", label="Histogram\n(with variation axis)"];
InputChunk -> RunBuilder;
RunBuilder -> PipelineCentral;
RunBuilder -> PipelineJECUp;
RunBuilder -> PipelineJECDn;
PipelineCentral -> HistogramBuilder;
PipelineJECUp -> HistogramBuilder;
PipelineJECDn -> HistogramBuilder;
HistogramBuilder -> FinalResult;
}](../_images/graphviz-30b5c973173c4288efdb236f6ee3b4b5553ad3b3.png)
The caching system ensures that modules whose inputs did not change across variations are not re-executed.
ParameterSpec¶
Modules declare dynamic parameters by overriding getParameterSpec():
from analyzer.core.param_specs import ParameterSpec
def getParameterSpec(self, metadata):
return {
"jec_systematic": ParameterSpec(
default_value="central",
possible_values={"central", "JES_up", "JES_down"},
tags={"shape_variation"},
)
}
The key fields of ParameterSpec:
Field |
Description |
|---|---|
|
The value used when no variation is requested. |
|
The set of all allowed values for this parameter. |
|
A set of tags classifying this parameter. Common tags: |
|
A dictionary mapping driver parameter names to mapping functions. See “Driven Parameters” below. |
The tags field is how the RunBuilder knows which parameters are weight systematics vs shape systematics.
Run Builders¶
A RunBuilder determines which parameter combinations to actually execute.
It receives the complete ParameterSpec from all modules in the pipeline and returns a list of (name, parameter_dict) tuples.
The default_run_builder in your configuration selects the strategy:
analyzer:
default_run_builder:
strategy_name: CompleteSysts
Available strategies:
- NoSystematics
Always returns just
[("central", {})]. Only the default parameter values are used.- CompleteSysts
Runs central + all weight variations + all shape variations. Each variation is run independently (one parameter changed at a time from central).
- WeightsOnly
Runs central + weight variations only. Shape systematics are skipped.
- SignalOnlySysts
Full systematics for datasets where
"signal"appears in the dataset name oris_signalis set in metadata. Central-only for everything else.- LimitSysts
Like
CompleteSystsbut filtered: only variations whose names match a given pattern are included.default_run_builder: strategy_name: LimitSysts systs: "JES*"
- LimitSystsBackground
Like
LimitSystsbut signal datasets always get central-only.- UnscaledOnly
Returns
[("UNSCALED", {})]. Used to produce unweighted histograms.
You can also combine multiple builders using the + operator in Python, though this is not directly exposed in YAML.
Driven Parameters¶
Sometimes one systematic is correlated with another. For example, certain b-tagging systematics only apply when a specific JES variation is active.
This is handled through the driven_by field of ParameterSpec:
def getParameterSpec(self, metadata):
return {
"btag_sf_systematic": ParameterSpec(
default_value="central",
possible_values={"central", "jes_up", "jes_down"},
tags={"shape_variation"},
driven_by={
"jec_systematic": lambda jec_val: {
"JES_up": "jes_up",
"JES_down": "jes_down",
}.get(jec_val),
},
)
}
When the jec_systematic parameter is set to JES_up, the btag_sf_systematic is automatically set to jes_up.
Driven parameter values are excluded from the independent variation list, so they are not varied on their own.
Weight vs Shape Systematics¶
The distinction between weight and shape systematics is important:
Weight systematics modify only the event weight. Examples: pileup scale factors, b-tagging weights, L1 prefiring corrections. These are cheap to compute because they only require re-weighting, not re-processing.
Shape systematics modify actual physics objects. Examples: JEC/JER variations, MET corrections. These are more expensive because any downstream computation depending on the modified objects must be re-run.
The framework handles both types uniformly through the dynamic parameter system, but the RunBuilder uses the tags to decide which to include.
A module that produces a weight variation should tag its parameter with weight_variation, while one that modifies object quantities should use shape_variation.