GCC Code Coverage Report


Directory: gridformat/
File: gridformat/vtk/hdf_unstructured_grid_writer.hpp
Date: 2024-11-20 14:41:59
Exec Total Coverage
Lines: 201 205 98.0%
Functions: 365 432 84.5%
Branches: 257 494 52.0%

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 Writer for the VTK HDF file format for unstructured grids.
7 */
8 #ifndef GRIDFORMAT_VTK_HDF_UNSTRUCTURED_GRID_WRITER_HPP_
9 #define GRIDFORMAT_VTK_HDF_UNSTRUCTURED_GRID_WRITER_HPP_
10 #if GRIDFORMAT_HAVE_HIGH_FIVE
11
12 #include <type_traits>
13 #include <ostream>
14
15 #include <gridformat/common/exceptions.hpp>
16 #include <gridformat/common/md_layout.hpp>
17 #include <gridformat/common/concepts.hpp>
18 #include <gridformat/common/lvalue_reference.hpp>
19
20 #include <gridformat/parallel/communication.hpp>
21 #include <gridformat/parallel/concepts.hpp>
22
23 #include <gridformat/grid/concepts.hpp>
24 #include <gridformat/grid/writer.hpp>
25
26 #include <gridformat/vtk/common.hpp>
27 #include <gridformat/vtk/hdf_common.hpp>
28
29 namespace GridFormat {
30
31 template<bool is_transient,
32 Concepts::UnstructuredGrid G,
33 Concepts::Communicator Communicator = NullCommunicator>
34 class VTKHDFUnstructuredGridWriterImpl : public GridDetail::WriterBase<is_transient, G>::type {
35 static constexpr int root_rank = 0;
36 static constexpr std::size_t vtk_space_dim = 3;
37
38 using CT = CoordinateType<G>;
39 template<typename T> using Vector = std::array<T, vtk_space_dim>;
40 template<typename T> using Tensor = std::array<T, vtk_space_dim*vtk_space_dim>;
41
42 using IOContext = VTKHDF::IOContext;
43 using HDF5File = HDF5::File<Communicator>;
44
45 static constexpr WriterOptions writer_opts{
46 .use_structured_grid_ordering = false,
47 .append_null_terminator_to_strings = true
48 };
49
50 struct TimeSeriesOffsets {
51 std::size_t cell_offset;
52 std::size_t connectivity_offset;
53 std::size_t point_offset;
54 };
55
56 public:
57 using Grid = G;
58
59 11 explicit VTKHDFUnstructuredGridWriterImpl(LValueReferenceOf<const Grid> grid)
60 requires(!is_transient && std::is_same_v<Communicator, NullCommunicator>)
61
3/6
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
55 : GridWriter<Grid>(grid.get(), ".hdf", writer_opts)
62 11 {}
63
64 41 explicit VTKHDFUnstructuredGridWriterImpl(LValueReferenceOf<const Grid> grid, const Communicator& comm)
65 requires(!is_transient && std::is_copy_constructible_v<Communicator>)
66 : GridWriter<Grid>(grid.get(), ".hdf", writer_opts)
67
3/6
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 25 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 25 times.
✗ Branch 11 not taken.
205 , _comm{comm}
68 41 {}
69
70 12 explicit VTKHDFUnstructuredGridWriterImpl(LValueReferenceOf<const Grid> grid,
71 std::string filename_without_extension,
72 VTK::HDFTransientOptions opts = {})
73 requires(is_transient && std::is_same_v<Communicator, NullCommunicator>)
74 : TimeSeriesGridWriter<Grid>(grid.get(), writer_opts)
75 , _comm{}
76
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 , _timeseries_filename{std::move(filename_without_extension) + ".hdf"}
77
1/2
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
24 , _transient_opts{std::move(opts)}
78 12 {}
79
80 21 explicit VTKHDFUnstructuredGridWriterImpl(LValueReferenceOf<const Grid> grid,
81 const Communicator& comm,
82 std::string filename_without_extension,
83 VTK::HDFTransientOptions opts = {})
84 requires(is_transient && std::is_copy_constructible_v<Communicator>)
85 : TimeSeriesGridWriter<Grid>(grid.get(), writer_opts)
86 20 , _comm{comm}
87
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 , _timeseries_filename{std::move(filename_without_extension) + ".hdf"}
88
1/2
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
42 , _transient_opts{std::move(opts)}
89 21 {}
90
91 const Communicator& communicator() const {
92 return _comm;
93 }
94
95 private:
96 void _write(std::ostream&) const {
97 throw InvalidState("VTKHDFUnstructuredGridWriter does not support export into stream");
98 }
99
100 61 void _write(const std::string& filename_with_ext) const {
101 if constexpr (is_transient)
102 throw InvalidState("This overload only works for non-transient output");
103
1/2
✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
61 HDF5File file{filename_with_ext, _comm, HDF5File::overwrite};
104
1/2
✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
61 _write_to(file);
105 61 }
106
107 141 std::string _write(double t) {
108 if constexpr (!is_transient)
109 throw InvalidState("This overload only works for transient output");
110
111
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 108 times.
141 if (this->_step_count == 0)
112
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 HDF5File::clear(_timeseries_filename, _comm);
113
114
1/2
✓ Branch 1 taken 141 times.
✗ Branch 2 not taken.
141 HDF5File file{_timeseries_filename, _comm, HDF5File::append};
115
1/2
✓ Branch 1 taken 141 times.
✗ Branch 2 not taken.
141 const auto offsets = _write_to(file);
116
117
2/4
✓ Branch 1 taken 141 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 141 times.
✗ Branch 5 not taken.
141 file.write_attribute(this->_step_count+1, "/VTKHDF/Steps/NSteps");
118
2/4
✓ Branch 2 taken 141 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 141 times.
✗ Branch 6 not taken.
423 file.write(std::array{t}, "VTKHDF/Steps/Values");
119
3/6
✓ Branch 2 taken 141 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 141 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 141 times.
✗ Branch 9 not taken.
705 file.write(std::vector{offsets.point_offset}, "VTKHDF/Steps/PointOffsets");
120
3/6
✓ Branch 2 taken 141 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 141 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 141 times.
✗ Branch 9 not taken.
705 file.write(std::vector{std::array{offsets.cell_offset}}, "/VTKHDF/Steps/CellOffsets");
121
3/6
✓ Branch 2 taken 141 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 141 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 141 times.
✗ Branch 9 not taken.
705 file.write(std::vector{std::array{offsets.connectivity_offset}}, "VTKHDF/Steps/ConnectivityIdOffsets");
122
123
6/10
✓ Branch 2 taken 141 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 84 times.
✓ Branch 6 taken 57 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 84 times.
✓ Branch 9 taken 57 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 84 times.
✗ Branch 12 not taken.
705 file.write(std::vector{Parallel::size(_comm)}, "/VTKHDF/Steps/NumberOfParts");
124
4/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 104 times.
141 if (this->_step_count > 0 && _transient_opts.static_grid) {
125
3/6
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
16 file.write(
126
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
12 std::vector{_get_last_step_data(file, "PartOffsets")},
127 "/VTKHDF/Steps/PartOffsets"
128 );
129 } else {
130 274 const std::size_t offset = this->_step_count == 0
131
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 33 times.
137 ? 0
132
9/16
✓ Branch 1 taken 104 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 104 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 104 times.
✓ Branch 8 taken 13 times.
✓ Branch 9 taken 64 times.
✓ Branch 10 taken 60 times.
✓ Branch 11 taken 13 times.
✓ Branch 12 taken 64 times.
✓ Branch 13 taken 20 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
137 : _get_last_step_data(file, "PartOffsets") + Parallel::size(_comm);
133
3/6
✓ Branch 2 taken 137 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 137 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 137 times.
✗ Branch 9 not taken.
685 file.write(std::vector{offset}, "/VTKHDF/Steps/PartOffsets");
134 }
135
136
1/2
✓ Branch 1 taken 141 times.
✗ Branch 2 not taken.
282 return _timeseries_filename;
137 141 }
138
139 292 TimeSeriesOffsets _write_to(HDF5File& file) const {
140
2/4
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 182 times.
✗ Branch 5 not taken.
584 file.write_attribute(std::array<std::size_t, 2>{(is_transient ? 2 : 1), 0}, "/VTKHDF/Version");
141
2/4
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 182 times.
✗ Branch 5 not taken.
292 file.write_attribute("UnstructuredGrid", "/VTKHDF/Type");
142
143 TimeSeriesOffsets offsets;
144
1/2
✓ Branch 2 taken 182 times.
✗ Branch 3 not taken.
292 const auto context = IOContext::from(this->grid(), _comm, root_rank);
145
1/2
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
292 _write_num_cells_and_points(file, context);
146
1/2
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
292 offsets.point_offset = _write_coordinates(file, context);
147
1/2
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
292 offsets.connectivity_offset = _write_connectivity(file, context);
148
1/2
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
292 offsets.cell_offset = _write_types(file, context);
149
1/2
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
292 _write_offsets(file, context);
150
1/2
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
292 _write_meta_data(file);
151
1/2
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
292 _write_point_fields(file, context);
152
1/2
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
292 _write_cell_fields(file, context);
153
154 584 return offsets;
155 292 }
156
157 292 void _write_num_cells_and_points(HDF5File& file, const IOContext& context) const {
158
7/11
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 134 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 48 times.
✓ Branch 6 taken 134 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 48 times.
✓ Branch 9 taken 134 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 48 times.
✗ Branch 12 not taken.
1168 _write_values(file, "/VTKHDF/NumberOfPoints", std::vector{number_of_points(this->grid())}, context);
159
7/11
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 134 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 48 times.
✓ Branch 6 taken 134 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 48 times.
✓ Branch 9 taken 134 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 48 times.
✗ Branch 12 not taken.
1168 _write_values(file, "/VTKHDF/NumberOfCells", std::vector{number_of_cells(this->grid())}, context);
160 292 }
161
162 292 std::size_t _write_coordinates(HDF5File& file, const IOContext& context) const {
163 if constexpr (is_transient) {
164
4/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 104 times.
216 if (this->_step_count > 0 && _transient_opts.static_grid)
165
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 return _get_last_step_data(file, "PointOffsets");
166 }
167
1/2
✓ Branch 2 taken 178 times.
✗ Branch 3 not taken.
288 const auto coords_field = VTK::make_coordinates_field<CT>(this->grid(), false);
168
2/4
✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 178 times.
✗ Branch 5 not taken.
288 const auto offset = _get_current_offset(file, "/VTKHDF/Points");
169
2/4
✓ Branch 2 taken 178 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 178 times.
✗ Branch 6 not taken.
576 _write_point_field(file, "/VTKHDF/Points", *coords_field, context);
170 288 return offset;
171 288 }
172
173 292 std::size_t _write_connectivity(HDF5File& file, const IOContext& context) const {
174 if constexpr (is_transient) {
175
4/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 104 times.
216 if (this->_step_count > 0 && _transient_opts.static_grid)
176
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 return _get_last_step_data(file, "ConnectivityIdOffsets");
177 }
178
1/2
✓ Branch 2 taken 178 times.
✗ Branch 3 not taken.
288 const auto point_id_map = make_point_id_map(this->grid());
179
1/2
✓ Branch 2 taken 178 times.
✗ Branch 3 not taken.
288 const auto connectivity_field = VTK::make_connectivity_field(this->grid(), point_id_map);
180
2/4
✓ Branch 2 taken 178 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 178 times.
✗ Branch 6 not taken.
288 const auto num_entries = connectivity_field->layout().number_of_entries();
181
1/2
✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
864 const auto my_num_ids = std::vector{static_cast<long>(num_entries)};
182
1/2
✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
288 std::vector<long> connectivity(num_entries);
183
1/2
✓ Branch 2 taken 178 times.
✗ Branch 3 not taken.
288 connectivity_field->export_to(connectivity);
184
2/4
✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 178 times.
✗ Branch 5 not taken.
576 const auto offset = _get_current_offset(file, "/VTKHDF/Connectivity");
185
2/4
✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 178 times.
✗ Branch 5 not taken.
576 _write_values(file, "/VTKHDF/Connectivity", connectivity, context);
186
2/4
✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 178 times.
✗ Branch 5 not taken.
288 _write_values(file, "/VTKHDF/NumberOfConnectivityIds", my_num_ids, context);
187 288 return offset;
188 288 }
189
190 292 std::size_t _write_types(HDF5File& file, const IOContext& context) const {
191 if constexpr (is_transient) {
192
4/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 104 times.
216 if (this->_step_count > 0 && _transient_opts.static_grid)
193
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 return _get_last_step_data(file, "CellOffsets");
194 }
195
1/2
✓ Branch 2 taken 178 times.
✗ Branch 3 not taken.
288 const auto types_field = VTK::make_cell_types_field(this->grid());
196
3/6
✓ Branch 2 taken 178 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 178 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 178 times.
✗ Branch 9 not taken.
288 std::vector<std::uint8_t> types(types_field->layout().number_of_entries());
197
1/2
✓ Branch 2 taken 178 times.
✗ Branch 3 not taken.
288 types_field->export_to(types);
198
2/4
✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 178 times.
✗ Branch 5 not taken.
576 const auto offset = _get_current_offset(file, "VTKHDF/Types");
199
2/4
✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 178 times.
✗ Branch 5 not taken.
288 _write_values(file, "VTKHDF/Types", types, context);
200 288 return offset;
201 288 }
202
203 292 std::size_t _write_offsets(HDF5File& file, const IOContext& context) const {
204 if constexpr (is_transient) {
205
4/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 104 times.
216 if (this->_step_count > 0 && _transient_opts.static_grid)
206
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 return _get_last_step_data(file, "CellOffsets");
207 }
208
1/2
✓ Branch 2 taken 178 times.
✗ Branch 3 not taken.
288 const auto offsets_field = VTK::make_offsets_field(this->grid());
209
2/4
✓ Branch 2 taken 178 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 178 times.
✗ Branch 6 not taken.
288 const auto num_offset_entries = offsets_field->layout().number_of_entries() + 1;
210
1/2
✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
288 std::vector<long> offsets(num_offset_entries);
211
1/2
✓ Branch 5 taken 178 times.
✗ Branch 6 not taken.
576 offsets_field->export_to(std::ranges::subrange(std::next(offsets.begin()), offsets.end()));
212 288 offsets[0] = long{0};
213
2/4
✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 178 times.
✗ Branch 5 not taken.
576 const auto offset = _get_current_offset(file, "/VTKHDF/Offsets");
214
2/4
✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 178 times.
✗ Branch 5 not taken.
288 _write_values(file, "/VTKHDF/Offsets", offsets, context);
215 288 return offset;
216 288 }
217
218 292 void _write_meta_data(HDF5File& file) const {
219
2/4
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 182 times.
✗ Branch 5 not taken.
691 std::ranges::for_each(this->_meta_data_field_names(), [&] (const std::string& name) {
220 if constexpr (is_transient) {
221
4/4
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 99 times.
✓ Branch 2 taken 312 times.
✓ Branch 3 taken 12 times.
423 if (this->_step_count > 0 && _transient_opts.static_meta_data) {
222
2/4
✓ Branch 2 taken 312 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 312 times.
✗ Branch 6 not taken.
312 file.write(std::array{0}, "/VTKHDF/Steps/FieldDataOffsets/" + name);
223 312 return;
224 } else {
225
2/4
✓ Branch 2 taken 111 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 111 times.
✗ Branch 6 not taken.
111 file.write(std::array{this->_step_count}, "/VTKHDF/Steps/FieldDataOffsets/" + name);
226 }
227 // For transient data, prepend a dimension indicating the step count
228
2/4
✓ Branch 1 taken 111 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 111 times.
✗ Branch 5 not taken.
111 TransformedField sub{this->_get_meta_data_field_ptr(name), FieldTransformation::as_sub_field};
229
2/4
✓ Branch 2 taken 111 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 111 times.
✗ Branch 6 not taken.
111 file.write(sub, "/VTKHDF/FieldData/" + name);
230 111 } else {
231
6/12
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 81 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 81 times.
✗ Branch 10 not taken.
✓ Branch 19 taken 21 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 21 times.
✗ Branch 23 not taken.
✓ Branch 26 taken 21 times.
✗ Branch 27 not taken.
102 file.write(*this->_get_meta_data_field_ptr(name), "/VTKHDF/FieldData/" + name);
232 }
233 });
234 292 }
235
236 292 void _write_point_fields(HDF5File& file, const IOContext& context) const {
237
2/4
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 182 times.
✗ Branch 5 not taken.
1149 std::ranges::for_each(this->_point_field_names(), [&] (const std::string& name) {
238 if constexpr (is_transient)
239
2/4
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 666 times.
✗ Branch 5 not taken.
666 _write_step_offset(
240 file,
241
1/2
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
1332 _get_current_offset(file, "/VTKHDF/PointData/" + name),
242
1/2
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
1332 "/VTKHDF/Steps/PointDataOffsets/" + name
243 );
244
9/18
✓ Branch 1 taken 362 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 362 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 362 times.
✗ Branch 8 not taken.
✓ Branch 14 taken 492 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 492 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 492 times.
✗ Branch 21 not taken.
✓ Branch 27 taken 3 times.
✗ Branch 28 not taken.
✓ Branch 30 taken 3 times.
✗ Branch 31 not taken.
✓ Branch 33 taken 3 times.
✗ Branch 34 not taken.
857 auto reshaped = _reshape(VTK::make_vtk_field(this->_get_point_field_ptr(name)));
245
6/12
✓ Branch 2 taken 362 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 362 times.
✗ Branch 6 not taken.
✓ Branch 11 taken 492 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 492 times.
✗ Branch 15 not taken.
✓ Branch 20 taken 3 times.
✗ Branch 21 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 24 not taken.
857 _write_point_field(file, "/VTKHDF/PointData/" + name, *reshaped, context);
246 857 });
247 292 }
248
249 292 void _write_cell_fields(HDF5File& file, const IOContext& context) const {
250
2/4
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 182 times.
✗ Branch 5 not taken.
1137 std::ranges::for_each(this->_cell_field_names(), [&] (const std::string& name) {
251 if constexpr (is_transient)
252
2/4
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 666 times.
✗ Branch 5 not taken.
666 _write_step_offset(
253 file,
254
1/2
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
1332 _get_current_offset(file, "VTKHDF/CellData/" + name),
255
1/2
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
1332 "/VTKHDF/Steps/CellDataOffsets/" + name
256 );
257
6/18
✓ Branch 1 taken 353 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 353 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 353 times.
✗ Branch 8 not taken.
✓ Branch 14 taken 492 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 492 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 492 times.
✗ Branch 21 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.
845 auto reshaped = _reshape(VTK::make_vtk_field(this->_get_cell_field_ptr(name)));
258
4/12
✓ Branch 2 taken 353 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 353 times.
✗ Branch 6 not taken.
✓ Branch 11 taken 492 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 492 times.
✗ Branch 15 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
845 _write_cell_field(file, "/VTKHDF/CellData/" + name, *reshaped, context);
259 845 });
260 292 }
261
262 2956 FieldPtr _reshape(FieldPtr field_ptr) const {
263 // VTK requires tensors to be written as flat fields
264
1/2
✓ Branch 2 taken 1702 times.
✗ Branch 3 not taken.
2956 const auto layout = field_ptr->layout();
265
3/4
✓ Branch 1 taken 1702 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 352 times.
✓ Branch 4 taken 1350 times.
2956 if (layout.dimension() > 2)
266
1/2
✓ Branch 2 taken 352 times.
✗ Branch 3 not taken.
2496 return make_field_ptr(ReshapedField{
267 field_ptr,
268
3/6
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 352 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 352 times.
✗ Branch 8 not taken.
1248 MDLayout{{layout.extent(0), layout.number_of_entries(1)}}
269
1/2
✓ Branch 1 taken 352 times.
✗ Branch 2 not taken.
624 });
270 2332 return field_ptr;
271 2956 }
272
273 template<Concepts::Scalar T>
274 2152 void _write_values(HDF5File& file,
275 const std::string& path,
276 const std::vector<T>& values,
277 const IOContext& context) const {
278
2/2
✓ Branch 0 taken 684 times.
✓ Branch 1 taken 392 times.
2152 if (context.is_parallel) {
279 1368 const auto num_values = values.size();
280
1/2
✓ Branch 1 taken 684 times.
✗ Branch 2 not taken.
1368 const auto total_num_values = Parallel::sum(_comm, num_values, root_rank);
281
1/2
✓ Branch 1 taken 684 times.
✗ Branch 2 not taken.
1368 const auto my_total_num_values = Parallel::broadcast(_comm, total_num_values, root_rank);
282
1/2
✓ Branch 1 taken 684 times.
✗ Branch 2 not taken.
1368 const auto my_offset = _accumulate_rank_offset(num_values);
283
3/10
✓ Branch 1 taken 684 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 684 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 684 times.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
6840 HDF5::Slice slice{
284 .offset = std::vector{my_offset},
285 .count = std::vector{num_values},
286 .total_size = std::vector{my_total_num_values}
287 };
288
2/4
✓ Branch 1 taken 684 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 684 times.
✗ Branch 5 not taken.
1368 file.write(values, path, slice);
289 1368 } else {
290
1/2
✓ Branch 2 taken 392 times.
✗ Branch 3 not taken.
784 file.write(values, path);
291 }
292 2152 }
293
294 1775 void _write_point_field(HDF5File& file,
295 const std::string& path,
296 const Field& field,
297 const IOContext& context) const {
298 1775 _write_field(file, path, field, context.is_parallel, context.my_point_offset, context.num_points_total);
299 1775 }
300
301 1469 void _write_cell_field(HDF5File& file,
302 const std::string& path,
303 const Field& field,
304 const IOContext& context) const {
305 1469 _write_field(file, path, field, context.is_parallel, context.my_cell_offset, context.num_cells_total);
306 1469 }
307
308 3244 void _write_field(HDF5File& file,
309 const std::string& path,
310 const Field& field,
311 bool is_parallel,
312 std::size_t main_offset,
313 std::size_t main_size) const {
314
2/2
✓ Branch 0 taken 1158 times.
✓ Branch 1 taken 722 times.
3244 if (is_parallel) {
315
1/2
✓ Branch 1 taken 1158 times.
✗ Branch 2 not taken.
2102 const auto layout = field.layout();
316
2/4
✓ Branch 1 taken 1158 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1158 times.
✗ Branch 5 not taken.
2102 std::vector<std::size_t> count(layout.dimension());
317
1/2
✓ Branch 1 taken 1158 times.
✗ Branch 2 not taken.
2102 layout.export_to(count);
318
319
1/2
✓ Branch 1 taken 1158 times.
✗ Branch 2 not taken.
2102 std::vector<std::size_t> size = count;
320
2/4
✓ Branch 1 taken 1158 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1158 times.
✗ Branch 5 not taken.
2102 std::vector<std::size_t> offset(layout.dimension(), 0);
321
1/2
✓ Branch 1 taken 1158 times.
✗ Branch 2 not taken.
2102 offset.at(0) = main_offset;
322
1/2
✓ Branch 1 taken 1158 times.
✗ Branch 2 not taken.
2102 size.at(0) = main_size;
323
324
1/2
✓ Branch 1 taken 1158 times.
✗ Branch 2 not taken.
2102 file.write(field, path, HDF5::Slice{
325 2102 .offset = std::move(offset),
326 2102 .count = std::move(count),
327 2102 .total_size = std::move(size)
328 });
329 2102 } else {
330
1/2
✓ Branch 2 taken 722 times.
✗ Branch 3 not taken.
1142 file.write(field, path);
331 }
332
0/4
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
5346 }
333
334 1140 std::size_t _accumulate_rank_offset(std::size_t my_size) const {
335
1/2
✓ Branch 1 taken 684 times.
✗ Branch 2 not taken.
1140 auto all_offsets = Parallel::gather(_comm, my_size, root_rank);
336
3/4
✓ Branch 1 taken 684 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 330 times.
✓ Branch 4 taken 354 times.
1140 if (Parallel::rank(_comm) == root_rank) {
337 1092 std::partial_sum(all_offsets.begin(), std::prev(all_offsets.end()), all_offsets.begin());
338
1/2
✓ Branch 4 taken 330 times.
✗ Branch 5 not taken.
1092 std::copy(std::next(all_offsets.rbegin()), all_offsets.rend(), all_offsets.rbegin());
339 546 all_offsets[0] = 0;
340 }
341
1/2
✓ Branch 1 taken 684 times.
✗ Branch 2 not taken.
1140 const auto my_offset = Parallel::scatter(_comm, all_offsets, root_rank);
342
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 684 times.
1140 if (my_offset.size() != 1)
343 throw ValueError("Unexpected scatter result");
344 2280 return my_offset[0];
345 1140 }
346
347 1332 void _write_step_offset(HDF5File& file,
348 const std::size_t offset,
349 const std::string& path) const {
350
1/2
✓ Branch 2 taken 1332 times.
✗ Branch 3 not taken.
1332 file.write(std::array{offset}, path);
351 1332 }
352
353 3384 std::size_t _get_current_offset(HDF5File& file, const std::string& path) const {
354
1/2
✓ Branch 1 taken 2044 times.
✗ Branch 2 not taken.
3384 const auto cur_dimensions = file.get_dimensions(path);
355
2/2
✓ Branch 1 taken 1472 times.
✓ Branch 2 taken 572 times.
6768 return cur_dimensions ? (*cur_dimensions)[0] : 0;
356 3384 }
357
358 124 std::size_t _get_last_step_data(const HDF5File& file, const std::string& sub_path) const {
359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
124 if (this->_step_count == 0)
360 throw ValueError("Last step data can only be read after at least one write");
361
1/2
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
124 const std::string path ="VTKHDF/Steps/" + sub_path;
362
363
2/4
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 124 times.
✗ Branch 5 not taken.
124 auto step_dimensions = file.get_dimensions(path).value();
364
1/2
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
124 std::ranges::fill(step_dimensions, std::size_t{1});
365
366
1/2
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
124 auto access_offset = step_dimensions;
367
1/2
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
124 std::ranges::fill(access_offset, std::size_t{0});
368
1/2
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
124 access_offset.at(0) = this->_step_count - 1;
369
370
1/2
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
248 return file.template read_dataset_to<std::size_t>(path, HDF5::Slice{
371 124 .offset = std::move(access_offset),
372 124 .count = std::move(step_dimensions)
373 248 });
374
0/4
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
248 }
375
376 Communicator _comm;
377 std::string _timeseries_filename = "";
378 VTK::HDFTransientOptions _transient_opts;
379 };
380
381 /*!
382 * \ingroup VTK
383 * \brief Writer for the VTK HDF file format for unstructured grids.
384 */
385 template<Concepts::UnstructuredGrid G, Concepts::Communicator C = NullCommunicator>
386 class VTKHDFUnstructuredGridWriter : public VTKHDFUnstructuredGridWriterImpl<false, G, C> {
387 using ParentType = VTKHDFUnstructuredGridWriterImpl<false, G, C>;
388 public:
389 using ParentType::ParentType;
390 };
391
392 /*!
393 * \ingroup VTK
394 * \brief Writer for the transient VTK HDF file format for unstructured grids.
395 */
396 template<Concepts::UnstructuredGrid G, Concepts::Communicator C = NullCommunicator>
397 class VTKHDFUnstructuredTimeSeriesWriter : public VTKHDFUnstructuredGridWriterImpl<true, G, C> {
398 using ParentType = VTKHDFUnstructuredGridWriterImpl<true, G, C>;
399 public:
400 using ParentType::ParentType;
401 };
402
403 template<Concepts::UnstructuredGrid G>
404 VTKHDFUnstructuredGridWriter(const G&) -> VTKHDFUnstructuredGridWriter<G, NullCommunicator>;
405 template<Concepts::UnstructuredGrid G, Concepts::Communicator C>
406 VTKHDFUnstructuredGridWriter(const G&, const C&) -> VTKHDFUnstructuredGridWriter<G, C>;
407
408 template<Concepts::UnstructuredGrid G>
409 VTKHDFUnstructuredTimeSeriesWriter(const G&, std::string, VTK::HDFTransientOptions = {}) -> VTKHDFUnstructuredTimeSeriesWriter<G, NullCommunicator>;
410 template<Concepts::UnstructuredGrid G, Concepts::Communicator C>
411 VTKHDFUnstructuredTimeSeriesWriter(const G&, const C&, std::string, VTK::HDFTransientOptions = {}) -> VTKHDFUnstructuredTimeSeriesWriter<G, C>;
412
413 } // namespace GridFormat
414
415 #endif // GRIDFORMAT_HAVE_HIGH_FIVE
416 #endif // GRIDFORMAT_VTK_HDF_UNSTRUCTURED_GRID_WRITER_HPP_
417