@@ -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,63 @@ 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+ const size_t n = inputsIndices.size ();
503+ std::vector<short > rows;
504+ std::vector<short > columns;
505+ std::vector<double > energies;
506+
507+ rows.reserve (n);
508+ columns.reserve (n);
509+ energies.reserve (n);
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+ const auto [row, column] = mGeomPtr ->GetTopologicalRowColumn (nSupMod, nModule, nIphi, nIeta);
517+
518+ rows.push_back (row);
519+ columns.push_back (column);
520+ energies.push_back (mInputsContainer [iInput].getEnergy ());
521+ }
522+
523+ // Now find local maxima using pre-computed data
524+ int nExMax = 0 ;
525+ for (size_t i = 0 ; i < n; i++) {
526+ // this cell is assumed to be local maximum unless we find a higher energy cell in the neighborhood
527+ bool isExMax = true ;
528+
529+ // loop over all other cells in cluster
530+ for (size_t j = 0 ; j < n; j++) {
531+ if (i == j)
532+ continue ;
533+
534+ // adjacent cell is any cell with adjacent phi or eta index
535+ if (std::abs (rows[i] - rows[j]) <= 1 &&
536+ std::abs (columns[i] - columns[j]) <= 1 ) {
537+
538+ // if there is a cell with higher energy than the current cell, it is not a local maximum
539+ if (energies[j] > energies[i]) {
540+ isExMax = false ;
541+ break ;
542+ }
543+ }
544+ }
545+ if (isExMax) {
546+ nExMax++;
547+ }
548+ }
549+ clusterAnalysis.setNExMax (nExMax);
550+ }
551+
492552// /
493553// / Calculates the axis of the shower ellipsoid in eta and phi
494554// / in cell units
0 commit comments