Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-08 08:09:55

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 
0013 #include <optional>
0014 #include <type_traits>
0015 #include <variant>
0016 
0017 namespace Acts {
0018 
0019 /// @brief Variant-like type to capture different types of boundary tolerances
0020 ///
0021 /// Since our track hypothesis comes with uncertainties, we sometimes need to
0022 /// check if the track is not just within the boundary of the surface but also
0023 /// within a certain tolerance. This class captures different parameterizations
0024 /// of such tolerances. The surface class will then use these tolerances to
0025 /// check if a ray is within the boundary+tolerance of the surface.
0026 ///
0027 /// Different types of boundary tolerances implemented:
0028 /// - Infinite: Infinite tolerance i.e. no boundary check will be performed.
0029 /// - None: No tolerance i.e. exact boundary check will be performed.
0030 /// - AbsoluteBound: Absolute tolerance in bound coordinates.
0031 ///   The tolerance is defined as a pair of absolute values for the bound
0032 ///   coordinates. Only if both coordinates are within the tolerance, the
0033 ///   boundary check is considered as passed.
0034 /// - AbsoluteCartesian: Absolute tolerance in Cartesian coordinates.
0035 ///   The tolerance is defined as a pair of absolute values for the Cartesian
0036 ///   coordinates. The transformation to Cartesian coordinates can be done via
0037 ///   the Jacobian for small distances. Only if both coordinates are within
0038 ///   the tolerance, the boundary check is considered as passed.
0039 /// - AbsoluteEuclidean: Absolute tolerance in Euclidean distance.
0040 ///   The tolerance is defined as a single absolute value for the Euclidean
0041 ///   distance. The Euclidean distance can be calculated via the local bound
0042 ///   Jacobian and the bound coordinate residual. If the distance is within
0043 ///   the tolerance, the boundary check is considered as passed.
0044 /// - Chi2Bound: Chi2 tolerance in bound coordinates.
0045 ///   The tolerance is defined as a maximum chi2 value and a weight matrix,
0046 ///   which is the inverse of the bound covariance matrix. The chi2 value is
0047 ///   calculated from the bound coordinates residual and the weight matrix.
0048 ///   If the chi2 value is below the maximum chi2 value, the boundary check
0049 ///   is considered as passed.
0050 ///
0051 /// The bound coordinates residual is defined as the difference between the
0052 /// point checked and the closest point on the boundary. The Jacobian is the
0053 /// derivative of the bound coordinates with respect to the Cartesian
0054 /// coordinates.
0055 ///
0056 class BoundaryTolerance {
0057  public:
0058   struct InfiniteParams {};
0059 
0060   struct NoneParams {};
0061 
0062   struct AbsoluteBoundParams {
0063     double tolerance0{};
0064     double tolerance1{};
0065   };
0066 
0067   struct AbsoluteCartesianParams {
0068     double tolerance0{};
0069     double tolerance1{};
0070   };
0071 
0072   struct AbsoluteEuclideanParams {
0073     double tolerance{};
0074   };
0075 
0076   struct Chi2BoundParams {
0077     double maxChi2{};
0078     std::array<double, 4> weight;
0079 
0080     Eigen::Map<SquareMatrix2> weightMatrix() {
0081       return Eigen::Map<SquareMatrix2>(weight.data());
0082     }
0083 
0084     Eigen::Map<const SquareMatrix2> weightMatrix() const {
0085       return Eigen::Map<const SquareMatrix2>(weight.data());
0086     }
0087   };
0088 
0089   static_assert(std::is_trivially_copyable_v<Chi2BoundParams>);
0090 
0091  private:
0092   /// Underlying variant type
0093   using Variant = std::variant<InfiniteParams, NoneParams, AbsoluteBoundParams,
0094                                AbsoluteCartesianParams, AbsoluteEuclideanParams,
0095                                Chi2BoundParams>;
0096   static_assert(std::is_trivially_copyable_v<Variant>);
0097 
0098   /// Construct from variant
0099   constexpr explicit BoundaryTolerance(Variant variant) : m_variant{variant} {}
0100 
0101  public:
0102   /// Infinite tolerance i.e. no boundary check
0103   constexpr static auto Infinite() noexcept {
0104     return BoundaryTolerance{InfiniteParams{}};
0105   }
0106 
0107   /// No tolerance i.e. exact boundary check
0108   constexpr static auto None() noexcept {
0109     return BoundaryTolerance{NoneParams{}};
0110   }
0111 
0112   /// Absolute tolerance in bound coordinates
0113   constexpr static auto AbsoluteBound(double tolerance0, double tolerance1) {
0114     if (tolerance0 < 0 || tolerance1 < 0) {
0115       throw std::invalid_argument(
0116           "AbsoluteBound: Tolerance must be non-negative");
0117     }
0118     return BoundaryTolerance{AbsoluteBoundParams{tolerance0, tolerance1}};
0119   }
0120 
0121   /// Absolute tolerance in Cartesian coordinates
0122   constexpr static auto AbsoluteCartesian(double tolerance0,
0123                                           double tolerance1) {
0124     if (tolerance0 < 0 || tolerance1 < 0) {
0125       throw std::invalid_argument(
0126           "AbsoluteCartesian: Tolerance must be non-negative");
0127     }
0128     if ((tolerance0 == 0) != (tolerance1 == 0)) {
0129       throw std::invalid_argument(
0130           "AbsoluteCartesian: Both tolerances must be zero or non-zero");
0131     }
0132     return BoundaryTolerance{AbsoluteCartesianParams{tolerance0, tolerance1}};
0133   }
0134 
0135   /// Absolute tolerance in Euclidean distance
0136   constexpr static auto AbsoluteEuclidean(double tolerance) noexcept {
0137     return BoundaryTolerance{AbsoluteEuclideanParams{tolerance}};
0138   }
0139 
0140   /// Chi2 tolerance in bound coordinates
0141   static auto Chi2Bound(const SquareMatrix2& weight, double maxChi2) noexcept {
0142     Chi2BoundParams tolerance{maxChi2, {}};
0143     tolerance.weightMatrix() = weight;
0144     return BoundaryTolerance{tolerance};
0145   }
0146 
0147   BoundaryTolerance(const BoundaryTolerance& other) noexcept = default;
0148   BoundaryTolerance& operator=(const BoundaryTolerance& other) noexcept =
0149       default;
0150   BoundaryTolerance(BoundaryTolerance&& other) noexcept = default;
0151   BoundaryTolerance& operator=(BoundaryTolerance&& other) noexcept = default;
0152 
0153   enum class ToleranceMode {
0154     Extend,  // Extend the boundary
0155     None,    // No tolerance
0156     Shrink   // Shrink the boundary
0157   };
0158 
0159   /// Check if the tolerance is infinite.
0160   constexpr bool isInfinite() const { return holdsVariant<InfiniteParams>(); }
0161   /// Check if the is no tolerance.
0162   constexpr bool isNone() const { return holdsVariant<NoneParams>(); }
0163   /// Check if the tolerance is absolute with bound coordinates.
0164   constexpr bool hasAbsoluteBound(bool isCartesian = false) const {
0165     return holdsVariant<NoneParams>() || holdsVariant<AbsoluteBoundParams>() ||
0166            (isCartesian && holdsVariant<AbsoluteCartesianParams>());
0167   }
0168   /// Check if the tolerance is absolute with Cartesian coordinates.
0169   constexpr bool hasAbsoluteCartesian() const {
0170     return holdsVariant<AbsoluteCartesianParams>();
0171   }
0172   /// Check if the tolerance is absolute with Euclidean distance.
0173   constexpr bool hasAbsoluteEuclidean() const {
0174     return holdsVariant<AbsoluteEuclideanParams>();
0175   }
0176   /// Check if the tolerance is chi2 with bound coordinates.
0177   constexpr bool hasChi2Bound() const {
0178     return holdsVariant<Chi2BoundParams>();
0179   }
0180 
0181   /// Check if any tolerance is set.
0182   ToleranceMode toleranceMode() const;
0183 
0184   /// Get the tolerance as absolute bound.
0185   AbsoluteBoundParams asAbsoluteBound(bool isCartesian = false) const;
0186   /// Get the tolerance as absolute Cartesian.
0187   constexpr const AbsoluteCartesianParams& asAbsoluteCartesian() const {
0188     return getVariant<AbsoluteCartesianParams>();
0189   }
0190   /// Get the tolerance as absolute Euclidean.
0191   constexpr const AbsoluteEuclideanParams& asAbsoluteEuclidean() const {
0192     return getVariant<AbsoluteEuclideanParams>();
0193   }
0194   /// Get the tolerance as chi2 bound.
0195   constexpr const Chi2BoundParams& asChi2Bound() const {
0196     return getVariant<Chi2BoundParams>();
0197   }
0198 
0199   /// Get the tolerance as absolute bound if possible.
0200   constexpr std::optional<AbsoluteBoundParams> asAbsoluteBoundOpt(
0201       bool isCartesian = false) const {
0202     return hasAbsoluteBound(isCartesian)
0203                ? std::optional(asAbsoluteBound(isCartesian))
0204                : std::nullopt;
0205   }
0206 
0207   /// Check if the distance is tolerated.
0208   bool isTolerated(const Vector2& distance,
0209                    const std::optional<SquareMatrix2>& jacobianOpt) const;
0210 
0211   /// Check if there is a metric assigned with this tolerance.
0212   constexpr bool hasMetric(bool hasJacobian) const {
0213     return hasJacobian || hasChi2Bound();
0214   }
0215 
0216   /// Get the metric for the tolerance.
0217   SquareMatrix2 getMetric(const std::optional<SquareMatrix2>& jacobian) const;
0218 
0219  private:
0220   Variant m_variant;
0221 
0222   /// Check if the boundary check is of a specific type.
0223   template <typename T>
0224   constexpr bool holdsVariant() const {
0225     return std::holds_alternative<T>(m_variant);
0226   }
0227 
0228   /// Get the specific underlying type.
0229   template <typename T>
0230   constexpr const T& getVariant() const {
0231     return std::get<T>(m_variant);
0232   }
0233 
0234   template <typename T>
0235   constexpr const T* getVariantPtr() const {
0236     return holdsVariant<T>() ? &getVariant<T>() : nullptr;
0237   }
0238 };
0239 
0240 static_assert(std::is_trivially_copyable_v<BoundaryTolerance>);
0241 static_assert(std::is_trivially_move_constructible_v<BoundaryTolerance>);
0242 
0243 }  // namespace Acts