File indexing completed on 2025-08-05 08:09:34
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 <stdexcept>
0024 #include <utility>
0025
0026 namespace Acts::Experimental {
0027 class DetectorVolume;
0028 }
0029
0030 namespace {
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
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
0050 Acts::Experimental::DetectorComponent::PortalContainer portalContainer;
0051 if (binning.size() == 1u) {
0052 Acts::BinningValue bv = binning.front();
0053
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 }
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
0089 if (m_cfg.builders.empty()) {
0090 throw std::invalid_argument(
0091 "CylindricalContainerBuilder: no sub builders provided.");
0092 }
0093
0094 if (m_cfg.binning.size() == 1u) {
0095
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
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
0111
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
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
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
0150 m_cfg.builders.push_back(std::make_shared<DetectorVolumeBuilder>(
0151 dvCfg, getDefaultLogger(child->name, logLevel)));
0152 } else {
0153
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
0165 if (m_cfg.binning.size() == 1u) {
0166
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
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
0182
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
0199 DetectorComponent::PortalContainer portalContainer;
0200 bool atNavigationLevel = true;
0201
0202
0203 std::vector<DetectorComponent> components;
0204 ACTS_DEBUG("Building container from " << m_cfg.builders.size()
0205 << " components.");
0206
0207
0208
0209 std::vector<std::shared_ptr<DetectorVolume>> volumes;
0210 std::vector<DetectorComponent::PortalContainer> containers;
0211 std::vector<std::shared_ptr<DetectorVolume>> rootVolumes;
0212
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
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
0224
0225 if (atNavigationLevel) {
0226 ACTS_VERBOSE(
0227 "Component volumes are at navigation level: connecting volumes.");
0228
0229 portalContainer = connect(gctx, volumes, m_cfg.binning, logger().level());
0230 } else {
0231 ACTS_VERBOSE("Components contain sub containers: connect containers.");
0232
0233 portalContainer =
0234 connect(gctx, containers, m_cfg.binning, logger().level());
0235 }
0236 ACTS_VERBOSE("Number of root volumes: " << rootVolumes.size());
0237
0238
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
0256
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
0267 if (m_cfg.rootVolumeFinderBuilder) {
0268
0269 return Acts::Experimental::DetectorComponent{
0270 {},
0271 portalContainer,
0272 RootDetectorVolumes{
0273 rootVolumes,
0274 m_cfg.rootVolumeFinderBuilder->construct(gctx, rootVolumes)}};
0275 }
0276
0277
0278 return Acts::Experimental::DetectorComponent{
0279 {}, portalContainer, RootDetectorVolumes{rootVolumes, tryRootVolumes()}};
0280 }