Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-09 08:18:11

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/Definitions/Tolerance.hpp"
0013 #include "Acts/Utilities/Logger.hpp"
0014 
0015 #include <algorithm>
0016 #include <array>
0017 #include <cstddef>
0018 #include <cstdint>
0019 #include <limits>
0020 #include <span>
0021 #include <type_traits>
0022 
0023 namespace Acts {
0024 
0025 /// Status enum
0026 enum class IntersectionStatus : int {
0027   unreachable = 0,
0028   reachable = 1,
0029   onSurface = 2
0030 };
0031 
0032 /// Ostream-operator for the IntersectionStatus enum
0033 /// @param os Output stream
0034 /// @param status IntersectionStatus to output
0035 /// @return Reference to output stream
0036 inline std::ostream& operator<<(std::ostream& os, IntersectionStatus status) {
0037   constexpr static std::array<const char*, 3> names = {
0038       {"missed/unreachable", "reachable", "onSurface"}};
0039 
0040   os << names[static_cast<std::size_t>(status)];
0041   return os;
0042 }
0043 
0044 /// Intersection struct containing the position, path length and status of an
0045 /// intersection.
0046 template <unsigned int DIM>
0047 class Intersection {
0048  public:
0049   /// Position type
0050   using Position = Eigen::Map<const Vector<DIM>>;
0051 
0052   /// Constructor with arguments
0053   ///
0054   /// @param position is the position of the intersection
0055   /// @param pathLength is the path length to the intersection
0056   /// @param status is an enum indicating the status of the intersection
0057   constexpr Intersection(const Vector<DIM>& position, double pathLength,
0058                          IntersectionStatus status) noexcept
0059       : Intersection(std::span<const double, DIM>{position.data(), DIM},
0060                      pathLength, status) {}
0061 
0062   /// Constructor from position vector, path length, and status
0063   /// @param position The intersection position
0064   /// @param pathLength The path length to the intersection
0065   /// @param status The intersection status
0066   constexpr Intersection(const Position& position, double pathLength,
0067                          IntersectionStatus status) noexcept
0068       : Intersection(std::span<const double, DIM>{position.data(), DIM},
0069                      pathLength, status) {}
0070 
0071   /// Constructor from position span, path length, and status
0072   /// @param position Span of position coordinates
0073   /// @param pathLength The path length to the intersection
0074   /// @param status The intersection status
0075   constexpr Intersection(std::span<const double, DIM> position,
0076                          double pathLength, IntersectionStatus status) noexcept
0077       : m_pathLength(pathLength), m_status(status) {
0078     std::ranges::copy(position, m_position.begin());
0079   }
0080 
0081   /// Copy constructor
0082   constexpr Intersection(const Intersection&) noexcept = default;
0083   /// Move constructor
0084   constexpr Intersection(Intersection&&) noexcept = default;
0085   /// Copy assignment operator
0086   /// @return Reference to this intersection for chaining
0087   constexpr Intersection& operator=(const Intersection&) noexcept = default;
0088   /// Move assignment operator
0089   /// @return Reference to this intersection for chaining
0090   constexpr Intersection& operator=(Intersection&&) noexcept = default;
0091 
0092   /// Returns whether the intersection was successful or not
0093   /// @return True if intersection is reachable or on surface, false if unreachable
0094   constexpr bool isValid() const noexcept {
0095     return m_status != IntersectionStatus::unreachable;
0096   }
0097 
0098   /// Returns the position of the interseciton
0099   /// @return Position vector of the intersection point
0100   Position position() const noexcept { return Position{m_position.data()}; }
0101 
0102   /// Returns the path length to the intersection
0103   /// @return Signed path length from origin to intersection point
0104   constexpr double pathLength() const noexcept { return m_pathLength; }
0105 
0106   /// Returns the intersection status enum
0107   /// @return Status indicating if intersection is unreachable, reachable, or on surface
0108   constexpr IntersectionStatus status() const noexcept { return m_status; }
0109 
0110   /// Static factory to create an invalid intersection
0111   /// @return Invalid intersection with unreachable status
0112   constexpr static Intersection Invalid() noexcept { return Intersection(); }
0113 
0114   /// Comparison function for path length order i.e. intersection closest to
0115   /// -inf will be first.
0116   /// @param aIntersection First intersection to compare
0117   /// @param bIntersection Second intersection to compare
0118   /// @return True if first intersection has smaller path length than second
0119   constexpr static bool pathLengthOrder(
0120       const Intersection& aIntersection,
0121       const Intersection& bIntersection) noexcept {
0122     auto a = aIntersection.pathLength();
0123     auto b = bIntersection.pathLength();
0124     return a < b;
0125   }
0126 
0127   /// Comparison function for closest order i.e. intersection closest to 0 will
0128   /// be first.
0129   /// @param aIntersection First intersection to compare
0130   /// @param bIntersection Second intersection to compare
0131   /// @return True if first intersection is closer to zero path length than second
0132   constexpr static bool closestOrder(
0133       const Intersection& aIntersection,
0134       const Intersection& bIntersection) noexcept {
0135     using enum IntersectionStatus;
0136 
0137     if ((aIntersection.status() == unreachable) &&
0138         (bIntersection.status() != unreachable)) {
0139       return false;
0140     }
0141     if ((aIntersection.status() != unreachable) &&
0142         (bIntersection.status() == unreachable)) {
0143       return true;
0144     }
0145     // both are reachable or onSurface now
0146     auto a = aIntersection.pathLength();
0147     auto b = bIntersection.pathLength();
0148     return std::abs(a) < std::abs(b);
0149   }
0150 
0151   /// Comparison function for closest forward order i.e. intersection closest to
0152   /// 0 with positive path length will be first.
0153   /// @param aIntersection First intersection to compare
0154   /// @param bIntersection Second intersection to compare
0155   /// @return True if first intersection is closer to zero with preference for forward direction
0156   constexpr static bool closestForwardOrder(
0157       const Intersection& aIntersection,
0158       const Intersection& bIntersection) noexcept {
0159     auto a = aIntersection.pathLength();
0160     auto b = bIntersection.pathLength();
0161     return std::signbit(a) == std::signbit(b) ? std::abs(a) < std::abs(b)
0162                                               : a > b;
0163   }
0164 
0165  private:
0166   /// Position of the intersection
0167   std::array<double, DIM> m_position{};
0168   /// Signed path length to the intersection (if valid)
0169   double m_pathLength = std::numeric_limits<double>::infinity();
0170   /// The Status of the intersection
0171   IntersectionStatus m_status = IntersectionStatus::unreachable;
0172 
0173   constexpr Intersection() noexcept = default;
0174 };
0175 
0176 /// Type alias for 2D intersection
0177 using Intersection2D = Intersection<2>;
0178 /// Type alias for 3D intersection
0179 using Intersection3D = Intersection<3>;
0180 
0181 static_assert(std::is_trivially_copy_constructible_v<Intersection2D>);
0182 static_assert(std::is_trivially_move_constructible_v<Intersection2D>);
0183 static_assert(std::is_trivially_move_assignable_v<Intersection2D>);
0184 
0185 /// Index type for intersections
0186 using IntersectionIndex = std::uint8_t;
0187 /// Maximum number of intersections that can be stored
0188 static constexpr IntersectionIndex s_maximumNumberOfIntersections = 2;
0189 
0190 /// Container for up to two intersections in a given dimension.
0191 template <unsigned int DIM>
0192 class MultiIntersection {
0193  public:
0194   /// Intersection type for this dimension
0195   using IntersectionType = Intersection<DIM>;
0196   /// Pair of intersection and its index
0197   using IndexedIntersection = std::pair<IntersectionType, IntersectionIndex>;
0198 
0199   /// Container type for storing intersections
0200   using Container =
0201       std::array<IntersectionType, s_maximumNumberOfIntersections>;
0202 
0203   /// Size type for indexing
0204   using size_type = IntersectionIndex;
0205 
0206   /// Construct from single intersection
0207   /// @param intersection The intersection
0208   constexpr explicit MultiIntersection(
0209       const IntersectionType& intersection) noexcept
0210       : m_intersections{intersection, IntersectionType::Invalid()}, m_size{1} {}
0211   /// Construct from two intersections
0212   /// @param intersection1 The first intersection
0213   /// @param intersection2 The second intersection
0214   constexpr MultiIntersection(const IntersectionType& intersection1,
0215                               const IntersectionType& intersection2) noexcept
0216       : m_intersections{intersection1, intersection2}, m_size{2} {}
0217 
0218   /// Copy constructor
0219   constexpr MultiIntersection(const MultiIntersection&) noexcept = default;
0220   /// Move constructor
0221   constexpr MultiIntersection(MultiIntersection&&) noexcept = default;
0222   /// Copy assignment operator
0223   /// @return Reference to this object
0224   constexpr MultiIntersection& operator=(const MultiIntersection&) noexcept =
0225       default;
0226   /// Move assignment operator
0227   /// @return Reference to this object
0228   constexpr MultiIntersection& operator=(MultiIntersection&&) noexcept =
0229       default;
0230 
0231   /// Access intersection by index
0232   /// @param index The index of the intersection
0233   /// @return Reference to the intersection
0234   constexpr const IntersectionType& operator[](IntersectionIndex index) const {
0235     return m_intersections[index];
0236   }
0237 
0238   /// Access intersection at index with bounds checking
0239   /// @param index The index of the intersection
0240   /// @return Reference to the intersection
0241   constexpr const IntersectionType& at(IntersectionIndex index) const {
0242     return m_intersections.at(index);
0243   }
0244 
0245   /// Get the number of intersections
0246   /// @return The number of intersections
0247   constexpr IntersectionIndex size() const noexcept { return m_size; }
0248 
0249   /// Get begin iterator
0250   /// @return Iterator to the beginning
0251   constexpr auto begin() const noexcept {
0252     return std::span(m_intersections.data(), m_size).begin();
0253   }
0254   /// Get end iterator
0255   /// @return Iterator to the end
0256   constexpr auto end() const noexcept {
0257     return std::span(m_intersections.data(), m_size).end();
0258   }
0259 
0260   /// Get closest intersection
0261   /// @return The closest intersection
0262   constexpr IntersectionType closest() const noexcept {
0263     return closestWithIndex().first;
0264   }
0265   /// Get closest intersection with its index
0266   /// @return Pair of intersection and its index
0267   constexpr IndexedIntersection closestWithIndex() const noexcept {
0268     auto min = std::ranges::min_element(m_intersections,
0269                                         IntersectionType::closestOrder);
0270     return {*min, static_cast<IntersectionIndex>(
0271                       std::distance(m_intersections.begin(), min))};
0272   }
0273 
0274   /// Get closest forward intersection
0275   /// @return The closest forward intersection
0276   constexpr IntersectionType closestForward() const noexcept {
0277     return closestForwardWithIndex().first;
0278   }
0279   /// Get closest forward intersection with its index
0280   /// @return Pair of intersection and its index
0281   constexpr IndexedIntersection closestForwardWithIndex() const noexcept {
0282     auto min = std::ranges::min_element(m_intersections,
0283                                         IntersectionType::closestForwardOrder);
0284     return {*min, static_cast<IntersectionIndex>(
0285                       std::distance(m_intersections.begin(), min))};
0286   }
0287 
0288  private:
0289   Container m_intersections{};
0290   IntersectionIndex m_size{};
0291 };
0292 
0293 /// Container for up to two 2D intersections
0294 using MultiIntersection2D = MultiIntersection<2>;
0295 /// Container for up to two 3D intersections
0296 using MultiIntersection3D = MultiIntersection<3>;
0297 
0298 static_assert(std::is_trivially_copy_constructible_v<MultiIntersection2D>);
0299 static_assert(std::is_trivially_move_constructible_v<MultiIntersection2D>);
0300 static_assert(std::is_trivially_move_assignable_v<MultiIntersection2D>);
0301 
0302 namespace detail {
0303 
0304 /// Verbose-logging companion of checkPathLength(): prints why a path length
0305 /// is (not) within the limits. Split out of line so the inline fast path
0306 /// below stays free of the log-message formatting.
0307 ///
0308 /// @param pathLength The path length of the intersection
0309 /// @param nearLimit The minimum path length for an intersection to be considered
0310 /// @param farLimit The maximum path length for an intersection to be considered
0311 /// @param logger The logger to print to (at VERBOSE level)
0312 void printCheckPathLength(double pathLength, double nearLimit, double farLimit,
0313                           const Logger& logger);
0314 
0315 /// This function checks if an intersection path length is valid for the
0316 /// specified near-limit and far-limit
0317 ///
0318 /// This is called per candidate on the navigation hot paths, so the two
0319 /// comparisons are inline and the (rarely enabled) verbose logging is
0320 /// delegated to an out-of-line helper.
0321 ///
0322 /// @param pathLength The path length of the intersection
0323 /// @param nearLimit The minimum path length for an intersection to be considered
0324 /// @param farLimit The maximum path length for an intersection to be considered
0325 /// @param logger A optionally supplied logger which prints out a lot of infos
0326 ///               at VERBOSE level
0327 inline bool checkPathLength(double pathLength, double nearLimit,
0328                             double farLimit,
0329                             const Logger& logger = getDummyLogger()) {
0330   if (logger.doPrint(Logging::VERBOSE)) [[unlikely]] {
0331     printCheckPathLength(pathLength, nearLimit, farLimit, logger);
0332   }
0333 
0334   // TODO why?
0335   const double tolerance = s_onSurfaceTolerance;
0336   return pathLength > nearLimit && pathLength < farLimit + tolerance;
0337 }
0338 
0339 }  // namespace detail
0340 
0341 }  // namespace Acts