Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-01 07:45:43

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