flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
test_cutcell.cpp
Go to the documentation of this file.
1// Correctness of the Kokkos cut-cell face openness (peclet::flow::buildOpenness) vs a host
2// replication on a sphere SDF, plus properties: an all-fluid SDF gives openness 1, an all-solid SDF
3// gives 0. SDF sign convention: negative inside solid, positive in fluid. Runs on whatever backend
4// Kokkos was built for.
5#include <cmath>
6#include <cstdio>
7#include <Kokkos_Core.hpp>
8#include <vector>
9
10#include "mac_cutcell.hpp"
11
12using namespace peclet::flow;
13
14int main(int argc, char** argv) {
15 Kokkos::initialize(argc, argv);
16 int status = 0;
17 {
18 C3 ext{16, 16, 16};
19 const double dx = 1.0, dy = 1.0, dz = 1.0;
20 const std::size_t n = (std::size_t)ext.x * ext.y * ext.z;
21 auto IDX = [&](int x, int y, int z) {
22 return (std::size_t)x + (std::size_t)y * ext.x + (std::size_t)z * (std::size_t)ext.x * ext.y;
23 };
24
25 // solid sphere radius 5 at (8,8,8): sdf = dist - R (>0 fluid outside, <0 solid inside)
26 std::vector<double> hsdf(n);
27 const double cx = 8, cy = 8, cz = 8, R = 5;
28 for (int z = 0; z < ext.z; ++z)
29 for (int y = 0; y < ext.y; ++y)
30 for (int x = 0; x < ext.x; ++x)
31 hsdf[IDX(x, y, z)] =
32 std::sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy) + (z - cz) * (z - cz)) - R;
33
34 auto upC = [&](const char* nm, std::vector<double>& h) {
35 CCField v(nm, n);
36 auto m = Kokkos::create_mirror_view(v);
37 for (std::size_t i = 0; i < n; ++i)
38 m(i) = h[i];
39 Kokkos::deep_copy(v, m);
40 return v;
41 };
42 auto getC = [&](CCField v) {
43 std::vector<double> o(n);
44 auto m = Kokkos::create_mirror_view(v);
45 Kokkos::deep_copy(m, v);
46 for (std::size_t i = 0; i < n; ++i)
47 o[i] = m(i);
48 return o;
49 };
50
51 CCField sdf = upC("sdf", hsdf), ox("ox", n), oy("oy", n), oz("oz", n);
52 buildOpenness(ox, oy, oz, sdf, ext, dx, dy, dz);
53 auto gox = getC(ox), goy = getC(oy), goz = getC(oz);
54
55 // host reference (same functions)
56 auto close = [](double a, double b) {
57 return std::fabs(a - b) <= 1e-10 * (1.0 + std::fabs(b));
58 };
59 int bad = 0;
60 // Host reference replicates the same math on the host SDF vector.
61 auto sampleH = [&](double X, double Y, double Z) {
62 double fx = std::floor(X), fy = std::floor(Y), fz = std::floor(Z);
63 double wx = X - fx, wy = Y - fy, wz = Z - fz;
64 int x0 = (int)fx, y0 = (int)fy, z0 = (int)fz;
65 auto cl = [&](int v, int nn) { return v < 0 ? 0 : (v >= nn ? nn - 1 : v); };
66 int x1 = cl(x0 + 1, ext.x), y1 = cl(y0 + 1, ext.y), z1 = cl(z0 + 1, ext.z);
67 x0 = cl(x0, ext.x);
68 y0 = cl(y0, ext.y);
69 z0 = cl(z0, ext.z);
70 auto F = [&](int xx, int yy, int zz) { return hsdf[IDX(xx, yy, zz)]; };
71 double c00 = F(x0, y0, z0) * (1 - wx) + F(x1, y0, z0) * wx,
72 c10 = F(x0, y1, z0) * (1 - wx) + F(x1, y1, z0) * wx;
73 double c01 = F(x0, y0, z1) * (1 - wx) + F(x1, y0, z1) * wx,
74 c11 = F(x0, y1, z1) * (1 - wx) + F(x1, y1, z1) * wx;
75 double c0 = c00 * (1 - wy) + c10 * wy, c1 = c01 * (1 - wy) + c11 * wy;
76 return c0 * (1 - wz) + c1 * wz;
77 };
78 auto faceH = [&](double X, double Y, double Z, int type) {
79 double sd = sampleH(X, Y, Z);
80 if (sd <= 0)
81 return 0.0;
82 double e = 1.0;
83 return ccFractionCore(sd, sampleH(X + e, Y, Z), sampleH(X - e, Y, Z), sampleH(X, Y + e, Z),
84 sampleH(X, Y - e, Z), sampleH(X, Y, Z + e), sampleH(X, Y, Z - e), type,
85 dx, dy, dz);
86 };
87 for (int z = 0; z < ext.z; ++z)
88 for (int y = 0; y < ext.y; ++y)
89 for (int x = 0; x < ext.x; ++x) {
90 std::size_t i = IDX(x, y, z);
91 if (!close(gox[i], faceH(x - 0.5, y, z, 1)))
92 ++bad;
93 if (!close(goy[i], faceH(x, y - 0.5, z, 2)))
94 ++bad;
95 if (!close(goz[i], faceH(x, y, z - 0.5, 3)))
96 ++bad;
97 }
98 if (bad) {
99 std::fprintf(stderr, "FAIL: %d openness faces differ\n", bad);
100 status = 1;
101 }
102
103 // count cut faces (0<open<1) — the sphere surface must produce some
104 int cut = 0, open1 = 0, closed0 = 0;
105 for (std::size_t i = 0; i < n; ++i) {
106 double v = gox[i];
107 if (v > 1e-9 && v < 1 - 1e-9)
108 ++cut;
109 else if (v > 1 - 1e-9)
110 ++open1;
111 else
112 ++closed0;
113 }
114
115 // properties
116 std::vector<double> allf(n, 100.0), alls(n, -100.0);
117 CCField sf = upC("sf", allf), so = upC("so", alls), a("a", n), b("b", n), c("c", n);
118 buildOpenness(a, b, c, sf, ext, dx, dy, dz);
119 auto ga = getC(a);
120 for (std::size_t i = 0; i < n; ++i)
121 if (!close(ga[i], 1.0))
122 ++bad;
123 buildOpenness(a, b, c, so, ext, dx, dy, dz);
124 auto ga2 = getC(a);
125 for (std::size_t i = 0; i < n; ++i)
126 if (!close(ga2[i], 0.0))
127 ++bad;
128 if (bad && !status) {
129 std::fprintf(stderr, "FAIL: all-fluid/all-solid property\n");
130 status = 1;
131 }
132
133 if (!status)
134 std::printf(
135 "[mac_cutcell] PASS: openness matches host (%d cut / %d open / %d closed x-faces) + "
136 "properties (exec: %s)\n",
137 cut, open1, closed0, CCExec::name());
138 }
139 Kokkos::finalize();
140 return status;
141}
flow — portable (Kokkos) cut-cell pressure-operator face openness from an SDF.
void buildOpenness(CCField ox, CCField oy, CCField oz, CCConst sdf, C3 ext, double dx, double dy, double dz)
double ccFractionCore(double sd, double sxp, double sxm, double syp, double sym, double szp, double szm, int type, double dx, double dy, double dz)
Kokkos::View< double *, CCMem > CCField
int main(int argc, char **argv)
static constexpr double F