Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-01 07:52:45

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/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 }  // namespace Acts::Experimental
0038 
0039 namespace {
0040 
0041 /// Check autorange for a given binning
0042 ///
0043 /// @param pBinning the proto binning
0044 /// @param extent the extent from which the range is taken
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     // Starting values
0051     const auto& axis = pb.getAxis();
0052     const auto& edges = axis.getBinEdges();
0053     double vmin = edges.front();
0054     double vmax = edges.back();
0055     // Check if extent overwrites that
0056     if (extent.constrains(pb.getAxisDirection())) {
0057       const auto& range = extent.range(pb.getAxisDirection());
0058       // Patch the edges values from the range
0059       vmin = range.min();
0060       vmax = range.max();
0061     }
0062     pb.setRange(vmin, vmax);
0063   }
0064 }
0065 
0066 }  // namespace
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   // Trivialities first: internal volumes
0082   std::vector<std::shared_ptr<DetectorVolume>> internalVolumes = {};
0083   ExternalNavigationDelegate internalVolumeUpdater = tryNoVolumes();
0084 
0085   // Print the auxiliary information
0086   if (!m_cfg.auxiliary.empty()) {
0087     ACTS_DEBUG(m_cfg.auxiliary);
0088   }
0089 
0090   // Retrieve the layer surfaces
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   // Check whether support structure is scheduled to be built, and if so
0098   // collect those that should be assigned to all bins
0099   std::vector<std::size_t> assignToAll = {};
0100   if (!m_cfg.supports.empty()) {
0101     ACTS_DEBUG("Adding " << m_cfg.supports.size() << " support structures.");
0102     // The surface candidate updator
0103     for (const auto& support : m_cfg.supports) {
0104       // Check if the supportsurface has already been built
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       // Throw an exception is misconfigured
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       // The support extent
0128       Extent supportExtent;
0129       // Let us start with an eventually existing volume extent, but only pick
0130       // the binning value that are not constrained by the internal surfaces
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       // Now add the internal constraints
0142       if (!support.internalConstraints.empty()) {
0143         // Estimate the extent from the surfaces
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       // Add cylindrical support
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         // Add disc support
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         // Set the local coordinates - cyclic permutation
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         // Add rectangular support
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     // Copy as we might patch it with the surface extent
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       // Sort the binning for conventions
0203       std::ranges::sort(binnings, {}, [](const auto& b) {
0204         return std::get<DirectedProtoAxis>(b).getAxisDirection();
0205       });
0206       // Check if autorange for binning applies
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       // Provide a reference generator
0213       Acts::Experimental::detail::PolyhedronReferenceGenerator rGenerator;
0214 
0215       // 1D surface binning
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   // Check if everything went ok
0248   if (!internalCandidatesUpdater.connected()) {
0249     throw std::runtime_error(
0250         "LayerStructureBuilder: could not connect surface candidate updator.");
0251   }
0252 
0253   // Return the internal structure
0254   return InternalStructure{internalSurfaces, internalVolumes,
0255                            std::move(internalCandidatesUpdater),
0256                            std::move(internalVolumeUpdater)};
0257 }