File indexing completed on 2025-07-11 07:50:06
0001
0002
0003
0004
0005
0006
0007
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 }
0030
0031 namespace {
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
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
0051 Acts::Experimental::DetectorComponent::PortalContainer portalContainer;
0052 if (binning.size() == 1u) {
0053 Acts::AxisDirection bv = binning.front();
0054
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 }
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
0091 if (m_cfg.builders.empty()) {
0092 throw std::invalid_argument(
0093 "CylindricalContainerBuilder: no sub builders provided.");
0094 }
0095
0096 if (m_cfg.binning.size() == 1u) {
0097
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
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
0115
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
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
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
0154 m_cfg.builders.push_back(std::make_shared<DetectorVolumeBuilder>(
0155 dvCfg, getDefaultLogger(child->name, logLevel)));
0156 } else {
0157
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
0169 if (m_cfg.binning.size() == 1u) {
0170
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
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
0188
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
0205 DetectorComponent::PortalContainer portalContainer;
0206 bool atNavigationLevel = true;
0207
0208
0209 std::vector<DetectorComponent> components;
0210 ACTS_DEBUG("Building container from " << m_cfg.builders.size()
0211 << " components.");
0212
0213
0214
0215 std::vector<std::shared_ptr<DetectorVolume>> volumes;
0216 std::vector<DetectorComponent::PortalContainer> containers;
0217 std::vector<std::shared_ptr<DetectorVolume>> rootVolumes;
0218
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
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
0229
0230 if (atNavigationLevel) {
0231 ACTS_VERBOSE(
0232 "Component volumes are at navigation level: connecting volumes.");
0233
0234 portalContainer = connect(gctx, volumes, m_cfg.binning, logger().level());
0235 } else {
0236 ACTS_VERBOSE("Components contain sub containers: connect containers.");
0237
0238 portalContainer =
0239 connect(gctx, containers, m_cfg.binning, logger().level());
0240 }
0241 ACTS_VERBOSE("Number of root volumes: " << rootVolumes.size());
0242
0243
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
0261
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
0272 if (m_cfg.rootVolumeFinderBuilder) {
0273
0274 return Acts::Experimental::DetectorComponent{
0275 volumes, portalContainer,
0276 RootDetectorVolumes{
0277 rootVolumes,
0278 m_cfg.rootVolumeFinderBuilder->construct(gctx, rootVolumes)}};
0279 }
0280
0281
0282 return Acts::Experimental::DetectorComponent{
0283 volumes, portalContainer,
0284 RootDetectorVolumes{rootVolumes, tryRootVolumes()}};
0285 }