Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-01 07:52:40

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