Skip to content

Run the card stages over several eras: one workflow whose branches are the cards - #32

Merged
kandrosov merged 3 commits into
cms-flaf:mainfrom
kandrosov:multi-era-c
Oct 19, 2026
Merged

kandrosov merged 3 commits into
cms-flaf:mainfrom
kandrosov:multi-era-c

Conversation

@kandrosov

@kandrosov kandrosov commented Oct 19, 2026 •

Copy link
Copy Markdown

Summary

Multi-era change set C: every StatInference task takes several eras (--era A,B,...).

CreateDatacardsTask and PreprocessShapesTask become one workflow each, with one branch per card of the datacard configuration (eras:, in its order; a group era of era_groups: is one card). Each branch reads the real eras its card needs. --era must hold every real era behind the cards; more eras are allowed and are not carded.

Outputs (Datacards/<card>, Hists_preprocessed/<card>) are unchanged. The job state and the logs no longer depend on --era, so a later run over more eras resumes the same jobs.

This follows FLAF's multi-era change set B (cms-flaf/FLAF#358): a workflow with allow_multi_era and without era branches. That shape is guarded on the FLAF side by cms-flaf/FLAF#359.

Changes

  • StatInferenceTask (allow_multi_era = True):
    • store_parts() and remote_log_dir_target() are keyed on the version and the class.
    • statinference_settings() reads the StatInference block through common(); it must agree between the eras.
    • A configuration without eras: raises.
    • get_sub_eras(card) and card_eras() refuse an --era that lacks an era behind any card, naming the cards and the missing eras.
    • merged_hist_reqs() requires MergedHists(hist_era=…).
    • check_card_eras: ResonantLimitsTask, ResonantLimitsAndHistPlotTask, PlotResonantLimitsTask and PlotPullsAndImpactsTask check at construction, so law run stops before scheduling.
  • MergedHists: a hist_era parameter, read from that era's own fs_HistTuple.
  • CreateDatacardsTask and PreprocessShapesTask:
    • The branch map is dict(enumerate(card_eras())); meta_era is gone.
    • Requirements go through FLAF's stage_workflow_requires().
    • Branch i requires branch i of the other, the same card.
    • A --branches selection reaches the inputs and the preprocessing.
    • The payloads get the card era (--eras, --era, ${ERA}); the plots get the card's first sub-era as the era.
    • plot_variable requires the var_list to agree over the eras summed in one plot.
  • ResonantLimitsTask requires the one card workflow and stages each card from its branch (era_card_outputs()); its store stays combined.
  • ResonantLimitsAndHistPlotTask requires one HistPlotTask over --era. It keeps its marker; the docstring says that a finished version is not re-checked (--remove-output 0,a,y).
  • repo-sanity-checks.yaml: FLAF's rename checker is pinned at 4d9602c (B's era-scope rules). The 12 sites it flagged here are gone.
  • test/test_card_eras.py (17 tests), the fixture's extra era, and unit-tests.yaml. test_law_chain.py changes only its helpers (root_params, card_workflows, cards_of, preprocess_of), as Test what the datacard chain reads, writes and runs per card #30 intended.
  • README and .github/copilot-instructions.md (Eras section, Tests row).

What changes for users

  • --era must name every real era behind the cards, e.g. --era Run3_2022,Run3_2022EE,Run3_2023,Run3_2023BPix for HH_bbWW's Run3_Early. With fewer, law run stops naming the missing eras:
    • the entry tasks exit with 60, at construction;
    • a card workflow started directly fails scheduling with 50 (local), or with a traceback and 60 (htcondor).
  • --meta-era is gone.
  • --branches k and --branch k select card k.
  • One datacard configuration per --version; do not reorder eras: while its jobs exist.
  • Paths that move: data/<v>/<Class>/ (job files), <fs_default>/<v>/logs/<Class>/ and ResonantLimitsAndHistPlotTask's marker lose their era directory. An old version reruns that marker task once.

Not implemented: the line naming the extra (uncarded) eras of a run (design §3.11). The docs say that extra eras are allowed and not carded.

