File indexing completed on 2025-08-05 08:09:34
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/ProtoBinning.hpp"
0013 #include "Acts/Detector/detail/IndexedSurfacesGenerator.hpp"
0014 #include "Acts/Detector/detail/ReferenceGenerators.hpp"
0015 #include "Acts/Detector/detail/SupportSurfacesHelper.hpp"
0016 #include "Acts/Geometry/Extent.hpp"
0017 #include "Acts/Geometry/Polyhedron.hpp"
0018 #include "Acts/Navigation/DetectorVolumeFinders.hpp"
0019 #include "Acts/Navigation/NavigationDelegates.hpp"
0020 #include "Acts/Surfaces/Surface.hpp"
0021 #include "Acts/Utilities/BinningData.hpp"
0022 #include "Acts/Utilities/Enumerate.hpp"
0023 #include "Acts/Utilities/Grid.hpp"
0024 #include "Acts/Utilities/GridAxisGenerators.hpp"
0025 #include "Acts/Utilities/detail/AxisFwd.hpp"
0026
0027 #include <cmath>
0028 #include <cstddef>
0029 #include <ostream>
0030 #include <set>
0031 #include <stdexcept>
0032 #include <utility>
0033
0034 namespace Acts::Experimental {
0035 class DetectorVolume;
0036 }
0037
0038 namespace {
0039
0040
0041
0042
0043
0044
0045 void adaptBinningRange(std::vector<Acts::Experimental::ProtoBinning>& pBinning,
0046 const Acts::Extent& extent) {
0047 for (auto& pb : pBinning) {
0048
0049 Acts::ActsScalar vmin = pb.edges.front();
0050 Acts::ActsScalar vmax = pb.edges.back();
0051
0052 std::size_t nBins = pb.bins();
0053
0054 if (extent.constrains(pb.binValue)) {
0055 const auto& range = extent.range(pb.binValue);
0056
0057 vmin = range.min();
0058 vmax = range.max();
0059 }
0060
0061 if (pb.axisType == Acts::detail::AxisType::Equidistant) {
0062 Acts::ActsScalar binWidth = (vmax - vmin) / nBins;
0063
0064 pb.edges = {vmin};
0065 pb.edges.resize(nBins + 1);
0066 for (std::size_t ib = 0; ib <= nBins; ++ib) {
0067 pb.edges[ib] = vmin + ib * binWidth;
0068 }
0069 } else {
0070 pb.edges.front() = vmin;
0071 pb.edges.back() = vmax;
0072 }
0073 }
0074 }
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086 template <Acts::detail::AxisBoundaryType aType>
0087 Acts::Experimental::SurfaceCandidatesUpdater createUpdater(
0088 const Acts::GeometryContext& gctx,
0089 std::vector<std::shared_ptr<Acts::Surface>> lSurfaces,
0090 std::vector<std::size_t> assignToAll,
0091 const Acts::Experimental::ProtoBinning& binning) {
0092
0093 Acts::Experimental::SurfaceCandidatesUpdater sfCandidates;
0094 Acts::Experimental::detail::PolyhedronReferenceGenerator rGenerator;
0095
0096 Acts::Experimental::detail::IndexedSurfacesGenerator<
0097 decltype(lSurfaces), Acts::Experimental::IndexedSurfacesImpl>
0098 isg{std::move(lSurfaces),
0099 std::move(assignToAll),
0100 {binning.binValue},
0101 {binning.expansion}};
0102 if (binning.axisType == Acts::detail::AxisType::Equidistant) {
0103
0104 Acts::GridAxisGenerators::Eq<aType> aGenerator{
0105 {binning.edges.front(), binning.edges.back()}, binning.bins()};
0106 sfCandidates = isg(gctx, aGenerator, rGenerator);
0107 } else {
0108
0109 Acts::GridAxisGenerators::Var<aType> aGenerator{binning.edges};
0110 sfCandidates = isg(gctx, aGenerator, rGenerator);
0111 }
0112 return sfCandidates;
0113 }
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127 template <Acts::detail::AxisBoundaryType aType,
0128 Acts::detail::AxisBoundaryType bType>
0129 Acts::Experimental::SurfaceCandidatesUpdater createUpdater(
0130 const Acts::GeometryContext& gctx,
0131 const std::vector<std::shared_ptr<Acts::Surface>>& lSurfaces,
0132 const std::vector<std::size_t>& assignToAll,
0133 const Acts::Experimental::ProtoBinning& aBinning,
0134 const Acts::Experimental::ProtoBinning& bBinning) {
0135
0136 Acts::Experimental::SurfaceCandidatesUpdater sfCandidates;
0137 Acts::Experimental::detail::PolyhedronReferenceGenerator rGenerator;
0138
0139 Acts::Experimental::detail::IndexedSurfacesGenerator<
0140 decltype(lSurfaces), Acts::Experimental::IndexedSurfacesImpl>
0141 isg{lSurfaces,
0142 assignToAll,
0143 {aBinning.binValue, bBinning.binValue},
0144 {aBinning.expansion, bBinning.expansion}};
0145
0146 if (aBinning.axisType == Acts::detail::AxisType::Equidistant &&
0147 bBinning.axisType == Acts::detail::AxisType::Equidistant) {
0148
0149 Acts::GridAxisGenerators::EqEq<aType, bType> aGenerator{
0150 {aBinning.edges.front(), aBinning.edges.back()},
0151 aBinning.bins(),
0152 {bBinning.edges.front(), bBinning.edges.back()},
0153 bBinning.bins()};
0154 sfCandidates = isg(gctx, aGenerator, rGenerator);
0155 } else if (bBinning.axisType == Acts::detail::AxisType::Equidistant) {
0156
0157 Acts::GridAxisGenerators::VarEq<aType, bType> aGenerator{
0158 aBinning.edges,
0159 {bBinning.edges.front(), bBinning.edges.back()},
0160 bBinning.bins()};
0161 sfCandidates = isg(gctx, aGenerator, rGenerator);
0162 } else if (aBinning.axisType == Acts::detail::AxisType::Equidistant) {
0163
0164 Acts::GridAxisGenerators::EqVar<aType, bType> aGenerator{
0165 {aBinning.edges.front(), aBinning.edges.back()},
0166 aBinning.bins(),
0167 bBinning.edges};
0168 sfCandidates = isg(gctx, aGenerator, rGenerator);
0169 } else {
0170
0171 Acts::GridAxisGenerators::VarVar<aType, bType> aGenerator{aBinning.edges,
0172 bBinning.edges};
0173 sfCandidates = isg(gctx, aGenerator, rGenerator);
0174 }
0175
0176 return sfCandidates;
0177 }
0178
0179 }
0180
0181 Acts::Experimental::LayerStructureBuilder::LayerStructureBuilder(
0182 const Acts::Experimental::LayerStructureBuilder::Config& cfg,
0183 std::unique_ptr<const Acts::Logger> logger)
0184 : IInternalStructureBuilder(), m_cfg(cfg), m_logger(std::move(logger)) {
0185 if (m_cfg.surfacesProvider == nullptr) {
0186 throw std::invalid_argument(
0187 "LayerStructureBuilder: surfaces provider is nullptr.");
0188 }
0189 }
0190
0191 Acts::Experimental::InternalStructure
0192 Acts::Experimental::LayerStructureBuilder::construct(
0193 const Acts::GeometryContext& gctx) const {
0194
0195 std::vector<std::shared_ptr<DetectorVolume>> internalVolumes = {};
0196 DetectorVolumeUpdater internalVolumeUpdater = tryNoVolumes();
0197
0198
0199 if (!m_cfg.auxiliary.empty()) {
0200 ACTS_DEBUG(m_cfg.auxiliary);
0201 }
0202
0203
0204 SurfaceCandidatesUpdater internalCandidatesUpdater =
0205 tryAllPortalsAndSurfaces();
0206 auto internalSurfaces = m_cfg.surfacesProvider->surfaces(gctx);
0207 ACTS_DEBUG("Building internal layer structure from "
0208 << internalSurfaces.size() << " provided surfaces.");
0209
0210
0211
0212 std::vector<std::size_t> assignToAll = {};
0213 if (!m_cfg.supports.empty()) {
0214 ACTS_DEBUG("Adding " << m_cfg.supports.size() << " support structures.")
0215
0216 for (const auto& support : m_cfg.supports) {
0217
0218 if (support.surface != nullptr) {
0219 ACTS_VERBOSE("- Use provided support surface directly.");
0220 if (support.assignToAll) {
0221 assignToAll.push_back(internalSurfaces.size());
0222 ACTS_VERBOSE(" Support surface is assigned to all bins.");
0223 }
0224 internalSurfaces.push_back(support.surface);
0225 continue;
0226 }
0227
0228
0229 if (support.type == Surface::SurfaceType::Other) {
0230 throw std::invalid_argument(
0231 "LayerStructureBuilder: support surface type not specified.");
0232 }
0233 ACTS_VERBOSE("- Build support of type '"
0234 << Acts::Surface::s_surfaceTypeNames[support.type] << "'.");
0235 if (support.splits > 1u) {
0236 ACTS_VERBOSE(" Support surface is modelled with " << support.splits
0237 << " planes.");
0238 }
0239
0240
0241 Extent supportExtent;
0242
0243
0244 for (const auto& bv : s_binningValues) {
0245 if (support.volumeExtent.constrains(bv) &&
0246 std::find(support.internalConstraints.begin(),
0247 support.internalConstraints.end(),
0248 bv) == support.internalConstraints.end()) {
0249 ACTS_VERBOSE(" Support surface is constrained by volume extent in "
0250 << binningValueNames()[bv]);
0251 supportExtent.set(bv, support.volumeExtent.min(bv),
0252 support.volumeExtent.max(bv));
0253 }
0254 }
0255
0256
0257 if (!support.internalConstraints.empty()) {
0258
0259 for (const auto& s : internalSurfaces) {
0260 auto sPolyhedron = s->polyhedronRepresentation(gctx, m_cfg.nSegments);
0261 supportExtent.extend(sPolyhedron.extent(),
0262 support.internalConstraints);
0263 }
0264 }
0265
0266
0267 if (support.type == Surface::SurfaceType::Cylinder) {
0268 detail::SupportSurfacesHelper::CylindricalSupport cSupport{
0269 support.offset, support.volumeClearance[binZ],
0270 support.volumeClearance[binPhi]};
0271 detail::SupportSurfacesHelper::addSupport(internalSurfaces, assignToAll,
0272 supportExtent, cSupport,
0273 support.splits);
0274 } else if (support.type == Surface::SurfaceType::Disc) {
0275
0276 detail::SupportSurfacesHelper::DiscSupport dSupport{
0277 support.offset, support.volumeClearance[binR],
0278 support.volumeClearance[binPhi]};
0279 detail::SupportSurfacesHelper::addSupport(internalSurfaces, assignToAll,
0280 supportExtent, dSupport,
0281 support.splits);
0282 } else if (support.type == Surface::SurfaceType::Plane) {
0283
0284 std::array<BinningValue, 2> locals = {binX, binY};
0285 if (support.pPlacement == binX) {
0286 locals = {binY, binZ};
0287 } else if (support.pPlacement == binY) {
0288 locals = {binZ, binX};
0289 }
0290
0291 detail::SupportSurfacesHelper::RectangularSupport rSupport{
0292 support.pPlacement, support.offset,
0293 support.volumeClearance[locals[0u]],
0294 support.volumeClearance[locals[1u]]};
0295 detail::SupportSurfacesHelper::addSupport(internalSurfaces, assignToAll,
0296 supportExtent, rSupport);
0297 }
0298
0299 else {
0300 throw std::invalid_argument(
0301 "LayerStructureBuilder: support surface type not supported.");
0302 }
0303 }
0304 }
0305
0306 if (internalSurfaces.size() >= m_cfg.nMinimalSurfaces) {
0307
0308 auto binnings = m_cfg.binnings;
0309
0310 if (binnings.empty()) {
0311 ACTS_DEBUG(
0312 "No surface binning provided, navigation will be 'tryAll' "
0313 "(potentially slow).");
0314 } else if (binnings.size() == 1u) {
0315
0316 if (m_cfg.extent.has_value()) {
0317 ACTS_DEBUG("- adapting the proto binning range to the surface extent.");
0318 adaptBinningRange(binnings, m_cfg.extent.value());
0319 }
0320 ACTS_DEBUG("- 1-dimensional surface binning detected.");
0321
0322 auto binning = binnings[0u];
0323 if (binning.boundaryType == Acts::detail::AxisBoundaryType::Closed) {
0324 ACTS_VERBOSE("-- closed binning option.");
0325 internalCandidatesUpdater =
0326 createUpdater<Acts::detail::AxisBoundaryType::Closed>(
0327 gctx, internalSurfaces, assignToAll, binning);
0328 } else {
0329 ACTS_VERBOSE("-- bound binning option.");
0330 internalCandidatesUpdater =
0331 createUpdater<Acts::detail::AxisBoundaryType::Bound>(
0332 gctx, internalSurfaces, assignToAll, binning);
0333 }
0334 } else if (binnings.size() == 2u) {
0335
0336 if (m_cfg.extent.has_value()) {
0337 ACTS_DEBUG(
0338 "- adapting the proto binning range(s) to the surface extent.");
0339 adaptBinningRange(binnings, m_cfg.extent.value());
0340 }
0341
0342 std::sort(binnings.begin(), binnings.end(),
0343 [](const ProtoBinning& a, const ProtoBinning& b) {
0344 return a.binValue < b.binValue;
0345 });
0346
0347 ACTS_DEBUG("- 2-dimensional surface binning detected.");
0348
0349 const auto& binning0 = binnings[0u];
0350 const auto& binning1 = binnings[1u];
0351
0352 if (binning0.boundaryType == Acts::detail::AxisBoundaryType::Closed) {
0353 ACTS_VERBOSE("-- closed/bound binning option.");
0354 internalCandidatesUpdater =
0355 createUpdater<Acts::detail::AxisBoundaryType::Closed,
0356 Acts::detail::AxisBoundaryType::Bound>(
0357 gctx, internalSurfaces, assignToAll, binning0, binning1);
0358 } else if (binning1.boundaryType ==
0359 Acts::detail::AxisBoundaryType::Closed) {
0360 ACTS_VERBOSE("-- bound/closed binning option.");
0361 internalCandidatesUpdater =
0362 createUpdater<Acts::detail::AxisBoundaryType::Bound,
0363 Acts::detail::AxisBoundaryType::Closed>(
0364 gctx, internalSurfaces, assignToAll, binning0, binning1);
0365 } else {
0366 ACTS_VERBOSE("-- bound/bound binning option.");
0367 internalCandidatesUpdater =
0368 createUpdater<Acts::detail::AxisBoundaryType::Bound,
0369 Acts::detail::AxisBoundaryType::Bound>(
0370 gctx, internalSurfaces, assignToAll, binning0, binning1);
0371 }
0372 }
0373 } else {
0374 ACTS_DEBUG("Only " << internalSurfaces.size() << " surfaces provided, "
0375 << "navigation will be 'tryAll'");
0376 ACTS_DEBUG("Per configuration " << m_cfg.nMinimalSurfaces
0377 << " surfaces are "
0378 << "required to use the surface binning.");
0379 }
0380
0381
0382 if (!internalCandidatesUpdater.connected()) {
0383 throw std::runtime_error(
0384 "LayerStructureBuilder: could not connect surface candidate updator.");
0385 }
0386
0387
0388 return InternalStructure{internalSurfaces, internalVolumes,
0389 std::move(internalCandidatesUpdater),
0390 std::move(internalVolumeUpdater)};
0391 }