8#ifndef PECLET_FLOW_FLOW_IBM_SCALARS_HPP
9#define PECLET_FLOW_FLOW_IBM_SCALARS_HPP
19 sc.cOld =
CCField(name +
"_old", n_);
20 sc.b =
CCField(name +
"_b", n_);
21 sc.AC =
CCField(name +
"_AC", n_);
22 sc.AW =
CCField(name +
"_AW", n_);
23 sc.AE =
CCField(name +
"_AE", n_);
24 sc.AS =
CCField(name +
"_AS", n_);
25 sc.AN =
CCField(name +
"_AN", n_);
26 sc.AB =
CCField(name +
"_AB", n_);
27 sc.AT =
CCField(name +
"_AT", n_);
35 sc.iters = iters < 1 ? 1 : iters;
38 sc.cut = std::make_shared<ScalarCutState>();
40 scalars_.push_back(sc);
45 for (
const auto& sc : scalars_)
53 for (
auto& sc : scalars_)
54 if (sc.name == name) {
56 sc.bcVal[face] = value;
58 sc.cut->hasProfile[face] =
false;
61 throw std::runtime_error(
"set_scalar_bc: no scalar named '" + name +
"'");
68 const double idt = 1.0 / dt_;
70 if constexpr (Grid::collocated) {
85 for (
auto& sc : scalars_) {
94 const bool energy = sc.energy && sc.kcell.extent(0) == n_;
95 const bool hasMask = sc.dmask.extent(0) == n_;
99 CCConst(sc.dmask), idt, e_,
G, u_.
w[0], u_.
w[1], u_.
w[2]);
100 applyScalarBcStencilVar(sc);
105 applyScalarBcStencil(sc);
109 const bool gfm =
hasMask && pcPlaneDir_ && sc.gfmB.extent(0) == n_ && pcGphi_.extent(0) == n_;
113 const bool gfm2 =
gfm && (pcGfmOrder_ >= 2 || (pcCurvDist_ && pcKappa_.extent(0) == n_));
118 CCConst(pcCurvDist_ && pcKappa_.extent(0) == n_ ? pcKappa_ : pcGphi_),
119 CCConst(sc.kcell), sc.D, energy, pcGfmThMin_, pcGfmThMax_, pcGfmOrder_,
120 pcCurvDist_ && pcKappa_.extent(0) == n_, e_,
G, u_.
w[0], u_.
w[1], u_.
w[2],
126 CCConst(sc.kcell), sc.D, energy, pcGfmThMin_, pcGfmThMax_, e_,
G, u_.
w[0],
127 u_.
w[1], u_.
w[2],
gmS);
132 Kokkos::deep_copy(sc.cOld, sc.c);
134 if (
hasMask && pcCarryConserve_ && pcCarrySrc_.extent(0) == n_)
136 scalarFillGhosts(sc);
147 if (
hasMask && pcBudgetOn_ && pcClsPrev_.extent(0) == n_)
152 for (
int it = 0; it < sc.iters; ++it) {
153 scalarFillGhosts(sc);
154 cutcellSmoothColor(sc.c,
CCConst(sc.b), sc.AC, sc.AW, sc.AE, sc.AS, sc.AN, sc.AB, sc.AT, e_,
156 scalarFillGhosts(sc);
157 cutcellSmoothColor(sc.c,
CCConst(sc.b), sc.AC, sc.AW, sc.AE, sc.AS, sc.AN, sc.AB, sc.AT, e_,
160 scalarFillGhosts(sc);
161 if (
hasMask && pcBudgetOn_ && pcClsPrev_.extent(0) == n_)
168 for (
auto& sc : scalars_)
171 throw std::runtime_error(
"no scalar named '" + name +
"'");
178 throw std::invalid_argument(
179 "the per-cell Dirichlet mask is not available on the cut-cell "
181 name +
"' (doc/scalar_ibm_design.md §8.1)");
182 if (sc.dmask.extent(0) != n_) {
183 sc.dmask =
CCField(name +
"_dmask", n_);
184 sc.dval =
CCField(name +
"_dval", n_);
185 sc.gfmB =
CCField(name +
"_gfmb", n_);
187 if (pcGphi_.extent(0) != n_) {
188 pcTgam_ =
CCField(
"pc_tgam", n_);
189 pcGn_[0] =
CCField(
"pc_gnx", n_);
190 pcGn_[1] =
CCField(
"pc_gny", n_);
191 pcGn_[2] =
CCField(
"pc_gnz", n_);
192 pcGphi_ =
CCField(
"pc_gphi", n_);
203void Solver<Grid>::applyScalarBc(ScalarField& sc) {
204 for (
int f = 0; f < 6; ++f)
205 if (sc.bc[f] != 0 && touchesGlobalFace(f))
210bool Solver<Grid>::touchesGlobalFace(
int f)
const {
211#ifdef PECLET_FLOW_MPI
214 const int o = (a == 0) ? og_.
x : (a == 1) ? og_.y : og_.z;
215 const int n = (a == 0) ? nx_ : (a == 1) ? ny_ : nz_;
216 const int gn = (a == 0) ? gnx_ : (a == 1) ? gny_ : gnz_;
217 return (f % 2 == 0) ? (o == 0) : (o + n == gn);
225void Solver<Grid>::applyScalarBcStencilVar(ScalarField& sc) {
226 for (
int f = 0;
f < 6; ++
f) {
227 if (
sc.bc[f] != 2 || !touchesGlobalFace(f))
229 const int a =
f / 2,
side =
f % 2;
238void Solver<Grid>::applyScalarBcStencil(ScalarField& sc) {
239 for (
int f = 0;
f < 6; ++
f) {
240 if (
sc.bc[f] != 2 || !touchesGlobalFace(f))
242 const int a =
f / 2,
side =
f % 2;
253 const double wa = u_.
w[a];
254 const int t1 = (a + 1) % 3,
t2 = (a + 2) % 3;
255 const int nt1 = (
t1 == 0) ? nx_ : (
t1 == 1) ? ny_ : nz_;
256 const int nt2 = (
t2 == 0) ? nx_ : (
t2 == 1) ? ny_ : nz_;
257 const int na = (a == 0) ? nx_ : (a == 1) ? ny_ : nz_;
258 const long sx = 1, sy = e_.
x, sz = (
long)e_.
x * e_.
y;
259 const long sa = (a == 0) ?
sx : (a == 1) ? sy : sz;
260 const long st1 = (
t1 == 0) ?
sx : (
t1 == 1) ? sy : sz;
261 const long st2 = (
t2 == 0) ?
sx : (
t2 == 1) ? sy : sz;
262 const int aInner = (side == 0) ?
G : (
G + na - 1);
264 Kokkos::parallel_for(
268 const double D = kc(i) *
wa;
269 AC(i) += D + band(i);
276 const double D =
Din * u_.
w[a];
277 const int t1 = (a + 1) % 3,
t2 = (a + 2) % 3;
278 const int nt1 = (
t1 == 0) ? nx_ : (
t1 == 1) ? ny_ : nz_;
279 const int nt2 = (
t2 == 0) ? nx_ : (
t2 == 1) ? ny_ : nz_;
280 const int na = (a == 0) ? nx_ : (a == 1) ? ny_ : nz_;
281 const long sx = 1, sy = e_.
x, sz = (
long)e_.
x * e_.
y;
282 const long sa = (a == 0) ?
sx : (a == 1) ? sy : sz;
283 const long st1 = (
t1 == 0) ?
sx : (
t1 == 1) ? sy : sz;
284 const long st2 = (
t2 == 0) ?
sx : (
t2 == 1) ? sy : sz;
285 const int aInner = (side == 0) ?
G : (
G + na - 1);
287 Kokkos::parallel_for(
293 AC(i) += D + band(i);
300 const int t1 = (a + 1) % 3,
t2 = (a + 2) % 3;
301 const int nt1 = (
t1 == 0) ? nx_ : (
t1 == 1) ? ny_ : nz_;
302 const int nt2 = (
t2 == 0) ? nx_ : (
t2 == 1) ? ny_ : nz_;
303 const int na = (a == 0) ? nx_ : (a == 1) ? ny_ : nz_;
304 const long sx = 1, sy = e_.
x, sz = (
long)e_.
x * e_.
y;
305 const long sa = (a == 0) ?
sx : (a == 1) ? sy : sz;
306 const long st1 = (
t1 == 0) ?
sx : (
t1 == 1) ? sy : sz;
307 const long st2 = (
t2 == 0) ?
sx : (
t2 == 1) ? sy : sz;
308 const int aInner = (side == 0) ?
G : (
G + na - 1);
309 const int dir = (side == 0) ? -1 : +1;
315 Kokkos::parallel_for(
319 for (
int L = 1; L <= 2; ++L) {
321 const long icell = base - (
long)dir * (L - 1) *
sa;
ScalarField & scalarField(const std::string &name)
void fillGhosts(CCField f)
void patchScalarDirichletFaceVar(CCField AC, CCField band, CCField kc, int a, int side)
CCField addField(const std::string &name)
void advanceScalarCutCell(ScalarField &sc)
void addScalar(const std::string &name, double D, int scheme, int iters, bool cutcell=false)
void applyScalarBcFace(CCField c, int a, int side, int type, double val, bool edges=false)
void setScalarBc(const std::string &name, int face, int type, double value)
void pcBudgetPost(ScalarField &sc)
WO-P3f, part 2: the state AFTER the energy solve, the heat the plane-anchored rows actually delivered...
void pcBudgetPre(ScalarField &sc)
WO-P3f, the energy-budget instrument, part 1: the state BEFORE the energy solve, and the class-change...
bool hasScalar(const std::string &name) const
void pcCarryApply(ScalarField &sc)
WO-P3f: consume pcCarrySrc_ into the energy solve's time base.
void patchScalarDirichletFace(CCField AC, CCField band, double Din, int a, int side)
void scalarDirichletMask(const std::string &name)
Allocate (idempotently) the per-cell Dirichlet mask + value of a registered scalar.
void scalarMaskRhs(CCField b, CCField c, CCConst mask, CCConst val, C3 e, int g)
void scalarMaskGfm2(CCField AC, CCField AW, CCField AE, CCField AS, CCField AN, CCField AB, CCField AT, CCField gfmB, CCConst ox, CCConst oy, CCConst oz, CCConst mask, CCConst tgam, CCConst gnx, CCConst gny, CCConst gnz, CCConst gphi, CCConst kap, CCConst kc, double Dconst, bool useK, double thMin, double thMax, int order, bool useKappa, C3 e, int g, double wx=1.0, double wy=1.0, double wz=1.0, vof::VofMetric gm=vof::VofMetric{})
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, double wx=1.0, double wy=1.0, double wz=1.0)
void scalarAddGfmRhs(CCField b, CCConst gfmB, CCConst mask, C3 e, int g)
void scalarMaskGfm(CCField AC, CCField AW, CCField AE, CCField AS, CCField AN, CCField AB, CCField AT, CCField gfmB, CCConst ox, CCConst oy, CCConst oz, CCConst mask, CCConst tgam, CCConst gnx, CCConst gny, CCConst gnz, CCConst gphi, CCConst kc, double Dconst, bool useK, double thMin, double thMax, C3 e, int g, double wx=1.0, double wy=1.0, double wz=1.0, vof::VofMetric gm=vof::VofMetric{})
void scalarMaskStencil(CCField AC, CCField AW, CCField AE, CCField AS, CCField AN, CCField AB, CCField AT, CCConst mask, C3 e, int g)
Kokkos::View< double *, CCMem > CCField
void cutcellSmoothColor(CCField phi, CCConst b, OpV AC, OpV AW, OpV AE, OpV AS, OpV AN, OpV AB, OpV AT, C3 e, C3 og, int g, int color)
Kokkos::DefaultExecutionSpace CCExec
void scalarBuildDiffusionVarK(CCField AC, CCField AW, CCField AE, CCField AS, CCField AN, CCField AB, CCField AT, CCConst ox, CCConst oy, CCConst oz, CCConst kc, CCConst rcp, CCConst mask, double idt, C3 e, int g, double wx=1.0, double wy=1.0, double wz=1.0)
void scalarBuildRhsHeat(CCField b, CCConst cOld, CCConst rcp, double idt, C3 e, int g)
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 w[3]
w_a = 1 / h_a'^2 (<= 1)
vof::VofMetric vofMetric() const
static constexpr double AC