From 30207b957df950692ba3f1a4c89fec537d8cee23 Mon Sep 17 00:00:00 2001 From: Henri Petrow <24872616+henripetrow@users.noreply.github.com> Date: Mon, 4 May 2026 17:24:37 +0300 Subject: [PATCH 1/9] L1TSC82ProngJetModel (#150) * Added nprong score to DataFormats. * Added L1TSC82ProngJet to DPGAnalysis. * Added L1TSC82ProngJetModel to L1Trigger/Phase2L1ParticleFlow * Fix for nprong tag. * Cleaned includes. * File renamed. * Removed comment from addPh2GTObjects(process) * fixes. * Reverted changes. * Removed cuts.. * Update L1Trigger/Phase2L1ParticleFlow/src/L1TSC82ProngJetID.cc Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update L1Trigger/Phase2L1ParticleFlow/plugins/L1TSC82ProngJetModelProducer.cc Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update DataFormats/L1TParticleFlow/src/jets.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * added values for minPt and maxEta. * Added std headers. * Added a check for fNParticles. * Update L1Trigger/Phase2L1ParticleFlow/python/l1pfJetMet_cff.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply CMSSW code-format --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../python/l1tPh2Nanotables_cff.py | 7 +- DataFormats/L1TParticleFlow/interface/jets.h | 6 +- DataFormats/L1TParticleFlow/src/jets.cpp | 6 +- .../interface/L1TSC82ProngJetID.h | 45 +++++ .../plugins/L1TSC82ProngJetModelProducer.cc | 108 ++++++++++++ .../python/l1pfJetMet_cff.py | 7 +- .../src/L1TSC82ProngJetID.cc | 154 ++++++++++++++++++ 7 files changed, 323 insertions(+), 10 deletions(-) create mode 100644 L1Trigger/Phase2L1ParticleFlow/interface/L1TSC82ProngJetID.h create mode 100644 L1Trigger/Phase2L1ParticleFlow/plugins/L1TSC82ProngJetModelProducer.cc create mode 100644 L1Trigger/Phase2L1ParticleFlow/src/L1TSC82ProngJetID.cc diff --git a/DPGAnalysis/Phase2L1TNanoAOD/python/l1tPh2Nanotables_cff.py b/DPGAnalysis/Phase2L1TNanoAOD/python/l1tPh2Nanotables_cff.py index 871445f2d0281..d3de5f2389dd8 100644 --- a/DPGAnalysis/Phase2L1TNanoAOD/python/l1tPh2Nanotables_cff.py +++ b/DPGAnalysis/Phase2L1TNanoAOD/python/l1tPh2Nanotables_cff.py @@ -394,12 +394,13 @@ ) sc8JetTable = pfJetTable.clone( - src = 'l1tSC8PFL1PuppiCorrectedEmulator', + src = cms.InputTag('l1tSC82ProngJetProducer', 'l1tSC82ProngJets'), name = "L1puppiJetSC8", doc = "SeededCone 0.8 Puppi jet, origin: Correlator", variables = cms.PSet( pfJetTable.variables.clone(), - mass = Var("mass", float) + mass = Var("mass", float), + nprongTagScore = Var('getTagScore("nprong")', float) ) ) @@ -580,7 +581,7 @@ # ## jets sc4JetTable, sc8JetTable, - sc4ExtJetTable, + sc4ExtJetTable, sc4NGJetTable, histoJetTable, caloJetTable, diff --git a/DataFormats/L1TParticleFlow/interface/jets.h b/DataFormats/L1TParticleFlow/interface/jets.h index 9a49248309765..aa41a0ef86aef 100644 --- a/DataFormats/L1TParticleFlow/interface/jets.h +++ b/DataFormats/L1TParticleFlow/interface/jets.h @@ -15,7 +15,7 @@ namespace l1ct { // all possible tag categories (can be extended for new / separate taggers) class JetTagClass { public: - enum JetTagClassValue : uint8_t { b, c, uds, g, tau_p, tau_n, mu, e }; + enum JetTagClassValue : uint8_t { b, c, uds, g, tau_p, tau_n, mu, e, nprong }; JetTagClass() = default; JetTagClass(JetTagClassValue aJetTagClassValue) : value_(aJetTagClassValue) {} JetTagClass(std::string aJetTagClassValueString) { @@ -47,7 +47,7 @@ namespace l1ct { // Define a separate class/struct for jet tag handling struct JetTagClassHandler { - static const unsigned NTagFields = 8; + static const unsigned NTagFields = 9; static const JetTagClass tagClassesDefault_[NTagFields]; JetTagClass tagClassesArray[NTagFields]; @@ -197,7 +197,7 @@ namespace l1ct { j.v3.phi = CTtoGT_phi(hwPhi); j.v3.eta = CTtoGT_eta(hwEta); j.z0(l1ct::z0_t::width - 1, 0) = hwZ0(l1ct::z0_t::width - 1, 0); - j.hwNProngScore = 0; + j.hwNProngScore = hwTagScores[0]; // currently only one WideJet tagger j.hwMassSq = CTtoGT_massSq(hwMassSq); return j; diff --git a/DataFormats/L1TParticleFlow/src/jets.cpp b/DataFormats/L1TParticleFlow/src/jets.cpp index 3c585c70fe987..f147c94d2c68f 100644 --- a/DataFormats/L1TParticleFlow/src/jets.cpp +++ b/DataFormats/L1TParticleFlow/src/jets.cpp @@ -8,7 +8,8 @@ const std::unordered_map l1ct: {"tau_p", l1ct::JetTagClass::JetTagClassValue::tau_p}, {"tau_n", l1ct::JetTagClass::JetTagClassValue::tau_n}, {"mu", l1ct::JetTagClass::JetTagClassValue::mu}, - {"e", l1ct::JetTagClass::JetTagClassValue::e}}; + {"e", l1ct::JetTagClass::JetTagClassValue::e}, + {"nprong", l1ct::JetTagClass::JetTagClassValue::nprong}}; const l1ct::JetTagClass l1ct::JetTagClassHandler::tagClassesDefault_[NTagFields] = {l1ct::JetTagClass("b"), l1ct::JetTagClass("c"), @@ -17,4 +18,5 @@ const l1ct::JetTagClass l1ct::JetTagClassHandler::tagClassesDefault_[NTagFields] l1ct::JetTagClass("tau_p"), l1ct::JetTagClass("tau_n"), l1ct::JetTagClass("mu"), - l1ct::JetTagClass("e")}; + l1ct::JetTagClass("e"), + l1ct::JetTagClass("nprong")}; diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/L1TSC82ProngJetID.h b/L1Trigger/Phase2L1ParticleFlow/interface/L1TSC82ProngJetID.h new file mode 100644 index 0000000000000..a1f5c9e1e117b --- /dev/null +++ b/L1Trigger/Phase2L1ParticleFlow/interface/L1TSC82ProngJetID.h @@ -0,0 +1,45 @@ +#ifndef L1TRIGGER_PHASE2L1PARTICLEFLOWS_L1TSC82ProngJetID_H +#define L1TRIGGER_PHASE2L1PARTICLEFLOWS_L1TSC82ProngJetID_H + +#include "DataFormats/L1TParticleFlow/interface/PFJet.h" +#include +#include + +//HLS4ML compiled emulator modeling +#include "ap_fixed.h" +#include "hls4ml/emulator.h" + +class L1TSC82ProngJetID { +public: + L1TSC82ProngJetID(const std::shared_ptr model, int iNParticles); + + typedef ap_fixed<24, 12, AP_RND, AP_SAT, 0> inputtype; + typedef ap_ufixed<20, 10, AP_RND, AP_SAT, 0> prong_score; + + void setNNVectorVar(); + std::vector EvaluateNNFixed(); + std::vector computeFixed(const l1t::PFJet &iJet); + +private: + std::vector NNvectorVar_; + int fNParticles_; + std::unique_ptr fPt_; + std::unique_ptr fPt_rel_; + std::unique_ptr fDEta_; + std::unique_ptr fDPhi_; + std::unique_ptr fPt_log_; + std::unique_ptr fMass_; + std::unique_ptr fZ0_; + std::unique_ptr fDxy_; + std::unique_ptr fIs_filled_; + std::unique_ptr fPuppi_weight_; + std::unique_ptr fEmID_; + std::unique_ptr fQuality_; + + std::unique_ptr fCharge_; + std::unique_ptr fId_; + std::shared_ptr modelRef_; + + //bool isDebugEnabled_; +}; +#endif diff --git a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TSC82ProngJetModelProducer.cc b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TSC82ProngJetModelProducer.cc new file mode 100644 index 0000000000000..a8bb606acb5d7 --- /dev/null +++ b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TSC82ProngJetModelProducer.cc @@ -0,0 +1,108 @@ +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Utilities/interface/InputTag.h" + +#include "DataFormats/L1TParticleFlow/interface/PFJet.h" +#include "DataFormats/JetReco/interface/Jet.h" +#include "DataFormats/L1TParticleFlow/interface/PFCandidate.h" +#include "L1Trigger/Phase2L1ParticleFlow/interface/L1TSC82ProngJetID.h" +#include "DataFormats/Common/interface/ValueMap.h" + +#include "DataFormats/L1Trigger/interface/VertexWord.h" + +#include +#include + +#include +#include "ap_fixed.h" +#include "hls4ml/emulator.h" + +using namespace l1t; + +class L1TSC82ProngJetProducer : public edm::stream::EDProducer<> { +public: + explicit L1TSC82ProngJetProducer(const edm::ParameterSet&); + ~L1TSC82ProngJetProducer() override = default; + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); + +private: + std::unique_ptr fJetId_; + void produce(edm::Event& iEvent, const edm::EventSetup& iSetup) override; + + edm::EDGetTokenT> const jets_; + double const fMinPt_; + double const fMaxEta_; + unsigned int const fMaxJets_; + int const fNParticles_; + + hls4mlEmulator::ModelLoader loader; + std::shared_ptr model; +}; + +L1TSC82ProngJetProducer::L1TSC82ProngJetProducer(const edm::ParameterSet& cfg) + : jets_(consumes>(cfg.getParameter("jets"))), + fMinPt_(cfg.getParameter("minPt")), + fMaxEta_(cfg.getParameter("maxEta")), + fMaxJets_(cfg.getParameter("maxJets")), + fNParticles_(cfg.getParameter("nParticles")), + loader(hls4mlEmulator::ModelLoader(cfg.getParameter("l1tSC82ProngJetModelPath"))) { + model = loader.load_model(); + fJetId_ = std::make_unique(model, fNParticles_); + produces("l1tSC82ProngJets"); +} + +void L1TSC82ProngJetProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + edm::Handle> jets; + iEvent.getByToken(jets_, jets); + std::vector taggedJets; + + for (const auto& srcjet : *jets) { + l1ct::Jet ctHWJet = l1ct::Jet::unpack(srcjet.encodedJet(l1t::PFJet::HWEncoding::CT)); + + if (srcjet.pt() < fMinPt_ || std::abs(srcjet.eta()) > fMaxEta_ || taggedJets.size() >= fMaxJets_) { + ctHWJet.clear(); + continue; + } + std::vector JetProngScore_float = fJetId_->computeFixed(srcjet); + l1gt::WideJet gtwHWJet = l1gt::WideJet::unpack(srcjet.getHWJetGTWide()); + + l1t::PFJet edmJet( + srcjet.pt(), srcjet.eta(), srcjet.phi(), srcjet.mass(), gtwHWJet.v3.pt.V, gtwHWJet.v3.eta.V, gtwHWJet.v3.phi.V); + + std::vector classes{l1ct::JetTagClass(l1ct::JetTagClass::JetTagClassValue::nprong)}; + + edmJet.addTagScores(JetProngScore_float, classes, 1.); + edmJet.setEncodedJet(l1t::PFJet::HWEncoding::CT, ctHWJet.pack()); + edmJet.setEncodedJet(l1t::PFJet::HWEncoding::GTWide, gtwHWJet.pack()); + + std::vector> constituents; + std::for_each(srcjet.constituents().begin(), srcjet.constituents().end(), [&](auto constituent) { + edmJet.addConstituent(constituent); + }); + + taggedJets.push_back(edmJet); + } + std::sort(taggedJets.begin(), taggedJets.end(), [](l1t::PFJet a, l1t::PFJet b) { return (a.pt() > b.pt()); }); + + std::unique_ptr taggedJetsCollection(new l1t::PFJetCollection); + taggedJetsCollection->swap(taggedJets); + iEvent.put(std::move(taggedJetsCollection), "l1tSC82ProngJets"); +} + +void L1TSC82ProngJetProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + desc.add("jets", edm::InputTag("l1tSC8PFL1PuppiEmulator")); + desc.add("l1tSC82ProngJetModelPath", std::string("L1TSC82ProngJetModel_v0")); + desc.add("minPt", 0.); + desc.add("maxEta", 5.); + desc.add("maxJets", 16); + desc.add("nParticles", 8); + descriptions.add("l1tSC82ProngJetProducer", desc); +} + +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(L1TSC82ProngJetProducer); diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1pfJetMet_cff.py b/L1Trigger/Phase2L1ParticleFlow/python/l1pfJetMet_cff.py index c3fb6c41d509a..4f19902b7c3dd 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1pfJetMet_cff.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/l1pfJetMet_cff.py @@ -60,9 +60,12 @@ correctorFile = cms.string("L1Trigger/Phase2L1ParticleFlow/data/jecs/jecs_20220308.root"), correctorDir = cms.string('L1PuppiSC4EmuJets')) + +l1tSC82ProngJetProducer = l1tSC4NGJetProducer.clone() + L1TPFJetsTask = cms.Task( l1tLayer2Deregionizer, l1tSC4PFL1PF, l1tSC4PFL1Puppi, l1tSC4PFL1PuppiCorrected, l1tSC8PFL1Puppi, l1tSC8PFL1PuppiCorrected, l1tSC4PFL1PuppiEmulator, l1tSC4PFL1PuppiCorrectedEmulator, l1tSC4PFL1PuppiCorrectedEmulatorMHT, - l1tSC8PFL1PuppiEmulator, l1tSC8PFL1PuppiCorrectedEmulator + l1tSC8PFL1PuppiEmulator, l1tSC8PFL1PuppiCorrectedEmulator, l1tSC82ProngJetProducer ) L1TPFJetsExtendedTask = cms.Task( @@ -71,5 +74,5 @@ L1TPFJetsEmulationTask = cms.Task( l1tLayer2Deregionizer, l1tSC4PFL1PuppiEmulator, l1tSC4PFL1PuppiCorrectedEmulator, l1tSC4PFL1PuppiCorrectedEmulatorMHT, - l1tSC8PFL1PuppiEmulator, l1tSC8PFL1PuppiCorrectedEmulator + l1tSC8PFL1PuppiEmulator, l1tSC8PFL1PuppiCorrectedEmulator, l1tSC82ProngJetProducer ) diff --git a/L1Trigger/Phase2L1ParticleFlow/src/L1TSC82ProngJetID.cc b/L1Trigger/Phase2L1ParticleFlow/src/L1TSC82ProngJetID.cc new file mode 100644 index 0000000000000..20e8a97f25040 --- /dev/null +++ b/L1Trigger/Phase2L1ParticleFlow/src/L1TSC82ProngJetID.cc @@ -0,0 +1,154 @@ +#include "L1Trigger/Phase2L1ParticleFlow/interface/L1TSC82ProngJetID.h" +#include "DataFormats/Math/interface/deltaPhi.h" +#include +#include + +L1TSC82ProngJetID::L1TSC82ProngJetID(const std::shared_ptr model, int iNParticles) + : modelRef_(model) { + NNvectorVar_.clear(); + fNParticles_ = iNParticles; + + fPt_ = std::make_unique(fNParticles_); + fPt_rel_ = std::make_unique(fNParticles_); + fDEta_ = std::make_unique(fNParticles_); + fDPhi_ = std::make_unique(fNParticles_); + fPt_log_ = std::make_unique(fNParticles_); + fMass_ = std::make_unique(fNParticles_); + fZ0_ = std::make_unique(fNParticles_); + fDxy_ = std::make_unique(fNParticles_); + fIs_filled_ = std::make_unique(fNParticles_); + fPuppi_weight_ = std::make_unique(fNParticles_); + fEmID_ = std::make_unique(fNParticles_); + fQuality_ = std::make_unique(fNParticles_); + + fId_ = std::make_unique(fNParticles_); + fCharge_ = std::make_unique(fNParticles_); +} + +void L1TSC82ProngJetID::setNNVectorVar() { + NNvectorVar_.clear(); + for (int i0 = 0; i0 < fNParticles_; i0++) { + NNvectorVar_.push_back(fPt_.get()[i0]); // pt + NNvectorVar_.push_back(fPt_rel_.get()[i0]); //pT as a fraction of jet pT + NNvectorVar_.push_back(fPt_log_.get()[i0]); // pt log + NNvectorVar_.push_back(fDEta_.get()[i0]); //dEta from jet axis + NNvectorVar_.push_back(fDPhi_.get()[i0]); //dPhi from jet axis + NNvectorVar_.push_back(fMass_.get()[i0]); // Mass + NNvectorVar_.push_back(fId_.get()[i0] == l1t::PFCandidate::Photon); // Photon + NNvectorVar_.push_back(fId_.get()[i0] == l1t::PFCandidate::Electron && fCharge_.get()[i0] > 0); // Positron + NNvectorVar_.push_back(fId_.get()[i0] == l1t::PFCandidate::Electron && fCharge_.get()[i0] < 0); // Electron + NNvectorVar_.push_back(fId_.get()[i0] == l1t::PFCandidate::Muon && fCharge_.get()[i0] > 0); // Anti-muon + NNvectorVar_.push_back(fId_.get()[i0] == l1t::PFCandidate::Muon && fCharge_.get()[i0] < 0); // Muon + NNvectorVar_.push_back(fId_.get()[i0] == l1t::PFCandidate::NeutralHadron); // Neutral Had + NNvectorVar_.push_back(fId_.get()[i0] == l1t::PFCandidate::ChargedHadron && fCharge_.get()[i0] > 0); // Anti-Pion + NNvectorVar_.push_back(fId_.get()[i0] == l1t::PFCandidate::ChargedHadron && fCharge_.get()[i0] < 0); // Pion + NNvectorVar_.push_back(fZ0_.get()[i0]); // z0 + NNvectorVar_.push_back(fDxy_.get()[i0]); // dxy + NNvectorVar_.push_back(fIs_filled_.get()[i0]); // isfilled + NNvectorVar_.push_back(fPuppi_weight_.get()[i0]); // puppi weight + NNvectorVar_.push_back(fEmID_.get()[i0]); // emID + NNvectorVar_.push_back(fQuality_.get()[i0]); // quality + } +} + +std::vector L1TSC82ProngJetID::EvaluateNNFixed() { + const unsigned int NInputs = 160; + const unsigned int FeaturesPerParticle = 20; + + if (fNParticles_ * FeaturesPerParticle != NInputs) { + throw std::runtime_error( + "L1TSC82ProngJetID::EvaluateNNFixed: " + "Model expects exactly 8 particles (160 inputs), but fNParticles_ = " + + std::to_string(fNParticles_)); + } + + prong_score prong_scores; + inputtype fillzero = 0.0; + + inputtype modelInput[NInputs]; + std::fill(std::begin(modelInput), std::end(modelInput), fillzero); + + for (unsigned int i = 0; i < NInputs; i++) { + modelInput[i] = NNvectorVar_[i]; + } + + modelRef_->prepare_input(modelInput); + modelRef_->predict(); + modelRef_->read_result(&prong_scores); + + std::vector prong_score_; + prong_score_.push_back(prong_scores.to_float()); + + return prong_score_; +} //end EvaluateNNFixed + +std::vector L1TSC82ProngJetID::computeFixed(const l1t::PFJet &iJet) { + for (int i0 = 0; i0 < fNParticles_; i0++) { + fPt_rel_.get()[i0] = 0; + fPt_.get()[i0] = 0; + fDEta_.get()[i0] = 0; + fDPhi_.get()[i0] = 0; + fPt_log_.get()[i0] = 0; + fMass_.get()[i0] = 0; + fZ0_.get()[i0] = 0; + fDxy_.get()[i0] = 0; + fIs_filled_.get()[i0] = 0; + fPuppi_weight_.get()[i0] = 0; + fEmID_.get()[i0] = 0; + fQuality_.get()[i0] = 0; + + fId_.get()[i0] = 0; + fCharge_.get()[i0] = 0; + } + auto iParts = iJet.constituents(); + std::sort(iParts.begin(), iParts.end(), [](edm::Ptr i, edm::Ptr j) { + return (i->pt() > j->pt()); + }); + + l1ct::Jet ctJet = l1ct::Jet::unpack(iJet.getHWJetCT()); + float jet_pt_ = ctJet.floatPt(); + float jet_eta_ = ctJet.floatEta(); + float jet_phi_ = ctJet.floatPhi(); + + for (unsigned int i0 = 0; i0 < iParts.size(); i0++) { + if (i0 >= (unsigned int)fNParticles_) + break; + fPt_.get()[i0] = iParts[i0]->pt(); + fZ0_.get()[i0] = iParts[i0]->z0(); + fPt_rel_.get()[i0] = iParts[i0]->pt() / jet_pt_; + fPt_log_.get()[i0] = std::log(iParts[i0]->pt()); + fDEta_.get()[i0] = jet_eta_ - float(iParts[i0]->eta()); + + if (1 < iParts[i0]->phi() - jet_phi_) { + fDPhi_.get()[i0] = 1; + } else if (-1 > iParts[i0]->phi() - jet_phi_) { + fDPhi_.get()[i0] = -1; + } else { + fDPhi_.get()[i0] = iParts[i0]->phi() - jet_phi_; + } + + fIs_filled_.get()[i0] = 1; + + float massCand = 0.13f; + if (abs(iParts[i0]->charge())) { + if ((iParts[i0]->id() == l1t::PFCandidate::Muon)) { + massCand = 0.105; + } else if ((iParts[i0]->id() == l1t::PFCandidate::Electron)) { + massCand = 0.005; + } + } else { + massCand = iParts[i0]->id() == l1t::PFCandidate::Photon ? 0.0 : 0.5; + } + + fMass_.get()[i0] = massCand; + fPuppi_weight_.get()[i0] = iParts[i0]->puppiWeight(); + fId_.get()[i0] = iParts[i0]->id(); + fCharge_.get()[i0] = iParts[i0]->charge(); + + fDxy_.get()[i0] = iParts[i0]->hwDxy(); + fEmID_.get()[i0] = iParts[i0]->hwEmID(); + fQuality_.get()[i0] = iParts[i0]->hwTkQuality(); + } + setNNVectorVar(); + return EvaluateNNFixed(); +} From 5460307b4e5fb41ea6cee251e6ebefafad0b9e4c Mon Sep 17 00:00:00 2001 From: Gianluca Date: Thu, 30 Apr 2026 16:10:05 +0200 Subject: [PATCH 2/9] TM18 is now the default configuration for all serenity modules fix elliptic config --- .../python/l1ctLayer1_cff.py | 26 ++-- .../python/l1ctLayer2EG_cff.py | 104 ++----------- .../test/make_l1ct_binaryFiles_cfg.py | 147 ++++++------------ 3 files changed, 71 insertions(+), 206 deletions(-) diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py index 508810eddf4b9..b36e6557d2cd7 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py @@ -213,13 +213,10 @@ emulateCorrections = cms.bool(False), # NOTE: should switch this on for FW bit-wise agreement! emInterpScenario = cms.string("allKeepHad"), # for all clusters, use EM intepretation to redefine the EM part of the energy ), - regionizerAlgo = cms.string("Multififo"), + regionizerAlgo = cms.string("BufferedFoldedMultififo"), regionizerAlgoParameters = cms.PSet( useAlsoVtxCoords = cms.bool(True), - nEndcaps = cms.uint32(2), - nClocks = cms.uint32(54), - nTkLinks = cms.uint32(2), - nCaloLinks = cms.uint32(3), + nClocks = cms.uint32(162), nTrack = cms.uint32(30), nCalo = cms.uint32(20), nEmCalo = cms.uint32(10), @@ -319,6 +316,13 @@ l1tLayer1HGCalExtended = l1tLayer1HGCal.clone(tracks = ('l1tPFTracksFromL1TracksExtended')) + +l1tLayer1BarrelElliptic = l1tLayer1Barrel.clone( + tkEgAlgoParameters = l1tLayer1Barrel.tkEgAlgoParameters.clone( + algorithm = 0, + trkQualityPtMin = 10.) +) + l1tLayer1HGCalElliptic = l1tLayer1HGCal.clone( tkEgAlgoParameters = l1tLayer1HGCal.tkEgAlgoParameters.clone( algorithm = 0, @@ -365,13 +369,10 @@ emulateCorrections = cms.bool(False), # NOTE: should switch this on for FW bit-wise agreement! emInterpScenario = cms.string("allKeepHad"), # for all clusters, use EM intepretation to redefine the EM part of the energy ), - regionizerAlgo = cms.string("Multififo"), + regionizerAlgo = cms.string("BufferedFoldedMultififo"), regionizerAlgoParameters = cms.PSet( useAlsoVtxCoords = cms.bool(True), - nEndcaps = cms.uint32(2), - nClocks = cms.uint32(54), - nTkLinks = cms.uint32(0), - nCaloLinks = cms.uint32(3), + nClocks = cms.uint32(162), nTrack = cms.uint32(0), nCalo = cms.uint32(12), nEmCalo = cms.uint32(12), @@ -590,7 +591,7 @@ cms.PSet( instance = cms.string("L1TkEleEB"), pfProducers = cms.VInputTag( - cms.InputTag("l1tLayer1Barrel", 'L1TkEle') + cms.InputTag("l1tLayer1BarrelElliptic", 'L1TkEle') ) ) ), @@ -605,7 +606,7 @@ cms.PSet( instance = cms.string("L1TkEmEB"), pfProducers = cms.VInputTag( - cms.InputTag("l1tLayer1Barrel", 'L1TkEm') + cms.InputTag("l1tLayer1BarrelElliptic", 'L1TkEm') ) ) ), @@ -639,6 +640,7 @@ l1tLayer1HF, l1tLayer1, l1tLayer1Extended, + l1tLayer1BarrelElliptic, l1tLayer1HGCalElliptic, l1tLayer1EG, l1tLayer1EGElliptic diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py index 11a874344a1ee..f8ac89ffa96ed 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py @@ -73,54 +73,32 @@ inPatternFile=cms.PSet( nFramesPerBX=cms.uint32(9), # 360 MHz clock or 25 Gb/s link format=cms.string("EMPv2"), - outputFilename=cms.string("L1TCTL2EG_InPattern"), + outputFilename=cms.string("L1TCTL2EG_TMUX18_InPattern"), outputFileExtension=cms.string("txt.gz"), TMUX=cms.uint32(6), maxLinesPerFile=cms.uint32(1024), eventsPerFile=cms.uint32(12), channels=cms.VPSet( cms.PSet( - TMUX=cms.uint32(6), - nWords=cms.uint32(48), # = 16*2words ele + 16words photons + TMUX=cms.uint32(18), + nWords=cms.uint32(156), # = (16*2words ele + 16words photons) * 3 (regions) every 6 BX (54 words) = 48+6(empty)+48+6(empty)+48 = 156 interface=cms.string("eglayer1Barrel"), id=cms.uint32(0), - channels=cms.vuint32(0) - ), - cms.PSet( - TMUX=cms.uint32(6), - nWords=cms.uint32(48), - interface=cms.string("eglayer1Barrel"), - id=cms.uint32(1), - channels=cms.vuint32(1) + channels=cms.vuint32(0,2,4) ), cms.PSet( - TMUX=cms.uint32(6), - nWords=cms.uint32(48), - interface=cms.string("eglayer1Barrel"), - id=cms.uint32(2), - channels=cms.vuint32(2) - ), - cms.PSet( - TMUX=cms.uint32(6), - nWords=cms.uint32(48), + TMUX=cms.uint32(18), + nWords=cms.uint32(129), # (16*2words ele + 16words photons) * 2 (regions) every 9 BX (81 words) = 48+33(empty)+48 interface=cms.string("eglayer1Endcap"), - id=cms.uint32(3), - channels=cms.vuint32(3) - ), - cms.PSet( - TMUX=cms.uint32(6), - nWords=cms.uint32(48), - interface=cms.string("eglayer1Endcap"), - id=cms.uint32(4), - channels=cms.vuint32(4) + id=cms.uint32(1), + channels=cms.vuint32(1,3,5) ), - ) ), outPatternFile=cms.PSet( nFramesPerBX=cms.uint32(9), # 360 MHz clock or 25 Gb/s link format=cms.string("EMPv2"), - outputFilename=cms.string("L1TCTL2EG_OutPattern"), + outputFilename=cms.string("L1TCTL2EG_TMUX18_OutPattern"), outputFileExtension=cms.string("txt.gz"), TMUX=cms.uint32(6), maxLinesPerFile=cms.uint32(1024), @@ -162,7 +140,7 @@ regions=cms.vint32(3, 4) ), cms.PSet( - pfProducer=cms.InputTag("l1tLayer1Barrel", 'L1TkElePerBoard'), + pfProducer=cms.InputTag("l1tLayer1BarrelElliptic", 'L1TkElePerBoard'), regions=cms.vint32(0, 1, 2) ), ), @@ -176,7 +154,7 @@ regions=cms.vint32(-1) ), cms.PSet( - pfProducer=cms.InputTag("l1tLayer1Barrel", 'L1TkEmPerBoard'), + pfProducer=cms.InputTag("l1tLayer1BarrelElliptic", 'L1TkEmPerBoard'), regions=cms.vint32(0, 1, 2) ), ), @@ -192,66 +170,6 @@ ), ) -# EG Layer2 with Layer1 @ TMUX18 -l1tLayer2EGTM18 = l1tLayer2EG.clone( - tkElectrons=cms.VPSet( - cms.PSet( - pfProducer=cms.InputTag("l1tLayer1HGCalTM18", 'L1TkElePerBoard'), - regions=cms.vint32(3, 4) - ), - cms.PSet( - pfProducer=cms.InputTag("l1tLayer1BarrelSerenityTM18", 'L1TkElePerBoard'), - regions=cms.vint32(0, 1, 2) - ), - ), - tkEms=cms.VPSet( - cms.PSet( - pfProducer=cms.InputTag("l1tLayer1HGCalTM18", 'L1TkEmPerBoard'), - regions=cms.vint32(3, 4) - ), - cms.PSet( - pfProducer=cms.InputTag("l1tLayer1HGCalNoTKTM18", 'L1TkEmPerBoard'), - regions=cms.vint32(-1) - ), - cms.PSet( - pfProducer=cms.InputTag("l1tLayer1BarrelSerenityTM18", 'L1TkEmPerBoard'), - regions=cms.vint32(0, 1, 2) - ), - ), - tkEgs=cms.VPSet( - cms.PSet( - pfProducer=cms.InputTag("l1tLayer1HGCalTM18", 'L1Eg'), - regions=cms.vint32(-1) - ), - cms.PSet( - pfProducer=cms.InputTag("l1tLayer1HGCalNoTKTM18", 'L1Eg'), - regions=cms.vint32(-1) - ), - ), -) - -l1tLayer2EGTM18.inPatternFile.outputFilename = "L1TCTL2EG_TMUX18_InPattern" -l1tLayer2EGTM18.inPatternFile.channels = cms.VPSet( - cms.PSet( - TMUX=cms.uint32(18), - nWords=cms.uint32(156), # = (16*2words ele + 16words photons) * 3 (regions) every 6 BX (54 words) = 48+6(empty)+48+6(empty)+48 = 156 - interface=cms.string("eglayer1Barrel"), - id=cms.uint32(0), - channels=cms.vuint32(0,2,4) - ), - cms.PSet( - TMUX=cms.uint32(18), - nWords=cms.uint32(129), # (16*2words ele + 16words photons) * 2 (regions) every 9 BX (81 words) = 48+33(empty)+48 - interface=cms.string("eglayer1Endcap"), - id=cms.uint32(1), - channels=cms.vuint32(1,3,5) - ), -) -l1tLayer2EGTM18.outPatternFile.outputFilename = 'L1TCTL2EG_TMUX18_OutPattern' -# FIXME: we need to schedule a new deregionizer for TM18 -# l1tLayer2EGTM18.l1PFObjects = cms.InputTag("l1tLayer2Deregionizer", "Puppi"), - - L1TLayer2EGTask = cms.Task( l1tLayer2Deregionizer, l1tLayer2EG, diff --git a/L1Trigger/Phase2L1ParticleFlow/test/make_l1ct_binaryFiles_cfg.py b/L1Trigger/Phase2L1ParticleFlow/test/make_l1ct_binaryFiles_cfg.py index 96690c4ae3ef9..9aa36e60eac27 100644 --- a/L1Trigger/Phase2L1ParticleFlow/test/make_l1ct_binaryFiles_cfg.py +++ b/L1Trigger/Phase2L1ParticleFlow/test/make_l1ct_binaryFiles_cfg.py @@ -10,11 +10,14 @@ parser.add_argument("--dumpFilesOFF", help="switch on dump file production", action="store_true", default=False) parser.add_argument("--patternFilesOFF", help="switch on Layer-1 pattern file production", action="store_true", default=False) parser.add_argument("--serenity", help="use Serenity settigns as default everwhere, i.e. also for barrel", action="store_true", default=False) -parser.add_argument("--tm18", help="Add TM18 emulators", action="store_true", default=False) +parser.add_argument("--tm18", help="[DEPRECATED] Add TM18 emulators", action="store_true", default=False) parser.add_argument("--split18", help="Make 3 TM18 layer 1 pattern files", action="store_true", default=False) args = parser.parse_args() +if args.tm18: + print('[WARNING] CTL1@TM18 is now the default: --tm18 option is deprecated') + if args.dumpFilesOFF: print(f'Switching off dump file creation: dumpFilesOFF is {args.dumpFilesOFF}') if args.patternFilesOFF: @@ -144,17 +147,14 @@ ) process.l1tLayer1BarrelSerenity = process.l1tLayer1Barrel.clone() -process.l1tLayer1BarrelSerenity.regionizerAlgo = "MultififoBarrel" +process.l1tLayer1BarrelSerenity.regionizerAlgo = "MiddleBufferMultififo" process.l1tLayer1BarrelSerenity.regionizerAlgoParameters = cms.PSet( - barrelSetup = cms.string("Full54"), - useAlsoVtxCoords = cms.bool(True), - nClocks = cms.uint32(54), - nHCalLinks = cms.uint32(2), - nECalLinks = cms.uint32(1), nTrack = cms.uint32(22), nCalo = cms.uint32(15), nEmCalo = cms.uint32(12), - nMu = cms.uint32(2)) + nMu = cms.uint32(2), + tmux6GCTinput = cms.bool(True), +) process.l1tLayer1BarrelSerenity.pfAlgoParameters.nTrack = 22 process.l1tLayer1BarrelSerenity.pfAlgoParameters.nSelCalo = 15 process.l1tLayer1BarrelSerenity.pfAlgoParameters.nCalo = 15 @@ -169,18 +169,15 @@ phiSlices = cms.uint32(3), phiZero = cms.double(math.pi/18) ), - cms.PSet( - etaBoundaries = cms.vdouble(-1.5, 0, 1.5), - phiSlices = cms.uint32(3), - phiZero = cms.double(math.pi*7/18) - ) - ) -# process.l1tLayer1BarrelSerenity.caloSectors = cms.VPSet( -# cms.PSet( -# etaBoundaries = cms.vdouble(-1.5, 1.5), -# phiSlices = cms.uint32(3), -# ) -# ) +) +process.l1tLayer1BarrelSerenity.boards = cms.VPSet(*[cms.PSet(regions = cms.vuint32(*range(18*i,18*i+18))) for i in range(3)]) +process.l1tLayer1BarrelSerenityElliptic = process.l1tLayer1BarrelSerenity.clone( + tkEgAlgoParameters = process.l1tLayer1BarrelSerenity.tkEgAlgoParameters.clone( + algorithm = 0, + trkQualityPtMin = 10.) +) + + if args.serenity: process.l1tLayer1.pfProducers[0] = "l1tLayer1BarrelSerenity" @@ -196,10 +193,12 @@ *barrelWriterDebugPFInConfigsAPx, *barrelWriterDebugPFOutConfigsAPx ) - process.l1tLayer1BarrelSerenity.patternWriters = cms.untracked.VPSet(barrelSerenityVU9PPhi1Config,barrelSerenityVU13PPhi1Config) - process.l1tLayer1HGCal.patternWriters = cms.untracked.VPSet(*hgcalWriterConfigs) - process.l1tLayer1HGCalElliptic.patternWriters = cms.untracked.VPSet(*hgcalWriterConfigs) - process.l1tLayer1HGCalNoTK.patternWriters = cms.untracked.VPSet(*hgcalNoTKWriterConfigs) + process.l1tLayer1BarrelSerenity.patternWriters = cms.untracked.VPSet(*barrelSerenityTM18WriterConfigs) + process.l1tLayer1BarrelSerenityElliptic.patternWriters = cms.untracked.VPSet(*barrelSerenityTM18WriterConfigs) + + process.l1tLayer1HGCal.patternWriters = cms.untracked.VPSet(*hgcalTM18WriterConfigs) + process.l1tLayer1HGCalElliptic.patternWriters = cms.untracked.VPSet(*hgcalTM18WriterConfigs) + process.l1tLayer1HGCalNoTK.patternWriters = cms.untracked.VPSet(hgcalNoTKOutputTM18WriterConfig) process.l1tLayer1HF.patternWriters = cms.untracked.VPSet(*hfWriterConfigs) process.l1tSC4NGJetProducer.jets = cms.InputTag("l1tSC4PFL1PuppiEmulator") @@ -221,6 +220,7 @@ process.l1tLayer1Barrel + process.l1tLayer1BarrelTDR + process.l1tLayer1BarrelSerenity + + process.l1tLayer1BarrelSerenityElliptic + process.l1tLayer1HGCal + process.l1tLayer1HGCalElliptic + process.l1tLayer1HGCalNoTK + @@ -259,7 +259,7 @@ process.runPF.insert(process.runPF.index(process.l1tLayer2SeedConeJetWriter)+1, process.l1tLayer2SeedConeNGJetWriter) process.l1tLayer2SeedConeNGJetWriter.maxLinesPerFile = _eventsPerFile*54 if not args.dumpFilesOFF: - for det in "Barrel", "BarrelTDR", "BarrelSerenity", "HGCal", "HGCalElliptic", "HGCalNoTK", "HF": + for det in "Barrel", "BarrelTDR", "BarrelSerenity", "BarrelSerenityElliptic", "HGCal", "HGCalElliptic", "HGCalNoTK", "HF": l1pf = getattr(process, 'l1tLayer1'+det) l1pf.dumpFileName = cms.untracked.string("TTbar_PU200_"+det+".dump") for det in "Barrel", "HGCal": @@ -267,81 +267,26 @@ l1pf.dumpFileName = cms.untracked.string("TTbar_PU200_"+det+"Extended.dump") -if args.tm18: - process.l1tLayer1HGCalTM18 = process.l1tLayer1HGCal.clone() - process.l1tLayer1HGCalTM18.regionizerAlgo = "BufferedFoldedMultififo" - process.l1tLayer1HGCalTM18.regionizerAlgoParameters.nClocks = 162 - process.l1tLayer1HGCalTM18.hgcalInputConversionParameters.emulateCorrections = True - del process.l1tLayer1HGCalTM18.regionizerAlgoParameters.nEndcaps - del process.l1tLayer1HGCalTM18.regionizerAlgoParameters.nTkLinks - del process.l1tLayer1HGCalTM18.regionizerAlgoParameters.nCaloLinks - process.l1tLayer1HGCalNoTKTM18 = process.l1tLayer1HGCalNoTK.clone() - process.l1tLayer1HGCalNoTKTM18.regionizerAlgo = "BufferedFoldedMultififo" - process.l1tLayer1HGCalNoTKTM18.regionizerAlgoParameters.nClocks = 162 - process.l1tLayer1HGCalNoTKTM18.hgcalInputConversionParameters.emulateCorrections = True - del process.l1tLayer1HGCalNoTKTM18.regionizerAlgoParameters.nEndcaps - del process.l1tLayer1HGCalNoTKTM18.regionizerAlgoParameters.nTkLinks - del process.l1tLayer1HGCalNoTKTM18.regionizerAlgoParameters.nCaloLinks - process.l1tLayer1BarrelSerenityTM18 = process.l1tLayer1BarrelSerenity.clone() - process.l1tLayer1BarrelSerenityTM18.caloSectors = cms.VPSet( - cms.PSet( - etaBoundaries = cms.vdouble(-1.5, 0, 1.5), - phiSlices = cms.uint32(3), - phiZero = cms.double(math.pi/18) - ), - ) - process.l1tLayer1BarrelSerenityTM18.regionizerAlgo = "MiddleBufferMultififo" - process.l1tLayer1BarrelSerenityTM18.regionizerAlgoParameters = cms.PSet( - nTrack = process.l1tLayer1BarrelSerenity.regionizerAlgoParameters.nTrack, - nCalo = process.l1tLayer1BarrelSerenity.regionizerAlgoParameters.nCalo, - nEmCalo = process.l1tLayer1BarrelSerenity.regionizerAlgoParameters.nEmCalo, - nMu = process.l1tLayer1BarrelSerenity.regionizerAlgoParameters.nMu, - tmux6GCTinput = cms.bool(True), - ) - process.l1tLayer1BarrelSerenityTM18.boards = cms.VPSet(*[cms.PSet(regions = cms.vuint32(*range(18*i,18*i+18))) for i in range(3)]) - - process.l1tLayer1BarrelSerenityEllipticTM18 = process.l1tLayer1BarrelSerenityTM18.clone( - tkEgAlgoParameters = process.l1tLayer1BarrelSerenityTM18.tkEgAlgoParameters.clone( - algorithm = 0, - trkQualityPtMin = 10.) - ) - - process.runPF.insert(process.runPF.index(process.l1tLayer1HGCal)+1, process.l1tLayer1HGCalTM18) - process.runPF.insert(process.runPF.index(process.l1tLayer1HGCalNoTK)+1, process.l1tLayer1HGCalNoTKTM18) - process.runPF.insert(process.runPF.index(process.l1tLayer1BarrelSerenity)+1, process.l1tLayer1BarrelSerenityTM18) - process.runPF.insert(process.runPF.index(process.l1tLayer1BarrelSerenity)+1, process.l1tLayer1BarrelSerenityEllipticTM18) - # FIXME: we need to schedule a new deregionizer for TM18 - process.runPF.insert(process.runPF.index(process.l1tLayer2EG)+1, process.l1tLayer2EGTM18) - if not args.patternFilesOFF: - process.l1tLayer1HGCalTM18.patternWriters = cms.untracked.VPSet(*hgcalTM18WriterConfigs) - process.l1tLayer1HGCalNoTKTM18.patternWriters = cms.untracked.VPSet(hgcalNoTKOutputTM18WriterConfig) - process.l1tLayer1BarrelSerenityTM18.patternWriters = cms.untracked.VPSet(*barrelSerenityTM18WriterConfigs) - process.l1tLayer1BarrelSerenityEllipticTM18.patternWriters = cms.untracked.VPSet(*barrelSerenityTM18WriterConfigs) - process.l1tLayer2EGTM18.writeInPattern = True - process.l1tLayer2EGTM18.writeOutPattern = True - if not args.dumpFilesOFF: - for det in "HGCalTM18", "HGCalNoTKTM18", "BarrelSerenityTM18", "BarrelSerenityEllipticTM18": - getattr(process, 'l1tLayer1'+det).dumpFileName = cms.untracked.string("TTbar_PU200_"+det+".dump") - if args.split18 and not args.patternFilesOFF: - from FWCore.Modules.preScaler_cfi import preScaler - for tmSlice, psOffset in (0,1), (6,2), (12,0): - setattr(process, f"preTM{tmSlice}", preScaler.clone(prescaleFactor = 3, prescaleOffset = psOffset)) - for det in "HGCalTM18", "HGCalNoTKTM18", "BarrelSerenityTM18": - tsmod = getattr(process, 'l1tLayer1'+det).clone() - tsmod.dumpFileName = cms.untracked.string("") - setattr(process, f"l1tLayer1{det}TS{tmSlice}", tsmod) - setattr(process, f"Write_{det}TS{tmSlice}", cms.Path(getattr(process, f"preTM{tmSlice}")+tsmod)) - getattr(process, f'l1tLayer1HGCalTM18TS{tmSlice}').patternWriters = cms.untracked.VPSet( - hgcalWriterOutputTM18WriterConfig.clone(outputFileName = f"l1HGCalTM18-outputs-ts{tmSlice}"), - hgcalWriterVU9PTM18WriterConfig.clone(inputFileName = f"l1HGCalTM18-inputs-vu9p-ts{tmSlice}"), - hgcalWriterVU13PTM18WriterConfig.clone(inputFileName = f"l1HGCalTM18-inputs-vu13p-ts{tmSlice}") - ) - getattr(process, f'l1tLayer1HGCalNoTKTM18TS{tmSlice}').patternWriters = cms.untracked.VPSet( - hgcalNoTKOutputTM18WriterConfig.clone(outputFileName = f"l1HGCalTM18-outputs-ts{tmSlice}"), - ) - getattr(process, f'l1tLayer1BarrelSerenityTM18TS{tmSlice}').patternWriters = cms.untracked.VPSet( - barrelSerenityOutputTM18WriterConfig.clone(outputFileName = f"l1BarrelSerenityTM18-outputs-ts{tmSlice}"), - barrelSerenityVU13PTM18WriterConfig.clone(inputFileName = f"l1BarrelSerenityTM18-inputs-vu13p-ts{tmSlice}") - ) +if args.split18 and not args.patternFilesOFF: + from FWCore.Modules.preScaler_cfi import preScaler + for tmSlice, psOffset in (0,1), (6,2), (12,0): + setattr(process, f"preTM{tmSlice}", preScaler.clone(prescaleFactor = 3, prescaleOffset = psOffset)) + for det in "HGCal", "HGCalNoTK", "BarrelSerenity": + tsmod = getattr(process, 'l1tLayer1'+det).clone() + tsmod.dumpFileName = cms.untracked.string("") + setattr(process, f"l1tLayer1{det}TS{tmSlice}", tsmod) + setattr(process, f"Write_{det}TS{tmSlice}", cms.Path(getattr(process, f"preTM{tmSlice}")+tsmod)) + getattr(process, f'l1tLayer1HGCalTS{tmSlice}').patternWriters = cms.untracked.VPSet( + hgcalWriterOutputTM18WriterConfig.clone(outputFileName = f"l1HGCalTM18-outputs-ts{tmSlice}"), + hgcalWriterVU9PTM18WriterConfig.clone(inputFileName = f"l1HGCalTM18-inputs-vu9p-ts{tmSlice}"), + hgcalWriterVU13PTM18WriterConfig.clone(inputFileName = f"l1HGCalTM18-inputs-vu13p-ts{tmSlice}") + ) + getattr(process, f'l1tLayer1HGCalNoTKTS{tmSlice}').patternWriters = cms.untracked.VPSet( + hgcalNoTKOutputTM18WriterConfig.clone(outputFileName = f"l1HGCalTM18-outputs-ts{tmSlice}"), + ) + getattr(process, f'l1tLayer1BarrelSerenityTS{tmSlice}').patternWriters = cms.untracked.VPSet( + barrelSerenityOutputTM18WriterConfig.clone(outputFileName = f"l1BarrelSerenityTM18-outputs-ts{tmSlice}"), + barrelSerenityVU13PTM18WriterConfig.clone(inputFileName = f"l1BarrelSerenityTM18-inputs-vu13p-ts{tmSlice}") + ) process.source.fileNames = [ '/store/cmst3/group/l1tr/FastPUPPI/14_2_X/fpinputs_140X/v0/TT_PU200/inputs140X_1.root' ] From 372f2744dba155fb19a47eda298c716790ac2442 Mon Sep 17 00:00:00 2001 From: Emyr Clement Date: Fri, 15 May 2026 14:23:25 +0000 Subject: [PATCH 3/9] Try to accurately emulate truncation/rounding of sqrt. --- .../interface/jetmet/L1PFHtEmulator.h | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/jetmet/L1PFHtEmulator.h b/L1Trigger/Phase2L1ParticleFlow/interface/jetmet/L1PFHtEmulator.h index 68e575e491cfa..b4e88ecd4b858 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/jetmet/L1PFHtEmulator.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/jetmet/L1PFHtEmulator.h @@ -23,6 +23,8 @@ namespace P2L1HTMHTEmu { typedef ap_fixed<12, 3> radians_t; typedef ap_fixed<9, 2> cossin_t; typedef ap_fixed<16, 13> pxy_t; + static constexpr int Fin = 6; // Number of decimal bits/precision of met squared i.e. 2*16 - 2*13 + static constexpr int Fout = pt_t::width - pt_t::iwidth; // Number of decimal bits/precision of output met static constexpr int N_TABLE = 2048; @@ -49,7 +51,7 @@ namespace P2L1HTMHTEmu { template void init_sinphi_table(table_T table_out[N]) { for (int i = 0; i < N; i++) { - float x = i * (M_PI / 180.) / 2.; + double x = i * (M_PI / 180.) / 2.; table_T sin_x = std::sin(x); table_out[i] = sin_x; } @@ -118,12 +120,17 @@ inline l1ct::Sum htmht(std::vector jets) { // Compute the MHT magnitude and direction l1ct::Sum ht; ht.hwSumPt = hthxhy.pt; -#ifdef CMSSW_GIT_HASH - ht.hwPt = - sqrt(((hthxhy.px * hthxhy.px) + (hthxhy.py * hthxhy.py)).to_double()); // hls_math.h not available yet in CMSSW -#else - ht.hwPt = hls::sqrt(((hthxhy.px * hthxhy.px) + (hthxhy.py * hthxhy.py))); -#endif + + // this emulates the following firmware function, since hls_math.h is not available in CMSSW + // ht.hwPt = hls::sqrt(((hthxhy.px * hthxhy.px) + (hthxhy.py * hthxhy.py))); + double d = std::sqrt(((hthxhy.px * hthxhy.px) + (hthxhy.py * hthxhy.py)).to_double()); + // emulate hls::sqrt internal rounding + double rounded = std::round(d * (1 << P2L1HTMHTEmu::Fin)) / (1 << P2L1HTMHTEmu::Fin); + // emulate AP_TRN conversion to output type + double truncated = std::floor(rounded * (1 << P2L1HTMHTEmu::Fout)) / (1 << P2L1HTMHTEmu::Fout); + P2L1HTMHTEmu::pt_t hwPt_hls = truncated; + ht.hwPt = hwPt_hls; + ht.hwPhi = P2L1HTMHTEmu::phi_cordic(hthxhy.py, hthxhy.px); return ht; } From d4a41d7e110739e018786453d42a707700e65f06 Mon Sep 17 00:00:00 2001 From: Christopher Date: Tue, 5 May 2026 18:20:46 +0200 Subject: [PATCH 4/9] NN Vtx association emulator --- .../L1TParticleFlow/interface/PFCandidate.h | 5 +- .../L1TParticleFlow/interface/datatypes.h | 1 + .../interface/layer1_emulator.h | 6 + .../L1TParticleFlow/src/classes_def.xml | 4 +- .../interface/NNVtxAssoc.h | 194 +++++++++++++++++- .../interface/puppi/linpuppi_ref.h | 49 ++--- .../plugins/L1TCorrelatorLayer1Producer.cc | 3 + .../python/l1ctLayer1_cff.py | 1 - .../python/mlAssociation_cfi.py | 5 +- .../Phase2L1ParticleFlow/src/NNVtxAssoc.cc | 147 ++++++++----- .../src/puppi/linpuppi_ref.cpp | 171 ++++++++------- .../test/make_l1ct_binaryFiles_cfg.py | 13 +- 12 files changed, 413 insertions(+), 186 deletions(-) diff --git a/DataFormats/L1TParticleFlow/interface/PFCandidate.h b/DataFormats/L1TParticleFlow/interface/PFCandidate.h index ff6e026acdfa3..b029ca99c3abd 100644 --- a/DataFormats/L1TParticleFlow/interface/PFCandidate.h +++ b/DataFormats/L1TParticleFlow/interface/PFCandidate.h @@ -62,6 +62,9 @@ namespace l1t { uint16_t hwEmID() const { return hwEmID_; } uint64_t encodedPuppi64() const { return encodedPuppi64_; } + float hwAssociationScore() const { return hwAssociationScore_; } + void setHwAssociationScore(float score) { hwAssociationScore_ = score; } + void setHwZ0(int16_t hwZ0) { hwZ0_ = hwZ0; } void setHwDxy(int16_t hwDxy) { hwDxy_ = hwDxy; } void setHwTkQuality(uint16_t hwTkQuality) { hwTkQuality_ = hwTkQuality; } @@ -73,7 +76,7 @@ namespace l1t { L1CandPtr caloPtr_; PFTrackRef trackRef_; MuonRef muonRef_; - float dxy_, puppiWeight_, caloEta_, caloPhi_; + float dxy_, puppiWeight_, caloEta_, caloPhi_, hwAssociationScore_; int16_t hwZ0_, hwDxy_; uint16_t hwTkQuality_, hwPuppiWeight_, hwEmID_; diff --git a/DataFormats/L1TParticleFlow/interface/datatypes.h b/DataFormats/L1TParticleFlow/interface/datatypes.h index da8d053b04a86..88f09a5dcf663 100644 --- a/DataFormats/L1TParticleFlow/interface/datatypes.h +++ b/DataFormats/L1TParticleFlow/interface/datatypes.h @@ -22,6 +22,7 @@ namespace l1ct { typedef ap_int<10> z0_t; // 40cm / 0.1 typedef ap_uint<8> dxy_t; // sqrt(32)cm / 0.004 packed into 8 bit for l1ct typedef ap_uint<3> tkquality_t; // tbd + typedef ap_fixed<16, 6> nn_assoc_t; typedef ap_ufixed<9, 1, AP_RND_CONV, AP_WRAP> puppiWgt_t; typedef ap_uint<6> emid_t; typedef ap_uint<14> tk2em_dr_t; diff --git a/DataFormats/L1TParticleFlow/interface/layer1_emulator.h b/DataFormats/L1TParticleFlow/interface/layer1_emulator.h index 22ae2df1758a9..a3967e318122b 100644 --- a/DataFormats/L1TParticleFlow/interface/layer1_emulator.h +++ b/DataFormats/L1TParticleFlow/interface/layer1_emulator.h @@ -126,6 +126,10 @@ namespace l1ct { const l1t::PFTrack *srcTrack = nullptr; const l1t::SAMuon *srcMu = nullptr; const l1t::PFCandidate *srcCand = nullptr; + + float AssociationScore; + int Association; + bool read(std::fstream &from); bool write(std::fstream &to) const; void clear() { @@ -134,6 +138,8 @@ namespace l1ct { srcTrack = nullptr; srcMu = nullptr; srcCand = nullptr; + AssociationScore = 0; + Association = 0; } inline void fill(const PFRegionEmu ®ion, const PFChargedObjEmu &src) { PuppiObj::fill(region, src); diff --git a/DataFormats/L1TParticleFlow/src/classes_def.xml b/DataFormats/L1TParticleFlow/src/classes_def.xml index e45d86590aa53..326dbfeceef42 100644 --- a/DataFormats/L1TParticleFlow/src/classes_def.xml +++ b/DataFormats/L1TParticleFlow/src/classes_def.xml @@ -23,7 +23,9 @@ - + + + diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/NNVtxAssoc.h b/L1Trigger/Phase2L1ParticleFlow/interface/NNVtxAssoc.h index 7c92ed343ab49..0c785daf06a6b 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/NNVtxAssoc.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/NNVtxAssoc.h @@ -9,37 +9,209 @@ // Created: February 2025 #include +#include #include "DataFormats/L1TParticleFlow/interface/layer1_emulator.h" +#include "ap_fixed.h" + +struct AssociationObjEmu { + l1ct::nn_assoc_t hwAssociationScore; + ap_uint<1> hwAssociation; +}; + +typedef ap_ufixed<22, 9> nn_inputtype; +typedef ap_fixed<22, 9> classtype; + +#define N_NN_ASSOC_FEATURES 4 // How many features are used in a track +#define N_NN_ASSOC_OUTPUTS 1 // How many features are used in a track + +static const nn_inputtype associationNetworkEtaBounds[127] = {0.0, + 0.01984126984126984, + 0.03968253968253968, + 0.05952380952380952, + 0.07936507936507936, + 0.0992063492063492, + 0.11904761904761904, + 0.1388888888888889, + 0.15873015873015872, + 0.17857142857142855, + 0.1984126984126984, + 0.21825396825396826, + 0.23809523809523808, + 0.2579365079365079, + 0.2777777777777778, + 0.2976190476190476, + 0.31746031746031744, + 0.33730158730158727, + 0.3571428571428571, + 0.376984126984127, + 0.3968253968253968, + 0.41666666666666663, + 0.4365079365079365, + 0.45634920634920634, + 0.47619047619047616, + 0.496031746031746, + 0.5158730158730158, + 0.5357142857142857, + 0.5555555555555556, + 0.5753968253968254, + 0.5952380952380952, + 0.615079365079365, + 0.6349206349206349, + 0.6547619047619048, + 0.6746031746031745, + 0.6944444444444444, + 0.7142857142857142, + 0.7341269841269841, + 0.753968253968254, + 0.7738095238095237, + 0.7936507936507936, + 0.8134920634920635, + 0.8333333333333333, + 0.8531746031746031, + 0.873015873015873, + 0.8928571428571428, + 0.9126984126984127, + 0.9325396825396824, + 0.9523809523809523, + 0.9722222222222222, + 0.992063492063492, + 1.0119047619047619, + 1.0317460317460316, + 1.0515873015873016, + 1.0714285714285714, + 1.0912698412698412, + 1.1111111111111112, + 1.130952380952381, + 1.1507936507936507, + 1.1706349206349205, + 1.1904761904761905, + 1.2103174603174602, + 1.23015873015873, + 1.25, + 1.2698412698412698, + 1.2896825396825395, + 1.3095238095238095, + 1.3293650793650793, + 1.349206349206349, + 1.369047619047619, + 1.3888888888888888, + 1.4087301587301586, + 1.4285714285714284, + 1.4484126984126984, + 1.4682539682539681, + 1.488095238095238, + 1.507936507936508, + 1.5277777777777777, + 1.5476190476190474, + 1.5674603174603174, + 1.5873015873015872, + 1.607142857142857, + 1.626984126984127, + 1.6468253968253967, + 1.6666666666666665, + 1.6865079365079365, + 1.7063492063492063, + 1.726190476190476, + 1.746031746031746, + 1.7658730158730158, + 1.7857142857142856, + 1.8055555555555554, + 1.8253968253968254, + 1.8452380952380951, + 1.865079365079365, + 1.8849206349206349, + 1.9047619047619047, + 1.9246031746031744, + 1.9444444444444444, + 1.9642857142857142, + 1.984126984126984, + 2.003968253968254, + 2.0238095238095237, + 2.0436507936507935, + 2.0634920634920633, + 2.083333333333333, + 2.1031746031746033, + 2.123015873015873, + 2.142857142857143, + 2.1626984126984126, + 2.1825396825396823, + 2.202380952380952, + 2.2222222222222223, + 2.242063492063492, + 2.261904761904762, + 2.2817460317460316, + 2.3015873015873014, + 2.321428571428571, + 2.341269841269841, + 2.361111111111111, + 2.380952380952381, + 2.4007936507936507, + 2.4206349206349205, + 2.4404761904761902, + 2.46031746031746, + 2.4801587301587302, + 2.5}; +static const nn_inputtype associationNetworkZ0ResBins[128] = { + 127.0, 126.0, 126.0, 126.0, 125.0, 124.0, 123.0, 122.0, 120.0, 119.0, 117.0, 115.0, 114.0, 112.0, 110.0, 107.0, + 105.0, 103.0, 101.0, 98.0, 96.0, 94.0, 91.0, 89.0, 87.0, 85.0, 82.0, 80.0, 78.0, 76.0, 74.0, 72.0, + 70.0, 68.0, 66.0, 64.0, 62.0, 61.0, 59.0, 57.0, 56.0, 54.0, 53.0, 51.0, 50.0, 48.0, 47.0, 46.0, + 45.0, 43.0, 42.0, 41.0, 40.0, 39.0, 38.0, 37.0, 36.0, 35.0, 34.0, 33.0, 33.0, 32.0, 31.0, 30.0, + 30.0, 29.0, 28.0, 28.0, 27.0, 26.0, 26.0, 25.0, 24.0, 24.0, 23.0, 23.0, 22.0, 22.0, 21.0, 21.0, + 21.0, 20.0, 20.0, 19.0, 19.0, 18.0, 18.0, 18.0, 17.0, 17.0, 17.0, 16.0, 16.0, 16.0, 15.0, 15.0, + 15.0, 15.0, 14.0, 14.0, 14.0, 14.0, 13.0, 13.0, 13.0, 13.0, 12.0, 12.0, 12.0, 12.0, 12.0, 11.0, + 11.0, 11.0, 11.0, 11.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 9.0, 9.0, 9.0, 9.0, 9.0, 0.0}; +static const l1ct::z0_t associationNetworkZ0binning[3] = {-20.46912512, 20.46912512, 0.15991504}; + +#ifdef CMSSW_GIT_HASH +//HLS4ML compiled emulator modeling +#include "hls4ml/emulator.h" namespace edm { class ParameterSet; class ParameterSetDescription; } // namespace edm -namespace tensorflow { - class Session; -} // namespace tensorflow -using namespace l1ct; class NNVtxAssoc { public: - NNVtxAssoc(std::string AssociationGraphPath, + NNVtxAssoc(const std::shared_ptr model, const double AssociationThreshold, const std::vector& AssociationNetworkZ0binning, const std::vector& AssociationNetworkEtaBounds, - const std::vector& AssociationNetworkZ0ResBins); - + const std::vector& AssociationNetworkZ0ResBins, + bool debug); void NNVtxAssocDebug(); + static edm::ParameterSetDescription getParameterSetDescription(); - template - bool TTTrackNetworkSelector(const PFRegionEmu& region, const T& t, const l1ct::PVObjEmu& v); + void TTTrackNetworkSelector(const l1ct::PFRegionEmu& region, + const l1ct::TkObjEmu& t, + const l1ct::PVObjEmu& v, + l1ct::nn_assoc_t& score); + + l1ct::nn_assoc_t getAssociationThreshold() { return associationThreshold_; } private: - tensorflow::Session* associationSesh_; - double associationThreshold_; + nn_inputtype fPt_; + nn_inputtype fMVA_; + nn_inputtype fResBin_; + nn_inputtype fDz_; + + l1ct::nn_assoc_t associationThreshold_; + std::vector z0_binning_; std::vector eta_bins_; std::vector res_bins_; + + std::shared_ptr modelRef_; + std::stringstream log_; + + bool isDebugEnabled_; }; +#else + +void EmuNetworkSelector(const l1ct::TkObj& t, const l1ct::PVObjEmu& v, l1ct::nn_assoc_t& output_score); + +#endif + #endif diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/puppi/linpuppi_ref.h b/L1Trigger/Phase2L1ParticleFlow/interface/puppi/linpuppi_ref.h index 92f6eac0ae6c0..09423c975586a 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/puppi/linpuppi_ref.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/puppi/linpuppi_ref.h @@ -14,12 +14,6 @@ namespace edm { } // namespace edm namespace l1ct { -#ifdef CMSSW_GIT_HASH - const bool withinCMSSW_ = true; -#else - const bool withinCMSSW_ = false; -#endif - class LinPuppiEmulator { public: enum class SortAlgo { Insertion, BitonicRUFL, BitonicHLS, Hybrid, FoldedHybrid, BitonicVHDL }; @@ -44,10 +38,6 @@ namespace l1ct { pt_t ptCut, bool useMLAssociation = false, const double associationThreshold = 0.0, - std::string associationGraphPath = "", - std::vector associationNetworkZ0binning = {}, - std::vector associationNetworkEtaBounds = {}, - std::vector associationNetworkZ0ResBins = {}, unsigned int nFinalSort = 0, SortAlgo finalSortAlgo = SortAlgo::Insertion) : nTrack_(nTrack), @@ -70,18 +60,11 @@ namespace l1ct { priorPh_(1, priorPh), ptCut_(1, ptCut), useMLAssociation_(useMLAssociation), + associationThreshold_(associationThreshold), nFinalSort_(nFinalSort ? nFinalSort : nOut), finalSortAlgo_(finalSortAlgo), debug_(false), - fakePuppi_(false) { - if (useMLAssociation_ and withinCMSSW_) { - nnVtxAssoc_ = std::make_unique(NNVtxAssoc(associationGraphPath, - associationThreshold, - associationNetworkZ0binning, - associationNetworkEtaBounds, - associationNetworkZ0ResBins)); - } - } + fakePuppi_(false) {} LinPuppiEmulator(unsigned int nTrack, unsigned int nIn, @@ -114,10 +97,6 @@ namespace l1ct { pt_t ptCut_1, bool useMLAssociation = false, const double associationThreshold = 0.0, - std::string associationGraphPath = "", - std::vector associationNetworkZ0binning = {}, - std::vector associationNetworkEtaBounds = {}, - std::vector associationNetworkZ0ResBins = {}, unsigned int nFinalSort = 0, SortAlgo finalSortAlgo = SortAlgo::Insertion); @@ -142,10 +121,6 @@ namespace l1ct { const std::vector &ptCut, bool useMLAssociation, const double associationThreshold, - std::string associationGraphPath, - std::vector associationNetworkZ0binning, - std::vector associationNetworkEtaBounds, - std::vector associationNetworkZ0ResBins, unsigned int nFinalSort, SortAlgo finalSortAlgo) : nTrack_(nTrack), @@ -168,6 +143,7 @@ namespace l1ct { priorPh_(priorPh), ptCut_(ptCut), useMLAssociation_(useMLAssociation), + associationThreshold_(associationThreshold), nFinalSort_(nFinalSort), finalSortAlgo_(finalSortAlgo), debug_(false), @@ -181,10 +157,12 @@ namespace l1ct { void linpuppi_chs_ref(const PFRegionEmu ®ion, const PVObjEmu &pv, const std::vector &pfch /*[nTrack]*/, - std::vector &outallch /*[nTrack]*/) const; + std::vector &outallch /*[nTrack]*/, + std::vector &association /*[nTrack]*/) const; //vtx vetor void linpuppi_chs_ref(const PFRegionEmu ®ion, const std::vector &pv /*[nVtx]*/, + std::vector &association /*[nTrack]*/, const std::vector &pfch /*[nTrack]*/, std::vector &outallch /*[nTrack]*/) const; @@ -192,6 +170,7 @@ namespace l1ct { void linpuppi_flt(const PFRegionEmu ®ion, const std::vector &track /*[nTrack]*/, const std::vector &pv /*[nVtx]*/, + std::vector &association /*[nTrack]*/, const std::vector &pfallne /*[nIn]*/, std::vector &outallne_nocut /*[nIn]*/, std::vector &outallne /*[nIn]*/, @@ -199,6 +178,7 @@ namespace l1ct { void linpuppi_ref(const PFRegionEmu ®ion, const std::vector &track /*[nTrack]*/, const std::vector &pv /*[nVtx]*/, + std::vector &association /*[nTrack]*/, const std::vector &pfallne /*[nIn]*/, std::vector &outallne_nocut /*[nIn]*/, std::vector &outallne /*[nIn]*/, @@ -206,10 +186,11 @@ namespace l1ct { void linpuppi_ref(const PFRegionEmu ®ion, const std::vector &track /*[nTrack]*/, const std::vector &pv /*[nVtx]*/, + std::vector &association /*[nTrack]*/, const std::vector &pfallne /*[nIn]*/, std::vector &outselne /*[nOut]*/) const { std::vector outallne_nocut, outallne; - linpuppi_ref(region, track, pv, pfallne, outallne_nocut, outallne, outselne); + linpuppi_ref(region, track, pv, association, pfallne, outallne_nocut, outallne, outselne); } // neutrals, forward @@ -229,6 +210,10 @@ namespace l1ct { std::vector &out, SortAlgo algo = SortAlgo::Insertion); + void linpuppi_associate_trk(const PFRegionEmu ®ion, + const std::vector &trk /*[nTrack]*/, + const std::vector &pv /*[nVtx]*/, + std::vector &association) const; // for CMSSW void run(const PFInputRegion &in, const std::vector &pvs, OutputRegion &out) const; @@ -249,7 +234,13 @@ namespace l1ct { // NNVtx Association: bool useMLAssociation_; + float associationThreshold_ = 0; + +#ifdef CMSSW_GIT_HASH // NNVtx Association: std::unique_ptr nnVtxAssoc_; + std::shared_ptr model; + hls4mlEmulator::ModelLoader loader; +#endif unsigned int nFinalSort_; // output after a full sort of charged + neutral SortAlgo finalSortAlgo_; diff --git a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc index 7f480cf5723df..b54b611885a10 100644 --- a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc +++ b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc @@ -1327,6 +1327,7 @@ std::unique_ptr L1TCorrelatorLayer1Producer::fetchPF ret->back().setHwTkQuality(p.hwTkQuality); ret->back().setCaloEta(reg.floatGlbEtaOf(p)); ret->back().setCaloPhi(reg.floatGlbPhiOf(p)); + ret->back().setHwAssociationScore(-1); // encode the PF candidate with the 64b encoding used for PUPPI l1ct::PuppiObj encodedPF; @@ -1391,9 +1392,11 @@ void L1TCorrelatorLayer1Producer::putPuppi(edm::Event &iEvent) const { coll->back().setHwZ0(p.hwZ0()); coll->back().setHwDxy(p.hwDxy()); coll->back().setHwTkQuality(p.hwTkQuality()); + coll->back().setHwAssociationScore(p.AssociationScore); } else { coll->back().setHwPuppiWeight(p.hwPuppiW()); coll->back().setHwEmID(p.hwEmID()); + coll->back().setHwAssociationScore(-1); } coll->back().setEncodedPuppi64(p.pack().to_uint64()); setRefs_(coll->back(), p); diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py index b36e6557d2cd7..471cd1addaec6 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py @@ -1,5 +1,4 @@ import FWCore.ParameterSet.Config as cms - import math from L1Trigger.Phase2L1ParticleFlow.l1tPFTracksFromL1Tracks_cfi import l1tPFTracksFromL1Tracks, l1tPFTracksFromL1TracksExtended diff --git a/L1Trigger/Phase2L1ParticleFlow/python/mlAssociation_cfi.py b/L1Trigger/Phase2L1ParticleFlow/python/mlAssociation_cfi.py index af10c2ee9fade..46d0b46a64722 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/mlAssociation_cfi.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/mlAssociation_cfi.py @@ -1,10 +1,11 @@ import FWCore.ParameterSet.Config as cms +import os from L1Trigger.VertexFinder.l1tVertexProducer_cfi import l1tVertexProducer # NNVertex Association Variables NNVtxAssociationPSet = cms.PSet( - associationThreshold = cms.double(0.1), #Association Network threshold for PV tracks - associationGraph = cms.string("L1Trigger/L1TTrackMatch/data/NNVtx_AssociationModelGraph.pb"), + associationThreshold = cms.double(-1.0), #Association Network threshold for PV tracks + associationNetworkPath = cms.string(os.environ["CMSSW_BASE"]+"/src/NNVtx/L1TNNVtx_Assoc_Model_v0"), associationNetworkZ0binning = l1tVertexProducer.VertexReconstruction.FH_HistogramParameters, #Z0 binning used for setting the input feature digitisation associationNetworkEtaBounds = cms.vdouble(0.0, 0.01984126984126984, 0.03968253968253968, 0.05952380952380952, 0.07936507936507936, 0.0992063492063492, 0.11904761904761904, 0.1388888888888889, 0.15873015873015872, 0.17857142857142855, 0.1984126984126984, 0.21825396825396826, 0.23809523809523808, 0.2579365079365079, 0.2777777777777778, 0.2976190476190476, 0.31746031746031744, 0.33730158730158727, 0.3571428571428571, 0.376984126984127, 0.3968253968253968, 0.41666666666666663, 0.4365079365079365, 0.45634920634920634, 0.47619047619047616, 0.496031746031746, 0.5158730158730158, 0.5357142857142857, 0.5555555555555556, 0.5753968253968254, 0.5952380952380952, 0.615079365079365, 0.6349206349206349, 0.6547619047619048, 0.6746031746031745, 0.6944444444444444, 0.7142857142857142, 0.7341269841269841, 0.753968253968254, 0.7738095238095237, 0.7936507936507936, 0.8134920634920635, 0.8333333333333333, 0.8531746031746031, 0.873015873015873, 0.8928571428571428, 0.9126984126984127, 0.9325396825396824, 0.9523809523809523, 0.9722222222222222, 0.992063492063492, 1.0119047619047619, 1.0317460317460316, 1.0515873015873016, 1.0714285714285714, 1.0912698412698412, 1.1111111111111112, 1.130952380952381, 1.1507936507936507, 1.1706349206349205, 1.1904761904761905, 1.2103174603174602, 1.23015873015873, 1.25, 1.2698412698412698, 1.2896825396825395, 1.3095238095238095, 1.3293650793650793, 1.349206349206349, 1.369047619047619, 1.3888888888888888, 1.4087301587301586, 1.4285714285714284, 1.4484126984126984, 1.4682539682539681, 1.488095238095238, 1.507936507936508, 1.5277777777777777, 1.5476190476190474, 1.5674603174603174, 1.5873015873015872, 1.607142857142857, 1.626984126984127, 1.6468253968253967, 1.6666666666666665, 1.6865079365079365, 1.7063492063492063, 1.726190476190476, 1.746031746031746, 1.7658730158730158, 1.7857142857142856, 1.8055555555555554, 1.8253968253968254, 1.8452380952380951, 1.865079365079365, 1.8849206349206349, 1.9047619047619047, 1.9246031746031744, 1.9444444444444444, 1.9642857142857142, 1.984126984126984, 2.003968253968254, 2.0238095238095237, 2.0436507936507935, 2.0634920634920633, 2.083333333333333, 2.1031746031746033, 2.123015873015873, 2.142857142857143, 2.1626984126984126, 2.1825396825396823, 2.202380952380952, 2.2222222222222223, 2.242063492063492, 2.261904761904762, 2.2817460317460316, 2.3015873015873014, 2.321428571428571, 2.341269841269841, 2.361111111111111, 2.380952380952381, 2.4007936507936507, 2.4206349206349205, 2.4404761904761902, 2.46031746031746, 2.4801587301587302, 2.5), #Eta bounds used to set z0 resolution input feature associationNetworkZ0ResBins = cms.vdouble(127.0, 126.0, 126.0, 126.0, 125.0, 124.0, 123.0, 122.0, 120.0, 119.0, 117.0, 115.0, 114.0, 112.0, 110.0, 107.0, 105.0, 103.0, 101.0, 98.0, 96.0, 94.0, 91.0, 89.0, 87.0, 85.0, 82.0, 80.0, 78.0, 76.0, 74.0, 72.0, 70.0, 68.0, 66.0, 64.0, 62.0, 61.0, 59.0, 57.0, 56.0, 54.0, 53.0, 51.0, 50.0, 48.0, 47.0, 46.0, 45.0, 43.0, 42.0, 41.0, 40.0, 39.0, 38.0, 37.0, 36.0, 35.0, 34.0, 33.0, 33.0, 32.0, 31.0, 30.0, 30.0, 29.0, 28.0, 28.0, 27.0, 26.0, 26.0, 25.0, 24.0, 24.0, 23.0, 23.0, 22.0, 22.0, 21.0, 21.0, 21.0, 20.0, 20.0, 19.0, 19.0, 18.0, 18.0, 18.0, 17.0, 17.0, 17.0, 16.0, 16.0, 16.0, 15.0, 15.0, 15.0, 15.0, 14.0, 14.0, 14.0, 14.0, 13.0, 13.0, 13.0, 13.0, 12.0, 12.0, 12.0, 12.0, 12.0, 11.0, 11.0, 11.0, 11.0, 11.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 9.0, 9.0, 9.0, 9.0, 9.0, 0.0), #z0 resolution input feature bins diff --git a/L1Trigger/Phase2L1ParticleFlow/src/NNVtxAssoc.cc b/L1Trigger/Phase2L1ParticleFlow/src/NNVtxAssoc.cc index 037b7a524b6d5..d44d00d974ae8 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/NNVtxAssoc.cc +++ b/L1Trigger/Phase2L1ParticleFlow/src/NNVtxAssoc.cc @@ -6,81 +6,94 @@ // Created: February 2025 #include "L1Trigger/Phase2L1ParticleFlow/interface/NNVtxAssoc.h" + +#ifdef CMSSW_GIT_HASH #include "DataFormats/L1TParticleFlow/interface/PFTrack.h" -#include "PhysicsTools/TensorFlow/interface/TensorFlow.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include #include -NNVtxAssoc::NNVtxAssoc(std::string AssociationGraphPath, +NNVtxAssoc::NNVtxAssoc(const std::shared_ptr model, const double AssociationThreshold, const std::vector& AssociationNetworkZ0binning, const std::vector& AssociationNetworkEtaBounds, - const std::vector& AssociationNetworkZ0ResBins) - : associationThreshold_(AssociationThreshold), + const std::vector& AssociationNetworkZ0ResBins, + bool debug) + : associationThreshold_((l1ct::nn_assoc_t)AssociationThreshold), z0_binning_(AssociationNetworkZ0binning), eta_bins_(AssociationNetworkEtaBounds), - res_bins_(AssociationNetworkZ0ResBins) { - tensorflow::GraphDef* associationGraph_ = tensorflow::loadGraphDef(AssociationGraphPath); - associationSesh_ = tensorflow::createSession(associationGraph_); + res_bins_(AssociationNetworkZ0ResBins), + modelRef_(model), + isDebugEnabled_(debug) { + fPt_ = 0; + fMVA_ = 0; + fResBin_ = 0; + fDz_ = 0; log_.setf(std::ios::fixed, std::ios::floatfield); log_.precision(3); } -template -bool NNVtxAssoc::TTTrackNetworkSelector(const PFRegionEmu& region, const T& t, const l1ct::PVObjEmu& v) { - tensorflow::Tensor inputAssoc(tensorflow::DT_FLOAT, {1, 4}); - std::vector outputAssoc; +void NNVtxAssoc::TTTrackNetworkSelector(const l1ct::PFRegionEmu& region, + const l1ct::TkObjEmu& t, + const l1ct::PVObjEmu& v, + l1ct::nn_assoc_t& score) { + nn_inputtype modelInput[N_NN_ASSOC_FEATURES] = {}; // Do something + classtype classresult; - auto lower = std::lower_bound(eta_bins_.begin(), eta_bins_.end(), region.floatGlbEta(t.hwVtxEta())); + int resbin = 0; + int Nresbins = std::size(associationNetworkEtaBounds); - int resbin = std::distance(eta_bins_.begin(), lower); - float binWidth = z0_binning_[2]; - // Calculate integer dZ from track z0 and vertex z0 (use floating point version and convert internally allowing use of both emulator and simulator vertex and track) - float dZ = - abs(floor(((t.floatZ0() + z0_binning_[1]) / (binWidth))) - floor(((v.floatZ0() + z0_binning_[1]) / (binWidth)))); + l1ct::eta_t temp_hwEta = t.hwEta; + if (temp_hwEta < 0) + temp_hwEta = -temp_hwEta; + for (int ibin = 0; ibin < Nresbins; ++ibin) { + if (temp_hwEta > l1ct::Scales::makeEta(associationNetworkEtaBounds[ibin]) && + temp_hwEta <= l1ct::Scales::makeEta(associationNetworkEtaBounds[ibin + 1])) { + resbin = ibin; + break; + } + } // The following constants <22, 9> are defined by the quantisation of the Neural Network - ap_ufixed<22, 9> ptEmulation_rescale = t.hwPt; - ap_ufixed<22, 9> resBinEmulation_rescale = res_bins_[resbin]; - ap_ufixed<22, 9> MVAEmulation_rescale = 0; - ap_ufixed<22, 9> dZEmulation_rescale = dZ; - - // Deal with this template class using 2 different objects (t) which have different calls to their PFTracks: - const l1t::PFTrack* srcTrack = nullptr; - if constexpr (std::is_same_v) - srcTrack = t.src; - else if constexpr (std::is_same_v) - srcTrack = t.srcTrack; - if (srcTrack) - MVAEmulation_rescale = srcTrack->trackWord().getMVAQualityBits(); - - inputAssoc.tensor()(0, 0) = ptEmulation_rescale.to_double(); - inputAssoc.tensor()(0, 1) = MVAEmulation_rescale.to_double(); - inputAssoc.tensor()(0, 2) = resBinEmulation_rescale.to_double() / 16.0; - inputAssoc.tensor()(0, 3) = dZEmulation_rescale.to_double(); - - // Run Association Network: - tensorflow::run(associationSesh_, {{"NNvtx_track_association:0", inputAssoc}}, {"Identity:0"}, &outputAssoc); - - double NNOutput = (double)outputAssoc[0].tensor()(0, 0); - double NNOutput_exp = 1.0 / (1.0 + exp(-1.0 * (NNOutput))); - - return NNOutput_exp >= associationThreshold_; + fPt_ = t.hwPt; + fResBin_ = associationNetworkZ0ResBins[resbin]; + fMVA_ = t.hwQuality; + fDz_ = t.hwZ0 - v.hwZ0; + + modelInput[0] = fPt_; // Obj pT + modelInput[1] = fMVA_; // Obj track quality + modelInput[2] = fResBin_ / 16; // Obj z0 resolution bin (rescaled) + modelInput[3] = fDz_; // Obj delta z from the PV + + modelRef_->prepare_input(modelInput); + modelRef_->predict(); + modelRef_->read_result(&classresult); + + score = (l1ct::nn_assoc_t)classresult; + + if (isDebugEnabled_) { + LogDebug("NNVtxAssoc") << "\n ===== Vertex Association Output Score =====" << std::endl; + } + float NNOutput_exp = 1.0 / (1.0 + exp(-1.0 * (classresult.to_float()))); + if (isDebugEnabled_) { + LogDebug("NNVtxAssoc") << "Score: " << classresult.to_float() << "exponentiated score " << NNOutput_exp + << std::endl; + } } -#ifdef CMSSW_GIT_HASH #include "FWCore/ParameterSet/interface/ParameterSet.h" #include "FWCore/ParameterSet/interface/ParameterSetDescription.h" edm::ParameterSetDescription NNVtxAssoc::getParameterSetDescription() { edm::ParameterSetDescription description; description.add("associationThreshold"); - description.add("associationGraph"); + description.add("associationNetworkPath"); description.add>("associationNetworkZ0binning"); description.add>("associationNetworkEtaBounds"); description.add>("associationNetworkZ0ResBins"); return description; } -#endif void NNVtxAssoc::NNVtxAssocDebug() { log_ << "-- NNVtxAssocDebug --\n"; @@ -100,9 +113,39 @@ void NNVtxAssoc::NNVtxAssocDebug() { edm::LogPrint("NNVtxAssoc") << log_.str(); } -template bool NNVtxAssoc::TTTrackNetworkSelector(const PFRegionEmu&, - const l1ct::TkObjEmu&, - const l1ct::PVObjEmu&); -template bool NNVtxAssoc::TTTrackNetworkSelector(const PFRegionEmu&, - const l1ct::PFChargedObjEmu&, - const l1ct::PVObjEmu&); +#else + +#include "NNVtx/L1TNNVtx_Assoc_Model_v0/NN/L1TNNVtx_Assoc_Model_v0.h" + +void EmuNetworkSelector(const l1ct::TkObj& t, const l1ct::PVObjEmu& v, l1ct::nn_assoc_t& output_score) { + int resbin = 0; + int Nresbins = sizeof(associationNetworkEtaBounds) / sizeof(associationNetworkEtaBounds[0]); + l1ct::eta_t temp_hwEta = t.hwEta; + if (temp_hwEta < 0) + temp_hwEta = -temp_hwEta; + for (int ibin = 0; ibin < Nresbins; ++ibin) { + if (temp_hwEta > l1ct::Scales::makeEta(associationNetworkEtaBounds[ibin]) && + temp_hwEta <= l1ct::Scales::makeEta(associationNetworkEtaBounds[ibin + 1])) { + resbin = ibin; + break; + } + } + // The following constants <22, 9> are defined by the quantisation of the Neural Network + nn_inputtype fPt_ = t.hwPt; + nn_inputtype fResBin_ = associationNetworkZ0ResBins[resbin]; + nn_inputtype fMVA_ = t.hwQuality; + nn_inputtype fDz_ = t.hwZ0 - v.hwZ0; + + hls4ml_L1TNNVtx_Assoc_Model_v0::input_t association_input[N_NN_ASSOC_FEATURES]; + hls4ml_L1TNNVtx_Assoc_Model_v0::result_t nn_output_score[N_NN_ASSOC_OUTPUTS]; + + association_input[0] = fPt_; // Obj pT + association_input[1] = fMVA_; // Obj track quality + association_input[2] = fResBin_ / 16; // Obj z0 resolution bin (rescaled) + association_input[3] = fDz_; // Obj delta z from the PV + + hls4ml_L1TNNVtx_Assoc_Model_v0::L1TNNVtx_Assoc_Model_v0(association_input, nn_output_score); + + output_score = (l1ct::nn_assoc_t)nn_output_score[0]; +} +#endif diff --git a/L1Trigger/Phase2L1ParticleFlow/src/puppi/linpuppi_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/puppi/linpuppi_ref.cpp index a38e4fdda8769..7a1c39ae7c0cd 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/puppi/linpuppi_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/puppi/linpuppi_ref.cpp @@ -14,9 +14,8 @@ #include "FWCore/Utilities/interface/transform.h" #include "FWCore/Utilities/interface/Exception.h" #include "FWCore/ParameterSet/interface/FileInPath.h" -#endif - #include "L1Trigger/Phase2L1ParticleFlow/interface/NNVtxAssoc.h" +#endif using namespace l1ct; using namespace linpuppi; @@ -52,10 +51,6 @@ l1ct::LinPuppiEmulator::LinPuppiEmulator(unsigned int nTrack, pt_t ptCut_1, bool useMLAssociation, const double associationThreshold, - std::string associationGraphPath, - std::vector associationNetworkZ0binning, - std::vector associationNetworkEtaBounds, - std::vector associationNetworkZ0ResBins, unsigned int nFinalSort, SortAlgo finalSortAlgo) : nTrack_(nTrack), @@ -78,6 +73,7 @@ l1ct::LinPuppiEmulator::LinPuppiEmulator(unsigned int nTrack, priorPh_(2), ptCut_(2), useMLAssociation_(useMLAssociation), + associationThreshold_(associationThreshold), nFinalSort_(nFinalSort ? nFinalSort : nOut), finalSortAlgo_(finalSortAlgo), debug_(false), @@ -102,14 +98,6 @@ l1ct::LinPuppiEmulator::LinPuppiEmulator(unsigned int nTrack, priorPh_[1] = priorPh_1; ptCut_[0] = ptCut_0; ptCut_[1] = ptCut_1; - - if (useMLAssociation_ and withinCMSSW_) { - nnVtxAssoc_ = std::make_unique(NNVtxAssoc(associationGraphPath, - associationThreshold, - associationNetworkZ0binning, - associationNetworkEtaBounds, - associationNetworkZ0ResBins)); - } } #ifdef CMSSW_GIT_HASH @@ -135,6 +123,8 @@ l1ct::LinPuppiEmulator::LinPuppiEmulator(const edm::ParameterSet &iConfig) priorPh_(iConfig.getParameter>("priorsPhoton")), ptCut_(edm::vector_transform(iConfig.getParameter>("ptCut"), l1ct::Scales::makePtFromFloat)), useMLAssociation_(iConfig.getParameter("useMLAssociation")), + loader(hls4mlEmulator::ModelLoader(iConfig.getParameter("NNVtxAssociation") + .getParameter("associationNetworkPath"))), nFinalSort_(iConfig.getParameter("nFinalSort")), debug_(iConfig.getUntrackedParameter("debug", false)), fakePuppi_(iConfig.getParameter("fakePuppi")) { @@ -160,15 +150,20 @@ l1ct::LinPuppiEmulator::LinPuppiEmulator(const edm::ParameterSet &iConfig) throw cms::Exception("Configuration", "size mismatch for ptCut parameter"); if (useMLAssociation_) { edm::ParameterSet nnVtxAssocPSet_ = iConfig.getParameter("NNVtxAssociation"); - edm::FileInPath associationGraphPathFIP = - edm::FileInPath(nnVtxAssocPSet_.getParameter("associationGraph")); - - nnVtxAssoc_ = std::make_unique( - NNVtxAssoc(associationGraphPathFIP.fullPath(), - nnVtxAssocPSet_.getParameter("associationThreshold"), - nnVtxAssocPSet_.getParameter>("associationNetworkZ0binning"), - nnVtxAssocPSet_.getParameter>("associationNetworkEtaBounds"), - nnVtxAssocPSet_.getParameter>("associationNetworkZ0ResBins"))); + try { + model = loader.load_model(); + nnVtxAssoc_ = std::make_unique( + NNVtxAssoc(model, + nnVtxAssocPSet_.getParameter("associationThreshold"), + nnVtxAssocPSet_.getParameter>("associationNetworkZ0binning"), + nnVtxAssocPSet_.getParameter>("associationNetworkEtaBounds"), + nnVtxAssocPSet_.getParameter>("associationNetworkZ0ResBins"), + debug_)); + } catch (std::runtime_error &e) { + throw cms::Exception("ModelError") << "Failed to load L1TNNVtxAssoc model from \"" + << nnVtxAssocPSet_.getParameter("associationNetworkPath") + << "\": " << e.what(); + } } const std::string &sortAlgo = iConfig.getParameter("finalSortAlgo"); if (sortAlgo == "Insertion") @@ -274,55 +269,48 @@ void l1ct::LinPuppiEmulator::puppisort_and_crop_ref(unsigned int nOutMax, void l1ct::LinPuppiEmulator::linpuppi_chs_ref(const PFRegionEmu ®ion, const std::vector &pv, + std::vector &association /*[nTrack]*/, const std::vector &pfch /*[nTrack]*/, std::vector &outallch /*[nTrack]*/) const { const unsigned int nTrack = std::min(nTrack_, pfch.size()); - const unsigned int nVtx = std::min(nVtx_, pv.size()); outallch.resize(nTrack); for (unsigned int i = 0; i < nTrack; ++i) { - int pZ0 = pfch[i].hwZ0; - int z0diff = -99999; - bool pass_network = false; - for (unsigned int j = 0; j < nVtx; ++j) { - int pZ0Diff = pZ0 - pv[j].hwZ0; - if (std::abs(z0diff) > std::abs(pZ0Diff)) - z0diff = pZ0Diff; - if (useMLAssociation_ and withinCMSSW_ && - nnVtxAssoc_->TTTrackNetworkSelector(region, pfch[i], pv[j]) == 1) - pass_network = true; - } bool accept = pfch[i].hwPt != 0; - if (!fakePuppi_ && !useMLAssociation_) - accept = accept && region.isFiducial(pfch[i]) && (std::abs(z0diff) <= int(dzCut_) || pfch[i].hwId.isMuon()); - if (!fakePuppi_ && useMLAssociation_) - accept = accept && region.isFiducial(pfch[i]) && (pass_network || pfch[i].hwId.isMuon()); + if (!fakePuppi_) + accept = accept && region.isFiducial(pfch[i]) && (association[i].hwAssociation == 1 || pfch[i].hwId.isMuon()); if (accept) { outallch[i].fill(region, pfch[i]); + outallch[i].Association = association[i].hwAssociation; + outallch[i].AssociationScore = association[i].hwAssociationScore; if (fakePuppi_) { // overwrite Dxy & TkQuality with debug information outallch[i].setHwDxy(dxy_t(pv[0].hwZ0)); ///hack to get this to work outallch[i].setHwTkQuality(region.isFiducial(pfch[i]) ? 1 : 0); } if (debug_ && pfch[i].hwPt > 0) - dbgPrintf("ref candidate %02u pt %7.2f pid %1d vz %+6d dz %+6d (cut %5d), fid %1d -> pass, packed %s\n", - i, - pfch[i].floatPt(), - pfch[i].intId(), - int(pfch[i].hwZ0), - z0diff, - dzCut_, - region.isFiducial(pfch[i]), - outallch[i].pack().to_string(16).c_str()); + dbgPrintf( + "ref candidate %02u pt %7.2f pid %1d, z0 %7d, associated %1d, association score %10.6f, fid %1d -> pass, " + "packed %s\n", + i, + pfch[i].floatPt(), + pfch[i].intId(), + int(pfch[i].hwZ0), + int(association[i].hwAssociation), + association[i].hwAssociationScore.to_float(), + region.isFiducial(pfch[i]), + outallch[i].pack().to_string(16).c_str()); } else { outallch[i].clear(); if (debug_ && pfch[i].hwPt > 0) - dbgPrintf("ref candidate %02u pt %7.2f pid %1d vz %+6d dz %+6d (cut %5d), fid %1d -> fail\n", - i, - pfch[i].floatPt(), - pfch[i].intId(), - int(pfch[i].hwZ0), - z0diff, - dzCut_, - region.isFiducial(pfch[i])); + dbgPrintf( + "ref candidate %02u pt %7.2f pid %1d , z0 %7d, associated %1d, association score %10.6f, fid %1d -> " + "fail\n", + i, + pfch[i].floatPt(), + pfch[i].intId(), + int(pfch[i].hwZ0), + int(association[i].hwAssociation), + association[i].hwAssociationScore.to_float(), + region.isFiducial(pfch[i])); } } } @@ -465,9 +453,41 @@ void l1ct::LinPuppiEmulator::fwdlinpuppi_ref(const PFRegionEmu ®ion, puppisort_and_crop_ref(nOut_, outallne, outselne); } +void l1ct::LinPuppiEmulator::linpuppi_associate_trk(const PFRegionEmu ®ion, + const std::vector &trk, + const std::vector &pv, + std::vector &Associations) const { + const unsigned int nTrack = trk.size(); + const unsigned int nVtx_ = pv.size(); + Associations.clear(); + nn_assoc_t nnvtx_score = 0; + nn_assoc_t associationThreshold = associationThreshold_; + AssociationObjEmu association; + for (unsigned int it = 0; it < nTrack; ++it) { + for (unsigned int v = 0; v < nVtx_; ++v) { + if (useMLAssociation_) { +#ifdef CMSSW_GIT_HASH + nnVtxAssoc_->TTTrackNetworkSelector(region, trk[it], pv[v], nnvtx_score); + associationThreshold = nnVtxAssoc_->getAssociationThreshold(); +#else + EmuNetworkSelector(trk[it], pv[v], nnvtx_score); +#endif + } else { + nnvtx_score = + (std::abs(int(trk[it].hwZ0) - int(pv[v].hwZ0)) <= int(dzCut_)) ? nn_assoc_t(1.0) : nn_assoc_t(0.0); + } + + association.hwAssociationScore = nnvtx_score; + association.hwAssociation = (nnvtx_score > associationThreshold) ? 1 : 0; + Associations.push_back(association); + } + } +} + void l1ct::LinPuppiEmulator::linpuppi_ref(const PFRegionEmu ®ion, const std::vector &track /*[nTrack]*/, const std::vector &pv, /*[nVtx]*/ + std::vector &association /*[nTrack]*/, const std::vector &pfallne /*[nIn]*/, std::vector &outallne_nocut /*[nIn]*/, std::vector &outallne /*[nIn]*/, @@ -487,22 +507,7 @@ void l1ct::LinPuppiEmulator::linpuppi_ref(const PFRegionEmu ®ion, for (unsigned int it = 0; it < nTrack; ++it) { if (track[it].hwPt == 0) continue; - - int pZMin = 99999; - bool pass_network = false; - for (unsigned int v = 0; v < nVtx_; ++v) { - if (v < pv.size()) { - int ppZMin = std::abs(int(track[it].hwZ0 - pv[v].hwZ0)); - if (pZMin > ppZMin) - pZMin = ppZMin; - if (useMLAssociation_ and withinCMSSW_ && - nnVtxAssoc_->TTTrackNetworkSelector(region, track[it], pv[v]) == 1) - pass_network = true; - } - } - if (useMLAssociation_ && !pass_network) - continue; - if (!useMLAssociation_ && std::abs(pZMin) > int(dzCut_)) + if (association[it].hwAssociation != 1) continue; unsigned int dr2 = dr2_int(pfallne[in].hwEta, pfallne[in].hwPhi, track[it].hwEta, track[it].hwPhi); if (dr2 <= dR2Max_) { // if dr is inside puppi cone @@ -624,6 +629,7 @@ void l1ct::LinPuppiEmulator::fwdlinpuppi_flt(const PFRegionEmu ®ion, void l1ct::LinPuppiEmulator::linpuppi_flt(const PFRegionEmu ®ion, const std::vector &track /*[nTrack]*/, const std::vector &pv, + std::vector &association /*[nTrack]*/, const std::vector &pfallne /*[nIn]*/, std::vector &outallne_nocut /*[nIn]*/, std::vector &outallne /*[nIn]*/, @@ -643,20 +649,7 @@ void l1ct::LinPuppiEmulator::linpuppi_flt(const PFRegionEmu ®ion, for (unsigned int it = 0; it < nTrack; ++it) { if (track[it].hwPt == 0) continue; - - int pZMin = 99999; - bool pass_network = false; - for (unsigned int v = 0, nVtx = std::min(nVtx_, pv.size()); v < nVtx; ++v) { - int ppZMin = std::abs(int(track[it].hwZ0 - pv[v].hwZ0)); - if (pZMin > ppZMin) - pZMin = ppZMin; - if (useMLAssociation_ and withinCMSSW_ && - nnVtxAssoc_->TTTrackNetworkSelector(region, track[it], pv[v]) == 1) - pass_network = true; - } - if (useMLAssociation_ && !pass_network) - continue; - if (!useMLAssociation_ && std::abs(pZMin) > int(dzCut_)) + if (association[it].hwAssociation != 1) continue; unsigned int dr2 = dr2_int( pfallne[in].hwEta, pfallne[in].hwPhi, track[it].hwEta, track[it].hwPhi); // if dr is inside puppi cone @@ -687,8 +680,10 @@ void l1ct::LinPuppiEmulator::run(const PFInputRegion &in, } if (std::abs(in.region.floatEtaCenter()) < 2.5) { // within tracker std::vector outallch, outallne_nocut, outallne, outselne; - linpuppi_chs_ref(in.region, pvs, out.pfcharged, outallch); - linpuppi_ref(in.region, in.track, pvs, out.pfneutral, outallne_nocut, outallne, outselne); + std::vector associations; + linpuppi_associate_trk(in.region, in.track, pvs, associations); + linpuppi_chs_ref(in.region, pvs, associations, out.pfcharged, outallch); + linpuppi_ref(in.region, in.track, pvs, associations, out.pfneutral, outallne_nocut, outallne, outselne); // ensure proper sizes of the vectors, to get accurate sorting wrt firmware const std::vector &ne = (nOut_ == nIn_ ? outallne : outselne); unsigned int nch = outallch.size(), nne = ne.size(), i; diff --git a/L1Trigger/Phase2L1ParticleFlow/test/make_l1ct_binaryFiles_cfg.py b/L1Trigger/Phase2L1ParticleFlow/test/make_l1ct_binaryFiles_cfg.py index 9aa36e60eac27..d4456abf87bb7 100644 --- a/L1Trigger/Phase2L1ParticleFlow/test/make_l1ct_binaryFiles_cfg.py +++ b/L1Trigger/Phase2L1ParticleFlow/test/make_l1ct_binaryFiles_cfg.py @@ -61,6 +61,7 @@ process.load('L1Trigger.Phase2L1ParticleFlow.l1ctLayer1_cff') process.load('L1Trigger.Phase2L1ParticleFlow.l1ctLayer2EG_cff') process.load('L1Trigger.Phase2L1ParticleFlow.l1pfJetMet_cff') +process.load('L1Trigger.Phase2L1ParticleFlow.mlAssociation_cfi') process.load('L1Trigger.L1TTrackMatch.l1tGTTInputProducer_cfi') process.load('L1Trigger.L1TTrackMatch.l1tTrackSelectionProducer_cfi') process.l1tTrackSelectionProducer.processSimulatedTracks = False # these would need stubs, and are not used anyway @@ -177,6 +178,11 @@ trkQualityPtMin = 10.) ) +process.l1tLayer1HGCalNNAssoc = process.l1tLayer1HGCal.clone() +associationPSset = process.NNVtxAssociationPSet.clone() +associationPSset.associationThreshold = cms.double(-1.0) +process.l1tLayer1HGCalNNAssoc.puAlgoParameters.useMLAssociation = True +process.l1tLayer1HGCalNNAssoc.puAlgoParameters.NNVtxAssociation = associationPSset if args.serenity: @@ -200,6 +206,7 @@ process.l1tLayer1HGCalElliptic.patternWriters = cms.untracked.VPSet(*hgcalTM18WriterConfigs) process.l1tLayer1HGCalNoTK.patternWriters = cms.untracked.VPSet(hgcalNoTKOutputTM18WriterConfig) process.l1tLayer1HF.patternWriters = cms.untracked.VPSet(*hfWriterConfigs) + process.l1tLayer1HGCalNNAssoc.patternWriters = cms.untracked.VPSet(*hgcalTM18WriterConfigs) process.l1tSC4NGJetProducer.jets = cms.InputTag("l1tSC4PFL1PuppiEmulator") process.l1tSC4NGJetProducer.doJEC = cms.bool(True) @@ -259,7 +266,7 @@ process.runPF.insert(process.runPF.index(process.l1tLayer2SeedConeJetWriter)+1, process.l1tLayer2SeedConeNGJetWriter) process.l1tLayer2SeedConeNGJetWriter.maxLinesPerFile = _eventsPerFile*54 if not args.dumpFilesOFF: - for det in "Barrel", "BarrelTDR", "BarrelSerenity", "BarrelSerenityElliptic", "HGCal", "HGCalElliptic", "HGCalNoTK", "HF": + for det in "Barrel", "BarrelTDR", "BarrelSerenity", "BarrelSerenityElliptic", "HGCal", "HGCalElliptic", "HGCalNoTK", "HF","HGCalNNAssoc": l1pf = getattr(process, 'l1tLayer1'+det) l1pf.dumpFileName = cms.untracked.string("TTbar_PU200_"+det+".dump") for det in "Barrel", "HGCal": @@ -281,6 +288,10 @@ hgcalWriterVU9PTM18WriterConfig.clone(inputFileName = f"l1HGCalTM18-inputs-vu9p-ts{tmSlice}"), hgcalWriterVU13PTM18WriterConfig.clone(inputFileName = f"l1HGCalTM18-inputs-vu13p-ts{tmSlice}") ) + getattr(process, f'l1tLayer1HGCalTM18NNAssocTS{tmSlice}').patternWriters = cms.untracked.VPSet( + hgcalWriterOutputTM18WriterConfig.clone(outputFileName = f"l1HGCalTM18NN-outputs-ts{tmSlice}"), + hgcalWriterVU13PTM18WriterConfig.clone(inputFileName = f"l1HGCalTM18NN-inputs-vu13p-ts{tmSlice}") + ) getattr(process, f'l1tLayer1HGCalNoTKTS{tmSlice}').patternWriters = cms.untracked.VPSet( hgcalNoTKOutputTM18WriterConfig.clone(outputFileName = f"l1HGCalTM18-outputs-ts{tmSlice}"), ) From bc8ef64d7575c30986caabaaa7f6255c67987c3b Mon Sep 17 00:00:00 2001 From: Jovan Mitrevski Date: Fri, 13 Jun 2025 17:35:13 -0500 Subject: [PATCH 5/9] TMUX 18 GCT inputs --- .../interface/CaloPFCluster.h | 7 + .../interface/DigitizedCaloToCorrelatorTM18.h | 45 ++ .../interface/DigitizedClusterCorrelator.h | 148 ++-- .../interface/DigitizedL1CaloJet.h | 103 +++ .../interface/GCTEmDigiCluster.h | 93 +-- .../interface/GCTHadDigiCluster.h | 51 +- .../L1TCalorimeterPhase2/src/classes.h | 2 + .../L1TCalorimeterPhase2/src/classes_def.xml | 16 +- .../interface/layer1_emulator.h | 6 +- .../L1TParticleFlow/src/layer1_emulator.cpp | 27 +- .../Phase2L1CaloBarrelToCorrelator.h | 27 - .../interface/Phase2L1CaloEGammaUtils.h | 209 +++-- .../interface/Phase2L1CaloPFClusterEmulator.h | 66 +- .../L1CaloTrigger/interface/Phase2L1GCT.h | 10 +- .../plugins/Phase2L1CaloJetEmulator.cc | 4 +- .../plugins/Phase2L1CaloPFClusterEmulator.cc | 49 +- .../plugins/Phase2L1CaloToCorrelatorTM18.cc | 287 +++++++ .../Phase2L1TCaloBarrelToCorrelator.cc | 160 ++-- .../l1tPhase2CaloToCorrelatorTM18_cfi.py | 6 + .../L1TCorrelatorLayer1PatternFileWriter.h | 16 +- .../egamma/pftkegsorter_barrel_ref.h | 8 +- .../interface/egamma/pftkegsorter_ref.h | 1 + .../interface/l1-converters/gcteminput_ref.h | 21 - .../interface/l1-converters/gcthadinput_ref.h | 27 +- .../middle_buffer_multififo_regionizer_ref.h | 32 +- .../regionizer/tdr_regionizer_elements_ref.h | 251 +----- .../tdr_regionizer_elements_ref.icc | 723 +++++++----------- .../interface/regionizer/tdr_regionizer_ref.h | 29 +- .../plugins/L1TCorrelatorLayer1Producer.cc | 181 +++-- .../PFClusterProducerFromL1EGClusters.cc | 6 +- .../python/l1TkEgAlgoEmulator_cfi.py | 6 +- .../python/l1ctLayer1_cff.py | 55 +- .../python/l1ctLayer1_patternWriters_cff.py | 179 ++--- .../L1TCorrelatorLayer1PatternFileWriter.cc | 113 ++- .../Phase2L1ParticleFlow/src/corrector.cc | 8 +- .../src/egamma/pftkegalgo_ref.cpp | 4 +- .../src/l1-converters/gcteminput_ref.cpp | 19 +- .../src/l1-converters/gcthadinput_ref.cpp | 36 +- .../src/pf/pfalgo3_ref.cpp | 12 + ...middle_buffer_multififo_regionizer_ref.cpp | 159 ++-- .../src/regionizer/tdr_regionizer_ref.cpp | 133 ++-- .../test/make_l1ct_binaryFiles_cfg.py | 75 +- 42 files changed, 1749 insertions(+), 1661 deletions(-) create mode 100644 DataFormats/L1TCalorimeterPhase2/interface/DigitizedCaloToCorrelatorTM18.h create mode 100644 DataFormats/L1TCalorimeterPhase2/interface/DigitizedL1CaloJet.h delete mode 100644 L1Trigger/L1CaloTrigger/interface/Phase2L1CaloBarrelToCorrelator.h create mode 100644 L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloToCorrelatorTM18.cc create mode 100644 L1Trigger/L1CaloTrigger/python/l1tPhase2CaloToCorrelatorTM18_cfi.py diff --git a/DataFormats/L1TCalorimeterPhase2/interface/CaloPFCluster.h b/DataFormats/L1TCalorimeterPhase2/interface/CaloPFCluster.h index 6a242e3f54939..88e0ee43a9b66 100644 --- a/DataFormats/L1TCalorimeterPhase2/interface/CaloPFCluster.h +++ b/DataFormats/L1TCalorimeterPhase2/interface/CaloPFCluster.h @@ -14,6 +14,7 @@ namespace l1tp2 { CaloPFCluster() : l1t::L1Candidate(), clusterEt_(0.), + ecalEt_(0.), clusterIEta_(-99), clusterIPhi_(-99), clusterEta_(-99.), @@ -21,23 +22,27 @@ namespace l1tp2 { CaloPFCluster(const PolarLorentzVector& p4, float clusterEt, + float ecalEt, int clusterIEta, int clusterIPhi, float clusterEta, float clusterPhi) : l1t::L1Candidate(p4), clusterEt_(clusterEt), + ecalEt_(ecalEt), clusterIEta_(clusterIEta), clusterIPhi_(clusterIPhi), clusterEta_(clusterEta), clusterPhi_(clusterPhi) {} inline float clusterEt() const { return clusterEt_; }; + inline float ecalEt() const { return ecalEt_; }; inline int clusterIEta() const { return clusterIEta_; }; inline int clusterIPhi() const { return clusterIPhi_; }; inline float clusterEta() const { return clusterEta_; }; inline float clusterPhi() const { return clusterPhi_; }; void setClusterEt(float clusterEtIn) { clusterEt_ = clusterEtIn; }; + void setEcalEt(float ecalEtIn) { ecalEt_ = ecalEtIn; }; void setClusterIEta(int clusterIEtaIn) { clusterIEta_ = clusterIEtaIn; }; void setClusterIPhi(int clusterIPhiIn) { clusterIPhi_ = clusterIPhiIn; }; void setClusterEta(float clusterEtaIn) { clusterEta_ = clusterEtaIn; }; @@ -46,6 +51,8 @@ namespace l1tp2 { private: // ET float clusterEt_; + // ECAL ET + float ecalEt_; // GCT ieta int clusterIEta_; // GCT iphi diff --git a/DataFormats/L1TCalorimeterPhase2/interface/DigitizedCaloToCorrelatorTM18.h b/DataFormats/L1TCalorimeterPhase2/interface/DigitizedCaloToCorrelatorTM18.h new file mode 100644 index 0000000000000..ab6b6aa484c74 --- /dev/null +++ b/DataFormats/L1TCalorimeterPhase2/interface/DigitizedCaloToCorrelatorTM18.h @@ -0,0 +1,45 @@ +#ifndef DataFormats_L1TCalorimeterPhase2_DigitizedCaloToCorrelatorTM18_h +#define DataFormats_L1TCalorimeterPhase2_DigitizedCaloToCorrelatorTM18_h + +#include +#include +#include +#include "DataFormats/L1TCalorimeterPhase2/interface/GCTEmDigiCluster.h" +#include "DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h" + +namespace l1tp2 { + + typedef std::variant GCTDigiCluster; + typedef std::vector GCTDigiClusterLink; + + class DigitizedCaloToCorrelatorTM18 { + private: + // Data (to remove) + ap_uint<64> CardData[162]; + + GCTDigiClusterLink CardLink; + + public: + DigitizedCaloToCorrelatorTM18() { + for (int i = 0; i < 162; i++) { + CardData[i] = 0; + } + } + DigitizedCaloToCorrelatorTM18(ap_uint<64> data[162], GCTDigiClusterLink link) { + for (int i = 0; i < 162; i++) { + CardData[i] = data[i]; + } + CardLink = link; + } + + const ap_uint<64>* dataCard() const { return CardData; } + const GCTDigiClusterLink& linkCard() const { return CardLink; } + }; + + // Collection typedef + // this represents both the EM and PF clusters from a single GCT card in one link + typedef std::vector DigitizedCaloToCorrelatorCollectionTM18; + +} // namespace l1tp2 + +#endif diff --git a/DataFormats/L1TCalorimeterPhase2/interface/DigitizedClusterCorrelator.h b/DataFormats/L1TCalorimeterPhase2/interface/DigitizedClusterCorrelator.h index 5b24441295f3d..65ac055bec285 100644 --- a/DataFormats/L1TCalorimeterPhase2/interface/DigitizedClusterCorrelator.h +++ b/DataFormats/L1TCalorimeterPhase2/interface/DigitizedClusterCorrelator.h @@ -20,49 +20,16 @@ namespace l1tp2 { static constexpr float ETA_RANGE_ONE_SIDE = 1.4841; // barrel goes from (-1.4841, +1.4841) static constexpr float LSB_ETA = ((2 * ETA_RANGE_ONE_SIDE) / (n_towers_eta * n_crystals_in_tower)); // (2.8 / 170) static constexpr float LSB_PHI = ((2 * M_PI) / (3 * n_towers_phi * n_crystals_in_tower)); // (2 pi * 360) + static constexpr float PHI_RANGE_PER_SLR_DEGREES = 120; static constexpr unsigned int n_bits_pt = 12; // 12 bits allocated for pt static constexpr unsigned int n_bits_unused_start = 63; // unused bits start at bit 63 // "top" of the correlator card #0 in GCT coordinates is iPhi tower index 24 - static constexpr int correlatorCard0_tower_iphi_offset = 24; + static constexpr int correlatorCard0_tower_iphi_offset = 68; // same but for correlator cards #1 and 2 (cards wrap around phi = 180 degrees): - static constexpr int correlatorCard1_tower_iphi_offset = 48; - static constexpr int correlatorCard2_tower_iphi_offset = 0; - - // Private member functions to perform digitization - ap_uint<12> digitizePt(float pt_f) { - float maxPt_f = (std::pow(2, n_bits_pt) - 1) * LSB_PT; - // If pT exceeds the maximum (extremely unlikely), saturate the value - if (pt_f >= maxPt_f) { - return (ap_uint<12>)0xFFF; - } - - return (ap_uint<12>)(pt_f / LSB_PT); - } - - ap_uint<8> digitizeIEtaCr(unsigned int iEtaCr) { return (ap_uint<8>)iEtaCr; } - - ap_uint<7> digitizeIPhiCr(unsigned int iPhiCr) { return (ap_uint<7>)iPhiCr; } - - // To-do: HoE is not defined for clusters - ap_uint<4> digitizeHoE(unsigned int hoe) { return (ap_uint<4>)hoe; } - ap_uint<2> digitizeHoeFlag(unsigned int hoeFlag) { return (ap_uint<2>)hoeFlag; } - - ap_uint<3> digitizeIso(unsigned int iso) { return (ap_uint<3>)iso; } - ap_uint<2> digitizeIsoFlag(unsigned int isoFlag) { return (ap_uint<2>)isoFlag; } - - // To-do: fb: no information yet - ap_uint<6> digitizeFb(unsigned int fb) { return (ap_uint<6>)fb; } - - // To-do: timing: no information yet - ap_uint<5> digitizeTiming(unsigned int timing) { return (ap_uint<5>)timing; } - - // Shape: shower shape working point - ap_uint<2> digitizeShapeFlag(unsigned int shapeFlag) { return (ap_uint<2>)shapeFlag; } - - // TO-DO: Brems: was brems applied (NOT STORED YET IN GCT) - ap_uint<2> digitizeBrems(unsigned int brems) { return (ap_uint<2>)brems; } + static constexpr int correlatorCard1_tower_iphi_offset = 20; + static constexpr int correlatorCard2_tower_iphi_offset = 44; public: DigitizedClusterCorrelator() { clusterData = 0x0; } @@ -71,45 +38,20 @@ namespace l1tp2 { // Constructor from digitized inputs DigitizedClusterCorrelator(ap_uint<12> pt, - ap_uint<8> etaCr, - ap_uint<7> phiCr, - ap_uint<4> hoe, - ap_uint<2> hoeFlag, - ap_uint<3> iso, - ap_uint<2> isoFlag, - ap_uint<6> fb, + ap_uint<7> eta, + ap_int<7> phi, + ap_uint<6> hoe, + ap_uint<6> iso, + ap_uint<6> shape, + ap_uint<3> wp, ap_uint<5> timing, - ap_uint<2> shapeFlag, ap_uint<2> brems, - int iGCTCard, - bool fullydigitizedInputs) { - (void)fullydigitizedInputs; - clusterData = ((ap_uint<64>)pt) | (((ap_uint<64>)etaCr) << 12) | (((ap_uint<64>)phiCr) << 20) | - (((ap_uint<64>)hoe) << 27) | (((ap_uint<64>)hoeFlag) << 31) | (((ap_uint<64>)iso) << 36) | - (((ap_uint<64>)isoFlag) << 38) | (((ap_uint<64>)fb) << 44) | (((ap_uint<64>)timing) << 49) | - (((ap_uint<64>)shapeFlag << 51)) | (((ap_uint<64>)brems << 53)); - idxGCTCard = iGCTCard; - } - - // Constructor from float inputs - DigitizedClusterCorrelator(float pt_f, - unsigned int iEtaCr, - unsigned int iPhiCr, - unsigned int hoe, - unsigned int hoeFlag, - unsigned int iso, - unsigned int isoFlag, - unsigned int fb, - unsigned int timing, - unsigned int shapeFlag, - unsigned int brems, + ap_uint<10> spare, int iGCTCard) { - clusterData = (((ap_uint<64>)digitizePt(pt_f)) | ((ap_uint<64>)digitizeIEtaCr(iEtaCr) << 12) | - ((ap_uint<64>)digitizeIPhiCr(iPhiCr) << 20) | ((ap_uint<64>)digitizeHoE(hoe) << 27) | - ((ap_uint<64>)digitizeHoeFlag(hoeFlag) << 31) | ((ap_uint<64>)digitizeIso(iso) << 36) | - ((ap_uint<64>)digitizeIsoFlag(isoFlag) << 38) | ((ap_uint<64>)digitizeFb(fb) << 44) | - ((ap_uint<64>)digitizeTiming(timing) << 49) | ((ap_uint<64>)digitizeShapeFlag(shapeFlag) << 51) | - ((ap_uint<64>)digitizeBrems(brems) << 53)); + clusterData = ((ap_uint<64>)pt) | (((ap_uint<64>)eta) << 12) | (((ap_uint<64>)(phi & 0x7F)) << 19) | + (((ap_uint<64>)hoe) << 26) | (((ap_uint<64>)iso) << 32) | (((ap_uint<64>)shape) << 38) | + (((ap_uint<64>)wp) << 44) | (((ap_uint<64>)timing) << 47) | (((ap_uint<64>)brems) << 52) | + (((ap_uint<64>)spare) << 54); idxGCTCard = iGCTCard; } @@ -121,49 +63,39 @@ namespace l1tp2 { float ptFloat() const { return (pt() * ptLSB()); } // crystal eta in the correlator region (LSB: 2.8/170) - ap_uint<8> eta() const { return ((clusterData >> 12) & 0xFF); } // (eight 1's) 0b11111111 = 0xFF + ap_uint<7> eta() const { return ((clusterData >> 12) & 0x7F); } // (seven 1's) 0b11111111 = 0x7F // crystal phi in the correlator region (LSB: 2pi/360) - ap_uint<7> phi() const { return ((clusterData >> 20) & 0x7F); } // (seven 1's) 0b1111111 = 0x7F + ap_int<7> phi() const { return ((clusterData >> 19) & 0x7F); } // HoE value and flag: not defined yet in the emulator - ap_uint<4> hoe() const { return ((clusterData >> 27) & 0xF); } // (four 1's) 0b1111 = 0xF - ap_uint<2> hoeFlag() const { return ((clusterData >> 31) & 0x3); } // (two 1's) 0b11 = 0x3 + ap_uint<6> hoe() const { return ((clusterData >> 26) & 0x3F); } - // Raw isolation sum: not saved in the emulator - ap_uint<3> iso() const { return ((clusterData >> 36) & 0x7); } + ap_uint<6> iso() const { return ((clusterData >> 32) & 0x3F); } // raw isolation sum - // iso flag: two bits, least significant bit is the standalone WP (true or false), second bit is the looseTk WP (true or false) - // e.g. 0b01 : standalone iso flag passed, loose Tk iso flag did not pass - ap_uint<2> isoFlags() const { return ((clusterData >> 38) & 0x3); } // (two 1's) 0b11 = 0x3 - bool passes_iso() const { return (isoFlags() & 0x1); } // standalone iso WP - bool passes_looseTkiso() const { return (isoFlags() & 0x2); } // loose Tk iso WP + ap_uint<6> shape() const { return ((clusterData >> 38) & 0x3F); } // et2x5/et5x5 - // fb and timing: not saved in the current emulator - ap_uint<6> fb() const { return ((clusterData >> 44) & 0x3F); } - ap_uint<5> timing() const { return ((clusterData >> 49) & 0x1F); } + ap_uint<3> wp() const { return ((clusterData >> 44) & 0x7); } // encoded standaloneWP, looseL1TkMatchWP, photonWP - // shower shape shape flag: two bits, least significant bit is the standalone WP, second bit is the looseTk WP - // e.g. 0b01 : standalone shower shape flag passed, loose Tk shower shape flag did not pass - ap_uint<2> shapeFlags() const { return ((clusterData >> 51) & 0x3); } - - bool passes_ss() const { return (shapeFlags() & 0x1); } // standalone shower shape WP - bool passes_looseTkss() const { return (shapeFlags() & 0x2); } // loose Tk shower shape WP + // timing: not saved in the current emulator + ap_uint<5> timing() const { return ((clusterData >> 47) & 0x1F); } // brems: not saved in the current emulator - ap_uint<2> brems() const { return ((clusterData >> 53) & 0x3); } + ap_uint<2> brems() const { return ((clusterData >> 52) & 0x3); } + + ap_uint<10> spare() const { return ((clusterData >> 54) & 0x3FF); } // which GCT card (0, 1, or 2) unsigned int cardNumber() const { return idxGCTCard; } - const int unusedBitsStart() const { return n_bits_unused_start; } - - // Other checks - bool passNullBitsCheck(void) const { return ((data() >> unusedBitsStart()) == 0x0); } - - // Get real eta (does not depend on card number). crystal iEta = 0 starts at real eta -1.4841. + // Get real eta (does not depend on card number) // LSB_ETA/2 is to add half a crystal width to get the center of the crystal in eta - float realEta() const { return (float)((-1 * ETA_RANGE_ONE_SIDE) + (eta() * LSB_ETA) + (LSB_ETA / 2)); } + float realEta() const { + float tmpeta = (eta() * LSB_ETA) + (LSB_ETA / 2); + if ((spare() & 0x4) == 0) + tmpeta = -((eta() * LSB_ETA) + (LSB_ETA / 2)); + return tmpeta; + } // Get real phi (uses card number). float realPhi() const { @@ -176,10 +108,18 @@ namespace l1tp2 { } else if (cardNumber() == 2) { offset_tower = correlatorCard2_tower_iphi_offset; } - int thisPhi = (phi() + (offset_tower * n_crystals_in_tower)); - // crystal iPhi = 0 starts at real phi = -180 degrees + + int tmpphi = (phi() + PHI_RANGE_PER_SLR_DEGREES / 4); + bool wrapped = !((spare() & 0x2) == 0); + if (wrapped) { + tmpphi += PHI_RANGE_PER_SLR_DEGREES / 2; + } + int thisPhi = (tmpphi + (offset_tower * n_crystals_in_tower)); + if (thisPhi > 180) + thisPhi -= 360; // range between -180 to 180 degrees + // LSB_PHI/2 is to add half a crystal width to get the center of the crystal in phi - return (float)((-1 * M_PI) + (thisPhi * LSB_PHI) + (LSB_PHI / 2)); + return (float)((thisPhi * LSB_PHI) + (LSB_PHI / 2)); } }; diff --git a/DataFormats/L1TCalorimeterPhase2/interface/DigitizedL1CaloJet.h b/DataFormats/L1TCalorimeterPhase2/interface/DigitizedL1CaloJet.h new file mode 100644 index 0000000000000..33779365e7589 --- /dev/null +++ b/DataFormats/L1TCalorimeterPhase2/interface/DigitizedL1CaloJet.h @@ -0,0 +1,103 @@ +#ifndef DataFormats_L1TCalorimeterPhase2_DigitizedL1CaloJet_h +#define DataFormats_L1TCalorimeterPhase2_DigitizedL1CaloJet_h + +#include +#include +#include +#include +#include +#include +#include "DataFormats/L1Trigger/interface/L1Candidate.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +namespace l1tp2 { + + class DigitizedL1CaloJet { + public: + DigitizedL1CaloJet() { jetData = 0x0; } + + DigitizedL1CaloJet(ap_uint<64> data) { jetData = data; } + + //Constructor from digitized inputs + DigitizedL1CaloJet(ap_uint<1> isValid, ap_uint<16> pt, ap_int<13> phi, ap_int<14> eta) { + jetData = + ((ap_uint<64>)isValid) | (((ap_uint<64>)pt) << 1) | (((ap_int<64>)phi) << 17) | (((ap_uint<64>)eta) << 30); + } + + // Constructor from float inputs + DigitizedL1CaloJet(bool isValid_b, float pt_f, float phi_f, float eta_f) { + jetData = ((ap_uint<64>)digitizeIsValid(isValid_b)) | ((ap_uint<64>)digitizePt(pt_f) << 1) | + ((ap_uint<64>)digitizePhi(phi_f) << 17) | ((ap_uint<64>)digitizeEta(eta_f) << 30); + } + + ap_uint<64> data() const { return jetData; } + + // LSB getters + float ptLSB() const { return LSB_PT; } + float phiLSB() const { return LSB_PHI; } + float etaLSB() const { return LSB_ETA; } + + // Data getters (digitized) + ap_uint<1> isValid() const { return (jetData & 1); } + ap_uint<16> pt() const { return ((jetData >> 1) & 0xFFFF); } // 16 1s = 0xFFFF + ap_int<13> phi() const { return ((jetData >> 17) & 0x1FFF); } // 13 1s = 0x1FFF + ap_int<14> eta() const { return ((jetData >> 30) & 0x3FFF); } // 14 1s = 0x3FFF + + // Data getters (floats/bools) + bool isValidBool() const { return (bool)isValid(); } + float ptFloat() const { return (pt() * ptLSB()); } + float phiFloat() const { return (phi() * phiLSB()); } + float etaFloat() const { return (eta() * etaLSB()); } + + private: + // Digitized information as one value + unsigned long long int jetData; + + // Constants + static constexpr float LSB_PT = 0.03125; + static constexpr float LSB_PHI = M_PI / 0x1000; // 2^12 = 0x1000 + static constexpr float LSB_ETA = M_PI / 0x1000; + + static constexpr unsigned int n_bits_pt = 16; + static constexpr unsigned int n_bits_phi = 13; + static constexpr unsigned int n_bits_eta = 14; + + // Private member functions for doing the digitization + ap_uint<16> digitizePt(float pt_f) { + float maxPt_f = (std::pow(2.0f, n_bits_pt) - 1) * LSB_PT; + // If pT exceeds the maximum, saturate the value + if (pt_f >= maxPt_f) { + return (ap_uint<16>)0xFFFF; // 16 1s = 0b1111111111111111 = 0xFFFF + } + return (ap_uint<16>)(pt_f / LSB_PT); + } + + ap_uint<13> digitizePhi(float phi_f) { + float maxPhi_f = (std::pow(2.0f, n_bits_phi - 1) - 1) * LSB_PHI; + // If phi exceeds the maximum (very few values should), saturate the value + if (phi_f >= maxPhi_f) { + return (ap_uint<13>)0xFFF; // 12 1s in binary = 0xFFF (1 bit for sign) + } else if (phi_f <= -maxPhi_f) { + return (ap_uint<13>)-0xFFF; + } + return (ap_uint<13>)(phi_f / LSB_PHI); + } + + ap_uint<14> digitizeEta(float eta_f) { + float maxEta_f = (std::pow(2.0f, n_bits_eta - 1) - 1) * LSB_ETA; + // If eta exceeds the maximum, saturate the value + if (eta_f >= maxEta_f) { + return (ap_uint<14>)0x1FFF; // 13 1s in binary = 0x1FFF (1 bit for sign) + } else if (eta_f <= -maxEta_f) { + return (ap_uint<14>)-0x1FFF; + } + return (ap_uint<14>)(eta_f / LSB_ETA); + } + + ap_uint<1> digitizeIsValid(bool isValid_b) { return (ap_uint<1>)isValid_b; } + }; + + // Concrete collection of output objects (with extra tuning information) + typedef std::vector DigitizedL1CaloJetCollection; +} // namespace l1tp2 +#endif diff --git a/DataFormats/L1TCalorimeterPhase2/interface/GCTEmDigiCluster.h b/DataFormats/L1TCalorimeterPhase2/interface/GCTEmDigiCluster.h index 0a2de6867a183..b9949e1951fc3 100644 --- a/DataFormats/L1TCalorimeterPhase2/interface/GCTEmDigiCluster.h +++ b/DataFormats/L1TCalorimeterPhase2/interface/GCTEmDigiCluster.h @@ -4,8 +4,10 @@ #include #include +#ifdef CMSSW_GIT_HASH #include "DataFormats/L1TCalorimeterPhase2/interface/CaloCrystalCluster.h" #include "DataFormats/L1TCalorimeterPhase2/interface/DigitizedClusterCorrelator.h" +#endif namespace l1tp2 { @@ -17,14 +19,13 @@ namespace l1tp2 { // Constants static constexpr float LSB_PT = 0.5; // 0.5 GeV - // start of the unused bits - static constexpr int n_bits_unused_start = 52; - +#ifdef CMSSW_GIT_HASH // Reference to the original float cluster edm::Ref clusterRef_; // reference to the original digitized cluster (before duplication in the output links) edm::Ref digiClusterRef_; +#endif public: GCTEmDigiCluster() { clusterData = 0; } @@ -32,94 +33,72 @@ namespace l1tp2 { GCTEmDigiCluster(ap_uint<64> data) { clusterData = data; } GCTEmDigiCluster(ap_uint<12> pt, - int etaCr, - int phiCr, - ap_uint<4> hoe, - ap_uint<2> hoeFlag, - ap_uint<3> iso, - ap_uint<2> isoFlag, - ap_uint<6> fb, + ap_uint<7> eta, + ap_int<7> phi, + ap_uint<6> hoe, + ap_uint<6> iso, + ap_uint<6> shape, + ap_uint<3> wp, ap_uint<5> timing, - ap_uint<2> shapeFlag, - ap_uint<2> brems) { - // To use .range() we need an ap class member - ap_uint<64> temp_data; - ap_uint<7> etaCrDigitized = abs(etaCr); - ap_int<7> phiCrDigitized = phiCr; - - temp_data.range(11, 0) = pt.range(); - temp_data.range(18, 12) = etaCrDigitized.range(); - temp_data.range(25, 19) = phiCrDigitized.range(); - temp_data.range(29, 26) = hoe.range(); - temp_data.range(31, 30) = hoeFlag.range(); - temp_data.range(34, 32) = iso.range(); - temp_data.range(36, 35) = isoFlag.range(); - temp_data.range(42, 37) = fb.range(); - temp_data.range(47, 43) = timing.range(); - temp_data.range(49, 48) = shapeFlag.range(); - temp_data.range(51, 50) = brems.range(); - - clusterData = temp_data; + ap_uint<2> brems, + ap_uint<10> spare) { + clusterData = ((ap_uint<64>)pt) | (((ap_uint<64>)eta) << 12) | (((ap_uint<64>)(phi & 0x7F)) << 19) | + (((ap_uint<64>)hoe) << 26) | (((ap_uint<64>)iso) << 32) | (((ap_uint<64>)shape) << 38) | + (((ap_uint<64>)wp) << 44) | (((ap_uint<64>)timing) << 47) | (((ap_uint<64>)brems << 52)) | + (((ap_uint<64>)spare << 54)); } +#ifdef CMSSW_GIT_HASH // Setters void setRef(const edm::Ref& clusterRef) { clusterRef_ = clusterRef; } void setDigiRef(const edm::Ref& digiClusterRef) { digiClusterRef_ = digiClusterRef; } +#endif // Getters ap_uint<64> data() const { return clusterData; } // Other getters float ptLSB() const { return LSB_PT; } - ap_uint<12> pt() const { return data().range(11, 0); } + ap_uint<12> pt() const { return (clusterData & 0xFFF); } float ptFloat() const { return pt() * ptLSB(); } // crystal eta (unsigned, 7 bits), starting at 0 at real eta = 0, and increasing in the direction of larger abs(real eta) // to convert to real eta, need to know which link this cluster is in - int eta() const { return (ap_uint<7>)data().range(18, 12); } + ap_uint<7> eta() const { return ((clusterData >> 12) & 0x7F); } // crystal phi (signed, 7 bits), relative to center of the SLR // to convert to real phi, need to know which SLR this cluster is in - int phi() const { return (ap_int<7>)data().range(25, 19); } - - // HoE value and flag: not defined yet in the emulator - ap_uint<4> hoe() const { return data().range(29, 26); } - ap_uint<2> hoeFlag() const { return data().range(31, 30); } + ap_int<7> phi() const { return ((clusterData >> 19) & 0x7F); } - // Raw isolation sum: not saved in the emulator - ap_uint<3> iso() const { return data().range(34, 32); } + // HoE value: not defined for EG cluster + ap_uint<6> hoe() const { return ((clusterData >> 26) & 0x3F); } - // iso flag: two bits, least significant bit is the standalone WP (true or false), second bit is the looseTk WP (true or false) - // e.g. 0b01 : standalone iso flag passed, loose Tk iso flag did not pass - ap_uint<2> isoFlags() const { return data().range(36, 35); } - bool passes_iso() const { return (isoFlags() & 0x1); } // standalone iso WP - bool passes_looseTkiso() const { return (isoFlags() & 0x2); } // loose Tk iso WP + // Raw isolation sum + ap_uint<6> iso() const { return ((clusterData >> 32) & 0x3F); } - // fb and timing: not saved in the current emulator - ap_uint<6> fb() const { return data().range(42, 37); } - ap_uint<5> timing() const { return data().range(47, 43); } + // Shape information: et2x5/et5x5 normalized to 0x3F + ap_uint<6> shape() const { return ((clusterData >> 38) & 0x3F); } - // shower shape shape flag: two bits, least significant bit is the standalone WP, second bit is the looseTk WP - // e.g. 0b01 : standalone shower shape flag passed, loose Tk shower shape flag did not pass - ap_uint<2> shapeFlags() const { return data().range(49, 48); } + // Working points: bit 0 standaloneWP, bit 1 looseL1TkMatchWP, bit 2 photonWP + ap_uint<3> wp() const { return ((clusterData >> 44) & 0x7); } - bool passes_ss() const { return (shapeFlags() & 0x1); } // standalone shower shape WP - bool passes_looseTkss() const { return (shapeFlags() & 0x2); } // loose Tk shower shape WP + ap_uint<5> timing() const { return ((clusterData >> 47) & 0x1F); } - // brems: not saved in the current emulator - ap_uint<2> brems() const { return data().range(51, 50); } + // Brem information from RCT + ap_uint<2> brems() const { return ((clusterData >> 52) & 0x3); } - // Check that unused bits are zero - const int unusedBitsStart() const { return n_bits_unused_start; } - bool passNullBitsCheck(void) const { return ((data() >> unusedBitsStart()) == 0); } + // Encoding region information + ap_uint<10> spare() const { return ((clusterData >> 54) & 0x3FF); } +#ifdef CMSSW_GIT_HASH // Get the underlying float cluster const edm::Ref& clusterRef() const { return clusterRef_; } // Get the underlying digitized cluster (before duplication and zero-padding) const edm::Ref& digiClusterRef() const { return digiClusterRef_; } +#endif }; // Collection typedefs diff --git a/DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h b/DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h index 3dfa4a133019e..7a12138a40ba7 100644 --- a/DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h +++ b/DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h @@ -4,7 +4,9 @@ #include #include +#ifdef CMSSW_GIT_HASH #include "DataFormats/L1TCalorimeterPhase2/interface/CaloPFCluster.h" +#endif namespace l1tp2 { @@ -16,57 +18,52 @@ namespace l1tp2 { // Constants static constexpr float LSB_PT = 0.5; // 0.5 GeV - // start of the unused bits - static constexpr int n_bits_unused_start = 31; - +#ifdef CMSSW_GIT_HASH // reference to corresponding float cluster edm::Ref clusterRef_; +#endif public: - GCTHadDigiCluster() { clusterData = 0; } + GCTHadDigiCluster() { clusterData = 0x0; } GCTHadDigiCluster(ap_uint<64> data) { clusterData = data; } - // Note types of the constructor - GCTHadDigiCluster(ap_uint<12> pt, int etaCr, int phiCr, ap_uint<4> hoe) { - // To use .range() we need an ap class member - ap_uint<64> temp_data; - - ap_uint<7> etaCrDigitized = abs(etaCr); - ap_int<7> phiCrDigitized = phiCr; - - temp_data.range(11, 0) = pt.range(); - temp_data.range(18, 12) = etaCrDigitized.range(); - temp_data.range(25, 19) = phiCrDigitized.range(); - - clusterData = temp_data; + GCTHadDigiCluster( + ap_uint<12> pt, ap_uint<7> eta, ap_int<7> phi, ap_uint<12> ecal, ap_uint<6> fb, ap_uint<20> spare) { + clusterData = ((ap_uint<64>)pt) | (((ap_uint<64>)eta) << 12) | (((ap_uint<64>)(phi & 0x7F)) << 19) | + (((ap_uint<64>)ecal) << 26) | (((ap_uint<64>)fb) << 38) | (((ap_uint<64>)spare << 44)); } +#ifdef CMSSW_GIT_HASH // Setters - void setRef(const edm::Ref &clusterRef) { clusterRef_ = clusterRef; } + void setRef(const edm::Ref& clusterRef) { clusterRef_ = clusterRef; } +#endif + // Getters ap_uint<64> data() const { return clusterData; } // Other getters float ptLSB() const { return LSB_PT; } - ap_uint<12> pt() const { return data().range(11, 0); } + ap_uint<12> pt() const { return (clusterData & 0xFFF); } float ptFloat() const { return pt() * ptLSB(); } // crystal eta (unsigned 7 bits) - int eta() const { return (ap_uint<7>)data().range(18, 12); } + ap_uint<7> eta() const { return ((clusterData >> 12) & 0x7F); } // crystal phi (signed 7 bits) - int phi() const { return (ap_int<7>)data().range(25, 19); } + ap_int<7> phi() const { return ((clusterData >> 19) & 0x7F); } - // HoE value - ap_uint<4> hoe() const { return data().range(30, 26); } + ap_uint<12> ecal() const { return ((clusterData >> 26) & 0xFFF); } - // Check that unused bits are zero - const int unusedBitsStart() const { return n_bits_unused_start; } - bool passNullBitsCheck(void) const { return ((data() >> unusedBitsStart()) == 0); } + ap_uint<6> fb() const { return ((clusterData >> 38) & 0x3F); } + // Encoding region information + ap_uint<36> spare() const { return ((clusterData >> 44) & 0xFFFFF); } + +#ifdef CMSSW_GIT_HASH // Get the underlying ref - edm::Ref clusterRef() const { return clusterRef_; } + const edm::Ref& clusterRef() const { return clusterRef_; } +#endif }; // Collection typedefs diff --git a/DataFormats/L1TCalorimeterPhase2/src/classes.h b/DataFormats/L1TCalorimeterPhase2/src/classes.h index e979982097f68..0c9ef90a160bb 100644 --- a/DataFormats/L1TCalorimeterPhase2/src/classes.h +++ b/DataFormats/L1TCalorimeterPhase2/src/classes.h @@ -18,3 +18,5 @@ #include "DataFormats/L1TCalorimeterPhase2/interface/GCTEmDigiCluster.h" #include "DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h" #include "DataFormats/L1TCalorimeterPhase2/interface/Phase2L1CaloJet.h" +#include "DataFormats/L1TCalorimeterPhase2/interface/DigitizedL1CaloJet.h" +#include "DataFormats/L1TCalorimeterPhase2/interface/DigitizedCaloToCorrelatorTM18.h" diff --git a/DataFormats/L1TCalorimeterPhase2/src/classes_def.xml b/DataFormats/L1TCalorimeterPhase2/src/classes_def.xml index d812650d64efd..96ab501c0039d 100644 --- a/DataFormats/L1TCalorimeterPhase2/src/classes_def.xml +++ b/DataFormats/L1TCalorimeterPhase2/src/classes_def.xml @@ -19,8 +19,8 @@ - - + + @@ -77,6 +77,18 @@ + + + + + + + + + + + + diff --git a/DataFormats/L1TParticleFlow/interface/layer1_emulator.h b/DataFormats/L1TParticleFlow/interface/layer1_emulator.h index a3967e318122b..09f69542f0928 100644 --- a/DataFormats/L1TParticleFlow/interface/layer1_emulator.h +++ b/DataFormats/L1TParticleFlow/interface/layer1_emulator.h @@ -273,9 +273,7 @@ namespace l1ct { std::vector>> track; DetectorSector> muon; // muons are global std::vector>> hgcalcluster; - std::vector>> gctHad; // the 48 hadronic clusters from the GCT - std::vector>> gctEm; // the 36 EM clusters from the GCT - // (The trigger towers that follow the clusters are not included in the above data) + std::vector>> gctcluster; // constains both em and pf clusters bool read(std::fstream &from); bool write(std::fstream &to) const; @@ -356,7 +354,7 @@ namespace l1ct { }; struct Event { - enum { VERSION = 14 }; + enum { VERSION = 15 }; uint32_t run, lumi; uint64_t event; RawInputs raw; diff --git a/DataFormats/L1TParticleFlow/src/layer1_emulator.cpp b/DataFormats/L1TParticleFlow/src/layer1_emulator.cpp index 76ee4ececcb34..cfa734fe639f0 100644 --- a/DataFormats/L1TParticleFlow/src/layer1_emulator.cpp +++ b/DataFormats/L1TParticleFlow/src/layer1_emulator.cpp @@ -169,16 +169,8 @@ bool l1ct::RawInputs::read(std::fstream& from) { if (!readVar(from, number)) return false; - gctHad.resize(number); - for (auto& v : gctHad) { - if (!(v.region.read(from) && readMany(from, v.obj))) - return false; - } - - if (!readVar(from, number)) - return false; - gctEm.resize(number); - for (auto& v : gctEm) { + gctcluster.resize(number); + for (auto& v : gctcluster) { if (!(v.region.read(from) && readMany(from, v.obj))) return false; } @@ -208,21 +200,14 @@ bool l1ct::RawInputs::write(std::fstream& to) const { return false; } - number = gctHad.size(); + number = gctcluster.size(); if (!writeVar(number, to)) return false; - for (const auto& v : gctHad) { + for (const auto& v : gctcluster) { if (!(v.region.write(to) && writeMany(v.obj, to))) return false; } - number = gctEm.size(); - if (!writeVar(number, to)) - return false; - for (const auto& v : gctEm) { - if (!(v.region.write(to) && writeMany(v.obj, to))) - return false; - } return true; } void l1ct::RawInputs::clear() { @@ -231,9 +216,7 @@ void l1ct::RawInputs::clear() { muon.clear(); for (auto& h : hgcalcluster) h.clear(); - for (auto& h : gctHad) - h.clear(); - for (auto& h : gctEm) + for (auto& h : gctcluster) h.clear(); } diff --git a/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloBarrelToCorrelator.h b/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloBarrelToCorrelator.h deleted file mode 100644 index d83cdb050a696..0000000000000 --- a/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloBarrelToCorrelator.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef PHASE_2_L1_CALO_BARREL_TO_CORRELATOR -#define PHASE_2_L1_CALO_BARREL_TO_CORRELATOR - -#include "DataFormats/L1TCalorimeterPhase2/interface/GCTEmDigiCluster.h" -#include "DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h" - -#include "L1Trigger/L1CaloTrigger/interface/Phase2L1CaloEGammaUtils.h" - -/* - * Returns the difference in the azimuth coordinates of phi1 and phi2 (all in degrees not radians), taking the wrap-around at 180 degrees into account - */ -inline float p2eg::deltaPhiInDegrees(float phi1, float phi2, const float c = 180) { - float r = std::fmod(phi1 - phi2, 2.0 * c); - if (r < -c) { - r += 2.0 * c; - } else if (r > c) { - r -= 2.0 * c; - } - return r; -} - -/* - * For a given phi in degrees (e.g. computed from some difference), return the phi (in degrees) which takes the wrap-around at 180 degrees into account - */ -inline float p2eg::wrappedPhiInDegrees(float phi) { return p2eg::deltaPhiInDegrees(phi, 0); } - -#endif diff --git a/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloEGammaUtils.h b/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloEGammaUtils.h index 7c4911fb2cd85..5d6616c0ac4e4 100644 --- a/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloEGammaUtils.h +++ b/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloEGammaUtils.h @@ -33,7 +33,7 @@ namespace p2eg { static constexpr int n_towers_Phi = 72; static constexpr int n_towers_halfPhi = 36; static constexpr int n_towers_cardEta = 17; // new: equivalent to n_towers_per_link - static constexpr int n_towers_cardPhi = 4; + static constexpr int n_towers_cardPhi = 5; static constexpr int n_crystals_cardEta = (n_towers_Eta * n_towers_cardEta); static constexpr int n_crystals_cardPhi = (n_towers_Phi * n_towers_cardPhi); @@ -53,7 +53,6 @@ namespace p2eg { static constexpr int CRYSTAL_IN_PHI = 20; // number of crystals in phi, in one 3x4 region (barrel) static constexpr float ECAL_eta_range = 1.4841; - static constexpr float half_crystal_size = 0.00873; static constexpr float slideIsoPtThreshold = 80; static constexpr float a0_80 = 0.85, a1_80 = 0.0080, a0 = 0.21; // passes_iso @@ -86,8 +85,10 @@ namespace p2eg { static constexpr int N_GCTINTERNAL_FIBERS = 64; static constexpr int N_GCTPOSITIVE_FIBERS = 32; static constexpr int N_GCTETA = 34; - static constexpr int N_GCTPHI = 32; + static constexpr int N_GCTPHI = 36; + // Note: this follows old GCT geometry, where each GCT has 8 RCT cards (6 unique) with each RCT having 4 towers in phi + // leading to the offset of 6*4 = 24 towers between two GCT card boundaries // for emulator: "top" of the GCT card in phi is tower idx 20, for GCT card #0: static constexpr int GCTCARD_0_TOWER_IPHI_OFFSET = 20; // same but for GCT cards #1 and 2 (cards wrap around phi = 180 degrees): @@ -98,10 +99,24 @@ namespace p2eg { // Outputs to correlator // Fixed number of EG and PF clusters per RCT card in each output SLR - static const int N_EG_CLUSTERS_PER_RCT_CARD = 9; - static const int N_PF_CLUSTERS_PER_RCT_CARD = 12; + static const int N_EG_CLUSTERS_PER_RCT_CARD = 4; // each eta side + static const int N_PF_CLUSTERS_PER_RCT_CARD = 6; // each eta side // Height of one SLR region in phi in degrees - static constexpr float PHI_RANGE_PER_SLR_DEGREES = 120; + static constexpr float PHI_RANGE_PER_SLR_DEGREES = 120; // including overlap + + // Returns the difference in the azimuth coordinates of phi1 and phi2 (all in degrees not radians), taking the wrap-around at 180 degrees into account + inline float deltaPhiInDegrees(float phi1, float phi2, const float c = 180) { + float r = std::fmod(phi1 - phi2, 2.0 * c); + if (r <= -c) { + r += 2.0 * c; + } else if (r > c) { + r -= 2.0 * c; + } + return r; + } + + // For a given phi in degrees (e.g. computed from some difference), return the phi (in degrees) which takes the wrap-around at 180 degrees into account + inline float wrappedPhiInDegrees(float phi) { return p2eg::deltaPhiInDegrees(phi, 0); } ////////////////////////////////////////////////////////////////////////// // RCT: indexing helper functions @@ -671,33 +686,34 @@ namespace p2eg { void addHoverEToTower(ap_uint<12> ECAL, ap_uint<12> HCAL) { ap_uint<4> hoeOut; ap_uint<1> hoeLSB = 0; - ap_uint<4> hoe = 0; + ap_uint<3> hoe = 0; ap_uint<12> A; ap_uint<12> B; A = (ECAL > HCAL) ? ECAL : HCAL; B = (ECAL > HCAL) ? HCAL : ECAL; - if (ECAL == 0 || HCAL == 0 || HCAL >= ECAL) + if (HCAL >= ECAL) hoeLSB = 0; else hoeLSB = 1; - if (A > B) { - if (A > 2 * B) - hoe = 0x1; - if (A > 4 * B) - hoe = 0x2; - if (A > 8 * B) - hoe = 0x3; - if (A > 16 * B) - hoe = 0x4; - if (A > 32 * B) - hoe = 0x5; - if (A > 64 * B) - hoe = 0x6; - if (A > 128 * B) - hoe = 0x7; - } + if (A > (B << 7)) + hoe = 0b111; + else if (A > (B << 6)) + hoe = 0b110; + else if (A > (B << 5)) + hoe = 0b101; + else if (A > (B << 4)) + hoe = 0b100; + else if (A > (B << 3)) + hoe = 0b011; + else if (A > (B << 2)) + hoe = 0b010; + else if (A > (B << 1)) + hoe = 0b001; + else + hoe = 0b000; + hoeOut = hoeLSB | (hoe << 1); ap_uint<16> hoeOutLong = ((((ap_uint<16>)hoeOut) << 12) | 0x0000); // e.g. 0b ____ 0000 0000 0000 where ___ are the hoe digits @@ -857,13 +873,13 @@ namespace p2eg { // Get real eta const float realEta(int cc) { float size_cell = 2 * ECAL_eta_range / (CRYSTALS_IN_TOWER_ETA * n_towers_Eta); - return crystaliEtaFromCardRegionInfo(cc) * size_cell - ECAL_eta_range + half_crystal_size; + return crystaliEtaFromCardRegionInfo(cc) * size_cell - ECAL_eta_range + (size_cell / 2); } // Get real phi const float realPhi(int cc) { float size_cell = 2 * M_PI / (CRYSTALS_IN_TOWER_PHI * n_towers_Phi); - return crystaliPhiFromCardRegionInfo(cc) * size_cell - M_PI + half_crystal_size; + return crystaliPhiFromCardRegionInfo(cc) * size_cell - M_PI + (size_cell / 2); } // Print info @@ -1045,7 +1061,7 @@ namespace p2eg { inline int standaloneWP() const { return (is_iso && is_ss); } inline int looseL1TkMatchWP() const { return (is_looseTkiso && is_looseTkss); } - inline int photonWP() const { return 1; } // NOTE: NO PHOTON WP + inline int photonWP() const { return (is_looseTkiso && is_looseTkss); } // NOTE: NO PHOTON WP inline int passesShowerShape() const { return is_ss; } @@ -1163,15 +1179,15 @@ namespace p2eg { */ float realEta(void) const { float size_cell = 2 * ECAL_eta_range / (CRYSTALS_IN_TOWER_ETA * n_towers_Eta); - return globalClusteriEta() * size_cell - ECAL_eta_range + half_crystal_size; + return globalClusteriEta() * size_cell - ECAL_eta_range + (size_cell / 2); } /* - * Get GCT cluster's real eta from global iPhi (0-71*5). + * Get GCT cluster's real phi from global iPhi (0-71*5). */ float realPhi(void) const { float size_cell = 2 * M_PI / (CRYSTALS_IN_TOWER_PHI * n_towers_Phi); - return globalClusteriPhi() * size_cell - M_PI + half_crystal_size; + return globalClusteriPhi() * size_cell - M_PI + (size_cell / 2); } /* @@ -1256,20 +1272,70 @@ namespace p2eg { * unique to each GCT card. */ l1tp2::DigitizedClusterCorrelator createDigitizedClusterCorrelator(const int corrTowPhiOffset) const { + ap_uint<7> abseta = 0; + ap_uint<10> spare = 0; + if (globalClusteriEta() >= n_towers_cardEta * CRYSTALS_IN_TOWER_ETA) { + abseta = globalClusteriEta() - n_towers_cardEta * CRYSTALS_IN_TOWER_ETA; // 0 to 84 + spare = 4; + } else { + abseta = n_towers_cardEta * CRYSTALS_IN_TOWER_ETA - globalClusteriEta() - 1; // 84 to 0 + spare = 0; + } + + //// Use towPhi to determine relative phi when clusters are assigned to corect GCT card + //ap_int<8> tmpphi = (((towPhi - corrTowPhiOffset) * CRYSTALS_IN_TOWER_PHI) + crPhi) ; // range between 0 to 120 + //if (tmpphi < PHI_RANGE_PER_SLR_DEGREES/2) {spare = spare | 3;} + //else { tmpphi = tmpphi - PHI_RANGE_PER_SLR_DEGREES/2 ; spare = spare | 1 ;} // set to range between 0 to 60 + //ap_int<7> phivscenter = ap_int<7>(tmpphi - PHI_RANGE_PER_SLR_DEGREES/4) ; // set to range between -30 to 30 + + // Use realPhi() to determine relative phi as current GCT card assignment uses old geometry + // This is emulator specific to bypass geometry issue + int cardnumber = 0; + float regionCentersInDegrees[6] = {10.0, 70.0, 130.0, -170.0, -110.0, -50.0}; + float clusterRealPhiAsDegree = realPhi() * 180 / M_PI; + ap_int<7> phivscenter = 0; + for (int i = 0; i < 6; i++) { + float tempDifference = p2eg::deltaPhiInDegrees(clusterRealPhiAsDegree, regionCentersInDegrees[i]); + if (abs(tempDifference) < PHI_RANGE_PER_SLR_DEGREES / 4) { + phivscenter = 0x7F & int(std::floor(tempDifference)); // greatest integer <= x + cardnumber = int(i / 2); + } + } + + float cardCentersInDegrees[3] = {40., 160., -80.}; + if (p2eg::deltaPhiInDegrees(clusterRealPhiAsDegree, cardCentersInDegrees[cardnumber]) > 0) { + spare = spare | 3; + } else { + spare = spare | 1; + } + + ap_uint<6> shape = (64 * et2x5 / et5x5) + 0.5f; // normalize to 0x3F + ap_uint<3> quality = + (standaloneWP() * std::pow(2, 0)) + (looseL1TkMatchWP() * std::pow(2, 1)) + (photonWP() * std::pow(2, 2)); + + // normalize relIso to 0x3F + float reliso_f = isoFloat() * 4.0f / etFloat(); // LSB = 16/64 to compress the useful range (0-16) in 6 bits + // implement saturation + if (reliso_f < 0.0f) + reliso_f = 0.0f; + if (reliso_f > 63.0f) + reliso_f = 63.0f; + + // normalize hoe to 0x3F + int hoe_int = (int)(hoe * 63 / 15); + return l1tp2::DigitizedClusterCorrelator( - etFloat(), // technically we are just multiplying and then dividing again by the LSB - globalClusteriEta(), - ((towPhi - corrTowPhiOffset) * CRYSTALS_IN_TOWER_PHI) + - crPhi, // cannot use globalClusteriPhi() helper function because correlator offset is different than GCT offset - hoe, - hoe_flag, - iso, - (is_iso) | (is_looseTkiso << 1), // 2 bits: e.g. 0b10 means is_looseTkiso was true, and is_iso was false - fb, - timing, - (is_ss) | (is_looseTkss << 1), // 2 bits (same as iso flags) is_ss in lowest bit, is_looseTkss in higher bit - brems, - nGCTCard); + et, // technically we are just multiplying and then dividing again by the LSB + abseta, + phivscenter, + ap_uint<6>(hoe_int & 0x3F), + ap_uint<6>(reliso_f + 0.5f), // rounding + ap_uint<6>(shape), + ap_uint<3>(quality), + ap_uint<5>(timing), + ap_uint<2>(brems), + ap_uint<10>(spare), + cardnumber); } /* @@ -1317,7 +1383,9 @@ namespace p2eg { inline float totalEtFloat() const { return ((float)et * ECAL_LSB); } // Return total energy as a float (assuming the energy uses the ECAL LSB convention) + inline float ecalEtFloat() const { return ((float)ecalEt * ECAL_LSB); } // Return ECAL energy as a float + inline float hcalEtFloat() const { return ((float)hcalEt * HCAL_LSB); } // Return HCAL energy as a float, use HCAL LSB @@ -1328,8 +1396,44 @@ namespace p2eg { void initFromRCTTower(const RCTtower_t& rctTower) { et = rctTower.et; hoe = rctTower.hoe; - ecalEt = rctTower.ecalEt; - hcalEt = rctTower.hcalEt; + // get E and H from et and hoe + ap_uint<12> A = et >> (hoe >> 1); + ap_uint<12> B = et - A; + ecalEt = ((hoe & 0x1) == 1) ? B : A; + hcalEt = ((hoe & 0x1) == 1) ? A : B; + } + + void addHoverEToTower(ap_uint<12> ECAL, ap_uint<12> HCAL) { + ap_uint<3> hoeOut; + ap_uint<1> hoeLSB = 0; + ap_uint<12> A; + ap_uint<12> B; + + A = (ECAL > HCAL) ? ECAL : HCAL; + B = (ECAL > HCAL) ? HCAL : ECAL; + + if (HCAL >= ECAL) + hoeLSB = 0; + else + hoeLSB = 1; + if (A > (B << 7)) + hoeOut = 0b111; + else if (A > (B << 6)) + hoeOut = 0b110; + else if (A > (B << 5)) + hoeOut = 0b101; + else if (A > (B << 4)) + hoeOut = 0b100; + else if (A > (B << 3)) + hoeOut = 0b011; + else if (A > (B << 2)) + hoeOut = 0b010; + else if (A > (B << 1)) + hoeOut = 0b001; + else + hoeOut = 0b000; + + hoe = hoeLSB | (hoeOut << 1); } /* @@ -1409,8 +1513,8 @@ namespace p2eg { */ l1tp2::CaloTower createCaloTowerFromFiberIdx(int nGCTCard, int iFiber, int iTowerInFiber) { l1tp2::CaloTower l1CaloTower; - l1CaloTower.setEcalTowerEt(ecalEtFloat()); // float: ECAL divide by 8.0 - l1CaloTower.setHcalTowerEt(hcalEtFloat()); // float: HCAL multiply by LSB + l1CaloTower.setEcalTowerEt(ecalEtFloat()); + l1CaloTower.setHcalTowerEt(hcalEtFloat()); int global_tower_iEta = globalToweriEta(nGCTCard, iFiber, iTowerInFiber); int global_tower_iPhi = globalToweriPhi(nGCTCard, iFiber, iTowerInFiber); l1CaloTower.setTowerIEta(global_tower_iEta); @@ -1425,9 +1529,8 @@ namespace p2eg { */ l1tp2::CaloTower createFullTowerFromCardIdx(int nGCTCard, int gctCard_tower_iEta, int gctCard_tower_iPhi) { l1tp2::CaloTower l1CaloTower; - // Store total Et (HCAL+ECAL) in the ECAL Et member - l1CaloTower.setEcalTowerEt(totalEtFloat()); - l1CaloTower.setHcalTowerEt(ecalEtFloat()); + l1CaloTower.setEcalTowerEt(ecalEtFloat()); + l1CaloTower.setHcalTowerEt(hcalEtFloat()); int global_tower_iEta = globalToweriEtaFromGCTcardiEta(gctCard_tower_iEta); int global_tower_iPhi = globalToweriPhiFromGCTcardiPhi(nGCTCard, gctCard_tower_iPhi); l1CaloTower.setTowerIEta(global_tower_iEta); @@ -1670,12 +1773,6 @@ namespace p2eg { int corrFiberIndexOffset, int corrTowPhiOffset); - /*******************************************************************************************/ - /* Interface to correlator helper functions (defined in Phase2L1CaloBarrelToCorrelator.h) */ - /*******************************************************************************************/ - float deltaPhiInDegrees(float phi1, float phi2, const float c); - float wrappedPhiInDegrees(float phi); - /* * Generic function to compare hadronic (had) or EM digi clusters. */ diff --git a/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloPFClusterEmulator.h b/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloPFClusterEmulator.h index 2fedbafe06d7c..ff5468355d85c 100644 --- a/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloPFClusterEmulator.h +++ b/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloPFClusterEmulator.h @@ -31,20 +31,15 @@ namespace gctpf { typedef struct { float et; + float ecal; int eta; int phi; - } GCTpfcluster_t; + } GCTint_t; typedef struct { - GCTpfcluster_t GCTpfclusters[nPFClusterSLR]; + GCTint_t GCTpfclusters[nPFClusterSLR]; } PFcluster_t; - typedef struct { - float et; - int eta; - int phi; - } GCTint_t; - typedef struct { GCTint_t t[nTowerPhiSLR]; } GCTEtaStrip_t; @@ -173,12 +168,13 @@ namespace gctpf { return max; } - inline Region_t initStructure(float temp[nTowerEtaSLR][nTowerPhiSLR]) { + inline Region_t initStructure(std::pair temp[nTowerEtaSLR][nTowerPhiSLR]) { Region_t r; for (int i = 0; i < nTowerPhiSLR; i++) { for (int j = 0; j < nTowerEtaSLR; j++) { - r.s[j].t[i].et = temp[j][i]; + r.s[j].t[i].et = temp[j][i].first; + r.s[j].t[i].ecal = temp[j][i].second; r.s[j].t[i].eta = j; r.s[j].t[i].phi = i; } @@ -193,6 +189,7 @@ namespace gctpf { for (int i = 0; i < nHfPhi / 6; i++) { for (int j = 0; j < nHfEta; j++) { r.s[j].t[i].et = temp[j][i]; + r.s[j].t[i].ecal = 0.; r.s[j].t[i].eta = j; r.s[j].t[i].phi = i; } @@ -201,20 +198,23 @@ namespace gctpf { return r; } - inline float getEt(float temp[nTowerEtaSLR][nTowerPhiSLR], int eta, int phi) { + inline std::pair getEt(std::pair temp[nTowerEtaSLR][nTowerPhiSLR], int eta, int phi) { float et_sumEta[3] = {0., 0., 0.}; + float ecal_sumEta[3] = {0., 0., 0.}; for (int i = 0; i < (nTowerEtaSLR - 2); i++) { for (int j = 0; j < (nTowerPhiSLR - 2); j++) { if (i + 1 == eta && j + 1 == phi) { for (int k = 0; k < 3; k++) { - et_sumEta[k] = temp[i + k][j] + temp[i + k][j + 1] + temp[i + k][j + 2]; + et_sumEta[k] = temp[i + k][j].first + temp[i + k][j + 1].first + temp[i + k][j + 2].first; + ecal_sumEta[k] = temp[i + k][j].second + temp[i + k][j + 1].second + temp[i + k][j + 2].second; } } } } - float pfcluster_et = et_sumEta[0] + et_sumEta[1] + et_sumEta[2]; + std::pair pfcluster_et = + std::make_pair(et_sumEta[0] + et_sumEta[1] + et_sumEta[2], ecal_sumEta[0] + ecal_sumEta[1] + ecal_sumEta[2]); return pfcluster_et; } @@ -250,12 +250,12 @@ namespace gctpf { return pfcluster_et; } - inline void RemoveTmp(float temp[nTowerEtaSLR][nTowerPhiSLR], int eta, int phi) { + inline void RemoveTmp(std::pair temp[nTowerEtaSLR][nTowerPhiSLR], int eta, int phi) { for (int i = 0; i < nTowerEtaSLR; i++) { if (i + 1 >= eta && i <= eta + 1) { for (int j = 0; j < nTowerPhiSLR; j++) { if (j + 1 >= phi && j <= phi + 1) { - temp[i][j] = 0; + temp[i][j] = std::make_pair(0., 0.); } } } @@ -278,8 +278,10 @@ namespace gctpf { return; } - inline GCTpfcluster_t recoPfcluster(float temporary[nTowerEtaSLR][nTowerPhiSLR], int etaoffset, int phioffset) { - GCTpfcluster_t pfclusterReturn; + inline GCTint_t recoPfcluster(std::pair temporary[nTowerEtaSLR][nTowerPhiSLR], + int etaoffset, + int phioffset) { + GCTint_t pfclusterReturn; Region_t region; @@ -287,28 +289,30 @@ namespace gctpf { GCTint_t regionMax = getPeakPosition(region); - float pfcluster_et = getEt(temporary, regionMax.eta, regionMax.phi); - float pfcluster_eta = regionMax.eta - 2 + etaoffset; - float pfcluster_phi = regionMax.phi - 2 + phioffset; + std::pair pfcluster_et = getEt(temporary, regionMax.eta, regionMax.phi); + float pfcluster_eta = regionMax.eta + etaoffset; + float pfcluster_phi = regionMax.phi + phioffset; RemoveTmp(temporary, regionMax.eta, regionMax.phi); if (!(regionMax.eta >= 2 && regionMax.eta < (nTowerEtaSLR - 2) && regionMax.phi >= 2 && regionMax.phi < (nTowerPhiSLR - 2))) { - pfcluster_et = 0; // set energy to be zero if maximum energy tower is not within the unique region - pfcluster_eta = 2; // choose the default to be at one corner of the unique region - pfcluster_phi = 2; // choose the default to be at one corner of the unique region + pfcluster_et = + std::make_pair(0., 0.); // set energy to be zero if maximum energy tower is not within the unique region + pfcluster_eta = 2; // choose the default to be at one corner of the unique region + pfcluster_phi = 2; // choose the default to be at one corner of the unique region } - pfclusterReturn.et = pfcluster_et; + pfclusterReturn.et = pfcluster_et.first; + pfclusterReturn.ecal = pfcluster_et.second; pfclusterReturn.eta = pfcluster_eta; pfclusterReturn.phi = pfcluster_phi; return pfclusterReturn; } - inline GCTpfcluster_t recoPfclusterHF(float temporary[nHfEta][nHfPhi / 6], int etaoffset, int phioffset) { - GCTpfcluster_t pfclusterReturn; + inline GCTint_t recoPfclusterHF(float temporary[nHfEta][nHfPhi / 6], int etaoffset, int phioffset) { + GCTint_t pfclusterReturn; RegionHF_t region; @@ -321,6 +325,7 @@ namespace gctpf { RemoveTmpHF(temporary, regionMax.eta, regionMax.phi); pfclusterReturn.et = pfcluster_et; + pfclusterReturn.ecal = 0.; pfclusterReturn.eta = regionMax.eta + etaoffset; pfclusterReturn.phi = regionMax.phi + phioffset; if (pfclusterReturn.phi < 0) @@ -329,8 +334,10 @@ namespace gctpf { return pfclusterReturn; } - inline PFcluster_t pfcluster(float temporary[nTowerEtaSLR][nTowerPhiSLR], int etaoffset, int phioffset) { - GCTpfcluster_t pfcluster[nPFClusterSLR]; + inline PFcluster_t pfcluster(std::pair temporary[nTowerEtaSLR][nTowerPhiSLR], + int etaoffset, + int phioffset) { + GCTint_t pfcluster[nPFClusterSLR]; for (int i = 0; i < nPFClusterSLR; i++) { pfcluster[i] = recoPfcluster(temporary, etaoffset, phioffset); @@ -340,6 +347,7 @@ namespace gctpf { for (int i = 0; i < nPFClusterSLR; i++) { GCTPfclusters.GCTpfclusters[i].et = pfcluster[i].et; + GCTPfclusters.GCTpfclusters[i].ecal = pfcluster[i].ecal; GCTPfclusters.GCTpfclusters[i].eta = pfcluster[i].eta; GCTPfclusters.GCTpfclusters[i].phi = pfcluster[i].phi; } @@ -348,7 +356,7 @@ namespace gctpf { } inline PFcluster_t pfclusterHF(float temporary[nHfEta][nHfPhi / 6], int etaoffset, int phioffset) { - GCTpfcluster_t pfcluster[nPFClusterSLR]; + GCTint_t pfcluster[nPFClusterSLR]; for (int i = 0; i < nPFClusterSLR; i++) { pfcluster[i] = recoPfclusterHF(temporary, etaoffset, phioffset); diff --git a/L1Trigger/L1CaloTrigger/interface/Phase2L1GCT.h b/L1Trigger/L1CaloTrigger/interface/Phase2L1GCT.h index 3f2b02aa49d44..6c5ed035dcb44 100644 --- a/L1Trigger/L1CaloTrigger/interface/Phase2L1GCT.h +++ b/L1Trigger/L1CaloTrigger/interface/Phase2L1GCT.h @@ -240,7 +240,6 @@ inline p2eg::GCTintTowers_t p2eg::getFullTowers(const p2eg::GCTinternal_t& GCTin ap_uint<15> phi = i + i1; ap_uint<15> eta = p2eg::N_GCTETA / 2 + k; GCTintTowers.GCTtower[eta][phi].et = GCTinternal.GCTCorrfiber[phi].GCTtowers[k].et; - GCTintTowers.GCTtower[eta][phi].hoe = GCTinternal.GCTCorrfiber[phi].GCTtowers[k].hoe; GCTintTowers.GCTtower[eta][phi].ecalEt = GCTinternal.GCTCorrfiber[phi].GCTtowers[k].ecalEt; GCTintTowers.GCTtower[eta][phi].hcalEt = GCTinternal.GCTCorrfiber[phi].GCTtowers[k].hcalEt; for (int ic1 = 0; ic1 < 4; ic1++) { @@ -250,9 +249,13 @@ inline p2eg::GCTintTowers_t p2eg::getFullTowers(const p2eg::GCTinternal_t& GCTin if (eta == eta1 && phi == phi1) { GCTintTowers.GCTtower[eta][phi].et = (GCTintTowers.GCTtower[eta][phi].et + GCTinternal.GCTCorrfiber[i + ic1].GCTclusters[jc].et); + GCTintTowers.GCTtower[eta][phi].ecalEt = + (GCTintTowers.GCTtower[eta][phi].ecalEt + GCTinternal.GCTCorrfiber[i + ic1].GCTclusters[jc].et); } } } + GCTintTowers.GCTtower[eta][phi].addHoverEToTower(GCTintTowers.GCTtower[eta][phi].ecalEt, + GCTintTowers.GCTtower[eta][phi].hcalEt); } } } @@ -264,7 +267,6 @@ inline p2eg::GCTintTowers_t p2eg::getFullTowers(const p2eg::GCTinternal_t& GCTin ap_uint<15> eta = p2eg::N_GCTETA / 2 - k - 1; ap_uint<15> phi = i + i1 - p2eg::N_GCTPOSITIVE_FIBERS; GCTintTowers.GCTtower[eta][phi].et = GCTinternal.GCTCorrfiber[i + i1].GCTtowers[k].et; - GCTintTowers.GCTtower[eta][phi].hoe = GCTinternal.GCTCorrfiber[i + i1].GCTtowers[k].hoe; GCTintTowers.GCTtower[eta][phi].ecalEt = GCTinternal.GCTCorrfiber[i + i1].GCTtowers[k].ecalEt; GCTintTowers.GCTtower[eta][phi].hcalEt = GCTinternal.GCTCorrfiber[i + i1].GCTtowers[k].hcalEt; for (int ic1 = 0; ic1 < 4; ic1++) { @@ -274,9 +276,13 @@ inline p2eg::GCTintTowers_t p2eg::getFullTowers(const p2eg::GCTinternal_t& GCTin if (eta == eta1 && phi == phi1) { GCTintTowers.GCTtower[eta][phi].et = (GCTintTowers.GCTtower[eta][phi].et + GCTinternal.GCTCorrfiber[i + ic1].GCTclusters[jc].et); + GCTintTowers.GCTtower[eta][phi].ecalEt = + (GCTintTowers.GCTtower[eta][phi].ecalEt + GCTinternal.GCTCorrfiber[i + ic1].GCTclusters[jc].et); } } } + GCTintTowers.GCTtower[eta][phi].addHoverEToTower(GCTintTowers.GCTtower[eta][phi].ecalEt, + GCTintTowers.GCTtower[eta][phi].hcalEt); } } } diff --git a/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloJetEmulator.cc b/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloJetEmulator.cc index b5172f5ac6459..eb50b56cc9a54 100644 --- a/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloJetEmulator.cc +++ b/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloJetEmulator.cc @@ -237,8 +237,8 @@ void Phase2L1CaloJetEmulator::produce(edm::Event& iEvent, const edm::EventSetup& for (const l1tp2::CaloTower& i : *caloTowerCollection) { int ieta = i.towerIEta(); int iphi = i.towerIPhi(); - if (i.ecalTowerEt() > 1.) - GCTintTowers[ieta][iphi] = i.ecalTowerEt(); // suppress <= 1 GeV towers + if (i.ecalTowerEt() + i.hcalTowerEt() > 1.) + GCTintTowers[ieta][iphi] = i.ecalTowerEt() + i.hcalTowerEt(); // suppress <= 1 GeV towers else GCTintTowers[ieta][iphi] = 0; realEta[ieta][iphi] = i.towerEta(); diff --git a/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloPFClusterEmulator.cc b/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloPFClusterEmulator.cc index 935e9ed1cd387..fd9b1be94c564 100644 --- a/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloPFClusterEmulator.cc +++ b/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloPFClusterEmulator.cc @@ -91,22 +91,24 @@ void Phase2L1CaloPFClusterEmulator::produce(edm::Event& iEvent, const edm::Event cms::Exception("Phase2L1CaloPFClusterEmulator") << "Failed to get towers from caloTowerCollection!"; float GCTintTowers[nTowerEta][nTowerPhi]; + float GCTintTowersEcal[nTowerEta][nTowerPhi]; float realEta[nTowerEta][nTowerPhi]; float realPhi[nTowerEta][nTowerPhi]; for (const l1tp2::CaloTower& i : *caloTowerCollection) { int ieta = i.towerIEta(); int iphi = i.towerIPhi(); - GCTintTowers[ieta][iphi] = i.ecalTowerEt(); + GCTintTowers[ieta][iphi] = i.ecalTowerEt() + i.hcalTowerEt(); + GCTintTowersEcal[ieta][iphi] = i.ecalTowerEt(); realEta[ieta][iphi] = i.towerEta(); realPhi[ieta][iphi] = i.towerPhi(); } - float regions[nSLR][nTowerEtaSLR][nTowerPhiSLR]; + std::pair regions[nSLR][nTowerEtaSLR][nTowerPhiSLR]; for (int ieta = 0; ieta < nTowerEtaSLR; ieta++) { for (int iphi = 0; iphi < nTowerPhiSLR; iphi++) { for (int k = 0; k < nSLR; k++) { - regions[k][ieta][iphi] = 0.; + regions[k][ieta][iphi] = std::make_pair(0., 0.); } } } @@ -117,28 +119,34 @@ void Phase2L1CaloPFClusterEmulator::produce(edm::Event& iEvent, const edm::Event for (int iphi = 0; iphi < nTowerPhiSLR; iphi++) { if (ieta > 1) { if (iphi > 1) - regions[0][ieta][iphi] = GCTintTowers[ieta - 2][iphi - 2]; + regions[0][ieta][iphi] = + std::make_pair(GCTintTowers[ieta - 2][iphi - 2], GCTintTowersEcal[ieta - 2][iphi - 2]); for (int k = 1; k < 17; k++) { - regions[k * 2][ieta][iphi] = GCTintTowers[ieta - 2][iphi + k * 4 - 2]; + regions[k * 2][ieta][iphi] = + std::make_pair(GCTintTowers[ieta - 2][iphi + k * 4 - 2], GCTintTowersEcal[ieta - 2][iphi + k * 4 - 2]); } if (iphi < 6) - regions[34][ieta][iphi] = GCTintTowers[ieta - 2][iphi + 66]; + regions[34][ieta][iphi] = + std::make_pair(GCTintTowers[ieta - 2][iphi + 66], GCTintTowersEcal[ieta - 2][iphi + 66]); } if (ieta < 19) { if (iphi > 1) - regions[1][ieta][iphi] = GCTintTowers[ieta + 15][iphi - 2]; + regions[1][ieta][iphi] = + std::make_pair(GCTintTowers[ieta + 15][iphi - 2], GCTintTowersEcal[ieta + 15][iphi - 2]); for (int k = 1; k < 17; k++) { - regions[k * 2 + 1][ieta][iphi] = GCTintTowers[ieta + 15][iphi + k * 4 - 2]; + regions[k * 2 + 1][ieta][iphi] = + std::make_pair(GCTintTowers[ieta + 15][iphi + k * 4 - 2], GCTintTowersEcal[ieta + 15][iphi + k * 4 - 2]); } if (iphi < 6) - regions[35][ieta][iphi] = GCTintTowers[ieta + 15][iphi + 66]; + regions[35][ieta][iphi] = + std::make_pair(GCTintTowers[ieta + 15][iphi + 66], GCTintTowersEcal[ieta + 15][iphi + 66]); } } } - float temporary[nTowerEtaSLR][nTowerPhiSLR]; + std::pair temporary[nTowerEtaSLR][nTowerPhiSLR]; int etaoffset = 0; - int phioffset = 0; + int phioffset = -2; //Use same code from firmware for finding clusters for (int k = 0; k < nSLR; k++) { @@ -148,7 +156,7 @@ void Phase2L1CaloPFClusterEmulator::produce(edm::Event& iEvent, const edm::Event } } if (k % 2 == 0) - etaoffset = 0; + etaoffset = -2; else etaoffset = nTowerEta / 2 - 2; if (k > 1 && k % 2 == 0) @@ -162,19 +170,21 @@ void Phase2L1CaloPFClusterEmulator::produce(edm::Event& iEvent, const edm::Event int gctphi = tempPfclusters.GCTpfclusters[i].phi; float towereta = realEta[gcteta][gctphi]; float towerphi = realPhi[gcteta][gctphi]; - l1tp2::CaloPFCluster l1CaloPFCluster; - l1CaloPFCluster.setClusterEt(tempPfclusters.GCTpfclusters[i].et); - l1CaloPFCluster.setClusterIEta(gcteta); - l1CaloPFCluster.setClusterIPhi(gctphi); - l1CaloPFCluster.setClusterEta(towereta); - l1CaloPFCluster.setClusterPhi(towerphi); + reco::Particle::PolarLorentzVector clusterP4(tempPfclusters.GCTpfclusters[i].et, towereta, towerphi, 0); + l1tp2::CaloPFCluster l1CaloPFCluster(clusterP4, + tempPfclusters.GCTpfclusters[i].et, + tempPfclusters.GCTpfclusters[i].ecal, + gcteta, + gctphi, + towereta, + towerphi); pfclusterCands->push_back(l1CaloPFCluster); } } edm::Handle hfHandle; if (!iEvent.getByToken(hfToken_, hfHandle)) - edm::LogError("Phase2L1CaloJetEmulator") << "Failed to get HcalTrigPrimDigi for HF!"; + edm::LogError("Phase2L1CaloPFClusterEmulator") << "Failed to get HcalTrigPrimDigi for HF!"; iEvent.getByToken(hfToken_, hfHandle); float hfTowers[2 * nHfEta][nHfPhi]; // split 12 -> 24 @@ -298,6 +308,7 @@ void Phase2L1CaloPFClusterEmulator::produce(edm::Event& iEvent, const edm::Event float towerphi = hfPhi[hfeta][hfphi]; l1tp2::CaloPFCluster l1CaloPFCluster; l1CaloPFCluster.setClusterEt(tempPfclustersHF.GCTpfclusters[i].et); + l1CaloPFCluster.setEcalEt(0.); l1CaloPFCluster.setClusterIEta(hfeta); l1CaloPFCluster.setClusterIPhi(hfphi); l1CaloPFCluster.setClusterEta(towereta); diff --git a/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloToCorrelatorTM18.cc b/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloToCorrelatorTM18.cc new file mode 100644 index 0000000000000..0ad9fba4d37ba --- /dev/null +++ b/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloToCorrelatorTM18.cc @@ -0,0 +1,287 @@ +/* AS */ + +// system include files +#include + +#include +#include + +// user include files +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" + +#include "DataFormats/L1TCalorimeterPhase2/interface/GCTEmDigiCluster.h" +#include "DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h" +#include "DataFormats/L1TCalorimeterPhase2/interface/DigitizedCaloToCorrelatorTM18.h" + +class Phase2L1CaloToCorrelatorTM18 : public edm::stream::EDProducer<> { +public: + explicit Phase2L1CaloToCorrelatorTM18(const edm::ParameterSet&); + ~Phase2L1CaloToCorrelatorTM18() override = default; + + static void fillDescriptions(edm::ConfigurationDescriptions&); + +private: + void produce(edm::Event&, const edm::EventSetup&) override; + edm::EDGetTokenT gctEmDigiClustersSrc_; + edm::EDGetTokenT gctHadDigiClustersSrc_; +}; + +Phase2L1CaloToCorrelatorTM18::Phase2L1CaloToCorrelatorTM18(const edm::ParameterSet& cfg) + : gctEmDigiClustersSrc_( + consumes(cfg.getParameter("gctEmDigiClusters"))), + gctHadDigiClustersSrc_( + consumes(cfg.getParameter("gctHadDigiClusters"))) { + produces("DigitizedCaloToCorrelatorTM18"); +} + +void Phase2L1CaloToCorrelatorTM18::produce(edm::Event& evt, const edm::EventSetup& es) { + using namespace edm; + std::unique_ptr caloCandsTM18( + std::make_unique()); + + int EM_SLR1_POS_OFFSET = 1; + int EM_SLR1_NEG_OFFSET = 17; + int PF_SLR1_POS_OFFSET = 33; + int PF_SLR1_NEG_OFFSET = 57; + int EM_SLR3_POS_OFFSET = 82; + int EM_SLR3_NEG_OFFSET = 98; + int PF_SLR3_POS_OFFSET = 114; + int PF_SLR3_NEG_OFFSET = 138; + int NUM_EM_WORDS = 16; + int NUM_PF_WORDS = 24; + + int cntr03pos = 0; + int cntr03neg = 0; + int cntr01pos = 0; + int cntr01neg = 0; + + int cntr13pos = 0; + int cntr13neg = 0; + int cntr11pos = 0; + int cntr11neg = 0; + + int cntr23pos = 0; + int cntr23neg = 0; + int cntr21pos = 0; + int cntr21neg = 0; + + ap_uint<64> mydata = 0; + ap_uint<64> dataToCL1Card0[162] = {0}; + ap_uint<64> dataToCL1Card1[162] = {0}; + ap_uint<64> dataToCL1Card2[162] = {0}; + l1tp2::GCTDigiClusterLink clusterCollCard0(162); + l1tp2::GCTDigiClusterLink clusterCollCard1(162); + l1tp2::GCTDigiClusterLink clusterCollCard2(162); + + // SLR1 and SLR3 both send 24 PFclusters each from +ve and -ve eta, total 48 words: 4x12(x64b) + + edm::Handle gctHadDigiClusters; + if (evt.getByToken(gctHadDigiClustersSrc_, gctHadDigiClusters)) { + for (int iLink = 0; iLink < 12; iLink++) { + // in order: + // GCT1 SLR3 +ve, GCT1 SLR3 -ve, GCT1 SLR1 +ve, GCT1 SLR1 -ve + // GCT2 SLR3 +ve, GCT2 SLR3 -ve, GCT2 SLR1 +ve, GCT2 SLR1 -ve + // GCT3 SLR3 +ve, GCT3 SLR3 -ve, GCT3 SLR1 +ve, GCT3 SLR1 -ve + int iGCT = (iLink / 4); + // 4 RCT regions per GCT + int iRCT = iLink - iGCT * 4; + // Eta: positive or negative depends on the link. If iLink is even, it is in positive eta + bool isNegativeEta = (iRCT % 2 == 1); + // SLR alternates every two links + bool isSLR3 = ((iLink % 4) < 2); + bool isSLR1 = !isSLR3; + for (const auto& cluster : (*gctHadDigiClusters).at(iLink)) { + mydata = cluster.data(); + + if ((iGCT == 0) && isSLR1 && !isNegativeEta && (cntr01pos < NUM_PF_WORDS)) { + dataToCL1Card0[PF_SLR1_POS_OFFSET + cntr01pos] = mydata; + clusterCollCard0[PF_SLR1_POS_OFFSET + cntr01pos] = cluster; + cntr01pos++; + } + if ((iGCT == 1) && isSLR1 && !isNegativeEta && (cntr11pos < NUM_PF_WORDS)) { + dataToCL1Card1[PF_SLR1_POS_OFFSET + cntr11pos] = mydata; + clusterCollCard1[PF_SLR1_POS_OFFSET + cntr11pos] = cluster; + cntr11pos++; + } + if ((iGCT == 2) && isSLR1 && !isNegativeEta && (cntr21pos < NUM_PF_WORDS)) { + dataToCL1Card2[PF_SLR1_POS_OFFSET + cntr21pos] = mydata; + clusterCollCard2[PF_SLR1_POS_OFFSET + cntr21pos] = cluster; + cntr21pos++; + } + if ((iGCT == 0) && isSLR1 && isNegativeEta && (cntr01neg < NUM_PF_WORDS)) { + dataToCL1Card0[PF_SLR1_NEG_OFFSET + cntr01neg] = mydata; + clusterCollCard0[PF_SLR1_NEG_OFFSET + cntr01neg] = cluster; + cntr01neg++; + } + if ((iGCT == 1) && isSLR1 && isNegativeEta && (cntr11neg < NUM_PF_WORDS)) { + dataToCL1Card1[PF_SLR1_NEG_OFFSET + cntr11neg] = mydata; + clusterCollCard1[PF_SLR1_NEG_OFFSET + cntr11neg] = cluster; + cntr11neg++; + } + if ((iGCT == 2) && isSLR1 && isNegativeEta && (cntr21neg < NUM_PF_WORDS)) { + dataToCL1Card2[PF_SLR1_NEG_OFFSET + cntr21neg] = mydata; + clusterCollCard2[PF_SLR1_NEG_OFFSET + cntr21neg] = cluster; + cntr21neg++; + } + if ((iGCT == 0) && isSLR3 && !isNegativeEta && (cntr03pos < NUM_PF_WORDS)) { + dataToCL1Card0[PF_SLR3_POS_OFFSET + cntr03pos] = mydata; + clusterCollCard0[PF_SLR3_POS_OFFSET + cntr03pos] = cluster; + cntr03pos++; + } + if ((iGCT == 1) && isSLR3 && !isNegativeEta && (cntr13pos < NUM_PF_WORDS)) { + dataToCL1Card1[PF_SLR3_POS_OFFSET + cntr13pos] = mydata; + clusterCollCard1[PF_SLR3_POS_OFFSET + cntr13pos] = cluster; + cntr13pos++; + } + if ((iGCT == 2) && isSLR3 && !isNegativeEta && (cntr23pos < NUM_PF_WORDS)) { + dataToCL1Card2[PF_SLR3_POS_OFFSET + cntr23pos] = mydata; + clusterCollCard2[PF_SLR3_POS_OFFSET + cntr23pos] = cluster; + cntr23pos++; + } + if ((iGCT == 0) && isSLR3 && isNegativeEta && (cntr03neg < NUM_PF_WORDS)) { + dataToCL1Card0[PF_SLR3_NEG_OFFSET + cntr03neg] = mydata; + clusterCollCard0[PF_SLR3_NEG_OFFSET + cntr03neg] = cluster; + cntr03neg++; + } + if ((iGCT == 1) && isSLR3 && isNegativeEta && (cntr13neg < NUM_PF_WORDS)) { + dataToCL1Card1[PF_SLR3_NEG_OFFSET + cntr13neg] = mydata; + clusterCollCard1[PF_SLR3_NEG_OFFSET + cntr13neg] = cluster; + cntr13neg++; + } + if ((iGCT == 2) && isSLR3 && isNegativeEta && (cntr23neg < NUM_PF_WORDS)) { + dataToCL1Card2[PF_SLR3_NEG_OFFSET + cntr23neg] = mydata; + clusterCollCard2[PF_SLR3_NEG_OFFSET + cntr23neg] = cluster; + cntr23neg++; + } + } + } + } + + cntr03pos = 0; + cntr03neg = 0; + cntr01pos = 0; + cntr01neg = 0; + + cntr13pos = 0; + cntr13neg = 0; + cntr11pos = 0; + cntr11neg = 0; + + cntr23pos = 0; + cntr23neg = 0; + cntr21pos = 0; + cntr21neg = 0; + + edm::Handle gctEmDigiClusters; + if (evt.getByToken(gctEmDigiClustersSrc_, gctEmDigiClusters)) { + for (int iLink = 0; iLink < 12; iLink++) { + // in order: + // GCT1 SLR3 +ve, GCT1 SLR3 -ve, GCT1 SLR1 +ve, GCT1 SLR1 -ve + // GCT2 SLR3 +ve, GCT2 SLR3 -ve, GCT2 SLR1 +ve, GCT2 SLR1 -ve + // GCT3 SLR3 +ve, GCT3 SLR3 -ve, GCT3 SLR1 +ve, GCT3 SLR1 -ve + int iGCT = (iLink / 4); + // 4 RCT regions per GCT + int iRCT = iLink - iGCT * 4; + // Eta: positive or negative depends on the link. If iLink is even, it is in positive eta + bool isNegativeEta = (iRCT % 2 == 1); + // SLR alternates every two links + bool isSLR3 = ((iLink % 4) < 2); + bool isSLR1 = !isSLR3; + for (const auto& cluster : (*gctEmDigiClusters).at(iLink)) { + mydata = cluster.data(); + + if ((iGCT == 0) && isSLR1 && !isNegativeEta && (cntr01pos < NUM_EM_WORDS)) { + dataToCL1Card0[EM_SLR1_POS_OFFSET + cntr01pos] = mydata; + clusterCollCard0[EM_SLR1_POS_OFFSET + cntr01pos] = cluster; + cntr01pos++; + } + if ((iGCT == 1) && isSLR1 && !isNegativeEta && (cntr11pos < NUM_EM_WORDS)) { + dataToCL1Card1[EM_SLR1_POS_OFFSET + cntr11pos] = mydata; + clusterCollCard1[EM_SLR1_POS_OFFSET + cntr11pos] = cluster; + cntr11pos++; + } + if ((iGCT == 2) && isSLR1 && !isNegativeEta && (cntr21pos < NUM_EM_WORDS)) { + dataToCL1Card2[EM_SLR1_POS_OFFSET + cntr21pos] = mydata; + clusterCollCard2[EM_SLR1_POS_OFFSET + cntr21pos] = cluster; + cntr21pos++; + } + if ((iGCT == 0) && isSLR1 && isNegativeEta && (cntr01neg < NUM_EM_WORDS)) { + dataToCL1Card0[EM_SLR1_NEG_OFFSET + cntr01neg] = mydata; + clusterCollCard0[EM_SLR1_NEG_OFFSET + cntr01neg] = cluster; + cntr01neg++; + } + if ((iGCT == 1) && isSLR1 && isNegativeEta && (cntr11neg < NUM_EM_WORDS)) { + dataToCL1Card1[EM_SLR1_NEG_OFFSET + cntr11neg] = mydata; + clusterCollCard1[EM_SLR1_NEG_OFFSET + cntr11neg] = cluster; + cntr11neg++; + } + if ((iGCT == 2) && isSLR1 && isNegativeEta && (cntr21neg < NUM_EM_WORDS)) { + dataToCL1Card2[EM_SLR1_NEG_OFFSET + cntr21neg] = mydata; + clusterCollCard2[EM_SLR1_NEG_OFFSET + cntr21neg] = cluster; + cntr21neg++; + } + if ((iGCT == 0) && isSLR3 && !isNegativeEta && (cntr03pos < NUM_EM_WORDS)) { + dataToCL1Card0[EM_SLR3_POS_OFFSET + cntr03pos] = mydata; + clusterCollCard0[EM_SLR3_POS_OFFSET + cntr03pos] = cluster; + cntr03pos++; + } + if ((iGCT == 1) && isSLR3 && !isNegativeEta && (cntr13pos < NUM_EM_WORDS)) { + dataToCL1Card1[EM_SLR3_POS_OFFSET + cntr13pos] = mydata; + clusterCollCard1[EM_SLR3_POS_OFFSET + cntr13pos] = cluster; + cntr13pos++; + } + if ((iGCT == 2) && isSLR3 && !isNegativeEta && (cntr23pos < NUM_EM_WORDS)) { + dataToCL1Card2[EM_SLR3_POS_OFFSET + cntr23pos] = mydata; + clusterCollCard2[EM_SLR3_POS_OFFSET + cntr23pos] = cluster; + cntr23pos++; + } + if ((iGCT == 0) && isSLR3 && isNegativeEta && (cntr03neg < NUM_EM_WORDS)) { + dataToCL1Card0[EM_SLR3_NEG_OFFSET + cntr03neg] = mydata; + clusterCollCard0[EM_SLR3_NEG_OFFSET + cntr03neg] = cluster; + cntr03neg++; + } + if ((iGCT == 1) && isSLR3 && isNegativeEta && (cntr13neg < NUM_EM_WORDS)) { + dataToCL1Card1[EM_SLR3_NEG_OFFSET + cntr13neg] = mydata; + clusterCollCard1[EM_SLR3_NEG_OFFSET + cntr13neg] = cluster; + cntr13neg++; + } + if ((iGCT == 2) && isSLR3 && isNegativeEta && (cntr23neg < NUM_EM_WORDS)) { + dataToCL1Card2[EM_SLR3_NEG_OFFSET + cntr23neg] = mydata; + clusterCollCard2[EM_SLR3_NEG_OFFSET + cntr23neg] = cluster; + cntr23neg++; + } + } + } + } + + l1tp2::DigitizedCaloToCorrelatorTM18 l1CaloTM18_0 = + l1tp2::DigitizedCaloToCorrelatorTM18(dataToCL1Card0, clusterCollCard0); + l1tp2::DigitizedCaloToCorrelatorTM18 l1CaloTM18_1 = + l1tp2::DigitizedCaloToCorrelatorTM18(dataToCL1Card1, clusterCollCard1); + l1tp2::DigitizedCaloToCorrelatorTM18 l1CaloTM18_2 = + l1tp2::DigitizedCaloToCorrelatorTM18(dataToCL1Card2, clusterCollCard2); + + caloCandsTM18->push_back(l1CaloTM18_0); + caloCandsTM18->push_back(l1CaloTM18_1); + caloCandsTM18->push_back(l1CaloTM18_2); + evt.put(std::move(caloCandsTM18), "DigitizedCaloToCorrelatorTM18"); +} + +// ------------ method fills 'descriptions' with the allowed parameters for the module ------------ +void Phase2L1CaloToCorrelatorTM18::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + desc.add("gctEmDigiClusters", + edm::InputTag("l1tPhase2GCTBarrelToCorrelatorLayer1Emulator", "GCTEmDigiClusters")); + desc.add("gctHadDigiClusters", + edm::InputTag("l1tPhase2GCTBarrelToCorrelatorLayer1Emulator", "GCTHadDigiClusters")); + descriptions.addWithDefaultLabel(desc); +} + +DEFINE_FWK_MODULE(Phase2L1CaloToCorrelatorTM18); diff --git a/L1Trigger/L1CaloTrigger/plugins/Phase2L1TCaloBarrelToCorrelator.cc b/L1Trigger/L1CaloTrigger/plugins/Phase2L1TCaloBarrelToCorrelator.cc index 9e5d1b13bf851..7bb0e408324d0 100644 --- a/L1Trigger/L1CaloTrigger/plugins/Phase2L1TCaloBarrelToCorrelator.cc +++ b/L1Trigger/L1CaloTrigger/plugins/Phase2L1TCaloBarrelToCorrelator.cc @@ -33,7 +33,6 @@ #include #include #include -#include "L1Trigger/L1CaloTrigger/interface/Phase2L1CaloBarrelToCorrelator.h" #include "L1Trigger/L1CaloTrigger/interface/Phase2L1CaloEGammaUtils.h" // @@ -149,7 +148,7 @@ void Phase2GCTBarrelToCorrelatorLayer1::produce(edm::Event& iEvent, const edm::E l1tp2::GCTHadDigiClusterLink buffer_had_GCT3_SLR3_negEta[4]; //***************************************************// - // Loop over the regions: in order: GCT1 SLR1, GCT1 SLR3, GCT2 SLR1, GCT2 SLR3, GCT3 SLR1, GCT3SLR3 + // Loop over the regions: in order: GCT1 SLR3, GCT1 SLR1, GCT2 SLR3, GCT2 SLR1, GCT3 SLR3, GCT3 SLR1 //***************************************************// const int nRegions = 6; @@ -163,34 +162,23 @@ void Phase2GCTBarrelToCorrelatorLayer1::produce(edm::Event& iEvent, const edm::E // Check if this cluster falls into each SLR region, i.e. if the cluster is within 120/2 = 60 degrees of the center of the SLR in phi float clusterRealPhiAsDegree = clusterIn.realPhi() * 180 / M_PI; float phiDifference = p2eg::deltaPhiInDegrees(clusterRealPhiAsDegree, regionCentersInDegrees[iRegion]); - if (std::abs(phiDifference) < (p2eg::PHI_RANGE_PER_SLR_DEGREES / 2)) { - // Go from real phi to an index in the SLR - // The crystal directly above the region center in phi, is iPhi 0. The crystal directly below the region center in phi, is iPhi -1. - int iPhiCrystalDifference = std::floor(phiDifference); - - // For eta, the eta is already digitized, just needs to be converted from [0, +2*17*5) to [-17*5, +17*5) - int temp_iEta_signed = clusterIn.eta() - (p2eg::CRYSTALS_IN_TOWER_ETA * p2eg::n_towers_per_link); - - // Default value: for clusters in positive eta, values go from 0, 1, 2, 3, 4 - int iEta = temp_iEta_signed; - // If cluster is in negative eta, instead of from -5, -4, -3, -2, -1, we want 4, 3, 2, 1, 0 - if (temp_iEta_signed < 0) { - // If in negative eta, convert to an absolute value, with 0 being the crystal nearest real eta = 0 - iEta = std::abs(temp_iEta_signed + 1); - } + if (std::abs(phiDifference) < (p2eg::PHI_RANGE_PER_SLR_DEGREES / 4)) { // only unique region + // Use realEta() to determine which link + float eta_LSB = p2eg::ECAL_eta_range / (p2eg::N_GCTTOWERS_FIBER * p2eg::CRYSTALS_IN_TOWER_ETA); + int temp_iEta_signed = std::floor(clusterIn.realEta() / eta_LSB); - // Initialize the new cluster and set the edm::Ref pointing to the underlying float + // Need to adapt DigitizedClusterCorrelator to DigitizedClusterCorrelatorTM18 l1tp2::GCTEmDigiCluster clusterOut = l1tp2::GCTEmDigiCluster(clusterIn.pt(), - iEta, - iPhiCrystalDifference, + clusterIn.eta(), + clusterIn.phi(), clusterIn.hoe(), - clusterIn.hoeFlag(), clusterIn.iso(), - clusterIn.isoFlags(), - clusterIn.fb(), + clusterIn.shape(), + clusterIn.wp(), clusterIn.timing(), - clusterIn.shapeFlags(), - clusterIn.brems()); + clusterIn.brems(), + clusterIn.spare()); + // there is a 1-to-1 mapping between the original float clusters and the first step of digitization, so we can build a ref to the same cluster edm::Ref thisRef(inputGCTClusters, iCluster); clusterOut.setRef(thisRef); @@ -200,11 +188,11 @@ void Phase2GCTBarrelToCorrelatorLayer1::produce(edm::Event& iEvent, const edm::E // Check which RCT card this falls into, ordered 0, 1, 2, 3 counting from the most negative phi (real phi or iPhi) to the most positive // so RCT card 0 is -60 to -30 degrees in phi from the center, RCT card 1 is -30 to 0 degrees in phi from the center, RCT card 2 is 0 to +30 degrees in phi from the center, RCT card 3 is +30 to +60 degrees in phi from the center int whichRCTcard = 0; - if (phiDifference < -30) { + if (phiDifference < -(p2eg::PHI_RANGE_PER_SLR_DEGREES / 4)) { whichRCTcard = 0; } else if (phiDifference < 0) { whichRCTcard = 1; - } else if (phiDifference < 30) { + } else if (phiDifference < (p2eg::PHI_RANGE_PER_SLR_DEGREES / 4)) { whichRCTcard = 2; } else { whichRCTcard = 3; @@ -212,39 +200,39 @@ void Phase2GCTBarrelToCorrelatorLayer1::produce(edm::Event& iEvent, const edm::E if (iRegion == 0) { if (temp_iEta_signed < 0) { - buffer_eg_GCT1_SLR1_negEta[whichRCTcard].push_back(clusterOut); + buffer_eg_GCT1_SLR3_negEta[whichRCTcard].push_back(clusterOut); } else { - buffer_eg_GCT1_SLR1_posEta[whichRCTcard].push_back(clusterOut); + buffer_eg_GCT1_SLR3_posEta[whichRCTcard].push_back(clusterOut); } } else if (iRegion == 1) { if (temp_iEta_signed < 0) { - buffer_eg_GCT1_SLR3_negEta[whichRCTcard].push_back(clusterOut); + buffer_eg_GCT1_SLR1_negEta[whichRCTcard].push_back(clusterOut); } else { - buffer_eg_GCT1_SLR3_posEta[whichRCTcard].push_back(clusterOut); + buffer_eg_GCT1_SLR1_posEta[whichRCTcard].push_back(clusterOut); } } else if (iRegion == 2) { if (temp_iEta_signed < 0) { - buffer_eg_GCT2_SLR1_negEta[whichRCTcard].push_back(clusterOut); + buffer_eg_GCT2_SLR3_negEta[whichRCTcard].push_back(clusterOut); } else { - buffer_eg_GCT2_SLR1_posEta[whichRCTcard].push_back(clusterOut); + buffer_eg_GCT2_SLR3_posEta[whichRCTcard].push_back(clusterOut); } } else if (iRegion == 3) { if (temp_iEta_signed < 0) { - buffer_eg_GCT2_SLR3_negEta[whichRCTcard].push_back(clusterOut); + buffer_eg_GCT2_SLR1_negEta[whichRCTcard].push_back(clusterOut); } else { - buffer_eg_GCT2_SLR3_posEta[whichRCTcard].push_back(clusterOut); + buffer_eg_GCT2_SLR1_posEta[whichRCTcard].push_back(clusterOut); } } else if (iRegion == 4) { if (temp_iEta_signed < 0) { - buffer_eg_GCT3_SLR1_negEta[whichRCTcard].push_back(clusterOut); + buffer_eg_GCT3_SLR3_negEta[whichRCTcard].push_back(clusterOut); } else { - buffer_eg_GCT3_SLR1_posEta[whichRCTcard].push_back(clusterOut); + buffer_eg_GCT3_SLR3_posEta[whichRCTcard].push_back(clusterOut); } } else if (iRegion == 5) { if (temp_iEta_signed < 0) { - buffer_eg_GCT3_SLR3_negEta[whichRCTcard].push_back(clusterOut); + buffer_eg_GCT3_SLR1_negEta[whichRCTcard].push_back(clusterOut); } else { - buffer_eg_GCT3_SLR3_posEta[whichRCTcard].push_back(clusterOut); + buffer_eg_GCT3_SLR1_posEta[whichRCTcard].push_back(clusterOut); } } } @@ -252,7 +240,7 @@ void Phase2GCTBarrelToCorrelatorLayer1::produce(edm::Event& iEvent, const edm::E // Repeat for PF Clusters for (size_t iCluster = 0; iCluster < inputPFClusters->size(); ++iCluster) { - l1tp2::CaloPFCluster pfIn = inputPFClusters->at(iCluster); + const l1tp2::CaloPFCluster& pfIn = inputPFClusters->at(iCluster); // Skip zero-energy clusters if (pfIn.clusterEt() == 0) @@ -260,15 +248,10 @@ void Phase2GCTBarrelToCorrelatorLayer1::produce(edm::Event& iEvent, const edm::E // Check if this cluster falls into each GCT card float clusterRealPhiAsDegree = pfIn.clusterPhi() * 180 / M_PI; - float differenceInPhi = p2eg::deltaPhiInDegrees(clusterRealPhiAsDegree, regionCentersInDegrees[iRegion]); - if (std::abs(differenceInPhi) < (p2eg::PHI_RANGE_PER_SLR_DEGREES / 2)) { - // Go from real phi to an index in the SLR - // Calculate the distance in phi from the center of the region - float phiDifference = clusterRealPhiAsDegree - regionCentersInDegrees[iRegion]; - int iPhiCrystalDifference = std::floor(phiDifference); - + float phiDifference = p2eg::deltaPhiInDegrees(clusterRealPhiAsDegree, regionCentersInDegrees[iRegion]); + if (std::abs(phiDifference) < (p2eg::PHI_RANGE_PER_SLR_DEGREES / 4)) { // only unique region // For PFClusters, the method clusterEta returns a float, so we need to digitize this - float eta_LSB = p2eg::ECAL_eta_range / (p2eg::N_GCTTOWERS_FIBER * p2eg::CRYSTALS_IN_TOWER_ETA); + static const float eta_LSB = p2eg::ECAL_eta_range / (p2eg::N_GCTTOWERS_FIBER * p2eg::CRYSTALS_IN_TOWER_ETA); int temp_iEta_signed = std::floor(pfIn.clusterEta() / eta_LSB); // Default value (for positive eta) int iEta = temp_iEta_signed; @@ -283,24 +266,41 @@ void Phase2GCTBarrelToCorrelatorLayer1::produce(edm::Event& iEvent, const edm::E if (iEta > maxEta) { continue; } + ap_uint<7> pf_eta = (ap_uint<7>)((std::abs(pfIn.clusterEta()) / eta_LSB)); + // std::cout << "[GCT] PF Cluster: eta in =" << pfIn.clusterEta() + // << " abs: " << std::abs(pfIn.clusterEta()) + // << " ratio: " << std::abs(pfIn.clusterEta())/ eta_LSB + // << " floor: " << std::floor(std::abs(pfIn.clusterEta())/ eta_LSB) + // << " rounded: " << std::floor(( std::abs(pfIn.clusterEta())/ eta_LSB) + 0.5) + // << ", eta out=" << pf_eta.to_int() + // << " float: " << pf_eta * eta_LSB + // << " ieta: " << iEta + // << " (f) " << iEta * eta_LSB + // << " LSB: " << eta_LSB + // << " diff: " << std::abs(std::abs(pfIn.clusterEta()) - (pf_eta * eta_LSB))/ eta_LSB + // << std::endl; + + ap_int<7> pf_phi = 0x7F & int(std::floor(phiDifference)); // greatest integer <= x // Initialize the new cluster - l1tp2::GCTHadDigiCluster pfOut = - l1tp2::GCTHadDigiCluster(pfIn.clusterEt() / p2eg::ECAL_LSB, // convert to integer - iEta, - iPhiCrystalDifference, - 0 // no HoE value in PF Cluster - ); + ap_uint<20> spare = 0; + if (temp_iEta_signed < 0) + spare = 4; // 3rd bit encode PosEta + ap_uint<12> pf_et = (ap_uint<12>)(pfIn.clusterEt() / p2eg::ECAL_LSB); + ap_uint<12> pf_ecal = (ap_uint<12>)(pfIn.ecalEt() / p2eg::ECAL_LSB); + l1tp2::GCTHadDigiCluster pfOut = l1tp2::GCTHadDigiCluster(pf_et, pf_eta, pf_phi, pf_ecal, 0x0, spare); + pfOut.setRef(edm::Ref(inputPFClusters, iCluster)); // Check which RCT card this falls into, ordered 0, 1, 2, 3 counting from the most negative phi (real phi or iPhi) to the most positive // so RCT card 0 is -60 to -30 degrees in phi from the center, RCT card 1 is -30 to 0 degrees in phi from the center, RCT card 2 is 0 to +30 degrees in phi from the center, RCT card 3 is +30 to +60 degrees in phi from the center + int whichRCTcard = 0; - if (phiDifference < -30) { + if (phiDifference < -(p2eg::PHI_RANGE_PER_SLR_DEGREES / 4)) { whichRCTcard = 0; } else if (phiDifference < 0) { whichRCTcard = 1; - } else if (phiDifference < 30) { + } else if (phiDifference < (p2eg::PHI_RANGE_PER_SLR_DEGREES / 4)) { whichRCTcard = 2; } else { whichRCTcard = 3; @@ -308,39 +308,39 @@ void Phase2GCTBarrelToCorrelatorLayer1::produce(edm::Event& iEvent, const edm::E if (iRegion == 0) { if (temp_iEta_signed < 0) { - buffer_had_GCT1_SLR1_negEta[whichRCTcard].push_back(pfOut); + buffer_had_GCT1_SLR3_negEta[whichRCTcard].push_back(pfOut); } else { - buffer_had_GCT1_SLR1_posEta[whichRCTcard].push_back(pfOut); + buffer_had_GCT1_SLR3_posEta[whichRCTcard].push_back(pfOut); } } else if (iRegion == 1) { if (temp_iEta_signed < 0) { - buffer_had_GCT1_SLR3_negEta[whichRCTcard].push_back(pfOut); + buffer_had_GCT1_SLR1_negEta[whichRCTcard].push_back(pfOut); } else { - buffer_had_GCT1_SLR3_posEta[whichRCTcard].push_back(pfOut); + buffer_had_GCT1_SLR1_posEta[whichRCTcard].push_back(pfOut); } } else if (iRegion == 2) { if (temp_iEta_signed < 0) { - buffer_had_GCT2_SLR1_negEta[whichRCTcard].push_back(pfOut); + buffer_had_GCT2_SLR3_negEta[whichRCTcard].push_back(pfOut); } else { - buffer_had_GCT2_SLR1_posEta[whichRCTcard].push_back(pfOut); + buffer_had_GCT2_SLR3_posEta[whichRCTcard].push_back(pfOut); } } else if (iRegion == 3) { if (temp_iEta_signed < 0) { - buffer_had_GCT2_SLR3_negEta[whichRCTcard].push_back(pfOut); + buffer_had_GCT2_SLR1_negEta[whichRCTcard].push_back(pfOut); } else { - buffer_had_GCT2_SLR3_posEta[whichRCTcard].push_back(pfOut); + buffer_had_GCT2_SLR1_posEta[whichRCTcard].push_back(pfOut); } } else if (iRegion == 4) { if (temp_iEta_signed < 0) { - buffer_had_GCT3_SLR1_negEta[whichRCTcard].push_back(pfOut); + buffer_had_GCT3_SLR3_negEta[whichRCTcard].push_back(pfOut); } else { - buffer_had_GCT3_SLR1_posEta[whichRCTcard].push_back(pfOut); + buffer_had_GCT3_SLR3_posEta[whichRCTcard].push_back(pfOut); } } else if (iRegion == 5) { if (temp_iEta_signed < 0) { - buffer_had_GCT3_SLR3_negEta[whichRCTcard].push_back(pfOut); + buffer_had_GCT3_SLR1_negEta[whichRCTcard].push_back(pfOut); } else { - buffer_had_GCT3_SLR3_posEta[whichRCTcard].push_back(pfOut); + buffer_had_GCT3_SLR1_posEta[whichRCTcard].push_back(pfOut); } } } @@ -418,31 +418,31 @@ void Phase2GCTBarrelToCorrelatorLayer1::produce(edm::Event& iEvent, const edm::E } // Finally, push back the SLR containers - outputEmClusters->push_back(out_eg_GCT1_SLR1_posEta); - outputEmClusters->push_back(out_eg_GCT1_SLR1_negEta); outputEmClusters->push_back(out_eg_GCT1_SLR3_posEta); outputEmClusters->push_back(out_eg_GCT1_SLR3_negEta); - outputEmClusters->push_back(out_eg_GCT2_SLR1_posEta); - outputEmClusters->push_back(out_eg_GCT2_SLR1_negEta); + outputEmClusters->push_back(out_eg_GCT1_SLR1_posEta); + outputEmClusters->push_back(out_eg_GCT1_SLR1_negEta); outputEmClusters->push_back(out_eg_GCT2_SLR3_posEta); outputEmClusters->push_back(out_eg_GCT2_SLR3_negEta); - outputEmClusters->push_back(out_eg_GCT3_SLR1_posEta); - outputEmClusters->push_back(out_eg_GCT3_SLR1_negEta); + outputEmClusters->push_back(out_eg_GCT2_SLR1_posEta); + outputEmClusters->push_back(out_eg_GCT2_SLR1_negEta); outputEmClusters->push_back(out_eg_GCT3_SLR3_posEta); outputEmClusters->push_back(out_eg_GCT3_SLR3_negEta); + outputEmClusters->push_back(out_eg_GCT3_SLR1_posEta); + outputEmClusters->push_back(out_eg_GCT3_SLR1_negEta); - outputHadClusters->push_back(out_had_GCT1_SLR1_posEta); - outputHadClusters->push_back(out_had_GCT1_SLR1_negEta); outputHadClusters->push_back(out_had_GCT1_SLR3_posEta); outputHadClusters->push_back(out_had_GCT1_SLR3_negEta); - outputHadClusters->push_back(out_had_GCT2_SLR1_posEta); - outputHadClusters->push_back(out_had_GCT2_SLR1_negEta); + outputHadClusters->push_back(out_had_GCT1_SLR1_posEta); + outputHadClusters->push_back(out_had_GCT1_SLR1_negEta); outputHadClusters->push_back(out_had_GCT2_SLR3_posEta); outputHadClusters->push_back(out_had_GCT2_SLR3_negEta); - outputHadClusters->push_back(out_had_GCT3_SLR1_posEta); - outputHadClusters->push_back(out_had_GCT3_SLR1_negEta); + outputHadClusters->push_back(out_had_GCT2_SLR1_posEta); + outputHadClusters->push_back(out_had_GCT2_SLR1_negEta); outputHadClusters->push_back(out_had_GCT3_SLR3_posEta); outputHadClusters->push_back(out_had_GCT3_SLR3_negEta); + outputHadClusters->push_back(out_had_GCT3_SLR1_posEta); + outputHadClusters->push_back(out_had_GCT3_SLR1_negEta); iEvent.put(std::move(outputEmClusters), "GCTEmDigiClusters"); iEvent.put(std::move(outputHadClusters), "GCTHadDigiClusters"); diff --git a/L1Trigger/L1CaloTrigger/python/l1tPhase2CaloToCorrelatorTM18_cfi.py b/L1Trigger/L1CaloTrigger/python/l1tPhase2CaloToCorrelatorTM18_cfi.py new file mode 100644 index 0000000000000..634608d4135f0 --- /dev/null +++ b/L1Trigger/L1CaloTrigger/python/l1tPhase2CaloToCorrelatorTM18_cfi.py @@ -0,0 +1,6 @@ +import FWCore.ParameterSet.Config as cms + +l1tPhase2CaloToCorrelatorTM18 = cms.EDProducer("Phase2L1CaloToCorrelatorTM18", + gctEmDigiClusters = cms.InputTag("l1tPhase2GCTBarrelToCorrelatorLayer1Emulator", "GCTEmDigiClusters"), + gctHadDigiClusters = cms.InputTag("l1tPhase2GCTBarrelToCorrelatorLayer1Emulator", "GCTHadDigiClusters"), +) diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/L1TCorrelatorLayer1PatternFileWriter.h b/L1Trigger/Phase2L1ParticleFlow/interface/L1TCorrelatorLayer1PatternFileWriter.h index cffcd935a165e..3ebc9b8634323 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/L1TCorrelatorLayer1PatternFileWriter.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/L1TCorrelatorLayer1PatternFileWriter.h @@ -31,18 +31,16 @@ class L1TCorrelatorLayer1PatternFileWriter { // They are not configurable in the current architecture. const unsigned int tfTmuxFactor_ = 18, tfLinksFactor_ = 1; const unsigned int hgcTmuxFactor_ = 18, hgcLinksFactor_ = 4; - const unsigned int gctEmTmuxFactor_ = 6, gctEmLinksFactor_ = 1; - const unsigned int gctHadTmuxFactor_ = 6, gctHadLinksFactor_ = 1; + const unsigned int gctTmuxFactor_ = 18, gctEmLinksFactor_ = 1; const unsigned int gmtTmuxFactor_ = 18, gmtLinksFactor_ = 1; const unsigned int gttTmuxFactor_ = 6, gttLinksFactor_ = 1; - const unsigned int tfTimeslices_, hgcTimeslices_, gctEmTimeslices_, gctHadTimeslices_, gmtTimeslices_, gttTimeslices_; + const unsigned int tfTimeslices_, hgcTimeslices_, gctTimeslices_, gmtTimeslices_, gttTimeslices_; uint32_t gctLinksEcal_, gctLinksHad_; bool gctSingleLink_; uint32_t gmtNumberOfMuons_; uint32_t gttNumberOfPVs_; uint32_t tfNumberOfTracks_; // if this messes up Serenity, change to int32 and only apply if not negative? - uint32_t gctNumberOfEMs_; - uint32_t gctNumberOfHads_; + uint32_t gctNumberOfObjects_; uint32_t gttLatency_; std::vector outputRegions_, outputLinksPuppi_; @@ -59,6 +57,8 @@ class L1TCorrelatorLayer1PatternFileWriter { const uint32_t nPFOutPhoton_; const uint32_t nPFOutNeutral_; const uint32_t nPFOutMuon_; + const uint32_t nEGElectron_; + const uint32_t nEGPhoton_; // Common stuff related to the format uint32_t nInputFramesPerBX_, nOutputFramesPerBX_; @@ -72,8 +72,7 @@ class L1TCorrelatorLayer1PatternFileWriter { static Partition parsePartition(const std::string& partition); static std::unique_ptr describeTF(); - static std::unique_ptr describeGCTEm(); - static std::unique_ptr describeGCTHad(); + static std::unique_ptr describeGCT(); static std::unique_ptr describeHGC(); static std::unique_ptr describeGMT(); static std::unique_ptr describeGTT(); @@ -98,8 +97,7 @@ class L1TCorrelatorLayer1PatternFileWriter { static std::unique_ptr describeLinks(const std::string& prefix); void writeTF(const l1ct::Event& event, l1t::demo::EventData& out); - void writeGCTEm(const l1ct::Event& event, l1t::demo::EventData& out); - void writeGCTHad(const l1ct::Event& event, l1t::demo::EventData& out); + void writeGCT(const l1ct::Event& event, l1t::demo::EventData& out); void writeHGC(const l1ct::Event& event, l1t::demo::EventData& out); void writeGMT(const l1ct::Event& event, l1t::demo::EventData& out); void writeGTT(const l1ct::Event& event, l1t::demo::EventData& out); diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegsorter_barrel_ref.h b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegsorter_barrel_ref.h index 624b3851fa36d..16446627a8331 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegsorter_barrel_ref.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegsorter_barrel_ref.h @@ -17,10 +17,14 @@ namespace l1ct { #ifdef CMSSW_GIT_HASH PFTkEGSorterBarrelEmulator(const edm::ParameterSet& iConfig) : PFTkEGSorterEmulator(iConfig.getParameter("nObjToSort"), - iConfig.getParameter("nObjSorted")) {} + iConfig.getParameter("nObjSorted")) { + debug_ = iConfig.getUntrackedParameter("debug"); + } static edm::ParameterSetDescription getParameterSetDescription() { - return PFTkEGSorterEmulator::getParameterSetDescription(); + auto description = PFTkEGSorterEmulator::getParameterSetDescription(); + description.addUntracked("debug", false); + return description; } #endif diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegsorter_ref.h b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegsorter_ref.h index 9e1c7b364514c..f0cc0f735ca5c 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegsorter_ref.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegsorter_ref.h @@ -3,6 +3,7 @@ #include #include +#include #include "DataFormats/L1TParticleFlow/interface/layer1_emulator.h" #include "L1Trigger/Phase2L1ParticleFlow/interface/dbgPrintf.h" diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/gcteminput_ref.h b/L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/gcteminput_ref.h index d97d087d4e78a..646b996e0f1e9 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/gcteminput_ref.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/gcteminput_ref.h @@ -35,27 +35,6 @@ namespace l1ct { l1ct::EmCaloObjEmu decode(const l1ct::PFRegionEmu §or, const ap_uint<64> &in) const; private: - ap_uint<12> pt(const ap_uint<64> &in) const { return in.range(11, 0); } - - // crystal eta (unsigned 7 bits) - ap_uint<7> eta(const ap_uint<64> &in) const { return (ap_uint<7>)in.range(18, 12); } - - // crystal phi (signed 7 bits) - ap_int<7> phi(const ap_uint<64> &in) const { return (ap_int<7>)in.range(25, 19); } - - // iso flag: two bits, least significant bit is the standalone WP (true or false), second bit is the looseTk WP (true or false) - // e.g. 0b01 : standalone iso flag passed, loose Tk iso flag did not pass - ap_uint<2> isoFlags(const ap_uint<64> &in) const { return in.range(36, 35); } - bool passes_iso(const ap_uint<64> &in) const { return (isoFlags(in) & 0x1); } // standalone iso WP - bool passes_looseTkiso(const ap_uint<64> &in) const { return (isoFlags(in) & 0x2); } // loose Tk iso WP - - // shower shape shape flag: two bits, least significant bit is the standalone WP, second bit is the looseTk WP - // e.g. 0b01 : standalone shower shape flag passed, loose Tk shower shape flag did not pass - ap_uint<2> shapeFlags(const ap_uint<64> &in) const { return in.range(49, 48); } - - bool passes_ss(const ap_uint<64> &in) const { return (shapeFlags(in) & 0x1); } // standalone shower shape WP - bool passes_looseTkss(const ap_uint<64> &in) const { return (shapeFlags(in) & 0x2); } // loose Tk shower shape WP - // tools for GCT clusters l1tpf::corrector corrector_; l1tpf::ParametricResolution resol_; diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/gcthadinput_ref.h b/L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/gcthadinput_ref.h index a0cdd28b74a17..dacc453664a41 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/gcthadinput_ref.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/gcthadinput_ref.h @@ -3,6 +3,9 @@ #include "DataFormats/L1TParticleFlow/interface/layer1_emulator.h" +#include "L1Trigger/Phase2L1ParticleFlow/interface/corrector.h" +#include "L1Trigger/Phase2L1ParticleFlow/interface/ParametricResolution.h" + // TODO: add calibration namespace edm { @@ -14,7 +17,15 @@ namespace l1ct { class GctHadClusterDecoderEmulator { public: GctHadClusterDecoderEmulator() {}; - GctHadClusterDecoderEmulator(const edm::ParameterSet &pset); + GctHadClusterDecoderEmulator(const edm::ParameterSet &iConfig); + GctHadClusterDecoderEmulator(const std::string &corrFile, + l1tpf::ParametricResolution::Kind kind, + std::vector etas, + std::vector offsets, + std::vector scales, + std::vector ptMins, + std::vector ptMaxs) + : corrector_(corrFile), resol_(kind, etas, offsets, scales, ptMins, ptMaxs) {} ~GctHadClusterDecoderEmulator() = default; @@ -23,17 +34,9 @@ namespace l1ct { l1ct::HadCaloObjEmu decode(const l1ct::PFRegionEmu §or, const ap_uint<64> &in) const; private: - double fracPart(const double total, const unsigned int hoe) const; - ap_uint<12> pt(const ap_uint<64> &in) const { return in.range(11, 0); } - - // crystal eta (unsigned 7 bits) - ap_uint<7> eta(const ap_uint<64> &in) const { return (ap_uint<7>)in.range(18, 12); } - - // crystal phi (signed 7 bits) - ap_int<7> phi(const ap_uint<64> &in) const { return (ap_int<7>)in.range(25, 19); } - - // HoE value - ap_uint<4> hoe(const ap_uint<64> &in) const { return in.range(29, 26); } + // tools for GCT clusters + l1tpf::corrector corrector_; + l1tpf::ParametricResolution resol_; }; } // namespace l1ct diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/middle_buffer_multififo_regionizer_ref.h b/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/middle_buffer_multififo_regionizer_ref.h index b140408a231bd..420d5caa356dd 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/middle_buffer_multififo_regionizer_ref.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/middle_buffer_multififo_regionizer_ref.h @@ -22,8 +22,7 @@ namespace l1ct { bool streaming, unsigned int outii, unsigned int pauseii, - bool useAlsoVtxCoords, - bool tmux6GCTinput = false); + bool useAlsoVtxCoords); // note: this one will work only in CMSSW MiddleBufferMultififoRegionizerEmulator(const edm::ParameterSet& iConfig); @@ -97,7 +96,7 @@ namespace l1ct { to.src = from.src; } - void convert_GCTinput_tmux(const RegionizerDecodedInputs& in_tm6, RegionizerDecodedInputs& in_tm18) const; + // void convert_GCTinput_tmux(const RegionizerDecodedInputs& in_tm6, RegionizerDecodedInputs& in_tm18) const; void init_GCT_tmux18sectors(std::vector>& gct_tmux18_hadcalo, std::vector>& gct_tmux18_emcalo) const; @@ -109,7 +108,6 @@ namespace l1ct { bool streaming_; bool init_; unsigned int iclock_; - bool tmux6GCTinput_; std::vector mergedRegions_, outputRegions_; multififo_regionizer::Regionizer tkRegionizerPre_, tkRegionizerPost_; multififo_regionizer::Regionizer commonCaloRegionizerPre_; @@ -121,7 +119,6 @@ namespace l1ct { std::vector> hadCaloBuffers_; std::vector> emCaloBuffers_; std::vector> muBuffers_; - std::vector gct_slr_regions_; std::vector> gct_tmux18_hadcalo_; std::vector> gct_tmux18_emcalo_; @@ -138,31 +135,6 @@ namespace l1ct { std::vector& valid); void run_worker(const RegionizerDecodedInputs& in, std::vector& out); - void init_GCT_slrs(std::vector& gct_slr_regions) const; - - template - void convert_GCTsector_tmux(const std::vector>& tm6_sectors, - std::vector>& tm18_sectors) const { - static constexpr std::array gct_slr_tmux18sector_mapping = {0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2}; - for (const auto& sec : tm6_sectors) { - // std::cout << "Processing TMUX6 hadcalo sector: " << isec << " #cl: " << sec.obj.size() << std::endl; - for (auto cl : sec.obj) { - if (cl.hwPt == 0) - continue; // skip empty objects - glbeta_t gl_hweta = sec.region.hwGlbEta(cl.hwEta); - glbphi_t gl_hwphi = sec.region.hwGlbPhi(cl.hwPhi); - for (unsigned int islr = 0; islr < gct_slr_regions_.size(); ++islr) { - if (gct_slr_regions_[islr].containsHw(gl_hweta, gl_hwphi)) { - auto itmux18 = gct_slr_tmux18sector_mapping[islr]; - cl.hwEta = l1ct::Scales::makeEta(tm18_sectors[itmux18].region.localEta(sec.region.floatGlbEtaOf(cl))); - cl.hwPhi = l1ct::Scales::makePhi(tm18_sectors[itmux18].region.localPhi(sec.region.floatGlbPhiOf(cl))); - tm18_sectors[itmux18].obj.push_back(cl); - break; - } - } - } - } - } }; } // namespace l1ct diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.h b/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.h index 0bedb18a32fe5..0efcbe084ca33 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.h @@ -22,213 +22,60 @@ namespace l1ct { return local_phi; } - /// corresponds to level1_to_2_pipe_t in firmware - template - class PipeEntry { - public: - PipeEntry() : obj_(), sr_(-1) {} - PipeEntry(const T& obj, int sr, int glbeta, int glbphi) : obj_(obj), sr_(sr), glbeta_(glbeta), glbphi_(glbphi) {} - - int sr() const { return sr_; } - - // Note, this returns a copy so you can modify - T obj() const { return obj_; } - - bool valid() const { return sr_ >= 0; } - - void setInvalid() { sr_ = -1; } - - int pt() const { return obj_.intPt(); } - int glbPhi() const { return glbphi_; } - int glbEta() const { return glbeta_; } - - private: - T obj_; - /// the SR linearized indices (can index regionmap_) where this object needs to go; -1 means invalid - int sr_; - /// The global eta and phi of the object (hard to get with duplicates) - int glbeta_, glbphi_; - }; - - /// The pipe, with multiple inputs and one output - template - class Pipe { - public: - /// if using the default constructor, have to call setTaps before use - Pipe() : pipe_() {} - - Pipe(size_t ntaps) : pipe_(ntaps) {} - - void setTaps(size_t taps) { pipe_.resize(taps); } - - /// check if the entry is valid (i.e. already has data) - bool valid(size_t idx) const { return pipe_.at(idx).valid(); } - - /// should check if valid before adding an entry - void addEntry(size_t idx, const PipeEntry& entry) { pipe_[idx] = entry; } - - /// perform one tick, shifting all the entries to higher indices, and returning the last - PipeEntry popEntry(); - - void reset(); - - size_t size() const { return pipe_.size(); } - - /// for debug - const PipeEntry& entry(size_t idx) const { return pipe_[idx]; } - - private: - std::vector> pipe_; - }; - - /// The pipe, with multiple inputs and one output - template - class Pipes { - public: - /// the number of pipes - Pipes(size_t nregions) : pipes_(nregions / SRS_PER_RAM) {} - - /// set the number of taps in each pipe - void setTaps(size_t taps); - - /// check if the entry is valid (i.e. already has data) - bool valid(int sr, size_t logicBufIdx) const { return pipes_[pipeIndex(sr)].valid(logicBufIdx); } - - /// should check if valid before adding an entry - void addEntry(int sr, size_t logicBufIdx, const PipeEntry& entry) { - pipes_[pipeIndex(sr)].addEntry(logicBufIdx, entry); - } - - /// perform one tick, shifting all the entries to higher indices, and returning the last - PipeEntry popEntry(size_t pipe) { return pipes_[pipe].popEntry(); }; - - void reset(); - - size_t size() const { return pipes_.size(); } - - size_t numTaps() const { return pipes_.at(0).size(); } - - /// for debug - const PipeEntry& entry(size_t pipe, size_t tap) const { return pipes_[pipe].entry(tap); } - - private: - /// SRs share RAMs (and hardware pipes) - static size_t constexpr SRS_PER_RAM = 2; - - /// Because some SRs share pipes, this determines the pipe index for a linearize SR index - /// (This is based on the VHDL function, get_target_pipe_index_subindex) - size_t pipeIndex(int sr) const { return sr / SRS_PER_RAM; } - - std::vector> pipes_; - }; - /// the components that make up the L1 regionizer buffer template class BufferEntry { public: BufferEntry() {} - BufferEntry(const T& obj, std::vector srIndices, int glbeta, int glbphi, bool duplicate, unsigned int clk); + BufferEntry(const T& obj, int glbeta, int glbphi); - unsigned int clock() const { return linkobjclk_; } - int nextSR() const { return (objcount_ < srIndices_.size()) ? srIndices_[objcount_] : -1; } - void incSR() { objcount_++; } int pt() const { return obj_.intPt(); } int glbPhi() const { return glbphi_; } int glbEta() const { return glbeta_; } - int duplicate() const { return duplicate_; } //T obj() { return obj_; } const T& obj() const { return obj_; } + T& obj() { return obj_; } private: T obj_; /// the SR linearized indices (can index regionmap_) where this object needs to go - std::vector srIndices_; - /// The global eta and phi of the object (hard to get with duplicates) int glbeta_, glbphi_; - /// Is this a duplciate that should be ignored? used for GCT duplicate removal - bool duplicate_; - unsigned int linkobjclk_, objcount_; }; /// The L1 regionizer buffer (corresponding to level1_fifo_buffer.vhd) template class Buffer { public: - Buffer() : clkindex360_(INIT360), clkindex240_(INIT240), timeOfNextObject_(-1) {} + Buffer() {} void addEntry(const T& obj, - std::vector srs, + std::vector srs, // physical SRs int glbeta, - int glbphi, - bool duplicate, // this is mainly for GCT, is it one of the duplicates - unsigned int dupNum, // this is for the (currently unused) feature of multiple buffers per sector - unsigned int ndup); - - BufferEntry& front() { return data_.front(); } - const BufferEntry& front() const { return data_.front(); } - - /// sets the next time something is taken from this buffer - void updateNextObjectTime(int currentTime, bool incrementTime = true); - - /// delete the front element - void pop() { data_.pop_front(); } + int glbphi); - // mostly for debug - unsigned int clock(unsigned int index = 0) const { return data_[index].clock(); } - int pt(unsigned int index = 0) const { return data_[index].pt(); } - int glbPhi(unsigned int index = 0) const { return data_[index].glbPhi(); } - int glbEta(unsigned int index = 0) const { return data_[index].glbEta(); } - int duplicate(unsigned int index = 0) const { return data_[index].duplicate(); } + bool empty(size_t sr) const; + BufferEntry getEntry(size_t sr); - unsigned int numEntries() const { return data_.size(); } + // mainly for debug/validation, to check that nothing is left over after an event + // This is the number of entries in all the deques, not necessarily the number of + // entries in the map. + unsigned int numEntries() const; - /// pop the first entry, formatted for inclusion in pipe - PipeEntry popEntry(int currTime, bool debug); + void reset() { data_.clear(); } - int timeOfNextObject() const { return timeOfNextObject_; } - - void reset() { - clkindex360_ = INIT360; - clkindex240_ = INIT240; - data_.clear(); - timeOfNextObject_ = -1; - } + void printDebug(size_t bufIdx, size_t logBufIdx) const; private: - // used when building up the linkobjclk_ entries for the BufferEntries - unsigned int nextObjClk(unsigned int ndup, bool skip); // may need to treat pt == 0 and overlap differently - // transient--used only during event construction, not used after - // Counts in 1.39ns increments (i.e. 360 increments by 2, 240 by 3) - unsigned int clkindex360_; - unsigned int clkindex240_; - - // These values represent at what clock count the first data arrives, counting in 1.39ns increments (2 increments - // for one 360MHz clock period, 3 increments for a 240MHz clock period). The 360 version refers to the data as it - // is transferred over the fibers, while the 240 is for data going to the regionizer. Some data is thrown out in between. - // Both counts are used to determine when the data reaches the regionizer. - static unsigned int constexpr INIT360 = 2; - static unsigned int constexpr INIT240 = 4; - - /// The actual data - std::deque> data_; - - /// the time of the next object in the buffer (-1 if none) - int timeOfNextObject_; + /// The actual data, indexed by the physical SR + std::map>> data_; }; template class Regionizer { public: Regionizer() = delete; - Regionizer(unsigned int neta, - unsigned int nphi, //the number of eta and phi SRs in a big region (board) - unsigned int maxobjects, - int bigRegionMin, - int bigRegionMax, // the phi range covered by this board - unsigned int nclocks, - unsigned int ndup = 1, // how much one duplicates the inputs (to increase processing bandwidth) - bool debug = false); + Regionizer(unsigned int maxobjects, bool debug = false); void initSectors(const std::vector>& sectors); void initSectors(const DetectorSector& sector); @@ -241,32 +88,36 @@ namespace l1ct { void reset(); - /// Return a map of of the SRs indexed by SR index (covering only those from board) - std::map> fillRegions(bool doSort); + const std::vector>& smallRegions() const { return smallRegionObjects_; } + void clearSmallRegions(); void printDebug(int count) const; private: - /// is the given small region in the big region - bool isInBigRegion(const PFRegionEmu& reg) const; + const size_t SMALL_REGION_ETA_COUNT = 6; + const size_t SMALL_REGION_PHI_COUNT = 9; + + /// @brief convert to logical SR + /// @param sr linear small region + /// @return pair (eta, phi) region index) + std::pair get_small_region(size_t sr) const; - /// Does the given region fit in the big region, taking into account overlaps? - bool isInBigRegionLoose(const PFRegionEmu& reg) const; + /// physical links associated with a logical sr (customized for each type) + /// Note that these are grouped in bundles (to help model calo order) + std::vector> linksForSR(size_t sr) const; + std::vector> caloLinksHelper(size_t iphi) const; + void getNextIndex(size_t sr, const std::vector& bundle, size_t& nextIdx) const; unsigned int numBuffers() const { return buffers_.size(); } unsigned int numEntries(unsigned int bufferIndex) const { return buffers_[bufferIndex].numEntries(); } std::vector getSmallRegions(int glbeta, int glbphi) const; - void addToBuffer(const T& obj, unsigned int index, unsigned int dupNum); - void setBuffer(const std::vector& objvec, unsigned int index); + /// fill the buffers with an event's link data. The buffers should be empty--checked by assert void setBuffers(const std::vector>&& objvecvec); - /// This retruns the linearized small region associated with the given item (-1 is throwout) - int nextSR(unsigned int linknum, unsigned int index = 0) { return buffers_[linknum].nextSR(index); } - - /// 'put' object in small region - void addToSmallRegion(PipeEntry&&); + /// 'put' object in small region. The sr is physics + void addToSmallRegion(size_t sr, BufferEntry bufEntry); /// returns 2D arrays, sectors (links) first dimension, objects second std::vector> fillLinks(const std::vector>& sectors) const; @@ -275,10 +126,11 @@ namespace l1ct { // this function is for sorting small regions first in phi and then in eta. // It takes regions_ indices bool sortRegionsRegular(size_t a, size_t b) const; + bool sortRegionsHelper(int etaa, int etab, int phia, int phib) const; + // This is for sorting sectors. It sorts in eta first, then phi bool sortSectors(size_t a, size_t b) const; - - bool sortRegionsHelper(int etaa, int etab, int phia, int phib) const; + bool sortSectorsHelper(int etaa, int etab, int phia, int phib) const; /// get the index in regions_ for a particular SR. size_t regionIndex(int sr) const { return regionmap_.at(sr); } @@ -286,26 +138,10 @@ namespace l1ct { /// get the logical buffer index (i.e. the index in the order in the firmware) size_t logicBuffIndex(size_t bufIdx) const; - /// GCT sends duplicates. This indicates if an entry is a duplicate - /// For other objects, it always returns false - bool isDuplicate(int locphi, size_t logicBufIdx) const; - - /// The numbers of eta and phi in a big region (board) - unsigned int neta_, nphi_; /// The maximum number of objects to output per small region unsigned int maxobjects_; - /// The number of input sectors for this type of device - unsigned int nsectors_; - /// the minimum phi of this board - int bigRegionMin_; - /// the maximum phi of this board - int bigRegionMax_; - /// the number of clocks to receive one event - unsigned int nclocks_; - /// How many buffers per link (default 1) - unsigned int ndup_; - - /// the region information associated with each input sector + + /// the region information associated with each input sector (link). Note, this is indexed in physical order std::vector sectors_; /// the region information associated with each SR @@ -320,21 +156,12 @@ namespace l1ct { /// the inverse mapping of sectormap_ (only used for debug printing) std::vector sectorMapLogToPhys_; - /// The buffers. There are ndup_ buffers per link/sector + /// The buffers. There is one buffer per link (or sector). Note, this is also indexed in physical order (= same index as sectors) std::vector> buffers_; - /// The pipes, one per ram (see SRS_PER_RAM) - Pipes pipes_; - /// The objects in each small region handled in board; Indexing corresponds to that in regionmap_ std::vector> smallRegionObjects_; - /// Whether this is the first event (since timing is a bit different then) - bool firstEvent_; - - /// This is the delay (only applied after first event) before processing starts - static unsigned int constexpr DELAY_TO_START = 10; - bool debug_; }; diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.icc b/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.icc index 30c0dcc782929..31035c871756c 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.icc +++ b/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.icc @@ -1,180 +1,69 @@ #include #include "L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.h" - -// PIPE ENTRY AND BUFFER -template -l1ct::tdr_regionizer::PipeEntry l1ct::tdr_regionizer::Pipe::popEntry() { - assert(pipe_.size() > 0); - auto last = pipe_.back(); - // shift one over - for (size_t i = pipe_.size() - 1; i > 0; --i) { - pipe_[i] = pipe_[i - 1]; - } - pipe_[0].setInvalid(); - return last; -} - -template -void l1ct::tdr_regionizer::Pipe::reset() { - for (auto& pe : pipe_) { - pe.setInvalid(); - } -} - -template -void l1ct::tdr_regionizer::Pipes::reset() { - for (auto& pipe : pipes_) { - pipe.reset(); - } -} - -template -void l1ct::tdr_regionizer::Pipes::setTaps(size_t taps) { - for (auto& pipe : pipes_) { - pipe.setTaps(taps); - } -} +#include "FWCore/Utilities/interface/Exception.h" // BUFFER ENTRY AND BUFFER template -l1ct::tdr_regionizer::BufferEntry::BufferEntry( - const T& obj, std::vector srIndices, int glbeta, int glbphi, bool duplicate, unsigned int clk) - : obj_(obj), srIndices_(srIndices), glbeta_(glbeta), glbphi_(glbphi), duplicate_(duplicate), linkobjclk_(clk) { - objcount_ = 0; -} +l1ct::tdr_regionizer::BufferEntry::BufferEntry(const T& obj, int glbeta, int glbphi) + : obj_(obj), glbeta_(glbeta), glbphi_(glbphi) {} template -inline void l1ct::tdr_regionizer::Buffer::addEntry( - const T& obj, - std::vector srIndices, - int glbeta, - int glbphi, - bool duplicate, // this is mainly for GCT, is it one of the duplicates - unsigned int dupNum, - unsigned int ndup) { - // dupNum is the duplicate number of this buffer (int range 0 to ndup_-1) - auto objClk = nextObjClk(ndup, obj.intPt() == 0); - data_.emplace_back(obj, srIndices, glbeta, glbphi, duplicate, objClk); - if (timeOfNextObject_ < 0) { - timeOfNextObject_ = objClk; +inline void l1ct::tdr_regionizer::Buffer::addEntry(const T& obj, + std::vector srIndices, + int glbeta, + int glbphi) { + for (auto sr : srIndices) { + data_[sr].emplace_back(obj, glbeta, glbphi); // note, this creates a deque if needed } } template -void l1ct::tdr_regionizer::Buffer::updateNextObjectTime(int currTime, bool incrementTime) { - if (data_.size() > 0) { - auto nextTime = incrementTime ? currTime + 1 : currTime; - timeOfNextObject_ = std::max(front().clock(), static_cast(nextTime)); +inline bool l1ct::tdr_regionizer::Buffer::empty(size_t sr) const { + auto it = data_.find(sr); + if (it != data_.end()) { + return it->second.empty(); } else { - timeOfNextObject_ = -1; + return true; } } +// Note: This assumes there's an entry. May need to check with empty (above) first. template -inline unsigned int l1ct::tdr_regionizer::Buffer::nextObjClk(unsigned int ndup, bool skip) { - unsigned int nextVal = std::max(clkindex360_, clkindex240_) / 3; - - clkindex360_ += 2 * ndup; - - // Though a 360MHz clock is used, one doesn't need to a 240MHz clock for pt == 0 - if (!skip) { - clkindex240_ += 3; - } - return nextVal; +inline l1ct::tdr_regionizer::BufferEntry l1ct::tdr_regionizer::Buffer::getEntry(size_t sr) { + BufferEntry entry = data_[sr].front(); + data_[sr].pop_front(); + return entry; } -// explicit for tracks -template <> -inline unsigned int l1ct::tdr_regionizer::Buffer::nextObjClk(unsigned int ndup, bool skip) { - if (ndup != 1) { - throw std::invalid_argument("Only ndup==1 is currently supported for the TkObjEmu buffers."); - } - - unsigned int nextVal = std::max(clkindex360_, clkindex240_) / 3; - - clkindex360_ += 2; - if ((clkindex360_ - INIT360) % 6 == 4) { - clkindex360_ += 2; - } - - if (!skip) { - clkindex240_ += 3; +template +unsigned int l1ct::tdr_regionizer::Buffer::numEntries() const { + unsigned int count = 0; + for (const auto& [key, value] : data_) { + count += value.size(); } - return nextVal; + return count; } template -l1ct::tdr_regionizer::PipeEntry l1ct::tdr_regionizer::Buffer::popEntry(int currTime, bool debug) { - if (front().nextSR() < 0) { - // throwout - pop(); - if (debug) { - dbgCout() << "updating time clock = " << front().clock() << ", currTime = " << currTime << std::endl; - } - updateNextObjectTime(currTime); - return l1ct::tdr_regionizer::PipeEntry(); - } - - auto pipeEntry = - l1ct::tdr_regionizer::PipeEntry(front().obj(), front().nextSR(), front().glbEta(), front().glbPhi()); - front().incSR(); - if (front().nextSR() < 0) { - // no more SRs for current front - pop(); - } else { - if (debug) { - dbgCout() << "Remain on same object, nextSR = " << front().nextSR() << std::endl; - } - // this is a processing_stall, but throwouts that follow can still be dropped - // due to the pipeline have to look two ticks back - if (numEntries() > 1 && data_[1].nextSR() == -1 && static_cast(data_[1].clock()) == currTime + 2) { - if (debug) { - dbgCout() << "removing a following throwout with time " << data_[1].clock() << std::endl; - } - data_.erase(data_.begin() + 1); - } else if (numEntries() > 2 && data_[2].nextSR() == -1 && static_cast(data_[2].clock()) <= currTime + 2) { - if (debug) { - dbgCout() << "removing the two-back throwout with time " << data_[2].clock() << std::endl; - } - data_.erase(data_.begin() + 2); +void l1ct::tdr_regionizer::Buffer::printDebug(size_t bufferIdx, size_t logBufIdx) const { + for (auto srq_it = data_.rbegin(); srq_it != data_.rend(); ++srq_it) { + for (unsigned int j = 0; j < srq_it->second.size(); j++) { + dbgCout() << logBufIdx << "\t" << bufferIdx << "\t" << srq_it->first << "\t" << j << "\t" + << srq_it->second[j].pt() << "\t" << srq_it->second[j].glbEta() << "\t" << srq_it->second[j].glbPhi() + << std::endl; } + dbgCout() << "-------------------------------" << std::endl; } - if (debug) { - dbgCout() << "updating time clock = " << front().clock() << ", currTime = " << currTime << std::endl; - } - - updateNextObjectTime(currTime); - return pipeEntry; } // REGIONIZER template -l1ct::tdr_regionizer::Regionizer::Regionizer(unsigned int neta, - unsigned int nphi, - unsigned int maxobjects, - int bigRegionMin, - int bigRegionMax, - unsigned int nclocks, - unsigned int ndup, - bool debug) - : neta_(neta), - nphi_(nphi), - maxobjects_(maxobjects), - nsectors_(0), - bigRegionMin_(bigRegionMin), - bigRegionMax_(bigRegionMax), - nclocks_(nclocks), - ndup_(ndup), - pipes_(neta * nphi), - smallRegionObjects_(neta * nphi), - firstEvent_(true), - debug_(debug) {} +l1ct::tdr_regionizer::Regionizer::Regionizer(unsigned int maxobjects, bool debug) + : maxobjects_(maxobjects), debug_(debug) {} template void l1ct::tdr_regionizer::Regionizer::initSectors(const std::vector>& sectors) { - assert(nsectors_ == 0); - // we need a mapping of physical (what's in the sectors variable) to logical, // but it's easier to create the inverse, first @@ -187,17 +76,17 @@ void l1ct::tdr_regionizer::Regionizer::initSectors(const std::vector @@ -238,11 +122,10 @@ void l1ct::tdr_regionizer::Regionizer::fillBuffers(const DetectorSector& s setBuffers(fillLinks(sector)); } -// this function is for sorting small regions -// in eta first, then in phi +// this function is for sorting small regions; For consistency with new regionizer, swap order. +// New order: in phi first, then in eta template bool l1ct::tdr_regionizer::Regionizer::sortRegionsRegular(size_t a, size_t b) const { - // first do eta auto etaa = regions_[a].intEtaCenter(); auto etab = regions_[b].intEtaCenter(); auto phia = regions_[a].intPhiCenter(); @@ -251,9 +134,29 @@ bool l1ct::tdr_regionizer::Regionizer::sortRegionsRegular(size_t a, size_t b) } // this function is for sorting small regions -// in eta first, then in phi +// in phi first, then in eta template bool l1ct::tdr_regionizer::Regionizer::sortRegionsHelper(int etaa, int etab, int phia, int phib) const { + // first do phi + if (phia < phib) { + return true; + } else if (phia > phib) { + return false; + } + + // Only here if have same phi + if (etaa < etab) { + return true; + } else { + return false; + } +} + +// this function is for sorting Sectors (mainly tracker) +// note it is opposite of regions to keep consistent +// It sorts in eta first, then phi +template +bool l1ct::tdr_regionizer::Regionizer::sortSectorsHelper(int etaa, int etab, int phia, int phib) const { // first do eta if (etaa < etab) { return true; @@ -261,17 +164,7 @@ bool l1ct::tdr_regionizer::Regionizer::sortRegionsHelper(int etaa, int etab, return false; } - // if here, then etaa == etab, move to phi - if (bigRegionMax_ < bigRegionMin_) { - // the wraparound case, rewrap around pi - if (phia < 0) { - phia += l1ct::Scales::INTPHI_TWOPI; - } - if (phib < 0) { - phib += l1ct::Scales::INTPHI_TWOPI; - } - } - // regular phi + // Only here if have same eta if (phia < phib) { return true; } else { @@ -288,77 +181,32 @@ bool l1ct::tdr_regionizer::Regionizer::sortSectors(size_t a, size_t b) const auto etab = sectors_[b].intEtaCenter(); auto phia = sectors_[a].intPhiCenter(); auto phib = sectors_[b].intPhiCenter(); - return sortRegionsHelper(etaa, etab, phia, phib); + return sortSectorsHelper(etaa, etab, phia, phib); } template void l1ct::tdr_regionizer::Regionizer::initRegions(const std::vector& regions) { regions_.resize(regions.size()); + smallRegionObjects_.resize(regions.size()); for (unsigned int i = 0; i < regions.size(); ++i) { regions_[i] = regions[i].region; - if (isInBigRegion(regions_[i])) { - regionmap_.push_back(i); - if (debug_) { - dbgCout() << "region [" << i << "] eta/phi: " << regions_[i].intEtaCenter() << " " << regions_[i].intPhiCenter() - << ", eta half width = " << regions_[i].hwEtaHalfWidth.to_int() - << ", phi half width = " << regions_[i].hwPhiHalfWidth.to_int() - << ", eta extra = " << regions_[i].hwEtaExtra.to_int() - << ", phi extra = " << regions_[i].hwPhiExtra.to_int() << std::endl; - } + regionmap_.push_back(i); + if (debug_) { + dbgCout() << "region [" << i << "] eta/phi: " << regions_[i].intEtaCenter() << " " << regions_[i].intPhiCenter() + << ", eta half width = " << regions_[i].hwEtaHalfWidth.to_int() + << ", phi half width = " << regions_[i].hwPhiHalfWidth.to_int() + << ", eta extra = " << regions_[i].hwEtaExtra.to_int() + << ", phi extra = " << regions_[i].hwPhiExtra.to_int() << std::endl; } } - assert(regionmap_.size() == neta_ * nphi_); std::sort( regionmap_.begin(), regionmap_.end(), [this](size_t a, size_t b) { return this->sortRegionsRegular(a, b); }); -} - -template -bool l1ct::tdr_regionizer::Regionizer::isInBigRegion(const PFRegionEmu& reg) const { - auto phi = reg.intPhiCenter(); - if (bigRegionMax_ < bigRegionMin_) { - // the wraparound case - return phi > bigRegionMin_ || phi < bigRegionMax_; - } else { - // the normal case - return phi > bigRegionMin_ && phi < bigRegionMax_; - } -} - -template -bool l1ct::tdr_regionizer::Regionizer::isInBigRegionLoose(const PFRegionEmu& reg) const { - auto phi = reg.intPhiCenter(); - auto brmax = phi_wrap(bigRegionMax_ + reg.hwPhiHalfWidth.to_int() + reg.hwPhiExtra.to_int()); - auto brmin = phi_wrap(bigRegionMin_ - reg.hwPhiHalfWidth.to_int() - reg.hwPhiExtra.to_int()); - if (brmax < brmin) { - // the wraparound case - return phi > brmin || phi < brmax; - } else { - // the normal case - return phi > brmin && phi < brmax; - } -} - -template <> -inline bool l1ct::tdr_regionizer::Regionizer::isInBigRegionLoose(const PFRegionEmu& reg) const { - return isInBigRegion(reg); -} -template <> -inline bool l1ct::tdr_regionizer::Regionizer::isInBigRegionLoose(const PFRegionEmu& reg) const { - return isInBigRegion(reg); -} - -template <> -inline bool l1ct::tdr_regionizer::Regionizer::isInBigRegionLoose(const PFRegionEmu& reg) const { - auto phi = reg.intPhiCenter(); - auto brmax = phi_wrap(bigRegionMax_ + 2 * reg.hwPhiHalfWidth.to_int()); - auto brmin = phi_wrap(bigRegionMin_ - 2 * reg.hwPhiHalfWidth.to_int()); - if (brmax < brmin) { - // the wraparound case - return phi > brmin || phi < brmax; - } else { - // the normal case - return phi > brmin && phi < brmax; + if (debug_) { + for (auto val : regionmap_) { + dbgCout() << "regionmap_ phys index = " << val << ", eta = " << regions_[val].intEtaCenter() + << ", phi = " << regions_[val].intPhiCenter() << std::endl; + } } } @@ -379,70 +227,180 @@ std::vector l1ct::tdr_regionizer::Regionizer::getSmallRegions(int glb } } - // In a silly convention, the order of these nneds to be modified if there are 4. - if (srIndices.size() == 4) { - auto ent1 = srIndices[1]; - srIndices[1] = srIndices[2]; - srIndices[2] = ent1; - } return srIndices; } template -void l1ct::tdr_regionizer::Regionizer::addToBuffer(const T& obj, unsigned int buffer, unsigned int dupNum) { - assert(buffer < numBuffers()); - const unsigned int sector = buffer / ndup_; - auto glbphi = sectors_[sector].hwGlbPhiOf(obj).to_int(); - auto glbeta = sectors_[sector].hwGlbEtaOf(obj).to_int(); - // get the SR indices that this object should go into - buffers_[buffer].addEntry(obj, - getSmallRegions(glbeta, glbphi), - glbeta, - glbphi, - isDuplicate(obj.hwPhi.to_int(), logicBuffIndex(buffer)), - dupNum, - ndup_); -} - -template -void l1ct::tdr_regionizer::Regionizer::setBuffer(const std::vector& objvec, unsigned int buffer) { - assert(buffer < numBuffers()); - buffers_[buffer].reset(); - unsigned int dupNum = buffer % ndup_; - for (unsigned int i = dupNum; i < objvec.size(); i += ndup_) { - if (debug_) { - dbgCout() << "Buffer " << buffer << " dupNum " << dupNum << ": add obj, index " << i - << " with pt = " << objvec[i].intPt() << std::endl; +void l1ct::tdr_regionizer::Regionizer::setBuffers(const std::vector>&& objvecvec) { + assert(numBuffers() == objvecvec.size()); + for (unsigned int buffer = 0; buffer < numBuffers(); buffer++) { + assert(buffers_[buffer].numEntries() == 0); // should be empty + for (auto& obj : objvecvec[buffer]) { + auto glbphi = sectors_[buffer].hwGlbPhiOf(obj).to_int(); + auto glbeta = sectors_[buffer].hwGlbEtaOf(obj).to_int(); + if (debug_) { + dbgCout() << "Buffer " << buffer << ": add obj with pt = " << obj.intPt() << ", glb eta = " << glbeta + << ", glb phi = " << glbphi << std::endl; + } + // get the SR indices that this object should go into if pt > 0 + auto srs = (obj.intPt() > 0) ? getSmallRegions(glbeta, glbphi) : std::vector(); + if (debug_) { + if (!srs.empty()) { + std::cout << " "; + for (auto sr : srs) { + std::cout << " " << sr; + } + std::cout << std::endl; + } + } + buffers_[buffer].addEntry(obj, srs, glbeta, glbphi); } - addToBuffer(objvec[i], buffer, dupNum); } } +// sr is physical template -void l1ct::tdr_regionizer::Regionizer::setBuffers(const std::vector>&& objvecvec) { - assert(numBuffers() == objvecvec.size() * ndup_); - for (unsigned int buffer = 0; buffer < numBuffers(); buffer++) { - setBuffer(objvecvec[buffer / ndup_], buffer); +void l1ct::tdr_regionizer::Regionizer::addToSmallRegion(size_t sr, BufferEntry bufEntry) { + auto rawObj = bufEntry.obj(); + + // in small region, the relative eta and phi are based on a different center, so need to update + auto etaC = regions_[sr].intEtaCenter(); + auto phiC = regions_[sr].intPhiCenter(); + + int locEta = bufEntry.glbEta() - etaC; + int locPhi = phi_wrap(bufEntry.glbPhi() - phiC); + + rawObj.hwEta = locEta; + rawObj.hwPhi = locPhi; + + if (debug_) { + dbgCout() << "smallRegionObjects_ " << sr << " obj with pt = " << rawObj.intPt() + << ", loc eta = " << rawObj.intEta() << ", loc phi = " << rawObj.intPhi() << std::endl; + } + + if (smallRegionObjects_[sr].size() >= maxobjects_) { + return; } + + smallRegionObjects_[sr].push_back(rawObj); } +// This is a dummy, should never be used. template -void l1ct::tdr_regionizer::Regionizer::addToSmallRegion(l1ct::tdr_regionizer::PipeEntry&& pipeEntry) { - if (pipeEntry.valid()) { - auto rawObj = pipeEntry.obj(); +inline std::vector> l1ct::tdr_regionizer::Regionizer::linksForSR(size_t) const { + std::vector> retval; + throw cms::Exception("LogicError") << "This should be customized per type."; + return retval; +} - // in small region, the relative eta and phi are based on a different center, so need to update - auto realRegIdx = regionIndex(pipeEntry.sr()); - auto etaC = regions_[realRegIdx].intEtaCenter(); - auto phiC = regions_[realRegIdx].intPhiCenter(); +// returns the physical links +template <> +inline std::vector> l1ct::tdr_regionizer::Regionizer::linksForSR(size_t sr) const { + std::pair logic_sr = get_small_region(sr); + const auto& ieta = logic_sr.first; + const auto& iphi = logic_sr.second; + std::vector> retval; + if (ieta < 3) { + auto nom = iphi; + auto smaller = (nom == 0) ? 8 : nom - 1; + auto bigger = (nom == 8) ? 0 : nom + 1; + retval.emplace_back(1, sectorMapLogToPhys_[nom]); + retval.emplace_back(1, sectorMapLogToPhys_[smaller]); + retval.emplace_back(1, sectorMapLogToPhys_[bigger]); + if (ieta == 2) { + // also add the other ones + retval.emplace_back(1, sectorMapLogToPhys_[nom + 9]); + retval.emplace_back(1, sectorMapLogToPhys_[smaller + 9]); + retval.emplace_back(1, sectorMapLogToPhys_[bigger + 9]); + } + } else { + auto nom = iphi + 9; + auto smaller = (nom == 9) ? 17 : nom - 1; + auto bigger = (nom == 17) ? 9 : nom + 1; + retval.emplace_back(1, sectorMapLogToPhys_[nom]); + retval.emplace_back(1, sectorMapLogToPhys_[smaller]); + retval.emplace_back(1, sectorMapLogToPhys_[bigger]); + if (ieta == 3) { + // also add the other ones + retval.emplace_back(1, sectorMapLogToPhys_[nom - 9]); + retval.emplace_back(1, sectorMapLogToPhys_[smaller - 9]); + retval.emplace_back(1, sectorMapLogToPhys_[bigger - 9]); + } + } + return retval; +} + +// Note that these are phyisical links +template +inline std::vector> l1ct::tdr_regionizer::Regionizer::caloLinksHelper(size_t iphi) const { + if (iphi < 2) { + std::vector> retval = {{9, 3, 8, 2}, {11, 5, 10, 4}}; + return retval; + } else if (iphi < 3) { + std::vector> retval = {{11, 5, 10, 4}}; + return retval; + } else if (iphi < 5) { + std::vector> retval = {{11, 5, 10, 4}, {7, 1, 6, 0}}; + return retval; + } else if (iphi < 6) { + std::vector> retval = {{7, 1, 6, 0}}; + return retval; + } else if (iphi < 8) { + std::vector> retval = {{7, 1, 6, 0}, {9, 3, 8, 2}}; + return retval; + } else { + std::vector> retval = {{9, 3, 8, 2}}; + return retval; + } +} - int locEta = pipeEntry.glbEta() - etaC; - int locPhi = phi_wrap(pipeEntry.glbPhi() - phiC); +template <> +inline std::vector> l1ct::tdr_regionizer::Regionizer::linksForSR( + size_t sr) const { + const std::pair logic_sr = get_small_region(sr); + return caloLinksHelper(logic_sr.second); +} - rawObj.hwEta = locEta; - rawObj.hwPhi = locPhi; +template <> +inline std::vector> l1ct::tdr_regionizer::Regionizer::linksForSR( + size_t sr) const { + const std::pair logic_sr = get_small_region(sr); + return caloLinksHelper(logic_sr.second); +} - smallRegionObjects_[pipeEntry.sr()].push_back(rawObj); +template <> +inline std::vector> l1ct::tdr_regionizer::Regionizer::linksForSR(size_t) const { + std::vector> retval = {{0}}; + return retval; +} + +// This is a port of: +// function get_small_region(index : linear_small_region_t) return eta_phi_small_region_t is +// variable rval : eta_phi_small_region_t; +// begin +// rval.eta_index := index / SMALL_REGION_ETA_COUNT; +// rval.phi_index := index rem SMALL_REGION_ETA_COUNT; +// return rval; +// end function get_small_region; +template +std::pair l1ct::tdr_regionizer::Regionizer::get_small_region(size_t sr) const { + std::pair rval; + rval.second = sr / SMALL_REGION_ETA_COUNT; + rval.first = sr % SMALL_REGION_ETA_COUNT; + return rval; +} + +// Note that this also updates the index so that if if's not empty, you can directly access value +// One needs to check that the next index is not bundle.size() +template +void l1ct::tdr_regionizer::Regionizer::getNextIndex(size_t sr, + const std::vector& bundle, + size_t& nextIdx) const { + for (; nextIdx < bundle.size(); nextIdx++) { + auto& buffer = buffers_[bundle[nextIdx]]; + if (!buffer.empty(sr)) { + return; + } } } @@ -451,86 +409,32 @@ void l1ct::tdr_regionizer::Regionizer::run() { if (debug_) printDebug(-1); - // first event doesn't have a delayed start - int startTime = firstEvent_ ? 0 : DELAY_TO_START; - firstEvent_ = false; - - for (int currTime = startTime; currTime < 972 + startTime; - currTime++) { //this is the max allowable if nothing ever blocks - // not positive where 972 comes from. It seems to be 162 * 6 - - // to exit early - bool processedAll = true; // to be overwritten if not the case - - // handle the fifo buffers - for (size_t bufIdx = 0; bufIdx < buffers_.size(); ++bufIdx) { - auto& buffer = buffers_[bufIdx]; - if (buffer.timeOfNextObject() >= 0) { - processedAll = false; - } - while (buffer.timeOfNextObject() == currTime) { - // time to handle the buffer entry - const auto nextSR = buffer.front().nextSR(); - if (debug_) { - dbgCout() << "Current time " << currTime << ", handling bufIdx " << bufIdx << ", logical " - << logicBuffIndex(bufIdx) << " object with SR = " << nextSR << ", pt = " << buffer.pt() - << ", glbeta = " << buffer.glbEta() << ", glbphi = " << buffer.glbPhi() - << ", duplicate = " << buffer.duplicate() << std::endl; - } - if (buffer.pt() == 0) { // double check that this also works for tracks + for (size_t sr = 0; sr < regionmap_.size(); sr++) { + // iterate over the (logical) SRs + auto links = linksForSR(sr); // these are the physical links, in bundles + std::vector nextIndex(links.size(), 0); // this is per bundle + auto physSR = regionmap_[sr]; + bool allEmpty; + do { + allEmpty = true; + for (size_t bundleIdx = 0; bundleIdx < links.size(); bundleIdx++) { + getNextIndex(sr, links[bundleIdx], nextIndex[bundleIdx]); + if (nextIndex[bundleIdx] < links[bundleIdx].size()) { + // found a non-empty buffer in the bundle + auto& buffer = buffers_[links[bundleIdx][nextIndex[bundleIdx]]]; + allEmpty = false; + auto entry = buffer.getEntry(sr); if (debug_) { - dbgCout() << "---Throw out, don't increment time" << std::endl; + dbgCout() << "Adding to sr " << sr << " (physSR = " << physSR << ") obj with pt = " << entry.pt() + << ", glb eta = " << entry.glbEta() << ", glb phi = " << entry.glbPhi() << std::endl; } - buffer.pop(); - buffer.updateNextObjectTime(currTime, false); // do not increment time - } else if (buffer.duplicate()) { - // remove the whole object, not worrying about nextSR - if (debug_) { - dbgCout() << "---Throw out, duplicate, increment time" << std::endl; - } - buffer.pop(); - buffer.updateNextObjectTime(currTime); // do increment time - } else if (nextSR < 0 || smallRegionObjects_[nextSR].size() == maxobjects_) { - // throwout or SR full, just get rid of object - if (debug_) { - dbgCout() << "---Throw out" << std::endl; - } - buffer.popEntry(currTime, debug_); - } else { - const auto logicBufIdx = logicBuffIndex(bufIdx); - if (pipes_.valid(nextSR, logicBufIdx)) { - // The pipe already has an entry, so wait till space is available - buffer.updateNextObjectTime(currTime); - } else { - // put the value in the pipe - pipes_.addEntry(nextSR, logicBufIdx, buffer.popEntry(currTime, debug_)); - } - } - } - } - - if (debug_) - printDebug(currTime); - - // add the small regions - for (size_t i = 0; i < pipes_.size(); i++) { - addToSmallRegion(pipes_.popEntry(i)); - } - - // check ot see if you have processed all - if (processedAll) { - // first clear the pipes - for (size_t tap = 0; tap < pipes_.numTaps(); tap++) { - // add the small regions - for (size_t i = 0; i < pipes_.size(); i++) { - addToSmallRegion(pipes_.popEntry(i)); + addToSmallRegion(physSR, entry); } } - if (debug_) - printDebug(2000); - break; - } - } //end main loop + } while (!allEmpty); + } + if (debug_) + printDebug(1); } template @@ -538,102 +442,39 @@ void l1ct::tdr_regionizer::Regionizer::reset() { for (auto& buffer : buffers_) { buffer.reset(); } - pipes_.reset(); - for (auto& smallRegionObject : smallRegionObjects_) { - smallRegionObject.clear(); - } - firstEvent_ = true; -} - -template -std::map> l1ct::tdr_regionizer::Regionizer::fillRegions(bool doSort) { - std::map> srMap; - for (size_t sr = 0; sr < smallRegionObjects_.size(); sr++) { - srMap[regionIndex(sr)] = smallRegionObjects_[sr]; - if (doSort) { - std::sort(srMap[regionIndex(sr)].begin(), srMap[regionIndex(sr)].end(), std::greater<>()); - } - } - return srMap; + clearSmallRegions(); } template -size_t l1ct::tdr_regionizer::Regionizer::logicBuffIndex(size_t bufIdx) const { - const unsigned int sector = bufIdx / ndup_; - auto logSector = sectorMapPhysToLog_[sector]; - return logSector * ndup_ + bufIdx % ndup_; -} - -// default is no duplicates. Note, locPhi is for the sector, not small region -template -bool l1ct::tdr_regionizer::Regionizer::isDuplicate(int locphi, size_t logicBufIdx) const { - return false; -} - -// specialize for GCT (CHECK ESPECIALLY EDGES) -template <> -inline bool l1ct::tdr_regionizer::Regionizer::isDuplicate(int locphi, size_t logicBufIdx) const { - auto odd = logicBufIdx % 2; - if (odd) { - return locphi <= -120; - } else { - return locphi > 120; - } -} - -template <> -inline bool l1ct::tdr_regionizer::Regionizer::isDuplicate(int locphi, size_t logicBufIdx) const { - auto odd = logicBufIdx % 2; - if (odd) { - return locphi <= -120; - } else { - return locphi > 120; +void l1ct::tdr_regionizer::Regionizer::clearSmallRegions() { + for (auto& smallRegionObject : smallRegionObjects_) { + smallRegionObject.clear(); } } template void l1ct::tdr_regionizer::Regionizer::printDebug(int count) const { dbgCout() << "BUFFERS, (for " << numBuffers() << " buffers)" << std::endl; - dbgCout() << count << "\tbuffer\tlogical\titem\tpt\teta\tphi\tduplicate\tclock" << std::endl; - for (auto sector : sectorMapLogToPhys_) { - for (unsigned int dup = 0; dup < ndup_; dup++) { - const unsigned int buffer = sector * ndup_ + dup; - for (unsigned int j = 0; j < numEntries(buffer); j++) { - dbgCout() << "\t" << buffer << "\t" << logicBuffIndex(buffer) << "\t" << j << "\t" << buffers_[buffer].pt(j) - << "\t" << buffers_[buffer].glbEta(j) << "\t" << buffers_[buffer].glbPhi(j) << "\t" - << buffers_[buffer].duplicate(j) << "\t" << buffers_[buffer].clock(j) << std::endl; - } - dbgCout() << "-------------------------------" << std::endl; - } - } - dbgCout() << "PIPES, (for " << pipes_.size() << " pipes)" << std::endl; - dbgCout() << count << "\tpipe\ttap\tsr\tpt\teta\tphi" << std::endl; - for (int tap = pipes_.numTaps() - 1; tap >= 0; --tap) { - for (int pipe = pipes_.size() - 1; pipe >= 0; --pipe) { - auto entry = pipes_.entry(pipe, tap); - dbgCout() << "\t" << pipe << "\t" << tap + 1 << "\t" << entry.sr() << "\t" << entry.pt() << "\t" << entry.glbEta() - << "\t" << entry.glbPhi() << std::endl; - } - dbgCout() << "-------------------------------" << std::endl; + dbgCout() << count << "\tbuffer\tlogreg\titem\tpt\teta\tphi\t" << std::endl; + for (size_t logSector = 0; logSector < sectorMapLogToPhys_.size(); logSector++) { + auto physSector = sectorMapLogToPhys_[logSector]; + buffers_[physSector].printDebug(physSector, logSector); } dbgCout() << "SMALL REGIONS" << std::endl; - for (unsigned int region = 0; region < neta_ * nphi_; region++) { - dbgCout() << count << "\tregion\t\titem\tpt\tloceta\tlocphi" << std::endl; - auto realRegIdx = regionIndex(region); - auto etaC = regions_[realRegIdx].intEtaCenter(); - auto phiC = regions_[realRegIdx].intPhiCenter(); - for (unsigned int j = 0; j < smallRegionObjects_[region].size(); j++) { - dbgCout() << "\t" << region << " (" << etaC << ", " << phiC << ")\t" << j << "\t" - << smallRegionObjects_[region][j].intPt() << "\t" << smallRegionObjects_[region][j].intEta() << "\t" - << smallRegionObjects_[region][j].intPhi() << std::endl; + for (unsigned int region = 0; region < regionmap_.size(); region++) { + dbgCout() << count << "\tregion\t\tphysRegion\titem\tpt\tloceta\tlocphi\tpacked" << std::endl; + auto physRegIdx = regionIndex(region); + auto etaC = regions_[physRegIdx].intEtaCenter(); + auto phiC = regions_[physRegIdx].intPhiCenter(); + for (unsigned int j = 0; j < smallRegionObjects_[physRegIdx].size(); j++) { + dbgCout() << "\t" << region << " (" << etaC << ", " << phiC << ")\t\t" << physRegIdx << "\t" << j << "\t" + << smallRegionObjects_[physRegIdx][j].intPt() << "\t" << smallRegionObjects_[physRegIdx][j].intEta() + << "\t" << smallRegionObjects_[physRegIdx][j].intPhi() << "\t" + << smallRegionObjects_[physRegIdx][j].pack().to_string(16) << std::endl; } dbgCout() << "-------------------------------" << std::endl; } - dbgCout() << "TIMES" << std::endl; - for (unsigned int i = 0; i < numBuffers(); i++) { - dbgCout() << " " << buffers_[i].timeOfNextObject(); - } dbgCout() << "\n-------------------------------" << std::endl; } @@ -648,11 +489,9 @@ std::vector> l1ct::tdr_regionizer::Regionizer::fillLinks( } //one link per sector for (const auto& sector : sectors) { - if (isInBigRegionLoose(sector.region)) { - links.emplace_back(); - for (unsigned int io = 0; io < sector.size() && io < nclocks_; io++) { - links.back().push_back(sector[io]); - } + links.emplace_back(); + for (unsigned int io = 0; io < sector.size(); io++) { + links.back().push_back(sector[io]); } } @@ -668,7 +507,7 @@ std::vector> l1ct::tdr_regionizer::Regionizer::fillLinks(const } links.emplace_back(); - for (unsigned int io = 0; io < sector.size() && io < nclocks_; io++) { + for (unsigned int io = 0; io < sector.size(); io++) { links.back().push_back(sector[io]); } return links; diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_ref.h b/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_ref.h index 3ee4950c81e01..eb78f2c3de183 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_ref.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_ref.h @@ -4,6 +4,8 @@ #include "L1Trigger/Phase2L1ParticleFlow/interface/regionizer/regionizer_base_ref.h" #include "L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.h" +// This is the second, alternate implementation of the TDR regionizer, which doesn't use a pipe for overlaps + namespace edm { class ParameterSet; class ParameterSetDescription; @@ -16,9 +18,10 @@ namespace l1ct { uint32_t ncalo, uint32_t nem, uint32_t nmu, - uint32_t nclocks, - std::vector bigRegionEdges, - bool dosort); + bool debug_tk = false, + bool debug_calo = false, + bool debug_emcalo = false, + bool debug_mu = false); // note: this one will work only in CMSSW TDRRegionizerEmulator(const edm::ParameterSet& iConfig); @@ -32,27 +35,15 @@ namespace l1ct { void run(const RegionizerDecodedInputs& in, std::vector& out) override; private: - /// The nubmer of barrel big regions (boards) - uint32_t nBigRegions_; /// The maximum number of objects of each type to output per small region uint32_t ntk_, ncalo_, nem_, nmu_; - /// The number of clocks to receive all data of an event (TMUX18 = 162) - uint32_t nclocks_; - - /// The phi edges of the big regions (boards); one greater than the number of boards - std::vector bigRegionEdges_; - - bool dosort_; - - /// The number of eta and phi small regions in a big region (board) - uint32_t netaInBR_, nphiInBR_; bool init_; // has initialization happened - std::vector> tkRegionizers_; - std::vector> hadCaloRegionizers_; - std::vector> emCaloRegionizers_; - std::vector> muRegionizers_; + tdr_regionizer::Regionizer tkRegionizers_; + tdr_regionizer::Regionizer hadCaloRegionizers_; + tdr_regionizer::Regionizer emCaloRegionizers_; + tdr_regionizer::Regionizer muRegionizers_; }; } // namespace l1ct diff --git a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc index b54b611885a10..1d1bbcdec6ffe 100644 --- a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc +++ b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCorrelatorLayer1Producer.cc @@ -48,16 +48,11 @@ #include "DataFormats/L1TCorrelator/interface/TkEm.h" #include "DataFormats/L1TCorrelator/interface/TkEmFwd.h" -#include "DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h" -#include "DataFormats/L1TCalorimeterPhase2/interface/GCTEmDigiCluster.h" -// #include "DataFormats/L1TCalorimeterPhase2/interface/CaloCrystalCluster.h" -#include "DataFormats/L1TCalorimeterPhase2/interface/DigitizedClusterCorrelator.h" -#include "DataFormats/L1THGCal/interface/HGCalMulticluster.h" +//#include "DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h" +//#include "DataFormats/L1TCalorimeterPhase2/interface/GCTEmDigiCluster.h" +#include "DataFormats/L1TCalorimeterPhase2/interface/DigitizedCaloToCorrelatorTM18.h" -constexpr unsigned int calomapping[] = {3, 0, 9, 6, 4, 1, 10, 7, 5, 2, 11, 8}; -// regions order: GCT1 SLR1, GCT1 SLR3, GCT2 SLR1, GCT2 SLR3, GCT3 SLR1, GCT3SLR3 -// phi center: 10 70 130 -170 -110 -50 -// eta: + - +#include "DataFormats/L1THGCal/interface/HGCalMulticluster.h" //-------------------------------------------------------------------------------------------------- class L1TCorrelatorLayer1Producer : public edm::stream::EDProducer<> { @@ -86,8 +81,7 @@ class L1TCorrelatorLayer1Producer : public edm::stream::EDProducer<> { edm::EDGetTokenT hadHGCalCands_; // can alternately give the raw containers (for GCT) - edm::EDGetTokenT emGCTRawCands_; - edm::EDGetTokenT hadGCTRawCands_; + edm::EDGetTokenT gctRawCands_; float emPtCut_, hadPtCut_; @@ -153,8 +147,7 @@ class L1TCorrelatorLayer1Producer : public edm::stream::EDProducer<> { // GCT input clusters void addGCTHadCalo(const l1t::PFCluster &calo, const edm::Ptr &caloPtr); // for GCT raw calos as input - void addGCTEmCaloRaw(const l1tp2::GCTEmDigiClusterLink &link, unsigned int linkidx, unsigned int entidx); - void addGCTHadCaloRaw(const l1tp2::GCTHadDigiClusterLink &link, unsigned int linkidx, unsigned int entidx); + void addGCTCaloRaw(const l1tp2::GCTDigiClusterLink &link, unsigned int linkidx, unsigned int entidx); // add objects in already-decoded format void addDecodedTrack(l1ct::DetectorSector &sec, const l1t::PFTrack &t); void addDecodedMuon(l1ct::DetectorSector &sec, const l1t::SAMuon &t); @@ -165,6 +158,9 @@ class L1TCorrelatorLayer1Producer : public edm::stream::EDProducer<> { const l1ct::DetectorSector> &sec, const l1t::HGCalMulticluster &c) const; + unsigned int emDecodedIndex(unsigned int linkidx, unsigned int entidx) const; + unsigned int hadDecodedIndex(unsigned int linkidx, unsigned int entidx) const; + // fetching outputs std::unique_ptr fetchHadCalo() const; std::unique_ptr fetchEmCalo() const; @@ -278,26 +274,30 @@ L1TCorrelatorLayer1Producer::L1TCorrelatorLayer1Producer(const edm::ParameterSet } else if (hgcalInAlgo != "None") throw cms::Exception("Configuration", "Unsupported hgcalInputConversionAlgo"); } + + // Note, currently do not support "Ideal" EM cluster algorithm, but one should be able to add it + // analogously to how the hadronic version is done. const std::string &gctEmInAlgo = iConfig.getParameter("gctEmInputConversionAlgo"); - const edm::InputTag emClusters = iConfig.getParameter("emClusters"); - if (!emClusters.label().empty()) { + const std::string &gctHadInAlgo = iConfig.getParameter("gctHadInputConversionAlgo"); + const edm::InputTag gctClusters = iConfig.getParameter("gctClusters"); + if (!gctClusters.label().empty()) { + if (gctEmInAlgo == "Emulator" || gctHadInAlgo == "Emulator") { + gctRawCands_ = consumes(gctClusters); + } if (gctEmInAlgo == "Emulator") { - gctEmInput_ = std::make_unique( + gctEmInput_ = std::make_unique( // FIXME iConfig.getParameter("gctEmInputConversionParameters")); - emGCTRawCands_ = consumes(emClusters); - } else if (gctEmInAlgo != "None") + } else if (gctEmInAlgo != "None") { throw cms::Exception("Configuration", "Unsupported gctEmInputConversionAlgo"); + } } - const std::string &gctHadInAlgo = iConfig.getParameter("gctHadInputConversionAlgo"); - if (!hadClusters.label().empty()) { - if (gctHadInAlgo == "Emulator") { - gctHadInput_ = std::make_unique( - iConfig.getParameter("gctHadInputConversionParameters")); - hadGCTRawCands_ = consumes(hadClusters); - } else if (gctHadInAlgo == "Ideal") { - hadGCTCands_ = consumes(hadClusters); - } else if (gctHadInAlgo != "None") - throw cms::Exception("Configuration", "Unsupported gctHadInputConversionAlgo"); + if (!gctClusters.label().empty() && gctHadInAlgo == "Emulator") { + gctHadInput_ = std::make_unique( + iConfig.getParameter("gctHadInputConversionParameters")); + } else if (!hadClusters.label().empty() && gctHadInAlgo == "Ideal") { + hadGCTCands_ = consumes(hadClusters); + } else if (gctHadInAlgo != "None") { + throw cms::Exception("Configuration", "Unsupported gctHadInputConversionAlgo"); } const std::string ®algo = iConfig.getParameter("regionizerAlgo"); @@ -395,7 +395,7 @@ void L1TCorrelatorLayer1Producer::fillDescriptions(edm::ConfigurationDescription // Inputs and cuts desc.add("tracks", edm::InputTag("")); desc.add("muons", edm::InputTag("l1tSAMuonsGmt", "prompt")); - desc.add("emClusters", edm::InputTag("")); + desc.add("gctClusters", edm::InputTag("")); desc.add("hadClusters", edm::InputTag("")); desc.add("vtxCollection", edm::InputTag("l1tVertexFinderEmulator", "L1VerticesEmulation")); desc.add("vtxCollectionEmulation", true); @@ -450,6 +450,11 @@ void L1TCorrelatorLayer1Producer::fillDescriptions(edm::ConfigurationDescription caloSectorPSD.add("phiSlices", 3); caloSectorPSD.add("phiZero", 0.); desc.addVPSet("caloSectors", caloSectorPSD); + edm::ParameterSetDescription rawGCTSectorPSD; + rawGCTSectorPSD.add>("etaBoundaries"); + rawGCTSectorPSD.add("phiSlices", 3); + rawGCTSectorPSD.add("phiZero", 0.); + desc.addVPSet("rawGCTSectors", rawGCTSectorPSD, std::vector()); // raw can be packed per link // geometry: regions edm::ParameterSetDescription regionPSD; regionPSD.add>("etaBoundaries"); @@ -533,13 +538,13 @@ void L1TCorrelatorLayer1Producer::produce(edm::Event &iEvent, const edm::EventSe // ------ READ CALOS ----- // this is for parsing raw calo information - if (!emGCTRawCands_.isUninitialized()) { - auto caloHandle = iEvent.getHandle(emGCTRawCands_); + if (!gctRawCands_.isUninitialized()) { + auto caloHandle = iEvent.getHandle(gctRawCands_); const auto &links = *caloHandle; for (unsigned int ic = 0; ic < links.size(); ++ic) { - const auto &link = links[ic]; + const auto &link = links[ic].linkCard(); for (unsigned int ie = 0; ie < link.size(); ++ie) { - addGCTEmCaloRaw(link, ic, ie); + addGCTCaloRaw(link, ic, ie); } } } @@ -555,18 +560,7 @@ void L1TCorrelatorLayer1Producer::produce(edm::Event &iEvent, const edm::EventSe } } - if (!hadGCTRawCands_.isUninitialized()) { - auto caloHandle = iEvent.getHandle(hadGCTRawCands_); - const auto &links = *caloHandle; - for (unsigned int ic = 0; ic < links.size(); ++ic) { - const auto &link = links[ic]; - for (unsigned int ie = 0; ie < link.size(); ++ie) { - addGCTHadCaloRaw(link, ic, ie); - } - } - } - - if (!hadGCTCands_.isUninitialized()) { + if (!hadGCTCands_.isUninitialized()) { // this is only for the Ideal (not Emulated) case auto caloHandle = iEvent.getHandle(hadGCTCands_); if (caloHandle.isValid()) { const auto &calos = *caloHandle; @@ -809,12 +803,6 @@ void L1TCorrelatorLayer1Producer::addDecodedEmCalo(l1ct::EmCaloObjEmu &decCalo, l1ct::DetectorSector &sec) { clusterRefMap_[caloPtr.get()] = caloPtr; decCalo.src = caloPtr.get(); - if (decCalo.hwPt > 0) { // NOTE: 0 pt clusters have null ptr. Do we need to keep them? - // FIXME: for now we extract these from the upstream object since they are not yet available in the digi format - const l1tp2::CaloCrystalCluster *crycl = dynamic_cast(decCalo.src); - decCalo.hwShowerShape = l1ct::shower_shape_t(crycl->e2x5() / crycl->e5x5()); - decCalo.hwRelIso = l1ct::Scales::makeRelIso(crycl->isolation() / decCalo.hwPt.to_float()); - } sec.obj.push_back(decCalo); } @@ -866,8 +854,7 @@ void L1TCorrelatorLayer1Producer::initSectorsAndRegions(const edm::ParameterSet event_.decoded.emcalo.clear(); event_.decoded.hadcalo.clear(); event_.raw.hgcalcluster.clear(); - event_.raw.gctEm.clear(); - event_.raw.gctHad.clear(); + event_.raw.gctcluster.clear(); for (const edm::ParameterSet &preg : iConfig.getParameter("caloSectors")) { std::vector etaBoundaries = preg.getParameter>("etaBoundaries"); @@ -887,12 +874,29 @@ void L1TCorrelatorLayer1Producer::initSectorsAndRegions(const edm::ParameterSet event_.decoded.hadcalo.emplace_back(etaBoundaries[ieta], etaBoundaries[ieta + 1], phiCenter, phiWidth); event_.decoded.emcalo.emplace_back(etaBoundaries[ieta], etaBoundaries[ieta + 1], phiCenter, phiWidth); event_.raw.hgcalcluster.emplace_back(etaBoundaries[ieta], etaBoundaries[ieta + 1], phiCenter, phiWidth); - event_.raw.gctEm.emplace_back(etaBoundaries[ieta], etaBoundaries[ieta + 1], phiCenter, phiWidth); - event_.raw.gctHad.emplace_back(etaBoundaries[ieta], etaBoundaries[ieta + 1], phiCenter, phiWidth); } } } + for (const edm::ParameterSet &preg : iConfig.getParameter("rawGCTSectors")) { + std::vector etaBoundaries = preg.getParameter>("etaBoundaries"); + if (!std::is_sorted(etaBoundaries.begin(), etaBoundaries.end())) + throw cms::Exception("Configuration", "caloSectors.etaBoundaries not sorted\n"); + unsigned int phiSlices = preg.getParameter("phiSlices"); + float phiWidth = 2 * M_PI / phiSlices; + if (phiWidth > 2 * l1ct::Scales::maxAbsPhi()) + throw cms::Exception("Configuration", "caloSectors phi range too large for phi_t data type"); + double phiZero = preg.getParameter("phiZero"); + for (unsigned int ieta = 0, neta = etaBoundaries.size() - 1; ieta < neta; ++ieta) { + float etaWidth = etaBoundaries[ieta + 1] - etaBoundaries[ieta]; + if (etaWidth > 2 * l1ct::Scales::maxAbsEta()) + throw cms::Exception("Configuration", "caloSectors eta range too large for eta_t data type"); + for (unsigned int iphi = 0; iphi < phiSlices; ++iphi) { + float phiCenter = reco::reducePhiRange(iphi * phiWidth + phiZero); + event_.raw.gctcluster.emplace_back(etaBoundaries[ieta], etaBoundaries[ieta + 1], phiCenter, phiWidth); + } + } + } event_.decoded.muon.region = l1ct::PFRegionEmu(0., 0.); // centered at (0,0) event_.raw.muon.region = l1ct::PFRegionEmu(0., 0.); // centered at (0,0) @@ -1001,25 +1005,58 @@ void L1TCorrelatorLayer1Producer::addHGCalHadCalo(const l1t::HGCalMulticluster & } } -void L1TCorrelatorLayer1Producer::addGCTEmCaloRaw(const l1tp2::GCTEmDigiClusterLink &link, - unsigned int linkidx, - unsigned int entidx) { - // in the "Ideal" regionizer, ignore the second set that is sent; only use the first - auto caloIdx = calomapping[linkidx]; - if (caloIdx < event_.raw.gctEm.size()) { - event_.raw.gctEm[caloIdx].obj.push_back(link[entidx].data()); - addDecodedGCTEmCalo(event_.decoded.emcalo[caloIdx], link[entidx]); +// The raw to decoded index mapping is +// raw -> eta+ slr1 eta- slr1 eta+ slr3 eta1 slr3 +// 0 7 1 6 0 +// 1 9 3 8 2 +// 2 11 5 10 4 + +unsigned int L1TCorrelatorLayer1Producer::emDecodedIndex(unsigned int linkidx, unsigned int entidx) const { + if (entidx < 17) { + return 2 * linkidx + 7; + } else if (entidx < 81) { + return 2 * linkidx + 1; + } else if (entidx < 98) { + return 2 * linkidx + 6; + } else { + return 2 * linkidx; + } +} + +unsigned int L1TCorrelatorLayer1Producer::hadDecodedIndex(unsigned int linkidx, unsigned int entidx) const { + if (entidx < 57) { + return 2 * linkidx + 7; + } else if (entidx < 81) { + return 2 * linkidx + 1; + } else if (entidx < 138) { + return 2 * linkidx + 6; + } else { + return 2 * linkidx; } } -void L1TCorrelatorLayer1Producer::addGCTHadCaloRaw(const l1tp2::GCTHadDigiClusterLink &link, - unsigned int linkidx, - unsigned int entidx) { - // in the "Ideal" regionizer, ignore the second set that is sent; only use the first - auto caloIdx = calomapping[linkidx]; - if (caloIdx < event_.raw.gctHad.size()) { - event_.raw.gctHad[caloIdx].obj.push_back(link[entidx].data()); - addDecodedGCTHadCalo(event_.decoded.hadcalo[caloIdx], link[entidx]); +void L1TCorrelatorLayer1Producer::addGCTCaloRaw(const l1tp2::GCTDigiClusterLink &link, + unsigned int linkidx, + unsigned int entidx) { + if (auto p = std::get_if(&link[entidx])) { + // (For EM don't currently support ideal, so it is always Emulated) + event_.raw.gctcluster[linkidx].obj.push_back(p->data()); + if (p->pt() > 0) { + auto decidx = emDecodedIndex(linkidx, entidx); + addDecodedGCTEmCalo(event_.decoded.emcalo[decidx], *p); + } + } else if (auto p = std::get_if(&link[entidx])) { + // Only do this if using Emulated GCT input, not Ideal. + if (hadGCTCands_.isUninitialized()) { + event_.raw.gctcluster[linkidx].obj.push_back(p->data()); + if (p->pt() > 0) { + auto decidx = hadDecodedIndex(linkidx, entidx); + addDecodedGCTHadCalo(event_.decoded.hadcalo[decidx], *p); + } + } + } else { + // this is the extra data that is neither had nor em + event_.raw.gctcluster[linkidx].obj.push_back(0); // the value should not be used } } @@ -1083,7 +1120,6 @@ void L1TCorrelatorLayer1Producer::addDecodedGCTEmCalo(l1ct::DetectorSectordecode(sec.region, digi.data()); auto caloPtr = edm::refToPtr(digi.clusterRef()); - // FIXME: should check hwPt > 0 addDecodedEmCalo(calo, caloPtr, sec); } @@ -1092,7 +1128,6 @@ void L1TCorrelatorLayer1Producer::addDecodedGCTHadCalo(l1ct::DetectorSectordecode(sec.region, digi.data()); auto caloPtr = edm::refToPtr(digi.clusterRef()); - // FIXME: should check hwPt > 0 addDecodedHadCalo(calo, caloPtr, sec); } diff --git a/L1Trigger/Phase2L1ParticleFlow/plugins/PFClusterProducerFromL1EGClusters.cc b/L1Trigger/Phase2L1ParticleFlow/plugins/PFClusterProducerFromL1EGClusters.cc index 149b4ca8c5315..ecbbd85a85130 100644 --- a/L1Trigger/Phase2L1ParticleFlow/plugins/PFClusterProducerFromL1EGClusters.cc +++ b/L1Trigger/Phase2L1ParticleFlow/plugins/PFClusterProducerFromL1EGClusters.cc @@ -88,8 +88,7 @@ void l1tpf::PFClusterProducerFromL1EGClusters::produce(edm::Event &iEvent, const // bit 0: standaloneWP: is_iso && is_ss // bit 1: looseL1TkMatchWP: is_looseTkiso && is_looseTkss // bit 2: photonWP: - unsigned int qual = (digiCryCl.passes_iso() && digiCryCl.passes_ss()) | - ((digiCryCl.passes_looseTkiso() && digiCryCl.passes_looseTkss()) << 1) | (false << 2); + unsigned int qual = digiCryCl.wp(); cluster.setHwQual(qual); // cluster.setDigiWord(digiCryCl.data()); out->push_back(cluster); @@ -109,8 +108,7 @@ void l1tpf::PFClusterProducerFromL1EGClusters::produce(edm::Event &iEvent, const if (corrector_.valid()) corrector_.correctPt(cluster); cluster.setPtError(resol_(cluster.pt(), std::abs(cluster.eta()))); - unsigned int qual = (digiCryCl.passes_iso() && digiCryCl.passes_ss()) | - ((digiCryCl.passes_looseTkiso() && digiCryCl.passes_looseTkss()) << 1) | (false << 2); + unsigned int qual = digiCryCl.wp(); cluster.setHwQual(qual); // cluster.setDigiWord(digiCryCl.data()); diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1TkEgAlgoEmulator_cfi.py b/L1Trigger/Phase2L1ParticleFlow/python/l1TkEgAlgoEmulator_cfi.py index e55c9530ec6c2..855f54116fc34 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1TkEgAlgoEmulator_cfi.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/l1TkEgAlgoEmulator_cfi.py @@ -62,14 +62,14 @@ ), #Algorithm 4: compositeEB_v1 cms.PSet( - model=cms.string("L1Trigger/Phase2L1ParticleFlow/data/egamma/compositeID_EB_v1.json"), + model=cms.string("L1Trigger/Phase2L1ParticleFlow/data/egamma/compositeID_EB_v1.1.json"), loose_wp=cms.PSet( bins=cms.vdouble(0), values=cms.vdouble(-1) ), tight_wp=cms.PSet( - bins=cms.vdouble(0, 5, 10, 30), - values=cms.vdouble(0.17, 0.018, -0.08, -0.11), + bins=cms.vdouble(0, 5.75, 9.25, 11.25, 15, 28.75, 33.25), + values=cms.vdouble(0.09375, -0.015625, -0.0742188, -0.109375, -0.144531, -0.201172, -0.242188), ), dPhi_max = cms.double(0.3), dEta_max = cms.double(0.03), diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py index 471cd1addaec6..8c40db9a169cf 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_cff.py @@ -10,12 +10,15 @@ from L1Trigger.Phase2L1ParticleFlow.mlAssociation_cfi import NNVtxAssociationPSet switchOnNNAssoc = cms.bool(False) +virtBoard0 = (5, 14, 23, 32, 41, 50, 6, 15, 24, 33, 42, 51, 7, 16, 25, 34, 43, 52) +virtBoard1 = (8, 17, 26, 35, 44, 53, 0, 9, 18, 27, 36, 45, 1, 10, 19, 28, 37, 46) +virtBoard2 = (2, 11, 20, 29, 38, 47, 3, 12, 21, 30, 39, 48, 4, 13, 22, 31, 40, 49) + l1tLayer1Barrel = cms.EDProducer("L1TCorrelatorLayer1Producer", tracks = cms.InputTag('l1tPFTracksFromL1Tracks'), muons = cms.InputTag('l1tSAMuonsGmt','prompt'), - emClusters = cms.InputTag('l1tPhase2GCTBarrelToCorrelatorLayer1Emulator', 'GCTEmDigiClusters'), - hadClusters = cms.InputTag('l1tPFClustersFromCombinedCaloHCal:calibrated'), - # hadClusters = cms.InputTag('l1tPhase2GCTBarrelToCorrelatorLayer1Emulator', 'GCTHadDigiClusters'), + gctClusters = cms.InputTag("l1tPhase2CaloToCorrelatorTM18", "DigitizedCaloToCorrelatorTM18"), + # hadClusters = cms.InputTag('l1tPFClustersFromCombinedCaloHCal:calibrated'), -- if you use Ideal gctHadInputConversionAlg vtxCollection = cms.InputTag("l1tVertexFinderEmulator","L1VerticesEmulation"), nVtx = cms.int32(1), emPtCut = cms.double(0.5), @@ -40,8 +43,7 @@ muonInputConversionAlgo = cms.string("Emulator"), gctEmInputConversionAlgo = cms.string("Emulator"), gctEmInputConversionParameters = cms.PSet( - # gctEmCorrector = cms.string("L1Trigger/Phase2L1ParticleFlow/data/emcorr_barrel.root"), - gctEmCorrector = cms.string(""), + gctEmCorrector = cms.string("L1Trigger/Phase2L1ParticleFlow/data/emcorr_barrel.root"), gctEmResol = cms.PSet( etaBins = cms.vdouble( 0.700, 1.200, 1.600), offset = cms.vdouble( 0.873, 1.081, 1.563), @@ -49,7 +51,16 @@ kind = cms.string('calo'), ), ), - gctHadInputConversionAlgo = cms.string("Ideal"), + gctHadInputConversionAlgo = cms.string("Emulator"), + gctHadInputConversionParameters = cms.PSet( + gctHadCorrector = cms.string("L1Trigger/Phase2L1ParticleFlow/data/hadcorr_barrel.root"), + gctHadResol = cms.PSet( + etaBins = cms.vdouble( 0.700, 1.200, 1.600), + offset = cms.vdouble( 3.675, 2.694, 1.640), + scale = cms.vdouble( 0.121, 0.156, 0.292), + kind = cms.string('calo'), + ), + ), regionizerAlgo = cms.string("Ideal"), pfAlgo = cms.string("PFAlgo3"), pfAlgoParameters = cms.PSet( @@ -108,14 +119,24 @@ ), tkEgSorterAlgo = cms.string("Barrel"), tkEgSorterParameters = tkEgSorterParameters.clone( - nObjToSort = 10 + nObjToSort = 16 ), - caloSectors = cms.VPSet( # for Ideal regionizer only--don't include the duplicates + # these are the sectors for the logical "decoded" clusters; + caloSectors = cms.VPSet( cms.PSet( etaBoundaries = cms.vdouble(-1.5, 0, 1.5), - phiSlices = cms.uint32(3), + phiSlices = cms.uint32(6), phiZero = cms.double(math.pi/18) - ) + ), + ), + + # these are the sectors for the raw GCT clusters; logical sectors can be combined + rawGCTSectors = cms.VPSet( + cms.PSet( + etaBoundaries = cms.vdouble(-1.5, 1.5), + phiSlices = cms.uint32(3), + phiZero = cms.double(2 * math.pi/9) + ), ), regions = cms.VPSet( cms.PSet( @@ -123,13 +144,10 @@ phiSlices = cms.uint32(9), ), ), - boards = cms.VPSet( - cms.PSet( - regions = cms.vuint32(*[0+9*ie+i for ie in range(6) for i in range(3)])), # phi splitting - cms.PSet( - regions = cms.vuint32(*[3+9*ie+i for ie in range(6) for i in range(3)])), # phi splitting - cms.PSet( - regions = cms.vuint32(*[6+9*ie+i for ie in range(6) for i in range(3)])), # phi splitting + boards = cms.VPSet( # In TM18, this is "virtual" boards for egamma + cms.PSet(regions = cms.vuint32(*virtBoard0)), # phi splitting + cms.PSet(regions = cms.vuint32(*virtBoard1)), # phi splitting + cms.PSet(regions = cms.vuint32(*virtBoard2)), # phi splitting ), ) @@ -152,7 +170,6 @@ l1tLayer1HGCal = cms.EDProducer("L1TCorrelatorLayer1Producer", tracks = cms.InputTag('l1tPFTracksFromL1Tracks'), muons = cms.InputTag('l1tSAMuonsGmt','prompt'), - emClusters = cms.InputTag(""), # the em clusters are "intercepted" from the had ones in the regionizer hadClusters = cms.InputTag("l1tHGCalBackEndLayer2Producer","HGCalBackendLayer2Processor3DClustering"), vtxCollection = cms.InputTag("l1tVertexFinderEmulator","L1VerticesEmulation"), nVtx = cms.int32(1), @@ -330,7 +347,6 @@ l1tLayer1HGCalNoTK = cms.EDProducer("L1TCorrelatorLayer1Producer", muons = cms.InputTag('l1tSAMuonsGmt','prompt'), - emClusters = cms.InputTag(""), hadClusters = cms.InputTag("l1tHGCalBackEndLayer2Producer","HGCalBackendLayer2Processor3DClustering"), vtxCollection = cms.InputTag("l1tVertexFinderEmulator","L1VerticesEmulation"), nVtx = cms.int32(1), @@ -446,7 +462,6 @@ l1tLayer1HF = cms.EDProducer("L1TCorrelatorLayer1Producer", muons = cms.InputTag('l1tSAMuonsGmt','prompt'), - emClusters = cms.InputTag(''), hadClusters = cms.InputTag('l1tPFClustersFromCombinedCaloHF:calibrated'), gctHadInputConversionAlgo = cms.string("Ideal"), vtxCollection = cms.InputTag("l1tVertexFinderEmulator","L1VerticesEmulation"), diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_patternWriters_cff.py b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_patternWriters_cff.py index 8bec8adc9dde1..61587c10ca8d6 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_patternWriters_cff.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer1_patternWriters_cff.py @@ -6,85 +6,51 @@ ##################################################################################################################### ## Barrel configurations: 54 regions, 6 puppi output links, only write out the layer 1 outputs for now + +virtBoard0 = (5, 14, 23, 32, 41, 50, 6, 15, 24, 33, 42, 51, 7, 16, 25, 34, 43, 52) +virtBoard1 = (8, 17, 26, 35, 44, 53, 0, 9, 18, 27, 36, 45, 1, 10, 19, 28, 37, 46) +virtBoard2 = (2, 11, 20, 29, 38, 47, 3, 12, 21, 30, 39, 48, 4, 13, 22, 31, 40, 49) + +srOrder = virtBoard0 + virtBoard1 + virtBoard2 + _barrelWriterOutputOnly = cms.PSet( partition = cms.string("Barrel"), - tmuxFactor = cms.uint32(6), + tmuxFactor = cms.uint32(18), outputLinksPuppi = cms.vuint32(*range(6)), outputLinkEgamma = cms.int32(6), nEgammaObjectsOut = cms.uint32(16), nInputFramesPerBX = cms.uint32(9), nOutputFramesPerBX = cms.uint32(9), - fileFormat = cms.string("EMPv2"), + fileFormat = cms.string("APx"), inputFileExtension = cms.string("txt.gz"), outputFileExtension = cms.string("txt.gz"), maxLinesPerInputFile = cms.uint32(1024), maxLinesPerOutputFile = cms.uint32(1024), eventsPerFile = cms.uint32(_eventsPerFile), - tfTimeSlices = cms.VPSet(), - gmtTimeSlices = cms.VPSet(), gmtNumberOfMuons = cms.uint32(12), + gmtLink = cms.int32(-1), + gctSectors = cms.VPSet(), + tfSectors = cms.VPSet(), gttLink = cms.int32(-1), - gttLatency = cms.uint32(156+10), + gttLatency = cms.uint32(167), gttNumberOfPVs = cms.uint32(_gttNumberOfPVs), - gctEmSectors = cms.VPSet(), - gctHadSectors = cms.VPSet(), tfNumberOfTracks = cms.uint32(108), - gctNumberOfEMs = cms.uint32(32), - gctNumberOfHads = cms.uint32(48), + gctNumberOfObjects = cms.uint32(162), + outputRegions = cms.vuint32(*srOrder), + outputBoard = cms.int32(0), ) ## Barrel (54) split in 3 phi slices (EMP format) barrelWriterOutputOnlyPhiConfigs = [ _barrelWriterOutputOnly.clone( + fileFormat = cms.string("EMPv2"), + tmuxFactor = cms.uint32(6), outputRegions = cms.vuint32(*[3*ip+9*ie+i for ie in range(6) for i in range(3) ]), outputBoard = cms.int32(ip), outputFileName = cms.string("l1BarrelPhi%d-outputs" % (ip+1)) ) for ip in range(3) ] -def _sortApxRegions(etaPhiSortedRegions): - """Returns the APx output order for a tuple/list of regions (ints) - """ - apxOrder = (0, 4, 2, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 16, 15, 1, 17, 3) - if len(etaPhiSortedRegions) != len(apxOrder): - raise RuntimeError(f"Unexptected number of regions passed: {len(etaPhiSortedRegions)}") - return [etaPhiSortedRegions[apxOrder[i]] for i in range(len(apxOrder))] - -## Barrel (54) split in 3 phi slices (APx format) -barrelWriterOutputOnlyPhiConfigsAPx = [ - _barrelWriterOutputOnly.clone( - fileFormat = cms.string("APx"), - outputRegions = cms.vuint32(*_sortApxRegions([3*ip+9*ie+i for ie in range(6) for i in range(3) ])), - outputBoard = cms.int32(ip), - outputFileName = cms.string("l1BarrelApxPhi%d-outputs" % (ip+1)) - ) for ip in range(3) -] - -barrelWriterDebugPFInConfigsAPx = [ - _barrelWriterOutputOnly.clone( - fileFormat = cms.string("APx"), - outputRegions = cms.vuint32(*_sortApxRegions([3*ip+9*ie+i for ie in range(6) for i in range(3) ])), - outputBoard = cms.int32(ip), - nPFInTrack = cms.uint32(22), - nPFInEmCalo = cms.uint32(12), - nPFInHadCalo = cms.uint32(15), - nPFInMuon = cms.uint32(2), - debugFileName = cms.string("l1BarrelApxPhi%d-pfin" % (ip+1)) - ) for ip in range(3) -] - -barrelWriterDebugPFOutConfigsAPx = [ - _barrelWriterOutputOnly.clone( - fileFormat = cms.string("APx"), - outputRegions = cms.vuint32(*_sortApxRegions([3*ip+9*ie+i for ie in range(6) for i in range(3) ])), - outputBoard = cms.int32(ip), - nPFOutCharged = cms.uint32(22), - nPFOutPhoton = cms.uint32(12), - nPFOutNeutral = cms.uint32(15), - nPFOutMuon = cms.uint32(2), - debugFileName = cms.string("l1BarrelApxPhi%d-pfout" % (ip+1)) - ) for ip in range(3) -] - +# I do not think these work any more, particularly for the gct barrelSerenityPhi1Config = barrelWriterOutputOnlyPhiConfigs[0].clone( tfTimeSlices = cms.VPSet(*[cms.PSet(tfSectors = cms.VPSet(*[ cms.PSet(tfLink = cms.int32(-1)) for s in range(18) ])) for t in range(3)]), gctEmSectors = cms.VPSet(*[ cms.PSet(gctEmLink = cms.int32(-1)) for s in range(12) ]), @@ -102,62 +68,8 @@ def _sortApxRegions(etaPhiSortedRegions): inputFileName = cms.string("l1BarrelPhi1Serenity-inputs-vu13p"), ) -# This includes muon and GTT sector mapping. There is only one GTT fiber, with a logical firmware link of 123. -# The muons, being TM18, have three time slices, to map the emulated data to logical firmware links of 10, 48, and 107 -# Only placeholders are entered for the GCT and TF link numbers here, which are filled in the loops below -barrelApxWriterConfig = [ - _barrelWriterOutputOnly.clone( - fileFormat = cms.string("APx"), - gttLink = cms.int32(123), - gmtTimeSlices = cms.VPSet(*[cms.PSet(gmtLink = cms.int32(38*t+10)) for t in range(3)]), - gctEmSectors = cms.VPSet(*[ cms.PSet(gctEmLink = cms.int32(-1)) for s in range(12) ]), - gctHadSectors = cms.VPSet(*[ cms.PSet(gctHadLink = cms.int32(-1)) for s in range(12) ]), - inputFileName = cms.string("l1BarrelApxPhi%d-inputs" % (ip+1)), - tfTimeSlices = cms.VPSet(*[cms.PSet(tfSectors = cms.VPSet(*[ cms.PSet(tfLink = cms.int32(-1)) for s in range(18) ])) for t in range(3)]), - ) for ip in range(3) -] - -# Set GCT link numbers. 115-122 are the logical fiber numbers in the firmware. -# This maps the emulated sector indices to the firmware logical numbers -# Note, since both the GCT and CL1 are TM6 in this case, there are no time slices -for iBigRegion, ilink in enumerate((0, 1, 2)): - barrelApxWriterConfig[iBigRegion].gctEmSectors[ilink].gctEmLink = 119 - barrelApxWriterConfig[iBigRegion].gctEmSectors[ilink+6].gctEmLink = 120 - barrelApxWriterConfig[iBigRegion].gctEmSectors[ilink+3].gctEmLink = 121 - barrelApxWriterConfig[iBigRegion].gctEmSectors[ilink+9].gctEmLink = 122 - barrelApxWriterConfig[iBigRegion].gctHadSectors[ilink].gctHadLink = 115 - barrelApxWriterConfig[iBigRegion].gctHadSectors[ilink+6].gctHadLink = 116 - barrelApxWriterConfig[iBigRegion].gctHadSectors[ilink+3].gctHadLink = 117 - barrelApxWriterConfig[iBigRegion].gctHadSectors[ilink+9].gctHadLink = 118 - -# Set tracking link numbers. The tracks are logically 0-9, 38-47, and 76-85 for TM groups 0, 1, and 2 in the firmware -# This maps the emulated sector indices to the firmware logical numbers -for timeSlice in range(3): - for iBigRegion, ilink in enumerate((8, 2, 5)): - barrelApxWriterConfig[iBigRegion].tfTimeSlices[timeSlice].tfSectors[ilink].tfLink = 0 + timeSlice * 38 - barrelApxWriterConfig[iBigRegion].tfTimeSlices[timeSlice].tfSectors[(ilink+1)%9].tfLink = 1 + timeSlice * 38 - barrelApxWriterConfig[iBigRegion].tfTimeSlices[timeSlice].tfSectors[(ilink+2)%9].tfLink = 2 + timeSlice * 38 - barrelApxWriterConfig[iBigRegion].tfTimeSlices[timeSlice].tfSectors[(ilink+3)%9].tfLink = 3 + timeSlice * 38 - barrelApxWriterConfig[iBigRegion].tfTimeSlices[timeSlice].tfSectors[(ilink+4)%9].tfLink = 4 + timeSlice * 38 - barrelApxWriterConfig[iBigRegion].tfTimeSlices[timeSlice].tfSectors[9 + ilink].tfLink = 5 + timeSlice * 38 - barrelApxWriterConfig[iBigRegion].tfTimeSlices[timeSlice].tfSectors[9 + (ilink+1)%9].tfLink = 6 + timeSlice * 38 - barrelApxWriterConfig[iBigRegion].tfTimeSlices[timeSlice].tfSectors[9 + (ilink+2)%9].tfLink = 7 + timeSlice * 38 - barrelApxWriterConfig[iBigRegion].tfTimeSlices[timeSlice].tfSectors[9 + (ilink+3)%9].tfLink = 8 + timeSlice * 38 - barrelApxWriterConfig[iBigRegion].tfTimeSlices[timeSlice].tfSectors[9 + (ilink+4)%9].tfLink = 9 + timeSlice * 38 - -# Similar mapping for the barrel Serenity setup -for t in range(3): - for ie in range(2): - for i,s in enumerate([8, 0, 1, 2, 3]): - loglink = 3*(i+5*ie)+t - physlink = loglink+4*1 if loglink < 15 else (loglink-15)+4*25 - barrelSerenityVU9PPhi1Config.tfTimeSlices[t].tfSectors[s+9*ie].tfLink = physlink - physlink = loglink+4*0 if loglink < 15 else (loglink-15)+4*28 - barrelSerenityVU13PPhi1Config.tfTimeSlices[t].tfSectors[s+9*ie].tfLink = physlink barrelWriterConfigs = barrelWriterOutputOnlyPhiConfigs -barrelOutputWriterConfigsAPx = barrelWriterOutputOnlyPhiConfigsAPx -barrelInputWriterConfigsAPx = barrelApxWriterConfig ##################################################################################################################### ## HGcal configuration: write out both inputs and outputs @@ -290,10 +202,9 @@ def _sortApxRegions(etaPhiSortedRegions): ##################################################################################################################### ## TM18 configuration _barrelSerenityTM18 = _barrelWriterOutputOnly.clone( + fileFormat = cms.string("EMPv2"), tmuxFactor = cms.uint32(18), - tfTimeSlices = None, tfSectors = cms.VPSet(*[cms.PSet(tfLink = cms.int32(-1)) for i in range(18)]), - gmtTimeSlices = None, gmtLink = cms.int32(4*18+0), gttLink = 4*28+3, eventsPerFile = 4, @@ -321,6 +232,56 @@ def _sortApxRegions(etaPhiSortedRegions): barrelSerenityVU13PTM18WriterConfig ] +## Barrel (54) TM18 (APx format) +barrelWriterOutputOnlyPhiConfigsAPx = _barrelWriterOutputOnly.clone( + fileFormat = cms.string("APx"), + outputFileName = cms.string("l1BarrelApx-outputs") +) + +barrelWriterDebugPFInConfigsAPx = _barrelWriterOutputOnly.clone( + fileFormat = cms.string("APx"), + nPFInTrack = cms.uint32(22), + nPFInEmCalo = cms.uint32(12), + nPFInHadCalo = cms.uint32(15), + nPFInMuon = cms.uint32(2), + nOutputFramesPerBX = cms.uint32(3), #(18 * 2/3 (going to 240) * 1/2 (doing II = 2)) + debugFileName = cms.string("l1BarrelApx-pfin") +) + +barrelWriterDebugPFOutConfigsAPx = _barrelWriterOutputOnly.clone( + fileFormat = cms.string("APx"), + nPFOutCharged = cms.uint32(22), + nPFOutPhoton = cms.uint32(0), # we are using merged neutrals + nPFOutNeutral = cms.uint32(27), + nPFOutMuon = cms.uint32(2), + nOutputFramesPerBX = cms.uint32(3), #(18 * 2/3 (going to 240) * 1/2 (doing II = 2)) + debugFileName = cms.string("l1BarrelApx-pfout") +) + +barrelWriterDebugEGConfigsAPx = _barrelWriterOutputOnly.clone( + fileFormat = cms.string("APx"), + nEGElectron = cms.uint32(10), + nEGPhoton = cms.uint32(10), + nOutputFramesPerBX = cms.uint32(3), #(18 * 2/3 (going to 240) * 1/2 (doing II = 2)) + debugFileName = cms.string("l1BarrelApx-egamma") +) + +# For the tracker, the logical (firmware) fiber order sorts negative eta first, then positive, +# and in a given eta from most negative to most positive phi. That is reflected in this remapping +trackFiberOrder = (4, 5, 6, 7, 8, 0, 1, 2, 3, 13, 14, 15, 16, 17, 9, 10, 11, 12) # phys to logical +# This includes the tracker, GCT, muon and GTT sector mapping. There is only one GTT fiber, with a logical firmware link of 123. +barrelApxWriterConfig = _barrelWriterOutputOnly.clone( + fileFormat = cms.string("APx"), + gttLink = cms.int32(123), + gmtLink = cms.int32(21), + gctSectors = cms.VPSet(*[cms.PSet(gctLink = cms.int32(i)) for i in (18, 19, 20)]), + tfSectors = cms.VPSet(*[cms.PSet(tfLink = cms.int32(i)) for i in trackFiberOrder]), + inputFileName = cms.string("l1BarrelApx-inputs") +) + +barrelOutputWriterConfigsAPx = barrelWriterOutputOnlyPhiConfigsAPx +barrelInputWriterConfigsAPx = barrelApxWriterConfig + _hgcalWriterTM18 = _hgcalWriterConfig.clone( tmuxFactor = cms.uint32(18), tfTimeSlices = None, diff --git a/L1Trigger/Phase2L1ParticleFlow/src/L1TCorrelatorLayer1PatternFileWriter.cc b/L1Trigger/Phase2L1ParticleFlow/src/L1TCorrelatorLayer1PatternFileWriter.cc index 85942c7d8af00..7146c6261ce85 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/L1TCorrelatorLayer1PatternFileWriter.cc +++ b/L1Trigger/Phase2L1ParticleFlow/src/L1TCorrelatorLayer1PatternFileWriter.cc @@ -4,6 +4,7 @@ #include "FWCore/Utilities/interface/Exception.h" #include "FWCore/ParameterSet/interface/allowedValues.h" #include +#include L1TCorrelatorLayer1PatternFileWriter::L1TCorrelatorLayer1PatternFileWriter(const edm::ParameterSet& iConfig, const l1ct::Event& eventTemplate) @@ -14,8 +15,7 @@ L1TCorrelatorLayer1PatternFileWriter::L1TCorrelatorLayer1PatternFileWriter(const writeDebugs_(!iConfig.getParameter("debugFileName").empty()), tfTimeslices_(std::max(1u, tfTmuxFactor_ / tmuxFactor_)), hgcTimeslices_(std::max(1u, hgcTmuxFactor_ / tmuxFactor_)), - gctEmTimeslices_(std::max(1u, gctEmTmuxFactor_ / tmuxFactor_)), - gctHadTimeslices_(std::max(1u, gctHadTmuxFactor_ / tmuxFactor_)), + gctTimeslices_(std::max(1u, gctTmuxFactor_ / tmuxFactor_)), gmtTimeslices_(std::max(1u, gmtTmuxFactor_ / tmuxFactor_)), gttTimeslices_(std::max(1u, gttTmuxFactor_ / tmuxFactor_)), outputBoard_(-1), @@ -28,6 +28,8 @@ L1TCorrelatorLayer1PatternFileWriter::L1TCorrelatorLayer1PatternFileWriter(const nPFOutPhoton_(iConfig.getParameter("nPFOutPhoton")), nPFOutNeutral_(iConfig.getParameter("nPFOutNeutral")), nPFOutMuon_(iConfig.getParameter("nPFOutMuon")), + nEGElectron_(iConfig.getParameter("nEGElectron")), + nEGPhoton_(iConfig.getParameter("nEGPhoton")), fileFormat_(iConfig.getParameter("fileFormat")), eventsPerFile_(iConfig.getParameter("eventsPerFile")), eventIndex_(0) { @@ -41,14 +43,10 @@ L1TCorrelatorLayer1PatternFileWriter::L1TCorrelatorLayer1PatternFileWriter(const tfTimeslices_ * nInputFramesPerBX_ * tmuxFactor_ - (tfNumberOfTracks_ * 3 / 2)}; } if (partition_ == Partition::Barrel) { - configTimeSlices(iConfig, "gctEm", eventTemplate.raw.gctEm.size(), gctEmTimeslices_, gctEmLinksFactor_); - gctNumberOfEMs_ = iConfig.getParameter("gctNumberOfEMs"); - channelSpecsInput_["gctEm"] = {tmuxFactor_ * gctEmTimeslices_, - gctEmTimeslices_ * nInputFramesPerBX_ * tmuxFactor_ - gctNumberOfEMs_}; - configTimeSlices(iConfig, "gctHad", eventTemplate.raw.gctHad.size(), gctHadTimeslices_, gctHadLinksFactor_); - gctNumberOfHads_ = iConfig.getParameter("gctNumberOfHads"); - channelSpecsInput_["gctHad"] = {tmuxFactor_ * gctHadTimeslices_, - gctHadTimeslices_ * nInputFramesPerBX_ * tmuxFactor_ - gctNumberOfHads_}; + configTimeSlices(iConfig, "gct", eventTemplate.raw.gctcluster.size(), gctTimeslices_, gctEmLinksFactor_); + gctNumberOfObjects_ = iConfig.getParameter("gctNumberOfObjects"); + channelSpecsInput_["gct"] = {tmuxFactor_ * gctTimeslices_, + gctTimeslices_ * nInputFramesPerBX_ * tmuxFactor_ - gctNumberOfObjects_}; } if (partition_ == Partition::HGCal || partition_ == Partition::HGCalNoTk) { configTimeSlices(iConfig, "hgc", eventTemplate.raw.hgcalcluster.size(), hgcTimeslices_, hgcLinksFactor_); @@ -149,6 +147,12 @@ L1TCorrelatorLayer1PatternFileWriter::L1TCorrelatorLayer1PatternFileWriter(const for (unsigned int i = 0; i < nPFOutMuon_ * 2; ++i) { channelIdsOutput_[l1t::demo::LinkId{"pfout_muon", i}].push_back(linkCount++); } + for (unsigned int i = 0; i < nEGElectron_ * 2; ++i) { + channelIdsOutput_[l1t::demo::LinkId{"egout_electron", i}].push_back(linkCount++); + } + for (unsigned int i = 0; i < nEGPhoton_ * 2; ++i) { + channelIdsOutput_[l1t::demo::LinkId{"egout_photon", i}].push_back(linkCount++); + } channelSpecsOutput_["pfin_track"] = {tmuxFactor_, 0}; channelSpecsOutput_["pfin_emcalo"] = {tmuxFactor_, 0}; channelSpecsOutput_["pfin_hadcalo"] = {tmuxFactor_, 0}; @@ -157,6 +161,8 @@ L1TCorrelatorLayer1PatternFileWriter::L1TCorrelatorLayer1PatternFileWriter(const channelSpecsOutput_["pfout_photon"] = {tmuxFactor_, 0}; channelSpecsOutput_["pfout_neutral"] = {tmuxFactor_, 0}; channelSpecsOutput_["pfout_muon"] = {tmuxFactor_, 0}; + channelSpecsOutput_["egout_electron"] = {tmuxFactor_, 0}; + channelSpecsOutput_["egout_photon"] = {tmuxFactor_, 0}; debugFileWriter_ = std::make_unique(l1t::demo::parseFileFormat(fileFormat_), @@ -197,10 +203,12 @@ edm::ParameterSetDescription L1TCorrelatorLayer1PatternFileWriter::getParameterS description.add("nPFOutPhoton", 0); description.add("nPFOutNeutral", 0); description.add("nPFOutMuon", 0); + description.add("nEGElectron", 0); + description.add("nEGPhoton", 0); description.ifValue(edm::ParameterDescription("partition", "Barrel", true), - "Barrel" >> (describeTF() and describeGCTEm() and describeGCTHad() and describeGTT() and - describeGMT() and describePuppi() and describeEG()) or + "Barrel" >> (describeTF() and describeGCT() and describeGTT() and describeGMT() and + describePuppi() and describeEG()) or "HGCal" >> (describeTF() and describeHGC() and describeGTT() and describeGMT() and describePuppi() and describeEG()) or "HGCalNoTk" >> (describeHGC() and describeGMT() and describePuppi()) or @@ -212,11 +220,8 @@ std::unique_ptr L1TCorrelatorLayer1PatternFileWri return describeTimeSlices("tf") and edm::ParameterDescription( "tfNumberOfTracks", 108, true); // need to change if Serenity needs variable } -std::unique_ptr L1TCorrelatorLayer1PatternFileWriter::describeGCTEm() { - return describeTimeSlices("gctEm") and edm::ParameterDescription("gctNumberOfEMs", 32, true); -} -std::unique_ptr L1TCorrelatorLayer1PatternFileWriter::describeGCTHad() { - return describeTimeSlices("gctHad") and edm::ParameterDescription("gctNumberOfHads", 48, true); +std::unique_ptr L1TCorrelatorLayer1PatternFileWriter::describeGCT() { + return describeTimeSlices("gct") and edm::ParameterDescription("gctNumberOfObjects", 162, true); } std::unique_ptr L1TCorrelatorLayer1PatternFileWriter::describeHGC() { return describeTimeSlices("hgc"); @@ -246,8 +251,7 @@ void L1TCorrelatorLayer1PatternFileWriter::write(const l1ct::Event& event) { writeTF(event, inputs); } if (partition_ == Partition::Barrel) { - writeGCTEm(event, inputs); - writeGCTHad(event, inputs); + writeGCT(event, inputs); } if (partition_ == Partition::HGCal || partition_ == Partition::HGCalNoTk) { writeHGC(event, inputs); @@ -403,25 +407,14 @@ void L1TCorrelatorLayer1PatternFileWriter::writeTF(const l1ct::Event& event, l1t } } -void L1TCorrelatorLayer1PatternFileWriter::writeGCTEm(const l1ct::Event& event, l1t::demo::EventData& out) { - for (unsigned int iS = 0, nS = event.raw.gctEm.size(); iS < nS; ++iS) { - l1t::demo::LinkId key{"gctEm", iS}; +void L1TCorrelatorLayer1PatternFileWriter::writeGCT(const l1ct::Event& event, l1t::demo::EventData& out) { + for (unsigned int iS = 0, nS = event.raw.gctcluster.size(); iS < nS; ++iS) { + l1t::demo::LinkId key{"gct", iS}; if (channelIdsInput_.count(key) == 0) continue; - std::vector> gctEm = event.raw.gctEm[iS].obj; - gctEm.resize(gctNumberOfEMs_, ap_uint<64>(0)); - out.add(key, gctEm); - } -} - -void L1TCorrelatorLayer1PatternFileWriter::writeGCTHad(const l1ct::Event& event, l1t::demo::EventData& out) { - for (unsigned int iS = 0, nS = event.raw.gctHad.size(); iS < nS; ++iS) { - l1t::demo::LinkId key{"gctHad", iS}; - if (channelIdsInput_.count(key) == 0) - continue; - std::vector> gctHad = event.raw.gctHad[iS].obj; - gctHad.resize(gctNumberOfHads_, ap_uint<64>(0)); - out.add(key, gctHad); + std::vector> gctclusters = event.raw.gctcluster[iS].obj; + gctclusters.resize(gctNumberOfObjects_, ap_uint<64>(0)); + out.add(key, gctclusters); } } @@ -477,10 +470,10 @@ void L1TCorrelatorLayer1PatternFileWriter::writeGTT(const l1ct::Event& event, l1 // Debug functions output internal data for debugging purposes, mainly emulation/simulation comparison void L1TCorrelatorLayer1PatternFileWriter::writeDebugs(const l1ct::Event& event, l1t::demo::EventData& out) { - // Note: the writers have a width of 64 very much hardcoded in the sizes. Therefore, send the 73 bits as + // Note: the writers have a width of 64 very much hardcoded in the sizes. Therefore, send the bits as // two separate "fibers" - constexpr unsigned int MAX_BITWIDTH = 73; // Should be the biggest object width (or greater) + constexpr unsigned int MAX_BITWIDTH = 128; if (nPFInTrack_) { std::vector>> linksLow(nPFInTrack_); // virtual links -- bits 63:0 @@ -489,7 +482,7 @@ void L1TCorrelatorLayer1PatternFileWriter::writeDebugs(const l1ct::Event& event, auto pfvals = event.pfinputs[ir].track; unsigned int npfvals = pfvals.size(); for (unsigned int i = 0; i < nPFInTrack_; ++i) { - ap_uint val = i < npfvals ? pfvals[i].pack() : ap_uint(0); + ap_uint val = i < npfvals ? pfvals[i].pack_barrel() : ap_uint(0); linksHigh[i].push_back(val(MAX_BITWIDTH - 1, 64)); linksLow[i].push_back(val(63, 0)); } @@ -506,7 +499,8 @@ void L1TCorrelatorLayer1PatternFileWriter::writeDebugs(const l1ct::Event& event, auto pfvals = event.pfinputs[ir].emcalo; unsigned int npfvals = pfvals.size(); for (unsigned int i = 0; i < nPFInEmCalo_; ++i) { - ap_uint val = i < npfvals ? pfvals[i].pack() : ap_uint(0); + ap_uint val = + i < npfvals ? pfvals[i].pack_barrel() : ap_uint(0); linksHigh[i].push_back(val(MAX_BITWIDTH - 1, 64)); linksLow[i].push_back(val(63, 0)); } @@ -523,7 +517,8 @@ void L1TCorrelatorLayer1PatternFileWriter::writeDebugs(const l1ct::Event& event, auto pfvals = event.pfinputs[ir].hadcalo; unsigned int npfvals = pfvals.size(); for (unsigned int i = 0; i < nPFInHadCalo_; ++i) { - ap_uint val = i < npfvals ? pfvals[i].pack() : ap_uint(0); + ap_uint val = + i < npfvals ? pfvals[i].pack_barrel() : ap_uint(0); linksHigh[i].push_back(val(MAX_BITWIDTH - 1, 64)); linksLow[i].push_back(val(63, 0)); } @@ -621,6 +616,42 @@ void L1TCorrelatorLayer1PatternFileWriter::writeDebugs(const l1ct::Event& event, out.add(l1t::demo::LinkId{"pfout_muon", 2 * i + 1}, linksLow[i]); } } + + if (nEGElectron_) { + std::vector>> linksLow(nEGElectron_); // virtual links -- bits 63:0 + std::vector>> linksHigh(nEGElectron_); // virtual links -- bits MAX_BITWIDTH-1:64 + for (auto ir : outputRegions_) { + auto egvals = event.out[ir].egelectron; + unsigned int negvals = egvals.size(); + for (unsigned int i = 0; i < nEGElectron_; ++i) { + ap_uint val = i < negvals ? egvals[i].pack() : ap_uint(0); + linksHigh[i].push_back(val(MAX_BITWIDTH - 1, 64)); + linksLow[i].push_back(val(63, 0)); + } + } + for (unsigned int i = 0; i < linksLow.size(); ++i) { + out.add(l1t::demo::LinkId{"egout_electron", 2 * i}, linksHigh[i]); + out.add(l1t::demo::LinkId{"egout_electron", 2 * i + 1}, linksLow[i]); + } + } + + if (nEGPhoton_) { + std::vector>> linksLow(nEGPhoton_); // virtual links -- bits 63:0 + std::vector>> linksHigh(nEGPhoton_); // virtual links -- bits MAX_BITWIDTH-1:64 + for (auto ir : outputRegions_) { + auto egvals = event.out[ir].egphoton; + unsigned int negvals = egvals.size(); + for (unsigned int i = 0; i < nEGPhoton_; ++i) { + ap_uint val = i < negvals ? egvals[i].pack() : ap_uint(0); + linksHigh[i].push_back(val(MAX_BITWIDTH - 1, 64)); + linksLow[i].push_back(val(63, 0)); + } + } + for (unsigned int i = 0; i < linksLow.size(); ++i) { + out.add(l1t::demo::LinkId{"egout_photon", 2 * i}, linksHigh[i]); + out.add(l1t::demo::LinkId{"egout_photon", 2 * i + 1}, linksLow[i]); + } + } } void L1TCorrelatorLayer1PatternFileWriter::writePuppi(const l1ct::Event& event, l1t::demo::EventData& out) { diff --git a/L1Trigger/Phase2L1ParticleFlow/src/corrector.cc b/L1Trigger/Phase2L1ParticleFlow/src/corrector.cc index 63c62b744e266..6e295df0881e9 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/corrector.cc +++ b/L1Trigger/Phase2L1ParticleFlow/src/corrector.cc @@ -276,7 +276,9 @@ l1tpf::corrector::corrector(corrector &&corr) neta_(corr.neta_), nemf_(corr.nemf_), emfMax_(corr.emfMax_), - emulate_(corr.emulate_) { + emulate_(corr.emulate_), + debug_(corr.debug_), + emulationMode_(corr.emulationMode_) { } l1tpf::corrector &l1tpf::corrector::operator=(corrector &&corr) { @@ -285,6 +287,8 @@ l1tpf::corrector &l1tpf::corrector::operator=(corrector &&corr) { std::swap(nemf_, corr.nemf_); std::swap(emfMax_, corr.emfMax_); std::swap(emulate_, corr.emulate_); + std::swap(debug_, corr.debug_); + std::swap(emulationMode_, corr.emulationMode_); #ifdef L1PF_USE_ROOT index_.swap(corr.index_); @@ -402,7 +406,7 @@ float l1tpf::corrector::correctedPt(float pt, float emPt, float eta) const { ptcorr = ptcorr * pt; } if (debug_) - dbgCout() << "[EMU] ieta: " << ieta << " iemf: " << iemf << " ipt: " << ipt - 1 + dbgCout() << "[EMU] this: " << this << " ieta: " << ieta << " iemf: " << iemf << " ipt: " << ipt - 1 << "corr: " << hist->GetBinContent(ipt) << " ptcorr: " << ptcorr << std::endl; } return ptcorr; diff --git a/L1Trigger/Phase2L1ParticleFlow/src/egamma/pftkegalgo_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/egamma/pftkegalgo_ref.cpp index 758995fed5e4f..2dfa4a54b7c13 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/egamma/pftkegalgo_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/egamma/pftkegalgo_ref.cpp @@ -381,8 +381,8 @@ id_score_t l1ct::TkEgCID_EB_v1::compute_score(const CompositeCandidate &cand, float cl_pt = calo.floatPt(); //This two ratios will be computed in the calotrigger and passed to the CTL1 in 6 bits - float cl_ss = emcalo[cand.cluster_idx].hwShowerShape.to_float(); - float cl_relIso = emcalo[cand.cluster_idx].hwRelIso.to_float(); + float cl_ss = calo.hwShowerShape.to_float(); + float cl_relIso = calo.hwRelIso.to_float(); float cl_staWP = calo.hwEmID & 0x1; float cl_looseTkWP = (calo.hwEmID & 0x2) == 0x2; float tk_chi2RPhi = chi2RPhiBins[tk.hwRedChi2RPhi.to_int()]; diff --git a/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/gcteminput_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/gcteminput_ref.cpp index c0891332016d8..1ef85d6618f8e 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/gcteminput_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/gcteminput_ref.cpp @@ -1,4 +1,5 @@ #include "L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/gcteminput_ref.h" +#include "DataFormats/L1TCalorimeterPhase2/interface/GCTEmDigiCluster.h" #ifdef CMSSW_GIT_HASH #include "FWCore/ParameterSet/interface/ParameterSet.h" @@ -28,13 +29,17 @@ l1ct::EmCaloObjEmu l1ct::GctEmClusterDecoderEmulator::decode(const l1ct::PFRegio constexpr float ETA_LSB = 2 * ETA_RANGE_ONE_SIDE / 170.; constexpr float PHI_LSB = 2 * M_PI / 360.; + l1tp2::GCTEmDigiCluster inclus(in); + // need to add emid l1ct::EmCaloObjEmu calo; calo.clear(); - calo.hwPt = pt(in) * l1ct::pt_t(0.5); // the LSB for GCT objects + calo.hwPt = inclus.pt() * l1ct::pt_t(inclus.ptLSB()); // the LSB for GCT objects // We add half a crystal both in eta and phi to avoid a bias - calo.hwEta = l1ct::Scales::makeGlbEta(eta(in) * ETA_LSB + ETA_LSB / 2.); // at this point eta is abs(globalEta) - calo.hwPhi = l1ct::Scales::makePhi(phi(in) * PHI_LSB + (PHI_LSB / 2)); // This is already in the local frame + calo.hwEta = l1ct::Scales::makeGlbEta(inclus.eta() * ETA_LSB + ETA_LSB / 2.); // at this point eta is abs(globalEta) + calo.hwPhi = l1ct::Scales::makePhi(inclus.phi() * PHI_LSB + (PHI_LSB / 2)); // This is already in the local frame + + calo.hwHoe = inclus.hoe(); if (corrector_.valid()) { float newpt = @@ -42,7 +47,6 @@ l1ct::EmCaloObjEmu l1ct::GctEmClusterDecoderEmulator::decode(const l1ct::PFRegio calo.hwPt = l1ct::Scales::makePtFromFloat(newpt); } - // Note: at this point still calo.hwPtErr = l1ct::Scales::makePtFromFloat(resol_(calo.floatPt(), calo.floatEta())); // NOTE: this is still abs(globalEta) @@ -50,8 +54,11 @@ l1ct::EmCaloObjEmu l1ct::GctEmClusterDecoderEmulator::decode(const l1ct::PFRegio // bit 0: standaloneWP: is_iso && is_ss // bit 1: looseL1TkMatchWP: is_looseTkiso && is_looseTkss // bit 2: photonWP: - calo.hwEmID = (passes_iso(in) && passes_ss(in)) | ((passes_looseTkiso(in) && passes_looseTkss(in)) << 1) | - ((passes_looseTkiso(in) && passes_looseTkss(in)) << 2); + calo.hwEmID = inclus.wp(); + + // Copying the bits directly. + calo.hwRelIso(rel_iso_t::width - 1, 0) = inclus.iso()(rel_iso_t::width - 1, 0); + calo.hwShowerShape(shower_shape_t::width - 1, 0) = inclus.shape()(shower_shape_t::width - 1, 0); // convert eta to local if (sector.hwEtaCenter < 0) { diff --git a/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/gcthadinput_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/gcthadinput_ref.cpp index a7f892d3679b4..e22bfdb217ea1 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/gcthadinput_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/l1-converters/gcthadinput_ref.cpp @@ -1,37 +1,51 @@ #include "L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/gcthadinput_ref.h" +#include "DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h" #ifdef CMSSW_GIT_HASH #include "FWCore/ParameterSet/interface/ParameterSet.h" #include "FWCore/ParameterSet/interface/ParameterSetDescription.h" -l1ct::GctHadClusterDecoderEmulator::GctHadClusterDecoderEmulator(const edm::ParameterSet &pset) {} +l1ct::GctHadClusterDecoderEmulator::GctHadClusterDecoderEmulator(const edm::ParameterSet &iConfig) + : corrector_(iConfig.getParameter("gctHadCorrector"), -1), + resol_(iConfig.getParameter("gctHadResol")) {} edm::ParameterSetDescription l1ct::GctHadClusterDecoderEmulator::getParameterSetDescription() { edm::ParameterSetDescription description; + description.add("gctHadCorrector"); + edm::ParameterSetDescription gctHadResolPSD; + gctHadResolPSD.add>("etaBins"); + gctHadResolPSD.add>("offset"); + gctHadResolPSD.add>("scale"); + gctHadResolPSD.add("kind"); + description.add("gctHadResol", gctHadResolPSD); return description; } #endif -double l1ct::GctHadClusterDecoderEmulator::fracPart(const double total, const unsigned int hoe) const { - return total * std::pow(2.0, hoe) / (std::pow(2.0, hoe) + 1); -} - l1ct::HadCaloObjEmu l1ct::GctHadClusterDecoderEmulator::decode(const l1ct::PFRegionEmu §or, const ap_uint<64> &in) const { constexpr float ETA_RANGE_ONE_SIDE = 1.4841; // barrel goes from (-1.4841, +1.4841) constexpr float ETA_LSB = 2 * ETA_RANGE_ONE_SIDE / 170.; constexpr float PHI_LSB = 2 * M_PI / 360.; + l1tp2::GCTHadDigiCluster inclus(in); + l1ct::HadCaloObjEmu calo; calo.clear(); - calo.hwPt = pt(in) * l1ct::pt_t(0.5); // the LSB for GCT objects - calo.hwEta = l1ct::Scales::makeGlbEta(eta(in) * ETA_LSB + ETA_LSB / 2.); // at this point eta is abs(globalEta) - calo.hwPhi = l1ct::Scales::makePhi(phi(in) * PHI_LSB + (PHI_LSB / 2)); // This is already in the local frame + calo.hwPt = inclus.pt() * inclus.ptLSB(); // the LSB for GCT objects + calo.hwEta = l1ct::Scales::makeGlbEta(inclus.eta() * ETA_LSB + ETA_LSB / 2.); // at this point eta is abs(globalEta) + calo.hwPhi = l1ct::Scales::makePhi(inclus.phi() * PHI_LSB + (PHI_LSB / 2)); // This is already in the local frame - // need to add EmPt when it becomes available + calo.hwEmPt = inclus.ecal() * inclus.ptLSB(); + + if (corrector_.valid()) { + float newpt = corrector_.correctedPt( + calo.floatPt(), calo.floatEmPt(), calo.floatEta()); // NOTE: this is still abs(globalEta) + calo.hwPt = l1ct::Scales::makePtFromFloat(newpt); + } - // need to add emid - calo.hwEmID = 1; + // need to add emid, default to zero for had/PF clusters from GCT + calo.hwEmID = inclus.fb(); // convert eta to local if (sector.hwEtaCenter < 0) { diff --git a/L1Trigger/Phase2L1ParticleFlow/src/pf/pfalgo3_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/pf/pfalgo3_ref.cpp index b3b108a53bb58..89bcef1481f4f 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/pf/pfalgo3_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/pf/pfalgo3_ref.cpp @@ -302,6 +302,15 @@ void l1ct::PFAlgo3Emulator::run(const PFInputRegion& in, OutputRegion& out) cons in.region.floatPhiCenter() + in.region.floatPhiHalfWidthExtra(), in.region.pack().to_string(16).c_str()); + dbgPrintf("FW\nFW \t region int eta %+d [ %+d , %+d ], phi %+d [ %+d , %+d ] packed %s\n", + in.region.intEtaCenter(), + (in.region.hwEtaCenter - in.region.hwEtaHalfWidth - in.region.hwEtaExtra).to_int(), + (in.region.hwEtaCenter + in.region.hwEtaHalfWidth + in.region.hwEtaExtra).to_int(), + in.region.intPhiCenter(), + (in.region.hwPhiCenter - in.region.hwPhiHalfWidth - in.region.hwPhiExtra).to_int(), + (in.region.hwPhiCenter + in.region.hwPhiHalfWidth + in.region.hwPhiExtra).to_int(), + in.region.pack().to_string(16).c_str()); + dbgPrintf("FW \t N(track) %3lu N(em) %3lu N(calo) %3lu N(mu) %3lu\n", in.track.size(), in.emcalo.size(), @@ -571,6 +580,9 @@ void l1ct::PFAlgo3Emulator::run(const PFInputRegion& in, OutputRegion& out) cons } void l1ct::PFAlgo3Emulator::mergeNeutrals(OutputRegion& out) const { + // To better match the firmware, the pfphotons are first padded to their maximum size. + // This matches the fixed port assignments in the firmware design. + out.pfphoton.resize(nPHOTON_); out.pfphoton.reserve(out.pfphoton.size() + out.pfneutral.size()); out.pfphoton.insert(out.pfphoton.end(), out.pfneutral.begin(), out.pfneutral.end()); out.pfphoton.swap(out.pfneutral); diff --git a/L1Trigger/Phase2L1ParticleFlow/src/regionizer/middle_buffer_multififo_regionizer_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/regionizer/middle_buffer_multififo_regionizer_ref.cpp index a9ff9410b42e0..d82d2ee9353c0 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/regionizer/middle_buffer_multififo_regionizer_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/regionizer/middle_buffer_multififo_regionizer_ref.cpp @@ -25,8 +25,7 @@ l1ct::MiddleBufferMultififoRegionizerEmulator::MiddleBufferMultififoRegionizerEm /*streaming=*/true, /*outii=*/2, /*pauseii=*/1, - iConfig.getParameter("useAlsoVtxCoords"), - iConfig.getParameter("tmux6GCTinput")) { + iConfig.getParameter("useAlsoVtxCoords")) { debug_ = iConfig.getUntrackedParameter("debug", false); } @@ -43,7 +42,6 @@ edm::ParameterSetDescription l1ct::MiddleBufferMultififoRegionizerEmulator::getP description.add("nEmCalo", 12); description.add("nMu", 2); description.add("useAlsoVtxCoords", true); - description.add("tmux6GCTinput", false); description.addUntracked("debug", false); return description; } @@ -63,8 +61,7 @@ l1ct::MiddleBufferMultififoRegionizerEmulator::MiddleBufferMultififoRegionizerEm bool streaming, unsigned int outii, unsigned int pauseii, - bool useAlsoVtxCoords, - bool tmux6GCTinput) + bool useAlsoVtxCoords) : RegionizerEmulator(useAlsoVtxCoords), NTK_SECTORS(9), NCALO_SECTORS(3), @@ -86,7 +83,6 @@ l1ct::MiddleBufferMultififoRegionizerEmulator::MiddleBufferMultififoRegionizerEm streaming_(streaming), init_(false), iclock_(0), - tmux6GCTinput_(tmux6GCTinput), tkRegionizerPre_(ntk, ntk, false, outii, pauseii, useAlsoVtxCoords), tkRegionizerPost_(ntk, (ntk + outii - 1) / outii, true, outii, pauseii, useAlsoVtxCoords), commonCaloRegionizerPre_(ncalo, ncalo, false, outii, pauseii), @@ -124,14 +120,16 @@ l1ct::MiddleBufferMultififoRegionizerEmulator::MiddleBufferMultififoRegionizerEm for (unsigned int j = 0; j < 3; ++j) { // 3 regions x sector for (unsigned int il = 0; il < HCAL_LINKS; ++il) { caloRoutes_.emplace_back(is, il, 3 * is + j + phisectors * ie, il); - if (j != 2) { - caloRoutes_.emplace_back((is + 2) % 3, il, 3 * is + j + phisectors * ie, il + HCAL_LINKS); + if (j != 1) { + const unsigned int from_sector = (is + (j == 2 ? 1 : 2)) % NCALO_SECTORS; + caloRoutes_.emplace_back(from_sector, il, 3 * is + j + phisectors * ie, il + HCAL_LINKS); } } for (unsigned int il = 0; il < ECAL_LINKS; ++il) { emCaloRoutes_.emplace_back(is, il, 3 * is + j + phisectors * ie, il); - if (j != 2) { - emCaloRoutes_.emplace_back((is + 2) % 3, il, 3 * is + j + phisectors * ie, il + ECAL_LINKS); + if (j != 1) { + const unsigned int from_sector = (is + (j == 2 ? 1 : 2)) % NCALO_SECTORS; + emCaloRoutes_.emplace_back(from_sector, il, 3 * is + j + phisectors * ie, il + ECAL_LINKS); } } } @@ -143,8 +141,6 @@ l1ct::MiddleBufferMultififoRegionizerEmulator::MiddleBufferMultififoRegionizerEm muRoutes_.emplace_back(0, il, j, il); } } - - init_GCT_slrs(gct_slr_regions_); } l1ct::MiddleBufferMultififoRegionizerEmulator::~MiddleBufferMultififoRegionizerEmulator() {} @@ -231,24 +227,28 @@ void l1ct::MiddleBufferMultififoRegionizerEmulator::initSectorsAndRegions(const tkRegionizerPost_.initRegions(out); } if (ncalo_) { - assert(in.hadcalo.size() == NCALO_SECTORS); + assert(in.hadcalo.size() == NCALO_SECTORS * 4); + + // we will map the decoded sectors (matching GTC SLRs x 2 eta) into the 3 link sectors + init_GCT_tmux18sectors(gct_tmux18_hadcalo_, gct_tmux18_emcalo_); + std::vector> commonCaloSectors(NCALO_SECTORS); for (unsigned int isec = 0; isec != NCALO_SECTORS; isec++) { - commonCaloSectors[isec].region = in.hadcalo[isec].region; + commonCaloSectors[isec].region = gct_tmux18_hadcalo_[isec].region; } commonCaloRegionizerPre_.initSectors(commonCaloSectors); commonCaloRegionizerPre_.initRegions(mergedRegions); commonCaloRegionizerPre_.initRouting(caloRoutes_); - hadCaloRegionizerPre_.initSectors(in.hadcalo); + hadCaloRegionizerPre_.initSectors(gct_tmux18_hadcalo_); hadCaloRegionizerPre_.initRegions(mergedRegions); if (ECAL_LINKS) hadCaloRegionizerPre_.initRouting(caloRoutes_); hadCaloRegionizerPost_.initRegions(out); } if (nem_) { - assert(in.emcalo.size() == NCALO_SECTORS); - emCaloRegionizerPre_.initSectors(in.emcalo); + assert(in.emcalo.size() == NCALO_SECTORS * 4); + emCaloRegionizerPre_.initSectors(gct_tmux18_emcalo_); emCaloRegionizerPre_.initRegions(mergedRegions); if (ECAL_LINKS) emCaloRegionizerPre_.initRouting(emCaloRoutes_); @@ -480,26 +480,70 @@ void l1ct::MiddleBufferMultififoRegionizerEmulator::fillSharedCaloLinks( const std::vector>& had_in, std::vector& links, std::vector& valid) { - // FIXME: the link filling should be done according to TMUX18 GCT-CTL1 interface document assert(ECAL_LINKS == 0 && HCAL_LINKS == 1 && ncalo_ != 0 && nem_ != 0); links.resize(NCALO_SECTORS); valid.resize(links.size()); - // for the moment we assume the first 54 clocks are for EM, the rest for HAD - const unsigned int NCLK_EM = 54; + + // input calo sectors map to GCT SLRs. We can use this to fill the links according to the interface document. + // while filling we also convert to the "link sector" coordinates + const unsigned int NEM_WORDS = 16; + const unsigned int NHAD_WORDS = 24; + + static constexpr unsigned int gct_slr_tmux18sector_mapping[12] = {0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2}; + static constexpr unsigned int slr_order_per_link[4] = {7, 1, 6, 0}; + for (unsigned int is = 0; is < NCALO_SECTORS; ++is) { links[is].clear(); - if (iclock < NCLK_EM) { - valid[is] = true; - if (iclock < em_in[is].size()) { - encode(em_in[is][iclock], links[is]); + if (iclock == 0 || iclock == 81) { + valid[is] = false; + continue; // technical words -> ignored + } + unsigned int rel_pos = (iclock) % 81; + if ((rel_pos - 1) < 2 * NEM_WORDS) { // EM clusters + unsigned int islr = ((rel_pos - 1) < NEM_WORDS) ? 0 : 1; + if (iclock > 81) + islr += 2; + unsigned int insec = slr_order_per_link[islr] + is * 2; + unsigned int itmux18 = gct_slr_tmux18sector_mapping[insec]; + const auto& sec = em_in[insec]; + unsigned int rel_em = (rel_pos - 1) % (NEM_WORDS); + if (rel_em < sec.size()) { + auto cl = sec[rel_em]; + if (!gct_tmux18_emcalo_[itmux18].region.containsHw(sec.region.hwGlbEtaOf(cl), sec.region.hwGlbPhiOf(cl))) { + assert(false && "EM calo cluster out of TMUX18 sector bounds!"); + } + + // convert to TMUX18 sector coordinates + cl.hwEta = l1ct::Scales::makeEta(gct_tmux18_emcalo_[itmux18].region.localEta(sec.region.floatGlbEtaOf(cl))); + cl.hwPhi = l1ct::Scales::makePhi(gct_tmux18_emcalo_[itmux18].region.localPhi(sec.region.floatGlbPhiOf(cl))); + encode(cl, links[is]); + valid[is] = true; + } else { + valid[is] = false; } - } else { - if (iclock - NCLK_EM < had_in[is].size()) { - encode(had_in[is][iclock - NCLK_EM], links[is]); + } else if ((rel_pos - 1) >= 2 * NEM_WORDS && (rel_pos - 1) < (2 * NEM_WORDS + 2 * NHAD_WORDS)) { // Had clusters + unsigned int islr = ((rel_pos - 1 - 2 * NEM_WORDS) < NHAD_WORDS) ? 0 : 1; + if (iclock > 81) + islr += 2; + unsigned int insec = slr_order_per_link[islr] + is * 2; + unsigned int itmux18 = gct_slr_tmux18sector_mapping[insec]; + const auto& sec = had_in[insec]; + unsigned int rel_had = (rel_pos - 1 - 2 * NEM_WORDS) % NHAD_WORDS; + if (rel_had < sec.size()) { + auto cl = sec[rel_had]; + // convert to TMUX18 sector coordinates + if (!gct_tmux18_hadcalo_[itmux18].region.containsHw(sec.region.hwGlbEtaOf(cl), sec.region.hwGlbPhiOf(cl))) { + assert(false && "Had calo cluster out of TMUX18 sector bounds!"); + } + cl.hwEta = l1ct::Scales::makeEta(gct_tmux18_hadcalo_[itmux18].region.localEta(sec.region.floatGlbEtaOf(cl))); + cl.hwPhi = l1ct::Scales::makePhi(gct_tmux18_hadcalo_[itmux18].region.localPhi(sec.region.floatGlbPhiOf(cl))); + encode(cl, links[is]); valid[is] = true; } else { valid[is] = false; } + } else { + valid[is] = false; } } // sectors } @@ -590,29 +634,17 @@ void l1ct::MiddleBufferMultififoRegionizerEmulator::reset() { b.reset(); } -void l1ct::MiddleBufferMultififoRegionizerEmulator::convert_GCTinput_tmux(const RegionizerDecodedInputs& in_tm6, - RegionizerDecodedInputs& in_tm18) const { - for (auto& sec : in_tm18.hadcalo) - sec.clear(); - - for (auto& sec : in_tm18.emcalo) - sec.clear(); - - convert_GCTsector_tmux(in_tm6.hadcalo, in_tm18.hadcalo); - convert_GCTsector_tmux(in_tm6.emcalo, in_tm18.emcalo); -} - void l1ct::MiddleBufferMultififoRegionizerEmulator::init_GCT_tmux18sectors( std::vector>& gct_tmux18_hadcalo, std::vector>& gct_tmux18_emcalo) const { std::vector etaBoundaries = {-1.5, 1.5}; - unsigned int phiSlices = 3; + const unsigned int phiSlices = 3; // if (!std::is_sorted(etaBoundaries.begin(), etaBoundaries.end())) // throw cms::Exception("Configuration", "caloSectors.etaBoundaries not sorted\n"); - float phiWidth = 2 * M_PI / phiSlices; + const float phiWidth = 2 * M_PI / phiSlices; // if (phiWidth > 2 * l1ct::Scales::maxAbsPhi()) // throw cms::Exception("Configuration", "caloSectors phi range too large for phi_t data type"); - float phiZero = M_PI * 7 / 18; + float phiZero = M_PI * 4 / 18; for (unsigned int ieta = 0, neta = etaBoundaries.size() - 1; ieta < neta; ++ieta) { // float etaWidth = etaBoundaries[ieta + 1] - etaBoundaries[ieta]; // if (etaWidth > 2 * l1ct::Scales::maxAbsEta()) @@ -635,50 +667,13 @@ void l1ct::MiddleBufferMultififoRegionizerEmulator::init_GCT_tmux18sectors( } } -void l1ct::MiddleBufferMultififoRegionizerEmulator::init_GCT_slrs( - std::vector& gct_slr_regions) const { - // We Initialize GCT SLR regions (dividing them in eta +- to be able to assign clusters to the correct link and sector - std::vector etaBoundaries = {-1.5, 0, 1.5}; - unsigned int phiSlices = 6; - // if (!std::is_sorted(etaBoundaries.begin(), etaBoundaries.end())) - // throw cms::Exception("Configuration", "caloSectors.etaBoundaries not sorted\n"); - float phiWidth = 2 * M_PI / phiSlices; - // if (phiWidth > 2 * l1ct::Scales::maxAbsPhi()) - // throw cms::Exception("Configuration", "caloSectors phi range too large for phi_t data type"); - float phiZero = M_PI * 4 / 18; - for (unsigned int ieta = 0, neta = etaBoundaries.size() - 1; ieta < neta; ++ieta) { - // float etaWidth = etaBoundaries[ieta + 1] - etaBoundaries[ieta]; - // if (etaWidth > 2 * l1ct::Scales::maxAbsEta()) - // throw cms::Exception("Configuration", "caloSectors eta range too large for eta_t data type"); - for (unsigned int iphi = 0; iphi < phiSlices; ++iphi) { - float phiCenter = reduceRange(iphi * phiWidth + phiZero); - gct_slr_regions.emplace_back(etaBoundaries[ieta], - etaBoundaries[ieta + 1], - phiCenter, - phiWidth, - 0, // no extra - 0); // no extra - } - } -} void l1ct::MiddleBufferMultififoRegionizerEmulator::run(const RegionizerDecodedInputs& in, std::vector& out) { - if (tmux6GCTinput_) { - if (!init_) { - init_GCT_tmux18sectors(gct_tmux18_hadcalo_, gct_tmux18_emcalo_); - } - RegionizerDecodedInputs in_tm18; - in_tm18.track = in.track; - in_tm18.muon = in.muon; - in_tm18.hadcalo = gct_tmux18_hadcalo_; - in_tm18.emcalo = gct_tmux18_emcalo_; - convert_GCTinput_tmux(in, in_tm18); - run_worker(in_tm18, out); - } else { - run_worker(in, out); - } + // FIXME: run_worker is no longer needed + run_worker(in, out); } +// FIXME: run_worker is no longer needed void l1ct::MiddleBufferMultififoRegionizerEmulator::run_worker(const RegionizerDecodedInputs& in, std::vector& out) { assert(streaming_); // doesn't make sense otherwise diff --git a/L1Trigger/Phase2L1ParticleFlow/src/regionizer/tdr_regionizer_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/regionizer/tdr_regionizer_ref.cpp index 29a224ff1df5a..c5b9d3155f4ff 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/regionizer/tdr_regionizer_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/regionizer/tdr_regionizer_ref.cpp @@ -12,22 +12,24 @@ l1ct::TDRRegionizerEmulator::TDRRegionizerEmulator(const edm::ParameterSet& iCon iConfig.getParameter("nCalo"), iConfig.getParameter("nEmCalo"), iConfig.getParameter("nMu"), - iConfig.getParameter("nClocks"), - iConfig.getParameter>("bigRegionEdges"), - iConfig.getParameter("doSort")) { + iConfig.getUntrackedParameter("debug_tk"), + iConfig.getUntrackedParameter("debug_calo"), + iConfig.getUntrackedParameter("debug_emcalo"), + iConfig.getUntrackedParameter("debug_mu")) { debug_ = iConfig.getUntrackedParameter("debug"); } edm::ParameterSetDescription l1ct::TDRRegionizerEmulator::getParameterSetDescription() { edm::ParameterSetDescription description; - description.add("nClocks", 162); description.add("nTrack", 22); description.add("nCalo", 15); description.add("nEmCalo", 12); description.add("nMu", 2); - description.add("doSort", false); - description.add>("bigRegionEdges", {-560, -80, 400, -560}); description.addUntracked("debug", false); + description.addUntracked("debug_tk", false); + description.addUntracked("debug_calo", false); + description.addUntracked("debug_emcalo", false); + description.addUntracked("debug_mu", false); return description; } #endif @@ -36,22 +38,20 @@ l1ct::TDRRegionizerEmulator::TDRRegionizerEmulator(uint32_t ntk, uint32_t ncalo, uint32_t nem, uint32_t nmu, - uint32_t nclocks, - std::vector bigRegionEdges, - bool dosort) + bool debug_tk, + bool debug_calo, + bool debug_emcalo, + bool debug_mu) : RegionizerEmulator(), ntk_(ntk), ncalo_(ncalo), nem_(nem), nmu_(nmu), - nclocks_(nclocks), - bigRegionEdges_(bigRegionEdges), - dosort_(dosort), - netaInBR_(6), - nphiInBR_(3), - init_(false) { - nBigRegions_ = bigRegionEdges_.size() - 1; -} + init_(false), + tkRegionizers_(ntk, debug_tk), + hadCaloRegionizers_(ncalo, debug_calo), + emCaloRegionizers_(nem, debug_emcalo), + muRegionizers_(nmu, debug_mu) {} l1ct::TDRRegionizerEmulator::~TDRRegionizerEmulator() {} @@ -63,47 +63,20 @@ void l1ct::TDRRegionizerEmulator::initSectorsAndRegions(const RegionizerDecodedI assert(!init_); init_ = true; - for (unsigned int i = 0; i < nBigRegions_; i++) { - tkRegionizers_.emplace_back( - netaInBR_, nphiInBR_, ntk_, bigRegionEdges_[i], bigRegionEdges_[i + 1], nclocks_, 1, false); - hadCaloRegionizers_.emplace_back( - netaInBR_, nphiInBR_, ncalo_, bigRegionEdges_[i], bigRegionEdges_[i + 1], nclocks_ / 3, 1, false); // TM6 - emCaloRegionizers_.emplace_back( - netaInBR_, nphiInBR_, nem_, bigRegionEdges_[i], bigRegionEdges_[i + 1], nclocks_ / 3, 1, false); // TM6 - muRegionizers_.emplace_back( - netaInBR_, nphiInBR_, nmu_, bigRegionEdges_[i], bigRegionEdges_[i + 1], nclocks_, 1, false); - } - if (debug_) { dbgCout() << "in.track.size() = " << in.track.size() << std::endl; dbgCout() << "in.hadcalo.size() = " << in.hadcalo.size() << std::endl; dbgCout() << "in.emcalo.size() = " << in.emcalo.size() << std::endl; } - if (ntk_) { - for (unsigned int i = 0; i < nBigRegions_; i++) { - tkRegionizers_[i].initSectors(in.track); - tkRegionizers_[i].initRegions(out); - } - } - if (ncalo_) { - for (unsigned int i = 0; i < nBigRegions_; i++) { - hadCaloRegionizers_[i].initSectors(in.hadcalo); - hadCaloRegionizers_[i].initRegions(out); - } - } - if (nem_) { - for (unsigned int i = 0; i < nBigRegions_; i++) { - emCaloRegionizers_[i].initSectors(in.emcalo); - emCaloRegionizers_[i].initRegions(out); - } - } - if (nmu_) { - for (unsigned int i = 0; i < nBigRegions_; i++) { - muRegionizers_[i].initSectors(in.muon); - muRegionizers_[i].initRegions(out); - } - } + tkRegionizers_.initSectors(in.track); + tkRegionizers_.initRegions(out); + hadCaloRegionizers_.initSectors(in.hadcalo); + hadCaloRegionizers_.initRegions(out); + emCaloRegionizers_.initSectors(in.emcalo); + emCaloRegionizers_.initRegions(out); + muRegionizers_.initSectors(in.muon); + muRegionizers_.initRegions(out); } void l1ct::TDRRegionizerEmulator::run(const RegionizerDecodedInputs& in, std::vector& out) { @@ -115,41 +88,33 @@ void l1ct::TDRRegionizerEmulator::run(const RegionizerDecodedInputs& in, std::ve initSectorsAndRegions(in, out); } - for (unsigned int ie = 0; ie < nBigRegions_; ie++) { - //add objects from link - tkRegionizers_[ie].reset(); - tkRegionizers_[ie].fillBuffers(in.track); - tkRegionizers_[ie].run(); + //add objects from link + tkRegionizers_.fillBuffers(in.track); + tkRegionizers_.run(); - emCaloRegionizers_[ie].reset(); - emCaloRegionizers_[ie].fillBuffers(in.emcalo); - emCaloRegionizers_[ie].run(); + emCaloRegionizers_.fillBuffers(in.emcalo); + emCaloRegionizers_.run(); - hadCaloRegionizers_[ie].reset(); - hadCaloRegionizers_[ie].fillBuffers(in.hadcalo); - hadCaloRegionizers_[ie].run(); + hadCaloRegionizers_.fillBuffers(in.hadcalo); + hadCaloRegionizers_.run(); - muRegionizers_[ie].reset(); - muRegionizers_[ie].fillBuffers(in.muon); - muRegionizers_[ie].run(); - } + muRegionizers_.fillBuffers(in.muon); + muRegionizers_.run(); - for (unsigned int ie = 0; ie < nBigRegions_; ie++) { - auto regionTrackMap = tkRegionizers_[ie].fillRegions(dosort_); - for (auto& pr : regionTrackMap) { - out[pr.first].track = pr.second; - } - auto regionEmCaloMap = emCaloRegionizers_[ie].fillRegions(dosort_); - for (auto& pr : regionEmCaloMap) { - out[pr.first].emcalo = pr.second; - } - auto regionHadCaloMap = hadCaloRegionizers_[ie].fillRegions(dosort_); - for (auto& pr : regionHadCaloMap) { - out[pr.first].hadcalo = pr.second; - } - auto regionMuMap = muRegionizers_[ie].fillRegions(dosort_); - for (auto& pr : regionMuMap) { - out[pr.first].muon = pr.second; - } + auto trackSRs = tkRegionizers_.smallRegions(); + auto emCaloSRs = emCaloRegionizers_.smallRegions(); + auto hadCaloSRs = hadCaloRegionizers_.smallRegions(); + auto muSRs = muRegionizers_.smallRegions(); + + for (size_t sr = 0; sr < trackSRs.size(); sr++) { + out[sr].track = trackSRs[sr]; + out[sr].emcalo = emCaloSRs[sr]; + out[sr].hadcalo = hadCaloSRs[sr]; + out[sr].muon = muSRs[sr]; } + + tkRegionizers_.clearSmallRegions(); + emCaloRegionizers_.clearSmallRegions(); + hadCaloRegionizers_.clearSmallRegions(); + muRegionizers_.clearSmallRegions(); } diff --git a/L1Trigger/Phase2L1ParticleFlow/test/make_l1ct_binaryFiles_cfg.py b/L1Trigger/Phase2L1ParticleFlow/test/make_l1ct_binaryFiles_cfg.py index d4456abf87bb7..e8418ed64f3a5 100644 --- a/L1Trigger/Phase2L1ParticleFlow/test/make_l1ct_binaryFiles_cfg.py +++ b/L1Trigger/Phase2L1ParticleFlow/test/make_l1ct_binaryFiles_cfg.py @@ -23,7 +23,6 @@ if args.patternFilesOFF: print(f'Switching off pattern file creation: patternFilesOFF is {args.patternFilesOFF}') - import FWCore.ParameterSet.Config as cms from Configuration.StandardSequences.Eras import eras @@ -35,17 +34,15 @@ process.options = cms.untracked.PSet( wantSummary = cms.untracked.bool(True), allowUnscheduled = cms.untracked.bool(False) ) process.maxEvents = cms.untracked.PSet( input = cms.untracked.int32(1008)) process.MessageLogger.cerr.FwkReport.reportEvery = 1 -# process.MessageLogger.cerr.threshold = "DEBUG" -# process.MessageLogger.debugModules = ["l1tLayer1BarrelTDR"] process.source = cms.Source("PoolSource", - fileNames = cms.untracked.vstring('file:inputs110X.root'), + fileNames = cms.untracked.vstring('file:inputs140X_1.root', + ), inputCommands = cms.untracked.vstring("keep *", "drop l1tPFClusters_*_*_*", "drop l1tPFTracks_*_*_*", "drop l1tPFCandidates_*_*_*", - "drop l1tTkPrimaryVertexs_*_*_*", - "drop l1tKMTFTracks_*_*_*"), + "drop l1tTkPrimaryVertexs_*_*_*"), skipEvents = cms.untracked.uint32(0), ) @@ -70,17 +67,22 @@ process.l1tSAMuonsGmt = l1tSAMuonsGmt.clone() from L1Trigger.L1CaloTrigger.l1tPhase2L1CaloEGammaEmulator_cfi import l1tPhase2L1CaloEGammaEmulator process.l1tPhase2L1CaloEGammaEmulator = l1tPhase2L1CaloEGammaEmulator.clone() + from L1Trigger.L1CaloTrigger.l1tPhase2CaloPFClusterEmulator_cfi import l1tPhase2CaloPFClusterEmulator process.l1tPhase2CaloPFClusterEmulator = l1tPhase2CaloPFClusterEmulator.clone() + from L1Trigger.L1CaloTrigger.l1tPhase2GCTBarrelToCorrelatorLayer1Emulator_cfi import l1tPhase2GCTBarrelToCorrelatorLayer1Emulator process.l1tPhase2GCTBarrelToCorrelatorLayer1Emulator = l1tPhase2GCTBarrelToCorrelatorLayer1Emulator.clone() +from L1Trigger.L1CaloTrigger.l1tPhase2CaloToCorrelatorTM18_cfi import l1tPhase2CaloToCorrelatorTM18 +process.l1tPhase2CaloToCorrelatorTM18 = l1tPhase2CaloToCorrelatorTM18.clone() + process.L1TInputTask = cms.Task( - process.l1tSAMuonsGmt, - process.l1tPhase2L1CaloEGammaEmulator, - process.l1tPhase2CaloPFClusterEmulator, - process.l1tPhase2GCTBarrelToCorrelatorLayer1Emulator -) + process.l1tPhase2L1CaloEGammaEmulator, + process.l1tPhase2CaloPFClusterEmulator, + process.l1tPhase2GCTBarrelToCorrelatorLayer1Emulator, + process.l1tPhase2CaloToCorrelatorTM18, + process.l1tSAMuonsGmt) from L1Trigger.Phase2L1ParticleFlow.l1tJetFileWriter_cfi import l1tSeededConeJetFileWriter @@ -108,6 +110,7 @@ outputFilename = 'L1CTSCNGJetsPatterns') +## Realistic barrel emulation process.l1tLayer1BarrelTDR = process.l1tLayer1Barrel.clone() process.l1tLayer1BarrelTDR.regionizerAlgo = cms.string("TDR") process.l1tLayer1BarrelTDR.regionizerAlgoParameters = cms.PSet( @@ -115,10 +118,9 @@ nCalo = cms.uint32(15), nEmCalo = cms.uint32(12), nMu = cms.uint32(2), - nClocks = cms.uint32(162), - doSort = cms.bool(False), - bigRegionEdges = cms.vint32(-560, -80, 400, -560), - debug = cms.untracked.bool(False) + debug = cms.untracked.bool(False), + debug_emcalo = cms.untracked.bool(False), + debug_tk = cms.untracked.bool(False) ) process.l1tLayer1BarrelTDR.pfAlgoParameters.nTrack = 22 process.l1tLayer1BarrelTDR.pfAlgoParameters.nSelCalo = 15 @@ -128,24 +130,11 @@ process.l1tLayer1BarrelTDR.puAlgoParameters.nIn = 27 process.l1tLayer1BarrelTDR.puAlgoParameters.nOut = 27 process.l1tLayer1BarrelTDR.puAlgoParameters.finalSortAlgo = "BitonicVHDL" +process.l1tLayer1BarrelTDR.tkEgAlgoParameters.nTRACK = 22 process.l1tLayer1BarrelTDR.tkEgAlgoParameters.nTRACK_EGIN = 22 process.l1tLayer1BarrelTDR.tkEgAlgoParameters.nEMCALO_EGIN = 12 - -process.l1tLayer1BarrelTDR.hadClusters = cms.InputTag('l1tPhase2GCTBarrelToCorrelatorLayer1Emulator', 'GCTHadDigiClusters') -process.l1tLayer1BarrelTDR.gctHadInputConversionAlgo = cms.string("Emulator") - -process.l1tLayer1BarrelTDR.caloSectors = cms.VPSet( - cms.PSet( - etaBoundaries = cms.vdouble(-1.5, 0, 1.5), - phiSlices = cms.uint32(3), - phiZero = cms.double(math.pi/18) - ), - cms.PSet( - etaBoundaries = cms.vdouble(-1.5, 0, 1.5), - phiSlices = cms.uint32(3), - phiZero = cms.double(math.pi*7/18) - ) - ) +process.l1tLayer1BarrelTDR.tkEgAlgoParameters.algorithm = 0 +process.l1tLayer1BarrelTDR.tkEgAlgoParameters.trkQualityPtMin = 10.0 process.l1tLayer1BarrelSerenity = process.l1tLayer1Barrel.clone() process.l1tLayer1BarrelSerenity.regionizerAlgo = "MiddleBufferMultififo" @@ -153,8 +142,7 @@ nTrack = cms.uint32(22), nCalo = cms.uint32(15), nEmCalo = cms.uint32(12), - nMu = cms.uint32(2), - tmux6GCTinput = cms.bool(True), + nMu = cms.uint32(2) ) process.l1tLayer1BarrelSerenity.pfAlgoParameters.nTrack = 22 process.l1tLayer1BarrelSerenity.pfAlgoParameters.nSelCalo = 15 @@ -164,13 +152,7 @@ process.l1tLayer1BarrelSerenity.puAlgoParameters.nIn = 27 process.l1tLayer1BarrelSerenity.puAlgoParameters.nOut = 27 process.l1tLayer1BarrelSerenity.puAlgoParameters.finalSortAlgo = "FoldedHybrid" -process.l1tLayer1BarrelSerenity.caloSectors = cms.VPSet( - cms.PSet( - etaBoundaries = cms.vdouble(-1.5, 0, 1.5), - phiSlices = cms.uint32(3), - phiZero = cms.double(math.pi/18) - ), -) + process.l1tLayer1BarrelSerenity.boards = cms.VPSet(*[cms.PSet(regions = cms.vuint32(*range(18*i,18*i+18))) for i in range(3)]) process.l1tLayer1BarrelSerenityElliptic = process.l1tLayer1BarrelSerenity.clone( tkEgAlgoParameters = process.l1tLayer1BarrelSerenity.tkEgAlgoParameters.clone( @@ -194,13 +176,14 @@ from L1Trigger.Phase2L1ParticleFlow.l1ctLayer1_patternWriters_cff import _eventsPerFile if not args.patternFilesOFF: process.l1tLayer1Barrel.patternWriters = cms.untracked.VPSet(*barrelWriterConfigs) - process.l1tLayer1BarrelTDR.patternWriters = cms.untracked.VPSet(*barrelInputWriterConfigsAPx, - *barrelOutputWriterConfigsAPx, - *barrelWriterDebugPFInConfigsAPx, - *barrelWriterDebugPFOutConfigsAPx + process.l1tLayer1BarrelTDR.patternWriters = cms.untracked.VPSet(barrelInputWriterConfigsAPx, + barrelOutputWriterConfigsAPx, + barrelWriterDebugPFInConfigsAPx, + barrelWriterDebugPFOutConfigsAPx, + barrelWriterDebugEGConfigsAPx ) - process.l1tLayer1BarrelSerenity.patternWriters = cms.untracked.VPSet(*barrelSerenityTM18WriterConfigs) - process.l1tLayer1BarrelSerenityElliptic.patternWriters = cms.untracked.VPSet(*barrelSerenityTM18WriterConfigs) + # process.l1tLayer1BarrelSerenity.patternWriters = cms.untracked.VPSet(*barrelSerenityTM18WriterConfigs) + # process.l1tLayer1BarrelSerenityElliptic.patternWriters = cms.untracked.VPSet(*barrelSerenityTM18WriterConfigs) process.l1tLayer1HGCal.patternWriters = cms.untracked.VPSet(*hgcalTM18WriterConfigs) process.l1tLayer1HGCalElliptic.patternWriters = cms.untracked.VPSet(*hgcalTM18WriterConfigs) From b6fbdcbae6a01c51e3ff4511cd9c89d6d402eb13 Mon Sep 17 00:00:00 2001 From: Piero Viscone Date: Mon, 23 Jun 2025 13:40:49 +0200 Subject: [PATCH 6/9] Implementation of the tkele pt regression @ CTL2 --- DataFormats/L1TCorrelator/interface/TkEm.h | 5 +- DataFormats/L1TCorrelator/src/classes_def.xml | 6 +- .../L1TParticleFlow/interface/datatypes.h | 6 ++ .../L1TParticleFlow/interface/egamma.h | 27 ++++- .../interface/egamma/L1EGPuppiIsoAlgo.h | 3 + .../interface/egamma/l2egencoder_ref.h | 5 +- .../interface/egamma/l2egsorter_ref.h | 4 +- .../interface/egamma/l2tkeleregression_ref.h | 70 ++++++++++++ .../plugins/L1TCtL2EgProducer.cc | 64 ++++++++++- .../python/l1ctLayer2EG_cff.py | 6 ++ .../l1tPFClustersFromL1EGClusters_cfi.py | 3 +- .../src/egamma/L1EGPuppiIsoAlgo.cc | 11 ++ .../src/egamma/l2egencoder_ref.cpp | 7 ++ .../src/egamma/l2egsorter_ref.cpp | 10 ++ .../src/egamma/l2tkeleregression_ref.cpp | 102 ++++++++++++++++++ .../src/egamma/pftkegalgo_ref.cpp | 7 ++ 16 files changed, 326 insertions(+), 10 deletions(-) create mode 100644 L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2tkeleregression_ref.h create mode 100644 L1Trigger/Phase2L1ParticleFlow/src/egamma/l2tkeleregression_ref.cpp diff --git a/DataFormats/L1TCorrelator/interface/TkEm.h b/DataFormats/L1TCorrelator/interface/TkEm.h index 051a324a8e082..4e3a677632fb2 100644 --- a/DataFormats/L1TCorrelator/interface/TkEm.h +++ b/DataFormats/L1TCorrelator/interface/TkEm.h @@ -56,6 +56,7 @@ namespace l1t { egBinaryWord0_ = word; egBinaryWord1_ = (word >> 32); egBinaryWord2_ = (word >> 64); + egBinaryWord3_ = (word >> 96); encoding_ = encoding; } @@ -68,7 +69,8 @@ namespace l1t { template ap_uint egBinaryWord() const { - return ap_uint(egBinaryWord0_) | (ap_uint(egBinaryWord1_) << 32) | (ap_uint(egBinaryWord2_) << 64); + return ap_uint(egBinaryWord0_) | (ap_uint(egBinaryWord1_) << 32) | (ap_uint(egBinaryWord2_) << 64) | + (ap_uint(egBinaryWord3_) << 96); } HWEncoding encoding() const { return encoding_; } @@ -84,6 +86,7 @@ namespace l1t { uint32_t egBinaryWord0_; uint32_t egBinaryWord1_; uint32_t egBinaryWord2_; + uint32_t egBinaryWord3_; HWEncoding encoding_; }; } // namespace l1t diff --git a/DataFormats/L1TCorrelator/src/classes_def.xml b/DataFormats/L1TCorrelator/src/classes_def.xml index 8ac314ea58ae1..16450c6f0f259 100644 --- a/DataFormats/L1TCorrelator/src/classes_def.xml +++ b/DataFormats/L1TCorrelator/src/classes_def.xml @@ -10,7 +10,8 @@ - + + @@ -51,7 +52,8 @@ - + + diff --git a/DataFormats/L1TParticleFlow/interface/datatypes.h b/DataFormats/L1TParticleFlow/interface/datatypes.h index 88f09a5dcf663..21ad4e360ca16 100644 --- a/DataFormats/L1TParticleFlow/interface/datatypes.h +++ b/DataFormats/L1TParticleFlow/interface/datatypes.h @@ -44,6 +44,7 @@ namespace l1ct { typedef ap_ufixed<11, 9, AP_TRN, AP_SAT> iso_t; typedef ap_ufixed<6, 0, AP_RND, AP_SAT> rel_iso_t; typedef ap_ufixed<6, 0, AP_RND, AP_SAT> shower_shape_t; + typedef ap_ufixed<10, 1, AP_RND, AP_SAT> caloTkPtRatio_t; struct ParticleID { ap_uint<3> bits; @@ -160,6 +161,7 @@ namespace l1ct { constexpr float HOE_LSB = 0.031250000; // pow(2, -5) // empirical choice: we saturate to 16 while waiting for updates to the GCT-CTL1 interface document constexpr unsigned int RELISO_SCALE = 16; + constexpr unsigned int CALOTKPTRATIO_SCALE = 8; inline float floatPt(pt_t pt) { return pt.to_float(); } inline float floatPt(dpt_t pt) { return pt.to_float(); } @@ -190,6 +192,9 @@ namespace l1ct { inline float floatIDProb(id_prob_t prob) { return prob.to_float(); }; inline float floatRelIso(rel_iso_t rel_iso) { return rel_iso.to_float() * RELISO_SCALE; } inline float floatShoweShape(shower_shape_t showe_shape) { return showe_shape.to_float(); } + inline float floatCaloTkPtRatio(caloTkPtRatio_t caloTkPtRatio) { + return caloTkPtRatio.to_float() * CALOTKPTRATIO_SCALE; + } inline pt_t makePt(int pt) { return ap_ufixed<16, 14>(pt) >> 2; } inline dpt_t makeDPt(int dpt) { return ap_fixed<18, 16>(dpt) >> 2; } @@ -225,6 +230,7 @@ namespace l1ct { inline meanz_t makeMeanZ(float var) { return round(var - MEANZ_OFFSET); }; inline hoe_t makeHoe(float var) { return hoe_t(HOE_LSB * round(var / HOE_LSB)); }; inline rel_iso_t makeRelIso(float var) { return rel_iso_t(var / RELISO_SCALE); }; + inline caloTkPtRatio_t makeCaloTkPtRatio(float var) { return caloTkPtRatio_t(var / CALOTKPTRATIO_SCALE); }; inline float maxAbsEta() { return ((1 << (eta_t::width - 1)) - 1) * ETAPHI_LSB; } inline float maxAbsPhi() { return ((1 << (phi_t::width - 1)) - 1) * ETAPHI_LSB; } diff --git a/DataFormats/L1TParticleFlow/interface/egamma.h b/DataFormats/L1TParticleFlow/interface/egamma.h index 3b94ebae565f3..bbb078ffc6033 100644 --- a/DataFormats/L1TParticleFlow/interface/egamma.h +++ b/DataFormats/L1TParticleFlow/interface/egamma.h @@ -90,13 +90,20 @@ namespace l1ct { id_score_t hwIDScore; bool hwCharge; + redChi2Bin_t hwTkRedChi2RPhi; // 4 bits + tkdphi_t hwTkCaloDphi; // 7 bits + shower_shape_t hwCaloShowerShape; // 6 bits + caloTkPtRatio_t hwCaloTkPtRatio; // 10 bits + glbphi_t hwVtxPhi() const { return hwCharge ? hwPhi + hwDPhi : hwPhi - hwDPhi; } glbeta_t hwVtxEta() const { return hwEta + hwDEta; } inline bool operator==(const EGIsoEleObj &other) const { return hwPt == other.hwPt && hwEta == other.hwEta && hwPhi == other.hwPhi && hwQual == other.hwQual && hwIso == other.hwIso && hwDEta == other.hwDEta && hwDPhi == other.hwDPhi && hwZ0 == other.hwZ0 && - hwIDScore == other.hwIDScore && hwCharge == other.hwCharge; + hwIDScore == other.hwIDScore && hwCharge == other.hwCharge && hwTkRedChi2RPhi == other.hwTkRedChi2RPhi && + hwTkCaloDphi == other.hwTkCaloDphi && hwCaloShowerShape == other.hwCaloShowerShape && + hwCaloTkPtRatio == other.hwCaloTkPtRatio; } inline bool operator>(const EGIsoEleObj &other) const { return hwPt > other.hwPt; } @@ -113,6 +120,10 @@ namespace l1ct { hwZ0 = 0; hwIDScore = 0; hwCharge = false; + hwTkRedChi2RPhi = 0; + hwTkCaloDphi = 0; + hwCaloShowerShape = 0; + hwCaloTkPtRatio = 0; } int intCharge() const { return hwCharge ? +1 : -1; } @@ -122,9 +133,11 @@ namespace l1ct { float floatVtxPhi() const { return Scales::floatPhi(hwVtxPhi()); } float floatZ0() const { return Scales::floatZ0(hwZ0); } float floatIDScore() const { return Scales::floatIDScore(hwIDScore); } + // FIXME: add accessors - static const int BITWIDTH = - EGIsoObj::BITWIDTH + tkdeta_t::width + tkdphi_t::width + z0_t::width + id_score_t::width + 1; + static const int BITWIDTH = EGIsoObj::BITWIDTH + tkdeta_t::width + tkdphi_t::width + z0_t::width + + id_score_t::width + 1 + redChi2Bin_t::width + tkdphi_t::width + shower_shape_t::width + + caloTkPtRatio_t::width; inline ap_uint pack() const { ap_uint ret; unsigned int start = 0; @@ -138,6 +151,10 @@ namespace l1ct { pack_into_bits(ret, start, hwZ0); pack_bool_into_bits(ret, start, hwCharge); pack_into_bits(ret, start, hwIDScore); + pack_into_bits(ret, start, hwTkRedChi2RPhi); + pack_into_bits(ret, start, hwTkCaloDphi); + pack_into_bits(ret, start, hwCaloShowerShape); + pack_into_bits(ret, start, hwCaloTkPtRatio); return ret; } inline static EGIsoEleObj unpack(const ap_uint &src) { @@ -158,6 +175,10 @@ namespace l1ct { unpack_from_bits(src, start, hwZ0); unpack_bool_from_bits(src, start, hwCharge); unpack_from_bits(src, start, hwIDScore); + unpack_from_bits(src, start, hwTkRedChi2RPhi); + unpack_from_bits(src, start, hwTkCaloDphi); + unpack_from_bits(src, start, hwCaloShowerShape); + unpack_from_bits(src, start, hwCaloTkPtRatio); } l1gt::Electron toGT() const { diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/egamma/L1EGPuppiIsoAlgo.h b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/L1EGPuppiIsoAlgo.h index 175b9d8d2cc5f..593838f3fd6e9 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/egamma/L1EGPuppiIsoAlgo.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/L1EGPuppiIsoAlgo.h @@ -11,6 +11,7 @@ #include "DataFormats/L1TParticleFlow/interface/egamma.h" #include "DataFormats/L1TParticleFlow/interface/puppi.h" #include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" namespace l1ct { @@ -46,6 +47,8 @@ namespace l1ct { public: L1EGPuppiIsoAlgo(const L1EGPuppiIsoAlgoConfig& config) : config_(config) {} L1EGPuppiIsoAlgo(const edm::ParameterSet& pSet); + static edm::ParameterSetDescription getParameterSetDescription(); + virtual ~L1EGPuppiIsoAlgo() = default; void run(const EGIsoObjsEmu& l1EGs, const PuppiObjs& l1PFCands, EGIsoObjsEmu& outL1EGs, z0_t z0 = 0) const; diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2egencoder_ref.h b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2egencoder_ref.h index 010fa8801d692..792901fe1de08 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2egencoder_ref.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2egencoder_ref.h @@ -7,7 +7,8 @@ namespace edm { class ParameterSet; -} + class ParameterSetDescription; +} // namespace edm namespace l1ct { @@ -20,6 +21,8 @@ namespace l1ct { L2EgEncoderEmulator(const edm::ParameterSet& iConfig); + static edm::ParameterSetDescription getParameterSetDescription(); + void toFirmware(const std::vector>& encoded_in, ap_uint<64> encoded_fw[]) const; std::vector> encodeLayer2EgObjs(const std::vector& photons, diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2egsorter_ref.h b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2egsorter_ref.h index 9e1e162c2d943..1bd74db5153c9 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2egsorter_ref.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2egsorter_ref.h @@ -11,7 +11,8 @@ namespace edm { class ParameterSet; -} + class ParameterSetDescription; +} // namespace edm namespace l1ct { @@ -21,6 +22,7 @@ namespace l1ct { : nREGIONS(nRegions), nEGPerRegion(nEGPerRegion), nEGOut(nEGOut), debug_(debug) {} L2EgSorterEmulator(const edm::ParameterSet &iConfig); + static edm::ParameterSetDescription getParameterSetDescription(); virtual ~L2EgSorterEmulator() {} diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2tkeleregression_ref.h b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2tkeleregression_ref.h new file mode 100644 index 0000000000000..fbb64f65e9349 --- /dev/null +++ b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2tkeleregression_ref.h @@ -0,0 +1,70 @@ +#ifndef L2TKELEREGRESSION_REF_H +#define L2TKELEREGRESSION_REF_H + +#include "DataFormats/L1TParticleFlow/interface/layer1_emulator.h" +#include "DataFormats/L1TParticleFlow/interface/egamma.h" +#include "L1Trigger/Phase2L1ParticleFlow/interface/dbgPrintf.h" + +#include +#include "conifer.h" + +namespace edm { + class ParameterSet; + class ParameterSetDescription; +} // namespace edm + +namespace l1ct { + class L2TkEleRegressionEmulator { + public: + enum class ModelType { null = 0, EB_v0 = 1 }; + + L2TkEleRegressionEmulator(const std::vector& eta_bins, + const std::vector& model_types, + const std::vector& model_paths, + int debug); + + L2TkEleRegressionEmulator(const edm::ParameterSet& iConfig); + static edm::ParameterSetDescription getParameterSetDescription(); + + class Model { + public: + Model() = default; + virtual ~Model() = default; + + virtual pt_t compute_ptCorr(const EGIsoEleObjEmu& ele) const = 0; + }; + + class Model_EB_v0 : public Model { + public: + Model_EB_v0(const std::string& model_path, int debug); + + l1ct::pt_t compute_ptCorr(const EGIsoEleObjEmu& ele) const override; + + typedef ap_fixed<10, 1, AP_RND_CONV, AP_SAT> bdt_feature_t; + typedef ap_fixed<12, 3, AP_RND_CONV, AP_SAT> bdt_out_t; + + private: + std::unique_ptr> model_; + bdt_feature_t scale(float x, float min_x, int bitshift, float inf = -1) const { + const float delta = x - min_x; + if (bitshift >= 0) { + const float denom = float(1u << unsigned(bitshift)); + return bdt_feature_t(inf + delta / denom); + } + const float mul = float(1u << unsigned(-bitshift)); + return bdt_feature_t(inf + delta * mul); + } + }; + + void toFirmware(const std::vector>& encoded_in, ap_uint<64> encoded_fw[]) const; + + void run(const std::vector& in_eles, std::vector& out_eles) const; + + private: + std::vector eta_bins_; + std::vector> models_; + }; + +} // namespace l1ct + +#endif diff --git a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc index f30b0838a9803..9c816f0d5761d 100644 --- a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc +++ b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc @@ -8,6 +8,8 @@ #include "FWCore/Framework/interface/Event.h" #include "FWCore/Framework/interface/global/EDProducer.h" #include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" + #include "FWCore/Utilities/interface/InputTag.h" #include "FWCore/Utilities/interface/transform.h" @@ -15,6 +17,7 @@ #include "L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2egsorter_ref.h" #include "L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2egencoder_ref.h" #include "L1Trigger/Phase2L1ParticleFlow/interface/egamma/L1EGPuppiIsoAlgo.h" +#include "L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2tkeleregression_ref.h" #include "L1Trigger/DemonstratorTools/interface/BoardDataWriter.h" #include "L1Trigger/DemonstratorTools/interface/utilities.h" @@ -29,6 +32,8 @@ class L1TCtL2EgProducer : public edm::global::EDProducer<> { explicit L1TCtL2EgProducer(const edm::ParameterSet &); ~L1TCtL2EgProducer() override; + edm::ParameterSetDescription getParameterSetDescription(); + private: ap_uint<64> encodeLayer1(const EGIsoObjEmu &egiso) const; ap_uint<128> encodeLayer1(const EGIsoEleObjEmu &egiso) const; @@ -137,6 +142,28 @@ class L1TCtL2EgProducer : public edm::global::EDProducer<> { channelSpecs); } + static edm::ParameterSetDescription getParameterSetDescription() { + edm::ParameterSetDescription desc; + desc.add("format"); + desc.add("outputFilename"); + desc.add("outputFileExtension"); + desc.add("nFramesPerBX"); + desc.add("TMUX"); + desc.add("maxLinesPerFile"); + desc.add("eventsPerFile"); + + edm::ParameterSetDescription channelDesc; + channelDesc.add("interface"); + channelDesc.add("id"); + channelDesc.add("TMUX"); + channelDesc.add("nWords"); + channelDesc.add>("channels"); + + desc.addVPSet("channels", channelDesc); + + return desc; + } + struct RegionLinkMetadata { l1t::demo::LinkId linkId; unsigned int nTrailingWords; @@ -231,6 +258,7 @@ class L1TCtL2EgProducer : public edm::global::EDProducer<> { std::string tkEleInstanceLabel_; l1ct::L2EgSorterEmulator l2egsorter; l1ct::L2EgEncoderEmulator l2encoder; + l1ct::L2TkEleRegressionEmulator l2tkeleregression; edm::EDGetTokenT> pfObjsToken_; l1ct::L1EGPuppiIsoAlgo l2EgPuppiIsoAlgo_; l1ct::L1EGPuppiIsoAlgo l2ElePuppiIsoAlgo_; @@ -249,6 +277,7 @@ L1TCtL2EgProducer::L1TCtL2EgProducer(const edm::ParameterSet &conf) tkEleInstanceLabel_(conf.getParameter("tkEleInstanceLabel")), l2egsorter(conf.getParameter("sorter")), l2encoder(conf.getParameter("encoder")), + l2tkeleregression(conf.getParameter("eleRegression")), pfObjsToken_(consumes>(conf.getParameter("l1PFObjects"))), l2EgPuppiIsoAlgo_(conf.getParameter("puppiIsoParametersTkEm")), l2ElePuppiIsoAlgo_(conf.getParameter("puppiIsoParametersTkEle")), @@ -270,6 +299,35 @@ L1TCtL2EgProducer::L1TCtL2EgProducer(const edm::ParameterSet &conf) L1TCtL2EgProducer::~L1TCtL2EgProducer() {} +edm::ParameterSetDescription L1TCtL2EgProducer::getParameterSetDescription() { + edm::ParameterSetDescription desc; + + edm::ParameterSetDescription inputDesc; + inputDesc.add("pfProducer"); + inputDesc.add>("regions"); + + desc.addVPSet("tkEgs", inputDesc); + desc.addVPSet("tkEms", inputDesc); + desc.addVPSet("tkElectrons", inputDesc); + desc.add("egStaInstanceLabel", "L1CtEgEE"); + desc.add("tkEmInstanceLabel", "L1CtTkEm"); + desc.add("tkEleInstanceLabel", "L1CtTkElectron"); + desc.add("sorter", l1ct::L2EgSorterEmulator::getParameterSetDescription()); + desc.add("encoder", l1ct::L2EgEncoderEmulator::getParameterSetDescription()); + desc.add("eleRegression", + l1ct::L2TkEleRegressionEmulator::getParameterSetDescription()); + desc.add("l1PFObjects", edm::InputTag("l1pfProducer")); + desc.add("puppiIsoParametersTkEm", + l1ct::L1EGPuppiIsoAlgo::getParameterSetDescription()); + desc.add("puppiIsoParametersTkEle", + l1ct::L1EGPuppiIsoAlgo::getParameterSetDescription()); + desc.add("writeInPattern", false); + desc.add("writeOutPattern", false); + desc.add("inPatternFile", PatternWriter::getParameterSetDescription()); + desc.add("outPatternFile", PatternWriter::getParameterSetDescription()); + return desc; +} + ap_uint<64> L1TCtL2EgProducer::encodeLayer1(const EGIsoObjEmu &egiso) const { ap_uint<64> ret = 0; ret(EGIsoObjEmu::BITWIDTH, 0) = egiso.pack(); @@ -345,8 +403,12 @@ void L1TCtL2EgProducer::produce(edm::StreamID, edm::Event &iEvent, const edm::Ev } std::vector out_photons_emu; + std::vector sorted_eles_emu; std::vector out_eles_emu; - l2egsorter.run(*regions, out_photons_emu, out_eles_emu); + l2egsorter.run(*regions, out_photons_emu, sorted_eles_emu); + + // Apply electron regression + l2tkeleregression.run(sorted_eles_emu, out_eles_emu); // PUPPI isolation auto &pfObjs = iEvent.get(pfObjsToken_); diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py index f8ac89ffa96ed..14019fe072f47 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py @@ -52,6 +52,12 @@ nTKELE_OUT=cms.uint32(12), nTKPHO_OUT=cms.uint32(12), ), + eleRegression=cms.PSet( + eta_bins=cms.vdouble(1.5), + model_types=cms.vuint32(1), + model_paths=cms.vstring( + "L1Trigger/Phase2L1ParticleFlow/data/egamma/TkElePtRegr_EB_sigVsBkg_v0_conifer.json") + ), puppiIsoParametersTkEm = cms.PSet( pfIsoType = cms.string("PUPPI"), pfPtMin = cms.double(1.), diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1tPFClustersFromL1EGClusters_cfi.py b/L1Trigger/Phase2L1ParticleFlow/python/l1tPFClustersFromL1EGClusters_cfi.py index 7004f87b03a96..da87c8ad72cad 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1tPFClustersFromL1EGClusters_cfi.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/l1tPFClustersFromL1EGClusters_cfi.py @@ -31,7 +31,8 @@ ) ) phase2_hgcalV11.toModify(l1tPFClustersFromL1EGClusters, - corrector = "", # In this setup, TP's are already calibrated correctly :-) + corrector = "L1Trigger/Phase2L1ParticleFlow/data/emcorr_barrel.root", + # In this setup, TP's are already calibrated correctly :-) # L1Trigger/Phase2L1ParticleFlow/data/emcorr_barrel_110X.root", resol = cms.PSet( etaBins = cms.vdouble( 0.700, 1.200, 1.600), diff --git a/L1Trigger/Phase2L1ParticleFlow/src/egamma/L1EGPuppiIsoAlgo.cc b/L1Trigger/Phase2L1ParticleFlow/src/egamma/L1EGPuppiIsoAlgo.cc index 4d77d7866c0c0..5fa3ae653af6f 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/egamma/L1EGPuppiIsoAlgo.cc +++ b/L1Trigger/Phase2L1ParticleFlow/src/egamma/L1EGPuppiIsoAlgo.cc @@ -10,6 +10,17 @@ L1EGPuppiIsoAlgo::L1EGPuppiIsoAlgo(const edm::ParameterSet& pSet) pSet.getParameter("dRMax"), pSet.getParameter("pfCandReuse")) {} +edm::ParameterSetDescription L1EGPuppiIsoAlgo::getParameterSetDescription() { + edm::ParameterSetDescription desc; + desc.add("pfIsoType"); + desc.add("pfPtMin"); + desc.add("dZ"); + desc.add("dRMin"); + desc.add("dRMax"); + desc.add("pfCandReuse"); + return desc; +} + void L1EGPuppiIsoAlgo::run(const EGIsoObjsEmu& l1EGs, const PuppiObjs& l1PFCands, EGIsoObjsEmu& outL1EGs, diff --git a/L1Trigger/Phase2L1ParticleFlow/src/egamma/l2egencoder_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/egamma/l2egencoder_ref.cpp index 64ffeb9f13e24..ea4a5157d7c7e 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/egamma/l2egencoder_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/egamma/l2egencoder_ref.cpp @@ -5,10 +5,17 @@ using namespace l1ct; #ifdef CMSSW_GIT_HASH #include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" l1ct::L2EgEncoderEmulator::L2EgEncoderEmulator(const edm::ParameterSet& pset) : L2EgEncoderEmulator(pset.getParameter("nTKELE_OUT"), pset.getParameter("nTKPHO_OUT")) {} +edm::ParameterSetDescription l1ct::L2EgEncoderEmulator::getParameterSetDescription() { + edm::ParameterSetDescription desc; + desc.add("nTKELE_OUT", 12); + desc.add("nTKPHO_OUT", 12); + return desc; +} #endif void L2EgEncoderEmulator::toFirmware(const std::vector>& encoded_in, ap_uint<64> encoded_fw[]) const { diff --git a/L1Trigger/Phase2L1ParticleFlow/src/egamma/l2egsorter_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/egamma/l2egsorter_ref.cpp index 64bc9314ff5ce..19871e3fb98c4 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/egamma/l2egsorter_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/egamma/l2egsorter_ref.cpp @@ -10,12 +10,22 @@ using namespace l1ct; #ifdef CMSSW_GIT_HASH #include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" l1ct::L2EgSorterEmulator::L2EgSorterEmulator(const edm::ParameterSet &pset) : L2EgSorterEmulator(pset.getParameter("nREGIONS"), pset.getParameter("nEGPerRegion"), pset.getParameter("nEGOut"), pset.getUntrackedParameter("debug", 0)) {} + +edm::ParameterSetDescription l1ct::L2EgSorterEmulator::getParameterSetDescription() { + edm::ParameterSetDescription desc; + desc.add("nREGIONS", 5); + desc.add("nEGPerRegion", 16); + desc.add("nEGOut", 12); + desc.addUntracked("debug", 0); + return desc; +} #endif void L2EgSorterEmulator::toFirmware(const std::vector &out_photons, diff --git a/L1Trigger/Phase2L1ParticleFlow/src/egamma/l2tkeleregression_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/egamma/l2tkeleregression_ref.cpp new file mode 100644 index 0000000000000..2ecbaad35107f --- /dev/null +++ b/L1Trigger/Phase2L1ParticleFlow/src/egamma/l2tkeleregression_ref.cpp @@ -0,0 +1,102 @@ +#include "L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2tkeleregression_ref.h" + +#ifdef CMSSW_GIT_HASH +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" + +l1ct::L2TkEleRegressionEmulator::L2TkEleRegressionEmulator(const edm::ParameterSet& iConfig) + : L2TkEleRegressionEmulator(iConfig.getParameter>("eta_bins"), + iConfig.getParameter>("model_types"), + iConfig.getParameter>("model_paths"), + iConfig.getUntrackedParameter("debug", 0)) {} + +edm::ParameterSetDescription l1ct::L2TkEleRegressionEmulator::getParameterSetDescription() { + edm::ParameterSetDescription desc; + desc.add>("eta_bins", std::vector{1.5}); + desc.add>("model_types", std::vector{1}); + desc.add>( + "model_paths", + std::vector{"L1Trigger/Phase2L1ParticleFlow/data/egamma/eb_v0/eta_bin0_emf_bin0/model.json"}); + desc.addUntracked("debug", 0); + return desc; +} + +#endif + +l1ct::L2TkEleRegressionEmulator::L2TkEleRegressionEmulator(const std::vector& eta_bins, + const std::vector& model_types, + const std::vector& model_paths, + int debug) { + if (model_types.size() != model_paths.size() || model_types.size() != eta_bins.size()) { + throw std::invalid_argument("Size of model_types and model_paths must be the same"); + } + // check the eta bins are in increasing order + for (size_t i = 1; i < eta_bins.size(); ++i) { + if (eta_bins[i] <= eta_bins[i - 1]) { + throw std::invalid_argument("Eta bins must be in increasing order"); + } + } + for (unsigned int i = 0; i < model_types.size(); ++i) { + auto type = ModelType(model_types[i]); + if (type == ModelType::EB_v0) { + models_.push_back(std::make_unique(model_paths[models_.size()], debug)); + } else if (type == ModelType::null) { + models_.push_back(nullptr); + } else { + throw std::invalid_argument("Unsupported regression algorithm"); + } + eta_bins_.push_back(eta_bins[i]); + } +} + +l1ct::L2TkEleRegressionEmulator::Model_EB_v0::Model_EB_v0(const std::string& model_path, int debug) { +#ifdef CMSSW_GIT_HASH + auto resolvedFileName = edm::FileInPath(model_path).fullPath(); +#else + auto resolvedFileName = model_path; +#endif + model_ = std::make_unique>(resolvedFileName); +} + +l1ct::pt_t l1ct::L2TkEleRegressionEmulator::Model_EB_v0::compute_ptCorr(const EGIsoEleObjEmu& ele) const { + bdt_feature_t scaled_ID = bdt_feature_t(ele.floatIDScore()); + bdt_feature_t scaled_cl_eta = scale(fabs(ele.floatEta()), 0., 0); + bdt_feature_t scaled_cltk_absDphi = scale(ele.hwTkCaloDphi.to_float(), 0., 5); + bdt_feature_t scaled_tk_chi2RPhi = scale(ele.hwTkRedChi2RPhi.to_float(), 0., 3); + bdt_feature_t scaled_cl_pt = scale(ele.floatPt(), 0., 5); + bdt_feature_t scaled_cl_ss = scale(ele.hwCaloShowerShape.to_float(), 0., -1); + bdt_feature_t scaled_cltk_ptRatio = scale(ele.hwCaloTkPtRatio.to_float(), 0., 0); + + // Run BDT inference + std::vector inputs = {scaled_ID, + scaled_cl_eta, + scaled_cltk_absDphi, + scaled_tk_chi2RPhi, + scaled_cl_pt, + scaled_cl_ss, + scaled_cltk_ptRatio}; + + std::vector bdt_output = model_->decision_function(inputs); + + bdt_out_t corr_factor = bdt_out_t(bdt_output[0]); + float corr_pt = ele.hwPt.to_float() * (1. + corr_factor.to_float()); + return pt_t(corr_pt); +} + +void l1ct::L2TkEleRegressionEmulator::run(const std::vector& in_eles, + std::vector& out_eles) const { + out_eles.clear(); + for (const auto& ele : in_eles) { + EGIsoEleObjEmu corrected_ele = ele; + // find the eta bin the electron falls into and apply the corresponding regression model + for (size_t i = 0; i < eta_bins_.size(); ++i) { + if (std::abs(ele.floatVtxEta()) < eta_bins_[i]) { + if (models_[i]) { + corrected_ele.hwPt = models_[i]->compute_ptCorr(ele); + } + break; + } + } + out_eles.push_back(corrected_ele); + } +} diff --git a/L1Trigger/Phase2L1ParticleFlow/src/egamma/pftkegalgo_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/egamma/pftkegalgo_ref.cpp index 2dfa4a54b7c13..032f34bc577db 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/egamma/pftkegalgo_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/egamma/pftkegalgo_ref.cpp @@ -827,6 +827,13 @@ EGIsoEleObjEmu &PFTkEGAlgoEmulator::addEGIsoEleToPF(std::vector egiso.srcCluster = calo.src; egiso.srcTrack = track.src; egiso.hwIDScore = bdtScore; + // additional variables for pt regression on layer-2 + egiso.hwTkRedChi2RPhi = track.hwRedChi2RPhi; + egiso.hwTkCaloDphi = abs(track.hwPhi - calo.hwPhi); + egiso.hwCaloShowerShape = calo.hwShowerShape; + + ap_ufixed<16, 0> tk_invPt = l1ct::invert_with_shift, 1024>(track.hwPt); + egiso.hwCaloTkPtRatio = l1ct::Scales::makeCaloTkPtRatio(calo.hwPt * tk_invPt); egobjs.push_back(egiso); if (debug_ > 2) From 9022c1da30c0aa039c6e902638373a768682e581 Mon Sep 17 00:00:00 2001 From: Gianluca Date: Mon, 22 Jun 2026 15:30:15 +0200 Subject: [PATCH 7/9] Add GCT TMUX18 link emulation to Phase2 tasks --- L1Trigger/Configuration/python/SimL1Emulator_cff.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/L1Trigger/Configuration/python/SimL1Emulator_cff.py b/L1Trigger/Configuration/python/SimL1Emulator_cff.py index 1ca6967ff2a25..7c8fc6669d8f9 100644 --- a/L1Trigger/Configuration/python/SimL1Emulator_cff.py +++ b/L1Trigger/Configuration/python/SimL1Emulator_cff.py @@ -108,6 +108,9 @@ from L1Trigger.L1CaloTrigger.l1tPhase2GCTBarrelToCorrelatorLayer1Emulator_cfi import * _phase2_siml1emulator.add(l1tPhase2GCTBarrelToCorrelatorLayer1Emulator) +from L1Trigger.L1CaloTrigger.l1tPhase2CaloToCorrelatorTM18_cfi import * +_phase2_siml1emulator.add(l1tPhase2CaloToCorrelatorTM18) + # Barrel and EndCap CaloJet/HT/NNCaloTau # ######################################################################## # ---- Produce the calibrated tower collection combining Barrel, HGCal, HF From 5d678bcebeac80d377a81a0ff1eca8667117c9e1 Mon Sep 17 00:00:00 2001 From: Gianluca Date: Tue, 23 Jun 2026 14:25:37 +0200 Subject: [PATCH 8/9] Code review --- .../interface/DigitizedL1CaloJet.h | 8 ++++---- .../interface/GCTHadDigiCluster.h | 2 +- .../L1TParticleFlow/interface/egamma.h | 5 ++++- .../interface/Phase2L1CaloEGammaUtils.h | 6 ++++-- .../interface/Phase2L1CaloPFClusterEmulator.h | 2 +- .../plugins/Phase2L1CaloToCorrelatorTM18.cc | 20 +++++++++---------- .../tdr_regionizer_elements_ref.icc | 6 +++--- .../plugins/L1TCtL2EgProducer.cc | 2 +- .../plugins/L1TSC82ProngJetModelProducer.cc | 10 +++++----- ...middle_buffer_multififo_regionizer_ref.cpp | 7 ------- 10 files changed, 33 insertions(+), 35 deletions(-) diff --git a/DataFormats/L1TCalorimeterPhase2/interface/DigitizedL1CaloJet.h b/DataFormats/L1TCalorimeterPhase2/interface/DigitizedL1CaloJet.h index 33779365e7589..00d4192779617 100644 --- a/DataFormats/L1TCalorimeterPhase2/interface/DigitizedL1CaloJet.h +++ b/DataFormats/L1TCalorimeterPhase2/interface/DigitizedL1CaloJet.h @@ -63,7 +63,7 @@ namespace l1tp2 { static constexpr unsigned int n_bits_eta = 14; // Private member functions for doing the digitization - ap_uint<16> digitizePt(float pt_f) { + ap_uint<16> digitizePt(float pt_f) const { float maxPt_f = (std::pow(2.0f, n_bits_pt) - 1) * LSB_PT; // If pT exceeds the maximum, saturate the value if (pt_f >= maxPt_f) { @@ -72,7 +72,7 @@ namespace l1tp2 { return (ap_uint<16>)(pt_f / LSB_PT); } - ap_uint<13> digitizePhi(float phi_f) { + ap_uint<13> digitizePhi(float phi_f) const { float maxPhi_f = (std::pow(2.0f, n_bits_phi - 1) - 1) * LSB_PHI; // If phi exceeds the maximum (very few values should), saturate the value if (phi_f >= maxPhi_f) { @@ -83,7 +83,7 @@ namespace l1tp2 { return (ap_uint<13>)(phi_f / LSB_PHI); } - ap_uint<14> digitizeEta(float eta_f) { + ap_uint<14> digitizeEta(float eta_f) const { float maxEta_f = (std::pow(2.0f, n_bits_eta - 1) - 1) * LSB_ETA; // If eta exceeds the maximum, saturate the value if (eta_f >= maxEta_f) { @@ -94,7 +94,7 @@ namespace l1tp2 { return (ap_uint<14>)(eta_f / LSB_ETA); } - ap_uint<1> digitizeIsValid(bool isValid_b) { return (ap_uint<1>)isValid_b; } + ap_uint<1> digitizeIsValid(bool isValid_b) const { return (ap_uint<1>)isValid_b; } }; // Concrete collection of output objects (with extra tuning information) diff --git a/DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h b/DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h index 7a12138a40ba7..17b60e81c6657 100644 --- a/DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h +++ b/DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h @@ -58,7 +58,7 @@ namespace l1tp2 { ap_uint<6> fb() const { return ((clusterData >> 38) & 0x3F); } // Encoding region information - ap_uint<36> spare() const { return ((clusterData >> 44) & 0xFFFFF); } + ap_uint<20> spare() const { return ((clusterData >> 44) & 0xFFFFF); } #ifdef CMSSW_GIT_HASH // Get the underlying ref diff --git a/DataFormats/L1TParticleFlow/interface/egamma.h b/DataFormats/L1TParticleFlow/interface/egamma.h index bbb078ffc6033..98efa538280f6 100644 --- a/DataFormats/L1TParticleFlow/interface/egamma.h +++ b/DataFormats/L1TParticleFlow/interface/egamma.h @@ -133,7 +133,10 @@ namespace l1ct { float floatVtxPhi() const { return Scales::floatPhi(hwVtxPhi()); } float floatZ0() const { return Scales::floatZ0(hwZ0); } float floatIDScore() const { return Scales::floatIDScore(hwIDScore); } - // FIXME: add accessors + int intTkRedChi2RPhi() const { return hwTkRedChi2RPhi.to_int(); } + float floatCaloDPhi() const { return Scales::floatPhi(hwTkCaloDphi); } + float floatCaloShowerShape() const { return Scales::floatShoweShape(hwCaloShowerShape); } + float floatCaloTkPtRatio() const { return Scales::floatCaloTkPtRatio(hwCaloTkPtRatio); } static const int BITWIDTH = EGIsoObj::BITWIDTH + tkdeta_t::width + tkdphi_t::width + z0_t::width + id_score_t::width + 1 + redChi2Bin_t::width + tkdphi_t::width + shower_shape_t::width + diff --git a/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloEGammaUtils.h b/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloEGammaUtils.h index 5d6616c0ac4e4..3249c39601366 100644 --- a/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloEGammaUtils.h +++ b/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloEGammaUtils.h @@ -1061,7 +1061,9 @@ namespace p2eg { inline int standaloneWP() const { return (is_iso && is_ss); } inline int looseL1TkMatchWP() const { return (is_looseTkiso && is_looseTkss); } - inline int photonWP() const { return (is_looseTkiso && is_looseTkss); } // NOTE: NO PHOTON WP + inline int photonWP() const { + return (is_looseTkiso && is_looseTkss); + } // NOTE: NO PHOTON WP, we use tghe Tkloose WP for the menu inline int passesShowerShape() const { return is_ss; } @@ -1296,7 +1298,7 @@ namespace p2eg { ap_int<7> phivscenter = 0; for (int i = 0; i < 6; i++) { float tempDifference = p2eg::deltaPhiInDegrees(clusterRealPhiAsDegree, regionCentersInDegrees[i]); - if (abs(tempDifference) < PHI_RANGE_PER_SLR_DEGREES / 4) { + if (std::abs(tempDifference) < PHI_RANGE_PER_SLR_DEGREES / 4) { phivscenter = 0x7F & int(std::floor(tempDifference)); // greatest integer <= x cardnumber = int(i / 2); } diff --git a/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloPFClusterEmulator.h b/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloPFClusterEmulator.h index ff5468355d85c..a2543932e0e66 100644 --- a/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloPFClusterEmulator.h +++ b/L1Trigger/L1CaloTrigger/interface/Phase2L1CaloPFClusterEmulator.h @@ -2,7 +2,7 @@ #define _PHASE_2_L1_CALO_PFCLUSTER_EMULATOR_H_ #include - +#include // eta: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // 0 | | // 1 | | diff --git a/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloToCorrelatorTM18.cc b/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloToCorrelatorTM18.cc index 0ad9fba4d37ba..74b8a396bc5c8 100644 --- a/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloToCorrelatorTM18.cc +++ b/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloToCorrelatorTM18.cc @@ -46,16 +46,16 @@ void Phase2L1CaloToCorrelatorTM18::produce(edm::Event& evt, const edm::EventSetu std::unique_ptr caloCandsTM18( std::make_unique()); - int EM_SLR1_POS_OFFSET = 1; - int EM_SLR1_NEG_OFFSET = 17; - int PF_SLR1_POS_OFFSET = 33; - int PF_SLR1_NEG_OFFSET = 57; - int EM_SLR3_POS_OFFSET = 82; - int EM_SLR3_NEG_OFFSET = 98; - int PF_SLR3_POS_OFFSET = 114; - int PF_SLR3_NEG_OFFSET = 138; - int NUM_EM_WORDS = 16; - int NUM_PF_WORDS = 24; + const int EM_SLR1_POS_OFFSET = 1; + const int EM_SLR1_NEG_OFFSET = 17; + const int PF_SLR1_POS_OFFSET = 33; + const int PF_SLR1_NEG_OFFSET = 57; + const int EM_SLR3_POS_OFFSET = 82; + const int EM_SLR3_NEG_OFFSET = 98; + const int PF_SLR3_POS_OFFSET = 114; + const int PF_SLR3_NEG_OFFSET = 138; + const int NUM_EM_WORDS = 16; + const int NUM_PF_WORDS = 24; int cntr03pos = 0; int cntr03neg = 0; diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.icc b/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.icc index 31035c871756c..cb47cd8131837 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.icc +++ b/L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_elements_ref.icc @@ -246,11 +246,11 @@ void l1ct::tdr_regionizer::Regionizer::setBuffers(const std::vector 0) ? getSmallRegions(glbeta, glbphi) : std::vector(); if (debug_) { if (!srs.empty()) { - std::cout << " "; + dbgCout() << " "; for (auto sr : srs) { - std::cout << " " << sr; + dbgCout() << " " << sr; } - std::cout << std::endl; + dbgCout() << std::endl; } } buffers_[buffer].addEntry(obj, srs, glbeta, glbphi); diff --git a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc index 9c816f0d5761d..c013aaa7c6d15 100644 --- a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc +++ b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc @@ -32,7 +32,7 @@ class L1TCtL2EgProducer : public edm::global::EDProducer<> { explicit L1TCtL2EgProducer(const edm::ParameterSet &); ~L1TCtL2EgProducer() override; - edm::ParameterSetDescription getParameterSetDescription(); + static edm::ParameterSetDescription getParameterSetDescription(); private: ap_uint<64> encodeLayer1(const EGIsoObjEmu &egiso) const; diff --git a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TSC82ProngJetModelProducer.cc b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TSC82ProngJetModelProducer.cc index a8bb606acb5d7..b35dcc002f259 100644 --- a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TSC82ProngJetModelProducer.cc +++ b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TSC82ProngJetModelProducer.cc @@ -1,8 +1,9 @@ #include "FWCore/Framework/interface/Frameworkfwd.h" #include "FWCore/Framework/interface/stream/EDProducer.h" #include "FWCore/Framework/interface/Event.h" -#include "FWCore/Framework/interface/MakerMacros.h" #include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" #include "FWCore/Utilities/interface/InputTag.h" #include "DataFormats/L1TParticleFlow/interface/PFJet.h" @@ -20,8 +21,6 @@ #include "ap_fixed.h" #include "hls4ml/emulator.h" -using namespace l1t; - class L1TSC82ProngJetProducer : public edm::stream::EDProducer<> { public: explicit L1TSC82ProngJetProducer(const edm::ParameterSet&); @@ -86,9 +85,10 @@ void L1TSC82ProngJetProducer::produce(edm::Event& iEvent, const edm::EventSetup& taggedJets.push_back(edmJet); } - std::sort(taggedJets.begin(), taggedJets.end(), [](l1t::PFJet a, l1t::PFJet b) { return (a.pt() > b.pt()); }); + std::sort( + taggedJets.begin(), taggedJets.end(), [](const l1t::PFJet& a, const l1t::PFJet& b) { return (a.pt() > b.pt()); }); - std::unique_ptr taggedJetsCollection(new l1t::PFJetCollection); + std::unique_ptr taggedJetsCollection = std::make_unique(); taggedJetsCollection->swap(taggedJets); iEvent.put(std::move(taggedJetsCollection), "l1tSC82ProngJets"); } diff --git a/L1Trigger/Phase2L1ParticleFlow/src/regionizer/middle_buffer_multififo_regionizer_ref.cpp b/L1Trigger/Phase2L1ParticleFlow/src/regionizer/middle_buffer_multififo_regionizer_ref.cpp index d82d2ee9353c0..97068c0f532f9 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/regionizer/middle_buffer_multififo_regionizer_ref.cpp +++ b/L1Trigger/Phase2L1ParticleFlow/src/regionizer/middle_buffer_multififo_regionizer_ref.cpp @@ -669,13 +669,6 @@ void l1ct::MiddleBufferMultififoRegionizerEmulator::init_GCT_tmux18sectors( void l1ct::MiddleBufferMultififoRegionizerEmulator::run(const RegionizerDecodedInputs& in, std::vector& out) { - // FIXME: run_worker is no longer needed - run_worker(in, out); -} - -// FIXME: run_worker is no longer needed -void l1ct::MiddleBufferMultififoRegionizerEmulator::run_worker(const RegionizerDecodedInputs& in, - std::vector& out) { assert(streaming_); // doesn't make sense otherwise if (!init_) initSectorsAndRegions(in, out); From 44897494a8635d72b47b7c749ad9bca8fb053d0a Mon Sep 17 00:00:00 2001 From: Gianluca Date: Tue, 23 Jun 2026 15:09:14 +0200 Subject: [PATCH 9/9] Code review cont. --- .../L1CaloTrigger/plugins/Phase2L1CaloToCorrelatorTM18.cc | 1 - L1Trigger/Phase2L1ParticleFlow/interface/NNVtxAssoc.h | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloToCorrelatorTM18.cc b/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloToCorrelatorTM18.cc index 74b8a396bc5c8..471ebb8539567 100644 --- a/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloToCorrelatorTM18.cc +++ b/L1Trigger/L1CaloTrigger/plugins/Phase2L1CaloToCorrelatorTM18.cc @@ -42,7 +42,6 @@ Phase2L1CaloToCorrelatorTM18::Phase2L1CaloToCorrelatorTM18(const edm::ParameterS } void Phase2L1CaloToCorrelatorTM18::produce(edm::Event& evt, const edm::EventSetup& es) { - using namespace edm; std::unique_ptr caloCandsTM18( std::make_unique()); diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/NNVtxAssoc.h b/L1Trigger/Phase2L1ParticleFlow/interface/NNVtxAssoc.h index 0c785daf06a6b..3cc33f2f078e2 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/NNVtxAssoc.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/NNVtxAssoc.h @@ -21,8 +21,8 @@ struct AssociationObjEmu { typedef ap_ufixed<22, 9> nn_inputtype; typedef ap_fixed<22, 9> classtype; -#define N_NN_ASSOC_FEATURES 4 // How many features are used in a track -#define N_NN_ASSOC_OUTPUTS 1 // How many features are used in a track +static constexpr int N_NN_ASSOC_FEATURES = 4; // How many features are used in a track +static constexpr int N_NN_ASSOC_OUTPUTS = 1; // How many features are used in a track static const nn_inputtype associationNetworkEtaBounds[127] = {0.0, 0.01984126984126984,