Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-11 07:50:06

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 "Acts/Detector/CylindricalContainerBuilder.hpp"
0010 
0011 #include "Acts/Detector/DetectorComponents.hpp"
0012 #include "Acts/Detector/DetectorVolumeBuilder.hpp"
0013 #include "Acts/Detector/VolumeStructureBuilder.hpp"
0014 #include "Acts/Detector/detail/CylindricalDetectorHelper.hpp"
0015 #include "Acts/Detector/detail/ProtoMaterialHelper.hpp"
0016 #include "Acts/Detector/interface/IGeometryIdGenerator.hpp"
0017 #include "Acts/Detector/interface/IRootVolumeFinderBuilder.hpp"
0018 #include "Acts/Material/ProtoSurfaceMaterial.hpp"
0019 #include "Acts/Navigation/DetectorVolumeFinders.hpp"
0020 
0021 #include <algorithm>
0022 #include <ostream>
0023 #include <ranges>
0024 #include <stdexcept>
0025 #include <utility>
0026 
0027 namespace Acts::Experimental {
0028 class DetectorVolume;
0029 }  // namespace Acts::Experimental
0030 
0031 namespace {
0032 
0033 /// @brief Helper method to connect/wrap volumes or containers
0034 ///
0035 /// @tparam object_collection either a vector of volumes or containers
0036 /// @param gctx The geometry context of the this call
0037 /// @param objects The object vector
0038 /// @param binnning the chosen binning
0039 /// @param logLevel the logging output level
0040 ///
0041 /// @note no checking on consistency is done as the caller container builder
0042 /// is already checked at construction
0043 ///
0044 /// @return a newly built container
0045 template <typename object_collection>
0046 Acts::Experimental::DetectorComponent::PortalContainer connect(
0047     const Acts::GeometryContext& gctx, object_collection& objects,
0048     const std::vector<Acts::AxisDirection>& binning,
0049     Acts::Logging::Level logLevel) {
0050   // Return container object
0051   Acts::Experimental::DetectorComponent::PortalContainer portalContainer;
0052   if (binning.size() == 1u) {
0053     Acts::AxisDirection bv = binning.front();
0054     // 1-dimensional binning options
0055     switch (bv) {
0056       case Acts::AxisDirection::AxisR: {
0057         portalContainer =
0058             Acts::Experimental::detail::CylindricalDetectorHelper::connectInR(
0059                 gctx, objects, {}, logLevel);
0060       } break;
0061       case Acts::AxisDirection::AxisZ: {
0062         portalContainer =
0063             Acts::Experimental::detail::CylindricalDetectorHelper::connectInZ(
0064                 gctx, objects, {}, logLevel);
0065       } break;
0066       case Acts::AxisDirection::AxisPhi: {
0067         portalContainer =
0068             Acts::Experimental::detail::CylindricalDetectorHelper::connectInPhi(
0069                 gctx, objects, {}, logLevel);
0070       } break;
0071       default:
0072         break;
0073     }
0074   } else if (binning ==
0075                  std::vector<Acts::AxisDirection>{Acts::AxisDirection::AxisZ,
0076                                                   Acts::AxisDirection::AxisR} &&
0077              objects.size() == 2u) {
0078     portalContainer =
0079         Acts::Experimental::detail::CylindricalDetectorHelper::wrapInZR(
0080             gctx, objects, logLevel);
0081   }
0082   return portalContainer;
0083 }
0084 }  // namespace
0085 
0086 Acts::Experimental::CylindricalContainerBuilder::CylindricalContainerBuilder(
0087     const Acts::Experimental::CylindricalContainerBuilder::Config& cfg,
0088     std::unique_ptr<const Acts::Logger> logger)
0089     : IDetectorComponentBuilder(), m_cfg(cfg), m_logger(std::move(logger)) {
0090   // Check if builders are present
0091   if (m_cfg.builders.empty()) {
0092     throw std::invalid_argument(
0093         "CylindricalContainerBuilder: no sub builders provided.");
0094   }
0095   // Check if binning value is correctly chosen
0096   if (m_cfg.binning.size() == 1u) {
0097     // 1-dimensional case
0098     auto b = m_cfg.binning.front();
0099     if (b != Acts::AxisDirection::AxisR && b != Acts::AxisDirection::AxisZ &&
0100         b != Acts::AxisDirection::AxisPhi) {
0101       throw std::invalid_argument(
0102           "CylindricalContainerBuilder: 1D binning only supported in z, r, or "
0103           "phi");
0104     }
0105   } else if (m_cfg.binning.size() == 2u) {
0106     // 2-dimensional case, this is for wrapping
0107     if (m_cfg.binning !=
0108         std::vector<Acts::AxisDirection>{Acts::AxisDirection::AxisZ,
0109                                          Acts::AxisDirection::AxisR}) {
0110       throw std::invalid_argument(
0111           "CylindricalContainerBuilder: 2D binning only supports wrapping in "
0112           "z-r.");
0113     } else if (m_cfg.builders.size() != 2u) {
0114       // Wrapping needs exactly one inner (volume or container) and one outer
0115       // volume
0116       throw std::invalid_argument(
0117           "CylindricalContainerBuilder: 2D wrapping in z-r requires exactly "
0118           "two builders.");
0119     }
0120   }
0121 }
0122 
0123 Acts::Experimental::CylindricalContainerBuilder::CylindricalContainerBuilder(
0124     const Acts::Experimental::Gen2Blueprint::Node& bpNode,
0125     Acts::Logging::Level logLevel)
0126     : IDetectorComponentBuilder(),
0127       m_logger(getDefaultLogger(bpNode.name + "_cont", logLevel)) {
0128   if (bpNode.boundsType != VolumeBounds::BoundsType::eCylinder) {
0129     throw std::invalid_argument(
0130         "CylindricalContainerBuilder: boundary type must be cylinder - for "
0131         "building from a blueprint node.");
0132   }
0133 
0134   std::vector<std::shared_ptr<const IDetectorComponentBuilder>> builders;
0135   for (const auto& child : bpNode.children) {
0136     if (child->isLeaf()) {
0137       // Volume structure
0138       VolumeStructureBuilder::Config vsCfg;
0139       vsCfg.transform = child->transform;
0140       vsCfg.boundsType = child->boundsType;
0141       vsCfg.boundValues = child->boundaryValues;
0142       vsCfg.auxiliary = "*** acts auto-generated shape builder ***";
0143       auto vsBuilder = std::make_shared<VolumeStructureBuilder>(
0144           vsCfg, getDefaultLogger(child->name + "_shape", logLevel));
0145       // Detector volume builder
0146       DetectorVolumeBuilder::Config dvCfg;
0147       dvCfg.name = child->name;
0148       dvCfg.externalsBuilder = vsBuilder;
0149       dvCfg.internalsBuilder = child->internalsBuilder;
0150       dvCfg.geoIdGenerator = child->geoIdGenerator;
0151       dvCfg.portalMaterialBinning = child->portalMaterialBinning;
0152       dvCfg.auxiliary = "*** acts auto-generated volume builder ***";
0153       // Add the builder
0154       m_cfg.builders.push_back(std::make_shared<DetectorVolumeBuilder>(
0155           dvCfg, getDefaultLogger(child->name, logLevel)));
0156     } else {
0157       // This evokes the recursive stepping down the tree
0158       m_cfg.builders.push_back(
0159           std::make_shared<CylindricalContainerBuilder>(*child, logLevel));
0160     }
0161   }
0162 
0163   if (m_cfg.builders.empty()) {
0164     throw std::invalid_argument(
0165         "CylindricalContainerBuilder: no sub builders provided.");
0166   }
0167   m_cfg.binning = bpNode.binning;
0168   // Check if binning value is correctly chosen
0169   if (m_cfg.binning.size() == 1u) {
0170     // 1-dimensional case
0171     auto b = m_cfg.binning.front();
0172     if (b != Acts::AxisDirection::AxisR && b != Acts::AxisDirection::AxisZ &&
0173         b != Acts::AxisDirection::AxisPhi) {
0174       throw std::invalid_argument(
0175           "CylindricalContainerBuilder: 1D binning only supported in z, r, or "
0176           "phi");
0177     }
0178   } else if (m_cfg.binning.size() == 2u) {
0179     // 2-dimensional case, this is for wrapping
0180     if (m_cfg.binning !=
0181         std::vector<Acts::AxisDirection>{Acts::AxisDirection::AxisZ,
0182                                          Acts::AxisDirection::AxisR}) {
0183       throw std::invalid_argument(
0184           "CylindricalContainerBuilder: 2D binning only supports wrapping in "
0185           "z-r.");
0186     } else if (m_cfg.builders.size() != 2u) {
0187       // Wrapping needs exactly one inner (volume or container) and one outer
0188       // volume
0189       throw std::invalid_argument(
0190           "CylindricalContainerBuilder: 2D wrapping in z-r requires exactly "
0191           "two builders.");
0192     }
0193   }
0194 
0195   m_cfg.auxiliary = "*** acts auto-generated from proxy ***";
0196   m_cfg.geoIdGenerator = bpNode.geoIdGenerator;
0197   m_cfg.rootVolumeFinderBuilder = bpNode.rootVolumeFinderBuilder;
0198   m_cfg.portalMaterialBinning = bpNode.portalMaterialBinning;
0199 }
0200 
0201 Acts::Experimental::DetectorComponent
0202 Acts::Experimental::CylindricalContainerBuilder::construct(
0203     const GeometryContext& gctx) const {
0204   // Return container object
0205   DetectorComponent::PortalContainer portalContainer;
0206   bool atNavigationLevel = true;
0207 
0208   // Create the indivudal components, collect for both outcomes
0209   std::vector<DetectorComponent> components;
0210   ACTS_DEBUG("Building container from " << m_cfg.builders.size()
0211                                         << " components.");
0212   // Check through the component volumes - if every builder only
0213   // built exactly one volume, you are at pure navigation level
0214   // Collect the volumes
0215   std::vector<std::shared_ptr<DetectorVolume>> volumes;
0216   std::vector<DetectorComponent::PortalContainer> containers;
0217   std::vector<std::shared_ptr<DetectorVolume>> rootVolumes;
0218   // Run through the builders
0219   std::ranges::for_each(m_cfg.builders, [&](const auto& builder) {
0220     auto [cVolumes, cContainer, cRoots] = builder->construct(gctx);
0221     atNavigationLevel = (atNavigationLevel && cVolumes.size() == 1u);
0222     // Collect individual components, volumes, containers, roots
0223     volumes.insert(volumes.end(), cVolumes.begin(), cVolumes.end());
0224     containers.push_back(cContainer);
0225     rootVolumes.insert(rootVolumes.end(), cRoots.volumes.begin(),
0226                        cRoots.volumes.end());
0227   });
0228   // Navigation level detected, connect volumes (cleaner and faster than
0229   // connect containers)
0230   if (atNavigationLevel) {
0231     ACTS_VERBOSE(
0232         "Component volumes are at navigation level: connecting volumes.");
0233     // Connect volumes
0234     portalContainer = connect(gctx, volumes, m_cfg.binning, logger().level());
0235   } else {
0236     ACTS_VERBOSE("Components contain sub containers: connect containers.");
0237     // Connect containers
0238     portalContainer =
0239         connect(gctx, containers, m_cfg.binning, logger().level());
0240   }
0241   ACTS_VERBOSE("Number of root volumes: " << rootVolumes.size());
0242 
0243   // Geometry Id generation
0244   if (m_cfg.geoIdGenerator != nullptr) {
0245     ACTS_DEBUG("Assigning geometry ids to the detector");
0246     auto cache = m_cfg.geoIdGenerator->generateCache();
0247     if (m_cfg.geoIdReverseGen) {
0248       std::for_each(rootVolumes.rbegin(), rootVolumes.rend(), [&](auto& v) {
0249         m_cfg.geoIdGenerator->assignGeometryId(cache, *v);
0250         ACTS_VERBOSE("-> Assigning geometry id to volume " << v->name());
0251       });
0252     } else {
0253       std::ranges::for_each(rootVolumes, [&](auto& v) {
0254         m_cfg.geoIdGenerator->assignGeometryId(cache, *v);
0255         ACTS_VERBOSE("-> Assigning geometry id to volume " << v->name());
0256       });
0257     }
0258   }
0259 
0260   // Assign the proto material
0261   // Material assignment from configuration
0262   for (const auto& [ip, bDescription] : m_cfg.portalMaterialBinning) {
0263     if (portalContainer.contains(ip)) {
0264       auto bd = detail::ProtoMaterialHelper::attachProtoMaterial(
0265           gctx, portalContainer[ip]->surface(), bDescription);
0266       ACTS_VERBOSE("-> Assigning proto material to portal " << ip << " with "
0267                                                             << bd);
0268     }
0269   }
0270 
0271   // Check if a root volume finder is provided
0272   if (m_cfg.rootVolumeFinderBuilder) {
0273     // Return the container
0274     return Acts::Experimental::DetectorComponent{
0275         volumes, portalContainer,
0276         RootDetectorVolumes{
0277             rootVolumes,
0278             m_cfg.rootVolumeFinderBuilder->construct(gctx, rootVolumes)}};
0279   }
0280 
0281   // Return the container
0282   return Acts::Experimental::DetectorComponent{
0283       volumes, portalContainer,
0284       RootDetectorVolumes{rootVolumes, tryRootVolumes()}};
0285 }