-
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 3 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,129 @@ | ||
| #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; | ||
| if (abseta == 0.00) | ||
| etabin = 1; | ||
| else if (abseta < J.edges[0]) | ||
| etabin = 1; | ||
| else if (abseta < J.edges[1]) | ||
| etabin = 2; | ||
| else if (abseta < J.edges[2]) | ||
| etabin = 3; | ||
| else if (abseta < J.edges[3]) | ||
| etabin = 4; | ||
| else | ||
| etabin = 0; | ||
|
||
|
|
||
| dPx_2 = 0; | ||
| dPy_2 = 0; | ||
| l1ct::Sum jet_resolution; | ||
| jet_resolution.hwPt = J.par0[etabin] * jet.hwPt + J.par1[etabin]; | ||
| jet_resolution.hwPhi = jet.hwPhi; | ||
| L1METEmu::Particle_xy dpt_xy = L1METEmu::Get_xy(jet_resolution.hwPt, jet_resolution.hwPhi); | ||
|
|
||
| dPx_2 = dpt_xy.hwPx * dpt_xy.hwPx; | ||
| dPy_2 = dpt_xy.hwPy * dpt_xy.hwPy; | ||
| } | ||
|
|
||
| inline void Met_dPt(const std::vector<l1ct::Jet> jets, L1METEmu::proj2_t& dPx_2, L1METEmu::proj2_t& dPy_2) { | ||
| L1METEmu::proj2_t each_dPx2 = 0; | ||
| L1METEmu::proj2_t each_dPy2 = 0; | ||
|
|
||
| L1METEmu::proj2_t sum_dPx2 = 0; | ||
| L1METEmu::proj2_t sum_dPy2 = 0; | ||
|
|
||
| for (uint i = 0; i < jets.size(); i++) { | ||
| Get_dPt(jets[i], each_dPx2, each_dPy2); | ||
| sum_dPx2 += each_dPx2; | ||
| sum_dPy2 += each_dPy2; | ||
| } | ||
|
|
||
| dPx_2 = sum_dPx2; | ||
| dPy_2 = sum_dPy2; | ||
| } | ||
| } // namespace L1JUMPEmu | ||
|
|
||
| inline void JUMP_emu(const l1ct::Sum inMet, const std::vector<l1ct::Jet> jets, l1ct::Sum& outMet) { | ||
| L1METEmu::Particle_xy inMet_xy = L1METEmu::Get_xy(inMet.hwPt, inMet.hwPhi); | ||
|
|
||
| L1METEmu::proj2_t dPx_2; | ||
| L1METEmu::proj2_t dPy_2; | ||
| L1JUMPEmu::Met_dPt(jets, dPx_2, dPy_2); | ||
|
|
||
| L1METEmu::Particle_xy outMet_xy; | ||
| outMet_xy.hwPx = (inMet_xy.hwPx > 0) ? inMet_xy.hwPx + L1METEmu::proj2_t(sqrt(dPx_2.to_float())) | ||
| : inMet_xy.hwPx - L1METEmu::proj2_t(sqrt(dPx_2.to_float())); | ||
| outMet_xy.hwPy = (inMet_xy.hwPy > 0) ? inMet_xy.hwPy + L1METEmu::proj2_t(sqrt(dPy_2.to_float())) | ||
| : inMet_xy.hwPy - L1METEmu::proj2_t(sqrt(dPy_2.to_float())); | ||
| L1METEmu::pxpy_to_ptphi(outMet_xy, outMet); | ||
| } | ||
|
|
||
| #endif | ||
| 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++) { |
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?