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>
403 lines
12 KiB
Markdown
403 lines
12 KiB
Markdown
# Create Study Wizard Skill
|
|
|
|
**Version**: 3.0 - StudyWizard Integration
|
|
**Last Updated**: 2025-12-06
|
|
|
|
You are helping the user create a complete Atomizer optimization study using the powerful `StudyWizard` class.
|
|
|
|
---
|
|
|
|
## Quick Reference
|
|
|
|
```python
|
|
from optimization_engine.study_wizard import StudyWizard, create_study, list_extractors
|
|
|
|
# Option 1: One-liner for simple studies
|
|
create_study(
|
|
study_name="my_study",
|
|
description="Optimize bracket for stiffness",
|
|
prt_file="path/to/model.prt",
|
|
design_variables=[
|
|
{"parameter": "thickness", "bounds": [5, 20], "units": "mm"}
|
|
],
|
|
objectives=[
|
|
{"name": "stiffness", "goal": "maximize", "extractor": "extract_displacement"}
|
|
],
|
|
constraints=[
|
|
{"name": "mass", "type": "less_than", "threshold": 0.5, "extractor": "extract_mass_from_bdf", "units": "kg"}
|
|
]
|
|
)
|
|
|
|
# Option 2: Step-by-step with full control
|
|
wizard = StudyWizard("my_study", "Optimize bracket")
|
|
wizard.set_model_files("path/to/model.prt")
|
|
wizard.introspect() # Discover expressions, solutions
|
|
wizard.add_design_variable("thickness", bounds=(5, 20), units="mm")
|
|
wizard.add_objective("mass", goal="minimize", extractor="extract_mass_from_bdf")
|
|
wizard.add_constraint("stress", type="less_than", threshold=250, extractor="extract_solid_stress", units="MPa")
|
|
wizard.generate()
|
|
```
|
|
|
|
---
|
|
|
|
## Trigger Phrases
|
|
|
|
Use this skill when user says:
|
|
- "create study", "new study", "set up study", "create optimization"
|
|
- "optimize my [part/model/bracket/component]"
|
|
- "help me minimize [mass/weight/cost]"
|
|
- "help me maximize [stiffness/strength/frequency]"
|
|
- "I want to find the best [design/parameters]"
|
|
|
|
---
|
|
|
|
## Workflow Steps
|
|
|
|
### Step 1: Gather Requirements
|
|
|
|
Ask the user (if not already provided):
|
|
|
|
1. **Model files**: "Where is your NX model? (path to .prt file)"
|
|
2. **Optimization goal**: "What do you want to optimize?"
|
|
- Minimize mass/weight
|
|
- Maximize stiffness
|
|
- Target a specific frequency
|
|
- Multi-objective trade-off
|
|
3. **Constraints**: "What limits must be respected?"
|
|
- Max stress < yield/safety factor
|
|
- Max displacement < tolerance
|
|
- Mass budget
|
|
|
|
### Step 2: Introspect Model
|
|
|
|
```python
|
|
from optimization_engine.study_wizard import StudyWizard
|
|
|
|
wizard = StudyWizard("study_name", "Description")
|
|
wizard.set_model_files("path/to/model.prt")
|
|
result = wizard.introspect()
|
|
|
|
# Show user what was found
|
|
print(f"Found {len(result.expressions)} expressions:")
|
|
for expr in result.expressions[:10]:
|
|
print(f" {expr['name']}: {expr.get('value', 'N/A')}")
|
|
|
|
print(f"\nFound {len(result.solutions)} solutions:")
|
|
for sol in result.solutions:
|
|
print(f" {sol['name']}")
|
|
|
|
# Suggest design variables
|
|
suggestions = result.suggest_design_variables()
|
|
for s in suggestions:
|
|
print(f" {s['name']}: {s['current_value']} -> bounds {s['suggested_bounds']}")
|
|
```
|
|
|
|
### Step 3: Configure Study
|
|
|
|
```python
|
|
# Add design variables from introspection suggestions
|
|
for dv in selected_design_variables:
|
|
wizard.add_design_variable(
|
|
parameter=dv['name'],
|
|
bounds=dv['bounds'],
|
|
units=dv.get('units', ''),
|
|
description=dv.get('description', '')
|
|
)
|
|
|
|
# Add objectives
|
|
wizard.add_objective(
|
|
name="mass",
|
|
goal="minimize",
|
|
extractor="extract_mass_from_bdf",
|
|
description="Minimize total bracket mass"
|
|
)
|
|
|
|
wizard.add_objective(
|
|
name="stiffness",
|
|
goal="maximize",
|
|
extractor="extract_displacement",
|
|
params={"invert_for_stiffness": True},
|
|
description="Maximize structural stiffness"
|
|
)
|
|
|
|
# Add constraints
|
|
wizard.add_constraint(
|
|
name="max_stress",
|
|
constraint_type="less_than",
|
|
threshold=250,
|
|
extractor="extract_solid_stress",
|
|
units="MPa",
|
|
description="Keep stress below yield/4"
|
|
)
|
|
|
|
# Set protocol based on objectives
|
|
if len(wizard.objectives) > 1:
|
|
wizard.set_protocol("protocol_11_multi") # NSGA-II
|
|
else:
|
|
wizard.set_protocol("protocol_10_single") # TPE
|
|
|
|
wizard.set_trials(100)
|
|
```
|
|
|
|
### Step 4: Generate Study
|
|
|
|
```python
|
|
files = wizard.generate()
|
|
|
|
print("Study generated successfully!")
|
|
print(f"Location: {wizard.study_dir}")
|
|
print("\nNext steps:")
|
|
print(" 1. cd", wizard.study_dir)
|
|
print(" 2. python run_optimization.py --discover")
|
|
print(" 3. python run_optimization.py --validate")
|
|
print(" 4. python run_optimization.py --run --trials 100")
|
|
```
|
|
|
|
---
|
|
|
|
## Available Extractors
|
|
|
|
| Extractor | What it extracts | Input | Output |
|
|
|-----------|------------------|-------|--------|
|
|
| `extract_mass_from_bdf` | Total mass | .dat/.bdf | kg |
|
|
| `extract_part_mass` | CAD mass | .prt | kg |
|
|
| `extract_displacement` | Max displacement | .op2 | mm |
|
|
| `extract_solid_stress` | Von Mises stress | .op2 | MPa |
|
|
| `extract_principal_stress` | Principal stresses | .op2 | MPa |
|
|
| `extract_strain_energy` | Strain energy | .op2 | J |
|
|
| `extract_spc_forces` | Reaction forces | .op2 | N |
|
|
| `extract_frequency` | Natural frequencies | .op2 | Hz |
|
|
| `get_first_frequency` | First mode frequency | .f06 | Hz |
|
|
| `extract_temperature` | Nodal temperatures | .op2 | K/°C |
|
|
| `extract_modal_mass` | Modal effective mass | .f06 | kg |
|
|
| `extract_zernike_from_op2` | Zernike WFE | .op2+.bdf | nm |
|
|
|
|
**List all extractors programmatically**:
|
|
```python
|
|
from optimization_engine.study_wizard import list_extractors
|
|
for name, info in list_extractors().items():
|
|
print(f"{name}: {info['description']}")
|
|
```
|
|
|
|
---
|
|
|
|
## Common Optimization Patterns
|
|
|
|
### Pattern 1: Minimize Mass with Stress Constraint
|
|
|
|
```python
|
|
create_study(
|
|
study_name="lightweight_bracket",
|
|
description="Minimize mass while keeping stress below yield",
|
|
prt_file="Bracket.prt",
|
|
design_variables=[
|
|
{"parameter": "wall_thickness", "bounds": [2, 10], "units": "mm"},
|
|
{"parameter": "rib_count", "bounds": [2, 8], "units": "count"}
|
|
],
|
|
objectives=[
|
|
{"name": "mass", "goal": "minimize", "extractor": "extract_mass_from_bdf"}
|
|
],
|
|
constraints=[
|
|
{"name": "stress", "type": "less_than", "threshold": 250,
|
|
"extractor": "extract_solid_stress", "units": "MPa"}
|
|
],
|
|
protocol="protocol_10_single"
|
|
)
|
|
```
|
|
|
|
### Pattern 2: Multi-Objective Stiffness vs Mass
|
|
|
|
```python
|
|
create_study(
|
|
study_name="pareto_bracket",
|
|
description="Trade-off between stiffness and mass",
|
|
prt_file="Bracket.prt",
|
|
design_variables=[
|
|
{"parameter": "thickness", "bounds": [5, 25], "units": "mm"},
|
|
{"parameter": "support_angle", "bounds": [20, 70], "units": "degrees"}
|
|
],
|
|
objectives=[
|
|
{"name": "stiffness", "goal": "maximize", "extractor": "extract_displacement"},
|
|
{"name": "mass", "goal": "minimize", "extractor": "extract_mass_from_bdf"}
|
|
],
|
|
constraints=[
|
|
{"name": "mass_limit", "type": "less_than", "threshold": 0.5,
|
|
"extractor": "extract_mass_from_bdf", "units": "kg"}
|
|
],
|
|
protocol="protocol_11_multi",
|
|
n_trials=150
|
|
)
|
|
```
|
|
|
|
### Pattern 3: Frequency-Targeted Modal Optimization
|
|
|
|
```python
|
|
create_study(
|
|
study_name="modal_bracket",
|
|
description="Tune first natural frequency to target",
|
|
prt_file="Bracket.prt",
|
|
design_variables=[
|
|
{"parameter": "thickness", "bounds": [3, 15], "units": "mm"},
|
|
{"parameter": "length", "bounds": [50, 150], "units": "mm"}
|
|
],
|
|
objectives=[
|
|
{"name": "frequency_error", "goal": "minimize",
|
|
"extractor": "get_first_frequency",
|
|
"params": {"target": 100}} # Target 100 Hz
|
|
],
|
|
constraints=[
|
|
{"name": "mass", "type": "less_than", "threshold": 0.3,
|
|
"extractor": "extract_mass_from_bdf", "units": "kg"}
|
|
]
|
|
)
|
|
```
|
|
|
|
### Pattern 4: Thermal Optimization
|
|
|
|
```python
|
|
create_study(
|
|
study_name="heat_sink",
|
|
description="Minimize max temperature",
|
|
prt_file="HeatSink.prt",
|
|
design_variables=[
|
|
{"parameter": "fin_height", "bounds": [10, 50], "units": "mm"},
|
|
{"parameter": "fin_count", "bounds": [5, 20], "units": "count"}
|
|
],
|
|
objectives=[
|
|
{"name": "max_temp", "goal": "minimize", "extractor": "get_max_temperature"}
|
|
],
|
|
constraints=[
|
|
{"name": "mass", "type": "less_than", "threshold": 0.2,
|
|
"extractor": "extract_mass_from_bdf", "units": "kg"}
|
|
]
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## Protocol Selection Guide
|
|
|
|
| Scenario | Protocol | Sampler |
|
|
|----------|----------|---------|
|
|
| Single objective | `protocol_10_single` | TPESampler |
|
|
| Multiple objectives (Pareto) | `protocol_11_multi` | NSGAIISampler |
|
|
| Smooth design space | `protocol_10_single` | CmaEsSampler |
|
|
| Discrete variables | `protocol_10_single` | TPESampler |
|
|
|
|
---
|
|
|
|
## Files Generated
|
|
|
|
The wizard generates a complete study structure:
|
|
|
|
```
|
|
studies/{study_name}/
|
|
├── 1_setup/
|
|
│ ├── model/ # NX model files (copied)
|
|
│ ├── optimization_config.json
|
|
│ └── workflow_config.json
|
|
├── 2_results/ # Created on first run
|
|
├── run_optimization.py # Main script with staged workflow
|
|
├── reset_study.py # Reset results
|
|
├── README.md # Engineering documentation
|
|
├── STUDY_REPORT.md # Results tracking template
|
|
└── MODEL_INTROSPECTION.md # Model analysis report
|
|
```
|
|
|
|
---
|
|
|
|
## Staged Workflow
|
|
|
|
After generation, guide user through staged validation:
|
|
|
|
```bash
|
|
# Stage 1: Discover model outputs
|
|
python run_optimization.py --discover
|
|
|
|
# Stage 2: Validate with single trial
|
|
python run_optimization.py --validate
|
|
|
|
# Stage 3: Integration test (3 trials)
|
|
python run_optimization.py --test
|
|
|
|
# Stage 4: Full optimization
|
|
python run_optimization.py --run --trials 100
|
|
|
|
# Resume if interrupted
|
|
python run_optimization.py --run --trials 50 --resume
|
|
```
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
### Common Issues and Solutions
|
|
|
|
| Error | Cause | Solution |
|
|
|-------|-------|----------|
|
|
| "Part file not found" | Wrong path | Use absolute path or relative to studies/ |
|
|
| "No expressions found" | Part not parametric | Add expressions in NX Modeling |
|
|
| "Simulation failed" | NX not running | Start NX before running |
|
|
| "Extractor not found" | Typo in name | Use `list_extractors()` to see valid names |
|
|
|
|
---
|
|
|
|
## Example Conversation
|
|
|
|
**User**: "I want to optimize my bracket for minimum weight while keeping stress low"
|
|
|
|
**Claude**: "I'll help you create a weight optimization study. Let me gather some information:
|
|
|
|
1. Where is your NX model file?
|
|
2. What's the maximum allowable stress (e.g., yield/4)?
|
|
3. Are there specific parameters you want to vary (thickness, angles, etc.)?"
|
|
|
|
**User**: "The model is at studies/my_bracket/model/Bracket.prt. Max stress should be 250 MPa. I want to vary the wall_thickness and support_angle."
|
|
|
|
**Claude**: "I'll create the study and introspect your model to confirm the parameters exist."
|
|
|
|
```python
|
|
from optimization_engine.study_wizard import StudyWizard
|
|
|
|
wizard = StudyWizard(
|
|
study_name="my_bracket_optimization",
|
|
description="Minimize bracket mass with stress constraint"
|
|
)
|
|
|
|
wizard.set_model_files("studies/my_bracket/model/Bracket.prt")
|
|
|
|
# Introspect to verify parameters
|
|
result = wizard.introspect()
|
|
print(f"Found expressions: {result.get_expression_names()}")
|
|
|
|
# Configure
|
|
wizard.add_design_variable("wall_thickness", bounds=(2, 15), units="mm")
|
|
wizard.add_design_variable("support_angle", bounds=(20, 60), units="degrees")
|
|
wizard.add_objective("mass", goal="minimize", extractor="extract_mass_from_bdf")
|
|
wizard.add_constraint("stress", constraint_type="less_than", threshold=250,
|
|
extractor="extract_solid_stress", units="MPa")
|
|
wizard.set_trials(100)
|
|
|
|
files = wizard.generate()
|
|
```
|
|
|
|
**Claude**: "Study created! Here's what I generated:
|
|
- `studies/my_bracket_optimization/run_optimization.py`
|
|
- `studies/my_bracket_optimization/README.md`
|
|
- Configuration files in `1_setup/`
|
|
|
|
Next steps:
|
|
1. `cd studies/my_bracket_optimization`
|
|
2. `python run_optimization.py --discover`
|
|
3. `python run_optimization.py --validate`
|
|
4. `python run_optimization.py --run --trials 100`"
|
|
|
|
---
|
|
|
|
## Cross-References
|
|
|
|
- **Extractor Library**: `docs/protocols/system/SYS_12_EXTRACTOR_LIBRARY.md`
|
|
- **Protocol 10 (IMSO)**: `docs/protocols/system/SYS_10_IMSO.md`
|
|
- **Protocol 11 (Multi-Objective)**: `docs/protocols/system/SYS_11_MULTI_OBJECTIVE.md`
|
|
- **StudyWizard Source**: `optimization_engine/study_wizard.py`
|