Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:11:29

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