File indexing completed on 2026-06-27 07:42:30
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Digitization/ModuleClusters.hpp"
0010
0011 #include "Acts/Clusterization/Clusterization.hpp"
0012 #include "Acts/Definitions/TrackParametrization.hpp"
0013 #include "Acts/Utilities/Helpers.hpp"
0014 #include "ActsExamples/Digitization/MeasurementCreation.hpp"
0015 #include "ActsExamples/EventData/SimHit.hpp"
0016
0017 #include <array>
0018 #include <cmath>
0019 #include <cstdlib>
0020 #include <limits>
0021 #include <map>
0022 #include <stdexcept>
0023
0024 namespace ActsExamples {
0025
0026 void ModuleClusters::add(DigitizedParameters params, SimHitIndex simhit) {
0027 ModuleValue mval;
0028 mval.paramIndices = std::move(params.indices);
0029 mval.paramValues = std::move(params.values);
0030 mval.paramVariances = std::move(params.variances);
0031 mval.sources = {simhit};
0032
0033 if (m_merge && !params.cluster.channels.empty()) {
0034
0035 for (const auto& cell : params.cluster.channels) {
0036 ModuleValue mval_cell = mval;
0037 mval_cell.value = cell;
0038 m_moduleValues.push_back(std::move(mval_cell));
0039 }
0040 } else {
0041
0042 mval.value = std::move(params.cluster);
0043 m_moduleValues.push_back(std::move(mval));
0044 }
0045 }
0046
0047 std::vector<std::pair<DigitizedParameters, std::set<SimHitIndex>>>
0048 ModuleClusters::digitizedParameters() {
0049 if (m_merge) {
0050 merge();
0051 }
0052 std::vector<std::pair<DigitizedParameters, std::set<SimHitIndex>>> retv;
0053 for (ModuleValue& mval : m_moduleValues) {
0054 if (std::holds_alternative<Cluster::Cell>(mval.value)) {
0055
0056
0057
0058 throw std::runtime_error("Invalid cluster!");
0059 }
0060 DigitizedParameters dpars;
0061 dpars.indices = mval.paramIndices;
0062 dpars.values = mval.paramValues;
0063 dpars.variances = mval.paramVariances;
0064 dpars.cluster = std::get<Cluster>(mval.value);
0065 retv.emplace_back(std::move(dpars), mval.sources);
0066 }
0067 return retv;
0068 }
0069
0070
0071 int getCellRow(const ModuleValue& mval) {
0072 if (std::holds_alternative<Cluster::Cell>(mval.value)) {
0073 return std::get<Cluster::Cell>(mval.value).bin[0];
0074 }
0075 throw std::domain_error("ModuleValue does not contain cell!");
0076 }
0077
0078 int getCellColumn(const ModuleValue& mval) {
0079 if (std::holds_alternative<Cluster::Cell>(mval.value)) {
0080 return std::get<Cluster::Cell>(mval.value).bin[1];
0081 }
0082 throw std::domain_error("ModuleValue does not contain cell!");
0083 }
0084
0085 void clusterAddCell(std::vector<ModuleValue>& cl, const ModuleValue& ce) {
0086 cl.push_back(ce);
0087 }
0088
0089 std::vector<ModuleValue> ModuleClusters::createCellCollection() const {
0090 std::map<ActsFatras::Segmentizer::Bin2D, ModuleValue> uniqueCells;
0091 for (const ModuleValue& mval : m_moduleValues) {
0092 if (!std::holds_alternative<Cluster::Cell>(mval.value)) {
0093 continue;
0094 }
0095 const auto& cell = std::get<Cluster::Cell>(mval.value).bin;
0096
0097 if (const auto it = uniqueCells.find(cell); it != uniqueCells.end()) {
0098
0099 std::get<Cluster::Cell>(it->second.value).activation +=
0100 std::get<Cluster::Cell>(mval.value).activation;
0101 } else {
0102
0103 uniqueCells[cell] = mval;
0104 }
0105 }
0106 std::vector<ModuleValue> cells;
0107 cells.reserve(uniqueCells.size());
0108 for (const auto& [_, mval] : uniqueCells) {
0109 cells.push_back(mval);
0110 }
0111 return cells;
0112 }
0113
0114 void ModuleClusters::merge() {
0115 std::vector<ModuleValue> cells = createCellCollection();
0116
0117 std::vector<ModuleValue> newVals;
0118
0119 if (!cells.empty()) {
0120
0121 Acts::Ccl::ClusteringData data;
0122 std::vector<std::vector<ModuleValue>> merged;
0123 Acts::Ccl::createClusters<std::vector<ModuleValue>,
0124 std::vector<std::vector<ModuleValue>>>(
0125 data, cells, merged,
0126 Acts::Ccl::DefaultConnect<ModuleValue>(m_commonCorner));
0127
0128 for (std::vector<ModuleValue>& cellv : merged) {
0129
0130
0131
0132
0133
0134
0135 for (std::vector<ModuleValue>& remerged : mergeParameters(cellv)) {
0136 newVals.push_back(squash(remerged));
0137 }
0138 }
0139 m_moduleValues = std::move(newVals);
0140 } else {
0141
0142 for (std::vector<ModuleValue>& merged : mergeParameters(m_moduleValues)) {
0143 newVals.push_back(squash(merged));
0144 }
0145 m_moduleValues = std::move(newVals);
0146 }
0147 }
0148
0149
0150 std::vector<std::size_t> ModuleClusters::nonGeoEntries(
0151 std::vector<Acts::BoundIndices>& indices) const {
0152 std::vector<std::size_t> retv;
0153 for (std::size_t i = 0; i < indices.size(); i++) {
0154 auto idx = indices.at(i);
0155 if (!rangeContainsValue(m_geoIndices, idx)) {
0156 retv.push_back(i);
0157 }
0158 }
0159 return retv;
0160 }
0161
0162
0163 std::vector<std::vector<ModuleValue>> ModuleClusters::mergeParameters(
0164 std::vector<ModuleValue> values) const {
0165 std::vector<std::vector<ModuleValue>> retv;
0166
0167 std::vector<bool> used(values.size(), false);
0168 for (std::size_t i = 0; i < values.size(); i++) {
0169 if (used.at(i)) {
0170 continue;
0171 }
0172
0173 retv.emplace_back();
0174 std::vector<ModuleValue>& thisvec = retv.back();
0175
0176
0177 thisvec.push_back(std::move(values.at(i)));
0178 used.at(i) = true;
0179
0180
0181
0182
0183 for (std::size_t j = i + 1; j < values.size(); j++) {
0184
0185 if (used.at(j)) {
0186 continue;
0187 }
0188
0189
0190
0191
0192
0193 bool matched = true;
0194
0195
0196
0197
0198 for (ModuleValue& thisval : thisvec) {
0199
0200 for (auto k : nonGeoEntries(thisval.paramIndices)) {
0201 double p_i = thisval.paramValues.at(k);
0202 double p_j = values.at(j).paramValues.at(k);
0203 double v_i = thisval.paramVariances.at(k);
0204 double v_j = values.at(j).paramVariances.at(k);
0205
0206 double left = 0, right = 0;
0207 if (p_i < p_j) {
0208 left = p_i + m_nsigma * std::sqrt(v_i);
0209 right = p_j - m_nsigma * std::sqrt(v_j);
0210 } else {
0211 left = p_j + m_nsigma * std::sqrt(v_j);
0212 right = p_i - m_nsigma * std::sqrt(v_i);
0213 }
0214 if (left < right) {
0215
0216
0217 matched = false;
0218 break;
0219 }
0220 }
0221 if (matched) {
0222
0223
0224
0225 break;
0226 }
0227 }
0228 if (matched) {
0229
0230 used.at(j) = true;
0231 thisvec.push_back(std::move(values.at(j)));
0232 }
0233 }
0234 }
0235 return retv;
0236 }
0237
0238 ModuleValue ModuleClusters::squash(std::vector<ModuleValue>& values) const {
0239 if (values.empty()) {
0240 throw std::runtime_error("Cannot squash empty cluster!");
0241 }
0242
0243 ModuleValue result;
0244
0245 double tot = 0;
0246 double tot2 = 0;
0247 std::vector<double> weights;
0248
0249
0250 for (const ModuleValue& other : values) {
0251 if (std::holds_alternative<Cluster::Cell>(other.value)) {
0252 weights.push_back(std::get<Cluster::Cell>(other.value).activation);
0253 } else {
0254 weights.push_back(1);
0255 }
0256 tot += weights.back();
0257 tot2 += weights.back() * weights.back();
0258 }
0259
0260
0261
0262
0263
0264 Cluster cluster;
0265
0266 const auto& binningData = m_segmentation.binningData();
0267 Acts::Vector2 pos(0., 0.);
0268 Acts::Vector2 var(0., 0.);
0269
0270 std::size_t b0min = std::numeric_limits<std::size_t>::max();
0271 std::size_t b0max = 0;
0272 std::size_t b1min = std::numeric_limits<std::size_t>::max();
0273 std::size_t b1max = 0;
0274
0275 for (std::size_t i = 0; i < values.size(); i++) {
0276 const ModuleValue& other = values.at(i);
0277 if (!std::holds_alternative<Cluster::Cell>(other.value)) {
0278 continue;
0279 }
0280
0281 Cluster::Cell ch = std::get<Cluster::Cell>(other.value);
0282 const auto bin = ch.bin;
0283
0284 const std::size_t b0 = bin[0];
0285 const std::size_t b1 = bin[1];
0286
0287 b0min = std::min(b0min, b0);
0288 b0max = std::max(b0max, b0);
0289 b1min = std::min(b1min, b1);
0290 b1max = std::max(b1max, b1);
0291
0292 const float p0 = binningData[0].center(b0);
0293 const float w0 = binningData[0].width(b0);
0294 const float p1 = binningData[1].center(b1);
0295 const float w1 = binningData[1].width(b1);
0296
0297 pos += Acts::Vector2(weights.at(i) * p0, weights.at(i) * p1);
0298
0299
0300
0301 var += Acts::Vector2(weights.at(i) * weights.at(i) * w0 * w0 / 12,
0302 weights.at(i) * weights.at(i) * w1 * w1 / 12);
0303
0304 cluster.channels.push_back(std::move(ch));
0305
0306
0307
0308 cluster.sizeLoc0 = b0max - b0min + 1;
0309 cluster.sizeLoc1 = b1max - b1min + 1;
0310 }
0311
0312 if (!m_geoIndices.empty() && cluster.channels.empty()) {
0313 throw std::runtime_error(
0314 "Expected to have at least one cell for a cluster with geo indices!");
0315 }
0316
0317 if (tot > 0) {
0318 pos /= tot;
0319 var /= tot * tot;
0320 }
0321
0322 for (const Acts::BoundIndices idx : m_geoIndices) {
0323 result.paramIndices.push_back(idx);
0324 result.paramValues.push_back(pos[idx]);
0325 result.paramVariances.push_back(var[idx]);
0326 }
0327
0328
0329
0330
0331
0332 for (std::size_t i = 0; i < values.size(); i++) {
0333 const ModuleValue& other = values.at(i);
0334 for (std::size_t j = 0; j < other.paramIndices.size(); j++) {
0335 const Acts::BoundIndices idx = other.paramIndices.at(j);
0336 if (!rangeContainsValue(m_geoIndices, idx)) {
0337 if (!rangeContainsValue(result.paramIndices, idx)) {
0338 result.paramIndices.push_back(idx);
0339 }
0340 if (result.paramValues.size() < j + 1) {
0341 result.paramValues.push_back(0);
0342 result.paramVariances.push_back(0);
0343 }
0344 double f = weights.at(i) / (tot > 0 ? tot : 1);
0345 double f2 = weights.at(i) * weights.at(i) / (tot2 > 0 ? tot2 : 1);
0346 result.paramValues.at(j) += f * other.paramValues.at(j);
0347 result.paramVariances.at(j) += f2 * other.paramVariances.at(j);
0348 }
0349 }
0350 }
0351
0352 result.value = std::move(cluster);
0353
0354
0355 for (ModuleValue& other : values) {
0356 result.sources.merge(other.sources);
0357 }
0358
0359 return result;
0360 }
0361
0362 }