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
7Face sdf = mean of the two adjacent centres, exactly as the solver classifies it.
11import scipy.sparse
as sp
12import scipy.sparse.csgraph
as csg
14pack, R = sys.argv[1], float(sys.argv[2])
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):
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:
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])
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))
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)")
52 """connected components of the pressure graph over `active` cells."""
53 idx = -np.ones(n, np.int64)
56 idx[ii] = np.arange(len(ii))
57 ID = np.arange(n).reshape(G)
60 m = open_faces[ax_] & active & np.roll(active, 1, axis=ax_)
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
70cur_open = [np.roll(fluidC, 1, axis=a) & fluidC
for a
in range(3)]
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")
comps(open_faces, active)