43 using CT = CoordinateType<Grid>;
45 static constexpr std::size_t space_dim = 3;
46 static constexpr std::size_t dim = dimension<Grid>;
47 static constexpr int root_rank = 0;
50 explicit PVTSWriter(LValueReferenceOf<const Grid> grid,
53 : ParentType(grid.get(),
".pvts",
true, xml_opts)
57 const Communicator& communicator()
const {
65 return PVTSWriter{this->grid(), _comm, std::move(xml_opts)};
68 void _write(std::ostream&)
const override {
70 "PVTSWriter does not support direct export into stream. "
71 "Use overload with filename instead!"
75 virtual void _write(
const std::string& filename_with_ext)
const override {
76 const auto& local_extents = extents(this->grid());
78 std::array<CT, dim> origin{};
79 std::array<bool, dim> is_negative_axis{};
80 Parallel::invoke_collectively(_comm, [&] () {
81 std::tie(origin, is_negative_axis) = _get_origin_and_orientations(local_extents);
82 },
"Determining the origin of the local grid");
85 const auto all_origins = Parallel::gather(_comm, origin, root_rank);
86 const auto all_extents = Parallel::gather(_comm, local_extents, root_rank);
87 const auto [exts_begin, exts_end, whole_extent, _] = helper.compute_extents_and_origin(
93 const auto my_whole_extent = Parallel::broadcast(_comm, whole_extent, root_rank);
94 const auto my_extent_offset = Parallel::scatter(_comm, Ranges::flat(exts_begin), root_rank);
98 Parallel::invoke_collectively(_comm, [&] () {
99 _write_piece(filename_with_ext, Ranges::to_array<dim>(my_extent_offset), {my_whole_extent});
100 },
"Writing the pieces of '" + filename_with_ext +
"'");
101 Parallel::invoke_collectively(_comm, [&] () {
102 if (Parallel::rank(_comm) == 0)
103 _write_pvts_file(filename_with_ext, my_whole_extent, exts_begin, exts_end);
104 },
"Writing '" + filename_with_ext +
"'");
107 auto _get_origin_and_orientations(
const std::ranges::range
auto& extents)
const {
108 auto is_negative_axis = Ranges::filled_array<dim>(
false);
109 std::ranges::for_each(extents, [&, dir=0] (
const auto& e)
mutable {
111 is_negative_axis[dir] = _is_negative_axis(dir);
115 std::array<CT, dim> origin;
116 static constexpr auto origin_loc = _origin_location();
117 for (
const auto& p : points(this->grid())) {
118 const auto& loc = location(this->grid(), p);
119 const auto& pos = coordinates(this->grid(), p);
120 if (std::ranges::equal(loc, origin_loc)) {
121 std::ranges::copy(pos, origin.begin());
122 return std::make_tuple(std::move(origin), std::move(is_negative_axis));
126 throw InvalidState(
"Could not determine origin");
129 static constexpr auto _origin_location() {
130 std::array<std::size_t, dim> origin;
131 std::ranges::fill(origin, 0);
135 bool _is_negative_axis(
unsigned axis)
const {
136 for (
const auto& p0 : points(this->grid())) {
137 const auto i0 = Ranges::at(axis, location(this->grid(), p0));
138 const auto x0 = Ranges::at(axis, coordinates(this->grid(), p0));
139 for (
const auto& p1 : points(this->grid())) {
140 const auto i1 = Ranges::at(axis, location(this->grid(), p1));
141 const auto x1 = Ranges::at(axis, coordinates(this->grid(), p1));
146 throw InvalidState(
"Could not determine axis orientation");
149 void _write_piece(
const std::string& par_filename,
150 const std::array<std::size_t, dim>& offset,
152 auto writer =
VTSWriter{this->grid(), this->_xml_opts}
153 .as_piece_for(std::move(domain))
154 .with_offset(offset);
155 this->copy_fields(writer);
159 void _write_pvts_file(
const std::string& filename_with_ext,
160 const std::array<std::size_t, dim>& extents,
161 const std::vector<std::array<std::size_t, dim>>& proc_extents_begin,
162 const std::vector<std::array<std::size_t, dim>>& proc_extents_end)
const {
163 XMLElement pvtk_xml(
"VTKFile");
164 pvtk_xml.set_attribute(
"type",
"PStructuredGrid");
166 XMLElement& grid = pvtk_xml.add_child(
"PStructuredGrid");
167 grid.set_attribute(
"WholeExtent", VTK::CommonDetail::extents_string(extents));
169 XMLElement& ppoint_data = grid.add_child(
"PPointData");
170 XMLElement& pcell_data = grid.add_child(
"PCellData");
171 XMLElement& pcoords = grid.add_child(
"PPoints");
172 std::visit([&] (
const auto& encoder) {
173 std::visit([&] (
const auto& data_format) {
176 std::ranges::for_each(this->_point_field_names(), [&] (
const std::string& name) {
177 pdata_helper.add(name, this->_get_point_field(name));
179 std::ranges::for_each(this->_cell_field_names(), [&] (
const std::string& name) {
180 cdata_helper.add(name, this->_get_cell_field(name));
183 std::visit([&] <
typename T> (
const Precision<T>& prec) {
184 XMLElement& pdata_array = pcoords.add_child(
"PDataArray");
185 pdata_array.set_attribute(
"NumberOfComponents", std::to_string(space_dim));
186 pdata_array.set_attribute(
"Name",
"Coordinates");
187 pdata_array.set_attribute(
"format", VTK::data_format_name(encoder, data_format));
188 pdata_array.set_attribute(
"type", VTK::attribute_name(prec));
189 }, this->_xml_settings.coordinate_precision);
190 }, this->_xml_settings.data_format);
191 }, this->_xml_settings.encoder);
193 std::ranges::for_each(Parallel::ranks(_comm), [&] (
int rank) {
194 std::array<std::size_t, dim> extents_begin;
195 std::array<std::size_t, dim> extents_end;
196 for (
unsigned dir = 0; dir < dim; ++dir) {
197 extents_begin[dir] = proc_extents_begin[rank][dir];
198 extents_end[dir] = proc_extents_end[rank][dir];
200 auto& piece = grid.add_child(
"Piece");
201 piece.set_attribute(
"Extent", VTK::CommonDetail::extents_string(extents_begin, extents_end));
202 piece.set_attribute(
"Source", std::filesystem::path{
207 this->_set_default_active_fields(pvtk_xml.get_child(
"PStructuredGrid"));
208 write_to(filename_with_ext, [&] (std::ostream& s) {
209 write_xml_with_version_header(pvtk_xml, s, Indentation{{.width = 2}});