Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-21 08:04:04

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/Direction.hpp"
0013 #include "Acts/Detector/DetectorVolume.hpp"
0014 #include "Acts/Detector/Portal.hpp"
0015 #include "Acts/Detector/PortalGenerators.hpp"
0016 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0017 #include "Acts/Geometry/GeometryContext.hpp"
0018 #include "Acts/Geometry/GeometryIdentifier.hpp"
0019 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
0020 #include "Acts/Material/MaterialSlab.hpp"
0021 #include "Acts/Navigation/InternalNavigation.hpp"
0022 #include "Acts/Navigation/NavigationDelegates.hpp"
0023 #include "Acts/Navigation/NavigationState.hpp"
0024 #include "Acts/Surfaces/PlaneSurface.hpp"
0025 #include "Acts/Surfaces/RectangleBounds.hpp"
0026 #include "Acts/Surfaces/Surface.hpp"
0027 
0028 #include <array>
0029 #include <memory>
0030 #include <stdexcept>
0031 #include <utility>
0032 #include <vector>
0033 
0034 namespace Acts::Experimental {
0035 
0036 /// a simple link to volume struct
0037 class LinkToVolumeImpl : public IExternalNavigation {
0038  public:
0039   std::shared_ptr<DetectorVolume> dVolume = nullptr;
0040 
0041   /// Constructor from volume
0042   explicit LinkToVolumeImpl(std::shared_ptr<DetectorVolume> dv)
0043       : dVolume(std::move(dv)) {}
0044 
0045   /// @return the link to the contained volume
0046   /// @note the parameters are ignored
0047   void link(const GeometryContext& /*gctx*/, NavigationState& nState) const {
0048     nState.currentVolume = dVolume.get();
0049   }
0050 };
0051 
0052 }  // namespace Acts::Experimental
0053 
0054 using namespace Acts;
0055 using namespace Acts::Experimental;
0056 
0057 // A test context
0058 GeometryContext tContext;
0059 
0060 namespace ActsTests {
0061 
0062 BOOST_AUTO_TEST_SUITE(DetectorSuite)
0063 
0064 BOOST_AUTO_TEST_CASE(PortalTest) {
0065   auto dTransform = Transform3::Identity();
0066   auto pGenerator = defaultPortalGenerator();
0067   auto volumeA = DetectorVolumeFactory::construct(
0068       pGenerator, tContext, "dummyA", dTransform,
0069       std::make_unique<CuboidVolumeBounds>(1, 1, 1),
0070       tryAllPortalsAndSurfaces());
0071   auto volumeB = DetectorVolumeFactory::construct(
0072       pGenerator, tContext, "dummyB", dTransform,
0073       std::make_unique<CuboidVolumeBounds>(1, 1, 1),
0074       tryAllPortalsAndSurfaces());
0075 
0076   // A rectangle bound surface
0077   auto rectangle = std::make_shared<RectangleBounds>(10., 100.);
0078   auto surface = Surface::makeShared<PlaneSurface>(dTransform, rectangle);
0079 
0080   // Create a portal out of it
0081   auto portalA = std::make_shared<Experimental::Portal>(surface);
0082 
0083   BOOST_CHECK_EQUAL(&(portalA->surface()), surface.get());
0084 
0085   portalA->assignGeometryId(GeometryIdentifier{5});
0086   BOOST_CHECK_EQUAL(portalA->surface().geometryId(), GeometryIdentifier{5});
0087 
0088   // Create a links to volumes
0089   auto linkToAImpl = std::make_unique<const LinkToVolumeImpl>(volumeA);
0090   ExternalNavigationDelegate linkToA;
0091   linkToA.connect<&LinkToVolumeImpl::link>(std::move(linkToAImpl));
0092   portalA->assignPortalNavigation(Direction::Positive(), std::move(linkToA),
0093                                   {volumeA});
0094 
0095   auto attachedDetectorVolumes = portalA->attachedDetectorVolumes();
0096   BOOST_CHECK(attachedDetectorVolumes[0u].empty());
0097   BOOST_CHECK_EQUAL(attachedDetectorVolumes[1u].size(), 1u);
0098   BOOST_CHECK_EQUAL(attachedDetectorVolumes[1u][0u], volumeA);
0099 
0100   NavigationState nState;
0101   nState.position = Vector3(0., 0., 0.);
0102   nState.direction = Vector3(0., 0., 1.);
0103   // The next volume in positive should be volume A
0104   portalA->updateDetectorVolume(tContext, nState);
0105   BOOST_CHECK_EQUAL(nState.currentVolume, volumeA.get());
0106   // negative should yield nullptr
0107   nState.direction = Vector3(0., 0., -1.);
0108   portalA->updateDetectorVolume(tContext, nState);
0109   BOOST_CHECK_EQUAL(nState.currentVolume, nullptr);
0110 
0111   auto portalB = std::make_shared<Experimental::Portal>(surface);
0112   ExternalNavigationDelegate linkToB;
0113   auto linkToBImpl = std::make_unique<const LinkToVolumeImpl>(volumeB);
0114   linkToB.connect<&LinkToVolumeImpl::link>(std::move(linkToBImpl));
0115   portalB->assignPortalNavigation(Direction::Negative(), std::move(linkToB),
0116                                   {volumeB});
0117 
0118   // Reverse: positive volume nullptr, negative volume volumeB
0119   nState.direction = Vector3(0., 0., 1.);
0120   portalB->updateDetectorVolume(tContext, nState);
0121   BOOST_CHECK_EQUAL(nState.currentVolume, nullptr);
0122   nState.direction = Vector3(0., 0., -1.);
0123   portalB->updateDetectorVolume(tContext, nState);
0124   BOOST_CHECK_EQUAL(nState.currentVolume, volumeB.get());
0125 
0126   GeometryContext gctx;
0127   BOOST_CHECK_EQUAL(portalA->surface().center(gctx),
0128                     portalB->surface().center(gctx));
0129 
0130   // Fuse with itself, nothing happens
0131   BOOST_CHECK_EQUAL(portalA, Experimental::Portal::fuse(portalA, portalA));
0132 
0133   // Now fuse the portals together, both links valid
0134   portalA = Experimental::Portal::fuse(portalA, portalB);
0135 
0136   nState.direction = Vector3(0., 0., 1.);
0137   portalA->updateDetectorVolume(tContext, nState);
0138   BOOST_CHECK_EQUAL(nState.currentVolume, volumeA.get());
0139   nState.direction = Vector3(0., 0., -1.);
0140   portalA->updateDetectorVolume(tContext, nState);
0141   BOOST_CHECK_EQUAL(nState.currentVolume, volumeB.get());
0142 
0143   // Portal A retains identical position to B
0144   BOOST_CHECK_EQUAL(portalA->surface().center(gctx),
0145                     portalB->surface().center(gctx));
0146 
0147   // Test visitor pattern - const access
0148   bool reached = false;
0149   const Experimental::Portal* cportalB = portalB.get();
0150   cportalB->visitSurface([&reached](const auto* s) {
0151     if (s != nullptr) {
0152       reached = true;
0153     }
0154   });
0155   BOOST_CHECK(reached);
0156 
0157   // Test visitor pattern - non-const access
0158   struct SetMaterial {
0159     /// The material to set
0160     std::shared_ptr<const HomogeneousSurfaceMaterial> material =
0161         std::make_shared<HomogeneousSurfaceMaterial>(
0162             MaterialSlab(Material::fromMolarDensity(1., 2., 3., 4., 5.), 1.));
0163     /// The visitor call
0164     void operator()(Surface* s) {
0165       if (s != nullptr) {
0166         s->assignSurfaceMaterial(material);
0167       }
0168     }
0169   };
0170 
0171   SetMaterial setMaterial;
0172   BOOST_CHECK(portalA->surface().surfaceMaterial() == nullptr);
0173   portalA->visitMutableSurface(setMaterial);
0174   BOOST_CHECK(portalA->surface().surfaceMaterial() ==
0175               setMaterial.material.get());
0176 }
0177 
0178 BOOST_AUTO_TEST_CASE(PortalMaterialTest) {
0179   // Volume A and B
0180   auto dTransform = Transform3::Identity();
0181   auto pGenerator = defaultPortalGenerator();
0182   auto volumeA = DetectorVolumeFactory::construct(
0183       pGenerator, tContext, "dummyA", dTransform,
0184       std::make_unique<CuboidVolumeBounds>(1, 1, 1),
0185       tryAllPortalsAndSurfaces());
0186   auto volumeB = DetectorVolumeFactory::construct(
0187       pGenerator, tContext, "dummyB", dTransform,
0188       std::make_unique<CuboidVolumeBounds>(1, 1, 1),
0189       tryAllPortalsAndSurfaces());
0190 
0191   // Create some material
0192   auto materialSlab =
0193       MaterialSlab(Material::fromMolarDensity(1., 2., 3., 4., 5.), 1.);
0194   auto materialA = std::make_shared<HomogeneousSurfaceMaterial>(materialSlab);
0195   auto materialB = std::make_shared<HomogeneousSurfaceMaterial>(materialSlab);
0196 
0197   // A few portals
0198   auto rectangle = std::make_shared<RectangleBounds>(10., 100.);
0199 
0200   auto surfaceA =
0201       Surface::makeShared<PlaneSurface>(Transform3::Identity(), rectangle);
0202   surfaceA->assignSurfaceMaterial(materialA);
0203   auto portalA = std::make_shared<Experimental::Portal>(surfaceA);
0204 
0205   ExternalNavigationDelegate linkToA;
0206   auto linkToAImpl = std::make_unique<const LinkToVolumeImpl>(volumeA);
0207   linkToA.connect<&LinkToVolumeImpl::link>(std::move(linkToAImpl));
0208   portalA->assignPortalNavigation(Direction::Positive(), std::move(linkToA),
0209                                   {volumeA});
0210 
0211   auto surfaceB =
0212       Surface::makeShared<PlaneSurface>(Transform3::Identity(), rectangle);
0213   auto portalB = std::make_shared<Experimental::Portal>(surfaceB);
0214   ExternalNavigationDelegate linkToB;
0215   auto linkToBImpl = std::make_unique<const LinkToVolumeImpl>(volumeB);
0216   linkToB.connect<&LinkToVolumeImpl::link>(std::move(linkToBImpl));
0217   portalB->assignPortalNavigation(Direction::Negative(), std::move(linkToB),
0218                                   {volumeB});
0219 
0220   // Portal A fuses with B
0221   // - has material and keeps it
0222   portalA = Experimental::Portal::fuse(portalA, portalB);
0223   BOOST_CHECK_EQUAL(portalA->surface().surfaceMaterial(), materialA.get());
0224 
0225   // Remake portal B
0226   portalB = std::make_shared<Experimental::Portal>(surfaceB);
0227   ExternalNavigationDelegate linkToB2;
0228   auto linkToB2Impl = std::make_unique<const LinkToVolumeImpl>(volumeB);
0229   linkToB2.connect<&LinkToVolumeImpl::link>(std::move(linkToB2Impl));
0230   portalB->assignPortalNavigation(Direction::Negative(), std::move(linkToB2),
0231                                   {volumeB});
0232 
0233   // Portal B fuses with A
0234   // - A has material, portal B gets it from A
0235   BOOST_REQUIRE_NE(portalA, portalB);
0236 
0237   // This fails because A has accumulated volumes on both sides through fusing
0238   BOOST_CHECK_THROW(Experimental::Portal::fuse(portalB, portalA),
0239                     std::invalid_argument);
0240   // Remove Negative volume on A
0241   portalA->assignPortalNavigation(Direction::Negative(),
0242                                   ExternalNavigationDelegate{}, {});
0243 
0244   portalB = Experimental::Portal::fuse(portalB, portalA);
0245   BOOST_CHECK_EQUAL(portalB->surface().surfaceMaterial(), materialA.get());
0246 
0247   // Remake portal A and B, this time both with material
0248   portalA = std::make_shared<Experimental::Portal>(surfaceA);
0249   ExternalNavigationDelegate linkToA2;
0250   auto linkToA2Impl = std::make_unique<const LinkToVolumeImpl>(volumeA);
0251   linkToA2.connect<&LinkToVolumeImpl::link>(std::move(linkToA2Impl));
0252   portalA->assignPortalNavigation(Direction::Positive(), std::move(linkToA2),
0253                                   {volumeA});
0254 
0255   surfaceB->assignSurfaceMaterial(materialB);
0256   portalB = std::make_shared<Experimental::Portal>(surfaceB);
0257   ExternalNavigationDelegate linkToB3;
0258   auto linkToB3Impl = std::make_unique<const LinkToVolumeImpl>(volumeB);
0259   linkToB3.connect<&LinkToVolumeImpl::link>(std::move(linkToB3Impl));
0260   portalB->assignPortalNavigation(Direction::Negative(), std::move(linkToB3),
0261                                   {volumeB});
0262 
0263   // Portal A fuses with B - both have material, throw exception
0264   BOOST_CHECK_THROW(Experimental::Portal::fuse(portalA, portalB),
0265                     std::runtime_error);
0266   // Same in reverse
0267   BOOST_CHECK_THROW(Experimental::Portal::fuse(portalB, portalA),
0268                     std::runtime_error);
0269 }
0270 
0271 BOOST_AUTO_TEST_SUITE_END()
0272 
0273 }  // namespace ActsTests