29def run(N=128, Re=100.0, U=1.0, nz=4, dt=1.0, max_steps=6000, implicit=False, vmg=False,
30 vlevels=8, vcycles=4, vel_iter=60, outer=2):
32 s = sdflow.Solver(N, N, nz)
33 s.set_rho(1.0); s.set_mu(nu); s.set_dt(dt); s.set_advection(
True)
34 s.set_implicit_advection(implicit)
35 s.set_outer_iterations(outer)
36 s.set_domain_bc(0, 1); s.set_domain_bc(1, 1); s.set_domain_bc(2, 1)
37 s.set_domain_bc(3, 2, U, 0.0, 0.0)
38 s.set_velocity_solver_params(vel_iter)
40 s.set_velocity_multigrid(
True, vlevels, vcycles)
41 s.set_pressure_multigrid(
True, levels=8)
42 s.set_pressure_solver_params(80)
43 s.set_pressure_geometry(np.full((N, N, nz), 1e30))
46 for it
in range(max_steps):
48 u = np.asarray(s.get_u()).reshape((N, N, nz), order=
"F")
49 if not np.isfinite(u).all()
or np.abs(u).max() > 1e3:
52 cur = u[:, :, nz // 2].copy()
54 d = np.max(np.abs(cur - prev)) / (np.max(np.abs(cur)) + 1e-30)
58 u = np.asarray(s.get_u()).reshape((N, N, nz), order=
"F")
59 uc = 0.5 * (u[N // 2 - 1, :, nz // 2] + u[N // 2, :, nz // 2])
60 yc = (np.arange(N) + 0.5) / N
61 u_rms = float(np.sqrt(np.mean((np.interp(GHIA_Y, yc, uc) - GHIA_U) ** 2)))
62 return dict(u_rms=u_rms, umin=float(uc.min()), div=float(s.max_open_divergence()), steps=steps)
66 N = int(os.environ.get(
"VMG_N", 64))
68 print(f
"=== upwind velocity-MG on domain-BC (lid cavity Re={Re:.0f}, N={N}, quasi-2D nz=4) ===")
72 ref =
run(N=N, Re=Re, dt=2.0, implicit=
False, vmg=
False, max_steps=12000)
73 print(f
" (1) explicit dt=2 (CFL=2, stable): u_rms={ref['u_rms']:.4f} "
74 f
"umin={ref['umin']:.4f} (Ghia -0.2058) div={ref['div']:.1e} steps={ref['steps']}")
78 DT = float(os.environ.get(
"VMG_DT", 40.0))
79 print(f
" (2) high CFL: dt={DT:.0f} (advective CFL = U*dt = {DT:.0f})")
80 ex =
run(N=N, Re=Re, dt=DT, implicit=
False, vmg=
False, max_steps=4000)
81 iv =
run(N=N, Re=Re, dt=DT, implicit=
True, vmg=
True, vlevels=8, vcycles=6, max_steps=4000)
82 expl_blew = ex
is None
83 vmg_ok = iv
is not None
84 print(f
" explicit advection : {'BLEW UP' if expl_blew else 'u_rms=%.4f umin=%.4f' % (ex['u_rms'], ex['umin'])}")
86 print(f
" implicit-FOU + upwind vmg: u_rms={iv['u_rms']:.4f} umin={iv['umin']:.4f} "
87 f
"div={iv['div']:.1e} steps={iv['steps']}")
89 print(
" implicit-FOU + upwind vmg: UNSTABLE")
92 match = vmg_ok
and abs(iv[
"u_rms"] - ref[
"u_rms"]) < 0.02
and iv[
"div"] < 1e-4
93 ok = expl_blew
and vmg_ok
and match
94 print(f
" result: {'PASS' if ok else 'FAIL'} (upwind vmg stable at CFL>>1 where explicit fails; "
95 f
"matches the Ghia ground truth)")
96 sys.exit(0
if ok
else 1)
run(N=128, Re=100.0, U=1.0, nz=4, dt=1.0, max_steps=6000, implicit=False, vmg=False, vlevels=8, vcycles=4, vel_iter=60, outer=2)