72def run(N, use_far2=False):
74 c = (np.arange(N)+0.5)*h - 0.5
75 X, Y, Z = np.meshgrid(c, c, c, indexing=
"ij")
78 U = np.where(fl,
ux(X, Y, Z), 0.0)
84 om = O[:-1]; op = O[1:]
87 Wa = np.moveaxis(Wa, [0, 1, 2], [a, (a+1) % 3, (a+2) % 3])
89 sumW = [float(W[a].sum())
for a
in range(3)]
90 area = float(np.sqrt(W[0]**2 + W[1]**2 + W[2]**2).sum())
93 g = [np.zeros((N, N, N))
for _
in range(3)]
94 gc = [np.zeros((N, N, N))
for _
in range(3)]
96 up = np.roll(U, -1, a); um = np.roll(U, +1, a)
97 sp = np.roll(S, -1, a); sm = np.roll(S, +1, a)
98 solP = sp < 0; solM = sm < 0
99 thP = np.clip(np.where(solP, S/np.maximum(S-sp, 1e-30), 1.0), 1e-3, 1.0)
100 thM = np.clip(np.where(solM, S/np.maximum(S-sm, 1e-30), 1.0), 1e-3, 1.0)
103 def alpha(th, Uc, Uf, farFluid):
104 quad = (Uc*(th+1.0)**2 - Uf*th*th)/(th*(th+1.0))
106 return np.where(farFluid, quad, lin)
107 aP = alpha(thP, U, um, ~solM)
108 aM = alpha(thM, U, up, ~solP)
109 cen = (up - um)/(2*h)
111 gA = np.where(solP & ~solM, -aP/h,
112 np.where(solM & ~solP, +aM/h,
113 np.where(both, 0.5*(-aP + aM)/h, cen)))
114 g[a] = np.where(fl, gA, 0.0)
115 gc[a] = np.where(fl, cen, 0.0)
119 need = (~fl) & ((np.abs(W[0]) + np.abs(W[1]) + np.abs(W[2])) > 0)
120 filled = np.zeros_like(need)
123 nb_fl = np.roll(fl, -d, a)
124 m = need & ~filled & nb_fl
126 g[q][m] = np.roll(g[q], -d, a)[m]
127 gc[q][m] = np.roll(gc[q], -d, a)[m]
129 orphan_share = float(np.sqrt(sum(W[a][need & ~filled]**2
for a
in range(3))).sum()/max(area, 1e-30))
131 Fest = MU*sum((W[a]*g[a]).sum()
for a
in range(3))
132 Fcen = MU*sum((W[a]*gc[a]).sum()
for a
in range(3))
141 m = (np.abs(W[0]) + np.abs(W[1]) + np.abs(W[2])) > 0
142 xm, ym, zm = X[m], Y[m], Z[m]
143 rx, ry, rz = xm - C0[0], ym - C0[1], zm - C0[2]
144 rr = np.sqrt(rx*rx + ry*ry + rz*rz)
145 nxh, nyh, nzh = rx/rr, ry/rr, rz/rr
146 px, py, pz = C0[0] + R*nxh, C0[1] + R*nyh, C0[2] + R*nzh
150 sg = np.where(nh[a] >= 0, 1.0, -1.0)
151 d1 = [px.copy(), py.copy(), pz.copy()]; d1[a] = d1[a] + sg*h
152 d2 = [px.copy(), py.copy(), pz.copy()]; d2[a] = d2[a] + 2*sg*h
153 u1 =
ux(d1[0], d1[1], d1[2])
154 u2 =
ux(d2[0], d2[1], d2[2])
155 gB = sg*(2.0*u1 - 0.5*u2)/h
156 FB += (W[a][m]*gB).sum()
158 return dict(Fest=Fest, Fcen=Fcen, FB=FB, sumW=sumW, area=area, orphan=orphan_share)
182 c = (np.arange(N) + 0.5) * h - 0.5
183 X, Y, Z = np.meshgrid(c, c, c, indexing=
"ij")
186 U = np.where(fl,
ux(X, Y, Z), 0.0)
192 Wa = h * h * (O[:-1] - O[1:])
193 W.append(np.moveaxis(Wa, [0, 1, 2], [a, (a + 1) % 3, (a + 2) % 3]))
194 A = np.sqrt(W[0]**2 + W[1]**2 + W[2]**2)
198 Im, Jm, Km = np.nonzero(m)
199 xm, ym, zm = X[m], Y[m], Z[m]
200 rx, ry, rz = xm - C0[0], ym - C0[1], zm - C0[2]
201 rr = np.sqrt(rx * rx + ry * ry + rz * rz)
202 nhat = np.stack([rx / rr, ry / rr, rz / rr], axis=1)
204 pcell = -sdm[:,
None] / h * nhat
205 cidx = np.stack([Im, Jm, Km], axis=1)
210 grad = np.full(Mn, np.nan)
211 used = np.zeros(Mn, dtype=int)
212 bl = np.zeros(Mn, dtype=bool)
213 da = np.argmax(np.abs(nhat), axis=1)
215 def gather(cc, a, oa, t1, ot1, t2, ot2):
216 idx = [cc[:, 0].copy(), cc[:, 1].copy(), cc[:, 2].copy()]
217 idx[a] = np.clip(idx[a] + oa, 0, N - 1)
218 idx[t1] = np.clip(idx[t1] + ot1, 0, N - 1)
219 idx[t2] = np.clip(idx[t2] + ot2, 0, N - 1)
220 return U[idx[0], idx[1], idx[2]], (S[idx[0], idx[1], idx[2]] >= 0)
223 g = np.nonzero(da == a)[0]
226 t1, t2 = (a + 1) % 3, (a + 2) % 3
228 na, nt1, nt2 = nhat[g, a], nhat[g, t1], nhat[g, t2]
229 pa, pt1, pt2 = pcell[g, a], pcell[g, t1], pcell[g, t2]
230 sgn = np.where(na >= 0, 1.0, -1.0)
235 i = (l + 1) * sgn.astype(int)
239 j = np.clip(np.round(y1), -1, 1).astype(int)
240 k = np.clip(np.round(z1), -1, 1).astype(int)
241 ly, lz = y1 - j, z1 - k
243 imx = [
None,
None,
None]
244 imx[a] = X[cc[:, 0], cc[:, 1], cc[:, 2]] + i * h
if a == 0
else None
246 base = [X[cc[:, 0], cc[:, 1], cc[:, 2]], Y[cc[:, 0], cc[:, 1], cc[:, 2]],
247 Z[cc[:, 0], cc[:, 1], cc[:, 2]]]
248 base[a] = base[a] + i * h
249 base[t1] = base[t1] + y1 * h
250 base[t2] = base[t2] + z1 * h
251 v[l] =
ux(base[0], base[1], base[2])
253 defd[l] = np.ones(len(g), dtype=bool)
258 for dk
in (-1, 0, 1):
259 for dj
in (-1, 0, 1):
260 vv[(dj, dk)], sf[(dj, dk)] = gather(cc, a, i, t1, j + dj, t2, k + dk)
261 full = np.ones(len(g), dtype=bool)
265 vbq =
_quad(lz,
_quad(ly, vv[(-1, -1)], vv[(0, -1)], vv[(1, -1)]),
266 _quad(ly, vv[(-1, 0)], vv[(0, 0)], vv[(1, 0)]),
267 _quad(ly, vv[(-1, 1)], vv[(0, 1)], vv[(1, 1)]))
273 def biased(coord, keyP, keyM):
274 return np.where(sf[keyP], np.abs(coord) * (vv[keyP] - vv[(0, 0)]),
275 np.where(sf[keyM], np.abs(coord) * (vv[(0, 0)] - vv[keyM]), 0.0))
279 cj = np.where(spj, biased(ly, (1, 0), (-1, 0)), biased(ly, (-1, 0), (1, 0)))
280 ck = np.where(spk, biased(lz, (0, 1), (0, -1)), biased(lz, (0, -1), (0, 1)))
281 vbl = vv[(0, 0)] + cj + ck
282 v[l] = np.where(full, vbq, vbl)
284 defd[l] = full | home
285 bl[g] |= (home & ~full)
286 d0, d1 = dd[0], dd[1]
288 two = defd[0] & defd[1]
289 near = defd[0] & ~defd[1]
291 gg = np.zeros(len(g))
292 gg[two] = (v0[two] * d1[two] / d0[two] - v1[two] * d0[two] / d1[two]) / \
293 ((d1[two] - d0[two]) * h)
294 gg[near] = v0[near] / (d0[near] * h)
295 d0deg = np.maximum(1e-3, np.abs(pa[deg] / na[deg]))
296 gg[deg] = Ucell[g][deg] / (d0deg * h)
298 used[g] = np.where(two, 2, np.where(near, 1, 0))
300 Fnorm = -MU * float(np.sum(Aw * grad))
301 frac_bl = float(np.mean(bl))
302 frac_deg = float(np.mean(used == 0))
303 return dict(Fnorm=Fnorm, frac_bl=frac_bl, frac_deg=frac_deg,
304 area=float(Aw.sum()), Mn=Mn)