diff --git a/L1Trigger/Configuration/python/L1Trigger_EventContent_cff.py b/L1Trigger/Configuration/python/L1Trigger_EventContent_cff.py index 17ee0b32aa165..bd302c7951555 100644 --- a/L1Trigger/Configuration/python/L1Trigger_EventContent_cff.py +++ b/L1Trigger/Configuration/python/L1Trigger_EventContent_cff.py @@ -227,6 +227,8 @@ def _appendPhase2Digis(obj): 'keep *_l1tHPSPFTauProducer_*_*', 'keep *_l1tBJetProducerPuppi_*_*', 'keep *_l1tBJetProducerPuppiCorrectedEmulator_*_*', + 'keep *_l1tTOoLLiPProducer_*_*', + 'keep *_l1tTOoLLiPProducerCorrectedEmulator_*_*', 'keep *_TTStubsFromPhase2TrackerDigis_*_*', 'keep *_TTClustersFromPhase2TrackerDigis_*_*', 'keep *_l1tTTTracksFromExtendedTrackletEmulation_*_*', diff --git a/L1Trigger/Configuration/python/SimL1Emulator_cff.py b/L1Trigger/Configuration/python/SimL1Emulator_cff.py index 91bd0ba2e181a..6136c3cc49919 100644 --- a/L1Trigger/Configuration/python/SimL1Emulator_cff.py +++ b/L1Trigger/Configuration/python/SimL1Emulator_cff.py @@ -244,6 +244,10 @@ from L1Trigger.Phase2L1ParticleFlow.L1BJetProducer_cff import * _phase2_siml1emulator.add(L1TBJetsTask) +# LLPJets +# ######################################################################## +from L1Trigger.Phase2L1ParticleFlow.TOoLLiPProducer_cff import * +_phase2_siml1emulator.add(L1TTOoLLiPTask) # --> add modules from Configuration.Eras.Modifier_phase2_trigger_cff import phase2_trigger diff --git a/L1Trigger/Phase2L1ParticleFlow/BuildFile.xml b/L1Trigger/Phase2L1ParticleFlow/BuildFile.xml index 9c3b1442767df..e45b710a713f9 100644 --- a/L1Trigger/Phase2L1ParticleFlow/BuildFile.xml +++ b/L1Trigger/Phase2L1ParticleFlow/BuildFile.xml @@ -13,8 +13,9 @@ - + + diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/BJetId.h b/L1Trigger/Phase2L1ParticleFlow/interface/JetId.h similarity index 60% rename from L1Trigger/Phase2L1ParticleFlow/interface/BJetId.h rename to L1Trigger/Phase2L1ParticleFlow/interface/JetId.h index cffbafce13e9c..8dd4d14a7afcf 100644 --- a/L1Trigger/Phase2L1ParticleFlow/interface/BJetId.h +++ b/L1Trigger/Phase2L1ParticleFlow/interface/JetId.h @@ -1,11 +1,16 @@ -#ifndef L1TRIGGER_PHASE2L1PARTICLEFLOWS_BJETID_H -#define L1TRIGGER_PHASE2L1PARTICLEFLOWS_BJETID_H +#ifndef L1TRIGGER_PHASE2L1PARTICLEFLOWS_JETID_H +#define L1TRIGGER_PHASE2L1PARTICLEFLOWS_JETID_H #include #include "PhysicsTools/TensorFlow/interface/TensorFlow.h" #include "DataFormats/L1TParticleFlow/interface/PFCandidate.h" #include "DataFormats/L1TParticleFlow/interface/PFJet.h" +//HLS4ML compiled emulator modeling +#include +#include "ap_fixed.h" +#include "hls4ml/emulator.h" + struct BJetTFCache { BJetTFCache(const std::string &graphPath) : graphDef(tensorflow::loadGraphDef(graphPath)) { session = tensorflow::createSession(graphDef.get()); @@ -15,14 +20,20 @@ struct BJetTFCache { tensorflow::Session *session; }; -class BJetId { +class JetId { public: - BJetId(const std::string &iInput, const std::string &iOutput, const BJetTFCache *cache, int iNParticles); - ~BJetId(); + JetId(const std::string &iInput, + const std::string &iOutput, + const std::shared_ptr model, + int iNParticles); + JetId(const std::string &iInput, const std::string &iOutput, const BJetTFCache *cache, int iNParticles); + ~JetId() = default; void setNNVectorVar(); float EvaluateNN(); + ap_fixed<16, 6> EvaluateNNFixed(); float compute(const l1t::PFJet &iJet, float vz, bool useRawPt); + ap_fixed<16, 6> computeFixed(const l1t::PFJet &iJet, float vz, bool useRawPt); private: std::vector NNvectorVar_; @@ -38,5 +49,6 @@ class BJetId { unique_ptr fDX_; unique_ptr fDY_; tensorflow::Session *sessionRef_; + std::shared_ptr modelRef_; }; #endif diff --git a/L1Trigger/Phase2L1ParticleFlow/plugins/L1BJetProducer.cc b/L1Trigger/Phase2L1ParticleFlow/plugins/L1BJetProducer.cc index 3db89a84a276e..f3a160a36a769 100644 --- a/L1Trigger/Phase2L1ParticleFlow/plugins/L1BJetProducer.cc +++ b/L1Trigger/Phase2L1ParticleFlow/plugins/L1BJetProducer.cc @@ -8,7 +8,7 @@ #include "DataFormats/L1TParticleFlow/interface/PFJet.h" #include "DataFormats/JetReco/interface/Jet.h" #include "DataFormats/L1TParticleFlow/interface/PFCandidate.h" -#include "L1Trigger/Phase2L1ParticleFlow/interface/BJetId.h" +#include "L1Trigger/Phase2L1ParticleFlow/interface/JetId.h" #include "DataFormats/Common/interface/ValueMap.h" #include "DataFormats/L1Trigger/interface/VertexWord.h" @@ -28,7 +28,7 @@ class L1BJetProducer : public edm::stream::EDProducer fBJetId_; + std::unique_ptr fBJetId_; void produce(edm::Event& iEvent, const edm::EventSetup& iSetup) override; edm::EDGetTokenT> const jets_; @@ -48,7 +48,7 @@ L1BJetProducer::L1BJetProducer(const edm::ParameterSet& cfg, const BJetTFCache* fMaxJets_(cfg.getParameter("maxJets")), fNParticles_(cfg.getParameter("nParticles")), fVtxEmu_(consumes>(cfg.getParameter("vtx"))) { - fBJetId_ = std::make_unique( + fBJetId_ = std::make_unique( cfg.getParameter("NNInput"), cfg.getParameter("NNOutput"), cache, fNParticles_); produces>("L1PFBJets"); } diff --git a/L1Trigger/Phase2L1ParticleFlow/plugins/TOoLLiPProducer.cc b/L1Trigger/Phase2L1ParticleFlow/plugins/TOoLLiPProducer.cc new file mode 100644 index 0000000000000..e33ff7040865a --- /dev/null +++ b/L1Trigger/Phase2L1ParticleFlow/plugins/TOoLLiPProducer.cc @@ -0,0 +1,112 @@ +#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/JetId.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 TOoLLiPProducer : public edm::stream::EDProducer<> { +public: + explicit TOoLLiPProducer(const edm::ParameterSet&); + ~TOoLLiPProducer() 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_; + bool const fUseRawPt_; + double const fMinPt_; + double const fMaxEta_; + unsigned int const fMaxJets_; + int const fNParticles_; + edm::EDGetTokenT> const fVtxEmu_; + + hls4mlEmulator::ModelLoader loader; + std::shared_ptr model; +}; + +TOoLLiPProducer::TOoLLiPProducer(const edm::ParameterSet& cfg) + : jets_(consumes>(cfg.getParameter("jets"))), + fUseRawPt_(cfg.getParameter("useRawPt")), + fMinPt_(cfg.getParameter("minPt")), + fMaxEta_(cfg.getParameter("maxEta")), + fMaxJets_(cfg.getParameter("maxJets")), + fNParticles_(cfg.getParameter("nParticles")), + fVtxEmu_(consumes>(cfg.getParameter("vtx"))), + loader(hls4mlEmulator::ModelLoader(cfg.getParameter("TOoLLiPVersion"))) { + model = loader.load_model(); + fJetId_ = std::make_unique( + cfg.getParameter("NNInput"), cfg.getParameter("NNOutput"), model, fNParticles_); + produces>("L1PFLLPJets"); +} + +void TOoLLiPProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + edm::Handle> jets; + iEvent.getByToken(jets_, jets); + float vz = 0.; + double ptsum = 0; + edm::Handle> vtxEmuHandle; + iEvent.getByToken(fVtxEmu_, vtxEmuHandle); + for (const auto& vtx : *vtxEmuHandle) { + if (ptsum == 0 || vtx.pt() > ptsum) { + ptsum = vtx.pt(); + vz = vtx.z0(); + } + } + + std::vector LLPScores; + for (const auto& srcjet : *jets) { + if (((fUseRawPt_ ? srcjet.rawPt() : srcjet.pt()) < fMinPt_) || std::abs(srcjet.eta()) > fMaxEta_ || + LLPScores.size() >= fMaxJets_) { + LLPScores.push_back(-1.); + continue; + } + ap_fixed<16, 6> LLPScore = fJetId_->computeFixed(srcjet, vz, fUseRawPt_); + LLPScores.push_back(LLPScore); + } + + auto outT = std::make_unique>(); + edm::ValueMap::Filler fillerT(*outT); + fillerT.insert(jets, LLPScores.begin(), LLPScores.end()); + fillerT.fill(); + + iEvent.put(std::move(outT), "L1PFLLPJets"); +} + +void TOoLLiPProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + desc.add("jets", edm::InputTag("scPFL1Puppi")); + desc.add("useRawPt", true); + desc.add("TOoLLiPVersion", std::string("TOoLLiP_v1")); + desc.add("NNInput", "input:0"); + desc.add("NNOutput", "sequential/dense_2/Sigmoid"); + desc.add("maxJets", 10); + desc.add("nParticles", 10); + desc.add("minPt", 20); + desc.add("maxEta", 2.4); + desc.add("vtx", edm::InputTag("L1VertexFinderEmulator", "L1VerticesEmulation")); + descriptions.add("TOoLLiPProducer", desc); +} + +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(TOoLLiPProducer); diff --git a/L1Trigger/Phase2L1ParticleFlow/python/TOoLLiPProducer_cff.py b/L1Trigger/Phase2L1ParticleFlow/python/TOoLLiPProducer_cff.py new file mode 100644 index 0000000000000..9eb1c774a8243 --- /dev/null +++ b/L1Trigger/Phase2L1ParticleFlow/python/TOoLLiPProducer_cff.py @@ -0,0 +1,20 @@ +import FWCore.ParameterSet.Config as cms + +from L1Trigger.Phase2L1ParticleFlow.l1pfJetMet_cff import L1TPFJetsExtendedTask + +from L1Trigger.Phase2L1ParticleFlow.TOoLLiPProducer_cfi import TOoLLiPProducer +l1tTOoLLiPProducer = TOoLLiPProducer.clone( + jets = ("l1tSC4PFL1PuppiExtended", ""), + maxJets = 6, + minPt = 10, + vtx = ("l1tVertexFinderEmulator","L1VerticesEmulation") +) + + +l1tTOoLLiPProducerCorrectedEmulator = l1tTOoLLiPProducer.clone( + jets = ("l1tSC4PFL1PuppiExtendedCorrectedEmulator", "") +) + +L1TTOoLLiPTask = cms.Task( + L1TPFJetsExtendedTask, l1tTOoLLiPProducer, l1tTOoLLiPProducerCorrectedEmulator +) diff --git a/L1Trigger/Phase2L1ParticleFlow/src/BJetId.cc b/L1Trigger/Phase2L1ParticleFlow/src/JetId.cc similarity index 58% rename from L1Trigger/Phase2L1ParticleFlow/src/BJetId.cc rename to L1Trigger/Phase2L1ParticleFlow/src/JetId.cc index eaf8087bf85e6..3692ad912c6d0 100644 --- a/L1Trigger/Phase2L1ParticleFlow/src/BJetId.cc +++ b/L1Trigger/Phase2L1ParticleFlow/src/JetId.cc @@ -1,8 +1,29 @@ -#include "L1Trigger/Phase2L1ParticleFlow/interface/BJetId.h" +#include "L1Trigger/Phase2L1ParticleFlow/interface/JetId.h" #include "DataFormats/Math/interface/deltaPhi.h" #include -BJetId::BJetId(const std::string &iInput, const std::string &iOutput, const BJetTFCache *cache, int iNParticles) +JetId::JetId(const std::string &iInput, + const std::string &iOutput, + const std::shared_ptr model, + int iNParticles) + : modelRef_(model) { + NNvectorVar_.clear(); + fNParticles_ = iNParticles; + + fPt_ = std::make_unique(fNParticles_); + fEta_ = std::make_unique(fNParticles_); + fPhi_ = std::make_unique(fNParticles_); + fId_ = std::make_unique(fNParticles_); + fCharge_ = std::make_unique(fNParticles_); + fDZ_ = std::make_unique(fNParticles_); + fDX_ = std::make_unique(fNParticles_); + fDY_ = std::make_unique(fNParticles_); + fInput_ = iInput; + fOutput_ = iOutput; +} + +//--BJet algo specific constructor +JetId::JetId(const std::string &iInput, const std::string &iOutput, const BJetTFCache *cache, int iNParticles) : sessionRef_(cache->session) { NNvectorVar_.clear(); fNParticles_ = iNParticles; @@ -19,8 +40,7 @@ BJetId::BJetId(const std::string &iInput, const std::string &iOutput, const BJet fOutput_ = iOutput; } -BJetId::~BJetId() {} -void BJetId::setNNVectorVar() { +void JetId::setNNVectorVar() { NNvectorVar_.clear(); for (int i0 = 0; i0 < fNParticles_; i0++) { if (fPt_.get()[i0] == 0) { @@ -43,7 +63,7 @@ void BJetId::setNNVectorVar() { NNvectorVar_.push_back(fPhi_.get()[i0]); //dPhi from jet axis } } -float BJetId::EvaluateNN() { +float JetId::EvaluateNN() { tensorflow::Tensor input(tensorflow::DT_FLOAT, {1, (unsigned int)NNvectorVar_.size(), 1}); for (unsigned int i = 0; i < NNvectorVar_.size(); i++) { input.tensor()(0, i, 0) = float(NNvectorVar_[i]); @@ -53,7 +73,21 @@ float BJetId::EvaluateNN() { return outputs[0].matrix()(0, 0); } //end EvaluateNN -float BJetId::compute(const l1t::PFJet &iJet, float vz, bool useRawPt) { +ap_fixed<16, 6> JetId::EvaluateNNFixed() { + ap_fixed<16, 6> modelInput[140] = {}; + for (unsigned int i = 0; i < NNvectorVar_.size(); i++) { + modelInput[i] = NNvectorVar_[i]; + } + ap_fixed<16, 6> modelResult[1] = {-1}; + + modelRef_->prepare_input(modelInput); + modelRef_->predict(); + modelRef_->read_result(modelResult); + ap_fixed<16, 6> modelResult_ = modelResult[0]; + return modelResult_; +} //end EvaluateNNFixed + +float JetId::compute(const l1t::PFJet &iJet, float vz, bool useRawPt) { for (int i0 = 0; i0 < fNParticles_; i0++) { fPt_.get()[i0] = 0; fEta_.get()[i0] = 0; @@ -86,3 +120,37 @@ float BJetId::compute(const l1t::PFJet &iJet, float vz, bool useRawPt) { setNNVectorVar(); return EvaluateNN(); } + +ap_fixed<16, 6> JetId::computeFixed(const l1t::PFJet &iJet, float vz, bool useRawPt) { + for (int i0 = 0; i0 < fNParticles_; i0++) { + fPt_.get()[i0] = 0; + fEta_.get()[i0] = 0; + fPhi_.get()[i0] = 0; + fId_.get()[i0] = 0; + fCharge_.get()[i0] = 0; + fDZ_.get()[i0] = 0; + fDX_.get()[i0] = 0; + fDY_.get()[i0] = 0; + } + auto iParts = iJet.constituents(); + std::sort(iParts.begin(), iParts.end(), [](edm::Ptr i, edm::Ptr j) { + return (i->pt() > j->pt()); + }); + float jetpt = useRawPt ? iJet.rawPt() : iJet.pt(); + for (unsigned int i0 = 0; i0 < iParts.size(); i0++) { + if (i0 >= (unsigned int)fNParticles_) + break; + fPt_.get()[i0] = iParts[i0]->pt() / jetpt; + fEta_.get()[i0] = iParts[i0]->eta() - iJet.eta(); + fPhi_.get()[i0] = deltaPhi(iParts[i0]->phi(), iJet.phi()); + fId_.get()[i0] = iParts[i0]->id(); + fCharge_.get()[i0] = iParts[i0]->charge(); + if (iParts[i0]->pfTrack().isNonnull()) { + fDX_.get()[i0] = iParts[i0]->pfTrack()->vx(); + fDY_.get()[i0] = iParts[i0]->pfTrack()->vy(); + fDZ_.get()[i0] = iParts[i0]->pfTrack()->vz() - vz; + } + } + setNNVectorVar(); + return EvaluateNNFixed(); +}