flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
test_transfer.cpp
Go to the documentation of this file.
1// Correctness of the Kokkos multigrid transfer (peclet::flow::restrict_ / prolong) + projection
2// correction (peclet::flow::correct) vs host replication. Plus property checks: restriction of a
3// constant is that constant; prolongation of a constant adds that constant. Runs on whatever
4// backend Kokkos has.
5#include <cmath>
6#include <cstdio>
7#include <Kokkos_Core.hpp>
8#include <random>
9#include <vector>
10
11#include "mac_transfer.hpp"
12
13using namespace peclet::flow;
14
15int main(int argc, char** argv) {
16 Kokkos::initialize(argc, argv);
17 int status = 0;
18 {
19 const int g = 1;
20 T3 ratio{2, 2, 2};
21 T3 cinner{8, 6, 5};
22 T3 cext{cinner.x + 2 * g, cinner.y + 2 * g, cinner.z + 2 * g};
23 T3 finner{ratio.x * cinner.x, ratio.y * cinner.y, ratio.z * cinner.z};
24 T3 fext{finner.x + 2 * g, finner.y + 2 * g, finner.z + 2 * g};
25 auto cn = (std::size_t)cext.x * cext.y * cext.z;
26 auto fn = (std::size_t)fext.x * fext.y * fext.z;
27
28 std::mt19937 rng(21);
29 std::uniform_real_distribution<double> uf(-1.0, 1.0);
30 std::vector<double> hfine(fn), hcoarse(cn), hu(fn), hv(fn), hw(fn), hphi(fn);
31 for (auto* vec : {&hfine, &hu, &hv, &hw, &hphi})
32 for (auto& x : *vec)
33 x = uf(rng);
34 for (auto& x : hcoarse)
35 x = uf(rng);
36
37 auto upN = [&](const char* nm, std::vector<double>& h, std::size_t n) {
38 TField v(nm, n);
39 auto m = Kokkos::create_mirror_view(v);
40 for (std::size_t i = 0; i < n; ++i)
41 m(i) = h[i];
42 Kokkos::deep_copy(v, m);
43 return v;
44 };
45 auto get = [&](TField v, std::size_t n) {
46 std::vector<double> o(n);
47 auto m = Kokkos::create_mirror_view(v);
48 Kokkos::deep_copy(m, v);
49 for (std::size_t i = 0; i < n; ++i)
50 o[i] = m(i);
51 return o;
52 };
53 auto close = [](double a, double b) {
54 return std::fabs(a - b) <= 1e-10 * (1.0 + std::fabs(b));
55 };
56 long lc = [&](int x, int y, int z) {
57 return (long)x + (long)y * cext.x + (long)z * (long)cext.x * cext.y;
58 }(0, 0, 0);
59 (void)lc;
60 auto CI = [&](int x, int y, int z) {
61 return (std::size_t)x + (std::size_t)y * cext.x +
62 (std::size_t)z * (std::size_t)cext.x * cext.y;
63 };
64 auto FI = [&](int x, int y, int z) {
65 return (std::size_t)x + (std::size_t)y * fext.x +
66 (std::size_t)z * (std::size_t)fext.x * fext.y;
67 };
68 int bad = 0;
69
70 // --- restriction ---
71 TField fine = upN("fine", hfine, fn), coarse("coarse", cn);
72 restrict_(coarse, fine, cext, fext, g, cinner, ratio);
73 auto gco = get(coarse, cn);
74 for (int icz = 0; icz < cinner.z; ++icz)
75 for (int icy = 0; icy < cinner.y; ++icy)
76 for (int icx = 0; icx < cinner.x; ++icx) {
77 double s = 0;
78 for (int dz = 0; dz < ratio.z; ++dz)
79 for (int dy = 0; dy < ratio.y; ++dy)
80 for (int dx = 0; dx < ratio.x; ++dx)
81 s += hfine[FI(ratio.x * icx + dx + g, ratio.y * icy + dy + g,
82 ratio.z * icz + dz + g)];
83 double r = s / (ratio.x * ratio.y * ratio.z);
84 if (!close(gco[CI(icx + g, icy + g, icz + g)], r))
85 ++bad;
86 }
87
88 // --- prolongation (coarse filled incl ghost) ---
89 TField coarse2 = upN("coarse2", hcoarse, cn), fine2 = upN("fine2", hfine, fn);
90 prolong(fine2, coarse2, fext, cext, g, finner, ratio);
91 auto gf = get(fine2, fn);
92 auto trilerp_h = [&](double x, double y, double z) {
93 double fx = std::floor(x), fy = std::floor(y), fz = std::floor(z);
94 double wx = x - fx, wy = y - fy, wz = z - fz;
95 int x0 = (int)fx, y0 = (int)fy, z0 = (int)fz;
96 auto F = [&](int xx, int yy, int zz) { return hcoarse[CI(xx, yy, zz)]; };
97 double c00 = F(x0, y0, z0) * (1 - wx) + F(x0 + 1, y0, z0) * wx,
98 c10 = F(x0, y0 + 1, z0) * (1 - wx) + F(x0 + 1, y0 + 1, z0) * wx;
99 double c01 = F(x0, y0, z0 + 1) * (1 - wx) + F(x0 + 1, y0, z0 + 1) * wx,
100 c11 = F(x0, y0 + 1, z0 + 1) * (1 - wx) + F(x0 + 1, y0 + 1, z0 + 1) * wx;
101 double c0 = c00 * (1 - wy) + c10 * wy, c1 = c01 * (1 - wy) + c11 * wy;
102 return c0 * (1 - wz) + c1 * wz;
103 };
104 for (int ifz = 0; ifz < finner.z; ++ifz)
105 for (int ify = 0; ify < finner.y; ++ify)
106 for (int ifx = 0; ifx < finner.x; ++ifx) {
107 double cx = ratio.x == 2 ? 0.5 * ifx - 0.25 + g : (double)(ifx + g);
108 double cy = ratio.y == 2 ? 0.5 * ify - 0.25 + g : (double)(ify + g);
109 double cz = ratio.z == 2 ? 0.5 * ifz - 0.25 + g : (double)(ifz + g);
110 double r = hfine[FI(ifx + g, ify + g, ifz + g)] + trilerp_h(cx, cy, cz);
111 if (!close(gf[FI(ifx + g, ify + g, ifz + g)], r))
112 ++bad;
113 }
114
115 // --- correction ---
116 TField u = upN("u", hu, fn), v = upN("v", hv, fn), w = upN("w", hw, fn),
117 phi = upN("phi", hphi, fn);
118 correct(u, v, w, phi, fext, g);
119 auto gu = get(u, fn), gvv = get(v, fn), gw = get(w, fn);
120 for (int z = g; z < fext.z - g; ++z)
121 for (int y = g; y < fext.y - g; ++y)
122 for (int x = g; x < fext.x - g; ++x) {
123 std::size_t i = FI(x, y, z);
124 long sx = 1, sy = fext.x, sz = (long)fext.x * fext.y;
125 if (!close(gu[i], hu[i] - (hphi[i] - hphi[i - sx])))
126 ++bad;
127 if (!close(gvv[i], hv[i] - (hphi[i] - hphi[i - sy])))
128 ++bad;
129 if (!close(gw[i], hw[i] - (hphi[i] - hphi[i - sz])))
130 ++bad;
131 }
132 if (bad) {
133 std::fprintf(stderr, "FAIL: %d transfer/correct cells differ\n", bad);
134 status = 1;
135 }
136
137 // --- property: restrict(const)=const, prolong adds const ---
138 std::vector<double> ones(fn, 3.5);
139 TField cf = upN("cf", ones, fn), cc("cc", cn);
140 restrict_(cc, cf, cext, fext, g, cinner, ratio);
141 auto gcc = get(cc, cn);
142 for (int icz = 0; icz < cinner.z; ++icz)
143 for (int icy = 0; icy < cinner.y; ++icy)
144 for (int icx = 0; icx < cinner.x; ++icx)
145 if (!close(gcc[CI(icx + g, icy + g, icz + g)], 3.5))
146 ++bad;
147 std::vector<double> cones(cn, 2.0), fzero(fn, 0.0);
148 TField cc2 = upN("cc2", cones, cn), ff = upN("ff", fzero, fn);
149 prolong(ff, cc2, fext, cext, g, finner, ratio);
150 auto gff = get(ff, fn);
151 for (int ifz = 0; ifz < finner.z; ++ifz)
152 for (int ify = 0; ify < finner.y; ++ify)
153 for (int ifx = 0; ifx < finner.x; ++ifx)
154 if (!close(gff[FI(ifx + g, ify + g, ifz + g)], 2.0))
155 ++bad;
156 if (bad && !status) {
157 std::fprintf(stderr, "FAIL: constant-field property\n");
158 status = 1;
159 }
160
161 if (!status)
162 std::printf(
163 "[mac_transfer] PASS: restrict/prolong/correct match host + constant properties (exec: "
164 "%s)\n",
165 TExec::name());
166 }
167 Kokkos::finalize();
168 return status;
169}
flow — portable (Kokkos) multigrid transfer operators + projection velocity correction.
void correct(TField u, TField v, TField w, TConst phi, T3 e, int g)
void restrict_(TField coarse, TConst fine, T3 cext, T3 fext, int g, T3 cinner, T3 ratio)
Kokkos::View< double *, TMem > TField
void prolong(TField fine, TConst coarse, T3 fext, T3 cext, int g, T3 finner, T3 ratio)
static constexpr double F
int main(int argc, char **argv)