Downloads · 30 days
0
LucasThil/turbofan-surrogate
turbofan-surrogate is a tabular regression model from LucasThil. Use it for the tabular regression task on the model card, and read the license before you ship it in a product. It is set up for flax. The card lists the license as mit.
Neural surrogate for the ODSMR turbofan engine simulator. A small Flax MLP (20k to 1M parameters) approximates ODSMR's thermodynamic map and runs on the order of a million times faster per device than the original CPU…
Downloads · 30 days
0
Access
Public
Updated May 10, 2026
Repo size
6.7 MB
Likes
0
Public
Click a slice to open those files.
.pkl6.7 MB · 99%
From the Hugging Face model README
Neural surrogate for the ODSMR turbofan engine simulator. A small Flax MLP (20k to 1M parameters) approximates ODSMR's thermodynamic map and runs on the order of a million times faster per device than the original CPU simulator, with overall R² above 0.998 on every sensor.
The surrogate is intended as a fast inference backend for reinforcement learning, world model evaluation, and any pipeline that needs to call ODSMR many millions of times.
Trained and evaluated on a 1.2 M sample dataset drawn from the TurboSens operating distribution (4 wear regimes × 16 contexts, ODSMR-sampled ground truth, 200 k held-out for evaluation).
| Headline | Number |
|---|---|
| Variants shipped | 4 (tiny, small, default, large) |
| Smallest variant | 19.7 k params, 78 KB on disk |
| Largest variant | 1.06 M params, 4.1 MB on disk |
| Best overall R² | ≥ 0.9999 on every sensor (large) |
| Best overall nMAE (×σ) | 0.0039 mean, 0.0057 worst-sensor (large) |
| Recommended variant (default) | R² ≥ 0.9998 on every sensor, mean nMAE 0.0055 |
| Throughput at batch 16 384 (V100) | 6.1 M samples/sec (small), 3.0 M (large) |
| Vs ODSMR per CPU thread | ~1.6 M× faster per device |
| Vs per-context mean baseline | 14× to 64× lower nMAE per sensor |
| Worst held-out sample relative error | ~2.5 % of natural sensor scale |
| Convergence rate of training data | 99.94 % (ODSMR diverges < 0.1 %) |
The trained surrogate beats the per-context mean baseline (which already knows the operating point) by 14× to 64×, evidence that it learned state-driven physics rather than per-context marginals. Hard-case analysis shows the worst residuals concentrate on the post-action wear regime (3.4× over-represented in the worst 1 %), which is exactly the regime where the underlying problem is most ambiguous and where action history matters most — a feature, not a bug, for downstream world-model evaluation.
Full per-sensor / per-slice breakdown in
reports/default_evaluation.md;
side-by-side variant comparison in
reports/comparison.md.
Takes a 17 dimensional input
and returns 7 sensor readings
HPC_Tout (K), HP_Nmech (rpm), HPC_Tin (K), LPT_Tin (K),
Fuel_flow (kg/s), HPC_Pout_st (Pa), LP_Nmech (rpm)pip install -e .
# for GPU inference (Linux + CUDA 12 + Ampere/Hopper/Volta):
pip install -e ".[gpu]"
import numpy as np
from turbofan_surrogate import (
load_surrogate, build_inputs, CONTEXT_PHASES, SENSOR_NAMES,
)
# Load the recommended model
surrogate = load_surrogate("weights/default.pkl")
# Build a batch of inputs
n = 1024
states = np.random.uniform(-0.05, 0.0, (n, 10)).astype("float32")
ci = np.random.randint(0, 16, n) # 16 named contexts
dtamb = np.full(n, 10.0, dtype="float32")
alt = np.full(n, 35000.0, dtype="float32")
mach = np.full(n, 0.78, dtype="float32")
cmd = np.full(n, 25000.0, dtype="float32")
X = build_inputs(states, ci, dtamb, alt, mach, cmd)
# Predict (7 sensors per input row, in natural units)
sensors = surrogate.predict(X)
print(dict(zip(SENSOR_NAMES, sensors[0])))
A complete worked example with timing is in examples/inference_demo.py.
Four architectures are shipped under weights/. All four were trained on
the same 999k row dataset for 100 epochs.
| Variant | Hidden × Depth | Params | Disk | nMAE (mean) | Throughput @ batch 16k (V100) |
|---|---|---|---|---|---|
tiny | 128 × 2 | 19.7k | 78 KB | 0.0137 | 6.1M samples/sec |
small | 256 × 3 | 138k | 540 KB | 0.0109 | 6.1M samples/sec |
default | 384 × 4 | 453k | 1.8 MB | 0.0055 | 3.8M samples/sec |
large | 512 × 5 | 1.06M | 4.1 MB | 0.0039 | 3.0M samples/sec |
Recommendations:
default. R² ≥ 0.9998 on every sensor, mean
nMAE 0.55 % of natural sensor std, 3.8M samples/sec on V100.small. Identical throughput to
tiny but 17 % lower nMAE, only 540 KB on disk.large. About 30 % lower nMAE than
default at 21 % throughput cost.tiny is dominated by small and is included for completeness only.A full per sensor breakdown lives in reports/comparison.md and a full
held out evaluation report (per phase, per context, per wear mode, per
quantile bin, hardest cases, sensitivity matrix, throughput) for the
default model lives in reports/default_evaluation.md.
On the held out 200k row eval set, the default model achieves:
| Sensor | nMAE (×σ) | R² | Max abs error |
|---|---|---|---|
| HPC_Tout | 0.0053 | 0.9999 | 9.6 K |
| HP_Nmech | 0.0102 | 0.9998 | 263 rpm |
| HPC_Tin | 0.0044 | 1.0000 | 8.2 K |
| LPT_Tin | 0.0056 | 0.9999 | 22 K |
| Fuel_flow | 0.0028 | 1.0000 | 0.024 kg/s |
| HPC_Pout_st | 0.0028 | 1.0000 | 72 kPa |
| LP_Nmech | 0.0073 | 0.9999 | 129 rpm |
Compared against the per context mean baseline (a strong baseline that already knows the operating point, just not the state), the trained surrogate is 14× to 64× lower nMAE per sensor — i.e. the model learned state-driven physics, not just the per context mean.
The surrogate was trained on the TurboSens operating distribution, which is wider than ODSMR's documented "tested core". Inputs should fall within:
STATE_BOUNDS (Eff in [-0.05, 0],
Wc in [-0.05, 0.03] or [-0.05, 0.05] depending on module)Predictions outside this envelope are not characterised; outputs may
extrapolate poorly. Inside the envelope, see MODEL_CARD.md for slice
level error guarantees.
The training set is 999k samples drawn from a four mode wear mixture
(pristine / mid wear / heavy wear / post action restoration) crossed
with uniform context sampling and per slot ALT/MACH/COMMAND jitter,
then run through ODSMR. The dataset is not redistributed here; see the
companion rl_simulator_safran repository for the generation pipeline.
Training: 100 epochs, AdamW (lr 1e-3 → 1e-5 cosine, weight decay 1e-4), per output normalised MSE in float32, batch 8192. Wall time on a single V100 is 15 to 75 seconds depending on variant.
See docs/MODEL_CARD.md for intended use, scope,
known failure modes, and ethical considerations.
MIT. See LICENSE.
If you use this surrogate, please also cite the underlying ODSMR (OpenDeckSMR) simulator it approximates:
Psaropoulos, M., Gkoutzamanis, V., Kalfas, A. I., Giannakakis, P., Razakarivony, S., Thepaut, S., & Vu, D. Q. (2025). OpenDeckSMR (Version 0.1) [Computer software]. https://github.com/OpenDeckLab/OpenDeckSMR
BibTeX:
@software{psaropoulos2025opendecksmr,
author = {Psaropoulos, M. and Gkoutzamanis, V. and Kalfas, A. I. and
Giannakakis, P. and Razakarivony, S. and Thepaut, S. and Vu, D. Q.},
title = {{OpenDeckSMR}},
year = {2025},
version = {0.1},
url = {https://github.com/OpenDeckLab/OpenDeckSMR}
}