| 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 |