openPMD-api
Series.hpp
1 /* Copyright 2017-2025 Fabian Koller, Axel Huebl, Franz Poeschel, Luca Fedeli
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/Error.hpp"
24 #include "openPMD/IO/AbstractIOHandler.hpp"
25 #include "openPMD/IO/Access.hpp"
26 #include "openPMD/IO/Format.hpp"
27 #include "openPMD/Iteration.hpp"
28 #include "openPMD/IterationEncoding.hpp"
29 #include "openPMD/Streaming.hpp"
30 #include "openPMD/auxiliary/TypeTraits.hpp"
31 #include "openPMD/auxiliary/Variant.hpp"
32 #include "openPMD/backend/Attributable.hpp"
33 #include "openPMD/backend/Container.hpp"
34 #include "openPMD/backend/HierarchyVisitor.hpp"
35 #include "openPMD/backend/ParsePreference.hpp"
36 #include "openPMD/config.hpp"
37 #include "openPMD/snapshots/Snapshots.hpp"
38 #include "openPMD/version.hpp"
39 
40 #if openPMD_HAVE_MPI
41 #include <mpi.h>
42 #endif
43 
44 #include <cstdint> // uint64_t
45 #include <deque>
46 #include <functional>
47 #include <map>
48 #include <memory>
49 #include <optional>
50 #include <set>
51 #include <stdexcept>
52 #include <string>
53 #include <tuple>
54 #include <unordered_map>
55 #include <variant>
56 #include <vector>
57 
58 // expose private and protected members for invasive testing
59 #ifndef OPENPMD_private
60 #define OPENPMD_private private:
61 #endif
62 
63 namespace openPMD
64 {
65 class ReadIterations;
66 class StatefulIterator;
67 class Series;
68 
69 namespace internal
70 {
71  /* Just a more self-documenting boolean used for
72  * m_iterationEncodingSetExplicitly */
73  enum class default_or_explicit : bool
74  {
75  default_,
76  explicit_
77  };
89  class SeriesData final : public AttributableData
90  {
91  public:
92  explicit SeriesData() = default;
93 
94  virtual ~SeriesData();
95 
96  SeriesData(SeriesData const &) = delete;
97  SeriesData(SeriesData &&) = delete;
98 
99  SeriesData &operator=(SeriesData const &) = delete;
100  SeriesData &operator=(SeriesData &&) = delete;
101 
102  using IterationIndex_t = Iteration::IterationIndex_t;
104  Iterations iterations{};
105 
121  std::unique_ptr<StatefulIterator> m_sharedStatefulIterator;
127  std::set<IterationIndex_t> m_currentlyActiveIterations;
131  std::unordered_map<IterationIndex_t, size_t> m_snapshotToStep;
151  std::unordered_map<IterationIndex_t, std::string> m_iterationFilenames;
161  std::optional<std::string> m_overrideFilebasedFilename;
168  std::string m_name;
173  std::string m_filenamePrefix;
177  std::string m_filenamePostfix;
182  std::string m_filenameExtension;
193  /*
194  * ADIOS2 should use variable-based encoding as default rather than
195  * group-based encoding as much as possible.
196  * Since this cannot be decided at construction time, groupBased
197  * encoding is selected first, and re-decided later.
198  * However, when group-based encoding is selected by the user explcitly,
199  * that selection should not be changed again.
200  * Hence, remember that here.
201  */
202  default_or_explicit m_iterationEncodingSetExplicitly =
203  default_or_explicit::default_;
215  StepStatus m_stepStatus = StepStatus::NoStep;
219  bool m_parseLazily = false;
220  uint64_t m_hintLazyParsingAfterTimeout = 20; // seconds
221 
230 
237  std::optional<ParsePreference> m_parsePreference;
238 
239  std::optional<std::function<AbstractIOHandler *(Series &)>>
240  m_deferred_initialization = std::nullopt;
241 
242  void close();
243 
244 #if openPMD_HAVE_MPI
245  /*
246  * @todo Once we have separate MPI headers, move this there.
247  */
248  std::optional<MPI_Comm> m_communicator;
249 #endif
250 
252  {};
254  {
255  std::string value;
256  };
258  {
259  std::string value;
260  };
261 
263  {
264  Attributable m_attributable;
265  std::variant<
269  m_rankTableSource;
270  std::optional<chunk_assignment::RankMeta> m_bufferedRead;
271  };
272  RankTableData m_rankTable;
273  }; // SeriesData
274 
275  class SeriesInternal;
276 } // namespace internal
277 
287 class Series : public Attributable
288 {
289  friend class Attributable;
290  friend class Iteration;
291  friend class Writable;
292  friend class ReadIterations;
293  friend class StatefulIterator;
294  friend class internal::SeriesData;
295  friend class internal::AttributableData;
296  friend class StatefulSnapshotsContainer;
297  template <typename T, typename Series_type>
298  friend T &internal::makeOwning(T &self, Series_type);
299 
300 public:
301  explicit Series();
302 
303 #if openPMD_HAVE_MPI
316  Series(
317  std::string const &filepath,
318  Access at,
319  MPI_Comm comm,
320  std::string const &options = "{}");
321 #endif
322 
369  Series(
370  std::string const &filepath,
371  Access at,
372  std::string const &options = "{}");
373 
374  Series(Series const &) = default;
375  Series(Series &&) = default;
376 
377  Series &operator=(Series const &) = default;
378  Series &operator=(Series &&) = default;
379 
380  ~Series() override = default;
381 
385  using IterationIndex_t = Iteration::IterationIndex_t;
390  Iterations iterations;
391 
398  operator bool() const;
399 
405  std::string openPMD() const;
414  Series &setOpenPMD(std::string const &openPMD);
415 
421  uint32_t openPMDextension() const;
431 
436  std::string basePath() const;
444  Series &setBasePath(std::string const &basePath);
445 
451  std::string meshesPath() const;
461  Series &setMeshesPath(std::string const &meshesPath);
462 
473  bool hasRankTableRead();
474 
486 #if openPMD_HAVE_MPI
487  chunk_assignment::RankMeta rankTable(bool collective);
488 #else
489  chunk_assignment::RankMeta rankTable(bool collective = false);
490 #endif
491 
499  Series &setRankTable(std::string const &myRankInfo);
500 
506  std::string particlesPath() const;
516  Series &setParticlesPath(std::string const &particlesPath);
517 
523  std::string author() const;
530  Series &setAuthor(std::string const &author);
531 
537  std::string software() const;
547  std::string const &newName,
548  std::string const &newVersion = std::string("unspecified"));
549 
555  std::string softwareVersion() const;
565  [[deprecated(
566  "Set the version with the second argument of setSoftware()")]] Series &
567  setSoftwareVersion(std::string const &softwareVersion);
568 
573  std::string date() const;
579  Series &setDate(std::string const &date);
580 
586  std::string softwareDependencies() const;
594  Series &setSoftwareDependencies(std::string const &newSoftwareDependencies);
595 
601  std::string machine() const;
608  Series &setMachine(std::string const &newMachine);
609 
632 
638  std::string iterationFormat() const;
650  Series &setIterationFormat(std::string const &iterationFormat);
651 
655  std::string name() const;
656 
663  Series &setName(std::string const &name);
664 
671  std::string backend() const;
672  std::string backend();
673 
681  void flush(std::string backendConfig = "{}");
682 
699 
743 
758  void parseBase();
759 
770 
781  void close();
782 
783  [[nodiscard]] bool closed() const;
784 
785  void visitHierarchy(HierarchyVisitor &v, bool recursive) override;
786 
790  template <typename X = void, typename... Args>
791  auto iterationFlush(Args &&...)
792  {
793  static_assert(
794  auxiliary::dependent_false_v<X>,
795  "Cannot call this on an instance of Series.");
796  }
797 
798  // clang-format off
799 OPENPMD_private
800  // clang-format on
801 
802  static constexpr char const *const BASEPATH = "/data/%T/";
803 
804  struct ParsedInput;
805  using iterations_t = decltype(internal::SeriesData::iterations);
806  using iterations_iterator = iterations_t::iterator;
807 
808  using Data_t = internal::SeriesData;
809  std::shared_ptr<Data_t> m_series = nullptr;
810 
811  inline std::shared_ptr<Data_t> getShared()
812  {
813  return m_series;
814  }
815 
816  inline Data_t &get()
817  {
818  if (m_series)
819  {
820  return *m_series;
821  }
822  else
823  {
824  throw std::runtime_error(
825  "[Series] Cannot use default-constructed Series.");
826  }
827  }
828 
829  inline Data_t const &get() const
830  {
831  if (m_series)
832  {
833  return *m_series;
834  }
835  else
836  {
837  throw std::runtime_error(
838  "[Series] Cannot use default-constructed Series.");
839  }
840  }
841 
842  inline void setData(std::shared_ptr<internal::SeriesData> series)
843  {
844  m_series = std::move(series);
845  iterations = m_series->iterations;
846  Attributable::setData(m_series);
847  }
848 
849  std::unique_ptr<ParsedInput> parseInput(std::string);
859  template <typename TracingJSON>
860  void parseJsonOptions(TracingJSON &options, ParsedInput &);
861  bool hasExpansionPattern(std::string filenameWithExtension);
862  bool reparseExpansionPattern(std::string filenameWithExtension);
863  template <typename... MPI_Communicator>
864  void init(
865  std::string const &filepath,
866  Access at,
867  std::string const &options,
868  MPI_Communicator &&...);
869  template <typename TracingJSON, typename... MPI_Communicator>
870  std::tuple<std::unique_ptr<ParsedInput>, TracingJSON> initIOHandler(
871  std::string const &filepath,
872  std::string const &options,
873  Access at,
874  bool resolve_generic_extension,
875  MPI_Communicator &&...);
876  void initSeries(
877  std::unique_ptr<AbstractIOHandler>, std::unique_ptr<ParsedInput>);
878  void initDefaults(IterationEncoding, bool initAll = false);
890  std::future<void> flush_impl(
891  iterations_iterator begin,
892  iterations_iterator end,
893  internal::FlushParams const &flushParams,
894  bool flushIOHandler = true);
895  void flushFileBased(
896  iterations_iterator begin,
897  iterations_iterator end,
898  internal::FlushParams const &flushParams,
899  bool flushIOHandler = true);
900  /*
901  * Group-based and variable-based iteration layouts share a lot of logic
902  * (realistically, the variable-based iteration layout only throws out
903  * one layer in the hierarchy).
904  * As a convention, methods that deal with both layouts are called
905  * .*GorVBased, short for .*GroupOrVariableBased
906  */
907  void flushGorVBased(
908  iterations_iterator begin,
909  iterations_iterator end,
910  internal::FlushParams const &flushParams,
911  bool flushIOHandler = true);
912  void flushMeshesPath();
913  void flushParticlesPath();
914  void flushRankTable();
915  /* Parameter `read_only_this_single_iteration` used for reopening an
916  * Iteration after closing it.
917  */
918  void readFileBased(
919  std::optional<IterationIndex_t> read_only_this_single_iteration);
920  void readOneIterationFileBased(std::string const &filePath);
936  std::vector<IterationIndex_t> readGorVBased(
937  bool do_always_throw_errors,
938  bool init,
939  std::optional<IterationIndex_t> read_only_this_single_iteration);
940  void readBase();
941  std::string iterationFilename(IterationIndex_t i);
942 
943  enum class IterationOpened : bool
944  {
945  HasBeenOpened,
946  RemainsClosed
947  };
948  /*
949  * For use by flushFileBased, flushGorVBased
950  * Open an iteration, but only if necessary.
951  * Only open if the iteration is dirty and if it is not in deferred
952  * parse state.
953  */
954  IterationOpened
955  openIterationIfDirty(IterationIndex_t index, Iteration &iteration);
956  /*
957  * Open an iteration. Ensures that the iteration's m_closed status
958  * is set properly and that any files pertaining to the iteration
959  * is opened.
960  * Does not create files when called in CREATE mode.
961  */
962  void openIteration(IterationIndex_t index, Iteration &iteration);
963 
968  iterations_iterator indexOf(Iteration const &);
969 
985  AdvanceMode mode,
986  internal::AttributableData &file,
987  iterations_iterator it);
988 
990 
998  void flushStep(bool doFlush);
999 
1000  /*
1001  * setIterationEncoding() should only be called by users of our public API,
1002  * but never internally. We need to distinguish if the iteration encoding
1003  * was selected explicitly or implicitly, see
1004  * m_iterationEncodingSetExplicitly for further details.
1005  */
1006  Series &setIterationEncoding_internal(
1007  IterationEncoding iterationEncoding, internal::default_or_explicit);
1008 
1009  /*
1010  * Returns the current content of the /data/snapshot attribute.
1011  * (We could also add this to the public API some time)
1012  */
1013  std::optional<std::vector<IterationIndex_t>> currentSnapshot();
1014 
1015  AbstractIOHandler *runDeferredInitialization();
1016 
1017  AbstractIOHandler *IOHandler();
1018  AbstractIOHandler const *IOHandler() const;
1019 
1020  /* adios2::Mode::ReadRandomAccess does not support reading modifiable
1021  * attributes. However, we need the values of /data/snapshot as a modifiable
1022  * attribute, so this function quickly opens the file in adios2::Mode::Read
1023  * and retrieves the changings values over time.
1024  * Return std::nullopt if /data/snapshot is not present.
1025  */
1026  std::optional<std::vector<std::vector<IterationIndex_t>>>
1027  preparseSnapshots();
1028 
1029  Snapshots makeRandomAccessSnapshots();
1030  Snapshots makeSynchronousSnapshots();
1031  /* Should adios2::Variable<T>::SetStepSelection() be used for accessing
1032  * steps?
1033  */
1034  [[nodiscard]] bool randomAccessSteps() const;
1035 
1036  std::vector<std::string> availableDatasets();
1037 }; // Series
1038 
1039 namespace debug
1040 {
1041  void printDirty(Series const &);
1042 }
1043 } // namespace openPMD
1044 
1045 // Make sure that this legacy header is always included if Series.hpp is
1046 // included, otherwise Series::readIterations() cannot be used
1047 #include "openPMD/ReadIterations.hpp"
Interface for communicating between logical and physically persistent data.
Definition: AbstractIOHandler.hpp:206
Layer to manage storage of attributes associated with file objects.
Definition: Attributable.hpp:225
Definition: HierarchyVisitor.hpp:20
Logical compilation of data from one snapshot (e.g.
Definition: Iteration.hpp:172
Definition: Iteration.hpp:543
Legacy class as return type for Series::readIterations().
Definition: ReadIterations.hpp:75
Implementation for the root level of the openPMD hierarchy.
Definition: Series.hpp:288
Series & setName(std::string const &name)
Set the pattern for file names.
Definition: Series.cpp:736
std::string softwareVersion() const
Definition: Series.cpp:644
Series & setMeshesPath(std::string const &meshesPath)
Set the path to mesh records, relative(!) to basePath.
Definition: Series.cpp:275
std::string iterationFormat() const
Definition: Series.cpp:700
void flush(std::string backendConfig="{}")
Execute all required remaining IO operations to write or read data.
Definition: Series.cpp:785
auto iterationFlush(Args &&...)
This overrides Attributable::iterationFlush() which will fail on Series.
Definition: Series.hpp:791
void parseBase()
Parse the Series.
Definition: Series.cpp:3534
std::string basePath() const
Definition: Series.cpp:249
Series & setSoftwareDependencies(std::string const &newSoftwareDependencies)
Indicate dependencies of software that were used to create the file.
Definition: Series.cpp:672
iterations_iterator indexOf(Iteration const &)
Find the given iteration in Series::iterations and return an iterator into Series::iterations at that...
Definition: Series.cpp:2603
Iteration::IterationIndex_t IterationIndex_t
An unsigned integer type, used to identify Iterations in a Series.
Definition: Series.hpp:385
Series & setParticlesPath(std::string const &particlesPath)
Set the path to groups for each particle species, relative(!) to basePath.
Definition: Series.cpp:599
std::future< void > flush_impl(iterations_iterator begin, iterations_iterator end, internal::FlushParams const &flushParams, bool flushIOHandler=true)
Internal call for flushing a Series.
Definition: Series.cpp:1369
std::string machine() const
Definition: Series.cpp:678
std::string date() const
Definition: Series.cpp:655
WriteIterations writeIterations()
Entry point to the writing end of the streaming API.
Definition: Series.cpp:3539
std::string backend() const
The currently used backend.
Definition: Series.cpp:774
void close()
Close the Series and release the data storage/transport backends.
Definition: Series.cpp:3555
Series & setOpenPMD(std::string const &openPMD)
Set the version of the enforced openPMD standard.
Definition: Series.cpp:226
void flushStep(bool doFlush)
Called at the end of an IO step to store the iterations defined in the IO step to the snapshot attrib...
Definition: Series.cpp:2826
std::string openPMD() const
Definition: Series.cpp:221
Series & setAuthor(std::string const &author)
Indicate the author and contact for the information in the file.
Definition: Series.cpp:625
Snapshots snapshots()
Preferred way to access Iterations/Snapshots.
Definition: Series.cpp:3424
Series & setSoftwareVersion(std::string const &softwareVersion)
Indicate the version of the software/code/simulation that created the file.
Definition: Series.cpp:649
AdvanceStatus advance(AdvanceMode mode, internal::AttributableData &file, iterations_iterator it)
In step-based IO mode, begin or end an IO step for the given iteration.
Definition: Series.cpp:2627
void visitHierarchy(HierarchyVisitor &v, bool recursive) override
Visitor pattern for the openPMD object hierarchy in postfix traversal.
Definition: Series.cpp:3575
std::string author() const
Definition: Series.cpp:620
std::string meshesPath() const
Definition: Series.cpp:270
Series & setMachine(std::string const &newMachine)
Indicate the machine or relevant hardware that created the file.
Definition: Series.cpp:683
std::string software() const
Definition: Series.cpp:631
std::vector< IterationIndex_t > readGorVBased(bool do_always_throw_errors, bool init, std::optional< IterationIndex_t > read_only_this_single_iteration)
Note on re-parsing of a Series: If init == false, the parsing process will seek for new Iterations/Re...
Definition: Series.cpp:2072
uint32_t openPMDextension() const
Definition: Series.cpp:238
chunk_assignment::RankMeta rankTable(bool collective)
Definition: Series.cpp:329
Series & setBasePath(std::string const &basePath)
Set the common prefix for all data sets and sub-groups of a specific iteration.
Definition: Series.cpp:254
bool hasRankTableRead()
Definition: Series.cpp:312
Series & setRankTable(std::string const &myRankInfo)
Set the Mpi Ranks Meta Info attribute, i.e.
Definition: Series.cpp:460
void parseJsonOptions(TracingJSON &options, ParsedInput &)
Parse non-backend-specific configuration in JSON config.
Definition: Series.cpp:3163
std::string particlesPath() const
Definition: Series.cpp:594
Series & setDate(std::string const &date)
Indicate the date of creation.
Definition: Series.cpp:660
std::string name() const
Definition: Series.cpp:731
Series & setSoftware(std::string const &newName, std::string const &newVersion=std::string("unspecified"))
Indicate the software/code/simulation that created the file.
Definition: Series.cpp:637
std::string softwareDependencies() const
Definition: Series.cpp:666
ReadIterations readIterations()
Entry point to the reading end of the streaming API.
Definition: Series.cpp:3376
Series & setOpenPMDextension(uint32_t openPMDextension)
Set a 32-bit mask of applied extensions to the openPMD standard.
Definition: Series.cpp:243
Series & setIterationEncoding(IterationEncoding iterationEncoding)
Set the encoding style for multiple iterations in this series.
Definition: Series.cpp:694
IterationEncoding iterationEncoding() const
Definition: Series.cpp:689
Series & setIterationFormat(std::string const &iterationFormat)
Set a pattern describing how to access single iterations in the raw file.
Definition: Series.cpp:705
Entry point for accessing Snapshots/Iterations.
Definition: Snapshots.hpp:50
Based on the logic of the former class ReadIterations, integrating into itself the logic of former Wr...
Definition: StatefulIterator.hpp:204
Definition: ContainerImpls.hpp:36
Layer to mirror structure of logical data and persistent data in file.
Definition: Writable.hpp:77
Definition: Attributable.hpp:110
Data members for Series.
Definition: Series.hpp:90
std::unordered_map< IterationIndex_t, size_t > m_snapshotToStep
For reading: In which IO step do I need to look for an Iteration?
Definition: Series.hpp:131
std::unique_ptr< StatefulIterator > m_sharedStatefulIterator
Series::readIterations() returns an iterator type that modifies the state of the Series (by proceedin...
Definition: Series.hpp:121
std::string m_filenamePrefix
Filename leading up to the expansion pattern.
Definition: Series.hpp:173
std::set< IterationIndex_t > m_currentlyActiveIterations
For writing: Remember which iterations have been written in the currently active output step.
Definition: Series.hpp:127
std::unordered_map< IterationIndex_t, std::string > m_iterationFilenames
This map contains the filenames of those Iterations which were found on the file system upon opening ...
Definition: Series.hpp:151
std::optional< std::string > m_overrideFilebasedFilename
Needed if reading a single iteration of a file-based series.
Definition: Series.hpp:161
StepStatus m_stepStatus
Whether a step is currently active for this iteration.
Definition: Series.hpp:215
std::string m_name
Name of the iteration without filename suffix.
Definition: Series.hpp:168
std::optional< ParsePreference > m_parsePreference
Remember the preference that the backend specified for parsing.
Definition: Series.hpp:237
std::string m_filenamePostfix
Filename after the expansion pattern without filename extension.
Definition: Series.hpp:177
int m_filenamePadding
The padding in file-based iteration encoding.
Definition: Series.hpp:188
bool m_parseLazily
True if a user opts into lazy parsing.
Definition: Series.hpp:219
bool m_wroteAtLeastOneIOStep
In variable-based encoding, all backends except ADIOS2 can only write one single iteration.
Definition: Series.hpp:229
std::string m_filenameExtension
Filename extension as specified by the user.
Definition: Series.hpp:182
IterationEncoding m_iterationEncoding
The iteration encoding used in this series.
Definition: Series.hpp:192
Format m_format
Detected IO format (backend).
Definition: Series.hpp:207
Public definitions of openPMD-api.
Definition: Date.cpp:29
Access
File access mode to use during IO.
Definition: Access.hpp:58
AdvanceMode
In step-based mode (i.e.
Definition: Streaming.hpp:46
StepStatus
Used in step-based mode (i.e.
Definition: Streaming.hpp:57
AdvanceStatus
In step-based mode (i.e.
Definition: Streaming.hpp:32
Format
File format to use during IO.
Definition: Format.hpp:30
IterationEncoding
Encoding scheme of an Iterations Series'.
Definition: IterationEncoding.hpp:33