Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:11:10

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Utilities/IAxis.hpp"
0013 #include "Acts/Utilities/Interpolation.hpp"
0014 #include "Acts/Utilities/TypeTag.hpp"
0015 #include "Acts/Utilities/detail/grid_helper.hpp"
0016 
0017 #include <array>
0018 #include <numeric>
0019 #include <set>
0020 #include <tuple>
0021 #include <type_traits>
0022 #include <utility>
0023 #include <vector>
0024 
0025 namespace Acts {
0026 template <typename T, class... Axes>
0027 class GridGlobalIterator;
0028 
0029 template <typename T, class... Axes>
0030 class GridLocalIterator;
0031 }  // namespace Acts
0032 
0033 namespace Acts {
0034 
0035 /// Base class for all grid types
0036 class IGrid {
0037  public:
0038   virtual ~IGrid() = default;
0039 
0040   /// Get a dynamically sized vector of axis objects for inspection
0041   /// @return a vector of axis pointers
0042   virtual boost::container::small_vector<const IAxis*, 3> axes() const = 0;
0043 
0044   /// Helper to print out the grid
0045   /// @param os the output stream
0046   /// @param grid the grid to print
0047   /// @return the output stream
0048   friend std::ostream& operator<<(std::ostream& os, const IGrid& grid) {
0049     grid.toStream(os);
0050     return os;
0051   }
0052 
0053   friend bool operator==(const IGrid& lhs, const IGrid& rhs) {
0054     auto lhsAxes = lhs.axes();
0055     auto rhsAxes = rhs.axes();
0056     return lhsAxes.size() == rhsAxes.size() &&
0057            std::equal(lhsAxes.begin(), lhsAxes.end(), rhsAxes.begin(),
0058                       [](const IAxis* a, const IAxis* b) { return *a == *b; });
0059   }
0060 
0061  protected:
0062   virtual void toStream(std::ostream& os) const = 0;
0063 };
0064 
0065 /// @brief class for describing a regular multi-dimensional grid
0066 ///
0067 /// @tparam T    type of values stored inside the bins of the grid
0068 /// @tparam Axes parameter pack of axis types defining the grid
0069 ///
0070 /// Class describing a multi-dimensional, regular grid which can store objects
0071 /// in its multi-dimensional bins. Bins are hyper-boxes and can be accessed
0072 /// either by global bin index, local bin indices or position.
0073 ///
0074 /// @note @c T must be default-constructible.
0075 template <typename T, class... Axes>
0076 class Grid final : public IGrid {
0077  public:
0078   /// number of dimensions of the grid
0079   static constexpr std::size_t DIM = sizeof...(Axes);
0080 
0081   /// type of values stored
0082   using value_type = T;
0083   /// reference type to values stored
0084   using reference = value_type&;
0085   /// constant reference type to values stored
0086   using const_reference = const value_type&;
0087   /// type for points in d-dimensional grid space
0088   using point_t = std::array<double, DIM>;
0089   /// index type using local bin indices along each axis
0090   using index_t = std::array<std::size_t, DIM>;
0091   /// global iterator type
0092   using global_iterator_t = Acts::GridGlobalIterator<T, Axes...>;
0093   /// local iterator type
0094   using local_iterator_t = Acts::GridLocalIterator<T, Axes...>;
0095 
0096   /// @brief Constructor from const axis tuple, this will allow
0097   /// creating a grid with a different value type from a template
0098   /// grid object.
0099   ///
0100   /// @param axes
0101   Grid(const std::tuple<Axes...>& axes) : m_axes(axes) {
0102     m_values.resize(size());
0103   }
0104 
0105   /// @brief Move constructor from axis tuple
0106   /// @param axes
0107   Grid(std::tuple<Axes...>&& axes) : m_axes(std::move(axes)) {
0108     m_values.resize(size());
0109   }
0110 
0111   /// @brief constructor from parameters pack of axes
0112   /// @param axes
0113   Grid(Axes&&... axes) : m_axes(std::forward_as_tuple(axes...)) {
0114     m_values.resize(size());
0115   }
0116 
0117   /// @brief constructor from parameters pack of axes
0118   /// @param axes
0119   Grid(const Axes&... axes) : m_axes(std::tuple(axes...)) {
0120     m_values.resize(size());
0121   }
0122 
0123   /// @brief constructor from parameters pack of axes and type tag
0124   /// @param axes
0125   Grid(TypeTag<T> /*tag*/, Axes&&... axes)
0126       : m_axes(std::forward_as_tuple(axes...)) {
0127     m_values.resize(size());
0128   }
0129 
0130   /// @brief constructor from parameters pack of axes and type tag
0131   /// @param axes
0132   Grid(TypeTag<T> /*tag*/, const Axes&... axes) : m_axes(std::tuple(axes...)) {
0133     m_values.resize(size());
0134   }
0135 
0136   // Grid(TypeTag<T> /*tag*/, Axes&... axes) = delete;
0137 
0138   /// @brief access value stored in bin for a given point
0139   ///
0140   /// @tparam Point any type with point semantics supporting component access
0141   ///               through @c operator[]
0142   /// @param [in] point point used to look up the corresponding bin in the
0143   ///                   grid
0144   /// @return reference to value stored in bin containing the given point
0145   ///
0146   /// @pre The given @c Point type must represent a point in d (or higher)
0147   ///      dimensions where d is dimensionality of the grid.
0148   ///
0149   /// @note The look-up considers under-/overflow bins along each axis.
0150   ///       Therefore, the look-up will never fail.
0151   //
0152   template <class Point>
0153   reference atPosition(const Point& point) {
0154     return m_values.at(globalBinFromPosition(point));
0155   }
0156 
0157   /// @brief access value stored in bin for a given point
0158   ///
0159   /// @tparam Point any type with point semantics supporting component access
0160   ///               through @c operator[]
0161   /// @param [in] point point used to look up the corresponding bin in the
0162   ///                   grid
0163   /// @return const-reference to value stored in bin containing the given
0164   ///         point
0165   ///
0166   /// @pre The given @c Point type must represent a point in d (or higher)
0167   ///      dimensions where d is dimensionality of the grid.
0168   ///
0169   /// @note The look-up considers under-/overflow bins along each axis.
0170   ///       Therefore, the look-up will never fail.
0171   template <class Point>
0172   const_reference atPosition(const Point& point) const {
0173     return m_values.at(globalBinFromPosition(point));
0174   }
0175 
0176   /// @brief access value stored in bin with given global bin number
0177   ///
0178   /// @param  [in] bin global bin number
0179   /// @return reference to value stored in bin containing the given
0180   ///         point
0181   reference at(std::size_t bin) { return m_values.at(bin); }
0182 
0183   /// @brief access value stored in bin with given global bin number
0184   ///
0185   /// @param  [in] bin global bin number
0186   /// @return const-reference to value stored in bin containing the given
0187   ///         point
0188   const_reference at(std::size_t bin) const { return m_values.at(bin); }
0189 
0190   /// @brief access value stored in bin with given local bin numbers
0191   ///
0192   /// @param  [in] localBins local bin indices along each axis
0193   /// @return reference to value stored in bin containing the given
0194   ///         point
0195   ///
0196   /// @pre All local bin indices must be a valid index for the corresponding
0197   ///      axis (including the under-/overflow bin for this axis).
0198   reference atLocalBins(const index_t& localBins) {
0199     return m_values.at(globalBinFromLocalBins(localBins));
0200   }
0201 
0202   /// @brief access value stored in bin with given local bin numbers
0203   ///
0204   /// @param  [in] localBins local bin indices along each axis
0205   /// @return const-reference to value stored in bin containing the given
0206   ///         point
0207   ///
0208   /// @pre All local bin indices must be a valid index for the corresponding
0209   ///      axis (including the under-/overflow bin for this axis).
0210   const_reference atLocalBins(const index_t& localBins) const {
0211     return m_values.at(globalBinFromLocalBins(localBins));
0212   }
0213 
0214   /// @brief get global bin indices for closest points on grid
0215   ///
0216   /// @tparam Point any type with point semantics supporting component access
0217   ///               through @c operator[]
0218   /// @param [in] position point of interest
0219   /// @return Iterable thatemits the indices of bins whose lower-left corners
0220   ///         are the closest points on the grid to the input.
0221   ///
0222   /// @pre The given @c Point type must represent a point in d (or higher)
0223   ///      dimensions where d is dimensionality of the grid. It must lie
0224   ///      within the grid range (i.e. not within a under-/overflow bin).
0225   template <class Point>
0226   detail::GlobalNeighborHoodIndices<DIM> closestPointsIndices(
0227       const Point& position) const {
0228     return rawClosestPointsIndices(localBinsFromPosition(position));
0229   }
0230 
0231   /// @brief dimensionality of grid
0232   ///
0233   /// @return number of axes spanning the grid
0234   static constexpr std::size_t dimensions() { return DIM; }
0235 
0236   /// @brief get center position of bin with given local bin numbers
0237   ///
0238   /// @param  [in] localBins local bin indices along each axis
0239   /// @return center position of bin
0240   ///
0241   /// @pre All local bin indices must be a valid index for the corresponding
0242   ///      axis (excluding the under-/overflow bins for each axis).
0243   std::array<double, DIM> binCenter(const index_t& localBins) const {
0244     return detail::grid_helper::getBinCenter(localBins, m_axes);
0245   }
0246 
0247   /// @brief determine global index for bin containing the given point
0248   ///
0249   /// @tparam Point any type with point semantics supporting component access
0250   ///               through @c operator[]
0251   ///
0252   /// @param  [in] point point to look up in the grid
0253   /// @return global index for bin containing the given point
0254   ///
0255   /// @pre The given @c Point type must represent a point in d (or higher)
0256   ///      dimensions where d is dimensionality of the grid.
0257   /// @note This could be a under-/overflow bin along one or more axes.
0258   template <class Point>
0259   std::size_t globalBinFromPosition(const Point& point) const {
0260     return globalBinFromLocalBins(localBinsFromPosition(point));
0261   }
0262 
0263   /// @brief determine global bin index from local bin indices along each axis
0264   ///
0265   /// @param  [in] localBins local bin indices along each axis
0266   /// @return global index for bin defined by the local bin indices
0267   ///
0268   /// @pre All local bin indices must be a valid index for the corresponding
0269   ///      axis (including the under-/overflow bin for this axis).
0270   std::size_t globalBinFromLocalBins(const index_t& localBins) const {
0271     return detail::grid_helper::getGlobalBin(localBins, m_axes);
0272   }
0273 
0274   /// @brief  determine global bin index of the bin with the lower left edge
0275   ///         closest to the given point for each axis
0276   ///
0277   /// @tparam Point any type with point semantics supporting component access
0278   ///               through @c operator[]
0279   ///
0280   /// @param  [in] point point to look up in the grid
0281   /// @return global index for bin containing the given point
0282   ///
0283   /// @pre The given @c Point type must represent a point in d (or higher)
0284   ///      dimensions where d is dimensionality of the grid.
0285   /// @note This could be a under-/overflow bin along one or more axes.
0286   template <class Point>
0287   std::size_t globalBinFromFromLowerLeftEdge(const Point& point) const {
0288     return globalBinFromLocalBins(localBinsFromLowerLeftEdge(point));
0289   }
0290 
0291   /// @brief  determine local bin index for each axis from the given point
0292   ///
0293   /// @tparam Point any type with point semantics supporting component access
0294   ///               through @c operator[]
0295   ///
0296   /// @param  [in] point point to look up in the grid
0297   /// @return array with local bin indices along each axis (in same order as
0298   ///         given @c axes object)
0299   ///
0300   /// @pre The given @c Point type must represent a point in d (or higher)
0301   ///      dimensions where d is dimensionality of the grid.
0302   /// @note This could be a under-/overflow bin along one or more axes.
0303   template <class Point>
0304   index_t localBinsFromPosition(const Point& point) const {
0305     return detail::grid_helper::getLocalBinIndices(point, m_axes);
0306   }
0307 
0308   /// @brief determine local bin index for each axis from global bin index
0309   ///
0310   /// @param  [in] bin global bin index
0311   /// @return array with local bin indices along each axis (in same order as
0312   ///         given @c axes object)
0313   ///
0314   /// @note Local bin indices can contain under-/overflow bins along the
0315   ///       corresponding axis.
0316   index_t localBinsFromGlobalBin(std::size_t bin) const {
0317     return detail::grid_helper::getLocalBinIndices(bin, m_axes);
0318   }
0319 
0320   /// @brief  determine local bin index of the bin with the lower left edge
0321   ///         closest to the given point for each axis
0322   ///
0323   /// @tparam Point any type with point semantics supporting component access
0324   ///               through @c operator[]
0325   ///
0326   /// @param  [in] point point to look up in the grid
0327   /// @return array with local bin indices along each axis (in same order as
0328   ///         given @c axes object)
0329   ///
0330   /// @pre The given @c Point type must represent a point in d (or higher)
0331   ///      dimensions where d is dimensionality of the grid.
0332   /// @note This could be a under-/overflow bin along one or more axes.
0333   template <class Point>
0334   index_t localBinsFromLowerLeftEdge(const Point& point) const {
0335     Point shiftedPoint;
0336     point_t width = detail::grid_helper::getWidth(m_axes);
0337     for (std::size_t i = 0; i < DIM; i++) {
0338       shiftedPoint[i] = point[i] + width[i] / 2;
0339     }
0340     return detail::grid_helper::getLocalBinIndices(shiftedPoint, m_axes);
0341   }
0342 
0343   /// @brief retrieve lower-left bin edge from set of local bin indices
0344   ///
0345   /// @param  [in] localBins local bin indices along each axis
0346   /// @return generalized lower-left bin edge position
0347   ///
0348   /// @pre @c localBins must only contain valid bin indices (excluding
0349   ///      underflow bins).
0350   point_t lowerLeftBinEdge(const index_t& localBins) const {
0351     return detail::grid_helper::getLowerLeftBinEdge(localBins, m_axes);
0352   }
0353 
0354   /// @brief retrieve upper-right bin edge from set of local bin indices
0355   ///
0356   /// @param  [in] localBins local bin indices along each axis
0357   /// @return generalized upper-right bin edge position
0358   ///
0359   /// @pre @c localBins must only contain valid bin indices (excluding
0360   ///      overflow bins).
0361   point_t upperRightBinEdge(const index_t& localBins) const {
0362     return detail::grid_helper::getUpperRightBinEdge(localBins, m_axes);
0363   }
0364 
0365   /// @brief get bin width along each specific axis
0366   ///
0367   /// @return array giving the bin width alonf all axes
0368   point_t binWidth() const { return detail::grid_helper::getWidth(m_axes); }
0369 
0370   /// @brief get number of bins along each specific axis
0371   ///
0372   /// @return array giving the number of bins along all axes
0373   ///
0374   /// @note Not including under- and overflow bins
0375   index_t numLocalBins() const { return detail::grid_helper::getNBins(m_axes); }
0376 
0377   /// @brief get the minimum value of all axes of one grid
0378   ///
0379   /// @return array returning the minima of all given axes
0380   point_t minPosition() const { return detail::grid_helper::getMin(m_axes); }
0381 
0382   /// @brief get the maximum value of all axes of one grid
0383   ///
0384   /// @return array returning the maxima of all given axes
0385   point_t maxPosition() const { return detail::grid_helper::getMax(m_axes); }
0386 
0387   /// @brief set all overflow and underflow bins to a certain value
0388   ///
0389   /// @param [in] value value to be inserted in every overflow and underflow
0390   ///                   bin of the grid.
0391   ///
0392   void setExteriorBins(const value_type& value) {
0393     for (std::size_t index : detail::grid_helper::exteriorBinIndices(m_axes)) {
0394       at(index) = value;
0395     }
0396   }
0397 
0398   /// @brief interpolate grid values to given position
0399   ///
0400   /// @tparam Point type specifying geometric positions
0401   /// @tparam U     dummy template parameter identical to @c T
0402   ///
0403   /// @param [in] point location to which to interpolate grid values. The
0404   ///                   position must be within the grid dimensions and not
0405   ///                   lie in an under-/overflow bin along any axis.
0406   ///
0407   /// @return interpolated value at given position
0408   ///
0409   /// @pre The given @c Point type must represent a point in d (or higher)
0410   ///      dimensions where d is dimensionality of the grid.
0411   ///
0412   /// @note This function is available only if the following conditions are
0413   /// fulfilled:
0414   /// - Given @c U and @c V of value type @c T as well as two @c double
0415   /// @c a and @c b, then the following must be a valid expression <tt>a * U + b
0416   /// * V</tt> yielding an object which is (implicitly) convertible to @c T.
0417   /// - @c Point must represent a d-dimensional position and support
0418   /// coordinate access using @c operator[] which should return a @c
0419   /// double (or a value which is implicitly convertible). Coordinate
0420   /// indices must start at 0.
0421   /// @note Bin values are interpreted as being the field values at the
0422   /// lower-left corner of the corresponding hyper-box.
0423   template <class Point>
0424   T interpolate(const Point& point) const
0425     requires(Concepts::interpolatable<T, Point, std::array<double, DIM>,
0426                                       std::array<double, DIM>>)
0427   {
0428     // there are 2^DIM corner points used during the interpolation
0429     constexpr std::size_t nCorners = 1 << DIM;
0430 
0431     // construct vector of pairs of adjacent bin centers and values
0432     std::array<value_type, nCorners> neighbors{};
0433 
0434     // get local indices for current bin
0435     // value of bin is interpreted as being the field value at its lower left
0436     // corner
0437     const auto& llIndices = localBinsFromPosition(point);
0438 
0439     // get global indices for all surrounding corner points
0440     const auto& closestIndices = rawClosestPointsIndices(llIndices);
0441 
0442     // get values on grid points
0443     std::size_t i = 0;
0444     for (std::size_t index : closestIndices) {
0445       neighbors.at(i++) = at(index);
0446     }
0447 
0448     return Acts::interpolate(point, lowerLeftBinEdge(llIndices),
0449                              upperRightBinEdge(llIndices), neighbors);
0450   }
0451 
0452   /// @brief check whether given point is inside grid limits
0453   ///
0454   /// @return @c true if \f$\text{xmin_i} \le x_i < \text{xmax}_i \forall i=0,
0455   ///         \dots, d-1\f$, otherwise @c false
0456   ///
0457   /// @pre The given @c Point type must represent a point in d (or higher)
0458   ///      dimensions where d is dimensionality of the grid.
0459   ///
0460   /// @post If @c true is returned, the global bin containing the given point
0461   ///       is a valid bin, i.e. it is neither a underflow nor an overflow bin
0462   ///       along any axis.
0463   template <class Point>
0464   bool isInside(const Point& position) const {
0465     return detail::grid_helper::isInside(position, m_axes);
0466   }
0467 
0468   /// @brief get global bin indices for neighborhood
0469   ///
0470   /// @param [in] localBins center bin defined by local bin indices along each
0471   ///                       axis
0472   /// @param [in] size      size of neighborhood determining how many adjacent
0473   ///                       bins along each axis are considered
0474   /// @return set of global bin indices for all bins in neighborhood
0475   ///
0476   /// @note Over-/underflow bins are included in the neighborhood.
0477   /// @note The @c size parameter sets the range by how many units each local
0478   ///       bin index is allowed to be varied. All local bin indices are
0479   ///       varied independently, that is diagonal neighbors are included.
0480   ///       Ignoring the truncation of the neighborhood size reaching beyond
0481   ///       over-/underflow bins, the neighborhood is of size \f$2 \times
0482   ///       \text{size}+1\f$ along each dimension.
0483   detail::GlobalNeighborHoodIndices<DIM> neighborHoodIndices(
0484       const index_t& localBins, std::size_t size = 1u) const {
0485     return detail::grid_helper::neighborHoodIndices(localBins, size, m_axes);
0486   }
0487 
0488   /// @brief get global bin   indices for neighborhood
0489   ///
0490   /// @param [in] localBins   center bin defined by local bin indices along
0491   ///                         each axis. If size is negative, center bin
0492   ///                         is not returned.
0493   /// @param [in] sizePerAxis size of neighborhood for each axis, how many
0494   ///                         adjacent bins along each axis are considered
0495   /// @return set of global bin indices for all bins in neighborhood
0496   ///
0497   /// @note Over-/underflow bins are included in the neighborhood.
0498   /// @note The @c size parameter sets the range by how many units each local
0499   ///       bin index is allowed to be varied. All local bin indices are
0500   ///       varied independently, that is diagonal neighbors are included.
0501   ///       Ignoring the truncation of the neighborhood size reaching beyond
0502   ///       over-/underflow bins, the neighborhood is of size \f$2 \times
0503   ///       \text{size}+1\f$ along each dimension.
0504   detail::GlobalNeighborHoodIndices<DIM> neighborHoodIndices(
0505       const index_t& localBins,
0506       std::array<std::pair<int, int>, DIM>& sizePerAxis) const {
0507     return detail::grid_helper::neighborHoodIndices(localBins, sizePerAxis,
0508                                                     m_axes);
0509   }
0510 
0511   /// @brief total number of bins
0512   ///
0513   /// @return total number of bins in the grid
0514   ///
0515   /// @note This number contains under-and overflow bins along all axes.
0516   std::size_t size(bool fullCounter = true) const {
0517     index_t nBinsArray = numLocalBins();
0518     std::size_t current_size = 1;
0519     // add under-and overflow bins for each axis and multiply all bins
0520     if (fullCounter) {
0521       for (const auto& value : nBinsArray) {
0522         current_size *= value + 2;
0523       }
0524     }
0525     // ignore under-and overflow bins for each axis and multiply all bins
0526     else {
0527       for (const auto& value : nBinsArray) {
0528         current_size *= value;
0529       }
0530     }
0531     return current_size;
0532   }
0533 
0534   /// @brief Convenience function to convert the type of the grid
0535   /// to hold another object type.
0536   ///
0537   /// @tparam U the new grid value type
0538   ///
0539   /// @return a new grid with the same axes and a different value type
0540   template <typename U>
0541   Grid<U, Axes...> convertType() const {
0542     Grid<U, Axes...> cGrid(m_axes);
0543     return cGrid;
0544   }
0545 
0546   /// @brief Convenience function to convert the type of the grid
0547   /// to hold another object type.
0548   ///
0549   /// @tparam converter_t the converter type
0550   ///
0551   /// This is designed to be most flexible with a converter object
0552   /// as a visitor. If needed, such a visitor could also use
0553   /// caching or other techniques to speed up the conversion.
0554   ///
0555   /// @param cVisitor the converter object as visitor
0556   ///
0557   /// @return a new grid with the same axes and a different value type
0558   template <typename converter_t>
0559   Grid<typename converter_t::value_type, Axes...> convertGrid(
0560       converter_t& cVisitor) const {
0561     Grid<typename converter_t::value_type, Axes...> cGrid(m_axes);
0562     // Loop through the values and convert them
0563     for (std::size_t i = 0; i < size(); i++) {
0564       cGrid.at(i) = cVisitor(at(i));
0565     }
0566     return cGrid;
0567   }
0568 
0569   /// @brief get the axes as a tuple
0570   const std::tuple<Axes...>& axesTuple() const { return m_axes; }
0571 
0572   /// @brief get the axes as an array of IAxis pointers
0573   boost::container::small_vector<const IAxis*, 3> axes() const override {
0574     boost::container::small_vector<const IAxis*, 3> result;
0575     auto axes = detail::grid_helper::getAxes(m_axes);
0576     std::copy(axes.begin(), axes.end(), std::back_inserter(result));
0577     return result;
0578   }
0579 
0580   /// begin iterator for global bins
0581   global_iterator_t begin() const { return global_iterator_t(*this, 0); }
0582 
0583   /// end iterator for global bins
0584   global_iterator_t end() const { return global_iterator_t(*this, size()); }
0585 
0586   /// @brief begin iterator for local bins
0587   ///
0588   /// @param navigator is local navigator for the grid
0589   local_iterator_t begin(
0590       const std::array<std::vector<std::size_t>, DIM>& navigator) const {
0591     std::array<std::size_t, DIM> localBin{};
0592     return local_iterator_t(*this, std::move(localBin), navigator);
0593   }
0594 
0595   /// @brief end iterator for local bins
0596   ///
0597   /// @param navigator is local navigator for the grid
0598   local_iterator_t end(
0599       const std::array<std::vector<std::size_t>, DIM>& navigator) const {
0600     std::array<std::size_t, DIM> endline{};
0601     for (std::size_t i(0ul); i < DIM; ++i) {
0602       endline[i] = navigator[i].size();
0603     }
0604     return local_iterator_t(*this, std::move(endline), navigator);
0605   }
0606 
0607  protected:
0608   void toStream(std::ostream& os) const override {
0609     printAxes(os, std::make_index_sequence<sizeof...(Axes)>());
0610   }
0611 
0612  private:
0613   /// set of axis defining the multi-dimensional grid
0614   std::tuple<Axes...> m_axes;
0615   /// linear value store for each bin
0616   std::vector<T> m_values;
0617 
0618   // Part of closestPointsIndices that goes after local bins resolution.
0619   // Used as an interpolation performance optimization, but not exposed as it
0620   // doesn't make that much sense from an API design standpoint.
0621   detail::GlobalNeighborHoodIndices<DIM> rawClosestPointsIndices(
0622       const index_t& localBins) const {
0623     return detail::grid_helper::closestPointsIndices(localBins, m_axes);
0624   }
0625 
0626   template <std::size_t... Is>
0627   void printAxes(std::ostream& os, std::index_sequence<Is...> /*s*/) const {
0628     auto printOne = [&os, this]<std::size_t index>(
0629                         std::integral_constant<std::size_t, index>) {
0630       if constexpr (index > 0) {
0631         os << ", ";
0632       }
0633       os << std::get<index>(m_axes);
0634     };
0635     (printOne(std::integral_constant<std::size_t, Is>()), ...);
0636   }
0637 };
0638 
0639 template <typename T, class... Axes>
0640 Grid(TypeTag<T> /*type*/, Axes&&... axes) -> Grid<T, Axes...>;
0641 
0642 template <typename T, class... Axes>
0643 Grid(TypeTag<T> /*type*/, Axes&... axes) -> Grid<T, Axes...>;
0644 
0645 }  // namespace Acts