Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-16 08:04:01

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/Detector/DetectorVolume.hpp"
0013 #include "Acts/Detector/Portal.hpp"
0014 #include "Acts/Detector/PortalGenerators.hpp"
0015 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0016 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0017 #include "Acts/Geometry/Extent.hpp"
0018 #include "Acts/Geometry/GeometryContext.hpp"
0019 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
0020 #include "Acts/Material/HomogeneousVolumeMaterial.hpp"
0021 #include "Acts/Material/Material.hpp"
0022 #include "Acts/Material/MaterialSlab.hpp"
0023 #include "Acts/Navigation/DetectorVolumeFinders.hpp"
0024 #include "Acts/Navigation/InternalNavigation.hpp"
0025 #include "Acts/Navigation/NavigationState.hpp"
0026 #include "Acts/Surfaces/CylinderBounds.hpp"
0027 #include "Acts/Surfaces/CylinderSurface.hpp"
0028 #include "Acts/Surfaces/PlaneSurface.hpp"
0029 #include "Acts/Surfaces/RectangleBounds.hpp"
0030 #include "Acts/Surfaces/Surface.hpp"
0031 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0032 
0033 #include <cstddef>
0034 #include <memory>
0035 #include <stdexcept>
0036 #include <utility>
0037 #include <vector>
0038 
0039 /// Unpack to shared - simply to test the getSharedPtr mechanism
0040 ///
0041 /// @tparam referenced_type is the type of the referenced object
0042 ///
0043 /// @param rt is the referenced object
0044 ///
0045 /// @returns a shared pointer
0046 template <typename referenced_type>
0047 std::shared_ptr<referenced_type> unpackToShared(referenced_type& rt) {
0048   return rt.getSharedPtr();
0049 }
0050 
0051 using namespace Acts;
0052 using namespace Acts::Experimental;
0053 
0054 GeometryContext tContext;
0055 
0056 namespace ActsTests {
0057 
0058 BOOST_AUTO_TEST_SUITE(DetectorSuite)
0059 
0060 BOOST_AUTO_TEST_CASE(SurfaceVolumeContainment) {
0061   // Create a surface that is placed way off
0062   auto surfaceOutOfBounds = Surface::makeShared<CylinderSurface>(
0063       Transform3::Identity() * Translation3(-1000, 0., 0.),
0064       std::make_shared<CylinderBounds>(1, 1));
0065 
0066   auto vBounds = CuboidVolumeBounds(10.0, 10.0, 10.0);
0067   auto portalGenerator = Experimental::defaultPortalAndSubPortalGenerator();
0068   BOOST_CHECK_THROW(
0069       Experimental::DetectorVolumeFactory::construct(
0070           portalGenerator, GeometryContext(), "CubeWithOutofBoundsSurface",
0071           Transform3::Identity(), std::make_shared<CuboidVolumeBounds>(vBounds),
0072           {surfaceOutOfBounds}, {}, Experimental::tryAllSubVolumes(),
0073           Experimental::tryAllPortalsAndSurfaces(), 1000),
0074       std::invalid_argument);
0075 
0076   // Create a surface that is too big
0077   auto surfaceTooBig = Surface::makeShared<PlaneSurface>(
0078       Transform3::Identity() * Translation3(0, 0., 0.),
0079       std::make_shared<RectangleBounds>(1, 100));
0080 
0081   BOOST_CHECK_THROW(
0082       Experimental::DetectorVolumeFactory::construct(
0083           portalGenerator, GeometryContext(), "CubeWithSurfaceTooBig",
0084           Transform3::Identity(), std::make_shared<CuboidVolumeBounds>(vBounds),
0085           {surfaceTooBig}, {}, Experimental::tryAllSubVolumes(),
0086           Experimental::tryAllPortalsAndSurfaces(), 1000),
0087       std::invalid_argument);
0088 
0089   // Envelope a bigger volume into a smaller one
0090   auto bigVolume = Experimental::DetectorVolumeFactory::construct(
0091       portalGenerator, GeometryContext(), "BigCube", Transform3::Identity(),
0092       std::make_shared<CuboidVolumeBounds>(vBounds), {}, {},
0093       Experimental::tryAllSubVolumes(),
0094       Experimental::tryAllPortalsAndSurfaces(), 1000);
0095 
0096   auto smallBounds = CuboidVolumeBounds(1.0, 1.0, 1.0);
0097   BOOST_CHECK_THROW(Experimental::DetectorVolumeFactory::construct(
0098                         portalGenerator, GeometryContext(),
0099                         "SmallCubeWithBigCubeInside", Transform3::Identity(),
0100                         std::make_shared<CuboidVolumeBounds>(smallBounds), {},
0101                         {bigVolume}, Experimental::tryAllSubVolumes(),
0102                         Experimental::tryAllPortalsAndSurfaces(), 1000),
0103                     std::invalid_argument);
0104 
0105   // Envelope a misaligned subvolume
0106   auto smallVolumeMisaligned = Experimental::DetectorVolumeFactory::construct(
0107       portalGenerator, GeometryContext(), "SmallCubeMisaligned",
0108       Transform3::Identity() * Translation3(9.5, 0., 0.),
0109       std::make_shared<CuboidVolumeBounds>(smallBounds), {}, {},
0110       Experimental::tryAllSubVolumes(),
0111       Experimental::tryAllPortalsAndSurfaces(), 1000);
0112 
0113   BOOST_CHECK_THROW(
0114       Experimental::DetectorVolumeFactory::construct(
0115           portalGenerator, GeometryContext(), "CubeWithMisalignedVolume",
0116           Transform3::Identity(), std::make_shared<CuboidVolumeBounds>(vBounds),
0117           {}, {smallVolumeMisaligned}, Experimental::tryAllSubVolumes(),
0118           Experimental::tryAllPortalsAndSurfaces(), 1000),
0119       std::invalid_argument);
0120 }
0121 
0122 BOOST_AUTO_TEST_CASE(CylindricalDetectorVolumePortals) {
0123   double rInner = 10.;
0124   double rOuter = 100.;
0125   double zHalfL = 200.;
0126 
0127   Transform3 nominal = Transform3::Identity();
0128 
0129   auto fullCylinderBounds =
0130       std::make_unique<CylinderVolumeBounds>(0., rOuter, zHalfL);
0131 
0132   auto portalGenerator = defaultPortalGenerator();
0133 
0134   // Misconfigured - null pointer for bounds
0135   BOOST_CHECK_THROW(
0136       DetectorVolumeFactory::construct(portalGenerator, tContext,
0137                                        "MisconfiguredFullCylinderVolume",
0138                                        nominal, nullptr, tryAllPortals()),
0139       std::invalid_argument);
0140 
0141   // Misconfigured - portal generator not connected
0142   PortalGenerator unconnected;
0143   BOOST_CHECK_THROW(
0144       DetectorVolumeFactory::construct(unconnected, tContext,
0145                                        "MisconfiguredFullCylinderVolume",
0146                                        nominal, nullptr, tryAllPortals()),
0147       std::invalid_argument);
0148 
0149   // A full cylinder
0150   auto fullCylinderVolume = DetectorVolumeFactory::construct(
0151       portalGenerator, tContext, "FullCylinderVolume", nominal,
0152       std::move(fullCylinderBounds), tryAllPortals());
0153 
0154   BOOST_CHECK_EQUAL(fullCylinderVolume,
0155                     unpackToShared<DetectorVolume>(*fullCylinderVolume));
0156   BOOST_CHECK_EQUAL(fullCylinderVolume,
0157                     unpackToShared<const DetectorVolume>(*fullCylinderVolume));
0158 
0159   BOOST_CHECK(fullCylinderVolume->surfaces().empty());
0160   BOOST_CHECK(fullCylinderVolume->volumes().empty());
0161   BOOST_CHECK_EQUAL(fullCylinderVolume->portals().size(), 3u);
0162 
0163   // A tube cylinder
0164   auto tubeCylinderBounds =
0165       std::make_unique<CylinderVolumeBounds>(rInner, rOuter, zHalfL);
0166 
0167   auto tubeCylinderVolume = DetectorVolumeFactory::construct(
0168       portalGenerator, tContext, "TubeCylinderVolume", nominal,
0169       std::move(tubeCylinderBounds), tryAllPortals());
0170 
0171   BOOST_CHECK(tubeCylinderVolume->surfaces().empty());
0172   BOOST_CHECK(tubeCylinderVolume->volumes().empty());
0173   BOOST_CHECK_EQUAL(tubeCylinderVolume->portals().size(), 4u);
0174 
0175   // Let's test the resizing, first inside test: OK
0176   BOOST_CHECK(tubeCylinderVolume->inside(tContext, Vector3(50., 0., 0.)));
0177   // Outside
0178   BOOST_CHECK(!tubeCylinderVolume->inside(tContext, Vector3(150., 0., 0.)));
0179 
0180   // Check the extent
0181   auto volumeExtent = tubeCylinderVolume->extent(tContext, 1);
0182   CHECK_CLOSE_ABS(volumeExtent.min(AxisDirection::AxisR), 10., 10e-5);
0183   CHECK_CLOSE_ABS(volumeExtent.max(AxisDirection::AxisR), 100., 10e-5);
0184   CHECK_CLOSE_ABS(volumeExtent.min(AxisDirection::AxisZ), -200., 10e-5);
0185   CHECK_CLOSE_ABS(volumeExtent.max(AxisDirection::AxisZ), 200., 10e-5);
0186 }
0187 
0188 BOOST_AUTO_TEST_CASE(UpdatePortal) {
0189   Transform3 nominal = Transform3::Identity();
0190 
0191   auto fullCylinderBounds =
0192       std::make_unique<CylinderVolumeBounds>(0., 10., 100.);
0193 
0194   auto portalGenerator = defaultPortalGenerator();
0195 
0196   auto fullCylinderVolume = DetectorVolumeFactory::construct(
0197       portalGenerator, tContext, "FullCylinderVolume", nominal,
0198       std::move(fullCylinderBounds), tryAllPortals());
0199 
0200   auto cylinderSurface =
0201       Surface::makeShared<CylinderSurface>(nominal, 10., 100.);
0202 
0203   auto cylinderPortal = std::make_shared<Experimental::Portal>(cylinderSurface);
0204 
0205   fullCylinderVolume->updatePortal(cylinderPortal, 2u);
0206 
0207   BOOST_CHECK_EQUAL(fullCylinderVolume->portals()[2u], cylinderPortal.get());
0208 }
0209 
0210 BOOST_AUTO_TEST_CASE(CuboidWithCuboid) {
0211   double bigBox = 100.;
0212   double smallBox = 10.;
0213 
0214   Transform3 nominal = Transform3::Identity();
0215 
0216   auto bigBoxBounds =
0217       std::make_unique<CuboidVolumeBounds>(bigBox, bigBox, bigBox);
0218 
0219   auto smallBoxBounds =
0220       std::make_unique<CuboidVolumeBounds>(smallBox, smallBox, smallBox);
0221 
0222   auto portals = defaultPortalGenerator();
0223   auto generatePortalsUpdateInternals = defaultPortalAndSubPortalGenerator();
0224 
0225   // Create the inner box
0226   auto innerBox = DetectorVolumeFactory::construct(
0227       portals, tContext, "InnerBox", nominal, std::move(smallBoxBounds),
0228       tryAllPortals());
0229 
0230   std::vector<std::shared_ptr<Surface>> surfaces = {};
0231   std::vector<std::shared_ptr<Experimental::DetectorVolume>> volumes = {
0232       innerBox};
0233 
0234   // Create the outer box and insert the inner box, use a portal generator
0235   // with sub portal registration
0236   auto outerBox = DetectorVolumeFactory::construct(
0237       generatePortalsUpdateInternals, tContext, "OuterBox", nominal,
0238       std::move(bigBoxBounds), surfaces, volumes, tryAllSubVolumes(),
0239       tryAllPortals());
0240 
0241   // Check that we are within the outer box
0242   Experimental::NavigationState nState;
0243   nState.position = Vector3(-50., 5., 0.);
0244   nState.direction = Vector3(1., 0., 0.);
0245 
0246   BOOST_CHECK(outerBox->inside(tContext, nState.position));
0247   nState.currentVolume = outerBox.get();
0248 
0249   outerBox->updateNavigationState(tContext, nState);
0250 
0251   // We should have 12 candidates, 6 inner, 6 outer portals but only 3 are
0252   // reachable
0253   BOOST_CHECK_EQUAL(nState.surfaceCandidates.size(), 3u);
0254 
0255   // Check surface visiting - const access
0256   // Test the visitor pattern for surfaces
0257   std::size_t nSurfaces = 0;
0258   outerBox->visitSurfaces([&nSurfaces](const auto* s) {
0259     if (s != nullptr) {
0260       nSurfaces++;
0261     }
0262   });
0263   // 6 portlas outer box, 6 portals inner box
0264   BOOST_CHECK_EQUAL(nSurfaces, 12u);
0265 
0266   // Check volume visiting - const access
0267   std::size_t nVolumes = 0;
0268   outerBox->visitVolumes([&nVolumes](const auto* v) {
0269     if (v != nullptr) {
0270       nVolumes++;
0271     }
0272   });
0273   BOOST_CHECK_EQUAL(nVolumes, 2u);
0274 
0275   // Check surface visiting - non-const access
0276   // Test visitor pattern - non-const access
0277   struct SetMaterial {
0278     /// The material to set
0279     std::shared_ptr<const HomogeneousSurfaceMaterial> surfaceMaterial =
0280         std::make_shared<HomogeneousSurfaceMaterial>(
0281             MaterialSlab(Material::fromMolarDensity(1., 2., 3., 4., 5.), 1.));
0282 
0283     std::shared_ptr<HomogeneousVolumeMaterial> volumeMaterial =
0284         std::make_shared<HomogeneousVolumeMaterial>(
0285             Material::fromMolarDensity(1., 2., 3., 4., 5.));
0286 
0287     /// The visitor call: set surface material
0288     void operator()(Surface* s) {
0289       if (s != nullptr) {
0290         s->assignSurfaceMaterial(surfaceMaterial);
0291       }
0292     }
0293 
0294     /// The visitor call : set volume material
0295     void operator()(DetectorVolume* v) {
0296       if (v != nullptr) {
0297         v->assignVolumeMaterial(volumeMaterial);
0298       }
0299     }
0300   };
0301 
0302   SetMaterial setMaterial;
0303   outerBox->visitMutableSurfaces(setMaterial);
0304   outerBox->visitMutableVolumes(setMaterial);
0305 
0306   // Count surfaces with material
0307   std::size_t nSurfacesWithMaterial = 0;
0308   outerBox->visitSurfaces([&nSurfacesWithMaterial](const auto* s) {
0309     if (s != nullptr && s->surfaceMaterial() != nullptr) {
0310       nSurfacesWithMaterial++;
0311     }
0312   });
0313   BOOST_CHECK_EQUAL(nSurfacesWithMaterial, 12u);
0314 
0315   // Count volumes with material
0316   std::size_t nVolumesWithMaterial = 0;
0317   outerBox->visitVolumes([&nVolumesWithMaterial](const auto* v) {
0318     if (v != nullptr && v->volumeMaterial() != nullptr) {
0319       nVolumesWithMaterial++;
0320     }
0321   });
0322   BOOST_CHECK_EQUAL(nVolumesWithMaterial, 2u);
0323 }
0324 
0325 BOOST_AUTO_TEST_CASE(CylinderWithSurfacesTestExtractors) {
0326   auto portalGenerator = defaultPortalGenerator();
0327 
0328   std::vector<double> radii = {100, 102, 104, 106, 108, 110};
0329   auto cylinderVoumeBounds =
0330       std::make_unique<CylinderVolumeBounds>(80, 130, 200);
0331   std::vector<std::shared_ptr<Surface>> surfaces = {};
0332   for (const auto& r : radii) {
0333     surfaces.push_back(Surface::makeShared<CylinderSurface>(
0334         Transform3::Identity(), std::make_shared<CylinderBounds>(r, 190)));
0335   }
0336 
0337   // A full cylinder
0338   auto cylinderVolume = DetectorVolumeFactory::construct(
0339       portalGenerator, tContext, "CylinderVolume", Transform3::Identity(),
0340       std::move(cylinderVoumeBounds), surfaces, {}, tryNoVolumes(),
0341       tryAllPortalsAndSurfaces());
0342 
0343   // The navigation state
0344   NavigationState nState;
0345   AllPortalsExtractor allPortals;
0346   AllSurfacesExtractor allSurfaces;
0347   IndexedSurfacesExtractor indexedSurfaces;
0348 
0349   // First check exception behaviour
0350   BOOST_CHECK_THROW(allPortals.extract(tContext, nState), std::runtime_error);
0351   BOOST_CHECK_THROW(allSurfaces.extract(tContext, nState), std::runtime_error);
0352   BOOST_CHECK_THROW(indexedSurfaces.extract(tContext, nState, {0u, 1u}),
0353                     std::runtime_error);
0354 
0355   // A volume needs to be set
0356   nState.currentVolume = cylinderVolume.get();
0357 
0358   // This extracts all portals as candidates
0359   auto eportals = allPortals.extract(tContext, nState);
0360   BOOST_CHECK_EQUAL(eportals.size(), 4u);
0361 
0362   auto esurfaces = allSurfaces.extract(tContext, nState);
0363   BOOST_CHECK_EQUAL(esurfaces.size(), 6u);
0364 
0365   esurfaces = indexedSurfaces.extract(tContext, nState, {2u, 4u});
0366   BOOST_CHECK_EQUAL(esurfaces.size(), 2u);
0367   BOOST_CHECK_EQUAL(esurfaces[0u], surfaces[2u].get());
0368   BOOST_CHECK_EQUAL(esurfaces[1u], surfaces[4u].get());
0369 
0370   // Test the visitor pattern for surfaces
0371   struct CountSurfaces {
0372     unsigned int counter = 0;
0373 
0374     void operator()(const Surface* s) {
0375       if (s != nullptr) {
0376         counter++;
0377       }
0378     }
0379   };
0380 
0381   CountSurfaces countSurfaces;
0382   cylinderVolume->visitSurfaces(countSurfaces);
0383 
0384   // 6 internal surfaces, 4 portals -> 10 surfaces counted
0385   BOOST_CHECK_EQUAL(countSurfaces.counter, 10u);
0386 }
0387 
0388 BOOST_AUTO_TEST_SUITE_END()
0389 
0390 }  // namespace ActsTests