airfoil_cst_rans_mlp
Ensemble of 5 MLPs (8 -> 96 -> 96 -> 96 -> 3, SiLU, bootstrap) mapping a 6-weight CST airfoil and the angle of attack to lift, drag and quarter-chord moment coefficients of a fully turbulent, incompressible 2-D RANS solution at Re = 4e6. The ensemble spread is returned as an uncertainty.
airfoil_cst_rans_mlp v1.0.0 (revision v1.0.0.post1) Β· part of the PINNeAPPle zoo Β· training data PINNeAPPle-Labs/airfoil-rans-cst-re4e6
Try it without installing anything: PINNeAPPle zoo demo (pick airfoil_cst_rans_mlp: its predictions along each input with their band and where its physics checks warn or fail, and your own inputs evaluated in the browser).
Task: Airfoil aerodynamic coefficients (Cl, Cd, Cm) from shape and angle of attack, 2-D steady RANS
Inputs
| Name | Unit | Description |
|---|---|---|
T0 |
- | CST thickness weight, leading edge |
T1 |
- | CST thickness weight, mid chord |
T2 |
- | CST thickness weight, aft |
M0 |
- | CST camber weight, front |
M1 |
- | CST camber weight, mid chord |
M2 |
- | CST camber weight, aft |
alpha_deg |
deg | angle of attack |
Outputs
| Name | Unit | Description |
|---|---|---|
Cl |
- | lift coefficient (per unit span, chord 1) |
Cd |
- | drag coefficient |
Cm |
- | pitching-moment coefficient about c/4 |
Validity range
T0: [0.1, 0.24]T1: [0.08, 0.22]T2: [0.08, 0.22]M0: [-0.03, 0.08]M1: [-0.02, 0.14]M2: [-0.04, 0.12]alpha_deg: [-2.0, 14.0]reynolds: 4000000.0mach: incompressiblegeometry_family: 2nd-order Bernstein CST, upper = M + T, lower = M - T, trailing-edge thickness 0.25 % chordregime: fully turbulent (k-omega SST), attached to mildly separated; deep stall (Cl swing > 0.1 over the last 500 iterations) was excluded from training
Known limitations
- Drag at high lift reads ~14 % high on the campaign grid (20k cells) compared with finer grids/XFOIL; the surrogate inherits the solver's bias, it does not correct it.
- Not valid in deep stall, at other Reynolds numbers, compressible flow or outside the CST bounds.
- Accuracy is against the same solver and grid that generated the training data (interpolation error); the solver's own error against experiment is the larger term.
Architecture
MLPEnsembleβ{"k": 5, "width": 96, "in_dim": 8, "out_dim": 3, "activation": "SiLU", "targets": ["Cl", "log Cd", "Cm"]}
Physics
- steady incompressible RANS, k-omega SST (OpenFOAM v1912 simpleFoam)
Validation
Reference: Held-out OpenFOAM RANS runs on 15 airfoil shapes never seen in training (60 runs) and 36 NACA 0012/2412/4412/4415 runs excluded from training. The solver is verified: 3-grid study on NACA 2412 at alpha 4 deg (Cd GCI 1.9 %, observed order 2.4; Cl within 0.02 %), XFOIL 6.99 tripped (Cl -2.3 %, Cd +4.5 %), lift slope 0.110/deg vs 0.110/deg thin-airfoil theory, NASA TMR NACA 0012 SST (Cd 0.00812 vs 0.0081).
| Metric | Value |
|---|---|
| test/Cl_mae | 0.0028476635807695894 |
| test/Cl_max_abs | 0.019326576151895702 |
| test/Cd_mae | 9.115975415693806e-05 |
| test/Cd_max_abs | 0.0011104396736285153 |
| test/Cd_mape_pct | 0.5447462642571239 |
| test/Cd_p90_pct | 1.0353616187191836 |
| test/Cm_mae | 0.0004539437796155409 |
| test/Cm_max_abs | 0.0025451080196258954 |
| test/n | 60.0 |
| naca_reference/Cl_mae | 0.003231396365459536 |
| naca_reference/Cl_max_abs | 0.028683417593309724 |
| naca_reference/Cd_mae | 0.00013511379859050402 |
| naca_reference/Cd_max_abs | 0.0013729081470662922 |
| naca_reference/Cd_mape_pct | 0.615631882294239 |
| naca_reference/Cd_p90_pct | 1.1373013614073955 |
| naca_reference/Cm_mae | 0.00022242696868302747 |
| naca_reference/Cm_max_abs | 0.0019696524520329602 |
| naca_reference/n | 36.0 |
| xfoil_naca2412/Cl_mae | 0.010092481383557984 |
| xfoil_naca2412/Cl_max_abs | 0.02017109433227715 |
| xfoil_naca2412/Cd_mae | 0.00028128564747221293 |
| xfoil_naca2412/Cd_max_abs | 0.0009061347505152015 |
| xfoil_naca2412/Cd_mape_pct | 2.812720929821659 |
| xfoil_naca2412/Cd_p90_pct | 6.872440265354455 |
| xfoil_naca2412/Cm_mae | 0.0009800236757100693 |
| xfoil_naca2412/Cm_max_abs | 0.0012370981942770864 |
| xfoil_naca2412/n | 9.0 |
Trust
Decision: APPROVED Β· score 1.00 Β· coverage 100%
Training data
- dataset: airfoil_rans_cst_re4e6
- split: by shape (seed 3, 15 % of LHS shapes held out)
- source: examples/handoff_cases/airfoil_ld (campaign), apps/aero_optimizer/model/surrogate.pt
License: apache-2.0
Citation
PINNeAPPle contributors (2026). Airfoil RANS campaign (OpenFOAM v1912 simpleFoam, k-omega SST, Re 4e6, 436 runs) and MLP-ensemble surrogate. PINNeAPPle model zoo, https://github.com/PINNeAPPle-Labs/PINNeAPPle
Physics validation
warn: data finite (missing values documented) (19/20 applicable checks pass; level standard; generated by pp.validate with PINNeAPPle 0.7.0, schema validation-report/v1).
| Factor | Credibility | Meaning |
|---|---|---|
| code_verification | 0 | no evidence |
| solution_verification | 3 | passes quantitative checks |
| validation | 4 | passes against an independent reference or a guaranteed bound |
| input_pedigree | 2 | passes with warnings or qualitative evidence only |
| uncertainty | 2 | passes with warnings or qualitative evidence only |
| robustness | 0 | no evidence |
| applicability | 0 | no evidence |
| Check | Status | Result |
|---|---|---|
method.status |
not-applicable | no catalog method id given (validate(..., method='S2')) |
reference.card_metrics |
pass | card metrics reproduced on the stored reference (max relative difference) |
reference.acceptance.test/Cl_mae |
pass | held-out test/Cl_mae within the zoo acceptance limit |
reference.acceptance.test/Cd_mape_pct |
pass | held-out test/Cd_mape_pct within the zoo acceptance limit |
reference.acceptance.test/Cm_mae |
pass | held-out test/Cm_mae within the zoo acceptance limit |
reference.acceptance.naca_reference/Cl_mae |
pass | held-out naca_reference/Cl_mae within the zoo acceptance limit |
reference.acceptance.naca_reference/Cd_mape_pct |
pass | held-out naca_reference/Cd_mape_pct within the zoo acceptance limit |
physics.model_checks.1 |
pass | lift slope vs thin-airfoil 2 pi/rad (alpha -2..6, held-out shapes) |
physics.model_checks.2 |
pass | Cl increases with alpha below stall (alpha -2..10, held-out shapes) |
physics.model_checks.3 |
pass | symmetric airfoil: /Cl(0)/ and /Cl(2)+Cl(-2)/ (NACA 0012) |
physics.model_checks.4 |
pass | Cd > 0 and finite outputs on 2000 random in-range inputs |
applicability.range |
not-applicable | no query inputs given |
uncertainty.spread |
pass | the model returns a predictive spread or bound |
metamorphic.symmetry.camber-mirror-lift |
pass | worst violation 0.819 over 64 samples |
metamorphic.symmetry.camber-mirror-moment |
pass | worst violation 1.03 over 64 samples |
metamorphic.symmetry.camber-mirror-drag |
pass | worst violation 0.0219 over 64 samples |
metamorphic.monotonicity.lift-grows-with-alpha |
pass | worst violation 0 over 64 samples |
data.finite |
warn | stored audit card of airfoil_rans_cst_re4e6: missing values (NaN) in train/Cm (340, documented) |
data.physics.physics |
not-applicable | stored audit card of airfoil_rans_cst_re4e6: no PDE stated for this dataset |
data.physics.constraint.cd-0 |
pass | stored audit card of airfoil_rans_cst_re4e6: Cd > 0: 0 of 448 rows violate it |
data.diversity.duplicates |
pass | stored audit card of airfoil_rans_cst_re4e6: train: 0 exact, 0 near copies of 340; test: 0 exact, 0 near copies of 60 |
data.diversity.effective |
pass | stored audit card of airfoil_rans_cst_re4e6: effective sample count 6.47 of 340 (no generator stated: only a collapse to one pattern is flagged) |
data.leakage |
pass | stored audit card of airfoil_rans_cst_re4e6: 0 of 60 test samples are (near) copies of train samples (closest: 1.03 x the median train spacing) |
Model SHA-256 fb3de764d06bc4194dd6e92120dc5f76a3db15c4a71501a17c8c1599345e7333.
How to use
pip install "pinneapple @ git+https://github.com/PINNeAPPle-Labs/PINNeAPPle"
import pinneapple as pp
model = pp.zoo.load("airfoil_cst_rans_mlp") # weights checked against their SHA-256
inputs = {"T0": 0.235519, "T1": 0.215361, "T2": 0.195097, "M0": 0.058294, "M1": 0.016703, "M2": 0.09483, "alpha_deg": 0.810289}
out = model.predict(inputs) # warns for inputs outside the validity range
print({k: round(float(v[0]), 6) for k, v in out.items()})
# {'Cl': 0.316984, 'Cd': 0.010137, 'Cm': -0.042694, 'Cl_std': 0.002746, 'Cd_std': 2.3e-05, 'Cm_std': 0.000136, 'LD': 31.270027, 'LD_std': 0.270385}
print(pp.zoo.query_checks(model, inputs)[0]["verdict"]["status"]) # per-query trust checks
# pass
print(pp.zoo.validate(model).decisao) # card metrics reproduced + physics checks
# APPROVED
The inputs are the first held-out test case of the training dataset; its reference value is Cl = 0.317408, Cd = 0.0101194, Cm = -0.0426839. pp.zoo.evaluate("airfoil_cst_rans_mlp") recomputes every metric of the card on the stored reference.
Hosted inference
No Hugging Face inference provider can run this model, so the Hub widget is off (inference: false). It is a small PyTorch network, but its prediction is more than a forward pass: the inputs are encoded and normalised, the outputs denormalised (and, for ensembles, averaged with their spread), and every query is checked against the validity range and the model's physics checks. The pinneapple library does all of that (below); the ONNX graph carries the pre- and post-processing but not the checks; the zoo demo Space shows the model along a sweep of each input and runs it, with its checks, in your browser.
ONNX
model.onnx (opset 17) maps x, shape (n, 7) float32 with the columns T0, T1, T2, M0, M1, M2, alpha_deg, to the outputs mean: ['Cl', 'Cd', 'Cm']; std: ['Cl_std', 'Cd_std', 'Cm_std']; ld: ['LD', 'LD_std']. Pre- and post-processing are in the graph (largest difference from PyTorch on the reference inputs: 5.3e-07); the validity-range and physics checks are not, so check the range yourself.
import numpy as np, onnxruntime as ort
from huggingface_hub import hf_hub_download
path = hf_hub_download("PINNeAPPle-Labs/airfoil-cst-rans-mlp", "model.onnx", revision="v1.0.0.post1")
session = ort.InferenceSession(path)
x = np.array([[0.235519, 0.215361, 0.195097, 0.058294, 0.016703, 0.09483, 0.810289]], np.float32)
print(dict(zip([o.name for o in session.get_outputs()], session.run(None, {"x": x}))))
Files
| File | Content | SHA-256 |
|---|---|---|
weights.pt |
PyTorch state_dict (torch.load(weights_only=True)), what pp.zoo.load reads |
ff223aab60cbade5eb711e565a90e86e69fe7a65e59e7e7d08be256828a898be |
config.json |
architecture and normalisation | 6d7d66c9d8d3e90f7b3480210b757d24d23bc5394c7f9d2d7bab08792608a093 |
model_card.json |
the model card: inputs, outputs, validity range, metrics, trust report | c3257991339ecf1604d64cc621ae21a0e26e0cd65e74f23e7f6fe166d0300a34 |
model.safetensors |
the same tensors as weights.pt in safetensors format (pinneapple_hub.zoo.export.load_safetensors loads them) |
derived |
model.onnx |
ONNX graph, physical inputs to physical outputs (below) | derived |
example.json |
the "How to use" case: inputs, outputs, reference, verdicts | derived |
The SHA-256 are those of the package's manifest: pp.zoo.load refuses any other file.
Cite
If you use this model, please cite PINNeAPPle (software, Zenodo DOI 10.5281/zenodo.23343062; see CITATION.cff):
@software{pinneapple,
author = {Barros, Yan and Schiassi, Enrico},
title = {PINNeAPPle},
doi = {10.5281/zenodo.23343062},
url = {https://github.com/PINNeAPPle-Labs/PINNeAPPle}
}
- Downloads last month
- 155