25#ifndef PECLET_CORE_AMR_GHOST_PROJECTION_SAMPLED_HPP
26#define PECLET_CORE_AMR_GHOST_PROJECTION_SAMPLED_HPP
28#ifdef PECLET_CORE_HAVE_MORTON
63 for (
int k = 0; k < n; ++k) {
65 for (
int r = k + 1;
r < n; ++
r)
66 if (std::fabs(A[
r * n + k]) > std::fabs(A[
piv * n + k]))
68 if (std::fabs(A[
piv * n + k]) < 1
e-14)
71 for (
int c = k;
c < n; ++
c) {
72 const double tmp = A[k * n +
c];
73 A[k * n +
c] = A[
piv * n +
c];
76 const double tb = b[k];
80 for (
int r = k + 1;
r < n; ++
r) {
81 const double f = A[
r * n + k] / A[k * n + k];
82 for (
int c = k;
c < n; ++
c)
83 A[
r * n +
c] -=
f * A[k * n +
c];
87 for (
int k = n - 1; k >= 0; --k) {
88 for (
int c = k + 1;
c < n; ++
c)
89 b[k] -= A[k * n +
c] * b[
c];
119template <
unsigned Bits,
class SdfFn>
126 std::array<long, 3>
q{};
127 for (
int d = 0; d < 3; ++d)
128 q[d] =
static_cast<long>(std::floor((
probe[d] - origin[d]) / h0));
131 return {
false, -1.0f};
132 auto b =
t.bounds(
j);
133 const double s =
static_cast<double>(
Index(1) <<
t.level(
j));
135 for (
int d = 0; d < 3; ++d)
136 c[d] = origin[d] + (
static_cast<double>(b[0][d]) + 0.5 *
s) * h0;
138 return {
sd > 0.0,
static_cast<float>(
sd)};
142 return (
flM &&
flP && 0.5f * (
sM +
sP) >= 0.0f) ? 1.0 : 0.0;
149template <
unsigned Bits,
class SdfFn>
154 GhostOverlaySampled ov;
155 const Index n =
t.numLeaves();
156 const double h0 =
pres.cellWidth(0) /
static_cast<double>(
Index(1) <<
t.level(0));
159 std::vector<Vec<3>>
cen(
static_cast<std::size_t
>(n));
160 std::vector<char> fluid(
static_cast<std::size_t
>(n));
162 auto b =
t.bounds(
i);
163 const double s =
static_cast<double>(
Index(1) <<
t.level(
i));
165 for (
int d = 0; d < 3; ++d)
166 c[d] = origin[d] + (
static_cast<double>(b[0][d]) + 0.5 *
s) * h0;
167 cen[
static_cast<std::size_t
>(
i)] =
c;
168 fluid[
static_cast<std::size_t
>(
i)] =
sdf(
c) > 0.0 ? 1 : 0;
173 const double hb = 4.0 * h0;
180 auto b =
t.bounds(
i);
181 for (
int d = 0; d < 3; ++d)
182 ext = std::max(
ext,
static_cast<long>(b[1][d]));
184 nbx = std::max<long>(1,
ext / 4);
186 const double domain =
static_cast<double>(
nbx) *
hb;
187 std::vector<std::vector<Index>>
bins(
static_cast<std::size_t
>(
nbx *
nbx *
nbx));
189 const Vec<3>&
c =
cen[
static_cast<std::size_t
>(
i)];
190 long bx =
static_cast<long>((
c[0] - origin[0]) /
hb) %
nbx;
191 long by =
static_cast<long>((
c[1] - origin[1]) /
hb) %
nbx;
192 long bz =
static_cast<long>((
c[2] - origin[2]) /
hb) %
nbx;
199 std::vector<Index>& idx, std::vector<double>& w) ->
bool {
202 std::vector<Index>
pts;
203 const long lo[3] = {
static_cast<long>(std::floor((p[0] - origin[0] -
rho) /
hb)),
204 static_cast<long>(std::floor((p[1] - origin[1] -
rho) /
hb)),
205 static_cast<long>(std::floor((p[2] - origin[2] -
rho) /
hb))};
206 const long hi[3] = {
static_cast<long>(std::floor((p[0] - origin[0] +
rho) /
hb)),
207 static_cast<long>(std::floor((p[1] - origin[1] +
rho) /
hb)),
208 static_cast<long>(std::floor((p[2] - origin[2] +
rho) /
hb))};
215 if (!fluid[
static_cast<std::size_t
>(
j)])
218 for (
int d = 0; d < 3; ++d) {
219 double del =
cen[
static_cast<std::size_t
>(
j)][d] - p[d];
230 const int need =
deg >= 2 ? 12 : 5;
231 if (
static_cast<long>(
pts.size()) <
need)
233 double A[100] = {},
e0[10] = {};
238 for (
int dd = 0;
dd < 3; ++
dd) {
239 double del =
cen[
static_cast<std::size_t
>(
j)][
dd] - p[
dd];
247 for (
int r = 0;
r <
nm; ++
r)
248 for (
int c = 0;
c <
nm; ++
c)
256 for (
int dd = 0;
dd < 3; ++
dd) {
257 double del =
cen[
static_cast<std::size_t
>(
j)][
dd] - p[
dd];
266 for (
int k = 0; k <
nm; ++k)
274 ov.rowOf.assign(
static_cast<std::size_t
>(n), -1);
275 ov.sampStart.assign(1, 0);
276 std::vector<Index>
sIdx;
277 std::vector<double>
sW;
280 if (!fluid[
static_cast<std::size_t
>(
i)])
282 const unsigned Li =
t.level(
i);
283 const double h =
pres.cellWidth(
i);
284 const Vec<3>&
c =
cen[
static_cast<std::size_t
>(
i)];
287 float Cq[3][5],
F[3][4];
288 for (
int a = 0;
a < 3; ++
a) {
289 for (
int q = -2;
q <= 2; ++
q) {
291 p[
a] +=
static_cast<double>(
q) *
h;
292 Cq[
a][
q + 2] =
static_cast<float>(
sdf(p));
294 for (
int m = 0; m < 4; ++m)
295 F[
a][m] = 0.5f * (
Cq[
a][m] +
Cq[
a][m + 1]);
301 const float si0 =
static_cast<float>(
sdf(
c));
302 pres.forEachFaceFull(
i, [&](
Index j,
int axis,
int dir,
double,
double,
double) {
303 const int face = 2 * axis + (dir > 0 ? 0 : 1);
305 if (
j >= 0 && fluid[
static_cast<std::size_t
>(
j)]) {
306 const float sj =
static_cast<float>(
sdf(
cen[
static_cast<std::size_t
>(
j)]));
307 if (0.5f * (
si0 +
sj) >= 0.0f)
311 for (
int k = 0; k < 6; ++k) {
313 const int m = (k & 1) ? 1 : 2;
315 F[
a][m] >= 0.0f &&
Cq[
a][(k & 1) ? 1 : 3] > 0.0f &&
Cq[
a][2] > 0.0f;
320 const float mag = std::fabs(
F[
a][m]) > 0.0f ? std::fabs(
F[
a][m]) : 1e-6f;
328 for (
int a = 0;
a < 3; ++
a)
333 const int slot =
static_cast<int>(ov.base.n);
335 ov.base.cell.resize(
static_cast<std::size_t
>(
nRows));
336 ov.base.rescale.resize(
static_cast<std::size_t
>(
nRows));
337 ov.base.coupled.resize(
static_cast<std::size_t
>(
nRows));
338 ov.base.state.resize(
static_cast<std::size_t
>(
nRows) * 6);
339 ov.base.th.resize(
static_cast<std::size_t
>(
nRows) * 6);
340 ov.base.w_bc.resize(
static_cast<std::size_t
>(
nRows) * 6);
341 ov.base.w_n1.resize(
static_cast<std::size_t
>(
nRows) * 6);
342 ov.base.w_n2.resize(
static_cast<std::size_t
>(
nRows) * 6);
343 ov.base.wm_n1.resize(
static_cast<std::size_t
>(
nRows) * 6);
344 ov.base.wm_n2.resize(
static_cast<std::size_t
>(
nRows) * 6);
347 detail::GhostOverlayRef
ref{ov.base};
354 for (
int a = 0;
a < 3; ++
a)
355 for (
int q = -2;
q <= 2; ++
q) {
357 p[
a] +=
static_cast<double>(
q) *
h;
360 std::array<long, 3>
lc{};
361 for (
int d = 0; d < 3; ++d)
362 lc[d] =
static_cast<long>(std::floor((p[d] - origin[d]) / h0));
365 ov.sampFluid.push_back(
fluidP ? 1 : 0);
366 if (
q == 0 || (
j >= 0 &&
t.level(
j) ==
Li)) {
368 if (
j >= 0 && fluid[
static_cast<std::size_t
>(
j)] == (
fluidP ? 1 : 0)) {
377 ov.sampStart.push_back(
static_cast<Index>(
sIdx.size()));
383 ov.sampStart.push_back(
static_cast<Index>(
sIdx.size()));
386 const double H = (
j >= 0) ?
pres.cellWidth(
j) :
h;
387 const double rho = 2.2 * std::max(
h,
H);
388 std::vector<Index> idx;
389 std::vector<double> w;
394 }
else if (
j >= 0 && fluid[
static_cast<std::size_t
>(
j)]) {
401 for (std::size_t k = 0; k < idx.size(); ++k) {
402 sIdx.push_back(idx[k]);
405 ov.sampStart.push_back(
static_cast<Index>(
sIdx.size()));
407 ov.base.invh.push_back(1.0 /
h);
408 ov.rowOf[
static_cast<std::size_t
>(
i)] = ov.base.n;
411 ov.sampIdx = std::move(
sIdx);
412 ov.sampW = std::move(
sW);
414 "[peclet.core.amr] sampled ghost overlay: %lld rows | slots identity %ld, LS2 %ld, "
415 "LS1 %ld, degraded %ld, solid %ld | sign-forced faces %ld, closed mixed faces %ld\n",
416 static_cast<long long>(ov.base.n), ov.nIdentity, ov.nLS2, ov.nLS1, ov.nDegraded,
417 ov.nSolidSlot, ov.nSignForced, ov.nMixedFace);
423 const std::vector<double>& x) {
424 const std::size_t
s =
static_cast<std::size_t
>(
r * 15 +
a * 5 + (
q + 2));
427 v += ov.
sampW[
static_cast<std::size_t
>(k)] *
428 x[
static_cast<std::size_t
>(ov.
sampIdx[
static_cast<std::size_t
>(k)])];
435 std::vector<double>&
y) {
438 const std::size_t
rr =
static_cast<std::size_t
>(
r);
441 y[
static_cast<std::size_t
>(
c)] = 0.0;
446 for (
int k = 0; k < 6; ++k) {
451 const int sgn = (k & 1) ? -1 : 1;
452 const int mn = (k & 1) ? 1 : 0;
453 const int mf = (k & 1) ? 2 : -1;
454 const double w1 = g.
wm_n1[
rr * 6 +
static_cast<std::size_t
>(k)];
455 const double w2 = g.
wm_n2[
rr * 6 +
static_cast<std::size_t
>(k)];
467 const std::array<std::vector<double>, 3>&
u,
468 std::vector<double>& d) {
471 const std::size_t
rr =
static_cast<std::size_t
>(
r);
474 d[
static_cast<std::size_t
>(
c)] = 0.0;
477 auto U = [&](
int a,
int m) {
478 return 0.5 * (
gpsSample(ov,
r,
a, m - 1,
u[
static_cast<std::size_t
>(
a)]) +
482 for (
int k = 0; k < 6; ++k) {
487 const int sgn = (k & 1) ? -1 : 1;
488 const int mg = (k & 1) ? 0 : 1;
489 const int mn = (k & 1) ? 1 : 0;
490 const int mf = (k & 1) ? 2 : -1;
497 double val = g.
w_n1[
rr * 6 +
static_cast<std::size_t
>(k)] *
U(
a,
mn);
499 val += g.
w_n2[
rr * 6 +
static_cast<std::size_t
>(k)] *
U(
a,
mf);
502 d[
static_cast<std::size_t
>(
c)] =
513 int c,
double invh) {
514 auto fl = [&](
int q) {
515 return ov.
sampFluid[
static_cast<std::size_t
>(
r * 15 +
c * 5 + (
q + 2))] != 0;
518 const bool ap =
fl(+1),
am =
fl(-1);
520 return (
F(+1) -
F(-1)) * 0.5 * invh;
522 return fl(+2) ? (-3.0 *
F(0) + 4.0 *
F(+1) -
F(+2)) * 0.5 * invh : (
F(+1) -
F(0)) * invh;
524 return fl(-2) ? (3.0 *
F(0) - 4.0 *
F(-1) +
F(-2)) * 0.5 * invh : (
F(0) -
F(-1)) * invh;
Cell-centered FV Poisson operator on one (periodic) block octree.
Per-block adaptive octree over block-local Morton codes.
bool gpsSolveDense(int n, double *A, double *b)
Gaussian elimination with partial pivoting (small dense normal equations).
void gpsMonomials(const double d[3], int deg, double *m, int &nm)
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...
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).
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,...
double gpsSample(const GhostOverlaySampled &ov, Index r, int a, int q, const std::vector< double > &x)
Evaluate slot (r, a, q) of a scalar leaf field. Empty functional reads 0.
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...
PECLET_CORE_GP_HD bool gpFillRow(const OV &ov, int slot, CellId cellId, const float F[3][4], const float Cq[3][5], int matrixOrder, int rhsOrder, const float *exStd=nullptr, const float *exSliver=nullptr)
Fill one overlay row from the per-axis sample sets.
std::array< Real, Dim > Vec
Multi-dimensional real vector.
std::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).
Sampled overlay: the classic per-row fields (weights, states, rescale — base; base....
std::vector< Index > rowOf
[numLeaves] row index of a leaf, -1 if none
std::vector< Index > sampIdx
std::vector< int8_t > sampFluid
[base.n*15] virtual position is fluid (gradient cascade)
std::vector< double > sampW
std::vector< Index > sampStart
[base.n*15 + 1]
Host ghost-projection overlay: one row per non-clean fluid leaf (== cut cell: some ±1 center sample s...
std::vector< float > w_n1
std::vector< float > w_n2
[n*6] RHS/diagnostic closure weights (rhsOrder)
std::vector< float > rescale
[n] rho = min(1, min_f D_f) of the MATRIX weights
std::vector< int8_t > state
[n*6]
std::vector< float > wm_n2
[n*6] matrix (implicit phi) weights (matrixOrder)
std::vector< double > invh
[n] 1/cellWidth of the row (finest band)
std::vector< float > wm_n1
std::vector< Index > cell
[n] leaf index
std::vector< int8_t > coupled
[n] 1 if the row has any phi coupling at all