Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-18 08:22:39

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();
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 
0146 BOOST_AUTO_TEST_CASE(NavigationStream_UpdatePlanes) {
0147   // Create the punch of surfaces
0148   auto surfaces = createPlaneSurfaces();
0149 
0150   // Surfaces are filled with no boundary tolerance, we require them to be
0151   // reachable and intersections inside bounds
0152   NavigationStream nStreamTemplate;
0153   for (const auto& surface : surfaces) {
0154     nStreamTemplate.addSurfaceCandidate(*surface, BoundaryTolerance::None());
0155   }
0156   BOOST_CHECK_EQUAL(nStreamTemplate.remainingCandidates(), 4u);
0157 
0158   // Run an initial update
0159   // - from a position where all are reachable and valid
0160   // - with infinite boundary tolerance
0161   NavigationStream::QueryPoint qPoint = {Vector3(0., 0., -30.),
0162                                          Vector3(0., 0., 1.)};
0163 
0164   NavigationStream nStream = nStreamTemplate;
0165   BOOST_CHECK(
0166       nStream.initialize(gContext, qPoint, BoundaryTolerance::Infinite()));
0167   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 4u);
0168   BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0169                     surfaces.at(1u).get());
0170   CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), 10.,
0171                   std::numeric_limits<double>::epsilon());
0172 
0173   // Let's push a bit closer to the surface
0174   qPoint.position = Vector3(0., 0., -22.);
0175   BOOST_CHECK(nStream.update(gContext, qPoint));
0176   // Surface unchanged, but the intersection should be closer
0177   BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0178                     surfaces.at(1u).get());
0179   CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), 2.,
0180                   std::numeric_limits<double>::epsilon());
0181 
0182   // Uuuups, an overstep
0183   qPoint.position = Vector3(0., 0., -19.5);
0184   BOOST_CHECK(nStream.update(gContext, qPoint));
0185   // Surface still unchanged, but pathLength is now negative
0186   BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0187                     surfaces.at(1u).get());
0188   CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), -0.5,
0189                   std::numeric_limits<double>::epsilon());
0190 
0191   // Finally hit it
0192   qPoint.position = Vector3(0., 0., -20.);
0193   BOOST_CHECK(nStream.update(gContext, qPoint));
0194   // Surface still unchanged, however, now withL
0195   // - pathlength smaller on surface tolerance, intersection status onSurface
0196   BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0197                     surfaces.at(1u).get());
0198   CHECK_CLOSE_ABS(
0199       nStream.currentCandidate().pathLength(), s_onSurfaceTolerance,
0200       std::numeric_limits<double>::epsilon() + s_onSurfaceTolerance);
0201   BOOST_CHECK_EQUAL(nStream.currentCandidate().status(),
0202                     IntersectionStatus::onSurface);
0203   // Let's say the stepper confirms this
0204   BOOST_CHECK(nStream.switchToNextCandidate());
0205   // Surface is now surfaceB
0206   BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0207                     surfaces.at(3u).get());
0208   // Distance should be the initial estimate from the intialializeStream() call
0209   CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), 130.,
0210                   std::numeric_limits<double>::epsilon());
0211   // Query update will re-evaluate this one: however, we will miss the surface
0212   // due to outside bounds - and will switch to the next candidate: which sits
0213   // at 200 and then will yield 220
0214   BOOST_CHECK(nStream.update(gContext, qPoint));
0215   CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), 220.,
0216                   std::numeric_limits<double>::epsilon());
0217   // Oh noooo, an actor just kicked in and changed the direction
0218   qPoint.direction = Vector3(0., 1., 1.).normalized();
0219   // All is lost, no surface is reachable anymore
0220   BOOST_CHECK(!nStream.update(gContext, qPoint));
0221 }
0222 
0223 BOOST_AUTO_TEST_CASE(NavigationStream_InitializeCylinders) {
0224   // Create the cylinder setup
0225   auto surfaces = createCylinders();
0226 
0227   // Let us fill the surfaces into the navigation stream
0228   NavigationStream nStreamTemplate;
0229   for (const auto& surface : surfaces) {
0230     const Surface* pointer = surface.get();
0231     nStreamTemplate.addSurfaceCandidates({&pointer, 1},
0232                                          BoundaryTolerance::None());
0233   }
0234   BOOST_CHECK_EQUAL(nStreamTemplate.remainingCandidates(), 4u);
0235 
0236   // (1) Run an initial update - from a position/direction where all are
0237   // reachable
0238   // - with infinite boundary tolerance
0239   NavigationStream nStream = nStreamTemplate;
0240   BOOST_CHECK(nStream.initialize(
0241       gContext, {Vector3(0., 0., 0.), Vector3(1., 1., 0.).normalized()},
0242       BoundaryTolerance::Infinite()));
0243 
0244   // We should have 4 candidates, as one cylinder is reachable twice
0245   // Technically, the surface at 20,20,0 is hit twice, but we deduplicate them
0246   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 4u);
0247   // First one is inner candidate
0248   BOOST_CHECK_EQUAL(&nStream.candidates().at(0u).surface(),
0249                     surfaces.at(2).get());
0250   BOOST_CHECK_EQUAL(&nStream.candidates().at(1u).surface(),
0251                     surfaces.at(1).get());
0252   BOOST_CHECK_EQUAL(&nStream.candidates().at(2u).surface(),
0253                     surfaces.at(0).get());
0254 
0255   // (2) Run an initial update - from a position/direction where only
0256   // the concentric ones are reachable
0257   // - with infinite boundary tolerance
0258   nStream = nStreamTemplate;
0259   BOOST_CHECK(nStream.initialize(gContext,
0260                                  {Vector3(0., 0., 0.), Vector3(1., 0., 0.)},
0261                                  BoundaryTolerance::Infinite()));
0262   // We should have 3 candidates
0263   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 3u);
0264 
0265   // (3) Run an initial update - from a position/direction where only the
0266   // concentric ones within bounds are reachable
0267   nStream = nStreamTemplate;
0268   BOOST_CHECK(nStream.initialize(gContext,
0269                                  {Vector3(0., 0., 0.), Vector3(1., 0., 0.)},
0270                                  BoundaryTolerance::None()));
0271   // We should have 2 candidates
0272   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 2u);
0273 
0274   // (4) Run an initial update - from a position/direction where none are
0275   // reachable
0276   // - (even) with infinite boundary tolerance
0277   nStream = nStreamTemplate;
0278   BOOST_CHECK(!nStream.initialize(gContext,
0279                                   {Vector3(0., 0., 0.), Vector3(0., 0., 1.)},
0280                                   BoundaryTolerance::None()));
0281   // We should have 0 candidates
0282   BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 0u);
0283   BOOST_CHECK_THROW(nStream.currentCandidate(), std::out_of_range);
0284 }
0285 
0286 BOOST_AUTO_TEST_SUITE_END()
0287 
0288 }  // namespace ActsTests