From b1ba8be6f514e92a4f0beb89f1b31fc4adf5ace6 Mon Sep 17 00:00:00 2001 From: Stephane Del Pino <stephane.delpino44@gmail.com> Date: Sun, 25 Aug 2024 22:56:29 +0200 Subject: [PATCH] Add tests for ItemValueVariant checkpointing --- .../checkpointing/ReadItemValueVariant.cpp | 2 + tests/CMakeLists.txt | 1 + tests/test_checkpointing_Connectivity.cpp | 1 - tests/test_checkpointing_ItemValueVariant.cpp | 319 ++++++++++++++++++ 4 files changed, 322 insertions(+), 1 deletion(-) create mode 100644 tests/test_checkpointing_ItemValueVariant.cpp diff --git a/src/utils/checkpointing/ReadItemValueVariant.cpp b/src/utils/checkpointing/ReadItemValueVariant.cpp index 8ebb98225..8775dc177 100644 --- a/src/utils/checkpointing/ReadItemValueVariant.cpp +++ b/src/utils/checkpointing/ReadItemValueVariant.cpp @@ -54,7 +54,9 @@ readItemValueVariant(const HighFive::Group& item_value_variant_group) p_item_value = std::make_shared<ItemValueVariant>( readItemValue<TinyMatrix<3>, item_type>(item_value_variant_group, "values", connectivity)); } else { + // LCOV_EXCL_START throw UnexpectedError("unexpected discrete function data type: " + data_type); + // LCOV_EXCL_STOP } return p_item_value; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d96587863..549a9d4e2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -165,6 +165,7 @@ if(PUGS_HAS_HDF5) test_checkpointing_HFTypes.cpp test_checkpointing_ItemArray.cpp test_checkpointing_ItemValue.cpp + test_checkpointing_ItemValueVariant.cpp test_checkpointing_OStream.cpp test_checkpointing_IBoundaryDescriptor.cpp test_checkpointing_IBoundaryConditionDescriptor.cpp diff --git a/tests/test_checkpointing_Connectivity.cpp b/tests/test_checkpointing_Connectivity.cpp index 6334973bf..dcb6bb146 100644 --- a/tests/test_checkpointing_Connectivity.cpp +++ b/tests/test_checkpointing_Connectivity.cpp @@ -47,7 +47,6 @@ TEST_CASE("checkpointing_Connectivity", "[utils/checkpointing]") { HighFive::Group checkpoint_group_0 = file.createGroup("checkpoint_0"); HighFive::Group checkpoint_group_1 = file.createGroup("checkpoint_1"); - HighFive::Group useless_group; { // Write auto mesh_1d = MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<1>>(); diff --git a/tests/test_checkpointing_ItemValueVariant.cpp b/tests/test_checkpointing_ItemValueVariant.cpp new file mode 100644 index 000000000..08ed52a93 --- /dev/null +++ b/tests/test_checkpointing_ItemValueVariant.cpp @@ -0,0 +1,319 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <utils/Messenger.hpp> + +#include <language/utils/DataHandler.hpp> +#include <language/utils/EmbeddedData.hpp> +#include <mesh/ItemValueVariant.hpp> +#include <mesh/Mesh.hpp> +#include <utils/GlobalVariableManager.hpp> +#include <utils/checkpointing/ReadItemValueVariant.hpp> +#include <utils/checkpointing/ResumingData.hpp> +#include <utils/checkpointing/WriteItemValueVariant.hpp> + +#include <MeshDataBaseForTests.hpp> +#include <checkpointing_Connectivity_utilities.hpp> + +#include <filesystem> + +// clazy:excludeall=non-pod-global-static + +namespace test_only +{ + +template <typename DataType, ItemType item_type> +PUGS_INLINE void +check_is_same(const ItemValue<DataType, item_type>& reference, const EmbeddedData& e_read_data) +{ + auto same_value = [](const auto& a, const auto& b) -> bool { + bool same = true; + for (size_t i = 0; i < a.size(); ++i) { + same &= (a[i] == b[i]); + } + return parallel::allReduceAnd(same); + }; + + REQUIRE_NOTHROW(dynamic_cast<const DataHandler<const ItemValueVariant>&>(e_read_data.get())); + + std::shared_ptr<const ItemValueVariant> p_new_data_v = + dynamic_cast<const DataHandler<const ItemValueVariant>&>(e_read_data.get()).data_ptr(); + + using ItemTypeT = ItemValue<const DataType, item_type>; + + ItemTypeT read_data = p_new_data_v->get<ItemTypeT>(); + + switch (reference.connectivity_ptr()->dimension()) { + case 1: { + REQUIRE(test_only::isSameConnectivity(dynamic_cast<const Connectivity<1>&>(*reference.connectivity_ptr()), + dynamic_cast<const Connectivity<1>&>(*read_data.connectivity_ptr()))); + break; + } + case 2: { + REQUIRE(test_only::isSameConnectivity(dynamic_cast<const Connectivity<2>&>(*reference.connectivity_ptr()), + dynamic_cast<const Connectivity<2>&>(*read_data.connectivity_ptr()))); + break; + } + case 3: { + REQUIRE(test_only::isSameConnectivity(dynamic_cast<const Connectivity<3>&>(*reference.connectivity_ptr()), + dynamic_cast<const Connectivity<3>&>(*read_data.connectivity_ptr()))); + break; + } + default: { + throw UnexpectedError("invalid connectivity dimension"); + } + } + + REQUIRE(same_value(reference.arrayView(), read_data.arrayView())); +} + +} // namespace test_only + +TEST_CASE("checkpointing_ItemValueVariant", "[utils/checkpointing]") +{ + std::string tmp_dirname; + { + { + if (parallel::rank() == 0) { + tmp_dirname = [&]() -> std::string { + std::string temp_filename = std::filesystem::temp_directory_path() / "pugs_checkpointing_XXXXXX"; + return std::string{mkdtemp(&temp_filename[0])}; + }(); + } + parallel::broadcast(tmp_dirname, 0); + } + std::filesystem::path path = tmp_dirname; + const std::string filename = path / "checkpoint.h5"; + + HighFive::FileAccessProps fapl; + fapl.add(HighFive::MPIOFileAccess{MPI_COMM_WORLD, MPI_INFO_NULL}); + fapl.add(HighFive::MPIOCollectiveMetadata{}); + HighFive::File file = HighFive::File(filename, HighFive::File::Truncate, fapl); + + const size_t initial_connectivity_id = GlobalVariableManager::instance().getConnectivityId(); + + SECTION("Connectivity") + { + using R1 = TinyVector<1>; + using R2 = TinyVector<2>; + using R3 = TinyVector<3>; + using R1x1 = TinyMatrix<1>; + using R2x2 = TinyMatrix<2>; + using R3x3 = TinyMatrix<3>; + + HighFive::Group checkpoint_group = file.createGroup("checkpoint"); + HighFive::Group symbol_table_group = checkpoint_group.createGroup("symbol_table"); + + auto mesh_1d = MeshDataBaseForTests::get().unordered1DMesh()->get<Mesh<1>>(); + + CellValue<bool> cell_B_1d{mesh_1d->connectivity()}; + for (CellId cell_id = 0; cell_id < mesh_1d->numberOfCells(); ++cell_id) { + cell_B_1d[cell_id] = (std::rand() / (RAND_MAX / mesh_1d->numberOfCells())) % 2; + } + + CellValue<uint64_t> cell_N_1d{mesh_1d->connectivity()}; + for (CellId cell_id = 0; cell_id < mesh_1d->numberOfCells(); ++cell_id) { + cell_N_1d[cell_id] = (std::rand() / (RAND_MAX / mesh_1d->numberOfCells())); + } + + NodeValue<int64_t> node_Z_1d{mesh_1d->connectivity()}; + for (NodeId node_id = 0; node_id < mesh_1d->numberOfNodes(); ++node_id) { + node_Z_1d[node_id] = 100 * (std::rand() - RAND_MAX / 2.) / (RAND_MAX / mesh_1d->numberOfNodes()); + } + + NodeValue<double> node_R_1d{mesh_1d->connectivity()}; + for (NodeId node_id = 0; node_id < mesh_1d->numberOfNodes(); ++node_id) { + node_R_1d[node_id] = std::rand() / (1. * RAND_MAX / mesh_1d->numberOfNodes()); + } + + CellValue<R1> cell_R1_1d{mesh_1d->connectivity()}; + for (CellId cell_id = 0; cell_id < mesh_1d->numberOfCells(); ++cell_id) { + cell_R1_1d[cell_id] = R1{std::rand() / (1. * RAND_MAX / mesh_1d->numberOfCells())}; + } + + NodeValue<R2> node_R2_1d{mesh_1d->connectivity()}; + for (NodeId node_id = 0; node_id < mesh_1d->numberOfNodes(); ++node_id) { + node_R2_1d[node_id] = R2{std::rand() / (1. * RAND_MAX / mesh_1d->numberOfNodes()), + std::rand() / (1. * RAND_MAX / mesh_1d->numberOfNodes())}; + } + + auto mesh_2d = MeshDataBaseForTests::get().hybrid2DMesh()->get<Mesh<2>>(); + + FaceValue<R3> face_R3_2d{mesh_2d->connectivity()}; + for (FaceId face_id = 0; face_id < mesh_2d->numberOfFaces(); ++face_id) { + face_R3_2d[face_id] = R3{std::rand() / (1. * RAND_MAX / mesh_2d->numberOfFaces()), + std::rand() / (1. * RAND_MAX / mesh_2d->numberOfFaces()), + std::rand() / (1. * RAND_MAX / mesh_2d->numberOfFaces())}; + } + + NodeValue<R2x2> node_R2x2_2d{mesh_2d->connectivity()}; + for (NodeId node_id = 0; node_id < mesh_2d->numberOfNodes(); ++node_id) { + node_R2x2_2d[node_id] = R2x2{std::rand() / (1. * RAND_MAX / mesh_2d->numberOfNodes()), + std::rand() / (1. * RAND_MAX / mesh_2d->numberOfNodes()), + std::rand() / (1. * RAND_MAX / mesh_2d->numberOfNodes()), + std::rand() / (1. * RAND_MAX / mesh_2d->numberOfNodes())}; + } + + auto mesh_3d = MeshDataBaseForTests::get().hybrid3DMesh()->get<Mesh<3>>(); + + EdgeValue<R3> edge_R3_3d{mesh_3d->connectivity()}; + for (EdgeId edge_id = 0; edge_id < mesh_3d->numberOfEdges(); ++edge_id) { + edge_R3_3d[edge_id] = R3{std::rand() / (1. * RAND_MAX / mesh_3d->numberOfEdges()), + std::rand() / (1. * RAND_MAX / mesh_3d->numberOfEdges()), + std::rand() / (1. * RAND_MAX / mesh_3d->numberOfEdges())}; + } + + FaceValue<R1x1> face_R1x1_3d{mesh_3d->connectivity()}; + for (FaceId face_id = 0; face_id < mesh_3d->numberOfFaces(); ++face_id) { + face_R1x1_3d[face_id] = R1x1{std::rand() / (1. * RAND_MAX / mesh_3d->numberOfFaces())}; + } + + NodeValue<R3x3> node_R3x3_3d{mesh_3d->connectivity()}; + for (NodeId node_id = 0; node_id < mesh_3d->numberOfNodes(); ++node_id) { + node_R3x3_3d[node_id] = R3x3{std::rand() / (1. * RAND_MAX / mesh_3d->numberOfNodes()), + std::rand() / (1. * RAND_MAX / mesh_3d->numberOfNodes()), + std::rand() / (1. * RAND_MAX / mesh_3d->numberOfNodes()), + std::rand() / (1. * RAND_MAX / mesh_3d->numberOfNodes()), + std::rand() / (1. * RAND_MAX / mesh_3d->numberOfNodes()), + std::rand() / (1. * RAND_MAX / mesh_3d->numberOfNodes()), + std::rand() / (1. * RAND_MAX / mesh_3d->numberOfNodes()), + std::rand() / (1. * RAND_MAX / mesh_3d->numberOfNodes()), + std::rand() / (1. * RAND_MAX / mesh_3d->numberOfNodes())}; + } + + { // Write + using DataHandlerT = DataHandler<const ItemValueVariant>; + + auto new_connectivity_1d = test_only::duplicateConnectivity(mesh_1d->connectivity()); + + CellValue<const bool> cell_B_1d_new{*new_connectivity_1d, cell_B_1d.arrayView()}; + NodeValue<const int64_t> node_Z_1d_new{*new_connectivity_1d, node_Z_1d.arrayView()}; + CellValue<const uint64_t> cell_N_1d_new{*new_connectivity_1d, cell_N_1d.arrayView()}; + NodeValue<const double> node_R_1d_new{*new_connectivity_1d, node_R_1d.arrayView()}; + CellValue<const R1> cell_R1_1d_new{*new_connectivity_1d, cell_R1_1d.arrayView()}; + NodeValue<const R2> node_R2_1d_new{*new_connectivity_1d, node_R2_1d.arrayView()}; + + checkpointing::writeItemValueVariant("cell_B_1d", + EmbeddedData{std::make_shared<DataHandlerT>( + std::make_shared<const ItemValueVariant>(cell_B_1d_new))}, + file, checkpoint_group, symbol_table_group); + + checkpointing::writeItemValueVariant("cell_N_1d", + EmbeddedData{std::make_shared<DataHandlerT>( + std::make_shared<const ItemValueVariant>(cell_N_1d_new))}, + file, checkpoint_group, symbol_table_group); + + checkpointing::writeItemValueVariant("node_Z_1d", + EmbeddedData{std::make_shared<DataHandlerT>( + std::make_shared<const ItemValueVariant>(node_Z_1d_new))}, + file, checkpoint_group, symbol_table_group); + + checkpointing::writeItemValueVariant("node_R_1d", + EmbeddedData{std::make_shared<DataHandlerT>( + std::make_shared<const ItemValueVariant>(node_R_1d_new))}, + file, checkpoint_group, symbol_table_group); + + checkpointing::writeItemValueVariant("cell_R1_1d", + EmbeddedData{std::make_shared<DataHandlerT>( + std::make_shared<const ItemValueVariant>(cell_R1_1d_new))}, + file, checkpoint_group, symbol_table_group); + + checkpointing::writeItemValueVariant("node_R2_1d", + EmbeddedData{std::make_shared<DataHandlerT>( + std::make_shared<const ItemValueVariant>(node_R2_1d_new))}, + file, checkpoint_group, symbol_table_group); + + auto new_connectivity_2d = test_only::duplicateConnectivity(mesh_2d->connectivity()); + + FaceValue<const R3> face_R3_2d_new{*new_connectivity_2d, face_R3_2d.arrayView()}; + NodeValue<const R2x2> node_R2x2_2d_new{*new_connectivity_2d, node_R2x2_2d.arrayView()}; + + checkpointing::writeItemValueVariant("face_R3_2d", + EmbeddedData{std::make_shared<DataHandlerT>( + std::make_shared<const ItemValueVariant>(face_R3_2d_new))}, + file, checkpoint_group, symbol_table_group); + + checkpointing::writeItemValueVariant("node_R2x2_2d", + EmbeddedData{std::make_shared<DataHandlerT>( + std::make_shared<const ItemValueVariant>(node_R2x2_2d_new))}, + file, checkpoint_group, symbol_table_group); + + auto new_connectivity_3d = test_only::duplicateConnectivity(mesh_3d->connectivity()); + + EdgeValue<const R3> edge_R3_3d_new{*new_connectivity_3d, edge_R3_3d.arrayView()}; + FaceValue<const R1x1> face_R1x1_3d_new{*new_connectivity_3d, face_R1x1_3d.arrayView()}; + NodeValue<const R3x3> node_R3x3_3d_new{*new_connectivity_3d, node_R3x3_3d.arrayView()}; + + checkpointing::writeItemValueVariant("edge_R3_3d", + EmbeddedData{std::make_shared<DataHandlerT>( + std::make_shared<const ItemValueVariant>(edge_R3_3d_new))}, + file, checkpoint_group, symbol_table_group); + + checkpointing::writeItemValueVariant("face_R1x1_3d", + EmbeddedData{std::make_shared<DataHandlerT>( + std::make_shared<const ItemValueVariant>(face_R1x1_3d_new))}, + file, checkpoint_group, symbol_table_group); + + checkpointing::writeItemValueVariant("node_R3x3_3d", + EmbeddedData{std::make_shared<DataHandlerT>( + std::make_shared<const ItemValueVariant>(node_R3x3_3d_new))}, + file, checkpoint_group, symbol_table_group); + + HighFive::Group global_variables_group = checkpoint_group.createGroup("singleton/global_variables"); + global_variables_group.createAttribute("connectivity_id", + GlobalVariableManager::instance().getConnectivityId()); + global_variables_group.createAttribute("mesh_id", GlobalVariableManager::instance().getMeshId()); + } + + // reset to reuse after resuming + GlobalVariableManager::instance().setConnectivityId(initial_connectivity_id); + + file.flush(); + + checkpointing::ResumingData::create(); + checkpointing::ResumingData::instance().readData(checkpoint_group, nullptr); + + GlobalVariableManager::instance().setConnectivityId(initial_connectivity_id); + { // Read + auto e_cell_B_1d = checkpointing::readItemValueVariant("cell_B_1d", symbol_table_group); + test_only::check_is_same(cell_B_1d, e_cell_B_1d); + + auto e_cell_N_1d = checkpointing::readItemValueVariant("cell_N_1d", symbol_table_group); + test_only::check_is_same(cell_N_1d, e_cell_N_1d); + + auto e_node_Z_1d = checkpointing::readItemValueVariant("node_Z_1d", symbol_table_group); + test_only::check_is_same(node_Z_1d, e_node_Z_1d); + + auto e_node_R_1d = checkpointing::readItemValueVariant("node_R_1d", symbol_table_group); + test_only::check_is_same(node_R_1d, e_node_R_1d); + + auto e_cell_R1_1d = checkpointing::readItemValueVariant("cell_R1_1d", symbol_table_group); + test_only::check_is_same(cell_R1_1d, e_cell_R1_1d); + + auto e_node_R2_1d = checkpointing::readItemValueVariant("node_R2_1d", symbol_table_group); + test_only::check_is_same(node_R2_1d, e_node_R2_1d); + + auto e_face_R3_2d = checkpointing::readItemValueVariant("face_R3_2d", symbol_table_group); + test_only::check_is_same(face_R3_2d, e_face_R3_2d); + + auto e_node_R2x2_2d = checkpointing::readItemValueVariant("node_R2x2_2d", symbol_table_group); + test_only::check_is_same(node_R2x2_2d, e_node_R2x2_2d); + + auto e_edge_R3_3d = checkpointing::readItemValueVariant("edge_R3_3d", symbol_table_group); + test_only::check_is_same(edge_R3_3d, e_edge_R3_3d); + + auto e_face_R1x1_3d = checkpointing::readItemValueVariant("face_R1x1_3d", symbol_table_group); + test_only::check_is_same(face_R1x1_3d, e_face_R1x1_3d); + + auto e_node_R3x3_3d = checkpointing::readItemValueVariant("node_R3x3_3d", symbol_table_group); + test_only::check_is_same(node_R3x3_3d, e_node_R3x3_3d); + } + checkpointing::ResumingData::destroy(); + } + } + + parallel::barrier(); + if (parallel::rank() == 0) { + std::filesystem::remove_all(std::filesystem::path{tmp_dirname}); + } +} -- GitLab