48#ifndef PECLET_AMR_GHOST_PROJECTION_HPP
49#define PECLET_AMR_GHOST_PROJECTION_HPP
59#include "peclet/core/common/types.hpp"
60#include "peclet/core/scheme/ghost_closure.hpp"
73 std::vector<float>
th;
76 std::vector<Index>
nbr;
88 float&
th(
int s)
const {
return g.
th[
static_cast<std::size_t
>(
s)]; }
89 float&
w_bc(
int s)
const {
return g.
w_bc[
static_cast<std::size_t
>(
s)]; }
90 float&
w_n1(
int s)
const {
return g.
w_n1[
static_cast<std::size_t
>(
s)]; }
91 float&
w_n2(
int s)
const {
return g.
w_n2[
static_cast<std::size_t
>(
s)]; }
92 float&
wm_n1(
int s)
const {
return g.
wm_n1[
static_cast<std::size_t
>(
s)]; }
93 float&
wm_n2(
int s)
const {
return g.
wm_n2[
static_cast<std::size_t
>(
s)]; }
108template <
unsigned Bits>
114 const Index n =
t.numLeaves();
116 return j >= 0 ?
static_cast<float>(
sdfC[
static_cast<std::size_t
>(
j)]) : -1.0f;
120 if (!(
sdfC[
static_cast<std::size_t
>(
i)] > 0.0))
124 for (
int a = 0;
a < 3; ++
a) {
130 clean &&
c1 >= 0.0f &&
c3 >= 0.0f && 0.5f * (
c1 +
c2) >= 0.0f && 0.5f * (
c2 +
c3) >= 0.0f;
135 const unsigned Li =
t.level(
i);
137 for (
int a = 0;
a < 3; ++
a) {
140 for (
int q = 0;
q < 5; ++
q)
146 throw std::runtime_error(
147 "amr ghost projection: an overlay row's ±2 closure reach crosses a 2:1 level "
148 "boundary — the cut band is too thin; widen the refineToSdf band margin");
152 float F[3][4],
Cq[3][5];
153 for (
int a = 0;
a < 3; ++
a) {
154 for (
int q = 0;
q < 5; ++
q)
156 for (
int m = 0; m < 4; ++m)
157 F[
a][m] = 0.5f * (
Cq[
a][m] +
Cq[
a][m + 1]);
159 const int slot =
static_cast<int>(ov.
n);
160 ov.
cell.resize(
static_cast<std::size_t
>(slot) + 1);
161 ov.
rescale.resize(
static_cast<std::size_t
>(slot) + 1);
162 ov.
coupled.resize(
static_cast<std::size_t
>(slot) + 1);
163 ov.
state.resize(
static_cast<std::size_t
>(slot + 1) * 6);
164 ov.
th.resize(
static_cast<std::size_t
>(slot + 1) * 6);
165 ov.
w_bc.resize(
static_cast<std::size_t
>(slot + 1) * 6);
166 ov.
w_n1.resize(
static_cast<std::size_t
>(slot + 1) * 6);
167 ov.
w_n2.resize(
static_cast<std::size_t
>(slot + 1) * 6);
168 ov.
wm_n1.resize(
static_cast<std::size_t
>(slot + 1) * 6);
169 ov.
wm_n2.resize(
static_cast<std::size_t
>(slot + 1) * 6);
174 ov.
cell.resize(
static_cast<std::size_t
>(slot));
175 ov.
rescale.resize(
static_cast<std::size_t
>(slot));
176 ov.
coupled.resize(
static_cast<std::size_t
>(slot));
177 ov.
state.resize(
static_cast<std::size_t
>(slot) * 6);
178 ov.
th.resize(
static_cast<std::size_t
>(slot) * 6);
179 ov.
w_bc.resize(
static_cast<std::size_t
>(slot) * 6);
180 ov.
w_n1.resize(
static_cast<std::size_t
>(slot) * 6);
181 ov.
w_n2.resize(
static_cast<std::size_t
>(slot) * 6);
182 ov.
wm_n1.resize(
static_cast<std::size_t
>(slot) * 6);
183 ov.
wm_n2.resize(
static_cast<std::size_t
>(slot) * 6);
186 for (
int a = 0;
a < 3; ++
a)
187 for (
int q = 0;
q < 5; ++
q)
189 for (
int a = 0;
a < 3; ++
a)
190 ov.
invh.push_back(1.0 /
pres.cellWidth(
i,
a));
204template <
class SdfFn>
208 pm[axis] -= 0.5 * h0[axis];
209 pp[axis] += 0.5 * h0[axis];
211 const float fm =
static_cast<float>(
sm),
fp =
static_cast<float>(
sp);
212 return (
sm > 0.0 &&
sp > 0.0 && 0.5f * (
fm +
fp) >= 0.0f) ? 1.0 : 0.0;
217template <
class SdfFn>
231template <
unsigned Bits>
234 const std::vector<double>&
sdfC) {
235 const Index n =
t.numLeaves();
236 std::vector<char>
pocket(
static_cast<std::size_t
>(n), 0);
237 std::vector<int> comp(
static_cast<std::size_t
>(n), -1);
238 auto fluid = [&](
Index i) {
return sdfC[
static_cast<std::size_t
>(
i)] > 0.0; };
242 if (!fluid(
s) || comp[
static_cast<std::size_t
>(
s)] >= 0)
247 comp[
static_cast<std::size_t
>(
s)] =
id;
248 while (!
stack.empty()) {
253 if (alpha > 0.5 && fluid(
j) && comp[
static_cast<std::size_t
>(
j)] < 0) {
254 comp[
static_cast<std::size_t
>(
j)] =
id;
263 for (
int c = 1;
c <
nc; ++
c)
268 if (fluid(
i) && comp[
static_cast<std::size_t
>(
i)] !=
mainId) {
269 pocket[
static_cast<std::size_t
>(
i)] = 1;
273 "[peclet.amr] ghost projection: binary coupled-face graph fragments into %d "
274 "components — decoupling %lld pocket cells outside the main component\n",
284 std::vector<double>&
y) {
286 const std::size_t
rr =
static_cast<std::size_t
>(
r);
289 y[
static_cast<std::size_t
>(
c)] = 0.0;
292 auto X = [&](
int a,
int q) {
293 return x[
static_cast<std::size_t
>(
294 ov.
nbr[
rr * 15 +
static_cast<std::size_t
>(
a) * 5 +
static_cast<std::size_t
>(
q + 2)])];
306 for (
int k = 0; k < 6; ++k) {
308 if (
st != scheme::GP_QUAD &&
st != scheme::GP_LIN)
311 const int sgn = (k & 1) ? -1 : 1;
312 const int mn = (k & 1) ? 1 : 0;
313 const int mf = (k & 1) ? 2 : -1;
314 const double w1 = ov.
wm_n1[
rr * 6 +
static_cast<std::size_t
>(k)];
315 const double w2 = ov.
wm_n2[
rr * 6 +
static_cast<std::size_t
>(k)];
317 if (
st == scheme::GP_QUAD &&
w2 != 0.0)
320 y[
static_cast<std::size_t
>(
c)] =
328 const std::array<std::vector<double>, 3>&
u,
329 std::vector<double>& d) {
331 const std::size_t
rr =
static_cast<std::size_t
>(
r);
334 d[
static_cast<std::size_t
>(
c)] = 0.0;
337 auto U = [&](
int a,
int m) {
338 const Index cm = ov.
nbr[
rr * 15 +
static_cast<std::size_t
>(
a) * 5 +
339 static_cast<std::size_t
>(m + 1)];
340 const Index cp = ov.
nbr[
rr * 15 +
static_cast<std::size_t
>(
a) * 5 +
341 static_cast<std::size_t
>(m + 2)];
342 return 0.5 * (
u[
static_cast<std::size_t
>(
a)][
static_cast<std::size_t
>(
cm)] +
343 u[
static_cast<std::size_t
>(
a)][
static_cast<std::size_t
>(
cp)]);
349 for (
int k = 0; k < 6; ++k) {
351 if (
st == scheme::GP_COUPLED)
354 const int sgn = (k & 1) ? -1 : 1;
355 const int mg = (k & 1) ? 0 : 1;
356 const int mn = (k & 1) ? 1 : 0;
357 const int mf = (k & 1) ? 2 : -1;
358 if (
st == scheme::GP_EXPLICIT) {
362 if (
st == scheme::GP_BC_ONLY)
364 double val = ov.
w_n1[
rr * 6 +
static_cast<std::size_t
>(k)] *
U(
a,
mn);
365 if (
st == scheme::GP_QUAD)
366 val += ov.
w_n2[
rr * 6 +
static_cast<std::size_t
>(k)] *
U(
a,
mf);
369 d[
static_cast<std::size_t
>(
c)] = ov.
rescale[
rr] * (d[
static_cast<std::size_t
>(
c)] +
ihd *
dd);
374#ifdef KOKKOS_INLINE_FUNCTION
416 Kokkos::parallel_for(
424 const double ih = invh(
r * 3);
425 const double rx = invh(
r * 3 + 1) /
ih,
ry = invh(
r * 3 + 2) /
ih;
428 for (
int k = 0; k < 6; ++k) {
430 if (
s != scheme::GP_QUAD &&
s != scheme::GP_LIN)
433 const int sgn = (k & 1) ? -1 : 1;
434 const int mn = (k & 1) ? 1 : 0;
435 const int mf = (k & 1) ? 2 : -1;
438 (
sgn *
w1 * (x(nbr(
r * 15 +
a * 5 +
mn + 2)) - x(nbr(
r * 15 +
a * 5 +
mn + 1))));
439 if (
s == scheme::GP_QUAD &&
w2 != 0.0)
441 (x(nbr(
r * 15 +
a * 5 +
mf + 2)) - x(nbr(
r * 15 +
a * 5 +
mf + 1))));
460 Kokkos::parallel_for(
467 auto U = [&](
int a,
int m) {
468 const Index cm = nbr(
r * 15 +
a * 5 + m + 1);
469 const Index cp = nbr(
r * 15 +
a * 5 + m + 2);
472 return 0.5 * (
vm +
vp);
475 const double ih = invh(
r * 3);
476 const double r1[3] = {1.0, invh(
r * 3 + 1) /
ih, invh(
r * 3 + 2) /
ih};
478 for (
int k = 0; k < 6; ++k) {
480 if (
s == scheme::GP_COUPLED)
483 const int sgn = (k & 1) ? -1 : 1;
484 const int mg = (k & 1) ? 0 : 1;
485 const int mn = (k & 1) ? 1 : 0;
486 const int mf = (k & 1) ? 2 : -1;
487 if (
s == scheme::GP_EXPLICIT) {
491 if (
s == scheme::GP_BC_ONLY)
494 if (
s == scheme::GP_QUAD)
Cell-centered FV Poisson operator on one (periodic) block octree.
Per-block adaptive octree over block-local Morton codes.
void ghostApplyDeltaHost(const GhostOverlay &ov, const std::vector< double > &x, std::vector< double > &y)
Matrix overlay: y currently holds the BINARY L matvec; overwrite the overlay rows with y = rho·(y + i...
void ghostApplyDelta(const GhostOverlayDev &ov, View< const double > x, View< double > y)
Device matrix overlay (== ghostApplyDeltaHost). Distinct rows per thread: no atomics.
std::vector< char > findPocketCells(const BlockOctree< 3, Bits > &t, const AmrPoisson< 3, Bits > &pres, const std::vector< double > &sdfC)
Fragmentation guard (the AMR port of flow's host-BFS pocket guard): the BINARY coupled-face graph (a ...
void ghostDivergDeltaHost(const GhostOverlay &ov, const std::array< std::vector< double >, 3 > &u, std::vector< double > &d)
Divergence overlay: d currently holds the BINARY divergence (physical); overwrite overlay rows with d...
auto makeBinaryOpenFn(SdfFn sdfFn, const Vec< 3 > &h0)
Binary openness callable factory for the MG surrogate: a face is open iff both adjacent centers (prob...
GhostOverlayDev uploadGhostOverlay(const GhostOverlay &h)
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,...
void ghostDivergDelta(const GhostOverlayDev &ov, View< const double > u0, View< const double > u1, View< const double > u2, View< double > d)
Device divergence overlay (== ghostDivergDeltaHost).
GhostOverlay buildGhostOverlay(const BlockOctree< 3, Bits > &t, const AmrPoisson< 3, Bits > &pres, const std::vector< double > &sdfC, int matrixOrder, int rhsOrder, bool *bandViolation=nullptr)
Build the overlay from the octree + the cell-centered SDF samples (AmrCutCell::sdfCRaw — EXTENDED ove...
Device mirror of GhostOverlay (uploaded once per setSolid).
Host ghost-projection overlay: one row per non-clean fluid leaf (== cut cell: some ±1 center sample s...
std::vector< float > wm_n2
[n*6] matrix (implicit phi) weights (matrixOrder)
std::vector< int8_t > coupled
[n] 1 if the row has any phi coupling at all
std::vector< Index > cell
[n] leaf index
std::vector< float > th
[n*6] (diagnostics)
std::vector< float > wm_n1
std::vector< int8_t > state
[n*6]
std::vector< float > w_bc
std::vector< Index > nbr
[n*15] ±2 neighbour chain per axis
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< float > w_n1
std::vector< double > invh
[n*3] 1/cellWidth PER AXIS of the row (Phase 3)
float & w_bc(int s) const
float & wm_n2(int s) const
float & w_n1(int s) const
float & wm_n1(int s) const
float & rescale(int s) const
int8_t & state(int s) const
Index & cell(int s) const
float & w_n2(int s) const
int8_t & coupled(int s) const