Distributed NumPy/CuPy arrays over MPI, with halo exchange, that you create like NumPy arrays:
import numpy as np
import mpiarray as mpa
a = mpa.array([1, 2, 3, 4]) # mpiexec -n 2: rank 0 holds [1, 2], rank 1 holds [3, 4]
b = mpa.zeros((64, 48), split=(0, 1), halo=1, periodic=(True, False))
c = 2 * a + np.sin(a) # elementwise: no communication
total = c.sum() # collective: the same value on every rank
full = c.gather() # collective: the whole array on every rank
print(c) # this rank's block; printing never communicatesmpiexec -n 2 python example.py # or just: python example.py- Creation like NumPy:
array,zeros,ones,full,empty, the*_likeversions,arange,linspaceandfromfunction, which compute only the local block. Arrays are split along their first axis by default;split=chooses other axes,split=Nonegives every rank the whole array. - Halo cells per axis:
update_halos()before a stencil,accumulate_halos()after depositing particles near block edges; both can overlap with computation (wait=False). - Operators, ufuncs and reductions as in NumPy (
sum,max,mean,var,argmax,cumsum,norm,vdot, …), and NumPy’s functions (np.mean(a, axis=0),np.allclose,np.where, …) through__array_function__. Global reductions return the same host scalar on every rank; reductions along axes and slices (a[2:10, :]) return distributed arrays, without gathering anything. - Redistribution and load balancing:
redistributemoves an array to any other layout with oneAlltoallv; explicit or weighted cut points (Layout(bounds=...),Layout.weighted,rebalance) andlayout.alignedfor cell and node arrays. - Particles:
layout.ownersfinds the rank of many cells at once,mpa.migratesends rows of NumPy or CuPy arrays to their ranks. - NumPy or CuPy: arrays come from
cunumpy, so the same code
runs on the GPU. Device buffers are copied through host memory unless
the program declares its MPI CUDA-aware
(
xp.mpi.set_mpi_cuda_aware(True)orxp.mpi.mpi_is_cuda_aware(comm)). - With or without MPI: without an MPI launcher the script runs as
one rank on maybempi’s stand-in for
mpi4py.MPI, without importing mpi4py. - Data in and out:
from_localbuilds an array from the pieces the ranks hold;save/loadwrite and read ordinary.npyfiles in parallel with MPI-IO, andsave_hdf5/load_hdf5several arrays and attributes in one HDF5 file (mpiarray[hdf5]). - Halo boundary conditions at walls: constant,
"edge","symmetric","reflect". - Debugging: with
MPIARRAY_DEBUG=1, a collective called on only some ranks raises an error instead of hanging.
Each array has a layout (a mpa.Layout) with its process grid,
neighbours and owned index ranges; most code only reads it.
Documentation: https://max-models.github.io/mpiarray/
pip install "mpiarray[mpi]" # with mpi4py, for runs under mpiexec
pip install mpiarray # serial only, no MPI library needed
pip install "mpiarray[hdf5]" # with h5py, for save_hdf5/load_hdf5The mpi extra installs mpi4py, which
needs an MPI library, e.g. brew install open-mpi or
sudo apt-get install libopenmpi-dev openmpi-bin. Without it, mpiarray
runs on maybempi’s serial stand-in for mpi4py.MPI, as one rank holding
the whole array. Starting such an installation with mpiexec gives a
warning, and every process then computes the whole problem on its own.
For development, with uv:
make install # uv sync --extra dev, plus the pre-commit hooksor with pip, in a Python 3.10+ environment:
pip install -e ".[dev]"The test, docs and dev extras install the test runner, the
documentation tooling and the linters; dev includes mpi.
Formatting and linting use ruff, type checking pyright and ty, run by pre-commit and in CI:
make lint # ruff check, ruff format --check, pyright, ty
make test # pytest with coverageThe tests run serially and under MPI; some only run on 2 or 6 ranks:
mpiexec -n 2 .venv/bin/python -m pytest
mpiexec -n 6 .venv/bin/python -m pytest
make coverage # serial and 2, 3, 4, 6 ranks, combined; fails below 100% line and branch coverageThe CuPy code paths run on the CPU with cunumpy’s fake CuPy
(CUNUMPY_FAKE_CUPY=1 CUNUMPY_BACKEND=cupy); .gitlab-ci.yml runs the
tests on NVIDIA GPUs.
Commit messages follow Conventional Commits; see CONTRIBUTING.md.
The documentation in docs/ is an Astro + Starlight site: hand-written
pages, the notebooks in guides/ executed and published as pages, and
the API reference generated from the docstrings with
starlight-pydocs. It needs
Node 22 or newer.
make docs-install # npm packages and the Python docs extra
make docs-notebooks # execute guides/*.ipynb and convert them to pages
make docs-dev # live preview at http://localhost:4321/mpiarray/
make docs-build # the static site in docs/distREADME.md is rendered from README.qmd with
Quarto:
make readmeBefore merging a release to main, update the version in
pyproject.toml, src/mpiarray/__init__.py and CITATION.cff
(including its release date), and add the release notes to
CHANGELOG.md. The push to main creates a GitHub release with a
vX.Y.Z tag and publishes the package to PyPI with trusted publishing
(OIDC). The one-time PyPI and GitHub configuration is described in the
publishing
guide.

