Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /acts/Tests/UnitTests/Core/Navigation/DetectorNavigatorTests.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/Direction.hpp"
0013 #include "Acts/Definitions/Units.hpp"
0014 #include "Acts/Detector/Detector.hpp"
0015 #include "Acts/Detector/DetectorVolume.hpp"
0016 #include "Acts/Detector/GeometryIdGenerator.hpp"
0017 #include "Acts/Detector/PortalGenerators.hpp"
0018 #include "Acts/Detector/detail/CuboidalDetectorHelper.hpp"
0019 #include "Acts/EventData/TrackParameters.hpp"
0020 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0021 #include "Acts/Geometry/GeometryContext.hpp"
0022 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0023 #include "Acts/Navigation/DetectorNavigator.hpp"
0024 #include "Acts/Navigation/DetectorVolumeFinders.hpp"
0025 #include "Acts/Navigation/InternalNavigation.hpp"
0026 #include "Acts/Propagator/ActorList.hpp"
0027 #include "Acts/Propagator/Propagator.hpp"
0028 #include "Acts/Propagator/StraightLineStepper.hpp"
0029 #include "Acts/Surfaces/CylinderSurface.hpp"
0030 #include "Acts/Surfaces/PlaneSurface.hpp"
0031 #include "Acts/Surfaces/RectangleBounds.hpp"
0032 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0033 #include "Acts/Utilities/Logger.hpp"
0034 
0035 using namespace Acts::UnitLiterals;
0036 
0037 namespace Acts {
0038 class Surface;
0039 }  // namespace Acts
0040 
0041 Acts::GeometryContext geoContext;
0042 Acts::MagneticFieldContext mfContext;
0043 
0044 /// A simple action to record the navigation state
0045 struct StateRecorder {
0046   using result_type = std::vector<Acts::Experimental::DetectorNavigator::State>;
0047 
0048   template <typename propagator_state_t, typename stepper_t,
0049             typename navigator_t>
0050   void act(propagator_state_t& state, const stepper_t& /*stepper*/,
0051            const navigator_t& /*navigator*/, result_type& result,
0052            const Acts::Logger& /*logger*/) const {
0053     result.push_back(state.navigation);
0054   }
0055 };
0056 
0057 BOOST_AUTO_TEST_SUITE(DetectorNavigator)
0058 
0059 // Initialization tests
0060 BOOST_AUTO_TEST_CASE(DetectorNavigatorTestsInitialization) {
0061   auto bounds = std::make_unique<Acts::CuboidVolumeBounds>(3, 3, 3);
0062   auto volume = Acts::Experimental::DetectorVolumeFactory::construct(
0063       Acts::Experimental::defaultPortalAndSubPortalGenerator(), geoContext,
0064       "volume", Acts::Transform3::Identity(), std::move(bounds), {}, {},
0065       Acts::Experimental::tryNoVolumes(),
0066       Acts::Experimental::tryAllPortalsAndSurfaces());
0067   volume->assignGeometryId(Acts::GeometryIdentifier(1));
0068   auto detector = Acts::Experimental::Detector::makeShared(
0069       "detector", {volume}, Acts::Experimental::tryRootVolumes());
0070 
0071   using Stepper = Acts::StraightLineStepper;
0072   using Navigator = Acts::Experimental::DetectorNavigator;
0073   using Propagator = Acts::Propagator<Stepper, Navigator>;
0074   using ActorList = Acts::ActorList<>;
0075   using PropagatorOptions = Propagator::Options<ActorList>;
0076 
0077   PropagatorOptions options(geoContext, mfContext);
0078 
0079   Stepper stepper;
0080 
0081   Acts::Vector4 pos(-2, 0, 0, 0);
0082   Acts::BoundTrackParameters start =
0083       Acts::BoundTrackParameters::createCurvilinear(
0084           pos, 0_degree, 90_degree, 1_e / 1_GeV, std::nullopt,
0085           Acts::ParticleHypothesis::electron());
0086 
0087   //
0088   // (1) Test for inactivity
0089   //
0090   // Run without anything present
0091   {
0092     Navigator::Config navCfg;
0093     navCfg.resolveSensitive = false;
0094     navCfg.resolveMaterial = false;
0095     navCfg.resolvePassive = false;
0096 
0097     Navigator navigator(navCfg);
0098 
0099     Propagator propagator(stepper, navigator);
0100 
0101     auto state = propagator.makeState(options);
0102 
0103     BOOST_CHECK_THROW(propagator.initialize(state, start).value(),
0104                       std::invalid_argument);
0105   }
0106 
0107   // Run with geometry but without resolving
0108   {
0109     Acts::Experimental::DetectorNavigator::Config navCfg;
0110     navCfg.resolveSensitive = false;
0111     navCfg.resolveMaterial = false;
0112     navCfg.resolvePassive = false;
0113     navCfg.detector = detector.get();
0114 
0115     Acts::Experimental::DetectorNavigator navigator(navCfg);
0116 
0117     Acts::Propagator<Acts::StraightLineStepper,
0118                      Acts::Experimental::DetectorNavigator>
0119         propagator(stepper, navigator);
0120 
0121     auto state = propagator.makeState(options);
0122 
0123     stepper.initialize(state.stepping, start);
0124 
0125     BOOST_CHECK(navigator
0126                     .initialize(state.navigation,
0127                                 stepper.position(state.stepping),
0128                                 stepper.direction(state.stepping),
0129                                 state.options.direction)
0130                     .ok());
0131 
0132     navigator.nextTarget(state.navigation, stepper.position(state.stepping),
0133                          stepper.direction(state.stepping));
0134     auto preStepState = state.navigation;
0135     BOOST_CHECK_EQUAL(preStepState.currentSurface, nullptr);
0136     BOOST_CHECK_EQUAL(preStepState.currentPortal, nullptr);
0137   }
0138 
0139   //
0140   // (2) Initialization tests
0141   //
0142   // Run from endOfWorld
0143   {
0144     Acts::Vector4 posEoW(-20, 0, 0, 0);
0145     Acts::BoundTrackParameters startEoW =
0146         Acts::BoundTrackParameters::createCurvilinear(
0147             posEoW, 0_degree, 90_degree, 1_e / 1_GeV, std::nullopt,
0148             Acts::ParticleHypothesis::electron());
0149 
0150     Acts::Experimental::DetectorNavigator::Config navCfg;
0151     navCfg.detector = detector.get();
0152 
0153     Acts::Experimental::DetectorNavigator navigator(navCfg);
0154 
0155     Acts::Propagator<Acts::StraightLineStepper,
0156                      Acts::Experimental::DetectorNavigator>
0157         propagator(stepper, navigator);
0158 
0159     auto state = propagator.makeState(options);
0160 
0161     BOOST_CHECK_THROW(propagator.initialize(state, startEoW).value(),
0162                       std::invalid_argument);
0163   }
0164 
0165   // Initialize properly
0166   {
0167     Acts::Experimental::DetectorNavigator::Config navCfg;
0168     navCfg.detector = detector.get();
0169 
0170     Acts::Experimental::DetectorNavigator navigator(navCfg);
0171 
0172     Acts::Propagator<Acts::StraightLineStepper,
0173                      Acts::Experimental::DetectorNavigator>
0174         propagator(stepper, navigator);
0175 
0176     auto state = propagator.makeState(options);
0177 
0178     stepper.initialize(state.stepping, start);
0179 
0180     BOOST_CHECK(navigator
0181                     .initialize(state.navigation,
0182                                 stepper.position(state.stepping),
0183                                 stepper.direction(state.stepping),
0184                                 state.options.direction)
0185                     .ok());
0186 
0187     auto initState = state.navigation;
0188     BOOST_CHECK_EQUAL(initState.currentDetector, detector.get());
0189     BOOST_CHECK_EQUAL(
0190         initState.currentVolume,
0191         detector->findDetectorVolume(geoContext, start.position(geoContext)));
0192     BOOST_CHECK_EQUAL(initState.currentSurface, nullptr);
0193     BOOST_CHECK_EQUAL(initState.currentPortal, nullptr);
0194     BOOST_CHECK_EQUAL(initState.surfaceCandidates.size(), 1u);
0195   }
0196 }
0197 
0198 // Stadard forward and backward propagation
0199 // through cubic volumes with planar surfaces
0200 // and no surprises
0201 BOOST_AUTO_TEST_CASE(DetectorNavigatorTestsForwardBackward) {
0202   // Construct a cubic detector with 3 volumes
0203   Acts::RotationMatrix3 rotation;
0204   double angle = 90_degree;
0205   Acts::Vector3 xPos(cos(angle), 0., sin(angle));
0206   Acts::Vector3 yPos(0., 1., 0.);
0207   Acts::Vector3 zPos(-sin(angle), 0., cos(angle));
0208   rotation.col(0) = xPos;
0209   rotation.col(1) = yPos;
0210   rotation.col(2) = zPos;
0211 
0212   auto bounds1 = std::make_unique<Acts::CuboidVolumeBounds>(3, 3, 3);
0213   auto transform1 = Acts::Transform3::Identity();
0214   auto surface1 = Acts::Surface::makeShared<Acts::PlaneSurface>(
0215       transform1 * Acts::Transform3(rotation),
0216       std::make_shared<Acts::RectangleBounds>(2, 2));
0217   auto volume1 = Acts::Experimental::DetectorVolumeFactory::construct(
0218       Acts::Experimental::defaultPortalAndSubPortalGenerator(), geoContext,
0219       "volume1", transform1, std::move(bounds1), {surface1}, {},
0220       Acts::Experimental::tryNoVolumes(),
0221       Acts::Experimental::tryAllPortalsAndSurfaces());
0222 
0223   auto bounds2 = std::make_unique<Acts::CuboidVolumeBounds>(3, 3, 3);
0224   auto transform2 =
0225       Acts::Transform3::Identity() * Acts::Translation3(Acts::Vector3(6, 0, 0));
0226   auto surface2 = Acts::Surface::makeShared<Acts::PlaneSurface>(
0227       transform2 * Acts::Transform3(rotation),
0228       std::make_shared<Acts::RectangleBounds>(2, 2));
0229   auto volume2 = Acts::Experimental::DetectorVolumeFactory::construct(
0230       Acts::Experimental::defaultPortalAndSubPortalGenerator(), geoContext,
0231       "volume2", transform2, std::move(bounds2), {surface2}, {},
0232       Acts::Experimental::tryNoVolumes(),
0233       Acts::Experimental::tryAllPortalsAndSurfaces());
0234 
0235   auto bounds3 = std::make_unique<Acts::CuboidVolumeBounds>(3, 3, 3);
0236   auto transform3 = Acts::Transform3::Identity() *
0237                     Acts::Translation3(Acts::Vector3(12, 0, 0));
0238   auto surface3 = Acts::Surface::makeShared<Acts::PlaneSurface>(
0239       transform3 * Acts::Transform3(rotation),
0240       std::make_shared<Acts::RectangleBounds>(2, 2));
0241   auto volume3 = Acts::Experimental::DetectorVolumeFactory::construct(
0242       Acts::Experimental::defaultPortalAndSubPortalGenerator(), geoContext,
0243       "volume3", transform3, std::move(bounds3), {surface3}, {},
0244       Acts::Experimental::tryNoVolumes(),
0245       Acts::Experimental::tryAllPortalsAndSurfaces());
0246 
0247   std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>>
0248       detectorVolumes = {volume1, volume2, volume3};
0249 
0250   auto portalContainer =
0251       Acts::Experimental::detail::CuboidalDetectorHelper::connect(
0252           geoContext, detectorVolumes, Acts::AxisDirection::AxisX, {},
0253           Acts::Logging::VERBOSE);
0254 
0255   // Make sure that the geometry ids are
0256   // independent of the potential Id generation
0257   // changes
0258   int id = 1;
0259 
0260   // Volume ids: 1-3
0261   for (auto& volume : detectorVolumes) {
0262     volume->assignGeometryId(Acts::GeometryIdentifier(id));
0263     id++;
0264   }
0265   // Intervolume portal ids: 6,7,10,11
0266   for (auto& volume : detectorVolumes) {
0267     for (auto& port : volume->portalPtrs()) {
0268       if (port->surface().geometryId() == Acts::GeometryIdentifier(0)) {
0269         port->surface().assignGeometryId(Acts::GeometryIdentifier(id));
0270         id++;
0271       }
0272     }
0273   }
0274   // Surface ids: 12-14
0275   for (auto& surf : {surface1, surface2, surface3}) {
0276     surf->assignGeometryId(Acts::GeometryIdentifier(id));
0277     id++;
0278   }
0279 
0280   auto detector = Acts::Experimental::Detector::makeShared(
0281       "cubicDetector", detectorVolumes, Acts::Experimental::tryRootVolumes());
0282 
0283   using Stepper = Acts::StraightLineStepper;
0284   using Navigator = Acts::Experimental::DetectorNavigator;
0285   using Propagator = Acts::Propagator<Stepper, Navigator>;
0286   using ActorList = Acts::ActorList<StateRecorder, Acts::EndOfWorldReached>;
0287   using PropagatorOptions = Propagator::Options<ActorList>;
0288 
0289   Navigator::Config navCfg;
0290   navCfg.detector = detector.get();
0291 
0292   Stepper stepper;
0293 
0294   Navigator navigator(navCfg,
0295                       Acts::getDefaultLogger("DetectorNavigator",
0296                                              Acts::Logging::Level::VERBOSE));
0297 
0298   PropagatorOptions options(geoContext, mfContext);
0299   options.direction = Acts::Direction::Forward();
0300 
0301   Propagator propagator(
0302       stepper, navigator,
0303       Acts::getDefaultLogger("Propagator", Acts::Logging::Level::VERBOSE));
0304 
0305   // Forward and backward propagation
0306   // should be consistent between each other
0307   Acts::Vector4 posFwd(-2, 0, 0, 0);
0308   Acts::BoundTrackParameters startFwd =
0309       Acts::BoundTrackParameters::createCurvilinear(
0310           posFwd, 0_degree, 90_degree, 1_e / 1_GeV, std::nullopt,
0311           Acts::ParticleHypothesis::electron());
0312 
0313   auto resultFwd = propagator.propagate(startFwd, options).value();
0314   auto statesFwd = resultFwd.get<StateRecorder::result_type>();
0315 
0316   options.direction = Acts::Direction::Backward();
0317 
0318   Acts::Vector4 posBwd(14, 0, 0, 0);
0319   Acts::BoundTrackParameters startBwd =
0320       Acts::BoundTrackParameters::createCurvilinear(
0321           posBwd, 0_degree, 90_degree, 1_e / 1_GeV, std::nullopt,
0322           Acts::ParticleHypothesis::electron());
0323 
0324   auto resultBwd = propagator.propagate(startBwd, options).value();
0325   auto statesBwd = resultBwd.get<StateRecorder::result_type>();
0326 
0327   // 7 steps to reach the end of world
0328   // + 1 recording in the post-step
0329   // + 1 recording before the stepping loop
0330   BOOST_CHECK_EQUAL(statesFwd.size(), 8u);
0331   BOOST_CHECK_EQUAL(statesFwd.size(), statesBwd.size());
0332   BOOST_CHECK_EQUAL(statesFwd[0].surfaceCandidates.size(), 2u);
0333   BOOST_CHECK_EQUAL(statesBwd[0].surfaceCandidates.size(), 2u);
0334 
0335   // Action list call before the first step
0336   // Starting in the volume1
0337   BOOST_CHECK_EQUAL(statesFwd[0].currentVolume->geometryId(),
0338                     Acts::GeometryIdentifier(1));
0339   BOOST_CHECK_EQUAL(statesFwd[0].currentSurface, nullptr);
0340   BOOST_CHECK_EQUAL(statesFwd[0].currentPortal, nullptr);
0341 
0342   // Step to the surface inside volume1
0343   BOOST_CHECK_EQUAL(statesFwd[1].currentVolume->geometryId(),
0344                     Acts::GeometryIdentifier(1));
0345   BOOST_CHECK_EQUAL(statesFwd[1].currentSurface->geometryId(),
0346                     Acts::GeometryIdentifier(12));
0347   BOOST_CHECK_EQUAL(statesFwd[1].currentPortal, nullptr);
0348 
0349   // Step to the volume1|volume2 boundary (portal has witched volume id)
0350   BOOST_CHECK_EQUAL(statesFwd[2].currentVolume->geometryId(),
0351                     Acts::GeometryIdentifier(2));
0352   BOOST_CHECK_EQUAL(statesFwd[2].currentSurface,
0353                     &(statesFwd[2].currentPortal->surface()));
0354   BOOST_CHECK_EQUAL(statesFwd[2].currentPortal->surface().geometryId(),
0355                     Acts::GeometryIdentifier(7));
0356 
0357   // Step to the surface inside volume2
0358   BOOST_CHECK_EQUAL(statesFwd[3].currentVolume->geometryId(),
0359                     Acts::GeometryIdentifier(2));
0360   BOOST_CHECK_EQUAL(statesFwd[3].currentSurface->geometryId(),
0361                     Acts::GeometryIdentifier(13));
0362   BOOST_CHECK_EQUAL(statesFwd[3].currentPortal, nullptr);
0363 
0364   // Step to the volume2|volume3 boundary - volume has switched
0365   BOOST_CHECK_EQUAL(statesFwd[4].currentVolume->geometryId(),
0366                     Acts::GeometryIdentifier(3));
0367   BOOST_CHECK_EQUAL(statesFwd[4].currentSurface,
0368                     &(statesFwd[4].currentPortal->surface()));
0369   BOOST_CHECK_EQUAL(statesFwd[4].currentPortal->surface().geometryId(),
0370                     Acts::GeometryIdentifier(10));
0371 
0372   // Step to the surface inside volume3
0373   BOOST_CHECK_EQUAL(statesFwd[5].currentVolume->geometryId(),
0374                     Acts::GeometryIdentifier(3));
0375   BOOST_CHECK_EQUAL(statesFwd[5].currentSurface->geometryId(),
0376                     Acts::GeometryIdentifier(14));
0377   BOOST_CHECK_EQUAL(statesFwd[5].currentPortal, nullptr);
0378 
0379   // Step to the volume3|endOfWorld boundary
0380   BOOST_CHECK_EQUAL(statesFwd[6].currentVolume, nullptr);
0381   BOOST_CHECK_EQUAL(statesFwd[6].currentSurface,
0382                     &(statesFwd[6].currentPortal->surface()));
0383   BOOST_CHECK_EQUAL(statesFwd[6].currentPortal->surface().geometryId(),
0384                     Acts::GeometryIdentifier(11));
0385 
0386   // Step to the end of world
0387   BOOST_CHECK(navigator.endOfWorldReached(statesFwd[7]));
0388   BOOST_CHECK(navigator.endOfWorldReached(statesBwd[7]));
0389 
0390   // Action list call before the first step
0391   // Starting in the volume3
0392   BOOST_CHECK_EQUAL(statesBwd[6].currentVolume, nullptr);
0393   BOOST_CHECK_EQUAL(statesBwd[6].currentSurface,
0394                     &(statesBwd[6].currentPortal->surface()));
0395   BOOST_CHECK_EQUAL(statesBwd[6].currentPortal->surface().geometryId(),
0396                     Acts::GeometryIdentifier(6));
0397 
0398   // Step to the surface inside volume1
0399   BOOST_CHECK_EQUAL(statesBwd[5].currentVolume->geometryId(),
0400                     Acts::GeometryIdentifier(1));
0401   BOOST_CHECK_EQUAL(statesBwd[5].currentSurface->geometryId(),
0402                     Acts::GeometryIdentifier(12));
0403   BOOST_CHECK_EQUAL(statesBwd[5].currentPortal, nullptr);
0404 
0405   // Step to the volume1|volume2 boundary / preStep not yet set
0406   BOOST_CHECK_EQUAL(statesBwd[4].currentVolume->geometryId(),
0407                     Acts::GeometryIdentifier(1));
0408   BOOST_CHECK_EQUAL(statesBwd[4].currentSurface,
0409                     &(statesBwd[4].currentPortal->surface()));
0410   BOOST_CHECK_EQUAL(statesBwd[4].currentPortal->surface().geometryId(),
0411                     Acts::GeometryIdentifier(7));
0412 
0413   // Step to the surface inside volume2
0414   BOOST_CHECK_EQUAL(statesBwd[3].currentVolume->geometryId(),
0415                     Acts::GeometryIdentifier(2));
0416   BOOST_CHECK_EQUAL(statesBwd[3].currentSurface->geometryId(),
0417                     Acts::GeometryIdentifier(13));
0418   BOOST_CHECK_EQUAL(statesBwd[3].currentPortal, nullptr);
0419 
0420   // Step to the volume2|volume3 boundary / pre-step not yet set
0421   BOOST_CHECK_EQUAL(statesBwd[2].currentVolume->geometryId(),
0422                     Acts::GeometryIdentifier(2));
0423   BOOST_CHECK_EQUAL(statesBwd[2].currentSurface,
0424                     &(statesBwd[2].currentPortal->surface()));
0425   BOOST_CHECK_EQUAL(statesBwd[2].currentPortal->surface().geometryId(),
0426                     Acts::GeometryIdentifier(10));
0427   BOOST_CHECK_EQUAL(statesBwd[2].surfaceCandidates.size(), 2u);
0428 
0429   // Step to the surface inside volume3
0430   BOOST_CHECK_EQUAL(statesBwd[1].currentVolume->geometryId(),
0431                     Acts::GeometryIdentifier(3));
0432   BOOST_CHECK_EQUAL(statesBwd[1].currentSurface->geometryId(),
0433                     Acts::GeometryIdentifier(14));
0434   BOOST_CHECK_EQUAL(statesBwd[1].currentPortal, nullptr);
0435 
0436   // Step to the volume3|endOfWorld boundary
0437   BOOST_CHECK_EQUAL(statesBwd[0].currentVolume->geometryId(),
0438                     Acts::GeometryIdentifier(3));
0439   BOOST_CHECK_EQUAL(statesBwd[0].currentSurface, nullptr);
0440   BOOST_CHECK_EQUAL(statesBwd[0].currentPortal, nullptr);
0441 }
0442 
0443 // Check how the navigator handles the case
0444 // when the same surface may be reached
0445 // in multiple points
0446 BOOST_AUTO_TEST_CASE(DetectorNavigatorTestsAmbiguity) {
0447   // Construct a cubic detector with a cylindrical surface
0448   auto bounds = std::make_unique<Acts::CuboidVolumeBounds>(10, 10, 10);
0449   auto surface = Acts::Surface::makeShared<Acts::CylinderSurface>(
0450       Acts::Transform3::Identity(),
0451       std::make_shared<Acts::CylinderBounds>(4, 9));
0452   auto volume = Acts::Experimental::DetectorVolumeFactory::construct(
0453       Acts::Experimental::defaultPortalAndSubPortalGenerator(), geoContext,
0454       "volume", Acts::Transform3::Identity(), std::move(bounds), {surface}, {},
0455       Acts::Experimental::tryNoVolumes(),
0456       Acts::Experimental::tryAllPortalsAndSurfaces());
0457 
0458   volume->assignGeometryId(Acts::GeometryIdentifier(1));
0459   surface->assignGeometryId(Acts::GeometryIdentifier(2));
0460   int id = 3;
0461   for (auto& port : volume->portalPtrs()) {
0462     port->surface().assignGeometryId(Acts::GeometryIdentifier(id));
0463     id++;
0464   }
0465 
0466   auto detector = Acts::Experimental::Detector::makeShared(
0467       "detector", {volume}, Acts::Experimental::tryRootVolumes());
0468 
0469   using Stepper = Acts::StraightLineStepper;
0470   using Navigator = Acts::Experimental::DetectorNavigator;
0471   using Propagator = Acts::Propagator<Stepper, Navigator>;
0472   using ActorList = Acts::ActorList<StateRecorder, Acts::EndOfWorldReached>;
0473   using PropagatorOptions = Propagator::Options<ActorList>;
0474 
0475   Navigator::Config navCfg;
0476   navCfg.detector = detector.get();
0477 
0478   Stepper stepper;
0479 
0480   Navigator navigator(navCfg,
0481                       Acts::getDefaultLogger("DetectorNavigator",
0482                                              Acts::Logging::Level::VERBOSE));
0483 
0484   PropagatorOptions options(geoContext, mfContext);
0485   options.direction = Acts::Direction::Forward();
0486 
0487   Propagator propagator(
0488       stepper, navigator,
0489       Acts::getDefaultLogger("Propagator", Acts::Logging::Level::VERBOSE));
0490 
0491   // Depending on the direction, the same surface
0492   // may be reached in different points
0493   Acts::Vector4 pos(0, 0, 0, 0);
0494   Acts::BoundTrackParameters start =
0495       Acts::BoundTrackParameters::createCurvilinear(
0496           pos, 0_degree, 90_degree, 1_e / 1_GeV, std::nullopt,
0497           Acts::ParticleHypothesis::electron());
0498 
0499   // Has to properly handle propagation in the
0500   // forward and backward direction
0501   auto resultFwd = propagator.propagate(start, options).value();
0502   auto statesFwd = resultFwd.get<StateRecorder::result_type>();
0503 
0504   options.direction = Acts::Direction::Backward();
0505 
0506   auto resultBwd = propagator.propagate(start, options).value();
0507   auto statesBwd = resultBwd.get<StateRecorder::result_type>();
0508 
0509   // 3 steps to reach the end of world
0510   // + 1 recording in the post-step
0511   // + 1 recording before the stepping loop
0512   BOOST_CHECK_EQUAL(statesFwd.size(), 4u);
0513   BOOST_CHECK_EQUAL(statesFwd.size(), statesBwd.size());
0514   BOOST_CHECK_EQUAL(statesFwd[0].surfaceCandidates.size(), 2u);
0515   BOOST_CHECK_EQUAL(statesBwd[0].surfaceCandidates.size(), 2u);
0516 
0517   // Action list call before the first step
0518   // Starting in the volume
0519   BOOST_CHECK_EQUAL(statesFwd[0].currentVolume->geometryId(),
0520                     Acts::GeometryIdentifier(1));
0521   BOOST_CHECK_EQUAL(statesFwd[0].currentSurface, nullptr);
0522   BOOST_CHECK_EQUAL(statesFwd[0].currentPortal, nullptr);
0523 
0524   // Step to the cylindrical surface
0525   BOOST_CHECK_EQUAL(statesFwd[1].currentVolume->geometryId(),
0526                     Acts::GeometryIdentifier(1));
0527   BOOST_CHECK_EQUAL(statesFwd[1].currentSurface->geometryId(),
0528                     Acts::GeometryIdentifier(2));
0529   BOOST_CHECK_EQUAL(statesFwd[1].currentPortal, nullptr);
0530   CHECK_CLOSE_REL(statesFwd[1].position.x(), 4, 1e-6);
0531 
0532   // Step to the volume|endOfWorld boundary
0533   BOOST_CHECK_EQUAL(statesFwd[2].currentVolume, nullptr);
0534   BOOST_CHECK_EQUAL(statesFwd[2].currentSurface,
0535                     &(statesFwd[2].currentPortal->surface()));
0536   BOOST_CHECK_EQUAL(statesFwd[2].currentPortal->surface().geometryId(),
0537                     Acts::GeometryIdentifier(6));
0538 
0539   // Step to the end of world
0540   BOOST_CHECK(navigator.endOfWorldReached(statesFwd[3]));
0541   BOOST_CHECK(navigator.endOfWorldReached(statesBwd[3]));
0542 
0543   // Step to the endOfWorld|volume boundary
0544   BOOST_CHECK_EQUAL(statesBwd[2].currentVolume, nullptr);
0545   BOOST_CHECK_EQUAL(statesBwd[2].currentSurface,
0546                     &(statesBwd[2].currentPortal->surface()));
0547   BOOST_CHECK_EQUAL(statesBwd[2].currentPortal->surface().geometryId(),
0548                     Acts::GeometryIdentifier(5));
0549 
0550   // Step to the cylindrical surface
0551   BOOST_CHECK_EQUAL(statesBwd[1].currentVolume->geometryId(),
0552                     Acts::GeometryIdentifier(1));
0553   BOOST_CHECK_EQUAL(statesBwd[1].currentSurface->geometryId(),
0554                     Acts::GeometryIdentifier(2));
0555   BOOST_CHECK_EQUAL(statesBwd[1].currentPortal, nullptr);
0556   CHECK_CLOSE_REL(statesBwd[1].position.x(), -4, 1e-6);
0557 
0558   // Action list call before the first step
0559   // Starting in the volume
0560   BOOST_CHECK_EQUAL(statesBwd[0].currentVolume->geometryId(),
0561                     Acts::GeometryIdentifier(1));
0562   BOOST_CHECK_EQUAL(statesBwd[0].currentSurface, nullptr);
0563   BOOST_CHECK_EQUAL(statesBwd[0].currentPortal, nullptr);
0564 }
0565 
0566 // Check how the navigator handles the case
0567 // when the same surface has multiple valid
0568 // intersections
0569 BOOST_AUTO_TEST_CASE(DetectorNavigatorTestsMultipleIntersection) {
0570   // Construct a cubic detector with a cylindrical surface
0571   auto bounds = std::make_unique<Acts::CuboidVolumeBounds>(10, 10, 10);
0572   auto surface = Acts::Surface::makeShared<Acts::CylinderSurface>(
0573       Acts::Transform3::Identity(),
0574       std::make_shared<Acts::CylinderBounds>(4, 9));
0575   auto volume = Acts::Experimental::DetectorVolumeFactory::construct(
0576       Acts::Experimental::defaultPortalAndSubPortalGenerator(), geoContext,
0577       "volume", Acts::Transform3::Identity(), std::move(bounds), {surface}, {},
0578       Acts::Experimental::tryNoVolumes(),
0579       Acts::Experimental::tryAllPortalsAndSurfaces());
0580 
0581   volume->assignGeometryId(Acts::GeometryIdentifier(1));
0582   surface->assignGeometryId(Acts::GeometryIdentifier(2));
0583   int id = 3;
0584   for (auto& port : volume->portalPtrs()) {
0585     port->surface().assignGeometryId(Acts::GeometryIdentifier(id));
0586     id++;
0587   }
0588 
0589   auto detector = Acts::Experimental::Detector::makeShared(
0590       "detector", {volume}, Acts::Experimental::tryRootVolumes());
0591 
0592   using Stepper = Acts::StraightLineStepper;
0593   using Navigator = Acts::Experimental::DetectorNavigator;
0594   using Propagator = Acts::Propagator<Stepper, Navigator>;
0595   using ActorList = Acts::ActorList<StateRecorder, Acts::EndOfWorldReached>;
0596   using PropagatorOptions = Propagator::Options<ActorList>;
0597 
0598   Navigator::Config navCfg;
0599   navCfg.detector = detector.get();
0600 
0601   Stepper stepper;
0602 
0603   Navigator navigator(navCfg,
0604                       Acts::getDefaultLogger("DetectorNavigator",
0605                                              Acts::Logging::Level::VERBOSE));
0606 
0607   PropagatorOptions options(geoContext, mfContext);
0608   options.direction = Acts::Direction::Forward();
0609 
0610   Propagator propagator(
0611       stepper, navigator,
0612       Acts::getDefaultLogger("Propagator", Acts::Logging::Level::VERBOSE));
0613 
0614   // Forward and backward propagation
0615   // should be consistent between each other
0616   // and the cylindrical surface should be
0617   // reached in two points during navigation
0618   Acts::Vector4 posFwd(-5, 0, 0, 0);
0619   Acts::BoundTrackParameters startFwd =
0620       Acts::BoundTrackParameters::createCurvilinear(
0621           posFwd, 0_degree, 90_degree, 1_e / 1_GeV, std::nullopt,
0622           Acts::ParticleHypothesis::electron());
0623 
0624   auto resultFwd = propagator.propagate(startFwd, options).value();
0625   auto statesFwd = resultFwd.get<StateRecorder::result_type>();
0626 
0627   options.direction = Acts::Direction::Backward();
0628   Acts::Vector4 posBwd(5, 0, 0, 0);
0629   Acts::BoundTrackParameters startBwd =
0630       Acts::BoundTrackParameters::createCurvilinear(
0631           posBwd, 0_degree, 90_degree, 1_e / 1_GeV, std::nullopt,
0632           Acts::ParticleHypothesis::electron());
0633 
0634   auto resultBwd = propagator.propagate(startBwd, options).value();
0635   auto statesBwd = resultBwd.get<StateRecorder::result_type>();
0636 
0637   // 4 steps to reach the end of world
0638   // + 1 recording in the post-step
0639   // + 1 recording before the stepping loop
0640   BOOST_CHECK_EQUAL(statesFwd.size(), 5u);
0641   BOOST_CHECK_EQUAL(statesFwd.size(), statesBwd.size());
0642   BOOST_CHECK_EQUAL(statesFwd[0].surfaceCandidates.size(), 3u);
0643   BOOST_CHECK_EQUAL(statesBwd[0].surfaceCandidates.size(), 3u);
0644 
0645   // Action list call before the first step
0646   // Starting in the volume
0647   BOOST_CHECK_EQUAL(statesFwd[0].currentVolume->geometryId(),
0648                     Acts::GeometryIdentifier(1));
0649   BOOST_CHECK_EQUAL(statesFwd[0].currentSurface, nullptr);
0650   BOOST_CHECK_EQUAL(statesFwd[0].currentPortal, nullptr);
0651 
0652   // First intersection of the cylindrical surface
0653   BOOST_CHECK_EQUAL(statesFwd[1].currentVolume->geometryId(),
0654                     Acts::GeometryIdentifier(1));
0655   BOOST_CHECK_EQUAL(statesFwd[1].currentSurface->geometryId(),
0656                     Acts::GeometryIdentifier(2));
0657   BOOST_CHECK_EQUAL(statesFwd[1].currentPortal, nullptr);
0658   CHECK_CLOSE_REL(statesFwd[1].position.x(), -4, 1e-6);
0659 
0660   // Second intersection of the cylindrical surface
0661   BOOST_CHECK_EQUAL(statesFwd[2].currentVolume->geometryId(),
0662                     Acts::GeometryIdentifier(1));
0663   BOOST_CHECK_EQUAL(statesFwd[2].currentSurface->geometryId(),
0664                     Acts::GeometryIdentifier(2));
0665   BOOST_CHECK_EQUAL(statesFwd[2].currentPortal, nullptr);
0666   CHECK_CLOSE_REL(statesFwd[2].position.x(), 4, 1e-6);
0667 
0668   // Step to the volume|endOfWorld boundary
0669   BOOST_CHECK_EQUAL(statesFwd[3].currentVolume, nullptr);
0670   BOOST_CHECK_EQUAL(statesFwd[3].currentSurface,
0671                     &(statesFwd[3].currentPortal->surface()));
0672   BOOST_CHECK_EQUAL(statesFwd[3].currentPortal->surface().geometryId(),
0673                     Acts::GeometryIdentifier(6));
0674 
0675   // Step to the end of world
0676   BOOST_CHECK(navigator.endOfWorldReached(statesFwd[4]));
0677   BOOST_CHECK(navigator.endOfWorldReached(statesBwd[4]));
0678 
0679   // Step to the endOfWorld|volume boundary
0680   BOOST_CHECK_EQUAL(statesBwd[3].currentVolume, nullptr);
0681   BOOST_CHECK_EQUAL(statesBwd[3].currentSurface,
0682                     &(statesBwd[3].currentPortal->surface()));
0683   BOOST_CHECK_EQUAL(statesBwd[3].currentPortal->surface().geometryId(),
0684                     Acts::GeometryIdentifier(5));
0685 
0686   // Step to the cylindrical surface
0687   BOOST_CHECK_EQUAL(statesBwd[2].currentVolume->geometryId(),
0688                     Acts::GeometryIdentifier(1));
0689   BOOST_CHECK_EQUAL(statesBwd[2].currentSurface->geometryId(),
0690                     Acts::GeometryIdentifier(2));
0691   BOOST_CHECK_EQUAL(statesBwd[2].currentPortal, nullptr);
0692   CHECK_CLOSE_REL(statesBwd[2].position.x(), -4, 1e-6);
0693 
0694   // First intersection of the cylindrical surface
0695   BOOST_CHECK_EQUAL(statesBwd[1].currentVolume->geometryId(),
0696                     Acts::GeometryIdentifier(1));
0697   BOOST_CHECK_EQUAL(statesBwd[1].currentSurface->geometryId(),
0698                     Acts::GeometryIdentifier(2));
0699   BOOST_CHECK_EQUAL(statesBwd[1].currentPortal, nullptr);
0700   CHECK_CLOSE_REL(statesBwd[1].position.x(), 4, 1e-6);
0701 
0702   // Action list call before the first step
0703   // Starting in the volume
0704   BOOST_CHECK_EQUAL(statesBwd[0].currentVolume->geometryId(),
0705                     Acts::GeometryIdentifier(1));
0706   BOOST_CHECK_EQUAL(statesBwd[0].currentSurface, nullptr);
0707   BOOST_CHECK_EQUAL(statesBwd[0].currentPortal, nullptr);
0708 }
0709 
0710 BOOST_AUTO_TEST_SUITE_END()