17#ifndef PECLET_AMR_CUT_CELL_HPP
18#define PECLET_AMR_CUT_CELL_HPP
30#include "peclet/core/common/host_parallel.hpp"
31#include "peclet/core/common/types.hpp"
32#include "peclet/core/scheme/cut_cell_closure.hpp"
48 return x < 0.0 ? -x : x;
51 return peclet::core::scheme::poly_D<double>(
xi);
54 return peclet::core::scheme::poly_N_nb<double>(
xi);
57 return peclet::core::scheme::poly_Nc<double>(
xi);
60 return peclet::core::scheme::poly_Nbc<double>(
xi);
63 return peclet::core::scheme::poly_D_sandwich<double>(
xm,
xp);
66 return peclet::core::scheme::poly_N_c_sandwich<double>(
xm,
xp);
69 return peclet::core::scheme::poly_Nbc_pp_sw<double>(
xm,
xp);
72 return peclet::core::scheme::poly_Nbc_mp_sw<double>(
xm,
xp);
76template <
unsigned Bits = 21u>
79 static constexpr int Dim = 3;
86 static constexpr int OPP[6] = {1, 0, 3, 2, 5, 4};
89 init(
t, detail::filledVec<3>(h0), origin);
95 extResolve_ =
nullptr;
99 for (
int d = 0; d < 3; ++d)
100 fineExt_[d] =
static_cast<Coord>(
t.brick()[d] * (
Index(1) <<
t.lmax()));
112 void setGhosts(std::vector<std::array<long, 3>>
lo, std::vector<unsigned>
lv) {
113 ghostLo_ = std::move(
lo);
114 ghostLv_ = std::move(
lv);
124 bool isCut(
Index i)
const {
return cut_[
static_cast<std::size_t
>(
i)] != 0; }
127 double kappa(
Index i)
const {
return kappa_[
static_cast<std::size_t
>(
i)]; }
139 const std::vector<Index>&
nbRaw()
const {
return nb_; }
140 const std::vector<char>&
fluidRaw()
const {
return fluid_; }
141 const std::vector<char>&
cutRaw()
const {
return cut_; }
142 const std::vector<double>&
acRaw()
const {
return AC_; }
143 const std::vector<double>&
offRaw()
const {
return off_; }
144 const std::vector<double>&
rscaleRaw()
const {
return rscale_; }
145 double idiag()
const {
return idiag_; }
146 double mu()
const {
return mu_; }
150 for (
int d = 0; d < 3; ++d)
151 b[d] = mu_ / (h0_[d] * h0_[d]);
155 const std::vector<double>&
advDiagRaw()
const {
return advDiag_; }
156 const std::vector<double>&
advCoefRaw()
const {
return advCoef_; }
157 const std::vector<Index>&
advStartRaw()
const {
return advStart_; }
158 const std::vector<Index>&
advNbrRaw()
const {
return advNbr_; }
163 template <
class SdfFn>
168 template <
class SdfFn>
183 mu_ =
beta[0] * h0_[0] * h0_[0];
184 sdfC_.assign(
static_cast<std::size_t
>(n +
ng), 0.0);
185 kappa_.assign(
static_cast<std::size_t
>(n), 0.0);
186 fluid_.assign(
static_cast<std::size_t
>(n +
ng),
false);
187 cut_.assign(
static_cast<std::size_t
>(n), 0);
189 AC_.assign(
static_cast<std::size_t
>(n), 1.0);
190 rscale_.assign(
static_cast<std::size_t
>(n), 1.0);
191 inhom_.assign(
static_cast<std::size_t
>(n), 0.0);
192 off_.assign(
static_cast<std::size_t
>(n) * 6, 0.0);
193 nb_.assign(
static_cast<std::size_t
>(n) * 6, -1);
212 sdfC_[
static_cast<std::size_t
>(
i)] =
sc;
213 fluid_[
static_cast<std::size_t
>(
i)] =
sc > 0.0;
214 kappa_[
static_cast<std::size_t
>(
i)] = volumeFraction(
i,
sdfFn,
nsub);
215 for (
int k = 0; k < 6; ++k)
216 nb_[
static_cast<std::size_t
>(
i) * 6 + k] = neighbor(
i, k);
221 for (
Index g = 0; g <
ng; ++g) {
222 const auto&
lo = ghostLo_[
static_cast<std::size_t
>(g)];
223 const double s =
static_cast<double>(1L << ghostLv_[
static_cast<std::size_t
>(g)]);
225 for (
int d = 0; d < 3; ++d)
226 c[d] = origin_[d] + (
static_cast<double>(
lo[d] + frameShift_[d]) + 0.5 *
s) * h0_[d];
228 sdfC_[
static_cast<std::size_t
>(n + g)] =
sc;
229 fluid_[
static_cast<std::size_t
>(n + g)] =
sc > 0.0;
254 const double f =
static_cast<double>(
Index(1) << t_->
level(
i));
255 const double inv = 1.0 / (
f *
f);
258 if (!fluid_[
static_cast<std::size_t
>(
i)]) {
259 AC_[
static_cast<std::size_t
>(
i)] = 1.0;
260 for (
int k = 0; k < 6; ++k)
261 off_[
static_cast<std::size_t
>(
i) * 6 + k] = 0.0;
266 for (
int k = 0; k < 6; ++k) {
267 Index j = nb_[
static_cast<std::size_t
>(
i) * 6 + k];
268 sdf_n[k] = (
j >= 0) ? sdfC_[
static_cast<std::size_t
>(
j)] : -1.0;
272 cut_[
static_cast<std::size_t
>(
i)] =
anyGhost ? 1 : 0;
273 double AC =
AC0, off[6];
274 for (
int k = 0; k < 6; ++k)
280 AC_[
static_cast<std::size_t
>(
i)] = AC;
281 for (
int k = 0; k < 6; ++k)
282 off_[
static_cast<std::size_t
>(
i) * 6 + k] = off[k];
283 rscale_[
static_cast<std::size_t
>(
i)] = rscale;
284 inhom_[
static_cast<std::size_t
>(
i)] =
inhomCoef;
313 A.
diag.assign(
static_cast<std::size_t
>(n), 0.0);
314 A.start.assign(
static_cast<std::size_t
>(n) + 1, 0);
315 std::vector<std::vector<std::pair<Index, double>>>
rows(
static_cast<std::size_t
>(n));
317 const std::size_t
s =
static_cast<std::size_t
>(
i);
324 for (
int k = 0; k < 6; ++k) {
325 double a = off_[
s * 6 + k];
343 A.diag[
s] +=
as * advDiag_[
s];
344 for (std::size_t
p =
static_cast<std::size_t
>(advStart_[
s]);
350 A.start[
static_cast<std::size_t
>(
i) + 1] =
351 A.start[
static_cast<std::size_t
>(
i)] +
352 static_cast<Index>(
rows[
static_cast<std::size_t
>(
i)].size());
353 const Index nnz =
A.start[
static_cast<std::size_t
>(n)];
354 A.nbr.resize(
static_cast<std::size_t
>(
nnz));
355 A.coef.resize(
static_cast<std::size_t
>(
nnz));
357 Index k =
A.start[
static_cast<std::size_t
>(
i)];
358 for (
auto&
e :
rows[
static_cast<std::size_t
>(
i)]) {
359 A.nbr[
static_cast<std::size_t
>(k)] =
e.first;
360 A.coef[
static_cast<std::size_t
>(k)] =
e.second;
386 void applyOp(
const std::vector<double>&
u, std::vector<double>&
out)
const {
390 out.assign(
static_cast<std::size_t
>(n), 0.0);
393 out[
static_cast<std::size_t
>(
i)] = faceCsrApplyRow(op,
i,
uacc);
396 double residual(
const std::vector<double>&
u,
const std::vector<double>& b,
397 std::vector<double>& res)
const {
401 res.assign(
static_cast<std::size_t
>(n), 0.0);
405 double r = b[
static_cast<std::size_t
>(
i)] - faceCsrApplyRow(op,
i,
uacc);
406 res[
static_cast<std::size_t
>(
i)] =
r;
407 if (fluid_[
static_cast<std::size_t
>(
i)])
424 faceCsrOffDiag(op,
i,
uacc, off, d);
425 u[
static_cast<std::size_t
>(
i)] = faceCsrPointUpdate(b[
static_cast<std::size_t
>(
i)], off, d,
426 u[
static_cast<std::size_t
>(
i)], 1.0);
438 out.assign(
static_cast<std::size_t
>(n), 0.0);
439 std::vector<double>
Lu;
442 const std::size_t
s =
static_cast<std::size_t
>(
i);
445 }
else if (cut_[
s]) {
446 double acc = AC_[
s] *
u[
s];
447 for (
int k = 0; k < 6; ++k) {
448 double a = off_[
s * 6 + k];
453 acc +=
a *
u[
static_cast<std::size_t
>(
j)];
459 if (hasAdv_ && fluid_[
s])
477 const std::vector<double>&
uf,
const std::vector<Index>& faceStart,
480 advDiag_.assign(
static_cast<std::size_t
>(n), 0.0);
481 advStart_.assign(
static_cast<std::size_t
>(n) + 1, 0);
484 return useFace ? dir *
uf[
static_cast<std::size_t
>(slot)]
486 (
uadv[axis][
static_cast<std::size_t
>(
i)] +
487 uadv[axis][
static_cast<std::size_t
>(
j)]);
491 if (!fluid_[
static_cast<std::size_t
>(
i)])
496 if (fluid_[
static_cast<std::size_t
>(
j)] &&
velOutOf(
i,
j, axis, dir,
s) < 0.0)
500 advStart_[
static_cast<std::size_t
>(
i) + 1] =
cnt;
503 advStart_[
static_cast<std::size_t
>(
i) + 1] += advStart_[
static_cast<std::size_t
>(
i)];
504 advNbr_.assign(advStart_[
static_cast<std::size_t
>(n)], -1);
505 advCoef_.assign(advStart_[
static_cast<std::size_t
>(n)], 0.0);
508 if (!fluid_[
static_cast<std::size_t
>(
i)])
511 std::size_t
pos =
static_cast<std::size_t
>(advStart_[
static_cast<std::size_t
>(
i)]);
515 if (!fluid_[
static_cast<std::size_t
>(
j)])
524 advDiag_[
static_cast<std::size_t
>(
i)] += w;
534 std::vector<double> b(
static_cast<std::size_t
>(n), 0.0);
536 if (!fluid_[
static_cast<std::size_t
>(
i)]) {
537 b[
static_cast<std::size_t
>(
i)] =
u_bc;
540 b[
static_cast<std::size_t
>(
i)] =
541 src[
static_cast<std::size_t
>(
i)] * rscale_[
static_cast<std::size_t
>(
i)] +
542 inhom_[
static_cast<std::size_t
>(
i)] *
u_bc;
548 std::vector<double>& res)
const {
553 double r = b[
static_cast<std::size_t
>(
i)] - res[
static_cast<std::size_t
>(
i)];
554 res[
static_cast<std::size_t
>(
i)] =
r;
555 if (fluid_[
static_cast<std::size_t
>(
i)])
566 const std::size_t
si =
static_cast<std::size_t
>(
i);
569 }
else if (cut_[
si]) {
571 for (
int k = 0; k < 6; ++k) {
572 double a = off_[
si * 6 + k];
577 sum -=
a *
u[
static_cast<std::size_t
>(
j)];
581 sum -= advOffSum(
i,
u);
589 offsum +=
c *
u[
static_cast<std::size_t
>(
j)];
596 sum -= advOffSum(
i,
u);
609 return advDiag_[
static_cast<std::size_t
>(
i)] * field[
static_cast<std::size_t
>(
i)] +
616 double advOffSum(
Index i,
const std::vector<double>& field)
const {
618 for (std::size_t
p =
static_cast<std::size_t
>(advStart_[
static_cast<std::size_t
>(
i)]);
620 s += advCoef_[
p] * field[
static_cast<std::size_t
>(advNbr_[
p])];
623 double advApply(
Index i,
const std::vector<double>&
u)
const {
return fouApply(
i,
u); }
635 for (
int k = 0; k < 6; ++k) {
636 if (
sdf_n[k] < 0.0) {
639 th = th < 1
e-4 ? 1
e-4 : (th > 1.0 ? 1.0 : th);
649 double Dsand[3] = {0, 0, 0};
650 for (
int a = 0;
a < 3; ++
a)
654 auto upd = [&](
double v) {
660 for (
int a = 0;
a < 3; ++
a) {
670 double K[6] = {0},
Mf[6] = {1, 1, 1, 1, 1, 1},
X[6] = {0},
Nbc[6] = {0},
671 R[6] = {1, 1, 1, 1, 1, 1};
672 for (
int a = 0;
a < 3; ++
a) {
673 int km = 2 *
a + 1,
kp = 2 *
a;
704 constexpr int OPP_[6] = {1, 0, 3, 2, 5, 4};
706 for (
int k = 0; k < 6; ++k) {
714 for (
int k = 0; k < 6; ++k)
715 off[k] = -
beta[k / 2] +
mod[k];
723 double s =
static_cast<double>(
Index(1) << t_->
level(
i));
725 for (
int d = 0; d < 3; ++d)
727 (
static_cast<double>(
static_cast<long>(b[0][d]) + frameShift_[d]) + 0.5 *
s) * h0_[d];
731 template <
class SdfFn>
734 double s =
static_cast<double>(
Index(1) << t_->
level(
i));
739 for (
int d = 0; d < 3; ++d) {
742 origin_[d] +
static_cast<double>(
static_cast<long>(b[0][d]) + frameShift_[d]) * h0_[d];
748 base[2] + (
cc2 + 0.5) /
nsub * w[2]};
762 const Octree* t_ =
nullptr;
763 Vec<3> h0_ = detail::filledVec<3>(1.0);
765 std::array<Coord, 3> fineExt_{};
767 std::vector<std::array<long, 3>> ghostLo_;
768 std::vector<unsigned> ghostLv_;
769 std::array<long, 3> frameShift_{};
770 std::vector<double> sdfC_, kappa_, AC_, rscale_, inhom_, off_;
771 std::vector<Index> nb_;
772 std::vector<char> fluid_, cut_;
773 AmrPoisson<3, Bits> lap_;
774 double idiag_ = 0.0, mu_ = 1.0;
775 std::vector<double> advDiag_, advCoef_;
776 std::vector<Index> advStart_, advNbr_;
777 bool hasAdv_ =
false;
const std::vector< double > & advCoefRaw() 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-...
FaceCsrOpT< HostArr< double >, HostArr< Index > > hostOp(const Assembled &A) const
View a host Assembled as a backend-agnostic FaceCsrOpT for the shared row kernels.
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 build(SdfFn &&sdfFn, double idiag=0.0, const Vec< 3 > &beta=detail::filledVec< 3 >(1.0), int nsub=4)
Phase 3: beta[a] = mu/h0_a² (the octree twin of the structured fold's beta_b).
const std::vector< double > & acRaw() const
double kappa(Index i) const
void applyOpGeometric(const std::vector< double > &u, std::vector< double > &out) const
Geometric operator apply (walks the octree live) — the INDEPENDENT reference encoding,...
void gaussSeidelGeometric(std::vector< double > &u, const std::vector< double > &b, int sweeps) 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< double > & advDiagRaw() const
const std::vector< char > & fluidRaw() const
void setFrameShift(const std::array< long, 3 > &s)
const std::vector< double > & offRaw() const
n·6 ξ-overlay off-diagonals
typename Octree::Code Code
const std::vector< Index > & nbRaw() const
n·6 periodic face-neighbour indices
void init(const Octree &t, Real h0, Vec< 3 > origin=Vec< 3 >{})
Assembled assembleOperator(bool scaleAdvByRscale=false) const
scaleAdvByRscale (default false ⇒ reproduces applyOp/gaussSeidel exactly, for the matvec test): when ...
bool hasAdvection() const
const std::vector< char > & cutRaw() const
const std::vector< Index > & advNbrRaw() const
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 AmrPoisson< 3, Bits > & lap() const
α=1 C/F ∇² geometry for regular cells
const std::vector< double > & sdfCRaw() const
per-cell SDF sample (build Pass 1)
void build(SdfFn &&sdfFn, double idiag, double beta, int nsub=4)
Build the cut-cell stencils from an SDF callable sdfFn(worldPoint) (>0 fluid, <0 solid).
void setResolver(ExtResolver r)
static void buildCutStencil(double sdf_c, const double sdf_n[6], const double beta[3], double AC0, double &ACout, double off[6], double &rscaleOut, double &inhomOut)
Phase 3: beta[3] — the viscous coefficient of each AXIS; face k uses beta[k/2].
BlockOctree< 3, Bits > Octree
const std::vector< Index > & advStartRaw() const
double residualGeometric(const std::vector< double > &u, const std::vector< double > &b, std::vector< double > &res) const
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...
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 ...
static constexpr int OPP[6]
bool isFluid(Index i) const
double rhsScale(Index i) const
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).
double residual(const std::vector< double > &u, const std::vector< double > &b, std::vector< double > &res) const
void init(const Octree &t, const Vec< 3 > &h0, Vec< 3 > origin=Vec< 3 >{})
Vec< 3 > beta() const
buildCutStencil's β PER AXIS (= mu_/h0_a²) — Phase 3, docs/amr_anisotropic.md §3/§4.
typename AmrPoisson< 3, Bits >::ExtResolver ExtResolver
const std::vector< double > & rscaleRaw() const
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...
typename Octree::Coord Coord
Cell-centered FV Poisson operator on one (periodic) block octree.
void setFrameShift(const std::array< long, Dim > &s)
Distributed frame shift: this block's global fine origin.
void forEachFaceFull(Index i, Fn &&fn) const
Like forEachFaceNeighbor but exposes geometry for a consistent FV divergence/gradient: fn(neighbour,...
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...
Index periodicNeighbor(Index i, int axis, int dir) const
Periodic face neighbour leaf (covering the cell just across the face).
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...
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 init(const Octree &t, Real h0)
Cubic-cell overload — the pre-Phase-3 spelling, and exactly the per-axis one with all three spacings ...
void applyLaplacian(const std::vector< double > &u, std::vector< double > &out) const
out = L u (periodic FV Laplacian).
void setResolver(ExtResolver r)
Real cellVolume(Index i) const
Per-block adaptive octree over block-local Morton codes.
morton::Morton< Dim, Bits > M
unsigned level(Index i) const
std::array< std::array< Coord, Dim >, 2 > bounds(Index i) const
Inclusive integer bounds [lo, hi] of leaf i in fine units.
typename M::coord_type Coord
typename M::code_type Code
double poly_Nbc_mp_sw(double xm, double xp)
double poly_Nbc(double xi)
double poly_D_sandwich(double xm, double xp)
double poly_Nbc_pp_sw(double xm, double xp)
double poly_abs(double x)
double poly_N_c_sandwich(double xm, double xp)
double poly_Nc(double xi)
double poly_N_nb(double xi)
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,...
The assembled linear operator A as a per-cell diagonal + face CSR: (A u)_i = diag[i]·u_i + Σ_{k∈[star...
std::vector< Index > nbr
neighbour leaf per off-diagonal, size nnz
std::vector< double > coef
off-diagonal coefficient, size nnz
std::vector< Index > start
CSR row offsets, size n+1.
std::vector< double > diag
size n