Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:10:47

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