25ZH_PHI = [0.000125, 0.001, 0.008, 0.027, 0.064, 0.125, 0.216, 0.343, 0.45, 0.5236]
26ZH_K = [1.096, 1.212, 1.525, 2.008, 2.810, 4.292, 7.442, 15.4, 28.1, 42.1]
45def run(N, phi, mode, vel_iter=200, vlevels=4, vcycles=12, mu=0.1, f=1e-3, dt=60.0,
46 max_steps=600, tol=1e-7):
47 """mode: 'rbgs' (plain RB-GS reference) | 'vmg' (the staircase velocity-MG, via set_velocity_multigrid)."""
49 s = sdflow.Solver(N, N, N)
50 s.set_rho(1.0); s.set_mu(mu); s.set_dt(dt); s.set_body_force(f, 0, 0); s.set_advection(
False)
52 s.set_velocity_solver_params(vel_iter)
54 s.set_velocity_multigrid(
True, vlevels, vcycles)
55 lv = max(2, int(np.log2(N)) - 1)
56 s.set_pressure_multigrid(
True, levels=lv)
57 s.set_pressure_pcg(
True, max_iter=200, rtol=1e-8)
58 s.set_solid(sdf, cutcell_pressure=
True, pressure_coarse=
"rediscretized")
59 prev = 0.0; t0 = time.time()
60 for it
in range(max_steps):
63 if not np.isfinite(u).all():
67 if it > 10
and abs(m - prev) < tol * (abs(m) + 1e-30):
70 return drag_K(float(s.get_u().mean()), R, N, f, mu), time.time() - t0
74 N = int(os.environ.get(
"VMG_N", 64))
75 phi = float(os.environ.get(
"VMG_PHI", 0.216))
76 vcyc = int(os.environ.get(
"VMG_VCYC", 12))
77 kref = float(np.interp(phi, ZH_PHI, ZH_K))
78 print(f
"=== staircase velocity-MG Z&H gate: SC sphere N={N} phi={phi} (Z&H K~{kref:.3f}) ===")
79 Krb, wrb =
run(N, phi,
"rbgs")
80 Kvm, wvm =
run(N, phi,
"vmg", vcycles=vcyc)
81 e = abs(Kvm - Krb) / Krb
if (Kvm
and Krb)
else float(
"nan")
82 print(f
" RB-GS : K={Krb:.5f} wall={wrb:.1f}s")
83 print(f
" vel-MG (v={vcyc:2d}) : K={'NaN' if Kvm is None else f'{Kvm:.5f}'} wall={wvm:.1f}s "
84 f
"err vs RB-GS {e*100:.3f}%")
85 ok1 = (Kvm
is not None)
and e < 0.001
88 dt_stiff = float(os.environ.get(
"VMG_DT_STIFF", 800.0))
89 print(f
" stiff dt={dt_stiff:.0f} (beta={mu_b(dt_stiff):.0f}; geometry-blind const coarse diverges):")
90 Krb_s, _ =
run(N, phi,
"rbgs", dt=dt_stiff)
91 Kv_s, _ =
run(N, phi,
"vmg", dt=dt_stiff, vcycles=vcyc)
92 e_s = abs(Kv_s - Krb_s) / Krb_s
if (Kv_s
and Krb_s)
else float(
"nan")
93 print(f
" RB-GS K={Krb_s:.5f} vel-MG={'BLEW UP' if Kv_s is None else f'{Kv_s:.5f} (err {e_s*100:.3f}%)'}")
94 ok2 = (Kv_s
is not None)
and e_s < 0.005
96 print(f
" result: {'PASS' if ok1 and ok2 else 'FAIL'} (staircase vel-MG == RB-GS drag, and stable+exact "
98 sys.exit(0
if ok1
and ok2
else 1)
run(N, phi, mode, vel_iter=200, vlevels=4, vcycles=12, mu=0.1, f=1e-3, dt=60.0, max_steps=600, tol=1e-7)