Files
Atomizer/docs/handoff/SETUP_TRAJECTORY_OPTIMIZATION.md

5.4 KiB

Handoff: Set Up Trajectory-Based Optimization for M1 Mirror

From: Mario (Clawdbot)
To: Claude (Windows/LAC)
Date: 2026-01-29
Context: M1 GigaBIT mirror optimization using new Zernike Trajectory Method


Summary

A new Zernike Trajectory extractor has been implemented and validated. It provides mode-specific optimization metrics (coma, astigmatism, trefoil, etc.) integrated across the full 20°-60° operating range instead of discrete weighted sums.

Your task: Set up an Atomizer optimization study using TPE optimizer with total_filtered_rms_nm as the primary objective, logging mode-specific metrics.


What's Already Done

  1. Extractor implemented: optimization_engine/extractors/extract_zernike_trajectory.py
  2. Validated on M1 model: R² = 1.0 (physics model confirmed)
  3. Documentation: docs/physics/ZERNIKE_TRAJECTORY_METHOD.md
  4. Example config: docs/examples/trajectory_optimization_config.yaml

Pull latest from Gitea:

git pull origin main

What You Need to Set Up

1. Create New Study: SAT3_Trajectory

Location: studies/SAT3_Trajectory/ (or similar)

2. FEA Configuration

The FEA must solve 6 subcases with these elevation angles:

  • 90° (manufacturing reference)
  • 20° (measurement/polishing reference)
  • 30° (new - for trajectory)
  • 40° (primary operational)
  • 50° (new - for trajectory)
  • 60° (secondary operational)

Subcase labels in NX must be the angle numbers (e.g., LABEL = 20, LABEL = 40, etc.)

3. Extractor Configuration

Use the trajectory extractor:

extractors:
  - id: ext_trajectory
    name: "Zernike Trajectory"
    type: zernike_trajectory
    config:
      reference_angle: 20.0
      # Subcases auto-detected from OP2 labels

4. Objectives

Primary objective (what optimizer minimizes):

objectives:
  - id: obj_total
    name: "Total Integrated RMS"
    source:
      extractor_id: ext_trajectory
      output_name: total_filtered_rms_nm
    direction: minimize
    weight: 1.0

Secondary objectives (logged but not optimized, weight=0):

  - id: obj_coma
    name: "Coma RMS"
    source:
      extractor_id: ext_trajectory
      output_name: coma_rms_nm
    direction: minimize
    weight: 0.0

  - id: obj_astig
    name: "Astigmatism RMS"
    source:
      extractor_id: ext_trajectory
      output_name: astigmatism_rms_nm
    direction: minimize
    weight: 0.0

  - id: obj_trefoil
    name: "Trefoil RMS"
    source:
      extractor_id: ext_trajectory
      output_name: trefoil_rms_nm
    direction: minimize
    weight: 0.0

  - id: obj_spherical
    name: "Spherical RMS"
    source:
      extractor_id: ext_trajectory
      output_name: spherical_rms_nm
    direction: minimize
    weight: 0.0

5. Optimizer Configuration

Use TPE (recommended for fresh start):

optimizer:
  type: tpe
  config:
    n_trials: 100
    n_startup_trials: 15
constraints:
  # Sanity check: linear model should fit well
  - id: con_r2
    name: "Trajectory fit quality"
    source:
      extractor_id: ext_trajectory
      output_name: linear_fit_r2
    type: soft
    operator: ">="
    threshold: 0.95

7. Design Variables

Use Antoine's existing wiffle tree and geometry parameters. Key ones likely include:

  • Wiffle tree radial positions (R1, R2, R3)
  • Wiffle tree angular offsets
  • Rib thickness
  • Back pocket geometry
  • Support pad locations

Ask Antoine for the current parameter names and ranges.


Validation Checklist

Before running optimization, verify:

  • FEA solves all 6 subcases (90, 20, 30, 40, 50, 60)
  • OP2 contains displacement results for all subcases
  • Subcase labels in OP2 are angle numbers (check with extractor)
  • Extractor returns valid results (run standalone test first)
  • R² ≈ 1.0 (confirms physics model holds)

Test command:

from optimization_engine.extractors.extract_zernike_trajectory import extract_zernike_trajectory

result = extract_zernike_trajectory('path/to/solution.op2')
print(f"R² = {result['linear_fit_r2']}")
print(f"Total RMS = {result['total_filtered_rms_nm']} nm")
print(f"Coma RMS = {result['coma_rms_nm']} nm")

Expected Outputs

After running the extractor, you should see:

  • total_filtered_rms_nm: ~4-10 nm (integrated across angles)
  • coma_rms_nm: ~3-10 nm
  • astigmatism_rms_nm: ~3-10 nm
  • linear_fit_r2: ~1.0

During optimization, track:

  • How total_filtered_rms_nm decreases
  • Which modes (coma, astig, etc.) improve most
  • Whether R² stays high (if it drops, something is wrong)

Key Files to Reference

File Purpose
docs/physics/ZERNIKE_TRAJECTORY_METHOD.md Full method documentation
docs/examples/trajectory_optimization_config.yaml Example config
optimization_engine/extractors/extract_zernike_trajectory.py Extractor code
2-Projects/P04-GigaBIT-M1/Technical-Analysis/Tensor_Project/TECH-SPEC-Zernike-Trajectory-Optimization.md Physics derivation + validation results

Questions?

If anything is unclear, the tech spec in PKM has the full physics derivation and validation results. The extractor auto-detects angles from OP2 subcase labels, so as long as the FEA is set up correctly, it should "just work."

Good luck! 🚀


Handoff document by Mario (Clawdbot), 2026-01-29