Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-24 08:18:31

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 = BoundSquareMatrix;
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   GenericBoundTrackParameters<Acts::ParticleHypothesis> toBound() const {
0161     return GenericBoundTrackParameters<Acts::ParticleHypothesis>{*this};
0162   }
0163 
0164   /// Parameters vector.
0165   /// @return Mutable reference to the parameters vector
0166   ParametersVector& parameters() { return m_params; }
0167   /// Parameters vector.
0168   /// @return Const reference to the parameters vector
0169   const ParametersVector& parameters() const { return m_params; }
0170   /// Vector of spatial impact parameters (i.e., d0 and z0)
0171   /// @return Two-dimensional vector of spatial impact parameters
0172   Vector2 spatialImpactParameters() const { return m_params.head<2>(); }
0173   /// Vector of spatial and temporal impact parameters (i.e., d0, z0, and t)
0174   /// @return Three-dimensional vector of impact parameters
0175   Vector3 impactParameters() const {
0176     Vector3 ip;
0177     ip.template head<2>() = m_params.template head<2>();
0178     ip(2) = m_params(eBoundTime);
0179     return ip;
0180   }
0181 
0182   /// Optional covariance matrix.
0183   /// @return Mutable reference to the optional covariance matrix
0184   std::optional<CovarianceMatrix>& covariance() { return m_cov; }
0185   /// Optional covariance matrix.
0186   /// @return Const reference to the optional covariance matrix
0187   const std::optional<CovarianceMatrix>& covariance() const { return m_cov; }
0188   /// Covariance matrix of the spatial impact parameters (i.e., of d0 and z0)
0189   /// @return Optional 2x2 covariance matrix of spatial impact parameters
0190   std::optional<ActsSquareMatrix<2>> spatialImpactParameterCovariance() const {
0191     if (!m_cov.has_value()) {
0192       return std::nullopt;
0193     }
0194 
0195     return m_cov.value().template topLeftCorner<2, 2>();
0196   }
0197 
0198   /// Covariance matrix of the spatial and temporal impact parameters (i.e., of
0199   /// d0, z0, and t)
0200   /// @return Optional 3x3 covariance matrix of impact parameters
0201   std::optional<ActsSquareMatrix<3>> impactParameterCovariance() const {
0202     if (!m_cov.has_value()) {
0203       return std::nullopt;
0204     }
0205 
0206     ActsSquareMatrix<3> ipCov;
0207     ipCov.template topLeftCorner<2, 2>() =
0208         m_cov.value().template topLeftCorner<2, 2>();
0209     ipCov.template block<2, 1>(0, 2) =
0210         m_cov.value().template block<2, 1>(0, eBoundTime);
0211     ipCov.template block<1, 2>(2, 0) =
0212         m_cov.value().template block<1, 2>(eBoundTime, 0);
0213     ipCov(2, 2) = m_cov.value()(eBoundTime, eBoundTime);
0214     return ipCov;
0215   }
0216 
0217   /// Access a single parameter value identified by its index.
0218   ///
0219   /// @tparam kIndex Track parameter index
0220   /// @return The parameter value at the specified index
0221   template <BoundIndices kIndex>
0222   double get() const {
0223     return m_params[kIndex];
0224   }
0225 
0226   /// Local spatial position two-vector.
0227   /// @return Two-dimensional local position vector on the reference surface
0228   Vector2 localPosition() const { return m_params.segment<2>(eBoundLoc0); }
0229   /// Space-time position four-vector.
0230   ///
0231   /// @param[in] geoCtx Geometry context for the local-to-global
0232   /// transformation
0233   ///
0234   /// @return Four-dimensional position vector (x, y, z, t) in global coordinates
0235   ///
0236   /// This uses the associated surface to transform the local position on
0237   /// the surface to globalcoordinates. This requires a geometry context to
0238   /// select the appropriate transformation and might be a computationally
0239   /// expensive operation.
0240   Vector4 fourPosition(const GeometryContext& geoCtx) const {
0241     Vector4 pos4;
0242     pos4.segment<3>(ePos0) =
0243         m_surface->localToGlobal(geoCtx, localPosition(), direction());
0244     pos4[eTime] = m_params[eBoundTime];
0245     return pos4;
0246   }
0247   /// Spatial position three-vector.
0248   ///
0249   /// @param[in] geoCtx Geometry context for the local-to-global
0250   /// transformation
0251   ///
0252   /// @return Three-dimensional position vector in global coordinates
0253   ///
0254   /// This uses the associated surface to transform the local position on
0255   /// the surface to globalcoordinates. This requires a geometry context to
0256   /// select the appropriate transformation and might be a computationally
0257   /// expensive operation.
0258   Vector3 position(const GeometryContext& geoCtx) const {
0259     return m_surface->localToGlobal(geoCtx, localPosition(), direction());
0260   }
0261   /// Time coordinate.
0262   /// @return The time coordinate value
0263   double time() const { return m_params[eBoundTime]; }
0264 
0265   /// Phi direction.
0266   /// @return The azimuthal angle phi in radians
0267   double phi() const { return m_params[eBoundPhi]; }
0268   /// Theta direction.
0269   /// @return The polar angle theta in radians
0270   double theta() const { return m_params[eBoundTheta]; }
0271   /// Charge over momentum.
0272   /// @return The charge over momentum ratio
0273   double qOverP() const { return m_params[eBoundQOverP]; }
0274 
0275   /// Unit direction three-vector, i.e. the normalized momentum
0276   /// three-vector.
0277   /// @return Normalized direction vector
0278   Vector3 direction() const {
0279     return makeDirectionFromPhiTheta(m_params[eBoundPhi],
0280                                      m_params[eBoundTheta]);
0281   }
0282   /// Absolute momentum.
0283   /// @return The absolute momentum magnitude
0284   double absoluteMomentum() const {
0285     return m_particleHypothesis.extractMomentum(m_params[eBoundQOverP]);
0286   }
0287   /// Transverse momentum.
0288   /// @return The transverse momentum magnitude
0289   double transverseMomentum() const {
0290     return std::sin(m_params[eBoundTheta]) * absoluteMomentum();
0291   }
0292   /// Momentum three-vector.
0293   /// @return Three-dimensional momentum vector
0294   Vector3 momentum() const { return absoluteMomentum() * direction(); }
0295 
0296   /// Particle electric charge.
0297   /// @return The particle electric charge
0298   double charge() const {
0299     return m_particleHypothesis.extractCharge(get<eBoundQOverP>());
0300   }
0301 
0302   /// Particle hypothesis.
0303   /// @return Reference to the particle hypothesis
0304   const ParticleHypothesis& particleHypothesis() const {
0305     return m_particleHypothesis;
0306   }
0307 
0308   /// Reference surface onto which the parameters are bound.
0309   /// @return Reference to the bound reference surface
0310   const Surface& referenceSurface() const { return *m_surface; }
0311   /// Reference frame in which the local error is defined.
0312   ///
0313   /// @param[in] geoCtx Geometry context for the local-to-global
0314   /// transformation
0315   ///
0316   /// @return The reference frame rotation matrix
0317   ///
0318   /// For planar surfaces, this is the transformation local-to-global
0319   /// rotation matrix. For non-planar surfaces, it is the local-to-global
0320   /// rotation matrix of the tangential plane at the track position.
0321   RotationMatrix3 referenceFrame(const GeometryContext& geoCtx) const {
0322     return m_surface->referenceFrame(geoCtx, position(geoCtx), momentum());
0323   }
0324 
0325   /// Reflect the parameters in place.
0326   void reflectInPlace() { m_params = reflectBoundParameters(m_params); }
0327 
0328   /// Reflect the parameters.
0329   /// @return Reflected parameters.
0330   GenericBoundTrackParameters<ParticleHypothesis> reflect() const {
0331     GenericBoundTrackParameters<ParticleHypothesis> reflected = *this;
0332     reflected.reflectInPlace();
0333     return reflected;
0334   }
0335 
0336  private:
0337   BoundVector m_params;
0338   std::optional<BoundSquareMatrix> m_cov;
0339   /// reference surface
0340   std::shared_ptr<const Surface> m_surface;
0341   // TODO use [[no_unique_address]] once we switch to C++20
0342   ParticleHypothesis m_particleHypothesis;
0343 
0344   /// Ensure phi and theta angles are within bounds.
0345   void normalizePhiTheta() {
0346     auto [phi, theta] =
0347         detail::normalizePhiTheta(m_params[eBoundPhi], m_params[eBoundTheta]);
0348     m_params[eBoundPhi] = phi;
0349     m_params[eBoundTheta] = theta;
0350   }
0351 
0352   /// Compare two bound track parameters for bitwise equality.
0353   ///
0354   /// @note Comparing track parameters for bitwise equality is not a good
0355   /// idea.
0356   ///   Depending on the context you might want to compare only the
0357   ///   parameter values, or compare them for compatibility instead of
0358   ///   equality; you might also have different (floating point) thresholds
0359   ///   of equality in different contexts. None of that can be handled by
0360   ///   this operator. Users should think really hard if this is what they
0361   ///   want and we might decided that we will remove this in the future.
0362   friend bool operator==(const GenericBoundTrackParameters& lhs,
0363                          const GenericBoundTrackParameters& rhs) {
0364     return (lhs.m_params == rhs.m_params) && (lhs.m_cov == rhs.m_cov) &&
0365            (lhs.m_surface == rhs.m_surface) &&
0366            (lhs.m_particleHypothesis == rhs.m_particleHypothesis);
0367   }
0368 
0369   /// Print information to the output stream.
0370   friend std::ostream& operator<<(std::ostream& os,
0371                                   const GenericBoundTrackParameters& tp) {
0372     detail::printBoundParameters(
0373         os, tp.referenceSurface(), tp.parameters(),
0374         tp.covariance().has_value() ? &tp.covariance().value() : nullptr);
0375     return os;
0376   }
0377 };
0378 
0379 }  // namespace Acts