42#include <Kokkos_Core.hpp>
50#if defined(__CUDACC__) || defined(__HIPCC__)
51#define PECLET_BOTTOM_UNROLL _Pragma("unroll 16")
53#define PECLET_BOTTOM_UNROLL
57#if defined(__CUDACC__) || defined(__HIPCC__)
58#define PECLET_BOTTOM_HOST_SIMD
60#define PECLET_BOTTOM_HOST_SIMD PECLET_FLOW_OMP_SIMD
79 int bcf[6] = {0, 0, 0, 0, 0, 0};
93 for (
int f = 0; f < 6; ++f)
94 p.bcf[f] = bc[f] != 0 ? 1 : 0;
95 for (
int a = 0; a < 3; ++a)
96 per[a] = (bc[2 * a] == 0 && bc[2 * a + 1] == 0) ? 1 : 0;
97 const long ncell = (
long)inner.x * inner.y * inner.z;
98 auto longer = [&](
int a,
int c) {
return p.n[a] > p.n[c] || (p.n[a] == p.n[c] && a > c); };
100 const bool anyWall = !per[0] || !per[1] || !per[2];
101 for (
int a = 0; a < 3; ++a)
102 if ((!
anyWall || !per[a]) && (first < 0 ||
longer(a, first)))
110 for (
int a = 0; a < 3; ++a)
118 for (
int i = 0; i < 2 && s < 0; ++i)
125 p.a0 = (s == 0) ? 1 : 0;
126 p.a1 = (s == 2) ? 1 : 2;
128 p.b = (int)(
ncell / p.P);
129 p.border = (per[s] && p.P >= 3) ? 1 : 0;
134template <
class FacReal>
136 using Mat = Kokkos::View<FacReal***, Kokkos::LayoutRight, CCMem>;
137 using Sq = Kokkos::View<FacReal**, Kokkos::LayoutRight, CCMem>;
144 Kokkos::View<double*, CCMem>
s;
145 Kokkos::View<FacReal*, CCMem>
g,
u;
148 Kokkos::View<int*, CCMem>
stat;
156 const int n = p.P * p.b;
157 d.Q =
Mat(
"peclet::flow::mg_bottom_Q", p.P, p.b, p.b);
159 d.Y =
Mat(
"peclet::flow::mg_bottom_Y", p.P - 1, p.b, p.b);
160 d.e =
Sq(
"peclet::flow::mg_bottom_e", p.P, p.b);
161 d.Sg =
Sq(
"peclet::flow::mg_bottom_sigma", p.b, p.b);
162 d.L =
Sq(
"peclet::flow::mg_bottom_L", p.b, p.b);
163 d.W =
Sq(
"peclet::flow::mg_bottom_W", p.b, p.b);
164 d.s = Kokkos::View<double*, CCMem>(
"peclet::flow::mg_bottom_s",
n);
165 d.g = Kokkos::View<FacReal*, CCMem>(
"peclet::flow::mg_bottom_g",
n);
166 d.u = Kokkos::View<FacReal*, CCMem>(
"peclet::flow::mg_bottom_u",
n);
167 d.stat = Kokkos::View<int*, CCMem>(
"peclet::flow::mg_bottom_stat", 2 +
kBottomAttempts);
173 const int k = f /
pl.
b, q = f - k *
pl.
b;
174 const int c1 = q /
pl.
n[
pl.
a0];
180 return (c[0] + 1) + (c[1] + 1) *
ext.
x + (c[2] + 1) *
ext.
x *
ext.
y;
196 int i,
int f6,
int nb[3],
double&
af)
const {
197 const int a =
f6 >> 1, side =
f6 & 1;
201 int v = c[a] + (side ? 1 : -1);
205 v = (v < 0) ? v +
pl.
n[a] : v -
pl.
n[a];
208 const int st = (a == 0) ? 1 : (a == 1 ?
ext.
x :
ext.
x *
ext.
y);
209 const int slotIdx = side ? i + st : i;
217 template <
class Member,
class RV,
class ZV,
class CV>
219 const ZV* keep)
const {
220 const int P =
pl.
P, b =
pl.
b,
nn = P * b;
222 Kokkos::parallel_for(Kokkos::TeamThreadRange(t,
nn), [&](
int f) {
229 for (
int k = 0; k <
Pt; ++k) {
230 const int o = k * b, op = o - b;
231 Kokkos::parallel_for(Kokkos::TeamThreadRange(t, b), [&](
int i) {
235 for (
int j = 0; j < b; ++j)
236 acc +=
Q(k, j, i) *
u(o + j);
239 for (
int j = 0; j < b; ++j)
240 acc +=
Q(k, j, i) * (
u(o + j) -
e(k, j) *
g(op + j));
246 for (
int k =
Pt - 2; k >= 0; --k) {
247 const int o = k * b,
on = o + b;
248 Kokkos::parallel_for(Kokkos::TeamThreadRange(t, b), [&](
int i) {
251 for (
int j = 0; j < b; ++j)
252 acc +=
Q(k, j, i) * (
e(k + 1, j) *
g(
on + j));
253 g(o + i) =
g(o + i) - acc;
258 const int oB = (P - 1) * b,
oL = (P - 2) * b;
259 Kokkos::parallel_for(Kokkos::TeamThreadRange(t, b), [&](
int i) {
262 for (
int j = 0; j < b; ++j)
263 acc +=
Q(P - 1, j, i) * ((
u(oB + j) -
e(0, j) *
g(j)) -
e(P - 1, j) *
g(
oL + j));
267 Kokkos::parallel_for(Kokkos::TeamThreadRange(t, oB), [&](
int f) {
268 const int k = f / b, i = f - k * b;
271 for (
int j = 0; j < b; ++j)
272 acc +=
Y(k, j, i) *
g(oB + j);
277 Kokkos::parallel_for(Kokkos::TeamThreadRange(t,
nn), [&](
int f) {
288template <
class FacReal,
class OpV>
290 using Member = Kokkos::TeamPolicy<CCExec>::member_type;
294 using SMat = Kokkos::View<
FacReal**, Kokkos::LayoutRight,
typename CCExec::scratch_memory_space,
295 Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
301 Kokkos::View<const int*, CCMem>
comp,
kc;
302 Kokkos::View<const double*, CCMem>
aug;
306 static constexpr bool kHostFactor = std::is_same_v<CCMem, Kokkos::HostSpace>;
311 Kokkos::parallel_for(Kokkos::TeamThreadRange(t,
D.n()), [&](
int f) {
314 const int i = D.extIndex(c);
315 double sum = 0.0, af = 0.0;
316 for (int f6 = 0; f6 < 6; ++f6)
317 if (D.face(AFX, AFY, AFZ, c, i, f6, nb, af))
319 const double d = -sum;
320 D.s(f) = (comp(i) >= 0 && d > 0.0) ? 1.0 / Kokkos::sqrt(d) : 0.0;
328 const int P =
D.pl.P;
329 Kokkos::parallel_for(Kokkos::TeamThreadRange(t,
D.n()), [&](
int f) {
332 const int i = D.extIndex(c), k = c[D.pl.s], q = f - k * D.pl.b;
333 const int km = (k - 1 + P) % P;
334 double v = 0.0, af = 0.0;
335 if (km != k && (k >= 1 || D.pl.border)) {
336 const double si = D.s(f);
337 for (int f6 = 0; f6 < 6; ++f6)
338 if (D.face(AFX, AFY, AFZ, c, i, f6, nb, af) && nb[D.pl.s] == km)
339 v += si * af * D.s(D.factorIndex(nb));
348 const int b = D.pl.b,
fi = k * b + i,
fj = k * b + j;
351 const int ei = D.extIndex(c);
352 double v = (i == j) ? 1.0 : 0.0,
af = 0.0;
353 const double si = D.s(
fi);
354 for (
int f6 = 0;
f6 < 6; ++
f6)
355 if (D.face(AFX, AFY, AFZ, c,
ei,
f6, nb,
af) && D.factorIndex(nb) ==
fj)
357 const int ci = comp(
ei);
358 if (
ci >= 0 &&
ci < (
int)kc.extent(0) && kc(
ci) == k && comp(D.extOf(
fj)) ==
ci)
368 const int b = D.pl.b, P = D.pl.P;
369 Kokkos::parallel_for(Kokkos::TeamThreadRange(t, b * b), [&](
int idx) {
370 const int i =
idx / b, j =
idx - i * b;
375 a = a - D.e(k, i) * D.Q(k - 1, i, j) * D.e(k, j);
377 a = (a - D.e(0, i) * D.Y(0, j, i)) - D.e(P - 1, i) * D.Y(P - 2, j, i);
390 const int b = D.pl.b;
391 const auto& S = D.Sg;
396 const int nc = j1 - j0;
401 for (
int c = -1; c < nc; ++c) {
402 Kokkos::parallel_for(Kokkos::TeamThreadRange(t, nc), [&](
int r) {
405 const int i = j0 + r;
407 const int j = j0 + c;
409 for (
int m = 0; m < c; ++m)
410 a2 +=
Ls(i, m) *
Ls(j, m);
417 for (
int m = 0; m < r; ++m)
418 acc +=
Ls(i, m) *
Ls(i, m);
420 if (!((
double)p >
tauPiv))
432 Kokkos::parallel_for(Kokkos::TeamThreadRange(t, j1, b), [&](
int i) {
433 for (
int c = 0; c < nc; ++c) {
434 const int j = j0 + c;
436 for (
int m = 0; m < c; ++m)
437 acc +=
Ls(i, m) *
Ls(j, m);
444 const int nt = b - j1;
445 Kokkos::parallel_for(Kokkos::TeamThreadRange(t,
nt *
nt), [&](
int idx) {
450 for (
int m = 0; m < nc; ++m)
451 acc +=
Ls(i, m) *
Ls(j, m);
452 const FacReal v = S(i, j) - acc;
455 St(i - j1, j - j1) = v;
468 const int nr = i1 - i0;
469 Kokkos::parallel_for(Kokkos::TeamThreadRange(t,
nr * i0 +
nr *
nr), [&](
int idx) {
471 const int r =
idx / i0, j =
idx - r * i0, i = i0 + r;
474 for (
int m = j; m < i0; ++m)
475 acc += L(i, m) * W(m, j);
478 const int q =
idx -
nr * i0, r = q /
nr, c = q - r *
nr;
480 St(r, c) = L(i0 + r, i0 + c);
484 Kokkos::parallel_for(Kokkos::TeamThreadRange(t, i1), [&](
int j) {
489 const int i = i0 + r;
500 const int m0 = (j > i0) ? j : i0;
501 for (
int m =
m0; m < i; ++m)
502 acc +=
St(r, m - i0) *
wb[m - i0];
503 wb[r] = -acc /
St(r, r);
509 Kokkos::parallel_for(Kokkos::TeamThreadRange(t, b * b), [&](
int idx) {
510 const int i =
idx / b, j =
idx - i * b;
515 for (
int m = i; m < b; ++m)
516 acc += W(m, i) * W(m, j);
526 const int P = D.pl.P, b = D.pl.b;
527 for (
int k = 0; k <= P - 2; ++k) {
528 Kokkos::parallel_for(Kokkos::TeamThreadRange(t, b * b), [&](
int idx) {
529 const int c =
idx / b, i =
idx - c * b;
532 for (
int j = 0; j < b; ++j) {
535 bj = (k == 0 ? D.e(0, j) :
FacReal(0)) + (k == P - 2 ? D.e(P - 1, j) :
FacReal(0));
536 const FacReal br = (k == 0) ?
bj :
bj - D.e(k, j) * D.Y(k - 1, c, j);
537 acc += D.Q(k, j, i) * br;
543 for (
int k = P - 3; k >= 0; --k) {
544 Kokkos::parallel_for(Kokkos::TeamThreadRange(t, b * b), [&](
int idx) {
545 const int c =
idx / b, i =
idx - c * b;
548 for (
int j = 0; j < b; ++j)
549 acc += D.Q(k, j, i) * (D.e(k + 1, j) * D.Y(k + 1, c, j));
550 D.Y(k, c, i) = D.Y(k, c, i) - acc;
569 const FacReal* y,
int b,
int m0,
int m1,
int lo,
572 for (; m + 4 <= m1; m += 4) {
574 const FacReal y0 = y[m * b], y1 = y[(m + 1) * b],
y2 = y[(m + 2) * b],
y3 = y[(m + 3) * b];
576 for (
int i = lo; i < hi; ++i) {
585 for (; m < m1; ++m) {
589 for (
int i = lo; i < hi; ++i)
590 acc[i] += xm[i] * ym;
598 const int rank = t.team_rank(), T = t.team_size();
600 for (
int i = 0; i < n; ++i)
605 for (
int i = 0; i < n; ++i) {
606 if (lo == n &&
cum >= tot * rank / T)
608 if (
cum >= tot * (rank + 1) / T) {
622 const int b = D.pl.b, P = D.pl.P, s = D.pl.s;
625 hostShare(t, b, [](
int i) {
return (
double)(i + 1); }, lo, hi);
626 for (
int i = lo; i < hi; ++i) {
628 for (
int j = 0; j < i; ++j)
631 const int fi = k * b + i;
634 const int ei = D.extIndex(c);
635 const double si = D.s(
fi);
637 for (
int f6 = 0;
f6 < 6; ++
f6)
638 if (D.face(AFX, AFY, AFZ, c,
ei,
f6, nb,
af) && nb[s] == k) {
639 const int fj = D.factorIndex(nb);
643 const int ci = comp(
ei);
644 if (
ci >= 0 &&
ci < (
int)kc.extent(0) && kc(
ci) == k)
645 for (
int j = 0; j <= i; ++j)
646 if (comp(D.extOf(k * b + j)) ==
ci)
649 for (
int j = 0; j <= i; ++j) {
652 a = a - D.e(k, i) * D.Q(k - 1, i, j) * D.e(k, j);
654 a = (a - D.e(0, i) * D.Y(0, j, i)) - D.e(P - 1, i) * D.Y(P - 2, j, i);
667 const int b = D.pl.b, rank = t.team_rank(), T = t.team_size();
673 const int nc = j1 - j0;
674 Kokkos::single(Kokkos::PerTeam(t), [&]() {
675 for (
int r = 0; r < nc; ++r) {
676 const int i = j0 + r;
677 for (
int c = 0; c < r; ++c) {
678 const int j = j0 + c;
680 for (
int m = 0; m < c; ++m)
681 a2 +=
Lt[(j0 + m) * b + i] *
Lt[(j0 + m) * b + j];
682 Lt[j * b + i] = (S[j * b + i] - a2) /
Lt[j * b + j];
685 for (
int m = 0; m < r; ++m)
686 acc +=
Lt[(j0 + m) * b + i] *
Lt[(j0 + m) * b + i];
687 const FacReal p = S[i * b + i] - acc;
688 if (!((
double)p >
tauPiv))
690 Lt[i * b + i] = Kokkos::sqrt(p);
694 for (
int c = 0; c < nc; ++c) {
695 const int j = j0 + c;
698 for (
int i = j1; i < b; ++i)
700 hostAccumulate(acc,
Lt + j0 * b,
Lt + j0 * b + j, b, 0, c, j1, b);
705 for (
int i = j1; i < b; ++i)
706 Lj[i] = (
Sj[i] - acc[i]) /
ljj;
713 for (
int j = j1 + rank; j < b; j += T) {
716 for (
int i = j; i < b; ++i)
718 hostAccumulate(acc,
Lt + j0 * b,
Lt + j0 * b + j, b, 0, nc, j, b);
721 for (
int i = j; i < b; ++i)
722 Sj[i] =
Sj[i] - acc[i];
731 hostShare(t, b, [&](
int j) {
return (
double)(b - j) * (b - j); },
ja,
jz);
732 for (
int i =
ja; i < b; ++i) {
734 const int jt = (i <
jz) ? i :
jz;
736 for (
int j =
ja; j <
jt; ++j)
739 for (; m + 4 <= i; m += 4) {
740 hostAccumulate(acc, W,
Lt + i, b, m, m + 4,
ja, (m + 1 <
jz) ? m + 1 :
jz);
741 for (
int d = 1; d < 4 && m + d <
jz; ++d)
742 for (
int q = m + d; q < m + 4; ++q)
743 acc[m + d] +=
Lt[q * b + i] * W[q * b + m + d];
746 hostAccumulate(acc, W,
Lt + i, b, m, m + 1,
ja, (m + 1 <
jz) ? m + 1 :
jz);
750 for (
int j =
ja; j <
jt; ++j)
751 Wi[j] = -acc[j] /
lii;
758 hostShare(t, b, [&](
int i) {
return (
double)(b - i) * (i + 1); },
qa,
qz);
759 for (
int i =
qa; i <
qz; ++i) {
762 for (
int j = 0; j <= i; ++j)
764 hostAccumulate(acc, W, W + i, b, i, b, 0, i + 1);
765 for (
int j = 0; j <= i; ++j) {
766 Qk[i * b + j] = acc[j];
767 Qk[j * b + i] = acc[j];
776 const int P = D.pl.P, b = D.pl.b, rank = t.team_rank(), T = t.team_size();
777 for (
int c = rank; c < b; c += T) {
779 for (
int k = 0; k <= P - 2; ++k) {
780 for (
int j = 0; j < b; ++j) {
783 bj = (k == 0 ? D.e(0, j) :
FacReal(0)) + (k == P - 2 ? D.e(P - 1, j) :
FacReal(0));
784 br[j] = (k == 0) ?
bj :
bj - D.e(k, j) * D.Y(k - 1, c, j);
787 for (
int i = 0; i < b; ++i)
789 for (
int j = 0; j < b; ++j) {
793 for (
int i = 0; i < b; ++i)
794 acc[i] +=
Qj[i] *
bj;
798 for (
int i = 0; i < b; ++i)
801 for (
int k = P - 3; k >= 0; --k) {
803 for (
int i = 0; i < b; ++i)
805 for (
int j = 0; j < b; ++j) {
807 const FacReal y = D.e(k + 1, j) * D.Y(k + 1, c, j);
809 for (
int i = 0; i < b; ++i)
814 for (
int i = 0; i < b; ++i)
815 Yk[i] =
Yk[i] - acc[i];
822 const int P = D.pl.P;
823 const int Pt = D.pl.border ? P - 1 : P;
824 Kokkos::single(Kokkos::PerTeam(t), [&]() {
836 for (
int k = 0; k <
Pt && ok; ++k) {
837 hostAssemble(t, k, k == 0 ? 0 : 1, delta);
840 if (ok && D.pl.border) {
842 hostAssemble(t, P - 1, 2, delta);
847 Kokkos::single(Kokkos::PerTeam(t), [&]() {
848 D.stat(0) = ok ? 1 : 0;
854 const int P = D.pl.P;
855 const int Pt = D.pl.border ? P - 1 : P;
856 if constexpr (kHostFactor) {
857 if (!teamAlgorithm) {
864 Kokkos::single(Kokkos::PerTeam(t), [&]() {
876 for (
int k = 0; k <
Pt && ok; ++k) {
877 assemble(t, k, k == 0 ? 0 : 1, delta,
St);
880 if (ok && D.pl.border) {
882 assemble(t, P - 1, 2, delta,
St);
887 Kokkos::single(Kokkos::PerTeam(t), [&]() {
888 D.stat(0) = ok ? 1 : 0;
flow — portable (Kokkos) cut-cell pressure-operator face openness from an SDF.
#define PECLET_BOTTOM_HOST_SIMD
#define PECLET_BOTTOM_UNROLL
double bottomShift(int attempt)
constexpr int kBottomMaxPlane
BottomPlanes bottomChoosePlanes(C3 inner, const int bc[6])
constexpr int kBottomAttempts
constexpr int kBottomTile
constexpr double kBottomPivotTol
Kokkos::View< FacReal ***, Kokkos::LayoutRight, CCMem > Mat
int factorIndex(const int c[3]) const
Kokkos::View< FacReal *, CCMem > u
Kokkos::View< FacReal *, CCMem > g
Kokkos::View< FacReal **, Kokkos::LayoutRight, CCMem > Sq
static BottomDirect allocate(const BottomPlanes &p, C3 ext)
Kokkos::View< double *, CCMem > s
void coords(int f, int c[3]) const
bool face(const OpV &AFX, const OpV &AFY, const OpV &AFZ, const int c[3], int i, int f6, int nb[3], double &af) const
void apply(const Member &t, const RV &r, const ZV &z, const CV &comp, const ZV *keep) const
Kokkos::View< int *, CCMem > stat
int extIndex(const int c[3]) const
Kokkos::View< const double *, CCMem > aug
Kokkos::View< FacReal **, Kokkos::LayoutRight, typename CCExec::scratch_memory_space, Kokkos::MemoryTraits< Kokkos::Unmanaged > > SMat
Kokkos::View< const int *, CCMem > comp
void couplings(const Member &t) const
Kokkos::View< const int *, CCMem > kc
bool hostInvert(const Member &t, int k, double tauPiv, int flag) const
static constexpr bool kHostFactor
void assemble(const Member &t, int k, int mode, double delta, const SMat &St) const
Kokkos::TeamPolicy< CCExec >::member_type Member
void hostAssemble(const Member &t, int k, int mode, double delta) const
void scaling(const Member &t) const
static void hostAccumulate(FacReal *acc, const FacReal *x, const FacReal *y, int b, int m0, int m1, int lo, int hi)
void operator()(const Member &t) const
void border(const Member &t) const
bool invert(const Member &t, int k, double tauPiv, int flag, const SMat &Ls, const SMat &St) const
static void hostShare(const Member &t, int n, const Wf &w, int &lo, int &hi)
static std::size_t scratchBytes(int b)
double entry(int k, int i, int j, double delta) const
void hostBorder(const Member &t) const
BottomDirect< FacReal > D
void hostFactor(const Member &t) const
Kokkos::View< double *, peclet::flow::CCMem > OpV