32#ifndef PECLET_CORE_AMR_FLOW_ORACLE_HPP
33#define PECLET_CORE_AMR_FLOW_ORACLE_HPP
35#ifdef PECLET_CORE_HAVE_MORTON
53template <
unsigned Bits = 21u>
82 template <
class SdfFn>
84 mom_.init(*t_, h0_, origin_);
85 mom_.build(
sdfFn, rho_ / dt_, mu_ / (h0_ * h0_));
89 presMG_.build(*t_, h0_);
90 presMG_.setOpenness([&](
const Vec<3>&
fc,
int axis) {
return faceFrac(
sdfFn,
fc, axis); });
91 const Index n = t_->numLeaves();
92 for (
int c = 0;
c < 3; ++
c)
93 u_[
c].assign(
static_cast<std::size_t
>(n), 0.0);
94 phi_.assign(
static_cast<std::size_t
>(n), 0.0);
95 p_.assign(
static_cast<std::size_t
>(n), 0.0);
98 faceStart_.assign(
static_cast<std::size_t
>(n) + 1, 0);
102 faceStart_[
static_cast<std::size_t
>(
i) + 1] = faceStart_[
static_cast<std::size_t
>(
i)] +
cnt;
104 uf_.assign(
static_cast<std::size_t
>(faceStart_[
static_cast<std::size_t
>(n)]), 0.0);
105 faceFieldBuilt_ =
false;
108 const std::vector<double>&
velocity(
int c)
const {
return u_[
c]; }
115 const Index n = t_->numLeaves();
120 std::array<std::vector<double>, 3>
adv;
123 mom_.buildAdvectionFou(u_, rho_, uf_, faceStart_,
125 for (
int c = 0;
c < 3; ++
c) {
126 adv[
c].assign(
static_cast<std::size_t
>(n), 0.0);
128 if (mom_.isFluid(
i)) {
129 double term = rho_ * advectHO(
c,
i);
131 term -= mom_.fouApply(
i, u_[
c]);
132 adv[
c][
static_cast<std::size_t
>(
i)] =
term;
138 for (
int c = 0;
c < 3; ++
c) {
139 std::vector<double>
src(
static_cast<std::size_t
>(n), 0.0);
141 if (mom_.isFluid(
i)) {
143 double s = (rho_ / dt_) * u_[
c][
static_cast<std::size_t
>(
i)] + f_[
c] - gradOf(p_,
i,
c);
145 s -=
adv[
c][
static_cast<std::size_t
>(
i)];
146 src[
static_cast<std::size_t
>(
i)] =
s;
148 std::vector<double> b = mom_.makeRhs(
src, 0.0);
157 const Index n = t_->numLeaves();
158 std::vector<double>
div(
static_cast<std::size_t
>(n), 0.0);
163 std::fill(phi_.begin(), phi_.end(), 0.0);
170 presMG_.vcycle(0, phi_,
div);
175 for (
int c = 0;
c < 3; ++
c)
178 u_[
c][
static_cast<std::size_t
>(
i)] -= gradOf(phi_,
i,
c);
185 p_[
static_cast<std::size_t
>(
i)] += (rho_ / dt_) * phi_[
static_cast<std::size_t
>(
i)] -
186 mu_ *
div[
static_cast<std::size_t
>(
i)];
195 double ui =
vel[axis][
static_cast<std::size_t
>(
i)];
196 double uj =
vel[axis][
static_cast<std::size_t
>(
j)];
197 d += alpha *
area * dir * 0.5 * (
ui +
uj);
202 double divNormL2(
const std::array<std::vector<double>, 3>&
vel)
const {
204 const Index n = t_->numLeaves();
206 if (mom_.isFluid(
i)) {
222 const Index n = t_->numLeaves();
224 Index s = faceStart_[
static_cast<std::size_t
>(
i)];
227 0.5 * (u_[axis][
static_cast<std::size_t
>(
i)] + u_[axis][
static_cast<std::size_t
>(
j)]);
231 ? (phi_[
static_cast<std::size_t
>(
j)] - phi_[
static_cast<std::size_t
>(
i)]) / dist
232 : (phi_[
static_cast<std::size_t
>(
i)] - phi_[
static_cast<std::size_t
>(
j)]) / dist;
233 uf_[
static_cast<std::size_t
>(
s++)] =
uface -
gphi;
236 faceFieldBuilt_ =
true;
244 const Index n = t_->numLeaves();
246 if (!mom_.isFluid(
i))
248 Index s = faceStart_[
static_cast<std::size_t
>(
i)];
251 d += alpha *
area * dir * uf_[
static_cast<std::size_t
>(
s++)];
256 return std::sqrt(
tot);
261 const std::vector<double>&
faceField()
const {
return uf_; }
262 const std::vector<Index>&
faceStart()
const {
return faceStart_; }
266 static double koren(
double up_m1,
double up,
double down,
double vel) {
268 double r = (std::fabs(
den) < 1
e-10) ? 0.0 :
num /
den;
269 double psi = std::fmax(0.0, std::fmin(2.0 *
r, std::fmin((1.0 + 2.0 *
r) / 3.0, 2.0)));
272 static double tvd(
double LL,
double L,
double R,
double RR,
double vel) {
276 double hoFace(
double upup,
double up,
double down)
const {
289 Index s = faceFieldBuilt_ ? faceStart_[
static_cast<std::size_t
>(
i)] : 0;
296 const double uface = faceFieldBuilt_ ? uf_[
static_cast<std::size_t
>(
s)]
300 if (!mom_.isFluid(
j))
306 double phiUp = u_[
comp][
static_cast<std::size_t
>(
up)];
322 double gradOf(
const std::vector<double>&
fld,
Index i,
int c)
const {
323 const double pi =
fld[
static_cast<std::size_t
>(
i)];
324 double gp = 0,
gm = 0;
329 if (axis !=
c || alpha <= 1
e-12)
331 double g = (dir > 0) ? (
fld[
static_cast<std::size_t
>(
j)] -
pi) / dist
351 template <
class SdfFn>
357 for (
int d = 0; d < 3; ++d) {
363 double gmag = std::sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2]);
366 int t1 = (axis + 1) % 3,
t2 = (axis + 2) % 3;
367 double denom = (std::fabs(g[t1]) + std::fabs(g[
t2])) /
gmag * h0_;
374 const Octree* t_ =
nullptr;
377 double rho_ = 1.0, mu_ = 1.0, dt_ = 1
e6;
378 bool advect_ =
false;
379 bool implicitFou_ =
true;
383 AmrPoisson<3, Bits> pres_;
385 std::array<std::vector<double>, 3> u_;
386 std::vector<double> phi_;
387 std::vector<double> p_;
394 std::vector<Index> faceStart_;
395 std::vector<double> uf_;
396 bool faceFieldBuilt_ =
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 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
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
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 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 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 >{})
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)
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).
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::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).