flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
test_ibm_overlay.cpp
Go to the documentation of this file.
1// Correctness of the Kokkos Robust-Scaled IBM overlay build (peclet::flow::ibmFillEntry) vs a
2// HostSpace reference using the same code. Random cut-cell SDF configurations (fluid centre + mixed
3// solid/fluid neighbours, including sandwiched double-sided axes), across point-value (SCHEME 0)
4// and cell-average (1) and Dirichlet/Neumann. Compares every factor (D_rescale, dir_code,
5// K/M/X/Nbc/R). Runs on any Kokkos backend.
6#include <cmath>
7#include <cstdio>
8#include <Kokkos_Core.hpp>
9#include <random>
10#include <vector>
11
12#include "cut_cell_ibm.hpp"
13
14using namespace peclet::flow;
15using DSpace = Kokkos::DefaultExecutionSpace;
16
17template <int SCHEME>
18static int run(int bc) {
19 const int N = 3000;
20 std::mt19937 rng(100 + SCHEME * 7 + bc);
21 std::uniform_real_distribution<float> uc(0.05f, 0.95f); // fluid centre
22 std::uniform_real_distribution<float> us(-0.95f, -0.05f); // solid neighbour
23 std::uniform_real_distribution<float> uf(0.05f, 0.95f); // fluid neighbour
24 std::uniform_real_distribution<float> u01(0.f, 1.f);
25
26 std::vector<float> hc(N), hn((std::size_t)N * 6);
27 for (int i = 0; i < N; ++i) {
28 hc[i] = uc(rng);
29 // force a sandwiched axis on ~1/3 of cells for coverage
30 bool sandwich_x = u01(rng) < 0.33f;
31 for (int k = 0; k < 6; ++k) {
32 bool solid;
33 if (sandwich_x && (k == 0 || k == 1))
34 solid = true;
35 else
36 solid = u01(rng) < 0.5f;
37 hn[(std::size_t)i * 6 + k] = solid ? us(rng) : uf(rng);
38 }
39 }
40
41 // device
42 Kokkos::View<float*, IMem> dc("dc", N), dn("dn", (std::size_t)N * 6);
43 {
44 auto m = Kokkos::create_mirror_view(dc);
45 for (int i = 0; i < N; ++i)
46 m(i) = hc[i];
47 Kokkos::deep_copy(dc, m);
48 }
49 {
50 auto m = Kokkos::create_mirror_view(dn);
51 for (std::size_t i = 0; i < (std::size_t)N * 6; ++i)
52 m(i) = hn[i];
53 Kokkos::deep_copy(dn, m);
54 }
55 IbmOverlay dev{Kokkos::View<int*, IMem>("ci", N),
56 Kokkos::View<int*, IMem>("nb", N),
57 Kokkos::View<float*, IMem>("dr", N),
58 Kokkos::View<int*, IMem>("dirc", (std::size_t)N * 6),
59 Kokkos::View<float*, IMem>("K", (std::size_t)N * 6),
60 Kokkos::View<float*, IMem>("M", (std::size_t)N * 6),
61 Kokkos::View<float*, IMem>("X", (std::size_t)N * 6),
62 Kokkos::View<float*, IMem>("Nbc", (std::size_t)N * 6),
63 Kokkos::View<float*, IMem>("R", (std::size_t)N * 6)};
64 Kokkos::parallel_for(
65 "ibm_build", Kokkos::RangePolicy<DSpace>(0, N), KOKKOS_LAMBDA(int i) {
66 float sn[6];
67 for (int k = 0; k < 6; ++k)
68 sn[k] = dn((std::size_t)i * 6 + k);
69 ibmFillEntry<SCHEME>(dev, i, i * 10, dc(i), sn, bc);
70 });
71 Kokkos::fence();
72
73 // host reference (HostSpace overlay, same fill code)
75 HOV h{Kokkos::View<int*, Kokkos::HostSpace>("hci", N),
76 Kokkos::View<int*, Kokkos::HostSpace>("hnb", N),
77 Kokkos::View<float*, Kokkos::HostSpace>("hdr", N),
78 Kokkos::View<int*, Kokkos::HostSpace>("hdirc", (std::size_t)N * 6),
79 Kokkos::View<float*, Kokkos::HostSpace>("hK", (std::size_t)N * 6),
80 Kokkos::View<float*, Kokkos::HostSpace>("hM", (std::size_t)N * 6),
81 Kokkos::View<float*, Kokkos::HostSpace>("hX", (std::size_t)N * 6),
82 Kokkos::View<float*, Kokkos::HostSpace>("hNbc", (std::size_t)N * 6),
83 Kokkos::View<float*, Kokkos::HostSpace>("hR", (std::size_t)N * 6)};
84 for (int i = 0; i < N; ++i) {
85 float sn[6];
86 for (int k = 0; k < 6; ++k)
87 sn[k] = hn[(std::size_t)i * 6 + k];
88 ibmFillEntry<SCHEME>(h, i, i * 10, hc[i], sn, bc);
89 }
90
91 auto cmp1i = [&](Kokkos::View<int*, IMem> dv, Kokkos::View<int*, Kokkos::HostSpace> hv,
92 std::size_t n) {
93 auto m = Kokkos::create_mirror_view(dv);
94 Kokkos::deep_copy(m, dv);
95 int bad = 0;
96 for (std::size_t i = 0; i < n; ++i)
97 if (m(i) != hv(i))
98 ++bad;
99 return bad;
100 };
101 auto cmp1f = [&](Kokkos::View<float*, IMem> dv, Kokkos::View<float*, Kokkos::HostSpace> hv,
102 std::size_t n) {
103 auto m = Kokkos::create_mirror_view(dv);
104 Kokkos::deep_copy(m, dv);
105 int bad = 0;
106 for (std::size_t i = 0; i < n; ++i)
107 if (std::fabs((double)m(i) - (double)hv(i)) > 1e-5 * (1.0 + std::fabs((double)hv(i))))
108 ++bad;
109 return bad;
110 };
111 int bad = 0;
112 bad += cmp1i(dev.cell_index, h.cell_index, N) + cmp1i(dev.num_boundaries, h.num_boundaries, N) +
113 cmp1i(dev.dir_code, h.dir_code, (std::size_t)N * 6);
114 bad += cmp1f(dev.D_rescale, h.D_rescale, N);
115 bad += cmp1f(dev.K_val, h.K_val, (std::size_t)N * 6) +
116 cmp1f(dev.M_val, h.M_val, (std::size_t)N * 6) +
117 cmp1f(dev.X_val, h.X_val, (std::size_t)N * 6) +
118 cmp1f(dev.Nbc_val, h.Nbc_val, (std::size_t)N * 6) +
119 cmp1f(dev.R_val, h.R_val, (std::size_t)N * 6);
120 return bad;
121}
122
123int main(int argc, char** argv) {
124 Kokkos::initialize(argc, argv);
125 int status = 0;
126 {
127 int bad = run<0>(0) + run<1>(0) + run<0>(1) + run<1>(1);
128 if (bad) {
129 std::fprintf(stderr, "FAIL: %d overlay-factor mismatches\n", bad);
130 status = 1;
131 } else
132 std::printf(
133 "[ibm_overlay] PASS: Robust-Scaled overlay (point/avg x Dirichlet/Neumann) matches host "
134 "(exec: %s)\n",
135 DSpace::name());
136 }
137 Kokkos::finalize();
138 return status;
139}
flow — portable (Kokkos) Robust-Scaled cut-cell IBM primitives + per-cut-cell overlay build.
static constexpr int N
Kokkos::DefaultExecutionSpace DSpace
static int run(int bc)
int main(int argc, char **argv)