Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-11 09:40:04

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/Direction.hpp"
0012 #include "Acts/Definitions/Units.hpp"
0013 #include "Acts/EventData/SpacePointContainer2.hpp"
0014 #include "Acts/Utilities/Delegate.hpp"
0015 #include "Acts/Utilities/detail/ContainerIterator.hpp"
0016 
0017 #include <cstdint>
0018 #include <vector>
0019 
0020 namespace Acts {
0021 
0022 /// Container for doublets found by the doublet seed finder.
0023 ///
0024 /// This implementation uses partial AoS/SoA depending on the access pattern in
0025 /// the doublet finding process.
0026 class DoubletsForMiddleSp {
0027  public:
0028   /// Type alias for index type used in doublets container
0029   using Index = std::uint32_t;
0030   /// Type alias for range of indices in doublets container
0031   using IndexRange = std::pair<Index, Index>;
0032   /// Type alias for subset of indices in doublets container
0033   using IndexSubset = std::span<const Index>;
0034 
0035   /// Check if the doublets container is empty
0036   /// @return True if container has no doublets
0037   [[nodiscard]] bool empty() const { return m_spacePoints.empty(); }
0038   /// Get the number of doublets in container
0039   /// @return Number of doublets stored
0040   [[nodiscard]] Index size() const {
0041     return static_cast<Index>(m_spacePoints.size());
0042   }
0043 
0044   /// Clear all stored doublets and associated data
0045   void clear() {
0046     m_spacePoints.clear();
0047     m_cotTheta.clear();
0048     m_er_iDeltaR.clear();
0049     m_uv.clear();
0050     m_xy.clear();
0051   }
0052 
0053   /// Add a new doublet with associated parameters
0054   /// @param sp Space point index for the doublet
0055   /// @param cotTheta Cotangent of polar angle
0056   /// @param iDeltaR Inverse delta R parameter
0057   /// @param er Error in R coordinate
0058   /// @param u U coordinate parameter
0059   /// @param v V coordinate parameter
0060   /// @param x X coordinate
0061   /// @param y Y coordinate
0062   void emplace_back(SpacePointIndex2 sp, float cotTheta, float iDeltaR,
0063                     float er, float u, float v, float x, float y) {
0064     m_spacePoints.push_back(sp);
0065     m_cotTheta.push_back(cotTheta);
0066     m_er_iDeltaR.push_back({er, iDeltaR});
0067     m_uv.push_back({u, v});
0068     m_xy.push_back({x, y});
0069   }
0070 
0071   /// Get reference to space point indices container
0072   /// @return Const reference to space point indices vector
0073   const std::vector<SpacePointIndex2>& spacePoints() const {
0074     return m_spacePoints;
0075   }
0076   /// Get reference to cotTheta values container
0077   /// @return Const reference to cotTheta values vector
0078   const std::vector<float>& cotTheta() const { return m_cotTheta; }
0079 
0080   struct IndexAndCotTheta {
0081     Index index{};
0082     float cotTheta{};
0083   };
0084 
0085   /// Type alias for subset of index and cotTheta pairs
0086   using IndexAndCotThetaSubset = std::span<const IndexAndCotTheta>;
0087 
0088   /// Sort doublets by cotTheta within given range
0089   /// @param range Index range to sort within
0090   /// @param indexAndCotTheta Output vector containing sorted index and cotTheta pairs
0091   void sortByCotTheta(const IndexRange& range,
0092                       std::vector<IndexAndCotTheta>& indexAndCotTheta) const {
0093     indexAndCotTheta.clear();
0094     indexAndCotTheta.reserve(range.second - range.first);
0095     for (Index i = range.first; i < range.second; ++i) {
0096       indexAndCotTheta.emplace_back(i, m_cotTheta[i]);
0097     }
0098     std::ranges::sort(indexAndCotTheta, {}, [](const IndexAndCotTheta& item) {
0099       return item.cotTheta;
0100     });
0101   }
0102 
0103   class Proxy {
0104    public:
0105     Proxy(const DoubletsForMiddleSp* container, Index index)
0106         : m_container(container), m_index(index) {}
0107 
0108     const DoubletsForMiddleSp& container() const { return *m_container; }
0109     Index index() const { return m_index; }
0110 
0111     SpacePointIndex2 spacePointIndex() const {
0112       return m_container->m_spacePoints[m_index];
0113     }
0114 
0115     float cotTheta() const { return m_container->m_cotTheta[m_index]; }
0116     float er() const { return m_container->m_er_iDeltaR[m_index][0]; }
0117     float iDeltaR() const { return m_container->m_er_iDeltaR[m_index][1]; }
0118     float u() const { return m_container->m_uv[m_index][0]; }
0119     float v() const { return m_container->m_uv[m_index][1]; }
0120     float x() const { return m_container->m_xy[m_index][0]; }
0121     float y() const { return m_container->m_xy[m_index][1]; }
0122 
0123    private:
0124     const DoubletsForMiddleSp* m_container{};
0125     Index m_index{};
0126   };
0127   /// Same as `Proxy` but also contains `cotTheta`. This is useful after sorting
0128   /// doublets by `cotTheta` to avoid indirect access.
0129   class Proxy2 : public Proxy {
0130    public:
0131     /// Constructor for Proxy2 with precomputed cotTheta
0132     /// @param container Pointer to the doublets container
0133     /// @param indexAndCotTheta Index and cotTheta pair
0134     Proxy2(const DoubletsForMiddleSp* container,
0135            IndexAndCotTheta indexAndCotTheta)
0136         : Proxy(container, indexAndCotTheta.index),
0137           m_cotTheta(indexAndCotTheta.cotTheta) {}
0138 
0139     /// Get precomputed cotTheta value (avoids indirect access)
0140     /// @return Cotangent of polar angle
0141     float cotTheta() const { return m_cotTheta; }
0142 
0143    private:
0144     float m_cotTheta{};
0145   };
0146 
0147   /// Access doublet by index
0148   /// @param index Index of the doublet to access
0149   /// @return Proxy object for the doublet
0150   Proxy operator[](Index index) const { return Proxy(this, index); }
0151   /// Access doublet by index and cotTheta pair
0152   /// @param indexAndCotTheta Index and cotTheta pair for the doublet
0153   /// @return Proxy2 object for the doublet with precomputed cotTheta
0154   Proxy2 operator[](IndexAndCotTheta indexAndCotTheta) const {
0155     return Proxy2(this, indexAndCotTheta);
0156   }
0157 
0158   /// Type alias for const iterator over doublets in container
0159   using const_iterator =
0160       detail::ContainerIterator<DoubletsForMiddleSp, Proxy, Index, true>;
0161 
0162   /// Get iterator to beginning of doublets container
0163   /// @return Const iterator to first doublet
0164   const_iterator begin() const { return const_iterator(*this, 0); }
0165   /// Get iterator to end of doublets container
0166   /// @return Const iterator past the last doublet
0167   const_iterator end() const { return const_iterator(*this, size()); }
0168 
0169   class Range : public detail::ContainerRange<Range, Range, DoubletsForMiddleSp,
0170                                               Index, true> {
0171    public:
0172     using Base =
0173         detail::ContainerRange<Range, Range, DoubletsForMiddleSp, Index, true>;
0174 
0175     using Base::Base;
0176   };
0177 
0178   /// Get range view of all doublets
0179   /// @return Range object covering all doublets
0180   Range range() const noexcept { return Range(*this, {0, size()}); }
0181   /// Get range view of doublets within specified index range
0182   /// @param range Index range to create view for
0183   /// @return Range object covering specified doublets
0184   Range range(const IndexRange& range) const noexcept {
0185     return Range(*this, range);
0186   }
0187 
0188   class Subset
0189       : public detail::ContainerSubset<Subset, Subset, DoubletsForMiddleSp,
0190                                        Proxy, Index, true> {
0191    public:
0192     using Base = detail::ContainerSubset<Subset, Subset, DoubletsForMiddleSp,
0193                                          Proxy, Index, true>;
0194 
0195     using Base::Base;
0196   };
0197   class Subset2
0198       : public detail::ContainerSubset<Subset2, Subset2, DoubletsForMiddleSp,
0199                                        Proxy2, IndexAndCotTheta, true> {
0200    public:
0201     using Base = detail::ContainerSubset<Subset2, Subset2, DoubletsForMiddleSp,
0202                                          Proxy2, IndexAndCotTheta, true>;
0203 
0204     using Base::Base;
0205   };
0206 
0207   /// Create subset view from index subset
0208   /// @param subset Span of indices to include in subset
0209   /// @return Subset object for the specified indices
0210   Subset subset(const IndexSubset& subset) const noexcept {
0211     return Subset(*this, subset);
0212   }
0213   /// Create subset view from index and cotTheta subset
0214   /// @param subset Span of index and cotTheta pairs to include
0215   /// @return Subset2 object with precomputed cotTheta values
0216   Subset2 subset(const IndexAndCotThetaSubset& subset) const noexcept {
0217     return Subset2(*this, subset);
0218   }
0219 
0220  private:
0221   std::vector<SpacePointIndex2> m_spacePoints;
0222 
0223   // parameters required to calculate a circle with linear equation
0224   std::vector<float> m_cotTheta;
0225   std::vector<std::array<float, 2>> m_er_iDeltaR;
0226   std::vector<std::array<float, 2>> m_uv;
0227   std::vector<std::array<float, 2>> m_xy;
0228 };
0229 
0230 struct MiddleSpInfo {
0231   /// minus one over radius of middle SP
0232   float uIP{};
0233   /// square of uIP
0234   float uIP2{};
0235   /// ratio between middle SP x position and radius
0236   float cosPhiM{};
0237   /// ratio between middle SP y position and radius
0238   float sinPhiM{};
0239 };
0240 
0241 /// Interface and a collection of standard implementations for a doublet seed
0242 /// finder. Given a starting space point and a collection of candidates, it
0243 /// finds all doublets that satisfy the selection criteria. For the standard
0244 /// implementations the criteria are given by interaction point cuts.
0245 ///
0246 /// @note The standard implementations rely on virtual function dispatch which
0247 /// did not turn out to affect the performance after measurement.
0248 class DoubletSeedFinder {
0249  public:
0250   /// Collection of configuration parameters for the doublet seed finder. This
0251   /// includes doublet cuts, steering switches, and assumptions about the space
0252   /// points.
0253   struct Config {
0254     /// Whether the input space points are sorted by radius
0255     bool spacePointsSortedByRadius = false;
0256 
0257     /// Direction of the doublet candidate space points. Either forward, also
0258     /// called top doublet, or backward, also called bottom doublet.
0259     Direction candidateDirection = Direction::Forward();
0260 
0261     /// Minimum radial distance between two doublet components
0262     float deltaRMin = 5 * UnitConstants::mm;
0263     /// Maximum radial distance between two doublet components
0264     float deltaRMax = 270 * UnitConstants::mm;
0265 
0266     /// Minimal z distance between two doublet components
0267     float deltaZMin = -std::numeric_limits<float>::infinity();
0268     /// Maximum z distance between two doublet components
0269     float deltaZMax = std::numeric_limits<float>::infinity();
0270 
0271     /// Maximum value of impact parameter estimation of the seed candidates
0272     float impactMax = 20 * UnitConstants::mm;
0273 
0274     /// Enable cut on the compatibility between interaction point and doublet,
0275     /// this is an useful approximation to speed up the seeding
0276     bool interactionPointCut = false;
0277 
0278     /// Limiting location of collision region in z-axis used to check if doublet
0279     /// origin is within reasonable bounds
0280     float collisionRegionMin = -150 * UnitConstants::mm;
0281     /// Maximum collision region boundary in z-axis for doublet origin checks
0282     float collisionRegionMax = +150 * UnitConstants::mm;
0283 
0284     /// Maximum allowed cotTheta between two space-points in doublet, used to
0285     /// check if forward angle is within bounds
0286     float cotThetaMax = 10.01788;  // equivalent to eta = 3 (pseudorapidity)
0287 
0288     /// Minimum transverse momentum (pT) used to check the r-z slope
0289     /// compatibility of triplets with maximum multiple scattering effect
0290     /// (produced by the minimum allowed pT particle) + a certain uncertainty
0291     /// term. Check the documentation for more information
0292     /// https://acts.readthedocs.io/en/latest/core/reconstruction/pattern_recognition/seeding.html
0293     float minPt = 400 * UnitConstants::MeV;
0294     /// Parameter which can loosen the tolerance of the track seed to form a
0295     /// helix. This is useful for e.g. misaligned seeding.
0296     float helixCutTolerance = 1;
0297 
0298     /// Type alias for delegate to apply experiment specific cuts during doublet
0299     /// finding
0300     using ExperimentCuts =
0301         Delegate<bool(const ConstSpacePointProxy2& /*middle*/,
0302                       const ConstSpacePointProxy2& /*other*/,
0303                       float /*cotTheta*/, bool /*isBottomCandidate*/)>;
0304 
0305     /// Delegate to apply experiment specific cuts during doublet finding
0306     ExperimentCuts experimentCuts;
0307   };
0308 
0309   /// Derived configuration for the doublet seed finder using a magnetic field.
0310   struct DerivedConfig : public Config {
0311     /// Constructor for derived configuration with magnetic field
0312     /// @param config Base configuration to derive from
0313     /// @param bFieldInZ Magnetic field strength in z-direction
0314     DerivedConfig(const Config& config, float bFieldInZ);
0315 
0316     /// Magnetic field strength in z-direction for helix calculation
0317     float bFieldInZ = std::numeric_limits<float>::quiet_NaN();
0318     /// Squared minimum helix diameter derived from magnetic field and minimum
0319     /// pT
0320     float minHelixDiameter2 = std::numeric_limits<float>::quiet_NaN();
0321   };
0322 
0323   /// Computes additional quantities from the middle space point which can be
0324   /// reused during doublet finding.
0325   /// @param spM Middle space point for doublet computation
0326   /// @return MiddleSpInfo structure with computed quantities
0327   static MiddleSpInfo computeMiddleSpInfo(const ConstSpacePointProxy2& spM);
0328 
0329   /// Creates a new doublet seed finder instance given the configuration.
0330   /// @param config Configuration for the doublet seed finder
0331   /// @return Unique pointer to new DoubletSeedFinder instance
0332   static std::unique_ptr<DoubletSeedFinder> create(const DerivedConfig& config);
0333 
0334   virtual ~DoubletSeedFinder() = default;
0335 
0336   /// Returns the configuration of the doublet seed finder.
0337   /// @return Reference to the configuration object
0338   virtual const DerivedConfig& config() const = 0;
0339 
0340   /// Creates compatible dublets by applying a series of cuts that can be
0341   /// tested with only two SPs.
0342   ///
0343   /// @param middleSp Space point candidate to be used as middle SP in a seed
0344   /// @param middleSpInfo Information about the middle space point
0345   /// @param candidateSps Subset of space points to be used as candidates for
0346   ///   middle SP in a seed
0347   /// @param compatibleDoublets Output container for compatible doublets
0348   virtual void createDoublets(
0349       const ConstSpacePointProxy2& middleSp, const MiddleSpInfo& middleSpInfo,
0350       SpacePointContainer2::ConstSubset& candidateSps,
0351       DoubletsForMiddleSp& compatibleDoublets) const = 0;
0352 
0353   /// Creates compatible dublets by applying a series of cuts that can be
0354   /// tested with only two SPs.
0355   ///
0356   /// @param middleSp Space point candidate to be used as middle SP in a seed
0357   /// @param middleSpInfo Information about the middle space point
0358   /// @param candidateSps Range of space points to be used as candidates for
0359   ///   middle SP in a seed
0360   /// @param compatibleDoublets Output container for compatible doublets
0361   virtual void createDoublets(
0362       const ConstSpacePointProxy2& middleSp, const MiddleSpInfo& middleSpInfo,
0363       SpacePointContainer2::ConstRange& candidateSps,
0364       DoubletsForMiddleSp& compatibleDoublets) const = 0;
0365 };
0366 
0367 }  // namespace Acts