Platform

Three components, one stack

A solver where performance and rigour are the same decision, a way to run it on any hardware without rewriting it, and a build that makes a result reproducible.


Architecture

Composition all the way down

Most solvers are assembled at runtime: a dictionary selects a model, a virtual call dispatches it, and that flexibility is paid for on every cell of every timestep — while stopping the compiler seeing across stage boundaries.

Here the equations, flux, reconstruction, gradients, closure, chemistry and integrator are all template parameters, composed at compile time into one fused update. Comparing two schemes means changing one token, with a guarantee nothing else moved.

That guarantee is not an aesthetic preference. It is what makes the attribution experiments behind our open questionsmean anything.

Case
Polyhedral meshCase dictionariesChemical mechanismBoundary conditions
KRAFTHeader-only solver core

Compile-time policies

EquationsFluxReconstructionGradientsClosureChemistryIntegrator
One fused updatestructure-of-arrays fields · CSR connectivity · 217 B/cell
Adapt chainMorton keys · sort / scan / scatter · no host round-trip
Contract
std::execution::par_unseq — 330 call sites, no vendor dialect
CPU threadscorrectness floor
Vendor stdparnvc++ offload
Parallax → SPIR-Vany vendor, old hardware
RIVETHermetic, content-addressed build — one lockfile reproduces the binary

Fig. 01From case to hardware. The parallelism contract in the middle is the whole portability argument: everything above it is standard C++, everything below it is interchangeable.

Component 01

KRAFT

Compressible and reactive finite-volume solver with GPU-native adaptive refinement

Header-onlyISO C++20Unstructured polyhedralDynamic AMR

Fused kernels, not a pipeline of passes

Profiling a 2.29 M-cell airframe sweep put the flux kernel at a third of the cost, gradients at a fifth, the viscous face sweep at a seventh — all three re-streaming the same data from memory. Because every stage is a compile-time policy rather than a virtual call, they fuse into one pass over the faces. A runtime-dispatched architecture cannot express that.

An unused model costs nothing

Fields are structures of arrays from a pooled allocator, and a closure you did not select contributes no branch, no field, no byte per cell. Hence 217 B/cell, audited line by line. Halo exchange is a few per cent of step time, so the solver is limited by arithmetic — the resource that keeps getting cheaper.

The adapt chain

01Senseflux-residual or pressure-jump criterion, per cell
02Dilatebuffer layers grown around flagged cells
03Balance2:1 level jump enforced, sticky cancellation
04Subdividehex 1→8 or Bey tet 1→8, incremental
05Match faceskey-based matching, unrefined faces frozen
06Remapconservative transfer, closure asserted
07Repartitionspace-filling curve, halos rebuilt

Every stage is a data-parallel pass. The host never sees the tree.

Fig. 02Seven stages, no serial tree walk and no host-side regridding step. Cells are addressed by integer-lattice Morton keys, so refine, balance and remap reduce to sort, scan and scatter — the primitives a GPU is built for.

L0L1L2L3

Fig. 03Levels flagged by a solution sensor around a curved front, two-to-one balanced.

01background mesh02castellate + carve03snap to surface

Fig. 04In-house generation: background mesh, castellation and carving against the surface, then snapping — all under a single outward-winding face invariant.

Component 02

PARALLAX

Standard C++ parallel algorithms, offloaded to any vendor's GPU

Zero source changesClang pluginSPIR-V / VulkanMIT

The portability trap, and the way out

Every mainstream GPU portability layer — Kokkos, RAJA, SYCL, OpenMP target offload, ISO C++ parallel algorithms — eventually compiles through a vendor compiler supporting a narrow and shrinking set of current accelerators. The effect is to abandon the one- and two-generation-old hardware most researchers and smaller institutions own.

Vulkan with SPIR-V has genuine all-vendor breadth down to old silicon, and is used almost exclusively for machine-learning inference — essentially never for PDE solvers.

Same source, different silicon

Parallax lowers standard C++ parallel algorithms to SPIR-V and dispatches them through Vulkan compute. No annotations, no custom allocators, no second code path: the translation unit that builds for CPU threads builds for the GPU. A 2014-era mobile part sustained 744 M elements/s on it.

That turns leanness into access: a solver that fits a consumer GPU, plus a runtime that reaches one of any brand and vintage.

Component 03

RIVET

Hermetic, content-addressed build and package toolchain

LLVM-basedReproducibleNo system toolchainApache-2.0

Reproducible means byte-identical, or it means nothing

A result is only reproducible if a third party can regenerate it. In practice that is defeated long before the numerics — by a compiler minor version, a library resolved differently, a timestamp baked into an object file.

Existing tools each solve a fragment: packaging, or determinism, or HPC combinatorics. None is light enough for one scientist. Rivet is built for that case — declare dependencies, commit the lockfile, and the same binary comes out on another machine. We wrote it because byte-identical results across refactors are unenforceable if the toolchain underneath drifts.

Next

See what it is pointed at

The open questions this machinery exists to answer.