Suite Architecture¶
Status: design document (living). Companion to CONVENTIONS, STYLE, INTERFACES, ROADMAP.
Purpose¶
The suite simulates transport phenomena with several complementary methods. Each method is its own code and stays that way — but they should correspond: share data conventions, geometry (SDF-described solids), the immersed-boundary methodology, GPU support, MPI domain decomposition with asynchronous ghost-layer exchange, and Python bindings. This document defines the layering that makes that correspondence concrete, so a developer moving between codes finds the same primitives, the same conventions, and the same interfaces.
Method taxonomy¶
| Code | Kind | State representation | Status |
|---|---|---|---|
flow |
Eulerian | Structured grid: staggered MAC (default) or collocated/cell-centered, via a GridLayout policy |
Extensively developed |
dem |
Lagrangian | Particles (DEM/XPBD), SoA on GPU | Extensively developed |
voro |
Mixed | Moving particles + their Voronoi cells (Lagrangian carriers, Eulerian-like fluxes across cell faces) | Developed; Kokkos + nanobind Python |
morton |
Primitive | Z-order codes / spatial index | Mature |
(block_decomposer, the original source of the shared MPI layer, has been retired/archived; its
reusable parts now live in core.)
The Eulerian/Lagrangian/mixed split is the key axis: it determines what travels in a halo exchange (grid cell slabs vs. migrating particles vs. ghost particles + cell neighbours) but not the decomposition (all use the same block decomposition) nor the geometry (all use the same SDF + IBM).
Layered design¶
┌──────────────────────────────────────────────────────────┐
methods │ flow dem voro (future) │ separate repos
└──────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────────────────┐
core │ core │ new shared repo
│ decomposition · halo (async MPI) · geometry/SDF · ibm │
│ common types/conventions · python (nanobind bridge) │
└──────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌──────────────────┐
primitives │ morton │ │ Kokkos, ArborX, │ external / vendored
│ (block/cell index) │ │ Voro++, MPI, ... │
└─────────────────────┘ └──────────────────┘
Rule: dependencies point downward only. A method depends on core; core
depends on primitives. No method depends on another method; primitives depend on nothing in the suite.
core modules¶
- common — shared types and conventions in code form (vector/index aliases, axis order, units, error/logging). Codifies CONVENTIONS.
- decomposition — orthogonal recursive bisection of the global domain into rank-owned blocks
(
BlockDecomposer), global↔local indexing with ghost layers (BlockIndexer), and morton/Z-order cell indexing (viamorton). Ported fromblock_decomposer. - halo — the asynchronous ghost-layer exchange. One
HaloExchangeinterface, two engines: an NBX nonblocking-consensus loop for dynamic/sparse patterns (particle migration) and a persistent neighborhood-collective path for static grid halos. Field-agnostic pack/unpack so a grid scalar field, a grid vector field, and a particle attribute array all flow through one path. GPU-aware (device-buffer exchange, on-device pack/unpack). - geometry/SDF — one signed-distance representation (analytic shapes + grid SDF), VTI/VTP I/O, the shared sign convention (negative inside solid). All three methods already use SDFs; this unifies them.
- ibm — the common Immersed Boundary Method interface: cut-cell / boundary data derived from an
SDF, consumed by Eulerian solvers (and the point-shell collision analog in
dem). - python — the shared nanobind zero-copy array bridge (
peclet::core::python,include/tpx/python/ndarray_interop.hpp) so every method exposes Python the same way (array shapes, ownership, naming). Host Views/vectors export as NumPy without a copy; device Views export as DLPack for CuPy/PyTorch. Provisioned viacmake/SuiteNanobind.cmake; see CONVENTIONS §6.
How each method maps onto the core¶
- flow (Eulerian): the global MAC grid is partitioned by
decomposition; each rank owns a block with ghost cells; per-step it exchanges grid-field halos through the persistent neighborhood path; SDF geometry + IBM come fromgeometry/ibm. First solver to be wired in (most grid-native). - dem (Lagrangian): particles are owned by the block containing them; per-step it does particle migration (NBX path) + ghost-particle exchange near block boundaries; collision geometry uses the shared SDF. Reuses its existing ArborX broad-phase locally inside a block.
- voro (mixed): particles migrate like Lagrangian carriers (NBX path), but each rank
also needs ghost particles one interaction radius deep to close the Voronoi cells touching the
block boundary; fluxes across Voronoi faces are the Eulerian aspect. Gets nanobind bindings via
python.
What stays method-specific¶
Numerical schemes and solvers: the CFD Newton/projection solver, the XPBD constraint solver, the
Voronoi tessellation/half-edge machinery, the ADI solver (kept in block_decomposer as a core
consumer, not in the core). The core provides where data lives and how it moves, not how the
physics is integrated.