18#ifndef PECLET_FLOW_SDFLOW_IBM_HPP
19#define PECLET_FLOW_SDFLOW_IBM_HPP
24#include <Kokkos_Core.hpp>
36#include "peclet/core/field/field_set.hpp"
50 using FV = Kokkos::View<float*, CCMem>;
51 static constexpr int G = 2;
62 n_ = (std::size_t)e_.
x * e_.
y * e_.
z;
64 n1_ = (std::size_t)e1_.
x * e1_.
y * e1_.
z;
82 for (
int c = 0; c < 3; ++c) {
85 C[c].AC =
FV(
"AC", n_);
86 C[c].AW =
FV(
"AW", n_);
87 C[c].AE =
FV(
"AE", n_);
88 C[c].AS =
FV(
"AS", n_);
89 C[c].AN =
FV(
"AN", n_);
90 C[c].AB =
FV(
"AB", n_);
91 C[c].AT =
FV(
"AT", n_);
92 C[c].inhom =
CCField(
"inhom", n_);
93 C[c].rscale =
CCField(
"rscale", n_);
94 C[c].mask =
CCField(
"mask", n_);
95 bcDcorr_[c] =
CCField(
"dcorr", n_);
96 bcBrhs_[c] =
CCField(
"brhs", n_);
97 const int maxCut =
nx *
ny *
nz;
98 C[c].ov =
IbmOverlay{Kokkos::View<int*, CCMem>(
"ci", maxCut),
99 Kokkos::View<int*, CCMem>(
"nb", maxCut),
101 Kokkos::View<int*, CCMem>(
"dc", (std::size_t)maxCut * 6),
102 FV(
"K", (std::size_t)maxCut * 6),
103 FV(
"M", (std::size_t)maxCut * 6),
104 FV(
"X", (std::size_t)maxCut * 6),
105 FV(
"Nbc", (std::size_t)maxCut * 6),
106 FV(
"R", (std::size_t)maxCut * 6)};
107 C[c].idMap = Kokkos::View<int*, CCMem>(
"idMap", n_);
108 C[c].counter = Kokkos::View<int, CCMem>(
"cnt");
110 prev_[c] =
CCField(
"uPrev", n_);
112 if constexpr (Grid::collocated) {
129 fields_.adopt(
"u", C[0].u,
G, peclet::core::Centering::FaceX);
130 fields_.adopt(
"v", C[1].u,
G, peclet::core::Centering::FaceY);
131 fields_.adopt(
"w", C[2].u,
G, peclet::core::Centering::FaceZ);
132 fields_.adopt(
"p", P_,
G, peclet::core::Centering::Cell);
133 fields_.adopt(
"sdf", sdf_,
G, peclet::core::Centering::Cell);
139 void setBodyForce(
double fx,
double fy,
double fz) { f_ = {fx, fy, fz}; }
165 vmgLevels_ = levels < 1 ? 1 : levels;
166 vmgVcycles_ = vcycles < 1 ? 1 : vcycles;
175 if (cutcellPressure_)
180 nLevels_ = levels < 1 ? 1 : levels;
199 chebBoundsSet_ =
false;
255 void uploadVelocity(
const std::vector<double>& uu,
const std::vector<double>& vv,
256 const std::vector<double>& ww) {
257 const std::vector<double>* src[3] = {&uu, &vv, &ww};
259 const int ex = e_.
x, ey = e_.
y,
nx = nx_,
ny = ny_,
nz = nz_, g =
G;
260 for (
int c = 0; c < 3; ++c) {
264 CCField din(
"peclet::flow::vel_in_d",
static_cast<std::size_t
>(nx_) * ny_ * nz_);
267 Kokkos::View<
const double*, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>(
268 src[c]->data(), src[c]->size()));
270 Kokkos::parallel_for(
271 "peclet::flow::upload_velocity",
272 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(space, {0, 0, 0}, {
nx,
ny,
nz}),
273 KOKKOS_LAMBDA(
int x,
int y,
int z) {
274 u((
long)(x + g) + (
long)(y + g) * ex + (
long)(z + g) * (
long)ex * ey) =
275 din((std::size_t)x + (std::size_t)y *
nx + (std::size_t)z * (std::size_t)
nx *
ny);
280#ifdef PECLET_FLOW_MPI
286 void initMpi(
int gnx,
int gny,
int gnz, MPI_Comm comm) {
288 MPI_Comm_size(comm, &size);
289 peclet::core::decomp::BlockDecomposer<3> dec(
static_cast<std::size_t
>(size),
290 peclet::core::IVec<3>{gnx, gny, gnz});
297 void initMpi(
const peclet::core::decomp::BlockDecomposer<3>& dec, MPI_Comm comm) {
300 const auto& gs = dec.globalSize();
305 MPI_Comm_rank(comm, &rank);
306 std::array<bool, 3> per{
true,
true,
true};
307 velHalo_ = std::make_shared<GridHaloTopology<3>>();
308 velHalo_->buildTopology(dec, rank,
G, per, comm);
309 velDev_ = std::make_shared<GridHalo<double>>();
310 velDev_->init(*velHalo_);
312 std::make_shared<peclet::core::decomp::BlockDecomposer<3>>(dec);
313 const auto oig = velHalo_->indexer().originInclGhost();
314 og_ = {(int)oig[0] +
G, (
int)oig[1] +
G,
323 void redistribute(
const peclet::core::decomp::BlockDecomposer<3>& newDec) {
324 if (!distributed_ || !dec_)
327 MPI_Comm_rank(comm_, &rank);
328 const auto ob = dec_->block(rank), nb = newDec.block(rank);
329 const int oex = (int)ob.size[0] + 2 *
G, oey = (
int)ob.size[1] + 2 *
G,
330 oez = (int)ob.size[2] + 2 *
G;
331 const int nex = (int)nb.size[0] + 2 *
G, ney = (
int)nb.size[1] + 2 *
G,
332 nez = (int)nb.size[2] + 2 *
G;
335 const auto names = fields_.names();
336 std::vector<std::vector<double>> oldHost(names.size()), newHost(names.size());
337 for (std::size_t k = 0; k < names.size(); ++k) {
338 CCField f = fields_.at(names[k]).data;
339 auto h = Kokkos::create_mirror_view(f);
340 Kokkos::deep_copy(h, f);
341 oldHost[k].assign(h.data(), h.data() + (std::size_t)oex * oey * oez);
342 newHost[k].assign((std::size_t)nex * ney * nez, 0.0);
345 std::vector<const double*> op(names.size());
346 std::vector<double*> np(names.size());
347 for (std::size_t k = 0; k < names.size(); ++k) {
348 op[k] = oldHost[k].data();
349 np[k] = newHost[k].data();
351 peclet::core::decomp::redistributeGridFields<double>(*dec_, newDec, rank,
G, op, np, comm_);
354 allocateBlock((
int)nb.size[0], (
int)nb.size[1], (
int)nb.size[2]);
355 initMpi(newDec, comm_);
357 auto scatterPadded = [&](
const std::string& name,
const std::vector<double>& src) {
359 auto h = Kokkos::create_mirror_view(f);
360 std::memcpy(h.data(), src.data(),
sizeof(
double) * (std::size_t)nex * ney * nez);
361 Kokkos::deep_copy(f, h);
364 for (std::size_t k = 0; k < names.size(); ++k)
365 scatterPadded(names[k], newHost[k]);
370 for (std::size_t k = 0; k < names.size(); ++k)
371 if (names[k] !=
"sdf")
372 scatterPadded(names[k], newHost[k]);
378 void rebalanceByWeights(
const std::vector<peclet::core::Real>& w) {
382 MPI_Comm_size(comm_, &size);
383 peclet::core::decomp::BlockDecomposer<3> newDec((std::size_t)size,
384 peclet::core::IVec<3>{gnx_, gny_, gnz_}, w);
385 redistribute(newDec);
390 void setDomainBc(
int face,
int type,
double vx,
double vy,
double vz) {
392 bcVel_[face][0] = vx;
393 bcVel_[face][1] = vy;
394 bcVel_[face][2] = vz;
397 for (
int i = 0; i < 6; ++i) {
409 const int a = face / 2;
410 const int dims[3] = {e_.
x, e_.
y, e_.
z};
411 const int bax = (a + 1) % 3, cax = (a + 2) % 3;
412 const int Lb = dims[bax], Lc = dims[cax];
413 CCField pf(
"bcprof", (std::size_t)Lb * Lc * 3);
414 auto h = Kokkos::create_mirror_view(pf);
415 auto cl = [](
int v,
int n) {
return v < 0 ? 0 : (v >= n ? n - 1 : v); };
416 for (
int p0 = 0; p0 < Lb; ++p0)
417 for (
int p1 = 0; p1 < Lc; ++p1) {
418 const int ib = cl(p0 -
G, nb), ic = cl(p1 -
G, nc);
419 for (
int k = 0; k < 3; ++k)
420 h(((
long)p0 * Lc + p1) * 3 + k) = prof[((std::size_t)ib * nc + ic) * 3 + k];
422 Kokkos::deep_copy(pf, h);
424 bcProfNc_[face] = Lc;
435 void setSolid(
const std::vector<double>& sdfInner,
bool cutcellPressure) {
436 cutcellPressure_ = cutcellPressure;
445#ifdef PECLET_FLOW_MPI
447 int local = hasSolid_ ? 1 : 0, global = 0;
448 MPI_Allreduce(&local, &global, 1, MPI_INT, MPI_MAX, comm_);
449 hasSolid_ = global != 0;
452#ifdef PECLET_FLOW_MPI
457 auto h = Kokkos::create_mirror_view(sdf_);
458 Kokkos::deep_copy(h, sdf_);
459 for (
int z = 0; z < nz_; ++z)
460 for (
int y = 0; y < ny_; ++y)
461 for (
int x = 0; x < nx_; ++x)
462 h((
long)(x +
G) + (
long)(y +
G) * e_.
x + (
long)(z +
G) * (
long)e_.
x * e_.
y) =
463 sdfInner[(std::size_t)x + (std::size_t)y * nx_ +
464 (std::size_t)z * (std::size_t)nx_ * ny_];
465 Kokkos::deep_copy(sdf_, h);
466 velDev_->exchange(sdf_);
473 CCField din(
"peclet::flow::sdfInner_d",
static_cast<std::size_t
>(nx_) * ny_ * nz_);
476 Kokkos::View<
const double*, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>(
477 sdfInner.data(), sdfInner.size()));
479 const int ex = e_.
x, ey = e_.
y, ez = e_.
z,
nx = nx_,
ny = ny_,
nz = nz_, g =
G;
481 Kokkos::parallel_for(
482 "peclet::flow::sdf_periodic_wrap",
483 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(space, {0, 0, 0}, {ex, ey, ez}),
484 KOKKOS_LAMBDA(
int x,
int y,
int z) {
485 const int ix = (((x - g) %
nx) +
nx) %
nx, iy = (((y - g) %
ny) +
ny) %
ny,
486 iz = (((z - g) %
nz) +
nz) %
nz;
487 sdf((
long)x + (
long)y * ex + (
long)z * (
long)ex * ey) = din(
488 (std::size_t)ix + (std::size_t)iy *
nx + (std::size_t)iz * (std::size_t)
nx *
ny);
492 for (
int c = 0; c < 3; ++c) {
495 C[c].nCut = buildIbmOverlay<0>(
496 CCConst(sdf_), e_,
G, off, 0, C[c].ov, C[c].idMap,
499 Kokkos::deep_copy(C[c].u, 0.0);
504 if (hasBc_ && !Grid::collocated)
506 if (useVelocityMg_) {
508 vmg_.
init(nx_, ny_, nz_, vmgLevels_);
512 vmgTheta_ =
CCField(
"vmgTheta", n_);
513 vmgClean_ =
CCField(
"vmgClean", n_);
516 if (cutcellPressure_) {
518 if constexpr (Grid::collocated) {
528 const std::size_t nn = n_;
529 for (
int c = 0; c < 3; ++c) {
531 Kokkos::parallel_for(
532 "peclet::flow::embed_solid_mask", Kokkos::RangePolicy<CCExec>(0, nn),
533 KOKKOS_LAMBDA(std::size_t i) { m(i) = cs(i) < 1e-6 ? 1.0 : 0.0; });
537#ifdef PECLET_FLOW_MPI
541 velDev_->exchange(ox_);
542 velDev_->exchange(oy_);
543 velDev_->exchange(oz_);
548 B3 e2{e_.
x, e_.
y, e_.
z};
549 CCField oa[3] = {ox_, oy_, oz_};
550 for (
int a = 0; a < 3; ++a)
551 for (
int s = 0; s < 2; ++s) {
552 const int t = bc_[2 * a + s];
553 const bool open = (t == 3) || (t == 2 && (bcProf_[2 * a + s].extent(0) > 0 ||
554 std::fabs(bcVel_[2 * a + s][a]) > 1e-12));
563#ifdef PECLET_FLOW_MPI
566 mg_.initMpi(gnx_, gny_, gnz_, nLevels_, comm_, dec_.get());
569 mg_.
init(nx_, ny_, nz_,
575 Kokkos::deep_copy(phi_, 0.0);
576 Kokkos::deep_copy(P_, 0.0);
587 if ((varProps_ || varRho_ || hasDrag_) && !
implicitAdv())
591 for (
int c = 0; c < 3; ++c)
592 Kokkos::deep_copy(old_[c], C[c].u);
593 if (cutcellPressure_ && incremental_) {
599 for (
int outer = 0; outer < outerIters_; ++outer) {
600 lastOuterIters_ = outer + 1;
602 for (
int c = 0; c < 3; ++c)
603 Kokkos::deep_copy(prev_[c], C[c].u);
604 if (advect_ || hasBc_ || (Grid::collocated && faceInterp_ >= 4))
605 for (
int c = 0; c < 3; ++c)
608 for (
int c = 0; c < 3; ++c)
616 for (
int c = 0; c < 3; ++c)
622 for (
int c = 0; c < 3; ++c)
627 if (useVelocityMg_ && implicitFou_ && advect_ && !hasBc_)
629 for (
int c = 0; c < 3; ++c)
631 if (cutcellPressure_)
634 for (
int c = 0; c < 3; ++c)
638 for (
int c = 0; c < 3; ++c)
640 lastOuterCorr_ = corr;
641 if (corr < outerTol_)
658 if constexpr (Grid::collocated) {
659 CCField fa[3] = {uf_, vf_, wf_};
670 CCField o[3] = {ox_, oy_, oz_};
680 const double ct = rho_ / dt_;
681 for (
double& x : out)
686 if (!cutcellPressure_)
688 if constexpr (Grid::collocated) {
697 B3 e{e_.
x, e_.
y, e_.
z};
698 CCField fa[3] = {uf_, vf_, wf_};
699 for (
int a = 0; a < 3; ++a)
700 if (bc_[2 * a + 1] == 3)
706 for (
int c = 0; c < 3; ++c)
712#ifdef PECLET_FLOW_MPI
715 MPI_Allreduce(&m, &g, 1, MPI_DOUBLE, MPI_MAX, comm_);
725 if (!porous_ || !cutcellPressure_)
727 for (
int c = 0; c < 3; ++c)
734 CCField d = div_, dd = depsdt_;
735 const bool useDt = porousDepsDt_;
736 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
737 Kokkos::parallel_for(
738 "peclet::flow::porous_resid", MD(space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
739 KOKKOS_LAMBDA(
int x,
int y,
int z) {
740 const long i = (long)x + (
long)y * e.x + (long)z * e.x * e.y;
746#ifdef PECLET_FLOW_MPI
749 MPI_Allreduce(&m, &g, 1, MPI_DOUBLE, MPI_MAX, comm_);
756 int nx()
const {
return nx_; }
757 int ny()
const {
return ny_; }
758 int nz()
const {
return nz_; }
762 CCField u, b, inhom, rscale, mask;
763 FV AC, AW, AE, AS, AN, AB, AT;
765 Kokkos::View<int*, CCMem> idMap;
766 Kokkos::View<int, CCMem> counter;
775 bool implicitAdv()
const {
return advect_ && (implicitFou_ || (hasBc_ && !useVelocityMg_)); }
789 return hasBc_ && !useVelocityMg_ &&
790 (hasSolid_ ||
implicitAdv() || varProps_ || varRho_ || hasDrag_);
798 for (
int face = 0; face < 6; ++face)
804 long strideOf(
int c)
const {
return (c == 0) ? 1 : (c == 1) ? e_.
x : (long)e_.
x * e_.
y; }
826 const double idiag = rho_ / dt_, beta = mu_;
831 for (
int c = 0; c < 3; ++c) {
832 Kokkos::deep_copy(C[c].rscale, 1.0);
833 Kokkos::deep_copy(C[c].inhom, 0.0);
834 if (varProps_ || varRho_)
840 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,
841 C[c].rscale, C[c].ov, C[c].nCut, 0.0f);
850 const int NX = nx_, NY = ny_;
851 Kokkos::parallel_for(
852 "peclet::flow::copyInner", Kokkos::RangePolicy<CCExec>(space, 0, (
long)nx_ * ny_ * nz_),
853 KOKKOS_LAMBDA(
long c) {
854 const int ix = (int)(c % NX), iy = (int)((c / NX) % NY), iz = (
int)(c / ((long)NX * NY));
856 (long)(ix + dg) + (long)(iy + dg) * de.
x + (long)(iz + dg) * (long)de.
x * de.
y;
858 (long)(ix + sg) + (long)(iy + sg) * se.
x + (long)(iz + sg) * (long)se.
x * se.
y;
869 Kokkos::parallel_for(
870 "peclet::flow::copyBlockShifted",
871 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(space, {0, 0, 0}, {de.
x, de.
y, de.
z}),
872 KOKKOS_LAMBDA(
int x,
int y,
int z) {
873 const long di = (long)x + (
long)y * de.
x + (long)z * (
long)de.
x * de.
y;
875 (long)(x + off) + (long)(y + off) * se.
x + (long)(z + off) * (long)se.
x * se.
y;
882#ifdef PECLET_FLOW_MPI
884 velDev_->exchange(f);
900#ifdef PECLET_FLOW_MPI
902 velDev_->exchange(f);
908 const int Nx = nx_, Ny = ny_, Nz = nz_;
909 const long sx = 1, sy = e.x, sz = (long)e.x * e.y;
911 Kokkos::parallel_for(
912 "peclet::flow::ibm_facefill", Kokkos::RangePolicy<CCExec>(space, 0, (
long)nx_ * ny_ * nz_),
913 KOKKOS_LAMBDA(
long n) {
914 const int ix = (int)(n % Nx), iy = (int)((n / Nx) % Ny), iz = (
int)(n / ((long)Nx * Ny));
915 const long i = (long)(ix +
G) * sx + (long)(iy +
G) * sy + (long)(iz +
G) * sz;
917 ff(i + (
long)Nx * sx) = ff(i);
918 else if (ix >= Nx -
G)
919 ff(i - (
long)Nx * sx) = ff(i);
921 ff(i + (
long)Ny * sy) = ff(i);
922 else if (iy >= Ny -
G)
923 ff(i - (
long)Ny * sy) = ff(i);
925 ff(i + (
long)Nz * sz) = ff(i);
926 else if (iz >= Nz -
G)
927 ff(i - (
long)Nz * sz) = ff(i);
933 int N3[3] = {nx_, ny_, nz_};
934 int dims[3] = {e.x, e.y, e.z};
935 long st[3] = {1, e.x, (long)e.x * e.y};
936 const int a = axis, b = (axis + 1) % 3, c = (axis + 2) % 3;
937 const long sa = st[a], sb = st[b], sc = st[c];
940 Kokkos::parallel_for(
941 "peclet::flow::ibm_pfill",
942 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<2>>(space, {0, 0}, {dims[b], dims[c]}),
943 KOKKOS_LAMBDA(
int p0,
int p1) {
944 const long base = (long)p0 * sb + (
long)p1 * sc;
945 for (
int gl = 0; gl <
G; ++gl) {
946 ff(base + (
long)gl * sa) = ff(base + (
long)(gl +
N) * sa);
947 ff(base + (
long)(
G +
N + gl) * sa) = ff(base + (
long)(
G + gl) * sa);
953 const double idiag = rho_ / dt_, fc = f_[c], rho = rho_;
955 CCField bb = C[c].b, rs = C[c].rscale, P = P_, brhs = bcBrhs_[c], inh = C[c].inhom;
958 const long strd = (c == 0) ? 1 : (c == 1) ? e_.
x : (long)e_.
x * e_.
y;
962 const bool pureFou =
implicitAdv() && !deferredCorr_;
963 const bool incr = cutcellPressure_ && incremental_, adv = advect_ && !pureFou,
972 const int sch = advScheme_;
977 const bool tg = Grid::collocated && faceInterp_ >= 2 && faceInterp_ <= 5 && incr;
979 const bool wg = Grid::collocated && (faceInterp_ == 6 || faceInterp_ == 7) && incr;
980 if constexpr (Grid::collocated) {
982 CCField xcs[3] = {xcx_, xcy_, xcz_};
983 CCField oax[3] = {ox_, oy_, oz_};
985 faceInterp_ >= 3, c, e_,
G);
987 CCField oax[3] = {ox_, oy_, oz_};
998 const bool wd = Grid::collocated && faceInterp_ >= 4;
999 if constexpr (Grid::collocated)
1005 if (faceInterp_ >= 5)
1013 const double fvw = fvRelax_;
1018 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
1019 Kokkos::parallel_for(
1020 "rhs", MD(space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1021 KOKKOS_LAMBDA(
int x,
int y,
int z) {
1022 const long i = (long)x + (
long)y * e.x + (long)z * (
long)e.x * e.y;
1023 double aK = 0.0, aF = 0.0;
1025 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};
1026 aK = (sch == 0) ? Grid::advect_sou(c, x, y, z, Ua, Va, Wa, Fa)
1027 : Grid::advect(c, x, y, z, Ua, Va, Wa, Fa);
1029 aF = Grid::advect_fou(c, x, y, z, Ua, Va, Wa, Fa);
1037 ? ((tg || wg) ? gpw(i) : 0.5 * (P((
long)i + strd) - P((
long)i - strd)))
1038 : (P(i) - P((
long)i - strd));
1042 const double bfv = idiag * cs(i) * un(i) + cs(i) * (fc - gp);
1043 bb(i) = fvM(i) - fvw * rs(i) * (fvL(i) - bfv);
1046 rs(i) * (idiag * un(i) + fc - rho * aK + rho * aF - gp) + (bc ? brhs(i) : -inh(i));
1056 const double idiag = rho_ / dt_, fc = f_[c], rho = rho_;
1058 CCField bb = C[c].b, rs = C[c].rscale, P = P_, brhs = bcBrhs_[c], inh = C[c].inhom;
1062 const long strd = (c == 0) ? 1 : (c == 1) ? e_.
x : (long)e_.
x * e_.
y;
1063 const bool pureFou =
implicitAdv() && !deferredCorr_;
1064 const bool incr = cutcellPressure_ && incremental_, adv = advect_ && !pureFou,
1067 const int sch = advScheme_;
1068 const bool tg = Grid::collocated && faceInterp_ >= 2 && incr;
1069 if constexpr (Grid::collocated)
1071 CCField xcs[3] = {xcx_, xcy_, xcz_};
1072 CCField oax[3] = {ox_, oy_, oz_};
1074 faceInterp_ >= 3, c, e_,
G);
1077 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
1078 Kokkos::parallel_for(
1079 "rhs_forced", MD(space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1080 KOKKOS_LAMBDA(
int x,
int y,
int z) {
1081 const long i = (long)x + (
long)y * e.x + (long)z * (
long)e.x * e.y;
1082 double aK = 0.0, aF = 0.0;
1084 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};
1085 aK = (sch == 0) ? Grid::advect_sou(c, x, y, z, Ua, Va, Wa, Fa)
1086 : Grid::advect(c, x, y, z, Ua, Va, Wa, Fa);
1088 aF = Grid::advect_fou(c, x, y, z, Ua, Va, Wa, Fa);
1090 const double gp = !incr ? 0.0
1092 ? (tg ? gpw(i) : 0.5 * (P((
long)i + strd) - P((
long)i - strd)))
1093 : (P(i) - P((
long)i - strd));
1094 bb(i) = rs(i) * (idiag * un(i) + fc + fb(i) - rho * aK + rho * aF - gp) +
1095 (bc ? brhs(i) : -inh(i));
1106 const double idt = 1.0 / dt_, fc = f_[c];
1108 CCField bb = C[c].b, rs = C[c].rscale, P = P_, brhs = bcBrhs_[c], inh = C[c].inhom;
1114 const bool pureFou =
implicitAdv() && !deferredCorr_;
1115 const bool incr = cutcellPressure_ && incremental_, adv = advect_ && !pureFou,
1118 const int sch = advScheme_;
1119 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
1120 Kokkos::parallel_for(
1121 "rhs_var", MD(space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1122 KOKKOS_LAMBDA(
int x,
int y,
int z) {
1123 const long i = (long)x + (
long)y * e.x + (long)z * (
long)e.x * e.y;
1124 const double rhoF = 0.5 * (rf(i) + rf(i - strd));
1125 double aK = 0.0, aF = 0.0;
1127 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};
1128 aK = (sch == 0) ? Grid::advect_sou(c, x, y, z, Ua, Va, Wa, Fa)
1129 : Grid::advect(c, x, y, z, Ua, Va, Wa, Fa);
1131 aF = Grid::advect_fou(c, x, y, z, Ua, Va, Wa, Fa);
1133 const double gp = !incr ? 0.0
1134 : Grid::collocated ? 0.5 * (P((
long)i + strd) - P((
long)i - strd))
1135 : (P(i) - P((
long)i - strd));
1136 const double fbF = 0.5 * (fb(i) + fb(i - strd));
1137 bb(i) = rs(i) * (rhoF * idt * un(i) + fc + fbF - rhoF * aK + rhoF * aF - gp) +
1138 (bc ? brhs(i) : -inh(i));
1146 const double idiag = rho_ / dt_, beta = mu_, fouw = rho_;
1148 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,
1151 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,
1154 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
1155 Kokkos::parallel_for(
1156 "advstencil", MD(space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1157 KOKKOS_LAMBDA(
int x,
int y,
int z) {
1158 const long i = (long)x + (
long)y * e.x + (long)z * (
long)e.x * e.y;
1159 double cC =
AC(i), cxm = AW(i), cxp = AE(i), cym = AS(i), cyp = AN(i), czm = AB(i),
1161 sadv::ViewAcc Ua{U, e.x, e.y}, Va{V, e.x, e.y}, Wa{W, e.x, e.y};
1162 Grid::fou_operator(c, x, y, z, Ua, Va, Wa, fouw, cC, cxm, cxp, cym, cyp, czm, czp);
1172 Kokkos::deep_copy(C[c].rscale, 1.0);
1173 Kokkos::deep_copy(C[c].inhom, 0.0);
1174 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,
1175 C[c].rscale, C[c].ov, C[c].nCut, 0.0f);
1193 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,
1196 const bool vr = varRho_;
1197 const double rhoC = rho_;
1200 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
1201 Kokkos::parallel_for(
1202 "advstencil_var", MD(space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1203 KOKKOS_LAMBDA(
int x,
int y,
int z) {
1204 const long i = (long)x + (
long)y * e.x + (long)z * (
long)e.x * e.y;
1205 double cC =
AC(i), cxm = AW(i), cxp = AE(i), cym = AS(i), cyp = AN(i), czm = AB(i),
1207 sadv::ViewAcc Ua{U, e.x, e.y}, Va{V, e.x, e.y}, Wa{W, e.x, e.y};
1208 const double fouw = vr ? 0.5 * (rf(i) + rf(i - sc)) : rhoC;
1209 Grid::fou_operator(c, x, y, z, Ua, Va, Wa, fouw, cC, cxm, cxp, cym, cyp, czm, czp);
1218 Kokkos::deep_copy(C[c].rscale, 1.0);
1219 Kokkos::deep_copy(C[c].inhom, 0.0);
1220 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,
1221 C[c].rscale, C[c].ov, C[c].nCut, 0.0f);
1235 if (backflowBeta_ <= 0.0 || !hasOutflow_)
1238 const double beta = backflowBeta_, rho = rho_;
1240 int dims[3] = {e.x, e.y, e.z};
1241 long st[3] = {1, e.x, (long)e.x * e.y};
1245 for (
int s = 0; s < 2; ++s) {
1246 if (bc_[2 * a + s] != 3)
1248 const long sa = st[a];
1249 const int na = dims[a];
1250 const int bic = (s == 0) ?
G : (na -
G - 1);
1251 const double sgn = (s == 0) ? 1.0 : -1.0;
1252 const int b = (a + 1) % 3, cc = (a + 2) % 3;
1253 const long sb = st[b], sc = st[cc];
1254 using MD2 = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<2>>;
1255 Kokkos::parallel_for(
1256 "peclet::flow::backflow", MD2(space, {
G,
G}, {dims[b] -
G, dims[cc] -
G}),
1257 KOKKOS_LAMBDA(
int p0,
int p1) {
1258 const long i = (long)p0 * sb + (
long)p1 * sc + (long)bic * sa;
1262 AC(i) += (float)(beta * rho * back);
1271 Kokkos::parallel_reduce(
1273 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(space, {
G,
G,
G},
1274 {e.x -
G, e.y -
G, e.z -
G}),
1275 KOKKOS_LAMBDA(
int x,
int y,
int z,
double& acc) {
1276 const long i = (long)x + (
long)y * e.x + (long)z * (
long)e.x * e.y;
1277 const double d = Kokkos::fabs(a(i) - b(i));
1281 Kokkos::Max<double>(m));
1285 if constexpr (Grid::collocated) {
1290 for (
int it = 0; it < velIters_; ++it) {
1310 for (
int it = 0; it < velIters_; ++it) {
1333 vmg_.
solve(
CCConst(C[c].b), C[c].u, vmgVcycles_, 2, 2, 8);
1337 const I3 e{e_.
x, e_.
y, e_.
z}, og{0, 0, 0};
1338 const double beta = mu_, Ac = rho_ / dt_ + 6.0 * mu_;
1339 for (
int it = 0; it < velIters_; ++it) {
1347 if (useVelocityMg_) {
1350 FPC(C[c].AB),
FPC(C[c].AT));
1351 if (implicitFou_ && advect_) {
1366 vmg_.
solve(
CCConst(C[c].b), C[c].u, vmgVcycles_, 2, 2, 8);
1371 for (
int it = 0; it < velIters_;
1392 int dims[3] = {e.x, e.y, e.z};
1393 long st[3] = {1, e.x, (long)e.x * e.y};
1394 for (
int a = 0; a < 3; ++a)
1395 for (
int s = 0; s < 2; ++s) {
1396 if (bc_[2 * a + s] == 0)
1398 const int b = (a + 1) % 3, c = (a + 2) % 3;
1399 const long sa = st[a], sb = st[b], sc = st[c];
1400 const int na = dims[a];
1401 const int bic = (s == 0) ?
G : (na -
G - 1);
1402 const int lo = (s == 0) ? 0 : (na -
G), hi = (s == 0) ? (
G - 1) : (na - 1);
1403 Kokkos::parallel_for(
1405 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<2>>(space, {0, 0}, {dims[b], dims[c]}),
1406 KOKKOS_LAMBDA(
int p0,
int p1) {
1407 const long base = (long)p0 * sb + (
long)p1 * sc;
1408 const double pin = P(base + (
long)bic * sa);
1409 for (
int ia = lo; ia <= hi; ++ia)
1410 P(base + (
long)ia * sa) = pin;
1423#ifdef PECLET_FLOW_MPI
1425 velDev_->exchange(f);
1430 for (
int a = 0; a < 3; ++a)
1431 if (bc_[2 * a] == 0 && bc_[2 * a + 1] == 0)
1438 B3 e{e_.
x, e_.
y, e_.
z};
1439 if constexpr (Grid::collocated) {
1444 for (
int a = 0; a < 3; ++a)
1445 for (
int s = 0; s < 2; ++s) {
1446 const int ff = 2 * a + s;
1447 const int t = bc_[ff];
1455 if (bcProf_[ff].extent(0) >
1464 for (
int a = 0; a < 3; ++a)
1465 for (
int s = 0; s < 2; ++s) {
1466 const int ff = 2 * a + s;
1467 const int t = bc_[ff];
1475 if (bcProf_[ff].extent(0) > 0)
1476 bcVelocityComp(f, e,
G, a, s, comp, 0.0, fold, bcProf_[ff], bcProfNc_[ff]);
1485 const double beta = mu_;
1486 B3 e{e_.
x, e_.
y, e_.
z};
1487 for (
int c = 0; c < 3; ++c) {
1488 Kokkos::deep_copy(bcDcorr_[c], 0.0);
1489 Kokkos::deep_copy(bcBrhs_[c], 0.0);
1490 for (
int a = 0; a < 3; ++a)
1491 for (
int s = 0; s < 2; ++s) {
1492 const int t = bc_[2 * a + s];
1497 }
else if (t != 0 && c != a) {
1499 bval = 2.0 * beta * bcVel_[2 * a + s][c];
1515 if constexpr (Grid::collocated) {
1520 for (
int c = 0; c < 3; ++c)
1522 if ((faceInterp_ >= 1 && faceInterp_ <= 5) ||
1526 faceInterp_ >= 3, e_,
G);
1532 for (
int c = 0; c < 3; ++c)
1549 CCField d = div_, dd = depsdt_, ep = epsField_, epp = epsPrev_;
1550 const double idt = 1.0 / dt_;
1551 const bool useDt = porousDepsDt_;
1552 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
1553 Kokkos::parallel_for(
1554 "peclet::flow::deps_dt", MD(space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
1555 KOKKOS_LAMBDA(
int x,
int y,
int z) {
1556 const long i = (long)x + (
long)y * e.x + (long)z * e.x * e.y;
1557 dd(i) = (ep(i) - epp(i)) * idt;
1568 Kokkos::parallel_for(
1569 "negdiv", Kokkos::RangePolicy<CCExec>(space, 0, n1_),
1570 KOKKOS_LAMBDA(std::size_t i) { r(i) = -r(i); });
1587 chebBoundsSet_ =
false;
1609 chebBoundsSet_ =
false;
1616 Kokkos::deep_copy(phi1_, 0.0);
1617 if (useChebyshev_) {
1618 if (!chebBoundsSet_) {
1620 chebBoundsSet_ =
true;
1622 lastPressureIters_ =
1623 mg_.
solveChebyshev(rhs1_, phi1_, chebMaxit_, chebRtol_, 2, 2, 12, chebA_, chebB_);
1625 lastPressureIters_ =
1626 mg_.
solvePCG(rhs1_, phi1_, r_, pp_, z_, Ap_, pcgMaxit_, pcgRtol_, 2, 2, 12);
1632 B3 e{e_.
x, e_.
y, e_.
z};
1633 for (
int a = 0; a < 3; ++a)
1634 for (
int s = 0; s < 2; ++s)
1635 if (bc_[2 * a + s] == 3)
1638 if constexpr (Grid::collocated) {
1644 B3 e{e_.
x, e_.
y, e_.
z};
1645 for (
int a = 0; a < 3; ++a)
1646 for (
int s = 0; s < 2; ++s) {
1647 const int t = bc_[2 * a + s];
1648 if (t != 0 && t != 3)
1660 B3 e{e_.
x, e_.
y, e_.
z};
1661 CCField fa[3] = {uf_, vf_, wf_};
1662 for (
int a = 0; a < 3; ++a)
1663 if (bc_[2 * a + 1] == 3)
1666 if (faceInterp_ >= 2 &&
1669 CCField xcs[3] = {xcx_, xcy_, xcz_};
1670 CCField oax[3] = {ox_, oy_, oz_};
1671 for (
int cc = 0; cc < 3; ++cc) {
1673 CCConst(xcs[cc]), faceInterp_ >= 3, cc, e_,
G);
1676 }
else if (faceInterp_ == 6 ||
1696 B3 e{e_.
x, e_.
y, e_.
z};
1697 for (
int a = 0; a < 3; ++a)
1698 if (bc_[2 * a + 1] == 3)
1705 for (
int c = 0; c < 3; ++c)
1712 CCField P = P_, ph = phi_, d = div_;
1718 const double ct = pressUnderRelax_ * rho_ / dt_, mu = mu_;
1724 if (varRotMode_ == 1) {
1726 const double chi = varRotChi_;
1727 Kokkos::parallel_for(
1728 "press_var_full", Kokkos::RangePolicy<CCExec>(space, 0, n_),
1729 KOKKOS_LAMBDA(std::size_t i) { P(i) += ct * ph(i) - chi * mf(i) * d(i); });
1731 const double muRot = (varRotMode_ == 2) ? 0.0 : varRotChi_ *
minMuInner();
1732 Kokkos::parallel_for(
1733 "press_var_min", Kokkos::RangePolicy<CCExec>(space, 0, n_),
1734 KOKKOS_LAMBDA(std::size_t i) { P(i) += ct * ph(i) - muRot * d(i); });
1737 Kokkos::parallel_for(
1738 "press", Kokkos::RangePolicy<CCExec>(space, 0, n_),
1739 KOKKOS_LAMBDA(std::size_t i) { P(i) += ct * ph(i) - mu * d(i); });
1744 Kokkos::deep_copy(epsPrev_, epsField_);
1748 CCField u = C[c].u, m = C[c].mask;
1749 Kokkos::parallel_for(
1750 "vmask", Kokkos::RangePolicy<CCExec>(space, 0, n_), KOKKOS_LAMBDA(std::size_t i) {
1762 Kokkos::parallel_reduce(
1764 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(space, {
G,
G,
G},
1765 {e.x -
G, e.y -
G, e.z -
G}),
1766 KOKKOS_LAMBDA(
int x,
int y,
int z,
double& acc) {
1767 const long i = (long)x + (
long)y * e.x + (long)z * (
long)e.x * e.y;
1771 Kokkos::Min<double>(m));
1772#ifdef PECLET_FLOW_MPI
1775 MPI_Allreduce(&m, &g, 1, MPI_DOUBLE, MPI_MIN, comm_);
1785 Kokkos::parallel_reduce(
1787 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<3>>(space, {
G,
G,
G},
1788 {e.x -
G, e.y -
G, e.z -
G}),
1789 KOKKOS_LAMBDA(
int x,
int y,
int z,
double& acc) {
1790 const long i = (long)x + (
long)y * e.x + (long)z * (
long)e.x * e.y;
1791 const double a = Kokkos::fabs(f(i));
1795 Kokkos::Max<double>(m));
1799 auto h = Kokkos::create_mirror_view(fld);
1800 Kokkos::deep_copy(h, fld);
1801 std::vector<double> out((std::size_t)nx_ * ny_ * nz_);
1802 for (
int z = 0; z < nz_; ++z)
1803 for (
int y = 0; y < ny_; ++y)
1804 for (
int x = 0; x < nx_; ++x)
1805 out[(std::size_t)x + (std::size_t)y * nx_ + (std::size_t)z * (std::size_t)nx_ * ny_] =
1806 h((
long)(x +
G) + (
long)(y +
G) * e_.
x + (
long)(z +
G) * (
long)e_.
x * e_.
y);
1812 if (in.size() != (std::size_t)nx_ * ny_ * nz_)
1813 throw std::runtime_error(
"flow::setField: array size does not match the inner grid");
1814 auto h = Kokkos::create_mirror_view(fld);
1815 Kokkos::deep_copy(h, fld);
1816 for (
int z = 0; z < nz_; ++z)
1817 for (
int y = 0; y < ny_; ++y)
1818 for (
int x = 0; x < nx_; ++x)
1819 h((
long)(x +
G) + (
long)(y +
G) * e_.
x + (
long)(z +
G) * (
long)e_.
x * e_.
y) =
1820 in[(std::size_t)x + (std::size_t)y * nx_ + (std::size_t)z * (std::size_t)nx_ * ny_];
1821 Kokkos::deep_copy(fld, h);
1828 if (fields_.has(name))
1829 return fields_.at(name).data;
1830 return fields_.add(name, n_,
G, peclet::core::Centering::Cell).data;
1832 bool hasField(
const std::string& name)
const {
return fields_.has(name); }
1834 std::vector<std::string>
fieldNames()
const {
return fields_.names(); }
1843#ifdef PECLET_FLOW_MPI
1844 if (distributed_ && velHalo_) {
1845 CCField f = fields_.at(name).data;
1846 auto h = Kokkos::create_mirror_view(f);
1847 Kokkos::deep_copy(h, f);
1848 peclet::core::halo::GridFieldView<double> view{h.data()};
1849 velHalo_->reverseAdd(view);
1850 Kokkos::deep_copy(f, h);
1858 std::vector<double>
getField(
const std::string& name) {
1861 void setField(
const std::string& name,
const std::vector<double>& v) {
1870#ifdef PECLET_FLOW_MPI
1872 return {gnx_, gny_, gnz_};
1874 return {nx_, ny_, nz_};
1885 void addScalar(
const std::string& name,
double D,
int scheme,
int iters) {
1900 sc.
iters = iters < 1 ? 1 : iters;
1901 scalars_.push_back(sc);
1904 for (
const auto& sc : scalars_)
1905 if (sc.name == name)
1911 void setScalarBc(
const std::string& name,
int face,
int type,
double value) {
1912 for (
auto& sc : scalars_)
1913 if (sc.name == name) {
1915 sc.bcVal[face] = value;
1918 throw std::runtime_error(
"set_scalar_bc: no scalar named '" + name +
"'");
1924 if (scalars_.empty())
1926 const double idt = 1.0 / dt_;
1928 if constexpr (Grid::collocated) {
1940 for (
auto& sc : scalars_) {
1943 applyScalarBcStencil(sc);
1944 Kokkos::deep_copy(sc.cOld, sc.c);
1945 scalarFillGhosts(sc);
1949 for (
int it = 0; it < sc.iters; ++it) {
1950 scalarFillGhosts(sc);
1951 cutcellSmoothColor(sc.c,
CCConst(sc.b), sc.AC, sc.AW, sc.AE, sc.AS, sc.AN, sc.AB, sc.AT, e_,
1953 scalarFillGhosts(sc);
1954 cutcellSmoothColor(sc.c,
CCConst(sc.b), sc.AC, sc.AW, sc.AE, sc.AS, sc.AN, sc.AB, sc.AT, e_,
1957 scalarFillGhosts(sc);
1968 const std::string& in1,
const std::vector<double>& params) {
1971 cl.
out = ensureTarget(target);
1975 for (
int k = 0; k < 4 && k < (int)params.size(); ++k)
1976 cl.
p[k] = params[k];
1977 closures_.push_back(cl);
1980 if (target ==
"rho")
1992 if constexpr (Grid::collocated) {
1994 throw std::runtime_error(
"set_density_mode: variable density is staggered-only (v1)");
1998 if (fields_.has(
"rho"))
1999 rhoField_ = fields_.at(
"rho").data;
2002 Kokkos::deep_copy(rhoField_, rho_);
2004 if (rho1_.extent(0) == 0) {
2010 ensureCellForceAll();
2011 useVelocityMg_ =
false;
2019 useChebyshev_ =
true;
2020 chebBoundsSet_ =
false;
2029 if constexpr (Grid::collocated) {
2031 throw std::runtime_error(
"set_porous_continuity: staggered-only (v1)");
2035 if (fields_.has(
"eps"))
2036 epsField_ = fields_.at(
"eps").data;
2039 Kokkos::deep_copy(epsField_, 1.0);
2041 if (epsPrev_.extent(0) == 0) {
2042 epsPrev_ =
CCField(
"epsPrev", n_);
2043 depsdt_ =
CCField(
"depsdt", n_);
2045 Kokkos::deep_copy(epsPrev_, epsField_);
2046 if (eps1_.extent(0) == 0)
2048 if (beta1_.extent(0) == 0)
2049 beta1_ =
CCField(
"beta1", n1_);
2050 if (rho1_.extent(0) == 0) {
2060 useChebyshev_ =
true;
2061 chebBoundsSet_ =
false;
2071 Kokkos::deep_copy(epsPrev_, epsField_);
2084 varProps_ = variable;
2085 harmonicMu_ = harmonic;
2087 if (fields_.has(
"mu"))
2088 muField_ = fields_.at(
"mu").data;
2091 Kokkos::deep_copy(muField_,
2117 varRotMode_ = mode < 0 ? 0 : (mode > 2 ? 2 : mode);
2118 varRotChi_ = chi < 0.0 ? 0.0 : chi;
2123 const std::vector<double>& xs,
const std::vector<double>& ys) {
2126 cl.
out = ensureTarget(target);
2128 cl.
nTab = (int)std::min(xs.size(), ys.size());
2131 auto hx = Kokkos::create_mirror_view(cl.
tabX);
2132 auto hy = Kokkos::create_mirror_view(cl.
tabY);
2133 for (
int k = 0; k < cl.
nTab; ++k) {
2137 Kokkos::deep_copy(cl.
tabX, hx);
2138 Kokkos::deep_copy(cl.
tabY, hy);
2139 closures_.push_back(cl);
2143 for (
auto& cl : closures_)
2157 if (!fields_.has(
"drag_beta"))
2160 dragBeta_ = fields_.at(
"drag_beta").data;
2161 ensureCellForceAll();
2170 if (!(porous_ && hasDrag_))
2172 pressGraphAmg_ =
true;
2175 if (cutcellPressure_)
2177 useChebyshev_ =
false;
2178 chebBoundsSet_ =
false;
2198 const bool faceAvg = porous_;
2199 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
2200 Kokkos::parallel_for(
2201 "peclet::flow::add_drag_diag", MD(space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
2202 KOKKOS_LAMBDA(
int x,
int y,
int z) {
2203 const long i = (long)x + (
long)y * e.x + (long)z * (
long)e.x * e.y;
2205 faceAvg ? 0.5 * ((double)beta(i) + (double)beta(i - sc)) : (double)beta(i);
2206 AC(i) = (float)((
double)
AC(i) + bd);
2213 CCField ensureTarget(
const std::string& name) {
2214 if (name ==
"force_x" || name ==
"force_y" || name ==
"force_z")
2215 ensureCellForceAll();
2218 void ensureCellForceAll() {
2219 static const char* fn[3] = {
"force_x",
"force_y",
"force_z"};
2220 for (
int c = 0; c < 3; ++c)
2222 hasCellForce_ =
true;
2226 void scalarFillGhosts(ScalarField& sc) {
2232 void applyScalarBc(ScalarField& sc) {
2234 for (
int f = 0;
f < 6; ++
f)
2235 any = any || (sc.bc[f] != 0);
2236 if (!any || distributed_)
2238 for (
int f = 0;
f < 6; ++
f)
2246 void applyScalarBcStencil(ScalarField& sc) {
2249 for (
int f = 0;
f < 6; ++
f) {
2252 const int a =
f / 2, side =
f % 2;
2253 CCField band = (a == 0) ? (side == 0 ? sc.AW : sc.AE)
2254 : (a == 1) ? (side == 0 ? sc.AS : sc.AN)
2255 : (side == 0 ? sc.AB : sc.AT);
2263 const int t1 = (a + 1) % 3, t2 = (a + 2) % 3;
2264 const int nt1 = (t1 == 0) ? nx_ : (t1 == 1) ? ny_ : nz_;
2265 const int nt2 = (t2 == 0) ? nx_ : (t2 == 1) ? ny_ : nz_;
2266 const int na = (a == 0) ? nx_ : (a == 1) ? ny_ : nz_;
2267 const long sx = 1, sy = e_.
x, sz = (long)e_.
x * e_.
y;
2268 const long sa = (a == 0) ? sx : (a == 1) ? sy : sz;
2269 const long st1 = (t1 == 0) ? sx : (t1 == 1) ? sy : sz;
2270 const long st2 = (t2 == 0) ? sx : (t2 == 1) ? sy : sz;
2271 const int aInner = (side == 0) ?
G : (
G + na - 1);
2273 Kokkos::parallel_for(
2274 "peclet::flow::scalar_bc_stencil",
2275 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<2>>(space, {
G,
G}, {
G + nt1,
G + nt2}),
2276 KOKKOS_LAMBDA(
int j1,
int j2) {
2277 const long i = (long)aInner * sa + (
long)j1 * st1 + (long)j2 * st2;
2280 AC(i) += D + band(i);
2285 const int t1 = (a + 1) % 3, t2 = (a + 2) % 3;
2286 const int nt1 = (t1 == 0) ? nx_ : (t1 == 1) ? ny_ : nz_;
2287 const int nt2 = (t2 == 0) ? nx_ : (t2 == 1) ? ny_ : nz_;
2288 const int na = (a == 0) ? nx_ : (a == 1) ? ny_ : nz_;
2289 const long sx = 1, sy = e_.
x, sz = (long)e_.
x * e_.
y;
2290 const long sa = (a == 0) ? sx : (a == 1) ? sy : sz;
2291 const long st1 = (t1 == 0) ? sx : (t1 == 1) ? sy : sz;
2292 const long st2 = (t2 == 0) ? sx : (t2 == 1) ? sy : sz;
2293 const int aInner = (side == 0) ?
G : (
G + na - 1);
2294 const int dir = (side == 0) ? -1 : +1;
2296 Kokkos::parallel_for(
2297 "peclet::flow::scalar_bc_face",
2298 Kokkos::MDRangePolicy<
CCExec, Kokkos::Rank<2>>(space, {
G,
G}, {
G + nt1,
G + nt2}),
2299 KOKKOS_LAMBDA(
int j1,
int j2) {
2300 const long base = (long)aInner * sa + (
long)j1 * st1 + (long)j2 * st2;
2301 for (
int L = 1; L <= 2; ++L) {
2302 const long gcell = base + (long)dir * L * sa;
2303 const long icell = base - (long)dir * (L - 1) * sa;
2304 c(gcell) = (type == 2) ? (2.0 * val - c(icell)) : c(icell);
2312 std::size_t n_, n1_;
2313 double rho_ = 1.0, mu_ = 0.1, dt_ = 50.0;
2314 std::array<double, 3> f_{{0, 0, 0}};
2315 int velIters_ = 200, presIters_ = 20;
2316 int pcgMaxit_ = 500;
2317 double pcgRtol_ = 1e-10;
2318 bool useChebyshev_ =
false,
2319 chebBoundsSet_ =
false;
2320 int chebMaxit_ = 120;
2321 double chebRtol_ = 1e-9, chebA_ = 0.0, chebB_ = 0.0;
2323 bool pressGraphAmg_ =
false;
2324 long lastPressureIters_ = 0;
2328 bool distributed_ =
false;
2330#ifdef PECLET_FLOW_MPI
2331 std::shared_ptr<GridHaloTopology<3>> velHalo_;
2332 std::shared_ptr<GridHalo<double>> velDev_;
2333 std::shared_ptr<peclet::core::decomp::BlockDecomposer<3>>
2335 MPI_Comm comm_ = MPI_COMM_NULL;
2336 int gnx_ = 0, gny_ = 0, gnz_ = 0;
2338 int bc_[6] = {0, 0, 0, 0, 0, 0};
2339 double bcVel_[6][3] = {};
2340 bool hasBc_ =
false, hasOutflow_ =
false;
2344 double backflowBeta_ =
2348 int bcProfNc_[6] = {0, 0, 0, 0, 0, 0};
2349 CCField bcDcorr_[3], bcBrhs_[3];
2350 bool advect_ =
false, cutcellPressure_ =
false, implicitFou_ =
false;
2351 bool deferredCorr_ =
true;
2353 bool incremental_ =
true,
2355 int faceInterp_ = 0;
2356 double fvRelax_ = 1.0;
2357 bool useVelocityMg_ =
false;
2358 int vmgLevels_ = 4, vmgVcycles_ = 8;
2361 int outerIters_ = 1;
2362 double outerTol_ = 0.0;
2363 long lastOuterIters_ = 0;
2364 double lastOuterCorr_ = 0.0;
2365 CCField sdf_, ox_, oy_, oz_, phi_, div_, P_, ox1_, oy1_, oz1_, rhs1_, phi1_, r_, z_, pp_, Ap_;
2373 peclet::core::FieldSet fields_;
2374 std::vector<ScalarField> scalars_;
2375 std::vector<Closure> closures_;
2377 bool hasCellForce_ =
false;
2378 bool varProps_ =
false;
2379 bool harmonicMu_ =
false;
2381 int varRotMode_ = 0;
2382 double varRotChi_ = 1.0;
2383 bool varRho_ =
false;
2385 CCField rho1_, cx1_, cy1_, cz1_;
2386 bool porous_ =
false;
2387 double pressUnderRelax_ = 1.0;
2388 bool porousDepsDt_ =
true;
2392 CCField epsField_, epsPrev_, eps1_, depsdt_;
2394 bool hasDrag_ =
false;
int solveChebyshev(CCField b, CCField x, int maxit, double rtol, int pre, int post, int bottom, double a, double bnd)
void setGraphAmgBottom(bool on)
void setOpenness(CCConst ox, CCConst oy, CCConst oz, double idx2, double idy2, double idz2)
int solvePCG(CCField b, CCField x, CCField r, CCField p, CCField z, CCField Ap, int maxit, double rtol, int pre, int post, int bottom)
void setBoundaryConditions(const int bc[6])
void init(int nx, int ny, int nz, int nLevels)
void estimateEigenvalues(CCConst seed, double &lmin, double &lmax, int iters, int pre, int post, int bottom)
std::vector< double > getFaceVelocity(int c)
std::array< int, 3 > globalResolution() const
void fillVelGhosts(int comp, int fold)
void setIncrementalPressure(bool on)
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)
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)
void applyVelocityBcComp(int comp, int fold, bool doOutflow)
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 patchScalarDirichletFace(CCField AC, CCField band, double D, int a, int side)
void setVariableRotational(int mode, double chi)
void setPressureUnderRelax(double w)
void setPressureLevels(int levels)
std::array< int, 3 > blockOrigin() const
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 setBodyForce(double fx, double fy, double fz)
void applyScalarBcFace(CCField c, int a, int side, int type, double val)
std::vector< double > getVelocity(int c)
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 setDensityMode(bool variable)
bool hasScalar(const std::string &name) const
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 addScalar(const std::string &name, double D, int scheme, int iters)
void buildAdvStencilVar(int c)
bool bcStencilPath() const
void setImplicitAdvection(bool on)
VarFaceProps makeFaceProps(int c)
double reduceMaxAbsInner(CCConst f)
void setPorousContinuity(bool on)
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)
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 — 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 buildOpenness(CCField ox, CCField oy, CCField oz, CCConst sdf, C3 ext, double dx, double dy, double dz)
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 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 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)
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)
void diffSmoothColor(SField c, SConst b, I3 e, I3 og, int g, double beta, double Ac, int color, SConst dcorr)
void bcDiffusionFold(BField dcorr, BField brhs, B3 ext, int g, int a, int s, double dval, double bval)
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)
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 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)
void bcCorrectOutflow(BField f, BField phi, B3 ext, int g, int a)
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 centerToFace(CCField uf, CCField vf, CCField wf, CCConst U, CCConst V, CCConst W, C3 e, int g)
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)
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)
Kokkos::View< const float *, CCMem > MConst
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)
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).
std::array< double, 4 > p
static constexpr double AC
Kokkos::View< float *, IMem > FV