Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:11:18

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 <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::AxisDirection>& binning,
0048     Acts::Logging::Level logLevel) {
0049   // Return container object
0050   Acts::Experimental::DetectorComponent::PortalContainer portalContainer;
0051   if (binning.size() == 1u) {
0052     Acts::AxisDirection bv = binning.front();
0053     // 1-dimensional binning options
0054     switch (bv) {
0055       case Acts::AxisDirection::AxisR: {
0056         portalContainer =
0057             Acts::Experimental::detail::CylindricalDetectorHelper::connectInR(
0058                 gctx, objects, {}, logLevel);
0059       } break;
0060       case Acts::AxisDirection::AxisZ: {
0061         portalContainer =
0062             Acts::Experimental::detail::CylindricalDetectorHelper::connectInZ(
0063                 gctx, objects, {}, logLevel);
0064       } break;
0065       case Acts::AxisDirection::AxisPhi: {
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::AxisDirection>{Acts::AxisDirection::AxisZ,
0075                                                   Acts::AxisDirection::AxisR} &&
0076              objects.size() == 2u) {
0077     portalContainer =
0078         Acts::Experimental::detail::CylindricalDetectorHelper::wrapInZR(
0079             gctx, objects, logLevel);
0080   }
0081   return portalContainer;
0082 }
0083 }  // namespace
0084 
0085 Acts::Experimental::CylindricalContainerBuilder::CylindricalContainerBuilder(
0086     const Acts::Experimental::CylindricalContainerBuilder::Config& cfg,
0087     std::unique_ptr<const Acts::Logger> logger)
0088     : IDetectorComponentBuilder(), m_cfg(cfg), m_logger(std::move(logger)) {
0089   // Check if builders are present
0090   if (m_cfg.builders.empty()) {
0091     throw std::invalid_argument(
0092         "CylindricalContainerBuilder: no sub builders provided.");
0093   }
0094   // Check if binning value is correctly chosen
0095   if (m_cfg.binning.size() == 1u) {
0096     // 1-dimensional case
0097     auto b = m_cfg.binning.front();
0098     if (b != Acts::AxisDirection::AxisR && b != Acts::AxisDirection::AxisZ &&
0099         b != Acts::AxisDirection::AxisPhi) {
0100       throw std::invalid_argument(
0101           "CylindricalContainerBuilder: 1D binning only supported in z, r, or "
0102           "phi");
0103     }
0104   } else if (m_cfg.binning.size() == 2u) {
0105     // 2-dimensional case, this is for wrapping
0106     if (m_cfg.binning !=
0107         std::vector<Acts::AxisDirection>{Acts::AxisDirection::AxisZ,
0108                                          Acts::AxisDirection::AxisR}) {
0109       throw std::invalid_argument(
0110           "CylindricalContainerBuilder: 2D binning only supports wrapping in "
0111           "z-r.");
0112     } else if (m_cfg.builders.size() != 2u) {
0113       // Wrapping needs exactly one inner (volume or container) and one outer
0114       // volume
0115       throw std::invalid_argument(
0116           "CylindricalContainerBuilder: 2D wrapping in z-r requires exactly "
0117           "two builders.");
0118     }
0119   }
0120 }
0121 
0122 Acts::Experimental::CylindricalContainerBuilder::CylindricalContainerBuilder(
0123     const Acts::Experimental::Blueprint::Node& bpNode,
0124     Acts::Logging::Level logLevel)
0125     : IDetectorComponentBuilder(),
0126       m_logger(getDefaultLogger(bpNode.name + "_cont", logLevel)) {
0127   if (bpNode.boundsType != VolumeBounds::BoundsType::eCylinder) {
0128     throw std::invalid_argument(
0129         "CylindricalContainerBuilder: boundary type must be cylinder - for "
0130         "building from a blueprint node.");
0131   }
0132 
0133   std::vector<std::shared_ptr<const IDetectorComponentBuilder>> builders;
0134   for (const auto& child : bpNode.children) {
0135     if (child->isLeaf()) {
0136       // Volume structure
0137       VolumeStructureBuilder::Config vsCfg;
0138       vsCfg.transform = child->transform;
0139       vsCfg.boundsType = child->boundsType;
0140       vsCfg.boundValues = child->boundaryValues;
0141       vsCfg.auxiliary = "*** acts auto-generated shape builder ***";
0142       auto vsBuilder = std::make_shared<VolumeStructureBuilder>(
0143           vsCfg, getDefaultLogger(child->name + "_shape", logLevel));
0144       // Detector volume builder
0145       DetectorVolumeBuilder::Config dvCfg;
0146       dvCfg.name = child->name;
0147       dvCfg.externalsBuilder = vsBuilder;
0148       dvCfg.internalsBuilder = child->internalsBuilder;
0149       dvCfg.geoIdGenerator = child->geoIdGenerator;
0150       dvCfg.portalMaterialBinning = child->portalMaterialBinning;
0151       dvCfg.auxiliary = "*** acts auto-generated volume builder ***";
0152       // Add the builder
0153       m_cfg.builders.push_back(std::make_shared<DetectorVolumeBuilder>(
0154           dvCfg, getDefaultLogger(child->name, logLevel)));
0155     } else {
0156       // This evokes the recursive stepping down the tree
0157       m_cfg.builders.push_back(
0158           std::make_shared<CylindricalContainerBuilder>(*child, logLevel));
0159     }
0160   }
0161 
0162   if (m_cfg.builders.empty()) {
0163     throw std::invalid_argument(
0164         "CylindricalContainerBuilder: no sub builders provided.");
0165   }
0166   m_cfg.binning = bpNode.binning;
0167   // Check if binning value is correctly chosen
0168   if (m_cfg.binning.size() == 1u) {
0169     // 1-dimensional case
0170     auto b = m_cfg.binning.front();
0171     if (b != Acts::AxisDirection::AxisR && b != Acts::AxisDirection::AxisZ &&
0172         b != Acts::AxisDirection::AxisPhi) {
0173       throw std::invalid_argument(
0174           "CylindricalContainerBuilder: 1D binning only supported in z, r, or "
0175           "phi");
0176     }
0177   } else if (m_cfg.binning.size() == 2u) {
0178     // 2-dimensional case, this is for wrapping
0179     if (m_cfg.binning !=
0180         std::vector<Acts::AxisDirection>{Acts::AxisDirection::AxisZ,
0181                                          Acts::AxisDirection::AxisR}) {
0182       throw std::invalid_argument(
0183           "CylindricalContainerBuilder: 2D binning only supports wrapping in "
0184           "z-r.");
0185     } else if (m_cfg.builders.size() != 2u) {
0186       // Wrapping needs exactly one inner (volume or container) and one outer
0187       // volume
0188       throw std::invalid_argument(
0189           "CylindricalContainerBuilder: 2D wrapping in z-r requires exactly "
0190           "two builders.");
0191     }
0192   }
0193 
0194   m_cfg.auxiliary = "*** acts auto-generated from proxy ***";
0195   m_cfg.geoIdGenerator = bpNode.geoIdGenerator;
0196   m_cfg.rootVolumeFinderBuilder = bpNode.rootVolumeFinderBuilder;
0197   m_cfg.portalMaterialBinning = bpNode.portalMaterialBinning;
0198 }
0199 
0200 Acts::Experimental::DetectorComponent
0201 Acts::Experimental::CylindricalContainerBuilder::construct(
0202     const GeometryContext& gctx) const {
0203   // Return container object
0204   DetectorComponent::PortalContainer portalContainer;
0205   bool atNavigationLevel = true;
0206 
0207   // Create the indivudal components, collect for both outcomes
0208   std::vector<DetectorComponent> components;
0209   ACTS_DEBUG("Building container from " << m_cfg.builders.size()
0210                                         << " components.");
0211   // Check through the component volumes - if every builder only
0212   // built exactly one volume, you are at pure navigation level
0213   // Collect the volumes
0214   std::vector<std::shared_ptr<DetectorVolume>> volumes;
0215   std::vector<DetectorComponent::PortalContainer> containers;
0216   std::vector<std::shared_ptr<DetectorVolume>> rootVolumes;
0217   // Run through the builders
0218   std::for_each(
0219       m_cfg.builders.begin(), m_cfg.builders.end(), [&](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::for_each(rootVolumes.begin(), rootVolumes.end(), [&](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.toString());
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 }