openPMD-api
Series.hpp
1 /* Copyright 2017-2021 Fabian Koller, Axel Huebl
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/WriteIterations.hpp"
31 #include "openPMD/auxiliary/TypeTraits.hpp"
32 #include "openPMD/auxiliary/Variant.hpp"
33 #include "openPMD/backend/Attributable.hpp"
34 #include "openPMD/backend/Container.hpp"
35 #include "openPMD/backend/ParsePreference.hpp"
36 #include "openPMD/config.hpp"
37 #include "openPMD/version.hpp"
38 
39 #if openPMD_HAVE_MPI
40 #include <mpi.h>
41 #endif
42 
43 #include <cstdint> // uint64_t
44 #include <deque>
45 #include <functional>
46 #include <map>
47 #include <memory>
48 #include <optional>
49 #include <set>
50 #include <stdexcept>
51 #include <string>
52 #include <tuple>
53 #include <variant>
54 
55 // expose private and protected members for invasive testing
56 #ifndef OPENPMD_private
57 #define OPENPMD_private private:
58 #endif
59 
60 namespace openPMD
61 {
62 class ReadIterations;
63 class SeriesIterator;
64 class Series;
65 class Series;
66 
67 namespace internal
68 {
80  class SeriesData final : public AttributableData
81  {
82  public:
83  explicit SeriesData() = default;
84 
85  virtual ~SeriesData();
86 
87  SeriesData(SeriesData const &) = delete;
88  SeriesData(SeriesData &&) = delete;
89 
90  SeriesData &operator=(SeriesData const &) = delete;
91  SeriesData &operator=(SeriesData &&) = delete;
92 
93  using IterationIndex_t = Iteration::IterationIndex_t;
95  IterationsContainer_t iterations{};
96 
103  std::optional<WriteIterations> m_writeIterations;
104 
120  std::unique_ptr<SeriesIterator> m_sharedStatefulIterator;
126  std::set<IterationIndex_t> m_currentlyActiveIterations;
136  std::optional<std::string> m_overrideFilebasedFilename;
143  std::string m_name;
148  std::string m_filenamePrefix;
152  std::string m_filenamePostfix;
157  std::string m_filenameExtension;
179  StepStatus m_stepStatus = StepStatus::NoStep;
183  bool m_parseLazily = false;
184 
193 
200  std::optional<ParsePreference> m_parsePreference;
201 
202  std::optional<std::function<AbstractIOHandler *(Series &)>>
203  m_deferred_initialization = std::nullopt;
204 
205  void close();
206 
207 #if openPMD_HAVE_MPI
208  /*
209  * @todo Once we have separate MPI headers, move this there.
210  */
211  std::optional<MPI_Comm> m_communicator;
212 #endif
213 
215  {};
217  {
218  std::string value;
219  };
221  {
222  std::string value;
223  };
224 
226  {
227  Attributable m_attributable;
228  std::variant<
232  m_rankTableSource;
233  std::optional<chunk_assignment::RankMeta> m_bufferedRead;
234  };
235  RankTableData m_rankTable;
236  }; // SeriesData
237 
238  class SeriesInternal;
239 } // namespace internal
240 
250 class Series : public Attributable
251 {
252  friend class Attributable;
253  friend class Iteration;
254  friend class Writable;
255  friend class ReadIterations;
256  friend class SeriesIterator;
257  friend class internal::SeriesData;
258  friend class internal::AttributableData;
259  friend class WriteIterations;
260 
261 public:
262  explicit Series();
263 
264 #if openPMD_HAVE_MPI
277  Series(
278  std::string const &filepath,
279  Access at,
280  MPI_Comm comm,
281  std::string const &options = "{}");
282 #endif
283 
330  Series(
331  std::string const &filepath,
332  Access at,
333  std::string const &options = "{}");
334 
335  Series(Series const &) = default;
336  Series(Series &&) = default;
337 
338  Series &operator=(Series const &) = default;
339  Series &operator=(Series &&) = default;
340 
341  ~Series() override = default;
342 
346  using IterationIndex_t = Iteration::IterationIndex_t;
351  IterationsContainer_t iterations;
352 
359  operator bool() const;
360 
366  std::string openPMD() const;
375  Series &setOpenPMD(std::string const &openPMD);
376 
382  uint32_t openPMDextension() const;
392 
397  std::string basePath() const;
405  Series &setBasePath(std::string const &basePath);
406 
412  std::string meshesPath() const;
422  Series &setMeshesPath(std::string const &meshesPath);
423 
435 #if openPMD_HAVE_MPI
436  chunk_assignment::RankMeta rankTable(bool collective);
437 #else
438  chunk_assignment::RankMeta rankTable(bool collective = false);
439 #endif
440 
448  Series &setRankTable(std::string const &myRankInfo);
449 
455  std::string particlesPath() const;
465  Series &setParticlesPath(std::string const &particlesPath);
466 
472  std::string author() const;
479  Series &setAuthor(std::string const &author);
480 
486  std::string software() const;
496  std::string const &newName,
497  std::string const &newVersion = std::string("unspecified"));
498 
504  std::string softwareVersion() const;
514  [[deprecated(
515  "Set the version with the second argument of setSoftware()")]] Series &
516  setSoftwareVersion(std::string const &softwareVersion);
517 
522  std::string date() const;
528  Series &setDate(std::string const &date);
529 
535  std::string softwareDependencies() const;
543  Series &setSoftwareDependencies(std::string const &newSoftwareDependencies);
544 
550  std::string machine() const;
557  Series &setMachine(std::string const &newMachine);
558 
581 
587  std::string iterationFormat() const;
599  Series &setIterationFormat(std::string const &iterationFormat);
600 
604  std::string name() const;
605 
612  Series &setName(std::string const &name);
613 
620  std::string backend() const;
621  std::string backend();
622 
630  void flush(std::string backendConfig = "{}");
631 
648 
663  void parseBase();
664 
683 
694  void close();
695 
699  template <typename X = void, typename... Args>
700  auto iterationFlush(Args &&...)
701  {
702  static_assert(
703  auxiliary::dependent_false_v<X>,
704  "Cannot call this on an instance of Series.");
705  }
706 
707  // clang-format off
708 OPENPMD_private
709  // clang-format on
710 
711  static constexpr char const *const BASEPATH = "/data/%T/";
712 
713  struct ParsedInput;
714  using iterations_t = decltype(internal::SeriesData::iterations);
715  using iterations_iterator = iterations_t::iterator;
716 
717  using Data_t = internal::SeriesData;
718  std::shared_ptr<Data_t> m_series = nullptr;
719 
720  inline Data_t &get()
721  {
722  if (m_series)
723  {
724  return *m_series;
725  }
726  else
727  {
728  throw std::runtime_error(
729  "[Series] Cannot use default-constructed Series.");
730  }
731  }
732 
733  inline Data_t const &get() const
734  {
735  if (m_series)
736  {
737  return *m_series;
738  }
739  else
740  {
741  throw std::runtime_error(
742  "[Series] Cannot use default-constructed Series.");
743  }
744  }
745 
746  inline void setData(std::shared_ptr<internal::SeriesData> series)
747  {
748  m_series = std::move(series);
749  iterations = m_series->iterations;
750  Attributable::setData(m_series);
751  }
752 
753  std::unique_ptr<ParsedInput> parseInput(std::string);
763  template <typename TracingJSON>
764  void parseJsonOptions(TracingJSON &options, ParsedInput &);
765  bool hasExpansionPattern(std::string filenameWithExtension);
766  bool reparseExpansionPattern(std::string filenameWithExtension);
767  template <typename... MPI_Communicator>
768  void init(
769  std::string const &filepath,
770  Access at,
771  std::string const &options,
772  MPI_Communicator &&...);
773  template <typename TracingJSON, typename... MPI_Communicator>
774  std::tuple<std::unique_ptr<ParsedInput>, TracingJSON> initIOHandler(
775  std::string const &filepath,
776  std::string const &options,
777  Access at,
778  bool resolve_generic_extension,
779  MPI_Communicator &&...);
780  void initSeries(
781  std::unique_ptr<AbstractIOHandler>, std::unique_ptr<ParsedInput>);
782  void initDefaults(IterationEncoding, bool initAll = false);
794  std::future<void> flush_impl(
795  iterations_iterator begin,
796  iterations_iterator end,
797  internal::FlushParams const &flushParams,
798  bool flushIOHandler = true);
799  void flushFileBased(
800  iterations_iterator begin,
801  iterations_iterator end,
802  internal::FlushParams const &flushParams,
803  bool flushIOHandler = true);
804  /*
805  * Group-based and variable-based iteration layouts share a lot of logic
806  * (realistically, the variable-based iteration layout only throws out
807  * one layer in the hierarchy).
808  * As a convention, methods that deal with both layouts are called
809  * .*GorVBased, short for .*GroupOrVariableBased
810  */
811  void flushGorVBased(
812  iterations_iterator begin,
813  iterations_iterator end,
814  internal::FlushParams const &flushParams,
815  bool flushIOHandler = true);
816  void flushMeshesPath();
817  void flushParticlesPath();
818  void flushRankTable();
819  void readFileBased();
820  void readOneIterationFileBased(std::string const &filePath);
834  std::optional<std::deque<IterationIndex_t>> readGorVBased(
835  bool do_always_throw_errors,
836  bool init,
837  std::set<IterationIndex_t> const &ignoreIterations = {});
838  void readBase();
839  std::string iterationFilename(IterationIndex_t i);
840 
841  enum class IterationOpened : bool
842  {
843  HasBeenOpened,
844  RemainsClosed
845  };
846  /*
847  * For use by flushFileBased, flushGorVBased
848  * Open an iteration, but only if necessary.
849  * Only open if the iteration is dirty and if it is not in deferred
850  * parse state.
851  */
852  IterationOpened
853  openIterationIfDirty(IterationIndex_t index, Iteration iteration);
854  /*
855  * Open an iteration. Ensures that the iteration's m_closed status
856  * is set properly and that any files pertaining to the iteration
857  * is opened.
858  * Does not create files when called in CREATE mode.
859  */
860  void openIteration(IterationIndex_t index, Iteration iteration);
861 
866  iterations_iterator indexOf(Iteration const &);
867 
884  AdvanceMode mode,
885  internal::AttributableData &file,
886  iterations_iterator it,
887  Iteration &iteration);
888 
890 
898  void flushStep(bool doFlush);
899 
900  /*
901  * Returns the current content of the /data/snapshot attribute.
902  * (We could also add this to the public API some time)
903  */
904  std::optional<std::vector<IterationIndex_t>> currentSnapshot() const;
905 
906  AbstractIOHandler *runDeferredInitialization();
907 
908  AbstractIOHandler *IOHandler();
909  AbstractIOHandler const *IOHandler() const;
910 }; // Series
911 
912 namespace debug
913 {
914  void printDirty(Series const &);
915 }
916 } // namespace openPMD
917 
918 // Make sure that this one is always included if Series.hpp is included,
919 // otherwise Series::readIterations() cannot be used
920 #include "openPMD/ReadIterations.hpp"
Interface for communicating between logical and physically persistent data.
Definition: AbstractIOHandler.hpp:186
Layer to manage storage of attributes associated with file objects.
Definition: Attributable.hpp:155
Logical compilation of data from one snapshot (e.g.
Definition: Iteration.hpp:127
Reading side of the streaming API.
Definition: ReadIterations.hpp:162
Implementation for the root level of the openPMD hierarchy.
Definition: Series.hpp:251
Series & setName(std::string const &name)
Set the pattern for file names.
Definition: Series.cpp:642
std::string softwareVersion() const
Definition: Series.cpp:513
std::optional< std::deque< IterationIndex_t > > readGorVBased(bool do_always_throw_errors, bool init, std::set< IterationIndex_t > const &ignoreIterations={})
Note on re-parsing of a Series: If init == false, the parsing process will seek for new Iterations/Re...
Definition: Series.cpp:1866
Series & setMeshesPath(std::string const &meshesPath)
Set the path to mesh records, relative(!) to basePath.
Definition: Series.cpp:178
std::string iterationFormat() const
Definition: Series.cpp:607
void flush(std::string backendConfig="{}")
Execute all required remaining IO operations to write or read data.
Definition: Series.cpp:691
auto iterationFlush(Args &&...)
This overrides Attributable::iterationFlush() which will fail on Series.
Definition: Series.hpp:700
void parseBase()
Parse the Series.
Definition: Series.cpp:2920
std::string basePath() const
Definition: Series.cpp:157
Series & setSoftwareDependencies(std::string const &newSoftwareDependencies)
Indicate dependencies of software that were used to create the file.
Definition: Series.cpp:541
iterations_iterator indexOf(Iteration const &)
Find the given iteration in Series::iterations and return an iterator into Series::iterations at that...
Definition: Series.cpp:2307
Iteration::IterationIndex_t IterationIndex_t
An unsigned integer type, used to identify Iterations in a Series.
Definition: Series.hpp:346
Series & setParticlesPath(std::string const &particlesPath)
Set the path to groups for each particle species, relative(!) to basePath.
Definition: Series.cpp:468
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:1239
std::string machine() const
Definition: Series.cpp:547
std::string date() const
Definition: Series.cpp:524
WriteIterations writeIterations()
Entry point to the writing end of the streaming API.
Definition: Series.cpp:2925
std::string backend() const
The currently used backend.
Definition: Series.cpp:680
void close()
Close the Series and release the data storage/transport backends.
Definition: Series.cpp:2939
Series & setOpenPMD(std::string const &openPMD)
Set the version of the enforced openPMD standard.
Definition: Series.cpp:140
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:2519
std::string openPMD() const
Definition: Series.cpp:135
Series & setAuthor(std::string const &author)
Indicate the author and contact for the information in the file.
Definition: Series.cpp:494
Series & setSoftwareVersion(std::string const &softwareVersion)
Indicate the version of the software/code/simulation that created the file.
Definition: Series.cpp:518
std::string author() const
Definition: Series.cpp:489
std::string meshesPath() const
Definition: Series.cpp:173
Series & setMachine(std::string const &newMachine)
Indicate the machine or relevant hardware that created the file.
Definition: Series.cpp:552
std::string software() const
Definition: Series.cpp:500
uint32_t openPMDextension() const
Definition: Series.cpp:146
chunk_assignment::RankMeta rankTable(bool collective)
Definition: Series.cpp:200
Series & setBasePath(std::string const &basePath)
Set the common prefix for all data sets and sub-groups of a specific iteration.
Definition: Series.cpp:162
Series & setRankTable(std::string const &myRankInfo)
Set the Mpi Ranks Meta Info attribute, i.e.
Definition: Series.cpp:335
void parseJsonOptions(TracingJSON &options, ParsedInput &)
Parse non-backend-specific configuration in JSON config.
Definition: Series.cpp:2729
std::string particlesPath() const
Definition: Series.cpp:463
AdvanceStatus advance(AdvanceMode mode, internal::AttributableData &file, iterations_iterator it, Iteration &iteration)
In step-based IO mode, begin or end an IO step for the given iteration.
Definition: Series.cpp:2322
Series & setDate(std::string const &date)
Indicate the date of creation.
Definition: Series.cpp:529
std::string name() const
Definition: Series.cpp:637
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:506
std::string softwareDependencies() const
Definition: Series.cpp:535
ReadIterations readIterations()
Entry point to the reading end of the streaming API.
Definition: Series.cpp:2910
Series & setOpenPMDextension(uint32_t openPMDextension)
Set a 32-bit mask of applied extensions to the openPMD standard.
Definition: Series.cpp:151
Series & setIterationEncoding(IterationEncoding iterationEncoding)
Set the encoding style for multiple iterations in this series.
Definition: Series.cpp:563
IterationEncoding iterationEncoding() const
Definition: Series.cpp:558
Series & setIterationFormat(std::string const &iterationFormat)
Set a pattern describing how to access single iterations in the raw file.
Definition: Series.cpp:612
Definition: ReadIterations.hpp:35
Layer to mirror structure of logical data and persistent data in file.
Definition: Writable.hpp:75
Writing side of the streaming API.
Definition: WriteIterations.hpp:67
Definition: Attributable.hpp:60
Data members for Series.
Definition: Series.hpp:81
std::string m_filenamePrefix
Filename leading up to the expansion pattern.
Definition: Series.hpp:148
std::set< IterationIndex_t > m_currentlyActiveIterations
For writing: Remember which iterations have been written in the currently active output step.
Definition: Series.hpp:126
std::unique_ptr< SeriesIterator > m_sharedStatefulIterator
Series::readIterations() returns an iterator type that modifies the state of the Series (by proceedin...
Definition: Series.hpp:120
std::optional< std::string > m_overrideFilebasedFilename
Needed if reading a single iteration of a file-based series.
Definition: Series.hpp:136
StepStatus m_stepStatus
Whether a step is currently active for this iteration.
Definition: Series.hpp:179
std::optional< WriteIterations > m_writeIterations
For each instance of Series, there is only one instance of WriteIterations, stored in this Option.
Definition: Series.hpp:103
std::string m_name
Name of the iteration without filename suffix.
Definition: Series.hpp:143
std::optional< ParsePreference > m_parsePreference
Remember the preference that the backend specified for parsing.
Definition: Series.hpp:200
std::string m_filenamePostfix
Filename after the expansion pattern without filename extension.
Definition: Series.hpp:152
int m_filenamePadding
The padding in file-based iteration encoding.
Definition: Series.hpp:163
bool m_parseLazily
True if a user opts into lazy parsing.
Definition: Series.hpp:183
bool m_wroteAtLeastOneIOStep
In variable-based encoding, all backends except ADIOS2 can only write one single iteration.
Definition: Series.hpp:192
std::string m_filenameExtension
Filename extension as specified by the user.
Definition: Series.hpp:157
IterationEncoding m_iterationEncoding
The iteration encoding used in this series.
Definition: Series.hpp:167
Format m_format
Detected IO format (backend).
Definition: Series.hpp:171
Public definitions of openPMD-api.
Definition: Date.cpp:29
Access
File access mode to use during IO.
Definition: Access.hpp:30
AdvanceMode
In step-based mode (i.e.
Definition: Streaming.hpp:35
StepStatus
Used in step-based mode (i.e.
Definition: Streaming.hpp:46
AdvanceStatus
In step-based mode (i.e.
Definition: Streaming.hpp:21
Format
File format to use during IO.
Definition: Format.hpp:30
IterationEncoding
Encoding scheme of an Iterations Series'.
Definition: IterationEncoding.hpp:33