Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-24 08:17:44

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/Algebra.hpp"
0012 #include "Acts/Definitions/Units.hpp"
0013 #include "Acts/Geometry/GeometryContext.hpp"
0014 #include "Acts/Geometry/ProtoLayer.hpp"
0015 #include "Acts/Surfaces/Surface.hpp"
0016 #include "Acts/Surfaces/SurfaceArray.hpp"
0017 #include "Acts/Utilities/AxisDefinitions.hpp"
0018 #include "Acts/Utilities/BinningType.hpp"
0019 #include "Acts/Utilities/IAxis.hpp"
0020 #include "Acts/Utilities/Logger.hpp"
0021 
0022 #include <cmath>
0023 #include <cstddef>
0024 #include <functional>
0025 #include <memory>
0026 #include <numbers>
0027 #include <optional>
0028 #include <utility>
0029 #include <vector>
0030 
0031 namespace ActsTests {
0032 struct SurfaceArrayCreatorFixture;
0033 }
0034 
0035 namespace Acts {
0036 
0037 /// Function type for comparing two surfaces in a given geometry context and
0038 /// axis direction.
0039 /// @param gctx The geometry context for the comparison
0040 /// @param dir The axis direction to consider
0041 /// @param s1 First surface to compare
0042 /// @param s2 Second surface to compare
0043 /// @return True if the surfaces are considered equivalent for binning purposes
0044 using SurfaceMatcher =
0045     std::function<bool(const GeometryContext& gctx, AxisDirection,
0046                        const Surface*, const Surface*)>;
0047 
0048 /// Vector of pointers to constant Surface objects
0049 using SurfaceVector = std::vector<const Surface*>;
0050 /// Matrix (2D vector) of pointers to constant Surface objects
0051 using SurfaceMatrix = std::vector<SurfaceVector>;
0052 
0053 /// @typedef V3Vector
0054 /// Vector of 3D vectors, used for storing collections of 3D points.
0055 using V3Vector = std::vector<Vector3>;
0056 
0057 /// @typedef V3Matrix
0058 /// Matrix (2D vector) of 3D vectors, used for storing grid-like collections of
0059 /// 3D points.
0060 using V3Matrix = std::vector<V3Vector>;
0061 
0062 /// @class SurfaceArrayCreator
0063 ///
0064 /// It is designed create sub surface arrays to be ordered on Surfaces
0065 ///
0066 /// @todo write more documentation on how this is done
0067 class SurfaceArrayCreator {
0068  public:
0069   friend struct ActsTests::SurfaceArrayCreatorFixture;
0070 
0071   /// Configuration options for the surface array creator.
0072   struct Config {
0073     /// Type-erased function which determines whether two surfaces are
0074     /// supposed to be considered equivalent in terms of the binning
0075     SurfaceMatcher surfaceMatcher = SurfaceArrayCreator::isSurfaceEquivalent;
0076 
0077     /// Optimize the binning in phi for disc layers. Reduces the number
0078     /// of bins to the lowest number of non-equivalent phi surfaces
0079     /// of all r-bins. If false, this step is skipped.
0080     bool doPhiBinningOptimization = true;
0081   };
0082 
0083   /// Constructor with default config
0084   ///
0085   /// @param logger logging instance
0086   explicit SurfaceArrayCreator(std::unique_ptr<const Logger> logger =
0087                                    getDefaultLogger("SurfaceArrayCreator",
0088                                                     Logging::INFO))
0089       : m_cfg(Config()), m_logger(std::move(logger)) {}
0090   /// Constructor with explicit config
0091   ///
0092   /// @param cfg Explicit config struct
0093   /// @param logger logging instance
0094   explicit SurfaceArrayCreator(const Config& cfg,
0095                                std::unique_ptr<const Logger> logger =
0096                                    getDefaultLogger("SurfaceArrayCreator",
0097                                                     Logging::INFO))
0098       : m_cfg(cfg), m_logger(std::move(logger)) {}
0099 
0100   /// Destructor
0101   virtual ~SurfaceArrayCreator() = default;
0102 
0103   /// SurfaceArrayCreator interface method
0104   ///
0105   /// - create an array in a cylinder, binned in phi, z when extrema and
0106   /// bin numbers are known
0107   /// @warning This function requires the cylinder aligned with the z-axis
0108   /// @param surfaces is the vector of pointers to sensitive surfaces
0109   /// to be ordered on the cylinder
0110   /// @pre the pointers to the sensitive surfaces in the surfaces vectors all
0111   /// need to be valid, since no check is performed
0112   /// @param [in] gctx The geometry context for this building call
0113   /// @param protoLayerOpt The proto layer containing the layer size
0114   /// @param binsPhi is the number of bins in phi for the surfaces
0115   /// @param binsZ is the number of bin in Z for the surfaces
0116   /// @param transform is the (optional) additional transform applied
0117   /// @param neighborWindow Bounds on the neighbor window the lookup derives
0118   ///        from the crossing angle, in bins per grid axis (phi, z)
0119   /// @param overfill Extra cells per direction and axis to fill around each matched cell
0120   ///
0121   /// @return a unique pointer to a new SurfaceArray
0122   SurfaceArray surfaceArrayOnCylinder(
0123       const GeometryContext& gctx,
0124       std::vector<std::shared_ptr<const Surface>> surfaces, std::size_t binsPhi,
0125       std::size_t binsZ, std::optional<ProtoLayer> protoLayerOpt = std::nullopt,
0126       const Transform3& transform = Transform3::Identity(),
0127       SurfaceArray::NeighborWindow neighborWindow = {{0, 0}, {1, 2}},
0128       std::uint8_t overfill = 0) const;
0129 
0130   /// SurfaceArrayCreator interface method
0131   ///
0132   /// - create an array in a cylinder, binned in phi, z when extrema and bin
0133   /// numbers are unknown - this method goes through the surfaces and finds
0134   /// out the needed information
0135   /// @warning This function requires the cylinder aligned with the z-axis
0136   /// @param surfaces is the vector of pointers to sensitive surfaces
0137   /// to be ordered on the cylinder
0138   /// @pre the pointers to the sensitive surfaces in the surfaces vectors all
0139   /// need to be valid, since no check is performed
0140   /// @param [in] gctx The geometry context for this building call
0141   /// @param protoLayerOpt The proto layer containing the layer size
0142   /// @param bTypePhi the binning type in phi direction (equidistant/arbitrary)
0143   /// @param bTypeZ the binning type in z direction (equidistant/arbitrary)
0144   /// @param transform is the (optional) additional transform applied
0145   /// @param neighborWindow Bounds on the neighbor window the lookup derives
0146   ///        from the crossing angle, in bins per grid axis (phi, z)
0147   /// @param overfill Extra cells per direction and axis to fill around each matched cell
0148   ///
0149   /// @return a unique pointer a new SurfaceArray
0150   SurfaceArray surfaceArrayOnCylinder(
0151       const GeometryContext& gctx,
0152       std::vector<std::shared_ptr<const Surface>> surfaces,
0153       BinningType bTypePhi = equidistant, BinningType bTypeZ = equidistant,
0154       std::optional<ProtoLayer> protoLayerOpt = std::nullopt,
0155       const Transform3& transform = Transform3::Identity(),
0156       SurfaceArray::NeighborWindow neighborWindow = {{0, 0}, {1, 2}},
0157       std::uint8_t overfill = 0) const;
0158 
0159   /// SurfaceArrayCreator interface method
0160   /// - create an array on a disc, binned in r, phi when extrema and
0161   /// bin numbers are known
0162   ///
0163   /// @param surfaces is the vector of pointers to sensitive surfaces
0164   /// to be ordered on the disc
0165   /// @pre the pointers to the sensitive surfaces in the surfaces vectors all
0166   /// need to be valid, since no check is performed
0167   /// @warning This function requires the disc aligned with the z-axis
0168   /// @param [in] gctx The geometry context for this building call
0169   /// @param protoLayerOpt The proto layer containing the layer size
0170   /// @param binsPhi is the number of bins in phi for the surfaces
0171   /// @param binsR is the number of bin in R for the surfaces
0172   /// @param transform is the (optional) additional transform applied
0173   /// @param neighborWindow Bounds on the neighbor window the lookup derives
0174   ///        from the crossing angle, in bins per grid axis (r, phi)
0175   /// @param overfill Extra cells per direction and axis to fill around each matched cell
0176   ///
0177   /// @return a unique pointer a new SurfaceArray
0178   SurfaceArray surfaceArrayOnDisc(
0179       const GeometryContext& gctx,
0180       std::vector<std::shared_ptr<const Surface>> surfaces, std::size_t binsR,
0181       std::size_t binsPhi,
0182       std::optional<ProtoLayer> protoLayerOpt = std::nullopt,
0183       const Transform3& transform = Transform3::Identity(),
0184       SurfaceArray::NeighborWindow neighborWindow = {{0, 0}, {2, 1}},
0185       std::uint8_t overfill = 0) const;
0186 
0187   /// SurfaceArrayCreator interface method
0188   ///
0189   /// - create an array in a cylinder, binned in phi, r when extrema and bin
0190   /// numbers are unknown - this method goes through the surfaces and finds
0191   /// out the needed information
0192   /// @param surfaces is the vector of pointers to sensitive surfaces
0193   /// to be ordered on the disc
0194   /// @pre the pointers to the sensitive surfaces in the surfaces vectors all
0195   /// need to be valid, since no check is performed
0196   /// @warning This function requires the disc aligned with the z-axis
0197   /// @param [in] gctx The geometry context for this building call
0198   /// @param protoLayerOpt The proto layer containing the layer size
0199   /// @param bTypeR the binning type in r direction (equidistant/arbitrary)
0200   /// @param bTypePhi the binning type in phi direction (equidistant/arbitrary)
0201   /// @param transform is the (optional) additional transform applied
0202   /// @param neighborWindow Bounds on the neighbor window the lookup derives
0203   ///        from the crossing angle, in bins per grid axis (r, phi)
0204   /// @param overfill Extra cells per direction and axis to fill around each matched cell
0205   ///
0206   /// @return a unique pointer a new SurfaceArray
0207   ///
0208   /// @note If there is more than on R-Ring, number of phi bins
0209   ///       will be set to lowest number of surfaces of any R-ring.
0210   ///       This ignores bTypePhi and produces equidistant binning in phi
0211   SurfaceArray surfaceArrayOnDisc(
0212       const GeometryContext& gctx,
0213       std::vector<std::shared_ptr<const Surface>> surfaces, BinningType bTypeR,
0214       BinningType bTypePhi,
0215       std::optional<ProtoLayer> protoLayerOpt = std::nullopt,
0216       const Transform3& transform = Transform3::Identity(),
0217       SurfaceArray::NeighborWindow neighborWindow = {{0, 0}, {2, 1}},
0218       std::uint8_t overfill = 0) const;
0219 
0220   /// SurfaceArrayCreator interface method
0221   /// - create an array on a plane
0222   ///
0223   /// @param [in] gctx The geometry context for this building call
0224   /// @param [in] surfaces is the vector of pointers to sensitive surfaces
0225   /// to be ordered on the plane
0226   /// @pre the pointers to the sensitive surfaces in the surfaces vectors all
0227   /// need to be valid, since no check is performed
0228   /// @warning This function requires the plane aligned with either the x-, y-
0229   /// or z-axis
0230   /// @param [in] bins1 is the number of bins in the orthogonal direction to @p
0231   /// aDir
0232   /// @param [in] bins2 is the number of bins in the orthogonal direction to @p
0233   /// aDir
0234   /// @param [in] aDir Direction of the aligned surfaces
0235   /// @param [in] protoLayerOpt Optional @c ProtoLayer instance
0236   /// @param [in] transform is the (optional) additional transform applied
0237   /// @param neighborWindow Bounds on the neighbor window the lookup derives
0238   ///        from the crossing angle, in bins per grid axis
0239   /// @param overfill Extra cells per direction and axis to fill around each matched cell
0240   ///
0241   /// @return a unique pointer a new SurfaceArray
0242   SurfaceArray surfaceArrayOnPlane(
0243       const GeometryContext& gctx,
0244       std::vector<std::shared_ptr<const Surface>> surfaces, std::size_t bins1,
0245       std::size_t bins2, AxisDirection aDir,
0246       std::optional<ProtoLayer> protoLayerOpt = std::nullopt,
0247       const Transform3& transform = Transform3::Identity(),
0248       SurfaceArray::NeighborWindow neighborWindow = {{0, 0}, {2, 2}},
0249       std::uint8_t overfill = 0) const;
0250 
0251   /// Static check function for surface equivalent
0252   ///
0253   /// @param [in] gctx the geometry context for this check
0254   /// @param aDir the axis direction for the binning
0255   /// @param a first surface for checking
0256   /// @param b second surface for checking
0257   /// @return true if surfaces are equivalent for binning purposes
0258   static bool isSurfaceEquivalent(const GeometryContext& gctx,
0259                                   AxisDirection aDir, const Surface* a,
0260                                   const Surface* b) {
0261     using namespace UnitLiterals;
0262     using VectorHelpers::perp;
0263 
0264     if (aDir == AxisDirection::AxisPhi) {
0265       // Take the two binning positions
0266       Vector3 pos1 = a->referencePosition(gctx, AxisDirection::AxisR);
0267       Vector3 pos2 = b->referencePosition(gctx, AxisDirection::AxisR);
0268 
0269       // Project them on the (x, y) plane, where Phi angles are calculated
0270       auto proj1 = pos1.head<2>(), proj2 = pos2.head<2>();
0271 
0272       // Basic dot and cross products identities give us the cosine and sine
0273       // of these angles, time the squared vector norm
0274       auto cos_dPhi_n2 = proj1.dot(proj2);
0275       auto sin_dPhi_n2 = proj1.x() * proj2.y() - proj2.x() * proj1.y();
0276 
0277       // ...so by injecting them into atan2, we get the angle between them
0278       auto dPhi = std::atan2(sin_dPhi_n2, cos_dPhi_n2);
0279       return std::abs(dPhi) < std::numbers::pi / 180.;
0280     }
0281 
0282     if (aDir == AxisDirection::AxisZ) {
0283       return (std::abs(a->referencePosition(gctx, AxisDirection::AxisR).z() -
0284                        b->referencePosition(gctx, AxisDirection::AxisR).z()) <
0285               1_um);
0286     }
0287 
0288     if (aDir == AxisDirection::AxisR) {
0289       return (std::abs(perp(a->referencePosition(gctx, AxisDirection::AxisR)) -
0290                        perp(b->referencePosition(gctx, AxisDirection::AxisR))) <
0291               1_um);
0292     }
0293 
0294     return false;
0295   }
0296 
0297   /// Set logging instance
0298   /// @param logger is the logging instance to be set
0299   void setLogger(std::unique_ptr<const Logger> logger) {
0300     m_logger = std::move(logger);
0301   }
0302 
0303   /// Determine the number of bins for a binning direction from the number of
0304   /// distinct module positions (i.e. one bin per module). Public so navigation
0305   /// policies can size their surface-array grids relative to the module count.
0306   /// @param gctx the geometry context
0307   /// @param surfaces the surfaces to analyse
0308   /// @param aDir the binning direction
0309   /// @return the number of distinct module positions along @p aDir
0310   std::size_t determineBinCount(const GeometryContext& gctx,
0311                                 const std::vector<const Surface*>& surfaces,
0312                                 AxisDirection aDir) const;
0313 
0314  private:
0315   /// configuration object
0316   Config m_cfg;
0317 
0318   /// Private access to logger
0319   const Logger& logger() const { return *m_logger; }
0320 
0321   std::vector<const Surface*> findKeySurfaces(
0322       const std::vector<const Surface*>& surfaces,
0323       const std::function<bool(const Surface*, const Surface*)>& equal) const;
0324 
0325   /// SurfaceArrayCreator internal method
0326   /// Creates a variable axis from a vector of (unsorted) surfaces with
0327   /// PlanarBounds
0328   /// It loops through the surfaces and finds out the needed information
0329   /// First the surfaces are sorted in the binning direction and the so called
0330   /// "key" surfaces (surfaces with different positions in the binning
0331   /// direction) are extracted. The boundary value between two surfaces is the
0332   /// mean value of the two center position in the binning direction. The
0333   /// first and the last boundaries are calculated from the vertices of the
0334   /// first and last surface.
0335   /// @note currently implemented for phi, r and z bining
0336   /// @todo implement for x,y binning
0337   /// @param [in] gctx the geometry context for this call
0338   /// @param surfaces are the sensitive surfaces to be
0339   /// @param aBoundaryType the AxisBoundaryType for the axis to be created
0340   /// @param aDir the AxisDirection in which direction should be binned
0341   /// (currently possible: AxisPhi, AxisR, AxisZ)
0342   /// @param protoLayer Instance of @c ProtoLayer holding generic layer info
0343   /// @param transform is the (optional) additional transform applied
0344   /// @return Type-erased @c IAxis containing the determined properties
0345   std::unique_ptr<const IAxis> createVariableAxis(
0346       const GeometryContext& gctx, const std::vector<const Surface*>& surfaces,
0347       AxisBoundaryType aBoundaryType, AxisDirection aDir,
0348       const ProtoLayer& protoLayer, Transform3& transform) const;
0349 
0350   /// SurfaceArrayCreator internal method
0351   /// Creates a equidistant axis when the extrema and the bin number
0352   /// are known.
0353   /// It loops through the surfaces and finds out the needed information
0354   /// First the surfaces are sorted in the binning direction and the so called
0355   /// "key" surfaces (surfaces with different positions in the binning
0356   /// direction) are extracted. The number of key surfaces equals the number
0357   /// of bins. Afterwards the minimum and maximum are calculated by
0358   /// subtracting/adding half of a bin size to the center position (in the
0359   /// binning direction) to the first/last surface.
0360   /// @note currently implemented for phi, r and z bining
0361   /// @todo implement for x,y binning
0362   /// @param [in] gctx the geometry context for this call
0363   /// @param surfaces are the sensitive surfaces to be
0364   /// @param aBoundaryType the AxisBoundaryType for the axis to be created
0365   /// @param aDir the AxisDirection in which direction should be binned
0366   /// (currently possible: AxisPhi, AxisR, AxisZ)
0367   /// @param protoLayer Instance of @c ProtoLayer holding generic layer info
0368   /// @param transform is the (optional) additional transform applied
0369   /// @param nBins Number of bins to use, 0 means determine automatically
0370   /// @return Type-erased @c IAxis containing the determined properties
0371   std::unique_ptr<const IAxis> createEquidistantAxis(
0372       const GeometryContext& gctx, const std::vector<const Surface*>& surfaces,
0373       AxisBoundaryType aBoundaryType, AxisDirection aDir,
0374       const ProtoLayer& protoLayer, Transform3& transform,
0375       std::size_t nBins = 0) const;
0376 
0377   /// logging instance
0378   std::unique_ptr<const Logger> m_logger;
0379 
0380   /// Private helper method to transform the  vertices of surface bounds into
0381   /// global coordinates
0382   /// @param [in] gctx the geometry context for this call
0383   /// @param surface the surface associated with the given vertices
0384   /// @param locVertices a vector of the vertices in local coordinates
0385   /// @return a vector of the vertices in global coordinates
0386   std::vector<Vector3> makeGlobalVertices(
0387       const GeometryContext& gctx, const Surface& surface,
0388       const std::vector<Vector2>& locVertices) const;
0389 };
0390 
0391 }  // namespace Acts