core
Shared MPI block decomposition + asynchronous ghost-layer exchange (header-only C++20)
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// Header-only, guarded by PECLET_CORE_HAVE_MORTON.
10#ifndef PECLET_CORE_AMR_VTU_IO_HPP
11#define PECLET_CORE_AMR_VTU_IO_HPP
12
13#ifdef PECLET_CORE_HAVE_MORTON
14
15#include <array>
16#include <fstream>
17#include <ios>
18#include <stdexcept>
19#include <string>
20#include <vector>
21
25
26namespace peclet::core::amr {
27
28namespace detail {
29// Corner offsets in VTK cell-point order. 3D: VTK_HEXAHEDRON (=12); 2D: VTK_QUAD (=9).
30template <int Dim>
31inline const std::array<std::array<int, Dim>, (1 << Dim)>& vtkCorners();
32
33template <>
34inline const std::array<std::array<int, 3>, 8>& vtkCorners<3>() {
35 static const std::array<std::array<int, 3>, 8> c{
36 {{0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {0, 1, 0}, {0, 0, 1}, {1, 0, 1}, {1, 1, 1}, {0, 1, 1}}};
37 return c;
38}
39template <>
40inline const std::array<std::array<int, 2>, 4>& vtkCorners<2>() {
41 static const std::array<std::array<int, 2>, 4> c{{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
42 return c;
43}
44} // namespace detail
45
48template <int Dim, unsigned Bits>
49void writeVtu(const std::string& path, const BlockOctree<Dim, Bits>& t, const AmrGeometry<Dim>& geo,
50 const std::string& name, const std::vector<double>& cellData) {
51 static_assert(Dim == 2 || Dim == 3, "writeVtu supports 2D/3D");
52 const Index nLeaf = t.numLeaves();
53 if (static_cast<Index>(cellData.size()) != nLeaf)
54 throw std::runtime_error("writeVtu: cellData size != numLeaves");
55
56 std::ofstream f(path);
57 if (!f)
58 throw std::runtime_error("writeVtu: cannot open " + path);
59
60 constexpr int NP = 1 << Dim; // points per cell
61 const int cellType = (Dim == 3) ? 12 : 9;
62 const auto& corners = detail::vtkCorners<Dim>();
63 const std::size_t npts = static_cast<std::size_t>(nLeaf) * NP;
64
65 f << "<?xml version=\"1.0\"?>\n"
66 << "<VTKFile type=\"UnstructuredGrid\" version=\"1.0\" byte_order=\"LittleEndian\">\n"
67 << " <UnstructuredGrid>\n"
68 << " <Piece NumberOfPoints=\"" << npts << "\" NumberOfCells=\"" << nLeaf << "\">\n";
69
70 // --- points (per-cell, in VTK corner order; always 3 components) ---
71 f << " <Points>\n"
72 << " <DataArray type=\"Float64\" NumberOfComponents=\"3\" format=\"ascii\">\n";
73 f.setf(std::ios::scientific);
74 f.precision(9);
75 for (Index i = 0; i < nLeaf; ++i) {
76 auto b = t.bounds(i);
77 const auto lo = b[0];
78 const Index sz = Index(1) << t.level(i);
79 for (int c = 0; c < NP; ++c) {
80 Real xyz[3] = {0, 0, 0};
81 for (int d = 0; d < Dim; ++d)
82 xyz[d] = geo.origin[d] + static_cast<Real>(lo[d] + corners[c][d] * sz) * geo.h0;
83 f << xyz[0] << ' ' << xyz[1] << ' ' << xyz[2] << '\n';
84 }
85 }
86 f << " </DataArray>\n </Points>\n";
87
88 // --- cells ---
89 f << " <Cells>\n"
90 << " <DataArray type=\"Int64\" Name=\"connectivity\" format=\"ascii\">\n";
91 for (std::size_t p = 0; p < npts; ++p)
92 f << p << (((p + 1) % NP == 0) ? '\n' : ' ');
93 f << " </DataArray>\n"
94 << " <DataArray type=\"Int64\" Name=\"offsets\" format=\"ascii\">\n";
95 for (Index i = 0; i < nLeaf; ++i)
96 f << static_cast<std::size_t>(i + 1) * NP << '\n';
97 f << " </DataArray>\n"
98 << " <DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">\n";
99 for (Index i = 0; i < nLeaf; ++i)
100 f << cellType << '\n';
101 f << " </DataArray>\n </Cells>\n";
102
103 // --- cell data ---
104 f << " <CellData Scalars=\"" << name << "\">\n"
105 << " <DataArray type=\"Float64\" Name=\"" << name << "\" format=\"ascii\">\n";
106 for (Index i = 0; i < nLeaf; ++i)
107 f << cellData[static_cast<std::size_t>(i)] << '\n';
108 f << " </DataArray>\n </CellData>\n";
109
110 f << " </Piece>\n </UnstructuredGrid>\n</VTKFile>\n";
111}
112
114template <int Dim, unsigned Bits>
115void writeVtu(const std::string& path, const BlockOctree<Dim, Bits>& t, const AmrGeometry<Dim>& geo,
116 const std::string& name, const LeafField<double>& field) {
117 writeVtu(path, t, geo, name, field.values);
118}
119
120} // namespace peclet::core::amr
121
122#endif // PECLET_CORE_HAVE_MORTON
123#endif // PECLET_CORE_AMR_VTU_IO_HPP
const std::array< std::array< int, 2 >, 4 > & vtkCorners< 2 >()
Definition vtu_io.hpp:40
const std::array< std::array< int, Dim >,(1<< Dim)> & vtkCorners()
const std::array< std::array< int, 3 >, 8 > & vtkCorners< 3 >()
Definition vtu_io.hpp:34
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:49
Kokkos::View< T *, MemSpace > View
1D device array.
Definition view.hpp:26
double Real
Default host floating type. Device kernels may use float; conversions happen at the boundary.
Definition types.hpp:18
std::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).
Definition types.hpp:15