openPMD-api
 
Loading...
Searching...
No Matches
ADIOS2File.hpp
1/* Copyright 2023 Franz Poeschel
2 *
3 * This file is part of openPMD-api.
4 *
5 * openPMD-api is free software: you can redistribute it and/or modify
6 * it under the terms of of either the GNU General Public License or
7 * the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * openPMD-api is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License and the GNU Lesser General Public License
15 * for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * and the GNU Lesser General Public License along with openPMD-api.
19 * If not, see <http://www.gnu.org/licenses/>.
20 */
21#pragma once
22
23#include "openPMD/IO/ADIOS/ADIOS2Auxiliary.hpp"
24#include "openPMD/IO/ADIOS/ADIOS2PreloadAttributes.hpp"
25#include "openPMD/IO/ADIOS/ADIOS2PreloadVariables.hpp"
26#include "openPMD/IO/AbstractIOHandler.hpp"
27#include "openPMD/IO/IOTask.hpp"
28#include "openPMD/IO/InvalidatableFile.hpp"
29#include "openPMD/config.hpp"
30#include <optional>
31
32#if openPMD_HAVE_ADIOS2
33#include <adios2.h>
34#endif
35#if openPMD_HAVE_MPI
36#include <mpi.h>
37#endif
38
39#include <functional>
40#include <string>
41
42namespace openPMD
43{
45}
46
47#if openPMD_HAVE_ADIOS2
48namespace openPMD::detail
49{
50class ADIOS2File;
51
52/*
53 * IO-heavy action to be executed upon flushing.
54 */
55struct BufferedAction
56{
57 explicit BufferedAction() = default;
58 virtual ~BufferedAction() = default;
59
60 BufferedAction(BufferedAction const &other) = delete;
61 BufferedAction(BufferedAction &&other) = default;
62
63 BufferedAction &operator=(BufferedAction const &other) = delete;
64 BufferedAction &operator=(BufferedAction &&other) = default;
65
66 virtual void run(ADIOS2File &) = 0;
67};
68
69struct BufferedGet : BufferedAction
70{
71 std::string name;
73 std::optional<size_t> stepSelection;
74
75 void run(ADIOS2File &) override;
76};
77
79{
80 template <typename T>
81 static void call(
83 BufferedGet &bp,
84 adios2::IO &IO,
85 adios2::Engine &engine,
86 std::string const &fileName,
87 std::optional<size_t> stepSelection,
88 detail::AdiosVariables const &av);
89
90 static constexpr char const *errorMsg = "ADIOS2: readDataset()";
91};
92
93struct BufferedPut : BufferedAction
94{
95 std::string name;
97
98 void run(ADIOS2File &) override;
99};
100
102{
103 template <typename T>
104 static void call(ADIOS2File &ba, BufferedPut &bp);
105
106 template <int n, typename... Params>
107 static void call(Params &&...);
108};
109
111{
112 std::string name;
113 Offset offset;
114 Extent extent;
116 Datatype dtype = Datatype::UNDEFINED;
117
118 void run(ADIOS2File &);
119};
120
122{
123 virtual void *update() = 0;
124 virtual ~I_UpdateSpan() = default;
125};
126
127template <typename T>
128struct UpdateSpan : I_UpdateSpan
129{
130 adios2::detail::Span<T> span;
131
132 UpdateSpan(adios2::detail::Span<T>);
133
134 void *update() override;
135};
136
137/*
138 * Manages per-file information about
139 * (1) the file's IO and Engine objects
140 * (2) the file's deferred IO-heavy actions
141 */
142class ADIOS2File
143{
144 friend struct BufferedGet;
145 friend struct BufferedPut;
146 friend struct RunUniquePtrPut;
147 friend struct WriteDataset;
148
149 using UseGroupTable = adios_defs::UseGroupTable;
150 using FlushTarget = adios_defs::FlushTarget;
151
152public:
153 ADIOS2File(ADIOS2File const &) = delete;
154
162 std::string m_file;
181 std::string m_IOName;
182 adios2::ADIOS &m_ADIOS;
183 adios2::IO m_IO;
188 std::vector<std::unique_ptr<BufferedAction>> m_buffer;
195 std::vector<BufferedUniquePtrPut> m_uniquePtrPuts;
202 std::vector<std::unique_ptr<BufferedAction>> m_alreadyEnqueued;
203 adios2::Mode m_mode;
212 std::map<unsigned, std::unique_ptr<I_UpdateSpan>> m_updateSpans;
213
214 /*
215 * We call an attribute committed if the step during which it was
216 * written has been closed.
217 * A committed attribute cannot be modified.
218 */
219 std::set<std::string> uncommittedAttributes;
220
221 /*
222 * The openPMD API will generally create new attributes for each
223 * iteration. This results in a growing number of attributes over time.
224 * In streaming-based modes, these will be completely sent anew in each
225 * iteration. If the following boolean is true, old attributes will be
226 * removed upon CLOSE_GROUP.
227 * Should not be set to true in persistent backends.
228 * Will be automatically set by ADIOS2File::configure_IO depending
229 * on chosen ADIOS2 engine and can not be explicitly overridden by user.
230 */
231 bool optimizeAttributesStreaming = false;
232
234 ParsePreference parsePreference = ParsePreference::UpFront;
235
236 using AttributeMap_t = std::map<std::string, adios2::Params>;
237
238 ADIOS2File(
241 adios_defs::OpenFileAs);
242
243 ~ADIOS2File();
244
249 void finalize();
250
251 UseGroupTable detectGroupTable();
252
253 adios2::Engine &getEngine();
254
255 template <typename BA>
256 void enqueue(BA &&ba)
257 {
258 enqueue<BA>(std::forward<BA>(ba), m_buffer);
259 }
260
261 template <typename BA>
262 void enqueue(BA &&ba, decltype(m_buffer) &buffer)
263 {
264 using BA_ = typename std::remove_reference<BA>::type;
265 buffer.emplace_back(
266 std::unique_ptr<BufferedAction>(new BA_(std::forward<BA>(ba))));
267 }
268
269 template <typename... Args>
270 void flush(Args &&...args);
271
272 struct ADIOS2FlushParams
273 {
274 /*
275 * Only execute performPutsGets if UserFlush.
276 */
277 FlushLevel level;
278 FlushTarget flushTarget = FlushTarget::Disk;
279
280 ADIOS2FlushParams(FlushLevel level_in) : level(level_in)
281 {}
282
283 ADIOS2FlushParams(FlushLevel level_in, FlushTarget flushTarget_in)
284 : level(level_in), flushTarget(flushTarget_in)
285 {}
286 };
287
305 void flush_impl(
306 ADIOS2FlushParams flushParams,
307 std::function<void(ADIOS2File &, adios2::Engine &)> const
308 &performPutGets,
309 bool writeLatePuts,
310 bool flushUnconditionally);
311
317 void flush_impl(ADIOS2FlushParams, bool writeLatePuts = false);
318
326
327 /*
328 * Delete all buffered actions without running them.
329 */
330 void drop();
331
332 std::vector<std::string>
333 availableAttributesPrefixed(std::string const &prefix);
334
335 AttributeMap_t const &availableVariables();
336
337 std::vector<std::string>
338 availableVariablesPrefixed(std::string const &prefix);
339
340 void markActive(Writable *);
341
342 // bool isActive(std::string const & path);
343
344 /*
345 * streamStatus is NoStream for file-based ADIOS engines.
346 * This is relevant for the method ADIOS2File::requireActiveStep,
347 * where a step is only opened if the status is OutsideOfStep, but not
348 * if NoStream. The rationale behind this is that parsing a Series
349 * works differently for file-based and for stream-based engines:
350 * * stream-based: Iterations are parsed as they arrive. For parsing an
351 * iteration, the iteration must be awaited.
352 * ADIOS2File::requireActiveStep takes care of this.
353 * * file-based: The Series is parsed up front. If no step has been
354 * opened yet, ADIOS2 gives access to all variables and attributes
355 * from all steps. Upon opening a step, only the variables from that
356 * step are shown which hinders parsing. So, until a step is
357 * explicitly opened via ADIOS2IOHandlerImpl::advance, do not open
358 * one.
359 * This is to enable use of ADIOS files without the Streaming API
360 * (i.e. all iterations should be visible to the user upon opening
361 * the Series.)
362 * @todo Add a workflow without up-front parsing of all iterations
363 * for file-based engines.
364 * (This would merely be an optimization since the streaming
365 * API still works with files as intended.)
366 *
367 */
407
408 size_t currentStep();
409 void setStepSelection(std::optional<size_t>);
410 [[nodiscard]] std::optional<size_t> const &stepSelection() const;
411
412 [[nodiscard]] detail::AdiosAttributes const &attributes() const
413 {
414 return m_attributes;
415 }
416 [[nodiscard]] detail::AdiosAttributes &attributes()
417 {
418 return m_attributes;
419 }
420 [[nodiscard]] detail::AdiosVariables const &variables() const
421 {
422 return m_variables;
423 }
424 [[nodiscard]] detail::AdiosVariables &variables()
425 {
426 return m_variables;
427 }
428
429private:
430 ADIOS2IOHandlerImpl *m_impl;
431 std::optional<adios2::Engine> m_engine;
432
433 /*
434 * Used for selecting steps in adios2::Mode::ReadRandomAccesss.
435 */
436 std::optional<size_t> m_stepSelection;
437 std::optional<size_t> m_max_steps_bp5 = std::make_optional<size_t>(100);
438
439 /*
440 * ADIOS2 does not give direct access to its internal attribute and
441 * variable maps, but will instead give access to copies of them.
442 * In order to avoid unnecessary copies, we buffer the returned map.
443 * The downside of this is that we need to pay attention to invalidate
444 * the map whenever an attribute/variable is altered. In that case, we
445 * fetch the map anew.
446 * If empty, the buffered map has been invalidated and needs to be
447 * queried from ADIOS2 again. If full, the buffered map is equivalent to
448 * the map that would be returned by a call to
449 * IO::Available(Attributes|Variables).
450 */
451 AdiosAttributes m_attributes;
452 AdiosVariables m_variables;
453
454 std::set<Writable *> m_pathsMarkedAsActive;
455
456 /*
457 * Cannot write attributes right after opening the engine
458 * https://github.com/ornladios/ADIOS2/issues/3433
459 */
460 bool initializedDefaults = false;
461 /*
462 * finalize() will set this true to avoid running twice.
463 */
464 bool finalized = false;
465
466 UseGroupTable useGroupTable() const;
467
468 void create_IO();
469
470 void configure_IO();
471 void configure_IO_Read();
472 void configure_IO_Write();
473};
474
475template <typename... Args>
476void ADIOS2File::flush(Args &&...args)
477{
478 try
479 {
480 flush_impl(std::forward<Args>(args)...);
481 }
482 catch (error::ReadError const &)
483 {
484 /*
485 * We need to take actions out of the buffer, since an exception
486 * should reset everything from the current IOHandler->flush() call.
487 * However, we cannot simply clear the buffer, since tasks may have
488 * been enqueued to ADIOS2 already and we cannot undo that.
489 * So, we need to keep the memory alive for the benefit of ADIOS2.
490 * Luckily, we have m_alreadyEnqueued for exactly that purpose.
491 */
492 for (auto &task : m_buffer)
493 {
494 m_alreadyEnqueued.emplace_back(std::move(task));
495 }
496 m_buffer.clear();
497 throw;
498 }
499}
500} // namespace openPMD::detail
501#endif
Definition ADIOS2IOHandler.hpp:100
Unique Pointer class that uses a dynamic destructor type.
Definition UniquePtr.hpp:86
Layer to mirror structure of logical data and persistent data in file.
Definition Writable.hpp:76
Definition ADIOS2File.hpp:143
AdvanceStatus advance(AdvanceMode mode)
Begin or end an ADIOS step.
Definition ADIOS2File.cpp:1184
void finalize()
Implementation of destructor, will only run once.
Definition ADIOS2File.cpp:230
std::map< unsigned, std::unique_ptr< I_UpdateSpan > > m_updateSpans
The base pointer of an ADIOS2 span might change after reallocations.
Definition ADIOS2File.hpp:212
std::vector< std::unique_ptr< BufferedAction > > m_buffer
The default queue for deferred actions.
Definition ADIOS2File.hpp:188
std::vector< std::unique_ptr< BufferedAction > > m_alreadyEnqueued
This contains deferred actions that have already been enqueued into ADIOS2, but not yet performed in ...
Definition ADIOS2File.hpp:202
std::vector< BufferedUniquePtrPut > m_uniquePtrPuts
When receiving a unique_ptr, we know that the buffer is ours and ours alone.
Definition ADIOS2File.hpp:195
std::string m_IOName
ADIOS requires giving names to instances of adios2::IO.
Definition ADIOS2File.hpp:181
void flush_impl(ADIOS2FlushParams flushParams, std::function< void(ADIOS2File &, adios2::Engine &)> const &performPutGets, bool writeLatePuts, bool flushUnconditionally)
Flush deferred IO actions.
Definition ADIOS2File.cpp:979
std::string m_file
The full path to the file created on disk, including the containing directory and the file extension,...
Definition ADIOS2File.hpp:162
StreamStatus
Definition ADIOS2File.hpp:369
@ ReadWithoutStream
File is not written is streaming fashion.
Definition ADIOS2File.hpp:398
@ StreamOver
Stream has ended.
Definition ADIOS2File.hpp:381
@ DuringStep
A step is currently active.
Definition ADIOS2File.hpp:373
@ OutsideOfStep
A stream is active, but no step.
Definition ADIOS2File.hpp:377
@ Undecided
The stream status of a file-based engine will be decided upon opening the engine if in read mode.
Definition ADIOS2File.hpp:404
Public definitions of openPMD-api.
Definition Date.cpp:29
AdvanceMode
In step-based mode (i.e.
Definition Streaming.hpp:46
AdvanceStatus
In step-based mode (i.e.
Definition Streaming.hpp:32
FlushLevel
Determine what items should be flushed upon Series::flush()
Definition AbstractIOHandler.hpp:55
Datatype
Concrete datatype of an object available at runtime.
Definition Datatype.hpp:51
Wrapper around a shared pointer to:
Definition InvalidatableFile.hpp:44
Typesafe description of all required arguments for a specified Operation.
Definition IOTask.hpp:148
Definition ADIOS2PreloadAttributes.hpp:152
Definition ADIOS2PreloadVariables.hpp:36
Definition ADIOS2File.hpp:70
Definition ADIOS2File.hpp:94
Definition ADIOS2File.hpp:111
Definition ADIOS2File.hpp:79
Definition ADIOS2File.hpp:122
Definition ADIOS2File.hpp:102