openPMD-api
ADIOS2IOHandler.hpp
1 /* Copyright 2017-2021 Fabian Koller and 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/ADIOS2FilePosition.hpp"
25 #include "openPMD/IO/ADIOS/ADIOS2PreloadAttributes.hpp"
26 #include "openPMD/IO/AbstractIOHandler.hpp"
27 #include "openPMD/IO/AbstractIOHandlerImpl.hpp"
28 #include "openPMD/IO/AbstractIOHandlerImplCommon.hpp"
29 #include "openPMD/IO/IOTask.hpp"
30 #include "openPMD/IO/InvalidatableFile.hpp"
31 #include "openPMD/IterationEncoding.hpp"
32 #include "openPMD/auxiliary/JSON.hpp"
33 #include "openPMD/auxiliary/Option.hpp"
34 #include "openPMD/backend/Writable.hpp"
35 #include "openPMD/config.hpp"
36 
37 #if openPMD_HAVE_ADIOS2
38 #include <adios2.h>
39 #endif
40 #if openPMD_HAVE_MPI
41 #include <mpi.h>
42 #endif
43 #include <nlohmann/json.hpp>
44 
45 #include <array>
46 #include <exception>
47 #include <future>
48 #include <iostream>
49 #include <memory> // shared_ptr
50 #include <set>
51 #include <string>
52 #include <unordered_map>
53 #include <utility> // pair
54 #include <vector>
55 
56 namespace openPMD
57 {
58 #if openPMD_HAVE_ADIOS2
59 
60 class ADIOS2IOHandler;
61 
62 namespace detail
63 {
64  template <typename, typename>
65  struct DatasetHelper;
66  struct GetSpan;
67  struct DatasetReader;
68  struct AttributeReader;
69  struct AttributeWriter;
70  struct OldAttributeReader;
71  struct OldAttributeWriter;
72  template <typename>
74  struct DatasetOpener;
75  struct VariableDefiner;
76  template <typename>
77  struct DatasetTypes;
78  struct WriteDataset;
79  struct BufferedActions;
80  struct BufferedPut;
81  struct BufferedGet;
82  struct BufferedAttributeRead;
84 } // namespace detail
85 
86 namespace ADIOS2Schema
87 {
88  using schema_t = uint64_t;
89  /*
90  * Original ADIOS schema.
91  */
92  constexpr schema_t schema_0000_00_00 = 00000000;
93  /*
94  * This introduces attribute layout via scalar ADIOS variables.
95  */
96  constexpr schema_t schema_2021_02_09 = 20210209;
97 
98  enum class SupportedSchema : char
99  {
100  s_0000_00_00,
101  s_2021_02_09
102  };
103 } // namespace ADIOS2Schema
104 using SupportedSchema = ADIOS2Schema::SupportedSchema;
105 
107  : public AbstractIOHandlerImplCommon<ADIOS2FilePosition>
108 {
109  template <typename, typename>
110  friend struct detail::DatasetHelper;
111  friend struct detail::GetSpan;
112  friend struct detail::DatasetReader;
113  friend struct detail::AttributeReader;
114  friend struct detail::AttributeWriter;
115  friend struct detail::OldAttributeReader;
116  friend struct detail::OldAttributeWriter;
117  template <typename>
118  friend struct detail::AttributeTypes;
119  friend struct detail::DatasetOpener;
120  friend struct detail::VariableDefiner;
121  template <typename>
122  friend struct detail::DatasetTypes;
123  friend struct detail::WriteDataset;
124  friend struct detail::BufferedActions;
125  friend struct detail::BufferedAttributeRead;
126 
127 public:
128 #if openPMD_HAVE_MPI
129 
132  MPI_Comm,
133  nlohmann::json config,
134  std::string engineType);
135 
136 #endif // openPMD_HAVE_MPI
137 
138  explicit ADIOS2IOHandlerImpl(
139  AbstractIOHandler *, nlohmann::json config, std::string engineType);
140 
141  ~ADIOS2IOHandlerImpl() override;
142 
143  std::future<void> flush(internal::FlushParams const &);
144 
145  void
146  createFile(Writable *, Parameter<Operation::CREATE_FILE> const &) override;
147 
148  void
149  createPath(Writable *, Parameter<Operation::CREATE_PATH> const &) override;
150 
151  void createDataset(
152  Writable *, Parameter<Operation::CREATE_DATASET> const &) override;
153 
154  void extendDataset(
155  Writable *, Parameter<Operation::EXTEND_DATASET> const &) override;
156 
157  void openFile(Writable *, Parameter<Operation::OPEN_FILE> const &) override;
158 
159  void
160  closeFile(Writable *, Parameter<Operation::CLOSE_FILE> const &) override;
161 
162  void openPath(Writable *, Parameter<Operation::OPEN_PATH> const &) override;
163 
164  void
165  closePath(Writable *, Parameter<Operation::CLOSE_PATH> const &) override;
166 
167  void openDataset(Writable *, Parameter<Operation::OPEN_DATASET> &) override;
168 
169  void
170  deleteFile(Writable *, Parameter<Operation::DELETE_FILE> const &) override;
171 
172  void
173  deletePath(Writable *, Parameter<Operation::DELETE_PATH> const &) override;
174 
175  void deleteDataset(
176  Writable *, Parameter<Operation::DELETE_DATASET> const &) override;
177 
178  void deleteAttribute(
179  Writable *, Parameter<Operation::DELETE_ATT> const &) override;
180 
181  void writeDataset(
182  Writable *, Parameter<Operation::WRITE_DATASET> const &) override;
183 
184  void writeAttribute(
185  Writable *, Parameter<Operation::WRITE_ATT> const &) override;
186 
187  void readDataset(Writable *, Parameter<Operation::READ_DATASET> &) override;
188 
189  void
190  getBufferView(Writable *, Parameter<Operation::GET_BUFFER_VIEW> &) override;
191 
192  void readAttribute(Writable *, Parameter<Operation::READ_ATT> &) override;
193 
194  void listPaths(Writable *, Parameter<Operation::LIST_PATHS> &) override;
195 
196  void
197  listDatasets(Writable *, Parameter<Operation::LIST_DATASETS> &) override;
198 
199  void listAttributes(
200  Writable *, Parameter<Operation::LIST_ATTS> &parameters) override;
201 
202  void advance(Writable *, Parameter<Operation::ADVANCE> &) override;
203 
204  void availableChunks(
210  adios2::Mode adios2AccessMode(std::string const &fullPath);
211 
212 private:
213  adios2::ADIOS m_ADIOS;
214  /*
215  * If the iteration encoding is variableBased, we default to using the
216  * 2021_02_09 schema since it allows mutable attributes.
217  */
218  IterationEncoding m_iterationEncoding = IterationEncoding::groupBased;
222  std::string m_engineType;
223  ADIOS2Schema::schema_t m_schema = ADIOS2Schema::schema_0000_00_00;
224 
225  enum class UseSpan : char
226  {
227  Yes,
228  No,
229  Auto
230  };
231 
232  UseSpan m_useSpanBasedPutByDefault = UseSpan::Auto;
233 
234  enum class AttributeLayout : char
235  {
236  ByAdiosAttributes,
237  ByAdiosVariables
238  };
239 
240  inline SupportedSchema schema() const
241  {
242  switch (m_schema)
243  {
244  case ADIOS2Schema::schema_0000_00_00:
245  return SupportedSchema::s_0000_00_00;
246  case ADIOS2Schema::schema_2021_02_09:
247  return SupportedSchema::s_2021_02_09;
248  default:
249  throw std::runtime_error(
250  "[ADIOS2] Encountered unsupported schema version: " +
251  std::to_string(m_schema));
252  }
253  }
254 
255  inline AttributeLayout attributeLayout() const
256  {
257  switch (schema())
258  {
259  case SupportedSchema::s_0000_00_00:
260  return AttributeLayout::ByAdiosAttributes;
261  case SupportedSchema::s_2021_02_09:
262  return AttributeLayout::ByAdiosVariables;
263  }
264  throw std::runtime_error("Unreachable!");
265  }
266 
267  struct ParameterizedOperator
268  {
269  adios2::Operator op;
270  adios2::Params params;
271  };
272 
273  std::vector<ParameterizedOperator> defaultOperators;
274 
275  auxiliary::TracingJSON m_config;
276  static auxiliary::TracingJSON nullvalue;
277 
278  void init(nlohmann::json config);
279 
280  template <typename Key>
281  auxiliary::TracingJSON config(Key &&key, auxiliary::TracingJSON &cfg)
282  {
283  if (cfg.json().is_object() && cfg.json().contains(key))
284  {
285  return cfg[key];
286  }
287  else
288  {
289  return nullvalue;
290  }
291  }
292 
293  template <typename Key>
294  auxiliary::TracingJSON config(Key &&key)
295  {
296  return config<Key>(std::forward<Key>(key), m_config);
297  }
298 
307  getOperators(auxiliary::TracingJSON config);
308 
309  // use m_config
311 
312  std::string fileSuffix() const;
313 
314  /*
315  * We need to give names to IO objects. These names are irrelevant
316  * within this application, since:
317  * 1) The name of the file written to is decided by the opened Engine's
318  * name.
319  * 2) The IOs are managed by the unordered_map m_fileData, so we do not
320  * need the ADIOS2 internal management.
321  * Since within one m_ADIOS object, the same IO name cannot be used more
322  * than once, we ensure different names by using the name counter.
323  * This allows to overwrite a file later without error.
324  */
325  int nameCounter{0};
326 
327  /*
328  * IO-heavy actions are deferred to a later point. This map stores for
329  * each open file (identified by an InvalidatableFile object) an object
330  * that manages IO-heavy actions, as well as its ADIOS2 objects, i.e.
331  * IO and Engine object.
332  * Not to be accessed directly, use getFileData().
333  */
334  std::unordered_map<
336  std::unique_ptr<detail::BufferedActions> >
337  m_fileData;
338 
339  std::map<std::string, adios2::Operator> m_operators;
340 
341  // Overrides from AbstractIOHandlerImplCommon.
342 
343  std::string
344  filePositionToString(std::shared_ptr<ADIOS2FilePosition>) override;
345 
346  std::shared_ptr<ADIOS2FilePosition> extendFilePosition(
347  std::shared_ptr<ADIOS2FilePosition> const &pos,
348  std::string extend) override;
349 
350  // Helper methods.
351 
353  getCompressionOperator(std::string const &compression);
354 
355  /*
356  * The name of the ADIOS2 variable associated with this Writable.
357  * To be used for Writables that represent a dataset.
358  */
359  std::string nameOfVariable(Writable *writable);
360 
370  std::string nameOfAttribute(Writable *writable, std::string attribute);
371 
372  /*
373  * Figure out whether the Writable corresponds with a
374  * group or a dataset.
375  */
376  ADIOS2FilePosition::GD groupOrDataset(Writable *);
377 
378  enum class IfFileNotOpen : bool
379  {
380  OpenImplicitly,
381  ThrowError
382  };
383 
384  detail::BufferedActions &getFileData(InvalidatableFile file, IfFileNotOpen);
385 
386  void dropFileData(InvalidatableFile file);
387 
388  /*
389  * Prepare a variable that already exists for an IO
390  * operation, including:
391  * (1) checking that its datatype matches T.
392  * (2) the offset and extent match the variable's shape
393  * (3) setting the offset and extent (ADIOS lingo: start
394  * and count)
395  */
396  template <typename T>
397  adios2::Variable<T> verifyDataset(
398  Offset const &offset,
399  Extent const &extent,
400  adios2::IO &IO,
401  std::string const &var);
402 }; // ADIOS2IOHandlerImpl
403 
404 /*
405  * The following strings are used during parsing of the JSON configuration
406  * string for the ADIOS2 backend.
407  */
408 namespace ADIOS2Defaults
409 {
410  using const_str = char const *const;
411  constexpr const_str str_engine = "engine";
412  constexpr const_str str_type = "type";
413  constexpr const_str str_params = "parameters";
414  constexpr const_str str_usesteps = "usesteps";
415  constexpr const_str str_usesstepsAttribute = "__openPMD_internal/useSteps";
416  constexpr const_str str_adios2Schema =
417  "__openPMD_internal/openPMD2_adios2_schema";
418  constexpr const_str str_isBooleanOldLayout = "__is_boolean__";
419  constexpr const_str str_isBooleanNewLayout =
420  "__openPMD_internal/is_boolean";
421 } // namespace ADIOS2Defaults
422 
423 namespace detail
424 {
425  // Helper structs for calls to the switchType function
426 
428  {
430 
432 
433  template <typename T>
434  void operator()(
435  BufferedGet &bp,
436  adios2::IO &IO,
437  adios2::Engine &engine,
438  std::string const &fileName);
439 
440  std::string errorMsg = "ADIOS2: readDataset()";
441  };
442 
444  {
445  template <typename T>
446  Datatype operator()(
447  adios2::IO &IO,
448  std::string name,
449  std::shared_ptr<Attribute::resource> resource);
450 
451  template <int n, typename... Params>
452  Datatype operator()(Params &&...);
453  };
454 
456  {
457  template <typename T>
458  void operator()(
459  ADIOS2IOHandlerImpl *impl,
460  Writable *writable,
461  const Parameter<Operation::WRITE_ATT> &parameters);
462 
463  template <int n, typename... Params>
464  void operator()(Params &&...);
465  };
466 
468  {
469  template <typename T>
470  Datatype operator()(
471  adios2::IO &IO,
472  detail::PreloadAdiosAttributes const &preloadedAttributes,
473  std::string name,
474  std::shared_ptr<Attribute::resource> resource);
475 
476  template <int n, typename... Params>
477  Datatype operator()(Params &&...);
478  };
479 
481  {
482  template <typename T>
483  void operator()(
485 
486  template <int n, typename... Params>
487  void operator()(Params &&...);
488  };
489 
491  {
492  ADIOS2IOHandlerImpl *m_impl;
493 
494  explicit DatasetOpener(ADIOS2IOHandlerImpl *impl);
495 
496  template <typename T>
497  void operator()(
499  const std::string &varName,
501 
502  std::string errorMsg = "ADIOS2: openDataset()";
503  };
504 
506  {
507  ADIOS2IOHandlerImpl *m_handlerImpl;
508 
509  WriteDataset(ADIOS2IOHandlerImpl *handlerImpl);
510 
511  template <typename T>
512  void
513  operator()(BufferedPut &bp, adios2::IO &IO, adios2::Engine &engine);
514 
515  template <int n, typename... Params>
516  void operator()(Params &&...);
517  };
518 
520  {
536  template <typename T>
537  void operator()(
538  adios2::IO &IO,
539  std::string const &name,
540  std::vector<ADIOS2IOHandlerImpl::ParameterizedOperator> const
541  &compressions,
542  adios2::Dims const &shape = adios2::Dims(),
543  adios2::Dims const &start = adios2::Dims(),
544  adios2::Dims const &count = adios2::Dims(),
545  bool const constantDims = false);
546 
547  std::string errorMsg = "ADIOS2: defineVariable()";
548  };
549 
551  {
552  template <typename T>
553  void operator()(
555  adios2::IO &IO,
556  adios2::Engine &engine,
557  std::string const &varName);
558 
559  template <int n, typename... Params>
560  void operator()(Params &&...);
561  };
562 
563  // Helper structs to help distinguish valid attribute/variable
564  // datatypes from invalid ones
565 
566  /*
567  * This struct's purpose is to have specialisations
568  * for vector and array types, as well as the boolean
569  * type (which is not natively supported by ADIOS).
570  */
571  template <typename T>
572  struct AttributeTypes
573  {
574  static void
575  oldCreateAttribute(adios2::IO &IO, std::string name, T value);
576 
577  static void oldReadAttribute(
578  adios2::IO &IO,
579  std::string name,
580  std::shared_ptr<Attribute::resource> resource);
581 
582  static void createAttribute(
583  adios2::IO &IO,
584  adios2::Engine &engine,
586  T value);
587 
588  static void readAttribute(
590  std::string name,
591  std::shared_ptr<Attribute::resource> resource);
592 
597  static bool attributeUnchanged(adios2::IO &IO, std::string name, T val)
598  {
599  auto attr = IO.InquireAttribute<T>(name);
600  if (!attr)
601  {
602  return false;
603  }
604  std::vector<T> data = attr.Data();
605  if (data.size() != 1)
606  {
607  return false;
608  }
609  return data[0] == val;
610  }
611  };
612 
613  template <>
614  struct AttributeTypes<std::complex<long double> >
615  {
616  static void
617  oldCreateAttribute(adios2::IO &, std::string, std::complex<long double>)
618  {
619  throw std::runtime_error(
620  "[ADIOS2] Internal error: no support for long double complex "
621  "attribute types");
622  }
623 
624  static void oldReadAttribute(
625  adios2::IO &, std::string, std::shared_ptr<Attribute::resource>)
626  {
627  throw std::runtime_error(
628  "[ADIOS2] Internal error: no support for long double complex "
629  "attribute types");
630  }
631 
632  static void createAttribute(
633  adios2::IO &,
634  adios2::Engine &,
636  std::complex<long double>)
637  {
638  throw std::runtime_error(
639  "[ADIOS2] Internal error: no support for long double complex "
640  "attribute types");
641  }
642 
643  static void readAttribute(
645  std::string,
646  std::shared_ptr<Attribute::resource>)
647  {
648  throw std::runtime_error(
649  "[ADIOS2] Internal error: no support for long double complex "
650  "attribute types");
651  }
652 
653  static bool
654  attributeUnchanged(adios2::IO &, std::string, std::complex<long double>)
655  {
656  throw std::runtime_error(
657  "[ADIOS2] Internal error: no support for long double complex "
658  "attribute types");
659  }
660  };
661 
662  template <>
663  struct AttributeTypes<std::vector<std::complex<long double> > >
664  {
665  static void oldCreateAttribute(
666  adios2::IO &,
667  std::string,
668  const std::vector<std::complex<long double> > &)
669  {
670  throw std::runtime_error(
671  "[ADIOS2] Internal error: no support for long double complex "
672  "vector attribute types");
673  }
674 
675  static void oldReadAttribute(
676  adios2::IO &, std::string, std::shared_ptr<Attribute::resource>)
677  {
678  throw std::runtime_error(
679  "[ADIOS2] Internal error: no support for long double complex "
680  "vector attribute types");
681  }
682 
683  static void createAttribute(
684  adios2::IO &,
685  adios2::Engine &,
687  const std::vector<std::complex<long double> > &)
688  {
689  throw std::runtime_error(
690  "[ADIOS2] Internal error: no support for long double complex "
691  "vector attribute types");
692  }
693 
694  static void readAttribute(
696  std::string,
697  std::shared_ptr<Attribute::resource>)
698  {
699  throw std::runtime_error(
700  "[ADIOS2] Internal error: no support for long double complex "
701  "vector attribute types");
702  }
703 
704  static bool attributeUnchanged(
705  adios2::IO &, std::string, std::vector<std::complex<long double> >)
706  {
707  throw std::runtime_error(
708  "[ADIOS2] Internal error: no support for long double complex "
709  "vector attribute types");
710  }
711  };
712 
713  template <typename T>
714  struct AttributeTypes<std::vector<T> >
715  {
716  static void oldCreateAttribute(
717  adios2::IO &IO, std::string name, const std::vector<T> &value);
718 
719  static void oldReadAttribute(
720  adios2::IO &IO,
721  std::string name,
722  std::shared_ptr<Attribute::resource> resource);
723 
724  static void createAttribute(
725  adios2::IO &IO,
726  adios2::Engine &engine,
728  const std::vector<T> &value);
729 
730  static void readAttribute(
732  std::string name,
733  std::shared_ptr<Attribute::resource> resource);
734 
735  static bool
736  attributeUnchanged(adios2::IO &IO, std::string name, std::vector<T> val)
737  {
738  auto attr = IO.InquireAttribute<T>(name);
739  if (!attr)
740  {
741  return false;
742  }
743  std::vector<T> data = attr.Data();
744  if (data.size() != val.size())
745  {
746  return false;
747  }
748  for (size_t i = 0; i < val.size(); ++i)
749  {
750  if (data[i] != val[i])
751  {
752  return false;
753  }
754  }
755  return true;
756  }
757  };
758 
759  template <>
760  struct AttributeTypes<std::vector<std::string> >
761  {
762  static void oldCreateAttribute(
763  adios2::IO &IO,
764  std::string name,
765  const std::vector<std::string> &value);
766 
767  static void oldReadAttribute(
768  adios2::IO &IO,
769  std::string name,
770  std::shared_ptr<Attribute::resource> resource);
771 
772  static void createAttribute(
773  adios2::IO &IO,
774  adios2::Engine &engine,
776  const std::vector<std::string> &vec);
777 
778  static void readAttribute(
780  std::string name,
781  std::shared_ptr<Attribute::resource> resource);
782 
783  static bool attributeUnchanged(
784  adios2::IO &IO, std::string name, std::vector<std::string> val)
785  {
786  auto attr = IO.InquireAttribute<std::string>(name);
787  if (!attr)
788  {
789  return false;
790  }
791  std::vector<std::string> data = attr.Data();
792  if (data.size() != val.size())
793  {
794  return false;
795  }
796  for (size_t i = 0; i < val.size(); ++i)
797  {
798  if (data[i] != val[i])
799  {
800  return false;
801  }
802  }
803  return true;
804  }
805  };
806 
807  template <typename T, size_t n>
808  struct AttributeTypes<std::array<T, n> >
809  {
810  static void oldCreateAttribute(
811  adios2::IO &IO, std::string name, const std::array<T, n> &value);
812 
813  static void oldReadAttribute(
814  adios2::IO &IO,
815  std::string name,
816  std::shared_ptr<Attribute::resource> resource);
817 
818  static void createAttribute(
819  adios2::IO &IO,
820  adios2::Engine &engine,
822  const std::array<T, n> &value);
823 
824  static void readAttribute(
826  std::string name,
827  std::shared_ptr<Attribute::resource> resource);
828 
829  static bool attributeUnchanged(
830  adios2::IO &IO, std::string name, std::array<T, n> val)
831  {
832  auto attr = IO.InquireAttribute<T>(name);
833  if (!attr)
834  {
835  return false;
836  }
837  std::vector<T> data = attr.Data();
838  if (data.size() != n)
839  {
840  return false;
841  }
842  for (size_t i = 0; i < n; ++i)
843  {
844  if (data[i] != val[i])
845  {
846  return false;
847  }
848  }
849  return true;
850  }
851  };
852 
853  template <>
854  struct AttributeTypes<bool>
855  {
856  using rep = detail::bool_representation;
857 
858  static void
859  oldCreateAttribute(adios2::IO &IO, std::string name, bool value);
860 
861  static void oldReadAttribute(
862  adios2::IO &IO,
863  std::string name,
864  std::shared_ptr<Attribute::resource> resource);
865 
866  static void createAttribute(
867  adios2::IO &IO,
868  adios2::Engine &engine,
870  bool value);
871 
872  static void readAttribute(
874  std::string name,
875  std::shared_ptr<Attribute::resource> resource);
876 
877  static constexpr rep toRep(bool b)
878  {
879  return b ? 1U : 0U;
880  }
881 
882  static constexpr bool fromRep(rep r)
883  {
884  return r != 0;
885  }
886 
887  static bool
888  attributeUnchanged(adios2::IO &IO, std::string name, bool val)
889  {
890  auto attr = IO.InquireAttribute<rep>(name);
891  if (!attr)
892  {
893  return false;
894  }
895  std::vector<rep> data = attr.Data();
896  if (data.size() != 1)
897  {
898  return false;
899  }
900  return data[0] == toRep(val);
901  }
902  };
903 
904  // Other datatypes used in the ADIOS2IOHandler implementation
905 
906  struct BufferedActions;
907 
908  /*
909  * IO-heavy action to be executed upon flushing.
910  */
912  {
913  explicit BufferedAction() = default;
914  virtual ~BufferedAction() = default;
915 
916  BufferedAction(BufferedAction const &other) = delete;
917  BufferedAction(BufferedAction &&other) = default;
918 
919  BufferedAction &operator=(BufferedAction const &other) = delete;
920  BufferedAction &operator=(BufferedAction &&other) = default;
921 
922  virtual void run(BufferedActions &) = 0;
923  };
924 
926  {
927  std::string name;
929 
930  void run(BufferedActions &) override;
931  };
932 
934  {
935  std::string name;
937 
938  void run(BufferedActions &) override;
939  };
940 
942  {
944  std::string name;
945 
946  void run(BufferedActions &) override;
947  };
948 
950  {
952  std::string name;
953 
954  void run(BufferedActions &);
955  };
956 
958  {
959  std::string name;
960  Datatype dtype;
961  Attribute::resource resource;
962  std::vector<char> bufferForVecString;
963 
964  void run(BufferedActions &) override;
965  };
966 
968  {
969  virtual void *update() = 0;
970  virtual ~I_UpdateSpan() = default;
971  };
972 
973  template <typename T>
975  {
976  adios2::detail::Span<T> span;
977 
978  UpdateSpan(adios2::detail::Span<T>);
979 
980  void *update() override;
981  };
982 
983  /*
984  * Manages per-file information about
985  * (1) the file's IO and Engine objects
986  * (2) the file's deferred IO-heavy actions
987  */
989  {
990  BufferedActions(BufferedActions const &) = delete;
991 
999  std::string m_file;
1018  std::string const m_IOName;
1019  adios2::ADIOS &m_ADIOS;
1020  adios2::IO m_IO;
1025  std::vector<std::unique_ptr<BufferedAction> > m_buffer;
1036  std::map<std::string, BufferedAttributeWrite> m_attributeWrites;
1042  std::vector<BufferedAttributeRead> m_attributeReads;
1049  std::vector<std::unique_ptr<BufferedAction> > m_alreadyEnqueued;
1050  adios2::Mode m_mode;
1059  std::map<unsigned, std::unique_ptr<I_UpdateSpan> > m_updateSpans;
1060  detail::WriteDataset const m_writeDataset;
1061  detail::DatasetReader const m_readDataset;
1062  detail::AttributeReader const m_attributeReader;
1063  PreloadAdiosAttributes preloadAttributes;
1064 
1065  /*
1066  * We call an attribute committed if the step during which it was
1067  * written has been closed.
1068  * A committed attribute cannot be modified.
1069  */
1070  std::set<std::string> uncommittedAttributes;
1071 
1072  /*
1073  * The openPMD API will generally create new attributes for each
1074  * iteration. This results in a growing number of attributes over time.
1075  * In streaming-based modes, these will be completely sent anew in each
1076  * iteration. If the following boolean is true, old attributes will be
1077  * removed upon CLOSE_GROUP.
1078  * Should not be set to true in persistent backends.
1079  * Will be automatically set by BufferedActions::configure_IO depending
1080  * on chosen ADIOS2 engine and can not be explicitly overridden by user.
1081  */
1082  bool optimizeAttributesStreaming = false;
1083 
1084  using AttributeMap_t = std::map<std::string, adios2::Params>;
1085 
1087 
1088  ~BufferedActions();
1089 
1094  void finalize();
1095 
1096  adios2::Engine &getEngine();
1097  adios2::Engine &requireActiveStep();
1098 
1099  template <typename BA>
1100  void enqueue(BA &&ba);
1101 
1102  template <typename BA>
1103  void enqueue(BA &&ba, decltype(m_buffer) &);
1104 
1121  template <typename F>
1122  void flush(
1123  FlushLevel level,
1124  F &&performPutsGets,
1125  bool writeAttributes,
1126  bool flushUnconditionally);
1127 
1133  void flush(FlushLevel, bool writeAttributes = false);
1134 
1141  AdvanceStatus advance(AdvanceMode mode);
1142 
1143  /*
1144  * Delete all buffered actions without running them.
1145  */
1146  void drop();
1147 
1148  AttributeMap_t const &availableAttributes();
1149 
1150  std::vector<std::string>
1151  availableAttributesPrefixed(std::string const &prefix);
1152 
1153  /*
1154  * See description below.
1155  */
1156  void invalidateAttributesMap();
1157 
1158  AttributeMap_t const &availableVariables();
1159 
1160  std::vector<std::string>
1161  availableVariablesPrefixed(std::string const &prefix);
1162 
1163  /*
1164  * See description below.
1165  */
1166  void invalidateVariablesMap();
1167 
1168  private:
1169  ADIOS2IOHandlerImpl *m_impl;
1171 
1174  std::string m_engineType;
1175  /*
1176  * streamStatus is NoStream for file-based ADIOS engines.
1177  * This is relevant for the method BufferedActions::requireActiveStep,
1178  * where a step is only opened if the status is OutsideOfStep, but not
1179  * if NoStream. The rationale behind this is that parsing a Series
1180  * works differently for file-based and for stream-based engines:
1181  * * stream-based: Iterations are parsed as they arrive. For parsing an
1182  * iteration, the iteration must be awaited.
1183  * BufferedActions::requireActiveStep takes care of this.
1184  * * file-based: The Series is parsed up front. If no step has been
1185  * opened yet, ADIOS2 gives access to all variables and attributes
1186  * from all steps. Upon opening a step, only the variables from that
1187  * step are shown which hinders parsing. So, until a step is
1188  * explicitly opened via ADIOS2IOHandlerImpl::advance, do not open
1189  * one.
1190  * This is to enable use of ADIOS files without the Streaming API
1191  * (i.e. all iterations should be visible to the user upon opening
1192  * the Series.)
1193  * @todo Add a workflow without up-front parsing of all iterations
1194  * for file-based engines.
1195  * (This would merely be an optimization since the streaming
1196  * API still works with files as intended.)
1197  *
1198  */
1199  enum class StreamStatus
1200  {
1204  DuringStep,
1208  OutsideOfStep,
1212  StreamOver,
1229  NoStream,
1256  Parsing,
1262  Undecided
1263  };
1264  StreamStatus streamStatus = StreamStatus::OutsideOfStep;
1265  adios2::StepStatus m_lastStepStatus = adios2::StepStatus::OK;
1266 
1272  bool delayOpeningTheFirstStep = false;
1273 
1274  /*
1275  * ADIOS2 does not give direct access to its internal attribute and
1276  * variable maps, but will instead give access to copies of them.
1277  * In order to avoid unnecessary copies, we buffer the returned map.
1278  * The downside of this is that we need to pay attention to invalidate
1279  * the map whenever an attribute/variable is altered. In that case, we
1280  * fetch the map anew.
1281  * If empty, the buffered map has been invalidated and needs to be
1282  * queried from ADIOS2 again. If full, the buffered map is equivalent to
1283  * the map that would be returned by a call to
1284  * IO::Available(Attributes|Variables).
1285  */
1286  auxiliary::Option<AttributeMap_t> m_availableAttributes;
1287  auxiliary::Option<AttributeMap_t> m_availableVariables;
1288 
1289  /*
1290  * finalize() will set this true to avoid running twice.
1291  */
1292  bool finalized = false;
1293 
1294  inline SupportedSchema schema() const
1295  {
1296  return m_impl->schema();
1297  }
1298 
1299  void configure_IO(ADIOS2IOHandlerImpl &impl);
1300 
1301  using AttributeLayout = ADIOS2IOHandlerImpl::AttributeLayout;
1302  inline AttributeLayout attributeLayout() const
1303  {
1304  return m_impl->attributeLayout();
1305  }
1306  };
1307 
1308 } // namespace detail
1309 #endif // openPMD_HAVE_ADIOS2
1310 
1312 {
1313 #if openPMD_HAVE_ADIOS2
1314 
1315  friend class ADIOS2IOHandlerImpl;
1316 
1317 private:
1318  ADIOS2IOHandlerImpl m_impl;
1319 
1320 public:
1321  ~ADIOS2IOHandler() override
1322  {
1323  // we must not throw in a destructor
1324  try
1325  {
1326  this->flush(internal::defaultFlushParams);
1327  }
1328  catch (std::exception const &ex)
1329  {
1330  std::cerr << "[~ADIOS2IOHandler] An error occurred: " << ex.what()
1331  << std::endl;
1332  }
1333  catch (...)
1334  {
1335  std::cerr << "[~ADIOS2IOHandler] An error occurred." << std::endl;
1336  }
1337  }
1338 
1339 #else
1340 public:
1341 #endif
1342 
1343 #if openPMD_HAVE_MPI
1344 
1346  std::string path,
1347  Access,
1348  MPI_Comm,
1349  nlohmann::json options,
1350  std::string engineType);
1351 
1352 #endif
1353 
1355  std::string path,
1356  Access,
1357  nlohmann::json options,
1358  std::string engineType);
1359 
1360  std::string backendName() const override
1361  {
1362  return "ADIOS2";
1363  }
1364 
1365  std::future<void> flush(internal::FlushParams const &) override;
1366 }; // ADIOS2IOHandler
1367 } // namespace openPMD
Definition: ADIOS2IOHandler.hpp:65
Wrapper around a shared pointer to:
Definition: InvalidatableFile.hpp:43
Definition: ADIOS2IOHandler.hpp:550
FlushLevel
Determine what items should be flushed upon Series::flush()
Definition: AbstractIOHandler.hpp:66
Definition: ADIOS2IOHandler.hpp:967
Definition: ADIOS2IOHandler.hpp:949
Definition: ADIOS2IOHandler.hpp:455
Definition: ADIOS2IOHandler.hpp:467
Access
File access mode to use during IO.
Definition: Access.hpp:27
Definition: ADIOS2IOHandler.hpp:519
STL namespace.
std::string m_file
The full path to the file created on disk, including the containing directory and the file extension...
Definition: ADIOS2IOHandler.hpp:999
Definition: ADIOS2IOHandler.hpp:106
Definition: ADIOS2IOHandler.hpp:988
std::vector< std::unique_ptr< BufferedAction > > m_buffer
The default queue for deferred actions.
Definition: ADIOS2IOHandler.hpp:1025
Definition: ADIOS2IOHandler.hpp:933
Definition: ADIOS2IOHandler.cpp:646
AdvanceStatus
In step-based mode (i.e.
Definition: Streaming.hpp:20
Definition: ADIOS2IOHandler.hpp:77
AdvanceMode
In step-based mode (i.e.
Definition: Streaming.hpp:33
Definition: ADIOS2IOHandler.hpp:941
std::string const m_IOName
ADIOS requires giving names to instances of adios2::IO.
Definition: ADIOS2IOHandler.hpp:1018
Definition: ADIOS2IOHandler.hpp:925
Definition: ADIOS2IOHandler.hpp:957
Datatype
Concrete datatype of an object available at runtime.
Definition: Datatype.hpp:45
Definition: Container.cpp:50
Interface for communicating between logical and physically persistent data.
Definition: AbstractIOHandler.hpp:122
Simple Option type based on variantSrc::variant.
Definition: Option.hpp:45
std::map< unsigned, std::unique_ptr< I_UpdateSpan > > m_updateSpans
The base pointer of an ADIOS2 span might change after reallocations.
Definition: ADIOS2IOHandler.hpp:1059
Public definitions of openPMD-api.
Definition: Date.cpp:28
Layer to mirror structure of logical data and persistent data in file.
Definition: Writable.hpp:63
Definition: ADIOS2IOHandler.hpp:1311
Definition: ADIOS2IOHandler.hpp:505
std::string backendName() const override
The currently used backend.
Definition: ADIOS2IOHandler.hpp:1360
Class that is responsible for scheduling and buffering openPMD attribute loads from ADIOS2...
Definition: ADIOS2PreloadAttributes.hpp:63
Definition: ADIOS2IOHandler.hpp:480
Parameters recursively passed through the openPMD hierarchy when flushing.
Definition: AbstractIOHandler.hpp:103
std::vector< BufferedAttributeRead > m_attributeReads
Definition: ADIOS2IOHandler.hpp:1042
Extend nlohmann::json with tracing of which keys have been accessed by operator[]().
Definition: JSON.hpp:52
IterationEncoding
Encoding scheme of an Iterations Series&#39;.
Definition: IterationEncoding.hpp:32
Definition: Writable.hpp:44
static bool attributeUnchanged(adios2::IO &IO, std::string name, T val)
Is the attribute given by parameters name and val already defined exactly in that way within the give...
Definition: ADIOS2IOHandler.hpp:597
Definition: ADIOS2IOHandler.hpp:490
std::map< std::string, BufferedAttributeWrite > m_attributeWrites
Buffer for attributes to be written in the new (variable-based) attribute layout. ...
Definition: ADIOS2IOHandler.hpp:1036
Definition: ADIOS2IOHandler.hpp:427
Definition: ADIOS2IOHandler.hpp:974
nlohmann::json & json()
Access the underlying JSON value.
Definition: JSON.hpp:63
Definition: ADIOS2IOHandler.hpp:73
Definition: ADIOS2IOHandler.hpp:911
Definition: ADIOS2IOHandler.hpp:443
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: ADIOS2IOHandler.hpp:1049