File indexing completed on 2025-07-01 07:52:45
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Detector/LayerStructureBuilder.hpp"
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Detector/detail/IndexedSurfacesGenerator.hpp"
0013 #include "Acts/Detector/detail/ReferenceGenerators.hpp"
0014 #include "Acts/Detector/detail/SupportSurfacesHelper.hpp"
0015 #include "Acts/Geometry/Extent.hpp"
0016 #include "Acts/Geometry/Polyhedron.hpp"
0017 #include "Acts/Navigation/DetectorVolumeFinders.hpp"
0018 #include "Acts/Navigation/NavigationDelegates.hpp"
0019 #include "Acts/Surfaces/Surface.hpp"
0020 #include "Acts/Utilities/AxisDefinitions.hpp"
0021 #include "Acts/Utilities/BinningData.hpp"
0022 #include "Acts/Utilities/Enumerate.hpp"
0023 #include "Acts/Utilities/Grid.hpp"
0024 #include "Acts/Utilities/Helpers.hpp"
0025 #include "Acts/Utilities/ProtoAxis.hpp"
0026
0027 #include <algorithm>
0028 #include <cmath>
0029 #include <cstddef>
0030 #include <ostream>
0031 #include <set>
0032 #include <stdexcept>
0033 #include <utility>
0034
0035 namespace Acts::Experimental {
0036 class DetectorVolume;
0037 }
0038
0039 namespace {
0040
0041
0042
0043
0044
0045
0046 void adaptBinningRange(
0047 std::vector<std::tuple<Acts::DirectedProtoAxis, std::size_t>>& pBinning,
0048 const Acts::Extent& extent) {
0049 for (auto& [pb, pe] : pBinning) {
0050
0051 const auto& axis = pb.getAxis();
0052 const auto& edges = axis.getBinEdges();
0053 double vmin = edges.front();
0054 double vmax = edges.back();
0055
0056 if (extent.constrains(pb.getAxisDirection())) {
0057 const auto& range = extent.range(pb.getAxisDirection());
0058
0059 vmin = range.min();
0060 vmax = range.max();
0061 }
0062 pb.setRange(vmin, vmax);
0063 }
0064 }
0065
0066 }
0067
0068 Acts::Experimental::LayerStructureBuilder::LayerStructureBuilder(
0069 const Acts::Experimental::LayerStructureBuilder::Config& cfg,
0070 std::unique_ptr<const Acts::Logger> logger)
0071 : IInternalStructureBuilder(), m_cfg(cfg), m_logger(std::move(logger)) {
0072 if (m_cfg.surfacesProvider == nullptr) {
0073 throw std::invalid_argument(
0074 "LayerStructureBuilder: surfaces provider is nullptr.");
0075 }
0076 }
0077
0078 Acts::Experimental::InternalStructure
0079 Acts::Experimental::LayerStructureBuilder::construct(
0080 const Acts::GeometryContext& gctx) const {
0081
0082 std::vector<std::shared_ptr<DetectorVolume>> internalVolumes = {};
0083 ExternalNavigationDelegate internalVolumeUpdater = tryNoVolumes();
0084
0085
0086 if (!m_cfg.auxiliary.empty()) {
0087 ACTS_DEBUG(m_cfg.auxiliary);
0088 }
0089
0090
0091 InternalNavigationDelegate internalCandidatesUpdater =
0092 tryAllPortalsAndSurfaces();
0093 auto internalSurfaces = m_cfg.surfacesProvider->surfaces(gctx);
0094 ACTS_DEBUG("Building internal layer structure from "
0095 << internalSurfaces.size() << " provided surfaces.");
0096
0097
0098
0099 std::vector<std::size_t> assignToAll = {};
0100 if (!m_cfg.supports.empty()) {
0101 ACTS_DEBUG("Adding " << m_cfg.supports.size() << " support structures.");
0102
0103 for (const auto& support : m_cfg.supports) {
0104
0105 if (support.surface != nullptr) {
0106 ACTS_VERBOSE("- Use provided support surface directly.");
0107 if (support.assignToAll) {
0108 assignToAll.push_back(internalSurfaces.size());
0109 ACTS_VERBOSE(" Support surface is assigned to all bins.");
0110 }
0111 internalSurfaces.push_back(support.surface);
0112 continue;
0113 }
0114
0115
0116 if (support.type == Surface::SurfaceType::Other) {
0117 throw std::invalid_argument(
0118 "LayerStructureBuilder: support surface type not specified.");
0119 }
0120 ACTS_VERBOSE("- Build support of type '"
0121 << Acts::Surface::s_surfaceTypeNames[support.type] << "'.");
0122 if (support.splits > 1u) {
0123 ACTS_VERBOSE(" Support surface is modelled with " << support.splits
0124 << " planes.");
0125 }
0126
0127
0128 Extent supportExtent;
0129
0130
0131 for (const auto& bv : allAxisDirections()) {
0132 if (support.volumeExtent.constrains(bv) &&
0133 !rangeContainsValue(support.internalConstraints, bv)) {
0134 ACTS_VERBOSE(" Support surface is constrained by volume extent in "
0135 << axisDirectionName(bv));
0136 supportExtent.set(bv, support.volumeExtent.min(bv),
0137 support.volumeExtent.max(bv));
0138 }
0139 }
0140
0141
0142 if (!support.internalConstraints.empty()) {
0143
0144 for (const auto& s : internalSurfaces) {
0145 auto sPolyhedron =
0146 s->polyhedronRepresentation(gctx, m_cfg.quarterSegments);
0147 supportExtent.extend(sPolyhedron.extent(),
0148 support.internalConstraints);
0149 }
0150 }
0151
0152
0153 if (support.type == Surface::SurfaceType::Cylinder) {
0154 detail::SupportSurfacesHelper::CylindricalSupport cSupport{
0155 support.offset, support.volumeClearance[AxisDirection::AxisZ],
0156 support.volumeClearance[AxisDirection::AxisPhi]};
0157 detail::SupportSurfacesHelper::addSupport(internalSurfaces, assignToAll,
0158 supportExtent, cSupport,
0159 support.splits);
0160 } else if (support.type == Surface::SurfaceType::Disc) {
0161
0162 detail::SupportSurfacesHelper::DiscSupport dSupport{
0163 support.offset, support.volumeClearance[AxisDirection::AxisR],
0164 support.volumeClearance[AxisDirection::AxisPhi]};
0165 detail::SupportSurfacesHelper::addSupport(internalSurfaces, assignToAll,
0166 supportExtent, dSupport,
0167 support.splits);
0168 } else if (support.type == Surface::SurfaceType::Plane) {
0169
0170 std::array<AxisDirection, 2> locals = {AxisDirection::AxisX,
0171 AxisDirection::AxisY};
0172 if (support.pPlacement == AxisDirection::AxisX) {
0173 locals = {AxisDirection::AxisY, AxisDirection::AxisZ};
0174 } else if (support.pPlacement == AxisDirection::AxisY) {
0175 locals = {AxisDirection::AxisZ, AxisDirection::AxisX};
0176 }
0177
0178 detail::SupportSurfacesHelper::RectangularSupport rSupport{
0179 support.pPlacement, support.offset,
0180 support.volumeClearance[locals[0u]],
0181 support.volumeClearance[locals[1u]]};
0182 detail::SupportSurfacesHelper::addSupport(internalSurfaces, assignToAll,
0183 supportExtent, rSupport);
0184 }
0185
0186 else {
0187 throw std::invalid_argument(
0188 "LayerStructureBuilder: support surface type not supported.");
0189 }
0190 }
0191 }
0192
0193 if (internalSurfaces.size() >= m_cfg.nMinimalSurfaces) {
0194
0195 auto binnings = m_cfg.binnings;
0196
0197 if (binnings.empty()) {
0198 ACTS_DEBUG(
0199 "No surface binning provided, navigation will be 'tryAll' "
0200 "(potentially slow).");
0201 } else {
0202
0203 std::ranges::sort(binnings, {}, [](const auto& b) {
0204 return std::get<DirectedProtoAxis>(b).getAxisDirection();
0205 });
0206
0207 if (m_cfg.extent.has_value()) {
0208 ACTS_DEBUG("- adapting the proto binning range to the surface extent.");
0209 adaptBinningRange(binnings, m_cfg.extent.value());
0210 }
0211
0212
0213 Acts::Experimental::detail::PolyhedronReferenceGenerator rGenerator;
0214
0215
0216 if (binnings.size() == 1) {
0217 ACTS_DEBUG("- creating a 1D internal binning and portal navigation");
0218 const auto& [protoAxis, fillExpansion] = binnings.at(0);
0219 internalCandidatesUpdater =
0220 Acts::detail::IndexedSurfacesGenerator::createInternalNavigation<
0221 Experimental::IndexedSurfacesNavigation>(
0222 gctx, internalSurfaces, rGenerator, protoAxis, fillExpansion,
0223 assignToAll);
0224 } else if (binnings.size() == 2u) {
0225 ACTS_DEBUG("- creating a 2D internal binning and portal navigation");
0226 const auto& [protoAxisA, fillExpansionA] = binnings.at(0);
0227 const auto& [protoAxisB, fillExpansionB] = binnings.at(1);
0228 internalCandidatesUpdater =
0229 Acts::detail::IndexedSurfacesGenerator::createInternalNavigation<
0230 Experimental::IndexedSurfacesNavigation>(
0231 gctx, internalSurfaces, rGenerator, protoAxisA, fillExpansionA,
0232 protoAxisB, fillExpansionB, assignToAll);
0233 } else {
0234 throw std::runtime_error(
0235 "LayerStructureBuilder: only 1D or 2D surface binning "
0236 "supported.");
0237 }
0238 }
0239 } else {
0240 ACTS_DEBUG("Only " << internalSurfaces.size() << " surfaces provided, "
0241 << "navigation will be 'tryAll'");
0242 ACTS_DEBUG("Per configuration " << m_cfg.nMinimalSurfaces
0243 << " surfaces are "
0244 << "required to use the surface binning.");
0245 }
0246
0247
0248 if (!internalCandidatesUpdater.connected()) {
0249 throw std::runtime_error(
0250 "LayerStructureBuilder: could not connect surface candidate updator.");
0251 }
0252
0253
0254 return InternalStructure{internalSurfaces, internalVolumes,
0255 std::move(internalCandidatesUpdater),
0256 std::move(internalVolumeUpdater)};
0257 }