CoolFace
Modelpublic

harshaperla/fan-design-surrogate-physicsnemo

sourceHugging Faceupdated 4mo agoView on Hugging Face
0likes2downloads
Model Card

Fan Design Surrogate Model — PhysicsNeMo Version

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)

How This Differs from the Standard PyTorch Version

Aspect[Standard PyTorch](https://huggingface.co/harshaperla/fan-design-surrogate)**PhysicsNeMo (this model)**
FrameworkPure PyTorch nn.ModulePhysicsNeMo FullyConnected (extends nn.Module)
Loss FunctionMSE on data onlyMSE + physics-informed constraints
ArchitectureCustom ResidualMLPPhysicsNeMo FullyConnected with skip_connections=True
ActivationGELUSiLU (Swish)
Parameters634K1.33M
Avg R²0.99520.9964 (+0.12%)
Avg MAPE2.08%1.40% (-32%)
ExtrapolationPoor (data-only)Better (physics constraints regularize)
Serializationtorch.save().mdlus native + torch.save()
CheckpointManualphysicsnemo.utils.checkpoint

Key Advantage: Physics-Informed Loss

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:

  1. 1.Power-Pressure Consistency: P = ΔPt × Q / η (energy conservation)
  2. 2.Flow Rate Consistency: Q = Vx × A_annulus (continuity equation)
  3. 3.Efficiency Bounds: 0 < η < 1 (second law of thermodynamics)
  4. 4.Euler Work Equation: ΔPt ≈ ρ × η × U × ΔVθ (turbomachinery fundamental)

These constraints act as regularizers — even without labeled data, the model learns physically meaningful relationships. This dramatically improves:

  • —Extrapolation to designs outside the training distribution
  • —Consistency between predicted outputs (power, pressure, flow are now thermodynamically coherent)
  • —Sample efficiency (same accuracy with less training data)

Performance (Test Set: 2000 samples)

Output MetricR²MAPE
Total Pressure Rise (Pa)0.99763.39%
Isentropic Efficiency0.98040.69%
Power Consumption (W)0.99872.70%
Flow Rate (m³/s)0.99981.08%
Specific Speed0.99751.48%
Degree of Reaction0.99880.46%
Diffusion Factor0.99910.88%
Noise Estimate (dBA)0.99940.51%
Average0.99641.40%

Usage

python
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")

Installation

bash
pip install nvidia-physicsnemo torch numpy

Architecture Details

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

When to Use PhysicsNeMo vs Standard PyTorch

ScenarioRecommendation
Abundant training data (>5000 samples)Either works; PhysicsNeMo slightly better
Sparse data (<500 samples)PhysicsNeMo (physics constraints compensate for missing data)
Extrapolation neededPhysicsNeMo (constraints prevent unphysical predictions)
Pure interpolationStandard PyTorch (simpler, faster training)
Need ONNX export / deploymentPhysicsNeMo (built-in export support)
Multi-physics couplingPhysicsNeMo (add PDE residuals, boundary conditions)
Quick prototypingStandard PyTorch (fewer dependencies)

Dataset

Trained on harshaperla/fan-design-dataset (8000 train / 2000 test).

References

<!-- ml-intern-provenance -->

Generated by ML Intern

This model repository was generated by ML Intern, an agent for machine learning research and development on the Hugging Face Hub.

  • —Try ML Intern: https://smolagents-ml-intern.hf.space
  • —Source code: https://github.com/huggingface/ml-intern