Files
Atomizer/studies/M1_Mirror/m1_mirror_adaptive_V12
Anto01 cb6b130908 feat(config): Add AtomizerSpec v2.0 schema and migrate all studies
Added JSON Schema:
- optimization_engine/schemas/atomizer_spec_v2.json

Migrated 28 studies to AtomizerSpec v2.0 format:
- Drone_Gimbal studies (1)
- M1_Mirror studies (21)
- M2_Mirror studies (2)
- SheetMetal_Bracket studies (4)

Each atomizer_spec.json is the unified configuration containing:
- Design variables with bounds and expressions
- Extractors (standard and custom)
- Objectives and constraints
- Optimization algorithm settings
- Canvas layout information
2026-01-20 13:11:23 -05:00
..

M1 Mirror Adaptive Surrogate Optimization V12

Adaptive neural-accelerated optimization of telescope primary mirror (M1) support structure using Zernike wavefront error decomposition with auto-tuned hyperparameters, ensemble surrogates, and mass constraints.

Created: 2024-12-04 Protocol: Protocol 12 (Adaptive Hybrid FEA/Neural with Hyperparameter Tuning) Status: Running Source Data: V11 (107 FEA samples)


1. Engineering Problem

1.1 Objective

Optimize the telescope primary mirror (M1) whiffle tree and lateral support structure to minimize wavefront error (WFE) across different gravity orientations while maintaining mass under 99 kg.

1.2 Physical System

Property Value
Component M1 primary mirror assembly with whiffle tree support
Material Borosilicate glass (mirror blank), steel (support structure)
Loading Gravity at multiple zenith angles (90°, 20°, 40°, 60°)
Boundary Conditions Whiffle tree kinematic mount with lateral supports
Analysis Type Linear static multi-subcase (Nastran SOL 101)
Subcases 4 orientations with different gravity vectors
Output Surface deformation → Zernike polynomial decomposition

1.3 Key Improvements in V12

Feature V11 V12
Hyperparameter Tuning Fixed architecture Optuna auto-tuning
Model Architecture Single network Ensemble of 3 models
Validation Train/test split K-fold cross-validation
Mass Constraint Post-hoc check Integrated penalty
Convergence Fixed iterations Early stopping with patience

2. Mathematical Formulation

2.1 Objectives

Objective Goal Weight Formula Units Target
rel_filtered_rms_40_vs_20 minimize 5.0 \sigma_{40/20} = \sqrt{\sum_{j=5}^{50} (Z_j^{40} - Z_j^{20})^2} nm 4 nm
rel_filtered_rms_60_vs_20 minimize 5.0 \sigma_{60/20} = \sqrt{\sum_{j=5}^{50} (Z_j^{60} - Z_j^{20})^2} nm 10 nm
mfg_90_optician_workload minimize 1.0 \sigma_{90}^{J4+} = \sqrt{\sum_{j=4}^{50} (Z_j^{90} - Z_j^{20})^2} nm 20 nm

Weighted Sum Objective:

J(\mathbf{x}) = \sum_{i=1}^{3} w_i \cdot \frac{f_i(\mathbf{x})}{t_i} + P_{mass}(\mathbf{x})

Where:

  • w_i = weight for objective i
  • f_i(\mathbf{x}) = objective value
  • t_i = target value (normalization)
  • P_{mass} = mass constraint penalty

2.2 Zernike Decomposition

The wavefront error W(r,\theta) is decomposed into Noll-indexed Zernike polynomials:

W(r,\theta) = \sum_{j=1}^{50} Z_j \cdot P_j(r,\theta)

WFE from Displacement (reflection factor of 2):

W_{nm} = 2 \cdot \delta_z \cdot 10^6

Where \delta_z is the Z-displacement in mm.

Filtered RMS (excluding alignable terms J1-J4):

\sigma_{filtered} = \sqrt{\sum_{j=5}^{50} Z_j^2}

Manufacturing RMS (excluding J1-J3, keeping defocus J4):

\sigma_{mfg} = \sqrt{\sum_{j=4}^{50} Z_j^2}

2.3 Design Variables (11 Parameters)

