flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
test_ibm_apply.cpp
Go to the documentation of this file.
1// Correctness of the Kokkos IBM operator assembly: build the base backward-Euler diffusion stencil
2// (ibmBuildDiffusion), build the Robust-Scaled overlay (ibmFillEntry), then apply it
3// (ibmModifyStencil), and compare the modified stencil + inhomogeneous term + row scaling to a host
4// replication. Runs on whatever backend Kokkos was built for.
5#include <cmath>
6#include <cstdio>
7#include <Kokkos_Core.hpp>
8#include <random>
9#include <vector>
10
11#include "cut_cell_ibm.hpp"
12
13using namespace peclet::flow;
14using DSpace = Kokkos::DefaultExecutionSpace;
15using FV = Kokkos::View<float*, IMem>;
16using DV = Kokkos::View<double*, IMem>;
17
18int main(int argc, char** argv) {
19 Kokkos::initialize(argc, argv);
20 int status = 0;
21 {
22 const int ex = 12, ey = 12, ez = 12;
23 const std::size_t n = (std::size_t)ex * ey * ez;
24 const double beta = 0.7, idiag = 3.0;
25 const float u_bc = 0.25f;
26 const int M = 64; // cut cells
27
28 // distinct interior grid indices + random cut-cell SDF configs
29 std::mt19937 rng(7);
30 std::uniform_int_distribution<int> ic(2, 9);
31 std::uniform_real_distribution<float> uc(0.05f, 0.95f), us(-0.95f, -0.05f), uf(0.05f, 0.95f),
32 u01(0, 1);
33 std::vector<int> cidx;
34 std::vector<float> sc(M);
35 std::vector<float> sn((std::size_t)M * 6);
36 std::vector<char> used(n, 0);
37 for (int i = 0; i < M;) {
38 int x = ic(rng), y = ic(rng), z = ic(rng);
39 std::size_t c = (std::size_t)x + (std::size_t)y * ex + (std::size_t)z * ex * ey;
40 if (used[c])
41 continue;
42 used[c] = 1;
43 cidx.push_back((int)c);
44 sc[i] = uc(rng);
45 bool sw = u01(rng) < 0.3f;
46 for (int k = 0; k < 6; ++k) {
47 bool solid = (sw && k < 2) || (u01(rng) < 0.5f);
48 sn[(std::size_t)i * 6 + k] = solid ? us(rng) : uf(rng);
49 }
50 ++i;
51 }
52
53 auto mkF = [&](const char* nm) {
54 FV v(nm, n);
55 return v;
56 };
57 FV AC = mkF("AC"), AW = mkF("AW"), AE = mkF("AE"), AS = mkF("AS"), AN = mkF("AN"),
58 AB = mkF("AB"), AT = mkF("AT");
59 DV inhom("inhom", n), rscale("rscale", n); // zero-init
60 ibmBuildDiffusion(AC, AW, AE, AS, AN, AB, AT, ex, ey, ez, beta, idiag);
61
62 // build overlay on device
63 IbmOverlay ov{
64 Kokkos::View<int*, IMem>("ci", M), Kokkos::View<int*, IMem>("nb", M),
65 Kokkos::View<float*, IMem>("dr", M), Kokkos::View<int*, IMem>("dc", (std::size_t)M * 6),
66 FV("K", (std::size_t)M * 6), FV("Mv", (std::size_t)M * 6),
67 FV("X", (std::size_t)M * 6), FV("Nbc", (std::size_t)M * 6),
68 FV("R", (std::size_t)M * 6)};
69 Kokkos::View<int*, IMem> dci("dci", M);
70 {
71 auto m = Kokkos::create_mirror_view(dci);
72 for (int i = 0; i < M; ++i)
73 m(i) = cidx[i];
74 Kokkos::deep_copy(dci, m);
75 }
76 FV dsc("dsc", M);
77 {
78 auto m = Kokkos::create_mirror_view(dsc);
79 for (int i = 0; i < M; ++i)
80 m(i) = sc[i];
81 Kokkos::deep_copy(dsc, m);
82 }
83 FV dsn("dsn", (std::size_t)M * 6);
84 {
85 auto m = Kokkos::create_mirror_view(dsn);
86 for (std::size_t i = 0; i < (std::size_t)M * 6; ++i)
87 m(i) = sn[i];
88 Kokkos::deep_copy(dsn, m);
89 }
90 Kokkos::parallel_for(
91 "bo", Kokkos::RangePolicy<DSpace>(0, M), KOKKOS_LAMBDA(int i) {
92 float s6[6];
93 for (int k = 0; k < 6; ++k)
94 s6[k] = dsn((std::size_t)i * 6 + k);
95 ibmFillEntry<0>(ov, i, dci(i), dsc(i), s6, 0);
96 });
97 Kokkos::fence();
98 ibmModifyStencil(AC, AW, AE, AS, AN, AB, AT, inhom, rscale, ov, M, u_bc);
99
100 auto gf = [&](FV v) {
101 std::vector<float> o(n);
102 auto m = Kokkos::create_mirror_view(v);
103 Kokkos::deep_copy(m, v);
104 for (std::size_t i = 0; i < n; ++i)
105 o[i] = m(i);
106 return o;
107 };
108 auto gd = [&](DV v) {
109 std::vector<double> o(n);
110 auto m = Kokkos::create_mirror_view(v);
111 Kokkos::deep_copy(m, v);
112 for (std::size_t i = 0; i < n; ++i)
113 o[i] = m(i);
114 return o;
115 };
116 auto GAC = gf(AC), GAW = gf(AW), GAE = gf(AE), GAS = gf(AS), GAN = gf(AN), GAB = gf(AB),
117 GAT = gf(AT);
118 auto GIN = gd(inhom), GRS = gd(rscale);
119
120 // --- host replication ---
121 std::vector<float> hAC(n), hAW(n), hAE(n), hAS(n), hAN(n), hAB(n), hAT(n);
122 std::vector<double> hin(n, 0), hrs(n, 0);
123 float nb = (float)(-beta), cc = (float)(idiag + 6.0 * beta);
124 for (std::size_t i = 0; i < n; ++i) {
125 hAC[i] = cc;
126 hAW[i] = nb;
127 hAE[i] = nb;
128 hAS[i] = nb;
129 hAN[i] = nb;
130 hAB[i] = nb;
131 hAT[i] = nb;
132 }
134 HOV h{Kokkos::View<int*, Kokkos::HostSpace>("hci", M),
135 Kokkos::View<int*, Kokkos::HostSpace>("hnb", M),
136 Kokkos::View<float*, Kokkos::HostSpace>("hdr", M),
137 Kokkos::View<int*, Kokkos::HostSpace>("hdc", (std::size_t)M * 6),
138 Kokkos::View<float*, Kokkos::HostSpace>("hK", (std::size_t)M * 6),
139 Kokkos::View<float*, Kokkos::HostSpace>("hM", (std::size_t)M * 6),
140 Kokkos::View<float*, Kokkos::HostSpace>("hX", (std::size_t)M * 6),
141 Kokkos::View<float*, Kokkos::HostSpace>("hNbc", (std::size_t)M * 6),
142 Kokkos::View<float*, Kokkos::HostSpace>("hR", (std::size_t)M * 6)};
143 for (int i = 0; i < M; ++i) {
144 float s6[6];
145 for (int k = 0; k < 6; ++k)
146 s6[k] = sn[(std::size_t)i * 6 + k];
147 ibmFillEntry<0>(h, i, cidx[i], sc[i], s6, 0);
148 }
149 const int OPP[6] = {1, 0, 3, 2, 5, 4};
150 for (int li = 0; li < M; ++li) {
151 int c = h.cell_index(li);
152 float descale = h.D_rescale(li);
153 hrs[c] = descale;
154 double orig[6] = {hAE[c], hAW[c], hAN[c], hAS[c], hAT[c], hAB[c]};
155 double aC = (double)hAC[c] * (double)descale;
156 double mod[6] = {0, 0, 0, 0, 0, 0};
157 double inh = 0;
158 for (int k = 0; k < 6; ++k) {
159 float K = h.K_val(li * 6 + k), Mv = h.M_val(li * 6 + k), X = h.X_val(li * 6 + k),
160 Nbc = h.Nbc_val(li * 6 + k);
161 double vnb = orig[k];
162 aC += vnb * K;
163 inh += (double)Nbc * u_bc * vnb;
164 mod[k] += vnb * ((double)descale * Mv - 1.0);
165 mod[OPP[k]] += vnb * X;
166 }
167 hAC[c] = (float)aC;
168 hAE[c] = (float)(orig[0] + mod[0]);
169 hAW[c] = (float)(orig[1] + mod[1]);
170 hAN[c] = (float)(orig[2] + mod[2]);
171 hAS[c] = (float)(orig[3] + mod[3]);
172 hAT[c] = (float)(orig[4] + mod[4]);
173 hAB[c] = (float)(orig[5] + mod[5]);
174 hin[c] += inh;
175 }
176
177 // Modified coefficients involve descale*M-1 cancellation + cross-terms; fma contraction differs
178 // between nvcc and gcc, so use a relative tolerance appropriate to that (dist/inhom tracked
179 // separately).
180 auto cf = [&](float a, float b) {
181 return std::fabs((double)a - (double)b) <= 2e-3 * (1.0 + std::fabs((double)b));
182 };
183 auto cd = [&](double a, double b) { return std::fabs(a - b) <= 2e-3 * (1.0 + std::fabs(b)); };
184 int bad = 0;
185 double maxrel = 0;
186 auto rel = [&](double a, double b) {
187 double r = std::fabs(a - b) / (1.0 + std::fabs(b));
188 if (r > maxrel)
189 maxrel = r;
190 };
191 for (std::size_t i = 0; i < n; ++i) {
192 rel(GAC[i], hAC[i]);
193 rel(GAW[i], hAW[i]);
194 rel(GAE[i], hAE[i]);
195 rel(GIN[i], hin[i]);
196 if (!cf(GAC[i], hAC[i]) || !cf(GAW[i], hAW[i]) || !cf(GAE[i], hAE[i]) ||
197 !cf(GAS[i], hAS[i]) || !cf(GAN[i], hAN[i]) || !cf(GAB[i], hAB[i]) || !cf(GAT[i], hAT[i]))
198 ++bad;
199 if (!cd(GIN[i], hin[i]) || !cd(GRS[i], hrs[i]))
200 ++bad;
201 }
202 if (bad) {
203 std::fprintf(stderr, "FAIL: %d modified-stencil cells differ (max rel diff %.3e)\n", bad,
204 maxrel);
205 status = 1;
206 } else
207 std::printf(
208 "[ibm_apply] PASS: build+overlay+modify stencil (%d cut cells) matches host (exec: %s)\n",
209 M, DSpace::name());
210 }
211 Kokkos::finalize();
212 return status;
213}
flow — portable (Kokkos) Robust-Scaled cut-cell IBM primitives + per-cut-cell overlay build.
void ibmBuildDiffusion(Kokkos::View< float *, IMem > AC, Kokkos::View< float *, IMem > AW, Kokkos::View< float *, IMem > AE, Kokkos::View< float *, IMem > AS, Kokkos::View< float *, IMem > AN, Kokkos::View< float *, IMem > AB, Kokkos::View< float *, IMem > AT, int ex, int ey, int ez, double beta, double idiag)
void ibmModifyStencil(Kokkos::View< float *, IMem > AC, Kokkos::View< float *, IMem > AW, Kokkos::View< float *, IMem > AE, Kokkos::View< float *, IMem > AS, Kokkos::View< float *, IMem > AN, Kokkos::View< float *, IMem > AB, Kokkos::View< float *, IMem > AT, Kokkos::View< double *, IMem > a_inhom, Kokkos::View< double *, IMem > rhs_scale, const IbmOverlay &ibm, int numActive, float u_bc_val)
static constexpr double AC
Kokkos::DefaultExecutionSpace DSpace
int main(int argc, char **argv)
Kokkos::View< double *, IMem > DV
Kokkos::View< float *, IMem > FV