Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-15 08:13:37

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