Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-19 09:23:34

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2016-2020 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 http://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/TrackParametrization.hpp"
0013 #include "Acts/Surfaces/detail/VerticesHelper.hpp"
0014 
0015 #include <cfloat>
0016 #include <cmath>
0017 #include <iterator>
0018 #include <vector>
0019 
0020 namespace Acts {
0021 
0022 /// @class BoundaryCheck
0023 ///
0024 /// The BoundaryCheck class provides boundary checks and distance calculations
0025 /// for aligned box-like and polygonal boundaries on local surfaces.
0026 /// Different types of boundary checks are supported and are transparently
0027 /// selected when calling the `isInside(...)` and `distance(...)` methods:
0028 ///
0029 /// -   Hard checks w/o any tolerances
0030 /// -   Tolerance-based checks in one or in both local coordinates
0031 /// -   Chi2-based checks based on a covariance matrix. Non-vanishing
0032 ///     correlations are correctly taken into account.
0033 ///
0034 /// With a defined covariance matrix, the closest point and the distance are
0035 /// not defined along the usual Euclidean metric, but by the Mahalanobis
0036 /// distance induced by the covariance.
0037 class BoundaryCheck {
0038  public:
0039   /// Construct either hard cut in both dimensions or no cut at all.
0040   explicit BoundaryCheck(bool check);
0041 
0042   /// Construct a tolerance based check.
0043   ///
0044   /// @param checkLocal0 Boolean directive to check coordinate 0
0045   /// @param checkLocal1 Boolean directive to check coordinate 1
0046   /// @param tolerance0 Tolerance along coordinate 0
0047   /// @param tolerance1 Tolerance along coordinate 1
0048   BoundaryCheck(bool checkLocal0, bool checkLocal1, double tolerance0 = 0,
0049                 double tolerance1 = 0);
0050 
0051   /// Construct a chi2-based check.
0052   ///
0053   /// @param localCovariance Coverance matrix in local coordinates
0054   /// @param sigmaMax  Significance for the compatibility test
0055   BoundaryCheck(const SquareMatrix2& localCovariance, double sigmaMax = 1);
0056 
0057   bool isEnabled() const { return m_type != Type::eNone; }
0058 
0059   /// Check if the point is inside a polygon.
0060   ///
0061   /// @param point    Test point
0062   /// @param vertices Forward iterable container of convex polygon vertices.
0063   ///                 Calling `std::begin`/ `std::end` on the container must
0064   ///                 return an iterator where `*it` must be convertible to
0065   ///                 an `Acts::Vector2`.
0066   ///
0067   /// The check takes into account whether tolerances or covariances are defined
0068   /// for the boundary check.
0069   template <typename Vector2Container>
0070   bool isInside(const Vector2& point, const Vector2Container& vertices) const;
0071 
0072   /// Check if the point is inside a box aligned with the local axes.
0073   ///
0074   /// @param point   Test point
0075   /// @param lowerLeft Minimal vertex of the box
0076   /// @param upperRight Maximal vertex of the box
0077   ///
0078   /// The check takes into account whether tolerances or covariances are defined
0079   /// for the boundary check.
0080   bool isInside(const Vector2& point, const Vector2& lowerLeft,
0081                 const Vector2& upperRight) const;
0082 
0083   /// Calculate the signed, weighted, closest distance to a polygonal boundary.
0084   ///
0085   /// @param point Test point
0086   /// @param vertices Forward iterable container of convex polygon vertices.
0087   ///                 Calling `std::begin`/ `std::end` on the container must
0088   ///                 return an iterator where `*it` must be convertible to
0089   ///                 an `Acts::Vector2`.
0090   /// @return Negative value if inside, positive if outside
0091   ///
0092   /// If a covariance is defined, the distance is the corresponding Mahalanobis
0093   /// distance. Otherwise, it is the Eucleadian distance.
0094   template <typename Vector2Container>
0095   double distance(const Vector2& point, const Vector2Container& vertices) const;
0096 
0097   /// Calculate the signed, weighted, closest distance to an aligned box.
0098   ///
0099   /// @param point Test point
0100   /// @param lowerLeft Minimal vertex of the box
0101   /// @param upperRight Maximal vertex of the box
0102   /// @return Negative value if inside, positive if outside
0103   ///
0104   /// If a covariance is defined, the distance is the corresponding Mahalanobis
0105   /// distance. Otherwise, it is the Eucleadian distance.
0106   double distance(const Vector2& point, const Vector2& lowerLeft,
0107                   const Vector2& upperRight) const;
0108 
0109   enum class Type {
0110     eNone,      ///< disable boundary check
0111     eAbsolute,  ///< absolute cut
0112     eChi2       ///< chi2-based cut with full correlations
0113   };
0114 
0115   /// Broadcast the type
0116   Type type() const;
0117 
0118   // Broadcast the tolerance
0119   const Vector2& tolerance() const;
0120 
0121   // Return the covariance matrix
0122   SquareMatrix2 covariance() const;
0123 
0124  private:
0125   /// Return a new BoundaryCheck with updated covariance.
0126   /// @param jacobian Transform Jacobian for the covariance
0127   /// @warning This currently only transforms the covariance and does not work
0128   ///          for the tolerance based check.
0129   BoundaryCheck transformed(const ActsMatrix<2, 2>& jacobian) const;
0130 
0131   /// Check if the distance vector is within the absolute or relative limits.
0132   bool isTolerated(const Vector2& delta) const;
0133 
0134   /// Compute vector norm based on the covariance.
0135   double squaredNorm(const Vector2& x) const;
0136 
0137   /// Calculate the closest point on the polygon.
0138   template <typename Vector2Container>
0139   Vector2 computeClosestPointOnPolygon(const Vector2& point,
0140                                        const Vector2Container& vertices) const;
0141 
0142   /// metric weight matrix: identity for absolute mode or inverse covariance
0143   SquareMatrix2 m_weight;
0144 
0145   /// dual use: absolute tolerances or relative chi2/ sigma cut.
0146   Vector2 m_tolerance;
0147   Type m_type;
0148 
0149   // To access the m_type
0150   friend class CylinderBounds;
0151   friend class RectangleBounds;
0152   // To be able to use `transformed`
0153   friend class CylinderBounds;
0154   friend class DiscTrapezoidBounds;
0155   // EllipseBounds needs a custom implementation
0156   friend class EllipseBounds;
0157 };
0158 
0159 }  // namespace Acts
0160 
0161 inline Acts::BoundaryCheck::Type Acts::BoundaryCheck::type() const {
0162   return m_type;
0163 }
0164 
0165 inline const Acts::Vector2& Acts::BoundaryCheck::tolerance() const {
0166   return m_tolerance;
0167 }
0168 
0169 inline Acts::SquareMatrix2 Acts::BoundaryCheck::covariance() const {
0170   return m_weight.inverse();
0171 }
0172 
0173 inline Acts::BoundaryCheck::BoundaryCheck(bool check)
0174     : m_weight(SquareMatrix2::Identity()),
0175       m_tolerance(0, 0),
0176       m_type(check ? Type::eAbsolute : Type::eNone) {}
0177 
0178 inline Acts::BoundaryCheck::BoundaryCheck(bool checkLocal0, bool checkLocal1,
0179                                           double tolerance0, double tolerance1)
0180     : m_weight(SquareMatrix2::Identity()),
0181       m_tolerance(checkLocal0 ? tolerance0 : DBL_MAX,
0182                   checkLocal1 ? tolerance1 : DBL_MAX),
0183       m_type(Type::eAbsolute) {}
0184 
0185 inline Acts::BoundaryCheck::BoundaryCheck(const SquareMatrix2& localCovariance,
0186                                           double sigmaMax)
0187     : m_weight(localCovariance.inverse()),
0188       m_tolerance(sigmaMax, 0),
0189       m_type(Type::eChi2) {}
0190 
0191 inline Acts::BoundaryCheck Acts::BoundaryCheck::transformed(
0192     const ActsMatrix<2, 2>& jacobian) const {
0193   BoundaryCheck bc = *this;
0194   if (m_type == Type::eAbsolute) {
0195     // project tolerances to the new system. depending on the jacobian we need
0196     // to check both tolerances, even when the initial check does not.
0197     bc.m_tolerance = (jacobian * m_tolerance).cwiseAbs();
0198   } else /* Type::eChi2 */ {
0199     bc.m_weight =
0200         (jacobian * m_weight.inverse() * jacobian.transpose()).inverse();
0201   }
0202   return bc;
0203 }
0204 
0205 template <typename Vector2Container>
0206 inline bool Acts::BoundaryCheck::isInside(
0207     const Vector2& point, const Vector2Container& vertices) const {
0208   if (m_type == Type::eNone) {
0209     // The null boundary check always succeeds
0210     return true;
0211   } else if (detail::VerticesHelper::isInsidePolygon(point, vertices)) {
0212     // If the point falls inside the polygon, the check always succeeds
0213     return true;
0214   } else if (m_tolerance == Vector2(0., 0.)) {
0215     // Outside of the polygon, since we've eliminated the case of an absence of
0216     // check above, we know we'll always fail if the tolerance is zero.
0217     //
0218     // This allows us to avoid the expensive computeClosestPointOnPolygon
0219     // computation in this simple case.
0220     //
0221     // TODO: When tolerance is not 0, we could also avoid this computation in
0222     //       some cases by testing against a bounding box of the polygon, padded
0223     //       on each side with our tolerance. Check if this optimization is
0224     //       worthwhile in some production workflows, and if so implement it.
0225     return false;
0226   } else {
0227     // We are outside of the polygon, but there is a tolerance. Must find what
0228     // the closest point on the polygon is and check if it's within tolerance.
0229     auto closestPoint = computeClosestPointOnPolygon(point, vertices);
0230     return isTolerated(closestPoint - point);
0231   }
0232 }
0233 
0234 inline bool Acts::BoundaryCheck::isInside(const Vector2& point,
0235                                           const Vector2& lowerLeft,
0236                                           const Vector2& upperRight) const {
0237   if (detail::VerticesHelper::isInsideRectangle(point, lowerLeft, upperRight)) {
0238     return true;
0239   } else {
0240     Vector2 closestPoint;
0241 
0242     if (m_type == Type::eNone || m_type == Type::eAbsolute) {
0243       // absolute, can calculate directly
0244       closestPoint =
0245           detail::VerticesHelper::computeEuclideanClosestPointOnRectangle(
0246               point, lowerLeft, upperRight);
0247 
0248     } else /* Type::eChi2 */ {
0249       // need to calculate by projection and squarednorm
0250       Vector2 vertices[] = {{lowerLeft[0], lowerLeft[1]},
0251                             {upperRight[0], lowerLeft[1]},
0252                             {upperRight[0], upperRight[1]},
0253                             {lowerLeft[0], upperRight[1]}};
0254       closestPoint = computeClosestPointOnPolygon(point, vertices);
0255     }
0256 
0257     return isTolerated(closestPoint - point);
0258   }
0259 }
0260 
0261 template <typename Vector2Container>
0262 inline double Acts::BoundaryCheck::distance(
0263     const Acts::Vector2& point, const Vector2Container& vertices) const {
0264   // TODO 2017-04-06 msmk: this should be calculable directly
0265   double d = squaredNorm(point - computeClosestPointOnPolygon(point, vertices));
0266   d = std::sqrt(d);
0267   return detail::VerticesHelper::isInsidePolygon(point, vertices) ? -d : d;
0268 }
0269 
0270 inline double Acts::BoundaryCheck::distance(const Acts::Vector2& point,
0271                                             const Vector2& lowerLeft,
0272                                             const Vector2& upperRight) const {
0273   if (m_type == Type::eNone || m_type == Type::eAbsolute) {
0274     // compute closest point on box
0275     double d = (point -
0276                 detail::VerticesHelper::computeEuclideanClosestPointOnRectangle(
0277                     point, lowerLeft, upperRight))
0278                    .norm();
0279     return detail::VerticesHelper::isInsideRectangle(point, lowerLeft,
0280                                                      upperRight)
0281                ? -d
0282                : d;
0283 
0284   } else /* Type::eChi2 */ {
0285     Vector2 vertices[] = {{lowerLeft[0], lowerLeft[1]},
0286                           {upperRight[0], lowerLeft[1]},
0287                           {upperRight[0], upperRight[1]},
0288                           {lowerLeft[0], upperRight[1]}};
0289     return distance(point, vertices);
0290   }
0291 }
0292 
0293 inline bool Acts::BoundaryCheck::isTolerated(const Vector2& delta) const {
0294   if (m_type == Type::eNone) {
0295     return true;
0296   } else if (m_type == Type::eAbsolute) {
0297     return (std::abs(delta[0]) <= m_tolerance[0]) &&
0298            (std::abs(delta[1]) <= m_tolerance[1]);
0299   } else /* Type::eChi2 */ {
0300     // Mahalanobis distances mean is 2 in 2-dim. cut is 1-d sigma.
0301     return (squaredNorm(delta) < (2 * m_tolerance[0]));
0302   }
0303 }
0304 
0305 inline double Acts::BoundaryCheck::squaredNorm(const Vector2& x) const {
0306   return (x.transpose() * m_weight * x).value();
0307 }
0308 
0309 template <typename Vector2Container>
0310 inline Acts::Vector2 Acts::BoundaryCheck::computeClosestPointOnPolygon(
0311     const Acts::Vector2& point, const Vector2Container& vertices) const {
0312   return detail::VerticesHelper::computeClosestPointOnPolygon(point, vertices,
0313                                                               m_weight);
0314 }