feat: Add Protocol 13 adaptive optimization, Plotly charts, and dashboard improvements

## Protocol 13: Adaptive Multi-Objective Optimization
- Iterative FEA + Neural Network surrogate workflow
- Initial FEA sampling, NN training, NN-accelerated search
- FEA validation of top NN predictions, retraining loop
- adaptive_state.json tracks iteration history and best values
- M1 mirror study (V11) with 103 FEA, 3000 NN trials

## Dashboard Visualization Enhancements
- Added Plotly.js interactive charts (parallel coords, Pareto, convergence)
- Lazy loading with React.lazy() for performance
- Code splitting: plotly.js-basic-dist (~1MB vs 3.5MB)
- Chart library toggle (Recharts default, Plotly on-demand)
- ExpandableChart component for full-screen modal views
- ConsoleOutput component for real-time log viewing

## Documentation
- Protocol 13 detailed documentation
- Dashboard visualization guide
- Plotly components README
- Updated run-optimization skill with Mode 5 (adaptive)

## Bug Fixes
- Fixed TypeScript errors in dashboard components
- Fixed Card component to accept ReactNode title
- Removed unused imports across components

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Antoine
2025-12-04 07:41:54 -05:00
parent e74f1ccf36
commit 8cbdbcad78
270 changed files with 15471 additions and 517 deletions

View File

