Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-31 08:16:03

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/EventData/GenericBoundTrackParameters.hpp"
0012 #include "Acts/EventData/TrackParameters.hpp"
0013 #include "Acts/Surfaces/PlaneSurface.hpp"
0014 #include "Acts/Surfaces/Surface.hpp"
0015 #include "Acts/Utilities/Intersection.hpp"
0016 
0017 #include <memory>
0018 #include <type_traits>
0019 #include <utility>
0020 
0021 namespace Acts {
0022 
0023 /// This class is only a light wrapper around a surface and a vector of
0024 /// parameters. Its main purpose is to provide many constructors for the
0025 /// underlying vector. Most accessors are generated from the
0026 /// BoundTrackParameters equivalent and thus may be expensive
0027 /// @note This class holds shared ownership on its reference surface.
0028 /// @note The accessors for parameters, covariance, position, etc.
0029 /// are the weighted means of the components.
0030 /// @note If all covariances are zero, the accessor for the total
0031 /// covariance does return std::nullopt;
0032 /// TODO Add constructor from range and projector maybe?
0033 class MultiComponentBoundTrackParameters {
0034  public:
0035   /// Type alias for bound track parameters
0036   using Parameters = BoundTrackParameters;
0037   /// Type alias for particle hypothesis
0038   using ParticleHypothesis = Parameters::ParticleHypothesis;
0039   /// Type alias for bound parameters vector
0040   using ParametersVector = typename Parameters::ParametersVector;
0041   /// Type alias for covariance matrix
0042   using CovarianceMatrix = typename Parameters::CovarianceMatrix;
0043 
0044  private:
0045   std::vector<std::tuple<double, BoundVector, std::optional<BoundSquareMatrix>>>
0046       m_components;
0047   std::shared_ptr<const Surface> m_surface;
0048 
0049   // TODO use [[no_unique_address]] once we switch to C++20
0050   ParticleHypothesis m_particleHypothesis;
0051 
0052   /// Helper function to reduce the component vector to a single representation
0053   template <typename projector_t>
0054   auto reduce(projector_t&& proj) const {
0055     using Ret = std::decay_t<decltype(proj(std::declval<Parameters>()))>;
0056 
0057     Ret ret;
0058 
0059     if constexpr (std::is_floating_point_v<Ret>) {
0060       ret = 0.0;
0061     } else {
0062       ret = Ret::Zero();
0063     }
0064 
0065     for (auto i = 0ul; i < m_components.size(); ++i) {
0066       const auto [weight, single_pars] = (*this)[i];
0067       ret += weight * proj(single_pars);
0068     }
0069 
0070     return ret;
0071   }
0072 
0073  public:
0074   /// Type alias for construction tuple containing weight, position, direction,
0075   /// q/p, and covariance
0076   using ConstructionTuple = std::tuple<double, Acts::Vector4, Acts::Vector3,
0077                                        double, CovarianceMatrix>;
0078 
0079   /// We need this helper function in order to construct the base class properly
0080   /// @param geoCtx Geometry context for construction
0081   /// @param curvi Vector of construction tuples containing component data
0082   /// @param particleHypothesis Particle hypothesis for the parameters
0083   /// @return Multi-component bound track parameters in curvilinear representation
0084   static MultiComponentBoundTrackParameters createCurvilinear(
0085       const GeometryContext& geoCtx,
0086       const std::vector<ConstructionTuple>& curvi,
0087       ParticleHypothesis particleHypothesis) {
0088     // Construct and average surface
0089     Acts::Vector3 avgPos = Acts::Vector3::Zero();
0090     Acts::Vector3 avgDir = Acts::Vector3::Zero();
0091     for (const auto& [w, pos4, dir, qop, cov] : curvi) {
0092       avgPos += w * pos4.template segment<3>(0);
0093       avgDir += w * dir;
0094     }
0095 
0096     std::shared_ptr<PlaneSurface> s =
0097         CurvilinearSurface(avgPos, avgDir).planeSurface();
0098 
0099     std::vector<std::tuple<double, ParametersVector, CovarianceMatrix>> bound;
0100     bound.reserve(curvi.size());
0101 
0102     // Project the position onto the surface, keep everything else as is
0103     for (const auto& [w, pos4, dir, qop, cov] : curvi) {
0104       Intersection3D closestIntersection =
0105           s->intersect(geoCtx, pos4.template segment<3>(eFreePos0), dir,
0106                        BoundaryTolerance::Infinite())
0107               .closest();
0108       const Vector3& newPos = closestIntersection.position();
0109 
0110       ParametersVector bv =
0111           transformFreeToCurvilinearParameters(pos4[eTime], dir, qop);
0112 
0113       // Because of the projection this should never fail
0114       bv.template segment<2>(eBoundLoc0) =
0115           *(s->globalToLocal(geoCtx, newPos, dir));
0116 
0117       bound.emplace_back(w, bv, cov);
0118     }
0119 
0120     return MultiComponentBoundTrackParameters(s, bound, particleHypothesis);
0121   }
0122 
0123   /// Construct from multiple components
0124   /// @param surface Surface on which the parameters are bound
0125   /// @param cmps Vector of weight, parameters vector, and covariance components
0126   /// @param particleHypothesis Particle hypothesis for the parameters
0127   template <typename covariance_t>
0128   MultiComponentBoundTrackParameters(
0129       std::shared_ptr<const Surface> surface,
0130       const std::vector<std::tuple<double, ParametersVector, covariance_t>>&
0131           cmps,
0132       ParticleHypothesis particleHypothesis)
0133       : m_surface(std::move(surface)),
0134         m_particleHypothesis(particleHypothesis) {
0135     static_assert(
0136         std::is_same_v<BoundSquareMatrix, covariance_t> ||
0137         std::is_same_v<std::optional<BoundSquareMatrix>, covariance_t>);
0138     if constexpr (std::is_same_v<BoundSquareMatrix, covariance_t>) {
0139       for (const auto& [weight, params, cov] : cmps) {
0140         m_components.push_back({weight, params, cov});
0141       }
0142     } else {
0143       m_components = cmps;
0144     }
0145   }
0146 
0147   /// Construct from a parameters vector on the surface and particle charge.
0148   ///
0149   /// @param surface Reference surface the parameters are defined on
0150   /// @param params Bound parameters vector
0151   /// @param particleHypothesis Particle hypothesis for these parameters
0152   /// @param cov Bound parameters covariance matrix
0153   ///
0154   /// In principle, only the charge magnitude is needed her to allow
0155   /// unambiguous extraction of the absolute momentum. The particle charge is
0156   /// required as an input here to be consistent with the other constructors
0157   /// below that that also take the charge as an input. The charge sign is
0158   /// only used in debug builds to check for consistency with the q/p
0159   /// parameter.
0160   MultiComponentBoundTrackParameters(std::shared_ptr<const Surface> surface,
0161                                      const ParametersVector& params,
0162                                      std::optional<BoundSquareMatrix> cov,
0163                                      ParticleHypothesis particleHypothesis)
0164       : m_surface(std::move(surface)),
0165         m_particleHypothesis(particleHypothesis) {
0166     m_components.push_back({1., params, std::move(cov)});
0167   }
0168 
0169   /// Parameters are not default constructible due to the charge type.
0170   MultiComponentBoundTrackParameters() = delete;
0171   /// Copy constructor
0172   MultiComponentBoundTrackParameters(
0173       const MultiComponentBoundTrackParameters&) = default;
0174   /// Move constructor
0175   MultiComponentBoundTrackParameters(MultiComponentBoundTrackParameters&&) =
0176       default;
0177   ~MultiComponentBoundTrackParameters() = default;
0178   /// Copy assignment operator
0179   /// @return Reference to this object after copying
0180   MultiComponentBoundTrackParameters& operator=(
0181       const MultiComponentBoundTrackParameters&) = default;
0182   /// Move assignment operator
0183   /// @return Reference to this object after moving
0184   MultiComponentBoundTrackParameters& operator=(
0185       MultiComponentBoundTrackParameters&&) = default;
0186 
0187   /// Comply with bound convertible, in this case return a copy
0188   /// @return Copy of this multi-component track parameters
0189   MultiComponentBoundTrackParameters toBound() const { return *this; }
0190 
0191   /// Access the parameters
0192   /// @return Reference to the vector of parameter components
0193   const auto& components() const { return m_components; }
0194 
0195   /// Reference surface onto which the parameters are bound.
0196   /// @return Reference to the bound reference surface
0197   const Surface& referenceSurface() const { return *m_surface; }
0198 
0199   /// Get the weight and a GenericBoundTrackParameters object for one component
0200   /// @param i Index of the component to access
0201   /// @return Pair of weight and bound track parameters for the component
0202   std::pair<double, Parameters> operator[](std::size_t i) const {
0203     return {
0204         std::get<double>(m_components[i]),
0205         Parameters(m_surface, std::get<ParametersVector>(m_components[i]),
0206                    std::get<std::optional<CovarianceMatrix>>(m_components[i]),
0207                    m_particleHypothesis)};
0208   }
0209 
0210   /// Parameters vector.
0211   /// @return Weighted average of parameters from all components
0212   ParametersVector parameters() const {
0213     return reduce([](const Parameters& p) { return p.parameters(); });
0214   }
0215 
0216   /// Optional covariance matrix.
0217   /// @return Optional weighted average covariance matrix, nullopt if all components have zero covariance
0218   std::optional<CovarianceMatrix> covariance() const {
0219     const auto ret = reduce([](const Parameters& p) {
0220       return p.covariance() ? *p.covariance() : CovarianceMatrix::Zero();
0221     });
0222 
0223     if (ret == CovarianceMatrix::Zero()) {
0224       return std::nullopt;
0225     } else {
0226       return ret;
0227     }
0228   }
0229 
0230   /// Access a single parameter value identified by its index.
0231   ///
0232   /// @tparam kIndex Track parameter index
0233   /// @return Weighted average of the parameter at the specified index
0234   template <BoundIndices kIndex>
0235   double get() const {
0236     return reduce([&](const Parameters& p) { return p.get<kIndex>(); });
0237   }
0238 
0239   /// Space-time position four-vector.
0240   ///
0241   /// @param[in] geoCtx Geometry context for the local-to-global
0242   /// transformation
0243   /// @return Weighted average four-dimensional position vector
0244   Vector4 fourPosition(const GeometryContext& geoCtx) const {
0245     return reduce([&](const Parameters& p) { return p.fourPosition(geoCtx); });
0246   }
0247 
0248   /// Spatial position three-vector.
0249   ///
0250   /// @param[in] geoCtx Geometry context for the local-to-global
0251   /// transformation
0252   /// @return Weighted average three-dimensional position vector
0253   Vector3 position(const GeometryContext& geoCtx) const {
0254     return reduce([&](const Parameters& p) { return p.position(geoCtx); });
0255   }
0256 
0257   /// Time coordinate.
0258   /// @return Weighted average time coordinate
0259   double time() const {
0260     return reduce([](const Parameters& p) { return p.time(); });
0261   }
0262 
0263   /// Unit direction three-vector, i.e. the normalized momentum
0264   /// three-vector.
0265   /// @return Weighted average normalized direction vector
0266   Vector3 direction() const {
0267     return reduce([](const Parameters& p) { return p.direction(); })
0268         .normalized();
0269   }
0270 
0271   /// Phi direction.
0272   /// @return Azimuthal angle phi derived from average direction
0273   double phi() const { return VectorHelpers::phi(direction()); }
0274 
0275   /// Theta direction.
0276   /// @return Polar angle theta derived from average direction
0277   double theta() const { return VectorHelpers::theta(direction()); }
0278 
0279   /// Charge over momentum.
0280   /// @return Weighted average charge over momentum ratio
0281   double qOverP() const { return get<eBoundQOverP>(); }
0282 
0283   /// Absolute momentum.
0284   /// @return Weighted average absolute momentum magnitude
0285   double absoluteMomentum() const {
0286     return reduce([](const Parameters& p) { return p.absoluteMomentum(); });
0287   }
0288 
0289   /// Transverse momentum.
0290   /// @return Weighted average transverse momentum magnitude
0291   double transverseMomentum() const {
0292     return reduce([](const Parameters& p) { return p.transverseMomentum(); });
0293   }
0294 
0295   /// Momentum three-vector.
0296   /// @return Weighted average three-dimensional momentum vector
0297   Vector3 momentum() const {
0298     return reduce([](const Parameters& p) { return p.momentum(); });
0299   }
0300 
0301   /// Particle electric charge.
0302   /// @return Weighted average particle electric charge
0303   double charge() const {
0304     return reduce([](const Parameters& p) { return p.charge(); });
0305   }
0306 
0307   /// Particle hypothesis.
0308   /// @return Reference to the particle hypothesis
0309   const ParticleHypothesis& particleHypothesis() const {
0310     return m_particleHypothesis;
0311   }
0312 };
0313 
0314 }  // namespace Acts