Allinea PINN alla fisica FDM: sorgente interna e BC Robin bilaterali

- model.py: aggiunge termine sorgente Gaussiana (σ=0.02) nella PDE loss
  per approssimare δ(x − X_SRC); sostituisce BC Neumann a x=0 con Robin
- engine.py: clustering collocation vicino X_SRC anziché x=0;
  downsample FDM su entrambi gli assi spaziale e temporale in evaluate_model()
- visualizer.py: downsample FDM su entrambi gli assi prima del plot
- app.py: aggiorna header con fisica corrente
- CLAUDE.md: aggiorna PDE, BC e note architetturali

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-14 12:07:14 +02:00
parent 687ff45512
commit b663a89abd
5 changed files with 34 additions and 25 deletions
+9 -7
View File
@@ -43,16 +43,17 @@ def prepare_data(N_f=4000, N_ic=400, N_bc=400):
x_f = torch.rand(N_f, device=device) * config.L
t_f = torch.rand(N_f, device=device) * config.T_END
# Extra points near x=0 (steep Neumann gradient) and t=T_STEP (flux step)
# Extra points near X_SRC (steep gradient at source) and t=T_STEP (flux step)
n_extra = N_f // 4
x_near0 = torch.rand(n_extra, device=device) * config.L * 0.1 # x in [0, 0.1]
t_near0 = torch.rand(n_extra, device=device) * config.T_END
x_near_src = config.X_SRC + (torch.rand(n_extra, device=device) - 0.5) * config.L * 0.1
x_near_src = x_near_src.clamp(0, config.L)
t_near_src = torch.rand(n_extra, device=device) * config.T_END
x_step = torch.rand(n_extra, device=device) * config.L
t_step = config.T_STEP + (torch.rand(n_extra, device=device) - 0.5) * 0.1 # t near T_STEP
t_step = t_step.clamp(0, config.T_END)
x_f = torch.cat([x_f, x_near0, x_step])
t_f = torch.cat([t_f, t_near0, t_step])
x_f = torch.cat([x_f, x_near_src, x_step])
t_f = torch.cat([t_f, t_near_src, t_step])
x_ic = torch.rand(N_ic, device=device) * config.L
t_bc = torch.rand(N_bc, device=device) * config.T_END
@@ -163,10 +164,11 @@ def evaluate_model(data):
from fdm.solver import solve as fdm_solve
T_fdm, _, _ = fdm_solve()
# Downsample FDM time axis (NX=100, NT=5000) to match PINN grid (100x100)
# Downsample FDM grid (NX, NT) to match PINN prediction grid (100x100)
nx, nt = T_pred.shape
x_indices = np.linspace(0, T_fdm.shape[0] - 1, nx, dtype=int)
t_indices = np.linspace(0, T_fdm.shape[1] - 1, nt, dtype=int)
T_fdm_ds = T_fdm[:, t_indices] # (100, 100)
T_fdm_ds = T_fdm[np.ix_(x_indices, t_indices)] # (100, 100)
l2_rel = np.sqrt(np.mean((T_pred - T_fdm_ds) ** 2)) / np.sqrt(np.mean(T_fdm_ds ** 2))
max_err = np.max(np.abs(T_pred - T_fdm_ds))