Repository navigation
Conversation
corrections.JECs now builds the jet factories of every Run 3 year from the CMS analysis-corrections JSONs (jec_clib), pinned to the latest dated JME folders: 2022/2022EE Summer22(EE)_22Sep2023_V4 with JER JRV2, 2023/2023BPix Summer23(BPix)Prompt23_V4 with JER RunCv1234/RunD_JRV3 (run-dependent data residuals), 2024/2025 unchanged. The compiled text-file JECs are read for Run 2 only. Checked on 2022 and 2023 MC and data: correctionlib reproduces the text-file JECs of the same version to a few 1e-6, and the update to V4 leaves the AK8 jets unchanged; AK4 jets move only at 4.25 < |eta| < 4.5 in 2022 (below 0.2%) and at raw pT 15-30 GeV, 1.3 < |eta| < 2.5 in 2023 data (about -1%).
Since the correctionlib JECs of every Run 3 year (#363 for 2024/2025, #366 for 2022/2023), jec_compiled.pkl.gz, jec_compiled_upto2023BPix.pkl.gz and their builder build_jec.py are no longer read: moved to corrections/archive/ with a README on their contents and the skims that used them. The corrections README describes the correctionlib JECs; comments point to the new path. Run 2 keeps jec_compiled_run2.pkl.gz and build_jec_run2.py.
The data MET went through coffea's CorrectedMETFactory, which in coffea <= 0.7.26 (we pin 0.7.21) adds the change of the jet pT relative to the raw pT with the wrong sign: applied on top of the Type-1 PuppiMET, it undid the Type-1 correction (data MET close to RawPuppiMET), while MC kept NanoAOD PuppiMET. NanoAOD PuppiMET itself carries the Type-1 correction of the JECs of its production, not the ones the skimmer re-applies to the jets. For the correctionlib (Run 3) years the MET is now the Type-1 PUPPI MET recomputed from RawPuppiMET with the re-applied AK4 PUPPI JECs, as CMSSW does for PUPPI (Jet and CorrT1METJet, muon-subtracted corrected pT above 15 GeV, EM fraction below 0.9, unsmeared jets), for data and MC alike. MET_pt and the new MET_phi hold it; PuppiMET_pt/phi and RawPuppiMET_pt/phi are saved as well. Other years keep the NanoAOD MET, also for data. ttSkimmer gets the same MET. With the JECs of the production it reproduces NanoAOD PuppiMET (CMSSW) to 0.3 GeV RMS (2022 and 2024 ttbar), and its output is identical to the Type-1 MET of coffea's CorrectedMETFactory (scikit-hep/coffea#1537), as used in DAZSLE/hbb-run3#74.
zichunhao
added a commit
that referenced
this pull request
Oct 25, 2026
Since the correctionlib JECs of every Run 3 year (#363 for 2024/2025, #366 for 2022/2023), jec_compiled.pkl.gz, jec_compiled_upto2023BPix.pkl.gz and their builder build_jec.py are no longer read: moved to corrections/archive/ with a README on their contents and the skims that used them. The corrections README describes the correctionlib JECs; comments point to the new path. Run 2 keeps jec_compiled_run2.pkl.gz and build_jec_run2.py.
In MC the skims now also save MET_pt/MET_phi for JES_up/down, JER_up/down and UES_up/down, and the JES/JER-shifted BDT scores use the shifted MET instead of the nominal. The variations are those of the unsmeared Type-1 MET in CMSJMECalculators (Type1METVariationsCalculator, isT1SmearedMET false), the same as the MET_T1 variations of nanoAOD-tools' jetmetUncertainties, for the jets of the Type-1 sum at their corrected pT (muon-subtracted part corrected, muon added back): JES up/down puts each of them at that pT x (1 +- the total JES uncertainty there); JER up and down are both the Type-1 MET with the Jets smeared by their nominal smearing factors (the CorrT1METJets unsmeared, as coffea's Type-1 MET does without their factors); UES up/down adds/subtracts the unclustered-energy shift of NanoAOD PuppiMET. coffea's Type-1 CorrectedMETFactory instead scales the jets by the JER-varied over the nominal smeared pT, which blows up for jets that the nominal smearing pushes to ~0 GeV.
zichunhao
force-pushed
the
jec-correctionlib-2022-2023
branch
from
October 25, 2026 08:05
79d5cda to
99c2b5e
Compare
… jet mass
The skims had no JES/JER-shifted columns for the two AK4 jets away from the
bb jets and none for the VBF jet mass, so in every JES/JER variation the BDT
inputs H1AK4JetAway1mass and H2AK4JetAway2mass stayed nominal and the VBF
dijet mass used the nominal jet masses. The MC signal-region skims now save
the shifted pT and mass of the AK4-away jets
(AK4JetAway{Pt,Mass}_{JES,JER}_{up,down}) and the shifted VBF jet mass
(VBFJetMass_*), from the AK4 PUPPI JERC of these jets, and the skimmer's
shifted BDT scores use them. In a 2024 TTto4Q chunk nothing else changes;
the JES-up shift of bdt_score_vbf widens from 4.7e-3 to 5.5e-3 RMS.
…e MET in the BDT inputs The JES/JER-shifted BDT inputs moved only the bb jets and the VBF jet pT; the AK4-away jets, the VBF jet mass and the MET stayed nominal. jec_vars now has VBFJetMass, AK4JetAwayPt, AK4JetAwayMass and MET_pt, the v15 BDT config reads the MET through key_map, and their shifted columns are loaded with the systematics where the skims have them (load_samples optional_columns). For skims made before they were saved, fill_ak4_jec_shifts derives the shifted VBF jet mass from the shifted VBF pT (the jet factory scales pT and mass by the same factor) and keeps the AK4-away jets and the MET nominal. On the current 2024 VBF HH skim only VBFjjMass of the shifted inputs changes (0.15% RMS, in the 57% of events with two VBF jets); the nominal inputs do not.
Collaborator
Author
|
Superseded by #367: the same changes on top of the current main, regrouped into one commit per topic. |
cmantill
pushed a commit
that referenced
this pull request
Oct 27, 2026
…-1 PUPPI MET with the re-applied JECs (#367) * Skimmer: 2022-2023 JECs and JER from the official correctionlib files corrections.JECs now builds the jet factories of every Run 3 year from the CMS analysis-corrections JSONs (jec_clib), pinned to the latest dated JME folders: 2022/2022EE Summer22(EE)_22Sep2023_V4 with JER JRV2, 2023/2023BPix Summer23(BPix)Prompt23_V4 with JER RunCv1234/RunD_JRV3 (run-dependent data residuals), 2024/2025 unchanged. The compiled text-file JECs are read for Run 2 only. Checked on 2022 and 2023 MC and data: correctionlib reproduces the text-file JECs of the same version to a few 1e-6, and the update to V4 leaves the AK8 jets unchanged; AK4 jets move only at 4.25 < |eta| < 4.5 in 2022 (below 0.2%) and at raw pT 15-30 GeV, 1.3 < |eta| < 2.5 in 2023 data (about -1%). * Archive the Run 3 text-file JECs Since the correctionlib JECs of every Run 3 year (#363 for 2024/2025, #366 for 2022/2023), jec_compiled.pkl.gz, jec_compiled_upto2023BPix.pkl.gz and their builder build_jec.py are no longer read: moved to corrections/archive/ with a README on their contents and the skims that used them. The corrections README describes the correctionlib JECs; comments point to the new path. Run 2 keeps jec_compiled_run2.pkl.gz and build_jec_run2.py. * JES/JER of the AK4 jets away from the bb jets and of the VBF jet mass The skims had no JES/JER-shifted columns for the two AK4 jets away from the bb jets and none for the VBF jet mass, so in every JES/JER variation the BDT inputs H1AK4JetAway1mass and H2AK4JetAway2mass stayed nominal and the VBF dijet mass used the nominal jet masses. The MC signal-region skims now save the shifted pT and mass of the AK4-away jets (AK4JetAway{Pt,Mass}_{JES,JER}_{up,down}) and the shifted VBF jet mass (VBFJetMass_*), from the AK4 PUPPI JERC of these jets, and the skimmer's shifted BDT scores use them. In a 2024 TTto4Q chunk the JES-up shift of bdt_score_vbf widens from 4.7e-3 to 5.5e-3 RMS. The loop over the shifted AK4 jet pT is now skipped when get_jec_jets applied no JECs (it returns None, e.g. in a chunk without AK4 jets, and the loop failed with a TypeError), as the other shifted jet variables already were. In postprocessing, jec_vars has VBFJetMass, AK4JetAwayPt and AK4JetAwayMass, and their shifted columns are loaded with the systematics where the skims have them (load_samples optional_columns). For skims made before they were saved, fill_ak4_jec_shifts derives the shifted VBF jet mass from the shifted VBF pT (the jet factory scales pT and mass by the same factor) and keeps the AK4-away jets nominal; the load_run3_samples unit test that checks the requested columns stubs it, since its fake frames have no jet columns. On the current 2024 VBF HH skim only VBFjjMass of the shifted inputs changes (0.15% RMS, in the 57% of events with two VBF jets); the nominal inputs do not. * Type-1 PUPPI MET recomputed with the re-applied JECs The data MET went through coffea's CorrectedMETFactory, which in coffea <= 0.7.26 (we pin 0.7.21) adds the change of the jet pT relative to the raw pT with the wrong sign: applied on top of the Type-1 PuppiMET, it undid the Type-1 correction (data MET close to RawPuppiMET), while MC kept NanoAOD PuppiMET. NanoAOD PuppiMET itself carries the Type-1 correction of the JECs of its production, not the ones the skimmer re-applies to the jets. For the correctionlib (Run 3) years the MET is now the Type-1 PUPPI MET recomputed from RawPuppiMET with the re-applied AK4 PUPPI JECs, as CMSSW does for PUPPI (Jet and CorrT1METJet, muon-subtracted corrected pT above 15 GeV, EM fraction below 0.9, unsmeared jets), for data and MC alike. MET_pt and the new MET_phi hold it; PuppiMET_pt/phi and RawPuppiMET_pt/phi are saved as well. Other years keep the NanoAOD MET, also for data. ttSkimmer gets the same MET. The skimmer's BDT scores and the v15 BDT config of postprocessing take this MET_pt as their MET input; the config reads it through key_map, so that a shifted MET column can replace it. With the JECs of the production it reproduces NanoAOD PuppiMET (CMSSW) to 0.3 GeV RMS (2022 and 2024 ttbar), and its output is identical to the Type-1 MET of coffea's CorrectedMETFactory (scikit-hep/coffea#1537), as used in DAZSLE/hbb-run3#74. * JES, JER and unclustered-energy variations of the Type-1 MET In MC the skims now also save MET_pt/MET_phi for JES_up/down, JER_up/down and UES_up/down, and the JES/JER-shifted BDT scores use the shifted MET instead of the nominal: in the skimmer, and in postprocessing, where jec_vars has MET_pt, so that the key_map of the BDT config reads the shifted MET. Postprocessing reads the shifted MET where the skims have it and keeps the nominal MET for older skims (fill_ak4_jec_shifts). The variations are those of the unsmeared Type-1 MET in CMSJMECalculators (Type1METVariationsCalculator, isT1SmearedMET false), the same as the MET_T1 variations of nanoAOD-tools' jetmetUncertainties, for the jets of the Type-1 sum at their corrected pT (muon-subtracted part corrected, muon added back): JES up/down puts each of them at that pT x (1 +- the total JES uncertainty there); JER up and down are both the Type-1 MET with the Jets smeared by their nominal smearing factors (the CorrT1METJets unsmeared, as coffea's Type-1 MET does without their factors); UES up/down adds/subtracts the unclustered-energy shift of NanoAOD PuppiMET. coffea's Type-1 CorrectedMETFactory instead scales the jets by the JER-varied over the nominal smeared pT, which blows up for jets that the nominal smearing pushes to ~0 GeV. * Archive README: the 2022-2023 JECs are from #367 It linked the closed #366, which #367 supersedes. * Corrections: one cat_corrections table for every Run 3 year cat_jerc (the JEC and JER of 2022-2025) and cat_corrections (the 2024-2025 JERC, jet veto maps and pileup weights) become one cat_corrections with every Run 3 year and the same keys. The 2022-2023 jet veto maps and pileup weights come from its pinned CAT folders instead of the frozen jsonpog-integration area; the files are identical. The pileup weights of every year go through get_pileup_weights. 2018 and 2022-2023 keep evaluating them at nPU, so nothing changes: one-chunk skims of 2022 and 2024 TTto4Q, 2023 Run C v4 and 2025C JetMET are identical to the previous commit. * JERC inputs: phi clipped to the correctionlib binning NanoAOD stores phi with 12 mantissa bits, so jets within about 2.4e-4 of pi have |phi| = 3.1416016, outside the phi binning of the 2023BPix-2025 L2Relative (edges +-3.1416, value 1 outside): they got no L2Relative, their pT 7-28% too low (one low-pT forward jet 48%), about 0.01% of the jets. The correctionlib inputs of the jet factories and of the Type-1 MET clip JetPhi to +-3.1415, as get_jetveto_event does for the veto maps; the MET keeps the unclipped jet direction. In the 2024 ggHH and 2024C data files of the ntuple comparison only these jets change, and they then agree with approach 1.
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.
Summary
corrections.JECsbuilds the AK4 and AK8 jet factories of every Run 3 year (2022-2025) from the official JME correctionlib files on CVMFS (/cvmfs/cms-griddata.cern.ch/cat/metadata/JME/, dated folders pinned incat_jerc), with the coffea 0.7 adapters ofprocessors/jec_clib.pythat 2024 and 2025 already use. No text files for Run 3: the compiled text-file JECs are read for Run 2 only.Summer22(EE)_22Sep2023_V2, JERJRV1Summer22(EE)_22Sep2023_V4, JERJRV2Summer23(BPix)Prompt23_V1, JERJRV1Summer23(BPix)Prompt23_V4, JERRunCv1234_JRV3/RunD_JRV3Summer24Prompt24_V5, JERJRV2(correctionlib)Summer24Prompt25_V3, JERJRV2(correctionlib)jec_clibpasses the run number per jet instead of picking a per-era stack by dataset name.Relation to DAZSLE/hbb-run3#74
Same approach as DAZSLE/hbb-run3#74: the official JSON files with the same versions, and the compound
L1L2L3Rescorrection fed into coffea'sCorrectedJetsFactory. There the stack is coffea'sCorrectionLibJECStack(newer coffea); our coffea 0.7 has no such class, sojec_clib.pyprovides the equivalent adapters. The data corrections take the run number as an input, whichjec_clibpasses per jet; the MC stack keeps the total JES uncertainty and the JER scale-factor variations.Effect on 2022 and 2023
Jets of the first 20,000 events of a 2022 HH4b MC file, a 2022C JetHT, a 2023 HH4b (κλ = 5) MC and a 2023Cv1 JetMET0 file, corrected with the old code and the new one, with the call of
bbbbSkimmer:2023_runCv4only ifRun2023Cv4is in the dataset name, whichJetMET_Run2023C-22Sep2023_v4-v1never matches, so all Run C v4 files (56% of the 2023 pre-BPix JetMET files) got the Run C v1-3 residuals. The V4 data correction is 4.5% (raw pT 50 GeV) to 5.8% (600 GeV) higher for central AK4 jets at run 368000 (v4) than at run 367300 (v1-3); in the skims the AK8 pT is 0.956 and the AK4 pT 0.963 of the NanoAOD values (2023BPix: 1.0001). The GloParT-v3 masses come from the NanoAOD raw mass and are unaffected. With the run passed per jet this is fixed.Type-1 PUPPI MET with the re-applied JECs
CorrectedMETFactory, which in coffea <= 0.7.26 (we pin 0.7.21) adds the change of the jet pT relative to the raw pT with the wrong sign. Applied on top of the Type-1 PuppiMET, it undid the Type-1 correction (data MET close to RawPuppiMET), while MC kept NanoAOD PuppiMET. NanoAOD PuppiMET itself carries the Type-1 correction of the production JECs, not of the JECs the skimmer re-applies. In the 2024C sidebands the Type-1 data MET changes the data above BDT score 0.5 by −3.9% (data-driven QCD BDT) and −2.7% (MC QCD BDT).jec_clib.type1_puppi_met,corrections.JECs.type1_puppi_met): for the correctionlib years, i.e. all of Run 3 with this PR, the MET is recomputed from RawPuppiMET with the re-applied AK4 PUPPI JECs, as CMSSW'sPFJetMETcorrInputProducerdoes for PUPPI: every Jet and CorrT1METJet with muon-subtracted corrected pT > 15 GeV and EM fraction < 0.9 shifts it by −(f_L1L2L3Res − f_L1) × the muon-subtracted raw pT, unsmeared, for data and MC alike.MET_ptand the newMET_phihold it;PuppiMET_pt/phiandRawPuppiMET_pt/phiare saved as well. ttSkimmer gets the same MET.MET_pt/MET_phiforJES_up/down,JER_up/downandUES_up/down, and the JES/JER-shifted BDT scores use the shifted MET. They are the variations of the unsmeared Type-1 MET in CMSJMECalculators (gitlab.cern.ch/cms-analysis/general/CMSJMECalculators,Type1METVariationsCalculatorwithisT1SmearedMETfalse), the same as theMET_T1variations of nanoAOD-tools'jetmetUncertainties, for the jets of the Type-1 sum at their corrected pT (muon-subtracted part corrected, muon added back): JES up/down puts each jet (Jet and CorrT1METJet) at that pT × (1 ± the total JES uncertainty there); JER up and down are both the Type-1 MET with the Jets smeared by their nominal smearing factors (the CorrT1METJets unsmeared, as coffea's Type-1 MET does without their factors); UES up/down adds/subtracts NanoAOD PuppiMET's unclustered shift. coffea's Type-1CorrectedMETFactoryscales the jets by the JER-varied over the nominal smeared pT instead, which blows up for jets that the nominal smearing pushes to ~0 GeV (a JER_down MET shift of +724 GeV on average in 2024 ttbar). Against a per-jet loop written after CMSJMECalculators'addVariations, all variations agree to 1e-13 GeV (20,000 2022 and 2024 TTto4Q events); the mean (RMS) shifts there are JES up +0.8 GeV (1.9), JES down −0.7 GeV (1.9), JER +2.2 GeV (5.7 in 2024, 6.4 in 2022), UES ±0.2-0.3 GeV (1.3).correct_metof Framework Updates DAZSLE/hbb-run3#74 (coffea's Type-1CorrectedMETFactory, feat: implement CMS Type-1 MET correction in CorrectedMETFactory scikit-hep/coffea#1537) for the same JECs. With our JECs, recomputed − NanoAOD PuppiMET (mean / RMS): −1.6 / 6.7 GeV in 2024C data, −3.1 / 8.5 GeV in 2024 TTto4Q, −1.8 / 9.8 GeV in 2022C data, −0.05 / 1.7 GeV in 2023 TTto4Q. One-chunk skims of this branch run for 2024 TTto4Q, 2023 JetMET Run C v4 and 2022 TTto4Q.jes_uncertainties, the same JES variations, but not this JER variation.JES/JER of the other BDT inputs
Skimmer: JES/JER of the AK4 jets away from the bb jets and of the VBF jet mass): the skims had no JES/JER-shifted columns for the two AK4 jets away from the bb jets and none for the VBF jet mass, so in every JES/JER variation the BDT inputsH1AK4JetAway1massandH2AK4JetAway2massstayed nominal and the VBF dijet mass used the nominal jet masses. The MC signal-region skims now saveAK4JetAway{Pt,Mass}_{JES,JER}_{up,down}andVBFJetMass_*, from the AK4 PUPPI JERC of these jets, and the skimmer's shifted BDT scores use them.Postprocessing: JES/JER of the AK4-away jets, the VBF jet mass and the MET in the BDT inputs):hh_vars.jec_varsgetsVBFJetMass,AK4JetAwayPt,AK4JetAwayMassandMET_pt, so the shifted BDT inputs (get_var_mapping) use the shifted MET of the section above as well; the v15 BDT config reads the MET throughkey_map. The shifted columns are loaded with the systematics where the skims have them (utils.load_samples(optional_columns=...)); for skims made before,postprocessing.fill_ak4_jec_shiftsderives the shifted VBF jet mass from the shifted VBF pT (the jet factory scales pT and mass by the same factor) and keeps the AK4-away jets and the MET nominal. The unit test ofload_run3_samplesthat checks the requested columns stubs this fill, since its fake frames have no jet columns.VBFjjMassof the shifted inputs changes (0.15% RMS, in the 57% of events with two VBF jets) and the nominal inputs are identical; a one-chunk 2024 TTto4Q skim of this branch writes the new columns andload_run3_samplesreads them (each shifted column differs from its nominal for every event with the jet); unit tests: 286 passed. For scale, shifting the MET with the jets changes the JES/JER-shifted ggF BDT score of the 2022-2025 BDT by about 0.001 (JES) and 0.002 (JER) per event on average (one-chunk 2022 and 2024 TTto4Q skims).Archive
The Run 3 text-file JECs are no longer read, so the second commit moves
jec_compiled.pkl.gz,jec_compiled_upto2023BPix.pkl.gzand their builderbuild_jec.pytosrc/HH4b/corrections/archive/, with a README on what they contain and which skims used them (e.g.20260820_glopartv3_v15_signal).corrections/README.mdnow describes the correctionlib JECs (a version update is a new dated folder and tag incat_jerc, nothing to build), and the comments that namedbuild_jec.pypoint to the new path. Run 2 keepsjec_compiled_run2.pkl.gzandbuild_jec_run2.py;JECs(year)loads for 2022-2025 and 2018.