File indexing completed on 2025-07-05 08:11:11
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Seeding/HoughTransformUtils.hpp"
0012
0013 #include <algorithm>
0014 #include <tuple>
0015
0016 template <class identifier_t>
0017 template <class PointType>
0018 void Acts::HoughTransformUtils::HoughPlane<identifier_t>::fill(
0019 const PointType& measurement, const HoughAxisRanges& axisRanges,
0020 LineParametrisation<PointType> linePar,
0021 LineParametrisation<PointType> widthPar, const identifier_t& identifier,
0022 unsigned layer, YieldType weight) {
0023
0024 for (std::size_t xBin = 0; xBin < m_cfg.nBinsX; xBin++) {
0025
0026 auto x = binCenter(axisRanges.xMin, axisRanges.xMax, m_cfg.nBinsX, xBin);
0027
0028 CoordType y = linePar(x, measurement);
0029 CoordType dy = widthPar(x, measurement);
0030
0031 int yBinDown =
0032 binIndex(axisRanges.yMin, axisRanges.yMax, m_cfg.nBinsY, y - dy);
0033 int yBinUp =
0034 binIndex(axisRanges.yMin, axisRanges.yMax, m_cfg.nBinsY, y + dy);
0035
0036 for (int yBin = yBinDown; yBin <= yBinUp; ++yBin) {
0037
0038 if (yBin >= static_cast<int>(m_cfg.nBinsY) || yBin < 0) {
0039 continue;
0040 }
0041 fillBin(xBin, yBin, identifier, layer, weight);
0042 }
0043 }
0044 }
0045
0046 template <class identifier_t>
0047 std::span<const identifier_t, std::dynamic_extent>
0048 Acts::HoughTransformUtils::HoughCell<identifier_t>::getHits() const {
0049 std::span<const identifier_t, std::dynamic_extent> hits(m_hits.begin(),
0050 m_iHit);
0051 return hits;
0052 }
0053
0054 template <class identifier_t>
0055 std::span<const unsigned, std::dynamic_extent>
0056 Acts::HoughTransformUtils::HoughCell<identifier_t>::getLayers() const {
0057 std::span<const unsigned, std::dynamic_extent> layers(m_layers.begin(),
0058 m_iLayer);
0059
0060 return layers;
0061 }
0062
0063 template <class identifier_t>
0064 void Acts::HoughTransformUtils::HoughCell<identifier_t>::fill(
0065 const identifier_t& identifier, unsigned layer, YieldType weight) {
0066
0067
0068 if (m_iHit != 0 && m_hits[m_iHit - 1] == identifier) {
0069 return;
0070 }
0071
0072 if (m_iHit == m_hits.size()) {
0073 m_hits.resize(m_hits.size() + m_assignBatch);
0074 }
0075
0076 if (m_iLayer == m_layers.size()) {
0077 m_layers.resize(m_layers.size() + m_assignBatch);
0078 }
0079
0080 m_hits[m_iHit] = identifier;
0081 m_layers[m_iLayer] = layer;
0082
0083 m_iHit += 1;
0084 m_iLayer += 1;
0085
0086 m_nHits += weight;
0087 m_nLayers += weight;
0088 }
0089
0090 template <class identifier_t>
0091 void Acts::HoughTransformUtils::HoughCell<identifier_t>::reset() {
0092 m_nHits = 0;
0093 m_nLayers = 0;
0094
0095 m_iLayer = 0;
0096 m_iHit = 0;
0097 }
0098
0099 template <class identifier_t>
0100 Acts::HoughTransformUtils::HoughPlane<identifier_t>::HoughPlane(
0101 const HoughPlaneConfig& cfg)
0102 : m_cfg(cfg),
0103 m_houghHist(Axis(0, m_cfg.nBinsX, m_cfg.nBinsX),
0104 Axis(0, m_cfg.nBinsY, m_cfg.nBinsY)) {
0105
0106
0107
0108 }
0109 template <class identifier_t>
0110 void Acts::HoughTransformUtils::HoughPlane<identifier_t>::fillBin(
0111 std::size_t binX, std::size_t binY, const identifier_t& identifier,
0112 unsigned layer, double w) {
0113
0114
0115 m_touchedBins.insert(globalBin({binX, binY}));
0116
0117
0118 m_houghHist.atLocalBins({binX, binY}).fill(identifier, layer, w);
0119
0120 YieldType layers = nLayers(binX, binY);
0121 YieldType hits = nHits(binX, binY);
0122 if (layers > m_maxLayers) {
0123 m_maxLayers = layers;
0124 m_maxLocLayers = {binX, binY};
0125 }
0126 if (hits > m_maxHits) {
0127 m_maxHits = hits;
0128 m_maxLocHits = {binX, binY};
0129 }
0130 }
0131
0132 template <class identifier_t>
0133 void Acts::HoughTransformUtils::HoughPlane<identifier_t>::reset() {
0134
0135
0136 for (auto bin : getNonEmptyBins()) {
0137 m_houghHist.at(bin).reset();
0138 }
0139
0140 m_maxHits = 0.;
0141 m_maxLayers = 0.;
0142
0143 m_iBin = 0;
0144 m_touchedBins.clear();
0145 }
0146
0147 template <class identifier_t>
0148 Acts::HoughTransformUtils::PeakFinders::LayerGuidedCombinatoric<identifier_t>::
0149 LayerGuidedCombinatoric(const LayerGuidedCombinatoricConfig& cfg)
0150 : m_cfg(cfg) {}
0151
0152 template <class identifier_t>
0153 std::vector<typename Acts::HoughTransformUtils::PeakFinders::
0154 LayerGuidedCombinatoric<identifier_t>::Maximum>
0155 Acts::HoughTransformUtils::PeakFinders::LayerGuidedCombinatoric<
0156 identifier_t>::findPeaks(const HoughPlane<identifier_t>& plane) const {
0157
0158 std::vector<PeakFinders::LayerGuidedCombinatoric<identifier_t>::Maximum>
0159 maxima;
0160
0161 for (auto nbin : plane.getNonEmptyBins()) {
0162
0163
0164 std::array<std::size_t, 2> xy = plane.axisBins(nbin);
0165
0166 if (passThreshold(plane, xy[0], xy[1])) {
0167
0168 Maximum max;
0169 max.hitIdentifiers = plane.hitIds(xy[0], xy[1]);
0170 maxima.push_back(max);
0171 }
0172 }
0173 return maxima;
0174 }
0175
0176 template <class identifier_t>
0177 bool Acts::HoughTransformUtils::PeakFinders::LayerGuidedCombinatoric<
0178 identifier_t>::passThreshold(const HoughPlane<identifier_t>& plane,
0179 std::size_t xBin, std::size_t yBin) const {
0180
0181 if (plane.nLayers(xBin, yBin) < m_cfg.threshold) {
0182 return false;
0183 }
0184
0185 if (m_cfg.localMaxWindowSize == 0) {
0186 return true;
0187 }
0188
0189
0190
0191 for (int dXbin = -m_cfg.localMaxWindowSize; dXbin <= m_cfg.localMaxWindowSize;
0192 dXbin++) {
0193 for (int dYbin = -m_cfg.localMaxWindowSize;
0194 dYbin <= m_cfg.localMaxWindowSize; dYbin++) {
0195
0196 if (dYbin == 0 && dXbin == 0) {
0197 continue;
0198 }
0199
0200 if (static_cast<int>(xBin) + dXbin < 0 ||
0201 static_cast<int>(yBin) + dYbin < 0) {
0202 continue;
0203 }
0204 if (xBin + dXbin >= plane.nBinsX() || yBin + dYbin >= plane.nBinsY()) {
0205 continue;
0206 }
0207
0208 if (plane.nLayers(xBin + dXbin, yBin + dYbin) >
0209 plane.nLayers(xBin, yBin)) {
0210 return false;
0211 }
0212
0213 if (plane.nLayers(xBin + dXbin, yBin + dYbin) <
0214 plane.nLayers(xBin, yBin)) {
0215 continue;
0216 }
0217
0218
0219
0220
0221
0222 if (plane.nHits(xBin + dXbin, yBin + dYbin) > plane.nHits(xBin, yBin)) {
0223 return false;
0224 }
0225
0226
0227 if (plane.nHits(xBin + dXbin, yBin + dYbin) == plane.nHits(xBin, yBin) &&
0228 (dYbin < 0 || (dYbin == 0 && dXbin < 0))) {
0229 return false;
0230 }
0231 }
0232 }
0233 return true;
0234 }
0235 template <class identifier_t>
0236 Acts::HoughTransformUtils::PeakFinders::IslandsAroundMax<
0237 identifier_t>::IslandsAroundMax(const IslandsAroundMaxConfig& cfg)
0238 : m_cfg(cfg) {}
0239
0240 template <class identifier_t>
0241 std::vector<typename Acts::HoughTransformUtils::PeakFinders::IslandsAroundMax<
0242 identifier_t>::Maximum>
0243 Acts::HoughTransformUtils::PeakFinders::IslandsAroundMax<
0244 identifier_t>::findPeaks(const HoughPlane<identifier_t>& plane,
0245 const HoughAxisRanges& ranges) {
0246
0247 YieldType max = plane.maxHits();
0248
0249 YieldType min = std::max(m_cfg.threshold, m_cfg.fractionCutoff * max);
0250
0251 const std::unordered_set<std::size_t>& nonEmptyBins{plane.getNonEmptyBins()};
0252 std::vector<std::size_t> candidates;
0253 candidates.reserve(nonEmptyBins.size());
0254 std::vector<Maximum> maxima;
0255 maxima.reserve(nonEmptyBins.size());
0256
0257 std::unordered_map<std::size_t, YieldType> yieldMap;
0258
0259
0260 for (const std::size_t nbin : nonEmptyBins) {
0261
0262
0263
0264
0265 if (plane.nHits(nbin) > min) {
0266 candidates.push_back(nbin);
0267 yieldMap[nbin] = plane.nHits(nbin);
0268 }
0269 }
0270
0271 std::ranges::sort(candidates, std::greater{}, [&yieldMap](std::size_t c) {
0272 return std::make_tuple(yieldMap[c], c);
0273 });
0274
0275
0276
0277 std::vector<std::size_t> toExplore;
0278 std::vector<std::array<std::size_t, 2>> solution;
0279
0280
0281 for (auto& cand : candidates) {
0282
0283
0284 if (yieldMap[cand] < min) {
0285 continue;
0286 }
0287
0288 std::array<std::size_t, 2> xy = plane.axisBins(cand);
0289
0290 CoordType xCand =
0291 binCenter(ranges.xMin, ranges.xMax, plane.nBinsX(), xy[0]);
0292 CoordType yCand =
0293 binCenter(ranges.yMin, ranges.yMax, plane.nBinsY(), xy[1]);
0294
0295 bool goodSpacing = true;
0296 for (auto& found : maxima) {
0297 if (std::abs(xCand - found.x) < m_cfg.minSpacingBetweenPeaks.first ||
0298 std::abs(yCand - found.y) < m_cfg.minSpacingBetweenPeaks.second) {
0299 goodSpacing = false;
0300 break;
0301 }
0302 }
0303 if (!goodSpacing) {
0304 continue;
0305 }
0306
0307 toExplore.clear();
0308 solution.clear();
0309
0310
0311 toExplore.push_back(cand);
0312
0313 while (!toExplore.empty()) {
0314 extendMaximum(plane, solution, toExplore, min, yieldMap);
0315 }
0316
0317 if (solution.empty()) {
0318 continue;
0319 }
0320
0321 Maximum maximum;
0322 CoordType max_x = 0;
0323 CoordType max_y = 0;
0324 CoordType pos_den = 0;
0325 CoordType ymax = -std::numeric_limits<CoordType>::max();
0326 CoordType ymin = std::numeric_limits<CoordType>::max();
0327 CoordType xmax = -std::numeric_limits<CoordType>::max();
0328 CoordType xmin = std::numeric_limits<CoordType>::max();
0329
0330
0331
0332 for (auto& [xBin, yBin] : solution) {
0333 auto hidIds = plane.hitIds(xBin, yBin);
0334 maximum.hitIdentifiers.insert(std::make_move_iterator(hidIds.begin()),
0335 std::make_move_iterator(hidIds.end()));
0336 CoordType xHit =
0337 binCenter(ranges.xMin, ranges.xMax, plane.nBinsX(), xBin);
0338 CoordType yHit =
0339 binCenter(ranges.yMin, ranges.yMax, plane.nBinsY(), yBin);
0340 YieldType nHits = plane.nHits(xBin, yBin);
0341 max_x += xHit * nHits;
0342 max_y += yHit * nHits;
0343 pos_den += nHits;
0344 if (xHit > xmax) {
0345 xmax = xHit;
0346 }
0347 if (yHit > ymax) {
0348 ymax = yHit;
0349 }
0350 if (xHit < xmin) {
0351 xmin = xHit;
0352 }
0353 if (yHit < ymin) {
0354 ymin = yHit;
0355 }
0356 }
0357
0358 maximum.x = max_x / pos_den;
0359 maximum.y = max_y / pos_den;
0360
0361 maximum.wx = 0.5 * (xmax - xmin);
0362 maximum.wy = 0.5 * (ymax - ymin);
0363 maxima.push_back(maximum);
0364 }
0365 return maxima;
0366 }
0367
0368 template <class identifier_t>
0369 void Acts::HoughTransformUtils::PeakFinders::IslandsAroundMax<identifier_t>::
0370 extendMaximum(
0371 const Acts::HoughTransformUtils::HoughPlane<identifier_t>& houghPlane,
0372 std::vector<std::array<std::size_t, 2>>& inMaximum,
0373 std::vector<std::size_t>& toExplore, YieldType threshold,
0374 std::unordered_map<std::size_t, YieldType>& yieldMap) {
0375
0376
0377
0378 const std::size_t candidate = toExplore.back();
0379 YieldType& yield{yieldMap[candidate]};
0380 toExplore.pop_back();
0381
0382 if (yield < threshold) {
0383 return;
0384 }
0385
0386 auto nextCand = houghPlane.axisBins(candidate);
0387
0388 inMaximum.push_back(nextCand);
0389
0390 yieldMap[candidate] = -1.0f;
0391
0392
0393
0394 for (auto step : m_stepDirections) {
0395 std::array<unsigned long, 2> newCandxy = {nextCand[0] + step.first,
0396 nextCand[1] + step.second};
0397
0398 if (newCandxy[0] >= houghPlane.nBinsX() ||
0399 newCandxy[1] >= houghPlane.nBinsY()) {
0400 continue;
0401 }
0402 std::size_t newCand = houghPlane.globalBin({newCandxy[0], newCandxy[1]});
0403
0404
0405
0406 if (yieldMap[newCand] > threshold) {
0407 toExplore.push_back(newCand);
0408 }
0409 }
0410 }