Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/Acts/Surfaces/SurfaceArray.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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/BinningType.hpp"
0014 #include "Acts/Utilities/Grid.hpp"
0015 #include "Acts/Utilities/IAxis.hpp"
0016 #include "Acts/Utilities/detail/Axis.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, 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 = (binCtr - srf->binningPosition(gctx, binR)).norm();
0198 
0199           if (curPath < minPath) {
0200             minPath = curPath;
0201             minSrf = srf;
0202           }
0203         }
0204 
0205         binContent.push_back(minSrf);
0206         ++binCompleted;
0207       }
0208 
0209       // recreate neighborcache
0210       populateNeighborCache();
0211       return binCompleted;
0212     }
0213 
0214     /// @brief Performs lookup at @c pos and returns bin content as reference
0215     /// @param position Lookup position
0216     /// @return @c SurfaceVector at given bin
0217     SurfaceVector& lookup(const Vector3& position) override {
0218       return m_grid.atPosition(m_globalToLocal(position));
0219     }
0220 
0221     /// @brief Performs lookup at @c pos and returns bin content as const
0222     /// reference
0223     /// @param position Lookup position
0224     /// @return @c SurfaceVector at given bin
0225     const SurfaceVector& lookup(const Vector3& position) const override {
0226       return m_grid.atPosition(m_globalToLocal(position));
0227     }
0228 
0229     /// @brief Performs lookup at global bin and returns bin content as
0230     /// reference
0231     /// @param bin Global lookup bin
0232     /// @return @c SurfaceVector at given bin
0233     SurfaceVector& lookup(std::size_t bin) override { return m_grid.at(bin); }
0234 
0235     /// @brief Performs lookup at global bin and returns bin content as const
0236     /// reference
0237     /// @param bin Global lookup bin
0238     /// @return @c SurfaceVector at given bin
0239     const SurfaceVector& lookup(std::size_t bin) const override {
0240       return m_grid.at(bin);
0241     }
0242 
0243     /// @brief Performs a lookup at @c pos, but returns neighbors as well
0244     ///
0245     /// @param position Lookup position
0246     /// @return @c SurfaceVector at given bin. Copy of all bins selected
0247     const SurfaceVector& neighbors(const Vector3& position) const override {
0248       auto lposition = m_globalToLocal(position);
0249       return m_neighborMap.at(m_grid.globalBinFromPosition(lposition));
0250     }
0251 
0252     /// @brief Returns the total size of the grid (including under/overflow
0253     /// bins)
0254     /// @return Size of the grid data structure
0255     std::size_t size() const override { return m_grid.size(); }
0256 
0257     /// @brief The binning values described by this surface grid lookup
0258     /// They are in order of the axes
0259     std::vector<BinningValue> binningValues() const override {
0260       return m_binValues;
0261     }
0262 
0263     /// @brief Gets the center position of bin @c bin in global coordinates
0264     /// @param bin the global bin index
0265     /// @return The bin center
0266     Vector3 getBinCenter(std::size_t bin) const override {
0267       return getBinCenterImpl(bin);
0268     }
0269 
0270     /// @brief Returns copies of the axes used in the grid as @c AnyAxis
0271     /// @return The axes
0272     /// @note This returns copies. Use for introspection and querying.
0273     std::vector<const IAxis*> getAxes() const override {
0274       auto arr = m_grid.axes();
0275       return std::vector<const IAxis*>(arr.begin(), arr.end());
0276     }
0277 
0278     /// @brief Get the number of dimensions of the grid.
0279     /// @return number of dimensions
0280     std::size_t dimensions() const override { return DIM; }
0281 
0282     /// @brief Checks if global bin is valid
0283     /// @param bin the global bin index
0284     /// @return bool if the bin is valid
0285     /// @note Valid means that the index points to a bin which is not a under
0286     ///       or overflow bin or out of range in any axis.
0287     bool isValidBin(std::size_t bin) const override {
0288       std::array<std::size_t, DIM> indices = m_grid.localBinsFromGlobalBin(bin);
0289       std::array<std::size_t, DIM> nBins = m_grid.numLocalBins();
0290       for (std::size_t i = 0; i < indices.size(); ++i) {
0291         std::size_t idx = indices.at(i);
0292         if (idx <= 0 || idx >= nBins.at(i) + 1) {
0293           return false;
0294         }
0295       }
0296 
0297       return true;
0298     }
0299 
0300    private:
0301     void populateNeighborCache() {
0302       // calculate neighbors for every bin and store in map
0303       for (std::size_t i = 0; i < m_grid.size(); i++) {
0304         if (!isValidBin(i)) {
0305           continue;
0306         }
0307         typename Grid_t::index_t loc = m_grid.localBinsFromGlobalBin(i);
0308         auto neighborIdxs = m_grid.neighborHoodIndices(loc, 1u);
0309         std::vector<const Surface*>& neighbors = m_neighborMap.at(i);
0310         neighbors.clear();
0311 
0312         for (const auto idx : neighborIdxs) {
0313           const std::vector<const Surface*>& binContent = m_grid.at(idx);
0314           std::copy(binContent.begin(), binContent.end(),
0315                     std::back_inserter(neighbors));
0316         }
0317       }
0318     }
0319 
0320     /// Internal method.
0321     /// This is here, because apparently Eigen doesn't like Vector1.
0322     /// So SurfaceGridLookup internally uses std::array<double, 1> instead
0323     /// of Vector1 (see the point_t typedef). This needs to be switched here,
0324     /// so as not to
0325     /// attempt an initialization of Vector1 that Eigen will complain about.
0326     /// The SFINAE is hidden in this private method so the public
0327     /// interface stays the same, since we don't care what happens
0328     /// here on the callers end
0329     /// This is the version for DIM>1
0330     template <std::size_t D = DIM, std::enable_if_t<D != 1, int> = 0>
0331     Vector3 getBinCenterImpl(std::size_t bin) const {
0332       return m_localToGlobal(ActsVector<DIM>(
0333           m_grid.binCenter(m_grid.localBinsFromGlobalBin(bin)).data()));
0334     }
0335 
0336     /// Internal method, see above.
0337     /// This is the version for DIM==1
0338     template <std::size_t D = DIM, std::enable_if_t<D == 1, int> = 0>
0339     Vector3 getBinCenterImpl(std::size_t bin) const {
0340       point_t pos = m_grid.binCenter(m_grid.localBinsFromGlobalBin(bin));
0341       return m_localToGlobal(pos);
0342     }
0343 
0344     std::function<point_t(const Vector3&)> m_globalToLocal;
0345     std::function<Vector3(const point_t&)> m_localToGlobal;
0346     Grid_t m_grid;
0347     std::vector<BinningValue> m_binValues;
0348     std::vector<SurfaceVector> m_neighborMap;
0349   };
0350 
0351   /// @brief Lookup implementation which wraps one element and always returns
0352   ///        this element when lookup is called
0353   struct SingleElementLookup : ISurfaceGridLookup {
0354     /// @brief Default constructor.
0355     /// @param element the one and only element.
0356     SingleElementLookup(SurfaceVector::value_type element)
0357         : m_element({element}) {}
0358 
0359     /// @brief Default constructor.
0360     /// @param elements the surfaces that are provided through a single lookup
0361     SingleElementLookup(const SurfaceVector& elements) : m_element(elements) {}
0362 
0363     /// @brief Lookup, always returns @c element
0364     /// @return reference to vector containing only @c element
0365     SurfaceVector& lookup(const Vector3& /*position*/) override {
0366       return m_element;
0367     }
0368 
0369     /// @brief Lookup, always returns @c element
0370     /// @return reference to vector containing only @c element
0371     const SurfaceVector& lookup(const Vector3& /*position*/) const override {
0372       return m_element;
0373     }
0374 
0375     /// @brief Lookup, always returns @c element
0376     /// @return reference to vector containing only @c element
0377     SurfaceVector& lookup(std::size_t /*bin*/) override { return m_element; }
0378 
0379     /// @brief Lookup, always returns @c element
0380     /// @return reference to vector containing only @c element
0381     const SurfaceVector& lookup(std::size_t /*bin*/) const override {
0382       return m_element;
0383     }
0384 
0385     /// @brief Lookup, always returns @c element
0386     /// @return reference to vector containing only @c element
0387     const SurfaceVector& neighbors(const Vector3& /*position*/) const override {
0388       return m_element;
0389     }
0390 
0391     /// @brief returns 1
0392     /// @return 1
0393     std::size_t size() const override { return 1; }
0394 
0395     /// @brief Gets the bin center, but always returns (0, 0, 0)
0396     /// @return (0, 0, 0)
0397     Vector3 getBinCenter(std::size_t /*bin*/) const override {
0398       return Vector3(0, 0, 0);
0399     }
0400 
0401     /// @brief Returns an empty vector of @c AnyAxis
0402     /// @return empty vector
0403     std::vector<const IAxis*> getAxes() const override { return {}; }
0404 
0405     /// @brief Get the number of dimensions
0406     /// @return always 0
0407     std::size_t dimensions() const override { return 0; }
0408 
0409     /// @brief Comply with concept and provide fill method
0410     /// @note Does nothing
0411     void fill(const GeometryContext& /*gctx*/,
0412               const SurfaceVector& /*surfaces*/) override {}
0413 
0414     /// @brief Comply with concept and provide completeBinning method
0415     /// @note Does nothing
0416     std::size_t completeBinning(const GeometryContext& /*gctx*/,
0417                                 const SurfaceVector& /*surfaces*/) override {
0418       return 0;
0419     }
0420 
0421     /// @brief Returns if the bin is valid (it is)
0422     /// @return always true
0423     bool isValidBin(std::size_t /*bin*/) const override { return true; }
0424 
0425    private:
0426     SurfaceVector m_element;
0427   };
0428 
0429   /// @brief Default constructor which takes a @c SurfaceLookup and a vector of
0430   /// surfaces
0431   /// @param gridLookup The grid storage. @c SurfaceArray does not fill it on
0432   /// its own
0433   /// @param surfaces The input vector of surfaces. This is only for
0434   /// bookkeeping, so we can ask
0435   /// @param transform Optional additional transform for this SurfaceArray
0436   SurfaceArray(std::unique_ptr<ISurfaceGridLookup> gridLookup,
0437                std::vector<std::shared_ptr<const Surface>> surfaces,
0438                const Transform3& transform = Transform3::Identity());
0439 
0440   /// @brief Constructor with a single surface
0441   /// @param srf The one and only surface
0442   SurfaceArray(std::shared_ptr<const Surface> srf);
0443 
0444   /// @brief Get all surfaces in bin given by position.
0445   /// @param position the lookup position
0446   /// @return reference to @c SurfaceVector contained in bin at that position
0447   SurfaceVector& at(const Vector3& position) {
0448     return p_gridLookup->lookup(position);
0449   }
0450 
0451   /// @brief Get all surfaces in bin given by position @p pos.
0452   /// @param position the lookup position
0453   /// @return const reference to @c SurfaceVector contained in bin at that
0454   /// position
0455   const SurfaceVector& at(const Vector3& position) const {
0456     return p_gridLookup->lookup(position);
0457   }
0458 
0459   /// @brief Get all surfaces in bin given by global bin index @p bin.
0460   /// @param bin the global bin index
0461   /// @return reference to @c SurfaceVector contained in bin
0462   SurfaceVector& at(std::size_t bin) { return p_gridLookup->lookup(bin); }
0463 
0464   /// @brief Get all surfaces in bin given by global bin index.
0465   /// @param bin the global bin index
0466   /// @return const reference to @c SurfaceVector contained in bin
0467   const SurfaceVector& at(std::size_t bin) const {
0468     return p_gridLookup->lookup(bin);
0469   }
0470 
0471   /// @brief Get all surfaces in bin at @p pos and its neighbors
0472   /// @param position The position to lookup as nominal
0473   /// @return Merged @c SurfaceVector of neighbors and nominal
0474   /// @note The @c SurfaceVector will be combined. For technical reasons, the
0475   ///       different bin content vectors have to be copied, so the resulting
0476   ///       vector contains copies.
0477   const SurfaceVector& neighbors(const Vector3& position) const {
0478     return p_gridLookup->neighbors(position);
0479   }
0480 
0481   /// @brief Get the size of the underlying grid structure including
0482   /// under/overflow bins
0483   /// @return the size
0484   std::size_t size() const { return p_gridLookup->size(); }
0485 
0486   /// @brief Get the center of the bin identified by global bin index @p bin
0487   /// @param bin the global bin index
0488   /// @return Center position of the bin in global coordinates
0489   Vector3 getBinCenter(std::size_t bin) {
0490     return p_gridLookup->getBinCenter(bin);
0491   }
0492 
0493   /// @brief Get all surfaces attached to this @c SurfaceArray
0494   /// @return Reference to @c SurfaceVector containing all surfaces
0495   /// @note This does not reflect the actual state of the grid. It only
0496   ///       returns what was given in the constructor, without any checks
0497   ///       if that is actually what's in the grid.
0498   const SurfaceVector& surfaces() const { return m_surfacesRawPointers; }
0499 
0500   /// @brief Get vector of axes spanning the grid as @c AnyAxis
0501   /// @return vector of @c AnyAxis
0502   /// @note The axes in the vector are copies. Only use for introspection and
0503   ///       querying.
0504   std::vector<const IAxis*> getAxes() const { return p_gridLookup->getAxes(); }
0505 
0506   /// @brief Checks if global bin is valid
0507   /// @param bin the global bin index
0508   /// @return bool if the bin is valid
0509   /// @note Valid means that the index points to a bin which is not a under
0510   ///       or overflow bin or out of range in any axis.
0511   bool isValidBin(std::size_t bin) const {
0512     return p_gridLookup->isValidBin(bin);
0513   }
0514 
0515   const Transform3& transform() const { return m_transform; }
0516 
0517   /// @brief The binning values described by this surface grid lookup
0518   /// They are in order of the axes
0519   std::vector<BinningValue> binningValues() const {
0520     return p_gridLookup->binningValues();
0521   };
0522 
0523   /// @brief String representation of this @c SurfaceArray
0524   /// @param gctx The current geometry context object, e.g. alignment
0525   /// @param sl Output stream to write to
0526   /// @return the output stream given as @p sl
0527   std::ostream& toStream(const GeometryContext& gctx, std::ostream& sl) const;
0528 
0529  private:
0530   std::unique_ptr<ISurfaceGridLookup> p_gridLookup;
0531   // this vector makes sure we have shared ownership over the surfaces
0532   std::vector<std::shared_ptr<const Surface>> m_surfaces;
0533   // this vector is returned, so that (expensive) copying of the shared_ptr
0534   // vector does not happen by default
0535   SurfaceVector m_surfacesRawPointers;
0536   // this is only used to keep info on transform applied
0537   // by l2g and g2l
0538   Transform3 m_transform;
0539 };
0540 
0541 }  // namespace Acts