ATLAS Offline Software
Loading...
Searching...
No Matches
CaloTopoClusterSplitter.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5//-----------------------------------------------------------------------
6// File and Version Information:
7// $Id: CaloTopoClusterSplitter.cxx,v 1.25 2009-04-18 02:56:18 ssnyder Exp $
8//
9// Description: see CaloTopoClusterSplitter.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#include "CaloProtoCluster.h"
24#include "CaloTopoTmpHashCell.h"
28#include "CaloEvent/CaloCell.h"
32#include "CxxUtils/prefetch.h"
33#include "CLHEP/Units/SystemOfUnits.h"
34#include <vector>
35#include <algorithm>
36#include <iterator>
37#include <sstream>
38#include <memory>
39
40
41using HepGeom::Vector3D;
42using CLHEP::MeV;
43using CLHEP::cm;
44
45//###############################################################################
46
48 const std::string& name,
49 const IInterface* parent)
50
51 : AthAlgTool(type, name, parent),
52 m_calo_id(nullptr),
53 m_neighborOption("super3D"),
54 m_nOption(LArNeighbours::super3D),
56 m_nCells(4),
57 m_minEnergy(500*MeV),
58 m_shareBorderCells(false),
60 m_minSampling (0),
61 m_maxSampling (0),
65 m_absOpt (false)
66{
67 declareInterface<CaloClusterCollectionProcessor> (this);
68 // Neighbor Option
69 declareProperty("NeighborOption",m_neighborOption);
70 // Restrict HEC IW and FCal Neighbors
71 declareProperty("RestrictHECIWandFCalNeighbors",m_restrictHECIWandFCalNeighbors);
72 // minimal number of cells around a local max
73 declareProperty("NumberOfCellsCut",m_nCells);
74 // minimal energy for a local max
75 declareProperty("EnergyCut",m_minEnergy);
76 // Name(s) of Calorimeter Samplings to consider for local maxima
77 declareProperty("SamplingNames",m_samplingNames);
78 // Name(s) of secondary Calorimeter Samplings to consider for local maxima
79 // if no maximum in a primary sampling is overlapping
80 declareProperty("SecondarySamplingNames",m_secondarySamplingNames);
81 // Whether or not to share cells at the boundary between two clusters
82 declareProperty("ShareBorderCells",m_shareBorderCells);
83 // Typical em shower distance for which the energy density should drop to 1/e
84 declareProperty("EMShowerScale",m_emShowerScale);
85
86 // Treat bad cells with dead OTX if predicted from L1 as good
87 declareProperty("TreatL1PredictedCellsAsGood",m_treatL1PredictedCellsAsGood);
88 // Use weighting of neg. clusters option?
89 declareProperty("WeightingOfNegClusters",m_absOpt);
90}
91
92//###############################################################################
93
95{
96 msg(MSG::INFO) << "Initializing " << name() << endmsg;
97 msg(MSG::INFO) << "Treat L1 Predicted Bad Cells as Good set to" << ((m_treatL1PredictedCellsAsGood) ? "true" : "false") << endmsg;
98
99 ATH_CHECK( detStore()->retrieve (m_calo_id, "CaloCell_ID") );
100
101 //--- set Neighbor Option
102
103 if ( m_neighborOption == "all2D" )
105 else if ( m_neighborOption == "all3D" )
107 else if ( m_neighborOption == "super3D" )
109 else {
110 msg(MSG::ERROR) <<"Invalid Neighbor Option "
111 << m_neighborOption << ", exiting ..." << endmsg;
112 return StatusCode::FAILURE;
113 }
114
115 msg(MSG::INFO) << "Neighbor Option "
116 << m_neighborOption << " is selected!" << endmsg;
117
118 //--- check sampling names to use
119 std::vector<std::string>::iterator samplingIter = m_samplingNames.begin();
120 std::vector<std::string>::iterator samplingIterEnd = m_samplingNames.end();
121 for(; samplingIter!=samplingIterEnd; ++samplingIter) {
122 if ( *samplingIter == "PreSamplerB" )
123 m_validSamplings.insert(CaloCell_ID::PreSamplerB);
124 else if ( *samplingIter == "EMB1" )
125 m_validSamplings.insert(CaloCell_ID::EMB1);
126 else if ( *samplingIter == "EMB2" )
127 m_validSamplings.insert(CaloCell_ID::EMB2);
128 else if ( *samplingIter == "EMB3" )
129 m_validSamplings.insert(CaloCell_ID::EMB3);
130 else if ( *samplingIter == "PreSamplerE" )
131 m_validSamplings.insert(CaloCell_ID::PreSamplerE);
132 else if ( *samplingIter == "EME1" )
133 m_validSamplings.insert(CaloCell_ID::EME1);
134 else if ( *samplingIter == "EME2" )
135 m_validSamplings.insert(CaloCell_ID::EME2);
136 else if ( *samplingIter == "EME3" )
137 m_validSamplings.insert(CaloCell_ID::EME3);
138 else if ( *samplingIter == "HEC0" )
139 m_validSamplings.insert(CaloCell_ID::HEC0);
140 else if ( *samplingIter == "HEC1" )
141 m_validSamplings.insert(CaloCell_ID::HEC1);
142 else if ( *samplingIter == "HEC2" )
143 m_validSamplings.insert(CaloCell_ID::HEC2);
144 else if ( *samplingIter == "HEC3" )
145 m_validSamplings.insert(CaloCell_ID::HEC3);
146 else if ( *samplingIter == "TileBar0" )
147 m_validSamplings.insert(CaloCell_ID::TileBar0);
148 else if ( *samplingIter == "TileBar1" )
149 m_validSamplings.insert(CaloCell_ID::TileBar1);
150 else if ( *samplingIter == "TileBar2" )
151 m_validSamplings.insert(CaloCell_ID::TileBar2);
152 else if ( *samplingIter == "TileGap1" )
153 m_validSamplings.insert(CaloCell_ID::TileGap1);
154 else if ( *samplingIter == "TileGap2" )
155 m_validSamplings.insert(CaloCell_ID::TileGap2);
156 else if ( *samplingIter == "TileGap3" )
157 m_validSamplings.insert(CaloCell_ID::TileGap3);
158 else if ( *samplingIter == "TileExt0" )
159 m_validSamplings.insert(CaloCell_ID::TileExt0);
160 else if ( *samplingIter == "TileExt1" )
161 m_validSamplings.insert(CaloCell_ID::TileExt1);
162 else if ( *samplingIter == "TileExt2" )
163 m_validSamplings.insert(CaloCell_ID::TileExt2);
164 else if ( *samplingIter == "FCAL0" )
165 m_validSamplings.insert(CaloCell_ID::FCAL0);
166 else if ( *samplingIter == "FCAL1" )
167 m_validSamplings.insert(CaloCell_ID::FCAL1);
168 else if ( *samplingIter == "FCAL2" )
169 m_validSamplings.insert(CaloCell_ID::FCAL2);
170 else
171 msg(MSG::ERROR) <<"Calorimeter sampling" << *samplingIter
172 << " is not a valid Calorimeter sampling name and will be ignored! "
173 << "Valid names are: "
174 << "PreSamplerB, EMB1, EMB2, EMB3, "
175 << "PreSamplerE, EME1, EME2, EME3, "
176 << "HEC0, HEC1, HEC2, HEC3, "
177 << "TileBar0, TileBar1, TileBar2, "
178 << "TileGap1, TileGap2, TileGap3, "
179 << "TileExt0, TileExt1, TileExt2, "
180 << "FCAL0, FCAL1, FCAL2." << endmsg;
181 }
182
183 msg(MSG::INFO) << "Samplings to consider for local maxima:";
184 samplingIter = m_samplingNames.begin();
185 for(; samplingIter!=samplingIterEnd; ++samplingIter)
186 msg() << " " << *samplingIter;
187 msg() << endmsg;
188
191 std::set<int>::const_iterator vSamplingIter = m_validSamplings.begin();
192 std::set<int>::const_iterator vSamplingIterEnd = m_validSamplings.end();
193 for(; vSamplingIter!=vSamplingIterEnd; ++vSamplingIter) {
194 if ( (*vSamplingIter) > m_maxSampling )
195 m_maxSampling = (*vSamplingIter);
196 if ( (*vSamplingIter) < m_minSampling )
197 m_minSampling = (*vSamplingIter);
198 }
199
201
202 for(vSamplingIter = m_validSamplings.begin(); vSamplingIter!=vSamplingIterEnd; ++vSamplingIter) {
203 m_useSampling[(*vSamplingIter)-m_minSampling] = true;
204 }
205
206 //--- check sampling names to use
207 samplingIter = m_secondarySamplingNames.begin();
208 samplingIterEnd = m_secondarySamplingNames.end();
209 for(; samplingIter!=samplingIterEnd; ++samplingIter) {
210 if ( *samplingIter == "PreSamplerB" )
211 m_validSecondarySamplings.insert(CaloCell_ID::PreSamplerB);
212 else if ( *samplingIter == "EMB1" )
213 m_validSecondarySamplings.insert(CaloCell_ID::EMB1);
214 else if ( *samplingIter == "EMB2" )
215 m_validSecondarySamplings.insert(CaloCell_ID::EMB2);
216 else if ( *samplingIter == "EMB3" )
217 m_validSecondarySamplings.insert(CaloCell_ID::EMB3);
218 else if ( *samplingIter == "PreSamplerE" )
219 m_validSecondarySamplings.insert(CaloCell_ID::PreSamplerE);
220 else if ( *samplingIter == "EME1" )
221 m_validSecondarySamplings.insert(CaloCell_ID::EME1);
222 else if ( *samplingIter == "EME2" )
223 m_validSecondarySamplings.insert(CaloCell_ID::EME2);
224 else if ( *samplingIter == "EME3" )
225 m_validSecondarySamplings.insert(CaloCell_ID::EME3);
226 else if ( *samplingIter == "HEC0" )
227 m_validSecondarySamplings.insert(CaloCell_ID::HEC0);
228 else if ( *samplingIter == "HEC1" )
229 m_validSecondarySamplings.insert(CaloCell_ID::HEC1);
230 else if ( *samplingIter == "HEC2" )
231 m_validSecondarySamplings.insert(CaloCell_ID::HEC2);
232 else if ( *samplingIter == "HEC3" )
233 m_validSecondarySamplings.insert(CaloCell_ID::HEC3);
234 else if ( *samplingIter == "TileBar0" )
235 m_validSecondarySamplings.insert(CaloCell_ID::TileBar0);
236 else if ( *samplingIter == "TileBar1" )
237 m_validSecondarySamplings.insert(CaloCell_ID::TileBar1);
238 else if ( *samplingIter == "TileBar2" )
239 m_validSecondarySamplings.insert(CaloCell_ID::TileBar2);
240 else if ( *samplingIter == "TileGap1" )
241 m_validSecondarySamplings.insert(CaloCell_ID::TileGap1);
242 else if ( *samplingIter == "TileGap2" )
243 m_validSecondarySamplings.insert(CaloCell_ID::TileGap2);
244 else if ( *samplingIter == "TileGap3" )
245 m_validSecondarySamplings.insert(CaloCell_ID::TileGap3);
246 else if ( *samplingIter == "TileExt0" )
247 m_validSecondarySamplings.insert(CaloCell_ID::TileExt0);
248 else if ( *samplingIter == "TileExt1" )
249 m_validSecondarySamplings.insert(CaloCell_ID::TileExt1);
250 else if ( *samplingIter == "TileExt2" )
251 m_validSecondarySamplings.insert(CaloCell_ID::TileExt2);
252 else if ( *samplingIter == "FCAL0" )
253 m_validSecondarySamplings.insert(CaloCell_ID::FCAL0);
254 else if ( *samplingIter == "FCAL1" )
255 m_validSecondarySamplings.insert(CaloCell_ID::FCAL1);
256 else if ( *samplingIter == "FCAL2" )
257 m_validSecondarySamplings.insert(CaloCell_ID::FCAL2);
258 else
259 msg(MSG::ERROR) <<"Calorimeter sampling" << *samplingIter
260 << " is not a valid Calorimeter sampling name and will be ignored! "
261 << "Valid names are: "
262 << "PreSamplerB, EMB1, EMB2, EMB3, "
263 << "PreSamplerE, EME1, EME2, EME3, "
264 << "HEC0, HEC1, HEC2, HEC3, "
265 << "TileBar0, TileBar1, TileBar2, "
266 << "TileGap1, TileGap2, TileGap3, "
267 << "TileExt0, TileExt1, TileExt2, "
268 << "FCAL0, FCAL1, FCAL2." << endmsg;
269 }
270
271 msg(MSG::INFO) << "Secondary samplings to consider for local maxima:";
272 samplingIter = m_secondarySamplingNames.begin();
273 for(; samplingIter!=samplingIterEnd; ++samplingIter)
274 msg() << " " << *samplingIter;
275 msg() << endmsg;
276
279 vSamplingIter = m_validSecondarySamplings.begin();
280 vSamplingIterEnd = m_validSecondarySamplings.end();
281 for(; vSamplingIter!=vSamplingIterEnd; ++vSamplingIter) {
282 if ( (*vSamplingIter) > m_maxSecondarySampling )
283 m_maxSecondarySampling = (*vSamplingIter);
284 if ( (*vSamplingIter) < m_minSecondarySampling )
285 m_minSecondarySampling = (*vSamplingIter);
286 }
287
289
290 for(vSamplingIter = m_validSecondarySamplings.begin(); vSamplingIter!=vSamplingIterEnd; ++vSamplingIter) {
291 m_useSecondarySampling[(*vSamplingIter)-m_minSecondarySampling] = true;
292 }
293
294 m_hashMin = 999999;
295 m_hashMax = 0;
296 for(unsigned int iCalo=0;iCalo<CaloCell_ID::NSUBCALO; iCalo++) {
297 IdentifierHash thismin, thismax;
298 m_calo_id->calo_cell_hash_range (iCalo, thismin, thismax);
299 m_hashMin = std::min (m_hashMin, thismin);
300 m_hashMax = std::max (m_hashMax, thismax);
301 }
302
303 return StatusCode::SUCCESS;
304
305}
306
307//###############################################################################
308
309StatusCode CaloTopoClusterSplitter::execute(const EventContext& ctx,
310 xAOD::CaloClusterContainer* clusColl) const
311{
312 ATH_MSG_DEBUG("Executing " << name());
313
315 using HashCluster = CaloTopoSplitterHashCluster;
316
318 tmpcell_pool;
320 tmpclus_pool;
322
323 // create cell list for cells above seed cut (for seed growing algo)
324 std::vector<HashCell> mySeedCells;
325 mySeedCells.reserve (200);
326 // create initial cluster list (one cell per cluster)
327 std::vector<HashCluster *> myHashClusters;
328 myHashClusters.reserve (20000);
329 // create cell list in order to clean up in the end
330 std::vector<CaloTopoSplitterClusterCell *> allCellList;
331 allCellList.reserve (20000);
332 // create vector to hold all cells for a given subsystem (the IdentifierHash is
333 // used as index - therefore the vector has always maximal size)
334 std::vector<HashCell> cellVector (m_hashMax - m_hashMin);
335
336 //---- loop over the initial set of Clusters
337
338 std::vector<int> hasLocalMaxVector;
339 hasLocalMaxVector.resize(clusColl->size(),0);
340 int iClusterNumber = 0;
341 float eTotOrig(0.);
342 int nTotOrig(0);
343 xAOD::CaloClusterContainer::iterator clusCollIter = clusColl->begin();
344 xAOD::CaloClusterContainer::iterator clusCollIterEnd = clusColl->end();
345
346 // get cluster size and underlying cell container (assume it's identical for the whole collection)
348 const CaloCellContainer* myCellColl=nullptr;
349 if (clusCollIter != clusCollIterEnd) {
350 clusterSize = (*clusCollIter)->clusterSize();
351 ATH_MSG_DEBUG("cluster size = " <<clusterSize);
352 const CaloClusterCellLink* lnk=(*clusCollIter)->getCellLinks();
353 if (!lnk) {
354 msg(MSG::ERROR) << "Can't get valid links to CaloCells (CaloClusterCellLink)!" << endmsg;
355 return StatusCode::FAILURE;
356 }
357 myCellColl = lnk->getCellContainer();
358 }
359 else {
360 ATH_MSG_DEBUG("Got an empty input collection. Do notihing");
361 return StatusCode::SUCCESS;
362 }
363
364
365 for (; clusCollIter != clusCollIterEnd; ++clusCollIter, ++iClusterNumber ){
366 xAOD::CaloCluster* parentCluster = (*clusCollIter);
367 CaloClusterCellLink* cellLinks=parentCluster->getOwnCellLinks();
368 if (!cellLinks) {
369 msg(MSG::ERROR) << "Can't get valid links to CaloCells (CaloClusterCellLink)!" << endmsg;
370 return StatusCode::FAILURE;
371 }
372
373 eTotOrig+=parentCluster->e();
374 nTotOrig+=cellLinks->size();
375 // use the number of the parent cluster to identify
376 // cells from the same parent cluster
377 // only cells belonging to the same parent cluster are allowed
378 // to be merged into one split cluster
379
380 //---- Get the CaloCells from this cluster
381 xAOD::CaloCluster::cell_iterator cellIter = parentCluster->cell_begin();
382 xAOD::CaloCluster::cell_iterator cellIterEnd = parentCluster->cell_end();
383
384 for(; cellIter != cellIterEnd; cellIter++ ){
385 CxxUtils::prefetchNext (cellIter, cellIterEnd); //FIXME Does this work with the new cell-iterator?
386
387 const CaloCell* pCell = (*cellIter);
388 Identifier myId = pCell->ID();
389
390 // store energy here to search for local maxima
391 int caloSample = m_calo_id->calo_sample(myId);
392 float signedRatio = 0;
393 bool is_secondary = false; //reintroduced is_secondary for negative cluster option
394 // in case the cell is not a bad cell
395 // check if the current cell belongs to a sampling
396 // that should be considered for local maxima.
397 // in case the cell does not belong to such a sampling its signedRatio
398 // is set to 0. The cell is still counted as neighbor cell but
399 // will not make (or prevent) a local maximum
401 if ( (m_absOpt || pCell->e() > 0)
402 && caloSample >= m_minSampling
403 && caloSample <= m_maxSampling
404 && m_useSampling[caloSample-m_minSampling] )
405 signedRatio = pCell->e();
406 // check also if the current cell belongs to a sampling
407 // that should be considered for secondary local maxima.
408 // in case the cell does belong to such a sampling its signedRatio
409 // will be set to -e(). The is still counted as neighbor cell but
410 // will not make (or prevent) a local maximum
411 else if ( (m_absOpt || pCell->e() > 0)
412 && caloSample >= m_minSecondarySampling
413 && caloSample <= m_maxSecondarySampling
415 signedRatio = -pCell->e();
416 is_secondary = true;
417 }
418 }
419
420
421 IdentifierHash hashid = m_calo_id->calo_cell_hash(myId);
422 CaloCell_ID::SUBCALO subdet = (CaloCell_ID::SUBCALO)m_calo_id->sub_calo (hashid);
423 // use iterator and not cell pointer in lookup of cell container for speed
424 //int myIndex = myCellColl->findIndex(hashid);
425 size_t myIndex=cellIter.index();
426 CaloTopoSplitterClusterCell *tmpClusterCell =
427 new (tmpcell_pool.allocate())
428 CaloTopoSplitterClusterCell(hashid, subdet,
429 cellIter,myIndex,
430 signedRatio,parentCluster,
431 iClusterNumber,is_secondary);
432 // some debug printout - can also be used to construct neighbor
433 // tables offline ...
434 if ( ctx.evt() == 0 && msgLvl(MSG::DEBUG)) {
435 msg(MSG::INFO) << " [ExtId|Id|SubDet|HashId|eta|phi|iParent|E]: "
436 << "[" << m_calo_id->show_to_string(myId,nullptr,'/')
437 << "|" << myId.getString()
438 << "|" << subdet
439 << "|" << (unsigned int)hashid
440 << "|" << pCell->eta()
441 << "|" << pCell->phi()
442 << "|" << iClusterNumber
443 << "|" << signedRatio
444 << "]" << endmsg;
445 }
446 HashCell hashCell(tmpClusterCell);
447 HashCluster *tmpCluster =
448 new (tmpclus_pool.allocate()) HashCluster (tmplist_pool);
449 tmpClusterCell->setCaloTopoTmpHashCluster(tmpCluster);
450 tmpCluster->add(hashCell);
451 myHashClusters.push_back(tmpCluster);
452 allCellList.push_back(tmpClusterCell);
453 cellVector[(unsigned int)hashid - m_hashMin] = hashCell;
454 }
455 }
456
457 // Vectors to hold the results of get_neighbors().
458 // Create them here, at the top level, so we don't need
459 // to reallocate the vectors each trip through the inner loops.
460 std::vector<IdentifierHash> theNeighbors;
461 theNeighbors.reserve(22);
462 std::vector<IdentifierHash> theSuperNeighbors;
463 theSuperNeighbors.reserve(22);
464 std::vector<IdentifierHash> theNNeighbors;
465 theNNeighbors.reserve(22);
466 std::vector<IdentifierHash> theCurrentNeighbors;
467 theCurrentNeighbors.reserve(88);
468 std::vector<IdentifierHash> theNextNeighbors;
469 theNextNeighbors.reserve(88);
470
471 // look for local maxima
472 std::vector<CaloTopoSplitterClusterCell*>::iterator allCellIter=allCellList.begin();
473 std::vector<CaloTopoSplitterClusterCell*>::iterator allCellIterEnd=allCellList.end();
474 for(;allCellIter != allCellIterEnd;++allCellIter) {
475 CaloTopoSplitterClusterCell* pClusCell = (*allCellIter);
476 // only check cells for which we don't know if a neighbor with larger
477 // energy was found before
478 if (! pClusCell->getUsed() ) {
479 float myEnergy = pClusCell->getSignedRatio();
480 if(m_absOpt) myEnergy=std::abs(myEnergy);
481 if ( myEnergy >= m_minEnergy && !pClusCell->getSecondary() ) {
482 int nCells=0;
483 bool isLocalMax = true;
484 size_t iParent = pClusCell->getParentClusterIndex();
485 IdentifierHash hashid = pClusCell->getID();
486 theNeighbors.clear();
487 m_calo_id->get_neighbours(hashid,m_nOption,theNeighbors);
488 for (unsigned int iN=0;iN<theNeighbors.size();iN++) {
489 IdentifierHash nId = theNeighbors[iN];
490 HashCell neighborCell = cellVector[(unsigned int)nId - m_hashMin];
491 CaloTopoSplitterClusterCell *pNeighCell = neighborCell.getCaloTopoTmpClusterCell();
492 if ( pNeighCell && pNeighCell->getParentClusterIndex() == iParent) {
493 nCells++;
494 if ( ((myEnergy > pNeighCell->getSignedRatio() ) && !m_absOpt) ||
495 (m_absOpt && myEnergy > std::abs(pNeighCell->getSignedRatio() ) ) ||
496 pNeighCell->getSecondary() ) {
497 // in case the neighbor cell is a 2nd local max candidate
498 // it has negative energy and we set it to used only if also
499 // its abs value is smaller than myEnergy
500 if (std::abs(pNeighCell->getSignedRatio()) < myEnergy )
501 pNeighCell->setUsed();
502 }
503 else {
504 isLocalMax=false;
505 }
506 }
507 }
508 if ( nCells < m_nCells )
509 isLocalMax = false;
510 if ( isLocalMax ) {
511 mySeedCells.push_back(cellVector[(unsigned int)hashid - m_hashMin]);
512 hasLocalMaxVector[iParent]++;
513 }
514 }
515 }
516 }
517
518 std::vector<CaloTopoSplitterClusterCell *> myPotentialSecondarySeeds;
519 //These will be used for ordering the secondary seeds
520 //in a way that we can ensure agrees with the GPU version,
521 //as without it we depend on the ordering of the cells
522 //within the clusters (and the order of the clusters themselves)
523 //to decide the elimination between overlapping secondary clusters.
524 myPotentialSecondarySeeds.reserve(100);
525
526 // look for secondary local maxima
527 if ( !m_validSecondarySamplings.empty() ) {
528 allCellIter=allCellList.begin();
529 for(;allCellIter != allCellIterEnd;++allCellIter) {
530 CaloTopoSplitterClusterCell* pClusCell = (*allCellIter);
531 // only check cells for which we don't know if a neighbor with larger
532 // energy was found before
533 if (! pClusCell->getUsed() && pClusCell->getSecondary()) {
534 float myEnergy = pClusCell->getSignedRatio();
535 if(m_absOpt) myEnergy=std::abs(myEnergy);
536 if ( (!m_absOpt && myEnergy <= -m_minEnergy) || (m_absOpt && myEnergy >= m_minEnergy) ) {
537 int nCells=0;
538 bool isLocalMax = true;
539 size_t iParent = pClusCell->getParentClusterIndex();
540 IdentifierHash hashid = pClusCell->getID();
541 //CaloCell_ID::SUBCALO mySubDet = pClusCell->getSubDet();
542 theNeighbors.clear();
543 m_calo_id->get_neighbours(hashid,m_nOption,theNeighbors);
544 for (unsigned int iN=0;iN<theNeighbors.size();iN++) {
545 IdentifierHash nId = theNeighbors[iN];
546 HashCell neighborCell = cellVector[(unsigned int)nId - m_hashMin];
547 CaloTopoSplitterClusterCell *pNeighCell = neighborCell.getCaloTopoTmpClusterCell();
548 if ( pNeighCell && pNeighCell->getParentClusterIndex() == iParent) {
549 nCells++;
550 if ( std::abs(myEnergy) > std::abs(pNeighCell->getSignedRatio()) ) {
551 pNeighCell->setUsed();
552 }
553 else {
554 isLocalMax=false;
555 }
556 }
557 }
558 if ( nCells < m_nCells )
559 isLocalMax = false;
560
561 if (m_useGPUCriteria) {
562 if (isLocalMax) {
563 myPotentialSecondarySeeds.push_back(pClusCell);
564 }
565 continue;
566 }
567
568 // check the neighbors in all previous and all next samplings
569 // for overlapping cells in the primary local maximum list
570 // in case such cells exist do not consider this cell as
571 // local maximum
572 if ( isLocalMax ) {
573 // first check previous samplings
575 // start with current cell
576 theCurrentNeighbors.clear();
577 theCurrentNeighbors.push_back(hashid);
578 while ( isLocalMax && !theCurrentNeighbors.empty() ) {
579 // loop over the current neighbors and add all found cells in
580 // previous samplings to the next neighbor list
581 theNextNeighbors.clear();
582 for (unsigned int iN=0;iN<theCurrentNeighbors.size()
583 && isLocalMax;iN++) {
584 theNeighbors.clear();
585 theSuperNeighbors.clear();
587 m_calo_id->get_neighbours(theCurrentNeighbors[iN],LArNeighbours::prevInSamp,theNeighbors);
589 m_calo_id->get_neighbours(theCurrentNeighbors[iN],LArNeighbours::prevSuperCalo,theSuperNeighbors);
590 theNeighbors.insert(theNeighbors.end(),theSuperNeighbors.begin(),theSuperNeighbors.end());
591 for(unsigned int iNN=0;iNN<theNeighbors.size() && isLocalMax;iNN++) {
592 IdentifierHash nId = theNeighbors[iNN];
593 std::vector<HashCell>::iterator hashCellIter;
594 std::vector<HashCell>::iterator hashCellIterEnd;
595
596 hashCellIter= mySeedCells.begin();
597 hashCellIterEnd=mySeedCells.end();
598
599 // loop over all seed cells and check if cells match
600 for(;hashCellIter!=hashCellIterEnd
601 && isLocalMax;++hashCellIter) {
602 if ( cellVector[(unsigned int)nId - m_hashMin]
603 == (*hashCellIter) )
604 {
605 isLocalMax = false;
606 }
607 }
608 if ( isLocalMax ) {
609 // no matching seed cell was found for this
610 // neighbor - so add it to the next list in case it's
611 // not yet included
612 bool doInclude(true);
613 for(unsigned int iNNN=0;iNNN<theNextNeighbors.size();iNNN++) {
614 if ( theNextNeighbors[iNNN] == theNeighbors[iNN] ) {
615 doInclude = false;
616 break;
617 }
618 }
619 if ( doInclude )
620 theNextNeighbors.push_back(theNeighbors[iNN]);
621 }
622 }
623 }
624 theCurrentNeighbors.swap (theNextNeighbors);
625 }
626 }
627 }
628 if ( isLocalMax ) {
629 // now check next samplings
631 std::vector<IdentifierHash> theCurrentNeighbors;
632 std::vector<IdentifierHash> theNextNeighbors;
633 // start with current cell
634 theCurrentNeighbors.push_back(hashid);
635 while ( isLocalMax && !theCurrentNeighbors.empty() ) {
636 // loop over the current neighbors and add all found cells in
637 // next samplings to the next neighbor list
638 theNextNeighbors.clear();
639 for (unsigned int iN=0;iN<theCurrentNeighbors.size()
640 && isLocalMax;iN++) {
641 theNeighbors.clear();
642 theSuperNeighbors.clear();
644 m_calo_id->get_neighbours(theCurrentNeighbors[iN],LArNeighbours::nextInSamp,theNeighbors);
646 m_calo_id->get_neighbours(theCurrentNeighbors[iN],LArNeighbours::nextSuperCalo,theSuperNeighbors);
647 theNeighbors.insert(theNeighbors.end(),theSuperNeighbors.begin(),theSuperNeighbors.end());
648 for(unsigned int iNN=0;iNN<theNeighbors.size() && isLocalMax;iNN++) {
649 IdentifierHash nId = theNeighbors[iNN];
650 std::vector<HashCell>::iterator hashCellIter;
651 std::vector<HashCell>::iterator hashCellIterEnd;
652
653 hashCellIter= mySeedCells.begin();
654 hashCellIterEnd=mySeedCells.end();
655
656 // loop over all seed cells and check if cells match
657 for(;hashCellIter!=hashCellIterEnd
658 && isLocalMax;++hashCellIter) {
659 if ( cellVector[(unsigned int)nId - m_hashMin]
660 == (*hashCellIter) )
661 {
662 isLocalMax = false;
663 }
664 }
665 if ( isLocalMax ) {
666 // no matching seed cell was found for this
667 // neighbor - so add it to the next list in case it's
668 // not yet included
669 bool doInclude(true);
670 for(unsigned int iNNN=0;iNNN<theNextNeighbors.size();iNNN++) {
671 if ( theNextNeighbors[iNNN] == theNeighbors[iNN] ) {
672 doInclude = false;
673 break;
674 }
675 }
676 if ( doInclude )
677 theNextNeighbors.push_back(theNeighbors[iNN]);
678 }
679 }
680 }
681 theCurrentNeighbors.swap (theNextNeighbors);
682 }
683 }
684 }
685 // did the cell survive until here make it a local maximum
686 if ( isLocalMax ) {
687 mySeedCells.push_back(cellVector[(unsigned int)hashid - m_hashMin]);
688 hasLocalMaxVector[iParent]++;
689 }
690 }
691 }
692 }
693 }
694 allCellIter=allCellList.begin();
695 for(;allCellIter != allCellIterEnd;++allCellIter) {
696 (*allCellIter)->setUnused();
697 const xAOD::CaloCluster::cell_iterator itrCell = (*allCellIter)->getCellIterator();
698 (*allCellIter)->setSignedRatio(itrCell->e());
699 }
700
701
702 //Declaring this here because it is used for secondary maxima elimination
704
706
707 std::sort(myPotentialSecondarySeeds.begin(), myPotentialSecondarySeeds.end(), [&](const auto & a, const auto & b) {
708 return compareEWithIndex(cellVector[(unsigned int)a->getID() - m_hashMin], cellVector[(unsigned int)b->getID() - m_hashMin]);
709 });
710
711 //This way, we always exclude the clusters based on overlap with more energetic ones.
712 //If the more energetic ones get excluded, then the cluster would end up being excluded too
713 //(since we're always checking with the same neighbour options).
714
715 std::vector<bool> secondarySeedExclude(myPotentialSecondarySeeds.size(), false);
716
717 for (unsigned int i = 0; i < myPotentialSecondarySeeds.size(); ++i) {
718 CaloTopoSplitterClusterCell * pClusCell = myPotentialSecondarySeeds[i];
719 bool isLocalMax = true;
720 IdentifierHash hashid = pClusCell->getID();
721
722 //Avoid repeated code...
723
724 auto check_with_neighbour_options = [&, this](const LArNeighbours::neighbourOption opt_1,
725 const LArNeighbours::neighbourOption opt_2) {
726 if (this->m_nOption & (opt_1 | opt_2)) {
727 theCurrentNeighbors.clear();
728 theCurrentNeighbors.push_back(hashid);
729
730 while ( isLocalMax && !theCurrentNeighbors.empty() ) {
731
732 theNextNeighbors.clear();
733 for (const IdentifierHash & currentNeighbor : theCurrentNeighbors) {
734
735 theNeighbors.clear();
736 theSuperNeighbors.clear();
737
738 if ( this->m_nOption & opt_1 ) {
739 this->m_calo_id->get_neighbours(currentNeighbor, opt_1, theNeighbors);
740 }
741
742 if ( this->m_nOption & opt_2 ) {
743 this->m_calo_id->get_neighbours(currentNeighbor, opt_2, theSuperNeighbors);
744 }
745
746 theNeighbors.insert(theNeighbors.end(), theSuperNeighbors.begin(), theSuperNeighbors.end());
747
748 for (const IdentifierHash nId : theNeighbors) {
749
750 for (const auto & seedCell: mySeedCells) {
751 if (cellVector[(unsigned int)nId - m_hashMin] == seedCell) {
752 return false;
753 }
754 }
755
756 for (unsigned int j = 0; j < i; ++j) {
757 if (cellVector[(unsigned int)nId - m_hashMin] == myPotentialSecondarySeeds[j]) {
758 return false;
759 }
760 }
761
762 bool doInclude(true);
763
764 for (const IdentifierHash nextNId : theNextNeighbors) {
765 if (nextNId == nId) {
766 doInclude = false;
767 break;
768 }
769 }
770
771 if ( doInclude ) {
772 theNextNeighbors.push_back(nId);
773 }
774 }
775 }
776
777 theCurrentNeighbors.swap (theNextNeighbors);
778 }
779 }
780
781 return true;
782 };
783
784 if ( ! ( check_with_neighbour_options(LArNeighbours::prevInSamp, LArNeighbours::prevSuperCalo) &&
785 check_with_neighbour_options(LArNeighbours::nextInSamp, LArNeighbours::nextSuperCalo) ) ) {
786 secondarySeedExclude[i] = true;
787 }
788 }
789
790 for (unsigned int i = 0; i < myPotentialSecondarySeeds.size(); ++i) {
791 CaloTopoSplitterClusterCell * pClusCell = myPotentialSecondarySeeds[i];
792 IdentifierHash hashid = pClusCell->getID();
793 size_t iParent = pClusCell->getParentClusterIndex();
794 if ( !secondarySeedExclude[i] ) {
795 mySeedCells.push_back(cellVector[(unsigned int)hashid - m_hashMin]);
796 hasLocalMaxVector[iParent]++;
797 }
798 }
799 }
800
801 // create shared cell list for border cells between two split clusters
802 std::vector<HashCell> sharedCellList;
803 std::vector<HashCell> nextSharedCellList;
804
805 std::vector<HashCell>::iterator hashCellIter;
806 std::vector<HashCell>::iterator hashCellIterEnd;
807
808 hashCellIter= mySeedCells.begin();
809 hashCellIterEnd=mySeedCells.end();
810
811 // loop over all seed cells and set them Used
812 for(;hashCellIter!=hashCellIterEnd;++hashCellIter) {
813 hashCellIter->getCaloTopoTmpClusterCell()->setUsed();
814 HashCluster *myCluster = hashCellIter->getCaloTopoTmpClusterCell()->getCaloTopoTmpHashCluster();
815 myCluster->setContainsLocalMax();
816 }
817
818 // sort initial seed cells to start with the cell of largest E
819 // this makes the resulting clusters independent of the initial
820 // ordering of the cells
821
823
824 auto compareE = [&, this](auto && ... ps) {
825 if (this->m_useGPUCriteria) {
826 return compareEWithIndex(std::forward<decltype(ps)>(ps)...);
827 }
828 else {
829 return compareEOriginal(std::forward<decltype(ps)>(ps)...);
830 }
831 };
832
833 std::sort(mySeedCells.begin(),mySeedCells.end(),compareE);
834
835 if ( msgLvl(MSG::DEBUG)) {
836 hashCellIter= mySeedCells.begin();
837 hashCellIterEnd=mySeedCells.end();
838
839 // loop over all current neighbor cells (for Seed Growing Algo)
840 for(;hashCellIter!=hashCellIterEnd;++hashCellIter) {
841 msg(MSG::DEBUG) << " SeedCell ["
842 << hashCellIter->getCaloTopoTmpClusterCell()->getSubDet()
843 << "|"
844 << (unsigned int)hashCellIter->getCaloTopoTmpClusterCell()->getID()
845 << "] has E = "
846 << hashCellIter->getCaloTopoTmpClusterCell()->getSignedRatio()
847 << endmsg;
848 }
849 }
850
851 std::vector<HashCell> myNextCells;
852 myNextCells.reserve (4096);
853 while ( !mySeedCells.empty() ) {
854 // create cell list for next neighbor cells to consider
855 myNextCells.clear();
856 hashCellIter= mySeedCells.begin();
857 hashCellIterEnd=mySeedCells.end();
858
859 // loop over all current neighbor cells (for Seed Growing Algo)
860 for(;hashCellIter!=hashCellIterEnd;++hashCellIter) {
861 CaloTopoSplitterClusterCell* pClusCell = hashCellIter->getCaloTopoTmpClusterCell();
862 IdentifierHash hashid = pClusCell->getID();
863 HashCluster *myCluster = pClusCell->getCaloTopoTmpHashCluster();
864 size_t iParent = pClusCell->getParentClusterIndex();
865 CaloCell_ID::SUBCALO mySubDet = pClusCell->getSubDet();
866 // in case we use all3d or super3D and the current cell is in the
867 // HEC IW or FCal2 & 3 and we want to restrict their neighbors,
868 // use only next in sampling neighbors
869 theNeighbors.clear();
872 && ( ( mySubDet == CaloCell_ID::LARHEC
873 && m_calo_id->region(m_calo_id->cell_id(hashid)) == 1 )
874 || ( mySubDet == CaloCell_ID::LARFCAL
875 && m_calo_id->sampling(m_calo_id->cell_id(hashid)) > 1 ) ) ) {
876 m_calo_id->get_neighbours(hashid,LArNeighbours::nextInSamp,theNeighbors);
877 }
878 else {
879 m_calo_id->get_neighbours(hashid,m_nOption,theNeighbors);
880 }
881 // loop over all neighbors of that cell (Seed Growing Algo)
882 if ( ctx.evt() == 0 && msgLvl(MSG::DEBUG)) {
883 Identifier myId;
884 myId = m_calo_id->cell_id(hashid);
885 msg(MSG::DEBUG) << " Cell [" << mySubDet << "|"
886 << (unsigned int)hashid << "|"
887 << m_calo_id->show_to_string(myId,nullptr,'/')
888 << "] has " << theNeighbors.size() << " neighbors:"
889 << endmsg;
890 }
891 int otherSubDet;
892 for (unsigned int iN=0;iN<theNeighbors.size();iN++) {
893 otherSubDet = m_calo_id->sub_calo(theNeighbors[iN]);
894 IdentifierHash nId = theNeighbors[iN];
895 if ( ctx.evt() == 0 && msgLvl(MSG::DEBUG)) {
896 Identifier myId;
897 myId = m_calo_id->cell_id(nId);
898 msg(MSG::DEBUG) << " NeighborCell [" << otherSubDet << "|"
899 << (unsigned int) nId << "|"
900 << m_calo_id->show_to_string(myId,nullptr,'/') << "]" << endmsg;
901 theNNeighbors.clear();
902 m_calo_id->get_neighbours(nId,m_nOption,theNNeighbors);
903 bool foundId (false);
904 int nOtherSubDet;
905 for (unsigned int iNN=0;iNN<theNNeighbors.size();iNN++) {
906 nOtherSubDet = m_calo_id->sub_calo(theNNeighbors[iNN]);
907 if (nOtherSubDet == ((int)(mySubDet)) &&
908 theNNeighbors[iNN] == hashid) {
909 foundId = true;
910 break;
911 }
912 }
913 if ( ! foundId ) {
914 myId = m_calo_id->cell_id(hashid);
915 msg(MSG::ERROR) <<" Cell [" << mySubDet << "|"
916 << (unsigned int)hashid << "|"
917 << m_calo_id->show_to_string(myId,nullptr,'/')
918 << "] has bad neighbor cell[";
919 myId = m_calo_id->cell_id(nId);
920
921 msg() << otherSubDet << "|" << nId << "|"
922 << m_calo_id->show_to_string(myId,nullptr,'/')
923 << "]" << endmsg;
924 }
925 }//end if printout
926 HashCell neighborCell = cellVector[(unsigned int)nId - m_hashMin];
927 CaloTopoSplitterClusterCell *pNCell = neighborCell.getCaloTopoTmpClusterCell();
928 if ( pNCell && pNCell->getParentClusterIndex() == iParent && !pNCell->getShared() ) {
929 // checking the neighbors
930 HashCluster *otherCluster = pNCell->getCaloTopoTmpHashCluster();
931 if ( !pNCell->getUsed() ) {
932 pNCell->setUsed();
933 myNextCells.push_back(neighborCell);
934 }
935 else {
936 // in case the cell is used already it might have been
937 // included in the same iteration from another cluster. In
938 // this case it is a shared cell and needs to be removed
939 // from the myNextCells list and from the other cluster
940 if ( m_shareBorderCells && myCluster != otherCluster ) {
941 std::vector<HashCell>::iterator nextCellIter = myNextCells.begin();
942 bool isRemoved(false);
943 // try to remove the neighborCell - if it belongs to the
944 // myNextCell list it is a shared cell, added to the
945 // list of shared cells and removed from the cluster it
946 // first was added to
947 while ( !isRemoved && nextCellIter != myNextCells.end() ) {
948 if ( (*nextCellIter) == neighborCell ) {
949 nextCellIter = myNextCells.erase(nextCellIter);
950 isRemoved=true;
951 }
952 else
953 ++nextCellIter;
954 }
955 if ( isRemoved ) {
956 pNCell->setShared();
957 pNCell->setSecondCaloTopoTmpHashCluster(myCluster);
958 nextSharedCellList.push_back(neighborCell);
959 otherCluster->remove(neighborCell);
960 }
961 }
962 }
963 if ( myCluster != otherCluster ) {
964 HashCluster *toKill = otherCluster;
965 HashCluster *toKeep = myCluster;
966 if ( toKill ) {
967 if ( !toKill->getContainsLocalMax() && toKill->size() == 1) {
968 // note that the other cluster can only be merged if
969 // it has size 1 and does not contain local
970 // maxima. Both conditions need to be tested as in
971 // some rare cases with sharing of border cells a
972 // cluster including a local max might temporarily be
973 // of size 1 if its direct neighbors are all shared
974 // with other local maxima
975 HashCluster::iterator clusCellIter=toKill->begin();
976 HashCluster::iterator clusCellIterEnd = toKill->end();
977 for(;clusCellIter!=clusCellIterEnd;++clusCellIter) {
978 clusCellIter->setCaloTopoTmpHashCluster(toKeep);
979 }
980 toKeep->add(*toKill);
981 toKill->removeAll();
982 myCluster = toKeep;
983 }
984 }
985 else {
986 toKeep->add(neighborCell);
987 pNCell->setCaloTopoTmpHashCluster(toKeep);
988 }
989 }
990 }
991 }
992 }
993 mySeedCells.swap (myNextCells);
994
995 // sort next seed cells to start again with the cell of largest E
996 std::sort(mySeedCells.begin(),mySeedCells.end(),compareE);
997 // sort next shared cells to start again with the cell of largest E
998 if ( m_shareBorderCells) {
999 std::sort(nextSharedCellList.begin(),nextSharedCellList.end(),compareE);
1000 if (sharedCellList.empty())
1001 sharedCellList.swap (nextSharedCellList);
1002 else {
1003 sharedCellList.insert(sharedCellList.end(),
1004 nextSharedCellList.begin(),
1005 nextSharedCellList.end());
1006 }
1007 nextSharedCellList.clear();
1008 }
1009 }
1010
1011 // cluster the remaining cells around the shared cells and give each
1012 // newly clustered cell the same cluster pointers as its seeding
1013 // neighbor. Newly included cells are used as seeds in the next
1014 // iteration and sorted in E.
1015 int nShared(0);
1016 if ( m_shareBorderCells ) {
1017 mySeedCells = sharedCellList;
1018 while ( !mySeedCells.empty() ) {
1019
1020 // create cell list for next neighbor cells to consider
1021 myNextCells.clear();
1022 hashCellIter= mySeedCells.begin();
1023 hashCellIterEnd=mySeedCells.end();
1024
1025 // loop over all current neighbor cells (for Seed Growing Algo)
1026 for(;hashCellIter!=hashCellIterEnd;++hashCellIter) {
1027 CaloTopoSplitterClusterCell* pClusCell = hashCellIter->getCaloTopoTmpClusterCell();
1028 IdentifierHash hashid = pClusCell->getID();
1029 HashCluster *myCluster = pClusCell->getCaloTopoTmpHashCluster();
1030 HashCluster *mySecondCluster = pClusCell->getSecondCaloTopoTmpHashCluster();
1031 size_t iParent = pClusCell->getParentClusterIndex();
1032 CaloCell_ID::SUBCALO mySubDet = pClusCell->getSubDet();
1033 // in case we use all3d or super3D and the current cell is in the
1034 // HEC IW or FCal2 & 3 and we want to restrict their neighbors,
1035 // use only next in sampling neighbors
1036 theNeighbors.clear();
1039 && ( ( mySubDet == CaloCell_ID::LARHEC
1040 && m_calo_id->region(m_calo_id->cell_id(hashid)) == 1 )
1041 || ( mySubDet == CaloCell_ID::LARFCAL
1042 && m_calo_id->sampling(m_calo_id->cell_id(hashid)) > 1 ) ) ) {
1043 m_calo_id->get_neighbours(hashid,LArNeighbours::nextInSamp,theNeighbors);
1044 }
1045 else {
1046 m_calo_id->get_neighbours(hashid,m_nOption,theNeighbors);
1047 }
1048 // loop over all neighbors of that cell (Seed Growing Algo)
1049 if ( ctx.evt() == 0 && msgLvl(MSG::DEBUG)) {
1050 Identifier myId;
1051 myId = m_calo_id->cell_id(hashid);
1052 msg(MSG::DEBUG) << " Shared Cell [" << mySubDet << "|"
1053 << (unsigned int)hashid << "|"
1054 << m_calo_id->show_to_string(myId,nullptr,'/')
1055 << "] has " << theNeighbors.size() << " neighbors:"
1056 << endmsg;
1057 }//end if printout
1058 int otherSubDet;
1059 for (unsigned int iN=0;iN<theNeighbors.size();iN++) {
1060 otherSubDet = m_calo_id->sub_calo(theNeighbors[iN]);
1061 IdentifierHash nId = theNeighbors[iN];
1062 if (ctx.evt() == 0 && msgLvl(MSG::DEBUG)) {
1063 Identifier myId;
1064 myId = m_calo_id->cell_id(nId);
1065 msg(MSG::DEBUG) << " NeighborCell [" << otherSubDet << "|"
1066 << (unsigned int) nId << "|"
1067 << m_calo_id->show_to_string(myId,nullptr,'/') << "]"
1068 << endmsg;
1069 theNNeighbors.clear();
1070 m_calo_id->get_neighbours(nId,m_nOption,theNNeighbors);
1071 bool foundId (false);
1072 int nOtherSubDet;
1073 for (unsigned int iNN=0;iNN<theNNeighbors.size();iNN++) {
1074 nOtherSubDet = m_calo_id->sub_calo(theNNeighbors[iNN]);
1075 if (nOtherSubDet == ((int)(mySubDet)) &&
1076 theNNeighbors[iNN] == hashid)
1077 {
1078 foundId = true;
1079 break;
1080 }
1081 }
1082 if ( ! foundId ) {
1083 myId = m_calo_id->cell_id(hashid);
1084 msg(MSG::ERROR) <<" Shared Cell [" << mySubDet << "|"
1085 << (unsigned int)hashid << "|"
1086 << m_calo_id->show_to_string(myId,nullptr,'/')
1087 << "] has bad neighbor cell[";
1088 myId = m_calo_id->cell_id(nId);
1089
1090 msg() << otherSubDet << "|" << nId << "|"
1091 << m_calo_id->show_to_string(myId,nullptr,'/')
1092 << "]" << endmsg;
1093 }
1094 }
1095 HashCell neighborCell = cellVector[(unsigned int)nId - m_hashMin];
1096 CaloTopoSplitterClusterCell *pNCell = neighborCell.getCaloTopoTmpClusterCell();
1097 if ( pNCell && pNCell->getParentClusterIndex() == iParent && !pNCell->getShared() && !pNCell->getUsed() ) {
1098 // checking the neighbors
1099 HashCluster *otherCluster = pNCell->getCaloTopoTmpHashCluster();
1100 // the neighbors cell cluster should have just one member and be
1101 // different from the 2 clusters the seed cells belongs to
1102 if ( myCluster != otherCluster && mySecondCluster != otherCluster) {
1103 pNCell->setUsed();
1104 pNCell->setShared();
1105 myNextCells.push_back(neighborCell);
1106 sharedCellList.push_back(neighborCell);
1107 if ( otherCluster )
1108 otherCluster->removeAll();
1109 pNCell->setCaloTopoTmpHashCluster(myCluster);
1110 pNCell->setSecondCaloTopoTmpHashCluster(mySecondCluster);
1111 }
1112 }
1113 }
1114 }
1115 mySeedCells.swap (myNextCells);
1116
1117 // sort next seed cells to start again with the cell of largest E
1118 std::sort(mySeedCells.begin(),mySeedCells.end(),compareE);
1119 }
1120
1121 // add the shared cells to the clusters. For this the weights have
1122 // to be known first. This means that all clusters referenced in
1123 // the shared cell list need to compute their energy and
1124 // centroid. Once the energies and centroids are calculated the
1125 // shared cells are added with the weights w_1 = E_1/(E_1+r*E_2),
1126 // w2 = 1-w1, with r = exp(d1-d2), and d_i is the distance of the
1127 // shared cell to cluster i in units of a typical em shower
1128 // scale. In case E_i is negative or 0 the minimum value of 1 MeV
1129 // is assumed.
1130
1131 // loop over all shared cells and calculate the weights. Note that
1132 // we don't add the shared cells to the clusters in this loop in
1133 // order to keep the energy calculation free of shared cells for
1134 // all weights
1135 hashCellIter= sharedCellList.begin();
1136 hashCellIterEnd=sharedCellList.end();
1137 for(;hashCellIter!=hashCellIterEnd;++hashCellIter) {
1138 CaloTopoSplitterClusterCell* pClusCell = hashCellIter->getCaloTopoTmpClusterCell();
1139 float e1 = (pClusCell->getCaloTopoTmpHashCluster())->getEnergy();
1140 float e2 = (pClusCell->getSecondCaloTopoTmpHashCluster())->getEnergy();
1141 if(m_absOpt) e1 = std::abs(e1);
1142 if(m_absOpt) e2 = std::abs(e2);
1143 if ( e1 <= 0 ) e1 = 1*MeV;
1144 if ( e2 <= 0 ) e2 = 1*MeV;
1145 const xAOD::CaloCluster::cell_iterator itrCell = pClusCell->getCellIterator();
1146 Vector3D<double> thisPos(itrCell->x(),itrCell->y(),itrCell->z());
1147 const Vector3D<double> & c1 = (pClusCell->getCaloTopoTmpHashCluster())->getCentroid();
1148 const Vector3D<double> & c2 = (pClusCell->getSecondCaloTopoTmpHashCluster())->getCentroid();
1149 double d1 = (thisPos-c1).mag();
1150 double d2 = (thisPos-c2).mag();
1151 double r = (d1-d2)/m_emShowerScale;
1152
1153 if (m_useGPUCriteria) {
1154 //The GPU stores the smallest weight to maintain precision,
1155 //while the standard CPU implementation just uses the first cluster.
1156 //This has an impact on the moments that cut based on weighted_energy > 0...
1157 //As elsewhere, keeping the branches separate
1158 //to be sure the CPU implementation is unchanged by default
1159 //(even if the first calculation is the same for both).
1160 const double real_r_exp = r > 10. ? 10. : r < -10. ? -10. : r;
1161 const double real_r = exp(real_r_exp);
1162 const double r_reverse = exp(-real_r_exp);
1163 const double weight = e1/(e1 + e2 * real_r);
1164 const double reverse_weight = e2 / (e2 + e1 * r_reverse);
1165 if (weight > 0.5) {
1166 pClusCell->setSharedWeight(-reverse_weight);
1167 }
1168 else {
1169 pClusCell->setSharedWeight(weight);
1170 }
1171
1172 }
1173 else {
1174
1175 if ( r > 10 )
1176 r = exp(10);
1177 else if ( r < -10 )
1178 r = exp(-10);
1179 else
1180 r = exp(r);
1181
1182 pClusCell->setSharedWeight(e1/(e1+e2*r));
1183 }
1184 }
1185
1186 // loop again over all shared cells and add them to their
1187 // respective clusters
1188 hashCellIter= sharedCellList.begin();
1189 hashCellIterEnd=sharedCellList.end();
1190 for(;hashCellIter!=hashCellIterEnd;++hashCellIter) {
1191 CaloTopoSplitterClusterCell* pClusCell = hashCellIter->getCaloTopoTmpClusterCell();
1192 HashCluster *firstCluster = pClusCell->getCaloTopoTmpHashCluster();
1193 HashCluster *secondCluster = pClusCell->getSecondCaloTopoTmpHashCluster();
1194 firstCluster->add(*hashCellIter);
1195 secondCluster->add(*hashCellIter);
1196 }
1197 nShared = sharedCellList.size();
1198 }
1199
1200 const DataLink<CaloCellContainer> myCellCollLink (myCellColl);
1201
1202 // create cluster list for the purpose of sorting in E_t before storing
1203 // in the cluster collection
1204 std::vector<std::unique_ptr<CaloProtoCluster> > myCaloClusters;
1205 myCaloClusters.reserve (500);
1206 std::vector<std::unique_ptr<CaloProtoCluster> > myRestClusters;
1207 myRestClusters.resize(clusColl->size()); // this has a 0 pointer as default!
1208 std::vector<HashCluster *>::iterator hashClusIter = myHashClusters.begin();
1209 std::vector<HashCluster *>::iterator hashClusIterEnd=myHashClusters.end();
1210 for (;hashClusIter!=hashClusIterEnd;++hashClusIter) {
1211 HashCluster * tmpCluster = (*hashClusIter);
1212 if ( (m_useGPUCriteria && tmpCluster->getContainsLocalMax()) || tmpCluster->size() > 1 ) {
1213 // local maximum implies at least 2 cells are in the cluster ...
1214
1215 // If one is not using shared cells and the thresholds are low enough,
1216 // some local maxima may be surrounded (with one cell in the middle)
1217 // by other local maxima that gobble up the cells first.
1218 // For this reason, it makes sense to also include those clusters
1219 // as separate entities instead of merging all of them to the original (pre-split) cluster
1220 // as it was being done before.
1221 // In practice, since these settings would seldom be chosen
1222 // and the clusters would get a very low energy,
1223 // they'd get cut and not influence the results,
1224 // but, when doing the CPU <-> GPU comparison,
1225 // they showed up as unexpected and unexplainable differences...
1226
1227 std::unique_ptr<CaloProtoCluster> myCluster = std::make_unique<CaloProtoCluster>(myCellCollLink);
1228 ATH_MSG_DEBUG("[CaloCluster@" << myCluster.get() << "] created in <myCaloClusters>.");
1229 HashCluster::iterator clusCellIter=tmpCluster->begin();
1230 HashCluster::iterator clusCellIterEnd=tmpCluster->end();
1231 myCluster->getCellLinks()->reserve(tmpCluster->size());
1232 for(;clusCellIter!=clusCellIterEnd;++clusCellIter) {
1233 CaloTopoSplitterClusterCell *pClusCell = *clusCellIter;
1235 double myWeight = itrCell.weight();//pClusCell->getParentCluster()->getCellWeight(itrCell);
1236 if ( pClusCell->getShared() ) {
1237 if (m_useGPUCriteria) {
1238 const double shared_weight = pClusCell->getSharedWeight();
1239 if (shared_weight < 0.) {
1240 if ( pClusCell->getCaloTopoTmpHashCluster() == tmpCluster )
1241 myWeight *= 1.0 + shared_weight;
1242 else
1243 myWeight *= -shared_weight;
1244 }
1245 else {
1246 if ( pClusCell->getCaloTopoTmpHashCluster() == tmpCluster )
1247 myWeight *= shared_weight;
1248 else
1249 myWeight *= 1.0 - shared_weight;
1250 }
1251 }
1252 else {
1253 if ( pClusCell->getCaloTopoTmpHashCluster() == tmpCluster )
1254 myWeight *= pClusCell->getSharedWeight();
1255 else
1256 myWeight *= (1.-pClusCell->getSharedWeight());
1257 }
1258 }
1259 myCluster->addCell(itrCell.index(),myWeight);
1260 }
1261 ATH_MSG_DEBUG("[CaloCluster@" << myCluster.get() << "] size: " << myCluster->size());
1262 myCaloClusters.push_back(std::move(myCluster));
1263 }
1264 else if ( tmpCluster->size() == 1 ) {
1265 // either cells belonging to a cluster with no local maximum
1266 // or in case there was a local maximum a non-connected part
1267 // of the cluster (different cluster algo for parent cluster, or
1268 // in case of TopoClustering different neighbor option)
1269 if ( hasLocalMaxVector[tmpCluster->getParentClusterIndex()]) {
1270 // need to take care only of those with local max, as clusters without
1271 // any local max are copied anyways
1272
1273 if (!myRestClusters[tmpCluster->getParentClusterIndex()]) {
1274 myRestClusters[tmpCluster->getParentClusterIndex()] = std::make_unique<CaloProtoCluster>(myCellColl);
1275 }
1276 ATH_MSG_DEBUG("[CaloCluster@" << myRestClusters[tmpCluster->getParentClusterIndex()].get()
1277 << "] created in <myRestClusters>");
1278 myRestClusters[tmpCluster->getParentClusterIndex()]->getCellLinks()->reserve(tmpCluster->size());
1279 HashCluster::iterator clusCellIter=tmpCluster->begin();
1280 HashCluster::iterator clusCellIterEnd=tmpCluster->end();
1281 for(;clusCellIter!=clusCellIterEnd;++clusCellIter) {
1282 CaloTopoSplitterClusterCell *pClusCell = *clusCellIter;
1284 const double myWeight = itrCell.weight();
1285 myRestClusters[tmpCluster->getParentClusterIndex()]->addCell(itrCell.index(),myWeight);
1286 }
1287 ATH_MSG_DEBUG("[CaloCluster@" << myRestClusters[tmpCluster->getParentClusterIndex()].get()
1288 << "] size: " << myRestClusters[tmpCluster->getParentClusterIndex()]->size());
1289 }
1290 }
1291 }
1292
1293 // add the clusters which do not have any local max and the rest clusters
1294 // to the list
1295 iClusterNumber = 0;
1296 clusCollIter = clusColl->begin();
1297 for (; clusCollIter != clusCollIterEnd; ++clusCollIter,++iClusterNumber){
1298 const xAOD::CaloCluster* parentCluster = (*clusCollIter);
1299 if ( !hasLocalMaxVector[iClusterNumber] ) {
1300 //xAOD::CaloCluster *myClone = new xAOD::CaloCluster(*parentCluster);
1301 myCaloClusters.push_back(std::make_unique<CaloProtoCluster>(parentCluster->getCellLinks()));
1302 ATH_MSG_DEBUG("[CaloProtoCluster@" << myCaloClusters.back().get() << "] with "
1303 << myCaloClusters.back()->size() << "cells cloned from "
1304 << parentCluster << " with " << parentCluster->size() <<" cells");
1305 }
1306 else if (myRestClusters[iClusterNumber]) {
1307 ATH_MSG_DEBUG("[CaloCluster@" << myRestClusters[iClusterNumber].get()
1308 << "] pushed into <myCaloClusters> with "
1309 << myRestClusters[iClusterNumber]->size() << " cells");
1310 myCaloClusters.push_back(std::move(myRestClusters[iClusterNumber]));
1311 }
1312 }
1313
1314 std::sort(myCaloClusters.begin(),myCaloClusters.end(),[](const std::unique_ptr<CaloProtoCluster>& pc1,
1315 const std::unique_ptr<CaloProtoCluster>& pc2) {
1316 //As in CaloUtils/CaloClusterEtSort.
1317 //assign to volatile to avoid excess precison on in FP unit on x386 machines
1318 volatile double et1(pc1->et());
1319 volatile double et2(pc2->et());
1320 return (et1 > et2);
1321 }
1322 );
1323 // remove all original clusters from the cluster container
1324 if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << "erase " << clusColl->size() << " clusters";
1325 clusColl->clear();
1326 if (msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << ", new size " << clusColl->size() << endmsg;
1327 clusColl->reserve (myCaloClusters.size());
1328
1329 float eTot(0.);
1330 int nTot(0);
1331 float eMax(0.);
1332 // add to cluster container.
1333 for(const auto& protoCluster : myCaloClusters) {
1334 xAOD::CaloCluster* xAODCluster=new xAOD::CaloCluster();
1335 clusColl->push_back(xAODCluster);
1336 xAODCluster->addCellLink(protoCluster->releaseCellLinks());//Hand over ownership to xAOD::CaloCluster
1337 xAODCluster->setClusterSize(clusterSize);
1339 ATH_MSG_DEBUG("CaloCluster@" << xAODCluster << " pushed into "
1340 << "CaloClusterContainer@" << clusColl);
1341
1342 ATH_MSG_DEBUG("CaloClusterContainer@" << clusColl
1343 << "->size() = " << clusColl->size());
1344 ATH_MSG_DEBUG("CaloCluster E = " << xAODCluster->e()
1345 << " MeV, Et = " << xAODCluster->et()
1346 << " MeV, NCells = " << xAODCluster->size());
1347 eTot+=xAODCluster->e();
1348 nTot+=xAODCluster->size();
1349
1350 if ( std::abs(xAODCluster->e()) > eMax )
1351 eMax = std::abs(xAODCluster->e());
1352 }
1353 ATH_MSG_DEBUG("Sum of all CaloClusters E = " << eTot
1354 << " MeV, NCells = " << nTot
1355 << " (including NShared = " << nShared << " twice)");
1356
1357 if ( std::abs(eTot) > eMax )
1358 eMax = std::abs(eTot);
1359 if ( std::abs(eTot-eTotOrig)>0.001*eMax ){
1360 msg(MSG::WARNING) << "Energy sum for split Clusters = " << eTot << " MeV does not equal original sum = " << eTotOrig << " MeV !" << endmsg;
1361 }
1362 if ( abs(nTot-nShared-nTotOrig) > 0 ) {
1363 msg(MSG::ERROR) <<"Cell sum for split Clusters does not equal original sum!" << endmsg;
1364 }
1365
1366 tmpcell_pool.erase();
1367 tmpclus_pool.erase();
1368
1369 return StatusCode::SUCCESS;
1370
1371}
Scalar mag() const
mag method
#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_DEBUG(x)
bool isLocalMax(vector2D< FPGATrackSimRoad * > const &acc, unsigned x, unsigned y, int localMaxWindowSize)
static Double_t a
Eigen::Matrix< double, 3, 1 > Vector3D
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.
CaloCell_Base_ID::SUBCALO SUBCALO
Definition CaloCell_ID.h:50
Data object for each calorimeter readout cell.
Definition CaloCell.h:57
virtual double e() const override final
get energy (data member) (synonym to method energy()
Definition CaloCell.h:333
virtual double phi() const override final
get phi (through CaloDetDescrElement)
Definition CaloCell.h:375
float y() const
get y (through CaloDetDescrElement)
Definition CaloCell.h:436
virtual double eta() const override final
get eta (through CaloDetDescrElement)
Definition CaloCell.h:382
float z() const
get z (through CaloDetDescrElement)
Definition CaloCell.h:443
float x() const
get x (through CaloDetDescrElement)
Definition CaloCell.h:429
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.
int m_maxSecondarySampling
largest valid secondary sampling found
float m_emShowerScale
typical em shower scale to use for distance criteria in shared cells
int m_minSampling
smallest valid sampling found
virtual StatusCode execute(const EventContext &ctx, xAOD::CaloClusterContainer *theClusters) const override
Execute on an entire collection of clusters.
std::string m_neighborOption
type of neighbor relations to use.
float m_minEnergy
local maxima need at least this energy content
virtual StatusCode initialize() override
Gaudi::Property< bool > m_useGPUCriteria
std::vector< bool > m_useSampling
flag for all samplings - true for used ones, false for excluded ones
std::vector< bool > m_useSecondarySampling
flag for all secondary samplings - true for used ones, false for excluded ones
int m_maxSampling
largest valid sampling found
std::vector< std::string > m_secondarySamplingNames
vector of names of the secondary calorimeter samplings to consider.
std::vector< std::string > m_samplingNames
vector of names of the calorimeter samplings to consider.
int m_minSecondarySampling
smallest valid secondary sampling found
std::set< int > m_validSamplings
actual set of samplings to be used
LArNeighbours::neighbourOption m_nOption
bool m_restrictHECIWandFCalNeighbors
if set to true limit the neighbors in HEC IW and FCal2&3.
std::set< int > m_validSecondarySamplings
actual set of secondary samplings to be used
bool m_treatL1PredictedCellsAsGood
if set to true treat cells with a dead OTX which can be predicted by L1 trigger info as good instead ...
CaloTopoClusterSplitter(const std::string &type, const std::string &name, const IInterface *parent)
bool m_absOpt
if set to true, splitter only looks at absolute value of Energy in order to identify potential seed c...
bool m_shareBorderCells
share cells at the border between two local maxima
int m_nCells
local maxima need at least this number of neighbors to become seeds
const CaloTopoSplitterHashCluster * getCaloTopoTmpHashCluster() const
CaloTopoSplitterHashCluster * getSecondCaloTopoTmpHashCluster()
const xAOD::CaloCluster::cell_iterator & getCellIterator() const
void setSharedWeight(const float &weight)
void setCaloTopoTmpHashCluster(CaloTopoSplitterHashCluster *cluster)
CaloCell_ID::SUBCALO getSubDet() const
const IdentifierHash & getID() 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.
DataModel_detail::iterator< DataVector > iterator
Definition DataVector.h:842
const_iterator end() const noexcept
Return a const_iterator pointing past the end of the collection.
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
void clear()
Erase all the elements in the collection.
This is a "hash" representation of an Identifier.
std::string getString() const
Provide a string form of the identifier - hexadecimal.
void erase()
Free all allocated elements and release memory back to the system (of this type in the current Arena)...
User interface for allocating memory.
Definition ArenaHandle.h:73
void * allocate()
Allocate a new element.
const CaloClusterCellLink * getCellLinks() const
Get a pointer to the CaloClusterCellLink object (const version)
void addCellLink(CaloClusterCellLink *CCCL)
size_t size() const
size method (forwarded from CaloClusterCellLink obj)
CaloClusterCellLink::iterator cell_iterator
Iterator of the underlying CaloClusterCellLink (non-const version)
virtual double e() const
The total energy of the particle.
void setClusterSize(const ClusterSize)
Get cluster size.
const_cell_iterator cell_end() const
ClusterSize
Enumeration to identify different cluster sizes.
CaloClusterCellLink * getOwnCellLinks()
Get a pointer to the owned CaloClusterCellLink object (non-const version)
const_cell_iterator cell_begin() const
Iterator of the underlying CaloClusterCellLink (const version)
int r
Definition globals.cxx:22
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130
void prefetchNext(Iter iter, Iter endIter)
Prefetch next object in sequence.
Definition prefetch.h:130
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.
Functions to prefetch blocks of memory.
static bool isBad(const CaloCell *pCell, bool treatL1PredictedCellsAsGood)