flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
scalar_transport.hpp
Go to the documentation of this file.
1
20#ifndef PECLET_FLOW_SCALAR_TRANSPORT_HPP
21#define PECLET_FLOW_SCALAR_TRANSPORT_HPP
22
23#include <Kokkos_Core.hpp>
24#include <string>
25
26#include "mac_cutcell.hpp"
28
29namespace peclet::flow {
30
31// Per-scalar BC on a domain face: 0 periodic (via the halo/periodic fill), 1 Neumann zero-flux
32// (ghost = inner, i.e. adiabatic wall), 2 Dirichlet value (ghost = 2*value - inner reflection).
33enum class ScalarBc { Periodic = 0, Neumann = 1, Dirichlet = 2 };
34
35// One transported scalar. `c` aliases the Solver's registered field (fields_); the rest is private
36// scratch on the same G=2 block. Bands are double (a scalar is cheap; no float-quantization
37// concern).
39 std::string name;
40 CCField c, cOld, b; // solution (registered), time base c^n, rhs
41 CCField AC, AW, AE, AS, AN, AB, AT; // implicit diffusion+time 7-band operator
42 double D = 0.0; // constant diffusivity (grid units)
43 int scheme = 1; // explicit advection flux: 0 FOU, 1 Koren TVD, 2 SOU
44 int iters = 50; // RB-GS sweeps for the implicit diffusion solve
45 int bc[6] = {0, 0, 0, 0, 0, 0}; // -x,+x,-y,+y,-z,+z (ScalarBc)
46 double bcVal[6] = {0, 0, 0, 0, 0, 0};
47 bool stencilBuilt = false;
48};
49
50// Build the implicit diffusion+time 7-band operator over inner cells:
51// A_C = idt + D*(ox(i)+ox(i+sx)+oy(i)+oy(i+sy)+oz(i)+oz(i+sz)), A_off = -D*open_face.
52// Openness-weighted (closed faces drop out) — the scalar analog of buildCutcellOp with the 1/dt
53// diagonal. ox(i) is the -x face openness of cell i (== +x face of cell i-1), matching divergOpen.
55 CCField AB, CCField AT, CCConst ox, CCConst oy, CCConst oz,
56 double D, double idt, C3 e, int g) {
57 CCExec space;
58 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
59 Kokkos::parallel_for(
60 "peclet::flow::scalar_build_diff", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
61 KOKKOS_LAMBDA(int lx, int ly, int lz) {
62 const long sx = 1, sy = e.x, sz = (long)e.x * e.y;
63 const long i = (long)lx + (long)ly * sy + (long)lz * sz;
64 const double tw = D * ox(i), te = D * ox(i + sx);
65 const double ts = D * oy(i), tn = D * oy(i + sy);
66 const double tb = D * oz(i), tt = D * oz(i + sz);
67 AW(i) = -tw;
68 AE(i) = -te;
69 AS(i) = -ts;
70 AN(i) = -tn;
71 AB(i) = -tb;
72 AT(i) = -tt;
73 AC(i) = idt + te + tw + tn + ts + tt + tb;
74 });
75}
76
77// b = idt*c^n - div(open u c^n): explicit conservative openness-weighted advection into the RHS.
78// U/V/W are the MAC face-normal velocities (staggered: C[fd].u; collocated: uf_/vf_/wf_) — U(i) is
79// the -x face velocity of cell i, co-located with ox(i). scheme: 0 FOU, 1 Koren TVD, 2 SOU.
80inline void scalarBuildRhs(CCField b, CCConst cOld, CCConst U, CCConst V, CCConst W, CCConst ox,
81 CCConst oy, CCConst oz, double idt, int scheme, C3 e, int g) {
82 CCExec space;
83 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
84 Kokkos::parallel_for(
85 "peclet::flow::scalar_build_rhs", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
86 KOKKOS_LAMBDA(int lx, int ly, int lz) {
87 const long sx = 1, sy = e.x, sz = (long)e.x * e.y;
88 const long i = (long)lx + (long)ly * sy + (long)lz * sz;
89 double adv = 0.0;
90 // per axis fd: flux through the +fd face (open(i+s), vel U(i+s)) minus the -fd face
91 // (open(i), vel U(i)). Face value from the upwind limiter on the 4-cell stencil.
92 for (int fd = 0; fd < 3; ++fd) {
93 const long s = (fd == 0) ? sx : (fd == 1) ? sy : sz;
94 CCConst Uf = (fd == 0) ? U : (fd == 1) ? V : W;
95 CCConst Of = (fd == 0) ? ox : (fd == 1) ? oy : oz;
96 const double velm = Uf(i), velp = Uf(i + s);
97 const double om = Of(i), op = Of(i + s);
98 const double cLL = cOld(i - 2 * s), cL = cOld(i - s), cR = cOld(i), cRR = cOld(i + s),
99 cRRR = cOld(i + 2 * s);
100 double Fp, Fm;
101 if (scheme == 0) { // first-order upwind
102 Fp = op * sadv::fou_flux(cR, cRR, velp);
103 Fm = om * sadv::fou_flux(cL, cR, velm);
104 } else if (scheme == 2) { // second-order upwind (unlimited)
105 Fp = op * sadv::sou(cL, cR, cRR, cRRR, velp);
106 Fm = om * sadv::sou(cLL, cL, cR, cRR, velm);
107 } else { // Koren TVD (default)
108 Fp = op * sadv::tvd(cL, cR, cRR, cRRR, velp);
109 Fm = om * sadv::tvd(cLL, cL, cR, cRR, velm);
110 }
111 adv += Fp - Fm;
112 }
113 b(i) = idt * cOld(i) - adv;
114 });
115}
116
117} // namespace peclet::flow
118
119#endif // PECLET_FLOW_SCALAR_TRANSPORT_HPP
flow — portable (Kokkos) cut-cell pressure-operator face openness from an SDF.
Kokkos::View< double *, CCMem > CCField
void scalarBuildDiffusionOpen(CCField AC, CCField AW, CCField AE, CCField AS, CCField AN, CCField AB, CCField AT, CCConst ox, CCConst oy, CCConst oz, double D, double idt, C3 e, int g)
Kokkos::DefaultExecutionSpace CCExec
Kokkos::View< const double *, CCMem > CCConst
void scalarBuildRhs(CCField b, CCConst cOld, CCConst U, CCConst V, CCConst W, CCConst ox, CCConst oy, CCConst oz, double idt, int scheme, C3 e, int g)
double fou_flux(double L, double R, double vel)
double tvd(double LL, double L, double R, double RR, double vel)
double sou(double LL, double L, double R, double RR, double vel)
flow — portable (Kokkos) staggered MAC momentum advection (Koren TVD + FOU).
static constexpr double AC