flow 0.4.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
gp_pressure_classification.py
Go to the documentation of this file.
1"""How many pressure unknowns does the CURRENT centre-based classification throw away, and what
2does it do to fluid connectivity? Compares
3 CURRENT : cell has a row iff its CENTRE is fluid; face open iff BOTH centres fluid
4 FACE : cell has a row iff >=1 of its 6 faces has a FLUID velocity point; face open iff that
5 face point is fluid (= the paper's rule: pressure lives wherever a fluid face needs
6 a gradient)
7Face sdf = mean of the two adjacent centres, exactly as the solver classifies it.
8"""
9import sys
10import numpy as np
11import scipy.sparse as sp
12import scipy.sparse.csgraph as csg
13
14pack, R = sys.argv[1], float(sys.argv[2])
15pk = np.load(pack)
16box = np.asarray(pk["box"], float)
17G = np.round(box * R).astype(int)
18c = np.asarray(pk["centers"]) * R
19r = np.asarray(pk["scales"]) * R
20S = np.full(tuple(G), 1e30, np.float32)
21ax = [np.arange(G[k]) + 0.5 for k in range(3)]
22for sh in np.stack(np.meshgrid(*[[-1., 0., 1.]] * 3, indexing="ij"), -1).reshape(-1, 3):
23 cs = c + sh * G
24 keep = np.all((cs + (r + 3)[:, None] > 0) & (cs - (r + 3)[:, None] < G), axis=1)
25 for (cx, cy, cz), rr in zip(cs[keep], r[keep]):
26 i0, i1 = np.searchsorted(ax[0], [cx - rr - 3, cx + rr + 3])
27 j0, j1 = np.searchsorted(ax[1], [cy - rr - 3, cy + rr + 3])
28 k0, k1 = np.searchsorted(ax[2], [cz - rr - 3, cz + rr + 3])
29 if i0 >= i1 or j0 >= j1 or k0 >= k1:
30 continue
31 d = np.sqrt((ax[0][i0:i1, None, None] - cx) ** 2 + (ax[1][None, j0:j1, None] - cy) ** 2
32 + (ax[2][None, None, k0:k1] - cz) ** 2) - rr
33 np.minimum(S[i0:i1, j0:j1, k0:k1], d, out=S[i0:i1, j0:j1, k0:k1])
34
35n = int(np.prod(G))
36fluidC = S >= 0 # fluid-centred
37# minus-face of cell i along axis a = mean(S[i-1], S[i]); fluid face point <=> that mean >= 0
38Fm = [0.5 * (np.roll(S, 1, axis=a) + S) >= 0 for a in range(3)]
39nfaces = sum(Fm[a].astype(np.int8) + np.roll(Fm[a], -1, axis=a).astype(np.int8) for a in range(3))
40
41hasface = nfaces > 0
42print(f"grid {tuple(G)} R={R:g} spheres={len(c)} cells={n/1e6:.2f}M")
43print(f" fluid-centred cells {fluidC.sum():9d} ({100*fluidC.mean():.2f} %)")
44print(f" cells with >=1 fluid FACE {hasface.sum():9d} ({100*hasface.mean():.2f} %)")
45print(f" SOLID-centred but >=1 fluid face {(hasface & ~fluidC).sum():9d}"
46 f" <- no pressure unknown today")
47print(f" SOLID-centred with >=2 fluid faces {((nfaces >= 2) & ~fluidC).sum():9d}"
48 f" <- THROATS: real passages with NO continuity equation")
49print(f" fluid-centred with 0 fluid faces {(fluidC & ~hasface).sum():9d} (dead rows today)")
50
51def comps(open_faces, active):
52 """connected components of the pressure graph over `active` cells."""
53 idx = -np.ones(n, np.int64)
54 a = active.ravel()
55 ii = np.nonzero(a)[0]
56 idx[ii] = np.arange(len(ii))
57 ID = np.arange(n).reshape(G)
58 rows, cols = [], []
59 for ax_ in range(3):
60 m = open_faces[ax_] & active & np.roll(active, 1, axis=ax_)
61 src = ID[m]
62 dst = np.roll(ID, 1, axis=ax_)[m]
63 rows.append(idx[src]); cols.append(idx[dst])
64 rr = np.concatenate(rows); cc = np.concatenate(cols)
65 A = sp.coo_matrix((np.ones(len(rr)), (rr, cc)), shape=(len(ii),) * 2).tocsr()
66 ncomp, lab = csg.connected_components(A, directed=False)
67 big = np.bincount(lab).max()
68 return ncomp, len(ii), len(ii) - big
69
70cur_open = [np.roll(fluidC, 1, axis=a) & fluidC for a in range(3)] # both centres fluid
71nc, tot, orph = comps(cur_open, fluidC)
72print(f" CURRENT graph: {nc:6d} components over {tot} cells, {orph} cells outside the largest")
73nc2, tot2, orph2 = comps(Fm, hasface)
74print(f" FACE graph: {nc2:6d} components over {tot2} cells, {orph2} cells outside the largest")