flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
verify_mpi_spheres_sdflow.py
Go to the documentation of this file.
1#!/usr/bin/env python
2"""Distributed (MPI) flow validation driver — mirrors tests/kokkos_mpi/test_sdflow_mpi.cpp in Python.
3
4Builds a GLOBAL 2x2x2 periodic sphere-packing SDF on every rank, uses peclet.flow.mpi_block(N,N,N) to
5get this rank's ORB block, slices the local SDF, constructs Solver(*size), init_mpi(N,N,N), configures
6rho/mu/dt/body-force, sets the local solid, runs STEPS steps, and reduces the global velocity sum via
7mpi4py. The reduced permeability k = mu*<u>/F must be the SAME across np=1,2,4 (the distributed solve is
8bit-exact to single-rank, to the MG-PCG reduction-order floor).
9
10Run:
11 PYTHONPATH=$PWD/build_mpi mpirun -np 1 ./.venv/bin/python scripts/verify_mpi_spheres_sdflow.py
12 PYTHONPATH=$PWD/build_mpi mpirun -np 2 ./.venv/bin/python scripts/verify_mpi_spheres_sdflow.py
13 PYTHONPATH=$PWD/build_mpi mpirun -np 4 ./.venv/bin/python scripts/verify_mpi_spheres_sdflow.py
14"""
15import numpy as np
16from mpi4py import MPI
17import peclet.flow
18
19N, STEPS = 32, 120
20RHO, MU, F, DT = 1.0, 0.1, 1e-3, 60.0
21
22
23def packing_sdf(rfrac=0.18):
24 """Global 2x2x2 sphere-packing SDF as an (N,N,N) Fortran-order array (negative inside, periodic)."""
25 R = rfrac * N
26 cs = np.array([0.25 * N, 0.75 * N])
27 xs = np.arange(N)
28 X, Y, Z = np.meshgrid(xs, xs, xs, indexing="ij") # (N,N,N) x-fastest via order F below
29 best = np.full((N, N, N), 1e30)
30 for sx in cs:
31 for sy in cs:
32 for sz in cs:
33 dx = X - sx; dx -= N * np.round(dx / N)
34 dy = Y - sy; dy -= N * np.round(dy / N)
35 dz = Z - sz; dz -= N * np.round(dz / N)
36 best = np.minimum(best, np.sqrt(dx * dx + dy * dy + dz * dz) - R)
37 return np.asfortranarray(best)
38
39
40def configure(s):
41 s.set_rho(RHO); s.set_mu(MU); s.set_dt(DT); s.set_body_force(F, 0.0, 0.0)
42 s.set_advection(False)
43 s.set_velocity_solver_params(80)
44 s.set_pressure_multigrid(True, 4)
45 s.set_pressure_pcg(True, 200, 1e-9)
46
47
48def main():
49 comm = MPI.COMM_WORLD
50 rank, size = comm.Get_rank(), comm.Get_size()
51
52 gsdf = packing_sdf() # (N,N,N) F-order on every rank
53 gcells = float(N * N * N)
54
55 origin, bsize = peclet.flow.mpi_block(N, N, N)
56 ox, oy, oz = origin
57 lnx, lny, lnz = bsize
58
59 # Slice this rank's LOCAL inner block from the global SDF (x-fastest / F-order indexing [x,y,z]).
60 lsdf = np.asfortranarray(gsdf[ox:ox + lnx, oy:oy + lny, oz:oz + lnz])
61
62 s = peclet.flow.Solver(lnx, lny, lnz)
63 s.init_mpi(N, N, N)
64 configure(s)
65 s.set_solid(lsdf, cutcell_pressure=True)
66 for _ in range(STEPS):
67 s.step()
68
69 lsum = float(np.sum(s.get_u()))
70 gsum = comm.allreduce(lsum, op=MPI.SUM)
71 k = MU * (gsum / gcells) / F
72 div = s.max_open_divergence()
73
74 if rank == 0:
75 print(f"np={size}: rank={s.rank()} size={s.size()} k={k:.12e} div={div:.3e} "
76 f"block(rank0)=origin{origin} size{bsize}")
77 return k, div
78
79
80if __name__ == "__main__":
81 main()