Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-08 07:50:40

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/Tolerance.hpp"
0012 #include "Acts/EventData/ParticleHypothesis.hpp"
0013 #include "Acts/EventData/TrackParameterHelpers.hpp"
0014 #include "Acts/EventData/TransformationHelpers.hpp"
0015 #include "Acts/EventData/detail/PrintParameters.hpp"
0016 #include "Acts/Surfaces/CurvilinearSurface.hpp"
0017 #include "Acts/Surfaces/Surface.hpp"
0018 #include "Acts/Utilities/UnitVectors.hpp"
0019 #include "Acts/Utilities/detail/periodic.hpp"
0020 
0021 #include <cassert>
0022 #include <cmath>
0023 #include <memory>
0024 
0025 namespace Acts {
0026 
0027 /// Track parameters bound to a reference surface for a single track.
0028 ///
0029 /// @tparam particle_hypothesis_t Helper type to interpret the particle charge/momentum
0030 ///
0031 /// This is intended as a user-facing data class that adds additional accessors
0032 /// and charge/momentum interpretation on top of the pure parameters vector. All
0033 /// parameters and their corresponding covariance matrix are stored in bound
0034 /// parametrization. The specific definition of the local spatial parameters is
0035 /// defined by the associated surface.
0036 ///
0037 /// @note This class holds shared ownership on its reference surface.
0038 template <class particle_hypothesis_t>
0039 class GenericBoundTrackParameters {
0040  public:
0041   /// Type alias for bound track parameters vector
0042   using ParametersVector = BoundVector;
0043   /// Type alias for bound track covariance matrix
0044   using CovarianceMatrix = BoundMatrix;
0045   /// Type alias for particle hypothesis used in reconstruction
0046   using ParticleHypothesis = particle_hypothesis_t;
0047 
0048   /// Factory to construct from four-position, direction, absolute momentum, and
0049   /// charge.
0050   ///
0051   /// @param geoCtx Geometry context for the local-to-global transformation
0052   /// @param surface Reference surface the parameters are defined on
0053   /// @param pos4 Track position/time four-vector
0054   /// @param dir Track direction three-vector; normalization is ignored
0055   /// @param qOverP Charge over momentum
0056   /// @param cov Bound parameters covariance matrix
0057   /// @param particleHypothesis Particle hypothesis
0058   /// @param tolerance Tolerance used for globalToLocal
0059   ///
0060   /// @return Result containing the constructed bound track parameters or error
0061   /// @note The returned result indicates whether the free parameters could
0062   /// successfully be converted to on-surface parameters.
0063   static Result<GenericBoundTrackParameters> create(
0064       const GeometryContext& geoCtx, std::shared_ptr<const Surface> surface,
0065       const Vector4& pos4, const Vector3& dir, double qOverP,
0066       std::optional<CovarianceMatrix> cov,
0067       ParticleHypothesis particleHypothesis,
0068       double tolerance = s_onSurfaceTolerance) {
0069     Result<BoundVector> bound =
0070         transformFreeToBoundParameters(pos4.segment<3>(ePos0), pos4[eTime], dir,
0071                                        qOverP, *surface, geoCtx, tolerance);
0072 
0073     if (!bound.ok()) {
0074       return bound.error();
0075     }
0076 
0077     return GenericBoundTrackParameters{std::move(surface), std::move(*bound),
0078                                        std::move(cov),
0079                                        std::move(particleHypothesis)};
0080   }
0081 
0082   /// Construct from four-position, direction, and qOverP.
0083   ///
0084   /// @param pos4 Track position/time four-vector
0085   /// @param dir Track direction three-vector; normalization is ignored.
0086   /// @param qOverP Charge over momentum
0087   /// @param cov Curvilinear bound parameters covariance matrix
0088   /// @param particleHypothesis Particle hypothesis
0089   /// @return Curvilinear bound track parameters
0090   static GenericBoundTrackParameters createCurvilinear(
0091       const Vector4& pos4, const Vector3& dir, double qOverP,
0092       std::optional<CovarianceMatrix> cov,
0093       ParticleHypothesis particleHypothesis) {
0094     return GenericBoundTrackParameters(
0095         CurvilinearSurface(pos4.segment<3>(ePos0), dir).surface(),
0096         transformFreeToCurvilinearParameters(pos4[eTime], dir, qOverP),
0097         std::move(cov), std::move(particleHypothesis));
0098   }
0099 
0100   /// Construct from four-position, angles, and qOverP.
0101   ///
0102   /// @param pos4 Track position/time four-vector
0103   /// @param phi Transverse track direction angle
0104   /// @param theta Longitudinal track direction angle
0105   /// @param qOverP Charge over momentum
0106   /// @param cov Curvilinear bound parameters covariance matrix
0107   /// @param particleHypothesis Particle hypothesis
0108   /// @return Curvilinear bound track parameters
0109   static GenericBoundTrackParameters createCurvilinear(
0110       const Vector4& pos4, double phi, double theta, double qOverP,
0111       std::optional<CovarianceMatrix> cov,
0112       ParticleHypothesis particleHypothesis) {
0113     return GenericBoundTrackParameters(
0114         CurvilinearSurface(pos4.segment<3>(ePos0),
0115                            makeDirectionFromPhiTheta(phi, theta))
0116             .surface(),
0117         transformFreeToCurvilinearParameters(pos4[eTime], phi, theta, qOverP),
0118         std::move(cov), std::move(particleHypothesis));
0119   }
0120 
0121   /// Construct from a parameters vector on the surface and particle charge.
0122   ///
0123   /// @param surface Reference surface the parameters are defined on
0124   /// @param params Bound parameters vector
0125   /// @param cov Bound parameters covariance matrix
0126   /// @param particleHypothesis Particle hypothesis
0127   ///
0128   /// In principle, only the charge magnitude is needed her to allow unambiguous
0129   /// extraction of the absolute momentum. The particle charge is required as
0130   /// an input here to be consistent with the other constructors below that
0131   /// that also take the charge as an input. The charge sign is only used in
0132   /// debug builds to check for consistency with the q/p parameter.
0133   GenericBoundTrackParameters(std::shared_ptr<const Surface> surface,
0134                               const ParametersVector& params,
0135                               std::optional<CovarianceMatrix> cov,
0136                               ParticleHypothesis particleHypothesis)
0137       : m_params(params),
0138         m_cov(std::move(cov)),
0139         m_surface(std::move(surface)),
0140         m_particleHypothesis(std::move(particleHypothesis)) {
0141     // TODO set `validateAngleRange` to `true` after fixing caller code
0142     assert(isBoundVectorValid(m_params, false) &&
0143            "Invalid bound parameters vector");
0144     assert(m_surface != nullptr && "Reference surface must not be null");
0145     normalizePhiTheta();
0146   }
0147 
0148   /// Converts a bound track parameter with a different hypothesis.
0149   /// @param other The other bound track parameters to convert from
0150   template <typename other_particle_hypothesis_t>
0151   explicit GenericBoundTrackParameters(
0152       const GenericBoundTrackParameters<other_particle_hypothesis_t>& other)
0153       : GenericBoundTrackParameters(
0154             other.referenceSurface().getSharedPtr(), other.parameters(),
0155             other.covariance(),
0156             ParticleHypothesis{other.particleHypothesis()}) {}
0157 
0158   /// Convert this track parameter object to the general type-erased one
0159   /// @return Type-erased bound track parameters
0160   [[deprecated("You already have a bound track parameter at hand")]]
0161   GenericBoundTrackParameters<Acts::ParticleHypothesis> toBound() const {
0162     return GenericBoundTrackParameters<Acts::ParticleHypothesis>{*this};
0163   }
0164 
0165   /// Parameters vector.
0166   /// @return Mutable reference to the parameters vector
0167   ParametersVector& parameters() { return m_params; }
0168   /// Parameters vector.
0169   /// @return Const reference to the parameters vector
0170   const ParametersVector& parameters() const { return m_params; }
0171   /// Vector of spatial impact parameters (i.e., d0 and z0)
0172   /// @return Two-dimensional vector of spatial impact parameters
0173   Vector2 spatialImpactParameters() const { return m_params.head<2>(); }
0174   /// Vector of spatial and temporal impact parameters (i.e., d0, z0, and t)
0175   /// @return Three-dimensional vector of impact parameters
0176   Vector3 impactParameters() const {
0177     Vector3 ip;
0178     ip.template head<2>() = m_params.template head<2>();
0179     ip(2) = m_params(eBoundTime);
0180     return ip;
0181   }
0182 
0183   /// Optional covariance matrix.
0184   /// @return Mutable reference to the optional covariance matrix
0185   std::optional<CovarianceMatrix>& covariance() { return m_cov; }
0186   /// Optional covariance matrix.
0187   /// @return Const reference to the optional covariance matrix
0188   const std::optional<CovarianceMatrix>& covariance() const { return m_cov; }
0189   /// Covariance matrix of the spatial impact parameters (i.e., of d0 and z0)
0190   /// @return Optional 2x2 covariance matrix of spatial impact parameters
0191   std::optional<SquareMatrix<2>> spatialImpactParameterCovariance() const {
0192     if (!m_cov.has_value()) {
0193       return std::nullopt;
0194     }
0195 
0196     return m_cov.value().template topLeftCorner<2, 2>();
0197   }
0198 
0199   /// Covariance matrix of the spatial and temporal impact parameters (i.e., of
0200   /// d0, z0, and t)
0201   /// @return Optional 3x3 covariance matrix of impact parameters
0202   std::optional<SquareMatrix<3>> impactParameterCovariance() const {
0203     if (!m_cov.has_value()) {
0204       return std::nullopt;
0205     }
0206 
0207     SquareMatrix<3> ipCov;
0208     ipCov.template topLeftCorner<2, 2>() =
0209         m_cov.value().template topLeftCorner<2, 2>();
0210     ipCov.template block<2, 1>(0, 2) =
0211         m_cov.value().template block<2, 1>(0, eBoundTime);
0212     ipCov.template block<1, 2>(2, 0) =
0213         m_cov.value().template block<1, 2>(eBoundTime, 0);
0214     ipCov(2, 2) = m_cov.value()(eBoundTime, eBoundTime);
0215     return ipCov;
0216   }
0217 
0218   /// Access a single parameter value identified by its index.
0219   ///
0220   /// @tparam kIndex Track parameter index
0221   /// @return The parameter value at the specified index
0222   template <BoundIndices kIndex>
0223   double get() const {
0224     return m_params[kIndex];
0225   }
0226 
0227   /// Local spatial position two-vector.
0228   /// @return Two-dimensional local position vector on the reference surface
0229   Vector2 localPosition() const { return m_params.segment<2>(eBoundLoc0); }
0230   /// Space-time position four-vector.
0231   ///
0232   /// @param[in] geoCtx Geometry context for the local-to-global
0233   /// transformation
0234   ///
0235   /// @return Four-dimensional position vector (x, y, z, t) in global coordinates
0236   ///
0237   /// This uses the associated surface to transform the local position on
0238   /// the surface to globalcoordinates. This requires a geometry context to
0239   /// select the appropriate transformation and might be a computationally
0240   /// expensive operation.
0241   Vector4 fourPosition(const GeometryContext& geoCtx) const {
0242     Vector4 pos4;
0243     pos4.segment<3>(ePos0) =
0244         m_surface->localToGlobal(geoCtx, localPosition(), direction());
0245     pos4[eTime] = m_params[eBoundTime];
0246     return pos4;
0247   }
0248   /// Spatial position three-vector.
0249   ///
0250   /// @param[in] geoCtx Geometry context for the local-to-global
0251   /// transformation
0252   ///
0253   /// @return Three-dimensional position vector in global coordinates
0254   ///
0255   /// This uses the associated surface to transform the local position on
0256   /// the surface to globalcoordinates. This requires a geometry context to
0257   /// select the appropriate transformation and might be a computationally
0258   /// expensive operation.
0259   Vector3 position(const GeometryContext& geoCtx) const {
0260     return m_surface->localToGlobal(geoCtx, localPosition(), direction());
0261   }
0262   /// Time coordinate.
0263   /// @return The time coordinate value
0264   double time() const { return m_params[eBoundTime]; }
0265 
0266   /// Phi direction.
0267   /// @return The azimuthal angle phi in radians
0268   double phi() const { return m_params[eBoundPhi]; }
0269   /// Theta direction.
0270   /// @return The polar angle theta in radians
0271   double theta() const { return m_params[eBoundTheta]; }
0272   /// Charge over momentum.
0273   /// @return The charge over momentum ratio
0274   double qOverP() const { return m_params[eBoundQOverP]; }
0275 
0276   /// Unit direction three-vector, i.e. the normalized momentum
0277   /// three-vector.
0278   /// @return Normalized direction vector
0279   Vector3 direction() const {
0280     return makeDirectionFromPhiTheta(m_params[eBoundPhi],
0281                                      m_params[eBoundTheta]);
0282   }
0283   /// Absolute momentum.
0284   /// @return The absolute momentum magnitude
0285   double absoluteMomentum() const {
0286     return m_particleHypothesis.extractMomentum(m_params[eBoundQOverP]);
0287   }
0288   /// Transverse momentum.
0289   /// @return The transverse momentum magnitude
0290   double transverseMomentum() const {
0291     return std::sin(m_params[eBoundTheta]) * absoluteMomentum();
0292   }
0293   /// Momentum three-vector.
0294   /// @return Three-dimensional momentum vector
0295   Vector3 momentum() const { return absoluteMomentum() * direction(); }
0296 
0297   /// Particle electric charge.
0298   /// @return The particle electric charge
0299   double charge() const {
0300     return m_particleHypothesis.extractCharge(get<eBoundQOverP>());
0301   }
0302 
0303   /// Particle hypothesis.
0304   /// @return Reference to the particle hypothesis
0305   const ParticleHypothesis& particleHypothesis() const {
0306     return m_particleHypothesis;
0307   }
0308 
0309   /// Reference surface onto which the parameters are bound.
0310   /// @return Reference to the bound reference surface
0311   const Surface& referenceSurface() const { return *m_surface; }
0312   /// Reference frame in which the local error is defined.
0313   ///
0314   /// @param[in] geoCtx Geometry context for the local-to-global
0315   /// transformation
0316   ///
0317   /// @return The reference frame rotation matrix
0318   ///
0319   /// For planar surfaces, this is the transformation local-to-global
0320   /// rotation matrix. For non-planar surfaces, it is the local-to-global
0321   /// rotation matrix of the tangential plane at the track position.
0322   RotationMatrix3 referenceFrame(const GeometryContext& geoCtx) const {
0323     return m_surface->referenceFrame(geoCtx, position(geoCtx), momentum());
0324   }
0325 
0326   /// Reflect the parameters in place.
0327   void reflectInPlace() { m_params = reflectBoundParameters(m_params); }
0328 
0329   /// Reflect the parameters.
0330   /// @return Reflected parameters.
0331   GenericBoundTrackParameters<ParticleHypothesis> reflect() const {
0332     GenericBoundTrackParameters<ParticleHypothesis> reflected = *this;
0333     reflected.reflectInPlace();
0334     return reflected;
0335   }
0336 
0337  private:
0338   BoundVector m_params;
0339   std::optional<BoundMatrix> m_cov;
0340   /// reference surface
0341   std::shared_ptr<const Surface> m_surface;
0342   // TODO use [[no_unique_address]] once we switch to C++20
0343   ParticleHypothesis m_particleHypothesis;
0344 
0345   /// Ensure phi and theta angles are within bounds.
0346   void normalizePhiTheta() {
0347     auto [phi, theta] =
0348         detail::normalizePhiTheta(m_params[eBoundPhi], m_params[eBoundTheta]);
0349     m_params[eBoundPhi] = phi;
0350     m_params[eBoundTheta] = theta;
0351   }
0352 
0353   /// Compare two bound track parameters for bitwise equality.
0354   ///
0355   /// @note Comparing track parameters for bitwise equality is not a good
0356   /// idea.
0357   ///   Depending on the context you might want to compare only the
0358   ///   parameter values, or compare them for compatibility instead of
0359   ///   equality; you might also have different (floating point) thresholds
0360   ///   of equality in different contexts. None of that can be handled by
0361   ///   this operator. Users should think really hard if this is what they
0362   ///   want and we might decided that we will remove this in the future.
0363   friend bool operator==(const GenericBoundTrackParameters& lhs,
0364                          const GenericBoundTrackParameters& rhs) {
0365     return (lhs.m_params == rhs.m_params) && (lhs.m_cov == rhs.m_cov) &&
0366            (lhs.m_surface == rhs.m_surface) &&
0367            (lhs.m_particleHypothesis == rhs.m_particleHypothesis);
0368   }
0369 
0370   /// Print information to the output stream.
0371   friend std::ostream& operator<<(std::ostream& os,
0372                                   const GenericBoundTrackParameters& tp) {
0373     detail::printBoundParameters(
0374         os, tp.referenceSurface(), tp.particleHypothesis(), tp.parameters(),
0375         tp.covariance().has_value() ? &tp.covariance().value() : nullptr);
0376     return os;
0377   }
0378 };
0379 
0380 }  // namespace Acts