Parameter Symbol Bounds Baseline Units Description
lateral_inner_angle \alpha_{in} [25, 28.5] 26.79 deg Inner lateral support angle
lateral_outer_angle \alpha_{out} [13, 17] 14.64 deg Outer lateral support angle
lateral_outer_pivot p_{out} [9, 12] 10.40 mm Outer pivot offset
lateral_inner_pivot p_{in} [9, 12] 10.07 mm Inner pivot offset
lateral_middle_pivot p_{mid} [18, 23] 20.73 mm Middle pivot offset
lateral_closeness c_{lat} [9.5, 12.5] 11.02 mm Lateral support spacing
whiffle_min w_{min} [35, 55] 40.55 mm Whiffle tree minimum
whiffle_outer_to_vertical \theta_w [68, 80] 75.67 deg Outer whiffle angle
whiffle_triangle_closeness c_w [50, 65] 60.00 mm Whiffle triangle spacing
blank_backface_angle \beta [4.0, 5.0] 4.23 deg Mirror backface angle (mass driver)
inner_circular_rib_dia D_{rib} [480, 620] 534.00 mm Inner rib diameter

Design Space:

\mathbf{x} = [\alpha_{in}, \alpha_{out}, p_{out}, p_{in}, p_{mid}, c_{lat}, w_{min}, \theta_w, c_w, \beta, D_{rib}]^T \in \mathbb{R}^{11}

2.4 Mass Constraint

Constraint Type Formula Threshold Handling
mass_limit upper_bound m(\mathbf{x}) \leq m_{max} 99 kg Penalty in objective

Penalty Function: $$P_{mass}(\mathbf{x}) = \begin{cases} 0 & \text{if } m \leq 99 \ 100 \cdot (m - 99) & \text{if } m > 99 \end{cases}$$

Mass Estimation (from blank_backface_angle):

\hat{m}(\beta) = 105 - 15 \cdot (\beta - 4.0) \text{ kg}

3. Optimization Algorithm

3.1 Adaptive Hybrid Strategy

Parameter Value Description
Algorithm Adaptive Hybrid FEA + Neural Surrogate
Surrogate Tuned Ensemble (3 models) Auto-tuned architecture
Sampler TPE Tree-structured Parzen Estimator
Max Iterations 100 Adaptive loop iterations
FEA Batch Size 5 Real FEA evaluations per iteration
NN Trials 1000 Surrogate evaluations per iteration
Patience 5 Early stopping threshold
Convergence 0.3 nm Objective improvement threshold

3.2 Hyperparameter Tuning

Setting Value
Tuning Trials 30
Cross-Validation 5-fold
Search Space Hidden dims, dropout, learning rate
Ensemble Size 3 models
MC Dropout Samples 30

Tuned Architecture:

Input(11) → Linear(128) → ReLU → Dropout →
Linear(256) → ReLU → Dropout →
Linear(256) → ReLU → Dropout →
Linear(128) → ReLU → Dropout →
Linear(64) → ReLU → Linear(4)

3.3 Adaptive Loop Flow

┌─────────────────────────────────────────────────────────────────────────┐
│                      ADAPTIVE ITERATION k                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  1. SURROGATE EXPLORATION (1000 trials)                                 │
│     ├── Sample 11 design variables via TPE                              │
│     ├── Predict objectives with ensemble (mean + uncertainty)           │
│     └── Select top candidates (exploitation) + diverse (exploration)    │
│                                                                          │
│  2. FEA VALIDATION (5 trials)                                           │
│     ├── Run NX Nastran SOL 101 (4 subcases)                             │
│     ├── Extract Zernike coefficients from OP2                           │
│     ├── Compute relative filtered RMS                                    │
│     └── Store in Optuna database                                        │
│                                                                          │
│  3. SURROGATE RETRAINING                                                │
│     ├── Load all FEA data from database                                 │
│     ├── Retrain ensemble with new data                                  │
│     └── Update uncertainty estimates                                    │
│                                                                          │
│  4. CONVERGENCE CHECK                                                   │
│     ├── Δbest < 0.3 nm for patience=5 iterations?                       │
│     └── If converged → STOP, else → next iteration                      │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

