Skip to content

Peclet

PyPI version Python License: MIT Docs build DOI

A suite of GPU-accelerated and parallel codes for the simulation of transport phenomena — Eulerian (CFD / Navier–Stokes, single- and two-phase), Lagrangian (DEM / granular dynamics), mixed (Voronoi) and coupled (CFD-DEM) methods, sharing one MPI block domain decomposition with asynchronous ghost-layer exchange, SDF-described solids, a common immersed-boundary methodology, GPU support (Kokkos: CUDA / HIP / OpenMP), and Python bindings everywhere.

The name nods to the Péclet number — the ratio of advective to diffusive transport, the dimensionless heart of transport phenomena.

Watch: the 1.1.0 release film

Eight minutes on what the suite does and, at length, the evidence for it — the exact solutions first, then published experiments, then the release's own scaling record: 32 H100 GPUs carrying 1.81 billion cells at 64 % weak efficiency, every rung returning the same mean velocity to one part in ten billion. It is also open about how it was built.

Watch on YouTube · the channel @PecletHPC carries a short movie for every example in the gallery, each one linking back to the page that produced it.

Quick start (Python)

The codes are driven from Python — one peclet.* namespace, installable from PyPI. The multicore-CPU (OpenMP) build ships as self-contained wheels, and so does the single-GPU CUDA build:

pip install peclet          # CPU family: peclet-morton + peclet-flow + peclet-pnm + peclet-dem + peclet-voro
pip install peclet-cu13     # the same family as CUDA wheels (NVIDIA driver only; not alongside `peclet`)
pip install peclet-flow     # or any single package

Wheels cover Linux (x86-64 and aarch64), Windows x64 and macOS on Apple silicon, CPython 3.10–3.14, all multi-threaded — OpenMP on Linux, Kokkos' C++ threads backend on the other two, since neither of those toolchains supplies an OpenMP that Kokkos accepts (DEPLOYMENT.md). A GPU on Windows means WSL2. The Colab link below needs nothing installed at all.

Stokes flow past a sphere in a box of side L, start to finish: 2.5 s on two workstation cores, around half a minute on the two shared vCPUs of a free Colab runtime (it prints its own wall clock). The physical problem is stated in your own units and N sets the resolution, so a grid-refinement study is one number away — at a price: N = 48 is eight times the work of N = 32. Run it as is, or open the same steps as a notebook in Colab — the first cell installs the wheels:

Open in Colab Download notebook

import time

import numpy as np
import peclet.flow as flow

# --- the physical problem, in any consistent unit system -------------------------------------
L, R = 1.0, 0.2              # side of the periodic box and radius of the sphere at its centre
rho, mu = 1.0, 0.1           # fluid density and viscosity
F = 1.0                      # driving pressure gradient along x (force per unit volume)
N = 32                       # cells per side: change this for a grid-refinement study

s = flow.Solver((N, N, N), extent=(L, L, L))                    # a periodic box: a cubic lattice of spheres
s.set_rho(rho); s.set_mu(mu); s.set_dt(1e3)                    # every input physical; a large dt marches
s.set_body_force((F, 0.0, 0.0))                                #   straight to the steady Stokes flow

x, y, z = s.cell_centers()                                     # the grid the solver laid inside the box
X, Y, Z = np.meshgrid(x, y, z, indexing="ij")
sdf = np.sqrt((X - L/2)**2 + (Y - L/2)**2 + (Z - L/2)**2) - R  # signed distance, < 0 inside the sphere
s.set_solid(sdf, cutcell_pressure=True)                        # no-slip cut-cell immersed boundary

t0, u_mean = time.perf_counter(), []
for it in range(200):
    s.step()
    u_mean.append(s.get_u().mean())
    if it >= 3 and abs(u_mean[-1] - u_mean[-4]) < 1e-3 * abs(u_mean[-1]):
        break                                                  # steady: three steps have not moved it
u, v, w = s.get_u(), s.get_v(), s.get_w()                      # physical velocity, physical pressure
p = s.get_p()
k = mu * u.mean() / F                                          # Darcy permeability of the sphere lattice
print(f"{flow.execution_space}: N = {N}, {it + 1} steps, {time.perf_counter() - t0:.1f} s, "
      f"permeability k = {k:.4e}")

# --- a look at the flow: speed and streamlines on the mid-plane through the sphere ---------------
import matplotlib.pyplot as plt
c = N // 2
speed = np.hypot(u[:, :, c], v[:, :, c])
plt.figure(figsize=(5, 4.2))
plt.imshow(speed.T, origin="lower", cmap="viridis", extent=[0, L, 0, L])
plt.streamplot(x, y, u[:, :, c].T, v[:, :, c].T, color="w", density=1.2, linewidth=0.6)
th = np.linspace(0, 2 * np.pi, 180)                             # the sphere itself, drawn exactly
plt.fill(L/2 + R*np.cos(th), L/2 + R*np.sin(th), color="w", zorder=3)
plt.colorbar(label="|u|"); plt.title("Stokes flow past a sphere (periodic box)")
plt.xlabel("x"); plt.ylabel("y"); plt.tight_layout()
plt.show()

