flow 1.3.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
test_poiseuille_ibm.cpp
Go to the documentation of this file.
1// Validation of the assembled IBM velocity solve (the verify_poiseuille_sdflow physics): plane
2// Poiseuille through an SDF-defined channel with cut-cell IBM no-slip walls, body-force driven,
3// physical units (rho/mu/dt). Solve the backward-Euler x-momentum to steady with the IBM-modified
4// stencil and compare to U_max = F*H^2/(8*mu). Exercises buildIbmOverlay + ibmBuildDiffusion +
5// ibmModifyStencil + ibmSolidMask + ibmRbgsSweep assembled together. Runs on any Kokkos backend.
6#include <cmath>
7#include <cstdio>
8#include <Kokkos_Core.hpp>
9#include <vector>
10
11#include "mac_ibm.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 const int nx = 4, nz = 4, ny = 48; // periodic x (flow) & z; channel along y
21 // Half-integer wall positions so the SDF zero lies BETWEEN cells -> fluid cells with solid
22 // neighbours (cut cells) form, exercising the Robust-Scaled cut-cell no-slip (not just
23 // masking).
24 const double ylo = 6.5, yhi = ny - 6.5; // immersed walls; H = yhi - ylo
25 const double H = yhi - ylo;
26 const double rho = 1.0, mu = 0.1, dt = 50.0, F = 0.01;
27 const double idiag = rho / dt, beta = mu;
28 C3 e{nx + 2 * g, ny + 2 * g, nz + 2 * g};
29 const std::size_t n = (std::size_t)e.x * e.y * e.z;
30 const Off3 offU{-0.5f, 0.0f, 0.0f}; // u stored at the -x face
31
32 // channel SDF: sdf(iy) = min(iy - ylo, yhi - iy) (>0 in fluid, <0 in the wall) at each ext
33 // cell.
34 CCField sdf("sdf", n);
35 {
36 auto h = Kokkos::create_mirror_view(sdf);
37 for (int z = 0; z < e.z; ++z)
38 for (int y = 0; y < e.y; ++y)
39 for (int x = 0; x < e.x; ++x) {
40 int iy = y - g;
41 double s = std::min((double)iy - ylo, yhi - (double)iy);
42 h((long)x + (long)y * e.x + (long)z * (long)e.x * e.y) = s;
43 }
44 Kokkos::deep_copy(sdf, h);
45 }
46
47 // build the u-component IBM overlay
48 const int maxCut = (int)((long)nx * ny * nz);
49 // IbmOverlay row storage follows mreal (G.6): float unless -DPECLET_FLOW_OPERATOR_DOUBLE.
50 IbmOverlay ov{Kokkos::View<int*, CCMem>("ci", maxCut),
51 Kokkos::View<int*, CCMem>("nb", maxCut),
52 Kokkos::View<mreal*, CCMem>("dr", maxCut),
53 Kokkos::View<int*, CCMem>("dc", (std::size_t)maxCut * 6),
54 Kokkos::View<mreal*, CCMem>("K", (std::size_t)maxCut * 6),
55 Kokkos::View<mreal*, CCMem>("M", (std::size_t)maxCut * 6),
56 Kokkos::View<mreal*, CCMem>("X", (std::size_t)maxCut * 6),
57 Kokkos::View<mreal*, CCMem>("Nbc", (std::size_t)maxCut * 6),
58 Kokkos::View<mreal*, CCMem>("R", (std::size_t)maxCut * 6)};
59 Kokkos::View<int*, CCMem> idMap("idMap", n);
60 Kokkos::View<int, CCMem> counter("counter");
61 int nCut =
62 buildIbmOverlay<1>(CCConst(sdf), e, g, offU, /*bc_type Dirichlet*/ 0, ov, idMap, counter);
63
64 // base diffusion stencil + apply overlay
65 using FV = Kokkos::View<float*, CCMem>;
66 FV AC("AC", n), AW("AW", n), AE("AE", n), AS("AS", n), AN("AN", n), AB("AB", n), AT("AT", n);
67 Kokkos::View<double*, CCMem> inhom("inhom", n), rscale("rscale", n);
68 Kokkos::deep_copy(rscale, 1.0); // non-cut cells: scale 1
69 ibmBuildDiffusion(AC, AW, AE, AS, AN, AB, AT, e.x, e.y, e.z, beta, idiag);
70 ibmModifyStencil(AC, AW, AE, AS, AN, AB, AT, inhom, rscale, ov, nCut, /*u_bc*/ 0.0f);
71
72 // solid mask for u
73 CCField mask("mask", n);
74 ibmSolidMask(mask, CCConst(sdf), e, offU);
75
76 CCField u("u", n), b("b", n);
77 Kokkos::deep_copy(u, 0.0);
79
80 // periodic x,z ghost fill (y handled by the immersed walls / mask)
81 auto fillXZ = [&]() {
82 CCField uu = u;
83 const int Nx = nx, Nz = nz;
84 Kokkos::parallel_for(
85 "fx", peclet::flow::MDRange2<CCExec>(space, {0, 0}, {e.y, e.z}),
86 KOKKOS_LAMBDA(int y, int z) {
87 long base = (long)y * e.x + (long)z * (long)e.x * e.y;
88 for (int gl = 0; gl < g; ++gl) {
89 uu(base + gl) = uu(base + gl + Nx);
90 uu(base + g + Nx + gl) = uu(base + g + gl);
91 }
92 });
93 Kokkos::parallel_for(
94 "fz", peclet::flow::MDRange2<CCExec>(space, {0, 0}, {e.x, e.y}),
95 KOKKOS_LAMBDA(int x, int y) {
96 long base = (long)x + (long)y * e.x;
97 long sz = (long)e.x * e.y;
98 for (int gl = 0; gl < g; ++gl) {
99 uu(base + (long)gl * sz) = uu(base + (long)(gl + Nz) * sz);
100 uu(base + (long)(g + Nz + gl) * sz) = uu(base + (long)(g + gl) * sz);
101 }
102 });
103 space.fence();
104 };
105
106 // time-step the IBM momentum solve to steady state (slow approach: ~mu*k^2*dt per step)
107 for (int step = 0; step < 600; ++step) {
108 // RHS b' = rscale * (idiag*u + F) (Robust-Scaled; inhom=0 for no-slip walls)
109 {
110 CCField uu = u, bb = b;
111 auto rs = rscale;
112 double id = idiag, ff = F;
113 Kokkos::parallel_for(
114 "rhs", Kokkos::RangePolicy<CCExec>(space, 0, n),
115 KOKKOS_LAMBDA(std::size_t i) { bb(i) = rs(i) * (id * uu(i) + ff); });
116 space.fence();
117 }
118 for (int it = 0; it < 200; ++it) {
119 fillXZ();
120 ibmRbgsStencilColor(u, CCConst(b), MConst(AC), MConst(AW), MConst(AE), MConst(AS),
121 MConst(AN), MConst(AB), MConst(AT), CCConst(mask), e, C3{0, 0, 0}, g,
122 0);
123 fillXZ();
124 ibmRbgsStencilColor(u, CCConst(b), MConst(AC), MConst(AW), MConst(AE), MConst(AS),
125 MConst(AN), MConst(AB), MConst(AT), CCConst(mask), e, C3{0, 0, 0}, g,
126 1);
127 }
128 }
129
130 // extract centerline profile u(y) at x=g,z=g and compare to the parabola
131 auto hu = Kokkos::create_mirror_view(u);
132 Kokkos::deep_copy(hu, u);
133 const double Uana = F * H * H / (8.0 * mu);
134 double umax = 0, l2num = 0, l2den = 0;
135 for (int iy = 0; iy < ny; ++iy) {
136 long i = (long)g + (long)(iy + g) * e.x + (long)g * (long)e.x * e.y;
137 double un = hu(i);
138 umax = std::fmax(umax, un);
139 if (iy > ylo && iy < yhi) { // fluid interior
140 double yy = iy;
141 double ue = (F / (2.0 * mu)) * (yy - ylo) * (yhi - yy);
142 l2num += (un - ue) * (un - ue);
143 l2den += ue * ue;
144 }
145 }
146 const double l2err = std::sqrt(l2num / l2den);
147 const double umaxErr = std::fabs(umax - Uana) / Uana;
148 std::printf(
149 "[poiseuille_ibm] cut cells=%d; U_max=%.5f analytic=%.5f (err %.2e); profile L2 err=%.2e\n",
150 nCut, umax, Uana, umaxErr, l2err);
151 if (nCut <= 0) {
152 std::fprintf(stderr, "FAIL: no cut cells found\n");
153 status = 1;
154 }
155 if (umaxErr > 3e-2) {
156 std::fprintf(stderr, "FAIL: U_max off analytic\n");
157 status = 1;
158 }
159 if (l2err > 3e-2) {
160 std::fprintf(stderr, "FAIL: profile not parabolic\n");
161 status = 1;
162 }
163 if (!status)
164 std::printf("[poiseuille_ibm] PASS: IBM cut-cell channel reproduces Poiseuille (exec %s)\n",
165 Kokkos::DefaultExecutionSpace::name());
166 }
167 Kokkos::finalize();
168 return status;
169}
int main()
Definition dbg_scene.cpp:13
flow — portable (Kokkos) IBM geometric fields + variable-coefficient RB-GS smoother.
void ibmSolidMask(CCField mask, CCConst sdf, C3 ext, Off3 off)
Definition mac_ibm.hpp:249
void ibmModifyStencil(MV AC, MV AW, MV AE, MV AS, MV AN, MV AB, MV AT, Kokkos::View< double *, IMem > a_inhom, Kokkos::View< double *, IMem > rhs_scale, const OV &ibm, int numActive, typename OV::value_type u_bc_val, Kokkos::View< const double *, IMem > u_bc=Kokkos::View< const double *, IMem >())
Kokkos::View< double *, CCMem > CCField
Kokkos::DefaultExecutionSpace CCExec
Kokkos::View< const float *, CCMem > MConst
void ibmBuildDiffusion(MV AC, MV AW, MV AE, MV AS, MV AN, MV AB, MV AT, int ex, int ey, int ez, double bx, double by, double bz, double idiag)
void ibmRbgsStencilColor(CCField x, CCConst b, MC AC, MC AW, MC AE, MC AS, MC AN, MC AB, MC AT, CCConst solidmask, C3 ext, C3 og, int g, int color)
Definition mac_ibm.hpp:287
Kokkos::View< const double *, CCMem > CCConst
static constexpr double AC
static constexpr double F
Kokkos::View< float *, IMem > FV