From 83a441c43a296751dd1ac1c3fb9f6c05a4911cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franz=20P=C3=B6schel?= Date: Tue, 25 Apr 2023 11:13:42 +0200 Subject: [PATCH] Testing Only test if ADIOS2 version at least 2.9 --- test/ParallelIOTest.cpp | 156 ++++++++++++++++++++++++++++++++++++++++ test/SerialIOTest.cpp | 144 +++++++++++++++++++++++++++++++++++++ 2 files changed, 300 insertions(+) diff --git a/test/ParallelIOTest.cpp b/test/ParallelIOTest.cpp index a82a300b0e..44d09151f8 100644 --- a/test/ParallelIOTest.cpp +++ b/test/ParallelIOTest.cpp @@ -1778,4 +1778,160 @@ TEST_CASE("unavailable_backend", "[core][parallel]") } #endif } + +void joined_dim(std::string const &ext) +{ + using type = float; + using patchType = uint64_t; + constexpr size_t patches_per_rank = 5; + constexpr size_t length_of_patch = 10; + + int size{-1}; + int rank{-1}; + MPI_Comm_size(MPI_COMM_WORLD, &size); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + { + Series s( + "../samples/joinedDimParallel." + ext, + Access::CREATE, + MPI_COMM_WORLD); + std::vector> writeFrom(patches_per_rank); + + auto it = s.writeIterations()[100]; + + Dataset numParticlesDS( + determineDatatype(), {Dataset::JOINED_DIMENSION}); + auto numParticles = + it.particles["e"] + .particlePatches["numParticles"][RecordComponent::SCALAR]; + auto numParticlesOffset = + it.particles["e"] + .particlePatches["numParticlesOffset"][RecordComponent::SCALAR]; + numParticles.resetDataset(numParticlesDS); + numParticlesOffset.resetDataset(numParticlesDS); + + auto patchOffset = it.particles["e"].particlePatches["offset"]["x"]; + auto patchExtent = it.particles["e"].particlePatches["extent"]["x"]; + Dataset particlePatchesDS( + determineDatatype(), {Dataset::JOINED_DIMENSION}); + patchOffset.resetDataset(particlePatchesDS); + patchExtent.resetDataset(particlePatchesDS); + + float start_value = rank * patches_per_rank * length_of_patch; + for (size_t i = 0; i < 5; ++i) + { + writeFrom[i] = UniquePtrWithLambda( + new type[length_of_patch], + [](auto const *ptr) { delete[] ptr; }); + std::iota( + writeFrom[i].get(), + writeFrom[i].get() + 10, + start_value + length_of_patch * i); + patchOffset.store(start_value + length_of_patch * i); + } + + auto epx = it.particles["e"]["position"]["x"]; + Dataset ds(determineDatatype(), {Dataset::JOINED_DIMENSION}); + epx.resetDataset(ds); + + size_t counter = 0; + for (auto &chunk : writeFrom) + { + epx.storeChunk(std::move(chunk), {}, {length_of_patch}); + numParticles.store(length_of_patch); + /* + * For the sake of the test case, we know that the + * numParticlesOffset has this value. In general, the purpose of the + * joined array is that we don't need to know these values, so the + * specification of particle patches is somewhat difficult. + */ + numParticlesOffset.store( + start_value + counter++ * length_of_patch); + patchExtent.store(10); + } + writeFrom.clear(); + it.close(); + s.close(); + } + + { + Series s( + "../samples/joinedDimParallel." + ext, + Access::READ_ONLY, + MPI_COMM_WORLD); + auto it = s.iterations[100]; + auto e = it.particles["e"]; + + auto particleData = e["position"]["x"].loadChunk(); + auto numParticles = + e.particlePatches["numParticles"][RecordComponent::SCALAR] + .load(); + auto numParticlesOffset = + e.particlePatches["numParticlesOffset"][RecordComponent::SCALAR] + .load(); + auto patchOffset = e.particlePatches["offset"]["x"].load(); + auto patchExtent = e.particlePatches["extent"]["x"].load(); + + it.close(); + + // check validity of particle patches + auto numPatches = + e.particlePatches["numParticlesOffset"][RecordComponent::SCALAR] + .getExtent()[0]; + REQUIRE( + e.particlePatches["numParticles"][RecordComponent::SCALAR] + .getExtent()[0] == numPatches); + for (size_t i = 0; i < numPatches; ++i) + { + for (size_t j = 0; j < numParticles.get()[i]; ++j) + { + REQUIRE( + patchOffset.get()[i] <= + particleData.get()[numParticlesOffset.get()[i] + j]); + REQUIRE( + particleData.get()[numParticlesOffset.get()[i] + j] < + patchOffset.get()[i] + patchExtent.get()[i]); + } + } + + /* + * Check that joined array joins early writes before later writes from + * the same rank + */ + for (size_t i = 0; i < size * length_of_patch * patches_per_rank; ++i) + { + REQUIRE(float(i) == particleData.get()[i]); + } + for (size_t i = 0; i < size * patches_per_rank; ++i) + { + REQUIRE(length_of_patch * i == numParticlesOffset.get()[i]); + REQUIRE(type(length_of_patch * i) == patchOffset.get()[i]); + } + } +} + +TEST_CASE("joined_dim", "[parallel]") +{ +#if 100000000 * ADIOS2_VERSION_MAJOR + 1000000 * ADIOS2_VERSION_MINOR + \ + 10000 * ADIOS2_VERSION_PATCH + 100 * ADIOS2_VERSION_TWEAK >= \ + 209000000 + constexpr char const *supportsJoinedDims[] = {"bp", "bp4", "bp5"}; +#else + // no zero-size arrays + std::vector supportsJoinedDims; +#endif + for (auto const &t : testedFileExtensions()) + { + for (auto const supported : supportsJoinedDims) + { + if (t == supported) + { + joined_dim(t); + break; + } + } + } +} + #endif // openPMD_HAVE_ADIOS2 && openPMD_HAVE_MPI diff --git a/test/SerialIOTest.cpp b/test/SerialIOTest.cpp index 7f126e104f..7d093c6b06 100644 --- a/test/SerialIOTest.cpp +++ b/test/SerialIOTest.cpp @@ -7276,3 +7276,147 @@ TEST_CASE("groupbased_read_write", "[serial]") groupbased_read_write("toml"); } } + +void joined_dim(std::string const &ext) +{ + using type = float; + using patchType = uint64_t; + constexpr size_t patches_per_rank = 5; + constexpr size_t length_of_patch = 10; + + { + Series s("../samples/joinedDimParallel." + ext, Access::CREATE); + std::vector> writeFrom(patches_per_rank); + + auto it = s.writeIterations()[100]; + + Dataset numParticlesDS( + determineDatatype(), {Dataset::JOINED_DIMENSION}); + auto numParticles = + it.particles["e"] + .particlePatches["numParticles"][RecordComponent::SCALAR]; + auto numParticlesOffset = + it.particles["e"] + .particlePatches["numParticlesOffset"][RecordComponent::SCALAR]; + numParticles.resetDataset(numParticlesDS); + numParticlesOffset.resetDataset(numParticlesDS); + + auto patchOffset = it.particles["e"].particlePatches["offset"]["x"]; + auto patchExtent = it.particles["e"].particlePatches["extent"]["x"]; + Dataset particlePatchesDS( + determineDatatype(), {Dataset::JOINED_DIMENSION}); + patchOffset.resetDataset(particlePatchesDS); + patchExtent.resetDataset(particlePatchesDS); + + for (size_t i = 0; i < 5; ++i) + { + writeFrom[i] = UniquePtrWithLambda( + new type[length_of_patch], + [](auto const *ptr) { delete[] ptr; }); + std::iota( + writeFrom[i].get(), + writeFrom[i].get() + 10, + length_of_patch * i); + patchOffset.store(length_of_patch * i); + } + + auto epx = it.particles["e"]["position"]["x"]; + Dataset ds(determineDatatype(), {Dataset::JOINED_DIMENSION}); + epx.resetDataset(ds); + + size_t counter = 0; + for (auto &chunk : writeFrom) + { + epx.storeChunk(std::move(chunk), {}, {length_of_patch}); + numParticles.store(length_of_patch); + /* + * For the sake of the test case, we know that the + * numParticlesOffset has this value. In general, the purpose of the + * joined array is that we don't need to know these values, so the + * specification of particle patches is somewhat difficult. + */ + numParticlesOffset.store(counter++ * length_of_patch); + patchExtent.store(10); + } + writeFrom.clear(); + it.close(); + s.close(); + } + + { + Series s("../samples/joinedDimParallel." + ext, Access::READ_ONLY); + auto it = s.iterations[100]; + auto e = it.particles["e"]; + + auto particleData = e["position"]["x"].loadChunk(); + auto numParticles = + e.particlePatches["numParticles"][RecordComponent::SCALAR] + .load(); + auto numParticlesOffset = + e.particlePatches["numParticlesOffset"][RecordComponent::SCALAR] + .load(); + auto patchOffset = e.particlePatches["offset"]["x"].load(); + auto patchExtent = e.particlePatches["extent"]["x"].load(); + + it.close(); + + // check validity of particle patches + auto numPatches = + e.particlePatches["numParticlesOffset"][RecordComponent::SCALAR] + .getExtent()[0]; + REQUIRE( + e.particlePatches["numParticles"][RecordComponent::SCALAR] + .getExtent()[0] == numPatches); + for (size_t i = 0; i < numPatches; ++i) + { + for (size_t j = 0; j < numParticles.get()[i]; ++j) + { + REQUIRE( + patchOffset.get()[i] <= + particleData.get()[numParticlesOffset.get()[i] + j]); + REQUIRE( + particleData.get()[numParticlesOffset.get()[i] + j] < + patchOffset.get()[i] + patchExtent.get()[i]); + } + } + + /* + * Check that: + * 1. Joined array joins writes from lower ranks before higher ranks + * 2. Joined array joins early writes before later writes from the same + * rank + */ + for (size_t i = 0; i < length_of_patch * patches_per_rank; ++i) + { + REQUIRE(float(i) == particleData.get()[i]); + } + for (size_t i = 0; i < patches_per_rank; ++i) + { + REQUIRE(length_of_patch * i == numParticlesOffset.get()[i]); + REQUIRE(type(length_of_patch * i) == patchOffset.get()[i]); + } + } +} + +TEST_CASE("joined_dim", "[serial]") +{ +#if 100000000 * ADIOS2_VERSION_MAJOR + 1000000 * ADIOS2_VERSION_MINOR + \ + 10000 * ADIOS2_VERSION_PATCH + 100 * ADIOS2_VERSION_TWEAK >= \ + 209000000 + constexpr char const *supportsJoinedDims[] = {"bp", "bp4", "bp5"}; +#else + // no zero-size arrays + std::vector supportsJoinedDims; +#endif + for (auto const &t : testedFileExtensions()) + { + for (auto const supported : supportsJoinedDims) + { + if (t == supported) + { + joined_dim(t); + break; + } + } + } +}