File indexing completed on 2025-06-08 07:53:21
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #include "algorithms/calorimetry/ImagingTopoCluster.h"
0023
0024 #include <Evaluator/DD4hepUnits.h>
0025 #include <edm4hep/Vector3f.h>
0026 #include <edm4hep/utils/vector_utils.h>
0027 #include <fmt/core.h>
0028 #include <cmath>
0029 #include <cstdlib>
0030 #include <gsl/pointers>
0031 #include <vector>
0032
0033 #include "algorithms/calorimetry/ImagingTopoClusterConfig.h"
0034
0035 namespace eicrecon {
0036
0037 void ImagingTopoCluster::init() {
0038
0039
0040 if (m_cfg.localDistXY.size() != 2) {
0041 error("Expected 2 values (x_dist, y_dist) for localDistXY");
0042 return;
0043 }
0044 if (m_cfg.layerDistEtaPhi.size() != 2) {
0045 error("Expected 2 values (eta_dist, phi_dist) for layerDistEtaPhi");
0046 return;
0047 }
0048 if (m_cfg.minClusterCenterEdep < m_cfg.minClusterHitEdep) {
0049 error("minClusterCenterEdep must be greater than or equal to minClusterHitEdep");
0050 return;
0051 }
0052
0053
0054 localDistXY[0] = m_cfg.localDistXY[0] / dd4hep::mm;
0055 localDistXY[1] = m_cfg.localDistXY[1] / dd4hep::mm;
0056 layerDistXY[0] = m_cfg.layerDistXY[0] / dd4hep::mm;
0057 layerDistXY[1] = m_cfg.layerDistXY[1] / dd4hep::mm;
0058 layerDistEtaPhi[0] = m_cfg.layerDistEtaPhi[0];
0059 layerDistEtaPhi[1] = m_cfg.layerDistEtaPhi[1] / dd4hep::rad;
0060 sectorDist = m_cfg.sectorDist / dd4hep::mm;
0061 minClusterHitEdep = m_cfg.minClusterHitEdep / dd4hep::GeV;
0062 minClusterCenterEdep = m_cfg.minClusterCenterEdep / dd4hep::GeV;
0063 minClusterEdep = m_cfg.minClusterEdep / dd4hep::GeV;
0064
0065
0066 info("Local clustering (same sector and same layer): "
0067 "Local [x, y] distance between hits <= [{:.4f} mm, {:.4f} mm].",
0068 localDistXY[0], localDistXY[1]);
0069 switch (m_cfg.layerMode) {
0070 case ImagingTopoClusterConfig::ELayerMode::etaphi:
0071 info("Neighbour layers clustering (same sector and layer id within +- {:d}: "
0072 "Global [eta, phi] distance between hits <= [{:.4f}, {:.4f} rad].",
0073 m_cfg.neighbourLayersRange, layerDistEtaPhi[0], layerDistEtaPhi[1]);
0074 break;
0075 case ImagingTopoClusterConfig::ELayerMode::xy:
0076 info("Neighbour layers clustering (same sector and layer id within +- {:d}: "
0077 "Local [x, y] distance between hits <= [{:.4f} mm, {:.4f} mm].",
0078 m_cfg.neighbourLayersRange, layerDistXY[0], layerDistXY[1]);
0079 break;
0080 default:
0081 error("Unknown layer mode.");
0082 }
0083 info("Neighbour sectors clustering (different sector): "
0084 "Global distance between hits <= {:.4f} mm.",
0085 sectorDist);
0086 }
0087
0088 void ImagingTopoCluster::process(const Input& input, const Output& output) const {
0089
0090 const auto [hits] = input;
0091 auto [proto] = output;
0092
0093
0094 auto compare = [&hits](const auto& a, const auto& b) {
0095
0096
0097 if ((*hits)[a].getLayer() == (*hits)[b].getLayer()) {
0098 return (*hits)[a].getObjectID().index < (*hits)[b].getObjectID().index;
0099 }
0100 return (*hits)[a].getLayer() < (*hits)[b].getLayer();
0101 };
0102
0103
0104 std::set<std::size_t, decltype(compare)> indices(compare);
0105
0106 for (std::size_t i = 0; i < hits->size(); ++i) {
0107 indices.insert(i);
0108 }
0109
0110 if (hits->size() != indices.size()) {
0111 error("equivalent hits were dropped: #hits {:d}, #indices {:d}", hits->size(), indices.size());
0112 }
0113
0114
0115 std::vector<std::list<std::size_t>> groups;
0116
0117
0118
0119
0120
0121 for (auto idx = indices.begin(); idx != indices.end();
0122 indices.empty() ? idx = indices.end() : idx) {
0123
0124 debug("hit {:d}: local position = ({}, {}, {}), global position = ({}, {}, {}), energy = {}",
0125 *idx, (*hits)[*idx].getLocal().x, (*hits)[*idx].getLocal().y,
0126 (*hits)[*idx].getPosition().z, (*hits)[*idx].getPosition().x,
0127 (*hits)[*idx].getPosition().y, (*hits)[*idx].getPosition().z, (*hits)[*idx].getEnergy());
0128
0129
0130 if ((*hits)[*idx].getEnergy() < minClusterCenterEdep) {
0131 idx++;
0132 continue;
0133 }
0134
0135
0136 groups.emplace_back(std::list{*idx});
0137 bfs_group(*hits, indices, groups.back(), *idx);
0138
0139
0140 idx = indices.erase(idx);
0141 }
0142 debug("found {} potential clusters (groups of hits)", groups.size());
0143 for (std::size_t i = 0; i < groups.size(); ++i) {
0144 debug("group {}: {} hits", i, groups[i].size());
0145 }
0146
0147
0148 for (const auto& group : groups) {
0149 if (group.size() < m_cfg.minClusterNhits) {
0150 continue;
0151 }
0152 double energy = 0.;
0153 for (std::size_t idx : group) {
0154 energy += (*hits)[idx].getEnergy();
0155 }
0156 if (energy < minClusterEdep) {
0157 continue;
0158 }
0159 auto pcl = proto->create();
0160 for (std::size_t idx : group) {
0161 pcl.addToHits((*hits)[idx]);
0162 pcl.addToWeights(1);
0163 }
0164 }
0165 }
0166
0167
0168 bool ImagingTopoCluster::is_neighbour(const edm4eic::CalorimeterHit& h1,
0169 const edm4eic::CalorimeterHit& h2) const {
0170
0171 if (h1.getSector() != h2.getSector()) {
0172 return std::hypot((h1.getPosition().x - h2.getPosition().x),
0173 (h1.getPosition().y - h2.getPosition().y),
0174 (h1.getPosition().z - h2.getPosition().z)) <= sectorDist;
0175 }
0176
0177
0178 int ldiff = std::abs(h1.getLayer() - h2.getLayer());
0179
0180 if (ldiff == 0) {
0181 return (std::abs(h1.getLocal().x - h2.getLocal().x) <= localDistXY[0]) &&
0182 (std::abs(h1.getLocal().y - h2.getLocal().y) <= localDistXY[1]);
0183 } else if (ldiff <= m_cfg.neighbourLayersRange) {
0184 switch (m_cfg.layerMode) {
0185 case eicrecon::ImagingTopoClusterConfig::ELayerMode::etaphi:
0186 return (std::abs(edm4hep::utils::eta(h1.getPosition()) -
0187 edm4hep::utils::eta(h2.getPosition())) <= layerDistEtaPhi[0]) &&
0188 (std::abs(edm4hep::utils::angleAzimuthal(h1.getPosition()) -
0189 edm4hep::utils::angleAzimuthal(h2.getPosition())) <= layerDistEtaPhi[1]);
0190 case eicrecon::ImagingTopoClusterConfig::ELayerMode::xy:
0191 return (std::abs(h1.getPosition().x - h2.getPosition().x) <= layerDistXY[0]) &&
0192 (std::abs(h1.getPosition().y - h2.getPosition().y) <= layerDistXY[1]);
0193 }
0194 }
0195
0196 return false;
0197 }
0198
0199 }