Skip to content

Field programmes and OpenFOAM

A field programme enters OpenFOAM as either a solver-owned Closure or a stage-owned Transform. Both use the same field, observation and lifecycle infrastructure, but their call sites remain separate because only the solver knows when an equation or correction is physically valid.

Closure route

Concern Owner Primary files
User declaration and graph eligibility Python control plane core/spec.py, core/graph.py
Dictionary generation Launch preparation execution/openfoam_rendering.py, tools/templates/openfoam/
Resident closure invocation OpenFOAM integration closureHook.H, closureHook.C
Field views and atomic commit OpenFOAM integration fieldBridge.H, fieldBridge.C
Algebraic LES correction Solver adapter models/nutFjord/
Transported LES state Solver adapter models/kEqnFjord/
Reaction-rate call site Solver adapter models/progressRateFjord/

When adding an equation-level adapter, begin with the nearest existing model and preserve OpenFOAM ownership of equations and boundary correction. Use ClosureHook for the resident request and bind only adapter-owned derived values through OperationFrame. The out-of-tree externalNutFjord example is the supported reference for an adapter built against the installed SDK.

Transform route

Generic transforms are rendered as the foamNordicExchange function object and execute at one declared solver stage. The Python declaration and stage validation live in core/spec.py; rendering lives in execution/openfoam_rendering.py; fjordExchange.C owns runtime sequencing, field snapshots, validation and commit.

Resident transforms pass field views through AtomicFieldExchange. Eligible symbolic transforms remain inside OpenFOAM and evaluate through operations/frame.C. Native multi-output transforms must evaluate and validate every right-hand side before committing any output.

Observation and profiling

FieldProgramObservation converts current OpenFOAM fields into the backend-neutral observation plan. NativeAlgebraMonitor composes observation, topology tracking and sampled native telemetry without adding those responsibilities to a turbulence model or function object.

An observation is read-only and best-effort. It must not alter field values, determine solver progress or turn a slow notebook consumer into solver backpressure. Profiling remains disabled when profile_every=0.

Required checks

Change Minimum evidence
Declaration, graph or rendering Focused test_graph.py and test_plan.py coverage
Field expression tests/openfoam/test_expression.cpp and an OpenFOAM integration build
Closure output or commit order Contract test plus a solver smoke test that reads the resulting field
Observation or profiling Adapter test plus a solver smoke test that produces an observation or telemetry record
New equation-level adapter Installed-SDK build test and solver-integrated numerical acceptance test

Use the complete verification sequence before handing off a cross-boundary change.