Files
Atomizer/tests/analyze_v11.py

151 lines
5.0 KiB
Python
Raw Normal View History

"""Analyze V11 optimization results."""
import sqlite3
from pathlib import Path
import json
import sys
sys.path.insert(0, '.')
db_path = Path('studies/M1_Mirror/m1_mirror_cost_reduction_V11/3_results/study.db')
conn = sqlite3.connect(db_path)
c = conn.cursor()
# Get all completed trials with their objectives
c.execute('''
SELECT t.trial_id
FROM trials t
WHERE t.state = 'COMPLETE'
ORDER BY t.trial_id
''')
completed_ids = [row[0] for row in c.fetchall()]
print(f'Completed trials: {len(completed_ids)}')
# Build trial data
trials = []
for tid in completed_ids:
c.execute('''
SELECT key, value_json
FROM trial_user_attributes
WHERE trial_id = ?
''', (tid,))
attrs = {row[0]: json.loads(row[1]) for row in c.fetchall()}
if 'rel_filtered_rms_40_vs_20' in attrs:
trials.append({
'id': tid,
'rms_40': attrs.get('rel_filtered_rms_40_vs_20', 999),
'rms_60': attrs.get('rel_filtered_rms_60_vs_20', 999),
'mfg_90': attrs.get('mfg_90_optician_workload', 999),
'ws': attrs.get('weighted_sum', 999),
'lateral': attrs.get('lateral_rms_um', 0),
})
# Sort by weighted sum or calculate it
for t in trials:
if t['ws'] == 999:
# Calculate weighted sum
w40 = 100 / 4.0 # Target 4 nm
w60 = 50 / 10.0 # Target 10 nm
w90 = 20 / 20.0 # Target 20 nm
t['ws'] = w40 * t['rms_40'] + w60 * t['rms_60'] + w90 * t['mfg_90']
# Find best
trials.sort(key=lambda x: x['ws'])
best = trials[0] if trials else None
print('\nV11 Optimization Summary')
print('=' * 70)
print(f'Completed trials: {len(trials)}')
if trials:
rms40 = [t['rms_40'] for t in trials]
rms60 = [t['rms_60'] for t in trials]
mfg90 = [t['mfg_90'] for t in trials]
print(f'\n40-20 RMS range: {min(rms40):.2f} - {max(rms40):.2f} nm (target: 4.0 nm)')
print(f'60-20 RMS range: {min(rms60):.2f} - {max(rms60):.2f} nm (target: 10.0 nm)')
print(f'90 MFG range: {min(mfg90):.2f} - {max(mfg90):.2f} nm (target: 20.0 nm)')
print(f'\nBest Trial (#{best["id"]}):')
print(f' 40-20 RMS: {best["rms_40"]:.2f} nm')
print(f' 60-20 RMS: {best["rms_60"]:.2f} nm')
print(f' MFG 90: {best["mfg_90"]:.2f} nm')
print(f' Lateral: {best["lateral"]:.3f} um')
print(f' WS: {best["ws"]:.1f}')
# Check if values make sense (not too good to be true)
print('\nSanity Check:')
if best['rms_40'] < 3.0:
print(' WARNING: 40-20 RMS suspiciously low!')
else:
print(f' 40-20 RMS {best["rms_40"]:.2f} nm - looks reasonable (expected ~6-7nm)')
if best['rms_60'] < 8.0:
print(' WARNING: 60-20 RMS suspiciously low!')
else:
print(f' 60-20 RMS {best["rms_60"]:.2f} nm - looks reasonable (expected ~13-15nm)')
# Compare to V7 baseline and V10 buggy values
print('\n' + '=' * 70)
print('Comparison to Known Values:')
print('=' * 70)
print('\nV7 Baseline (original Zernike, correct):')
print(' 40-20 RMS: 6.05 nm')
print(' 60-20 RMS: 13.03 nm')
print(' MFG 90: 26.34 nm')
print('\nV10 BUGGY (abs(RMS_target - RMS_ref) - WRONG):')
print(' 40-20 RMS: ~1.99 nm <- WAY TOO LOW')
print(' 60-20 RMS: ~6.82 nm <- WAY TOO LOW')
print('\nV11 Best (extract_relative() - CORRECT):')
print(f' 40-20 RMS: {best["rms_40"]:.2f} nm')
print(f' 60-20 RMS: {best["rms_60"]:.2f} nm')
print(f' MFG 90: {best["mfg_90"]:.2f} nm')
# Verdict
print('\n' + '=' * 70)
print('VERDICT:')
print('=' * 70)
if best['rms_40'] > 5.0 and best['rms_40'] < 10.0:
print(' 40-20: CORRECT - matches expected V7 range')
else:
print(f' 40-20: INVESTIGATE - {best["rms_40"]:.2f} nm is outside expected range')
if best['rms_60'] > 10.0 and best['rms_60'] < 20.0:
print(' 60-20: CORRECT - matches expected V7 range')
else:
print(f' 60-20: INVESTIGATE - {best["rms_60"]:.2f} nm is outside expected range')
conn.close()
# Now generate Zernike dashboard for visual verification
print('\n' + '=' * 70)
print('Generating Zernike Dashboard for Best Iteration...')
print('=' * 70)
from optimization_engine.insights import ZernikeDashboardInsight, InsightConfig
study_path = Path('studies/M1_Mirror/m1_mirror_cost_reduction_V11')
# Find the iteration with the best design
best_archive = study_path / '3_results' / 'best_design_archive'
if best_archive.exists():
op2_files = list(best_archive.glob('*.op2'))
if op2_files:
print(f'Found best design archive: {op2_files[0].name}')
insight = ZernikeDashboardInsight(study_path)
if insight.can_generate():
print('Generating dashboard...')
result = insight.generate(InsightConfig())
if result.success:
print(f'\nDashboard generated: {result.html_path}')
print(f'\nDashboard Summary:')
for key, value in result.summary.items():
print(f' {key}: {value}')
else:
print(f'Error: {result.error}')
else:
print('Cannot generate insight - no OP2 files found')