## Removed Duplicate Directories - Deleted old `dashboard/` (replaced by atomizer-dashboard) - Deleted old `mcp_server/` Python tools (moved model_discovery to optimization_engine) - Deleted `tests/mcp_server/` (obsolete tests) - Deleted `launch_dashboard.bat` (old launcher) ## Consolidated Code - Moved `mcp_server/tools/model_discovery.py` to `optimization_engine/model_discovery/` - Updated import in `optimization_config_builder.py` - Deleted stub `extract_mass.py` (use extract_mass_from_bdf instead) - Deleted unused `intelligent_setup.py` and `hybrid_study_creator.py` - Archived `result_extractors/` to `archive/deprecated/` ## Documentation Cleanup - Deleted deprecated `docs/06_PROTOCOLS_DETAILED/` (14 files) - Archived dated dev docs to `docs/08_ARCHIVE/sessions/` - Archived old plans to `docs/08_ARCHIVE/plans/` - Updated `docs/protocols/README.md` with SYS_15 ## Skills Consolidation - Archived redundant study creation skills to `.claude/skills/archive/` - Kept `core/study-creation-core.md` as canonical ## Housekeeping - Updated `.gitignore` to prevent `nul` and `_dat_run*.dat` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
12 KiB
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
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):
- Model files: "Where is your NX model? (path to .prt file)"
- Optimization goal: "What do you want to optimize?"
- Minimize mass/weight
- Maximize stiffness
- Target a specific frequency
- Multi-objective trade-off
- Constraints: "What limits must be respected?"
- Max stress < yield/safety factor
- Max displacement < tolerance
- Mass budget
Step 2: Introspect Model
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
# 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
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:
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
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
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
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
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:
# 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:
- Where is your NX model file?
- What's the maximum allowable stress (e.g., yield/4)?
- 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."
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.pystudies/my_bracket_optimization/README.md- Configuration files in
1_setup/
Next steps:
cd studies/my_bracket_optimizationpython run_optimization.py --discoverpython run_optimization.py --validatepython 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