peclet.voro 1.0.4
Device-native moving-particle Voronoi dynamics
Loading...
Searching...
No Matches
collocated.hpp
Go to the documentation of this file.
1
28#ifndef PECLET_VORO_FV_COLLOCATED_HPP
29#define PECLET_VORO_FV_COLLOCATED_HPP
30
31#include <functional>
32#include <Kokkos_Core.hpp>
33
37
39
40template <class Real>
42 using Exec = peclet::core::ExecSpace;
44 Real nu = 0;
45 Real convScale = 1; // 0 = Stokes (diagnostic)
46 bool incremental = true; // flow's incremental_: false = classical Chorin (φ = the pressure)
47 bool skewCorrected = true; // centroid-consistent constraint pair (see the header); MEASURED
48 // TGV order 2.10 / 2.08 on jittered / CVT meshes vs 1.72 / 1.17 plain
49 DV<Real> U, uf, p, force; // 3N, nFaces, N, 3N (optional)
50 DV<Real> Uwall, ub; // 3 × nBoundary wall velocity, nBoundary wall flux (C3)
51 bool wallQuadratic = true; // second-order wall gradient (wallGradientLS) vs two-point
52 DV<Real> wg; // 3 × nBoundary wall gradient
53 // Distributed hooks (rung C5, see fv/distributed.hpp): ghost refresh of a cell field and the
54 // global sum / max. Unset = single rank.
55 std::function<void(const DV<Real>&, int)> exchange;
56 std::function<Real(Real)> sum, max;
57 // Implicit diffusion (flow's step structure): explicit convection, backward-Euler viscous solve
58 // per component with the two-point Laplacian and the two-point wall term implicit and the
59 // quadratic wall-gradient correction lagged (deferred correction keeps the matrix SPD), then the
60 // approximate projection. First order in time, no diffusive Δt limit (Stokes: Δt free).
61 bool implicitDiffusion = false;
63 true; // P += φ − ν div u* (Timmermans; flow's rotationalP_) with the implicit step
65 Real viscDt = -1;
67 DV<Real> a, U1, U2, uf1, uf2, div, gphi, gp, phi, g9; // workspace
68
69 void setup(const FaceMesh<Real>& mesh, Real viscosity, bool amg = false) {
70 m = mesh;
71 nu = viscosity;
72 const int N = m.nCells, F = m.nFaces, NC = m.nCombined > 0 ? m.nCombined : N;
73 U = DV<Real>("co.U", 3 * NC);
74 uf = DV<Real>("co.uf", F);
75 p = DV<Real>("co.p", NC);
76 a = DV<Real>("co.a", 3 * N);
77 U1 = DV<Real>("co.U1", 3 * NC);
78 U2 = DV<Real>("co.U2", 3 * NC);
79 uf1 = DV<Real>("co.uf1", F);
80 uf2 = DV<Real>("co.uf2", F);
81 div = DV<Real>("co.div", N);
82 gphi = DV<Real>("co.gphi", F);
83 gp = DV<Real>("co.gp", 3 * N);
84 phi = DV<Real>("co.phi", NC);
85 g9 = DV<Real>("co.g9", 9 * NC);
87 poisson.setup(m, amg);
88 }
90 template <class Ex>
91 void setExchange(Ex& ex) {
92 exchange = [&ex](const DV<Real>& f, int nc) { ex.exchange(f, nc); };
93 sum = [&ex](Real v) { return ex.sum(v); };
94 max = [&ex](Real v) { return ex.max(v); };
95 poisson.setHooks(exchange, sum);
96 }
99 void setWallVelocity(const DV<Real>& Uw) {
100 const int nB = m.nFaces - m.nInterior, nI = m.nInterior;
101 Uwall = Uw;
102 ub = DV<Real>("fv.ub", nB);
103 if (Uw.extent(0) == 0)
104 return;
105 const FaceMesh<Real> mm = m;
106 const DV<Real> bb = ub;
107 Kokkos::parallel_for(
108 "fv.ub", Kokkos::RangePolicy<Exec>(0, nB), KOKKOS_LAMBDA(const int b) {
109 Real un = 0;
110 for (int c = 0; c < 3; ++c)
111 un += Uw(3 * b + c) * mm.normal(nI + b, c);
112 bb(b) = un;
113 });
114 }
116 void applyWallFlux(const DV<Real>& uf) const {
117 const int nB = m.nFaces - m.nInterior, nI = m.nInterior;
118 const DV<Real> bb = ub;
119 Kokkos::parallel_for(
120 "fv.wall", Kokkos::RangePolicy<Exec>(0, nB),
121 KOKKOS_LAMBDA(const int b) { uf(nI + b) = bb(b); });
122 }
124
126 void toFaces(const DV<Real>& Uc, const DV<Real>& out) {
127 if (skewCorrected) {
128 vectorGreenGauss(m, Uc, g9, Uwall);
129 if (exchange)
130 exchange(g9, 9);
131 projectToFaces(m, Uc, out, g9, ub);
132 } else {
133 projectToFaces(m, Uc, out, DV<Real>{}, ub);
134 }
135 }
137 void cellGrad(const DV<Real>& q, const DV<Real>& out) {
138 faceGradient(m, q, gphi);
139 faceInterpTranspose(m, gphi, out, skewCorrected, g9, Uwall.extent(0) > 0, exchange);
140 }
142 void tendency(const DV<Real>& Uin, const DV<Real>& ufin, const DV<Real>& out) {
143 if (wallQuadratic && m.nFaces > m.nInterior) {
144 if (wg.extent(0) == 0)
145 wg = DV<Real>("co.wg", 3 * (m.nFaces - m.nInterior));
146 vectorGreenGauss(m, Uin, g9, Uwall);
147 wallGradientLS(m, Uin, g9, Uwall, wg);
148 cellTendency(m, ufin, Uin, nu, out, force, convScale, Uwall, wg);
149 } else {
150 cellTendency(m, ufin, Uin, nu, out, force, convScale, Uwall);
151 }
152 if (!incremental)
153 return;
154 const DV<Real> gc = gp;
155 cellGrad(p, gc);
156 Kokkos::parallel_for(
157 "co.gradp", Kokkos::RangePolicy<Exec>(0, 3 * m.nCells),
158 KOKKOS_LAMBDA(const int i) { out(i) -= gc(i); });
159 }
162 void project(const DV<Real>& Ustar, const DV<Real>& ufOut, Real dt,
163 const DV<Real>& divOut = DV<Real>{}) {
164 const DV<Real> dv = div, g = gphi, gc = gp, ph = phi, pp = p;
165 if (exchange)
166 exchange(Ustar, 3); // the predictor's ghosts (interface faces read both cells)
167 toFaces(Ustar, ufOut);
168 divergence(m, ufOut, dv);
169 if (divOut.extent(0) > 0)
170 Kokkos::deep_copy(divOut, dv); // div u* for the rotational pressure update
171 const Real s = -Real(1) / dt;
172 Kokkos::parallel_for(
173 "co.rhsP", Kokkos::RangePolicy<Exec>(0, m.nCells),
174 KOKKOS_LAMBDA(const int i) { dv(i) *= s; });
175 poisson.solve(dv, ph);
176 faceGradient(m, ph, g);
177 Kokkos::parallel_for(
178 "co.corrF", Kokkos::RangePolicy<Exec>(0, m.nFaces),
179 KOKKOS_LAMBDA(const int f) { ufOut(f) -= dt * g(f); });
180 cellGrad(ph, gc);
181 Kokkos::parallel_for(
182 "co.corrC", Kokkos::RangePolicy<Exec>(0, 3 * m.nCells),
183 KOKKOS_LAMBDA(const int i) { Ustar(i) -= dt * gc(i); });
184 if (incremental)
185 Kokkos::parallel_for(
186 "co.pinc", Kokkos::RangePolicy<Exec>(0, m.nCells),
187 KOKKOS_LAMBDA(const int i) { pp(i) += ph(i); });
188 else
189 Kokkos::deep_copy(pp, ph);
190 if (exchange) {
191 exchange(Ustar, 3); // corrected cells (the next tendency's neighbours)
192 exchange(pp, 1); // the incremental predictor's −∇P
193 }
194 }
196 void initialize(const DV<Real>& Uin) {
197 Kokkos::deep_copy(U, Uin);
198 Kokkos::deep_copy(p, Real(0));
199 project(U, uf, Real(1));
200 Kokkos::deep_copy(p, Real(0));
201 }
202 void step(Real dt) {
204 stepImplicit(dt);
205 else
206 stepRK3(dt);
207 }
211 void stepImplicit(Real dt) {
212 const int N = m.nCells, NC = m.nCombined > 0 ? m.nCombined : N;
213 if (viscDt != dt) {
214 visc.setupVelocity(m, nu, dt, poisson.useAmg);
215 visc.tol = poisson.tol;
216 if (exchange)
217 visc.setHooks(exchange, sum);
218 viscDt = dt;
219 if (rhs3.extent(0) == 0) {
220 rhs3 = DV<Real>("co.rhs3", 3 * N);
221 uc = DV<Real>("co.uc", NC);
222 wcorr = DV<Real>("co.wcorr", 3 * N);
223 aT = DV<Real>("co.aT", 3 * N);
224 divStar = DV<Real>("co.divStar", N);
225 }
226 }
227 const DV<Real> UU = U, aa = a, R3 = rhs3, WC = wcorr, AT = aT, UC = uc, gc = gp;
228 const FaceMesh<Real> mm = m;
229 const Real nuL = nu;
230 const bool hasWall = m.nFaces > m.nInterior;
231 // explicit part: convection + force (nu = 0) − G Pⁿ
232 cellTendency(m, uf, UU, Real(0), aa, force, convScale, Uwall);
233 if (incremental) {
234 cellGrad(p, gc);
235 Kokkos::parallel_for(
236 "co.igradp", Kokkos::RangePolicy<Exec>(0, 3 * N),
237 KOKKOS_LAMBDA(const int i) { aa(i) -= gc(i); });
238 }
239 // lagged wall correction: quadratic − two-point viscous wall term at Uⁿ (interior cancels)
240 if (hasWall && wallQuadratic) {
241 if (wg.extent(0) == 0)
242 wg = DV<Real>("co.wg", 3 * (m.nFaces - m.nInterior));
243 vectorGreenGauss(m, UU, g9, Uwall);
244 wallGradientLS(m, UU, g9, Uwall, wg);
245 const DV<Real> zero("co.zero", m.nFaces);
246 cellTendency(m, zero, UU, nuL, WC, DV<Real>{}, Real(0), Uwall, wg);
247 cellTendency(m, zero, UU, nuL, AT, DV<Real>{}, Real(0), Uwall);
248 Kokkos::parallel_for(
249 "co.wcorr", Kokkos::RangePolicy<Exec>(0, 3 * N),
250 KOKKOS_LAMBDA(const int i) { aa(i) += WC(i) - AT(i); });
251 }
252 // right-hand side: V(U/Δt + a) + ν Σ_wall (A/h_A) U_wall
253 const DV<Real> Uw = Uwall;
254 const bool hasW = Uw.extent(0) > 0;
255 const int nI = m.nInterior;
256 Kokkos::parallel_for(
257 "co.rhs", Kokkos::RangePolicy<Exec>(0, N), KOKKOS_LAMBDA(const int i) {
258 const Real V = mm.cellVolume(i);
259 Real wall[3] = {0, 0, 0};
260 if (hasW)
261 for (int t = mm.cellFacesBegin(i); t < mm.cellFacesEnd(i); ++t) {
262 const int f = mm.cellFace(t);
263 if (f >= nI) {
264 const Real w = nuL * mm.faceArea(f) / mm.faceHa(f);
265 for (int c = 0; c < 3; ++c)
266 wall[c] += w * Uw(3 * (f - nI) + c);
267 }
268 }
269 for (int c = 0; c < 3; ++c)
270 R3(3 * i + c) = V * (UU(3 * i + c) / dt + aa(3 * i + c)) + wall[c];
271 });
272 // three scalar solves; the previous velocity component is the initial guess's replacement
273 // (PressureSolver starts from zero — fine for CG)
274 for (int c = 0; c < 3; ++c) {
275 const DV<Real> rc("co.rc", N);
276 Kokkos::parallel_for(
277 "co.gather", Kokkos::RangePolicy<Exec>(0, N),
278 KOKKOS_LAMBDA(const int i) { rc(i) = R3(3 * i + c); });
279 visc.solve(rc, UC);
280 Kokkos::parallel_for(
281 "co.scatter", Kokkos::RangePolicy<Exec>(0, N),
282 KOKKOS_LAMBDA(const int i) { UU(3 * i + c) = UC(i); });
283 }
284 // approximate projection (exchanges the predictor's ghosts itself)
285 const DV<Real> dS = divStar;
286 project(UU, uf, dt, rotational ? dS : DV<Real>{});
287 if (rotational && incremental) {
288 const DV<Real> pp = p;
289 Kokkos::parallel_for(
290 "co.rot", Kokkos::RangePolicy<Exec>(0, N),
291 KOKKOS_LAMBDA(const int i) { pp(i) -= nuL * dS(i); });
292 if (exchange)
293 exchange(pp, 1);
294 }
295 }
297 void stepRK3(Real dt) {
298 const int N3 = 3 * m.nCells;
299 const DV<Real> UU = U, aa = a, V1 = U1, V2 = U2;
300 tendency(UU, uf, aa);
301 Kokkos::parallel_for(
302 "co.s1", Kokkos::RangePolicy<Exec>(0, N3),
303 KOKKOS_LAMBDA(const int i) { V1(i) = UU(i) + dt * aa(i); });
304 project(V1, uf1, dt);
305 tendency(V1, uf1, aa);
306 Kokkos::parallel_for(
307 "co.s2", Kokkos::RangePolicy<Exec>(0, N3), KOKKOS_LAMBDA(const int i) {
308 V2(i) = Real(0.75) * UU(i) + Real(0.25) * (V1(i) + dt * aa(i));
309 });
310 project(V2, uf2, Real(0.25) * dt);
311 tendency(V2, uf2, aa);
312 Kokkos::parallel_for(
313 "co.s3", Kokkos::RangePolicy<Exec>(0, N3),
314 KOKKOS_LAMBDA(const int i) { UU(i) = (UU(i) + Real(2) * (V2(i) + dt * aa(i))) / Real(3); });
315 project(UU, uf, Real(2) / Real(3) * dt);
316 }
318 Real kineticEnergy() const {
319 const FaceMesh<Real> mm = m;
320 const DV<Real> UU = U;
321 Real e = 0;
322 Kokkos::parallel_reduce(
323 "co.ke", Kokkos::RangePolicy<Exec>(0, m.nCells),
324 KOKKOS_LAMBDA(const int i, Real& acc) {
325 acc += mm.cellVolume(i) * (UU(3 * i) * UU(3 * i) + UU(3 * i + 1) * UU(3 * i + 1) +
326 UU(3 * i + 2) * UU(3 * i + 2));
327 },
328 e);
329 if (sum)
330 e = sum(e);
331 return Real(0.5) * e;
332 }
334 Real maxFaceDivergence() { return maxDivOf(uf); }
337 toFaces(U, uf1);
338 return maxDivOf(uf1);
339 }
340 Real maxDivOf(const DV<Real>& flux) {
341 const DV<Real> dv = div;
342 divergence(m, flux, dv);
343 Real mx = 0;
344 Kokkos::parallel_reduce(
345 "co.maxdiv", Kokkos::RangePolicy<Exec>(0, m.nCells),
346 KOKKOS_LAMBDA(const int i, Real& acc) {
347 const Real v = Kokkos::fabs(dv(i));
348 if (v > acc)
349 acc = v;
350 },
351 Kokkos::Max<Real>(mx));
352 return max ? max(mx) : mx;
353 }
354};
355
356} // namespace peclet::voro::fv
357
358#endif // PECLET_VORO_FV_COLLOCATED_HPP
Track C, rung C2a (Voronoi methods plan, verdict V4): the staggered COVOLUME Navier–Stokes solver on ...
Track C, rung C1 (Voronoi methods plan): the FACE mesh of a published tessellation — one record per g...
Definition collocated.hpp:38
void vectorGreenGauss(const FaceMesh< Real > &m, const DV< Real > &U, const DV< Real > &out, const DV< Real > &Uwall=DV< Real >{})
Definition operators.hpp:161
void faceInterpTranspose(const FaceMesh< Real > &m, const DV< Real > &g, const DV< Real > &out, bool skew=false, const DV< Real > &scratch9=DV< Real >{}, bool wallPrescribed=false, const std::function< void(const DV< Real > &, int)> &exchange={})
Definition operators.hpp:272
void cellTendency(const FaceMesh< Real > &m, const DV< Real > &u, const DV< Real > &U, Real nu, const DV< Real > &out, const DV< Real > &force=DV< Real >{}, Real convScale=Real(1), const DV< Real > &Uwall=DV< Real >{}, const DV< Real > &wallGrad=DV< Real >{})
Definition covolume.hpp:70
void projectToFaces(const FaceMesh< Real > &m, const DV< Real > &ucell, const DV< Real > &out, const DV< Real > &gradU=DV< Real >{}, const DV< Real > &ub=DV< Real >{})
Definition operators.hpp:206
Kokkos::View< Real *, peclet::core::MemSpace > DV
Definition operators.hpp:26
void divergence(const FaceMesh< Real > &m, const DV< Real > &u, const DV< Real > &out)
(div u)_i from face-normal fluxes u (nFaces; boundary faces included, along the outward normal).
Definition operators.hpp:30
void faceGradient(const FaceMesh< Real > &m, const DV< Real > &p, const DV< Real > &out, const DV< Real > &pb=DV< Real >{})
Definition operators.hpp:46
void wallGradientLS(const FaceMesh< Real > &m, const DV< Real > &U, const DV< Real > &gradU, const DV< Real > &Uwall, const DV< Real > &out)
Definition operators.hpp:359
Track C, rung C1: the discrete operators of the staggered COVOLUME scheme on a face mesh (plan verdic...
Definition collocated.hpp:41
void setup(const FaceMesh< Real > &mesh, Real viscosity, bool amg=false)
Definition collocated.hpp:69
void cellGrad(const DV< Real > &q, const DV< Real > &out)
The cell gradient of a scalar q = the transpose of the constraint applied to grad_f q.
Definition collocated.hpp:137
Real maxFaceDivergence()
max_i |div u_f|_i of the transporting face flux (exactly projected)
Definition collocated.hpp:334
DV< Real > wcorr
Definition collocated.hpp:66
DV< Real > g9
Definition collocated.hpp:67
void step(Real dt)
Definition collocated.hpp:202
DV< Real > div
Definition collocated.hpp:67
DV< Real > aT
Definition collocated.hpp:66
bool skewCorrected
Definition collocated.hpp:47
DV< Real > uf
Definition collocated.hpp:49
DV< Real > U1
Definition collocated.hpp:67
DV< Real > wg
Definition collocated.hpp:52
bool incremental
Definition collocated.hpp:46
peclet::core::ExecSpace Exec
Definition collocated.hpp:42
DV< Real > gp
Definition collocated.hpp:67
Real nu
Definition collocated.hpp:44
DV< Real > phi
Definition collocated.hpp:67
std::function< void(const DV< Real > &, int)> exchange
Definition collocated.hpp:55
PressureSolver< Real > poisson
Definition collocated.hpp:123
DV< Real > divStar
Definition collocated.hpp:66
Real maxCellDivergence()
max_i |div (T U)|_i — the residual divergence of the CELL field (the "approximate" of ABC)
Definition collocated.hpp:336
void project(const DV< Real > &Ustar, const DV< Real > &ufOut, Real dt, const DV< Real > &divOut=DV< Real >{})
Definition collocated.hpp:162
DV< Real > p
Definition collocated.hpp:49
Real viscDt
Definition collocated.hpp:65
void setExchange(Ex &ex)
Install the distributed hooks on the solver and its pressure solver.
Definition collocated.hpp:91
DV< Real > ub
Definition collocated.hpp:50
DV< Real > U2
Definition collocated.hpp:67
DV< Real > Uwall
Definition collocated.hpp:50
void initialize(const DV< Real > &Uin)
Initialise from a cell field: U = Uin projected once (dt = 1, no pressure kept).
Definition collocated.hpp:196
DV< Real > uf1
Definition collocated.hpp:67
void applyWallFlux(const DV< Real > &uf) const
Impose the boundary fluxes on a face field.
Definition collocated.hpp:116
Real maxDivOf(const DV< Real > &flux)
Definition collocated.hpp:340
DV< Real > rhs3
Definition collocated.hpp:66
void stepImplicit(Real dt)
Definition collocated.hpp:211
bool implicitDiffusion
Definition collocated.hpp:61
void toFaces(const DV< Real > &Uc, const DV< Real > &out)
The constraint interpolation: face flux of the cell field.
Definition collocated.hpp:126
void tendency(const DV< Real > &Uin, const DV< Real > &ufin, const DV< Real > &out)
a = tendency of Uin transported by ufin, minus the current pressure gradient (incremental).
Definition collocated.hpp:142
Real convScale
Definition collocated.hpp:45
DV< Real > gphi
Definition collocated.hpp:67
void stepRK3(Real dt)
One SSP-RK3 step, flow's predictor/projection structure at every stage.
Definition collocated.hpp:297
DV< Real > uc
Definition collocated.hpp:66
DV< Real > a
Definition collocated.hpp:67
void setWallVelocity(const DV< Real > &Uw)
Definition collocated.hpp:99
bool wallQuadratic
Definition collocated.hpp:51
bool rotational
Definition collocated.hpp:62
std::function< Real(Real)> sum
Definition collocated.hpp:56
std::function< Real(Real)> max
Definition collocated.hpp:56
DV< Real > U
Definition collocated.hpp:49
DV< Real > force
Definition collocated.hpp:49
FaceMesh< Real > m
Definition collocated.hpp:43
PressureSolver< Real > visc
Definition collocated.hpp:64
Real kineticEnergy() const
½ Σ V_i |U_i|²
Definition collocated.hpp:318
DV< Real > uf2
Definition collocated.hpp:67
Definition mesh.hpp:33
Kokkos::View< int *, Mem > cellFace
Definition mesh.hpp:49
KOKKOS_INLINE_FUNCTION Real normal(int f, int c) const
Definition mesh.hpp:55
int nCells
Definition mesh.hpp:35
KOKKOS_INLINE_FUNCTION int cellFacesBegin(int i) const
Definition mesh.hpp:53
KOKKOS_INLINE_FUNCTION int cellFacesEnd(int i) const
Definition mesh.hpp:54
Kokkos::View< Real *, Mem > cellVolume
Definition mesh.hpp:51
int nFaces
Definition mesh.hpp:35
Kokkos::View< Real *, Mem > faceArea
Definition mesh.hpp:42
Kokkos::View< Real *, Mem > faceHa
Definition mesh.hpp:45
Definition covolume.hpp:111