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