peclet.voro 1.0.4
Device-native moving-particle Voronoi dynamics
Loading...
Searching...
No Matches
covolume.hpp
Go to the documentation of this file.
1
26#ifndef PECLET_VORO_FV_COVOLUME_HPP
27#define PECLET_VORO_FV_COVOLUME_HPP
28
29#include <cstdio>
30#include <functional>
31#include <Kokkos_Core.hpp>
32#include <type_traits>
33#include <vector>
34
35#include "peclet/core/common/view.hpp"
36#include "peclet/core/solver/graph_amg_device.hpp"
40
41namespace peclet::voro::fv {
42
44template <class Real>
45void perotTranspose(const FaceMesh<Real>& m, const DV<Real>& acell, const DV<Real>& out) {
46 using Exec = peclet::core::ExecSpace;
47 const int nI = m.nInterior;
48 Kokkos::parallel_for(
49 "fv.perotT", Kokkos::RangePolicy<Exec>(0, m.nFaces), KOKKOS_LAMBDA(const int f) {
50 if (f >= nI) {
51 out(f) = Real(0);
52 return;
53 }
54 const int a = m.faceCellA(f), b = m.faceCellB(f);
55 Real s = 0;
56 for (int c = 0; c < 3; ++c) {
57 const Real cf = m.centroid(f, c);
58 s += cf * acell(3 * a + c) - (cf - m.conn(f, c)) * acell(3 * b + c);
59 }
60 out(f) = s / m.faceDist(f);
61 });
62}
63
69template <class Real>
70void cellTendency(const FaceMesh<Real>& m, const DV<Real>& u, const DV<Real>& U, Real nu,
71 const DV<Real>& out, const DV<Real>& force = DV<Real>{}, Real convScale = Real(1),
72 const DV<Real>& Uwall = DV<Real>{}, const DV<Real>& wallGrad = DV<Real>{}) {
73 using Exec = peclet::core::ExecSpace;
74 const int nI = m.nInterior;
75 const bool hasF = force.extent(0) > 0, hasW = Uwall.extent(0) > 0, hasWG = wallGrad.extent(0) > 0;
76 Kokkos::parallel_for(
77 "fv.tendency", Kokkos::RangePolicy<Exec>(0, m.nCells), KOKKOS_LAMBDA(const int i) {
78 Real acc[3] = {0, 0, 0};
79 const Real Ui[3] = {U(3 * i), U(3 * i + 1), U(3 * i + 2)};
80 for (int q = m.cellFacesBegin(i); q < m.cellFacesEnd(i); ++q) {
81 const int f = m.cellFace(q);
82 const Real s = m.cellFaceSign(q);
83 const Real F = convScale * s * u(f) * m.faceArea(f); // outward volume flux
84 if (f < nI) {
85 const int j = (s > 0) ? m.faceCellB(f) : m.faceCellA(f);
86 const Real w = nu * m.faceArea(f) / m.faceDist(f);
87 for (int c = 0; c < 3; ++c) {
88 const Real Uj = U(3 * j + c);
89 acc[c] += -F * Real(0.5) * (Ui[c] + Uj) + w * (Uj - Ui[c]);
90 }
91 } else { // wall at distance h_A with the prescribed velocity
92 const Real w = nu * m.faceArea(f) / m.faceHa(f);
93 for (int c = 0; c < 3; ++c) {
94 const Real Uw = hasW ? Uwall(3 * (f - nI) + c) : Real(0);
95 // viscous wall flux: −ν A ∂u/∂n at the wall (n outward), two-point or quadratic
96 const Real visc =
97 hasWG ? -nu * m.faceArea(f) * wallGrad(3 * (f - nI) + c) : w * (Uw - Ui[c]);
98 acc[c] += -F * Uw + visc;
99 }
100 }
101 }
102 const Real iv = Real(1) / m.cellVolume(i);
103 for (int c = 0; c < 3; ++c)
104 out(3 * i + c) = acc[c] * iv + (hasF ? force(3 * i + c) : Real(0));
105 });
106}
107
110template <class Real>
112 using Exec = peclet::core::ExecSpace;
114 bool useAmg = false;
115 Real tol = 1e-12;
116 int maxIter = 5000;
117 // Generalization (implicit diffusion, C2): K = extraDiag + lapScale·(−V L). Pressure: lapScale 1,
118 // no extraDiag, `deflate` (mean removal + pin, singular Neumann). Velocity: extraDiag_i = V_i/Δt
119 // + ν Σ_wall A_f/h_A (the two-point wall term), lapScale = ν, no deflation (SPD).
120 Real lapScale = 1;
121 bool deflate = true;
123 int lastIters = 0;
124 Real lastRes = 0;
125 peclet::core::solver::GraphAMGDevice amg;
126 // Distributed hooks (rung C5): `exchange(field, ncomp)` refreshes the ghost entries of a
127 // cell field (sized m.nCombined) from their owners, `sum` is the global reduction. Unset =
128 // single rank. With `exchange` set the PCG path is used (block-Jacobi AMG per rank when
129 // useAmg, plain CG otherwise) — poissonCG has no hooks.
130 std::function<void(const DV<Real>&, int)> exchange;
131 std::function<Real(Real)> sum;
132 Real localVtot_ = 0;
136 void setHooks(std::function<void(const DV<Real>&, int)> ex, std::function<Real(Real)> s) {
137 exchange = std::move(ex);
138 sum = std::move(s);
140 }
142 Kokkos::View<double*, peclet::core::MemSpace> rd, zd; // AMG works in double
143 Real Vtot = 0;
144
147 void setupVelocity(const FaceMesh<Real>& mesh, Real nu, Real dt, bool withAmg) {
148 lapScale = nu;
149 deflate = false;
150 const FaceMesh<Real> mm = mesh;
151 extraDiag = DV<Real>("ps.extraDiag", mesh.nCells);
152 const DV<Real> ed = extraDiag;
153 const int nI = mesh.nInterior;
154 Kokkos::parallel_for(
155 "ps.ediag", Kokkos::RangePolicy<Exec>(0, mesh.nCells), KOKKOS_LAMBDA(const int i) {
156 Real d = mm.cellVolume(i) / dt;
157 for (int t = mm.cellFacesBegin(i); t < mm.cellFacesEnd(i); ++t) {
158 const int f = mm.cellFace(t);
159 if (f >= nI)
160 d += nu * mm.faceArea(f) / mm.faceHa(f);
161 }
162 ed(i) = d;
163 });
164 setup(mesh, withAmg);
165 }
166 void setup(const FaceMesh<Real>& mesh, bool withAmg) {
167 m = mesh;
168 useAmg = withAmg;
169 const int N = m.nCells;
170 const int NC = m.nCombined > 0 ? m.nCombined : N;
171 r = DV<Real>("ps.r", N);
172 z = DV<Real>("ps.z", NC); // read at ghosts by applyK (distributed)
173 q = DV<Real>("ps.q", N);
174 b = DV<Real>("ps.b", N);
175 {
176 const FaceMesh<Real> mm = m; // no `this` capture on the device
177 Kokkos::parallel_reduce(
178 "ps.vtot", Kokkos::RangePolicy<Exec>(0, N),
179 KOKKOS_LAMBDA(const int i, Real& acc) { acc += mm.cellVolume(i); }, Vtot);
180 }
181 if (sum)
182 Vtot = sum(Vtot);
184 if (!useAmg)
185 return;
186 rd = Kokkos::View<double*, peclet::core::MemSpace>("ps.rd", N);
187 zd = Kokkos::View<double*, peclet::core::MemSpace>("ps.zd", N);
188 // host CSR of K = −V L (interior faces only: Neumann walls contribute nothing). Distributed:
189 // the owned block only (couplings to ghosts stay in the diagonal — block-Jacobi AMG).
190 auto A = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace{}, m.faceCellA);
191 auto B = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace{}, m.faceCellB);
192 auto Af = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace{}, m.faceArea);
193 auto df = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace{}, m.faceDist);
194 auto off = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace{}, m.cellFaceOffset);
195 auto cf = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace{}, m.cellFace);
196 auto cs = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace{}, m.cellFaceSign);
197 peclet::core::solver::HostCsrOp K;
198 K.n = N;
199 K.diag.assign(N, 0.0);
200 K.start.assign(N + 1, 0);
201 std::vector<Real> edh;
202 if (extraDiag.extent(0) > 0)
203 edh = peclet::core::toVector(extraDiag);
204 for (int i = 0; i < N; ++i) {
205 if (!edh.empty())
206 K.diag[i] += edh[i];
207 for (int qq = off(i); qq < off(i + 1); ++qq) {
208 const int f = cf(qq);
209 if (f >= m.nInterior)
210 continue;
211 const int j = cs(qq) > 0 ? B(f) : A(f);
212 const double w = lapScale * Af(f) / df(f);
213 K.diag[i] += w;
214 if (j >= N)
215 continue; // ghost neighbour: off-block
216 K.nbr.push_back(j);
217 K.coef.push_back(-w);
218 }
219 K.start[i + 1] = (peclet::core::Index)K.nbr.size();
220 }
221 peclet::core::solver::AmgParams prm;
222 prm.ndofPerNode = 1;
223 // K is singular (constant null space): smoother sweeps on the coarsest level instead of the
224 // near-exact coarse CG, which divides by zero once the coarse residual lies in the null
225 // space (seen on a 512-cell mesh, NaN).
226 prm.coarseSweeps = deflate ? 8 : 0; // the velocity matrix is SPD: exact coarse solve is fine
227 amg.build(K, prm);
228 }
229
230 // q = K z
231 void applyK(const DV<Real>& zz, const DV<Real>& qq) const {
232 const FaceMesh<Real> mm = m;
233 const int nI = mm.nInterior;
234 const Real ls = lapScale;
235 const DV<Real> ed = extraDiag;
236 const bool hasEd = ed.extent(0) > 0;
237 Kokkos::parallel_for(
238 "ps.K", Kokkos::RangePolicy<Exec>(0, mm.nCells), KOKKOS_LAMBDA(const int i) {
239 Real acc = 0;
240 const Real zi = zz(i);
241 for (int t = mm.cellFacesBegin(i); t < mm.cellFacesEnd(i); ++t) {
242 const int f = mm.cellFace(t);
243 if (f >= nI)
244 continue;
245 const int j = mm.cellFaceSign(t) > 0 ? mm.faceCellB(f) : mm.faceCellA(f);
246 acc += ls * mm.faceArea(f) / mm.faceDist(f) * (zi - zz(j));
247 }
248 qq(i) = acc + (hasEd ? ed(i) * zi : Real(0));
249 });
250 }
251 // dot over the OWNED cells (fields may be sized nCombined), globally reduced
252 Real dot(const DV<Real>& a, const DV<Real>& bb) const {
253 Real s = 0;
254 Kokkos::parallel_reduce(
255 "ps.dot", Kokkos::RangePolicy<Exec>(0, m.nCells),
256 KOKKOS_LAMBDA(const int i, Real& acc) { acc += a(i) * bb(i); }, s);
257 return sum ? sum(s) : s;
258 }
259 void precond(const DV<Real>& rr, const DV<Real>& zz) const {
260 if (!useAmg) { // zz may be longer than rr (ghost slots): copy the owned part
261 Kokkos::deep_copy(Kokkos::subview(zz, std::make_pair(0, (int)rr.extent(0))), rr);
262 return;
263 }
264 if constexpr (std::is_same_v<Real, double>) {
265 if (zz.extent(0) == rr.extent(0))
266 amg.apply(rr, zz);
267 else
268 amg.apply(rr, Kokkos::subview(zz, std::make_pair(0, (int)rr.extent(0))));
269 } else {
270 Kokkos::deep_copy(rd, rr);
271 amg.apply(rd, zd);
272 Kokkos::deep_copy(zz, zd);
273 }
274 }
276 int solve(const DV<Real>& f, const DV<Real>& p) {
277 const int N = m.nCells;
278 if (!useAmg && !exchange && deflate)
279 return lastIters = poissonCG(m, f, p, tol, maxIter, lastRes);
280 const FaceMesh<Real> mm = m;
281 const DV<Real> rr = r, zz = z, qq = q;
282 const Real vt = Vtot;
283 Real fMean = 0;
284 if (deflate) {
285 Kokkos::parallel_reduce(
286 "ps.fmean", Kokkos::RangePolicy<Exec>(0, N),
287 KOKKOS_LAMBDA(const int i, Real& acc) { acc += mm.cellVolume(i) * f(i); }, fMean);
288 if (sum)
289 fMean = sum(fMean);
290 fMean /= vt;
291 }
292 Kokkos::deep_copy(p, Real(0));
293 const bool defl = deflate;
294 Kokkos::parallel_for(
295 "ps.b", Kokkos::RangePolicy<Exec>(0, N), KOKKOS_LAMBDA(const int i) {
296 rr(i) = defl ? mm.cellVolume(i) * (f(i) - fMean) : f(i); // velocity: f is the full RHS
297 });
298 const Real r0 = Kokkos::sqrt(dot(rr, rr));
299 if (!(r0 > Real(0))) { // zero right-hand side: p = 0
300 lastRes = 0;
301 return lastIters = 0;
302 }
303 precond(rr, zz);
304 DV<Real> d("ps.d", zz.extent(0));
305 Kokkos::deep_copy(d, zz);
306 Real rz = dot(rr, zz);
307 int it = 0;
308 for (; it < maxIter; ++it) {
309 if (exchange)
310 exchange(d, 1);
311 applyK(d, qq);
312 const Real dq = dot(d, qq);
313 if (!(dq > Real(0)))
314 break;
315 const Real alpha = rz / dq;
316 Kokkos::parallel_for(
317 "ps.upd", Kokkos::RangePolicy<Exec>(0, N), KOKKOS_LAMBDA(const int i) {
318 p(i) += alpha * d(i);
319 rr(i) -= alpha * qq(i);
320 });
321 lastRes = Kokkos::sqrt(dot(rr, rr)) / (r0 > Real(0) ? r0 : Real(1));
322 if (lastRes < tol) {
323 ++it;
324 break;
325 }
326 precond(rr, zz);
327 const Real rzn = dot(rr, zz);
328 const Real beta = rzn / rz;
329 rz = rzn;
330 Kokkos::parallel_for(
331 "ps.d", Kokkos::RangePolicy<Exec>(0, N),
332 KOKKOS_LAMBDA(const int i) { d(i) = zz(i) + beta * d(i); });
333 }
334 if (deflate) {
335 Real pMean = 0;
336 Kokkos::parallel_reduce(
337 "ps.pmean", Kokkos::RangePolicy<Exec>(0, N),
338 KOKKOS_LAMBDA(const int i, Real& acc) { acc += mm.cellVolume(i) * p(i); }, pMean);
339 if (sum)
340 pMean = sum(pMean);
341 pMean /= vt;
342 Kokkos::parallel_for(
343 "ps.pin", Kokkos::RangePolicy<Exec>(0, N), KOKKOS_LAMBDA(const int i) { p(i) -= pMean; });
344 }
345 if (exchange)
346 exchange(p, 1);
347 return lastIters = it;
348 }
349};
350
352template <class Real>
354 using Exec = peclet::core::ExecSpace;
356 Real nu = 0;
357 Real convScale = 1; // 0 = Stokes (diagnostic)
358 DV<Real> u, p, force; // nFaces, nCells, 3N (optional)
359 DV<Real> Uwall, ub; // 3 × nBoundary wall velocity, nBoundary wall flux (C3)
360 bool wallQuadratic = true; // second-order wall gradient (wallGradientLS) vs two-point
361 DV<Real> wg, g9w; // 3 × nBoundary wall gradient, 9N gradient scratch
362 // C2a′: the DEC (Nicolaides) viscous term ν(grad div − curl curl) on the faces instead of the
363 // Perot-reconstructed Rᵀ Δ₂ R. Enable with setDec(view) (needs the view's edge lengths,
364 // `withAreaGrad`); periodic (wall-free) meshes only for now.
365 bool viscousDEC = false;
368 DV<Real> U, a, k, u1, u2, div, gphi; // workspace
370 // Distributed hooks (rung C5, fv/distributed.hpp): the reconstructed cell velocity and the cell
371 // tendency are refreshed at the ghosts (interface faces read both cells), the energy counts an
372 // interface face once (½ on each rank), the pressure PCG uses the same hooks.
373 std::function<void(const DV<Real>&, int)> exchange;
374 std::function<Real(Real)> sum, max;
375 template <class Ex>
376 void setExchange(Ex& ex) {
377 exchange = [&ex](const DV<Real>& f, int nc) { ex.exchange(f, nc); };
378 sum = [&ex](Real v) { return ex.sum(v); };
379 max = [&ex](Real v) { return ex.max(v); };
380 poisson.setHooks(exchange, sum);
381 }
382 Real lastDiv = 0;
383
384 void setup(const FaceMesh<Real>& mesh, Real viscosity, bool amg = false) {
385 m = mesh;
386 nu = viscosity;
387 const int N = m.nCells, F = m.nFaces;
388 const int NC = m.nCombined > 0 ? m.nCombined : N;
389 u = DV<Real>("ns.u", F);
390 p = DV<Real>("ns.p", NC);
391 U = DV<Real>("ns.U", 3 * NC);
392 a = DV<Real>("ns.a", 3 * NC);
393 k = DV<Real>("ns.k", F);
394 u1 = DV<Real>("ns.u1", F);
395 u2 = DV<Real>("ns.u2", F);
396 div = DV<Real>("ns.div", N);
397 gphi = DV<Real>("ns.gphi", F);
399 poisson.setup(m, amg);
400 }
403 void setWallVelocity(const DV<Real>& Uw) {
404 const int nB = m.nFaces - m.nInterior, nI = m.nInterior;
405 Uwall = Uw;
406 ub = DV<Real>("fv.ub", nB);
407 if (Uw.extent(0) == 0)
408 return;
409 const FaceMesh<Real> mm = m;
410 const DV<Real> bb = ub;
411 Kokkos::parallel_for(
412 "fv.ub", Kokkos::RangePolicy<Exec>(0, nB), KOKKOS_LAMBDA(const int b) {
413 Real un = 0;
414 for (int c = 0; c < 3; ++c)
415 un += Uw(3 * b + c) * mm.normal(nI + b, c);
416 bb(b) = un;
417 });
418 }
420 void applyWallFlux(const DV<Real>& uf) const {
421 const int nB = m.nFaces - m.nInterior, nI = m.nInterior;
422 const DV<Real> bb = ub;
423 Kokkos::parallel_for(
424 "fv.wall", Kokkos::RangePolicy<Exec>(0, nB),
425 KOKKOS_LAMBDA(const int b) { uf(nI + b) = bb(b); });
426 }
428 void setDec(const TessellationView<Real>& view) {
429 dec = buildDecEdges<Real>(view, m);
430 decOut = DV<Real>("ns.decOut", m.nFaces);
431 decDiv = DV<Real>("ns.decDiv", m.nCells);
432 viscousDEC = true;
433 }
435 void rhs(const DV<Real>& uf, const DV<Real>& out) {
436 if (viscousDEC) { // convection (+ force) through Rᵀ, viscous term directly on the faces
437 perotVelocity(m, uf, U);
438 if (exchange)
439 exchange(U, 3);
440 cellTendency(m, uf, U, Real(0), a, force, convScale, Uwall);
441 if (exchange)
442 exchange(a, 3);
443 perotTranspose(m, a, out);
445 const DV<Real> dO = decOut;
446 const Real nuL = nu;
447 Kokkos::parallel_for(
448 "ns.decvisc", Kokkos::RangePolicy<Exec>(0, m.nInterior),
449 KOKKOS_LAMBDA(const int f) { out(f) += nuL * dO(f); });
450 return;
451 }
452 perotVelocity(m, uf, U);
453 if (exchange)
454 exchange(U, 3); // the ghosts' reconstructed velocity (the convective face mean, walls)
455 if (wallQuadratic && m.nFaces > m.nInterior) {
456 if (wg.extent(0) == 0) {
457 wg = DV<Real>("ns.wg", 3 * (m.nFaces - m.nInterior));
458 g9w = DV<Real>("ns.g9w", 9 * (m.nCombined > 0 ? m.nCombined : m.nCells));
459 }
462 cellTendency(m, uf, U, nu, a, force, convScale, Uwall, wg);
463 } else {
464 cellTendency(m, uf, U, nu, a, force, convScale, Uwall);
465 }
466 if (exchange)
467 exchange(a, 3); // Rᵀ reads the ghost cell's tendency on an interface face
468 perotTranspose(m, a, out);
469 }
471 void project(const DV<Real>& uf, Real dt) {
472 const DV<Real> dv = div, g = gphi;
473 divergence(m, uf, dv);
474 const Real s = -Real(1) / dt;
475 Kokkos::parallel_for(
476 "ns.rhsP", Kokkos::RangePolicy<Exec>(0, m.nCells),
477 KOKKOS_LAMBDA(const int i) { dv(i) *= s; });
478 poisson.solve(dv, p);
479 faceGradient(m, p, g);
480 Kokkos::parallel_for(
481 "ns.corr", Kokkos::RangePolicy<Exec>(0, m.nFaces),
482 KOKKOS_LAMBDA(const int f) { uf(f) -= dt * g(f); });
483 }
485 void step(Real dt) {
486 const int F = m.nFaces;
487 const DV<Real> uu = u, kk = k, v1 = u1, v2 = u2;
488 rhs(uu, kk);
489 Kokkos::parallel_for(
490 "ns.s1", Kokkos::RangePolicy<Exec>(0, F),
491 KOKKOS_LAMBDA(const int f) { v1(f) = uu(f) + dt * kk(f); });
492 project(v1, dt);
493 rhs(v1, kk);
494 Kokkos::parallel_for(
495 "ns.s2", Kokkos::RangePolicy<Exec>(0, F), KOKKOS_LAMBDA(const int f) {
496 v2(f) = Real(0.75) * uu(f) + Real(0.25) * (v1(f) + dt * kk(f));
497 });
498 project(v2, Real(0.25) * dt);
499 rhs(v2, kk);
500 Kokkos::parallel_for(
501 "ns.s3", Kokkos::RangePolicy<Exec>(0, F),
502 KOKKOS_LAMBDA(const int f) { uu(f) = (uu(f) + Real(2) * (v2(f) + dt * kk(f))) / Real(3); });
503 project(uu, Real(2) / Real(3) * dt);
504 }
506 Real kineticEnergy() const {
507 // ½⟨u,u⟩_F over the owned faces; an interface face exists on both ranks → weight ½
508 const FaceMesh<Real> mm = m;
509 const DV<Real> uu = u;
510 const int nOwn = m.nCells;
511 Real e = 0;
512 Kokkos::parallel_reduce(
513 "ns.ke", Kokkos::RangePolicy<Exec>(0, m.nInterior),
514 KOKKOS_LAMBDA(const int f, Real& acc) {
515 const Real w = mm.faceCellB(f) >= nOwn ? Real(0.5) : Real(1);
516 acc += w * mm.faceArea(f) * mm.faceDist(f) * uu(f) * uu(f);
517 },
518 e);
519 if (sum)
520 e = sum(e);
521 return Real(0.5) * e;
522 }
525 const DV<Real> dv = div;
526 divergence(m, u, dv);
527 Real mx = 0;
528 Kokkos::parallel_reduce(
529 "ns.maxdiv", Kokkos::RangePolicy<Exec>(0, m.nCells),
530 KOKKOS_LAMBDA(const int i, Real& acc) {
531 const Real v = Kokkos::fabs(dv(i));
532 if (v > acc)
533 acc = v;
534 },
535 Kokkos::Max<Real>(mx));
536 return max ? max(mx) : mx;
537 }
538};
539
540} // namespace peclet::voro::fv
541
542#endif // PECLET_VORO_FV_COVOLUME_HPP
Track C, rung C2a′ (Voronoi methods plan): the discrete-exterior-calculus (Nicolaides covolume) vecto...
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 perotTranspose(const FaceMesh< Real > &m, const DV< Real > &acell, const DV< Real > &out)
Transpose of the Perot reconstruction: face-normal tendency from cell tendencies (3N).
Definition covolume.hpp:45
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
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 decLaplacian(const FaceMesh< Real > &m, const DecEdges< Real > &d, const DV< Real > &u, const DV< Real > &divScratch, const DV< Real > &out)
Definition dec.hpp:185
void perotVelocity(const FaceMesh< Real > &m, const DV< Real > &u, const DV< Real > &out)
Perot reconstruction of the cell velocity (3N) from face-normal fluxes.
Definition operators.hpp:103
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
int poissonCG(const FaceMesh< Real > &m, const DV< Real > &f, const DV< Real > &p, Real tol, int maxIter, Real &resOut)
Definition operators.hpp:429
Track C, rung C1: the discrete operators of the staggered COVOLUME scheme on a face mesh (plan verdic...
Definition tessellation_view.hpp:111
The covolume NS solver state: face fluxes u, cell pressure p (from the last projection).
Definition covolume.hpp:353
DV< Real > gphi
Definition covolume.hpp:368
peclet::core::ExecSpace Exec
Definition covolume.hpp:354
DecEdges< Real > dec
Definition covolume.hpp:366
DV< Real > k
Definition covolume.hpp:368
DV< Real > Uwall
Definition covolume.hpp:359
DV< Real > decDiv
Definition covolume.hpp:367
std::function< Real(Real)> max
Definition covolume.hpp:374
void applyWallFlux(const DV< Real > &uf) const
Impose the boundary fluxes on a face field.
Definition covolume.hpp:420
DV< Real > U
Definition covolume.hpp:368
void setWallVelocity(const DV< Real > &Uw)
Definition covolume.hpp:403
Real convScale
Definition covolume.hpp:357
bool viscousDEC
Definition covolume.hpp:365
void setExchange(Ex &ex)
Definition covolume.hpp:376
void rhs(const DV< Real > &uf, const DV< Real > &out)
k = Rᵀ a(u): the face-normal tendency (no pressure).
Definition covolume.hpp:435
DV< Real > div
Definition covolume.hpp:368
Real maxDivergence()
max_i |div u|_i
Definition covolume.hpp:524
DV< Real > force
Definition covolume.hpp:358
DV< Real > ub
Definition covolume.hpp:359
void step(Real dt)
One SSP-RK3 step with a projection after every stage.
Definition covolume.hpp:485
Real nu
Definition covolume.hpp:356
void setup(const FaceMesh< Real > &mesh, Real viscosity, bool amg=false)
Definition covolume.hpp:384
void project(const DV< Real > &uf, Real dt)
Make uf divergence-free: L φ = div uf / dt, uf −= dt grad φ; p = φ.
Definition covolume.hpp:471
Real lastDiv
Definition covolume.hpp:382
Real kineticEnergy() const
½⟨u,u⟩_F — the energy the scheme conserves.
Definition covolume.hpp:506
DV< Real > decOut
Definition covolume.hpp:367
DV< Real > p
Definition covolume.hpp:358
DV< Real > wg
Definition covolume.hpp:361
DV< Real > u
Definition covolume.hpp:358
bool wallQuadratic
Definition covolume.hpp:360
DV< Real > g9w
Definition covolume.hpp:361
std::function< void(const DV< Real > &, int)> exchange
Definition covolume.hpp:373
PressureSolver< Real > poisson
Definition covolume.hpp:369
DV< Real > u2
Definition covolume.hpp:368
std::function< Real(Real)> sum
Definition covolume.hpp:374
DV< Real > u1
Definition covolume.hpp:368
DV< Real > a
Definition covolume.hpp:368
void setDec(const TessellationView< Real > &view)
Install the DEC viscous term from the published view (facet-edge CSR with edge lengths).
Definition covolume.hpp:428
FaceMesh< Real > m
Definition covolume.hpp:355
Definition dec.hpp:39
Definition mesh.hpp:33
Kokkos::View< int *, Mem > cellFace
Definition mesh.hpp:49
int nInterior
Definition mesh.hpp:35
Kokkos::View< int *, Mem > faceCellB
Definition mesh.hpp:40
KOKKOS_INLINE_FUNCTION Real conn(int f, int c) const
Definition mesh.hpp:57
Kokkos::View< Real *, Mem > faceDist
Definition mesh.hpp:44
KOKKOS_INLINE_FUNCTION Real normal(int f, int c) const
Definition mesh.hpp:55
Kokkos::View< int *, Mem > faceCellA
Definition mesh.hpp:40
int nCells
Definition mesh.hpp:35
KOKKOS_INLINE_FUNCTION Real centroid(int f, int c) const
Definition mesh.hpp:56
KOKKOS_INLINE_FUNCTION int cellFacesBegin(int i) const
Definition mesh.hpp:53
Kokkos::View< Real *, Mem > cellFaceSign
Definition mesh.hpp:50
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
peclet::core::solver::GraphAMGDevice amg
Definition covolume.hpp:125
DV< Real > extraDiag
Definition covolume.hpp:122
void setup(const FaceMesh< Real > &mesh, bool withAmg)
Definition covolume.hpp:166
Real lastRes
Definition covolume.hpp:124
Kokkos::View< double *, peclet::core::MemSpace > zd
Definition covolume.hpp:142
int maxIter
Definition covolume.hpp:116
void setHooks(std::function< void(const DV< Real > &, int)> ex, std::function< Real(Real)> s)
Definition covolume.hpp:136
DV< Real > Kd
Definition covolume.hpp:141
Real dot(const DV< Real > &a, const DV< Real > &bb) const
Definition covolume.hpp:252
int solve(const DV< Real > &f, const DV< Real > &p)
Solve −L p = f (mean of f removed, mean of p pinned to zero). Returns iterations.
Definition covolume.hpp:276
std::function< void(const DV< Real > &, int)> exchange
Definition covolume.hpp:130
Real tol
Definition covolume.hpp:115
Real lapScale
Definition covolume.hpp:120
void precond(const DV< Real > &rr, const DV< Real > &zz) const
Definition covolume.hpp:259
std::function< Real(Real)> sum
Definition covolume.hpp:131
DV< Real > z
Definition covolume.hpp:141
bool useAmg
Definition covolume.hpp:114
Real Vtot
Definition covolume.hpp:143
DV< Real > b
Definition covolume.hpp:141
int lastIters
Definition covolume.hpp:123
Real localVtot_
Definition covolume.hpp:132
void applyK(const DV< Real > &zz, const DV< Real > &qq) const
Definition covolume.hpp:231
DV< Real > r
Definition covolume.hpp:141
FaceMesh< Real > m
Definition covolume.hpp:113
Kokkos::View< double *, peclet::core::MemSpace > rd
Definition covolume.hpp:142
bool deflate
Definition covolume.hpp:121
peclet::core::ExecSpace Exec
Definition covolume.hpp:112
DV< Real > q
Definition covolume.hpp:141
void setupVelocity(const FaceMesh< Real > &mesh, Real nu, Real dt, bool withAmg)
Definition covolume.hpp:147