Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:09:34

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