Repository navigation
Correctionlib JECs for 2022-2023, JES/JER of the AK4 BDT inputs, Type-1 PUPPI MET with the re-applied JECs - #367
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 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.
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.
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.
|
LGTM, before merging could you post a comparison of the ntuple w Aashwin and Thierry to make sure that the JECs make the jet pt etc agree? |
|
So far we have one ntuple comparison, with Aashwin's (approach 1): AK8 jets of a 2024 SM ggHH NanoAOD file (10,030 events), Summer24Prompt24_V5 JECs on both sides, no JER, pT > 180 GeV.
This validates the 2024 AK8 JECs, which this PR does not change. For 2022-2023, the JECs of this PR are compared with our results before it in the table of the description: the same versions through correctionlib agree with the text-file JECs to a few 1e-6, and the update to V4 leaves the AK8 jets unchanged. |
|
Thanks, Thierry's file can be found in this link Can you produce plots like this (i.e. comparing Pocket Coffea PC, Approach One from Ashwin, and Approach Two yours?) Additionally the directory from Aashwin now should contain MET and AK4 jet information as well: https://cernbox.cern.ch/s/ryJNVocadBXpsxm |
| same MC truth and JES uncertainty as 2024, residuals and JER scale factors derived on 2025 data. | ||
| """ | ||
| cat_correction_path = "/cvmfs/cms-griddata.cern.ch/cat/metadata" | ||
| cat_corrections = { |
There was a problem hiding this comment.
Why are the 2022 and 2023 corrections not defined directly in these cat_corrections dictionary? What are the choices for jetveto, pileup_json or pileup for those years?
There was a problem hiding this comment.
I had left the old logic for 2022-2023 intact (jet veto maps and pileup weights from jsonpog-integration), but for readability they are now in cat_corrections too, with the same keys as the other years (jme, jec, jer, jetveto, pileup_json, pileup). For 2022-2023:
- jetveto:
Summer22_23Sep2023_RunCD_V1,Summer22EE_23Sep2023_RunEFG_V1,Summer23Prompt23_RunC_V1,Summer23BPixPrompt23_RunD_V1 - pileup_json:
puWeights.json.gzof the LUM foldersRun3-22CDSep23-Summer22-NanoAODv12/2024-01-31(and the 22EFG, 23C, 23D ones) - pileup:
Collisions2022_355100_357900_eraBCD_GoldenJson,Collisions2022_359022_362760_eraEFG_GoldenJson,Collisions2023_366403_369802_eraBC_GoldenJson,Collisions2023_369803_370790_eraD_GoldenJson
The files are the same as before, so the skims do not change.
Note: The 2022-2023 weights are still evaluated at Pileup_nPU; Pileup_nTrueInt comes in the next PR.
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.
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.
Here is the comparison of the three ntuples on the same events. Names in the plots and below:
Plots: https://cernbox.cern.ch/s/zipzR0stIAkZccK (
Our AK8 jets are identical to PC's: every quantity agrees to float precision, except the softdrop mass, where our skim keeps NanoAOD's Numbers, including AK4 jets and data: ratios of matched jets, median (68% half-width), for jets with
The spreads are NanoAOD's storage precision. What the comparison found:
|
|
Lgtm, we could understand better the differences in MET and softdrop. To follow up with Ashwin, but merging this now |
NanoAOD msoftdrop sums the subjets with the JEC of the MiniAOD production, while the jets carry the re-applied JECs. In 2024 that subjet JEC (Winter24 in MC, a pre-Summer24 payload in the 2024C data) puts msoftdrop +0.6% (MC) and -1.6% (data) away from Summer24Prompt24_V5, and in the 2023 PFNano data msoftdrop is 7% below the mass of its own subjets. As in PocketCoffea's msoftdrop_correction, each raw subjet is now corrected with the AK4 PUPPI JEC of the AK4 jets (L1L2L3 in MC, with the residuals in data), without JER, and the softdrop mass is the mass of their sum; jets without subjets or with msoftdrop <= 0, and NaN masses, keep NanoAOD's value, which is saved as MsdNano. The cuts and the JMS/JMR variations use the new mass. On the 2024 ggHH file of the #367 ntuple comparison it equals the V5 softdrop mass of that comparison to 6e-8, which approach 1 and PocketCoffea reproduce. In one-chunk skims only the softdrop columns change: by 0.992 in 2024 MC, 1.000 in 2022 MC, 1.04 in 2025C data and 1.11 in 2023C data (median ratio to NanoAOD), with 1 and 12 more data events passing the msd cuts.

Supersedes #366: the same changes on top of the current
main, regrouped into one commit per topic: correctionlib JECs, archive, JES/JER of the AK4-jet inputs (skimmer and postprocessing, with the fix of the shifted AK4 jet pT loop for chunks without JECs), Type-1 PUPPI MET recomputed (with the BDT reading it), its JES/JER/UES variations (with their use in the shifted BDT inputs of postprocessing).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. The skimmer's BDT scores and the v15 BDT config take thisMET_ptas their MET input (the config throughkey_map).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
H1AK4JetAway1massandH2AK4JetAway2massstayed 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.hh_vars.jec_varsgetsVBFJetMass,AK4JetAwayPtandAK4JetAwayMass, and their 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 nominal. The unit test ofload_run3_samplesthat checks the requested columns stubs this fill, since its fake frames have no jet columns. The MET-recompute commit makes the v15 BDT config read the MET throughkey_map, and the MET-variations commit addsMET_ptto the same list (so the shifted BDT inputs use the shifted MET) and keeps the MET nominal for older skims.get_jec_jetsapplied 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.VBFjjMassof the shifted inputs changes (0.15% RMS, in the 57% of events with two VBF jets) and the nominal inputs are identical; one-chunk 2024 TTto4Q skims of the branch (at this commit and at the tip) write the new columns, andload_run3_samplesreads them (each shifted column differs from its nominal for every event with the jet); unit tests: 286 passed at every commit from this one on. 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.