FoamNordic¶
FOAM Native Orchestration Runtime for Distributed Inference Coupling
FoamNordic couples OpenFOAM fields to mathematical and machine-learning operators without making Python part of the solver loop. The same Longship interface runs an unchanged OpenFOAM case, a field transform, or an equation-level closure supplied by any compatible solver adapter.
Documentation · Installation · API
FNOM stores the model payload, tensor contracts, scaling and runtime metadata. BindNordic evaluates it; Fjord exchanges fields over shared memory, Unix sockets, UCX or TCP; Longship manages placement, execution and results.
Python 3.11 and 3.12 are supported. See the changelog for release notes and upgrade guidance.
Architecture¶
The diagrams separate workload setup and launch from the field exchange and inference path used during solver execution.
| Figure 1: Setup and launch. | Figure 2: Runtime exchange and inference. |
Requirements¶
| Component | Requirement |
|---|---|
| Python | CPython 3.11 or 3.12 |
| OpenFOAM | A supported installation with its compiler and MPI environment for solver execution |
| Operating system | Linux x86_64, Linux aarch64, or Apple Silicon |
| ONNX Runtime | Downloaded by foamnordic build, or supplied through FOAMNORDIC_ONNX_RUNTIME_ROOT |
Linux with OpenFOAM v2512 is the primary HPC target. OpenFOAM.app supplies the native macOS environment.
Install¶
Install the PyPI release with pip or uv:
pip install foamnordic
Or, in an existing virtual environment:
uv pip install foamnordic
Follow the installation guide for optional environment setup, OpenFOAM activation, build checks and separate main or editable installation instructions. Add foamnordic[ml] for CPU model training or foamnordic[ml-cuda12] for Linux CUDA 12 training.
Installing the Python package does not install OpenFOAM. Build the integration in the target OpenFOAM environment, then run foamnordic doctor there before launching a case.
On macOS with OpenFOAM.app, enter its environment before building:
openfoam
foamnordic build
foamnordic doctor
Keep the Python environment containing FoamNordic active inside the OpenFOAM shell.
Quick start¶
from pathlib import Path
import foamnordic as fno
case = fno.OpenFOAM.Case(
name="lidDrivenCavity",
case_dir=Path("cases/lidDrivenCavity"),
run_dir=Path("output"),
of_cmd="module load openfoam/2512",
shell="bash", # HPC: bash | macOS: zsh
application="pimpleFoam",
)
case.initialize(ranks=1, mesh="blockMesh", validate_mesh=True)
run = fno.Longship(case=case).launch()
result = run.stop(timeout=900, progress=True)
result.summary(style="compact")
post = result.postprocess
post.statistics(["U", "p"], time_idx=-1, verbose=True)
The source case is copied into an isolated run directory. 0.orig/ is accepted when 0/ is absent. With no scheduler, rank one runs directly and multiple ranks use the MPI launcher from the declared OpenFOAM environment.
Couple a model or function¶
Transform mutates ordinary registered fields at a solver stage. Closure enters an equation-specific adapter. FoamNordic ships generic field hooks and two LES adapters (nutFjord and kEqnFjord) as integration examples; domain solvers own their conservation equations and physical closure semantics.
transform = fno.Transform(
name="predictVelocity",
operator=fno.Operator.model("velocity.fnom"),
inputs={"pressure": fno.Field("p")},
outputs={"velocity": fno.Field("U")},
at="time_step_start",
)
run = fno.Longship(case=case, transforms=(transform,)).launch()
FNOM selects compiled C++, ONNX, Joblib, Equinox, or a native regular-grid table internally, so model loading does not alter the solver-facing API. foamnordic inspect reports whether a backend is data-only or code-bearing. Stochastic functions use fno.Random.key(seed=42, scope="global"); deterministic programs need no key.
External solvers can add an equation-level adapter without including the FoamNordic source tree. See the installed-SDK externalNutFjord example.
Slurm resources¶
OpenFOAM and the node-local model worker have explicit resource declarations. One model worker is placed on every OpenFOAM node only when a coupled program is present.
openfoam_resources = fno.Slurm.openfoam(
nodes=2,
ntasks=16,
cpus_per_task=1,
mem_per_cpu="2G",
)
model_resources = fno.Slurm.model(
cpus_per_task=4,
mem_per_cpu="2G",
)
scheduler = fno.Slurm(
account="<allocation-account>",
partition="medium",
time="00:15:00",
openfoam=openfoam_resources,
model=model_resources,
)
case.initialize(ranks=16, mesh=None, validate_mesh=True)
run = fno.Longship(case=case, scheduler=scheduler, transforms=(transform,)).launch()
Same-node bulk exchange uses shared memory; multi-node runs place a resident worker beside each node's solver ranks.
Develop from source¶
uv sync --all-packages --all-extras
source .venv/bin/activate
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DFOAMNORDIC_TESTS=ON
cmake --build build --parallel
ctest --test-dir build --output-on-failure
python -m pytest
Native tests that compile the OpenFOAM integration require the target OpenFOAM environment to be active.
Documentation¶
Read the FoamNordic section of the shared Nordic documentation site for guides and API references.
- Package boundary
- Python API
- Architecture
- Benchmarks and validation
- Tutorials
- Development and publishing
FoamNordic is GPL-3.0 licensed research software. It is developed by Hanseul Kang at Aalto University under the supervision of Shervin Karimkashi.