Skip to content

Commit 5065b27

Browse files
franzpoeschelax3lgujpre-commit-ci[bot]
authored
Backport non-CI PRs (#1759): #1744 #1732 #1722 #1733 #1738 #1740 #1749
* Fix: Late unique_ptr puts without CLOSE_FILE or ADVANCE operations (#1744) * Add failing test * Add failing test * Revert "Add failing test" This reverts commit 5e04ece. * Reactivate writing from unique_ptr in finalize() * BP5+groupbased: allow only up to 100 steps (#1732) * BP5+groupbased: allow only up to 1000 steps * Configure this via env variable OPENPMD_BP5_GROUPENCODING_MAX_STEPS=1000 * Add documentation * Lower limit to 100 * Add compile-time check for #1720 (#1722) * WarpX: Repo Moved (#1733) Update a link to WarpX. * Fix zero-sized storeChunk for Span API in Python (#1738) * working around an unusual encounter when the joined_dim has actual value "max::size_t - 1" (#1740) * working around an unusal encounter when the joined_dim has actual value "max::size_t - 1" * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add test for redundant resetDataset() * Merge check into above logic * Better error messages in verifyDataset * Add further safety guards to createDataset and extendDataset tasks * Move joinedDim logic into middle-end for extendDataset * Update include/openPMD/IO/ADIOS/ADIOS2IOHandler.hpp --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Franz Pöschel <franz.poeschel@gmail.com> * ADIOS2 bugfix: Always use CurrentStep() in mode::Read (#1749) * Always use CurrentStep() in mode::Read * Remove manual step counting m_currentStep only necessary for SetStepSelection, it seems * Clean up logic that is no longer needed * Add test --------- Co-authored-by: Axel Huebl <axel.huebl@plasma.ninja> Co-authored-by: Junmin Gu <guj@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent e8debe1 commit 5065b27

23 files changed

Lines changed: 380 additions & 89 deletions

docs/source/analysis/paraview.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ The file contains the same string as one would put in an openPMD ``Series("...."
4444
.. warning::
4545

4646
As of ParaView 5.11 and older, the axisLabel is not yet read for fields.
47-
See, e.g., `WarpX issue 21162 <https://github.com/ECP-WarpX/WarpX/issues/1803>`__.
47+
See, e.g., `WarpX issue 21162 <https://github.com/BLAST-WarpX/warpx/issues/1803>`__.
4848
Please apply rotation of, e.g., ``0 -90 0`` to mesh data where needed.
4949

5050
.. warning::

docs/source/backends/adios2.rst

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -78,23 +78,24 @@ The ADIOS2 SST engine for streaming can be picked by specifying the ending ``.ss
7878
The following environment variables control ADIOS2 I/O behavior at runtime.
7979
Fine-tuning these is especially useful when running at large scale.
8080

81-
===================================== ========== ================================================================================
82-
environment variable default description
83-
===================================== ========== ================================================================================
84-
``OPENPMD_ADIOS2_HAVE_PROFILING`` ``1`` Turns on/off profiling information right after a run.
85-
``OPENPMD_ADIOS2_HAVE_METADATA_FILE`` ``1`` Online creation of the adios journal file (``1``: yes, ``0``: no).
86-
``OPENPMD_ADIOS2_NUM_SUBSTREAMS`` ``0`` Number of files to be created, 0 indicates maximum number possible.
87-
``OPENPMD_ADIOS2_ENGINE`` ``File`` `ADIOS2 engine <https://adios2.readthedocs.io/en/latest/engines/engines.html>`_
88-
``OPENPMD_ADIOS2_PRETEND_ENGINE`` *empty* Pretend that an (unknown) ADIOS2 engine is in fact another one (also see the ``adios2.pretend_engine`` :ref:`parameter <backendconfig-adios2>`).
89-
``OPENPMD2_ADIOS2_USE_GROUP_TABLE`` ``0`` Use group table (see below)
90-
``OPENPMD_ADIOS2_STATS_LEVEL`` ``0`` whether to generate statistics for variables in ADIOS2. (``1``: yes, ``0``: no).
91-
``OPENPMD_ADIOS2_ASYNC_WRITE`` ``0`` ADIOS2 BP5 engine: 1 means setting "AsyncWrite" in ADIOS2 to "on". Flushes will go to the buffer by default (see ``preferred_flush_target``).
92-
``OPENPMD_ADIOS2_BP5_BufferChunkMB`` ``0`` ADIOS2 BP5 engine: applies when using either EveryoneWrites or EveryoneWritesSerial aggregation
93-
``OPENPMD_ADIOS2_BP5_MaxShmMB`` ``0`` ADIOS2 BP5 engine: applies when using TwoLevelShm aggregation
94-
``OPENPMD_ADIOS2_BP5_NumSubFiles`` ``0`` ADIOS2 BP5 engine: num of subfiles
95-
``OPENPMD_ADIOS2_BP5_NumAgg`` ``0`` ADIOS2 BP5 engine: num of aggregators
96-
``OPENPMD_ADIOS2_BP5_TypeAgg`` *empty* ADIOS2 BP5 engine: aggregation type. (EveryoneWrites, EveryoneWritesSerial, TwoLevelShm)
97-
===================================== ========== ================================================================================
81+
======================================= ========== ================================================================================
82+
environment variable default description
83+
======================================= ========== ================================================================================
84+
``OPENPMD_ADIOS2_HAVE_PROFILING`` ``1`` Turns on/off profiling information right after a run.
85+
``OPENPMD_ADIOS2_HAVE_METADATA_FILE`` ``1`` Online creation of the adios journal file (``1``: yes, ``0``: no).
86+
``OPENPMD_ADIOS2_NUM_SUBSTREAMS`` ``0`` Number of files to be created, 0 indicates maximum number possible.
87+
``OPENPMD_ADIOS2_ENGINE`` ``File`` `ADIOS2 engine <https://adios2.readthedocs.io/en/latest/engines/engines.html>`_
88+
``OPENPMD_ADIOS2_PRETEND_ENGINE`` *empty* Pretend that an (unknown) ADIOS2 engine is in fact another one (also see the ``adios2.pretend_engine`` :ref:`parameter <backendconfig-adios2>`).
89+
``OPENPMD2_ADIOS2_USE_GROUP_TABLE`` ``0`` Use group table (see below)
90+
``OPENPMD_ADIOS2_STATS_LEVEL`` ``0`` whether to generate statistics for variables in ADIOS2. (``1``: yes, ``0``: no).
91+
``OPENPMD_ADIOS2_ASYNC_WRITE`` ``0`` ADIOS2 BP5 engine: 1 means setting "AsyncWrite" in ADIOS2 to "on". Flushes will go to the buffer by default (see ``preferred_flush_target``).
92+
``OPENPMD_ADIOS2_BP5_BufferChunkMB`` ``0`` ADIOS2 BP5 engine: applies when using either EveryoneWrites or EveryoneWritesSerial aggregation
93+
``OPENPMD_ADIOS2_BP5_MaxShmMB`` ``0`` ADIOS2 BP5 engine: applies when using TwoLevelShm aggregation
94+
``OPENPMD_ADIOS2_BP5_NumSubFiles`` ``0`` ADIOS2 BP5 engine: num of subfiles
95+
``OPENPMD_ADIOS2_BP5_NumAgg`` ``0`` ADIOS2 BP5 engine: num of aggregators
96+
``OPENPMD_ADIOS2_BP5_TypeAgg`` *empty* ADIOS2 BP5 engine: aggregation type. (EveryoneWrites, EveryoneWritesSerial, TwoLevelShm)
97+
``OPENPMD_BP5_GROUPENCODING_MAX_STEPS`` ``100`` ADIOS2 BP5 engine: max number of allowed output steps in group encoding.
98+
======================================= ========== ================================================================================
9899

99100
Please refer to the `ADIOS2 documentation <https://adios2.readthedocs.io/en/latest/engines/engines.html>`_ for details on I/O tuning.
100101

@@ -315,6 +316,21 @@ Rather than by reallocation as in BP4, this is done by appending a new chunk, le
315316
The default is to flush to disk (except when specifying ``OPENPMD_ADIOS2_ASYNC_WRITE=1``), but the default ``preferred_flush_target`` can also be specified via JSON/TOML at the ``Series`` level.
316317

317318

319+
The BP5 engine is known to perform extremely bad for group-based encoding with many Iterations, since its design assumes that the metadata structure will be constant across output steps, while group-based encoding will add new variables and attributes for each Iteration.
320+
The openPMD-api will hence cancel operation after 100 written Iterations in group-based encoding for BP5.
321+
Experiments with PIConGPU show that the metadata (!) size grows from 10MB to 1GB when going from 100 to 1000 output steps in this setup.
322+
The environment variable ``OPENPMD_BP5_GROUPENCODING_MAX_STEPS`` may be used to change this limit (specifying the limit as ``0`` will disable the check).
323+
324+
For workarounds you may follow these guidelines:
325+
326+
* Use file encoding by including an expansion pattern ``%T`` in the filename.
327+
* If output to a single file is required, then:
328+
329+
* Use another ADIOS2 engine, recommended is the BP4 engine by selecting file ending ``.bp4``.
330+
* Use another openPMD backend, recommended is HDF5 by selecting file ending ``.h5``.
331+
* (experimental) use variable encoding with BP5, either by using the API call ``Series::setIterationEncoding(IterationEncoding::variableBased)`` / ``Series.iteration_encoding = Iteration_Encoding.variable_based`` or by using the JSON/TOML configuration ``{"iteration_encoding": "variable_based"}`` / ``iteration_encoding = "variable_based"``.
332+
Note that there is at this point no complete read support for variable-encoded outputs.
333+
318334

319335

320336
Known Issues

examples/10_streaming_write.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,16 @@ int main()
2020
}
2121

2222
// open file for writing
23+
// use QueueFullPolicy = Discard in order to create a situation where from
24+
// the reader's perspective steps are skipped. This tests the bug reported
25+
// in https://github.com/openPMD/openPMD-api/issues/1747.
2326
Series series = Series("electrons.sst", Access::CREATE, R"(
2427
{
2528
"adios2": {
2629
"engine": {
2730
"parameters": {
28-
"DataTransport": "WAN"
31+
"DataTransport": "WAN",
32+
"QueueFullPolicy": "Discard"
2933
}
3034
}
3135
}

include/openPMD/Dataset.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,6 @@ class Dataset
6464
bool empty() const;
6565

6666
std::optional<size_t> joinedDimension() const;
67+
static std::optional<size_t> joinedDimension(Extent const &);
6768
};
6869
} // namespace openPMD

include/openPMD/IO/ADIOS/ADIOS2File.hpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "openPMD/IO/IOTask.hpp"
2626
#include "openPMD/IO/InvalidatableFile.hpp"
2727
#include "openPMD/config.hpp"
28+
#include <optional>
2829

2930
#if openPMD_HAVE_ADIOS2
3031
#include <adios2.h>
@@ -414,11 +415,7 @@ class ADIOS2File
414415
ADIOS2IOHandlerImpl *m_impl;
415416
std::optional<adios2::Engine> m_engine; //! ADIOS engine
416417

417-
/*
418-
* Not all engines support the CurrentStep() call, so we have to
419-
* implement this manually.
420-
*/
421-
size_t m_currentStep = 0;
418+
std::optional<size_t> m_max_steps_bp5 = std::make_optional<size_t>(100);
422419

423420
/*
424421
* ADIOS2 does not give direct access to its internal attribute and

include/openPMD/IO/ADIOS/ADIOS2IOHandler.hpp

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "openPMD/IterationEncoding.hpp"
3333
#include "openPMD/ThrowError.hpp"
3434
#include "openPMD/auxiliary/JSON_internal.hpp"
35+
#include "openPMD/auxiliary/StringManip.hpp"
3536
#include "openPMD/backend/Writable.hpp"
3637
#include "openPMD/config.hpp"
3738
#include <stdexcept>
@@ -473,20 +474,44 @@ class ADIOS2IOHandlerImpl
473474
}
474475
}
475476
auto joinedDim = joinedDimension(shape);
476-
if (joinedDim.has_value())
477+
auto make_runtime_error = [&](char const *message) {
478+
std::stringstream s;
479+
s << "[ADIOS2IOHandlerImpl::verifyDataset()] " << message;
480+
s << "\nNote: Variable '" << varName << "' has shape ";
481+
auxiliary::write_vec_to_stream(s, shape)
482+
<< ", is accessed from offset ";
483+
auxiliary::write_vec_to_stream(s, offset) << " with extent ";
484+
auxiliary::write_vec_to_stream(s, extent);
485+
if (joinedDim.has_value())
486+
{
487+
s << " (joined dimension on index " << *joinedDim << ").";
488+
}
489+
else
490+
{
491+
s << " (no joined dimension).";
492+
}
493+
return std::runtime_error(s.str());
494+
};
495+
if (joinedDim.has_value() ||
496+
var.ShapeID() == adios2::ShapeID::JoinedArray)
477497
{
478498
if (!offset.empty())
479499
{
480-
throw std::runtime_error(
481-
"[ADIOS2] Offset must be an empty vector in case of joined "
482-
"array.");
500+
throw make_runtime_error(
501+
"Offset must be an empty vector in case of joined array.");
502+
}
503+
if (!joinedDim.has_value())
504+
{
505+
throw make_runtime_error(
506+
"Trying to access a dataset as a non-joined array, but it "
507+
"has previously been array.");
483508
}
484509
for (unsigned int i = 0; i < actualDim; i++)
485510
{
486511
if (*joinedDim != i && extent[i] != shape[i])
487512
{
488-
throw std::runtime_error(
489-
"[ADIOS2] store_chunk extent of non-joined dimensions "
513+
throw make_runtime_error(
514+
"store_chunk extent of non-joined dimensions "
490515
"must be equivalent to the total extent.");
491516
}
492517
}
@@ -498,8 +523,7 @@ class ADIOS2IOHandlerImpl
498523
if (!(joinedDim.has_value() && *joinedDim == i) &&
499524
offset[i] + extent[i] > shape[i])
500525
{
501-
throw std::runtime_error(
502-
"[ADIOS2] Dataset access out of bounds.");
526+
throw make_runtime_error("Dataset access out of bounds.");
503527
}
504528
}
505529
}

include/openPMD/IO/IOTask.hpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@ struct OPENPMDAPI_EXPORT AbstractParameter
9898

9999
virtual std::unique_ptr<AbstractParameter> to_heap() && = 0;
100100

101+
// Used as a tag in some constructors to make callsites explicitly
102+
// acknowledge that joined dimensions will not be automatically resolved
103+
struct I_dont_want_to_use_joined_dimensions_t
104+
{};
105+
constexpr static I_dont_want_to_use_joined_dimensions_t
106+
I_dont_want_to_use_joined_dimensions{};
107+
101108
protected:
102109
// avoid object slicing
103110
// by allow only child classes to use these things for defining their own
@@ -327,7 +334,17 @@ template <>
327334
struct OPENPMDAPI_EXPORT Parameter<Operation::CREATE_DATASET>
328335
: public AbstractParameter
329336
{
330-
Parameter() = default;
337+
Parameter(Dataset const &ds)
338+
: extent(ds.extent)
339+
, dtype(ds.dtype)
340+
, options(ds.options)
341+
, joinedDimension(ds.joinedDimension())
342+
{}
343+
344+
// default constructor, but callsites need to explicitly acknowledge that
345+
// joined dimensions will not be automatically configured when using it
346+
Parameter(I_dont_want_to_use_joined_dimensions_t)
347+
{}
331348
Parameter(Parameter &&) = default;
332349
Parameter(Parameter const &) = default;
333350
Parameter &operator=(Parameter &&) = default;
@@ -362,7 +379,15 @@ template <>
362379
struct OPENPMDAPI_EXPORT Parameter<Operation::EXTEND_DATASET>
363380
: public AbstractParameter
364381
{
365-
Parameter() = default;
382+
Parameter(Extent e) : joinedDimension(Dataset::joinedDimension(e))
383+
{
384+
this->extent = std::move(e);
385+
}
386+
387+
// default constructor, but callsites need to explicitly acknowledge that
388+
// joined dimensions will not be automatically configured when using it
389+
Parameter(I_dont_want_to_use_joined_dimensions_t)
390+
{}
366391
Parameter(Parameter &&) = default;
367392
Parameter(Parameter const &) = default;
368393
Parameter &operator=(Parameter &&) = default;
@@ -375,6 +400,7 @@ struct OPENPMDAPI_EXPORT Parameter<Operation::EXTEND_DATASET>
375400
}
376401

377402
Extent extent = {};
403+
std::optional<size_t> joinedDimension;
378404
};
379405

380406
template <>

include/openPMD/RecordComponent.tpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -309,18 +309,14 @@ RecordComponent::storeChunk(Offset o, Extent e, F &&createBuffer)
309309
if (!written())
310310
{
311311
auto &rc = get();
312-
Parameter<Operation::CREATE_DATASET> dCreate;
313-
dCreate.name = rc.m_name;
314-
dCreate.extent = getExtent();
315-
dCreate.dtype = getDatatype();
316-
dCreate.joinedDimension = joinedDimension();
317312
if (!rc.m_dataset.has_value())
318313
{
319314
throw error::WrongAPIUsage(
320315
"[RecordComponent] Must specify dataset type and extent before "
321316
"using storeChunk() (see RecordComponent::resetDataset()).");
322317
}
323-
dCreate.options = rc.m_dataset.value().options;
318+
Parameter<Operation::CREATE_DATASET> dCreate(rc.m_dataset.value());
319+
dCreate.name = rc.m_name;
324320
IOHandler()->enqueue(IOTask(this, dCreate));
325321
}
326322
Parameter<Operation::GET_BUFFER_VIEW> getBufferView;

include/openPMD/auxiliary/StringManip.hpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,5 +242,40 @@ namespace auxiliary
242242
});
243243
return std::forward<S>(s);
244244
}
245+
246+
template <typename Stream, typename Vec>
247+
auto write_vec_to_stream(Stream &&s, Vec const &vec) -> Stream &&
248+
{
249+
if (vec.empty())
250+
{
251+
s << "[]";
252+
}
253+
else
254+
{
255+
s << '[';
256+
auto it = vec.begin();
257+
s << *it++;
258+
auto end = vec.end();
259+
for (; it != end; ++it)
260+
{
261+
s << ", " << *it;
262+
}
263+
s << ']';
264+
}
265+
return std::forward<Stream>(s);
266+
}
267+
268+
template <typename Vec>
269+
auto vec_as_string(Vec const &vec) -> std::string
270+
{
271+
if (vec.empty())
272+
{
273+
return "[]";
274+
}
275+
else
276+
{
277+
return write_vec_to_stream(std::stringstream(), vec).str();
278+
}
279+
}
245280
} // namespace auxiliary
246281
} // namespace openPMD

include/openPMD/openPMD.hpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,21 @@
2525
namespace openPMD
2626
{}
2727

28+
#if defined(CUDA_VERSION) && !defined(OPENPMD_SKIP_CHECK_ISSUE_1720)
29+
static_assert(__cplusplus < 202002L || CUDA_VERSION >= 12040, R"(
30+
Cannot use the openPMD-api in C++20 projects under a Cuda version lower
31+
than 12.4.0 due to a bug in the implementation of std::variant.
32+
Further information at:
33+
https://github.com/openPMD/openPMD-api/issues/1720
34+
https://forums.developer.nvidia.com/t/nvcc-c-20-std-variant-complie-failed/270162/5
35+
This cannot be fixed on our side, please either upgrade to CUDA >= 12.4.0
36+
or use C++17.
37+
If you think that this assertion is shown wrongly, please apply
38+
'#define OPENPMD_SKIP_CHECK_ISSUE_1720' before including
39+
'<openPMD/openPMD.hpp>'.
40+
)");
41+
#endif
42+
2843
// IWYU pragma: begin_exports
2944
#include "openPMD/Dataset.hpp"
3045
#include "openPMD/Datatype.hpp"

0 commit comments

Comments
 (0)