49def run(Re, S=16, Lr=12, U_in=1.0, nz=4, dt=0.2, max_steps=24000):
50 """Run the backward-facing step at Reynolds number `Re` (Re_S = U_in*S/nu) and return its diagnostics.
52 Step height S, full channel height 2S, channel length Lr*S; a partial parabolic inlet feeds the upper
53 half, the lower half is the step face. Marches to steady state and returns a dict with the lower-wall
54 reattachment length (x_r/S, x_r/H), bubble presence, mass-conservation error and max divergence.
55 Returns None off root.
74 s = sdflow.Solver(L, H, nz)
75 s.set_rho(1.0); s.set_mu(nu); s.set_dt(dt); s.set_advection(
True)
77 s.set_domain_bc(
"+x",
"outflow")
78 s.set_domain_bc(
"-y",
"wall"); s.set_domain_bc(
"+y",
"wall")
79 s.diagnostics.set_velocity_solver_params(60)
80 if os.environ.get(
"SDFLOW_BFS_VMG") ==
"1":
81 s.set_velocity_multigrid(
True, 8, 4)
82 s.set_pressure_multigrid(
True, levels=8)
83 s.set_pressure_solver_params(80)
84 s.set_pressure_geometry(np.full((L, H, nz), 1e30))
86 verbose = os.environ.get(
"SDFLOW_BFS_VERBOSE") ==
"1"
90 for it
in range(max_steps):
94 xr =
reattachment(u[:, 0, nz // 2])
if s.rank() == 0
else 0.0
97 done = it > 3000
and xr > S
and abs(xr - prev) < 1e-3 * S
98 if verbose
and s.rank() == 0:
99 print(f
" [Re={Re} it={it+1} x_r/S={xr/S:.2f} t={time.time()-t0:.0f}s]", flush=
True)
101 if s.diagnostics.bcast_from_root(done):
104 u = s.get_u(); div = s.max_open_divergence()
108 flux_in = float(u[2, :, nz // 2].sum())
109 flux_out = float(u[L - 3, :, nz // 2].sum())
110 mass_err = abs(flux_out - flux_in) / (abs(flux_in) + 1e-30)
111 has_bubble = bool((u[1:S, 0, nz // 2] < 0).any())
112 return dict(Re=Re, S=S, H=H, L=L, steps=steps, secs=time.time() - t0, xr_S=xr / S, xr_H=xr / H,
113 div=div, mass_err=mass_err, bubble=has_bubble)