Add PS Uncertainties - #129
Open
aebid wants to merge 3 commits into
Open
Conversation
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
Contributor
Author
|
pipeline#15661124 started |
Contributor
Author
|
pipeline#15668268 started |
Contributor
Author
|
pipeline#15668315 started |
Contributor
Author
|
pipeline#15669362 started |
Contributor
Author
|
@kandrosov ready for review |
This was referenced Sep 2, 2026
kandrosov
requested changes
Sep 9, 2026
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; |
Contributor
There was a problem hiding this comment.
Do not silently hide problems: if ps.size !=4 or w value is not finite, throw an exception.
Contributor
Author
|
pipeline#15747645 started |
Contributor
Author
|
pipeline#15748149 started |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.