21KN_R, KI_I, KI_R = 16, 2, 17
25 node_ints = np.array([1, -1, -1], dtype=np.int32)
26 node_reals = np.zeros(KN_R); node_reals[0] = R
27 node_reals[14] = 1.0; node_reals[15] = 1.0
28 ii = np.zeros((len(cen), KI_I), dtype=np.int32)
29 ir = np.zeros((len(cen), KI_R))
30 for m, c
in enumerate(cen):
35 return node_ints, node_reals, ii.ravel(), ir.ravel()
38def build(N, moving, V):
40 cen = [(0.25*N, 0.25*N, 0.25*N), (0.75*N, 0.75*N, 0.25*N),
41 (0.75*N, 0.25*N, 0.75*N), (0.25*N, 0.75*N, 0.75*N)]
42 s = sdflow.Solver(N, N, N)
43 s.set_rho(1.0); s.set_mu(0.1); s.set_dt(0.5)
44 s.set_advection(
False)
49 s.set_body_force(1e-3, 0.0, 0.0)
50 s.set_velocity_solver_params(40)
51 s.set_pressure_solver_params(15)
55 s.set_pressure_multigrid(
True, levels=4)
56 s.set_scene(*
make_scene(cen, R), periodic=
True)
58 for i
in range(len(cen)):
59 s.set_instance_motion(i, lin_vel=[V, 0.0, 0.0])
60 s.set_solid_from_scene(
True)
67 for label, moving, rebuild
in ((
"static",
False,
False),
68 (
"moving (no rebuild)",
True,
False),
69 (
"moving + rebuild",
True,
True)):
70 s, cen, R = build(N, moving, V)
73 t0 = time.perf_counter()
74 for k
in range(nstep):
77 for i
in range(len(cen)):
79 s.set_instance_transform(i, [c[0] + V * 0.5 * (k + 1), c[1], c[2]])
81 dt = (time.perf_counter() - t0) / nstep * 1e3
83 print(
" N=%3d %-20s %8.1f ms/step" % (N, label, dt))
84 print(
" N=%3d rebuild overhead %8.1f ms/step (%.1fx a static step)"
85 % (N, out[
"moving + rebuild"] - out[
"moving (no rebuild)"],
86 out[
"moving + rebuild"] / out[
"static"]))
91 """A translating sphere in quiescent fluid: it must move, drag fluid, and stay divergence free."""
94 cen = [(0.25 * N, 0.5 * N, 0.5 * N)]
95 s = sdflow.Solver(N, N, N)
96 s.set_rho(1.0); s.set_mu(0.1); s.set_dt(0.5)
97 s.set_advection(
False)
98 s.set_velocity_solver_params(60)
99 s.set_pressure_solver_params(20)
103 s.set_pressure_multigrid(
True, levels=4)
104 s.set_scene(*
make_scene(cen, R), periodic=
True)
105 s.set_instance_motion(0, lin_vel=[V, 0.0, 0.0])
106 s.set_solid_from_scene(
True)
109 for k
in range(nstep):
111 worstdiv = max(worstdiv, s.max_open_divergence())
113 s.set_instance_transform(0, [x, cen[0][1], cen[0][2]])
115 u = np.asarray(s.get_u())
117 g = np.arange(N).astype(float)
118 X, Y, Z = np.meshgrid(g - 0.5, g, g, indexing=
"ij")
119 dx = np.abs(X - x); dx = np.minimum(dx, N - dx)
120 dy = np.abs(Y - cen[0][1]); dy = np.minimum(dy, N - dy)
121 dz = np.abs(Z - cen[0][2]); dz = np.minimum(dz, N - dz)
122 sd = np.sqrt(dx*dx + dy*dy + dz*dz) - R
124 near = fl & (sd < 0.6 * R)
125 print(
" march: %d steps, sphere x %.2f -> %.2f (moved %.2f cells, expected %.2f)"
126 % (nstep, cen[0][0], x, x - cen[0][0], V * 0.5 * nstep))
127 print(
" max|div| over the march %.3e" % worstdiv)
128 print(
" mean u in the near wake shell %+.4e (wall speed %+.4f) -> fluid is dragged "
129 "ALONG: %s" % (float(u[near].
mean()), V, float(u[near].
mean()) > 0.05 * V))
133 print(
" mean u over all fluid %+.4e (momentum injected by the driven body, "
134 "accumulated across all %d rebuilds)" % (float(u[fl].
mean()), nstep))