flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
bench_velocity_mg_bfs.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""Velocity-MG benchmark on the backward-facing step (high-resolution 2D; BFS is a channel, not a cube).
3
4Same two questions as the cavity bench: does the velocity-MG (a) speed up the march to steady at high
5resolution, and (b) stay free of any dt restriction (no immersed solid -> geometry-exact coarse operator)?
6Re_S = U_in*S/nu; the step is the inlet condition (set_domain_bc_profile), +x outflow, -y/+y no-slip walls.
7"""
8import os
9import sys
10import time
11
12import numpy as np
13
14sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..",
15 os.environ.get("SDFLOW_BUILD", "build_mpi"))))
16from peclet import flow as sdflow # noqa: E402
17
18
19def inlet_profile(H, S, nz, U_in):
20 prof = np.zeros((H, nz, 3))
21 yc = np.arange(H) + 0.5
22 eta = (yc - S) / S
23 up = yc > S
24 prof[up, :, 0] = (6.0 * U_in * eta * (1.0 - eta))[up, None]
25 return prof
26
27
28def reattach(u_bottom):
29 rev = False
30 for i in range(1, len(u_bottom)):
31 if u_bottom[i] < 0.0:
32 rev = True
33 elif rev and u_bottom[i] >= 0.0:
34 return (i - 1) + u_bottom[i - 1] / (u_bottom[i - 1] - u_bottom[i])
35 return 0.0
36
37
38def bfs(S, Re, dt, mode, Lr=12, U_in=1.0, nz=4, max_steps=6000, tol=2e-5, vcyc=4, vel_iter=60, outer=2):
39 H, L, nu = 2 * S, Lr * S, U_in * S / Re
40 s = sdflow.Solver(L, H, nz)
41 s.set_rho(1.0); s.set_mu(nu); s.set_dt(dt); s.set_advection(True)
42 if mode == "vmg_fou":
43 s.set_implicit_advection(True); s.set_outer_iterations(outer)
44 s.set_domain_bc_profile(0, inlet_profile(H, S, nz, U_in))
45 s.set_domain_bc(1, 3); s.set_domain_bc(2, 1); s.set_domain_bc(3, 1)
46 s.set_velocity_solver_params(vel_iter)
47 if mode in ("vmg", "vmg_fou"):
48 s.set_velocity_multigrid(True, 8, vcyc)
49 s.set_pressure_multigrid(True, levels=8); s.set_pressure_solver_params(80)
50 prev = None; steps = max_steps; t0 = time.time()
51 for it in range(max_steps):
52 s.step()
53 u = s.get_u()
54 if not np.isfinite(u).all() or np.abs(u).max() > 1e3:
55 return dict(blew=True, steps=it, wall=time.time() - t0, xr=np.nan)
56 if it % 25 == 24:
57 uu = np.asarray(u).reshape((L, H, nz), order="F")
58 cur = uu[:, :, nz // 2].copy()
59 if prev is not None and np.max(np.abs(cur - prev)) / (np.max(np.abs(cur)) + 1e-30) < tol:
60 steps = it + 1; break
61 prev = cur
62 uu = np.asarray(s.get_u()).reshape((L, H, nz), order="F")
63 xr = reattach(uu[:, 0, nz // 2]) / S
64 return dict(blew=False, steps=steps, wall=time.time() - t0, xr=xr)
65
66
67def main():
68 S = int(os.environ.get("VMG_S", 128)) # H=2S=256 channel height; L=12S
69 Re = float(os.environ.get("VMG_RE", 200.0))
70 ms = int(os.environ.get("VMG_MAXSTEPS", 6000))
71 print(f"=== backward-facing step {12*S}x{2*S}x4 Re_S={Re:.0f} ===")
72 dts = float(os.environ.get("VMG_DT_SPEEDUP", 0.4))
73 print(f"--- SPEEDUP: time to steady (explicit-advection dt={dts:g}) ---")
74 rb = bfs(S, Re, dt=dts, mode="rbgs", vel_iter=60, max_steps=ms)
75 print(f" RB-GS 60 sweeps : steps={rb['steps']:5d} wall={rb['wall']:7.1f}s x_r/S={rb['xr']:.2f}")
76 rb2 = bfs(S, Re, dt=dts, mode="rbgs", vel_iter=200, max_steps=ms)
77 print(f" RB-GS 200 sweeps : steps={rb2['steps']:5d} wall={rb2['wall']:7.1f}s x_r/S={rb2['xr']:.2f}")
78 vg = bfs(S, Re, dt=dts, mode="vmg", vcyc=4, max_steps=ms)
79 print(f" vel-MG 4 vcyc : steps={vg['steps']:5d} wall={vg['wall']:7.1f}s x_r/S={vg['xr']:.2f}"
80 f" speedup x{rb2['wall'] / max(vg['wall'], 1e-9):.2f} (vs RB-GS 200)")
81 print("--- NO DT RESTRICTION: implicit-FOU + upwind vel-MG, growing dt (CFL=U*dt) ---")
82 for dt in [2.0, 8.0, 32.0, 128.0]:
83 r = bfs(S, Re, dt=dt, mode="vmg_fou", vcyc=6, max_steps=600)
84 tag = "BLEW UP" if r["blew"] else f"finite, x_r/S={r['xr']:.2f} (steps {r['steps']})"
85 print(f" dt={dt:7.1f} (CFL~{dt:.0f}): {tag}")
86
87
88if __name__ == "__main__":
89 main()
bfs(S, Re, dt, mode, Lr=12, U_in=1.0, nz=4, max_steps=6000, tol=2e-5, vcyc=4, vel_iter=60, outer=2)