Files
Atomizer/docs/physics/ZERNIKE_TRAJECTORY_METHOD.md

270 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Zernike Trajectory Method for Elevation-Dependent Optimization
**Document Version**: 1.0
**Created**: 2026-01-29
**Author**: Mario (Clawdbot) + Antoine Letarte
**Status**: Validated ✅
---
## Executive Summary
The Zernike Trajectory Method provides **mode-specific optimization objectives** for telescope mirrors operating across multiple elevation angles. Instead of optimizing a weighted sum of discrete WFE values, this method:
1. **Tracks how each Zernike mode evolves** with elevation angle
2. **Fits a physics-based linear model** to the trajectory
3. **Provides integrated RMS metrics** for each aberration type
4. **Reveals which modes respond to axial vs lateral gravity loads**
**Key result**: For a well-designed support system, the linear model achieves R² ≈ 1.0, meaning deformation is entirely predictable from the gravity load decomposition.
---
## 1. Physics Background
### 1.1 Gravity Load Decomposition
At elevation angle θ from horizontal:
```
Axial load (along optical axis): F_axial ∝ sin(θ)
Lateral load (perpendicular): F_lateral ∝ cos(θ)
```
For a linear elastic structure, surface deformation is linear in these load components.
### 1.2 Zernike Coefficient Evolution
Each Zernike coefficient c_j follows:
```
c_j(θ) = a_j · (sin(θ) - sin(θ_ref)) + b_j · (cos(θ) - cos(θ_ref))
```
Where:
- `θ_ref` = reference angle (typically 20° for polishing/measurement)
- `a_j` = sensitivity of mode j to axial load change
- `b_j` = sensitivity of mode j to lateral load change
### 1.3 The Sensitivity Matrix
Define trajectory parameters:
```
τ(θ) = [sin(θ) - sin(θ_ref), cos(θ) - cos(θ_ref)]ᵀ
```
The full coefficient vector evolves as:
```
c⃗(θ) = S · τ(θ)
```
Where **S** is the sensitivity matrix (N_modes × 2).
---
## 2. Implementation
### 2.1 Extractor Location
```
optimization_engine/extractors/extract_zernike_trajectory.py
```
### 2.2 Basic Usage
```python
from optimization_engine.extractors.extract_zernike_trajectory import extract_zernike_trajectory
result = extract_zernike_trajectory(
'path/to/solution.op2',
reference_angle=20.0, # Reference elevation (degrees)
)
# Mode-specific integrated RMS (nm)
print(result['coma_rms_nm'])
print(result['astigmatism_rms_nm'])
print(result['trefoil_rms_nm'])
print(result['spherical_rms_nm'])
# Total filtered RMS across all angles
print(result['total_filtered_rms_nm'])
# Linear model fit quality (should be > 0.95)
print(result['linear_fit_r2'])
# Sensitivity analysis
print(result['sensitivity_matrix'])
# {'coma': {'axial': 0.63, 'lateral': 36.04, 'total': 36.05}, ...}
```
### 2.3 Auto-Detection Features
The extractor automatically:
- Reads subcase labels from OP2 metadata (e.g., "20", "40", "60")
- Excludes manufacturing angle (90°) by default
- Sorts angles for proper trajectory fitting
### 2.4 Output Dictionary
```python
{
# Mode-specific integrated RMS (nm)
'coma_rms_nm': float,
'astigmatism_rms_nm': float,
'trefoil_rms_nm': float,
'spherical_rms_nm': float,
'secondary_astig_rms_nm': float,
'secondary_coma_rms_nm': float,
'quadrafoil_rms_nm': float,
# Total filtered RMS (all modes, integrated)
'total_filtered_rms_nm': float,
# Model quality
'linear_fit_r2': float, # Should be > 0.95
# Sensitivity analysis
'sensitivity_matrix': {
'coma': {'axial': float, 'lateral': float, 'total': float},
'astigmatism': {...},
...
},
# Mode ranking (by sensitivity)
'mode_ranking': ['spherical', 'coma', 'astigmatism', ...],
'dominant_mode': str,
# Metadata
'angles_deg': [20.0, 30.0, 40.0, 50.0, 60.0],
'reference_angle': 20.0,
}
```
---
## 3. Optimization Integration
### 3.1 AtomizerSpec Configuration
```yaml
extractors:
- id: ext_trajectory
name: "Zernike Trajectory"
type: zernike_trajectory
config:
reference_angle: 20.0
# Subcases auto-detected from OP2 labels
objectives:
# Option A: Single combined objective
- id: obj_total
name: "Total Integrated RMS"
source:
extractor_id: ext_trajectory
output_name: total_filtered_rms_nm
direction: minimize
weight: 1.0
# Option B: Mode-specific objectives (multi-objective)
- id: obj_coma
name: "Coma RMS"
source:
extractor_id: ext_trajectory
output_name: coma_rms_nm
direction: minimize
weight: 1.0
- id: obj_astig
name: "Astigmatism RMS"
source:
extractor_id: ext_trajectory
output_name: astigmatism_rms_nm
direction: minimize
weight: 0.8
```
### 3.2 Recommended Optimization Strategy
**For SAT (Surrogate-Assisted Tuning):**
- Use `total_filtered_rms_nm` as primary objective
- Add mode-specific objectives as secondary for Pareto analysis
- SAT handles the expensive FEA evaluations efficiently
**For TPE (Tree-Parzen Estimator):**
- Good for single-objective optimization
- Use weighted combination if needed:
```
J = w_coma * coma_rms + w_astig * astig_rms + w_total * total_rms
```
---
## 4. Validation Results (M1 Mirror, 2026-01-29)
### 4.1 Test Configuration
- **Model**: M1 GigaBIT mirror (1.2m Zerodur)
- **Angles**: 20°, 30°, 40°, 50°, 60° (5 subcases)
- **Reference**: 20° (polishing/measurement)
### 4.2 Linear Fit Quality
```
R² = 1.0000 ← PERFECT FIT
```
The physics model is **exactly correct** for this mirror design.
### 4.3 Mode-Specific Results
| Mode | Integrated RMS (nm) | Axial Sensitivity | Lateral Sensitivity |
|------|---------------------|-------------------|---------------------|
| Secondary Astig | 12.95 | 1.93 | 48.91 |
| Spherical | 10.57 | 19.84 | 68.08 |
| Coma | 9.14 | 0.63 | **36.04** |
| Trefoil | 6.83 | — | — |
| Astigmatism | 6.80 | — | — |
**Key insight**: Coma is almost entirely driven by lateral loads (axial/lateral ratio = 0.02). Optimizing lateral support locations will have the biggest impact on coma.
---
## 5. Troubleshooting
### 5.1 Low R² Value
If R² < 0.9:
- Check for contact nonlinearity (supports lifting off)
- Check for material nonlinearity
- Verify subcases have consistent boundary conditions
### 5.2 Missing Subcases
Ensure your FEA includes all required angles. Minimum recommended:
- 20° (reference)
- 40° (primary operational)
- 60° (secondary operational)
Adding 30° and 50° improves trajectory fit quality.
### 5.3 Subcase Label Detection
If auto-detection fails, specify manually:
```python
result = extract_zernike_trajectory(
'solution.op2',
subcases=[2, 5, 3, 6, 4], # Subcase IDs
angles=[20.0, 30.0, 40.0, 50.0, 60.0], # Corresponding angles
)
```
---
## 6. References
- [ZERNIKE_OPD_METHOD.md](ZERNIKE_OPD_METHOD.md) — OPD correction for lateral displacement
- [ZERNIKE_FUNDAMENTALS.md](../ZERNIKE_FUNDAMENTALS.md) — Zernike polynomial basics
- AtomizerSpec v2.0 — Objective/extractor configuration
---
*Document maintained by Atomizer Framework. Last updated: 2026-01-29*