Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-15 08:27:18

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2016-2020 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 http://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/AxisFwd.hpp"
0018 #include "Acts/Utilities/BinningType.hpp"
0019 #include "Acts/Utilities/Logger.hpp"
0020 
0021 #include <algorithm>
0022 #include <cmath>
0023 #include <cstddef>
0024 #include <functional>
0025 #include <iterator>
0026 #include <memory>
0027 #include <optional>
0028 #include <ostream>
0029 #include <tuple>
0030 #include <utility>
0031 #include <vector>
0032 
0033 namespace Acts {
0034 namespace Test {
0035 struct SurfaceArrayCreatorFixture;
0036 }
0037 
0038 using SurfaceMatcher = std::function<bool(
0039     const GeometryContext& gctx, BinningValue, const Surface*, const Surface*)>;
0040 
0041 using SurfaceVector = std::vector<const Surface*>;
0042 using SurfaceMatrix = std::vector<SurfaceVector>;
0043 
0044 using V3Vector = std::vector<Vector3>;
0045 using V3Matrix = std::vector<V3Vector>;
0046 
0047 using AxisScalar = Vector3::Scalar;
0048 
0049 /// @class SurfaceArrayCreator
0050 ///
0051 /// It is designed create sub surface arrays to be ordered on Surfaces
0052 ///
0053 /// @todo write more documentation on how this is done
0054 class SurfaceArrayCreator {
0055  public:
0056   friend struct Acts::Test::SurfaceArrayCreatorFixture;
0057   friend class Acts::SurfaceArray;
0058 
0059   struct ProtoAxis {
0060     BinningType bType = BinningType::equidistant;
0061     BinningValue bValue = BinningValue::binX;
0062     std::size_t nBins = 0;
0063     AxisScalar min = 0;
0064     AxisScalar max = 0;
0065     std::vector<AxisScalar> binEdges;
0066 
0067     std::size_t getBin(AxisScalar x) const {
0068       if (binEdges.empty()) {
0069         // equidistant
0070         AxisScalar w = (max - min) / nBins;
0071         return static_cast<std::size_t>(std::floor((x - min) / w));
0072       } else {
0073         // variable
0074         const auto it =
0075             std::upper_bound(std::begin(binEdges), std::end(binEdges), x);
0076         return std::distance(std::begin(binEdges), it) - 1;
0077       }
0078     }
0079   };
0080 
0081   // Configuration struct
0082   struct Config {
0083     /// Type-erased function which determines whether two surfaces are supposed
0084     /// to be considered equivalent in terms of the binning
0085     SurfaceMatcher surfaceMatcher = SurfaceArrayCreator::isSurfaceEquivalent;
0086 
0087     /// Optimize the binning in phi for disc layers. Reduces the number
0088     /// of bins to the lowest number of non-equivalent phi surfaces
0089     /// of all r-bins. If false, this step is skipped.
0090     bool doPhiBinningOptimization = true;
0091   };
0092 
0093   /// Constructor with default config
0094   ///
0095   /// @param logger logging instance
0096   SurfaceArrayCreator(std::unique_ptr<const Logger> logger = getDefaultLogger(
0097                           "SurfaceArrayCreator", Logging::INFO))
0098       : m_cfg(Config()), m_logger(std::move(logger)) {}
0099   /// Constructor with explicit config
0100   ///
0101   /// @param cfg Explicit config struct
0102   /// @param logger logging instance
0103   SurfaceArrayCreator(const Config& cfg,
0104                       std::unique_ptr<const Logger> logger = getDefaultLogger(
0105                           "SurfaceArrayCreator", Logging::INFO))
0106       : m_cfg(cfg), m_logger(std::move(logger)) {}
0107 
0108   /// Destructor
0109   virtual ~SurfaceArrayCreator() = default;
0110 
0111   /// SurfaceArrayCreator interface method
0112   ///
0113   /// - create an array in a cylinder, binned in phi, z when extremas and
0114   /// bin numbers are known
0115   /// @warning This function requires the cylinder aligned with the z-axis
0116   /// @param surfaces is the vector of pointers to sensitive surfaces
0117   /// to be ordered on the cylinder
0118   /// @pre the pointers to the sensitive surfaces in the surfaces vectors all
0119   /// need to be valid, since no check is performed
0120   /// @param [in] gctx The gometry context for this building call
0121   /// @param protoLayerOpt The proto layer containing the layer size
0122   /// @param binsPhi is the number of bins in phi for the surfaces
0123   /// @param binsZ is the number of bin in Z for the surfaces
0124   /// @param transform is the (optional) additional transform applied
0125   ///
0126   /// @return a unique pointer to a new SurfaceArray
0127   std::unique_ptr<SurfaceArray> surfaceArrayOnCylinder(
0128       const GeometryContext& gctx,
0129       std::vector<std::shared_ptr<const Surface>> surfaces, std::size_t binsPhi,
0130       std::size_t binsZ, std::optional<ProtoLayer> protoLayerOpt = std::nullopt,
0131       const Transform3& transform = Transform3::Identity()) const;
0132 
0133   /// SurfaceArrayCreator interface method
0134   ///
0135   /// - create an array in a cylinder, binned in phi, z when extremas and bin
0136   /// numbers are unknown - this method goes through the surfaces and finds out
0137   /// the needed information
0138   /// @warning This function requires the cylinder aligned with the z-axis
0139   /// @param surfaces is the vector of pointers to sensitive surfaces
0140   /// to be ordered on the cylinder
0141   /// @pre the pointers to the sensitive surfaces in the surfaces vectors all
0142   /// need to be valid, since no check is performed
0143   /// @param [in] gctx The gometry context for this building call
0144   /// @param protoLayerOpt The proto layer containing the layer size
0145   /// @param bTypePhi the binning type in phi direction (equidistant/arbitrary)
0146   /// @param bTypeZ the binning type in z direction (equidistant/arbitrary)
0147   /// @param transform is the (optional) additional transform applied
0148   ///
0149   /// @return a unique pointer a new SurfaceArray
0150   std::unique_ptr<Acts::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()) const;
0156 
0157   /// SurfaceArrayCreator interface method
0158   /// - create an array on a disc, binned in r, phi when extremas and
0159   /// bin numbers are known
0160   ///
0161   /// @param surfaces is the vector of pointers to sensitive surfaces
0162   /// to be ordered on the disc
0163   /// @pre the pointers to the sensitive surfaces in the surfaces vectors all
0164   /// need to be valid, since no check is performed
0165   /// @warning This function requires the disc aligned with the z-axis
0166   /// @param [in] gctx The gometry context for this building call
0167   /// @param protoLayerOpt The proto layer containing the layer size
0168   /// @param binsPhi is the number of bins in phi for the surfaces
0169   /// @param binsR is the number of bin in R for the surfaces
0170   /// @param transform is the (optional) additional transform applied
0171   ///
0172   /// @return a unique pointer a new SurfaceArray
0173   std::unique_ptr<SurfaceArray> surfaceArrayOnDisc(
0174       const GeometryContext& gctx,
0175       std::vector<std::shared_ptr<const Surface>> surfaces, std::size_t binsR,
0176       std::size_t binsPhi,
0177       std::optional<ProtoLayer> protoLayerOpt = std::nullopt,
0178       const Transform3& transform = Transform3::Identity()) const;
0179 
0180   /// SurfaceArrayCreator interface method
0181   ///
0182   /// - create an array in a cylinder, binned in phi, r when extremas and bin
0183   /// numbers are unknown - this method goes through the surfaces and finds out
0184   /// the needed information
0185   /// @param surfaces is the vector of pointers to sensitive surfaces
0186   /// to be ordered on the disc
0187   /// @pre the pointers to the sensitive surfaces in the surfaces vectors all
0188   /// need to be valid, since no check is performed
0189   /// @warning This function requires the disc aligned with the z-axis
0190   /// @param [in] gctx The gometry context for this building call
0191   /// @param protoLayerOpt The proto layer containing the layer size
0192   /// @param bTypeR the binning type in r direction (equidistant/arbitrary)
0193   /// @param bTypePhi the binning type in phi direction (equidistant/arbitrary)
0194   /// @param transform is the (optional) additional transform applied
0195   ///
0196   /// @return a unique pointer a new SurfaceArray
0197   /// @note If there is more than on R-Ring, number of phi bins
0198   ///       will be set to lowest number of surfaces of any R-ring.
0199   ///       This ignores bTypePhi and produces equidistant binning in phi
0200   std::unique_ptr<Acts::SurfaceArray> surfaceArrayOnDisc(
0201       const GeometryContext& gctx,
0202       std::vector<std::shared_ptr<const Surface>> surfaces, BinningType bTypeR,
0203       BinningType bTypePhi,
0204       std::optional<ProtoLayer> protoLayerOpt = std::nullopt,
0205       const Transform3& transform = Transform3::Identity()) const;
0206 
0207   /// SurfaceArrayCreator interface method
0208   /// - create an array on a plane
0209   ///
0210   /// @param [in] gctx The gometry context for this building call
0211   /// @param [in] surfaces is the vector of pointers to sensitive surfaces
0212   /// to be ordered on the plane
0213   /// @pre the pointers to the sensitive surfaces in the surfaces vectors all
0214   /// need to be valid, since no check is performed
0215   /// @warning This function requires the plane aligned with either the x-, y-
0216   /// or z-axis
0217   /// @param [in] bins1 is the number of bins in the orthogonal direction to @p
0218   /// bValue
0219   /// @param [in] bins2 is the number of bins in the orthogonal direction to @p
0220   /// bValue
0221   /// @param [in] bValue Direction of the aligned surfaces
0222   /// @param [in] protoLayerOpt Optional @c ProtoLayer instance
0223   /// @param [in] transform is the (optional) additional transform applied
0224   ///
0225   /// @return a unique pointer a new SurfaceArray
0226   std::unique_ptr<SurfaceArray> surfaceArrayOnPlane(
0227       const GeometryContext& gctx,
0228       std::vector<std::shared_ptr<const Surface>> surfaces, std::size_t bins1,
0229       std::size_t bins2, BinningValue bValue,
0230       std::optional<ProtoLayer> protoLayerOpt = std::nullopt,
0231       const Transform3& transform = Transform3::Identity()) const;
0232 
0233   /// Static check function for surface equivalent
0234   ///
0235   /// @param [in] gctx the geometry context for this check
0236   /// @param bValue the binning value for the binning
0237   /// @param a first surface for checking
0238   /// @param b second surface for checking
0239   static bool isSurfaceEquivalent(const GeometryContext& gctx,
0240                                   BinningValue bValue, const Surface* a,
0241                                   const Surface* b) {
0242     using namespace UnitLiterals;
0243     using VectorHelpers::perp;
0244 
0245     if (bValue == Acts::BinningValue::binPhi) {
0246       // Take the two binning positions
0247       auto pos1 = a->binningPosition(gctx, BinningValue::binR),
0248            pos2 = b->binningPosition(gctx, BinningValue::binR);
0249 
0250       // Project them on the (x, y) plane, where Phi angles are calculated
0251       auto proj1 = pos1.head<2>(), proj2 = pos2.head<2>();
0252 
0253       // Basic dot and cross products identities give us the cosine and sine
0254       // of these angles, time the squared vector norm
0255       auto cos_dPhi_n2 = proj1.dot(proj2);
0256       auto sin_dPhi_n2 = proj1.x() * proj2.y() - proj2.x() * proj1.y();
0257 
0258       // ...so by injecting them into atan2, we get the angle between them
0259       auto dPhi = std::atan2(sin_dPhi_n2, cos_dPhi_n2);
0260       return std::abs(dPhi) < M_PI / 180.;
0261     }
0262 
0263     if (bValue == Acts::BinningValue::binZ) {
0264       return (std::abs(a->binningPosition(gctx, BinningValue::binR).z() -
0265                        b->binningPosition(gctx, BinningValue::binR).z()) <
0266               1_um);
0267     }
0268 
0269     if (bValue == Acts::BinningValue::binR) {
0270       return (std::abs(perp(a->binningPosition(gctx, BinningValue::binR)) -
0271                        perp(b->binningPosition(gctx, BinningValue::binR))) <
0272               1_um);
0273     }
0274 
0275     return false;
0276   }
0277 
0278   /// Set logging instance
0279   /// @param logger is the logging instance to be set
0280   void setLogger(std::unique_ptr<const Logger> logger) {
0281     m_logger = std::move(logger);
0282   }
0283 
0284  private:
0285   /// configuration object
0286   Config m_cfg;
0287 
0288   /// Private access to logger
0289   const Logger& logger() const { return *m_logger; }
0290 
0291   std::vector<const Surface*> findKeySurfaces(
0292       const std::vector<const Surface*>& surfaces,
0293       const std::function<bool(const Surface*, const Surface*)>& equal) const;
0294 
0295   std::size_t determineBinCount(const GeometryContext& gctx,
0296                                 const std::vector<const Surface*>& surfaces,
0297                                 BinningValue bValue) const;
0298 
0299   /// SurfaceArrayCreator internal method
0300   /// Creates a variable @c ProtoAxis from a vector of (unsorted) surfaces with
0301   /// PlanarBounds
0302   /// It loops through the surfaces and finds out the needed information
0303   /// First the surfaces are sorted in the binning direction and the so called
0304   /// "key" surfaces (surfaces with different positions in the binning
0305   /// direction) are extracted. The boundary value between two surfaces is the
0306   /// mean value of the two center position in the binning direction. The first
0307   /// and the last boundaries are calculated from the vertices of the first and
0308   /// last surface.
0309   /// @note currently implemented for phi, r and z bining
0310   /// @todo implement for x,y binning
0311   /// @param [in] gctx the geometry context for this call
0312   /// @param surfaces are the sensitive surfaces to be
0313   /// @param bValue the BinningValue in which direction should be binned
0314   /// (currently possible: binPhi, binR, binZ)
0315   /// @param protoLayer Instance of @c ProtoLayer holding generic layer info
0316   /// @param transform is the (optional) additional transform applied
0317   /// @return Instance of @c ProtoAxis containing determined properties
0318   /// @note This only creates the @c ProtoAxis, this needs to be turned
0319   ///       into an actual @c Axis object to be used
0320   ProtoAxis createVariableAxis(const GeometryContext& gctx,
0321                                const std::vector<const Surface*>& surfaces,
0322                                BinningValue bValue,
0323                                const ProtoLayer& protoLayer,
0324                                Transform3& transform) const;
0325 
0326   /// SurfaceArrayCreator internal method
0327   /// Creates a equidistant @c ProtoAxis when the extremas and the bin number
0328   /// are
0329   /// It loops through the surfaces and finds out the needed information
0330   /// First the surfaces are sorted in the binning direction and the so called
0331   /// "key" surfaces (surfaces with different positions in the binning
0332   /// direction) are extracted. The number of key surfaces euqals the number of
0333   /// bins. Afterwards the minimum and maximum are calculated by
0334   /// subtracting/adding half of a bin size to the center position (in the
0335   /// binning direction) to the first/last surface.
0336   /// @note currently implemented for phi, r and z bining
0337   /// @todo implement for x,y binning
0338   /// @param [in] gctx the geometry context for this call
0339   /// @param surfaces are the sensitive surfaces to be
0340   /// @param bValue the BinningValue in which direction should be binned
0341   /// (currently possible: binPhi, binR, binZ)
0342   /// @param protoLayer Instance of @c ProtoLayer holding generic layer info
0343   /// @param transform is the (optional) additional transform applied
0344   /// @param nBins Number of bins to use, 0 means determine automatically
0345   /// @return Instance of @c ProtoAxis containing determined properties
0346   /// @note This only creates the @c ProtoAxis, this needs to be turned
0347   ///       into an actual @c Axis object to be used
0348   ProtoAxis createEquidistantAxis(const GeometryContext& gctx,
0349                                   const std::vector<const Surface*>& surfaces,
0350                                   BinningValue bValue,
0351                                   const ProtoLayer& protoLayer,
0352                                   Transform3& transform,
0353                                   std::size_t nBins = 0) const;
0354 
0355   /// SurfaceArrayCreator internal method
0356   /// @brief Creates a SurfaceGridLookup instance within an any
0357   /// This is essentially a factory which absorbs some if/else logic
0358   /// that is required by the templating.
0359   /// @tparam bdtA AxisBoundaryType of axis A
0360   /// @tparam bdtB AxisBoundaryType of axis B
0361   /// @tparam F1 type-deducted value of g2l lambda
0362   /// @tparam F2 type-deducted value of l2g lambda
0363   /// @param globalToLocal transform callable
0364   /// @param localToGlobal transform callable
0365   /// @param pAxisA ProtoAxis object for axis A
0366   /// @param pAxisB ProtoAxis object for axis B
0367   template <AxisBoundaryType bdtA, AxisBoundaryType bdtB, typename F1,
0368             typename F2>
0369   static std::unique_ptr<SurfaceArray::ISurfaceGridLookup>
0370   makeSurfaceGridLookup2D(F1 globalToLocal, F2 localToGlobal, ProtoAxis pAxisA,
0371                           ProtoAxis pAxisB) {
0372     using ISGL = SurfaceArray::ISurfaceGridLookup;
0373     std::unique_ptr<ISGL> ptr;
0374 
0375     // this becomes completely unreadable otherwise
0376     // clang-format off
0377     if (pAxisA.bType == equidistant && pAxisB.bType == equidistant) {
0378 
0379       Axis<AxisType::Equidistant, bdtA> axisA(pAxisA.min, pAxisA.max, pAxisA.nBins);
0380       Axis<AxisType::Equidistant, bdtB> axisB(pAxisB.min, pAxisB.max, pAxisB.nBins);
0381 
0382       using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>;
0383       ptr = std::unique_ptr<ISGL>(static_cast<ISGL*>(
0384             new SGL(globalToLocal, localToGlobal, std::make_tuple(axisA, axisB), {pAxisA.bValue, pAxisB.bValue})));
0385 
0386     } else if (pAxisA.bType == equidistant && pAxisB.bType == arbitrary) {
0387 
0388       Axis<AxisType::Equidistant, bdtA> axisA(pAxisA.min, pAxisA.max, pAxisA.nBins);
0389       Axis<AxisType::Variable, bdtB> axisB(pAxisB.binEdges);
0390 
0391       using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>;
0392       ptr = std::unique_ptr<ISGL>(static_cast<ISGL*>(
0393             new SGL(globalToLocal, localToGlobal, std::make_tuple(axisA, axisB), {pAxisA.bValue, pAxisB.bValue})));
0394 
0395     } else if (pAxisA.bType == arbitrary && pAxisB.bType == equidistant) {
0396 
0397       Axis<AxisType::Variable, bdtA> axisA(pAxisA.binEdges);
0398       Axis<AxisType::Equidistant, bdtB> axisB(pAxisB.min, pAxisB.max, pAxisB.nBins);
0399 
0400       using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>;
0401       ptr = std::unique_ptr<ISGL>(static_cast<ISGL*>(
0402             new SGL(globalToLocal, localToGlobal, std::make_tuple(axisA, axisB), {pAxisA.bValue, pAxisB.bValue})));
0403 
0404     } else /*if (pAxisA.bType == arbitrary && pAxisB.bType == arbitrary)*/ {
0405 
0406       Axis<AxisType::Variable, bdtA> axisA(pAxisA.binEdges);
0407       Axis<AxisType::Variable, bdtB> axisB(pAxisB.binEdges);
0408 
0409       using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>;
0410       ptr = std::unique_ptr<ISGL>(static_cast<ISGL*>(
0411             new SGL(globalToLocal, localToGlobal, std::make_tuple(axisA, axisB), {pAxisA.bValue, pAxisB.bValue})));
0412     }
0413     // clang-format on
0414 
0415     return ptr;
0416   }
0417 
0418   /// logging instance
0419   std::unique_ptr<const Logger> m_logger;
0420 
0421   /// Private helper method to complete the binning
0422   ///
0423   ///
0424   ///  given a grid point o
0425   ///    |  0  |  1 |  2  |  3 |  4  |
0426   ///    ------------------------------
0427   ///  0 |  x  |    |     |    |  x  |
0428   ///  1 |     |    |  o  |    |     |
0429   ///  2 |  x  |    |     |    |  x  |
0430   ///
0431   /// This is being called when you chose to use more bins thans surfaces
0432   /// I.e. to put a finer granularity binning onto your surface
0433   /// Neighbour bins are then filled to contain pointers as well
0434   /// This method delegates to SurfaceGridLookup itself.
0435   /// @param [in] gctx the geometry context for this call
0436   /// @param sl The @c SurfaceGridLookup
0437   /// @param surfaces the surfaces
0438   void completeBinning(const GeometryContext& gctx,
0439                        SurfaceArray::ISurfaceGridLookup& sl,
0440                        const std::vector<const Surface*>& surfaces) const {
0441     ACTS_VERBOSE(
0442         "Complete binning by filling closest neighbour surfaces into "
0443         "empty bins.");
0444 
0445     std::size_t binCompleted = sl.completeBinning(gctx, surfaces);
0446 
0447     ACTS_VERBOSE("       filled  : " << binCompleted
0448                                      << " (includes under/overflow)");
0449   }
0450 
0451   /// Private helper method to transform the  vertices of surface bounds into
0452   /// global coordinates
0453   /// @param [in] gctx the geometry context for this call
0454   /// @param surface the surface associated with the given vertices
0455   /// @param locVertices a vector of the vertices in local coordinates
0456   /// @return a vector of the vertices in global coordinates
0457   std::vector<Acts::Vector3> makeGlobalVertices(
0458       const GeometryContext& gctx, const Acts::Surface& surface,
0459       const std::vector<Acts::Vector2>& locVertices) const;
0460 };
0461 
0462 }  // namespace Acts