core
Shared MPI block decomposition + asynchronous ghost-layer exchange (header-only C++20)
Loading...
Searching...
No Matches
vti_io.hpp
Go to the documentation of this file.
1
9#ifndef PECLET_CORE_GEOM_VTI_IO_HPP
10#define PECLET_CORE_GEOM_VTI_IO_HPP
11
12#include <fstream>
13#include <ios>
14#include <sstream>
15#include <stdexcept>
16#include <string>
17
20
21namespace peclet::core::geom {
22
24inline void writeVti(const std::string& path, const GridSdf& g, const std::string& name = "sdf") {
25 std::ofstream f(path);
26 if (!f)
27 throw std::runtime_error("writeVti: cannot open " + path);
28 const Index nx = g.dims[0], ny = g.dims[1], nz = g.dims[2];
29 f << "<?xml version=\"1.0\"?>\n"
30 << "<VTKFile type=\"ImageData\" version=\"1.0\" byte_order=\"LittleEndian\">\n"
31 << " <ImageData WholeExtent=\"0 " << nx - 1 << " 0 " << ny - 1 << " 0 " << nz - 1 << "\""
32 << " Origin=\"" << g.origin[0] << " " << g.origin[1] << " " << g.origin[2] << "\""
33 << " Spacing=\"" << g.spacing[0] << " " << g.spacing[1] << " " << g.spacing[2] << "\">\n"
34 << " <Piece Extent=\"0 " << nx - 1 << " 0 " << ny - 1 << " 0 " << nz - 1 << "\">\n"
35 << " <PointData Scalars=\"" << name << "\">\n"
36 << " <DataArray type=\"Float32\" Name=\"" << name << "\" format=\"ascii\">\n";
37 f.setf(std::ios::scientific);
38 f.precision(9); // 9 significant digits round-trips float32 exactly
39 for (std::size_t i = 0; i < g.values.size(); ++i) {
40 f << g.values[i] << (((i + 1) % static_cast<std::size_t>(nx) == 0) ? '\n' : ' ');
41 }
42 f << "\n </DataArray>\n </PointData>\n </Piece>\n </ImageData>\n</VTKFile>\n";
43}
44
45namespace detail {
46inline std::string vtiAttr(const std::string& s, const std::string& key) {
47 std::string needle = key + "=\"";
48 auto p = s.find(needle);
49 if (p == std::string::npos)
50 throw std::runtime_error("readVti: missing attribute " + key);
51 p += needle.size();
52 auto e = s.find('"', p);
53 return s.substr(p, e - p);
54}
55} // namespace detail
56
58inline GridSdf readVti(const std::string& path) {
59 std::ifstream f(path);
60 if (!f)
61 throw std::runtime_error("readVti: cannot open " + path);
62 std::stringstream buf;
63 buf << f.rdbuf();
64 const std::string s = buf.str();
65
66 GridSdf g;
67 Index x0, x1, y0, y1, z0, z1;
68 std::istringstream(detail::vtiAttr(s, "WholeExtent")) >> x0 >> x1 >> y0 >> y1 >> z0 >> z1;
69 g.dims = {x1 - x0 + 1, y1 - y0 + 1, z1 - z0 + 1};
70 std::istringstream(detail::vtiAttr(s, "Origin")) >> g.origin[0] >> g.origin[1] >> g.origin[2];
71 std::istringstream(detail::vtiAttr(s, "Spacing")) >> g.spacing[0] >> g.spacing[1] >> g.spacing[2];
72
73 auto da = s.find("<DataArray");
74 if (da == std::string::npos)
75 throw std::runtime_error("readVti: no DataArray");
76 auto open = s.find('>', da);
77 auto close = s.find("</DataArray>", open);
78 std::istringstream data(s.substr(open + 1, close - open - 1));
79
80 std::size_t n = static_cast<std::size_t>(g.dims[0]) * g.dims[1] * g.dims[2];
81 g.values.resize(n);
82 for (std::size_t i = 0; i < n; ++i) {
83 float v = 0.0f;
84 data >> v;
85 g.values[i] = v;
86 }
87 return g;
88}
89
91struct VtiVector {
94 Vec<3> spacing{1, 1, 1};
95 std::vector<float> values; // size = 3 * dims[0]*dims[1]*dims[2], interleaved (vx,vy,vz)
96};
97
99inline void writeVtiVector(const std::string& path, const VtiVector& g,
100 const std::string& name = "vector") {
101 std::ofstream f(path);
102 if (!f)
103 throw std::runtime_error("writeVtiVector: cannot open " + path);
104 const Index nx = g.dims[0], ny = g.dims[1], nz = g.dims[2];
105 f << "<?xml version=\"1.0\"?>\n"
106 << "<VTKFile type=\"ImageData\" version=\"1.0\" byte_order=\"LittleEndian\">\n"
107 << " <ImageData WholeExtent=\"0 " << nx - 1 << " 0 " << ny - 1 << " 0 " << nz - 1 << "\""
108 << " Origin=\"" << g.origin[0] << " " << g.origin[1] << " " << g.origin[2] << "\""
109 << " Spacing=\"" << g.spacing[0] << " " << g.spacing[1] << " " << g.spacing[2] << "\">\n"
110 << " <Piece Extent=\"0 " << nx - 1 << " 0 " << ny - 1 << " 0 " << nz - 1 << "\">\n"
111 << " <PointData Vectors=\"" << name << "\">\n"
112 << " <DataArray type=\"Float32\" Name=\"" << name
113 << "\" NumberOfComponents=\"3\" format=\"ascii\">\n";
114 f.setf(std::ios::scientific);
115 f.precision(9);
116 std::size_t npts = static_cast<std::size_t>(nx) * ny * nz;
117 for (std::size_t p = 0; p < npts; ++p) {
118 f << g.values[3 * p] << ' ' << g.values[3 * p + 1] << ' ' << g.values[3 * p + 2] << '\n';
119 }
120 f << " </DataArray>\n </PointData>\n </Piece>\n </ImageData>\n</VTKFile>\n";
121}
122
124inline VtiVector readVtiVector(const std::string& path) {
125 std::ifstream f(path);
126 if (!f)
127 throw std::runtime_error("readVtiVector: cannot open " + path);
128 std::stringstream buf;
129 buf << f.rdbuf();
130 const std::string s = buf.str();
131
132 VtiVector g;
133 Index x0, x1, y0, y1, z0, z1;
134 std::istringstream(detail::vtiAttr(s, "WholeExtent")) >> x0 >> x1 >> y0 >> y1 >> z0 >> z1;
135 g.dims = {x1 - x0 + 1, y1 - y0 + 1, z1 - z0 + 1};
136 std::istringstream(detail::vtiAttr(s, "Origin")) >> g.origin[0] >> g.origin[1] >> g.origin[2];
137 std::istringstream(detail::vtiAttr(s, "Spacing")) >> g.spacing[0] >> g.spacing[1] >> g.spacing[2];
138
139 auto da = s.find("<DataArray");
140 auto open = s.find('>', da);
141 auto close = s.find("</DataArray>", open);
142 std::istringstream data(s.substr(open + 1, close - open - 1));
143 std::size_t n3 = 3u * static_cast<std::size_t>(g.dims[0]) * g.dims[1] * g.dims[2];
144 g.values.resize(n3);
145 for (std::size_t i = 0; i < n3; ++i) {
146 float v = 0.0f;
147 data >> v;
148 g.values[i] = v;
149 }
150 return g;
151}
152
153} // namespace peclet::core::geom
154
155#endif // PECLET_CORE_GEOM_VTI_IO_HPP
Sampled (grid) signed-distance field with trilinear interpolation.
std::string vtiAttr(const std::string &s, const std::string &key)
Definition vti_io.hpp:46
VtiVector readVtiVector(const std::string &path)
Read a vector-field VTI written by writeVtiVector.
Definition vti_io.hpp:124
GridSdf readVti(const std::string &path)
Read a VTK ImageData (.vti) written by writeVti (ASCII PointData scalar) into a GridSdf.
Definition vti_io.hpp:58
void writeVti(const std::string &path, const GridSdf &g, const std::string &name="sdf")
Write a GridSdf as a VTK ImageData (.vti), PointData Float32 scalar, ASCII.
Definition vti_io.hpp:24
void writeVtiVector(const std::string &path, const VtiVector &g, const std::string &name="vector")
Write a 3-component vector field as a VTK ImageData PointData vector (ASCII), ParaView-openable.
Definition vti_io.hpp:99
Kokkos::View< T *, MemSpace > View
1D device array.
Definition view.hpp:26
std::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).
Definition types.hpp:15
A signed-distance field sampled on a regular axis-aligned grid (negative inside solid).
Definition grid_sdf.hpp:23
Vec< 3 > origin
World position of sample (0,0,0).
Definition grid_sdf.hpp:26
std::vector< float > values
Sample values, x-fastest: idx = i + j*nx + k*nx*ny.
Definition grid_sdf.hpp:24
Vec< 3 > spacing
World-space distance between samples per axis.
Definition grid_sdf.hpp:27
IVec< 3 > dims
Sample count per axis (nx, ny, nz).
Definition grid_sdf.hpp:25
A sampled vector field on a regular grid (3 interleaved components per point, x-fastest).
Definition vti_io.hpp:91
std::vector< float > values
Definition vti_io.hpp:95