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