Back to home page

EIC code displayed by LXR

 
 

    


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

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/Tolerance.hpp"
0013 #include "Acts/Definitions/Units.hpp"
0014 #include "Acts/Geometry/GeometryContext.hpp"
0015 #include "Acts/Surfaces/ConeSurface.hpp"
0016 #include "Acts/Surfaces/CylinderSurface.hpp"
0017 #include "Acts/Surfaces/PlaneSurface.hpp"
0018 #include "Acts/Surfaces/RectangleBounds.hpp"
0019 #include "Acts/Surfaces/StrawSurface.hpp"
0020 #include "Acts/Surfaces/Surface.hpp"
0021 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0022 #include "Acts/Utilities/Intersection.hpp"
0023 
0024 #include <cmath>
0025 #include <memory>
0026 #include <numbers>
0027 
0028 using namespace Acts::UnitLiterals;
0029 
0030 namespace Acts::Test {
0031 
0032 // Create a test context
0033 GeometryContext tgContext = GeometryContext();
0034 
0035 // Some random transform
0036 Transform3 aTransform = Transform3::Identity() *
0037                         Translation3(30_cm, 7_m, -87_mm) *
0038                         AngleAxis3(0.42, Vector3(-3., 1., 8).normalized());
0039 
0040 BOOST_AUTO_TEST_SUITE(Surfaces)
0041 
0042 /// This tests the intersection with cylinders
0043 /// and looks for valid, non-valid, solutions
0044 BOOST_AUTO_TEST_CASE(CylinderIntersectionTests) {
0045   const double radius = 1_m;
0046   const double halfZ = 10_m;
0047 
0048   auto testCylinderIntersection = [&](const Transform3& transform) -> void {
0049     // A cylinder created aligned with a provided transform
0050     auto aCylinder =
0051         Surface::makeShared<CylinderSurface>(transform, radius, halfZ);
0052 
0053     // Linear transform
0054     auto lTransform = transform.linear();
0055 
0056     // An onCylinder solution
0057     Vector3 onCylinder = transform * Vector3(radius, 0., 0.);
0058     Vector3 outCylinder = transform * Vector3(-radius, 0.6 * radius, 90_cm);
0059     Vector3 atCenter = transform * Vector3(0., 0., 0.);
0060     Vector3 atEdge = transform * Vector3(0.5 * radius, 0., 0.99 * halfZ);
0061     // Simply along the x axis
0062     Vector3 alongX = lTransform * Vector3(1., 0., 0.);
0063     Vector3 transXY = lTransform * Vector3(1., 1., 0).normalized();
0064     Vector3 transTZ = lTransform * Vector3(1., 0., 1.).normalized();
0065 
0066     // Intersect without boundary check
0067     auto aIntersection = aCylinder->intersect(tgContext, onCylinder, alongX,
0068                                               BoundaryTolerance::None());
0069 
0070     // Check the validity of the intersection
0071     BOOST_CHECK(aIntersection[0].isValid());
0072     // The status of this one should be on surface
0073     BOOST_CHECK_EQUAL(aIntersection[0].status(), IntersectionStatus::reachable);
0074     // The intersection is at 2 meter distance
0075     CHECK_CLOSE_ABS(aIntersection[0].pathLength(), -2_m, s_onSurfaceTolerance);
0076     // There MUST be a second solution
0077     BOOST_CHECK(aIntersection[1].isValid());
0078     // The other intersection MUST be reachable
0079     BOOST_CHECK_EQUAL(aIntersection[1].status(), IntersectionStatus::onSurface);
0080 
0081     // Intersect from the center
0082     auto cIntersection = aCylinder->intersect(tgContext, atCenter, alongX,
0083                                               BoundaryTolerance::None());
0084 
0085     // Check the validity of the intersection
0086     BOOST_CHECK(cIntersection[0].isValid());
0087     // The status of this one MUST be reachable
0088     BOOST_CHECK_EQUAL(cIntersection[0].status(), IntersectionStatus::reachable);
0089     // There MUST be a second solution
0090     BOOST_CHECK(cIntersection[1].isValid());
0091     // The other intersection MUST be reachable
0092     BOOST_CHECK_EQUAL(cIntersection[1].status(), IntersectionStatus::reachable);
0093     // There MUST be one forward one backwards solution
0094     BOOST_CHECK_LT(
0095         cIntersection[1].pathLength() * cIntersection[0].pathLength(), 0);
0096 
0097     // Intersect from outside where both intersections are reachable
0098     auto oIntersection = aCylinder->intersect(tgContext, outCylinder, alongX,
0099                                               BoundaryTolerance::None());
0100 
0101     // Check the validity of the intersection
0102     BOOST_CHECK(oIntersection[0].isValid());
0103     // The status of this one MUST be reachable
0104     BOOST_CHECK_EQUAL(oIntersection[0].status(), IntersectionStatus::reachable);
0105     // There MUST be a second solution
0106     BOOST_CHECK(oIntersection[1].isValid());
0107     // The other intersection MUST be reachable
0108     BOOST_CHECK_EQUAL(oIntersection[1].status(), IntersectionStatus::reachable);
0109     // There MUST be one forward one backwards solution
0110     BOOST_CHECK_GT(
0111         oIntersection[1].pathLength() * oIntersection[0].pathLength(), 0);
0112 
0113     // Intersection from outside without chance of hitting the cylinder
0114     auto iIntersection = aCylinder->intersect(tgContext, outCylinder, transXY,
0115                                               BoundaryTolerance::Infinite());
0116 
0117     // Check the validity of the intersection
0118     BOOST_CHECK(!iIntersection[0].isValid());
0119 
0120     // From edge tests - wo boundary test
0121     auto eIntersection = aCylinder->intersect(tgContext, atEdge, transTZ,
0122                                               BoundaryTolerance::Infinite());
0123 
0124     // Check the validity of the intersection
0125     BOOST_CHECK(eIntersection[0].isValid());
0126     // This should be the positive one
0127     BOOST_CHECK_LT(eIntersection[0].pathLength(), 0.);
0128     // The status of this one should be reachable
0129     BOOST_CHECK_EQUAL(eIntersection[0].status(), IntersectionStatus::reachable);
0130     // There MUST be a second solution
0131     BOOST_CHECK(eIntersection[1].isValid());
0132     // The other intersection MUST be reachable
0133     BOOST_CHECK_EQUAL(eIntersection[1].status(), IntersectionStatus::reachable);
0134     // And be the negative one
0135     BOOST_CHECK_GT(eIntersection[1].pathLength(), 0.);
0136 
0137     // Now re-do with boundary check
0138     eIntersection = aCylinder->intersect(tgContext, atEdge, transTZ,
0139                                          BoundaryTolerance::None());
0140     // This should be the negative one
0141     BOOST_CHECK_LT(eIntersection[0].pathLength(), 0.);
0142     // The status of this one should be reachable
0143     BOOST_CHECK_EQUAL(eIntersection[0].status(), IntersectionStatus::reachable);
0144     // There MUST be a second solution
0145     BOOST_CHECK(!eIntersection[1].isValid());
0146     // The other intersection MUST NOT be reachable
0147     BOOST_CHECK_EQUAL(eIntersection[1].status(),
0148                       IntersectionStatus::unreachable);
0149     // And be the positive one
0150     BOOST_CHECK_GT(eIntersection[1].pathLength(), 0.);
0151   };
0152 
0153   // In a nominal world
0154   testCylinderIntersection(Transform3::Identity());
0155 
0156   // In a system somewhere away
0157   testCylinderIntersection(aTransform);
0158 }
0159 
0160 /// This tests the intersection with cylinders
0161 /// and looks for valid, non-valid, solutions
0162 BOOST_AUTO_TEST_CASE(ConeIntersectionTest) {
0163   const double alpha = std::numbers::pi / 4.;
0164 
0165   auto testConeIntersection = [&](const Transform3& transform) -> void {
0166     // A cone surface ready to use
0167     auto aCone = Surface::makeShared<ConeSurface>(transform, alpha, true);
0168 
0169     // Linear transform
0170     auto lTransform = transform.linear();
0171 
0172     // An onCylinder solution
0173     Vector3 onCone =
0174         transform * Vector3(std::numbers::sqrt2, std::numbers::sqrt2, 2.);
0175     Vector3 outCone = transform * Vector3(std::sqrt(4.), std::sqrt(4.), 2.);
0176     // Simply along the x axis
0177     Vector3 perpXY = lTransform * Vector3(1., -1., 0.).normalized();
0178     Vector3 transXY = lTransform * Vector3(1., 1., 0).normalized();
0179 
0180     // Intersect without boundary check with an on solution
0181     BOOST_CHECK(aCone->isOnSurface(tgContext, onCone, transXY,
0182                                    BoundaryTolerance::Infinite()));
0183     auto aIntersection =
0184         aCone->intersect(tgContext, onCone, transXY, BoundaryTolerance::None());
0185 
0186     // Check the validity of the intersection
0187     BOOST_CHECK(aIntersection[0].isValid());
0188     // The status of this one should be on surface
0189     BOOST_CHECK_EQUAL(aIntersection[0].status(), IntersectionStatus::reachable);
0190     // The intersection is at 4 mm distance
0191     CHECK_CLOSE_ABS(aIntersection[0].pathLength(), -4., s_onSurfaceTolerance);
0192     // There MUST be a second solution
0193     BOOST_CHECK(aIntersection[1].isValid());
0194     // The other intersection MUST be reachable
0195     BOOST_CHECK_EQUAL(aIntersection[1].status(), IntersectionStatus::onSurface);
0196 
0197     // Intersection from outside without chance of hitting the cylinder
0198     auto iIntersection = aCone->intersect(tgContext, outCone, perpXY,
0199                                           BoundaryTolerance::Infinite());
0200 
0201     // Check the validity of the intersection
0202     BOOST_CHECK(!iIntersection[0].isValid());
0203   };
0204 
0205   // In a nominal world
0206   testConeIntersection(Transform3::Identity());
0207 
0208   // In a system somewhere away
0209   testConeIntersection(aTransform);
0210 }
0211 
0212 /// This tests the intersection with planar surfaces (plane, disk)
0213 /// as those share the same PlanarHelper methods, only one test is
0214 /// sufficient
0215 /// - it looks for valid, non-valid, solutions
0216 BOOST_AUTO_TEST_CASE(PlanarIntersectionTest) {
0217   const double halfX = 1_m;
0218   const double halfY = 10_m;
0219 
0220   auto testPlanarIntersection = [&](const Transform3& transform) -> void {
0221     // A Plane created with a specific transform
0222     auto aPlane = Surface::makeShared<PlaneSurface>(
0223         transform, std::make_shared<RectangleBounds>(halfX, halfY));
0224 
0225     /// Forward intersection test
0226     Vector3 before = transform * Vector3(-50_cm, -1_m, -1_m);
0227     Vector3 onit = transform * Vector3(11_cm, -22_cm, 0_m);
0228     Vector3 after = transform * Vector3(33_cm, 12_mm, 1_m);
0229     Vector3 outside = transform * Vector3(2. * halfX, 2 * halfY, -1_mm);
0230 
0231     // Linear transform
0232     auto lTransform = transform.linear();
0233 
0234     // A direction that is non trivial
0235     Vector3 direction = lTransform * Vector3(4_mm, 8_mm, 50_cm).normalized();
0236     Vector3 parallel = lTransform * Vector3(1., 1., 0.).normalized();
0237 
0238     // Intersect forward
0239     auto fIntersection = aPlane->intersect(tgContext, before, direction,
0240                                            BoundaryTolerance::None());
0241 
0242     // The intersection MUST be valid
0243     BOOST_CHECK(fIntersection[0].isValid());
0244     // The intersection MUST be reachable
0245     BOOST_CHECK_EQUAL(fIntersection[0].status(), IntersectionStatus::reachable);
0246     // The path length MUST be positive
0247     BOOST_CHECK_GT(fIntersection[0].pathLength(), 0.);
0248     // The intersection MUST be unique
0249     BOOST_CHECK(!fIntersection[1].isValid());
0250 
0251     // On surface intersection
0252     auto oIntersection = aPlane->intersect(tgContext, onit, direction,
0253                                            BoundaryTolerance::None());
0254     // The intersection MUST be valid
0255     BOOST_CHECK(oIntersection[0].isValid());
0256     // The intersection MUST be reachable
0257     BOOST_CHECK_EQUAL(oIntersection[0].status(), IntersectionStatus::onSurface);
0258     // The path length MUST be positive
0259     BOOST_CHECK_LT(std::abs(oIntersection[0].pathLength()),
0260                    s_onSurfaceTolerance);
0261     // The intersection MUST be unique
0262     BOOST_CHECK(!oIntersection[1].isValid());
0263 
0264     // Intersect backwards
0265     auto bIntersection = aPlane->intersect(tgContext, after, direction,
0266                                            BoundaryTolerance::None());
0267     // The intersection MUST be valid
0268     BOOST_CHECK(bIntersection[0].isValid());
0269     // The intersection MUST be reachable
0270     BOOST_CHECK_EQUAL(bIntersection[0].status(), IntersectionStatus::reachable);
0271     // The path length MUST be negative
0272     BOOST_CHECK_LT(bIntersection[0].pathLength(), 0.);
0273     // The intersection MUST be unique
0274     BOOST_CHECK(!bIntersection[1].isValid());
0275 
0276     // An out of bounds attempt: missed
0277     auto mIntersection = aPlane->intersect(tgContext, outside, direction,
0278                                            BoundaryTolerance::None());
0279     // The intersection MUST NOT be valid
0280     BOOST_CHECK(!mIntersection[0].isValid());
0281     // The intersection MUST be reachable
0282     BOOST_CHECK_EQUAL(mIntersection[0].status(),
0283                       IntersectionStatus::unreachable);
0284     // The path length MUST be negative
0285     BOOST_CHECK_GT(mIntersection[0].pathLength(), 0.);
0286     // The intersection MUST be unique
0287     BOOST_CHECK(!mIntersection[1].isValid());
0288 
0289     // An invalid attempt
0290     auto iIntersection = aPlane->intersect(tgContext, before, parallel,
0291                                            BoundaryTolerance::None());
0292     // The intersection MUST NOT be valid
0293     BOOST_CHECK(!iIntersection[0].isValid());
0294     // The intersection MUST be reachable
0295     BOOST_CHECK_EQUAL(iIntersection[0].status(),
0296                       IntersectionStatus::unreachable);
0297     // The intersection MUST be unique
0298     BOOST_CHECK(!iIntersection[1].isValid());
0299   };
0300 
0301   // In a nominal world
0302   testPlanarIntersection(Transform3::Identity());
0303 
0304   // In a system somewhere away
0305   testPlanarIntersection(aTransform);
0306 }
0307 
0308 /// This tests the intersection with line like surfaces (straw, perigee)
0309 /// as those share the same methods, only one test is
0310 /// sufficient
0311 /// - it looks for valid, non-valid, solutions
0312 BOOST_AUTO_TEST_CASE(LineIntersectionTest) {
0313   const double radius = 1_m;
0314   const double halfZ = 10_m;
0315 
0316   auto testLineAppraoch = [&](const Transform3& transform) -> void {
0317     // A Plane created with a specific transform
0318     auto aLine = Surface::makeShared<StrawSurface>(transform, radius, halfZ);
0319 
0320     /// Forward intersection test
0321     Vector3 before = transform * Vector3(-50_cm, -1_m, -1_m);
0322     Vector3 onit1 = transform * Vector3(0_m, 0_m, 0_m);
0323     Vector3 onitP = transform * Vector3(1_cm, 0_m, 23_um);
0324     Vector3 after = transform * Vector3(33_cm, 12_mm, 1_m);
0325     Vector3 outside = transform * Vector3(2., 0., 100_m);
0326 
0327     // Linear transform
0328     auto lTransform = transform.linear();
0329     Vector3 direction = lTransform * Vector3(2_cm, 3_cm, 5_cm).normalized();
0330     Vector3 normalP = lTransform * Vector3(0, 1., 0.).normalized();
0331     Vector3 parallel = lTransform * Vector3(0, 0., 1.).normalized();
0332 
0333     // A random intersection form backward
0334     // Intersect forward
0335     auto fIntersection = aLine->intersect(tgContext, before, direction,
0336                                           BoundaryTolerance::None());
0337     // The intersection MUST be valid
0338     BOOST_CHECK(fIntersection[0].isValid());
0339     // The intersection MUST be reachable
0340     BOOST_CHECK_EQUAL(fIntersection[0].status(), IntersectionStatus::reachable);
0341     // The path length MUST be positive
0342     BOOST_CHECK_GT(fIntersection[0].pathLength(), 0.);
0343     // The intersection MUST be unique
0344     BOOST_CHECK(!fIntersection[1].isValid());
0345 
0346     // On surface intersection - on the straw with random direction
0347     auto oIntersection = aLine->intersect(tgContext, onit1, direction,
0348                                           BoundaryTolerance::None());
0349     // The intersection MUST be valid
0350     BOOST_CHECK(oIntersection[0].isValid());
0351     // The intersection MUST be reachable
0352     BOOST_CHECK_EQUAL(oIntersection[0].status(), IntersectionStatus::onSurface);
0353     // The path length MUST be positive
0354     BOOST_CHECK_LT(std::abs(oIntersection[0].pathLength()),
0355                    s_onSurfaceTolerance);
0356     // The intersection MUST be unique
0357     BOOST_CHECK(!oIntersection[1].isValid());
0358 
0359     // On surface intersecion - on the surface with normal vector
0360     oIntersection =
0361         aLine->intersect(tgContext, onitP, normalP, BoundaryTolerance::None());
0362     // The intersection MUST be valid
0363     BOOST_CHECK(oIntersection[0].isValid());
0364     // The intersection MUST be reachable
0365     BOOST_CHECK_EQUAL(oIntersection[0].status(), IntersectionStatus::onSurface);
0366     // The path length MUST be positive
0367     BOOST_CHECK_LT(std::abs(oIntersection[0].pathLength()),
0368                    s_onSurfaceTolerance);
0369     // The intersection MUST be unique
0370     BOOST_CHECK(!oIntersection[1].isValid());
0371 
0372     // Intersect backwards
0373     auto bIntersection = aLine->intersect(tgContext, after, direction,
0374                                           BoundaryTolerance::None());
0375     // The intersection MUST be valid
0376     BOOST_CHECK(bIntersection[0].isValid());
0377     // The intersection MUST be reachable
0378     BOOST_CHECK_EQUAL(bIntersection[0].status(), IntersectionStatus::reachable);
0379     // The path length MUST be negative
0380     BOOST_CHECK_LT(bIntersection[0].pathLength(), 0.);
0381     // The intersection MUST be unique
0382     BOOST_CHECK(!bIntersection[1].isValid());
0383 
0384     // An out of bounds attempt: missed
0385     auto mIntersection = aLine->intersect(tgContext, outside, direction,
0386                                           BoundaryTolerance::None());
0387     // The intersection MUST NOT be valid
0388     BOOST_CHECK(!mIntersection[0].isValid());
0389     // The intersection MUST be reachable
0390     BOOST_CHECK_EQUAL(mIntersection[0].status(),
0391                       IntersectionStatus::unreachable);
0392     // The path length MUST be negative
0393     BOOST_CHECK_LT(mIntersection[0].pathLength(), 0.);
0394     // The intersection MUST be unique
0395     BOOST_CHECK(!mIntersection[1].isValid());
0396 
0397     // An invalid attempt
0398     auto iIntersection = aLine->intersect(tgContext, before, parallel,
0399                                           BoundaryTolerance::None());
0400     // The intersection MUST NOT be valid
0401     BOOST_CHECK(!iIntersection[0].isValid());
0402     // The intersection MUST be reachable
0403     BOOST_CHECK_EQUAL(iIntersection[0].status(),
0404                       IntersectionStatus::unreachable);
0405     // The intersection MUST be unique
0406     BOOST_CHECK(!iIntersection[1].isValid());
0407   };
0408 
0409   // In a nominal world
0410   testLineAppraoch(Transform3::Identity());
0411 
0412   // In a system somewhere away
0413   testLineAppraoch(aTransform);
0414 }
0415 
0416 BOOST_AUTO_TEST_SUITE_END()
0417 
0418 }  // namespace Acts::Test