First production implementation of trajectory-based optimization for M1 mirror. Study Configuration: - Optimizer: TPE (100 trials, 15 startup) - Primary objective: total_filtered_rms_nm (integrated RMS across 20-60 deg) - Logged objectives: coma_rms_nm, astigmatism_rms_nm, trefoil_rms_nm, spherical_rms_nm - Design variables: 11 (full wiffle tree + lateral supports) - Physics validation: R² fit quality monitoring Key Features: - Mode-specific aberration tracking (coma, astigmatism, trefoil, spherical) - Physics-based trajectory model: c_j(θ) = a_j·sin(θ) + b_j·cos(θ) - Sensitivity analysis: axial vs lateral load contributions - OPD correction with focal_length=22000mm - Annular aperture (inner_radius=135.75mm) Validation Results: - Tested on existing M1_Tensor OP2: R²=1.0000 (perfect fit) - Baseline total RMS: 4.30 nm - All 5 angles auto-detected: [20, 30, 40, 50, 60] deg - Dominant mode: spherical (10.51 nm) Files Created: - studies/M1_Mirror/SAT3_Trajectory/README.md (complete documentation) - studies/M1_Mirror/SAT3_Trajectory/STUDY_REPORT.md (results template) - studies/M1_Mirror/SAT3_Trajectory/run_optimization.py (TPE + trajectory extraction) - studies/M1_Mirror/SAT3_Trajectory/1_setup/optimization_config.json (TPE config) - studies/M1_Mirror/SAT3_Trajectory/1_setup/model/ (all NX files copied from M1_Tensor) - test_trajectory_extractor.py (validation script) References: - Physics: docs/physics/ZERNIKE_TRAJECTORY_METHOD.md - Handoff: docs/handoff/SETUP_TRAJECTORY_OPTIMIZATION.md - Extractor: optimization_engine/extractors/extract_zernike_trajectory.py Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
49 lines
1.7 KiB
Python
49 lines
1.7 KiB
Python
"""Test the Zernike Trajectory extractor on an existing OP2 file."""
|
|
|
|
from optimization_engine.extractors.extract_zernike_trajectory import extract_zernike_trajectory
|
|
from pathlib import Path
|
|
|
|
op2_file = Path(r'tests\M1_Tensor\Atomizer_M1_Best_2026-01-29 - Tensor\assy_m1_assyfem1_sim1-solution_1.op2')
|
|
|
|
print(f'Testing trajectory extractor on: {op2_file}')
|
|
print('=' * 60)
|
|
|
|
try:
|
|
result = extract_zernike_trajectory(
|
|
op2_file,
|
|
reference_angle=20.0,
|
|
focal_length=22000.0
|
|
)
|
|
|
|
print('[OK] Extractor ran successfully!')
|
|
print()
|
|
print(f'Angles detected: {result["angles_deg"]}')
|
|
print(f'Reference angle: {result["reference_angle"]} deg')
|
|
print(f'Number of angles: {result["n_angles"]}')
|
|
print()
|
|
print(f'Linear fit R2: {result["linear_fit_r2"]:.4f}')
|
|
if result["linear_fit_r2"] > 0.95:
|
|
print(' [OK] Excellent fit - physics model validated')
|
|
elif result["linear_fit_r2"] > 0.85:
|
|
print(' [~] Good fit - some nonlinearity present')
|
|
else:
|
|
print(' [!] Poor fit - significant nonlinearity')
|
|
print()
|
|
print('--- Mode-Specific RMS (nm) ---')
|
|
print(f'Total Filtered RMS: {result["total_filtered_rms_nm"]:.2f} nm')
|
|
print(f'Coma RMS: {result["coma_rms_nm"]:.2f} nm')
|
|
print(f'Astigmatism RMS: {result["astigmatism_rms_nm"]:.2f} nm')
|
|
print(f'Trefoil RMS: {result["trefoil_rms_nm"]:.2f} nm')
|
|
print(f'Spherical RMS: {result["spherical_rms_nm"]:.2f} nm')
|
|
print()
|
|
print(f'Dominant mode: {result["dominant_mode"]}')
|
|
print(f'Mode ranking: {", ".join(result["mode_ranking"][:5])}')
|
|
print()
|
|
print('[OK] All validation checks passed!')
|
|
|
|
except Exception as e:
|
|
print(f'[ERROR] {e}')
|
|
import traceback
|
|
traceback.print_exc()
|
|
exit(1)
|