flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
test_poiseuille.cpp
Go to the documentation of this file.
1// Domain-BC validation in context: steady plane Poiseuille flow. Periodic in x (flow) and z,
2// no-slip walls in y, body force fx. The steady x-momentum reduces to -nu*Lap(u) = fx with u=0 at
3// the walls, whose solution is the parabola u(y) = (fx/2nu) y(Ly-y). We solve it with the ported
4// RB-GS diffusion smoother (peclet::flow::diffSmoothColor) using the wall face-fold for the no-slip
5// tangential BC (the mac_bc operators), and check u_max/U_mean -> 1.5 and the profile matches the
6// analytic parabola. Validates the domain-BC operators assembled with the diffusion operator. Runs
7// on any Kokkos backend.
8#include <cmath>
9#include <cstdio>
10#include <Kokkos_Core.hpp>
11#include <vector>
12
13#include "mac_stencils.hpp"
14
15using namespace peclet::flow;
16
17int main(int argc, char** argv) {
18 Kokkos::initialize(argc, argv);
19 int status = 0;
20 {
21 const int N = 24, g = 1;
22 const double nu = 1.0, fx = 1.0; // grid units; Ly = N
23 I3 e{N + 2 * g, N + 2 * g, N + 2 * g}, og{0, 0, 0};
24 const std::size_t n = (std::size_t)e.x * e.y * e.z;
25 const long sy = e.x;
26 const double Ac = 6.0 * nu; // steady: 6nu*u - nu*sum = fx
27
28 SField u("u", n), b("b", n), dcorr("dcorr", n);
29 Kokkos::deep_copy(u, 0.0);
30 // RHS = fx at inner cells; dcorr = +nu at the y-wall-adjacent inner planes (face-fold: the
31 // dropped no-slip wall face moves its beta=nu onto the diagonal). bval = 2*nu*wall = 0 for
32 // no-slip.
33 {
34 auto hb = Kokkos::create_mirror_view(b);
35 auto hd = Kokkos::create_mirror_view(dcorr);
36 Kokkos::deep_copy(hb, b);
37 Kokkos::deep_copy(hd, dcorr);
38 for (std::size_t i = 0; i < n; ++i) {
39 hb(i) = 0;
40 hd(i) = 0;
41 }
42 for (int z = g; z < e.z - g; ++z)
43 for (int y = g; y < e.y - g; ++y)
44 for (int x = g; x < e.x - g; ++x) {
45 long i = (long)x + (long)y * e.x + (long)z * (long)e.x * e.y;
46 hb(i) = fx;
47 if (y == g || y == e.y - g - 1)
48 hd(i) += nu; // wall-adjacent (bottom / top)
49 }
50 Kokkos::deep_copy(b, hb);
51 Kokkos::deep_copy(dcorr, hd);
52 }
53
54 // ghost fill: periodic in x and z; no-slip wall (ghost=0) in y.
55 SExec space;
56 auto fillBC = [&]() {
57 SField uu = u;
58 const int Ny = N;
59 // x periodic
60 Kokkos::parallel_for(
61 "fx", Kokkos::MDRangePolicy<SExec, Kokkos::Rank<2>>(space, {0, 0}, {e.y, e.z}),
62 KOKKOS_LAMBDA(int y, int z) {
63 long base = (long)y * e.x + (long)z * (long)e.x * e.y;
64 for (int gl = 0; gl < g; ++gl) {
65 uu(base + gl) = uu(base + gl + N);
66 uu(base + g + N + gl) = uu(base + g + gl);
67 }
68 });
69 // z periodic
70 Kokkos::parallel_for(
71 "fz", Kokkos::MDRangePolicy<SExec, Kokkos::Rank<2>>(space, {0, 0}, {e.x, e.y}),
72 KOKKOS_LAMBDA(int x, int y) {
73 long base = (long)x + (long)y * e.x;
74 long sz = (long)e.x * e.y;
75 for (int gl = 0; gl < g; ++gl) {
76 uu(base + (long)gl * sz) = uu(base + (long)(gl + N) * sz);
77 uu(base + (long)(g + N + gl) * sz) = uu(base + (long)(g + gl) * sz);
78 }
79 });
80 // y walls: ghost = 0
81 Kokkos::parallel_for(
82 "fy", Kokkos::MDRangePolicy<SExec, Kokkos::Rank<2>>(space, {0, 0}, {e.x, e.z}),
83 KOKKOS_LAMBDA(int x, int z) {
84 long base = (long)x + (long)z * (long)e.x * e.y;
85 for (int gl = 0; gl < g; ++gl) {
86 uu(base + (long)gl * sy) = 0.0;
87 uu(base + (long)(g + N + gl) * sy) = 0.0;
88 }
89 (void)Ny;
90 });
91 space.fence();
92 };
93
94 for (int it = 0; it < 6000; ++it) {
95 fillBC();
96 diffSmoothColor(u, SConst(b), e, og, g, nu, Ac, 0, SConst(dcorr));
97 fillBC();
98 diffSmoothColor(u, SConst(b), e, og, g, nu, Ac, 1, SConst(dcorr));
99 }
100
101 // extract the y-profile (x,z-uniform) and compare to the analytic parabola
102 auto hu = Kokkos::create_mirror_view(u);
103 Kokkos::deep_copy(hu, u);
104 std::vector<double> prof(N), exact(N);
105 double umax = 0, usum = 0;
106 for (int yc = 0; yc < N; ++yc) {
107 long i = (long)(g) + (long)(yc + g) * e.x + (long)(g) * (long)e.x * e.y; // x=g,z=g column
108 prof[yc] = hu(i);
109 double yphys = yc + 0.5;
110 exact[yc] = (fx / (2.0 * nu)) * yphys * (N - yphys);
111 umax = std::fmax(umax, prof[yc]);
112 usum += prof[yc];
113 }
114 const double umean = usum / N;
115 const double ratio = umax / umean; // Poiseuille: 1.5
116 double num = 0, den = 0;
117 for (int yc = 0; yc < N; ++yc) {
118 num += (prof[yc] - exact[yc]) * (prof[yc] - exact[yc]);
119 den += exact[yc] * exact[yc];
120 }
121 const double l2err = std::sqrt(num / den);
122
123 std::printf(
124 "[poiseuille] u_max/U_mean=%.4f (target 1.5); profile L2 err vs parabola=%.3e "
125 "(umax=%.4f)\n",
126 ratio, l2err, umax);
127 if (std::fabs(ratio - 1.5) > 0.03) {
128 std::fprintf(stderr, "FAIL: u_max/U_mean off 1.5\n");
129 status = 1;
130 }
131 if (l2err > 2e-2) {
132 std::fprintf(stderr, "FAIL: profile not parabolic\n");
133 status = 1;
134 }
135 if (!status)
136 std::printf(
137 "[poiseuille] PASS: no-slip-wall diffusion gives the Poiseuille parabola (exec %s)\n",
138 Kokkos::DefaultExecutionSpace::name());
139 }
140 Kokkos::finalize();
141 return status;
142}
flow — portable (Kokkos) MAC stencil operators: Red-Black Gauss-Seidel smoothers + divergence.
void diffSmoothColor(SField c, SConst b, I3 e, I3 og, int g, double beta, double Ac, int color, SConst dcorr)
Kokkos::View< const double *, SMem > SConst
Kokkos::DefaultExecutionSpace SExec
Kokkos::View< double *, SMem > SField
static constexpr int N
int main(int argc, char **argv)