flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
verify_colocated_poiseuille.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""Phase-2 verification (collocated grid): plane Poiseuille flow through an SDF channel, driven by a body
3force, with Robust-Scaled cut-cell IBM no-slip walls and NO pressure projection (cutcell_pressure=False).
4
5Runs the SAME setup on both grids: sdflow.Solver (staggered) and sdflow.SolverColocated (cell-centered).
6The steady centreline velocity must match the analytic parabola U_max = F*H^2/(8*mu) and the error must
7shrink with resolution on the collocated grid too. The u-component's wall-normal (y) location is the cell
8centre on BOTH grids, so the two solvers should agree closely. This exercises the collocated {0,0,0} IBM
9offset + implicit diffusion path (advection is ~0 for unidirectional flow; it is stressed in phase 3).
10"""
11import os
12import sys
13
14import numpy as np
15
16sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", os.environ.get("SDFLOW_BUILD", "build"))))
17from peclet import flow as sdflow # noqa: E402
18
19
20def channel_sdf(nx, ny, nz, ylo, yhi):
21 gy = np.arange(ny, dtype=np.float64)
22 sdf = np.empty((nx, ny, nz))
23 sdf[:, :, :] = np.minimum(gy - ylo, yhi - gy)[None, :, None]
24 return sdf
25
26
27def run(SolverCls, N, rho=1.0, mu=0.1, dt=50.0, F=0.01, max_steps=400):
28 nx, nz = 8, 8
29 ny = N
30 ylo = round(0.30 * ny) + 0.5
31 yhi = round(0.70 * ny) + 0.5
32 H = yhi - ylo
33
34 s = SolverCls(nx, ny, nz)
35 s.set_rho(rho)
36 s.set_mu(mu)
37 s.set_dt(dt)
38 s.set_body_force(F, 0.0, 0.0)
39 s.set_velocity_solver_params(200)
40 s.set_solid(channel_sdf(nx, ny, nz, ylo, yhi), cutcell_pressure=False)
41
42 prev = 0.0
43 for it in range(max_steps):
44 s.step()
45 u_now = float(s.get_u().max())
46 if it > 5 and abs(u_now - prev) < 1e-7 * (abs(u_now) + 1e-12):
47 break
48 prev = u_now
49
50 U_sim = float(s.get_u().max())
51 U_ana = F * H * H / (8.0 * mu)
52 err = 100.0 * abs(U_sim - U_ana) / U_ana
53 return ny, H, U_sim, U_ana, err
54
55
56def main():
57 print("=== sdflow phase-2: collocated vs staggered Poiseuille (cut-cell IBM, no pressure) ===")
58 print(f"{'Ny':>5} {'H':>6} {'U_stag':>11} {'U_coloc':>11} {'U_ana':>11} {'err_st%':>8} {'err_co%':>8} {'|st-co|':>9}")
59 errs_co = []
60 ok_all = True
61 for N in (16, 32, 64):
62 _, H, U_st, U_an, e_st = run(sdflow.Solver, N)
63 _, _, U_co, _, e_co = run(sdflow.SolverColocated, N)
64 d = abs(U_st - U_co)
65 print(f"{N:5d} {H:6.1f} {U_st:11.5f} {U_co:11.5f} {U_an:11.5f} {e_st:8.3f} {e_co:8.3f} {d:9.2e}")
66 errs_co.append(e_co)
67 ok_all = errs_co[-1] < 2.0 and errs_co[-1] <= errs_co[0] + 1e-9
68 print(f" result: {'PASS' if ok_all else 'FAIL'} (collocated error shrinks with resolution, <2% at N=64)")
69 sys.exit(0 if ok_all else 1)
70
71
72if __name__ == "__main__":
73 main()
run(SolverCls, N, rho=1.0, mu=0.1, dt=50.0, F=0.01, max_steps=400)