Skip to content

Commit d645301

Browse files
committed
Main implementation + testing
1 parent bdda98b commit d645301

4 files changed

Lines changed: 167 additions & 15 deletions

File tree

include/openPMD/IO/ADIOS/ADIOS2IOHandler.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
#include "openPMD/auxiliary/JSON_internal.hpp"
3535
#include "openPMD/backend/Writable.hpp"
3636
#include "openPMD/config.hpp"
37-
#include <stdexcept>
3837

3938
#if openPMD_HAVE_ADIOS2
4039
#include <adios2.h>
@@ -432,6 +431,10 @@ class ADIOS2IOHandlerImpl
432431
}
433432
// TODO leave this check to ADIOS?
434433
adios2::Dims shape = var.Shape();
434+
if (shape == adios2::Dims{adios2::LocalValueDim})
435+
{
436+
return var;
437+
}
435438
auto actualDim = shape.size();
436439
{
437440
auto requiredDim = extent.size();

src/IO/ADIOS/ADIOS2File.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "openPMD/IO/ADIOS/ADIOS2File.hpp"
2323
#include "openPMD/IO/ADIOS/ADIOS2IOHandler.hpp"
2424
#include "openPMD/auxiliary/Environment.hpp"
25+
#include <adios2/common/ADIOSTypes.h>
2526

2627
#if openPMD_USE_VERIFY
2728
#define VERIFY(CONDITION, TEXT) \
@@ -86,7 +87,21 @@ void WriteDataset::call(ADIOS2File &ba, detail::BufferedPut &bp)
8687
adios2::Variable<T> var = ba.m_impl->verifyDataset<T>(
8788
bp.param.offset, bp.param.extent, ba.m_IO, bp.name);
8889

89-
ba.getEngine().Put(var, ptr);
90+
if (var.Shape() == adios2::Dims{adios2::LocalValue})
91+
{
92+
if (bp.param.extent != Extent{1})
93+
{
94+
throw error::OperationUnsupportedInBackend(
95+
"ADIOS2",
96+
"Can only write a single element to LocalValue "
97+
"variables (extent == Extent{1}).");
98+
}
99+
ba.getEngine().Put(var, *ptr);
100+
}
101+
else
102+
{
103+
ba.getEngine().Put(var, ptr);
104+
}
90105
}
91106
else if constexpr (std::is_same_v<
92107
ptr_type,
@@ -143,7 +158,21 @@ struct RunUniquePtrPut
143158
auto ptr = static_cast<T const *>(bufferedPut.data.get());
144159
adios2::Variable<T> var = ba.m_impl->verifyDataset<T>(
145160
bufferedPut.offset, bufferedPut.extent, ba.m_IO, bufferedPut.name);
146-
ba.getEngine().Put(var, ptr);
161+
if (var.Shape() == adios2::Dims{adios2::LocalValue})
162+
{
163+
if (bufferedPut.extent != Extent{1})
164+
{
165+
throw error::OperationUnsupportedInBackend(
166+
"ADIOS2",
167+
"Can only write a single element to LocalValue "
168+
"variables (extent == Extent{1}).");
169+
}
170+
ba.getEngine().Put(var, *ptr);
171+
}
172+
else
173+
{
174+
ba.getEngine().Put(var, ptr);
175+
}
147176
}
148177

149178
static constexpr char const *errorMsg = "RunUniquePtrPut";

src/IO/ADIOS/ADIOS2IOHandler.cpp

Lines changed: 90 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "openPMD/IterationEncoding.hpp"
3131
#include "openPMD/auxiliary/Environment.hpp"
3232
#include "openPMD/auxiliary/Filesystem.hpp"
33+
#include "openPMD/auxiliary/JSON_internal.hpp"
3334
#include "openPMD/auxiliary/Mpi.hpp"
3435
#include "openPMD/auxiliary/StringManip.hpp"
3536
#include "openPMD/auxiliary/TypeTraits.hpp"
@@ -213,7 +214,8 @@ void ADIOS2IOHandlerImpl::init(
213214
{
214215
"adios2": {
215216
"dataset": {
216-
"operators": null
217+
"operators": null,
218+
"shape": null
217219
}
218220
}
219221
})";
@@ -739,6 +741,12 @@ void ADIOS2IOHandlerImpl::createPath(
739741
}
740742
}
741743

