Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-06-06 07:49:13

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