GCC Code Coverage Report


Directory: gridformat/
File: gridformat/grid/reader.hpp
Date: 2024-11-20 14:41:59
Exec Total Coverage
Lines: 132 137 96.4%
Functions: 58 87 66.7%
Branches: 81 318 25.5%

Line Branch Exec Source
1 // SPDX-FileCopyrightText: 2022-2023 Dennis Gläser <dennis.glaeser@iws.uni-stuttgart.de>
2 // SPDX-License-Identifier: MIT
3 /*!
4 * \file
5 * \ingroup Grid
6 * \brief Base class for grid data readers.
7 */
8 #ifndef GRIDFORMAT_GRID_READER_HPP_
9 #define GRIDFORMAT_GRID_READER_HPP_
10
11 #include <array>
12 #include <vector>
13 #include <utility>
14 #include <functional>
15 #include <type_traits>
16 #include <string_view>
17 #include <sstream>
18 #include <string>
19 #include <span>
20
21 #include <gridformat/common/field.hpp>
22 #include <gridformat/common/ranges.hpp>
23 #include <gridformat/common/exceptions.hpp>
24 #include <gridformat/common/concepts.hpp>
25 #include <gridformat/common/logging.hpp>
26 #include <gridformat/grid/cell_type.hpp>
27
28 namespace GridFormat::Concepts {
29
30 //! \addtogroup Grid
31 //! \{
32
33 //! Concept for grid factories, to allow for convenient creation of grids from grid files
34 template<typename T, std::size_t space_dim = 3>
35 concept GridFactory = requires(T& t) {
36 typename T::ctype;
37 { t.insert_point(std::declval<const std::array<typename T::ctype, space_dim>&>()) };
38 { t.insert_cell(GridFormat::CellType{}, std::declval<const std::vector<std::size_t>&>()) };
39 };
40
41 //! \} group Grid
42
43 } // namespace Concepts
44
45 namespace GridFormat {
46
47 //! \addtogroup Grid
48 //! \{
49
50 //! Abstract base class for all readers, defines the common interface.
51 class GridReader {
52 public:
53 using Vector = std::array<double, 3>;
54 using CellVisitor = std::function<void(CellType, const std::vector<std::size_t>&)>;
55
56 //! Describes the location of a piece within a distributed structured grid
57 struct PieceLocation {
58 std::array<std::size_t, 3> lower_left;
59 std::array<std::size_t, 3> upper_right;
60 };
61
62
1/2
✓ Branch 1 taken 3209 times.
✗ Branch 2 not taken.
9627 GridReader() = default;
63
64 2352 GridReader(GridReader&&) = default;
65 GridReader(const GridReader&) = delete;
66 1 GridReader& operator=(GridReader&&) = default;
67 GridReader& operator=(const GridReader&) = delete;
68
69 explicit GridReader(const std::string& filename) { open(filename); }
70 11122 virtual ~GridReader() = default;
71
72 //! Return the name of this reader
73 148 std::string name() const {
74 148 return _name();
75 }
76
77 //! Open the given grid file
78 2999 void open(const std::string& filename) {
79 2999 _filename = filename;
80 2999 _field_names.clear();
81 2999 _open(filename, _field_names);
82 2941 }
83
84 //! Close the grid file
85 630 void close() {
86 630 _close();
87 630 _field_names.clear();
88 630 _filename.clear();
89 630 }
90
91 //! Return the name of the opened grid file (empty string until open() is called)
92 23 const std::string& filename() const {
93 23 return _filename;
94 }
95
96 //! Return the number of cells in the grid read from the file
97 7118 std::size_t number_of_cells() const {
98 7118 return _number_of_cells();
99 }
100
101 //! Return the number of points in the grid read from the file
102 8738 std::size_t number_of_points() const {
103 8738 return _number_of_points();
104 }
105
106 //! Return the number of pieces contained in the read file (when constructing readers
107 //! in parallel, this reader instance contains the data of only one or some of these pieces)
108 173 std::size_t number_of_pieces() const {
109 173 return _number_of_pieces();
110 }
111
112 //! Return the extents of the grid (only available for structured grid formats)
113 455 std::array<std::size_t, 3> extents() const {
114
1/2
✓ Branch 1 taken 455 times.
✗ Branch 2 not taken.
455 const auto loc = location();
115 return {
116
2/4
✓ Branch 1 taken 455 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 455 times.
✗ Branch 5 not taken.
455 loc.upper_right.at(0) - loc.lower_left.at(0),
117
1/2
✓ Branch 1 taken 455 times.
✗ Branch 2 not taken.
455 loc.upper_right.at(1) - loc.lower_left.at(1),
118
1/2
✓ Branch 1 taken 455 times.
✗ Branch 2 not taken.
455 loc.upper_right.at(2) - loc.lower_left.at(2)
119
2/4
✓ Branch 1 taken 455 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 455 times.
✗ Branch 5 not taken.
1365 };
120 }
121
122 //! Return the location of this piece in a structured grid (only available for structured grid formats)
123 958 PieceLocation location() const {
124 958 return _location();
125 }
126
127 //! Return the ordinates of the grid (only available for rectilinear grid formats)
128 82 std::vector<double> ordinates(unsigned int direction) const {
129
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 81 times.
82 if (direction >= 3)
130
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 throw ValueError("direction must be < 3");
131 81 return _ordinates(direction);
132 }
133
134 //! Return the spacing of the grid (only available for image grid formats)
135 36 Vector spacing() const {
136 36 return _spacing();
137 }
138
139 //! Return the origin of the grid (only available for image grid formats)
140 33 Vector origin() const {
141 33 return _origin();
142 }
143
144 //! Return the basis vector of the grid in the given direction (only available for image grid formats)
145 12 Vector basis_vector(unsigned int direction) const {
146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (direction >= 3)
147 throw ValueError("direction must be < 3");
148 12 return _basis_vector(direction);
149 }
150
151 //! Return true if the read file is a sequence
152 1385 bool is_sequence() const {
153 1385 return _is_sequence();
154 }
155
156 //! Return the number of available steps (only available for sequence formats)
157 610 std::size_t number_of_steps() const {
158 610 return _number_of_steps();
159 }
160
161 //! Return the time at the current step (only available for sequence formats)
162 1241 double time_at_step(std::size_t step_idx) const {
163 1241 return _time_at_step(step_idx);
164 }
165
166 //! Set the step from which to read data (only available for sequence formats)
167 1511 void set_step(std::size_t step_idx) {
168 1511 _set_step(step_idx, _field_names);
169 1510 }
170
171 //! Export the grid read from the file into the given grid factory
172 template<std::size_t space_dim = 3, Concepts::GridFactory<space_dim> Factory>
173 472 void export_grid(Factory& factory) const {
174
2/2
✓ Branch 1 taken 449 times.
✓ Branch 2 taken 1 times.
472 if (number_of_points() > 0) {
175
1/2
✓ Branch 1 taken 449 times.
✗ Branch 2 not taken.
470 const auto point_field = points();
176
1/2
✓ Branch 2 taken 449 times.
✗ Branch 3 not taken.
470 const auto point_layout = point_field->layout();
177
1/2
✓ Branch 1 taken 449 times.
✗ Branch 2 not taken.
470 const auto read_space_dim = point_layout.extent(1);
178 470 const auto copied_space_dim = std::min(space_dim, read_space_dim);
179
3/6
✓ Branch 1 taken 449 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 449 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 449 times.
470 if (point_layout.extent(0) != number_of_points()) {
180 std::ostringstream s; s << point_layout;
181 throw SizeError(
182 "Point layout " + s.str() + " does not match number of points: " + std::to_string(number_of_points())
183 );
184 }
185
186
1/2
✓ Branch 2 taken 449 times.
✗ Branch 3 not taken.
1347 point_field->visit_field_values([&] <typename T> (std::span<const T> coords) {
187 449 auto p = Ranges::filled_array<space_dim>(typename Factory::ctype{0.0});
188
9/88
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✓ Branch 46 taken 16527 times.
✗ Branch 47 not taken.
✓ Branch 48 taken 16104 times.
✓ Branch 49 taken 423 times.
✓ Branch 51 taken 777 times.
✗ Branch 52 not taken.
✓ Branch 53 taken 756 times.
✓ Branch 54 taken 21 times.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 64 not taken.
✗ Branch 66 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 71 not taken.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✗ Branch 78 not taken.
✗ Branch 79 not taken.
✗ Branch 81 not taken.
✗ Branch 82 not taken.
✗ Branch 83 not taken.
✗ Branch 84 not taken.
✗ Branch 86 not taken.
✗ Branch 87 not taken.
✗ Branch 88 not taken.
✗ Branch 89 not taken.
✗ Branch 91 not taken.
✗ Branch 92 not taken.
✗ Branch 93 not taken.
✗ Branch 94 not taken.
✓ Branch 96 taken 187 times.
✗ Branch 97 not taken.
✓ Branch 98 taken 182 times.
✓ Branch 99 taken 5 times.
✗ Branch 101 not taken.
✗ Branch 102 not taken.
✗ Branch 103 not taken.
✗ Branch 104 not taken.
✗ Branch 106 not taken.
✗ Branch 107 not taken.
✗ Branch 108 not taken.
✗ Branch 109 not taken.
17491 for (std::size_t i = 0; i < point_layout.extent(0); ++i) {
189
6/44
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 48312 times.
✓ Branch 19 taken 16104 times.
✓ Branch 20 taken 2268 times.
✓ Branch 21 taken 756 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✓ Branch 38 taken 546 times.
✓ Branch 39 taken 182 times.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
68168 for (std::size_t dir = 0; dir < copied_space_dim; ++dir)
190 51126 p[dir] = static_cast<typename Factory::ctype>(coords[i*read_space_dim + dir]);
191
3/44
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✓ Branch 38 taken 16104 times.
✗ Branch 39 not taken.
✓ Branch 42 taken 756 times.
✗ Branch 43 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 66 not taken.
✗ Branch 67 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 74 not taken.
✗ Branch 75 not taken.
✓ Branch 78 taken 182 times.
✗ Branch 79 not taken.
✗ Branch 82 not taken.
✗ Branch 83 not taken.
✗ Branch 86 not taken.
✗ Branch 87 not taken.
17042 factory.insert_point(std::as_const(p));
192 }
193 });
194 470 }
195
1/2
✓ Branch 2 taken 450 times.
✗ Branch 3 not taken.
984 visit_cells([&] (GridFormat::CellType ct, const std::vector<std::size_t>& corners) {
196 10471 factory.insert_cell(std::move(ct), corners);
197 });
198 472 }
199
200 //! Visit all cells in the grid read from the file
201 5339 void visit_cells(const CellVisitor& visitor) const {
202 5339 _visit_cells(visitor);
203 5338 }
204
205 //! Return the points of the grid as field
206 2638 FieldPtr points() const {
207 2638 return _points();
208 }
209
210 //! Return the cell field with the given name
211 13246 FieldPtr cell_field(std::string_view name) const {
212 13246 return _cell_field(name);
213 }
214
215 //! Return the point field with the given name
216 13469 FieldPtr point_field(std::string_view name) const {
217 13469 return _point_field(name);
218 }
219
220 //! Return the meta data field with the given name
221 888 FieldPtr meta_data_field(std::string_view name) const {
222 888 return _meta_data_field(name);
223 }
224
225 //! Return a range over the names of all read cell fields
226 4473 friend std::ranges::range auto cell_field_names(const GridReader& reader) {
227 4473 return reader._field_names.cell_fields;
228 }
229
230 //! Return a range over the names of all read point fields
231 4473 friend std::ranges::range auto point_field_names(const GridReader& reader) {
232 4473 return reader._field_names.point_fields;
233 }
234
235 //! Return a range over the names of all read metadata fields
236 4434 friend std::ranges::range auto meta_data_field_names(const GridReader& reader) {
237 4434 return reader._field_names.meta_data_fields;
238 }
239
240 //! Return a range over name-field pairs for all read cell fields
241 1168 friend std::ranges::range auto cell_fields(const GridReader& reader) {
242
1/2
✓ Branch 1 taken 1168 times.
✗ Branch 2 not taken.
2336 return reader._field_names.cell_fields | std::views::transform([&] (const std::string& n) {
243
2/4
✓ Branch 2 taken 4304 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 4304 times.
✗ Branch 7 not taken.
4304 return std::make_pair(std::move(n), reader.cell_field(n));
244
1/2
✓ Branch 1 taken 1168 times.
✗ Branch 2 not taken.
2336 });
245 }
246
247 //! Return a range over name-field pairs for all read point fields
248 1168 friend std::ranges::range auto point_fields(const GridReader& reader) {
249
1/2
✓ Branch 1 taken 1168 times.
✗ Branch 2 not taken.
2336 return reader._field_names.point_fields | std::views::transform([&] (const std::string& n) {
250
2/4
✓ Branch 2 taken 4385 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 4385 times.
✗ Branch 7 not taken.
4385 return std::make_pair(std::move(n), reader.point_field(n));
251
1/2
✓ Branch 1 taken 1168 times.
✗ Branch 2 not taken.
2336 });
252 }
253
254 //! Return a range over name-field pairs for all read metadata fields
255 222 friend std::ranges::range auto meta_data_fields(const GridReader& reader) {
256
1/2
✓ Branch 1 taken 222 times.
✗ Branch 2 not taken.
444 return reader._field_names.meta_data_fields | std::views::transform([&] (std::string n) {
257
1/2
✓ Branch 2 taken 411 times.
✗ Branch 3 not taken.
411 return std::make_pair(std::move(n), reader.meta_data_field(n));
258
1/2
✓ Branch 1 taken 222 times.
✗ Branch 2 not taken.
444 });
259 }
260
261 void set_ignore_warnings(bool value) {
262 _ignore_warnings = value;
263 }
264
265 protected:
266 struct FieldNames {
267 std::vector<std::string> cell_fields;
268 std::vector<std::string> point_fields;
269 std::vector<std::string> meta_data_fields;
270
271 4889 void clear() {
272 4889 cell_fields.clear();
273 4889 point_fields.clear();
274 4889 meta_data_fields.clear();
275 4889 }
276 };
277
278 1 void _log_warning(std::string_view warning) const {
279
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!_ignore_warnings)
280
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 log_warning(
281
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 std::string{warning}
282
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
3 + (warning.ends_with("\n") ? "" : "\n")
283
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
3 + "To deactivate this warning, call set_ignore_warnings(true);"
284 );
285 1 }
286
287 private:
288 std::string _filename = "";
289 FieldNames _field_names;
290 bool _ignore_warnings = false;
291
292 virtual std::string _name() const = 0;
293 virtual void _open(const std::string&, FieldNames&) = 0;
294 virtual void _close() = 0;
295
296 virtual std::size_t _number_of_cells() const = 0;
297 virtual std::size_t _number_of_points() const = 0;
298 virtual std::size_t _number_of_pieces() const = 0;
299
300 virtual FieldPtr _cell_field(std::string_view) const = 0;
301 virtual FieldPtr _point_field(std::string_view) const = 0;
302 virtual FieldPtr _meta_data_field(std::string_view) const = 0;
303
304 1 virtual void _visit_cells(const CellVisitor&) const {
305
4/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
1 throw NotImplemented("'" + _name() + "' does not implement cell visiting");
306 }
307
308 1 virtual FieldPtr _points() const {
309
4/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
1 throw NotImplemented("'" + _name() + "' does not implement points()");
310 }
311
312 1 virtual PieceLocation _location() const {
313
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 throw NotImplemented("Extents/Location are only available with structured grid formats");
314 }
315
316 1 virtual std::vector<double> _ordinates(unsigned int) const {
317
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 throw NotImplemented("Ordinates are only available with rectilinear grid formats.");
318 }
319
320 1 virtual Vector _spacing() const {
321
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 throw NotImplemented("Spacing is only available with image grid formats.");
322 }
323
324 1 virtual Vector _origin() const {
325
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 throw NotImplemented("Origin is only available with image grid formats.");
326 }
327
328 6 virtual Vector _basis_vector(unsigned int i) const {
329 6 std::array<double, 3> result{0., 0., 0.};
330 6 result[i] = 1.0;
331 6 return result;
332 }
333
334 virtual bool _is_sequence() const = 0;
335
336 1 virtual std::size_t _number_of_steps() const {
337
4/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
1 throw NotImplemented("The format read by '" + _name() + "' is not a sequence");
338 }
339
340 1 virtual double _time_at_step(std::size_t) const {
341
4/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
1 throw NotImplemented("The format read by '" + _name() + "' is not a sequence");
342 }
343
344 1 virtual void _set_step(std::size_t, FieldNames&) {
345
4/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
1 throw NotImplemented("The format read by '" + _name() + "' is not a sequence");
346 }
347 };
348
349 //! \} group Grid
350
351 } // namespace GridFormat
352
353 #endif // GRIDFORMAT_GRID_READER_HPP_
354