File indexing completed on 2026-05-21 07:48:35
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/tools/old/interface.hpp>
0010 #include <boost/test/unit_test.hpp>
0011
0012 #include "Acts/Definitions/Algebra.hpp"
0013 #include "Acts/Geometry/GeometryIdentifier.hpp"
0014 #include "Acts/Seeding/HoughTransformUtils.hpp"
0015 #include "Acts/Utilities/Logger.hpp"
0016
0017 #include <array>
0018 #include <format>
0019 #include <vector>
0020
0021 using namespace Acts;
0022
0023 namespace ActsTests {
0024
0025 auto logger = getDefaultLogger("UnitTests", Logging::VERBOSE);
0026
0027 struct DriftCircle {
0028 double y{0.};
0029 double z{0.};
0030 double rDrift{0.};
0031 double rDriftError{0.};
0032
0033 DriftCircle(const double _y, const double _z, const double _r,
0034 const double _rUncert)
0035 : y{_y}, z{_z}, rDrift{_r}, rDriftError{_rUncert} {}
0036 };
0037
0038 BOOST_AUTO_TEST_SUITE(SeedingSuite)
0039
0040 BOOST_AUTO_TEST_CASE(hough_transform_seeder) {
0041
0042
0043 std::vector<std::pair<double, double>> simHits = {
0044 {-0.0401472 / 0.994974, -422.612}};
0045
0046
0047 constexpr double uncert{0.3};
0048 std::array<DriftCircle, 6> driftCircles{
0049 DriftCircle{-427.981, -225.541, 14.5202, uncert},
0050 DriftCircle{-412.964, -199.53, 1.66237, uncert},
0051 DriftCircle{-427.981, -173.519, 12.3176, uncert},
0052 DriftCircle{-427.981, 173.519, 1.5412, uncert},
0053 DriftCircle{-442.999, 199.53, 12.3937, uncert},
0054 DriftCircle{-427.981, 225.541, 3.77967, uncert}
0055
0056 };
0057
0058
0059 HoughTransformUtils::HoughPlaneConfig planeCfg;
0060 planeCfg.nBinsX = 1000;
0061 planeCfg.nBinsY = 1000;
0062
0063
0064 HoughTransformUtils::PeakFinders::IslandsAroundMaxConfig peakFinderCfg;
0065 peakFinderCfg.fractionCutoff = 0.7;
0066 peakFinderCfg.threshold = 3.;
0067 peakFinderCfg.minSpacingBetweenPeaks = {0., 30.};
0068
0069
0070
0071 HoughTransformUtils::HoughAxisRanges axisRanges{-3., 3., -2000., 2000.};
0072
0073
0074
0075
0076
0077 auto houghParamFromDCleft = [](double tanTheta, const DriftCircle& DC) {
0078 return DC.y - tanTheta * DC.z - DC.rDrift / std::cos(std::atan(tanTheta));
0079 };
0080
0081 auto houghParamFromDCright = [](double tanTheta, const DriftCircle& DC) {
0082 return DC.y - tanTheta * DC.z + DC.rDrift / std::cos(std::atan(tanTheta));
0083 };
0084
0085
0086 auto houghWidthFromDC = [](double, const DriftCircle& DC) {
0087 return std::min(DC.rDriftError * 3.,
0088 1.0);
0089
0090
0091 };
0092
0093
0094 HoughTransformUtils::HoughPlane<GeometryIdentifier::Value> houghPlane(
0095 planeCfg);
0096
0097
0098 HoughTransformUtils::PeakFinders::IslandsAroundMax<GeometryIdentifier::Value>
0099 peakFinder(peakFinderCfg);
0100
0101
0102 for (auto& sh : simHits) {
0103 houghPlane.reset();
0104
0105 for (std::size_t k = 0; k < driftCircles.size(); ++k) {
0106 auto dc = driftCircles[k];
0107
0108 houghPlane.fill<DriftCircle>(dc, axisRanges, houghParamFromDCleft,
0109 houghWidthFromDC, k);
0110 houghPlane.fill<DriftCircle>(dc, axisRanges, houghParamFromDCright,
0111 houghWidthFromDC, k);
0112 }
0113
0114
0115 auto maxima = peakFinder.findPeaks(houghPlane, axisRanges);
0116 for (auto& max : maxima) {
0117
0118 BOOST_CHECK_CLOSE(max.x, sh.first, 4.);
0119 BOOST_CHECK_CLOSE(max.y, sh.second, 0.2);
0120 }
0121 }
0122 }
0123
0124 BOOST_AUTO_TEST_CASE(hough_transform_sliding_window) {
0125
0126
0127
0128
0129
0130
0131 const std::size_t nX = 10;
0132 const std::size_t nY = 10;
0133 HoughTransformUtils::HoughPlaneConfig config{nX, nY};
0134 HoughTransformUtils::HoughPlane<int> plane(config);
0135
0136 auto addTriangular = [&](const std::vector<std::array<std::size_t, 2>>& peaks,
0137 HoughTransformUtils::YieldType peak) {
0138 for (std::size_t x = 0; x < nX; ++x) {
0139 for (std::size_t y = 0; y < nY; ++y) {
0140 HoughTransformUtils::YieldType val = 0.0f;
0141 for (auto [cx, cy] : peaks) {
0142 int dist = (x >= cx ? x - cx : cx - x) +
0143 (y >= cy ? y - cy : cy - y);
0144 val = std::max(
0145 val, peak - static_cast<HoughTransformUtils::YieldType>(dist));
0146 }
0147 plane.fillBin(x, y, x, y, val);
0148 }
0149 }
0150 };
0151
0152
0153 std::vector<std::array<std::size_t, 2>> testPeaks({{4, 4}, {4, 5}, {2, 6}});
0154 addTriangular(testPeaks, 4.0f);
0155
0156
0157 BOOST_CHECK_EQUAL(plane.nHits(4, 4), 4.0f);
0158 BOOST_CHECK_EQUAL(plane.nHits(4, 5), 4.0f);
0159
0160
0161 HoughTransformUtils::PeakFinders::SlidingWindowConfig cfg1{4, 0, 0,
0162 false, 0, 0};
0163 auto peaks1 = slidingWindowPeaks(plane, cfg1);
0164 BOOST_CHECK_EQUAL(peaks1[0][0], 2);
0165 BOOST_CHECK_EQUAL(peaks1[0][1], 6);
0166 BOOST_CHECK_EQUAL(peaks1[1][0], 4);
0167 BOOST_CHECK_EQUAL(peaks1[1][1], 4);
0168 BOOST_CHECK_EQUAL(peaks1[2][0], 4);
0169 BOOST_CHECK_EQUAL(peaks1[2][1], 5);
0170
0171
0172 HoughTransformUtils::PeakFinders::SlidingWindowConfig cfg2{4, 2, 2,
0173 false, 0, 0};
0174 auto peaks2 = slidingWindowPeaks(plane, cfg2);
0175 BOOST_CHECK_EQUAL(peaks2.size(), 1);
0176 BOOST_CHECK_EQUAL(peaks2[0][0], 4);
0177 BOOST_CHECK_EQUAL(peaks2[0][1], 4);
0178
0179
0180 HoughTransformUtils::PeakFinders::SlidingWindowConfig cfg3{4, 2, 2,
0181 true, 2, 2};
0182 auto peaks3 = slidingWindowPeaks(plane, cfg3);
0183 BOOST_CHECK_EQUAL(peaks3.size(), 1);
0184 BOOST_CHECK_EQUAL(peaks3[0][0], 3);
0185 BOOST_CHECK_EQUAL(peaks3[0][1], 5);
0186
0187
0188 plane.reset();
0189 addTriangular({{1, 1}, {5, 5}, {8, 9}}, 4.0f);
0190 peaks3 = slidingWindowPeaks(plane, cfg3);
0191 BOOST_CHECK_EQUAL(peaks3.size(), 1);
0192
0193 {
0194 auto img1 =
0195 HoughTransformUtils::PeakFinders::hitsCountImage(plane, {1, 1}, 4, 4);
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205 std::vector<unsigned char> expected(
0206 {0, 0, 0, 0, 0, 2, 3, 2, 0, 3, 4, 3, 0, 2, 3, 2});
0207 BOOST_CHECK_EQUAL(expected.size(), img1.size());
0208 BOOST_CHECK_EQUAL_COLLECTIONS(img1.begin(), img1.end(), expected.begin(),
0209 expected.end());
0210 }
0211 {
0212
0213 auto maskGetter = [](const HoughTransformUtils::HoughPlane<int>& p, int x,
0214 int y) -> unsigned {
0215 unsigned mask = 0;
0216 for (unsigned l : p.layers(x, y)) {
0217 mask |= 1 << std::min(l, 16u);
0218 std::cout << x << " " << y << " " << l << "\n";
0219 }
0220 return mask;
0221 };
0222
0223 plane.reset();
0224 plane.fillBin(1, 1, 0, 1, 1);
0225 plane.fillBin(1, 1, 1, 2, 1);
0226 plane.fillBin(1, 1, 2, 3, 1);
0227 plane.fillBin(2, 2, 3, 3, 1);
0228
0229 auto img = HoughTransformUtils::PeakFinders::hitsCountImage<int, unsigned>(
0230 plane, {1, 1}, 4, 4, maskGetter);
0231
0232 std::vector<unsigned char> expected({0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0233 1 << 0x1 | 1 << 0x2 | 1 << 0x3, 0, 0,
0234 0, 0, 1 << 0x3});
0235
0236 BOOST_CHECK_EQUAL(expected.size(), img.size());
0237 BOOST_CHECK_EQUAL_COLLECTIONS(img.begin(), img.end(), expected.begin(),
0238 expected.end());
0239 }
0240 }
0241
0242 BOOST_AUTO_TEST_CASE(hough_plane_layers_hits) {
0243
0244
0245
0246 const std::size_t nX = 1;
0247 const std::size_t nY = 1;
0248 HoughTransformUtils::HoughPlaneConfig config{nX, nY};
0249 HoughTransformUtils::HoughPlane<std::uint8_t> plane(config);
0250
0251 std::uint8_t nHits = 0;
0252 static constexpr std::uint8_t nLayers = 10;
0253 for (std::uint8_t layer = 1; layer <= nLayers; ++layer) {
0254
0255 for (std::uint8_t hit = 0; hit < layer; ++hit) {
0256 plane.fillBin(0, 0, nHits++, layer);
0257 }
0258 }
0259
0260 BOOST_CHECK_EQUAL(nLayers, plane.nLayers(0, 0));
0261 BOOST_CHECK_EQUAL(nHits, plane.nHits(0, 0));
0262 }
0263
0264 BOOST_AUTO_TEST_SUITE_END()
0265
0266 }