Skip to content

Add PS Uncertainties - #129

Open
aebid wants to merge 3 commits into
cms-flaf:mainfrom
aebid:Add_PS_Uncertainties
Open

Add PS Uncertainties#129
aebid wants to merge 3 commits into
cms-flaf:mainfrom
aebid:Add_PS_Uncertainties

Conversation

@aebid

@aebid aebid commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Addition of the PS ISR and FSR uncertainties. As these will need to be normalized along with PU this also reworks the Shape Weights normalization logic and denominator definition.

aebid and others added 2 commits September 1, 2026 05:27
The normalisation weight is assembled twice: as the numerator in
getNormalisationCorrections, and as the anaCache denominator in FLAF's
anaTupleProducer. Both answer the same question -- for variation (source, scale), which
weight branches multiply together -- and both answered it by assuming pileup is the only
non-central shape source.

That assumption is load-bearing in a way that is invisible today. Each producer appended
only its own branches to shape_weights_dict, so a second producer's variation key would
hold only that producer's varied branch, with the first producer's *central* branch
missing. weight_base_<var> / weight_base_Central would then retain a spurious factor of
one over the missing weight -- for pileup, a number spanning 0.034 to 3.07 on a real
file, which would swamp any percent-level variation it was multiplied into. Nothing
would fail; the shapes would just be wrong.

ShapeWeightRegistry does the cross product instead: each producer registers the sources
it owns plus a (source, scale) -> branch-name callable, and the registry returns the
varied branch from whichever producer owns the source and the central branch from every
other. One map now drives both the numerator and the denominator, so they cannot
disagree.

Registration is deliberately independent of `enabled`: a branch written at AnaTuple has
to be nameable again at AnaTupleMerge, where the producer is disabled and the branch is
read back from the tuple. That is why registerShapeWeights and defineShapeWeights are
separate.

No behaviour change. With pileup as the only registered producer the registry reproduces
the previous mapping exactly, and since the weight product is built by " * ".join, the
resulting C++ expression string is character-identical -- there is no arithmetic that
could differ. test_shape_weight_registry.py asserts that for pileup applied or not,
crossed with variations computed or not, and separately asserts the cross product a
second producer needs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VxRjUQZDMve3Zuv93btrui
Pythia8 shower weights, not LHE ones: PSWeight is produced after the matrix element,
which is why it carries no LHE prefix even though anaTupleDef lists it beside
LHEPdfWeight and LHEScaleWeight. Closes the parton-shower half of the theory shape gap.

The weights are already w_var / w_nominal, so there is no central correction to apply --
the nominal sample is the nominal shower. weight_ps_Central is the literal 1.f, which
means no GetWeight hook is needed in the analysis, and, deliberately, that adding this
producer multiplies the existing pileup denominators by an IEEE-754 exact 1.0f and so
leaves them bit-identical.

What makes the nuisance shape-only is the anaCache denominator, not anything here: the
`base` block divides each variation by its own inclusive sum of weights, so the
inclusive yield is fixed and only the acceptance difference reaches the fit. That is the
right choice given TT's rate is constrained to its MC prediction -- there is no
rateParam anywhere in the datacard configs -- so the acceptance shift is a real
uncertainty rather than an artifact to normalise away.

Index ordering is fixed by the CMSSW producer that writes the branch,
PhysicsTools/NanoAOD/plugins/GenWeightsTableProducer.cc, and quoted verbatim in
parton_shower.h. That documentation string lives in the NanoAOD branch title and is
dropped by the Define-rename in anaTupleDef, so it cannot be read back from the anaTuple
-- which is what makes the size guard load-bearing rather than cosmetic. The same
producer writes a single dummy 1.0 when a sample lacks the expected 14 or 46 underlying
weights, and the full set for Sherpa, so only a length of exactly 4 is the standard
four-variation set. Anything else yields 1, and the inclusive denominator ratio coming
out exactly 1.000000 is the diagnostic for it.

Reads PSWeight, not the renamed PS_Weight: the denominator is accumulated in
updateDenomEntry, which runs before addAllVariables defines the renamed column.

Non-finite weights are guarded; zero or negative ones are not. Those are generator
problems worth seeing downstream rather than quietly rewriting to 1.

If the input branch is absent the producer warns once and defines 1.f, so one bad sample
cannot block an era -- except where weight_ps_* columns already exist, which means a
stage that should have been disabled and where defining them again would shadow the
persisted values. That raises.

Verified through RDataFrame: the index mapping against known inputs, all three size
guards (empty, the 1-weight dummy, a Sherpa-like length), Central exactly 1.0, the
disabled and no-variations paths, the shadow tripwire firing, and the missing-input path
warning rather than raising.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VxRjUQZDMve3Zuv93btrui
@aebid

aebid commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

@cms-flaf-bot

Copy link
Copy Markdown

pipeline#15661124 started

@cms-flaf-bot

Copy link
Copy Markdown

pipeline#15661124 failed

@aebid

aebid commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

@cms-flaf-bot

Copy link
Copy Markdown

pipeline#15668268 started

@aebid

aebid commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

@cms-flaf-bot

Copy link
Copy Markdown

pipeline#15668315 started

@cms-flaf-bot

Copy link
Copy Markdown

pipeline#15668268 failed

@cms-flaf-bot

Copy link
Copy Markdown

pipeline#15668315 failed

@aebid

aebid commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

@cms-flaf-bot

Copy link
Copy Markdown

pipeline#15669362 started

@cms-flaf-bot

Copy link
Copy Markdown

pipeline#15669362 passed

@aebid aebid mentioned this pull request Sep 2, 2026
@aebid

aebid commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

@kandrosov ready for review

Comment thread parton_shower.h Outdated
Comment on lines +26 to +30
if (ps.size() != 4) return 1.f;
const float w = ps[idx];
// Guard non-finite only. A zero or negative PS weight is a generator problem worth
// seeing downstream, not something to quietly rewrite to 1.
return std::isfinite(w) ? w : 1.f;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not silently hide problems: if ps.size !=4 or w value is not finite, throw an exception.

@aebid

aebid commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

@cms-flaf-bot

Copy link
Copy Markdown

pipeline#15747645 started

@cms-flaf-bot

Copy link
Copy Markdown

pipeline#15747645 failed

@aebid

aebid commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

@cms-flaf-bot

Copy link
Copy Markdown

pipeline#15748149 started

@cms-flaf-bot

Copy link
Copy Markdown

pipeline#15748149 passed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants