Skip to content

Feat: embedding ff measurements - #1

Merged
SimonSPD merged 35 commits into
mainfrom
feat/embedding-ff-measurements
Sep 30, 2026
Merged

SimonSPD merged 35 commits into
mainfrom
feat/embedding-ff-measurements

Conversation

@SimonSPD

Copy link
Copy Markdown
Contributor

It adds embedding and fake-factor shape systematics as well as the fake-factor and tau-ID/ES measurements.

… (G2)

Histograms of hist, estimate (fake factors and an ABCD variant), the datacard
text and shapes, and the ML-export frames, stored as exact floats. The rebuilt
core must reproduce them bitwise.
…ion by nick

read_sample_list reads one nick per line and rejects anything else (the former
DBS column included) and duplicates. normalisation(database, nicks) looks up by
nick only and reports every missing nick at once. Removed: InventoryEntry,
read_inventory, write_inventory, the DBS fallback, database_nick and the
inventory command.
Everything that differs by channel lives in Channel (samples, cuts, processes,
regions, categories, variables, variations, estimators). A process has a role
(data, signal, background, auxiliary) and owns its whole weight set; the core
weight and cut rule has no branches on sample kind and lives in one place,
events.select. Regions replace cuts, replace weights where a process carries
them and add weights.

Column variations (SW core):
- ColumnVariation(name, suffix | derived, applies_to, regions): a CROWN shift
  read from `c + suffix`, or a shift computed from nominal columns (derived).
  A name ending in Up/Down needs its partner; other names are templates that
  datacards never turn into shape lines.
- skim: shifted branches are read, an event is kept if the skim cuts pass
  nominally or under any variation of its kind, and per file every declared
  shift must have a branch and every shifted branch of a needed column must be
  declared (checked for kinds that declare shifts).
- skim reuse: rows and columns must be a superset of the needed ones (skim
  cuts, normalisation, sample cut equal; recorded column variations and friends
  contain the current ones; the Parquet schema holds the needed columns). The
  v4 manifests stay reusable. Incompatible skims are listed together.
- fill: a variation is filled where it applies; a column variation only where
  it changes an expression of the histogram. Hist re-applies the (varied) skim
  cuts and always refills the requested scopes (no --force).
- estimates: DataMinus propagates every column variation of its inputs with a
  nominal fallback; ABCD stays nominal; TemplateShift replaces the hard-coded
  embedding ttbar contamination and reads an auxiliary process.

Module layout: validate, events, fill, estimates, shapes (sync), store,
ntuples, provenance (versions/<analysis>.json), cmssw + limits (was fit).
Deleted: io/, estimators/, histograms.py, sync.py, the kind taxonomy,
Process.key, Sample.channels, the Selection-or-map, Channel.baseline/skim
weights, example-config.

The mini-dataset outputs stay bitwise identical to aa5daa5 (G2).
A measurement is an object with a name and run(context); the stage calls it
with a MeasureContext (config, analysis, channels, output directory
<output_dir>/<name>/<era>/, events() on the one event rule, payload
provenance) and records versions there. --suggest-binning is passed through
and writes nothing.
shapesmith.payloads builds schema-v2 nodes (binning, category, correction,
correction set), stores the provenance as JSON in CorrectionSet.description,
checks every payload (schema, evaluator, no $schema key so that correctionlib
2.6 reads it) and writes it gzip compressed. correctionlib>=2.6 and
numpy>=2.0 become core dependencies.
smooth_kern transcribes ROOT's TGraphSmooth::SmoothKern (normal kernel,
BDRksmooth) including its running window start, which still sums the last
point left of the window. smooth ports FF_Updated _smooth_function: 100
Normal(y, stat_sigma * sigma) samples per bin from RandomState(19), the
100 n-point grid without its last point, mean and standard deviation over the
samples, binwise and hybrid options (_get_index_and_slices), clipping at zero
and padding to the outer bin edges.

tests/reference/make_smoothing_reference.py (run once with pyROOT from
LCG_108) calls ROOT and FF_Updated itself; the port matches its output to
5e-16 (kernel) and exactly (sampled curves).
…us can clip negative bins

A TemplateShift now also varies each template variation of its process (a
variation without a direction, e.g. an energy-scale grid point). The result
is named <variation>@<template>, which datacards never read as a shape. The
tau-ID/ES measurement needs this for the embedding ttbar contamination of
every grid point. DataMinus gains clip_negative for the same-sign QCD of the
measurement, as in the predecessor's estimate.
MeasureContext.merge asks a measurement to combine the results of its earlier
runs (the tau-ID/ES measurement runs once per working-point combination) into
one payload. payloads.transform builds the formula transform the tau energy
scale payload uses for |eta|.
From an LCG view (the ShapeSmith environment) the subshell inherited
PYTHONPATH and LD_LIBRARY_PATH, and combineTool.py failed to import ROOT
(GLIBCXX mismatch between LCG_108 and el9_amd64_gcc12). The subshell now keeps
only PATH=/usr/bin:/bin, HOME, USER, LOGNAME, TMPDIR and X509_USER_PROXY.
CROWN produces some shifts only for some samples (the MET recoil shifts for
DY and W, the muon-fake tau ES for DY). ColumnVariation.groups restricts a
variation to the samples of those groups: only they read, check and fill it,
so the per-file shift check no longer fails on the other samples.
…taus

