Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-04 08:20:08

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