Feature/zbb zmm core 400 - #1
Conversation
- Update 2024 JEC and JER tags to the latest Summer24 payload versions. - Switch 2025 JME corrections to the Summer24 campaign and matching JEC/JER tags. - Validate the full 2024 muon input with both the 2024 and 2025 era configurations.
- implement two-fatjet QCD selection with channel-owned SV matching and optional SV detail output - generalize base fatjet branch definition and filling for channel-specific output counts - add QCD runtime cards with reduced tagger lists across supported NanoAOD versions - add validated Run 2 NanoAOD v9 QCD MC and data sample cards - validate the final 2024 card with 305 processed events, 9 accepted events, and stable output values
- clarify the QCD control-region selection and its role in X->bb/cc calibration studies
- Move each completed merge into the final output directory immediately to limit temporary disk usage. - Preserve resume behavior for final outputs, completed temporary outputs, and chunked partial merges. - Remove per-group partial files after publication and consolidate duplicated group-processing logic. - Validate with the standard CMake build plus normal, variation, resume, and 201-input chunked merge tests.
Add muon variations, correctionlib V+jets weights, LHE metadata preservation, and focused validation coverage. Lower the inclusive dimuon and leading zbb fatjet thresholds to 400 GeV and document both workflows.
There was a problem hiding this comment.
🟡 Changes recommended
HeavyFlavBaseProducer::fill_fatjet_info currently skips filling when is_qualified is false, which can silently leave fatjet slot outputs at defaults for existing jets (notably affecting the new QCD two-fatjet output).
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR expands the nano.cpp heavy-flavour framework with new Run 3 control-region channels (zbb, zmm, and qcd) and adds shared infrastructure for muon corrections, NLO EW weights, and enhanced variation handling across running/Condor/merging workflows.
Changes:
- Add new producers and runtime cards for
zbb(boosted dijet) andzmm(boosted Z→μμ recoil), plus aqcddijet control region with optional SV-detail filling. - Introduce muon scale/smearing corrections + muon SF outputs, and add NLO EW weight production from correctionlib payloads.
- Extend tooling: allow muon variations in
nano_run/Condor, add selective-variation merging innano_merge, and propagate Condor sample nicknames into the runtime config.
File summaries
| File | Description |
|---|---|
| UPDATE.md | Adds a staged-change summary document (currently contains stale/inaccurate statements). |
| CMakeLists.txt | Adds ROOT::Hist, compiles new helpers/producers, and registers new tests. |
| README.md | Documents new channels, muon payloads, NLO EW, and new variation behavior. |
| docs/framework-structure.md | Adds QCD producer entry in framework overview. |
| app/nano_run.cpp | Adds qcd/zbb/zmm channels, parses new YAML config blocks, preserves LHE branch titles, and enforces variation scope rules. |
| app/nano_merge.cpp | Adds --variations filtering and publishes merged outputs incrementally. |
| app/nano_make_condor.cpp | Extends usage/validation to include muon variations only where supported. |
| templates/condor/process.sh.in | Reads job nickname and forwards it to nano_run as channels.<channel>.sample_name. |
| include/nano/producers/HeavyFlavBaseProducer.h | Adds muon/NLO EW config, multi-fatjet output support, and LHE/gen V pT helpers. |
| src/producers/HeavyFlavBaseProducer.cpp | Implements multi-fatjet branch booking/filling, LHE/gen V pT helpers, and NLO EW weight integration. |
| include/nano/producers/HeavyFlavZbbSampleProducer.h | Declares zbb producer with two-fatjet output. |
| src/producers/HeavyFlavZbbSampleProducer.cpp | Implements zbb selection and two-fatjet filling. |
| include/nano/producers/HeavyFlavZmmSampleProducer.h | Declares zmm producer with muon correction support. |
| src/producers/HeavyFlavZmmSampleProducer.cpp | Implements zmm selection, muon variations handling, and muon SF outputs. |
| include/nano/producers/HeavyFlavQCDSampleProducer.h | Declares QCD producer with two-fatjet output and optional SV filling. |
| src/producers/HeavyFlavQCDSampleProducer.cpp | Implements QCD dijet selection, SV matching, and SV-detail output blocks. |
| src/producers/HeavyFlavMuonSampleProducer.cpp | Updates fatjet filling call-site to new indexed API. |
| src/producers/HeavyFlavMinimalProducer.cpp | Updates fatjet filling call-site to new indexed API. |
| include/nano/helpers/MuonCorrection.h | Declares muon correction wrapper and SF evaluation interface. |
| src/helpers/MuonCorrection.cpp | Implements correctionlib-backed muon scale/smear application and SF aggregation. |
| include/nano/helpers/NloEWWeightProducer.h | Declares NLO EW weight producer. |
| src/helpers/NloEWWeightProducer.cpp | Implements correctionlib-backed NLO EW weights with symmetric uncertainty. |
| include/nano/helpers/JmeVariation.h | Adds muon variation enum values and is_muon_variation(). |
| src/helpers/JmeVariation.cpp | Implements names/parsing for muon variations and is_muon_variation(). |
| src/helpers/JetMETCorrector.cpp | Maps muon variations to nominal JME correction index. |
| include/nano/io/RootOutputFile.h | Adds API to set output branch titles. |
| src/io/RootOutputFile.cpp | Implements setting ROOT branch titles after booking. |
| tests/README.md | Documents new correction-equivalence tests. |
| tests/muon_validation_test.py | Extends LHE weight copy checks to also cover LHEPdfWeight and branch titles. |
| tests/muon_external_equivalence.cpp | Adds C++ equivalence test against legacy muon formulas. |
| tests/vjets_ewk_json_test.py | Validates bin-by-bin equivalence between ROOT references and correctionlib JSON payloads. |
| tests/condor_sample_name_test.py | Verifies Condor template propagates sample nickname into config and is bash-syntax valid. |
| configs/base.yaml | Adds muon correction + NLO EW config blocks and updates JEC/JER tags. |
| configs/common/read_branches_v9.yaml | Adds LHE V pT + LHEPart branches to v9 read manifest. |
| configs/common/read_branches_v12.yaml | Adds LHE V pT + LHEPart branches to v12 read manifest. |
| configs/common/read_branches_v15.yaml | Adds muon charge/IDs/layers, SV_pt, and LHE V pT + LHEPart branches to v15 read manifest. |
| configs/common/nano_branches_v9.yaml | Adds HLT_PFHT900 to v9 branch catalogue. |
| configs/common/nano_branches_v15.yaml | Adds HLT_PFHT900 to v15 branch catalogue. |
| configs/run/zbb_2024_v15.yaml | New runtime card for 2024 v15 zbb channel (HLT 380/30). |
| configs/run/zmm_2024_v15.yaml | New runtime card for 2024 v15 zmm channel, includes LHE weights. |
| configs/run/qcd_2025_v15.yaml | Adds qcd runtime card for 2025 v15. |
| configs/run/qcd_2024_v15.yaml | Adds qcd runtime card for 2024 v15. |
| configs/run/qcd_2023BPix_v12.yaml | Adds qcd runtime card for 2023BPix v12. |
| configs/run/qcd_2023_v12.yaml | Adds qcd runtime card for 2023 v12. |
| configs/run/qcd_2022EE_v12.yaml | Adds qcd runtime card for 2022EE v12. |
| configs/run/qcd_2022_v12.yaml | Adds qcd runtime card for 2022 v12. |
| configs/run/qcd_2018_v9.yaml | Adds qcd runtime card for 2018 v9. |
| configs/run/qcd_2018_v15.yaml | Adds qcd runtime card for 2018 v15. |
| configs/run/qcd_2017_v9.yaml | Adds qcd runtime card for 2017 v9. |
| configs/run/qcd_2017_v15.yaml | Adds qcd runtime card for 2017 v15. |
| configs/run/qcd_2016APV_v9.yaml | Adds qcd runtime card for 2016APV v9. |
| configs/run/qcd_2016APV_v15.yaml | Adds qcd runtime card for 2016APV v15. |
| configs/run/qcd_2016_v9.yaml | Adds qcd runtime card for 2016 v9. |
| configs/run/qcd_2016_v15.yaml | Adds qcd runtime card for 2016 v15. |
| configs/samples/zbb_2024_v15_MC.yaml | Adds 2024 v15 zbb MC sample lists. |
| configs/samples/zbb_2024_v15_DATA.yaml | Adds 2024 v15 zbb DATA sample lists. |
| configs/samples/zmm_2024_v15_MC.yaml | Adds 2024 v15 zmm MC sample lists. |
| configs/samples/zmm_2024_v15_DATA.yaml | Adds 2024 v15 zmm DATA sample lists. |
| configs/samples/xsec_2024.conf | Adds 2024 cross-section mappings for new sample sets. |
| configs/samples/qcd_2018_v9_MC.yaml | Adds/updates QCD 2018 v9 MC sample lists. |
| configs/samples/qcd_2018_v9_DATA.yaml | Adds/updates QCD 2018 v9 DATA sample lists. |
| configs/samples/qcd_2017_v9_MC.yaml | Adds/updates QCD 2017 v9 MC sample lists. |
| configs/samples/qcd_2017_v9_DATA.yaml | Adds/updates QCD 2017 v9 DATA sample lists. |
| configs/samples/qcd_2016APV_v9_MC.yaml | Adds/updates QCD 2016APV v9 MC sample lists. |
| configs/samples/qcd_2016APV_v9_DATA.yaml | Adds/updates QCD 2016APV v9 DATA sample lists. |
| configs/samples/qcd_2016_v9_MC.yaml | Adds/updates QCD 2016 v9 MC sample lists. |
| configs/samples/qcd_2016_v9_DATA.yaml | Adds/updates QCD 2016 v9 DATA sample lists. |
| data/vjets-ewk/convert_root_to_json.py | Adds conversion utility for ROOT→correctionlib JSON payloads. |
| data/vjets-ewk/2023-08-11/WJetsCorr_collection_ewk.root | Adds ROOT reference payload for W+jets EWK validation. |
| data/vjets-ewk/2023-08-11/ZJetsCorr_collection_ewk.root | Adds ROOT reference payload for Z+jets/DY EWK validation. |
Review details
Suppressed comments (3)
UPDATE.md:72
- The zbb section lists
HLT_AK8PFJet500as required and states the leading jet pT threshold is 450 GeV, but the added runtime card only requiresHLT_AK8PFJet380_SoftDropMass30and the producer selection uses 400/200 GeV. This documentation should match the actual configuration/implementation to avoid incorrect analysis instructions.
Required triggers are `HLT_AK8PFJet380_SoftDropMass30` and `HLT_AK8PFJet500`.
Event selection and processing:
- Requires two JME-corrected AK8 jets.
- The two jets must have transverse momenta above `450` and `200 GeV`, respectively.
- The two leading jets must satisfy `|DeltaPhi| > pi/2`.
UPDATE.md:117
- The zmm section states the dimuon system must have
pT > 450 GeV, but the implemented selection inHeavyFlavZmmSampleProduceruses a 400 GeV threshold. Please align the documentation with the code to avoid confusion when validating yields.
- The Muon ID is either `pt>15` with `looseId`, or `pt>30` with `highPtId != 0`.
- The two muons must have opposite charge, with leading/subleading `pT` above `60/30 GeV`.
- The dimuon system must have `pT > 450 GeV` and `70 < m < 110 GeV`.
- Selects corrected AK8 recoil jets with `DeltaR > 0.8` from both muons and keeps only the leading jet.
UPDATE.md:168
- The NLO EW section claims the up/down weights combine the three uncertainty components in quadrature and that production reads ROOT histograms, but the current implementation uses the correctionlib JSON payload and applies a symmetric
± 50%uncertainty on the nominal correction. The summary should be updated to reflect the actual algorithm and data source.
- Uses the hard-process W/Z `pT`; values below `100 GeV` retain the default weight.
- The nominal weight is `1 + kappa`; the three uncertainty histogram deviations are combined in quadrature for the up/down weights.
- ROOT histograms are cloned and detached from the source file; missing files, histograms, or uncertainty entries raise an error.
- Files reviewed: 69/74 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if (fatjet_index >= output_fatjet_count()) { | ||
| throw std::out_of_range("Fatjet output index exceeds the configured number of slots"); | ||
| } | ||
| if (fatjet_index >= fatjets.size() || !fatjets[fatjet_index].get<bool>("is_qualified")) { | ||
| return; | ||
| } |
| # Staged Changes | ||
|
|
||
| Recorded at: `2026-07-24 15:26:52 CEST` | ||
|
|
||
| This document records only the 27 files currently staged in Git. Unstaged and untracked workspace files are excluded. | ||
|
|
| - `muon`: a heavy-flavour muon control region targeting semileptonic ttbar-like phase space, enriched in boosted top/W jets. | ||
| - `minimal`: a lightweight boosted-AK8 stream that runs the shared lepton cleaning, JME, and fatjet preparation, then keeps the leading cleaned AK8 jet above the configured `channels.minimal.leading_fatjet_pt_min` threshold. | ||
| - `qcd`: a dijet control region that retains the two leading cleaned AK8 jets and requires at least one qualified fatjet satisfying the soft-drop mass selection, with secondary-vertex matching enabled by default. The region is enriched in heavy-flavor QCD jets and provides gluon-enriched proxy samples for X->bb/cc calibration studies, including sfBDT-based methods. | ||
| - `zbb`: a 2024 NanoAOD v15 boosted dijet control region requiring two corrected AK8 jets with leading/subleading pT >= 400/200 GeV and |DeltaPhi| >= pi/2. It stores both probe jets and can require at least two secondary vertices. | ||
| - `zmm`: a 2024 NanoAOD v15 boosted `Z -> mumu` recoil control region requiring exactly two isolated opposite-sign muons with pT >= 60/30 GeV, dimuon pT >= 400 GeV, and 70 <= m(mumu) <= 110 GeV. It stores the leading corrected AK8 jet separated from both muons and provides muon scale/smearing variations and efficiency scale factors. |
Add Zbb and Zmm channel
Lower the HLtrigger to 380 and 30 GeV