Download scripts/verify.py from OneScience-Group/PINN-SWE-CircularDamBreak: direct link, hf CLI and curl.
- Browser
- Download file 6.02 kB
-
https://huggingface.co/OneScience-Group/PINN-SWE-CircularDamBreak/resolve/main/scripts/verify.py
- Command line
-
hf download hf://OneScience-Group/PINN-SWE-CircularDamBreak/scripts/verify.py
-
curl -L -o verify.py https://huggingface.co/OneScience-Group/PINN-SWE-CircularDamBreak/resolve/main/scripts/verify.py
6.02 kB
| """Independent conservation identity check and completed-artifact audit.""" | |
| import csv | |
| import json | |
| from pathlib import Path | |
| import sys | |
| import numpy as np | |
| import torch | |
| sys.path.insert(0, str(Path(__file__).resolve().parents[1])) | |
| from model import PINNShallowWater | |
| from common import arguments, device_for, errors, load_config, output_path, runtime_info, save_json, sha256 | |
| from train import check_formal_config | |
| def conservation_identity(config, device): | |
| """Compare expanded R=A*r to derivatives of the conserved fluxes. | |
| This checks a separate mathematical representation, including mixed | |
| momentum fluxes; it catches dropped mass-residual terms and axis mistakes. | |
| """ | |
| torch.manual_seed(config['seed']) | |
| model = PINNShallowWater(**config['model']).to(device=device, dtype=torch.float64) | |
| points = torch.rand(19, 3, dtype=torch.float64, device=device).requires_grad_(True) | |
| points = points * torch.tensor([20, 20, 0.8], device=device) - torch.tensor([10, 10, 0], device=device) | |
| state, expanded = model.residuals(points, config['physics']['gravity'], True) | |
| h, u, v = state.unbind(1) | |
| g = config['physics']['gravity'] | |
| conserved = torch.stack((h, h * u, h * v), dim=1) | |
| flux_x = torch.stack((h * u, h * u.square() + 0.5 * g * h.square(), h * u * v), dim=1) | |
| flux_y = torch.stack((h * v, h * u * v, h * v.square() + 0.5 * g * h.square()), dim=1) | |
| expected = torch.zeros_like(expanded) | |
| for component in range(3): | |
| for value, axis in [(conserved, 2), (flux_x, 0), (flux_y, 1)]: | |
| expected[:, component] += torch.autograd.grad(value[:, component].sum(), points, retain_graph=True)[0][:, axis] | |
| maximum_error = (expanded - expected).abs().max().item() | |
| torch.testing.assert_close(expanded, expected, rtol=1e-9, atol=1e-10) | |
| (expanded.square().mean() + model.slope_recovery()).backward() | |
| assert all(p.grad is not None and torch.isfinite(p.grad).all() for p in model.parameters()) | |
| assert model.slopes.numel() == 1500 | |
| return {'flux_vs_expanded_max_abs': maximum_error, 'backward_all_parameters_finite': True, | |
| 'neuron_slopes': model.slopes.numel(), 'double_precision_identity_passed': True} | |
| def main(): | |
| parser = arguments(__doc__) | |
| parser.add_argument('--preflight', action='store_true') | |
| args = parser.parse_args() | |
| config, root = load_config(args.config) | |
| check_formal_config(config) | |
| device = device_for(config) | |
| identity = conservation_identity(config, device) | |
| if args.preflight: | |
| report = {'status': 'passed', 'execution_readiness': 'ready', 'preflight_passed': True, | |
| 'evidence': {'preflight': {'status': 'passed'}}, | |
| 'runtime': runtime_info(device), 'conservation_identity': identity, | |
| 'entry_config': 'formal dCDB9 checked', 'training_performed': False} | |
| save_json(root / '.onescience/preflight_compute.json', report) | |
| print('PREFLIGHT_COMPUTE_PASSED', report, flush=True) | |
| return | |
| results = output_path(root, config['paths']['results']) | |
| summary = json.loads((results / 'training_summary.json').read_text()) | |
| metrics = json.loads((results / 'metrics.json').read_text()) | |
| with (results / 'training_history.csv').open() as handle: | |
| history = list(csv.DictReader(handle)) | |
| assert len(history) == 5000 | |
| assert [int(row['iteration']) for row in history] == list(range(1, 5001)) | |
| assert all(float(row['learning_rate']) == 0.001 for row in history) | |
| assert all(np.isfinite(float(row[key])) for row in history for key in row) | |
| best_path = output_path(root, config['paths']['best_checkpoint']) | |
| best = torch.load(best_path, map_location='cpu', weights_only=False) | |
| last = torch.load(output_path(root, config['paths']['last_checkpoint']), map_location='cpu', weights_only=False) | |
| assert last['iteration'] == best['completed_iterations'] == summary['completed_iterations'] == 5000 | |
| assert best['iteration'] == summary['best_iteration'] | |
| assert best['formal_run_complete'] and not summary['stopped_early'] | |
| model = PINNShallowWater(**config['model']).to(device) | |
| model.load_state_dict(best['model_state_dict'], strict=True) | |
| assert all(torch.isfinite(p).all() for p in model.parameters()) | |
| assert sha256(best_path) == summary['best_checkpoint_sha256'] == metrics['checkpoint_sha256'] | |
| assert sha256(output_path(root, config['paths']['samples'])) == best['sampling_sha256'] | |
| with (np.load(output_path(root, config['paths']['predictions'])) as prediction, | |
| np.load(output_path(root, config['paths']['hll_reference'])) as reference): | |
| fields, refs = prediction['fields'], reference['fields'] | |
| assert fields.shape == refs.shape == (3, 500, 500, 3) | |
| assert np.isfinite(fields).all() and np.isfinite(refs).all() | |
| for k in range(3): | |
| recomputed = errors(fields[k].reshape(-1, 3), refs[k].reshape(-1, 3)) | |
| for key in ['MAE', 'RMSE']: | |
| np.testing.assert_allclose(recomputed[key], metrics['errors'][k][key], rtol=1e-10, atol=1e-12) | |
| figures = ['dCDB9_fields_and_errors.png', 'dCDB9_fields_and_errors.pdf', | |
| 'dCDB9_centerline_comparison.png', 'dCDB9_water_depth_surfaces.png', 'training_loss.png'] | |
| for name in figures: | |
| assert (results / name).stat().st_size > 1000 | |
| final = {'status': 'passed', 'formal_iterations': 5000, 'history_rows': len(history), | |
| 'learning_rate_constant': True, 'checkpoint_strict_load': True, | |
| 'checkpoint_finite': True, 'checkpoint_sha256': sha256(best_path), | |
| 'conservative_identity': identity, 'predictions_shape': list(fields.shape), | |
| 'metrics_independently_recomputed': True, 'figures_nonempty': figures, | |
| 'runtime': runtime_info(device), 'accuracy_claim': 'actual metrics reported; no claim of paper accuracy parity'} | |
| save_json(results / 'verification.json', final) | |
| print('FINAL_VERIFICATION_PASSED', final, flush=True) | |
| if __name__ == '__main__': | |
| main() | |