27 """Vectorized area of {u<x, v<y, u^2+v^2<r^2}, disk at origin."""
29 yc = np.clip(y, -r, r)
33 return 0.5 * (t * np.sqrt(np.maximum(r * r - t * t, 0.0)) + r * r * np.arcsin(t / r))
35 us = np.sqrt(np.maximum(r * r - yc * yc, 0.0))
37 a_m = np.maximum(-r, -us)
38 b_m = np.minimum(x, us)
39 mid = np.where(b_m > a_m, yc * (b_m - a_m) + (
G(b_m) -
G(a_m)), 0.0)
41 a1, b1 = -r + 0.0 * x, np.minimum(x, -us)
42 left = np.where(b1 > a1, 2.0 * (
G(b1) -
G(a1)), 0.0)
43 a2, b2 = us, np.maximum(x, us)
44 right = np.where(b2 > a2, 2.0 * (
G(b2) -
G(a2)), 0.0)
45 outer = np.where(y >= 0, left + right, 0.0)
47 F = np.where(y >= r, 2.0 * (
G(x) -
G(-r)), F)
48 F = np.where(y <= -r, 0.0, F)
64 """o[a][i,j,k]: openness of the -a face of cell (i,j,k); union over spheres by subtraction
65 with clamping (multi-sphere faces are rare; counted and reported)."""
66 o = [np.ones((N, N, N))
for _
in range(3)]
68 for sh
in np.stack(np.meshgrid(*[[-1., 0., 1.]] * 3, indexing=
"ij"), -1).reshape(-1, 3):
70 keep = np.all((cs + (Rr + 2)[:,
None] > 0) & (cs - (Rr + 2)[:,
None] < N + 1), axis=1)
71 for (scx, scy, scz), rr
in zip(cs[keep], Rr[keep]):
74 t1, t2 = (a + 1) % 3, (a + 2) % 3
75 p0 = max(int(np.ceil(cen[a] - rr)), 0)
76 p1 = min(int(np.floor(cen[a] + rr)), N - 1)
77 for p
in range(p0, p1 + 1):
79 rho2 = rr * rr - d * d
83 j0 = max(int(np.floor(cen[t1] - rho)), 0)
84 j1 = min(int(np.ceil(cen[t1] + rho)), N)
85 k0 = max(int(np.floor(cen[t2] - rho)), 0)
86 k1 = min(int(np.ceil(cen[t2] + rho)), N)
87 if j0 >= j1
or k0 >= k1:
90 idx = [slice(
None)] * 3
92 idx[t1] = slice(j0, j1)
93 idx[t2] = slice(k0, k1)
94 view = o[a][tuple(idx)]
96 Ax = A.T
if t1 > t2
else A
97 multi += int(((view < 1.0) & (Ax > 1e-12)).sum())
98 np.subtract(view, Ax, out=view)
99 np.clip(view, 0.0, 1.0, out=view)
100 print(f
" exact_openness: multi-sphere faces (union approximated): {multi}", flush=
True)
102 o[a][o[a] < 1e-6] = 0.0