PINN: risolve problemi minori — sigma in config, scale precompilate, closure fuori loop

- config.py: aggiunge GAUSS_SIGMA = 0.02 nella sezione parametri fisici
- model.py: T_char, grad_char, pde_scale diventano costanti di modulo (_T_char,
  _grad_char, _pde_scale) calcolate una sola volta all'import
- engine.py: closure L-BFGS definita una volta sola fuori dal loop

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-14 14:23:33 +02:00
parent bca829bd7e
commit 9e77deffd5
3 changed files with 26 additions and 19 deletions
+3
View File
@@ -20,6 +20,9 @@ T_END = 10.0 # fine simulazione [s]
NX = 250 # nodi spaziali
NT = 15000 # passi temporali (verifica CFL automatica)
# Sorgente gaussiana (approssimazione continua del delta di Dirac)
GAUSS_SIGMA = 0.02 # larghezza del picco gaussiano [m]
# Architettura PINN
HIDDEN_SIZE = 128 # neuroni per layer nascosto
N_HIDDEN_LAYERS = 4 # numero di layer nascosti
+1 -1
View File
@@ -117,7 +117,6 @@ def train_model(data, epochs=None, patience=None):
_last = {}
for step in range(config.LBFGS_STEPS):
def closure():
lbfgs.zero_grad()
loss, L_pde, L_ic, L_bc = heat_pinn_loss(
@@ -130,6 +129,7 @@ def train_model(data, epochs=None, patience=None):
_last['bc'] = L_bc.item()
return loss
for step in range(config.LBFGS_STEPS):
lbfgs.step(closure)
if _last['loss'] < best_loss:
best_loss = _last['loss']
+11 -7
View File
@@ -22,14 +22,19 @@ class HeatPINN(nn.Module):
return config.T_AMB + (config.Q_VAL * config.L / config.K) * self.net(xt_norm)
# Precomputed loss scales (depend only on config constants)
_T_char = config.Q_VAL * config.L / config.K # ~150 °C — temperature scale
_grad_char = (config.Q_VAL / config.K) ** 2 # ~22500 — gradient scale²
_pde_scale = (_T_char / config.T_END) ** 2 + 1e-8
def heat_pinn_loss(model, x_f, t_f, x_ic, t_bc,
w_pde=None, w_ic=None, w_bc=None):
if w_pde is None: w_pde = config.W_PDE
if w_ic is None: w_ic = config.W_IC
if w_bc is None: w_bc = config.W_BC
# Characteristic scales for normalization
T_char = config.Q_VAL * config.L / config.K # ~50 °C — temperature scale
grad_char = (config.Q_VAL / config.K) ** 2 # ~2500 — gradient scale²
T_char = _T_char
grad_char = _grad_char
# PDE residual: dT/dt - alpha * d2T/dx2 - source(x,t) = 0 (normalized by T_char/t_char)
x_f = x_f.detach().requires_grad_(True)
@@ -37,19 +42,18 @@ def heat_pinn_loss(model, x_f, t_f, x_ic, t_bc,
T_f = model(torch.stack([x_f, t_f], dim=1))
dT_dt, dT_dx = torch.autograd.grad(T_f.sum(), [t_f, x_f], create_graph=True)
d2T_dx2 = torch.autograd.grad(dT_dx.sum(), x_f, create_graph=True)[0]
sigma = 0.02
Q_t_f = torch.where(t_f >= config.T_STEP,
torch.tensor(config.Q_VAL, device=t_f.device, dtype=t_f.dtype),
torch.tensor(0.0, device=t_f.device, dtype=t_f.dtype))
sigma = config.GAUSS_SIGMA
gauss = torch.exp(-0.5 * ((x_f - config.X_SRC) / sigma) ** 2) / (sigma * (2 * torch.pi) ** 0.5)
source_term = (config.ALPHA / config.K) * Q_t_f * gauss
pde_scale = (T_char / config.T_END) ** 2 + 1e-8
L_pde = ((dT_dt - config.ALPHA * d2T_dx2 - source_term) ** 2).mean() / pde_scale
L_pde = ((dT_dt - config.ALPHA * d2T_dx2 - source_term) ** 2).mean() / _pde_scale
# IC: T(x, 0) = T0 — normalized by T_char²
T_ic_pred = model(torch.stack([x_ic, torch.zeros_like(x_ic)], dim=1))
T_ic_true = torch.full_like(T_ic_pred, config.T0)
L_ic = ((T_ic_pred - T_ic_true) ** 2).mean() / (T_char ** 2 + 1e-8)
L_ic = ((T_ic_pred - T_ic_true) ** 2).mean() / (_T_char ** 2 + 1e-8)
# BC x=0: Robin — dT/dx + H_CONV/K * (T(0,t) - T_AMB) = 0
x_left = torch.zeros(t_bc.shape[0], device=t_bc.device).requires_grad_(True)