-
Notifications
You must be signed in to change notification settings - Fork 4.6k
[L1T] Update L1T MET and Add JUMP algorithm (Phase 2) #48308
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
db7e90b
070951d
104769c
9a8ce18
88d6bf5
af82bf2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,123 @@ | ||||
| #ifndef L1Trigger_Phase2L1ParticleFlow_JUMP_h | ||||
| #define L1Trigger_Phase2L1ParticleFlow_JUMP_h | ||||
|
|
||||
| #include "DataFormats/L1TParticleFlow/interface/jets.h" | ||||
| #include "DataFormats/L1TParticleFlow/interface/sums.h" | ||||
| #include "DataFormats/L1TParticleFlow/interface/layer1_emulator.h" | ||||
|
|
||||
| #include "L1Trigger/Phase2L1ParticleFlow/interface/dbgPrintf.h" | ||||
| #include "L1Trigger/Phase2L1ParticleFlow/interface/jetmet/L1PFMetEmulator.h" | ||||
|
|
||||
| #include "FWCore/Utilities/interface/FileInPath.h" | ||||
| #include "FWCore/Utilities/interface/Exception.h" | ||||
| #include "nlohmann/json.hpp" | ||||
|
|
||||
| #include <vector> | ||||
| #include <numeric> | ||||
| #include <array> | ||||
| #include <fstream> | ||||
| #include <algorithm> | ||||
| #include <cmath> | ||||
| #include "ap_int.h" | ||||
| #include "ap_fixed.h" | ||||
|
|
||||
| namespace L1JUMPEmu { | ||||
| /* | ||||
| Emulator for the JUMP Algorithm | ||||
| DPS Note publicly available on CDS: CMS DP-2025/023 | ||||
| JUMP: Jet Uncertainty-aware MET Prediction | ||||
| - Approximate L1 Jet energy resolution by pT, eta value | ||||
| - Apply the estimated resolution to MET | ||||
| */ | ||||
| struct JER_param { | ||||
| std::array<ap_fixed<11, 1>, 5> par0; // eta.par0 (slope) | ||||
| std::array<ap_fixed<8, 5>, 5> par1; // eta.par1 (offset) | ||||
| std::array<L1METEmu::eta_t, 4> edges; // |eta| boundaries in HW scale | ||||
|
||||
| }; | ||||
|
|
||||
| inline const JER_param& Get_jer_param() { | ||||
| static JER_param P = []() { | ||||
| JER_param t{}; | ||||
| edm::FileInPath fip("L1Trigger/Phase2L1ParticleFlow/data/met/l1jump_jer_v1.json"); | ||||
|
||||
| std::ifstream in(fip.fullPath()); | ||||
| if (!in) | ||||
| throw cms::Exception("FileNotFound") << fip.fullPath(); | ||||
| nlohmann::json j; | ||||
| in >> j; | ||||
|
|
||||
| for (int i = 0; i < 5; ++i) { | ||||
| t.par0[i] = ap_fixed<11, 1>(j["eta"]["par0"][i].get<double>()); | ||||
| t.par1[i] = ap_fixed<8, 5>(j["eta"]["par1"][i].get<double>()); | ||||
| } | ||||
| for (int i = 0; i < 4; ++i) { | ||||
| t.edges[i] = l1ct::Scales::makeGlbEta(j["eta_edges"][i].get<double>()); | ||||
| } | ||||
| return t; | ||||
| }(); | ||||
| return P; | ||||
| } | ||||
|
|
||||
| inline void Get_dPt(const l1ct::Jet jet, L1METEmu::proj2_t& dPx_2, L1METEmu::proj2_t& dPy_2) { | ||||
| /* | ||||
| L1 Jet Energy Resolution parameterization | ||||
| - Fitted σ(pT)/pT as a function of jet pT in each η region (detector boundary at η≈1.3, 1.7, 2.5, 3.0) | ||||
| - Derived from simulated QCD multijet samples to calculate detector‐dependent resolution | ||||
| - σ(pT) ≈ eta_par0[i] * pT + eta_par1[i] | ||||
| */ | ||||
|
|
||||
| const auto& J = Get_jer_param(); | ||||
|
|
||||
| L1METEmu::eta_t abseta = abs(jet.hwEta.to_float()); | ||||
| int etabin = 0; | ||||
| for (uint i = 0; i < 4;) { | ||||
|
||||
| for (uint i = 0; i < jets.size(); i++) { |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a bug to me as you are not incrementing i.
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,149 @@ | ||||
| #ifndef L1Trigger_Phase2L1ParticleFlow_MET_h | ||||
| #define L1Trigger_Phase2L1ParticleFlow_MET_h | ||||
|
||||
|
|
||||
| #include "DataFormats/L1TParticleFlow/interface/jets.h" | ||||
| #include "DataFormats/L1TParticleFlow/interface/sums.h" | ||||
| #include "DataFormats/L1TParticleFlow/interface/layer1_emulator.h" | ||||
|
|
||||
| #include "L1Trigger/Phase2L1ParticleFlow/interface/dbgPrintf.h" | ||||
|
|
||||
| #include "FWCore/Utilities/interface/FileInPath.h" | ||||
| #include "FWCore/Utilities/interface/Exception.h" | ||||
| #include "nlohmann/json.hpp" | ||||
|
|
||||
| #ifndef CMSSW_GIT_HASH | ||||
| #include "hls_math.h" | ||||
| #endif | ||||
|
|
||||
| #include <vector> | ||||
| #include <array> | ||||
| #include <fstream> | ||||
| #include <numeric> | ||||
| #include <algorithm> | ||||
| #include "ap_int.h" | ||||
| #include "ap_fixed.h" | ||||
|
|
||||
| namespace L1METEmu { | ||||
| // Define Data types for P2 L1 MET Emulator | ||||
| typedef l1ct::pt_t pt_t; | ||||
| typedef l1ct::glbphi_t phi_t; | ||||
| typedef l1ct::glbeta_t eta_t; | ||||
| typedef l1ct::dpt_t pxy_t; | ||||
| typedef l1ct::Sum Met; | ||||
|
|
||||
| typedef ap_fixed<22, 12> proj_t; | ||||
| typedef ap_fixed<32, 22> proj2_t; | ||||
| typedef ap_fixed<32, 2> poly_t; | ||||
|
|
||||
| struct Particle_xy { | ||||
| // 44bits | ||||
| proj_t hwPx; | ||||
| proj_t hwPy; | ||||
| }; | ||||
|
|
||||
| struct Poly2_param { | ||||
| std::array<poly_t, 16> c0, c1, c2, s0, s1, s2; | ||||
| std::array<phi_t, 17> phi_edges; | ||||
| }; | ||||
|
|
||||
| inline const Poly2_param& Get_Poly2_param() { | ||||
| static Poly2_param P = [] { | ||||
| Poly2_param t{}; | ||||
| edm::FileInPath f("L1Trigger/Phase2L1ParticleFlow/data/met/l1met_ptphi2pxpy_poly2_v1.json"); | ||||
|
||||
| std::ifstream in(f.fullPath()); | ||||
| if (!in) | ||||
| throw cms::Exception("FileNotFound") << f.fullPath(); | ||||
| nlohmann::json j; | ||||
| in >> j; | ||||
|
|
||||
| for (int i = 0; i < 16; ++i) { | ||||
| t.c0[i] = poly_t(j["cos"]["par0"][i].get<double>()); | ||||
| t.c1[i] = poly_t(j["cos"]["par1"][i].get<double>()); | ||||
| t.c2[i] = poly_t(j["cos"]["par2"][i].get<double>()); | ||||
| t.s0[i] = poly_t(j["sin"]["par0"][i].get<double>()); | ||||
| t.s1[i] = poly_t(j["sin"]["par1"][i].get<double>()); | ||||
| t.s2[i] = poly_t(j["sin"]["par2"][i].get<double>()); | ||||
| } | ||||
| for (int i = 0; i < 17; ++i) { | ||||
| t.phi_edges[i] = l1ct::Scales::makeGlbPhi(j["phi_edges"][i].get<double>() * M_PI); | ||||
| } | ||||
| return t; | ||||
| }(); | ||||
| return P; | ||||
| } | ||||
|
|
||||
| inline Particle_xy Get_xy(const l1ct::pt_t hwPt, const l1ct::glbphi_t hwPhi) { | ||||
| /* | ||||
| Convert pt, phi to px, py | ||||
| - Use 2nd order Polynomial interpolation for cos, sin | ||||
| - Divide the sine and cosine value from -2 pi to 2 pi into 16 parts | ||||
| - Fitting the value with 2nd order function | ||||
| */ | ||||
|
|
||||
| const auto& P = L1METEmu::Get_Poly2_param(); | ||||
| int phibin = 0; | ||||
| for (int i = 0; i < 16; i++) { | ||||
| if (hwPhi >= P.phi_edges[i] && hwPhi < P.phi_edges[i + 1]) { | ||||
| phibin = i; | ||||
| break; | ||||
| } | ||||
| } | ||||
|
|
||||
| Particle_xy proj_xy; | ||||
|
|
||||
| poly_t cos_var = P.c0[phibin] + P.c1[phibin] * (hwPhi - P.phi_edges[phibin]) + | ||||
| P.c2[phibin] * (hwPhi - P.phi_edges[phibin]) * (hwPhi - P.phi_edges[phibin]); | ||||
| poly_t sin_var = P.s0[phibin] + P.s1[phibin] * (hwPhi - P.phi_edges[phibin]) + | ||||
| P.s2[phibin] * (hwPhi - P.phi_edges[phibin]) * (hwPhi - P.phi_edges[phibin]); | ||||
|
|
||||
| proj_xy.hwPx = hwPt * cos_var; | ||||
| proj_xy.hwPy = hwPt * sin_var; | ||||
|
|
||||
| return proj_xy; | ||||
| } | ||||
|
|
||||
| inline void Sum_Particles(const std::vector<Particle_xy> particles_xy, Particle_xy& met_xy) { | ||||
|
||||
| met_xy.hwPx = 0; | ||||
| met_xy.hwPy = 0; | ||||
|
|
||||
| for (uint i = 0; i < particles_xy.size(); ++i) { | ||||
|
||||
| for (uint i = 0; i < particles.size(); i++) { |
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,122 @@ | ||||
| #include <vector> | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure how this sounds, but wouldn’t it be better to create a header file for this, to produce and construct all the constants/headers there, rather than having everything in one place?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the suggestion. Maybe I misunderstood, but the reason I kept the declarations/definitions together inside each producer file was to keep them self-contained, since each producer can also be run standalone. In this way they don’t depend on an extra header that would not be reused elsewhere. This is also consistent with how other L1 producers are currently organized. Of course, if there is a strong preference to split them I can do that. |
||||
| #include <string> | ||||
| #include <ap_int.h> | ||||
| #include <ap_fixed.h> | ||||
| #include <TVector2.h> | ||||
| #include <iostream> | ||||
|
|
||||
| #include "FWCore/Framework/interface/global/EDProducer.h" | ||||
| #include "FWCore/Framework/interface/Event.h" | ||||
| #include "FWCore/Utilities/interface/InputTag.h" | ||||
| #include "FWCore/Framework/interface/MakerMacros.h" | ||||
| #include "FWCore/ParameterSet/interface/ParameterSet.h" | ||||
| #include "FWCore/MessageLogger/interface/MessageLogger.h" | ||||
|
|
||||
| #include "DataFormats/L1TParticleFlow/interface/PFCandidate.h" | ||||
| #include "DataFormats/L1TParticleFlow/interface/PFJet.h" | ||||
|
|
||||
| #include "DataFormats/L1TParticleFlow/interface/puppi.h" | ||||
| #include "DataFormats/L1TParticleFlow/interface/sums.h" | ||||
| #include "DataFormats/L1TParticleFlow/interface/jets.h" | ||||
| #include "DataFormats/L1TParticleFlow/interface/layer1_emulator.h" | ||||
|
|
||||
| #include "DataFormats/L1Trigger/interface/EtSum.h" | ||||
| #include "DataFormats/Math/interface/LorentzVector.h" | ||||
|
|
||||
| #include "L1Trigger/Phase2L1ParticleFlow/interface/jetmet/L1PFJUMPEmulator.h" | ||||
|
|
||||
| class L1JUMPProducer : public edm::global::EDProducer<> { | ||||
| /* | ||||
| Producer for the JUMP Algorithm | ||||
| JUMP: Jet Uncertainty-aware MET Prediction | ||||
| - Approximate L1 Jet energy resolution by pT, eta value | ||||
| - Apply the estimated resolution to MET | ||||
| */ | ||||
| public: | ||||
| explicit L1JUMPProducer(const edm::ParameterSet&); | ||||
| ~L1JUMPProducer() override; | ||||
|
|
||||
| private: | ||||
| void produce(edm::StreamID, edm::Event& iEvent, const edm::EventSetup& iSetup) const override; | ||||
| edm::EDGetTokenT<std::vector<l1t::EtSum>> metToken; | ||||
| edm::EDGetTokenT<std::vector<l1t::PFJet>> jetsToken; | ||||
|
|
||||
| typedef l1ct::pt_t pt_t; | ||||
| typedef l1ct::Jet Jet; | ||||
|
|
||||
| static constexpr float ptLSB_ = 0.25; | ||||
| static constexpr float phiLSB_ = M_PI / 720; | ||||
| static constexpr float maxPt_ = ((1 << pt_t::width) - 1) * ptLSB_; | ||||
|
|
||||
| void CalcJUMP_HLS(const l1t::EtSum& metVector, | ||||
| const std::vector<l1ct::Jet>& jets, | ||||
| reco::Candidate::PolarLorentzVector& JUMPVector) const; | ||||
|
|
||||
| std::vector<l1ct::Jet> convertEDMToHW(const std::vector<l1t::PFJet> edmJets) const; | ||||
|
|
||||
| double minJetPt; | ||||
| double maxJetEta; | ||||
| }; | ||||
|
|
||||
| L1JUMPProducer::L1JUMPProducer(const edm::ParameterSet& cfg) | ||||
| : metToken(consumes<std::vector<l1t::EtSum>>(cfg.getParameter<edm::InputTag>("RawMET"))), | ||||
| jetsToken(consumes<std::vector<l1t::PFJet>>(cfg.getParameter<edm::InputTag>("L1PFJets"))), | ||||
| minJetPt(cfg.getParameter<double>("MinJetpT")), | ||||
| maxJetEta(cfg.getParameter<double>("MaxJetEta")) { | ||||
| produces<std::vector<l1t::EtSum>>(); | ||||
| } | ||||
|
|
||||
| void L1JUMPProducer::produce(edm::StreamID, edm::Event& iEvent, const edm::EventSetup& iSetup) const { | ||||
| // Load Met | ||||
| l1t::EtSum rawMET = iEvent.get(metToken)[0]; | ||||
| // Load Jets | ||||
| l1t::PFJetCollection edmJets = iEvent.get(jetsToken); | ||||
|
|
||||
| std::vector<l1ct::Jet> hwJets = convertEDMToHW(edmJets); // convert to the emulator format | ||||
| // Apply pT and eta selections | ||||
| std::vector<l1ct::Jet> hwJetsFiltered; | ||||
| std::copy_if(hwJets.begin(), hwJets.end(), std::back_inserter(hwJetsFiltered), [&](auto jet) { | ||||
| return jet.hwPt > l1ct::Scales::makePtFromFloat(float(minJetPt)) && | ||||
| std::abs(jet.hwEta) < l1ct::Scales::makeGlbEta(maxJetEta); | ||||
| }); | ||||
|
|
||||
| // JUMP Algorithm | ||||
| reco::Candidate::PolarLorentzVector JUMPVector; | ||||
| CalcJUMP_HLS(rawMET, hwJetsFiltered, JUMPVector); | ||||
|
|
||||
| l1t::EtSum theJUMP(JUMPVector, l1t::EtSum::EtSumType::kMissingEt, 0, 0, 0, 0); | ||||
| auto JUMPCollection = std::make_unique<std::vector<l1t::EtSum>>(0); | ||||
| JUMPCollection->push_back(theJUMP); | ||||
| iEvent.put(std::move(JUMPCollection)); | ||||
| } | ||||
|
|
||||
| void L1JUMPProducer::CalcJUMP_HLS(const l1t::EtSum& metVector, | ||||
| const std::vector<l1ct::Jet>& jets, | ||||
| reco::Candidate::PolarLorentzVector& outMet_Vector) const { | ||||
| // JUMP Calculate | ||||
| l1ct::Sum inMet; | ||||
| inMet.hwPt = metVector.pt(); | ||||
| inMet.hwPhi = l1ct::Scales::makeGlbPhi(metVector.phi()); | ||||
|
|
||||
| l1ct::Sum outMet; | ||||
|
|
||||
| JUMP_emu(inMet, jets, outMet); | ||||
|
|
||||
| outMet_Vector.SetPt(outMet.hwPt.to_double()); | ||||
| outMet_Vector.SetPhi(outMet.hwPhi.to_double() * phiLSB_); | ||||
| outMet_Vector.SetEta(0); | ||||
| } | ||||
|
|
||||
| std::vector<l1ct::Jet> L1JUMPProducer::convertEDMToHW(const std::vector<l1t::PFJet> edmJets) const { | ||||
| std::vector<l1ct::Jet> hwJets; | ||||
| std::for_each(edmJets.begin(), edmJets.end(), [&](const l1t::PFJet jet) { | ||||
| l1ct::Jet hwJet = l1ct::Jet::unpack(jet.getHWJetCT()); | ||||
| hwJets.push_back(hwJet); | ||||
| }); | ||||
| return hwJets; | ||||
| } | ||||
|
|
||||
| L1JUMPProducer::~L1JUMPProducer() {} | ||||
|
|
||||
| #include "FWCore/Framework/interface/MakerMacros.h" | ||||
|
||||
| #include "FWCore/Framework/interface/MakerMacros.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be
L1Trigger_Phase2L1ParticleFlow_JUMPEmulator_hto match the filename?