From 009d5e59ce8382485aa31e0597bd54020a200530 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 13:02:03 +0000 Subject: [PATCH 1/3] Add isEtSum/isHtSum flags and physical isolation/HT accessors to P2GTCandidate l1t::P2GTCandidate was missing an easy way to identify Et-sum/Ht-sum type objects, and had no physical (GeV) accessor for isolation and HT (scalarSumPT) -- only the raw hardware ints were exposed, forcing DPGAnalysis/Phase2L1TNanoAOD's NanoAOD table config to hand-multiply by a hardcoded LSB pulled from the python scales config as a workaround. Add isEtSum()/isHtSum() predicates alongside the existing isJet() etc. Add isolationPT()/scalarSumPT() physical-value accessors, filled by L1GTProducer from its live L1GTScales at construction time (the same way pt/eta/phi/z0 already are), so the LSB stays defined in exactly one place (l1tGTScales.py) instead of being duplicated as a constant in DataFormats. operator== is left untouched, still comparing only the bit-exact raw hw fields. Update the NanoAOD table config to use the new accessors instead of the HACK. Adding a persisted double is a schema change, so classes_def.xml gets a new Optional dictionary entry and a ClassVersion bump; the recorded checksum is a placeholder pending a full build. --- .../python/l1tPh2GTtables_cff.py | 7 +++--- .../L1Trigger/interface/P2GTCandidate.h | 25 +++++++++++++++++++ DataFormats/L1Trigger/src/classes_def.xml | 6 ++++- L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc | 7 ++++++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/DPGAnalysis/Phase2L1TNanoAOD/python/l1tPh2GTtables_cff.py b/DPGAnalysis/Phase2L1TNanoAOD/python/l1tPh2GTtables_cff.py index d93a5ab626eed..303fd1e33aaca 100644 --- a/DPGAnalysis/Phase2L1TNanoAOD/python/l1tPh2GTtables_cff.py +++ b/DPGAnalysis/Phase2L1TNanoAOD/python/l1tPh2GTtables_cff.py @@ -72,9 +72,8 @@ hwQual = Var("hwQualityFlags_toInt()",int), hwIso = Var("hwIsolationPT_toInt()",int), ## more physical values - ## using the GT scales for HW to physicsal vonversion, see scales in https://github.com/cms-sw/cmssw/blob/master/L1Trigger/Phase2L1GT/python/l1tGTScales.py - iso = Var(f"hwIsolationPT_toInt()*{scale_parameter.isolationPT_lsb.value()}",float, doc = "absolute isolation"), - relIso = Var(f"hwIsolationPT_toInt()*{scale_parameter.isolationPT_lsb.value()} / pt",float, doc = "relative isolation") + iso = Var("isolationPT()",float, doc = "absolute isolation"), + relIso = Var("isolationPT()/pt",float, doc = "relative isolation") ) ) @@ -198,7 +197,7 @@ # l1GTObjVars, mht = Var("pt", float, doc="MHT pt"), mhtPhi = Var("phi", float, doc="MHT phi"), - ht = Var(f"hwScalarSumPT_toInt()*{scale_parameter.scalarSumPT_lsb.value()}", float, doc="HT"), ## HACK via hw value! + ht = Var("scalarSumPT()", float, doc="HT"), ) ) diff --git a/DataFormats/L1Trigger/interface/P2GTCandidate.h b/DataFormats/L1Trigger/interface/P2GTCandidate.h index bb5c1fdcc8514..78b557c75ca94 100644 --- a/DataFormats/L1Trigger/interface/P2GTCandidate.h +++ b/DataFormats/L1Trigger/interface/P2GTCandidate.h @@ -99,6 +99,7 @@ namespace l1t { void setHwEta(hwEta_t hwEta) { hwEta_ = hwEta.to_int(); } void setHwZ0(hwZ0_t hwZ0) { hwZ0_ = hwZ0.to_int(); } void setHwIsolationPT(hwIsolationPT_t hwIso) { hwIsolationPT_ = hwIso.to_int(); } + void setIsolationPT(double isolationPT) { isolationPT_ = isolationPT; } void setHwQualityFlags(hwQualityFlags_t hwQualityFlags) { hwQualityFlags_ = hwQualityFlags.to_int(); } void setHwQualityScore(hwQualityScore_t hwQualityScore) { hwQualityScore_ = hwQualityScore.to_int(); } void setHwCharge(hwCharge_t hwCharge) { hwCharge_ = hwCharge.to_int(); } @@ -109,6 +110,7 @@ namespace l1t { void setHwSeed_pT(hwSeed_pT_t hwSeed_pT) { hwSeed_pT_ = hwSeed_pT.to_int(); } void setHwSeed_z0(hwSeed_z0_t hwSeed_z0) { hwSeed_z0_ = hwSeed_z0.to_int(); } void setHwScalarSumPT(hwScalarSumPT_t hwScalarSumPT) { hwScalarSumPT_ = hwScalarSumPT.to_int(); } + void setScalarSumPT(double scalarSumPT) { scalarSumPT_ = scalarSumPT; } void setHwNumber_of_tracks(hwNumber_of_tracks_t hwNumber_of_tracks) { hwNumber_of_tracks_ = hwNumber_of_tracks.to_int(); } @@ -161,6 +163,13 @@ namespace l1t { return static_cast(hwIsolationPT_); } + double isolationPT() const { + if (!isolationPT_) { + throw std::invalid_argument("Object doesn't have isolationPT"); + } + return isolationPT_; + } + hwQualityFlags_t hwQualityFlags() const { if (!hwQualityFlags_) { throw std::invalid_argument("Object doesn't have qualityFlags"); @@ -231,6 +240,13 @@ namespace l1t { return static_cast(hwScalarSumPT_); } + double scalarSumPT() const { + if (!scalarSumPT_) { + throw std::invalid_argument("Object doesn't have scalarSumPT"); + } + return scalarSumPT_; + } + hwNumber_of_tracks_t hwNumber_of_tracks() const { if (!hwNumber_of_tracks_) { throw std::invalid_argument("Object doesn't have number_of_tracks"); @@ -320,12 +336,20 @@ namespace l1t { objectType_ == CL2JetsSC4 || objectType_ == CL2JetsSC8; } + bool isEtSum() const { return objectType_ == GCTEtSum || objectType_ == GTTEtSum || objectType_ == CL2EtSum; } + + bool isHtSum() const { + return objectType_ == GCTHtSum || objectType_ == GTTPromptHtSum || objectType_ == GTTDisplacedHtSum || + objectType_ == CL2HtSum; + } + private: Optional hwPT_; Optional hwPhi_; Optional hwEta_; Optional hwZ0_; Optional hwIsolationPT_; + Optional isolationPT_; Optional hwQualityFlags_; Optional hwQualityScore_; Optional hwCharge_; @@ -336,6 +360,7 @@ namespace l1t { Optional hwSeed_pT_; Optional hwSeed_z0_; Optional hwScalarSumPT_; + Optional scalarSumPT_; Optional hwNumber_of_tracks_; Optional hwNumber_of_displaced_tracks_; diff --git a/DataFormats/L1Trigger/src/classes_def.xml b/DataFormats/L1Trigger/src/classes_def.xml index b974886982dc5..ef9f8524429aa 100644 --- a/DataFormats/L1Trigger/src/classes_def.xml +++ b/DataFormats/L1Trigger/src/classes_def.xml @@ -14,7 +14,11 @@ - + + + + diff --git a/L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc b/L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc index f07b1c507197b..536b1c78fb253 100644 --- a/L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc +++ b/L1Trigger/Phase2L1GT/plugins/L1GTProducer.cc @@ -240,6 +240,7 @@ namespace l1t { gtObj.hwPT_ = htMiss.Et.V.to_int(); gtObj.hwPhi_ = obj.hwPhi(); gtObj.hwScalarSumPT_ = obj.hwPt(); + gtObj.scalarSumPT_ = scales_.to_scalarSumPT(obj.hwPt()); gtObj.objectType_ = P2GTCandidate::GTTPromptHtSum; outputCollection->push_back(gtObj); @@ -262,6 +263,7 @@ namespace l1t { gtObj.hwPT_ = htMiss.Et.V.to_int(); gtObj.hwPhi_ = obj.hwPhi(); gtObj.hwScalarSumPT_ = obj.hwPt(); + gtObj.scalarSumPT_ = scales_.to_scalarSumPT(obj.hwPt()); gtObj.objectType_ = P2GTCandidate::GTTDisplacedHtSum; outputCollection->push_back(gtObj); @@ -357,6 +359,7 @@ namespace l1t { gtObj.hwZ0_ = hwZ0; gtObj.hwQualityFlags_ = obj.apQualFlags().to_int(); gtObj.hwIsolationPT_ = obj.apIso().to_int(); + gtObj.isolationPT_ = scales_.to_isolationPT(obj.apIso().to_int()); gtObj.hwCharge_ = obj.apCharge().to_int(); gtObj.hwD0_ = obj.apD0().to_int(); gtObj.hwBeta_ = obj.apBeta().to_int(); @@ -427,6 +430,7 @@ namespace l1t { gtObj.hwPhi_ = gtPhoton.v3.phi.V.to_int(); gtObj.hwEta_ = gtPhoton.v3.eta.V.to_int(); gtObj.hwIsolationPT_ = gtPhoton.isolationPT.V.to_int(); + gtObj.isolationPT_ = scales_.to_isolationPT(gtPhoton.isolationPT.V.to_int()); gtObj.hwQualityFlags_ = gtPhoton.qualityFlags.V.to_int(); gtObj.objectType_ = P2GTCandidate::CL2Photons; @@ -452,6 +456,7 @@ namespace l1t { gtObj.hwEta_ = gtElectron.v3.eta.V.to_int(); gtObj.hwZ0_ = hwZ0; gtObj.hwIsolationPT_ = gtElectron.isolationPT.V.to_int(); + gtObj.isolationPT_ = scales_.to_isolationPT(gtElectron.isolationPT.V.to_int()); gtObj.hwQualityFlags_ = gtElectron.qualityFlags.V.to_int(); gtObj.hwQualityScore_ = gtElectron.idScore.V.to_int(); gtObj.hwCharge_ = gtElectron.charge.V.to_int(); @@ -500,6 +505,7 @@ namespace l1t { gtObj.hwPT_ = sum.vector_pt.V.to_int(); gtObj.hwPhi_ = sum.vector_phi.V.to_int(); gtObj.hwScalarSumPT_ = sum.scalar_pt.V.to_int(); + gtObj.scalarSumPT_ = scales_.to_scalarSumPT(sum.scalar_pt.V.to_int()); gtObj.objectType_ = P2GTCandidate::CL2EtSum; outputCollection->push_back(gtObj); @@ -517,6 +523,7 @@ namespace l1t { gtObj.hwPT_ = mht.hwPt(); gtObj.hwPhi_ = mht.hwPhi(); gtObj.hwScalarSumPT_ = ht.hwPt(); + gtObj.scalarSumPT_ = scales_.to_scalarSumPT(ht.hwPt()); gtObj.objectType_ = P2GTCandidate::CL2HtSum; outputCollection->push_back(gtObj); From 2d00a201a04e1b86f2cf1a00e7089d83ebf8f30e Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 17:25:02 +0000 Subject: [PATCH 2/3] Drop unused setIsolationPT/setScalarSumPT setters from P2GTCandidate Unlike the other hw fields, these had no caller: L1GTProducer builds P2GTCandidate via friend access (direct private member assignment), and the only other constructor of this class, L1GTEvaluationInterface.h (a bit-packing board-emulation path with no L1GTScales access), only ever populates the raw hw fields. Keep the class free of dead API. --- DataFormats/L1Trigger/interface/P2GTCandidate.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/DataFormats/L1Trigger/interface/P2GTCandidate.h b/DataFormats/L1Trigger/interface/P2GTCandidate.h index 78b557c75ca94..63ee6ef91a70e 100644 --- a/DataFormats/L1Trigger/interface/P2GTCandidate.h +++ b/DataFormats/L1Trigger/interface/P2GTCandidate.h @@ -99,7 +99,6 @@ namespace l1t { void setHwEta(hwEta_t hwEta) { hwEta_ = hwEta.to_int(); } void setHwZ0(hwZ0_t hwZ0) { hwZ0_ = hwZ0.to_int(); } void setHwIsolationPT(hwIsolationPT_t hwIso) { hwIsolationPT_ = hwIso.to_int(); } - void setIsolationPT(double isolationPT) { isolationPT_ = isolationPT; } void setHwQualityFlags(hwQualityFlags_t hwQualityFlags) { hwQualityFlags_ = hwQualityFlags.to_int(); } void setHwQualityScore(hwQualityScore_t hwQualityScore) { hwQualityScore_ = hwQualityScore.to_int(); } void setHwCharge(hwCharge_t hwCharge) { hwCharge_ = hwCharge.to_int(); } @@ -110,7 +109,6 @@ namespace l1t { void setHwSeed_pT(hwSeed_pT_t hwSeed_pT) { hwSeed_pT_ = hwSeed_pT.to_int(); } void setHwSeed_z0(hwSeed_z0_t hwSeed_z0) { hwSeed_z0_ = hwSeed_z0.to_int(); } void setHwScalarSumPT(hwScalarSumPT_t hwScalarSumPT) { hwScalarSumPT_ = hwScalarSumPT.to_int(); } - void setScalarSumPT(double scalarSumPT) { scalarSumPT_ = scalarSumPT; } void setHwNumber_of_tracks(hwNumber_of_tracks_t hwNumber_of_tracks) { hwNumber_of_tracks_ = hwNumber_of_tracks.to_int(); } From d6f8ea117cdbdf4994683550bc7ee94c66637fae Mon Sep 17 00:00:00 2001 From: Artur Lobanov Date: Tue, 1 Sep 2026 20:28:31 +0200 Subject: [PATCH 3/3] Record the real ClassVersion=4 checksum for l1t::io_v1::P2GTCandidate The placeholder checksum 0 was rejected by edmCheckClassVersion during the DataFormats/L1Trigger dictionary build. Built in CMSSW_20_1_0_pre1 (el9_amd64_gcc13); edmCheckClassVersion reports 3737213310 for the class as extended by this PR, and passes with that value recorded. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_012ZhBBoZkn3gtRtXmW3FYoM --- DataFormats/L1Trigger/src/classes_def.xml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/DataFormats/L1Trigger/src/classes_def.xml b/DataFormats/L1Trigger/src/classes_def.xml index ef9f8524429aa..6e59c0e15436c 100644 --- a/DataFormats/L1Trigger/src/classes_def.xml +++ b/DataFormats/L1Trigger/src/classes_def.xml @@ -16,9 +16,7 @@ - - +