flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
compare_amr_sdflow_field.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""Localize the ~1% sdflow-collocated vs AMR converged-k difference: run both on the SAME
3registration-matched SC sphere and compare the converged velocity fields cell-by-cell. Is the
4difference at the cut cells (projection/openness) or in the bulk (base operator)?
5
6sdflow and AMR each init Kokkos and one finalizes it, so they cannot share a process — each engine
7runs in its own subprocess (mode 'sdflow'/'amr') and writes its u-field to .npy; mode 'compare'
8(default) spawns both and diffs. sdflow cell (i,j,k) centre=(i,j,k); AMR origin=-0.5 puts leaf
9(i,j,k) centre at (i,j,k), so the grids coincide.
10"""
11import os, sys, subprocess
12import numpy as np
13
14HERE = os.path.dirname(os.path.abspath(__file__))
15N = int(sys.argv[2]) if len(sys.argv) > 2 else 16
16phi = 0.125
17mu, f, dt = 0.1, 1e-3, 60.0
18R = (phi * 3 / (4 * np.pi)) ** (1 / 3) * N
19c = N / 2.0
20OUT = f"/tmp/cmp_{{}}_{N}.npy"
21
22
24 sys.path.insert(0, os.path.join(HERE, "..", "build_omp"))
25 from peclet import flow as sdflow
26 g = np.arange(N); X, Y, Z = np.meshgrid(g, g, g, indexing="ij")
27 sdf = np.asfortranarray(np.sqrt((X - c) ** 2 + (Y - c) ** 2 + (Z - c) ** 2) - R)
28 s = sdflow.SolverColocated(N, N, N)
29 s.set_rho(1.0); s.set_mu(mu); s.set_dt(dt); s.set_body_force(f, 0, 0); s.set_advection(False)
30 s.set_velocity_solver_params(300); s.set_pressure_multigrid(True, levels=max(2, int(np.log2(N)) - 1))
31 s.set_pressure_pcg(True, 300, 1e-10); s.set_solid(sdf, cutcell_pressure=True)
32 prev = 0.0
33 for it in range(800):
34 s.step()
35 if it % 5 == 4:
36 m = float(s.get_u().mean())
37 if it > 10 and abs(m - prev) < 1e-7 * (abs(m) + 1e-30):
38 break
39 prev = m
40 np.save(OUT.format("sdflow"), np.asarray(s.get_u()))
41
42
43def run_amr():
44 sys.path.insert(0, os.path.join(HERE, "..", "..", "transport-core", "python", "build"))
45 import tpx_amr
46 def sph(x, y, z):
47 return ((x - c) ** 2 + (y - c) ** 2 + (z - c) ** 2) ** 0.5 - R
48 oct = tpx_amr.Octree([N, N, N], 0, [-0.5, -0.5, -0.5], 1.0)
49 fl = tpx_amr.Flow(oct, 1.0, mu, dt); fl.set_body_force(f, 0, 0); fl.set_advection(False); fl.set_solid(sph)
50 # The device Stokes MG-PCG amplifies a near-nullspace mode over MANY steps; 120 steps is the
51 # converged plateau (matches the registration study), well before the blow-up.
52 for _ in range(120):
53 fl.step(100, 60)
54 ua = np.asarray(fl.velocity(0)); cen = np.rint(np.asarray(oct.centers())).astype(int)
55 u = np.zeros((N, N, N)); u[cen[:, 0], cen[:, 1], cen[:, 2]] = ua
56 np.save(OUT.format("amr"), u)
57
58
59def compare():
60 env = dict(os.environ, OMP_NUM_THREADS=os.environ.get("OMP_NUM_THREADS", "4"))
61 for mode in ("sdflow", "amr"):
62 subprocess.run([sys.executable, __file__, mode, str(N)], check=True, env=env,
63 stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
64 u_sd = np.load(OUT.format("sdflow")); u_amr = np.load(OUT.format("amr"))
65 g = np.arange(N); X, Y, Z = np.meshgrid(g, g, g, indexing="ij")
66 dist = np.sqrt((X - c) ** 2 + (Y - c) ** 2 + (Z - c) ** 2) - R
67 ksd = f * N ** 3 / (6 * np.pi * mu * R * u_sd.mean())
68 kam = f * N ** 3 / (6 * np.pi * mu * R * u_amr.mean())
69 print(f"N={N} phi={phi} K_sdflow={ksd:.4f} ({100*(ksd-4.292)/4.292:+.2f}%) "
70 f"K_amr={kam:.4f} ({100*(kam-4.292)/4.292:+.2f}%)")
71 d = u_sd - u_amr
72 print(f" Umean: sdflow {u_sd.mean():.5e} amr {u_amr.mean():.5e} Δmean {d.mean():+.3e} "
73 f"max|du| {np.abs(d).max():.3e} (u scale {u_sd.max():.3e})")
74 solid = dist <= 0; cut = (dist > 0) & (dist < 1.5); bulk = dist >= 1.5
75 tot = d.mean()
76 for name, msk in [("solid", solid), ("cut-band(<1.5h)", cut), ("bulk(>1.5h)", bulk)]:
77 contrib = d[msk].sum() / d.size
78 nz = np.abs(d[msk])
79 print(f" {name:16s}: ncells={int(msk.sum()):6d} mean|du|={nz.mean():.3e} max|du|={nz.max():.3e} "
80 f"Δmean-contrib={contrib:+.3e} ({100*contrib/tot if tot else 0:+6.1f}% of Δmean)")
81
82
83if __name__ == "__main__":
84 mode = sys.argv[1] if len(sys.argv) > 1 else "compare"
85 {"sdflow": run_sdflow, "amr": run_amr, "compare": compare}[mode]()