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