4. Simulation Pipeline

4.1 FEA Trial Execution Flow

┌─────────────────────────────────────────────────────────────────────────┐
│                         FEA TRIAL n EXECUTION                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  1. CANDIDATE SELECTION                                                 │
│     Hybrid strategy: 70% exploitation (best NN predictions)             │
│                      30% exploration (uncertain regions)                │
│                                                                          │
│  2. NX PARAMETER UPDATE                                                 │
│     Module: optimization_engine/nx_solver.py                            │
│     Target Part: M1_Blank.prt (and related components)                  │
│     Action: Update 11 expressions with new design values                │
│                                                                          │
│  3. NX SIMULATION (Nastran SOL 101 - 4 Subcases)                        │
│     Module: optimization_engine/solve_simulation.py                     │
│     Input: ASSY_M1_assyfem1_sim1.sim                                    │
│     Subcases:                                                           │
│       1 = 90° zenith (polishing/manufacturing)                          │
│       2 = 20° zenith (reference)                                        │
│       3 = 40° zenith (operational target 1)                             │
│       4 = 60° zenith (operational target 2)                             │
│     Output: .dat, .op2, .f06                                            │
│                                                                          │
│  4. ZERNIKE EXTRACTION                                                  │
│     Module: optimization_engine/extractors/extract_zernike.py           │
│     a. Read node coordinates from BDF/DAT                               │
│     b. Read Z-displacements from OP2 for each subcase                   │
│     c. Compute RELATIVE displacement (target - reference)               │
│     d. Convert to WFE: W = 2 × Δδz × 10⁶ nm                             │
│     e. Fit 50 Zernike coefficients via least-squares                    │
│     f. Compute filtered RMS (exclude J1-J4)                             │
│                                                                          │
│  5. MASS EXTRACTION                                                     │
│     Module: optimization_engine/extractors/extract_mass_from_expression │
│     Expression: p173 (CAD mass property)                                │
│                                                                          │
│  6. OBJECTIVE COMPUTATION                                               │
│     rel_filtered_rms_40_vs_20 ← Zernike RMS (subcase 3 - 2)            │
│     rel_filtered_rms_60_vs_20 ← Zernike RMS (subcase 4 - 2)            │
│     mfg_90_optician_workload ← Zernike RMS J4+ (subcase 1 - 2)         │
│                                                                          │
│  7. WEIGHTED OBJECTIVE + MASS PENALTY                                   │
│     J = Σ (weight × objective / target) + mass_penalty                  │
│                                                                          │
│  8. STORE IN DATABASE                                                   │
│     Optuna SQLite: 3_results/study.db                                   │
│     User attrs: trial_source='fea', mass_kg, all Zernike coefficients   │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

4.2 Subcase Configuration

Subcase Zenith Angle Gravity Direction Role
1 90° Horizontal Manufacturing/polishing reference
2 20° Near-vertical Operational reference (baseline)
3 40° Mid-elevation Operational target 1
4 60° Low-elevation Operational target 2

5. Result Extraction Methods

5.1 Zernike WFE Extraction

Attribute Value
Extractor ZernikeExtractor
Module optimization_engine.extractors.extract_zernike
Method extract_relative()
Geometry Source .dat (BDF format, auto-detected)
Displacement Source .op2 (OP2 binary)
Output 50 Zernike coefficients + RMS metrics per subcase pair

Algorithm:

  1. Load node coordinates (X_i, Y_i) from BDF
  2. Load Z-displacements \delta_{z,i} from OP2 for each subcase
  3. Compute relative displacement (node-by-node): \Delta\delta_{z,i} = \delta_{z,i}^{target} - \delta_{z,i}^{reference}
  4. Convert to WFE: W_i = 2 \cdot \Delta\delta_{z,i} \cdot 10^6 \text{ nm}
  5. Fit Zernike coefficients via least-squares: \min_{\mathbf{Z}} \| \mathbf{W} - \mathbf{P} \mathbf{Z} \|^2
  6. Compute filtered RMS: \sigma_{filtered} = \sqrt{\sum_{j=5}^{50} Z_j^2}

