Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:12:45

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