flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
verify_colocated_lid_cavity.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""Phase-5a verification (collocated grid): the lid-driven cavity vs Ghia, Ghia & Shin (1982), Re=100 --
3the canonical native-domain-BC benchmark. Three no-slip walls (-x,+x,-y) + a lid (+y) moving in +x,
4quasi-2D (periodic z), no immersed solid. This exercises the collocated domain-BC machinery: cell-centered
5reflection velocity ghosts (every component reflects about the boundary face), the explicit-reflection
6diffusion smoother, and the Neumann phi wall ghost in the approximate projection.
7"""
8import os
9import sys
10
11import numpy as np
12
13sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", os.environ.get("SDFLOW_BUILD", "build"))))
14from peclet import flow as sdflow # noqa: E402
15
16GHIA_Y = np.array([0, .0547, .0625, .0703, .1016, .1719, .2813, .4531, .5, .6172, .7344, .8516, .9531,
17 .9609, .9688, .9766, 1])
18GHIA_U = np.array([0, -.03717, -.04192, -.04775, -.06434, -.10150, -.15662, -.21090, -.20581, -.13641,
19 .00332, .23151, .68717, .73722, .78871, .84123, 1])
20GHIA_X = np.array([0, .0625, .0703, .0781, .0938, .1563, .2266, .2344, .5, .8047, .8594, .9063, .9453,
21 .9531, .9609, .9688, 1])
22GHIA_V = np.array([0, .09233, .10091, .10890, .12317, .16077, .17507, .17527, .05454, -.24533, -.22445,
23 -.16914, -.10313, -.08864, -.07391, -.05906, 0])
24
25
26def run(N=128, Re=100.0, U=1.0, nz=4, max_steps=9000):
27 nu = U * N / Re
28 s = sdflow.SolverColocated(N, N, nz)
29 s.set_rho(1.0); s.set_mu(nu); s.set_dt(1.0); s.set_advection(True)
30 s.set_domain_bc(0, 1); s.set_domain_bc(1, 1); s.set_domain_bc(2, 1) # -x, +x, -y no-slip
31 s.set_domain_bc(3, 2, U, 0.0, 0.0) # +y lid moving in +x
32 s.set_velocity_solver_params(60)
33 s.set_pressure_pcg(True, 400, 1e-9)
34 s.set_pressure_geometry(np.asfortranarray(np.full((N, N, nz), 1e30))) # all-fluid + Neumann walls
35
36 prevp = None
37 steps = max_steps
38 for it in range(max_steps):
39 s.step()
40 if it % 100 == 99:
41 uc = s.get_u()[N // 2, :, nz // 2]
42 if prevp is not None and np.max(np.abs(uc - prevp)) < 1e-5:
43 steps = it + 1
44 break
45 prevp = uc.copy()
46
47 u = s.get_u(); v = s.get_v(); div = float(s.max_open_divergence())
48 yc = (np.arange(N) + 0.5) / N
49 uc = u[N // 2, :, nz // 2] / U
50 vc = v[:, N // 2, nz // 2] / U
51 u_rms = float(np.sqrt(np.mean((np.interp(GHIA_Y, yc, uc) - GHIA_U) ** 2)))
52 v_rms = float(np.sqrt(np.mean((np.interp(GHIA_X, yc, vc) - GHIA_V) ** 2)))
53 return N, Re, u_rms, v_rms, float(uc.min()), div, steps
54
55
56def main():
57 N, Re, u_rms, v_rms, umin, div, steps = run()
58 print("=== sdflow phase-5a: collocated lid-driven cavity vs Ghia, Ghia & Shin (1982) ===")
59 print(f" Re={Re:.0f} N={N} ({steps} steps)")
60 print(f" u(y) rms vs Ghia = {u_rms:.4f} v(x) rms vs Ghia = {v_rms:.4f}")
61 print(f" min centreline u = {umin:.4f} (Ghia -0.2058) max flux divergence = {div:.1e}")
62 ok = u_rms < 0.02 and v_rms < 0.02 and div < 1e-6
63 print(f" result: {'PASS' if ok else 'FAIL'} (centreline profiles match Ghia, incompressible)")
64 sys.exit(0 if ok else 1)
65
66
67if __name__ == "__main__":
68 main()
run(N=128, Re=100.0, U=1.0, nz=4, max_steps=9000)