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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user