From 01bb043bf5c0985e0b5f9491059e8e682e3278e7 Mon Sep 17 00:00:00 2001 From: Alexander Liemen <47395086+aliemen@users.noreply.github.com> Date: Sun, 24 May 2026 15:39:18 +0200 Subject: [PATCH] Re-implement field write api from #506, but template view directly (no auto in parameter) --- src/Field/BareField.h | 21 +++++++++++ src/Field/BareField.hpp | 19 +++++++++- src/Utility/ViewUtils.h | 48 +++++++++++++++++++++++++ unit_tests/BareField/BareField.cpp | 57 ++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 1 deletion(-) diff --git a/src/Field/BareField.h b/src/Field/BareField.h index 33908ef53..6ff4a5e01 100644 --- a/src/Field/BareField.h +++ b/src/Field/BareField.h @@ -199,6 +199,27 @@ namespace ippl { */ void write(Inform& inf) const; + /*! + * Print the rank local BareField. + * @param out stream + */ + void write_as_list(std::ostream& out = std::cout) const; + + /*! + * Print the rank local BareField. + * @param inf Inform object + */ + void write_as_list(Inform& inf) const; + + /*! + * Stream opreator to print the rank local BareField. + */ + friend std::ostream& operator<<(std::ostream& out, + const BareField& field) { + field.write_as_list(out); + return out; + } + T sum(int nghost = 0) const; T max(int nghost = 0) const; T min(int nghost = 0) const; diff --git a/src/Field/BareField.hpp b/src/Field/BareField.hpp index 511a4ee3d..695576af3 100644 --- a/src/Field/BareField.hpp +++ b/src/Field/BareField.hpp @@ -2,6 +2,9 @@ // Class BareField // A BareField consists of multple LFields and represents a field. // +#ifndef IPPL_BARE_FIELD_HPP +#define IPPL_BARE_FIELD_HPP + #include "Ippl.h" #include @@ -13,6 +16,8 @@ #include "Utility/Inform.h" #include "Utility/IpplInfo.h" + +#include "BareField.h" namespace Kokkos { template struct reduction_identity> { @@ -191,7 +196,7 @@ namespace ippl { template void BareField::write(std::ostream& out) const { Kokkos::fence(); - detail::write(dview_m, out); + detail::write(dview_m, out); } template @@ -199,6 +204,17 @@ namespace ippl { write(inf.getDestination()); } + template + void BareField::write_as_list(std::ostream& out) const { + Kokkos::fence(); + detail::write_as_list(dview_m, out); + } + + template + void BareField::write_as_list(Inform& inf) const { + write_as_list(inf.getDestination()); + } + #define DefineReduction(fun, name, op, MPI_Op) \ template \ T BareField::name(int nghost) const { \ @@ -223,3 +239,4 @@ namespace ippl { DefineReduction(Prod, prod, valL *= myVal, std::multiplies) } // namespace ippl +#endif // IPPL_BARE_FIELD_HPP diff --git a/src/Utility/ViewUtils.h b/src/Utility/ViewUtils.h index f03ae5a21..6ef5e8906 100644 --- a/src/Utility/ViewUtils.h +++ b/src/Utility/ViewUtils.h @@ -8,6 +8,8 @@ #include +#include + #include "Types/ViewTypes.h" namespace ippl { @@ -99,6 +101,52 @@ namespace ippl { }); } + /*! + * Recursive implementation to write a view in list format to output stream + * @tparam Dim + * + * @param view + * @param out stream + */ + template + void write_as_list_impl(const View& view, std::ostream& out = std::cout) { + auto N = view.extent(0); + out << "["; + for (std::size_t i = 0; i < N; ++i) { + if constexpr (Dim == 1) { + out << view(i); + } else { + auto make_subview = [&](std::index_sequence) { + return Kokkos::subview(view, i, (static_cast(Is), Kokkos::ALL)...); + }; + + auto subview = make_subview(std::make_index_sequence()); + write_as_list_impl(subview, out); + } + if (i != N - 1) + out << ", "; + } + out << "]"; + }; + + /*! + * Writes a view to an output stream in folded list format + * @tparam T view data type + * @tparam Dim view dimension + * @tparam Properties further template parameters of Kokkos + * + * @param view to write + * @param out stream + */ + template + void write_as_list(const typename ViewType::view_type& view, + std::ostream& out = std::cout) { + auto hview = + Kokkos::create_mirror_view_and_copy(Kokkos::DefaultHostExecutionSpace(), view); + + write_as_list_impl(hview, out); + } + /*! * Utility function for shrinkView */ diff --git a/unit_tests/BareField/BareField.cpp b/unit_tests/BareField/BareField.cpp index fe439dc6f..0bcb09fc5 100644 --- a/unit_tests/BareField/BareField.cpp +++ b/unit_tests/BareField/BareField.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "Utility/TypeUtils.h" @@ -259,6 +260,62 @@ TYPED_TEST(BareFieldTest, AllFuncs) { }); } +TYPED_TEST(BareFieldTest, write_as_list) { + using T = typename TestFixture::value_type; + using ExecSpace = typename TestFixture::exec_space; + constexpr static unsigned Dim = TestFixture::dim; + + if constexpr (Dim == 2) { + // not implemented for MPI Communicators greater than two + if (ippl::Comm->size() <= 2) { + // 2D, 2x2 Field + ippl::FieldLayout layout(ippl::Comm->getCommunicator(), + ippl::NDIndex(ippl::Vector(2)), + std::array{true}); + ippl::BareField field(layout, 0); + + auto view = field.getView(); + auto hview = + Kokkos::create_mirror_view_and_copy(Kokkos::DefaultHostExecutionSpace(), view); + + if (layout.comm.size() == 1) { + hview(0, 0) = 1; + hview(0, 1) = 2; + hview(1, 0) = 3; + hview(1, 1) = 4; + } else if (layout.comm.size() == 2) { + if (layout.comm.rank() == 0) { + hview(0, 0) = 1; + hview(0, 1) = 2; + } + if (layout.comm.rank() == 1) { + hview(0, 0) = 3; + hview(0, 1) = 4; + } + } + + Kokkos::deep_copy(view, hview); + + std::ostringstream ss; + field.write_as_list(ss); + + if (layout.comm.size() == 1) { + ASSERT_STREQ(ss.str().c_str(), "[[1, 2], [3, 4]]"); + } else if (layout.comm.size() == 2) { + if (layout.comm.rank() == 0) { + ASSERT_STREQ(ss.str().c_str(), "[[1, 2]]"); + } + if (layout.comm.rank() == 1) { + ASSERT_STREQ(ss.str().c_str(), "[[3, 4]]"); + } + } else + GTEST_SKIP(); + } else + GTEST_SKIP(); + } else + GTEST_SKIP(); +} + int main(int argc, char* argv[]) { int success = 1; ippl::initialize(argc, argv);