Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-09 08:04:11

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2017-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 #include "Acts/Definitions/Algebra.hpp"
0011 #include "Acts/Geometry/GeometryContext.hpp"
0012 #include "Acts/Surfaces/Surface.hpp"
0013 #include "Acts/Utilities/Axis.hpp"
0014 #include "Acts/Utilities/BinningType.hpp"
0015 #include "Acts/Utilities/Grid.hpp"
0016 #include "Acts/Utilities/IAxis.hpp"
0017 
0018 #include <iostream>
0019 #include <type_traits>
0020 #include <vector>
0021 
0022 namespace Acts {
0023 
0024 using SurfaceVector = std::vector<const Surface*>;
0025 
0026 /// @brief Provides Surface binning in N dimensions
0027 ///
0028 /// Uses @c Grid under the hood to implement the storage and lookup
0029 /// Contains a lookup struct which talks to the @c Grid
0030 /// and performs utility actions. This struct needs to be initialised
0031 /// externally and passed to @c SurfaceArray on construction.
0032 class SurfaceArray {
0033  public:
0034   /// @brief Base interface for all surface lookups.
0035   struct ISurfaceGridLookup {
0036     /// @brief Fill provided surfaces into the contained @c Grid.
0037     /// @param gctx The current geometry context object, e.g. alignment
0038 
0039     /// @param surfaces Input surface pointers
0040     virtual void fill(const GeometryContext& gctx,
0041                       const SurfaceVector& surfaces) = 0;
0042 
0043     /// @brief Attempts to fix sub-optimal binning by filling closest
0044     ///        Surfaces into empty bin
0045     ///
0046     /// @param gctx The current geometry context object, e.g. alignment
0047 
0048     /// @param surfaces The surface pointers to fill
0049     /// @return number of bins that were filled
0050     virtual std::size_t completeBinning(const GeometryContext& gctx,
0051                                         const SurfaceVector& surfaces) = 0;
0052 
0053     /// @brief Performs lookup at @c pos and returns bin content as reference
0054     /// @param position Lookup position
0055     /// @return @c SurfaceVector at given bin
0056     virtual SurfaceVector& lookup(const Vector3& position) = 0;
0057 
0058     /// @brief Performs lookup at @c pos and returns bin content as const
0059     /// reference
0060     /// @param position Lookup position
0061     /// @return @c SurfaceVector at given bin
0062     virtual const SurfaceVector& lookup(const Vector3& position) const = 0;
0063 
0064     /// @brief Performs lookup at global bin and returns bin content as
0065     /// reference
0066     /// @param bin Global lookup bin
0067     /// @return @c SurfaceVector at given bin
0068     virtual SurfaceVector& lookup(std::size_t bin) = 0;
0069 
0070     /// @brief Performs lookup at global bin and returns bin content as const
0071     /// reference
0072     /// @param bin Global lookup bin
0073     /// @return @c SurfaceVector at given bin
0074     virtual const SurfaceVector& lookup(std::size_t bin) const = 0;
0075 
0076     /// @brief Performs a lookup at @c pos, but returns neighbors as well
0077     ///
0078     /// @param position Lookup position
0079     /// @return @c SurfaceVector at given bin. Copy of all bins selected
0080     virtual const SurfaceVector& neighbors(const Vector3& position) const = 0;
0081 
0082     /// @brief Returns the total size of the grid (including under/overflow
0083     /// bins)
0084     /// @return Size of the grid data structure
0085     virtual std::size_t size() const = 0;
0086 
0087     /// @brief Gets the center position of bin @c bin in global coordinates
0088     /// @param bin the global bin index
0089     /// @return The bin center
0090     virtual Vector3 getBinCenter(std::size_t bin) const = 0;
0091 
0092     /// @brief Returns copies of the axes used in the grid as @c AnyAxis
0093     /// @return The axes
0094     /// @note This returns copies. Use for introspection and querying.
0095     virtual std::vector<const IAxis*> getAxes() const = 0;
0096 
0097     /// @brief Get the number of dimensions of the grid.
0098     /// @return number of dimensions
0099     virtual std::size_t dimensions() const = 0;
0100 
0101     /// @brief Checks if global bin is valid
0102     /// @param bin the global bin index
0103     /// @return bool if the bin is valid
0104     /// @note Valid means that the index points to a bin which is not a under
0105     ///       or overflow bin or out of range in any axis.
0106     virtual bool isValidBin(std::size_t bin) const = 0;
0107 
0108     /// @brief The binning values described by this surface grid lookup
0109     /// They are in order of the axes (optional) and empty for eingle lookups
0110     virtual std::vector<BinningValue> binningValues() const { return {}; };
0111 
0112     /// Pure virtual destructor
0113     virtual ~ISurfaceGridLookup() = 0;
0114   };
0115 
0116   /// @brief Lookup helper which encapsulates a @c Grid
0117   /// @tparam Axes The axes used for the grid
0118   template <class... Axes>
0119   struct SurfaceGridLookup : ISurfaceGridLookup {
0120     static constexpr std::size_t DIM = sizeof...(Axes);
0121 
0122    public:
0123     /// @brief Specifies the local coordinate type.
0124     /// This resolves to @c ActsVector<DIM> for DIM > 1, else @c
0125     /// std::array<double, 1>
0126     using point_t =
0127         std::conditional_t<DIM == 1, std::array<double, 1>, ActsVector<DIM>>;
0128     using Grid_t = Grid<SurfaceVector, Axes...>;
0129 
0130     /// @brief Default constructor
0131     ///
0132     /// @param globalToLocal Callable that converts from global to local
0133     /// @param localToGlobal Callable that converts from local to global
0134     /// @param axes The axes to build the grid data structure.
0135     /// @param bValues What the axes represent (optional)
0136     /// @note Signature of localToGlobal and globalToLocal depends on @c DIM.
0137     ///       If DIM > 1, local coords are @c ActsVector<DIM> else
0138     ///       @c std::array<double, 1>.
0139     SurfaceGridLookup(std::function<point_t(const Vector3&)> globalToLocal,
0140                       std::function<Vector3(const point_t&)> localToGlobal,
0141                       std::tuple<Axes...> axes,
0142                       std::vector<BinningValue> bValues = {})
0143         : m_globalToLocal(std::move(globalToLocal)),
0144           m_localToGlobal(std::move(localToGlobal)),
0145           m_grid(std::move(axes)),
0146           m_binValues(std::move(bValues)) {
0147       m_neighborMap.resize(m_grid.size());
0148     }
0149 
0150     /// @brief Fill provided surfaces into the contained @c Grid.
0151     ///
0152     /// This is done by iterating, accessing the binningPosition, lookup
0153     /// and append.
0154     /// Also populates the neighbor map by combining the filled bins of
0155     /// all bins around a given one.
0156     ///
0157     /// @param gctx The current geometry context object, e.g. alignment
0158     /// @param surfaces Input surface pointers
0159     void fill(const GeometryContext& gctx,
0160               const SurfaceVector& surfaces) override {
0161       for (const auto& srf : surfaces) {
0162         Vector3 pos = srf->binningPosition(gctx, BinningValue::binR);
0163         lookup(pos).push_back(srf);
0164       }
0165 
0166       populateNeighborCache();
0167     }
0168 
0169     /// @brief Attempts to fix sub-optimal binning by filling closest
0170     ///        Surfaces into empty bins
0171     /// @note This does not always do what you want.
0172     ///
0173     /// @param gctx The current geometry context object, e.g. alignment
0174     /// @param surfaces The surface pointers to fill
0175     /// @return number of bins that were filled
0176     std::size_t completeBinning(const GeometryContext& gctx,
0177                                 const SurfaceVector& surfaces) override {
0178       std::size_t binCompleted = 0;
0179       std::size_t nBins = size();
0180       double minPath = 0;
0181       double curPath = 0;
0182       const Surface* minSrf = nullptr;
0183 
0184       for (std::size_t b = 0; b < nBins; ++b) {
0185         if (!isValidBin(b)) {
0186           continue;
0187         }
0188         std::vector<const Surface*>& binContent = lookup(b);
0189         // only complete if we have an empty bin
0190         if (!binContent.empty()) {
0191           continue;
0192         }
0193 
0194         Vector3 binCtr = getBinCenter(b);
0195         minPath = std::numeric_limits<double>::max();
0196         for (const auto& srf : surfaces) {
0197           curPath =
0198               (binCtr - srf->binningPosition(gctx, BinningValue::binR)).norm();
0199 
0200           if (curPath < minPath) {
0201             minPath = curPath;
0202             minSrf = srf;
0203           }
0204         }
0205 
0206         binContent.push_back(minSrf);
0207         ++binCompleted;
0208       }
0209 
0210       // recreate neighborcache
0211       populateNeighborCache();
0212       return binCompleted;
0213     }
0214 
0215     /// @brief Performs lookup at @c pos and returns bin content as reference
0216     /// @param position Lookup position
0217     /// @return @c SurfaceVector at given bin
0218     SurfaceVector& lookup(const Vector3& position) override {
0219       return m_grid.atPosition(m_globalToLocal(position));
0220     }
0221 
0222     /// @brief Performs lookup at @c pos and returns bin content as const
0223     /// reference
0224     /// @param position Lookup position
0225     /// @return @c SurfaceVector at given bin
0226     const SurfaceVector& lookup(const Vector3& position) const override {
0227       return m_grid.atPosition(m_globalToLocal(position));
0228     }
0229 
0230     /// @brief Performs lookup at global bin and returns bin content as
0231     /// reference
0232     /// @param bin Global lookup bin
0233     /// @return @c SurfaceVector at given bin
0234     SurfaceVector& lookup(std::size_t bin) override { return m_grid.at(bin); }
0235 
0236     /// @brief Performs lookup at global bin and returns bin content as const
0237     /// reference
0238     /// @param bin Global lookup bin
0239     /// @return @c SurfaceVector at given bin
0240     const SurfaceVector& lookup(std::size_t bin) const override {
0241       return m_grid.at(bin);
0242     }
0243 
0244     /// @brief Performs a lookup at @c pos, but returns neighbors as well
0245     ///
0246     /// @param position Lookup position
0247     /// @return @c SurfaceVector at given bin. Copy of all bins selected
0248     const SurfaceVector& neighbors(const Vector3& position) const override {
0249       auto lposition = m_globalToLocal(position);
0250       return m_neighborMap.at(m_grid.globalBinFromPosition(lposition));
0251     }
0252 
0253     /// @brief Returns the total size of the grid (including under/overflow
0254     /// bins)
0255     /// @return Size of the grid data structure
0256     std::size_t size() const override { return m_grid.size(); }
0257 
0258     /// @brief The binning values described by this surface grid lookup
0259     /// They are in order of the axes
0260     std::vector<BinningValue> binningValues() const override {
0261       return m_binValues;
0262     }
0263 
0264     /// @brief Gets the center position of bin @c bin in global coordinates
0265     /// @param bin the global bin index
0266     /// @return The bin center
0267     Vector3 getBinCenter(std::size_t bin) const override {
0268       return getBinCenterImpl(bin);
0269     }
0270 
0271     /// @brief Returns copies of the axes used in the grid as @c AnyAxis
0272     /// @return The axes
0273     /// @note This returns copies. Use for introspection and querying.
0274     std::vector<const IAxis*> getAxes() const override {
0275       auto arr = m_grid.axes();
0276       return std::vector<const IAxis*>(arr.begin(), arr.end());
0277     }
0278 
0279     /// @brief Get the number of dimensions of the grid.
0280     /// @return number of dimensions
0281     std::size_t dimensions() const override { return DIM; }
0282 
0283     /// @brief Checks if global bin is valid
0284     /// @param bin the global bin index
0285     /// @return bool if the bin is valid
0286     /// @note Valid means that the index points to a bin which is not a under
0287     ///       or overflow bin or out of range in any axis.
0288     bool isValidBin(std::size_t bin) const override {
0289       std::array<std::size_t, DIM> indices = m_grid.localBinsFromGlobalBin(bin);
0290       std::array<std::size_t, DIM> nBins = m_grid.numLocalBins();
0291       for (std::size_t i = 0; i < indices.size(); ++i) {
0292         std::size_t idx = indices.at(i);
0293         if (idx <= 0 || idx >= nBins.at(i) + 1) {
0294           return false;
0295         }
0296       }
0297 
0298       return true;
0299     }
0300 
0301    private:
0302     void populateNeighborCache() {
0303       // calculate neighbors for every bin and store in map
0304       for (std::size_t i = 0; i < m_grid.size(); i++) {
0305         if (!isValidBin(i)) {
0306           continue;
0307         }
0308         typename Grid_t::index_t loc = m_grid.localBinsFromGlobalBin(i);
0309         auto neighborIdxs = m_grid.neighborHoodIndices(loc, 1u);
0310         std::vector<const Surface*>& neighbors = m_neighborMap.at(i);
0311         neighbors.clear();
0312 
0313         for (const auto idx : neighborIdxs) {
0314           const std::vector<const Surface*>& binContent = m_grid.at(idx);
0315           std::copy(binContent.begin(), binContent.end(),
0316                     std::back_inserter(neighbors));
0317         }
0318       }
0319     }
0320 
0321     /// Internal method.
0322     /// This is here, because apparently Eigen doesn't like Vector1.
0323     /// So SurfaceGridLookup internally uses std::array<double, 1> instead
0324     /// of Vector1 (see the point_t typedef). This needs to be switched here,
0325     /// so as not to
0326     /// attempt an initialization of Vector1 that Eigen will complain about.
0327     /// The SFINAE is hidden in this private method so the public
0328     /// interface stays the same, since we don't care what happens
0329     /// here on the callers end
0330     /// This is the version for DIM>1
0331     Vector3 getBinCenterImpl(std::size_t bin) const
0332       requires(DIM != 1)
0333     {
0334       return m_localToGlobal(ActsVector<DIM>(
0335           m_grid.binCenter(m_grid.localBinsFromGlobalBin(bin)).data()));
0336     }
0337 
0338     /// Internal method, see above.
0339     /// This is the version for DIM==1
0340     Vector3 getBinCenterImpl(std::size_t bin) const
0341       requires(DIM == 1)
0342     {
0343       point_t pos = m_grid.binCenter(m_grid.localBinsFromGlobalBin(bin));
0344       return m_localToGlobal(pos);
0345     }
0346 
0347     std::function<point_t(const Vector3&)> m_globalToLocal;
0348     std::function<Vector3(const point_t&)> m_localToGlobal;
0349     Grid_t m_grid;
0350     std::vector<BinningValue> m_binValues;
0351     std::vector<SurfaceVector> m_neighborMap;
0352   };
0353 
0354   /// @brief Lookup implementation which wraps one element and always returns
0355   ///        this element when lookup is called
0356   struct SingleElementLookup : ISurfaceGridLookup {
0357     /// @brief Default constructor.
0358     /// @param element the one and only element.
0359     SingleElementLookup(SurfaceVector::value_type element)
0360         : m_element({element}) {}
0361 
0362     /// @brief Default constructor.
0363     /// @param elements the surfaces that are provided through a single lookup
0364     SingleElementLookup(const SurfaceVector& elements) : m_element(elements) {}
0365 
0366     /// @brief Lookup, always returns @c element
0367     /// @return reference to vector containing only @c element
0368     SurfaceVector& lookup(const Vector3& /*position*/) override {
0369       return m_element;
0370     }
0371 
0372     /// @brief Lookup, always returns @c element
0373     /// @return reference to vector containing only @c element
0374     const SurfaceVector& lookup(const Vector3& /*position*/) const override {
0375       return m_element;
0376     }
0377 
0378     /// @brief Lookup, always returns @c element
0379     /// @return reference to vector containing only @c element
0380     SurfaceVector& lookup(std::size_t /*bin*/) override { return m_element; }
0381 
0382     /// @brief Lookup, always returns @c element
0383     /// @return reference to vector containing only @c element
0384     const SurfaceVector& lookup(std::size_t /*bin*/) const override {
0385       return m_element;
0386     }
0387 
0388     /// @brief Lookup, always returns @c element
0389     /// @return reference to vector containing only @c element
0390     const SurfaceVector& neighbors(const Vector3& /*position*/) const override {
0391       return m_element;
0392     }
0393 
0394     /// @brief returns 1
0395     /// @return 1
0396     std::size_t size() const override { return 1; }
0397 
0398     /// @brief Gets the bin center, but always returns (0, 0, 0)
0399     /// @return (0, 0, 0)
0400     Vector3 getBinCenter(std::size_t /*bin*/) const override {
0401       return Vector3(0, 0, 0);
0402     }
0403 
0404     /// @brief Returns an empty vector of @c AnyAxis
0405     /// @return empty vector
0406     std::vector<const IAxis*> getAxes() const override { return {}; }
0407 
0408     /// @brief Get the number of dimensions
0409     /// @return always 0
0410     std::size_t dimensions() const override { return 0; }
0411 
0412     /// @brief Comply with concept and provide fill method
0413     /// @note Does nothing
0414     void fill(const GeometryContext& /*gctx*/,
0415               const SurfaceVector& /*surfaces*/) override {}
0416 
0417     /// @brief Comply with concept and provide completeBinning method
0418     /// @note Does nothing
0419     std::size_t completeBinning(const GeometryContext& /*gctx*/,
0420                                 const SurfaceVector& /*surfaces*/) override {
0421       return 0;
0422     }
0423 
0424     /// @brief Returns if the bin is valid (it is)
0425     /// @return always true
0426     bool isValidBin(std::size_t /*bin*/) const override { return true; }
0427 
0428    private:
0429     SurfaceVector m_element;
0430   };
0431 
0432   /// @brief Default constructor which takes a @c SurfaceLookup and a vector of
0433   /// surfaces
0434   /// @param gridLookup The grid storage. @c SurfaceArray does not fill it on
0435   /// its own
0436   /// @param surfaces The input vector of surfaces. This is only for
0437   /// bookkeeping, so we can ask
0438   /// @param transform Optional additional transform for this SurfaceArray
0439   SurfaceArray(std::unique_ptr<ISurfaceGridLookup> gridLookup,
0440                std::vector<std::shared_ptr<const Surface>> surfaces,
0441                const Transform3& transform = Transform3::Identity());
0442 
0443   /// @brief Constructor with a single surface
0444   /// @param srf The one and only surface
0445   SurfaceArray(std::shared_ptr<const Surface> srf);
0446 
0447   /// @brief Get all surfaces in bin given by position.
0448   /// @param position the lookup position
0449   /// @return reference to @c SurfaceVector contained in bin at that position
0450   SurfaceVector& at(const Vector3& position) {
0451     return p_gridLookup->lookup(position);
0452   }
0453 
0454   /// @brief Get all surfaces in bin given by position @p pos.
0455   /// @param position the lookup position
0456   /// @return const reference to @c SurfaceVector contained in bin at that
0457   /// position
0458   const SurfaceVector& at(const Vector3& position) const {
0459     return p_gridLookup->lookup(position);
0460   }
0461 
0462   /// @brief Get all surfaces in bin given by global bin index @p bin.
0463   /// @param bin the global bin index
0464   /// @return reference to @c SurfaceVector contained in bin
0465   SurfaceVector& at(std::size_t bin) { return p_gridLookup->lookup(bin); }
0466 
0467   /// @brief Get all surfaces in bin given by global bin index.
0468   /// @param bin the global bin index
0469   /// @return const reference to @c SurfaceVector contained in bin
0470   const SurfaceVector& at(std::size_t bin) const {
0471     return p_gridLookup->lookup(bin);
0472   }
0473 
0474   /// @brief Get all surfaces in bin at @p pos and its neighbors
0475   /// @param position The position to lookup as nominal
0476   /// @return Merged @c SurfaceVector of neighbors and nominal
0477   /// @note The @c SurfaceVector will be combined. For technical reasons, the
0478   ///       different bin content vectors have to be copied, so the resulting
0479   ///       vector contains copies.
0480   const SurfaceVector& neighbors(const Vector3& position) const {
0481     return p_gridLookup->neighbors(position);
0482   }
0483 
0484   /// @brief Get the size of the underlying grid structure including
0485   /// under/overflow bins
0486   /// @return the size
0487   std::size_t size() const { return p_gridLookup->size(); }
0488 
0489   /// @brief Get the center of the bin identified by global bin index @p bin
0490   /// @param bin the global bin index
0491   /// @return Center position of the bin in global coordinates
0492   Vector3 getBinCenter(std::size_t bin) {
0493     return p_gridLookup->getBinCenter(bin);
0494   }
0495 
0496   /// @brief Get all surfaces attached to this @c SurfaceArray
0497   /// @return Reference to @c SurfaceVector containing all surfaces
0498   /// @note This does not reflect the actual state of the grid. It only
0499   ///       returns what was given in the constructor, without any checks
0500   ///       if that is actually what's in the grid.
0501   const SurfaceVector& surfaces() const { return m_surfacesRawPointers; }
0502 
0503   /// @brief Get vector of axes spanning the grid as @c AnyAxis
0504   /// @return vector of @c AnyAxis
0505   /// @note The axes in the vector are copies. Only use for introspection and
0506   ///       querying.
0507   std::vector<const IAxis*> getAxes() const { return p_gridLookup->getAxes(); }
0508 
0509   /// @brief Checks if global bin is valid
0510   /// @param bin the global bin index
0511   /// @return bool if the bin is valid
0512   /// @note Valid means that the index points to a bin which is not a under
0513   ///       or overflow bin or out of range in any axis.
0514   bool isValidBin(std::size_t bin) const {
0515     return p_gridLookup->isValidBin(bin);
0516   }
0517 
0518   const Transform3& transform() const { return m_transform; }
0519 
0520   /// @brief The binning values described by this surface grid lookup
0521   /// They are in order of the axes
0522   std::vector<BinningValue> binningValues() const {
0523     return p_gridLookup->binningValues();
0524   };
0525 
0526   /// @brief String representation of this @c SurfaceArray
0527   /// @param gctx The current geometry context object, e.g. alignment
0528   /// @param sl Output stream to write to
0529   /// @return the output stream given as @p sl
0530   std::ostream& toStream(const GeometryContext& gctx, std::ostream& sl) const;
0531 
0532  private:
0533   std::unique_ptr<ISurfaceGridLookup> p_gridLookup;
0534   // this vector makes sure we have shared ownership over the surfaces
0535   std::vector<std::shared_ptr<const Surface>> m_surfaces;
0536   // this vector is returned, so that (expensive) copying of the shared_ptr
0537   // vector does not happen by default
0538   SurfaceVector m_surfacesRawPointers;
0539   // this is only used to keep info on transform applied
0540   // by l2g and g2l
0541   Transform3 m_transform;
0542 };
0543 
0544 }  // namespace Acts