1- /* Copyright 2020-2021 Franz Poeschel
1+ /* Copyright 2020-2025 Franz Poeschel
22 *
33 * This file is part of openPMD-api.
44 *
2020 */
2121#pragma once
2222
23- #include " openPMD/auxiliary/Variant.hpp"
2423#include " openPMD/config.hpp"
25- #include < optional>
26- #include < variant>
2724#if openPMD_HAVE_ADIOS2
2825
2926#include < adios2.h>
3027#include < map>
28+ #include < optional>
29+ #include < variant>
3130
3231#include " openPMD/Datatype.hpp"
32+ #include " openPMD/auxiliary/Variant.hpp"
3333
3434namespace openPMD ::detail
3535{
@@ -46,24 +46,21 @@ struct AttributeWithShape
4646};
4747
4848/* *
49- * Class that is responsible for scheduling and buffering openPMD attribute
50- * loads from ADIOS2, if using ADIOS variables to store openPMD attributes .
49+ * Class that is responsible for buffering loaded openPMD attributes from
50+ * ADIOS2.
5151 *
52- * Reasoning: ADIOS variables can be of any shape and size, and ADIOS cannot
53- * know which variables to buffer. While it will preload and buffer scalar
54- * variables, openPMD also stores vector-type attributes which are not
55- * preloaded. Since in Streaming setups, every variable load requires full
56- * communication back to the writer, this can quickly become very expensive.
57- * Hence, do this manually.
52+ * This is used for reading variable-encoded files in random-access mode.
53+ * Random-access mode in ADIOS2 has the restriction that modifiable attributes
54+ * can only be recovered in normal non-random-access read mode, so we open the
55+ * file first in that mode, store all attribute metadata in this class and only
56+ * then continue in random-access mode.
5857 *
5958 */
6059class PreloadAdiosAttributes
6160{
6261public:
6362 /* *
64- * Internally used struct to store meta information on a buffered
65- * attribute. Public for simplicity (helper struct in the
66- * implementation uses it).
63+ * Meta information on a buffered attribute.
6764 */
6865 struct AttributeLocation
6966 {
@@ -106,11 +103,7 @@ class PreloadAdiosAttributes
106103 PreloadAdiosAttributes &operator =(PreloadAdiosAttributes &&other) = default ;
107104
108105 /* *
109- * @brief Schedule attributes for preloading.
110- *
111- * This will invalidate all previously buffered attributes.
112- * This will *not* flush the scheduled loads. This way, attributes can
113- * be loaded along with the next adios2::Engine flush.
106+ * @brief Load attributes from the current step into the buffer.
114107 *
115108 * @param IO
116109 */
@@ -131,45 +124,27 @@ class PreloadAdiosAttributes
131124
132125 Datatype attributeType (std::string const &name) const ;
133126
134- std::map<std::string, AttributeLocation> const &
135- availableAttributes () const &
136- {
137- return m_offsets;
138- }
127+ std::map<std::string, AttributeLocation> const &availableAttributes () const ;
139128};
140129
141130template <typename T>
142131struct AttributeWithShapeAndResource : AttributeWithShape<T>
143132{
144- AttributeWithShapeAndResource (AttributeWithShape<T> parent)
145- : AttributeWithShape<T>(std::move(parent))
146- {}
133+ AttributeWithShapeAndResource (AttributeWithShape<T> parent);
147134 AttributeWithShapeAndResource (
148135 size_t len_in,
149136 T const *data_in,
150- std::optional<std::vector<T>> resource_in)
151- : AttributeWithShape<T>{len_in, data_in}
152- , resource{std::move (resource_in)}
153- {}
154- explicit AttributeWithShapeAndResource () : AttributeWithShape<T>(0 , nullptr )
155- {}
156- AttributeWithShapeAndResource (adios2::Attribute<T> attr)
157- {
158- if (!attr)
159- {
160- this ->data = nullptr ;
161- this ->len = 0 ;
162- return ;
163- }
164- auto vec = attr.Data ();
165- this ->len = vec.size ();
166- this ->data = vec.data ();
167- this ->resource = std::move (vec);
168- }
169- operator bool () const
170- {
171- return this ->data ;
172- }
137+ std::optional<std::vector<T>> resource_in);
138+ AttributeWithShapeAndResource (adios2::Attribute<T> attr);
139+ operator bool () const ;
140+
141+ private:
142+ /*
143+ * Users should still use the API of AttributeWithShape (parent type), we
144+ * just need somewhere to store the std::vector<T> returned by
145+ * Attribute<T>::Data(). This field will not be used when using preparsing,
146+ * because the data pointer will go right into the preparse buffer.
147+ */
173148 std::optional<std::vector<T>> resource;
174149};
175150
@@ -178,12 +153,34 @@ struct AdiosAttributes
178153 using RandomAccess_t = std::vector<PreloadAdiosAttributes>;
179154 struct StreamAccess_t
180155 {
156+ /*
157+ * These are only buffered for performance reasons.
158+ * IO::AvailableAttributes() returns by value, so we should avoid
159+ * calling it too often. Instead, store the returned value along with
160+ * the step, so we know when we need to update again (i.e. when the
161+ * current step changes).
162+ */
181163 size_t m_currentStep = 0 ;
182164 std::optional<std::map<std::string, adios2::Params>> m_attributes;
183165 };
184166
167+ /*
168+ * Variant RandomAcces_t has to be initialized explicitly by
169+ * ADIOS2IOHandlerImpl::readAttributeAllsteps(), so we use StreamAccess_t by
170+ * default.
171+ */
185172 std::variant<RandomAccess_t, StreamAccess_t> m_data = StreamAccess_t{};
186173
174+ /*
175+ * Needs to be this somewhat ugly API since the AvailableAttributes map has
176+ * a different type depending if we use preparsing or not. If we don't use
177+ * preparsing, we just use the returned std::map<std::string,
178+ * adios2::Params> from IO::AvailableAttributes(). Otherwise, we use the
179+ * std::map<std::string, AttributeLocation> map from the
180+ * PreloadAdiosAttributes class. The functor f will be called either with
181+ * the one or the other, so needs to be written such that the mapped-to type
182+ * does not matter.
183+ */
187184 template <typename Functor>
188185 auto withAvailableAttributes (size_t step, adios2::IO &IO, Functor &&f)
189186 -> decltype(std::forward<Functor>(f)(
0 commit comments