openPMD-api
ReadIterations.hpp
1 /* Copyright 2021 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/Iteration.hpp"
24 #include "openPMD/Series.hpp"
25 #include "openPMD/backend/ParsePreference.hpp"
26 
27 #include <deque>
28 #include <iostream>
29 #include <optional>
30 #include <set>
31 
32 namespace openPMD
33 {
39 {
40  friend class SeriesIterator;
41 
42 public:
43  using iterations_t = decltype(internal::SeriesData::iterations);
44  using index_t = iterations_t::key_type;
45  index_t const iterationIndex;
46 
47 private:
48  template <typename Iteration_t>
49  IndexedIteration(Iteration_t &&it, index_t index)
50  : Iteration(std::forward<Iteration_t>(it)), iterationIndex(index)
51  {}
52 };
53 
55 {
56  using iteration_index_t = IndexedIteration::index_t;
57 
58  using maybe_series_t = std::optional<Series>;
59 
60  struct SharedData
61  {
62  SharedData() = default;
63  SharedData(SharedData const &) = delete;
64  SharedData(SharedData &&) = delete;
65  SharedData &operator=(SharedData const &) = delete;
66  SharedData &operator=(SharedData &&) = delete;
67 
68  maybe_series_t series;
69  std::deque<iteration_index_t> iterationsInCurrentStep;
70  uint64_t currentIteration{};
71  std::optional<internal::ParsePreference> parsePreference;
72  /*
73  * Necessary because in the old ADIOS2 schema, old iterations' metadata
74  * will leak into new steps, making the frontend think that the groups
75  * are still there and the iterations can be parsed again.
76  */
77  std::set<Iteration::IterationIndex_t> ignoreIterations;
78  };
79 
80  /*
81  * The shared data is never empty, emptiness is indicated by std::optional
82  */
83  std::shared_ptr<std::optional<SharedData>> m_data =
84  std::make_shared<std::optional<SharedData>>(std::nullopt);
85 
86  SharedData &get()
87  {
88  return m_data->value();
89  }
90  SharedData const &get() const
91  {
92  return m_data->value();
93  }
94 
95 public:
97  explicit SeriesIterator();
98 
100  Series, std::optional<internal::ParsePreference> parsePreference);
101 
102  SeriesIterator &operator++();
103 
104  IndexedIteration operator*();
105 
106  bool operator==(SeriesIterator const &other) const;
107 
108  bool operator!=(SeriesIterator const &other) const;
109 
110  static SeriesIterator end();
111 
112 private:
113  inline bool setCurrentIteration()
114  {
115  auto &data = get();
116  if (data.iterationsInCurrentStep.empty())
117  {
118  std::cerr << "[ReadIterations] Encountered a step without "
119  "iterations. Closing the Series."
120  << std::endl;
121  *this = end();
122  return false;
123  }
124  data.currentIteration = *data.iterationsInCurrentStep.begin();
125  return true;
126  }
127 
128  inline std::optional<uint64_t> peekCurrentIteration()
129  {
130  auto &data = get();
131  if (data.iterationsInCurrentStep.empty())
132  {
133  return std::nullopt;
134  }
135  else
136  {
137  return {*data.iterationsInCurrentStep.begin()};
138  }
139  }
140 
141  std::optional<SeriesIterator *> nextIterationInStep();
142 
143  /*
144  * When a step cannot successfully be opened, the method nextStep() calls
145  * itself again recursively.
146  * (Recursion massively simplifies the logic here, and it only happens
147  * in case of error.)
148  * After successfully beginning a step, this methods needs to remember, how
149  * many broken steps have been skipped. In case the Series does not use
150  * the /data/snapshot attribute, this helps figuring out which iteration
151  * is now active. Hence, recursion_depth.
152  */
153  std::optional<SeriesIterator *> nextStep(size_t recursion_depth);
154 
155  std::optional<SeriesIterator *> loopBody();
156 
157  void deactivateDeadIteration(iteration_index_t);
158 
159  void initSeriesInLinearReadMode();
160 
161  void close();
162 };
163 
181 {
182  friend class Series;
183 
184 private:
185  using iterations_t = decltype(internal::SeriesData::iterations);
186  using iterator_t = SeriesIterator;
187 
188  Series m_series;
189  std::optional<internal::ParsePreference> m_parsePreference;
190 
192  Series,
193  Access,
194  std::optional<internal::ParsePreference> parsePreference);
195 
196 public:
197  iterator_t begin();
198 
199  iterator_t end();
200 };
201 } // namespace openPMD
Subclass of Iteration that knows its own index withing the containing Series.
Definition: ReadIterations.hpp:39
Logical compilation of data from one snapshot (e.g.
Definition: Iteration.hpp:127
Reading side of the streaming API.
Definition: ReadIterations.hpp:181
Implementation for the root level of the openPMD hierarchy.
Definition: Series.hpp:206
Definition: ReadIterations.hpp:55
SeriesIterator()
construct the end() iterator
Public definitions of openPMD-api.
Definition: Date.cpp:29
Access
File access mode to use during IO.
Definition: Access.hpp:30