18#ifndef PECLET_FLOW_SDFLOW_IBM_HPP
19#define PECLET_FLOW_SDFLOW_IBM_HPP
26#include <Kokkos_Core.hpp>
42#include "peclet/core/field/field_set.hpp"
56 using FV = Kokkos::View<float*, CCMem>;
57 static constexpr int G = 2;
68 n_ = (std::size_t)e_.
x * e_.
y * e_.
z;
70 n1_ = (std::size_t)e1_.
x * e1_.
y * e1_.
z;
88 for (
int c = 0; c < 3; ++c) {
91 C[c].AC =
FV(
"AC", n_);
92 C[c].AW =
FV(
"AW", n_);
93 C[c].AE =
FV(
"AE", n_);
94 C[c].AS =
FV(
"AS", n_);
95 C[c].AN =
FV(
"AN", n_);
96 C[c].AB =
FV(
"AB", n_);
97 C[c].AT =
FV(
"AT", n_);
98 C[c].inhom =
CCField(
"inhom", n_);
99 C[c].rscale =
CCField(
"rscale", n_);
100 C[c].mask =
CCField(
"mask", n_);
101 bcDcorr_[c] =
CCField(
"dcorr", n_);
102 bcBrhs_[c] =
CCField(
"brhs", n_);
105 Kokkos::View<int*, CCMem>(
"nb",
maxCut),
107 Kokkos::View<int*, CCMem>(
"dc", (std::size_t)
maxCut * 6),
113 C[c].idMap = Kokkos::View<int*, CCMem>(
"idMap", n_);
114 C[c].counter = Kokkos::View<int, CCMem>(
"cnt");
116 prev_[c] =
CCField(
"uPrev", n_);
118 if constexpr (Grid::collocated) {
135 fields_.adopt(
"u", C[0].u,
G, peclet::core::Centering::FaceX);
136 fields_.adopt(
"v", C[1].u,
G, peclet::core::Centering::FaceY);
137 fields_.adopt(
"w", C[2].u,
G, peclet::core::Centering::FaceZ);
138 fields_.adopt(
"p", P_,
G, peclet::core::Centering::Cell);
139 fields_.adopt(
"sdf", sdf_,
G, peclet::core::Centering::Cell);
203 pressAgglomMode_ = mode;
204 if (cutcellPressure_)
209 if (cutcellPressure_)
233 chebBoundsSet_ =
false;
258 if constexpr (Grid::collocated) {
264 if (
on && faceInterp_ != 0)
269 if (
on && (porous_ || varRho_ || hasBc_ || useChebyshev_))
270 throw std::runtime_error(
271 "set_ghost_projection: incompatible with porous/variable-rho/domain-BC/Chebyshev (v1)");
273 throw std::runtime_error(
"set_ghost_projection: matrix_order/rhs_order must be 1 or 2");
274 if (
on && distributed_ && (hasExactCross_ || hasOpenOverride_))
275 throw std::runtime_error(
276 "set_ghost_projection: exact-crossings/openness-override are single-rank only");
277 ghostProjection_ =
on;
278 colSchemeAuto_ =
false;
291 const std::size_t n = (std::size_t)nx_ * ny_ * nz_;
293 hasExactCross_ =
false;
296 if (
t.size() != 9 * n)
297 throw std::runtime_error(
"set_exact_crossings: expected 9*nx*ny*nz values");
298#ifdef PECLET_FLOW_MPI
300 throw std::runtime_error(
"set_exact_crossings: single-rank only");
302 for (
int c = 0; c < 3; ++c)
303 for (
int k = 0;
k < 3; ++
k) {
307 Kokkos::View<
const double*, Kokkos::HostSpace,
308 Kokkos::MemoryTraits<Kokkos::Unmanaged>>(
309 t.data() + ((std::size_t)c * 3 +
k) * n, n));
311 hasExactCross_ =
true;
317 const std::vector<double>& oz) {
318 const std::size_t n = (std::size_t)nx_ * ny_ * nz_;
320 hasOpenOverride_ =
false;
323 if (ox.size() != n || oy.size() != n || oz.size() != n)
324 throw std::runtime_error(
"set_openness_override: expected nx*ny*nz values per field");
325#ifdef PECLET_FLOW_MPI
327 throw std::runtime_error(
"set_openness_override: single-rank only");
332 hasOpenOverride_ =
true;
409 static constexpr int kRetired[] = {1, 2, 10};
412 throw std::runtime_error(
413 "set_face_interp(" + std::to_string(mode) +
414 "): retired 2026-08-18 (ablation / measured divergent). Use "
415 "set_collocated_scheme(\"gauge-exact\") — the default — or \"plain\" for the "
416 "legacy first-order aperture projection.");
418 throw std::runtime_error(
"set_face_interp: unknown mode " + std::to_string(mode));
419 if (ghostProjection_ && mode != 0)
420 throw std::runtime_error(
421 "set_face_interp: incompatible with the ghost projection (set_ghost_projection(False) "
422 "first, or use set_collocated_scheme which handles the transition)");
424 colSchemeAuto_ =
false;
430 if (name !=
"ghost" && ghostProjection_) {
431 ghostProjection_ =
false;
434 if (name ==
"gauge-exact") {
437 }
else if (name ==
"gauge-2a") {
440 }
else if (name ==
"plain") {
443 }
else if (name ==
"ghost") {
454 throw std::runtime_error(
455 "set_collocated_scheme: expected \"gauge-exact\", \"gauge-2a\", \"plain\" or "
456 "\"ghost\", got \"" +
486 throw std::runtime_error(
"set_aperture_order: order must be 1 or 2");
487 apertureOrder_ = order;
491 throw std::runtime_error(
"set_fluid_only_constraint: mode must be 0, 1 or 2");
492 fluidOnlyMode_ = mode;
494 colSchemeAuto_ =
false;
515 const std::vector<double>&
ww) {
516 const std::vector<double>*
src[3] = {&
uu, &
vv, &
ww};
518 const int ex = e_.
x, ey = e_.
y,
nx = nx_,
ny = ny_,
nz = nz_, g =
G;
519 for (
int c = 0; c < 3; ++c) {
523 CCField din(
"peclet::flow::vel_in_d",
static_cast<std::size_t
>(nx_) * ny_ * nz_);
526 Kokkos::View<
const double*, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>(
529 Kokkos::parallel_for(
530 "peclet::flow::upload_velocity",
533 u((
long)(x + g) + (
long)(y + g) * ex + (
long)(z + g) * (
long)ex * ey) =
534 din((std::size_t)x + (std::size_t)y *
nx + (std::size_t)z * (std::size_t)
nx *
ny);
539#ifdef PECLET_FLOW_MPI
552 initMpi(CutcellMG::decomposition(
static_cast<std::size_t
>(size),
gnx,
gny,
gnz), comm);
561 const auto&
gs =
dec.globalSize();
567 std::array<bool, 3>
per{
true,
true,
true};
568 velHalo_ = std::make_shared<GridHaloTopology<3>>();
570 velDev_ = std::make_shared<GridHalo<double>>();
576 velDevF_ = std::make_shared<GridHalo<float>>();
578 long minExt = std::numeric_limits<long>::max();
580 for (int
k = 0;
k < 3; ++
k)
586 std::make_shared<peclet::core::decomp::BlockDecomposer<3>>(
dec);
587 const auto oig =
velHalo_->indexer().originInclGhost();
588 og_ = {(int)
oig[0] +
G, (
int)
oig[1] +
G,
598 if (!distributed_ || !
dec_)
603 const int oex = (
int)
ob.size[0] + 2 *
G,
oey = (
int)
ob.size[1] + 2 *
G,
605 const int nex = (
int)
nb.size[0] + 2 *
G,
ney = (
int)
nb.size[1] + 2 *
G,
609 const auto names = fields_.names();
611 for (std::size_t
k = 0;
k <
names.size(); ++
k) {
613 auto h = Kokkos::create_mirror_view(f);
614 Kokkos::deep_copy(
h, f);
619 std::vector<const double*>
op(
names.size());
620 std::vector<double*>
np(
names.size());
621 for (std::size_t
k = 0;
k <
names.size(); ++
k) {
625 peclet::core::decomp::redistributeGridFields<double>(*
dec_,
newDec, rank,
G, op,
np,
comm_);
631 auto scatterPadded = [&](
const std::string& name,
const std::vector<double>&
src) {
633 auto h = Kokkos::create_mirror_view(f);
634 std::memcpy(
h.data(),
src.data(),
sizeof(
double) * (std::size_t)
nex *
ney *
nez);
635 Kokkos::deep_copy(f,
h);
638 for (std::size_t
k = 0;
k <
names.size(); ++
k)
644 for (std::size_t
k = 0;
k <
names.size(); ++
k)
657 peclet::core::decomp::BlockDecomposer<3>
newDec((std::size_t)size,
671 for (
int i = 0;
i < 6; ++
i) {
683 const int a =
face / 2;
684 const int dims[3] = {e_.
x, e_.
y, e_.
z};
685 const int bax = (a + 1) % 3,
cax = (a + 2) % 3;
688 auto h = Kokkos::create_mirror_view(
pf);
689 auto cl = [](
int v,
int n) {
return v < 0 ? 0 : (v >= n ? n - 1 : v); };
690 for (
int p0 = 0; p0 <
Lb; ++p0)
693 for (
int k = 0;
k < 3; ++
k)
694 h(((
long)p0 *
Lc +
p1) * 3 +
k) =
prof[((std::size_t)
ib * nc +
ic) * 3 +
k];
696 Kokkos::deep_copy(
pf,
h);
711 if constexpr (Grid::collocated) {
719 if (colSchemeAuto_) {
720 const bool ok = !(porous_ || varRho_ || hasBc_ || useChebyshev_ || hasExactCross_ ||
721 hasOpenOverride_ || fluidOnlyMode_ != 0);
723 ghostProjection_ =
true;
729 if (ghostProjection_)
731 ghostProjection_ =
false;
734 "peclet::flow SolverColocated: AUTO scheme fell back to gauge-exact "
735 "(configuration unsupported by the ghost projection v1). Select explicitly "
736 "with set_collocated_scheme to silence this notice.\n");
740#ifdef PECLET_FLOW_MPI
752#ifdef PECLET_FLOW_MPI
759#ifdef PECLET_FLOW_MPI
764 auto h = Kokkos::create_mirror_view(sdf_);
765 Kokkos::deep_copy(
h, sdf_);
766 for (
int z = 0; z < nz_; ++z)
767 for (
int y = 0; y < ny_; ++y)
768 for (
int x = 0; x < nx_; ++x)
769 h((
long)(x +
G) + (
long)(y +
G) * e_.
x + (
long)(z +
G) * (
long)e_.
x * e_.
y) =
770 sdfInner[(std::size_t)x + (std::size_t)y * nx_ +
771 (std::size_t)z * (std::size_t)nx_ * ny_];
772 Kokkos::deep_copy(sdf_,
h);
780 CCField din(
"peclet::flow::sdfInner_d",
static_cast<std::size_t
>(nx_) * ny_ * nz_);
783 Kokkos::View<
const double*, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>(
786 const int ex = e_.
x, ey = e_.
y,
ez = e_.
z,
nx = nx_,
ny = ny_,
nz = nz_, g =
G;
788 Kokkos::parallel_for(
789 "peclet::flow::sdf_periodic_wrap",
790 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(
space, {0, 0, 0}, {ex, ey,
ez}),
794 sdf((
long)x + (
long)y * ex + (
long)z * (
long)ex * ey) =
din(
795 (std::size_t)
ix + (std::size_t)
iy *
nx + (std::size_t)
iz * (std::size_t)
nx *
ny);
799 const bool useEx = hasExactCross_ && !Grid::collocated;
801 for (
int c = 0; c < 3; ++c) {
805 CCConst(sdf_), e_,
G,
off, 0, C[c].ov, C[c].idMap, C[c].counter,
810 Kokkos::deep_copy(C[c].u, 0.0);
815 if (hasBc_ && !Grid::collocated)
817 if (useVelocityMg_) {
819 vmg_.
init(nx_, ny_, nz_, vmgLevels_);
823 vmgTheta_ =
CCField(
"vmgTheta", n_);
824 vmgClean_ =
CCField(
"vmgClean", n_);
827 if (cutcellPressure_) {
830 if (hasOpenOverride_) {
833 const std::vector<double>*
src[3] = {&oxOverride_, &oyOverride_, &ozOverride_};
835 for (
int f = 0; f < 3; ++f) {
836 CCField din(
"peclet::flow::openOv_d", (std::size_t)nx_ * ny_ * nz_);
837 Kokkos::deep_copy(
din, Kokkos::View<
const double*, Kokkos::HostSpace,
838 Kokkos::MemoryTraits<Kokkos::Unmanaged>>(
841 const int ex = e_.
x, ey = e_.
y,
ez = e_.
z,
nx = nx_,
ny = ny_,
nz = nz_, g =
G;
843 Kokkos::parallel_for(
844 "peclet::flow::open_override_wrap",
845 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(
space, {0, 0, 0}, {ex, ey,
ez}),
849 o((
long)x + (
long)y * ex + (
long)z * (
long)ex * ey) =
850 din((std::size_t)
ix + (std::size_t)
iy *
nx +
851 (std::size_t)
iz * (std::size_t)
nx *
ny);
856 if constexpr (Grid::collocated) {
859 if (faceInterp_ >= 5 &&
867 const std::size_t
nn = n_;
868 for (
int c = 0; c < 3; ++c) {
870 Kokkos::parallel_for(
871 "peclet::flow::embed_solid_mask", Kokkos::RangePolicy<CCExec>(0,
nn),
876 if (fluidOnlyMode_ == 1) {
889 for (
int a = 0; a < 3; ++a) {
891 const long sa = (a == 0) ? 1 : (a == 1) ? (
long)e.x : (
long)e.x * e.y;
892 Kokkos::parallel_for(
893 "peclet::flow::fluid_only_openness",
894 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(
CCExec(), {1, 1, 1},
897 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
898 if (
sd(
i) < 0.0 ||
sd(
i -
sa) < 0.0)
903#ifdef PECLET_FLOW_MPI
914 B3 e2{e_.
x, e_.
y, e_.
z};
916 for (
int a = 0; a < 3; ++a)
917 for (
int s = 0; s < 2; ++s) {
918 const int t = bc_[2 * a + s];
919 const bool open = (
t == 3) || (
t == 2 && (bcProf_[2 * a + s].
extent(0) > 0 ||
920 std::fabs(bcVel_[2 * a + s][a]) > 1e-12));
929 if (fluidOnlyMode_ == 2) {
934 if (porous_ || varRho_ || hasBc_ || ghostProjection_ || distributed_ || !Grid::collocated)
935 throw std::runtime_error(
936 "set_fluid_only_constraint(2): v1 is single-rank periodic collocated only");
940 const C3 e1 = e1_, e2 = e_;
941 for (
int a = 0; a < 3; ++a) {
943 const long sa2 = (a == 0) ? 1 : (a == 1) ? (
long)e2.x : (
long)e2.x * e2.y;
944 Kokkos::parallel_for(
945 "peclet::flow::star_filter_bridge",
946 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(
space, {0, 0, 0}, {nx_, ny_, nz_}),
951 o1((
long)(x + 1) + (
long)(y + 1) *
e1.x + (
long)(z + 1) * (
long)
e1.x *
e1.y) =
956 starCounter_ = Kokkos::View<int, CCMem>(
"star_counter");
957 const C3 nn{nx_, ny_, nz_};
962 starOv_, starCounter_);
964 if (ghostProjection_) {
969 if (porous_ || varRho_ || hasBc_)
970 throw std::runtime_error(
971 "ghost projection: incompatible with porous/variable-rho/domain-BC (v1)");
972 const std::size_t
nInner = (std::size_t)nx_ * ny_ * nz_;
974 gpIdMap_ = Kokkos::View<int*, CCMem>(
"gp_idmap",
nInner);
975 gpCounter_ = Kokkos::View<int, CCMem>(
"gp_counter");
998 std::vector<double>
work;
999 int fx = nx_,
fy = ny_,
fz = nz_;
1001#ifdef PECLET_FLOW_MPI
1013 for (
int r = 0; r <
nRanks; ++r) {
1014 const auto b =
dec_->block(r);
1015 cnts[r] = (int)(b.size[0] * b.size[1] * b.size[2]);
1019 std::vector<double>
flat((std::size_t)
acc);
1023 for (
int r = 0; r <
nRanks; ++r) {
1024 const auto b =
dec_->block(r);
1026 for (
int z = 0; z < (int)b.size[2]; ++z)
1027 for (
int y = 0; y < (int)b.size[1]; ++y)
1028 for (
int x = 0; x < (int)b.size[0]; ++x)
1029 work[(std::size_t)(x + b.origin[0]) + (std::size_t)(y + b.origin[1]) *
fx +
1030 (std::size_t)(z + b.origin[2]) * (std::size_t)
fx *
fy] =
1031 src[(std::size_t)x + (std::size_t)y * b.size[0] +
1032 (std::size_t)z * (std::size_t)b.size[0] * b.size[1]];
1037 const std::size_t
nTot =
work.size();
1039 auto id = [&](
int x,
int y,
int z) {
1040 return (std::size_t)((x +
nx) %
nx) + (std::size_t)((y +
ny) %
ny) *
nx +
1041 (std::size_t)((z +
nz) %
nz) * (std::size_t)
nx *
ny;
1044 std::vector<std::size_t>
stack;
1050 std::size_t size = 0;
1053 while (!
stack.empty()) {
1054 const std::size_t c =
stack.back();
1057 const int x = (int)(c %
nx), y = (int)((c /
nx) %
ny),
1058 z = (
int)(c / ((std::size_t)
nx *
ny));
1059 const int nb[6][3] = {{x - 1, y, z}, {x + 1, y, z}, {x, y - 1, z},
1060 {x, y + 1, z}, {x, y, z - 1}, {x, y, z + 1}};
1061 for (
auto&
q :
nb) {
1062 const std::size_t
j =
id(
q[0],
q[1],
q[2]);
1081 for (std::size_t
i = 0;
i <
nTot; ++
i)
1083 work[
i] = -(std::abs(
work[
i]) * 1.001 + 1e-30);
1087 printf(
"peclet::flow ghost projection: %d fluid components; decoupled %zu pocket "
1088 "cells outside the main component (%zu of %zu fluid cells)\n",
1091#ifdef PECLET_FLOW_MPI
1095 for (
int z = 0; z < nz_; ++z)
1096 for (
int y = 0; y < ny_; ++y)
1097 for (
int x = 0; x < nx_; ++x)
1098 sdfGpHost[(std::size_t)x + (std::size_t)y * nx_ +
1099 (std::size_t)z * (std::size_t)nx_ * ny_] =
1100 work[(std::size_t)(x + b.origin[0]) + (std::size_t)(y + b.origin[1]) *
fx +
1101 (std::size_t)(z + b.origin[2]) * (std::size_t)
fx *
fy];
1106 sdfGp_ =
CCField(
"peclet::flow::sdfGp", n_);
1109#ifdef PECLET_FLOW_MPI
1113 auto h = Kokkos::create_mirror_view(sdfGp_);
1114 Kokkos::deep_copy(
h, sdfGp_);
1115 for (
int z = 0; z < nz_; ++z)
1116 for (
int y = 0; y < ny_; ++y)
1117 for (
int x = 0; x < nx_; ++x)
1118 h((
long)(x +
G) + (
long)(y +
G) * e_.
x + (
long)(z +
G) * (
long)e_.
x * e_.
y) =
1119 sdfGpHost[(std::size_t)x + (std::size_t)y * nx_ +
1120 (std::size_t)z * (std::size_t)nx_ * ny_];
1121 Kokkos::deep_copy(sdfGp_,
h);
1127 Kokkos::deep_copy(
din, Kokkos::View<
const double*, Kokkos::HostSpace,
1128 Kokkos::MemoryTraits<Kokkos::Unmanaged>>(
1131 const int ex = e_.
x, ey = e_.
y,
ez = e_.
z,
nx = nx_,
ny = ny_,
nz = nz_, g =
G;
1132 Kokkos::parallel_for(
1133 "peclet::flow::sdfgp_wrap",
1134 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(
space, {0, 0, 0}, {ex, ey,
ez}),
1136 const int ix = (((x - g) %
nx) +
nx) %
nx,
iy = (((y - g) %
ny) +
ny) %
ny,
1138 sdfGp((
long)x + (
long)y * ex + (
long)z * (
long)ex * ey) =
1139 din((std::size_t)
ix + (std::size_t)
iy *
nx +
1140 (std::size_t)
iz * (std::size_t)
nx *
ny);
1146 gpCounter_, gpMatrixOrder_, gpRhsOrder_,
1153#ifdef PECLET_FLOW_MPI
1166#ifdef PECLET_FLOW_MPI
1172 mg_.
init(nx_, ny_, nz_,
1178 Kokkos::deep_copy(phi_, 0.0);
1179 Kokkos::deep_copy(P_, 0.0);
1184 const double ts0 = phaseTick();
1185 tPredictor_ = tMomentum_ = tProjection_ = 0.0;
1186 lastMomentumSweeps_ = 0;
1197 if (porous_ && porousCons_)
1202 if (((varProps_ || varRho_ || hasDrag_ || (porous_ && porousCons_)) || dtDirty_) &&
1208 for (
int c = 0; c < 3; ++c)
1209 Kokkos::deep_copy(old_[c], C[c].u);
1210 if (cutcellPressure_ && incremental_) {
1215 lastOuterIters_ = 0;
1217 const double tp0 = phaseTick();
1218 lastOuterIters_ =
outer + 1;
1220 for (
int c = 0; c < 3; ++c)
1221 Kokkos::deep_copy(prev_[c], C[c].u);
1222 if (advect_ || hasBc_ || (Grid::collocated && faceInterp_ >= 4 && faceInterp_ <= 7))
1223 for (
int c = 0; c < 3; ++c)
1235 if (porous_ && advect_)
1237 for (
int c = 0; c < 3; ++c)
1244 if (
implicitAdv() && (!hasBc_ || !useVelocityMg_))
1245 for (
int c = 0; c < 3; ++c)
1251 for (
int c = 0; c < 3; ++c)
1256 if (useVelocityMg_ && implicitFou_ && advect_ && !hasBc_)
1258 const double tp1 = phaseTick();
1259 tPredictor_ +=
tp1 -
tp0;
1260 for (
int c = 0; c < 3; ++c)
1262 const double tp2 = phaseTick();
1269 if (porous_ && !cutcellPressure_)
1270 throw std::runtime_error(
1271 "set_porous_continuity(True) requires the cut-cell pressure operator: call "
1272 "set_solid(...) or set_pressure_geometry(all-fluid SDF) before stepping (a "
1273 "domain-BC-only box otherwise runs with NO continuity constraint at all)");
1274 if (cutcellPressure_)
1276 tProjection_ += phaseTick() -
tp2;
1278 for (
int c = 0; c < 3; ++c)
1280 if (outerTol_ > 0) {
1282 for (
int c = 0; c < 3; ++c)
1284 lastOuterCorr_ =
corr;
1285 if (
corr < outerTol_)
1293 tStep_ = phaseTick() -
ts0;
1303 if constexpr (Grid::collocated) {
1315 CCField o[3] = {ox_, oy_, oz_};
1324 const bool gp = ghostProjection_ && oxb_.extent(0) > 0;
1325 CCField o[3] = {
gp ? oxb_ : ox_,
gp ? oyb_ : oy_,
gp ? ozb_ : oz_};
1335 const double ct = rho_ / dt_;
1336 for (
double& x : out)
1341 if (!cutcellPressure_)
1343 if constexpr (Grid::collocated) {
1352 B3 e{e_.
x, e_.
y, e_.
z};
1354 for (
int a = 0; a < 3; ++a)
1355 if (bc_[2 * a + 1] == 3)
1358 if (ghostProjection_ && gpNRows_ >= 0) {
1364 C3{nx_, ny_, nz_}, e_,
G, distributed_);
1369 for (
int c = 0; c < 3; ++c)
1371 if (ghostProjection_ && gpNRows_ >= 0) {
1378 C3{nx_, ny_, nz_}, e_,
G, distributed_);
1384#ifdef PECLET_FLOW_MPI
1397 if (!porous_ || !cutcellPressure_)
1399 for (
int c = 0; c < 3; ++c)
1409 const bool useDt = porousDepsDt_;
1410 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
1411 Kokkos::parallel_for(
1412 "peclet::flow::porous_resid",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1414 const long i = (
long)x + (
long)y * e.x + (
long)z * e.x * e.y;
1420#ifdef PECLET_FLOW_MPI
1441 int nx()
const {
return nx_; }
1442 int ny()
const {
return ny_; }
1443 int nz()
const {
return nz_; }
1447 CCField u, b, inhom, rscale, mask;
1448 FV AC, AW, AE, AS, AN, AB, AT;
1450 Kokkos::View<int*, CCMem> idMap;
1451 Kokkos::View<int, CCMem> counter;
1460 bool implicitAdv()
const {
return advect_ && (implicitFou_ || (hasBc_ && !useVelocityMg_)); }
1474 return hasBc_ && !useVelocityMg_ &&
1475 (hasSolid_ ||
implicitAdv() || varProps_ || varRho_ || hasDrag_);
1502 const int t = bc_[
face];
1505 if (
t == 2 ||
t == 3)
1518 bool effVarRho()
const {
return varRho_ || (porous_ && porousCons_); }
1524 const double rho = rho_;
1525 Kokkos::parallel_for(
1526 "peclet::flow::eps_rho", Kokkos::RangePolicy<CCExec>(
space, 0, n_),
1536 fp.harmMu = harmonicMu_;
1543 fp.rhoIdtC = rho_ / dt_;
1547 const double idiag = rho_ / dt_, beta = mu_;
1552 for (
int c = 0; c < 3; ++c) {
1553 Kokkos::deep_copy(C[c].rscale, 1.0);
1554 Kokkos::deep_copy(C[c].inhom, 0.0);
1561 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,
1562 C[c].rscale, C[c].ov, C[c].nCut, 0.0f);
1571 const int NX = nx_,
NY = ny_;
1572 Kokkos::parallel_for(
1573 "peclet::flow::copyInner", Kokkos::RangePolicy<CCExec>(
space, 0, (
long)nx_ * ny_ * nz_),
1575 const int ix = (int)(c % NX),
iy = (int)((c / NX) %
NY),
iz = (
int)(c / ((
long)NX *
NY));
1590 Kokkos::parallel_for(
1591 "peclet::flow::copyBlockShifted",
1592 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(
space, {0, 0, 0}, {
de.x,
de.y,
de.z}),
1603#ifdef PECLET_FLOW_MPI
1621#ifdef PECLET_FLOW_MPI
1629 const int Nx = nx_,
Ny = ny_,
Nz = nz_;
1630 const long sx = 1,
sy = e.x,
sz = (
long)e.x * e.y;
1632 Kokkos::parallel_for(
1633 "peclet::flow::ibm_facefill", Kokkos::RangePolicy<CCExec>(
space, 0, (
long)nx_ * ny_ * nz_),
1639 else if (
ix >=
Nx -
G)
1643 else if (
iy >=
Ny -
G)
1647 else if (
iz >=
Nz -
G)
1654 int N3[3] = {nx_, ny_, nz_};
1655 int dims[3] = {e.x, e.y, e.z};
1656 long st[3] = {1, e.x, (
long)e.x * e.y};
1657 const int a = axis, b = (axis + 1) % 3, c = (axis + 2) % 3;
1658 const long sa = st[a],
sb = st[b], sc = st[c];
1659 const int N =
N3[a];
1661 Kokkos::parallel_for(
1662 "peclet::flow::ibm_pfill",
1665 const long base = (
long)p0 *
sb + (
long)
p1 * sc;
1666 for (
int gl = 0;
gl <
G; ++
gl) {
1680 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
1681 Kokkos::parallel_for(
1682 "peclet::flow::div_adv",
1683 MD(
space, {
G - 1,
G - 1,
G - 1}, {e.x -
G + 1, e.y -
G + 1, e.z -
G + 1}),
1685 const long sx = 1,
sy = e.x,
sz = (
long)e.x * e.y;
1693 const double idiag = rho_ / dt_, fc = f_[c], rho = rho_;
1698 const long strd = (c == 0) ? 1 : (c == 1) ? e_.
x : (
long)e_.
x * e_.
y;
1703 const bool incr = cutcellPressure_ && incremental_,
adv = advect_ && !
pureFou,
1712 const int sch = advScheme_;
1717 const bool tg = Grid::collocated && faceInterp_ >= 2 && faceInterp_ <= 5 &&
incr;
1719 const bool wg = Grid::collocated && (faceInterp_ == 6 || faceInterp_ == 7) &&
incr;
1723 const bool ag = Grid::collocated && (faceInterp_ >= 11 && faceInterp_ <= 13) &&
incr;
1729 Grid::collocated && (ghostProjection_ || faceInterp_ == 9 || faceInterp_ == 10) &&
incr;
1730 if constexpr (Grid::collocated) {
1737 faceInterp_ >= 3, c, e_,
G);
1743 if (faceInterp_ == 12)
1746 else if (faceInterp_ == 13)
1761 const bool pc = porous_ && advect_;
1763 const bool wd = Grid::collocated && faceInterp_ >= 4 && faceInterp_ <= 7;
1764 if constexpr (Grid::collocated)
1770 if (faceInterp_ >= 5)
1778 const double fvw = fvRelax_;
1784 "rhs",
C3{
G,
G,
G},
C3{e.x -
G, e.y -
G, e.z -
G},
1786 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
1787 double aK = 0.0,
aF = 0.0;
1789 sadv::ViewAcc Ua{U, e.x, e.y},
Va{
V, e.x, e.y},
Wa{
W, e.x, e.y},
Fa{
uu, e.x, e.y};
1790 aK = (
sch == 0) ? Grid::advect_sou(c, x, y, z,
Ua,
Va,
Wa,
Fa)
1791 : Grid::advect(c, x, y, z,
Ua,
Va,
Wa,
Fa);
1793 aF = Grid::advect_fou(c, x, y, z,
Ua,
Va,
Wa,
Fa);
1806 const double bfv = idiag * cs(
i) *
un(
i) + cs(
i) * (fc -
gp);
1809 const double comp =
pc ? rho *
uu(
i) * 0.5 * (dv(
i) + dv((
long)
i -
strd)) : 0.0;
1821 const double idiag = rho_ / dt_, fc = f_[c], rho = rho_;
1827 const long strd = (c == 0) ? 1 : (c == 1) ? e_.
x : (
long)e_.
x * e_.
y;
1829 const bool incr = cutcellPressure_ && incremental_,
adv = advect_ && !
pureFou,
1832 const int sch = advScheme_;
1834 const bool pc = porous_ && advect_;
1836 const bool tg = Grid::collocated && faceInterp_ >= 2 && faceInterp_ <= 5 &&
1839 Grid::collocated && (ghostProjection_ || faceInterp_ == 9 || faceInterp_ == 10) &&
1842 Grid::collocated && (faceInterp_ >= 11 && faceInterp_ <= 13) &&
incr;
1843 if constexpr (Grid::collocated) {
1850 faceInterp_ >= 3, c, e_,
G);
1853 if (faceInterp_ == 12)
1856 else if (faceInterp_ == 13)
1863 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
1864 Kokkos::parallel_for(
1865 "rhs_forced",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1867 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
1868 double aK = 0.0,
aF = 0.0;
1870 sadv::ViewAcc Ua{U, e.x, e.y},
Va{
V, e.x, e.y},
Wa{
W, e.x, e.y},
Fa{
uu, e.x, e.y};
1871 aK = (
sch == 0) ? Grid::advect_sou(c, x, y, z,
Ua,
Va,
Wa,
Fa)
1872 : Grid::advect(c, x, y, z,
Ua,
Va,
Wa,
Fa);
1874 aF = Grid::advect_fou(c, x, y, z,
Ua,
Va,
Wa,
Fa);
1876 const double gp = !
incr ? 0.0
1881 const double comp =
pc ? rho *
uu(
i) * 0.5 * (dv(
i) + dv((
long)
i -
strd)) : 0.0;
1894 const double idt = 1.0 / dt_, fc = f_[c];
1903 const bool incr = cutcellPressure_ && incremental_,
adv = advect_ && !
pureFou,
1906 const int sch = advScheme_;
1910 const bool pc = porous_ && advect_;
1912 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
1913 Kokkos::parallel_for(
1914 "rhs_var",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1916 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
1918 double aK = 0.0,
aF = 0.0;
1920 sadv::ViewAcc Ua{U, e.x, e.y},
Va{
V, e.x, e.y},
Wa{
W, e.x, e.y},
Fa{
uu, e.x, e.y};
1921 aK = (
sch == 0) ? Grid::advect_sou(c, x, y, z,
Ua,
Va,
Wa,
Fa)
1922 : Grid::advect(c, x, y, z,
Ua,
Va,
Wa,
Fa);
1924 aF = Grid::advect_fou(c, x, y, z,
Ua,
Va,
Wa,
Fa);
1926 const double gp = !
incr ? 0.0
1927 : Grid::collocated ? 0.5 * (
P((
long)
i +
strd) -
P((
long)
i -
strd))
1940 const double idiag = rho_ / dt_, beta = mu_,
fouw = rho_;
1942 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,
1945 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,
1948 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
1949 Kokkos::parallel_for(
1950 "advstencil",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1952 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
1956 Grid::fou_operator(c, x, y, z,
Ua,
Va,
Wa,
fouw,
cC,
cxm,
cxp,
cym,
cyp,
czm,
czp);
1966 Kokkos::deep_copy(C[c].rscale, 1.0);
1967 Kokkos::deep_copy(C[c].inhom, 0.0);
1968 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,
1969 C[c].rscale, C[c].ov, C[c].nCut, 0.0f);
1983 if (!varRho_ && porous_ && porousCons_)
1989 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,
1993 const double rhoC = rho_;
1996 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
1997 Kokkos::parallel_for(
1998 "advstencil_var",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
2000 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
2005 Grid::fou_operator(c, x, y, z,
Ua,
Va,
Wa,
fouw,
cC,
cxm,
cxp,
cym,
cyp,
czm,
czp);
2014 Kokkos::deep_copy(C[c].rscale, 1.0);
2015 Kokkos::deep_copy(C[c].inhom, 0.0);
2016 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,
2017 C[c].rscale, C[c].ov, C[c].nCut, 0.0f);
2031 if (backflowBeta_ <= 0.0 || !hasOutflow_)
2034 const double beta = backflowBeta_, rho = rho_;
2036 int dims[3] = {e.x, e.y, e.z};
2037 long st[3] = {1, e.x, (
long)e.x * e.y};
2041 for (
int s = 0; s < 2; ++s) {
2042 if (bc_[2 * a + s] != 3)
2044 const long sa = st[a];
2046 const int bic = (s == 0) ?
G : (
na -
G - 1);
2047 const double sgn = (s == 0) ? 1.0 : -1.0;
2048 const int b = (a + 1) % 3,
cc = (a + 2) % 3;
2049 const long sb = st[b], sc = st[
cc];
2050 using MD2 = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<2>>;
2051 Kokkos::parallel_for(
2058 AC(
i) += (float)(beta * rho *
back);
2067 Kokkos::parallel_reduce(
2070 {e.x -
G, e.y -
G, e.z -
G}),
2072 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
2073 const double d = Kokkos::fabs(a(
i) - b(
i));
2077 Kokkos::Max<double>(m));
2084 template <
class Fill,
class Color,
class ColorDu>
2087 int used = velIters_;
2088 for (
int it = 0;
it < velIters_; ++
it) {
2092 if (velTol_ > 0.0) {
2094#ifdef PECLET_FLOW_MPI
2103 if (
it + 1 >= velMinIters_ && du <= velTol_ *
du0) {
2111 lastMomentumSweeps_ +=
used;
2115 if constexpr (Grid::collocated) {
2170 vmg_.
solve(
CCConst(C[c].b), C[c].u, vmgVcycles_, 2, 2, 8);
2174 const I3 e{e_.
x, e_.
y, e_.
z}, og{0, 0, 0};
2175 const double beta = mu_,
Ac = rho_ / dt_ + 6.0 * mu_;
2187 if (useVelocityMg_) {
2190 FPC(C[c].AB),
FPC(C[c].AT));
2191 if (implicitFou_ && advect_) {
2206 vmg_.
solve(
CCConst(C[c].b), C[c].u, vmgVcycles_, 2, 2, 8);
2213#ifdef PECLET_FLOW_MPI
2233 for (
FV* a : {&C[c].AC, &C[c].AW, &C[c].AE, &C[c].AS, &C[c].AN, &C[c].AB, &C[c].AT})
2239 const C3 lo{
G + 1,
G + 1,
G + 1},
hi{e_.
x -
G - 1, e_.
y -
G - 1, e_.
z -
G - 1};
2240 const C3 rlo{
G - 1,
G - 1,
G - 1},
rhi{e_.
x -
G + 1, e_.
y -
G + 1, e_.
z -
G + 1};
2241 const C3 z0{0, 0, 0};
2246 velDev_->exchangeBegin(C[c].u);
2282 const C3 lo{
G + 1,
G + 1,
G + 1},
hi{e_.
x -
G - 1, e_.
y -
G - 1, e_.
z -
G - 1};
2283 const C3 z0{0, 0, 0};
2287 velDev_->exchangeBegin(C[c].u);
2299 velDev_->exchangeBegin(C[c].u);
2336 int dims[3] = {e.x, e.y, e.z};
2337 long st[3] = {1, e.x, (
long)e.x * e.y};
2338 for (
int a = 0; a < 3; ++a)
2339 for (
int s = 0; s < 2; ++s) {
2340 if (bc_[2 * a + s] == 0)
2342 const int b = (a + 1) % 3, c = (a + 2) % 3;
2343 const long sa = st[a],
sb = st[b], sc = st[c];
2345 const int bic = (s == 0) ?
G : (
na -
G - 1);
2346 const int lo = (s == 0) ? 0 : (
na -
G),
hi = (s == 0) ? (
G - 1) : (
na - 1);
2347 Kokkos::parallel_for(
2351 const long base = (
long)p0 *
sb + (
long)
p1 * sc;
2352 const double pin =
P(base + (
long)
bic *
sa);
2354 P(base + (
long)
ia *
sa) = pin;
2367#ifdef PECLET_FLOW_MPI
2374 for (
int a = 0; a < 3; ++a)
2375 if (bc_[2 * a] == 0 && bc_[2 * a + 1] == 0)
2382 B3 e{e_.
x, e_.
y, e_.
z};
2383 if constexpr (Grid::collocated) {
2388 for (
int a = 0; a < 3; ++a)
2389 for (
int s = 0; s < 2; ++s) {
2390 const int ff = 2 * a + s;
2391 const int t = bc_[
ff];
2408 for (
int a = 0; a < 3; ++a)
2409 for (
int s = 0; s < 2; ++s) {
2410 const int ff = 2 * a + s;
2411 const int t = bc_[
ff];
2429 const double beta = mu_;
2430 B3 e{e_.
x, e_.
y, e_.
z};
2431 for (
int c = 0; c < 3; ++c) {
2432 Kokkos::deep_copy(bcDcorr_[c], 0.0);
2433 Kokkos::deep_copy(bcBrhs_[c], 0.0);
2434 for (
int a = 0; a < 3; ++a)
2435 for (
int s = 0; s < 2; ++s) {
2436 const int t = bc_[2 * a + s];
2441 }
else if (
t != 0 && c != a) {
2443 bval = 2.0 * beta * bcVel_[2 * a + s][c];
2460 Kokkos::deep_copy(tgp_, f);
2464 const double eps = rotFilterEps_;
2466 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
2467 Kokkos::parallel_for(
2468 "peclet::flow::rot_filter",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
2470 const long sy = e.x,
sz = (
long)e.x * e.y;
2472 const long sa = (axis == 0) ? 1 : (axis == 1) ?
sy :
sz;
2475 const bool am =
sd(
i -
sa) >= 0.0, ap =
sd(
i +
sa) >= 0.0;
2497 if constexpr (Grid::collocated) {
2502 for (
int c = 0; c < 3; ++c)
2504 if ((faceInterp_ >= 1 && faceInterp_ <= 5) || faceInterp_ == 7 ||
2508 faceInterp_ >= 3, e_,
G);
2511 if (ghostProjection_) {
2517 throw std::runtime_error(
"ghost projection: call set_solid after set_ghost_projection");
2518 if (porous_ || varRho_ || useChebyshev_)
2519 throw std::runtime_error(
2520 "ghost projection: porous/variable-rho/Chebyshev unsupported (v1)");
2524 C3{nx_, ny_, nz_}, e_,
G, distributed_);
2529 for (
int c = 0; c < 3; ++c)
2538 }
else if (ghostProjection_) {
2543 throw std::runtime_error(
"ghost projection: call set_solid after set_ghost_projection");
2544 if (porous_ || varRho_ || useChebyshev_)
2545 throw std::runtime_error(
2546 "ghost projection: porous/variable-rho/Chebyshev unsupported (v1)");
2550 C3{nx_, ny_, nz_}, e_,
G, distributed_);
2563 const double idt = 1.0 / dt_;
2564 const bool useDt = porousDepsDt_;
2565 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
2566 Kokkos::parallel_for(
2567 "peclet::flow::deps_dt",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
2569 const long i = (
long)x + (
long)y * e.x + (
long)z * e.x * e.y;
2581 Kokkos::parallel_for(
2582 "negdiv", Kokkos::RangePolicy<CCExec>(
space, 0, n1_),
2585 if (fluidOnlyMode_ == 2) {
2589 throw std::runtime_error(
"set_fluid_only_constraint(2): Chebyshev unsupported (v1)");
2593 const C3 e1 = e1_, e2 = e_;
2594 Kokkos::parallel_for(
2595 "peclet::flow::star_mask_rhs",
2596 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(
space, {0, 0, 0}, {nx_, ny_, nz_}),
2601 r((
long)(x + 1) + (
long)(y + 1) *
e1.x + (
long)(z + 1) * (
long)
e1.x *
e1.y) = 0.0;
2619 chebBoundsSet_ =
false;
2635 }
else if (porousCons_) {
2636 Kokkos::deep_copy(beta1_, 0.0);
2644 }
else if (hasDrag_) {
2653 chebBoundsSet_ =
false;
2660 Kokkos::deep_copy(phi1_, 0.0);
2661 if (useChebyshev_) {
2662 if (!chebBoundsSet_) {
2664 chebBoundsSet_ =
true;
2666 lastPressureIters_ =
2667 mg_.
solveChebyshev(rhs1_, phi1_, chebMaxit_, chebRtol_, 2, 2, 12, chebA_, chebB_);
2668 }
else if (ghostProjection_) {
2674#ifdef PECLET_FLOW_MPI
2676 lastPressureIters_ =
2677 mg_.
solveBiCGStab(rhs1_, phi1_, r_, gpRh_, pp_, Ap_, gpT_, z_, gpZ2_, pcgMaxit_,
2678 pcgRtol_, 2, 2, 12, gpOv_, gpNRows_,
C3{nx_, ny_, nz_}, gpX2_,
2682 lastPressureIters_ =
2683 mg_.
solveBiCGStab(rhs1_, phi1_, r_, gpRh_, pp_, Ap_, gpT_, z_, gpZ2_, pcgMaxit_,
2684 pcgRtol_, 2, 2, 12, gpOv_, gpNRows_,
C3{nx_, ny_, nz_});
2697 auto idMap = gpIdMap_;
2699 const C3 e1 = e1_, e2 = e_;
2700 const int lnx = nx_,
lny = ny_;
2701 Kokkos::parallel_for(
2702 "peclet::flow::gp_pin_decoupled",
2703 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(
space, {0, 0, 0}, {nx_, ny_, nz_}),
2709 bool dec = sg(
i2) < 0.0;
2711 const int s = idMap((
long)x + (
long)y *
lnx + (
long)z * (
long)
lnx *
lny);
2712 if (s >= 0 && ov.coupled(s) == 0)
2720 lastPressureIters_ =
2721 mg_.
solvePCG(rhs1_, phi1_, r_, pp_, z_, Ap_, pcgMaxit_, pcgRtol_, 2, 2, 12,
2722 fluidOnlyMode_ == 2 ? &starOv_ :
nullptr, nStar_,
C3{nx_, ny_, nz_});
2724 if (fluidOnlyMode_ == 2) {
2731 const C3 e1 = e1_, e2 = e_;
2732 Kokkos::parallel_for(
2733 "peclet::flow::star_pin_solid",
2734 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(
space, {0, 0, 0}, {nx_, ny_, nz_}),
2739 ph((
long)(x + 1) + (
long)(y + 1) *
e1.x + (
long)(z + 1) * (
long)
e1.x *
e1.y) = 0.0;
2746 B3 e{e_.
x, e_.
y, e_.
z};
2747 for (
int a = 0; a < 3; ++a)
2748 for (
int s = 0; s < 2; ++s)
2749 if (bc_[2 * a + s] == 3)
2752 if constexpr (Grid::collocated) {
2758 B3 e{e_.
x, e_.
y, e_.
z};
2759 for (
int a = 0; a < 3; ++a)
2760 for (
int s = 0; s < 2; ++s) {
2761 const int t = bc_[2 * a + s];
2762 if (
t != 0 &&
t != 3)
2769 if (fluidOnlyMode_ == 2)
2771 C3{nx_, ny_, nz_}, e_,
G, e_,
G);
2777 B3 e{e_.x, e_.y, e_.z};
2779 for (
int a = 0; a < 3; ++a)
2780 if (bc_[2 * a + 1] == 3)
2783 if (ghostProjection_ || faceInterp_ == 9 || faceInterp_ == 10) {
2789 for (
int cc = 0;
cc < 3; ++
cc) {
2793 }
else if (faceInterp_ >= 2 &&
2798 for (
int cc = 0;
cc < 3; ++
cc) {
2803 }
else if (faceInterp_ == 6 ||
2808 }
else if (faceInterp_ >= 11 && faceInterp_ <= 13) {
2814 for (
int cc = 0;
cc < 3; ++
cc) {
2815 if (faceInterp_ == 12)
2818 else if (faceInterp_ == 13)
2829 if (porous_ && porousCons_)
2832 CCConst(dragBeta_), hasDrag_, rho_ / dt_, e_,
G);
2843 B3 e{e_.
x, e_.
y, e_.
z};
2844 for (
int a = 0; a < 3; ++a)
2845 if (bc_[2 * a + 1] == 3)
2852 for (
int c = 0; c < 3; ++c)
2858 if (rotFilter_ && rotationalP_)
2859 for (
int a = 0; a < 3; ++a)
2868 const double ct = pressUnderRelax_ * rho_ / dt_,
2869 mu = rotationalP_ ? rotWeight_ * mu_ : 0.0;
2875 if (varRotMode_ == 1) {
2877 const double chi = varRotChi_;
2878 Kokkos::parallel_for(
2879 "press_var_full", Kokkos::RangePolicy<CCExec>(
space, 0, n_),
2882 const double muRot = (varRotMode_ == 2) ? 0.0 : varRotChi_ *
minMuInner();
2883 Kokkos::parallel_for(
2884 "press_var_min", Kokkos::RangePolicy<CCExec>(
space, 0, n_),
2887 }
else if (rotWallW_ > 0.0 && rotationalP_) {
2897 const double w0 = rotWallW_,
muF = rotWeight_ * mu_;
2899 Kokkos::parallel_for(
2900 "press_wallblend", Kokkos::RangePolicy<CCExec>(
space, 0, n_),
2902 const long sy = e.x,
sz = (
long)e.x * e.y;
2903 const int x = (int)(
i % e.x), y = (int)((
i / e.x) % e.y), z = (
int)(
i /
sz);
2905 if (x > 0 && y > 0 && z > 0 && x < e.x - 1 && y < e.y - 1 && z < e.z - 1 &&
2907 (
sd(
i - 1) < 0.0 ||
sd(
i + 1) < 0.0 ||
sd(
i -
sy) < 0.0 ||
sd(
i +
sy) < 0.0 ||
2913 Kokkos::parallel_for(
2914 "press", Kokkos::RangePolicy<CCExec>(
space, 0, n_),
2920 Kokkos::deep_copy(epsPrev_, epsField_);
2924 CCField u = C[c].u, m = C[c].mask;
2925 Kokkos::parallel_for(
2938 Kokkos::parallel_reduce(
2941 {e.x -
G, e.y -
G, e.z -
G}),
2943 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
2947 Kokkos::Min<double>(m));
2948#ifdef PECLET_FLOW_MPI
2961 Kokkos::parallel_reduce(
2964 {e.x -
G, e.y -
G, e.z -
G}),
2966 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
2967 const double a = Kokkos::fabs(f(
i));
2971 Kokkos::Max<double>(m));
2975 auto h = Kokkos::create_mirror_view(
fld);
2976 Kokkos::deep_copy(
h,
fld);
2977 std::vector<double> out((std::size_t)nx_ * ny_ * nz_);
2978 for (
int z = 0; z < nz_; ++z)
2979 for (
int y = 0; y < ny_; ++y)
2980 for (
int x = 0; x < nx_; ++x)
2981 out[(std::size_t)x + (std::size_t)y * nx_ + (std::size_t)z * (std::size_t)nx_ * ny_] =
2982 h((
long)(x +
G) + (
long)(y +
G) * e_.
x + (
long)(z +
G) * (
long)e_.
x * e_.
y);
2988 if (
in.size() != (std::size_t)nx_ * ny_ * nz_)
2989 throw std::runtime_error(
"flow::setField: array size does not match the inner grid");
2990 auto h = Kokkos::create_mirror_view(
fld);
2991 Kokkos::deep_copy(
h,
fld);
2992 for (
int z = 0; z < nz_; ++z)
2993 for (
int y = 0; y < ny_; ++y)
2994 for (
int x = 0; x < nx_; ++x)
2995 h((
long)(x +
G) + (
long)(y +
G) * e_.
x + (
long)(z +
G) * (
long)e_.
x * e_.
y) =
2996 in[(std::size_t)x + (std::size_t)y * nx_ + (std::size_t)z * (std::size_t)nx_ * ny_];
2997 Kokkos::deep_copy(
fld,
h);
3004 if (fields_.has(name))
3005 return fields_.at(name).data;
3006 return fields_.add(name, n_,
G, peclet::core::Centering::Cell).data;
3008 bool hasField(
const std::string& name)
const {
return fields_.has(name); }
3010 std::vector<std::string>
fieldNames()
const {
return fields_.names(); }
3019#ifdef PECLET_FLOW_MPI
3021 CCField f = fields_.at(name).data;
3022 auto h = Kokkos::create_mirror_view(f);
3023 Kokkos::deep_copy(
h, f);
3024 peclet::core::halo::GridFieldView<double>
view{
h.data()};
3026 Kokkos::deep_copy(f,
h);
3034 std::vector<double>
getField(
const std::string& name) {
3037 void setField(
const std::string& name,
const std::vector<double>& v) {
3046#ifdef PECLET_FLOW_MPI
3050 return {nx_, ny_, nz_};
3061 void addScalar(
const std::string& name,
double D,
int scheme,
int iters) {
3065 sc.cOld =
CCField(name +
"_old", n_);
3066 sc.b =
CCField(name +
"_b", n_);
3067 sc.AC =
CCField(name +
"_AC", n_);
3068 sc.AW =
CCField(name +
"_AW", n_);
3069 sc.AE =
CCField(name +
"_AE", n_);
3070 sc.AS =
CCField(name +
"_AS", n_);
3071 sc.AN =
CCField(name +
"_AN", n_);
3072 sc.AB =
CCField(name +
"_AB", n_);
3073 sc.AT =
CCField(name +
"_AT", n_);
3076 sc.iters = iters < 1 ? 1 : iters;
3077 scalars_.push_back(sc);
3080 for (
const auto& sc : scalars_)
3081 if (sc.name == name)
3088 for (
auto& sc : scalars_)
3089 if (sc.name == name) {
3094 throw std::runtime_error(
"set_scalar_bc: no scalar named '" + name +
"'");
3100 if (scalars_.empty())
3102 const double idt = 1.0 / dt_;
3104 if constexpr (Grid::collocated) {
3116 for (
auto& sc : scalars_) {
3119 applyScalarBcStencil(sc);
3120 Kokkos::deep_copy(sc.cOld, sc.c);
3121 scalarFillGhosts(sc);
3125 for (
int it = 0;
it < sc.iters; ++
it) {
3126 scalarFillGhosts(sc);
3127 cutcellSmoothColor(sc.c,
CCConst(sc.b), sc.AC, sc.AW, sc.AE, sc.AS, sc.AN, sc.AB, sc.AT, e_,
3129 scalarFillGhosts(sc);
3130 cutcellSmoothColor(sc.c,
CCConst(sc.b), sc.AC, sc.AW, sc.AE, sc.AS, sc.AN, sc.AB, sc.AT, e_,
3133 scalarFillGhosts(sc);
3144 const std::string& in1,
const std::vector<double>&
params) {
3151 for (
int k = 0;
k < 4 &&
k < (int)
params.size(); ++
k)
3153 closures_.push_back(
cl);
3168 if constexpr (Grid::collocated) {
3170 throw std::runtime_error(
"set_density_mode: variable density is staggered-only (v1)");
3174 if (fields_.has(
"rho"))
3175 rhoField_ = fields_.at(
"rho").data;
3178 Kokkos::deep_copy(rhoField_, rho_);
3180 if (rho1_.extent(0) == 0) {
3186 ensureCellForceAll();
3187 useVelocityMg_ =
false;
3195 useChebyshev_ =
true;
3196 chebBoundsSet_ =
false;
3209 if constexpr (Grid::collocated) {
3211 throw std::runtime_error(
"set_porous_continuity: staggered-only (v1)");
3215 if (fields_.has(
"eps"))
3216 epsField_ = fields_.at(
"eps").data;
3219 Kokkos::deep_copy(epsField_, 1.0);
3221 if (epsPrev_.extent(0) == 0) {
3222 epsPrev_ =
CCField(
"epsPrev", n_);
3223 depsdt_ =
CCField(
"depsdt", n_);
3225 if (divAdv_.extent(0) == 0)
3226 divAdv_ =
CCField(
"divAdv", n_);
3227 if (epsRho_.extent(0) == 0)
3228 epsRho_ =
CCField(
"epsRho", n_);
3233 ensureCellForceAll();
3234 Kokkos::deep_copy(epsPrev_, epsField_);
3235 if (eps1_.extent(0) == 0)
3237 if (beta1_.extent(0) == 0)
3238 beta1_ =
CCField(
"beta1", n1_);
3239 if (rho1_.extent(0) == 0) {
3249 useChebyshev_ =
true;
3250 chebBoundsSet_ =
false;
3260 Kokkos::deep_copy(epsPrev_, epsField_);
3275 harmonicMu_ = harmonic;
3277 if (fields_.has(
"mu"))
3278 muField_ = fields_.at(
"mu").data;
3281 Kokkos::deep_copy(muField_,
3307 varRotMode_ = mode < 0 ? 0 : (mode > 2 ? 2 : mode);
3308 varRotChi_ =
chi < 0.0 ? 0.0 :
chi;
3313 const std::vector<double>&
xs,
const std::vector<double>&
ys) {
3318 cl.nTab = (int)std::min(
xs.size(),
ys.size());
3321 auto hx = Kokkos::create_mirror_view(
cl.tabX);
3322 auto hy = Kokkos::create_mirror_view(
cl.tabY);
3323 for (
int k = 0;
k <
cl.nTab; ++
k) {
3327 Kokkos::deep_copy(
cl.tabX,
hx);
3328 Kokkos::deep_copy(
cl.tabY,
hy);
3329 closures_.push_back(
cl);
3333 for (
auto&
cl : closures_)
3347 if (!fields_.has(
"drag_beta"))
3350 dragBeta_ = fields_.at(
"drag_beta").data;
3351 ensureCellForceAll();
3360 if (!(porous_ && hasDrag_))
3362 pressGraphAmg_ =
true;
3365 if (cutcellPressure_)
3367 useChebyshev_ =
false;
3368 chebBoundsSet_ =
false;
3389 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
3390 Kokkos::parallel_for(
3391 "peclet::flow::add_drag_diag",
MD(
space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
3393 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
3396 AC(
i) = (float)((
double)
AC(
i) +
bd);
3403 CCField ensureTarget(
const std::string& name) {
3404 if (name ==
"force_x" || name ==
"force_y" || name ==
"force_z")
3405 ensureCellForceAll();
3408 void ensureCellForceAll() {
3409 static const char*
fn[3] = {
"force_x",
"force_y",
"force_z"};
3410 for (
int c = 0; c < 3; ++c)
3412 hasCellForce_ =
true;
3416 void scalarFillGhosts(ScalarField& sc) {
3426 void applyScalarBc(ScalarField& sc) {
3427 for (
int f = 0;
f < 6; ++
f)
3428 if (
sc.bc[f] != 0 && touchesGlobalFace(f))
3432 bool touchesGlobalFace(
int f)
const {
3433#ifdef PECLET_FLOW_MPI
3435 const int a =
f / 2;
3436 const int o = (
a == 0) ? og_.
x : (
a == 1) ? og_.y : og_.
z;
3437 const int n = (
a == 0) ? nx_ : (
a == 1) ? ny_ : nz_;
3439 return (f % 2 == 0) ? (
o == 0) : (
o +
n ==
gn);
3449 void applyScalarBcStencil(ScalarField& sc) {
3450 for (
int f = 0;
f < 6; ++
f) {
3451 if (
sc.bc[f] != 2 || !touchesGlobalFace(f))
3453 const int a =
f / 2,
side =
f % 2;
3455 : (
a == 1) ? (
side == 0 ?
sc.AS :
sc.AN)
3464 const int t1 = (a + 1) % 3,
t2 = (a + 2) % 3;
3465 const int nt1 = (
t1 == 0) ? nx_ : (
t1 == 1) ? ny_ : nz_;
3466 const int nt2 = (
t2 == 0) ? nx_ : (
t2 == 1) ? ny_ : nz_;
3467 const int na = (a == 0) ? nx_ : (a == 1) ? ny_ : nz_;
3469 const long sa = (a == 0) ?
sx : (a == 1) ?
sy :
sz;
3472 const int aInner = (side == 0) ?
G : (
G +
na - 1);
3474 Kokkos::parallel_for(
3475 "peclet::flow::scalar_bc_stencil",
3481 AC(
i) += D + band(
i);
3486 const int t1 = (a + 1) % 3,
t2 = (a + 2) % 3;
3487 const int nt1 = (
t1 == 0) ? nx_ : (
t1 == 1) ? ny_ : nz_;
3488 const int nt2 = (
t2 == 0) ? nx_ : (
t2 == 1) ? ny_ : nz_;
3489 const int na = (a == 0) ? nx_ : (a == 1) ? ny_ : nz_;
3491 const long sa = (a == 0) ?
sx : (a == 1) ?
sy :
sz;
3494 const int aInner = (side == 0) ?
G : (
G +
na - 1);
3495 const int dir = (side == 0) ? -1 : +1;
3497 Kokkos::parallel_for(
3498 "peclet::flow::scalar_bc_face",
3502 for (
int L = 1;
L <= 2; ++
L) {
3513 std::size_t n_, n1_;
3514 double rho_ = 1.0, mu_ = 0.1, dt_ = 50.0;
3515 std::array<double, 3> f_{{0, 0, 0}};
3516 int velIters_ = 200, presIters_ = 20;
3517 double velTol_ = 0.0;
3518 int velMinIters_ = 2;
3519 long lastMomentumSweeps_ = 0;
3520 int pcgMaxit_ = 500;
3521 double pcgRtol_ = 1e-10;
3522 bool useChebyshev_ =
false,
3523 chebBoundsSet_ =
false;
3524 int chebMaxit_ = 120;
3525 double chebRtol_ = 1e-9, chebA_ = 0.0, chebB_ = 0.0;
3527 bool pressGraphAmg_ =
false;
3532 int pressAgglomMode_ = -1;
3533 long lastPressureIters_ = 0;
3537 bool distributed_ =
false;
3539#ifdef PECLET_FLOW_MPI
3540 std::shared_ptr<GridHaloTopology<3>>
velHalo_;
3541 std::shared_ptr<GridHalo<double>>
velDev_;
3542 std::shared_ptr<GridHalo<float>>
velDevF_;
3545 std::shared_ptr<peclet::core::decomp::BlockDecomposer<3>>
3550 int bc_[6] = {0, 0, 0, 0, 0, 0};
3551 double bcVel_[6][3] = {};
3552 bool hasBc_ =
false, hasOutflow_ =
false;
3556 double backflowBeta_ =
3560 int bcProfNc_[6] = {0, 0, 0, 0, 0, 0};
3561 CCField bcDcorr_[3], bcBrhs_[3];
3562 bool advect_ =
false, cutcellPressure_ =
false, implicitFou_ =
false;
3563 bool deferredCorr_ =
true;
3565 bool incremental_ =
true,
3567 bool dtDirty_ =
false;
3568 int faceInterp_ = 9;
3569 double apertureFloor_ = [] {
3570 const char* v = std::getenv(
"PECLET_FLOW_APERTURE_FLOOR");
3571 return v ? std::atof(v) : 0.25;
3573 bool gauge2a_ =
false;
3577 bool rotationalP_ =
true;
3579 bool rotFilter_ =
false;
3584 double rotFilterEps_ = 0.05;
3585 double rotWeight_ = 1.0;
3586 double rotWallW_ = 0.0;
3587 int apertureOrder_ = 1;
3588 int fluidOnlyMode_ = 0;
3589 StarOverlay starOv_;
3590 Kokkos::View<int, CCMem> starCounter_;
3592 double fvRelax_ = 1.0;
3593 bool useVelocityMg_ =
false;
3594 int vmgLevels_ = 4, vmgVcycles_ = 8;
3597 int outerIters_ = 1;
3598 double outerTol_ = 0.0;
3599 long lastOuterIters_ = 0;
3600 double lastOuterCorr_ = 0.0;
3602 double tStep_ = 0.0, tPredictor_ = 0.0, tMomentum_ = 0.0, tProjection_ = 0.0;
3605 static double phaseTick() {
3607 return std::chrono::duration<double>(std::chrono::steady_clock::now().
time_since_epoch())
3610 CCField sdf_, ox_, oy_, oz_, phi_, div_, P_, ox1_, oy1_, oz1_, rhs1_, phi1_, r_, z_, pp_, Ap_;
3611 bool ghostProjection_ =
false;
3612 bool colSchemeAuto_ = Grid::collocated;
3615 Kokkos::View<int*, CCMem> gpIdMap_;
3616 Kokkos::View<int, CCMem> gpCounter_;
3618 int gpMatrixOrder_ = 2, gpRhsOrder_ = 2;
3620 bool hasExactCross_ =
false;
3621 std::vector<double> oxOverride_, oyOverride_, ozOverride_;
3622 bool hasOpenOverride_ =
false;
3635 peclet::core::FieldSet fields_;
3636 std::vector<ScalarField> scalars_;
3637 std::vector<Closure> closures_;
3639 bool hasCellForce_ =
false;
3640 bool varProps_ =
false;
3641 bool harmonicMu_ =
false;
3643 int varRotMode_ = 0;
3644 double varRotChi_ = 1.0;
3645 bool varRho_ =
false;
3647 CCField rho1_, cx1_, cy1_, cz1_;
3648 bool porous_ =
false;
3649 double pressUnderRelax_ = 1.0;
3650 bool porousDepsDt_ =
true;
3654 CCField epsField_, epsPrev_, eps1_, depsdt_;
3661 bool porousCons_ =
true;
3663 bool hasDrag_ =
false;
int solveChebyshev(CCField b, CCField x, int maxit, double rtol, int pre, int post, int bottom, double a, double bnd)
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 resetAllreduceCounters()
void setGraphAmgBottom(bool on)
void setOpenness(CCConst ox, CCConst oy, CCConst oz, double idx2, double idy2, double idz2)
void setBoundaryConditions(const int bc[6])
long allreduceCount() const
double allreduceSeconds() const
void setAgglomerationMode(int mode)
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 GpOverlay &ov, int nOv, C3 nn)
void init(int nx, int ny, int nz, int nLevels)
void setMeanRemovalScope(bool all)
void estimateEigenvalues(CCConst seed, double &lmin, double &lmax, int iters, int pre, int post, int bottom)
bool hasCutcellPressure() const
void setPressureMeanRemoval(bool all)
std::vector< double > getFaceVelocity(int c)
std::array< int, 3 > globalResolution() const
void fillVelGhosts(int comp, int fold)
void setIncrementalPressure(bool on)
void velSweepLoop(Fill &&fill, Color &&sweepColor, ColorDu &&sweepColorDu)
long lastPressureAllreduceCount() const
void setVelocityTolerance(double rtol, int minIters)
void scatterInner(CCField fld, const std::vector< double > &in)
void setSolid(const std::vector< double > &sdfInner, bool cutcellPressure)
void setPressurePcg(bool, int maxit, double rtol)
void setFvRelax(double w)
void fillGhosts(CCField f)
long lastOuterIterations() const
void setDomainBc(int face, int type, double vx, double vy, double vz)
double lastStepSeconds() const
void setFaceInterp(int mode)
void applyBackflowStab(int c)
std::vector< double > getField(const std::string &name)
void setPropertyMode(bool variable, bool harmonic)
void fillVelGhostsTo(CCField f, int comp, int fold)
double lastPressureAllreduceSeconds() const
void applyVelocityBcComp(int comp, int fold, bool doOutflow)
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 maxOpenDivergence()
void setPressureGraphAmg(bool on)
void fillGhostsFaces(CCField f)
void exchangeFieldAdd(const std::string &name)
void setVelocityStreams(bool)
void exchangeField(const std::string &name)
void setAdvection(bool on)
double maxPorousResidual()
void uploadVelocity(const std::vector< double > &uu, const std::vector< double > &vv, const std::vector< double > &ww)
void copyInner(CCField dst, C3 de, int dg, CCConst src, C3 se, int sg)
void applyVelocityBcCompTo(CCField f, int comp, int fold, bool doOutflow)
void setPropertyModel(const std::string &target, ClosureKind kind, const std::string &in0, const std::string &in1, const std::vector< double > ¶ms)
double maxAbsDiffInner(CCConst a, CCConst b)
void setBackflowStab(double beta)
void fillPropGhosts(CCField f)
void setVelocityIterations(int it)
void setPressureChebyshev(bool on, int maxit, double rtol)
void setScalarBc(const std::string &name, int face, int type, double value)
std::vector< double > getOpenness(int c)
Solver(int nx, int ny, int nz)
void addDragDiagonal(int c)
void setGhostProjection(bool on, int matrixOrder=2, int rhsOrder=2)
void patchScalarDirichletFace(CCField AC, CCField band, double D, int a, int side)
void setVariableRotational(int mode, double chi)
void setPressureUnderRelax(double w)
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 setPressureGeometry(const std::vector< double > &sdfInner)
void fillAxis(CCField f, int axis)
void setPorousDepsDt(bool on)
void setField(const std::string &name, const std::vector< double > &v)
void setApertureOrder(int order)
double lastProjectionSeconds() const
void setBodyForce(double fx, double fy, double fz)
std::vector< double > getOpennessProj(int c)
void applyScalarBcFace(CCField c, int a, int side, int type, double val)
std::vector< double > getVelocity(int c)
void setPorousConservative(bool on)
std::array< int, 3 > blockShape() const
long strideOf(int c) const
bool hasField(const std::string &name) const
void setDomainBcProfile(int face, const std::vector< double > &prof, int nb, int nc)
void setAdvectionScheme(int s)
long lastPressureIterations() const
void allocateBlock(int nx, int ny, int nz)
void setVelocityMultigrid(bool on, int levels, int vcycles)
void setRotationalWeight(double w)
void setDensityMode(bool variable)
double lastPredictorSeconds() const
bool hasScalar(const std::string &name) const
void setExactCrossings(const std::vector< double > &t)
void setPressureWarmstart(bool on)
void setPressureIterations(int it)
void setPropertyTable(const std::string &target, const std::string &in0, const std::vector< double > &xs, const std::vector< double > &ys)
void configurePorousDragSolver()
void buildAdvStencil(int c)
Kokkos::View< float *, CCMem > FV
CCField fieldView(const std::string &name)
void setCollocatedScheme(const std::string &name)
double lastMomentumSeconds() const
void filterCellField(CCField f, int axis)
void addScalar(const std::string &name, double D, int scheme, int iters)
void buildAdvStencilVar(int c)
bool bcStencilPath() const
void setImplicitAdvection(bool on)
void setPressureBottomMode(int mode)
VarFaceProps makeFaceProps(int c)
void setRotationalWallWeight(double w0)
double reduceMaxAbsInner(CCConst f)
void setPorousContinuity(bool on)
void setRotationalFilter(bool on, double eps=0.05)
void buildRhsForced(int c)
std::vector< std::string > fieldNames() const
std::vector< double > gatherInner(CCField fld)
void copyBlockShifted(CCField dst, C3 de, CCConst src, C3 se, int off)
void fillPorousEpsGhosts()
std::vector< double > getPressure()
void setOuterIterations(int iters)
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 setBcApplyL0(std::function< void(CCField)> fn)
void setDomainBcOp(int comp, double nu_dt, double idiag)
void solve(CCConst b, CCField x, int nvc, int pre, int post, int bottom)
void restrictAdvVelocities(CCConst u0, CCConst v0, CCConst w0)
void setStaircase(CCConst theta0, CCConst solid0, CCConst resmask0, double nu_dt, double idiag, double thresh)
void setBC(const int bc[6])
void init(int nx, int ny, int nz, int nLevels)
flow — face/cell material-property accessors for the variable-coefficient momentum operator.
flow — the gauge-exact directional cell-centre pressure gradient.
flow — OPT-IN forensics for the ghost-projection overlay (PECLET_FLOW_GP_DEBUG).
flow — GridLayout policy traits (placement of the velocity unknowns).
flow — collocated approximate (MAC) projection helpers (Almgren–Bell–Colella style).
flow — portable (Kokkos) geometric multigrid for the cut-cell (variable-openness) pressure Poisson.
flow — portable (Kokkos) IBM geometric fields + variable-coefficient RB-GS smoother.
flow — portable (Kokkos) cut-cell pressure operator + Chorin projection.
flow — portable (Kokkos) MAC stencil operators: Red-Black Gauss-Seidel smoothers + divergence.
flow — portable (Kokkos) velocity (momentum) multigrid for the IBM diffusion solve: the STAIRCASE coa...
void transposeGradWallAware(CCField out, CCConst p, CCConst sdf, CCConst o, CCConst xc, bool useCen, int axis, C3 e, int g)
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 projectCorrectPorousDrag(CCField u, CCField v, CCField w, CCConst phi, CCConst beta, double idt, C3 e, int g)
void projectCorrectCenterOpen(CCField u, CCField v, CCField w, CCConst phi, CCConst ox, CCConst oy, CCConst oz, C3 e, int g)
void buildFaceCentroidDist(CCField xcx, CCField xcy, CCField xcz, CCConst sdf, C3 e)
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 ibmSolidMask(CCField mask, CCConst sdf, C3 ext, Off3 off)
void bcZeroPressureGhost(BField phi, B3 ext, int g, int a, int s)
void ibmCleanFluidMask(CCField m, CCConst sdf, C3 ext, Off3 off)
void gpBinaryOpenness(CCField ox, CCField oy, CCField oz, CCConst sdf, C3 ext)
Binary openness for the symmetric MG surrogate, on the extended-block layout of buildOpenness: o(face...
void subtractField(CCField u, CCConst d, C3 e, int g)
void stencilMatvec(CCField y, CCConst u, MConst AC, MConst AW, MConst AE, MConst AS, MConst AN, MConst AB, MConst AT, C3 e, int g)
StarOverlay starMakeOverlay(long n)
void buildCellFraction(CCField cs, CCConst sdf, C3 e, int g)
void divergOpen(CCConst u, CCConst v, CCConst w, CCConst ox, CCConst oy, CCConst oz, CCField d, C3 e, int g)
void bcZeroOpenness(BField oa, B3 ext, int g, int a, int s)
double ibmRbgsStencilColorDuBox(CCField x, CCConst b, MConst AC, MConst AW, MConst AE, MConst AS, MConst AN, MConst AB, MConst AT, CCConst solidmask, C3 ext, C3 og, int color, C3 rlo, C3 rhi, C3 slo, C3 shi)
void diffSmoothColor(SField c, SConst b, I3 e, I3 og, int g, double beta, double Ac, int color, SConst dcorr)
double ibmRbgsStencilColorDu(CCField x, CCConst b, MConst AC, MConst AW, MConst AE, MConst AS, MConst AN, MConst AB, MConst AT, CCConst solidmask, C3 ext, C3 og, int g, int color)
void centerGradApertureScaled(CCField out, CCConst p, CCConst ox, CCConst oy, CCConst oz, int axis, C3 e, int g)
int buildStarOverlay(CCConst sdf, CCConst ox, CCConst oy, CCConst oz, C3 ext, int g, C3 nn, const StarOverlay &ov, Kokkos::View< int, CCMem > counter)
Count + fill the star overlay from the cell-centered sdf and the ORIGINAL (unfiltered) apertures on t...
int gpDebugLevel()
0 = off (default). Read once per call; cheap enough, and keeps the flag hot-swappable in tests.
void bcDiffusionFold(BField dcorr, BField brhs, B3 ext, int g, int a, int s, double dval, double bval)
double diffSmoothColorDu(SField c, SConst b, I3 e, I3 og, int g, double beta, double Ac, int color, SConst dcorr)
void ibmBuildDiffusionVar(Kokkos::View< float *, IMem > AC, Kokkos::View< float *, IMem > AW, Kokkos::View< float *, IMem > AE, Kokkos::View< float *, IMem > AS, Kokkos::View< float *, IMem > AN, Kokkos::View< float *, IMem > AB, Kokkos::View< float *, IMem > AT, int ex, int ey, int ez, int g, FaceProps fp)
void ibmRbgsStencilColor(CCField x, CCConst b, MConst AC, MConst AW, MConst AE, MConst AS, MConst AN, MConst AB, MConst AT, CCConst solidmask, C3 ext, C3 og, int g, int color)
void bcVelocityColocated(BField f, B3 ext, int g, int a, int s, double wall, int comp=0, BField prof=BField(), int prof_nc=0)
GpOverlayT< CCMem > GpOverlay
void projectCorrectVar(CCField u, CCField v, CCField w, CCConst phi, CCConst rho, double rho0, C3 e, int g)
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 fvViscousApply(CCField Lu, CCConst U, CCConst sdf, CCConst cs, CCConst ox, CCConst oy, CCConst oz, double mu, double idt, 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)
Fix the face correction at fluid|solid faces: projectCorrect applied -(phi_hi - phi_lo) with the soli...
void gpDebugReport(const GpOverlay &ov, int nRows, C3 nn, Kokkos::View< int *, CCMem > idMap, int rank=0)
Census + optional per-row dump of the built overlay.
void ibmBuildDiffusion(Kokkos::View< float *, IMem > AC, Kokkos::View< float *, IMem > AW, Kokkos::View< float *, IMem > AE, Kokkos::View< float *, IMem > AS, Kokkos::View< float *, IMem > AN, Kokkos::View< float *, IMem > AB, Kokkos::View< float *, IMem > AT, int ex, int ey, int ez, double beta, double idiag)
void centerGradOpen(CCField out, CCConst p, CCConst o, int axis, C3 e, int g)
GpOverlay gpMakeOverlay(long n)
void bcCorrectOutflow(BField f, BField phi, B3 ext, int g, int a)
void gpCenterGrad(CCField out, CCConst p, CCConst sdf, int axis, C3 e, int g, bool grad2a=false)
Directional cell-center gradient (collocated ghost path) of a cell field p whose solid-centered rows ...
void centerGradAperture(CCField out, CCConst p, CCConst o, int axis, C3 e, int g)
void bcVelocityComp(BField f, B3 ext, int g, int a, int s, int comp, double wall, int fold, BField prof=BField(), int prof_nc=0)
void embedViscousApply(CCField Lu, CCConst U, CCConst sdf, CCConst cs, CCConst ox, CCConst oy, CCConst oz, double mu, double idt, 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)
void ibmFillEntry(const OV &o, int list_idx, int c_idx, float sdf_c, const float sdf_n[6], int bc_type, const float *thEx)
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)
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)
void ibmModifyStencil(Kokkos::View< float *, IMem > AC, Kokkos::View< float *, IMem > AW, Kokkos::View< float *, IMem > AE, Kokkos::View< float *, IMem > AS, Kokkos::View< float *, IMem > AN, Kokkos::View< float *, IMem > AB, Kokkos::View< float *, IMem > AT, Kokkos::View< double *, IMem > a_inhom, Kokkos::View< double *, IMem > rhs_scale, const IbmOverlay &ibm, int numActive, float u_bc_val)
void buildPorousCoeff(CCField cx, CCField cy, CCField cz, CCConst ox, CCConst oy, CCConst oz, CCConst eps, C3 e, int g)
void gpDivergDelta(CCField d, CCConst u, CCConst v, CCConst w, const GpOverlay &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),...
Kokkos::DefaultExecutionSpace CCExec
void projectCorrectCenter(CCField u, CCField v, CCField w, CCConst phi, CCConst ox, CCConst oy, CCConst oz, 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 ibmRbgsStencilColorBox(CCField x, CCConst b, MConst AC, MConst AW, MConst AE, MConst AS, MConst AN, MConst AB, MConst AT, CCConst solidmask, C3 ext, C3 og, int color, C3 rlo, C3 rhi, C3 slo, C3 shi)
Kokkos::View< const float *, CCMem > MConst
void projectCorrectPorousCons(CCField u, CCField v, CCField w, CCConst phi, CCConst eps, CCConst beta, bool useBeta, double rhoidt, C3 e, int g)
void centerGradOpenCapped(CCField out, CCConst p, CCConst o, int axis, double omin, C3 e, int g)
void buildOpenness(CCField ox, CCField oy, CCField oz, CCConst sdf, C3 ext, double dx, double dy, double dz, int order=1)
void bcOutflowComp(BField f, B3 ext, int g, int a, int s, int comp, int fold)
void applyClosure(const Closure &cl, C3 e, int g)
void bcNeumannGhost(BField f, B3 ext, int g, int a, int s)
Kokkos::View< const double *, CCMem > CCConst
void projectCorrect(CCField u, CCField v, CCField w, CCConst phi, C3 e, int g)
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)
void ibmVolfrac(CCField theta, CCConst sdf, C3 ext, Off3 off)
int buildGpOverlay(CCConst sdf, C3 ext, int g, C3 nn, const GpOverlay &ov, Kokkos::View< int *, CCMem > idMap, Kokkos::View< int, CCMem > counter, int matrixOrder=2, int rhsOrder=2, CCConst tx=CCConst(), CCConst ty=CCConst(), CCConst tz=CCConst(), bool useGhost=false)
Build the overlay over the inner grid nn from the cell-centered sdf on the extended block (ext,...
flow — device property closures: material properties / body forces as functions of fields.
flow — cell-centred scalar transport (advection–diffusion) on the cut-cell grid.
flow — portable (Kokkos) staggered MAC momentum advection (Koren TVD + FOU).
One entry per eliminated solid-centered cell: packed INNER flat index + the apertures of its (up to 6...
static constexpr double AC
Kokkos::View< float *, IMem > FV