Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:11:18

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
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 }  // namespace Acts::Experimental
0039 
0040 namespace {
0041 
0042 /// Check autorange for a given binning
0043 ///
0044 /// @param pBinning the proto binning
0045 /// @param extent the extent from which the range is taken
0046 ///
0047 void adaptBinningRange(std::vector<Acts::Experimental::ProtoBinning>& pBinning,
0048                        const Acts::Extent& extent) {
0049   for (auto& pb : pBinning) {
0050     // Starting values
0051     double vmin = pb.edges.front();
0052     double vmax = pb.edges.back();
0053     // Get the number of bins
0054     std::size_t nBins = pb.bins();
0055     // Check if extent overwrites that
0056     if (extent.constrains(pb.axisDir)) {
0057       const auto& range = extent.range(pb.axisDir);
0058       // Patch the edges values from the range
0059       vmin = range.min();
0060       vmax = range.max();
0061     }
0062     // Possibly update the edges
0063     if (pb.axisType == Acts::AxisType::Equidistant) {
0064       double binWidth = (vmax - vmin) / nBins;
0065       // Fill the edges
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 /// Helper for 1-dimensional generators
0079 ///
0080 /// @tparam aType is the axis boundary type: closed or bound
0081 ///
0082 /// @param gctx the geometry context
0083 /// @param lSurfaces the surfaces of the layer
0084 /// @param assignToAll the indices assigned to all
0085 /// @param binning the binning struct
0086 ///
0087 /// @return a configured surface candidate updators
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   // The surface candidate updator & a generator for polyhedrons
0095   Acts::Experimental::InternalNavigationDelegate sfCandidates;
0096   Acts::Experimental::detail::PolyhedronReferenceGenerator rGenerator;
0097   // Indexed Surface generator for this case
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     // Equidistant
0106     Acts::GridAxisGenerators::Eq<aType> aGenerator{
0107         {binning.edges.front(), binning.edges.back()}, binning.bins()};
0108     sfCandidates = isg(gctx, aGenerator, rGenerator);
0109   } else {
0110     // Variable
0111     Acts::GridAxisGenerators::Var<aType> aGenerator{binning.edges};
0112     sfCandidates = isg(gctx, aGenerator, rGenerator);
0113   }
0114   return sfCandidates;
0115 }
0116 
0117 /// Helper for 2-dimensional generators
0118 ///
0119 /// @tparam aType is the axis boundary type, axis a: closed or bound
0120 /// @tparam bType is the axis boundary type, axis b: closed or bound
0121 ///
0122 /// @param gctx the geometry context
0123 /// @param lSurfaces the surfaces of the layer
0124 /// @param assignToAll the indices assigned to all
0125 /// @param aBinning the binning struct of axis a
0126 /// @param bBinning the binning struct of axis b
0127 ///
0128 /// @return a configured surface candidate updators
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   // The surface candidate updator & a generator for polyhedrons
0137   Acts::Experimental::InternalNavigationDelegate sfCandidates;
0138   Acts::Experimental::detail::PolyhedronReferenceGenerator rGenerator;
0139   // Indexed Surface generator for this case
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   // Run through the cases
0147   if (aBinning.axisType == Acts::AxisType::Equidistant &&
0148       bBinning.axisType == Acts::AxisType::Equidistant) {
0149     // Equidistant-Equidistant
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     // Variable-Equidistant
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     // Equidistant-Variable
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     // Variable-Variable
0172     Acts::GridAxisGenerators::VarVar<aType, bType> aGenerator{aBinning.edges,
0173                                                               bBinning.edges};
0174     sfCandidates = isg(gctx, aGenerator, rGenerator);
0175   }
0176   // Return the candidates
0177   return sfCandidates;
0178 }
0179 
0180 }  // namespace
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   // Trivialities first: internal volumes
0196   std::vector<std::shared_ptr<DetectorVolume>> internalVolumes = {};
0197   ExternalNavigationDelegate internalVolumeUpdater = tryNoVolumes();
0198 
0199   // Print the auxiliary information
0200   if (!m_cfg.auxiliary.empty()) {
0201     ACTS_DEBUG(m_cfg.auxiliary);
0202   }
0203 
0204   // Retrieve the layer surfaces
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   // Check whether support structure is scheduled to be built, and if so
0212   // collect those that should be assigned to all bins
0213   std::vector<std::size_t> assignToAll = {};
0214   if (!m_cfg.supports.empty()) {
0215     ACTS_DEBUG("Adding " << m_cfg.supports.size() << " support structures.");
0216     // The surface candidate updator
0217     for (const auto& support : m_cfg.supports) {
0218       // Check if the supportsurface has already been built
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       // Throw an exception is misconfigured
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       // The support extent
0242       Extent supportExtent;
0243       // Let us start with an eventually existing volume extent, but only pick
0244       // the binning value that are not constrained by the internal surfaces
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       // Now add the internal constraints
0256       if (!support.internalConstraints.empty()) {
0257         // Estimate the extent from the surfaces
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       // Add cylindrical support
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         // Add disc support
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         // Set the local coordinates - cyclic permutation
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         // Add rectangular support
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     // Copy as we might patch it with the surface extent
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       // Check if autorange for binning applies
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       // Capture the binning
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       // Check if autorange for binning applies
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       // Sort the binning for conventions
0343       std::ranges::sort(binnings, {}, [](const auto& b) { return b.axisDir; });
0344 
0345       ACTS_DEBUG("- 2-dimensional surface binning detected.");
0346       // Capture the binnings
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   // Check if everything went ok
0379   if (!internalCandidatesUpdater.connected()) {
0380     throw std::runtime_error(
0381         "LayerStructureBuilder: could not connect surface candidate updator.");
0382   }
0383 
0384   // Return the internal structure
0385   return InternalStructure{internalSurfaces, internalVolumes,
0386                            std::move(internalCandidatesUpdater),
0387                            std::move(internalVolumeUpdater)};
0388 }