diff --git a/DataFormats/L1TParticleFlow/interface/layer1_emulator.h b/DataFormats/L1TParticleFlow/interface/layer1_emulator.h index 0fcaa3580f7af..a257ed2efbda6 100644 --- a/DataFormats/L1TParticleFlow/interface/layer1_emulator.h +++ b/DataFormats/L1TParticleFlow/interface/layer1_emulator.h @@ -175,18 +175,20 @@ namespace l1ct { hwIsoVars[1] = 0; hwIsoVars[2] = 0; hwIsoVars[3] = 0; + hwIsoVars[4] = 0; + hwIsoVars[5] = 0; } using EGIsoObj::floatIso; - enum IsoType { TkIso = 0, PfIso = 1, TkIsoPV = 2, PfIsoPV = 3 }; + enum IsoType { TkIso = 0, PfIso = 1, TkIsoPV = 2, PfIsoPV = 3, PuppiIso = 4, PuppiIsoPV = 5 }; float floatIso(IsoType type) const { return Scales::floatIso(hwIsoVars[type]); } float floatRelIso(IsoType type) const { return Scales::floatIso(hwIsoVars[type]) / floatPt(); } float hwIsoVar(IsoType type) const { return hwIsoVars[type]; } void setHwIso(IsoType type, iso_t value) { hwIsoVars[type] = value; } - iso_t hwIsoVars[4]; + iso_t hwIsoVars[6]; }; struct EGIsoEleObjEmu : public EGIsoEleObj { @@ -207,18 +209,19 @@ namespace l1ct { void clearIsoVars() { hwIsoVars[0] = 0; hwIsoVars[1] = 0; + hwIsoVars[2] = 0; } using EGIsoEleObj::floatIso; - enum IsoType { TkIso = 0, PfIso = 1 }; + enum IsoType { TkIso = 0, PfIso = 1, PuppiIso = 2 }; float floatIso(IsoType type) const { return Scales::floatIso(hwIsoVars[type]); } float floatRelIso(IsoType type) const { return Scales::floatIso(hwIsoVars[type]) / floatPt(); } float hwIsoVar(IsoType type) const { return hwIsoVars[type]; } void setHwIso(IsoType type, iso_t value) { hwIsoVars[type] = value; } - iso_t hwIsoVars[2]; + iso_t hwIsoVars[3]; }; struct PVObjEmu : public PVObj { diff --git a/L1Trigger/Phase2L1ParticleFlow/interface/egamma/L1EGPuppiIsoAlgo.h b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/L1EGPuppiIsoAlgo.h new file mode 100644 index 0000000000000..a7a87bba35262 --- /dev/null +++ b/L1Trigger/Phase2L1ParticleFlow/interface/egamma/L1EGPuppiIsoAlgo.h @@ -0,0 +1,63 @@ +#ifndef L1Trigger_Phase2L1ParticleFlow_L1EGPuppiIsoAlgo_h +#define L1Trigger_Phase2L1ParticleFlow_L1EGPuppiIsoAlgo_h + +#include +#include +#include +#include + +#include "DataFormats/Math/interface/deltaR.h" +#include "DataFormats/L1TParticleFlow/interface/datatypes.h" +#include "DataFormats/L1TParticleFlow/interface/layer1_emulator.h" +#include "DataFormats/L1TParticleFlow/interface/egamma.h" +#include "DataFormats/L1TParticleFlow/interface/puppi.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +namespace l1ct { + + struct L1EGPuppiIsoAlgoConfig { + enum { kPFIso, kPuppiIso }; + + int pfIsoType_; + pt_t ptMin_; + ap_int dZMax_; + int dRMin2_; + int dRMax2_; + bool pfCandReuse_; + + L1EGPuppiIsoAlgoConfig(const std::string& pfIsoTypeStr, + const float ptMin, + const float dZMax, + const float dRMin, + const float dRMax, + const bool pfCandReuse) + : pfIsoType_(pfIsoTypeStr == "PF" ? kPFIso : kPuppiIso), + ptMin_(Scales::makePtFromFloat(ptMin)), + dZMax_(Scales::makeZ0(dZMax)), + dRMin2_(Scales::makeDR2FromFloatDR(dRMin)), + dRMax2_(Scales::makeDR2FromFloatDR(dRMax)), + pfCandReuse_(pfCandReuse) {} + }; + + typedef std::vector EGIsoObjsEmu; + typedef std::vector EGIsoEleObjsEmu; + typedef std::vector PuppiObjs; + + class L1EGPuppiIsoAlgo { + public: + L1EGPuppiIsoAlgo(const L1EGPuppiIsoAlgoConfig& config) : config_(config) {} + L1EGPuppiIsoAlgo(const edm::ParameterSet& pSet); + virtual ~L1EGPuppiIsoAlgo() = default; + + void run(const EGIsoObjsEmu& l1EGs, const PuppiObjs& l1PFCands, EGIsoObjsEmu& outL1EGs, z0_t z0 = 0) const; + void run(EGIsoObjsEmu& l1EGs, const PuppiObjs& l1PFCands, z0_t z0 = 0) const; + void run(EGIsoEleObjsEmu& l1Eles, const PuppiObjs& l1PFCands) const; + + private: + iso_t calcIso(const EGIsoObj& l1EG, std::list& workPFCands, z0_t z0 = 0) const; + + const L1EGPuppiIsoAlgoConfig config_; + }; + +} // namespace l1ct +#endif diff --git a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc index 75265d23765a0..99b0251eff85b 100644 --- a/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc +++ b/L1Trigger/Phase2L1ParticleFlow/plugins/L1TCtL2EgProducer.cc @@ -3,6 +3,7 @@ #include "DataFormats/L1TCorrelator/interface/TkEm.h" #include "DataFormats/L1TCorrelator/interface/TkEmFwd.h" #include "DataFormats/L1Trigger/interface/EGamma.h" +#include "DataFormats/L1TParticleFlow/interface/PFCandidate.h" #include "FWCore/Framework/interface/Event.h" #include "FWCore/Framework/interface/global/EDProducer.h" @@ -12,9 +13,8 @@ #include "DataFormats/L1TParticleFlow/interface/layer1_emulator.h" #include "L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2egsorter_ref.h" -//#include "L1Trigger/Phase2L1ParticleFlow/src/newfirmware/egamma/l2egsorter_ref.cpp" #include "L1Trigger/Phase2L1ParticleFlow/interface/egamma/l2egencoder_ref.h" -//#include "L1Trigger/Phase2L1ParticleFlow/src/newfirmware/egamma/l2egencoder_ref.cpp" +#include "L1Trigger/Phase2L1ParticleFlow/interface/egamma/L1EGPuppiIsoAlgo.h" #include "L1Trigger/DemonstratorTools/interface/BoardDataWriter.h" #include "L1Trigger/DemonstratorTools/interface/utilities.h" @@ -54,6 +54,7 @@ class L1TCtL2EgProducer : public edm::global::EDProducer<> { void convertToEmu(const l1t::TkElectron &tkele, RefRemapper &refRemapper, l1ct::OutputBoard &boarOut) const; void convertToEmu(const l1t::TkEm &tkele, RefRemapper &refRemapper, l1ct::OutputBoard &boarOut) const; + void convertToPuppi(const l1t::PFCandidateCollection &l1PFCands, l1ct::PuppiObjs &puppiObjs) const; template class PFInstanceInputs { @@ -194,6 +195,9 @@ class L1TCtL2EgProducer : public edm::global::EDProducer<> { std::string tkEleInstanceLabel_; l1ct::L2EgSorterEmulator l2egsorter; l1ct::L2EgEncoderEmulator l2encoder; + edm::EDGetTokenT> pfObjsToken_; + l1ct::L1EGPuppiIsoAlgo l2EgPuppiIsoAlgo_; + l1ct::L1EGPuppiIsoAlgo l2ElePuppiIsoAlgo_; bool doInPtrn_; bool doOutPtrn_; std::unique_ptr inPtrnWrt_; @@ -209,6 +213,9 @@ L1TCtL2EgProducer::L1TCtL2EgProducer(const edm::ParameterSet &conf) tkEleInstanceLabel_(conf.getParameter("tkEleInstanceLabel")), l2egsorter(conf.getParameter("sorter")), l2encoder(conf.getParameter("encoder")), + pfObjsToken_(consumes>(conf.getParameter("l1PFObjects"))), + l2EgPuppiIsoAlgo_(conf.getParameter("puppiIsoParametersTkEm")), + l2ElePuppiIsoAlgo_(conf.getParameter("puppiIsoParametersTkEle")), doInPtrn_(conf.getParameter("writeInPattern")), doOutPtrn_(conf.getParameter("writeOutPattern")), inPtrnWrt_(nullptr), @@ -300,6 +307,13 @@ void L1TCtL2EgProducer::produce(edm::StreamID, edm::Event &iEvent, const edm::Ev std::vector out_eles_emu; l2egsorter.run(*boards, out_photons_emu, out_eles_emu); + // PUPPI isolation + auto &pfObjs = iEvent.get(pfObjsToken_); + l1ct::PuppiObjs puppiObjs; + convertToPuppi(pfObjs, puppiObjs); + l2EgPuppiIsoAlgo_.run(out_photons_emu, puppiObjs); + l2ElePuppiIsoAlgo_.run(out_eles_emu, puppiObjs); + if (doOutPtrn_) { l1t::demo::EventData outData; outData.add({"eglayer2", 0}, l2encoder.encodeLayer2EgObjs(out_photons_emu, out_eles_emu)); @@ -335,6 +349,7 @@ void L1TCtL2EgProducer::convertToEmu(const l1t::TkElectron &tkele, // NOTE: The emulator and FW data-format stores absolute iso while the CMSSW object stores relative iso emu.setHwIso(EGIsoEleObjEmu::IsoType::TkIso, l1ct::Scales::makeIso(tkele.trkIsol() * tkele.pt())); emu.setHwIso(EGIsoEleObjEmu::IsoType::PfIso, l1ct::Scales::makeIso(tkele.pfIsol() * tkele.pt())); + emu.setHwIso(EGIsoEleObjEmu::IsoType::PuppiIso, l1ct::Scales::makeIso(tkele.puppiIsol() * tkele.pt())); // std::cout << "[convertToEmu] TkEle pt: " << emu.hwPt << " eta: " << emu.hwEta << " phi: " << emu.hwPhi << " staidx: " << emu.sta_idx << std::endl; boarOut.egelectron.push_back(emu); @@ -356,12 +371,21 @@ void L1TCtL2EgProducer::convertToEmu(const l1t::TkEm &tkem, // NOTE: The emulator and FW data-format stores absolute iso while the CMSSW object stores relative iso emu.setHwIso(EGIsoObjEmu::IsoType::TkIso, l1ct::Scales::makeIso(tkem.trkIsol() * tkem.pt())); emu.setHwIso(EGIsoObjEmu::IsoType::PfIso, l1ct::Scales::makeIso(tkem.pfIsol() * tkem.pt())); + emu.setHwIso(EGIsoObjEmu::IsoType::PuppiIso, l1ct::Scales::makeIso(tkem.puppiIsol() * tkem.pt())); emu.setHwIso(EGIsoObjEmu::IsoType::TkIsoPV, l1ct::Scales::makeIso(tkem.trkIsolPV() * tkem.pt())); emu.setHwIso(EGIsoObjEmu::IsoType::PfIsoPV, l1ct::Scales::makeIso(tkem.pfIsolPV() * tkem.pt())); // std::cout << "[convertToEmu] TkEM pt: " << emu.hwPt << " eta: " << emu.hwEta << " phi: " << emu.hwPhi << " staidx: " << emu.sta_idx << std::endl; boarOut.egphoton.push_back(emu); } +void L1TCtL2EgProducer::convertToPuppi(const l1t::PFCandidateCollection &l1PFCands, l1ct::PuppiObjs &puppiObjs) const { + for (const auto &l1PFCand : l1PFCands) { + l1ct::PuppiObj obj; + obj.initFromBits(l1PFCand.encodedPuppi64()); + puppiObjs.emplace_back(obj); + } +} + l1t::TkEm L1TCtL2EgProducer::convertFromEmu(const l1ct::EGIsoObjEmu &egiso, const RefRemapper &refRemapper) const { // std::cout << "[convertFromEmu] TkEm pt: " << egiso.hwPt << " eta: " << egiso.hwEta << " phi: " << egiso.hwPhi << " staidx: " << egiso.sta_idx << std::endl; // NOTE: the TkEM object is created with the accuracy as in GT object (not the Correlator internal one)! @@ -376,6 +400,7 @@ l1t::TkEm L1TCtL2EgProducer::convertFromEmu(const l1ct::EGIsoObjEmu &egiso, cons tkem.setHwQual(gteg.quality); tkem.setPFIsol(egiso.floatRelIso(l1ct::EGIsoObjEmu::IsoType::PfIso)); tkem.setPFIsolPV(egiso.floatRelIso(l1ct::EGIsoObjEmu::IsoType::PfIsoPV)); + tkem.setPuppiIsol(egiso.floatRelIso(l1ct::EGIsoObjEmu::IsoType::PuppiIso)); tkem.setEgBinaryWord(gteg.pack()); return tkem; } @@ -394,6 +419,7 @@ l1t::TkElectron L1TCtL2EgProducer::convertFromEmu(const l1ct::EGIsoEleObjEmu &eg egele.floatRelIso(l1ct::EGIsoEleObjEmu::IsoType::TkIso)); tkele.setHwQual(gteg.quality); tkele.setPFIsol(egele.floatRelIso(l1ct::EGIsoEleObjEmu::IsoType::PfIso)); + tkele.setPuppiIsol(egele.floatRelIso(l1ct::EGIsoEleObjEmu::IsoType::PuppiIso)); tkele.setEgBinaryWord(gteg.pack()); return tkele; } diff --git a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py index af063d32cce49..80c341d5cc227 100644 --- a/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py +++ b/L1Trigger/Phase2L1ParticleFlow/python/l1ctLayer2EG_cff.py @@ -1,5 +1,7 @@ import FWCore.ParameterSet.Config as cms +from L1Trigger.Phase2L1ParticleFlow.DeregionizerProducer_cfi import DeregionizerProducer as l1ctLayer2Deregionizer + l1ctLayer2EG = cms.EDProducer( "L1TCtL2EgProducer", tkElectrons=cms.VPSet( @@ -36,6 +38,7 @@ channels=cms.vint32(-1) ), ), + l1PFObjects = cms.InputTag("l1ctLayer2Deregionizer", "Puppi"), egStaInstanceLabel=cms.string("L1CtEgEE"), tkEmInstanceLabel=cms.string("L1CtTkEm"), tkEleInstanceLabel=cms.string("L1CtTkElectron"), @@ -49,6 +52,22 @@ nTKELE_OUT=cms.uint32(12), nTKPHO_OUT=cms.uint32(12), ), + puppiIsoParametersTkEm = cms.PSet( + pfIsoType = cms.string("PUPPI"), + pfPtMin = cms.double(1.), + dZ = cms.double(0.6), + dRMin = cms.double(0.07), + dRMax = cms.double(0.3), + pfCandReuse = cms.bool(True) + ), + puppiIsoParametersTkEle = cms.PSet( + pfIsoType = cms.string("PUPPI"), + pfPtMin = cms.double(1.), + dZ = cms.double(0.6), + dRMin = cms.double(0.03), + dRMax = cms.double(0.2), + pfCandReuse = cms.bool(True) + ), writeInPattern=cms.bool(False), writeOutPattern=cms.bool(False), inPatternFile=cms.PSet( @@ -133,5 +152,6 @@ l1ctLayer2EGTask = cms.Task( + l1ctLayer2Deregionizer, l1ctLayer2EG ) diff --git a/L1Trigger/Phase2L1ParticleFlow/src/egamma/L1EGPuppiIsoAlgo.cc b/L1Trigger/Phase2L1ParticleFlow/src/egamma/L1EGPuppiIsoAlgo.cc new file mode 100644 index 0000000000000..4d77d7866c0c0 --- /dev/null +++ b/L1Trigger/Phase2L1ParticleFlow/src/egamma/L1EGPuppiIsoAlgo.cc @@ -0,0 +1,132 @@ +#include "L1Trigger/Phase2L1ParticleFlow/interface/egamma/L1EGPuppiIsoAlgo.h" + +using namespace l1ct; + +L1EGPuppiIsoAlgo::L1EGPuppiIsoAlgo(const edm::ParameterSet& pSet) + : config_(pSet.getParameter("pfIsoType"), + pSet.getParameter("pfPtMin"), + pSet.getParameter("dZ"), + pSet.getParameter("dRMin"), + pSet.getParameter("dRMax"), + pSet.getParameter("pfCandReuse")) {} + +void L1EGPuppiIsoAlgo::run(const EGIsoObjsEmu& l1EGs, + const PuppiObjs& l1PFCands, + EGIsoObjsEmu& outL1EGs, + z0_t z0) const { + outL1EGs.reserve(l1EGs.size()); + + // make a list of pointers to PF candidates + // the pointer will be removed from the list once the candidate has been used and the the module is configured to to so + std::list workPFCands; + std::list workPFCandsPV; + for (const auto& l1PFCand : l1PFCands) { + workPFCands.emplace_back(&l1PFCand); + workPFCandsPV.emplace_back(&l1PFCand); + } + + for (const auto& l1EG : l1EGs) { + auto outL1EG(l1EG); + iso_t iso = 0; + iso_t isoPV = 0; + if (!workPFCands.empty()) { + iso = calcIso(l1EG, workPFCands); + isoPV = calcIso(l1EG, workPFCandsPV, z0); + } + + if (config_.pfIsoType_ == L1EGPuppiIsoAlgoConfig::kPFIso) { + outL1EG.setHwIso(EGIsoObjEmu::IsoType::PfIso, iso); + outL1EG.setHwIso(EGIsoObjEmu::IsoType::PfIsoPV, isoPV); + } else { + outL1EG.setHwIso(EGIsoObjEmu::IsoType::PuppiIso, iso); + outL1EG.setHwIso(EGIsoObjEmu::IsoType::PuppiIsoPV, isoPV); + } + outL1EGs.emplace_back(outL1EG); + } +} + +void L1EGPuppiIsoAlgo::run(EGIsoObjsEmu& l1EGs, const PuppiObjs& l1PFCands, z0_t z0) const { + // make a list of pointers to PF candidates + // the pointer will be removed from the list once the candidate has been used and the the module is configured to to so + std::list workPFCands; + std::list workPFCandsPV; + for (const auto& l1PFCand : l1PFCands) { + workPFCands.emplace_back(&l1PFCand); + workPFCandsPV.emplace_back(&l1PFCand); + } + + for (auto& l1EG : l1EGs) { + iso_t iso = 0; + iso_t isoPV = 0; + if (!workPFCands.empty()) { + iso = calcIso(l1EG, workPFCands); + isoPV = calcIso(l1EG, workPFCandsPV, z0); + } + + if (config_.pfIsoType_ == L1EGPuppiIsoAlgoConfig::kPFIso) { + l1EG.setHwIso(EGIsoObjEmu::IsoType::PfIso, iso); + l1EG.setHwIso(EGIsoObjEmu::IsoType::PfIsoPV, isoPV); + } else { + l1EG.setHwIso(EGIsoObjEmu::IsoType::PuppiIso, iso); + l1EG.setHwIso(EGIsoObjEmu::IsoType::PuppiIsoPV, isoPV); + } + } +} + +void L1EGPuppiIsoAlgo::run(EGIsoEleObjsEmu& l1Eles, const PuppiObjs& l1PFCands) const { + // make a list of pointers to PF candidates + // the pointer will be removed from the list once the candidate has been used and the the module is configured to to so + std::list workPFCands; + for (const auto& l1PFCand : l1PFCands) { + workPFCands.emplace_back(&l1PFCand); + } + + for (auto& l1Ele : l1Eles) { + iso_t iso = 0; + if (!workPFCands.empty()) { + iso = calcIso(l1Ele, workPFCands); + } + + if (config_.pfIsoType_ == L1EGPuppiIsoAlgoConfig::kPFIso) { + l1Ele.setHwIso(EGIsoEleObjEmu::IsoType::PfIso, iso); + } else { + l1Ele.setHwIso(EGIsoEleObjEmu::IsoType::PuppiIso, iso); + } + } +} + +iso_t L1EGPuppiIsoAlgo::calcIso(const EGIsoObj& l1EG, std::list& workPFCands, z0_t z0) const { + iso_t sumPt = 0; + + auto pfIt = workPFCands.cbegin(); + while (pfIt != workPFCands.cend()) { + // use the PF candidate pT if it is within the cone and optional dz cut for charged PF candidates + const auto workPFCand = *pfIt; + z0_t pfCandZ0 = 0; + if (workPFCand->hwId.charged()) { + pfCandZ0 = workPFCand->hwZ0(); + } + + // calculate dz + ap_int dz = z0 - pfCandZ0; + if (dz < 0) { + dz = -dz; + } + + if (workPFCand->intCharge() == 0 || (workPFCand->intCharge() != 0 && dz < config_.dZMax_)) { + const auto dR2 = dr2_int(l1EG.hwEta, l1EG.hwPhi, workPFCand->hwEta, workPFCand->hwPhi); + if (dR2 >= config_.dRMin2_ && dR2 < config_.dRMax2_ && workPFCand->hwPt >= config_.ptMin_) { + sumPt += workPFCand->hwPt; + // remove the candidate from the collection if the module is configured to not reuse them + if (!config_.pfCandReuse_) { + // this returns an iterator to the next element already so no need to increase here + pfIt = workPFCands.erase(pfIt); + continue; + } + } + } + ++pfIt; + } + + return sumPt; +}