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