From 664add397ab2ca312f9c776fcb578a9d84c1e8c3 Mon Sep 17 00:00:00 2001 From: Carlo Varni <75478407+CarloVarni@users.noreply.github.com> Date: Fri, 15 Dec 2023 16:15:38 +0100 Subject: [PATCH] feat: generic Grid iterator (#2718) Just an idea @andiwand @paulgessinger @LuisFelipeCoelho @noemina This adds two grid iterators: - A global iterator that simply runs on the global index. As such you also run on the under/over flow bins - A local iterator that uses instead local indexes. This one avoids under/over flow bins The cool thing about the local one is that is also allows for a custom navigation pattern for any axis. This is currently done for the Z azis where we jump from the first bins, then the last bins and then the central Z bins in the grid Still a draft since I need to add a few things. But opening anyway to get additional feedbacks --- Core/include/Acts/Seeding/BinnedSPGroup.hpp | 32 +- Core/include/Acts/Seeding/BinnedSPGroup.ipp | 118 ++-- Core/include/Acts/Utilities/Grid.hpp | 31 + Core/include/Acts/Utilities/GridIterator.hpp | 127 ++++ Core/include/Acts/Utilities/GridIterator.ipp | 249 +++++++ Tests/UnitTests/Core/Utilities/CMakeLists.txt | 1 + .../Core/Utilities/GridIterationTests.cpp | 651 ++++++++++++++++++ .../Cuda/Seeding/SeedFinderCudaTest.cpp | 15 +- .../UnitTests/Plugins/Cuda/Seeding2/main.cpp | 16 +- 9 files changed, 1155 insertions(+), 85 deletions(-) create mode 100644 Core/include/Acts/Utilities/GridIterator.hpp create mode 100644 Core/include/Acts/Utilities/GridIterator.ipp create mode 100644 Tests/UnitTests/Core/Utilities/GridIterationTests.cpp diff --git a/Core/include/Acts/Seeding/BinnedSPGroup.hpp b/Core/include/Acts/Seeding/BinnedSPGroup.hpp index b04135c202f..cc10a493db7 100644 --- a/Core/include/Acts/Seeding/BinnedSPGroup.hpp +++ b/Core/include/Acts/Seeding/BinnedSPGroup.hpp @@ -14,6 +14,7 @@ #include "Acts/Seeding/Seed.hpp" #include "Acts/Seeding/SeedFinderConfig.hpp" #include "Acts/Seeding/SpacePointGrid.hpp" +#include "Acts/Utilities/GridIterator.hpp" #include "Acts/Utilities/Holders.hpp" #include @@ -39,9 +40,12 @@ class BinnedSPGroupIterator { public: // Never take ownerships BinnedSPGroupIterator(BinnedSPGroup&& group, - std::size_t) = delete; + std::array index, + std::array, 2> navigation) = + delete; BinnedSPGroupIterator(BinnedSPGroup& group, - std::size_t index); + std::array index, + std::array, 2> navigation); BinnedSPGroupIterator(const BinnedSPGroupIterator&) = delete; BinnedSPGroupIterator& operator=(const BinnedSPGroupIterator&) = delete; @@ -66,10 +70,12 @@ class BinnedSPGroupIterator { private: // The group, it contains the grid and the bin finders Acts::detail::RefHolder> m_group; - // Max Local Bins - limits of the grid - std::array m_max_localBins; - // Current Local Bins - std::array m_current_localBins{0, 0}; + // Current grid iterator + typename Acts::SpacePointGrid::local_iterator_t + m_gridItr; + // End iterator + typename Acts::SpacePointGrid::local_iterator_t + m_gridItrEnd; }; /// @c BinnedSPGroup Provides access to begin and end BinnedSPGroupIterator @@ -81,6 +87,8 @@ class BinnedSPGroup { friend BinnedSPGroupIterator; #endif + enum INDEX : int { PHI = 0, Z = 1 }; + public: BinnedSPGroup() = delete; @@ -119,17 +127,19 @@ class BinnedSPGroup { private: // grid with ownership of all InternalSpacePoint - std::unique_ptr> m_grid; + std::unique_ptr> m_grid{nullptr}; // BinFinder must return std::vector with content of // each bin sorted in r (ascending) - std::shared_ptr> m_topBinFinder; - std::shared_ptr> m_bottomBinFinder; + std::shared_ptr> m_topBinFinder{ + nullptr}; + std::shared_ptr> m_bottomBinFinder{ + nullptr}; // Order of z bins to loop over when searching for SPs - std::vector m_bins; + std::array, 2> m_bins{}; // Number of Z bins to skip the search for middle SP - std::size_t m_skipZMiddleBin; + std::size_t m_skipZMiddleBin{0ul}; }; } // namespace Acts diff --git a/Core/include/Acts/Seeding/BinnedSPGroup.ipp b/Core/include/Acts/Seeding/BinnedSPGroup.ipp index 0f10a0b3483..4402a8375cc 100644 --- a/Core/include/Acts/Seeding/BinnedSPGroup.ipp +++ b/Core/include/Acts/Seeding/BinnedSPGroup.ipp @@ -12,29 +12,23 @@ template Acts::BinnedSPGroupIterator::BinnedSPGroupIterator( - Acts::BinnedSPGroup& group, std::size_t index) - : m_group(group), m_max_localBins(m_group->m_grid->numLocalBins()) { - m_max_localBins[INDEX::PHI] += 1; - m_current_localBins[INDEX::Z] = m_group->skipZMiddleBin(); - if (index == m_group->m_grid->size()) { - m_current_localBins = m_max_localBins; - } else { - // Go to the next not-empty bin - findNotEmptyBin(); - } + Acts::BinnedSPGroup& group, + std::array index, + std::array, 2> navigation) + : m_group(group), m_gridItr(*group.m_grid.get(), index, navigation) { + std::array endline{}; + endline[0ul] = navigation[0ul].size(); + endline[1ul] = navigation[1ul].size(); + m_gridItrEnd = + typename Acts::SpacePointGrid::local_iterator_t( + *group.m_grid.get(), endline, std::move(navigation)); + findNotEmptyBin(); } template inline Acts::BinnedSPGroupIterator& Acts::BinnedSPGroupIterator::operator++() { - // Increase the position by one - // if we were on the edge, go up one phi bin and reset z bin - if (++m_current_localBins[INDEX::Z] == m_max_localBins[INDEX::Z]) { - ++m_current_localBins[INDEX::PHI]; - m_current_localBins[INDEX::Z] = m_group->skipZMiddleBin(); - } - - // Get the next not-empty bin in the grid + ++m_gridItr; findNotEmptyBin(); return *this; } @@ -42,10 +36,7 @@ Acts::BinnedSPGroupIterator::operator++() { template inline bool Acts::BinnedSPGroupIterator::operator==( const Acts::BinnedSPGroupIterator& other) const { - return m_group.ptr == other.m_group.ptr && - m_current_localBins[INDEX::PHI] == - other.m_current_localBins[INDEX::PHI] && - m_current_localBins[INDEX::Z] == other.m_current_localBins[INDEX::Z]; + return m_group.ptr == other.m_group.ptr && m_gridItr == other.m_gridItr; } template @@ -59,20 +50,18 @@ std::tuple, std::size_t, boost::container::small_vector> Acts::BinnedSPGroupIterator::operator*() const { // Global Index - std::size_t global_index = m_group->m_grid->globalBinFromLocalBins( - {m_current_localBins[INDEX::PHI], - m_group->m_bins[m_current_localBins[INDEX::Z]]}); + std::array localPosition = m_gridItr.localPosition(); + std::size_t global_index = + m_group->m_grid->globalBinFromLocalBins(localPosition); boost::container::small_vector bottoms = - m_group->m_bottomBinFinder->findBins( - m_current_localBins[INDEX::PHI], - m_group->m_bins[m_current_localBins[INDEX::Z]], - m_group->m_grid.get()); + m_group->m_bottomBinFinder->findBins(localPosition[INDEX::PHI], + localPosition[INDEX::Z], + m_group->m_grid.get()); boost::container::small_vector tops = - m_group->m_topBinFinder->findBins( - m_current_localBins[INDEX::PHI], - m_group->m_bins[m_current_localBins[INDEX::Z]], - m_group->m_grid.get()); + m_group->m_topBinFinder->findBins(localPosition[INDEX::PHI], + localPosition[INDEX::Z], + m_group->m_grid.get()); // GCC12+ in Release throws an overread warning here due to the move. // This is from inside boost code, so best we can do is to suppress it. @@ -89,37 +78,15 @@ Acts::BinnedSPGroupIterator::operator*() const { template inline void Acts::BinnedSPGroupIterator::findNotEmptyBin() { + if (m_gridItr == m_gridItrEnd) { + return; + } // Iterate on the grid till we find a not-empty bin // We start from the current bin configuration and move forward - - for (std::size_t phiBin(m_current_localBins[INDEX::PHI]); - phiBin < m_max_localBins[INDEX::PHI]; ++phiBin) { - // 0 is the underflow - skip - if (phiBin == 0) { - continue; - } - - for (std::size_t zBin(m_current_localBins[INDEX::Z]); - zBin < m_max_localBins[INDEX::Z]; ++zBin) { - std::size_t zBinIndex = m_group->m_bins[zBin]; - std::size_t index = - m_group->m_grid->globalBinFromLocalBins({phiBin, zBinIndex}); - // Check if there are entries in this bin - if (m_group->m_grid->at(index).empty()) { - continue; - } - - // Set the new current bins - m_current_localBins[INDEX::PHI] = phiBin; - m_current_localBins[INDEX::Z] = zBin; - return; - } - // Reset z-index - m_current_localBins[INDEX::Z] = m_group->skipZMiddleBin(); + std::size_t dimCollection = (*m_gridItr).size(); + while (dimCollection == 0ul && ++m_gridItr != m_gridItrEnd) { + dimCollection = (*m_gridItr).size(); } - - // Could find nothing ... setting this to end() - m_current_localBins = m_max_localBins; } // Binned SP Group @@ -231,13 +198,21 @@ Acts::BinnedSPGroup::BinnedSPGroup( m_topBinFinder = tBinFinder; m_skipZMiddleBin = config.skipZMiddleBinSearch; - m_bins = config.zBinsCustomLooping; - if (m_bins.empty()) { - std::size_t nZbins = m_grid->numLocalBins()[1]; - m_bins.reserve(nZbins); - for (std::size_t i(0); i < nZbins; ++i) { - m_bins.push_back(i + 1); - } + + // phi axis + m_bins[INDEX::PHI].resize(m_grid->numLocalBins()[0]); + std::iota(m_bins[INDEX::PHI].begin(), m_bins[INDEX::PHI].end(), 1ul); + + // z axis + if (config.zBinsCustomLooping.empty()) { + std::size_t nZbins = m_grid->numLocalBins()[1] - m_skipZMiddleBin; + m_bins[INDEX::Z] = std::vector(nZbins); + std::iota(m_bins[INDEX::Z].begin(), m_bins[INDEX::Z].end(), + 1ul + m_skipZMiddleBin); + } else { + m_bins[INDEX::Z] = std::vector( + config.zBinsCustomLooping.begin() + m_skipZMiddleBin, + config.zBinsCustomLooping.end()); } } @@ -249,11 +224,14 @@ inline std::size_t Acts::BinnedSPGroup::size() const { template inline Acts::BinnedSPGroupIterator Acts::BinnedSPGroup::begin() { - return {*this, 0}; + return {*this, {0ul, 0ul}, m_bins}; } template inline Acts::BinnedSPGroupIterator Acts::BinnedSPGroup::end() { - return {*this, m_grid->size()}; + std::array endline{}; + endline[0ul] = m_bins[0ul].size(); + endline[1ul] = m_bins[1ul].size(); + return {*this, endline, m_bins}; } diff --git a/Core/include/Acts/Utilities/Grid.hpp b/Core/include/Acts/Utilities/Grid.hpp index f4b1671a077..3d0913207df 100644 --- a/Core/include/Acts/Utilities/Grid.hpp +++ b/Core/include/Acts/Utilities/Grid.hpp @@ -20,6 +20,14 @@ #include #include +namespace Acts { +template +class GridGlobalIterator; + +template +class GridLocalIterator; +} // namespace Acts + namespace Acts { /// @brief class for describing a regular multi-dimensional grid @@ -48,6 +56,10 @@ class Grid final { using point_t = std::array; /// index type using local bin indices along each axis using index_t = std::array; + /// global iterator type + using global_iterator_t = Acts::GridGlobalIterator; + /// local iterator type + using local_iterator_t = Acts::GridLocalIterator; /// @brief default constructor /// @@ -457,6 +469,25 @@ class Grid final { return detail::grid_helper::getAxes(m_axes); } + global_iterator_t begin() const { return global_iterator_t(*this, 0); } + + global_iterator_t end() const { return global_iterator_t(*this, size()); } + + local_iterator_t begin( + const std::array, DIM>& navigator) const { + std::array localBin{}; + return local_iterator_t(*this, std::move(localBin), navigator); + } + + local_iterator_t end( + const std::array, DIM>& navigator) const { + std::array endline{}; + for (std::size_t i(0ul); i < DIM; ++i) { + endline[i] = navigator[i].size(); + } + return local_iterator_t(*this, std::move(endline), navigator); + } + private: /// set of axis defining the multi-dimensional grid std::tuple m_axes; diff --git a/Core/include/Acts/Utilities/GridIterator.hpp b/Core/include/Acts/Utilities/GridIterator.hpp new file mode 100644 index 00000000000..5fd2c687e62 --- /dev/null +++ b/Core/include/Acts/Utilities/GridIterator.hpp @@ -0,0 +1,127 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2023 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Utilities/Grid.hpp" +#include "Acts/Utilities/Holders.hpp" + +#include + +namespace Acts { + +// Using Global iterator, including over/under flow bins +template +class GridGlobalIterator { + public: + static constexpr std::size_t DIM = sizeof...(Axes); + + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + + GridGlobalIterator() = default; + GridGlobalIterator(Acts::Grid&& grid, std::size_t idx) = delete; + GridGlobalIterator(const Acts::Grid& grid, std::size_t idx = 0ul); + + GridGlobalIterator(const GridGlobalIterator& other) = default; + GridGlobalIterator& operator=( + const GridGlobalIterator& other) = default; + + GridGlobalIterator(GridGlobalIterator&& other) noexcept; + GridGlobalIterator& operator=( + GridGlobalIterator&& other) noexcept; + + ~GridGlobalIterator() = default; + + bool operator==(const GridGlobalIterator& other) const; + bool operator!=(const GridGlobalIterator& other) const; + + bool operator<(const GridGlobalIterator& other) const; + bool operator>(const GridGlobalIterator& other) const; + bool operator<=(const GridGlobalIterator& other) const; + bool operator>=(const GridGlobalIterator& other) const; + + GridGlobalIterator& operator+=(const std::size_t offset); + GridGlobalIterator& operator-=(const std::size_t offset); + GridGlobalIterator operator+(const std::size_t offset) const; + GridGlobalIterator operator-(const std::size_t offset) const; + + difference_type operator-(const GridGlobalIterator& other) const; + const value_type& operator*() const; + + GridGlobalIterator& operator++(); + GridGlobalIterator operator++(int); + + private: + Acts::detail::RefHolder> m_grid{nullptr}; + std::size_t m_idx{0ul}; +}; + +// Using Local iterator, excluding over/under flow bins +// Can also allow for custom navigation pattern along axes +template +class GridLocalIterator { + public: + static constexpr std::size_t DIM = sizeof...(Axes); + + using iterator_category = std::bidirectional_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + + GridLocalIterator() = default; + GridLocalIterator(Acts::Grid&& grid, + const std::array& indexes) = delete; + GridLocalIterator(Acts::Grid&& grid, + const std::array& indexes, + std::array, DIM> navigation) = + delete; + GridLocalIterator(const Acts::Grid& grid, + const std::array& indexes); + GridLocalIterator(const Acts::Grid& grid, + const std::array& indexes, + std::array, DIM> navigation); + + GridLocalIterator(const GridLocalIterator& other) = default; + GridLocalIterator& operator=( + const GridLocalIterator& other) = default; + + GridLocalIterator(GridLocalIterator&& other) noexcept; + GridLocalIterator& operator=( + GridLocalIterator&& other) noexcept; + + ~GridLocalIterator() = default; + + bool operator==(const Acts::GridLocalIterator& other) const; + bool operator!=(const Acts::GridLocalIterator& other) const; + + const value_type& operator*() const; + + GridLocalIterator& operator++(); + GridLocalIterator operator++(int); + + std::array localPosition() const; + + private: + template + void increment(); + + private: + Acts::detail::RefHolder> m_grid{nullptr}; + std::array m_numLocalBins{}; + std::array m_currentIndex{}; + std::array, DIM> m_navigationIndex{}; +}; + +} // namespace Acts + +#include "Acts/Utilities/GridIterator.ipp" diff --git a/Core/include/Acts/Utilities/GridIterator.ipp b/Core/include/Acts/Utilities/GridIterator.ipp new file mode 100644 index 00000000000..e2d358f9394 --- /dev/null +++ b/Core/include/Acts/Utilities/GridIterator.ipp @@ -0,0 +1,249 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2016-2023 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +namespace Acts { +// Global Iterator +template +GridGlobalIterator::GridGlobalIterator( + const Acts::Grid& grid, std::size_t idx) + : m_grid(&grid), m_idx(idx) {} + +template +GridGlobalIterator::GridGlobalIterator( + GridGlobalIterator&& other) noexcept + : m_grid(std::exchange(other.m_grid.ptr, nullptr)), m_idx(other.m_idx) {} + +template +GridGlobalIterator& GridGlobalIterator::operator=( + GridGlobalIterator&& other) noexcept { + m_grid.ptr = std::exchange(other.m_grid.ptr, nullptr); + m_idx = other.m_idx; + return *this; +} + +template +bool GridGlobalIterator::operator==( + const GridGlobalIterator& other) const { + return (m_grid.ptr == other.m_grid.ptr) && m_idx == other.m_idx; +} + +template +bool GridGlobalIterator::operator!=( + const GridGlobalIterator& other) const { + return !(*this == other); +} + +template +bool GridGlobalIterator::operator<( + const GridGlobalIterator& other) const { + return m_idx < other.m_idx; +} + +template +bool GridGlobalIterator::operator>( + const GridGlobalIterator& other) const { + return m_idx > other.m_idx; +} + +template +bool GridGlobalIterator::operator<=( + const GridGlobalIterator& other) const { + return !(*this > other); +} + +template +bool GridGlobalIterator::operator>=( + const GridGlobalIterator& other) const { + return !(*this < other); +} + +template +GridGlobalIterator& GridGlobalIterator::operator+=( + const std::size_t offset) { + m_idx += offset; + return *this; +} + +template +GridGlobalIterator& GridGlobalIterator::operator-=( + const std::size_t offset) { + m_idx -= offset; + return *this; +} + +template +GridGlobalIterator GridGlobalIterator::operator+( + const std::size_t offset) const { + return {*m_grid, m_idx + offset}; +} + +template +GridGlobalIterator GridGlobalIterator::operator-( + const std::size_t offset) const { + return {*m_grid, m_idx - offset}; +} + +template +typename GridGlobalIterator::difference_type +GridGlobalIterator::operator-( + const GridGlobalIterator& other) const { + assert(other <= *this); + return m_idx - other.m_idx; +} + +template +const typename GridGlobalIterator::value_type& +GridGlobalIterator::operator*() const { + return m_grid->at(m_idx); +} + +template +GridGlobalIterator& GridGlobalIterator::operator++() { + ++m_idx; + return *this; +} + +template +GridGlobalIterator GridGlobalIterator::operator++(int) { + GridGlobalIterator output(*m_grid, m_idx++); + return output; +} + +// Local Iterator +template +Acts::GridLocalIterator::GridLocalIterator( + const Acts::Grid& grid, + const std::array& indexes) + : m_grid(&grid), + m_numLocalBins(grid.numLocalBins()), + m_currentIndex(indexes) { + for (std::size_t i(0); i < DIM; ++i) { + m_navigationIndex[i].resize(m_numLocalBins[i]); + std::iota(m_navigationIndex[i].begin(), m_navigationIndex[i].end(), 1ul); + } +} + +template +Acts::GridLocalIterator::GridLocalIterator( + const Acts::Grid& grid, + const std::array& indexes, + std::array, DIM> navigation) + : m_grid(&grid), + m_numLocalBins(grid.numLocalBins()), + m_currentIndex(indexes), + m_navigationIndex(std::move(navigation)) { + // We can allow navigation on only a subset of bins. + // If the number of specified bins in the navigation for one axis is not + // zero then override the maximum number of navigation bins instead of using + // the total number of available bins in the axis + for (std::size_t i(0ul); i < DIM; ++i) { + // We do not allow empty bin sequences + if (m_navigationIndex[i].size() == 0) { + throw std::invalid_argument( + "Invalid navigation sequence in local grid iterator. No bins " + "specified."); + } + // Too many bins + if (m_navigationIndex[i].size() > m_numLocalBins[i]) { + throw std::invalid_argument( + "Invalid navigation sequence in local grid iterator. Too many bins " + "specified."); + } + m_numLocalBins[i] = m_navigationIndex[i].size(); + } +} + +template +Acts::GridLocalIterator::GridLocalIterator( + Acts::GridLocalIterator&& other) noexcept + : m_grid(std::exchange(other.m_grid.ptr, nullptr)), + m_numLocalBins(other.m_numLocalBins), + m_currentIndex(other.m_currentIndex), + m_navigationIndex(std::move(other.m_navigationIndex)) {} + +template +Acts::GridLocalIterator& +Acts::GridLocalIterator::operator=( + Acts::GridLocalIterator&& other) noexcept { + m_grid.ptr = std::exchange(other.m_grid.ptr, nullptr); + m_numLocalBins = other.m_numLocalBins; + m_currentIndex = other.m_currentIndex; + m_navigationIndex = std::move(other.m_navigationIndex); + return *this; +} + +template +bool Acts::GridLocalIterator::operator==( + const Acts::GridLocalIterator& other) const { + if (m_grid.ptr != other.m_grid.ptr) { + return false; + } + + for (std::size_t i(0); i < DIM; ++i) { + if (m_currentIndex[i] != other.m_currentIndex[i]) { + return false; + } + } + + return true; +} + +template +bool Acts::GridLocalIterator::operator!=( + const Acts::GridLocalIterator& other) const { + return !(*this == other); +} + +template +const typename Acts::GridLocalIterator::value_type& +Acts::GridLocalIterator::operator*() const { + std::array localPositionBin{}; + for (std::size_t i(0); i < DIM; ++i) { + localPositionBin[i] = m_navigationIndex[i][m_currentIndex[i]]; + } + return m_grid->atLocalBins(localPositionBin); +} + +template +GridLocalIterator& GridLocalIterator::operator++() { + increment(); + return *this; +} + +template +GridLocalIterator GridLocalIterator::operator++(int) { + GridLocalIterator output(*this); + this->operator++(); + return output; +} + +template +template +void GridLocalIterator::increment() { + if (++m_currentIndex[N] < m_numLocalBins[N]) { + return; + } + if constexpr (N != 0) { + m_currentIndex[N] = 0; + increment(); + } else { + m_currentIndex = m_numLocalBins; + } +} + +template +std::array::DIM> +GridLocalIterator::localPosition() const { + std::array output{}; + for (std::size_t i(0); i < DIM; ++i) { + output[i] = m_navigationIndex[i][m_currentIndex[i]]; + } + return output; +} + +} // namespace Acts diff --git a/Tests/UnitTests/Core/Utilities/CMakeLists.txt b/Tests/UnitTests/Core/Utilities/CMakeLists.txt index 7e75e042034..78e9e6dcf8a 100644 --- a/Tests/UnitTests/Core/Utilities/CMakeLists.txt +++ b/Tests/UnitTests/Core/Utilities/CMakeLists.txt @@ -13,6 +13,7 @@ target_link_libraries(ActsUnitTestBoundingBox PRIVATE std::filesystem) add_unittest(Extendable ExtendableTests.cpp) add_unittest(FiniteStateMachine FiniteStateMachineTests.cpp) add_unittest(Frustum FrustumTest.cpp) +add_unittest(GridIteration GridIterationTests.cpp) add_unittest(Grid GridTests.cpp) add_unittest(Helpers HelpersTests.cpp) add_unittest(Interpolation InterpolationTests.cpp) diff --git a/Tests/UnitTests/Core/Utilities/GridIterationTests.cpp b/Tests/UnitTests/Core/Utilities/GridIterationTests.cpp new file mode 100644 index 00000000000..2f3bf5deb37 --- /dev/null +++ b/Tests/UnitTests/Core/Utilities/GridIterationTests.cpp @@ -0,0 +1,651 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2023 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include "Acts/Utilities/Grid.hpp" +#include "Acts/Utilities/GridIterator.hpp" + +#include +#include + +namespace Acts::Test { + +BOOST_AUTO_TEST_CASE(grid_iteration_test_1d_global_operators) { + const std::size_t nBins = 10ul; + Acts::detail::EquidistantAxis xAxis(0, 100, nBins); + Acts::Grid grid( + std::make_tuple(std::move(xAxis))); + + BOOST_CHECK_EQUAL(grid.size(true), nBins + 2ul); + + Acts::GridGlobalIterator gridStart = + grid.begin(); + Acts::GridGlobalIterator gridStop = + grid.end(); + + BOOST_CHECK_EQUAL(gridStart == gridStop, false); + BOOST_CHECK_EQUAL(gridStart != gridStop, true); + BOOST_CHECK_EQUAL(gridStart < gridStop, true); + BOOST_CHECK_EQUAL(gridStart <= gridStop, true); + BOOST_CHECK_EQUAL(gridStart > gridStop, false); + BOOST_CHECK_EQUAL(gridStart >= gridStop, false); + + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), nBins + 2ul); + auto itr = gridStart++; + BOOST_CHECK_EQUAL(std::distance(itr, gridStart), 1ul); + BOOST_CHECK_EQUAL(std::distance(itr, gridStop), nBins + 2ul); + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), nBins + 1ul); + + itr = ++gridStart; + BOOST_CHECK_EQUAL(std::distance(itr, gridStart), 0ul); + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), nBins); + + itr = gridStart + std::distance(gridStart, gridStop); + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), nBins); + BOOST_CHECK_EQUAL(std::distance(itr, gridStop), 0ul); + BOOST_CHECK_EQUAL(itr == gridStop, true); + + itr = gridStart - 1ul; + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), nBins); + BOOST_CHECK_EQUAL(std::distance(itr, gridStop), nBins + 1ul); + + gridStart += std::distance(gridStart, gridStop); + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), 0ul); + BOOST_CHECK_EQUAL(gridStart == gridStop, true); + + gridStart -= 3ul; + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), 3ul); + BOOST_CHECK_EQUAL(gridStart != gridStop, true); + + [[maybe_unused]] double value = *gridStart; + + Acts::GridGlobalIterator gridDefault; + Acts::GridGlobalIterator gridDummy( + grid, 0ul); + + BOOST_CHECK_EQUAL(gridDefault == gridDummy, false); +} + +BOOST_AUTO_TEST_CASE(grid_iteration_test_2d_global_operators) { + const std::size_t nBinsX = 10ul; + const std::size_t nBinsY = 5ul; + Acts::detail::EquidistantAxis xAxis(0, 100, nBinsX); + Acts::detail::EquidistantAxis yAxis(0, 100, nBinsY); + Acts::Grid + grid(std::make_tuple(std::move(xAxis), std::move(yAxis))); + + BOOST_CHECK_EQUAL(grid.size(true), (nBinsX + 2ul) * (nBinsY + 2ul)); + + Acts::GridGlobalIterator + gridStart = grid.begin(); + Acts::GridGlobalIterator + gridStop = grid.end(); + + BOOST_CHECK_EQUAL(gridStart == gridStop, false); + BOOST_CHECK_EQUAL(gridStart != gridStop, true); + BOOST_CHECK_EQUAL(gridStart < gridStop, true); + BOOST_CHECK_EQUAL(gridStart <= gridStop, true); + BOOST_CHECK_EQUAL(gridStart > gridStop, false); + BOOST_CHECK_EQUAL(gridStart >= gridStop, false); + + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), grid.size(true)); + auto itr = gridStart++; + BOOST_CHECK_EQUAL(std::distance(itr, gridStart), 1ul); + BOOST_CHECK_EQUAL(std::distance(itr, gridStop), grid.size(true)); + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), grid.size(true) - 1ul); + + itr = ++gridStart; + BOOST_CHECK_EQUAL(std::distance(itr, gridStart), 0ul); + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), grid.size(true) - 2ul); + + itr = gridStart + std::distance(gridStart, gridStop); + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), grid.size(true) - 2ul); + BOOST_CHECK_EQUAL(std::distance(itr, gridStop), 0ul); + BOOST_CHECK_EQUAL(itr == gridStop, true); + + itr = gridStart - 1ul; + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), grid.size(true) - 2ul); + BOOST_CHECK_EQUAL(std::distance(itr, gridStop), grid.size(true) - 1ul); + + gridStart += std::distance(gridStart, gridStop); + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), 0ul); + BOOST_CHECK_EQUAL(gridStart == gridStop, true); + + gridStart -= 3ul; + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), 3ul); + BOOST_CHECK_EQUAL(gridStart != gridStop, true); + + [[maybe_unused]] double value = *gridStart; + + Acts::GridGlobalIterator + gridDefault; + Acts::GridGlobalIterator + gridDummy(grid, 0ul); + + BOOST_CHECK_EQUAL(gridDefault == gridDummy, false); +} + +BOOST_AUTO_TEST_CASE(grid_iteration_test_1d_global) { + const std::size_t nBins = 10ul; + Acts::detail::EquidistantAxis xAxis(0, 100, nBins); + Acts::Grid grid( + std::make_tuple(std::move(xAxis))); + + // test general properties + BOOST_CHECK_EQUAL(grid.size(false), nBins); + BOOST_CHECK_EQUAL(grid.size(true), nBins + 2ul); + + const std::array numLocalBins = grid.numLocalBins(); + BOOST_CHECK_EQUAL(numLocalBins[0ul], nBins); + + Acts::GridGlobalIterator gridStart = + grid.begin(); + Acts::GridGlobalIterator gridStop = + grid.end(); + std::size_t numIterations = 0ul; + for (; gridStart != gridStop; ++gridStart) { + ++numIterations; + } + BOOST_CHECK_EQUAL(numIterations, grid.size(true)); +} + +BOOST_AUTO_TEST_CASE(grid_iteration_test_2d_global) { + const std::size_t nBins = 10ul; + Acts::detail::EquidistantAxis xAxis(0, 100, nBins); + Acts::detail::EquidistantAxis yAxis(0, 100, nBins); + Acts::Grid + grid(std::make_tuple(std::move(xAxis), std::move(yAxis))); + + // test general properties + BOOST_CHECK_EQUAL(grid.size(false), nBins * nBins); + BOOST_CHECK_EQUAL(grid.size(true), (nBins + 2ul) * (nBins + 2ul)); + + const std::array numLocalBins = grid.numLocalBins(); + BOOST_CHECK_EQUAL(numLocalBins[0ul], nBins); + BOOST_CHECK_EQUAL(numLocalBins[1ul], nBins); + + Acts::GridGlobalIterator + gridStart = grid.begin(); + Acts::GridGlobalIterator + gridStop = grid.end(); + std::size_t numIterations = 0ul; + for (; gridStart != gridStop; ++gridStart) { + ++numIterations; + } + BOOST_CHECK_EQUAL(numIterations, grid.size(true)); +} + +BOOST_AUTO_TEST_CASE(grid_iteration_test_3d_global) { + const std::size_t nBins = 10ul; + const std::size_t nBinsZ = 20ul; + Acts::detail::EquidistantAxis xAxis(0, 100, nBins); + Acts::detail::EquidistantAxis yAxis(0, 100, nBins); + Acts::detail::EquidistantAxis zAxis(0, 100, nBinsZ); + Acts::Grid + grid(std::make_tuple(std::move(xAxis), std::move(yAxis), + std::move(zAxis))); + + // test general properties + BOOST_CHECK_EQUAL(grid.size(false), nBins * nBins * nBinsZ); + BOOST_CHECK_EQUAL(grid.size(true), + (nBins + 2ul) * (nBins + 2ul) * (nBinsZ + 2ul)); + + const std::array numLocalBins = grid.numLocalBins(); + BOOST_CHECK_EQUAL(numLocalBins[0ul], nBins); + BOOST_CHECK_EQUAL(numLocalBins[1ul], nBins); + BOOST_CHECK_EQUAL(numLocalBins[2ul], nBinsZ); + + Acts::GridGlobalIterator + gridStart = grid.begin(); + Acts::GridGlobalIterator + gridStop = grid.end(); + std::size_t numIterations = 0ul; + for (; gridStart != gridStop; ++gridStart) { + ++numIterations; + } + BOOST_CHECK_EQUAL(numIterations, grid.size(true)); +} + +BOOST_AUTO_TEST_CASE(grid_iteration_test_1d_local_operators) { + const std::size_t nBins = 10ul; + Acts::detail::EquidistantAxis xAxis(0, 100, nBins); + Acts::Grid grid( + std::make_tuple(std::move(xAxis))); + + std::array, 1ul> navigation; + navigation[0ul].resize(nBins); + std::iota(navigation[0ul].begin(), navigation[0ul].end(), 1ul); + + // Constructor without navigation + Acts::GridLocalIterator gridIterNoNav( + grid, {0ul}); + // Constructor(s) with navigation + Acts::GridLocalIterator gridStart( + grid, {0ul}, navigation); + + BOOST_CHECK_EQUAL(std::distance(gridIterNoNav, gridStart), 0ul); + BOOST_CHECK_EQUAL(gridIterNoNav == gridStart, true); + + Acts::GridLocalIterator gridStop( + grid, {nBins}, std::move(navigation)); + + BOOST_CHECK_EQUAL(gridStart == gridStop, false); + BOOST_CHECK_EQUAL(gridStart != gridStop, true); + + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), grid.size(false)); + BOOST_CHECK_EQUAL(gridStart != gridStop, true); + + auto itr = gridStart++; + BOOST_CHECK_EQUAL(std::distance(itr, gridStart), 1ul); + BOOST_CHECK_EQUAL(std::distance(itr, gridStop), nBins); + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), nBins - 1ul); + + itr = ++gridStart; + BOOST_CHECK_EQUAL(std::distance(itr, gridStart), 0ul); + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), nBins - 2ul); + + [[maybe_unused]] double value = *gridStart; + std::array locPos = gridStart.localPosition(); + BOOST_CHECK_EQUAL(locPos[0ul], 3ul); + + Acts::GridLocalIterator gridDefault; + Acts::GridLocalIterator gridDummy( + grid, {0ul}); + + BOOST_CHECK_EQUAL(gridDefault == gridDummy, false); + + // move operation will invalidate gridStart since the grid gets moved and + // replaced with a nullptr + itr = std::move(gridStart); + BOOST_CHECK_EQUAL(itr == gridStart, false); + BOOST_CHECK_EQUAL(itr != gridStart, true); + BOOST_CHECK_EQUAL(std::distance(itr, gridStop), nBins - 2ul); +} + +BOOST_AUTO_TEST_CASE(grid_iteration_test_2d_local_operators) { + const std::size_t nBinsX = 10ul; + const std::size_t nBinsY = 5ul; + Acts::detail::EquidistantAxis xAxis(0, 100, nBinsX); + Acts::detail::EquidistantAxis yAxis(0, 100, nBinsY); + Acts::Grid + grid(std::make_tuple(std::move(xAxis), std::move(yAxis))); + + std::array, 2ul> navigation; + navigation[0ul].resize(nBinsX); + navigation[1ul].resize(nBinsY); + std::iota(navigation[0ul].begin(), navigation[0ul].end(), 1ul); + std::iota(navigation[1ul].begin(), navigation[1ul].end(), 1ul); + + // Constructor without navigation + Acts::GridLocalIterator + gridIterNoNav(grid, {0ul, 0ul}); + // Constructor(s) with navigation + Acts::GridLocalIterator + gridStart(grid, {0ul, 0ul}, navigation); + + BOOST_CHECK_EQUAL(std::distance(gridIterNoNav, gridStart), 0ul); + BOOST_CHECK_EQUAL(gridIterNoNav == gridStart, true); + + Acts::GridLocalIterator + gridStop(grid, {nBinsX, nBinsY}, std::move(navigation)); + + BOOST_CHECK_EQUAL(gridStart == gridStop, false); + BOOST_CHECK_EQUAL(gridStart != gridStop, true); + + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), grid.size(false)); + BOOST_CHECK_EQUAL(gridStart != gridStop, true); + + auto itr = gridStart++; + BOOST_CHECK_EQUAL(std::distance(itr, gridStart), 1ul); + BOOST_CHECK_EQUAL(std::distance(itr, gridStop), nBinsX * nBinsY); + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), nBinsX * nBinsY - 1ul); + + itr = ++gridStart; + BOOST_CHECK_EQUAL(std::distance(itr, gridStart), 0ul); + BOOST_CHECK_EQUAL(std::distance(gridStart, gridStop), nBinsX * nBinsY - 2ul); + + [[maybe_unused]] double value = *gridStart; + std::array locPos = gridStart.localPosition(); + BOOST_CHECK_EQUAL(locPos[0ul], 1ul); + BOOST_CHECK_EQUAL(locPos[1ul], 3ul); + + Acts::GridLocalIterator + gridDefault; + Acts::GridLocalIterator + gridDummy(grid, {0ul, 0ul}); + + BOOST_CHECK_EQUAL(gridDefault == gridDummy, false); + + // move operation will invalidate gridStart since the grid gets moved and + // replaced with a nullptr + itr = std::move(gridStart); + BOOST_CHECK_EQUAL(itr == gridStart, false); + BOOST_CHECK_EQUAL(itr != gridStart, true); + BOOST_CHECK_EQUAL(std::distance(itr, gridStop), nBinsX * nBinsY - 2ul); +} + +BOOST_AUTO_TEST_CASE(grid_iteration_test_1d_local_notvalid) { + const std::size_t nBins = 10ul; + Acts::detail::EquidistantAxis xAxis(0, 100, nBins); + Acts::Grid grid( + std::make_tuple(std::move(xAxis))); + + // no navigation bins + std::array, 1ul> noNavigation; + BOOST_CHECK_THROW( + (Acts::GridLocalIterator( + grid, {0ul}, std::move(noNavigation))), + std::invalid_argument); + + // too many steps in the navigation, there are not enough bins in the axis + std::array, 1ul> tooMuchNavigation; + tooMuchNavigation[0ul].resize(2 * nBins); + std::iota(tooMuchNavigation[0ul].begin(), tooMuchNavigation[0ul].end(), 1ul); + BOOST_CHECK_THROW( + (Acts::GridLocalIterator( + grid, {0ul}, std::move(tooMuchNavigation))), + std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(grid_iteration_test_1d_local) { + const std::size_t nBins = 10ul; + Acts::detail::EquidistantAxis xAxis(0, 100, nBins); + Acts::Grid grid( + std::make_tuple(std::move(xAxis))); + + // test general properties + BOOST_CHECK_EQUAL(grid.size(false), nBins); + BOOST_CHECK_EQUAL(grid.size(true), nBins + 2ul); + + const std::array numLocalBins = grid.numLocalBins(); + BOOST_CHECK_EQUAL(numLocalBins[0ul], nBins); + + std::array, 1ul> navigation; + navigation[0ul].resize(nBins); + std::iota(navigation[0ul].begin(), navigation[0ul].end(), 1ul); + + Acts::GridLocalIterator gridStart = + grid.begin(navigation); + Acts::GridLocalIterator gridStop = + grid.end(navigation); + std::size_t numIterations = 0ul; + for (; gridStart != gridStop; ++gridStart) { + ++numIterations; + } + BOOST_CHECK_EQUAL(numIterations, grid.size(false)); +} + +BOOST_AUTO_TEST_CASE(grid_iteration_test_2d_local) { + const std::size_t nBins = 10ul; + Acts::detail::EquidistantAxis xAxis(0, 100, nBins); + Acts::detail::EquidistantAxis yAxis(0, 100, nBins); + Acts::Grid + grid(std::make_tuple(std::move(xAxis), std::move(yAxis))); + + // test general properties + BOOST_CHECK_EQUAL(grid.size(false), nBins * nBins); + BOOST_CHECK_EQUAL(grid.size(true), (nBins + 2ul) * (nBins + 2ul)); + + const std::array numLocalBins = grid.numLocalBins(); + BOOST_CHECK_EQUAL(numLocalBins[0ul], nBins); + BOOST_CHECK_EQUAL(numLocalBins[1ul], nBins); + + std::array, 2ul> navigation; + navigation[0ul].resize(nBins); + navigation[1ul].resize(nBins); + for (std::size_t i(0ul); i < 2ul; ++i) { + std::iota(navigation[i].begin(), navigation[i].end(), 1ul); + } + + Acts::GridLocalIterator + gridStart = grid.begin(navigation); + Acts::GridLocalIterator + gridStop = grid.end(navigation); + std::size_t numIterations = 0ul; + for (; gridStart != gridStop; ++gridStart) { + ++numIterations; + } + BOOST_CHECK_EQUAL(numIterations, grid.size(false)); +} + +BOOST_AUTO_TEST_CASE(grid_iteration_test_3d_local) { + const std::size_t nBins = 10ul; + const std::size_t nBinsZ = 20ul; + Acts::detail::EquidistantAxis xAxis(0, 100, nBins); + Acts::detail::EquidistantAxis yAxis(0, 100, nBins); + Acts::detail::EquidistantAxis zAxis(0, 100, nBinsZ); + Acts::Grid + grid(std::make_tuple(std::move(xAxis), std::move(yAxis), + std::move(zAxis))); + + // test general properties + BOOST_CHECK_EQUAL(grid.size(false), nBins * nBins * nBinsZ); + BOOST_CHECK_EQUAL(grid.size(true), + (nBins + 2ul) * (nBins + 2ul) * (nBinsZ + 2ul)); + + const std::array numLocalBins = grid.numLocalBins(); + BOOST_CHECK_EQUAL(numLocalBins[0ul], nBins); + BOOST_CHECK_EQUAL(numLocalBins[1ul], nBins); + BOOST_CHECK_EQUAL(numLocalBins[2ul], nBinsZ); + + std::array, 3ul> navigation; + navigation[0ul].resize(nBins); + navigation[1ul].resize(nBins); + navigation[2ul].resize(nBinsZ); + for (std::size_t i(0ul); i < 3ul; ++i) { + std::iota(navigation[i].begin(), navigation[i].end(), 1ul); + } + + Acts::GridLocalIterator + gridStart = grid.begin(navigation); + Acts::GridLocalIterator + gridStop = grid.end(navigation); + std::size_t numIterations = 0ul; + for (; gridStart != gridStop; ++gridStart) { + ++numIterations; + } + BOOST_CHECK_EQUAL(numIterations, grid.size(false)); +} + +BOOST_AUTO_TEST_CASE(grid_iteration_test_3d_local_custom_navigation) { + const std::size_t nBins = 10ul; + const std::size_t nBinsZ = 20ul; + Acts::detail::EquidistantAxis xAxis(0, 100, nBins); + Acts::detail::EquidistantAxis yAxis(0, 100, nBins); + Acts::detail::EquidistantAxis zAxis(0, 100, nBinsZ); + Acts::Grid + grid(std::make_tuple(std::move(xAxis), std::move(yAxis), + std::move(zAxis))); + + // test general properties + BOOST_CHECK_EQUAL(grid.size(false), nBins * nBins * nBinsZ); + BOOST_CHECK_EQUAL(grid.size(true), + (nBins + 2ul) * (nBins + 2ul) * (nBinsZ + 2ul)); + + const std::array numLocalBins = grid.numLocalBins(); + BOOST_CHECK_EQUAL(numLocalBins[0ul], nBins); + BOOST_CHECK_EQUAL(numLocalBins[1ul], nBins); + BOOST_CHECK_EQUAL(numLocalBins[2ul], nBinsZ); + + std::array, 3ul> navigation; + navigation[0ul] = {1ul, 5ul, 3ul, 2ul, 9ul, 10ul, 4ul, 6ul, 8ul, 7ul}; + navigation[1ul] = {6ul, 8ul, 7ul, 1ul, 5ul, 3ul, 2ul, 9ul, 10ul, 4ul}; + navigation[2ul] = {1ul, 5ul, 3ul, 2ul, 9ul, 10ul, 4ul, + 6ul, 8ul, 7ul, 11ul, 15ul, 13ul, 12ul, + 19ul, 20ul, 14ul, 16ul, 18ul, 17ul}; + + Acts::GridLocalIterator + gridStart = grid.begin(navigation); + Acts::GridLocalIterator + gridStop = grid.end(navigation); + std::size_t numIterations = 0ul; + for (; gridStart != gridStop; ++gridStart) { + ++numIterations; + } + BOOST_CHECK_EQUAL(numIterations, grid.size(false)); +} + +BOOST_AUTO_TEST_CASE(grid_iteration_test_5d_local_custom_subnavigation) { + const std::size_t nBins = 10ul; + const std::size_t nBinsZ = 20ul; + const std::size_t nBinsJK = 5ul; + Acts::detail::EquidistantAxis xAxis(0, 100, nBins); + Acts::detail::EquidistantAxis yAxis(0, 100, nBins); + Acts::detail::EquidistantAxis zAxis(0, 100, nBinsZ); + Acts::detail::EquidistantAxis jAxis(0, 100, nBinsJK); + Acts::detail::EquidistantAxis kAxis(0, 100, nBinsJK); + Acts::Grid + grid(std::make_tuple(std::move(xAxis), std::move(yAxis), std::move(zAxis), + std::move(jAxis), std::move(kAxis))); + + // test general properties + BOOST_CHECK_EQUAL(grid.size(false), + nBins * nBins * nBinsZ * nBinsJK * nBinsJK); + BOOST_CHECK_EQUAL(grid.size(true), (nBins + 2ul) * (nBins + 2ul) * + (nBinsZ + 2ul) * (nBinsJK + 2ul) * + (nBinsJK + 2ul)); + + const std::array numLocalBins = grid.numLocalBins(); + BOOST_CHECK_EQUAL(numLocalBins[0ul], nBins); + BOOST_CHECK_EQUAL(numLocalBins[1ul], nBins); + BOOST_CHECK_EQUAL(numLocalBins[2ul], nBinsZ); + BOOST_CHECK_EQUAL(numLocalBins[3ul], nBinsJK); + BOOST_CHECK_EQUAL(numLocalBins[4ul], nBinsJK); + + // Iterate only on a few bins + std::array, 5ul> navigation; + navigation[0ul] = {1ul, 5ul, 3ul, 2ul, 9ul, 10ul, 4ul, 6ul, 8ul, 7ul}; + navigation[1ul] = {6ul, 8ul, 7ul, 1ul}; + navigation[2ul] = {1ul, 5ul}; + navigation[3ul] = {5ul, 3ul, 2ul}; + navigation[4ul] = {2ul}; + + Acts::GridLocalIterator< + double, Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis> + gridStart = grid.begin(navigation); + Acts::GridLocalIterator< + double, Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis, Acts::detail::EquidistantAxis, + Acts::detail::EquidistantAxis> + gridStop = grid.end(navigation); + std::size_t numIterations = 0ul; + for (; gridStart != gridStop; ++gridStart) { + ++numIterations; + } + + std::size_t expectedIterations = 1ul; + for (std::size_t i(0ul); i < 5ul; ++i) { + expectedIterations *= navigation[i].size(); + } + + BOOST_CHECK_EQUAL(numIterations, expectedIterations); +} + +BOOST_AUTO_TEST_CASE(grid_iteration_test_3d_local_norepetitions) { + const std::size_t nBinsX = 5ul; + const std::size_t nBinsY = 5ul; + const std::size_t nBinsZ = 2ul; + Acts::detail::EquidistantAxis xAxis(0, 100, nBinsX); + Acts::detail::EquidistantAxis yAxis(0, 100, nBinsY); + Acts::detail::EquidistantAxis zAxis(0, 100, nBinsZ); + Acts::Grid + grid(std::make_tuple(std::move(xAxis), std::move(yAxis), + std::move(zAxis))); + + std::array, 3ul> navigation; + navigation[0ul] = {1ul, 5ul, 3ul, 2ul, 4ul}; + navigation[1ul] = {4ul, 2ul, 3ul, 5ul, 1ul}; + navigation[2ul] = {2ul, 1ul}; + + std::size_t expectedIterations = + navigation[0ul].size() * navigation[1ul].size() * navigation[2ul].size(); + + // Set the allowed values + std::unordered_set allowed_global_bins; + for (std::size_t x : navigation[0ul]) { + for (std::size_t y : navigation[1ul]) { + for (std::size_t z : navigation[2ul]) { + std::array locPos({x, y, z}); + std::size_t globPos = grid.globalBinFromLocalBins(locPos); + BOOST_CHECK_EQUAL( + allowed_global_bins.find(globPos) != allowed_global_bins.end(), + false); + allowed_global_bins.insert(globPos); + } + } + } + + BOOST_CHECK_EQUAL(expectedIterations, allowed_global_bins.size()); + + Acts::GridLocalIterator + gridStart = grid.begin(navigation); + Acts::GridLocalIterator + gridStop = grid.end(navigation); + + // Prepare visited values + std::unordered_set visited_global_bins; + + std::size_t numIterations = 0ul; + for (; gridStart != gridStop; ++gridStart) { + ++numIterations; + std::array locPos = gridStart.localPosition(); + std::size_t globPos = grid.globalBinFromLocalBins(locPos); + BOOST_CHECK_EQUAL( + visited_global_bins.find(globPos) != visited_global_bins.end(), false); + BOOST_CHECK_EQUAL( + allowed_global_bins.find(globPos) != allowed_global_bins.end(), true); + visited_global_bins.insert(globPos); + } + + BOOST_CHECK_EQUAL(expectedIterations, numIterations); + BOOST_CHECK_EQUAL(visited_global_bins.size(), allowed_global_bins.size()); +} + +} // namespace Acts::Test diff --git a/Tests/UnitTests/Plugins/Cuda/Seeding/SeedFinderCudaTest.cpp b/Tests/UnitTests/Plugins/Cuda/Seeding/SeedFinderCudaTest.cpp index d7fd2f8d820..edf77868991 100644 --- a/Tests/UnitTests/Plugins/Cuda/Seeding/SeedFinderCudaTest.cpp +++ b/Tests/UnitTests/Plugins/Cuda/Seeding/SeedFinderCudaTest.cpp @@ -261,8 +261,18 @@ int main(int argc, char** argv) { auto start_cpu = std::chrono::system_clock::now(); + std::array, 2ul> navigation; + navigation[0ul].resize(spGroup.grid().numLocalBins()[0ul]); + navigation[1ul].resize(spGroup.grid().numLocalBins()[1ul]); + std::iota(navigation[0ul].begin(), navigation[0ul].end(), 1ul); + std::iota(navigation[1ul].begin(), navigation[1ul].end(), 1ul); + + std::array localPosition = + spGroup.grid().localBinsFromGlobalBin(skip); + int group_count; - auto groupIt = Acts::BinnedSPGroupIterator(spGroup, skip); + auto groupIt = Acts::BinnedSPGroupIterator(spGroup, localPosition, + navigation); //----------- CPU ----------// group_count = 0; @@ -298,7 +308,8 @@ int main(int argc, char** argv) { group_count = 0; std::vector>> seedVector_cuda; - groupIt = Acts::BinnedSPGroupIterator(spGroup, skip); + groupIt = Acts::BinnedSPGroupIterator(spGroup, localPosition, + navigation); Acts::SpacePointData spacePointData; spacePointData.resize(spVec.size()); diff --git a/Tests/UnitTests/Plugins/Cuda/Seeding2/main.cpp b/Tests/UnitTests/Plugins/Cuda/Seeding2/main.cpp index f45aca17957..ee85f2bbdfe 100644 --- a/Tests/UnitTests/Plugins/Cuda/Seeding2/main.cpp +++ b/Tests/UnitTests/Plugins/Cuda/Seeding2/main.cpp @@ -174,11 +174,20 @@ int main(int argc, char* argv[]) { // Create the result object. std::vector>> seeds_host; + std::array, 2ul> navigation; + navigation[0ul].resize(spGroup.grid().numLocalBins()[0ul]); + navigation[1ul].resize(spGroup.grid().numLocalBins()[1ul]); + std::iota(navigation[0ul].begin(), navigation[0ul].end(), 1ul); + std::iota(navigation[1ul].begin(), navigation[1ul].end(), 1ul); + // Perform the seed finding. if (!cmdl.onlyGPU) { decltype(seedFinder_host)::SeedingState state; for (std::size_t i = 0; i < cmdl.groupsToIterate; ++i) { - auto spGroup_itr = Acts::BinnedSPGroupIterator(spGroup, i); + std::array localPosition = + spGroup.grid().localBinsFromGlobalBin(i); + auto spGroup_itr = + Acts::BinnedSPGroupIterator(spGroup, localPosition, navigation); if (spGroup_itr == spGroup.end()) { break; } @@ -214,7 +223,10 @@ int main(int argc, char* argv[]) { // Perform the seed finding. for (std::size_t i = 0; i < cmdl.groupsToIterate; ++i) { - auto spGroup_itr = Acts::BinnedSPGroupIterator(spGroup, i); + std::array localPosition = + spGroup.grid().localBinsFromGlobalBin(i); + auto spGroup_itr = + Acts::BinnedSPGroupIterator(spGroup, localPosition, navigation); if (spGroup_itr == spGroup_end) { break; }