Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-06-20 01:53:34

0001 // system include files
0002 #include <memory>
0003 #include <algorithm>
0004 #include <fstream>
0005 #include <cstdio>
0006 
0007 // user include files
0008 #include "FWCore/Framework/interface/Frameworkfwd.h"
0009 #include "FWCore/Framework/interface/stream/EDProducer.h"
0010 #include "FWCore/Framework/interface/Event.h"
0011 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0012 #include "FWCore/ParameterSet/interface/FileInPath.h"
0013 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0014 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0015 #include "FWCore/ParameterSet/interface/allowedValues.h"
0016 
0017 #include "DataFormats/Common/interface/RefToPtr.h"
0018 #include "DataFormats/L1TParticleFlow/interface/PFCandidate.h"
0019 #include "DataFormats/L1TParticleFlow/interface/PFCluster.h"
0020 #include "DataFormats/L1Trigger/interface/Vertex.h"
0021 #include "DataFormats/L1Trigger/interface/VertexWord.h"
0022 
0023 #include "DataFormats/Math/interface/deltaR.h"
0024 
0025 #include "L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/tkinput_ref.h"
0026 #include "L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/muonGmtToL1ct_ref.h"
0027 #include "L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/hgcalinput_ref.h"
0028 #include "L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/gcteminput_ref.h"
0029 #include "L1Trigger/Phase2L1ParticleFlow/interface/l1-converters/gcthadinput_ref.h"
0030 #include "L1Trigger/Phase2L1ParticleFlow/interface/regionizer/regionizer_base_ref.h"
0031 #include "L1Trigger/Phase2L1ParticleFlow/interface/regionizer/multififo_regionizer_ref.h"
0032 #include "L1Trigger/Phase2L1ParticleFlow/interface/regionizer/buffered_folded_multififo_regionizer_ref.h"
0033 #include "L1Trigger/Phase2L1ParticleFlow/interface/regionizer/middle_buffer_multififo_regionizer_ref.h"
0034 #include "L1Trigger/Phase2L1ParticleFlow/interface/regionizer/tdr_regionizer_ref.h"
0035 #include "L1Trigger/Phase2L1ParticleFlow/interface/pf/pfalgo2hgc_ref.h"
0036 #include "L1Trigger/Phase2L1ParticleFlow/interface/pf/pfalgo3_ref.h"
0037 #include "L1Trigger/Phase2L1ParticleFlow/interface/pf/pfalgo_dummy_ref.h"
0038 #include "L1Trigger/Phase2L1ParticleFlow/interface/puppi/linpuppi_ref.h"
0039 #include "L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegalgo_ref.h"
0040 #include "L1Trigger/Phase2L1ParticleFlow/interface/pf/pfalgo_common_ref.h"
0041 #include "L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegsorter_ref.h"
0042 #include "L1Trigger/Phase2L1ParticleFlow/interface/egamma/pftkegsorter_barrel_ref.h"
0043 #include "L1Trigger/Phase2L1ParticleFlow/interface/L1TCorrelatorLayer1PatternFileWriter.h"
0044 
0045 #include "DataFormats/L1TCorrelator/interface/TkElectron.h"
0046 #include "DataFormats/L1TCorrelator/interface/TkElectronFwd.h"
0047 #include "DataFormats/L1Trigger/interface/EGamma.h"
0048 #include "DataFormats/L1TCorrelator/interface/TkEm.h"
0049 #include "DataFormats/L1TCorrelator/interface/TkEmFwd.h"
0050 
0051 #include "DataFormats/L1TCalorimeterPhase2/interface/GCTHadDigiCluster.h"
0052 #include "DataFormats/L1TCalorimeterPhase2/interface/GCTEmDigiCluster.h"
0053 // #include "DataFormats/L1TCalorimeterPhase2/interface/CaloCrystalCluster.h"
0054 #include "DataFormats/L1TCalorimeterPhase2/interface/DigitizedClusterCorrelator.h"
0055 #include "DataFormats/L1THGCal/interface/HGCalMulticluster.h"
0056 
0057 constexpr unsigned int calomapping[] = {3, 0, 9, 6, 4, 1, 10, 7, 5, 2, 11, 8};
0058 // regions order:  GCT1 SLR1, GCT1 SLR3, GCT2 SLR1, GCT2 SLR3, GCT3 SLR1, GCT3SLR3
0059 // phi center:         10         70         130        -170       -110       -50
0060 // eta:               + -
0061 
0062 //--------------------------------------------------------------------------------------------------
0063 class L1TCorrelatorLayer1Producer : public edm::stream::EDProducer<> {
0064 public:
0065   explicit L1TCorrelatorLayer1Producer(const edm::ParameterSet &);
0066   ~L1TCorrelatorLayer1Producer() override;
0067 
0068   static void fillDescriptions(edm::ConfigurationDescriptions &descriptions);
0069 
0070 private:
0071   edm::ParameterSet config_;
0072 
0073   bool hasTracks_;
0074   edm::EDGetTokenT<l1t::PFTrackCollection> tkCands_;
0075   float trkPt_;
0076   bool emuTkVtx_;
0077   edm::EDGetTokenT<std::vector<l1t::Vertex>> extTkVtx_;
0078   edm::EDGetTokenT<std::vector<l1t::VertexWord>> tkVtxEmu_;
0079   int nVtx_;
0080 
0081   edm::EDGetTokenT<l1t::SAMuonCollection> muCands_;  // standalone muons
0082 
0083   // For calo, can give either the already converted containers, or the raw containers (for GCT only)
0084   // These are the already converted containers
0085   edm::EDGetTokenT<l1t::PFClusterCollection> hadGCTCands_;
0086   edm::EDGetTokenT<l1t::HGCalMulticlusterBxCollection> hadHGCalCands_;
0087 
0088   // can alternately give the raw containers (for GCT)
0089   edm::EDGetTokenT<l1tp2::GCTEmDigiClusterCollection> emGCTRawCands_;
0090   edm::EDGetTokenT<l1tp2::GCTHadDigiClusterCollection> hadGCTRawCands_;
0091 
0092   float emPtCut_, hadPtCut_;
0093 
0094   l1ct::Event event_;
0095   std::unique_ptr<l1ct::TrackInputEmulator> trackInput_;
0096   std::unique_ptr<l1ct::GMTMuonDecoderEmulator> muonInput_;
0097   std::unique_ptr<l1ct::HgcalClusterDecoderEmulator> hgcalInput_;
0098   std::unique_ptr<l1ct::GctHadClusterDecoderEmulator> gctHadInput_;
0099   std::unique_ptr<l1ct::GctEmClusterDecoderEmulator> gctEmInput_;
0100   std::unique_ptr<l1ct::RegionizerEmulator> regionizer_;
0101   std::unique_ptr<l1ct::PFAlgoEmulatorBase> l1pfalgo_;
0102   std::unique_ptr<l1ct::LinPuppiEmulator> l1pualgo_;
0103   std::unique_ptr<l1ct::PFTkEGAlgoEmulator> l1tkegalgo_;
0104   std::unique_ptr<l1ct::PFTkEGSorterEmulator> l1tkegsorter_;
0105 
0106   // Region dump
0107   const std::string regionDumpName_;
0108   std::fstream fRegionDump_;
0109   const edm::VParameterSet patternWriterConfigs_;
0110   std::vector<std::unique_ptr<L1TCorrelatorLayer1PatternFileWriter>> patternWriters_;
0111 
0112   // region of interest debugging
0113   float debugEta_, debugPhi_, debugR_;
0114 
0115   // these are used to link items back
0116   std::unordered_map<const l1t::L1Candidate *, edm::Ptr<l1t::L1Candidate>> clusterRefMap_;
0117   std::unordered_map<const l1t::PFTrack *, l1t::PFTrackRef> trackRefMap_;
0118   std::unordered_map<const l1t::SAMuon *, l1t::PFCandidate::MuonRef> muonRefMap_;
0119 
0120   // main methods
0121   void beginStream(edm::StreamID) override;
0122   void endStream() override;
0123   void produce(edm::Event &, const edm::EventSetup &) override;
0124   void encodeAndAddHgcalCluster(ap_uint<256> &word,
0125                                 l1ct::DetectorSector<ap_uint<256>> &sec,
0126                                 const l1t::HGCalMulticluster &calo) const;
0127   void getDecodedGCTPFCluster(l1ct::HadCaloObjEmu &calo,
0128                               l1ct::DetectorSector<l1ct::HadCaloObjEmu> &sec,
0129                               const l1t::PFCluster &cluster) const;
0130   void addDecodedEmCalo(l1ct::EmCaloObjEmu &decCalo,
0131                         const edm::Ptr<l1t::L1Candidate> &caloPtr,
0132                         l1ct::DetectorSector<l1ct::EmCaloObjEmu> &sec);
0133   void addEmPFCluster(const l1ct::EmCaloObjEmu &decCalo,
0134                       const l1ct::PFRegionEmu &region,
0135                       std::unique_ptr<l1t::PFClusterCollection> &pfClusters) const;
0136   void addDecodedHadCalo(l1ct::HadCaloObjEmu &decCalo,
0137                          const edm::Ptr<l1t::L1Candidate> &caloPtr,
0138                          l1ct::DetectorSector<l1ct::HadCaloObjEmu> &sec);
0139 
0140   void addHadPFCluster(const l1ct::HadCaloObjEmu &decCalo,
0141                        const l1ct::PFRegionEmu &region,
0142                        std::unique_ptr<l1t::PFClusterCollection> &pfClusters) const;
0143 
0144   void addUInt(unsigned int value, std::string iLabel, edm::Event &iEvent);
0145 
0146   void initSectorsAndRegions(const edm::ParameterSet &iConfig);
0147   void initEvent(const edm::Event &e);
0148   // add object, tracking references
0149   void addTrack(const l1t::PFTrack &t, l1t::PFTrackRef ref);
0150   void addMuon(const l1t::SAMuon &t, l1t::PFCandidate::MuonRef ref);
0151   // HGCAl input clusters
0152   void addHGCalHadCalo(const l1t::HGCalMulticluster &calo, const edm::Ptr<l1t::L1Candidate> &caloPtr);
0153   // GCT input clusters
0154   void addGCTHadCalo(const l1t::PFCluster &calo, const edm::Ptr<l1t::L1Candidate> &caloPtr);
0155   // for GCT raw calos as input
0156   void addGCTEmCaloRaw(const l1tp2::GCTEmDigiClusterLink &link, unsigned int linkidx, unsigned int entidx);
0157   void addGCTHadCaloRaw(const l1tp2::GCTHadDigiClusterLink &link, unsigned int linkidx, unsigned int entidx);
0158   // add objects in already-decoded format
0159   void addDecodedTrack(l1ct::DetectorSector<l1ct::TkObjEmu> &sec, const l1t::PFTrack &t);
0160   void addDecodedMuon(l1ct::DetectorSector<l1ct::MuObjEmu> &sec, const l1t::SAMuon &t);
0161   void addDecodedGCTEmCalo(l1ct::DetectorSector<l1ct::EmCaloObjEmu> &sec, const l1tp2::GCTEmDigiCluster &digi);
0162   void addDecodedGCTHadCalo(l1ct::DetectorSector<l1ct::HadCaloObjEmu> &sec, const l1tp2::GCTHadDigiCluster &digi);
0163 
0164   void rawHgcalClusterEncode(ap_uint<256> &cwrd,
0165                              const l1ct::DetectorSector<ap_uint<256>> &sec,
0166                              const l1t::HGCalMulticluster &c) const;
0167 
0168   // fetching outputs
0169   std::unique_ptr<l1t::PFCandidateCollection> fetchHadCalo() const;
0170   std::unique_ptr<l1t::PFCandidateCollection> fetchEmCalo() const;
0171   std::unique_ptr<l1t::PFCandidateCollection> fetchTracks() const;
0172   std::unique_ptr<l1t::PFCandidateCollection> fetchPF() const;
0173   std::unique_ptr<l1t::PFClusterCollection> fetchDecodedHadCalo() const;
0174   std::unique_ptr<l1t::PFClusterCollection> fetchDecodedEmCalo() const;
0175   std::unique_ptr<l1t::PFTrackCollection> fetchDecodedTracks() const;
0176   void putPuppi(edm::Event &iEvent) const;
0177 
0178   void putEgStaObjects(edm::Event &iEvent, const std::string &egLablel) const;
0179   void putEgObjects(edm::Event &iEvent,
0180                     const bool writeEgSta,
0181                     const std::string &tkEmLabel,
0182                     const std::string &tkEmPerBoardLabel,
0183                     const std::string &tkEleLabel,
0184                     const std::string &tkElePerBoardLabel) const;
0185 
0186   template <typename T>
0187   void setRefs_(l1t::PFCandidate &pf, const T &p) const;
0188   template <typename T>
0189   void setRefs_(l1t::PFCluster &pf, const T &p) const;
0190   template <typename Tm, typename Tk, typename To>
0191   auto findRef_(const Tm &map, const Tk *key, const To &obj) const {
0192     auto match = map.find(key);
0193     if (match == map.end()) {
0194       throw cms::Exception("CorruptData") << refExcepMsg_(obj);
0195     }
0196     return match->second;
0197   }
0198   template <typename T>
0199   std::string refExcepMsg_(const T &key) const;
0200 
0201   void doVertexings(std::vector<float> &pvdz) const;
0202   // for multiplicities
0203   enum InputType { caloType = 0, emcaloType = 1, trackType = 2, l1muType = 3 };
0204   static constexpr const char *inputTypeName[l1muType + 1] = {"Calo", "EmCalo", "TK", "Mu"};
0205   std::unique_ptr<std::vector<unsigned>> vecSecInput(InputType i) const;
0206   std::unique_ptr<std::vector<unsigned>> vecRegInput(InputType i) const;
0207   typedef l1ct::OutputRegion::ObjType OutputType;
0208   std::unique_ptr<std::vector<unsigned>> vecOutput(OutputType i, bool usePuppi) const;
0209   std::pair<unsigned int, unsigned int> totAndMax(const std::vector<unsigned> &perRegion) const;
0210 
0211   // utilities
0212   template <typename T>
0213   static edm::ParameterDescription<edm::ParameterSetDescription> getParDesc(const std::string &name) {
0214     return edm::ParameterDescription<edm::ParameterSetDescription>(
0215         name + "Parameters", T::getParameterSetDescription(), true);
0216   }
0217 };
0218 
0219 //
0220 // constructors and destructor
0221 //
0222 L1TCorrelatorLayer1Producer::L1TCorrelatorLayer1Producer(const edm::ParameterSet &iConfig)
0223     : config_(iConfig),
0224       hasTracks_(!iConfig.getParameter<edm::InputTag>("tracks").label().empty()),
0225       tkCands_(hasTracks_ ? consumes<l1t::PFTrackCollection>(iConfig.getParameter<edm::InputTag>("tracks"))
0226                           : edm::EDGetTokenT<l1t::PFTrackCollection>()),
0227       trkPt_(iConfig.getParameter<double>("trkPtCut")),
0228       muCands_(consumes<l1t::SAMuonCollection>(iConfig.getParameter<edm::InputTag>("muons"))),
0229       emPtCut_(iConfig.getParameter<double>("emPtCut")),
0230       hadPtCut_(iConfig.getParameter<double>("hadPtCut")),
0231       regionizer_(nullptr),
0232       l1pfalgo_(nullptr),
0233       l1pualgo_(nullptr),
0234       l1tkegalgo_(nullptr),
0235       l1tkegsorter_(nullptr),
0236       regionDumpName_(iConfig.getUntrackedParameter<std::string>("dumpFileName")),
0237       patternWriterConfigs_(iConfig.getUntrackedParameter<edm::VParameterSet>("patternWriters")),
0238       debugEta_(iConfig.getUntrackedParameter<double>("debugEta")),
0239       debugPhi_(iConfig.getUntrackedParameter<double>("debugPhi")),
0240       debugR_(iConfig.getUntrackedParameter<double>("debugR")) {
0241   produces<l1t::PFCandidateCollection>("PF");
0242   produces<l1t::PFCandidateCollection>("Puppi");
0243   produces<l1t::PFCandidateRegionalOutput>("PuppiRegional");
0244 
0245   produces<l1t::PFCandidateCollection>("EmCalo");
0246   produces<l1t::PFCandidateCollection>("Calo");
0247   produces<l1t::PFCandidateCollection>("TK");
0248 #if 0  // LATER
0249   produces<l1t::PFCandidateCollection>("TKVtx");
0250 #endif
0251   produces<l1t::PFTrackCollection>("DecodedTK");
0252   produces<l1t::PFClusterCollection>("DecodedEmClusters");
0253   produces<l1t::PFClusterCollection>("DecodedHadClusters");
0254 
0255   if (hasTracks_) {
0256     const std::string &tkInAlgo = iConfig.getParameter<std::string>("trackInputConversionAlgo");
0257     if (tkInAlgo == "Emulator") {
0258       trackInput_ = std::make_unique<l1ct::TrackInputEmulator>(
0259           iConfig.getParameter<edm::ParameterSet>("trackInputConversionParameters"));
0260     } else if (tkInAlgo != "Ideal")
0261       throw cms::Exception("Configuration", "Unsupported trackInputConversionAlgo");
0262   }
0263 
0264   const std::string &muInAlgo = iConfig.getParameter<std::string>("muonInputConversionAlgo");
0265   if (muInAlgo == "Emulator") {
0266     muonInput_ = std::make_unique<l1ct::GMTMuonDecoderEmulator>(
0267         iConfig.getParameter<edm::ParameterSet>("muonInputConversionParameters"));
0268   } else if (muInAlgo != "Ideal")
0269     throw cms::Exception("Configuration", "Unsupported muonInputConversionAlgo");
0270 
0271   const std::string &hgcalInAlgo = iConfig.getParameter<std::string>("hgcalInputConversionAlgo");
0272   const edm::InputTag hadClusters = iConfig.getParameter<edm::InputTag>("hadClusters");
0273   if (!hadClusters.label().empty()) {
0274     if (hgcalInAlgo == "Emulator") {
0275       hadHGCalCands_ = consumes<l1t::HGCalMulticlusterBxCollection>(hadClusters);
0276       hgcalInput_ = std::make_unique<l1ct::HgcalClusterDecoderEmulator>(
0277           iConfig.getParameter<edm::ParameterSet>("hgcalInputConversionParameters"));
0278     } else if (hgcalInAlgo != "None")
0279       throw cms::Exception("Configuration", "Unsupported hgcalInputConversionAlgo");
0280   }
0281   const std::string &gctEmInAlgo = iConfig.getParameter<std::string>("gctEmInputConversionAlgo");
0282   const edm::InputTag emClusters = iConfig.getParameter<edm::InputTag>("emClusters");
0283   if (!emClusters.label().empty()) {
0284     if (gctEmInAlgo == "Emulator") {
0285       gctEmInput_ = std::make_unique<l1ct::GctEmClusterDecoderEmulator>(
0286           iConfig.getParameter<edm::ParameterSet>("gctEmInputConversionParameters"));
0287       emGCTRawCands_ = consumes<l1tp2::GCTEmDigiClusterCollection>(emClusters);
0288     } else if (gctEmInAlgo != "None")
0289       throw cms::Exception("Configuration", "Unsupported gctEmInputConversionAlgo");
0290   }
0291   const std::string &gctHadInAlgo = iConfig.getParameter<std::string>("gctHadInputConversionAlgo");
0292   if (!hadClusters.label().empty()) {
0293     if (gctHadInAlgo == "Emulator") {
0294       gctHadInput_ = std::make_unique<l1ct::GctHadClusterDecoderEmulator>(
0295           iConfig.getParameter<edm::ParameterSet>("gctHadInputConversionParameters"));
0296       hadGCTRawCands_ = consumes<l1tp2::GCTHadDigiClusterCollection>(hadClusters);
0297     } else if (gctHadInAlgo == "Ideal") {
0298       hadGCTCands_ = consumes<l1t::PFClusterCollection>(hadClusters);
0299     } else if (gctHadInAlgo != "None")
0300       throw cms::Exception("Configuration", "Unsupported gctHadInputConversionAlgo");
0301   }
0302 
0303   const std::string &regalgo = iConfig.getParameter<std::string>("regionizerAlgo");
0304   if (regalgo == "Ideal") {
0305     regionizer_ =
0306         std::make_unique<l1ct::RegionizerEmulator>(iConfig.getParameter<edm::ParameterSet>("regionizerAlgoParameters"));
0307   } else if (regalgo == "Multififo") {
0308     regionizer_ = std::make_unique<l1ct::MultififoRegionizerEmulator>(
0309         iConfig.getParameter<edm::ParameterSet>("regionizerAlgoParameters"));
0310   } else if (regalgo == "BufferedFoldedMultififo") {
0311     regionizer_ = std::make_unique<l1ct::BufferedFoldedMultififoRegionizerEmulator>(
0312         iConfig.getParameter<edm::ParameterSet>("regionizerAlgoParameters"));
0313   } else if (regalgo == "MultififoBarrel") {
0314     const auto &pset = iConfig.getParameter<edm::ParameterSet>("regionizerAlgoParameters");
0315     regionizer_ =
0316         std::make_unique<l1ct::MultififoRegionizerEmulator>(pset.getParameter<std::string>("barrelSetup"), pset);
0317   } else if (regalgo == "MiddleBufferMultififo") {
0318     regionizer_ = std::make_unique<l1ct::MiddleBufferMultififoRegionizerEmulator>(
0319         iConfig.getParameter<edm::ParameterSet>("regionizerAlgoParameters"));
0320   } else if (regalgo == "TDR") {
0321     regionizer_ = std::make_unique<l1ct::TDRRegionizerEmulator>(
0322         iConfig.getParameter<edm::ParameterSet>("regionizerAlgoParameters"));
0323   } else
0324     throw cms::Exception("Configuration", "Unsupported regionizerAlgo");
0325 
0326   const std::string &algo = iConfig.getParameter<std::string>("pfAlgo");
0327   if (algo == "PFAlgo3") {
0328     l1pfalgo_ = std::make_unique<l1ct::PFAlgo3Emulator>(iConfig.getParameter<edm::ParameterSet>("pfAlgoParameters"));
0329   } else if (algo == "PFAlgo2HGC") {
0330     l1pfalgo_ = std::make_unique<l1ct::PFAlgo2HGCEmulator>(iConfig.getParameter<edm::ParameterSet>("pfAlgoParameters"));
0331   } else if (algo == "PFAlgoDummy") {
0332     l1pfalgo_ =
0333         std::make_unique<l1ct::PFAlgoDummyEmulator>(iConfig.getParameter<edm::ParameterSet>("pfAlgoParameters"));
0334   } else
0335     throw cms::Exception("Configuration", "Unsupported pfAlgo");
0336 
0337   const std::string &pualgo = iConfig.getParameter<std::string>("puAlgo");
0338   if (pualgo == "LinearizedPuppi") {
0339     l1pualgo_ = std::make_unique<l1ct::LinPuppiEmulator>(iConfig.getParameter<edm::ParameterSet>("puAlgoParameters"));
0340   } else
0341     throw cms::Exception("Configuration", "Unsupported puAlgo");
0342 
0343   l1tkegalgo_ = std::make_unique<l1ct::PFTkEGAlgoEmulator>(
0344       l1ct::PFTkEGAlgoEmuConfig(iConfig.getParameter<edm::ParameterSet>("tkEgAlgoParameters")));
0345 
0346   const std::string &egsortalgo = iConfig.getParameter<std::string>("tkEgSorterAlgo");
0347   if (egsortalgo == "Barrel") {
0348     l1tkegsorter_ = std::make_unique<l1ct::PFTkEGSorterBarrelEmulator>(
0349         iConfig.getParameter<edm::ParameterSet>("tkEgSorterParameters"));
0350   } else if (egsortalgo == "Endcap") {
0351     l1tkegsorter_ =
0352         std::make_unique<l1ct::PFTkEGSorterEmulator>(iConfig.getParameter<edm::ParameterSet>("tkEgSorterParameters"));
0353   } else
0354     throw cms::Exception("Configuration", "Unsupported tkEgSorterAlgo");
0355 
0356   if (l1tkegalgo_->writeEgSta())
0357     produces<BXVector<l1t::EGamma>>("L1Eg");
0358   produces<l1t::TkElectronCollection>("L1TkEle");
0359   produces<l1t::TkElectronRegionalOutput>("L1TkElePerBoard");
0360   produces<l1t::TkEmCollection>("L1TkEm");
0361   produces<l1t::TkEmRegionalOutput>("L1TkEmPerBoard");
0362 
0363   emuTkVtx_ = iConfig.getParameter<bool>("vtxCollectionEmulation");
0364   if (emuTkVtx_) {
0365     tkVtxEmu_ = consumes<std::vector<l1t::VertexWord>>(iConfig.getParameter<edm::InputTag>("vtxCollection"));
0366   } else {
0367     extTkVtx_ = consumes<std::vector<l1t::Vertex>>(iConfig.getParameter<edm::InputTag>("vtxCollection"));
0368   }
0369   nVtx_ = iConfig.getParameter<int>("nVtx");
0370 
0371   const char *iprefix[4] = {"totNReg", "maxNReg", "totNSec", "maxNSec"};
0372   for (int i = 0; i <= l1muType; ++i) {
0373     for (int ip = 0; ip < 4; ++ip) {
0374       produces<unsigned int>(std::string(iprefix[ip]) + inputTypeName[i]);
0375     }
0376     produces<std::vector<unsigned>>(std::string("vecNReg") + inputTypeName[i]);
0377     produces<std::vector<unsigned>>(std::string("vecNSec") + inputTypeName[i]);
0378   }
0379   const char *oprefix[4] = {"totNPF", "maxNPF", "totNPuppi", "maxNPuppi"};
0380   for (int i = 0; i < l1ct::OutputRegion::nPFTypes; ++i) {
0381     for (int ip = 0; ip < 4; ++ip) {
0382       produces<unsigned int>(std::string(oprefix[ip]) + l1ct::OutputRegion::objTypeName[i]);
0383     }
0384     produces<std::vector<unsigned>>(std::string("vecNPF") + l1ct::OutputRegion::objTypeName[i]);
0385     produces<std::vector<unsigned>>(std::string("vecNPuppi") + l1ct::OutputRegion::objTypeName[i]);
0386   }
0387 
0388   initSectorsAndRegions(iConfig);
0389 }
0390 
0391 L1TCorrelatorLayer1Producer::~L1TCorrelatorLayer1Producer() {}
0392 
0393 void L1TCorrelatorLayer1Producer::fillDescriptions(edm::ConfigurationDescriptions &descriptions) {
0394   edm::ParameterSetDescription desc;
0395   // Inputs and cuts
0396   desc.add<edm::InputTag>("tracks", edm::InputTag(""));
0397   desc.add<edm::InputTag>("muons", edm::InputTag("l1tSAMuonsGmt", "prompt"));
0398   desc.add<edm::InputTag>("emClusters", edm::InputTag(""));
0399   desc.add<edm::InputTag>("hadClusters", edm::InputTag(""));
0400   desc.add<edm::InputTag>("vtxCollection", edm::InputTag("l1tVertexFinderEmulator", "L1VerticesEmulation"));
0401   desc.add<bool>("vtxCollectionEmulation", true);
0402   desc.add<double>("emPtCut", 0.0);
0403   desc.add<double>("hadPtCut", 0.0);
0404   desc.add<double>("trkPtCut", 0.0);
0405   desc.add<int32_t>("nVtx");
0406   // Input conversion
0407   edm::EmptyGroupDescription emptyGroup;
0408   desc.ifValue(edm::ParameterDescription<std::string>("trackInputConversionAlgo", "Ideal", true),
0409                "Ideal" >> emptyGroup or "Emulator" >> getParDesc<l1ct::TrackInputEmulator>("trackInputConversion"));
0410   desc.ifValue(edm::ParameterDescription<std::string>("muonInputConversionAlgo", "Ideal", true),
0411                "Ideal" >> emptyGroup or "Emulator" >> getParDesc<l1ct::GMTMuonDecoderEmulator>("muonInputConversion"));
0412   desc.ifValue(
0413       edm::ParameterDescription<std::string>("hgcalInputConversionAlgo", "None", true),
0414       "None" >> emptyGroup or "Emulator" >> getParDesc<l1ct::HgcalClusterDecoderEmulator>("hgcalInputConversion"));
0415   desc.ifValue(
0416       edm::ParameterDescription<std::string>("gctEmInputConversionAlgo", "None", true),
0417       "None" >> emptyGroup or "Emulator" >> getParDesc<l1ct::GctEmClusterDecoderEmulator>("gctEmInputConversion"));
0418   desc.ifValue(edm::ParameterDescription<std::string>("gctHadInputConversionAlgo", "None", true),
0419                "Ideal" >> emptyGroup or "None" >> emptyGroup or
0420                    "Emulator" >> getParDesc<l1ct::GctHadClusterDecoderEmulator>("gctHadInputConversion"));
0421   // Regionizer
0422   auto idealRegPD = getParDesc<l1ct::RegionizerEmulator>("regionizerAlgo");
0423   auto tdrRegPD = getParDesc<l1ct::TDRRegionizerEmulator>("regionizerAlgo");
0424   auto multififoRegPD = getParDesc<l1ct::MultififoRegionizerEmulator>("regionizerAlgo");
0425   auto bfMultififoRegPD = getParDesc<l1ct::BufferedFoldedMultififoRegionizerEmulator>("regionizerAlgo");
0426   auto multififoBarrelRegPD = edm::ParameterDescription<edm::ParameterSetDescription>(
0427       "regionizerAlgoParameters", l1ct::MultififoRegionizerEmulator::getParameterSetDescriptionBarrel(), true);
0428   auto mbMultififoRegPD = getParDesc<l1ct::MiddleBufferMultififoRegionizerEmulator>("regionizerAlgo");
0429   desc.ifValue(edm::ParameterDescription<std::string>("regionizerAlgo", "Ideal", true),
0430                "Ideal" >> idealRegPD or "TDR" >> tdrRegPD or "Multififo" >> multififoRegPD or
0431                    "BufferedFoldedMultififo" >> bfMultififoRegPD or "MultififoBarrel" >> multififoBarrelRegPD or
0432                    "MiddleBufferMultififo" >> mbMultififoRegPD);
0433   // PF
0434   desc.ifValue(edm::ParameterDescription<std::string>("pfAlgo", "PFAlgo3", true),
0435                "PFAlgo3" >> getParDesc<l1ct::PFAlgo3Emulator>("pfAlgo") or
0436                    "PFAlgo2HGC" >> getParDesc<l1ct::PFAlgo2HGCEmulator>("pfAlgo") or
0437                    "PFAlgoDummy" >> getParDesc<l1ct::PFAlgoDummyEmulator>("pfAlgo"));
0438   // Puppi
0439   desc.ifValue(edm::ParameterDescription<std::string>("puAlgo", "LinearizedPuppi", true),
0440                "LinearizedPuppi" >> getParDesc<l1ct::LinPuppiEmulator>("puAlgo"));
0441   // EGamma
0442   desc.add<edm::ParameterSetDescription>("tkEgAlgoParameters", l1ct::PFTkEGAlgoEmuConfig::getParameterSetDescription());
0443   // EGamma sort
0444   desc.ifValue(edm::ParameterDescription<std::string>("tkEgSorterAlgo", "Barrel", true),
0445                "Barrel" >> getParDesc<l1ct::PFTkEGSorterBarrelEmulator>("tkEgSorter") or
0446                    "Endcap" >> getParDesc<l1ct::PFTkEGSorterEmulator>("tkEgSorter"));
0447   // geometry: calo sectors
0448   edm::ParameterSetDescription caloSectorPSD;
0449   caloSectorPSD.add<std::vector<double>>("etaBoundaries");
0450   caloSectorPSD.add<uint32_t>("phiSlices", 3);
0451   caloSectorPSD.add<double>("phiZero", 0.);
0452   desc.addVPSet("caloSectors", caloSectorPSD);
0453   // geometry: regions
0454   edm::ParameterSetDescription regionPSD;
0455   regionPSD.add<std::vector<double>>("etaBoundaries");
0456   regionPSD.add<uint32_t>("phiSlices", 9);
0457   regionPSD.add<double>("etaExtra", 0.25);
0458   regionPSD.add<double>("phiExtra", 0.25);
0459   desc.addVPSet("regions", regionPSD);
0460   // geometry: boards
0461   edm::ParameterSetDescription boardPSD;
0462   boardPSD.add<std::vector<unsigned int>>("regions");
0463   desc.addVPSet("boards", boardPSD);
0464   // dump files
0465   desc.addUntracked<std::string>("dumpFileName", "");
0466   // pattern files
0467   desc.addVPSetUntracked(
0468       "patternWriters", L1TCorrelatorLayer1PatternFileWriter::getParameterSetDescription(), edm::VParameterSet());
0469   // debug
0470   desc.addUntracked<double>("debugEta", 0.);
0471   desc.addUntracked<double>("debugPhi", 0.);
0472   desc.addUntracked<double>("debugR", -1.);
0473   descriptions.add("l1tCorrelatorLayer1", desc);
0474 }
0475 
0476 void L1TCorrelatorLayer1Producer::beginStream(edm::StreamID id) {
0477   if (!regionDumpName_.empty()) {
0478     if (id == 0) {
0479       fRegionDump_.open(regionDumpName_.c_str(), std::ios::out | std::ios::binary);
0480     } else {
0481       edm::LogWarning("L1TCorrelatorLayer1Producer")
0482           << "Job running with multiple streams, but dump file will have only events on stream zero.";
0483     }
0484   }
0485   if (!patternWriterConfigs_.empty()) {
0486     if (id == 0) {
0487       for (const auto &pset : patternWriterConfigs_) {
0488         patternWriters_.emplace_back(std::make_unique<L1TCorrelatorLayer1PatternFileWriter>(pset, event_));
0489       }
0490     } else {
0491       edm::LogWarning("L1TCorrelatorLayer1Producer")
0492           << "Job running with multiple streams, but pattern files will be written only on stream zero.";
0493     }
0494   }
0495 }
0496 
0497 void L1TCorrelatorLayer1Producer::endStream() {
0498   for (auto &writer : patternWriters_) {
0499     writer->flush();
0500   }
0501 }
0502 
0503 // ------------ method called to produce the data  ------------
0504 void L1TCorrelatorLayer1Producer::produce(edm::Event &iEvent, const edm::EventSetup &iSetup) {
0505   // clear the regions also at the beginning, in case one event didn't complete but the job continues on
0506   initEvent(iEvent);
0507 
0508   /// ------ READ TRACKS ----
0509   if (hasTracks_) {
0510     edm::Handle<l1t::PFTrackCollection> htracks;
0511     iEvent.getByToken(tkCands_, htracks);
0512     const auto &tracks = *htracks;
0513     for (unsigned int itk = 0, ntk = tracks.size(); itk < ntk; ++itk) {
0514       const auto &tk = tracks[itk];
0515       // adding objects to PF
0516       if (debugR_ > 0 && deltaR(tk.eta(), tk.phi(), debugEta_, debugPhi_) > debugR_)
0517         continue;
0518       if (tk.pt() > trkPt_) {
0519         addTrack(tk, l1t::PFTrackRef(htracks, itk));
0520       }
0521     }
0522   }
0523 
0524   /// ------ READ MUONS ----
0525   edm::Handle<l1t::SAMuonCollection> muons;
0526   iEvent.getByToken(muCands_, muons);
0527   for (unsigned int i = 0, n = muons->size(); i < n; ++i) {
0528     const l1t::SAMuon &mu = (*muons)[i];
0529     if (debugR_ > 0 && deltaR(mu.eta(), mu.phi(), debugEta_, debugPhi_) > debugR_)
0530       continue;
0531     addMuon(mu, l1t::PFCandidate::MuonRef(muons, i));
0532   }
0533   // ------ READ CALOS -----
0534 
0535   // this is for parsing raw calo information
0536   if (!emGCTRawCands_.isUninitialized()) {
0537     auto caloHandle = iEvent.getHandle(emGCTRawCands_);
0538     const auto &links = *caloHandle;
0539     for (unsigned int ic = 0; ic < links.size(); ++ic) {
0540       const auto &link = links[ic];
0541       for (unsigned int ie = 0; ie < link.size(); ++ie) {
0542         addGCTEmCaloRaw(link, ic, ie);
0543       }
0544     }
0545   }
0546 
0547   if (!hadHGCalCands_.isUninitialized()) {
0548     auto caloHandle = iEvent.getHandle(hadHGCalCands_);
0549     if (caloHandle.isValid()) {
0550       const auto &calos = *caloHandle;
0551       for (unsigned int ic = 0, nc = calos.size(); ic < nc; ++ic) {
0552         const auto &calo = calos[ic];
0553         addHGCalHadCalo(calo, edm::Ptr<l1t::L1Candidate>(caloHandle, ic));
0554       }
0555     }
0556   }
0557 
0558   if (!hadGCTRawCands_.isUninitialized()) {
0559     auto caloHandle = iEvent.getHandle(hadGCTRawCands_);
0560     const auto &links = *caloHandle;
0561     for (unsigned int ic = 0; ic < links.size(); ++ic) {
0562       const auto &link = links[ic];
0563       for (unsigned int ie = 0; ie < link.size(); ++ie) {
0564         addGCTHadCaloRaw(link, ic, ie);
0565       }
0566     }
0567   }
0568 
0569   if (!hadGCTCands_.isUninitialized()) {
0570     auto caloHandle = iEvent.getHandle(hadGCTCands_);
0571     if (caloHandle.isValid()) {
0572       const auto &calos = *caloHandle;
0573       for (unsigned int ic = 0, nc = calos.size(); ic < nc; ++ic) {
0574         const auto &calo = calos[ic];
0575         addGCTHadCalo(calo, edm::Ptr<l1t::L1Candidate>(caloHandle, ic));
0576       }
0577     }
0578   }
0579 
0580   regionizer_->run(event_.decoded, event_.pfinputs);
0581 
0582   // First, get a copy of the discretized and corrected inputs, and write them out
0583   // FIXME: steer via config flag
0584   iEvent.put(fetchEmCalo(), "EmCalo");
0585   iEvent.put(fetchHadCalo(), "Calo");
0586   iEvent.put(fetchTracks(), "TK");
0587 
0588   iEvent.put(fetchDecodedHadCalo(), "DecodedHadClusters");
0589   iEvent.put(fetchDecodedEmCalo(), "DecodedEmClusters");
0590   iEvent.put(fetchDecodedTracks(), "DecodedTK");
0591 
0592   // Then do the vertexing, and save it out
0593   std::vector<float> z0s;
0594   std::vector<std::pair<float, float>> ptsums;
0595   float z0 = 0;
0596   double ptsum = 0;
0597   l1t::VertexWord pvwd;
0598   // FIXME: collections seem to be already sorted
0599   if (emuTkVtx_) {
0600     edm::Handle<std::vector<l1t::VertexWord>> vtxEmuHandle;
0601     iEvent.getByToken(tkVtxEmu_, vtxEmuHandle);
0602     for (const auto &vtx : *vtxEmuHandle) {
0603       ptsums.push_back(std::pair<float, float>(vtx.pt(), vtx.z0()));
0604       if (ptsum == 0 || vtx.pt() > ptsum) {
0605         ptsum = vtx.pt();
0606         pvwd = vtx;
0607       }
0608     }
0609   } else {
0610     edm::Handle<std::vector<l1t::Vertex>> vtxHandle;
0611     iEvent.getByToken(extTkVtx_, vtxHandle);
0612     for (const auto &vtx : *vtxHandle) {
0613       ptsums.push_back(std::pair<float, float>(vtx.pt(), vtx.z0()));
0614       if (ptsum == 0 || vtx.pt() > ptsum) {
0615         ptsum = vtx.pt();
0616         z0 = vtx.z0();
0617       }
0618     }
0619     pvwd = l1t::VertexWord(1, z0, 1, ptsum, 1, 1, 1);
0620   }
0621   l1ct::PVObjEmu hwpv;
0622   hwpv.hwZ0 = l1ct::Scales::makeZ0(pvwd.z0());
0623   event_.pvs.push_back(hwpv);
0624   event_.pvs_emu.push_back(pvwd.vertexWord());
0625   //get additional vertices if requested
0626   if (nVtx_ > 1) {
0627     std::stable_sort(ptsums.begin(), ptsums.end(), [](const auto &a, const auto &b) { return a.first > b.first; });
0628     for (int i0 = 0; i0 < std::min(int(ptsums.size()), int(nVtx_)); i0++) {
0629       z0s.push_back(ptsums[i0].second);
0630     }
0631     for (unsigned int i = 1; i < z0s.size(); ++i) {
0632       l1ct::PVObjEmu hwpv;
0633       hwpv.hwZ0 = l1ct::Scales::makeZ0(z0s[i]);
0634       event_.pvs.push_back(hwpv);  //Skip emu
0635     }
0636   }
0637   // Then also save the tracks with a vertex cut
0638 #if 0
0639   iEvent.put(l1regions_.fetchTracks(/*ptmin=*/0.0, /*fromPV=*/true), "TKVtx");
0640 #endif
0641 
0642   // Then run PF in each region
0643   event_.out.resize(event_.pfinputs.size());
0644   for (unsigned int ir = 0, nr = event_.pfinputs.size(); ir < nr; ++ir) {
0645     l1pfalgo_->run(event_.pfinputs[ir], event_.out[ir]);
0646     l1pfalgo_->mergeNeutrals(event_.out[ir]);
0647     l1tkegalgo_->run(event_.pfinputs[ir], event_.out[ir]);
0648     l1tkegalgo_->runIso(event_.pfinputs[ir], event_.pvs, event_.out[ir]);
0649   }
0650 
0651   // Then run puppi (regionally)
0652   for (unsigned int ir = 0, nr = event_.pfinputs.size(); ir < nr; ++ir) {
0653     l1pualgo_->run(event_.pfinputs[ir], event_.pvs, event_.out[ir]);
0654     //l1pualgo_->runNeutralsPU(l1region, z0, -1., puGlobals);
0655   }
0656 
0657   // NOTE: This needs to happen before the EG sorting per board so that the EG objects
0658   // get a global reference to the EGSta before being mixed among differente regions
0659   std::vector<edm::Ref<BXVector<l1t::EGamma>>> egsta_refs;
0660   if (l1tkegalgo_->writeEgSta()) {
0661     putEgStaObjects(iEvent, "L1Eg");
0662   }
0663 
0664   // l1tkegsorter_->setDebug(true);
0665   for (auto &board : event_.board_out) {
0666     l1tkegsorter_->runPho(event_.pfinputs, event_.out, board.region_index, board.egphoton);
0667     l1tkegsorter_->runEle(event_.pfinputs, event_.out, board.region_index, board.egelectron);
0668   }
0669 
0670   // save PF into the event
0671   iEvent.put(fetchPF(), "PF");
0672 
0673   // and save puppi
0674   putPuppi(iEvent);
0675 
0676   // save the EG objects
0677   putEgObjects(iEvent, l1tkegalgo_->writeEgSta(), "L1TkEm", "L1TkEmPerBoard", "L1TkEle", "L1TkElePerBoard");
0678 
0679   // Then go do the multiplicities
0680   for (int i = 0; i <= l1muType; ++i) {
0681     auto vecInputs = vecSecInput(InputType(i));
0682     auto tm = totAndMax(*vecInputs);
0683     addUInt(tm.first, std::string("totNSec") + inputTypeName[i], iEvent);
0684     addUInt(tm.second, std::string("maxNSec") + inputTypeName[i], iEvent);
0685     iEvent.put(std::move(vecInputs), std::string("vecNSec") + inputTypeName[i]);
0686   }
0687   for (int i = 0; i <= l1muType; ++i) {
0688     auto vecInputs = vecRegInput(InputType(i));
0689     auto tm = totAndMax(*vecInputs);
0690     addUInt(tm.first, std::string("totNReg") + inputTypeName[i], iEvent);
0691     addUInt(tm.second, std::string("maxNReg") + inputTypeName[i], iEvent);
0692     iEvent.put(std::move(vecInputs), std::string("vecNReg") + inputTypeName[i]);
0693   }
0694   for (int i = 0; i < l1ct::OutputRegion::nPFTypes; ++i) {
0695     auto vecPF = vecOutput(OutputType(i), false);
0696     auto tmPF = totAndMax(*vecPF);
0697     addUInt(tmPF.first, std::string("totNPF") + l1ct::OutputRegion::objTypeName[i], iEvent);
0698     addUInt(tmPF.second, std::string("maxNPF") + l1ct::OutputRegion::objTypeName[i], iEvent);
0699     iEvent.put(std::move(vecPF), std::string("vecNPF") + l1ct::OutputRegion::objTypeName[i]);
0700     auto vecPuppi = vecOutput(OutputType(i), true);
0701     auto tmPuppi = totAndMax(*vecPuppi);
0702     addUInt(tmPuppi.first, std::string("totNPuppi") + l1ct::OutputRegion::objTypeName[i], iEvent);
0703     addUInt(tmPuppi.second, std::string("maxNPuppi") + l1ct::OutputRegion::objTypeName[i], iEvent);
0704     iEvent.put(std::move(vecPuppi), std::string("vecNPuppi") + l1ct::OutputRegion::objTypeName[i]);
0705   }
0706 
0707   if (fRegionDump_.is_open()) {
0708     event_.write(fRegionDump_);
0709   }
0710   for (auto &writer : patternWriters_) {
0711     writer->write(event_);
0712   }
0713 
0714   // finally clear the regions
0715   event_.clear();
0716 }
0717 
0718 void L1TCorrelatorLayer1Producer::rawHgcalClusterEncode(ap_uint<256> &cwrd,
0719                                                         const l1ct::DetectorSector<ap_uint<256>> &sec,
0720                                                         const l1t::HGCalMulticluster &c) const {
0721   cwrd = 0;
0722 
0723   // implemented as of interface document (version of 15/11/2025)
0724   ap_ufixed<14, 12, AP_RND_CONV, AP_SAT> w_pt = c.pt();
0725   // NOTE: We use iPt here for now despite final HGC FW implementation might be different
0726   ap_ufixed<14, 12, AP_RND_CONV, AP_SAT> w_empt = c.iPt(l1t::HGCalMulticluster::EnergyInterpretation::EM);
0727 
0728   // NOTE: this number is not consistent with the iPt interpretation nor with hoe.
0729   // hoe uses the total cluster em and had energies while eot computed in the showershapes only accounts for a
0730   // a max radius from the cluster center. This is the value used by the ID models
0731   ap_uint<8> w_emfrac = std::min(round(c.eot() * 256), float(255.));
0732 
0733   // NOTE II: we compute a second eot value to propagate the value of the total hadronic energy as in
0734   // the hoe computation
0735   float em_frac_tot = c.hOverE() < 0 ? 0. : 1. / (c.hOverE() + 1.);
0736   ap_uint<8> w_emfrac_tot = std::min(round(em_frac_tot * 256), float(255.));
0737 
0738   // LSB defintions according to the HGC/Correlator interface document
0739   static constexpr float ETAPHI_LSB = M_PI / 720;
0740   static constexpr float SIGMAZZ_LSB = 778.098 / (1 << 7);
0741   static constexpr float SIGMAPHIPHI_LSB = 0.12822 / (1 << 7);
0742   static constexpr float SIGMAETAETA_LSB = 0.148922 / (1 << 5);
0743 
0744   ap_uint<10> w_eta = round(fabs(c.eta()) / ETAPHI_LSB);
0745   ap_int<9> w_phi = round(sec.region.localPhi(c.phi()) / ETAPHI_LSB);
0746   // FIXME: we keep subtracting an arbitrary number different from the HLGCal FW one
0747   ap_ufixed<12, 11, AP_RND_CONV, AP_SAT> w_meanz = fabs(c.zBarycenter()) - 320;  // LSB = 0.5cm
0748 
0749   ap_uint<6> w_showerlength = c.showerLength();
0750   ap_uint<7> w_sigmazz = round(c.sigmaZZ() / SIGMAZZ_LSB);
0751   ap_uint<7> w_sigmaphiphi = round(c.sigmaPhiPhiTot() / SIGMAPHIPHI_LSB);
0752   ap_uint<6> w_coreshowerlength = c.coreShowerLength();
0753   ap_uint<5> w_sigmaetaeta = round(c.sigmaEtaEtaTot() / SIGMAETAETA_LSB);
0754   // NOTE: this is an arbitrary choice to keep the rounding consistent with the "addDecodedHadCalo" one
0755   // FIXME: the scaling here is added to the encoded word...
0756   ap_uint<13> w_sigmarrtot = round(c.sigmaRRTot() * l1ct::Scales::SRRTOT_SCALE / l1ct::Scales::SRRTOT_LSB);
0757 
0758   // Word 0
0759   cwrd(13, 0) = w_pt.range();     // 14 bits: 13-0
0760   cwrd(27, 14) = w_empt.range();  // 14 bits: 27-14
0761   cwrd(39, 32) = w_emfrac_tot;    //  8 bits: 39-32
0762   cwrd(47, 40) = w_emfrac;        //  8 bits: 47-40
0763 
0764   // Word 1
0765   cwrd(64 + 9, 64 + 0) = w_eta;              // 10 bits: 9-0
0766   cwrd(64 + 18, 64 + 10) = w_phi;            //  9 bits: 18-10
0767   cwrd(64 + 30, 64 + 19) = w_meanz.range();  // 12 bits: 30-19
0768   // Word 2
0769   cwrd(128 + 18, 128 + 13) = w_showerlength;      //  6 bits: 18-13
0770   cwrd(128 + 38, 128 + 32) = w_sigmazz;           //  7 bits: 38-32
0771   cwrd(128 + 45, 128 + 39) = w_sigmaphiphi;       //  7 bits: 45-39
0772   cwrd(128 + 51, 128 + 46) = w_coreshowerlength;  //  6 bits: 51-46
0773   cwrd(128 + 56, 128 + 52) = w_sigmaetaeta;       //  5 bits: 56-52
0774 
0775   // cwrd(128+63, 128+57) = w_sigmarrtot;       //  7 bits: 63-57 // FIXME: use word3 spare bits
0776   // Word 3
0777   cwrd(213, 201) = w_sigmarrtot;  // these are spare bits for now
0778 }
0779 
0780 void L1TCorrelatorLayer1Producer::encodeAndAddHgcalCluster(ap_uint<256> &word,
0781                                                            l1ct::DetectorSector<ap_uint<256>> &sec,
0782                                                            const l1t::HGCalMulticluster &calo) const {
0783   rawHgcalClusterEncode(word, sec, calo);
0784   sec.obj.push_back(word);
0785 }
0786 
0787 void L1TCorrelatorLayer1Producer::addEmPFCluster(const l1ct::EmCaloObjEmu &decCalo,
0788                                                  const l1ct::PFRegionEmu &region,
0789                                                  std::unique_ptr<l1t::PFClusterCollection> &pfClusters) const {
0790   // Crete the PFCluster and add the original object as Consitutent
0791   pfClusters->emplace_back(decCalo.floatPt(),
0792                            region.floatGlbEta(decCalo.hwEta),
0793                            region.floatGlbPhi(decCalo.hwPhi),
0794                            decCalo.floatHoe(),
0795                            true,
0796                            decCalo.floatPtErr(),
0797                            decCalo.intPt(),
0798                            decCalo.intEta(),
0799                            decCalo.intPhi());
0800 
0801   // Add additional variables specialized for GCT and HGCal clusters
0802   pfClusters->back().setHwQual(decCalo.hwEmID.to_int());
0803   pfClusters->back().setCaloDigi(decCalo);
0804   setRefs_(pfClusters->back(), decCalo);
0805 }
0806 
0807 void L1TCorrelatorLayer1Producer::addDecodedEmCalo(l1ct::EmCaloObjEmu &decCalo,
0808                                                    const edm::Ptr<l1t::L1Candidate> &caloPtr,
0809                                                    l1ct::DetectorSector<l1ct::EmCaloObjEmu> &sec) {
0810   clusterRefMap_[caloPtr.get()] = caloPtr;
0811   decCalo.src = caloPtr.get();
0812   if (decCalo.hwPt > 0) {  // NOTE: 0 pt clusters have null ptr. Do we need to keep them?
0813     // FIXME: for now we extract these from the upstream object since they are not yet available in the digi format
0814     const l1tp2::CaloCrystalCluster *crycl = dynamic_cast<const l1tp2::CaloCrystalCluster *>(decCalo.src);
0815     decCalo.hwShowerShape = l1ct::shower_shape_t(crycl->e2x5() / crycl->e5x5());
0816     decCalo.hwRelIso = l1ct::Scales::makeRelIso(crycl->isolation() / decCalo.hwPt.to_float());
0817   }
0818   sec.obj.push_back(decCalo);
0819 }
0820 
0821 void L1TCorrelatorLayer1Producer::addHadPFCluster(const l1ct::HadCaloObjEmu &decCalo,
0822                                                   const l1ct::PFRegionEmu &region,
0823                                                   std::unique_ptr<l1t::PFClusterCollection> &pfClusters) const {
0824   // Crete the PFCluster and add the original object as Consitutent
0825   pfClusters->emplace_back(decCalo.floatPt(),
0826                            region.floatGlbEta(decCalo.hwEta),
0827                            region.floatGlbPhi(decCalo.hwPhi),
0828                            decCalo.floatHoe(),
0829                            decCalo.hwIsEM(),
0830                            0.,  // ptError
0831                            decCalo.intPt(),
0832                            decCalo.intEta(),
0833                            decCalo.intPhi());
0834 
0835   // Add additional variables specialized for GCT and HGCal clusters
0836   pfClusters->back().setHwQual(decCalo.hwEmID.to_int());
0837   pfClusters->back().setCaloDigi(decCalo);
0838   setRefs_(pfClusters->back(), decCalo);
0839 }
0840 
0841 void L1TCorrelatorLayer1Producer::addDecodedHadCalo(l1ct::HadCaloObjEmu &decCalo,
0842                                                     const edm::Ptr<l1t::L1Candidate> &caloPtr,
0843                                                     l1ct::DetectorSector<l1ct::HadCaloObjEmu> &sec) {
0844   clusterRefMap_[caloPtr.get()] = caloPtr;
0845   decCalo.src = caloPtr.get();
0846   sec.obj.push_back(decCalo);
0847 }
0848 
0849 void L1TCorrelatorLayer1Producer::addUInt(unsigned int value, std::string iLabel, edm::Event &iEvent) {
0850   iEvent.put(std::make_unique<unsigned>(value), iLabel);
0851 }
0852 
0853 void L1TCorrelatorLayer1Producer::initSectorsAndRegions(const edm::ParameterSet &iConfig) {
0854   // the track finder geometry is fixed
0855   unsigned int TF_phiSlices = 9;
0856   float TF_phiWidth = 2 * M_PI / TF_phiSlices;
0857   event_.decoded.track.clear();
0858   for (unsigned int ieta = 0, neta = 2; ieta < neta; ++ieta) {
0859     for (unsigned int iphi = 0; iphi < TF_phiSlices; ++iphi) {
0860       float phiCenter = reco::reducePhiRange(iphi * TF_phiWidth);
0861       event_.decoded.track.emplace_back((ieta ? 0. : -2.5), (ieta ? 2.5 : 0.0), phiCenter, TF_phiWidth);
0862       event_.raw.track.emplace_back((ieta ? 0. : -2.5), (ieta ? 2.5 : 0.0), phiCenter, TF_phiWidth);
0863     }
0864   }
0865 
0866   event_.decoded.emcalo.clear();
0867   event_.decoded.hadcalo.clear();
0868   event_.raw.hgcalcluster.clear();
0869   event_.raw.gctEm.clear();
0870   event_.raw.gctHad.clear();
0871 
0872   for (const edm::ParameterSet &preg : iConfig.getParameter<edm::VParameterSet>("caloSectors")) {
0873     std::vector<double> etaBoundaries = preg.getParameter<std::vector<double>>("etaBoundaries");
0874     if (!std::is_sorted(etaBoundaries.begin(), etaBoundaries.end()))
0875       throw cms::Exception("Configuration", "caloSectors.etaBoundaries not sorted\n");
0876     unsigned int phiSlices = preg.getParameter<uint32_t>("phiSlices");
0877     float phiWidth = 2 * M_PI / phiSlices;
0878     if (phiWidth > 2 * l1ct::Scales::maxAbsPhi())
0879       throw cms::Exception("Configuration", "caloSectors phi range too large for phi_t data type");
0880     double phiZero = preg.getParameter<double>("phiZero");
0881     for (unsigned int ieta = 0, neta = etaBoundaries.size() - 1; ieta < neta; ++ieta) {
0882       float etaWidth = etaBoundaries[ieta + 1] - etaBoundaries[ieta];
0883       if (etaWidth > 2 * l1ct::Scales::maxAbsEta())
0884         throw cms::Exception("Configuration", "caloSectors eta range too large for eta_t data type");
0885       for (unsigned int iphi = 0; iphi < phiSlices; ++iphi) {
0886         float phiCenter = reco::reducePhiRange(iphi * phiWidth + phiZero);
0887         event_.decoded.hadcalo.emplace_back(etaBoundaries[ieta], etaBoundaries[ieta + 1], phiCenter, phiWidth);
0888         event_.decoded.emcalo.emplace_back(etaBoundaries[ieta], etaBoundaries[ieta + 1], phiCenter, phiWidth);
0889         event_.raw.hgcalcluster.emplace_back(etaBoundaries[ieta], etaBoundaries[ieta + 1], phiCenter, phiWidth);
0890         event_.raw.gctEm.emplace_back(etaBoundaries[ieta], etaBoundaries[ieta + 1], phiCenter, phiWidth);
0891         event_.raw.gctHad.emplace_back(etaBoundaries[ieta], etaBoundaries[ieta + 1], phiCenter, phiWidth);
0892       }
0893     }
0894   }
0895 
0896   event_.decoded.muon.region = l1ct::PFRegionEmu(0., 0.);  // centered at (0,0)
0897   event_.raw.muon.region = l1ct::PFRegionEmu(0., 0.);      // centered at (0,0)
0898 
0899   event_.pfinputs.clear();
0900   for (const edm::ParameterSet &preg : iConfig.getParameter<edm::VParameterSet>("regions")) {
0901     std::vector<double> etaBoundaries = preg.getParameter<std::vector<double>>("etaBoundaries");
0902     if (!std::is_sorted(etaBoundaries.begin(), etaBoundaries.end()))
0903       throw cms::Exception("Configuration", "regions.etaBoundaries not sorted\n");
0904     unsigned int phiSlices = preg.getParameter<uint32_t>("phiSlices");
0905     float etaExtra = preg.getParameter<double>("etaExtra");
0906     float phiExtra = preg.getParameter<double>("phiExtra");
0907     float phiWidth = 2 * M_PI / phiSlices;
0908     for (unsigned int ieta = 0, neta = etaBoundaries.size() - 1; ieta < neta; ++ieta) {
0909       for (unsigned int iphi = 0; iphi < phiSlices; ++iphi) {
0910         float phiCenter = reco::reducePhiRange(iphi * phiWidth);  //align with L1 TrackFinder phi sector indexing
0911         event_.pfinputs.emplace_back(
0912             etaBoundaries[ieta], etaBoundaries[ieta + 1], phiCenter, phiWidth, etaExtra, phiExtra);
0913       }
0914     }
0915   }
0916 
0917   event_.board_out.clear();
0918   const edm::VParameterSet &board_params = iConfig.getParameter<edm::VParameterSet>("boards");
0919   event_.board_out.resize(board_params.size());
0920   for (unsigned int bidx = 0; bidx < board_params.size(); bidx++) {
0921     event_.board_out[bidx].region_index = board_params[bidx].getParameter<std::vector<unsigned int>>("regions");
0922     float etaBoard = 0.;
0923     float phiBoard = 0.;
0924     for (auto ridx : event_.board_out[bidx].region_index) {
0925       etaBoard += event_.pfinputs[ridx].region.floatEtaCenter();
0926       phiBoard += event_.pfinputs[ridx].region.floatPhiCenter();
0927     }
0928     event_.board_out[bidx].eta = etaBoard / event_.board_out[bidx].region_index.size();
0929     event_.board_out[bidx].phi = phiBoard / event_.board_out[bidx].region_index.size();
0930   }
0931 }
0932 
0933 void L1TCorrelatorLayer1Producer::initEvent(const edm::Event &iEvent) {
0934   event_.clear();
0935   event_.run = iEvent.id().run();
0936   event_.lumi = iEvent.id().luminosityBlock();
0937   event_.event = iEvent.id().event();
0938   clusterRefMap_.clear();
0939   trackRefMap_.clear();
0940   muonRefMap_.clear();
0941 }
0942 
0943 void L1TCorrelatorLayer1Producer::addTrack(const l1t::PFTrack &t, l1t::PFTrackRef ref) {
0944   auto &rawsectors = event_.raw.track;
0945   auto &sectors = event_.decoded.track;
0946   assert(sectors.size() == 18 && rawsectors.size() == 18);
0947   int isec = t.track()->phiSector() + (t.eta() >= 0 ? 9 : 0);
0948   rawsectors[isec].obj.push_back(t.trackWord().getTrackWord());
0949   addDecodedTrack(sectors[isec], t);
0950   trackRefMap_[&t] = ref;
0951 }
0952 void L1TCorrelatorLayer1Producer::addMuon(const l1t::SAMuon &mu, l1t::PFCandidate::MuonRef ref) {
0953   event_.raw.muon.obj.emplace_back(mu.word());
0954   addDecodedMuon(event_.decoded.muon, mu);
0955   muonRefMap_[&mu] = ref;
0956 }
0957 
0958 void L1TCorrelatorLayer1Producer::addGCTHadCalo(const l1t::PFCluster &calo, const edm::Ptr<l1t::L1Candidate> &caloPtr) {
0959   for (unsigned int isec = 0; isec < event_.decoded.hadcalo.size(); isec++) {
0960     auto &sec = event_.decoded.hadcalo[isec];
0961     // Get the raw and decoded sectors
0962     if (sec.region.contains(calo.eta(), calo.phi())) {
0963       l1ct::HadCaloObjEmu decCalo;
0964       getDecodedGCTPFCluster(decCalo, sec, calo);
0965       if (decCalo.floatPt() > hadPtCut_)
0966         addDecodedHadCalo(decCalo, caloPtr, sec);
0967     }
0968   }
0969 }
0970 
0971 void L1TCorrelatorLayer1Producer::getDecodedGCTPFCluster(l1ct::HadCaloObjEmu &calo,
0972                                                          l1ct::DetectorSector<l1ct::HadCaloObjEmu> &sec,
0973                                                          const l1t::PFCluster &cluster) const {
0974   calo.clear();
0975   calo.hwPt = l1ct::Scales::makePtFromFloat(cluster.pt());
0976   calo.hwEta = l1ct::Scales::makeGlbEta(cluster.eta()) -
0977                sec.region.hwEtaCenter;  // important to enforce that the region boundary is on a discrete value
0978   calo.hwPhi = l1ct::Scales::makePhi(sec.region.localPhi(cluster.phi()));
0979   calo.hwEmPt = l1ct::Scales::makePtFromFloat(cluster.emEt());
0980   calo.hwEmID = cluster.hwEmID();
0981   calo.hwHoe = l1ct::Scales::makeHoe(cluster.hOverE());
0982 }
0983 
0984 void L1TCorrelatorLayer1Producer::addHGCalHadCalo(const l1t::HGCalMulticluster &calo,
0985                                                   const edm::Ptr<l1t::L1Candidate> &caloPtr) {
0986   for (unsigned int isec = 0; isec < event_.decoded.hadcalo.size(); isec++) {
0987     auto &sec = event_.decoded.hadcalo[isec];
0988     // Get the raw and decoded sectors
0989     if (sec.region.contains(calo.eta(), calo.phi())) {
0990       auto &sec_raw = event_.raw.hgcalcluster[isec];
0991       // Get the raw word
0992       ap_uint<256> cwrd = 0;
0993       encodeAndAddHgcalCluster(cwrd, sec_raw, calo);
0994       // Crete the decoded object calling the unpacker
0995       // Use the valid flag to reject PU clusters when creating the decoded object
0996       bool valid = true;
0997       l1ct::HadCaloObjEmu decCalo = hgcalInput_->decode(sec_raw.region, cwrd, valid);
0998       if (decCalo.floatPt() > hadPtCut_ && valid)
0999         addDecodedHadCalo(decCalo, caloPtr, sec);
1000     }
1001   }
1002 }
1003 
1004 void L1TCorrelatorLayer1Producer::addGCTEmCaloRaw(const l1tp2::GCTEmDigiClusterLink &link,
1005                                                   unsigned int linkidx,
1006                                                   unsigned int entidx) {
1007   // in the "Ideal" regionizer, ignore the second set that is sent; only use the first
1008   auto caloIdx = calomapping[linkidx];
1009   if (caloIdx < event_.raw.gctEm.size()) {
1010     event_.raw.gctEm[caloIdx].obj.push_back(link[entidx].data());
1011     addDecodedGCTEmCalo(event_.decoded.emcalo[caloIdx], link[entidx]);
1012   }
1013 }
1014 
1015 void L1TCorrelatorLayer1Producer::addGCTHadCaloRaw(const l1tp2::GCTHadDigiClusterLink &link,
1016                                                    unsigned int linkidx,
1017                                                    unsigned int entidx) {
1018   // in the "Ideal" regionizer, ignore the second set that is sent; only use the first
1019   auto caloIdx = calomapping[linkidx];
1020   if (caloIdx < event_.raw.gctHad.size()) {
1021     event_.raw.gctHad[caloIdx].obj.push_back(link[entidx].data());
1022     addDecodedGCTHadCalo(event_.decoded.hadcalo[caloIdx], link[entidx]);
1023   }
1024 }
1025 
1026 void L1TCorrelatorLayer1Producer::addDecodedTrack(l1ct::DetectorSector<l1ct::TkObjEmu> &sec, const l1t::PFTrack &t) {
1027   std::pair<l1ct::TkObjEmu, bool> tkAndSel;
1028   if (trackInput_) {
1029     tkAndSel = trackInput_->decodeTrack(t.trackWord().getTrackWord(), sec.region);
1030   } else {
1031     tkAndSel.first.hwPt = l1ct::Scales::makePtFromFloat(t.pt());
1032     tkAndSel.first.hwEta =
1033         l1ct::Scales::makeGlbEta(t.caloEta()) -
1034         sec.region.hwEtaCenter;  // important to enforce that the region boundary is on a discrete value
1035     tkAndSel.first.hwPhi = l1ct::Scales::makePhi(sec.region.localPhi(t.caloPhi()));
1036     tkAndSel.first.hwCharge = t.charge() > 0;
1037     tkAndSel.first.hwQuality = t.quality();
1038     tkAndSel.first.hwDEta = l1ct::Scales::makeEta(t.eta() - t.caloEta());
1039     tkAndSel.first.hwDPhi = l1ct::Scales::makePhi(std::abs(reco::deltaPhi(t.phi(), t.caloPhi())));
1040     tkAndSel.first.hwZ0 = l1ct::Scales::makeZ0(t.vertex().Z());
1041     tkAndSel.first.hwDxy = 0;
1042     tkAndSel.second = t.quality() > 0;
1043   }
1044   // CMSSW-only extra info
1045   tkAndSel.first.hwChi2 = round(t.chi2() * 10);
1046   tkAndSel.first.simPt = t.pt();
1047   tkAndSel.first.simCaloEta = t.caloEta();
1048   tkAndSel.first.simCaloPhi = t.caloPhi();
1049   tkAndSel.first.simVtxEta = t.eta();
1050   tkAndSel.first.simVtxPhi = t.phi();
1051   tkAndSel.first.simZ0 = t.vertex().Z();
1052   tkAndSel.first.simD0 = t.vertex().Rho();
1053   tkAndSel.first.src = &t;
1054 
1055   // If the track fails, we set its pT to zero, so that the decoded tracks are still aligned with the raw tracks
1056   // Downstream, the regionizer will just ignore zero-momentum tracks
1057   if (!tkAndSel.second)
1058     tkAndSel.first.hwPt = 0;
1059   sec.obj.push_back(tkAndSel.first);
1060 }
1061 
1062 void L1TCorrelatorLayer1Producer::addDecodedMuon(l1ct::DetectorSector<l1ct::MuObjEmu> &sec, const l1t::SAMuon &t) {
1063   l1ct::MuObjEmu mu;
1064   if (muonInput_) {
1065     mu = muonInput_->decode(t.word());
1066   } else {
1067     mu.hwPt = l1ct::Scales::makePtFromFloat(t.pt());
1068     mu.hwEta = l1ct::Scales::makeGlbEta(t.eta());  // IMPORTANT: input is in global coordinates!
1069     mu.hwPhi = l1ct::Scales::makeGlbPhi(t.phi());
1070     mu.hwCharge = !t.hwCharge();
1071     mu.hwQuality = t.hwQual() / 2;
1072     mu.hwDEta = 0;
1073     mu.hwDPhi = 0;
1074     mu.hwZ0 = l1ct::Scales::makeZ0(t.vertex().Z());
1075     mu.hwDxy = 0;  // Dxy not defined yet
1076   }
1077   mu.src = &t;
1078   sec.obj.push_back(mu);
1079 }
1080 
1081 void L1TCorrelatorLayer1Producer::addDecodedGCTEmCalo(l1ct::DetectorSector<l1ct::EmCaloObjEmu> &sec,
1082                                                       const l1tp2::GCTEmDigiCluster &digi) {
1083   l1ct::EmCaloObjEmu calo = gctEmInput_->decode(sec.region, digi.data());
1084 
1085   auto caloPtr = edm::refToPtr(digi.clusterRef());
1086   // FIXME: should check hwPt > 0
1087   addDecodedEmCalo(calo, caloPtr, sec);
1088 }
1089 
1090 void L1TCorrelatorLayer1Producer::addDecodedGCTHadCalo(l1ct::DetectorSector<l1ct::HadCaloObjEmu> &sec,
1091                                                        const l1tp2::GCTHadDigiCluster &digi) {
1092   l1ct::HadCaloObjEmu calo = gctHadInput_->decode(sec.region, digi.data());
1093 
1094   auto caloPtr = edm::refToPtr(digi.clusterRef());
1095   // FIXME: should check hwPt > 0
1096   addDecodedHadCalo(calo, caloPtr, sec);
1097 }
1098 
1099 template <typename T>
1100 void L1TCorrelatorLayer1Producer::setRefs_(l1t::PFCandidate &pf, const T &p) const {
1101   if (p.srcCluster) {
1102     auto match = clusterRefMap_.find(p.srcCluster);
1103     if (match == clusterRefMap_.end()) {
1104       throw cms::Exception("CorruptData") << "Invalid cluster pointer in PF candidate id " << p.intId() << " pt "
1105                                           << p.floatPt() << " eta " << p.floatEta() << " phi " << p.floatPhi();
1106     }
1107     pf.setCaloPtr(match->second);
1108   }
1109 
1110   if (p.srcTrack) {
1111     auto match = trackRefMap_.find(p.srcTrack);
1112     if (match == trackRefMap_.end()) {
1113       throw cms::Exception("CorruptData") << "Invalid track pointer in PF candidate id " << p.intId() << " pt "
1114                                           << p.floatPt() << " eta " << p.floatEta() << " phi " << p.floatPhi();
1115     }
1116     pf.setPFTrack(match->second);
1117   }
1118   if (p.srcMu) {
1119     auto match = muonRefMap_.find(p.srcMu);
1120     if (match == muonRefMap_.end()) {
1121       throw cms::Exception("CorruptData") << "Invalid muon pointer in PF candidate id " << p.intId() << " pt "
1122                                           << p.floatPt() << " eta " << p.floatEta() << " phi " << p.floatPhi();
1123     }
1124     pf.setMuon(match->second);
1125   }
1126 }
1127 
1128 template <>
1129 std::string L1TCorrelatorLayer1Producer::refExcepMsg_<l1ct::PFNeutralObjEmu>(const l1ct::PFNeutralObjEmu &key) const {
1130   return "Invalid pointer in Neutral PF candidate id " + std::to_string(key.intId()) + " pt " +
1131          std::to_string(key.floatPt()) + " eta " + std::to_string(key.floatEta()) + " phi " +
1132          std::to_string(key.floatPhi());
1133 }
1134 
1135 template <>
1136 std::string L1TCorrelatorLayer1Producer::refExcepMsg_<l1ct::HadCaloObjEmu>(const l1ct::HadCaloObjEmu &key) const {
1137   return "Invalid pointer in hadcalo obj, pt " + std::to_string(key.floatPt()) + " eta " +
1138          std::to_string(key.floatEta()) + " phi " + std::to_string(key.floatPhi());
1139 }
1140 
1141 template <>
1142 std::string L1TCorrelatorLayer1Producer::refExcepMsg_<l1ct::EmCaloObjEmu>(const l1ct::EmCaloObjEmu &key) const {
1143   return "Invalid pointer in emcalo obj, pt " + std::to_string(key.floatPt()) + " eta " +
1144          std::to_string(key.floatEta()) + " phi " + std::to_string(key.floatPhi());
1145 }
1146 
1147 template <>
1148 std::string L1TCorrelatorLayer1Producer::refExcepMsg_<l1ct::TkObjEmu>(const l1ct::TkObjEmu &key) const {
1149   return "Invalid track pointer in track obj, pt " + std::to_string(key.floatPt()) + " eta " +
1150          std::to_string(key.floatEta()) + " phi " + std::to_string(key.floatPhi());
1151 }
1152 
1153 template <>
1154 std::string L1TCorrelatorLayer1Producer::refExcepMsg_<l1ct::EGIsoObjEmu>(const l1ct::EGIsoObjEmu &key) const {
1155   return "Invalid cluster pointer in EGIso candidate, pt " + std::to_string(key.floatPt()) + " eta " +
1156          std::to_string(key.floatEta()) + " phi " + std::to_string(key.floatPhi());
1157 }
1158 
1159 template <>
1160 std::string L1TCorrelatorLayer1Producer::refExcepMsg_<l1ct::EGIsoEleObjEmu>(const l1ct::EGIsoEleObjEmu &key) const {
1161   return "Invalid cluster pointer in EGEleIso candidate, pt " + std::to_string(key.floatPt()) + " eta " +
1162          std::to_string(key.floatEta()) + " phi " + std::to_string(key.floatPhi());
1163 }
1164 
1165 template <>
1166 void L1TCorrelatorLayer1Producer::setRefs_<l1ct::PFNeutralObjEmu>(l1t::PFCandidate &pf,
1167                                                                   const l1ct::PFNeutralObjEmu &p) const {
1168   if (p.srcCluster) {
1169     pf.setCaloPtr(findRef_(clusterRefMap_, p.srcCluster, p));
1170   }
1171 }
1172 
1173 template <>
1174 void L1TCorrelatorLayer1Producer::setRefs_<l1ct::HadCaloObjEmu>(l1t::PFCandidate &pf,
1175                                                                 const l1ct::HadCaloObjEmu &p) const {
1176   if (p.src) {
1177     pf.setCaloPtr(findRef_(clusterRefMap_, p.src, p));
1178   }
1179 }
1180 
1181 template <>
1182 void L1TCorrelatorLayer1Producer::setRefs_<l1ct::EmCaloObjEmu>(l1t::PFCandidate &pf,
1183                                                                const l1ct::EmCaloObjEmu &p) const {
1184   if (p.src) {
1185     pf.setCaloPtr(findRef_(clusterRefMap_, p.src, p));
1186   }
1187 }
1188 
1189 template <>
1190 void L1TCorrelatorLayer1Producer::setRefs_<l1ct::TkObjEmu>(l1t::PFCandidate &pf, const l1ct::TkObjEmu &p) const {
1191   if (p.src) {
1192     pf.setPFTrack(findRef_(trackRefMap_, p.src, p));
1193   }
1194 }
1195 
1196 template <typename T>
1197 void L1TCorrelatorLayer1Producer::setRefs_(l1t::PFCluster &pf, const T &p) const {
1198   if (p.src) {
1199     pf.addConstituent(findRef_(clusterRefMap_, p.src, p));
1200   }
1201 }
1202 
1203 std::unique_ptr<l1t::PFCandidateCollection> L1TCorrelatorLayer1Producer::fetchHadCalo() const {
1204   auto ret = std::make_unique<l1t::PFCandidateCollection>();
1205   for (const auto &r : event_.pfinputs) {
1206     const auto &reg = r.region;
1207     for (const auto &p : r.hadcalo) {
1208       if (p.hwPt == 0 || !reg.isFiducial(p))
1209         continue;
1210       reco::Particle::PolarLorentzVector p4(p.floatPt(), reg.floatGlbEtaOf(p), reg.floatGlbPhiOf(p), 0.13f);
1211       l1t::PFCandidate::ParticleType type = p.hwIsEM() ? l1t::PFCandidate::Photon : l1t::PFCandidate::NeutralHadron;
1212       ret->emplace_back(type, 0, p4, 1, p.intPt(), p.intEta(), p.intPhi());
1213       ret->back().setHwEmID(p.hwEmID);
1214       setRefs_(ret->back(), p);
1215     }
1216   }
1217   return ret;
1218 }
1219 
1220 std::unique_ptr<l1t::PFClusterCollection> L1TCorrelatorLayer1Producer::fetchDecodedHadCalo() const {
1221   auto ret = std::make_unique<l1t::PFClusterCollection>();
1222   for (const auto &r : event_.pfinputs) {
1223     const auto &reg = r.region;
1224     for (const auto &p : r.hadcalo) {
1225       if (p.hwPt == 0 || !reg.isFiducial(p))
1226         continue;
1227       addHadPFCluster(p, reg, ret);
1228     }
1229   }
1230   return ret;
1231 }
1232 
1233 std::unique_ptr<l1t::PFClusterCollection> L1TCorrelatorLayer1Producer::fetchDecodedEmCalo() const {
1234   auto ret = std::make_unique<l1t::PFClusterCollection>();
1235   for (const auto &r : event_.pfinputs) {
1236     const auto &reg = r.region;
1237     for (const auto &p : r.emcalo) {
1238       if (p.hwPt == 0 || !reg.isFiducial(p))
1239         continue;
1240       addEmPFCluster(p, reg, ret);
1241     }
1242   }
1243   return ret;
1244 }
1245 
1246 std::unique_ptr<l1t::PFCandidateCollection> L1TCorrelatorLayer1Producer::fetchEmCalo() const {
1247   auto ret = std::make_unique<l1t::PFCandidateCollection>();
1248   for (const auto &r : event_.pfinputs) {
1249     const auto &reg = r.region;
1250     for (const auto &p : r.emcalo) {
1251       if (p.hwPt == 0 || !reg.isFiducial(p))
1252         continue;
1253       reco::Particle::PolarLorentzVector p4(p.floatPt(), reg.floatGlbEtaOf(p), reg.floatGlbPhiOf(p), 0.13f);
1254       ret->emplace_back(l1t::PFCandidate::Photon, 0, p4, 1, p.intPt(), p.intEta(), p.intPhi());
1255       ret->back().setHwEmID(p.hwEmID);
1256       setRefs_(ret->back(), p);
1257     }
1258   }
1259   return ret;
1260 }
1261 std::unique_ptr<l1t::PFCandidateCollection> L1TCorrelatorLayer1Producer::fetchTracks() const {
1262   auto ret = std::make_unique<l1t::PFCandidateCollection>();
1263   for (const auto &r : event_.pfinputs) {
1264     const auto &reg = r.region;
1265     for (const auto &p : r.track) {
1266       if (p.hwPt == 0 || !reg.isFiducial(p))
1267         continue;
1268       reco::Particle::PolarLorentzVector p4(
1269           p.floatPt(), reg.floatGlbEta(p.hwVtxEta()), reg.floatGlbPhi(p.hwVtxPhi()), 0.13f);
1270       ret->emplace_back(l1t::PFCandidate::ChargedHadron, p.intCharge(), p4, 1, p.intPt(), p.intEta(), p.intPhi());
1271       setRefs_(ret->back(), p);
1272     }
1273   }
1274   return ret;
1275 }
1276 
1277 std::unique_ptr<l1t::PFTrackCollection> L1TCorrelatorLayer1Producer::fetchDecodedTracks() const {
1278   auto ret = std::make_unique<l1t::PFTrackCollection>();
1279   for (const auto &r : event_.decoded.track) {
1280     const auto &reg = r.region;
1281     for (const auto &p : r.obj) {
1282       if (p.hwPt == 0)
1283         continue;
1284       reco::Particle::PolarLorentzVector p4(
1285           p.floatPt(), reg.floatGlbEta(p.hwVtxEta()), reg.floatGlbPhi(p.hwVtxPhi()), 0);
1286 
1287       reco::Particle::Point vtx(0, 0, p.floatZ0());
1288 
1289       ret->emplace_back(l1t::PFTrack(p.intCharge(),
1290                                      reco::Particle::LorentzVector(p4),
1291                                      vtx,
1292                                      p.src->track(),
1293                                      0,
1294                                      reg.floatGlbEta(p.hwEta),
1295                                      reg.floatGlbPhi(p.hwPhi),
1296                                      -1,
1297                                      -1,
1298                                      p.hwQuality.to_int(),
1299                                      false,
1300                                      p.intPt(),
1301                                      p.intEta(),
1302                                      p.intPhi()));
1303     }
1304   }
1305   return ret;
1306 }
1307 
1308 std::unique_ptr<l1t::PFCandidateCollection> L1TCorrelatorLayer1Producer::fetchPF() const {
1309   auto ret = std::make_unique<l1t::PFCandidateCollection>();
1310   for (unsigned int ir = 0, nr = event_.pfinputs.size(); ir < nr; ++ir) {
1311     const auto &reg = event_.pfinputs[ir].region;
1312     for (const auto &p : event_.out[ir].pfcharged) {
1313       if (p.hwPt == 0 || !reg.isFiducial(p))
1314         continue;
1315       reco::Particle::PolarLorentzVector p4(
1316           p.floatPt(), reg.floatGlbEta(p.hwVtxEta()), reg.floatGlbPhi(p.hwVtxPhi()), 0.13f);
1317       l1t::PFCandidate::ParticleType type = l1t::PFCandidate::ChargedHadron;
1318       if (p.hwId.isMuon())
1319         type = l1t::PFCandidate::Muon;
1320       else if (p.hwId.isElectron())
1321         type = l1t::PFCandidate::Electron;
1322       ret->emplace_back(type, p.intCharge(), p4, 1, p.intPt(), p.intEta(), p.intPhi());
1323       ret->back().setZ0(p.floatZ0());
1324       ret->back().setDxy(p.floatDxy());
1325       ret->back().setHwZ0(p.hwZ0);
1326       ret->back().setHwDxy(p.hwDxy);
1327       ret->back().setHwTkQuality(p.hwTkQuality);
1328       ret->back().setCaloEta(reg.floatGlbEtaOf(p));
1329       ret->back().setCaloPhi(reg.floatGlbPhiOf(p));
1330 
1331       setRefs_(ret->back(), p);
1332     }
1333     for (const auto &p : event_.out[ir].pfneutral) {
1334       if (p.hwPt == 0 || !reg.isFiducial(p))
1335         continue;
1336       reco::Particle::PolarLorentzVector p4(p.floatPt(), reg.floatGlbEtaOf(p), reg.floatGlbPhiOf(p), 0.13f);
1337       l1t::PFCandidate::ParticleType type =
1338           p.hwId.isPhoton() ? l1t::PFCandidate::Photon : l1t::PFCandidate::NeutralHadron;
1339       ret->emplace_back(type, 0, p4, 1, p.intPt(), p.intEta(), p.intPhi());
1340       ret->back().setHwEmID(p.hwEmID);
1341       ret->back().setCaloEta(reg.floatGlbEtaOf(p));
1342       ret->back().setCaloPhi(reg.floatGlbPhiOf(p));
1343       setRefs_(ret->back(), p);
1344     }
1345   }
1346   return ret;
1347 }
1348 
1349 void L1TCorrelatorLayer1Producer::putPuppi(edm::Event &iEvent) const {
1350   auto refprod = iEvent.getRefBeforePut<l1t::PFCandidateCollection>("Puppi");
1351   auto coll = std::make_unique<l1t::PFCandidateCollection>();
1352   auto reg = std::make_unique<l1t::PFCandidateRegionalOutput>(refprod);
1353   std::vector<int> nobj;
1354   for (unsigned int ir = 0, nr = event_.pfinputs.size(); ir < nr; ++ir) {
1355     nobj.clear();
1356     for (const auto &p : event_.out[ir].puppi) {
1357       if (p.hwPt == 0)
1358         continue;
1359       // note: Puppi candidates are already in global coordinates & fiducial-only!
1360       l1t::PFCandidate::ParticleType type;
1361       float mass = 0.13f;
1362       if (p.hwId.charged()) {
1363         if (p.hwId.isMuon()) {
1364           type = l1t::PFCandidate::Muon;
1365           mass = 0.105;
1366         } else if (p.hwId.isElectron()) {
1367           type = l1t::PFCandidate::Electron;
1368           mass = 0.005;
1369         } else
1370           type = l1t::PFCandidate::ChargedHadron;
1371       } else {
1372         type = p.hwId.isPhoton() ? l1t::PFCandidate::Photon : l1t::PFCandidate::NeutralHadron;
1373         mass = p.hwId.isPhoton() ? 0.0 : 0.5;
1374       }
1375       reco::Particle::PolarLorentzVector p4(p.floatPt(), p.floatEta(), p.floatPhi(), mass);
1376       coll->emplace_back(type, p.intCharge(), p4, p.floatPuppiW(), p.intPt(), p.intEta(), p.intPhi());
1377       if (p.hwId.charged()) {
1378         coll->back().setZ0(p.floatZ0());
1379         coll->back().setDxy(p.floatDxy());
1380         coll->back().setHwZ0(p.hwZ0());
1381         coll->back().setHwDxy(p.hwDxy());
1382         coll->back().setHwTkQuality(p.hwTkQuality());
1383       } else {
1384         coll->back().setHwPuppiWeight(p.hwPuppiW());
1385         coll->back().setHwEmID(p.hwEmID());
1386       }
1387       coll->back().setEncodedPuppi64(p.pack().to_uint64());
1388       setRefs_(coll->back(), p);
1389       nobj.push_back(coll->size() - 1);
1390     }
1391     reg->addRegion(nobj, event_.pfinputs[ir].region.floatEtaCenter(), event_.pfinputs[ir].region.floatPhiCenter());
1392   }
1393   iEvent.put(std::move(coll), "Puppi");
1394   iEvent.put(std::move(reg), "PuppiRegional");
1395 }
1396 
1397 void L1TCorrelatorLayer1Producer::putEgStaObjects(edm::Event &iEvent, const std::string &egLablel) const {
1398   auto egs = std::make_unique<BXVector<l1t::EGamma>>();
1399   // FIXME: in case more BXes are introduced shuld probably use egs->key(egs->end(bx));
1400 
1401   for (unsigned int ir = 0, nr = event_.pfinputs.size(); ir < nr; ++ir) {
1402     const auto &reg = event_.pfinputs[ir].region;
1403 
1404     // EG standalone objects
1405     for (unsigned int ieg = 0, neg = event_.out[ir].egsta.size(); ieg < neg; ++ieg) {
1406       const auto &p = event_.out[ir].egsta[ieg];
1407       if (p.hwPt == 0 || !reg.isFiducial(p))
1408         continue;
1409       l1t::EGamma eg(
1410           reco::Candidate::PolarLorentzVector(p.floatPt(), reg.floatGlbEta(p.hwEta), reg.floatGlbPhi(p.hwPhi), 0.));
1411       eg.setHwQual(p.hwQual);
1412       egs->push_back(0, eg);
1413     }
1414   }
1415 
1416   iEvent.put(std::move(egs), egLablel);
1417 }
1418 
1419 void L1TCorrelatorLayer1Producer::putEgObjects(edm::Event &iEvent,
1420                                                const bool writeEgSta,
1421                                                const std::string &tkEmLabel,
1422                                                const std::string &tkEmPerBoardLabel,
1423                                                const std::string &tkEleLabel,
1424                                                const std::string &tkElePerBoardLabel) const {
1425   auto tkems = std::make_unique<l1t::TkEmCollection>();
1426   auto tkemRefProd = iEvent.getRefBeforePut<l1t::TkEmCollection>(tkEmLabel);
1427   auto tkemPerBoard = std::make_unique<l1t::TkEmRegionalOutput>(tkemRefProd);
1428   auto tkeles = std::make_unique<l1t::TkElectronCollection>();
1429   auto tkeleRefProd = iEvent.getRefBeforePut<l1t::TkElectronCollection>(tkEleLabel);
1430   auto tkelePerBoard = std::make_unique<l1t::TkElectronRegionalOutput>(tkeleRefProd);
1431 
1432   // TkEG objects are written out after the per-board sorting.
1433   // The mapping to each board is saved into the regionalmap for further (stage-2 consumption)
1434   std::vector<int> nele_obj;
1435   std::vector<int> npho_obj;
1436 
1437   for (const auto &board : event_.board_out) {
1438     npho_obj.clear();
1439     for (const auto &egiso : board.egphoton) {
1440       if (egiso.hwPt == 0)
1441         continue;
1442 
1443       reco::Candidate::PolarLorentzVector mom(egiso.floatPt(), egiso.floatEta(), egiso.floatPhi(), 0.);
1444 
1445       l1t::TkEm tkem(reco::Candidate::LorentzVector(mom),
1446                      findRef_(clusterRefMap_, egiso.srcCluster, egiso),
1447                      egiso.floatRelIso(l1ct::EGIsoObjEmu::IsoType::TkIso),
1448                      egiso.floatRelIso(l1ct::EGIsoObjEmu::IsoType::TkIsoPV));
1449       tkem.setHwQual(egiso.hwQual);
1450       tkem.setPFIsol(egiso.floatRelIso(l1ct::EGIsoObjEmu::IsoType::PfIso));
1451       tkem.setPFIsolPV(egiso.floatRelIso(l1ct::EGIsoObjEmu::IsoType::PfIsoPV));
1452       tkem.setEgBinaryWord(egiso.pack(), l1t::TkEm::HWEncoding::CT);
1453       tkems->push_back(tkem);
1454       npho_obj.push_back(tkems->size() - 1);
1455     }
1456     tkemPerBoard->addRegion(npho_obj, board.eta, board.phi);
1457 
1458     nele_obj.clear();
1459     for (const auto &egele : board.egelectron) {
1460       if (egele.hwPt == 0)
1461         continue;
1462 
1463       reco::Candidate::PolarLorentzVector mom(egele.floatPt(), egele.floatVtxEta(), egele.floatVtxPhi(), 0.);
1464 
1465       l1t::TkElectron tkele(reco::Candidate::LorentzVector(mom),
1466                             findRef_(clusterRefMap_, egele.srcCluster, egele),
1467                             edm::refToPtr(egele.srcTrack->track()),
1468                             egele.floatRelIso(l1ct::EGIsoEleObjEmu::IsoType::TkIso));
1469       tkele.setHwQual(egele.hwQual);
1470       tkele.setPFIsol(egele.floatRelIso(l1ct::EGIsoEleObjEmu::IsoType::PfIso));
1471       tkele.setEgBinaryWord(egele.pack(), l1t::TkElectron::HWEncoding::CT);
1472       tkele.setIdScore(egele.floatIDScore());
1473       tkele.setCharge(egele.intCharge());
1474       tkele.setTrkzVtx(egele.floatZ0());
1475       tkeles->push_back(tkele);
1476       nele_obj.push_back(tkeles->size() - 1);
1477     }
1478     tkelePerBoard->addRegion(nele_obj, board.eta, board.phi);
1479   }
1480 
1481   iEvent.put(std::move(tkems), tkEmLabel);
1482   iEvent.put(std::move(tkemPerBoard), tkEmPerBoardLabel);
1483   iEvent.put(std::move(tkeles), tkEleLabel);
1484   iEvent.put(std::move(tkelePerBoard), tkElePerBoardLabel);
1485 }
1486 
1487 std::unique_ptr<std::vector<unsigned>> L1TCorrelatorLayer1Producer::vecSecInput(InputType t) const {
1488   auto v = std::make_unique<std::vector<unsigned>>();
1489   {
1490     switch (t) {
1491       case caloType:
1492         for (const auto &s : event_.decoded.hadcalo)
1493           v->push_back(s.size());
1494         break;
1495       case emcaloType:
1496         for (const auto &s : event_.decoded.emcalo)
1497           v->push_back(s.size());
1498         break;
1499       case trackType:
1500         for (const auto &s : event_.decoded.track)
1501           v->push_back(s.size());
1502         break;
1503       case l1muType:
1504         v->push_back(event_.decoded.muon.size());
1505         break;
1506     }
1507   }
1508   return v;
1509 }
1510 
1511 std::unique_ptr<std::vector<unsigned>> L1TCorrelatorLayer1Producer::vecRegInput(InputType t) const {
1512   auto v = std::make_unique<std::vector<unsigned>>();
1513   for (const auto &reg : event_.pfinputs) {
1514     switch (t) {
1515       case caloType:
1516         v->push_back(reg.hadcalo.size());
1517         break;
1518       case emcaloType:
1519         v->push_back(reg.emcalo.size());
1520         break;
1521       case trackType:
1522         v->push_back(reg.track.size());
1523         break;
1524       case l1muType:
1525         v->push_back(reg.muon.size());
1526         break;
1527     }
1528   }
1529   return v;
1530 }
1531 
1532 std::unique_ptr<std::vector<unsigned>> L1TCorrelatorLayer1Producer::vecOutput(OutputType i, bool usePuppi) const {
1533   auto v = std::make_unique<std::vector<unsigned>>();
1534   for (const auto &reg : event_.out) {
1535     v->push_back(reg.nObj(i, usePuppi));
1536   }
1537   return v;
1538 }
1539 std::pair<unsigned int, unsigned int> L1TCorrelatorLayer1Producer::totAndMax(
1540     const std::vector<unsigned> &perRegion) const {
1541   unsigned int ntot = 0, nmax = 0;
1542   for (unsigned ni : perRegion) {
1543     ntot += ni;
1544     nmax = std::max(nmax, ni);
1545   }
1546   return std::make_pair(ntot, nmax);
1547 }
1548 //define this as a plug-in
1549 #include "FWCore/Framework/interface/MakerMacros.h"
1550 DEFINE_FWK_MODULE(L1TCorrelatorLayer1Producer);