ATLAS Offline Software
Loading...
Searching...
No Matches
CaloTopoClusterMaker.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5//-----------------------------------------------------------------------
6// File and Version Information:
7// $Id: CaloTopoClusterMaker.cxx,v 1.44 2009-05-19 10:04:47 gunal Exp $
8//
9// Description: see CaloTopoClusterMaker.h
10//
11// Environment:
12// Software developed for the ATLAS Detector at CERN LHC
13//
14// Author List:
15// Sven Menke
16//
17//-----------------------------------------------------------------------
18
19//-----------------------
20// This Class's Header --
21//-----------------------
25#include "CaloTopoTmpHashCell.h"
29#include "CaloEvent/CaloCell.h"
34#include "GaudiKernel/StatusCode.h"
35#include "CLHEP/Units/SystemOfUnits.h"
36#include <vector>
37#include <algorithm>
38#include <iterator>
39#include <sstream>
40#include <memory>
41
43
44#include "CaloProtoCluster.h"
45
46using CLHEP::MeV;
47using CLHEP::ns;
48
49//#############################################################################
50
52 const std::string& name,
53 const IInterface* parent)
54
55 : AthAlgTool(type, name, parent),
56 m_calo_id(nullptr),
57 m_cellsKey(""),
62 m_seedThresholdOnTAbs ( 12.5*ns),
64 m_xtalkDeltaT ( 15.*ns),
65 m_xtalk2Eratio1 ( 4.),
66 m_xtalk2Eratio2 ( 25.),
67 m_xtalk3Eratio ( 10.),
69 m_xtalk2DEratio (4.),
70 m_neighborOption ("super3D"),
71 m_nOption (LArNeighbours::super3D),
74 m_seedCutsInAbsE (false),
76 m_cellCutsInAbsE (true),
78 m_clusterEtorAbsEtCut ( 0.*MeV),
79 m_twogaussiannoise (false),
81 m_seedCutsInT (false),
82 m_cutOOTseed (false),
84 m_xtalkEM2 (false),
85 m_xtalkEM2D (false),
86 m_xtalkEM2n (false),
87 m_xtalkEM3 (false),
88 m_xtalkEMEta (false),
89 m_minSampling (0),
90 m_maxSampling (0),
91 m_hashMin (999999),
92 m_hashMax (0),
94{
95 declareInterface<CaloClusterCollectionProcessor> (this);
96 // Name(s) of Cell Containers
97 declareProperty("CellsName",m_cellsKey);
98
99 // Name(s) of Calorimeters to consider
100 declareProperty("CalorimeterNames",m_caloNames);
101
102 // Name(s) of Calorimeter Samplings to consider for seeds
103 declareProperty("SeedSamplingNames",m_samplingNames);
104
105 // Energy thresholds (in units of noise Sigma)
106 declareProperty("SeedThresholdOnEorAbsEinSigma",
108 declareProperty("NeighborThresholdOnEorAbsEinSigma",
110 declareProperty("CellThresholdOnEorAbsEinSigma",
112
113 // Seed and cluster cuts are in E or Abs E
114 declareProperty("SeedCutsInAbsE",m_seedCutsInAbsE);
115
116 // Time thresholds (in abs. val.)
117 declareProperty("SeedThresholdOnTAbs",m_seedThresholdOnTAbs);
118
119 // Significance upper limit for applying time cut
120 declareProperty("TimeCutUpperLimit",m_timeCutUpperLimit);
121
122 //do Seed cuts on Time
123 declareProperty("SeedCutsInT",m_seedCutsInT);
124 //exclude out-of-time seeds from neighbouring and cell stage
125 declareProperty("CutOOTseed",m_cutOOTseed);
126 //do not apply time cut on cells of large significance
127 declareProperty("UseTimeCutUpperLimit",m_useTimeCutUpperLimit);
128 //relax time window (if timing is used) in EM2 when xTalk is present
129 declareProperty("XTalkEM2",m_xtalkEM2);
130 //relax time window (if timing is used) in EM2 when xTalk is present for all 2D neighbirs
131 declareProperty("XTalkEM2D",m_xtalkEM2D);
132 //relax time window (if timing is used) in EM2 Eta directionwhen xTalk is present
133 declareProperty("XTalkEMEta",m_xtalkEMEta);
134 //relax time window (if timing is used) in EM2 when xTalk is present also for 2nd phi neighbors (if XTalkEM2 is also set)
135 declareProperty("XTalkEM2n",m_xtalkEM2n);
136 //relax time window (if timing is used) in EM3 when xTalk is present for layer 3 neighbor of high energy layer 2 cells
137 declareProperty("XTalkEM3",m_xtalkEM3);
138 //delta T to add to upper time threshold for EM2 cells affected by xtalk
139 declareProperty("XTalkDeltaT",m_xtalkDeltaT);
140 //Eratio for first phi neighbor in layer2
141 declareProperty("XTalk2Eratio1",m_xtalk2Eratio1);
142 //Eratio for second phi neighbor in layer2
143 declareProperty("XTalk2Eratio2",m_xtalk2Eratio2);
144 //Eratio for previous sampling neighbor in layer 3
145 declareProperty("XTalk3Eratio",m_xtalk3Eratio);
146 //Eratio for cross-talk in eta layer 2
147 declareProperty("XTalkEtaEratio",m_xtalkEtaEratio);
148 //Eratio for cross-talk in all 2D layer 2 neighbors
149 declareProperty("XTalk2DEratio",m_xtalk2DEratio);
150
151 // Neighbor cuts are in E or Abs E
152 declareProperty("NeighborCutsInAbsE",m_neighborCutsInAbsE);
153
154 // Cell cuts are in E or Abs E
155 declareProperty("CellCutsInAbsE",m_cellCutsInAbsE);
156
157 // Neighbor Option
158 declareProperty("NeighborOption",m_neighborOption);
159
160 // Restrict HEC IW and FCal Neighbors
161 declareProperty("RestrictHECIWandFCalNeighbors",m_restrictHECIWandFCalNeighbors);
162
163 // Restrict PS Neighbors
164 declareProperty("RestrictPSNeighbors",m_restrictPSNeighbors);
165
166 //Cluster cuts are in E_t or Abs E_t
167 declareProperty("ClusterCutsInAbsEt",m_clusterCutsInAbsE);
168
169 // Cluster E_t or Abs E_t cut
170 declareProperty("ClusterEtorAbsEtCut",m_clusterEtorAbsEtCut);
171
172 // use 2-gaussian noise for Tile
173 declareProperty("TwoGaussianNoise",m_twogaussiannoise);
174
175 // Treat bad cells with dead OTX if predicted from L1 as good
176 declareProperty("TreatL1PredictedCellsAsGood",m_treatL1PredictedCellsAsGood);
177}
178
179//#############################################################################
180
182{
183 ATH_MSG_INFO( "Initializing " << name() );
184 ATH_MSG_INFO( "Treat L1 Predicted Bad Cells as Good set to" << ((m_treatL1PredictedCellsAsGood) ? "true" : "false") );
185 ATH_MSG_INFO( "Two-Gaussian noise for Tile set to " << ((m_twogaussiannoise) ? "true" : "false") );
186 ATH_CHECK( m_cellsKey.initialize() );
188
189 ATH_CHECK( detStore()->retrieve (m_calo_id, "CaloCell_ID") );
190
191 ATH_MSG_INFO( "Threshold choices:"
192 << (m_seedCutsInAbsE?" SeedThresholdOnAbsEinSigma=":
193 " SeedThresholdOnEinSigma=")
195 << (m_neighborCutsInAbsE?", NeighborThresholdOnAbsEinSigma=":
196 ", NeighborThresholdOnEinSigma=")
198 << (m_cellCutsInAbsE?", CellThresholdOnAbsEinSigma=":
199 ", CellThresholdOnEinSigma=")
201 );
202
203 ATH_MSG_INFO( "Time cut option: " << ((!m_seedCutsInT) ? "None" : (m_cutOOTseed ? "Seed Extended" : "Seed")));
204 ATH_MSG_INFO( "E/sigma veto on T cut: m_useTimeCutUpperLimit=" << (m_useTimeCutUpperLimit ? "true" : "false") << ", m_timeCutUpperLimit=" << m_timeCutUpperLimit);
205
206 //--- set Neighbor Option
207
208 if ( m_neighborOption == "all2D" )
210 else if ( m_neighborOption == "all3D" )
212 else if ( m_neighborOption == "super3D" )
214 else {
215 ATH_MSG_ERROR( "Invalid Neighbor Option "
216 << m_neighborOption << ", exiting ..." );
217 return StatusCode::FAILURE;
218 }
219
220 ATH_MSG_INFO( "Neighbor Option "
221 << m_neighborOption << " is selected!" );
222
223 //--- check calorimeter names to use
224 for (const std::string& caloName : m_caloNames) {
225 if ( caloName == "LAREM" )
227 else if ( caloName == "LARHEC" )
229 else if ( caloName == "LARFCAL" )
231 else if ( caloName == "TILE" )
233 else
234 ATH_MSG_ERROR( "Calorimeter " << caloName
235 << " is not a valid Calorimeter name and will be ignored! "
236 << "Valid names are: LAREM, LARHEC, LARFCAL, and TILE." );
237 }
238
239 //--- check sampling names to use for seeds
240 for (const std::string& sampName : m_samplingNames) {
241 if ( sampName == "PreSamplerB" )
242 m_validSamplings.insert(CaloCell_ID::PreSamplerB);
243 else if ( sampName == "EMB1" )
244 m_validSamplings.insert(CaloCell_ID::EMB1);
245 else if ( sampName == "EMB2" )
246 m_validSamplings.insert(CaloCell_ID::EMB2);
247 else if ( sampName == "EMB3" )
248 m_validSamplings.insert(CaloCell_ID::EMB3);
249 else if ( sampName == "PreSamplerE" )
250 m_validSamplings.insert(CaloCell_ID::PreSamplerE);
251 else if ( sampName == "EME1" )
252 m_validSamplings.insert(CaloCell_ID::EME1);
253 else if ( sampName == "EME2" )
254 m_validSamplings.insert(CaloCell_ID::EME2);
255 else if ( sampName == "EME3" )
256 m_validSamplings.insert(CaloCell_ID::EME3);
257 else if ( sampName == "HEC0" )
258 m_validSamplings.insert(CaloCell_ID::HEC0);
259 else if ( sampName == "HEC1" )
260 m_validSamplings.insert(CaloCell_ID::HEC1);
261 else if ( sampName == "HEC2" )
262 m_validSamplings.insert(CaloCell_ID::HEC2);
263 else if ( sampName == "HEC3" )
264 m_validSamplings.insert(CaloCell_ID::HEC3);
265 else if ( sampName == "TileBar0" )
266 m_validSamplings.insert(CaloCell_ID::TileBar0);
267 else if ( sampName == "TileBar1" )
268 m_validSamplings.insert(CaloCell_ID::TileBar1);
269 else if ( sampName == "TileBar2" )
270 m_validSamplings.insert(CaloCell_ID::TileBar2);
271 else if ( sampName == "TileGap1" )
272 m_validSamplings.insert(CaloCell_ID::TileGap1);
273 else if ( sampName == "TileGap2" )
274 m_validSamplings.insert(CaloCell_ID::TileGap2);
275 else if ( sampName == "TileGap3" )
276 m_validSamplings.insert(CaloCell_ID::TileGap3);
277 else if ( sampName == "TileExt0" )
278 m_validSamplings.insert(CaloCell_ID::TileExt0);
279 else if ( sampName == "TileExt1" )
280 m_validSamplings.insert(CaloCell_ID::TileExt1);
281 else if ( sampName == "TileExt2" )
282 m_validSamplings.insert(CaloCell_ID::TileExt2);
283 else if ( sampName == "FCAL0" )
284 m_validSamplings.insert(CaloCell_ID::FCAL0);
285 else if ( sampName == "FCAL1" )
286 m_validSamplings.insert(CaloCell_ID::FCAL1);
287 else if ( sampName == "FCAL2" )
288 m_validSamplings.insert(CaloCell_ID::FCAL2);
289 else
290 ATH_MSG_ERROR( "Calorimeter sampling" << sampName
291 << " is not a valid Calorimeter sampling name and will be ignored! "
292 << "Valid names are: "
293 << "PreSamplerB, EMB1, EMB2, EMB3, "
294 << "PreSamplerE, EME1, EME2, EME3, "
295 << "HEC0, HEC1, HEC2, HEC3, "
296 << "TileBar0, TileBar1, TileBar2, "
297 << "TileGap1, TileGap2, TileGap3, "
298 << "TileExt0, TileExt1, TileExt2, "
299 << "FCAL0, FCAL1, FCAL2." );
300 }
301
302 msg(MSG::INFO) << "Samplings to consider for seeds:";
303 for (const std::string& sampName : m_samplingNames)
304 msg() << " " << sampName;
305 msg() << endmsg;
306
309 for (int s : m_validSamplings) {
310 if ( s > m_maxSampling )
311 m_maxSampling = s;
312 if ( s < m_minSampling )
313 m_minSampling = s;
314 }
315
317
318 for (int s : m_validSamplings) {
320 }
321
322 ATH_MSG_INFO( "CellCollection to use: " << m_cellsKey.key() );
323
324 msg(MSG::INFO) << "Calorimeters to consider:";
325 for (const std::string& caloName : m_caloNames)
326 msg() << " " << caloName;
327 msg() << endmsg;
328
329 //---- retrieve the noise CDO ----------------
330
331 ATH_CHECK(m_noiseCDOKey.initialize());
332
333 ATH_MSG_INFO( (m_clusterCutsInAbsE?"ClusterAbsEtCut= ":"ClusterEtCut= ")
334 << m_clusterEtorAbsEtCut << " MeV" );
335
336 m_hashMin = 999999;
337 m_hashMax = 0;
338 for (int subdet = 0; subdet < CaloCell_ID::NSUBCALO; ++subdet) {
339 if (m_subcaloUsed[subdet]) {
340 IdentifierHash thismin, thismax;
341 m_calo_id->calo_cell_hash_range ((CaloCell_ID::SUBCALO)subdet,
342 thismin, thismax);
343 m_hashMin = std::min (m_hashMin, thismin);
344 m_hashMax = std::max (m_hashMax, thismax);
345 }
346 }
347
348 //ATH_CHECK( m_cablingKey.initialize() );
349
350 // silence possible warnings from AuxSelection (ATLASRECTS-7180)
351 xAOD::CaloCluster dummyCluster;
352 static const SG::ConstAccessor<ElementLink<CaloClusterCellLinkContainer> > accCellLinks("CellLink");
353 (void) accCellLinks.isAvailable(dummyCluster);
354
355 return StatusCode::SUCCESS;
356
357}
358
359//#############################################################################
360
361StatusCode
362CaloTopoClusterMaker::execute(const EventContext& ctx,
363 xAOD::CaloClusterContainer* clusColl) const
364{
365 // minimal significance - should be > 0 in order to avoid
366 // throwing away of bad cells
367 const float epsilon = 0.00001;
368
369 //ATH_MSG_DEBUG( "Executing " << name());
370
372 using HashCluster = CaloTopoTmpHashCluster;
373
377
378 // create cell list for cells above seed cut (for seed growing algo)
379 std::vector<HashCell> mySeedCells;
380 mySeedCells.reserve (2000);
381 // create initial cluster list (one cell per cluster)
382 std::vector<HashCluster *> myHashClusters;
383 myHashClusters.reserve (10000);
384
385 // create vector to hold all cells.
386 std::vector<HashCell> cellVector (m_hashMax - m_hashMin);
387 HashCell* hashCells = cellVector.data() - m_hashMin;
388
389
391 const CaloNoise* noiseCDO=*noiseHdl;
392
393 //---- Get the CellContainers ----------------
394
395 // for (const std::string& cellsName : m_cellsNames) {
397 if( !cellColl.isValid()){
398 ATH_MSG_ERROR( " Can not retrieve CaloCellContainer: "
399 << cellColl.name() );
400 return StatusCode::RECOVERABLE;
401 }
402
403 const DataLink<CaloCellContainer> cellCollLink (cellColl.name(),ctx);
404
405 //ATH_MSG_DEBUG("CaloCell container: "<< cellsName
406 // <<" contains " << cellColl->size() << " cells");
407
408 for (int isubdet = 0; isubdet < CaloCell_ID::NSUBCALO; ++isubdet) {
410 if (m_subcaloUsed[subdet] && cellColl->hasCalo(subdet)) {
411 auto cellIter = cellColl->beginConstCalo (subdet);
412 auto cellIterEnd = cellColl->endConstCalo (subdet);
413 for (int iCell = cellColl->indexFirstCellCalo(subdet);
414 cellIter != cellIterEnd;
415 ++iCell, ++cellIter)
416 {
417 CaloPrefetch::nextDDE(cellIter, cellIterEnd, 2);
418 const CaloCell* pCell = *cellIter;
419 const float noiseSigma = m_twogaussiannoise ? \
420 noiseCDO->getEffectiveSigma(pCell->ID(),pCell->gain(),pCell->energy()) : \
421 noiseCDO->getNoise(pCell->ID(),pCell->gain());
422
423 float signedE = pCell->energy();
424 float signedEt = pCell->et();
425 float signedRatio = epsilon; // not 0 in order to keep bad cells
426 if ( finite(noiseSigma) && noiseSigma > 0 && !CaloBadCellHelper::isBad(pCell,m_treatL1PredictedCellsAsGood) )
427 signedRatio = signedE/noiseSigma;
428
429 bool passedCellCut = (m_cellCutsInAbsE?std::abs(signedRatio):signedRatio) > m_cellThresholdOnEorAbsEinSigma;
430 bool passedNeighborCut = (m_neighborCutsInAbsE?std::abs(signedRatio):signedRatio) > m_neighborThresholdOnEorAbsEinSigma;
431 bool passedSeedCut = (m_seedCutsInAbsE?std::abs(signedRatio):signedRatio) > m_seedThresholdOnEorAbsEinSigma;
432
433 bool applyTimeCut = m_seedCutsInT && (!m_useTimeCutUpperLimit || signedRatio <= m_timeCutUpperLimit);
434 bool passTimeCut_seedCell = (!applyTimeCut || passCellTimeCut(pCell,cellColl.cptr()));
435 bool passedSeedAndTimeCut = (passedSeedCut && passTimeCut_seedCell);
436
437 bool passedNeighborAndTimeCut = passedNeighborCut;
438 if(m_cutOOTseed && passedSeedCut && !passTimeCut_seedCell) passedNeighborAndTimeCut=false; //exclude Out-Of-Time seeds from neighbouring stage as well (if required)
439
440 bool passedCellAndTimeCut = passedCellCut;
441 if(m_cutOOTseed && passedSeedCut && !passTimeCut_seedCell) passedCellAndTimeCut=false; //exclude Out-Of-Time seeds from cluster (if required)
442
443 if ( passedCellAndTimeCut || passedNeighborAndTimeCut || passedSeedAndTimeCut ) {
444 const CaloDetDescrElement* dde = pCell->caloDDE();
445 IdentifierHash hashid = dde ? dde->calo_hash() : m_calo_id->calo_cell_hash(pCell->ID());
446 CaloTopoTmpClusterCell *tmpClusterCell =
447 new (tmpcell_pool.allocate())
448 CaloTopoTmpClusterCell(hashid,subdet,iCell,signedRatio,signedEt);
449#if 0
450 // some debug printout - can also be used to construct neighbor
451 // tables offline ...
452 if ( m_doALotOfPrintoutInFirstEvent ) {
453 ATH_MSG_DEBUG( " [ExtId|Id|SubDet|HashId|eta|phi|E/noise|Et]: "
454 << "[" << m_calo_id->show_to_string(pCell->ID(),0,'/')
455 << "|" << mypCell->ID().getString()
456 << "|" << subdet
457 << "|" << (unsigned int)hashid
458 << "|" << pCell->eta()
459 << "|" << pCell->phi()
460 << "|" << signedRatio
461 << "|" << signedEt
462 << "]");
463
464 }
465#endif
466 HashCell hashCell(tmpClusterCell);
467 if ( passedNeighborAndTimeCut || passedSeedAndTimeCut ) {
468 HashCluster *tmpCluster =
469 new (tmpclus_pool.allocate()) HashCluster (tmplist_pool);
470 tmpClusterCell->setCaloTopoTmpHashCluster(tmpCluster);
471 tmpCluster->add(hashCell);
472 myHashClusters.push_back(tmpCluster);
473 int caloSample = dde ? dde->getSampling() : m_calo_id->calo_sample(pCell->ID());
474 if ( passedSeedAndTimeCut
475 && caloSample >= m_minSampling
476 && caloSample <= m_maxSampling
477 && m_useSampling[caloSample-m_minSampling]) {
478 tmpClusterCell->setUsed();
479 mySeedCells.push_back(hashCell);
480 }
481 }
482 hashCells[hashid] = hashCell;
483 }
484 }//end loop over cells
485 }//end if use subcalo
486 }//end loop over subcalos
487
488
489 // sort initial seed cells to start with the cell of largest S/N
490 // this makes the resulting clusters independent of the initial
491 // ordering of the cells
492 if ( m_useGPUCriteria) {
493 if ( m_seedCutsInAbsE) {
495 std::sort(mySeedCells.begin(),mySeedCells.end(),compareSoverN);
496 }
497 else {
499 std::sort(mySeedCells.begin(),mySeedCells.end(),compareSoverN);
500 }
501 }
502 else {
503 if ( m_seedCutsInAbsE) {
505 std::sort(mySeedCells.begin(),mySeedCells.end(),compareSoverN);
506 }
507 else {
509 std::sort(mySeedCells.begin(),mySeedCells.end(),compareSoverN);
510 }
511 }
512
513#if 1
514 if (msgLvl(MSG::DEBUG)) {
515 for (const HashCell& hc : mySeedCells) {
516 ATH_MSG_DEBUG( " SeedCell ["
517 << hc.getCaloTopoTmpClusterCell()->getSubDet()
518 << "|"
519 << (unsigned int)hc.getCaloTopoTmpClusterCell()->getID()
520 << "] has S/N = "
521 << hc.getCaloTopoTmpClusterCell()->getSignedRatio()
522 );
523 }
524 }
525#endif
526
527 std::vector<HashCell> myNextCells;
528 myNextCells.reserve (1000);
529
530 std::vector<IdentifierHash> theNeighbors;
531 theNeighbors.reserve(22);
532#if 0
533 std::vector<IdentifierHash> theNNeighbors;
534 theNNeighbors.reserve(22);
535#endif
536
537 bool doRestrictHECIWandFCal = m_restrictHECIWandFCalNeighbors &&
539
540 bool doRestrictPS = m_restrictPSNeighbors &&
542
543 while ( !mySeedCells.empty() ) {
544 // create cell list for next neighbor cells to consider
545 myNextCells.clear();
546
547 // loop over all current neighbor cells (for Seed Growing Algo)
548 for (HashCell& hc : mySeedCells) {
549 CaloTopoTmpClusterCell* pCell= hc.getCaloTopoTmpClusterCell();
550 IdentifierHash hashid = pCell->getID();
551 HashCluster *myCluster = pCell->getCaloTopoTmpHashCluster();
552 CaloCell_ID::SUBCALO mySubDet = pCell->getSubDet();
553 // in case we use all3d or super3D and the current cell is in the
554 // HEC IW or FCal2 & 3 or PS and we want to restrict their neighbors,
555 // use only next in sampling neighbors
557 if (( mySubDet != CaloCell_ID::LAREM &&
558 doRestrictHECIWandFCal &&
559 ( ( mySubDet == CaloCell_ID::LARHEC &&
560 m_calo_id->region(m_calo_id->cell_id(hashid)) == 1 ) ||
561 ( mySubDet == CaloCell_ID::LARFCAL &&
562 m_calo_id->sampling(m_calo_id->cell_id(hashid)) > 1 ) ) ) ||
563 ( doRestrictPS &&
564 ( ( mySubDet == CaloCell_ID::LAREM &&
565 m_calo_id->sampling(m_calo_id->cell_id(hashid)) == 0 ) ) ) ) {
567 }
568 m_calo_id->get_neighbours(hashid,opt,theNeighbors);
569 // loop over all neighbors of that cell (Seed Growing Algo)
570 for (IdentifierHash nId : theNeighbors) {
571 CaloCell_ID::SUBCALO otherSubDet =
572 (CaloCell_ID::SUBCALO)m_calo_id->sub_calo(nId);
573 if ( otherSubDet < CaloCell_ID::NSUBCALO &&
574 m_subcaloUsed[otherSubDet] )
575 {
576 HashCell neighborCell = hashCells[nId];
577 if ( neighborCell.getCaloTopoTmpClusterCell() ) {
578 CaloTopoTmpClusterCell* pNCell = neighborCell.getCaloTopoTmpClusterCell();
579 // check neighbor threshold only since seed cells are already in
580 // the original list
581 bool isAboveNeighborThreshold =
583 // checking the neighbors
584 if ( isAboveNeighborThreshold && !pNCell->getUsed() ) {
585 pNCell->setUsed();
586 myNextCells.push_back(neighborCell);
587 }
588 HashCluster *otherCluster = pNCell->getCaloTopoTmpHashCluster();
589 if ( myCluster != otherCluster ) {
590 HashCluster *toKill = nullptr;
591 HashCluster *toKeep = nullptr;
592 if ( !otherCluster || isAboveNeighborThreshold ) {
593
594 auto compareClusters = [&](const auto & c1, const auto & c2) {
595 if (m_useGPUCriteria) {
596 //The seed cell with the largest SNR wins
597 if (m_seedCutsInAbsE) {
599 return compare(*(c1->begin()), *(c2->begin()));
600 }
601 else {
603 return compare(*(c1->begin()), *(c2->begin()));
604 }
605 }
606 else {
607 //We merge the smallest cluster to the largest...
608 return c1->size() > c2->size();
609 }
610 };
611
612 if ( !otherCluster || compareClusters(myCluster, otherCluster) ) {
613 toKill = otherCluster;
614 toKeep = myCluster;
615 }
616 else {
617 toKill = myCluster;
618 toKeep = otherCluster;
619 }
620 if ( toKill ) {
621 for (auto *hc : *toKill)
622 hc->setCaloTopoTmpHashCluster(toKeep);
623 toKeep->add(*toKill);
624 toKill->removeAll();
625 }
626 else {
627 toKeep->add(neighborCell);
628 pNCell->setCaloTopoTmpHashCluster(toKeep);
629 }
630 myCluster = toKeep;
631 }
632 }
633 }
634 }
635 }
636 }
637 mySeedCells.swap (myNextCells);
638 }
639
640
641 //Create temporary list of proto-clusters
642 //Clusters below Et cut will be dropped.
643 //The remaining clusters will be sorted in E_t before storing
644 std::vector<std::unique_ptr<CaloProtoCluster> > sortClusters;
645 sortClusters.reserve (myHashClusters.size());
646
647 for (HashCluster* tmpCluster : myHashClusters) {
648 bool addCluster(false);
649 if ( tmpCluster->size() > 1 )
650 addCluster = true;
651 else if ( tmpCluster->size() == 1 ) {
652 // need to check if seed cell was good
653 HashCluster::iterator clusCellIter=tmpCluster->begin();
654 if ( clusCellIter->getUsed() )
655 addCluster = true;
656 }
657 if ( addCluster) {
658 std::unique_ptr<CaloProtoCluster> myCluster = std::make_unique<CaloProtoCluster>(cellCollLink);
659 //CaloProtoCluster* myCluster = new CaloProtoCluster(cellCollLink);
660 myCluster->getCellLinks()->reserve(tmpCluster->size());
661
662 for (CaloTopoTmpClusterCell* cell : *tmpCluster) {
663 const size_t iCell = cell->getCaloCell();
664 myCluster->addCell(iCell,1.);
665 }
666 const float cl_et = myCluster->et();
667 if ( (m_clusterCutsInAbsE ? std::abs(cl_et) : cl_et) > m_clusterEtorAbsEtCut ) {
668 sortClusters.push_back(std::move(myCluster));
669 }
670 }
671 }
672
673 // Sort the clusters according to Et
674 std::sort(sortClusters.begin(),sortClusters.end(),[](const std::unique_ptr<CaloProtoCluster>& pc1,
675 const std::unique_ptr<CaloProtoCluster>& pc2) {
676 //As in CaloUtils/CaloClusterEtSort.
677 //assign to volatile to avoid excess precison on in FP unit on x386 machines
678 volatile double et1(pc1->et());
679 volatile double et2(pc2->et());
680 //return (et1 < et2); //This is the order we had from CaloRec-02-13-11 to CaloRec-03-00-31
681 return (et1 > et2); //This is the order we should have
682 }
683 );
684 // add to cluster container
685 clusColl->reserve(sortClusters.size());
686
687 for (const auto& protoCluster: sortClusters) {
688 xAOD::CaloCluster* xAODCluster=new xAOD::CaloCluster();
689 clusColl->push_back(xAODCluster);
690 xAODCluster->addCellLink(protoCluster->releaseCellLinks());//Hand over ownership to xAOD::CaloCluster
691 xAODCluster->setClusterSize(m_clusterSize);
692 CaloClusterKineHelper::calculateKine(xAODCluster,false,true, m_useGPUCriteria); //No weight at this point!
693 }
694
695 tmpclus_pool.erase();
696 tmpcell_pool.erase();
697
698 return StatusCode::SUCCESS;
699}
700
718
719
720inline bool CaloTopoClusterMaker::passCellTimeCut(const CaloCell* pCell, const CaloCellContainer* cellColl) const {
721 // get the cell time to cut on (the same as in CaloEvent/CaloCluster.h)
722 bool isInTime = true;
723 // need sampling number already for time
725 // check for unknown sampling
726 if (sam != CaloSampling::PreSamplerB && sam != CaloSampling::PreSamplerE && sam != CaloSampling::Unknown) {
727 const unsigned pmask= pCell->caloDDE()->is_tile() ? 0x8080 : 0x2000;
728 //0x2000 is used to tell that time and quality information are available for this channel
729 //(from TWiki: https://twiki.cern.ch/twiki/bin/viewauth/AtlasComputing/CaloEventDataModel#The_Raw_Data_Model)
730 // Is time defined?
731 if(pCell->provenance() & pmask) {
732 isInTime = (std::abs(pCell->time())<m_seedThresholdOnTAbs);
733 if ( m_xtalkEM2 && (!isInTime) && (pCell->energy() > 0 && (sam == CaloSampling::EMB2 || (sam == CaloSampling::EME2 && std::abs(pCell->eta()) < 2.5)))) {
734 // relax time constraints in EMB2 and EME2_OW due to xTalk from direct phi neighbours
735 // check if |E| is less than 0.25 times one of the |E| values of direct
736 // phi-neighbours. In case that phi-neigbour is in-time, expand upper limit by m_xtalkDeltaT
737 IdentifierHash hashid = pCell->caloDDE()->calo_hash();
738 std::vector<IdentifierHash> theNeighbors;
739 LArNeighbours::neighbourOption opt = (LArNeighbours::neighbourOption)(((int)LArNeighbours::prevInPhi)|((int)LArNeighbours::nextInPhi)); // shoud make a proper enum in LarNeighbours.h for this one ...
740 m_calo_id->get_neighbours(hashid,opt,theNeighbors);
741 // loop over all neighbors of that cell (Seed Growing Algo)
742 for (IdentifierHash nId : theNeighbors) {
743 const CaloCell * pNCell = cellColl->findCell(nId);
744 if ( pNCell ) {
745 if ( pNCell->energy() > m_xtalk2Eratio1*pCell->energy() ) {
746 if ( (!(pNCell->provenance() & pmask)) || std::abs(pNCell->time()) < m_seedThresholdOnTAbs) {
747 isInTime = ((pCell->time() > -m_seedThresholdOnTAbs) && (pCell->time() < m_seedThresholdOnTAbs + m_xtalkDeltaT));
748 if ( isInTime ) {
749 // exit after first phi neighbour in case that already made
750 // the time-cut pass
751 break;
752 }
753 }
754 }
755
756 // check second neighbor
757 if (m_xtalkEM2n) {
758 std::vector<IdentifierHash> theNextNeighbors;
759 m_calo_id->get_neighbours(nId,opt,theNextNeighbors);
760 for (IdentifierHash n2Id : theNextNeighbors) {
761 if (n2Id != hashid) {
762 const CaloCell * p2NCell = cellColl->findCell(n2Id);
763 if (p2NCell) {
764 if (p2NCell->energy() > m_xtalk2Eratio2*pCell->energy()) {
765 if ( (!(p2NCell->provenance() & pmask)) || std::abs(p2NCell->time()) < m_seedThresholdOnTAbs) {
766 isInTime = ((pCell->time() > -m_seedThresholdOnTAbs) && (pCell->time() < m_seedThresholdOnTAbs + m_xtalkDeltaT));
767 if (isInTime) break;
768 }
769 }
770 }
771 }
772 } // loop over 2nd neighbors
773 }
774 } // if (pNcell)
775 } // loop over first neighbors
776 } // special case for layer 2
777
778 // check cross talk in eta
779 if ( m_xtalkEMEta && (!isInTime) && (pCell->energy() > 0 && (sam == CaloSampling::EMB2 || (sam == CaloSampling::EME2 && std::abs(pCell->eta()) < 2.5)))) {
780 IdentifierHash hashid = pCell->caloDDE()->calo_hash();
781 std::vector<IdentifierHash> theNeighbors;
783 m_calo_id->get_neighbours(hashid,opt,theNeighbors);
784 for (IdentifierHash nId : theNeighbors) {
785 const CaloCell * pNCell = cellColl->findCell(nId);
786 if ( pNCell ) {
787 if ( pNCell->energy() > m_xtalkEtaEratio*pCell->energy() ) {
788 if ( (!(pNCell->provenance() & pmask)) || std::abs(pNCell->time()) < m_seedThresholdOnTAbs) {
789 isInTime = ((pCell->time() > -m_seedThresholdOnTAbs) && (pCell->time() < m_seedThresholdOnTAbs + m_xtalkDeltaT));
790 if ( isInTime ) {
791 // exit after first phi neighbour in case that already made
792 // the time-cut pass
793 break;
794 }
795 }
796 }
797 }
798 }
799 }
800
801 // option for all2D
802 if ( m_xtalkEM2D && (!isInTime) && (pCell->energy() > 0 && (sam == CaloSampling::EMB2 || (sam == CaloSampling::EME2 && std::abs(pCell->eta()) < 2.5)))) {
803 IdentifierHash hashid = pCell->caloDDE()->calo_hash();
804 std::vector<IdentifierHash> theNeighbors;
806 m_calo_id->get_neighbours(hashid,opt,theNeighbors);
807 for (IdentifierHash nId : theNeighbors) {
808 const CaloCell * pNCell = cellColl->findCell(nId);
809 if ( pNCell ) {
810 if ( pNCell->energy() > m_xtalk2DEratio*pCell->energy() ) {
811 if ( (!(pNCell->provenance() & pmask)) || std::abs(pNCell->time()) < m_seedThresholdOnTAbs) {
812 isInTime = ((pCell->time() > -m_seedThresholdOnTAbs) && (pCell->time() < m_seedThresholdOnTAbs + m_xtalkDeltaT));
813 if ( isInTime ) break;
814 }
815 }
816 }
817 }
818 }
819
820 // relax also time constraint for EMB3 and EME2_OW
821 if ( m_xtalkEM3 && (!isInTime) && (pCell->energy() > 0 && (sam == CaloSampling::EMB3 || (sam == CaloSampling::EME3 && std::abs(pCell->eta()) < 2.5)))) {
822 // check previous sampling cell, should be >10 times more (TBC)
823 IdentifierHash hashid = pCell->caloDDE()->calo_hash();
824 std::vector<IdentifierHash> theNeighbors;
826 m_calo_id->get_neighbours(hashid,opt,theNeighbors);
827 for (IdentifierHash nId : theNeighbors) {
828 const CaloCell * pNCell = cellColl->findCell(nId);
829 if ( pNCell ) {
830 if ( pNCell->energy() > m_xtalk3Eratio*pCell->energy() ) {
831 if ( (!(pNCell->provenance() & pmask)) || std::abs(pNCell->time()) < m_seedThresholdOnTAbs) {
832 isInTime = ((pCell->time() > -m_seedThresholdOnTAbs) && (pCell->time() < m_seedThresholdOnTAbs + m_xtalkDeltaT));
833 if (isInTime) break;
834 }
835 } // Eratio cut at 10
836 }
837 } // loop over neighors
838 } // cell is layer 3 EM
839
840 }
841 }
842 return isInTime;
843}
#define endmsg
User interface for allocating memory. See Arena.h for an overview of the arena-based memory allocator...
Pool-based allocator. See Arena.h for an overview of the arena-based memory allocators.
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
const ServiceHandle< StoreGateSvc > & detStore() const
bool msgLvl(const MSG::Level lvl) const
MsgStream & msg() const
Container class for CaloCell.
const CaloCell * findCell(const IdentifierHash theHash) const
fast find method given identifier hash.
CaloCell_Base_ID::SUBCALO SUBCALO
Definition CaloCell_ID.h:50
Data object for each calorimeter readout cell.
Definition CaloCell.h:57
float time() const
get time (data member)
Definition CaloCell.h:368
virtual double phi() const override final
get phi (through CaloDetDescrElement)
Definition CaloCell.h:375
double energy() const
get energy (data member)
Definition CaloCell.h:327
const CaloDetDescrElement * caloDDE() const
get pointer to CaloDetDescrElement (data member)
Definition CaloCell.h:321
uint16_t provenance() const
get provenance (data member)
Definition CaloCell.h:354
virtual double eta() const override final
get eta (through CaloDetDescrElement)
Definition CaloCell.h:382
CaloGain::CaloGain gain() const
get gain (data member )
Definition CaloCell.h:361
virtual double et() const override final
get et
Definition CaloCell.h:423
Identifier ID() const
get ID (from cached data member) non-virtual and inline for fast access
Definition CaloCell.h:295
static void calculateKine(xAOD::CaloCluster *clu, const bool useweight=true, const bool updateLayers=true, const bool useGPUCriteria=false)
Helper class to calculate cluster kinematics based on cells.
This class groups all DetDescr information related to a CaloCell.
CaloCell_ID::CaloSample getSampling() const
cell sampling
float getNoise(const IdentifierHash h, const int gain) const
Accessor by IdentifierHash and gain.
Definition CaloNoise.h:34
float getEffectiveSigma(const Identifier id, const int gain, const float energy) const
Definition CaloNoise.h:55
Wrapper for SG::ArenaHandle with pre-fetching.
void * allocate()
Return space for new element, then allocate and prefetch one more.
void erase()
Free all allocated elements.
Gaudi::Property< bool > m_useGPUCriteria
float m_xtalkDeltaT
additional max.
float m_seedThresholdOnEorAbsEinSigma
cells with start a cluster
bool m_xtalkEM2D
if set to true, the time window is softened in the EMB2 and EME2_OW due to xtalk from all 2D neighors
bool m_subcaloUsed[CaloCell_ID::NSUBCALO]
Flag which subdetectors are to be used.
float m_xtalkEtaEratio
cut on Eneighbor/E to revover out of time layer 2 cell close in eta to energetic neighor cell
SG::ReadCondHandleKey< CaloNoise > m_noiseCDOKey
Key of the CaloNoise Conditions data object.
bool m_twogaussiannoise
if set to true use 2-gaussian noise description for TileCal
bool m_xtalkEM3
if set to true we extend the time window for direct layer 3 neighbors of high energy layer 2 cells
bool m_treatL1PredictedCellsAsGood
if set to true treat cells with a dead OTX which can be predicted by L1 trigger info as good instead ...
bool m_cellCutsInAbsE
if set to true cell cuts are on and .
float m_neighborThresholdOnEorAbsEinSigma
cells with extend the cluster
std::string m_neighborOption
type of neighbor relations to use.
bool m_clusterCutsInAbsE
if set to true final cluster cuts are on .
bool passCellTimeCut(const CaloCell *, const CaloCellContainer *) const
bool m_xtalkEMEta
if set to true, the time window is softened in the EMB2 and EME2_OW due to xtalk from direct neighbou...
float m_xtalk2Eratio2
cut on Eneighbor/E to revover out of time cell close to energetic second phi neighbor cell
SG::ReadHandleKey< CaloCellContainer > m_cellsKey
vector of names of the cell containers to use as input.
bool m_useTimeCutUpperLimit
if set to true, the time cut is not applied on cell of large significance
int m_maxSampling
largest valid seed sampling found
CaloTopoClusterMaker(const std::string &type, const std::string &name, const IInterface *parent)
const CaloCell_ID * m_calo_id
float m_cellThresholdOnEorAbsEinSigma
all cells have to satisfy
bool m_neighborCutsInAbsE
if set to true neighbor cuts are on and .
float m_timeCutUpperLimit
upper limit on the energy significance, for applying the cell time cut
float m_seedThresholdOnTAbs
threshold used for timing cut on seed cells.
float m_clusterEtorAbsEtCut
cut on the final cluster.
std::vector< std::string > m_caloNames
vector of names of the calorimeters to consider.
float m_xtalk2Eratio1
cut on Eneighbor/E to revover out of time cell close to energetic first phi neighbor cell
bool m_xtalkEM2
if set to true, the time window is softened in the EMB2 and EME2_OW due to xtalk from direct neighbou...
virtual StatusCode execute(const EventContext &ctx, xAOD::CaloClusterContainer *theClusters) const override
Execute on an entire collection of clusters.
virtual StatusCode initialize() override
std::set< int > m_validSamplings
actual set of samplings to be used for seeds
LArNeighbours::neighbourOption m_nOption
std::vector< std::string > m_samplingNames
vector of names of the calorimeter samplings to consider for seeds.
bool m_restrictPSNeighbors
if set to true limit the neighbors in presampler Barrel and Endcap.
bool m_xtalkEM2n
if set to true (together with m_xtalkEM2) we also extend the time window for 2nd phi neighbors
std::vector< bool > m_useSampling
flag for all samplings - true for used ones, false for excluded ones
int m_minSampling
smallest valid seed sampling found
bool m_seedCutsInT
if set to true, time cut is applied to seed cells, no cut otherwise
bool m_seedCutsInAbsE
if set to true seed cuts are on and .
float m_xtalk3Eratio
cut on Eneighbor/E to revover out of time layer 3cell close to energetic previous sampling neighbor
float m_xtalk2DEratio
cut on Eneighbor/E to remove out of time layer layer2 all 2D neighbors
bool m_restrictHECIWandFCalNeighbors
if set to true limit the neighbors in HEC IW and FCal2&3.
bool m_cutOOTseed
if set to true, seed cells failing the time cut are also excluded from cluster at all
xAOD::CaloCluster::ClusterSize m_clusterSize
Cluster size enum. Set based on energy cut jobO.
CaloCell_ID::SUBCALO getSubDet() const
const IdentifierHash & getID() const
void setCaloTopoTmpHashCluster(CaloTopoTmpHashCluster *cluster)
const CaloTopoTmpHashCluster * getCaloTopoTmpHashCluster() const
void reserve(size_type n)
Attempt to preallocate enough memory for a specified number of elements.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
This is a "hash" representation of an Identifier.
Helper class to provide constant type-safe access to aux data.
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
const std::string & name() const
Return the StoreGate ID for the referenced object.
void addCellLink(CaloClusterCellLink *CCCL)
void setClusterSize(const ClusterSize)
Get cluster size.
void nextDDE(Iter iter, Iter endIter)
Prefetch next CaloDDE.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
CaloClusterContainer_v1 CaloClusterContainer
Define the latest version of the calorimeter cluster container.
static bool isBad(const CaloCell *pCell, bool treatL1PredictedCellsAsGood)