Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:12: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/data/test_case.hpp>
0010 #include <boost/test/unit_test.hpp>
0011 
0012 #include "Acts/Definitions/Algebra.hpp"
0013 #include "Acts/Definitions/Direction.hpp"
0014 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0015 #include "Acts/Geometry/GeometryContext.hpp"
0016 #include "Acts/Geometry/VolumeBounds.hpp"
0017 #include "Acts/Surfaces/CylinderBounds.hpp"
0018 #include "Acts/Surfaces/RadialBounds.hpp"
0019 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0020 #include "Acts/Utilities/BinningType.hpp"
0021 #include "Acts/Utilities/BoundingBox.hpp"
0022 
0023 #include <algorithm>
0024 #include <array>
0025 #include <cmath>
0026 #include <memory>
0027 #include <numbers>
0028 #include <stdexcept>
0029 #include <vector>
0030 
0031 namespace bdata = boost::unit_test::data;
0032 
0033 namespace Acts::Test {
0034 
0035 BOOST_AUTO_TEST_SUITE(Geometry)
0036 
0037 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsConstruction) {
0038   double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{std::numbers::pi / 4.},
0039       avgphi{0.};
0040 
0041   // Test different construction modes: solid
0042   CylinderVolumeBounds solidCylinder(0., rmax, halfz);
0043   BOOST_CHECK_EQUAL(solidCylinder.orientedSurfaces().size(), 3);
0044 
0045   // Test different construction modes: sectoral solid
0046   CylinderVolumeBounds solidCylinderSector(0., rmax, halfz, halfphi);
0047   BOOST_CHECK_EQUAL(solidCylinderSector.orientedSurfaces().size(), 5);
0048 
0049   // Test different construction modes: tube
0050   CylinderVolumeBounds tubeCylinder(rmin, rmax, halfz);
0051   BOOST_CHECK_EQUAL(tubeCylinder.orientedSurfaces().size(), 4);
0052 
0053   // Test different construction modes: sectoral tube
0054   CylinderVolumeBounds tubeCylinderSector(rmin, rmax, halfz, halfphi);
0055   BOOST_CHECK_EQUAL(tubeCylinderSector.orientedSurfaces().size(), 6);
0056 
0057   CylinderVolumeBounds original(rmin, rmax, halfz, halfphi, avgphi);
0058 
0059   // Test construction from CylinderBounds and thickness
0060   double rmed = 0.5 * (rmin + rmax);
0061   double rthickness = (rmax - rmin);
0062   CylinderBounds cBounds(rmed, halfz, halfphi, avgphi);
0063   CylinderVolumeBounds fromCylinder(cBounds, rthickness);
0064   BOOST_CHECK_EQUAL(original, fromCylinder);
0065 
0066   // Test construction from RadialBounds and thickness
0067   RadialBounds rBounds(rmin, rmax, halfphi, avgphi);
0068   CylinderVolumeBounds fromDisc(rBounds, 2 * halfz);
0069   BOOST_CHECK_EQUAL(original, fromDisc);
0070 
0071   // Test the copy construction
0072   CylinderVolumeBounds copied(original);
0073   BOOST_CHECK_EQUAL(original, copied);
0074 
0075   // Test the assignment
0076   CylinderVolumeBounds assigned = original;
0077   BOOST_CHECK_EQUAL(original, assigned);
0078 }
0079 
0080 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsRecreation) {
0081   double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{std::numbers::pi / 4.},
0082       avgphi{0.};
0083 
0084   CylinderVolumeBounds original(rmin, rmax, halfz, halfphi, avgphi);
0085   std::array<double, CylinderVolumeBounds::eSize> values{};
0086   std::vector<double> valvector = original.values();
0087   std::copy_n(valvector.begin(), CylinderVolumeBounds::eSize, values.begin());
0088   CylinderVolumeBounds recreated(values);
0089   BOOST_CHECK_EQUAL(original, recreated);
0090 }
0091 
0092 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsExceptions) {
0093   double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{std::numbers::pi / 4.},
0094       avgphi{0.};
0095 
0096   // Negative inner radius
0097   BOOST_CHECK_THROW(CylinderVolumeBounds(-rmin, rmax, halfz, halfphi, avgphi),
0098                     std::logic_error);
0099 
0100   // Negative outer radius
0101   BOOST_CHECK_THROW(CylinderVolumeBounds(rmin, -rmax, halfz, halfphi, avgphi),
0102                     std::logic_error);
0103 
0104   // Swapped radii
0105   BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, halfz, halfphi, avgphi),
0106                     std::logic_error);
0107 
0108   // Zero half length
0109   BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, 0., halfphi, avgphi),
0110                     std::logic_error);
0111 
0112   // Negative half length
0113   BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, -halfz, halfphi, avgphi),
0114                     std::logic_error);
0115 
0116   // Out of bounds half phi
0117   BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, halfz, -4., avgphi),
0118                     std::logic_error);
0119 
0120   // Wrong positioning phi
0121   BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, halfz, halfphi, 4.),
0122                     std::logic_error);
0123 
0124   // Test construction from CylinderBounds and thickness
0125   double rmed = 0.5 * (rmin + rmax);
0126   CylinderBounds cBounds(rmed, halfz, halfphi, avgphi);
0127   RadialBounds rBounds(rmin, rmax, halfphi, avgphi);
0128 
0129   // Negative thickness
0130   BOOST_CHECK_THROW(CylinderVolumeBounds(cBounds, -1.), std::logic_error);
0131 
0132   // Wrong thickness
0133   BOOST_CHECK_THROW(CylinderVolumeBounds(cBounds, 1000.), std::logic_error);
0134 
0135   // Test construction from RadialBounds and thickness
0136   BOOST_CHECK_THROW(CylinderVolumeBounds(rBounds, -1), std::logic_error);
0137 }
0138 
0139 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsAccess) {
0140   double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{std::numbers::pi / 4.},
0141       avgphi{0.};
0142   CylinderVolumeBounds cvBounds(rmin, rmax, halfz, halfphi, avgphi);
0143 
0144   // Test the accessors
0145   BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eMinR), rmin);
0146   BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eMaxR), rmax);
0147   BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eHalfLengthZ), halfz);
0148   BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eHalfPhiSector),
0149                     halfphi);
0150   BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eAveragePhi), avgphi);
0151 }
0152 
0153 /// Unit test for testing the orientedSurfaces() function
0154 BOOST_DATA_TEST_CASE(
0155     CylinderVolumeBoundsOrientedSurfaces,
0156     bdata::random((bdata::engine = std::mt19937(), bdata::seed = 1,
0157                    bdata::distribution = std::uniform_real_distribution<double>(
0158                        -std::numbers::pi, std::numbers::pi))) ^
0159         bdata::random(
0160             (bdata::engine = std::mt19937(), bdata::seed = 2,
0161              bdata::distribution = std::uniform_real_distribution<double>(
0162                  -std::numbers::pi, std::numbers::pi))) ^
0163         bdata::random(
0164             (bdata::engine = std::mt19937(), bdata::seed = 3,
0165              bdata::distribution = std::uniform_real_distribution<double>(
0166                  -std::numbers::pi, std::numbers::pi))) ^
0167         bdata::random((bdata::engine = std::mt19937(), bdata::seed = 4,
0168                        bdata::distribution =
0169                            std::uniform_real_distribution<double>(-10., 10.))) ^
0170         bdata::random((bdata::engine = std::mt19937(), bdata::seed = 5,
0171                        bdata::distribution =
0172                            std::uniform_real_distribution<double>(-10., 10.))) ^
0173         bdata::random((bdata::engine = std::mt19937(), bdata::seed = 6,
0174                        bdata::distribution =
0175                            std::uniform_real_distribution<double>(-10., 10.))) ^
0176         bdata::xrange(100),
0177     alpha, beta, gamma, posX, posY, posZ, index) {
0178   (void)index;
0179 
0180   // Create a test context
0181   GeometryContext tgContext = GeometryContext();
0182 
0183   // position of volume
0184   const Vector3 pos(posX, posY, posZ);
0185   // rotation around x axis
0186   AngleAxis3 rotX(alpha, Vector3(1., 0., 0.));
0187   // rotation around y axis
0188   AngleAxis3 rotY(beta, Vector3(0., 1., 0.));
0189   // rotation around z axis
0190   AngleAxis3 rotZ(gamma, Vector3(0., 0., 1.));
0191 
0192   // create the cylinder bounds
0193   double rmin = 1.;
0194   double rmax = 2.;
0195   double halfz = 3.;
0196   CylinderVolumeBounds cylBounds(rmin, rmax, halfz);
0197   // create the transformation matrix
0198   auto transform = Transform3(Translation3(pos));
0199   transform *= rotZ;
0200   transform *= rotY;
0201   transform *= rotX;
0202   // get the boundary surfaces
0203   auto boundarySurfaces = cylBounds.orientedSurfaces(transform);
0204   // Test
0205 
0206   // check if difference is halfZ - sign and direction independent
0207   CHECK_CLOSE_REL(
0208       (pos - boundarySurfaces.at(0).surface->center(tgContext)).norm(),
0209       cylBounds.get(CylinderVolumeBounds::eHalfLengthZ), 1e-12);
0210   CHECK_CLOSE_REL(
0211       (pos - boundarySurfaces.at(1).surface->center(tgContext)).norm(),
0212       cylBounds.get(CylinderVolumeBounds::eHalfLengthZ), 1e-12);
0213   // transform to local
0214   double posDiscPosZ =
0215       (transform.inverse() * boundarySurfaces.at(1).surface->center(tgContext))
0216           .z();
0217   double centerPosZ = (transform.inverse() * pos).z();
0218   double negDiscPosZ =
0219       (transform.inverse() * boundarySurfaces.at(0).surface->center(tgContext))
0220           .z();
0221   // check if center of disc boundaries lies in the middle in z
0222   BOOST_CHECK_LT(centerPosZ, posDiscPosZ);
0223   BOOST_CHECK_GT(centerPosZ, negDiscPosZ);
0224   // check positions of disc boundarysurfaces
0225   // checks for zero value. double precision value is not exact.
0226   CHECK_CLOSE_ABS(
0227       negDiscPosZ + cylBounds.get(CylinderVolumeBounds::eHalfLengthZ),
0228       centerPosZ, 1e-12);
0229   CHECK_CLOSE_ABS(
0230       posDiscPosZ - cylBounds.get(CylinderVolumeBounds::eHalfLengthZ),
0231       centerPosZ, 1e-12);
0232   // orientation of disc surfaces
0233   // positive disc durface should point in positive direction in the frame of
0234   // the volume
0235   CHECK_CLOSE_REL(
0236       transform.rotation().col(2).dot(boundarySurfaces.at(1).surface->normal(
0237           tgContext, Acts::Vector2(0., 0.))),
0238       1., 1e-12);
0239   // negative disc durface should point in positive direction in the frame of
0240   // the volume
0241   CHECK_CLOSE_REL(
0242       transform.rotation().col(2).dot(boundarySurfaces.at(0).surface->normal(
0243           tgContext, Acts::Vector2(0., 0.))),
0244       1., 1e-12);
0245   // test in r
0246   CHECK_CLOSE_REL(boundarySurfaces.at(3).surface->center(tgContext), pos,
0247                   1e-12);
0248   CHECK_CLOSE_REL(boundarySurfaces.at(2).surface->center(tgContext), pos,
0249                   1e-12);
0250 }
0251 
0252 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsBoundingBox) {
0253   GeometryContext tgContext = GeometryContext();
0254 
0255   float tol = 1e-4;
0256 
0257   CylinderVolumeBounds cvb(0., 5, 10);
0258   auto bb = cvb.boundingBox();
0259 
0260   Transform3 rot;
0261   rot = AngleAxis3(std::numbers::pi / 2., Vector3::UnitX());
0262 
0263   BOOST_CHECK_EQUAL(bb.entity(), nullptr);
0264   BOOST_CHECK_EQUAL(bb.max(), Vector3(5, 5, 10));
0265   BOOST_CHECK_EQUAL(bb.min(), Vector3(-5, -5, -10));
0266 
0267   bb = cvb.boundingBox(&rot);
0268   BOOST_CHECK_EQUAL(bb.entity(), nullptr);
0269   CHECK_CLOSE_ABS(bb.max(), Vector3(5, 10, 5), tol);
0270   CHECK_CLOSE_ABS(bb.min(), Vector3(-5, -10, -5), tol);
0271 
0272   cvb = CylinderVolumeBounds(5, 8, 12);
0273   bb = cvb.boundingBox();
0274   BOOST_CHECK_EQUAL(bb.entity(), nullptr);
0275   BOOST_CHECK_EQUAL(bb.max(), Vector3(8, 8, 12));
0276   BOOST_CHECK_EQUAL(bb.min(), Vector3(-8, -8, -12));
0277 
0278   double angle = std::numbers::pi / 8.;
0279   cvb = CylinderVolumeBounds(5, 8, 13, angle);
0280   bb = cvb.boundingBox();
0281   BOOST_CHECK_EQUAL(bb.entity(), nullptr);
0282   CHECK_CLOSE_ABS(bb.max(), Vector3(8, 8 * std::sin(angle), 13), tol);
0283   CHECK_CLOSE_ABS(bb.min(),
0284                   Vector3(5 * std::cos(angle), -8 * std::sin(angle), -13), tol);
0285 
0286   rot = AngleAxis3(std::numbers::pi / 2., Vector3::UnitZ());
0287   bb = cvb.boundingBox(&rot);
0288   BOOST_CHECK_EQUAL(bb.entity(), nullptr);
0289   CHECK_CLOSE_ABS(bb.max(), Vector3(8 * std::sin(angle), 8, 13), tol);
0290   CHECK_CLOSE_ABS(bb.min(),
0291                   Vector3(-8 * std::sin(angle), 5 * std::cos(angle), -13), tol);
0292 
0293   rot = AngleAxis3(std::numbers::pi / 2., Vector3(-2, 4, 5).normalized());
0294   bb = cvb.boundingBox(&rot);
0295   BOOST_CHECK_EQUAL(bb.entity(), nullptr);
0296   CHECK_CLOSE_ABS(bb.max(), Vector3(8.40007, 15.2828, 3.88911), tol);
0297   CHECK_CLOSE_ABS(bb.min(), Vector3(-7.27834, -8.12028, -14.2182), tol);
0298 }
0299 
0300 BOOST_AUTO_TEST_CASE(CylinderVolumeOrientedBoundaries) {
0301   GeometryContext tgContext = GeometryContext();
0302 
0303   CylinderVolumeBounds cvb(5, 10, 20);
0304 
0305   auto cvbOrientedSurfaces = cvb.orientedSurfaces(Transform3::Identity());
0306   BOOST_CHECK_EQUAL(cvbOrientedSurfaces.size(), 4);
0307 
0308   auto geoCtx = GeometryContext();
0309   Vector3 xaxis(1., 0., 0.);
0310   Vector3 yaxis(0., 1., 0.);
0311   Vector3 zaxis(0., 0., 1.);
0312 
0313   for (auto& os : cvbOrientedSurfaces) {
0314     auto onSurface =
0315         os.surface->referencePosition(geoCtx, AxisDirection::AxisR);
0316     auto locPos =
0317         os.surface->globalToLocal(geoCtx, onSurface, Vector3::Zero()).value();
0318     auto osNormal = os.surface->normal(geoCtx, locPos);
0319     // Check if you step inside the volume with the oriented normal
0320     Vector3 insideCvb = onSurface + os.direction * osNormal;
0321     Vector3 outsideCvb = onSurface - os.direction * osNormal;
0322 
0323     BOOST_CHECK(cvb.inside(insideCvb));
0324     BOOST_CHECK(!cvb.inside(outsideCvb));
0325 
0326     // Test the orientation of the boundary surfaces
0327     auto rot = os.surface->transform(geoCtx).rotation();
0328     BOOST_CHECK(rot.col(0).isApprox(xaxis));
0329     BOOST_CHECK(rot.col(1).isApprox(yaxis));
0330     BOOST_CHECK(rot.col(2).isApprox(zaxis));
0331   }
0332 }
0333 
0334 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsSetValues) {
0335   CylinderVolumeBounds cyl(100, 300, 200);
0336 
0337   BOOST_CHECK_THROW(cyl.set(CylinderVolumeBounds::eMinR, 400),
0338                     std::invalid_argument);
0339   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eMinR), 100);
0340 
0341   cyl.set(CylinderVolumeBounds::eMinR, 200);
0342   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eMinR), 200);
0343 
0344   BOOST_CHECK_THROW(cyl.set(CylinderVolumeBounds::eMaxR, 50),
0345                     std::invalid_argument);
0346   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eMaxR), 300);
0347 
0348   cyl.set(CylinderVolumeBounds::eMaxR, 250);
0349   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eMaxR), 250);
0350 
0351   BOOST_CHECK_THROW(cyl.set(CylinderVolumeBounds::eHalfLengthZ, -200),
0352                     std::invalid_argument);
0353   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfLengthZ), 200);
0354 
0355   cyl.set(CylinderVolumeBounds::eHalfLengthZ, 250);
0356   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfLengthZ), 250);
0357 
0358   cyl.set(CylinderVolumeBounds::eHalfLengthZ, 150);
0359   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfLengthZ), 150);
0360 
0361   BOOST_CHECK_THROW(
0362       cyl.set(CylinderVolumeBounds::eHalfPhiSector, -std::numbers::pi),
0363       std::invalid_argument);
0364   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfPhiSector),
0365                     std::numbers::pi);
0366 
0367   BOOST_CHECK_THROW(
0368       cyl.set(CylinderVolumeBounds::eHalfPhiSector, 1.5 * std::numbers::pi),
0369       std::invalid_argument);
0370   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfPhiSector),
0371                     std::numbers::pi);
0372 
0373   cyl.set(CylinderVolumeBounds::eHalfPhiSector, std::numbers::pi / 2.);
0374   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfPhiSector),
0375                     std::numbers::pi / 2.);
0376 
0377   for (auto bValue :
0378        {CylinderVolumeBounds::eAveragePhi, CylinderVolumeBounds::eBevelMaxZ,
0379         CylinderVolumeBounds::eBevelMinZ}) {
0380     BOOST_CHECK_THROW(cyl.set(bValue, -1.5 * std::numbers::pi),
0381                       std::invalid_argument);
0382     BOOST_CHECK_EQUAL(cyl.get(bValue), 0);
0383 
0384     BOOST_CHECK_THROW(cyl.set(bValue, 1.5 * std::numbers::pi),
0385                       std::invalid_argument);
0386     BOOST_CHECK_EQUAL(cyl.get(bValue), 0);
0387 
0388     cyl.set(bValue, std::numbers::pi / 2.);
0389     BOOST_CHECK_EQUAL(cyl.get(bValue), std::numbers::pi / 2.);
0390     cyl.set(bValue, -std::numbers::pi / 2.);
0391     BOOST_CHECK_EQUAL(cyl.get(bValue), -std::numbers::pi / 2.);
0392   }
0393 
0394   cyl = CylinderVolumeBounds(100, 300, 200);
0395   auto previous = cyl.values();
0396 
0397   BOOST_CHECK_THROW(cyl.set({
0398                         {CylinderVolumeBounds::eMinR, 50},
0399                         {CylinderVolumeBounds::eMaxR, 200},
0400                         {CylinderVolumeBounds::eHalfLengthZ, -1},
0401                     }),
0402                     std::logic_error);
0403   auto act = cyl.values();
0404   BOOST_CHECK_EQUAL_COLLECTIONS(previous.begin(), previous.end(), act.begin(),
0405                                 act.end());
0406 
0407   cyl.set({
0408       {CylinderVolumeBounds::eMinR, 50},
0409       {CylinderVolumeBounds::eMaxR, 200},
0410       {CylinderVolumeBounds::eHalfLengthZ, 150},
0411   });
0412 
0413   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eMinR), 50);
0414   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eMaxR), 200);
0415   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfLengthZ), 150);
0416   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eHalfPhiSector),
0417                     std::numbers::pi);
0418   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eAveragePhi), 0);
0419   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eBevelMinZ), 0);
0420   BOOST_CHECK_EQUAL(cyl.get(CylinderVolumeBounds::eBevelMaxZ), 0);
0421 }
0422 
0423 BOOST_AUTO_TEST_SUITE_END()
0424 
0425 }  // namespace Acts::Test