@@ -120,6 +120,9 @@ o2::emcal::AnalysisCluster ClusterFactory<InputType>::buildCluster(int clusterIn
120120 evalElipsAxis (inputsIndices, clusterAnalysis);
121121 evalDispersion (inputsIndices, clusterAnalysis);
122122
123+ // evaluate number of local maxima
124+ evalNExMax (inputsIndices, clusterAnalysis);
125+
123126 evalCoreEnergy (inputsIndices, clusterAnalysis);
124127 evalTime (inputsIndices, clusterAnalysis);
125128
@@ -489,6 +492,59 @@ void ClusterFactory<InputType>::evalCoreEnergy(gsl::span<const int> inputsIndice
489492 clusterAnalysis.setCoreEnergy (coreEnergy);
490493}
491494
495+ // /
496+ // / Calculate the number of local maxima in the cluster
497+ // ____________________________________________________________________________
498+ template <class InputType >
499+ void ClusterFactory<InputType>::evalNExMax(gsl::span<const int > inputsIndices, AnalysisCluster& clusterAnalysis) const
500+ {
501+ // Pre-compute cell indices and energies for all cells in cluster to avoid multiple expensive geometry lookups
502+ struct CellInfo {
503+ int row;
504+ int column;
505+ double energy;
506+ };
507+
508+ std::vector<CellInfo> cellInfos;
509+ cellInfos.reserve (inputsIndices.size ());
510+
511+ for (auto iInput : inputsIndices) {
512+ auto [nSupMod, nModule, nIphi, nIeta] = mGeomPtr ->GetCellIndex (mInputsContainer [iInput].getTower ());
513+
514+ // get a nice topological indexing that is done in exactly the same way as used by the clusterizer
515+ // this way we can handle the shared cluster cases correctly
516+ auto [row, column] = mGeomPtr ->GetTopologicalRowColumn (nSupMod, nModule, nIphi, nIeta);
517+ cellInfos.push_back ({row, column, mInputsContainer [iInput].getEnergy ()});
518+ }
519+
520+ // Now find local maxima using pre-computed data
521+ int nExMax = 0 ;
522+ for (size_t i = 0 ; i < cellInfos.size (); i++) {
523+ // this cell is assumed to be local maximum unless we find a higher energy cell in the neighborhood
524+ bool isExMax = true ;
525+
526+ // loop over all other cells in cluster
527+ for (size_t j = 0 ; j < cellInfos.size (); j++) {
528+ if (i == j) continue ;
529+
530+ // adjacent cell is any cell with adjacent phi or eta index
531+ if (std::abs (cellInfos[i].row - cellInfos[j].row ) <= 1 &&
532+ std::abs (cellInfos[i].column - cellInfos[j].column ) <= 1 ) {
533+
534+ // if there is a cell with higher energy than the current cell, it is not a local maximum
535+ if (cellInfos[j].energy > cellInfos[i].energy ) {
536+ isExMax = false ;
537+ break ;
538+ }
539+ }
540+ }
541+ if (isExMax) {
542+ nExMax++;
543+ }
544+ }
545+ clusterAnalysis.setNExMax (nExMax);
546+ }
547+
492548// /
493549// / Calculates the axis of the shower ellipsoid in eta and phi
494550// / in cell units
0 commit comments