48#ifndef PECLET_CORE_AMR_GHOST_PROJECTION_HPP
49#define PECLET_CORE_AMR_GHOST_PROJECTION_HPP
51#ifdef PECLET_CORE_HAVE_MORTON
74 std::vector<float>
th;
77 std::vector<Index>
nbr;
89 float&
th(
int s)
const {
return g.
th[
static_cast<std::size_t
>(
s)]; }
90 float&
w_bc(
int s)
const {
return g.
w_bc[
static_cast<std::size_t
>(
s)]; }
91 float&
w_n1(
int s)
const {
return g.
w_n1[
static_cast<std::size_t
>(
s)]; }
92 float&
w_n2(
int s)
const {
return g.
w_n2[
static_cast<std::size_t
>(
s)]; }
93 float&
wm_n1(
int s)
const {
return g.
wm_n1[
static_cast<std::size_t
>(
s)]; }
94 float&
wm_n2(
int s)
const {
return g.
wm_n2[
static_cast<std::size_t
>(
s)]; }
109template <
unsigned Bits>
115 const Index n =
t.numLeaves();
117 return j >= 0 ?
static_cast<float>(
sdfC[
static_cast<std::size_t
>(
j)]) : -1.0f;
121 if (!(
sdfC[
static_cast<std::size_t
>(
i)] > 0.0))
125 for (
int a = 0;
a < 3; ++
a) {
131 0.5f * (
c2 +
c3) >= 0.0f;
136 const unsigned Li =
t.level(
i);
138 for (
int a = 0;
a < 3; ++
a) {
143 for (
int q = 0;
q < 5; ++
q)
149 throw std::runtime_error(
150 "amr ghost projection: an overlay row's ±2 closure reach crosses a 2:1 level "
151 "boundary — the cut band is too thin; widen the refineToSdf band margin");
155 float F[3][4],
Cq[3][5];
156 for (
int a = 0;
a < 3; ++
a) {
157 for (
int q = 0;
q < 5; ++
q)
159 for (
int m = 0; m < 4; ++m)
160 F[
a][m] = 0.5f * (
Cq[
a][m] +
Cq[
a][m + 1]);
162 const int slot =
static_cast<int>(ov.
n);
163 ov.
cell.resize(
static_cast<std::size_t
>(slot) + 1);
164 ov.
rescale.resize(
static_cast<std::size_t
>(slot) + 1);
165 ov.
coupled.resize(
static_cast<std::size_t
>(slot) + 1);
166 ov.
state.resize(
static_cast<std::size_t
>(slot + 1) * 6);
167 ov.
th.resize(
static_cast<std::size_t
>(slot + 1) * 6);
168 ov.
w_bc.resize(
static_cast<std::size_t
>(slot + 1) * 6);
169 ov.
w_n1.resize(
static_cast<std::size_t
>(slot + 1) * 6);
170 ov.
w_n2.resize(
static_cast<std::size_t
>(slot + 1) * 6);
171 ov.
wm_n1.resize(
static_cast<std::size_t
>(slot + 1) * 6);
172 ov.
wm_n2.resize(
static_cast<std::size_t
>(slot + 1) * 6);
177 ov.
cell.resize(
static_cast<std::size_t
>(slot));
178 ov.
rescale.resize(
static_cast<std::size_t
>(slot));
179 ov.
coupled.resize(
static_cast<std::size_t
>(slot));
180 ov.
state.resize(
static_cast<std::size_t
>(slot) * 6);
181 ov.
th.resize(
static_cast<std::size_t
>(slot) * 6);
182 ov.
w_bc.resize(
static_cast<std::size_t
>(slot) * 6);
183 ov.
w_n1.resize(
static_cast<std::size_t
>(slot) * 6);
184 ov.
w_n2.resize(
static_cast<std::size_t
>(slot) * 6);
185 ov.
wm_n1.resize(
static_cast<std::size_t
>(slot) * 6);
186 ov.
wm_n2.resize(
static_cast<std::size_t
>(slot) * 6);
189 for (
int a = 0;
a < 3; ++
a)
190 for (
int q = 0;
q < 5; ++
q)
192 ov.
invh.push_back(1.0 /
pres.cellWidth(
i));
204template <
class SdfFn>
208 pm[axis] -= 0.5 * h0;
209 pp[axis] += 0.5 * h0;
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;
225template <
unsigned Bits>
228 const std::vector<double>&
sdfC) {
229 const Index n =
t.numLeaves();
230 std::vector<char>
pocket(
static_cast<std::size_t
>(n), 0);
231 std::vector<int> comp(
static_cast<std::size_t
>(n), -1);
232 auto fluid = [&](
Index i) {
return sdfC[
static_cast<std::size_t
>(
i)] > 0.0; };
236 if (!fluid(
s) || comp[
static_cast<std::size_t
>(
s)] >= 0)
241 comp[
static_cast<std::size_t
>(
s)] =
id;
242 while (!
stack.empty()) {
247 if (alpha > 0.5 && fluid(
j) && comp[
static_cast<std::size_t
>(
j)] < 0) {
248 comp[
static_cast<std::size_t
>(
j)] =
id;
257 for (
int c = 1;
c < nc; ++
c)
262 if (fluid(
i) && comp[
static_cast<std::size_t
>(
i)] !=
mainId) {
263 pocket[
static_cast<std::size_t
>(
i)] = 1;
267 "[peclet.core.amr] ghost projection: binary coupled-face graph fragments into %d "
268 "components — decoupling %lld pocket cells outside the main component\n",
269 nc,
static_cast<long long>(
nPocket));
278 std::vector<double>&
y) {
280 const std::size_t
rr =
static_cast<std::size_t
>(
r);
283 y[
static_cast<std::size_t
>(
c)] = 0.0;
286 auto X = [&](
int a,
int q) {
287 return x[
static_cast<std::size_t
>(ov.
nbr[
rr * 15 +
static_cast<std::size_t
>(
a) * 5 +
288 static_cast<std::size_t
>(
q + 2)])];
291 for (
int k = 0; k < 6; ++k) {
296 const int sgn = (k & 1) ? -1 : 1;
297 const int mn = (k & 1) ? 1 : 0;
298 const int mf = (k & 1) ? 2 : -1;
299 const double w1 = ov.
wm_n1[
rr * 6 +
static_cast<std::size_t
>(k)];
300 const double w2 = ov.
wm_n2[
rr * 6 +
static_cast<std::size_t
>(k)];
306 y[
static_cast<std::size_t
>(
c)] =
314 const std::array<std::vector<double>, 3>&
u,
315 std::vector<double>& d) {
317 const std::size_t
rr =
static_cast<std::size_t
>(
r);
320 d[
static_cast<std::size_t
>(
c)] = 0.0;
323 auto U = [&](
int a,
int m) {
324 const Index cm = ov.
nbr[
rr * 15 +
static_cast<std::size_t
>(
a) * 5 +
325 static_cast<std::size_t
>(m + 1)];
326 const Index cp = ov.
nbr[
rr * 15 +
static_cast<std::size_t
>(
a) * 5 +
327 static_cast<std::size_t
>(m + 2)];
328 return 0.5 * (
u[
static_cast<std::size_t
>(
a)][
static_cast<std::size_t
>(
cm)] +
329 u[
static_cast<std::size_t
>(
a)][
static_cast<std::size_t
>(
cp)]);
332 for (
int k = 0; k < 6; ++k) {
337 const int sgn = (k & 1) ? -1 : 1;
338 const int mg = (k & 1) ? 0 : 1;
339 const int mn = (k & 1) ? 1 : 0;
340 const int mf = (k & 1) ? 2 : -1;
347 double val = ov.
w_n1[
rr * 6 +
static_cast<std::size_t
>(k)] *
U(
a,
mn);
349 val += ov.
w_n2[
rr * 6 +
static_cast<std::size_t
>(k)] *
U(
a,
mf);
352 d[
static_cast<std::size_t
>(
c)] =
358#ifdef KOKKOS_INLINE_FUNCTION
400 Kokkos::parallel_for(
408 for (
int k = 0; k < 6; ++k) {
413 const int sgn = (k & 1) ? -1 : 1;
414 const int mn = (k & 1) ? 1 : 0;
415 const int mf = (k & 1) ? 2 : -1;
416 const double w1 =
wm1(
r * 6 + k), w2 =
wm2(
r * 6 + k);
417 delta +=
sgn * w1 * (x(nbr(
r * 15 +
a * 5 +
mn + 2)) - x(nbr(
r * 15 +
a * 5 +
mn + 1)));
420 sgn * w2 * (x(nbr(
r * 15 +
a * 5 +
mf + 2)) - x(nbr(
r * 15 +
a * 5 +
mf + 1)));
422 const double ih = invh(
r);
440 Kokkos::parallel_for(
447 auto U = [&](
int a,
int m) {
448 const Index cm = nbr(
r * 15 +
a * 5 + m + 1);
449 const Index cp = nbr(
r * 15 +
a * 5 + m + 2);
452 return 0.5 * (
vm +
vp);
455 for (
int k = 0; k < 6; ++k) {
460 const int sgn = (k & 1) ? -1 : 1;
461 const int mg = (k & 1) ? 0 : 1;
462 const int mn = (k & 1) ? 1 : 0;
463 const int mf = (k & 1) ? 2 : -1;
Cell-centered FV Poisson operator on one (periodic) block octree.
Per-block adaptive octree over block-local Morton codes.
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...
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 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...
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 ghostDivergDelta(const GhostOverlayDev &ov, View< const double > u0, View< const double > u1, View< const double > u2, View< double > d)
Device divergence overlay (== ghostDivergDeltaHost).
auto makeBinaryOpenFn(SdfFn sdfFn, double h0)
Binary openness callable factory for the MG surrogate: a face is open iff both adjacent centers (prob...
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.
View< T > toDevice(const std::vector< T > &h, const std::string &label)
Upload a host std::vector into a freshly-sized device View (empty vector => empty view).
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).
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< Index > nbr
[n*15] ±2 neighbour chain per axis
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< float > w_bc
std::vector< Index > cell
[n] leaf index
std::vector< float > th
[n*6] (diagnostics)
std::vector< int8_t > coupled
[n] 1 if the row has any phi coupling at all
float & rescale(int s) const
int8_t & coupled(int s) const
float & wm_n1(int s) const
float & wm_n2(int s) const
Index & cell(int s) const
float & w_bc(int s) const
float & w_n1(int s) const
int8_t & state(int s) const
float & w_n2(int s) const