import sys import os sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import pytest import numpy as np import torch import config # ── FDM ─────────────────────────────────────────────────────────────────────── def test_fdm_full_run(): """Il solver FDM produce un campo di temperatura fisicamente corretto.""" from fdm.solver import solve T, x, t = solve() assert T.shape == (config.NX, config.NT) assert np.isfinite(T).all() assert T[:, -1].mean() > config.T0 # la sorgente ha scaldato il dominio assert T.max() > config.T0 # picco sopra la IC assert T.min() >= config.T0 - 1e-6 # nessun raffreddamento sotto T0 (no sorgenti fredde) def test_fdm_visualizer_creates_html(tmp_path, monkeypatch): """Il visualizer FDM scrive almeno un file HTML senza errori.""" import fdm.visualizer as fdm_vis monkeypatch.setattr(fdm_vis, 'BASE_DIR', str(tmp_path)) from fdm.solver import solve T, x, t = solve() fdm_vis.visualize_fdm(T, x, t) html_files = list(tmp_path.rglob('*.html')) assert len(html_files) >= 1, "Nessun file HTML generato dal visualizer FDM" def test_pinn_visualizer_creates_html(tmp_path, monkeypatch): """Il visualizer PINN scrive i tre file HTML senza errori.""" import visualizer as pinn_vis monkeypatch.setattr(pinn_vis, 'BASE_DIR', str(tmp_path)) from fdm.solver import solve as fdm_solve T_fdm, _, _ = fdm_solve() nx, nt = 20, 20 x_vals = np.linspace(0, config.L, nx) t_vals = np.linspace(0, config.T_END, nt) T_pred = np.full((nx, nt), config.T_AMB) # predizione costante (dummy) pinn_vis.visualize_heat_field(T_pred, x_vals, t_vals, T_fdm) html_files = list(tmp_path.rglob('*.html')) assert len(html_files) == 3, f"Attesi 3 HTML, trovati {len(html_files)}" # ── PINN training (lento) ───────────────────────────────────────────────────── @pytest.mark.slow def test_pinn_training_saves_checkpoint(tmp_path, monkeypatch): """Training per 30 epoche: il checkpoint viene salvato.""" import engine save_path = str(tmp_path / 'model.pth') monkeypatch.setattr(engine, 'MODEL_SAVE_PATH', save_path) monkeypatch.setattr(engine, 'MODELS_DIR', str(tmp_path)) from engine import prepare_data, train_model data = prepare_data(N_f=300, N_ic=100, N_bc=100) train_model(data, epochs=30, patience=30) assert os.path.exists(save_path) ckpt = torch.load(save_path, map_location='cpu', weights_only=True) assert 'state_dict' in ckpt @pytest.mark.slow def test_pinn_evaluate_after_training(tmp_path, monkeypatch): """evaluate_model gira senza errori dopo un training minimo.""" import engine save_path = str(tmp_path / 'model.pth') monkeypatch.setattr(engine, 'MODEL_SAVE_PATH', save_path) monkeypatch.setattr(engine, 'MODELS_DIR', str(tmp_path)) from engine import prepare_data, train_model, evaluate_model data = prepare_data(N_f=300, N_ic=100, N_bc=100) train_model(data, epochs=30, patience=30) evaluate_model(data)