Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-19 09:23:23

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/BinningType.hpp"
0018 #include "Acts/Utilities/Logger.hpp"
0019 #include "Acts/Utilities/detail/AxisFwd.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::binPhi) {
0246       // Take the two binning positions
0247       auto pos1 = a->binningPosition(gctx, binR),
0248            pos2 = b->binningPosition(gctx, 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::binZ) {
0264       return (std::abs(a->binningPosition(gctx, binR).z() -
0265                        b->binningPosition(gctx, binR).z()) < 1_um);
0266     }
0267 
0268     if (bValue == Acts::binR) {
0269       return (std::abs(perp(a->binningPosition(gctx, binR)) -
0270                        perp(b->binningPosition(gctx, binR))) < 1_um);
0271     }
0272 
0273     return false;
0274   }
0275 
0276   /// Set logging instance
0277   /// @param logger is the logging instance to be set
0278   void setLogger(std::unique_ptr<const Logger> logger) {
0279     m_logger = std::move(logger);
0280   }
0281 
0282  private:
0283   /// configuration object
0284   Config m_cfg;
0285 
0286   /// Private access to logger
0287   const Logger& logger() const { return *m_logger; }
0288 
0289   std::vector<const Surface*> findKeySurfaces(
0290       const std::vector<const Surface*>& surfaces,
0291       const std::function<bool(const Surface*, const Surface*)>& equal) const;
0292 
0293   std::size_t determineBinCount(const GeometryContext& gctx,
0294                                 const std::vector<const Surface*>& surfaces,
0295                                 BinningValue bValue) const;
0296 
0297   /// SurfaceArrayCreator internal method
0298   /// Creates a variable @c ProtoAxis from a vector of (unsorted) surfaces with
0299   /// PlanarBounds
0300   /// It loops through the surfaces and finds out the needed information
0301   /// First the surfaces are sorted in the binning direction and the so called
0302   /// "key" surfaces (surfaces with different positions in the binning
0303   /// direction) are extracted. The boundary value between two surfaces is the
0304   /// mean value of the two center position in the binning direction. The first
0305   /// and the last boundaries are calculated from the vertices of the first and
0306   /// last surface.
0307   /// @note currently implemented for phi, r and z bining
0308   /// @todo implement for x,y binning
0309   /// @param [in] gctx the geometry context for this call
0310   /// @param surfaces are the sensitive surfaces to be
0311   /// @param bValue the BinningValue in which direction should be binned
0312   /// (currently possible: binPhi, binR, binZ)
0313   /// @param protoLayer Instance of @c ProtoLayer holding generic layer info
0314   /// @param transform is the (optional) additional transform applied
0315   /// @return Instance of @c ProtoAxis containing determined properties
0316   /// @note This only creates the @c ProtoAxis, this needs to be turned
0317   ///       into an actual @c Axis object to be used
0318   ProtoAxis createVariableAxis(const GeometryContext& gctx,
0319                                const std::vector<const Surface*>& surfaces,
0320                                BinningValue bValue,
0321                                const ProtoLayer& protoLayer,
0322                                Transform3& transform) const;
0323 
0324   /// SurfaceArrayCreator internal method
0325   /// Creates a equidistant @c ProtoAxis when the extremas and the bin number
0326   /// are
0327   /// It loops through the surfaces and finds out the needed information
0328   /// First the surfaces are sorted in the binning direction and the so called
0329   /// "key" surfaces (surfaces with different positions in the binning
0330   /// direction) are extracted. The number of key surfaces euqals the number of
0331   /// bins. Afterwards the minimum and maximum are calculated by
0332   /// subtracting/adding half of a bin size to the center position (in the
0333   /// binning direction) to the first/last surface.
0334   /// @note currently implemented for phi, r and z bining
0335   /// @todo implement for x,y binning
0336   /// @param [in] gctx the geometry context for this call
0337   /// @param surfaces are the sensitive surfaces to be
0338   /// @param bValue the BinningValue in which direction should be binned
0339   /// (currently possible: binPhi, binR, binZ)
0340   /// @param protoLayer Instance of @c ProtoLayer holding generic layer info
0341   /// @param transform is the (optional) additional transform applied
0342   /// @param nBins Number of bins to use, 0 means determine automatically
0343   /// @return Instance of @c ProtoAxis containing determined properties
0344   /// @note This only creates the @c ProtoAxis, this needs to be turned
0345   ///       into an actual @c Axis object to be used
0346   ProtoAxis createEquidistantAxis(const GeometryContext& gctx,
0347                                   const std::vector<const Surface*>& surfaces,
0348                                   BinningValue bValue,
0349                                   const ProtoLayer& protoLayer,
0350                                   Transform3& transform,
0351                                   std::size_t nBins = 0) const;
0352 
0353   /// SurfaceArrayCreator internal method
0354   /// @brief Creates a SurfaceGridLookup instance within an any
0355   /// This is essentially a factory which absorbs some if/else logic
0356   /// that is required by the templating.
0357   /// @tparam bdtA AxisBoundaryType of axis A
0358   /// @tparam bdtB AxisBoundaryType of axis B
0359   /// @tparam F1 type-deducted value of g2l lambda
0360   /// @tparam F2 type-deducted value of l2g lambda
0361   /// @param globalToLocal transform callable
0362   /// @param localToGlobal transform callable
0363   /// @param pAxisA ProtoAxis object for axis A
0364   /// @param pAxisB ProtoAxis object for axis B
0365   template <detail::AxisBoundaryType bdtA, detail::AxisBoundaryType bdtB,
0366             typename F1, typename F2>
0367   static std::unique_ptr<SurfaceArray::ISurfaceGridLookup>
0368   makeSurfaceGridLookup2D(F1 globalToLocal, F2 localToGlobal, ProtoAxis pAxisA,
0369                           ProtoAxis pAxisB) {
0370     using ISGL = SurfaceArray::ISurfaceGridLookup;
0371     std::unique_ptr<ISGL> ptr;
0372 
0373     // this becomes completely unreadable otherwise
0374     // clang-format off
0375     if (pAxisA.bType == equidistant && pAxisB.bType == equidistant) {
0376 
0377       detail::Axis<detail::AxisType::Equidistant, bdtA> axisA(pAxisA.min, pAxisA.max, pAxisA.nBins);
0378       detail::Axis<detail::AxisType::Equidistant, bdtB> axisB(pAxisB.min, pAxisB.max, pAxisB.nBins);
0379 
0380       using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>;
0381       ptr = std::unique_ptr<ISGL>(static_cast<ISGL*>(
0382             new SGL(globalToLocal, localToGlobal, std::make_tuple(axisA, axisB), {pAxisA.bValue, pAxisB.bValue})));
0383 
0384     } else if (pAxisA.bType == equidistant && pAxisB.bType == arbitrary) {
0385 
0386       detail::Axis<detail::AxisType::Equidistant, bdtA> axisA(pAxisA.min, pAxisA.max, pAxisA.nBins);
0387       detail::Axis<detail::AxisType::Variable, bdtB> axisB(pAxisB.binEdges);
0388 
0389       using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>;
0390       ptr = std::unique_ptr<ISGL>(static_cast<ISGL*>(
0391             new SGL(globalToLocal, localToGlobal, std::make_tuple(axisA, axisB), {pAxisA.bValue, pAxisB.bValue})));
0392 
0393     } else if (pAxisA.bType == arbitrary && pAxisB.bType == equidistant) {
0394 
0395       detail::Axis<detail::AxisType::Variable, bdtA> axisA(pAxisA.binEdges);
0396       detail::Axis<detail::AxisType::Equidistant, bdtB> axisB(pAxisB.min, pAxisB.max, pAxisB.nBins);
0397 
0398       using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>;
0399       ptr = std::unique_ptr<ISGL>(static_cast<ISGL*>(
0400             new SGL(globalToLocal, localToGlobal, std::make_tuple(axisA, axisB), {pAxisA.bValue, pAxisB.bValue})));
0401 
0402     } else /*if (pAxisA.bType == arbitrary && pAxisB.bType == arbitrary)*/ {
0403 
0404       detail::Axis<detail::AxisType::Variable, bdtA> axisA(pAxisA.binEdges);
0405       detail::Axis<detail::AxisType::Variable, bdtB> axisB(pAxisB.binEdges);
0406 
0407       using SGL = SurfaceArray::SurfaceGridLookup<decltype(axisA), decltype(axisB)>;
0408       ptr = std::unique_ptr<ISGL>(static_cast<ISGL*>(
0409             new SGL(globalToLocal, localToGlobal, std::make_tuple(axisA, axisB), {pAxisA.bValue, pAxisB.bValue})));
0410     }
0411     // clang-format on
0412 
0413     return ptr;
0414   }
0415 
0416   /// logging instance
0417   std::unique_ptr<const Logger> m_logger;
0418 
0419   /// Private helper method to complete the binning
0420   ///
0421   ///
0422   ///  given a grid point o
0423   ///    |  0  |  1 |  2  |  3 |  4  |
0424   ///    ------------------------------
0425   ///  0 |  x  |    |     |    |  x  |
0426   ///  1 |     |    |  o  |    |     |
0427   ///  2 |  x  |    |     |    |  x  |
0428   ///
0429   /// This is being called when you chose to use more bins thans surfaces
0430   /// I.e. to put a finer granularity binning onto your surface
0431   /// Neighbour bins are then filled to contain pointers as well
0432   /// This method delegates to SurfaceGridLookup itself.
0433   /// @param [in] gctx the geometry context for this call
0434   /// @param sl The @c SurfaceGridLookup
0435   /// @param surfaces the surfaces
0436   void completeBinning(const GeometryContext& gctx,
0437                        SurfaceArray::ISurfaceGridLookup& sl,
0438                        const std::vector<const Surface*>& surfaces) const {
0439     ACTS_VERBOSE(
0440         "Complete binning by filling closest neighbour surfaces into "
0441         "empty bins.");
0442 
0443     std::size_t binCompleted = sl.completeBinning(gctx, surfaces);
0444 
0445     ACTS_VERBOSE("       filled  : " << binCompleted
0446                                      << " (includes under/overflow)");
0447   }
0448 
0449   /// Private helper method to transform the  vertices of surface bounds into
0450   /// global coordinates
0451   /// @param [in] gctx the geometry context for this call
0452   /// @param surface the surface associated with the given vertices
0453   /// @param locVertices a vector of the vertices in local coordinates
0454   /// @return a vector of the vertices in global coordinates
0455   std::vector<Acts::Vector3> makeGlobalVertices(
0456       const GeometryContext& gctx, const Acts::Surface& surface,
0457       const std::vector<Acts::Vector2>& locVertices) const;
0458 };
0459 
0460 }  // namespace Acts