Running this in a container? Bound the thread pool first.

Kokkos sizes its OpenMP pool from the CPUs it can see. Colab, Binder, Docker and a Slurm cgroup all normally show you the whole host while granting a fraction of it, so the default pool spin-waits itself to a standstill — measured on the wheel above, this 2.5-second solve did not finish in 15 minutes on 2 CPUs of quota with 48 visible, and took 2.5 s with the pool bounded. Before importing peclet:

import os
os.environ.setdefault("OMP_NUM_THREADS", "2")   # or however many CPUs you were actually granted
os.environ.setdefault("OMP_PROC_BIND", "false")

The Colab notebook linked above resolves this process's own cgroup and takes the tightest quota on the chain — /sys/fs/cgroup/cpu.max is the cgroup root, and reads max on a host that does limit you. On a workstation you do not need it: there, visible and granted are the same.

Stokes flow past a sphere: speed and streamlines on the mid-plane

→ Examples gallery (runnable, validated notebooks) · Python API reference · Install & run (GPU / MPI / HPC containers).

The codes

Code PyPI · import Role
geom peclet-geom · peclet.geom Analytic-SDF scene authoring: CSG trees, batch evaluation, lattice baking, rigid-body mass properties. Host-only — wheels, numpy the only dependency, included in pip install peclet
core peclet-halo · peclet.halo Shared infrastructure: ORB block decomposition, async grid/particle halo, migration and rebalancing, sampled SDF geometry, VTI I/O. The C++ headers remain peclet/core/…; the Python distribution is peclet-halo
flow peclet-flow · peclet.flow Incompressible Navier–Stokes for porous media (staggered MAC or collocated grid, cut-cell IBM, multigrid), geometric VoF two-phase flow, moving analytic geometry
pnm peclet-pnm · peclet.pnm Pore-network extraction from SDF geometry (pores, watershed segmentation, throat topology) and network flow data from a flow DNS
dem peclet-dem · peclet.dem Discrete Element Method (XPBD and Hertz–Mindlin) with SDF point-shell collision for spheres and arbitrary SDF shapes
voro peclet-voro · peclet.voro Dynamic 3D Voronoi tessellation of moving particles (periodic boxes), mesh generation, Navier–Stokes on a Voronoi mesh
coupling peclet-coupling · peclet.coupling CFD-DEM: unresolved (volume-averaged drag) and resolved (cut-cell) two-way coupling of flow and dem
morton peclet-morton · peclet.morton Morton/Z-order codes with arithmetic in Morton space — the spatial-index primitive

The GPU codes are Kokkos-based: the same source runs on CUDA, HIP (AMD/LUMI) and OpenMP, chosen at build time by the install prefix, the wheel flavour (peclet vs peclet-cu13) or the container.

computational-chemical-engineering.github.io/peclet-examples is the worked-examples site: every page is a notebook executed against the released package, with an Open in Colab button and the validation numbers in the open —

  • Single-phase flow — exact and canonical benchmarks (Poiseuille, Taylor–Green, lid-driven cavity, Schäfer–Turek cylinder, Rayleigh–Bénard, turbulent channel DNS) and moving-body drag / torque cases.
  • Packings & porous media — Zick–Homsy sphere arrays, random and ring packed beds (dem → flow), pore-space Voronoi meshes, pore-network extraction.
  • Two-phase flow (VoF) — advection benchmarks, parasitic currents, capillary waves, rising bubble, wetting, bubbles and trickle flow through packings.
  • Granular (DEM) — SDF-shaped particles, rotating drum, tumbling cubes, Pall rings, stirred column.
  • CFD-DEM — fluidized bed, bubble injection, segregation, homogeneous cooling (MFIX-Exa comparisons).
  • Benchmarks — the multi-GPU and CPU scaling studies (Snellius) and a DEM bulk-flow benchmark.

Where a page has a movie, the movie is on @PecletHPC — a bubble squeezing through a packed bed, a million-particle fluidized bed, tumbling cubes in a drum, Rayleigh–Bénard convection, trickle flow over a packing, the tennis-racket effect — and each video's description links straight back to the page with the code and the numbers.

Documentation

Citing

If you use Peclet in your research, please cite it. Each release is archived on Zenodo:

  • Concept DOI (all versions): 10.5281/zenodo.21132445 — always resolves to the latest release; use this unless you need to pin an exact version.
  • A specific version: the Zenodo record above lists a version DOI for every release, and each GitHub release links to its own.

Machine-readable metadata lives in CITATION.cff — use GitHub's "Cite this repository" button for ready-made BibTeX/APA.