# 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`