GridFormat 0.4.0
I/O-Library for grid-like data structures
Loading...
Searching...
No Matches
pvti_writer.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2022-2023 Dennis Gläser <dennis.glaeser@iws.uni-stuttgart.de>
2// SPDX-License-Identifier: MIT
8#ifndef GRIDFORMAT_VTK_PVTI_WRITER_HPP_
9#define GRIDFORMAT_VTK_PVTI_WRITER_HPP_
10
11#include <ostream>
12#include <string>
13#include <fstream>
14#include <algorithm>
15#include <filesystem>
16#include <array>
17#include <tuple>
18#include <cmath>
19
21#include <gridformat/common/ranges.hpp>
22#include <gridformat/common/exceptions.hpp>
23#include <gridformat/common/lvalue_reference.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>
32
33namespace GridFormat {
34
39template<Concepts::ImageGrid Grid,
40 Concepts::Communicator Communicator>
41class PVTIWriter : public 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 explicit PVTIWriter(LValueReferenceOf<const Grid> grid,
50 Communicator comm,
51 VTK::XMLOptions xml_opts = {})
52 : ParentType(grid.get(), ".pvti", true, xml_opts)
53 , _comm(comm)
54 {}
55
56 const Communicator& communicator() const {
57 return _comm;
58 }
59
60 private:
61 Communicator _comm;
62
63 PVTIWriter _with(VTK::XMLOptions xml_opts) const override {
64 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 virtual void _write(const std::string& filename_with_ext) const override {
75 const auto& local_origin = origin(this->grid());
76 const auto& local_extents = extents(this->grid());
77
79 const auto all_origins = Parallel::gather(_comm, local_origin, root_rank);
80 const auto all_extents = Parallel::gather(_comm, local_extents, root_rank);
81 const auto is_negative_axis = VTK::CommonDetail::structured_grid_axis_orientation(spacing(this->grid()));
82 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 basis(this->grid())
87 );
88
89 const auto my_whole_extent = Parallel::broadcast(_comm, whole_extent, root_rank);
90 const auto my_whole_origin = Parallel::broadcast(_comm, origin, root_rank);
91 const auto my_extent_offset = Parallel::scatter(_comm, Ranges::flat(exts_begin), root_rank);
92
93 _write_piece(filename_with_ext, Ranges::to_array<dim>(my_extent_offset), {my_whole_origin, my_whole_extent});
94 Parallel::barrier(_comm); // ensure all pieces finished successfully
95 if (Parallel::rank(_comm) == 0)
96 _write_pvti_file(filename_with_ext, my_whole_origin, my_whole_extent, exts_begin, exts_end);
97 Parallel::barrier(_comm); // ensure .pvti file is written before returning
98 }
99
100 void _write_piece(const std::string& par_filename,
101 const std::array<std::size_t, dim>& offset,
102 typename VTIWriter<Grid>::Domain domain) const {
103 auto writer = VTIWriter{this->grid(), this->_xml_opts}
104 .as_piece_for(std::move(domain))
105 .with_offset(offset);
106 this->copy_fields(writer);
107 writer.write(PVTK::piece_basefilename(par_filename, Parallel::rank(_comm)));
108 }
109
110 void _write_pvti_file(const std::string& filename_with_ext,
111 const std::array<CT, dim>& origin,
112 const std::array<std::size_t, dim>& extents,
113 const std::vector<std::array<std::size_t, dim>>& proc_extents_begin,
114 const std::vector<std::array<std::size_t, dim>>& proc_extents_end) const {
115 std::ofstream file_stream(filename_with_ext, std::ios::out);
116
117 XMLElement pvtk_xml("VTKFile");
118 pvtk_xml.set_attribute("type", "PImageData");
119
120 XMLElement& grid = pvtk_xml.add_child("PImageData");
121 grid.set_attribute("WholeExtent", VTK::CommonDetail::extents_string(extents));
122 grid.set_attribute("Origin", VTK::CommonDetail::number_string_3d(origin));
123 grid.set_attribute("Spacing", VTK::CommonDetail::number_string_3d(spacing(this->grid())));
124 grid.set_attribute("Direction", VTK::CommonDetail::direction_string(basis(this->grid())));
125
126 XMLElement& ppoint_data = grid.add_child("PPointData");
127 XMLElement& pcell_data = grid.add_child("PCellData");
128 std::visit([&] (const auto& encoder) {
129 std::visit([&] (const auto& data_format) {
130 PVTK::PDataArrayHelper pdata_helper{encoder, data_format, ppoint_data};
131 PVTK::PDataArrayHelper cdata_helper{encoder, data_format, pcell_data};
132 std::ranges::for_each(this->_point_field_names(), [&] (const std::string& name) {
133 pdata_helper.add(name, this->_get_point_field(name));
134 });
135 std::ranges::for_each(this->_cell_field_names(), [&] (const std::string& name) {
136 cdata_helper.add(name, this->_get_cell_field(name));
137 });
138 }, this->_xml_settings.data_format);
139 }, this->_xml_settings.encoder);
140
141 std::ranges::for_each(Parallel::ranks(_comm), [&] (int rank) {
142 std::array<std::size_t, dim> extents_begin;
143 std::array<std::size_t, dim> extents_end;
144 for (unsigned dir = 0; dir < dim; ++dir) {
145 extents_begin[dir] = proc_extents_begin[rank][dir];
146 extents_end[dir] = proc_extents_end[rank][dir];
147 }
148
149 auto& piece = grid.add_child("Piece");
150 piece.set_attribute("Extent", VTK::CommonDetail::extents_string(extents_begin, extents_end));
151 piece.set_attribute("Source", std::filesystem::path{
152 PVTK::piece_basefilename(filename_with_ext, rank) + ".vti"
153 }.filename());
154 });
155
156 this->_set_default_active_fields(pvtk_xml.get_child("PImageData"));
157 write_xml_with_version_header(pvtk_xml, file_stream, Indentation{{.width = 2}});
158 }
159};
160
161template<typename G, Concepts::Communicator C>
162PVTIWriter(G&&, const C&, VTK::XMLOptions = {}) -> PVTIWriter<std::remove_cvref_t<G>, C>;
163
164namespace Traits {
165
166template<typename... Args>
167struct WritesConnectivity<PVTIWriter<Args...>> : public std::false_type {};
168
169} // namespace Traits
170} // namespace GridFormat
171
172#endif // GRIDFORMAT_VTK_PVTI_WRITER_HPP_
Writer for parallel .pvti files.
Definition: pvti_writer.hpp:41
Helper to add a PDataArray child to an xml element.
Definition: parallel.hpp:45
Writer for .vti file format.
Definition: vti_writer.hpp:33
Base class for VTK-XML Writer implementations.
Definition: xml.hpp:190
Helper function for writing parallel VTK files.
Can be specialized by writers in case the file format does not contain connectivity information.
Definition: writer.hpp:36
Definition: vti_writer.hpp:39
Options for VTK-XML files for setting the desired encoding, data format and compression.
Definition: xml.hpp:99