Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-20 07:58:14

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 #pragma once
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Detector/Portal.hpp"
0013 #include "Acts/Navigation/NavigationDelegates.hpp"
0014 #include "Acts/Navigation/NavigationState.hpp"
0015 #include "Acts/Utilities/AxisDefinitions.hpp"
0016 #include "Acts/Utilities/Enumerate.hpp"
0017 #include "Acts/Utilities/GridAccessHelpers.hpp"
0018 
0019 #include <algorithm>
0020 #include <array>
0021 
0022 namespace Acts::Experimental {
0023 
0024 /// Helper method to update the candidates (portals/surfaces),
0025 /// this can be called for initial surface/portal estimation,
0026 /// but also during the navigation to update the current list
0027 /// of candidates.
0028 ///
0029 /// @param gctx is the Geometry context of this call
0030 /// @param nState [in,out] is the navigation state to be updated
0031 ///
0032 /// @todo for surfaces skip the non-reached ones, while keep for portals
0033 inline void intitializeCandidates(const GeometryContext& gctx,
0034                                   NavigationState& nState) {
0035   const auto& position = nState.position;
0036   const auto& direction = nState.direction;
0037 
0038   nState.surfaceCandidateIndex = 0;
0039 
0040   NavigationState::SurfaceCandidates confirmedCandidates;
0041   confirmedCandidates.reserve(nState.surfaceCandidates.size());
0042 
0043   for (auto& sc : nState.surfaceCandidates) {
0044     // Get the surface representation: either native surface of portal
0045     const Surface& surface = sc.surface();
0046     // Only allow overstepping if it's not a portal
0047     double overstepTolerance =
0048         sc.isPortalTarget() ? s_onSurfaceTolerance : nState.overstepTolerance;
0049     // Boundary tolerance is forced to 0 for portals
0050     BoundaryTolerance boundaryTolerance = sc.isPortalTarget()
0051                                               ? BoundaryTolerance::None()
0052                                               : sc.boundaryTolerance();
0053     // Check the surface intersection
0054     auto multiIntersection = surface.intersect(
0055         gctx, position, direction, boundaryTolerance, s_onSurfaceTolerance);
0056     for (auto [intersectionIndex, intersection] :
0057          Acts::enumerate(multiIntersection)) {
0058       if (intersection.isValid() &&
0059           intersection.pathLength() > overstepTolerance) {
0060         if (sc.isPortalTarget()) {
0061           confirmedCandidates.emplace_back(intersection, intersectionIndex,
0062                                            sc.gen2Portal(), boundaryTolerance);
0063         } else {
0064           confirmedCandidates.emplace_back(intersection, intersectionIndex,
0065                                            surface, boundaryTolerance);
0066         }
0067       }
0068     }
0069   }
0070 
0071   std::ranges::sort(confirmedCandidates, {}, [](const auto& c) {
0072     return c.intersection().pathLength();
0073   });
0074 
0075   nState.surfaceCandidates = std::move(confirmedCandidates);
0076   nState.surfaceCandidateIndex = 0;
0077 }
0078 
0079 /// @brief This sets a single object, e.g. single surface or single volume
0080 /// into the navigation state
0081 ///
0082 /// @tparam navigation_type distinguishes between internal and external navigation
0083 /// @tparam object_type the type of the object to be filled
0084 /// @tparam filler_type is the helper to fill the object into nState
0085 ///
0086 template <typename navigation_type, typename object_type, typename filler_type>
0087 class SingleObjectNavigation : public navigation_type {
0088  public:
0089   /// Convenience constructor
0090   /// @param so the single object
0091   explicit SingleObjectNavigation(const object_type* so) : m_object(so) {
0092     if (so == nullptr) {
0093       throw std::invalid_argument("SingleObjectNavigation: object is nullptr");
0094     }
0095   }
0096 
0097   /// @brief Fill the navigation state with a single object that it holds
0098   ///
0099   /// @param gctx is the Geometry context of this call
0100   /// @param nState the navigation state to which the surfaces are attached
0101   ///
0102   /// @note this is attaching objects without intersecting nor checking
0103   void fill([[maybe_unused]] const GeometryContext& gctx,
0104             NavigationState& nState) const {
0105     filler_type::fill(nState, m_object);
0106   }
0107 
0108   /// @brief Update the navigation state with a single object that it holds
0109   ///
0110   /// @note it calls fill and then initializes the candidates (including intersection)
0111   ///
0112   /// @param gctx is the Geometry context of this call
0113   /// @param nState the navigation state to which the surfaces are attached
0114   ///
0115   /// @note this is attaching objects and will perform a check
0116   void update([[maybe_unused]] const GeometryContext& gctx,
0117               NavigationState& nState) const {
0118     fill(gctx, nState);
0119     // If the delegate type is of type IInternalNavigation
0120     if constexpr (std::is_base_of_v<IInternalNavigation, navigation_type>) {
0121       intitializeCandidates(gctx, nState);
0122     }
0123   }
0124 
0125   /// Const Access to the object
0126   /// @return Pointer to the object or nullptr if not set
0127   const object_type* object() const { return m_object; }
0128 
0129  private:
0130   // The object to be filled in
0131   const object_type* m_object = nullptr;
0132 };
0133 
0134 /// @brief This uses stateless extractor and fillers to manipulate
0135 /// the navigation state
0136 ///
0137 /// @tparam navigation_type distinguishes between internal and external navigation
0138 /// @tparam extractor_type the helper to extract the objects from
0139 /// @tparam filler_type is the helper to fill the object into nState
0140 ///
0141 template <typename navigation_type, typename extractor_type,
0142           typename filler_type>
0143 class StaticAccessNavigation : public navigation_type {
0144  public:
0145   /// @brief fills the navigation state with extracted objects
0146   ///
0147   /// @param gctx is the Geometry context of this call
0148   /// @param nState the navigation state to which the surfaces are attached
0149   ///
0150   /// @note this is attaching objects without intersecting nor checking
0151   void fill([[maybe_unused]] const GeometryContext& gctx,
0152             NavigationState& nState) const {
0153     auto extracted = extractor_type::extract(gctx, nState);
0154     filler_type::fill(nState, extracted);
0155   }
0156 
0157   /// @brief Update the navigation state with extracted objects
0158   ///
0159   /// @note it calls fill and then initializes the candidates (including intersection)
0160   ///
0161   /// @param gctx is the Geometry context of this call
0162   /// @param nState the navigation state to which the surfaces are attached
0163   ///
0164   /// @note this will perform the intersection test
0165   void update([[maybe_unused]] const GeometryContext& gctx,
0166               NavigationState& nState) const {
0167     fill(gctx, nState);
0168     // If the delegate type is of type IInternalNavigation
0169     if constexpr (std::is_base_of_v<IInternalNavigation, navigation_type>) {
0170       intitializeCandidates(gctx, nState);
0171     }
0172   }
0173 };
0174 
0175 /// @brief  This is an index grid based navigation state updator, it uses
0176 /// an extractor type and a filler type to handle the navigation state
0177 ///
0178 /// @note a transform is applied `p3l = transform * p3` in order to allow
0179 /// shifted, transformed grids
0180 ///
0181 /// It can be used for volumes, surfaces at convenience
0182 ///
0183 /// @tparam navigation_type distinguishes between internal and external navigation
0184 /// @tparam grid_t is the type of the grid
0185 /// @tparam extractor_type is the helper to extract the object
0186 /// @tparam filler_type is the helper to fill the object into the nState
0187 template <typename navigation_type, typename grid_t, typename extractor_type,
0188           typename filler_type>
0189 class IndexedGridNavigation : public navigation_type {
0190  public:
0191   /// Broadcast the grid type
0192   using grid_type = grid_t;
0193 
0194   /// An extractor helper to get the object(s) from the volume
0195   extractor_type extractor;
0196 
0197   /// The grid where the indices are stored
0198   grid_type grid;
0199 
0200   /// These are the cast parameters - copied from constructor
0201   std::array<AxisDirection, grid_type::DIM> casts{};
0202 
0203   /// A transform to be applied to the position
0204   Transform3 transform = Transform3::Identity();
0205 
0206   /// @brief  Constructor for a grid based surface attacher
0207   /// @param igrid the grid that is moved into this attacher
0208   /// @param icasts is the cast values array
0209   /// @param itr a transform applied to the global position
0210   IndexedGridNavigation(grid_type&& igrid,
0211                         const std::array<AxisDirection, grid_type::DIM>& icasts,
0212                         const Transform3& itr = Transform3::Identity())
0213       : grid(std::move(igrid)), casts(icasts), transform(itr) {}
0214 
0215   IndexedGridNavigation() = delete;
0216 
0217   /// @brief fill the navigation state with objects from the grid entries
0218   /// AFTER applying `p3loc = transform * p3` and casting to subsbpace
0219   ///
0220   /// @param gctx is the Geometry context of this call
0221   /// @param nState the navigation state to which the surfaces are attached
0222   ///
0223   /// @note this will only fill the state without intersecting
0224   void fill(const GeometryContext& gctx, NavigationState& nState) const {
0225     // Extract the index grid entry a
0226     const auto& entry =
0227         grid.atPosition(GridAccessHelpers::castPosition<grid_type>(
0228             transform * nState.position, casts));
0229     auto extracted = extractor.extract(gctx, nState, entry);
0230     filler_type::fill(nState, extracted);
0231   }
0232 
0233   /// @brief Update the navigation state with objects from the entries
0234   /// AFTER applying `p3loc = transform * p3` and casting to subsbpace
0235   ///
0236   /// @note it calls fill and then initializes the candidates (including intersection)
0237   ///
0238   /// @param gctx is the Geometry context of this call
0239   /// @param nState the navigation state to which the surfaces are attached
0240   ///
0241   /// @note this will perform the intersection test for internal navigation paths
0242   void update(const GeometryContext& gctx, NavigationState& nState) const {
0243     fill(gctx, nState);
0244     // If the delegate type is of type IInternalNavigation
0245     if constexpr (std::is_base_of_v<IInternalNavigation, navigation_type>) {
0246       // Update the candidates: initial update
0247       intitializeCandidates(gctx, nState);
0248     }
0249   }
0250 };
0251 
0252 /// This is a chained updated, which can either performed a chained filling,
0253 /// or a chaine update (which included intersection test)
0254 ///
0255 /// @tparam navigation_type distinguishes between internal and external navigation
0256 /// @tparam updators_t the updators that will be called in sequence
0257 ///
0258 template <typename navigation_type, typename... updators_t>
0259 class ChainedNavigation : public navigation_type {
0260  public:
0261   /// The stored updators
0262   std::tuple<updators_t...> updators;
0263 
0264   /// Constructor for chained updators in a tuple, this will unroll
0265   /// the tuple and call them in sequence
0266   ///
0267   /// @param upts the updators to be called in chain
0268   explicit ChainedNavigation(const std::tuple<updators_t...>&& upts)
0269       : updators(std::move(upts)) {}
0270 
0271   /// A combined navigation state updated to fill the candidates from
0272   /// a sequence of pre-defined updators
0273   ///
0274   /// @param gctx is the Geometry context of this call
0275   /// @param nState the navigation state to which the objects are attached
0276   ///
0277   void fill(const GeometryContext& gctx, NavigationState& nState) const {
0278     // Unfold the tuple and add the attachers
0279     std::apply([&](auto&&... updator) { ((updator.fill(gctx, nState)), ...); },
0280                updators);
0281   }
0282 
0283   /// A combined navigation state to fill & update the candidatesthe candidates
0284   ///
0285   /// @param gctx is the Geometry context of this call
0286   /// @param nState the navigation state to which the objects are attached
0287   ///
0288   /// @note It will call the chained filling and then perform a single update on
0289   /// the candidates to avoid copying and multiple intersection tests
0290   void update(const GeometryContext& gctx, NavigationState& nState) const {
0291     // Unfold the tuple and add the attachers
0292     fill(gctx, nState);
0293     // Update the candidates: initial update
0294     intitializeCandidates(gctx, nState);
0295   }
0296 };
0297 
0298 }  // namespace Acts::Experimental