From a134e6611aca671d6e00b4edc49ce1783e04a8c1 Mon Sep 17 00:00:00 2001 From: Thomas Padioleau Date: Thu, 26 Dec 2024 13:22:41 +0100 Subject: [PATCH 01/12] Remove internal_mdspan --- include/ddc/chunk.hpp | 21 +++++++----- include/ddc/chunk_common.hpp | 64 ++++++++---------------------------- include/ddc/chunk_span.hpp | 33 ++++--------------- 3 files changed, 32 insertions(+), 86 deletions(-) diff --git a/include/ddc/chunk.hpp b/include/ddc/chunk.hpp index 440fa5842..e46cbd683 100644 --- a/include/ddc/chunk.hpp +++ b/include/ddc/chunk.hpp @@ -31,9 +31,6 @@ class Chunk, Allocator> protected: using base_type = ChunkCommon, Kokkos::layout_right>; - /// ND memory view - using internal_mdspan_type = typename base_type::internal_mdspan_type; - public: /// type of a span of this full chunk using span_type = ChunkSpan< @@ -116,12 +113,13 @@ class Chunk, Allocator> , m_allocator(std::move(other.m_allocator)) , m_label(std::move(other.m_label)) { - other.m_internal_mdspan = internal_mdspan_type(nullptr, other.m_internal_mdspan.mapping()); + other.m_allocation_mdspan + = allocation_mdspan_type(nullptr, other.m_allocation_mdspan.mapping()); } ~Chunk() noexcept { - if (this->m_internal_mdspan.data_handle()) { + if (this->m_allocation_mdspan.data_handle()) { m_allocator.deallocate(this->data_handle(), this->size()); } } @@ -138,13 +136,14 @@ class Chunk, Allocator> if (this == &other) { return *this; } - if (this->m_internal_mdspan.data_handle()) { + if (this->m_allocation_mdspan.data_handle()) { m_allocator.deallocate(this->data_handle(), this->size()); } static_cast(*this) = std::move(static_cast(other)); m_allocator = std::move(other.m_allocator); m_label = std::move(other.m_label); - other.m_internal_mdspan = internal_mdspan_type(nullptr, other.m_internal_mdspan.mapping()); + other.m_allocation_mdspan + = allocation_mdspan_type(nullptr, other.m_allocation_mdspan.mapping()); return *this; } @@ -192,7 +191,9 @@ class Chunk, Allocator> && ...)); assert(((DiscreteElement(take(delems...)) <= back(this->m_domain)) && ...)); - return DDC_MDSPAN_ACCESS_OP(this->m_internal_mdspan, uid(take(delems...))...); + return DDC_MDSPAN_ACCESS_OP( + this->m_allocation_mdspan, + (DiscreteElement(take(delems...)) - front(this->m_domain))...); } /** Element access using a list of DiscreteElement @@ -210,7 +211,9 @@ class Chunk, Allocator> && ...)); assert(((DiscreteElement(take(delems...)) <= back(this->m_domain)) && ...)); - return DDC_MDSPAN_ACCESS_OP(this->m_internal_mdspan, uid(take(delems...))...); + return DDC_MDSPAN_ACCESS_OP( + this->m_allocation_mdspan, + (DiscreteElement(take(delems...)) - front(this->m_domain))...); } /** Returns the label of the Chunk diff --git a/include/ddc/chunk_common.hpp b/include/ddc/chunk_common.hpp index 3792d5544..4f37a88dc 100644 --- a/include/ddc/chunk_common.hpp +++ b/include/ddc/chunk_common.hpp @@ -35,13 +35,6 @@ class ChunkCommon; template class ChunkCommon, LayoutStridedPolicy> { -protected: - /// the raw mdspan underlying this, with the same indexing (0 might no be dereferenceable) - using internal_mdspan_type = Kokkos::mdspan< - ElementType, - Kokkos::dextents, - Kokkos::layout_stride>; - public: using discrete_domain_type = DiscreteDomain; @@ -76,7 +69,7 @@ class ChunkCommon, LayoutStridedPolicy> using reference = typename allocation_mdspan_type::reference; - // ChunkCommon, ChunkSpan and Chunk need to access to m_internal_mdspan and m_domain of other template versions + // ChunkCommon, ChunkSpan and Chunk need to access to m_allocation_mdspan_mdspan and m_domain of other template versions template friend class ChunkCommon; @@ -90,7 +83,7 @@ class ChunkCommon, LayoutStridedPolicy> protected: /// The raw view of the data - internal_mdspan_type m_internal_mdspan; + allocation_mdspan_type m_allocation_mdspan; /// The mesh on which this chunk is defined discrete_domain_type m_domain; @@ -129,26 +122,16 @@ class ChunkCommon, LayoutStridedPolicy> private: template static KOKKOS_FUNCTION constexpr std:: - enable_if_t, internal_mdspan_type> - make_internal_mdspan(ElementType* ptr, discrete_domain_type const& domain) + enable_if_t, allocation_mdspan_type> + make_allocation_mdspan(ElementType* ptr, discrete_domain_type const& domain) { - if (domain.empty()) { - return internal_mdspan_type(ptr, Kokkos::layout_stride::mapping()); - } - extents_type const extents_r(::ddc::extents(domain).value()...); - mapping_type const mapping_r(extents_r); - - extents_type const extents_s((front(domain) + ddc::extents(domain)).uid()...); - std::array const strides_s { - mapping_r.stride(type_seq_rank_v>)...}; - Kokkos::layout_stride::mapping const mapping_s(extents_s, strides_s); - return internal_mdspan_type(ptr - mapping_s(front(domain).uid()...), mapping_s); + return allocation_mdspan_type(ptr, ::ddc::extents(domain).value()...); } public: KOKKOS_FUNCTION constexpr accessor_type accessor() const { - return m_internal_mdspan.accessor(); + return m_allocation_mdspan.accessor(); } KOKKOS_FUNCTION constexpr DiscreteVector extents() const noexcept @@ -190,7 +173,7 @@ class ChunkCommon, LayoutStridedPolicy> template KOKKOS_FUNCTION constexpr size_type stride() const { - return m_internal_mdspan.stride(type_seq_rank_v>); + return m_allocation_mdspan.stride(type_seq_rank_v>); } /** Provide access to the domain on which this chunk is defined @@ -215,13 +198,13 @@ class ChunkCommon, LayoutStridedPolicy> KOKKOS_DEFAULTED_FUNCTION constexpr ChunkCommon() = default; /** Constructs a new ChunkCommon from scratch - * @param internal_mdspan + * @param allocation_mdspan * @param domain */ KOKKOS_FUNCTION constexpr ChunkCommon( - internal_mdspan_type internal_mdspan, + allocation_mdspan_type allocation_mdspan, discrete_domain_type const& domain) noexcept - : m_internal_mdspan(std::move(internal_mdspan)) + : m_allocation_mdspan(std::move(allocation_mdspan)) , m_domain(domain) { } @@ -234,7 +217,7 @@ class ChunkCommon, LayoutStridedPolicy> class Mapping = mapping_type, std::enable_if_t, int> = 0> KOKKOS_FUNCTION constexpr ChunkCommon(ElementType* ptr, discrete_domain_type const& domain) - : m_internal_mdspan(make_internal_mdspan(ptr, domain)) + : m_allocation_mdspan(make_allocation_mdspan(ptr, domain)) , m_domain(domain) { // Handle the case where an allocation of size 0 returns a nullptr. @@ -271,19 +254,7 @@ class ChunkCommon, LayoutStridedPolicy> */ KOKKOS_FUNCTION constexpr ElementType* data_handle() const { - ElementType* ptr = m_internal_mdspan.data_handle(); - if (!m_domain.empty()) { - ptr += m_internal_mdspan.mapping()(front(m_domain).uid()...); - } - return ptr; - } - - /** Provide a modifiable view of the data - * @return a modifiable view of the data - */ - KOKKOS_FUNCTION constexpr internal_mdspan_type internal_mdspan() const - { - return m_internal_mdspan; + return m_allocation_mdspan.data_handle(); } /** Provide a modifiable view of the data @@ -291,16 +262,7 @@ class ChunkCommon, LayoutStridedPolicy> */ KOKKOS_FUNCTION constexpr allocation_mdspan_type allocation_mdspan() const { - DDC_IF_NVCC_THEN_PUSH_AND_SUPPRESS(implicit_return_from_non_void_function) - extents_type const extents_s(::ddc::extents(m_domain).value()...); - if constexpr (std::is_same_v) { - mapping_type const map(extents_s, m_internal_mdspan.mapping().strides()); - return allocation_mdspan_type(data_handle(), map); - } else { - mapping_type const map(extents_s); - return allocation_mdspan_type(data_handle(), map); - } - DDC_IF_NVCC_THEN_POP + return m_allocation_mdspan; } }; diff --git a/include/ddc/chunk_span.hpp b/include/ddc/chunk_span.hpp index 411615b0c..af4a0b4f9 100644 --- a/include/ddc/chunk_span.hpp +++ b/include/ddc/chunk_span.hpp @@ -52,9 +52,6 @@ class ChunkSpan, LayoutStridedPolicy, Memo protected: using base_type = ChunkCommon, LayoutStridedPolicy>; - /// the raw mdspan underlying this, with the same indexing (0 might no be dereferenceable) - using typename base_type::internal_mdspan_type; - public: /// type of a span of this full chunk using span_type @@ -100,24 +97,6 @@ class ChunkSpan, LayoutStridedPolicy, Memo friend class ChunkSpan; protected: - static KOKKOS_FUNCTION internal_mdspan_type build_internal_mdspan( - allocation_mdspan_type const& allocation_mdspan, - discrete_domain_type const& domain) - { - if (!domain.empty()) { - extents_type const extents_s((front(domain) + extents(domain)).uid()...); - std::array const strides_s { - allocation_mdspan.mapping().stride( - type_seq_rank_v>)...}; - Kokkos::layout_stride::mapping const mapping_s(extents_s, strides_s); - return internal_mdspan_type( - allocation_mdspan.data_handle() - mapping_s(front(domain).uid()...), - mapping_s); - } - - return internal_mdspan_type(allocation_mdspan); - } - template KOKKOS_FUNCTION constexpr auto get_slicer_for(DiscreteElement const& c) const { @@ -175,7 +154,7 @@ class ChunkSpan, LayoutStridedPolicy, Memo class = std::enable_if_t>> KOKKOS_FUNCTION constexpr explicit ChunkSpan( Chunk& other) noexcept - : base_type(other.m_internal_mdspan, other.m_domain) + : base_type(other.m_allocation_mdspan, other.m_domain) { } @@ -191,7 +170,7 @@ class ChunkSpan, LayoutStridedPolicy, Memo class = std::enable_if_t>> KOKKOS_FUNCTION constexpr explicit ChunkSpan( Chunk const& other) noexcept - : base_type(other.m_internal_mdspan, other.m_domain) + : base_type(other.m_allocation_mdspan, other.m_domain) { } @@ -202,7 +181,7 @@ class ChunkSpan, LayoutStridedPolicy, Memo KOKKOS_FUNCTION constexpr explicit ChunkSpan( ChunkSpan const& other) noexcept - : base_type(other.m_internal_mdspan, other.m_domain) + : base_type(other.m_allocation_mdspan, other.m_domain) { } @@ -225,7 +204,7 @@ class ChunkSpan, LayoutStridedPolicy, Memo KOKKOS_FUNCTION constexpr ChunkSpan( allocation_mdspan_type allocation_mdspan, discrete_domain_type const& domain) - : base_type(build_internal_mdspan(allocation_mdspan, domain), domain) + : base_type(allocation_mdspan, domain) { assert(((allocation_mdspan.extent(type_seq_rank_v>) == static_cast(domain.template extent().value())) @@ -335,7 +314,9 @@ class ChunkSpan, LayoutStridedPolicy, Memo && ...)); assert(((DiscreteElement(take(delems...)) <= back(this->m_domain)) && ...)); - return DDC_MDSPAN_ACCESS_OP(this->m_internal_mdspan, uid(take(delems...))...); + return DDC_MDSPAN_ACCESS_OP( + this->m_allocation_mdspan, + (DiscreteElement(take(delems...)) - front(this->m_domain))...); } /** Access to the underlying allocation pointer From 6a1e80277c64443c28fdd234e0b38d235f93ebf3 Mon Sep 17 00:00:00 2001 From: Thomas Padioleau Date: Thu, 5 Dec 2024 22:21:11 +0100 Subject: [PATCH 02/12] Transfer distance function in DiscreteDomain --- include/ddc/chunk.hpp | 14 +++------- include/ddc/chunk_span.hpp | 7 ++--- include/ddc/discrete_domain.hpp | 47 +++++++++++++++++++++++++++++++++ tests/discrete_domain.cpp | 13 +++++++++ 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/include/ddc/chunk.hpp b/include/ddc/chunk.hpp index e46cbd683..906973d43 100644 --- a/include/ddc/chunk.hpp +++ b/include/ddc/chunk.hpp @@ -187,13 +187,10 @@ class Chunk, Allocator> sizeof...(DDims) == (0 + ... + DElems::size()), "Invalid number of dimensions"); static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); - assert(((DiscreteElement(take(delems...)) >= front(this->m_domain)) - && ...)); - assert(((DiscreteElement(take(delems...)) <= back(this->m_domain)) - && ...)); + assert(this->m_domain.is_inside(delems...)); return DDC_MDSPAN_ACCESS_OP( this->m_allocation_mdspan, - (DiscreteElement(take(delems...)) - front(this->m_domain))...); + detail::array(this->m_domain.distance_from_front(delems...))); } /** Element access using a list of DiscreteElement @@ -207,13 +204,10 @@ class Chunk, Allocator> sizeof...(DDims) == (0 + ... + DElems::size()), "Invalid number of dimensions"); static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); - assert(((DiscreteElement(take(delems...)) >= front(this->m_domain)) - && ...)); - assert(((DiscreteElement(take(delems...)) <= back(this->m_domain)) - && ...)); + assert(this->m_domain.is_inside(delems...)); return DDC_MDSPAN_ACCESS_OP( this->m_allocation_mdspan, - (DiscreteElement(take(delems...)) - front(this->m_domain))...); + detail::array(this->m_domain.distance_from_front(delems...))); } /** Returns the label of the Chunk diff --git a/include/ddc/chunk_span.hpp b/include/ddc/chunk_span.hpp index af4a0b4f9..6b5811ef7 100644 --- a/include/ddc/chunk_span.hpp +++ b/include/ddc/chunk_span.hpp @@ -310,13 +310,10 @@ class ChunkSpan, LayoutStridedPolicy, Memo sizeof...(DDims) == (0 + ... + DElems::size()), "Invalid number of dimensions"); static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); - assert(((DiscreteElement(take(delems...)) >= front(this->m_domain)) - && ...)); - assert(((DiscreteElement(take(delems...)) <= back(this->m_domain)) - && ...)); + assert(this->m_domain.is_inside(delems...)); return DDC_MDSPAN_ACCESS_OP( this->m_allocation_mdspan, - (DiscreteElement(take(delems...)) - front(this->m_domain))...); + detail::array(this->m_domain.distance_from_front(delems...))); } /** Access to the underlying allocation pointer diff --git a/include/ddc/discrete_domain.hpp b/include/ddc/discrete_domain.hpp index b7b70147e..f87fa0ba8 100644 --- a/include/ddc/discrete_domain.hpp +++ b/include/ddc/discrete_domain.hpp @@ -187,6 +187,33 @@ class DiscreteDomain DiscreteVector((get_or(oextents, get(myextents)))...)); } + template + bool is_inside(DElems const&... delems) const noexcept + { + static_assert( + sizeof...(DDims) == (0 + ... + DElems::size()), + "Invalid number of dimensions"); + static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); + return (((DiscreteElement(take(delems...)) + >= DiscreteElement(m_element_begin)) + && ...) + && ((DiscreteElement(take(delems...)) + < DiscreteElement(m_element_end)) + && ...)); + } + + template + DiscreteVector distance_from_front(DElems const&... delems) const noexcept + { + static_assert( + sizeof...(DDims) == (0 + ... + DElems::size()), + "Invalid number of dimensions"); + static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); + return DiscreteVector( + (DiscreteElement(take(delems...)) + - DiscreteElement(m_element_begin))...); + } + KOKKOS_FUNCTION constexpr bool empty() const noexcept { return size() == 0; @@ -361,6 +388,26 @@ class DiscreteDomain<> return *this; } + static bool is_inside() noexcept + { + return true; + } + + static bool is_inside(DiscreteElement<>) noexcept + { + return true; + } + + static DiscreteVector<> distance_from_front() noexcept + { + return DiscreteVector<>(); + } + + static DiscreteVector<> distance_from_front(DiscreteElement<>) noexcept + { + return DiscreteVector<>(); + } + static KOKKOS_FUNCTION constexpr bool empty() noexcept { return false; diff --git a/tests/discrete_domain.cpp b/tests/discrete_domain.cpp index b6e93fe07..41b5908fc 100644 --- a/tests/discrete_domain.cpp +++ b/tests/discrete_domain.cpp @@ -245,6 +245,19 @@ TEST(DiscreteDomainTest, Remove) DDomXY(dom_x_y.front() + DVectXY(1, 4), dom_x_y.extents() - DVectXY(2, 5))); } +TEST(DiscreteDomainTest, IsInside) +{ + DDomXY const dom_x_y(lbound_x_y, nelems_x_y); + EXPECT_TRUE(dom_x_y.is_inside(lbound_x_y)); + EXPECT_FALSE(dom_x_y.is_inside(lbound_x_y + nelems_x_y)); +} + +TEST(DiscreteDomainTest, DistanceFromFront) +{ + DDomXY const dom_x_y(lbound_x_y, nelems_x_y); + EXPECT_EQ(dom_x_y.distance_from_front(lbound_x_y), DVectXY(0, 0)); +} + TEST(DiscreteDomainTest, SliceDomainXTooearly) { #ifndef NDEBUG // The assertion is only checked if NDEBUG isn't defined From 325a0544d7f0ddbf72f1568fca7aa1f85f44a59b Mon Sep 17 00:00:00 2001 From: Thomas Padioleau Date: Thu, 5 Dec 2024 22:44:43 +0100 Subject: [PATCH 03/12] Almost implement Chunk and ChunkSpan with SupportType --- include/ddc/chunk.hpp | 93 +++++++++-------- include/ddc/chunk_common.hpp | 27 ++--- include/ddc/chunk_span.hpp | 195 +++++++++++++++++------------------ tests/chunk.cpp | 190 +++++++++++++++++----------------- 4 files changed, 248 insertions(+), 257 deletions(-) diff --git a/include/ddc/chunk.hpp b/include/ddc/chunk.hpp index 906973d43..ee757cb4a 100644 --- a/include/ddc/chunk.hpp +++ b/include/ddc/chunk.hpp @@ -24,25 +24,24 @@ class Chunk; template inline constexpr bool enable_chunk> = true; -template -class Chunk, Allocator> - : public ChunkCommon, Kokkos::layout_right> +template +class Chunk : public ChunkCommon { protected: - using base_type = ChunkCommon, Kokkos::layout_right>; + using base_type = ChunkCommon; public: /// type of a span of this full chunk using span_type = ChunkSpan< ElementType, - DiscreteDomain, + SupportType, Kokkos::layout_right, typename Allocator::memory_space>; /// type of a view of this full chunk using view_type = ChunkSpan< ElementType const, - DiscreteDomain, + SupportType, Kokkos::layout_right, typename Allocator::memory_space>; @@ -88,7 +87,7 @@ class Chunk, Allocator> /// Construct a labeled Chunk on a domain with uninitialized values explicit Chunk( std::string const& label, - discrete_domain_type const& domain, + SupportType const& domain, Allocator allocator = Allocator()) : base_type(allocator.allocate(label, domain.size()), domain) , m_allocator(std::move(allocator)) @@ -97,7 +96,7 @@ class Chunk, Allocator> } /// Construct a Chunk on a domain with uninitialized values - explicit Chunk(discrete_domain_type const& domain, Allocator allocator = Allocator()) + explicit Chunk(SupportType const& domain, Allocator allocator = Allocator()) : Chunk("no-label", domain, std::move(allocator)) { } @@ -148,33 +147,33 @@ class Chunk, Allocator> return *this; } - /// Slice out some dimensions - template - auto operator[](DiscreteElement const& slice_spec) const - { - return view_type(*this)[slice_spec]; - } - - /// Slice out some dimensions - template - auto operator[](DiscreteElement const& slice_spec) - { - return span_view()[slice_spec]; - } - - /// Slice out some dimensions - template - auto operator[](DiscreteDomain const& odomain) const - { - return span_view()[odomain]; - } - - /// Slice out some dimensions - template - auto operator[](DiscreteDomain const& odomain) - { - return span_view()[odomain]; - } + // /// Slice out some dimensions + // template + // auto operator[](DiscreteElement const& slice_spec) const + // { + // return view_type(*this)[slice_spec]; + // } + + // /// Slice out some dimensions + // template + // auto operator[](DiscreteElement const& slice_spec) + // { + // return span_view()[slice_spec]; + // } + + // /// Slice out some dimensions + // template + // auto operator[](DiscreteDomain const& odomain) const + // { + // return span_view()[odomain]; + // } + + // /// Slice out some dimensions + // template + // auto operator[](DiscreteDomain const& odomain) + // { + // return span_view()[odomain]; + // } /** Element access using a list of DiscreteElement * @param delems discrete coordinates @@ -184,7 +183,7 @@ class Chunk, Allocator> element_type const& operator()(DElems const&... delems) const noexcept { static_assert( - sizeof...(DDims) == (0 + ... + DElems::size()), + SupportType::rank() == (0 + ... + DElems::size()), "Invalid number of dimensions"); static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); assert(this->m_domain.is_inside(delems...)); @@ -201,7 +200,7 @@ class Chunk, Allocator> element_type& operator()(DElems const&... delems) noexcept { static_assert( - sizeof...(DDims) == (0 + ... + DElems::size()), + SupportType::rank() == (0 + ... + DElems::size()), "Invalid number of dimensions"); static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); assert(this->m_domain.is_inside(delems...)); @@ -259,9 +258,9 @@ class Chunk, Allocator> auto kokkos_layout = detail::build_kokkos_layout( s.extents(), s.mapping(), - std::make_index_sequence {}); + std::make_index_sequence {}); return Kokkos::View< - detail::mdspan_to_kokkos_element_t, + detail::mdspan_to_kokkos_element_t, decltype(kokkos_layout), typename Allocator::memory_space>(s.data_handle(), kokkos_layout); } @@ -275,9 +274,9 @@ class Chunk, Allocator> auto kokkos_layout = detail::build_kokkos_layout( s.extents(), s.mapping(), - std::make_index_sequence {}); + std::make_index_sequence {}); return Kokkos::View< - detail::mdspan_to_kokkos_element_t, + detail::mdspan_to_kokkos_element_t, decltype(kokkos_layout), typename Allocator::memory_space>(s.data_handle(), kokkos_layout); } @@ -298,13 +297,13 @@ class Chunk, Allocator> } }; -template +template Chunk(std::string const&, - DiscreteDomain const&, - Allocator) -> Chunk, Allocator>; + SupportType const&, + Allocator) -> Chunk; -template -Chunk(DiscreteDomain const&, - Allocator) -> Chunk, Allocator>; +template +Chunk(SupportType const&, + Allocator) -> Chunk; } // namespace ddc diff --git a/include/ddc/chunk_common.hpp b/include/ddc/chunk_common.hpp index 4f37a88dc..dea70dcc8 100644 --- a/include/ddc/chunk_common.hpp +++ b/include/ddc/chunk_common.hpp @@ -32,21 +32,21 @@ KOKKOS_FUNCTION auto get_domain(ChunkType const& chunk) noexcept template class ChunkCommon; -template -class ChunkCommon, LayoutStridedPolicy> +template +class ChunkCommon { public: - using discrete_domain_type = DiscreteDomain; + using discrete_domain_type = SupportType; /// The dereferenceable part of the co-domain but with a different domain, starting at 0 using allocation_mdspan_type = Kokkos::mdspan< ElementType, - Kokkos::dextents, + Kokkos::dextents, LayoutStridedPolicy>; using const_allocation_mdspan_type = Kokkos::mdspan< const ElementType, - Kokkos::dextents, + Kokkos::dextents, LayoutStridedPolicy>; using discrete_element_type = typename discrete_domain_type::discrete_element_type; @@ -86,7 +86,7 @@ class ChunkCommon, LayoutStridedPolicy> allocation_mdspan_type m_allocation_mdspan; /// The mesh on which this chunk is defined - discrete_domain_type m_domain; + SupportType m_domain; public: static KOKKOS_FUNCTION constexpr int rank() noexcept @@ -123,9 +123,9 @@ class ChunkCommon, LayoutStridedPolicy> template static KOKKOS_FUNCTION constexpr std:: enable_if_t, allocation_mdspan_type> - make_allocation_mdspan(ElementType* ptr, discrete_domain_type const& domain) + make_allocation_mdspan(ElementType* ptr, SupportType const& domain) { - return allocation_mdspan_type(ptr, ::ddc::extents(domain).value()...); + return allocation_mdspan_type(ptr, detail::array(domain.extents())); } public: @@ -134,7 +134,7 @@ class ChunkCommon, LayoutStridedPolicy> return m_allocation_mdspan.accessor(); } - KOKKOS_FUNCTION constexpr DiscreteVector extents() const noexcept + KOKKOS_FUNCTION constexpr SupportType::discrete_vector_type extents() const noexcept { return m_domain.extents(); } @@ -173,13 +173,14 @@ class ChunkCommon, LayoutStridedPolicy> template KOKKOS_FUNCTION constexpr size_type stride() const { - return m_allocation_mdspan.stride(type_seq_rank_v>); + return m_allocation_mdspan.stride( + type_seq_rank_v>); } /** Provide access to the domain on which this chunk is defined * @return the domain on which this chunk is defined */ - KOKKOS_FUNCTION constexpr discrete_domain_type domain() const noexcept + KOKKOS_FUNCTION constexpr SupportType domain() const noexcept { return m_domain; } @@ -203,7 +204,7 @@ class ChunkCommon, LayoutStridedPolicy> */ KOKKOS_FUNCTION constexpr ChunkCommon( allocation_mdspan_type allocation_mdspan, - discrete_domain_type const& domain) noexcept + SupportType const& domain) noexcept : m_allocation_mdspan(std::move(allocation_mdspan)) , m_domain(domain) { @@ -216,7 +217,7 @@ class ChunkCommon, LayoutStridedPolicy> template < class Mapping = mapping_type, std::enable_if_t, int> = 0> - KOKKOS_FUNCTION constexpr ChunkCommon(ElementType* ptr, discrete_domain_type const& domain) + KOKKOS_FUNCTION constexpr ChunkCommon(ElementType* ptr, SupportType const& domain) : m_allocation_mdspan(make_allocation_mdspan(ptr, domain)) , m_domain(domain) { diff --git a/include/ddc/chunk_span.hpp b/include/ddc/chunk_span.hpp index 6b5811ef7..fc6dfda00 100644 --- a/include/ddc/chunk_span.hpp +++ b/include/ddc/chunk_span.hpp @@ -39,9 +39,8 @@ inline constexpr bool enable_borrowed_chunk> = true; -template -class ChunkSpan, LayoutStridedPolicy, MemorySpace> - : public ChunkCommon, LayoutStridedPolicy> +template +class ChunkSpan : public ChunkCommon { static_assert( std::is_same_v @@ -50,19 +49,14 @@ class ChunkSpan, LayoutStridedPolicy, Memo "ChunkSpan only supports layout_left, layout_right or layout_stride"); protected: - using base_type = ChunkCommon, LayoutStridedPolicy>; + using base_type = ChunkCommon; public: /// type of a span of this full chunk - using span_type - = ChunkSpan, LayoutStridedPolicy, MemorySpace>; + using span_type = ChunkSpan; /// type of a view of this full chunk - using view_type = ChunkSpan< - ElementType const, - DiscreteDomain, - LayoutStridedPolicy, - MemorySpace>; + using view_type = ChunkSpan; using discrete_domain_type = typename base_type::discrete_domain_type; @@ -143,7 +137,7 @@ class ChunkSpan, LayoutStridedPolicy, Memo class OElementType, class Allocator, class = std::enable_if_t>> - ChunkSpan(Chunk&& other) noexcept = delete; + ChunkSpan(Chunk&& other) noexcept = delete; /** Constructs a new ChunkSpan from a Chunk, yields a new view to the same data * @param other the Chunk to view @@ -153,7 +147,7 @@ class ChunkSpan, LayoutStridedPolicy, Memo class Allocator, class = std::enable_if_t>> KOKKOS_FUNCTION constexpr explicit ChunkSpan( - Chunk& other) noexcept + Chunk& other) noexcept : base_type(other.m_allocation_mdspan, other.m_domain) { } @@ -169,7 +163,7 @@ class ChunkSpan, LayoutStridedPolicy, Memo class Allocator, class = std::enable_if_t>> KOKKOS_FUNCTION constexpr explicit ChunkSpan( - Chunk const& other) noexcept + Chunk const& other) noexcept : base_type(other.m_allocation_mdspan, other.m_domain) { } @@ -179,8 +173,7 @@ class ChunkSpan, LayoutStridedPolicy, Memo */ template KOKKOS_FUNCTION constexpr explicit ChunkSpan( - ChunkSpan const& - other) noexcept + ChunkSpan const& other) noexcept : base_type(other.m_allocation_mdspan, other.m_domain) { } @@ -192,7 +185,7 @@ class ChunkSpan, LayoutStridedPolicy, Memo template < class Mapping = mapping_type, std::enable_if_t, int> = 0> - KOKKOS_FUNCTION constexpr ChunkSpan(ElementType* const ptr, discrete_domain_type const& domain) + KOKKOS_FUNCTION constexpr ChunkSpan(ElementType* const ptr, SupportType const& domain) : base_type(ptr, domain) { } @@ -203,12 +196,13 @@ class ChunkSpan, LayoutStridedPolicy, Memo */ KOKKOS_FUNCTION constexpr ChunkSpan( allocation_mdspan_type allocation_mdspan, - discrete_domain_type const& domain) + SupportType const& domain) : base_type(allocation_mdspan, domain) { - assert(((allocation_mdspan.extent(type_seq_rank_v>) - == static_cast(domain.template extent().value())) - && ...)); + for (std::size_t i = 0; i < SupportType::rank(); ++i) { + assert(allocation_mdspan.extent(i) + == static_cast(detail::array(domain.extents())[i])); + } } /** Constructs a new ChunkSpan from scratch @@ -216,11 +210,9 @@ class ChunkSpan, LayoutStridedPolicy, Memo * @param domain the domain that sustains the view */ template >> - KOKKOS_FUNCTION constexpr ChunkSpan( - KokkosView const& view, - discrete_domain_type const& domain) noexcept + KOKKOS_FUNCTION constexpr ChunkSpan(KokkosView const& view, SupportType const& domain) noexcept : ChunkSpan( - detail::build_mdspan(view, std::make_index_sequence {}), + detail::build_mdspan(view, std::make_index_sequence {}), domain) { } @@ -239,65 +231,66 @@ class ChunkSpan, LayoutStridedPolicy, Memo */ KOKKOS_DEFAULTED_FUNCTION constexpr ChunkSpan& operator=(ChunkSpan&& other) noexcept = default; - /** Slice out some dimensions - */ - template - KOKKOS_FUNCTION constexpr auto operator[]( - DiscreteElement const& slice_spec) const - { - auto subview = Kokkos::submdspan(allocation_mdspan(), get_slicer_for(slice_spec)...); - using layout_type = typename decltype(subview)::layout_type; - using extents_type = typename decltype(subview)::extents_type; - using detail::TypeSeq; - using OutTypeSeqDDims = type_seq_remove_t, TypeSeq>; - using OutDDom = detail::convert_type_seq_to_discrete_domain_t; - if constexpr ( - std::is_same_v> - || std::is_same_v>) { - Kokkos::layout_stride::mapping const mapping_stride(subview.mapping()); - Kokkos::mdspan const - a(subview.data_handle(), mapping_stride); - return ChunkSpan< - ElementType, - OutDDom, - Kokkos::layout_stride, - memory_space>(a, OutDDom(this->m_domain)); - } else { - return ChunkSpan< - ElementType, - OutDDom, - layout_type, - memory_space>(subview, OutDDom(this->m_domain)); - } - } - - /** Restrict to a subdomain - */ - template - KOKKOS_FUNCTION constexpr auto operator[](DiscreteDomain const& odomain) const - { - auto subview = Kokkos::submdspan(allocation_mdspan(), get_slicer_for(odomain)...); - using layout_type = typename decltype(subview)::layout_type; - using extents_type = typename decltype(subview)::extents_type; - if constexpr ( - std::is_same_v> - || std::is_same_v>) { - Kokkos::layout_stride::mapping const mapping_stride(subview.mapping()); - Kokkos::mdspan const - a(subview.data_handle(), mapping_stride); - return ChunkSpan< - ElementType, - decltype(this->m_domain.restrict_with(odomain)), - Kokkos::layout_stride, - memory_space>(a, this->m_domain.restrict_with(odomain)); - } else { - return ChunkSpan< - ElementType, - decltype(this->m_domain.restrict_with(odomain)), - layout_type, - memory_space>(subview, this->m_domain.restrict_with(odomain)); - } - } + // /** Slice out some dimensions + // */ + // template + // KOKKOS_FUNCTION constexpr auto operator[]( + // DiscreteElement const& slice_spec) const + // { + // auto subview = Kokkos::submdspan(allocation_mdspan(), get_slicer_for(slice_spec)...); + // using layout_type = typename decltype(subview)::layout_type; + // using extents_type = typename decltype(subview)::extents_type; + // using detail::TypeSeq; + // using OutTypeSeqDDims + // = type_seq_remove_t, TypeSeq>; + // using OutDDom = detail::convert_type_seq_to_discrete_domain_t; + // if constexpr ( + // std::is_same_v> + // || std::is_same_v>) { + // Kokkos::layout_stride::mapping const mapping_stride(subview.mapping()); + // Kokkos::mdspan const + // a(subview.data_handle(), mapping_stride); + // return ChunkSpan< + // ElementType, + // OutDDom, + // Kokkos::layout_stride, + // memory_space>(a, OutDDom(this->m_domain)); + // } else { + // return ChunkSpan< + // ElementType, + // OutDDom, + // layout_type, + // memory_space>(subview, OutDDom(this->m_domain)); + // } + // } + + // /** Restrict to a subdomain + // */ + // template + // KOKKOS_FUNCTION constexpr auto operator[](DiscreteDomain const& odomain) const + // { + // auto subview = Kokkos::submdspan(allocation_mdspan(), get_slicer_for(odomain)...); + // using layout_type = typename decltype(subview)::layout_type; + // using extents_type = typename decltype(subview)::extents_type; + // if constexpr ( + // std::is_same_v> + // || std::is_same_v>) { + // Kokkos::layout_stride::mapping const mapping_stride(subview.mapping()); + // Kokkos::mdspan const + // a(subview.data_handle(), mapping_stride); + // return ChunkSpan< + // ElementType, + // decltype(this->m_domain.restrict_with(odomain)), + // Kokkos::layout_stride, + // memory_space>(a, this->m_domain.restrict_with(odomain)); + // } else { + // return ChunkSpan< + // ElementType, + // decltype(this->m_domain.restrict_with(odomain)), + // layout_type, + // memory_space>(subview, this->m_domain.restrict_with(odomain)); + // } + // } /** Element access using a list of DiscreteElement * @param delems discrete elements @@ -307,7 +300,7 @@ class ChunkSpan, LayoutStridedPolicy, Memo KOKKOS_FUNCTION constexpr reference operator()(DElems const&... delems) const noexcept { static_assert( - sizeof...(DDims) == (0 + ... + DElems::size()), + SupportType::rank() == (0 + ... + DElems::size()), "Invalid number of dimensions"); static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); assert(this->m_domain.is_inside(delems...)); @@ -341,9 +334,9 @@ class ChunkSpan, LayoutStridedPolicy, Memo auto kokkos_layout = detail::build_kokkos_layout( s.extents(), s.mapping(), - std::make_index_sequence {}); + std::make_index_sequence {}); return Kokkos::View< - detail::mdspan_to_kokkos_element_t, + detail::mdspan_to_kokkos_element_t, decltype(kokkos_layout), MemorySpace>(s.data_handle(), kokkos_layout); } @@ -359,33 +352,31 @@ class ChunkSpan, LayoutStridedPolicy, Memo } }; -template +template KOKKOS_DEDUCTION_GUIDE ChunkSpan( Kokkos::View const& view, - DiscreteDomain domain) + SupportType domain) -> ChunkSpan< detail::kokkos_to_mdspan_element_t< typename Kokkos::View::data_type>, - DiscreteDomain, + SupportType, detail::kokkos_to_mdspan_layout_t< typename Kokkos::View::array_layout>, typename Kokkos::View::memory_space>; template -ChunkSpan(Chunk& other) - -> ChunkSpan< - ElementType, - SupportType, - Kokkos::layout_right, - typename Allocator::memory_space>; +ChunkSpan(Chunk& other) -> ChunkSpan< + ElementType, + SupportType, + Kokkos::layout_right, + typename Allocator::memory_space>; template -ChunkSpan(Chunk const& other) - -> ChunkSpan< - const ElementType, - SupportType, - Kokkos::layout_right, - typename Allocator::memory_space>; +ChunkSpan(Chunk const& other) -> ChunkSpan< + const ElementType, + SupportType, + Kokkos::layout_right, + typename Allocator::memory_space>; template < class ElementType, diff --git a/tests/chunk.cpp b/tests/chunk.cpp index 0733da4d7..5010e2dab 100644 --- a/tests/chunk.cpp +++ b/tests/chunk.cpp @@ -468,101 +468,101 @@ TEST(Chunk2DTest, Cview) } } -TEST(Chunk2DTest, SliceCoordX) -{ - DElemX const slice_x_val(lbound_x + 1); - - ChunkXY chunk(dom_x_y); - ChunkXY const& chunk_cref = chunk; - for (DElemX const ix : chunk.domain()) { - for (DElemY const iy : chunk.domain()) { - chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); - } - } - - ddc::ChunkSpan const chunk_y = chunk_cref[slice_x_val]; - EXPECT_TRUE( - (std::is_same_v::layout_type, Kokkos::layout_right>)); - EXPECT_EQ(chunk_y.extent(), chunk.extent()); - for (DElemY const iy : chunk_cref.domain()) { - // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy - EXPECT_EQ(chunk_y(iy), chunk_cref(slice_x_val, iy)); - } -} - -TEST(Chunk2DTest, SliceCoordY) -{ - DElemY const slice_y_val(lbound_y + 1); - - ChunkXY chunk(dom_x_y); - ChunkXY const& chunk_cref = chunk; - for (DElemX const ix : chunk.domain()) { - for (DElemY const iy : chunk.domain()) { - chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); - } - } - - ddc::ChunkSpan const chunk_x = chunk_cref[slice_y_val]; - EXPECT_TRUE( - (std::is_same_v::layout_type, Kokkos::layout_stride>)); - EXPECT_EQ(chunk_x.extent(), chunk.extent()); - for (DElemX const ix : chunk_cref.domain()) { - // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy - EXPECT_EQ(chunk_x(ix), chunk_cref(ix, slice_y_val)); - } -} - -TEST(Chunk2DTest, SliceDomainX) -{ - DDomX const subdomain_x(lbound_x + 1, nelems_x - 2); - - ChunkXY chunk(dom_x_y); - ChunkXY const& chunk_cref = chunk; - for (DElemX const ix : chunk.domain()) { - for (DElemY const iy : chunk.domain()) { - chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); - } - } - - ddc::ChunkSpan const subchunk_x = chunk_cref[subdomain_x]; - EXPECT_TRUE(( - std::is_same_v::layout_type, Kokkos::layout_right>)); - - EXPECT_EQ(subchunk_x.extent(), subdomain_x.size()); - EXPECT_EQ(subchunk_x.extent(), chunk.domain().size()); - for (DElemX const ix : subchunk_x.domain()) { - for (DElemY const iy : subchunk_x.domain()) { - // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy - EXPECT_EQ(subchunk_x(ix, iy), chunk_cref(ix, iy)); - } - } -} - -TEST(Chunk2DTest, SliceDomainY) -{ - DDomY const subdomain_y(lbound_y + 1, nelems_y - 2); - - ChunkXY chunk(dom_x_y); - ChunkXY const& chunk_cref = chunk; - for (DElemX const ix : chunk.domain()) { - for (DElemY const iy : chunk.domain()) { - chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); - } - } - ddc::ChunkSpan const subchunk_y = chunk_cref[subdomain_y]; - EXPECT_TRUE((std::is_same_v< - std::decay_t::layout_type, - Kokkos::layout_stride>)); - - EXPECT_EQ(subchunk_y.extent(), chunk.domain().size()); - EXPECT_EQ(subchunk_y.extent(), subdomain_y.size()); - for (DElemX const ix : subchunk_y.domain()) { - for (DElemY const iy : subchunk_y.domain()) { - // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy - EXPECT_EQ(subchunk_y(ix, iy), chunk_cref(ix, iy)); - } - } -} +// TEST(Chunk2DTest, SliceCoordX) +// { +// DElemX const slice_x_val(lbound_x + 1); + +// ChunkXY chunk(dom_x_y); +// ChunkXY const& chunk_cref = chunk; +// for (DElemX const ix : chunk.domain()) { +// for (DElemY const iy : chunk.domain()) { +// chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); +// } +// } + +// ddc::ChunkSpan const chunk_y = chunk_cref[slice_x_val]; +// EXPECT_TRUE( +// (std::is_same_v::layout_type, Kokkos::layout_right>)); +// EXPECT_EQ(chunk_y.extent(), chunk.extent()); +// for (DElemY const iy : chunk_cref.domain()) { +// // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy +// EXPECT_EQ(chunk_y(iy), chunk_cref(slice_x_val, iy)); +// } +// } + +// TEST(Chunk2DTest, SliceCoordY) +// { +// DElemY const slice_y_val(lbound_y + 1); + +// ChunkXY chunk(dom_x_y); +// ChunkXY const& chunk_cref = chunk; +// for (DElemX const ix : chunk.domain()) { +// for (DElemY const iy : chunk.domain()) { +// chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); +// } +// } + +// ddc::ChunkSpan const chunk_x = chunk_cref[slice_y_val]; +// EXPECT_TRUE( +// (std::is_same_v::layout_type, Kokkos::layout_stride>)); +// EXPECT_EQ(chunk_x.extent(), chunk.extent()); +// for (DElemX const ix : chunk_cref.domain()) { +// // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy +// EXPECT_EQ(chunk_x(ix), chunk_cref(ix, slice_y_val)); +// } +// } + +// TEST(Chunk2DTest, SliceDomainX) +// { +// DDomX const subdomain_x(lbound_x + 1, nelems_x - 2); + +// ChunkXY chunk(dom_x_y); +// ChunkXY const& chunk_cref = chunk; +// for (DElemX const ix : chunk.domain()) { +// for (DElemY const iy : chunk.domain()) { +// chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); +// } +// } + +// ddc::ChunkSpan const subchunk_x = chunk_cref[subdomain_x]; +// EXPECT_TRUE(( +// std::is_same_v::layout_type, Kokkos::layout_right>)); + +// EXPECT_EQ(subchunk_x.extent(), subdomain_x.size()); +// EXPECT_EQ(subchunk_x.extent(), chunk.domain().size()); +// for (DElemX const ix : subchunk_x.domain()) { +// for (DElemY const iy : subchunk_x.domain()) { +// // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy +// EXPECT_EQ(subchunk_x(ix, iy), chunk_cref(ix, iy)); +// } +// } +// } + +// TEST(Chunk2DTest, SliceDomainY) +// { +// DDomY const subdomain_y(lbound_y + 1, nelems_y - 2); + +// ChunkXY chunk(dom_x_y); +// ChunkXY const& chunk_cref = chunk; +// for (DElemX const ix : chunk.domain()) { +// for (DElemY const iy : chunk.domain()) { +// chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); +// } +// } +// ddc::ChunkSpan const subchunk_y = chunk_cref[subdomain_y]; +// EXPECT_TRUE((std::is_same_v< +// std::decay_t::layout_type, +// Kokkos::layout_stride>)); + +// EXPECT_EQ(subchunk_y.extent(), chunk.domain().size()); +// EXPECT_EQ(subchunk_y.extent(), subdomain_y.size()); +// for (DElemX const ix : subchunk_y.domain()) { +// for (DElemY const iy : subchunk_y.domain()) { +// // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy +// EXPECT_EQ(subchunk_y(ix, iy), chunk_cref(ix, iy)); +// } +// } +// } TEST(Chunk2DTest, Deepcopy) { From 5d4187f3632dfdd37eb92c036b470b82dcc814e8 Mon Sep 17 00:00:00 2001 From: Thomas Padioleau Date: Mon, 9 Dec 2024 10:18:41 +0100 Subject: [PATCH 04/12] Add StridedDiscreteDomain --- include/ddc/ddc.hpp | 1 + include/ddc/strided_discrete_domain.hpp | 729 ++++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/chunk.cpp | 9 + tests/strided_discrete_domain.cpp | 322 +++++++++++ 5 files changed, 1062 insertions(+) create mode 100644 include/ddc/strided_discrete_domain.hpp create mode 100644 tests/strided_discrete_domain.cpp diff --git a/include/ddc/ddc.hpp b/include/ddc/ddc.hpp index 6f7e8d312..73ffbbb79 100644 --- a/include/ddc/ddc.hpp +++ b/include/ddc/ddc.hpp @@ -31,6 +31,7 @@ namespace ddc { #include "ddc/discrete_vector.hpp" #include "ddc/non_uniform_point_sampling.hpp" #include "ddc/periodic_sampling.hpp" +#include "ddc/strided_discrete_domain.hpp" #include "ddc/uniform_point_sampling.hpp" // Algorithms diff --git a/include/ddc/strided_discrete_domain.hpp b/include/ddc/strided_discrete_domain.hpp new file mode 100644 index 000000000..12b84eebb --- /dev/null +++ b/include/ddc/strided_discrete_domain.hpp @@ -0,0 +1,729 @@ +// Copyright (C) The DDC development team, see COPYRIGHT.md file +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include "ddc/detail/type_seq.hpp" +#include "ddc/discrete_element.hpp" +#include "ddc/discrete_vector.hpp" + +namespace ddc { + +template +struct StridedDiscreteDomainIterator; + +template +class StridedDiscreteDomain; + +template +struct is_strided_discrete_domain : std::false_type +{ +}; + +template +struct is_strided_discrete_domain> : std::true_type +{ +}; + +template +inline constexpr bool is_strided_discrete_domain_v = is_strided_discrete_domain::value; + + +namespace detail { + +template +struct ToTypeSeq> +{ + using type = TypeSeq; +}; + +} // namespace detail + +template +DiscreteVector prod( + DiscreteVector const& lhs, + DiscreteVector const& rhs) noexcept +{ + return DiscreteVector((get(lhs) * get(rhs))...); +} + +template +class StridedDiscreteDomain +{ + template + friend class StridedDiscreteDomain; + +public: + using discrete_element_type = DiscreteElement; + + using discrete_vector_type = DiscreteVector; + +private: + DiscreteElement m_element_begin; + + DiscreteVector m_extents; + + DiscreteVector m_strides; + +public: + static KOKKOS_FUNCTION constexpr std::size_t rank() + { + return sizeof...(DDims); + } + + KOKKOS_DEFAULTED_FUNCTION StridedDiscreteDomain() = default; + + /// Construct a StridedDiscreteDomain by copies and merge of domains + template < + class... DDoms, + class = std::enable_if_t<(is_strided_discrete_domain_v && ...)>> + KOKKOS_FUNCTION constexpr explicit StridedDiscreteDomain(DDoms const&... domains) + : m_element_begin(domains.front()...) + , m_extents(domains.extents()...) + , m_strides(domains.strides()...) + { + } + + /** Construct a StridedDiscreteDomain starting from element_begin with size points. + * @param element_begin the lower bound in each direction + * @param size the number of points in each direction + */ + KOKKOS_FUNCTION constexpr StridedDiscreteDomain( + discrete_element_type const& element_begin, + discrete_vector_type const& extents, + discrete_vector_type const& strides) + : m_element_begin(element_begin) + , m_extents(extents) + , m_strides(strides) + { + } + + KOKKOS_DEFAULTED_FUNCTION StridedDiscreteDomain(StridedDiscreteDomain const& x) = default; + + KOKKOS_DEFAULTED_FUNCTION StridedDiscreteDomain(StridedDiscreteDomain&& x) = default; + + KOKKOS_DEFAULTED_FUNCTION ~StridedDiscreteDomain() = default; + + KOKKOS_DEFAULTED_FUNCTION StridedDiscreteDomain& operator=(StridedDiscreteDomain const& x) + = default; + + KOKKOS_DEFAULTED_FUNCTION StridedDiscreteDomain& operator=(StridedDiscreteDomain&& x) = default; + + template + KOKKOS_FUNCTION constexpr bool operator==(StridedDiscreteDomain const& other) const + { + if (empty() && other.empty()) { + return true; + } + return m_element_begin == other.m_element_begin && m_extents == other.m_extents + && m_strides == other.m_strides; + } + +#if !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201902L + // In C++20, `a!=b` shall be automatically translated by the compiler to `!(a==b)` + template + KOKKOS_FUNCTION constexpr bool operator!=(StridedDiscreteDomain const& other) const + { + return !(*this == other); + } +#endif + + KOKKOS_FUNCTION constexpr std::size_t size() const + { + return (1UL * ... * get(m_extents)); + } + + KOKKOS_FUNCTION constexpr discrete_vector_type extents() const noexcept + { + return m_extents; + } + + KOKKOS_FUNCTION constexpr discrete_vector_type strides() const noexcept + { + return m_strides; + } + + template + KOKKOS_FUNCTION constexpr DiscreteVector extent() const noexcept + { + return DiscreteVector(uid(m_extents)); + } + + KOKKOS_FUNCTION constexpr discrete_element_type front() const noexcept + { + return m_element_begin; + } + + KOKKOS_FUNCTION constexpr discrete_element_type back() const noexcept + { + return discrete_element_type( + (uid(m_element_begin) + + (get(m_extents) - 1) * get(m_strides))...); + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomain take_first(discrete_vector_type n) const + { + return StridedDiscreteDomain(front(), n, m_strides); + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomain take_last(discrete_vector_type n) const + { + return StridedDiscreteDomain(front() + prod(extents() - n, m_strides), n, m_strides); + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomain remove_first(discrete_vector_type n) const + { + return StridedDiscreteDomain(front() + prod(n, m_strides), extents() - n, m_strides); + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomain remove_last(discrete_vector_type n) const + { + return StridedDiscreteDomain(front(), extents() - n, m_strides); + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomain remove( + discrete_vector_type n1, + discrete_vector_type n2) const + { + return StridedDiscreteDomain(front() + prod(n1, m_strides), extents() - n1 - n2, m_strides); + } + + // template + // KOKKOS_FUNCTION constexpr auto restrict_with( + // StridedDiscreteDomain const& odomain) const + // { + // assert(((uid(m_element_begin) <= uid(odomain.m_element_begin)) && ...)); + // assert(((uid(m_element_end) >= uid(odomain.m_element_end)) && ...)); + // const DiscreteVector myextents = extents(); + // const DiscreteVector oextents = odomain.extents(); + // return StridedDiscreteDomain( + // DiscreteElement( + // (uid_or(odomain.m_element_begin, uid(m_element_begin)))...), + // DiscreteVector((get_or(oextents, get(myextents)))...)); + // } + + template + bool is_inside(DElems const&... delems) const noexcept + { + static_assert( + sizeof...(DDims) == (0 + ... + DElems::size()), + "Invalid number of dimensions"); + static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); + auto const test1 + = ((select(take(delems...)) >= select(m_element_begin)) + && ...); + auto const test2 + = ((select(take(delems...)) + < (select(m_element_begin) + + select(m_extents) * select(m_strides))) + && ...); + auto const test3 + = ((((select(take(delems...)) - select(m_element_begin)) + % select(m_strides)) + == 0) + && ...); + return test1 && test2 && test3; + } + + template + DiscreteVector distance_from_front(DElems const&... delems) const noexcept + { + static_assert( + sizeof...(DDims) == (0 + ... + DElems::size()), + "Invalid number of dimensions"); + static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); + assert(is_inside(delems...)); + return DiscreteVector( + ((select(take(delems...)) - select(m_element_begin)) + / select(m_strides))...); + } + + KOKKOS_FUNCTION constexpr bool empty() const noexcept + { + return size() == 0; + } + + KOKKOS_FUNCTION constexpr explicit operator bool() + { + return !empty(); + } + + template < + std::size_t N = sizeof...(DDims), + class DDim0 = std::enable_if_t>>> + KOKKOS_FUNCTION auto begin() const + { + return StridedDiscreteDomainIterator(front(), m_strides); + } + + template < + std::size_t N = sizeof...(DDims), + class DDim0 = std::enable_if_t>>> + KOKKOS_FUNCTION auto end() const + { + return StridedDiscreteDomainIterator< + DDim0>(m_element_begin + m_extents * m_strides, m_strides); + } + + template < + std::size_t N = sizeof...(DDims), + class DDim0 = std::enable_if_t>>> + KOKKOS_FUNCTION auto cbegin() const + { + return StridedDiscreteDomainIterator(front(), m_strides); + } + + template < + std::size_t N = sizeof...(DDims), + class DDim0 = std::enable_if_t>>> + KOKKOS_FUNCTION auto cend() const + { + return StridedDiscreteDomainIterator< + DDim0>(m_element_begin + m_extents * m_strides, m_strides); + } + + template < + std::size_t N = sizeof...(DDims), + class = std::enable_if_t>>> + KOKKOS_FUNCTION constexpr decltype(auto) operator[](std::size_t n) + { + return begin()[n]; + } + + template < + std::size_t N = sizeof...(DDims), + class = std::enable_if_t>>> + KOKKOS_FUNCTION constexpr decltype(auto) operator[](std::size_t n) const + { + return begin()[n]; + } +}; + +template <> +class StridedDiscreteDomain<> +{ + template + friend class StridedDiscreteDomain; + +public: + using discrete_element_type = DiscreteElement<>; + + using discrete_vector_type = DiscreteVector<>; + + static KOKKOS_FUNCTION constexpr std::size_t rank() + { + return 0; + } + + KOKKOS_DEFAULTED_FUNCTION constexpr StridedDiscreteDomain() = default; + + // Construct a StridedDiscreteDomain from a reordered copy of `domain` + template + KOKKOS_FUNCTION constexpr explicit StridedDiscreteDomain( + [[maybe_unused]] StridedDiscreteDomain const& domain) + { + } + + /** Construct a StridedDiscreteDomain starting from element_begin with size points. + * @param element_begin the lower bound in each direction + * @param size the number of points in each direction + */ + KOKKOS_FUNCTION constexpr StridedDiscreteDomain( + [[maybe_unused]] discrete_element_type const& element_begin, + [[maybe_unused]] discrete_vector_type const& size) + { + } + + KOKKOS_DEFAULTED_FUNCTION StridedDiscreteDomain(StridedDiscreteDomain const& x) = default; + + KOKKOS_DEFAULTED_FUNCTION StridedDiscreteDomain(StridedDiscreteDomain&& x) = default; + + KOKKOS_DEFAULTED_FUNCTION ~StridedDiscreteDomain() = default; + + KOKKOS_DEFAULTED_FUNCTION StridedDiscreteDomain& operator=(StridedDiscreteDomain const& x) + = default; + + KOKKOS_DEFAULTED_FUNCTION StridedDiscreteDomain& operator=(StridedDiscreteDomain&& x) = default; + + KOKKOS_FUNCTION constexpr bool operator==( + [[maybe_unused]] StridedDiscreteDomain const& other) const + { + return true; + } + +#if !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201902L + // In C++20, `a!=b` shall be automatically translated by the compiler to `!(a==b)` + KOKKOS_FUNCTION constexpr bool operator!=(StridedDiscreteDomain const& other) const + { + return !(*this == other); + } +#endif + + static KOKKOS_FUNCTION constexpr std::size_t size() + { + return 1; + } + + static KOKKOS_FUNCTION constexpr discrete_vector_type extents() noexcept + { + return {}; + } + + static KOKKOS_FUNCTION constexpr discrete_element_type front() noexcept + { + return {}; + } + + static KOKKOS_FUNCTION constexpr discrete_element_type back() noexcept + { + return {}; + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomain take_first( + [[maybe_unused]] discrete_vector_type n) const + { + return *this; + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomain take_last( + [[maybe_unused]] discrete_vector_type n) const + { + return *this; + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomain remove_first( + [[maybe_unused]] discrete_vector_type n) const + { + return *this; + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomain remove_last( + [[maybe_unused]] discrete_vector_type n) const + { + return *this; + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomain remove( + [[maybe_unused]] discrete_vector_type n1, + [[maybe_unused]] discrete_vector_type n2) const + { + return *this; + } + +#if defined(DDC_BUILD_DEPRECATED_CODE) + template + [[deprecated( + "Use `restrict_with` " + "instead")]] KOKKOS_FUNCTION constexpr StridedDiscreteDomain restrict(StridedDiscreteDomain const& + odomain) + const + { + return restrict_with(odomain); + } +#endif + + template + KOKKOS_FUNCTION constexpr StridedDiscreteDomain restrict_with( + StridedDiscreteDomain const& /* odomain */) const + { + return *this; + } + + static bool is_inside() noexcept + { + return true; + } + + static bool is_inside(DiscreteElement<>) noexcept + { + return true; + } + + static DiscreteVector<> distance_from_front() noexcept + { + return DiscreteVector<>(); + } + + static DiscreteVector<> distance_from_front(DiscreteElement<>) noexcept + { + return DiscreteVector<>(); + } + + static KOKKOS_FUNCTION constexpr bool empty() noexcept + { + return false; + } + + KOKKOS_FUNCTION constexpr explicit operator bool() + { + return true; + } +}; + +template +KOKKOS_FUNCTION constexpr StridedDiscreteDomain select( + StridedDiscreteDomain const& domain) +{ + return StridedDiscreteDomain( + select(domain.front()), + select(domain.extents())); +} + +namespace detail { + +template +struct ConvertTypeSeqToStridedDiscreteDomain; + +template +struct ConvertTypeSeqToStridedDiscreteDomain> +{ + using type = StridedDiscreteDomain; +}; + +template +using convert_type_seq_to_strided_discrete_domain_t = + typename ConvertTypeSeqToStridedDiscreteDomain::type; + +} // namespace detail + +// Computes the substraction DDom_a - DDom_b in the sense of linear spaces(retained dimensions are those in DDom_a which are not in DDom_b) +template +KOKKOS_FUNCTION constexpr auto remove_dims_of( + StridedDiscreteDomain const& DDom_a, + [[maybe_unused]] StridedDiscreteDomain const& DDom_b) noexcept +{ + using TagSeqA = detail::TypeSeq; + using TagSeqB = detail::TypeSeq; + + using type_seq_r = type_seq_remove_t; + return detail::convert_type_seq_to_strided_discrete_domain_t(DDom_a); +} + +namespace detail { + +// Checks if dimension of DDom_a is DDim1. If not, returns restriction to DDim2 of DDom_b. May not be usefull in its own, it helps for replace_dim_of +template +KOKKOS_FUNCTION constexpr std::conditional_t< + std::is_same_v, + ddc::StridedDiscreteDomain, + ddc::StridedDiscreteDomain> +replace_dim_of_1d( + StridedDiscreteDomain const& DDom_a, + [[maybe_unused]] StridedDiscreteDomain const& DDom_b) noexcept +{ + if constexpr (std::is_same_v) { + return ddc::select(DDom_b); + } else { + return DDom_a; + } +} + +} // namespace detail + +// Replace in DDom_a the dimension Dim1 by the dimension Dim2 of DDom_b +template +KOKKOS_FUNCTION constexpr auto replace_dim_of( + StridedDiscreteDomain const& DDom_a, + [[maybe_unused]] StridedDiscreteDomain const& DDom_b) noexcept +{ + // TODO : static_asserts + using TagSeqA = detail::TypeSeq; + using TagSeqB = detail::TypeSeq; + using TagSeqC = detail::TypeSeq; + + using type_seq_r = ddc::type_seq_replace_t; + return ddc::detail::convert_type_seq_to_strided_discrete_domain_t( + detail::replace_dim_of_1d< + DDim1, + DDim2, + DDimsA, + DDimsB...>(ddc::select(DDom_a), DDom_b)...); +} + +template +KOKKOS_FUNCTION constexpr DiscreteVector extents( + StridedDiscreteDomain const& domain) noexcept +{ + return DiscreteVector(select(domain).size()...); +} + +template +KOKKOS_FUNCTION constexpr DiscreteElement front( + StridedDiscreteDomain const& domain) noexcept +{ + return DiscreteElement(select(domain).front()...); +} + +template +KOKKOS_FUNCTION constexpr DiscreteElement back( + StridedDiscreteDomain const& domain) noexcept +{ + return DiscreteElement(select(domain).back()...); +} + +template +struct StridedDiscreteDomainIterator +{ +private: + DiscreteElement m_value = DiscreteElement(); + + DiscreteVector m_stride = DiscreteVector(); + +public: + using iterator_category = std::random_access_iterator_tag; + + using value_type = DiscreteElement; + + using difference_type = std::ptrdiff_t; + + KOKKOS_DEFAULTED_FUNCTION StridedDiscreteDomainIterator() = default; + + KOKKOS_FUNCTION constexpr explicit StridedDiscreteDomainIterator( + DiscreteElement value, + DiscreteVector stride) + : m_value(value) + , m_stride(stride) + { + } + + KOKKOS_FUNCTION constexpr DiscreteElement operator*() const noexcept + { + return m_value; + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomainIterator& operator++() + { + m_value.uid() += m_stride.value(); + return *this; + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomainIterator operator++(int) + { + auto tmp = *this; + ++*this; + return tmp; + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomainIterator& operator--() + { + m_value.uid() -= m_stride.value(); + return *this; + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomainIterator operator--(int) + { + auto tmp = *this; + --*this; + return tmp; + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomainIterator& operator+=(difference_type n) + { + if (n >= difference_type(0)) { + m_value.uid() += static_cast(n) * m_stride.value(); + } else { + m_value.uid() -= static_cast(-n) * m_stride.value(); + } + return *this; + } + + KOKKOS_FUNCTION constexpr StridedDiscreteDomainIterator& operator-=(difference_type n) + { + if (n >= difference_type(0)) { + m_value.uid() -= static_cast(n) * m_stride.value(); + } else { + m_value.uid() += static_cast(-n) * m_stride.value(); + } + return *this; + } + + KOKKOS_FUNCTION constexpr DiscreteElement operator[](difference_type n) const + { + return m_value + n * m_stride.value(); + } + + friend KOKKOS_FUNCTION constexpr bool operator==( + StridedDiscreteDomainIterator const& xx, + StridedDiscreteDomainIterator const& yy) + { + return xx.m_value == yy.m_value; + } + +#if !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201902L + // In C++20, `a!=b` shall be automatically translated by the compiler to `!(a==b)` + friend KOKKOS_FUNCTION constexpr bool operator!=( + StridedDiscreteDomainIterator const& xx, + StridedDiscreteDomainIterator const& yy) + { + return xx.m_value != yy.m_value; + } +#endif + + friend KOKKOS_FUNCTION constexpr bool operator<( + StridedDiscreteDomainIterator const& xx, + StridedDiscreteDomainIterator const& yy) + { + return xx.m_value < yy.m_value; + } + + friend KOKKOS_FUNCTION constexpr bool operator>( + StridedDiscreteDomainIterator const& xx, + StridedDiscreteDomainIterator const& yy) + { + return yy < xx; + } + + friend KOKKOS_FUNCTION constexpr bool operator<=( + StridedDiscreteDomainIterator const& xx, + StridedDiscreteDomainIterator const& yy) + { + return !(yy < xx); + } + + friend KOKKOS_FUNCTION constexpr bool operator>=( + StridedDiscreteDomainIterator const& xx, + StridedDiscreteDomainIterator const& yy) + { + return !(xx < yy); + } + + friend KOKKOS_FUNCTION constexpr StridedDiscreteDomainIterator operator+( + StridedDiscreteDomainIterator i, + difference_type n) + { + return i += n; + } + + friend KOKKOS_FUNCTION constexpr StridedDiscreteDomainIterator operator+( + difference_type n, + StridedDiscreteDomainIterator i) + { + return i += n; + } + + friend KOKKOS_FUNCTION constexpr StridedDiscreteDomainIterator operator-( + StridedDiscreteDomainIterator i, + difference_type n) + { + return i -= n; + } + + friend KOKKOS_FUNCTION constexpr difference_type operator-( + StridedDiscreteDomainIterator const& xx, + StridedDiscreteDomainIterator const& yy) + { + return (yy.m_value > xx.m_value) ? (-static_cast(yy.m_value - xx.m_value)) + : (xx.m_value - yy.m_value); + } +}; + +} // namespace ddc diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8aeacaa23..25ac4916f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -29,6 +29,7 @@ add_executable( relocatable_device_code.cpp relocatable_device_code_initialization.cpp single_discretization.cpp + strided_discrete_domain.cpp tagged_vector.cpp transform_reduce.cpp type_seq.cpp diff --git a/tests/chunk.cpp b/tests/chunk.cpp index 5010e2dab..3512f5549 100644 --- a/tests/chunk.cpp +++ b/tests/chunk.cpp @@ -634,3 +634,12 @@ TEST(Chunk2DTest, Mirror) } } } + +TEST(ChunkStridedDiscreteDomain, Constructor) +{ + ddc::StridedDiscreteDomain dom(lbound_x_y, nelems_x_y, DVectXY(10, 10)); + ddc::Chunk chk("", dom, ddc::HostAllocator()); + ddc::parallel_fill(chk.span_view(), 2); + EXPECT_EQ(chk(lbound_x_y), 2); + EXPECT_EQ(chk(lbound_x_y + DVectXY(10, 10)), 2); +} diff --git a/tests/strided_discrete_domain.cpp b/tests/strided_discrete_domain.cpp new file mode 100644 index 000000000..c84eea2de --- /dev/null +++ b/tests/strided_discrete_domain.cpp @@ -0,0 +1,322 @@ +// Copyright (C) The DDC development team, see COPYRIGHT.md file +// +// SPDX-License-Identifier: MIT + +#include + +#include + +namespace DDC_HIP_5_7_ANONYMOUS_NAMESPACE_WORKAROUND(DISCRETE_DOMAIN_CPP) { + +struct DDimX +{ +}; +using DElemX = ddc::DiscreteElement; +using DVectX = ddc::DiscreteVector; +using DDomX = ddc::StridedDiscreteDomain; + + +struct DDimY +{ +}; +using DElemY = ddc::DiscreteElement; +using DVectY = ddc::DiscreteVector; +using DDomY = ddc::StridedDiscreteDomain; + + +struct DDimZ +{ +}; +using DElemZ = ddc::DiscreteElement; +using DVectZ = ddc::DiscreteVector; +using DDomZ = ddc::StridedDiscreteDomain; + + +using DElemXY = ddc::DiscreteElement; +using DVectXY = ddc::DiscreteVector; +using DDomXY = ddc::StridedDiscreteDomain; + + +using DElemYX = ddc::DiscreteElement; +using DVectYX = ddc::DiscreteVector; +using DDomYX = ddc::StridedDiscreteDomain; + +using DElemXZ = ddc::DiscreteElement; +using DVectXZ = ddc::DiscreteVector; +using DDomXZ = ddc::StridedDiscreteDomain; + +using DElemZY = ddc::DiscreteElement; +using DVectZY = ddc::DiscreteVector; +using DDomZY = ddc::StridedDiscreteDomain; + + +using DElemXYZ = ddc::DiscreteElement; +using DVectXYZ = ddc::DiscreteVector; +using DDomXYZ = ddc::StridedDiscreteDomain; + +using DElemZYX = ddc::DiscreteElement; +using DVectZYX = ddc::DiscreteVector; +using DDomZYX = ddc::StridedDiscreteDomain; + +DElemX constexpr lbound_x(50); +DVectX constexpr nelems_x(3); +DVectX constexpr strides_x(10); +DElemX constexpr sentinel_x(lbound_x + nelems_x * strides_x); +DElemX constexpr ubound_x(sentinel_x - strides_x); + + +DElemY constexpr lbound_y(4); +DVectY constexpr nelems_y(12); +DVectY constexpr strides_y(10); +DElemY constexpr sentinel_y(lbound_y + nelems_y * strides_y); +DElemY constexpr ubound_y(sentinel_y - strides_y); + +DElemZ constexpr lbound_z(7); +DVectZ constexpr nelems_z(15); +DVectZ constexpr strides_z(3); + +DElemXY constexpr lbound_x_y(lbound_x, lbound_y); +DVectXY constexpr nelems_x_y(nelems_x, nelems_y); +DVectXY constexpr strides_x_y(strides_x, strides_y); +DElemXY constexpr ubound_x_y(ubound_x, ubound_y); + +DElemXZ constexpr lbound_x_z(lbound_x, lbound_z); +DVectXZ constexpr nelems_x_z(nelems_x, nelems_z); + +} // namespace DDC_HIP_5_7_ANONYMOUS_NAMESPACE_WORKAROUND(DISCRETE_DOMAIN_CPP) + +TEST(StridedDiscreteDomainTest, Constructor) +{ + DDomXY const dom_x_y(lbound_x_y, nelems_x_y, strides_x_y); + EXPECT_EQ(dom_x_y.extents(), nelems_x_y); + EXPECT_EQ(dom_x_y.front(), lbound_x_y); + EXPECT_EQ(dom_x_y.back(), ubound_x_y); + EXPECT_EQ(dom_x_y.size(), nelems_x.value() * nelems_y.value()); + + DDomX const dom_x(lbound_x, nelems_x, strides_x); + EXPECT_EQ(dom_x.size(), nelems_x); + EXPECT_EQ(dom_x.empty(), false); + EXPECT_EQ(dom_x[0], lbound_x); + EXPECT_EQ(dom_x.front(), lbound_x); + EXPECT_EQ(dom_x.back(), ubound_x); + + DDomX const empty_domain(lbound_x, DVectX(0), DVectX(0)); + EXPECT_EQ(empty_domain.size(), 0); + EXPECT_EQ(empty_domain.empty(), true); + EXPECT_EQ(empty_domain[0], lbound_x); +} + +TEST(StridedDiscreteDomainTest, ConstructorFromStridedDiscreteDomains) +{ + DDomXY const dom_x_y(lbound_x_y, nelems_x_y, strides_x_y); + DDomZ const dom_z(lbound_z, nelems_z, strides_z); + DDomXYZ const dom_x_y_z(dom_z, dom_x_y); + EXPECT_EQ(dom_x_y_z.front(), DElemXYZ(lbound_x, lbound_y, lbound_z)); + EXPECT_EQ(dom_x_y_z.extents(), DVectXYZ(nelems_x, nelems_y, nelems_z)); +} + +TEST(StridedDiscreteDomainTest, EmptyDomain) +{ + DDomXY const dom_x_y = DDomXY(); + EXPECT_EQ(dom_x_y.extents(), DVectXY(0, 0)); + EXPECT_EQ(dom_x_y.size(), 0); + EXPECT_TRUE(dom_x_y.empty()); +} + +TEST(StridedDiscreteDomainTest, CompareSameDomains) +{ + DDomXY const dom_x_y_1(lbound_x_y, nelems_x_y, strides_x_y); + DDomXY const dom_x_y_2(dom_x_y_1); + EXPECT_TRUE(dom_x_y_1 == dom_x_y_2); + EXPECT_TRUE(dom_x_y_1 == DDomYX(dom_x_y_2)); + EXPECT_FALSE(dom_x_y_1 != dom_x_y_2); + EXPECT_FALSE(dom_x_y_1 != DDomYX(dom_x_y_2)); +} + +TEST(StridedDiscreteDomainTest, CompareDifferentDomains) +{ + DDomXY const dom_x_y_1(DElemXY(0, 1), DVectXY(1, 2), strides_x_y); + DDomXY const dom_x_y_2(DElemXY(2, 3), DVectXY(3, 4), strides_x_y); + EXPECT_FALSE(dom_x_y_1 == dom_x_y_2); + EXPECT_FALSE(dom_x_y_1 == DDomYX(dom_x_y_2)); + EXPECT_TRUE(dom_x_y_1 != dom_x_y_2); + EXPECT_TRUE(dom_x_y_1 != DDomYX(dom_x_y_2)); +} + +TEST(StridedDiscreteDomainTest, CompareEmptyDomains) +{ + DDomXY const dom_x_y_1(DElemXY(4, 1), DVectXY(0, 0), strides_x_y); + DDomXY const dom_x_y_2(DElemXY(3, 9), DVectXY(0, 0), strides_x_y); + EXPECT_TRUE(dom_x_y_1.empty()); + EXPECT_TRUE(dom_x_y_2.empty()); + EXPECT_TRUE(dom_x_y_1 == dom_x_y_2); + EXPECT_FALSE(dom_x_y_1 != dom_x_y_2); +} + +// TEST(StridedDiscreteDomainTest, Subdomain) +// { +// DDomXY const dom_x_y(lbound_x_y, nelems_x_y); +// ddc::DiscreteElement const lbound_subdomain_x(lbound_x + 1); +// ddc::DiscreteVector const npoints_subdomain_x(nelems_x - 2); +// DDomX const subdomain_x(lbound_subdomain_x, npoints_subdomain_x); +// DDomXY const subdomain = dom_x_y.restrict_with(subdomain_x); +// EXPECT_EQ( +// subdomain, +// DDomXY(ddc::DiscreteElement(lbound_subdomain_x, lbound_y), +// ddc::DiscreteVector(npoints_subdomain_x, nelems_y))); +// } + +TEST(StridedDiscreteDomainTest, RangeFor) +{ + DDomX const dom(lbound_x, nelems_x, strides_x); + DElemX ii = lbound_x; + for (DElemX const ix : dom) { + EXPECT_LE(lbound_x, ix); + EXPECT_EQ(ix, ii); + EXPECT_LE(ix, ubound_x); + ii.uid() += strides_x.value(); + } +} + +// TEST(StridedDiscreteDomainTest, DiffEmpty) +// { +// DDomX const dom_x = DDomX(); +// ddc::remove_dims_of_t const subdomain1 = ddc::remove_dims_of(dom_x, dom_x); +// ddc::remove_dims_of_t const subdomain2 = ddc::remove_dims_of(dom_x); +// EXPECT_EQ(subdomain1, ddc::DiscreteDomain<>()); +// EXPECT_EQ(subdomain2, ddc::DiscreteDomain<>()); +// } + +// TEST(StridedDiscreteDomainTest, Diff) +// { +// DDomX const dom_x = DDomX(); +// DDomXY const dom_x_y = DDomXY(); +// DDomZY const dom_z_y = DDomZY(); +// ddc::remove_dims_of_t const subdomain1 +// = ddc::remove_dims_of(dom_x_y, dom_z_y); +// ddc::remove_dims_of_t const subdomain2 +// = ddc::remove_dims_of(dom_x_y); +// EXPECT_EQ(subdomain1, dom_x); +// EXPECT_EQ(subdomain2, dom_x); +// } + +// TEST(StridedDiscreteDomainTest, Replace) +// { +// DDomXY const dom_x_y(lbound_x_y, nelems_x_y); +// DDomZ const dom_z(lbound_z, nelems_z); +// DDomXZ const dom_x_z(lbound_x_z, nelems_x_z); +// ddc::replace_dim_of_t const subdomain +// = ddc::replace_dim_of(dom_x_y, dom_z); +// EXPECT_EQ(subdomain, dom_x_z); +// } + + +TEST(StridedDiscreteDomainTest, TakeFirst) +{ + DDomXY const dom_x_y(lbound_x_y, nelems_x_y, strides_x_y); + EXPECT_EQ( + dom_x_y.take_first(DVectXY(1, 4)), + DDomXY(dom_x_y.front(), DVectXY(1, 4), strides_x_y)); +} + +TEST(StridedDiscreteDomainTest, TakeLast) +{ + DDomXY const dom_x_y(lbound_x_y, nelems_x_y, strides_x_y); + EXPECT_EQ( + dom_x_y.take_last(DVectXY(1, 4)), + DDomXY(dom_x_y.front() + ddc::prod(dom_x_y.extents() - DVectXY(1, 4), strides_x_y), + DVectXY(1, 4), + strides_x_y)); +} + +TEST(StridedDiscreteDomainTest, RemoveFirst) +{ + DDomXY const dom_x_y(lbound_x_y, nelems_x_y, strides_x_y); + EXPECT_EQ( + dom_x_y.remove_first(DVectXY(1, 4)), + DDomXY(dom_x_y.front() + ddc::prod(DVectXY(1, 4), strides_x_y), + dom_x_y.extents() - DVectXY(1, 4), + strides_x_y)); +} + +TEST(StridedDiscreteDomainTest, RemoveLast) +{ + DDomXY const dom_x_y(lbound_x_y, nelems_x_y, strides_x_y); + EXPECT_EQ( + dom_x_y.remove_last(DVectXY(1, 4)), + DDomXY(dom_x_y.front(), dom_x_y.extents() - DVectXY(1, 4), strides_x_y)); +} + +TEST(StridedDiscreteDomainTest, Remove) +{ + DDomXY const dom_x_y(lbound_x_y, nelems_x_y, strides_x_y); + EXPECT_EQ( + dom_x_y.remove(DVectXY(1, 4), DVectXY(1, 1)), + DDomXY(dom_x_y.front() + prod(DVectXY(1, 4), strides_x_y), + dom_x_y.extents() - DVectXY(2, 5), + strides_x_y)); +} + +TEST(StridedDiscreteDomainTest, IsInside) +{ + DDomXY const dom_x_y(lbound_x_y, nelems_x_y, strides_x_y); + EXPECT_TRUE(dom_x_y.is_inside(lbound_x_y)); + EXPECT_FALSE(dom_x_y.is_inside(lbound_x_y + DVectXY(1, 1))); +} + +TEST(StridedDiscreteDomainTest, DistanceFromFront) +{ + DDomXY const dom_x_y(lbound_x_y, nelems_x_y, strides_x_y); + EXPECT_EQ(dom_x_y.distance_from_front(lbound_x_y), DVectXY(0, 0)); +} + +// TEST(StridedDiscreteDomainTest, SliceDomainXTooearly) +// { +// #ifndef NDEBUG // The assertion is only checked if NDEBUG isn't defined +// DDomX const subdomain_x(lbound_x - 1, nelems_x); +// DDomXY const dom_x_y(lbound_x_y, nelems_x_y); +// // the error message is checked with clang & gcc only +// EXPECT_DEATH( +// dom_x_y.restrict_with(subdomain_x), +// R"rgx([Aa]ssert.*uid\(m_element_begin\).*uid\(odomain\.m_element_begin\))rgx"); +// #else +// GTEST_SKIP(); +// #endif +// } + +// TEST(StridedDiscreteDomainTest, SliceDomainXToolate) +// { +// #ifndef NDEBUG // The assertion is only checked if NDEBUG isn't defined +// DDomX const subdomain_x(lbound_x, nelems_x + 1); +// DDomXY const dom_x_y(lbound_x_y, nelems_x_y); +// // the error message is checked with clang & gcc only +// EXPECT_DEATH( +// dom_x_y.restrict_with(subdomain_x), +// R"rgx([Aa]ssert.*uid\(m_element_end\).*uid\(odomain\.m_element_end\).*)rgx"); +// #else +// GTEST_SKIP(); +// #endif +// } + +TEST(StridedDiscreteDomainTest, Transpose3DConstructor) +{ + DDomX const dom_x(lbound_x, nelems_x, strides_x); + DDomY const dom_y(lbound_y, nelems_y, strides_y); + DDomZ const dom_z(lbound_z, nelems_z, strides_z); + DDomXYZ const dom_x_y_z(dom_x, dom_y, dom_z); + DDomZYX const dom_z_y_x(dom_x_y_z); + EXPECT_EQ(ddc::select(dom_x_y_z.front()), ddc::select(dom_z_y_x.front())); + EXPECT_EQ(ddc::select(dom_x_y_z.front()), ddc::select(dom_z_y_x.front())); + EXPECT_EQ(ddc::select(dom_x_y_z.front()), ddc::select(dom_z_y_x.front())); + EXPECT_EQ(ddc::select(dom_x_y_z.back()), ddc::select(dom_z_y_x.back())); + EXPECT_EQ(ddc::select(dom_x_y_z.back()), ddc::select(dom_z_y_x.back())); + EXPECT_EQ(ddc::select(dom_x_y_z.back()), ddc::select(dom_z_y_x.back())); +} + +// TEST(StridedDiscreteDomainTest, CartesianProduct) +// { +// EXPECT_TRUE((std::is_same_v, ddc::DiscreteDomain<>>)); +// EXPECT_TRUE((std::is_same_v, DDomX>)); +// EXPECT_TRUE((std::is_same_v, DDomXYZ>)); +// EXPECT_TRUE((std::is_same_v, DDomZYX>)); +// } From 78a3fa26705de84bc612701b9beca1e8a9ef3fb1 Mon Sep 17 00:00:00 2001 From: Thomas Padioleau Date: Mon, 9 Dec 2024 11:30:10 +0100 Subject: [PATCH 05/12] Add support for generalized domains in parallel_for_each and transform_reduce --- .../ddc/ddc_to_kokkos_execution_policy.hpp | 35 ++++++------ include/ddc/discrete_domain.hpp | 6 ++ include/ddc/parallel_for_each.hpp | 55 +++++++++++-------- include/ddc/parallel_transform_reduce.hpp | 50 ++++++++++------- include/ddc/strided_discrete_domain.hpp | 39 ++++++++----- tests/parallel_for_each.cpp | 22 ++++++++ tests/strided_discrete_domain.cpp | 12 ++-- 7 files changed, 136 insertions(+), 83 deletions(-) diff --git a/include/ddc/ddc_to_kokkos_execution_policy.hpp b/include/ddc/ddc_to_kokkos_execution_policy.hpp index 79dcef997..dff21c0d2 100644 --- a/include/ddc/ddc_to_kokkos_execution_policy.hpp +++ b/include/ddc/ddc_to_kokkos_execution_policy.hpp @@ -15,34 +15,33 @@ namespace ddc::detail { -template -auto ddc_to_kokkos_execution_policy( - ExecSpace const& execution_space, - DiscreteDomain const& domain) +template +auto ddc_to_kokkos_execution_policy(ExecSpace const& execution_space, Support const& domain) { using work_tag = void; using index_type = Kokkos::IndexType; - if constexpr (sizeof...(DDims) == 0) { + if constexpr (Support::rank() == 0) { return Kokkos::RangePolicy(execution_space, 0, 1); } else { - DiscreteElement const ddc_begin = domain.front(); - DiscreteElement const ddc_end = domain.front() + domain.extents(); - if constexpr (sizeof...(DDims) == 1) { - std::size_t const begin = ddc_begin.uid(); - std::size_t const end = ddc_end.uid(); - return Kokkos:: - RangePolicy(execution_space, begin, end); + if constexpr (Support::rank() == 1) { + return Kokkos::RangePolicy< + ExecSpace, + work_tag, + index_type>(execution_space, 0, domain.extents().value()); } else { - using iteration_pattern = Kokkos:: - Rank; - Kokkos::Array const begin { - ddc::uid(ddc_begin)...}; - Kokkos::Array const end {ddc::uid(ddc_end)...}; + using iteration_pattern + = Kokkos::Rank; + Kokkos::Array const begin {}; + std::array const end = detail::array(domain.extents()); + Kokkos::Array end2; + for (int i = 0; i < Support::rank(); ++i) { + end2[i] = end[i]; + } return Kokkos::MDRangePolicy< ExecSpace, iteration_pattern, work_tag, - index_type>(execution_space, begin, end); + index_type>(execution_space, begin, end2); } } } diff --git a/include/ddc/discrete_domain.hpp b/include/ddc/discrete_domain.hpp index f87fa0ba8..ad480ed63 100644 --- a/include/ddc/discrete_domain.hpp +++ b/include/ddc/discrete_domain.hpp @@ -174,6 +174,12 @@ class DiscreteDomain return DiscreteDomain(front() + n1, extents() - n1 - n2); } + KOKKOS_FUNCTION constexpr DiscreteElement operator()( + DiscreteVector const& dvect) const noexcept + { + return m_element_begin + dvect; + } + template KOKKOS_FUNCTION constexpr auto restrict_with(DiscreteDomain const& odomain) const { diff --git a/include/ddc/parallel_for_each.hpp b/include/ddc/parallel_for_each.hpp index ed68acca5..c642c5166 100644 --- a/include/ddc/parallel_for_each.hpp +++ b/include/ddc/parallel_for_each.hpp @@ -20,41 +20,53 @@ namespace ddc { namespace detail { -template -class ForEachKokkosLambdaAdapter +template +class ForEachKokkosLambdaAdapter; + +template +class ForEachKokkosLambdaAdapter> { - template + template using index_type = DiscreteElementType; F m_f; + Support m_support; + public: - explicit ForEachKokkosLambdaAdapter(F const& f) : m_f(f) {} + explicit ForEachKokkosLambdaAdapter(F const& f, Support const& support) + : m_f(f) + , m_support(support) + { + } - template = true> - KOKKOS_FUNCTION void operator()([[maybe_unused]] index_type unused_id) const + template = true> + KOKKOS_FUNCTION void operator()([[maybe_unused]] index_type<0> unused_id) const { m_f(DiscreteElement<>()); } - template 0), bool> = true> - KOKKOS_FUNCTION void operator()(index_type... ids) const + template 0), bool> = true> + KOKKOS_FUNCTION void operator()(index_type... ids) const { - m_f(DiscreteElement(ids...)); + m_f(m_support(typename Support::discrete_vector_type(ids...))); } }; -template +template void for_each_kokkos( std::string const& label, ExecSpace const& execution_space, - DiscreteDomain const& domain, + Support const& domain, Functor const& f) noexcept { Kokkos::parallel_for( label, ddc_to_kokkos_execution_policy(execution_space, domain), - ForEachKokkosLambdaAdapter(f)); + ForEachKokkosLambdaAdapter< + Functor, + Support, + std::make_index_sequence>(f, domain)); } } // namespace detail @@ -65,11 +77,11 @@ void for_each_kokkos( * @param[in] domain the domain over which to iterate * @param[in] f a functor taking an index as parameter */ -template +template void parallel_for_each( std::string const& label, ExecSpace const& execution_space, - DiscreteDomain const& domain, + Support const& domain, Functor&& f) noexcept { detail::for_each_kokkos(label, execution_space, domain, std::forward(f)); @@ -80,10 +92,10 @@ void parallel_for_each( * @param[in] domain the domain over which to iterate * @param[in] f a functor taking an index as parameter */ -template +template std::enable_if_t> parallel_for_each( ExecSpace const& execution_space, - DiscreteDomain const& domain, + Support const& domain, Functor&& f) noexcept { detail::for_each_kokkos( @@ -98,11 +110,8 @@ std::enable_if_t> parallel_for_each( * @param[in] domain the domain over which to iterate * @param[in] f a functor taking an index as parameter */ -template -void parallel_for_each( - std::string const& label, - DiscreteDomain const& domain, - Functor&& f) noexcept +template +void parallel_for_each(std::string const& label, Support const& domain, Functor&& f) noexcept { parallel_for_each(label, Kokkos::DefaultExecutionSpace(), domain, std::forward(f)); } @@ -111,8 +120,8 @@ void parallel_for_each( * @param[in] domain the domain over which to iterate * @param[in] f a functor taking an index as parameter */ -template -void parallel_for_each(DiscreteDomain const& domain, Functor&& f) noexcept +template +void parallel_for_each(Support const& domain, Functor&& f) noexcept { parallel_for_each( "ddc_for_each_default", diff --git a/include/ddc/parallel_transform_reduce.hpp b/include/ddc/parallel_transform_reduce.hpp index 87c4b0744..305630333 100644 --- a/include/ddc/parallel_transform_reduce.hpp +++ b/include/ddc/parallel_transform_reduce.hpp @@ -88,34 +88,41 @@ struct ddc_to_kokkos_reducer> template using ddc_to_kokkos_reducer_t = typename ddc_to_kokkos_reducer::type; -template -class TransformReducerKokkosLambdaAdapter +template +class TransformReducerKokkosLambdaAdapter; + +template +class TransformReducerKokkosLambdaAdapter> { - template + template using index_type = DiscreteElementType; Reducer reducer; Functor functor; + Support m_support; + public: - TransformReducerKokkosLambdaAdapter(Reducer const& r, Functor const& f) : reducer(r), functor(f) + TransformReducerKokkosLambdaAdapter(Reducer const& r, Functor const& f, Support const& support) + : reducer(r) + , functor(f) + , m_support(support) { } - template = true> + template = true> KOKKOS_FUNCTION void operator()( - [[maybe_unused]] index_type unused_id, + [[maybe_unused]] index_type<0> unused_id, typename Reducer::value_type& a) const - { a = reducer(a, functor(DiscreteElement<>())); } - template 0), bool> = true> - KOKKOS_FUNCTION void operator()(index_type... ids, typename Reducer::value_type& a) const + template 0), bool> = true> + KOKKOS_FUNCTION void operator()(index_type... ids, typename Reducer::value_type& a) const { - a = reducer(a, functor(DiscreteElement(ids...))); + a = reducer(a, functor(m_support(typename Support::discrete_vector_type(ids...)))); } }; @@ -129,11 +136,11 @@ class TransformReducerKokkosLambdaAdapter * @param[in] transform a unary FunctionObject that will be applied to each element of the input * range. The return type must be acceptable as input to reduce */ -template +template T transform_reduce_kokkos( std::string const& label, ExecSpace const& execution_space, - DiscreteDomain const& domain, + Support const& domain, T neutral, BinaryReductionOp const& reduce, UnaryTransformOp const& transform) noexcept @@ -145,7 +152,8 @@ T transform_reduce_kokkos( TransformReducerKokkosLambdaAdapter< BinaryReductionOp, UnaryTransformOp, - DDims...>(reduce, transform), + Support, + std::make_index_sequence>(reduce, transform, domain), ddc_to_kokkos_reducer_t(result)); return result; } @@ -162,11 +170,11 @@ T transform_reduce_kokkos( * @param[in] transform a unary FunctionObject that will be applied to each element of the input * range. The return type must be acceptable as input to reduce */ -template +template T parallel_transform_reduce( std::string const& label, ExecSpace const& execution_space, - DiscreteDomain const& domain, + Support const& domain, T neutral, BinaryReductionOp&& reduce, UnaryTransformOp&& transform) noexcept @@ -189,10 +197,10 @@ T parallel_transform_reduce( * @param[in] transform a unary FunctionObject that will be applied to each element of the input * range. The return type must be acceptable as input to reduce */ -template +template std::enable_if_t, T> parallel_transform_reduce( ExecSpace const& execution_space, - DiscreteDomain const& domain, + Support const& domain, T neutral, BinaryReductionOp&& reduce, UnaryTransformOp&& transform) noexcept @@ -215,10 +223,10 @@ std::enable_if_t, T> parallel_transform_ * @param[in] transform a unary FunctionObject that will be applied to each element of the input * range. The return type must be acceptable as input to reduce */ -template +template T parallel_transform_reduce( std::string const& label, - DiscreteDomain const& domain, + Support const& domain, T neutral, BinaryReductionOp&& reduce, UnaryTransformOp&& transform) noexcept @@ -240,9 +248,9 @@ T parallel_transform_reduce( * @param[in] transform a unary FunctionObject that will be applied to each element of the input * range. The return type must be acceptable as input to reduce */ -template +template T parallel_transform_reduce( - DiscreteDomain const& domain, + Support const& domain, T neutral, BinaryReductionOp&& reduce, UnaryTransformOp&& transform) noexcept diff --git a/include/ddc/strided_discrete_domain.hpp b/include/ddc/strided_discrete_domain.hpp index 12b84eebb..7df7f8a57 100644 --- a/include/ddc/strided_discrete_domain.hpp +++ b/include/ddc/strided_discrete_domain.hpp @@ -197,6 +197,12 @@ class StridedDiscreteDomain return StridedDiscreteDomain(front() + prod(n1, m_strides), extents() - n1 - n2, m_strides); } + KOKKOS_FUNCTION constexpr DiscreteElement operator()( + DiscreteVector const& dvect) const noexcept + { + return m_element_begin + prod(dvect, m_strides); + } + // template // KOKKOS_FUNCTION constexpr auto restrict_with( // StridedDiscreteDomain const& odomain) const @@ -219,16 +225,18 @@ class StridedDiscreteDomain "Invalid number of dimensions"); static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); auto const test1 - = ((select(take(delems...)) >= select(m_element_begin)) + = ((DiscreteElement(take(delems...)) + >= DiscreteElement(m_element_begin)) && ...); auto const test2 - = ((select(take(delems...)) - < (select(m_element_begin) - + select(m_extents) * select(m_strides))) + = ((DiscreteElement(take(delems...)) + < (DiscreteElement(m_element_begin) + + DiscreteVector(m_extents) * DiscreteVector(m_strides))) && ...); auto const test3 - = ((((select(take(delems...)) - select(m_element_begin)) - % select(m_strides)) + = ((((DiscreteElement(take(delems...)) + - DiscreteElement(m_element_begin)) + % DiscreteVector(m_strides)) == 0) && ...); return test1 && test2 && test3; @@ -243,8 +251,9 @@ class StridedDiscreteDomain static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); assert(is_inside(delems...)); return DiscreteVector( - ((select(take(delems...)) - select(m_element_begin)) - / select(m_strides))...); + ((DiscreteElement(take(delems...)) + - DiscreteElement(m_element_begin)) + / DiscreteVector(m_strides))...); } KOKKOS_FUNCTION constexpr bool empty() const noexcept @@ -474,8 +483,8 @@ KOKKOS_FUNCTION constexpr StridedDiscreteDomain select( StridedDiscreteDomain const& domain) { return StridedDiscreteDomain( - select(domain.front()), - select(domain.extents())); + DiscreteElement(domain.front()), + DiscreteElement(domain.extents())); } namespace detail { @@ -521,7 +530,7 @@ replace_dim_of_1d( [[maybe_unused]] StridedDiscreteDomain const& DDom_b) noexcept { if constexpr (std::is_same_v) { - return ddc::select(DDom_b); + return ddc::StridedDiscreteDomain(DDom_b); } else { return DDom_a; } @@ -546,28 +555,28 @@ KOKKOS_FUNCTION constexpr auto replace_dim_of( DDim1, DDim2, DDimsA, - DDimsB...>(ddc::select(DDom_a), DDom_b)...); + DDimsB...>(ddc::StridedDiscreteDomain(DDom_a), DDom_b)...); } template KOKKOS_FUNCTION constexpr DiscreteVector extents( StridedDiscreteDomain const& domain) noexcept { - return DiscreteVector(select(domain).size()...); + return DiscreteVector(StridedDiscreteDomain(domain).size()...); } template KOKKOS_FUNCTION constexpr DiscreteElement front( StridedDiscreteDomain const& domain) noexcept { - return DiscreteElement(select(domain).front()...); + return DiscreteElement(StridedDiscreteDomain(domain).front()...); } template KOKKOS_FUNCTION constexpr DiscreteElement back( StridedDiscreteDomain const& domain) noexcept { - return DiscreteElement(select(domain).back()...); + return DiscreteElement(StridedDiscreteDomain(domain).back()...); } template diff --git a/tests/parallel_for_each.cpp b/tests/parallel_for_each.cpp index fb5005dff..3e1163976 100644 --- a/tests/parallel_for_each.cpp +++ b/tests/parallel_for_each.cpp @@ -154,3 +154,25 @@ TEST(ParallelForEachParallelDevice, TwoDimensions) { TestParallelForEachParallelDeviceTwoDimensions(); } + +void TestParallelForEachParallelDeviceTwoDimensionsStrided() +{ + using DDomXY = ddc::StridedDiscreteDomain; + DDomXY const dom(lbound_x_y, nelems_x_y, DVectXY(3, 3)); + ddc::Chunk> storage(dom); + Kokkos::deep_copy(storage.allocation_kokkos_view(), 0); + ddc::ChunkSpan const view(storage.span_view()); + ddc::parallel_for_each(dom, KOKKOS_LAMBDA(DElemXY const ixy) { view(ixy) += 1; }); + int const* const ptr = storage.data_handle(); + int sum; + Kokkos::parallel_reduce( + dom.size(), + KOKKOS_LAMBDA(std::size_t i, int& local_sum) { local_sum += ptr[i]; }, + Kokkos::Sum(sum)); + EXPECT_EQ(sum, dom.size()); +} + +TEST(ParallelForEachParallelDevice, TwoDimensionsStrided) +{ + TestParallelForEachParallelDeviceTwoDimensionsStrided(); +} diff --git a/tests/strided_discrete_domain.cpp b/tests/strided_discrete_domain.cpp index c84eea2de..a44904fe9 100644 --- a/tests/strided_discrete_domain.cpp +++ b/tests/strided_discrete_domain.cpp @@ -305,12 +305,12 @@ TEST(StridedDiscreteDomainTest, Transpose3DConstructor) DDomZ const dom_z(lbound_z, nelems_z, strides_z); DDomXYZ const dom_x_y_z(dom_x, dom_y, dom_z); DDomZYX const dom_z_y_x(dom_x_y_z); - EXPECT_EQ(ddc::select(dom_x_y_z.front()), ddc::select(dom_z_y_x.front())); - EXPECT_EQ(ddc::select(dom_x_y_z.front()), ddc::select(dom_z_y_x.front())); - EXPECT_EQ(ddc::select(dom_x_y_z.front()), ddc::select(dom_z_y_x.front())); - EXPECT_EQ(ddc::select(dom_x_y_z.back()), ddc::select(dom_z_y_x.back())); - EXPECT_EQ(ddc::select(dom_x_y_z.back()), ddc::select(dom_z_y_x.back())); - EXPECT_EQ(ddc::select(dom_x_y_z.back()), ddc::select(dom_z_y_x.back())); + EXPECT_EQ(DElemX(dom_x_y_z.front()), DElemX(dom_z_y_x.front())); + EXPECT_EQ(DElemY(dom_x_y_z.front()), DElemY(dom_z_y_x.front())); + EXPECT_EQ(DElemZ(dom_x_y_z.front()), DElemZ(dom_z_y_x.front())); + EXPECT_EQ(DElemX(dom_x_y_z.back()), DElemX(dom_z_y_x.back())); + EXPECT_EQ(DElemY(dom_x_y_z.back()), DElemY(dom_z_y_x.back())); + EXPECT_EQ(DElemZ(dom_x_y_z.back()), DElemZ(dom_z_y_x.back())); } // TEST(StridedDiscreteDomainTest, CartesianProduct) From dcd33574b5ee18d3b6273589eee4222d3c253ca2 Mon Sep 17 00:00:00 2001 From: Thomas Padioleau Date: Mon, 9 Dec 2024 11:59:14 +0100 Subject: [PATCH 06/12] Add support for generalized domains in for_each and transform_reduce --- include/ddc/chunk_common.hpp | 3 +-- include/ddc/discrete_domain.hpp | 6 ++++++ include/ddc/for_each.hpp | 23 ++++++++++------------- include/ddc/strided_discrete_domain.hpp | 6 ++++++ include/ddc/transform_reduce.hpp | 20 ++++++++------------ 5 files changed, 31 insertions(+), 27 deletions(-) diff --git a/include/ddc/chunk_common.hpp b/include/ddc/chunk_common.hpp index dea70dcc8..74bb91d98 100644 --- a/include/ddc/chunk_common.hpp +++ b/include/ddc/chunk_common.hpp @@ -173,8 +173,7 @@ class ChunkCommon template KOKKOS_FUNCTION constexpr size_type stride() const { - return m_allocation_mdspan.stride( - type_seq_rank_v>); + return m_allocation_mdspan.stride(type_seq_rank_v>); } /** Provide access to the domain on which this chunk is defined diff --git a/include/ddc/discrete_domain.hpp b/include/ddc/discrete_domain.hpp index ad480ed63..904d92620 100644 --- a/include/ddc/discrete_domain.hpp +++ b/include/ddc/discrete_domain.hpp @@ -387,6 +387,12 @@ class DiscreteDomain<> return *this; } + KOKKOS_FUNCTION constexpr DiscreteElement<> operator()( + DiscreteVector<> const& /* dvect */) const noexcept + { + return DiscreteElement<>(); + } + template KOKKOS_FUNCTION constexpr DiscreteDomain restrict_with( DiscreteDomain const& /* odomain */) const diff --git a/include/ddc/for_each.hpp b/include/ddc/for_each.hpp index 4856a3888..6b71f767c 100644 --- a/include/ddc/for_each.hpp +++ b/include/ddc/for_each.hpp @@ -16,19 +16,19 @@ namespace ddc { namespace detail { -template +template void for_each_serial( - std::array const& begin, - std::array const& end, + Support const& support, + std::array const& size, Functor const& f, Is const&... is) noexcept { static constexpr std::size_t I = sizeof...(Is); if constexpr (I == N) { - f(RetType(is...)); + f(support(typename Support::discrete_vector_type(is...))); } else { - for (Element ii = begin[I]; ii < end[I]; ++ii) { - for_each_serial(begin, end, f, is..., ii); + for (Element ii = 0; ii < size[I]; ++ii) { + for_each_serial(support, size, f, is..., ii); } } } @@ -39,14 +39,11 @@ void for_each_serial( * @param[in] domain the domain over which to iterate * @param[in] f a functor taking an index as parameter */ -template -void for_each(DiscreteDomain const& domain, Functor&& f) noexcept +template +void for_each(Support const& domain, Functor&& f) noexcept { - DiscreteElement const ddc_begin = domain.front(); - DiscreteElement const ddc_end = domain.front() + domain.extents(); - std::array const begin = detail::array(ddc_begin); - std::array const end = detail::array(ddc_end); - detail::for_each_serial>(begin, end, std::forward(f)); + std::array const size = detail::array(domain.extents()); + detail::for_each_serial(domain, size, std::forward(f)); } } // namespace ddc diff --git a/include/ddc/strided_discrete_domain.hpp b/include/ddc/strided_discrete_domain.hpp index 7df7f8a57..bcc92f622 100644 --- a/include/ddc/strided_discrete_domain.hpp +++ b/include/ddc/strided_discrete_domain.hpp @@ -428,6 +428,12 @@ class StridedDiscreteDomain<> return *this; } + KOKKOS_FUNCTION constexpr DiscreteElement<> operator()( + DiscreteVector<> const& dvect) const noexcept + { + return DiscreteElement<>(); + } + #if defined(DDC_BUILD_DEPRECATED_CODE) template [[deprecated( diff --git a/include/ddc/transform_reduce.hpp b/include/ddc/transform_reduce.hpp index ac0747cf9..6febb3d54 100644 --- a/include/ddc/transform_reduce.hpp +++ b/include/ddc/transform_reduce.hpp @@ -9,6 +9,7 @@ #include "ddc/detail/macros.hpp" #include "ddc/discrete_domain.hpp" #include "ddc/discrete_element.hpp" +#include "ddc/strided_discrete_domain.hpp" namespace ddc { @@ -23,24 +24,19 @@ namespace detail { * range. The return type must be acceptable as input to reduce * @param[in] dcoords discrete elements from dimensions already in a loop */ -template < - class... DDims, - class T, - class BinaryReductionOp, - class UnaryTransformOp, - class... DCoords> +template T transform_reduce_serial( - DiscreteDomain const& domain, + Support const& domain, [[maybe_unused]] T const neutral, BinaryReductionOp const& reduce, UnaryTransformOp const& transform, DCoords const&... dcoords) noexcept { DDC_IF_NVCC_THEN_PUSH_AND_SUPPRESS(implicit_return_from_non_void_function) - if constexpr (sizeof...(DCoords) == sizeof...(DDims)) { - return transform(DiscreteElement(dcoords...)); + if constexpr (sizeof...(DCoords) == Support::rank()) { + return transform(typename Support::discrete_element_type(dcoords...)); } else { - using CurrentDDim = type_seq_element_t>; + using CurrentDDim = type_seq_element_t>; T result = neutral; for (DiscreteElement const ii : DiscreteDomain(domain)) { result = reduce( @@ -62,9 +58,9 @@ T transform_reduce_serial( * @param[in] transform a unary FunctionObject that will be applied to each element of the input * range. The return type must be acceptable as input to reduce */ -template +template T transform_reduce( - DiscreteDomain const& domain, + Support const& domain, T neutral, BinaryReductionOp&& reduce, UnaryTransformOp&& transform) noexcept From 99097aeedc564230520d52b249eccf379c1c1869 Mon Sep 17 00:00:00 2001 From: Thomas Padioleau Date: Fri, 13 Dec 2024 19:29:07 +0100 Subject: [PATCH 07/12] Add StorageDiscreteDomain class --- include/ddc/chunk_common.hpp | 2 +- include/ddc/ddc.hpp | 1 + include/ddc/storage_discrete_domain.hpp | 784 ++++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/storage_discrete_domain.cpp | 101 +++ 5 files changed, 888 insertions(+), 1 deletion(-) create mode 100644 include/ddc/storage_discrete_domain.hpp create mode 100644 tests/storage_discrete_domain.cpp diff --git a/include/ddc/chunk_common.hpp b/include/ddc/chunk_common.hpp index 74bb91d98..b4f1abb5e 100644 --- a/include/ddc/chunk_common.hpp +++ b/include/ddc/chunk_common.hpp @@ -134,7 +134,7 @@ class ChunkCommon return m_allocation_mdspan.accessor(); } - KOKKOS_FUNCTION constexpr SupportType::discrete_vector_type extents() const noexcept + KOKKOS_FUNCTION constexpr typename SupportType::discrete_vector_type extents() const noexcept { return m_domain.extents(); } diff --git a/include/ddc/ddc.hpp b/include/ddc/ddc.hpp index 73ffbbb79..08556d11d 100644 --- a/include/ddc/ddc.hpp +++ b/include/ddc/ddc.hpp @@ -31,6 +31,7 @@ namespace ddc { #include "ddc/discrete_vector.hpp" #include "ddc/non_uniform_point_sampling.hpp" #include "ddc/periodic_sampling.hpp" +#include "ddc/storage_discrete_domain.hpp" #include "ddc/strided_discrete_domain.hpp" #include "ddc/uniform_point_sampling.hpp" diff --git a/include/ddc/storage_discrete_domain.hpp b/include/ddc/storage_discrete_domain.hpp new file mode 100644 index 000000000..b12777853 --- /dev/null +++ b/include/ddc/storage_discrete_domain.hpp @@ -0,0 +1,784 @@ +// Copyright (C) The DDC development team, see COPYRIGHT.md file +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +#include "ddc/detail/kokkos.hpp" +#include "ddc/detail/tagged_vector.hpp" +#include "ddc/detail/type_seq.hpp" +#include "ddc/discrete_element.hpp" +#include "ddc/discrete_vector.hpp" + +namespace ddc { + +template +struct StorageDiscreteDomainIterator; + +template +class StorageDiscreteDomain; + +template +struct is_storage_discrete_domain : std::false_type +{ +}; + +template +struct is_storage_discrete_domain> : std::true_type +{ +}; + +template +inline constexpr bool is_storage_discrete_domain_v = is_storage_discrete_domain::value; + + +namespace detail { + +template +struct ToTypeSeq> +{ + using type = TypeSeq; +}; + +template +KOKKOS_FUNCTION bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2) +{ + for (; first1 != last1; ++first1, ++first2) { + if (!(*first1 == *first2)) { + return false; + } + } + + return true; +} + +template < + class ForwardIt, + class T = typename std::iterator_traits::value_type, + class Compare> +KOKKOS_FUNCTION ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value, Compare comp) +{ + ForwardIt it; + typename std::iterator_traits::difference_type count = last - first; + while (count > 0) { + it = first; + typename std::iterator_traits::difference_type step = count / 2; + it += step; + + if (comp(*it, value)) { + first = ++it; + count -= step + 1; + } else { + count = step; + } + } + + return first; +} + +template < + class ForwardIt, + class T = typename std::iterator_traits::value_type, + class Compare> +bool binary_search(ForwardIt first, ForwardIt last, const T& value, Compare comp) +{ + first = ::ddc::detail::lower_bound(first, last, value, comp); + return (!(first == last) && !(comp(value, *first))); +} + +} // namespace detail + +template +class StorageDiscreteDomain +{ + template + friend class StorageDiscreteDomain; + +public: + using discrete_element_type = DiscreteElement; + + using discrete_vector_type = DiscreteVector; + +private: + detail::TaggedVector, DDims...> m_views; + +public: + static KOKKOS_FUNCTION constexpr std::size_t rank() + { + return sizeof...(DDims); + } + + KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain() = default; + + /// Construct a StorageDiscreteDomain by copies and merge of domains + template < + class... DDoms, + class = std::enable_if_t<(is_storage_discrete_domain_v && ...)>> + KOKKOS_FUNCTION constexpr explicit StorageDiscreteDomain(DDoms const&... domains) + : m_views(domains...) + { + } + + /** Construct a StridedDiscreteDomain starting from element_begin with size points. + * @param element_begin the lower bound in each direction + * @param size the number of points in each direction + */ + KOKKOS_FUNCTION explicit constexpr StorageDiscreteDomain( + Kokkos::View*, Kokkos::SharedSpace> const&... views) + { + ((m_views[type_seq_rank_v>] + = Kokkos::View(views.label(), views.size())), + ...); + ((Kokkos::Experimental::transform( + "StorageDiscreteDomainCtor", + Kokkos::DefaultExecutionSpace(), + views, + m_views[type_seq_rank_v>], + KOKKOS_LAMBDA(DiscreteElement const& delem) { return delem.uid(); })), + ...); + Kokkos::fence("StorageDiscreteDomainCtor"); + } + + KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain(StorageDiscreteDomain const& x) = default; + + KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain(StorageDiscreteDomain&& x) = default; + + KOKKOS_DEFAULTED_FUNCTION ~StorageDiscreteDomain() = default; + + KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain& operator=(StorageDiscreteDomain const& x) + = default; + + KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain& operator=(StorageDiscreteDomain&& x) = default; + + template + KOKKOS_FUNCTION constexpr bool operator==(StorageDiscreteDomain const& other) const + { + if (empty() && other.empty()) { + return true; + } + if (m_views.size() != other.m_views.size()) { + return false; + } + for (std::size_t i = 0; i < m_views.size(); ++i) { + if (m_views[i].size() != other.m_views[i].size()) { + return false; + } + if (!detail:: + equal(m_views[i].data(), + m_views[i].data() + m_views[i].size(), + other.m_views[i].data())) { + return false; + } + } + return true; + } + +#if !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201902L + // In C++20, `a!=b` shall be automatically translated by the compiler to `!(a==b)` + template + KOKKOS_FUNCTION constexpr bool operator!=(StorageDiscreteDomain const& other) const + { + return !(*this == other); + } +#endif + + KOKKOS_FUNCTION constexpr std::size_t size() const + { + return (1UL * ... * get(m_views).size()); + } + + KOKKOS_FUNCTION constexpr discrete_vector_type extents() const noexcept + { + return discrete_vector_type(get(m_views).size()...); + } + + template + KOKKOS_FUNCTION constexpr DiscreteVector extent() const noexcept + { + return DiscreteVector(get(m_views).size()); + } + + KOKKOS_FUNCTION constexpr discrete_element_type front() const noexcept + { + return discrete_element_type(get(m_views)(0)...); + } + + KOKKOS_FUNCTION constexpr discrete_element_type back() const noexcept + { + return discrete_element_type(get(m_views)(get(m_views).size() - 1)...); + } + + KOKKOS_FUNCTION constexpr StorageDiscreteDomain take_first(discrete_vector_type n) const + { + return StorageDiscreteDomain(front(), n); + } + + KOKKOS_FUNCTION constexpr StorageDiscreteDomain take_last(discrete_vector_type n) const + { + return StorageDiscreteDomain(front() + prod(extents() - n), n); + } + + KOKKOS_FUNCTION constexpr StorageDiscreteDomain remove_first(discrete_vector_type n) const + { + return StorageDiscreteDomain(front() + prod(n), extents() - n); + } + + KOKKOS_FUNCTION constexpr StorageDiscreteDomain remove_last(discrete_vector_type n) const + { + return StorageDiscreteDomain(front(), extents() - n); + } + + KOKKOS_FUNCTION constexpr StorageDiscreteDomain remove( + discrete_vector_type n1, + discrete_vector_type n2) const + { + return StorageDiscreteDomain(front() + prod(n1), extents() - n1 - n2); + } + + KOKKOS_FUNCTION constexpr DiscreteElement operator()( + DiscreteVector const& dvect) const noexcept + { + return m_views(get(dvect)...); + } + + // template + // KOKKOS_FUNCTION constexpr auto restrict_with( + // StorageDiscreteDomain const& odomain) const + // { + // assert(((uid(m_element_begin) <= uid(odomain.m_element_begin)) && ...)); + // assert(((uid(m_element_end) >= uid(odomain.m_element_end)) && ...)); + // const DiscreteVector myextents = extents(); + // const DiscreteVector oextents = odomain.extents(); + // return StorageDiscreteDomain( + // DiscreteElement( + // (uid_or(odomain.m_element_begin, uid(m_element_begin)))...), + // DiscreteVector((get_or(oextents, get(myextents)))...)); + // } + + template + KOKKOS_FUNCTION bool is_inside(DElems const&... delems) const noexcept + { + static_assert( + sizeof...(DDims) == (0 + ... + DElems::size()), + "Invalid number of dimensions"); + static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); + return (detail::binary_search( + get(m_views).data(), + get(m_views).data() + get(m_views).size(), + uid(take(delems...)), + std::less {}) + && ...); + } + + template + KOKKOS_FUNCTION DiscreteVector distance_from_front( + DElems const&... delems) const noexcept + { + static_assert( + sizeof...(DDims) == (0 + ... + DElems::size()), + "Invalid number of dimensions"); + static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); + assert(is_inside(delems...)); + return DiscreteVector( + (detail::lower_bound( + get(m_views).data(), + get(m_views).data() + get(m_views).size(), + uid(take(delems...)), + std::less {}) + - get(m_views).data())...); + } + + KOKKOS_FUNCTION constexpr bool empty() const noexcept + { + return size() == 0; + } + + KOKKOS_FUNCTION constexpr explicit operator bool() + { + return !empty(); + } + + // template < + // std::size_t N = sizeof...(DDims), + // class DDim0 = std::enable_if_t>>> + // KOKKOS_FUNCTION auto begin() const + // { + // return StorageDiscreteDomainIterator(front(), m_strides); + // } + + // template < + // std::size_t N = sizeof...(DDims), + // class DDim0 = std::enable_if_t>>> + // KOKKOS_FUNCTION auto end() const + // { + // return StorageDiscreteDomainIterator< + // DDim0>(m_element_begin + m_extents * m_strides, m_strides); + // } + + // template < + // std::size_t N = sizeof...(DDims), + // class DDim0 = std::enable_if_t>>> + // KOKKOS_FUNCTION auto cbegin() const + // { + // return StorageDiscreteDomainIterator(front() s); + // } + + // template < + // std::size_t N = sizeof...(DDims), + // class DDim0 = std::enable_if_t>>> + // KOKKOS_FUNCTION auto cend() const + // { + // return StorageDiscreteDomainIterator(m_element_begin); + // } + + // template < + // std::size_t N = sizeof...(DDims), + // class = std::enable_if_t>>> + // KOKKOS_FUNCTION constexpr decltype(auto) operator[](std::size_t n) + // { + // return begin()[n]; + // } + + // template < + // std::size_t N = sizeof...(DDims), + // class = std::enable_if_t>>> + // KOKKOS_FUNCTION constexpr decltype(auto) operator[](std::size_t n) const + // { + // return begin()[n]; + // } +}; + +// template <> +// class StorageDiscreteDomain<> +// { +// template +// friend class StorageDiscreteDomain; + +// public: +// using discrete_element_type = DiscreteElement<>; + +// using discrete_vector_type = DiscreteVector<>; + +// static KOKKOS_FUNCTION constexpr std::size_t rank() +// { +// return 0; +// } + +// KOKKOS_DEFAULTED_FUNCTION constexpr StorageDiscreteDomain() = default; + +// // Construct a StorageDiscreteDomain from a reordered copy of `domain` +// template +// KOKKOS_FUNCTION constexpr explicit StorageDiscreteDomain( +// [[maybe_unused]] StorageDiscreteDomain const& domain) +// { +// } + +// /** Construct a StorageDiscreteDomain starting from element_begin with size points. +// * @param element_begin the lower bound in each direction +// * @param size the number of points in each direction +// */ +// KOKKOS_FUNCTION constexpr StorageDiscreteDomain( +// [[maybe_unused]] discrete_element_type const& element_begin, +// [[maybe_unused]] discrete_vector_type const& size) +// { +// } + +// KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain(StorageDiscreteDomain const& x) = default; + +// KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain(StorageDiscreteDomain&& x) = default; + +// KOKKOS_DEFAULTED_FUNCTION ~StorageDiscreteDomain() = default; + +// KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain& operator=(StorageDiscreteDomain const& x) +// = default; + +// KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain& operator=(StorageDiscreteDomain&& x) = default; + +// KOKKOS_FUNCTION constexpr bool operator==( +// [[maybe_unused]] StorageDiscreteDomain const& other) const +// { +// return true; +// } + +// #if !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201902L +// // In C++20, `a!=b` shall be automatically translated by the compiler to `!(a==b)` +// KOKKOS_FUNCTION constexpr bool operator!=(StorageDiscreteDomain const& other) const +// { +// return !(*this == other); +// } +// #endif + +// static KOKKOS_FUNCTION constexpr std::size_t size() +// { +// return 1; +// } + +// static KOKKOS_FUNCTION constexpr discrete_vector_type extents() noexcept +// { +// return {}; +// } + +// static KOKKOS_FUNCTION constexpr discrete_element_type front() noexcept +// { +// return {}; +// } + +// static KOKKOS_FUNCTION constexpr discrete_element_type back() noexcept +// { +// return {}; +// } + +// KOKKOS_FUNCTION constexpr StorageDiscreteDomain take_first( +// [[maybe_unused]] discrete_vector_type n) const +// { +// return *this; +// } + +// KOKKOS_FUNCTION constexpr StorageDiscreteDomain take_last( +// [[maybe_unused]] discrete_vector_type n) const +// { +// return *this; +// } + +// KOKKOS_FUNCTION constexpr StorageDiscreteDomain remove_first( +// [[maybe_unused]] discrete_vector_type n) const +// { +// return *this; +// } + +// KOKKOS_FUNCTION constexpr StorageDiscreteDomain remove_last( +// [[maybe_unused]] discrete_vector_type n) const +// { +// return *this; +// } + +// KOKKOS_FUNCTION constexpr StorageDiscreteDomain remove( +// [[maybe_unused]] discrete_vector_type n1, +// [[maybe_unused]] discrete_vector_type n2) const +// { +// return *this; +// } + +// KOKKOS_FUNCTION constexpr DiscreteElement<> operator()( +// DiscreteVector<> const& /* dvect */) const noexcept +// { +// return DiscreteElement<>(); +// } + +// #if defined(DDC_BUILD_DEPRECATED_CODE) +// template +// [[deprecated( +// "Use `restrict_with` " +// "instead")]] KOKKOS_FUNCTION constexpr StorageDiscreteDomain restrict(StorageDiscreteDomain const& +// odomain) +// const +// { +// return restrict_with(odomain); +// } +// #endif + +// template +// KOKKOS_FUNCTION constexpr StorageDiscreteDomain restrict_with( +// StorageDiscreteDomain const& /* odomain */) const +// { +// return *this; +// } + +// static bool is_inside() noexcept +// { +// return true; +// } + +// static bool is_inside(DiscreteElement<>) noexcept +// { +// return true; +// } + +// static DiscreteVector<> distance_from_front() noexcept +// { +// return DiscreteVector<>(); +// } + +// static DiscreteVector<> distance_from_front(DiscreteElement<>) noexcept +// { +// return DiscreteVector<>(); +// } + +// static KOKKOS_FUNCTION constexpr bool empty() noexcept +// { +// return false; +// } + +// KOKKOS_FUNCTION constexpr explicit operator bool() +// { +// return true; +// } +// }; + +template +KOKKOS_FUNCTION constexpr StorageDiscreteDomain select( + StorageDiscreteDomain const& domain) +{ + return StorageDiscreteDomain( + DiscreteElement(domain.front()), + DiscreteElement(domain.extents())); +} + +namespace detail { + +template +struct ConvertTypeSeqToStorageDiscreteDomain; + +template +struct ConvertTypeSeqToStorageDiscreteDomain> +{ + using type = StorageDiscreteDomain; +}; + +template +using convert_type_seq_to_storage_discrete_domain_t = + typename ConvertTypeSeqToStorageDiscreteDomain::type; + +} // namespace detail + +// Computes the substraction DDom_a - DDom_b in the sense of linear spaces(retained dimensions are those in DDom_a which are not in DDom_b) +template +KOKKOS_FUNCTION constexpr auto remove_dims_of( + StorageDiscreteDomain const& DDom_a, + [[maybe_unused]] StorageDiscreteDomain const& DDom_b) noexcept +{ + using TagSeqA = detail::TypeSeq; + using TagSeqB = detail::TypeSeq; + + using type_seq_r = type_seq_remove_t; + return detail::convert_type_seq_to_storage_discrete_domain_t(DDom_a); +} + +namespace detail { + +// Checks if dimension of DDom_a is DDim1. If not, returns restriction to DDim2 of DDom_b. May not be usefull in its own, it helps for replace_dim_of +template +KOKKOS_FUNCTION constexpr std::conditional_t< + std::is_same_v, + ddc::StorageDiscreteDomain, + ddc::StorageDiscreteDomain> +replace_dim_of_1d( + StorageDiscreteDomain const& DDom_a, + [[maybe_unused]] StorageDiscreteDomain const& DDom_b) noexcept +{ + if constexpr (std::is_same_v) { + return ddc::StorageDiscreteDomain(DDom_b); + } else { + return DDom_a; + } +} + +} // namespace detail + +// Replace in DDom_a the dimension Dim1 by the dimension Dim2 of DDom_b +template +KOKKOS_FUNCTION constexpr auto replace_dim_of( + StorageDiscreteDomain const& DDom_a, + [[maybe_unused]] StorageDiscreteDomain const& DDom_b) noexcept +{ + // TODO : static_asserts + using TagSeqA = detail::TypeSeq; + using TagSeqB = detail::TypeSeq; + using TagSeqC = detail::TypeSeq; + + using type_seq_r = ddc::type_seq_replace_t; + return ddc::detail::convert_type_seq_to_storage_discrete_domain_t( + detail::replace_dim_of_1d< + DDim1, + DDim2, + DDimsA, + DDimsB...>(ddc::StorageDiscreteDomain(DDom_a), DDom_b)...); +} + +template +KOKKOS_FUNCTION constexpr DiscreteVector extents( + StorageDiscreteDomain const& domain) noexcept +{ + return DiscreteVector(StorageDiscreteDomain(domain).size()...); +} + +template +KOKKOS_FUNCTION constexpr DiscreteElement front( + StorageDiscreteDomain const& domain) noexcept +{ + return DiscreteElement(StorageDiscreteDomain(domain).front()...); +} + +template +KOKKOS_FUNCTION constexpr DiscreteElement back( + StorageDiscreteDomain const& domain) noexcept +{ + return DiscreteElement(StorageDiscreteDomain(domain).back()...); +} + +// template +// struct StorageDiscreteDomainIterator +// { +// private: +// DiscreteElement m_value = DiscreteElement(); + +// DiscreteVector m_stride = DiscreteVector(); + +// public: +// using iterator_category = std::random_access_iterator_tag; + +// using value_type = DiscreteElement; + +// using difference_type = std::ptrdiff_t; + +// KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomainIterator() = default; + +// KOKKOS_FUNCTION constexpr explicit StorageDiscreteDomainIterator( +// DiscreteElement value, +// DiscreteVector stride) +// : m_value(value) +// , m_stride(stride) +// { +// } + +// KOKKOS_FUNCTION constexpr DiscreteElement operator*() const noexcept +// { +// return m_value; +// } + +// KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator& operator++() +// { +// m_value.uid() += m_stride.value(); +// return *this; +// } + +// KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator operator++(int) +// { +// auto tmp = *this; +// ++*this; +// return tmp; +// } + +// KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator& operator--() +// { +// m_value.uid() -= m_stride.value(); +// return *this; +// } + +// KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator operator--(int) +// { +// auto tmp = *this; +// --*this; +// return tmp; +// } + +// KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator& operator+=(difference_type n) +// { +// if (n >= difference_type(0)) { +// m_value.uid() += static_cast(n) * m_stride.value(); +// } else { +// m_value.uid() -= static_cast(-n) * m_stride.value(); +// } +// return *this; +// } + +// KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator& operator-=(difference_type n) +// { +// if (n >= difference_type(0)) { +// m_value.uid() -= static_cast(n) * m_stride.value(); +// } else { +// m_value.uid() += static_cast(-n) * m_stride.value(); +// } +// return *this; +// } + +// KOKKOS_FUNCTION constexpr DiscreteElement operator[](difference_type n) const +// { +// return m_value + n * m_stride.value(); +// } + +// friend KOKKOS_FUNCTION constexpr bool operator==( +// StorageDiscreteDomainIterator const& xx, +// StorageDiscreteDomainIterator const& yy) +// { +// return xx.m_value == yy.m_value; +// } + +// #if !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201902L +// // In C++20, `a!=b` shall be automatically translated by the compiler to `!(a==b)` +// friend KOKKOS_FUNCTION constexpr bool operator!=( +// StorageDiscreteDomainIterator const& xx, +// StorageDiscreteDomainIterator const& yy) +// { +// return xx.m_value != yy.m_value; +// } +// #endif + +// friend KOKKOS_FUNCTION constexpr bool operator<( +// StorageDiscreteDomainIterator const& xx, +// StorageDiscreteDomainIterator const& yy) +// { +// return xx.m_value < yy.m_value; +// } + +// friend KOKKOS_FUNCTION constexpr bool operator>( +// StorageDiscreteDomainIterator const& xx, +// StorageDiscreteDomainIterator const& yy) +// { +// return yy < xx; +// } + +// friend KOKKOS_FUNCTION constexpr bool operator<=( +// StorageDiscreteDomainIterator const& xx, +// StorageDiscreteDomainIterator const& yy) +// { +// return !(yy < xx); +// } + +// friend KOKKOS_FUNCTION constexpr bool operator>=( +// StorageDiscreteDomainIterator const& xx, +// StorageDiscreteDomainIterator const& yy) +// { +// return !(xx < yy); +// } + +// friend KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator operator+( +// StorageDiscreteDomainIterator i, +// difference_type n) +// { +// return i += n; +// } + +// friend KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator operator+( +// difference_type n, +// StorageDiscreteDomainIterator i) +// { +// return i += n; +// } + +// friend KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator operator-( +// StorageDiscreteDomainIterator i, +// difference_type n) +// { +// return i -= n; +// } + +// friend KOKKOS_FUNCTION constexpr difference_type operator-( +// StorageDiscreteDomainIterator const& xx, +// StorageDiscreteDomainIterator const& yy) +// { +// return (yy.m_value > xx.m_value) ? (-static_cast(yy.m_value - xx.m_value)) +// : (xx.m_value - yy.m_value); +// } +// }; + +} // namespace ddc diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 25ac4916f..dd4151d55 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -29,6 +29,7 @@ add_executable( relocatable_device_code.cpp relocatable_device_code_initialization.cpp single_discretization.cpp + storage_discrete_domain.cpp strided_discrete_domain.cpp tagged_vector.cpp transform_reduce.cpp diff --git a/tests/storage_discrete_domain.cpp b/tests/storage_discrete_domain.cpp new file mode 100644 index 000000000..45c770c16 --- /dev/null +++ b/tests/storage_discrete_domain.cpp @@ -0,0 +1,101 @@ +// Copyright (C) The DDC development team, see COPYRIGHT.md file +// +// SPDX-License-Identifier: MIT + +#include + +#include + +namespace DDC_HIP_5_7_ANONYMOUS_NAMESPACE_WORKAROUND(DISCRETE_DOMAIN_CPP) { + +struct DDimX +{ +}; +using DElemX = ddc::DiscreteElement; +using DVectX = ddc::DiscreteVector; +using DDomX = ddc::StorageDiscreteDomain; + + +struct DDimY +{ +}; +using DElemY = ddc::DiscreteElement; +using DVectY = ddc::DiscreteVector; +using DDomY = ddc::StorageDiscreteDomain; + + +struct DDimZ +{ +}; +using DElemZ = ddc::DiscreteElement; +using DVectZ = ddc::DiscreteVector; +using DDomZ = ddc::StorageDiscreteDomain; + + +using DElemXY = ddc::DiscreteElement; +using DVectXY = ddc::DiscreteVector; +using DDomXY = ddc::StorageDiscreteDomain; + + +using DElemYX = ddc::DiscreteElement; +using DVectYX = ddc::DiscreteVector; +using DDomYX = ddc::StorageDiscreteDomain; + +using DElemXZ = ddc::DiscreteElement; +using DVectXZ = ddc::DiscreteVector; +using DDomXZ = ddc::StorageDiscreteDomain; + +using DElemZY = ddc::DiscreteElement; +using DVectZY = ddc::DiscreteVector; +using DDomZY = ddc::StorageDiscreteDomain; + + +using DElemXYZ = ddc::DiscreteElement; +using DVectXYZ = ddc::DiscreteVector; +using DDomXYZ = ddc::StorageDiscreteDomain; + +using DElemZYX = ddc::DiscreteElement; +using DVectZYX = ddc::DiscreteVector; +using DDomZYX = ddc::StorageDiscreteDomain; + +DElemX constexpr lbound_x(50); +DVectX constexpr nelems_x(3); +DElemX constexpr sentinel_x(lbound_x + nelems_x); +DElemX constexpr ubound_x(sentinel_x - 1); + + +DElemY constexpr lbound_y(4); +DVectY constexpr nelems_y(10); +DElemY constexpr sentinel_y(lbound_y); +DElemY constexpr ubound_y(sentinel_y - 1); + +DElemZ constexpr lbound_z(7); +DVectZ constexpr nelems_z(15); + +DElemXY constexpr lbound_x_y(lbound_x, lbound_y); +DVectXY constexpr nelems_x_y(nelems_x, nelems_y); +DElemXY constexpr ubound_x_y(ubound_x, ubound_y); + +DElemXZ constexpr lbound_x_z(lbound_x, lbound_z); +DVectXZ constexpr nelems_x_z(nelems_x, nelems_z); + +} // namespace DDC_HIP_5_7_ANONYMOUS_NAMESPACE_WORKAROUND(DISCRETE_DOMAIN_CPP) + +TEST(StorageDiscreteDomainTest, Constructor) +{ + Kokkos::View const view_x("view_x", 2); + view_x(0) = lbound_x + 0; + view_x(1) = lbound_x + 2; + Kokkos::View const view_y("view_y", 3); + view_y(0) = lbound_y + 0; + view_y(1) = lbound_y + 2; + view_y(2) = lbound_y + 5; + DDomXY const dom_xy(view_x, view_y); + EXPECT_EQ(dom_xy.distance_from_front(lbound_x + 0, lbound_y + 0), DVectXY(0, 0)); + EXPECT_EQ(dom_xy.distance_from_front(lbound_x + 0, lbound_y + 2), DVectXY(0, 1)); + EXPECT_EQ(dom_xy.distance_from_front(lbound_x + 0, lbound_y + 5), DVectXY(0, 2)); + EXPECT_EQ(dom_xy.distance_from_front(lbound_x + 2, lbound_y + 0), DVectXY(1, 0)); + EXPECT_EQ(dom_xy.distance_from_front(lbound_x + 2, lbound_y + 2), DVectXY(1, 1)); + EXPECT_EQ(dom_xy.distance_from_front(lbound_x + 2, lbound_y + 5), DVectXY(1, 2)); + EXPECT_FALSE(dom_xy.is_inside(lbound_x + 1, lbound_y + 0)); +} From 1046fe42d420f035c0b03fe07fbd38b61f5da245 Mon Sep 17 00:00:00 2001 From: Thomas Padioleau Date: Wed, 15 Jan 2025 21:55:02 +0100 Subject: [PATCH 08/12] Reintroduce ddc::DiscreteDomain specialization and fix some warnings --- include/ddc/chunk.hpp | 291 +++++++++++++++++- include/ddc/chunk_common.hpp | 272 +++++++++++++++++ include/ddc/chunk_span.hpp | 388 +++++++++++++++++++++--- include/ddc/discrete_domain.hpp | 6 +- include/ddc/storage_discrete_domain.hpp | 25 +- include/ddc/strided_discrete_domain.hpp | 22 +- include/ddc/transform_reduce.hpp | 1 - tests/chunk.cpp | 192 ++++++------ tests/storage_discrete_domain.cpp | 26 +- tests/strided_discrete_domain.cpp | 4 +- 10 files changed, 1037 insertions(+), 190 deletions(-) diff --git a/include/ddc/chunk.hpp b/include/ddc/chunk.hpp index ee757cb4a..a4137995a 100644 --- a/include/ddc/chunk.hpp +++ b/include/ddc/chunk.hpp @@ -24,6 +24,283 @@ class Chunk; template inline constexpr bool enable_chunk> = true; +template +class Chunk, Allocator> + : public ChunkCommon, Kokkos::layout_right> +{ +protected: + using base_type = ChunkCommon, Kokkos::layout_right>; + + /// ND memory view + using internal_mdspan_type = typename base_type::internal_mdspan_type; + +public: + /// type of a span of this full chunk + using span_type = ChunkSpan< + ElementType, + DiscreteDomain, + Kokkos::layout_right, + typename Allocator::memory_space>; + + /// type of a view of this full chunk + using view_type = ChunkSpan< + ElementType const, + DiscreteDomain, + Kokkos::layout_right, + typename Allocator::memory_space>; + + /// The dereferenceable part of the co-domain but with indexing starting at 0 + using allocation_mdspan_type = typename base_type::allocation_mdspan_type; + + using const_allocation_mdspan_type = typename base_type::const_allocation_mdspan_type; + + using discrete_domain_type = typename base_type::discrete_domain_type; + + using memory_space = typename Allocator::memory_space; + + using discrete_element_type = typename base_type::discrete_element_type; + + using extents_type = typename base_type::extents_type; + + using layout_type = typename base_type::layout_type; + + using mapping_type = typename base_type::mapping_type; + + using element_type = typename base_type::element_type; + + using value_type = typename base_type::value_type; + + using size_type = typename base_type::size_type; + + using data_handle_type = typename base_type::data_handle_type; + + using reference = typename base_type::reference; + + template + friend class Chunk; + +private: + Allocator m_allocator; + + std::string m_label; + +public: + /// Empty Chunk + Chunk() = default; + + /// Construct a labeled Chunk on a domain with uninitialized values + explicit Chunk( + std::string const& label, + discrete_domain_type const& domain, + Allocator allocator = Allocator()) + : base_type(allocator.allocate(label, domain.size()), domain) + , m_allocator(std::move(allocator)) + , m_label(label) + { + } + + /// Construct a Chunk on a domain with uninitialized values + explicit Chunk(discrete_domain_type const& domain, Allocator allocator = Allocator()) + : Chunk("no-label", domain, std::move(allocator)) + { + } + + /// Deleted: use deepcopy instead + Chunk(Chunk const& other) = delete; + + /** Constructs a new Chunk by move + * @param other the Chunk to move + */ + Chunk(Chunk&& other) noexcept + : base_type(std::move(static_cast(other))) + , m_allocator(std::move(other.m_allocator)) + , m_label(std::move(other.m_label)) + { + other.m_internal_mdspan = internal_mdspan_type(nullptr, other.m_internal_mdspan.mapping()); + } + + ~Chunk() noexcept + { + if (this->m_internal_mdspan.data_handle()) { + m_allocator.deallocate(this->data_handle(), this->size()); + } + } + + /// Deleted: use deepcopy instead + Chunk& operator=(Chunk const& other) = delete; + + /** Move-assigns a new value to this field + * @param other the Chunk to move + * @return *this + */ + Chunk& operator=(Chunk&& other) noexcept + { + if (this == &other) { + return *this; + } + if (this->m_internal_mdspan.data_handle()) { + m_allocator.deallocate(this->data_handle(), this->size()); + } + static_cast(*this) = std::move(static_cast(other)); + m_allocator = std::move(other.m_allocator); + m_label = std::move(other.m_label); + other.m_internal_mdspan = internal_mdspan_type(nullptr, other.m_internal_mdspan.mapping()); + + return *this; + } + + /// Slice out some dimensions + template + auto operator[](DiscreteElement const& slice_spec) const + { + return view_type(*this)[slice_spec]; + } + + /// Slice out some dimensions + template + auto operator[](DiscreteElement const& slice_spec) + { + return span_view()[slice_spec]; + } + + /// Slice out some dimensions + template + auto operator[](DiscreteDomain const& odomain) const + { + return span_view()[odomain]; + } + + /// Slice out some dimensions + template + auto operator[](DiscreteDomain const& odomain) + { + return span_view()[odomain]; + } + + /** Element access using a list of DiscreteElement + * @param delems discrete coordinates + * @return const-reference to this element + */ + template + element_type const& operator()(DElems const&... delems) const noexcept + { + static_assert( + sizeof...(DDims) == (0 + ... + DElems::size()), + "Invalid number of dimensions"); + static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); + assert(((DiscreteElement(take(delems...)) >= front(this->m_domain)) + && ...)); + assert(((DiscreteElement(take(delems...)) <= back(this->m_domain)) + && ...)); + return DDC_MDSPAN_ACCESS_OP(this->m_internal_mdspan, uid(take(delems...))...); + } + + /** Element access using a list of DiscreteElement + * @param delems discrete coordinates + * @return reference to this element + */ + template + element_type& operator()(DElems const&... delems) noexcept + { + static_assert( + sizeof...(DDims) == (0 + ... + DElems::size()), + "Invalid number of dimensions"); + static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); + assert(((DiscreteElement(take(delems...)) >= front(this->m_domain)) + && ...)); + assert(((DiscreteElement(take(delems...)) <= back(this->m_domain)) + && ...)); + return DDC_MDSPAN_ACCESS_OP(this->m_internal_mdspan, uid(take(delems...))...); + } + + /** Returns the label of the Chunk + * @return c-string + */ + char const* label() const + { + return m_label.c_str(); + } + + /** Access to the underlying allocation pointer + * @return read-only allocation pointer + */ + ElementType const* data_handle() const + { + return base_type::data_handle(); + } + + /** Access to the underlying allocation pointer + * @return allocation pointer + */ + ElementType* data_handle() + { + return base_type::data_handle(); + } + + /** Provide a mdspan on the memory allocation + * @return read-only allocation mdspan + */ + const_allocation_mdspan_type allocation_mdspan() const + { + return base_type::allocation_mdspan(); + } + + /** Provide a mdspan on the memory allocation + * @return allocation mdspan + */ + allocation_mdspan_type allocation_mdspan() + { + return base_type::allocation_mdspan(); + } + + /** Provide an unmanaged `Kokkos::View` on the memory allocation + * @return allocation `Kokkos::View` + */ + auto allocation_kokkos_view() + { + auto s = this->allocation_mdspan(); + auto kokkos_layout = detail::build_kokkos_layout( + s.extents(), + s.mapping(), + std::make_index_sequence {}); + return Kokkos::View< + detail::mdspan_to_kokkos_element_t, + decltype(kokkos_layout), + typename Allocator::memory_space>(s.data_handle(), kokkos_layout); + } + + /** Provide an unmanaged `Kokkos::View` on the memory allocation + * @return read-only allocation `Kokkos::View` + */ + auto allocation_kokkos_view() const + { + auto s = this->allocation_mdspan(); + auto kokkos_layout = detail::build_kokkos_layout( + s.extents(), + s.mapping(), + std::make_index_sequence {}); + return Kokkos::View< + detail::mdspan_to_kokkos_element_t, + decltype(kokkos_layout), + typename Allocator::memory_space>(s.data_handle(), kokkos_layout); + } + + view_type span_cview() const + { + return view_type(*this); + } + + view_type span_view() const + { + return view_type(*this); + } + + span_type span_view() + { + return span_type(*this); + } +}; + template class Chunk : public ChunkCommon { @@ -161,20 +438,6 @@ class Chunk : public ChunkCommon // return span_view()[slice_spec]; // } - // /// Slice out some dimensions - // template - // auto operator[](DiscreteDomain const& odomain) const - // { - // return span_view()[odomain]; - // } - - // /// Slice out some dimensions - // template - // auto operator[](DiscreteDomain const& odomain) - // { - // return span_view()[odomain]; - // } - /** Element access using a list of DiscreteElement * @param delems discrete coordinates * @return const-reference to this element diff --git a/include/ddc/chunk_common.hpp b/include/ddc/chunk_common.hpp index b4f1abb5e..6c5127045 100644 --- a/include/ddc/chunk_common.hpp +++ b/include/ddc/chunk_common.hpp @@ -32,6 +32,278 @@ KOKKOS_FUNCTION auto get_domain(ChunkType const& chunk) noexcept template class ChunkCommon; +template +class ChunkCommon, LayoutStridedPolicy> +{ +protected: + /// the raw mdspan underlying this, with the same indexing (0 might no be dereferenceable) + using internal_mdspan_type = Kokkos::mdspan< + ElementType, + Kokkos::dextents, + Kokkos::layout_stride>; + +public: + using discrete_domain_type = DiscreteDomain; + + /// The dereferenceable part of the co-domain but with a different domain, starting at 0 + using allocation_mdspan_type = Kokkos::mdspan< + ElementType, + Kokkos::dextents, + LayoutStridedPolicy>; + + using const_allocation_mdspan_type = Kokkos::mdspan< + const ElementType, + Kokkos::dextents, + LayoutStridedPolicy>; + + using discrete_element_type = typename discrete_domain_type::discrete_element_type; + + using extents_type = typename allocation_mdspan_type::extents_type; + + using layout_type = typename allocation_mdspan_type::layout_type; + + using accessor_type = typename allocation_mdspan_type::accessor_type; + + using mapping_type = typename allocation_mdspan_type::mapping_type; + + using element_type = typename allocation_mdspan_type::element_type; + + using value_type = typename allocation_mdspan_type::value_type; + + using size_type = typename allocation_mdspan_type::size_type; + + using data_handle_type = typename allocation_mdspan_type::data_handle_type; + + using reference = typename allocation_mdspan_type::reference; + + // ChunkCommon, ChunkSpan and Chunk need to access to m_internal_mdspan and m_domain of other template versions + template + friend class ChunkCommon; + + template + friend class ChunkSpan; + + template + friend class Chunk; + + static_assert(mapping_type::is_always_strided()); + +protected: + /// The raw view of the data + internal_mdspan_type m_internal_mdspan; + + /// The mesh on which this chunk is defined + discrete_domain_type m_domain; + +public: + static KOKKOS_FUNCTION constexpr int rank() noexcept + { + return extents_type::rank(); + } + + static KOKKOS_FUNCTION constexpr int rank_dynamic() noexcept + { + return extents_type::rank_dynamic(); + } + + static KOKKOS_FUNCTION constexpr size_type static_extent(std::size_t r) noexcept + { + return extents_type::static_extent(r); + } + + static KOKKOS_FUNCTION constexpr bool is_always_unique() noexcept + { + return mapping_type::is_always_unique(); + } + + static KOKKOS_FUNCTION constexpr bool is_always_exhaustive() noexcept + { + return mapping_type::is_always_exhaustive(); + } + + static KOKKOS_FUNCTION constexpr bool is_always_strided() noexcept + { + return mapping_type::is_always_strided(); + } + +private: + template + static KOKKOS_FUNCTION constexpr std:: + enable_if_t, internal_mdspan_type> + make_internal_mdspan(ElementType* ptr, discrete_domain_type const& domain) + { + if (domain.empty()) { + return internal_mdspan_type(ptr, Kokkos::layout_stride::mapping()); + } + extents_type const extents_r(::ddc::extents(domain).value()...); + mapping_type const mapping_r(extents_r); + + extents_type const extents_s((front(domain) + ddc::extents(domain)).uid()...); + std::array const strides_s { + mapping_r.stride(type_seq_rank_v>)...}; + Kokkos::layout_stride::mapping const mapping_s(extents_s, strides_s); + return internal_mdspan_type(ptr - mapping_s(front(domain).uid()...), mapping_s); + } + +public: + KOKKOS_FUNCTION constexpr accessor_type accessor() const + { + return m_internal_mdspan.accessor(); + } + + KOKKOS_FUNCTION constexpr DiscreteVector extents() const noexcept + { + return m_domain.extents(); + } + + template + KOKKOS_FUNCTION constexpr size_type extent() const noexcept + { + return m_domain.template extent(); + } + + KOKKOS_FUNCTION constexpr size_type size() const noexcept + { + return allocation_mdspan().size(); + } + + KOKKOS_FUNCTION constexpr mapping_type mapping() const noexcept + { + return allocation_mdspan().mapping(); + } + + KOKKOS_FUNCTION constexpr bool is_unique() const noexcept + { + return allocation_mdspan().is_unique(); + } + + KOKKOS_FUNCTION constexpr bool is_exhaustive() const noexcept + { + return allocation_mdspan().is_exhaustive(); + } + + KOKKOS_FUNCTION constexpr bool is_strided() const noexcept + { + return allocation_mdspan().is_strided(); + } + + template + KOKKOS_FUNCTION constexpr size_type stride() const + { + return m_internal_mdspan.stride(type_seq_rank_v>); + } + + /** Provide access to the domain on which this chunk is defined + * @return the domain on which this chunk is defined + */ + KOKKOS_FUNCTION constexpr discrete_domain_type domain() const noexcept + { + return m_domain; + } + + /** Provide access to the domain on which this chunk is defined + * @return the domain on which this chunk is defined + */ + template + KOKKOS_FUNCTION constexpr DiscreteDomain domain() const noexcept + { + return DiscreteDomain(domain()); + } + +protected: + /// Empty ChunkCommon + KOKKOS_DEFAULTED_FUNCTION constexpr ChunkCommon() = default; + + /** Constructs a new ChunkCommon from scratch + * @param internal_mdspan + * @param domain + */ + KOKKOS_FUNCTION constexpr ChunkCommon( + internal_mdspan_type internal_mdspan, + discrete_domain_type const& domain) noexcept + : m_internal_mdspan(std::move(internal_mdspan)) + , m_domain(domain) + { + } + + /** Constructs a new ChunkCommon from scratch + * @param ptr the allocation pointer to the data + * @param domain the domain that sustains the view + */ + template < + class Mapping = mapping_type, + std::enable_if_t, int> = 0> + KOKKOS_FUNCTION constexpr ChunkCommon(ElementType* ptr, discrete_domain_type const& domain) + : m_internal_mdspan(make_internal_mdspan(ptr, domain)) + , m_domain(domain) + { + // Handle the case where an allocation of size 0 returns a nullptr. + assert(domain.empty() || ((ptr != nullptr) && !domain.empty())); + } + + /** Constructs a new ChunkCommon by copy, yields a new view to the same data + * @param other the ChunkCommon to copy + */ + KOKKOS_DEFAULTED_FUNCTION constexpr ChunkCommon(ChunkCommon const& other) = default; + + /** Constructs a new ChunkCommon by move + * @param other the ChunkCommon to move + */ + KOKKOS_DEFAULTED_FUNCTION constexpr ChunkCommon(ChunkCommon&& other) noexcept = default; + + KOKKOS_DEFAULTED_FUNCTION ~ChunkCommon() noexcept = default; + + /** Copy-assigns a new value to this ChunkCommon, yields a new view to the same data + * @param other the ChunkCommon to copy + * @return *this + */ + KOKKOS_DEFAULTED_FUNCTION constexpr ChunkCommon& operator=(ChunkCommon const& other) = default; + + /** Move-assigns a new value to this ChunkCommon + * @param other the ChunkCommon to move + * @return *this + */ + KOKKOS_DEFAULTED_FUNCTION constexpr ChunkCommon& operator=(ChunkCommon&& other) noexcept + = default; + + /** Access to the underlying allocation pointer + * @return allocation pointer + */ + KOKKOS_FUNCTION constexpr ElementType* data_handle() const + { + ElementType* ptr = m_internal_mdspan.data_handle(); + if (!m_domain.empty()) { + ptr += m_internal_mdspan.mapping()(front(m_domain).uid()...); + } + return ptr; + } + + /** Provide a modifiable view of the data + * @return a modifiable view of the data + */ + KOKKOS_FUNCTION constexpr internal_mdspan_type internal_mdspan() const + { + return m_internal_mdspan; + } + + /** Provide a modifiable view of the data + * @return a modifiable view of the data + */ + KOKKOS_FUNCTION constexpr allocation_mdspan_type allocation_mdspan() const + { + DDC_IF_NVCC_THEN_PUSH_AND_SUPPRESS(implicit_return_from_non_void_function) + extents_type const extents_s(::ddc::extents(m_domain).value()...); + if constexpr (std::is_same_v) { + mapping_type const map(extents_s, m_internal_mdspan.mapping().strides()); + return allocation_mdspan_type(data_handle(), map); + } else { + mapping_type const map(extents_s); + return allocation_mdspan_type(data_handle(), map); + } + DDC_IF_NVCC_THEN_POP + } +}; + template class ChunkCommon { diff --git a/include/ddc/chunk_span.hpp b/include/ddc/chunk_span.hpp index fc6dfda00..0f25f6dd9 100644 --- a/include/ddc/chunk_span.hpp +++ b/include/ddc/chunk_span.hpp @@ -39,8 +39,9 @@ inline constexpr bool enable_borrowed_chunk> = true; -template -class ChunkSpan : public ChunkCommon +template +class ChunkSpan, LayoutStridedPolicy, MemorySpace> + : public ChunkCommon, LayoutStridedPolicy> { static_assert( std::is_same_v @@ -49,14 +50,22 @@ class ChunkSpan : public ChunkCommon; + using base_type = ChunkCommon, LayoutStridedPolicy>; + + /// the raw mdspan underlying this, with the same indexing (0 might no be dereferenceable) + using typename base_type::internal_mdspan_type; public: /// type of a span of this full chunk - using span_type = ChunkSpan; + using span_type + = ChunkSpan, LayoutStridedPolicy, MemorySpace>; /// type of a view of this full chunk - using view_type = ChunkSpan; + using view_type = ChunkSpan< + ElementType const, + DiscreteDomain, + LayoutStridedPolicy, + MemorySpace>; using discrete_domain_type = typename base_type::discrete_domain_type; @@ -91,6 +100,24 @@ class ChunkSpan : public ChunkCommon(domain) + extents(domain)).uid()...); + std::array const strides_s { + allocation_mdspan.mapping().stride( + type_seq_rank_v>)...}; + Kokkos::layout_stride::mapping const mapping_s(extents_s, strides_s); + return internal_mdspan_type( + allocation_mdspan.data_handle() - mapping_s(front(domain).uid()...), + mapping_s); + } + + return internal_mdspan_type(allocation_mdspan); + } + template KOKKOS_FUNCTION constexpr auto get_slicer_for(DiscreteElement const& c) const { @@ -117,6 +144,307 @@ class ChunkSpan : public ChunkCommon>> + ChunkSpan(Chunk&& other) noexcept = delete; + + /** Constructs a new ChunkSpan from a Chunk, yields a new view to the same data + * @param other the Chunk to view + */ + template < + class OElementType, + class Allocator, + class = std::enable_if_t>> + KOKKOS_FUNCTION constexpr explicit ChunkSpan( + Chunk& other) noexcept + : base_type(other.m_internal_mdspan, other.m_domain) + { + } + + /** Constructs a new ChunkSpan from a Chunk, yields a new view to the same data + * @param other the Chunk to view + */ + // Disabled by SFINAE in the case of `ElementType` is not `const` to avoid write access + template < + class OElementType, + class SFINAEElementType = ElementType, + class = std::enable_if_t>, + class Allocator, + class = std::enable_if_t>> + KOKKOS_FUNCTION constexpr explicit ChunkSpan( + Chunk const& other) noexcept + : base_type(other.m_internal_mdspan, other.m_domain) + { + } + + /** Constructs a new ChunkSpan by copy of a chunk, yields a new view to the same data + * @param other the ChunkSpan to move + */ + template + KOKKOS_FUNCTION constexpr explicit ChunkSpan( + ChunkSpan const& + other) noexcept + : base_type(other.m_internal_mdspan, other.m_domain) + { + } + + /** Constructs a new ChunkSpan from scratch + * @param ptr the allocation pointer to the data + * @param domain the domain that sustains the view + */ + template < + class Mapping = mapping_type, + std::enable_if_t, int> = 0> + KOKKOS_FUNCTION constexpr ChunkSpan(ElementType* const ptr, discrete_domain_type const& domain) + : base_type(ptr, domain) + { + } + + /** Constructs a new ChunkSpan from scratch + * @param allocation_mdspan the allocation mdspan to the data + * @param domain the domain that sustains the view + */ + KOKKOS_FUNCTION constexpr ChunkSpan( + allocation_mdspan_type allocation_mdspan, + discrete_domain_type const& domain) + : base_type(build_internal_mdspan(allocation_mdspan, domain), domain) + { + assert(((allocation_mdspan.extent(type_seq_rank_v>) + == static_cast(domain.template extent().value())) + && ...)); + } + + /** Constructs a new ChunkSpan from scratch + * @param view the Kokkos view + * @param domain the domain that sustains the view + */ + template >> + KOKKOS_FUNCTION constexpr ChunkSpan( + KokkosView const& view, + discrete_domain_type const& domain) noexcept + : ChunkSpan( + detail::build_mdspan(view, std::make_index_sequence {}), + domain) + { + } + + KOKKOS_DEFAULTED_FUNCTION ~ChunkSpan() noexcept = default; + + /** Copy-assigns a new value to this ChunkSpan, yields a new view to the same data + * @param other the ChunkSpan to copy + * @return *this + */ + KOKKOS_DEFAULTED_FUNCTION constexpr ChunkSpan& operator=(ChunkSpan const& other) = default; + + /** Move-assigns a new value to this ChunkSpan + * @param other the ChunkSpan to move + * @return *this + */ + KOKKOS_DEFAULTED_FUNCTION constexpr ChunkSpan& operator=(ChunkSpan&& other) noexcept = default; + + /** Slice out some dimensions + */ + template + KOKKOS_FUNCTION constexpr auto operator[]( + DiscreteElement const& slice_spec) const + { + auto subview = Kokkos::submdspan(allocation_mdspan(), get_slicer_for(slice_spec)...); + using layout_type = typename decltype(subview)::layout_type; + using extents_type = typename decltype(subview)::extents_type; + using detail::TypeSeq; + using OutTypeSeqDDims = type_seq_remove_t, TypeSeq>; + using OutDDom = detail::convert_type_seq_to_discrete_domain_t; + if constexpr ( + std::is_same_v> + || std::is_same_v>) { + Kokkos::layout_stride::mapping const mapping_stride(subview.mapping()); + Kokkos::mdspan const + a(subview.data_handle(), mapping_stride); + return ChunkSpan< + ElementType, + OutDDom, + Kokkos::layout_stride, + memory_space>(a, OutDDom(this->m_domain)); + } else { + return ChunkSpan< + ElementType, + OutDDom, + layout_type, + memory_space>(subview, OutDDom(this->m_domain)); + } + } + + /** Restrict to a subdomain + */ + template + KOKKOS_FUNCTION constexpr auto operator[](DiscreteDomain const& odomain) const + { + auto subview = Kokkos::submdspan(allocation_mdspan(), get_slicer_for(odomain)...); + using layout_type = typename decltype(subview)::layout_type; + using extents_type = typename decltype(subview)::extents_type; + if constexpr ( + std::is_same_v> + || std::is_same_v>) { + Kokkos::layout_stride::mapping const mapping_stride(subview.mapping()); + Kokkos::mdspan const + a(subview.data_handle(), mapping_stride); + return ChunkSpan< + ElementType, + decltype(this->m_domain.restrict_with(odomain)), + Kokkos::layout_stride, + memory_space>(a, this->m_domain.restrict_with(odomain)); + } else { + return ChunkSpan< + ElementType, + decltype(this->m_domain.restrict_with(odomain)), + layout_type, + memory_space>(subview, this->m_domain.restrict_with(odomain)); + } + } + + /** Element access using a list of DiscreteElement + * @param delems discrete elements + * @return reference to this element + */ + template + KOKKOS_FUNCTION constexpr reference operator()(DElems const&... delems) const noexcept + { + static_assert( + sizeof...(DDims) == (0 + ... + DElems::size()), + "Invalid number of dimensions"); + static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); + assert(((DiscreteElement(take(delems...)) >= front(this->m_domain)) + && ...)); + assert(((DiscreteElement(take(delems...)) <= back(this->m_domain)) + && ...)); + return DDC_MDSPAN_ACCESS_OP(this->m_internal_mdspan, uid(take(delems...))...); + } + + /** Access to the underlying allocation pointer + * @return allocation pointer + */ + KOKKOS_FUNCTION constexpr ElementType* data_handle() const + { + return base_type::data_handle(); + } + + /** Provide a mdspan on the memory allocation + * @return allocation mdspan + */ + KOKKOS_FUNCTION constexpr allocation_mdspan_type allocation_mdspan() const + { + return base_type::allocation_mdspan(); + } + + /** Provide a mdspan on the memory allocation + * @return allocation mdspan + */ + KOKKOS_FUNCTION constexpr auto allocation_kokkos_view() const + { + auto s = this->allocation_mdspan(); + auto kokkos_layout = detail::build_kokkos_layout( + s.extents(), + s.mapping(), + std::make_index_sequence {}); + return Kokkos::View< + detail::mdspan_to_kokkos_element_t, + decltype(kokkos_layout), + MemorySpace>(s.data_handle(), kokkos_layout); + } + + KOKKOS_FUNCTION constexpr view_type span_cview() const + { + return view_type(*this); + } + + KOKKOS_FUNCTION constexpr span_type span_view() const + { + return *this; + } +}; + +template +class ChunkSpan : public ChunkCommon +{ + static_assert( + std::is_same_v + || std::is_same_v + || std::is_same_v, + "ChunkSpan only supports layout_left, layout_right or layout_stride"); + +protected: + using base_type = ChunkCommon; + +public: + /// type of a span of this full chunk + using span_type = ChunkSpan; + + /// type of a view of this full chunk + using view_type = ChunkSpan; + + using discrete_domain_type = typename base_type::discrete_domain_type; + + using memory_space = MemorySpace; + + /// The dereferenceable part of the co-domain but with a different domain, starting at 0 + using allocation_mdspan_type = typename base_type::allocation_mdspan_type; + + using const_allocation_mdspan_type = typename base_type::const_allocation_mdspan_type; + + using discrete_element_type = typename discrete_domain_type::discrete_element_type; + + using extents_type = typename base_type::extents_type; + + using layout_type = typename base_type::layout_type; + + using accessor_type = typename base_type::accessor_type; + + using mapping_type = typename base_type::mapping_type; + + using element_type = typename base_type::element_type; + + using value_type = typename base_type::value_type; + + using size_type = typename base_type::size_type; + + using data_handle_type = typename base_type::data_handle_type; + + using reference = typename base_type::reference; + + template + friend class ChunkSpan; + +protected: + template + KOKKOS_FUNCTION constexpr auto get_slicer_for(DiscreteElement const& c) const + { + DDC_IF_NVCC_THEN_PUSH_AND_SUPPRESS(implicit_return_from_non_void_function) + if constexpr (in_tags_v>) { + return (uid(c) - front(this->m_domain).uid()); + } else { + return Kokkos::full_extent; + } + DDC_IF_NVCC_THEN_POP + } + public: /// Empty ChunkSpan KOKKOS_DEFAULTED_FUNCTION constexpr ChunkSpan() = default; @@ -264,34 +592,6 @@ class ChunkSpan : public ChunkCommon - // KOKKOS_FUNCTION constexpr auto operator[](DiscreteDomain const& odomain) const - // { - // auto subview = Kokkos::submdspan(allocation_mdspan(), get_slicer_for(odomain)...); - // using layout_type = typename decltype(subview)::layout_type; - // using extents_type = typename decltype(subview)::extents_type; - // if constexpr ( - // std::is_same_v> - // || std::is_same_v>) { - // Kokkos::layout_stride::mapping const mapping_stride(subview.mapping()); - // Kokkos::mdspan const - // a(subview.data_handle(), mapping_stride); - // return ChunkSpan< - // ElementType, - // decltype(this->m_domain.restrict_with(odomain)), - // Kokkos::layout_stride, - // memory_space>(a, this->m_domain.restrict_with(odomain)); - // } else { - // return ChunkSpan< - // ElementType, - // decltype(this->m_domain.restrict_with(odomain)), - // layout_type, - // memory_space>(subview, this->m_domain.restrict_with(odomain)); - // } - // } - /** Element access using a list of DiscreteElement * @param delems discrete elements * @return reference to this element @@ -365,18 +665,20 @@ KOKKOS_DEDUCTION_GUIDE ChunkSpan( typename Kokkos::View::memory_space>; template -ChunkSpan(Chunk& other) -> ChunkSpan< - ElementType, - SupportType, - Kokkos::layout_right, - typename Allocator::memory_space>; +ChunkSpan(Chunk& other) + -> ChunkSpan< + ElementType, + SupportType, + Kokkos::layout_right, + typename Allocator::memory_space>; template -ChunkSpan(Chunk const& other) -> ChunkSpan< - const ElementType, - SupportType, - Kokkos::layout_right, - typename Allocator::memory_space>; +ChunkSpan(Chunk const& other) + -> ChunkSpan< + const ElementType, + SupportType, + Kokkos::layout_right, + typename Allocator::memory_space>; template < class ElementType, diff --git a/include/ddc/discrete_domain.hpp b/include/ddc/discrete_domain.hpp index 904d92620..98eb37877 100644 --- a/include/ddc/discrete_domain.hpp +++ b/include/ddc/discrete_domain.hpp @@ -390,7 +390,7 @@ class DiscreteDomain<> KOKKOS_FUNCTION constexpr DiscreteElement<> operator()( DiscreteVector<> const& /* dvect */) const noexcept { - return DiscreteElement<>(); + return {}; } template @@ -412,12 +412,12 @@ class DiscreteDomain<> static DiscreteVector<> distance_from_front() noexcept { - return DiscreteVector<>(); + return {}; } static DiscreteVector<> distance_from_front(DiscreteElement<>) noexcept { - return DiscreteVector<>(); + return {}; } static KOKKOS_FUNCTION constexpr bool empty() noexcept diff --git a/include/ddc/storage_discrete_domain.hpp b/include/ddc/storage_discrete_domain.hpp index b12777853..929197c33 100644 --- a/include/ddc/storage_discrete_domain.hpp +++ b/include/ddc/storage_discrete_domain.hpp @@ -71,7 +71,7 @@ KOKKOS_FUNCTION ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& typename std::iterator_traits::difference_type count = last - first; while (count > 0) { it = first; - typename std::iterator_traits::difference_type step = count / 2; + typename std::iterator_traits::difference_type const step = count / 2; it += step; if (comp(*it, value)) { @@ -95,6 +95,16 @@ bool binary_search(ForwardIt first, ForwardIt last, const T& value, Compare comp return (!(first == last) && !(comp(value, *first))); } +template +struct GetUidFn +{ + KOKKOS_FUNCTION DiscreteElementType + operator()(DiscreteElement const& delem) const noexcept + { + return delem.uid(); + } +}; + } // namespace detail template @@ -128,11 +138,10 @@ class StorageDiscreteDomain { } - /** Construct a StridedDiscreteDomain starting from element_begin with size points. - * @param element_begin the lower bound in each direction - * @param size the number of points in each direction + /** Construct a StorageDiscreteDomain with Kokkos::View explicitly listing the discrete elements. + * @param views list of Kokkos::View */ - KOKKOS_FUNCTION explicit constexpr StorageDiscreteDomain( + explicit constexpr StorageDiscreteDomain( Kokkos::View*, Kokkos::SharedSpace> const&... views) { ((m_views[type_seq_rank_v>] @@ -143,7 +152,7 @@ class StorageDiscreteDomain Kokkos::DefaultExecutionSpace(), views, m_views[type_seq_rank_v>], - KOKKOS_LAMBDA(DiscreteElement const& delem) { return delem.uid(); })), + detail::GetUidFn())), ...); Kokkos::fence("StorageDiscreteDomainCtor"); } @@ -550,7 +559,7 @@ using convert_type_seq_to_storage_discrete_domain_t = } // namespace detail -// Computes the substraction DDom_a - DDom_b in the sense of linear spaces(retained dimensions are those in DDom_a which are not in DDom_b) +// Computes the subtraction DDom_a - DDom_b in the sense of linear spaces(retained dimensions are those in DDom_a which are not in DDom_b) template KOKKOS_FUNCTION constexpr auto remove_dims_of( StorageDiscreteDomain const& DDom_a, @@ -565,7 +574,7 @@ KOKKOS_FUNCTION constexpr auto remove_dims_of( namespace detail { -// Checks if dimension of DDom_a is DDim1. If not, returns restriction to DDim2 of DDom_b. May not be usefull in its own, it helps for replace_dim_of +// Checks if dimension of DDom_a is DDim1. If not, returns restriction to DDim2 of DDom_b. May not be useful in its own, it helps for replace_dim_of template KOKKOS_FUNCTION constexpr std::conditional_t< std::is_same_v, diff --git a/include/ddc/strided_discrete_domain.hpp b/include/ddc/strided_discrete_domain.hpp index bcc92f622..74b3b4fec 100644 --- a/include/ddc/strided_discrete_domain.hpp +++ b/include/ddc/strided_discrete_domain.hpp @@ -49,7 +49,7 @@ struct ToTypeSeq> } // namespace detail template -DiscreteVector prod( +KOKKOS_FUNCTION DiscreteVector prod( DiscreteVector const& lhs, DiscreteVector const& rhs) noexcept { @@ -95,7 +95,8 @@ class StridedDiscreteDomain /** Construct a StridedDiscreteDomain starting from element_begin with size points. * @param element_begin the lower bound in each direction - * @param size the number of points in each direction + * @param extents the number of points in each direction + * @param strides the step between two elements */ KOKKOS_FUNCTION constexpr StridedDiscreteDomain( discrete_element_type const& element_begin, @@ -218,7 +219,7 @@ class StridedDiscreteDomain // } template - bool is_inside(DElems const&... delems) const noexcept + KOKKOS_FUNCTION bool is_inside(DElems const&... delems) const noexcept { static_assert( sizeof...(DDims) == (0 + ... + DElems::size()), @@ -243,7 +244,8 @@ class StridedDiscreteDomain } template - DiscreteVector distance_from_front(DElems const&... delems) const noexcept + KOKKOS_FUNCTION DiscreteVector distance_from_front( + DElems const&... delems) const noexcept { static_assert( sizeof...(DDims) == (0 + ... + DElems::size()), @@ -429,9 +431,9 @@ class StridedDiscreteDomain<> } KOKKOS_FUNCTION constexpr DiscreteElement<> operator()( - DiscreteVector<> const& dvect) const noexcept + DiscreteVector<> const& /* dvect */) const noexcept { - return DiscreteElement<>(); + return {}; } #if defined(DDC_BUILD_DEPRECATED_CODE) @@ -465,12 +467,12 @@ class StridedDiscreteDomain<> static DiscreteVector<> distance_from_front() noexcept { - return DiscreteVector<>(); + return {}; } static DiscreteVector<> distance_from_front(DiscreteElement<>) noexcept { - return DiscreteVector<>(); + return {}; } static KOKKOS_FUNCTION constexpr bool empty() noexcept @@ -510,7 +512,7 @@ using convert_type_seq_to_strided_discrete_domain_t = } // namespace detail -// Computes the substraction DDom_a - DDom_b in the sense of linear spaces(retained dimensions are those in DDom_a which are not in DDom_b) +// Computes the subtraction DDom_a - DDom_b in the sense of linear spaces(retained dimensions are those in DDom_a which are not in DDom_b) template KOKKOS_FUNCTION constexpr auto remove_dims_of( StridedDiscreteDomain const& DDom_a, @@ -525,7 +527,7 @@ KOKKOS_FUNCTION constexpr auto remove_dims_of( namespace detail { -// Checks if dimension of DDom_a is DDim1. If not, returns restriction to DDim2 of DDom_b. May not be usefull in its own, it helps for replace_dim_of +// Checks if dimension of DDom_a is DDim1. If not, returns restriction to DDim2 of DDom_b. May not be useful in its own, it helps for replace_dim_of template KOKKOS_FUNCTION constexpr std::conditional_t< std::is_same_v, diff --git a/include/ddc/transform_reduce.hpp b/include/ddc/transform_reduce.hpp index 6febb3d54..a57fa2311 100644 --- a/include/ddc/transform_reduce.hpp +++ b/include/ddc/transform_reduce.hpp @@ -9,7 +9,6 @@ #include "ddc/detail/macros.hpp" #include "ddc/discrete_domain.hpp" #include "ddc/discrete_element.hpp" -#include "ddc/strided_discrete_domain.hpp" namespace ddc { diff --git a/tests/chunk.cpp b/tests/chunk.cpp index 3512f5549..3b8fe1a89 100644 --- a/tests/chunk.cpp +++ b/tests/chunk.cpp @@ -468,101 +468,101 @@ TEST(Chunk2DTest, Cview) } } -// TEST(Chunk2DTest, SliceCoordX) -// { -// DElemX const slice_x_val(lbound_x + 1); - -// ChunkXY chunk(dom_x_y); -// ChunkXY const& chunk_cref = chunk; -// for (DElemX const ix : chunk.domain()) { -// for (DElemY const iy : chunk.domain()) { -// chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); -// } -// } - -// ddc::ChunkSpan const chunk_y = chunk_cref[slice_x_val]; -// EXPECT_TRUE( -// (std::is_same_v::layout_type, Kokkos::layout_right>)); -// EXPECT_EQ(chunk_y.extent(), chunk.extent()); -// for (DElemY const iy : chunk_cref.domain()) { -// // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy -// EXPECT_EQ(chunk_y(iy), chunk_cref(slice_x_val, iy)); -// } -// } - -// TEST(Chunk2DTest, SliceCoordY) -// { -// DElemY const slice_y_val(lbound_y + 1); - -// ChunkXY chunk(dom_x_y); -// ChunkXY const& chunk_cref = chunk; -// for (DElemX const ix : chunk.domain()) { -// for (DElemY const iy : chunk.domain()) { -// chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); -// } -// } - -// ddc::ChunkSpan const chunk_x = chunk_cref[slice_y_val]; -// EXPECT_TRUE( -// (std::is_same_v::layout_type, Kokkos::layout_stride>)); -// EXPECT_EQ(chunk_x.extent(), chunk.extent()); -// for (DElemX const ix : chunk_cref.domain()) { -// // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy -// EXPECT_EQ(chunk_x(ix), chunk_cref(ix, slice_y_val)); -// } -// } - -// TEST(Chunk2DTest, SliceDomainX) -// { -// DDomX const subdomain_x(lbound_x + 1, nelems_x - 2); - -// ChunkXY chunk(dom_x_y); -// ChunkXY const& chunk_cref = chunk; -// for (DElemX const ix : chunk.domain()) { -// for (DElemY const iy : chunk.domain()) { -// chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); -// } -// } - -// ddc::ChunkSpan const subchunk_x = chunk_cref[subdomain_x]; -// EXPECT_TRUE(( -// std::is_same_v::layout_type, Kokkos::layout_right>)); - -// EXPECT_EQ(subchunk_x.extent(), subdomain_x.size()); -// EXPECT_EQ(subchunk_x.extent(), chunk.domain().size()); -// for (DElemX const ix : subchunk_x.domain()) { -// for (DElemY const iy : subchunk_x.domain()) { -// // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy -// EXPECT_EQ(subchunk_x(ix, iy), chunk_cref(ix, iy)); -// } -// } -// } - -// TEST(Chunk2DTest, SliceDomainY) -// { -// DDomY const subdomain_y(lbound_y + 1, nelems_y - 2); - -// ChunkXY chunk(dom_x_y); -// ChunkXY const& chunk_cref = chunk; -// for (DElemX const ix : chunk.domain()) { -// for (DElemY const iy : chunk.domain()) { -// chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); -// } -// } -// ddc::ChunkSpan const subchunk_y = chunk_cref[subdomain_y]; -// EXPECT_TRUE((std::is_same_v< -// std::decay_t::layout_type, -// Kokkos::layout_stride>)); - -// EXPECT_EQ(subchunk_y.extent(), chunk.domain().size()); -// EXPECT_EQ(subchunk_y.extent(), subdomain_y.size()); -// for (DElemX const ix : subchunk_y.domain()) { -// for (DElemY const iy : subchunk_y.domain()) { -// // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy -// EXPECT_EQ(subchunk_y(ix, iy), chunk_cref(ix, iy)); -// } -// } -// } +TEST(Chunk2DTest, SliceCoordX) +{ + DElemX const slice_x_val(lbound_x + 1); + + ChunkXY chunk(dom_x_y); + ChunkXY const& chunk_cref = chunk; + for (DElemX const ix : chunk.domain()) { + for (DElemY const iy : chunk.domain()) { + chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); + } + } + + ddc::ChunkSpan const chunk_y = chunk_cref[slice_x_val]; + EXPECT_TRUE( + (std::is_same_v::layout_type, Kokkos::layout_right>)); + EXPECT_EQ(chunk_y.extent(), chunk.extent()); + for (DElemY const iy : chunk_cref.domain()) { + // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy + EXPECT_EQ(chunk_y(iy), chunk_cref(slice_x_val, iy)); + } +} + +TEST(Chunk2DTest, SliceCoordY) +{ + DElemY const slice_y_val(lbound_y + 1); + + ChunkXY chunk(dom_x_y); + ChunkXY const& chunk_cref = chunk; + for (DElemX const ix : chunk.domain()) { + for (DElemY const iy : chunk.domain()) { + chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); + } + } + + ddc::ChunkSpan const chunk_x = chunk_cref[slice_y_val]; + EXPECT_TRUE( + (std::is_same_v::layout_type, Kokkos::layout_stride>)); + EXPECT_EQ(chunk_x.extent(), chunk.extent()); + for (DElemX const ix : chunk_cref.domain()) { + // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy + EXPECT_EQ(chunk_x(ix), chunk_cref(ix, slice_y_val)); + } +} + +TEST(Chunk2DTest, SliceDomainX) +{ + DDomX const subdomain_x(lbound_x + 1, nelems_x - 2); + + ChunkXY chunk(dom_x_y); + ChunkXY const& chunk_cref = chunk; + for (DElemX const ix : chunk.domain()) { + for (DElemY const iy : chunk.domain()) { + chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); + } + } + + ddc::ChunkSpan const subchunk_x = chunk_cref[subdomain_x]; + EXPECT_TRUE(( + std::is_same_v::layout_type, Kokkos::layout_right>)); + + EXPECT_EQ(subchunk_x.extent(), subdomain_x.size()); + EXPECT_EQ(subchunk_x.extent(), chunk.domain().size()); + for (DElemX const ix : subchunk_x.domain()) { + for (DElemY const iy : subchunk_x.domain()) { + // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy + EXPECT_EQ(subchunk_x(ix, iy), chunk_cref(ix, iy)); + } + } +} + +TEST(Chunk2DTest, SliceDomainY) +{ + DDomY const subdomain_y(lbound_y + 1, nelems_y - 2); + + ChunkXY chunk(dom_x_y); + ChunkXY const& chunk_cref = chunk; + for (DElemX const ix : chunk.domain()) { + for (DElemY const iy : chunk.domain()) { + chunk(ix, iy) = 1. * ix.uid() + .001 * iy.uid(); + } + } + ddc::ChunkSpan const subchunk_y = chunk_cref[subdomain_y]; + EXPECT_TRUE((std::is_same_v< + std::decay_t::layout_type, + Kokkos::layout_stride>)); + + EXPECT_EQ(subchunk_y.extent(), chunk.domain().size()); + EXPECT_EQ(subchunk_y.extent(), subdomain_y.size()); + for (DElemX const ix : subchunk_y.domain()) { + for (DElemY const iy : subchunk_y.domain()) { + // we expect complete equality, not EXPECT_DOUBLE_EQ: these are copy + EXPECT_EQ(subchunk_y(ix, iy), chunk_cref(ix, iy)); + } + } +} TEST(Chunk2DTest, Deepcopy) { @@ -637,7 +637,7 @@ TEST(Chunk2DTest, Mirror) TEST(ChunkStridedDiscreteDomain, Constructor) { - ddc::StridedDiscreteDomain dom(lbound_x_y, nelems_x_y, DVectXY(10, 10)); + ddc::StridedDiscreteDomain const dom(lbound_x_y, nelems_x_y, DVectXY(10, 10)); ddc::Chunk chk("", dom, ddc::HostAllocator()); ddc::parallel_fill(chk.span_view(), 2); EXPECT_EQ(chk(lbound_x_y), 2); diff --git a/tests/storage_discrete_domain.cpp b/tests/storage_discrete_domain.cpp index 45c770c16..6696deeb6 100644 --- a/tests/storage_discrete_domain.cpp +++ b/tests/storage_discrete_domain.cpp @@ -59,25 +59,25 @@ using DVectZYX = ddc::DiscreteVector; using DDomZYX = ddc::StorageDiscreteDomain; DElemX constexpr lbound_x(50); -DVectX constexpr nelems_x(3); -DElemX constexpr sentinel_x(lbound_x + nelems_x); -DElemX constexpr ubound_x(sentinel_x - 1); +// DVectX constexpr nelems_x(3); +// DElemX constexpr sentinel_x(lbound_x + nelems_x); +// DElemX constexpr ubound_x(sentinel_x - 1); DElemY constexpr lbound_y(4); -DVectY constexpr nelems_y(10); -DElemY constexpr sentinel_y(lbound_y); -DElemY constexpr ubound_y(sentinel_y - 1); +// DVectY constexpr nelems_y(10); +// DElemY constexpr sentinel_y(lbound_y); +// DElemY constexpr ubound_y(sentinel_y - 1); -DElemZ constexpr lbound_z(7); -DVectZ constexpr nelems_z(15); +// DElemZ constexpr lbound_z(7); +// DVectZ constexpr nelems_z(15); -DElemXY constexpr lbound_x_y(lbound_x, lbound_y); -DVectXY constexpr nelems_x_y(nelems_x, nelems_y); -DElemXY constexpr ubound_x_y(ubound_x, ubound_y); +// DElemXY constexpr lbound_x_y(lbound_x, lbound_y); +// DVectXY constexpr nelems_x_y(nelems_x, nelems_y); +// DElemXY constexpr ubound_x_y(ubound_x, ubound_y); -DElemXZ constexpr lbound_x_z(lbound_x, lbound_z); -DVectXZ constexpr nelems_x_z(nelems_x, nelems_z); +// DElemXZ constexpr lbound_x_z(lbound_x, lbound_z); +// DVectXZ constexpr nelems_x_z(nelems_x, nelems_z); } // namespace DDC_HIP_5_7_ANONYMOUS_NAMESPACE_WORKAROUND(DISCRETE_DOMAIN_CPP) diff --git a/tests/strided_discrete_domain.cpp b/tests/strided_discrete_domain.cpp index a44904fe9..f4d8cb313 100644 --- a/tests/strided_discrete_domain.cpp +++ b/tests/strided_discrete_domain.cpp @@ -80,8 +80,8 @@ DVectXY constexpr nelems_x_y(nelems_x, nelems_y); DVectXY constexpr strides_x_y(strides_x, strides_y); DElemXY constexpr ubound_x_y(ubound_x, ubound_y); -DElemXZ constexpr lbound_x_z(lbound_x, lbound_z); -DVectXZ constexpr nelems_x_z(nelems_x, nelems_z); +// DElemXZ constexpr lbound_x_z(lbound_x, lbound_z); +// DVectXZ constexpr nelems_x_z(nelems_x, nelems_z); } // namespace DDC_HIP_5_7_ANONYMOUS_NAMESPACE_WORKAROUND(DISCRETE_DOMAIN_CPP) From e0845476187806a47f92e524bd70afd350c4791b Mon Sep 17 00:00:00 2001 From: Thomas Padioleau Date: Thu, 16 Jan 2025 18:43:23 +0100 Subject: [PATCH 09/12] Rename is_inside to contains --- include/ddc/chunk.hpp | 4 ++-- include/ddc/chunk_span.hpp | 2 +- include/ddc/discrete_domain.hpp | 6 +++--- include/ddc/storage_discrete_domain.hpp | 8 ++++---- include/ddc/strided_discrete_domain.hpp | 8 ++++---- tests/discrete_domain.cpp | 6 +++--- tests/storage_discrete_domain.cpp | 2 +- tests/strided_discrete_domain.cpp | 6 +++--- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/include/ddc/chunk.hpp b/include/ddc/chunk.hpp index a4137995a..b6115cfb9 100644 --- a/include/ddc/chunk.hpp +++ b/include/ddc/chunk.hpp @@ -449,7 +449,7 @@ class Chunk : public ChunkCommon SupportType::rank() == (0 + ... + DElems::size()), "Invalid number of dimensions"); static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); - assert(this->m_domain.is_inside(delems...)); + assert(this->m_domain.contains(delems...)); return DDC_MDSPAN_ACCESS_OP( this->m_allocation_mdspan, detail::array(this->m_domain.distance_from_front(delems...))); @@ -466,7 +466,7 @@ class Chunk : public ChunkCommon SupportType::rank() == (0 + ... + DElems::size()), "Invalid number of dimensions"); static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); - assert(this->m_domain.is_inside(delems...)); + assert(this->m_domain.contains(delems...)); return DDC_MDSPAN_ACCESS_OP( this->m_allocation_mdspan, detail::array(this->m_domain.distance_from_front(delems...))); diff --git a/include/ddc/chunk_span.hpp b/include/ddc/chunk_span.hpp index 0f25f6dd9..0594dc9e3 100644 --- a/include/ddc/chunk_span.hpp +++ b/include/ddc/chunk_span.hpp @@ -603,7 +603,7 @@ class ChunkSpan : public ChunkCommon && ...), "Expected DiscreteElements"); - assert(this->m_domain.is_inside(delems...)); + assert(this->m_domain.contains(delems...)); return DDC_MDSPAN_ACCESS_OP( this->m_allocation_mdspan, detail::array(this->m_domain.distance_from_front(delems...))); diff --git a/include/ddc/discrete_domain.hpp b/include/ddc/discrete_domain.hpp index 98eb37877..7b3beca6f 100644 --- a/include/ddc/discrete_domain.hpp +++ b/include/ddc/discrete_domain.hpp @@ -194,7 +194,7 @@ class DiscreteDomain } template - bool is_inside(DElems const&... delems) const noexcept + bool contains(DElems const&... delems) const noexcept { static_assert( sizeof...(DDims) == (0 + ... + DElems::size()), @@ -400,12 +400,12 @@ class DiscreteDomain<> return *this; } - static bool is_inside() noexcept + static bool contains() noexcept { return true; } - static bool is_inside(DiscreteElement<>) noexcept + static bool contains(DiscreteElement<>) noexcept { return true; } diff --git a/include/ddc/storage_discrete_domain.hpp b/include/ddc/storage_discrete_domain.hpp index 929197c33..79ba7fa32 100644 --- a/include/ddc/storage_discrete_domain.hpp +++ b/include/ddc/storage_discrete_domain.hpp @@ -274,7 +274,7 @@ class StorageDiscreteDomain // } template - KOKKOS_FUNCTION bool is_inside(DElems const&... delems) const noexcept + KOKKOS_FUNCTION bool contains(DElems const&... delems) const noexcept { static_assert( sizeof...(DDims) == (0 + ... + DElems::size()), @@ -296,7 +296,7 @@ class StorageDiscreteDomain sizeof...(DDims) == (0 + ... + DElems::size()), "Invalid number of dimensions"); static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); - assert(is_inside(delems...)); + assert(contains(delems...)); return DiscreteVector( (detail::lower_bound( get(m_views).data(), @@ -502,12 +502,12 @@ class StorageDiscreteDomain // return *this; // } -// static bool is_inside() noexcept +// static bool contains() noexcept // { // return true; // } -// static bool is_inside(DiscreteElement<>) noexcept +// static bool contains(DiscreteElement<>) noexcept // { // return true; // } diff --git a/include/ddc/strided_discrete_domain.hpp b/include/ddc/strided_discrete_domain.hpp index 74b3b4fec..2b2b793e9 100644 --- a/include/ddc/strided_discrete_domain.hpp +++ b/include/ddc/strided_discrete_domain.hpp @@ -219,7 +219,7 @@ class StridedDiscreteDomain // } template - KOKKOS_FUNCTION bool is_inside(DElems const&... delems) const noexcept + KOKKOS_FUNCTION bool contains(DElems const&... delems) const noexcept { static_assert( sizeof...(DDims) == (0 + ... + DElems::size()), @@ -251,7 +251,7 @@ class StridedDiscreteDomain sizeof...(DDims) == (0 + ... + DElems::size()), "Invalid number of dimensions"); static_assert((is_discrete_element_v && ...), "Expected DiscreteElements"); - assert(is_inside(delems...)); + assert(contains(delems...)); return DiscreteVector( ((DiscreteElement(take(delems...)) - DiscreteElement(m_element_begin)) @@ -455,12 +455,12 @@ class StridedDiscreteDomain<> return *this; } - static bool is_inside() noexcept + static bool contains() noexcept { return true; } - static bool is_inside(DiscreteElement<>) noexcept + static bool contains(DiscreteElement<>) noexcept { return true; } diff --git a/tests/discrete_domain.cpp b/tests/discrete_domain.cpp index 41b5908fc..f6baaf5f6 100644 --- a/tests/discrete_domain.cpp +++ b/tests/discrete_domain.cpp @@ -245,11 +245,11 @@ TEST(DiscreteDomainTest, Remove) DDomXY(dom_x_y.front() + DVectXY(1, 4), dom_x_y.extents() - DVectXY(2, 5))); } -TEST(DiscreteDomainTest, IsInside) +TEST(DiscreteDomainTest, Contains) { DDomXY const dom_x_y(lbound_x_y, nelems_x_y); - EXPECT_TRUE(dom_x_y.is_inside(lbound_x_y)); - EXPECT_FALSE(dom_x_y.is_inside(lbound_x_y + nelems_x_y)); + EXPECT_TRUE(dom_x_y.contains(lbound_x_y)); + EXPECT_FALSE(dom_x_y.contains(lbound_x_y + nelems_x_y)); } TEST(DiscreteDomainTest, DistanceFromFront) diff --git a/tests/storage_discrete_domain.cpp b/tests/storage_discrete_domain.cpp index 6696deeb6..22845b7a2 100644 --- a/tests/storage_discrete_domain.cpp +++ b/tests/storage_discrete_domain.cpp @@ -97,5 +97,5 @@ TEST(StorageDiscreteDomainTest, Constructor) EXPECT_EQ(dom_xy.distance_from_front(lbound_x + 2, lbound_y + 0), DVectXY(1, 0)); EXPECT_EQ(dom_xy.distance_from_front(lbound_x + 2, lbound_y + 2), DVectXY(1, 1)); EXPECT_EQ(dom_xy.distance_from_front(lbound_x + 2, lbound_y + 5), DVectXY(1, 2)); - EXPECT_FALSE(dom_xy.is_inside(lbound_x + 1, lbound_y + 0)); + EXPECT_FALSE(dom_xy.contains(lbound_x + 1, lbound_y + 0)); } diff --git a/tests/strided_discrete_domain.cpp b/tests/strided_discrete_domain.cpp index f4d8cb313..48217d45e 100644 --- a/tests/strided_discrete_domain.cpp +++ b/tests/strided_discrete_domain.cpp @@ -257,11 +257,11 @@ TEST(StridedDiscreteDomainTest, Remove) strides_x_y)); } -TEST(StridedDiscreteDomainTest, IsInside) +TEST(StridedDiscreteDomainTest, Contains) { DDomXY const dom_x_y(lbound_x_y, nelems_x_y, strides_x_y); - EXPECT_TRUE(dom_x_y.is_inside(lbound_x_y)); - EXPECT_FALSE(dom_x_y.is_inside(lbound_x_y + DVectXY(1, 1))); + EXPECT_TRUE(dom_x_y.contains(lbound_x_y)); + EXPECT_FALSE(dom_x_y.contains(lbound_x_y + DVectXY(1, 1))); } TEST(StridedDiscreteDomainTest, DistanceFromFront) From afaf0063d7bfd9e7b924e293458e7b261d61e2c2 Mon Sep 17 00:00:00 2001 From: Thomas Padioleau Date: Thu, 23 Jan 2025 22:05:50 +0100 Subject: [PATCH 10/12] Enable some commented code --- include/ddc/storage_discrete_domain.hpp | 580 ++++++++---------------- include/ddc/strided_discrete_domain.hpp | 40 +- 2 files changed, 198 insertions(+), 422 deletions(-) diff --git a/include/ddc/storage_discrete_domain.hpp b/include/ddc/storage_discrete_domain.hpp index 79ba7fa32..f66708536 100644 --- a/include/ddc/storage_discrete_domain.hpp +++ b/include/ddc/storage_discrete_domain.hpp @@ -141,20 +141,21 @@ class StorageDiscreteDomain /** Construct a StorageDiscreteDomain with Kokkos::View explicitly listing the discrete elements. * @param views list of Kokkos::View */ - explicit constexpr StorageDiscreteDomain( + explicit StorageDiscreteDomain( Kokkos::View*, Kokkos::SharedSpace> const&... views) { ((m_views[type_seq_rank_v>] = Kokkos::View(views.label(), views.size())), ...); + Kokkos::DefaultExecutionSpace const execution_space; ((Kokkos::Experimental::transform( "StorageDiscreteDomainCtor", - Kokkos::DefaultExecutionSpace(), + execution_space, views, m_views[type_seq_rank_v>], detail::GetUidFn())), ...); - Kokkos::fence("StorageDiscreteDomainCtor"); + execution_space.fence("StorageDiscreteDomainCtor"); } KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain(StorageDiscreteDomain const& x) = default; @@ -210,6 +211,11 @@ class StorageDiscreteDomain return discrete_vector_type(get(m_views).size()...); } + KOKKOS_FUNCTION constexpr auto discrete_elements() const noexcept + { + return m_views; + } + template KOKKOS_FUNCTION constexpr DiscreteVector extent() const noexcept { @@ -259,20 +265,6 @@ class StorageDiscreteDomain return m_views(get(dvect)...); } - // template - // KOKKOS_FUNCTION constexpr auto restrict_with( - // StorageDiscreteDomain const& odomain) const - // { - // assert(((uid(m_element_begin) <= uid(odomain.m_element_begin)) && ...)); - // assert(((uid(m_element_end) >= uid(odomain.m_element_end)) && ...)); - // const DiscreteVector myextents = extents(); - // const DiscreteVector oextents = odomain.extents(); - // return StorageDiscreteDomain( - // DiscreteElement( - // (uid_or(odomain.m_element_begin, uid(m_element_begin)))...), - // DiscreteVector((get_or(oextents, get(myextents)))...)); - // } - template KOKKOS_FUNCTION bool contains(DElems const&... delems) const noexcept { @@ -316,222 +308,192 @@ class StorageDiscreteDomain return !empty(); } - // template < - // std::size_t N = sizeof...(DDims), - // class DDim0 = std::enable_if_t>>> - // KOKKOS_FUNCTION auto begin() const - // { - // return StorageDiscreteDomainIterator(front(), m_strides); - // } - - // template < - // std::size_t N = sizeof...(DDims), - // class DDim0 = std::enable_if_t>>> - // KOKKOS_FUNCTION auto end() const - // { - // return StorageDiscreteDomainIterator< - // DDim0>(m_element_begin + m_extents * m_strides, m_strides); - // } - - // template < - // std::size_t N = sizeof...(DDims), - // class DDim0 = std::enable_if_t>>> - // KOKKOS_FUNCTION auto cbegin() const - // { - // return StorageDiscreteDomainIterator(front() s); - // } - - // template < - // std::size_t N = sizeof...(DDims), - // class DDim0 = std::enable_if_t>>> - // KOKKOS_FUNCTION auto cend() const - // { - // return StorageDiscreteDomainIterator(m_element_begin); - // } - - // template < - // std::size_t N = sizeof...(DDims), - // class = std::enable_if_t>>> - // KOKKOS_FUNCTION constexpr decltype(auto) operator[](std::size_t n) - // { - // return begin()[n]; - // } - - // template < - // std::size_t N = sizeof...(DDims), - // class = std::enable_if_t>>> - // KOKKOS_FUNCTION constexpr decltype(auto) operator[](std::size_t n) const - // { - // return begin()[n]; - // } + template < + std::size_t N = sizeof...(DDims), + class DDim0 = std::enable_if_t>>> + KOKKOS_FUNCTION auto begin() const + { + return Kokkos::Experimental::begin(get(m_views)); + } + + template < + std::size_t N = sizeof...(DDims), + class DDim0 = std::enable_if_t>>> + KOKKOS_FUNCTION auto end() const + { + return Kokkos::Experimental::end(get(m_views)); + } + + template < + std::size_t N = sizeof...(DDims), + class DDim0 = std::enable_if_t>>> + KOKKOS_FUNCTION auto cbegin() const + { + return Kokkos::Experimental::cbegin(get(m_views)); + } + + template < + std::size_t N = sizeof...(DDims), + class DDim0 = std::enable_if_t>>> + KOKKOS_FUNCTION auto cend() const + { + return Kokkos::Experimental::cend(get(m_views)); + } + + template < + std::size_t N = sizeof...(DDims), + class = std::enable_if_t>>> + KOKKOS_FUNCTION constexpr decltype(auto) operator[](std::size_t n) + { + return begin()[n]; + } + + template < + std::size_t N = sizeof...(DDims), + class = std::enable_if_t>>> + KOKKOS_FUNCTION constexpr decltype(auto) operator[](std::size_t n) const + { + return begin()[n]; + } }; -// template <> -// class StorageDiscreteDomain<> -// { -// template -// friend class StorageDiscreteDomain; - -// public: -// using discrete_element_type = DiscreteElement<>; - -// using discrete_vector_type = DiscreteVector<>; - -// static KOKKOS_FUNCTION constexpr std::size_t rank() -// { -// return 0; -// } - -// KOKKOS_DEFAULTED_FUNCTION constexpr StorageDiscreteDomain() = default; - -// // Construct a StorageDiscreteDomain from a reordered copy of `domain` -// template -// KOKKOS_FUNCTION constexpr explicit StorageDiscreteDomain( -// [[maybe_unused]] StorageDiscreteDomain const& domain) -// { -// } - -// /** Construct a StorageDiscreteDomain starting from element_begin with size points. -// * @param element_begin the lower bound in each direction -// * @param size the number of points in each direction -// */ -// KOKKOS_FUNCTION constexpr StorageDiscreteDomain( -// [[maybe_unused]] discrete_element_type const& element_begin, -// [[maybe_unused]] discrete_vector_type const& size) -// { -// } - -// KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain(StorageDiscreteDomain const& x) = default; - -// KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain(StorageDiscreteDomain&& x) = default; - -// KOKKOS_DEFAULTED_FUNCTION ~StorageDiscreteDomain() = default; - -// KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain& operator=(StorageDiscreteDomain const& x) -// = default; - -// KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain& operator=(StorageDiscreteDomain&& x) = default; - -// KOKKOS_FUNCTION constexpr bool operator==( -// [[maybe_unused]] StorageDiscreteDomain const& other) const -// { -// return true; -// } - -// #if !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201902L -// // In C++20, `a!=b` shall be automatically translated by the compiler to `!(a==b)` -// KOKKOS_FUNCTION constexpr bool operator!=(StorageDiscreteDomain const& other) const -// { -// return !(*this == other); -// } -// #endif - -// static KOKKOS_FUNCTION constexpr std::size_t size() -// { -// return 1; -// } - -// static KOKKOS_FUNCTION constexpr discrete_vector_type extents() noexcept -// { -// return {}; -// } - -// static KOKKOS_FUNCTION constexpr discrete_element_type front() noexcept -// { -// return {}; -// } - -// static KOKKOS_FUNCTION constexpr discrete_element_type back() noexcept -// { -// return {}; -// } - -// KOKKOS_FUNCTION constexpr StorageDiscreteDomain take_first( -// [[maybe_unused]] discrete_vector_type n) const -// { -// return *this; -// } - -// KOKKOS_FUNCTION constexpr StorageDiscreteDomain take_last( -// [[maybe_unused]] discrete_vector_type n) const -// { -// return *this; -// } - -// KOKKOS_FUNCTION constexpr StorageDiscreteDomain remove_first( -// [[maybe_unused]] discrete_vector_type n) const -// { -// return *this; -// } - -// KOKKOS_FUNCTION constexpr StorageDiscreteDomain remove_last( -// [[maybe_unused]] discrete_vector_type n) const -// { -// return *this; -// } - -// KOKKOS_FUNCTION constexpr StorageDiscreteDomain remove( -// [[maybe_unused]] discrete_vector_type n1, -// [[maybe_unused]] discrete_vector_type n2) const -// { -// return *this; -// } - -// KOKKOS_FUNCTION constexpr DiscreteElement<> operator()( -// DiscreteVector<> const& /* dvect */) const noexcept -// { -// return DiscreteElement<>(); -// } - -// #if defined(DDC_BUILD_DEPRECATED_CODE) -// template -// [[deprecated( -// "Use `restrict_with` " -// "instead")]] KOKKOS_FUNCTION constexpr StorageDiscreteDomain restrict(StorageDiscreteDomain const& -// odomain) -// const -// { -// return restrict_with(odomain); -// } -// #endif - -// template -// KOKKOS_FUNCTION constexpr StorageDiscreteDomain restrict_with( -// StorageDiscreteDomain const& /* odomain */) const -// { -// return *this; -// } - -// static bool contains() noexcept -// { -// return true; -// } - -// static bool contains(DiscreteElement<>) noexcept -// { -// return true; -// } - -// static DiscreteVector<> distance_from_front() noexcept -// { -// return DiscreteVector<>(); -// } - -// static DiscreteVector<> distance_from_front(DiscreteElement<>) noexcept -// { -// return DiscreteVector<>(); -// } - -// static KOKKOS_FUNCTION constexpr bool empty() noexcept -// { -// return false; -// } - -// KOKKOS_FUNCTION constexpr explicit operator bool() -// { -// return true; -// } -// }; +template <> +class StorageDiscreteDomain<> +{ + template + friend class StorageDiscreteDomain; + +public: + using discrete_element_type = DiscreteElement<>; + + using discrete_vector_type = DiscreteVector<>; + + static KOKKOS_FUNCTION constexpr std::size_t rank() + { + return 0; + } + + KOKKOS_DEFAULTED_FUNCTION constexpr StorageDiscreteDomain() = default; + + // Construct a StorageDiscreteDomain from a reordered copy of `domain` + template + KOKKOS_FUNCTION constexpr explicit StorageDiscreteDomain( + [[maybe_unused]] StorageDiscreteDomain const& domain) + { + } + + KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain(StorageDiscreteDomain const& x) = default; + + KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain(StorageDiscreteDomain&& x) = default; + + KOKKOS_DEFAULTED_FUNCTION ~StorageDiscreteDomain() = default; + + KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain& operator=(StorageDiscreteDomain const& x) + = default; + + KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomain& operator=(StorageDiscreteDomain&& x) = default; + + KOKKOS_FUNCTION constexpr bool operator==( + [[maybe_unused]] StorageDiscreteDomain const& other) const + { + return true; + } + +#if !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201902L + // In C++20, `a!=b` shall be automatically translated by the compiler to `!(a==b)` + KOKKOS_FUNCTION constexpr bool operator!=(StorageDiscreteDomain const& other) const + { + return !(*this == other); + } +#endif + + static KOKKOS_FUNCTION constexpr std::size_t size() + { + return 1; + } + + static KOKKOS_FUNCTION constexpr discrete_vector_type extents() noexcept + { + return {}; + } + + static KOKKOS_FUNCTION constexpr discrete_element_type front() noexcept + { + return {}; + } + + static KOKKOS_FUNCTION constexpr discrete_element_type back() noexcept + { + return {}; + } + + KOKKOS_FUNCTION constexpr StorageDiscreteDomain take_first( + [[maybe_unused]] discrete_vector_type n) const + { + return *this; + } + + KOKKOS_FUNCTION constexpr StorageDiscreteDomain take_last( + [[maybe_unused]] discrete_vector_type n) const + { + return *this; + } + + KOKKOS_FUNCTION constexpr StorageDiscreteDomain remove_first( + [[maybe_unused]] discrete_vector_type n) const + { + return *this; + } + + KOKKOS_FUNCTION constexpr StorageDiscreteDomain remove_last( + [[maybe_unused]] discrete_vector_type n) const + { + return *this; + } + + KOKKOS_FUNCTION constexpr StorageDiscreteDomain remove( + [[maybe_unused]] discrete_vector_type n1, + [[maybe_unused]] discrete_vector_type n2) const + { + return *this; + } + + KOKKOS_FUNCTION constexpr DiscreteElement<> operator()( + DiscreteVector<> const& /* dvect */) const noexcept + { + return {}; + } + + static bool contains() noexcept + { + return true; + } + + static bool contains(DiscreteElement<>) noexcept + { + return true; + } + + static DiscreteVector<> distance_from_front() noexcept + { + return {}; + } + + static DiscreteVector<> distance_from_front(DiscreteElement<>) noexcept + { + return {}; + } + + static KOKKOS_FUNCTION constexpr bool empty() noexcept + { + return false; + } + + KOKKOS_FUNCTION constexpr explicit operator bool() + { + return true; + } +}; template KOKKOS_FUNCTION constexpr StorageDiscreteDomain select( @@ -634,160 +596,4 @@ KOKKOS_FUNCTION constexpr DiscreteElement back( return DiscreteElement(StorageDiscreteDomain(domain).back()...); } -// template -// struct StorageDiscreteDomainIterator -// { -// private: -// DiscreteElement m_value = DiscreteElement(); - -// DiscreteVector m_stride = DiscreteVector(); - -// public: -// using iterator_category = std::random_access_iterator_tag; - -// using value_type = DiscreteElement; - -// using difference_type = std::ptrdiff_t; - -// KOKKOS_DEFAULTED_FUNCTION StorageDiscreteDomainIterator() = default; - -// KOKKOS_FUNCTION constexpr explicit StorageDiscreteDomainIterator( -// DiscreteElement value, -// DiscreteVector stride) -// : m_value(value) -// , m_stride(stride) -// { -// } - -// KOKKOS_FUNCTION constexpr DiscreteElement operator*() const noexcept -// { -// return m_value; -// } - -// KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator& operator++() -// { -// m_value.uid() += m_stride.value(); -// return *this; -// } - -// KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator operator++(int) -// { -// auto tmp = *this; -// ++*this; -// return tmp; -// } - -// KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator& operator--() -// { -// m_value.uid() -= m_stride.value(); -// return *this; -// } - -// KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator operator--(int) -// { -// auto tmp = *this; -// --*this; -// return tmp; -// } - -// KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator& operator+=(difference_type n) -// { -// if (n >= difference_type(0)) { -// m_value.uid() += static_cast(n) * m_stride.value(); -// } else { -// m_value.uid() -= static_cast(-n) * m_stride.value(); -// } -// return *this; -// } - -// KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator& operator-=(difference_type n) -// { -// if (n >= difference_type(0)) { -// m_value.uid() -= static_cast(n) * m_stride.value(); -// } else { -// m_value.uid() += static_cast(-n) * m_stride.value(); -// } -// return *this; -// } - -// KOKKOS_FUNCTION constexpr DiscreteElement operator[](difference_type n) const -// { -// return m_value + n * m_stride.value(); -// } - -// friend KOKKOS_FUNCTION constexpr bool operator==( -// StorageDiscreteDomainIterator const& xx, -// StorageDiscreteDomainIterator const& yy) -// { -// return xx.m_value == yy.m_value; -// } - -// #if !defined(__cpp_impl_three_way_comparison) || __cpp_impl_three_way_comparison < 201902L -// // In C++20, `a!=b` shall be automatically translated by the compiler to `!(a==b)` -// friend KOKKOS_FUNCTION constexpr bool operator!=( -// StorageDiscreteDomainIterator const& xx, -// StorageDiscreteDomainIterator const& yy) -// { -// return xx.m_value != yy.m_value; -// } -// #endif - -// friend KOKKOS_FUNCTION constexpr bool operator<( -// StorageDiscreteDomainIterator const& xx, -// StorageDiscreteDomainIterator const& yy) -// { -// return xx.m_value < yy.m_value; -// } - -// friend KOKKOS_FUNCTION constexpr bool operator>( -// StorageDiscreteDomainIterator const& xx, -// StorageDiscreteDomainIterator const& yy) -// { -// return yy < xx; -// } - -// friend KOKKOS_FUNCTION constexpr bool operator<=( -// StorageDiscreteDomainIterator const& xx, -// StorageDiscreteDomainIterator const& yy) -// { -// return !(yy < xx); -// } - -// friend KOKKOS_FUNCTION constexpr bool operator>=( -// StorageDiscreteDomainIterator const& xx, -// StorageDiscreteDomainIterator const& yy) -// { -// return !(xx < yy); -// } - -// friend KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator operator+( -// StorageDiscreteDomainIterator i, -// difference_type n) -// { -// return i += n; -// } - -// friend KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator operator+( -// difference_type n, -// StorageDiscreteDomainIterator i) -// { -// return i += n; -// } - -// friend KOKKOS_FUNCTION constexpr StorageDiscreteDomainIterator operator-( -// StorageDiscreteDomainIterator i, -// difference_type n) -// { -// return i -= n; -// } - -// friend KOKKOS_FUNCTION constexpr difference_type operator-( -// StorageDiscreteDomainIterator const& xx, -// StorageDiscreteDomainIterator const& yy) -// { -// return (yy.m_value > xx.m_value) ? (-static_cast(yy.m_value - xx.m_value)) -// : (xx.m_value - yy.m_value); -// } -// }; - } // namespace ddc diff --git a/include/ddc/strided_discrete_domain.hpp b/include/ddc/strided_discrete_domain.hpp index 2b2b793e9..a10b298e2 100644 --- a/include/ddc/strided_discrete_domain.hpp +++ b/include/ddc/strided_discrete_domain.hpp @@ -204,20 +204,6 @@ class StridedDiscreteDomain return m_element_begin + prod(dvect, m_strides); } - // template - // KOKKOS_FUNCTION constexpr auto restrict_with( - // StridedDiscreteDomain const& odomain) const - // { - // assert(((uid(m_element_begin) <= uid(odomain.m_element_begin)) && ...)); - // assert(((uid(m_element_end) >= uid(odomain.m_element_end)) && ...)); - // const DiscreteVector myextents = extents(); - // const DiscreteVector oextents = odomain.extents(); - // return StridedDiscreteDomain( - // DiscreteElement( - // (uid_or(odomain.m_element_begin, uid(m_element_begin)))...), - // DiscreteVector((get_or(oextents, get(myextents)))...)); - // } - template KOKKOS_FUNCTION bool contains(DElems const&... delems) const noexcept { @@ -347,10 +333,12 @@ class StridedDiscreteDomain<> /** Construct a StridedDiscreteDomain starting from element_begin with size points. * @param element_begin the lower bound in each direction * @param size the number of points in each direction + * @param strides the step between two elements */ KOKKOS_FUNCTION constexpr StridedDiscreteDomain( [[maybe_unused]] discrete_element_type const& element_begin, - [[maybe_unused]] discrete_vector_type const& size) + [[maybe_unused]] discrete_vector_type const& size, + [[maybe_unused]] discrete_vector_type const& strides) { } @@ -436,25 +424,6 @@ class StridedDiscreteDomain<> return {}; } -#if defined(DDC_BUILD_DEPRECATED_CODE) - template - [[deprecated( - "Use `restrict_with` " - "instead")]] KOKKOS_FUNCTION constexpr StridedDiscreteDomain restrict(StridedDiscreteDomain const& - odomain) - const - { - return restrict_with(odomain); - } -#endif - - template - KOKKOS_FUNCTION constexpr StridedDiscreteDomain restrict_with( - StridedDiscreteDomain const& /* odomain */) const - { - return *this; - } - static bool contains() noexcept { return true; @@ -492,7 +461,8 @@ KOKKOS_FUNCTION constexpr StridedDiscreteDomain select( { return StridedDiscreteDomain( DiscreteElement(domain.front()), - DiscreteElement(domain.extents())); + DiscreteVector(domain.extents()), + DiscreteVector(domain.strides())); } namespace detail { From 247846447cb23ee6b989fb156c772fdcd903b876 Mon Sep 17 00:00:00 2001 From: Thomas Padioleau Date: Sat, 25 Jan 2025 09:41:16 +0100 Subject: [PATCH 11/12] Support for discrete element slicing --- include/ddc/chunk.hpp | 26 ++++---- include/ddc/chunk_span.hpp | 86 +++++++++++++++---------- include/ddc/discrete_domain.hpp | 9 +++ include/ddc/storage_discrete_domain.hpp | 11 +++- include/ddc/strided_discrete_domain.hpp | 9 +++ 5 files changed, 93 insertions(+), 48 deletions(-) diff --git a/include/ddc/chunk.hpp b/include/ddc/chunk.hpp index b6115cfb9..1dde58531 100644 --- a/include/ddc/chunk.hpp +++ b/include/ddc/chunk.hpp @@ -424,19 +424,19 @@ class Chunk : public ChunkCommon return *this; } - // /// Slice out some dimensions - // template - // auto operator[](DiscreteElement const& slice_spec) const - // { - // return view_type(*this)[slice_spec]; - // } - - // /// Slice out some dimensions - // template - // auto operator[](DiscreteElement const& slice_spec) - // { - // return span_view()[slice_spec]; - // } + /// Slice out some dimensions + template + auto operator[](DiscreteElement const& slice_spec) const + { + return view_type(*this)[slice_spec]; + } + + /// Slice out some dimensions + template + auto operator[](DiscreteElement const& slice_spec) + { + return span_view()[slice_spec]; + } /** Element access using a list of DiscreteElement * @param delems discrete coordinates diff --git a/include/ddc/chunk_span.hpp b/include/ddc/chunk_span.hpp index 0594dc9e3..c2af0ff12 100644 --- a/include/ddc/chunk_span.hpp +++ b/include/ddc/chunk_span.hpp @@ -14,6 +14,7 @@ #include "ddc/chunk_common.hpp" #include "ddc/detail/kokkos.hpp" +#include "ddc/detail/type_seq.hpp" #include "ddc/discrete_domain.hpp" #include "ddc/discrete_element.hpp" @@ -434,17 +435,32 @@ class ChunkSpan : public ChunkCommon - KOKKOS_FUNCTION constexpr auto get_slicer_for(DiscreteElement const& c) const + KOKKOS_FUNCTION static constexpr auto get_slicer_for(DiscreteVector const& c) { DDC_IF_NVCC_THEN_PUSH_AND_SUPPRESS(implicit_return_from_non_void_function) if constexpr (in_tags_v>) { - return (uid(c) - front(this->m_domain).uid()); + return c.template get(); } else { return Kokkos::full_extent; } DDC_IF_NVCC_THEN_POP } + template + struct slicer; + + template + struct slicer> + { + template + KOKKOS_FUNCTION constexpr auto operator()( + allocation_mdspan_type const& span, + DiscreteVector const& c) const + { + return Kokkos::submdspan(span, get_slicer_for(c)...); + } + }; + public: /// Empty ChunkSpan KOKKOS_DEFAULTED_FUNCTION constexpr ChunkSpan() = default; @@ -559,38 +575,40 @@ class ChunkSpan : public ChunkCommon - // KOKKOS_FUNCTION constexpr auto operator[]( - // DiscreteElement const& slice_spec) const - // { - // auto subview = Kokkos::submdspan(allocation_mdspan(), get_slicer_for(slice_spec)...); - // using layout_type = typename decltype(subview)::layout_type; - // using extents_type = typename decltype(subview)::extents_type; - // using detail::TypeSeq; - // using OutTypeSeqDDims - // = type_seq_remove_t, TypeSeq>; - // using OutDDom = detail::convert_type_seq_to_discrete_domain_t; - // if constexpr ( - // std::is_same_v> - // || std::is_same_v>) { - // Kokkos::layout_stride::mapping const mapping_stride(subview.mapping()); - // Kokkos::mdspan const - // a(subview.data_handle(), mapping_stride); - // return ChunkSpan< - // ElementType, - // OutDDom, - // Kokkos::layout_stride, - // memory_space>(a, OutDDom(this->m_domain)); - // } else { - // return ChunkSpan< - // ElementType, - // OutDDom, - // layout_type, - // memory_space>(subview, OutDDom(this->m_domain)); - // } - // } + /** Slice out some dimensions + */ + template + KOKKOS_FUNCTION constexpr auto operator[]( + DiscreteElement const& slice_spec) const + { + slicer> const slicer; + auto subview + = slicer(this->allocation_mdspan(), this->m_domain.distance_from_front(slice_spec)); + using layout_type = typename decltype(subview)::layout_type; + using extents_type = typename decltype(subview)::extents_type; + using detail::TypeSeq; + using OutTypeSeqDDims + = type_seq_remove_t, TypeSeq>; + using OutDDom = typename detail::RebindDomain::type; + if constexpr ( + std::is_same_v> + || std::is_same_v>) { + Kokkos::layout_stride::mapping const mapping_stride(subview.mapping()); + Kokkos::mdspan const + a(subview.data_handle(), mapping_stride); + return ChunkSpan< + ElementType, + OutDDom, + Kokkos::layout_stride, + memory_space>(a, OutDDom(this->m_domain)); + } else { + return ChunkSpan< + ElementType, + OutDDom, + layout_type, + memory_space>(subview, OutDDom(this->m_domain)); + } + } /** Element access using a list of DiscreteElement * @param delems discrete elements diff --git a/include/ddc/discrete_domain.hpp b/include/ddc/discrete_domain.hpp index 7b3beca6f..59d419516 100644 --- a/include/ddc/discrete_domain.hpp +++ b/include/ddc/discrete_domain.hpp @@ -46,6 +46,15 @@ struct ToTypeSeq> using type = TypeSeq; }; +template +struct RebindDomain; + +template +struct RebindDomain, detail::TypeSeq> +{ + using type = DiscreteDomain; +}; + } // namespace detail template diff --git a/include/ddc/storage_discrete_domain.hpp b/include/ddc/storage_discrete_domain.hpp index f66708536..80b9c556d 100644 --- a/include/ddc/storage_discrete_domain.hpp +++ b/include/ddc/storage_discrete_domain.hpp @@ -49,6 +49,15 @@ struct ToTypeSeq> using type = TypeSeq; }; +template +struct RebindDomain; + +template +struct RebindDomain, detail::TypeSeq> +{ + using type = StorageDiscreteDomain; +}; + template KOKKOS_FUNCTION bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2) { @@ -134,7 +143,7 @@ class StorageDiscreteDomain class... DDoms, class = std::enable_if_t<(is_storage_discrete_domain_v && ...)>> KOKKOS_FUNCTION constexpr explicit StorageDiscreteDomain(DDoms const&... domains) - : m_views(domains...) + : m_views(domains.m_views...) { } diff --git a/include/ddc/strided_discrete_domain.hpp b/include/ddc/strided_discrete_domain.hpp index a10b298e2..e3134bc97 100644 --- a/include/ddc/strided_discrete_domain.hpp +++ b/include/ddc/strided_discrete_domain.hpp @@ -46,6 +46,15 @@ struct ToTypeSeq> using type = TypeSeq; }; +template +struct RebindDomain; + +template +struct RebindDomain, detail::TypeSeq> +{ + using type = StridedDiscreteDomain; +}; + } // namespace detail template From ce3cda40c59504c6d6da94f22a65e54dadb1dbd0 Mon Sep 17 00:00:00 2001 From: Thomas Padioleau Date: Sat, 25 Jan 2025 10:06:29 +0100 Subject: [PATCH 12/12] Support remove_dims_of --- include/ddc/discrete_domain.hpp | 13 +++-- include/ddc/storage_discrete_domain.hpp | 14 ++++++ include/ddc/strided_discrete_domain.hpp | 14 ++++++ tests/strided_discrete_domain.cpp | 63 +++++++++++++------------ 4 files changed, 66 insertions(+), 38 deletions(-) diff --git a/include/ddc/discrete_domain.hpp b/include/ddc/discrete_domain.hpp index 59d419516..96bb33c00 100644 --- a/include/ddc/discrete_domain.hpp +++ b/include/ddc/discrete_domain.hpp @@ -507,10 +507,10 @@ KOKKOS_FUNCTION constexpr auto remove_dims_of( //! Remove the dimensions DDimsB from DDom_a //! @param[in] DDom_a The discrete domain on which to remove dimensions //! @return The discrete domain without DDimsB dimensions -template -KOKKOS_FUNCTION constexpr auto remove_dims_of(DDomA const& DDom_a) noexcept +template +KOKKOS_FUNCTION constexpr auto remove_dims_of(DiscreteDomain const& DDom_a) noexcept { - using TagSeqA = typename detail::ToTypeSeq::type; + using TagSeqA = detail::TypeSeq; using TagSeqB = detail::TypeSeq; using type_seq_r = type_seq_remove_t; @@ -564,10 +564,9 @@ KOKKOS_FUNCTION constexpr auto replace_dim_of( // Replace dimensions from a domain type template -using replace_dim_of_t - = decltype(replace_dim_of< - DDim1, - DDim2>(std::declval(), std::declval>())); +using replace_dim_of_t = decltype(replace_dim_of( + std::declval(), + std::declval>::type>())); template diff --git a/include/ddc/storage_discrete_domain.hpp b/include/ddc/storage_discrete_domain.hpp index 80b9c556d..17c9699c0 100644 --- a/include/ddc/storage_discrete_domain.hpp +++ b/include/ddc/storage_discrete_domain.hpp @@ -543,6 +543,20 @@ KOKKOS_FUNCTION constexpr auto remove_dims_of( return detail::convert_type_seq_to_storage_discrete_domain_t(DDom_a); } +//! Remove the dimensions DDimsB from DDom_a +//! @param[in] DDom_a The discrete domain on which to remove dimensions +//! @return The discrete domain without DDimsB dimensions +template +KOKKOS_FUNCTION constexpr auto remove_dims_of( + StorageDiscreteDomain const& DDom_a) noexcept +{ + using TagSeqA = detail::TypeSeq; + using TagSeqB = detail::TypeSeq; + + using type_seq_r = type_seq_remove_t; + return detail::convert_type_seq_to_storage_discrete_domain_t(DDom_a); +} + namespace detail { // Checks if dimension of DDom_a is DDim1. If not, returns restriction to DDim2 of DDom_b. May not be useful in its own, it helps for replace_dim_of diff --git a/include/ddc/strided_discrete_domain.hpp b/include/ddc/strided_discrete_domain.hpp index e3134bc97..9b4295c2b 100644 --- a/include/ddc/strided_discrete_domain.hpp +++ b/include/ddc/strided_discrete_domain.hpp @@ -504,6 +504,20 @@ KOKKOS_FUNCTION constexpr auto remove_dims_of( return detail::convert_type_seq_to_strided_discrete_domain_t(DDom_a); } +//! Remove the dimensions DDimsB from DDom_a +//! @param[in] DDom_a The discrete domain on which to remove dimensions +//! @return The discrete domain without DDimsB dimensions +template +KOKKOS_FUNCTION constexpr auto remove_dims_of( + StridedDiscreteDomain const& DDom_a) noexcept +{ + using TagSeqA = detail::TypeSeq; + using TagSeqB = detail::TypeSeq; + + using type_seq_r = type_seq_remove_t; + return detail::convert_type_seq_to_strided_discrete_domain_t(DDom_a); +} + namespace detail { // Checks if dimension of DDom_a is DDim1. If not, returns restriction to DDim2 of DDom_b. May not be useful in its own, it helps for replace_dim_of diff --git a/tests/strided_discrete_domain.cpp b/tests/strided_discrete_domain.cpp index 48217d45e..94846a2a1 100644 --- a/tests/strided_discrete_domain.cpp +++ b/tests/strided_discrete_domain.cpp @@ -80,8 +80,9 @@ DVectXY constexpr nelems_x_y(nelems_x, nelems_y); DVectXY constexpr strides_x_y(strides_x, strides_y); DElemXY constexpr ubound_x_y(ubound_x, ubound_y); -// DElemXZ constexpr lbound_x_z(lbound_x, lbound_z); -// DVectXZ constexpr nelems_x_z(nelems_x, nelems_z); +DElemXZ constexpr lbound_x_z(lbound_x, lbound_z); +DVectXZ constexpr nelems_x_z(nelems_x, nelems_z); +DVectXZ constexpr strides_x_z(strides_x, strides_z); } // namespace DDC_HIP_5_7_ANONYMOUS_NAMESPACE_WORKAROUND(DISCRETE_DOMAIN_CPP) @@ -178,37 +179,37 @@ TEST(StridedDiscreteDomainTest, RangeFor) } } -// TEST(StridedDiscreteDomainTest, DiffEmpty) -// { -// DDomX const dom_x = DDomX(); -// ddc::remove_dims_of_t const subdomain1 = ddc::remove_dims_of(dom_x, dom_x); -// ddc::remove_dims_of_t const subdomain2 = ddc::remove_dims_of(dom_x); -// EXPECT_EQ(subdomain1, ddc::DiscreteDomain<>()); -// EXPECT_EQ(subdomain2, ddc::DiscreteDomain<>()); -// } +TEST(StridedDiscreteDomainTest, DiffEmpty) +{ + DDomX const dom_x = DDomX(); + ddc::remove_dims_of_t const subdomain1 = ddc::remove_dims_of(dom_x, dom_x); + ddc::remove_dims_of_t const subdomain2 = ddc::remove_dims_of(dom_x); + EXPECT_EQ(subdomain1, ddc::StridedDiscreteDomain<>()); + EXPECT_EQ(subdomain2, ddc::StridedDiscreteDomain<>()); +} -// TEST(StridedDiscreteDomainTest, Diff) -// { -// DDomX const dom_x = DDomX(); -// DDomXY const dom_x_y = DDomXY(); -// DDomZY const dom_z_y = DDomZY(); -// ddc::remove_dims_of_t const subdomain1 -// = ddc::remove_dims_of(dom_x_y, dom_z_y); -// ddc::remove_dims_of_t const subdomain2 -// = ddc::remove_dims_of(dom_x_y); -// EXPECT_EQ(subdomain1, dom_x); -// EXPECT_EQ(subdomain2, dom_x); -// } +TEST(StridedDiscreteDomainTest, Diff) +{ + DDomX const dom_x = DDomX(); + DDomXY const dom_x_y = DDomXY(); + DDomZY const dom_z_y = DDomZY(); + ddc::remove_dims_of_t const subdomain1 + = ddc::remove_dims_of(dom_x_y, dom_z_y); + ddc::remove_dims_of_t const subdomain2 + = ddc::remove_dims_of(dom_x_y); + EXPECT_EQ(subdomain1, dom_x); + EXPECT_EQ(subdomain2, dom_x); +} -// TEST(StridedDiscreteDomainTest, Replace) -// { -// DDomXY const dom_x_y(lbound_x_y, nelems_x_y); -// DDomZ const dom_z(lbound_z, nelems_z); -// DDomXZ const dom_x_z(lbound_x_z, nelems_x_z); -// ddc::replace_dim_of_t const subdomain -// = ddc::replace_dim_of(dom_x_y, dom_z); -// EXPECT_EQ(subdomain, dom_x_z); -// } +TEST(StridedDiscreteDomainTest, Replace) +{ + DDomXY const dom_x_y(lbound_x_y, nelems_x_y, strides_x_y); + DDomZ const dom_z(lbound_z, nelems_z, strides_z); + DDomXZ const dom_x_z(lbound_x_z, nelems_x_z, strides_x_z); + ddc::replace_dim_of_t const subdomain + = ddc::replace_dim_of(dom_x_y, dom_z); + EXPECT_EQ(subdomain, dom_x_z); +} TEST(StridedDiscreteDomainTest, TakeFirst)