CMS 3D CMS Logo

Phase1L1TJetProducer.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: L1CaloTrigger
4 // Class: Phase1L1TJetProducer
5 //
31 //
32 // Original Simone Bologna
33 // Created: Mon Jul 02 2018
34 // Modified 2020 Emyr Clement
35 //
36 
51 
52 #include "TH2F.h"
53 
54 #include <cmath>
55 
56 #include <algorithm>
61 
63 public:
64  explicit Phase1L1TJetProducer(const edm::ParameterSet&);
65  ~Phase1L1TJetProducer() override;
66 
67  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
68 
69 private:
70  void produce(edm::Event&, const edm::EventSetup&) override;
71 
73  std::vector<std::tuple<int, int>> findSeeds(float seedThreshold) const;
74 
75  // Calculates the pt sum of the bins around the seeds
76  // And applies some PU mitigation
77  // Warning - not used for some time, so user beware
78  std::vector<reco::CaloJet> buildJetsFromSeedsWithPUSubtraction(const std::vector<std::tuple<int, int>>& seeds,
79  bool killZeroPt) const;
80 
81  // Calculates the pt sum of the bins around the seeds
82  std::vector<reco::CaloJet> buildJetsFromSeeds(const std::vector<std::tuple<int, int>>& seeds) const;
83 
84  // Used by buildJetsFromSeedsWithPUSubtraction
85  // Implementation of pileup mitigation
86  // Warning - not used for some time, so user beware
87  void subtract9x9Pileup(reco::CaloJet& jet) const;
88 
90  float getTowerEnergy(int iEta, int iPhi) const;
91 
92  // Implementation of pt sum of bins around one seed
93  reco::CaloJet buildJetFromSeed(const std::tuple<int, int>& seed) const;
94 
95  // <3 handy method to fill the calogrid with whatever type
96  template <class Container>
97  void fillCaloGrid(TH2F& caloGrid, const Container& triggerPrimitives, const unsigned int regionIndex);
98 
99  // Digitise the eta and phi coordinates of input candidates
100  // This converts the quantities to integers to reduce precision
101  // And takes account of bin edge effects i.e. makes sure the
102  // candidate ends up in the correct (i.e. same behaviour as the firmware) bin of caloGrid_
103  std::pair<float, float> getCandidateDigiEtaPhi(const float eta,
104  const float phi,
105  const unsigned int regionIndex) const;
106 
107  // Sorts the input candidates into the PF regions they arrive in
108  // Truncates the inputs. Takes the first N candidates as they are provided, without any sorting (this may be needed in the future and/or provided in this way from emulation of layer 1)
109  template <class Handle>
110  std::vector<std::vector<reco::CandidatePtr>> prepareInputsIntoRegions(const Handle triggerPrimitives);
111 
112  // Converts phi and eta (PF) region indices to a single index
113  unsigned int getRegionIndex(const unsigned int phiRegion, const unsigned int etaRegion) const;
114  // From the single index, calculated by getRegionIndex, provides the lower eta and phi boundaries of the input (PF) region index
115  std::pair<double, double> regionEtaPhiLowEdges(const unsigned int regionIndex) const;
116  // From the single index, calculated by getRegionIndex, provides the upper eta and phi boundaries of the input (PF) region index
117  std::pair<double, double> regionEtaPhiUpEdges(const unsigned int regionIndex) const;
118 
119  // computes MET
120  // Takes grid used by jet finder and projects to 1D histogram of phi, bin contents are total pt in that phi bin
121  // the phi bin index is used to retrieve the sin-cos value from the LUT emulator
122  // the pt of the input is multiplied by that sin cos value to obtain px and py that is added to the total event px & py
123  // after all the inputs have been processed we compute the total pt of the event, and set that as MET
124  l1t::EtSum computeMET(const double etaCut, l1t::EtSum::EtSumType sumType) const;
125 
126  // Determine if this tower should be trimmed or not
127  // Used only when trimmedGrid_ option is set to true
128  // Trim means removing 3 towers in each corner of the square grid
129  // giving a cross shaped grid, which is a bit more circular in shape than a square
130  bool trimTower(const int etaIndex, const int phiIndex) const;
131 
133  // histogram containing our clustered inputs
134  std::unique_ptr<TH2F> caloGrid_;
135 
136  std::vector<double> etaBinning_;
137  size_t nBinsEta_;
138  unsigned int nBinsPhi_;
139  double phiLow_;
140  double phiUp_;
141  unsigned int jetIEtaSize_;
142  unsigned int jetIPhiSize_;
145  double ptlsb_;
146  double philsb_;
147  double etalsb_;
150  // Eta and phi edges of input PF regions
151  std::vector<double> etaRegionEdges_;
152  std::vector<double> phiRegionEdges_;
153  // Maximum number of candidates per input PF region
154  unsigned int maxInputsPerRegion_;
155  // LUT for sin and cos phi, to match that used in firmware
156  std::vector<double> sinPhi_;
157  std::vector<double> cosPhi_;
158  // input eta cut for met calculation
160  // input eta cut for metHF calculation
163 };
164 
166  : // getting configuration settings
167  inputCollectionTag_{
168  consumes<edm::View<reco::Candidate>>(iConfig.getParameter<edm::InputTag>("inputCollectionTag"))},
169  etaBinning_(iConfig.getParameter<std::vector<double>>("etaBinning")),
170  nBinsEta_(etaBinning_.size() - 1),
171  nBinsPhi_(iConfig.getParameter<unsigned int>("nBinsPhi")),
172  phiLow_(iConfig.getParameter<double>("phiLow")),
173  phiUp_(iConfig.getParameter<double>("phiUp")),
174  jetIEtaSize_(iConfig.getParameter<unsigned int>("jetIEtaSize")),
175  jetIPhiSize_(iConfig.getParameter<unsigned int>("jetIPhiSize")),
176  trimmedGrid_(iConfig.getParameter<bool>("trimmedGrid")),
177  seedPtThreshold_(iConfig.getParameter<double>("seedPtThreshold")),
178  ptlsb_(iConfig.getParameter<double>("ptlsb")),
179  philsb_(iConfig.getParameter<double>("philsb")),
180  etalsb_(iConfig.getParameter<double>("etalsb")),
181  puSubtraction_(iConfig.getParameter<bool>("puSubtraction")),
182  vetoZeroPt_(iConfig.getParameter<bool>("vetoZeroPt")),
183  etaRegionEdges_(iConfig.getParameter<std::vector<double>>("etaRegions")),
184  phiRegionEdges_(iConfig.getParameter<std::vector<double>>("phiRegions")),
185  maxInputsPerRegion_(iConfig.getParameter<unsigned int>("maxInputsPerRegion")),
186  sinPhi_(iConfig.getParameter<std::vector<double>>("sinPhi")),
187  cosPhi_(iConfig.getParameter<std::vector<double>>("cosPhi")),
188  metAbsEtaCut_(iConfig.getParameter<double>("metAbsEtaCut")),
189  metHFAbsEtaCut_(iConfig.getParameter<double>("metHFAbsEtaCut")),
190  outputCollectionName_(iConfig.getParameter<std::string>("outputCollectionName")) {
191  caloGrid_ =
192  std::make_unique<TH2F>("caloGrid", "Calorimeter grid", nBinsEta_, etaBinning_.data(), nBinsPhi_, phiLow_, phiUp_);
193  caloGrid_->GetXaxis()->SetTitle("#eta");
194  caloGrid_->GetYaxis()->SetTitle("#phi");
195  produces<std::vector<reco::CaloJet>>(outputCollectionName_).setBranchAlias(outputCollectionName_);
196  produces<std::vector<l1t::EtSum>>(outputCollectionName_ + "MET").setBranchAlias(outputCollectionName_ + "MET");
197 }
198 
200 
201 float Phase1L1TJetProducer::getTowerEnergy(int iEta, int iPhi) const {
202  // We return the pt of a certain bin in the calo grid, taking account of the phi periodicity when overflowing (e.g. phi > phiSize), and returning 0 for the eta out of bounds
203 
204  int nBinsEta = caloGrid_->GetNbinsX();
205  int nBinsPhi = caloGrid_->GetNbinsY();
206  while (iPhi < 1) {
207  iPhi += nBinsPhi;
208  }
209  while (iPhi > nBinsPhi) {
210  iPhi -= nBinsPhi;
211  }
212  if (iEta < 1) {
213  return 0;
214  }
215  if (iEta > nBinsEta) {
216  return 0;
217  }
218  return caloGrid_->GetBinContent(iEta, iPhi);
219 }
220 
222  edm::Handle<edm::View<reco::Candidate>> inputCollectionHandle;
223  iEvent.getByToken(inputCollectionTag_, inputCollectionHandle);
224 
225  // sort inputs into PF regions
226  std::vector<std::vector<reco::CandidatePtr>> inputsInRegions = prepareInputsIntoRegions<>(inputCollectionHandle);
227 
228  // histogramming the data
229  caloGrid_->Reset();
230  for (unsigned int iInputRegion = 0; iInputRegion < inputsInRegions.size(); ++iInputRegion) {
231  fillCaloGrid<>(*(caloGrid_), inputsInRegions[iInputRegion], iInputRegion);
232  }
233 
234  // find the seeds
235  const auto& seedsVector = findSeeds(seedPtThreshold_); // seedPtThreshold = 5
236  // build jets from the seeds
237  auto l1jetVector =
239 
240  // sort by pt
241  std::sort(l1jetVector.begin(), l1jetVector.end(), [](const reco::CaloJet& jet1, const reco::CaloJet& jet2) {
242  return jet1.pt() > jet2.pt();
243  });
244 
245  auto l1jetVectorPtr = std::make_unique<std::vector<reco::CaloJet>>(l1jetVector);
246  iEvent.put(std::move(l1jetVectorPtr), outputCollectionName_);
247 
248  // calculate METs
251  std::unique_ptr<std::vector<l1t::EtSum>> lSumVectorPtr(new std::vector<l1t::EtSum>(0));
252  lSumVectorPtr->push_back(lMET);
253  lSumVectorPtr->push_back(lMETHF);
254  iEvent.put(std::move(lSumVectorPtr), this->outputCollectionName_ + "MET");
255 
256  return;
257 }
258 
260  // these variables host the total pt in each sideband and the total pileup contribution
261  float topBandPt = 0;
262  float leftBandPt = 0;
263  float rightBandPt = 0;
264  float bottomBandPt = 0;
265  float pileUpEnergy;
266 
267  // hold the jet's x-y (and z, as I have to use it, even if 2D) location in the histo
268  int xCenter, yCenter, zCenter;
269  // Retrieving histo-coords for seed
270  caloGrid_->GetBinXYZ(caloGrid_->FindFixBin(jet.eta(), jet.phi()), xCenter, yCenter, zCenter);
271 
272  // Computing pileup
273  for (int x = x_scroll_min; x <= x_scroll_max; x++) {
274  for (int y = y_scroll_min; y < y_scroll_max; y++) {
275  // top band, I go up 5 squares to reach the bottom of the top band
276  // +x scrolls from left to right, +y scrolls up
277  topBandPt += getTowerEnergy(xCenter + x, yCenter + (5 + y));
278  // left band, I go left 5 squares (-5) to reach the bottom of the top band
279  // +x scrolls from bottom to top, +y scrolls left
280  leftBandPt += getTowerEnergy(xCenter - (5 + y), yCenter + x);
281  // right band, I go right 5 squares (+5) to reach the bottom of the top band
282  // +x scrolls from bottom to top, +y scrolls right
283  rightBandPt += getTowerEnergy(xCenter + (5 + y), yCenter + x);
284  // right band, I go right 5 squares (+5) to reach the bottom of the top band
285  // +x scrolls from bottom to top, +y scrolls right
286  bottomBandPt += getTowerEnergy(xCenter + x, yCenter - (5 + y));
287  }
288  }
289  // adding bands and removing the maximum band (equivalent to adding the three minimum bands)
290  pileUpEnergy = topBandPt + leftBandPt + rightBandPt + bottomBandPt -
291  std::max(topBandPt, std::max(leftBandPt, std::max(rightBandPt, bottomBandPt)));
292 
293  //preparing the new 4-momentum vector
295  // removing pu contribution
296  float ptAfterPUSubtraction = jet.pt() - pileUpEnergy;
297  ptVector.SetPt((ptAfterPUSubtraction > 0) ? ptAfterPUSubtraction : 0);
298  ptVector.SetEta(jet.eta());
299  ptVector.SetPhi(jet.phi());
300  //updating the jet
301  jet.setP4(ptVector);
302  jet.setPileup(pileUpEnergy);
303  return;
304 }
305 
306 std::vector<std::tuple<int, int>> Phase1L1TJetProducer::findSeeds(float seedThreshold) const {
307  int nBinsX = caloGrid_->GetNbinsX();
308  int nBinsY = caloGrid_->GetNbinsY();
309 
310  std::vector<std::tuple<int, int>> seeds;
311 
312  int etaHalfSize = (int)jetIEtaSize_ / 2;
313  int phiHalfSize = (int)jetIPhiSize_ / 2;
314 
315  // for each point of the grid check if it is a local maximum
316  // to do so I take a point, and look if is greater than the points around it (in the 9x9 neighborhood)
317  // to prevent mutual exclusion, I check greater or equal for points above and right to the one I am considering (including the top-left point)
318  // to prevent mutual exclusion, I check greater for points below and left to the one I am considering (including the bottom-right point)
319 
320  for (int iPhi = 1; iPhi <= nBinsY; iPhi++) {
321  for (int iEta = 1; iEta <= nBinsX; iEta++) {
322  float centralPt = caloGrid_->GetBinContent(iEta, iPhi);
323  if (centralPt < seedThreshold)
324  continue;
325  bool isLocalMaximum = true;
326 
327  // Scanning through the grid centered on the seed
328  for (int etaIndex = -etaHalfSize; etaIndex <= etaHalfSize; etaIndex++) {
329  for (int phiIndex = -phiHalfSize; phiIndex <= phiHalfSize; phiIndex++) {
330  if (trimmedGrid_) {
331  if (trimTower(etaIndex, phiIndex))
332  continue;
333  }
334 
335  if ((etaIndex == 0) && (phiIndex == 0))
336  continue;
337  if (phiIndex > 0) {
338  if (phiIndex > -etaIndex) {
339  isLocalMaximum = ((isLocalMaximum) && (centralPt > getTowerEnergy(iEta + etaIndex, iPhi + phiIndex)));
340  } else {
341  isLocalMaximum = ((isLocalMaximum) && (centralPt >= getTowerEnergy(iEta + etaIndex, iPhi + phiIndex)));
342  }
343  } else {
344  if (phiIndex >= -etaIndex) {
345  isLocalMaximum = ((isLocalMaximum) && (centralPt > getTowerEnergy(iEta + etaIndex, iPhi + phiIndex)));
346  } else {
347  isLocalMaximum = ((isLocalMaximum) && (centralPt >= getTowerEnergy(iEta + etaIndex, iPhi + phiIndex)));
348  }
349  }
350  }
351  }
352  if (isLocalMaximum) {
353  seeds.emplace_back(iEta, iPhi);
354  }
355  }
356  }
357 
358  return seeds;
359 }
360 
361 reco::CaloJet Phase1L1TJetProducer::buildJetFromSeed(const std::tuple<int, int>& seed) const {
362  int iEta = std::get<0>(seed);
363  int iPhi = std::get<1>(seed);
364 
365  int etaHalfSize = (int)jetIEtaSize_ / 2;
366  int phiHalfSize = (int)jetIPhiSize_ / 2;
367 
368  float ptSum = 0;
369  // Scanning through the grid centered on the seed
370  for (int etaIndex = -etaHalfSize; etaIndex <= etaHalfSize; etaIndex++) {
371  for (int phiIndex = -phiHalfSize; phiIndex <= phiHalfSize; phiIndex++) {
372  if (trimmedGrid_) {
373  if (trimTower(etaIndex, phiIndex))
374  continue;
375  }
376  ptSum += getTowerEnergy(iEta + etaIndex, iPhi + phiIndex);
377  }
378  }
379 
380  // Creating a jet with eta phi centered on the seed and momentum equal to the sum of the pt of the components
382  ptVector.SetPt(ptSum);
383  ptVector.SetEta(caloGrid_->GetXaxis()->GetBinCenter(iEta));
384  ptVector.SetPhi(caloGrid_->GetYaxis()->GetBinCenter(iPhi));
386  jet.setP4(ptVector);
387  return jet;
388 }
389 
391  const std::vector<std::tuple<int, int>>& seeds, bool killZeroPt) const {
392  // For each seed take a grid centered on the seed of the size specified by the user
393  // Sum the pf in the grid, that will be the pt of the l1t jet. Eta and phi of the jet is taken from the seed.
394  std::vector<reco::CaloJet> jets;
395  for (const auto& seed : seeds) {
398  //killing jets with 0 pt
399  if ((vetoZeroPt_) && (jet.pt() <= 0))
400  continue;
401  jets.push_back(jet);
402  }
403  return jets;
404 }
405 
406 std::vector<reco::CaloJet> Phase1L1TJetProducer::buildJetsFromSeeds(
407  const std::vector<std::tuple<int, int>>& seeds) const {
408  // For each seed take a grid centered on the seed of the size specified by the user
409  // Sum the pf in the grid, that will be the pt of the l1t jet. Eta and phi of the jet is taken from the seed.
410  std::vector<reco::CaloJet> jets;
411  for (const auto& seed : seeds) {
413  jets.push_back(jet);
414  }
415  return jets;
416 }
417 
418 template <class Container>
420  const Container& triggerPrimitives,
421  const unsigned int regionIndex) {
422  //Filling the calo grid with the primitives
423  for (const auto& primitiveIterator : triggerPrimitives) {
424  // Get digitised (floating point with reduced precision) eta and phi
425  std::pair<float, float> digi_EtaPhi =
426  getCandidateDigiEtaPhi(primitiveIterator->eta(), primitiveIterator->phi(), regionIndex);
427 
428  caloGrid.Fill(static_cast<float>(digi_EtaPhi.first),
429  static_cast<float>(digi_EtaPhi.second),
430  static_cast<float>(primitiveIterator->pt()));
431  }
432 }
433 
434 std::pair<float, float> Phase1L1TJetProducer::getCandidateDigiEtaPhi(const float eta,
435  const float phi,
436  const unsigned int regionIndex) const {
437  std::pair<double, double> regionLowEdges = regionEtaPhiLowEdges(regionIndex);
438 
439  int digitisedEta = floor((eta - regionLowEdges.second) / etalsb_);
440  int digitisedPhi = floor((phi - regionLowEdges.first) / philsb_);
441 
442  // If eta or phi is on a bin edge
443  // Put in bin above, to match behaviour of HLS
444  // Unless it's on the last bin of this pf region
445  // Then it is placed in the last bin, not the overflow
446  TAxis* etaAxis = caloGrid_->GetXaxis();
447  std::pair<double, double> regionUpEdges = regionEtaPhiUpEdges(regionIndex);
448  int digiEtaEdgeLastBinUp = floor((regionUpEdges.second - regionLowEdges.second) / etalsb_);
449  // If the digi eta is outside the last bin of this pf region
450  // Set the digitised quantity so it would be in the last bin
451  // These cases could be avoided by sorting input candidates based on digitised eta/phi
452  if (digitisedEta >= digiEtaEdgeLastBinUp) {
453  digitisedEta = digiEtaEdgeLastBinUp - 1;
454  } else {
455  for (int i = 0; i < etaAxis->GetNbins(); ++i) {
456  if (etaAxis->GetBinUpEdge(i) < regionLowEdges.second)
457  continue;
458  int digiEdgeBinUp = floor((etaAxis->GetBinUpEdge(i) - regionLowEdges.second) / etalsb_);
459  if (digiEdgeBinUp == digitisedEta) {
460  digitisedEta += 1;
461  }
462  }
463  }
464 
465  // Similar for phi
466  TAxis* phiAxis = caloGrid_->GetYaxis();
467  int digiPhiEdgeLastBinUp = floor((regionUpEdges.first - regionLowEdges.first) / philsb_);
468  if (digitisedPhi >= digiPhiEdgeLastBinUp) {
469  digitisedPhi = digiPhiEdgeLastBinUp - 1;
470  } else {
471  for (int i = 0; i < phiAxis->GetNbins(); ++i) {
472  if (phiAxis->GetBinUpEdge(i) < regionLowEdges.first)
473  continue;
474  int digiEdgeBinUp = floor((phiAxis->GetBinUpEdge(i) - regionLowEdges.first) / philsb_);
475  if (digiEdgeBinUp == digitisedPhi) {
476  digitisedPhi += 1;
477  }
478  }
479  }
480 
481  // Convert digitised eta and phi back to floating point quantities with reduced precision
482  float floatDigitisedEta = (digitisedEta + 0.5) * etalsb_ + regionLowEdges.second;
483  float floatDigitisedPhi = (digitisedPhi + 0.5) * philsb_ + regionLowEdges.first;
484 
485  return std::pair<float, float>{floatDigitisedEta, floatDigitisedPhi};
486 }
487 
490  desc.add<edm::InputTag>("inputCollectionTag", edm::InputTag("l1pfCandidates", "Puppi"));
491  desc.add<std::vector<double>>("etaBinning");
492  desc.add<unsigned int>("nBinsPhi", 72);
493  desc.add<double>("phiLow", -M_PI);
494  desc.add<double>("phiUp", M_PI);
495  desc.add<unsigned int>("jetIEtaSize", 7);
496  desc.add<unsigned int>("jetIPhiSize", 7);
497  desc.add<bool>("trimmedGrid", false);
498  desc.add<double>("seedPtThreshold", 5);
499  desc.add<double>("ptlsb", 0.25), desc.add<double>("philsb", 0.0043633231), desc.add<double>("etalsb", 0.0043633231),
500  desc.add<bool>("puSubtraction", false);
501  desc.add<string>("outputCollectionName", "UncalibratedPhase1L1TJetFromPfCandidates");
502  desc.add<bool>("vetoZeroPt", true);
503  desc.add<std::vector<double>>("etaRegions");
504  desc.add<std::vector<double>>("phiRegions");
505  desc.add<unsigned int>("maxInputsPerRegion", 18);
506  desc.add<std::vector<double>>("sinPhi");
507  desc.add<std::vector<double>>("cosPhi");
508  desc.add<double>("metAbsEtaCut", 3);
509  desc.add<double>("metHFAbsEtaCut", 5);
510  descriptions.add("Phase1L1TJetProducer", desc);
511 }
512 
513 template <class Handle>
514 std::vector<std::vector<edm::Ptr<reco::Candidate>>> Phase1L1TJetProducer::prepareInputsIntoRegions(
515  const Handle triggerPrimitives) {
516  std::vector<std::vector<reco::CandidatePtr>> inputsInRegions{etaRegionEdges_.size() * (phiRegionEdges_.size() - 1)};
517 
518  for (unsigned int i = 0; i < triggerPrimitives->size(); ++i) {
519  reco::CandidatePtr tp(triggerPrimitives, i);
520 
521  if (tp->phi() < phiRegionEdges_.front() || tp->phi() >= phiRegionEdges_.back() ||
522  tp->eta() < etaRegionEdges_.front() || tp->eta() >= etaRegionEdges_.back())
523  continue;
524 
525  // Which phi region does this tp belong to
526  auto it_phi = phiRegionEdges_.begin();
527  it_phi = std::upper_bound(phiRegionEdges_.begin(), phiRegionEdges_.end(), tp->phi()) - 1;
528 
529  // Which eta region does this tp belong to
530  auto it_eta = etaRegionEdges_.begin();
531  it_eta = std::upper_bound(etaRegionEdges_.begin(), etaRegionEdges_.end(), tp->eta()) - 1;
532 
533  if (it_phi != phiRegionEdges_.end() && it_eta != etaRegionEdges_.end()) {
534  auto phiRegion = it_phi - phiRegionEdges_.begin();
535  auto etaRegion = it_eta - etaRegionEdges_.begin();
536  inputsInRegions[getRegionIndex(phiRegion, etaRegion)].emplace_back(tp);
537  }
538  }
539 
540  // Truncate number of inputs in each pf region
541  for (auto& inputs : inputsInRegions) {
542  if (inputs.size() > maxInputsPerRegion_) {
543  inputs.resize(maxInputsPerRegion_);
544  }
545  }
546 
547  return inputsInRegions;
548 }
549 
550 unsigned int Phase1L1TJetProducer::getRegionIndex(const unsigned int phiRegion, const unsigned int etaRegion) const {
551  return etaRegion * (phiRegionEdges_.size() - 1) + phiRegion;
552 }
553 
554 std::pair<double, double> Phase1L1TJetProducer::regionEtaPhiLowEdges(const unsigned int regionIndex) const {
555  unsigned int phiRegion = regionIndex % (phiRegionEdges_.size() - 1);
556  unsigned int etaRegion = (regionIndex - phiRegion) / (phiRegionEdges_.size() - 1);
557  return std::pair<double, double>{phiRegionEdges_.at(phiRegion), etaRegionEdges_.at(etaRegion)};
558 }
559 
560 std::pair<double, double> Phase1L1TJetProducer::regionEtaPhiUpEdges(const unsigned int regionIndex) const {
561  unsigned int phiRegion = regionIndex % (phiRegionEdges_.size() - 1);
562  unsigned int etaRegion = (regionIndex - phiRegion) / (phiRegionEdges_.size() - 1);
563  if (phiRegion == phiRegionEdges_.size() - 1) {
564  return std::pair<double, double>{phiRegionEdges_.at(phiRegion), etaRegionEdges_.at(etaRegion + 1)};
565  } else if (etaRegion == etaRegionEdges_.size() - 1) {
566  return std::pair<double, double>{phiRegionEdges_.at(phiRegion + 1), etaRegionEdges_.at(etaRegion)};
567  }
568 
569  return std::pair<double, double>{phiRegionEdges_.at(phiRegion + 1), etaRegionEdges_.at(etaRegion + 1)};
570 }
571 
573  const auto lowEtaBin = caloGrid_->GetXaxis()->FindBin(-1.0 * etaCut);
574  const auto highEtaBin = caloGrid_->GetXaxis()->FindBin(etaCut) - 1;
575  const auto phiProjection = caloGrid_->ProjectionY("temp", lowEtaBin, highEtaBin);
576 
577  // Use digitised quantities when summing to improve agreement with firmware
578  int totalDigiPx{0};
579  int totalDigiPy{0};
580 
581  for (int i = 1; i < phiProjection->GetNbinsX() + 1; ++i) {
582  double pt = phiProjection->GetBinContent(i);
583  totalDigiPx += trunc(floor(pt / ptlsb_) * cosPhi_[i - 1]);
584  totalDigiPy += trunc(floor(pt / ptlsb_) * sinPhi_[i - 1]);
585  }
586 
587  double lMET = floor(sqrt(totalDigiPx * totalDigiPx + totalDigiPy * totalDigiPy)) * ptlsb_;
588 
589  math::PtEtaPhiMLorentzVector lMETVector(lMET, 0, acos(totalDigiPx / (lMET / ptlsb_)), 0);
590  l1t::EtSum lMETSum(lMETVector, sumType, 0, 0, 0, 0);
591  return lMETSum;
592 }
593 
594 bool Phase1L1TJetProducer::trimTower(const int etaIndex, const int phiIndex) const {
595  int etaHalfSize = jetIEtaSize_ / 2;
596  int phiHalfSize = jetIPhiSize_ / 2;
597 
598  if (etaIndex == -etaHalfSize || etaIndex == etaHalfSize) {
599  if (phiIndex <= -phiHalfSize + 1 || phiIndex >= phiHalfSize - 1) {
600  return true;
601  }
602  } else if (etaIndex == -etaHalfSize + 1 || etaIndex == etaHalfSize - 1) {
603  if (phiIndex == -phiHalfSize || phiIndex == phiHalfSize) {
604  return true;
605  }
606  }
607 
608  return false;
609 }
l1t::EtSum computeMET(const double etaCut, l1t::EtSum::EtSumType sumType) const
T getParameter(std::string const &) const
Definition: ParameterSet.h:307
std::vector< double > phiRegionEdges_
std::vector< double > cosPhi_
Jets made from CaloTowers.
Definition: CaloJet.h:27
double pt() const final
transverse momentum
std::pair< float, float > getCandidateDigiEtaPhi(const float eta, const float phi, const unsigned int regionIndex) const
std::vector< reco::CaloJet > buildJetsFromSeedsWithPUSubtraction(const std::vector< std::tuple< int, int >> &seeds, bool killZeroPt) const
std::pair< double, double > regionEtaPhiLowEdges(const unsigned int regionIndex) const
Phase1L1TJetProducer(const edm::ParameterSet &)
void subtract9x9Pileup(reco::CaloJet &jet) const
float getTowerEnergy(int iEta, int iPhi) const
Get the energy of a certain tower while correctly handling phi periodicity in case of overflow...
std::vector< std::vector< reco::CandidatePtr > > prepareInputsIntoRegions(const Handle triggerPrimitives)
std::vector< double > sinPhi_
PtEtaPhiMLorentzVectorD PtEtaPhiMLorentzVector
Lorentz vector with cartesian internal representation.
Definition: LorentzVector.h:25
unsigned int getRegionIndex(const unsigned int phiRegion, const unsigned int etaRegion) const
constexpr int x_scroll_max
std::vector< std::tuple< int, int > > findSeeds(float seedThreshold) const
Finds the seeds in the caloGrid, seeds are saved in a vector that contain the index in the TH2F of ea...
int iEvent
Definition: GenABIO.cc:224
std::vector< double > etaBinning_
void produce(edm::Event &, const edm::EventSetup &) override
T sqrt(T t)
Definition: SSEVec.h:23
std::unique_ptr< TH2F > caloGrid_
void fillCaloGrid(TH2F &caloGrid, const Container &triggerPrimitives, const unsigned int regionIndex)
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
constexpr int y_scroll_max
#define M_PI
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
constexpr int y_scroll_min
std::vector< double > etaRegionEdges_
void add(std::string const &label, ParameterSetDescription const &psetDescription)
constexpr int x_scroll_min
std::pair< double, double > regionEtaPhiUpEdges(const unsigned int regionIndex) const
std::vector< reco::CaloJet > buildJetsFromSeeds(const std::vector< std::tuple< int, int >> &seeds) const
EtSumType
Definition: EtSum.h:27
edm::AssociationVector< reco::JetRefBaseProd, Values > Container
reco::CaloJet buildJetFromSeed(const std::tuple< int, int > &seed) const
def move(src, dest)
Definition: eostools.py:511
bool trimTower(const int etaIndex, const int phiIndex) const
math::PtEtaPhiMLorentzVector PolarLorentzVector
Lorentz vector.
Definition: Candidate.h:38
edm::EDGetTokenT< edm::View< reco::Candidate > > inputCollectionTag_