CMS 3D CMS Logo

L1GctHardwareJetFinder.cc
Go to the documentation of this file.
2 
3 //DEFINE STATICS
4 const unsigned int L1GctHardwareJetFinder::N_COLS = 2;
5 const unsigned int L1GctHardwareJetFinder::CENTRAL_COL0 = 0;
7  (((L1CaloRegionDetId::N_ETA) / 2) + N_EXTRA_REGIONS_ETA00) * L1GctHardwareJetFinder::N_COLS;
8 
11  m_localMaxima(MAX_JETS_OUT),
12  m_clusters(MAX_JETS_OUT),
13  m_numberOfClusters(0),
14  m_localMax00(2),
15  m_cluster00(2) {
16  this->reset();
17  // Initialise parameters for Region input calculations in the
18  // derived class so we get the right values of constants.
19  static const unsigned NPHI = L1CaloRegionDetId::N_PHI;
20  m_minColThisJf = (NPHI + m_id * 2 - CENTRAL_COL0) % NPHI;
21 }
22 
24 
25 std::ostream& operator<<(std::ostream& os, const L1GctHardwareJetFinder& algo) {
26  os << "===L1GctHardwareJetFinder===" << std::endl;
27  const L1GctJetFinderBase* temp = &algo;
28  os << *temp;
29  return os;
30 }
31 
33 
35  if (setupOk()) {
36  findProtoJets();
37  }
38 }
39 
41  if (setupOk()) {
43  findJets();
44  sortJets();
45  doEnergySums();
46  }
47 }
48 
50 
56 }
57 
62 }
63 
65 // Find the local et maxima in the 2x11 array of regions
67  m_localMaxima.clear();
69  m_localMax00.clear();
70  m_localMax00.resize(2);
71 
72  UShort jetNum = 0; //holds the number of jets currently found
73  UShort centreIndex = COL_OFFSET * this->centralCol0();
74  for (UShort column = 0; column < 2; ++column) //Find jets in the central search region
75  {
76  // The input regions include two extra bins on the other side of eta=0. This allows "seamless"
77  // jetfinding across the eta=0 boundary. We skip the first input region in each row. We perform
78  // the full pre-clustering on the next region but store the resulting clusters separately
79  // from the main list of output pre-clusters - they will be used in the final cluster stage to
80  // make sure we do not produce jets in adjacent regions on opposite sides of eta=0.
81  ++centreIndex;
82  for (UShort row = 1; row < COL_OFFSET; ++row) {
83  // Here's the array of greater-than and greater-or-equal tests
84  // to ensure each localMaximum appears once and only once in the list
85  // It is different for forward and backward eta.
86  unsigned JET_THRESHOLD = ((row > m_EtaBoundry) ? m_FwdJetSeed : m_CenJetSeed);
87  bool localMax = !m_inputRegions.at(centreIndex).empty() && (m_inputRegions.at(centreIndex).et() >= JET_THRESHOLD);
88  if (m_positiveEtaWheel) { // Forward eta
89  localMax &= (m_inputRegions.at(centreIndex).et() >= m_inputRegions.at(centreIndex - 1).et());
90  if (row < (COL_OFFSET - 1)) {
91  localMax &= (m_inputRegions.at(centreIndex).et() > m_inputRegions.at(centreIndex + 1).et());
92  }
93  if (column == 0) {
94  localMax &= (m_inputRegions.at(centreIndex).et() > m_inputRegions.at(centreIndex + COL_OFFSET).et());
95  localMax &= (m_inputRegions.at(centreIndex).et() > m_inputRegions.at(centreIndex + COL_OFFSET - 1).et());
96  if (row < (COL_OFFSET - 1)) {
97  localMax &= (m_inputRegions.at(centreIndex).et() > m_inputRegions.at(centreIndex + COL_OFFSET + 1).et());
98  }
99  } else {
100  localMax &= (m_inputRegions.at(centreIndex).et() >= m_inputRegions.at(centreIndex - COL_OFFSET).et());
101  localMax &= (m_inputRegions.at(centreIndex).et() >= m_inputRegions.at(centreIndex - COL_OFFSET - 1).et());
102  if (row < (COL_OFFSET - 1)) {
103  localMax &= (m_inputRegions.at(centreIndex).et() >= m_inputRegions.at(centreIndex - COL_OFFSET + 1).et());
104  }
105  }
106  } else { // Backward eta
107  localMax &= (m_inputRegions.at(centreIndex).et() > m_inputRegions.at(centreIndex - 1).et());
108  if (row < (COL_OFFSET - 1)) {
109  localMax &= (m_inputRegions.at(centreIndex).et() >= m_inputRegions.at(centreIndex + 1).et());
110  }
111  if (column == 0) {
112  localMax &= (m_inputRegions.at(centreIndex).et() >= m_inputRegions.at(centreIndex + COL_OFFSET).et());
113  localMax &= (m_inputRegions.at(centreIndex).et() >= m_inputRegions.at(centreIndex + COL_OFFSET - 1).et());
114  if (row < (COL_OFFSET - 1)) {
115  localMax &= (m_inputRegions.at(centreIndex).et() >= m_inputRegions.at(centreIndex + COL_OFFSET + 1).et());
116  }
117  } else {
118  localMax &= (m_inputRegions.at(centreIndex).et() > m_inputRegions.at(centreIndex - COL_OFFSET).et());
119  localMax &= (m_inputRegions.at(centreIndex).et() > m_inputRegions.at(centreIndex - COL_OFFSET - 1).et());
120  if (row < (COL_OFFSET - 1)) {
121  localMax &= (m_inputRegions.at(centreIndex).et() > m_inputRegions.at(centreIndex - COL_OFFSET + 1).et());
122  }
123  }
124  }
125  if (localMax) {
126  if (row > 1) {
127  if (jetNum < MAX_JETS_OUT) {
128  m_localMaxima.at(jetNum) = m_inputRegions.at(centreIndex);
129  ++jetNum;
130  }
131  }
132  // Treat row 1 as a separate case. It's not required for jetfinding but
133  // is used for vetoing of jets double counted across the eta=0 boundary
134  else {
135  unsigned phi = m_inputRegions.at(centreIndex).rctPhi();
136  m_localMax00.at(phi) = m_inputRegions.at(centreIndex);
137  }
138  }
139  ++centreIndex;
140  }
141  }
142 
143  m_numberOfClusters = jetNum;
144 }
145 
146 // For each local maximum, find the cluster et in a 2x3 region.
147 // The logic ensures that a given region et cannot be used in more than one cluster.
148 // The sorting of the local maxima ensures the highest et maximum has priority.
150  m_clusters.clear();
151  m_clusters.resize(MAX_JETS_OUT);
152  m_cluster00.clear();
153  m_cluster00.resize(2);
154 
155  RegionsVector topJets(MAX_JETS_OUT), botJets(MAX_JETS_OUT);
156  std::vector<unsigned> topJetsPosition(MAX_JETS_OUT), botJetsPosition(MAX_JETS_OUT);
157  unsigned numberOfTopJets = 0, numberOfBotJets = 0;
158 
159  // Loop over local maxima
160  for (unsigned j = 0; j < m_numberOfClusters; ++j) {
161  // Make a proto-jet cluster
163 
164  if (m_localMaxima.at(j).rctPhi() == 0) {
165  // Store "top edge" jets
166  topJets.at(numberOfTopJets) = temp;
167  topJetsPosition.at(numberOfTopJets) = 0;
168  for (unsigned k = 0; k < numberOfTopJets; ++k) {
169  if (topJets.at(numberOfTopJets).et() >= topJets.at(k).et()) {
170  ++topJetsPosition.at(k);
171  }
172  if (topJets.at(numberOfTopJets).et() <= topJets.at(k).et()) {
173  ++topJetsPosition.at(numberOfTopJets);
174  }
175  }
176  ++numberOfTopJets;
177  } else {
178  // Store "bottom edge" jets
179  botJets.at(numberOfBotJets) = temp;
180  botJetsPosition.at(numberOfBotJets) = 0;
181  for (unsigned k = 0; k < numberOfBotJets; ++k) {
182  if (botJets.at(numberOfBotJets).et() >= botJets.at(k).et()) {
183  ++botJetsPosition.at(k);
184  }
185  if (botJets.at(numberOfBotJets).et() <= botJets.at(k).et()) {
186  ++botJetsPosition.at(numberOfBotJets);
187  }
188  }
189  ++numberOfBotJets;
190  }
191  }
192  // Now we've found all the proto-jets, copy the best ones to the output array
193  //
194  // We fill the first half of the array with "bottom jets"
195  // and the remainder with "top jets". For cases where
196  // we have found too many jets in one phi column,
197  // we keep those with the highest Et.
198  static const unsigned int MAX_TOPBOT_JETS = MAX_JETS_OUT / 2;
199  unsigned pos = 0;
200  for (unsigned j = 0; j < numberOfBotJets; ++j) {
201  if (botJetsPosition.at(j) < MAX_TOPBOT_JETS) {
202  m_clusters.at(pos++) = botJets.at(j);
203  }
204  }
205  pos = MAX_TOPBOT_JETS;
206  for (unsigned j = 0; j < numberOfTopJets; ++j) {
207  if (topJetsPosition.at(j) < MAX_TOPBOT_JETS) {
208  m_clusters.at(pos++) = topJets.at(j);
209  }
210  }
211  // Finally, deal with eta00 maxima
212  if (!m_localMax00.at(0).empty())
213  m_cluster00.at(0) = makeProtoJet(m_localMax00.at(0));
214  if (!m_localMax00.at(1).empty())
215  m_cluster00.at(1) = makeProtoJet(m_localMax00.at(1));
216 }
217 
220  unsigned eta = localMax.gctEta();
221  unsigned phi = localMax.gctPhi();
222  int16_t bx = localMax.bx();
223 
224  unsigned localEta = localMax.rctEta();
225  unsigned localPhi = localMax.rctPhi();
226 
227  unsigned etCluster = 0;
228  bool ovrFlowOr = false;
229  bool tauVetoOr = false;
230  unsigned rgnsAboveIsoThreshold = 0;
231 
232  // check for row00
233  const unsigned midEta = (L1CaloRegionDetId::N_ETA) / 2;
234  bool wrongEtaWheel = ((!m_positiveEtaWheel) && (eta >= midEta)) || ((m_positiveEtaWheel) && (eta < midEta));
235 
236  // Which rows are we looking over?
237  unsigned rowStart, rowEnd, rowMid;
238  static const unsigned row0 = N_EXTRA_REGIONS_ETA00 - 1;
239  if (wrongEtaWheel) {
240  if (localEta > row0 - 1) {
241  rowStart = 0;
242  rowMid = 0;
243  } else {
244  rowStart = row0 - 1 - localEta;
245  rowMid = rowStart + 1;
246  }
247  if (localEta > row0 + 2) { // Shouldn't happen, but big problems if it does
248  rowEnd = 0;
249  } else {
250  rowEnd = row0 + 2 - localEta;
251  }
252  } else {
253  rowStart = row0 + localEta;
254  rowMid = rowStart + 1;
255  if (localEta < COL_OFFSET - row0 - 2) {
256  rowEnd = rowStart + 3;
257  } else {
258  rowEnd = COL_OFFSET;
259  }
260  }
261 
262  for (unsigned row = rowStart; row < rowEnd; ++row) {
263  for (unsigned column = 0; column < 2; ++column) {
264  unsigned index = column * COL_OFFSET + row;
265  etCluster += m_inputRegions.at(index).et();
266  ovrFlowOr |= m_inputRegions.at(index).overFlow();
267  // Distinguish between central and tau-flagged jets. Two versions of the algorithm.
268  if (m_useImprovedTauAlgo) {
269  //===========================================================================================
270  // "Old" version of improved tau algorithm tests the tau veto for the central region always
271  // if ((row==(localEta+N_EXTRA_REGIONS_ETA00)) && (column==localPhi)) {
272  // // central region - check the tau veto
273  // tauVetoOr |= m_inputRegions.at(index).tauVeto();
274  // } else {
275  // // other regions - check the tau veto if required
276  // if (!m_ignoreTauVetoBitsForIsolation) {
277  // tauVetoOr |= m_inputRegions.at(index).tauVeto();
278  // }
279  // // check the region energy against the isolation threshold
280  // if (m_inputRegions.at(index).et() >= m_tauIsolationThreshold) {
281  // rgnsAboveIsoThreshold++;
282  // }
283  // }
284  //===========================================================================================
285 
286  // In the hardware, the ignoreTauVetoBitsForIsolation switch ignores all the veto bits,
287  // including the one for the central region.
288  if (!((row == rowMid) && (column == localPhi))) {
289  // non-central region - check the region energy against the isolation threshold
290  if (m_inputRegions.at(index).et() >= m_tauIsolationThreshold) {
291  rgnsAboveIsoThreshold++;
292  }
293  }
294  // all regions - check the tau veto if required
296  tauVetoOr |= m_inputRegions.at(index).tauVeto();
297  }
298  // End of improved tau algorithm
299  } else {
300  // Original tau algorithm
301  tauVetoOr |= m_inputRegions.at(index).tauVeto();
302  }
303  }
304  }
305  // Encode the number of towers over threshold for the isolated tau algorithm
306  bool tauFeatureBit = false;
307  if (m_useImprovedTauAlgo) {
308  tauVetoOr |= (rgnsAboveIsoThreshold > 1);
309  tauFeatureBit |= (rgnsAboveIsoThreshold == 1);
310  }
311 
312  L1GctRegion temp(L1GctRegion::makeProtoJetRegion(etCluster, ovrFlowOr, tauVetoOr, tauFeatureBit, eta, phi, bx));
313  return temp;
314 }
315 
318  m_clusters.clear();
319  m_clusters.resize(MAX_JETS_OUT);
320 
321  // Loop over proto-jets received from neighbours.
322  // Form a jet to send to the output if there is no proto-jet nearby in the
323  // list of jets found locally. If local jets are found nearby, form a jet
324  // if the received jet has higher Et than any one of the local ones.
325  for (unsigned j = 0; j < MAX_JETS_OUT; ++j) {
326  unsigned et0 = m_rcvdProtoJets.at(j).et();
327  unsigned localEta0 = m_rcvdProtoJets.at(j).rctEta();
328  unsigned localPhi0 = m_rcvdProtoJets.at(j).rctPhi();
329  unsigned JET_THRESHOLD = ((localEta0 >= m_EtaBoundry) ? m_FwdJetSeed : m_CenJetSeed);
330  if (et0 >= JET_THRESHOLD) {
331  bool storeJet = false;
332  bool isolated = true;
333  // eta00 boundary check/veto
334  if (localEta0 == 0) {
335  unsigned neighbourEt = m_cluster00.at(1 - localPhi0).et();
336  isolated &= et0 >= neighbourEt;
337  }
338  // If the jet is NOT vetoed, look at the jets found locally (m_keptProtoJets).
339  // We accept the jet if there are no local jets nearby, or if the local jet
340  // (there should be no more than one) has lower Et.
341  if (isolated) {
342  for (unsigned k = 0; k < MAX_JETS_OUT; ++k) {
343  unsigned et1 = m_keptProtoJets.at(k).et();
344  unsigned localEta1 = m_keptProtoJets.at(k).rctEta();
345  unsigned localPhi1 = m_keptProtoJets.at(k).rctPhi();
346  if (et1 > 0) {
347  bool distantJet = ((localPhi0 == localPhi1) || (localEta1 > localEta0 + 1) || (localEta0 > localEta1 + 1));
348 
349  isolated &= distantJet;
350  storeJet |= !distantJet && ((et0 > et1) || ((et0 == et1) && localPhi0 == 1));
351  }
352  }
353  }
354 
355  storeJet |= isolated;
356 
357  if (storeJet) {
358  // Start with the et sum, tau veto and overflow flags of the protoJet (2x3 regions)
359  unsigned etCluster = et0;
360  bool ovrFlowOr = m_rcvdProtoJets.at(j).overFlow();
361  bool tauVetoOr = m_rcvdProtoJets.at(j).tauVeto();
362  unsigned rgnsAboveIsoThreshold = (m_rcvdProtoJets.at(j).featureBit0() ? 1 : 0);
363 
364  // Combine with the corresponding regions from
365  // the local array to make a 3x3 jet cluster
366  unsigned column = 1 - localPhi0;
367  // Which rows are we looking over?
368  unsigned rowStart, rowEnd;
369  static const unsigned row0 = N_EXTRA_REGIONS_ETA00 - 1;
370  rowStart = row0 + localEta0;
371  if (localEta0 < COL_OFFSET - row0 - 2) {
372  rowEnd = rowStart + 3;
373  } else {
374  rowEnd = COL_OFFSET;
375  }
376  unsigned index = COL_OFFSET * (this->centralCol0() + column) + rowStart;
377  for (unsigned row = rowStart; row < rowEnd; ++row) {
378  etCluster += m_inputRegions.at(index).et();
379  ovrFlowOr |= m_inputRegions.at(index).overFlow();
380  if (m_useImprovedTauAlgo) {
382  tauVetoOr |= m_inputRegions.at(index).tauVeto();
383  }
384  // check the region energy against the isolation threshold
385  if (m_inputRegions.at(index).et() >= m_tauIsolationThreshold) {
386  rgnsAboveIsoThreshold++;
387  }
388  } else {
389  tauVetoOr |= m_inputRegions.at(index).tauVeto();
390  }
391 
392  ++index;
393  }
394 
395  // Store the new jet
396  unsigned eta = m_rcvdProtoJets.at(j).gctEta();
397  unsigned phi = m_rcvdProtoJets.at(j).gctPhi();
398  int16_t bx = m_rcvdProtoJets.at(j).bx();
399 
400  // Use the number of towers over threshold for the isolated tau algorithm
401  if (m_useImprovedTauAlgo) {
402  tauVetoOr |= (rgnsAboveIsoThreshold > 1);
403  }
404 
405  L1GctRegion temp(L1GctRegion::makeFinalJetRegion(etCluster, ovrFlowOr, tauVetoOr, eta, phi, bx));
406  m_clusters.at(j) = temp;
407  }
408  }
409  }
410 }
411 
414  for (unsigned j = 0; j < MAX_JETS_OUT; ++j) {
415  bool isForward = (m_clusters.at(j).rctEta() >= m_EtaBoundry);
416  unsigned JET_THRESHOLD = (isForward ? m_FwdJetSeed : m_CenJetSeed);
417  if (m_clusters.at(j).et() >= JET_THRESHOLD) {
418  m_keptProtoJets.at(j) = m_clusters.at(j);
419  m_sentProtoJets.at(j) = m_clusters.at(j);
420  }
421  }
422 }
423 
426  for (unsigned j = 0; j < MAX_JETS_OUT; ++j) {
427  bool isForward = (m_clusters.at(j).rctEta() >= m_EtaBoundry);
428  unsigned JET_THRESHOLD = (isForward ? m_FwdJetSeed : m_CenJetSeed);
429  if (m_clusters.at(j).et() >= JET_THRESHOLD) {
430  L1GctJet temp(m_clusters.at(j).et(),
431  m_clusters.at(j).gctEta(),
432  m_clusters.at(j).gctPhi(),
433  m_clusters.at(j).overFlow(),
434  isForward,
435  m_clusters.at(j).tauVeto(),
436  m_clusters.at(j).bx());
437  m_outputJets.at(j) = temp;
438  }
439  }
440 }
void reset()
complete reset of processor
unsigned m_numberOfClusters
The number of local Maxima/clusters found at each stage of clustering.
static const unsigned int MAX_JETS_OUT
Max of 6 jets found per jetfinder in a 2*11 search area.
void findFinalClusters()
Convert protojets to final jets.
unsigned rctPhi() const
get local phi index (within RCT crate)
Definition: L1CaloRegion.h:150
void process() override
process the data, fill output buffers
RegionsVector m_sentProtoJets
List of pre-clustered jets to be sent to neighbour after the first stage of clustering.
void findProtoJets()
The first stage of clustering, called by fetchInput()
void convertClustersToProtoJets()
Organise the pre-clustered jets into the ones we keep and those we send to the neighbour.
void findJets()
The second stage of clustering, called by process()
static const unsigned int MAX_REGIONS_IN
The real jetFinders must define these constants.
bool isForward(DetId const &)
Gct version of a calorimeter region, used within GCT emulation.
Definition: L1GctRegion.h:17
RegionsVector m_clusters
Each local maximum becomes a cluster.
L1GctHardwareJetFinder(int id)
id is 0-8 for -ve Eta jetfinders, 9-17 for +ve Eta, for increasing Phi.
static L1GctRegion makeProtoJetRegion(const unsigned et, const bool overFlow, const bool fineGrain, const bool tauIsolationVeto, const unsigned ieta, const unsigned iphi, const int16_t bx)
Definition: L1GctRegion.cc:13
A Level-1 jet candidate, used within GCT emulation.
Definition: L1GctJet.h:26
void fetchInput() override
get input data from sources
static const unsigned N_ETA
void findLocalMaxima()
Find local maxima in the search array.
Base class to allow implementation of jetFinder algorithms.
void findProtoClusters()
Convert local maxima to clusters.
unsigned rctEta() const
Definition: L1GctRegion.h:50
void sortJets()
Sort the found jets. All jetFinders should call this in process().
static L1GctRegion makeFinalJetRegion(const unsigned et, const bool overFlow, const bool fineGrain, const unsigned ieta, const unsigned iphi, const int16_t bx)
Definition: L1GctRegion.cc:29
static const unsigned int N_EXTRA_REGIONS_ETA00
Number of additional regions to process on the "wrong" side of eta=0 (determines COL_OFFSET) ...
unsigned short int UShort
RegionsVector m_keptProtoJets
List of pre-clustered jets retained locally as input to the final clustering.
static const unsigned int COL_OFFSET
The index offset between columns.
RawJetVector m_outputJets
output jets
int16_t bx() const
get bunch-crossing index
Definition: L1CaloRegion.h:165
RegionsVector m_inputRegions
bool setupOk() const
Check setup is Ok.
static const unsigned int N_COLS
unsigned gctEta() const
get GCT eta index
Definition: L1CaloRegion.h:153
virtual void reset()
include additional reset functionality
void fetchProtoJetsFromNeighbour(const fetchType ft)
fetch the protoJets from neighbour jetFinder
void convertClustersToOutputJets()
Organise the final clustered jets into L1GctJets.
std::ostream & operator<<(std::ostream &os, const L1GctHardwareJetFinder &algo)
unsigned gctPhi() const
get GCT phi index
Definition: L1CaloRegion.h:156
Emulation of the hardware jet finder.
static const unsigned N_PHI
unsigned m_minColThisJf
parameter to determine which Regions belong in our acceptance
static const unsigned int CENTRAL_COL0
RegionsVector m_rcvdProtoJets
List of pre-clustered jets received from neighbour before the final stage of clustering.
std::vector< L1GctRegion > RegionsVector
bool m_useImprovedTauAlgo
Setup parameters for the tau jet algorithm.
void doEnergySums()
Fill the Et strip sums and Ht sum. All jetFinders should call this in process().
unsigned centralCol0() const override
L1GctRegion makeProtoJet(L1GctRegion localMax)
Method to make a single proto-jet.
RegionsVector m_localMaxima
Local vectors used during both stages of clustering.