Files
Atomizer/optimization_engine/gnn/test_field_extraction.py
Antoine 96b196de58 feat: Add Zernike GNN surrogate module and M1 mirror V12/V13 studies
This commit introduces the GNN-based surrogate for Zernike mirror optimization
and the M1 mirror study progression from V12 (GNN validation) to V13 (pure NSGA-II).

## GNN Surrogate Module (optimization_engine/gnn/)

New module for Graph Neural Network surrogate prediction of mirror deformations:

- `polar_graph.py`: PolarMirrorGraph - fixed 3000-node polar grid structure
- `zernike_gnn.py`: ZernikeGNN with design-conditioned message passing
- `differentiable_zernike.py`: GPU-accelerated Zernike fitting and objectives
- `train_zernike_gnn.py`: ZernikeGNNTrainer with multi-task loss
- `gnn_optimizer.py`: ZernikeGNNOptimizer for turbo mode (~900k trials/hour)
- `extract_displacement_field.py`: OP2 to HDF5 field extraction
- `backfill_field_data.py`: Extract fields from existing FEA trials

Key innovation: Design-conditioned convolutions that modulate message passing
based on structural design parameters, enabling accurate field prediction.

## M1 Mirror Studies

### V12: GNN Field Prediction + FEA Validation
- Zernike GNN trained on V10/V11 FEA data (238 samples)
- Turbo mode: 5000 GNN predictions → top candidates → FEA validation
- Calibration workflow for GNN-to-FEA error correction
- Scripts: run_gnn_turbo.py, validate_gnn_best.py, compute_full_calibration.py

### V13: Pure NSGA-II FEA (Ground Truth)
- Seeds 217 FEA trials from V11+V12
- Pure multi-objective NSGA-II without any surrogate
- Establishes ground-truth Pareto front for GNN accuracy evaluation
- Narrowed blank_backface_angle range to [4.0, 5.0]

## Documentation Updates

- SYS_14: Added Zernike GNN section with architecture diagrams
- CLAUDE.md: Added GNN module reference and quick start
- V13 README: Study documentation with seeding strategy

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 08:44:04 -05:00

38 lines
1.3 KiB
Python

"""Quick test script for displacement field extraction."""
import h5py
import numpy as np
from pathlib import Path
# Test file
h5_path = Path("C:/Users/Antoine/Atomizer/studies/m1_mirror_adaptive_V11/gnn_data/trial_0091/displacement_field.h5")
print(f"Testing: {h5_path}")
print(f"Exists: {h5_path.exists()}")
if h5_path.exists():
with h5py.File(h5_path, 'r') as f:
print(f"\nDatasets in file: {list(f.keys())}")
node_coords = f['node_coords'][:]
node_ids = f['node_ids'][:]
print(f"\nTotal nodes: {len(node_ids)}")
# Calculate radial position
r = np.sqrt(node_coords[:, 0]**2 + node_coords[:, 1]**2)
print(f"Radial range: [{r.min():.1f}, {r.max():.1f}] mm")
print(f"Z range: [{node_coords[:, 2].min():.1f}, {node_coords[:, 2].max():.1f}] mm")
# Check nodes in optical surface range (100-650 mm radius)
surface_mask = (r >= 100) & (r <= 650)
print(f"Nodes in r=[100, 650]: {np.sum(surface_mask)}")
# Check subcases
subcases = [k for k in f.keys() if k.startswith("subcase_")]
print(f"Subcases: {subcases}")
if subcases:
for sc in subcases:
disp = f[sc][:]
print(f" {sc}: Z-disp range [{disp.min():.4f}, {disp.max():.4f}] mm")