32#ifndef PECLET_CORE_AMR_FLOW_ORACLE_HPP
33#define PECLET_CORE_AMR_FLOW_ORACLE_HPP
35#ifdef PECLET_CORE_HAVE_MORTON
59template <
unsigned Bits = 21u>
105 ghostProjReq_ =
on ? 1 : 0;
130 template <
class SdfFn>
132 mom_.init(*t_, h0_, origin_);
133 mom_.build(
sdfFn, rho_ / dt_, mu_ / (h0_ * h0_));
134 pres_.
init(*t_, h0_);
136 presMG_.build(*t_, h0_);
140 ghostProj_ = (ghostProjReq_ != 0);
141 ghostSampled_ = ghostProj_ && (ghostSampledReq_ == 1);
142 if (ghostProj_ && !ghostSampled_) {
146 if (ghostProjReq_ == 1)
147 throw std::runtime_error(
148 "amr ghost projection: an overlay row's ±2 closure reach crosses a 2:1 level "
149 "boundary — widen the refineToSdf band margin");
152 "peclet::core AmrFlow(oracle): AUTO scheme fell back to the aperture projection "
153 "(the finest band is too thin for the ghost overlay).\n");
169 presMG_.setOpenness(
binFn);
173 presMG_.setOpenness(
binFn);
178 maskC_.assign(
static_cast<std::size_t
>(t_->
numLeaves()), 0.0);
180 maskC_[
static_cast<std::size_t
>(
i)] =
181 (mom_.isFluid(
i) && !(!gpPocket_.empty() && gpPocket_[
static_cast<std::size_t
>(
i)]))
186 if (!
rows.coupled[
static_cast<std::size_t
>(
r)])
187 maskC_[
static_cast<std::size_t
>(
rows.cell[
static_cast<std::size_t
>(
r)])] = 0.0;
191 presMG_.setOpenness([&](
const Vec<3>&
fc,
int axis) {
return faceFrac(
sdfFn,
fc, axis); });
212 for (
int c = 0;
c < 3; ++
c)
213 u_[
c].assign(
static_cast<std::size_t
>(n), 0.0);
214 phi_.assign(
static_cast<std::size_t
>(n), 0.0);
215 p_.assign(
static_cast<std::size_t
>(n), 0.0);
218 faceStart_.assign(
static_cast<std::size_t
>(n) + 1, 0);
222 faceStart_[
static_cast<std::size_t
>(
i) + 1] = faceStart_[
static_cast<std::size_t
>(
i)] +
cnt;
224 uf_.assign(
static_cast<std::size_t
>(faceStart_[
static_cast<std::size_t
>(n)]), 0.0);
225 faceFieldBuilt_ =
false;
228 const std::vector<double>&
velocity(
int c)
const {
return u_[
c]; }
234 adaptOldT_ = std::make_unique<Octree>(*t_);
238 template <
class SdfFn>
241 throw std::runtime_error(
"oracle::AmrFlow::finishAdapt called without beginAdapt");
242 std::array<std::vector<double>, 3>
nu;
243 for (
int c = 0;
c < 3; ++
c)
244 nu[
static_cast<std::size_t
>(
c)] =
245 transferField(*adaptOldT_, adaptU_[
static_cast<std::size_t
>(
c)], *t_,
true);
246 std::vector<double>
np =
transferField(*adaptOldT_, adaptP_, *t_,
true);
249 const bool fl = mom_.isFluid(
i);
250 for (
int c = 0;
c < 3; ++
c)
251 u_[
static_cast<std::size_t
>(
c)][
static_cast<std::size_t
>(
i)] =
252 fl ?
nu[
static_cast<std::size_t
>(
c)][
static_cast<std::size_t
>(
i)] : 0.0;
253 p_[
static_cast<std::size_t
>(
i)] =
fl ?
np[
static_cast<std::size_t
>(
i)] : 0.0;
266 std::array<std::vector<double>, 3>
adv;
269 mom_.buildAdvectionFou(u_, rho_, uf_, faceStart_,
271 for (
int c = 0;
c < 3; ++
c) {
272 adv[
c].assign(
static_cast<std::size_t
>(n), 0.0);
274 if (mom_.isFluid(
i)) {
275 double term = rho_ * advectHO(
c,
i);
277 term -= mom_.fouApply(
i, u_[
c]);
278 adv[
c][
static_cast<std::size_t
>(
i)] =
term;
284 for (
int c = 0;
c < 3; ++
c) {
287 std::vector<double>
cfm;
289 cfm.assign(
static_cast<std::size_t
>(n), 0.0);
292 std::vector<double>
src(
static_cast<std::size_t
>(n), 0.0);
294 if (mom_.isFluid(
i)) {
296 double s = (rho_ / dt_) * u_[
c][
static_cast<std::size_t
>(
i)] + f_[
c] - gradP(p_,
i,
c);
298 s -=
adv[
c][
static_cast<std::size_t
>(
i)];
300 s +=
cfm[
static_cast<std::size_t
>(
i)];
301 src[
static_cast<std::size_t
>(
i)] =
s;
303 std::vector<double> b = mom_.makeRhs(
src, 0.0);
313 std::vector<double>
div(
static_cast<std::size_t
>(n), 0.0);
326 std::fill(phi_.begin(), phi_.end(), 0.0);
338 presMG_.vcycle(0, phi_,
div);
344 for (
int c = 0;
c < 3; ++
c)
347 u_[
c][
static_cast<std::size_t
>(
i)] -= gradP(phi_,
i,
c);
354 p_[
static_cast<std::size_t
>(
i)] += (rho_ / dt_) * phi_[
static_cast<std::size_t
>(
i)] -
355 mu_ *
div[
static_cast<std::size_t
>(
i)];
364 double ui = vel[axis][
static_cast<std::size_t
>(
i)];
365 double uj = vel[axis][
static_cast<std::size_t
>(
j)];
366 d += alpha *
area * dir * 0.5 * (
ui +
uj);
371 double divNormL2(
const std::array<std::vector<double>, 3>& vel)
const {
375 if (mom_.isFluid(
i)) {
393 Index s = faceStart_[
static_cast<std::size_t
>(
i)];
396 0.5 * (u_[axis][
static_cast<std::size_t
>(
i)] + u_[axis][
static_cast<std::size_t
>(
j)]);
400 ? (phi_[
static_cast<std::size_t
>(
j)] - phi_[
static_cast<std::size_t
>(
i)]) / dist
401 : (phi_[
static_cast<std::size_t
>(
i)] - phi_[
static_cast<std::size_t
>(
j)]) / dist;
402 uf_[
static_cast<std::size_t
>(
s++)] =
uface -
gphi;
411 faceFieldBuilt_ =
true;
421 if (!mom_.isFluid(
i))
423 Index s = faceStart_[
static_cast<std::size_t
>(
i)];
426 d += alpha *
area * dir * uf_[
static_cast<std::size_t
>(
s++)];
431 return std::sqrt(
tot);
436 const std::vector<double>&
faceField()
const {
return uf_; }
437 const std::vector<Index>&
faceStart()
const {
return faceStart_; }
441 static double koren(
double up_m1,
double up,
double down,
double vel) {
443 double r = (std::fabs(
den) < 1
e-10) ? 0.0 :
num /
den;
444 double psi = std::fmax(0.0, std::fmin(2.0 *
r, std::fmin((1.0 + 2.0 *
r) / 3.0, 2.0)));
447 static double tvd(
double LL,
double L,
double R,
double RR,
double vel) {
448 return (vel > 0.0) ? koren(
LL,
L,
R, vel) : koren(
RR,
R,
L, vel);
451 double hoFace(
double upup,
double up,
double down)
const {
462 double advectHO(
int comp,
Index i)
const {
464 Index s = faceFieldBuilt_ ? faceStart_[
static_cast<std::size_t
>(
i)] : 0;
471 const double uface = faceFieldBuilt_ ? uf_[
static_cast<std::size_t
>(
s)]
475 if (!mom_.isFluid(
j))
481 double phiUp = u_[comp][
static_cast<std::size_t
>(
up)];
483 (
upup >= 0 && mom_.isFluid(
upup)) ? u_[comp][
static_cast<std::size_t
>(
upup)] :
phiUp;
493 void gpProject(std::vector<double>&
v)
const {
495 double su = 0.0,
sv = 0.0;
497 const std::size_t
s =
static_cast<std::size_t
>(
i);
499 if (maskC_[
s] > 0.0) {
505 const double m = (
sv > 0.0) ?
su /
sv : 0.0;
507 v[
static_cast<std::size_t
>(
i)] -= maskC_[
static_cast<std::size_t
>(
i)] * m;
515 void solveGhostBiCGStab(std::vector<double>& x,
const std::vector<double>& b,
int maxIters,
516 double tol = 1
e-10) {
518 const std::size_t
ns =
static_cast<std::size_t
>(n);
519 auto applyA = [&](
const std::vector<double>&
v, std::vector<double>&
y) {
527 auto prec = [&](
const std::vector<double>&
r, std::vector<double>&
z) {
528 std::fill(
z.begin(),
z.end(), 0.0);
529 presMG_.vcycle(0,
z,
r);
530 presMG_.vcycle(0,
z,
r);
533 auto dot = [&](
const std::vector<double>&
a,
const std::vector<double>&
c) {
535 for (std::size_t
i = 0;
i <
ns; ++
i)
541 for (std::size_t
i = 0;
i <
ns; ++
i)
545 const double res0 = std::sqrt(dot(
r,
r));
555 for (std::size_t
i = 0;
i <
ns; ++
i)
563 for (std::size_t
i = 0;
i <
ns; ++
i)
564 s[
i] =
r[
i] - alpha *
v[
i];
565 double snorm = std::sqrt(dot(
s,
s));
567 for (std::size_t
i = 0;
i <
ns; ++
i)
573 const double tt = dot(
t,
t);
575 for (std::size_t
i = 0;
i <
ns; ++
i) {
579 const double rnorm = std::sqrt(dot(
r,
r));
599 double gradP(
const std::vector<double>&
fld,
Index i,
int c)
const {
600 if (ghostGrad_ && mom_.isCut(
i)) {
605 const Index r = gpOvS_.
rowOf[
static_cast<std::size_t
>(
i)];
609 return gradOfDir(
fld,
i,
c);
611 double g = gradOf(
fld,
i,
c);
613 if (cfScheme_ !=
CfScheme::standard && !cfGrad_[
static_cast<std::size_t
>(
c)].start.empty()) {
614 const CfCsr&
cs = cfGrad_[
static_cast<std::size_t
>(
c)];
615 for (
Index k =
cs.start[
static_cast<std::size_t
>(
i)];
616 k <
cs.start[
static_cast<std::size_t
>(
i) + 1]; ++k)
617 g +=
cs.coef[
static_cast<std::size_t
>(k)] *
618 fld[
static_cast<std::size_t
>(
cs.slot[
static_cast<std::size_t
>(k)])];
629 double gradOfDir(
const std::vector<double>&
fld,
Index i,
int c)
const {
631 auto F = [&](
Index j) {
return fld[
static_cast<std::size_t
>(
j)]; };
634 return j >= 0 && mom_.isFluid(
j) && t_->
level(
j) == t_->
level(
i) &&
635 !(!gpPocket_.empty() && gpPocket_[
static_cast<std::size_t
>(
j)]);
641 return (
F(
jp) -
F(
jm)) / (2.0 *
h);
660 double gradOf(
const std::vector<double>&
fld,
Index i,
int c)
const {
661 const double pi =
fld[
static_cast<std::size_t
>(
i)];
662 double gp = 0,
gm = 0;
667 if (axis !=
c || alpha <= 1
e-12)
669 double g = (dir > 0) ? (
fld[
static_cast<std::size_t
>(
j)] -
pi) / dist
689 template <
class SdfFn>
695 for (
int d = 0; d < 3; ++d) {
701 double gmag = std::sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2]);
704 int t1 = (axis + 1) % 3,
t2 = (axis + 2) % 3;
705 double denom = (std::fabs(g[t1]) + std::fabs(g[
t2])) /
gmag * h0_;
712 const Octree* t_ =
nullptr;
715 double rho_ = 1.0, mu_ = 1.0, dt_ = 1
e6;
716 bool advect_ =
false;
717 bool ghostGrad_ =
true;
718 bool ghostProj_ =
false;
719 int8_t ghostProjReq_ = -1;
721 int gpMatrixOrder_ = 2, gpRhsOrder_ = 2;
724 bool ghostSampled_ =
false;
725 int8_t ghostSampledReq_ = 0;
726 GhostOverlaySampled gpOvS_;
727 std::vector<double> maskC_;
728 std::vector<char> gpPocket_;
732 std::array<CfCsr, 3> cfGrad_;
734 bool implicitFou_ =
true;
738 AmrPoisson<3, Bits> pres_;
740 std::array<std::vector<double>, 3> u_;
741 std::vector<double> phi_;
742 std::vector<double> p_;
749 std::vector<Index> faceStart_;
750 std::vector<double> uf_;
751 std::unique_ptr<Octree> adaptOldT_;
752 std::array<std::vector<double>, 3> adaptU_;
753 std::vector<double> adaptP_;
754 bool faceFieldBuilt_ =
Real cellWidth(Index i) const
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).
void applyLaplacian(const std::vector< double > &u, std::vector< double > &out) const
out = L u (periodic FV Laplacian).
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.
unsigned level(Index i) const
void setGhostGradient(bool on)
Directional ghost cell-gradient for the −∇pⁿ predictor and the projection's cell correction (the AMR ...
void step(int momSweeps=200, int presIters=60, int presSweeps=4)
One Stokes projection step.
const std::vector< double > & velocity(int c) const
bool isFluid(Index i) const
void setGhostSampled(bool on)
SAMPLED ghost projection: the mixed-level cut-band prototype (the D1 machinery of docs/amr_mixed_leve...
const std::vector< Index > & faceStart() const
void project(int presIters=60, int presSweeps=4)
Pressure projection of the current velocity in place: solve ∇²φ = ∇·u and correct u -= ∇φ.
std::array< std::vector< double >, 3 > & velocityRef()
void setCfScheme(int scheme)
Coarse/fine (2:1) interface scheme (cf_scheme.hpp): 0 = standard two-point flux (default,...
void setImplicitAdvection(bool on)
Implicit-FOU deferred-correction advection (default ON): the first-order-upwind part is solved implic...
void setViscosity(double mu)
const std::vector< double > & faceField() const
The divergence-free face field (read-only): uf[faceStart()[i]+s] for cell i's s-th forEachFaceFull fa...
void setAdvection(bool on)
double advectTerm(int comp, Index i) const
Conservative Koren-TVD advection term ∇·(u u_comp) at leaf i (physical units; the explicit momentum a...
void finishAdapt(SdfFn &&sdfFn)
void buildFaceField()
Build the ABC/Basilisk divergence-free FACE field from the current cell velocity u* and the projectio...
void setAdvectionScheme(int s)
High-order advection scheme: 0 = second-order upwind (SOU, default), 1 = Koren TVD.
void init(const Octree &t, Real h0, Vec< 3 > origin=Vec< 3 >{})
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 ...
double divergence(const std::array< std::vector< double >, 3 > &vel, Index i) const
Openness-weighted FV divergence at leaf i, C/F-consistent: sum over (sub)faces of α·area·(outward fac...
void setSolid(SdfFn &&sdfFn)
Build the cut-cell operators from an SDF callable sdfFn(worldPoint) (>0 fluid).
double divNormFace() const
L2 norm of the divergence of the FACE field uf_ (the div-free flux).
void setDensity(double rho)
double divNormL2(const std::array< std::vector< double >, 3 > &vel) const
BlockOctree< 3, Bits > Octree
void setBodyForce(double fx, double fy, double fz)
auto makeBinaryOpenFnMixed(const BlockOctree< 3, Bits > &t, const AmrPoisson< 3, Bits > &pres, SdfFn sdfFn, double h0, Vec< 3 > origin)
The canonical (sub)face openness for mixed-level cut bands: open iff both adjacent ACTUAL leaf center...
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...
void cfApplyCompHost(const CfCompCsr &c, const std::array< std::vector< double >, 3 > &u, std::vector< double > &out)
out(i) += Σ coef·u[comp](slot) (the divergence overlay).
CfUfDelta buildCfUfDelta(const AmrPoisson< 3, Bits > &ap, const BlockOctree< 3, Bits > &t, FluidFn &&fluidOk, CfScheme scheme)
void ghostDivergDeltaSampledHost(const GhostOverlaySampled &ov, const std::array< std::vector< double >, 3 > &u, std::vector< double > &d)
Divergence overlay (sampled): the sampled analog of ghostDivergDeltaHost (u_bc = 0).
CfScheme
Coarse/fine interface scheme for the collocated flow operators.
@ standard
raw coarse value (two-point flux; 1st-order at 2:1 faces)
void ghostApplyDeltaSampledHost(const GhostOverlaySampled &ov, const std::vector< double > &x, std::vector< double > &y)
Matrix overlay (sampled): y currently holds the BINARY L matvec; overwrite overlay rows with y = rho·...
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,...
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 cfApplyHost(const CfCsr &c, const std::vector< double > &f, std::vector< double > &out)
out(i) += Σ coef·f(slot) (the scalar overlay: momentum ∇² delta, gradient delta per axis).
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 ...
void ghostDivergDeltaHost(const GhostOverlay &ov, const std::array< std::vector< double >, 3 > &u, std::vector< double > &d)
Divergence overlay: d currently holds the BINARY divergence (physical); overwrite overlay rows with d...
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,...
void ghostApplyDeltaHost(const GhostOverlay &ov, const std::vector< double > &x, std::vector< double > &y)
Matrix overlay: y currently holds the BINARY L matvec; overwrite the overlay rows with y = rho·(y + i...
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).
GhostOverlaySampled buildGhostOverlaySampled(const BlockOctree< 3, Bits > &t, const AmrPoisson< 3, Bits > &pres, SdfFn &&sdf, int matrixOrder, int rhsOrder, Vec< 3 > origin=Vec< 3 >{})
Build the sampled overlay.
double gpsDirGrad(const GhostOverlaySampled &ov, Index r, const std::vector< double > &fld, int c, double invh)
Directional ghost cell-gradient on a sampled row (the mixed-level gradOfDir): the same cascade — cent...
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).
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...
std::array< Real, Dim > Vec
Multi-dimensional real vector.
double Real
Default host floating type. Device kernels may use float; conversions happen at the boundary.
std::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).
Component-tagged CSR overlay (the divergence delta): out(i) += Σ_k coef·u[comp](slot).
std::vector< Index > start
Scalar-input CSR overlay: out(i) += Σ_k coef·f(slot) over rows with C/F faces.
(uf_scheme − uf_std) for the div-free FACE field uf_k = ½(u_i+u_j) − (φ₊−φ₋)/d, one delta row per for...
CfCsr phi
reads the projection potential φ, rows = face slots
CfCompCsr vel
reads the velocity components, rows = face slots
std::vector< Index > rowOf
[numLeaves] row index of a leaf, -1 if none
Host ghost-projection overlay: one row per non-clean fluid leaf (== cut cell: some ±1 center sample s...