29#ifndef PECLET_FLOW_SCALAR_CUTCELL_GEOMETRY_HPP
30#define PECLET_FLOW_SCALAR_CUTCELL_GEOMETRY_HPP
33#include <Kokkos_Core.hpp>
36#include "peclet/core/scheme/cut_cell_geometry.hpp"
37#include "peclet/core/scheme/probe_flux.hpp"
42namespace cs = peclet::core::scheme;
52 Kokkos::View<long*, CCMem>
cell;
53 Kokkos::View<double*, CCMem>
alpha;
54 Kokkos::View<double* [3], Kokkos::LayoutLeft, CCMem>
normal;
55 Kokkos::View<double* [3], Kokkos::LayoutLeft, CCMem>
centroid;
56 Kokkos::View<int*, CCMem>
body;
57 Kokkos::View<double*, CCMem>
sF;
58 Kokkos::View<int* [8], Kokkos::LayoutLeft, CCMem>
offF;
59 Kokkos::View<double* [8], Kokkos::LayoutLeft, CCMem>
wF;
60 Kokkos::View<std::uint8_t*, CCMem>
rungF;
91 return (((s(i0) + s(i0 + 1)) + (s(i0 + sy) + s(i0 + 1 + sy))) +
92 ((s(i0 + sz) + s(i0 + 1 + sz)) + (s(i0 + sy + sz) + s(i0 + 1 + sy + sz)))) *
100 double face[6],
double&
centre) {
101 for (
int c = 0; c < 8; ++c) {
103 i + (
long)((c & 1) - 1) + (
long)(((c >> 1) & 1) - 1) * sy + (
long)(((c >> 2) & 1) - 1) * sz;
106 const long st[3] = {1, sy, sz};
107 for (
int a = 0; a < 3; ++a) {
108 face[2 * a] = 0.5 * (s(i - st[a]) + s(i));
109 face[2 * a + 1] = 0.5 * (s(i) + s(i + st[a]));
117 const long st[3] = {1, sy, sz};
118 const int t1 = (a == 0) ? 1 : 0,
t2 = (a == 2) ? 1 : 2;
120 auto corner = [&](
int u,
int w) {
121 return cornerSample(s, i - st[a] + (
long)(u - 1) * st[
t1] + (
long)(w - 1) * st[
t2], sy, sz);
123 const double cc = 0.5 * (s(i - st[a]) + s(i));
124 return cs::snapAperture(
132 const long sy = e.x, sz = (
long)e.x * e.y;
133 const int hx = e.x - g,
hy = e.y - g,
hz = e.z - g;
134 Kokkos::parallel_for(
137 const long i = (
long)x + (
long)y * sy + (
long)z * sz;
138 if (y <
hy && z <
hz)
140 if (x <
hx && z <
hz)
142 if (x <
hx && y <
hy)
151 long sz,
double ap[6]) {
163 const double h[3],
double area[2][3],
double cen[2][3]) {
165 cs::facetAreaVector(ap, h,
aSnap);
167 double maxA = cs::cutCellFaceArea(0, h);
168 maxA = cs::cutCellFaceArea(1, h) >
maxA ? cs::cutCellFaceArea(1, h) :
maxA;
169 maxA = cs::cutCellFaceArea(2, h) >
maxA ? cs::cutCellFaceArea(2, h) :
maxA;
174 for (
int d = 0; d < 3; ++d) {
175 area[0][d] =
aSnap[d];
176 cen[0][d] = g.facetCentroid[0][d];
182 for (
int k = 0; k < 2; ++k)
183 m[k] = g.facetArea[k][0] * g.facetArea[k][0] + g.facetArea[k][1] * g.facetArea[k][1] +
184 g.facetArea[k][2] * g.facetArea[k][2];
185 const int big = m[1] > m[0] ? 1 : 0;
186 for (
int k = 0; k < 2; ++k)
187 for (
int d = 0; d < 3; ++d) {
188 area[k][d] = g.facetArea[k][d] + (k ==
big ?
aSnap[d] - g.areaPL[d] : 0.0);
189 cen[k][d] = g.facetCentroid[k][d];
198 Kokkos::View<std::int8_t*, CCMem>
nfac;
199 Kokkos::View<std::int8_t*, CCMem>
kind;
208 const long sy = e.x, sz = (
long)e.x * e.y;
209 const int nx = e.x - 2 * g, ny = e.y - 2 * g;
210 const double h0 = hp[0],
h1 = hp[1], h2 = hp[2];
213 Kokkos::parallel_for(
216 const long i = (
long)x + (
long)y * sy + (
long)z * sz;
218 const double h[3] = {
h0,
h1, h2};
221 const cs::CutCellGeometry
gg = cs::cutCellGeometryFanTet(
corner, face,
centre, h);
224 const double apSum = ((ap[0] + ap[1]) + (ap[2] + ap[3])) + (ap[4] + ap[5]);
227 double area[2][3], cen[2][3];
229 kind(
ii) = (std::int8_t)
gg.kind;
238 const long nx = e.x - 2 * g, ny = e.y - 2 * g, nz = e.z - 2 * g;
239 const long nInner = nx * ny * nz;
241 Kokkos::View<long*, CCMem>
fStart(
"peclet::flow::scg_fstart", nInner);
242 Kokkos::View<long*, CCMem>
cStart(
"peclet::flow::scg_cstart", nInner);
244 Kokkos::parallel_scan(
245 "peclet::flow::scg_scan_facets", Kokkos::RangePolicy<CCExec>(0, nInner),
252 Kokkos::parallel_scan(
253 "peclet::flow::scg_scan_cut", Kokkos::RangePolicy<CCExec>(0, nInner),
257 acc += nfac(
ii) > 0 ? 1 : 0;
262 fo.cell = Kokkos::View<long*, CCMem>(
"peclet::flow::scg_cell",
totF);
263 fo.alpha = Kokkos::View<double*, CCMem>(
"peclet::flow::scg_alpha",
totF);
264 fo.normal =
decltype(
fo.normal)(
"peclet::flow::scg_normal",
totF);
265 fo.centroid =
decltype(
fo.centroid)(
"peclet::flow::scg_centroid",
totF);
266 fo.body = Kokkos::View<int*, CCMem>(
"peclet::flow::scg_body",
totF);
267 fo.sF = Kokkos::View<double*, CCMem>(
"peclet::flow::scg_sF",
totF);
268 fo.offF =
decltype(
fo.offF)(
"peclet::flow::scg_offF",
totF);
269 fo.wF =
decltype(
fo.wF)(
"peclet::flow::scg_wF",
totF);
270 fo.rungF = Kokkos::View<std::uint8_t*, CCMem>(
"peclet::flow::scg_rungF",
totF);
271 fo.cutCell = Kokkos::View<long*, CCMem>(
"peclet::flow::scg_cutCell",
totC);
272 fo.cellFacetStart = Kokkos::View<int*, CCMem>(
"peclet::flow::scg_cellFacetStart",
totC + 1);
275 const long sy = e.x, sz = (
long)e.x * e.y;
276 const double h0 = hp[0],
h1 = hp[1], h2 = hp[2];
277 const double vol =
h0 *
h1 * h2;
278 auto fcell =
fo.cell;
282 auto cutCell =
fo.cutCell;
283 auto cfs =
fo.cellFacetStart;
284 Kokkos::parallel_for(
285 "peclet::flow::scg_facets", Kokkos::RangePolicy<CCExec>(
space, 0, nInner),
289 const long x =
ii % nx, y = (
ii / nx) % ny, z =
ii / (nx * ny);
290 const long i = (x + g) + (y + g) * sy + (z + g) * sz;
291 const double h[3] = {
h0,
h1, h2};
294 const cs::CutCellGeometry
gg = cs::cutCellGeometryFanTet(
corner, face,
centre, h);
297 double area[2][3], cen[2][3];
300 for (
int k = 0; k <
nf; ++k) {
301 const long f =
f0 + k;
302 const double mag = Kokkos::sqrt(area[k][0] * area[k][0] + area[k][1] * area[k][1] +
303 area[k][2] * area[k][2]);
306 for (
int d = 0; d < 3; ++d) {
308 fcen(f, d) = cen[k][d];
325 return unk(
base + (
long)dx + (
long)dy *
sy + (
long)dz *
sz) > 0.5;
330 cs::trilinearStencil(
xi, b, w);
332 for (
int k = 0; k < 8; ++k)
333 v += w[k] *
sdf(
base + (
long)(b[0] + (k & 1)) + (
long)(b[1] + ((k >> 1) & 1)) *
sy +
334 (
long)(b[2] + (k >> 2)) *
sz);
342 const double hp[3]) {
344 const long sy = e.x, sz = (
long)e.x * e.y;
345 const double h0 = hp[0],
h1 = hp[1], h2 = hp[2];
346 auto fcell =
fo.cell;
352 auto rungF =
fo.rungF;
353 Kokkos::parallel_for(
354 "peclet::flow::scg_fluid_probes", Kokkos::RangePolicy<CCExec>(
space, 0,
fo.n),
356 const double h[3] = {
h0,
h1, h2};
359 const BlockLookup L{sdf, unknown, fcell(f), sy, sz, 1.0};
360 const cs::ProbeResult r = cs::buildProbe(
xw, n, h, L);
362 rungF(f) = (std::uint8_t)r.rung;
363 for (
int k = 0; k < 8; ++k) {
364 const bool used = k < r.n;
366 used ? (int)((
long)r.off[k][0] + (
long)r.off[k][1] * sy + (
long)r.off[k][2] * sz) : 0;
367 wF(f, k) =
used ? r.w[k] : 0.0;
377 const int a = face / 2, s = face % 2;
378 const int ext[3] = {e.x, e.y, e.z};
379 int lo[3] = {0, 0, 0}, hi[3] = {e.x, e.y, e.z};
380 lo[a] = s ? ext[a] - g : 0;
381 hi[a] = s ? ext[a] : g;
382 const long sy = e.x, sz = (
long)e.x * e.y;
383 Kokkos::parallel_for(
384 "peclet::flow::scg_zero_ghost",
386 KOKKOS_LAMBDA(
int x,
int y,
int z) { f((
long)x + (
long)y * sy + (
long)z * sz) = 0.0; });
397 const long sy = e.x, sz = (
long)e.x * e.y;
398 const int nx = e.x - 2 * g, ny = e.y - 2 * g;
403 Kokkos::parallel_reduce(
404 "peclet::flow::scg_census_cells",
407 const long i = (
long)x + (
long)y * sy + (
long)z * sz;
409 u += unknown(i) > 0.5 ? 1 : 0;
410 two += nfac(
ii) == 2 ? 1 : 0;
411 thin += (nfac(
ii) == 2 && kind(
ii) == (std::int8_t)cs::CutCellKind::thinSolid) ? 1 : 0;
414 const double apSum = ((ap[0] + ap[1]) + (ap[2] + ap[3])) + (ap[4] + ap[5]);
415 if (kappa(i) > 0.0 &&
apSum == 0.0) {
417 vs += kappa(i) * vol;
421 long r[4] = {0, 0, 0, 0};
422 auto rungF =
fo.rungF;
423 for (
int k = 0; k < 4; ++k) {
425 Kokkos::parallel_reduce(
426 "peclet::flow::scg_census_rungs", Kokkos::RangePolicy<CCExec>(
space, 0,
fo.n),
427 KOKKOS_LAMBDA(
const long f,
long& acc) { acc += (int)rungF(f) == k ? 1 : 0; }, cnt);
431 c.numCutCells =
fo.nCut;
433 c.numTwoSided =
nTwo;
434 c.numThinSolid =
nThin;
437 for (
int k = 0; k < 4; ++k)
442 Kokkos::parallel_reduce(
443 "peclet::flow::scg_census_volume",
446 v += kappa((
long)x + (
long)y * sy + (
long)z * sz) * vol;
flow — portable (Kokkos) cut-cell pressure-operator face openness from an SDF.
void cellSamples(const V &s, long i, long sy, long sz, double corner[8], double face[6], double ¢re)
The 15 PL samples of the cell at extended linear index i (corner index bx + 2 by + 4 bz,...
double lowFaceAperture(const CCConst &s, long i, int a, long sy, long sz)
The snapped aperture of the -a face of the cell at extended index i (the fan of cs::fanFaceAperture: ...
void cellSnapped(const V &sax, const V &say, const V &saz, long i, long sy, long sz, double ap[6])
The snapped apertures of cell i in face order -x,+x,-y,+y,-z,+z.
void buildFacets(ScalarFacetOverlay &fo, const CellPass &cp, CCConst sdf, CCConst sax, CCConst say, CCConst saz, C3 e, int g, const double hp[3])
Kernel 3 (§2.5): exclusive scans of the facet counts and of the cut-cell indicator in x-fastest inner...
constexpr double kFacetAreaRel
|A^snap| below this times max_a A_a: no facet (§2.3).
void buildFluidProbes(ScalarFacetOverlay &fo, CCConst sdf, CCConst unknown, C3 e, const double hp[3])
Kernel 5 (§2.5, §3.3): the fluid probe ladder of every facet.
int cellFacets(const cs::CutCellGeometry &g, const double ap[6], const double h[3], double area[2][3], double cen[2][3])
The operator facets of one cell (§2.3) from its PL record and snapped apertures: returns the count (0...
double cornerSample(const V &s, long i0, long sy, long sz)
Corner sample: the 8 cells whose lowest is i0, in the fixed order of §2.2.
constexpr double kKappaUnknown
kappa above which a cell with an open face is a fluid unknown (§2.4).
void zeroGhostSlab(CCField f, C3 e, int g, int face)
Zero f on every ghost layer beyond face face (0..5 = -x,+x,-y,+y,-z,+z), full transverse extent: the ...
void buildCells(CCField kappa, CCField unknown, const CellPass &cp, CCConst sdf, CCConst sax, CCConst say, CCConst saz, C3 e, int g, const double hp[3])
Kernel 2 (§2.5): kappa, the unknown flag and the per-cell facet count/kind on the inner cells.
void buildApertures(CCField sax, CCField say, CCField saz, CCConst sdf, C3 e, int g)
Kernel 1 (§2.5): the snapped scalar apertures of every face of every inner cell, including the high-s...
ScalarCutCensus localCensus(const ScalarFacetOverlay &fo, const CellPass &cp, CCConst kappa, CCConst unknown, CCConst sax, CCConst say, CCConst saz, C3 e, int g, double vol)
The census of the record on this rank (not yet summed over ranks); sealedVolume in internal volume un...
Kokkos::View< double *, CCMem > CCField
Kokkos::DefaultExecutionSpace CCExec
Kokkos::View< const double *, CCMem > CCConst
flow — the multidimensional iteration policies: iteration order follows storage.
The block Lookup of cs::buildProbe for one facet's cell: unknown flags (haloed) at lattice offsets,...
bool unknown(int dx, int dy, int dz) const
double sign
+1 fluid, -1 solid
double phi(const double xi[3]) const
Per-cell flags of the record pass, on the INNER grid (x fastest).
Kokkos::View< std::int8_t *, CCMem > nfac
facets of the cell (0, 1, 2)
Kokkos::View< std::int8_t *, CCMem > kind
cs::CutCellKind of the PL record
The geometry part of diagnostics.scalar_census (§8.2).
double fluidVolume
Sum kappa V over the inner cells (physical after ensureScalarCutGeometry): the reference of the §9 se...
long rungs[4]
fluid R0, R1a, R1b, R2
The whole record: per-cell fields on the extended block (kappa and unknown haloed; the apertures comp...
long version
the Solver's geometry version this record was built for
The facet overlay (§3.5): SoA, facet index fastest. Offsets are LINEAR offsets on the block.
Kokkos::View< int *[8], Kokkos::LayoutLeft, CCMem > offF
fluid probe stencil offsets
Kokkos::View< double *[3], Kokkos::LayoutLeft, CCMem > centroid
x_phi - cell centre
Kokkos::View< long *, CCMem > cell
extended-block linear index
Kokkos::View< std::uint8_t *, CCMem > rungF
ladder rung (cs::kProbeR*)
Kokkos::View< int *, CCMem > cellFacetStart
CSR, nCut + 1 entries.
Kokkos::View< double *, CCMem > sF
fluid probe distance
Kokkos::View< int *, CCMem > body
scene instance (0: raw SDF)
Kokkos::View< double *, CCMem > alpha
|A_phi| / V
Kokkos::View< long *, CCMem > cutCell
their extended linear index
Kokkos::View< double *[3], Kokkos::LayoutLeft, CCMem > normal
n_phi (into the fluid)
Kokkos::View< double *[8], Kokkos::LayoutLeft, CCMem > wF
fluid probe weights (0: unused)
long n
facets on this rank
long nCut
cells carrying >= 1 facet