GCC Code Coverage Report


Directory: gridformat/
File: gridformat/vtk/pvti_writer.hpp
Date: 2026-10-12 17:50:57
Exec Total Coverage
Lines: 67 69 97.1%
Functions: 53 113 46.9%
Branches: 160 298 53.7%

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 * \copydoc GridFormat::PVTIWriter
7 */
8 #ifndef GRIDFORMAT_VTK_PVTI_WRITER_HPP_
9 #define GRIDFORMAT_VTK_PVTI_WRITER_HPP_
10
11 #include <ostream>
12 #include <string>
13 #include <algorithm>
14 #include <filesystem>
15 #include <array>
16 #include <tuple>
17 #include <cmath>
18
19 #include <gridformat/common/field.hpp>
20 #include <gridformat/common/ranges.hpp>
21 #include <gridformat/common/exceptions.hpp>
22 #include <gridformat/common/lvalue_reference.hpp>
23 #include <gridformat/common/output_file.hpp>
24
25 #include <gridformat/parallel/communication.hpp>
26 #include <gridformat/parallel/helpers.hpp>
27
28 #include <gridformat/grid/grid.hpp>
29 #include <gridformat/xml/element.hpp>
30 #include <gridformat/vtk/parallel.hpp>
31 #include <gridformat/vtk/vti_writer.hpp>
32
33 namespace GridFormat {
34
35 /*!
36 * \ingroup VTK
37 * \brief Writer for parallel .pvti files
38 */
39 template<Concepts::ImageGrid Grid,
40 Concepts::Communicator Communicator>
41 class PVTIWriter : public VTK::XMLWriterBase<Grid, PVTIWriter<Grid, Communicator>> {
42 using ParentType = VTK::XMLWriterBase<Grid, PVTIWriter<Grid, Communicator>>;
43 using CT = CoordinateType<Grid>;
44
45 static constexpr std::size_t dim = dimension<Grid>;
46 static constexpr int root_rank = 0;
47
48 public:
49 12297 explicit PVTIWriter(LValueReferenceOf<const Grid> grid,
50 Communicator comm,
51 VTK::XMLOptions xml_opts = {})
52 12297 : ParentType(grid.get(), ".pvti", true, xml_opts)
53
2/4
✓ Branch 1 taken 6161 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6161 times.
✗ Branch 5 not taken.
36891 , _comm(comm)
54 12297 {}
55
56 52 const Communicator& communicator() const {
57 52 return _comm;
58 }
59
60 private:
61 Communicator _comm;
62
63 8400 PVTIWriter _with(VTK::XMLOptions xml_opts) const override {
64
1/2
✓ Branch 4 taken 4200 times.
✗ Branch 5 not taken.
8400 return PVTIWriter{this->grid(), _comm, std::move(xml_opts)};
65 }
66
67 ✗ void _write(std::ostream&) const override {
68 ✗ throw InvalidState(
69 "PVTIWriter does not support direct export into stream. "
70 "Use overload with filename instead!"
71 );
72 }
73
74 4179 virtual void _write(const std::string& filename_with_ext) const override {
75
1/2
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
4179 const auto& local_origin = origin(this->grid());
76
1/2
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
4179 const auto& local_extents = extents(this->grid());
77
78 4179 PVTK::StructuredParallelGridHelper helper{_comm};
79
1/2
✓ Branch 1 taken 2123 times.
✗ Branch 2 not taken.
4179 const auto all_origins = Parallel::gather(_comm, local_origin, root_rank);
80
1/2
✓ Branch 1 taken 2123 times.
✗ Branch 2 not taken.
4179 const auto all_extents = Parallel::gather(_comm, local_extents, root_rank);
81
3/5
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 2107 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
✗ Branch 6 not taken.
4179 const auto is_negative_axis = VTK::CommonDetail::structured_grid_axis_orientation(spacing(this->grid()));
82
1/2
✓ Branch 1 taken 2123 times.
✗ Branch 2 not taken.
8358 const auto [exts_begin, exts_end, whole_extent, origin] = helper.compute_extents_and_origin(
83 all_origins,
84 all_extents,
85 is_negative_axis,
86
1/2
✓ Branch 2 taken 2123 times.
✗ Branch 3 not taken.
8358 basis(this->grid())
87 );
88
89
1/2
✓ Branch 1 taken 2123 times.
✗ Branch 2 not taken.
4179 const auto my_whole_extent = Parallel::broadcast(_comm, whole_extent, root_rank);
90
1/2
✓ Branch 1 taken 2123 times.
✗ Branch 2 not taken.
4179 const auto my_whole_origin = Parallel::broadcast(_comm, origin, root_rank);
91
2/4
✓ Branch 1 taken 2123 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2123 times.
✗ Branch 5 not taken.
4179 const auto my_extent_offset = Parallel::scatter(_comm, Ranges::flat(exts_begin), root_rank);
92
93 // the collective invocations also ensure that all pieces are written before the main file,
94 // and that the main file is written before returning
95
2/2
✓ Branch 1 taken 2121 times.
✓ Branch 2 taken 2 times.
8291 Parallel::invoke_collectively(_comm, [&] () {
96
5/8
✓ Branch 1 taken 483 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 482 times.
✓ Branch 5 taken 1 times.
✓ Branch 7 taken 1640 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1640 times.
✗ Branch 11 not taken.
2123 _write_piece(filename_with_ext, Ranges::to_array<dim>(my_extent_offset), {my_whole_origin, my_whole_extent});
97
2/4
✓ Branch 1 taken 2123 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2123 times.
✗ Branch 5 not taken.
8362 }, "Writing the pieces of '" + filename_with_ext + "'");
98
2/2
✓ Branch 1 taken 2118 times.
✓ Branch 2 taken 3 times.
8289 Parallel::invoke_collectively(_comm, [&] () {
99
4/4
✓ Branch 1 taken 171 times.
✓ Branch 2 taken 310 times.
✓ Branch 4 taken 546 times.
✓ Branch 5 taken 1094 times.
2121 if (Parallel::rank(_comm) == 0)
100 717 _write_pvti_file(filename_with_ext, my_whole_origin, my_whole_extent, exts_begin, exts_end);
101
2/4
✓ Branch 1 taken 2121 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2121 times.
✗ Branch 5 not taken.
8360 }, "Writing '" + filename_with_ext + "'");
102 4194 }
103
104 4179 void _write_piece(const std::string& par_filename,
105 const std::array<std::size_t, dim>& offset,
106 typename VTIWriter<Grid>::Domain domain) const {
107
1/2
✓ Branch 2 taken 2123 times.
✗ Branch 3 not taken.
8358 auto writer = VTIWriter{this->grid(), this->_xml_opts}
108
2/4
✓ Branch 2 taken 2123 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2123 times.
✗ Branch 7 not taken.
8358 .as_piece_for(std::move(domain))
109 .with_offset(offset);
110
1/2
✓ Branch 1 taken 2123 times.
✗ Branch 2 not taken.
4179 this->copy_fields(writer);
111
6/8
✓ Branch 1 taken 2122 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2122 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2121 times.
✓ Branch 8 taken 1 times.
4180 writer.write(PVTK::piece_basefilename(par_filename, Parallel::rank(_comm)));
112 4179 }
113
114 1401 void _write_pvti_file(const std::string& filename_with_ext,
115 const std::array<CT, dim>& origin,
116 const std::array<std::size_t, dim>& extents,
117 const std::vector<std::array<std::size_t, dim>>& proc_extents_begin,
118 const std::vector<std::array<std::size_t, dim>>& proc_extents_end) const {
119
1/2
✓ Branch 1 taken 717 times.
✗ Branch 2 not taken.
2802 XMLElement pvtk_xml("VTKFile");
120
2/4
✓ Branch 1 taken 717 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 717 times.
✗ Branch 5 not taken.
2802 pvtk_xml.set_attribute("type", "PImageData");
121
122
2/4
✓ Branch 1 taken 717 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 717 times.
✗ Branch 5 not taken.
1401 XMLElement& grid = pvtk_xml.add_child("PImageData");
123
3/6
✓ Branch 1 taken 717 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 717 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 717 times.
✗ Branch 8 not taken.
4203 grid.set_attribute("WholeExtent", VTK::CommonDetail::extents_string(extents));
124
3/6
✓ Branch 1 taken 717 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 717 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 717 times.
✗ Branch 8 not taken.
4203 grid.set_attribute("Origin", VTK::CommonDetail::number_string_3d(origin));
125
7/11
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 713 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 713 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 713 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 4 times.
✗ Branch 12 not taken.
4203 grid.set_attribute("Spacing", VTK::CommonDetail::number_string_3d(spacing(this->grid())));
126
4/8
✓ Branch 2 taken 717 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 717 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 717 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 717 times.
✗ Branch 12 not taken.
4203 grid.set_attribute("Direction", VTK::CommonDetail::direction_string(basis(this->grid())));
127
128
2/4
✓ Branch 1 taken 717 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 717 times.
✗ Branch 5 not taken.
2802 XMLElement& ppoint_data = grid.add_child("PPointData");
129
2/4
✓ Branch 1 taken 717 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 717 times.
✗ Branch 5 not taken.
1401 XMLElement& pcell_data = grid.add_child("PCellData");
130 1500 std::visit([&] (const auto& encoder) {
131 2217 std::visit([&] (const auto& data_format) {
132 717 PVTK::PDataArrayHelper pdata_helper{encoder, data_format, ppoint_data};
133 717 PVTK::PDataArrayHelper cdata_helper{encoder, data_format, pcell_data};
134
24/48
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 98 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 98 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 128 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 128 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 258 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 258 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 8 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 8 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 8 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 8 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 8 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 8 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 32 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 32 times.
✗ Branch 47 not taken.
✓ Branch 49 taken 32 times.
✗ Branch 50 not taken.
✓ Branch 52 taken 32 times.
✗ Branch 53 not taken.
✓ Branch 55 taken 32 times.
✗ Branch 56 not taken.
✓ Branch 58 taken 32 times.
✗ Branch 59 not taken.
✓ Branch 61 taken 16 times.
✗ Branch 62 not taken.
✓ Branch 64 taken 16 times.
✗ Branch 65 not taken.
✓ Branch 67 taken 64 times.
✗ Branch 68 not taken.
✓ Branch 70 taken 64 times.
✗ Branch 71 not taken.
8389 std::ranges::for_each(this->_point_field_names(), [&] (const std::string& name) {
135 3720 pdata_helper.add(name, this->_get_point_field(name));
136 });
137
24/48
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 98 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 98 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 128 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 128 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 258 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 258 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 8 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 8 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 8 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 8 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 8 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 8 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 32 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 32 times.
✗ Branch 47 not taken.
✓ Branch 49 taken 32 times.
✗ Branch 50 not taken.
✓ Branch 52 taken 32 times.
✗ Branch 53 not taken.
✓ Branch 55 taken 32 times.
✗ Branch 56 not taken.
✓ Branch 58 taken 32 times.
✗ Branch 59 not taken.
✓ Branch 61 taken 16 times.
✗ Branch 62 not taken.
✓ Branch 64 taken 16 times.
✗ Branch 65 not taken.
✓ Branch 67 taken 64 times.
✗ Branch 68 not taken.
✓ Branch 70 taken 64 times.
✗ Branch 71 not taken.
8385 std::ranges::for_each(this->_cell_field_names(), [&] (const std::string& name) {
138 3719 cdata_helper.add(name, this->_get_cell_field(name));
139 });
140
6/12
✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 106 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 160 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 290 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 24 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 96 times.
✗ Branch 17 not taken.
717 }, this->_xml_settings.data_format);
141
1/2
✓ Branch 1 taken 717 times.
✗ Branch 2 not taken.
1401 }, this->_xml_settings.encoder);
142
143
2/4
✓ Branch 1 taken 717 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 717 times.
✗ Branch 5 not taken.
5513 std::ranges::for_each(Parallel::ranks(_comm), [&] (int rank) {
144 std::array<std::size_t, dim> extents_begin;
145 std::array<std::size_t, dim> extents_end;
146
4/4
✓ Branch 0 taken 962 times.
✓ Branch 1 taken 481 times.
✓ Branch 2 taken 4920 times.
✓ Branch 3 taken 1640 times.
8003 for (unsigned dir = 0; dir < dim; ++dir) {
147 5882 extents_begin[dir] = proc_extents_begin[rank][dir];
148 5882 extents_end[dir] = proc_extents_end[rank][dir];
149 }
150
151
4/8
✓ Branch 1 taken 481 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 481 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 1640 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 1640 times.
✗ Branch 13 not taken.
4242 auto& piece = grid.add_child("Piece");
152
6/12
✓ Branch 1 taken 481 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 481 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 481 times.
✗ Branch 8 not taken.
✓ Branch 14 taken 1640 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1640 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 1640 times.
✗ Branch 21 not taken.
6363 piece.set_attribute("Extent", VTK::CommonDetail::extents_string(extents_begin, extents_end));
153
6/12
✓ Branch 1 taken 481 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 481 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 481 times.
✗ Branch 8 not taken.
✓ Branch 14 taken 1640 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1640 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 1640 times.
✗ Branch 21 not taken.
6363 piece.set_attribute("Source", std::filesystem::path{
154
4/8
✓ Branch 1 taken 481 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 481 times.
✗ Branch 5 not taken.
✓ Branch 11 taken 1640 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 1640 times.
✗ Branch 15 not taken.
4242 PVTK::piece_basefilename(filename_with_ext, rank) + ".vti"
155
2/4
✓ Branch 1 taken 481 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 1640 times.
✗ Branch 7 not taken.
6363 }.filename());
156 });
157
158
2/4
✓ Branch 2 taken 717 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 717 times.
✗ Branch 6 not taken.
1401 this->_set_default_active_fields(pvtk_xml.get_child("PImageData"));
159
2/2
✓ Branch 1 taken 715 times.
✓ Branch 2 taken 2 times.
2769 write_to(filename_with_ext, [&] (std::ostream& s) {
160
4/8
✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 169 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 546 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 546 times.
✗ Branch 13 not taken.
715 write_xml_with_version_header(pvtk_xml, s, Indentation{{.width = 2}});
161 });
162 1401 }
163 };
164
165 template<typename G, Concepts::Communicator C>
166 PVTIWriter(G&&, const C&, VTK::XMLOptions = {}) -> PVTIWriter<std::remove_cvref_t<G>, C>;
167
168 namespace Traits {
169
170 template<typename... Args>
171 struct WritesConnectivity<PVTIWriter<Args...>> : public std::false_type {};
172
173 } // namespace Traits
174 } // namespace GridFormat
175
176 #endif // GRIDFORMAT_VTK_PVTI_WRITER_HPP_
177