heatsink_design_ai already uses for its own on-demand verification.Milliseconds vs. seconds, to scale
Every surrogate prediction, checked against a real 3D solve
Prediction, real data, and the error between them — together
The surrogate answers in --, on average, across this sweep. The real 3D FEA cross-check — a genuine finite-element solve, mesh and all — takes --. That's a real --× difference in wall-clock time. It would be a hollow result if the fast answer were also a wrong one: across these seven designs, the surrogate's prediction differs from the real 3D solve by --% on average, worst case --% — every design inside a 10% band on a real, independent physics solve it never trained on directly.
The speed isn't the hard part. The speed that still agrees with the physics is.
| Design | Fins × height × thickness | Power | Surrogate °C | FEA °C | Diff % | Surrogate time | FEA time | Speedup |
|---|
How this actually works
1 The surrogate: a small MLP, trained on real physics-labeled data
The surrogate is a plain PyTorch MLP — five inputs (fin count, fin height, fin thickness, power, convective coefficient), three hidden layers of 48 units with tanh activations, one output. Nothing exotic, nothing hidden. What makes it trustworthy isn't the architecture, it's the training data: 6,000 samples, each one a real design run through heatsink_design_ai.physics.junction_temperature_c() — the same closed-form analytical model described below, not a human guess or a fabricated label. Training is deterministic (fixed seed), so the same weights come back every time; only the wall-clock timing measured against them varies run to run.
That's the whole trick: a surrogate is only as honest as what it was trained to reproduce. Here, that's a real, textbook thermal model — not a black box learning an unknown target.
2 The cross-check: a genuinely independent 3D solve
The surrogate is never trained against the 3D FEA solve — it only ever sees the faster analytical model. So the 3D cross-check on this page is a real, independent test, not a comparison rigged to agree. heatsink_design_ai/fea_fenics/solve_fin.py meshes one fin unit-cell with gmsh and solves the actual steady-state conduction+convection PDE with dolfinx (FEniCS) — a full 3D finite-element solve of the heat equation over that mesh, not a 1D fin-efficiency shortcut. It runs in a separate `fenicsx` conda environment (dolfinx's own dependency stack doesn't install cleanly alongside this app's), invoked via subprocess — the same call pattern heatsink_design_ai's own production verification endpoint already uses. The wall-clock time reported here is the real, honest one: process spin-up and mesh generation included, not just the solver's internal loop.
3 The agreement metric: why speed alone isn't the story
A fast wrong answer is worse than a slow right one — this org's whole verification-first position. So every design on this page reports a surrogate-vs-FEA difference, computed on temperature rise above ambient (not raw °C, since a fixed 25°C ambient would otherwise understate real disagreement on smaller rises). The 10% threshold used to call a design "agreeing" was set from heatsink_design_ai's own documented accuracy regime before this sweep ran — not tuned afterward to make seven designs look better than they are. That's the difference between a speed demo and a verified one.
heatsink_design_ai.physics.junction_temperature_c() uses as its own cross-check — is pinneapple_physics.closed_form.fin_array_conduction, a real, shared, tested module inside PINNeAPPle (this org's physics-AI platform), imported directly by heatsink_design_ai/physics.py rather than reimplemented. The 3D cross-check on this page is a real dolfinx/FEniCS finite-element solve — genuinely independent physics, not derived from that same closed-form module — run through heatsink_design_ai's own fea_fenics/solve_fin.py, the exact solver that product already ships for its own on-demand verification. Every number on this page comes from that same real chain, live, for every sweep.
The real code, not a black box
heatsink_design_ai/model.py and PINNeAPPle's pinneapple_physics.closed_form.fin_array_conduction.class Surrogate(nn.Module): def __init__(self, hidden: int = 48): super().__init__() # three hidden layers, tanh activations -- a small MLP, nothing hidden self.net = nn.Sequential( nn.Linear(5, hidden), nn.Tanh(), nn.Linear(hidden, hidden), nn.Tanh(), nn.Linear(hidden, hidden), nn.Tanh(), nn.Linear(hidden, 1), ) def forward(self, x_raw): # normalize raw physical units in, de-normalize temperature out -- # the entire "model" is this one real forward pass x = x_raw / _SCALES return self.net(x).squeeze(-1) * _T_SCALE
def fin_array_base_temperature_c(params, t_ambient_c, power_w): # the real, closed-form ground truth the surrogate trained on return t_ambient_c + power_w * params["r_base"] + params["theta_fin_base_c"] def fin_array_profile_params(k_material_w_mk, h_conv_w_m2k, n_fins, fin_thickness_m, fin_length_m, transverse_extent_m, spacing_extent_m, base_thickness_m, power_w): lc = fin_length_m + fin_thickness_m / 2.0 m = math.sqrt(2.0 * h_conv_w_m2k / (k_material_w_mk * fin_thickness_m)) eta_fin = math.tanh(m * lc) / (m * lc) # real fin efficiency # ... effective area, R_conv, R_base from the real geometry ...