flow 1.3.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
mac_stencils.hpp
Go to the documentation of this file.
1
11#ifndef PECLET_FLOW_MAC_STENCILS_HPP
12#define PECLET_FLOW_MAC_STENCILS_HPP
13
14#include <Kokkos_Core.hpp>
15#include <type_traits>
16
17#include "policy.hpp"
18
19namespace peclet::flow {
20
21using SExec = Kokkos::DefaultExecutionSpace;
22using SMem = SExec::memory_space;
23using SField = Kokkos::View<double*, SMem>;
24using SConst = Kokkos::View<const double*, SMem>;
25
26struct I3 {
27 int x, y, z;
28};
29
30KOKKOS_INLINE_FUNCTION long L3(int x, int y, int z, I3 e) {
31 return static_cast<long>(x) + static_cast<long>(y) * e.x +
32 static_cast<long>(z) * static_cast<long>(e.x) * e.y;
33}
34
35// One Red-Black sweep colour of the implicit-diffusion smoother:
36// c[i] = (b[i] + beta*sum_neighbours) / (Ac + dcorr[i]). Call for colour 0 then 1.
37// Host backends take the line-sweep form (one (y,z) pencil per task, stride-2 x-loop at the
38// colour's parity — bit-identical, same-colour cells are independent); device keeps MDRange.
39//
40// ANISO DISPATCH (doc/anisotropic_metric.md §2, trap 4). With per-axis viscous coefficients the
41// numerator is `bx*(sW+sE) + by*(sS+sN) + bz*(sB+sT)`, which SUMS IN A DIFFERENT ORDER from the
42// isotropic `beta*(sW+sE+sS+sN+sB+sT)` and is therefore not bit-identical at bx==by==bz. The
43// isotropic path is the reference: `Aniso == false` runs today's expression LITERALLY, and the
44// per-axis body exists only for a genuinely stretched domain.
45template <bool Aniso>
46inline void diffSmoothColorT(SField c, SConst b, I3 e, I3 og, int g, double bx, double by,
47 double bz, double Ac, int color, SConst dcorr) {
49 const bool hasD = (dcorr.extent(0) != 0);
50 if constexpr (std::is_same_v<typename SExec::memory_space, Kokkos::HostSpace>) {
51 const int nyi = e.y - 2 * g, nzi = e.z - 2 * g;
52 Kokkos::parallel_for(
53 "peclet::flow::diff", Kokkos::RangePolicy<SExec>(space, 0, (long)nyi * nzi),
54 KOKKOS_LAMBDA(long t) {
55 const int y = g + (int)(t % nyi), z = g + (int)(t / nyi);
56 const long sx = 1, sy = e.x, sz = static_cast<long>(e.x) * e.y;
57 const int P = (color + og.x + og.y + y + og.z + z) & 1;
58 for (int x = g + ((P ^ (g & 1)) & 1); x < e.x - g; x += 2) {
59 const long i = L3(x, y, z, e);
60 // nvcc forbids an extended lambda FIRST-capturing a variable inside an
61 // `if constexpr`, so name the coefficients and read the six neighbours here. Both
62 // are exact: the copies are copies and the sums below keep the legacy operand order.
63 const double b0 = bx, b1 = by, b2 = bz;
64 const double nE = c(i + sx), nW = c(i - sx), nN = c(i + sy), nS = c(i - sy),
65 nT = c(i + sz), nB = c(i - sz);
66 double s;
67 if constexpr (Aniso)
68 s = b0 * (nE + nW) + b1 * (nN + nS) + b2 * (nT + nB);
69 else
70 s = b0 * (nE + nW + nN + nS + nT + nB);
71 c(i) = (b(i) + s) / (Ac + (hasD ? dcorr(i) : 0.0));
72 }
73 });
74 return;
75 }
76 using MD = MDRange3<SExec>;
77 Kokkos::parallel_for(
78 "peclet::flow::diff", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
79 KOKKOS_LAMBDA(int x, int y, int z) {
80 if ((((x + og.x) + (y + og.y) + (z + og.z)) & 1) != color)
81 return;
82 const long i = L3(x, y, z, e), sx = 1, sy = e.x, sz = static_cast<long>(e.x) * e.y;
83 const double b0 = bx, b1 = by, b2 = bz; // first-capture outside the constexpr-if (nvcc)
84 const double nE = c(i + sx), nW = c(i - sx), nN = c(i + sy), nS = c(i - sy), nT = c(i + sz),
85 nB = c(i - sz);
86 double s;
87 if constexpr (Aniso)
88 s = b0 * (nE + nW) + b1 * (nN + nS) + b2 * (nT + nB);
89 else
90 s = b0 * (nE + nW + nN + nS + nT + nB);
91 c(i) = (b(i) + s) / (Ac + (hasD ? dcorr(i) : 0.0));
92 });
93}
94
95// Per-axis entry point: `aniso` selects the per-axis body, `!aniso` the legacy one (bx is beta).
96inline void diffSmoothColor(SField c, SConst b, I3 e, I3 og, int g, double bx, double by, double bz,
97 double Ac, int color, SConst dcorr, bool aniso) {
98 if (aniso)
99 diffSmoothColorT<true>(c, b, e, og, g, bx, by, bz, Ac, color, dcorr);
100 else
101 diffSmoothColorT<false>(c, b, e, og, g, bx, by, bz, Ac, color, dcorr);
102}
103
104// Isotropic spelling (the legacy signature).
105inline void diffSmoothColor(SField c, SConst b, I3 e, I3 og, int g, double beta, double Ac,
106 int color, SConst dcorr) {
107 diffSmoothColorT<false>(c, b, e, og, g, beta, beta, beta, Ac, color, dcorr);
108}
109
110// Residual r = b - A c of the constant-coefficient folded diffusion operator over the inner
111// cells (both colours): A c = (Ac + dcorr) c - beta * sum(neighbours). The residual-based
112// momentum stop for the all-fluid domain-BC path (velSweepLoop's `resid` functor).
113template <bool Aniso>
114inline void diffResidualT(SField r, SConst c, SConst b, I3 e, int g, double bx, double by,
115 double bz, double Ac, SConst dcorr) {
116 SExec space;
117 const bool hasD = (dcorr.extent(0) != 0);
118 using MD = MDRange3<SExec>;
119 Kokkos::parallel_for(
120 "peclet::flow::diff_resid", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
121 KOKKOS_LAMBDA(int x, int y, int z) {
122 const long i = L3(x, y, z, e), sx = 1, sy = e.x, sz = static_cast<long>(e.x) * e.y;
123 const double b0 = bx, b1 = by, b2 = bz; // first-capture outside the constexpr-if (nvcc)
124 const double nE = c(i + sx), nW = c(i - sx), nN = c(i + sy), nS = c(i - sy), nT = c(i + sz),
125 nB = c(i - sz);
126 double sum;
127 if constexpr (Aniso)
128 sum = b0 * (nE + nW) + b1 * (nN + nS) + b2 * (nT + nB);
129 else
130 sum = b0 * (nE + nW + nN + nS + nT + nB);
131 r(i) = b(i) - ((Ac + (hasD ? dcorr(i) : 0.0)) * c(i) - sum);
132 });
133}
134
135// Per-axis entry point (see diffSmoothColor's ANISO DISPATCH note: the summation order differs).
136inline void diffResidual(SField r, SConst c, SConst b, I3 e, int g, double bx, double by, double bz,
137 double Ac, SConst dcorr, bool aniso) {
138 if (aniso)
139 diffResidualT<true>(r, c, b, e, g, bx, by, bz, Ac, dcorr);
140 else
141 diffResidualT<false>(r, c, b, e, g, bx, by, bz, Ac, dcorr);
142}
143
144// Isotropic spelling (the legacy signature).
145inline void diffResidual(SField r, SConst c, SConst b, I3 e, int g, double beta, double Ac,
146 SConst dcorr) {
147 diffResidualT<false>(r, c, b, e, g, beta, beta, beta, Ac, dcorr);
148}
149
150// diffSmoothColor + fused max|Δ| reduction over the swept colour (see ibmRbgsStencilColorDu):
151// runs as the second colour of a sweep when the momentum tolerance stop is active.
152template <bool Aniso>
153inline double diffSmoothColorDuT(SField c, SConst b, I3 e, I3 og, int g, double bx, double by,
154 double bz, double Ac, int color, SConst dcorr) {
155 SExec space;
156 const bool hasD = (dcorr.extent(0) != 0);
157 double du = 0.0;
158 if constexpr (std::is_same_v<typename SExec::memory_space, Kokkos::HostSpace>) {
159 const int nyi = e.y - 2 * g, nzi = e.z - 2 * g;
160 Kokkos::parallel_reduce(
161 "peclet::flow::diff_du", Kokkos::RangePolicy<SExec>(space, 0, (long)nyi * nzi),
162 KOKKOS_LAMBDA(long t, double& m) {
163 const int y = g + (int)(t % nyi), z = g + (int)(t / nyi);
164 const long sx = 1, sy = e.x, sz = static_cast<long>(e.x) * e.y;
165 const int P = (color + og.x + og.y + y + og.z + z) & 1;
166 for (int x = g + ((P ^ (g & 1)) & 1); x < e.x - g; x += 2) {
167 const long i = L3(x, y, z, e);
168 // nvcc forbids an extended lambda FIRST-capturing a variable inside an
169 // `if constexpr`, so name the coefficients and read the six neighbours here. Both
170 // are exact: the copies are copies and the sums below keep the legacy operand order.
171 const double b0 = bx, b1 = by, b2 = bz;
172 const double nE = c(i + sx), nW = c(i - sx), nN = c(i + sy), nS = c(i - sy),
173 nT = c(i + sz), nB = c(i - sz);
174 double s;
175 if constexpr (Aniso)
176 s = b0 * (nE + nW) + b1 * (nN + nS) + b2 * (nT + nB);
177 else
178 s = b0 * (nE + nW + nN + nS + nT + nB);
179 const double cn = (b(i) + s) / (Ac + (hasD ? dcorr(i) : 0.0));
180 const double d = Kokkos::fabs(cn - c(i));
181 if (d > m)
182 m = d;
183 c(i) = cn;
184 }
185 },
186 Kokkos::Max<double>(du));
187 return du;
188 }
189 using MD = MDRange3<SExec>;
190 Kokkos::parallel_reduce(
191 "peclet::flow::diff_du", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
192 KOKKOS_LAMBDA(int x, int y, int z, double& m) {
193 if ((((x + og.x) + (y + og.y) + (z + og.z)) & 1) != color)
194 return;
195 const long i = L3(x, y, z, e), sx = 1, sy = e.x, sz = static_cast<long>(e.x) * e.y;
196 const double b0 = bx, b1 = by, b2 = bz; // first-capture outside the constexpr-if (nvcc)
197 const double nE = c(i + sx), nW = c(i - sx), nN = c(i + sy), nS = c(i - sy), nT = c(i + sz),
198 nB = c(i - sz);
199 double s;
200 if constexpr (Aniso)
201 s = b0 * (nE + nW) + b1 * (nN + nS) + b2 * (nT + nB);
202 else
203 s = b0 * (nE + nW + nN + nS + nT + nB);
204 const double cn = (b(i) + s) / (Ac + (hasD ? dcorr(i) : 0.0));
205 const double d = Kokkos::fabs(cn - c(i));
206 if (d > m)
207 m = d;
208 c(i) = cn;
209 },
210 Kokkos::Max<double>(du));
211 return du;
212}
213
214// Per-axis entry point (see diffSmoothColor's ANISO DISPATCH note).
215inline double diffSmoothColorDu(SField c, SConst b, I3 e, I3 og, int g, double bx, double by,
216 double bz, double Ac, int color, SConst dcorr, bool aniso) {
217 return aniso ? diffSmoothColorDuT<true>(c, b, e, og, g, bx, by, bz, Ac, color, dcorr)
218 : diffSmoothColorDuT<false>(c, b, e, og, g, bx, by, bz, Ac, color, dcorr);
219}
220
221// Isotropic spelling (the legacy signature).
222inline double diffSmoothColorDu(SField c, SConst b, I3 e, I3 og, int g, double beta, double Ac,
223 int color, SConst dcorr) {
224 return diffSmoothColorDuT<false>(c, b, e, og, g, beta, beta, beta, Ac, color, dcorr);
225}
226
227// One Red-Black sweep colour of the (unit-coefficient) Poisson smoother: phi[i] = (sum - d[i]) / 6.
228inline void poisSmoothColor(SField phi, SConst d, I3 e, I3 og, int g, int color) {
229 SExec space;
230 using MD = MDRange3<SExec>;
231 Kokkos::parallel_for(
232 "peclet::flow::pois", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
233 KOKKOS_LAMBDA(int x, int y, int z) {
234 if ((((x + og.x) + (y + og.y) + (z + og.z)) & 1) != color)
235 return;
236 const long i = L3(x, y, z, e), sx = 1, sy = e.x, sz = static_cast<long>(e.x) * e.y;
237 const double s =
238 phi(i + sx) + phi(i - sx) + phi(i + sy) + phi(i - sy) + phi(i + sz) + phi(i - sz);
239 phi(i) = (s - d(i)) / 6.0;
240 });
241}
242
243// MAC divergence d[i] = (u[i+sx]-u[i]) + (v[i+sy]-v[i]) + (w[i+sz]-w[i]) over inner cells.
244inline void divergence(SConst u, SConst v, SConst w, SField d, I3 e, int g) {
245 SExec space;
246 using MD = MDRange3<SExec>;
247 Kokkos::parallel_for(
248 "peclet::flow::diverg", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
249 KOKKOS_LAMBDA(int x, int y, int z) {
250 const long i = L3(x, y, z, e), sx = 1, sy = e.x, sz = static_cast<long>(e.x) * e.y;
251 d(i) = (u(i + sx) - u(i)) + (v(i + sy) - v(i)) + (w(i + sz) - w(i));
252 });
253}
254
255// Full Red-Black Gauss-Seidel sweep (both colours) of the Poisson smoother.
256inline void poisSweep(SField phi, SConst d, I3 e, I3 og, int g) {
257 poisSmoothColor(phi, d, e, og, g, 0);
258 poisSmoothColor(phi, d, e, og, g, 1);
259}
260
261} // namespace peclet::flow
262
263#endif // PECLET_FLOW_MAC_STENCILS_HPP
void diffResidualT(SField r, SConst c, SConst b, I3 e, int g, double bx, double by, double bz, double Ac, SConst dcorr)
long L3(int x, int y, int z, I3 e)
void divergence(SConst u, SConst v, SConst w, SField d, I3 e, int g)
void diffSmoothColorT(SField c, SConst b, I3 e, I3 og, int g, double bx, double by, double bz, double Ac, int color, SConst dcorr)
double diffSmoothColorDu(SField c, SConst b, I3 e, I3 og, int g, double bx, double by, double bz, double Ac, int color, SConst dcorr, bool aniso)
double diffSmoothColorDuT(SField c, SConst b, I3 e, I3 og, int g, double bx, double by, double bz, double Ac, int color, SConst dcorr)
void diffResidual(SField r, SConst c, SConst b, I3 e, int g, double bx, double by, double bz, double Ac, SConst dcorr, bool aniso)
Kokkos::View< const double *, SMem > SConst
void poisSmoothColor(SField phi, SConst d, I3 e, I3 og, int g, int color)
SExec::memory_space SMem
Kokkos::DefaultExecutionSpace SExec
void diffSmoothColor(SField c, SConst b, I3 e, I3 og, int g, double bx, double by, double bz, double Ac, int color, SConst dcorr, bool aniso)
Kokkos::View< double *, SMem > SField
void poisSweep(SField phi, SConst d, I3 e, I3 og, int g)
flow — the multidimensional iteration policies: iteration order follows storage.