20#ifndef PECLET_CORE_AMR_FLOW_HPP
21#define PECLET_CORE_AMR_FLOW_HPP
23#ifdef PECLET_CORE_HAVE_MORTON
60 const char*
v = std::getenv(
name);
61 return v &&
v[0] && !(
v[0] ==
'0' &&
v[1] ==
'\0');
68template <
int Dim,
unsigned Bits,
class Flu
idFn>
71 std::vector<Index> start(
static_cast<std::size_t
>(n) + 1, 0);
75 start[
static_cast<std::size_t
>(
i) + 1] = start[
static_cast<std::size_t
>(
i)] +
cnt;
77 const Index nf = start[
static_cast<std::size_t
>(n)];
78 std::vector<Index> nbr(
static_cast<std::size_t
>(
nf));
79 std::vector<int> axis(
static_cast<std::size_t
>(
nf)), dir(
static_cast<std::size_t
>(
nf));
80 std::vector<double>
aArea(
static_cast<std::size_t
>(
nf)),
rArea(
static_cast<std::size_t
>(
nf)),
81 dist(
static_cast<std::size_t
>(
nf)), alpha(
static_cast<std::size_t
>(
nf));
82 std::vector<Index> upupI(
static_cast<std::size_t
>(
nf)), upupJ(
static_cast<std::size_t
>(
nf));
83 std::vector<double> invVol(
static_cast<std::size_t
>(n));
84 std::vector<char> fluid(
static_cast<std::size_t
>(n));
86 invVol[
static_cast<std::size_t
>(
i)] = 1.0 / ap.
cellVolume(
i);
87 fluid[
static_cast<std::size_t
>(
i)] = isFluid(
i) ? 1 : 0;
88 Index k = start[
static_cast<std::size_t
>(
i)];
90 nbr[
static_cast<std::size_t
>(k)] =
j;
91 axis[
static_cast<std::size_t
>(k)] =
ax;
92 dir[
static_cast<std::size_t
>(k)] =
dr;
94 rArea[
static_cast<std::size_t
>(k)] =
area;
95 dist[
static_cast<std::size_t
>(k)] = d;
96 alpha[
static_cast<std::size_t
>(k)] =
al;
133 Kokkos::parallel_for(
142 const double ui = (
a == 0) ?
u0(
i) : (
a == 1) ?
u1(
i) :
u2(
i);
144 const double uj = (
a == 0) ?
u0(
j) : (
a == 1) ?
u1(
j) :
u2(
j);
145 d +=
aA(k) *
dr(k) * 0.5 * (
ui +
uj);
164 Kokkos::parallel_for(
169 const double ui = (
a == 0) ?
u0(
i) : (
a == 1) ?
u1(
i) :
u2(
i);
170 const double uj = (
a == 0) ?
u0(
j) : (
a == 1) ?
u1(
j) :
u2(
j);
171 const double gphi = (
dr(k) > 0) ? (phi(
j) - phi(
i)) /
di(k) : (phi(
i) - phi(
j)) /
di(k);
186 Kokkos::parallel_reduce(
187 "amr::flow_divface", g.
n,
193 d +=
aA(k) *
dr(k) *
uf(k);
213 Kokkos::parallel_for(
219 const double fi =
f(
i);
220 double gp[3] = {0, 0, 0},
gm[3] = {0, 0, 0};
221 int np[3] = {0, 0, 0},
nm[3] = {0, 0, 0};
236 for (
int a = 0;
a < 3; ++
a) {
268 Kokkos::parallel_for(
272 for (
int a = 0;
a < 3; ++
a) {
274 for (
int k = 0; k < 3; ++k)
275 acc += w(
s * 9 +
a * 3 + k) *
f(idx(
s * 9 +
a * 3 + k));
291 Kokkos::parallel_for(
293 b(
i) = fluid(
i) ? (idiag *
uc(
i) +
fc - gradP(
i) -
adv(
i)) * rscale(
i) : 0.0;
316 Kokkos::parallel_for(
324 const double rs = rscale(
i);
333 const double ui = (
a == 0) ?
u0(
i) : (
a == 1) ?
u1(
i) :
u2(
i);
334 const double uj = (
a == 0) ?
u0(
j) : (
a == 1) ?
u1(
j) :
u2(
j);
367 Kokkos::parallel_for(
373 auto fld = [&](
Index c) {
return (comp == 0) ?
u0(
c) : (comp == 1) ?
u1(
c) :
u2(
c); };
374 double sou = 0.0,
fou = 0.0;
411 Kokkos::parallel_for(
417 auto fld = [&](
Index c) {
return (comp == 0) ?
u0(
c) : (comp == 1) ?
u1(
c) :
u2(
c); };
442 Kokkos::parallel_for(
452 Kokkos::parallel_for(
462template <
unsigned Bits = 21u>
535 ghostProjReq_ =
on ? 1 : 0;
615 outerIters_ = (n < 1) ? 1 : n;
621 template <
class SdfFn>
625 throw std::runtime_error(
626 "amr::AmrFlow: the C/F quadratic scheme is not distributed yet (rung-4 follow-up)");
628 mom_.init(*t_, h0_, origin_);
629 pres_.
init(*t_, h0_);
638 const bool wantGhost = (ghostProjReq_ != 0);
648 momSolver_.setDistributed({}, {}, 0);
649 pcg_.setDistributed({}, {}, 0);
650 mom_.build(
sdfFn, rho_ / dt_, mu_ / (h0_ * h0_));
664 if (ghostProjReq_ == 1)
665 throw std::runtime_error(
666 "amr ghost projection: an overlay row's ±2 closure reach crosses a 2:1 level "
667 "boundary — widen the refineToSdf band margin");
670 "peclet::core AmrFlow: AUTO scheme fell back to the aperture projection (the "
671 "finest band is too thin for the ghost overlay). Select explicitly with "
672 "setGhostProjection to silence this notice.\n");
681 presMGD_.build(*dist_, h0_,
binFn, &dhalo_);
683 presMG_.build(*t_, h0_,
binFn,
true);
690 gpPocket_ = dist_ ? std::vector<char>{} :
findPocketCells(*t_, pres_, mom_.sdfCRaw());
696 presMGD_.build(*dist_, h0_,
openFn, &dhalo_);
698 presMG_.build(*t_, h0_,
openFn,
true);
702 presMGD_.setRemoveMean(
true);
703 pcg_.setDistributed([
this](
View<double> v) { presMGD_.sync(0,
v); }, allred_,
704 presMGD_.extendedSize(0));
706 presMG_.setRemoveMean(
true);
722 auto A = mom_.assembleOperator();
748 if (momMGon_ && dist_ && !useStaircaseMG_) {
749 auto A = mom_.assembleOperator();
750 std::vector<Index>
lstart(1, 0);
751 std::vector<Index>
lnbr;
752 std::vector<double>
lcoef;
754 for (
Index k = A.start[
static_cast<std::size_t
>(
i)];
755 k < A.start[
static_cast<std::size_t
>(
i) + 1]; ++k)
756 if (A.nbr[
static_cast<std::size_t
>(k)] < n) {
757 lnbr.push_back(A.nbr[
static_cast<std::size_t
>(k)]);
758 lcoef.push_back(A.coef[
static_cast<std::size_t
>(k)]);
763 momMG_.setGaussSeidel(momGS_);
764 }
else if (momMGon_ && !dist_) {
765 if (useStaircaseMG_) {
766 std::vector<double>
kap(
static_cast<std::size_t
>(n));
767 std::vector<char>
fl(
static_cast<std::size_t
>(n)),
cu(
static_cast<std::size_t
>(n));
769 kap[
static_cast<std::size_t
>(
i)] = mom_.kappa(
i);
770 fl[
static_cast<std::size_t
>(
i)] = mom_.isFluid(
i) ? 1 : 0;
771 cu[
static_cast<std::size_t
>(
i)] = mom_.isCut(
i) ? 1 : 0;
773 velMG_.build(*t_, h0_, rho_ / dt_, mu_, momOp_,
kap,
fl,
cu, mgMinCoarse_);
774 velMG_.setGaussSeidel(momGS_);
778 auto A = mom_.assembleOperator();
779 momMG_.build(*t_, A.diag, A.start, A.nbr, A.coef);
780 momMG_.setGaussSeidel(momGS_);
783 std::vector<char>
fluidVec(
static_cast<std::size_t
>(n));
785 fluidVec[
static_cast<std::size_t
>(
i)] = mom_.isFluid(
i) ? 1 : 0;
795 std::vector<double>
rs(
static_cast<std::size_t
>(n));
797 rs[
static_cast<std::size_t
>(
i)] = mom_.rhsScale(
i);
799 fluid_ = geom_.
fluid;
801 buildGhostGradOverlay();
816 for (
int a = 0;
a < 3; ++
a)
817 cfGrad_[
static_cast<std::size_t
>(
a)] =
825 for (
int a = 0;
a < 3; ++
a)
826 cfGrad_[
static_cast<std::size_t
>(
a)] =
CfCsrDev{};
834 std::vector<double>
mc(
static_cast<std::size_t
>(n), 0.0);
836 mc[
static_cast<std::size_t
>(
i)] =
837 (mom_.isFluid(
i) && !(!gpPocket_.empty() && gpPocket_[
static_cast<std::size_t
>(
i)]))
841 if (!
hov.coupled[
static_cast<std::size_t
>(
r)])
842 mc[
static_cast<std::size_t
>(
hov.cell[
static_cast<std::size_t
>(
r)])] = 0.0;
845 auto mk = [&](
const char*
l) {
return View<double>(
l,
static_cast<std::size_t
>(nExt_)); };
847 gprh_ =
mk(
"gp_rhat");
849 gpph_ =
mk(
"gp_phat");
852 gpsh_ =
mk(
"gp_shat");
860 for (
int c = 0;
c < 3; ++
c) {
861 u_[
c] =
View<double>(
"df_u",
static_cast<std::size_t
>(nExt_));
863 Kokkos::deep_copy(u_[
c], 0.0);
865 p_ =
View<double>(
"df_p",
static_cast<std::size_t
>(nExt_));
866 phi_ =
View<double>(
"df_phi",
static_cast<std::size_t
>(nExt_));
867 div_ =
View<double>(
"df_div",
static_cast<std::size_t
>(nExt_));
869 geom_.
nbr.extent(0));
870 faceFieldBuilt_ =
false;
871 bmom_ =
View<double>(
"df_bmom",
static_cast<std::size_t
>(n));
872 Kokkos::deep_copy(p_, 0.0);
878 for (
int c = 0;
c < 3; ++
c) {
879 defc_[
c] =
View<double>(
"df_defc",
static_cast<std::size_t
>(n));
880 Kokkos::deep_copy(defc_[
c], 0.0);
883 u0_[
c] =
View<double>(
"df_u0",
static_cast<std::size_t
>(nExt_));
884 uprev_[
c] =
View<double>(
"df_uprev",
static_cast<std::size_t
>(nExt_));
890 advDiag_ =
View<double>(
"df_advdiag",
static_cast<std::size_t
>(n));
897 momSolver_.setJacobi(2, 0.7);
901 if (momMGon_ && !(dist_ && useStaircaseMG_)) {
903 momSolver_.setPreconditioner(
906 momSolver_.setPreconditioner(
909 pcg_.setVcycle(2, 2, 60, 0.8);
910 pcg_.setSingular(
true);
919 const double idiag = rho_ / dt_;
925 for (
int c = 0;
c < 3; ++
c)
931 for (
int a = 0;
a < 3; ++
a)
944 momOp_.
hasAdv = implicitFou_;
954 ufv, faceFieldBuilt_);
955 for (
int c = 0;
c < 3; ++
c) {
967 if (momMGon_ && useStaircaseMG_)
968 velMG_.setFineOp(momOp_);
973 for (
int c = 0;
c < 3; ++
c) {
984 (momMGSolver_ ? momSolver_.solveDefectCorrection(
993 if (outerIters_ > 1) {
994 lastOuterIters_ =
outer + 1;
997 for (
int c = 0;
c < 3; ++
c)
1000 if (
dmax < outerTol_)
1003 for (
int c = 0;
c < 3; ++
c)
1021 Kokkos::deep_copy(phi_, 0.0);
1043 if (
dbg && !dist_) {
1046 const FvOp&
op0 = presMG_.op(0);
1047 auto st =
op0.faceStart;
1050 auto iv =
op0.invVol;
1052 double su = 0.0,
sv = 0.0,
sn = 0.0;
1053 Kokkos::parallel_reduce(
1054 "amr::dbg_compat", n,
1059 const double m = (d > 1
e-30) ? 1.0 : 0.0;
1065 std::fprintf(
stderr,
"[amr pres] rhs fluid-mean=%.3e |rhs|_D=%.3e (rel mean %.3e)\n",
1066 su /
sv, std::sqrt(
sn), (
su /
sv) / (std::sqrt(
sn) + 1
e-300));
1067 if (!presDbgSpdDone_) {
1071 presDbgSpdDone_ =
true;
1073 yr(
"dbg_y",
static_cast<std::size_t
>(n)),
Ax(
"dbg_Ax",
static_cast<std::size_t
>(n)),
1074 Ay(
"dbg_Ay",
static_cast<std::size_t
>(n));
1075 Kokkos::parallel_for(
1077 xr(
i) = std::sin(0.7 *
static_cast<double>(
i) + 0.3);
1078 yr(
i) = std::cos(1.3 *
static_cast<double>(
i) + 1.1);
1084 Kokkos::parallel_reduce(
1094 "[amr pres] SPD probe: <y,Lx>_D=%.15e <x,Ly>_D=%.15e rel asym=%.2e; "
1095 "Rayleigh <x,Lx>_D=%.3e <y,Ly>_D=%.3e (must be <=0)\n",
1103 lastPresIters_ =
R.iters;
1105 std::fprintf(
stderr,
"[amr pres] pcg iters=%d res0=%.3e res=%.3e rel=%.3e\n",
R.iters,
1106 R.res0,
R.res,
R.res0 > 0 ?
R.res /
R.res0 : 0.0);
1108 Kokkos::deep_copy(presMGD_.b(0), div_);
1109 Kokkos::deep_copy(presMGD_.x(0), 0.0);
1111 presMGD_.vcycle(2, 2, 60, 0.8);
1112 Kokkos::deep_copy(phi_, presMGD_.x(0));
1115 Kokkos::deep_copy(presMG_.b(0), div_);
1116 Kokkos::deep_copy(presMG_.x(0), 0.0);
1121 presMG_.vcycle(2, 2, 60, 0.8);
1127 std::fprintf(
stderr,
"[amr pres] vcycle %2d |r|=%.6e\n",
it + 1,
rn);
1130 Kokkos::deep_copy(phi_, presMG_.x(0));
1149 faceFieldBuilt_ =
true;
1151 for (
int a = 0;
a < 3; ++
a)
1154 for (
int c = 0;
c < 3; ++
c)
1157 rho_ / dt_, mu_, n);
1176 adaptOldT_ = std::make_unique<Octree>(*t_);
1177 for (
int c = 0;
c < 3; ++
c)
1178 adaptU_[
static_cast<std::size_t
>(
c)] =
velocity(
c);
1184 for (
int c = 0;
c < 3; ++
c)
1185 adaptGradU_[
static_cast<std::size_t
>(
c)] =
1192 template <
class SdfFn>
1195 throw std::runtime_error(
"amr::AmrFlow::finishAdapt called without beginAdapt");
1196 std::array<std::vector<double>, 3>
nu;
1197 for (
int c = 0;
c < 3; ++
c)
1198 nu[
static_cast<std::size_t
>(
c)] =
1199 transferField(*adaptOldT_, adaptU_[
static_cast<std::size_t
>(
c)], *t_,
true,
1200 dist_ ? &adaptGradU_[
static_cast<std::size_t
>(
c)] :
nullptr);
1201 std::vector<double>
np =
transferField(*adaptOldT_, adaptP_, *t_,
true,
1202 dist_ ? &adaptGradP_ :
nullptr);
1204 for (
int c = 0;
c < 3; ++
c) {
1211 for (
int c = 0;
c < 3; ++
c)
1212 adaptU_[
static_cast<std::size_t
>(
c)].clear();
1222 template <
class SdfFn>
1225 throw std::runtime_error(
"amr::AmrFlow::rebalanceMpi requires initMpi");
1226 std::vector<std::vector<double>>
cols(4);
1227 for (
int c = 0;
c < 3; ++
c)
1230 dist_->rebalance(
cols);
1232 for (
int c = 0;
c < 3; ++
c) {
1242 auto m = Kokkos::create_mirror_view(p_);
1244 m(
i) =
h[
static_cast<std::size_t
>(
i)];
1245 Kokkos::deep_copy(p_, m);
1251 Kokkos::parallel_for(
1266 std::vector<double>
h(
static_cast<std::size_t
>(n_));
1267 auto m = Kokkos::create_mirror_view(
s);
1268 Kokkos::deep_copy(m,
s);
1270 h[
static_cast<std::size_t
>(
i)] = m(
i);
1284 Kokkos::parallel_for(
1287 Kokkos::deep_copy(
mg.x(0), 0.0);
1288 mg.vcycle(mgVcPre_, mgVcPre_, mgVcBottom_, 0.7);
1291 Kokkos::parallel_for(
1298 Kokkos::parallel_reduce(
1299 "amr::flow_maxdiff", n,
1301 double d =
a(
i) - b(
i);
1307 Kokkos::Max<double>(m));
1312 auto m = Kokkos::create_mirror_view(d);
1313 Kokkos::deep_copy(m, d);
1315 h[
static_cast<std::size_t
>(
i)] = m(
i);
1319 auto m = Kokkos::create_mirror_view(u_[
c]);
1321 m(
i) =
h[
static_cast<std::size_t
>(
i)];
1322 Kokkos::deep_copy(u_[
c], m);
1333 if (
v.extent(0) ==
static_cast<std::size_t
>(n_))
1335 View<double> packed(Kokkos::view_alloc(
"amr::local_packed", Kokkos::WithoutInitializing),
1336 static_cast<std::size_t
>(n_));
1337 Kokkos::parallel_for(
1347 View<double> packed(Kokkos::view_alloc(
"amr::vel_packed", Kokkos::WithoutInitializing),
1348 static_cast<std::size_t
>(n_) * 3);
1349 for (
int c = 0;
c < 3; ++
c) {
1353 Kokkos::parallel_for(
1413 const FvOp&
gpOp0() {
return dist_ ? presMGD_.op(0) : presMG_.op(0); }
1418 template <
class SdfFn>
1420 dhalo_.init(*dist_);
1421 for (
int a = 0;
a < 3; ++
a)
1422 shiftD_[
a] = dist_->blockFineOrigin()[
a];
1423 auto resv = [hp = &dhalo_,
sh = shiftD_](
const std::array<long, 3>& p) ->
Index {
1424 std::array<long, 3> g = p;
1425 for (
int a = 0;
a < 3; ++
a)
1427 return hp->resolveGlobal(g);
1429 mom_.setFrameShift(shiftD_);
1430 mom_.setResolver(
resv);
1434 const double beta = mu_ / (h0_ * h0_);
1437 mom_.build(
sdfFn, rho_ / dt_, beta);
1441 (void)pres_.periodicNeighbor(i, ax, -dr);
1443 (void)pres_.periodicNeighbor(j, ax, dr);
1447 if (ghostProj_ || ghostGrad_) {
1451 if (dhalo_.resolveMisses() == 0)
1456 nExt_ = dhalo_.extendedSize();
1458 allred_ = [
this](
double s) {
return allSum(
s); };
1464 const Index ng = dhalo_.numGhosts();
1465 std::vector<std::array<long, 3>>
glo(
static_cast<std::size_t
>(
ng));
1466 std::vector<unsigned>
glv(
static_cast<std::size_t
>(
ng));
1467 for (
Index g = 0; g <
ng; ++g) {
1468 for (
int a = 0;
a < 3; ++
a)
1469 glo[
static_cast<std::size_t
>(g)][
a] =
1470 static_cast<long>(dhalo_.ghostCoord(g)[
a]) - shiftD_[
a];
1471 glv[
static_cast<std::size_t
>(g)] =
1472 static_cast<unsigned>(dhalo_.level(dhalo_.numLocal() + g));
1474 mom_.setGhosts(
glo,
glv);
1498 Kokkos::deep_copy(presMGD_.b(0),
r);
1499 Kokkos::deep_copy(presMGD_.x(0), 0.0);
1500 presMGD_.vcycle(2, 2, 60, 0.8);
1501 presMGD_.vcycle(2, 2, 60, 0.8);
1502 Kokkos::deep_copy(
z, presMGD_.x(0));
1504 Kokkos::deep_copy(presMG_.b(0),
r);
1505 Kokkos::deep_copy(presMG_.x(0), 0.0);
1506 presMG_.vcycle(2, 2, 60, 0.8);
1507 presMG_.vcycle(2, 2, 60, 0.8);
1508 Kokkos::deep_copy(
z, presMG_.x(0));
1526 Kokkos::parallel_for(
1530 Kokkos::deep_copy(gprh_, gpr_);
1537 Kokkos::deep_copy(gpv_, 0.0);
1538 Kokkos::deep_copy(gpp_, 0.0);
1550 const double rhatV =
1555 Kokkos::deep_copy(gps_, gpr_);
1557 const double snorm =
1573 Kokkos::deep_copy(gpr_, gps_);
1575 const double rnorm =
1602 void buildGhostGradOverlay() {
1604 std::vector<Index>
cells;
1609 std::vector<Index> idx(
static_cast<std::size_t
>(m) * 9, 0);
1610 std::vector<double> w(
static_cast<std::size_t
>(m) * 9, 0.0);
1623 for (
int a = 0;
a < 3; ++
a) {
1624 const std::size_t
o =
static_cast<std::size_t
>(
s) * 9 +
static_cast<std::size_t
>(
a) * 3;
1625 for (
int k = 0; k < 3; ++k)
1626 idx[
o +
static_cast<std::size_t
>(k)] =
i;
1634 w[
o + 1] = -0.5 /
h;
1643 w[
o + 2] = -0.5 /
h;
1648 w[
o + 1] = -1.0 /
h;
1656 w[
o + 1] = -2.0 /
h;
1663 w[
o + 1] = -1.0 /
h;
1675 template <
class SdfFn>
1681 for (
int d = 0; d < 3; ++d) {
1687 double gmag = std::sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2]);
1690 int t1 = (axis + 1) % 3,
t2 = (axis + 2) % 3;
1691 double denom = (std::fabs(g[t1]) + std::fabs(g[
t2])) /
gmag * h0_;
1698 const Octree* t_ =
nullptr;
1701 double rho_ = 1.0, mu_ = 1.0, dt_ = 1
e6;
1703 bool presPCG_ =
true;
1704 bool presDbgSpdDone_ =
false;
1705 bool momMGon_ =
true;
1706 bool useStaircaseMG_ =
false;
1707 int mgVcPre_ = 2, mgVcBottom_ = 30;
1708 Index mgMinCoarse_ = 256;
1709 bool momGS_ =
false;
1712 bool ghostGrad_ =
true;
1715 bool ghostProj_ =
false;
1716 int8_t ghostProjReq_ = -1;
1718 int gpMatrixOrder_ = 2, gpRhsOrder_ = 2;
1721 int outerIters_ = 1;
1722 double outerTol_ = 1
e-6;
1723 double momTol_ = 1
e-8;
1724 bool advect_ =
false;
1725 bool implicitFou_ =
true;
1728 int lastMomIters_ = 0, lastPresIters_ = 0, lastOuterIters_ = 1;
1731 AmrPoisson<3, Bits> pres_;
1738 std::array<View<double>, 3> defc_;
1741 GhostGradOverlay gc_;
1742 GhostOverlayDev gpOv_;
1743 std::vector<char> gpPocket_;
1745 CfCompCsrDev cfDiv_;
1746 std::array<CfCsrDev, 3> cfGrad_;
1747 CfCompCsrDev cfUfVel_;
1750 View<double> gpr_, gprh_, gpp_, gpph_, gpv_, gps_, gpsh_, gpt_;
1753 std::array<View<double>, 3> u_, gx_;
1754 std::array<View<double>, 3> u0_,
1758 bool faceFieldBuilt_ =
1760 std::unique_ptr<Octree> adaptOldT_;
1761 std::array<std::vector<double>, 3> adaptU_;
1762 std::vector<double> adaptP_;
1763 std::array<std::vector<std::array<double, 3>>, 3> adaptGradU_;
1764 std::vector<std::array<double, 3>> adaptGradP_;
1769 LeafHaloExchange dhex_;
1771 std::array<long, 3> shiftD_{};
1773 std::function<
double(
double)> allred_;
double allSum(double s) const
Global sum (identity single-rank).
void setMomentumGS(bool on)
Opt-in: use the multicolour Gauss–Seidel smoother in the momentum MG (Galerkin or staircase) instead ...
void setViscosity(double mu)
void setPressure(const std::vector< double > &h)
Write the accumulated rotational pressure from host (restart / finishAdapt).
void runMgVcycle(MG &mg, View< const double > r, View< double > z)
Run one V-cycle of a momentum MG as a preconditioner: z = M⁻¹ r.
void setCfScheme(int scheme)
Coarse/fine (2:1) interface scheme (cf_scheme.hpp): 0 = standard two-point flux (default,...
void syncScalar(View< double > v)
Refresh the ghost tail of one cell scalar (p, φ, Krylov scratch).
std::vector< double > faceField() const
Copy the divergence-free face field to host (one value per CSR (sub)face, forEachFaceFull order).
void ghostMatvec(View< const double > x, View< double > y)
void setVelocityMGStaircase(bool on)
Choose the momentum-MG coarse-operator strategy: false (default) = Galerkin (MomentumMG,...
void syncVel()
Refresh the ghost tails of the three velocity components (one batched message round).
void setAdvectionScheme(int s)
High-order advection scheme: 0 = second-order upwind (SOU, default), 1 = Koren TVD.
std::vector< double > pressure() const
Copy the pressure field back to host (single D2H), (num_leaves,) — the incremental-rotational p.
void copyToHost(const View< double > &d, std::vector< double > &h) const
Copy a device View into a host vector (sized n_).
void initMpi(DistributedOctree< 3, Bits > &d)
Distributed mode (docs/amr_distributed_flow.md, rung 4): run this solver on one ORB block of a Distri...
void finishProjection(Index n)
Shared projection tail: build the div-free face field from u* + φ, correct the cell velocities (ABC /...
void setMomentumMG(bool on)
Use the Galerkin velocity multigrid (MomentumMG) as the momentum BiCGStab preconditioner.
std::vector< double > velocity(int c) const
Copy a velocity component back to host (single D2H, no host loop — S2a).
BlockOctree< 3, Bits > Octree
void setVelocity(int c, const std::vector< double > &h)
Set a velocity component from host (testing / initial conditions).
std::vector< double > velocities() const
All three velocity components interleaved as a flat (n,3) row-major host buffer (out[i*3+c]) with a s...
void setBodyForce(double fx, double fy, double fz)
double divNormFace()
L2 norm of the divergence of the ABC face field uf_ (built each project()): the φ-solve residual,...
void setMomentumTol(double tol)
Relative tolerance for the per-step momentum BiCGStab solve (default 1e-8).
void zeroSolid(View< double > v)
Zero a per-leaf field on non-fluid cells (the transferred fields' solid cleanup).
bool isFluid(Index i) const
Per-leaf fluid mask (false inside the solid) — for host-side post-processing / bindings.
Index numGhostCells() const
Distributed: number of ghost slots in the ±2 registry (0 single-rank).
std::vector< double > debugSou(int comp)
DEBUG: the raw high-order advection ∇·(u u_comp) per cell from the current velocity (== host oracle::...
void setVelocityMGMinCoarse(Index m)
Pore-scale cap for the staircase velocity-MG: the coarsest level keeps ≥ this many cells,...
void finishAdapt(SdfFn &&sdfFn)
Rebuild on the mutated octree and transfer the snapshotted fields onto it.
static double maxAbsDiff(View< const double > a, View< const double > b, Index n)
Max |a − b| over all cells (the Picard outer-loop convergence measure).
void ghostPrec(View< const double > r, View< double > z)
int lastMomIters() const
Total momentum BiCGStab iterations (summed over the 3 components) of the last step.
double divNormL2()
L2 norm of the (openness-weighted) divergence of the current velocity — the ghost-closed divergence w...
void setMomentumMGSolver(bool on)
Opt-in (P4): solve the momentum predictor with the velocity multigrid used as the solver — MG-precond...
void setDensity(double rho)
void project(int presIters=60)
Pressure projection of the current velocity in place.
void setOuterIterations(int n, double tol=1e-6)
Optional Picard outer loop over the lagged advection (mirror of flow's outerIters_): each outer itera...
void setImplicitAdvection(bool on)
Implicit-FOU deferred correction (default ON).
const FvOp & gpOp0()
The pressure operator the ghost solver runs on (distributed MG level 0 or presMG_'s).
void rebalanceMpi(SdfFn &&sdfFn)
Distributed load rebalance (docs/amr_distributed_flow.md, rung 6): re-decompose the octree by leaf co...
void installGhostMeta()
Mirror the halo registry's ghost metadata (block-local lo + level) into mom_ and pres_.
int solveGhostBiCGStab(View< double > x, View< const double > b, int maxIters, double tol=1e-10)
void prepareDistributed(SdfFn &&sdfFn)
Install the resolver seams, run every prober to the miss-collect fixpoint, freeze the ±2 halo,...
void init(const Octree &t, Real h0, Vec< 3 > origin=Vec< 3 >{})
int lastPresIters() const
Pressure PCG iterations of the last step.
void setSolid(SdfFn &&sdfFn)
Build the cut-cell operators (host) + upload all device structures.
void setGhostGradient(bool on)
Directional ghost cell-gradient for the −∇pⁿ predictor and the projection's cell correction (the AMR ...
void step(int momIters=100, int presIters=60)
One incompressible step on device (Stokes, or Navier–Stokes with setAdvection).
void setPressurePCG(bool on)
Use MG-preconditioned CG for the pressure solve (default) vs plain V-cycles.
void gpProject(View< double > v)
int lastOuterIters() const
Picard outer iterations actually run in the last step (1 unless setOuterIterations(>1)).
void beginAdapt()
Snapshot the octree topology + (u, p) ahead of an external mesh mutation.
void setGhostProjection(bool on, int matrixOrder=2, int rhsOrder=2)
FULL directional ghost-cell projection (the AMR port of flow's collocated set_ghost_projection): the ...
void setAdvection(bool on)
Enable momentum advection ∇·(u u) (default OFF ⇒ Stokes).
std::vector< double > localVector(const View< double > &v) const
Host copy of the LOCAL rows of a (possibly ghost-extended) per-cell field.
Cell-centered FV Poisson operator on one (periodic) block octree.
void setGhosts(std::vector< std::array< long, Dim > > lo, std::vector< unsigned > lv)
Declare the ghost slots [n, n+nGhost): block-local lo corner (longs — ghosts lie outside the block) a...
const Octree & octree() const
Real cellWidth(Index i) const
void setFrameShift(const std::array< long, Dim > &s)
Distributed frame shift: this block's global fine origin.
void init(const Octree &t, Real h0)
void setOrigin(const Vec< Dim > &o)
Index periodicNeighbor(Index i, int axis, int dir) const
Periodic face neighbour leaf (covering the cell just across the face).
unsigned levelOf(Index slot) const
Octree level of an extended slot (local leaf or declared ghost).
void setResolver(ExtResolver r)
void forEachFaceFull(Index i, Fn &&fn) const
Like forEachFaceNeighbor but exposes geometry for a consistent FV divergence/gradient: fn(neighbour,...
void buildOpenness(OpenFn &&openFn)
Build face openness from a geometry callable openFn(faceCentreWorld, axis) -> [0,1] (1 = fully fluid,...
Real cellVolume(Index i) const
Per-block adaptive octree over block-local Morton codes.
const AmrGeometry< Dim > & globalGeometry() const
void init(const LeafHalo< Dim, Bits > &h)
void exchange3(View< double > x0, View< double > x1, View< double > x2, int tag=46) const
Batched 3-component refresh (one message round for u0,u1,u2 — stride-3 packing).
void exchange(View< double > x, int tag=45) const
Refresh x[nLocal, nLocal+nGhost) (x is the extended device field, size >= extendedSize()).
int MPI_Allreduce(const void *sbuf, void *rbuf, int count, MPI_Datatype dt, MPI_Op, MPI_Comm)
void presUpdate(View< double > p, View< const double > phi, View< const double > div, View< const char > fluid, double rho_dt, double mu, Index n)
Rotational incremental pressure update: p += (ρ/dt)φ − μ·div, on fluid cells.
double divFaceNorm(const FaceGeom &g, View< const double > uf)
L2 norm of the divergence of the FACE field uf (the div-free flux diagnostic / host-parity check).
void axpy(View< double > y, double a, View< const double > x, Index n)
y += a·x
GhostOverlay buildGhostOverlay(const BlockOctree< 3, Bits > &t, const AmrPoisson< 3, Bits > &pres, const std::vector< double > &sdfC, int matrixOrder, int rhsOrder, bool *bandViolation=nullptr)
Build the overlay from the octree + the cell-centered SDF samples (AmrCutCell::sdfCRaw — EXTENDED ove...
CfUfDelta buildCfUfDelta(const AmrPoisson< 3, Bits > &ap, const BlockOctree< 3, Bits > &t, FluidFn &&fluidOk, CfScheme scheme)
void bicgPUpdate(View< double > p, View< const double > r, View< const double > v, double beta, double omega, Index n)
BiCGStab direction update: p = r + β(p − ω v).
void deferredSou(const FaceGeom &g, View< const double > u0, View< const double > u1, View< const double > u2, int comp, double rho, int advScheme, View< double > defc, View< const double > uf, bool useFace)
Deferred-correction advection term for component comp: defc = ρ·SOU − ρ·FOU (UNSCALED; the predictor ...
void advectExplicit(const FaceGeom &g, View< const double > u0, View< const double > u1, View< const double > u2, int comp, double rho, int advScheme, View< double > defc, View< const double > uf, bool useFace)
Fully-explicit high-order advection for component comp: defc = ρ·SOU (no implicit FOU; the setImplici...
void cfApply(const CfCsrDev &c, View< const double > f, View< double > out)
out(i) += Σ coef·f(slot).
void correct(View< double > uc, View< const double > gphi, View< const char > fluid, Index n)
u_c -= gradPhi_c on fluid cells (the projection velocity correction).
GhostOverlayDev uploadGhostOverlay(const GhostOverlay &h)
CfScheme
Coarse/fine interface scheme for the collocated flow operators.
@ standard
raw coarse value (two-point flux; 1st-order at 2:1 faces)
CfCompCsrDev uploadCfCompCsr(const CfCompCsr &h, const char *name)
void applyFv(const FvOp &op, View< const double > u, View< double > Lu)
Hu = (c0·I + cD·L) u (consistent conservative FV Laplacian, c0=0/cD=1 ⇒ pure L).
std::vector< std::array< double, Dim > > transferFieldGradients(const BlockOctree< Dim, Bits > &oldT, const std::vector< double > &oldF)
Per-old-leaf minmod prolongation gradients (per fine-coordinate unit) — transferField's stencil,...
bool amrEnvFlag(const char *name)
Truthy environment flag (unset / "" / "0" ⇒ false).
void buildFaceField(const FaceGeom &g, View< const double > u0, View< const double > u1, View< const double > u2, View< const double > phi, View< double > uf)
Build the ABC/Basilisk divergence-free FACE field: uf(k) = ½(u^axis_i+u^axis_j) − (φ₊−φ₋)/dist for fa...
std::array< CfCsr, 3 > buildCfGradDelta(const AmrPoisson< 3, Bits > &ap, const BlockOctree< 3, Bits > &t, RowFn &&rowOk, FluidFn &&fluidOk, CfScheme scheme)
(G_scheme − G_std) for the ABC cell gradient gradOf/grad3.
void ghostApplyDelta(const GhostOverlayDev &ov, View< const double > x, View< double > y)
Device matrix overlay (== ghostApplyDeltaHost). Distinct rows per thread: no atomics.
void momRhs(View< const double > uc, View< const double > gradP, View< const double > adv, View< const double > rscale, View< const char > fluid, double idiag, double fc, View< double > b, Index n)
Momentum RHS for one component: b_i = fluid ? (idiag·u_i + f_c − gradP_i − adv_i)·rscale_i : 0 (== Am...
void buildFou(const FaceGeom &g, View< const double > u0, View< const double > u1, View< const double > u2, double rho, View< const double > rscale, View< double > advDiag, View< double > advCoef, View< const double > uf, bool useFace)
Build the implicit-FOU advection operator from the lagged velocity u0..2 (uⁿ) entirely on device,...
void applyGhostGrad(const GhostGradOverlay &ov, View< const double > f, View< double > gx, View< double > gy, View< double > gz)
Overwrite gx/gy/gz on the overlay cells with the directional stencil applied to f.
void grad3(const FaceGeom &g, View< const double > f, View< double > gx, View< double > gy, View< double > gz)
ABC cell-gradient of a scalar field f: gx/gy/gz = ½(g⁻+g⁺) of the adjacent face gradients along each ...
std::vector< char > findPocketCells(const BlockOctree< 3, Bits > &t, const AmrPoisson< 3, Bits > &pres, const std::vector< double > &sdfC)
Fragmentation guard (the AMR port of flow's host-BFS pocket guard): the BINARY coupled-face graph (a ...
CfCsr buildCfLapDelta(const AmrPoisson< 3, Bits > &ap, const BlockOctree< 3, Bits > &t, double factor, RowFn &&rowOk, FluidFn &&fluidOk, CfScheme scheme)
(∇²_scheme − ∇²_std) as a scalar CSR, ×factor (pass μ for the momentum deferred-correction RHS,...
CfCompCsr buildCfDivDelta(const AmrPoisson< 3, Bits > &ap, const BlockOctree< 3, Bits > &t, RowFn &&rowOk, FluidFn &&fluidOk, CfScheme scheme)
(D_scheme − D_std) for the face-average divergence div_i = invV·Σ α·A·dir·(face value).
double dotPlain(View< const double > a, View< const double > b, Index n)
Plain (unweighted) dot product.
FaceGeom buildFaceGeom(const AmrPoisson< Dim, Bits > &ap, FluidFn &&isFluid)
Build FaceGeom from a built AmrPoisson (openness set) + a fluid predicate.
void ghostDivergDelta(const GhostOverlayDev &ov, View< const double > u0, View< const double > u1, View< const double > u2, View< double > d)
Device divergence overlay (== ghostDivergDeltaHost).
void cfApplyComp(const CfCompCsrDev &c, View< const double > u0, View< const double > u1, View< const double > u2, View< double > out)
out(i) += Σ coef·u[comp](slot).
std::vector< double > transferField(const BlockOctree< Dim, Bits > &oldT, const std::vector< double > &oldF, const BlockOctree< Dim, Bits > &newT, bool linear=true, const std::type_identity_t< std::vector< std::array< double, Dim > > > *gradIn=nullptr)
Conservative remap of a leaf field from oldT to newT (same domain).
void divergence(const FaceGeom &g, View< const double > u0, View< const double > u1, View< const double > u2, View< double > div)
Openness-weighted FV divergence: div_i = invVol_i Σ_faces α·area·dir·½(u^axis_i+u^axis_j),...
void residualFv(const FvOp &op, View< const double > u, View< const double > rhs, View< double > res)
res = rhs − H u.
std::vector< std::array< double, Dim > > transferGradients(const DistributedOctree< Dim, Bits > &d, const std::vector< double > &f)
transferField's minmod prolongation gradients on a DistributedOctree: bit-identical to the block-loca...
void removeMeanVolReduced(View< double > u, View< const double > invVol, View< const double > mask, Index n, const std::function< double(double)> &reduce)
Project u onto the FLUID range: zero solid cells, then subtract the volume-weighted mean over the flu...
MORTON_HD double hoFaceValue(double upup, double up, double down, int scheme)
High-order advected face value from the two upwind cells (upup, up) and the downwind cell (down).
auto makeBinaryOpenFn(SdfFn sdfFn, double h0)
Binary openness callable factory for the MG surrogate: a face is open iff both adjacent centers (prob...
CfCsrDev uploadCfCsr(const CfCsr &h, const char *name)
std::array< Real, Dim > Vec
Multi-dimensional real vector.
View< T > toDevice(const std::vector< T > &h, const std::string &label)
Upload a host std::vector into a freshly-sized device View (empty vector => empty view).
Kokkos::View< T *, MemSpace > View
1D device array.
double Real
Default host floating type. Device kernels may use float; conversions happen at the boundary.
std::vector< std::remove_const_t< typename V::value_type > > toVector(const V &view)
Copy a (host- or device-resident) Kokkos View of any rank into a contiguous host std::vector,...
std::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).
Device mirror of a BlockOctree's leaf arrays + device-callable queries.
void upload(const Host &t)
(Re)upload the host octree's current leaf set to the device.
Device mirror of a CfCsr (empty when the scheme is standard / no C/F rows).
View< Index > upupI
upstream-of-i probe (periodicNeighbor(i,axis,−dir)) — SOU, size nFaces
View< double > dist
face-normal distance (physical) per face, size nFaces
View< Index > upupJ
upstream-of-j probe (periodicNeighbor(j,axis,+dir)) — SOU, size nFaces
View< double > rawArea
raw face area (physical, no openness) per face — advection flux
View< int > axis
face axis 0/1/2, size nFaces
View< char > fluid
per-cell fluid flag, size n
View< double > alphaArea
α·area (physical) per face, size nFaces
View< Index > start
CSR row offsets, size n+1.
View< double > invVol
1/V_i per cell, size n
View< double > alpha
openness per face (gradient gate), size nFaces
View< Index > nbr
neighbour leaf per face, size nFaces
View< int > dir
face direction +1/-1, size nFaces
Ghost-gradient overlay (setGhostGradient): per cut cell, a precomputed 3-point directional FD stencil...
View< Index > cell
[n] leaf index
Index n
number of overlay (cut) cells
View< Index > idx
[n*9] stencil cell, slot s*9 + axis*3 + k
View< double > w
[n*9] stencil weight (0 = unused)
Host ghost-projection overlay: one row per non-clean fluid leaf (== cut cell: some ±1 center sample s...
Assembled momentum operator on the device: (A u)_i = diag_i u_i + Σ coef·u[nbr], with an optional imp...
View< double > diag
size n
View< Index > advStart
face-geom CSR row offsets, size n+1
View< Index > faceNbr
neighbour leaf per off-diagonal, size nnz
View< Index > advNbr
face-geom neighbour per face, size nFaces
View< double > advDiag
per-cell outflow (diagonal) advection weight, size n
View< double > faceCoef
off-diagonal coefficient, size nnz
View< Index > faceStart
CSR row offsets, size n+1.
View< double > advCoef
per-face inflow advection coefficient (0 on outflow/solid faces)