Back to home page

EIC code displayed by LXR

 
 

    


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