Download scripts/result.py from OneScience-Group/PseudoTimePINN-BackwardFacingStep: direct link, hf CLI and curl.
- Browser
- Download file 6.25 kB
-
https://huggingface.co/OneScience-Group/PseudoTimePINN-BackwardFacingStep/resolve/main/scripts/result.py
- Command line
-
hf download hf://OneScience-Group/PseudoTimePINN-BackwardFacingStep/scripts/result.py
-
curl -L -o result.py https://huggingface.co/OneScience-Group/PseudoTimePINN-BackwardFacingStep/resolve/main/scripts/result.py
6.25 kB
| #!/usr/bin/env python3 | |
| """Scientific field, error and convergence plots from actual run artifacts.""" | |
| import argparse | |
| import csv | |
| import json | |
| from pathlib import Path | |
| import sys | |
| sys.path.insert(0, str(Path(__file__).resolve().parents[1])) | |
| import numpy as np | |
| import matplotlib | |
| matplotlib.use('Agg') | |
| import matplotlib.pyplot as plt | |
| import matplotlib.tri as mtri | |
| from scripts.common import load_config, atomic_json | |
| def save(fig, directory, stem): | |
| for ext in ('png', 'pdf'): | |
| fig.savefig(directory / f'{stem}.{ext}', dpi=300, bbox_inches='tight') | |
| plt.close(fig) | |
| def main(): | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument('--config', default='config/config.yaml') | |
| args = parser.parse_args() | |
| cfg, root = load_config(args.config) | |
| results = root / cfg['paths']['results'] | |
| metrics = json.loads((results / 'metrics.json').read_text()) | |
| manifest = [] | |
| for label in metrics['checkpoints']: | |
| data = np.load(results / f'predictions_{label}.npz') | |
| xy, pred, ref = data['xy'], data['prediction_uvp'], data['reference_uvp'] | |
| tri = mtri.Triangulation(xy[:, 0], xy[:, 1]) | |
| fig, axes = plt.subplots(3, 1, figsize=(15, 5.5), constrained_layout=True) | |
| lower, upper = min(ref[:, 0].min(), pred[:, 0].min()), max(ref[:, 0].max(), pred[:, 0].max()) | |
| values = [ref[:, 0], pred[:, 0], abs(pred[:, 0] - ref[:, 0])] | |
| titles = ['SU2 reference u', f'Adaptive pseudo-time PINN u ({label}, step {int(data["checkpoint_step"])})', '|u_PINN - u_SU2|'] | |
| for i, (ax, val, title) in enumerate(zip(axes, values, titles)): | |
| kwargs = dict(cmap='viridis', shading='gouraud') | |
| if i < 2: | |
| kwargs.update(vmin=lower, vmax=upper) | |
| c = ax.tripcolor(tri, val, **kwargs) | |
| fig.colorbar(c, ax=ax, pad=0.01) | |
| ax.set(xlim=(0, 15), ylim=(-.5, .5), xlabel='x / H', ylabel='y / H', title=title) | |
| ax.set_aspect('equal') | |
| fig.suptitle(f'Re = 800; relative L2(u) = {metrics["checkpoints"][label]["relative_l2_u"]:.6g}') | |
| save(fig, results, f'velocity_u_{label}') | |
| manifest += [f'velocity_u_{label}.png', f'velocity_u_{label}.pdf'] | |
| fig, axes = plt.subplots(2, 1, figsize=(15, 4), constrained_layout=True) | |
| for ax, val, title, cmap in [(axes[0], np.linalg.norm(pred[:, :2], axis=1), 'Predicted speed', 'viridis'), | |
| (axes[1], pred[:, 2], 'Predicted pressure', 'coolwarm')]: | |
| c = ax.tripcolor(tri, val, cmap=cmap, shading='gouraud') | |
| fig.colorbar(c, ax=ax, pad=.01) | |
| ax.set(xlabel='x / H', ylabel='y / H', title=title, xlim=(0, 15), ylim=(-.5, .5)) | |
| ax.set_aspect('equal') | |
| save(fig, results, f'speed_pressure_{label}') | |
| manifest += [f'speed_pressure_{label}.png', f'speed_pressure_{label}.pdf'] | |
| rows = list(csv.DictReader((results / 'training_history.csv').open())) | |
| def series(key): | |
| valid = [r for r in rows if r.get(key, '')] | |
| return np.array([float(r['step']) for r in valid]), np.array([float(r[key]) for r in valid]) | |
| fig, axes = plt.subplots(2, 2, figsize=(11, 7), constrained_layout=True) | |
| x, y = series('loss') | |
| axes[0, 0].semilogy(x, y, label='Weighted relaxed loss') | |
| for key in ('raw_u_res', 'raw_v_res', 'raw_p_res'): | |
| x, y = series(key) | |
| axes[0, 0].semilogy(x, y, label=key) | |
| axes[0, 0].legend(fontsize=8) | |
| x, y = series('relative_l2_u') | |
| axes[0, 1].semilogy(x, y, label='Actual SU2 relative L2(u)') | |
| axes[0, 1].axhline(cfg['evaluation']['paper_relative_l2_u'], color='gray', linestyle='--', label='Table 1: 2.32e-3') | |
| axes[0, 1].legend(fontsize=8) | |
| for key in ('tau_u', 'tau_v', 'tau_p'): | |
| x, y = series(key) | |
| axes[1, 0].semilogy(x, y, label=key) | |
| axes[1, 0].legend() | |
| x, y = series('learning_rate') | |
| axes[1, 1].plot(x, y) | |
| axes[1, 1].set_ylabel('Learning rate') | |
| for ax in axes.flat: | |
| ax.set_xlabel('Actual optimizer iterations') | |
| ax.grid(alpha=.2) | |
| save(fig, results, 'training_curves') | |
| manifest += ['training_curves.png', 'training_curves.pdf'] | |
| summary = json.loads((results / 'training_summary.json').read_text()) | |
| report = ['# BFS Re=800 formal reproduction', '', | |
| f'Actual completed steps: {summary["completed_steps"]} / {summary["requested_steps"]}.', | |
| f'Slurm job: {summary["slurm_job_id"]}; host: {summary["host"]}.', | |
| f'Elapsed training seconds: {summary["elapsed_seconds"]:.1f}.', '', | |
| '| Selection | Checkpoint step | Relative L2(u) |', '|---|---:|---:|'] | |
| for key, value in metrics['checkpoints'].items(): | |
| report.append(f'| {key} | {value["checkpoint_step"]} | {value["relative_l2_u"]:.8g} |') | |
| report += ['', 'Paper Table 1 adaptive value: 0.00232. This is a comparison target, not a measured result.', | |
| 'Training used only analytic boundary conditions and resampled PDE collocation points.', | |
| 'The SU2 reference was used only for reporting. Checkpoint selection used an independent unlabeled physics validation set.', | |
| 'Full parameter provenance and paper/repository conflicts are recorded in the reproduction specification.', | |
| '', 'Figures:', ''] + [f'- {f}' for f in manifest if f.endswith('.png')] | |
| error_history = results / 'error_history.jsonl' | |
| if error_history.exists(): | |
| report += ['', 'Execution errors and repairs:', ''] | |
| for line in error_history.read_text().splitlines(): | |
| event = json.loads(line) | |
| report.append(f'- Job {event["job_id"]}, actual formal steps {event["completed_steps"]}: ' | |
| f'{event["error"]}. Repair: {event["repair"]}.') | |
| (results / 'report.md').write_text('\n'.join(report) + '\n') | |
| atomic_json(results / 'visualization_manifest.json', {'status': 'completed', 'figures': manifest, | |
| 'reference': metrics['reference'], 'dpi': 300, 'interpolation': 'triangulation only for display; metrics use original nodes'}) | |
| print(json.dumps({'event': 'visualization_completed', 'figures': manifest, 'report': str(results / 'report.md')}), flush=True) | |
| if __name__ == '__main__': | |
| main() | |