#!/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()