32 """Periodic union-of-spheres SDF from a packing, sampled on an N^3 grid (cubic box only)."""
34 box = np.asarray(pk[
"box"], float)
35 assert np.allclose(box, box[0]), f
"{npz}: box {box} is not cubic"
37 c = np.asarray(pk[
"centers"]) * Rc
38 r = np.asarray(pk[
"scales"]) * Rc
39 ax = np.arange(N) + 0.5
40 S = np.full((N, N, N), 1e30)
41 for sh
in np.stack(np.meshgrid(*[[-1., 0., 1.]] * 3, indexing=
"ij"), -1).reshape(-1, 3):
43 keep = np.all((cs + (r + 3)[:,
None] > 0) & (cs - (r + 3)[:,
None] < N), axis=1)
44 for (cx, cy, cz), rr
in zip(cs[keep], r[keep]):
45 i0, i1 = np.searchsorted(ax, [cx - rr - 3, cx + rr + 3])
46 j0, j1 = np.searchsorted(ax, [cy - rr - 3, cy + rr + 3])
47 k0, k1 = np.searchsorted(ax, [cz - rr - 3, cz + rr + 3])
48 if i0 >= i1
or j0 >= j1
or k0 >= k1:
50 d = np.sqrt((ax[i0:i1,
None,
None] - cx) ** 2 + (ax[
None, j0:j1,
None] - cy) ** 2
51 + (ax[
None,
None, k0:k1] - cz) ** 2) - rr
52 np.minimum(S[i0:i1, j0:j1, k0:k1], d, out=S[i0:i1, j0:j1, k0:k1])
53 return np.asfortranarray(np.clip(S, -1e3, 1e3)), Rc
56def solve(N, kind, mu=0.1, F=1e-3, dt=80.0, warm_tol=1e-7, tail=40, max_steps=4000):
60 R = (3 * PHI0 / (4 * np.pi)) ** (1 / 3) * N
61 g = np.arange(N) + 0.5
62 X, Y, Z = np.meshgrid(g, g, g, indexing=
"ij")
63 d =
lambda A: A - 0.5 * N - N * np.round((A - 0.5 * N) / N)
64 sdf = np.asfortranarray(np.sqrt(
d(X) ** 2 +
d(Y) ** 2 +
d(Z) ** 2) - R)
65 s = flow.Solver(N, N, N)
if kind ==
"stag" else flow.SolverColocated(N, N, N)
66 s.set_rho(1.0); s.set_mu(mu); s.set_dt(dt)
67 s.set_body_force(F, 0, 0); s.set_advection(
False)
68 s.set_velocity_solver_params(150)
69 s.set_pressure_multigrid(
True, max(2, int(np.log2(N)) - 1))
70 s.set_pressure_pcg(
True, 200, 1e-8)
74 if hasattr(s,
"set_collocated_scheme"):
75 s.set_collocated_scheme(kind)
77 s.set_face_interp({
"gauge-exact": 9,
"plain": 0}[kind])
78 s.set_solid(sdf, cutcell_pressure=
True, pressure_coarse=
"rediscretized")
79 prev, warm = 0.0,
None
80 for it
in range(max_steps):
82 um = float(s.get_u().mean())
85 if it > 10
and abs(um - prev) < warm_tol * (abs(um) + 1e-30):
88 elif it - warm >= tail:
90 uf = np.asarray(s.get_u()
if kind ==
"stag" else s.get_uf())
91 return uf, np.asarray(s.get_ox()), sdf, R