Files
Atomizer/tests/test_zernike_opd_comparison.py

96 lines
3.2 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python
"""
Quick test script to compare Standard vs OPD Zernike methods.
Usage:
conda activate atomizer
python test_zernike_opd_comparison.py
This will analyze a recent OP2 file and show you:
1. How much lateral displacement exists
2. How different the WFE metrics are between methods
3. Whether you need to switch to OPD method for your optimizations
"""
from pathlib import Path
import sys
# Add project root to path
sys.path.insert(0, str(Path(__file__).parent))
def main():
import numpy as np
from optimization_engine.extractors.extract_zernike_opd import (
ZernikeOPDExtractor,
)
# Find a recent OP2 file from your studies
studies_path = Path("studies/M1_Mirror")
op2_files = list(studies_path.glob("**/2_iterations/**/*.op2"))
if not op2_files:
op2_files = list(studies_path.glob("**/*.op2"))
if not op2_files:
print("No OP2 files found in studies/M1_Mirror")
return
# Use the most recent one
op2_file = max(op2_files, key=lambda p: p.stat().st_mtime)
print(f"Analyzing: {op2_file}")
print("=" * 80)
# Run comparison
try:
extractor = ZernikeOPDExtractor(op2_file)
print(f"\nAvailable subcases: {list(extractor.displacements.keys())}")
# Show geometry info
geo = extractor.node_geometry
all_pos = np.array(list(geo.values()))
print(f"\n--- Geometry Info ---")
print(f" Nodes: {len(geo)}")
print(f" X range: {all_pos[:,0].min():.1f} to {all_pos[:,0].max():.1f} mm")
print(f" Y range: {all_pos[:,1].min():.1f} to {all_pos[:,1].max():.1f} mm")
print(f" Z range: {all_pos[:,2].min():.1f} to {all_pos[:,2].max():.1f} mm")
for label in extractor.displacements.keys():
print(f"\n{'=' * 80}")
print(f"SUBCASE {label}")
print('=' * 80)
comparison = extractor.extract_comparison(label)
print(f"\n--- Standard Method (Z-only) ---")
print(f" Global RMS: {comparison['standard_method']['global_rms_nm']:.2f} nm")
print(f" Filtered RMS: {comparison['standard_method']['filtered_rms_nm']:.2f} nm")
print(f"\n--- Rigorous OPD Method ---")
print(f" Global RMS: {comparison['opd_method']['global_rms_nm']:.2f} nm")
print(f" Filtered RMS: {comparison['opd_method']['filtered_rms_nm']:.2f} nm")
print(f"\n--- Difference (OPD - Standard) ---")
delta = comparison['delta']['filtered_rms_nm']
pct = comparison['delta']['percent_difference_filtered']
sign = "+" if delta > 0 else ""
print(f" Filtered RMS: {sign}{delta:.2f} nm ({sign}{pct:.1f}%)")
print(f"\n--- Lateral Displacement ---")
print(f" Max: {comparison['lateral_displacement']['max_um']:.3f} µm")
print(f" RMS: {comparison['lateral_displacement']['rms_um']:.3f} µm")
print(f" P99: {comparison['lateral_displacement']['p99_um']:.3f} µm")
print(f"\n>>> {comparison['recommendation']}")
except Exception as e:
print(f"Error: {e}")
import traceback
traceback.print_exc()
return
if __name__ == '__main__':
main()