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