9#ifndef PECLET_FLOW_FLOW_IBM_CORE_HPP
10#define PECLET_FLOW_FLOW_IBM_CORE_HPP
24 for (
int a = 0; a < 3; ++a) {
25 m.a[a] = u_.
org[a] + 0.5 * u_.
h[a];
36 const std::array<double, 3>& origin,
const std::array<long, 3>& globalCells) {
43 const std::array<double, 3>& origin,
44 const std::array<long, 3>& globalCells) {
48 for (
int a = 0; a < 3; ++a) {
49 if (!(extent[a] > 0.0))
50 throw std::runtime_error(
"physical domain: every extent component must be > 0");
52 throw std::runtime_error(
"physical domain: every cell count must be > 0");
55 for (
int a = 0; a < 3; ++a)
56 hh[a] = extent[a] / (
double)c[a];
68 for (
int a = 1; a < 3; ++a)
69 if (std::fabs(
hh[a] -
hh[0]) > 1e-12 * std::fabs(
hh[0]))
72 for (
int a = 1; a < 3; ++a)
75 for (
int a = 0; a < 3; ++a) {
77 u_.
ext[a] = extent[a];
78 u_.
org[a] = origin[a];
81 u_.
hRef = std::min(
hh[0], std::min(
hh[1],
hh[2]));
82 for (
int a = 0; a < 3; ++a) {
84 u_.
w[a] =
iso ? 1.0 : 1.0 / (u_.
hp[a] * u_.
hp[a]);
104 std::snprintf(
msg,
sizeof msg,
105 "%s: this entry point requires ISOTROPIC cells, but extent/cells gives "
106 "dx=%.17g dy=%.17g dz=%.17g (hRef=%.17g, h'=(%.17g, %.17g, %.17g)).",
107 what, u_.
h[0], u_.
h[1], u_.
h[2], u_.
hRef, u_.
hp[0], u_.
hp[1], u_.
hp[2]);
108 throw std::runtime_error(
msg);
123 return {u_.
h[0], u_.
h[1], u_.
h[2]};
128 return {u_.
org[0], u_.
org[1], u_.
org[2]};
134 return {u_.
ext[0], u_.
ext[1], u_.
ext[2]};
143#ifdef PECLET_FLOW_MPI
147 return {nx_, ny_, nz_};
153 throw std::runtime_error(
"cell_centers: axis must be 0, 1 or 2");
154 const int n[3] = {nx_, ny_, nz_};
155 const int og[3] = {og_.
x, og_.
y, og_.
z};
156 std::vector<double> c((std::size_t)n[axis]);
157 for (
int i = 0; i < n[axis]; ++i)
158 c[(std::size_t)i] = u_.
org[axis] + ((
double)(og[axis] + i) + 0.5) * u_.
h[axis];
169 u_.
hpMax = std::max(u_.
hp[0], std::max(u_.
hp[1], u_.
hp[2]));
176 for (
int a = 0; a < 3; ++a)
179 slipLambda_ = slipPhys_ * u_.
lenToInt();
180 for (
auto& sc : scalars_)
183 for (
auto&
cl : closures_)
185 for (
int face = 0; face < 6; ++face) {
186 for (
int a = 0; a < 3; ++a)
187 bcVel_[face][a] = bcVelPhys_[face][a] * u_.
velToInt(a);
188 if (!bcProfRaw_[face].empty())
206 vofBlocks_->setMetric(g);
215 n_ = (std::size_t)e_.
x * e_.
y * e_.
z;
217 n1_ = (std::size_t)e1_.
x * e1_.
y * e1_.
z;
235 for (
int c = 0; c < 3; ++c) {
238 C[c].AC =
FV(
"AC", n_);
239 C[c].AW =
FV(
"AW", n_);
240 C[c].AE =
FV(
"AE", n_);
241 C[c].AS =
FV(
"AS", n_);
242 C[c].AN =
FV(
"AN", n_);
243 C[c].AB =
FV(
"AB", n_);
244 C[c].AT =
FV(
"AT", n_);
245 C[c].inhom =
CCField(
"inhom", n_);
246 C[c].rscale =
CCField(
"rscale", n_);
247 C[c].mask =
CCField(
"mask", n_);
248 bcDcorr_[c] =
CCField(
"dcorr", n_);
249 bcBrhs_[c] =
CCField(
"brhs", n_);
254 Kokkos::View<int*, CCMem>(
"nb",
maxCut),
256 Kokkos::View<int*, CCMem>(
"dc", (std::size_t)
maxCut * 6),
262 C[c].idMap = Kokkos::View<int*, CCMem>(
"idMap", n_);
263 C[c].counter = Kokkos::View<int, CCMem>(
"cnt");
265 prev_[c] =
CCField(
"uPrev", n_);
267 if constexpr (Grid::collocated) {
283 fields_.adopt(
"u", C[0].u,
G, peclet::core::Centering::FaceX);
284 fields_.adopt(
"v", C[1].u,
G, peclet::core::Centering::FaceY);
285 fields_.adopt(
"w", C[2].u,
G, peclet::core::Centering::FaceZ);
286 fields_.adopt(
"p", P_,
G, peclet::core::Centering::Cell);
287 fields_.adopt(
"sdf", sdf_,
G, peclet::core::Centering::Cell);
322 const double before = dt_;
339 for (
int a = 0; a < 3; ++a)
346 superficialAxis_ = -1;
350 throw std::invalid_argument(
"set_superficial_velocity: axis must be 0, 1 or 2");
351 if constexpr (Grid::collocated)
352 throw std::runtime_error(
353 "set_superficial_velocity: staggered Solver only (the collocated grid would have to "
354 "shift the projected face field and the cell velocity consistently; not implemented)");
355 superficialAxis_ = axis;
356 superficialVelPhys_ = velocity;
357 if (superficialShift_.data() ==
nullptr)
358 superficialShift_ = Kokkos::View<double, CCMem>(
"superficial_shift");
359 Kokkos::deep_copy(superficialShift_, 0.0);
364 if (superficialAxis_ < 0 || superficialShift_.data() ==
nullptr)
367 Kokkos::deep_copy(h, superficialShift_);
368 return h * u_.
velToPhys(superficialAxis_);
378 velTol_ = rtol > 0.0 ? rtol : 0.0;
384 return lastMomentumSweeps_;
404 useVelocityCheb_ =
on;
405 velChebMaxit_ = maxit < 1 ? 1 : maxit;
410 vmgExplicit_ =
false;
411 useVelocityCheb_ =
false;
412 useVelocityMg_ =
false;
418 return useVelocityCheb_;
436 if (velResTol_ >= 0.0)
438 return useChebyshev_ ? chebRtol_ : pcgRtol_;
444 return lastMomentumResid_;
474 outerIters_ = iters < 1 ? 1 : iters;
484 return lastOuterIters_;
493 vmgLevels_ = levels < 1 ? 1 : levels;
499 throw std::invalid_argument(
501 ": the velocity multigrid takes a SCALAR viscosity and would silently solve the momentum "
502 "equation with the constant set_mu value, ignoring the variable viscosity (a 'mu' "
503 "closure or set_property_mode('variable')). Use set_velocity_solver('gauss_seidel') or "
504 "'auto' (the AUTO rule already keeps variable viscosity on the red-black smoother).");
509 return useVelocityMg_;
514 pressAgglomMode_ = mode;
515 if (cutcellPressure_)
547 if (cutcellPressure_)
554 nLevels_ = levels < 1 ? 1 : levels;
559 backflowBeta_ = beta < 0.0 ? 0.0 : beta;
574 chebBoundsSet_ =
false;
582 throw std::runtime_error(
583 "set_pressure_pcg(False): MG-PCG is the default/terminal pressure driver, so it cannot be "
584 "deselected on its own — select the driver you want instead "
585 "(set_pressure_chebyshev(True, ...) or set_pressure_fcg(True, ...)).");
586 useChebyshev_ =
false;
588 chebBoundsSet_ =
false;
597 if (
on && ghostProjection_)
598 throw std::runtime_error(
599 "set_pressure_fcg: the ghost-projection operator is nonsymmetric and is solved by "
600 "BiCGStab; FCG does not apply");
603 useChebyshev_ =
false;
610 if constexpr (Grid::collocated) {
616 if (
on && faceInterp_ != 0)
621 if (
on && geometryBuilt_)
622 throw std::runtime_error(
623 "set_ghost_projection / set_collocated_scheme('ghost'): call BEFORE set_solid -- the "
624 "ghost overlay is built with the geometry");
625 if (
on && (porous_ || varRho_ || hasBc_ || useChebyshev_))
626 throw std::runtime_error(
627 "set_ghost_projection: incompatible with porous/variable-rho/domain-BC/Chebyshev (v1)");
629 throw std::runtime_error(
"set_ghost_projection: matrix_order/rhs_order must be 1 or 2");
630 if (
on && distributed_ && (hasExactCross_ || hasOpenOverride_))
631 throw std::runtime_error(
632 "set_ghost_projection: exact-crossings/openness-override are single-rank only");
633 ghostProjection_ =
on;
634 colSchemeAuto_ =
false;
643 const std::size_t n = (std::size_t)nx_ * ny_ * nz_;
645 hasExactCross_ =
false;
648 if (t.size() != 9 * n)
649 throw std::runtime_error(
"set_exact_crossings: expected 9*nx*ny*nz values");
650#ifdef PECLET_FLOW_MPI
652 throw std::runtime_error(
"set_exact_crossings: single-rank only");
654 for (
int c = 0; c < 3; ++c)
655 for (
int k = 0; k < 3; ++k) {
656 tEx_[c][k] =
CCField(
"tEx", n);
659 Kokkos::View<
const double*, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>(
660 t.data() + ((std::size_t)c * 3 + k) * n, n));
662 hasExactCross_ =
true;
667 const std::vector<double>& oz) {
669 const std::size_t n = (std::size_t)nx_ * ny_ * nz_;
671 hasOpenOverride_ =
false;
674 if (ox.size() != n || oy.size() != n || oz.size() != n)
675 throw std::runtime_error(
"set_openness_override: expected nx*ny*nz values per field");
676#ifdef PECLET_FLOW_MPI
678 throw std::runtime_error(
"set_openness_override: single-rank only");
683 hasOpenOverride_ =
true;
699 throw std::runtime_error(
700 "set_face_interp: mode " + std::to_string(mode) +
701 " is not one of 0 (plain), 5/6/7 (embed rungs) or 9 (gauge-exact); use "
702 "set_collocated_scheme('plain' | 'gauge-exact' | 'embed' | 'ghost')");
703 if (ghostProjection_ && mode != 0)
704 throw std::runtime_error(
705 "set_face_interp: incompatible with the ghost projection (set_ghost_projection(False) "
706 "first, or use set_collocated_scheme which handles the transition)");
708 colSchemeAuto_ =
false;
718 if (name !=
"ghost" && ghostProjection_) {
719 ghostProjection_ =
false;
722 if (name ==
"gauge-exact") {
724 }
else if (name ==
"plain") {
726 }
else if (name ==
"embed") {
728 }
else if (name ==
"ghost") {
738 throw std::runtime_error(
739 "set_collocated_scheme: expected 'ghost', 'gauge-exact', 'plain' or 'embed', got '" + name +
762 throw std::runtime_error(
"set_aperture_order: order must be 1 or 2");
763 apertureOrder_ = order;
768 return apertureOrder_;
784 throw std::runtime_error(
785 "set_comm_avoiding: call BEFORE init_mpi -- the momentum half is latched with the halo "
799 throw std::runtime_error(
"set_multigrid_aspect_threshold: theta must be > 1");
800 aspectTheta_ = theta;
843 throw std::runtime_error(
844 "set_decomposition: call BEFORE init_mpi -- the decomposition is built there");
845 decompLevels_ = levels;
851 return decompLevels_;
856 return decompMaxImbalance_;
863 throw std::runtime_error(
"set_fluid_only_constraint: mode must be 0, 1 or 2");
864 fluidOnlyMode_ = mode;
866 colSchemeAuto_ =
false;
877 if constexpr (Grid::collocated) {
878 for (
int c = 0; c < 3; ++c)
880 if (faceInterp_ == 5 || faceInterp_ == 7)
886 faceFieldValid_ =
true;
893 const std::vector<double>&
ww) {
894 const std::vector<double>* src[3] = {&
uu, &
vv, &
ww};
895 std::vector<double>
scaled[3];
896 for (
int c = 0; c < 3; ++c) {
900 scaled[c].resize(src[c]->size());
901 for (std::size_t i = 0; i < src[c]->size(); ++i)
902 scaled[c][i] = (*src[c])[i] * k;
906 const int ex = e_.
x, ey = e_.
y,
nx = nx_,
ny = ny_,
nz = nz_, g =
G;
907 for (
int c = 0; c < 3; ++c) {
911 CCField din(
"peclet::flow::vel_in_d",
static_cast<std::size_t
>(nx_) * ny_ * nz_);
914 Kokkos::View<
const double*, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>(
915 src[c]->
data(), src[c]->size()));
917 Kokkos::parallel_for(
920 u((
long)(x + g) + (
long)(y + g) * ex + (
long)(z + g) * (
long)ex * ey) =
921 din((std::size_t)x + (std::size_t)y *
nx + (std::size_t)z * (std::size_t)
nx *
ny);
945 return advect_ && (implicitFou_ || (hasBc_ && (!useVelocityMg_ || hasSolid_)));
951 (hasSolid_ || (!useVelocityMg_ && (
implicitAdv() || varProps_ || varRho_ || hasDrag_)));
956 return hasBc_ && useVelocityMg_ && hasSolid_ && !varProps_ && !varRho_ && !hasDrag_;
961 return (c == 0) ? 1 : (c == 1) ? e_.
x : (
long)e_.
x * e_.
y;
968 const double idiag = rho_ / dt_,
bx = mu_ * u_.
w[0],
by = mu_ * u_.
w[1],
bz = mu_ * u_.
w[2];
973 for (
int c = 0; c < 3; ++c) {
974 Kokkos::deep_copy(C[c].rscale, 1.0);
975 Kokkos::deep_copy(C[c].inhom, 0.0);
982 ibmModifyStencil(C[c].
AC, C[c].AW, C[c].AE, C[c].AS, C[c].AN, C[c].AB, C[c].AT, C[c].inhom,
983 C[c].rscale, C[c].ov, C[c].nCut, 0.0f,
wallVelView(c));
995 "peclet::flow::copyInner",
C3{0, 0, 0},
C3{nx_, ny_, nz_},
1005template <
class Gr
id>
1008 "peclet::flow::copyBlockShifted",
C3{0, 0, 0},
C3{
de.x,
de.y,
de.z},
1017template <
class Gr
id>
1019#ifdef PECLET_FLOW_MPI
1028template <
class Gr
id>
1030#ifdef PECLET_FLOW_MPI
1038 const int Nx = nx_,
Ny = ny_,
Nz = nz_;
1039 const long sx = 1, sy = e.x, sz = (
long)e.x * e.y;
1041 Kokkos::parallel_for(
1042 "peclet::flow::ibm_facefill", Kokkos::RangePolicy<CCExec>(
space, 0, (
long)nx_ * ny_ * nz_),
1048 else if (
ix >=
Nx -
G)
1051 ff(i + (
long)
Ny * sy) =
ff(i);
1052 else if (
iy >=
Ny -
G)
1053 ff(i - (
long)
Ny * sy) =
ff(i);
1055 ff(i + (
long)
Nz * sz) =
ff(i);
1056 else if (
iz >=
Nz -
G)
1057 ff(i - (
long)
Nz * sz) =
ff(i);
1061template <
class Gr
id>
1065 int N3[3] = {nx_, ny_, nz_};
1066 int dims[3] = {e.x, e.y, e.z};
1067 long st[3] = {1, e.x, (
long)e.x * e.y};
1068 const int a = axis, b = (axis + 1) % 3, c = (axis + 2) % 3;
1069 const long sa = st[a],
sb = st[b], sc = st[c];
1070 const int N =
N3[a];
1072 Kokkos::parallel_for(
1075 const long base = (
long)p0 *
sb + (
long)
p1 * sc;
1076 for (
int gl = 0;
gl <
G; ++
gl) {
1093template <
class Gr
id>
1095 const bool px =
axes & 1, py =
axes & 2, pz =
axes & 4;
1096 const int nx = nx_,
ny = ny_,
nz = nz_;
1097 if ((px &&
nx <
G) || (py &&
ny <
G) || (pz &&
nz <
G)) {
1100 for (
int a = 0; a < 3; ++a)
1101 if (
axes & (1 << a))
1107 const long exy = (
long)e.x * e.y;
1110 const int z0 = pz ?
G : 0,
zn = pz ?
nz : e.z;
1111 const int y0 = py ?
G : 0,
yn = py ?
ny : e.y;
1112 const long nZ = pz ? 2L *
G *
exy : 0,
nY = py ? (
long)
zn * 2 *
G * e.x : 0,
1115 if constexpr (std::is_same_v<typename CCExec::memory_space, Kokkos::HostSpace>) {
1118 const long rZ = pz ? 2L *
G * e.y : 0,
rY = py ? (
long)
zn * 2 *
G : 0,
1120 auto copyRow = [=](
long dst,
long src) {
1122 for (
int x = 0; x <
G; ++x)
1123 ff(dst + x) =
ff(src + x +
nx);
1124 for (
int x =
G; x <
G +
nx; ++x)
1125 ff(dst + x) =
ff(src + x);
1126 for (
int x =
G +
nx; x < e.x; ++x)
1127 ff(dst + x) =
ff(src + x -
nx);
1129 for (
int x = 0; x < e.x; ++x)
1130 ff(dst + x) =
ff(src + x);
1133 auto row = [=](
long t) {
1135 const int l = (int)(t / e.y), y = (int)(t - (
long)l * e.y);
1136 const int z = l <
G ? l :
nz + l;
1137 const int sy = !py ? y : (y <
G ? y +
ny : (y >=
G +
ny ? y -
ny : y));
1138 const int sz = z <
G ? z +
nz : z -
nz;
1139 copyRow((
long)y * e.x + (
long)z *
exy, (
long)sy * e.x + (
long)sz *
exy);
1140 }
else if (t <
rZ +
rY) {
1141 const long t2 = t -
rZ;
1142 const int zi = (int)(
t2 / (2 *
G)), l = (
int)(
t2 - (
long)
zi * 2 *
G);
1143 const int y = l <
G ? l :
ny + l, z =
z0 +
zi;
1144 const int sy = y <
G ? y +
ny : y -
ny;
1145 copyRow((
long)y * e.x + (
long)z *
exy, (
long)sy * e.x + (
long)z *
exy);
1147 const long t3 = t -
rZ -
rY;
1150 for (
int x = 0; x <
G; ++x)
1151 ff(base + x) =
ff(base + x +
nx);
1152 for (
int x =
G +
nx; x < e.x; ++x)
1153 ff(base + x) =
ff(base + x -
nx);
1157 for (
long t = 0; t <
rZ +
rY +
rX; ++t)
1161 Kokkos::parallel_for(
"peclet::flow::ibm_pfill3",
1162 Kokkos::RangePolicy<CCExec>(
space, 0,
rZ +
rY +
rX), row);
1165 Kokkos::parallel_for(
1166 "peclet::flow::ibm_pfill3", Kokkos::RangePolicy<CCExec>(
space, 0,
nZ +
nY +
nX),
1170 const int l = (int)(t /
exy);
1171 const long r = t - (
long)l *
exy;
1174 z = l <
G ? l :
nz + l;
1175 }
else if (t <
nZ +
nY) {
1176 const long t2 = t -
nZ, rw = 2L *
G * e.x;
1177 const long zi =
t2 / rw, r =
t2 -
zi * rw;
1178 const int l = (int)(r / e.x);
1180 y = l <
G ? l :
ny + l;
1184 const long zi =
t3 / rw, r =
t3 -
zi * rw;
1185 const int l = (int)(r % (2 *
G));
1186 x = l <
G ? l :
nx + l;
1187 y = y0 + (int)(r / (2 *
G));
1190 const int sx = !px ? x : (x <
G ? x +
nx : (x >=
G +
nx ? x -
nx : x));
1191 const int sy = !py ? y : (y <
G ? y +
ny : (y >=
G +
ny ? y -
ny : y));
1192 const int sz = !pz ? z : (z <
G ? z +
nz : (z >=
G +
nz ? z -
nz : z));
1193 ff((
long)x + (
long)y * e.x + (
long)z *
exy) =
1194 ff((
long)
sx + (
long)sy * e.x + (
long)sz *
exy);
1198template <
class Gr
id>
1201 for (
int a = 0; a < 3; ++a)
1202 if (bc_[2 * a] == 0 && bc_[2 * a + 1] == 0) {
1213template <
class Gr
id>
1215 return advWallVel_ && !Grid::collocated && hasScene_ && hasMotion_ && advect_ &&
1216 uBc_[0].extent(0) == n_ && C[0].mask.extent(0) == n_;
1219template <
class Gr
id>
1224 for (
int c = 0; c < 3; ++c) {
1225 if (uwAdv_[c].extent(0) != n_)
1226 uwAdv_[c] =
CCField(
"uwAdv", n_);
1227 Kokkos::deep_copy(uwAdv_[c], C[c].u);
1230 Kokkos::parallel_for(
1231 "peclet::flow::adv_wall_inputs", Kokkos::RangePolicy<CCExec>(
space, 0, (
long)n_),
1241template <
class Gr
id>
1246template <
class Gr
id>
1248 return CCConst(c == 0 ? uf_ : (c == 1 ? vf_ : wf_));
1251template <
class Gr
id>
1253 return (hasOutflow_ && ufOpen_[c].extent(0) == n_) ?
CCConst(ufOpen_[c]) :
advFaceView(c);
1256template <
class Gr
id>
1258 if constexpr (Grid::collocated) {
1261 CCField src[3] = {uf_, vf_, wf_};
1262 for (
int a = 0; a < 3; ++a) {
1263 if (ufOpen_[a].extent(0) != n_)
1264 ufOpen_[a] =
CCField(
"peclet::flow::ufOpen", n_);
1265 Kokkos::deep_copy(ufOpen_[a], src[a]);
1267 B3 e{e_.
x, e_.
y, e_.
z};
1268 for (
int a = 0; a < 3; ++a)
1269 if (bc_[2 * a + 1] == 3 && touchesGlobalFace(2 * a + 1))
1274template <
class Gr
id>
1276 return Grid::collocated && ufAdvect_ && faceFieldValid_;
1279template <
class Gr
id>
1284template <
class Gr
id>
1289template <
class Gr
id>
1291 const bool want = !Grid::collocated && hasScene_ && adv;
1292 if (want && advRhs_[c].extent(0) != n_)
1293 advRhs_[c] =
CCField(
"advRhs", n_);
1298template <
class Gr
id>
1301 const double idiag = rho_ / dt_,
fouw = rho_,
bx = mu_ * u_.
w[0],
by = mu_ * u_.
w[1],
1304 ibmBuildDiffusion(C[c].
AC, C[c].AW, C[c].AE, C[c].AS, C[c].AN, C[c].AB, C[c].AT, e.x, e.y, e.z,
1307 FV AC = C[c].AC, AW = C[c].AW, AE = C[c].AE, AS = C[c].AS, AN = C[c].AN, AB = C[c].AB,
1317 Kokkos::parallel_for(
1318 "advstencil",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1320 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
1324 Grid::fou_operator(c, x, y, z,
Ua,
Va,
Wa,
fouw,
cC,
cxm,
cxp,
cym,
cyp,
czm,
czp,
ufa);
1334 Kokkos::deep_copy(C[c].rscale, 1.0);
1335 Kokkos::deep_copy(C[c].inhom, 0.0);
1336 ibmModifyStencil(C[c].
AC, C[c].AW, C[c].AE, C[c].AS, C[c].AN, C[c].AB, C[c].AT, C[c].inhom,
1337 C[c].rscale, C[c].ov, C[c].nCut, 0.0f,
wallVelView(c));
1342template <
class Gr
id>
1350 if (!varRho_ && porous_ && porousCons_)
1353 ibmBuildDiffusionVar(C[c].
AC, C[c].AW, C[c].AE, C[c].AS, C[c].AN, C[c].AB, C[c].AT, e.x, e.y, e.z,
1356 FV AC = C[c].AC, AW = C[c].AW, AE = C[c].AE, AS = C[c].AS, AN = C[c].AN, AB = C[c].AB,
1366 const double rhoC = rho_;
1370 Kokkos::parallel_for(
1371 "advstencil_var",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1373 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
1377 const double fouw =
vr ? 0.5 * (rf(i) + rf(i - sc)) :
rhoC;
1378 Grid::fou_operator(c, x, y, z,
Ua,
Va,
Wa,
fouw,
cC,
cxm,
cxp,
cym,
cyp,
czm,
czp,
ufa);
1387 Kokkos::deep_copy(C[c].rscale, 1.0);
1388 Kokkos::deep_copy(C[c].inhom, 0.0);
1389 ibmModifyStencil(C[c].
AC, C[c].AW, C[c].AE, C[c].AS, C[c].AN, C[c].AB, C[c].AT, C[c].inhom,
1390 C[c].rscale, C[c].ov, C[c].nCut, 0.0f,
wallVelView(c));
1395template <
class Gr
id>
1400 Kokkos::parallel_reduce(
1403 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
1404 const double d = Kokkos::fabs(a(i) - b(i));
1408 Kokkos::Max<double>(m));
1412template <
class Gr
id>
1413template <
class Fill,
class Color,
class ColorDu>
1415 std::function<
double()>
resid,
double bnorm) {
1417 int used = velIters_;
1420 auto gmax = [&](
double v) {
1421#ifdef PECLET_FLOW_MPI
1430 double scale = 0.0,
rPrev = -1.0;
1441 for (
int it = 0; it < velIters_; ++it) {
1448 if (it == 0 || (it + 1) % 4 == 0 || it + 1 == velIters_) {
1451 const double ratio = scale > 0 ? r / scale : 0.0;
1455 const bool floor = r <= 1e-14 * scale || (
rPrev >= 0.0 && r >=
rPrev);
1457 if (r <=
vtol * scale ||
floor || it + 1 == velIters_) {
1458 lastMomentumResid_ = std::max(lastMomentumResid_, ratio);
1463 }
else if (velTol_ > 0.0) {
1465#ifdef PECLET_FLOW_MPI
1474 if (it + 1 >= velMinIters_ && du <= velTol_ *
du0) {
1482 lastMomentumSweeps_ +=
used;
1485template <
class Gr
id>
1487#ifdef PECLET_FLOW_MPI
1494template <
class Gr
id>
1497 const int t = bc_[2 * c];
1498 if ((t == 1 || t == 2 || t == 4) && touchesGlobalFace(2 * c))
1505template <
class Gr
id>
1509 if (velRes_.extent(0) != n_)
1510 velRes_ =
CCField(
"velRes", n_);
1511 return [
this, c, exchange]() {
1512#ifdef PECLET_FLOW_MPI
1513 if (exchange && distributed_)
1525template <
class Gr
id>
1530 if (velRes_.extent(0) != n_)
1531 velRes_ =
CCField(
"velRes", n_);
1534 const I3 e{e_.
x, e_.
y, e_.
z};
1541template <
class Gr
id>
1546template <
class Gr
id>
1548 if (chebD_.extent(0) != n_)
1549 chebD_ =
CCField(
"chebD", n_);
1550 if (velRes_.extent(0) != n_)
1551 velRes_ =
CCField(
"velRes", n_);
1552 Kokkos::deep_copy(chebD_, 0.0);
1554 auto gmax = [&](
double v) {
1555#ifdef PECLET_FLOW_MPI
1565#ifdef PECLET_FLOW_MPI
1573 auto residual = [&] {
1582 double lo = 0.0, hi = 0.0;
1589 if (!(hi > lo) || !(lo > 0.0)) {
1597 double scale = 0.0,
rPrev = -1.0;
1607 int used = velChebMaxit_;
1608 for (
int it = 0; it < velChebMaxit_; ++it) {
1611 if (
useRes && (it == 0 || (it + 1) % 4 == 0 || it + 1 == velChebMaxit_)) {
1618 const bool floor = r <= 1e-14 * scale;
1621 lastMomentumResid_ = std::max(lastMomentumResid_, scale > 0 ? r / scale : 0.0);
1626 double alpha = 0.0, beta = 0.0;
1627 cb.
next(it, alpha, beta);
1631 lastMomentumSweeps_ +=
used;
1634template <
class Gr
id>
1636 if constexpr (Grid::collocated) {
1644 FPC(C[c].AE),
FPC(C[c].AS),
FPC(C[c].AN),
FPC(C[c].AB),
1645 FPC(C[c].AT),
CCConst(C[c].mask), e_, og_,
G, col);
1649 FPC(C[c].AW),
FPC(C[c].AE),
FPC(C[c].AS),
1650 FPC(C[c].AN),
FPC(C[c].AB),
FPC(C[c].AT),
1651 CCConst(C[c].mask), e_, og_,
G, col);
1662 const Off3 off = Grid::offset(c);
1667 FPC(C[c].AB),
FPC(C[c].AT));
1676 lastMomentumSweeps_ += vmg_.
solve(
CCConst(C[c].b), C[c].u, vmgVcycles_, 2, 2, 8, velTol_,
1692 FPC(C[c].AE),
FPC(C[c].AS),
FPC(C[c].AN),
FPC(C[c].AB),
1693 FPC(C[c].AT),
CCConst(C[c].mask), e_, og_,
G, col);
1697 FPC(C[c].AE),
FPC(C[c].AS),
FPC(C[c].AN),
1716 lastMomentumSweeps_ += vmg_.
solve(
CCConst(C[c].b), C[c].u, vmgVcycles_, 2, 2, 8, velTol_,
1725 const I3 e{e_.
x, e_.
y, e_.
z}, og{og_.
x, og_.
y, og_.
z};
1728 const double bx = mu_ * u_.
w[0],
by = mu_ * u_.
w[1],
bz = mu_ * u_.
w[2];
1729 const double Ac = rho_ / dt_ + 2.0 * ((
bx +
by) +
bz);
1733 diffSmoothColor(C[c].u,
CCConst(C[c].b), e, og,
G,
bx,
by,
bz,
Ac, col,
1737 return diffSmoothColorDu(C[c].u,
CCConst(C[c].b), e, og,
G,
bx,
by,
bz,
Ac, col,
1743 if (useVelocityCheb_) {
1751 if (useVelocityMg_) {
1754 FPC(C[c].AB),
FPC(C[c].AT));
1755 if (implicitFou_ && advect_) {
1771 lastMomentumSweeps_ += vmg_.
solve(
CCConst(C[c].b), C[c].u, vmgVcycles_, 2, 2, 8, velTol_,
1779#ifdef PECLET_FLOW_MPI
1798 for (
FV* a : {&C[c].AC, &C[c].AW, &C[c].AE, &C[c].AS, &C[c].AN, &C[c].AB, &C[c].AT})
1804 const C3 lo{
G + 1,
G + 1,
G + 1}, hi{e_.
x -
G - 1, e_.
y -
G - 1, e_.
z -
G - 1};
1805 const C3 rlo{
G - 1,
G - 1,
G - 1},
rhi{e_.
x -
G + 1, e_.
y -
G + 1, e_.
z -
G + 1};
1806 const C3 z0{0, 0, 0};
1811 velDev_->exchangeBegin(C[c].u);
1813 FPC(C[c].AE),
FPC(C[c].AS),
FPC(C[c].AN),
FPC(C[c].AB),
1817 FPC(C[c].AE),
FPC(C[c].AS),
FPC(C[c].AN),
FPC(C[c].AB),
1822 FPC(C[c].AS),
FPC(C[c].AN),
FPC(C[c].AB),
FPC(C[c].AT),
1823 CCConst(C[c].mask), e_, og_,
G, col);
1828 FPC(C[c].AE),
FPC(C[c].AS),
FPC(C[c].AN),
FPC(C[c].AB),
1829 FPC(C[c].AT),
CCConst(C[c].mask), e_, og_,
G, col);
1845 const C3 lo{
G + 1,
G + 1,
G + 1}, hi{e_.
x -
G - 1, e_.
y -
G - 1, e_.
z -
G - 1};
1846 const C3 z0{0, 0, 0};
1850 velDev_->exchangeBegin(C[c].u);
1852 FPC(C[c].AS),
FPC(C[c].AN),
FPC(C[c].AB),
FPC(C[c].AT),
1853 CCConst(C[c].mask), e_, og_, col, lo, hi,
z0,
z0);
1856 FPC(C[c].AS),
FPC(C[c].AN),
FPC(C[c].AB),
FPC(C[c].AT),
1860 velDev_->exchangeBegin(C[c].u);
1863 FPC(C[c].AN),
FPC(C[c].AB),
FPC(C[c].AT),
CCConst(C[c].mask), e_, og_, col, lo, hi,
1879 FPC(C[c].AE),
FPC(C[c].AS),
FPC(C[c].AN),
FPC(C[c].AB),
1880 FPC(C[c].AT),
CCConst(C[c].mask), e_, og_,
G, col);
1884 FPC(C[c].AE),
FPC(C[c].AS),
FPC(C[c].AN),
1891template <
class Gr
id>
1894 CCField u = C[c].u, m = C[c].mask;
1895 Kokkos::parallel_for(
1902template <
class Gr
id>
1908 Kokkos::parallel_reduce(
1911 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
1915 Kokkos::Min<double>(m));
1916#ifdef PECLET_FLOW_MPI
1926template <
class Gr
id>
1931 Kokkos::parallel_reduce(
1934 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
1935 const double a = Kokkos::fabs(f(i));
1939 Kokkos::Max<double>(m));
1943template <
class Gr
id>
1945 auto h = Kokkos::create_mirror_view(
fld);
1946 Kokkos::deep_copy(h,
fld);
1947 std::vector<double> out((std::size_t)nx_ * ny_ * nz_);
1948 for (
int z = 0; z < nz_; ++z)
1949 for (
int y = 0; y < ny_; ++y)
1950 for (
int x = 0; x < nx_; ++x)
1951 out[(std::size_t)x + (std::size_t)y * nx_ + (std::size_t)z * (std::size_t)nx_ * ny_] =
1952 h((
long)(x +
G) + (
long)(y +
G) * e_.
x + (
long)(z +
G) * (
long)e_.
x * e_.
y);
1956template <
class Gr
id>
1958 if (
in.size() != (std::size_t)nx_ * ny_ * nz_)
1959 throw std::runtime_error(
"flow::setField: array size does not match the inner grid");
1960 auto h = Kokkos::create_mirror_view(
fld);
1961 Kokkos::deep_copy(h,
fld);
1962 for (
int z = 0; z < nz_; ++z)
1963 for (
int y = 0; y < ny_; ++y)
1964 for (
int x = 0; x < nx_; ++x)
1965 h((
long)(x +
G) + (
long)(y +
G) * e_.
x + (
long)(z +
G) * (
long)e_.
x * e_.
y) =
1966 in[(std::size_t)x + (std::size_t)y * nx_ + (std::size_t)z * (std::size_t)nx_ * ny_];
1967 Kokkos::deep_copy(
fld, h);
1970template <
class Gr
id>
1972 if (fields_.has(name))
1973 return fields_.at(name).data;
1974 return fields_.add(name, n_,
G, peclet::core::Centering::Cell).data;
1977template <
class Gr
id>
1979 return fields_.has(name);
1982template <
class Gr
id>
1984 return fields_.at(name).data;
1987template <
class Gr
id>
1989 return fields_.names();
1992template <
class Gr
id>
1997template <
class Gr
id>
1999#ifdef PECLET_FLOW_MPI
2001 CCField f = fields_.at(name).data;
2002 auto h = Kokkos::create_mirror_view(f);
2003 Kokkos::deep_copy(h, f);
2004 peclet::core::halo::GridFieldView<double>
view{h.data()};
2006 Kokkos::deep_copy(f, h);
2013template <
class Gr
id>
2018template <
class Gr
id>
2025 else if (name ==
"p_balanced")
2029template <
class Gr
id>
2031 return {e_.
x, e_.
y, e_.
z};
2034template <
class Gr
id>
2039template <
class Gr
id>
2041#ifdef PECLET_FLOW_MPI
2045 return {nx_, ny_, nz_};
2048template <
class Gr
id>
2050 return {og_.
x, og_.
y, og_.
z};
2053template <
class Gr
id>
2055 rhoFaceHarmonic_ =
on;
2056 bfpChebSet_ =
false;
2059template <
class Gr
id>
2061 exactResidual_ =
on;
2065template <
class Gr
id>
2067 outflowOpCoeff_ =
on;
2070template <
class Gr
id>
2072 return outflowOpCoeff_;
2075template <
class Gr
id>
2077 return exactResidual_;
2080template <
class Gr
id>
2082 return rhoFaceHarmonic_;
2085template <
class Gr
id>
2087 outflowRhoCorr_ =
on;
2090template <
class Gr
id>
2092 return outflowRhoCorr_;
2095template <
class Gr
id>
2097 if (name ==
"force_x" || name ==
"force_y" || name ==
"force_z")
2098 ensureCellForceAll();
2102template <
class Gr
id>
2103void Solver<Grid>::ensureCellForceAll() {
2104 static const char* fn[3] = {
"force_x",
"force_y",
"force_z"};
2105 for (
int c = 0; c < 3; ++c)
2107 hasCellForce_ =
true;
void setStrictPressure(bool on)
Throw instead of reporting when the preconditioner returns a non-finite correction.
void setGraphAmgBottom(bool on)
void setTelescope(bool on)
void setCoarseGhost(bool on)
Neumann coarse ghost on wall/inflow faces before the prolongation (see bcGhost_).
void setAspectThreshold(double theta)
Anisotropic-coarsening aspect threshold theta (see aspectTheta_).
int telescopeCount() const
void setAgglomerationMode(int mode)
void setTelescopeForceLevel(int L)
void setAgglomerationExtent(int cells)
bool strictPressure() const
void setExactResidual(bool on)
The exact double flux-form level-0 apply in the residual and the Krylov matvec.
void setMeanRemovalScope(bool all)
int agglomerationExtent() const
void setCommAvoiding(int mask)
Communication-avoiding smoothing mask (kCaMomentum | kCaMg); only kCaMg is read here.
void setBottomSolver(int m)
int pressureBottomExtent() const
void setPressureMeanRemoval(bool all)
double multigridAspectThreshold() const
std::array< int, 3 > globalResolution() const
void setPhysicalDomain(const std::array< double, 3 > &extent, const std::array< double, 3 > &origin, const std::array< long, 3 > &globalCells)
Arm the physical domain.
void fillVelGhosts(int comp, int fold)
void setIncrementalPressure(bool on)
std::function< double()> constCoeffResidual(int c, double bx, double by, double bz, double Ac)
void setVelocityTolerance(double rtol, int minIters)
double stencilBnorm(int c)
bool pressureCoarseGhost() const
void scatterInner(CCField fld, const std::vector< double > &in)
void buildOpenFaceField()
Build ufOpen_ = the face field with each open (outflow) domain face overwritten by its zero-gradient ...
void fillGhosts(CCField f)
long lastOuterIterations() const
double decompositionMaxImbalance() const
void fillDomainPeriodic(CCField f)
void setPressureCoarseGhost(bool on)
Neumann (zero-gradient) coarse ghost on wall/inflow faces before the pressure MG's prolongation — the...
bool advWallInputs() const
R0 helper: allocate (once) and arm the per-component advective-term stash the reaction-force budget c...
void setUfAdvection(bool on)
Advect the collocated momentum with the PROJECTED, divergence-free MAC face field uf_/vf_/wf_ (DEFAUL...
void fillPropGhosts(CCField f, bool edges=false)
void seedFaceFieldFromCells()
void setFaceInterp(int mode)
std::vector< double > getField(const std::string &name)
void setOutflowRhoCorrection(bool on)
void setVelocityChebyshev(bool on, int maxit=400)
void setOpennessOverride(const std::vector< double > &ox, const std::vector< double > &oy, const std::vector< double > &oz)
void setOuterTolerance(double tol)
CCField addField(const std::string &name)
double lastMomentumResidual() const
std::array< double, 3 > domainOrigin() const
Physical lower corner of the GLOBAL inner grid.
void setPressureGraphAmg(bool on)
VelocityMG::Comm vmgComm() const
double velocityResidualTolerance() const
void setVelocitySolverAuto()
void setPressureTelescope(bool on)
void setPressureStrict(bool on)
Throw instead of reporting when the pressure preconditioner returns a non-finite correction (ISSUES s...
void fillGhostsFaces(CCField f)
bool advectionWallVelocity() const
void exchangeFieldAdd(const std::string &name)
CCConst advVelView(int c) const
The velocity view the advection operators must read for component c: the wall-corrected scratch while...
void exchangeField(const std::string &name)
void setAdvection(bool on)
std::array< long, 3 > globalCells() const
The GLOBAL cell counts (this rank's block single-rank).
void setPressureExactResidual(bool on)
WO-R2 item 3 — the exact (matrix-free, double, flux-form) level-0 operator apply in the residual and ...
void uploadVelocity(const std::vector< double > &uu, const std::vector< double > &vv, const std::vector< double > &ww)
Upload an initial velocity field in the caller's PHYSICAL units (converted per component to the index...
bool outflowRhoCorrection() const
void copyInner(CCField dst, C3 de, int dg, CCConst src, C3 se, int sg)
void requireNoGeometry(const char *who) const
void applyVelocityBcCompTo(CCField f, int comp, int fold, bool doOutflow)
double maxAbsDiffInner(CCConst a, CCConst b)
void fillPeriodicAxes(CCField f, int axes)
void requireIsotropic(const char *what) const
Phase 2 §7 — refuse an ANISOTROPIC domain in a consumer this phase does not carry.
void setBackflowStab(double beta)
std::array< double, 3 > spacing() const
Cell size per axis (equal on every axis unless the Phase 2 anisotropic path is armed – see unitScales...
bool velocityChebyshevActive() const
void setVelocityIterations(int it)
double finishResidual(int c)
bool ufAdvVelocity() const
Are the advection operators reading the projected face field this step? Collocated grid,...
void setPressureChebyshev(bool on, int maxit, double rtol)
const UnitScales & unitScales() const
bool rhoFaceHarmonic() const
CCConst openFaceView(int c) const
Component c of the face field AS THE ADVECTION AND THE DIVERGENCE DIAGNOSTIC MUST READ IT: advFaceVie...
bool pressureStrict() const
Solver(int nx, int ny, int nz)
void addDragDiagonal(int c)
void setGhostProjection(bool on, int matrixOrder=2, int rhsOrder=2)
CCConst advFaceView(int c) const
Component c of the collocated MAC face field (uf_/vf_/wf_), flow's low-face convention: entry i is th...
int apertureOrder() const
long lastMomentumSweeps() const
void setPressureLevels(int levels)
std::array< int, 3 > blockOrigin() const
void setFluidOnlyConstraint(int mode)
void setRotationalPressure(bool on)
void setDeferredCorrection(bool on)
void resampleBcProfile(int face)
void fillVelGhostsTo(CCField f, int comp, int fold, bool doOutflow=true)
SceneMap sceneMap() const
void setCommAvoiding(int mask)
Communication-avoiding red-black smoothing: kCaMomentum | kCaMg.
void fillAxis(CCField f, int axis)
void setAdvectionWallVelocity(bool on)
A0 — wall velocity (not zeros) in the advection inputs' masked rows. DEFAULT true.
void setField(const std::string &name, const std::vector< double > &v)
void setApertureOrder(int order)
double lastSuperficialVelocityShift() const
The shift the last step() applied (caller's velocity units; 0 when off).
void setBodyForce(double fx, double fy, double fz)
Body force per unit volume, in the caller's units (e.g. a mean pressure gradient, or rho*g).
void closureRefreshUnits(Closure &cl)
Re-derive a closure's internal p / tabY from its physical pPhys / tabYPhys with the current reference...
void chebSolveComp(int c)
std::array< int, 3 > blockShape() const
void setRhoFaceHarmonic(bool on)
bool pressureExactResidual() const
long strideOf(int c) const
bool hasField(const std::string &name) const
void setAdvectionScheme(int s)
void throwVelocityMgVariableMu(const char *who) const
int pressureTelescopeCount() const
void setPressurePcg(bool on, int maxit, double rtol)
void setVelocityMultigridAuto(long cellsPerRank, long minGlobalCells=-1, int minBlockExtent=-1)
void allocateBlock(int nx, int ny, int nz)
void setVelocityMultigrid(bool on, int levels, int vcycles)
void setRotationalWeight(double w)
void setMu(double m)
Dynamic viscosity, in the caller's units.
void setDecomposition(int levels, double maxImbalance=1.05)
How the shared level-0 MPI decomposition is built.
void setExactCrossings(const std::vector< double > &t)
void setPressureWarmstart(bool on)
void velSweepLoop(Fill &&fill, Color &&sweepColor, ColorDu &&sweepColorDu, std::function< double()> resid=nullptr, double bnorm=0.0)
void setPressureIterations(int it)
Kokkos::View< MReal *, CCMem > FV
bool velocityMgChebyshev() const
void refreshUnitDerived()
Re-derive every internal (index-unit) quantity from the stored physical inputs.
void setPressureBottomSolver(int engine)
void buildAdvStencil(int c)
void setPressureTelescopeForceLevel(int level)
CCField fieldView(const std::string &name)
void pushVofMetric()
Hand the anisotropic cell metric to every VoF driver that exists (Phase 3).
void setCollocatedScheme(const std::string &name)
void setVelocityMgChebyshev(bool on, int degree=0, double eig_ratio=10.0)
void setPressureBottomExtent(int cells)
The set_pressure_bottom("auto") criterion: agglomerate once the coarsest GLOBAL grid exceeds this man...
void buildAdvStencilVar(int c)
bool ensureAdvStash(int c, bool adv)
bool bcStencilPath() const
void setOutflowOperatorCoefficient(bool on)
WO-R2 item 1 ABLATION: set_outflow_operator_coefficient(False) restores the pre-WO-R2 operator,...
void setImplicitAdvection(bool on)
void setVelocityResidualTolerance(double rtol)
std::function< double()> stencilResidual(int c, bool exchange=false)
bool mixedVelocityMg() const
void setPressureBottomMode(int mode)
VarFaceProps makeFaceProps(int c)
void setRotationalWallWeight(double w0)
bool pressureTelescope() const
double reduceMaxAbsInner(CCConst f)
void setRho(double r)
Fluid density, in the caller's units.
void setRotationalFilter(bool on, double eps=0.05)
bool velocityMultigridActive() const
std::array< double, 3 > domainExtent() const
Physical extent of the GLOBAL inner grid (cell counts without a physical domain).
std::vector< std::string > fieldNames() const
std::vector< double > gatherInner(CCField fld)
void setSuperficialVelocity(bool on, int axis, double velocity)
Hold the SUPERFICIAL velocity along a periodic axis: at the end of every step() one uniform shift is ...
std::vector< double > cellCentres(int axis) const
Physical cell-centre coordinates of THIS rank's inner block along axis (nx/ny/nz values).
void copyBlockShifted(CCField dst, C3 de, CCConst src, C3 se, int off)
void pcRefreshUnits()
Re-derive the INTERNAL phase-change constants (pcRhoG_ ... pcRcpL_) from the caller's physical ones (...
int decompositionLevels() const
CCConst wallVelView(int c) const
bool outflowOperatorCoefficient() const
void setPressureFcg(bool on, int maxit, double rtol)
void setMultigridAspectThreshold(double theta)
The anisotropic-coarsening aspect threshold theta shared by the pressure and velocity multigrids (doc...
void setOuterIterations(int iters)
bool hasPhysicalDomain() const
void setFineStencil(FPC AC, FPC AW, FPC AE, FPC AS, FPC AN, FPC AB, FPC AT)
void buildUpwindCoarse(int comp, double nu_dt, double idiag, double fouw)
void setChebyshevSmoother(bool on, int degree=0, double eigRatio=10.0)
void setStaircaseBc(int comp, CCConst theta0, CCConst solid0, CCConst resmask0, double nu_dt, double idiag, double thresh, bool upwind=false, double fouw=0.0)
int solve(CCConst b, CCField x, int nvc, int pre, int post, int bottom, double tol=0.0, Comm comm=nullComm(), double resTol=0.0)
void setBcApplyL0(std::function< void(CCField)> fn)
void setDomainBcOp(int comp, double nu_dt, double idiag)
void setAspectThreshold(double theta)
Anisotropic-coarsening aspect threshold theta (doc/anisotropic_metric.md §5.1).
void setStaircase(CCConst theta0, CCConst solid0, CCConst resmask0, double nu_dt, double idiag, double thresh)
double lastResidualRatio() const
VofMetric metric
The anisotropic cell metric (Phase 3).
VofMetric metric
The anisotropic cell metric (Phase 3); {1,1,1} == the pre-Phase-3 arithmetic.
VofMetric metric
The interfacial predicate's wisp threshold — the phase-change driver passes ITS OWN (pcEffInterfaceEp...
VofMetric metric
Which VofWettingPivot anchors the theta-plane (a measured ablation; see wetting.hpp).
void zeroPlane(CCField m, C3 e, int axis, int idx)
void ibmChebUpdate(CCField x, CCField d, CCConst r, FPC AC, CCConst solidmask, C3 e, int g, double alpha, double beta)
One Chebyshev update on the Jacobi-preconditioned system: d <- beta*d + alpha*r/AC ; x += d.
Kokkos::View< const MReal *, CCMem > FPC
void ibmCleanFluidMask(CCField m, CCConst sdf, C3 ext, Off3 off)
void ibmStencilJacobiBounds(MC AC, MC AW, MC AE, MC AS, MC AN, MC AB, MC AT, CCConst solidmask, C3 e, int g, double &lo, double &hi)
Gershgorin bounds [lo, hi] on the spectrum of the Jacobi-preconditioned cut-cell Helmholtz diag(AC)^-...
void ibmBuildDiffusionVar(MV AC, MV AW, MV AE, MV AS, MV AN, MV AB, MV AT, int ex, int ey, int ez, int g, FaceProps fp, double wx=1.0, double wy=1.0, double wz=1.0)
void ibmModifyStencil(MV AC, MV AW, MV AE, MV AS, MV AN, MV AB, MV AT, Kokkos::View< double *, IMem > a_inhom, Kokkos::View< double *, IMem > rhs_scale, const OV &ibm, int numActive, typename OV::value_type u_bc_val, Kokkos::View< const double *, IMem > u_bc=Kokkos::View< const double *, IMem >())
void ibmVolfrac(CCField theta, CCConst sdf, C3 ext, Off3 off, bool aniso=false, double hpx=1.0, double hpy=1.0, double hpz=1.0, double wx=1.0, double wy=1.0, double wz=1.0)
void residualVarPin(CCField r, CCConst x, CCConst b, FPC AC, FPC AW, FPC AE, FPC AS, FPC AN, FPC AB, FPC AT, CCConst pin, C3 e, int g)
double diffSmoothColorDu(SField c, SConst b, I3 e, I3 og, int g, double bx, double by, double bz, double Ac, int color, SConst dcorr, bool aniso)
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)
void diffResidual(SField r, SConst c, SConst b, I3 e, int g, double bx, double by, double bz, double Ac, SConst dcorr, bool aniso)
double maxAbsInner(CCConst a, C3 e, int g)
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)
Kokkos::View< double *, CCMem > CCField
double maxAbsDiffInner(CCConst a, CCConst b, C3 e, int g)
void ibmRbgsStencilColorBox(CCField x, CCConst b, MC AC, MC AW, MC AE, MC AS, MC AN, MC AB, MC AT, CCConst solidmask, C3 ext, C3 og, int color, C3 rlo, C3 rhi, C3 slo, C3 shi)
Kokkos::DefaultExecutionSpace CCExec
double ibmRbgsStencilColorDuBox(CCField x, CCConst b, MC AC, MC AW, MC AE, MC AS, MC AN, MC AB, MC AT, CCConst solidmask, C3 ext, C3 og, int color, C3 rlo, C3 rhi, C3 slo, C3 shi)
void ibmBuildDiffusion(MV AC, MV AW, MV AE, MV AS, MV AN, MV AB, MV AT, int ex, int ey, int ez, double bx, double by, double bz, double idiag)
double ibmRbgsStencilColorDu(CCField x, CCConst b, MC AC, MC AW, MC AE, MC AS, MC AN, MC AB, MC AT, CCConst solidmask, C3 ext, C3 og, int g, int color)
bool hostRunSerial(long cells)
void bcNeumannGhost(BField f, B3 ext, int g, int a, int s)
void ibmRbgsStencilColor(CCField x, CCConst b, MC AC, MC AW, MC AE, MC AS, MC AN, MC AB, MC AT, CCConst solidmask, C3 ext, C3 og, int g, int color)
void diffSmoothColor(SField c, SConst b, I3 e, I3 og, int g, double bx, double by, double bz, double Ac, int color, SConst dcorr, bool aniso)
Kokkos::View< const double *, CCMem > CCConst
The Chebyshev coefficient recurrence (Golub-Varga; the form multigrid Chebyshev smoothers use).
void next(int it, double &alpha, double &beta)
Coefficients for iteration it (0-based). Advances the recurrence.
The map between the solver's INDEX coordinates and the coordinate system the analytic scene is writte...
double w[3]
w_a = 1 / h_a'^2 (<= 1)
double org[3]
physical lower corner of the GLOBAL inner grid
double angVelToInt() const
double rhoRef
reference density = the first set_rho
double forceToInt(int a) const
vof::VofMetric vofMetric() const
bool physical
an extent was given (the scales are armed)
double h[3]
cell size per axis = extent / cells
double hp[3]
h_a' = h_a / hRef (>= 1, exactly 1 on the finest axis)
double sigmaToInt() const
double velToPhys(int a) const
double vol
V' = h_x' h_y' h_z' (cell volume in hRef^3)
long cells[3]
the GLOBAL cell counts the extent spans
bool aniso
some h_a' != 1 — kernels dispatch the per-axis body
double tRef
reference time = the first set_dt
double hRef
reference length = min_a h_a (== h_a, Phase 1)
double ext[3]
physical extent of the GLOBAL inner grid
double velToInt(int a) const
VofMetric metric
The anisotropic cell metric (Phase 3, V4.3); {1,1,1} == the pre-Phase-3 arithmetic.
static constexpr double AC
static constexpr double U