dave1368's picture
Publish trained Similitude Regressor checkpoint (POC, private)
8e89df3 verified
Raw
History Blame Contribute Delete
2.59 kB
"""
Standalone architecture definition for the Cluster 1 Similitude Regressor.
This is a self-contained copy of the model class used by the
Scientific AI Cluster Orchestration Framework's Cluster 1 pipeline
(https://huggingface.co/spaces/dave1368/cluster-01-dimensional-analysis) --
included here so the checkpoint can be loaded independently of that app.
Usage:
from huggingface_hub import hf_hub_download
from modeling import SimilitudeRegressorPINN
import torch
ckpt_path = hf_hub_download("dave1368/cluster-01-similitude-regressor", "similitude_regressor.pt")
checkpoint = torch.load(ckpt_path, map_location="cpu")
model = SimilitudeRegressorPINN()
model.load_state_dict(checkpoint["model_state_dict"])
model.eval()
# Inputs are RAW [Reynolds, Froude, Mach] -- normalization happens inside forward().
pi_groups = torch.tensor([[10000.0, 0.5, 0.2]]) # Re=10,000, Fr=0.5, Mach=0.2
cd, cp = model(pi_groups)[0].tolist()
print(f"Cd={cd:.4f} Cp={cp:.4f}")
"""
import torch
import torch.nn as nn
# Re spans orders of magnitude (10 to 1e6); log-scaling it keeps the calling
# convention "pass raw [Re, Fr, Mach]" simple for callers.
RE_LOG_MIN, RE_LOG_MAX = 1.0, 6.0 # log10(10) .. log10(1e6)
class SimilitudeRegressorPINN(nn.Module):
"""
Neural regressor mapping dimensionless input groups (Re, Fr, Mach)
to scaled performance coefficients (Cd, Cp).
Trained against Morrison (2013)'s sphere drag correlation Cd(Re) and the
Prandtl-Glauert compressibility-corrected stagnation Cp(Mach). See this
repo's README.md for the full training story, including the drag-crisis
oversampling fix.
"""
def __init__(self, input_dim=3, hidden_neurons=64):
super().__init__()
layers = [nn.Linear(input_dim, hidden_neurons), nn.Tanh()]
for _ in range(3):
layers.extend([nn.Linear(hidden_neurons, hidden_neurons), nn.Tanh()])
# Output: [Drag Coefficient Cd, Pressure Coefficient Cp]
layers.append(nn.Linear(hidden_neurons, 2))
self.net = nn.Sequential(*layers)
def _normalize(self, pi_groups: torch.Tensor) -> torch.Tensor:
log_re = torch.log10(torch.clamp(pi_groups[:, 0], min=1.0))
re_norm = 2.0 * (log_re - RE_LOG_MIN) / (RE_LOG_MAX - RE_LOG_MIN) - 1.0
fr_norm = 2.0 * pi_groups[:, 1] - 1.0
mach_norm = 2.0 * pi_groups[:, 2] - 1.0
return torch.stack([re_norm, fr_norm, mach_norm], dim=1)
def forward(self, pi_groups: torch.Tensor) -> torch.Tensor:
return self.net(self._normalize(pi_groups))