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