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 extResolve_ =
nullptr;
94 for (
int d = 0; d < 3; ++d)
95 fineExt_[d] =
static_cast<Coord>(
t.brick()[d] * (
Index(1) <<
t.lmax()));
107 void setGhosts(std::vector<std::array<long, 3>>
lo, std::vector<unsigned>
lv) {
108 ghostLo_ = std::move(
lo);
109 ghostLv_ = std::move(
lv);
119 bool isCut(
Index i)
const {
return cut_[
static_cast<std::size_t
>(
i)] != 0; }
122 double kappa(
Index i)
const {
return kappa_[
static_cast<std::size_t
>(
i)]; }
134 const std::vector<Index>&
nbRaw()
const {
return nb_; }
135 const std::vector<char>&
fluidRaw()
const {
return fluid_; }
136 const std::vector<char>&
cutRaw()
const {
return cut_; }
137 const std::vector<double>&
acRaw()
const {
return AC_; }
138 const std::vector<double>&
offRaw()
const {
return off_; }
139 const std::vector<double>&
rscaleRaw()
const {
return rscale_; }
140 double idiag()
const {
return idiag_; }
141 double mu()
const {
return mu_; }
142 double beta()
const {
return mu_ / (h0_ * h0_); }
144 const std::vector<double>&
advDiagRaw()
const {
return advDiag_; }
145 const std::vector<double>&
advCoefRaw()
const {
return advCoef_; }
146 const std::vector<Index>&
advStartRaw()
const {
return advStart_; }
147 const std::vector<Index>&
advNbrRaw()
const {
return advNbr_; }
152 template <
class SdfFn>
166 mu_ =
beta * h0_ * h0_;
167 sdfC_.assign(
static_cast<std::size_t
>(n +
ng), 0.0);
168 kappa_.assign(
static_cast<std::size_t
>(n), 0.0);
169 fluid_.assign(
static_cast<std::size_t
>(n +
ng),
false);
170 cut_.assign(
static_cast<std::size_t
>(n), 0);
172 AC_.assign(
static_cast<std::size_t
>(n), 1.0);
173 rscale_.assign(
static_cast<std::size_t
>(n), 1.0);
174 inhom_.assign(
static_cast<std::size_t
>(n), 0.0);
175 off_.assign(
static_cast<std::size_t
>(n) * 6, 0.0);
176 nb_.assign(
static_cast<std::size_t
>(n) * 6, -1);
182 sdfC_[
static_cast<std::size_t
>(
i)] =
sc;
183 fluid_[
static_cast<std::size_t
>(
i)] =
sc > 0.0;
184 kappa_[
static_cast<std::size_t
>(
i)] = volumeFraction(
i,
sdfFn,
nsub);
185 for (
int k = 0; k < 6; ++k)
186 nb_[
static_cast<std::size_t
>(
i) * 6 + k] = neighbor(
i, k);
191 for (
Index g = 0; g <
ng; ++g) {
192 const auto&
lo = ghostLo_[
static_cast<std::size_t
>(g)];
193 const double s =
static_cast<double>(1L << ghostLv_[
static_cast<std::size_t
>(g)]);
195 for (
int d = 0; d < 3; ++d)
196 c[d] = origin_[d] + (
static_cast<double>(
lo[d] + frameShift_[d]) + 0.5 *
s) * h0_;
198 sdfC_[
static_cast<std::size_t
>(n + g)] =
sc;
199 fluid_[
static_cast<std::size_t
>(n + g)] =
sc > 0.0;
205 if (!fluid_[
static_cast<std::size_t
>(
i)]) {
206 AC_[
static_cast<std::size_t
>(
i)] = 1.0;
207 for (
int k = 0; k < 6; ++k)
208 off_[
static_cast<std::size_t
>(
i) * 6 + k] = 0.0;
213 for (
int k = 0; k < 6; ++k) {
214 Index j = nb_[
static_cast<std::size_t
>(
i) * 6 + k];
215 sdf_n[k] = (
j >= 0) ? sdfC_[
static_cast<std::size_t
>(
j)] : -1.0;
219 cut_[
static_cast<std::size_t
>(
i)] =
anyGhost ? 1 : 0;
220 double AC =
AC0, off[6];
221 for (
int k = 0; k < 6; ++k)
227 AC_[
static_cast<std::size_t
>(
i)] = AC;
228 for (
int k = 0; k < 6; ++k)
229 off_[
static_cast<std::size_t
>(
i) * 6 + k] = off[k];
230 rscale_[
static_cast<std::size_t
>(
i)] = rscale;
231 inhom_[
static_cast<std::size_t
>(
i)] =
inhomCoef;
260 A.
diag.assign(
static_cast<std::size_t
>(n), 0.0);
261 A.
start.assign(
static_cast<std::size_t
>(n) + 1, 0);
262 std::vector<std::vector<std::pair<Index, double>>>
rows(
static_cast<std::size_t
>(n));
264 const std::size_t
s =
static_cast<std::size_t
>(
i);
271 for (
int k = 0; k < 6; ++k) {
272 double a = off_[
s * 6 + k];
291 for (std::size_t p =
static_cast<std::size_t
>(advStart_[
s]);
297 A.
start[
static_cast<std::size_t
>(
i) + 1] =
298 A.
start[
static_cast<std::size_t
>(
i)] +
299 static_cast<Index>(
rows[
static_cast<std::size_t
>(
i)].size());
301 A.
nbr.resize(
static_cast<std::size_t
>(
nnz));
302 A.
coef.resize(
static_cast<std::size_t
>(
nnz));
305 for (
auto&
e :
rows[
static_cast<std::size_t
>(
i)]) {
306 A.
nbr[
static_cast<std::size_t
>(k)] =
e.first;
307 A.
coef[
static_cast<std::size_t
>(k)] =
e.second;
333 void applyOp(
const std::vector<double>&
u, std::vector<double>&
out)
const {
335 const auto op =
hostOp(A);
337 out.assign(
static_cast<std::size_t
>(n), 0.0);
343 double residual(
const std::vector<double>&
u,
const std::vector<double>& b,
344 std::vector<double>& res)
const {
346 const auto op =
hostOp(A);
348 res.assign(
static_cast<std::size_t
>(n), 0.0);
353 res[
static_cast<std::size_t
>(
i)] =
r;
354 if (fluid_[
static_cast<std::size_t
>(
i)])
365 const auto op =
hostOp(A);
373 u[
static_cast<std::size_t
>(
i)], 1.0);
385 out.assign(
static_cast<std::size_t
>(n), 0.0);
386 std::vector<double>
Lu;
389 const std::size_t
s =
static_cast<std::size_t
>(
i);
392 }
else if (cut_[
s]) {
393 double acc = AC_[
s] *
u[
s];
394 for (
int k = 0; k < 6; ++k) {
395 double a = off_[
s * 6 + k];
400 acc +=
a *
u[
static_cast<std::size_t
>(
j)];
406 if (hasAdv_ && fluid_[
s])
424 const std::vector<double>&
uf,
const std::vector<Index>& faceStart,
427 advDiag_.assign(
static_cast<std::size_t
>(n), 0.0);
428 advStart_.assign(
static_cast<std::size_t
>(n) + 1, 0);
431 return useFace ? dir *
uf[
static_cast<std::size_t
>(slot)]
433 (
uadv[axis][
static_cast<std::size_t
>(
i)] +
434 uadv[axis][
static_cast<std::size_t
>(
j)]);
438 if (!fluid_[
static_cast<std::size_t
>(
i)])
443 if (fluid_[
static_cast<std::size_t
>(
j)] &&
velOutOf(
i,
j, axis, dir,
s) < 0.0)
447 advStart_[
static_cast<std::size_t
>(
i) + 1] =
cnt;
450 advStart_[
static_cast<std::size_t
>(
i) + 1] += advStart_[
static_cast<std::size_t
>(
i)];
451 advNbr_.assign(advStart_[
static_cast<std::size_t
>(n)], -1);
452 advCoef_.assign(advStart_[
static_cast<std::size_t
>(n)], 0.0);
455 if (!fluid_[
static_cast<std::size_t
>(
i)])
458 std::size_t
pos =
static_cast<std::size_t
>(advStart_[
static_cast<std::size_t
>(
i)]);
462 if (!fluid_[
static_cast<std::size_t
>(
j)])
471 advDiag_[
static_cast<std::size_t
>(
i)] += w;
481 std::vector<double> b(
static_cast<std::size_t
>(n), 0.0);
483 if (!fluid_[
static_cast<std::size_t
>(
i)]) {
484 b[
static_cast<std::size_t
>(
i)] =
u_bc;
487 b[
static_cast<std::size_t
>(
i)] =
488 src[
static_cast<std::size_t
>(
i)] * rscale_[
static_cast<std::size_t
>(
i)] +
489 inhom_[
static_cast<std::size_t
>(
i)] *
u_bc;
495 std::vector<double>& res)
const {
500 double r = b[
static_cast<std::size_t
>(
i)] - res[
static_cast<std::size_t
>(
i)];
501 res[
static_cast<std::size_t
>(
i)] =
r;
502 if (fluid_[
static_cast<std::size_t
>(
i)])
513 const std::size_t
si =
static_cast<std::size_t
>(
i);
516 }
else if (cut_[
si]) {
518 for (
int k = 0; k < 6; ++k) {
519 double a = off_[
si * 6 + k];
524 sum -=
a *
u[
static_cast<std::size_t
>(
j)];
528 sum -= advOffSum(
i,
u);
536 offsum +=
c *
u[
static_cast<std::size_t
>(
j)];
543 sum -= advOffSum(
i,
u);
556 return advDiag_[
static_cast<std::size_t
>(
i)] * field[
static_cast<std::size_t
>(
i)] +
563 double advOffSum(
Index i,
const std::vector<double>& field)
const {
565 for (std::size_t p =
static_cast<std::size_t
>(advStart_[
static_cast<std::size_t
>(
i)]);
567 s += advCoef_[p] * field[
static_cast<std::size_t
>(advNbr_[p])];
570 double advApply(
Index i,
const std::vector<double>&
u)
const {
return fouApply(
i,
u); }
580 for (
int k = 0; k < 6; ++k) {
581 if (
sdf_n[k] < 0.0) {
584 th = th < 1
e-4 ? 1
e-4 : (th > 1.0 ? 1.0 : th);
593 bool sand[3] = {ghost[0] && ghost[1], ghost[2] && ghost[3], ghost[4] && ghost[5]};
594 double Dsand[3] = {0, 0, 0};
595 for (
int a = 0;
a < 3; ++
a)
599 auto upd = [&](
double v) {
605 for (
int a = 0;
a < 3; ++
a) {
611 if (ghost[2 *
a + 1])
615 double K[6] = {0},
Mf[6] = {1, 1, 1, 1, 1, 1},
X[6] = {0},
Nbc[6] = {0},
616 R[6] = {1, 1, 1, 1, 1, 1};
617 for (
int a = 0;
a < 3; ++
a) {
618 int km = 2 *
a + 1,
kp = 2 *
a;
649 constexpr int OPP_[6] = {1, 0, 3, 2, 5, 4};
651 for (
int k = 0; k < 6; ++k) {
659 for (
int k = 0; k < 6; ++k)
668 double s =
static_cast<double>(
Index(1) << t_->
level(
i));
670 for (
int d = 0; d < 3; ++d)
672 (
static_cast<double>(
static_cast<long>(b[0][d]) + frameShift_[d]) + 0.5 *
s) * h0_;
676 template <
class SdfFn>
679 double s =
static_cast<double>(
Index(1) << t_->
level(
i));
683 for (
int d = 0; d < 3; ++d)
685 origin_[d] +
static_cast<double>(
static_cast<long>(b[0][d]) + frameShift_[d]) * h0_;
690 base[2] + (
cc2 + 0.5) /
nsub * w};
704 const Octree* t_ =
nullptr;
707 std::array<Coord, 3> fineExt_{};
709 std::vector<std::array<long, 3>> ghostLo_;
710 std::vector<unsigned> ghostLv_;
711 std::array<long, 3> frameShift_{};
712 std::vector<double> sdfC_, kappa_, AC_, rscale_, inhom_, off_;
713 std::vector<Index> nb_;
714 std::vector<char> fluid_, cut_;
715 AmrPoisson<3, Bits> lap_;
716 double idiag_ = 0.0, mu_ = 1.0;
717 std::vector<double> advDiag_, advCoef_;
718 std::vector<Index> advStart_, advNbr_;
719 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 setResolver(ExtResolver r)
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
typename AmrPoisson< 3, Bits >::ExtResolver ExtResolver
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...
void setGhosts(std::vector< std::array< long, 3 > > lo, std::vector< unsigned > lv)
Ghost slots [n, n+nGhost): block-local lo (longs) + covering-leaf level.
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
void setFrameShift(const std::array< long, 3 > &s)
const std::vector< double > & offRaw() const
n·6 ξ-overlay off-diagonals
static constexpr int OPP[6]
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...
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...
std::function< Index(const std::array< long, Dim > &)> ExtResolver
Route probes that exit the block through an external resolver (the LeafHalo registry): fn(blockLocalP...
void setFrameShift(const std::array< long, Dim > &s)
Distributed frame shift: this block's global fine origin.
void init(const Octree &t, Real h0)
Index periodicNeighbor(Index i, int axis, int dir) const
Periodic face neighbour leaf (covering the cell just across the face).
void setResolver(ExtResolver r)
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
Per-block adaptive octree over block-local Morton codes.
morton::Morton< Dim, Bits > M
typename M::coord_type Coord
unsigned level(Index i) const
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...
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,...
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.
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).
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
A backend-agnostic view of an assembled face-CSR operator.
A uniform accessor over a raw host array, giving it the operator()(i) that Kokkos::View has,...