From 881f70d90a9f4ae100f70865b441cf4368159460 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Wed, 3 Jun 2026 16:39:13 +0200 Subject: [PATCH 1/6] chore: Cleanup and move `grid_helper.hpp` to `MultiAxisHelper.hpp` --- .../Acts/Material/InterpolatedMaterialMap.hpp | 2 +- .../Acts/Seeding/BinnedGroupIterator.hpp | 33 +- .../Acts/Seeding/BinnedGroupIterator.ipp | 11 +- Core/include/Acts/Utilities/Grid.hpp | 58 +- Core/include/Acts/Utilities/GridBinFinder.hpp | 4 +- Core/include/Acts/Utilities/MathHelpers.hpp | 7 + .../{grid_helper.hpp => MultiAxisHelper.hpp} | 585 +++++++++--------- Core/src/Surfaces/SurfaceArray.cpp | 23 +- .../MagneticField/MagneticField.hpp | 11 - Tests/UnitTests/Core/Utilities/GridTests.cpp | 4 - 10 files changed, 355 insertions(+), 383 deletions(-) rename Core/include/Acts/Utilities/detail/{grid_helper.hpp => MultiAxisHelper.hpp} (51%) diff --git a/Core/include/Acts/Material/InterpolatedMaterialMap.hpp b/Core/include/Acts/Material/InterpolatedMaterialMap.hpp index 23b52eab7d1..4ace3a79bb6 100644 --- a/Core/include/Acts/Material/InterpolatedMaterialMap.hpp +++ b/Core/include/Acts/Material/InterpolatedMaterialMap.hpp @@ -151,7 +151,7 @@ struct MaterialMapLookup { MaterialCell getMaterialCell(const Vector3& position) const { const auto& gridPosition = m_transformPos(position); std::size_t bin = m_grid.globalBinFromPosition(gridPosition); - const auto& indices = m_grid.localBinsFromPosition(bin); + const auto& indices = m_grid.localBinsFromGlobalBin(bin); const auto& lowerLeft = m_grid.lowerLeftBinEdge(indices); const auto& upperRight = m_grid.upperRightBinEdge(indices); diff --git a/Core/include/Acts/Seeding/BinnedGroupIterator.hpp b/Core/include/Acts/Seeding/BinnedGroupIterator.hpp index 634c2783bcc..f2d09db03d5 100644 --- a/Core/include/Acts/Seeding/BinnedGroupIterator.hpp +++ b/Core/include/Acts/Seeding/BinnedGroupIterator.hpp @@ -9,10 +9,11 @@ #pragma once #include "Acts/Utilities/Holders.hpp" -#include "Acts/Utilities/detail/grid_helper.hpp" +#include "Acts/Utilities/MathHelpers.hpp" #include #include +#include #include @@ -57,29 +58,6 @@ class BinnedGroupIterator { std::array index, std::array, DIM> navigation); - /// Do not allow Copy operations - - /// @brief Copy Constructor - /// @param [in] other The BinnedGroupIterator to copy - BinnedGroupIterator(const BinnedGroupIterator& other) = delete; - /// @brief Copy assignment - /// @param [in] other The BinnedGroupIterator to copy - /// @return The copied BinnedGroupIterator - BinnedGroupIterator& operator=( - const BinnedGroupIterator& other) = delete; - - /// @brief Move Constructor - /// @param [in] other The BinnedGroupIterator to move - BinnedGroupIterator(BinnedGroupIterator&& other) noexcept = default; - /// @brief Move assignment - /// @param [in] other The BinnedGroupIterator to move - /// @return The moved BinnedGroupIterator - BinnedGroupIterator& operator=(BinnedGroupIterator&& other) noexcept = - default; - - /// @brief Default Destructor - ~BinnedGroupIterator() = default; - /// @brief Equality operator /// @param [in] other The BinnedGroupIterator we are comparing against this one /// @return The result of the comparison @@ -93,10 +71,9 @@ class BinnedGroupIterator { /// bins with the possible bottom and top candidates /// /// @return The collection of all the bins in the grid - std::tuple< - boost::container::small_vector, - std::size_t, - boost::container::small_vector> + std::tuple, + std::size_t, + boost::container::small_vector> operator*() const; private: diff --git a/Core/include/Acts/Seeding/BinnedGroupIterator.ipp b/Core/include/Acts/Seeding/BinnedGroupIterator.ipp index 00dfd7544aa..fe08de43fea 100644 --- a/Core/include/Acts/Seeding/BinnedGroupIterator.ipp +++ b/Core/include/Acts/Seeding/BinnedGroupIterator.ipp @@ -42,10 +42,9 @@ BinnedGroupIterator& BinnedGroupIterator::operator++() { } template -std::tuple< - boost::container::small_vector, - std::size_t, - boost::container::small_vector> +std::tuple, + std::size_t, + boost::container::small_vector> BinnedGroupIterator::operator*() const { /// Get the global and local position from current iterator. This is the bin /// with the middle candidate And we know this is not an empty bin @@ -54,9 +53,9 @@ BinnedGroupIterator::operator*() const { m_group->grid().globalBinFromLocalBins(localPosition); /// Get the neighbouring bins - boost::container::small_vector bottoms = + boost::container::small_vector bottoms = m_group->m_bottomBinFinder->findBins(localPosition, m_group->grid()); - boost::container::small_vector tops = + boost::container::small_vector tops = m_group->m_topBinFinder->findBins(localPosition, m_group->grid()); // GCC12+ in Release throws an overread warning here due to the move. diff --git a/Core/include/Acts/Utilities/Grid.hpp b/Core/include/Acts/Utilities/Grid.hpp index d9f3af4530c..4a08fbd0791 100644 --- a/Core/include/Acts/Utilities/Grid.hpp +++ b/Core/include/Acts/Utilities/Grid.hpp @@ -12,7 +12,7 @@ #include "Acts/Utilities/IAxis.hpp" #include "Acts/Utilities/Interpolation.hpp" #include "Acts/Utilities/TypeTag.hpp" -#include "Acts/Utilities/detail/grid_helper.hpp" +#include "Acts/Utilities/detail/MultiAxisHelper.hpp" #include "Acts/Utilities/detail/interpolation_impl.hpp" #include @@ -300,7 +300,7 @@ class Grid final : public IGrid { /// dimensions where d is dimensionality of the grid. It must lie /// within the grid range (i.e. not within a under-/overflow bin). template - detail::GlobalNeighborHoodIndices closestPointsIndices( + detail::FlatNeighborHoodIndices closestPointsIndices( const Point& position) const { return rawClosestPointsIndices(localBinsFromPosition(position)); } @@ -321,7 +321,7 @@ class Grid final : public IGrid { /// @pre All local bin indices must be a valid index for the corresponding /// axis (excluding the under-/overflow bins for each axis). point_t binCenter(const index_t& localBins) const { - return detail::grid_helper::getBinCenter(localBins, m_axes); + return detail::MultiAxisHelper::getBinCenter(localBins, m_axes); } AnyPointType binCenterAny(AnyIndexType indices) const override { @@ -352,7 +352,8 @@ class Grid final : public IGrid { /// @pre All local bin indices must be a valid index for the corresponding /// axis (including the under-/overflow bin for this axis). std::size_t globalBinFromLocalBins(const index_t& localBins) const { - return detail::grid_helper::getGlobalBin(localBins, m_axes); + return detail::MultiAxisHelper::getFlatIndexFromMultiIndex(localBins, + m_axes); } /// @brief determine global bin index of the bin with the lower left edge @@ -386,7 +387,7 @@ class Grid final : public IGrid { /// @note This could be a under-/overflow bin along one or more axes. template index_t localBinsFromPosition(const Point& point) const { - return detail::grid_helper::getLocalBinIndices(point, m_axes); + return detail::MultiAxisHelper::getMultiIndexFromPoint(point, m_axes); } /// @brief determine local bin index for each axis from global bin index @@ -398,7 +399,7 @@ class Grid final : public IGrid { /// @note Local bin indices can contain under-/overflow bins along the /// corresponding axis. index_t localBinsFromGlobalBin(std::size_t bin) const { - return detail::grid_helper::getLocalBinIndices(bin, m_axes); + return detail::MultiAxisHelper::getMultiIndexFromFlatIndex(bin, m_axes); } /// @brief determine local bin index of the bin with the lower left edge @@ -417,11 +418,12 @@ class Grid final : public IGrid { template index_t localBinsFromLowerLeftEdge(const Point& point) const { Point shiftedPoint; - point_t width = detail::grid_helper::getWidth(m_axes); + point_t width = detail::MultiAxisHelper::getWidth(m_axes); for (std::size_t i = 0; i < DIM; i++) { shiftedPoint[i] = point[i] + width[i] / 2; } - return detail::grid_helper::getLocalBinIndices(shiftedPoint, m_axes); + return detail::MultiAxisHelper::getMultiIndexFromPoint(shiftedPoint, + m_axes); } /// @brief retrieve lower-left bin edge from set of local bin indices @@ -432,7 +434,7 @@ class Grid final : public IGrid { /// @pre @c localBins must only contain valid bin indices (excluding /// underflow bins). point_t lowerLeftBinEdge(const index_t& localBins) const { - return detail::grid_helper::getLowerLeftBinEdge(localBins, m_axes); + return detail::MultiAxisHelper::getLowerLeftBinCorner(localBins, m_axes); } /// @copydoc Acts::IGrid::lowerLeftBinEdgeAny @@ -448,7 +450,7 @@ class Grid final : public IGrid { /// @pre @c localBins must only contain valid bin indices (excluding /// overflow bins). point_t upperRightBinEdge(const index_t& localBins) const { - return detail::grid_helper::getUpperRightBinEdge(localBins, m_axes); + return detail::MultiAxisHelper::getUpperRightBinCorner(localBins, m_axes); } /// @copydoc Acts::IGrid::upperRightBinEdgeAny @@ -459,14 +461,16 @@ class Grid final : public IGrid { /// @brief get bin width along each specific axis /// /// @return array giving the bin width alonf all axes - point_t binWidth() const { return detail::grid_helper::getWidth(m_axes); } + point_t binWidth() const { return detail::MultiAxisHelper::getWidth(m_axes); } /// @brief get number of bins along each specific axis /// /// @return array giving the number of bins along all axes /// /// @note Not including under- and overflow bins - index_t numLocalBins() const { return detail::grid_helper::getNBins(m_axes); } + index_t numLocalBins() const { + return detail::MultiAxisHelper::getNBins(m_axes); + } /// @copydoc Acts::IGrid::numLocalBinsAny AnyIndexType numLocalBinsAny() const override { @@ -476,12 +480,16 @@ class Grid final : public IGrid { /// @brief get the minimum value of all axes of one grid /// /// @return array returning the minima of all given axes - point_t minPosition() const { return detail::grid_helper::getMin(m_axes); } + point_t minPosition() const { + return detail::MultiAxisHelper::getMin(m_axes); + } /// @brief get the maximum value of all axes of one grid /// /// @return array returning the maxima of all given axes - point_t maxPosition() const { return detail::grid_helper::getMax(m_axes); } + point_t maxPosition() const { + return detail::MultiAxisHelper::getMax(m_axes); + } /// @brief set all overflow and underflow bins to a certain value /// @@ -489,7 +497,8 @@ class Grid final : public IGrid { /// bin of the grid. /// void setExteriorBins(const value_type& value) { - for (std::size_t index : detail::grid_helper::exteriorBinIndices(m_axes)) { + for (std::size_t index : + detail::MultiAxisHelper::exteriorBinIndices(m_axes)) { at(index) = value; } } @@ -562,7 +571,7 @@ class Grid final : public IGrid { /// along any axis. template bool isInside(const Point& position) const { - return detail::grid_helper::isInside(position, m_axes); + return detail::MultiAxisHelper::isInside(position, m_axes); } /// @brief get global bin indices for neighborhood @@ -580,9 +589,10 @@ class Grid final : public IGrid { /// Ignoring the truncation of the neighborhood size reaching beyond /// over-/underflow bins, the neighborhood is of size \f$2 \times /// \text{size}+1\f$ along each dimension. - detail::GlobalNeighborHoodIndices neighborHoodIndices( + detail::FlatNeighborHoodIndices neighborHoodIndices( const index_t& localBins, std::size_t size = 1u) const { - return detail::grid_helper::neighborHoodIndices(localBins, size, m_axes); + return detail::MultiAxisHelper::neighborHoodIndices(localBins, size, + m_axes); } /// @brief get global bin indices for neighborhood @@ -601,11 +611,11 @@ class Grid final : public IGrid { /// Ignoring the truncation of the neighborhood size reaching beyond /// over-/underflow bins, the neighborhood is of size \f$2 \times /// \text{size}+1\f$ along each dimension. - detail::GlobalNeighborHoodIndices neighborHoodIndices( + detail::FlatNeighborHoodIndices neighborHoodIndices( const index_t& localBins, std::array, DIM>& sizePerAxis) const { - return detail::grid_helper::neighborHoodIndices(localBins, sizePerAxis, - m_axes); + return detail::MultiAxisHelper::neighborHoodIndices(localBins, sizePerAxis, + m_axes); } /// @brief total number of bins @@ -675,7 +685,7 @@ class Grid final : public IGrid { /// @return Vector containing pointers to all grid axes boost::container::small_vector axes() const override { boost::container::small_vector result; - auto axes = detail::grid_helper::getAxes(m_axes); + auto axes = detail::MultiAxisHelper::getAxes(m_axes); std::ranges::copy(axes, std::back_inserter(result)); return result; } @@ -725,9 +735,9 @@ class Grid final : public IGrid { // Part of closestPointsIndices that goes after local bins resolution. // Used as an interpolation performance optimization, but not exposed as it // doesn't make that much sense from an API design standpoint. - detail::GlobalNeighborHoodIndices rawClosestPointsIndices( + detail::FlatNeighborHoodIndices rawClosestPointsIndices( const index_t& localBins) const { - return detail::grid_helper::closestPointsIndices(localBins, m_axes); + return detail::MultiAxisHelper::closestPointsIndices(localBins, m_axes); } template diff --git a/Core/include/Acts/Utilities/GridBinFinder.hpp b/Core/include/Acts/Utilities/GridBinFinder.hpp index 27f7e461f1a..75774071185 100644 --- a/Core/include/Acts/Utilities/GridBinFinder.hpp +++ b/Core/include/Acts/Utilities/GridBinFinder.hpp @@ -10,7 +10,7 @@ #include "Acts/Utilities/Concepts.hpp" #include "Acts/Utilities/Grid.hpp" -#include "Acts/Utilities/detail/grid_helper.hpp" +#include "Acts/Utilities/MathHelpers.hpp" #include #include @@ -29,7 +29,7 @@ template class GridBinFinder { public: /// Number of neighbor bins in 3^DIM grid configuration - static constexpr std::size_t dimCubed = detail::ipow(3, DIM); + static constexpr std::size_t dimCubed = ipow(3, DIM); /// Type alias for variant storing different bin finding configurations using stored_values_t = diff --git a/Core/include/Acts/Utilities/MathHelpers.hpp b/Core/include/Acts/Utilities/MathHelpers.hpp index 9ea2ec7a88d..a2b96bd1418 100644 --- a/Core/include/Acts/Utilities/MathHelpers.hpp +++ b/Core/include/Acts/Utilities/MathHelpers.hpp @@ -265,4 +265,11 @@ inline double sinc(double x) { return std::sin(x) / x; } +template +constexpr T ipow(T num, unsigned int pow) { + return (pow >= sizeof(unsigned int) * 8) ? 0 + : pow == 0 ? 1 + : num * ipow(num, pow - 1); +} + } // namespace Acts diff --git a/Core/include/Acts/Utilities/detail/grid_helper.hpp b/Core/include/Acts/Utilities/detail/MultiAxisHelper.hpp similarity index 51% rename from Core/include/Acts/Utilities/detail/grid_helper.hpp rename to Core/include/Acts/Utilities/detail/MultiAxisHelper.hpp index 657fdd33fd5..9b18374d695 100644 --- a/Core/include/Acts/Utilities/detail/grid_helper.hpp +++ b/Core/include/Acts/Utilities/detail/MultiAxisHelper.hpp @@ -10,6 +10,7 @@ #include "Acts/Utilities/Axis.hpp" #include "Acts/Utilities/IAxis.hpp" +#include "Acts/Utilities/MathHelpers.hpp" #include #include @@ -20,38 +21,29 @@ namespace Acts::detail { -template -constexpr T ipow(T num, unsigned int pow) { - return (pow >= sizeof(unsigned int) * 8) ? 0 - : pow == 0 ? 1 - : num * ipow(num, pow - 1); -} - -// This object can be iterated to produce the (ordered) set of global indices -// associated with a neighborhood around a certain point on a grid. -// -// The goal is to emulate the effect of enumerating the global indices into -// an std::set (or into an std::vector that gets subsequently sorted), without -// paying the price of dynamic memory allocation in hot magnetic field -// interpolation code. -// +/// This object can be iterated to produce the (ordered) set of flat indices +/// associated with a neighborhood around a certain point on a grid. +/// +/// The goal is to emulate the effect of enumerating the flat indices into +/// an std::set (or into an std::vector that gets subsequently sorted), without +/// paying the price of dynamic memory allocation in hot magnetic field +/// interpolation code. template -class GlobalNeighborHoodIndices { +class FlatNeighborHoodIndices { public: - // You can get the local neighbor indices from - // grid_helper_impl::neighborHoodIndices and the number of bins in - // each direction from grid_helper_impl::getNBins. - GlobalNeighborHoodIndices( - std::array& neighborIndices, - const std::array& nBinsArray) - : m_localIndices(neighborIndices) { + /// You can get the neighbor multi indices from + /// MultiAxisHelperImpl::neighborHoodIndices and the number of bins in + /// each direction from MultiAxisHelperImpl::getNBins. + FlatNeighborHoodIndices(std::array& neighborIndices, + const std::array& nBinsArray) + : m_multiIndices(neighborIndices) { if (DIM == 1) { return; } - std::size_t globalStride = 1; + std::size_t flatStride = 1; for (long i = DIM - 2; i >= 0; --i) { - globalStride *= (nBinsArray[i + 1] + 2); - m_globalStrides[i] = globalStride; + flatStride *= (nBinsArray[i + 1] + 2); + m_flatStride[i] = flatStride; } } @@ -65,38 +57,38 @@ class GlobalNeighborHoodIndices { iterator() = default; - iterator(const GlobalNeighborHoodIndices& parent, - std::array&& localIndicesIter) - : m_localIndicesIter(std::move(localIndicesIter)), m_parent(&parent) {} + iterator(const FlatNeighborHoodIndices& parent, + std::array&& multiIndicesIter) + : m_multiIndicesIter(std::move(multiIndicesIter)), m_parent(&parent) {} std::size_t operator*() const { - std::size_t globalIndex = *m_localIndicesIter[DIM - 1]; + std::size_t flatIndex = *m_multiIndicesIter[DIM - 1]; if (DIM == 1) { - return globalIndex; + return flatIndex; } for (std::size_t i = 0; i < DIM - 1; ++i) { - globalIndex += m_parent->m_globalStrides[i] * (*m_localIndicesIter[i]); + flatIndex += m_parent->m_flatStride[i] * (*m_multiIndicesIter[i]); } - return globalIndex; + return flatIndex; } iterator& operator++() { - const auto& localIndices = m_parent->m_localIndices; + const auto& multiIndices = m_parent->m_multiIndices; - // Go to the next global index via a lexicographic increment: - // - Start by incrementing the last local index + // Go to the next flat index via a lexicographic increment: + // - Start by incrementing the last multi index // - If it reaches the end, reset it and increment the previous one... for (long i = DIM - 1; i > 0; --i) { - ++m_localIndicesIter[i]; - if (m_localIndicesIter[i] != localIndices[i].end()) { + ++m_multiIndicesIter[i]; + if (m_multiIndicesIter[i] != multiIndices[i].end()) { return *this; } - m_localIndicesIter[i] = localIndices[i].begin(); + m_multiIndicesIter[i] = multiIndices[i].begin(); } // The first index should stay at the end value when it reaches it, so // that we know when we've reached the end of iteration. - ++m_localIndicesIter[0]; + ++m_multiIndicesIter[0]; return *this; } @@ -108,9 +100,9 @@ class GlobalNeighborHoodIndices { bool isEqual(const iterator& b) const { if (b.m_parent == nullptr) { - return m_localIndicesIter[0] == m_parent->m_localIndices[0].end(); + return m_multiIndicesIter[0] == m_parent->m_multiIndices[0].end(); } else { - return m_localIndicesIter == b.m_localIndicesIter; + return m_multiIndicesIter == b.m_multiIndicesIter; } } @@ -119,30 +111,30 @@ class GlobalNeighborHoodIndices { } private: - std::array m_localIndicesIter; - const GlobalNeighborHoodIndices* m_parent = nullptr; + std::array m_multiIndicesIter; + const FlatNeighborHoodIndices* m_parent = nullptr; }; iterator begin() const { - std::array localIndicesIter{}; + std::array multiIndicesIter{}; for (std::size_t i = 0; i < DIM; ++i) { - localIndicesIter[i] = m_localIndices[i].begin(); + multiIndicesIter[i] = m_multiIndices[i].begin(); } - return iterator(*this, std::move(localIndicesIter)); + return iterator(*this, std::move(multiIndicesIter)); } iterator end() const { return iterator(); } - // Number of indices that will be produced if this sequence is iterated + /// Number of indices that will be produced if this sequence is iterated std::size_t size() const { - std::size_t result = m_localIndices[0].size(); + std::size_t result = m_multiIndices[0].size(); for (std::size_t i = 1; i < DIM; ++i) { - result *= m_localIndices[i].size(); + result *= m_multiIndices[i].size(); } return result; } - // Collect the sequence of indices into a vector + /// Collect the sequence of indices into a vector auto collect() const { boost::container::small_vector result; result.reserve(this->size()); @@ -158,75 +150,77 @@ class GlobalNeighborHoodIndices { } private: - std::array m_localIndices{}; - std::array m_globalStrides{}; + std::array m_multiIndices{}; + std::array m_flatStride{}; }; /// @cond -/// @brief helper struct to calculate number of bins inside a grid +/// helper struct to calculate number of bins inside a grid /// /// @tparam N number of axes to consider template -struct grid_helper_impl; +struct MultiAxisHelperImpl; template -struct grid_helper_impl { +struct MultiAxisHelperImpl { template static void getBinCenter( std::array& center, - const std::array& localIndices, + const std::array& multiIndex, const std::tuple& axes) { - center.at(N) = std::get(axes).getBinCenter(localIndices.at(N)); - grid_helper_impl::getBinCenter(center, localIndices, axes); + center.at(N) = std::get(axes).getBinCenter(multiIndex.at(N)); + MultiAxisHelperImpl::getBinCenter(center, multiIndex, axes); } template - static void getGlobalBin( - const std::array& localBins, + static void getFlatIndexFromMultiIndex( + const std::array& multiIndex, const std::tuple& axes, std::size_t& bin, std::size_t& area) { const auto& thisAxis = std::get(axes); - bin += area * localBins.at(N); + bin += area * multiIndex.at(N); // make sure to account for under-/overflow bins area *= (thisAxis.getNBins() + 2); - grid_helper_impl::getGlobalBin(localBins, axes, bin, area); + MultiAxisHelperImpl::getFlatIndexFromMultiIndex(multiIndex, axes, + bin, area); } template - static void getLocalBinIndices( + static void getMultiIndexFromPoint( const Point& point, const std::tuple& axes, - std::array& indices) { + std::array& multiIndex) { const auto& thisAxis = std::get(axes); - indices.at(N) = static_cast(thisAxis.getBin(point[N])); - grid_helper_impl::getLocalBinIndices(point, axes, indices); + multiIndex.at(N) = static_cast(thisAxis.getBin(point[N])); + MultiAxisHelperImpl::getMultiIndexFromPoint(point, axes, multiIndex); } template - static void getLocalBinIndices( + static void getMultiIndexFromFlatIndex( std::size_t& bin, const std::tuple& axes, std::size_t& area, - std::array& indices) { + std::array& multiIndex) { const auto& thisAxis = std::get(axes); // make sure to account for under-/overflow bins std::size_t new_area = area * (thisAxis.getNBins() + 2); - grid_helper_impl::getLocalBinIndices(bin, axes, new_area, indices); - indices.at(N) = bin / area; + MultiAxisHelperImpl::getMultiIndexFromFlatIndex(bin, axes, new_area, + multiIndex); + multiIndex.at(N) = bin / area; bin %= area; } template - static void getLowerLeftBinEdge( + static void getLowerLeftBinCorner( std::array& llEdge, - const std::array& localIndices, + const std::array& multiIndex, const std::tuple& axes) { - llEdge.at(N) = std::get(axes).getBinLowerBound(localIndices.at(N)); - grid_helper_impl::getLowerLeftBinEdge(llEdge, localIndices, axes); + llEdge.at(N) = std::get(axes).getBinLowerBound(multiIndex.at(N)); + MultiAxisHelperImpl::getLowerLeftBinCorner(llEdge, multiIndex, axes); } template static void getLowerLeftBinIndices( - std::array& localIndices, + std::array& multiIndex, const std::tuple& axes) { - localIndices.at(N) = std::get(axes).wrapBin(localIndices.at(N) - 1); - grid_helper_impl::getLowerLeftBinIndices(localIndices, axes); + multiIndex.at(N) = std::get(axes).wrapBin(multiIndex.at(N) - 1); + MultiAxisHelperImpl::getLowerLeftBinIndices(multiIndex, axes); } template @@ -234,155 +228,156 @@ struct grid_helper_impl { std::array& nBinsArray) { // by convention getNBins does not include under-/overflow bins nBinsArray[N] = std::get(axes).getNBins(); - grid_helper_impl::getNBins(axes, nBinsArray); + MultiAxisHelperImpl::getNBins(axes, nBinsArray); } template static void getAxes(const std::tuple& axes, std::array& axesArr) { axesArr[N] = static_cast(&std::get(axes)); - grid_helper_impl::getAxes(axes, axesArr); + MultiAxisHelperImpl::getAxes(axes, axesArr); } template - static void getUpperRightBinEdge( + static void getUpperRightBinCorner( std::array& urEdge, - const std::array& localIndices, + const std::array& multiIndex, const std::tuple& axes) { - urEdge.at(N) = std::get(axes).getBinUpperBound(localIndices.at(N)); - grid_helper_impl::getUpperRightBinEdge(urEdge, localIndices, axes); + urEdge.at(N) = std::get(axes).getBinUpperBound(multiIndex.at(N)); + MultiAxisHelperImpl::getUpperRightBinCorner(urEdge, multiIndex, + axes); } template static void getUpperRightBinIndices( - std::array& localIndices, + std::array& multiIndex, const std::tuple& axes) { - localIndices.at(N) = std::get(axes).wrapBin(localIndices.at(N) + 1); - grid_helper_impl::getUpperRightBinIndices(localIndices, axes); + multiIndex.at(N) = std::get(axes).wrapBin(multiIndex.at(N) + 1); + MultiAxisHelperImpl::getUpperRightBinIndices(multiIndex, axes); } template static void getMin(const std::tuple& axes, std::array& minArray) { minArray[N] = std::get(axes).getMin(); - grid_helper_impl::getMin(axes, minArray); + MultiAxisHelperImpl::getMin(axes, minArray); } template static void getMax(const std::tuple& axes, std::array& maxArray) { maxArray[N] = std::get(axes).getMax(); - grid_helper_impl::getMax(axes, maxArray); + MultiAxisHelperImpl::getMax(axes, maxArray); } template static void getWidth(const std::tuple& axes, std::array& widthArray) { widthArray[N] = std::get(axes).getBinWidth(); - grid_helper_impl::getWidth(axes, widthArray); + MultiAxisHelperImpl::getWidth(axes, widthArray); } template - static bool isInside(const Point& position, const std::tuple& axes) { - bool insideThisAxis = std::get(axes).isInside(position[N]); - return insideThisAxis && grid_helper_impl::isInside(position, axes); + static bool isInside(const Point& point, const std::tuple& axes) { + bool insideThisAxis = std::get(axes).isInside(point[N]); + return insideThisAxis && MultiAxisHelperImpl::isInside(point, axes); } template static void neighborHoodIndices( - const std::array& localIndices, + const std::array& multiIndex, std::pair sizes, const std::tuple& axes, std::array& neighborIndices) { // ask n-th axis - std::size_t locIdx = localIndices.at(N); + std::size_t locIdx = multiIndex.at(N); NeighborHoodIndices locNeighbors = std::get(axes).neighborHoodIndices(locIdx, sizes); neighborIndices.at(N) = locNeighbors; - grid_helper_impl::neighborHoodIndices(localIndices, sizes, axes, - neighborIndices); + MultiAxisHelperImpl::neighborHoodIndices(multiIndex, sizes, axes, + neighborIndices); } template static void neighborHoodIndices( - const std::array& localIndices, + const std::array& multiIndex, std::array, sizeof...(Axes)> sizes, const std::tuple& axes, std::array& neighborIndices) { // ask n-th axis - std::size_t locIdx = localIndices.at(N); + std::size_t locIdx = multiIndex.at(N); NeighborHoodIndices locNeighbors = std::get(axes).neighborHoodIndices(locIdx, sizes.at(N)); neighborIndices.at(N) = locNeighbors; - grid_helper_impl::neighborHoodIndices(localIndices, sizes, axes, - neighborIndices); + MultiAxisHelperImpl::neighborHoodIndices(multiIndex, sizes, axes, + neighborIndices); } template - static void exteriorBinIndices(std::array& idx, - std::array isExterior, - std::set& combinations, - const std::tuple& axes) { + static void exteriorBinIndices( + std::array& multiIndex, + std::array isExterior, + std::set& combinations, const std::tuple& axes) { // iterate over this axis' bins, remembering which bins are exterior for (std::size_t i = 0; i < std::get(axes).getNBins() + 2; ++i) { - idx.at(N) = i; + multiIndex.at(N) = i; isExterior.at(N) = (i == 0) || (i == std::get(axes).getNBins() + 1); // vary other axes recursively - grid_helper_impl::exteriorBinIndices(idx, isExterior, combinations, - axes); + MultiAxisHelperImpl::exteriorBinIndices(multiIndex, isExterior, + combinations, axes); } } }; template <> -struct grid_helper_impl<0u> { +struct MultiAxisHelperImpl<0u> { template static void getBinCenter( std::array& center, - const std::array& localIndices, + const std::array& multiIndex, const std::tuple& axes) { - center.at(0u) = std::get<0u>(axes).getBinCenter(localIndices.at(0u)); + center.at(0u) = std::get<0u>(axes).getBinCenter(multiIndex.at(0u)); } template - static void getGlobalBin( - const std::array& localBins, + static void getFlatIndexFromMultiIndex( + const std::array& multiIndex, const std::tuple& /*axes*/, std::size_t& bin, std::size_t& area) { - bin += area * localBins.at(0u); + bin += area * multiIndex.at(0u); } template - static void getLocalBinIndices( + static void getMultiIndexFromPoint( const Point& point, const std::tuple& axes, - std::array& indices) { + std::array& multiIndex) { const auto& thisAxis = std::get<0u>(axes); - indices.at(0u) = thisAxis.getBin(point[0u]); + multiIndex.at(0u) = thisAxis.getBin(point[0u]); } template - static void getLocalBinIndices( + static void getMultiIndexFromFlatIndex( std::size_t& bin, const std::tuple& /*axes*/, std::size_t& area, - std::array& indices) { + std::array& multiIndex) { // make sure to account for under-/overflow bins - indices.at(0u) = bin / area; + multiIndex.at(0u) = bin / area; bin %= area; } template - static void getLowerLeftBinEdge( + static void getLowerLeftBinCorner( std::array& llEdge, - const std::array& localIndices, + const std::array& multiIndex, const std::tuple& axes) { - llEdge.at(0u) = std::get<0u>(axes).getBinLowerBound(localIndices.at(0u)); + llEdge.at(0u) = std::get<0u>(axes).getBinLowerBound(multiIndex.at(0u)); } template static void getLowerLeftBinIndices( - std::array& localIndices, + std::array& multiIndex, const std::tuple& axes) { - localIndices.at(0u) = std::get<0u>(axes).wrapBin(localIndices.at(0u) - 1); + multiIndex.at(0u) = std::get<0u>(axes).wrapBin(multiIndex.at(0u) - 1); } template @@ -399,18 +394,18 @@ struct grid_helper_impl<0u> { } template - static void getUpperRightBinEdge( + static void getUpperRightBinCorner( std::array& urEdge, - const std::array& localIndices, + const std::array& multiIndex, const std::tuple& axes) { - urEdge.at(0u) = std::get<0u>(axes).getBinUpperBound(localIndices.at(0u)); + urEdge.at(0u) = std::get<0u>(axes).getBinUpperBound(multiIndex.at(0u)); } template static void getUpperRightBinIndices( - std::array& localIndices, + std::array& multiIndex, const std::tuple& axes) { - localIndices.at(0u) = std::get<0u>(axes).wrapBin(localIndices.at(0u) + 1); + multiIndex.at(0u) = std::get<0u>(axes).wrapBin(multiIndex.at(0u) + 1); } template @@ -432,17 +427,17 @@ struct grid_helper_impl<0u> { } template - static bool isInside(const Point& position, const std::tuple& axes) { - return std::get<0u>(axes).isInside(position[0u]); + static bool isInside(const Point& point, const std::tuple& axes) { + return std::get<0u>(axes).isInside(point[0u]); } template static void neighborHoodIndices( - const std::array& localIndices, + const std::array& multiIndex, std::pair sizes, const std::tuple& axes, std::array& neighborIndices) { // ask 0-th axis - std::size_t locIdx = localIndices.at(0u); + std::size_t locIdx = multiIndex.at(0u); NeighborHoodIndices locNeighbors = std::get<0u>(axes).neighborHoodIndices(locIdx, sizes); neighborIndices.at(0u) = locNeighbors; @@ -450,28 +445,29 @@ struct grid_helper_impl<0u> { template static void neighborHoodIndices( - const std::array& localIndices, + const std::array& multiIndex, std::array, sizeof...(Axes)> sizes, const std::tuple& axes, std::array& neighborIndices) { // ask 0-th axis - std::size_t locIdx = localIndices.at(0u); + std::size_t locIdx = multiIndex.at(0u); NeighborHoodIndices locNeighbors = std::get<0u>(axes).neighborHoodIndices(locIdx, sizes.at(0u)); neighborIndices.at(0u) = locNeighbors; } template - static void exteriorBinIndices(std::array& idx, - std::array isExterior, - std::set& combinations, - const std::tuple& axes) { + static void exteriorBinIndices( + std::array& multiIndex, + std::array isExterior, + std::set& combinations, const std::tuple& axes) { // For each exterior bin on this axis, we will do this auto recordExteriorBin = [&](std::size_t i) { - idx.at(0u) = i; + multiIndex.at(0u) = i; // at this point, combinations are complete: save the global bin std::size_t bin = 0, area = 1; - grid_helper_impl::getGlobalBin(idx, axes, bin, area); + MultiAxisHelperImpl::getFlatIndexFromMultiIndex( + multiIndex, axes, bin, area); combinations.insert(bin); }; @@ -498,166 +494,165 @@ struct grid_helper_impl<0u> { }; /// @endcond -/// @brief helper functions for grid-related operations -struct grid_helper { - /// @brief get the global indices for closest points on grid +/// helper functions for grid-related operations +struct MultiAxisHelper { + /// get the global indices for closest points on grid /// /// @tparam Axes parameter pack of axis types defining the grid - /// @param [in] bin global bin index for bin of interest - /// @param [in] axes actual axis objects spanning the grid + /// @param bin global bin index for bin of interest + /// @param axes actual axis objects spanning the grid /// @return Sorted collection of global bin indices for bins whose - /// lower-left corners are the closest points on the grid to every - /// point in the given bin + /// lower-left corners are the closest points on the grid to every + /// point in the given bin /// /// @note @c bin must be a valid bin index (excluding under-/overflow bins - /// along any axis). + /// along any axis). template - static GlobalNeighborHoodIndices closestPointsIndices( - const std::array& localIndices, + static FlatNeighborHoodIndices closestPointsIndices( + const std::array& multiIndex, const std::tuple& axes) { // get neighboring bins, but only increment. - return neighborHoodIndices(localIndices, std::make_pair(0, 1), axes); + return neighborHoodIndices(multiIndex, std::make_pair(0, 1), axes); } - /// @brief retrieve bin center from set of local bin indices + /// retrieve bin center from set of local bin indices /// /// @tparam Axes parameter pack of axis types defining the grid - /// @param [in] localIndices local bin indices along each axis - /// @param [in] axes actual axis objects spanning the grid + /// @param multiIndex local bin indices along each axis + /// @param axes actual axis objects spanning the grid /// @return center position of bin /// - /// @pre @c localIndices must only contain valid bin indices (i.e. excluding - /// under-/overflow bins). + /// @pre @c multiIndex must only contain valid bin indices (i.e. excluding + /// under-/overflow bins). template static std::array getBinCenter( - const std::array& localIndices, + const std::array& multiIndex, const std::tuple& axes) { std::array center{}; - grid_helper_impl::getBinCenter(center, localIndices, - axes); + MultiAxisHelperImpl::getBinCenter(center, multiIndex, + axes); return center; } - /// @brief determine global bin index from local indices along each axis + /// determine global bin index from local indices along each axis /// /// @tparam Axes parameter pack of axis types defining the grid /// - /// @param [in] localBins local bin indices along each axis - /// @param [in] axes actual axis objects spanning the grid + /// @param localBins local bin indices along each axis + /// @param axes actual axis objects spanning the grid /// @return global index for bin defined by the local bin indices /// /// @pre All local bin indices must be a valid index for the corresponding - /// axis (including the under-/overflow bin for this axis). + /// axis (including the under-/overflow bin for this axis). template - static std::size_t getGlobalBin( - const std::array& localBins, + static std::size_t getFlatIndexFromMultiIndex( + const std::array& multiIndex, const std::tuple& axes) { std::size_t area = 1; std::size_t bin = 0; - grid_helper_impl::getGlobalBin(localBins, axes, bin, - area); + MultiAxisHelperImpl::getFlatIndexFromMultiIndex( + multiIndex, axes, bin, area); return bin; } - /// @brief determine local bin index for each axis from point + /// determine local bin index for each axis from point /// /// @tparam Point any type with point semantics supporting component access - /// through @c operator[] + /// through @c operator[] /// @tparam Axes parameter pack of axis types defining the grid /// - /// @param [in] point point to look up in the grid - /// @param [in] axes actual axis objects spanning the grid + /// @param point point to look up in the grid + /// @param axes actual axis objects spanning the grid /// @return array with local bin indices along each axis (in same order as - /// given @c axes object) + /// given @c axes object) /// /// @pre The given @c Point type must represent a point in d (or higher) - /// dimensions where d is the number of axis objects in the tuple. + /// dimensions where d is the number of axis objects in the tuple. /// @note This could be a under-/overflow bin along one or more axes. template - static std::array getLocalBinIndices( + static std::array getMultiIndexFromPoint( const Point& point, const std::tuple& axes) { - std::array indices{}; + std::array multiIndex{}; - grid_helper_impl::getLocalBinIndices(point, axes, - indices); + MultiAxisHelperImpl::getMultiIndexFromPoint( + point, axes, multiIndex); - return indices; + return multiIndex; } - /// @brief determine local bin index for each axis from global bin index + /// determine local bin index for each axis from global bin index /// /// @tparam Axes parameter pack of axis types defining the grid /// - /// @param [in] bin global bin index - /// @param [in] axes actual axis objects spanning the grid + /// @param bin global bin index + /// @param axes actual axis objects spanning the grid /// @return array with local bin indices along each axis (in same order as - /// given @c axes object) + /// given @c axes object) /// /// @note Local bin indices can contain under-/overflow bins along any axis. template - static std::array getLocalBinIndices( + static std::array getMultiIndexFromFlatIndex( std::size_t bin, const std::tuple& axes) { std::size_t area = 1; - std::array indices{}; + std::array multiIndex{}; - grid_helper_impl::getLocalBinIndices(bin, axes, area, - indices); + MultiAxisHelperImpl::getMultiIndexFromFlatIndex( + bin, axes, area, multiIndex); - return indices; + return multiIndex; } - /// @brief retrieve lower-left bin edge from set of local bin indices + /// retrieve lower-left bin edge from set of local bin indices /// /// @tparam Axes parameter pack of axis types defining the grid - /// @param [in] localIndices local bin indices along each axis - /// @param [in] axes actual axis objects spanning the grid + /// @param multiIndex local bin indices along each axis + /// @param axes actual axis objects spanning the grid /// @return generalized lower-left bin edge /// - /// @pre @c localIndices must only contain valid bin indices (excluding - /// underflow bins). + /// @pre @c multiIndex must only contain valid bin indices (excluding + /// underflow bins). template - static std::array getLowerLeftBinEdge( - const std::array& localIndices, + static std::array getLowerLeftBinCorner( + const std::array& multiIndex, const std::tuple& axes) { std::array llEdge{}; - grid_helper_impl::getLowerLeftBinEdge( - llEdge, localIndices, axes); + MultiAxisHelperImpl::getLowerLeftBinCorner( + llEdge, multiIndex, axes); return llEdge; } - /// @brief get local bin indices for lower-left neighboring bin + /// get local bin indices for lower-left neighboring bin /// /// @tparam Axes parameter pack of axis types defining the grid - /// @param [in] localIndices local bin indices along each axis - /// @param [in] axes actual axis objects spanning the grid + /// @param multiIndex local bin indices along each axis + /// @param axes actual axis objects spanning the grid /// @return array with local bin indices of lower-left neighbor bin /// - /// @pre @c localIndices must only contain valid bin indices (excluding - /// underflow bins). + /// @pre @c multiIndex must only contain valid bin indices (excluding + /// underflow bins). /// /// This function returns the local bin indices for the generalized /// lower-left neighbor which simply means that all local bin indices are /// decremented by one. template static std::array getLowerLeftBinIndices( - const std::array& localIndices, + const std::array& multiIndex, const std::tuple& axes) { - auto llIndices = localIndices; - grid_helper_impl::getLowerLeftBinIndices(llIndices, - axes); + auto llIndices = multiIndex; + MultiAxisHelperImpl::getLowerLeftBinIndices(llIndices, + axes); return llIndices; } - /// @brief calculate number of bins in a grid defined by a set of - /// axes for each axis + /// calculate number of bins in a grid defined by a set of axes for each axis /// /// @tparam Axes parameter pack of axis types defining the grid - /// @param [in] axes actual axis objects spanning the grid + /// @param axes actual axis objects spanning the grid /// @return array of number of bins for each axis of the grid /// /// @note This does not include under-/overflow bins along each axis. @@ -665,226 +660,222 @@ struct grid_helper { static std::array getNBins( const std::tuple& axes) { std::array nBinsArray{}; - grid_helper_impl::getNBins(axes, nBinsArray); + MultiAxisHelperImpl::getNBins(axes, nBinsArray); return nBinsArray; } - /// @brief return an array with copies of the axes, converted - /// to type AnyAxis + /// return an array with copies of the axes, converted to type AnyAxis /// /// @tparam Axes parameter pack of axis types defining the grid - /// @param [in] axes actual axis objects spanning the grid + /// @param axes actual axis objects spanning the grid /// @return array with copies of the axis template static std::array getAxes( const std::tuple& axes) { std::array arr{}; - grid_helper_impl::getAxes(axes, arr); + MultiAxisHelperImpl::getAxes(axes, arr); return arr; } - /// @brief retrieve upper-right bin edge from set of local bin indices + /// retrieve upper-right bin edge from set of local bin indices /// /// @tparam Axes parameter pack of axis types defining the grid - /// @param [in] localIndices local bin indices along each axis - /// @param [in] axes actual axis objects spanning the grid + /// @param multiIndex local bin indices along each axis + /// @param axes actual axis objects spanning the grid /// @return generalized upper-right bin edge /// - /// @pre @c localIndices must only contain valid bin indices (excluding + /// @pre @c multiIndex must only contain valid bin indices (excluding /// overflow bins). template - static std::array getUpperRightBinEdge( - const std::array& localIndices, + static std::array getUpperRightBinCorner( + const std::array& multiIndex, const std::tuple& axes) { std::array urEdge{}; - grid_helper_impl::getUpperRightBinEdge( - urEdge, localIndices, axes); + MultiAxisHelperImpl::getUpperRightBinCorner( + urEdge, multiIndex, axes); return urEdge; } - /// @brief get local bin indices for upper-right neighboring bin + /// get local bin indices for upper-right neighboring bin + /// + /// @note This function returns the local bin indices for the generalized + /// upper-right neighbor which simply means that all local bin indices are + /// incremented by one. /// /// @tparam Axes parameter pack of axis types defining the grid - /// @param [in] localIndices local bin indices along each axis - /// @param [in] axes actual axis objects spanning the grid + /// @param multiIndex local bin indices along each axis + /// @param axes axis objects spanning the grid /// @return array with local bin indices of upper-right neighbor bin /// - /// @pre @c localIndices must only contain valid bin indices (excluding + /// @pre @c multiIndex must only contain valid bin indices (excluding /// overflow bins). - /// - /// This function returns the local bin indices for the generalized - /// upper-right neighbor which simply means that all local bin indices are - /// incremented by one. template static std::array getUpperRightBinIndices( - const std::array& localIndices, + const std::array& multiIndex, const std::tuple& axes) { - auto urIndices = localIndices; - grid_helper_impl::getUpperRightBinIndices(urIndices, - axes); + auto urIndices = multiIndex; + MultiAxisHelperImpl::getUpperRightBinIndices(urIndices, + axes); return urIndices; } - /// @brief get the minimum value of all axes of one grid + /// get the minimum value of all axes of one grid /// /// @tparam Axes parameter pack of axis types defining the grid - /// @param [in] axes actual axis objects spanning the grid + /// @param axes actual axis objects spanning the grid /// @return array returning the minima of all given axes template static std::array getMin( const std::tuple& axes) { std::array minArray{}; - grid_helper_impl::getMin(axes, minArray); + MultiAxisHelperImpl::getMin(axes, minArray); return minArray; } - /// @brief get the maximum value of all axes of one grid + /// get the maximum value of all axes of one grid /// /// @tparam Axes parameter pack of axis types defining the grid - /// @param [in] axes actual axis objects spanning the grid + /// @param axes actual axis objects spanning the grid /// @return array returning the maxima of all given axes template static std::array getMax( const std::tuple& axes) { std::array maxArray{}; - grid_helper_impl::getMax(axes, maxArray); + MultiAxisHelperImpl::getMax(axes, maxArray); return maxArray; } - /// @brief get the bin width of all axes of one grid + /// get the bin width of all axes of one grid /// /// @tparam Axes parameter pack of axis types defining the grid - /// @param [in] axes actual axis objects spanning the grid + /// @param axes actual axis objects spanning the grid /// @return array returning the maxima of all given axes template static std::array getWidth( const std::tuple& axes) { std::array widthArray{}; - grid_helper_impl::getWidth(axes, widthArray); + MultiAxisHelperImpl::getWidth(axes, widthArray); return widthArray; } - /// @brief get global bin indices for bins in specified neighborhood + /// get global bin indices for bins in specified neighborhood /// /// @tparam Axes parameter pack of axis types defining the grid - /// @param [in] localIndices local bin indices along each axis - /// @param [in] size size of neighborhood determining how many - /// adjacent bins along each axis are considered - /// @param [in] axes actual axis objects spanning the grid + /// @param multiIndex local bin indices along each axis + /// @param size size of neighborhood determining how many + /// adjacent bins along each axis are considered + /// @param axes actual axis objects spanning the grid /// @return Sorted collection of global bin indices for all bins in - /// the neighborhood + /// the neighborhood /// /// @note Over-/underflow bins are included in the neighborhood. /// @note The @c size parameter sets the range by how many units each local - /// bin index is allowed to be varied. All local bin indices are - /// varied independently, that is diagonal neighbors are included. - /// Ignoring the truncation of the neighborhood size reaching beyond - /// over-/underflow bins, the neighborhood is of size \f$2 \times - /// \text{size}+1\f$ along each dimension. + /// bin index is allowed to be varied. All local bin indices are + /// varied independently, that is diagonal neighbors are included. + /// Ignoring the truncation of the neighborhood size reaching beyond + /// over-/underflow bins, the neighborhood is of size \f$2 \times + /// \text{size}+1\f$ along each dimension. /// @note The concrete bins which are returned depend on the WrappingTypes - /// of the contained axes - /// + /// of the contained axes template - static GlobalNeighborHoodIndices neighborHoodIndices( - const std::array& localIndices, + static FlatNeighborHoodIndices neighborHoodIndices( + const std::array& multiIndex, std::pair sizes, const std::tuple& axes) { // length N array which contains local neighbors based on size par std::array neighborIndices{}; // get local bin indices for neighboring bins - grid_helper_impl::neighborHoodIndices( - localIndices, sizes, axes, neighborIndices); + MultiAxisHelperImpl::neighborHoodIndices( + multiIndex, sizes, axes, neighborIndices); // Query the number of bins std::array nBinsArray = getNBins(axes); // Produce iterator of global indices - return GlobalNeighborHoodIndices(neighborIndices, nBinsArray); + return FlatNeighborHoodIndices(neighborIndices, nBinsArray); } template - static GlobalNeighborHoodIndices neighborHoodIndices( - const std::array& localIndices, + static FlatNeighborHoodIndices neighborHoodIndices( + const std::array& multiIndex, std::size_t size, const std::tuple& axes) { return neighborHoodIndices( - localIndices, std::make_pair(-static_cast(size), size), axes); + multiIndex, std::make_pair(-static_cast(size), size), axes); } - /// @brief get global bin indices for bins in specified neighborhood - /// for each axis + /// get global bin indices for bins in specified neighborhood for each axis /// /// @tparam Axes parameter pack of axis types defining the grid - /// @param [in] localIndices local bin indices along each axis - /// @param [in] size size of neighborhood for each axis, which - /// bins along each axis are considered - /// @param [in] axes actual axis objects spanning the grid + /// @param multiIndex local bin indices along each axis + /// @param size size of neighborhood for each axis, which + /// bins along each axis are considered + /// @param axes actual axis objects spanning the grid /// @return Sorted collection of global bin indices for all bins in - /// the neighborhood + /// the neighborhood /// /// @note Over-/underflow bins are included in the neighborhood. /// @note The @c size parameter sets the range by how many units each local - /// bin index is allowed to be varied. All local bin indices are - /// varied independently, that is diagonal neighbors are included. - /// Ignoring the truncation of the neighborhood size reaching beyond - /// over-/underflow bins, the neighborhood is of size \f$2 \times - /// \text{size}+1\f$ along each dimension. + /// bin index is allowed to be varied. All local bin indices are + /// varied independently, that is diagonal neighbors are included. + /// Ignoring the truncation of the neighborhood size reaching beyond + /// over-/underflow bins, the neighborhood is of size \f$2 \times + /// \text{size}+1\f$ along each dimension. /// @note The concrete bins which are returned depend on the WrappingTypes - /// of the contained axes - /// + /// of the contained axes template - static GlobalNeighborHoodIndices neighborHoodIndices( - const std::array& localIndices, + static FlatNeighborHoodIndices neighborHoodIndices( + const std::array& multiIndex, std::array, sizeof...(Axes)>& sizes, const std::tuple& axes) { // length N array which contains local neighbors based on size par std::array neighborIndices{}; // get local bin indices for neighboring bins - grid_helper_impl::neighborHoodIndices( - localIndices, sizes, axes, neighborIndices); + MultiAxisHelperImpl::neighborHoodIndices( + multiIndex, sizes, axes, neighborIndices); // Query the number of bins std::array nBinsArray = getNBins(axes); // Produce iterator of global indices - return GlobalNeighborHoodIndices(neighborIndices, nBinsArray); + return FlatNeighborHoodIndices(neighborIndices, nBinsArray); } - /// @brief get bin indices of all overflow and underflow bins + /// get bin indices of all overflow and underflow bins /// /// @tparam Axes parameter pack of axis types defining the grid - /// @param [in] axes actual axis objects spanning the grid + /// @param axes actual axis objects spanning the grid /// @return set of global bin indices for all over- and underflow bins template static std::set exteriorBinIndices( const std::tuple& axes) { - std::array idx{}; + std::array multiIndex{}; std::array isExterior{}; std::set combinations; - grid_helper_impl::exteriorBinIndices( - idx, isExterior, combinations, axes); + MultiAxisHelperImpl::exteriorBinIndices( + multiIndex, isExterior, combinations, axes); return combinations; } - /// @brief check whether given point is inside axes limits + /// check whether given point is inside axes limits /// /// @tparam Point any type with point semantics supporting component access - /// through @c operator[] + /// through @c operator[] /// @tparam Axes parameter pack of axis types defining the grid /// - /// @param [in] position point to look up in the grid - /// @param [in] axes actual axis objects spanning the grid + /// @param point point to look up in the grid + /// @param axes actual axis objects spanning the grid /// @return @c true if \f$\text{xmin_i} \le x_i < \text{xmax}_i \forall i=0, - /// \dots, d-1\f$, otherwise @c false + /// \dots, d-1\f$, otherwise @c false /// /// @pre The given @c Point type must represent a point in d (or higher) - /// dimensions where d is the number of axis objects in the tuple. + /// dimensions where d is the number of axis objects in the tuple. template - static bool isInside(const Point& position, const std::tuple& axes) { + static bool isInside(const Point& point, const std::tuple& axes) { constexpr std::size_t MAX = sizeof...(Axes) - 1; - return grid_helper_impl::isInside(position, axes); + return MultiAxisHelperImpl::isInside(point, axes); } }; diff --git a/Core/src/Surfaces/SurfaceArray.cpp b/Core/src/Surfaces/SurfaceArray.cpp index 1d6bbbd7eae..3f15d56dd9e 100644 --- a/Core/src/Surfaces/SurfaceArray.cpp +++ b/Core/src/Surfaces/SurfaceArray.cpp @@ -15,7 +15,7 @@ #include "Acts/Utilities/Helpers.hpp" #include "Acts/Utilities/IAxis.hpp" #include "Acts/Utilities/Ranges.hpp" -#include "Acts/Utilities/detail/grid_helper.hpp" +#include "Acts/Utilities/detail/MultiAxisHelper.hpp" #include #include @@ -346,26 +346,28 @@ struct SurfaceGridLookupImpl final : SurfaceArray::ISurfaceGridLookup { } GridIndex localBinsFromPosition2D(const GridPoint& point) const { - return detail::grid_helper::getLocalBinIndices(point, m_axes); + return detail::MultiAxisHelper::getMultiIndexFromPoint(point, m_axes); } GridIndex localBinsFromGlobalBin2D(std::size_t globalBin) const { - return detail::grid_helper::getLocalBinIndices(globalBin, m_axes); + return detail::MultiAxisHelper::getMultiIndexFromFlatIndex(globalBin, + m_axes); } std::size_t globalBinFromLocalBins2D(const GridIndex& localBins) const { - return detail::grid_helper::getGlobalBin(localBins, m_axes); + return detail::MultiAxisHelper::getFlatIndexFromMultiIndex(localBins, + m_axes); } std::size_t globalBinFromLocalBins3D(const GridIndex& localBins, std::uint8_t neighborDistance) const { const std::size_t globalGridBin = - detail::grid_helper::getGlobalBin(localBins, m_axes); + detail::MultiAxisHelper::getFlatIndexFromMultiIndex(localBins, m_axes); return globalGridBin * (m_maxNeighborDistance + 1) + neighborDistance; } GridPoint binCenter(const GridIndex& localBins) const { - return detail::grid_helper::getBinCenter(localBins, m_axes); + return detail::MultiAxisHelper::getBinCenter(localBins, m_axes); } /// map surface center to grid @@ -391,7 +393,7 @@ struct SurfaceGridLookupImpl final : SurfaceArray::ISurfaceGridLookup { const Surface& surface, std::size_t startBin) { const GridIndex startIndices = localBinsFromGlobalBin2D(startBin); const auto startNeighborIndices = - detail::grid_helper::neighborHoodIndices(startIndices, 1u, m_axes); + detail::MultiAxisHelper::neighborHoodIndices(startIndices, 1u, m_axes); std::set visited({startBin}); std::vector queue(startNeighborIndices.begin(), @@ -422,8 +424,8 @@ struct SurfaceGridLookupImpl final : SurfaceArray::ISurfaceGridLookup { } m_fillingGrid.at(current).push_back(&surface); - const auto neighborIndices = - detail::grid_helper::neighborHoodIndices(currentIndices, 1u, m_axes); + const auto neighborIndices = detail::MultiAxisHelper::neighborHoodIndices( + currentIndices, 1u, m_axes); queue.insert(queue.end(), neighborIndices.begin(), neighborIndices.end()); } } @@ -451,7 +453,8 @@ struct SurfaceGridLookupImpl final : SurfaceArray::ISurfaceGridLookup { neighborDistance <= m_maxNeighborDistance; ++neighborDistance) { surfacePack.clear(); - for (const std::size_t idx : detail::grid_helper::neighborHoodIndices( + for (const std::size_t idx : + detail::MultiAxisHelper::neighborHoodIndices( indices, neighborDistance, m_axes)) { const std::vector& binContent = m_fillingGrid.at(idx); std::copy(binContent.begin(), binContent.end(), diff --git a/Examples/Detectors/MagneticField/include/ActsExamples/MagneticField/MagneticField.hpp b/Examples/Detectors/MagneticField/include/ActsExamples/MagneticField/MagneticField.hpp index 9e1997e97a2..5431ccafae4 100644 --- a/Examples/Detectors/MagneticField/include/ActsExamples/MagneticField/MagneticField.hpp +++ b/Examples/Detectors/MagneticField/include/ActsExamples/MagneticField/MagneticField.hpp @@ -9,20 +9,9 @@ #pragma once #include "Acts/Definitions/Algebra.hpp" -#include "Acts/MagneticField/ConstantBField.hpp" #include "Acts/MagneticField/InterpolatedBFieldMap.hpp" -#include "Acts/MagneticField/MagneticFieldProvider.hpp" -#include "Acts/MagneticField/NullBField.hpp" -#include "Acts/Utilities/Axis.hpp" #include "Acts/Utilities/AxisDefinitions.hpp" #include "Acts/Utilities/Grid.hpp" -#include "Acts/Utilities/Result.hpp" -#include "Acts/Utilities/detail/grid_helper.hpp" -#include "ActsExamples/MagneticField/ScalableBField.hpp" - -#include -#include -#include namespace ActsExamples::detail { diff --git a/Tests/UnitTests/Core/Utilities/GridTests.cpp b/Tests/UnitTests/Core/Utilities/GridTests.cpp index 953393022c8..196e442f6bf 100644 --- a/Tests/UnitTests/Core/Utilities/GridTests.cpp +++ b/Tests/UnitTests/Core/Utilities/GridTests.cpp @@ -8,19 +8,15 @@ #include -#include "Acts/Definitions/Algebra.hpp" #include "Acts/Utilities/Axis.hpp" #include "Acts/Utilities/AxisDefinitions.hpp" #include "Acts/Utilities/Grid.hpp" -#include "Acts/Utilities/detail/grid_helper.hpp" #include "ActsTests/CommonHelpers/FloatComparisons.hpp" -#include #include #include #include #include -#include #include #include #include From dd781ff96db19351e0208793121197fc8c078c34 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Wed, 3 Jun 2026 16:45:46 +0200 Subject: [PATCH 2/6] fix docs --- Core/include/Acts/Utilities/MathHelpers.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Core/include/Acts/Utilities/MathHelpers.hpp b/Core/include/Acts/Utilities/MathHelpers.hpp index a2b96bd1418..5b71550b182 100644 --- a/Core/include/Acts/Utilities/MathHelpers.hpp +++ b/Core/include/Acts/Utilities/MathHelpers.hpp @@ -265,6 +265,11 @@ inline double sinc(double x) { return std::sin(x) / x; } +/// Calculate the integer power of a number at compile time using recursion. +/// @tparam T The type of the base number, which should support multiplication and negation if negative powers are used +/// @param num The base number to be raised to a power +/// @param pow The exponent to which the base number is raised +/// @return The result of num raised to the power of pow template constexpr T ipow(T num, unsigned int pow) { return (pow >= sizeof(unsigned int) * 8) ? 0 From 2faea4265c3fbfe101f769abf79e509c36895cac Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Wed, 3 Jun 2026 16:58:59 +0200 Subject: [PATCH 3/6] improve ipow doc and impl --- Core/include/Acts/Utilities/MathHelpers.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Core/include/Acts/Utilities/MathHelpers.hpp b/Core/include/Acts/Utilities/MathHelpers.hpp index 5b71550b182..b3519340d8c 100644 --- a/Core/include/Acts/Utilities/MathHelpers.hpp +++ b/Core/include/Acts/Utilities/MathHelpers.hpp @@ -266,15 +266,13 @@ inline double sinc(double x) { } /// Calculate the integer power of a number at compile time using recursion. -/// @tparam T The type of the base number, which should support multiplication and negation if negative powers are used +/// @tparam T The type of the base number, which should support multiplication by itself /// @param num The base number to be raised to a power /// @param pow The exponent to which the base number is raised /// @return The result of num raised to the power of pow template constexpr T ipow(T num, unsigned int pow) { - return (pow >= sizeof(unsigned int) * 8) ? 0 - : pow == 0 ? 1 - : num * ipow(num, pow - 1); + return (pow == 0) ? 1 : num * ipow(num, pow - 1); } } // namespace Acts From d3c0cd981626835dfe8b9613492501322d8357eb Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Fri, 5 Jun 2026 17:27:58 +0200 Subject: [PATCH 4/6] fix --- Core/include/Acts/Seeding/SeedFinder.hpp | 11 +++++------ Core/include/Acts/Seeding/SeedFinder.ipp | 6 ++++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Core/include/Acts/Seeding/SeedFinder.hpp b/Core/include/Acts/Seeding/SeedFinder.hpp index c32c8e0a87e..5483217040a 100644 --- a/Core/include/Acts/Seeding/SeedFinder.hpp +++ b/Core/include/Acts/Seeding/SeedFinder.hpp @@ -17,6 +17,7 @@ #include "Acts/Seeding/SeedFinderUtils.hpp" #include "Acts/Seeding/detail/UtilityFunctions.hpp" #include "Acts/Utilities/Logger.hpp" +#include "Acts/Utilities/MathHelpers.hpp" #include "Acts/Utilities/RangeXD.hpp" #include @@ -75,12 +76,10 @@ SeedFinder { /// Managing seed candidates for SpM CandidatesForMiddleSp candidatesCollector{}; /// Managing bottom doublet candidates - boost::container::small_vector, - detail::ipow(3, grid_t::DIM)> + boost::container::small_vector, ipow(3, grid_t::DIM)> bottomNeighbours{}; /// Managing top doublet candidates - boost::container::small_vector, - detail::ipow(3, grid_t::DIM)> + boost::container::small_vector, ipow(3, grid_t::DIM)> topNeighbours{}; /// Mutable variables for Space points used in the seeding @@ -148,8 +147,8 @@ SeedFinder { void getCompatibleDoublets( const SeedFinderOptions& options, const grid_t& grid, SpacePointMutableData& mutableData, - boost::container::small_vector< - Neighbour, detail::ipow(3, grid_t::DIM)>& otherSPsNeighbours, + boost::container::small_vector, ipow(3, grid_t::DIM)>& + otherSPsNeighbours, const external_space_point_t& mediumSP, std::vector& linCircleVec, out_range_t& outVec, const float deltaRMinSP, const float deltaRMaxSP, const float uIP, diff --git a/Core/include/Acts/Seeding/SeedFinder.ipp b/Core/include/Acts/Seeding/SeedFinder.ipp index 8d19d6ee692..22067fae7d0 100644 --- a/Core/include/Acts/Seeding/SeedFinder.ipp +++ b/Core/include/Acts/Seeding/SeedFinder.ipp @@ -10,6 +10,8 @@ #include "Acts/Seeding/SeedFinder.hpp" +#include "Acts/Utilities/MathHelpers.hpp" + #include #include @@ -205,8 +207,8 @@ inline void SeedFinder::getCompatibleDoublets( const SeedFinderOptions& options, const grid_t& grid, SpacePointMutableData& mutableData, - boost::container::small_vector< - Neighbour, detail::ipow(3, grid_t::DIM)>& otherSPsNeighbours, + boost::container::small_vector, ipow(3, grid_t::DIM)>& + otherSPsNeighbours, const external_space_point_t& mediumSP, std::vector& linCircleVec, out_range_t& outVec, const float deltaRMinSP, const float deltaRMaxSP, const float uIP, From 5ffdfc3d7c9041b513bd39d35e1eef2bbb6b3b29 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Sun, 7 Jun 2026 11:13:54 +0200 Subject: [PATCH 5/6] pr feedback --- Core/include/Acts/Utilities/MathHelpers.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/include/Acts/Utilities/MathHelpers.hpp b/Core/include/Acts/Utilities/MathHelpers.hpp index b3519340d8c..f17f5984a86 100644 --- a/Core/include/Acts/Utilities/MathHelpers.hpp +++ b/Core/include/Acts/Utilities/MathHelpers.hpp @@ -266,12 +266,13 @@ inline double sinc(double x) { } /// Calculate the integer power of a number at compile time using recursion. +/// @todo std::pow() will be constexpr in C++26 and this function can be removed /// @tparam T The type of the base number, which should support multiplication by itself /// @param num The base number to be raised to a power /// @param pow The exponent to which the base number is raised /// @return The result of num raised to the power of pow template -constexpr T ipow(T num, unsigned int pow) { +consteval T ipow(T num, unsigned int pow) { return (pow == 0) ? 1 : num * ipow(num, pow - 1); } From dfc9699630c4785307d2c9020c2d6e3d2e66be1f Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 8 Jun 2026 10:30:27 +0200 Subject: [PATCH 6/6] minor --- Core/include/Acts/Seeding/BinnedGroupIterator.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Core/include/Acts/Seeding/BinnedGroupIterator.hpp b/Core/include/Acts/Seeding/BinnedGroupIterator.hpp index f2d09db03d5..63b0d859af3 100644 --- a/Core/include/Acts/Seeding/BinnedGroupIterator.hpp +++ b/Core/include/Acts/Seeding/BinnedGroupIterator.hpp @@ -76,10 +76,6 @@ class BinnedGroupIterator { boost::container::small_vector> operator*() const; - private: - /// @brief Move to the next not-empty bin in the grid - void findNotEmptyBin(); - private: /// @brief The group that contains the grid and the bin finders detail::RefHolder> m_group{nullptr}; @@ -87,6 +83,9 @@ class BinnedGroupIterator { typename grid_t::local_iterator_t m_gridItr; /// @brief End iterator; typename grid_t::local_iterator_t m_gridItrEnd; + + /// @brief Move to the next not-empty bin in the grid + void findNotEmptyBin(); }; } // namespace Acts