@@ -2,6 +2,33 @@
This document describes the multi-part assembly FEM workflow used when optimizing complex assemblies with `.afm` (Assembly FEM) files.
## CRITICAL: Working Copy Requirement
**NEVER run optimization directly on user's master model files.**
Before any optimization run, ALL model files must be copied to the study's working directory:
```
Source (NEVER MODIFY) Working Copy (optimization runs here)
────────────────────────────────────────────────────────────────────────────
C:/Users/.../M1-Gigabit/Latest/ studies/{study}/1_setup/model/
├── M1_Blank.prt → ├── M1_Blank.prt
├── M1_Blank_fem1.fem → ├── M1_Blank_fem1.fem
├── M1_Blank_fem1_i.prt → ├── M1_Blank_fem1_i.prt
├── M1_Vertical_Support_Skeleton.prt → ├── M1_Vertical_Support_Skeleton.prt
├── ASSY_M1_assyfem1.afm → ├── ASSY_M1_assyfem1.afm
└── ASSY_M1_assyfem1_sim1.sim → └── ASSY_M1_assyfem1_sim1.sim
```
**Why**: Optimization iteratively modifies expressions, meshes, and saves files. If corruption occurs during iteration (solver crash, bad parameter combo), the working copy can be deleted and re-copied. Master files remain safe.
**Files to Copy**:
- `*.prt` - All part files (geometry + idealized)
- `*.fem` - All FEM files
- `*.afm` - Assembly FEM files
- `*.sim` - Simulation files
- `*.exp` - Expression files (if any)
## Overview
Assembly FEMs have a more complex dependency chain than single-part simulations:
@@ -40,6 +67,29 @@ Open M1_Blank.prt
The `.prt` file contains the parametric CAD model with expressions that drive dimensions. These expressions are updated with new design parameter values, then the geometry is rebuilt.
### Step 1b: Update ALL Linked Geometry Parts (CRITICAL!)
**⚠️ THIS STEP IS CRITICAL - SKIPPING IT CAUSES CORRUPT RESULTS ⚠️**
```
For each geometry part with linked expressions:
├── Open M1_Vertical_Support_Skeleton.prt
├── DoUpdate() - propagate linked expression changes
├── Geometry rebuilds to match M1_Blank
└── Save part
```
**Why this is critical:**
- M1_Vertical_Support_Skeleton has expressions linked to M1_Blank
- When M1_Blank geometry changes, the support skeleton MUST also update
- If not updated, FEM nodes will be at OLD positions → nodes not coincident → merge fails
- Result: "billion nm" RMS values (corrupt displacement data)
**Rule: YOU MUST UPDATE ALL GEOMETRY PARTS UNDER THE .sim FILE!**
- If there are 5 geometry parts, update all 5
- If there are 10 geometry parts, update all 10
- Unless explicitly told otherwise in the study config
### Step 2: Update Component FEM Files (.fem)
```
@@ -180,9 +230,100 @@ See `optimization_engine/solve_simulation.py` for the full implementation:
- `update_assembly_fem()` - Step 3 implementation
- `solve_simulation_file()` - Step 4 implementation
## HEEDS-Style Iteration Folder Management (V9+)
For complex assemblies, each optimization trial uses a fresh copy of the master model:
```
study_name/
├── 1_setup/
│ └── model/ # Master model files (NEVER MODIFY)
│ ├── ASSY_M1.prt
│ ├── ASSY_M1_assyfem1.afm
│ ├── ASSY_M1_assyfem1_sim1.sim
│ ├── M1_Blank.prt
│ ├── M1_Blank_fem1.fem
│ └── ...
├── 2_iterations/
│ ├── iter0/ # Trial 0 working copy
│ │ ├── [all model files]
│ │ ├── params.exp # Expression values for this trial
│ │ └── results/ # OP2, Zernike CSV, etc.
│ ├── iter1/ # Trial 1 working copy
│ └── ...
└── 3_results/
└── study.db # Optuna database
```
### Why Fresh Copies Per Iteration?
1. **Corruption isolation**: If mesh regeneration fails mid-trial, only that iteration is affected
2. **Reproducibility**: Can re-run any trial by using its params.exp
3. **Debugging**: All intermediate files preserved for post-mortem analysis
4. **Parallelization**: Multiple NX sessions could run different iterations (future)
### Iteration Folder Contents
| File | Purpose |
|------|---------|
| `*.prt, *.fem, *.afm, *.sim` | Fresh copy of all NX model files |
| `params.exp` | Expression file with trial parameter values |
| `*-solution_1.op2` | Nastran results (after solve) |
| `results/zernike_trial_N.csv` | Extracted Zernike metrics |
### 0-Based Iteration Numbering
Iterations are numbered starting from 0 to match Optuna trial numbers:
- `iter0` = Optuna trial 0 = Dashboard shows trial 0
- `iter1` = Optuna trial 1 = Dashboard shows trial 1
This ensures cross-referencing between dashboard, database, and file system is straightforward.
## Multi-Subcase Solutions
For gravity analysis at multiple orientations, use subcases:
```
Simulation Setup in NX:
├── Subcase 1: 90 deg elevation (zenith/polishing)
├── Subcase 2: 20 deg elevation (low angle reference)
├── Subcase 3: 40 deg elevation
└── Subcase 4: 60 deg elevation
```
### Solving All Subcases
Use `solution_name=None` or `solve_all_subcases=True` to ensure all subcases are solved:
```json
"nx_settings": {
"solution_name": "Solution 1",
"solve_all_subcases": true
}
```
### Subcase ID Mapping
NX subcase IDs (1, 2, 3, 4) may not match the angle labels. Always define explicit mapping:
```json
"zernike_settings": {
"subcases": ["1", "2", "3", "4"],
"subcase_labels": {
"1": "90deg",
"2": "20deg",
"3": "40deg",
"4": "60deg"
},
"reference_subcase": "2"
}
```
## Tips
1. **Start with baseline solve**: Before optimization, manually verify the full workflow completes in NX
2. **Check mesh quality**: Poor mesh quality after updates can cause solve failures
3. **Monitor memory**: Assembly FEMs with many components use significant memory
4. **Use Foreground mode**: For multi-subcase solutions, Foreground mode ensures all subcases complete
5. **Validate OP2 data**: Check for corrupt results (all zeros, unrealistic magnitudes) before processing
6. **Preserve user NX sessions**: NXSessionManager tracks PIDs to avoid closing user's NX instances