flow 1.3.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
flow_reference.hpp
Go to the documentation of this file.
1
10#ifndef PECLET_FLOW_SDFLOW_HPP
11#define PECLET_FLOW_SDFLOW_HPP
12
13#include <Kokkos_Core.hpp>
14
15#include "mac_cutcell.hpp" // ccFor3 (rule H)
16#include "mac_mg.hpp"
17#include "mac_reductions.hpp"
18#include "mac_stencils.hpp"
19#include "mac_transfer.hpp"
20#include "policy.hpp"
22
23namespace peclet::flow {
24
26 public:
27 using F = Kokkos::View<double*, SMem>;
28 static constexpr int G = 2;
29
30 FlowReference(int n, double nu, double dt) : N_(n), nu_(nu), dt_(dt), mg_(n) {
31 e_ = I3{N_ + 2 * G, N_ + 2 * G, N_ + 2 * G};
32 ne_ = (std::size_t)e_.x * e_.y * e_.z;
33 u_ = F("u", ne_);
34 v_ = F("v", ne_);
35 w_ = F("w", ne_);
36 us_ = F("us", ne_);
37 vs_ = F("vs", ne_);
38 ws_ = F("ws", ne_);
39 bu_ = F("bu", ne_);
40 bv_ = F("bv", ne_);
41 bw_ = F("bw", ne_);
42 phi_ = F("phi", ne_);
43 div_ = F("div", ne_);
44 // g=1 scratch for the multigrid level-0 (MG uses ghost width 1; the solver uses 2).
45 eMg_ = I3{N_ + 2, N_ + 2, N_ + 2};
46 const std::size_t nm = (std::size_t)eMg_.x * eMg_.y * eMg_.z;
47 dMg_ = F("dMg", nm);
48 phiMg_ = F("phiMg", nm);
49 }
50
51 F& u() { return u_; }
52 F& v() { return v_; }
53 F& w() { return w_; }
54 int N() const { return N_; }
55 I3 ext() const { return e_; }
56 void setBodyForce(double fx, double fy, double fz) {
57 fx_ = fx;
58 fy_ = fy;
59 fz_ = fz;
60 }
61 void setAdvection(bool on) { advect_ = on; }
62 void setIterations(int nDiff, int nPois) {
63 nDiff_ = nDiff;
64 nPois_ = nPois;
65 }
66 // Pressure solver: multigrid V-cycles (default) or plain RB-GS (useMg=false).
68 useMg_ = useMg;
69 nVcycles_ = nVcycles;
70 }
71
72 void step() {
73 const I3 og{0, 0, 0};
74 periodicFill(u_);
75 periodicFill(v_);
76 periodicFill(w_);
77 buildRhs(); // bu/bv/bw = idiag*u + f - advect
78 // implicit diffusion (RB-GS) per component, starting guess = current field
79 Kokkos::deep_copy(us_, u_);
80 Kokkos::deep_copy(vs_, v_);
81 Kokkos::deep_copy(ws_, w_);
82 const double Ac = idiag() + 6.0 * nu_;
83 for (int it = 0; it < nDiff_; ++it) {
84 diffuseComp(us_, bu_, Ac);
85 diffuseComp(vs_, bv_, Ac);
86 diffuseComp(ws_, bw_, Ac);
87 }
88 // projection: Lap(phi) = div(u*); u = u* - grad(phi)
89 periodicFill(us_);
90 periodicFill(vs_);
91 periodicFill(ws_);
92 divergence(SConst(us_), SConst(vs_), SConst(ws_), div_, e_, G);
93 Kokkos::deep_copy(phi_, 0.0);
94 if (useMg_) { // geometric multigrid V-cycles (fast); bridge g=2 <-> g=1 by inner-cell copy
95 copyInner(dMg_, eMg_, 1, SConst(div_), e_, G);
96 Kokkos::deep_copy(phiMg_, 0.0);
97 mg_.solve(phiMg_, SConst(dMg_), nVcycles_);
98 copyInner(phi_, e_, G, SConst(phiMg_), eMg_, 1);
99 } else { // plain RB-GS (slow; kept for comparison)
100 for (int it = 0; it < nPois_; ++it) {
101 periodicFill(phi_);
102 poisSweep(phi_, SConst(div_), e_, og, G);
103 removeMean(phi_);
104 }
105 }
106 periodicFill(phi_);
107 correct(us_, vs_, ws_, SConst(phi_), T3{e_.x, e_.y, e_.z}, G);
108 Kokkos::deep_copy(u_, us_);
109 Kokkos::deep_copy(v_, vs_);
110 Kokkos::deep_copy(w_, ws_);
111 }
112
113 // L2 over inner cells of a component (for diagnostics / validation).
114 double l2(F f) {
116 return std::sqrt(s.sum);
117 }
118
119 // max|div(u)| over inner cells (projection quality).
120 double maxDivU() {
121 periodicFill(u_);
122 periodicFill(v_);
123 periodicFill(w_);
124 divergence(SConst(u_), SConst(v_), SConst(w_), div_, e_, G);
125 return reduceInner(SConst(div_), false).maxabs;
126 }
127
128 // (public: nvcc forbids extended __host__ __device__ lambdas inside private/protected members.)
129 double idiag() const { return 1.0 / dt_; }
130
131 // Copy the N^3 inner cells between two extended blocks of different ghost width.
132 // rule H (§4.5; §14 H-3a): ccFor3 -- host pencil, device MDRange, no per-cell div/mod.
133 void copyInner(F dst, I3 de, int dg, SConst src, I3 se, int sg) {
134 const int N = N_;
135 ccFor3(
136 "peclet::flow::copyInner", C3{0, 0, 0}, C3{N, N, N}, KOKKOS_LAMBDA(int ix, int iy, int iz) {
137 const long di =
138 (long)(ix + dg) + (long)(iy + dg) * de.x + (long)(iz + dg) * (long)de.x * de.y;
139 const long si =
140 (long)(ix + sg) + (long)(iy + sg) * se.x + (long)(iz + sg) * (long)se.x * se.y;
141 dst(di) = src(si);
142 });
143 }
144
145 void diffuseComp(F x, F b, double Ac) {
146 periodicFill(x);
147 diffSmoothColor(x, SConst(b), e_, I3{0, 0, 0}, G, nu_, Ac, 0, SConst());
148 periodicFill(x);
149 diffSmoothColor(x, SConst(b), e_, I3{0, 0, 0}, G, nu_, Ac, 1, SConst());
150 }
151
152 void buildRhs() {
153 SExec space;
154 const double id = idiag();
155 const bool adv = advect_;
156 const double fx = fx_, fy = fy_, fz = fz_;
157 const I3 e = e_;
158 F u = u_, v = v_, w = w_, bu = bu_, bv = bv_, bw = bw_;
159 using MD = MDRange3<SExec>;
160 Kokkos::parallel_for(
161 "peclet::flow::sdflow_rhs", MD(space, {G, G, G}, {e.x - G, e.y - G, e.z - G}),
162 KOKKOS_LAMBDA(int x, int y, int z) {
163 const long i = (long)x + (long)y * e.x + (long)z * (long)e.x * e.y;
164 double au = 0, av = 0, aw = 0;
165 if (adv) {
166 sadv::ViewAcc U{SConst(u), e.x, e.y}, V{SConst(v), e.x, e.y}, W{SConst(w), e.x, e.y};
167 au = sadv::advect(0, x, y, z, U, V, W, U);
168 av = sadv::advect(1, x, y, z, U, V, W, V);
169 aw = sadv::advect(2, x, y, z, U, V, W, W);
170 }
171 bu(i) = id * u(i) + fx - au;
172 bv(i) = id * v(i) + fy - av;
173 bw(i) = id * w(i) + fz - aw;
174 });
175 }
176
177 void removeMean(F f) {
178 SumMax s = localSumMax(SConst(f));
179 const double mean = s.sum / ((double)N_ * N_ * N_);
180 SExec space;
181 const I3 e = e_;
182 Kokkos::parallel_for(
183 "peclet::flow::submean", Kokkos::RangePolicy<SExec>(space, 0, ne_),
184 KOKKOS_LAMBDA(std::size_t i) { f(i) -= mean; });
185 }
186
187 // sum + max|.| over inner cells (reuse mac_reductions math inline for the periodic block).
188 SumMax localSumMax(SConst f) { return reduceInner(f, false); }
189 SumMax localSumMaxSq(SConst f) { return reduceInner(f, true); }
191 SExec space;
192 const I3 e = e_;
193 const int N = N_;
194 SumMax r;
195 Kokkos::parallel_reduce(
196 "peclet::flow::sdflow_reduce", Kokkos::RangePolicy<SExec>(space, 0, (long)N * N * N),
197 KOKKOS_LAMBDA(long c, SumMax& acc) {
198 const int ix = (int)(c % N), iy = (int)((c / N) % N), iz = (int)(c / ((long)N * N));
199 const long i = (long)(ix + G) + (long)(iy + G) * e.x + (long)(iz + G) * (long)e.x * e.y;
200 const double val = f(i);
201 acc.sum += sq ? val * val : val;
202 const double a = Kokkos::fabs(val);
203 if (a > acc.maxabs)
204 acc.maxabs = a;
205 },
206 r);
207 return r;
208 }
209
210 // Fill ghost width G periodically on all 3 axes (x then y then z, covering corners).
211 void periodicFill(F f) {
212 fillAxis(f, 0);
213 fillAxis(f, 1);
214 fillAxis(f, 2);
215 }
216 void fillAxis(F f, int axis) {
217 SExec space;
218 const I3 e = e_;
219 const int N = N_;
220 int dims[3] = {e.x, e.y, e.z};
221 long st[3] = {1, e.x, (long)e.x * e.y};
222 const int a = axis, b = (axis + 1) % 3, c = (axis + 2) % 3;
223 const long sa = st[a], sb = st[b], sc = st[c];
224 F ff = f;
225 using MD = MDRange2<SExec>;
226 // copy the two ghost slabs from the wrapped inner planes; over the FULL perp extent so corners
227 // fill.
228 Kokkos::parallel_for(
229 "peclet::flow::pfill", MD(space, {0, 0}, {dims[b], dims[c]}),
230 KOKKOS_LAMBDA(int p0, int p1) {
231 const long base = (long)p0 * sb + (long)p1 * sc;
232 for (int gl = 0; gl < G; ++gl) {
233 // low ghost gl <- inner plane (gl + N) ; high ghost (G+N+gl) <- inner plane (G+gl)
234 ff(base + (long)gl * sa) = ff(base + (long)(gl + N) * sa);
235 ff(base + (long)(G + N + gl) * sa) = ff(base + (long)(G + gl) * sa);
236 }
237 });
238 }
239
240 private:
241 int N_;
242 double nu_, dt_;
243 I3 e_;
244 std::size_t ne_;
245 F u_, v_, w_, us_, vs_, ws_, bu_, bv_, bw_, phi_, div_;
246 MgPoisson mg_;
247 I3 eMg_;
248 F dMg_, phiMg_;
249 double fx_ = 0, fy_ = 0, fz_ = 0;
250 bool advect_ = true, useMg_ = true;
251 int nDiff_ = 20, nPois_ = 50, nVcycles_ = 8;
252};
253
254} // namespace peclet::flow
255
256#endif // PECLET_FLOW_SDFLOW_HPP
FlowReference(int n, double nu, double dt)
void diffuseComp(F x, F b, double Ac)
Kokkos::View< double *, SMem > F
void copyInner(F dst, I3 de, int dg, SConst src, I3 se, int sg)
void setPressureMultigrid(bool useMg, int nVcycles)
void setBodyForce(double fx, double fy, double fz)
void setIterations(int nDiff, int nPois)
SumMax reduceInner(SConst f, bool sq)
void solve(SField phi, SConst d, int nVcycles, int nu1=2, int nu2=2)
Definition mac_mg.hpp:69
flow — portable (Kokkos) cut-cell pressure-operator face openness from an SDF.
flow — portable (Kokkos) geometric multigrid V-cycle for the periodic pressure Poisson.
flow — portable (Kokkos) global reductions over a MAC grid's inner (owned) cells.
flow — portable (Kokkos) MAC stencil operators: Red-Black Gauss-Seidel smoothers + divergence.
flow — portable (Kokkos) multigrid transfer operators + projection velocity correction.
void divergence(SConst u, SConst v, SConst w, SField d, I3 e, int g)
void correct(TField u, TField v, TField w, TConst phi, T3 e, int g)
void ccFor3(const char *name, C3 lo, C3 hi, F f)
Kokkos::View< const double *, SMem > SConst
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)
void poisSweep(SField phi, SConst d, I3 e, I3 og, int g)
double advect(int comp, int x, int y, int z, A U, A V, A W, A PHI)
flow — the multidimensional iteration policies: iteration order follows storage.
flow — portable (Kokkos) staggered MAC momentum advection (Koren TVD + FOU).
{sum, max|.|} reduction value.
static constexpr double U
static double mean(const std::vector< double > &a)