CMS 3D CMS Logo

L1NNCaloTauProducer.cc
Go to the documentation of this file.
1 /* -*- C++ -*-
2 
3 Package: L1CaloTrigger
4 Class: L1NNCaloTauProducer
5 Frinedly name: The TauMinator
6 
7 \class L1NNCaloTauProducer L1NNCaloTauProducer.cc
8 
9 Description:
10 Perform reconstruction and identification of tau
11 candidates at L1 Trigger with a CNN.
12 
13 Implementation:
14 Take as input the HCAL TPs, the ECAL TPs from
15 l1tEGammaClusterEmuProducer, and the HGCAL TPs
16 from l1tHGCalTowerProducer and l1tHGCalBackEndLayer2Producer.
17 Proceed to clustering of trigger towers in NxM
18 clusters, match to HGcal 3D clusters in the endcap.
19 Finally apply the CNNs.
20 
21 Original Author: Jona Motta
22 Created: Tue May 30th 2023
23 
24 */
25 
26 #include <iostream>
27 #include <vector>
28 #include <cmath>
29 
30 #include "boost/property_tree/ptree.hpp"
31 #include "boost/property_tree/json_parser.hpp"
32 
42 
50 
53 
57 
59 
60 struct NNmodels_GlobalCache {
64 
69  boost::property_tree::ptree FeatScaler_CE;
70 
71  tensorflow::GraphDef* CNNmodel_CB;
72  tensorflow::GraphDef* DNNident_CB;
73  tensorflow::GraphDef* DNNcalib_CB;
74 
75  tensorflow::Session* CNNmodel_CBsession;
76  tensorflow::Session* DNNident_CBsession;
77  tensorflow::Session* DNNcalib_CBsession;
78 
79  tensorflow::GraphDef* CNNmodel_CE;
80  tensorflow::GraphDef* DNNident_CE;
81  tensorflow::GraphDef* DNNcalib_CE;
82 
83  tensorflow::Session* CNNmodel_CEsession;
84  tensorflow::Session* DNNident_CEsession;
85  tensorflow::Session* DNNcalib_CEsession;
86 };
87 
88 class L1NNCaloTauProducer : public edm::stream::EDProducer<edm::GlobalCache<NNmodels_GlobalCache>> {
89 public:
91 
92  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
93  static std::unique_ptr<NNmodels_GlobalCache> initializeGlobalCache(const edm::ParameterSet&);
94  static void globalEndJob(const NNmodels_GlobalCache*) { /*do nothing*/ }
95 
96 private:
97  //----edm control---
98  void produce(edm::Event&, const edm::EventSetup&) override;
99 
100  //----private functions----
101  int tower_dIPhi(int& iPhi_1, int& iPhi_2) const;
102  int tower_dIEta(int& iEta_1, int& iEta_2) const;
103  int endcap_iphi(float& phi) const;
104  int endcap_ieta(float& eta) const;
105  float inputQuantizer(float inputF, float LSB, int nbits);
106  float inputScaler(float inputF, std::string feature);
107 
108  //----tokens and handles----
111 
114 
117 
118  //----private variables----
123 
128  double CB_CE_split;
129 
130  double IdWp90_CB;
131  double IdWp95_CB;
132  double IdWp99_CB;
133 
134  double IdWp90_CE;
135  double IdWp95_CE;
136  double IdWp99_CE;
137 
138  bool DEBUG;
139 
140  // hardoced dimensions of the tower clusters
141  const int seedIdx = 22;
142  const int IEta_dim = 5;
143  const int IPhi_dim = 9;
144  const float Eta_dim = 0.2;
145  const float Phi_dim = 0.4;
146  const float Eta_dim_seed = 0.35;
147  const float Phi_dim_seed = 0.7;
148  const float Eta_limit = 2.83;
149 
150  // classes of objects used only in this producer
152  public:
153  float towerEta = -99.;
154  float towerPhi = -99.;
155  float towerEm = 0.;
156  float towerHad = 0.;
157  float l1egTowerEt = 0.;
158  float towerEt = 0.;
159  int towerIeta = -99;
160  int towerIphi = -99;
161  bool isBarrel = true;
162  bool stale = false;
163  bool stale4seed = false;
164  };
165 
167  public:
168  bool barrelSeeded = false;
169  int seedIeta = -99;
170  int seedIphi = -99;
171  float seedEta = -99.;
172  float seedPhi = -99.;
173  float rawEt = 0.;
174  float IDscore = -99.;
175  float calibPt = -99.;
176 
177  std::vector<SimpleTowerHit> towerHits;
178 
179  void InitHits(int N, int M) { towerHits.resize(N * M); }
180  };
181 
183  public:
184  float pt = -99.;
185  float eta = -99.;
186  float phi = -99.;
187  float showerlength = -99.;
188  float coreshowerlength = -99.;
189  float spptot = -99.;
190  float szz = -99.;
191  float srrtot = -99.;
192  float meanz = -99.;
193  bool stale = false;
194  };
195 };
196 
197 /*
198 ████████ ██ ██ ██████ ████████ █████ ██ ██ ███ ███ ██ ███ ██ █████ ████████ ██████ ██████
199  ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██
200  ██ ███████ █████ ██ ███████ ██ ██ ██ ████ ██ ██ ██ ██ ██ ███████ ██ ██ ██ ██████
201  ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
202  ██ ██ ██ ██████ ██ ██ ██ ███████ ██ ██ ██ ██ ████ ██ ██ ██ ██████ ██ ██
203 */
204 
205 std::unique_ptr<NNmodels_GlobalCache> L1NNCaloTauProducer::initializeGlobalCache(const edm::ParameterSet& iConfig) {
206  edm::LogInfo("Initialization") << "Init NN models Global Cache " << std::endl;
207 
208  std::unique_ptr<NNmodels_GlobalCache> GlobalCache(new NNmodels_GlobalCache);
209 
210  GlobalCache->CNNmodel_CB_path = iConfig.getParameter<std::string>("CNNmodel_CB_path");
211  GlobalCache->DNNident_CB_path = iConfig.getParameter<std::string>("DNNident_CB_path");
212  GlobalCache->DNNcalib_CB_path = iConfig.getParameter<std::string>("DNNcalib_CB_path");
213  GlobalCache->CNNmodel_CE_path = iConfig.getParameter<std::string>("CNNmodel_CE_path");
214  GlobalCache->DNNident_CE_path = iConfig.getParameter<std::string>("DNNident_CE_path");
215  GlobalCache->DNNcalib_CE_path = iConfig.getParameter<std::string>("DNNcalib_CE_path");
216  GlobalCache->FeatScaler_CE_path = iConfig.getParameter<std::string>("FeatScaler_CE_path");
217 
218  // Create sessions for Tensorflow inferece
219  (GlobalCache->CNNmodel_CB) = tensorflow::loadGraphDef(edm::FileInPath((GlobalCache->CNNmodel_CB_path)).fullPath());
220  (GlobalCache->CNNmodel_CBsession) = tensorflow::createSession((GlobalCache->CNNmodel_CB));
221 
222  (GlobalCache->DNNident_CB) = tensorflow::loadGraphDef(edm::FileInPath((GlobalCache->DNNident_CB_path)).fullPath());
223  (GlobalCache->DNNident_CBsession) = tensorflow::createSession((GlobalCache->DNNident_CB));
224 
225  (GlobalCache->DNNcalib_CB) = tensorflow::loadGraphDef(edm::FileInPath((GlobalCache->DNNcalib_CB_path)).fullPath());
226  (GlobalCache->DNNcalib_CBsession) = tensorflow::createSession((GlobalCache->DNNcalib_CB));
227 
228  (GlobalCache->CNNmodel_CE) = tensorflow::loadGraphDef(edm::FileInPath((GlobalCache->CNNmodel_CE_path)).fullPath());
229  (GlobalCache->CNNmodel_CEsession) = tensorflow::createSession((GlobalCache->CNNmodel_CE));
230 
231  (GlobalCache->DNNident_CE) = tensorflow::loadGraphDef(edm::FileInPath((GlobalCache->DNNident_CE_path)).fullPath());
232  (GlobalCache->DNNident_CEsession) = tensorflow::createSession((GlobalCache->DNNident_CE));
233 
234  (GlobalCache->DNNcalib_CE) = tensorflow::loadGraphDef(edm::FileInPath((GlobalCache->DNNcalib_CE_path)).fullPath());
235  (GlobalCache->DNNcalib_CEsession) = tensorflow::createSession((GlobalCache->DNNcalib_CE));
236 
237  // Read features scaler
238  boost::property_tree::read_json(edm::FileInPath((GlobalCache->FeatScaler_CE_path)).fullPath(),
239  (GlobalCache->FeatScaler_CE));
240 
241  return GlobalCache;
242 }
243 
244 // ----Constructor and Destructor -----
246  : l1TowersToken(consumes<l1tp2::CaloTowerCollection>(iConfig.getParameter<edm::InputTag>("l1CaloTowers"))),
247  hgcalTowersToken(consumes<l1t::HGCalTowerBxCollection>(iConfig.getParameter<edm::InputTag>("hgcalTowers"))),
248 
249  HGClusterToken(
250  consumes<l1t::HGCalMulticlusterBxCollection>(iConfig.getParameter<edm::InputTag>("HgcalClusters"))),
251  scenario(UseEmInterp::No),
252  preEmId(iConfig.getParameter<std::string>("preEmId")),
253  VsPuId(iConfig.getParameter<edm::ParameterSet>("VsPuId")),
254 
255  EcalEtMinForClustering(iConfig.getParameter<double>("EcalEtMinForClustering")),
256  HcalEtMinForClustering(iConfig.getParameter<double>("HcalEtMinForClustering")),
257  EtMinForSeeding(iConfig.getParameter<double>("EtMinForSeeding")),
258  EtaRestriction(iConfig.getParameter<double>("EtaRestriction")),
259  CB_CE_split(iConfig.getParameter<double>("CB_CE_split")),
260 
261  IdWp90_CB(iConfig.getParameter<double>("IdWp90_CB")),
262  IdWp95_CB(iConfig.getParameter<double>("IdWp95_CB")),
263  IdWp99_CB(iConfig.getParameter<double>("IdWp99_CB")),
264 
265  IdWp90_CE(iConfig.getParameter<double>("IdWp90_CE")),
266  IdWp95_CE(iConfig.getParameter<double>("IdWp95_CE")),
267  IdWp99_CE(iConfig.getParameter<double>("IdWp99_CE")),
268 
269  DEBUG(iConfig.getParameter<bool>("DEBUG")) {
270  // Initialize HGCAL BDTs
271  if (!VsPuId.method().empty()) {
273  }
274 
275  // Create produced outputs
276  produces<BXVector<l1t::Tau>>("L1NNCaloTauCollectionBXV");
277 
278  // Settings output
279  edm::LogInfo("Settings") << "EtaRestriction = " << EtaRestriction << " , CB_CE_split = " << CB_CE_split
280  << " , EtMinForSeeding = " << EtMinForSeeding
281  << " , HcalTpEtMin = " << HcalEtMinForClustering
282  << " , EcalTpEtMin = " << EcalEtMinForClustering << std::endl;
283 }
284 
286  // Output collection
287  std::unique_ptr<BXVector<l1t::Tau>> L1NNCaloTauCollectionBXV(new l1t::TauBxCollection);
288 
289  // Create and Fill collection of all calotowers and their attributes
290  std::vector<SimpleTowerHit> l1CaloTowers;
291 
293  int warnings = 0;
294  for (auto& hit : *l1CaloTowerHandle.product()) {
295  // Skip this weird towers and store warning
296  if (hit.towerIEta() == -1016 && hit.towerIPhi() == -962) {
297  warnings += 1;
298  continue;
299  }
300 
301  SimpleTowerHit l1Hit;
302  l1Hit.isBarrel = true;
303  l1Hit.l1egTowerEt = hit.l1egTowerEt();
304  l1Hit.towerEta = hit.towerEta();
305  l1Hit.towerPhi = hit.towerPhi();
306  l1Hit.towerEm = hit.ecalTowerEt();
307  l1Hit.towerHad = hit.hcalTowerEt();
308  l1Hit.towerEt = l1Hit.towerEm + l1Hit.towerHad + l1Hit.l1egTowerEt;
309  l1Hit.towerIeta = hit.towerIEta();
310  l1Hit.towerIphi = hit.towerIPhi();
311 
312  l1CaloTowers.push_back(l1Hit);
313  }
314  if (warnings != 0 && DEBUG) {
315  edm::LogWarning("BrokenTowers") << " ** WARNING : FOUND " << warnings
316  << " TOWERS WITH towerIeta=-1016 AND towerIphi=-962" << std::endl;
317  }
318 
320  for (auto& hit : *hgcalTowersHandle.product()) {
321  SimpleTowerHit l1Hit;
322  l1Hit.isBarrel = false;
323  l1Hit.l1egTowerEt = 0.0;
324  l1Hit.towerEta = hit.eta();
325  l1Hit.towerPhi = hit.phi();
326  l1Hit.towerEm = hit.etEm();
327  l1Hit.towerHad = hit.etHad();
328  l1Hit.towerEt = l1Hit.towerEm + l1Hit.towerHad;
329  l1Hit.towerIeta = endcap_ieta(l1Hit.towerEta); // computed and filled but not used
330  l1Hit.towerIphi = endcap_iphi(l1Hit.towerPhi); // computed and filled but not used
331 
332  l1CaloTowers.push_back(l1Hit);
333  }
334 
335  // Sort the ECAL+HCAL+L1EGs tower sums based on total ET
337  return a.towerEt > b.towerEt;
338  });
339 
340  // Create and Fill the collection of 3D clusters and their attributes
341  std::vector<SimpleHGCluster> AllHGClusters;
343 
344  for (auto cl3dIt = HGClusterHandle->begin(0); cl3dIt != HGClusterHandle->end(0); ++cl3dIt) {
345  auto& cl3d = *cl3dIt;
346 
347  // Implement cl3d PU ID as done in
348  // https://github.com/cms-sw/cmssw/blob/master/L1Trigger/Phase2L1ParticleFlow/plugins/PFClusterProducerFromHGC3DClusters.cc#L120
349  bool isEM = preEmId(*cl3dIt);
350  l1t::PFCluster cluster(cl3d.pt(), cl3d.eta(), cl3d.phi(), cl3d.hOverE());
351  if (scenario == UseEmInterp::EmOnly) // for emID objs, use EM interp as pT and set H = 0
352  {
353  if (isEM) {
354  float pt_new = cl3d.iPt(l1t::HGCalMulticluster::EnergyInterpretation::EM);
355  float hoe_new = 0.;
356  cluster = l1t::PFCluster(pt_new, cl3d.eta(), cl3d.phi(), hoe_new, isEM);
357  }
358  } else if (scenario == UseEmInterp::AllKeepHad) // for all objs, replace EM part with EM interp, preserve H
359  {
360  float had_old = cl3d.pt() - cluster.emEt();
361  float em_new = cl3d.iPt(l1t::HGCalMulticluster::EnergyInterpretation::EM);
362  float pt_new = had_old + em_new;
363  float hoe_new = em_new > 0 ? (had_old / em_new) : -1;
364  cluster = l1t::PFCluster(pt_new, cl3d.eta(), cl3d.phi(), hoe_new, isEM);
365  } else if (scenario == UseEmInterp::AllKeepTot) // for all objs, replace EM part with EM interp, preserve pT
366  {
367  float em_new = cl3d.iPt(l1t::HGCalMulticluster::EnergyInterpretation::EM);
368  float hoe_new = em_new > 0 ? (cl3d.pt() / em_new - 1) : -1;
369  cluster = l1t::PFCluster(cl3d.pt(), cl3d.eta(), cl3d.phi(), hoe_new, isEM);
370  }
371 
372  if (!VsPuId.method().empty()) {
373  int id = VsPuId.passID(*cl3dIt, cluster);
374  if (!id) {
375  continue;
376  } // skip cl3d if it does not pass puid
377  }
378 
379  SimpleHGCluster HGCluster;
380  HGCluster.pt = cl3d.pt();
381  HGCluster.eta = cl3d.eta();
382  HGCluster.phi = cl3d.phi();
383  HGCluster.showerlength = cl3d.showerLength();
384  HGCluster.coreshowerlength = cl3d.coreShowerLength();
385  HGCluster.spptot = cl3d.sigmaPhiPhiTot();
386  HGCluster.szz = cl3d.sigmaZZ();
387  HGCluster.srrtot = cl3d.sigmaRRTot();
388  HGCluster.meanz = cl3d.zBarycenter();
389 
390  AllHGClusters.push_back(HGCluster);
391  }
392 
393  // Order the collection in pt (the input to the GCT will be pt ordered)
394  std::sort(begin(AllHGClusters), end(AllHGClusters), [](const SimpleHGCluster& a, SimpleHGCluster& b) {
395  return a.pt > b.pt;
396  });
397 
398  // Make NxM TowerClusters and HGClusters collections for TauMinator
399  std::vector<SimpleTowerCluster> l1TowerClustersNxM_CB;
400  std::vector<SimpleTowerCluster> l1TowerClustersNxM_CE;
401  std::vector<SimpleHGCluster> HGClusters;
402 
403  // Supporting collection of endcap clusters before cl3d matching
404  std::vector<SimpleTowerCluster> AllL1TowerClustersNxM_CE;
405 
406  bool caloTauSeedingFinished = false;
407  // Loop for seeding of clNxM objects
408  while (!caloTauSeedingFinished) {
409  SimpleTowerCluster clNxM;
410  clNxM.InitHits(IEta_dim, IPhi_dim);
411  bool seeded = false;
412 
413  for (auto& l1CaloTower : l1CaloTowers) {
414  // Skip seeding in towers that would make the cluster extend in HF
415  // Skip l1CaloTowers which are already used by this clusters' mask
416  if (abs(l1CaloTower.towerEta) > Eta_limit || abs(l1CaloTower.towerEta) > EtaRestriction ||
417  l1CaloTower.stale4seed) {
418  continue;
419  }
420 
421  // If not seded do the seeding
422  if (!seeded) {
423  // The leading unused tower has ET < min, stop jet clustering
424  if (l1CaloTower.towerEt < EtMinForSeeding) {
425  caloTauSeedingFinished = true;
426  continue;
427  }
428 
429  clNxM.seedIeta = l1CaloTower.towerIeta;
430  clNxM.seedIphi = l1CaloTower.towerIphi;
431  clNxM.seedEta = l1CaloTower.towerEta;
432  clNxM.seedPhi = l1CaloTower.towerPhi;
433  if (l1CaloTower.isBarrel) {
434  clNxM.barrelSeeded = true;
435  }
436 
437  clNxM.rawEt += l1CaloTower.towerEt;
438  clNxM.towerHits[seedIdx] = l1CaloTower;
439  l1CaloTower.stale4seed = true;
440  l1CaloTower.stale = true;
441  seeded = true;
442 
443  continue;
444  }
445 
446  int d_iEta = 99;
447  int d_iPhi = 99;
448  float d_Eta = 99.;
449  float d_Phi = 99.;
450  // Ese iEta/iPhi comparisons in the barrel and eta/phi in HGCal
451  if (clNxM.barrelSeeded && l1CaloTower.isBarrel) {
452  d_iEta = tower_dIEta(l1CaloTower.towerIeta, clNxM.seedIeta);
453  d_iPhi = tower_dIPhi(l1CaloTower.towerIphi, clNxM.seedIphi);
454  } else {
455  d_Eta = l1CaloTower.towerEta - clNxM.seedEta;
456  d_Phi = reco::deltaPhi(l1CaloTower.towerPhi, clNxM.seedPhi);
457  }
458 
459  // Stale tower for seeding if it would lead to overalp between clusters
460  if ((abs(d_iEta) <= IEta_dim - 1 && abs(d_iPhi) <= IPhi_dim - 1) ||
461  (abs(d_Eta) < Eta_dim_seed && abs(d_Phi) < Phi_dim_seed)) {
462  l1CaloTower.stale4seed = true;
463  }
464 
465  } // End for loop over TPs
466 
467  // Pushback seeds split in barrel and endcap
468  if (seeded) {
469  if (abs(clNxM.seedEta) < CB_CE_split) {
470  l1TowerClustersNxM_CB.push_back(clNxM);
471  } else {
472  AllL1TowerClustersNxM_CE.push_back(clNxM);
473  }
474  }
475 
476  } // End while loop of TowerClusters seeding
477 
478  // Loop for barrel NxM TowerClusters clustering starting from the seeds
479  for (auto& clNxM : l1TowerClustersNxM_CB) {
480  for (auto& l1CaloTower : l1CaloTowers) {
481  // Skip l1CaloTowers which are already used
482  if (l1CaloTower.stale) {
483  continue;
484  }
485 
486  int d_iEta = 99;
487  int d_iPhi = 99;
488  float d_Eta = 99.;
489  float d_Phi = 99.;
490  int hitIdx = 99.;
491  // Use iEta/iPhi comparisons in the barrel and use eta/phi in HGCal
492  if (l1CaloTower.isBarrel) {
493  d_iEta = tower_dIEta(l1CaloTower.towerIeta, clNxM.seedIeta);
494  d_iPhi = tower_dIPhi(l1CaloTower.towerIphi, clNxM.seedIphi);
495 
496  hitIdx = d_iEta * IPhi_dim + d_iPhi + seedIdx;
497  } else {
498  d_Eta = l1CaloTower.towerEta - clNxM.seedEta;
499  d_Phi = reco::deltaPhi(l1CaloTower.towerPhi, clNxM.seedPhi);
500 
501  int dieta = d_Eta / 0.0807; // minimal difference in endcap is 0.0808
502  int diphi = d_Phi / 0.0872;
503  hitIdx = dieta * IPhi_dim + diphi + seedIdx;
504  }
505 
506  // Cluster all towers in a NxM towers mask
507  if ((abs(d_iEta) <= (IEta_dim - 1) / 2 && abs(d_iPhi) <= (IPhi_dim - 1) / 2) ||
508  (abs(d_Eta) < Eta_dim && abs(d_Phi) < Phi_dim)) {
509  clNxM.rawEt += l1CaloTower.towerEt;
510  clNxM.towerHits[hitIdx] = l1CaloTower;
511  l1CaloTower.stale = true;
512  }
513 
514  } // End for loop over TPs
515 
516  } // End while loop of barrel TowerClusters creation
517 
518  // In the endcap cross-loop over clNxM and cl3d to match them
519  // (we can do it before full clustering just using the seed info)
520  for (auto& clNxM : AllL1TowerClustersNxM_CE) {
521  bool matched = false;
522  for (auto& HGCluster : AllHGClusters) {
523  // In case the clNxM or HGCluster have already been matched just continue through the list to the end
524  // only use cl3ds above 4GeV
525  if (matched || HGCluster.stale || HGCluster.pt < 4) {
526  continue;
527  }
528 
529  float d_Eta = HGCluster.eta - clNxM.seedEta;
530  float d_Phi = reco::deltaPhi(HGCluster.phi, clNxM.seedPhi);
531  float d_R2 = pow(d_Eta, 2) + pow(d_Phi, 2);
532 
533  if (d_R2 < 0.25) {
534  HGCluster.stale = true;
535  HGClusters.push_back(HGCluster);
536  l1TowerClustersNxM_CE.push_back(clNxM);
537  matched = true;
538  }
539 
540  } // End for loop over cl3ds
541 
542  } // End for loop over clNxM
543 
544  // Loop for endcap matched NxM TowerClusters clustering starting from the seeds just found
545  for (auto& clNxM : l1TowerClustersNxM_CE) {
546  for (auto& l1CaloTower : l1CaloTowers) {
547  // Skip l1CaloTowers which are already used
548  if (l1CaloTower.stale) {
549  continue;
550  }
551 
552  int d_iEta = 99;
553  int d_iPhi = 99;
554  float d_Eta = 99.;
555  float d_Phi = 99.;
556  int hitIdx = 99.;
557  // Use iEta/iPhi comparisons in the endcap and use eta/phi in HGCal
558  if (l1CaloTower.isBarrel) {
559  d_iEta = tower_dIEta(l1CaloTower.towerIeta, clNxM.seedIeta);
560  d_iPhi = tower_dIPhi(l1CaloTower.towerIphi, clNxM.seedIphi);
561 
562  hitIdx = d_iEta * IPhi_dim + d_iPhi + seedIdx;
563  } else {
564  d_Eta = l1CaloTower.towerEta - clNxM.seedEta;
565  d_Phi = reco::deltaPhi(l1CaloTower.towerPhi, clNxM.seedPhi);
566 
567  int dieta = d_Eta / 0.0807; // minimal difference in endcap is 0.0808
568  int diphi = d_Phi / 0.0872;
569  hitIdx = dieta * IPhi_dim + diphi + seedIdx;
570  }
571 
572  // Cluster all towers in a NxM towers mask
573  if ((abs(d_iEta) <= (IEta_dim - 1) / 2 && abs(d_iPhi) <= (IPhi_dim - 1) / 2) ||
574  (abs(d_Eta) < Eta_dim && abs(d_Phi) < Phi_dim)) {
575  clNxM.rawEt += l1CaloTower.towerEt;
576  clNxM.towerHits[hitIdx] = l1CaloTower;
577  l1CaloTower.stale = true;
578  }
579 
580  } // End for loop over TPs
581 
582  } // End while loop of endcap TowerClusters creation
583 
584  // Barrel TauMinator application
585  int batchSize_CB = (int)(l1TowerClustersNxM_CB.size());
586  tensorflow::TensorShape imageShape_CB({batchSize_CB, IEta_dim, IPhi_dim, 2});
587  tensorflow::TensorShape positionShape_CB({batchSize_CB, 2});
588  tensorflow::Tensor TowerClusterImage_CB(tensorflow::DT_FLOAT, imageShape_CB);
589  tensorflow::Tensor TowerClusterPosition_CB(tensorflow::DT_FLOAT, positionShape_CB);
590 
591  int clIdx = 0;
592  for (auto& clNxM : l1TowerClustersNxM_CB) {
593  // Fill inputs for Tensorflow inference
594  for (int eta = 0; eta < IEta_dim; ++eta) {
595  for (int phi = 0; phi < IPhi_dim; ++phi) {
596  int towerIdx = eta * IPhi_dim + phi;
597  TowerClusterImage_CB.tensor<float, 4>()(clIdx, eta, phi, 0) =
598  inputQuantizer(clNxM.towerHits[towerIdx].l1egTowerEt + clNxM.towerHits[towerIdx].towerEm, 0.25, 10);
599  TowerClusterImage_CB.tensor<float, 4>()(clIdx, eta, phi, 1) =
600  inputQuantizer(clNxM.towerHits[towerIdx].towerHad, 0.25, 10);
601  }
602  }
603 
604  TowerClusterPosition_CB.tensor<float, 2>()(clIdx, 0) = clNxM.seedEta;
605  TowerClusterPosition_CB.tensor<float, 2>()(clIdx, 1) = clNxM.seedPhi;
606 
607  clIdx++; // Increase batch index
608  }
609 
610  if (batchSize_CB >
611  0) // from CMSSW_14_0_X tensorflow does not seem to be able to deal with a tensor of dimension 0 anymore
612  {
613  // Apply CNN model
614  tensorflow::NamedTensorList CNNmodel_CBinputList = {{"TowerClusterImage", TowerClusterImage_CB},
615  {"TowerClusterPosition", TowerClusterPosition_CB}};
616  std::vector<tensorflow::Tensor> CNNmodel_CBoutputs;
617  tensorflow::run((globalCache()->CNNmodel_CBsession),
618  CNNmodel_CBinputList,
619  {"TauMinator_CB_conv/middleMan/concat"},
620  &CNNmodel_CBoutputs);
621  tensorflow::NamedTensorList DNN_CBinputsList = {{"middleMan", CNNmodel_CBoutputs[0]}};
622 
623  // Apply DNN for identification
624  std::vector<tensorflow::Tensor> DNN_CBoutputsIdent;
625  tensorflow::run((globalCache()->DNNident_CBsession),
626  DNN_CBinputsList,
627  {"TauMinator_CB_ident/sigmoid_IDout/Sigmoid"},
628  &DNN_CBoutputsIdent);
629 
630  // Apply DNN for calibration
631  std::vector<tensorflow::Tensor> DNN_CBoutputsCalib;
632  tensorflow::run((globalCache()->DNNcalib_CBsession),
633  DNN_CBinputsList,
634  {"TauMinator_CB_calib/LIN_DNNout/Relu"},
635  &DNN_CBoutputsCalib);
636 
637  // Fill TauMinator output variables of TowerClusters
638  clIdx = 0;
639  for (auto& clNxM : l1TowerClustersNxM_CB) {
640  clNxM.IDscore = DNN_CBoutputsIdent[0].matrix<float>()(0, clIdx);
641  clNxM.calibPt = DNN_CBoutputsCalib[0].matrix<float>()(0, clIdx);
642  clIdx++; // Increase batch index
643  }
644  }
645 
646  // Endcap TauMinator application
647  int batchSize_CE = (int)(l1TowerClustersNxM_CE.size());
648  tensorflow::TensorShape imageShape_CE({batchSize_CE, IEta_dim, IPhi_dim, 2});
649  tensorflow::TensorShape positionShape_CE({batchSize_CE, 2});
650  tensorflow::TensorShape cl3dfeatShape_CE({batchSize_CE, 8});
651  tensorflow::Tensor TowerClusterImage_CE(tensorflow::DT_FLOAT, imageShape_CE);
652  tensorflow::Tensor TowerClusterPosition_CE(tensorflow::DT_FLOAT, positionShape_CE);
653  tensorflow::Tensor Cl3dShapeFeatures_CE(tensorflow::DT_FLOAT, cl3dfeatShape_CE);
654 
655  clIdx = 0;
656  for (auto& clNxM : l1TowerClustersNxM_CE) {
657  // Indexing of cl3ds is the same as the one of clNxMs
658  SimpleHGCluster HGClu = HGClusters[clIdx];
659 
660  // Fill inputs for Tensorflow inference
661  for (int eta = 0; eta < IEta_dim; ++eta) {
662  for (int phi = 0; phi < IPhi_dim; ++phi) {
663  int towerIdx = eta * IPhi_dim + phi;
664  TowerClusterImage_CE.tensor<float, 4>()(clIdx, eta, phi, 0) =
665  inputQuantizer(clNxM.towerHits[towerIdx].l1egTowerEt + clNxM.towerHits[towerIdx].towerEm, 0.25, 10);
666  TowerClusterImage_CE.tensor<float, 4>()(clIdx, eta, phi, 1) =
667  inputQuantizer(clNxM.towerHits[towerIdx].towerHad, 0.25, 10);
668  }
669  }
670 
671  TowerClusterPosition_CE.tensor<float, 2>()(clIdx, 0) = clNxM.seedEta;
672  TowerClusterPosition_CE.tensor<float, 2>()(clIdx, 1) = clNxM.seedPhi;
673 
674  Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 0) = inputScaler(inputQuantizer(HGClu.pt, 0.25, 14), "pt");
675  Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 1) =
676  inputScaler(inputQuantizer(abs(HGClu.eta) - 1.321, 0.004, 9), "eta");
677  Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 2) = inputScaler(HGClu.showerlength, "showerlength");
678  Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 3) = inputScaler(HGClu.coreshowerlength, "coreshowerlength");
679  Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 4) =
680  inputScaler(inputQuantizer(HGClu.spptot, 0.0000153, 16), "spptot");
681  Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 5) = inputScaler(inputQuantizer(HGClu.szz, 0.00153, 16), "szz");
682  Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 6) =
683  inputScaler(inputQuantizer(HGClu.srrtot, 0.0000153, 16), "srrtot");
684  Cl3dShapeFeatures_CE.tensor<float, 2>()(clIdx, 7) =
685  inputScaler(inputQuantizer(10 * (abs(HGClu.meanz) - 321.05), 0.5, 12), "meanz");
686 
687  clIdx++; // Increase batch index
688  }
689 
690  if (batchSize_CE >
691  0) // from CMSSW_14_0_X tensorflow does not seem to be able to deal with a tensor of dimension 0 anymore
692  {
693  // Apply CNN model
694  tensorflow::NamedTensorList CNNmodel_CEinputList = {{"TowerClusterImage", TowerClusterImage_CE},
695  {"TowerClusterPosition", TowerClusterPosition_CE},
696  {"AssociatedCl3dFeatures", Cl3dShapeFeatures_CE}};
697  std::vector<tensorflow::Tensor> CNNmodel_CEoutputs;
698  tensorflow::run((globalCache()->CNNmodel_CEsession),
699  CNNmodel_CEinputList,
700  {"TauMinator_CE_conv/middleMan/concat"},
701  &CNNmodel_CEoutputs);
702  tensorflow::NamedTensorList DNN_CEinputsList = {{"middleMan", CNNmodel_CEoutputs[0]}};
703 
704  // Apply DNN for identification
705  std::vector<tensorflow::Tensor> DNN_CEoutputsIdent;
706  tensorflow::run((globalCache()->DNNident_CEsession),
707  DNN_CEinputsList,
708  {"TauMinator_CE_ident/sigmoid_IDout/Sigmoid"},
709  &DNN_CEoutputsIdent);
710 
711  // Apply DNN for calibration
712  std::vector<tensorflow::Tensor> DNN_CEoutputsCalib;
713  tensorflow::run((globalCache()->DNNcalib_CEsession),
714  DNN_CEinputsList,
715  {"TauMinator_CE_calib/LIN_DNNout/Relu"},
716  &DNN_CEoutputsCalib);
717 
718  // Fill TauMinator output variables of TowerClusters
719  clIdx = 0;
720  for (auto& clNxM : l1TowerClustersNxM_CE) {
721  clNxM.IDscore = DNN_CEoutputsIdent[0].matrix<float>()(0, clIdx);
722  clNxM.calibPt = DNN_CEoutputsCalib[0].matrix<float>()(0, clIdx);
723  clIdx++; // Increase batch index
724  }
725  }
726 
727  // Fill the output collection of L1 taus
728  for (auto& clNxM : l1TowerClustersNxM_CB) {
729  // Apply eta restriction
730  if (abs(clNxM.seedEta) > EtaRestriction) {
731  continue;
732  }
733 
734  // Assign increasing quality to higher scoring candidates
735  int quality = 0;
736  // 99% WP
737  if (clNxM.IDscore > IdWp99_CB) {
738  quality = 1;
739  }
740  // 95% WP
741  if (clNxM.IDscore > IdWp95_CB) {
742  quality = 2;
743  }
744  // 90% WP
745  if (clNxM.IDscore > IdWp90_CB) {
746  quality = 3;
747  }
748 
750  reco::Candidate::PolarLorentzVector(clNxM.calibPt, clNxM.seedEta, clNxM.seedPhi, 0);
751 
752  // store ID score multiplied by 10E4 to have good precision even using the Phase1 tau int iso format
753  // (this is stored just in case for possible additional offline studies)
754  // tau initialisation = (p4, pt, eta, phi, qual, iso)
755  l1t::Tau l1Tau = l1t::Tau(tauP4, clNxM.calibPt, clNxM.seedEta, clNxM.seedPhi, quality, clNxM.IDscore * 10E4);
756  l1Tau.setTowerIEta(clNxM.seedIeta);
757  l1Tau.setTowerIPhi(clNxM.seedIphi);
758  l1Tau.setRawEt(clNxM.rawEt);
759 
760  L1NNCaloTauCollectionBXV->push_back(0, l1Tau);
761  }
762 
763  for (auto& clNxM : l1TowerClustersNxM_CE) {
764  // Apply eta restriction
765  if (abs(clNxM.seedEta) > EtaRestriction) {
766  continue;
767  }
768 
769  // Assign increasing quality to higher scoring candidates
770  int quality = 0;
771  // 99% WP
772  if (clNxM.IDscore > IdWp99_CE) {
773  quality = 1;
774  }
775  // 95% WP
776  if (clNxM.IDscore > IdWp95_CE) {
777  quality = 2;
778  }
779  // 90% WP
780  if (clNxM.IDscore > IdWp90_CE) {
781  quality = 3;
782  }
783 
785  reco::Candidate::PolarLorentzVector(clNxM.calibPt, clNxM.seedEta, clNxM.seedPhi, 0);
786 
787  // store ID score multiplied by 10E4 to have good precision even using the Phase1 tau int iso format
788  // (this is stored just in case for possible additional offline studies)
789  // tau initialisation = (p4, pt, eta, phi, qual, iso)
790  l1t::Tau l1Tau = l1t::Tau(tauP4, clNxM.calibPt, clNxM.seedEta, clNxM.seedPhi, quality, clNxM.IDscore * 10E4);
791  l1Tau.setTowerIEta(clNxM.seedIeta);
792  l1Tau.setTowerIPhi(clNxM.seedIphi);
793  l1Tau.setRawEt(clNxM.rawEt);
794 
795  L1NNCaloTauCollectionBXV->push_back(0, l1Tau);
796  }
797 
798  // Fill output
799  iEvent.put(std::move(L1NNCaloTauCollectionBXV), "L1NNCaloTauCollectionBXV");
800 
801 } // End of produce function
802 
804  const int PI = 36;
805  int result = iPhi_1 - iPhi_2;
806  if (result > PI) {
807  result -= 2 * PI;
808  }
809  if (result <= -PI) {
810  result += 2 * PI;
811  }
812  return result;
813 }
814 
815 int L1NNCaloTauProducer::tower_dIEta(int& iEta_1, int& iEta_2) const {
816  if (iEta_1 * iEta_2 > 0) {
817  return iEta_1 - iEta_2;
818  } else {
819  if (iEta_1 > 0) {
820  return iEta_1 - iEta_2 - 1;
821  } else {
822  return iEta_1 - iEta_2 + 1;
823  }
824  }
825 }
826 
828  const float phi_step = 0.0872664;
829  if (phi > 0) {
830  return floor(phi / phi_step) + 1;
831  } else {
832  return floor(phi / phi_step) + 73;
833  }
834 }
835 
837  const float eta_step = 0.0845;
838  return floor(abs(eta) / eta_step) * std::copysign(1, eta);
839 }
840 
841 float L1NNCaloTauProducer::inputQuantizer(float inputF, float LSB, int nbits) {
842  return min(floor(inputF / LSB), float(pow(2, nbits) - 1)) * LSB;
843 }
844 
845 float L1NNCaloTauProducer::inputScaler(float inputF, std::string feature) {
846  float mean = (globalCache()->FeatScaler_CE).get_child(feature).get<float>("mean");
847  float std = (globalCache()->FeatScaler_CE).get_child(feature).get<float>("std");
848 
849  return (inputF - mean) / std;
850 }
851 
854 
855  desc.add<edm::InputTag>("l1CaloTowers", edm::InputTag("l1tEGammaClusterEmuProducer", "L1CaloTowerCollection"));
856  desc.add<edm::InputTag>("hgcalTowers", edm::InputTag("l1tHGCalTowerProducer", "HGCalTowerProcessor"));
857  desc.add<edm::InputTag>("HgcalClusters",
858  edm::InputTag("l1tHGCalBackEndLayer2Producer", "HGCalBackendLayer2Processor3DClustering"));
859 
860  desc.add<std::string>("preEmId", "hOverE < 0.3 && hOverE >= 0");
861  {
863  psd0.add<bool>("isPUFilter", true);
864  psd0.add<std::string>("preselection", "");
865  psd0.add<std::string>("method", "BDT");
866  {
868  vpsd2.add<std::string>("name");
869  vpsd2.add<std::string>("value");
870  std::vector<edm::ParameterSet> temp2;
871  temp2.reserve(5);
872  {
873  edm::ParameterSet temp3;
874  temp3.addParameter<std::string>("name", "eMax");
875  temp3.addParameter<std::string>("value", "eMax()");
876  temp2.push_back(temp3);
877  }
878  {
879  edm::ParameterSet temp3;
880  temp3.addParameter<std::string>("name", "eMaxOverE");
881  temp3.addParameter<std::string>("value", "eMax()/energy()");
882  temp2.push_back(temp3);
883  }
884  {
885  edm::ParameterSet temp3;
886  temp3.addParameter<std::string>("name", "sigmaPhiPhiTot");
887  temp3.addParameter<std::string>("value", "sigmaPhiPhiTot()");
888  temp2.push_back(temp3);
889  }
890  {
891  edm::ParameterSet temp3;
892  temp3.addParameter<std::string>("name", "sigmaRRTot");
893  temp3.addParameter<std::string>("value", "sigmaRRTot()");
894  temp2.push_back(temp3);
895  }
896  {
897  edm::ParameterSet temp3;
898  temp3.addParameter<std::string>("name", "triggerCells90percent");
899  temp3.addParameter<std::string>("value", "triggerCells90percent()");
900  temp2.push_back(temp3);
901  }
902  psd0.addVPSet("variables", vpsd2, temp2);
903  }
904  psd0.add<std::string>(
905  "weightsFile", "L1Trigger/Phase2L1ParticleFlow/data/hgcal_egID/Photon_Pion_vs_Neutrino_BDTweights_1116.xml.gz");
906  psd0.add<std::string>("wp", "-0.10");
907  desc.add<edm::ParameterSetDescription>("VsPuId", psd0);
908  }
909 
910  desc.add<double>("EcalEtMinForClustering", 0.0);
911  desc.add<double>("HcalEtMinForClustering", 0.0);
912  desc.add<double>("EtMinForSeeding", 2.5);
913  desc.add<double>("EtaRestriction", 2.4);
914  desc.add<double>("CB_CE_split", 1.55);
915 
916  desc.add<std::string>("CNNmodel_CB_path", "L1Trigger/L1CaloTrigger/data/Phase2_NNCaloTaus/v22/CNNmodel_CB.pb");
917  desc.add<std::string>("DNNident_CB_path", "L1Trigger/L1CaloTrigger/data/Phase2_NNCaloTaus/v22/DNNident_CB.pb");
918  desc.add<std::string>("DNNcalib_CB_path", "L1Trigger/L1CaloTrigger/data/Phase2_NNCaloTaus/v22/DNNcalib_CB.pb");
919  desc.add<std::string>("CNNmodel_CE_path", "L1Trigger/L1CaloTrigger/data/Phase2_NNCaloTaus/v22/CNNmodel_CE.pb");
920  desc.add<std::string>("DNNident_CE_path", "L1Trigger/L1CaloTrigger/data/Phase2_NNCaloTaus/v22/DNNident_CE.pb");
921  desc.add<std::string>("DNNcalib_CE_path", "L1Trigger/L1CaloTrigger/data/Phase2_NNCaloTaus/v22/DNNcalib_CE.pb");
922  desc.add<std::string>("FeatScaler_CE_path", "L1Trigger/L1CaloTrigger/data/Phase2_NNCaloTaus/Cl3dFeatScaler_CE.json");
923 
924  desc.add<double>("IdWp90_CB", 0.706);
925  desc.add<double>("IdWp95_CB", 0.3432);
926  desc.add<double>("IdWp99_CB", 0.0337);
927  desc.add<double>("IdWp90_CE", 0.5711);
928  desc.add<double>("IdWp95_CE", 0.2742);
929  desc.add<double>("IdWp99_CE", 0.0394);
930 
931  desc.add<bool>("DEBUG", false);
932 
933  descriptions.add("l1tNNCaloTauProducer", desc);
934 }
935 
edm::Handle< l1t::HGCalMulticlusterBxCollection > HGClusterHandle
boost::property_tree::ptree FeatScaler_CE
tensorflow::Session * CNNmodel_CEsession
constexpr double deltaPhi(double phi1, double phi2)
Definition: deltaPhi.h:26
tensorflow::GraphDef * DNNident_CB
std::vector< NamedTensor > NamedTensorList
Definition: TensorFlow.h:31
T getParameter(std::string const &) const
Definition: ParameterSet.h:307
tensorflow::GraphDef * CNNmodel_CB
ParameterDescriptionBase * addVPSet(U const &iLabel, ParameterSetDescription const &validator, std::vector< ParameterSet > const &defaults)
StringCutObjectSelector< l1t::HGCalMulticluster > preEmId
double pt() const final
transverse momentum
int tower_dIEta(int &iEta_1, int &iEta_2) const
GraphDef * loadGraphDef(const std::string &pbFile)
Definition: TensorFlow.cc:119
Definition: Tau.h:20
T const * product() const
Definition: Handle.h:70
tensorflow::Session * DNNident_CBsession
tensorflow::Session * DNNcalib_CEsession
edm::Handle< l1t::HGCalTowerBxCollection > hgcalTowersHandle
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
delete x;
Definition: CaloConfig.h:22
std::vector< SimpleTowerHit > towerHits
scenario
Definition: constants.h:219
tensorflow::Session * DNNident_CEsession
BXVector< HGCalTower > HGCalTowerBxCollection
Definition: HGCalTower.h:10
int endcap_ieta(float &eta) const
string quality
int iEvent
Definition: GenABIO.cc:224
tensorflow::GraphDef * DNNcalib_CE
int tower_dIPhi(int &iPhi_1, int &iPhi_2) const
void addParameter(std::string const &name, T const &value)
Definition: ParameterSet.h:136
L1NNCaloTauProducer(const edm::ParameterSet &, const NNmodels_GlobalCache *)
BXVector< HGCalMulticluster > HGCalMulticlusterBxCollection
void run(Session *session, const NamedTensorList &inputs, const std::vector< std::string > &outputNames, std::vector< Tensor > *outputs, const thread::ThreadPoolOptions &threadPoolOptions)
Definition: TensorFlow.cc:271
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
tensorflow::GraphDef * CNNmodel_CE
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
edm::EDGetTokenT< l1t::HGCalMulticlusterBxCollection > HGClusterToken
ParameterDescriptionBase * add(U const &iLabel, T const &value)
#define PI
Definition: QcdUeDQM.h:37
float inputScaler(float inputF, std::string feature)
edm::Handle< l1tp2::CaloTowerCollection > l1CaloTowerHandle
tensorflow::Session * DNNcalib_CBsession
float inputQuantizer(float inputF, float LSB, int nbits)
Session * createSession()
Definition: TensorFlow.cc:136
Log< level::Info, false > LogInfo
static std::unique_ptr< NNmodels_GlobalCache > initializeGlobalCache(const edm::ParameterSet &)
#define N
Definition: blowfish.cc:9
void produce(edm::Event &, const edm::EventSetup &) override
tensorflow::Session * CNNmodel_CBsession
double b
Definition: hdecay.h:120
void add(std::string const &label, ParameterSetDescription const &psetDescription)
int endcap_iphi(float &phi) const
l1tpf::HGC3DClusterEgID VsPuId
static void globalEndJob(const NNmodels_GlobalCache *)
HLT enums.
tensorflow::GraphDef * DNNcalib_CB
double a
Definition: hdecay.h:121
#define DEBUG
Definition: DMRChecker.cc:120
edm::EDGetToken hgcalTowersToken
const std::string & fullPath() const
Definition: FileInPath.cc:144
edm::EDGetTokenT< l1tp2::CaloTowerCollection > l1TowersToken
Log< level::Warning, false > LogWarning
float passID(l1t::HGCalMulticluster c, l1t::PFCluster &cpf)
tensorflow::GraphDef * DNNident_CE
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
def move(src, dest)
Definition: eostools.py:511
math::PtEtaPhiMLorentzVector PolarLorentzVector
Lorentz vector.
Definition: Candidate.h:38