744+
enum class Shape
745+
{
746+
GlobalArray,
747+
LocalValue
748+
};
749+
742750
void ADIOS2IOHandlerImpl::createDataset(
743751
Writable *writable, const Parameter<Operation::CREATE_DATASET> &parameters)
744752
{
@@ -798,15 +806,52 @@ void ADIOS2IOHandlerImpl::createDataset(
798806
}();
799807

800808
std::vector<ParameterizedOperator> operators;
801-
if (config.json().contains("adios2"))
802-
{
803-
json::TracingJSON datasetConfig(config["adios2"]);
804-
auto datasetOperators = getOperators(datasetConfig);
809+
810+
Shape arrayShape = Shape::GlobalArray;
811+
[&]() {
812+
if (!config.json().contains("adios2"))
813+
{
814+
return;
815+
};
816+
json::TracingJSON adios2Config(config["adios2"]);
817+
auto datasetOperators = getOperators(adios2Config);
805818
if (datasetOperators.has_value())
806819
{
807820
operators = std::move(*datasetOperators);
808821
}
809-
}
822+
if (!adios2Config.json().contains("dataset"))
823+
{
824+
return;
825+
}
826+
auto datasetConfig = adios2Config["dataset"];
827+
if (!datasetConfig.json().contains("shape"))
828+
{
829+
return;
830+
}
831+
auto maybe_shape =
832+
json::asLowerCaseStringDynamic(datasetConfig["shape"].json());
833+
if (!maybe_shape.has_value())
834+
{
835+
throw error::BackendConfigSchema(
836+
{"adios2", "dataset", "shape"},
837+
"Must be convertible to string type.");
838+
}
839+
auto const &shape = *maybe_shape;
840+
if (shape == "global_array")
841+
{
842+
arrayShape = Shape::GlobalArray;
843+
}
844+
else if (shape == "local_value")
845+
{
846+
arrayShape = Shape::LocalValue;
847+
}
848+
else
849+
{
850+
throw error::BackendConfigSchema(
851+
{"adios2", "dataset", "shape"},
852+
"Unknown value: '" + shape + "'.");
853+
}
854+
}();
810855

811856
#if 0
812857
std::cout << "Operations for '" << varName << "':";
@@ -823,12 +868,41 @@ void ADIOS2IOHandlerImpl::createDataset(
823868
"Warning: parts of the backend configuration for ADIOS2 dataset '" +
824869
varName + "' remain unused:\n");
825870

826-
// cast from openPMD::Extent to adios2::Dims
827-
adios2::Dims shape(parameters.extent.begin(), parameters.extent.end());
828-
if (auto jd = parameters.joinedDimension; jd.has_value())
829-
{
830-
shape[jd.value()] = adios2::JoinedDim;
831-
}
871+
adios2::Dims shape = [&]() {
872+
switch (arrayShape)
873+
{
874+
875+
case Shape::GlobalArray: {
876+
// cast from openPMD::Extent to adios2::Dims
877+
adios2::Dims res(
878+
parameters.extent.begin(), parameters.extent.end());
879+
if (auto jd = parameters.joinedDimension; jd.has_value())
880+
{
881+
res[jd.value()] = adios2::JoinedDim;
882+
}
883+
return res;
884+
}
885+
case Shape::LocalValue: {
886+
int required_size = 1;
887+
#if openPMD_HAVE_MPI
888+
if (m_communicator.has_value())
889+
{
890+
MPI_Comm_size(*m_communicator, &required_size);
891+
}
892+
#endif
893+
if (parameters.extent !=
894+
Extent{Extent::value_type(required_size)})
895+
{
896+
throw error::OperationUnsupportedInBackend(
897+
"ADIOS2",
898+
"Shape for local value array must be a 1D array "
899+
"equivalent to the MPI size.");
900+
}
901+
return adios2::Dims{adios2::LocalValueDim};
902+
}
903+
}
904+
throw std::runtime_error("Unreachable!");
905+
}();
832906

833907
auto &fileData = getFileData(file, IfFileNotOpen::ThrowError);
834908

@@ -1125,6 +1199,10 @@ namespace detail
11251199
auto &engine = ba.getEngine();
11261200
adios2::Variable<T> variable = impl->verifyDataset<T>(
11271201
params.offset, params.extent, IO, varName);
1202+
if (variable.Shape() == adios2::Dims{adios2::LocalValueDim})
1203+
{
1204+
params.out->backendManagedBuffer = false;
1205+
}
11281206
adios2::Dims offset(params.offset.begin(), params.offset.end());
11291207
adios2::Dims extent(params.extent.begin(), params.extent.end());
11301208
variable.SetSelection({std::move(offset), std::move(extent)});

test/ParallelIOTest.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,48 @@ void available_chunks_test(std::string const &file_ending)
422422
auto E_x = it0.meshes["E"]["x"];
423423
E_x.resetDataset({Datatype::INT, {mpi_size, 4}});
424424
E_x.storeChunk(data, {mpi_rank, 0}, {1, 4});
425+
426+
auto electrons = it0.particles["e"].particlePatches;
427+
auto numParticles = electrons["numParticles"];
428+
auto numParticlesOffset = electrons["numParticlesOffset"];
429+
for (auto rc : {&numParticles, &numParticlesOffset})
430+
{
431+
rc->resetDataset(
432+
{Datatype::ULONG,
433+
{Extent::value_type{mpi_size}},
434+
R"(adios2.dataset.shape = "local_value")"});
435+
}
436+
numParticles.storeChunk(
437+
std::make_unique<unsigned long>(10), {size_t(mpi_rank)}, {1});
438+
numParticlesOffset.storeChunk(
439+
std::make_unique<unsigned long>(10 * ((unsigned long)mpi_rank)),
440+
{size_t(mpi_rank)},
441+
{1});
442+
auto offset = electrons["offset"];
443+
for (auto const &dim : {"x", "y", "z"})
444+
{
445+
auto rc = offset[dim];
446+
rc.resetDataset(
447+
{Datatype::ULONG,
448+
{Extent::value_type{mpi_size}},
449+
R"(adios2.dataset.shape = "local_value")"});
450+
rc.storeChunk(
451+
std::make_unique<unsigned long>((unsigned long)mpi_rank),
452+
{size_t(mpi_rank)},
453+
{1});
454+
}
455+
auto extent = electrons["extent"];
456+
for (auto const &dim : {"x", "y", "z"})
457+
{
458+
auto rc = extent[dim];
459+
rc.resetDataset(
460+
{Datatype::ULONG,
461+
{Extent::value_type{mpi_size}},
462+
R"(adios2.dataset.shape = "local_value")"});
463+
rc.storeChunk(
464+
std::make_unique<unsigned long>(1), {size_t(mpi_rank)}, {1});
465+
}
466+
425467
it0.close();
426468
}
427469

0 commit comments

Comments
 (0)