flow
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_mg.hpp"
16#include "mac_reductions.hpp"
17#include "mac_stencils.hpp"
18#include "mac_transfer.hpp"
20
21namespace peclet::flow {
22
24 public:
25 using F = Kokkos::View<double*, SMem>;
26 static constexpr int G = 2;
27
28 FlowReference(int n, double nu, double dt) : N_(n), nu_(nu), dt_(dt), mg_(n) {
29 e_ = I3{N_ + 2 * G, N_ + 2 * G, N_ + 2 * G};
30 ne_ = (std::size_t)e_.x * e_.y * e_.z;
31 u_ = F("u", ne_);
32 v_ = F("v", ne_);
33 w_ = F("w", ne_);
34 us_ = F("us", ne_);
35 vs_ = F("vs", ne_);
36 ws_ = F("ws", ne_);
37 bu_ = F("bu", ne_);
38 bv_ = F("bv", ne_);
39 bw_ = F("bw", ne_);
40 phi_ = F("phi", ne_);
41 div_ = F("div", ne_);
42 // g=1 scratch for the multigrid level-0 (MG uses ghost width 1; the solver uses 2).
43 eMg_ = I3{N_ + 2, N_ + 2, N_ + 2};
44 const std::size_t nm = (std::size_t)eMg_.x * eMg_.y * eMg_.z;
45 dMg_ = F("dMg", nm);
46 phiMg_ = F("phiMg", nm);
47 }
48
49 F& u() { return u_; }
50 F& v() { return v_; }
51 F& w() { return w_; }
52 int N() const { return N_; }
53 I3 ext() const { return e_; }
54 void setBodyForce(double fx, double fy, double fz) {
55 fx_ = fx;
56 fy_ = fy;
57 fz_ = fz;
58 }
59 void setAdvection(bool on) { advect_ = on; }
60 void setIterations(int nDiff, int nPois) {
61 nDiff_ = nDiff;
62 nPois_ = nPois;
63 }
64 // Pressure solver: multigrid V-cycles (default) or plain RB-GS (useMg=false).
65 void setPressureMultigrid(bool useMg, int nVcycles) {
66 useMg_ = useMg;
67 nVcycles_ = nVcycles;
68 }
69
70 void step() {
71 const I3 og{0, 0, 0};
72 periodicFill(u_);
73 periodicFill(v_);
74 periodicFill(w_);
75 buildRhs(); // bu/bv/bw = idiag*u + f - advect
76 // implicit diffusion (RB-GS) per component, starting guess = current field
77 Kokkos::deep_copy(us_, u_);
78 Kokkos::deep_copy(vs_, v_);
79 Kokkos::deep_copy(ws_, w_);
80 const double Ac = idiag() + 6.0 * nu_;
81 for (int it = 0; it < nDiff_; ++it) {
82 diffuseComp(us_, bu_, Ac);
83 diffuseComp(vs_, bv_, Ac);
84 diffuseComp(ws_, bw_, Ac);
85 }
86 // projection: Lap(phi) = div(u*); u = u* - grad(phi)
87 periodicFill(us_);
88 periodicFill(vs_);
89 periodicFill(ws_);
90 divergence(SConst(us_), SConst(vs_), SConst(ws_), div_, e_, G);
91 Kokkos::deep_copy(phi_, 0.0);
92 if (useMg_) { // geometric multigrid V-cycles (fast); bridge g=2 <-> g=1 by inner-cell copy
93 copyInner(dMg_, eMg_, 1, SConst(div_), e_, G);
94 Kokkos::deep_copy(phiMg_, 0.0);
95 mg_.solve(phiMg_, SConst(dMg_), nVcycles_);
96 copyInner(phi_, e_, G, SConst(phiMg_), eMg_, 1);
97 } else { // plain RB-GS (slow; kept for comparison)
98 for (int it = 0; it < nPois_; ++it) {
99 periodicFill(phi_);
100 poisSweep(phi_, SConst(div_), e_, og, G);
101 removeMean(phi_);
102 }
103 }
104 periodicFill(phi_);
105 correct(us_, vs_, ws_, SConst(phi_), T3{e_.x, e_.y, e_.z}, G);
106 Kokkos::deep_copy(u_, us_);
107 Kokkos::deep_copy(v_, vs_);
108 Kokkos::deep_copy(w_, ws_);
109 }
110
111 // L2 over inner cells of a component (for diagnostics / validation).
112 double l2(F f) {
114 return std::sqrt(s.sum);
115 }
116
117 // max|div(u)| over inner cells (projection quality).
118 double maxDivU() {
119 periodicFill(u_);
120 periodicFill(v_);
121 periodicFill(w_);
122 divergence(SConst(u_), SConst(v_), SConst(w_), div_, e_, G);
123 return reduceInner(SConst(div_), false).maxabs;
124 }
125
126 // (public: nvcc forbids extended __host__ __device__ lambdas inside private/protected members.)
127 double idiag() const { return 1.0 / dt_; }
128
129 // Copy the N^3 inner cells between two extended blocks of different ghost width.
130 void copyInner(F dst, I3 de, int dg, SConst src, I3 se, int sg) {
131 SExec space;
132 const int N = N_;
133 Kokkos::parallel_for(
134 "peclet::flow::copyInner", Kokkos::RangePolicy<SExec>(space, 0, (long)N * N * N),
135 KOKKOS_LAMBDA(long c) {
136 const int ix = (int)(c % N), iy = (int)((c / N) % N), iz = (int)(c / ((long)N * N));
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 = Kokkos::MDRangePolicy<SExec, Kokkos::Rank<3>>;
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 = Kokkos::MDRangePolicy<SExec, Kokkos::Rank<2>>;
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:68
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 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
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 — portable (Kokkos) staggered MAC momentum advection (Koren TVD + FOU).
{sum, max|.|} reduction value.