39 s = flow.Solver((n, n, n), extent=(L, L, L))
43 s.set_dt(a.beta * h * h)
44 s.set_body_force((1.0, 0.0, 0.0))
45 s.set_advection(
False)
46 s.diagnostics.set_velocity_solver_params(200)
47 s.set_pressure_multigrid(
True, levels=max(2, int(np.log2(n)) - 1))
48 s.set_pressure_pcg(
True, max_iter=st[
"pcg"][0], rtol=st[
"pcg"][1])
49 if st[
"vel_rtol"]
is not None:
50 s.set_velocity_residual_tolerance(st[
"vel_rtol"])
51 R = (3.0 * a.phi / (4.0 * math.pi)) ** (1.0 / 3.0) * L
52 c = [0.5 * L + a.shift[k] * h
for k
in range(3)]
53 ni = np.array([1, -1, -1], dtype=np.int32)
58 ii = np.array([0, -1], dtype=np.int32)
63 s.set_scene(ni, nr, ii, ir, periodic=
True)
64 s.set_solid_from_scene(cutcell_pressure=
True)
67 return L ** 3 / (6.0 * math.pi * R * u)
72 st = SAG.settings_of(a.settings)
74 st[
"max_steps"] = a.max_steps
76 case = SAG.Case(PP.case_args(a))
77 s = PP.build(flow, case,
"staggered", st)
81 res = flow.march_to_steady(s,
lambda: float(s.get_u().
mean()), rtol=st[
"rtol"],
82 max_steps=st[
"max_steps"], accelerate=(a.window > 0),
83 window=max(a.window, 1))
84 r = np.array(s.hydro_force_torque_reaction())
85 U = [np.array(g())
for g
in (s.get_u, s.get_v, s.get_w)]
86 O = [np.array(g())
for g
in (s.get_ox_proj, s.get_oy_proj, s.get_oz_proj)]
87 print(f
"{a.case} {a.settings} m={a.window}: converged={res.converged} {res.reason} "
88 f
"steps={res.steps} acc={res.accelerated_steps} K={K(res.monitor):.12f} "
89 f
"sum Fx={r[0][:, 0].sum():.12e}", flush=
True)
90 np.savez(a.out, K=K(res.monitor), monitor=res.monitor, steps=res.steps,
91 accelerated=res.accelerated_steps, converged=res.converged, F=r[0], T=r[1],
92 u=U[0], v=U[1], w=U[2], ox=O[0], oy=O[1], oz=O[2])
96 A, B = np.load(a.a), np.load(a.b)
97 dK = float(B[
"K"] / A[
"K"] - 1.0)
98 dF = float(np.abs(B[
"F"] - A[
"F"]).max() / np.abs(A[
"F"]).max())
99 dT = float(np.abs(B[
"T"] - A[
"T"]).max() / np.abs(A[
"T"]).max())
100 umax = max(float(np.abs(A[f]).max())
for f
in "uvw")
101 du, rem, nmask = 0.0, 0.0, 0
102 for f, o
in zip(
"uvw", (
"ox",
"oy",
"oz")):
104 pinned = (A[f] == 0.0) | (B[f] == 0.0)
105 closed = (A[o] == 0.0) & (A[f] != 0.0)
106 nmask += int(closed.sum())
107 rem = max(rem, float(np.abs(A[f][closed]).max())
if closed.any()
else 0.0)
108 du = max(du, float(np.abs(B[f] - A[f])[~pinned].max()))
109 print(f
"{os.path.basename(a.a)} -> {os.path.basename(a.b)}: |dK/K| {abs(dK):.3e} "
110 f
"(K {float(A['K']):.12f} -> {float(B['K']):.12f}); reaction F {dF:.3e}, T {dT:.3e} "
111 f
"(per body, / max); max|du| / max|u| off the pinned points {du / umax:.3e}; "
112 f
"{nmask} closed-aperture points live in the first run, max |u| there / max|u| "
113 f
"{rem / umax:.3e}; steps {int(A['steps'])} -> {int(B['steps'])} "
114 f
"(accelerated {int(A['accelerated'])} -> {int(B['accelerated'])}), converged "
115 f
"{bool(A['converged'])} -> {bool(B['converged'])}")
119 ap = argparse.ArgumentParser()
120 ap.add_argument(
"cmd", choices=(
"run",
"compare"))
121 ap.add_argument(
"a", nargs=
"?")
122 ap.add_argument(
"b", nargs=
"?")
123 ap.add_argument(
"--case", choices=(
"bed",
"sphere"), default=
"bed")
124 ap.add_argument(
"--arrangement", default=
None)
125 ap.add_argument(
"--N", type=int, default=
None)
126 ap.add_argument(
"--phi", type=float, default=0.216)
127 ap.add_argument(
"--shift", type=float, nargs=3, default=[0.0, 0.0, 0.0])
128 ap.add_argument(
"--beta", type=float, default=6.0)
129 ap.add_argument(
"--settings", choices=(
"production",
"tight"), default=
"production")
130 ap.add_argument(
"--window", type=int, default=5)
131 ap.add_argument(
"--max-steps", type=int, default=
None)
132 ap.add_argument(
"--out", default=
None)
134 if a.cmd ==
"compare":
138 a.N = 64
if a.case ==
"bed" else 24
139 sys.path.insert(0, os.path.join(HERE,
"..",
"..",
"scripts"))
140 from _bootstrap
import ensure_flow