Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:20:10

0001 /* -*- C++ -*-
0002 
0003 Package: L1CaloTrigger
0004 Class: L1NNCaloTauProducer
0005 Frinedly name: The TauMinator
0006 
0007 \class L1NNCaloTauProducer L1NNCaloTauProducer.cc
0008 
0009 Description: 
0010 Perform reconstruction and identification of tau 
0011 candidates at L1 Trigger with a CNN.
0012 
0013 Implementation:
0014 Take as input the HCAL TPs, the ECAL TPs from
0015 l1tEGammaClusterEmuProducer, and the HGCAL TPs
0016 from l1tHGCalTowerProducer and l1tHGCalBackEndLayer2Producer.
0017 Proceed to clustering of trigger towers in NxM
0018 clusters, match to HGcal 3D clusters in the endcap.
0019 Finally apply the CNNs.
0020 
0021 Original Author: Jona Motta
0022 Created: Tue May 30th 2023
0023 
0024 */
0025 
0026 #include <iostream>
0027 #include <vector>
0028 #include <cmath>
0029 
0030 #include "boost/property_tree/ptree.hpp"
0031 #include "boost/property_tree/json_parser.hpp"
0032 
0033 #include "FWCore/Framework/interface/Frameworkfwd.h"
0034 #include "FWCore/Framework/interface/stream/EDProducer.h"
0035 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0036 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0037 #include "FWCore/ServiceRegistry/interface/Service.h"
0038 #include "FWCore/Framework/interface/Event.h"
0039 #include "FWCore/Framework/interface/ESHandle.h"
0040 #include "FWCore/Framework/interface/MakerMacros.h"
0041 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0042 
0043 #include "DataFormats/L1TCalorimeterPhase2/interface/CaloTower.h"
0044 #include "DataFormats/HcalDigi/interface/HcalDigiCollections.h"
0045 #include "DataFormats/L1THGCal/interface/HGCalMulticluster.h"
0046 #include "DataFormats/L1TParticleFlow/interface/PFCluster.h"
0047 #include "DataFormats/L1THGCal/interface/HGCalTower.h"
0048 #include "DataFormats/Math/interface/deltaPhi.h"
0049 #include "DataFormats/L1Trigger/interface/Tau.h"
0050 
0051 #include "CalibFormats/CaloTPG/interface/CaloTPGTranscoder.h"
0052 #include "CalibFormats/CaloTPG/interface/CaloTPGRecord.h"
0053 
0054 #include "L1Trigger/L1THGCal/interface/backend/HGCalTriggerClusterIdentificationBase.h"
0055 #include "L1Trigger/Phase2L1ParticleFlow/interface/HGC3DClusterEgID.h"
0056 #include "L1Trigger/L1TCalorimeter/interface/CaloTools.h"
0057 
0058 #include "PhysicsTools/TensorFlow/interface/TensorFlow.h"
0059 
0060 struct NNmodels_GlobalCache {
0061   std::string CNNmodel_CB_path;
0062   std::string DNNident_CB_path;
0063   std::string DNNcalib_CB_path;
0064 
0065   std::string CNNmodel_CE_path;
0066   std::string DNNident_CE_path;
0067   std::string DNNcalib_CE_path;
0068   std::string FeatScaler_CE_path;
0069   boost::property_tree::ptree FeatScaler_CE;
0070 
0071   tensorflow::GraphDef* CNNmodel_CB;
0072   tensorflow::GraphDef* DNNident_CB;
0073   tensorflow::GraphDef* DNNcalib_CB;
0074 
0075   tensorflow::Session* CNNmodel_CBsession;
0076   tensorflow::Session* DNNident_CBsession;
0077   tensorflow::Session* DNNcalib_CBsession;
0078 
0079   tensorflow::GraphDef* CNNmodel_CE;
0080   tensorflow::GraphDef* DNNident_CE;
0081   tensorflow::GraphDef* DNNcalib_CE;
0082 
0083   tensorflow::Session* CNNmodel_CEsession;
0084   tensorflow::Session* DNNident_CEsession;
0085   tensorflow::Session* DNNcalib_CEsession;
0086 };
0087 
0088 class L1NNCaloTauProducer : public edm::stream::EDProducer<edm::GlobalCache<NNmodels_GlobalCache>> {
0089 public:
0090   explicit L1NNCaloTauProducer(const edm::ParameterSet&, const NNmodels_GlobalCache*);
0091 
0092   static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
0093   static std::unique_ptr<NNmodels_GlobalCache> initializeGlobalCache(const edm::ParameterSet&);
0094   static void globalEndJob(const NNmodels_GlobalCache*){/*do nothing*/};
0095 
0096 private:
0097   //----edm control---
0098   void produce(edm::Event&, const edm::EventSetup&) override;
0099 
0100   //----private functions----
0101   int tower_dIPhi(int& iPhi_1, int& iPhi_2) const;
0102   int tower_dIEta(int& iEta_1, int& iEta_2) const;
0103   int endcap_iphi(float& phi) const;
0104   int endcap_ieta(float& eta) const;
0105   float inputQuantizer(float inputF, float LSB, int nbits);
0106   float inputScaler(float inputF, std::string feature);
0107 
0108   //----tokens and handles----
0109   edm::EDGetTokenT<l1tp2::CaloTowerCollection> l1TowersToken;
0110   edm::Handle<l1tp2::CaloTowerCollection> l1CaloTowerHandle;
0111 
0112   edm::EDGetToken hgcalTowersToken;
0113   edm::Handle<l1t::HGCalTowerBxCollection> hgcalTowersHandle;
0114 
0115   edm::EDGetTokenT<l1t::HGCalMulticlusterBxCollection> HGClusterToken;
0116   edm::Handle<l1t::HGCalMulticlusterBxCollection> HGClusterHandle;
0117 
0118   //----private variables----
0119   enum class UseEmInterp { No, EmOnly, AllKeepHad, AllKeepTot };
0120   UseEmInterp scenario;
0121   StringCutObjectSelector<l1t::HGCalMulticluster> preEmId;
0122   l1tpf::HGC3DClusterEgID VsPuId;
0123 
0124   double EcalEtMinForClustering;
0125   double HcalEtMinForClustering;
0126   double EtMinForSeeding;
0127   double EtaRestriction;
0128   double CB_CE_split;
0129 
0130   double IdWp90_CB;
0131   double IdWp95_CB;
0132   double IdWp99_CB;
0133 
0134   double IdWp90_CE;
0135   double IdWp95_CE;
0136   double IdWp99_CE;
0137 
0138   // hardoced dimensions of the tower clusters
0139   const int seedIdx = 22;
0140   const int IEta_dim = 5;
0141   const int IPhi_dim = 9;
0142   const float Eta_dim = 0.2;
0143   const float Phi_dim = 0.4;
0144   const float Eta_dim_seed = 0.35;
0145   const float Phi_dim_seed = 0.7;
0146   const float Eta_limit = 2.83;
0147 
0148   // classes of objects used only in this producer
0149   class SimpleTowerHit {
0150   public:
0151     float towerEta = -99.;
0152     float towerPhi = -99.;
0153     float towerEm = 0.;
0154     float towerHad = 0.;
0155     float l1egTowerEt = 0.;
0156     float towerEt = 0.;
0157     int towerIeta = -99;
0158     int towerIphi = -99;
0159     bool isBarrel = true;
0160     bool stale = false;
0161     bool stale4seed = false;
0162   };
0163 
0164   class SimpleTowerCluster {
0165   public:
0166     bool barrelSeeded = false;
0167     int seedIeta = -99;
0168     int seedIphi = -99;
0169     float seedEta = -99.;
0170     float seedPhi = -99.;
0171     float rawEt = 0.;
0172     float IDscore = -99.;
0173     float calibPt = -99.;
0174 
0175     std::vector<SimpleTowerHit> towerHits;
0176 
0177     void InitHits(int N, int M) { towerHits.resize(N * M); }
0178   };
0179 
0180   class SimpleHGCluster {
0181   public:
0182     float pt = -99.;
0183     float eta = -99.;
0184     float phi = -99.;
0185     float showerlength = -99.;
0186     float coreshowerlength = -99.;
0187     float spptot = -99.;
0188     float szz = -99.;
0189     float srrtot = -99.;
0190     float meanz = -99.;
0191     bool stale = false;
0192   };
0193 };
0194 
0195 /*
0196 ████████ ██   ██ ██████     ████████  █████  ██   ██ ███    ███ ██ ███    ██  █████  ████████  ██████  ██████  
0197    ██    ██   ██ ██            ██    ██   ██ ██   ██ ████  ████ ██ ████   ██ ██   ██    ██    ██    ██ ██   ██ 
0198    ██    ███████ █████         ██    ███████ ██   ██ ██ ████ ██ ██ ██ ██  ██ ███████    ██    ██    ██ ██████  
0199    ██    ██   ██ ██            ██    ██   ██ ██   ██ ██  ██  ██ ██ ██  ██ ██ ██   ██    ██    ██    ██ ██   ██ 
0200    ██    ██   ██ ██████        ██    ██   ██ ███████ ██      ██ ██ ██   ████ ██   ██    ██     ██████  ██    ██
0201 */
0202 
0203 std::unique_ptr<NNmodels_GlobalCache> L1NNCaloTauProducer::initializeGlobalCache(const edm::ParameterSet& iConfig) {
0204   edm::LogInfo("Initialization") << "Init NN models Global Cache " << std::endl;
0205 
0206   std::unique_ptr<NNmodels_GlobalCache> GlobalCache(new NNmodels_GlobalCache);
0207 
0208   GlobalCache->CNNmodel_CB_path = iConfig.getParameter<std::string>("CNNmodel_CB_path");
0209   GlobalCache->DNNident_CB_path = iConfig.getParameter<std::string>("DNNident_CB_path");
0210   GlobalCache->DNNcalib_CB_path = iConfig.getParameter<std::string>("DNNcalib_CB_path");
0211   GlobalCache->CNNmodel_CE_path = iConfig.getParameter<std::string>("CNNmodel_CE_path");
0212   GlobalCache->DNNident_CE_path = iConfig.getParameter<std::string>("DNNident_CE_path");
0213   GlobalCache->DNNcalib_CE_path = iConfig.getParameter<std::string>("DNNcalib_CE_path");
0214   GlobalCache->FeatScaler_CE_path = iConfig.getParameter<std::string>("FeatScaler_CE_path");
0215 
0216   // Create sessions for Tensorflow inferece
0217   (GlobalCache->CNNmodel_CB) = tensorflow::loadGraphDef(edm::FileInPath((GlobalCache->CNNmodel_CB_path)).fullPath());
0218   (GlobalCache->CNNmodel_CBsession) = tensorflow::createSession((GlobalCache->CNNmodel_CB));
0219 
0220   (GlobalCache->DNNident_CB) = tensorflow::loadGraphDef(edm::FileInPath((GlobalCache->DNNident_CB_path)).fullPath());
0221   (GlobalCache->DNNident_CBsession) = tensorflow::createSession((GlobalCache->DNNident_CB));
0222 
0223   (GlobalCache->DNNcalib_CB) = tensorflow::loadGraphDef(edm::FileInPath((GlobalCache->DNNcalib_CB_path)).fullPath());
0224   (GlobalCache->DNNcalib_CBsession) = tensorflow::createSession((GlobalCache->DNNcalib_CB));
0225 
0226   (GlobalCache->CNNmodel_CE) = tensorflow::loadGraphDef(edm::FileInPath((GlobalCache->CNNmodel_CE_path)).fullPath());
0227   (GlobalCache->CNNmodel_CEsession) = tensorflow::createSession((GlobalCache->CNNmodel_CE));
0228 
0229   (GlobalCache->DNNident_CE) = tensorflow::loadGraphDef(edm::FileInPath((GlobalCache->DNNident_CE_path)).fullPath());
0230   (GlobalCache->DNNident_CEsession) = tensorflow::createSession((GlobalCache->DNNident_CE));
0231 
0232   (GlobalCache->DNNcalib_CE) = tensorflow::loadGraphDef(edm::FileInPath((GlobalCache->DNNcalib_CE_path)).fullPath());
0233   (GlobalCache->DNNcalib_CEsession) = tensorflow::createSession((GlobalCache->DNNcalib_CE));
0234 
0235   // Read features scaler
0236   boost::property_tree::read_json(edm::FileInPath((GlobalCache->FeatScaler_CE_path)).fullPath(),
0237                                   (GlobalCache->FeatScaler_CE));
0238 
0239   return GlobalCache;
0240 }
0241 
0242 // ----Constructor and Destructor -----
0243 L1NNCaloTauProducer::L1NNCaloTauProducer(const edm::ParameterSet& iConfig, const NNmodels_GlobalCache* globalCache)
0244     : l1TowersToken(consumes<l1tp2::CaloTowerCollection>(iConfig.getParameter<edm::InputTag>("l1CaloTowers"))),
0245       hgcalTowersToken(consumes<l1t::HGCalTowerBxCollection>(iConfig.getParameter<edm::InputTag>("hgcalTowers"))),
0246 
0247       HGClusterToken(
0248           consumes<l1t::HGCalMulticlusterBxCollection>(iConfig.getParameter<edm::InputTag>("HgcalClusters"))),
0249       scenario(UseEmInterp::No),
0250       preEmId(iConfig.getParameter<std::string>("preEmId")),
0251       VsPuId(iConfig.getParameter<edm::ParameterSet>("VsPuId")),
0252 
0253       EcalEtMinForClustering(iConfig.getParameter<double>("EcalEtMinForClustering")),
0254       HcalEtMinForClustering(iConfig.getParameter<double>("HcalEtMinForClustering")),
0255       EtMinForSeeding(iConfig.getParameter<double>("EtMinForSeeding")),
0256       EtaRestriction(iConfig.getParameter<double>("EtaRestriction")),
0257       CB_CE_split(iConfig.getParameter<double>("CB_CE_split")),
0258 
0259       IdWp90_CB(iConfig.getParameter<double>("IdWp90_CB")),
0260       IdWp95_CB(iConfig.getParameter<double>("IdWp95_CB")),
0261       IdWp99_CB(iConfig.getParameter<double>("IdWp99_CB")),
0262 
0263       IdWp90_CE(iConfig.getParameter<double>("IdWp90_CE")),
0264       IdWp95_CE(iConfig.getParameter<double>("IdWp95_CE")),
0265       IdWp99_CE(iConfig.getParameter<double>("IdWp99_CE")) {
0266   // Initialize HGCAL BDTs
0267   if (!VsPuId.method().empty()) {
0268     VsPuId.prepareTMVA();
0269   }
0270 
0271   // Create produced outputs
0272   produces<BXVector<l1t::Tau>>("L1NNCaloTauCollectionBXV");
0273 
0274   // Settings output
0275   edm::LogInfo("Settings") << "EtaRestriction = " << EtaRestriction << " , CB_CE_split = " << CB_CE_split
0276                            << " , EtMinForSeeding = " << EtMinForSeeding
0277                            << " , HcalTpEtMin = " << HcalEtMinForClustering
0278                            << " , EcalTpEtMin = " << EcalEtMinForClustering << std::endl;
0279 }
0280 
0281 void L1NNCaloTauProducer::produce(edm::Event& iEvent, const edm::EventSetup& eSetup) {
0282   // Output collection
0283   std::unique_ptr<BXVector<l1t::Tau>> L1NNCaloTauCollectionBXV(new l1t::TauBxCollection);
0284 
0285   // Create and Fill collection of all calotowers and their attributes
0286   std::vector<SimpleTowerHit> l1CaloTowers;
0287 
0288   iEvent.getByToken(l1TowersToken, l1CaloTowerHandle);
0289   int warnings = 0;
0290   for (auto& hit : *l1CaloTowerHandle.product()) {
0291     // Skip this weird towers and store warning
0292     if (hit.towerIEta() == -1016 && hit.towerIPhi() == -962) {
0293       warnings += 1;
0294       continue;
0295     }
0296 
0297     SimpleTowerHit l1Hit;
0298     l1Hit.isBarrel = true;
0299     l1Hit.l1egTowerEt = hit.l1egTowerEt();
0300     l1Hit.towerEta = hit.towerEta();
0301     l1Hit.towerPhi = hit.towerPhi();
0302     l1Hit.towerEm = hit.ecalTowerEt();
0303     l1Hit.towerHad = hit.hcalTowerEt();
0304     l1Hit.towerEt = l1Hit.towerEm + l1Hit.towerHad + l1Hit.l1egTowerEt;
0305     l1Hit.towerIeta = hit.towerIEta();
0306     l1Hit.towerIphi = hit.towerIPhi();
0307 
0308     l1CaloTowers.push_back(l1Hit);
0309   }
0310   if (warnings != 0) {
0311     edm::LogWarning("BrokenTowers") << " ** WARNING : FOUND " << warnings
0312                                     << " TOWERS WITH towerIeta=-1016 AND towerIphi=-962" << std::endl;
0313   }
0314 
0315   iEvent.getByToken(hgcalTowersToken, hgcalTowersHandle);
0316   for (auto& hit : *hgcalTowersHandle.product()) {
0317     SimpleTowerHit l1Hit;
0318     l1Hit.isBarrel = false;
0319     l1Hit.l1egTowerEt = 0.0;
0320     l1Hit.towerEta = hit.eta();
0321     l1Hit.towerPhi = hit.phi();
0322     l1Hit.towerEm = hit.etEm();
0323     l1Hit.towerHad = hit.etHad();
0324     l1Hit.towerEt = l1Hit.towerEm + l1Hit.towerHad;
0325     l1Hit.towerIeta = endcap_ieta(l1Hit.towerEta);  // computed and filled but not used
0326     l1Hit.towerIphi = endcap_iphi(l1Hit.towerPhi);  // computed and filled but not used
0327 
0328     l1CaloTowers.push_back(l1Hit);
0329   }
0330 
0331   // Sort the ECAL+HCAL+L1EGs tower sums based on total ET
0332   std::sort(begin(l1CaloTowers), end(l1CaloTowers), [](const SimpleTowerHit& a, SimpleTowerHit& b) {
0333     return a.towerEt > b.towerEt;
0334   });
0335 
0336   // Create and Fill the collection of 3D clusters and their attributes
0337   std::vector<SimpleHGCluster> AllHGClusters;
0338   iEvent.getByToken(HGClusterToken, HGClusterHandle);
0339 
0340   for (auto cl3dIt = HGClusterHandle->begin(0); cl3dIt != HGClusterHandle->end(0); ++cl3dIt) {
0341     auto& cl3d = *cl3dIt;
0342 
0343     // Implement cl3d PU ID as done in
0344     // https://github.com/cms-sw/cmssw/blob/master/L1Trigger/Phase2L1ParticleFlow/plugins/PFClusterProducerFromHGC3DClusters.cc#L120
0345     bool isEM = preEmId(*cl3dIt);
0346     l1t::PFCluster cluster(cl3d.pt(), cl3d.eta(), cl3d.phi(), cl3d.hOverE());
0347     if (scenario == UseEmInterp::EmOnly)  // for emID objs, use EM interp as pT and set H = 0
0348     {
0349       if (isEM) {
0350         float pt_new = cl3d.iPt(l1t::HGCalMulticluster::EnergyInterpretation::EM);
0351         float hoe_new = 0.;
0352         cluster = l1t::PFCluster(pt_new, cl3d.eta(), cl3d.phi(), hoe_new, isEM);
0353       }
0354     } else if (scenario == UseEmInterp::AllKeepHad)  // for all objs, replace EM part with EM interp, preserve H
0355     {
0356       float had_old = cl3d.pt() - cluster.emEt();
0357       float em_new = cl3d.iPt(l1t::HGCalMulticluster::EnergyInterpretation::EM);
0358       float pt_new = had_old + em_new;
0359       float hoe_new = em_new > 0 ? (had_old / em_new) : -1;
0360       cluster = l1t::PFCluster(pt_new, cl3d.eta(), cl3d.phi(), hoe_new, isEM);
0361     } else if (scenario == UseEmInterp::AllKeepTot)  // for all objs, replace EM part with EM interp, preserve pT
0362     {
0363       float em_new = cl3d.iPt(l1t::HGCalMulticluster::EnergyInterpretation::EM);
0364       float hoe_new = em_new > 0 ? (cl3d.pt() / em_new - 1) : -1;
0365       cluster = l1t::PFCluster(cl3d.pt(), cl3d.eta(), cl3d.phi(), hoe_new, isEM);
0366     }
0367 
0368     if (!VsPuId.method().empty()) {
0369       int id = VsPuId.passID(*cl3dIt, cluster);
0370       if (!id) {
0371         continue;
0372       }  // skip cl3d if it does not pass puid
0373     }
0374 
0375     SimpleHGCluster HGCluster;
0376     HGCluster.pt = cl3d.pt();
0377     HGCluster.eta = cl3d.eta();
0378     HGCluster.phi = cl3d.phi();
0379     HGCluster.showerlength = cl3d.showerLength();
0380     HGCluster.coreshowerlength = cl3d.coreShowerLength();
0381     HGCluster.spptot = cl3d.sigmaPhiPhiTot();
0382     HGCluster.szz = cl3d.sigmaZZ();
0383     HGCluster.srrtot = cl3d.sigmaRRTot();
0384     HGCluster.meanz = cl3d.zBarycenter();
0385 
0386     AllHGClusters.push_back(HGCluster);
0387   }
0388 
0389   // Order the collection in pt (the input to the GCT will be pt ordered)
0390   std::sort(begin(AllHGClusters), end(AllHGClusters), [](const SimpleHGCluster& a, SimpleHGCluster& b) {
0391     return a.pt > b.pt;
0392   });
0393 
0394   // Make NxM TowerClusters and HGClusters collections for TauMinator
0395   std::vector<SimpleTowerCluster> l1TowerClustersNxM_CB;
0396   std::vector<SimpleTowerCluster> l1TowerClustersNxM_CE;
0397   std::vector<SimpleHGCluster> HGClusters;
0398 
0399   // Supporting collection of endcap clusters before cl3d matching
0400   std::vector<SimpleTowerCluster> AllL1TowerClustersNxM_CE;
0401 
0402   bool caloTauSeedingFinished = false;
0403   // Loop for seeding of clNxM objects
0404   while (!caloTauSeedingFinished) {
0405     SimpleTowerCluster clNxM;
0406     clNxM.InitHits(IEta_dim, IPhi_dim);
0407     bool seeded = false;
0408 
0409     for (auto& l1CaloTower : l1CaloTowers) {
0410       // Skip seeding in towers that would make the cluster extend in HF
0411       // Skip l1CaloTowers which are already used by this clusters' mask
0412       if (abs(l1CaloTower.towerEta) > Eta_limit || abs(l1CaloTower.towerEta) > EtaRestriction ||
0413           l1CaloTower.stale4seed) {
0414         continue;
0415       }
0416 
0417       // If not seded do the seeding
0418       if (!seeded) {
0419         // The leading unused tower has ET < min, stop jet clustering
0420         if (l1CaloTower.towerEt < EtMinForSeeding) {
0421           caloTauSeedingFinished = true;
0422           continue;
0423         }
0424 
0425         clNxM.seedIeta = l1CaloTower.towerIeta;
0426         clNxM.seedIphi = l1CaloTower.towerIphi;
0427         clNxM.seedEta = l1CaloTower.towerEta;
0428         clNxM.seedPhi = l1CaloTower.towerPhi;
0429         if (l1CaloTower.isBarrel) {
0430           clNxM.barrelSeeded = true;
0431         }
0432 
0433         clNxM.rawEt += l1CaloTower.towerEt;
0434         clNxM.towerHits[seedIdx] = l1CaloTower;
0435         l1CaloTower.stale4seed = true;
0436         l1CaloTower.stale = true;
0437         seeded = true;
0438 
0439         continue;
0440       }
0441 
0442       int d_iEta = 99;
0443       int d_iPhi = 99;
0444       float d_Eta = 99.;
0445       float d_Phi = 99.;
0446       // Ese iEta/iPhi comparisons in the barrel and eta/phi in HGCal
0447       if (clNxM.barrelSeeded && l1CaloTower.isBarrel) {
0448         d_iEta = tower_dIEta(l1CaloTower.towerIeta, clNxM.seedIeta);
0449         d_iPhi = tower_dIPhi(l1CaloTower.towerIphi, clNxM.seedIphi);
0450       } else {
0451         d_Eta = l1CaloTower.towerEta - clNxM.seedEta;
0452         d_Phi = reco::deltaPhi(l1CaloTower.towerPhi, clNxM.seedPhi);
0453       }
0454 
0455       // Stale tower for seeding if it would lead to overalp between clusters
0456       if ((abs(d_iEta) <= IEta_dim - 1 && abs(d_iPhi) <= IPhi_dim - 1) ||
0457           (abs(d_Eta) < Eta_dim_seed && abs(d_Phi) < Phi_dim_seed)) {
0458         l1CaloTower.stale4seed = true;
0459       }
0460 
0461     }  // End for loop over TPs
0462 
0463     // Pushback seeds split in barrel and endcap
0464     if (seeded) {
0465       if (abs(clNxM.seedEta) < CB_CE_split) {
0466         l1TowerClustersNxM_CB.push_back(clNxM);
0467       } else {
0468         AllL1TowerClustersNxM_CE.push_back(clNxM);
0469       }
0470     }
0471 
0472   }  // End while loop of TowerClusters seeding
0473 
0474   // Loop for barrel NxM TowerClusters clustering starting from the seeds
0475   for (auto& clNxM : l1TowerClustersNxM_CB) {
0476     for (auto& l1CaloTower : l1CaloTowers) {
0477       // Skip l1CaloTowers which are already used
0478       if (l1CaloTower.stale) {
0479         continue;
0480       }
0481 
0482       int d_iEta = 99;
0483       int d_iPhi = 99;
0484       float d_Eta = 99.;
0485       float d_Phi = 99.;
0486       int hitIdx = 99.;
0487       // Use iEta/iPhi comparisons in the barrel and use eta/phi in HGCal
0488       if (l1CaloTower.isBarrel) {
0489         d_iEta = tower_dIEta(l1CaloTower.towerIeta, clNxM.seedIeta);
0490         d_iPhi = tower_dIPhi(l1CaloTower.towerIphi, clNxM.seedIphi);
0491 
0492         hitIdx = d_iEta * IPhi_dim + d_iPhi + seedIdx;
0493       } else {
0494         d_Eta = l1CaloTower.towerEta - clNxM.seedEta;
0495         d_Phi = reco::deltaPhi(l1CaloTower.towerPhi, clNxM.seedPhi);
0496 
0497         int dieta = d_Eta / 0.0807;  // minimal difference in endcap is 0.0808
0498         int diphi = d_Phi / 0.0872;
0499         hitIdx = dieta * IPhi_dim + diphi + seedIdx;
0500       }
0501 
0502       // Cluster all towers in a NxM towers mask
0503       if ((abs(d_iEta) <= (IEta_dim - 1) / 2 && abs(d_iPhi) <= (IPhi_dim - 1) / 2) ||
0504           (abs(d_Eta) < Eta_dim && abs(d_Phi) < Phi_dim)) {
0505         clNxM.rawEt += l1CaloTower.towerEt;
0506         clNxM.towerHits[hitIdx] = l1CaloTower;
0507         l1CaloTower.stale = true;
0508       }
0509 
0510     }  // End for loop over TPs
0511 
0512   }  // End while loop of barrel TowerClusters creation
0513 
0514   // In the endcap cross-loop over clNxM and cl3d to match them
0515   // (we can do it before full clustering just using the seed info)
0516   for (auto& clNxM : AllL1TowerClustersNxM_CE) {
0517     bool matched = false;
0518     for (auto& HGCluster : AllHGClusters) {
0519       // In case the clNxM or HGCluster have already been matched just continue through the list to the end
0520       // only use cl3ds above 4GeV
0521       if (matched || HGCluster.stale || HGCluster.pt < 4) {
0522         continue;
0523       }
0524 
0525       float d_Eta = HGCluster.eta - clNxM.seedEta;
0526       float d_Phi = reco::deltaPhi(HGCluster.phi, clNxM.seedPhi);
0527       float d_R2 = pow(d_Eta, 2) + pow(d_Phi, 2);
0528 
0529       if (d_R2 < 0.25) {
0530         HGCluster.stale = true;
0531         HGClusters.push_back(HGCluster);
0532         l1TowerClustersNxM_CE.push_back(clNxM);
0533         matched = true;
0534       }
0535 
0536     }  // End for loop over cl3ds
0537 
0538   }  // End for loop over clNxM
0539 
0540   // Loop for endcap matched NxM TowerClusters clustering starting from the seeds just found
0541   for (auto& clNxM : l1TowerClustersNxM_CE) {
0542     for (auto& l1CaloTower : l1CaloTowers) {
0543       // Skip l1CaloTowers which are already used
0544       if (l1CaloTower.stale) {
0545         continue;
0546       }
0547 
0548       int d_iEta = 99;
0549       int d_iPhi = 99;
0550       float d_Eta = 99.;
0551       float d_Phi = 99.;
0552       int hitIdx = 99.;
0553       // Use iEta/iPhi comparisons in the endcap and use eta/phi in HGCal
0554       if (l1CaloTower.isBarrel) {
0555         d_iEta = tower_dIEta(l1CaloTower.towerIeta, clNxM.seedIeta);
0556         d_iPhi = tower_dIPhi(l1CaloTower.towerIphi, clNxM.seedIphi);
0557 
0558         hitIdx = d_iEta * IPhi_dim + d_iPhi + seedIdx;
0559       } else {
0560         d_Eta = l1CaloTower.towerEta - clNxM.seedEta;
0561         d_Phi = reco::deltaPhi(l1CaloTower.towerPhi, clNxM.seedPhi);
0562 
0563         int dieta = d_Eta / 0.0807;  // minimal difference in endcap is 0.0808
0564         int diphi = d_Phi / 0.0872;
0565         hitIdx = dieta * IPhi_dim + diphi + seedIdx;
0566       }
0567 
0568       // Cluster all towers in a NxM towers mask
0569       if ((abs(d_iEta) <= (IEta_dim - 1) / 2 && abs(d_iPhi) <= (IPhi_dim - 1) / 2) ||
0570           (abs(d_Eta) < Eta_dim && abs(d_Phi) < Phi_dim)) {
0571         clNxM.rawEt += l1CaloTower.towerEt;
0572         clNxM.towerHits[hitIdx] = l1CaloTower;
0573         l1CaloTower.stale = true;
0574       }
0575 
0576     }  // End for loop over TPs
0577 
0578   }  // End while loop of endcap TowerClusters creation
0579 
0580   // Barrel TauMinator application
0581   tensorflow::setLogging("2");
0582   int batchSize_CB = (int)(l1TowerClustersNxM_CB.size());
0583   tensorflow::TensorShape imageShape_CB({batchSize_CB, IEta_dim, IPhi_dim, 2});
0584   tensorflow::TensorShape positionShape_CB({batchSize_CB, 2});
0585   tensorflow::Tensor TowerClusterImage_CB(tensorflow::DT_FLOAT, imageShape_CB);
0586   tensorflow::Tensor TowerClusterPosition_CB(tensorflow::DT_FLOAT, positionShape_CB);
0587 
0588   int clIdx = 0;
0589   for (auto& clNxM : l1TowerClustersNxM_CB) {
0590     // Fill inputs for Tensorflow inference
0591     for (int eta = 0; eta < IEta_dim; ++eta) {
0592       for (int phi = 0; phi < IPhi_dim; ++phi) {
0593         int towerIdx = eta * IPhi_dim + phi;
0594         TowerClusterImage_CB.tensor<float, 4>()(clIdx, eta, phi, 0) =
0595             inputQuantizer(clNxM.towerHits[towerIdx].l1egTowerEt + clNxM.towerHits[towerIdx].towerEm, 0.25, 10);
0596         TowerClusterImage_CB.tensor<float, 4>()(clIdx, eta, phi, 1) =
0597             inputQuantizer(clNxM.towerHits[towerIdx].towerHad, 0.25, 10);
0598       }
0599     }
0600 
0601     TowerClusterPosition_CB.tensor<float, 2>()(clIdx, 0) = clNxM.seedEta;
0602     TowerClusterPosition_CB.tensor<float, 2>()(clIdx, 1) = clNxM.seedPhi;
0603 
0604     clIdx++;  // Increase batch index
0605   }
0606 
0607   if (batchSize_CB >
0608       0)  // from CMSSW_14_0_X tensorflow does not seem to be able to deal with a tensor of dimension 0 anymore
0609   {
0610     // Apply CNN model
0611     tensorflow::NamedTensorList CNNmodel_CBinputList = {{"TowerClusterImage", TowerClusterImage_CB},
0612                                                         {"TowerClusterPosition", TowerClusterPosition_CB}};
0613     std::vector<tensorflow::Tensor> CNNmodel_CBoutputs;
0614     tensorflow::run((globalCache()->CNNmodel_CBsession),
0615                     CNNmodel_CBinputList,
0616                     {"TauMinator_CB_conv/middleMan/concat"},
0617                     &CNNmodel_CBoutputs);
0618     tensorflow::NamedTensorList DNN_CBinputsList = {{"middleMan", CNNmodel_CBoutputs[0]}};
0619 
0620     // Apply DNN for identification
0621     std::vector<tensorflow::Tensor> DNN_CBoutputsIdent;
0622     tensorflow::run((globalCache()->DNNident_CBsession),
0623                     DNN_CBinputsList,
0624                     {"TauMinator_CB_ident/sigmoid_IDout/Sigmoid"},
0625                     &DNN_CBoutputsIdent);
0626 
0627     // Apply DNN for calibration
0628     std::vector<tensorflow::Tensor> DNN_CBoutputsCalib;
0629     tensorflow::run((globalCache()->DNNcalib_CBsession),
0630                     DNN_CBinputsList,
0631                     {"TauMinator_CB_calib/LIN_DNNout/Relu"},
0632                     &DNN_CBoutputsCalib);
0633 
0634     // Fill TauMinator output variables of TowerClusters
0635     clIdx = 0;
0636     for (auto& clNxM : l1TowerClustersNxM_CB) {
0637       clNxM.IDscore = DNN_CBoutputsIdent[0].matrix<float>()(0, clIdx);
0638       clNxM.calibPt = DNN_CBoutputsCalib[0].matrix<float>()(0, clIdx);
0639       clIdx++;  // Increase batch index
0640     }
0641   }
0642 
0643   // Endcap TauMinator application
0644   int batchSize_CE = (int)(l1TowerClustersNxM_CE.size());
0645   tensorflow::TensorShape imageShape_CE({batchSize_CE, IEta_dim, IPhi_dim, 2});
0646   tensorflow::TensorShape positionShape_CE({batchSize_CE, 2});
0647   tensorflow::TensorShape cl3dfeatShape_CE({batchSize_CE, 8});
0648   tensorflow::Tensor TowerClusterImage_CE(tensorflow::DT_FLOAT, imageShape_CE);
0649   tensorflow::Tensor TowerClusterPosition_CE(tensorflow::DT_FLOAT, positionShape_CE);
0650   tensorflow::Tensor Cl3dShapeFeatures_CE(tensorflow::DT_FLOAT, cl3dfeatShape_CE);
0651 
0652   clIdx = 0;
0653   for (auto& clNxM : l1TowerClustersNxM_CE) {
0654     // Indexing of cl3ds is the same as the one of clNxMs
0655     SimpleHGCluster HGClu = HGClusters[clIdx];
0656 
0657     // Fill inputs for Tensorflow inference
0658     for (int eta = 0; eta < IEta_dim; ++eta) {
0659       for (int phi = 0; phi < IPhi_dim; ++phi) {
0660         int towerIdx = eta * IPhi_dim + phi;
0661         TowerClusterImage_CE.tensor<float, 4>()(clIdx, eta, phi, 0) =
0662             inputQuantizer(clNxM.towerHits[towerIdx].l1egTowerEt + clNxM.towerHits[towerIdx].towerEm, 0.25, 10);
0663         TowerClusterImage_CE.tensor<float, 4>()(clIdx, eta, phi, 1) =
0664             inputQuantizer(clNxM.towerHits[towerIdx].towerHad, 0.25, 10);
0665       }
0666     }
0667 
0668     TowerClusterPosition_CE.tensor<float, 2>()(clIdx, 0) = clNxM.seedEta;
0669     TowerClusterPosition_CE.tensor<float, 2>()(clIdx, 1) = clNxM.seedPhi;
0670 
0671     Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 0) = inputScaler(inputQuantizer(HGClu.pt, 0.25, 14), "pt");
0672     Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 1) =
0673         inputScaler(inputQuantizer(abs(HGClu.eta) - 1.321, 0.004, 9), "eta");
0674     Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 2) = inputScaler(HGClu.showerlength, "showerlength");
0675     Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 3) = inputScaler(HGClu.coreshowerlength, "coreshowerlength");
0676     Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 4) =
0677         inputScaler(inputQuantizer(HGClu.spptot, 0.0000153, 16), "spptot");
0678     Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 5) = inputScaler(inputQuantizer(HGClu.szz, 0.00153, 16), "szz");
0679     Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 6) =
0680         inputScaler(inputQuantizer(HGClu.srrtot, 0.0000153, 16), "srrtot");
0681     Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 7) =
0682         inputScaler(inputQuantizer(10 * (abs(HGClu.meanz) - 321.05), 0.5, 12), "meanz");
0683 
0684     clIdx++;  // Increase batch index
0685   }
0686 
0687   if (batchSize_CE >
0688       0)  // from CMSSW_14_0_X tensorflow does not seem to be able to deal with a tensor of dimension 0 anymore
0689   {
0690     // Apply CNN model
0691     tensorflow::NamedTensorList CNNmodel_CEinputList = {{"TowerClusterImage", TowerClusterImage_CE},
0692                                                         {"TowerClusterPosition", TowerClusterPosition_CE},
0693                                                         {"AssociatedCl3dFeatures", Cl3dShapeFeatures_CE}};
0694     std::vector<tensorflow::Tensor> CNNmodel_CEoutputs;
0695     tensorflow::run((globalCache()->CNNmodel_CEsession),
0696                     CNNmodel_CEinputList,
0697                     {"TauMinator_CE_conv/middleMan/concat"},
0698                     &CNNmodel_CEoutputs);
0699     tensorflow::NamedTensorList DNN_CEinputsList = {{"middleMan", CNNmodel_CEoutputs[0]}};
0700 
0701     // Apply DNN for identification
0702     std::vector<tensorflow::Tensor> DNN_CEoutputsIdent;
0703     tensorflow::run((globalCache()->DNNident_CEsession),
0704                     DNN_CEinputsList,
0705                     {"TauMinator_CE_ident/sigmoid_IDout/Sigmoid"},
0706                     &DNN_CEoutputsIdent);
0707 
0708     // Apply DNN for calibration
0709     std::vector<tensorflow::Tensor> DNN_CEoutputsCalib;
0710     tensorflow::run((globalCache()->DNNcalib_CEsession),
0711                     DNN_CEinputsList,
0712                     {"TauMinator_CE_calib/LIN_DNNout/Relu"},
0713                     &DNN_CEoutputsCalib);
0714 
0715     // Fill TauMinator output variables of TowerClusters
0716     clIdx = 0;
0717     for (auto& clNxM : l1TowerClustersNxM_CE) {
0718       clNxM.IDscore = DNN_CEoutputsIdent[0].matrix<float>()(0, clIdx);
0719       clNxM.calibPt = DNN_CEoutputsCalib[0].matrix<float>()(0, clIdx);
0720       clIdx++;  // Increase batch index
0721     }
0722   }
0723 
0724   // Fill the output collection of L1 taus
0725   for (auto& clNxM : l1TowerClustersNxM_CB) {
0726     // Apply eta restriction
0727     if (abs(clNxM.seedEta) > EtaRestriction) {
0728       continue;
0729     }
0730 
0731     // Assign increasing quality to higher scoring candidates
0732     int quality = 0;
0733     // 99% WP
0734     if (clNxM.IDscore > IdWp99_CB) {
0735       quality = 1;
0736     }
0737     // 95% WP
0738     if (clNxM.IDscore > IdWp95_CB) {
0739       quality = 2;
0740     }
0741     // 90% WP
0742     if (clNxM.IDscore > IdWp90_CB) {
0743       quality = 3;
0744     }
0745 
0746     reco::Candidate::PolarLorentzVector tauP4 =
0747         reco::Candidate::PolarLorentzVector(clNxM.calibPt, clNxM.seedEta, clNxM.seedPhi, 0);
0748 
0749     // store ID score multiplied by 10E4 to have good precision even using the Phase1 tau int iso format
0750     // (this is stored just in case for possible additional offline studies)
0751     // tau initialisation =  (p4,    pt,            eta,           phi,           qual,    iso)
0752     l1t::Tau l1Tau = l1t::Tau(tauP4, clNxM.calibPt, clNxM.seedEta, clNxM.seedPhi, quality, clNxM.IDscore * 10E4);
0753     l1Tau.setTowerIEta(clNxM.seedIeta);
0754     l1Tau.setTowerIPhi(clNxM.seedIphi);
0755     l1Tau.setRawEt(clNxM.rawEt);
0756 
0757     L1NNCaloTauCollectionBXV->push_back(0, l1Tau);
0758   }
0759 
0760   for (auto& clNxM : l1TowerClustersNxM_CE) {
0761     // Apply eta restriction
0762     if (abs(clNxM.seedEta) > EtaRestriction) {
0763       continue;
0764     }
0765 
0766     // Assign increasing quality to higher scoring candidates
0767     int quality = 0;
0768     // 99% WP
0769     if (clNxM.IDscore > IdWp99_CE) {
0770       quality = 1;
0771     }
0772     // 95% WP
0773     if (clNxM.IDscore > IdWp95_CE) {
0774       quality = 2;
0775     }
0776     // 90% WP
0777     if (clNxM.IDscore > IdWp90_CE) {
0778       quality = 3;
0779     }
0780 
0781     reco::Candidate::PolarLorentzVector tauP4 =
0782         reco::Candidate::PolarLorentzVector(clNxM.calibPt, clNxM.seedEta, clNxM.seedPhi, 0);
0783 
0784     // store ID score multiplied by 10E4 to have good precision even using the Phase1 tau int iso format
0785     // (this is stored just in case for possible additional offline studies)
0786     // tau initialisation =  (p4,    pt,            eta,           phi,           qual,    iso)
0787     l1t::Tau l1Tau = l1t::Tau(tauP4, clNxM.calibPt, clNxM.seedEta, clNxM.seedPhi, quality, clNxM.IDscore * 10E4);
0788     l1Tau.setTowerIEta(clNxM.seedIeta);
0789     l1Tau.setTowerIPhi(clNxM.seedIphi);
0790     l1Tau.setRawEt(clNxM.rawEt);
0791 
0792     L1NNCaloTauCollectionBXV->push_back(0, l1Tau);
0793   }
0794 
0795   // Fill output
0796   iEvent.put(std::move(L1NNCaloTauCollectionBXV), "L1NNCaloTauCollectionBXV");
0797 
0798 }  // End of produce function
0799 
0800 int L1NNCaloTauProducer::tower_dIPhi(int& iPhi_1, int& iPhi_2) const {
0801   const int PI = 36;
0802   int result = iPhi_1 - iPhi_2;
0803   if (result > PI) {
0804     result -= 2 * PI;
0805   }
0806   if (result <= -PI) {
0807     result += 2 * PI;
0808   }
0809   return result;
0810 }
0811 
0812 int L1NNCaloTauProducer::tower_dIEta(int& iEta_1, int& iEta_2) const {
0813   if (iEta_1 * iEta_2 > 0) {
0814     return iEta_1 - iEta_2;
0815   } else {
0816     if (iEta_1 > 0) {
0817       return iEta_1 - iEta_2 - 1;
0818     } else {
0819       return iEta_1 - iEta_2 + 1;
0820     }
0821   }
0822 }
0823 
0824 int L1NNCaloTauProducer::endcap_iphi(float& phi) const {
0825   const float phi_step = 0.0872664;
0826   if (phi > 0) {
0827     return floor(phi / phi_step) + 1;
0828   } else {
0829     return floor(phi / phi_step) + 73;
0830   }
0831 }
0832 
0833 int L1NNCaloTauProducer::endcap_ieta(float& eta) const {
0834   const float eta_step = 0.0845;
0835   return floor(abs(eta) / eta_step) * std::copysign(1, eta);
0836 }
0837 
0838 float L1NNCaloTauProducer::inputQuantizer(float inputF, float LSB, int nbits) {
0839   return min(floor(inputF / LSB), float(pow(2, nbits) - 1)) * LSB;
0840 }
0841 
0842 float L1NNCaloTauProducer::inputScaler(float inputF, std::string feature) {
0843   float mean = (globalCache()->FeatScaler_CE).get_child(feature).get<float>("mean");
0844   float std = (globalCache()->FeatScaler_CE).get_child(feature).get<float>("std");
0845 
0846   return (inputF - mean) / std;
0847 }
0848 
0849 void L1NNCaloTauProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
0850   edm::ParameterSetDescription desc;
0851 
0852   desc.add<edm::InputTag>("l1CaloTowers", edm::InputTag("l1tEGammaClusterEmuProducer", "L1CaloTowerCollection"));
0853   desc.add<edm::InputTag>("hgcalTowers", edm::InputTag("l1tHGCalTowerProducer", "HGCalTowerProcessor"));
0854   desc.add<edm::InputTag>("HgcalClusters",
0855                           edm::InputTag("l1tHGCalBackEndLayer2Producer", "HGCalBackendLayer2Processor3DClustering"));
0856 
0857   desc.add<std::string>("preEmId", "hOverE < 0.3 && hOverE >= 0");
0858   {
0859     edm::ParameterSetDescription psd0;
0860     psd0.add<bool>("isPUFilter", true);
0861     psd0.add<std::string>("preselection", "");
0862     psd0.add<std::string>("method", "BDT");
0863     {
0864       edm::ParameterSetDescription vpsd2;
0865       vpsd2.add<std::string>("name");
0866       vpsd2.add<std::string>("value");
0867       std::vector<edm::ParameterSet> temp2;
0868       temp2.reserve(5);
0869       {
0870         edm::ParameterSet temp3;
0871         temp3.addParameter<std::string>("name", "eMax");
0872         temp3.addParameter<std::string>("value", "eMax()");
0873         temp2.push_back(temp3);
0874       }
0875       {
0876         edm::ParameterSet temp3;
0877         temp3.addParameter<std::string>("name", "eMaxOverE");
0878         temp3.addParameter<std::string>("value", "eMax()/energy()");
0879         temp2.push_back(temp3);
0880       }
0881       {
0882         edm::ParameterSet temp3;
0883         temp3.addParameter<std::string>("name", "sigmaPhiPhiTot");
0884         temp3.addParameter<std::string>("value", "sigmaPhiPhiTot()");
0885         temp2.push_back(temp3);
0886       }
0887       {
0888         edm::ParameterSet temp3;
0889         temp3.addParameter<std::string>("name", "sigmaRRTot");
0890         temp3.addParameter<std::string>("value", "sigmaRRTot()");
0891         temp2.push_back(temp3);
0892       }
0893       {
0894         edm::ParameterSet temp3;
0895         temp3.addParameter<std::string>("name", "triggerCells90percent");
0896         temp3.addParameter<std::string>("value", "triggerCells90percent()");
0897         temp2.push_back(temp3);
0898       }
0899       psd0.addVPSet("variables", vpsd2, temp2);
0900     }
0901     psd0.add<std::string>(
0902         "weightsFile", "L1Trigger/Phase2L1ParticleFlow/data/hgcal_egID/Photon_Pion_vs_Neutrino_BDTweights_1116.xml.gz");
0903     psd0.add<std::string>("wp", "-0.10");
0904     desc.add<edm::ParameterSetDescription>("VsPuId", psd0);
0905   }
0906 
0907   desc.add<double>("EcalEtMinForClustering", 0.0);
0908   desc.add<double>("HcalEtMinForClustering", 0.0);
0909   desc.add<double>("EtMinForSeeding", 2.5);
0910   desc.add<double>("EtaRestriction", 2.4);
0911   desc.add<double>("CB_CE_split", 1.55);
0912 
0913   desc.add<std::string>("CNNmodel_CB_path", "L1Trigger/L1CaloTrigger/data/Phase2_NNCaloTaus/v22/CNNmodel_CB.pb");
0914   desc.add<std::string>("DNNident_CB_path", "L1Trigger/L1CaloTrigger/data/Phase2_NNCaloTaus/v22/DNNident_CB.pb");
0915   desc.add<std::string>("DNNcalib_CB_path", "L1Trigger/L1CaloTrigger/data/Phase2_NNCaloTaus/v22/DNNcalib_CB.pb");
0916   desc.add<std::string>("CNNmodel_CE_path", "L1Trigger/L1CaloTrigger/data/Phase2_NNCaloTaus/v22/CNNmodel_CE.pb");
0917   desc.add<std::string>("DNNident_CE_path", "L1Trigger/L1CaloTrigger/data/Phase2_NNCaloTaus/v22/DNNident_CE.pb");
0918   desc.add<std::string>("DNNcalib_CE_path", "L1Trigger/L1CaloTrigger/data/Phase2_NNCaloTaus/v22/DNNcalib_CE.pb");
0919   desc.add<std::string>("FeatScaler_CE_path", "L1Trigger/L1CaloTrigger/data/Phase2_NNCaloTaus/Cl3dFeatScaler_CE.json");
0920 
0921   desc.add<double>("IdWp90_CB", 0.706);
0922   desc.add<double>("IdWp95_CB", 0.3432);
0923   desc.add<double>("IdWp99_CB", 0.0337);
0924   desc.add<double>("IdWp90_CE", 0.5711);
0925   desc.add<double>("IdWp95_CE", 0.2742);
0926   desc.add<double>("IdWp99_CE", 0.0394);
0927 
0928   desc.add<bool>("DEBUG", false);
0929 
0930   descriptions.add("l1tNNCaloTauProducer", desc);
0931 }
0932 
0933 DEFINE_FWK_MODULE(L1NNCaloTauProducer);