Code:

from optimization_engine.extractors import ZernikeExtractor

extractor = ZernikeExtractor(op2_file, bdf_file)
result = extractor.extract_relative(
    target_subcase="3",      # 40 deg
    reference_subcase="2",   # 20 deg
    displacement_unit="mm"
)
filtered_rms = result['relative_filtered_rms_nm']  # nm

5.2 Mass Extraction

Attribute Value
Extractor extract_mass_from_expression
Module optimization_engine.extractors
Expression p173 (CAD mass property)
Output kg

Code:

from optimization_engine.extractors import extract_mass_from_expression

mass_kg = extract_mass_from_expression(model_file, expression_name="p173")

6. Neural Acceleration (Tuned Ensemble Surrogate)

6.1 Configuration

Setting Value Description
enabled true Neural surrogate active
model_type TunedEnsembleSurrogate Ensemble of tuned networks
ensemble_size 3 Number of models in ensemble
hidden_dims [128, 256, 256, 128, 64] Auto-tuned architecture
dropout 0.1 Regularization
learning_rate 0.001 Adam optimizer
batch_size 16 Mini-batch size
mc_dropout_samples 30 Monte Carlo uncertainty

6.2 Hyperparameter Tuning

Parameter Search Space
n_layers [3, 4, 5, 6]
hidden_dim [64, 128, 256, 512]
dropout [0.0, 0.1, 0.2, 0.3]
learning_rate [1e-4, 1e-3, 1e-2]
batch_size [8, 16, 32, 64]

Tuning Objective:

\mathcal{L}_{tune} = \frac{1}{K} \sum_{k=1}^{K} MSE_{val}^{(k)}

Using 5-fold cross-validation.

6.3 Surrogate Model

Input: \mathbf{x} = [11 \text{ design variables}]^T \in \mathbb{R}^{11}

Output: \hat{\mathbf{y}} = [4 \text{ objectives/constraints}]^T \in \mathbb{R}^{4}

  • rel_filtered_rms_40_vs_20 (nm)
  • rel_filtered_rms_60_vs_20 (nm)
  • mfg_90_optician_workload (nm)
  • mass_kg (kg)

Ensemble Prediction:

\hat{y} = \frac{1}{M} \sum_{m=1}^{M} f_m(\mathbf{x})

Uncertainty Quantification (MC Dropout):

\sigma_y^2 = \frac{1}{T} \sum_{t=1}^{T} f_{dropout}^{(t)}(\mathbf{x})^2 - \hat{y}^2

6.4 Training Data Location

m1_mirror_adaptive_V12/
├── 2_iterations/
│   ├── iter_001/           # Iteration 1 working files
│   ├── iter_002/
│   └── ...
├── 3_results/
│   ├── study.db            # Optuna database (all trials)
│   ├── optimization.log    # Detailed log
│   ├── surrogate_best.pt   # Best tuned model weights
│   └── tuning_results.json # Hyperparameter tuning history

6.5 Expected Performance

Metric Value
Source Data V11: 107 FEA samples
FEA time per trial 10-15 min
Neural time per trial ~5 ms
Speedup ~120,000x
Expected R² > 0.90 (after tuning)
Uncertainty Coverage ~95% (ensemble + MC dropout)

7. Study File Structure

m1_mirror_adaptive_V12/
│
├── 1_setup/                              # INPUT CONFIGURATION
│   ├── model/ → symlink to V11          # NX Model Files
│   │   ├── ASSY_M1.prt                   # Top-level assembly
│   │   ├── M1_Blank.prt                  # Mirror blank (expressions)
│   │   ├── ASSY_M1_assyfem1.afm          # Assembly FEM
│   │   ├── ASSY_M1_assyfem1_sim1.sim     # Simulation file
│   │   └── *-solution_1.op2              # Results (generated)
│   │
│   └── optimization_config.json          # Study configuration
│
├── 2_iterations/                         # WORKING DIRECTORY
│   ├── iter_001/                         # Iteration 1 model copy
│   ├── iter_002/
│   └── ...
│
├── 3_results/                            # OUTPUT (auto-generated)
│   ├── study.db                          # Optuna SQLite database
│   ├── optimization.log                  # Structured log
│   ├── surrogate_best.pt                 # Trained ensemble weights
│   ├── tuning_results.json               # Hyperparameter tuning
│   └── convergence.json                  # Iteration history
│
├── run_optimization.py                   # Main entry point
├── final_validation.py                   # FEA validation of best NN trials
├── README.md                             # This blueprint
└── STUDY_REPORT.md                       # Results report (updated during run)

