FNOM artefact API¶
fno.Export.sklearn(), fno.Export.equinox(), fno.Export.onnx(), and fno.Export.table() create self-contained .fnom files. fno.Operator.model() declares an executable model and fno.Operator.table() declares a data-only lookup table; inspection returns metadata rather than raw backend bytes.
flowchart LR
A[Fitted model or table] --> B[Export]
B --> C[FNOM contract and payload]
C --> D[Models.load and validate]
C --> E[Operator.model or Operator.table]
E --> F[Native connector or resident ModelHost]
API index¶
| API | Purpose | Returns |
|---|---|---|
fno.Tensor.scalar() |
Declare one scalar port | Tensor |
fno.Tensor.vector() |
Declare a fixed-width vector port | Tensor |
fno.Tensor.tensor() |
Declare a fixed-width tensor port | Tensor |
fno.Export.sklearn() |
Export a fitted sklearn-compatible estimator | .fnom Path |
fno.Export.onnx() |
Export an ONNX model | .fnom Path |
fno.Export.equinox() |
Export an Equinox PyTree | .fnom Path |
fno.Export.table() |
Export a regular-grid lookup table | .fnom Path |
fno.Models.load() |
Inspect an FNOM manifest without executing its payload | Models.FnomArtifact |
Tensor contracts¶
fno.Tensor.scalar(*, dtype="float64")
fno.Tensor.vector(*, components=3, dtype="float64")
fno.Tensor.tensor(*, components=9, dtype="float64")
| Parameter | Type | Default | Allowed values or constraint |
|---|---|---|---|
components |
int |
3 or 9 |
Positive packed width; not present on scalar() |
dtype |
str |
"float64" |
float32 or float64 |
Every input and output in one artefact must use the same dtype. Mapping insertion order defines packed port order and each logical name must match the binding used by Closure or Transform.
Supported backends¶
| Export | Backend | Execution |
|---|---|---|
Export.sklearn() |
Compiled, native forest, or Joblib | Native C++ or resident Python |
Export.onnx() |
ONNX | Native ONNX Runtime |
Export.equinox() |
Equinox | Resident JAX |
Export.table() |
Regular-grid table | Native multilinear interpolation |
Export.sklearn() uses backend="auto" by default: supported estimators use the compiled backend and other sklearn-compatible predictors use Joblib. Select compiled, forest, or joblib explicitly only when the deployed representation must be fixed. The native forest backend accepts ExtraTreesRegressor and RandomForestRegressor; Joblib accepts a fitted object with predict() or a callable object.
Joblib models receive a NumPy array by default. Set input_format="pandas" or input_format="polars" when a model requires a named DataFrame; FoamNordic records the choice in FNOM and constructs columns from the declared scalar input ports in their contract order. These formats require the corresponding optional dependency in the ModelHost environment, while compiled backends retain the NumPy-only native path.
Compiled estimators¶
| Family | Models |
|---|---|
| Linear | LinearRegression, Ridge, Lasso, ElasticNet |
| Forest | ExtraTreesRegressor, RandomForestRegressor |
| Nearest neighbours | KNeighborsRegressor |
| Boosting | GradientBoostingRegressor, XGBRegressor, XGBRFRegressor, LGBMRegressor |
| Ensemble | VotingRegressor composed only of supported models |
Compiled estimators emit one numerical value per prediction; this is a model output-width limit, independent of the OpenFOAM field type. Joblib, ONNX and Equinox support wider outputs. Leave backend="auto" selected to fall back to Joblib for unsupported estimators.
Export.sklearn¶
fno.Export.sklearn(model, *, path, inputs, outputs, name=None,
x_scaler=None, y_scaler=None, backend="auto",
runtime="sklearn", input_format="numpy", verbose=False)
| Parameter | Type | Default | Allowed values or constraint |
|---|---|---|---|
model |
object | required | Fitted supported estimator, object with predict(), or callable Joblib payload |
path |
path | required | Destination ending in .fnom |
inputs |
Mapping[str, Tensor] |
required | Non-empty ordered input contract |
outputs |
Mapping[str, Tensor] |
required | Non-empty ordered output contract |
name |
str \| None |
None |
Non-empty artefact name; destination stem when omitted |
x_scaler |
object or None |
None |
Supported fitted affine input scaler |
y_scaler |
object or None |
None |
Supported fitted affine output scaler |
backend |
str |
"auto" |
auto, compiled, forest or joblib |
runtime |
str |
"sklearn" |
sklearn or sklearnex; applies only to Joblib |
input_format |
str |
"numpy" |
numpy, pandas or polars; compiled backends require numpy |
verbose |
bool |
False |
Display the completed artefact summary |
pandas and polars formats require scalar input ports and the corresponding library in the ModelHost environment. FoamNordic does not install either library as a mandatory dependency.
artifact = fno.Export.sklearn(
model,
path="smagorinsky.fnom",
inputs={"features": fno.Tensor.vector(components=10)},
outputs={"nut": fno.Tensor.scalar()},
x_scaler=scaler_X,
)
The first compiled load caches a target-native library. XGBoost and LightGBM are needed only for export. Run foamnordic compile smagorinsky.fnom to warm a cache shared by nodes with the same target ABI. runtime applies only to Joblib and selects sklearn or sklearnex.
Scalers¶
x_scaler and y_scaler accept fitted StandardScaler, MinMaxScaler, MaxAbsScaler, RobustScaler, or a shape-preserving affine FunctionTransformer. Custom affine scaler types can be registered with bindnordic.scalers.register_scaler_adapter(). FoamNordic stores the resulting gain and bias in FNOM, transforms inputs before inference, and reverses output scaling before field commit. Nonlinear and feature-mixing transforms are not representable by this native scaler contract.
Export.onnx¶
fno.Export.onnx(model, *, path, inputs, outputs, name=None,
x_scaler=None, y_scaler=None, verbose=False)
model may be an object exposing SerializeToString(), raw bytes, or a path accepted by the ONNX payload writer. path, inputs, outputs, name, scalers and verbose follow Export.sklearn. ONNX execution requires the native ONNX connector selected by foamnordic build; exporting an artefact does not execute it.
Export.equinox¶
fno.Export.equinox(model, *, path, inputs, outputs, name=None,
batched=False, x_scaler=None, y_scaler=None,
verbose=False)
| Parameter | Type | Default | Meaning |
|---|---|---|---|
model |
object | required | Reconstructable Equinox PyTree |
batched |
bool |
False |
True when the model already accepts a leading batch dimension; otherwise ModelHost vectorises it |
All remaining parameters follow Export.sklearn. Equinox payloads execute in a resident JAX worker and are classified as code-bearing.
Inspecting an artefact¶
fno.Models.load(path)
Models.load() validates the FNOM container and returns read-only metadata without loading its payload for execution.
import foamnordic as fno
artifact = fno.Models.load("reaction-rate.fnom")
print(artifact.name)
print(artifact.backend)
print(artifact.inputs)
print(artifact.outputs)
print(artifact.trust_policy)
artifact.validate()
FnomArtifact is immutable. validate() parses FNOM without executing its payload. inspect identifies code-bearing Joblib, Equinox and portable C++ payloads, versus data-only ONNX, forests and tables.
Operator.model() or foamnordic compile authorises execution; no extra trust flag is required.
The exchange accepts float32 or float64 model tensors with either OpenFOAM precision. Packing and field commit perform required conversions. Equal-precision fields use direct copies; converted fields cannot be zero-copy.
The equivalent CLI commands are:
foamnordic inspect reaction-rate.fnom
foamnordic inspect reaction-rate.fnom --json
foamnordic validate reaction-rate.fnom
foamnordic diff reference.fnom candidate.fnom
foamnordic diff reference.fnom candidate.fnom --json
diff validates both artefacts, compares their complete execution manifests and streams embedded or external payloads through SHA-256. File names, external payload paths, and container padding do not affect equivalence, and neither model payload is executed.
See the FNOM format specification for binary layout and trust boundaries.
Regular-grid tables¶
table() stores ordered scalar coordinate axes and one dense output array. The last value dimension is the packed width of the declared outputs. BindNordic performs multilinear interpolation natively; no Python process or domain library is present in the solver loop.
artifact = fno.Export.table(
{"progress": c_axis, "variance": g_axis},
manifold,
path="manifold.fnom",
outputs={"state": fno.Tensor.vector(components=8)},
bounds={"progress": "clamp", "variance": "error"},
)
operator = fno.Operator.table(artifact)
fno.Export.table(axes, values, *, path, outputs, name=None,
dtype="float64", bounds="clamp", verbose=False)
| Parameter | Type | Default | Allowed values or constraint |
|---|---|---|---|
axes |
Mapping[str, array-like] |
required | Non-empty ordered scalar axes; every axis finite and strictly increasing |
values |
array-like | required | Dense grid whose leading dimensions match axis lengths and whose final packed width matches outputs |
path |
path | required | Destination ending in .fnom |
outputs |
Mapping[str, Tensor] |
required | Non-empty ordered output contract |
name |
str \| None |
None |
Destination stem when omitted |
dtype |
str |
"float64" |
float32 or float64 |
bounds |
str \| Mapping[str, str] |
"clamp" |
Global or per-axis clamp or error policy |
verbose |
bool |
False |
Display the completed artefact summary |
Axis order is the input contract. Output names and widths are the output contract. The table is domain-neutral: thermochemical manifolds, material properties, control maps, and other regular-grid data use the same artefact and kernel. Each axis must be finite and strictly increasing. Bounds may be clamp or error, globally or per axis.
Models.FnomArtifact¶
| Member | Type or signature | Meaning |
|---|---|---|
path |
Path |
Resolved FNOM path |
name |
str |
Logical artefact name |
backend |
str |
Stored model format |
format |
str |
Stored model format as written in the manifest |
inputs |
tuple[TensorContract, ...] |
Ordered input ports |
outputs |
tuple[TensorContract, ...] |
Ordered output ports |
runtime |
str \| None |
Requested backend runtime |
input_format |
str |
Model input container format |
input_scaler |
str \| None |
Embedded affine input scaler kind |
output_scaler |
str \| None |
Embedded affine output scaler kind |
bundled |
bool |
Whether the payload is embedded in the container |
payload_offset |
int \| None |
Byte offset of the embedded payload |
payload_size |
int \| None |
Embedded payload size in bytes |
executable_payload |
bool |
Whether loading the payload may execute supplied code |
trust_policy |
str |
data-only or explicit-trust-required |
size |
int |
Complete FNOM size in bytes |
validate() |
FnomArtifact |
Re-read and validate the complete container without executing the payload |
Each TensorContract exposes name, components and dtype in packed order.