Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-11-06 09:17:10

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/Surfaces/DiscBounds.hpp"
0014 #include "Acts/Surfaces/SurfaceBounds.hpp"
0015 
0016 #include <array>
0017 #include <cmath>
0018 #include <iosfwd>
0019 #include <numbers>
0020 #include <vector>
0021 
0022 namespace Acts {
0023 
0024 /// @brief Class that implements a (potentially asymmetric) bounds with
0025 /// difference between surface bound center and surface coordinate center
0026 ///
0027 /// These bounds combine two different systems:
0028 ///  * module system : radial bounds centred on the moduleOrigin
0029 ///  * strip system : phi bounds centred on the stripOrigin
0030 ///
0031 /// The measurement will be done in the strip system, with r/phi local
0032 /// coordinates.
0033 ///
0034 class AnnulusBounds : public DiscBounds {
0035  public:
0036   /// Enumeration for the different bound values
0037   enum BoundValues : int {
0038     eMinR = 0,
0039     eMaxR = 1,
0040     eMinPhiRel = 2,
0041     eMaxPhiRel = 3,
0042     eAveragePhi = 4,
0043     eOriginX = 5,
0044     eOriginY = 6,
0045     eSize = 7
0046   };
0047 
0048   /// @brief Default constructor from parameters
0049   /// @param minR The inner radius of the annulus
0050   /// @param maxR The outer radius of the annulus
0051   /// @param minPhiRel The minimum phi relative to average phi
0052   /// @param maxPhiRel The maximum phi relative to average phi
0053   /// @param moduleOrigin The origin of the module in the strip frame
0054   /// @param avgPhi The average phi value
0055   /// @note For @c morigin you need to actually calculate the cartesian
0056   /// offset
0057   explicit AnnulusBounds(double minR, double maxR, double minPhiRel,
0058                          double maxPhiRel, const Vector2& moduleOrigin = {0, 0},
0059                          double avgPhi = 0) noexcept(false)
0060       : AnnulusBounds({minR, maxR, minPhiRel, maxPhiRel, avgPhi,
0061                        moduleOrigin.x(), moduleOrigin.y()}) {}
0062 
0063   /// Constructor - from fixed size array
0064   ///
0065   /// @param values The bound values stored in a fixed size array
0066   explicit AnnulusBounds(const std::array<double, eSize>& values) noexcept(
0067       false);
0068 
0069   BoundsType type() const final { return eAnnulus; }
0070 
0071   /// @copydoc SurfaceBounds::isCartesian
0072   bool isCartesian() const final { return false; }
0073 
0074   /// @copydoc SurfaceBounds::boundToCartesianJacobian
0075   SquareMatrix2 boundToCartesianJacobian(const Vector2& lposition) const final;
0076 
0077   /// @copydoc SurfaceBounds::boundToCartesianMetric
0078   SquareMatrix2 boundToCartesianMetric(const Vector2& lposition) const final;
0079 
0080   /// Return the bound values as dynamically sized vector
0081   /// @return this returns a copy of the internal values
0082   std::vector<double> values() const final;
0083 
0084   /// @copydoc SurfaceBounds::inside
0085   bool inside(const Vector2& lposition) const final;
0086 
0087   /// @copydoc SurfaceBounds::closestPoint
0088   Vector2 closestPoint(const Vector2& lposition,
0089                        const SquareMatrix2& metric) const final;
0090 
0091   using SurfaceBounds::inside;
0092 
0093   /// @copydoc SurfaceBounds::center
0094   /// @note For AnnulusBounds: returns pre-calculated center from corner vertices in strip polar coordinates (r, phi), accounting for average phi rotation
0095   Vector2 center() const final;
0096 
0097   /// Outstream operator
0098   /// @param sl is the ostream to be dumped into
0099   /// @return Reference to the output stream
0100   std::ostream& toStream(std::ostream& sl) const final;
0101 
0102   /// Access to the bound values
0103   /// @param bValue the class nested enum for the array access
0104   /// @return The value of the specified bound parameter
0105   double get(BoundValues bValue) const { return m_values[bValue]; }
0106 
0107   /// @brief Returns the right angular edge of the module
0108   /// @return The right side angle
0109   double phiMin() const { return get(eMinPhiRel) + get(eAveragePhi); }
0110 
0111   /// @brief Returns the left angular edge of the module
0112   /// @return The left side angle
0113   double phiMax() const { return get(eMaxPhiRel) + get(eAveragePhi); }
0114 
0115   /// Returns true for full phi coverage
0116   /// @return True if the annulus covers the full azimuthal range, false otherwise
0117   bool coversFullAzimuth() const final {
0118     return (std::abs((get(eMinPhiRel) - get(eMaxPhiRel)) - std::numbers::pi) <
0119             s_onSurfaceTolerance);
0120   }
0121 
0122   /// Checks if this is inside the radial coverage
0123   /// given the a tolerance
0124   /// @param R The radius value to check
0125   /// @param tolerance The tolerance for the check
0126   /// @return True if the radius is within bounds (plus tolerance), false otherwise
0127   bool insideRadialBounds(double R, double tolerance = 0.) const final {
0128     return ((R + tolerance) > get(eMinR) && (R - tolerance) < get(eMaxR));
0129   }
0130 
0131   /// Return a reference radius for binning
0132   /// @return Average radius for binning purposes
0133   double binningValueR() const final { return 0.5 * (get(eMinR) + get(eMaxR)); }
0134 
0135   /// Return a reference phi for binning
0136   /// @return Average phi angle for binning purposes
0137   double binningValuePhi() const final { return get(eAveragePhi); }
0138 
0139   /// @brief Returns moduleOrigin, but rotated out, so @c averagePhi is already
0140   /// considered. The module origin needs to consider the rotation introduced by
0141   /// @c averagePhi
0142   /// @return The origin of the local frame
0143   Vector2 moduleOrigin() const;
0144 
0145   /// This method returns the four corners of the bounds in polar coordinates
0146   /// Starting from the upper right (max R, pos locX) and proceeding clock-wise
0147   /// i.e. (max R; pos locX), (min R; pos locX), (min R; neg loc X), (max R: neg
0148   /// locX)
0149   /// @return Vector of corner points in polar coordinates
0150   std::vector<Vector2> corners() const;
0151 
0152   /// This method returns the xy coordinates of the four corners of the
0153   /// bounds in module coordinates (in x/y), and if quarterSegments is bigger or
0154   /// equal to 0, the curved part of the segment is included and approximated
0155   /// by the corresponding number of segments.
0156   ///
0157   /// Starting from the upper right (max R, pos locX) and proceeding clock-wise
0158   /// i.e. (max R; pos locX), (min R; pos locX), (min R; neg loc X), (max R: neg
0159   /// locX)
0160   ///
0161   /// @param quarterSegments the number of segments used to approximate
0162   /// a quarter of a circle
0163   ///
0164   /// @return vector for vertices in 2D
0165   std::vector<Vector2> vertices(
0166       unsigned int quarterSegments = 2u) const override;
0167 
0168   /// This method returns inner radius
0169   /// @return Minimum radius of the annulus
0170   double rMin() const final { return get(eMinR); }
0171 
0172   /// This method returns outer radius
0173   /// @return Maximum radius of the annulus
0174   double rMax() const final { return get(eMaxR); }
0175 
0176  private:
0177   std::array<double, eSize> m_values;
0178 
0179   // @TODO: Does this need to be in bound values?
0180   Vector2 m_moduleOrigin{
0181       Vector2::Zero()};  ///< The origin of the module in the strip frame
0182   Vector2 m_shiftXY{Vector2::Zero()};  // == -m_moduleOrigin
0183   Vector2 m_shiftPC{Vector2::Zero()};
0184   Transform2 m_rotationStripPC{Transform2::Identity()};  ///< Rotation to strip
0185   Transform2 m_translation{Transform2::Identity()};  ///< Translation to strip
0186 
0187   // Vectors needed for inside checking
0188   Vector2 m_outLeftStripPC{Vector2::Zero()};
0189   Vector2 m_inLeftStripPC{Vector2::Zero()};
0190   Vector2 m_outRightStripPC{Vector2::Zero()};
0191   Vector2 m_inRightStripPC{Vector2::Zero()};
0192 
0193   Vector2 m_outLeftModulePC{Vector2::Zero()};
0194   Vector2 m_inLeftModulePC{Vector2::Zero()};
0195   Vector2 m_outRightModulePC{Vector2::Zero()};
0196   Vector2 m_inRightModulePC{Vector2::Zero()};
0197 
0198   Vector2 m_outLeftStripXY{Vector2::Zero()};
0199   Vector2 m_inLeftStripXY{Vector2::Zero()};
0200   Vector2 m_outRightStripXY{Vector2::Zero()};
0201   Vector2 m_inRightStripXY{Vector2::Zero()};
0202 
0203   /// Pre-calculated center point (average of vertices)
0204   Vector2 m_center{Vector2::Zero()};
0205 
0206   /// Check the input values for consistency, will throw a logic_exception
0207   /// if consistency is not given
0208   void checkConsistency() noexcept(false);
0209 
0210   /// Transform the strip cartesian into the module polar system
0211   ///
0212   /// @param vStripXY the position in the cartesian strip system
0213   /// @return the position in the module polar coordinate system
0214   Vector2 stripXYToModulePC(const Vector2& vStripXY) const;
0215 
0216   Vector2 stripPCToModulePC(const Vector2& vStripPC) const;
0217 
0218   Vector2 modulePCToStripPC(const Vector2& vModulePC) const;
0219 
0220   SquareMatrix2 stripPCToModulePCJacobian(
0221       const Vector2& lpositionRotated) const;
0222 };
0223 
0224 }  // namespace Acts