C(NN)FD -- a deep learning framework for turbomachinery CFD analysis
Paper • 2306.05889 • Published
A physics-informed deep learning surrogate model for axial fan aerodynamic performance prediction, built with NVIDIA PhysicsNeMo.
R² = 0.9964 | MAPE = 1.40% (32% better than pure data-driven approach)
| Aspect | Standard PyTorch | PhysicsNeMo (this model) |
|---|---|---|
| Framework | Pure PyTorch nn.Module |
PhysicsNeMo FullyConnected (extends nn.Module) |
| Loss Function | MSE on data only | MSE + physics-informed constraints |
| Architecture | Custom ResidualMLP | PhysicsNeMo FullyConnected with skip_connections=True |
| Activation | GELU | SiLU (Swish) |
| Parameters | 634K | 1.33M |
| Avg R² | 0.9952 | 0.9964 (+0.12%) |
| Avg MAPE | 2.08% | 1.40% (-32%) |
| Extrapolation | Poor (data-only) | Better (physics constraints regularize) |
| Serialization | torch.save() |
.mdlus native + torch.save() |
| Checkpoint | Manual | physicsnemo.utils.checkpoint |
The standard model learns purely from data. The PhysicsNeMo version adds 4 physics constraint terms to the loss function that enforce thermodynamic and aerodynamic consistency:
These constraints act as regularizers — even without labeled data, the model learns physically meaningful relationships. This dramatically improves:
| Output Metric | R² | MAPE |
|---|---|---|
| Total Pressure Rise (Pa) | 0.9976 | 3.39% |
| Isentropic Efficiency | 0.9804 | 0.69% |
| Power Consumption (W) | 0.9987 | 2.70% |
| Flow Rate (m³/s) | 0.9998 | 1.08% |
| Specific Speed | 0.9975 | 1.48% |
| Degree of Reaction | 0.9988 | 0.46% |
| Diffusion Factor | 0.9991 | 0.88% |
| Noise Estimate (dBA) | 0.9994 | 0.51% |
| Average | 0.9964 | 1.40% |
import torch
import numpy as np
import json
from physicsnemo.models.mlp.fully_connected import FullyConnected
# Load model
model = FullyConnected(
in_features=14, out_features=8,
num_layers=6, layer_size=512,
activation_fn='silu', skip_connections=True,
)
# Option 1: Load from PhysicsNeMo native format
model = FullyConnected.from_checkpoint("fan_surrogate.mdlus")
# Option 2: Load from PyTorch state dict
state = torch.load("model.pt", map_location="cpu")
model.load_state_dict(state)
model.eval()
# Load scalers
with open("scalers.json") as f:
scalers = json.load(f)
sx_mean = np.array(scalers['scaler_X_mean'], dtype=np.float32)
sx_scale = np.array(scalers['scaler_X_scale'], dtype=np.float32)
sy_mean = np.array(scalers['scaler_y_mean'], dtype=np.float32)
sy_scale = np.array(scalers['scaler_y_scale'], dtype=np.float32)
# Predict
INPUT_COLS = ["blade_inlet_angle_deg", "blade_turning_angle_deg", "chord_length_mm",
"blade_thickness_ratio", "stagger_angle_deg", "hub_tip_ratio",
"tip_clearance_ratio", "num_blades", "aspect_ratio", "solidity",
"sweep_angle_deg", "flow_coefficient", "rotational_speed_rpm", "tip_radius_mm"]
LOG_IDX = [0, 2, 3]
design = [55, 15, 100, 0.06, 45, 0.5, 0.015, 12, 2.5, 1.0, 0, 0.5, 3000, 300]
x = np.array([design], dtype=np.float32)
x_scaled = (x - sx_mean) / sx_scale
with torch.no_grad():
y_scaled = model(torch.from_numpy(x_scaled)).numpy()
y_proc = y_scaled * sy_scale + sy_mean
for i in LOG_IDX:
y_proc[0, i] = np.expm1(y_proc[0, i])
print(f"Pressure Rise: {y_proc[0,0]:.1f} Pa")
print(f"Efficiency: {y_proc[0,1]:.3f}")
print(f"Power: {y_proc[0,2]:.1f} W")
print(f"Flow Rate: {y_proc[0,3]:.3f} m³/s")
pip install nvidia-physicsnemo torch numpy
FullyConnected(
(layers): ModuleList(
(0): FCLayer(Linear(14→512) + SiLU)
(1-5): 5 × FCLayer(Linear(512→512) + SiLU + skip_connection)
)
(final_layer): FCLayer(Linear(512→8))
)
Total parameters: 1,325,064
| Scenario | Recommendation |
|---|---|
| Abundant training data (>5000 samples) | Either works; PhysicsNeMo slightly better |
| Sparse data (<500 samples) | PhysicsNeMo (physics constraints compensate for missing data) |
| Extrapolation needed | PhysicsNeMo (constraints prevent unphysical predictions) |
| Pure interpolation | Standard PyTorch (simpler, faster training) |
| Need ONNX export / deployment | PhysicsNeMo (built-in export support) |
| Multi-physics coupling | PhysicsNeMo (add PDE residuals, boundary conditions) |
| Quick prototyping | Standard PyTorch (fewer dependencies) |
Trained on harshaperla/fan-design-dataset (8000 train / 2000 test).
This model repository was generated by ML Intern, an agent for machine learning research and development on the Hugging Face Hub.