flow 0.4.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
collocated_zh_schemes.py
Go to the documentation of this file.
1#!/usr/bin/env python
2"""Zick & Homsy grid convergence of the COLLOCATED schemes, in the protocol the
3staggered-vs-collocated example page quotes (warm_tol 1e-7, tail 40, up to 4000 steps).
4
5Regenerates the page's collocated columns now that "gauge-exact" (the former set_face_interp(9))
6is the default. Reproducing the published "plain" column is the control that the harness matches
7the earlier runs.
8
9 SDFLOW_BUILD=build_ge python tests/study/collocated_zh_schemes.py
10"""
11import os
12import sys
13import time
14
15import numpy as np
16
17sys.path.insert(0, os.path.abspath(os.path.join(
18 os.path.dirname(__file__), "..", "..", os.environ.get("SDFLOW_BUILD", "build"))))
19from peclet import flow # noqa: E402
20
21PHI0, K_ZH = 0.125, 4.292
22
23
24def sphere_sdf(N, phi):
25 R = (3 * phi / (4 * np.pi)) ** (1 / 3) * N
26 g = np.arange(N) + 0.5
27 X, Y, Z = np.meshgrid(g, g, g, indexing="ij")
28 d = lambda A, c: A - c * N - N * np.round((A - c * N) / N) # noqa: E731
29 return np.sqrt(d(X, .5) ** 2 + d(Y, .5) ** 2 + d(Z, .5) ** 2) - R, R
30
31
32def drag(N, scheme, mu=0.1, F=1e-3, dt=80.0, warm_tol=1e-7, tail=40, max_steps=4000):
33 sdf, R = sphere_sdf(N, PHI0)
34 s = flow.SolverColocated(N, N, N)
35 s.set_rho(1.0); s.set_mu(mu); s.set_dt(dt)
36 s.set_body_force(F, 0, 0); s.set_advection(False)
37 s.set_velocity_solver_params(150)
38 s.set_pressure_multigrid(True, max(2, int(np.log2(N)) - 1))
39 s.set_pressure_pcg(True, 200, 1e-8)
40 s.set_collocated_scheme(scheme)
41 s.set_solid(sdf, cutcell_pressure=True, pressure_coarse="rediscretized")
42 prev, warm, um, pit, t0 = 0.0, None, [], [], time.time()
43 for it in range(max_steps):
44 s.step()
45 um.append(float(s.get_u().mean())); pit.append(int(s.last_pressure_iterations()))
46 if warm is None:
47 if it % 10 == 9:
48 if it > 10 and abs(um[-1] - prev) < warm_tol * (abs(um[-1]) + 1e-30):
49 warm = it
50 prev = um[-1]
51 elif it - warm >= tail:
52 break
53 umean = float(np.mean(um[-tail:]))
54 K = F * N ** 3 / (6 * np.pi * mu * R * umean)
55 return K, 100 * (K - K_ZH) / K_ZH, float(np.mean(pit[-tail:])), it + 1, time.time() - t0
56
57
58if __name__ == "__main__":
59 Ns = [int(x) for x in (sys.argv[1:] or [32, 48, 64, 96, 128])]
60 print(f"{'N':>5} {'scheme':>12} {'K':>9} {'err %':>9} {'p.iters':>8} {'steps':>7} {'secs':>7}")
61 out = {}
62 for scheme in ("plain", "gauge-exact"):
63 for N in Ns:
64 K, e, pit, st, secs = drag(N, scheme)
65 out.setdefault(scheme, []).append((N, e))
66 print(f"{N:>5} {scheme:>12} {K:>9.4f} {e:>+9.3f} {pit:>8.1f} {st:>7} {secs:>7.1f}",
67 flush=True)
68 print("\nobserved order (|err| ratio between successive N):")
69 for scheme, rows in out.items():
70 ords = [f"{np.log(abs(rows[i-1][1]/rows[i][1]))/np.log(rows[i][0]/rows[i-1][0]):+.2f}"
71 for i in range(1, len(rows))]
72 print(f" {scheme:>12}: " + " ".join(ords))
73 print("\nPUBLISHED col cutcell (plain) for the control: "
74 "+1.004 +0.685 +0.598 +0.397 +0.299 at N=32,48,64,96,128")
drag(N, scheme, mu=0.1, F=1e-3, dt=80.0, warm_tol=1e-7, tail=40, max_steps=4000)