28RHO, MU, F, DT = 1.0, 0.1, 1e-3, 60.0
31CEN = [(0.25*N, 0.25*N, 0.25*N), (0.75*N, 0.75*N, 0.25*N),
32 (0.75*N, 0.25*N, 0.75*N), (0.25*N, 0.75*N, 0.75*N)]
37 ni = np.array([1, -1, -1], dtype=np.int32)
38 nr = np.zeros(KN_R); nr[0] = R; nr[14] = 1.0; nr[15] = 1.0
39 ii = np.zeros((len(CEN), KI_I), dtype=np.int32)
40 ir = np.zeros((len(CEN), KI_R))
41 for m, c
in enumerate(CEN):
42 ii[m] = (0, -1); ir[m, 0:3] = c; ir[m, 6] = 1.0; ir[m, 7] = 1.0
43 return ni, nr, ii.ravel(), ir.ravel()
47 ref = np.load(os.path.join(OUT,
"np1.npz"))
50 p = os.path.join(OUT,
"np%d.npz" % np_)
51 if not os.path.exists(p):
52 print(
" np=%d: missing" % np_)
55 dk = abs(d[
"k"] - ref[
"k"]) / abs(ref[
"k"])
56 df = np.abs(d[
"F"] - ref[
"F"]).max() / max(np.abs(ref[
"F"]).max(), 1e-300)
57 dfr = (np.abs(d[
"FR"] - ref[
"FR"]).max() / max(np.abs(ref[
"FR"]).max(), 1e-300)
58 if "FR" in d
and "FR" in ref
else float(
"nan"))
59 downer = int(d[
"owner_mismatch"])
60 dsdf = float(d[
"sdf_maxdiff"])
61 print(
" np=%d vs np=1: k rel diff %.3e traction F rel diff %.3e "
62 "REACTION F rel diff %.3e owner mismatches %d sdf max diff %.3e"
63 % (np_, dk, df, dfr, downer, dsdf))
64 if dk > 1e-9
or df > 1e-6
or downer
or dsdf != 0.0:
66 print(
"GATE %s [scene geometry EXACT per rank; k and resolved loads agree across np]"
67 % (
"PASS" if ok
else "FAIL"))
72 from mpi4py
import MPI
75 rank, size = comm.Get_rank(), comm.Get_size()
78 g = np.arange(N).astype(float)
79 X, Y, Z = np.meshgrid(g, g, g, indexing=
"ij")
80 gsdf = np.full((N, N, N), 1e30)
81 gd = np.empty((len(CEN), N, N, N))
82 for kk, (cx, cy, cz)
in enumerate(CEN):
83 dx = np.abs(X-cx); dx = np.minimum(dx, N-dx)
84 dy = np.abs(Y-cy); dy = np.minimum(dy, N-dy)
85 dz = np.abs(Z-cz); dz = np.minimum(dz, N-dz)
86 gd[kk] = np.sqrt(dx*dx+dy*dy+dz*dz) - R
88 gowner = np.argmin(gd, axis=0)
90 origin, bsize = sdflow.mpi_block(N, N, N)
94 s = sdflow.Solver(lnx, lny, lnz)
96 s.set_rho(RHO); s.set_mu(MU); s.set_dt(DT); s.set_body_force(F, 0.0, 0.0)
97 s.set_advection(
False)
98 s.set_velocity_solver_params(80)
99 s.set_pressure_multigrid(
True, 4)
100 s.set_pressure_pcg(
True, 200, 1e-9)
101 s.set_scene(*
scene(), periodic=
True)
102 s.set_solid_from_scene(
True)
105 lowner = np.asarray(s.get_cut_owner())
106 ref_owner = gowner[ox:ox+lnx, oy:oy+lny, oz:oz+lnz]
107 owner_bad = int((lowner != ref_owner).sum())
108 owner_bad = comm.allreduce(owner_bad, op=MPI.SUM)
111 for _
in range(STEPS):
113 lsum = float(np.sum(np.asarray(s.get_u())))
114 gsum = comm.allreduce(lsum, op=MPI.SUM)
115 k = MU * (gsum / float(N**3)) / F
116 Fh = np.asarray(s.diagnostics.hydro_force_torque_traction())[0]
117 FR = np.asarray(s.hydro_force_torque_reaction())[0]
118 Nc = s.fluid_momentum_cells()
119 div = s.max_open_divergence()
122 print(
"np=%d k=%.12e div=%.3e owner mismatches=%d sum|F|=%.6e "
123 "reaction identity-1=%+.3e"
124 % (size, k, div, owner_bad, np.abs(Fh).sum(),
125 FR[:, 0].sum() / (F * Nc[0]) - 1))
126 np.savez(os.path.join(OUT,
"np%d.npz" % size), k=k, F=Fh, FR=FR,
127 owner_mismatch=owner_bad, sdf_maxdiff=sdf_diff)