8#ifndef PECLET_FLOW_FLOW_IBM_PROJECT_HPP
9#define PECLET_FLOW_FLOW_IBM_PROJECT_HPP
46 const double ts0 = phaseTick();
47 tPredictor_ = tMomentum_ = tProjection_ = 0.0;
48 lastMomentumSweeps_ = 0;
49 lastMomentumResid_ = -1.0;
62 const double _t0 = vofTick();
81 const double _t0 = vofTick();
91 if (porous_ && porousCons_)
96 if (((varProps_ || varRho_ || hasDrag_ || (porous_ && porousCons_)) || dtDirty_) &&
102 for (
int c = 0; c < 3; ++c)
103 Kokkos::deep_copy(old_[c], C[c].u);
104 if (cutcellPressure_ && incremental_) {
121 coeffBuiltThisStep_ =
false;
122 if (pWritten_ || pbWritten_) {
123 pbValid_ = pWritten_ && pbWritten_;
124 pWritten_ = pbWritten_ =
false;
133 bfpOpenNotice_ =
true;
135#ifdef PECLET_FLOW_MPI
141 "peclet::flow SolverColocated: the balanced-force projection (default ON on "
142 "variable density / surface tension) is OFF: it does not support "
143 "inflow/outflow domain faces (v1). Call set_balanced_force_projection(False) "
144 "to silence this notice.\n");
149 const double tp0 = phaseTick();
150 lastOuterIters_ =
outer + 1;
152 for (
int c = 0; c < 3; ++c)
153 Kokkos::deep_copy(prev_[c], C[c].u);
154 if (advect_ || hasBc_ || (Grid::collocated && faceInterp_ >= 5 && faceInterp_ <= 7))
155 for (
int c = 0; c < 3; ++c)
171 if (porous_ && advect_)
179 for (
int c = 0; c < 3; ++c)
189 const double _t0 = vofTick();
190 for (
int c = 0; c < 3; ++c)
202 for (
int c = 0; c < 3; ++c)
208 for (
int c = 0; c < 3; ++c)
213 if (useVelocityMg_ && advect_ &&
222 const double tp1 = phaseTick();
224 for (
int c = 0; c < 3; ++c)
231 if constexpr (!Grid::collocated) {
233 for (
int c = 0; c < 3; ++c) {
234 if (uStar_[c].extent(0) != n_)
235 uStar_[c] =
CCField(
"uStar", n_);
236 Kokkos::deep_copy(uStar_[c], C[c].u);
241 const double tp2 = phaseTick();
248 if (porous_ && !cutcellPressure_)
249 throw std::runtime_error(
250 "set_porous_continuity(True) requires the cut-cell pressure operator: call "
251 "set_solid(...) or set_pressure_geometry(all-fluid SDF) before stepping (a "
252 "domain-BC-only box otherwise runs with NO continuity constraint at all)");
253 if (cutcellPressure_)
255 tProjection_ += phaseTick() -
tp2;
260 if (cutcellPressure_)
264 for (
int c = 0; c < 3; ++c)
266 lastOuterCorr_ =
corr;
267 if (
corr < outerTol_)
297 if (hasOutflow_ && backflowBeta_ <= 0.0 && !backflowWarned_) {
299 if (
ob.reversed > 0) {
300 backflowWarned_ =
true;
302#ifdef PECLET_FLOW_MPI
308 "peclet::flow WARNING: reversed flow on an OUTFLOW face (max u.n = -%.3e, "
309 "%.1f%% of the outlet area, kinetic-energy influx %.3e) with the backflow "
310 "stabilization OFF. The zero-gradient outflow is only conditionally "
311 "energy-stable under reversal (the re-entering flux carries the boundary "
312 "cell's own velocity back in with no sink); this is the configuration in "
313 "which the literature's backflow divergence occurs. Call "
314 "set_backflow_stabilization(beta) (default 0.2; beta >= 0.5 is the "
315 "unconditional bound), or lengthen the domain so the recirculation closes "
316 "before the outlet. Monitor with outflow_backflow().\n",
317 ob.maxReverse, 100.0 *
ob.fraction,
ob.energyInflux);
320 tStep_ = phaseTick() -
ts0;
323 tPredSum_ += tPredictor_;
324 tMomSum_ += tMomentum_;
325 tProjSum_ += tProjection_;
332 if (superficialAxis_ < 0)
334 const int a = superficialAxis_;
335 if (bc_[2 * a] != 0 || bc_[2 * a + 1] != 0)
336 throw std::runtime_error(
337 "set_superficial_velocity: the axis carries a domain boundary condition; a uniform "
338 "shift of the normal velocity is divergence-free only on a PERIODIC axis");
340 throw std::runtime_error(
341 "set_superficial_velocity: an immersed solid is present; a uniform shift would move fluid "
342 "through the cut faces (all-fluid domains only)");
347 if (superficialAxis_ < 0)
349 const int a = superficialAxis_;
353 long ncell =
static_cast<long>(nx_) * ny_ * nz_;
354#ifdef PECLET_FLOW_MPI
359 Kokkos::View<double, CCMem>
shift = superficialShift_;
362 Kokkos::parallel_reduce(
363 "superficial_velocity_sum", inner,
365 acc += f((
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y);
367 Kokkos::Sum<double, CCMem>(
shift));
368#ifdef PECLET_FLOW_MPI
371 double loc = 0.0, glob = 0.0;
372 Kokkos::deep_copy(loc,
shift);
374 Kokkos::deep_copy(
shift, glob);
377 Kokkos::parallel_for(
378 "superficial_velocity_to_shift", Kokkos::RangePolicy<CCExec>(
space, 0, 1),
380 Kokkos::parallel_for(
381 "superficial_velocity_shift", inner,
KOKKOS_LAMBDA(
int x,
int y,
int z) {
382 f((
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y) +=
shift();
391 return Grid::collocated && (varRho_ ||
csfActive());
396 if constexpr (Grid::collocated) {
397 if (colSchemeAuto_ && ghostProjection_) {
398 ghostProjection_ =
false;
402 "peclet::flow SolverColocated: AUTO scheme fell back to gauge-exact (%s is rung V8 "
403 "and the ghost projection v1 does not support it). Select explicitly with "
404 "set_collocated_scheme to silence this notice.\n",
412 for (
int c = 0; c < 3; ++c)
413 if (faceAcc_[c].extent(0) != n_)
414 faceAcc_[c] =
CCField(
"faceAcc", n_);
423 throw std::runtime_error(
425 ": variable density / surface tension on SolverColocated is rung V8 and is ALL-FLUID "
426 "only (set_pressure_geometry). Immersed solids on this path are the next package "
427 "(doc/collocated_multiphase_solids_plan.md) — not this rung.");
428 if (ghostProjection_)
429 throw std::runtime_error(
431 ": the ghost projection (v1) does not support variable density; select "
432 "set_collocated_scheme(\"gauge-exact\") (the AUTO fallback already does).");
433 if (rhoFaceHarmonic_)
434 throw std::runtime_error(
436 ": set_rho_face_harmonic is not wired into the collocated variable-density pair (the "
437 "pressure force and the face coefficient would use different rho_f). Staggered only.");
439 throw std::runtime_error(
441 ": variable density / surface tension on SolverColocated needs the incremental pressure "
442 "(diagnostics.set_incremental_pressure(True)): the pressure force lives inside the "
443 "implicit predictor, and the non-incremental (Chorin) step has none, so its steady state "
444 "would depend on dt.");
469 return lastBalancedForceIters_;
474 return lastBalancedForceFailed_;
479 return balancedForceFailures_;
496 for (
int f = 0; f < 6; ++f)
497 if (bc_[f] == 2 || bc_[f] == 3)
504 const std::string m = std::string(
who) +
": the balanced-force projection ";
506 throw std::runtime_error(m +
507 "does not support the porous (volume-averaged) continuity: the "
508 "VANS operator carries eps and the drag relaxation (CFD-DEM is out "
509 "of scope). Call set_balanced_force_projection(False).");
511 if constexpr (Grid::collocated)
514 throw std::runtime_error(m +
515 "does not support the ghost projection (its overlay does not reach "
516 "the balanced face force yet). Call set_balanced_force_projection"
518 if (fluidOnlyMode_ == 2)
519 throw std::runtime_error(m +
"does not support set_fluid_only_constraint(2).");
521 throw std::runtime_error(m +
"does not support the block CSF (enable_vof_block_csf).");
522 for (
int f = 0; f < 6; ++f)
523 if (bc_[f] == 2 || bc_[f] == 3)
524 throw std::runtime_error(
526 "does not support inflow/outflow domain faces (v1: the operator-vs-flux openness rule "
527 "at inflow and the outflow planes are not wired). Call "
528 "set_balanced_force_projection(False).");
530 throw std::runtime_error(m +
"needs the incremental pressure (it re-splits P).");
532 if (!cutcellPressure_)
533 throw std::runtime_error(
534 m +
"needs the cut-cell pressure operator (set_solid or set_pressure_geometry).");
535 if constexpr (Grid::collocated)
537 throw std::runtime_error(
539 "has nothing to balance on the constant-density collocated path without surface "
540 "tension (its pressure force is the gauge-exact cell gradient, not the face "
541 "integral). It applies to variable density / surface tension on SolverColocated "
542 "and to every Solver configuration. Call set_balanced_force_projection(False).");
553 const double fc = f_[c];
555 const bool haveFb = hasCellForce_;
560 Kokkos::parallel_for(
561 "peclet::flow::bfp_face_force",
MD(
space, {
G,
G,
G}, {e.x -
G + 1, e.y -
G + 1, e.z -
G + 1}),
563 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
569 if (Grid::collocated || csfMode_ == 0)
577 const double rho0 = rho_;
578 const bool harm = rhoFaceHarmonic_;
579 Kokkos::parallel_for(
580 "peclet::flow::bfp_face_coeff",
581 MD(
space, {
G,
G,
G}, {e.x -
G + 1, e.y -
G + 1, e.z -
G + 1}),
583 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
584 const double cf =
harm ?
rho0 * (rho(i) + rho(i - s)) / (2.0 * rho(i) * rho(i - s))
585 :
rho0 / (0.5 * (rho(i) + rho(i - s)));
597 coeffBuiltThisStep_ =
true;
600 if (pb1_.extent(0) != n1_)
605 for (
int c = 0; c < 3; ++c)
617#ifdef PECLET_FLOW_MPI
625 Kokkos::deep_copy(pb1_, 0.0);
631 Kokkos::parallel_for(
632 "peclet::flow::bfp_negdiv", Kokkos::RangePolicy<CCExec>(
space, 0, n1_),
636 const double rtol = useChebyshev_ ? chebRtol_ : pcgRtol_;
637 const double bref = std::max(mg_.
rhsNorm(rhs1_, r_), 1e-300);
638 const double r0 = mg_.
residualNorm(rhs1_, pb1_, r_, Ap_);
639 if (r0 > rtol *
bref) {
649 Kokkos::parallel_reduce(
650 "peclet::flow::bfp_nonfinite",
653 const long i = (
long)x + (
long)y *
e1.x + (
long)z * (
long)
e1.x *
e1.y;
654 if (!Kokkos::isfinite(
x1(i)))
660#ifdef PECLET_FLOW_MPI
670 lastBalancedForceIters_ = iters;
671 lastBalancedForceFailed_ = failed;
676 ++balancedForceFailures_;
677 if (!bfpFailWarned_) {
678 bfpFailWarned_ =
true;
680#ifdef PECLET_FLOW_MPI
686 "peclet::flow WARNING: the balanced-force pre-projection solve failed (driver "
687 "breakdown or a non-finite result, %ld iterations); P and p_balanced were "
688 "kept for this step. Further failures are counted silently in "
689 "diagnostics.balanced_force_failures().\n",
703 const C3 e1 = e1_, e2 = e_;
704 const bool resplit = !pbValid_;
705 Kokkos::parallel_for(
710 const double xv =
x1(i1);
744 mg_.
solveChebyshev(rhs1_, pb1_, chebMaxit_, chebRtol_, 2, 2, 12, bfpChebA_, bfpChebB_);
745 if (it >= chebMaxit_) {
751 mg_.
solveChebyshev(rhs1_, pb1_, chebMaxit_, chebRtol_, 2, 2, 12, bfpChebA_, bfpChebB_);
757 if (zp1_.extent(0) != n1_)
759 return mg_.
solveFCG(rhs1_, pb1_, r_, pp_, z_, zp1_, Ap_, pcgMaxit_, pcgRtol_, 2, 2, 12,
nullptr,
760 0,
C3{nx_, ny_, nz_});
762 return mg_.
solvePCG(rhs1_, pb1_, r_, pp_, z_, Ap_, pcgMaxit_, pcgRtol_, 2, 2, 12,
nullptr, 0,
769 const double idiag = rho_ / dt_, fc = f_[c], rho = rho_,
wc = u_.
w[c];
782 const long strd = (c == 0) ? 1 : (c == 1) ? e_.
x : (
long)e_.
x * e_.
y;
787 const bool incr = cutcellPressure_ && incremental_, adv = advect_ && !
pureFou,
795 const int sch = advScheme_;
805 const bool tg = Grid::collocated && faceInterp_ == 5 &&
incr;
807 const bool wg = Grid::collocated && (faceInterp_ == 6 || faceInterp_ == 7) &&
incr;
812 const bool gg = Grid::collocated && (ghostProjection_ || faceInterp_ == 9) &&
incr;
813 if constexpr (Grid::collocated) {
823 true, c, e_,
G, u_.
w[c]);
838 const bool pc = porous_ && advect_;
840 const bool wd = Grid::collocated && faceInterp_ >= 5 && faceInterp_ <= 7;
841 if constexpr (Grid::collocated)
844 FPC(C[c].AN),
FPC(C[c].AB),
FPC(C[c].AT), e_,
G);
847 u_.
w[2], u_.
hp[0], u_.
hp[1], u_.
hp[2]);
855 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
856 double aK = 0.0,
aF = 0.0;
858 sadv::ViewAcc Ua{
U, e.x, e.y},
Va{V, e.x, e.y},
Wa{W, e.x, e.y},
Fa{
aP, e.x, e.y};
875 ? ((tg || wg ||
gg) ?
gpw(i) :
wc * (0.5 * (P((
long)i +
strd) - P((
long)i -
strd))))
876 :
wc * (P(i) - P((
long)i -
strd));
879 const double bfv = idiag * cs(i) *
un(i) + cs(i) * (fc -
gp);
882 const double comp =
pc ? rho *
uu(i) * 0.5 * (dv(i) + dv((
long)i -
strd)) : 0.0;
883 bb(i) =
rs(i) * (idiag *
un(i) + fc - rho *
aK + rho *
aF + comp -
gp) +
892 const double idiag = rho_ / dt_, fc = f_[c], rho = rho_,
wc = u_.
w[c];
906 const long strd = (c == 0) ? 1 : (c == 1) ? e_.
x : (
long)e_.
x * e_.
y;
908 const bool incr = cutcellPressure_ && incremental_, adv = advect_ && !
pureFou,
911 const int sch = advScheme_;
915 const bool pc = porous_ && advect_;
917 const bool tg = Grid::collocated && faceInterp_ == 5 &&
incr;
918 const bool gg = Grid::collocated && (ghostProjection_ || faceInterp_ == 9) &&
920 if constexpr (Grid::collocated) {
927 true, c, e_,
G, u_.
w[c]);
932 Kokkos::parallel_for(
933 "rhs_forced",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
935 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
936 double aK = 0.0,
aF = 0.0;
938 sadv::ViewAcc Ua{
U, e.x, e.y},
Va{V, e.x, e.y},
Wa{W, e.x, e.y},
Fa{
aP, e.x, e.y};
949 ? ((tg ||
gg) ?
gpw(i) :
wc * (0.5 * (P((
long)i +
strd) - P((
long)i -
strd))))
950 :
wc * (P(i) - P((
long)i -
strd));
951 const double comp =
pc ? rho *
uu(i) * 0.5 * (dv(i) + dv((
long)i -
strd)) : 0.0;
954 const double fbU = Grid::atVelocity(
fb, i,
strd);
955 bb(i) =
rs(i) * (idiag *
un(i) + fc +
fbU - rho *
aK + rho *
aF + comp -
gp) +
962 const double idt = 1.0 / dt_, fc = f_[c],
wc = u_.
w[c];
979 const bool incr = cutcellPressure_ && incremental_, adv = advect_ && !
pureFou,
982 const int sch = advScheme_;
986 const bool pc = porous_ && advect_;
992 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
993 const double rhoF = 0.5 * (rf(i) + rf(i -
strd));
994 double aK = 0.0,
aF = 0.0;
996 sadv::ViewAcc Ua{
U, e.x, e.y},
Va{V, e.x, e.y},
Wa{W, e.x, e.y},
Fa{
aP, e.x, e.y};
1002 const double gp = !
incr ? 0.0
1003 : Grid::collocated ?
wc * (0.5 * (P((
long)i +
strd) - P((
long)i -
strd)))
1004 :
wc * (P(i) - P((
long)i -
strd));
1005 const double fbF = Grid::atVelocity(
fb, i,
strd);
1006 const double comp =
pc ?
rhoF *
uu(i) * 0.5 * (dv(i) + dv((
long)i -
strd)) : 0.0;
1012template <
class Gr
id>
1015 const double idt = 1.0 / dt_, fc = f_[c],
wc = u_.
w[c];
1022 const bool incr = cutcellPressure_ && incremental_;
1025 Kokkos::parallel_for(
1026 "rhs_var_mom",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1028 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
1029 const double rhoF = 0.5 * (rf(i) + rf(i -
strd));
1030 const double gp = !
incr ? 0.0
1031 : Grid::collocated ?
wc * (0.5 * (P((
long)i +
strd) - P((
long)i -
strd)))
1032 :
wc * (P(i) - P((
long)i -
strd));
1033 const double fbF = Grid::atVelocity(
fb, i,
strd);
1048template <
class Gr
id>
1055 const bool incr = cutcellPressure_ && incremental_;
1060 rho_, f_[c],
incr, 1.0, sc, e_,
G, u_.
w[c]);
1063 haveRho, rho_, sigmaCsf_, 1.0 / u_.
w[c], 1.0, sc, e_,
G);
1068 const double idt = 1.0 / dt_, rhoIdtC = rho_ / dt_,
rhoK = rho_;
1073 const bool haveFb = hasCellForce_;
1081 const int sch = advScheme_;
1083 Kokkos::parallel_for(
1084 "rhs_colo_var",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1086 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
1087 const double rhoC = haveRho ? rf(i) :
rhoK;
1088 const double dg = haveRho ?
rhoC * idt : rhoIdtC;
1089 double aK = 0.0,
aF = 0.0;
1091 sadv::ViewAcc Ua{
U, e.x, e.y},
Va{V, e.x, e.y},
Wa{W, e.x, e.y},
Fa{
aP, e.x, e.y};
1097 const long j = i + (
long)((c == 0) ? 1 : (c == 1) ? e.x : (
long)e.x * e.y);
1098 const double oLo = o(i),
oHi = o(j);
1107template <
class Gr
id>
1110 Kokkos::deep_copy(tgp_, f);
1114 const double eps = rotFilterEps_;
1117 Kokkos::parallel_for(
1118 "peclet::flow::rot_filter",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1120 const long sy = e.x, sz = (
long)e.x * e.y;
1121 const long i = (
long)x + (
long)y * sy + (
long)z * sz;
1122 const long sa = (axis == 0) ? 1 : (axis == 1) ? sy : sz;
1125 const bool am =
sd(i -
sa) >= 0.0, ap =
sd(i +
sa) >= 0.0;
1128 sm = 0.25 * (src(i -
sa) + 2.0 * src(i) + src(i +
sa));
1130 sm = 0.5 * (src(i) + src(i +
sa));
1132 sm = 0.5 * (src(i) + src(i -
sa));
1140 f(i) = eps * src(i) + (1.0 - eps) *
sm;
1144template <
class Gr
id>
1147 if (!coeffBuiltThisStep_)
1154template <
class Gr
id>
1159 if constexpr (Grid::collocated) {
1164 for (
int c = 0; c < 3; ++c)
1175 }
else if (faceInterp_ == 5 || faceInterp_ == 7)
1181 faceFieldValid_ =
true;
1182 if (ghostProjection_) {
1188 throw std::runtime_error(
"ghost projection: call set_solid after set_ghost_projection");
1189 if (porous_ || varRho_ || useChebyshev_)
1190 throw std::runtime_error(
1191 "ghost projection: porous/variable-rho/Chebyshev unsupported (v1)");
1195 C3{nx_, ny_, nz_}, e_,
G, distributed_);
1199 for (
int c = 0; c < 3; ++c)
1208 }
else if (ghostProjection_) {
1213 throw std::runtime_error(
"ghost projection: call set_solid after set_ghost_projection");
1214 if (porous_ || varRho_ || useChebyshev_)
1215 throw std::runtime_error(
1216 "ghost projection: porous/variable-rho/Chebyshev unsupported (v1)");
1220 C3{nx_, ny_, nz_}, e_,
G, distributed_);
1237 CCField d = div_, dd = depsdt_,
ep = epsField_,
epp = epsPrev_;
1238 const double idt = 1.0 / dt_;
1239 const bool useDt = porousDepsDt_;
1241 Kokkos::parallel_for(
1242 "peclet::flow::deps_dt",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1244 const long i = (
long)x + (
long)y * e.x + (
long)z * e.x * e.y;
1245 dd(i) = (
ep(i) -
epp(i)) * idt;
1256 Kokkos::parallel_for(
1257 "negdiv", Kokkos::RangePolicy<CCExec>(
space, 0, n1_),
1260 if (fluidOnlyMode_ == 2) {
1264 throw std::runtime_error(
"set_fluid_only_constraint(2): Chebyshev unsupported (v1)");
1268 const C3 e1 = e1_, e2 = e_;
1269 Kokkos::parallel_for(
1274 r((
long)(x + 1) + (
long)(y + 1) *
e1.x + (
long)(z + 1) * (
long)
e1.x *
e1.y) = 0.0;
1279template <
class Gr
id>
1295 if (rhoFaceHarmonic_)
1297 CCConst(rho1_), rho_, e1_, 1);
1307 CCField cc[3] = {cx1_, cy1_, cz1_};
1309 for (
int a = 0; a < 3; ++a)
1310 if (bc_[2 * a + 1] == 3 && touchesGlobalFace(2 * a + 1))
1320 chebWarmOk_ = chebWarmOk_ || chebBoundsSet_;
1321 chebBoundsSet_ =
false;
1337 }
else if (porousCons_) {
1338 Kokkos::deep_copy(beta1_, 0.0);
1346 }
else if (hasDrag_) {
1360 chebWarmOk_ = chebWarmOk_ || chebBoundsSet_;
1361 chebBoundsSet_ =
false;
1365template <
class Gr
id>
1372 Kokkos::deep_copy(phi1_, 0.0);
1379 if (fluidOnlyMode_ == 2) {
1386 const C3 e1 = e1_, e2 = e_;
1387 Kokkos::parallel_for(
1392 ph((
long)(x + 1) + (
long)(y + 1) *
e1.x + (
long)(z + 1) * (
long)
e1.x *
e1.y) = 0.0;
1399 B3 e{e_.
x, e_.
y, e_.
z};
1400 for (
int a = 0; a < 3; ++a)
1401 for (
int s = 0; s < 2; ++s)
1402 if (bc_[2 * a + s] == 3 && touchesGlobalFace(2 * a + s))
1407template <
class Gr
id>
1410 if (useChebyshev_) {
1420 if (!chebBoundsSet_) {
1423 warm ? ES::Warm : ES::ColdKeep);
1428 chebBoundsSet_ =
true;
1434 if (chebX0_.extent(0) !=
x1.extent(0))
1435 chebX0_ =
CCField(
"chebX0",
x1.extent(0));
1436 Kokkos::deep_copy(chebX0_,
x1);
1440 ++chebColdRestarts_;
1443 Kokkos::deep_copy(
x1, chebX0_);
1445 Kokkos::deep_copy(
x1, 0.0);
1449 }
else if (ghostProjection_) {
1455#ifdef PECLET_FLOW_MPI
1458 mg_.
solveBiCGStab(
rhs1,
x1, r_, gpRh_, pp_, Ap_, gpT_, z_, gpZ2_, pcgMaxit_, pcgRtol_, 2,
1459 2, 12, gpOv_, gpNRows_,
C3{nx_, ny_, nz_}, gpX2_,
velDev_.get(), e_);
1462 iters = mg_.
solveBiCGStab(
rhs1,
x1, r_, gpRh_, pp_, Ap_, gpT_, z_, gpZ2_, pcgMaxit_, pcgRtol_,
1463 2, 2, 12, gpOv_, gpNRows_,
C3{nx_, ny_, nz_});
1476 auto idMap = gpIdMap_;
1478 const C3 e1 = e1_, e2 = e_;
1479 const int lnx = nx_,
lny = ny_;
1480 Kokkos::parallel_for(
1487 bool dec = sg(
i2) < 0.0;
1489 const int s = idMap((
long)x + (
long)y *
lnx + (
long)z * (
long)
lnx *
lny);
1490 if (s >= 0 && ov.coupled(s) == 0)
1497 }
else if (useFcg_) {
1502 if (zp1_.extent(0) != n1_)
1504 iters = mg_.
solveFCG(
rhs1,
x1, r_, pp_, z_, zp1_, Ap_, pcgMaxit_, pcgRtol_, 2, 2, 12,
1505 fluidOnlyMode_ == 2 ? &starOv_ :
nullptr, nStar_,
C3{nx_, ny_, nz_});
1507 iters = mg_.
solvePCG(
rhs1,
x1, r_, pp_, z_, Ap_, pcgMaxit_, pcgRtol_, 2, 2, 12,
1508 fluidOnlyMode_ == 2 ? &starOv_ :
nullptr, nStar_,
C3{nx_, ny_, nz_});
1513template <
class Gr
id>
1518template <
class Gr
id>
1520 if constexpr (Grid::collocated) {
1526 B3 e{e_.
x, e_.
y, e_.
z};
1527 for (
int a = 0; a < 3; ++a)
1528 for (
int s = 0; s < 2; ++s) {
1529 const int t = bc_[2 * a + s];
1530 if (t != 0 && t != 3 && touchesGlobalFace(2 * a + s))
1545 if (fluidOnlyMode_ == 2)
1547 C3{nx_, ny_, nz_}, e_,
G, e_,
G, exactResidual_, u_.
w[0], u_.
w[1], u_.
w[2]);
1553 B3 e{e_.x, e_.y, e_.z};
1557 const bool var = varRho_ && !porous_ && outflowRhoCorr_;
1558 for (
int a = 0; a < 3; ++a)
1559 if (bc_[2 * a + 1] == 3 && touchesGlobalFace(2 * a + 1)) {
1576 for (
int cc = 0; cc < 3; ++cc)
1579 varRho_, rho_,
strideOf(cc), e_,
G, u_.
w[cc]);
1580 }
else if (ghostProjection_ || faceInterp_ == 9) {
1586 for (
int cc = 0; cc < 3; ++cc) {
1591 }
else if (faceInterp_ == 5) {
1595 for (
int cc = 0; cc < 3; ++cc) {
1600 }
else if (faceInterp_ == 6 || faceInterp_ == 7) {
1609 if (porous_ && porousCons_)
1612 CCConst(dragBeta_), hasDrag_, rho_ / dt_, e_,
G, u_.
w[0], u_.
w[1],
1617 rho_ / dt_, e_,
G, u_.
w[0], u_.
w[1], u_.
w[2]);
1618 else if (varRho_ && rhoFaceHarmonic_)
1620 u_.
w[0], u_.
w[1], u_.
w[2]);
1623 u_.
w[0], u_.
w[1], u_.
w[2]);
1628 B3 e{e_.
x, e_.
y, e_.
z};
1638 const bool var = varRho_ && !porous_ && outflowRhoCorr_;
1639 for (
int a = 0; a < 3; ++a)
1640 if (bc_[2 * a + 1] == 3 && touchesGlobalFace(2 * a + 1)) {
1646 outflowCorrValid_ =
true;
1652 for (
int c = 0; c < 3; ++c)
1656template <
class Gr
id>
1662 if (rotFilter_ && rotationalP_)
1663 for (
int a = 0; a < 3; ++a)
1666 CCField P = P_, ph = phi_, d = div_;
1672 const double ct = pressUnderRelax_ * rho_ / dt_, mu = rotationalP_ ? rotWeight_ * mu_ : 0.0;
1678 if (varRotMode_ == 1) {
1680 const double chi = varRotChi_;
1681 Kokkos::parallel_for(
1682 "press_var_full", Kokkos::RangePolicy<CCExec>(
space, 0, n_),
1685 const double muRot = (varRotMode_ == 2) ? 0.0 : varRotChi_ *
minMuInner();
1686 Kokkos::parallel_for(
1687 "press_var_min", Kokkos::RangePolicy<CCExec>(
space, 0, n_),
1690 }
else if (rotWallW_ > 0.0 && rotationalP_) {
1700 const double w0 = rotWallW_,
muF = rotWeight_ * mu_;
1702 Kokkos::parallel_for(
1703 "press_wallblend", Kokkos::RangePolicy<CCExec>(
space, 0, n_),
1705 const long sy = e.x, sz = (
long)e.x * e.y;
1706 const int x = (int)(i % e.x), y = (int)((i / e.x) % e.y), z = (
int)(i / sz);
1708 if (x > 0 && y > 0 && z > 0 && x < e.x - 1 && y < e.y - 1 && z < e.z - 1 &&
1710 (
sd(i - 1) < 0.0 ||
sd(i + 1) < 0.0 ||
sd(i - sy) < 0.0 ||
sd(i + sy) < 0.0 ||
1711 sd(i - sz) < 0.0 ||
sd(i + sz) < 0.0))
1713 P(i) += (
ct + w *
muF) * ph(i) - (1.0 - w) *
muF * d(i);
1716 Kokkos::parallel_for(
1717 "press", Kokkos::RangePolicy<CCExec>(
space, 0, n_),
1723 Kokkos::deep_copy(epsPrev_, epsField_);
int solveBiCGStab(CCField b, CCField x, CCField r, CCField rh, CCField p, CCField v, CCField t, CCField z, CCField z2, int maxit, double rtol, int pre, int post, int bottom, const GpOverlayReal< MReal > &ov, int nOv, C3 nn)
bool chebyshevGuardTripped() const
double residualNorm(CCField b, CCField x, CCField r, CCField Ap)
int solvePCG(CCField b, CCField x, CCField r, CCField p, CCField z, CCField Ap, int maxit, double rtol, int pre, int post, int bottom, const StarOverlay *star=nullptr, int nStar=0, C3 nnStar=C3{0, 0, 0})
void setOutflowCoefficient(bool on)
void resetAllreduceCounters()
bool eigenWarmReady() const
void setOpenness(CCConst ox, CCConst oy, CCConst oz, double idx2, double idy2, double idz2)
void setBoundaryConditions(const int bc[6])
int solveChebyshev(CCField b, CCField x, int maxit, double rtol, int pre, int post, int bottom, double a, double bnd, bool guard3=false)
void setStopReference(double ref)
void estimateEigenvalues(CCConst seed, double &lmin, double &lmax, int iters, int pre, int post, int bottom, EigenStart start=EigenStart::Cold)
int solveFCG(CCField b, CCField x, CCField r, CCField p, CCField z, CCField zp, CCField Ap, int maxit, double rtol, int pre, int post, int bottom, const StarOverlay *star=nullptr, int nStar=0, C3 nnStar=C3{0, 0, 0})
double rhsNorm(CCField b, CCField scratch)
void projectAssembleDivergence()
void projectPressureUpdate()
void applyVelocityBcAll(int fold, bool doOutflow)
void fillVelGhosts(int comp, int fold)
void addCsfRhs(int c, CCField dst, bool rowScaled, bool faceRange=false)
void registerBalancedForceState()
void buildRhsVarMom(int c)
void phaseChangeStep()
The in-step driver: everything applyPhaseChange does, at the head of step().
bool balancedForceProjection() const
void buildOpenFaceField()
Build ufOpen_ = the face field with each open (outflow) domain face overwritten by its zero-gradient ...
long solveBalancedForceSystem(double bref, double r0)
void fillDragBetaGhosts()
void fillGhosts(CCField f)
void fillPropGhosts(CCField f, bool edges=false)
void requireCollocatedFaceForceScope(const char *who)
void applyBackflowStab(int c)
void pcApplyDivergenceSource(CCField div)
Subtract the phase-change (and any prescribed) divergence source from div_ so the deflated pressure s...
void addCsfRhsBlocks(int c)
CCField addField(const std::string &name)
void buildRhsColoVar(int c)
void pcUpdateThermalMask()
OutflowBackflow outflowBackflow()
void pcUpdateEnergyProps()
Refresh k(C) and (rho c_p)(C) on the G=2 block from the current colour.
CCConst advVelView(int c) const
The velocity view the advection operators must read for component c: the wall-corrected scratch while...
void copyInner(CCField dst, C3 de, int dg, CCConst src, C3 se, int sg)
double maxAbsDiffInner(CCConst a, CCConst b)
bool ufAdvVelocity() const
Are the advection operators reading the projected face field this step? Collocated grid,...
bool lastBalancedForceFailed() const
CCConst openFaceView(int c) const
Component c of the face field AS THE ADVECTION AND THE DIVERGENCE DIAGNOSTIC MUST READ IT: advFaceVie...
void addWallFluxDivergence(CCField d)
long lastBalancedForceIterations() const
bool hasOpenDomainFace() const
void constraintDivergence(CCConst fx, CCConst fy, CCConst fz, CCField out)
void projectBuildCoefficients()
long balancedForceFailures() const
void applySuperficialVelocity()
void updateVofCurvature()
void applyBalancedForceProjection()
long strideOf(int c) const
void collocatedV8AutoFallback(const char *why)
long solvePressureSystem(CCField rhs1, CCField x1)
void scalarCaptureOpenFaceFlux()
void fillCellForceGhosts()
void superficialVelocityPrecheck() const
bool balancedForceActive() const
void setSolidVelocityMgAuto()
void buildAdvStencil(int c)
void requireBalancedForceScope(const char *who, bool atStep) const
void filterCellField(CCField f, int axis)
void buildAdvStencilVar(int c)
bool ensureAdvStash(int c, bool adv)
bool bcStencilPath() const
bool mixedVelocityMg() const
void addCsfRhsCellInterp(int c, CCField dst, bool rowScaled, bool faceRange=false)
void setBalancedForceProjection(bool enabled)
void buildRhsForced(int c)
void copyBlockShifted(CCField dst, C3 de, CCConst src, C3 se, int off)
void buildBalancedFaceForce(int c)
void fillPorousEpsGhosts()
bool colocatedFaceForce() const
void projectCorrectVelocities()
void restrictAdvVelocities(CCConst u0, CCConst v0, CCConst w0)
double weightSum(double oLo, double oHi)
double cellFromFaces(double aLo, double aHi, double oLo, double oHi)
void stencilMatvec(CCField y, CCConst u, MC AC, MC AW, MC AE, MC AS, MC AN, MC AB, MC AT, C3 e, int g)
void bcCorrectOutflow(BField f, BField phi, B3 ext, int g, int a, double wa=1.0)
void buildRhoCoeffOutflowFace(CCField ca, CCConst oa, CCConst rho, double rho0, C3 e, int g, int a, bool harmonic)
void gpDivergDelta(CCField d, CCConst u, CCConst v, CCConst w, const GpOverlayReal< Real > &ov, int nOv, C3 nn, C3 extb, int gb, bool useGhost=false)
Overlay divergence correction: d(r) = rho_r * (d(r) + closure/BC/explicit face values),...
void buildPorousCoeffDrag(CCField cx, CCField cy, CCField cz, CCConst ox, CCConst oy, CCConst oz, CCConst eps, CCConst beta, double idt, C3 e, int g)
void centerGradOpen(CCField out, CCConst p, CCConst o, int axis, C3 e, int g, double wa=1.0)
void projectCorrectPorousDrag(CCField u, CCField v, CCField w, CCConst phi, CCConst beta, double idt, C3 e, int g, double wx=1.0, double wy=1.0, double wz=1.0)
Kokkos::View< const MReal *, CCMem > FPC
void buildRhoCoeff(CCField cx, CCField cy, CCField cz, CCConst ox, CCConst oy, CCConst oz, CCConst rho, double rho0, C3 e, int g)
void buildPorousCoeffCons(CCField cx, CCField cy, CCField cz, CCConst ox, CCConst oy, CCConst oz, CCConst eps, CCConst beta, bool useBeta, double rhoidt, C3 e, int g)
void bcZeroPressureGhost(BField phi, B3 ext, int g, int a, int s)
void subtractField(CCField u, CCConst d, C3 e, int g)
void transposeGradWallAware(CCField out, CCConst p, CCConst sdf, CCConst o, CCConst xc, bool useCen, int axis, C3 e, int g, double wa=1.0)
void divergOpen(CCConst u, CCConst v, CCConst w, CCConst ox, CCConst oy, CCConst oz, CCField d, C3 e, int g)
void projectCorrect(CCField u, CCField v, CCField w, CCConst phi, C3 e, int g, double wx=1.0, double wy=1.0, double wz=1.0)
void projectCorrectCenterOpen(CCField u, CCField v, CCField w, CCConst phi, CCConst ox, CCConst oy, CCConst oz, C3 e, int g, double wx=1.0, double wy=1.0, double wz=1.0)
void correctCellFaceAverageVar(CCField u, CCConst phi, CCConst rho, CCConst o, bool haveRho, double rho0, long s, C3 e, int g, double wa=1.0)
void projectCorrectPorousCons(CCField u, CCField v, CCField w, CCConst phi, CCConst eps, CCConst beta, bool useBeta, double rhoidt, C3 e, int g, double wx=1.0, double wy=1.0, double wz=1.0)
void buildFaceAccelVar(CCField af, CCConst P, CCConst rho, CCConst fb, bool haveFb, bool haveRho, double rhoC, double fc, bool incr, double scale, long s, C3 e, int g, double wa=1.0)
void centerToFaceWallAware(CCField uf, CCField vf, CCField wf, CCConst U, CCConst V, CCConst W, CCConst sdf, CCConst xcx, CCConst xcy, CCConst xcz, bool useCen, C3 e, int g)
double maxAbsInner(CCConst a, C3 e, int g)
void starCorrectFaces(CCField uf, CCField vf, CCField wf, CCConst phi, const StarOverlay &ov, int nOv, C3 nn, C3 ext, int g, C3 extP, int gP, bool exact, double wx=1.0, double wy=1.0, double wz=1.0)
Fix the face correction at fluid|solid faces: projectCorrect applied -(phi_hi - phi_lo) with the soli...
void projectCorrectVar(CCField u, CCField v, CCField w, CCConst phi, CCConst rho, double rho0, C3 e, int g, double wx=1.0, double wy=1.0, double wz=1.0)
void ccFor3(const char *name, C3 lo, C3 hi, F f)
void centerToFace(CCField uf, CCField vf, CCField wf, CCConst U, CCConst V, CCConst W, C3 e, int g)
void embedViscousApply(CCField Lu, CCConst U, CCConst sdf, CCConst cs, CCConst ox, CCConst oy, CCConst oz, double mu, double idt, C3 e, int g, double wx=1.0, double wy=1.0, double wz=1.0, double hpx=1.0, double hpy=1.0, double hpz=1.0)
Kokkos::View< double *, CCMem > CCField
void buildPorousCoeff(CCField cx, CCField cy, CCField cz, CCConst ox, CCConst oy, CCConst oz, CCConst eps, C3 e, int g)
Kokkos::DefaultExecutionSpace CCExec
void buildRhoCoeffHarm(CCField cx, CCField cy, CCField cz, CCConst ox, CCConst oy, CCConst oz, CCConst rho, double rho0, C3 e, int g)
void projectCorrectCenter(CCField u, CCField v, CCField w, CCConst phi, CCConst ox, CCConst oy, CCConst oz, C3 e, int g, double wx=1.0, double wy=1.0, double wz=1.0)
void centerToFaceMassWeighted(CCField uf, CCField vf, CCField wf, CCConst U, CCConst V, CCConst W, CCConst rho, C3 e, int g)
void divergOpenEps(CCConst u, CCConst v, CCConst w, CCConst ox, CCConst oy, CCConst oz, CCConst eps, CCField d, C3 e, int g)
void projectCorrectVarHarm(CCField u, CCField v, CCField w, CCConst phi, CCConst rho, double rho0, C3 e, int g, double wx=1.0, double wy=1.0, double wz=1.0)
void addFaceAccelCsf(CCField af, CCConst cv, CCConst kp, CCConst kb, CCConst rho, bool haveRho, double rhoC, double sigma, double hGrad, double scale, long s, C3 e, int g)
void gpCenterGrad(CCField out, CCConst p, CCConst sdf, int axis, C3 e, int g, double wa=1.0)
Directional cell-center gradient (collocated ghost path) of a cell field p whose solid-centered rows ...
void bcCorrectOutflowVar(BField f, BField phi, BField rho, double rho0, B3 ext, int g, int a, bool harmonic, double wa=1.0)
void bcNeumannGhost(BField f, B3 ext, int g, int a, int s)
Kokkos::View< const double *, CCMem > CCConst
OUTFLOW REVERSAL CENSUS – the regime in which the zero-gradient (do-nothing) outflow is only conditio...
double w[3]
w_a = 1 / h_a'^2 (<= 1)
double hp[3]
h_a' = h_a / hRef (>= 1, exactly 1 on the finest axis)
double velToInt(int a) const
double curvature
the V3 height-function cascade + the capillary dt check
double csf
the V4 balanced-force CSF added to the three momentum RHSs
double phaseChange
the Part II phase-change stage (mdot, deposit, regression)
static constexpr double AC
static constexpr double U