18#ifndef PECLET_CORE_AMR_CUT_CELL_HPP
19#define PECLET_CORE_AMR_CUT_CELL_HPP
21#ifdef PECLET_CORE_HAVE_MORTON
46 return x < 0.0 ? -x : x;
49 return xi * (1.0 +
xi);
52 return xi * (1.0 -
xi);
55 return 2.0 * (
xi *
xi - 1.0);
64 return (
xm + 1.0) * (
xp - 1.0);
67 return (
xm / (
xm +
xp)) * (1.0 +
xm);
70 return (
xp / (
xm +
xp)) * (1.0 -
xp);
74template <
unsigned Bits = 21u>
77 static constexpr int Dim = 3;
84 static constexpr int OPP[6] = {1, 0, 3, 2, 5, 4};
90 for (
int d = 0; d < 3; ++d)
91 fineExt_[d] =
static_cast<Coord>(
t.brick()[d] * (
Index(1) <<
t.lmax()));
99 bool isCut(
Index i)
const {
return cut_[
static_cast<std::size_t
>(
i)] != 0; }
102 double kappa(
Index i)
const {
return kappa_[
static_cast<std::size_t
>(
i)]; }
114 const std::vector<Index>&
nbRaw()
const {
return nb_; }
115 const std::vector<char>&
fluidRaw()
const {
return fluid_; }
116 const std::vector<char>&
cutRaw()
const {
return cut_; }
117 const std::vector<double>&
acRaw()
const {
return AC_; }
118 const std::vector<double>&
offRaw()
const {
return off_; }
119 const std::vector<double>&
rscaleRaw()
const {
return rscale_; }
120 double idiag()
const {
return idiag_; }
121 double mu()
const {
return mu_; }
122 double beta()
const {
return mu_ / (h0_ * h0_); }
124 const std::vector<double>&
advDiagRaw()
const {
return advDiag_; }
125 const std::vector<double>&
advCoefRaw()
const {
return advCoef_; }
126 const std::vector<Index>&
advStartRaw()
const {
return advStart_; }
127 const std::vector<Index>&
advNbrRaw()
const {
return advNbr_; }
132 template <
class SdfFn>
140 mu_ =
beta * h0_ * h0_;
141 sdfC_.assign(
static_cast<std::size_t
>(n), 0.0);
142 kappa_.assign(
static_cast<std::size_t
>(n), 0.0);
143 fluid_.assign(
static_cast<std::size_t
>(n),
false);
144 cut_.assign(
static_cast<std::size_t
>(n), 0);
146 AC_.assign(
static_cast<std::size_t
>(n), 1.0);
147 rscale_.assign(
static_cast<std::size_t
>(n), 1.0);
148 inhom_.assign(
static_cast<std::size_t
>(n), 0.0);
149 off_.assign(
static_cast<std::size_t
>(n) * 6, 0.0);
150 nb_.assign(
static_cast<std::size_t
>(n) * 6, -1);
156 sdfC_[
static_cast<std::size_t
>(
i)] =
sc;
157 fluid_[
static_cast<std::size_t
>(
i)] =
sc > 0.0;
158 kappa_[
static_cast<std::size_t
>(
i)] = volumeFraction(
i,
sdfFn,
nsub);
159 for (
int k = 0; k < 6; ++k)
160 nb_[
static_cast<std::size_t
>(
i) * 6 + k] = neighbor(
i, k);
166 if (!fluid_[
static_cast<std::size_t
>(
i)]) {
167 AC_[
static_cast<std::size_t
>(
i)] = 1.0;
168 for (
int k = 0; k < 6; ++k)
169 off_[
static_cast<std::size_t
>(
i) * 6 + k] = 0.0;
174 for (
int k = 0; k < 6; ++k) {
175 Index j = nb_[
static_cast<std::size_t
>(
i) * 6 + k];
176 sdf_n[k] = (
j >= 0) ? sdfC_[
static_cast<std::size_t
>(
j)] : -1.0;
180 cut_[
static_cast<std::size_t
>(
i)] =
anyGhost ? 1 : 0;
181 double AC =
AC0, off[6];
182 for (
int k = 0; k < 6; ++k)
188 AC_[
static_cast<std::size_t
>(
i)] = AC;
189 for (
int k = 0; k < 6; ++k)
190 off_[
static_cast<std::size_t
>(
i) * 6 + k] = off[k];
191 rscale_[
static_cast<std::size_t
>(
i)] = rscale;
192 inhom_[
static_cast<std::size_t
>(
i)] =
inhomCoef;
221 A.
diag.assign(
static_cast<std::size_t
>(n), 0.0);
222 A.
start.assign(
static_cast<std::size_t
>(n) + 1, 0);
223 std::vector<std::vector<std::pair<Index, double>>>
rows(
static_cast<std::size_t
>(n));
225 const std::size_t
s =
static_cast<std::size_t
>(
i);
232 for (
int k = 0; k < 6; ++k) {
233 double a = off_[
s * 6 + k];
252 for (std::size_t p =
static_cast<std::size_t
>(advStart_[
s]);
258 A.
start[
static_cast<std::size_t
>(
i) + 1] =
259 A.
start[
static_cast<std::size_t
>(
i)] +
260 static_cast<Index>(
rows[
static_cast<std::size_t
>(
i)].size());
262 A.
nbr.resize(
static_cast<std::size_t
>(
nnz));
263 A.
coef.resize(
static_cast<std::size_t
>(
nnz));
266 for (
auto&
e :
rows[
static_cast<std::size_t
>(
i)]) {
267 A.
nbr[
static_cast<std::size_t
>(k)] =
e.first;
268 A.
coef[
static_cast<std::size_t
>(k)] =
e.second;
294 void applyOp(
const std::vector<double>&
u, std::vector<double>&
out)
const {
296 const auto op =
hostOp(A);
298 out.assign(
static_cast<std::size_t
>(n), 0.0);
304 double residual(
const std::vector<double>&
u,
const std::vector<double>& b,
305 std::vector<double>& res)
const {
307 const auto op =
hostOp(A);
309 res.assign(
static_cast<std::size_t
>(n), 0.0);
314 res[
static_cast<std::size_t
>(
i)] =
r;
315 if (fluid_[
static_cast<std::size_t
>(
i)])
326 const auto op =
hostOp(A);
334 u[
static_cast<std::size_t
>(
i)], 1.0);
346 out.assign(
static_cast<std::size_t
>(n), 0.0);
347 std::vector<double>
Lu;
350 const std::size_t
s =
static_cast<std::size_t
>(
i);
353 }
else if (cut_[
s]) {
354 double acc = AC_[
s] *
u[
s];
355 for (
int k = 0; k < 6; ++k) {
356 double a = off_[
s * 6 + k];
361 acc +=
a *
u[
static_cast<std::size_t
>(
j)];
367 if (hasAdv_ && fluid_[
s])
385 const std::vector<double>&
uf,
const std::vector<Index>& faceStart,
388 advDiag_.assign(
static_cast<std::size_t
>(n), 0.0);
389 advStart_.assign(
static_cast<std::size_t
>(n) + 1, 0);
394 (
uadv[axis][
static_cast<std::size_t
>(
i)] +
395 uadv[axis][
static_cast<std::size_t
>(
j)]);
399 if (!fluid_[
static_cast<std::size_t
>(
i)])
404 if (fluid_[
static_cast<std::size_t
>(
j)] &&
velOutOf(
i,
j, axis, dir,
s) < 0.0)
408 advStart_[
static_cast<std::size_t
>(
i) + 1] =
cnt;
411 advStart_[
static_cast<std::size_t
>(
i) + 1] += advStart_[
static_cast<std::size_t
>(
i)];
412 advNbr_.assign(advStart_[
static_cast<std::size_t
>(n)], -1);
413 advCoef_.assign(advStart_[
static_cast<std::size_t
>(n)], 0.0);
416 if (!fluid_[
static_cast<std::size_t
>(
i)])
419 std::size_t
pos =
static_cast<std::size_t
>(advStart_[
static_cast<std::size_t
>(
i)]);
423 if (!fluid_[
static_cast<std::size_t
>(
j)])
432 advDiag_[
static_cast<std::size_t
>(
i)] +=
w;
442 std::vector<double> b(
static_cast<std::size_t
>(n), 0.0);
444 if (!fluid_[
static_cast<std::size_t
>(
i)]) {
445 b[
static_cast<std::size_t
>(
i)] =
u_bc;
448 b[
static_cast<std::size_t
>(
i)] =
449 src[
static_cast<std::size_t
>(
i)] * rscale_[
static_cast<std::size_t
>(
i)] +
450 inhom_[
static_cast<std::size_t
>(
i)] *
u_bc;
456 std::vector<double>& res)
const {
461 double r = b[
static_cast<std::size_t
>(
i)] - res[
static_cast<std::size_t
>(
i)];
462 res[
static_cast<std::size_t
>(
i)] =
r;
463 if (fluid_[
static_cast<std::size_t
>(
i)])
474 const std::size_t
si =
static_cast<std::size_t
>(
i);
477 }
else if (cut_[
si]) {
479 for (
int k = 0; k < 6; ++k) {
480 double a = off_[
si * 6 + k];
485 sum -=
a *
u[
static_cast<std::size_t
>(
j)];
489 sum -= advOffSum(
i,
u);
497 offsum +=
c *
u[
static_cast<std::size_t
>(
j)];
504 sum -= advOffSum(
i,
u);
517 return advDiag_[
static_cast<std::size_t
>(
i)] * field[
static_cast<std::size_t
>(
i)] +
524 double advOffSum(
Index i,
const std::vector<double>& field)
const {
526 for (std::size_t p =
static_cast<std::size_t
>(advStart_[
static_cast<std::size_t
>(
i)]);
528 s += advCoef_[p] * field[
static_cast<std::size_t
>(advNbr_[p])];
531 double advApply(
Index i,
const std::vector<double>&
u)
const {
return fouApply(
i,
u); }
541 for (
int k = 0; k < 6; ++k) {
542 if (
sdf_n[k] < 0.0) {
545 th =
th < 1
e-4 ? 1
e-4 : (
th > 1.0 ? 1.0 :
th);
554 bool sand[3] = {ghost[0] && ghost[1], ghost[2] && ghost[3], ghost[4] && ghost[5]};
555 double Dsand[3] = {0, 0, 0};
556 for (
int a = 0;
a < 3; ++
a)
560 auto upd = [&](
double v) {
566 for (
int a = 0;
a < 3; ++
a) {
572 if (ghost[2 *
a + 1])
576 double K[6] = {0},
Mf[6] = {1, 1, 1, 1, 1, 1},
X[6] = {0},
Nbc[6] = {0},
577 R[6] = {1, 1, 1, 1, 1, 1};
578 for (
int a = 0;
a < 3; ++
a) {
579 int km = 2 *
a + 1,
kp = 2 *
a;
610 constexpr int OPP_[6] = {1, 0, 3, 2, 5, 4};
612 for (
int k = 0; k < 6; ++k) {
620 for (
int k = 0; k < 6; ++k)
629 double s =
static_cast<double>(
Index(1) << t_->
level(
i));
631 for (
int d = 0; d < 3; ++d)
632 c[d] = origin_[d] + (
static_cast<double>(b[0][d]) + 0.5 *
s) * h0_;
636 template <
class SdfFn>
639 double s =
static_cast<double>(
Index(1) << t_->
level(
i));
645 Vec<3> p{origin_[0] +
static_cast<double>(b[0][0]) * h0_ + (
a + 0.5) /
nsub *
w,
646 origin_[1] +
static_cast<double>(b[0][1]) * h0_ + (
bb + 0.5) /
nsub *
w,
647 origin_[2] +
static_cast<double>(b[0][2]) * h0_ + (
cc2 + 0.5) /
nsub *
w};
655 int axis = k / 2, dir = (k % 2 == 0) ? +1 : -1;
657 const auto&
lo = b[0];
659 long pc = (dir > 0) ?
static_cast<long>(
lo[axis]) +
static_cast<long>(
si)
661 long e =
static_cast<long>(fineExt_[axis]);
662 std::array<Coord, 3> p =
lo;
663 p[axis] =
static_cast<Coord>(((
pc %
e) +
e) %
e);
664 return t_->
find(M::encode(p).code());
667 const Octree* t_ =
nullptr;
670 std::array<Coord, 3> fineExt_{};
671 std::vector<double> sdfC_, kappa_, AC_, rscale_, inhom_, off_;
672 std::vector<Index> nb_;
673 std::vector<char> fluid_, cut_;
674 AmrPoisson<3, Bits> lap_;
675 double idiag_ = 0.0, mu_ = 1.0;
676 std::vector<double> advDiag_, advCoef_;
677 std::vector<Index> advStart_, advNbr_;
678 bool hasAdv_ =
false;
double kappa(Index i) const
double fouApply(Index i, const std::vector< double > &field) const
The implicit-FOU advection operator applied to field at leaf i: advDiag·field_i + Σ_csr coef·field_nb...
const std::vector< Index > & nbRaw() const
n·6 periodic face-neighbour indices
const std::vector< double > & advCoefRaw() const
void applyOp(const std::vector< double > &u, std::vector< double > &out) const
out = A u, via the shared kernel over the assembled CSR (== device applyMom arithmetic).
void gaussSeidelGeometric(std::vector< double > &u, const std::vector< double > &b, int sweeps) const
double rhsScale(Index i) const
const std::vector< double > & acRaw() const
void init(const Octree &t, Real h0, Vec< 3 > origin=Vec< 3 >{})
const std::vector< double > & rscaleRaw() const
double residualGeometric(const std::vector< double > &u, const std::vector< double > &b, std::vector< double > &res) const
bool hasAdvection() const
const std::vector< double > & sdfCRaw() const
per-cell SDF sample (build Pass 1)
FaceCsrOpT< HostArr< double >, HostArr< Index > > hostOp(const Assembled &A) const
View a host Assembled as a backend-agnostic FaceCsrOpT for the shared row kernels.
const std::vector< double > & advDiagRaw() const
void gaussSeidel(std::vector< double > &u, const std::vector< double > &b, int sweeps) const
sweeps true serial Gauss–Seidel sweeps (ω=1, in place) over the assembled CSR using the shared point-...
double residual(const std::vector< double > &u, const std::vector< double > &b, std::vector< double > &res) const
const std::vector< char > & cutRaw() const
Assembled assembleOperator(bool scaleAdvByRscale=false) const
scaleAdvByRscale (default false ⇒ reproduces applyOp/gaussSeidel exactly, for the matvec test): when ...
void buildAdvectionFou(const std::array< std::vector< double >, 3 > &uadv, double rho, const std::vector< double > &uf, const std::vector< Index > &faceStart, bool useFace)
Build the implicit first-order-upwind advection operator from a (lagged) advecting velocity field uad...
const std::vector< Index > & advNbrRaw() const
typename Octree::Coord Coord
std::vector< double > makeRhs(const std::vector< double > &src, double u_bc) const
Effective RHS for source src (≈ -h^2 f at cell centres) and wall value u_bc: row-scaled by D_rescale ...
void applyOpGeometric(const std::vector< double > &u, std::vector< double > &out) const
Geometric operator apply (walks the octree live) — the INDEPENDENT reference encoding,...
bool isFluid(Index i) const
BlockOctree< 3, Bits > Octree
double beta() const
buildCutStencil's β (= mu_/h0²)
static MORTON_HD void buildCutStencil(double sdf_c, const double sdf_n[6], double beta, double AC0, double &ACout, double off[6], double &rscaleOut, double &inhomOut)
Index neighborOf(Index i, int k) const
Periodic face neighbour of leaf i in direction k (0=+x,1=-x,2=+y,3=-y,4=+z,5=-z).
bool isCut(Index i) const
True for a cut cell: a fluid cell with at least one solid face neighbour (the row-scaled ξ-overlay ba...
const std::vector< Index > & advStartRaw() const
typename Octree::Code Code
void build(SdfFn &&sdfFn, double idiag=0.0, double beta=1.0, int nsub=4)
Build the cut-cell stencils from an SDF callable sdfFn(worldPoint) (>0 fluid, <0 solid).
const std::vector< char > & fluidRaw() const
const AmrPoisson< 3, Bits > & lap() const
α=1 C/F ∇² geometry for regular cells
const std::vector< double > & offRaw() const
n·6 ξ-overlay off-diagonals
static constexpr int OPP[6]
void forEachFaceNeighbor(Index i, Fn &&fn) const
Visit each face neighbour of leaf i: fn(neighbourSlot, coeff, axis, alpha) where coeff = A_f / d_f (p...
void init(const Octree &t, Real h0)
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,...
Real cellVolume(Index i) const
morton::Morton< Dim, Bits > M
typename M::coord_type Coord
unsigned level(Index i) const
Index find(Code p) const
Leaf containing Morton code p, or -1. Host wrapper over amrLocate.
typename M::code_type Code
std::array< std::array< Coord, Dim >, 2 > bounds(Index i) const
Inclusive integer bounds [lo, hi] of leaf i in fine units.
MORTON_HD double poly_Nc(double xi)
MORTON_HD double poly_N_nb(double xi)
MORTON_HD double poly_abs(double x)
MORTON_HD double poly_D_sandwich(double xm, double xp)
MORTON_HD double poly_N_c_sandwich(double xm, double xp)
MORTON_HD double poly_D(double xi)
MORTON_HD double poly_Nbc_mp_sw(double xm, double xp)
MORTON_HD double poly_Nbc(double)
MORTON_HD double poly_Nbc_pp_sw(double xm, double xp)
MORTON_HD void faceCsrOffDiag(const Op &op, Index i, const U &u, double &off, double &d)
Off-diagonal sum and the (advection-inclusive) diagonal for the point smoothers: out off = Σ coef·u[n...
MORTON_HD double faceCsrPointUpdate(double b_i, double off, double d, double uOld, double omega)
The damped point update used by both Jacobi and (multicolour) Gauss–Seidel: returns the new u_i given...
MORTON_HD double faceCsrApplyRow(const Op &op, Index i, const U &u)
(A u)_i — one assembled-operator row.
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).
The assembled linear operator A as a per-cell diagonal + face CSR: (A u)_i = diag[i]·u_i + Σ_{k∈[star...
std::vector< Index > start
CSR row offsets, size n+1.
std::vector< double > diag
size n
std::vector< double > coef
off-diagonal coefficient, size nnz
std::vector< Index > nbr
neighbour leaf per off-diagonal, size nnz