ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_IntervalMeansCheckpoint.H
Go to the documentation of this file.
1 #ifndef ERF_INTERVAL_MEANS_CHECKPOINT_H_
2 #define ERF_INTERVAL_MEANS_CHECKPOINT_H_
3 
4 #include <cmath>
5 #include <istream>
6 #include <limits>
7 #include <sstream>
8 #include <string>
9 #include <vector>
10 
11 #include <AMReX_BoxArray.H>
12 #include <AMReX_IntVect.H>
13 #include <AMReX_Vector.H>
14 
15 namespace erf_interval_means {
16 
17 namespace detail {
18 
19 inline bool
20 read_int_vector (std::istream& input, amrex::IntVect& value)
21 {
22  char delimiter;
23  if (!(input >> delimiter) || delimiter != '(') return false;
24  for (int idir = 0; idir < AMREX_SPACEDIM; ++idir) {
25  if (idir > 0 && (!(input >> delimiter) || delimiter != ',')) return false;
26  if (!(input >> value[idir])) return false;
27  }
28  return static_cast<bool>(input >> delimiter) && delimiter == ')';
29 }
30 
31 // BoxArray::readFrom calls amrex::Error on malformed input. Checkpoint
32 // metadata is external input, so parse the format emitted by writeOn first
33 // and only construct a BoxArray after the complete record is validated.
34 inline bool
35 read_box_array (std::istream& input, amrex::BoxArray& result)
36 {
37  char delimiter;
38  long long box_count;
39  unsigned long long hash;
40  if (!(input >> delimiter) || delimiter != '(' ||
41  !(input >> box_count >> hash) || box_count < 0 ||
42  box_count > static_cast<long long>(std::numeric_limits<int>::max())) {
43  return false;
44  }
45 
46  std::vector<amrex::Box> boxes;
47  boxes.reserve(static_cast<std::size_t>(box_count));
48  for (long long ibox = 0; ibox < box_count; ++ibox) {
49  if (!(input >> delimiter) || delimiter != '(') return false;
50  amrex::IntVect small, big, type;
51  if (!read_int_vector(input, small) || !read_int_vector(input, big) ||
52  !read_int_vector(input, type) ||
53  !(input >> delimiter) || delimiter != ')') {
54  return false;
55  }
56  boxes.emplace_back(small, big, type);
57  }
58  if (!(input >> delimiter) || delimiter != ')') return false;
59 
60  result = boxes.empty()
61  ? amrex::BoxArray{}
62  : amrex::BoxArray(boxes.data(), static_cast<int>(boxes.size()));
63  return true;
64 }
65 
66 } // namespace detail
67 
69 {
70  int level{-1};
71  double accumulation_count{0.0};
72  int reset_done{0};
73  amrex::BoxArray boxes;
74  amrex::Vector<int> processor_map;
75 };
76 
77 struct Metadata
78 {
79  int levels{0};
80  int components{0};
81  amrex::Vector<LevelMetadata> level;
82 };
83 
84 inline bool
85 parse_metadata (std::istream& input, Metadata& result, std::string& error)
86 {
87  std::string title;
88  if (!std::getline(input, title) || title != "ERF interval means checkpoint v1") {
89  error = "expected ERF interval means checkpoint v1 title";
90  return false;
91  }
92  if (!(input >> result.levels >> result.components) || result.levels < 0 ||
93  result.components < 0) {
94  error = "missing or invalid interval-mean level/component counts";
95  return false;
96  }
97 
98  result.level.clear();
99  result.level.resize(result.levels);
100  for (int lev = 0; lev < result.levels; ++lev) {
101  auto& record = result.level[lev];
102  if (!(input >> record.level >> record.accumulation_count >> record.reset_done) ||
103  record.level != lev || !std::isfinite(record.accumulation_count) ||
104  record.accumulation_count < 0.0 ||
105  (record.reset_done != 0 && record.reset_done != 1)) {
106  error = "invalid interval-mean level record " + std::to_string(lev);
107  return false;
108  }
109 
110  if (!detail::read_box_array(input, record.boxes)) {
111  error = "truncated interval-mean BoxArray record for level " +
112  std::to_string(lev);
113  return false;
114  }
115  std::string box_remainder;
116  if (!std::getline(input, box_remainder)) {
117  error = "truncated interval-mean BoxArray line for level " +
118  std::to_string(lev);
119  return false;
120  }
121 
122  long long map_size = -1;
123  if (!(input >> map_size) || map_size < 0 ||
124  map_size != static_cast<long long>(record.boxes.size())) {
125  error = "invalid interval-mean processor-map size for level " +
126  std::to_string(lev);
127  return false;
128  }
129  // The map records the writer's ranks, which need not exist in the
130  // restarted run, so only reject entries that cannot be a rank at all.
131  record.processor_map.resize(static_cast<std::size_t>(map_size));
132  for (long long ibox = 0; ibox < map_size; ++ibox) {
133  int& rank = record.processor_map[static_cast<std::size_t>(ibox)];
134  if (!(input >> rank)) {
135  error = "truncated interval-mean processor map for level " +
136  std::to_string(lev);
137  return false;
138  }
139  if (rank < 0) {
140  error = "invalid interval-mean processor-map rank " +
141  std::to_string(rank) + " for level " + std::to_string(lev);
142  return false;
143  }
144  }
145  }
146  return true;
147 }
148 
149 inline std::string
150 validate_metadata (const Metadata& metadata,
151  int expected_levels,
152  int expected_components,
153  const amrex::Vector<amrex::BoxArray>& expected_boxes)
154 {
155  if (metadata.levels != expected_levels || metadata.components != expected_components) {
156  return "expected " + std::to_string(expected_levels) + " levels and " +
157  std::to_string(expected_components) + " components";
158  }
159  if (static_cast<int>(expected_boxes.size()) < expected_levels ||
160  static_cast<int>(metadata.level.size()) != expected_levels) {
161  return "interval-mean metadata level count does not match the restart";
162  }
163  for (int lev = 0; lev < expected_levels; ++lev) {
164  if (!(metadata.level[lev].boxes == expected_boxes[lev])) {
165  return "interval-mean checkpoint BoxArray does not match level " +
166  std::to_string(lev);
167  }
168  }
169  return {};
170 }
171 
172 inline int
173 global_reset_done (const Metadata& metadata)
174 {
175  for (const auto& record : metadata.level) {
176  if (record.reset_done != 0) return 1;
177  }
178  return 0;
179 }
180 
181 inline int
182 legacy_reset_done (bool time_reset_mode, double checkpoint_time, double reset_time)
183 {
184  return time_reset_mode && checkpoint_time >= reset_time ? 1 : 0;
185 }
186 
187 inline bool
188 initialization_accumulates_state (bool restarting) noexcept
189 {
190  return !restarting;
191 }
192 
193 // The t=0 sample exists only to populate an initial plotfile: it is an
194 // instantaneous state, not a completed step, so it must not leak into the
195 // first real interval. Clearing it regardless of whether an initial plotfile
196 // was written is what makes the step-1 window independent of the output
197 // cadence, and therefore restart-exact (issue 4243): a leg that writes no
198 // initial plotfile would otherwise carry that sample through the checkpoint
199 // and normalize by one dt more than the run it is compared against. A
200 // restart instead restores a window that must survive untouched. In "time"
201 // reset mode the t=0 sample is part of the configured window by design and is
202 // kept -- nothing resets at a plotfile there, so both legs already agree.
203 inline bool
205  bool compute_mean_vars,
206  const std::string& reset_mode) noexcept
207 {
208  return !restarting && compute_mean_vars && reset_mode == "plotfile";
209 }
210 
211 } // namespace erf_interval_means
212 
213 #endif
bool read_box_array(std::istream &input, amrex::BoxArray &result)
Definition: ERF_IntervalMeansCheckpoint.H:35
bool read_int_vector(std::istream &input, amrex::IntVect &value)
Definition: ERF_IntervalMeansCheckpoint.H:20
Definition: ERF_IntervalMeansCheckpoint.H:15
int legacy_reset_done(bool time_reset_mode, double checkpoint_time, double reset_time)
Definition: ERF_IntervalMeansCheckpoint.H:182
bool initialization_accumulates_state(bool restarting) noexcept
Definition: ERF_IntervalMeansCheckpoint.H:188
bool initialization_clears_interval(bool restarting, bool compute_mean_vars, const std::string &reset_mode) noexcept
Definition: ERF_IntervalMeansCheckpoint.H:204
std::string validate_metadata(const Metadata &metadata, int expected_levels, int expected_components, const amrex::Vector< amrex::BoxArray > &expected_boxes)
Definition: ERF_IntervalMeansCheckpoint.H:150
bool parse_metadata(std::istream &input, Metadata &result, std::string &error)
Definition: ERF_IntervalMeansCheckpoint.H:85
int global_reset_done(const Metadata &metadata)
Definition: ERF_IntervalMeansCheckpoint.H:173
Definition: ERF_IntervalMeansCheckpoint.H:69
amrex::BoxArray boxes
Definition: ERF_IntervalMeansCheckpoint.H:73
amrex::Vector< int > processor_map
Definition: ERF_IntervalMeansCheckpoint.H:74
int level
Definition: ERF_IntervalMeansCheckpoint.H:70
int reset_done
Definition: ERF_IntervalMeansCheckpoint.H:72
double accumulation_count
Definition: ERF_IntervalMeansCheckpoint.H:71
Definition: ERF_IntervalMeansCheckpoint.H:78
int levels
Definition: ERF_IntervalMeansCheckpoint.H:79
int components
Definition: ERF_IntervalMeansCheckpoint.H:80
amrex::Vector< LevelMetadata > level
Definition: ERF_IntervalMeansCheckpoint.H:81