Neural Acceleration (MLP Surrogate): - Add run_nn_optimization.py with hybrid FEA/NN workflow - MLP architecture: 4-layer (64->128->128->64) with BatchNorm/Dropout - Three workflow modes: - --all: Sequential export->train->optimize->validate - --hybrid-loop: Iterative Train->NN->Validate->Retrain cycle - --turbo: Aggressive single-best validation (RECOMMENDED) - Turbo mode: 5000 NN trials + 50 FEA validations in ~12 minutes - Separate nn_study.db to avoid overloading dashboard Performance Results (bracket_pareto_3obj study): - NN prediction errors: mass 1-5%, stress 1-4%, stiffness 5-15% - Found minimum mass designs at boundary (angle~30deg, thick~30mm) - 100x speedup vs pure FEA exploration Protocol Operating System: - Add .claude/skills/ with Bootstrap, Cheatsheet, Context Loader - Add docs/protocols/ with operations (OP_01-06) and system (SYS_10-14) - Update SYS_14_NEURAL_ACCELERATION.md with MLP Turbo Mode docs NX Automation: - Add optimization_engine/hooks/ for NX CAD/CAE automation - Add study_wizard.py for guided study creation - Fix FEM mesh update: load idealized part before UpdateFemodel() New Study: - bracket_pareto_3obj: 3-objective Pareto (mass, stress, stiffness) - 167 FEA trials + 5000 NN trials completed - Demonstrates full hybrid workflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
404 lines
11 KiB
Markdown
404 lines
11 KiB
Markdown
# OP_01: Create Optimization Study
|
|
|
|
<!--
|
|
PROTOCOL: Create Optimization Study
|
|
LAYER: Operations
|
|
VERSION: 1.0
|
|
STATUS: Active
|
|
LAST_UPDATED: 2025-12-05
|
|
PRIVILEGE: user
|
|
LOAD_WITH: [core/study-creation-core.md]
|
|
-->
|
|
|
|
## Overview
|
|
|
|
This protocol guides you through creating a complete Atomizer optimization study from scratch. It covers gathering requirements, generating configuration files, and validating setup.
|
|
|
|
**Skill to Load**: `.claude/skills/core/study-creation-core.md`
|
|
|
|
---
|
|
|
|
## When to Use
|
|
|
|
| Trigger | Action |
|
|
|---------|--------|
|
|
| "new study", "create study" | Follow this protocol |
|
|
| "set up optimization" | Follow this protocol |
|
|
| "optimize my design" | Follow this protocol |
|
|
| User provides NX model | Assess and follow this protocol |
|
|
|
|
---
|
|
|
|
## Quick Reference
|
|
|
|
**Required Outputs**:
|
|
| File | Purpose | Location |
|
|
|------|---------|----------|
|
|
| `optimization_config.json` | Design vars, objectives, constraints | `1_setup/` |
|
|
| `run_optimization.py` | Execution script | Study root |
|
|
| `README.md` | Engineering documentation | Study root |
|
|
| `STUDY_REPORT.md` | Results template | Study root |
|
|
|
|
**Study Structure**:
|
|
```
|
|
studies/{study_name}/
|
|
├── 1_setup/
|
|
│ ├── model/ # NX files (.prt, .sim, .fem)
|
|
│ └── optimization_config.json
|
|
├── 2_results/ # Created during run
|
|
├── README.md # MANDATORY
|
|
├── STUDY_REPORT.md # MANDATORY
|
|
└── run_optimization.py
|
|
```
|
|
|
|
---
|
|
|
|
## Detailed Steps
|
|
|
|
### Step 1: Gather Requirements
|
|
|
|
**Ask the user**:
|
|
1. What are you trying to optimize? (objective)
|
|
2. What can you change? (design variables)
|
|
3. What limits must be respected? (constraints)
|
|
4. Where are your NX files?
|
|
|
|
**Example Dialog**:
|
|
```
|
|
User: "I want to optimize my bracket"
|
|
You: "What should I optimize for - minimum mass, maximum stiffness,
|
|
target frequency, or something else?"
|
|
User: "Minimize mass while keeping stress below 250 MPa"
|
|
```
|
|
|
|
### Step 2: Analyze Model (Introspection)
|
|
|
|
**MANDATORY**: When user provides NX files, run comprehensive introspection:
|
|
|
|
```python
|
|
from optimization_engine.hooks.nx_cad.model_introspection import (
|
|
introspect_part,
|
|
introspect_simulation,
|
|
introspect_op2,
|
|
introspect_study
|
|
)
|
|
|
|
# Introspect the part file to get expressions, mass, features
|
|
part_info = introspect_part("C:/path/to/model.prt")
|
|
|
|
# Introspect the simulation to get solutions, BCs, loads
|
|
sim_info = introspect_simulation("C:/path/to/model.sim")
|
|
|
|
# If OP2 exists, check what results are available
|
|
op2_info = introspect_op2("C:/path/to/results.op2")
|
|
|
|
# Or introspect entire study directory at once
|
|
study_info = introspect_study("studies/my_study/")
|
|
```
|
|
|
|
**Introspection Report Contents**:
|
|
|
|
| Source | Information Extracted |
|
|
|--------|----------------------|
|
|
| `.prt` | Expressions (count, values, types), bodies, mass, material, features |
|
|
| `.sim` | Solutions, boundary conditions, loads, materials, mesh info, output requests |
|
|
| `.op2` | Available results (displacement, stress, strain, SPC forces, etc.), subcases |
|
|
|
|
**Generate Introspection Report** at study creation:
|
|
1. Save report to `studies/{study_name}/MODEL_INTROSPECTION.md`
|
|
2. Include summary of what's available for optimization
|
|
3. List potential design variables (expressions)
|
|
4. List extractable results (from OP2)
|
|
|
|
**Key Questions Answered by Introspection**:
|
|
- What expressions exist? (potential design variables)
|
|
- What solution types? (static, modal, etc.)
|
|
- What results are available in OP2? (displacement, stress, SPC forces)
|
|
- Multi-solution required? (static + modal = set `solution_name=None`)
|
|
|
|
### Step 3: Select Protocol
|
|
|
|
Based on objectives:
|
|
|
|
| Scenario | Protocol | Sampler |
|
|
|----------|----------|---------|
|
|
| Single objective | Protocol 10 (IMSO) | TPE, CMA-ES, or GP |
|
|
| 2-3 objectives | Protocol 11 | NSGA-II |
|
|
| >50 trials, need speed | Protocol 14 | + Neural acceleration |
|
|
|
|
See [SYS_10_IMSO](../system/SYS_10_IMSO.md), [SYS_11_MULTI_OBJECTIVE](../system/SYS_11_MULTI_OBJECTIVE.md).
|
|
|
|
### Step 4: Select Extractors
|
|
|
|
Match physics to extractors from [SYS_12_EXTRACTOR_LIBRARY](../system/SYS_12_EXTRACTOR_LIBRARY.md):
|
|
|
|
| Need | Extractor ID | Function |
|
|
|------|--------------|----------|
|
|
| Max displacement | E1 | `extract_displacement()` |
|
|
| Natural frequency | E2 | `extract_frequency()` |
|
|
| Von Mises stress | E3 | `extract_solid_stress()` |
|
|
| Mass from BDF | E4 | `extract_mass_from_bdf()` |
|
|
| Mass from NX | E5 | `extract_mass_from_expression()` |
|
|
| Wavefront error | E8-E10 | Zernike extractors |
|
|
|
|
### Step 5: Generate Configuration
|
|
|
|
Create `optimization_config.json`:
|
|
|
|
```json
|
|
{
|
|
"study_name": "bracket_optimization",
|
|
"description": "Minimize bracket mass while meeting stress constraint",
|
|
|
|
"design_variables": [
|
|
{
|
|
"name": "thickness",
|
|
"type": "continuous",
|
|
"min": 2.0,
|
|
"max": 10.0,
|
|
"unit": "mm",
|
|
"description": "Wall thickness"
|
|
}
|
|
],
|
|
|
|
"objectives": [
|
|
{
|
|
"name": "mass",
|
|
"type": "minimize",
|
|
"unit": "kg",
|
|
"description": "Total bracket mass"
|
|
}
|
|
],
|
|
|
|
"constraints": [
|
|
{
|
|
"name": "max_stress",
|
|
"type": "less_than",
|
|
"value": 250.0,
|
|
"unit": "MPa",
|
|
"description": "Maximum allowable von Mises stress"
|
|
}
|
|
],
|
|
|
|
"simulation": {
|
|
"model_file": "1_setup/model/bracket.prt",
|
|
"sim_file": "1_setup/model/bracket.sim",
|
|
"solver": "nastran",
|
|
"solution_name": null
|
|
},
|
|
|
|
"optimization_settings": {
|
|
"protocol": "protocol_10_single_objective",
|
|
"sampler": "TPESampler",
|
|
"n_trials": 50
|
|
}
|
|
}
|
|
```
|
|
|
|
### Step 6: Generate run_optimization.py
|
|
|
|
```python
|
|
#!/usr/bin/env python
|
|
"""
|
|
{study_name} - Optimization Runner
|
|
Generated by Atomizer LLM
|
|
"""
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Add optimization engine to path
|
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
|
|
|
from optimization_engine.nx_solver import NXSolver
|
|
from optimization_engine.extractors import extract_displacement, extract_solid_stress
|
|
|
|
# Paths
|
|
STUDY_DIR = Path(__file__).parent
|
|
MODEL_DIR = STUDY_DIR / "1_setup" / "model"
|
|
RESULTS_DIR = STUDY_DIR / "2_results"
|
|
|
|
def objective(trial):
|
|
"""Optimization objective function."""
|
|
# Sample design variables
|
|
thickness = trial.suggest_float("thickness", 2.0, 10.0)
|
|
|
|
# Update NX model and solve
|
|
nx_solver = NXSolver(...)
|
|
result = nx_solver.run_simulation(
|
|
sim_file=MODEL_DIR / "bracket.sim",
|
|
working_dir=MODEL_DIR,
|
|
expression_updates={"thickness": thickness}
|
|
)
|
|
|
|
if not result['success']:
|
|
raise optuna.TrialPruned("Simulation failed")
|
|
|
|
# Extract results using library extractors
|
|
op2_file = result['op2_file']
|
|
stress_result = extract_solid_stress(op2_file)
|
|
max_stress = stress_result['max_von_mises']
|
|
|
|
# Check constraint
|
|
if max_stress > 250.0:
|
|
raise optuna.TrialPruned(f"Stress constraint violated: {max_stress} MPa")
|
|
|
|
# Return objective
|
|
mass = extract_mass(...)
|
|
return mass
|
|
|
|
if __name__ == "__main__":
|
|
# Run optimization
|
|
import optuna
|
|
study = optuna.create_study(direction="minimize")
|
|
study.optimize(objective, n_trials=50)
|
|
```
|
|
|
|
### Step 7: Generate Documentation
|
|
|
|
**README.md** (11 sections required):
|
|
1. Engineering Problem
|
|
2. Mathematical Formulation
|
|
3. Optimization Algorithm
|
|
4. Simulation Pipeline
|
|
5. Result Extraction Methods
|
|
6. Neural Acceleration (if applicable)
|
|
7. Study File Structure
|
|
8. Results Location
|
|
9. Quick Start
|
|
10. Configuration Reference
|
|
11. References
|
|
|
|
**STUDY_REPORT.md** (template):
|
|
```markdown
|
|
# Study Report: {study_name}
|
|
|
|
## Executive Summary
|
|
- Trials completed: _pending_
|
|
- Best objective: _pending_
|
|
- Constraint satisfaction: _pending_
|
|
|
|
## Optimization Progress
|
|
_To be filled after run_
|
|
|
|
## Best Designs Found
|
|
_To be filled after run_
|
|
|
|
## Recommendations
|
|
_To be filled after analysis_
|
|
```
|
|
|
|
### Step 8: Validate NX Model File Chain
|
|
|
|
**CRITICAL**: NX simulation files have parent-child dependencies. ALL linked files must be copied to the study folder.
|
|
|
|
**Required File Chain Check**:
|
|
```
|
|
.sim (Simulation)
|
|
└── .fem (FEM)
|
|
└── _i.prt (Idealized Part) ← OFTEN MISSING!
|
|
└── .prt (Geometry Part)
|
|
```
|
|
|
|
**Validation Steps**:
|
|
1. Open the `.sim` file in NX
|
|
2. Go to **Assemblies → Assembly Navigator** or check **Part Navigator**
|
|
3. Identify ALL child components (especially `*_i.prt` idealized parts)
|
|
4. Copy ALL linked files to `1_setup/model/`
|
|
|
|
**Common Issue**: The `_i.prt` (idealized part) is often forgotten. Without it:
|
|
- `UpdateFemodel()` runs but mesh doesn't change
|
|
- Geometry changes don't propagate to FEM
|
|
- All optimization trials produce identical results
|
|
|
|
**File Checklist**:
|
|
| File Pattern | Description | Required |
|
|
|--------------|-------------|----------|
|
|
| `*.prt` | Geometry part | ✅ Always |
|
|
| `*_i.prt` | Idealized part | ✅ If FEM uses idealization |
|
|
| `*.fem` | FEM file | ✅ Always |
|
|
| `*.sim` | Simulation file | ✅ Always |
|
|
|
|
**Introspection should report**:
|
|
- List of all parts referenced by .sim
|
|
- Warning if any referenced parts are missing from study folder
|
|
|
|
### Step 9: Final Validation Checklist
|
|
|
|
Before running:
|
|
|
|
- [ ] NX files exist in `1_setup/model/`
|
|
- [ ] **ALL child parts copied** (especially `*_i.prt`)
|
|
- [ ] Expression names match model
|
|
- [ ] Config validates (JSON schema)
|
|
- [ ] `run_optimization.py` has no syntax errors
|
|
- [ ] README.md has all 11 sections
|
|
- [ ] STUDY_REPORT.md template exists
|
|
|
|
---
|
|
|
|
## Examples
|
|
|
|
### Example 1: Simple Bracket
|
|
|
|
```
|
|
User: "Optimize my bracket.prt for minimum mass, stress < 250 MPa"
|
|
|
|
Generated config:
|
|
- 1 design variable (thickness)
|
|
- 1 objective (minimize mass)
|
|
- 1 constraint (stress < 250)
|
|
- Protocol 10, TPE sampler
|
|
- 50 trials
|
|
```
|
|
|
|
### Example 2: Multi-Objective Beam
|
|
|
|
```
|
|
User: "Minimize mass AND maximize stiffness for my beam"
|
|
|
|
Generated config:
|
|
- 2 design variables (width, height)
|
|
- 2 objectives (minimize mass, maximize stiffness)
|
|
- Protocol 11, NSGA-II sampler
|
|
- 50 trials (Pareto front)
|
|
```
|
|
|
|
### Example 3: Telescope Mirror
|
|
|
|
```
|
|
User: "Minimize wavefront error at 40deg vs 20deg reference"
|
|
|
|
Generated config:
|
|
- Multiple design variables (mount positions)
|
|
- 1 objective (minimize relative WFE)
|
|
- Zernike extractor E9
|
|
- Protocol 10
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
| Symptom | Cause | Solution |
|
|
|---------|-------|----------|
|
|
| "Expression not found" | Name mismatch | Verify expression names in NX |
|
|
| "No feasible designs" | Constraints too tight | Relax constraint values |
|
|
| Config validation fails | Missing required field | Check JSON schema |
|
|
| Import error | Wrong path | Check sys.path setup |
|
|
|
|
---
|
|
|
|
## Cross-References
|
|
|
|
- **Depends On**: [SYS_12_EXTRACTOR_LIBRARY](../system/SYS_12_EXTRACTOR_LIBRARY.md)
|
|
- **Next Step**: [OP_02_RUN_OPTIMIZATION](./OP_02_RUN_OPTIMIZATION.md)
|
|
- **Skill**: `.claude/skills/core/study-creation-core.md`
|
|
|
|
---
|
|
|
|
## Version History
|
|
|
|
| Version | Date | Changes |
|
|
|---------|------|---------|
|
|
| 1.0 | 2025-12-05 | Initial release |
|