Back to home page

sPhenix code displayed by LXR

 
 

    


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

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2022 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/unit_test.hpp>
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Detector/CylindricalContainerBuilder.hpp"
0013 #include "Acts/Detector/DetectorComponents.hpp"
0014 #include "Acts/Detector/DetectorVolume.hpp"
0015 #include "Acts/Detector/PortalGenerators.hpp"
0016 #include "Acts/Detector/ProtoBinning.hpp"
0017 #include "Acts/Detector/interface/IDetectorComponentBuilder.hpp"
0018 #include "Acts/Detector/interface/IGeometryIdGenerator.hpp"
0019 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0020 #include "Acts/Geometry/GeometryContext.hpp"
0021 #include "Acts/Geometry/GeometryIdentifier.hpp"
0022 #include "Acts/Navigation/DetectorVolumeFinders.hpp"
0023 #include "Acts/Navigation/SurfaceCandidatesUpdaters.hpp"
0024 #include "Acts/Surfaces/CylinderBounds.hpp"
0025 #include "Acts/Surfaces/CylinderSurface.hpp"
0026 #include "Acts/Surfaces/DiscSurface.hpp"
0027 #include "Acts/Surfaces/RadialBounds.hpp"
0028 #include "Acts/Surfaces/Surface.hpp"
0029 #include "Acts/Utilities/BinningType.hpp"
0030 #include "Acts/Utilities/Enumerate.hpp"
0031 #include "Acts/Utilities/Logger.hpp"
0032 
0033 #include <any>
0034 #include <cmath>
0035 #include <iterator>
0036 #include <memory>
0037 #include <stdexcept>
0038 #include <string>
0039 #include <utility>
0040 #include <vector>
0041 
0042 using namespace Acts;
0043 using namespace Acts::Experimental;
0044 
0045 GeometryContext tContext;
0046 
0047 /// @brief A mockup volume builder, it generates volumes with
0048 /// a single surface filled in in order to use the CylindricalContainerBuilder
0049 /// infrastructure.
0050 template <typename surface_type, typename surface_bounds_type>
0051 class CylindricalVolumeBuilder : public IDetectorComponentBuilder {
0052  public:
0053   CylindricalVolumeBuilder(const Transform3& transform,
0054                            const CylinderVolumeBounds& vBounds,
0055                            const surface_bounds_type& sBounds,
0056                            const std::string& vName)
0057       : IDetectorComponentBuilder(),
0058         m_transform(transform),
0059         m_volumeBounds(vBounds),
0060         m_surfaceBounds(sBounds),
0061         m_name(vName) {}
0062 
0063   DetectorComponent construct(
0064       [[maybe_unused]] const GeometryContext& gctx) const final {
0065     // The outgoing root volumes
0066     std::vector<std::shared_ptr<DetectorVolume>> rootVolumes;
0067 
0068     // Ingredients
0069     auto surface = Surface::makeShared<surface_type>(
0070         (m_transform), std::make_shared<surface_bounds_type>(m_surfaceBounds));
0071 
0072     auto bounds = std::make_unique<CylinderVolumeBounds>(m_volumeBounds);
0073     auto portalGenerator = defaultPortalGenerator();
0074     auto volume = DetectorVolumeFactory::construct(
0075         portalGenerator, tContext, m_name, m_transform, std::move(bounds),
0076         {surface}, {}, tryNoVolumes(), tryAllPortalsAndSurfaces());
0077 
0078     // Add to the roots
0079     rootVolumes.push_back(volume);
0080 
0081     DetectorComponent::PortalContainer dContainer;
0082     for (auto [ip, p] : enumerate(volume->portalPtrs())) {
0083       dContainer[ip] = p;
0084     }
0085     return DetectorComponent{
0086         {volume},
0087         dContainer,
0088         RootDetectorVolumes{rootVolumes, tryRootVolumes()}};
0089   }
0090 
0091  private:
0092   Transform3 m_transform;
0093   CylinderVolumeBounds m_volumeBounds;
0094   surface_bounds_type m_surfaceBounds;
0095   std::string m_name;
0096 };
0097 
0098 class VolumeGeoIdGenerator : public IGeometryIdGenerator {
0099  public:
0100   struct Cache {
0101     unsigned int volumeCount = 0;
0102   };
0103 
0104   IGeometryIdGenerator::GeoIdCache generateCache() const final {
0105     return Cache{0};
0106   }
0107 
0108   void assignGeometryId(IGeometryIdGenerator::GeoIdCache& cache,
0109                         DetectorVolume& dVolume) const final {
0110     auto& ccache = std::any_cast<Cache&>(cache);
0111     ccache.volumeCount += 1;
0112     Acts::GeometryIdentifier geoID;
0113     geoID.setVolume(ccache.volumeCount);
0114     dVolume.assignGeometryId(geoID);
0115   }
0116 
0117   void assignGeometryId(
0118       Acts::Experimental::IGeometryIdGenerator::GeoIdCache& /*cache*/,
0119       Acts::Experimental::Portal& /*portal*/) const final {}
0120 
0121   void assignGeometryId(
0122       Acts::Experimental::IGeometryIdGenerator::GeoIdCache& /*cache*/,
0123       Acts::Surface& /*surface*/) const final {}
0124 };
0125 
0126 BOOST_AUTO_TEST_SUITE(Detector)
0127 
0128 BOOST_AUTO_TEST_CASE(CylindricaContainerBuilder_Misconfiguration) {
0129   // misconfiruation: no builders
0130   CylindricalContainerBuilder::Config misCfg;
0131   BOOST_CHECK_THROW(auto a = CylindricalContainerBuilder(misCfg),
0132                     std::invalid_argument);
0133   // misconfiguration - 1D binning not in z, r, phi
0134   misCfg.builders = {nullptr};
0135   misCfg.binning = {Acts::binX};
0136   BOOST_CHECK_THROW(auto b = CylindricalContainerBuilder(misCfg),
0137                     std::invalid_argument);
0138 
0139   // misconfiguration - 2D binning not in z, r,
0140   misCfg.builders = {nullptr, nullptr};
0141   misCfg.binning = {Acts::binZ, Acts::binPhi};
0142   BOOST_CHECK_THROW(auto c = CylindricalContainerBuilder(misCfg),
0143                     std::invalid_argument);
0144 
0145   // misconfiguration - 2D binning  in z, r, but not exactly 2 builders
0146   misCfg.builders = {nullptr, nullptr, nullptr};
0147   misCfg.binning = {Acts::binZ, Acts::binR};
0148   BOOST_CHECK_THROW(auto d = CylindricalContainerBuilder(misCfg),
0149                     std::invalid_argument);
0150 }
0151 
0152 BOOST_AUTO_TEST_CASE(CylindricaContainerBuildingZ) {
0153   // Declare a negative disc builder
0154   Transform3 negZ = Transform3::Identity();
0155   negZ.pretranslate(Vector3(0., 0., -300.));
0156   auto negDisc =
0157       std::make_shared<CylindricalVolumeBuilder<DiscSurface, RadialBounds>>(
0158           negZ, CylinderVolumeBounds(50., 200., 100.), RadialBounds(60., 190.),
0159           "NegativeDisc");
0160 
0161   // Declare a barrel builder
0162   auto barrel = std::make_shared<
0163       CylindricalVolumeBuilder<CylinderSurface, CylinderBounds>>(
0164       Transform3::Identity(), CylinderVolumeBounds(50., 200., 200.),
0165       CylinderBounds(80., 190.), "Barrel");
0166   // Declare a positive disc builder
0167   Transform3 posZ = Transform3::Identity();
0168   posZ.pretranslate(Vector3(0., 0., 300.));
0169   auto posDisc =
0170       std::make_shared<CylindricalVolumeBuilder<DiscSurface, RadialBounds>>(
0171           posZ, CylinderVolumeBounds(50., 200., 100.), RadialBounds(60., 190.),
0172           "PositiveDisc");
0173 
0174   // Create the container builder
0175   CylindricalContainerBuilder::Config tripleZCfg;
0176   tripleZCfg.auxiliary = "*** Test 0 - Build triple in Z ***";
0177   tripleZCfg.builders = {negDisc, barrel, posDisc};
0178   tripleZCfg.binning = {binZ};
0179   tripleZCfg.geoIdGenerator = std::make_shared<VolumeGeoIdGenerator>();
0180   // Create a materialBinning
0181   tripleZCfg.portalMaterialBinning[2u] = BinningDescription{
0182       {ProtoBinning(binZ, Acts::detail::AxisBoundaryType::Bound, 50),
0183        ProtoBinning(binPhi, Acts::detail::AxisBoundaryType::Closed, -M_PI, M_PI,
0184                     12)}};
0185 
0186   // Let's test the reverse generation
0187   tripleZCfg.geoIdReverseGen = true;
0188 
0189   auto tripleZ = std::make_shared<CylindricalContainerBuilder>(
0190       tripleZCfg, getDefaultLogger("TripleBuilderZ", Logging::VERBOSE));
0191 
0192   auto [volumes, portals, roots] = tripleZ->construct(tContext);
0193 
0194   BOOST_CHECK_EQUAL(portals.size(), 4u);
0195   BOOST_CHECK_EQUAL(roots.volumes.size(), 3u);
0196   BOOST_CHECK_EQUAL(roots.volumes[0]->geometryId().volume(), 3u);
0197   BOOST_CHECK_EQUAL(roots.volumes[1]->geometryId().volume(), 2u);
0198   BOOST_CHECK_EQUAL(roots.volumes[2]->geometryId().volume(), 1u);
0199 
0200   // The outside surface should have a proto material description now
0201   BOOST_CHECK_NE(portals[2u]->surface().surfaceMaterial(), nullptr);
0202   // others should not have a proto material description
0203   BOOST_CHECK_EQUAL(portals[0u]->surface().surfaceMaterial(), nullptr);
0204   BOOST_CHECK_EQUAL(portals[1u]->surface().surfaceMaterial(), nullptr);
0205   BOOST_CHECK_EQUAL(portals[3u]->surface().surfaceMaterial(), nullptr);
0206 }
0207 
0208 BOOST_AUTO_TEST_CASE(CylindricaContainerBuildingR) {
0209   // Declare a barrel builder
0210   auto barrel0 = std::make_shared<
0211       CylindricalVolumeBuilder<CylinderSurface, CylinderBounds>>(
0212       Transform3::Identity(), CylinderVolumeBounds(50., 80., 200.),
0213       CylinderBounds(65., 190.), "Barrel0");
0214 
0215   // Declare a barrel builder
0216   auto barrel1 = std::make_shared<
0217       CylindricalVolumeBuilder<CylinderSurface, CylinderBounds>>(
0218       Transform3::Identity(), CylinderVolumeBounds(80., 110., 200.),
0219       CylinderBounds(95., 190.), "Barrel1");
0220 
0221   // Declare a barrel builder
0222   auto barrel2 = std::make_shared<
0223       CylindricalVolumeBuilder<CylinderSurface, CylinderBounds>>(
0224       Transform3::Identity(), CylinderVolumeBounds(110., 140., 200.),
0225       CylinderBounds(125., 190.), "Barrel2");
0226 
0227   // Create the container builder
0228   CylindricalContainerBuilder::Config barrelRCfg;
0229   barrelRCfg.auxiliary = "*** Test 1 - Build multilayer barrel ***";
0230   barrelRCfg.builders = {barrel0, barrel1, barrel2};
0231   barrelRCfg.binning = {binR};
0232   barrelRCfg.geoIdGenerator = std::make_shared<VolumeGeoIdGenerator>();
0233 
0234   auto barrelR = std::make_shared<CylindricalContainerBuilder>(
0235       barrelRCfg, getDefaultLogger("BarrelBuilderR", Logging::VERBOSE));
0236 
0237   auto [volumes, portals, roots] = barrelR->construct(tContext);
0238 
0239   BOOST_CHECK_EQUAL(portals.size(), 4u);
0240   BOOST_CHECK_EQUAL(roots.volumes.size(), 3u);
0241   BOOST_CHECK_EQUAL(roots.volumes[0]->geometryId().volume(), 1u);
0242   BOOST_CHECK_EQUAL(roots.volumes[1]->geometryId().volume(), 2u);
0243   BOOST_CHECK_EQUAL(roots.volumes[2]->geometryId().volume(), 3u);
0244 }
0245 
0246 BOOST_AUTO_TEST_CASE(CylindricaContainerBuildingPhi) {
0247   // Create the container builder
0248   CylindricalContainerBuilder::Config barrelPhiCfg;
0249   barrelPhiCfg.auxiliary = "*** Test 2 - Build segmented phi barrel ***";
0250   barrelPhiCfg.binning = {binPhi};
0251 
0252   unsigned int phiSectors = 5;
0253   Acts::ActsScalar phiHalfSector = M_PI / phiSectors;
0254 
0255   std::vector<std::shared_ptr<DetectorVolume>> phiVolumes = {};
0256   for (unsigned int i = 0; i < phiSectors; ++i) {
0257     // The volume bounds
0258     Acts::CylinderVolumeBounds volumeBounds(
0259         10., 100., 100., phiHalfSector, -M_PI + (2u * i + 1u) * phiHalfSector);
0260     // The surface boudns
0261     Acts::CylinderBounds surfaceBounds(50., 90., 0.99 * phiHalfSector,
0262                                        -M_PI + (2u * i + 1u) * phiHalfSector);
0263 
0264     auto builder = std::make_shared<
0265         CylindricalVolumeBuilder<CylinderSurface, CylinderBounds>>(
0266         Transform3::Identity(), volumeBounds, surfaceBounds,
0267         std::string("Sector_") + std::to_string(i));
0268     barrelPhiCfg.builders.push_back(builder);
0269   }
0270 
0271   auto barrelPhi = std::make_shared<CylindricalContainerBuilder>(
0272       barrelPhiCfg, getDefaultLogger("BarrelBuilderPhi", Logging::VERBOSE));
0273 
0274   auto [volumes, portals, roots] = barrelPhi->construct(tContext);
0275 
0276   BOOST_CHECK_EQUAL(portals.size(), 4u);
0277   BOOST_CHECK_EQUAL(roots.volumes.size(), 5u);
0278 }
0279 
0280 BOOST_AUTO_TEST_CASE(CylindricalContainerBuilderDetector) {
0281   // Declare a barrel sub builder
0282   auto beampipe = std::make_shared<
0283       CylindricalVolumeBuilder<CylinderSurface, CylinderBounds>>(
0284       Transform3::Identity(), CylinderVolumeBounds(0., 50., 600.),
0285       CylinderBounds(25., 590.), "BeamPipe");
0286 
0287   // Declare a negative disc builder
0288   Transform3 negZ = Transform3::Identity();
0289   negZ.pretranslate(Vector3(0., 0., -300.));
0290   auto endcapN =
0291       std::make_shared<CylindricalVolumeBuilder<DiscSurface, RadialBounds>>(
0292           negZ, CylinderVolumeBounds(50., 140., 100.), RadialBounds(60., 130.),
0293           "NegativeEndcap");
0294 
0295   // Declare a barrel sub builder
0296   auto barrel0 = std::make_shared<
0297       CylindricalVolumeBuilder<CylinderSurface, CylinderBounds>>(
0298       Transform3::Identity(), CylinderVolumeBounds(50., 80., 200.),
0299       CylinderBounds(65., 190.), "Barrel0");
0300 
0301   // Declare a barrel sub builder
0302   auto barrel1 = std::make_shared<
0303       CylindricalVolumeBuilder<CylinderSurface, CylinderBounds>>(
0304       Transform3::Identity(), CylinderVolumeBounds(80., 110., 200.),
0305       CylinderBounds(95., 190.), "Barrel1");
0306 
0307   // Declare a barrel sub builder
0308   auto barrel2 = std::make_shared<
0309       CylindricalVolumeBuilder<CylinderSurface, CylinderBounds>>(
0310       Transform3::Identity(), CylinderVolumeBounds(110., 140., 200.),
0311       CylinderBounds(125., 190.), "Barrel2");
0312 
0313   // Create the barrel container builder
0314   CylindricalContainerBuilder::Config barrelRCfg;
0315   barrelRCfg.builders = {barrel0, barrel1, barrel2};
0316   barrelRCfg.binning = {binR};
0317 
0318   auto barrel = std::make_shared<CylindricalContainerBuilder>(
0319       barrelRCfg, getDefaultLogger("BarrelBuilderR", Logging::VERBOSE));
0320 
0321   Transform3 posZ = Transform3::Identity();
0322   posZ.pretranslate(Vector3(0., 0., 300.));
0323   auto endcapP =
0324       std::make_shared<CylindricalVolumeBuilder<DiscSurface, RadialBounds>>(
0325           posZ, CylinderVolumeBounds(50., 140., 100.), RadialBounds(60., 130.),
0326           "PositiveEndcap");
0327 
0328   // Create the barrel container builder
0329   CylindricalContainerBuilder::Config barrelEndcapCfg;
0330   barrelEndcapCfg.builders = {endcapN, barrel, endcapP};
0331   barrelEndcapCfg.binning = {binZ};
0332 
0333   auto barrelEndcap = std::make_shared<CylindricalContainerBuilder>(
0334       barrelEndcapCfg,
0335       getDefaultLogger("BarrelEndcapBuilder", Logging::VERBOSE));
0336 
0337   // Create the barrel container builder
0338   CylindricalContainerBuilder::Config detectorCfg;
0339   detectorCfg.builders = {beampipe, barrelEndcap};
0340   detectorCfg.binning = {binR};
0341 
0342   auto detector = std::make_shared<CylindricalContainerBuilder>(
0343       detectorCfg, getDefaultLogger("DetectorBuilder", Logging::VERBOSE));
0344 
0345   auto [volumes, portals, roots] = detector->construct(tContext);
0346   BOOST_CHECK_EQUAL(portals.size(), 3u);
0347   BOOST_CHECK_EQUAL(roots.volumes.size(), 6u);
0348 }
0349 
0350 BOOST_AUTO_TEST_SUITE_END()