flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
test_stencils.cpp
Go to the documentation of this file.
1// Correctness of the Kokkos MAC stencils (peclet::flow::poisSweep RB-GS + divergence) vs a host
2// replication, plus a smoother sanity check (Poisson residual decreases over sweeps). Extended
3// (inner+ghost=1) block, x-fastest. Within a Red-Black colour the updates are independent, so
4// device (parallel) and host (sequential, colour 0 then 1) match exactly. Runs on whatever backend
5// Kokkos was built for.
6#include <cmath>
7#include <cstdio>
8#include <Kokkos_Core.hpp>
9#include <random>
10#include <vector>
11
12#include "mac_stencils.hpp"
13
14using namespace peclet::flow;
15
16static long l3(int x, int y, int z, I3 e) {
17 return (long)x + (long)y * e.x + (long)z * (long)e.x * e.y;
18}
19
20int main(int argc, char** argv) {
21 Kokkos::initialize(argc, argv);
22 int status = 0;
23 {
24 const int g = 1;
25 I3 inner{18, 14, 10};
26 I3 e{inner.x + 2 * g, inner.y + 2 * g, inner.z + 2 * g};
27 I3 og{0, 0, 0}; // single block: global origin 0
28 const std::size_t n = (std::size_t)e.x * e.y * e.z;
29
30 std::mt19937 rng(8);
31 std::uniform_real_distribution<double> uf(-1.0, 1.0);
32 std::vector<double> hphi(n), hd(n), hu(n), hv(n), hw(n);
33 for (std::size_t i = 0; i < n; ++i) {
34 hphi[i] = uf(rng);
35 hd[i] = uf(rng);
36 hu[i] = uf(rng);
37 hv[i] = uf(rng);
38 hw[i] = uf(rng);
39 }
40
41 auto up = [&](const char* nm, std::vector<double>& h) {
42 SField v(nm, n);
43 auto m = Kokkos::create_mirror_view(v);
44 for (std::size_t i = 0; i < n; ++i)
45 m(i) = h[i];
46 Kokkos::deep_copy(v, m);
47 return v;
48 };
49 SField phi = up("phi", hphi), d = up("d", hd), u = up("u", hu), v = up("v", hv),
50 w = up("w", hw);
51 SField dout("dout", n);
52
53 // device: one RB-GS sweep + divergence
54 poisSweep(phi, d, e, og, g);
55 divergence(u, v, w, dout, e, g);
56 auto hp = Kokkos::create_mirror_view(phi);
57 Kokkos::deep_copy(hp, phi);
58 auto hdo = Kokkos::create_mirror_view(dout);
59 Kokkos::deep_copy(hdo, dout);
60
61 // host reference: identical RB-GS sweep (colour 0 then 1) + divergence
62 std::vector<double> rphi = hphi;
63 for (int color = 0; color < 2; ++color)
64 for (int z = g; z < e.z - g; ++z)
65 for (int y = g; y < e.y - g; ++y)
66 for (int x = g; x < e.x - g; ++x) {
67 if ((((x + og.x) + (y + og.y) + (z + og.z)) & 1) != color)
68 continue;
69 long i = l3(x, y, z, e), sx = 1, sy = e.x, sz = (long)e.x * e.y;
70 double s = rphi[i + sx] + rphi[i - sx] + rphi[i + sy] + rphi[i - sy] + rphi[i + sz] +
71 rphi[i - sz];
72 rphi[i] = (s - hd[i]) / 6.0;
73 }
74 auto close = [](double a, double b) {
75 return std::fabs(a - b) <= 1e-10 * (1.0 + std::fabs(b));
76 };
77 int bad = 0;
78 for (std::size_t i = 0; i < n; ++i)
79 if (!close(hp(i), rphi[i]))
80 ++bad;
81 for (int z = g; z < e.z - g; ++z)
82 for (int y = g; y < e.y - g; ++y)
83 for (int x = g; x < e.x - g; ++x) {
84 long i = l3(x, y, z, e), sx = 1, sy = e.x, sz = (long)e.x * e.y;
85 double rd = (hu[i + sx] - hu[i]) + (hv[i + sy] - hv[i]) + (hw[i + sz] - hw[i]);
86 if (!close(hdo(i), rd))
87 ++bad;
88 }
89 if (bad) {
90 std::fprintf(stderr, "FAIL: %d cells differ (sweep/divergence)\n", bad);
91 status = 1;
92 }
93
94 // smoother sanity: many sweeps on Lap(phi)=d (periodic-ish, ghosts left as data) -> residual
95 // drops.
96 SField phi2 = up("phi2", hphi);
97 auto resid = [&]() {
98 auto m = Kokkos::create_mirror_view(phi2);
99 Kokkos::deep_copy(m, phi2);
100 double r = 0.0;
101 for (int z = g; z < e.z - g; ++z)
102 for (int y = g; y < e.y - g; ++y)
103 for (int x = g; x < e.x - g; ++x) {
104 long i = l3(x, y, z, e), sx = 1, sy = e.x, sz = (long)e.x * e.y;
105 double s = m(i + sx) + m(i - sx) + m(i + sy) + m(i - sy) + m(i + sz) + m(i - sz);
106 double res = (s - 6.0 * m(i)) - hd[i]; // Lap(phi)-d
107 r += res * res;
108 }
109 return std::sqrt(r);
110 };
111 double r0 = resid();
112 for (int it = 0; it < 100; ++it)
113 poisSweep(phi2, d, e, og, g);
114 double r1 = resid();
115 if (!(r1 < 0.2 * r0)) {
116 std::fprintf(stderr, "FAIL: smoother did not reduce residual (%.3e -> %.3e)\n", r0, r1);
117 status = 1;
118 }
119
120 if (!status)
121 std::printf(
122 "[mac_stencils] PASS: RB-GS sweep + divergence match host; residual %.2e -> %.2e (exec: "
123 "%s)\n",
124 r0, r1, SExec::name());
125 }
126 Kokkos::finalize();
127 return status;
128}
flow — portable (Kokkos) MAC stencil operators: Red-Black Gauss-Seidel smoothers + divergence.
void divergence(SConst u, SConst v, SConst w, SField d, I3 e, int g)
Kokkos::View< double *, SMem > SField
void poisSweep(SField phi, SConst d, I3 e, I3 og, int g)
static long l3(int x, int y, int z, I3 e)
int main(int argc, char **argv)