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