Testing

  • Unit tests (unit-tests.yaml list): 38 passed. The environment was Python 3.13 with only pyyaml, numpy, luigi 3.8.1, law 0.1.21 and pytest, FLAF 4d9602c side by side, env -i.
    • 22 mutations of law/, each caught. Among them: no superset check, or one at construction for every task; job state or logs keyed on --era; the StatInference block or the merged-histogram store taken from the first era; the preprocess map reordered; a card reading another card's preprocessing; workflows without their inputs; the selection not handed on; the var_list compared only up to the first gap; the limits requiring or staging one card; the HistPlot over one era.
    • FLAF's checker at 4d9602c passes.
  • flaf-reviewer:
    • round 1 at 52ef366: 2 blocking issues (the superset rule skipped by ResonantLimitsAndHistPlotTask when the limits existed; a wrong claim about the checker), both fixed;
    • round 2: REVIEWER OK for StatInference e1ae483.
    • 982426f…9599cc8 differ from c855232…e1ae483 only in the wording of one comment (StatInferenceTask.check_card_eras).
  • flaf-tester V1, exact local A/B on identical inputs: TESTER VERDICT: PASS (V1 re-run, StatInference c855232 vs 31b4c6a; HH_bbWW f0efc2c, FLAF 4d9602c).
    • Inputs: the HH_bbWW CI Hists_merged of pipeline 16086078, all 7 eras.
    • ResonantLimitsTask, --workflow local. Baseline main --era Run3_2022; candidate over the 4 eras, and over all 7 (round 1).
    • (a) CI_card_SL.yaml: IDENTICAL. Datacards txt=41, root=8 (2656 histograms, exact bin values and errors), limits npz=5 (combined 4.9375, per era 29.0 / 5.125 / 771.0 / 51.375), and identical to the CI's own pre-C outputs.
    • (b) a group card (eras: [Run3_2022, Run3_Early], Run3_Early = 4 eras, with the preprocess step): IDENTICAL. txt=25, root=9 (14870 histograms), npz=3, both binning.json byte-equal; paths Datacards/Run3_Early, Hists_preprocessed/Run3_Early.
    • The comparison script reports planted differences.
    • Negatives under HH_bbWW's law.cfg (keep_alive: True):
      • ResonantLimitsTask --era Run3_2022: RC 60 after 4 s, the message names the missing eras, no worker.
      • The same for ResonantLimitsAndHistPlotTask with the limits present: RC 60, nothing written.
      • CreateDatacardsTask local: RC 50. Htcondor: RC 60, nothing submitted.
  • flaf-tester V2, HTCondor with a WLCG fs_default (test_htcondor EOS area), group card (b), inputs staged on EOS:
    • round 1 (52ef366): one job file per class, data/<v>/<Class>/htcondor_jobs_0To2.json. Every job had --era with all 4 eras. Logs at <fs_default>/<v>/logs/<Class>/, and the outputs matched V1.
    • Rerun with a fifth era: complete, nothing submitted, job files byte-identical.
    • Driver killed after the first submission and restarted over another set of eras: the same job file was resumed, and no job was submitted twice.
    • Round-1 check 4 failed: --branches 1 preprocessed every card. Fixed.
    • round 2: TESTER VERDICT: PASS (V2 re-check, StatInference c855232). --branches 1 submitted exactly one preprocess and one datacard job, for card 1 only, and wrote nothing for the other card. The full run is identical to round 1's.
  • run_ci_test.sh does not reach StatInference, so the runs above stand in for it.
  • Integration (both backends): triggered on this PR.
    • With allow_multi_era = True here, the multi-era job passes all CI eras (law_era_value).
    • CI_card_SL.yaml cards 4 of them; the other three are plotted.

Docs and merge order

  • Docs here: README, .github/copilot-instructions.md.
  • FLAF companion: Describe the StatInference tasks over several eras; their own error for an era-numbered selection FLAF#360 (eras, troubleshooting, task reference, contributing, walkthrough, arguments; a clearer BranchSelectionError for card workflows).
  • After this merges: HH_bbWW PR advancing its StatInference gitlink, with docs/stat_inference.md (--era examples and warning).
  • Merge order: this PR, then the HH_bbWW PR, then the FLAF companion, which describes the behaviour once the analyses carry it.

@kandrosov

Copy link
Copy Markdown
Author

@cms-flaf-bot please test

@cms-flaf-bot

Copy link
Copy Markdown

pipeline#16087295 started

@kandrosov

Copy link
Copy Markdown
Author

@cms-flaf-bot please test

  • ci_backend=github

@cms-flaf-bot

Copy link
Copy Markdown

GitHub Actions integration workflow dispatched for HH_bbWW, HH_bbtautau, H_mumu

@cms-flaf-bot

Copy link
Copy Markdown

pipeline#16087295 passed

@cms-flaf-bot

Copy link
Copy Markdown

❌ GitHub Actions integration pipeline failed.

@kandrosov

Copy link
Copy Markdown
Author

@cms-flaf-bot please test

  • ci_backend=github

@cms-flaf-bot

Copy link
Copy Markdown

GitHub Actions integration workflow dispatched for HH_bbWW, HH_bbtautau, H_mumu

@cms-flaf-bot

Copy link
Copy Markdown

✅ GitHub Actions integration pipeline 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.

2 participants