File indexing completed on 2026-09-05 08:17:47
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/Common.hpp"
0013 #include "Acts/Definitions/TrackParametrization.hpp"
0014 #include "Acts/Utilities/AngleHelpers.hpp"
0015 #include "Acts/Utilities/AxisDefinitions.hpp"
0016 #include "Acts/Utilities/MathHelpers.hpp"
0017 #include "Acts/Utilities/detail/periodic.hpp"
0018
0019 #include <array>
0020 #include <cassert>
0021 #include <limits>
0022 #include <numbers>
0023
0024 #include "Eigen/Dense"
0025 namespace Acts::VectorHelpers {
0026
0027
0028
0029
0030
0031
0032 template <typename Derived>
0033 double phi(const Eigen::MatrixBase<Derived>& v) noexcept
0034 requires(Eigen::MatrixBase<Derived>::RowsAtCompileTime >= 2)
0035 {
0036 return std::atan2(v[1], v[0]);
0037 }
0038
0039
0040
0041
0042
0043
0044
0045 template <typename Derived>
0046 double phi(const Eigen::MatrixBase<Derived>& v) noexcept
0047 requires(Eigen::MatrixBase<Derived>::RowsAtCompileTime == -1)
0048 {
0049 assert(v.rows() >= 2 && "Phi function not valid for vectors not at least 2D");
0050 return std::atan2(v[1], v[0]);
0051 }
0052
0053
0054
0055
0056
0057
0058 template <typename T>
0059 double phi(const T& v) noexcept
0060 requires requires {
0061 { v.phi() } -> std::floating_point;
0062 }
0063 {
0064 return v.phi();
0065 }
0066
0067
0068
0069
0070
0071
0072
0073 template <typename Derived>
0074 double perp(const Eigen::MatrixBase<Derived>& v) noexcept {
0075 constexpr int rows = Eigen::MatrixBase<Derived>::RowsAtCompileTime;
0076 if constexpr (rows != -1) {
0077
0078 static_assert(rows >= 2,
0079 "Perp function not valid for vectors not at least 2D");
0080 } else {
0081
0082 assert(v.rows() >= 2 &&
0083 "Perp function not valid for vectors not at least 2D");
0084 }
0085 return v.template head<2>().norm();
0086 }
0087
0088
0089
0090
0091
0092
0093 template <typename Derived>
0094 double theta(const Eigen::MatrixBase<Derived>& v) noexcept
0095 requires(Eigen::MatrixBase<Derived>::RowsAtCompileTime == 3)
0096 {
0097 return std::atan2(perp(v), v[2]);
0098 }
0099
0100
0101
0102
0103
0104
0105
0106 template <typename Derived>
0107 double theta(const Eigen::MatrixBase<Derived>& v) noexcept
0108 requires(Eigen::MatrixBase<Derived>::RowsAtCompileTime == -1)
0109 {
0110 assert(v.rows() == 3 && "Theta function not valid for non-3D vectors.");
0111 return std::atan2(perp(v), v[2]);
0112 }
0113
0114
0115
0116
0117
0118 template <typename Derived>
0119 double eta(const Eigen::MatrixBase<Derived>& v) noexcept
0120 requires(Eigen::MatrixBase<Derived>::RowsAtCompileTime == 3)
0121 {
0122 if (v[0] == 0. && v[1] == 0.) {
0123 return std::copysign(std::numeric_limits<double>::infinity(), v[2]);
0124 } else {
0125 return std::asinh(v[2] / perp(v));
0126 }
0127 }
0128
0129
0130
0131
0132
0133
0134 template <typename Derived>
0135 double eta(const Eigen::MatrixBase<Derived>& v) noexcept
0136 requires(Eigen::MatrixBase<Derived>::RowsAtCompileTime == -1)
0137 {
0138 assert(v.rows() == 3 && "Eta function not valid for non-3D vectors.");
0139 if (v[0] == 0. && v[1] == 0.) {
0140 return std::copysign(std::numeric_limits<double>::infinity(), v[2]);
0141 } else {
0142 return std::asinh(v[2] / perp(v));
0143 }
0144 }
0145
0146
0147
0148
0149
0150
0151 template <typename T>
0152 double eta(const T& v) noexcept
0153 requires requires {
0154 { v.theta() } -> std::floating_point;
0155 }
0156 {
0157 return Acts::AngleHelpers::etaFromTheta(v.theta());
0158 }
0159
0160
0161
0162
0163
0164
0165 inline std::array<double, 4> evaluateTrigonomics(const Vector3& direction) {
0166 const double x = direction(0);
0167 const double y = direction(1);
0168 const double z = direction(2);
0169
0170 const double cosTheta = z;
0171 const double sinTheta = fastCathetus(1, z);
0172 assert(sinTheta != 0 &&
0173 "VectorHelpers: Vector is parallel to the z-axis "
0174 "which leads to division by zero");
0175 const double invSinTheta = 1. / sinTheta;
0176 const double cosPhi = x * invSinTheta;
0177 const double sinPhi = y * invSinTheta;
0178
0179 return {cosPhi, sinPhi, cosTheta, sinTheta};
0180 }
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191 inline double cast(const Vector3& position, AxisDirection aDir) {
0192 using enum AxisDirection;
0193 switch (aDir) {
0194 case AxisX:
0195 return position[0];
0196 case AxisY:
0197 return position[1];
0198 case AxisZ:
0199 return position[2];
0200 case AxisR:
0201 return perp(position);
0202 case AxisPhi:
0203 return phi(position);
0204 case AxisRPhi:
0205 return perp(position) * phi(position);
0206 case AxisTheta:
0207 return theta(position);
0208 case AxisEta:
0209 return eta(position);
0210 case AxisMag:
0211 return position.norm();
0212 default:
0213 assert(false && "Invalid AxisDirection enum value");
0214 return std::numeric_limits<double>::quiet_NaN();
0215 }
0216 }
0217
0218
0219
0220
0221
0222
0223
0224 inline SquareMatrix3 cross(const SquareMatrix3& m, const Vector3& v) {
0225 SquareMatrix3 r;
0226 r.col(0) = m.col(0).cross(v);
0227 r.col(1) = m.col(1).cross(v);
0228 r.col(2) = m.col(2).cross(v);
0229
0230 return r;
0231 }
0232
0233
0234 inline auto position(const Vector4& pos4) {
0235 return pos4.segment<3>(ePos0);
0236 }
0237
0238
0239 inline auto position(const FreeVector& params) {
0240 return params.segment<3>(eFreePos0);
0241 }
0242
0243
0244 template <typename vector3_t>
0245 inline auto makeVector4(const Eigen::MatrixBase<vector3_t>& vec3,
0246 typename vector3_t::Scalar w)
0247 -> Eigen::Matrix<typename vector3_t::Scalar, 4, 1> {
0248 EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(vector3_t, 3);
0249
0250 Eigen::Matrix<typename vector3_t::Scalar, 4, 1> vec4;
0251 vec4[ePos0] = vec3[ePos0];
0252 vec4[ePos1] = vec3[ePos1];
0253 vec4[ePos2] = vec3[ePos2];
0254 vec4[eTime] = w;
0255 return vec4;
0256 }
0257
0258
0259
0260
0261
0262
0263 inline std::pair<double, double> incidentAngles(
0264 const Acts::Vector3& direction,
0265 const Acts::RotationMatrix3& globalToLocal) {
0266 Acts::Vector3 trfDir = globalToLocal * direction;
0267
0268
0269 double phi = std::atan2(trfDir[2], trfDir[0]);
0270 double theta = std::atan2(trfDir[2], trfDir[1]);
0271 return {phi, theta};
0272 }
0273
0274
0275
0276
0277
0278
0279
0280 template <typename Derived>
0281 double deltaR(const Eigen::MatrixBase<Derived>& v1,
0282 const Eigen::MatrixBase<Derived>& v2)
0283 requires(Eigen::MatrixBase<Derived>::RowsAtCompileTime == 3)
0284 {
0285 const double dphi =
0286 detail::difference_periodic(phi(v1), phi(v2), 2 * std::numbers::pi);
0287 const double deta = eta(v1) - eta(v2);
0288 return fastHypot(dphi, deta);
0289 }
0290
0291 }