flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
collocated_zh_embed.py
Go to the documentation of this file.
1"""Z&H sphere-array drag A/B: collocated EMBED momentum (setFaceInterp(5), Basilisk embed.h true-normal
2dirichlet_gradient wall drag) vs mode 0. ROBUST convergence: run past a min-step floor until the drag
3drifts < 5e-5 over 200 steps (avoids false early plateaus), report K + the residual drift so convergence
4is visible. Incremental-rotational pressure + warm-start. Success: order -> ~2, error below mode 0."""
5import os, sys, time
6sys.path.insert(0, os.path.abspath("build_cuda2"))
7import numpy as np
8from peclet import flow
9
10def lattice_sdf(N, phi=0.125):
11 R = (3 * phi / (4 * np.pi))**(1 / 3) * N
12 g = np.arange(N) + 0.5; X, Y, Z = np.meshgrid(g, g, g, indexing="ij")
13 dx = X - 0.5 * N; dx -= N * np.round(dx / N)
14 dy = Y - 0.5 * N; dy -= N * np.round(dy / N)
15 dz = Z - 0.5 * N; dz -= N * np.round(dz / N)
16 return np.sqrt(dx * dx + dy * dy + dz * dz) - R, R
17
18def drag(N, mode, mu=0.1, F=1e-3, dt=400.0, min_steps=500, max_steps=3500, dtol=5e-5):
19 sdf, R = lattice_sdf(N); lv = max(2, int(np.log2(N)) - 1)
20 s = flow.SolverColocated(N, N, N)
21 s.set_rho(1.0); s.set_mu(mu); s.set_dt(dt); s.set_body_force(F, 0, 0); s.set_advection(False)
22 s.set_velocity_solver_params(200); s.set_pressure_multigrid(True, levels=lv)
23 s.set_pressure_pcg(True, 500, 1e-12); s.set_face_interp(mode); s.set_pressure_warmstart(True)
24 s.set_solid(sdf, cutcell_pressure=True, pressure_coarse="rediscretized")
25 kfac = F * N**3 / (6 * np.pi * mu * R); hist = []; t0 = time.time(); drift = 1.0
26 for it in range(max_steps):
27 s.step()
28 if it % 50 == 49:
29 K = kfac / float(s.get_u().mean()); hist.append(K)
30 if len(hist) >= 5:
31 drift = abs(hist[-1] - hist[-5]) / abs(hist[-1]) # over 200 steps
32 if it + 1 >= min_steps and drift < dtol: break
33 return hist[-1], it + 1, drift, time.time() - t0
34
35kref = 4.2920
36print(f"Z&H K={kref}. Collocated EMBED (mode 5) vs mode 0. drift = |dK| over last 200 steps.", flush=True)
37print(f"{'N':>4} | {'mode0 err%':>10} {'ord':>5} {'drift':>8} | {'embed err%':>11} {'ord':>5} {'drift':>8} | secs",
38 flush=True)
39p0 = p5 = pN = None
40for N in (32, 48, 64, 96, 128):
41 K0, st0, d0, s0 = drag(N, 0); K5, st5, d5, s5 = drag(N, 5)
42 e0 = 100 * (K0 - kref) / kref; e5 = 100 * (K5 - kref) / kref
43 o0 = np.log(abs(p0) / abs(e0)) / np.log(N / pN) if p0 else float("nan")
44 o5 = np.log(abs(p5) / abs(e5)) / np.log(N / pN) if p5 else float("nan")
45 print(f"{N:>4} | {e0:>+10.4f} {o0:>+5.2f} {d0:>8.1e} | {e5:>+11.4f} {o5:>+5.2f} {d5:>8.1e} | {s0+s5:>4.0f}",
46 flush=True)
47 p0, p5, pN = e0, e5, N
drag(N, mode, mu=0.1, F=1e-3, dt=400.0, min_steps=500, max_steps=3500, dtol=5e-5)