Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-05-09 22:40:11

0001 #include "L1Trigger/Phase2L1ParticleFlow/interface/jetmet/L1SeedConePFJetEmulator.h"
0002 
0003 L1SCJetEmu::L1SCJetEmu(bool debug, float coneSize, unsigned nJets)
0004     : debug_(debug),
0005       coneSize_(coneSize),
0006       nJets_(nJets),
0007       rCone2_(coneSize * coneSize / l1ct::Scales::ETAPHI_LSB / l1ct::Scales::ETAPHI_LSB) {
0008   init_invert_table<pt_t, inv_pt_t, N_table_inv_pt>(inv_pt_table_);
0009 }
0010 
0011 L1SCJetEmu::detaphi_t L1SCJetEmu::deltaPhi(L1SCJetEmu::Particle a, L1SCJetEmu::Particle b) {
0012   detaphi_t dphi = detaphi_t(a.hwPhi) - detaphi_t(b.hwPhi);
0013   // phi wrap
0014   detaphi_t dphi0 =
0015       dphi > detaphi_t(l1ct::Scales::INTPHI_PI) ? detaphi_t(l1ct::Scales::INTPHI_TWOPI - dphi) : detaphi_t(dphi);
0016   detaphi_t dphi1 =
0017       dphi < detaphi_t(-l1ct::Scales::INTPHI_PI) ? detaphi_t(l1ct::Scales::INTPHI_TWOPI + dphi) : detaphi_t(dphi);
0018   detaphi_t dphiw = dphi > detaphi_t(0) ? dphi0 : dphi1;
0019   return dphiw;
0020 }
0021 
0022 bool L1SCJetEmu::inCone(L1SCJetEmu::Particle seed, L1SCJetEmu::Particle part) const {
0023   // scale the particle eta, phi to hardware units
0024   detaphi_t deta = detaphi_t(seed.hwEta) - detaphi_t(part.hwEta);
0025   detaphi_t dphi = deltaPhi(seed, part);
0026   bool ret = deta * deta + dphi * dphi < rCone2_;
0027   //bool ret = r2 < cone2;
0028   if (debug_) {
0029     detaphi2_t r2 = detaphi2_t(deta) * detaphi2_t(deta) + detaphi2_t(dphi) * detaphi2_t(dphi);
0030     dbgCout() << "  part eta, seed eta: " << part.hwEta << ", " << seed.hwEta << std::endl;
0031     dbgCout() << "  part phi, seed phi: " << part.hwPhi << ", " << seed.hwPhi << std::endl;
0032     dbgCout() << "  pt, deta, dphi, r2, cone2, lt: " << part.hwPt << ", " << deta << ", " << dphi << ", "
0033               << deta * deta + dphi * dphi << ", " << rCone2_ << ", " << ret << std::endl;
0034   }
0035   return ret;
0036 }
0037 
0038 std::vector<L1SCJetEmu::Particle> L1SCJetEmu::sortConstituents(const std::vector<Particle>& parts,
0039                                                                const Particle seed) const {
0040   std::vector<Particle> sortedParts = parts;  // instantiate a vector to store sorted parts
0041   std::sort(sortedParts.begin(), sortedParts.end(), [](const Particle& a, const Particle& b) {
0042     return a.hwPt > b.hwPt;
0043   });                               // sort by pt by jet mass fn as in firmware
0044   std::vector<Particle> truncated;  // instantiate vector to store truncated, sorted parts
0045   truncated.resize(NCONSTITSFW);
0046   for (unsigned iConst = 0; iConst < NCONSTITSFW; ++iConst) {  // iterate over NCONSTITS (or truncated.size())
0047     if (iConst <
0048         sortedParts.size()) {  // if iConst is less than the number of constituents in the jet then store the constituent
0049       truncated[iConst].hwEta = static_cast<detaphi_t>(sortedParts.at(iConst).hwEta - seed.hwEta);
0050       truncated[iConst].hwPhi = static_cast<detaphi_t>(deltaPhi(sortedParts.at(iConst), seed));
0051       truncated[iConst].hwPt = sortedParts.at(iConst).hwPt;
0052     } else {  // if iConst is greater than the number of constituents in the jet then store an empty constituent (pt = 0) to mimic sparse array from firmware
0053       truncated[iConst].clear();
0054     }
0055   }
0056   return truncated;
0057 }
0058 
0059 L1SCJetEmu::mass2_t L1SCJetEmu::jetMass_HW(const std::vector<Particle>& parts) const {  // need ampersand?
0060 
0061   // // INSTANTIATE LUTS
0062   static std::array<eventrig_t, hwEtaPhi_steps> cosh_lut =
0063       init_trig_lut<eventrig_t, hwEtaPhi_steps>([](float x) -> eventrig_t { return std::cosh(x); });
0064   static std::array<eventrig_t, hwEtaPhi_steps> cos_lut =
0065       init_trig_lut<eventrig_t, hwEtaPhi_steps>([](float x) -> eventrig_t { return std::cos(x); });
0066   static std::array<oddtrig_t, hwEtaPhi_steps> sin_lut =
0067       init_trig_lut<oddtrig_t, hwEtaPhi_steps>([](float x) -> oddtrig_t { return std::sin(x); });
0068   static std::array<oddtrig_t, hwEtaPhi_steps> sinh_lut =
0069       init_trig_lut<oddtrig_t, hwEtaPhi_steps>([](float x) -> oddtrig_t { return std::sinh(x); });
0070 
0071   std::vector<ppt_t> en;
0072   en.resize(parts.size());
0073   std::transform(parts.begin(), parts.end(), en.begin(), [](const Particle& part) {
0074     return ppt_t(part.hwPt * cosh_lut[std::abs(part.hwEta)]);
0075   });
0076   ppt_t sum_en = std::accumulate(en.begin(), en.end(), ppt_t(0));
0077 
0078   std::vector<ppt_t> px;
0079   px.resize(parts.size());
0080   std::transform(parts.begin(), parts.end(), px.begin(), [](const Particle& part) {
0081     return ppt_t(part.hwPt * cos_lut[std::abs(part.hwPhi)]);
0082   });
0083   ppt_t sum_px = std::accumulate(px.begin(), px.end(), ppt_t(0));
0084 
0085   std::vector<npt_t> py;
0086   py.resize(parts.size());
0087   std::transform(parts.begin(), parts.end(), py.begin(), [](const Particle& part) {
0088     return npt_t(part.hwPt * sin_lut[std::abs(part.hwPhi)] * ((part.hwPhi >= 0) ? 1 : -1));
0089   });
0090   npt_t sum_py = std::accumulate(py.begin(), py.end(), npt_t(0));
0091 
0092   std::vector<npt_t> pz;
0093   pz.resize(parts.size());
0094   std::transform(parts.begin(), parts.end(), pz.begin(), [](const Particle& part) {
0095     return npt_t(part.hwPt * sinh_lut[std::abs(part.hwEta)] * ((part.hwEta >= 0) ? 1 : -1));
0096   });
0097   npt_t sum_pz = std::accumulate(pz.begin(), pz.end(), npt_t(0));
0098 
0099   return (sum_en * sum_en) - (sum_px * sum_px) - (sum_py * sum_py) - (sum_pz * sum_pz);
0100 }
0101 
0102 L1SCJetEmu::Jet L1SCJetEmu::makeJet_HW(const std::vector<Particle>& parts, const Particle seed) const {
0103   // Seed Cone Jet algorithm with ap_fixed types and hardware emulation
0104 
0105   // Event with saturation, order of terms doesn't matter since they're all positive
0106   auto sumpt = [](pt_t(a), const Particle& b) { return a + b.hwPt; };  // essentially a python lambda fn
0107 
0108   // Sum the pt
0109   pt_t pt = std::accumulate(parts.begin(), parts.end(), pt_t(0), sumpt);
0110   inv_pt_t inv_pt = invert_with_shift<pt_t, inv_pt_t, N_table_inv_pt>(pt, inv_pt_table_, false);
0111 
0112   // pt weighted d eta
0113   std::vector<pt_etaphi_t> pt_deta;
0114   pt_deta.resize(parts.size());
0115   std::transform(parts.begin(), parts.end(), pt_deta.begin(), [&seed](const Particle& part) {
0116     // In the firmware we calculate the per-particle pt-weighted deta
0117     return pt_etaphi_t(part.hwPt * detaphi_t(part.hwEta - seed.hwEta));
0118   });
0119   // Accumulate the pt-weighted etas. Init to 0, include seed in accumulation
0120   pt_etaphi_t sum_pt_eta = std::accumulate(pt_deta.begin(), pt_deta.end(), pt_etaphi_t(0));
0121   etaphi_t eta = seed.hwEta + etaphi_t(sum_pt_eta * inv_pt);
0122 
0123   // pt weighted d phi
0124   std::vector<pt_etaphi_t> pt_dphi;
0125   pt_dphi.resize(parts.size());
0126   std::transform(parts.begin(), parts.end(), pt_dphi.begin(), [&seed](const Particle& part) {
0127     // In the firmware we calculate the per-particle pt-weighted dphi
0128     return pt_etaphi_t(part.hwPt * deltaPhi(part, seed));
0129   });
0130   // Accumulate the pt-weighted phis. Init to 0, include seed in accumulation
0131   pt_etaphi_t sum_pt_phi = std::accumulate(pt_dphi.begin(), pt_dphi.end(), pt_etaphi_t(0));
0132   etaphi_t phi = seed.hwPhi + etaphi_t(sum_pt_phi * inv_pt);  // shift the seed by pt weighted sum_pt_phi
0133 
0134   std::vector<Particle> truncated =
0135       sortConstituents(parts, seed);  // sort the constituents by pt and truncate to NCONSTITS
0136   mass2_t massSq = L1SCJetEmu::jetMass_HW(truncated);
0137 
0138   Jet jet;
0139   jet.hwPt = pt;
0140   jet.hwEta = eta;
0141   jet.hwPhi = phi;
0142   jet.hwMassSq = massSq;
0143   jet.constituents = parts;
0144   // jet.constituents = truncated;  // store the truncated, sorted NCONSTITSFW sparse array of constituents
0145 
0146   if (debug_) {
0147     std::for_each(pt_dphi.begin(), pt_dphi.end(), [](pt_etaphi_t& x) { dbgCout() << "pt_dphi: " << x << std::endl; });
0148     std::for_each(pt_deta.begin(), pt_deta.end(), [](pt_etaphi_t& x) { dbgCout() << "pt_deta: " << x << std::endl; });
0149     dbgCout() << " sum_pt_eta: " << sum_pt_eta << ", 1/pt: " << inv_pt
0150               << ", sum_pt_eta * 1/pt: " << etaphi_t(sum_pt_eta * inv_pt) << std::endl;
0151     dbgCout() << " sum_pt_phi: " << sum_pt_phi << ", 1/pt: " << inv_pt
0152               << ", sum_pt_phi * 1/pt: " << etaphi_t(sum_pt_phi * inv_pt) << std::endl;
0153     dbgCout() << " uncorr eta: " << seed.hwEta << ", phi: " << seed.hwPhi << std::endl;
0154     dbgCout() << "   corr eta: " << eta << ", phi: " << phi << std::endl;
0155     dbgCout() << "         pt: " << pt << std::endl;
0156   }
0157 
0158   return jet;
0159 }
0160 
0161 std::vector<L1SCJetEmu::Jet> L1SCJetEmu::emulateEvent(std::vector<Particle>& parts) const {
0162   // The fixed point algorithm emulation
0163   std::vector<Particle> work;
0164   work.resize(parts.size());
0165   std::transform(parts.begin(), parts.end(), work.begin(), [](const Particle& part) { return part; });
0166 
0167   std::vector<Jet> jets;
0168   jets.reserve(nJets_);
0169   while ((!work.empty() && jets.size() < nJets_)) {
0170     // Take the highest pt candidate as a seed
0171     // Use the firmware reduce function to find the same seed as the firmware
0172     // in case there are multiple seeds with the same pT
0173     // ... or use external seed if configured to do so
0174     Particle seed = reduce(work, op_max);
0175 
0176     // Get the particles within a coneSize_ of the seed
0177     std::vector<Particle> particlesInCone;
0178     std::copy_if(work.begin(), work.end(), std::back_inserter(particlesInCone), [&](const Particle& part) {
0179       return inCone(seed, part);
0180     });
0181     if (debug_) {
0182       dbgCout() << "Seed: " << seed.hwPt << ", " << seed.hwEta << ", " << seed.hwPhi << std::endl;
0183       dbgCout() << "N particles : " << particlesInCone.size() << std::endl;
0184       std::for_each(particlesInCone.begin(), particlesInCone.end(), [&](Particle& part) {
0185         dbgCout() << "  Part: " << part.hwPt << ", " << part.hwEta << ", " << part.hwPhi << std::endl;
0186         inCone(seed, part);
0187       });
0188     }
0189     jets.push_back(makeJet_HW(particlesInCone, seed));
0190     //remove the clustered particles
0191     work.erase(std::remove_if(work.begin(),
0192                               work.end(),
0193                               [&](const Particle& part) {
0194                                 return inCone(seed, part);
0195                               }),  //erase particles from further jet clustering
0196                work.end());
0197   }
0198   return jets;
0199 }