flow 1.3.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
star_elimination.hpp
Go to the documentation of this file.
1
22#ifndef PECLET_FLOW_STAR_ELIMINATION_HPP
23#define PECLET_FLOW_STAR_ELIMINATION_HPP
24
25#include <Kokkos_Core.hpp>
26
27#include "mac_cutcell.hpp" // CCField/CCConst, C3, CCExec, CCMem
28#include "policy.hpp"
29
30namespace peclet::flow {
31
37 Kokkos::View<int*, CCMem> cell;
38 // [slot*6+k]. DOUBLE since P2: this is the masked face openness, and the openness source
39 // (Level::ox/oy/oz) is double — storing it float made the star row a float-rounded copy of a
40 // coefficient the solver already holds exactly. Gate-off reads it back through (float) so the
41 // default path is bitwise what it was; see starAval().
42 Kokkos::View<double*, CCMem> a;
43};
44
46 StarOverlay ov;
47 ov.cell = Kokkos::View<int*, CCMem>("star_cell", n);
48 ov.a = Kokkos::View<double*, CCMem>("star_a", 6 * n);
49 return ov;
50}
51
55KOKKOS_INLINE_FUNCTION double starAval(const StarOverlay& ov, long k, bool exact) {
56 const double v = ov.a(k);
57 // Deliberate bit-compat gate (not an operator-precision leak): OFF reproduces the float-rounded
58 // value the overlay used to store (bitwise unchanged default path), ON returns the exact double.
59 return exact ? v : (double)(float)v; // PRECISION-EXEMPT: bit-compat gate, see above
60}
61
63 v %= n;
64 return v < 0 ? v + n : v;
65}
66
72inline int buildStarOverlay(CCConst sdf, CCConst ox, CCConst oy, CCConst oz, C3 ext, int g, C3 nn,
73 const StarOverlay& ov, Kokkos::View<int, CCMem> counter) {
75 Kokkos::deep_copy(counter, 0);
76 const bool fill = ov.cell.extent(0) > 0;
77 using MD = MDRange3<CCExec>;
78 Kokkos::parallel_for(
79 "peclet::flow::star_build", MD(space, {0, 0, 0}, {nn.x, nn.y, nn.z}),
80 KOKKOS_LAMBDA(int x, int y, int z) {
81 const long sx = 1, sy = ext.x, sz = (long)ext.x * ext.y;
82 const long st[3] = {sx, sy, sz};
83 const long i = (long)(x + g) + (long)(y + g) * sy + (long)(z + g) * sz;
84 if (sdf(i) >= 0.0)
85 return; // fluid-centered: not eliminated
86 CCConst oa[3] = {ox, oy, oz};
87 double av[6];
88 double D = 0.0;
89 for (int a2 = 0; a2 < 3; ++a2) {
90 const double op = oa[a2](i + st[a2]), om = oa[a2](i); // +side face / -side face
91 const bool fp = sdf(i + st[a2]) >= 0.0, fm = sdf(i - st[a2]) >= 0.0;
92 av[2 * a2] = (fp && op > 0.0) ? op : 0.0;
93 av[2 * a2 + 1] = (fm && om > 0.0) ? om : 0.0;
94 D += av[2 * a2] + av[2 * a2 + 1];
95 }
96 if (D <= 0.0)
97 return; // no open fluid face: fully decoupled solid cell
98 const int slot = Kokkos::atomic_fetch_add(&counter(), 1);
99 if (fill) {
100 ov.cell(slot) = x + y * nn.x + z * nn.x * nn.y;
101 for (int k = 0; k < 6; ++k)
102 ov.a(slot * 6 + k) = av[k];
103 }
104 });
105 space.fence();
106 auto h = Kokkos::create_mirror_view(counter);
107 Kokkos::deep_copy(h, counter);
108 return h();
109}
110
114inline void starApplyDelta(CCField y, CCConst x, const StarOverlay& ov, int nOv, C3 nn, C3 extY,
115 int gY, C3 extX, int gX, bool exact) {
116 if (nOv <= 0)
117 return;
119 Kokkos::parallel_for(
120 "peclet::flow::star_apply", Kokkos::RangePolicy<CCExec>(space, 0, nOv), KOKKOS_LAMBDA(int s) {
121 const int inner = ov.cell(s);
122 const int ix = inner % nn.x, iy = (inner / nn.x) % nn.y, iz = inner / (nn.x * nn.y);
123 auto idx = [&](int cx, int cy, int cz, C3 ext, int gb) {
124 return (long)(starWrap(cx, nn.x) + gb) + (long)(starWrap(cy, nn.y) + gb) * ext.x +
125 (long)(starWrap(cz, nn.z) + gb) * (long)ext.x * ext.y;
126 };
127 const int nb[6][3] = {{ix + 1, iy, iz}, {ix - 1, iy, iz}, {ix, iy + 1, iz},
128 {ix, iy - 1, iz}, {ix, iy, iz + 1}, {ix, iy, iz - 1}};
129 double D = 0.0, num = 0.0;
130 double av[6], xv[6];
131 for (int k = 0; k < 6; ++k) {
132 av[k] = starAval(ov, (long)s * 6 + k, exact);
133 if (av[k] <= 0.0)
134 continue;
135 xv[k] = x(idx(nb[k][0], nb[k][1], nb[k][2], extX, gX));
136 D += av[k];
137 num += av[k] * xv[k];
138 }
139 if (exact) {
140 // FLUX FORM (P2, the P1 trick applied to the star row). Algebraically identical to the
141 // phibar form below --
142 // a_k (x_k - phibar) = (a_k/D)(D x_k - sum_j a_j x_j) = (a_k/D) sum_j a_j (x_k - x_j)
143 // -- but every term is a coefficient times a DIFFERENCE, so a constant x is annihilated
144 // BITWISE. The phibar form is not: phibar = sum(a x)/sum(a) does not return x exactly
145 // for constant x even in double (the two sums round independently, then divide), so the
146 // star delta leaked a nonzero row contribution into A*1 that P1's exact 7-point apply
147 // could not cancel. Composing the two is the whole point of the rung: the level-0
148 // operator is the 7-point part PLUS this delta, and A*1 = 0 needs both halves exact.
149 for (int k = 0; k < 6; ++k) {
150 if (av[k] <= 0.0)
151 continue;
152 double acc = 0.0;
153 for (int j = 0; j < 6; ++j)
154 if (av[j] > 0.0)
155 acc += av[j] * (xv[k] - xv[j]);
156 Kokkos::atomic_add(&y(idx(nb[k][0], nb[k][1], nb[k][2], extY, gY)), (av[k] / D) * acc);
157 }
158 return;
159 }
160 const double phibar = num / D;
161 for (int k = 0; k < 6; ++k) {
162 if (av[k] <= 0.0)
163 continue;
164 Kokkos::atomic_add(&y(idx(nb[k][0], nb[k][1], nb[k][2], extY, gY)),
165 av[k] * (xv[k] - phibar));
166 }
167 });
168}
169
182 int nOv, C3 nn, C3 ext, int g, C3 extP, int gP, bool exact,
183 double wx = 1.0, double wy = 1.0, double wz = 1.0) {
184 if (nOv <= 0)
185 return;
187 Kokkos::parallel_for(
188 "peclet::flow::star_correct_faces", Kokkos::RangePolicy<CCExec>(space, 0, nOv),
189 KOKKOS_LAMBDA(int s) {
190 const int inner = ov.cell(s);
191 const int ix = inner % nn.x, iy = (inner / nn.x) % nn.y, iz = inner / (nn.x * nn.y);
192 auto idxP = [&](int cx, int cy, int cz) {
193 return (long)(starWrap(cx, nn.x) + gP) + (long)(starWrap(cy, nn.y) + gP) * extP.x +
194 (long)(starWrap(cz, nn.z) + gP) * (long)extP.x * extP.y;
195 };
196 auto idxF = [&](int cx, int cy, int cz) {
197 return (long)(starWrap(cx, nn.x) + g) + (long)(starWrap(cy, nn.y) + g) * ext.x +
198 (long)(starWrap(cz, nn.z) + g) * (long)ext.x * ext.y;
199 };
200 const int nb[6][3] = {{ix + 1, iy, iz}, {ix - 1, iy, iz}, {ix, iy + 1, iz},
201 {ix, iy - 1, iz}, {ix, iy, iz + 1}, {ix, iy, iz - 1}};
202 double D = 0.0, num = 0.0;
203 for (int k = 0; k < 6; ++k) {
204 const double a = starAval(ov, (long)s * 6 + k, exact);
205 if (a <= 0.0)
206 continue;
207 D += a;
208 num += a * phi(idxP(nb[k][0], nb[k][1], nb[k][2]));
209 }
210 // phibar itself IS the wanted quantity here (the eliminated cell's reconstructed value),
211 // not an operator row, so there is no difference form to take -- only the aperture
212 // precision matters, and it must match the operator that was actually solved.
213 const double phibar = num / D;
214 CCField fa[3] = {uf, vf, wf};
215 const double wv[3] = {wx, wy, wz};
216 for (int k = 0; k < 6; ++k) {
217 if (starAval(ov, (long)s * 6 + k, exact) <= 0.0)
218 continue;
219 const int a2 = k / 2;
220 if ((k & 1) == 0) {
221 // + side: face is the LOW face of the + neighbour; s is the LOW cell -> += phibar
222 fa[a2](idxF(nb[k][0], nb[k][1], nb[k][2])) += wv[a2] * phibar;
223 } else {
224 // - side: face is s's own LOW face; s is the HIGH cell -> -= phibar
225 fa[a2](idxF(ix, iy, iz)) -= wv[a2] * phibar;
226 }
227 }
228 });
229}
230
231} // namespace peclet::flow
232
233#endif // PECLET_FLOW_STAR_ELIMINATION_HPP
flow — portable (Kokkos) cut-cell pressure-operator face openness from an SDF.
StarOverlay starMakeOverlay(long n)
int buildStarOverlay(CCConst sdf, CCConst ox, CCConst oy, CCConst oz, C3 ext, int g, C3 nn, const StarOverlay &ov, Kokkos::View< int, CCMem > counter)
Count + fill the star overlay from the cell-centered sdf and the ORIGINAL (unfiltered) apertures on t...
void starCorrectFaces(CCField uf, CCField vf, CCField wf, CCConst phi, const StarOverlay &ov, int nOv, C3 nn, C3 ext, int g, C3 extP, int gP, bool exact, double wx=1.0, double wy=1.0, double wz=1.0)
Fix the face correction at fluid|solid faces: projectCorrect applied -(phi_hi - phi_lo) with the soli...
Kokkos::View< double *, CCMem > CCField
int starWrap(int v, int n)
Kokkos::DefaultExecutionSpace CCExec
Kokkos::View< const double *, CCMem > CCConst
double starAval(const StarOverlay &ov, long k, bool exact)
One stored aperture, at the precision the gate selects.
void starApplyDelta(CCField y, CCConst x, const StarOverlay &ov, int nOv, C3 nn, C3 extY, int gY, C3 extX, int gX, bool exact)
y += S_star x over the inner cells of the (extY, gY) block, x read from the (extX,...
flow — the multidimensional iteration policies: iteration order follows storage.
One entry per eliminated solid-centered cell: packed INNER flat index + the apertures of its (up to 6...
Kokkos::View< double *, CCMem > a
Kokkos::View< int *, CCMem > cell