GCC Code Coverage Report


Directory: gridformat/
File: gridformat/vtk/hdf_unstructured_grid_reader.hpp
Date: 2026-10-12 17:50:57
Exec Total Coverage
Lines: 233 247 94.3%
Functions: 81 113 71.7%
Branches: 313 732 42.8%

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 VTK
6 * \brief Reader for the VTK HDF file format for unstructured grids.
7 */
8 #ifndef GRIDFORMAT_VTK_HDF_UNSTRUCTURED_GRID_READER_HPP_
9 #define GRIDFORMAT_VTK_HDF_UNSTRUCTURED_GRID_READER_HPP_
10 #if GRIDFORMAT_HAVE_HIGH_FIVE
11
12 #include <iterator>
13 #include <optional>
14 #include <algorithm>
15 #include <type_traits>
16 #include <concepts>
17 #include <numeric>
18 #include <utility>
19 #include <cassert>
20
21 #include <gridformat/common/field.hpp>
22 #include <gridformat/common/range_field.hpp>
23 #include <gridformat/common/field_transformations.hpp>
24 #include <gridformat/common/concepts.hpp>
25 #include <gridformat/common/exceptions.hpp>
26 #include <gridformat/grid/reader.hpp>
27 #include <gridformat/parallel/concepts.hpp>
28 #include <gridformat/vtk/common.hpp>
29 #include <gridformat/vtk/hdf_common.hpp>
30
31 namespace GridFormat {
32
33 /*!
34 * \ingroup VTK
35 * \brief Reader for the VTK-HDF file format for unstructured grids.
36 */
37 template<Concepts::Communicator Communicator = NullCommunicator>
38 class VTKHDFUnstructuredGridReader : public GridReader {
39 using HDF5File = HDF5::File<Communicator>;
40 static constexpr std::size_t vtk_space_dim = 3;
41 static constexpr bool read_rank_piece_only = !std::is_same_v<Communicator, NullCommunicator>;
42
43 public:
44 3 explicit VTKHDFUnstructuredGridReader() requires(std::is_same_v<Communicator, NullCommunicator>)
45 3 : _comm{}
46 3 {}
47
48 88 explicit VTKHDFUnstructuredGridReader(Communicator comm)
49 88 : _comm{comm}
50 88 {}
51
52 private:
53 1 std::string _name() const override {
54
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (_is_transient())
55 ✗ return "VTKHDFUnstructuredGridReader (transient)";
56
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 return "VTKHDFUnstructuredGridReader";
57 }
58
59 91 void _open(const std::string& filename, typename GridReader::FieldNames& field_names) override {
60
1/2
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
91 _close();
61
2/4
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 61 times.
✗ Branch 5 not taken.
91 _file = HDF5File{filename, _comm, HDF5File::read_only};
62
2/4
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 61 times.
✗ Branch 5 not taken.
91 const auto type = VTKHDF::get_file_type(_file.value());
63
2/4
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 61 times.
91 if (type != "UnstructuredGrid")
64 ✗ throw ValueError("Incompatible VTK-HDF type: '" + type + "', expected 'UnstructuredGrid'.");
65
66
2/4
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 61 times.
✗ Branch 5 not taken.
91 VTKHDF::check_version_compatibility(_file.value(), {2, 0});
67
68
4/6
✓ Branch 2 taken 61 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 61 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 31 times.
✓ Branch 9 taken 30 times.
273 if (_file->exists("VTKHDF/Steps"))
69
2/4
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 31 times.
✗ Branch 6 not taken.
230 _file->visit_attribute("VTKHDF/Steps/NSteps", [&] (auto&& field) {
70 31 _num_steps.emplace();
71 31 field.export_to(_num_steps.value());
72 31 _step_index.emplace(0);
73 });
74
75
1/2
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
91 _compute_piece_offsets();
76 243 const auto copy_names_in = [&] (const std::string& group, auto& storage) {
77
4/4
✓ Branch 2 taken 70 times.
✓ Branch 3 taken 29 times.
✓ Branch 6 taken 76 times.
✓ Branch 7 taken 8 times.
183 if (_file->exists(group))
78
4/8
✓ Branch 3 taken 70 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 70 times.
✗ Branch 7 not taken.
✓ Branch 13 taken 76 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 76 times.
✗ Branch 17 not taken.
146 std::ranges::copy(_file->dataset_names_in(group), std::back_inserter(storage));
79 };
80
2/4
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 61 times.
✗ Branch 5 not taken.
182 copy_names_in("VTKHDF/CellData", field_names.cell_fields);
81
2/4
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 61 times.
✗ Branch 5 not taken.
182 copy_names_in("VTKHDF/PointData", field_names.point_fields);
82
2/4
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 61 times.
✗ Branch 5 not taken.
182 copy_names_in("VTKHDF/FieldData", field_names.meta_data_fields);
83 91 }
84
85 91 void _close() override {
86
1/2
✓ Branch 2 taken 61 times.
✗ Branch 3 not taken.
91 _file = {};
87 91 _num_cells = 0;
88 91 _num_points = 0;
89 91 _cell_offset = 0;
90 91 _point_offset = 0;
91 91 _num_steps = {};
92 91 _step_index = {};
93 91 }
94
95 337 void _compute_piece_offsets() {
96 337 _cell_offset = 0;
97 337 _point_offset = 0;
98
1/2
✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
337 _check_communicator_size();
99
2/4
✓ Branch 1 taken 215 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 215 times.
✗ Branch 5 not taken.
674 const auto num_step_cells = _number_of_all_piece_entities("Cells");
100
2/4
✓ Branch 1 taken 215 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 215 times.
✗ Branch 5 not taken.
337 const auto num_step_points = _number_of_all_piece_entities("Points");
101 if constexpr (read_rank_piece_only) {
102
1/2
✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
232 const auto my_rank = Parallel::rank(_comm);
103
1/2
✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
232 _num_cells = num_step_cells.at(my_rank);
104
1/2
✓ Branch 1 taken 116 times.
✗ Branch 2 not taken.
232 _num_points = num_step_points.at(my_rank);
105 232 _cell_offset += _accumulate_until(my_rank, num_step_cells);
106 232 _point_offset += _accumulate_until(my_rank, num_step_points);
107 } else {
108 105 _num_cells = _accumulate_until(num_step_cells.size(), num_step_cells);
109 105 _num_points = _accumulate_until(num_step_points.size(), num_step_points);
110 }
111 337 }
112
113 1737 std::size_t _get_part_offset() const {
114 1737 return _is_transient()
115
13/28
✓ Branch 0 taken 934 times.
✓ Branch 1 taken 155 times.
✓ Branch 3 taken 934 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 934 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 934 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 934 times.
✓ Branch 13 taken 155 times.
✓ Branch 14 taken 934 times.
✓ Branch 15 taken 155 times.
✓ Branch 17 taken 934 times.
✓ Branch 18 taken 155 times.
✓ Branch 20 taken 934 times.
✓ Branch 21 taken 155 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
7950 ? _access_file().template read_dataset_to<std::size_t>(
116 "/VTKHDF/Steps/PartOffsets",
117 HDF5::Slice{
118
1/2
✓ Branch 1 taken 934 times.
✗ Branch 2 not taken.
1492 .offset = {_step_index.value()},
119 .count = {1}
120 })
121
2/2
✓ Branch 0 taken 934 times.
✓ Branch 1 taken 155 times.
3474 : std::size_t{0};
122
4/14
✓ Branch 1 taken 934 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 934 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 934 times.
✓ Branch 9 taken 155 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
7705 }
123
124 930 std::size_t _get_step_cells_offset() const {
125 930 return _is_transient()
126
15/30
✓ Branch 0 taken 472 times.
✓ Branch 1 taken 78 times.
✓ Branch 3 taken 472 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 472 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 472 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 472 times.
✓ Branch 13 taken 78 times.
✓ Branch 14 taken 472 times.
✓ Branch 15 taken 78 times.
✓ Branch 17 taken 472 times.
✓ Branch 18 taken 78 times.
✓ Branch 20 taken 472 times.
✓ Branch 21 taken 78 times.
✓ Branch 22 taken 472 times.
✓ Branch 23 taken 78 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
5060 ? _access_file().template read_dataset_to<std::size_t>(
127 "VTKHDF/Steps/CellOffsets",
128 HDF5::Slice{
129
1/2
✓ Branch 1 taken 472 times.
✗ Branch 2 not taken.
800 .offset = {_step_index.value(), 0},
130 .count = {1, 1}
131 })
132
2/2
✓ Branch 0 taken 472 times.
✓ Branch 1 taken 78 times.
1860 : std::size_t{0};
133
2/12
✓ Branch 1 taken 472 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 472 times.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
3330 }
134
135 229 std::size_t _get_step_points_offset() const {
136 229 return _is_transient()
137
13/28
✓ Branch 0 taken 113 times.
✓ Branch 1 taken 24 times.
✓ Branch 3 taken 113 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 113 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 113 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 113 times.
✓ Branch 13 taken 24 times.
✓ Branch 14 taken 113 times.
✓ Branch 15 taken 24 times.
✓ Branch 17 taken 113 times.
✓ Branch 18 taken 24 times.
✓ Branch 20 taken 113 times.
✓ Branch 21 taken 24 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
1028 ? _access_file().template read_dataset_to<std::size_t>(
138 "VTKHDF/Steps/PointOffsets",
139 HDF5::Slice{
140
1/2
✓ Branch 1 taken 113 times.
✗ Branch 2 not taken.
190 .offset = {_step_index.value()},
141 .count = {1}
142 })
143
2/2
✓ Branch 0 taken 113 times.
✓ Branch 1 taken 24 times.
458 : std::size_t{0};
144
4/14
✓ Branch 1 taken 113 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 113 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 113 times.
✓ Branch 9 taken 24 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
989 }
145
146 465 std::size_t _get_connectivity_id_offset() const {
147 465 return _is_transient()
148
15/30
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 39 times.
✓ Branch 3 taken 236 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 236 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 236 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 236 times.
✓ Branch 13 taken 39 times.
✓ Branch 14 taken 236 times.
✓ Branch 15 taken 39 times.
✓ Branch 17 taken 236 times.
✓ Branch 18 taken 39 times.
✓ Branch 20 taken 236 times.
✓ Branch 21 taken 39 times.
✓ Branch 22 taken 236 times.
✓ Branch 23 taken 39 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
2530 ? _access_file().template read_dataset_to<std::size_t>(
149 "VTKHDF/Steps/ConnectivityIdOffsets",
150 HDF5::Slice{
151
1/2
✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
400 .offset = {_step_index.value(), 0},
152 .count = {1, 1}
153 })
154
2/2
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 39 times.
930 : std::size_t{0};
155
2/12
✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 236 times.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
1665 }
156
157 1156 std::size_t _get_cell_data_offset(std::string_view name) const {
158 1156 return _is_transient()
159
8/18
✓ Branch 0 taken 570 times.
✓ Branch 1 taken 118 times.
✓ Branch 3 taken 570 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 570 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 570 times.
✓ Branch 10 taken 118 times.
✓ Branch 12 taken 570 times.
✓ Branch 13 taken 118 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
4232 ? _access_file().template read_dataset_to<std::size_t>(
160
8/16
✓ Branch 1 taken 570 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 570 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 570 times.
✓ Branch 8 taken 118 times.
✓ Branch 10 taken 570 times.
✓ Branch 11 taken 118 times.
✓ Branch 12 taken 570 times.
✓ Branch 13 taken 118 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
3076 "VTKHDF/Steps/CellDataOffsets/" + std::string{name},
161 HDF5::Slice{
162
1/2
✓ Branch 1 taken 570 times.
✗ Branch 2 not taken.
960 .offset = {_step_index.value()},
163 .count = {1}
164 })
165
2/2
✓ Branch 0 taken 570 times.
✓ Branch 1 taken 118 times.
2312 : std::size_t{0};
166
4/14
✓ Branch 1 taken 570 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 570 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 570 times.
✓ Branch 9 taken 118 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
4996 }
167
168 1164 std::size_t _get_point_data_offset(std::string_view name) const {
169 1164 return _is_transient()
170
8/18
✓ Branch 0 taken 570 times.
✓ Branch 1 taken 122 times.
✓ Branch 3 taken 570 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 570 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 570 times.
✓ Branch 10 taken 122 times.
✓ Branch 12 taken 570 times.
✓ Branch 13 taken 122 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
4248 ? _access_file().template read_dataset_to<std::size_t>(
171
8/16
✓ Branch 1 taken 570 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 570 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 570 times.
✓ Branch 8 taken 122 times.
✓ Branch 10 taken 570 times.
✓ Branch 11 taken 122 times.
✓ Branch 12 taken 570 times.
✓ Branch 13 taken 122 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
3084 "VTKHDF/Steps/PointDataOffsets/" + std::string{name},
172 HDF5::Slice{
173
1/2
✓ Branch 1 taken 570 times.
✗ Branch 2 not taken.
960 .offset = {_step_index.value()},
174 .count = {1}
175 })
176
2/2
✓ Branch 0 taken 570 times.
✓ Branch 1 taken 122 times.
2328 : std::size_t{0};
177
4/14
✓ Branch 1 taken 570 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 570 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 570 times.
✓ Branch 9 taken 122 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
5004 }
178
179 45 bool _is_sequence() const override {
180 45 return _is_transient();
181 }
182
183 613 std::size_t _number_of_steps() const override {
184
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 393 times.
613 if (!_num_steps)
185 ✗ throw ValueError("No step information available");
186 613 return _num_steps.value();
187 }
188
189 160 double _time_at_step(std::size_t step_idx) const override {
190
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 95 times.
160 if (step_idx >= _number_of_steps())
191 ✗ throw ValueError("Only " + as_string(_number_of_steps()) + " available");
192
2/4
✓ Branch 2 taken 95 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 95 times.
✗ Branch 6 not taken.
640 return _access_file().template read_dataset_to<double>("/VTKHDF/Steps/Values", HDF5::Slice{
193 .offset = {step_idx},
194 .count = {1}
195 320 });
196
2/8
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 95 times.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
640 }
197
198 287 void _set_step(std::size_t step_idx, typename GridReader::FieldNames&) override {
199
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 182 times.
287 if (step_idx >= _number_of_steps())
200 ✗ throw ValueError("Only " + as_string(_number_of_steps()) + " available");
201
2/2
✓ Branch 1 taken 154 times.
✓ Branch 2 taken 28 times.
287 if (step_idx != _step_index.value()) {
202 246 _compute_piece_offsets();
203 246 _step_index = step_idx;
204 }
205 287 }
206
207 380 std::size_t _number_of_cells() const override {
208 380 return _num_cells;
209 }
210
211 725 std::size_t _number_of_points() const override {
212 725 return _num_points;
213 }
214
215 30 std::size_t _number_of_pieces() const override {
216 30 return _number_of_current_pieces_in_file();
217 }
218
219 2108 std::size_t _number_of_current_pieces_in_file() const {
220
2/2
✓ Branch 1 taken 1122 times.
✓ Branch 2 taken 198 times.
2108 if (_is_transient())
221 1794 return _number_of_pieces_in_file_at_step(_step_index.value());
222 314 return _total_number_of_pieces();
223 }
224
225 314 std::size_t _total_number_of_pieces() const {
226
3/6
✓ Branch 1 taken 198 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 198 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 198 times.
✗ Branch 8 not taken.
628 auto ncells = _access_file().get_dimensions("/VTKHDF/NumberOfCells");
227
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 198 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
314 if (!ncells) throw IOError("Missing dataset at '/VTKHDF/NumberOfCells'");
228
1/4
✗ Branch 2 not taken.
✓ Branch 3 taken 198 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
314 if (ncells->size() != 1) throw IOError("Unexpected dimension of '/VTKHDF/NumberOfCells'");
229
1/2
✓ Branch 2 taken 198 times.
✗ Branch 3 not taken.
628 return ncells->at(0);
230 314 }
231
232 2614 std::size_t _number_of_pieces_in_file_at_step(std::size_t step) const {
233
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1606 times.
2614 if (!_is_transient())
234 ✗ throw InvalidState("Step data only available in transient files");
235
3/6
✓ Branch 2 taken 1606 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1606 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1606 times.
✗ Branch 9 not taken.
7842 if (const auto& file = _access_file(); file.exists("/VTKHDF/Steps/NumberOfParts"))
236
3/6
✓ Branch 2 taken 1606 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1606 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1606 times.
✗ Branch 9 not taken.
7842 return file.template read_dataset_to<std::vector<std::size_t>>("/VTKHDF/Steps/NumberOfParts").at(step);
237
238 // all steps have the same number of parts
239 ✗ if (_total_number_of_pieces()%_num_steps.value() != 0)
240 ✗ throw IOError(
241 "Cannot deduce the number of pieces. "
242 "The dataset '/VTKHDF/Steps/NumberOfParts' is not available, "
243 "but the total number of pieces is not divisble by the number of steps"
244 );
245 ✗ return _total_number_of_pieces()/_num_steps.value();
246 }
247
248 337 void _check_communicator_size() const {
249 if constexpr (!std::is_same_v<Communicator, NullCommunicator>)
250
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 116 times.
232 if (_number_of_current_pieces_in_file() != static_cast<std::size_t>(Parallel::size(_comm)))
251 ✗ throw SizeError(
252 "Can only read the file in parallel if the size of the communicator matches the size "
253 "of that used when writing the file. Please read in the file sequentially on one process "
254 "and distribute the grid yourself, or restart the parallel run with "
255 ✗ + std::to_string(_number_of_current_pieces_in_file()) + " processes."
256 );
257 337 }
258
259 441 void _visit_cells(const typename GridReader::CellVisitor& visitor) const override {
260 if constexpr (read_rank_piece_only)
261 332 _visit_cells_for_rank(Parallel::rank(_comm), 0, visitor);
262 else
263
1/2
✓ Branch 1 taken 97 times.
✗ Branch 2 not taken.
109 std::ranges::for_each(
264
2/4
✓ Branch 1 taken 97 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 97 times.
✗ Branch 5 not taken.
109 std::views::iota(std::size_t{0}, _number_of_current_pieces_in_file()),
265 109 [&] (int rank) mutable {
266
2/4
✓ Branch 1 taken 109 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 109 times.
✗ Branch 5 not taken.
327 const auto [_, base_offset] = _number_of_entities_and_offset_at_rank(rank, "Points");
267
1/2
✓ Branch 1 taken 109 times.
✗ Branch 2 not taken.
109 _visit_cells_for_rank(rank, base_offset, visitor);
268 }
269 );
270 441 }
271
272 465 void _visit_cells_for_rank(int piece_rank,
273 std::size_t point_base_offset,
274 const typename GridReader::CellVisitor& visitor) const {
275
1/2
✓ Branch 1 taken 275 times.
✗ Branch 2 not taken.
465 const auto& file = _access_file();
276
2/4
✓ Branch 1 taken 275 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 275 times.
✗ Branch 5 not taken.
930 const auto [my_num_cells, my_cell_offset] = _number_of_entities_and_offset_at_rank(piece_rank, "Cells");
277
2/4
✓ Branch 1 taken 275 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 275 times.
✗ Branch 5 not taken.
930 const auto num_connectivity_ids = file.template read_dataset_to<std::vector<std::size_t>>(
278 "VTKHDF/NumberOfConnectivityIds",
279 HDF5::Slice{
280
1/2
✓ Branch 1 taken 275 times.
✗ Branch 2 not taken.
465 .offset = {_get_part_offset()},
281 930 .count = {_number_of_current_pieces_in_file()}
282 }
283 );
284 930 const auto my_num_connectivity_ids = num_connectivity_ids.at(piece_rank);
285 465 const auto my_id_offset = std::accumulate(
286 num_connectivity_ids.begin(),
287 465 num_connectivity_ids.begin() + piece_rank,
288 std::size_t{0}
289 );
290
291
2/4
✓ Branch 1 taken 275 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 275 times.
✗ Branch 5 not taken.
930 auto offsets = file.template read_dataset_to<std::vector<std::size_t>>("VTKHDF/Offsets", {{
292 // offsets have length num_cells+1, so we need to add +1 per rank to the cell offsets
293 .offset = {
294
2/4
✓ Branch 1 taken 275 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 275 times.
✗ Branch 6 not taken.
465 _get_step_cells_offset() + _accumulate_over_pieces_until_step(_step_index.value_or(0), 1) // offset from step
295 465 + my_cell_offset + piece_rank // offset from this piece in the pieces of the current step
296 },
297 465 .count = {my_num_cells + 1}
298 }});
299
2/4
✓ Branch 1 taken 275 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 275 times.
✗ Branch 5 not taken.
930 auto types = file.template read_dataset_to<std::vector<std::uint_least8_t>>(
300 "VTKHDF/Types",
301 930 {{.offset = {_get_step_cells_offset() + my_cell_offset}, .count = {my_num_cells}}}
302 );
303
2/4
✓ Branch 1 taken 275 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 275 times.
✗ Branch 5 not taken.
930 auto connectivity = file.template read_dataset_to<std::vector<std::size_t>>(
304 "VTKHDF/Connectivity",
305 930 {{.offset = {_get_connectivity_id_offset() + my_id_offset}, .count = {my_num_connectivity_ids}}}
306 );
307
308 465 std::vector<std::size_t> corners;
309
2/2
✓ Branch 1 taken 3574 times.
✓ Branch 2 taken 275 times.
6351 for (std::size_t i = 0; i < types.size(); ++i) {
310
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3574 times.
5886 assert(i < offsets.size() - 1);
311
3/6
✓ Branch 1 taken 3574 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3574 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3574 times.
5886 assert(offsets.at(i+1) > offsets.at(i));
312
1/2
✓ Branch 1 taken 3574 times.
✗ Branch 2 not taken.
5886 const auto p0_offset = offsets.at(i);
313
1/2
✓ Branch 1 taken 3574 times.
✗ Branch 2 not taken.
5886 const auto num_corners = offsets.at(i+1) - p0_offset;
314
315
1/2
✓ Branch 1 taken 3574 times.
✗ Branch 2 not taken.
5886 corners.resize(num_corners);
316
2/2
✓ Branch 0 taken 14296 times.
✓ Branch 1 taken 3574 times.
29430 for (std::size_t c = 0; c < num_corners; ++c)
317
1/2
✓ Branch 1 taken 14296 times.
✗ Branch 2 not taken.
23544 corners[c] = connectivity.at(p0_offset + c) + point_base_offset;
318
3/6
✓ Branch 1 taken 3574 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3574 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3574 times.
✗ Branch 8 not taken.
5886 visitor(VTK::cell_type(types.at(i)), corners);
319 }
320
12/40
✓ Branch 1 taken 275 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 275 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 275 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 275 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 275 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 275 times.
✗ Branch 19 not taken.
✓ Branch 23 taken 275 times.
✗ Branch 24 not taken.
✓ Branch 26 taken 275 times.
✗ Branch 27 not taken.
✓ Branch 29 taken 275 times.
✗ Branch 30 not taken.
✓ Branch 34 taken 275 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 275 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 275 times.
✗ Branch 41 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
6975 }
321
322 229 FieldPtr _points() const override {
323
1/2
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
229 const std::string path = "VTKHDF/Points";
324
2/4
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 137 times.
✗ Branch 5 not taken.
687 return make_field_ptr(VTKHDF::DataSetField{
325 _file.value(),
326
1/2
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
229 MDLayout{{_num_points, vtk_space_dim}},
327
3/6
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 137 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 137 times.
✗ Branch 8 not taken.
229 _file.value().get_precision(path).value(),
328
1/2
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
458 _serialization_callback(path, HDF5::Slice{
329
1/2
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
229 .offset = {_point_offset + _get_step_points_offset(), 0},
330 229 .count = {_num_points, vtk_space_dim}
331 })
332
1/2
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
458 });
333
2/8
✓ Branch 1 taken 137 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 137 times.
✗ Branch 5 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
916 }
334
335 1156 FieldPtr _cell_field(std::string_view name) const override {
336
2/4
✓ Branch 1 taken 688 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 688 times.
✗ Branch 5 not taken.
1156 const std::string path = "VTKHDF/CellData/" + std::string{name};
337
2/4
✓ Branch 1 taken 688 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 688 times.
✗ Branch 5 not taken.
1156 const auto slice = _get_slice(path, _num_cells, _cell_offset + _get_cell_data_offset(name));
338
3/6
✓ Branch 1 taken 688 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 688 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 688 times.
✗ Branch 8 not taken.
3468 return make_field_ptr(VTKHDF::DataSetField{
339 _file.value(),
340 MDLayout{slice.count},
341
3/6
✓ Branch 1 taken 688 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 688 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 688 times.
✗ Branch 8 not taken.
1156 _file.value().get_precision(path).value(),
342
2/4
✓ Branch 1 taken 688 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 688 times.
✗ Branch 5 not taken.
2312 _serialization_callback(path, slice)
343
1/2
✓ Branch 1 taken 688 times.
✗ Branch 2 not taken.
2312 });
344 1156 }
345
346 1164 FieldPtr _point_field(std::string_view name) const override {
347
2/4
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 692 times.
✗ Branch 5 not taken.
1164 const std::string path = "VTKHDF/PointData/" + std::string{name};
348
2/4
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 692 times.
✗ Branch 5 not taken.
1164 const auto slice = _get_slice(path, _num_points, _point_offset + _get_point_data_offset(name));
349
3/6
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 692 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 692 times.
✗ Branch 8 not taken.
3492 return make_field_ptr(VTKHDF::DataSetField{
350 _file.value(),
351 MDLayout{slice.count},
352
3/6
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 692 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 692 times.
✗ Branch 8 not taken.
1164 _file.value().get_precision(path).value(),
353
2/4
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 692 times.
✗ Branch 5 not taken.
2328 _serialization_callback(path, slice)
354
1/2
✓ Branch 1 taken 692 times.
✗ Branch 2 not taken.
2328 });
355 1164 }
356
357 496 FieldPtr _meta_data_field(std::string_view name) const override {
358 return VTKHDF::read_field_data(
359 _file.value(),
360
1/2
✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
1488 std::string{name},
361 496 _is_transient() ? std::optional{_step_index.value()} : std::nullopt
362
4/6
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 52 times.
✓ Branch 6 taken 316 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 316 times.
✗ Branch 10 not taken.
1488 );
363 }
364
365 template<Concepts::Scalar T>
366 T _read_rank_scalar(const std::string& path, const std::size_t base_offset = 0) const {
367 T result;
368 _file.value().visit_dataset(
369 path,
370 [&] (auto&& field) { field.export_to(result); },
371 HDF5::Slice{
372 .offset = {base_offset + static_cast<std::size_t>(Parallel::rank(_comm))},
373 .count = {1}
374 }
375 );
376 return result;
377 }
378
379 2320 HDF5::Slice _get_slice(const std::string& path,
380 std::size_t count,
381 std::size_t offset) const {
382
3/6
✓ Branch 1 taken 1380 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1380 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1380 times.
✗ Branch 8 not taken.
2320 auto ds_size = _file.value().get_dimensions(path).value();
383
1/2
✓ Branch 1 taken 1380 times.
✗ Branch 2 not taken.
2320 auto ds_offset = ds_size;
384
1/2
✓ Branch 1 taken 1380 times.
✗ Branch 2 not taken.
2320 std::ranges::fill(ds_offset, std::size_t{0});
385
1/2
✓ Branch 1 taken 1380 times.
✗ Branch 2 not taken.
2320 ds_size.at(0) = count;
386
1/2
✓ Branch 1 taken 1380 times.
✗ Branch 2 not taken.
2320 ds_offset.at(0) = offset;
387 2320 return {.offset = ds_offset, .count = ds_size};
388
2/6
✓ Branch 1 taken 1380 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1380 times.
✗ Branch 5 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
2320 }
389
390 2549 auto _serialization_callback(std::string path, std::optional<HDF5::Slice> slice = {}) const {
391 3485 return [_p=std::move(path), _s=std::move(slice)] (const HDF5File& file) {
392
2/4
✓ Branch 1 taken 515 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 858 times.
✗ Branch 5 not taken.
1373 if (_s)
393
6/12
✓ Branch 1 taken 515 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 515 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 515 times.
✗ Branch 8 not taken.
✓ Branch 13 taken 858 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 858 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 858 times.
✗ Branch 20 not taken.
3183 return file.visit_dataset(_p, [&] <typename F> (F&& f) { return f.serialized(); }, _s.value());
394 ✗ return file.visit_dataset(_p, [&] <typename F> (F&& f) { return f.serialized(); });
395 2549 };
396 }
397
398 11267 bool _is_transient() const {
399 11267 return static_cast<bool>(_num_steps);
400 }
401
402 9627 const HDF5File& _access_file() const {
403
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5883 times.
9627 if (!_file.has_value())
404 ✗ throw InvalidState("No file has been read");
405 9627 return _file.value();
406 }
407
408 1272 std::vector<std::size_t> _number_of_all_piece_entities(const std::string& entity_type) const {
409
1/2
✓ Branch 2 taken 814 times.
✗ Branch 3 not taken.
3816 return _access_file().template read_dataset_to<std::vector<std::size_t>>("/VTKHDF/NumberOf" + entity_type, {{
410
1/2
✓ Branch 1 taken 814 times.
✗ Branch 2 not taken.
1272 .offset = {_get_part_offset()},
411 2544 .count = {_number_of_current_pieces_in_file()}
412
1/2
✓ Branch 1 taken 814 times.
✗ Branch 2 not taken.
2544 }});
413
3/10
✓ Branch 1 taken 814 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 814 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 814 times.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
5088 }
414
415 template<std::integral T>
416 598 std::array<std::size_t, 2> _number_of_entities_and_offset_at_rank(T rank, const std::string& entity_type) const {
417
1/2
✓ Branch 1 taken 384 times.
✗ Branch 2 not taken.
598 const auto entities = _number_of_all_piece_entities(entity_type);
418
1/2
✓ Branch 1 taken 384 times.
✗ Branch 2 not taken.
1196 return std::array{entities.at(rank), _accumulate_until(rank, entities)};
419 598 }
420
421 template<typename T>
422 1628 T _accumulate_until(std::integral auto rank, const std::vector<T>& values) const {
423 1628 return std::accumulate(values.begin(), values.begin() + rank, T{0});
424 }
425
426 275 std::size_t _accumulate_over_pieces_until_step(std::size_t step, std::size_t count_per_piece) const {
427
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 58 times.
275 if (step == 0)
428 85 return 0;
429
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 58 times.
190 if (!_is_transient())
430 ✗ throw InvalidState("Step data only available in transient files");
431
432 190 std::size_t result = 0;
433
2/4
✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 58 times.
✗ Branch 5 not taken.
862 std::ranges::for_each(std::views::iota(std::size_t{0}, step), [&] (std::size_t step_idx) {
434 484 const auto num_step_pieces = _number_of_pieces_in_file_at_step(step_idx);
435 484 result += count_per_piece*num_step_pieces;
436 });
437 190 return result;
438 }
439
440 Communicator _comm;
441 std::optional<HDF5File> _file;
442 std::size_t _num_cells = 0;
443 std::size_t _num_points = 0;
444 std::size_t _cell_offset = 0;
445 std::size_t _point_offset = 0;
446 std::optional<std::size_t> _num_steps;
447 std::optional<std::size_t> _step_index;
448 };
449
450 } // namespace GridFormat
451
452 #endif // GRIDFORMAT_HAVE_HIGH_FIVE
453 #endif // GRIDFORMAT_VTK_HDF_UNSTRUCTURED_GRID_READER_HPP_
454