peclet-amr 0.2.0
Block-local-Morton AMR octree + collocated cut-cell Navier–Stokes solver (header-only C++20, Kokkos + MPI)
Loading...
Searching...
No Matches
vtu_io.hpp
Go to the documentation of this file.
1// core — VTK UnstructuredGrid (.vtu) output for an adaptive octree.
2//
3// A graded octree can't be a single VTK ImageData (vti_io.hpp), so each leaf is
4// emitted as one cell — a hexahedron (3D) or quad (2D) — carrying a per-leaf
5// CellData scalar. Points are written per-cell (not shared), which keeps the
6// writer trivial and is what ParaView expects for a cell-wise AMR dump. ASCII,
7// human-readable, openable in ParaView.
8//
9#ifndef PECLET_AMR_VTU_IO_HPP
10#define PECLET_AMR_VTU_IO_HPP
11
12#include <array>
13#include <fstream>
14#include <ios>
15#include <stdexcept>
16#include <string>
17#include <vector>
18
20#include "peclet/amr/common.hpp"
22#include "peclet/core/common/types.hpp"
23
24namespace peclet::amr {
25
26namespace detail {
27// Corner offsets in VTK cell-point order. 3D: VTK_HEXAHEDRON (=12); 2D: VTK_QUAD (=9).
28template <int Dim>
29inline const std::array<std::array<int, Dim>, (1 << Dim)>& vtkCorners();
30
31template <>
32inline const std::array<std::array<int, 3>, 8>& vtkCorners<3>() {
33 static const std::array<std::array<int, 3>, 8> c{
34 {{0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {0, 1, 0}, {0, 0, 1}, {1, 0, 1}, {1, 1, 1}, {0, 1, 1}}};
35 return c;
36}
37template <>
38inline const std::array<std::array<int, 2>, 4>& vtkCorners<2>() {
39 static const std::array<std::array<int, 2>, 4> c{{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
40 return c;
41}
42} // namespace detail
43
46template <int Dim, unsigned Bits>
47void writeVtu(const std::string& path, const BlockOctree<Dim, Bits>& t, const AmrGeometry<Dim>& geo,
48 const std::string& name, const std::vector<double>& cellData) {
49 static_assert(Dim == 2 || Dim == 3, "writeVtu supports 2D/3D");
50 const Index nLeaf = t.numLeaves();
51 if (static_cast<Index>(cellData.size()) != nLeaf)
52 throw std::runtime_error("writeVtu: cellData size != numLeaves");
53
54 std::ofstream f(path);
55 if (!f)
56 throw std::runtime_error("writeVtu: cannot open " + path);
57
58 constexpr int NP = 1 << Dim; // points per cell
59 const int cellType = (Dim == 3) ? 12 : 9;
60 const auto& corners = detail::vtkCorners<Dim>();
61 const std::size_t npts = static_cast<std::size_t>(nLeaf) * NP;
62
63 f << "<?xml version=\"1.0\"?>\n"
64 << "<VTKFile type=\"UnstructuredGrid\" version=\"1.0\" byte_order=\"LittleEndian\">\n"
65 << " <UnstructuredGrid>\n"
66 << " <Piece NumberOfPoints=\"" << npts << "\" NumberOfCells=\"" << nLeaf << "\">\n";
67
68 // --- points (per-cell, in VTK corner order; always 3 components) ---
69 f << " <Points>\n"
70 << " <DataArray type=\"Float64\" NumberOfComponents=\"3\" format=\"ascii\">\n";
71 f.setf(std::ios::scientific);
72 f.precision(9);
73 for (Index i = 0; i < nLeaf; ++i) {
74 auto b = t.bounds(i);
75 const auto lo = b[0];
76 const Index sz = Index(1) << t.level(i);
77 for (int c = 0; c < NP; ++c) {
78 Real xyz[3] = {0, 0, 0};
79 for (int d = 0; d < Dim; ++d)
80 xyz[d] = geo.origin[d] + static_cast<Real>(lo[d] + corners[c][d] * sz) * geo.h0[d];
81 f << xyz[0] << ' ' << xyz[1] << ' ' << xyz[2] << '\n';
82 }
83 }
84 f << " </DataArray>\n </Points>\n";
85
86 // --- cells ---
87 f << " <Cells>\n"
88 << " <DataArray type=\"Int64\" Name=\"connectivity\" format=\"ascii\">\n";
89 for (std::size_t p = 0; p < npts; ++p)
90 f << p << (((p + 1) % NP == 0) ? '\n' : ' ');
91 f << " </DataArray>\n"
92 << " <DataArray type=\"Int64\" Name=\"offsets\" format=\"ascii\">\n";
93 for (Index i = 0; i < nLeaf; ++i)
94 f << static_cast<std::size_t>(i + 1) * NP << '\n';
95 f << " </DataArray>\n"
96 << " <DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">\n";
97 for (Index i = 0; i < nLeaf; ++i)
98 f << cellType << '\n';
99 f << " </DataArray>\n </Cells>\n";
100
101 // --- cell data ---
102 f << " <CellData Scalars=\"" << name << "\">\n"
103 << " <DataArray type=\"Float64\" Name=\"" << name << "\" format=\"ascii\">\n";
104 for (Index i = 0; i < nLeaf; ++i)
105 f << cellData[static_cast<std::size_t>(i)] << '\n';
106 f << " </DataArray>\n </CellData>\n";
107
108 f << " </Piece>\n </UnstructuredGrid>\n</VTKFile>\n";
109}
110
112template <int Dim, unsigned Bits>
113void writeVtu(const std::string& path, const BlockOctree<Dim, Bits>& t, const AmrGeometry<Dim>& geo,
114 const std::string& name, const LeafField<double>& field) {
115 writeVtu(path, t, geo, name, field.values);
116}
117
118} // namespace peclet::amr
119
120#endif // PECLET_AMR_VTU_IO_HPP
Per-block adaptive octree over block-local Morton codes.
const std::array< std::array< int, 3 >, 8 > & vtkCorners< 3 >()
Definition vtu_io.hpp:32
const std::array< std::array< int, Dim >,(1<< Dim)> & vtkCorners()
const std::array< std::array< int, 2 >, 4 > & vtkCorners< 2 >()
Definition vtu_io.hpp:38
void writeVtu(const std::string &path, const BlockOctree< Dim, Bits > &t, const AmrGeometry< Dim > &geo, const std::string &name, const std::vector< double > &cellData)
Write a BlockOctree (+ world geometry + a per-leaf scalar) as a VTK UnstructuredGrid (....
Definition vtu_io.hpp:47
std::vector< std::array< double, Dim > > transferFieldGradients(const BlockOctree< Dim, Bits > &oldT, const std::vector< double > &oldF)
Per-old-leaf minmod prolongation gradients (per fine-coordinate unit) — transferField's stencil,...
Definition adapt.hpp:51
World-space placement of a block-local octree: fine coordinate (0,..,0) sits at origin,...
A value per leaf, in the octree's Z-order leaf slot order.
std::vector< T > values