flow 1.3.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
robin.py
Go to the documentation of this file.
1"""Robin eigenproblem on the disc: -lap c = mu c, D dc/dn + k c = 0 (n out of the fluid), D=R=1.
2Exact: sqrt(mu) = x with x J1(x) = Bi J0(x). Variants:
3 RF : flux form - aperture FV, kappa mass, all kappa>0 cells, wall flux A_w c/(d_centroid + 1/k)
4 RFc : same, d measured from the cell CENTRE (sdf), clamped >= 0.05 h
5 RG : linear ghost on centre-fluid cells, c_Gamma eliminated through the normal Robin relation
6 (diag += k|n_a| / (h (1+k d_n)) per crossing link; k->0 = staircase Neumann)
7"""
8import numpy as np, scipy.sparse as sp, sys
9from scipy.optimize import brentq
10from scipy.special import j0, j1
11from disc_bc import Geo, assemble_fv, smallest_eig
12
13def xref(Bi):
14 f = lambda x: x * j1(x) - Bi * j0(x)
15 return brentq(f, 1e-9, 2.4048)
16
17def run(ND, off, Bi):
18 G = Geo(ND, off); h = G.h; k = Bi
19 cells = G.kap > 1e-12
20 out = {}
21 for tag, d in (("RF", G.dwall), ("RFc", np.maximum(G.sdf, 0.05 * h))):
22 wc = np.where(cells, G.Aw / (h * h * (np.maximum(d, 1e-3 * h) + 1 / k)), 0)
23 K, _ = assemble_fv(G, G.ax, G.ay, cells, wall_coef=wc)
24 out[tag] = smallest_eig(K, G.kap[cells], k=1)[0]
25 sc = G.sdf > 0
26 n = G.n
27 X, Y = np.meshgrid(G.xc, G.yc, indexing="ij")
28 rr = np.hypot(X, Y); nx, ny = X / rr, Y / rr
29 wallc = np.zeros((n, n))
30 for i, j in zip(*np.nonzero(sc)):
31 dn = G.sdf[i, j]
32 for (di, dj, na) in ((1, 0, nx), (-1, 0, nx), (0, 1, ny), (0, -1, ny)):
33 if not sc[i + di, j + dj]:
34 th = max(dn / (dn - G.sdf[i + di, j + dj]), 1e-3)
35 wallc[i, j] += (k * dn / th / h) / (h * (1 + k * dn))
36 axb = np.zeros_like(G.ax); ayb = np.zeros_like(G.ay)
37 axb[1:-1, :] = (sc[1:, :] & sc[:-1, :]); ayb[:, 1:-1] = (sc[:, 1:] & sc[:, :-1])
38 K, _ = assemble_fv(G, axb, ayb, sc, wall_coef=wallc)
39 out["RG"] = smallest_eig(K, np.ones(sc.sum()), k=1)[0]
40 return out
41
42if __name__ == "__main__":
43 rng = np.random.default_rng(1); offs = rng.random((3, 2))
44 NDs = [16, 32, 64, 128]
45 for Bi in (0.1, 1.0, 10.0, 100.0):
46 ref = xref(Bi) ** 2
47 res = {}
48 for ND in NDs:
49 for o in offs:
50 for t, v in run(ND, o, Bi).items():
51 res.setdefault((t, ND), []).append(v / ref - 1)
52 for t in ("RF", "RFc", "RG"):
53 line = f"Bi={Bi:6g} {t:4s}"; prev = None
54 for ND in NDs:
55 e = np.sqrt(np.mean(np.square(res[(t, ND)])))
56 line += f" | N={ND:3d} {e:8.2e}" + (f" p={np.log(prev/e)/np.log(2):4.1f}" if prev else "")
57 prev = e
58 print(line)
run(ND, off, Bi)
Definition robin.py:17
xref(Bi)
Definition robin.py:13