File indexing completed on 2025-07-09 05:00:28
0001 #include "RecoParticleFlow/PFClusterProducer/plugins/BarrelCLUEAlgo.h"
0002 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0003
0004 #include "Geometry/CaloGeometry/interface/CaloSubdetectorGeometry.h"
0005 #include "DataFormats/CaloRecHit/interface/CaloID.h"
0006 #include "DataFormats/HcalDetId/interface/HcalDetId.h"
0007
0008 #include "oneapi/tbb/task_arena.h"
0009 #include "oneapi/tbb.h"
0010 #include <limits>
0011
0012 using namespace hgcal_clustering;
0013
0014 template <typename T>
0015 void BarrelCLUEAlgoT<T>::setThresholds(edm::ESGetToken<EcalPFRecHitThresholds, EcalPFRecHitThresholdsRcd> EBThres,
0016 edm::ESGetToken<HcalPFCuts, HcalPFCutsRcd> HCALThres) {
0017 tok_ebThresholds_ = EBThres;
0018 tok_hcalThresholds_ = HCALThres;
0019 }
0020
0021 template <typename T>
0022 void BarrelCLUEAlgoT<T>::getEventSetupPerAlgorithm(const edm::EventSetup& es) {
0023 cells_.clear();
0024 numberOfClustersPerLayer_.clear();
0025 ebThresholds_ = &es.getData(tok_ebThresholds_);
0026 hcalThresholds_ = &es.getData(tok_hcalThresholds_);
0027 maxlayer_ = maxLayerIndex_;
0028 cells_.resize(maxlayer_ + 1);
0029 numberOfClustersPerLayer_.resize(maxlayer_ + 1, 0);
0030 }
0031
0032 template <typename T>
0033 void BarrelCLUEAlgoT<T>::populate(const reco::PFRecHitCollection& hits) {
0034 for (unsigned int i = 0; i < hits.size(); ++i) {
0035 const reco::PFRecHit& hit = hits[i];
0036 DetId detid(hit.detId());
0037 const GlobalPoint position = rhtools_.getPosition(detid);
0038 int layer = 0;
0039
0040 if (detid.det() == DetId::Hcal) {
0041 HcalDetId hid(detid);
0042 layer = hid.depth();
0043 if (detid.subdetId() == HcalSubdetector::HcalOuter)
0044 layer += 1;
0045 }
0046
0047 cells_[layer].detid.push_back(detid);
0048 cells_[layer].eta.push_back(position.eta());
0049 cells_[layer].phi.push_back(position.phi());
0050 cells_[layer].weight.push_back(hit.energy());
0051 cells_[layer].r.push_back(position.mag());
0052 float sigmaNoise = 0.f;
0053 if (detid.det() == DetId::Ecal) {
0054 sigmaNoise = (*ebThresholds_)[detid];
0055 } else {
0056 const HcalPFCut* item = (*hcalThresholds_).getValues(detid);
0057 sigmaNoise = item->seedThreshold();
0058 }
0059 cells_[layer].sigmaNoise.push_back(sigmaNoise);
0060 }
0061 }
0062
0063 template <typename T>
0064 void BarrelCLUEAlgoT<T>::prepareDataStructures(unsigned int l) {
0065 auto cellsSize = cells_[l].detid.size();
0066 cells_[l].rho.resize(cellsSize, 0.f);
0067 cells_[l].delta.resize(cellsSize, 9999999);
0068 cells_[l].nearestHigher.resize(cellsSize, -1);
0069 cells_[l].clusterIndex.resize(cellsSize);
0070 cells_[l].followers.resize(cellsSize);
0071 cells_[l].isSeed.resize(cellsSize, false);
0072 cells_[l].eta.resize(cellsSize, 0.f);
0073 cells_[l].phi.resize(cellsSize, 0.f);
0074 cells_[l].r.resize(cellsSize, 0.f);
0075 }
0076
0077 template <typename T>
0078 void BarrelCLUEAlgoT<T>::makeClusters() {
0079 tbb::this_task_arena::isolate([&] {
0080 tbb::parallel_for(size_t(0), size_t(maxlayer_ + 1), [&](size_t i) {
0081 prepareDataStructures(i);
0082 T lt;
0083 lt.clear();
0084 lt.fill(cells_[i].eta, cells_[i].phi);
0085
0086 calculateLocalDensity(lt, i, deltac_);
0087 calculateDistanceToHigher(lt, i, deltac_);
0088 numberOfClustersPerLayer_[i] = findAndAssignClusters(i, deltac_);
0089
0090 if (doSharing_)
0091
0092 passSharedClusterIndex(lt, i, deltac_);
0093 });
0094 });
0095 for (unsigned int i = 0; i < maxlayer_ + 1; ++i) {
0096 setDensity(i);
0097 }
0098 }
0099
0100 template <typename T>
0101 std::vector<reco::BasicCluster> BarrelCLUEAlgoT<T>::getClusters(bool) {
0102 std::vector<int> offsets(numberOfClustersPerLayer_.size(), 0);
0103
0104 int maxClustersOnLayer = numberOfClustersPerLayer_[0];
0105
0106 if constexpr (!std::is_same_v<T, EBLayerTiles>) {
0107 for (unsigned layerId = 1; layerId < offsets.size(); ++layerId) {
0108 offsets[layerId] = offsets[layerId - 1] + numberOfClustersPerLayer_[layerId - 1];
0109 maxClustersOnLayer = std::max(maxClustersOnLayer, numberOfClustersPerLayer_[layerId]);
0110 }
0111 }
0112
0113 auto totalNumberOfClusters = offsets.back() + numberOfClustersPerLayer_.back();
0114 clusters_v_.resize(totalNumberOfClusters);
0115
0116
0117 std::vector<std::vector<std::pair<int, float>>> cellsIdInCluster;
0118 cellsIdInCluster.reserve(maxClustersOnLayer);
0119
0120 for (unsigned int layerId = 0; layerId < maxlayer_ + 1; ++layerId) {
0121 cellsIdInCluster.resize(numberOfClustersPerLayer_[layerId]);
0122 auto& cellsOnLayer = cells_[layerId];
0123 unsigned int numberOfCells = cellsOnLayer.detid.size();
0124 auto firstClusterIdx = offsets[layerId];
0125
0126 for (unsigned int i = 0; i < numberOfCells; ++i) {
0127 auto clusterIndex = cellsOnLayer.clusterIndex[i];
0128
0129 if (clusterIndex.size() == 1) {
0130 cellsIdInCluster[clusterIndex[0]].push_back(std::make_pair(i, 1.f));
0131 } else if (clusterIndex.size() > 1) {
0132 std::vector<float> fractions(clusterIndex.size());
0133
0134 for (unsigned int j = 0; j < clusterIndex.size(); j++) {
0135 const auto& seed = clusterIndex[j];
0136 const auto& seedCell = cellsOnLayer.seedToCellIndex[seed];
0137 const auto& seedEnergy = cellsOnLayer.weight[seedCell];
0138
0139 float dist = distance(i, seedCell, layerId) / T::type::cellWidthEta;
0140 fractions[j] = seedEnergy * std::exp(-(std::pow(dist, 2)) / (2 * std::pow(T::type::showerSigma, 2)));
0141 }
0142 auto tot_norm_fractions = std::accumulate(std::begin(fractions), std::end(fractions), 0.);
0143
0144 for (unsigned int j = 0; j < clusterIndex.size(); j++) {
0145 float norm_fraction = fractions[j] / tot_norm_fractions;
0146 if (norm_fraction < fractionCutoff_) {
0147 auto clusterIndex_it = std::find(clusterIndex.begin(), clusterIndex.end(), clusterIndex[j]);
0148 auto fraction_it = std::find(fractions.begin(), fractions.end(), fractions[j]);
0149 clusterIndex.erase(clusterIndex_it);
0150 fractions.erase(fraction_it);
0151 }
0152 if (norm_fraction >= fractionCutoff_) {
0153 cellsIdInCluster[clusterIndex[j]].push_back(std::make_pair(i, norm_fraction));
0154 }
0155 }
0156 auto tot_norm_cleaned_fractions = std::accumulate(fractions.begin(), fractions.end(), 0.);
0157 for (unsigned int j = 0; j < clusterIndex.size(); j++) {
0158 float norm_fraction = fractions[j] / tot_norm_cleaned_fractions;
0159 cellsIdInCluster[clusterIndex[j]].push_back(std::make_pair(i, norm_fraction));
0160 }
0161 }
0162 }
0163
0164 std::vector<std::pair<DetId, float>> thisCluster;
0165 for (int clIndex = 0; clIndex < numberOfClustersPerLayer_[layerId]; clIndex++) {
0166 auto& cl = cellsIdInCluster[clIndex];
0167 auto position = calculatePosition(cl, layerId);
0168 float energy = 0.f;
0169 int seedDetId = -1;
0170
0171 for (auto [cellIdx, fraction] : cl) {
0172 energy += cellsOnLayer.weight[cellIdx] * fraction;
0173 thisCluster.emplace_back(cellsOnLayer.detid[cellIdx], fraction);
0174 if (cellsOnLayer.isSeed[cellIdx]) {
0175 seedDetId = cellsOnLayer.detid[cellIdx];
0176 }
0177 }
0178 auto globalClusterIndex = clIndex + firstClusterIdx;
0179
0180 if constexpr (std::is_same_v<T, EBLayerTiles>) {
0181 clusters_v_[globalClusterIndex] =
0182 reco::BasicCluster(energy, position, reco::CaloID::DET_ECAL_BARREL, thisCluster, algoId_);
0183 } else if constexpr (std::is_same_v<T, HBLayerTiles>) {
0184 clusters_v_[globalClusterIndex] =
0185 reco::BasicCluster(energy, position, reco::CaloID::DET_HCAL_BARREL, thisCluster, algoId_);
0186 } else {
0187 clusters_v_[globalClusterIndex] =
0188 reco::BasicCluster(energy, position, reco::CaloID::DET_HO, thisCluster, algoId_);
0189 }
0190 clusters_v_[globalClusterIndex].setSeed(seedDetId);
0191 thisCluster.clear();
0192 }
0193 cellsIdInCluster.clear();
0194 }
0195 return clusters_v_;
0196 }
0197
0198 template <typename T>
0199 math::XYZPoint BarrelCLUEAlgoT<T>::calculatePosition(const std::vector<std::pair<int, float>>& v,
0200 const unsigned int layerId) const {
0201 float total_weight = 0.f;
0202 float x = 0.f;
0203 float y = 0.f;
0204 float z = 0.f;
0205
0206 auto& cellsOnLayer = cells_[layerId];
0207 for (const auto& [i, fraction] : v) {
0208 float rhEnergy = cellsOnLayer.weight[i] * fraction;
0209 total_weight += rhEnergy;
0210 float theta = 2 * std::atan(std::exp(-cellsOnLayer.eta[i]));
0211 const GlobalPoint gp(GlobalPoint::Polar(theta, cellsOnLayer.phi[i], cellsOnLayer.r[i]));
0212 x += gp.x() * rhEnergy;
0213 y += gp.y() * rhEnergy;
0214 z += gp.z() * rhEnergy;
0215 }
0216 if (total_weight != 0.f) {
0217 float inv_total_weight = 1.f / total_weight;
0218 return math::XYZPoint(x * inv_total_weight, y * inv_total_weight, z * inv_total_weight);
0219 } else {
0220 return math::XYZPoint(0.f, 0.f, 0.f);
0221 }
0222 }
0223
0224 template <typename T>
0225 void BarrelCLUEAlgoT<T>::calculateLocalDensity(const T& lt, const unsigned int layerId, float deltac_) {
0226 auto& cellsOnLayer = cells_[layerId];
0227 unsigned int numberOfCells = cellsOnLayer.detid.size();
0228
0229 for (unsigned int i = 0; i < numberOfCells; ++i) {
0230 float delta = deltac_;
0231 std::array<int, 4> search_box = lt.searchBox(cellsOnLayer.eta[i] - delta,
0232 cellsOnLayer.eta[i] + delta,
0233 cellsOnLayer.phi[i] - delta,
0234 cellsOnLayer.phi[i] + delta);
0235 LogDebug("BarrelCLUEAlgo") << "searchBox for cell " << i << " cell eta: " << cellsOnLayer.eta[i]
0236 << " cell phi: " << cellsOnLayer.phi[i] << " eta window: " << cellsOnLayer.eta[i] - delta
0237 << " -> " << cellsOnLayer.eta[i] + delta
0238 << " phi window: " << cellsOnLayer.phi[i] - delta << " -> "
0239 << cellsOnLayer.phi[i] + delta << "\n";
0240 for (int etaBin = search_box[0]; etaBin < search_box[1]; ++etaBin) {
0241 for (int phiBin = search_box[2]; phiBin < search_box[3]; ++phiBin) {
0242 int phi = (phiBin % T::type::nRows);
0243 int binId = lt.getGlobalBinByBin(etaBin, phi);
0244 size_t binSize = lt[binId].size();
0245 LogDebug("BarrelCLUEAlgo") << "Bin size for cell " << i << ": " << binSize << " binId: " << binId
0246 << " etaBin: " << etaBin << " phi: " << phi << "\n";
0247 for (unsigned int j = 0; j < binSize; ++j) {
0248 unsigned int otherId = lt[binId][j];
0249 if (distance(i, otherId, layerId) < delta) {
0250 cellsOnLayer.rho[i] += (i == otherId ? 1.f : 0.5f) * cellsOnLayer.weight[otherId];
0251 }
0252 }
0253 }
0254 }
0255 }
0256 }
0257
0258 template <typename T>
0259 void BarrelCLUEAlgoT<T>::calculateDistanceToHigher(const T& lt, const unsigned int layerId, float delta_c) {
0260 auto& cellsOnLayer = cells_[layerId];
0261 unsigned int numberOfCells = cellsOnLayer.detid.size();
0262
0263 for (unsigned int i = 0; i < numberOfCells; ++i) {
0264 float maxDelta = std::numeric_limits<float>::max();
0265 float i_delta = maxDelta;
0266 float i_nearestHigher = -1;
0267
0268 float range = delta_c;
0269 std::array<int, 4> search_box = lt.searchBox(cellsOnLayer.eta[i] - range,
0270 cellsOnLayer.eta[i] + range,
0271 cellsOnLayer.phi[i] - range,
0272 cellsOnLayer.phi[i] + range);
0273
0274 for (int etaBin = search_box[0]; etaBin < search_box[1]; ++etaBin) {
0275 for (int phiBin = search_box[2]; phiBin < search_box[3]; ++phiBin) {
0276 int phi = (phiBin % T::type::nRows);
0277 size_t binId = lt.getGlobalBinByBin(etaBin, phi);
0278 size_t binSize = lt[binId].size();
0279
0280 for (unsigned int j = 0; j < binSize; ++j) {
0281 int otherId = lt[binId][j];
0282 float dist = distance(i, otherId, layerId);
0283 bool foundHigher =
0284 (cellsOnLayer.rho[otherId] > cellsOnLayer.rho[i]) ||
0285 (cellsOnLayer.rho[otherId] == cellsOnLayer.rho[i] && cellsOnLayer.detid[otherId] > cellsOnLayer.detid[i]);
0286 if (foundHigher && dist <= i_delta) {
0287 i_delta = dist;
0288 i_nearestHigher = otherId;
0289 }
0290 }
0291 }
0292 }
0293 bool foundNearestHigherInSearchBox = (i_delta != maxDelta);
0294 if (foundNearestHigherInSearchBox) {
0295 cellsOnLayer.delta[i] = i_delta;
0296 cellsOnLayer.nearestHigher[i] = i_nearestHigher;
0297 } else {
0298 cellsOnLayer.delta[i] = maxDelta;
0299 cellsOnLayer.nearestHigher[i] = -1;
0300 }
0301 LogDebug("BarrelCLUEAlgo") << "Debugging calculateDistanceToHigher: \n"
0302 << " cell: " << i << " eta: " << cellsOnLayer.eta[i] << " phi: " << cellsOnLayer.phi[i]
0303 << " energy: " << cellsOnLayer.weight[i] << " density: " << cellsOnLayer.rho[i]
0304 << " nearest higher: " << cellsOnLayer.nearestHigher[i]
0305 << " distance: " << cellsOnLayer.delta[i] << "\n";
0306 }
0307 }
0308
0309 template <typename T>
0310 int BarrelCLUEAlgoT<T>::findAndAssignClusters(const unsigned int layerId, float delta_c) {
0311 unsigned int nClustersOnLayer = 0;
0312 auto& cellsOnLayer = cells_[layerId];
0313 unsigned int numberOfCells = cellsOnLayer.detid.size();
0314 std::vector<int> localStack;
0315 for (unsigned int i = 0; i < numberOfCells; ++i) {
0316 float rho_c = kappa_ * cellsOnLayer.sigmaNoise[i];
0317 float delta = delta_c;
0318
0319
0320
0321
0322 bool isSeed = (cellsOnLayer.delta[i] > delta) && (cellsOnLayer.rho[i] >= rho_c);
0323 bool isOutlier = (cellsOnLayer.delta[i] > outlierDeltaFactor_) && (cellsOnLayer.rho[i] < rho_c);
0324 if (isSeed) {
0325 cellsOnLayer.clusterIndex[i].push_back(nClustersOnLayer);
0326 cellsOnLayer.isSeed[i] = true;
0327 cellsOnLayer.seedToCellIndex.push_back(i);
0328 nClustersOnLayer++;
0329 localStack.push_back(i);
0330 } else if (!isOutlier) {
0331 cellsOnLayer.followers[cellsOnLayer.nearestHigher[i]].push_back(i);
0332 }
0333 }
0334
0335 while (!localStack.empty()) {
0336 int endStack = localStack.back();
0337 auto& thisSeed = cellsOnLayer.followers[endStack];
0338 localStack.pop_back();
0339
0340 for (int j : thisSeed) {
0341 cellsOnLayer.clusterIndex[j].push_back(cellsOnLayer.clusterIndex[endStack][0]);
0342 localStack.push_back(j);
0343 }
0344 }
0345 return nClustersOnLayer;
0346 }
0347
0348 template <typename T>
0349 void BarrelCLUEAlgoT<T>::passSharedClusterIndex(const T& lt, const unsigned int layerId, float delta_c) {
0350 auto& cellsOnLayer = cells_[layerId];
0351 unsigned int numberOfCells = cellsOnLayer.detid.size();
0352 float delta = delta_c;
0353 for (unsigned int i = 0; i < numberOfCells; ++i) {
0354
0355 if ((cellsOnLayer.clusterIndex[i].size() == 0))
0356 continue;
0357
0358 std::array<int, 4> search_box = lt.searchBox(cellsOnLayer.eta[i] - delta,
0359 cellsOnLayer.eta[i] + delta,
0360 cellsOnLayer.phi[i] - delta,
0361 cellsOnLayer.phi[i] + delta);
0362
0363 for (int etaBin = search_box[0]; etaBin < search_box[1]; ++etaBin) {
0364 for (int phiBin = search_box[2]; phiBin < search_box[3]; ++phiBin) {
0365 int phi = (phiBin % T::type::nRows);
0366 size_t binId = lt.getGlobalBinByBin(etaBin, phi);
0367 size_t binSize = lt[binId].size();
0368
0369 for (unsigned int j = 0; j < binSize; ++j) {
0370 unsigned int otherId = lt[binId][j];
0371 if (cellsOnLayer.clusterIndex[otherId].size() == 0)
0372 continue;
0373 int otherClusterIndex = cellsOnLayer.clusterIndex[otherId][0];
0374 if (std::find(std::begin(cellsOnLayer.clusterIndex[i]),
0375 std::end(cellsOnLayer.clusterIndex[i]),
0376 otherClusterIndex) == std::end(cellsOnLayer.clusterIndex[i]))
0377 cellsOnLayer.clusterIndex[i].push_back(otherClusterIndex);
0378 }
0379 }
0380 }
0381 }
0382 }
0383
0384 template <typename T>
0385 void BarrelCLUEAlgoT<T>::setDensity(const unsigned int layerId) {
0386 auto& cellsOnLayer = cells_[layerId];
0387 unsigned int numberOfCells = cellsOnLayer.detid.size();
0388 for (unsigned int i = 0; i < numberOfCells; ++i) {
0389 density_[cellsOnLayer.detid[i]] = cellsOnLayer.rho[i];
0390 }
0391 }
0392
0393 template <typename T>
0394 Density BarrelCLUEAlgoT<T>::getDensity() {
0395 return density_;
0396 }
0397
0398 template class BarrelCLUEAlgoT<EBLayerTiles>;
0399 template class BarrelCLUEAlgoT<HBLayerTiles>;