feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
"""
Optimization API endpoints
Handles study status , history retrieval , and control operations
"""
2025-11-24 09:12:36 -05:00
from fastapi import APIRouter , HTTPException , UploadFile , File , Form
from fastapi . responses import JSONResponse , FileResponse
2025-12-04 15:02:13 -05:00
from pydantic import BaseModel
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
from pathlib import Path
from typing import List , Dict , Optional
import json
import sys
import sqlite3
2025-11-24 09:12:36 -05:00
import shutil
2025-12-04 15:02:13 -05:00
import subprocess
import psutil
import signal
2025-11-24 09:12:36 -05:00
from datetime import datetime
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
# Add project root to path
sys . path . append ( str ( Path ( __file__ ) . parent . parent . parent . parent . parent ) )
router = APIRouter ( )
# Base studies directory
STUDIES_DIR = Path ( __file__ ) . parent . parent . parent . parent . parent / " studies "
2025-12-02 22:01:49 -05:00
def get_results_dir ( study_dir : Path ) - > Path :
""" Get the results directory for a study, supporting both 2_results and 3_results. """
results_dir = study_dir / " 2_results "
if not results_dir . exists ( ) :
results_dir = study_dir / " 3_results "
return results_dir
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
def resolve_study_path ( study_id : str ) - > Path :
""" Find study folder by scanning all topic directories.
Supports nested folder structure : studies / Topic / study_name /
Study ID is the short name ( e . g . , ' m1_mirror_adaptive_V14 ' )
Returns the full path to the study directory .
Raises HTTPException 404 if not found .
"""
# First check direct path (backwards compatibility for flat structure)
direct_path = STUDIES_DIR / study_id
if direct_path . exists ( ) and direct_path . is_dir ( ) :
# Verify it's actually a study (has 1_setup or config)
if ( direct_path / " 1_setup " ) . exists ( ) or ( direct_path / " optimization_config.json " ) . exists ( ) :
return direct_path
# Scan topic folders for nested structure
for topic_dir in STUDIES_DIR . iterdir ( ) :
if topic_dir . is_dir ( ) and not topic_dir . name . startswith ( ' . ' ) :
study_dir = topic_dir / study_id
if study_dir . exists ( ) and study_dir . is_dir ( ) :
# Verify it's actually a study
if ( study_dir / " 1_setup " ) . exists ( ) or ( study_dir / " optimization_config.json " ) . exists ( ) :
return study_dir
raise HTTPException ( status_code = 404 , detail = f " Study not found: { study_id } " )
def get_study_topic ( study_dir : Path ) - > Optional [ str ] :
""" Get the topic folder name for a study, or None if in root. """
# Check if parent is a topic folder (not the root studies dir)
parent = study_dir . parent
if parent != STUDIES_DIR and parent . parent == STUDIES_DIR :
return parent . name
return None
2025-12-05 12:56:34 -05:00
def is_optimization_running ( study_id : str ) - > bool :
""" Check if an optimization process is currently running for a study.
Looks for Python processes running run_optimization . py with the study_id in the command line .
"""
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
try :
study_dir = resolve_study_path ( study_id )
except HTTPException :
return False
2025-12-05 12:56:34 -05:00
for proc in psutil . process_iter ( [ ' pid ' , ' name ' , ' cmdline ' , ' cwd ' ] ) :
try :
cmdline = proc . info . get ( ' cmdline ' ) or [ ]
cmdline_str = ' ' . join ( cmdline ) if cmdline else ' '
# Check if this is a Python process running run_optimization.py for this study
if ' python ' in cmdline_str . lower ( ) and ' run_optimization ' in cmdline_str :
if study_id in cmdline_str or str ( study_dir ) in cmdline_str :
return True
except ( psutil . NoSuchProcess , psutil . AccessDenied ) :
continue
return False
def get_accurate_study_status ( study_id : str , trial_count : int , total_trials : int , has_db : bool ) - > str :
""" Determine accurate study status based on multiple factors.
Status can be :
- not_started : No database or 0 trials
- running : Active process found
- paused : Has trials but no active process and not completed
- completed : Reached trial target
- failed : Has error indicators ( future enhancement )
Args :
study_id : The study identifier
trial_count : Number of completed trials
total_trials : Target number of trials from config
has_db : Whether the study database exists
Returns :
Status string : " not_started " , " running " , " paused " , or " completed "
"""
# No database or no trials = not started
if not has_db or trial_count == 0 :
return " not_started "
# Check if we've reached the target
if trial_count > = total_trials :
return " completed "
# Check if process is actively running
if is_optimization_running ( study_id ) :
return " running "
# Has trials but not running and not complete = paused
return " paused "
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
def _load_study_info ( study_dir : Path , topic : Optional [ str ] = None ) - > Optional [ dict ] :
""" Load study info from a study directory. Returns None if not a valid study. """
# Look for optimization config (check multiple locations)
config_file = study_dir / " optimization_config.json "
if not config_file . exists ( ) :
config_file = study_dir / " 1_setup " / " optimization_config.json "
if not config_file . exists ( ) :
return None
# Load config
with open ( config_file ) as f :
config = json . load ( f )
# Check if results directory exists (support both 2_results and 3_results)
results_dir = study_dir / " 2_results "
if not results_dir . exists ( ) :
results_dir = study_dir / " 3_results "
# Check for Optuna database (Protocol 10) or JSON history (other protocols)
study_db = results_dir / " study.db "
history_file = results_dir / " optimization_history_incremental.json "
trial_count = 0
best_value = None
has_db = False
# Protocol 10: Read from Optuna SQLite database
if study_db . exists ( ) :
has_db = True
try :
# Use timeout to avoid blocking on locked databases
conn = sqlite3 . connect ( str ( study_db ) , timeout = 2.0 )
cursor = conn . cursor ( )
# Get trial count and status
cursor . execute ( " SELECT COUNT(*) FROM trials WHERE state = ' COMPLETE ' " )
trial_count = cursor . fetchone ( ) [ 0 ]
# Get best trial (for single-objective, or first objective for multi-objective)
if trial_count > 0 :
cursor . execute ( """
SELECT value FROM trial_values
WHERE trial_id IN (
SELECT trial_id FROM trials WHERE state = ' COMPLETE '
)
ORDER BY value ASC
LIMIT 1
""" )
result = cursor . fetchone ( )
if result :
best_value = result [ 0 ]
conn . close ( )
except Exception as e :
print ( f " Warning: Failed to read Optuna database for { study_dir . name } : { e } " )
# Legacy: Read from JSON history
elif history_file . exists ( ) :
has_db = True
with open ( history_file ) as f :
history = json . load ( f )
trial_count = len ( history )
if history :
# Find best trial
best_trial = min ( history , key = lambda x : x [ ' objective ' ] )
best_value = best_trial [ ' objective ' ]
# Get total trials from config (supports both formats)
total_trials = (
config . get ( ' optimization_settings ' , { } ) . get ( ' n_trials ' ) or
config . get ( ' optimization ' , { } ) . get ( ' n_trials ' ) or
config . get ( ' trials ' , { } ) . get ( ' n_trials ' , 50 )
)
# Get accurate status using process detection
status = get_accurate_study_status ( study_dir . name , trial_count , total_trials , has_db )
# Get creation date from directory or config modification time
created_at = None
try :
# First try to get from database (most accurate)
if study_db . exists ( ) :
created_at = datetime . fromtimestamp ( study_db . stat ( ) . st_mtime ) . isoformat ( )
elif config_file . exists ( ) :
created_at = datetime . fromtimestamp ( config_file . stat ( ) . st_mtime ) . isoformat ( )
else :
created_at = datetime . fromtimestamp ( study_dir . stat ( ) . st_ctime ) . isoformat ( )
except :
created_at = None
# Get last modified time
last_modified = None
try :
if study_db . exists ( ) :
last_modified = datetime . fromtimestamp ( study_db . stat ( ) . st_mtime ) . isoformat ( )
elif history_file . exists ( ) :
last_modified = datetime . fromtimestamp ( history_file . stat ( ) . st_mtime ) . isoformat ( )
except :
last_modified = None
return {
" id " : study_dir . name ,
" name " : study_dir . name . replace ( " _ " , " " ) . title ( ) ,
" topic " : topic , # NEW: topic field for grouping
" status " : status ,
" progress " : {
" current " : trial_count ,
" total " : total_trials
} ,
" best_value " : best_value ,
" target " : config . get ( ' target ' , { } ) . get ( ' value ' ) ,
" path " : str ( study_dir ) ,
" created_at " : created_at ,
" last_modified " : last_modified
}
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
@router.get ( " /studies " )
async def list_studies ( ) :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
""" List all available optimization studies.
Supports both flat and nested folder structures :
- Flat : studies / study_name /
- Nested : studies / Topic / study_name /
Returns studies with ' topic ' field for frontend grouping .
"""
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
try :
studies = [ ]
if not STUDIES_DIR . exists ( ) :
return { " studies " : [ ] }
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
for item in STUDIES_DIR . iterdir ( ) :
if not item . is_dir ( ) :
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
continue
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
if item . name . startswith ( ' . ' ) :
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
continue
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
# Check if this is a study (flat structure) or a topic folder (nested structure)
is_study = ( item / " 1_setup " ) . exists ( ) or ( item / " optimization_config.json " ) . exists ( )
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
if is_study :
# Flat structure: study directly in studies/
study_info = _load_study_info ( item , topic = None )
if study_info :
studies . append ( study_info )
else :
# Nested structure: this might be a topic folder
# Check if it contains study subdirectories
for sub_item in item . iterdir ( ) :
if not sub_item . is_dir ( ) :
continue
if sub_item . name . startswith ( ' . ' ) :
continue
2025-12-04 17:36:00 -05:00
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
# Check if this subdirectory is a study
sub_is_study = ( sub_item / " 1_setup " ) . exists ( ) or ( sub_item / " optimization_config.json " ) . exists ( )
if sub_is_study :
study_info = _load_study_info ( sub_item , topic = item . name )
if study_info :
studies . append ( study_info )
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
return { " studies " : studies }
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to list studies: { str ( e ) } " )
@router.get ( " /studies/ {study_id} /status " )
async def get_study_status ( study_id : str ) :
""" Get detailed status of a specific study """
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Load config (check multiple locations)
config_file = study_dir / " optimization_config.json "
if not config_file . exists ( ) :
config_file = study_dir / " 1_setup " / " optimization_config.json "
with open ( config_file ) as f :
config = json . load ( f )
2025-12-02 22:01:49 -05:00
# Check for results (support both 2_results and 3_results)
results_dir = get_results_dir ( study_dir )
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
study_db = results_dir / " study.db "
history_file = results_dir / " optimization_history_incremental.json "
# Protocol 10: Read from Optuna database
if study_db . exists ( ) :
conn = sqlite3 . connect ( str ( study_db ) )
cursor = conn . cursor ( )
# Get trial counts by state
cursor . execute ( " SELECT COUNT(*) FROM trials WHERE state = ' COMPLETE ' " )
trial_count = cursor . fetchone ( ) [ 0 ]
cursor . execute ( " SELECT COUNT(*) FROM trials WHERE state = ' PRUNED ' " )
pruned_count = cursor . fetchone ( ) [ 0 ]
# Get best trial (first objective for multi-objective)
best_trial = None
if trial_count > 0 :
cursor . execute ( """
SELECT t . trial_id , t . number , tv . value
FROM trials t
JOIN trial_values tv ON t . trial_id = tv . trial_id
WHERE t . state = ' COMPLETE '
ORDER BY tv . value ASC
LIMIT 1
""" )
result = cursor . fetchone ( )
if result :
trial_id , trial_number , best_value = result
# Get parameters for this trial
cursor . execute ( """
SELECT param_name , param_value
FROM trial_params
WHERE trial_id = ?
""" , (trial_id,))
params = { row [ 0 ] : row [ 1 ] for row in cursor . fetchall ( ) }
best_trial = {
" trial_number " : trial_number ,
" objective " : best_value ,
" design_variables " : params ,
" results " : { " first_frequency " : best_value }
}
conn . close ( )
total_trials = config . get ( ' optimization_settings ' , { } ) . get ( ' n_trials ' , 50 )
2025-12-05 12:56:34 -05:00
status = get_accurate_study_status ( study_id , trial_count , total_trials , True )
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
return {
" study_id " : study_id ,
" status " : status ,
" progress " : {
" current " : trial_count ,
" total " : total_trials ,
" percentage " : ( trial_count / total_trials * 100 ) if total_trials > 0 else 0
} ,
" best_trial " : best_trial ,
" pruned_trials " : pruned_count ,
" config " : config
}
# Legacy: Read from JSON history
if not history_file . exists ( ) :
return {
" study_id " : study_id ,
" status " : " not_started " ,
" progress " : { " current " : 0 , " total " : config . get ( ' trials ' , { } ) . get ( ' n_trials ' , 50 ) } ,
" config " : config
}
with open ( history_file ) as f :
history = json . load ( f )
trial_count = len ( history )
total_trials = config . get ( ' trials ' , { } ) . get ( ' n_trials ' , 50 )
# Find best trial
best_trial = None
if history :
best_trial = min ( history , key = lambda x : x [ ' objective ' ] )
# Check for pruning data
pruning_file = results_dir / " pruning_history.json "
pruned_count = 0
if pruning_file . exists ( ) :
with open ( pruning_file ) as f :
pruning_history = json . load ( f )
pruned_count = len ( pruning_history )
status = " completed " if trial_count > = total_trials else " running "
return {
" study_id " : study_id ,
" status " : status ,
" progress " : {
" current " : trial_count ,
" total " : total_trials ,
" percentage " : ( trial_count / total_trials * 100 ) if total_trials > 0 else 0
} ,
" best_trial " : best_trial ,
" pruned_trials " : pruned_count ,
" config " : config
}
except FileNotFoundError :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to get study status: { str ( e ) } " )
@router.get ( " /studies/ {study_id} /history " )
async def get_optimization_history ( study_id : str , limit : Optional [ int ] = None ) :
""" Get optimization history (all trials) """
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-02 22:01:49 -05:00
results_dir = get_results_dir ( study_dir )
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
study_db = results_dir / " study.db "
history_file = results_dir / " optimization_history_incremental.json "
# Protocol 10: Read from Optuna database
if study_db . exists ( ) :
conn = sqlite3 . connect ( str ( study_db ) )
cursor = conn . cursor ( )
2025-12-04 07:41:54 -05:00
# Get all completed trials FROM ALL STUDIES in the database
# This handles adaptive optimizations that create multiple Optuna studies
# (e.g., v11_fea for FEA trials, v11_iter1_nn for NN trials, etc.)
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
cursor . execute ( """
2025-12-04 07:41:54 -05:00
SELECT t . trial_id , t . number , t . datetime_start , t . datetime_complete , s . study_name
FROM trials t
JOIN studies s ON t . study_id = s . study_id
WHERE t . state = ' COMPLETE '
ORDER BY t . datetime_start DESC
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
""" + (f " LIMIT {limit} " if limit else " " ))
trial_rows = cursor . fetchall ( )
trials = [ ]
2025-12-04 07:41:54 -05:00
for trial_id , trial_num , start_time , end_time , study_name in trial_rows :
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
# Get objectives for this trial
cursor . execute ( """
SELECT value
FROM trial_values
WHERE trial_id = ?
ORDER BY objective
""" , (trial_id,))
values = [ row [ 0 ] for row in cursor . fetchall ( ) ]
# Get parameters for this trial
cursor . execute ( """
SELECT param_name , param_value
FROM trial_params
WHERE trial_id = ?
""" , (trial_id,))
params = { }
for param_name , param_value in cursor . fetchall ( ) :
try :
params [ param_name ] = float ( param_value ) if param_value is not None else None
except ( ValueError , TypeError ) :
params [ param_name ] = param_value
2025-11-24 09:12:36 -05:00
# Get user attributes (extracted results: mass, frequency, stress, displacement, etc.)
cursor . execute ( """
SELECT key , value_json
FROM trial_user_attributes
WHERE trial_id = ?
""" , (trial_id,))
user_attrs = { }
for key , value_json in cursor . fetchall ( ) :
try :
user_attrs [ key ] = json . loads ( value_json )
except ( ValueError , TypeError ) :
user_attrs [ key ] = value_json
2025-12-02 22:01:49 -05:00
# Extract ALL numeric metrics from user_attrs for results
# This ensures multi-objective studies show all Zernike metrics, RMS values, etc.
2025-11-24 09:12:36 -05:00
results = { }
2025-12-02 22:01:49 -05:00
excluded_keys = { " design_vars " , " constraint_satisfied " , " constraint_violations " }
for key , val in user_attrs . items ( ) :
if key in excluded_keys :
continue
# Include numeric values and lists of numbers
if isinstance ( val , ( int , float ) ) :
results [ key ] = val
elif isinstance ( val , list ) and len ( val ) > 0 and isinstance ( val [ 0 ] , ( int , float ) ) :
# For lists, store as-is (e.g., Zernike coefficients)
results [ key ] = val
elif key == " objectives " and isinstance ( val , dict ) :
# Extract nested objectives dict (Zernike multi-objective studies)
for obj_key , obj_val in val . items ( ) :
if isinstance ( obj_val , ( int , float ) ) :
results [ obj_key ] = obj_val
2025-11-24 09:12:36 -05:00
# Fallback to first frequency from objectives if available
if not results and len ( values ) > 0 :
results [ " first_frequency " ] = values [ 0 ]
feat: Major update with validators, skills, dashboard, and docs reorganization
- Add validation framework (config, model, results, study validators)
- Add Claude Code skills (create-study, run-optimization, generate-report,
troubleshoot, analyze-model)
- Add Atomizer Dashboard (React frontend + FastAPI backend)
- Reorganize docs into structured directories (00-09)
- Add neural surrogate modules and training infrastructure
- Add multi-objective optimization support
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 19:23:58 -05:00
# CRITICAL: Extract design_vars from user_attrs if stored there
# The optimization code does: trial.set_user_attr("design_vars", design_vars)
design_vars_from_attrs = user_attrs . get ( " design_vars " , { } )
# Merge with params (prefer user_attrs design_vars if available)
final_design_vars = { * * params , * * design_vars_from_attrs } if design_vars_from_attrs else params
2025-12-04 07:41:54 -05:00
# Extract source for FEA vs NN differentiation
source = user_attrs . get ( " source " , " FEA " ) # Default to FEA for legacy studies
2025-12-10 21:34:07 -05:00
# Get iter_num from user_attrs if available (this is the actual iteration folder number)
iter_num = user_attrs . get ( " iter_num " , None )
# Use iter_num if available, otherwise use trial_id as unique identifier
# trial_id is unique across all studies in the database
unique_trial_num = iter_num if iter_num is not None else trial_id
2025-12-04 07:41:54 -05:00
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
trials . append ( {
2025-12-04 07:41:54 -05:00
" trial_number " : unique_trial_num ,
2025-12-10 21:34:07 -05:00
" trial_id " : trial_id , # Keep original for debugging
" optuna_trial_num " : trial_num , # Keep original Optuna trial number
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
" objective " : values [ 0 ] if len ( values ) > 0 else None , # Primary objective
" objectives " : values if len ( values ) > 1 else None , # All objectives for multi-objective
feat: Major update with validators, skills, dashboard, and docs reorganization
- Add validation framework (config, model, results, study validators)
- Add Claude Code skills (create-study, run-optimization, generate-report,
troubleshoot, analyze-model)
- Add Atomizer Dashboard (React frontend + FastAPI backend)
- Reorganize docs into structured directories (00-09)
- Add neural surrogate modules and training infrastructure
- Add multi-objective optimization support
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 19:23:58 -05:00
" design_variables " : final_design_vars , # Use merged design vars
2025-11-24 09:12:36 -05:00
" results " : results ,
" user_attrs " : user_attrs , # Include all user attributes
2025-12-04 07:41:54 -05:00
" source " : source , # FEA or NN
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
" start_time " : start_time ,
2025-12-04 07:41:54 -05:00
" end_time " : end_time ,
" study_name " : study_name # Include for debugging
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
} )
conn . close ( )
return { " trials " : trials }
# Legacy: Read from JSON history
if not history_file . exists ( ) :
return { " trials " : [ ] }
with open ( history_file ) as f :
history = json . load ( f )
# Apply limit if specified
if limit :
history = history [ - limit : ]
return { " trials " : history }
except FileNotFoundError :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to get history: { str ( e ) } " )
@router.get ( " /studies/ {study_id} /pruning " )
async def get_pruning_history ( study_id : str ) :
2025-12-02 22:01:49 -05:00
""" Get pruning diagnostics from Optuna database or legacy JSON file """
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-02 22:01:49 -05:00
results_dir = get_results_dir ( study_dir )
study_db = results_dir / " study.db "
pruning_file = results_dir / " pruning_history.json "
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
2025-12-02 22:01:49 -05:00
# Protocol 10+: Read from Optuna database
if study_db . exists ( ) :
conn = sqlite3 . connect ( str ( study_db ) )
cursor = conn . cursor ( )
# Get all pruned trials from Optuna database
cursor . execute ( """
SELECT t . trial_id , t . number , t . datetime_start , t . datetime_complete
FROM trials t
WHERE t . state = ' PRUNED '
ORDER BY t . number DESC
""" )
pruned_rows = cursor . fetchall ( )
pruned_trials = [ ]
for trial_id , trial_num , start_time , end_time in pruned_rows :
# Get parameters for this trial
cursor . execute ( """
SELECT param_name , param_value
FROM trial_params
WHERE trial_id = ?
""" , (trial_id,))
params = { row [ 0 ] : row [ 1 ] for row in cursor . fetchall ( ) }
# Get user attributes (may contain pruning cause)
cursor . execute ( """
SELECT key , value_json
FROM trial_user_attributes
WHERE trial_id = ?
""" , (trial_id,))
user_attrs = { }
for key , value_json in cursor . fetchall ( ) :
try :
user_attrs [ key ] = json . loads ( value_json )
except ( ValueError , TypeError ) :
user_attrs [ key ] = value_json
pruned_trials . append ( {
" trial_number " : trial_num ,
" params " : params ,
" pruning_cause " : user_attrs . get ( " pruning_cause " , " Unknown " ) ,
" start_time " : start_time ,
" end_time " : end_time
} )
conn . close ( )
return { " pruned_trials " : pruned_trials , " count " : len ( pruned_trials ) }
# Legacy: Read from JSON history
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
if not pruning_file . exists ( ) :
2025-12-02 22:01:49 -05:00
return { " pruned_trials " : [ ] , " count " : 0 }
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
with open ( pruning_file ) as f :
pruning_history = json . load ( f )
2025-12-02 22:01:49 -05:00
return { " pruned_trials " : pruning_history , " count " : len ( pruning_history ) }
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
except FileNotFoundError :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to get pruning history: { str ( e ) } " )
def _infer_objective_unit ( objective : Dict ) - > str :
""" Infer unit from objective name and description """
name = objective . get ( " name " , " " ) . lower ( )
desc = objective . get ( " description " , " " ) . lower ( )
# Common unit patterns
if " frequency " in name or " hz " in desc :
return " Hz "
elif " stiffness " in name or " n/mm " in desc :
return " N/mm "
elif " mass " in name or " kg " in desc :
return " kg "
elif " stress " in name or " mpa " in desc or " pa " in desc :
return " MPa "
elif " displacement " in name or " mm " in desc :
return " mm "
elif " force " in name or " newton " in desc :
return " N "
elif " % " in desc or " percent " in desc :
return " % "
# Check if unit is explicitly mentioned in description (e.g., "(N/mm)")
import re
unit_match = re . search ( r ' \ (([^)]+) \ ) ' , desc )
if unit_match :
return unit_match . group ( 1 )
return " " # No unit found
@router.get ( " /studies/ {study_id} /metadata " )
async def get_study_metadata ( study_id : str ) :
""" Read optimization_config.json for objectives, design vars, units (Protocol 13) """
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Load config (check multiple locations)
config_file = study_dir / " optimization_config.json "
if not config_file . exists ( ) :
config_file = study_dir / " 1_setup " / " optimization_config.json "
if not config_file . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Config file not found for study { study_id } " )
with open ( config_file ) as f :
config = json . load ( f )
# Enhance objectives with inferred units if not present
objectives = config . get ( " objectives " , [ ] )
for obj in objectives :
if " unit " not in obj or not obj [ " unit " ] :
obj [ " unit " ] = _infer_objective_unit ( obj )
2025-12-22 21:28:16 -05:00
# Get sampler/algorithm info
optimization = config . get ( " optimization " , { } )
algorithm = optimization . get ( " algorithm " , " TPE " )
# Map algorithm names to Optuna sampler names for frontend display
sampler_map = {
" CMA-ES " : " CmaEsSampler " ,
" cma-es " : " CmaEsSampler " ,
" cmaes " : " CmaEsSampler " ,
" TPE " : " TPESampler " ,
" tpe " : " TPESampler " ,
" NSGA-II " : " NSGAIISampler " ,
" nsga-ii " : " NSGAIISampler " ,
" NSGA-III " : " NSGAIIISampler " ,
" Random " : " RandomSampler " ,
}
sampler = sampler_map . get ( algorithm , algorithm )
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
return {
" objectives " : objectives ,
" design_variables " : config . get ( " design_variables " , [ ] ) ,
" constraints " : config . get ( " constraints " , [ ] ) ,
" study_name " : config . get ( " study_name " , study_id ) ,
2025-12-22 21:28:16 -05:00
" description " : config . get ( " description " , " " ) ,
" sampler " : sampler ,
" algorithm " : algorithm ,
" n_trials " : optimization . get ( " n_trials " , 100 )
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
}
except FileNotFoundError :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to get study metadata: { str ( e ) } " )
@router.get ( " /studies/ {study_id} /optimizer-state " )
async def get_optimizer_state ( study_id : str ) :
""" Read realtime optimizer state from intelligent_optimizer/ (Protocol 13) """
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-02 22:01:49 -05:00
results_dir = get_results_dir ( study_dir )
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
state_file = results_dir / " intelligent_optimizer " / " optimizer_state.json "
if not state_file . exists ( ) :
return { " available " : False }
with open ( state_file ) as f :
state = json . load ( f )
return { " available " : True , * * state }
except FileNotFoundError :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to get optimizer state: { str ( e ) } " )
@router.get ( " /studies/ {study_id} /pareto-front " )
async def get_pareto_front ( study_id : str ) :
""" Get Pareto-optimal solutions for multi-objective studies (Protocol 13) """
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-02 22:01:49 -05:00
results_dir = get_results_dir ( study_dir )
feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.
## New Features
### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API
### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
- 3 modes: Raw, Min-Max [0-1], Z-Score standardization
- Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
- Objectives + design variables on parallel axes
- Click-to-select, hover-to-highlight
- Color-coded feasibility
- Dynamic units throughout all visualizations
### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage
## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`
## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`
## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00
study_db = results_dir / " study.db "
if not study_db . exists ( ) :
return { " is_multi_objective " : False , " pareto_front " : [ ] }
# Import optuna here to avoid loading it for all endpoints
import optuna
storage = optuna . storages . RDBStorage ( f " sqlite:/// { study_db } " )
study = optuna . load_study ( study_name = study_id , storage = storage )
# Check if multi-objective
if len ( study . directions ) == 1 :
return { " is_multi_objective " : False , " pareto_front " : [ ] }
# Get Pareto front
pareto_trials = study . best_trials
return {
" is_multi_objective " : True ,
" pareto_front " : [
{
" trial_number " : t . number ,
" values " : t . values ,
" params " : t . params ,
" user_attrs " : dict ( t . user_attrs ) ,
" constraint_satisfied " : t . user_attrs . get ( " constraint_satisfied " , True )
}
for t in pareto_trials
]
}
except FileNotFoundError :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to get Pareto front: { str ( e ) } " )
2025-11-24 09:12:36 -05:00
2025-12-05 12:56:34 -05:00
@router.get ( " /studies/ {study_id} /nn-pareto-front " )
async def get_nn_pareto_front ( study_id : str ) :
""" Get NN surrogate Pareto front from nn_pareto_front.json """
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-05 12:56:34 -05:00
results_dir = get_results_dir ( study_dir )
nn_pareto_file = results_dir / " nn_pareto_front.json "
if not nn_pareto_file . exists ( ) :
return { " has_nn_results " : False , " pareto_front " : [ ] }
with open ( nn_pareto_file ) as f :
nn_pareto = json . load ( f )
# Transform to match Trial interface format
transformed = [ ]
for trial in nn_pareto :
transformed . append ( {
" trial_number " : trial . get ( " trial_number " ) ,
" values " : [ trial . get ( " mass " ) , trial . get ( " frequency " ) ] ,
" params " : trial . get ( " params " , { } ) ,
" user_attrs " : {
" source " : " NN " ,
" feasible " : trial . get ( " feasible " , False ) ,
" predicted_stress " : trial . get ( " predicted_stress " ) ,
" predicted_displacement " : trial . get ( " predicted_displacement " ) ,
" mass " : trial . get ( " mass " ) ,
" frequency " : trial . get ( " frequency " )
} ,
" constraint_satisfied " : trial . get ( " feasible " , False ) ,
" source " : " NN "
} )
return {
" has_nn_results " : True ,
" pareto_front " : transformed ,
" count " : len ( transformed )
}
except FileNotFoundError :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to get NN Pareto front: { str ( e ) } " )
@router.get ( " /studies/ {study_id} /nn-state " )
async def get_nn_optimization_state ( study_id : str ) :
""" Get NN optimization state/summary from nn_optimization_state.json """
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-05 12:56:34 -05:00
results_dir = get_results_dir ( study_dir )
nn_state_file = results_dir / " nn_optimization_state.json "
if not nn_state_file . exists ( ) :
return { " has_nn_state " : False }
with open ( nn_state_file ) as f :
state = json . load ( f )
return {
" has_nn_state " : True ,
" total_fea_count " : state . get ( " total_fea_count " , 0 ) ,
" total_nn_count " : state . get ( " total_nn_count " , 0 ) ,
" pareto_front_size " : state . get ( " pareto_front_size " , 0 ) ,
" best_mass " : state . get ( " best_mass " ) ,
" best_frequency " : state . get ( " best_frequency " ) ,
" timestamp " : state . get ( " timestamp " )
}
except FileNotFoundError :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to get NN state: { str ( e ) } " )
2025-11-24 09:12:36 -05:00
@router.post ( " /studies " )
async def create_study (
config : str = Form ( . . . ) ,
prt_file : Optional [ UploadFile ] = File ( None ) ,
sim_file : Optional [ UploadFile ] = File ( None ) ,
fem_file : Optional [ UploadFile ] = File ( None )
) :
"""
Create a new optimization study
Accepts :
- config : JSON string with study configuration
- prt_file : NX part file ( optional if using existing study )
- sim_file : NX simulation file ( optional )
- fem_file : NX FEM file ( optional )
"""
try :
# Parse config
config_data = json . loads ( config )
study_name = config_data . get ( " name " ) # Changed from study_name to name to match frontend
if not study_name :
raise HTTPException ( status_code = 400 , detail = " name is required in config " )
# Create study directory structure
study_dir = STUDIES_DIR / study_name
if study_dir . exists ( ) :
raise HTTPException ( status_code = 400 , detail = f " Study { study_name } already exists " )
setup_dir = study_dir / " 1_setup "
model_dir = setup_dir / " model "
results_dir = study_dir / " 2_results "
setup_dir . mkdir ( parents = True , exist_ok = True )
model_dir . mkdir ( parents = True , exist_ok = True )
results_dir . mkdir ( parents = True , exist_ok = True )
# Save config file
config_file = setup_dir / " optimization_config.json "
with open ( config_file , ' w ' ) as f :
json . dump ( config_data , f , indent = 2 )
# Save uploaded files
files_saved = { }
if prt_file :
prt_path = model_dir / prt_file . filename
with open ( prt_path , ' wb ' ) as f :
content = await prt_file . read ( )
f . write ( content )
files_saved [ ' prt_file ' ] = str ( prt_path )
if sim_file :
sim_path = model_dir / sim_file . filename
with open ( sim_path , ' wb ' ) as f :
content = await sim_file . read ( )
f . write ( content )
files_saved [ ' sim_file ' ] = str ( sim_path )
if fem_file :
fem_path = model_dir / fem_file . filename
with open ( fem_path , ' wb ' ) as f :
content = await fem_file . read ( )
f . write ( content )
files_saved [ ' fem_file ' ] = str ( fem_path )
return JSONResponse (
status_code = 201 ,
content = {
" status " : " created " ,
" study_id " : study_name ,
" study_path " : str ( study_dir ) ,
" config_path " : str ( config_file ) ,
" files_saved " : files_saved ,
" message " : f " Study { study_name } created successfully. Ready to run optimization. "
}
)
except json . JSONDecodeError as e :
raise HTTPException ( status_code = 400 , detail = f " Invalid JSON in config: { str ( e ) } " )
except Exception as e :
# Clean up on error
if ' study_dir ' in locals ( ) and study_dir . exists ( ) :
shutil . rmtree ( study_dir )
raise HTTPException ( status_code = 500 , detail = f " Failed to create study: { str ( e ) } " )
@router.post ( " /studies/ {study_id} /convert-mesh " )
async def convert_study_mesh ( study_id : str ) :
"""
Convert study mesh to GLTF for 3 D visualization
Creates a web - viewable 3 D model with FEA results as vertex colors
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-11-24 09:12:36 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Import mesh converter
sys . path . append ( str ( Path ( __file__ ) . parent . parent . parent . parent . parent ) )
refactor: Major reorganization of optimization_engine module structure
BREAKING CHANGE: Module paths have been reorganized for better maintainability.
Backwards compatibility aliases with deprecation warnings are provided.
New Structure:
- core/ - Optimization runners (runner, intelligent_optimizer, etc.)
- processors/ - Data processing
- surrogates/ - Neural network surrogates
- nx/ - NX/Nastran integration (solver, updater, session_manager)
- study/ - Study management (creator, wizard, state, reset)
- reporting/ - Reports and analysis (visualizer, report_generator)
- config/ - Configuration management (manager, builder)
- utils/ - Utilities (logger, auto_doc, etc.)
- future/ - Research/experimental code
Migration:
- ~200 import changes across 125 files
- All __init__.py files use lazy loading to avoid circular imports
- Backwards compatibility layer supports old import paths with warnings
- All existing functionality preserved
To migrate existing code:
OLD: from optimization_engine.nx_solver import NXSolver
NEW: from optimization_engine.nx.solver import NXSolver
OLD: from optimization_engine.runner import OptimizationRunner
NEW: from optimization_engine.core.runner import OptimizationRunner
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 12:30:59 -05:00
from optimization_engine . nx . mesh_converter import convert_study_mesh
2025-11-24 09:12:36 -05:00
# Convert mesh
output_path = convert_study_mesh ( study_dir )
if output_path and output_path . exists ( ) :
return {
" status " : " success " ,
" gltf_path " : str ( output_path ) ,
" gltf_url " : f " /api/optimization/studies/ { study_id } /mesh/model.gltf " ,
" metadata_url " : f " /api/optimization/studies/ { study_id } /mesh/model.json " ,
" message " : " Mesh converted successfully "
}
else :
raise HTTPException ( status_code = 500 , detail = " Mesh conversion failed " )
except FileNotFoundError :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to convert mesh: { str ( e ) } " )
@router.get ( " /studies/ {study_id} /mesh/ {filename} " )
async def get_mesh_file ( study_id : str , filename : str ) :
"""
Serve GLTF mesh files and metadata
Supports . gltf , . bin , and . json files
"""
try :
# Validate filename to prevent directory traversal
if ' .. ' in filename or ' / ' in filename or ' \\ ' in filename :
raise HTTPException ( status_code = 400 , detail = " Invalid filename " )
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-11-24 09:12:36 -05:00
visualization_dir = study_dir / " 3_visualization "
file_path = visualization_dir / filename
if not file_path . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " File { filename } not found " )
# Determine content type
suffix = file_path . suffix . lower ( )
content_types = {
' .gltf ' : ' model/gltf+json ' ,
' .bin ' : ' application/octet-stream ' ,
' .json ' : ' application/json ' ,
' .glb ' : ' model/gltf-binary '
}
content_type = content_types . get ( suffix , ' application/octet-stream ' )
return FileResponse (
path = str ( file_path ) ,
media_type = content_type ,
filename = filename
)
except FileNotFoundError :
raise HTTPException ( status_code = 404 , detail = f " File not found " )
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to serve mesh file: { str ( e ) } " )
feat: Major update with validators, skills, dashboard, and docs reorganization
- Add validation framework (config, model, results, study validators)
- Add Claude Code skills (create-study, run-optimization, generate-report,
troubleshoot, analyze-model)
- Add Atomizer Dashboard (React frontend + FastAPI backend)
- Reorganize docs into structured directories (00-09)
- Add neural surrogate modules and training infrastructure
- Add multi-objective optimization support
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 19:23:58 -05:00
@router.get ( " /studies/ {study_id} /optuna-url " )
async def get_optuna_dashboard_url ( study_id : str ) :
"""
Get the Optuna dashboard URL for a specific study .
Returns the URL to access the study in Optuna dashboard .
The Optuna dashboard should be started with a relative path from the Atomizer root :
sqlite : / / / studies / { study_id } / 2 _results / study . db
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
feat: Major update with validators, skills, dashboard, and docs reorganization
- Add validation framework (config, model, results, study validators)
- Add Claude Code skills (create-study, run-optimization, generate-report,
troubleshoot, analyze-model)
- Add Atomizer Dashboard (React frontend + FastAPI backend)
- Reorganize docs into structured directories (00-09)
- Add neural surrogate modules and training infrastructure
- Add multi-objective optimization support
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 19:23:58 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
2025-12-02 22:01:49 -05:00
results_dir = get_results_dir ( study_dir )
feat: Major update with validators, skills, dashboard, and docs reorganization
- Add validation framework (config, model, results, study validators)
- Add Claude Code skills (create-study, run-optimization, generate-report,
troubleshoot, analyze-model)
- Add Atomizer Dashboard (React frontend + FastAPI backend)
- Reorganize docs into structured directories (00-09)
- Add neural surrogate modules and training infrastructure
- Add multi-objective optimization support
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 19:23:58 -05:00
study_db = results_dir / " study.db "
if not study_db . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " No Optuna database found for study { study_id } " )
# Get the study name from the database (may differ from folder name)
import optuna
storage = optuna . storages . RDBStorage ( f " sqlite:/// { study_db } " )
studies = storage . get_all_studies ( )
if not studies :
raise HTTPException ( status_code = 404 , detail = f " No Optuna study found in database for { study_id } " )
# Use the actual study name from the database
optuna_study_name = studies [ 0 ] . study_name
# Return URL info for the frontend
# The dashboard should be running on port 8081 with the correct database
return {
" study_id " : study_id ,
" optuna_study_name " : optuna_study_name ,
" database_path " : f " studies/ { study_id } /2_results/study.db " ,
" dashboard_url " : f " http://localhost:8081/dashboard/studies/ { studies [ 0 ] . _study_id } " ,
" dashboard_base " : " http://localhost:8081 " ,
" note " : " Optuna dashboard must be started with: sqlite:///studies/ {study_id} /2_results/study.db "
}
except FileNotFoundError :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to get Optuna URL: { str ( e ) } " )
2025-11-24 09:12:36 -05:00
@router.post ( " /studies/ {study_id} /generate-report " )
async def generate_report (
study_id : str ,
format : str = " markdown " ,
include_llm_summary : bool = False
) :
"""
Generate an optimization report in the specified format
Args :
study_id : Study identifier
format : Report format ( ' markdown ' , ' html ' , or ' pdf ' )
include_llm_summary : Whether to include LLM - generated executive summary
Returns :
Information about the generated report including download URL
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-11-24 09:12:36 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Validate format
valid_formats = [ ' markdown ' , ' md ' , ' html ' , ' pdf ' ]
if format . lower ( ) not in valid_formats :
raise HTTPException ( status_code = 400 , detail = f " Invalid format. Must be one of: { ' , ' . join ( valid_formats ) } " )
# Import report generator
sys . path . append ( str ( Path ( __file__ ) . parent . parent . parent . parent . parent ) )
from optimization_engine . report_generator import generate_study_report
# Generate report
output_path = generate_study_report (
study_dir = study_dir ,
output_format = format . lower ( ) ,
include_llm_summary = include_llm_summary
)
if output_path and output_path . exists ( ) :
# Get relative path for URL
rel_path = output_path . relative_to ( study_dir )
return {
" status " : " success " ,
" format " : format ,
" file_path " : str ( output_path ) ,
" download_url " : f " /api/optimization/studies/ { study_id } /reports/ { output_path . name } " ,
" file_size " : output_path . stat ( ) . st_size ,
" message " : f " Report generated successfully in { format } format "
}
else :
raise HTTPException ( status_code = 500 , detail = " Report generation failed " )
except FileNotFoundError :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to generate report: { str ( e ) } " )
@router.get ( " /studies/ {study_id} /reports/ {filename} " )
async def download_report ( study_id : str , filename : str ) :
"""
Download a generated report file
Args :
study_id : Study identifier
filename : Report filename
Returns :
Report file for download
"""
try :
# Validate filename to prevent directory traversal
if ' .. ' in filename or ' / ' in filename or ' \\ ' in filename :
raise HTTPException ( status_code = 400 , detail = " Invalid filename " )
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-02 22:01:49 -05:00
results_dir = get_results_dir ( study_dir )
2025-11-24 09:12:36 -05:00
file_path = results_dir / filename
if not file_path . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Report file { filename } not found " )
# Determine content type
suffix = file_path . suffix . lower ( )
content_types = {
' .md ' : ' text/markdown ' ,
' .html ' : ' text/html ' ,
' .pdf ' : ' application/pdf ' ,
' .json ' : ' application/json '
}
content_type = content_types . get ( suffix , ' application/octet-stream ' )
return FileResponse (
path = str ( file_path ) ,
media_type = content_type ,
filename = filename ,
headers = { " Content-Disposition " : f " attachment; filename= { filename } " }
)
except FileNotFoundError :
raise HTTPException ( status_code = 404 , detail = f " Report file not found " )
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to download report: { str ( e ) } " )
2025-12-02 22:01:49 -05:00
2025-12-04 07:41:54 -05:00
@router.get ( " /studies/ {study_id} /console " )
async def get_console_output ( study_id : str , lines : int = 200 ) :
"""
Get the latest console output / logs from the optimization run
Args :
study_id : Study identifier
lines : Number of lines to return ( default : 200 )
Returns :
JSON with console output lines
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-04 07:41:54 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Look for log files in various locations
log_paths = [
study_dir / " optimization.log " ,
study_dir / " 2_results " / " optimization.log " ,
study_dir / " 3_results " / " optimization.log " ,
study_dir / " run.log " ,
]
log_content = None
log_path_used = None
for log_path in log_paths :
if log_path . exists ( ) :
log_path_used = log_path
break
if log_path_used is None :
return {
" lines " : [ ] ,
" total_lines " : 0 ,
" log_file " : None ,
" message " : " No log file found. Optimization may not have started yet. "
}
# Read the last N lines efficiently
with open ( log_path_used , ' r ' , encoding = ' utf-8 ' , errors = ' replace ' ) as f :
all_lines = f . readlines ( )
# Get last N lines
last_lines = all_lines [ - lines : ] if len ( all_lines ) > lines else all_lines
# Clean up lines (remove trailing newlines)
last_lines = [ line . rstrip ( ' \n \r ' ) for line in last_lines ]
return {
" lines " : last_lines ,
" total_lines " : len ( all_lines ) ,
" displayed_lines " : len ( last_lines ) ,
" log_file " : str ( log_path_used ) ,
" timestamp " : datetime . now ( ) . isoformat ( )
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to read console output: { str ( e ) } " )
2025-12-02 22:01:49 -05:00
@router.get ( " /studies/ {study_id} /report " )
async def get_study_report ( study_id : str ) :
"""
Get the STUDY_REPORT . md file content for a study
Args :
study_id : Study identifier
Returns :
JSON with the markdown content
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-02 22:01:49 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Look for STUDY_REPORT.md in the study root
report_path = study_dir / " STUDY_REPORT.md "
if not report_path . exists ( ) :
raise HTTPException ( status_code = 404 , detail = " No STUDY_REPORT.md found for this study " )
with open ( report_path , ' r ' , encoding = ' utf-8 ' ) as f :
content = f . read ( )
return {
" content " : content ,
" path " : str ( report_path ) ,
" study_id " : study_id
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to read study report: { str ( e ) } " )
2025-12-04 15:02:13 -05:00
# ============================================================================
# Study README and Config Endpoints
# ============================================================================
@router.get ( " /studies/ {study_id} /readme " )
async def get_study_readme ( study_id : str ) :
"""
Get the README . md file content for a study ( from 1 _setup folder )
Args :
study_id : Study identifier
Returns :
JSON with the markdown content
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-04 15:02:13 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Look for README.md in various locations
readme_paths = [
study_dir / " README.md " ,
study_dir / " 1_setup " / " README.md " ,
study_dir / " readme.md " ,
]
readme_content = None
readme_path = None
for path in readme_paths :
if path . exists ( ) :
readme_path = path
with open ( path , ' r ' , encoding = ' utf-8 ' ) as f :
readme_content = f . read ( )
break
if readme_content is None :
# Generate a basic README from config if none exists
config_file = study_dir / " 1_setup " / " optimization_config.json "
if not config_file . exists ( ) :
config_file = study_dir / " optimization_config.json "
if config_file . exists ( ) :
with open ( config_file ) as f :
config = json . load ( f )
readme_content = f """ # { config . get ( ' study_name ' , study_id ) }
{ config . get ( ' description ' , ' No description available. ' ) }
## Design Variables
{ chr ( 10 ) . join ( [ f " - ** { dv [ ' name ' ] } **: { dv . get ( ' min ' , ' ? ' ) } - { dv . get ( ' max ' , ' ? ' ) } { dv . get ( ' units ' , ' ' ) } " for dv in config . get ( ' design_variables ' , [ ] ) ] ) }
## Objectives
{ chr ( 10 ) . join ( [ f " - ** { obj [ ' name ' ] } **: { obj . get ( ' description ' , ' ' ) } ( { obj . get ( ' direction ' , ' minimize ' ) } ) " for obj in config . get ( ' objectives ' , [ ] ) ] ) }
"""
else :
readme_content = f " # { study_id } \n \n No README or configuration found for this study. "
return {
" content " : readme_content ,
" path " : str ( readme_path ) if readme_path else None ,
" study_id " : study_id
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to read README: { str ( e ) } " )
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
@router.get ( " /studies/ {study_id} /image/ { image_path:path} " )
async def get_study_image ( study_id : str , image_path : str ) :
"""
Serve images from a study directory .
Supports images in :
- study_dir / image . png
- study_dir / 1 _setup / image . png
- study_dir / 3 _results / image . png
- study_dir / assets / image . png
Args :
study_id : Study identifier
image_path : Relative path to the image within the study
Returns :
FileResponse with the image
"""
try :
study_dir = resolve_study_path ( study_id )
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Sanitize path to prevent directory traversal
image_path = image_path . replace ( ' .. ' , ' ' ) . lstrip ( ' / ' )
# Try multiple locations for the image
possible_paths = [
study_dir / image_path ,
study_dir / " 1_setup " / image_path ,
study_dir / " 3_results " / image_path ,
study_dir / " 2_results " / image_path ,
study_dir / " assets " / image_path ,
]
image_file = None
for path in possible_paths :
if path . exists ( ) and path . is_file ( ) :
image_file = path
break
if image_file is None :
raise HTTPException ( status_code = 404 , detail = f " Image not found: { image_path } " )
# Determine media type
suffix = image_file . suffix . lower ( )
media_types = {
' .png ' : ' image/png ' ,
' .jpg ' : ' image/jpeg ' ,
' .jpeg ' : ' image/jpeg ' ,
' .gif ' : ' image/gif ' ,
' .svg ' : ' image/svg+xml ' ,
' .webp ' : ' image/webp ' ,
}
media_type = media_types . get ( suffix , ' application/octet-stream ' )
return FileResponse ( image_file , media_type = media_type )
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to serve image: { str ( e ) } " )
2025-12-04 15:02:13 -05:00
@router.get ( " /studies/ {study_id} /config " )
async def get_study_config ( study_id : str ) :
"""
Get the full optimization_config . json for a study
Args :
study_id : Study identifier
Returns :
JSON with the complete configuration
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-04 15:02:13 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Look for config in various locations
config_file = study_dir / " 1_setup " / " optimization_config.json "
if not config_file . exists ( ) :
config_file = study_dir / " optimization_config.json "
if not config_file . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Config file not found for study { study_id } " )
with open ( config_file ) as f :
config = json . load ( f )
return {
" config " : config ,
" path " : str ( config_file ) ,
" study_id " : study_id
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to read config: { str ( e ) } " )
# ============================================================================
# Process Control Endpoints
# ============================================================================
# Track running processes by study_id
_running_processes : Dict [ str , int ] = { }
def _find_optimization_process ( study_id : str ) - > Optional [ psutil . Process ] :
""" Find a running optimization process for a given study """
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-04 15:02:13 -05:00
for proc in psutil . process_iter ( [ ' pid ' , ' name ' , ' cmdline ' , ' cwd ' ] ) :
try :
cmdline = proc . info . get ( ' cmdline ' ) or [ ]
cmdline_str = ' ' . join ( cmdline ) if cmdline else ' '
# Check if this is a Python process running run_optimization.py for this study
if ' python ' in cmdline_str . lower ( ) and ' run_optimization ' in cmdline_str :
if study_id in cmdline_str or str ( study_dir ) in cmdline_str :
return proc
except ( psutil . NoSuchProcess , psutil . AccessDenied ) :
continue
return None
@router.get ( " /studies/ {study_id} /process " )
async def get_process_status ( study_id : str ) :
"""
Get the process status for a study ' s optimization run
Args :
study_id : Study identifier
Returns :
JSON with process status ( is_running , pid , iteration counts )
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-04 15:02:13 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Check if process is running
proc = _find_optimization_process ( study_id )
is_running = proc is not None
pid = proc . pid if proc else None
# Get iteration counts from database
results_dir = get_results_dir ( study_dir )
study_db = results_dir / " study.db "
fea_count = 0
nn_count = 0
iteration = None
if study_db . exists ( ) :
try :
conn = sqlite3 . connect ( str ( study_db ) )
cursor = conn . cursor ( )
# Count FEA trials (from main study or studies with "_fea" suffix)
cursor . execute ( """
SELECT COUNT ( * ) FROM trials t
JOIN studies s ON t . study_id = s . study_id
WHERE t . state = ' COMPLETE '
AND ( s . study_name LIKE ' % _fea ' OR s . study_name NOT LIKE ' % _nn % ' )
""" )
fea_count = cursor . fetchone ( ) [ 0 ]
# Count NN trials
cursor . execute ( """
SELECT COUNT ( * ) FROM trials t
JOIN studies s ON t . study_id = s . study_id
WHERE t . state = ' COMPLETE '
AND s . study_name LIKE ' % _nn % '
""" )
nn_count = cursor . fetchone ( ) [ 0 ]
# Try to get current iteration from study names
cursor . execute ( """
SELECT study_name FROM studies
WHERE study_name LIKE ' % _iter % '
ORDER BY study_name DESC LIMIT 1
""" )
result = cursor . fetchone ( )
if result :
import re
match = re . search ( r ' iter( \ d+) ' , result [ 0 ] )
if match :
iteration = int ( match . group ( 1 ) )
conn . close ( )
except Exception as e :
print ( f " Warning: Failed to read database for process status: { e } " )
return {
" is_running " : is_running ,
" pid " : pid ,
" iteration " : iteration ,
" fea_count " : fea_count ,
" nn_count " : nn_count ,
" study_id " : study_id
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to get process status: { str ( e ) } " )
class StartOptimizationRequest ( BaseModel ) :
freshStart : bool = False
maxIterations : int = 100
feaBatchSize : int = 5
tuneTrials : int = 30
ensembleSize : int = 3
patience : int = 5
@router.post ( " /studies/ {study_id} /start " )
async def start_optimization ( study_id : str , request : StartOptimizationRequest = None ) :
"""
Start the optimization process for a study
Args :
study_id : Study identifier
request : Optional start options
Returns :
JSON with process info
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-04 15:02:13 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Check if already running
existing_proc = _find_optimization_process ( study_id )
if existing_proc :
return {
" success " : False ,
" message " : f " Optimization already running (PID: { existing_proc . pid } ) " ,
" pid " : existing_proc . pid
}
# Find run_optimization.py
run_script = study_dir / " run_optimization.py "
if not run_script . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " run_optimization.py not found for study { study_id } " )
# Build command with arguments
python_exe = sys . executable
cmd = [ python_exe , str ( run_script ) , " --start " ]
if request :
if request . freshStart :
cmd . append ( " --fresh " )
cmd . extend ( [ " --fea-batch " , str ( request . feaBatchSize ) ] )
cmd . extend ( [ " --tune-trials " , str ( request . tuneTrials ) ] )
cmd . extend ( [ " --ensemble-size " , str ( request . ensembleSize ) ] )
cmd . extend ( [ " --patience " , str ( request . patience ) ] )
# Start process in background
proc = subprocess . Popen (
cmd ,
cwd = str ( study_dir ) ,
stdout = subprocess . PIPE ,
stderr = subprocess . PIPE ,
start_new_session = True
)
_running_processes [ study_id ] = proc . pid
return {
" success " : True ,
" message " : f " Optimization started successfully " ,
" pid " : proc . pid ,
" command " : ' ' . join ( cmd )
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to start optimization: { str ( e ) } " )
class StopRequest ( BaseModel ) :
force : bool = True # Default to force kill
@router.post ( " /studies/ {study_id} /stop " )
async def stop_optimization ( study_id : str , request : StopRequest = None ) :
"""
Stop the optimization process for a study ( hard kill by default )
Args :
study_id : Study identifier
request . force : If True ( default ) , immediately kill . If False , try graceful first .
Returns :
JSON with result
"""
if request is None :
request = StopRequest ( )
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-04 15:02:13 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Find running process
proc = _find_optimization_process ( study_id )
if not proc :
return {
" success " : False ,
" message " : " No running optimization process found "
}
pid = proc . pid
killed_pids = [ ]
try :
# FIRST: Get all children BEFORE killing parent
children = [ ]
try :
children = proc . children ( recursive = True )
except ( psutil . NoSuchProcess , psutil . AccessDenied ) :
pass
if request . force :
# Hard kill: immediately kill parent and all children
# Kill children first (bottom-up)
for child in reversed ( children ) :
try :
child . kill ( ) # SIGKILL on Unix, TerminateProcess on Windows
killed_pids . append ( child . pid )
except ( psutil . NoSuchProcess , psutil . AccessDenied ) :
pass
# Then kill parent
try :
proc . kill ( )
killed_pids . append ( pid )
except psutil . NoSuchProcess :
pass
else :
# Graceful: try SIGTERM first, then force
try :
proc . terminate ( )
proc . wait ( timeout = 5 )
except psutil . TimeoutExpired :
# Didn't stop gracefully, force kill
for child in reversed ( children ) :
try :
child . kill ( )
killed_pids . append ( child . pid )
except ( psutil . NoSuchProcess , psutil . AccessDenied ) :
pass
proc . kill ( )
killed_pids . append ( pid )
except psutil . NoSuchProcess :
pass
# Clean up tracking
if study_id in _running_processes :
del _running_processes [ study_id ]
return {
" success " : True ,
" message " : f " Optimization killed (PID: { pid } , + { len ( children ) } children) " ,
" pid " : pid ,
" killed_pids " : killed_pids
}
except psutil . NoSuchProcess :
if study_id in _running_processes :
del _running_processes [ study_id ]
return {
" success " : True ,
" message " : " Process already terminated "
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to stop optimization: { str ( e ) } " )
class ValidateRequest ( BaseModel ) :
topN : int = 5
@router.post ( " /studies/ {study_id} /validate " )
async def validate_optimization ( study_id : str , request : ValidateRequest = None ) :
"""
Run final FEA validation on top NN predictions
Args :
study_id : Study identifier
request : Validation options ( topN )
Returns :
JSON with process info
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-04 15:02:13 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Check if optimization is still running
existing_proc = _find_optimization_process ( study_id )
if existing_proc :
return {
" success " : False ,
" message " : " Cannot validate while optimization is running. Stop optimization first. "
}
# Look for final_validation.py script
validation_script = study_dir / " final_validation.py "
if not validation_script . exists ( ) :
# Fall back to run_optimization.py with --validate flag if script doesn't exist
run_script = study_dir / " run_optimization.py "
if not run_script . exists ( ) :
raise HTTPException ( status_code = 404 , detail = " No validation script found " )
python_exe = sys . executable
top_n = request . topN if request else 5
cmd = [ python_exe , str ( run_script ) , " --validate " , " --top " , str ( top_n ) ]
else :
python_exe = sys . executable
top_n = request . topN if request else 5
cmd = [ python_exe , str ( validation_script ) , " --top " , str ( top_n ) ]
# Start validation process
proc = subprocess . Popen (
cmd ,
cwd = str ( study_dir ) ,
stdout = subprocess . PIPE ,
stderr = subprocess . PIPE ,
start_new_session = True
)
return {
" success " : True ,
" message " : f " Validation started for top { top_n } NN predictions " ,
" pid " : proc . pid ,
" command " : ' ' . join ( cmd )
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to start validation: { str ( e ) } " )
# ============================================================================
# Optuna Dashboard Launch
# ============================================================================
_optuna_processes : Dict [ str , subprocess . Popen ] = { }
@router.post ( " /studies/ {study_id} /optuna-dashboard " )
async def launch_optuna_dashboard ( study_id : str ) :
"""
Launch Optuna dashboard for a specific study
Args :
study_id : Study identifier
Returns :
JSON with dashboard URL and process info
"""
import time
import socket
def is_port_in_use ( port : int ) - > bool :
""" Check if a port is already in use """
with socket . socket ( socket . AF_INET , socket . SOCK_STREAM ) as s :
return s . connect_ex ( ( ' localhost ' , port ) ) == 0
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-04 15:02:13 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
results_dir = get_results_dir ( study_dir )
study_db = results_dir / " study.db "
if not study_db . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " No Optuna database found for study { study_id } " )
port = 8081
# Check if dashboard is already running on this port
if is_port_in_use ( port ) :
# Check if it's our process
if study_id in _optuna_processes :
proc = _optuna_processes [ study_id ]
if proc . poll ( ) is None : # Still running
return {
" success " : True ,
" url " : f " http://localhost: { port } " ,
" pid " : proc . pid ,
" message " : " Optuna dashboard already running "
}
# Port in use but not by us - still return success since dashboard is available
return {
" success " : True ,
" url " : f " http://localhost: { port } " ,
" pid " : None ,
" message " : " Optuna dashboard already running on port 8081 "
}
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
# Launch optuna-dashboard using CLI command (more robust than Python import)
2025-12-04 15:02:13 -05:00
# Use absolute path with POSIX format for SQLite URL
abs_db_path = study_db . absolute ( ) . as_posix ( )
storage_url = f " sqlite:/// { abs_db_path } "
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
# Use optuna-dashboard CLI command directly
cmd = [ " optuna-dashboard " , storage_url , " --port " , str ( port ) , " --host " , " 0.0.0.0 " ]
2025-12-04 15:02:13 -05:00
# On Windows, use CREATE_NEW_PROCESS_GROUP and DETACHED_PROCESS flags
import platform
if platform . system ( ) == ' Windows ' :
# Windows-specific: create detached process
DETACHED_PROCESS = 0x00000008
CREATE_NEW_PROCESS_GROUP = 0x00000200
proc = subprocess . Popen (
cmd ,
stdout = subprocess . PIPE ,
stderr = subprocess . PIPE ,
creationflags = DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP
)
else :
proc = subprocess . Popen (
cmd ,
stdout = subprocess . PIPE ,
stderr = subprocess . PIPE ,
start_new_session = True
)
_optuna_processes [ study_id ] = proc
# Wait for dashboard to start (check port repeatedly)
max_wait = 5 # seconds
start_time = time . time ( )
while time . time ( ) - start_time < max_wait :
if is_port_in_use ( port ) :
return {
" success " : True ,
" url " : f " http://localhost: { port } " ,
" pid " : proc . pid ,
" message " : " Optuna dashboard launched successfully "
}
# Check if process died
if proc . poll ( ) is not None :
stderr = " "
try :
stderr = proc . stderr . read ( ) . decode ( ) if proc . stderr else " "
except :
pass
return {
" success " : False ,
" message " : f " Failed to start Optuna dashboard: { stderr } "
}
time . sleep ( 0.5 )
# Timeout - process might still be starting
if proc . poll ( ) is None :
return {
" success " : True ,
" url " : f " http://localhost: { port } " ,
" pid " : proc . pid ,
" message " : " Optuna dashboard starting (may take a moment) "
}
else :
stderr = " "
try :
stderr = proc . stderr . read ( ) . decode ( ) if proc . stderr else " "
except :
pass
return {
" success " : False ,
" message " : f " Failed to start Optuna dashboard: { stderr } "
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to launch Optuna dashboard: { str ( e ) } " )
feat: Add Analysis page, run comparison, notifications, and config editor
Dashboard enhancements:
- Add Analysis page with tabs: Overview, Parameters, Pareto, Correlations, Constraints, Surrogate, Runs
- Add PlotlyCorrelationHeatmap for parameter-objective correlation analysis
- Add PlotlyFeasibilityChart for constraint satisfaction visualization
- Add PlotlySurrogateQuality for FEA vs NN prediction comparison
- Add PlotlyRunComparison for comparing optimization runs within a study
Real-time improvements:
- Replace watchdog file-watching with SQLite database polling for better Windows reliability
- Add DatabasePoller class with 2-second polling interval
- Enhanced WebSocket messages: trial_completed, new_best, pareto_update, progress
Desktop notifications:
- Add useNotifications hook using Web Notifications API
- Add NotificationSettings toggle component
- Notify users when new best solutions are found
Config editor:
- Add PUT /studies/{study_id}/config endpoint with auto-backup
- Add ConfigEditor modal with tabs: General, Variables, Objectives, Settings, JSON
- Prevents editing while optimization is running
Enhanced Pareto visualization:
- Add dark mode styling with transparent backgrounds
- Add stats bar showing Pareto, FEA, NN, and infeasible counts
- Add Pareto front connecting line for 2D view
- Add table showing top 10 Pareto-optimal solutions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 19:57:20 -05:00
# ============================================================================
# Model Files Endpoint
# ============================================================================
@router.get ( " /studies/ {study_id} /model-files " )
async def get_model_files ( study_id : str ) :
"""
Get list of NX model files ( . prt , . sim , . fem , . bdf , . dat , . op2 ) for a study
Args :
study_id : Study identifier
Returns :
JSON with list of model files and their paths
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
feat: Add Analysis page, run comparison, notifications, and config editor
Dashboard enhancements:
- Add Analysis page with tabs: Overview, Parameters, Pareto, Correlations, Constraints, Surrogate, Runs
- Add PlotlyCorrelationHeatmap for parameter-objective correlation analysis
- Add PlotlyFeasibilityChart for constraint satisfaction visualization
- Add PlotlySurrogateQuality for FEA vs NN prediction comparison
- Add PlotlyRunComparison for comparing optimization runs within a study
Real-time improvements:
- Replace watchdog file-watching with SQLite database polling for better Windows reliability
- Add DatabasePoller class with 2-second polling interval
- Enhanced WebSocket messages: trial_completed, new_best, pareto_update, progress
Desktop notifications:
- Add useNotifications hook using Web Notifications API
- Add NotificationSettings toggle component
- Notify users when new best solutions are found
Config editor:
- Add PUT /studies/{study_id}/config endpoint with auto-backup
- Add ConfigEditor modal with tabs: General, Variables, Objectives, Settings, JSON
- Prevents editing while optimization is running
Enhanced Pareto visualization:
- Add dark mode styling with transparent backgrounds
- Add stats bar showing Pareto, FEA, NN, and infeasible counts
- Add Pareto front connecting line for 2D view
- Add table showing top 10 Pareto-optimal solutions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 19:57:20 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Look for model directory (check multiple locations)
model_dirs = [
study_dir / " 1_setup " / " model " ,
study_dir / " model " ,
study_dir / " 1_setup " ,
study_dir
]
model_files = [ ]
model_dir_path = None
# NX and FEA file extensions to look for
nx_extensions = { ' .prt ' , ' .sim ' , ' .fem ' , ' .bdf ' , ' .dat ' , ' .op2 ' , ' .f06 ' , ' .inp ' }
for model_dir in model_dirs :
if model_dir . exists ( ) and model_dir . is_dir ( ) :
for file_path in model_dir . iterdir ( ) :
if file_path . is_file ( ) and file_path . suffix . lower ( ) in nx_extensions :
model_files . append ( {
" name " : file_path . name ,
" path " : str ( file_path ) ,
" extension " : file_path . suffix . lower ( ) ,
" size_bytes " : file_path . stat ( ) . st_size ,
" size_display " : _format_file_size ( file_path . stat ( ) . st_size ) ,
" modified " : datetime . fromtimestamp ( file_path . stat ( ) . st_mtime ) . isoformat ( )
} )
if model_dir_path is None :
model_dir_path = str ( model_dir )
# Sort by extension for better display (prt first, then sim, fem, etc.)
extension_order = { ' .prt ' : 0 , ' .sim ' : 1 , ' .fem ' : 2 , ' .bdf ' : 3 , ' .dat ' : 4 , ' .op2 ' : 5 , ' .f06 ' : 6 , ' .inp ' : 7 }
model_files . sort ( key = lambda x : ( extension_order . get ( x [ ' extension ' ] , 99 ) , x [ ' name ' ] ) )
return {
" study_id " : study_id ,
" model_dir " : model_dir_path or str ( study_dir / " 1_setup " / " model " ) ,
" files " : model_files ,
" count " : len ( model_files )
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to get model files: { str ( e ) } " )
def _format_file_size ( size_bytes : int ) - > str :
""" Format file size in human-readable form """
if size_bytes < 1024 :
return f " { size_bytes } B "
elif size_bytes < 1024 * 1024 :
return f " { size_bytes / 1024 : .1f } KB "
elif size_bytes < 1024 * 1024 * 1024 :
return f " { size_bytes / ( 1024 * 1024 ) : .1f } MB "
else :
return f " { size_bytes / ( 1024 * 1024 * 1024 ) : .2f } GB "
@router.post ( " /studies/ {study_id} /open-folder " )
async def open_model_folder ( study_id : str , folder_type : str = " model " ) :
"""
Open the model folder in system file explorer
Args :
study_id : Study identifier
folder_type : Type of folder to open ( model , results , setup )
Returns :
JSON with success status
"""
import os
import platform
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
feat: Add Analysis page, run comparison, notifications, and config editor
Dashboard enhancements:
- Add Analysis page with tabs: Overview, Parameters, Pareto, Correlations, Constraints, Surrogate, Runs
- Add PlotlyCorrelationHeatmap for parameter-objective correlation analysis
- Add PlotlyFeasibilityChart for constraint satisfaction visualization
- Add PlotlySurrogateQuality for FEA vs NN prediction comparison
- Add PlotlyRunComparison for comparing optimization runs within a study
Real-time improvements:
- Replace watchdog file-watching with SQLite database polling for better Windows reliability
- Add DatabasePoller class with 2-second polling interval
- Enhanced WebSocket messages: trial_completed, new_best, pareto_update, progress
Desktop notifications:
- Add useNotifications hook using Web Notifications API
- Add NotificationSettings toggle component
- Notify users when new best solutions are found
Config editor:
- Add PUT /studies/{study_id}/config endpoint with auto-backup
- Add ConfigEditor modal with tabs: General, Variables, Objectives, Settings, JSON
- Prevents editing while optimization is running
Enhanced Pareto visualization:
- Add dark mode styling with transparent backgrounds
- Add stats bar showing Pareto, FEA, NN, and infeasible counts
- Add Pareto front connecting line for 2D view
- Add table showing top 10 Pareto-optimal solutions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 19:57:20 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Determine which folder to open
if folder_type == " model " :
target_dir = study_dir / " 1_setup " / " model "
if not target_dir . exists ( ) :
target_dir = study_dir / " 1_setup "
elif folder_type == " results " :
target_dir = get_results_dir ( study_dir )
elif folder_type == " setup " :
target_dir = study_dir / " 1_setup "
else :
target_dir = study_dir
if not target_dir . exists ( ) :
target_dir = study_dir
# Open in file explorer based on platform
system = platform . system ( )
try :
if system == " Windows " :
os . startfile ( str ( target_dir ) )
elif system == " Darwin " : # macOS
subprocess . Popen ( [ " open " , str ( target_dir ) ] )
else : # Linux
subprocess . Popen ( [ " xdg-open " , str ( target_dir ) ] )
return {
" success " : True ,
" message " : f " Opened { target_dir } " ,
" path " : str ( target_dir )
}
except Exception as e :
return {
" success " : False ,
" message " : f " Failed to open folder: { str ( e ) } " ,
" path " : str ( target_dir )
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to open folder: { str ( e ) } " )
@router.get ( " /studies/ {study_id} /best-solution " )
async def get_best_solution ( study_id : str ) :
""" Get the best trial(s) for a study with improvement metrics """
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
feat: Add Analysis page, run comparison, notifications, and config editor
Dashboard enhancements:
- Add Analysis page with tabs: Overview, Parameters, Pareto, Correlations, Constraints, Surrogate, Runs
- Add PlotlyCorrelationHeatmap for parameter-objective correlation analysis
- Add PlotlyFeasibilityChart for constraint satisfaction visualization
- Add PlotlySurrogateQuality for FEA vs NN prediction comparison
- Add PlotlyRunComparison for comparing optimization runs within a study
Real-time improvements:
- Replace watchdog file-watching with SQLite database polling for better Windows reliability
- Add DatabasePoller class with 2-second polling interval
- Enhanced WebSocket messages: trial_completed, new_best, pareto_update, progress
Desktop notifications:
- Add useNotifications hook using Web Notifications API
- Add NotificationSettings toggle component
- Notify users when new best solutions are found
Config editor:
- Add PUT /studies/{study_id}/config endpoint with auto-backup
- Add ConfigEditor modal with tabs: General, Variables, Objectives, Settings, JSON
- Prevents editing while optimization is running
Enhanced Pareto visualization:
- Add dark mode styling with transparent backgrounds
- Add stats bar showing Pareto, FEA, NN, and infeasible counts
- Add Pareto front connecting line for 2D view
- Add table showing top 10 Pareto-optimal solutions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 19:57:20 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study ' { study_id } ' not found " )
results_dir = get_results_dir ( study_dir )
db_path = results_dir / " study.db "
if not db_path . exists ( ) :
return {
" study_id " : study_id ,
" best_trial " : None ,
" first_trial " : None ,
" improvements " : { } ,
" total_trials " : 0
}
conn = sqlite3 . connect ( str ( db_path ) )
conn . row_factory = sqlite3 . Row
cursor = conn . cursor ( )
# Get best trial (single objective - minimize by default)
cursor . execute ( """
SELECT t . trial_id , t . number , tv . value as objective ,
datetime ( tv . value_id , ' unixepoch ' ) as timestamp
FROM trials t
JOIN trial_values tv ON t . trial_id = tv . trial_id
WHERE t . state = ' COMPLETE '
ORDER BY tv . value ASC
LIMIT 1
""" )
best_row = cursor . fetchone ( )
# Get first completed trial for comparison
cursor . execute ( """
SELECT t . trial_id , t . number , tv . value as objective
FROM trials t
JOIN trial_values tv ON t . trial_id = tv . trial_id
WHERE t . state = ' COMPLETE '
ORDER BY t . number ASC
LIMIT 1
""" )
first_row = cursor . fetchone ( )
# Get total trial count
cursor . execute ( " SELECT COUNT(*) FROM trials WHERE state = ' COMPLETE ' " )
total_trials = cursor . fetchone ( ) [ 0 ]
best_trial = None
first_trial = None
improvements = { }
if best_row :
best_trial_id = best_row [ ' trial_id ' ]
# Get design variables
cursor . execute ( """
SELECT param_name , param_value
FROM trial_params
WHERE trial_id = ?
""" , (best_trial_id,))
params = { row [ ' param_name ' ] : row [ ' param_value ' ] for row in cursor . fetchall ( ) }
# Get user attributes (including results)
cursor . execute ( """
SELECT key , value_json
FROM trial_user_attributes
WHERE trial_id = ?
""" , (best_trial_id,))
user_attrs = { }
for row in cursor . fetchall ( ) :
try :
user_attrs [ row [ ' key ' ] ] = json . loads ( row [ ' value_json ' ] )
except :
user_attrs [ row [ ' key ' ] ] = row [ ' value_json ' ]
best_trial = {
" trial_number " : best_row [ ' number ' ] ,
" objective " : best_row [ ' objective ' ] ,
" design_variables " : params ,
" user_attrs " : user_attrs ,
" timestamp " : best_row [ ' timestamp ' ]
}
if first_row :
first_trial_id = first_row [ ' trial_id ' ]
cursor . execute ( """
SELECT param_name , param_value
FROM trial_params
WHERE trial_id = ?
""" , (first_trial_id,))
first_params = { row [ ' param_name ' ] : row [ ' param_value ' ] for row in cursor . fetchall ( ) }
first_trial = {
" trial_number " : first_row [ ' number ' ] ,
" objective " : first_row [ ' objective ' ] ,
" design_variables " : first_params
}
# Calculate improvement
if best_row and first_row [ ' objective ' ] != 0 :
improvement_pct = ( ( first_row [ ' objective ' ] - best_row [ ' objective ' ] ) / abs ( first_row [ ' objective ' ] ) ) * 100
improvements [ " objective " ] = {
" initial " : first_row [ ' objective ' ] ,
" final " : best_row [ ' objective ' ] ,
" improvement_pct " : round ( improvement_pct , 2 ) ,
" absolute_change " : round ( first_row [ ' objective ' ] - best_row [ ' objective ' ] , 6 )
}
conn . close ( )
return {
" study_id " : study_id ,
" best_trial " : best_trial ,
" first_trial " : first_trial ,
" improvements " : improvements ,
" total_trials " : total_trials
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to get best solution: { str ( e ) } " )
@router.get ( " /studies/ {study_id} /runs " )
async def get_study_runs ( study_id : str ) :
"""
Get all optimization runs / studies in the database for comparison .
Many studies have multiple Optuna studies ( e . g . , v11_fea , v11_iter1_nn , v11_iter2_nn ) .
This endpoint returns metrics for each sub - study .
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
feat: Add Analysis page, run comparison, notifications, and config editor
Dashboard enhancements:
- Add Analysis page with tabs: Overview, Parameters, Pareto, Correlations, Constraints, Surrogate, Runs
- Add PlotlyCorrelationHeatmap for parameter-objective correlation analysis
- Add PlotlyFeasibilityChart for constraint satisfaction visualization
- Add PlotlySurrogateQuality for FEA vs NN prediction comparison
- Add PlotlyRunComparison for comparing optimization runs within a study
Real-time improvements:
- Replace watchdog file-watching with SQLite database polling for better Windows reliability
- Add DatabasePoller class with 2-second polling interval
- Enhanced WebSocket messages: trial_completed, new_best, pareto_update, progress
Desktop notifications:
- Add useNotifications hook using Web Notifications API
- Add NotificationSettings toggle component
- Notify users when new best solutions are found
Config editor:
- Add PUT /studies/{study_id}/config endpoint with auto-backup
- Add ConfigEditor modal with tabs: General, Variables, Objectives, Settings, JSON
- Prevents editing while optimization is running
Enhanced Pareto visualization:
- Add dark mode styling with transparent backgrounds
- Add stats bar showing Pareto, FEA, NN, and infeasible counts
- Add Pareto front connecting line for 2D view
- Add table showing top 10 Pareto-optimal solutions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 19:57:20 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study ' { study_id } ' not found " )
results_dir = get_results_dir ( study_dir )
db_path = results_dir / " study.db "
if not db_path . exists ( ) :
return { " runs " : [ ] , " total_runs " : 0 }
conn = sqlite3 . connect ( str ( db_path ) )
conn . row_factory = sqlite3 . Row
cursor = conn . cursor ( )
# Get all Optuna studies in this database
cursor . execute ( """
SELECT study_id , study_name
FROM studies
ORDER BY study_id
""" )
studies = cursor . fetchall ( )
runs = [ ]
for study_row in studies :
optuna_study_id = study_row [ ' study_id ' ]
study_name = study_row [ ' study_name ' ]
# Get trial count
cursor . execute ( """
SELECT COUNT ( * ) FROM trials
WHERE study_id = ? AND state = ' COMPLETE '
""" , (optuna_study_id,))
trial_count = cursor . fetchone ( ) [ 0 ]
if trial_count == 0 :
continue
# Get best value (first objective)
cursor . execute ( """
SELECT MIN ( tv . value ) as best_value
FROM trial_values tv
JOIN trials t ON tv . trial_id = t . trial_id
WHERE t . study_id = ? AND t . state = ' COMPLETE ' AND tv . objective = 0
""" , (optuna_study_id,))
best_result = cursor . fetchone ( )
best_value = best_result [ ' best_value ' ] if best_result else None
# Get average value
cursor . execute ( """
SELECT AVG ( tv . value ) as avg_value
FROM trial_values tv
JOIN trials t ON tv . trial_id = t . trial_id
WHERE t . study_id = ? AND t . state = ' COMPLETE ' AND tv . objective = 0
""" , (optuna_study_id,))
avg_result = cursor . fetchone ( )
avg_value = avg_result [ ' avg_value ' ] if avg_result else None
# Get time range
cursor . execute ( """
SELECT MIN ( datetime_start ) as first_trial , MAX ( datetime_complete ) as last_trial
FROM trials
WHERE study_id = ? AND state = ' COMPLETE '
""" , (optuna_study_id,))
time_result = cursor . fetchone ( )
# Determine source type (FEA or NN)
source = " NN " if " _nn " in study_name . lower ( ) else " FEA "
runs . append ( {
" run_id " : optuna_study_id ,
" name " : study_name ,
" source " : source ,
" trial_count " : trial_count ,
" best_value " : best_value ,
" avg_value " : avg_value ,
" first_trial " : time_result [ ' first_trial ' ] if time_result else None ,
" last_trial " : time_result [ ' last_trial ' ] if time_result else None
} )
conn . close ( )
return {
" runs " : runs ,
" total_runs " : len ( runs ) ,
" study_id " : study_id
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to get runs: { str ( e ) } " )
class UpdateConfigRequest ( BaseModel ) :
config : dict
@router.put ( " /studies/ {study_id} /config " )
async def update_study_config ( study_id : str , request : UpdateConfigRequest ) :
"""
Update the optimization_config . json for a study
Args :
study_id : Study identifier
request : New configuration data
Returns :
JSON with success status
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
feat: Add Analysis page, run comparison, notifications, and config editor
Dashboard enhancements:
- Add Analysis page with tabs: Overview, Parameters, Pareto, Correlations, Constraints, Surrogate, Runs
- Add PlotlyCorrelationHeatmap for parameter-objective correlation analysis
- Add PlotlyFeasibilityChart for constraint satisfaction visualization
- Add PlotlySurrogateQuality for FEA vs NN prediction comparison
- Add PlotlyRunComparison for comparing optimization runs within a study
Real-time improvements:
- Replace watchdog file-watching with SQLite database polling for better Windows reliability
- Add DatabasePoller class with 2-second polling interval
- Enhanced WebSocket messages: trial_completed, new_best, pareto_update, progress
Desktop notifications:
- Add useNotifications hook using Web Notifications API
- Add NotificationSettings toggle component
- Notify users when new best solutions are found
Config editor:
- Add PUT /studies/{study_id}/config endpoint with auto-backup
- Add ConfigEditor modal with tabs: General, Variables, Objectives, Settings, JSON
- Prevents editing while optimization is running
Enhanced Pareto visualization:
- Add dark mode styling with transparent backgrounds
- Add stats bar showing Pareto, FEA, NN, and infeasible counts
- Add Pareto front connecting line for 2D view
- Add table showing top 10 Pareto-optimal solutions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 19:57:20 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study { study_id } not found " )
# Check if optimization is running - don't allow config changes while running
if is_optimization_running ( study_id ) :
raise HTTPException (
status_code = 409 ,
detail = " Cannot modify config while optimization is running. Stop the optimization first. "
)
# Find config file location
config_file = study_dir / " 1_setup " / " optimization_config.json "
if not config_file . exists ( ) :
config_file = study_dir / " optimization_config.json "
if not config_file . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Config file not found for study { study_id } " )
# Backup existing config
backup_file = config_file . with_suffix ( ' .json.backup ' )
shutil . copy ( config_file , backup_file )
# Write new config
with open ( config_file , ' w ' ) as f :
json . dump ( request . config , f , indent = 2 )
return {
" success " : True ,
" message " : " Configuration updated successfully " ,
" path " : str ( config_file ) ,
" backup_path " : str ( backup_file )
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to update config: { str ( e ) } " )
2025-12-10 21:34:07 -05:00
# ============================================================================
# Zernike Analysis Endpoints
# ============================================================================
@router.get ( " /studies/ {study_id} /zernike-available " )
async def get_zernike_available_trials ( study_id : str ) :
"""
Get list of trial numbers that have Zernike analysis available ( OP2 files ) .
Returns :
JSON with list of trial numbers that have iteration folders with OP2 files
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-10 21:34:07 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study ' { study_id } ' not found " )
iter_base = study_dir / " 2_iterations "
if not iter_base . exists ( ) :
return { " study_id " : study_id , " available_trials " : [ ] , " count " : 0 }
available_trials = [ ]
for d in iter_base . iterdir ( ) :
if d . is_dir ( ) and d . name . startswith ( ' iter ' ) :
# Check for OP2 file
op2_files = list ( d . glob ( " *.op2 " ) )
if op2_files :
iter_num_str = d . name . replace ( ' iter ' , ' ' )
try :
iter_num = int ( iter_num_str )
# Map iter number to trial number (iter1 -> trial 0, etc.)
# But also keep iter_num as possibility
if iter_num != 9999 :
available_trials . append ( iter_num - 1 ) # 0-indexed trial
else :
available_trials . append ( 9999 ) # Special test iteration
except ValueError :
pass
available_trials . sort ( )
return {
" study_id " : study_id ,
" available_trials " : available_trials ,
" count " : len ( available_trials )
}
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to get available trials: { str ( e ) } " )
@router.get ( " /studies/ {study_id} /trials/ {trial_number} /zernike " )
async def get_trial_zernike ( study_id : str , trial_number : int ) :
"""
Generate or retrieve Zernike analysis HTML for a specific trial .
This endpoint generates interactive Zernike wavefront analysis for mirror
optimization trials . It produces 3 D surface residual plots , RMS metrics ,
and coefficient bar charts for each angle comparison ( 40 _vs_20 , 60 _vs_20 , 90 _vs_20 ) .
Args :
study_id : Study identifier
trial_number : Trial / iteration number
Returns :
JSON with HTML content for each comparison , or error if OP2 not found
"""
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
2025-12-10 21:34:07 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study ' { study_id } ' not found " )
# Find iteration directory
# Trial numbers in Optuna DB may differ from iteration folder numbers
# Common patterns:
# 1. iter{trial_number} - direct mapping
# 2. iter{trial_number + 1} - 0-indexed trials vs 1-indexed folders
# 3. Check for actual folder existence
iter_dir = None
possible_iter_nums = [ trial_number , trial_number + 1 ]
for iter_num in possible_iter_nums :
candidate = study_dir / " 2_iterations " / f " iter { iter_num } "
if candidate . exists ( ) :
iter_dir = candidate
break
if iter_dir is None :
raise HTTPException (
status_code = 404 ,
detail = f " No FEA results for trial { trial_number } . This trial may have used surrogate model (NN) prediction instead of full FEA simulation. Zernike analysis requires OP2 results from actual FEA runs. "
)
# Check for OP2 file BEFORE doing expensive imports
op2_files = list ( iter_dir . glob ( " *.op2 " ) )
if not op2_files :
raise HTTPException (
status_code = 404 ,
detail = f " No OP2 results file found in { iter_dir . name } . FEA may not have completed. "
)
# Only import heavy dependencies after we know we have an OP2 file
sys . path . append ( str ( Path ( __file__ ) . parent . parent . parent . parent . parent ) )
2025-12-22 21:28:16 -05:00
from optimization_engine . extractors . extract_zernike_figure import ZernikeOPDExtractor
2025-12-10 21:34:07 -05:00
from optimization_engine . extractors import ZernikeExtractor
import numpy as np
from math import factorial
import plotly . graph_objects as go
from plotly . subplots import make_subplots
from matplotlib . tri import Triangulation
2025-12-22 21:28:16 -05:00
# Also find BDF/DAT geometry file for OPD extractor
bdf_files = list ( iter_dir . glob ( " *.dat " ) ) + list ( iter_dir . glob ( " *.bdf " ) )
bdf_path = bdf_files [ 0 ] if bdf_files else None
2025-12-10 21:34:07 -05:00
# Configuration
N_MODES = 50
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
AMP = 0.5 # Reduced deformation scaling (0.5x)
PANCAKE = 3.0 # Z-axis range multiplier
2025-12-10 21:34:07 -05:00
PLOT_DOWNSAMPLE = 5000 # Reduced for faster loading
FILTER_LOW_ORDERS = 4
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
COLORSCALE = ' Turbo ' # Colorscale: 'RdBu_r', 'Viridis', 'Plasma', 'Turbo'
2025-12-10 21:34:07 -05:00
SUBCASE_MAP = {
' 1 ' : ' 90 ' , ' 2 ' : ' 20 ' , ' 3 ' : ' 40 ' , ' 4 ' : ' 60 ' ,
}
REF_SUBCASE = ' 2 '
def noll_indices ( j : int ) :
if j < 1 :
raise ValueError ( " Noll index j must be >= 1 " )
count = 0
n = 0
while True :
if n == 0 :
ms = [ 0 ]
elif n % 2 == 0 :
ms = [ 0 ] + [ m for k in range ( 1 , n / / 2 + 1 ) for m in ( - 2 * k , 2 * k ) ]
else :
ms = [ m for k in range ( 0 , ( n + 1 ) / / 2 ) for m in ( - ( 2 * k + 1 ) , ( 2 * k + 1 ) ) ]
for m in ms :
count + = 1
if count == j :
return n , m
n + = 1
def zernike_noll ( j : int , r : np . ndarray , th : np . ndarray ) - > np . ndarray :
n , m = noll_indices ( j )
R = np . zeros_like ( r )
for s in range ( ( n - abs ( m ) ) / / 2 + 1 ) :
c = ( ( - 1 ) * * s * factorial ( n - s ) /
( factorial ( s ) *
factorial ( ( n + abs ( m ) ) / / 2 - s ) *
factorial ( ( n - abs ( m ) ) / / 2 - s ) ) )
R + = c * r * * ( n - 2 * s )
if m == 0 :
return R
return R * ( np . cos ( m * th ) if m > 0 else np . sin ( - m * th ) )
def zernike_common_name ( n : int , m : int ) - > str :
names = {
( 0 , 0 ) : " Piston " , ( 1 , - 1 ) : " Tilt X " , ( 1 , 1 ) : " Tilt Y " ,
( 2 , 0 ) : " Defocus " , ( 2 , - 2 ) : " Astig 45° " , ( 2 , 2 ) : " Astig 0° " ,
( 3 , - 1 ) : " Coma X " , ( 3 , 1 ) : " Coma Y " , ( 3 , - 3 ) : " Trefoil X " , ( 3 , 3 ) : " Trefoil Y " ,
( 4 , 0 ) : " Primary Spherical " , ( 4 , - 2 ) : " Sec Astig X " , ( 4 , 2 ) : " Sec Astig Y " ,
( 4 , - 4 ) : " Quadrafoil X " , ( 4 , 4 ) : " Quadrafoil Y " ,
( 5 , - 1 ) : " Sec Coma X " , ( 5 , 1 ) : " Sec Coma Y " ,
( 5 , - 3 ) : " Sec Trefoil X " , ( 5 , 3 ) : " Sec Trefoil Y " ,
( 5 , - 5 ) : " Pentafoil X " , ( 5 , 5 ) : " Pentafoil Y " ,
( 6 , 0 ) : " Sec Spherical " ,
}
return names . get ( ( n , m ) , f " Z(n= { n } , m= { m } ) " )
def zernike_label ( j : int ) - > str :
n , m = noll_indices ( j )
return f " J { j : 02d } - { zernike_common_name ( n , m ) } "
def compute_manufacturing_metrics ( coefficients : np . ndarray ) - > dict :
""" Compute manufacturing-related aberration metrics. """
return {
' defocus_nm ' : float ( abs ( coefficients [ 3 ] ) ) , # J4
' astigmatism_rms ' : float ( np . sqrt ( coefficients [ 4 ] * * 2 + coefficients [ 5 ] * * 2 ) ) , # J5+J6
' coma_rms ' : float ( np . sqrt ( coefficients [ 6 ] * * 2 + coefficients [ 7 ] * * 2 ) ) , # J7+J8
' trefoil_rms ' : float ( np . sqrt ( coefficients [ 8 ] * * 2 + coefficients [ 9 ] * * 2 ) ) , # J9+J10
' spherical_nm ' : float ( abs ( coefficients [ 10 ] ) ) if len ( coefficients ) > 10 else 0.0 , # J11
}
def compute_rms_filter_j1to3 ( X , Y , W_nm , coefficients , R ) :
""" Compute RMS with J1-J3 filtered (keeping defocus for optician workload). """
Xc = X - np . mean ( X )
Yc = Y - np . mean ( Y )
r = np . hypot ( Xc / R , Yc / R )
th = np . arctan2 ( Yc , Xc )
Z_j1to3 = np . column_stack ( [ zernike_noll ( j , r , th ) for j in range ( 1 , 4 ) ] )
W_filter_j1to3 = W_nm - Z_j1to3 @ coefficients [ : 3 ]
return float ( np . sqrt ( np . mean ( W_filter_j1to3 * * 2 ) ) )
def generate_zernike_html (
title : str ,
X : np . ndarray ,
Y : np . ndarray ,
W_nm : np . ndarray ,
coefficients : np . ndarray ,
rms_global : float ,
rms_filtered : float ,
ref_title : str = " 20 deg " ,
abs_pair = None ,
is_manufacturing : bool = False ,
mfg_metrics : dict = None ,
correction_metrics : dict = None
) - > str :
""" Generate HTML string for Zernike visualization with full tables. """
# Compute residual surface (filtered)
Xc = X - np . mean ( X )
Yc = Y - np . mean ( Y )
R = float ( np . max ( np . hypot ( Xc , Yc ) ) )
r = np . hypot ( Xc / R , Yc / R )
th = np . arctan2 ( Yc , Xc )
Z = np . column_stack ( [ zernike_noll ( j , r , th ) for j in range ( 1 , N_MODES + 1 ) ] )
W_res_filt = W_nm - Z [ : , : FILTER_LOW_ORDERS ] . dot ( coefficients [ : FILTER_LOW_ORDERS ] )
# Compute J1-J3 filtered RMS (optician workload metric)
rms_filter_j1to3 = compute_rms_filter_j1to3 ( X , Y , W_nm , coefficients , R )
# Downsample for display
n = len ( X )
if n > PLOT_DOWNSAMPLE :
rng = np . random . default_rng ( 42 )
sel = rng . choice ( n , size = PLOT_DOWNSAMPLE , replace = False )
Xp , Yp , Wp = X [ sel ] , Y [ sel ] , W_res_filt [ sel ]
else :
Xp , Yp , Wp = X , Y , W_res_filt
res_amp = AMP * Wp
max_amp = float ( np . max ( np . abs ( res_amp ) ) ) if res_amp . size else 1.0
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
# Create smooth shaded SURFACE mesh with lighting
2025-12-10 21:34:07 -05:00
surface_trace = None
try :
tri = Triangulation ( Xp , Yp )
if tri . triangles is not None and len ( tri . triangles ) > 0 :
i_idx , j_idx , k_idx = tri . triangles . T
surface_trace = go . Mesh3d (
x = Xp . tolist ( ) , y = Yp . tolist ( ) , z = res_amp . tolist ( ) ,
i = i_idx . tolist ( ) , j = j_idx . tolist ( ) , k = k_idx . tolist ( ) ,
intensity = res_amp . tolist ( ) ,
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
colorscale = COLORSCALE ,
opacity = 1.0 ,
flatshading = False , # Smooth shading
lighting = dict (
ambient = 0.4 ,
diffuse = 0.8 ,
specular = 0.3 ,
roughness = 0.5 ,
fresnel = 0.2
) ,
lightposition = dict ( x = 100 , y = 200 , z = 300 ) ,
2025-12-10 21:34:07 -05:00
showscale = True ,
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
colorbar = dict (
title = dict ( text = " Residual (nm) " , side = ' right ' ) ,
thickness = 15 ,
len = 0.6 ,
tickformat = " .1f "
) ,
hovertemplate = " X: % {x:.1f} <br>Y: % {y:.1f} <br>Residual: % {z:.2f} nm<extra></extra> "
2025-12-10 21:34:07 -05:00
)
except Exception as e :
print ( f " Triangulation failed: { e } " )
labels = [ zernike_label ( j ) for j in range ( 1 , N_MODES + 1 ) ]
coeff_abs = np . abs ( coefficients )
mfg = compute_manufacturing_metrics ( coefficients )
# Determine layout based on whether this is manufacturing (90 deg) view
if is_manufacturing and mfg_metrics and correction_metrics :
# Manufacturing view: 5 rows
fig = make_subplots (
rows = 5 , cols = 1 ,
specs = [ [ { " type " : " scene " } ] ,
[ { " type " : " table " } ] ,
[ { " type " : " table " } ] ,
[ { " type " : " table " } ] ,
[ { " type " : " xy " } ] ] ,
row_heights = [ 0.35 , 0.10 , 0.15 , 0.15 , 0.25 ] ,
vertical_spacing = 0.025 ,
subplot_titles = [
f " <b>Surface Residual (relative to { ref_title } )</b> " ,
" <b>RMS Metrics</b> " ,
" <b>Mode Magnitudes (Absolute 90 deg)</b> " ,
" <b>Pre-Correction (90 deg - 20 deg)</b> " ,
f " <b>Zernike Coefficients ( { N_MODES } modes)</b> "
]
)
else :
# Standard relative view: 4 rows with full coefficient table
fig = make_subplots (
rows = 4 , cols = 1 ,
specs = [ [ { " type " : " scene " } ] ,
[ { " type " : " table " } ] ,
[ { " type " : " table " } ] ,
[ { " type " : " xy " } ] ] ,
row_heights = [ 0.40 , 0.12 , 0.28 , 0.20 ] ,
vertical_spacing = 0.03 ,
subplot_titles = [
f " <b>Surface Residual (relative to { ref_title } )</b> " ,
" <b>RMS Metrics</b> " ,
f " <b>Zernike Coefficients ( { N_MODES } modes)</b> " ,
" <b>Top 20 |Zernike Coefficients| (nm)</b> "
]
)
# Add surface mesh (or fallback to scatter)
if surface_trace is not None :
fig . add_trace ( surface_trace , row = 1 , col = 1 )
else :
# Fallback to scatter if triangulation failed
fig . add_trace ( go . Scatter3d (
x = Xp . tolist ( ) , y = Yp . tolist ( ) , z = res_amp . tolist ( ) ,
mode = ' markers ' ,
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
marker = dict ( size = 2 , color = res_amp . tolist ( ) , colorscale = COLORSCALE , showscale = True ) ,
2025-12-10 21:34:07 -05:00
showlegend = False
) , row = 1 , col = 1 )
fig . update_scenes (
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
camera = dict (
eye = dict ( x = 1.2 , y = 1.2 , z = 0.8 ) ,
up = dict ( x = 0 , y = 0 , z = 1 )
) ,
xaxis = dict (
title = " X (mm) " ,
showgrid = True ,
gridcolor = ' rgba(128,128,128,0.3) ' ,
showbackground = True ,
backgroundcolor = ' rgba(240,240,240,0.9) '
) ,
yaxis = dict (
title = " Y (mm) " ,
showgrid = True ,
gridcolor = ' rgba(128,128,128,0.3) ' ,
showbackground = True ,
backgroundcolor = ' rgba(240,240,240,0.9) '
) ,
zaxis = dict (
title = " Residual (nm) " ,
range = [ - max_amp * PANCAKE , max_amp * PANCAKE ] ,
showgrid = True ,
gridcolor = ' rgba(128,128,128,0.3) ' ,
showbackground = True ,
backgroundcolor = ' rgba(230,230,250,0.9) '
) ,
aspectmode = ' manual ' ,
aspectratio = dict ( x = 1 , y = 1 , z = 0.4 )
2025-12-10 21:34:07 -05:00
)
# Row 2: RMS table with all metrics
if abs_pair is not None :
abs_global , abs_filtered = abs_pair
fig . add_trace ( go . Table (
header = dict (
values = [ " <b>Metric</b> " , " <b>Relative (nm)</b> " , " <b>Absolute (nm)</b> " ] ,
align = " left " ,
fill_color = ' rgb(55, 83, 109) ' ,
font = dict ( color = ' white ' , size = 12 )
) ,
cells = dict (
values = [
[ " Global RMS " , " Filtered RMS (J1-J4) " , " Filtered RMS (J1-J3, w/ defocus) " ] ,
[ f " { rms_global : .2f } " , f " { rms_filtered : .2f } " , f " { rms_filter_j1to3 : .2f } " ] ,
[ f " { abs_global : .2f } " , f " { abs_filtered : .2f } " , " - " ] ,
] ,
align = " left " ,
fill_color = ' rgb(243, 243, 243) '
)
) , row = 2 , col = 1 )
else :
fig . add_trace ( go . Table (
header = dict (
values = [ " <b>Metric</b> " , " <b>Value (nm)</b> " ] ,
align = " left " ,
fill_color = ' rgb(55, 83, 109) ' ,
font = dict ( color = ' white ' , size = 12 )
) ,
cells = dict (
values = [
[ " Global RMS " , " Filtered RMS (J1-J4) " , " Filtered RMS (J1-J3, w/ defocus) " ] ,
[ f " { rms_global : .2f } " , f " { rms_filtered : .2f } " , f " { rms_filter_j1to3 : .2f } " ]
] ,
align = " left " ,
fill_color = ' rgb(243, 243, 243) '
)
) , row = 2 , col = 1 )
if is_manufacturing and mfg_metrics and correction_metrics :
# Row 3: Mode magnitudes at 90 deg (absolute)
fig . add_trace ( go . Table (
header = dict (
values = [ " <b>Mode</b> " , " <b>Value (nm)</b> " ] ,
align = " left " ,
fill_color = ' rgb(55, 83, 109) ' ,
font = dict ( color = ' white ' , size = 11 )
) ,
cells = dict (
values = [
[ " Defocus (J4) " , " Astigmatism (J5+J6) " , " Coma (J7+J8) " , " Trefoil (J9+J10) " , " Spherical (J11) " ] ,
[ f " { mfg_metrics [ ' defocus_nm ' ] : .2f } " , f " { mfg_metrics [ ' astigmatism_rms ' ] : .2f } " ,
f " { mfg_metrics [ ' coma_rms ' ] : .2f } " , f " { mfg_metrics [ ' trefoil_rms ' ] : .2f } " ,
f " { mfg_metrics [ ' spherical_nm ' ] : .2f } " ]
] ,
align = " left " ,
fill_color = ' rgb(243, 243, 243) '
)
) , row = 3 , col = 1 )
# Row 4: Pre-correction (90 deg - 20 deg)
fig . add_trace ( go . Table (
header = dict (
values = [ " <b>Correction Mode</b> " , " <b>Value (nm)</b> " ] ,
align = " left " ,
fill_color = ' rgb(55, 83, 109) ' ,
font = dict ( color = ' white ' , size = 11 )
) ,
cells = dict (
values = [
[ " Total RMS (J1-J3 filter) " , " Defocus (J4) " , " Astigmatism (J5+J6) " , " Coma (J7+J8) " ] ,
[ f " { correction_metrics . get ( ' rms_filter_j1to3 ' , 0 ) : .2f } " ,
f " { correction_metrics [ ' defocus_nm ' ] : .2f } " ,
f " { correction_metrics [ ' astigmatism_rms ' ] : .2f } " ,
f " { correction_metrics [ ' coma_rms ' ] : .2f } " ]
] ,
align = " left " ,
fill_color = ' rgb(243, 243, 243) '
)
) , row = 4 , col = 1 )
# Row 5: Bar chart
sorted_idx = np . argsort ( coeff_abs ) [ : : - 1 ] [ : 20 ]
fig . add_trace (
go . Bar (
x = [ float ( coeff_abs [ i ] ) for i in sorted_idx ] ,
y = [ labels [ i ] for i in sorted_idx ] ,
orientation = ' h ' ,
marker_color = ' rgb(55, 83, 109) ' ,
hovertemplate = " % {y} <br>|Coeff| = % {x:.3f} nm<extra></extra> " ,
showlegend = False
) ,
row = 5 , col = 1
)
else :
# Row 3: Full coefficient table
fig . add_trace ( go . Table (
header = dict (
values = [ " <b>Noll j</b> " , " <b>Mode Name</b> " , " <b>Coeff (nm)</b> " , " <b>|Coeff| (nm)</b> " ] ,
align = " left " ,
fill_color = ' rgb(55, 83, 109) ' ,
font = dict ( color = ' white ' , size = 11 )
) ,
cells = dict (
values = [
list ( range ( 1 , N_MODES + 1 ) ) ,
labels ,
[ f " { c : +.3f } " for c in coefficients ] ,
[ f " { abs ( c ) : .3f } " for c in coefficients ]
] ,
align = " left " ,
fill_color = ' rgb(243, 243, 243) ' ,
font = dict ( size = 10 ) ,
height = 22
)
) , row = 3 , col = 1 )
# Row 4: Bar chart - top 20 modes by magnitude
sorted_idx = np . argsort ( coeff_abs ) [ : : - 1 ] [ : 20 ]
fig . add_trace (
go . Bar (
x = [ float ( coeff_abs [ i ] ) for i in sorted_idx ] ,
y = [ labels [ i ] for i in sorted_idx ] ,
orientation = ' h ' ,
marker_color = ' rgb(55, 83, 109) ' ,
hovertemplate = " % {y} <br>|Coeff| = % {x:.3f} nm<extra></extra> " ,
showlegend = False
) ,
row = 4 , col = 1
)
fig . update_layout (
width = 1400 ,
height = 1800 if is_manufacturing else 1600 ,
margin = dict ( t = 80 , b = 20 , l = 20 , r = 20 ) ,
title = dict (
text = f " <b> { title } </b> " ,
font = dict ( size = 20 ) ,
x = 0.5
) ,
paper_bgcolor = ' white ' ,
plot_bgcolor = ' white '
)
return fig . to_html ( include_plotlyjs = ' cdn ' , full_html = True )
2025-12-22 21:28:16 -05:00
# =====================================================================
# NEW: Use OPD method (accounts for lateral X,Y displacement)
# =====================================================================
2025-12-10 21:34:07 -05:00
op2_path = op2_files [ 0 ]
2025-12-22 21:28:16 -05:00
# Try OPD extractor first (more accurate), fall back to Standard if no BDF
use_opd = bdf_path is not None
if use_opd :
try :
opd_extractor = ZernikeOPDExtractor (
str ( op2_path ) ,
bdf_path = str ( bdf_path ) ,
n_modes = N_MODES ,
filter_orders = FILTER_LOW_ORDERS
)
except Exception as e :
print ( f " OPD extractor failed, falling back to Standard: { e } " )
use_opd = False
2025-12-10 21:34:07 -05:00
2025-12-22 21:28:16 -05:00
# Also create Standard extractor for comparison
std_extractor = ZernikeExtractor ( str ( op2_path ) , displacement_unit = ' mm ' , n_modes = N_MODES )
2025-12-10 21:34:07 -05:00
2025-12-22 21:28:16 -05:00
def generate_dual_method_html (
title : str ,
target_sc : str ,
ref_sc : str ,
is_manufacturing : bool = False
) - > tuple :
""" Generate HTML with OPD method and displacement component views.
Returns : ( html_content , rms_global_opd , rms_filtered_opd , lateral_stats )
"""
target_angle = SUBCASE_MAP . get ( target_sc , target_sc )
ref_angle = SUBCASE_MAP . get ( ref_sc , ref_sc )
2025-12-10 21:34:07 -05:00
2025-12-22 21:28:16 -05:00
# Extract using OPD method (primary)
if use_opd :
opd_rel = opd_extractor . extract_relative ( target_sc , ref_sc )
opd_abs = opd_extractor . extract_subcase ( target_sc )
else :
opd_rel = None
opd_abs = None
# Extract using Standard method (for comparison)
std_rel = std_extractor . extract_relative ( target_sc , ref_sc , include_coefficients = True )
std_abs = std_extractor . extract_subcase ( target_sc , include_coefficients = True )
# Get OPD data with full arrays for visualization
if use_opd :
opd_data = opd_extractor . _build_figure_opd_data ( target_sc )
opd_ref_data = opd_extractor . _build_figure_opd_data ( ref_sc )
# Build relative displacement arrays (node-by-node)
ref_map = { int ( nid ) : i for i , nid in enumerate ( opd_ref_data [ ' node_ids ' ] ) }
X_list , Y_list , WFE_list = [ ] , [ ] , [ ]
dx_list , dy_list , dz_list = [ ] , [ ] , [ ]
for i , nid in enumerate ( opd_data [ ' node_ids ' ] ) :
nid = int ( nid )
if nid not in ref_map :
continue
ref_idx = ref_map [ nid ]
# Use deformed coordinates from OPD
X_list . append ( opd_data [ ' x_deformed ' ] [ i ] )
Y_list . append ( opd_data [ ' y_deformed ' ] [ i ] )
WFE_list . append ( opd_data [ ' wfe_nm ' ] [ i ] - opd_ref_data [ ' wfe_nm ' ] [ ref_idx ] )
# Relative displacements (target - reference)
dx_list . append ( opd_data [ ' dx ' ] [ i ] - opd_ref_data [ ' dx ' ] [ ref_idx ] )
dy_list . append ( opd_data [ ' dy ' ] [ i ] - opd_ref_data [ ' dy ' ] [ ref_idx ] )
dz_list . append ( opd_data [ ' dz ' ] [ i ] - opd_ref_data [ ' dz ' ] [ ref_idx ] )
X = np . array ( X_list )
Y = np . array ( Y_list )
W = np . array ( WFE_list )
dx = np . array ( dx_list ) * 1000.0 # mm to µm
dy = np . array ( dy_list ) * 1000.0
dz = np . array ( dz_list ) * 1000.0
# Lateral displacement magnitude
lateral_um = np . sqrt ( dx * * 2 + dy * * 2 )
max_lateral = float ( np . max ( np . abs ( lateral_um ) ) )
rms_lateral = float ( np . sqrt ( np . mean ( lateral_um * * 2 ) ) )
rms_global_opd = opd_rel [ ' relative_global_rms_nm ' ]
rms_filtered_opd = opd_rel [ ' relative_filtered_rms_nm ' ]
coefficients = np . array ( opd_rel . get ( ' delta_coefficients ' , std_rel [ ' coefficients ' ] ) )
else :
# Fallback to Standard method arrays
target_disp = std_extractor . displacements [ target_sc ]
ref_disp = std_extractor . displacements [ ref_sc ]
ref_map = { int ( nid ) : i for i , nid in enumerate ( ref_disp [ ' node_ids ' ] ) }
2025-12-10 21:34:07 -05:00
2025-12-22 21:28:16 -05:00
X_list , Y_list , W_list = [ ] , [ ] , [ ]
dx_list , dy_list , dz_list = [ ] , [ ] , [ ]
2025-12-10 21:34:07 -05:00
2025-12-22 21:28:16 -05:00
for i , nid in enumerate ( target_disp [ ' node_ids ' ] ) :
nid = int ( nid )
if nid not in ref_map :
continue
geo = std_extractor . node_geometry . get ( nid )
if geo is None :
continue
ref_idx = ref_map [ nid ]
2025-12-10 21:34:07 -05:00
2025-12-22 21:28:16 -05:00
X_list . append ( geo [ 0 ] )
Y_list . append ( geo [ 1 ] )
2025-12-10 21:34:07 -05:00
2025-12-22 21:28:16 -05:00
target_wfe = target_disp [ ' disp ' ] [ i , 2 ] * std_extractor . wfe_factor
ref_wfe = ref_disp [ ' disp ' ] [ ref_idx , 2 ] * std_extractor . wfe_factor
W_list . append ( target_wfe - ref_wfe )
2025-12-10 21:34:07 -05:00
2025-12-22 21:28:16 -05:00
# Relative displacements (mm to µm)
dx_list . append ( ( target_disp [ ' disp ' ] [ i , 0 ] - ref_disp [ ' disp ' ] [ ref_idx , 0 ] ) * 1000.0 )
dy_list . append ( ( target_disp [ ' disp ' ] [ i , 1 ] - ref_disp [ ' disp ' ] [ ref_idx , 1 ] ) * 1000.0 )
dz_list . append ( ( target_disp [ ' disp ' ] [ i , 2 ] - ref_disp [ ' disp ' ] [ ref_idx , 2 ] ) * 1000.0 )
2025-12-10 21:34:07 -05:00
2025-12-22 21:28:16 -05:00
X = np . array ( X_list )
Y = np . array ( Y_list )
W = np . array ( W_list )
dx = np . array ( dx_list )
dy = np . array ( dy_list )
dz = np . array ( dz_list )
2025-12-10 21:34:07 -05:00
2025-12-22 21:28:16 -05:00
lateral_um = np . sqrt ( dx * * 2 + dy * * 2 )
max_lateral = float ( np . max ( np . abs ( lateral_um ) ) )
rms_lateral = float ( np . sqrt ( np . mean ( lateral_um * * 2 ) ) )
2025-12-10 21:34:07 -05:00
2025-12-22 21:28:16 -05:00
rms_global_opd = std_rel [ ' relative_global_rms_nm ' ]
rms_filtered_opd = std_rel [ ' relative_filtered_rms_nm ' ]
coefficients = np . array ( std_rel [ ' coefficients ' ] )
2025-12-10 21:34:07 -05:00
2025-12-22 21:28:16 -05:00
# Standard method RMS values
rms_global_std = std_rel [ ' relative_global_rms_nm ' ]
rms_filtered_std = std_rel [ ' relative_filtered_rms_nm ' ]
# Compute residual surface
Xc = X - np . mean ( X )
Yc = Y - np . mean ( Y )
R = float ( np . max ( np . hypot ( Xc , Yc ) ) )
r = np . hypot ( Xc / R , Yc / R )
th = np . arctan2 ( Yc , Xc )
Z_basis = np . column_stack ( [ zernike_noll ( j , r , th ) for j in range ( 1 , N_MODES + 1 ) ] )
W_res_filt = W - Z_basis [ : , : FILTER_LOW_ORDERS ] . dot ( coefficients [ : FILTER_LOW_ORDERS ] )
# Downsample for display
n = len ( X )
if n > PLOT_DOWNSAMPLE :
rng = np . random . default_rng ( 42 )
sel = rng . choice ( n , size = PLOT_DOWNSAMPLE , replace = False )
Xp , Yp = X [ sel ] , Y [ sel ]
Wp = W_res_filt [ sel ]
dxp , dyp , dzp = dx [ sel ] , dy [ sel ] , dz [ sel ]
else :
Xp , Yp , Wp = X , Y , W_res_filt
dxp , dyp , dzp = dx , dy , dz
res_amp = AMP * Wp
max_amp = float ( np . max ( np . abs ( res_amp ) ) ) if res_amp . size else 1.0
2025-12-10 21:34:07 -05:00
2025-12-22 21:28:16 -05:00
# Helper to build mesh trace
def build_mesh_trace ( Zp , colorscale , colorbar_title , unit ) :
try :
tri = Triangulation ( Xp , Yp )
if tri . triangles is not None and len ( tri . triangles ) > 0 :
i_idx , j_idx , k_idx = tri . triangles . T
return go . Mesh3d (
x = Xp . tolist ( ) , y = Yp . tolist ( ) , z = Zp . tolist ( ) ,
i = i_idx . tolist ( ) , j = j_idx . tolist ( ) , k = k_idx . tolist ( ) ,
intensity = Zp . tolist ( ) ,
colorscale = colorscale ,
opacity = 1.0 ,
flatshading = False ,
lighting = dict ( ambient = 0.4 , diffuse = 0.8 , specular = 0.3 , roughness = 0.5 , fresnel = 0.2 ) ,
lightposition = dict ( x = 100 , y = 200 , z = 300 ) ,
showscale = True ,
colorbar = dict ( title = dict ( text = colorbar_title , side = ' right ' ) , thickness = 15 , len = 0.5 ) ,
hovertemplate = f " X: % {{ x:.1f }} <br>Y: % {{ y:.1f }} <br> { unit } : % {{ z:.3f }} <extra></extra> "
)
except Exception :
pass
return go . Scatter3d (
x = Xp . tolist ( ) , y = Yp . tolist ( ) , z = Zp . tolist ( ) ,
mode = ' markers ' , marker = dict ( size = 2 , color = Zp . tolist ( ) , colorscale = colorscale , showscale = True )
2025-12-10 21:34:07 -05:00
)
2025-12-22 21:28:16 -05:00
# Build traces for each view
trace_wfe = build_mesh_trace ( res_amp , COLORSCALE , " WFE (nm) " , " WFE nm " )
trace_dx = build_mesh_trace ( dxp , ' RdBu_r ' , " ΔX (µm) " , " ΔX µm " )
trace_dy = build_mesh_trace ( dyp , ' RdBu_r ' , " ΔY (µm) " , " ΔY µm " )
trace_dz = build_mesh_trace ( dzp , ' RdBu_r ' , " ΔZ (µm) " , " ΔZ µm " )
# Create figure with dropdown to switch views
fig = go . Figure ( )
# Add all traces (only WFE visible initially)
trace_wfe . visible = True
trace_dx . visible = False
trace_dy . visible = False
trace_dz . visible = False
fig . add_trace ( trace_wfe )
fig . add_trace ( trace_dx )
fig . add_trace ( trace_dy )
fig . add_trace ( trace_dz )
# Dropdown menu for view selection
fig . update_layout (
updatemenus = [
dict (
type = " buttons " ,
direction = " right " ,
x = 0.0 , y = 1.12 ,
xanchor = " left " ,
showactive = True ,
buttons = [
dict ( label = " WFE (nm) " , method = " update " ,
args = [ { " visible " : [ True , False , False , False ] } ] ) ,
dict ( label = " ΔX (µm) " , method = " update " ,
args = [ { " visible " : [ False , True , False , False ] } ] ) ,
dict ( label = " ΔY (µm) " , method = " update " ,
args = [ { " visible " : [ False , False , True , False ] } ] ) ,
dict ( label = " ΔZ (µm) " , method = " update " ,
args = [ { " visible " : [ False , False , False , True ] } ] ) ,
] ,
font = dict ( size = 12 ) ,
pad = dict ( r = 10 , t = 10 ) ,
)
]
)
# Compute method difference
pct_diff = 100.0 * ( rms_filtered_opd - rms_filtered_std ) / rms_filtered_std if rms_filtered_std > 0 else 0.0
# Annotations for metrics
method_label = " OPD (X,Y,Z) " if use_opd else " Standard (Z-only) "
annotations_text = f """
< b > Method : < / b > { method_label } { ' ← More Accurate ' if use_opd else ' (BDF not found) ' }
< b > RMS Metrics ( Filtered J1 - J4 ) : < / b >
• OPD : { rms_filtered_opd : .2 f } nm
• Standard : { rms_filtered_std : .2 f } nm
• Δ : { pct_diff : + .1 f } %
< b > Lateral Displacement : < / b >
• Max : { max_lateral : .3 f } µm
• RMS : { rms_lateral : .3 f } µm
< b > Displacement RMS : < / b >
• ΔX : { float ( np . sqrt ( np . mean ( dx * * 2 ) ) ) : .3 f } µm
• ΔY : { float ( np . sqrt ( np . mean ( dy * * 2 ) ) ) : .3 f } µm
• ΔZ : { float ( np . sqrt ( np . mean ( dz * * 2 ) ) ) : .3 f } µm
"""
# Z-axis range for different views
max_disp = max ( float ( np . max ( np . abs ( dxp ) ) ) , float ( np . max ( np . abs ( dyp ) ) ) , float ( np . max ( np . abs ( dzp ) ) ) , 0.1 )
fig . update_layout (
scene = dict (
camera = dict ( eye = dict ( x = 1.2 , y = 1.2 , z = 0.8 ) , up = dict ( x = 0 , y = 0 , z = 1 ) ) ,
xaxis = dict ( title = " X (mm) " , showgrid = True , gridcolor = ' rgba(128,128,128,0.3) ' ,
showbackground = True , backgroundcolor = ' rgba(240,240,240,0.9) ' ) ,
yaxis = dict ( title = " Y (mm) " , showgrid = True , gridcolor = ' rgba(128,128,128,0.3) ' ,
showbackground = True , backgroundcolor = ' rgba(240,240,240,0.9) ' ) ,
zaxis = dict ( title = " Value " , showgrid = True , gridcolor = ' rgba(128,128,128,0.3) ' ,
showbackground = True , backgroundcolor = ' rgba(230,230,250,0.9) ' ) ,
aspectmode = ' manual ' ,
aspectratio = dict ( x = 1 , y = 1 , z = 0.4 )
) ,
width = 1400 ,
height = 900 ,
margin = dict ( t = 120 , b = 20 , l = 20 , r = 20 ) ,
title = dict (
text = f " <b> { title } </b><br><sup>Click buttons to switch: WFE, ΔX, ΔY, ΔZ</sup> " ,
font = dict ( size = 18 ) ,
x = 0.5
) ,
paper_bgcolor = ' white ' ,
plot_bgcolor = ' white ' ,
annotations = [
dict (
text = annotations_text . replace ( ' \n ' , ' <br> ' ) ,
xref = " paper " , yref = " paper " ,
x = 1.02 , y = 0.98 ,
xanchor = " left " , yanchor = " top " ,
showarrow = False ,
font = dict ( family = " monospace " , size = 11 ) ,
align = " left " ,
bgcolor = " rgba(255,255,255,0.9) " ,
bordercolor = " rgba(0,0,0,0.3) " ,
borderwidth = 1 ,
borderpad = 8
) ,
dict (
text = " <b>View:</b> " ,
xref = " paper " , yref = " paper " ,
x = 0.0 , y = 1.15 ,
xanchor = " left " , yanchor = " top " ,
showarrow = False ,
font = dict ( size = 12 )
)
]
)
html_content = fig . to_html ( include_plotlyjs = ' cdn ' , full_html = True )
return ( html_content , rms_global_opd , rms_filtered_opd , {
' max_lateral_um ' : max_lateral ,
' rms_lateral_um ' : rms_lateral ,
' method ' : ' opd ' if use_opd else ' standard ' ,
' rms_std ' : rms_filtered_std ,
' pct_diff ' : pct_diff
} )
# Generate results for each comparison
results = { }
comparisons = [
( ' 3 ' , ' 2 ' , ' 40_vs_20 ' , ' 40 deg vs 20 deg ' ) ,
( ' 4 ' , ' 2 ' , ' 60_vs_20 ' , ' 60 deg vs 20 deg ' ) ,
( ' 1 ' , ' 2 ' , ' 90_vs_20 ' , ' 90 deg vs 20 deg (manufacturing) ' ) ,
]
for target_sc , ref_sc , key , title_suffix in comparisons :
if target_sc not in std_extractor . displacements :
continue
target_angle = SUBCASE_MAP . get ( target_sc , target_sc )
ref_angle = SUBCASE_MAP . get ( ref_sc , ref_sc )
is_mfg = ( key == ' 90_vs_20 ' )
html_content , rms_global , rms_filtered , lateral_stats = generate_dual_method_html (
title = f " iter { trial_number } : { target_angle } ° vs { ref_angle } ° " ,
target_sc = target_sc ,
ref_sc = ref_sc ,
is_manufacturing = is_mfg
2025-12-10 21:34:07 -05:00
)
results [ key ] = {
" html " : html_content ,
2025-12-22 21:28:16 -05:00
" rms_global " : rms_global ,
" rms_filtered " : rms_filtered ,
" title " : f " { target_angle } ° vs { ref_angle } ° " ,
" method " : lateral_stats [ ' method ' ] ,
" rms_std " : lateral_stats [ ' rms_std ' ] ,
" pct_diff " : lateral_stats [ ' pct_diff ' ] ,
" max_lateral_um " : lateral_stats [ ' max_lateral_um ' ] ,
" rms_lateral_um " : lateral_stats [ ' rms_lateral_um ' ]
2025-12-10 21:34:07 -05:00
}
if not results :
raise HTTPException (
status_code = 500 ,
detail = " Failed to generate Zernike analysis. Check if subcases are available. "
)
return {
" study_id " : study_id ,
" trial_number " : trial_number ,
" comparisons " : results ,
2025-12-22 21:28:16 -05:00
" available_comparisons " : list ( results . keys ( ) ) ,
" method " : " opd " if use_opd else " standard "
2025-12-10 21:34:07 -05:00
}
except HTTPException :
raise
except Exception as e :
import traceback
traceback . print_exc ( )
raise HTTPException ( status_code = 500 , detail = f " Failed to generate Zernike analysis: { str ( e ) } " )
feat: Add Analysis page, run comparison, notifications, and config editor
Dashboard enhancements:
- Add Analysis page with tabs: Overview, Parameters, Pareto, Correlations, Constraints, Surrogate, Runs
- Add PlotlyCorrelationHeatmap for parameter-objective correlation analysis
- Add PlotlyFeasibilityChart for constraint satisfaction visualization
- Add PlotlySurrogateQuality for FEA vs NN prediction comparison
- Add PlotlyRunComparison for comparing optimization runs within a study
Real-time improvements:
- Replace watchdog file-watching with SQLite database polling for better Windows reliability
- Add DatabasePoller class with 2-second polling interval
- Enhanced WebSocket messages: trial_completed, new_best, pareto_update, progress
Desktop notifications:
- Add useNotifications hook using Web Notifications API
- Add NotificationSettings toggle component
- Notify users when new best solutions are found
Config editor:
- Add PUT /studies/{study_id}/config endpoint with auto-backup
- Add ConfigEditor modal with tabs: General, Variables, Objectives, Settings, JSON
- Prevents editing while optimization is running
Enhanced Pareto visualization:
- Add dark mode styling with transparent backgrounds
- Add stats bar showing Pareto, FEA, NN, and infeasible counts
- Add Pareto front connecting line for 2D view
- Add table showing top 10 Pareto-optimal solutions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 19:57:20 -05:00
@router.get ( " /studies/ {study_id} /export/ {format} " )
async def export_study_data ( study_id : str , format : str ) :
""" Export study data in various formats: csv, json, excel """
try :
feat: Add Study Insights module (SYS_16) for physics visualizations
Introduces a new plugin architecture for study-specific physics
visualizations, separating "optimizer perspective" (Analysis) from
"engineer perspective" (Insights).
New module: optimization_engine/insights/
- base.py: StudyInsight base class, InsightConfig, InsightResult, registry
- zernike_wfe.py: Mirror WFE with 3D surface and Zernike decomposition
- stress_field.py: Von Mises stress contours with safety factors
- modal_analysis.py: Natural frequencies and mode shapes
- thermal_field.py: Temperature distribution visualization
- design_space.py: Parameter-objective landscape exploration
Features:
- 5 insight types: zernike_wfe, stress_field, modal, thermal, design_space
- CLI: python -m optimization_engine.insights generate <study>
- Standalone HTML generation with Plotly
- Enhanced Zernike viz: Turbo colorscale, smooth shading, 0.5x AMP
- Dashboard API fix: Added include_coefficients param to extract_relative()
Documentation:
- docs/protocols/system/SYS_16_STUDY_INSIGHTS.md
- Updated ATOMIZER_CONTEXT.md (v1.7)
- Updated 01_CHEATSHEET.md with insights section
Tools:
- tools/zernike_html_generator.py: Standalone WFE HTML generator
- tools/analyze_wfe.bat: Double-click to analyze OP2 files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 13:46:28 -05:00
study_dir = resolve_study_path ( study_id )
feat: Add Analysis page, run comparison, notifications, and config editor
Dashboard enhancements:
- Add Analysis page with tabs: Overview, Parameters, Pareto, Correlations, Constraints, Surrogate, Runs
- Add PlotlyCorrelationHeatmap for parameter-objective correlation analysis
- Add PlotlyFeasibilityChart for constraint satisfaction visualization
- Add PlotlySurrogateQuality for FEA vs NN prediction comparison
- Add PlotlyRunComparison for comparing optimization runs within a study
Real-time improvements:
- Replace watchdog file-watching with SQLite database polling for better Windows reliability
- Add DatabasePoller class with 2-second polling interval
- Enhanced WebSocket messages: trial_completed, new_best, pareto_update, progress
Desktop notifications:
- Add useNotifications hook using Web Notifications API
- Add NotificationSettings toggle component
- Notify users when new best solutions are found
Config editor:
- Add PUT /studies/{study_id}/config endpoint with auto-backup
- Add ConfigEditor modal with tabs: General, Variables, Objectives, Settings, JSON
- Prevents editing while optimization is running
Enhanced Pareto visualization:
- Add dark mode styling with transparent backgrounds
- Add stats bar showing Pareto, FEA, NN, and infeasible counts
- Add Pareto front connecting line for 2D view
- Add table showing top 10 Pareto-optimal solutions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 19:57:20 -05:00
if not study_dir . exists ( ) :
raise HTTPException ( status_code = 404 , detail = f " Study ' { study_id } ' not found " )
results_dir = get_results_dir ( study_dir )
db_path = results_dir / " study.db "
if not db_path . exists ( ) :
raise HTTPException ( status_code = 404 , detail = " No study data available " )
conn = sqlite3 . connect ( str ( db_path ) )
conn . row_factory = sqlite3 . Row
cursor = conn . cursor ( )
# Get all completed trials with their params and values
cursor . execute ( """
SELECT t . trial_id , t . number , tv . value as objective
FROM trials t
JOIN trial_values tv ON t . trial_id = tv . trial_id
WHERE t . state = ' COMPLETE '
ORDER BY t . number
""" )
trials_data = [ ]
for row in cursor . fetchall ( ) :
trial_id = row [ ' trial_id ' ]
# Get params
cursor . execute ( """
SELECT param_name , param_value
FROM trial_params
WHERE trial_id = ?
""" , (trial_id,))
params = { r [ ' param_name ' ] : r [ ' param_value ' ] for r in cursor . fetchall ( ) }
# Get user attrs
cursor . execute ( """
SELECT key , value_json
FROM trial_user_attributes
WHERE trial_id = ?
""" , (trial_id,))
user_attrs = { }
for r in cursor . fetchall ( ) :
try :
user_attrs [ r [ ' key ' ] ] = json . loads ( r [ ' value_json ' ] )
except :
user_attrs [ r [ ' key ' ] ] = r [ ' value_json ' ]
trials_data . append ( {
" trial_number " : row [ ' number ' ] ,
" objective " : row [ ' objective ' ] ,
" params " : params ,
" user_attrs " : user_attrs
} )
conn . close ( )
if format . lower ( ) == " json " :
return JSONResponse ( content = {
" study_id " : study_id ,
" total_trials " : len ( trials_data ) ,
" trials " : trials_data
} )
elif format . lower ( ) == " csv " :
import io
import csv
if not trials_data :
return JSONResponse ( content = { " error " : " No data to export " } )
# Build CSV
output = io . StringIO ( )
# Get all param names
param_names = sorted ( set (
key for trial in trials_data
for key in trial [ ' params ' ] . keys ( )
) )
fieldnames = [ ' trial_number ' , ' objective ' ] + param_names
writer = csv . DictWriter ( output , fieldnames = fieldnames )
writer . writeheader ( )
for trial in trials_data :
row_data = {
' trial_number ' : trial [ ' trial_number ' ] ,
' objective ' : trial [ ' objective ' ]
}
row_data . update ( trial [ ' params ' ] )
writer . writerow ( row_data )
csv_content = output . getvalue ( )
return JSONResponse ( content = {
" filename " : f " { study_id } _data.csv " ,
" content " : csv_content ,
" content_type " : " text/csv "
} )
elif format . lower ( ) == " config " :
# Export optimization config
setup_dir = study_dir / " 1_setup "
config_path = setup_dir / " optimization_config.json "
if config_path . exists ( ) :
with open ( config_path , ' r ' ) as f :
config = json . load ( f )
return JSONResponse ( content = {
" filename " : f " { study_id } _config.json " ,
" content " : json . dumps ( config , indent = 2 ) ,
" content_type " : " application/json "
} )
else :
raise HTTPException ( status_code = 404 , detail = " Config file not found " )
else :
raise HTTPException ( status_code = 400 , detail = f " Unsupported format: { format } " )
except HTTPException :
raise
except Exception as e :
raise HTTPException ( status_code = 500 , detail = f " Failed to export data: { str ( e ) } " )