The chain of smhtt_ul tauID_SFs_dev on ShapeSmith histograms, one run per
working-point combination: histograms and estimates of the mt channel and the
mm control region, the shapes in the MorphingTauID2017 input format, and per
category in CMSSW the datacards with the r_DY_incl rate parameters, the
multiSignalModel workspace, the 2D likelihood scan and the MultiDimFit singles
fit with the predecessor's options. The singles fit starts at the scan's best
fit, inside the region the scan gives (the close-up scans are gone). Results
with an interval at the fit range or a scan region at the scan boundary are
errors. --merge writes the correctionlib payload with the node structure of
the predecessor's file plus provenance. The energy-scale grid is in integer
units of 0.1 % (grid.py), so variation names, percentages and MorphingTauID2017
mass strings correspond exactly.

Reference tests (skipped without /work/jvoss): the payload built from the
predecessor's 36 singles fits equals its payload, the signal names equal those
of its shapes, and MorphingTauID2017 on its shapes writes its cards.
…ategories

A singles fit with FITTER_NEVER_GIVE_UP can iterate without end (seen in the
reproduction, T_T DM1011 with the scan-derived ranges). cmssw.run takes a
timeout and kills the whole process group when it expires. tau_id_es gives
each CMSSW step of a category an hour; a failed or expired step becomes a
problem of that category, the other categories still finish, and --merge
refuses the result.
The default colour cycle repeats after ten processes, so ZL took the colour
of the embedded signal in the postfit plots of mt.
…bin counts

The kernel sums run in ROOT's order with libm's exp, so that the port equals
TGraphSmooth::SmoothKern and FF_Updated's _smooth_function bitwise (the tests
now require equality). smooth() takes binwise_left/binwise_right instead of
TauFakeFactors' option strings; binwise() is the plain bin curve.
A measurement analysis (fake factors, tau ID) has no signal; Analysis.signal
may be None and validate() checks it only when set.
The model of the SM fake-factor measurement (FM-12): Fit, Split, Binned,
ProcessFF with its DR->SR correction and data/MC scale, Fractions, Leg and
FakeFactorMeasurement. hist.Hist is TauFakeFactors' patched TH1D without ROOT:
contents, Sumw2, the centre of mass and the MC-suppressed errors (FM-11).
fit.fit turns a ratio into the stored steps with StatShift, SystMCShift,
SystBand{High,Low,Asym}, the compatibility-with-1 reset and sparsify (FM-2,
FM-3, FM-14). Both are checked against ROOT with FF_Updated's patches
(tests/reference/make_fake_factor_reference.py).
…ning

shapesmith measure runs the QCD and ttbar fake factors, the fractions, the
orthogonal fake factors and the DR->SR correction and the non-closures in
TauFakeFactors' order. Every data-driven step subtracts its own process list
(FM-1); applied fake factors and corrections are evaluated per event with
correctionlib from the payload models of the run (FM-5). The payloads follow
the conventions of the CROWN fake-factor friend (FM-15); measurement_<ch>.json
records every ratio, fit input and result, and the plots show the fits and the
closures. --suggest-binning is adjust_binning's equipopulated binning (FM-13).
Both measurements are listed together in the README.
One run measures every channel, there is nothing to merge.
As the predecessor (emb_tau_id_sfs_ul.sh, plot_2D_scan.py): close-up 1D
scans of each POI, the other profiled, start at the lowest grid point of
the 2D scan within its 2 sigma intervals (2 dNLL = 6.18) widened by
0.2 / 2 %; the singles fit starts at the lowest points of the close-up
scans within their 2 sigma intervals widened by 0.05 / 0.5 %. The
close-up ranges come from the profiles of the 2D scan, where the
predecessor used coarse 1D scans and hand-tuned margins. This replaces
the 2D-scan box and its boundary problem; the singles interval check
stays.
A background named as the signal (the tau-ID measurement named EMB) was
accepted, and sync, datacards and plots then list it twice.
needed_columns collects the selections of every process, region and weight
variation, mostly the same expressions: the 72 tt samples of sm2018_binned_v3
took 6.9 s, now 0.3 s.
The MorphingTauID2017 input differed from the synced layout only in the name
of the embedded signal; synced_entries takes the naming function instead of a
second copy of the loop. The test analysis has no signal, as the tau-ID
analysis.
@SimonSPD
SimonSPD merged commit df21ec2 into main Sep 30, 2026
2 checks passed
@SimonSPD
SimonSPD deleted the feat/embedding-ff-measurements branch October 5, 2026 23:08
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.

1 participant