File indexing completed on 2026-07-16 08:08:48
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/data/test_case.hpp>
0010 #include <boost/test/unit_test.hpp>
0011
0012 #include "Acts/Definitions/Algebra.hpp"
0013 #include "Acts/Definitions/Tolerance.hpp"
0014 #include "Acts/Definitions/Units.hpp"
0015 #include "Acts/Geometry/CylinderPortalShell.hpp"
0016 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0017 #include "Acts/Geometry/GeometryContext.hpp"
0018 #include "Acts/Geometry/NavigationPolicyFactory.hpp"
0019 #include "Acts/Geometry/TrackingVolume.hpp"
0020 #include "Acts/Navigation/CylinderNavigationPolicy.hpp"
0021 #include "Acts/Navigation/INavigationPolicy.hpp"
0022 #include "Acts/Navigation/MultiNavigationPolicy.hpp"
0023 #include "Acts/Navigation/NavigationDelegate.hpp"
0024 #include "Acts/Navigation/NavigationStream.hpp"
0025 #include "Acts/Navigation/TryAllNavigationPolicy.hpp"
0026 #include "Acts/Utilities/Logger.hpp"
0027
0028 #include <boost/algorithm/string/join.hpp>
0029
0030 using namespace Acts;
0031 using namespace Acts::UnitLiterals;
0032 namespace bdata = boost::unit_test::data;
0033
0034 namespace ActsTests {
0035
0036 BOOST_AUTO_TEST_SUITE(NavigationSuite)
0037
0038 auto gctx = GeometryContext::dangerouslyDefaultConstruct();
0039 auto logger = getDefaultLogger("NavigationPolicyTests", Logging::VERBOSE);
0040
0041 struct APolicy : public INavigationPolicy {
0042 APolicy(const GeometryContext& , const TrackingVolume& ,
0043 const Logger& ) {}
0044
0045 void initializeCandidates(const GeometryContext& ,
0046 const NavigationArguments& ,
0047 AppendOnlyNavigationStream& ,
0048 const Logger& ) const {
0049 const_cast<APolicy*>(this)->executed = true;
0050 }
0051
0052 void connect(NavigationDelegate& delegate) const override {
0053 connectDefault<APolicy>(delegate);
0054 }
0055
0056 bool executed = false;
0057 };
0058
0059 struct BPolicy : public INavigationPolicy {
0060 struct Config {
0061 int value;
0062 };
0063
0064 BPolicy(const GeometryContext& , const TrackingVolume& ,
0065 const Logger& , Config config)
0066 : m_config(config) {}
0067
0068 void connect(NavigationDelegate& delegate) const override {
0069 connectDefault<BPolicy>(delegate);
0070 }
0071
0072 void initializeCandidates(const GeometryContext& ,
0073 const NavigationArguments& ,
0074 AppendOnlyNavigationStream& ,
0075 const Logger& ) const {
0076 const_cast<BPolicy*>(this)->executed = true;
0077 const_cast<BPolicy*>(this)->value = m_config.value;
0078 }
0079
0080 bool executed = false;
0081 int value = 0;
0082
0083 Config m_config;
0084 };
0085
0086 BOOST_AUTO_TEST_CASE(DirectTest) {
0087 TrackingVolume volume{
0088 Transform3::Identity(),
0089 std::make_shared<CylinderVolumeBounds>(250_mm, 400_mm, 310_mm),
0090 "PixelLayer3"};
0091
0092 MultiNavigationPolicy policy{
0093 std::make_unique<APolicy>(gctx, volume, *logger),
0094 std::make_unique<BPolicy>(gctx, volume, *logger,
0095 BPolicy::Config{.value = 4242})};
0096
0097 NavigationDelegate delegate;
0098 policy.connect(delegate);
0099
0100 NavigationStream main;
0101 AppendOnlyNavigationStream stream{main};
0102 delegate(gctx,
0103 NavigationArguments{.position = Vector3::Zero(),
0104 .direction = Vector3::Zero()},
0105 stream, *logger);
0106
0107 BOOST_REQUIRE_EQUAL(policy.policies().size(), 2);
0108 const auto& policyA = dynamic_cast<const APolicy&>(*policy.policies()[0]);
0109 const auto& policyB = dynamic_cast<const BPolicy&>(*policy.policies()[1]);
0110
0111 BOOST_CHECK(policyA.executed);
0112 BOOST_CHECK(policyB.executed);
0113 BOOST_CHECK_EQUAL(policyB.value, 4242);
0114 }
0115
0116 BOOST_AUTO_TEST_CASE(FactoryTest) {
0117 TrackingVolume volume{
0118 Transform3::Identity(),
0119 std::make_shared<CylinderVolumeBounds>(250_mm, 400_mm, 310_mm),
0120 "PixelLayer3"};
0121
0122 BPolicy::Config config{.value = 42};
0123
0124 std::function<std::unique_ptr<INavigationPolicy>(
0125 const GeometryContext&, const TrackingVolume&, const Logger&)>
0126 factory = NavigationPolicyFactory{}
0127 .add<APolicy>()
0128 .add<BPolicy>(config);
0129
0130 auto policyBase = factory(gctx, volume, *logger);
0131 auto policyBase2 = factory(gctx, volume, *logger);
0132
0133 auto& policy = dynamic_cast<MultiNavigationPolicy&>(*policyBase);
0134
0135 NavigationDelegate delegate;
0136 policy.connect(delegate);
0137
0138 NavigationStream main;
0139 AppendOnlyNavigationStream stream{main};
0140 delegate(gctx,
0141 NavigationArguments{.position = Vector3::Zero(),
0142 .direction = Vector3::Zero()},
0143 stream, *logger);
0144
0145 BOOST_REQUIRE_EQUAL(policy.policies().size(), 2);
0146 const auto& policyA = dynamic_cast<const APolicy&>(*policy.policies()[0]);
0147 const auto& policyB = dynamic_cast<const BPolicy&>(*policy.policies()[1]);
0148
0149 BOOST_CHECK(policyA.executed);
0150 BOOST_CHECK(policyB.executed);
0151 BOOST_CHECK_EQUAL(policyB.value, 42);
0152
0153 auto& policy2 = dynamic_cast<MultiNavigationPolicy&>(*policyBase2);
0154
0155 NavigationDelegate delegate2;
0156 policyBase2->connect(delegate2);
0157
0158 delegate2(gctx,
0159 NavigationArguments{.position = Vector3::Zero(),
0160 .direction = Vector3::Zero()},
0161 stream, *logger);
0162
0163 BOOST_REQUIRE_EQUAL(policy2.policies().size(), 2);
0164 const auto& policy2A = dynamic_cast<const APolicy&>(*policy2.policies()[0]);
0165 const auto& policy2B = dynamic_cast<const BPolicy&>(*policy2.policies()[1]);
0166
0167 BOOST_CHECK(policy2A.executed);
0168 BOOST_CHECK(policy2B.executed);
0169 BOOST_CHECK_EQUAL(policy2B.value, 42);
0170 }
0171
0172 BOOST_AUTO_TEST_CASE(AsUniquePtrTest) {
0173 TrackingVolume volume{
0174 Transform3::Identity(),
0175 std::make_shared<CylinderVolumeBounds>(250_mm, 400_mm, 310_mm),
0176 "PixelLayer3"};
0177
0178 std::unique_ptr<NavigationPolicyFactory> factory =
0179 NavigationPolicyFactory{}.add<APolicy>().asUniquePtr();
0180
0181 auto policyBase = factory->build(gctx, volume, *logger);
0182 auto& policy = dynamic_cast<MultiNavigationPolicy&>(*policyBase);
0183
0184 NavigationDelegate delegate;
0185 policyBase->connect(delegate);
0186
0187 NavigationStream main;
0188 AppendOnlyNavigationStream stream{main};
0189 delegate(gctx,
0190 NavigationArguments{.position = Vector3::Zero(),
0191 .direction = Vector3::Zero()},
0192 stream, *logger);
0193
0194 BOOST_REQUIRE_EQUAL(policy.policies().size(), 1);
0195 BOOST_CHECK(dynamic_cast<const APolicy&>(*policy.policies()[0]).executed);
0196 }
0197
0198 struct CPolicy : public INavigationPolicy {};
0199
0200 template <typename T>
0201 struct CPolicySpecialized : public CPolicy {
0202 struct Config {
0203 T value;
0204 };
0205
0206 CPolicySpecialized(const TrackingVolume& , Config config)
0207 : m_config(config) {}
0208
0209 void connect(NavigationDelegate& delegate) const override {
0210 connectDefault<CPolicySpecialized<T>>(delegate);
0211 }
0212
0213 void initializeCandidates(const GeometryContext& ,
0214 const NavigationArguments& ,
0215 AppendOnlyNavigationStream& ,
0216 const Logger& ) const {
0217 auto* self = const_cast<CPolicySpecialized<int>*>(this);
0218 self->executed = true;
0219 self->value = m_config.value;
0220 }
0221
0222 bool executed = false;
0223 int value = 0;
0224
0225 Config m_config;
0226 };
0227
0228 struct IsolatedConfig {
0229 int value;
0230 };
0231
0232 auto makeCPolicy(const GeometryContext& , const TrackingVolume& volume,
0233 const Logger& , IsolatedConfig config) {
0234
0235 CPolicySpecialized<int>::Config config2{.value = config.value};
0236 return CPolicySpecialized<int>(volume, config2);
0237 }
0238
0239 BOOST_AUTO_TEST_CASE(IsolatedFactory) {
0240 TrackingVolume volume{
0241 Transform3::Identity(),
0242 std::make_shared<CylinderVolumeBounds>(250_mm, 400_mm, 310_mm),
0243 "PixelLayer3"};
0244
0245 IsolatedConfig config{.value = 44};
0246 auto factory =
0247 NavigationPolicyFactory{}.add<APolicy>().add(makeCPolicy, config);
0248
0249 auto factory2 =
0250 NavigationPolicyFactory{}.add(makeCPolicy, config).add<APolicy>();
0251
0252 auto policyBase = factory(gctx, volume, *logger);
0253 auto& policy = dynamic_cast<MultiNavigationPolicy&>(*policyBase);
0254
0255 NavigationDelegate delegate;
0256 policyBase->connect(delegate);
0257
0258 NavigationStream main;
0259 AppendOnlyNavigationStream stream{main};
0260 delegate(gctx,
0261 NavigationArguments{.position = Vector3::Zero(),
0262 .direction = Vector3::Zero()},
0263 stream, *logger);
0264
0265 BOOST_REQUIRE_EQUAL(policy.policies().size(), 2);
0266
0267 const auto& policyA = dynamic_cast<const APolicy&>(*policy.policies()[0]);
0268 const auto& cPolicy =
0269 dynamic_cast<const CPolicySpecialized<int>&>(*policy.policies()[1]);
0270
0271 BOOST_CHECK(policyA.executed);
0272 BOOST_CHECK(cPolicy.executed);
0273 BOOST_CHECK_EQUAL(cPolicy.value, 44);
0274 }
0275
0276 namespace {
0277
0278 std::vector<const Portal*> getTruth(const Vector3& position,
0279 const Vector3& direction,
0280 const Transform3& transform,
0281 const TrackingVolume& cylVolume,
0282 SingleCylinderPortalShell& shell,
0283 const Logger& logger, bool posOnly = true) {
0284 Vector3 gpos = transform * position;
0285 Vector3 gdir = transform.linear() * direction;
0286 TryAllNavigationPolicy tryAll(gctx, cylVolume, logger);
0287 NavigationArguments args{.position = gpos, .direction = gdir};
0288 NavigationStream main;
0289 AppendOnlyNavigationStream stream{main};
0290 auto gctx = GeometryContext::dangerouslyDefaultConstruct();
0291 tryAll.initializeCandidates(gctx, args, stream, logger);
0292 main.initialize(gctx, {gpos, gdir}, BoundaryTolerance::None());
0293 std::vector<const Portal*> portals;
0294 for (auto& candidate : main.candidates()) {
0295 if (!candidate.intersection().isValid()) {
0296 continue;
0297 }
0298
0299 if (main.candidates().size() > 1 && posOnly &&
0300 !detail::checkPathLength(candidate.intersection().pathLength(),
0301 s_onSurfaceTolerance,
0302 std::numeric_limits<double>::max(), logger)) {
0303 continue;
0304 }
0305
0306 portals.push_back(&candidate.portal());
0307 }
0308
0309
0310 const Portal* outerCylinder = nullptr;
0311 const Portal* innerCylinder = nullptr;
0312 const Portal* positiveDisc = nullptr;
0313 const Portal* negativeDisc = nullptr;
0314
0315 for (const Portal* portal : portals) {
0316 if (portal ==
0317 shell.portal(CylinderVolumeBounds::Face::OuterCylinder).get()) {
0318 outerCylinder = portal;
0319 } else if (portal ==
0320 shell.portal(CylinderVolumeBounds::Face::InnerCylinder).get()) {
0321 innerCylinder = portal;
0322 } else if (portal ==
0323 shell.portal(CylinderVolumeBounds::Face::PositiveDisc).get()) {
0324 positiveDisc = portal;
0325 } else if (portal ==
0326 shell.portal(CylinderVolumeBounds::Face::NegativeDisc).get()) {
0327 negativeDisc = portal;
0328 }
0329 }
0330
0331
0332 std::vector<const Portal*> filteredPortals;
0333
0334
0335
0336 if ((innerCylinder != nullptr) && (outerCylinder != nullptr)) {
0337
0338 filteredPortals.push_back(innerCylinder);
0339 } else {
0340
0341 if (innerCylinder != nullptr) {
0342 filteredPortals.push_back(innerCylinder);
0343 }
0344 if (outerCylinder != nullptr) {
0345 filteredPortals.push_back(outerCylinder);
0346 }
0347 }
0348
0349
0350
0351 if (innerCylinder == nullptr) {
0352
0353 if (positiveDisc != nullptr) {
0354 filteredPortals.push_back(positiveDisc);
0355 }
0356 if (negativeDisc != nullptr) {
0357 filteredPortals.push_back(negativeDisc);
0358 }
0359 }
0360
0361
0362 return filteredPortals;
0363 }
0364
0365 std::vector<const Portal*> getSmart(const Vector3& position,
0366 const Vector3& direction,
0367 const Transform3& transform,
0368 CylinderNavigationPolicy& policy) {
0369 Vector3 gpos = transform * position;
0370 Vector3 gdir = transform.linear() * direction;
0371 NavigationArguments args{.position = gpos, .direction = gdir};
0372 NavigationStream main;
0373 auto gctx = GeometryContext::dangerouslyDefaultConstruct();
0374 AppendOnlyNavigationStream stream{main};
0375 policy.initializeCandidates(gctx, args, stream, *logger);
0376
0377 std::vector<const Portal*> portals;
0378
0379
0380 for (auto& candidate : main.candidates()) {
0381 portals.push_back(&candidate.portal());
0382 }
0383 return portals;
0384 }
0385
0386 void checkEqual(const std::vector<const Portal*>& exp,
0387 const std::vector<const Portal*>& act,
0388 SingleCylinderPortalShell& shell) {
0389 auto which = [&](const Portal* p) -> std::string {
0390 if (p == shell.portal(CylinderVolumeBounds::Face::InnerCylinder).get()) {
0391 return "InnerCylinder";
0392 }
0393 if (p == shell.portal(CylinderVolumeBounds::Face::OuterCylinder).get()) {
0394 return "OuterCylinder";
0395 }
0396 if (p == shell.portal(CylinderVolumeBounds::Face::PositiveDisc).get()) {
0397 return "PositiveDisc";
0398 }
0399 if (p == shell.portal(CylinderVolumeBounds::Face::NegativeDisc).get()) {
0400 return "NegativeDisc";
0401 }
0402 BOOST_FAIL("Unknown portal");
0403 return "";
0404 };
0405
0406 std::set<const Portal*> expSet;
0407 std::set<const Portal*> actSet;
0408
0409 std::ranges::copy(exp, std::inserter(expSet, expSet.begin()));
0410 std::ranges::copy(act, std::inserter(actSet, actSet.begin()));
0411
0412 if (expSet != actSet) {
0413 BOOST_ERROR([&]() -> std::string {
0414 std::vector<std::string> exps;
0415 for (auto& p : exp) {
0416 exps.push_back(which(p));
0417 }
0418 std::vector<std::string> acts;
0419 for (auto& p : act) {
0420 acts.push_back(which(p));
0421 }
0422 return "[" + boost::algorithm::join(exps, ", ") + "] != [" +
0423 boost::algorithm::join(acts, ", ") + "]";
0424 }());
0425 }
0426 }
0427
0428 }
0429
0430 BOOST_DATA_TEST_CASE(
0431 CylinderPolicyTest,
0432 (bdata::xrange(-135, 180, 45) *
0433 bdata::make(Vector3{0_mm, 0_mm, 0_mm}, Vector3{20_mm, 0_mm, 0_mm},
0434 Vector3{0_mm, 20_mm, 0_mm}, Vector3{20_mm, 20_mm, 0_mm},
0435 Vector3{0_mm, 0_mm, 20_mm})),
0436 angle, offset) {
0437 using enum CylinderVolumeBounds::Face;
0438
0439 Transform3 transform = Transform3::Identity();
0440 transform *= AngleAxis3{angle * 1_degree, Vector3::UnitX()};
0441 transform *= Translation3{offset};
0442 auto cylBounds =
0443 std::make_shared<CylinderVolumeBounds>(100_mm, 400_mm, 300_mm);
0444 auto cylVolume =
0445 std::make_shared<TrackingVolume>(transform, cylBounds, "CylinderVolume");
0446 SingleCylinderPortalShell shell{*cylVolume};
0447 shell.applyToVolume();
0448
0449 {
0450 Vector3 position = Vector3::UnitX() * 150_mm;
0451 Vector3 direction = Vector3::UnitZ();
0452
0453 auto exp =
0454 getTruth(position, direction, transform, *cylVolume, shell, *logger);
0455
0456 BOOST_CHECK(exp.size() == 1);
0457 BOOST_CHECK(exp.at(0) == shell.portal(PositiveDisc).get());
0458
0459 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0460 auto act = getSmart(position, direction, transform, policy);
0461 checkEqual(exp, act, shell);
0462 }
0463
0464 {
0465 Vector3 position = Vector3::UnitX() * 150_mm;
0466 Vector3 direction = Vector3{1, 1, 0}.normalized();
0467
0468 auto exp =
0469 getTruth(position, direction, transform, *cylVolume, shell, *logger);
0470
0471 BOOST_CHECK(exp.size() == 1);
0472 BOOST_CHECK(exp.at(0) == shell.portal(OuterCylinder).get());
0473
0474 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0475 auto act = getSmart(position, direction, transform, policy);
0476 checkEqual(exp, act, shell);
0477 }
0478
0479 {
0480 Vector3 position = Vector3::UnitX() * 150_mm;
0481 Vector3 direction = Vector3{-1, 0, 0}.normalized();
0482
0483 auto exp =
0484 getTruth(position, direction, transform, *cylVolume, shell, *logger);
0485
0486 BOOST_CHECK(exp.size() == 1);
0487 BOOST_CHECK(exp.at(0) == shell.portal(InnerCylinder).get());
0488
0489 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0490 auto act = getSmart(position, direction, transform, policy);
0491 checkEqual(exp, act, shell);
0492 }
0493
0494 {
0495 Vector3 position = Vector3::UnitX() * 150_mm;
0496 Vector3 direction = -Vector3::UnitZ();
0497
0498 auto exp =
0499 getTruth(position, direction, transform, *cylVolume, shell, *logger);
0500
0501 BOOST_CHECK(exp.size() == 1);
0502 BOOST_CHECK(exp.at(0) == shell.portal(NegativeDisc).get());
0503
0504 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0505 auto act = getSmart(position, direction, transform, policy);
0506 checkEqual(exp, act, shell);
0507 }
0508
0509 {
0510 Vector3 position{50, -200, 0};
0511 Vector3 direction = Vector3{0, 1.5, 1}.normalized();
0512
0513 auto exp =
0514 getTruth(position, direction, transform, *cylVolume, shell, *logger);
0515
0516 BOOST_CHECK(exp.size() == 1);
0517 BOOST_CHECK(exp.at(0) == shell.portal(InnerCylinder).get());
0518
0519 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0520 auto act = getSmart(position, direction, transform, policy);
0521 checkEqual(exp, act, shell);
0522 }
0523
0524 {
0525 Vector3 position{50, -200, 0};
0526 Vector3 direction = Vector3{0, 1.2, 1}.normalized();
0527
0528 auto exp =
0529 getTruth(position, direction, transform, *cylVolume, shell, *logger);
0530
0531 BOOST_CHECK(exp.size() == 1);
0532 BOOST_CHECK(exp.at(0) == shell.portal(InnerCylinder).get());
0533
0534 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0535 auto act = getSmart(position, direction, transform, policy);
0536 checkEqual(exp, act, shell);
0537 }
0538
0539 {
0540 Vector3 position{50, -200, 0};
0541 Vector3 direction = Vector3{0, 0.9, 1}.normalized();
0542
0543 auto exp =
0544 getTruth(position, direction, transform, *cylVolume, shell, *logger);
0545
0546 BOOST_CHECK(exp.size() == 1);
0547 BOOST_CHECK(exp.at(0) == shell.portal(InnerCylinder).get());
0548
0549 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0550 auto act = getSmart(position, direction, transform, policy);
0551 checkEqual(exp, act, shell);
0552 }
0553
0554 {
0555 Vector3 position{20, -200, 0};
0556 Vector3 direction = Vector3{0.45, 0.9, 1}.normalized();
0557
0558 auto exp =
0559 getTruth(position, direction, transform, *cylVolume, shell, *logger);
0560
0561 BOOST_CHECK(exp.size() == 1);
0562 BOOST_CHECK(exp.at(0) == shell.portal(PositiveDisc).get());
0563
0564 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0565 auto act = getSmart(position, direction, transform, policy);
0566 checkEqual(exp, act, shell);
0567 }
0568
0569 {
0570 Vector3 position{20, -200, 0};
0571 Vector3 direction = Vector3{0.45, 0.9, -1}.normalized();
0572
0573 auto exp =
0574 getTruth(position, direction, transform, *cylVolume, shell, *logger);
0575
0576 BOOST_CHECK(exp.size() == 1);
0577 BOOST_CHECK(exp.at(0) == shell.portal(NegativeDisc).get());
0578
0579 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0580 auto act = getSmart(position, direction, transform, policy);
0581 checkEqual(exp, act, shell);
0582 }
0583
0584 {
0585 Vector3 position{400 * std::cos(std::numbers::pi / 4),
0586 400 * std::sin(std::numbers::pi / 4), 0};
0587 Vector3 direction = Vector3{0.45, -0.9, -0.1}.normalized();
0588
0589
0590
0591 auto exp = getTruth(position, direction, transform, *cylVolume, shell,
0592 *logger, false);
0593
0594 BOOST_CHECK(exp.size() == 1);
0595 BOOST_CHECK(exp.at(0) == shell.portal(OuterCylinder).get());
0596
0597 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0598 auto act = getSmart(position, direction, transform, policy);
0599 checkEqual(exp, act, shell);
0600 }
0601
0602 {
0603 Vector3 position{400 * std::cos(std::numbers::pi / 4),
0604 400 * std::sin(std::numbers::pi / 4), 0};
0605 Vector3 direction = Vector3{-0.3, -0.9, -0.1}.normalized();
0606
0607
0608
0609 auto exp = getTruth(position, direction, transform, *cylVolume, shell,
0610 *logger, false);
0611
0612 BOOST_CHECK(exp.size() == 1);
0613 BOOST_CHECK(exp.at(0) == shell.portal(OuterCylinder).get());
0614
0615 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0616 auto act = getSmart(position, direction, transform, policy);
0617 checkEqual(exp, act, shell);
0618 }
0619
0620 {
0621 Vector3 position{100 * std::cos(std::numbers::pi / 4),
0622 100 * std::sin(std::numbers::pi / 4), 0};
0623 double dangle = 0.1;
0624 Vector3 direction = Vector3{std::cos(dangle), std::sin(dangle), 0.01};
0625
0626
0627 auto exp =
0628 getTruth(position, direction, transform, *cylVolume, shell, *logger);
0629
0630 BOOST_CHECK(exp.size() == 1);
0631 BOOST_CHECK(exp.at(0) == shell.portal(OuterCylinder).get());
0632
0633 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0634 auto act = getSmart(position, direction, transform, policy);
0635 checkEqual(exp, act, shell);
0636 }
0637
0638 {
0639 Vector3 position{200 * std::cos(std::numbers::pi / 4),
0640 200 * std::sin(std::numbers::pi / 4), 0};
0641 Vector3 target{150 * std::cos(std::numbers::pi * 5 / 4),
0642 150 * std::sin(std::numbers::pi * 5 / 4), 300};
0643 Vector3 direction = (target - position).normalized();
0644
0645 auto exp =
0646 getTruth(position, direction, transform, *cylVolume, shell, *logger);
0647
0648 BOOST_CHECK_EQUAL(exp.size(), 1);
0649 BOOST_CHECK_EQUAL(exp.at(0), shell.portal(InnerCylinder).get());
0650
0651 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0652 auto act = getSmart(position, direction, transform, policy);
0653 checkEqual(exp, act, shell);
0654 }
0655 }
0656
0657 namespace {
0658
0659 std::mt19937 engine;
0660
0661 unsigned long seed() {
0662 static unsigned long s = 42;
0663 return s++;
0664 }
0665
0666 std::uniform_real_distribution<double> rDistOffBoundary{
0667 100 + 2 * s_onSurfaceTolerance, 400 - 2 * s_onSurfaceTolerance};
0668 std::uniform_real_distribution<double> zDistOffBoundary{
0669 -300_mm + 2 * s_onSurfaceTolerance, 300_mm - 2 * s_onSurfaceTolerance};
0670 std::uniform_real_distribution<double> phiDist{-std::numbers::pi,
0671 std::numbers::pi};
0672 std::uniform_real_distribution<double> thetaDist{0, std::numbers::pi};
0673
0674 }
0675
0676 BOOST_DATA_TEST_CASE(
0677 CylinderPolicyTestOffBoundary,
0678 bdata::random((bdata::engine = engine, bdata::seed = seed(),
0679 bdata::distribution = rDistOffBoundary)) ^
0680 bdata::random((bdata::engine = engine, bdata::seed = seed(),
0681 bdata::distribution = zDistOffBoundary)) ^
0682 bdata::random((bdata::engine = engine, bdata::seed = seed(),
0683 bdata::distribution = phiDist)) ^
0684 bdata::random((bdata::engine = engine, bdata::seed = seed(),
0685 bdata::distribution = phiDist)) ^
0686 bdata::random((bdata::engine = engine, bdata::seed = seed(),
0687 bdata::distribution = thetaDist)) ^
0688 bdata::xrange(100),
0689 r, z, phiPos, phiDir, theta, index) {
0690 static_cast<void>(index);
0691
0692 Transform3 transform = Transform3::Identity();
0693 auto cylBounds =
0694 std::make_shared<CylinderVolumeBounds>(100_mm, 400_mm, 300_mm);
0695 auto cylVolume =
0696 std::make_shared<TrackingVolume>(transform, cylBounds, "CylinderVolume");
0697 SingleCylinderPortalShell shell{*cylVolume};
0698 shell.applyToVolume();
0699
0700 Vector3 position{r * std::cos(phiPos), r * std::sin(phiPos), z};
0701 Vector3 direction{std::sin(theta) * std::cos(phiDir),
0702 std::sin(theta) * std::sin(phiDir), std::cos(theta)};
0703
0704 BOOST_CHECK(cylBounds->inside(position));
0705
0706 auto exp =
0707 getTruth(position, direction, transform, *cylVolume, shell, *logger);
0708
0709 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0710 auto act = getSmart(position, direction, transform, policy);
0711 checkEqual(exp, act, shell);
0712 }
0713
0714 BOOST_DATA_TEST_CASE(
0715 CylinderPolicyTestOnRBoundary,
0716 bdata::make(100, 400) *
0717 (bdata::random((bdata::engine = engine, bdata::seed = seed(),
0718 bdata::distribution = zDistOffBoundary)) ^
0719 bdata::random((bdata::engine = engine, bdata::seed = seed(),
0720 bdata::distribution = phiDist)) ^
0721 bdata::random((bdata::engine = engine, bdata::seed = seed(),
0722 bdata::distribution = phiDist)) ^
0723 bdata::random((bdata::engine = engine, bdata::seed = seed(),
0724 bdata::distribution = zDistOffBoundary)) ^
0725 bdata::xrange(100)),
0726 r, z, phiPos, phiTarget, zTarget, index) {
0727 static_cast<void>(index);
0728
0729 Transform3 transform = Transform3::Identity();
0730 auto cylBounds =
0731 std::make_shared<CylinderVolumeBounds>(100_mm, 400_mm, 300_mm);
0732 auto cylVolume =
0733 std::make_shared<TrackingVolume>(transform, cylBounds, "CylinderVolume");
0734 SingleCylinderPortalShell shell{*cylVolume};
0735 shell.applyToVolume();
0736
0737 Vector3 position{r * std::cos(phiPos), r * std::sin(phiPos), z};
0738 Vector3 target{r * std::cos(phiTarget), r * std::sin(phiTarget), zTarget};
0739 Vector3 direction = (target - position).normalized();
0740
0741 auto exp =
0742 getTruth(position, direction, transform, *cylVolume, shell, *logger);
0743
0744 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0745 auto act = getSmart(position, direction, transform, policy);
0746 checkEqual(exp, act, shell);
0747 }
0748
0749 BOOST_DATA_TEST_CASE(
0750 CylinderPolicyTestOnZBoundary,
0751 bdata::make(-300, 300) *
0752 (bdata::random((bdata::engine = engine, bdata::seed = seed(),
0753 bdata::distribution = rDistOffBoundary)) ^
0754 bdata::random((bdata::engine = engine, bdata::seed = seed(),
0755 bdata::distribution = phiDist)) ^
0756 bdata::random((bdata::engine = engine, bdata::seed = seed(),
0757 bdata::distribution = phiDist)) ^
0758 bdata::random((bdata::engine = engine, bdata::seed = seed(),
0759 bdata::distribution = zDistOffBoundary)) ^
0760 bdata::xrange(100)),
0761 z, r, phiPos, phiTarget, zTarget, index) {
0762 static_cast<void>(index);
0763 Transform3 transform = Transform3::Identity();
0764 auto cylBounds =
0765 std::make_shared<CylinderVolumeBounds>(100_mm, 400_mm, 300_mm);
0766 auto cylVolume =
0767 std::make_shared<TrackingVolume>(transform, cylBounds, "CylinderVolume");
0768 SingleCylinderPortalShell shell{*cylVolume};
0769 shell.applyToVolume();
0770
0771 Vector3 position{r * std::cos(phiPos), r * std::sin(phiPos),
0772 static_cast<double>(z)};
0773 Vector3 target{r * std::cos(phiTarget), r * std::sin(phiTarget), zTarget};
0774 Vector3 direction = (target - position).normalized();
0775
0776 BOOST_CHECK(cylBounds->inside(position));
0777
0778 auto exp =
0779 getTruth(position, direction, transform, *cylVolume, shell, *logger);
0780
0781 CylinderNavigationPolicy policy(gctx, *cylVolume, *logger);
0782 auto act = getSmart(position, direction, transform, policy);
0783 checkEqual(exp, act, shell);
0784 }
0785
0786 BOOST_AUTO_TEST_CASE(CylinderPolicyZeroInnerRadiusTest) {
0787
0788 Transform3 transform = Transform3::Identity();
0789
0790
0791 auto cylBounds = std::make_shared<CylinderVolumeBounds>(0_mm, 400_mm, 300_mm);
0792 auto cylVolume = std::make_shared<TrackingVolume>(transform, cylBounds,
0793 "ZeroInnerRadiusVolume");
0794
0795
0796
0797 {
0798 Acts::Logging::ScopedFailureThreshold log{Logging::FATAL};
0799 BOOST_CHECK_THROW(CylinderNavigationPolicy(gctx, *cylVolume, *logger),
0800 std::invalid_argument);
0801 }
0802 }
0803
0804 BOOST_AUTO_TEST_SUITE_END()
0805
0806 }