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:
@@ -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
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user