File indexing completed on 2026-09-30 08:04:28
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Geometry/Blueprint.hpp"
0012 #include "Acts/Geometry/ContainerBlueprintNode.hpp"
0013 #include "Acts/Surfaces/BoundaryTolerance.hpp"
0014 #include "Acts/Surfaces/CylinderBounds.hpp"
0015 #include "Acts/Surfaces/CylinderSurface.hpp"
0016 #include "Acts/Surfaces/PerigeeSurface.hpp"
0017
0018 #include <algorithm>
0019
0020 #include "NavigatorTelescope.hpp"
0021
0022 using namespace Acts;
0023 using namespace Acts::UnitLiterals;
0024 using namespace ActsTests::NavigatorTelescope;
0025
0026 namespace ActsTests {
0027
0028
0029
0030 namespace {
0031
0032
0033 bool isSubsequence(const std::vector<const Surface*>& sub,
0034 const std::vector<const Surface*>& full) {
0035 auto itr = full.begin();
0036 for (const Surface* surface : sub) {
0037 itr = std::find(itr, full.end(), surface);
0038 if (itr == full.end()) {
0039 return false;
0040 }
0041 ++itr;
0042 }
0043 return true;
0044 }
0045
0046 }
0047
0048 BOOST_AUTO_TEST_SUITE(NavigatorAdditionalSurface)
0049
0050
0051
0052 BOOST_AUTO_TEST_CASE(OffPathGen1) {
0053 ACTS_LOCAL_LOGGER(getDefaultLogger("Gen1", logLevel));
0054 Telescope telescope = makeTelescopeGen1();
0055 Navigator navigator = makeNavigator(telescope.geometry, logger());
0056
0057 auto additional = makeOutOfGeometrySurface({0, surfaceY, 0.25_m});
0058
0059 Navigator::Options options(gctx);
0060 options.registerAdditionalSurface(*additional);
0061 NavigationTarget target = firstTarget(navigator, options, Vector3::Zero());
0062
0063 BOOST_REQUIRE(!target.isNone());
0064 BOOST_CHECK_EQUAL(&target.surface(), additional.get());
0065 }
0066
0067 BOOST_AUTO_TEST_CASE(OffPathGen3) {
0068 ACTS_LOCAL_LOGGER(getDefaultLogger("Gen3", logLevel));
0069 Telescope telescope = makeTelescopeGen3(logger());
0070 Navigator navigator = makeNavigator(telescope.geometry, logger());
0071
0072 auto additional = makeOutOfGeometrySurface({0, surfaceY, 0.25_m});
0073
0074 Navigator::Options options(gctx);
0075 options.registerAdditionalSurface(*additional);
0076 NavigationTarget target = firstTarget(navigator, options, Vector3::Zero());
0077
0078 BOOST_REQUIRE(!target.isNone());
0079 BOOST_CHECK_EQUAL(&target.surface(), additional.get());
0080 }
0081
0082 BOOST_AUTO_TEST_CASE(BoundsCheckedGen1) {
0083 ACTS_LOCAL_LOGGER(getDefaultLogger("Gen1", logLevel));
0084 Telescope telescope = makeTelescopeGen1();
0085 Navigator navigator = makeNavigator(telescope.geometry, logger());
0086
0087 auto additional = makeOutOfGeometrySurface({0, surfaceY, 0.25_m});
0088
0089 Navigator::Options options(gctx);
0090 options.registerAdditionalSurface(*additional, BoundaryTolerance::None());
0091 std::vector<const Surface*> reached =
0092 walk(navigator, options, Vector3::Zero(), Vector3::UnitZ());
0093
0094 BOOST_CHECK_EQUAL(std::ranges::count(reached, additional.get()), 0);
0095 }
0096
0097 BOOST_AUTO_TEST_CASE(BoundsCheckedGen3) {
0098 ACTS_LOCAL_LOGGER(getDefaultLogger("Gen3", logLevel));
0099 Telescope telescope = makeTelescopeGen3(logger());
0100 Navigator navigator = makeNavigator(telescope.geometry, logger());
0101
0102 auto additional = makeOutOfGeometrySurface({0, surfaceY, 0.25_m});
0103
0104 Navigator::Options options(gctx);
0105 options.registerAdditionalSurface(*additional, BoundaryTolerance::None());
0106 std::vector<const Surface*> reached =
0107 walk(navigator, options, Vector3::Zero(), Vector3::UnitZ());
0108
0109 BOOST_CHECK_EQUAL(std::ranges::count(reached, additional.get()), 0);
0110 }
0111
0112
0113
0114 BOOST_AUTO_TEST_CASE(NothingOfTheGeometryIsSkippedGen1) {
0115 ACTS_LOCAL_LOGGER(getDefaultLogger("Gen1", logLevel));
0116 Telescope telescope = makeTelescopeGen1();
0117 Navigator navigator = makeNavigator(telescope.geometry, logger());
0118
0119
0120 auto additional = makeOutOfGeometrySurface({0, 0, 0.25_m});
0121
0122 Navigator::Options plain(gctx);
0123 std::vector<const Surface*> baseline =
0124 walk(navigator, plain, Vector3::Zero(), Vector3::UnitZ(), 20);
0125
0126 Navigator::Options options(gctx);
0127 options.registerAdditionalSurface(*additional);
0128 std::vector<const Surface*> reached =
0129 walk(navigator, options, Vector3::Zero(), Vector3::UnitZ(), 20);
0130
0131 BOOST_REQUIRE(!baseline.empty());
0132 BOOST_CHECK_EQUAL(std::ranges::count(reached, additional.get()), 1);
0133 BOOST_CHECK(isSubsequence(baseline, reached));
0134 }
0135
0136 BOOST_AUTO_TEST_CASE(NothingOfTheGeometryIsSkippedGen3) {
0137 ACTS_LOCAL_LOGGER(getDefaultLogger("Gen3", logLevel));
0138 Telescope telescope = makeTelescopeGen3(logger());
0139 Navigator navigator = makeNavigator(telescope.geometry, logger());
0140
0141 auto additional = makeOutOfGeometrySurface({0, 0, 0.25_m});
0142
0143 Navigator::Options plain(gctx);
0144 std::vector<const Surface*> baseline =
0145 walk(navigator, plain, Vector3::Zero(), Vector3::UnitZ(), 20);
0146
0147 Navigator::Options options(gctx);
0148 options.registerAdditionalSurface(*additional);
0149 std::vector<const Surface*> reached =
0150 walk(navigator, options, Vector3::Zero(), Vector3::UnitZ(), 20);
0151
0152 BOOST_REQUIRE(!baseline.empty());
0153 BOOST_CHECK_EQUAL(std::ranges::count(reached, additional.get()), 1);
0154 BOOST_CHECK(isSubsequence(baseline, reached));
0155 }
0156
0157
0158
0159 BOOST_AUTO_TEST_CASE(PortalWinsGen1) {
0160 ACTS_LOCAL_LOGGER(getDefaultLogger("Gen1", logLevel));
0161 Telescope telescope = makeTelescopeGen1();
0162 Navigator navigator = makeNavigator(telescope.geometry, logger());
0163
0164 auto outside = makeOutOfGeometrySurface({0, 0, 0.96_m}, 10_m, 10_m);
0165
0166 Navigator::Options options(gctx);
0167 options.registerAdditionalSurface(*outside);
0168 std::vector<const Surface*> reached =
0169 walk(navigator, options, Vector3::Zero(), Vector3::UnitZ(), 20);
0170
0171 auto boundary = std::ranges::find_if(reached, [](const Surface* sf) {
0172 return sf->geometryId().boundary() != 0;
0173 });
0174 BOOST_REQUIRE(boundary != reached.end());
0175 BOOST_CHECK_EQUAL(std::count(reached.begin(), boundary, outside.get()), 0);
0176 }
0177
0178
0179 BOOST_AUTO_TEST_CASE(PortalWinsGen3) {
0180 ACTS_LOCAL_LOGGER(getDefaultLogger("Gen3", logLevel));
0181 Telescope telescope = makeTelescopeGen3(logger());
0182 Navigator navigator = makeNavigator(telescope.geometry, logger());
0183
0184 auto outside = makeOutOfGeometrySurface({0, 0, 0.96_m}, 10_m, 10_m);
0185
0186 Navigator::Options options(gctx);
0187 options.registerAdditionalSurface(*outside);
0188 std::vector<const Surface*> reached =
0189 walk(navigator, options, Vector3::Zero(), Vector3::UnitZ(), 20);
0190
0191 auto itr = std::ranges::find(reached, outside.get());
0192 BOOST_REQUIRE(itr != reached.end());
0193 BOOST_CHECK_EQUAL(std::ranges::count(reached, outside.get()), 1);
0194
0195 BOOST_CHECK(std::ranges::any_of(reached.begin(), itr, [](const Surface* sf) {
0196 return sf->geometryId().boundary() != 0;
0197 }));
0198 }
0199
0200
0201 BOOST_AUTO_TEST_CASE(PerigeeGen3) {
0202 ACTS_LOCAL_LOGGER(getDefaultLogger("Gen3", logLevel));
0203 Telescope telescope = makeTelescopeGen3(logger());
0204 Navigator navigator = makeNavigator(telescope.geometry, logger());
0205
0206 auto perigee = Surface::makeShared<PerigeeSurface>(Vector3{0.1_m, 0, 0.25_m});
0207
0208 Navigator::Options options(gctx);
0209 options.registerAdditionalSurface(*perigee);
0210 const Vector3 dir = Vector3{0.3, 0, 1}.normalized();
0211 std::vector<const Surface*> reached =
0212 walk(navigator, options, Vector3::Zero(), dir);
0213
0214 BOOST_CHECK_EQUAL(std::ranges::count(reached, perigee.get()), 1);
0215 }
0216
0217
0218
0219
0220 namespace {
0221
0222 NavigationTarget targetOnSecondApproach(const Navigator& navigator,
0223 const Navigator::Options& options,
0224 const Surface& additional) {
0225 Navigator::State state = navigator.makeState(options);
0226 Vector3 position = Vector3::Zero();
0227 const Vector3 direction = Vector3::UnitZ();
0228 BOOST_REQUIRE(
0229 navigator
0230 .initialize(state, {.position = position, .direction = direction})
0231 .ok());
0232
0233 NavigationTarget target = navigator.nextTarget(state, position, direction);
0234 BOOST_REQUIRE(!target.isNone());
0235 BOOST_REQUIRE_EQUAL(&target.surface(), &additional);
0236 stepOnto(position, direction, target.surface());
0237 navigator.handleSurfaceReached(state, position, direction, target.surface());
0238
0239
0240 position -= 1_mm * direction;
0241 return navigator.nextTarget(state, position, direction);
0242 }
0243 }
0244
0245 BOOST_AUTO_TEST_CASE(DroppedAfterReachedGen1) {
0246 ACTS_LOCAL_LOGGER(getDefaultLogger("Gen1", logLevel));
0247 Telescope telescope = makeTelescopeGen1();
0248 Navigator navigator = makeNavigator(telescope.geometry, logger());
0249
0250 auto additional = makeOutOfGeometrySurface({0, 0, 0.25_m});
0251
0252 Navigator::Options options(gctx);
0253 options.registerAdditionalSurface(*additional);
0254 NavigationTarget target =
0255 targetOnSecondApproach(navigator, options, *additional);
0256
0257 BOOST_CHECK_NE(&target.surface(), additional.get());
0258 }
0259
0260 BOOST_AUTO_TEST_CASE(KeptAfterReachedGen1) {
0261 ACTS_LOCAL_LOGGER(getDefaultLogger("Gen1", logLevel));
0262 Telescope telescope = makeTelescopeGen1();
0263 Navigator navigator = makeNavigator(telescope.geometry, logger());
0264
0265 auto additional = makeOutOfGeometrySurface({0, 0, 0.25_m});
0266
0267 Navigator::Options options(gctx);
0268 options.registerAdditionalSurface(*additional, BoundaryTolerance::Infinite(),
0269 nullptr, false);
0270 NavigationTarget target =
0271 targetOnSecondApproach(navigator, options, *additional);
0272
0273 BOOST_REQUIRE(!target.isNone());
0274 BOOST_CHECK_EQUAL(&target.surface(), additional.get());
0275 }
0276
0277
0278
0279 BOOST_AUTO_TEST_CASE(ScopedToAVolumeGen3) {
0280 auto logger = getDefaultLogger("Gen3", logLevel);
0281
0282 Blueprint::Config cfg;
0283 cfg.envelope = ExtentEnvelope{{
0284 .x = {20_mm, 20_mm},
0285 .y = {20_mm, 20_mm},
0286 .z = {20_mm, 20_mm},
0287 }};
0288 Blueprint root{cfg};
0289
0290 root.addCuboidContainer("Stack", AxisDirection::AxisZ, [&](auto& stack) {
0291 stack.addChild(
0292 std::make_shared<StaticBlueprintNode>(std::make_unique<TrackingVolume>(
0293 Transform3{Translation3{Vector3{0, 0, -0.5_m}}},
0294 std::make_shared<CuboidVolumeBounds>(0.5_m, 0.5_m, 0.5_m),
0295 "near")));
0296 stack.addChild(
0297 std::make_shared<StaticBlueprintNode>(std::make_unique<TrackingVolume>(
0298 Transform3{Translation3{Vector3{0, 0, 0.5_m}}},
0299 std::make_shared<CuboidVolumeBounds>(0.5_m, 0.5_m, 0.5_m), "far")));
0300 });
0301
0302 auto geometry = std::shared_ptr<const TrackingGeometry>(
0303 root.construct({}, gctx, *logger));
0304 Navigator navigator = makeNavigator(geometry, *logger);
0305
0306
0307 auto additional = makeOutOfGeometrySurface({0, 0, -0.5_m});
0308 const TrackingVolume* farVolume = geometry->findVolumeByName("far");
0309 BOOST_REQUIRE(farVolume != nullptr);
0310
0311 const Vector3 start{0, 0, -0.9_m};
0312
0313
0314 {
0315 Navigator::Options options(gctx);
0316 options.registerAdditionalSurface(*additional,
0317 BoundaryTolerance::Infinite(), farVolume);
0318 std::vector<const Surface*> reached =
0319 walk(navigator, options, start, Vector3::UnitZ(), 12);
0320 BOOST_CHECK_EQUAL(std::ranges::count(reached, additional.get()), 0);
0321 }
0322
0323 {
0324 Navigator::Options options(gctx);
0325 options.registerAdditionalSurface(*additional);
0326 std::vector<const Surface*> reached =
0327 walk(navigator, options, start, Vector3::UnitZ(), 12);
0328 BOOST_CHECK_EQUAL(std::ranges::count(reached, additional.get()), 1);
0329 }
0330 }
0331
0332
0333
0334 BOOST_AUTO_TEST_CASE(SeveralSurfacesInOrderGen3) {
0335 ACTS_LOCAL_LOGGER(getDefaultLogger("Gen3", logLevel));
0336 Telescope telescope = makeTelescopeGen3(logger());
0337 Navigator navigator = makeNavigator(telescope.geometry, logger());
0338
0339 auto first = makeOutOfGeometrySurface({0, 0, 0.1_m});
0340 auto second = makeOutOfGeometrySurface({0, 0, 0.2_m});
0341 auto third = makeOutOfGeometrySurface({0, 0, 0.3_m});
0342
0343 Navigator::Options options(gctx);
0344 options.registerAdditionalSurface(*third);
0345 options.registerAdditionalSurface(*first);
0346 options.registerAdditionalSurface(*second);
0347
0348 std::vector<const Surface*> reached =
0349 walk(navigator, options, Vector3::Zero(), Vector3::UnitZ(), 20);
0350
0351 std::vector<const Surface*> reachedAdditional;
0352 for (const Surface* surface : reached) {
0353 if (surface == first.get() || surface == second.get() ||
0354 surface == third.get()) {
0355 reachedAdditional.push_back(surface);
0356 }
0357 }
0358 const std::vector<const Surface*> expected{first.get(), second.get(),
0359 third.get()};
0360 BOOST_CHECK(reachedAdditional == expected);
0361 }
0362
0363
0364
0365 BOOST_AUTO_TEST_CASE(SecondSolutionAheadGen1) {
0366 ACTS_LOCAL_LOGGER(getDefaultLogger("Gen1", logLevel));
0367 Telescope telescope = makeTelescopeGen1();
0368 Navigator navigator = makeNavigator(telescope.geometry, logger());
0369
0370
0371 constexpr double radius = 0.3_m;
0372 auto additional = Surface::makeShared<CylinderSurface>(
0373 Transform3{AngleAxis3{90._degree, Vector3::UnitX()}},
0374 std::make_shared<const CylinderBounds>(radius, 0.5_m));
0375
0376 Navigator::Options options(gctx);
0377 options.registerAdditionalSurface(*additional);
0378
0379 NavigationTarget target =
0380 firstTarget(navigator, options, {0, 0, -0.2 * radius});
0381
0382 BOOST_REQUIRE(!target.isNone());
0383 BOOST_CHECK_EQUAL(&target.surface(), additional.get());
0384 BOOST_CHECK_GT(target.pathLength(), 0.);
0385 }
0386
0387 BOOST_AUTO_TEST_SUITE_END()
0388
0389 }