12#ifndef PECLET_FLOW_MAC_APPROX_PROJECTION_HPP
13#define PECLET_FLOW_MAC_APPROX_PROJECTION_HPP
15#include <Kokkos_Core.hpp>
24using MConst = Kokkos::View<const float*, CCMem>;
37 "peclet::flow::center_to_face",
MD(
space, {1, 1, 1}, {e.x, e.y, e.z}),
39 const long sx = 1, sy = e.x, sz = (
long)e.x * e.y;
40 const long i = (
long)x + (
long)y * sy + (
long)z * sz;
41 uf(i) = 0.5 * (
U(i) +
U(i -
sx));
42 vf(i) = 0.5 * (V(i) + V(i - sy));
43 wf(i) = 0.5 * (W(i) + W(i - sz));
70 double xcen,
long idx[3],
double w[3]) {
71 const double sm = sdf(i -
sa), sp = sdf(i);
72 const bool fm =
sm >= 0.0,
fp = sp >= 0.0;
82 const long ic =
fp ? i : i -
sa;
83 const double sc =
fp ? sp :
sm, ss =
fp ?
sm : sp;
84 double th = sc / (sc - ss);
85 th = th < 1e-4 ? 1e-4 : (th > 1.0 ? 1.0 : th);
93 const double xe = (
xcen >= 0.0) ?
xcen : th - 0.5;
97 const int up =
fp ? 1 : -1;
98 const long dir =
fp ? -
sa :
sa;
99 const bool ok1 = (cc +
up >= 0) && (cc +
up <
eAxis) && sdf(
ic - dir) >= 0.0;
102 w[0] = Kokkos::fmin(xe / th, 2.0);
105 const bool ok2 = (cc + 2 *
up >= 0) && (cc + 2 *
up <
eAxis) && sdf(
ic - 2 * dir) >= 0.0;
106 const double wc = th * th / (th * th + 0.0225);
107 const double w2 = ok2 ? 0.25 : 0.0;
108 const double xc = th, xf = th + 1.0,
xg = th + 2.0;
109 const double S11 =
wc * xc * xc + xf * xf +
w2 *
xg *
xg;
110 const double S12 =
wc * xc * xc * xc + xf * xf * xf +
w2 *
xg *
xg *
xg;
111 const double S22 =
wc * xc * xc * xc * xc + xf * xf * xf * xf +
w2 *
xg *
xg *
xg *
xg + 0.01;
115 const double A = (
S22 * xe -
S12 * xe * xe) /
det, B = (
S11 * xe * xe -
S12 * xe) /
det;
117 w[0] =
wc * (xc * A + xc * xc * B);
119 w[1] = xf * A + xf * xf * B;
122 idx[2] =
ic - 2 * dir;
133 for (
int k = 0; k < n; ++k)
134 v += w[k] *
U(
idx[k]);
147 Kokkos::parallel_for(
148 "peclet::flow::face_centroid_dist",
MD(
space, {1, 1, 1}, {e.x, e.y, e.z}),
150 const long sx = 1, sy = e.x, sz = (
long)e.x * e.y;
151 const long i = (
long)x + (
long)y * sy + (
long)z * sz;
154 const double fc[3][3] = {{x - 0.5, (
double)y, (
double)z},
155 {(
double)x, y - 0.5, (
double)z},
156 {(
double)x, (
double)y, z - 0.5}};
157 const long st[3] = {
sx, sy, sz};
159 for (
int a = 0; a < 3; ++a) {
160 const double sm = sdf(i - st[a]), sp = sdf(i);
161 if ((
sm >= 0.0) == (sp >= 0.0)) {
165 const double dir = (
sm < 0.0) ? -1.0 : 1.0;
166 const int t1 = (a + 1) % 3,
t2 = (a + 2) % 3;
167 double c1 = 0.0, c2 = 0.0;
169 for (
int j1 = 0; j1 < 4; ++j1)
170 for (
int j2 = 0;
j2 < 4; ++
j2) {
171 const double o1 = -0.375 + 0.25 * j1,
o2 = -0.375 + 0.25 *
j2;
172 double p[3] = {fc[a][0], fc[a][1], fc[a][2]};
185 double p0[3] = {fc[a][0], fc[a][1], fc[a][2]};
188 double p1[3] = {p0[0], p0[1], p0[2]};
190 const double s0 =
ccSampleExt(sdf, e, p0[0], p0[1], p0[2]);
192 double d = (s0 > 0.0 && s0 - s1 > 1e-12) ? s0 / (s0 - s1) : 0.0;
193 out[a](i) = d < 0.0 ? 0.0 : (d > 2.0 ? 2.0 : d);
209 Kokkos::parallel_for(
210 "peclet::flow::center_to_face_wall",
MD(
space, {1, 1, 1}, {e.x, e.y, e.z}),
212 const long sx = 1, sy = e.x, sz = (
long)e.x * e.y;
213 const long i = (
long)x + (
long)y * sy + (
long)z * sz;
243 bool useCen,
int axis,
C3 e,
int g,
double wa = 1.0) {
246 Kokkos::parallel_for(
247 "peclet::flow::transpose_grad_wall",
MD(
space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
249 const long sx = 1, sy = e.x, sz = (
long)e.x * e.y;
250 const long i = (
long)x + (
long)y * sy + (
long)z * sz;
251 const long sa = (axis == 0) ?
sx : (axis == 1) ? sy : sz;
252 const int eA = (axis == 0) ? e.x : (axis == 1) ? e.y : e.z;
253 const int ca = (axis == 0) ? x : (axis == 1) ? y : z;
257 for (
int m = -2; m <= 3; ++m) {
258 const int cf = ca + m;
261 const long f = i + (
long)m *
sa;
263 for (
int k = 0; k < n; ++k)
265 acc += w[k] * o(f) * (p(f) - p(f -
sa));
278 Kokkos::parallel_for(
279 "peclet::flow::cell_fraction",
MD(
space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
281 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
282 const double sc = sdf(i);
284 const long sx = 1, sy = e.x, sz = (
long)e.x * e.y;
285 const bool f0 = sc >= 0.0;
286 const bool cut = (sdf(i +
sx) >= 0.0) !=
f0 || (sdf(i -
sx) >= 0.0) !=
f0 ||
287 (sdf(i + sy) >= 0.0) !=
f0 || (sdf(i - sy) >= 0.0) !=
f0 ||
288 (sdf(i + sz) >= 0.0) !=
f0 || (sdf(i - sz) >= 0.0) !=
f0;
290 cs(i) = sc >= 0.0 ? 1.0 : 0.0;
294 for (
int j0 = 0; j0 < 4; ++j0)
295 for (
int j1 = 0; j1 < 4; ++j1)
296 for (
int j2 = 0;
j2 < 4; ++
j2) {
297 const double o0 = -0.375 + 0.25 * j0,
o1 = -0.375 + 0.25 * j1,
298 o2 = -0.375 + 0.25 *
j2;
308 return (a1 * (
xx - 1.0) +
a3 * (
xx + 1.0)) *
xx * 0.5 - a2 * (
xx - 1.0) * (
xx + 1.0);
331 int z,
double nx,
double ny,
double nz,
332 double px,
double py,
double pz) {
333 const double nv[3] = {nx, ny, nz}, pv[3] = {px, py, pz};
334 const int ci[3] = {x, y, z}, ext[3] = {e.x, e.y, e.z};
335 const long st[3] = {1, (
long)e.x, (
long)e.x * e.y};
337 double best = Kokkos::fabs(
nv[0]);
338 if (Kokkos::fabs(
nv[1]) >
best) {
339 best = Kokkos::fabs(
nv[1]);
342 if (Kokkos::fabs(
nv[2]) >
best)
344 const int t1 = (
da + 1) % 3,
t2 = (
da + 2) % 3;
345 const double sgn =
nv[
da] >= 0.0 ? 1.0 : -1.0;
346 auto clampi = [](
int v,
int n) {
return v < 0 ? 0 : (v >= n ? n - 1 : v); };
347 auto rd = [](
double v) {
348 double r = v >= 0.0 ? Kokkos::floor(v + 0.5) : Kokkos::ceil(v - 0.5);
349 return r > 1.0 ? 1.0 : (r < -1.0 ? -1.0 : r);
353 for (
int l = 0; l < 2; ++l) {
354 const int io = (l + 1) * (
int)sgn;
361 for (
int dk = -1; dk <= 1; ++dk)
362 for (
int dj = -1;
dj <= 1; ++
dj) {
370 sf[
dj + 1][dk + 1] = sdf(
idx) >= 0.0;
373 for (
int a2 = 0; a2 < 3; ++a2)
374 for (
int b2 = 0;
b2 < 3; ++
b2)
376 const bool home = sf[1][1];
380 double vbl =
vv[1][1];
382 const int fp =
ly >= 0.0 ? 2 : 0,
fm =
ly >= 0.0 ? 0 : 2;
389 const int fp =
lz >= 0.0 ? 2 : 0,
fm =
lz >= 0.0 ? 0 : 2;
401 return (
v0 *
d1 / d0 -
v1 * d0 /
d1) / (
d1 - d0);
404 return vL[0] /
dL[0];
405 double d0 = Kokkos::fabs(pv[
da] /
nv[
da]);
417 const long ii = (
long)
ci[0] * st[0] + (
long)
ci[1] * st[1] + (
long)
ci[2] * st[2];
435 double wx = 1.0,
double wy = 1.0,
double wz = 1.0,
double hpx = 1.0,
436 double hpy = 1.0,
double hpz = 1.0) {
439 Kokkos::parallel_for(
440 "peclet::flow::embed_viscous_apply",
MD(
space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
442 const long sx = 1, sy = e.x, sz = (
long)e.x * e.y;
443 const long st[3] = {
sx, sy, sz};
444 const long i = (
long)x + (
long)y * sy + (
long)z * sz;
448 double diag = 0.0, offs = 0.0;
449 for (
int a = 0; a < 3; ++a) {
450 const double om =
oa[a](i), op =
oa[a](i + st[a]);
452 diag +=
wv[a] * (
om + op);
453 offs +=
wv[a] * (
om *
U(i - st[a]) + op *
U(i + st[a]));
459 double nx = 0.5 * (sdf(i +
sx) - sdf(i -
sx)) /
hpx;
460 double ny = 0.5 * (sdf(i + sy) - sdf(i - sy)) /
hpy;
461 double nz = 0.5 * (sdf(i + sz) - sdf(i - sz)) /
hpz;
462 const double nn = Kokkos::sqrt(nx * nx + ny * ny + nz * nz);
467 const double mx = nx /
hpx, my = ny /
hpy, mz = nz /
hpz;
468 const double sdi = sdf(i);
469 const double dudn =
embedDirichletGradient(
U, sdf, e, x, y, z, mx, my, mz, -
sdi * mx,
474 Lu(i) = idt * cs(i) *
U(i) + mu * (diag *
U(i) - offs + wall);
486 Kokkos::parallel_for(
487 "peclet::flow::stencil_matvec",
MD(
space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
489 const long sx = 1, sy = e.x, sz = (
long)e.x * e.y;
490 const long i = (
long)x + (
long)
y2 * sy + (
long)z * sz;
493 (
double)AT(i) * u(i + sz);
502 Kokkos::parallel_for(
503 "peclet::flow::subtract_field",
MD(
space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
505 const long i = (
long)x + (
long)y * e.x + (
long)z * (
long)e.x * e.y;
522 Kokkos::parallel_for(
523 "peclet::flow::center_grad_open",
MD(
space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
525 const long sx = 1, sy = e.x, sz = (
long)e.x * e.y;
526 const long i = (
long)x + (
long)y * sy + (
long)z * sz;
527 const long sa = (axis == 0) ?
sx : (axis == 1) ? sy : sz;
528 const double om = o(i), op = o(i +
sa);
529 out(i) =
wa * ((
om * (p(i) - p(i -
sa)) + op * (p(i +
sa) - p(i))) / (
om + op + 1e-12));
538 double wy = 1.0,
double wz = 1.0) {
541 Kokkos::parallel_for(
542 "peclet::flow::correct_center_open",
MD(
space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
544 const long sx = 1, sy = e.x, sz = (
long)e.x * e.y;
545 const long i = (
long)x + (
long)y * sy + (
long)z * sz;
546 const double omx = ox(i),
opx = ox(i +
sx);
547 const double omy = oy(i),
opy = oy(i + sy);
548 const double omz = oz(i),
opz = oz(i + sz);
549 u(i) -=
wx * ((
omx * (phi(i) - phi(i -
sx)) +
opx * (phi(i +
sx) - phi(i))) /
551 v(i) -=
wy * ((
omy * (phi(i) - phi(i - sy)) +
opy * (phi(i + sy) - phi(i))) /
553 w(i) -=
wz * ((
omz * (phi(i) - phi(i - sz)) +
opz * (phi(i + sz) - phi(i))) /
575 double wy = 1.0,
double wz = 1.0) {
578 Kokkos::parallel_for(
579 "peclet::flow::correct_center",
MD(
space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
581 const long sx = 1, sy = e.x, sz = (
long)e.x * e.y;
582 const long i = (
long)x + (
long)y * sy + (
long)z * sz;
583 const double gm_x = (ox(i) > 1e-12) ? (phi(i) - phi(i -
sx)) : 0.0;
584 const double gp_x = (ox(i +
sx) > 1e-12) ? (phi(i +
sx) - phi(i)) : 0.0;
585 const double gm_y = (oy(i) > 1e-12) ? (phi(i) - phi(i - sy)) : 0.0;
586 const double gp_y = (oy(i + sy) > 1e-12) ? (phi(i + sy) - phi(i)) : 0.0;
587 const double gm_z = (oz(i) > 1e-12) ? (phi(i) - phi(i - sz)) : 0.0;
588 const double gp_z = (oz(i + sz) > 1e-12) ? (phi(i + sz) - phi(i)) : 0.0;
flow — portable (Kokkos) cut-cell pressure-operator face openness from an SDF.
void stencilMatvec(CCField y, CCConst u, MC AC, MC AW, MC AE, MC AS, MC AN, MC AB, MC AT, C3 e, int g)
void centerGradOpen(CCField out, CCConst p, CCConst o, int axis, C3 e, int g, double wa=1.0)
double eQuad(double xx, double a1, double a2, double a3)
void buildFaceCentroidDist(CCField xcx, CCField xcy, CCField xcz, CCConst sdf, C3 e)
void subtractField(CCField u, CCConst d, C3 e, int g)
void buildCellFraction(CCField cs, CCConst sdf, C3 e, int g)
void transposeGradWallAware(CCField out, CCConst p, CCConst sdf, CCConst o, CCConst xc, bool useCen, int axis, C3 e, int g, double wa=1.0)
void projectCorrectCenterOpen(CCField u, CCField v, CCField w, CCConst phi, CCConst ox, CCConst oy, CCConst oz, C3 e, int g, double wx=1.0, double wy=1.0, double wz=1.0)
double embedDirichletGradient(CCConst U, CCConst sdf, C3 e, int x, int y, int z, double nx, double ny, double nz, double px, double py, double pz)
void centerToFaceWallAware(CCField uf, CCField vf, CCField wf, CCConst U, CCConst V, CCConst W, CCConst sdf, CCConst xcx, CCConst xcy, CCConst xcz, bool useCen, C3 e, int g)
void centerToFace(CCField uf, CCField vf, CCField wf, CCConst U, CCConst V, CCConst W, C3 e, int g)
int wallAwareFaceStencil(CCConst sdf, long i, long sa, int cFace, int eAxis, double xcen, long idx[3], double w[3])
void embedViscousApply(CCField Lu, CCConst U, CCConst sdf, CCConst cs, CCConst ox, CCConst oy, CCConst oz, double mu, double idt, C3 e, int g, double wx=1.0, double wy=1.0, double wz=1.0, double hpx=1.0, double hpy=1.0, double hpz=1.0)
Kokkos::View< double *, CCMem > CCField
Kokkos::DefaultExecutionSpace CCExec
void projectCorrectCenter(CCField u, CCField v, CCField w, CCConst phi, CCConst ox, CCConst oy, CCConst oz, C3 e, int g, double wx=1.0, double wy=1.0, double wz=1.0)
Kokkos::View< const float *, CCMem > MConst
double ccSampleExt(CCConst sdf, C3 ext, double x, double y, double z)
double wallAwareFaceValue(CCConst U, CCConst sdf, long i, long sa, int cFace, int eAxis, double xcen)
Kokkos::View< const double *, CCMem > CCConst
flow — the multidimensional iteration policies: iteration order follows storage.
static constexpr double AC
static constexpr double U