12#ifndef PECLET_FLOW_MAC_APPROX_PROJECTION_HPP
13#define PECLET_FLOW_MAC_APPROX_PROJECTION_HPP
15#include <Kokkos_Core.hpp>
23using MConst = Kokkos::View<const float*, CCMem>;
34 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
36 "peclet::flow::center_to_face", MD(space, {1, 1, 1}, {e.x, e.y, e.z}),
37 KOKKOS_LAMBDA(
int x,
int y,
int z) {
38 const long sx = 1, sy = e.x, sz = (long)e.x * e.y;
39 const long i = (long)x + (
long)y * sy + (long)z * sz;
40 uf(i) = 0.5 * (U(i) + U(i - sx));
41 vf(i) = 0.5 * (V(i) + V(i - sy));
42 wf(i) = 0.5 * (W(i) + W(i - sz));
69 double xcen,
long idx[3],
double w[3]) {
70 const double sm = sdf(i - sa), sp = sdf(i);
71 const bool fm = sm >= 0.0, fp = sp >= 0.0;
81 const long ic = fp ? i : i - sa;
82 const double sc = fp ? sp : sm, ss = fp ? sm : sp;
83 double th = sc / (sc - ss);
84 th = th < 1e-4 ? 1e-4 : (th > 1.0 ? 1.0 : th);
92 const double xe = (xcen >= 0.0) ? xcen : th - 0.5;
95 const int cc = fp ? cFace : cFace - 1;
96 const int up = fp ? 1 : -1;
97 const long dir = fp ? -sa : sa;
98 const bool ok1 = (cc + up >= 0) && (cc + up < eAxis) && sdf(ic - dir) >= 0.0;
101 w[0] = Kokkos::fmin(xe / th, 2.0);
104 const bool ok2 = (cc + 2 * up >= 0) && (cc + 2 * up < eAxis) && sdf(ic - 2 * dir) >= 0.0;
105 const double wc = th * th / (th * th + 0.0225);
106 const double w2 = ok2 ? 0.25 : 0.0;
107 const double xc = th, xf = th + 1.0, xg = th + 2.0;
108 const double S11 = wc * xc * xc + xf * xf + w2 * xg * xg;
109 const double S12 = wc * xc * xc * xc + xf * xf * xf + w2 * xg * xg * xg;
110 const double S22 = wc * xc * xc * xc * xc + xf * xf * xf * xf + w2 * xg * xg * xg * xg + 0.01;
111 const double det = S11 * S22 - S12 * S12;
114 const double A = (S22 * xe - S12 * xe * xe) / det, B = (S11 * xe * xe - S12 * xe) / det;
116 w[0] = wc * (xc * A + xc * xc * B);
118 w[1] = xf * A + xf * xf * B;
121 idx[2] = ic - 2 * dir;
122 w[2] = w2 * (xg * A + xg * xg * B);
127 int eAxis,
double xcen) {
132 for (
int k = 0; k < n; ++k)
133 v += w[k] * U(idx[k]);
145 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
146 Kokkos::parallel_for(
147 "peclet::flow::face_centroid_dist", MD(space, {1, 1, 1}, {e.x, e.y, e.z}),
148 KOKKOS_LAMBDA(
int x,
int y,
int z) {
149 const long sx = 1, sy = e.x, sz = (long)e.x * e.y;
150 const long i = (long)x + (
long)y * sy + (long)z * sz;
153 const double fc[3][3] = {{x - 0.5, (double)y, (
double)z},
154 {(double)x, y - 0.5, (
double)z},
155 {(double)x, (
double)y, z - 0.5}};
156 const long st[3] = {sx, sy, sz};
157 CCField out[3] = {xcx, xcy, xcz};
158 for (
int a = 0; a < 3; ++a) {
159 const double sm = sdf(i - st[a]), sp = sdf(i);
160 if ((sm >= 0.0) == (sp >= 0.0)) {
164 const double dir = (sm < 0.0) ? -1.0 : 1.0;
165 const int t1 = (a + 1) % 3, t2 = (a + 2) % 3;
166 double c1 = 0.0, c2 = 0.0;
168 for (
int j1 = 0; j1 < 4; ++j1)
169 for (
int j2 = 0; j2 < 4; ++j2) {
170 const double o1 = -0.375 + 0.25 * j1, o2 = -0.375 + 0.25 * j2;
171 double p[3] = {fc[a][0], fc[a][1], fc[a][2]};
184 double p0[3] = {fc[a][0], fc[a][1], fc[a][2]};
185 p0[t1] += c1 / nOpen;
186 p0[t2] += c2 / nOpen;
187 double p1[3] = {p0[0], p0[1], p0[2]};
189 const double s0 =
ccSampleExt(sdf, e, p0[0], p0[1], p0[2]);
190 const double s1 =
ccSampleExt(sdf, e, p1[0], p1[1], p1[2]);
191 double d = (s0 > 0.0 && s0 - s1 > 1e-12) ? s0 / (s0 - s1) : 0.0;
192 out[a](i) = d < 0.0 ? 0.0 : (d > 2.0 ? 2.0 : d);
204 bool useCen,
C3 e,
int g) {
207 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
208 Kokkos::parallel_for(
209 "peclet::flow::center_to_face_wall", MD(space, {1, 1, 1}, {e.x, e.y, e.z}),
210 KOKKOS_LAMBDA(
int x,
int y,
int z) {
211 const long sx = 1, sy = e.x, sz = (long)e.x * e.y;
212 const long i = (long)x + (
long)y * sy + (long)z * sz;
236 bool useCen,
int axis,
C3 e,
int g) {
238 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
239 Kokkos::parallel_for(
240 "peclet::flow::transpose_grad_wall", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
241 KOKKOS_LAMBDA(
int x,
int y,
int z) {
242 const long sx = 1, sy = e.x, sz = (long)e.x * e.y;
243 const long i = (long)x + (
long)y * sy + (long)z * sz;
244 const long sa = (axis == 0) ? sx : (axis == 1) ? sy : sz;
245 const int eA = (axis == 0) ? e.x : (axis == 1) ? e.y : e.z;
246 const int ca = (axis == 0) ? x : (axis == 1) ? y : z;
250 for (
int m = -2; m <= 3; ++m) {
251 const int cf = ca + m;
252 if (cf < 1 || cf >= eA)
254 const long f = i + (long)m * sa;
256 for (
int k = 0; k < n; ++k)
258 acc += w[k] * o(f) * (p(f) - p(f - sa));
270 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
271 Kokkos::parallel_for(
272 "peclet::flow::cell_fraction", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
273 KOKKOS_LAMBDA(
int x,
int y,
int z) {
274 const long i = (long)x + (
long)y * e.x + (long)z * (
long)e.x * e.y;
275 const double sc = sdf(i);
277 const long sx = 1, sy = e.x, sz = (long)e.x * e.y;
278 const bool f0 = sc >= 0.0;
279 const bool cut = (sdf(i + sx) >= 0.0) != f0 || (sdf(i - sx) >= 0.0) != f0 ||
280 (sdf(i + sy) >= 0.0) != f0 || (sdf(i - sy) >= 0.0) != f0 ||
281 (sdf(i + sz) >= 0.0) != f0 || (sdf(i - sz) >= 0.0) != f0;
283 cs(i) = sc >= 0.0 ? 1.0 : 0.0;
287 for (
int j0 = 0; j0 < 4; ++j0)
288 for (
int j1 = 0; j1 < 4; ++j1)
289 for (
int j2 = 0; j2 < 4; ++j2) {
290 const double o0 = -0.375 + 0.25 * j0, o1 = -0.375 + 0.25 * j1,
291 o2 = -0.375 + 0.25 * j2;
292 if (
ccSampleExt(sdf, e, x + o0, y + o1, z + o2) > 0.0)
307 CCConst oz,
double mu,
double idt,
C3 e,
int g) {
309 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
310 Kokkos::parallel_for(
311 "peclet::flow::fv_viscous_apply", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
312 KOKKOS_LAMBDA(
int x,
int y,
int z) {
313 const long sx = 1, sy = e.x, sz = (long)e.x * e.y;
314 const long st[3] = {sx, sy, sz};
315 const long i = (long)x + (
long)y * sy + (long)z * sz;
318 double diag = 0.0, offs = 0.0, aw = 0.0;
319 for (
int a = 0; a < 3; ++a) {
320 const double om = oa[a](i), op = oa[a](i + st[a]);
324 offs += om * U(i - st[a]) + op * U(i + st[a]);
325 aw += (W[a] < 0.0 ? -W[a] : W[a]);
330 double nx = 0.5 * (sdf(i + sx) - sdf(i - sx));
331 double ny = 0.5 * (sdf(i + sy) - sdf(i - sy));
332 double nz = 0.5 * (sdf(i + sz) - sdf(i - sz));
333 double nn = Kokkos::sqrt(nx * nx + ny * ny + nz * nz);
338 const double nv[3] = {nx, ny, nz};
339 const double sdi = sdf(i);
343 auto cl = [](
double v,
double hi) {
return v < 1.0 ? 1.0 : (v > hi ? hi : v); };
344 const double px = cl(x - sdi * nx, e.x - 2.0);
345 const double py = cl(y - sdi * ny, e.y - 2.0);
346 const double pz = cl(z - sdi * nz, e.z - 2.0);
347 for (
int a = 0; a < 3; ++a) {
348 const double sg = nv[a] >= 0.0 ? 1.0 : -1.0;
349 const double u1 =
ccSampleExt(U, e, px + (a == 0 ? sg : 0.0),
350 py + (a == 1 ? sg : 0.0), pz + (a == 2 ? sg : 0.0));
352 ccSampleExt(U, e, px + (a == 0 ? 2.0 * sg : 0.0), py + (a == 1 ? 2.0 * sg : 0.0),
353 pz + (a == 2 ? 2.0 * sg : 0.0));
354 wall += W[a] * sg * (2.0 * u1 - 0.5 * u2);
362 Lu(i) = idt * cs(i) * U(i) + mu * (diag * U(i) - offs - wall);
368KOKKOS_INLINE_FUNCTION
double eQuad(
double xx,
double a1,
double a2,
double a3) {
369 return (a1 * (xx - 1.0) + a3 * (xx + 1.0)) * xx * 0.5 - a2 * (xx - 1.0) * (xx + 1.0);
384 int z,
double nx,
double ny,
double nz,
385 double px,
double py,
double pz) {
386 const double nv[3] = {nx, ny, nz}, pv[3] = {px, py, pz};
387 const int ci[3] = {x, y, z}, ext[3] = {e.x, e.y, e.z};
388 const long st[3] = {1, (long)e.x, (
long)e.x * e.y};
390 double best = Kokkos::fabs(nv[0]);
391 if (Kokkos::fabs(nv[1]) > best) {
392 best = Kokkos::fabs(nv[1]);
395 if (Kokkos::fabs(nv[2]) > best)
397 const int t1 = (da + 1) % 3, t2 = (da + 2) % 3;
398 const double sgn = nv[da] >= 0.0 ? 1.0 : -1.0;
399 auto clampi = [](
int v,
int n) {
return v < 0 ? 0 : (v >= n ? n - 1 : v); };
400 auto rd = [](
double v) {
401 double r = v >= 0.0 ? Kokkos::floor(v + 0.5) : Kokkos::ceil(v - 0.5);
402 return r > 1.0 ? 1.0 : (r < -1.0 ? -1.0 : r);
406 for (
int l = 0; l < 2; ++l) {
407 const int io = (l + 1) * (
int)sgn;
408 const double dl = ((double)io - pv[da]) / nv[da];
409 const double y1 = pv[t1] + dl * nv[t1], z1 = pv[t2] + dl * nv[t2];
410 const int jj = (int)rd(y1), kk = (int)rd(z1);
411 const double ly = y1 - jj, lz = z1 - kk;
414 for (
int dk = -1; dk <= 1; ++dk)
415 for (
int dj = -1; dj <= 1; ++dj) {
417 cc[da] = ci[da] + io;
418 cc[t1] = ci[t1] + jj + dj;
419 cc[t2] = ci[t2] + kk + dk;
420 const long idx = (long)clampi(cc[0], ext[0]) * st[0] + (long)clampi(cc[1], ext[1]) * st[1] +
421 (long)clampi(cc[2], ext[2]) * st[2];
422 vv[dj + 1][dk + 1] = U(idx);
423 sf[dj + 1][dk + 1] = sdf(idx) >= 0.0;
426 for (
int a2 = 0; a2 < 3; ++a2)
427 for (
int b2 = 0; b2 < 3; ++b2)
428 full = full && sf[a2][b2];
429 const bool home = sf[1][1];
431 eQuad(lz,
eQuad(ly, vv[0][0], vv[1][0], vv[2][0]),
eQuad(ly, vv[0][1], vv[1][1], vv[2][1]),
432 eQuad(ly, vv[0][2], vv[1][2], vv[2][2]));
433 double vbl = vv[1][1];
435 const int fp = ly >= 0.0 ? 2 : 0, fm = ly >= 0.0 ? 0 : 2;
437 vbl += Kokkos::fabs(ly) * (vv[fp][1] - vv[1][1]);
439 vbl += Kokkos::fabs(ly) * (vv[1][1] - vv[fm][1]);
442 const int fp = lz >= 0.0 ? 2 : 0, fm = lz >= 0.0 ? 0 : 2;
444 vbl += Kokkos::fabs(lz) * (vv[1][fp] - vv[1][1]);
446 vbl += Kokkos::fabs(lz) * (vv[1][1] - vv[1][fm]);
448 vL[l] = full ? vbq : vbl;
450 defd[l] = full || home;
452 if (defd[0] && defd[1]) {
453 const double d0 = dL[0], d1 = dL[1], v0 = vL[0], v1 = vL[1];
454 return (v0 * d1 / d0 - v1 * d0 / d1) / (d1 - d0);
457 return vL[0] / dL[0];
458 double d0 = Kokkos::fabs(pv[da] / nv[da]);
461 const long ii = (long)ci[0] * st[0] + (
long)ci[1] * st[1] + (long)ci[2] * st[2];
475 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
476 Kokkos::parallel_for(
477 "peclet::flow::embed_viscous_apply", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
478 KOKKOS_LAMBDA(
int x,
int y,
int z) {
479 const long sx = 1, sy = e.x, sz = (long)e.x * e.y;
480 const long st[3] = {sx, sy, sz};
481 const long i = (long)x + (
long)y * sy + (long)z * sz;
484 double diag = 0.0, offs = 0.0;
485 for (
int a = 0; a < 3; ++a) {
486 const double om = oa[a](i), op = oa[a](i + st[a]);
489 offs += om * U(i - st[a]) + op * U(i + st[a]);
491 const double area = Kokkos::sqrt(Wv[0] * Wv[0] + Wv[1] * Wv[1] + Wv[2] * Wv[2]);
494 double nx = 0.5 * (sdf(i + sx) - sdf(i - sx));
495 double ny = 0.5 * (sdf(i + sy) - sdf(i - sy));
496 double nz = 0.5 * (sdf(i + sz) - sdf(i - sz));
497 const double nn = Kokkos::sqrt(nx * nx + ny * ny + nz * nz);
502 const double sdi = sdf(i);
503 const double dudn =
embedDirichletGradient(U, sdf, e, x, y, z, nx, ny, nz, -sdi * nx,
504 -sdi * ny, -sdi * nz);
508 Lu(i) = idt * cs(i) * U(i) + mu * (diag * U(i) - offs + wall);
518 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
519 Kokkos::parallel_for(
520 "peclet::flow::stencil_matvec", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
521 KOKKOS_LAMBDA(
int x,
int y2,
int z) {
522 const long sx = 1, sy = e.x, sz = (long)e.x * e.y;
523 const long i = (long)x + (
long)y2 * sy + (long)z * sz;
524 y(i) = (double)
AC(i) * u(i) + (double)AW(i) * u(i - sx) + (double)AE(i) * u(i + sx) +
525 (double)AS(i) * u(i - sy) + (double)AN(i) * u(i + sy) + (double)AB(i) * u(i - sz) +
526 (double)AT(i) * u(i + sz);
533 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
534 Kokkos::parallel_for(
535 "peclet::flow::subtract_field", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
536 KOKKOS_LAMBDA(
int x,
int y,
int z) {
537 const long i = (long)x + (
long)y * e.x + (long)z * (
long)e.x * e.y;
552 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
553 Kokkos::parallel_for(
554 "peclet::flow::center_grad_open", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
555 KOKKOS_LAMBDA(
int x,
int y,
int z) {
556 const long sx = 1, sy = e.x, sz = (long)e.x * e.y;
557 const long i = (long)x + (
long)y * sy + (long)z * sz;
558 const long sa = (axis == 0) ? sx : (axis == 1) ? sy : sz;
559 const double om = o(i), op = o(i + sa);
560 out(i) = (om * (p(i) - p(i - sa)) + op * (p(i + sa) - p(i))) / (om + op + 1e-12);
570 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
571 Kokkos::parallel_for(
572 "peclet::flow::correct_center_open", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
573 KOKKOS_LAMBDA(
int x,
int y,
int z) {
574 const long sx = 1, sy = e.x, sz = (long)e.x * e.y;
575 const long i = (long)x + (
long)y * sy + (long)z * sz;
576 const double omx = ox(i), opx = ox(i + sx);
577 const double omy = oy(i), opy = oy(i + sy);
578 const double omz = oz(i), opz = oz(i + sz);
579 u(i) -= (omx * (phi(i) - phi(i - sx)) + opx * (phi(i + sx) - phi(i))) / (omx + opx + 1e-12);
580 v(i) -= (omy * (phi(i) - phi(i - sy)) + opy * (phi(i + sy) - phi(i))) / (omy + opy + 1e-12);
581 w(i) -= (omz * (phi(i) - phi(i - sz)) + opz * (phi(i + sz) - phi(i))) / (omz + opz + 1e-12);
603 using MD = Kokkos::MDRangePolicy<CCExec, Kokkos::Rank<3>>;
604 Kokkos::parallel_for(
605 "peclet::flow::correct_center", MD(space, {g, g, g}, {e.x - g, e.y - g, e.z - g}),
606 KOKKOS_LAMBDA(
int x,
int y,
int z) {
607 const long sx = 1, sy = e.x, sz = (long)e.x * e.y;
608 const long i = (long)x + (
long)y * sy + (long)z * sz;
609 const double gm_x = (ox(i) > 1e-12) ? (phi(i) - phi(i - sx)) : 0.0;
610 const double gp_x = (ox(i + sx) > 1e-12) ? (phi(i + sx) - phi(i)) : 0.0;
611 const double gm_y = (oy(i) > 1e-12) ? (phi(i) - phi(i - sy)) : 0.0;
612 const double gp_y = (oy(i + sy) > 1e-12) ? (phi(i + sy) - phi(i)) : 0.0;
613 const double gm_z = (oz(i) > 1e-12) ? (phi(i) - phi(i - sz)) : 0.0;
614 const double gp_z = (oz(i + sz) > 1e-12) ? (phi(i + sz) - phi(i)) : 0.0;
615 u(i) -= 0.5 * (gm_x + gp_x);
616 v(i) -= 0.5 * (gm_y + gp_y);
617 w(i) -= 0.5 * (gm_z + gp_z);
flow — portable (Kokkos) cut-cell pressure-operator face openness from an SDF.
void transposeGradWallAware(CCField out, CCConst p, CCConst sdf, CCConst o, CCConst xc, bool useCen, int axis, C3 e, int g)
void projectCorrectCenterOpen(CCField u, CCField v, CCField w, CCConst phi, CCConst ox, CCConst oy, CCConst oz, C3 e, int g)
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 stencilMatvec(CCField y, CCConst u, MConst AC, MConst AW, MConst AE, MConst AS, MConst AN, MConst AB, MConst AT, C3 e, int g)
void buildCellFraction(CCField cs, CCConst sdf, C3 e, int g)
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 fvViscousApply(CCField Lu, CCConst U, CCConst sdf, CCConst cs, CCConst ox, CCConst oy, CCConst oz, double mu, double idt, C3 e, int g)
void centerGradOpen(CCField out, CCConst p, CCConst o, int axis, C3 e, int g)
void embedViscousApply(CCField Lu, CCConst U, CCConst sdf, CCConst cs, CCConst ox, CCConst oy, CCConst oz, double mu, double idt, 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])
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)
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
static constexpr double AC