Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-14 08:20:54

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/Navigation/NavigationStream.hpp"
0012 #include "Acts/Surfaces/CylinderSurface.hpp"
0013 #include "Acts/Surfaces/PlaneSurface.hpp"
0014 #include "Acts/Surfaces/RectangleBounds.hpp"
0015 #include "Acts/Utilities/Intersection.hpp"
0016 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0017 
0018 using namespace Acts;
0019 
0020 namespace ActsTests {
0021 
0022 // This creates a set of plane surfaces along the z axis
0023 std::vector<std::shared_ptr<Surface>> createPlaneSurfaces() {
0024   auto rectangle = std::make_shared<RectangleBounds>(10., 10.);
0025   // Surface A:
0026   // This surface should not be reachable from (0.,0.,0.) position along z
0027   Transform3 aTransform = Transform3::Identity();
0028   aTransform.pretranslate(Vector3(0., 0., -20.));
0029   auto surfaceA = Surface::makeShared<PlaneSurface>(aTransform, rectangle);
0030   // Surface B:
0031   // This surface should not be reachable from (0.,0.,0.) position along z with
0032   // boundary check
0033   Transform3 bTransform = Transform3::Identity();
0034   bTransform.pretranslate(Vector3(50., 50., 100.));
0035   auto surfaceB = Surface::makeShared<PlaneSurface>(bTransform, rectangle);
0036   // Surface C:
0037   Transform3 cTransform = Transform3::Identity();
0038   cTransform.pretranslate(Vector3(0., 0., 200.));
0039   auto surfaceC = Surface::makeShared<PlaneSurface>(cTransform, rectangle);
0040   // Surface D:
0041   Transform3 dTransform = Transform3::Identity();
0042   dTransform.pretranslate(Vector3(0., 0., 400.));
0043   auto surfaceD = Surface::makeShared<PlaneSurface>(dTransform, rectangle);
0044 
0045   // Let's fill them shuffled
0046   return {surfaceC, surfaceA, surfaceD, surfaceB};
0047 }
0048 
0049 // This creates a set of cylinder surfaces
0050 std::vector<std::shared_ptr<Surface>> createCylinders() {
0051   // Surface A:
0052   // A concentric cylinder with a radius of 10 and a half length of 20
0053   Transform3 aTransform = Transform3::Identity();
0054   auto surfaceA = Surface::makeShared<CylinderSurface>(aTransform, 10., 20);
0055 
0056   // Surface B:
0057   // A  small cylinder sitting at 20, 20
0058   Transform3 bTransform = Transform3::Identity();
0059   bTransform.pretranslate(Vector3(20., 20., 0.));
0060   auto surfaceB = Surface::makeShared<CylinderSurface>(bTransform, 2., 10);
0061 
0062   // Surface C:
0063   // A concentric cylinder with a radius of 40 and a half length of 20
0064   Transform3 cTransform = Transform3::Identity();
0065   auto surfaceC = Surface::makeShared<CylinderSurface>(cTransform, 40., 20);
0066 
0067   // Surface C:
0068   // A concentric, but shifted cylinder with a radius of 50 and a half length of
0069   // 5
0070   Transform3 dTransform = Transform3::Identity();
0071   dTransform.pretranslate(Vector3(0., 0., 10.));
0072   auto surfaceD = Surface::makeShared<CylinderSurface>(dTransform, 50., 5.);
0073 
0074   // Return in a shuffled order
0075   return {surfaceC, surfaceB, surfaceA, surfaceD};
0076 }
0077 
0078 auto gContext = GeometryContext::dangerouslyDefaultConstruct();
0079 
0080 BOOST_AUTO_TEST_SUITE(Navigation)
0081 
0082 BOOST_AUTO_TEST_CASE(NavigationStream_InitializePlanes) {
0083   // Create the punch of surfaces
0084   auto surfaces = createPlaneSurfaces();
0085 
0086   NavigationStream nStreamTemplate;
0087   for (const auto& surface : surfaces) {
0088     nStreamTemplate.addSurfaceCandidate(*surface, BoundaryTolerance::None());
0089   }
0090   BOOST_CHECK_EQUAL(nStreamTemplate.remainingCandidates(), 4u);
0091 
0092   // (1) Run an initial update
0093   // - from a position where all are reachable and valid
0094   // - with infinite boundary tolerance
0095   NavigationStream nStream = nStreamTemplate;
0096   BOOST_CHECK(nStream.initialize(gContext,
0097                                  {Vector3(0., 0., -30.), Vector3(0., 0., 1.)},
0098                                  BoundaryTolerance::Infinite()));
0099 
0100   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 4u);
0101   BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0102                     surfaces.at(1u).get());
0103 
0104   // (2) Run an initial update
0105   // - from a position where all but one are reachable
0106   // - with infinite boundary tolerance
0107   nStream = nStreamTemplate;
0108   BOOST_CHECK(nStream.initialize(gContext,
0109                                  {Vector3(0., 0., 0.), Vector3(0., 0., 1.)},
0110                                  BoundaryTolerance::Infinite()));
0111   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 3u);
0112   BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0113                     surfaces.at(3u).get());
0114 
0115   // (3) Run an initial update
0116   // - from a position where all would be reachable, but
0117   // - with no boundary tolerance
0118   nStream = nStreamTemplate;
0119   BOOST_CHECK(nStream.initialize(gContext,
0120                                  {Vector3(0., 0., -100.), Vector3(0., 0., 1.)},
0121                                  BoundaryTolerance::None()));
0122   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 3u);
0123 
0124   // (4) Run an initial update
0125   // - none of the surfaces should be reachable
0126   nStream = nStreamTemplate;
0127   BOOST_CHECK(!nStream.initialize(gContext,
0128                                   {Vector3(0., 0., 0.), Vector3(1., 0., 0.)},
0129                                   BoundaryTolerance::Infinite()));
0130   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 0u);
0131   BOOST_CHECK_THROW(nStream.currentCandidate(), std::out_of_range);
0132 
0133   // (5) Test de-duplication
0134   nStream = nStreamTemplate;
0135   nStreamTemplate.addSurfaceCandidate(*surfaces.at(0),
0136                                       BoundaryTolerance::None());
0137   // One surface is duplicated in the stream
0138   BOOST_CHECK_EQUAL(nStreamTemplate.remainingCandidates(), 5u);
0139   // Initialize stream reaches all surfaces, but also de-duplicates
0140   BOOST_CHECK(nStream.initialize(gContext,
0141                                  {Vector3(0., 0., -100.), Vector3(0., 0., 1.)},
0142                                  BoundaryTolerance::Infinite()));
0143   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 4u);
0144 
0145   // (6) Even when the caller asserts uniqueness (skipping the
0146   // pre-intersection de-duplication pass), a duplicate that slips through is
0147   // still removed by the post-sort unique pass
0148   nStream = nStreamTemplate;
0149   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 5u);
0150   BOOST_CHECK(nStream.initialize(
0151       gContext, {Vector3(0., 0., -100.), Vector3(0., 0., 1.)},
0152       BoundaryTolerance::Infinite(), s_onSurfaceTolerance,
0153       /*candidatesAreUnique=*/true));
0154   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 4u);
0155 }
0156 
0157 BOOST_AUTO_TEST_CASE(NavigationStream_UpdatePlanes) {
0158   // Create the punch of surfaces
0159   auto surfaces = createPlaneSurfaces();
0160 
0161   // Surfaces are filled with no boundary tolerance, we require them to be
0162   // reachable and intersections inside bounds
0163   NavigationStream nStreamTemplate;
0164   for (const auto& surface : surfaces) {
0165     nStreamTemplate.addSurfaceCandidate(*surface, BoundaryTolerance::None());
0166   }
0167   BOOST_CHECK_EQUAL(nStreamTemplate.remainingCandidates(), 4u);
0168 
0169   // Run an initial update
0170   // - from a position where all are reachable and valid
0171   // - with infinite boundary tolerance
0172   NavigationStream::QueryPoint qPoint = {Vector3(0., 0., -30.),
0173                                          Vector3(0., 0., 1.)};
0174 
0175   NavigationStream nStream = nStreamTemplate;
0176   BOOST_CHECK(
0177       nStream.initialize(gContext, qPoint, BoundaryTolerance::Infinite()));
0178   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 4u);
0179   BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0180                     surfaces.at(1u).get());
0181   CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), 10.,
0182                   std::numeric_limits<double>::epsilon());
0183 
0184   // Let's push a bit closer to the surface
0185   qPoint.position = Vector3(0., 0., -22.);
0186   BOOST_CHECK(nStream.update(gContext, qPoint));
0187   // Surface unchanged, but the intersection should be closer
0188   BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0189                     surfaces.at(1u).get());
0190   CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), 2.,
0191                   std::numeric_limits<double>::epsilon());
0192 
0193   // Uuuups, an overstep
0194   qPoint.position = Vector3(0., 0., -19.5);
0195   BOOST_CHECK(nStream.update(gContext, qPoint));
0196   // Surface still unchanged, but pathLength is now negative
0197   BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0198                     surfaces.at(1u).get());
0199   CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), -0.5,
0200                   std::numeric_limits<double>::epsilon());
0201 
0202   // Finally hit it
0203   qPoint.position = Vector3(0., 0., -20.);
0204   BOOST_CHECK(nStream.update(gContext, qPoint));
0205   // Surface still unchanged, however, now withL
0206   // - pathlength smaller on surface tolerance, intersection status onSurface
0207   BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0208                     surfaces.at(1u).get());
0209   CHECK_CLOSE_ABS(
0210       nStream.currentCandidate().pathLength(), s_onSurfaceTolerance,
0211       std::numeric_limits<double>::epsilon() + s_onSurfaceTolerance);
0212   BOOST_CHECK_EQUAL(nStream.currentCandidate().status(),
0213                     IntersectionStatus::onSurface);
0214   // Let's say the stepper confirms this
0215   BOOST_CHECK(nStream.switchToNextCandidate());
0216   // Surface is now surfaceB
0217   BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0218                     surfaces.at(3u).get());
0219   // Distance should be the initial estimate from the intialializeStream() call
0220   CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), 130.,
0221                   std::numeric_limits<double>::epsilon());
0222   // Query update will re-evaluate this one: however, we will miss the surface
0223   // due to outside bounds - and will switch to the next candidate: which sits
0224   // at 200 and then will yield 220
0225   BOOST_CHECK(nStream.update(gContext, qPoint));
0226   CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), 220.,
0227                   std::numeric_limits<double>::epsilon());
0228   // Oh noooo, an actor just kicked in and changed the direction
0229   qPoint.direction = Vector3(0., 1., 1.).normalized();
0230   // All is lost, no surface is reachable anymore
0231   BOOST_CHECK(!nStream.update(gContext, qPoint));
0232 }
0233 
0234 BOOST_AUTO_TEST_CASE(NavigationStream_InitializeCylinders) {
0235   // Create the cylinder setup
0236   auto surfaces = createCylinders();
0237 
0238   // Let us fill the surfaces into the navigation stream
0239   NavigationStream nStreamTemplate;
0240   for (const auto& surface : surfaces) {
0241     const Surface* pointer = surface.get();
0242     nStreamTemplate.addSurfaceCandidates({&pointer, 1},
0243                                          BoundaryTolerance::None());
0244   }
0245   BOOST_CHECK_EQUAL(nStreamTemplate.remainingCandidates(), 4u);
0246 
0247   // (1) Run an initial update - from a position/direction where all are
0248   // reachable
0249   // - with infinite boundary tolerance
0250   NavigationStream nStream = nStreamTemplate;
0251   BOOST_CHECK(nStream.initialize(
0252       gContext, {Vector3(0., 0., 0.), Vector3(1., 1., 0.).normalized()},
0253       BoundaryTolerance::Infinite()));
0254 
0255   // We should have 4 candidates, as one cylinder is reachable twice
0256   // Technically, the surface at 20,20,0 is hit twice, but we deduplicate them
0257   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 4u);
0258   // First one is inner candidate
0259   BOOST_CHECK_EQUAL(&nStream.candidates().at(0u).surface(),
0260                     surfaces.at(2).get());
0261   BOOST_CHECK_EQUAL(&nStream.candidates().at(1u).surface(),
0262                     surfaces.at(1).get());
0263   BOOST_CHECK_EQUAL(&nStream.candidates().at(2u).surface(),
0264                     surfaces.at(0).get());
0265 
0266   // (2) Run an initial update - from a position/direction where only
0267   // the concentric ones are reachable
0268   // - with infinite boundary tolerance
0269   nStream = nStreamTemplate;
0270   BOOST_CHECK(nStream.initialize(gContext,
0271                                  {Vector3(0., 0., 0.), Vector3(1., 0., 0.)},
0272                                  BoundaryTolerance::Infinite()));
0273   // We should have 3 candidates
0274   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 3u);
0275 
0276   // (3) Run an initial update - from a position/direction where only the
0277   // concentric ones within bounds are reachable
0278   nStream = nStreamTemplate;
0279   BOOST_CHECK(nStream.initialize(gContext,
0280                                  {Vector3(0., 0., 0.), Vector3(1., 0., 0.)},
0281                                  BoundaryTolerance::None()));
0282   // We should have 2 candidates
0283   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 2u);
0284 
0285   // (4) Run an initial update - from a position/direction where none are
0286   // reachable
0287   // - (even) with infinite boundary tolerance
0288   nStream = nStreamTemplate;
0289   BOOST_CHECK(!nStream.initialize(gContext,
0290                                   {Vector3(0., 0., 0.), Vector3(0., 0., 1.)},
0291                                   BoundaryTolerance::None()));
0292   // We should have 0 candidates
0293   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 0u);
0294   BOOST_CHECK_THROW(nStream.currentCandidate(), std::out_of_range);
0295 }
0296 
0297 BOOST_AUTO_TEST_SUITE_END()
0298 
0299 }  // namespace ActsTests