Back to home page

EIC code displayed by LXR

 
 

    


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

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