8. Results Location

After optimization, results are stored in 3_results/:

File Description Format
study.db Optuna database with all trials (FEA + NN) SQLite
optimization.log Detailed execution log Text
surrogate_best.pt Tuned ensemble model weights PyTorch
tuning_results.json Hyperparameter search history JSON
convergence.json Best value per iteration JSON

8.1 Trial Identification

Trials are tagged with source:

  • FEA trials: trial.user_attrs['trial_source'] = 'fea'
  • NN trials: trial.user_attrs['trial_source'] = 'nn'

Dashboard Visualization:

  • FEA trials: Blue circles
  • NN trials: Orange crosses

8.2 Results Report

See STUDY_REPORT.md for:

  • Optimization progress and convergence
  • Best designs found (FEA-validated)
  • Surrogate model accuracy (R², MAE)
  • Pareto trade-off analysis
  • Engineering recommendations

9. Quick Start

Launch Optimization

cd studies/m1_mirror_adaptive_V12

# Start with default settings (uses V11 FEA data)
python run_optimization.py --start

# Custom tuning parameters
python run_optimization.py --start --tune-trials 30 --ensemble-size 3 --fea-batch 5 --patience 5

# Tune hyperparameters only (no FEA)
python run_optimization.py --tune-only

Command Line Options

Option Default Description
--start - Start adaptive optimization
--tune-only - Only tune hyperparameters, no optimization
--tune-trials 30 Number of hyperparameter tuning trials
--ensemble-size 3 Number of models in ensemble
--fea-batch 5 FEA evaluations per iteration
--patience 5 Early stopping patience

Monitor Progress

# View log
tail -f 3_results/optimization.log

# Check database
sqlite3 3_results/study.db "SELECT COUNT(*) FROM trials WHERE state='COMPLETE'"

# Launch Optuna dashboard
optuna-dashboard sqlite:///3_results/study.db --port 8081

Dashboard Access

Dashboard URL Purpose
Atomizer Dashboard http://localhost:3000 Real-time monitoring
Optuna Dashboard http://localhost:8081 Trial history

10. Configuration Reference

File: 1_setup/optimization_config.json

Section Key Description
design_variables[] 11 parameters All lateral/whiffle/blank params
objectives[] 3 WFE metrics Relative filtered RMS
constraints[] mass_limit Upper bound 99 kg
zernike_settings.n_modes 50 Zernike polynomial count
zernike_settings.filter_low_orders 4 Exclude J1-J4
zernike_settings.subcases [1,2,3,4] Zenith angles
adaptive_settings.max_iterations 100 Loop limit
adaptive_settings.surrogate_trials_per_iter 1000 NN trials
adaptive_settings.fea_batch_size 5 FEA per iteration
adaptive_settings.patience 5 Early stopping
surrogate_settings.ensemble_size 3 Model ensemble
surrogate_settings.mc_dropout_samples 30 Uncertainty samples

11. References

  • Deb, K. et al. (2002). A fast and elitist multiobjective genetic algorithm: NSGA-II. IEEE TEC.
  • Noll, R.J. (1976). Zernike polynomials and atmospheric turbulence. JOSA.
  • Wilson, R.N. (2004). Reflecting Telescope Optics I. Springer.
  • Snoek, J. et al. (2012). Practical Bayesian optimization of machine learning algorithms. NeurIPS.
  • Gal, Y. & Ghahramani, Z. (2016). Dropout as a Bayesian approximation. ICML.
  • pyNastran Documentation: BDF/OP2 parsing for FEA post-processing.
  • Optuna Documentation: Hyperparameter optimization framework.

Atomizer V12: Where adaptive AI meets precision optics.