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