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>
12 KiB
Analyze Model Skill
Last Updated: December 6, 2025 Version: 2.0 - Added Comprehensive Model Introspection
You are helping the user understand their NX model's structure and identify optimization opportunities.
Purpose
Extract and present information about an NX model to help the user:
- Identify available parametric expressions (potential design variables)
- Understand the simulation setup (analysis types, boundary conditions)
- Discover material properties
- Identify extractable results from OP2 files
- Recommend optimization strategies based on model characteristics
Triggers
- "analyze this model"
- "what can I optimize"
- "show me the expressions"
- "look at my NX model"
- "what parameters are available"
- "introspect my model"
- "what results are available"
Prerequisites
- User must provide path to NX model files (.prt, .sim, .fem) or study directory
- NX must be available on the system for part/sim introspection
- OP2 introspection works without NX (pure Python)
Information Gathering
Ask these questions if not already provided:
-
Model Location:
- "Where is your NX model? (path to .prt file or study directory)"
- Default: Look in
studies/*/1_setup/model/
-
Analysis Interest:
- "What type of optimization are you considering?" (optional)
- This helps focus the analysis on relevant aspects
MANDATORY: Model Introspection
ALWAYS use the introspection module for comprehensive model analysis:
from optimization_engine.hooks.nx_cad.model_introspection import (
introspect_part,
introspect_simulation,
introspect_op2,
introspect_study
)
# Option 1: Introspect entire study directory (recommended)
study_info = introspect_study("studies/my_study/")
# Option 2: Introspect individual files
part_info = introspect_part("path/to/model.prt")
sim_info = introspect_simulation("path/to/model.sim")
op2_info = introspect_op2("path/to/results.op2")
What Introspection Extracts
| 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 |
Introspection Report Generation
MANDATORY: Generate MODEL_INTROSPECTION.md for every study:
# Generate and save introspection report
study_info = introspect_study(study_dir)
# Create markdown report
report = generate_introspection_report(study_info)
with open(study_dir / "MODEL_INTROSPECTION.md", "w") as f:
f.write(report)
Execution Steps
Step 1: Run Comprehensive Introspection
Use the introspection module (MANDATORY):
from optimization_engine.hooks.nx_cad.model_introspection import introspect_study
# Introspect the entire study
result = introspect_study("studies/my_study/")
if result["success"]:
# Part information
for part in result["data"]["parts"]:
print(f"Part: {part['file']}")
print(f" Expressions: {part['data'].get('expression_count', 0)}")
print(f" Bodies: {part['data'].get('body_count', 0)}")
# Simulation information
for sim in result["data"]["simulations"]:
print(f"Simulation: {sim['file']}")
print(f" Solutions: {sim['data'].get('solution_count', 0)}")
# OP2 results
for op2 in result["data"]["results"]:
print(f"OP2: {op2['file']}")
available = op2['data'].get('available_results', {})
print(f" Displacement: {available.get('displacement', False)}")
print(f" Stress: {available.get('stress', False)}")
Step 2: Validate Model Files
Check that required files exist:
from pathlib import Path
def validate_model_files(model_path: Path) -> dict:
"""Validate NX model files exist."""
prt_file = model_path
base_name = prt_file.stem
parent_dir = prt_file.parent
result = {
'prt_exists': prt_file.exists(),
'sim_file': None,
'fem_file': None,
'errors': []
}
# Look for simulation file
sim_patterns = [
f"{base_name}_sim1.sim",
f"{base_name}_sim.sim",
f"{base_name}.sim"
]
for pattern in sim_patterns:
sim_path = parent_dir / pattern
if sim_path.exists():
result['sim_file'] = sim_path
break
# Look for FEM file
fem_patterns = [
f"{base_name}_fem1.fem",
f"{base_name}_fem.fem",
f"{base_name}.fem"
]
for pattern in fem_patterns:
fem_path = parent_dir / pattern
if fem_path.exists():
result['fem_file'] = fem_path
break
if not result['prt_exists']:
result['errors'].append(f"Part file not found: {prt_file}")
if not result['sim_file']:
result['errors'].append("No simulation file (.sim) found")
if not result['fem_file']:
result['errors'].append("No FEM file (.fem) found - will be created on first solve")
return result
Step 3: Extract Expressions (via Introspection)
The introspection module extracts expressions automatically:
from optimization_engine.hooks.nx_cad.model_introspection import introspect_part
result = introspect_part("path/to/model.prt")
if result["success"]:
expressions = result["data"].get("expressions", [])
for expr in expressions:
print(f" {expr['name']}: {expr['value']} {expr.get('unit', '')}")
Step 4: Classify Expressions
Categorize expressions by likely purpose:
| Pattern | Category | Optimization Relevance |
|---|---|---|
*_thickness, *_t, wall_* |
Structural | High - affects mass & stiffness |
*_diameter, *_d, hole_* |
Geometric | High - affects mass & stress |
*_radius, *_r, fillet_* |
Geometric | Medium - affects stress concentration |
*_count, n_*, num_* |
Discrete | Medium - affects mass & complexity |
*_length, *_l, span_* |
Dimensional | Context-dependent |
*_angle, *_deg |
Orientation | Low-Medium |
material_*, mat_* |
Material | Special handling required |
Step 4: Analyze Simulation Setup
If .sim file exists, analyze:
-
Solution Types:
- SOL 101 (Static) → Displacement, Stress
- SOL 103 (Modal) → Natural Frequencies
- SOL 105 (Buckling) → Buckling Load Factor
- SOL 106 (Nonlinear Static) → Large deformation
- SOL 112 (Transient) → Dynamic response
-
Load Cases: Identify applied loads and boundary conditions
-
Material Properties: Extract material definitions
Step 5: Generate Recommendations
Based on analysis, recommend:
- Design Variables: Which expressions are good candidates
- Objectives: What can be optimized
- Constraints: What should be bounded
- Protocol: Which optimization protocol fits best
Output Format
Present analysis using the MODEL_INTROSPECTION.md format:
# Model Introspection Report
**Study**: {study_name}
**Generated**: {date}
**Introspection Version**: 1.0
---
## 1. Files Discovered
| Type | File | Status |
|------|------|--------|
| Part (.prt) | {prt_file} | ✓ Found |
| Simulation (.sim) | {sim_file} | ✓ Found |
| FEM (.fem) | {fem_file} | ✓ Found |
| Results (.op2) | {op2_file} | ✓ Found |
---
## 2. Part Information
### Expressions (Potential Design Variables)
| Name | Value | Unit | Type | Optimization Candidate |
|------|-------|------|------|------------------------|
| thickness | 2.0 | mm | User | ✓ High |
| hole_diameter | 10.0 | mm | User | ✓ High |
| p173_mass | 0.125 | kg | Reference | Read-only |
### Mass Properties
| Property | Value | Unit |
|----------|-------|------|
| Mass | 0.125 | kg |
| Material | Aluminum 6061-T6 | - |
---
## 3. Simulation Information
### Solutions
| Solution | Type | Nastran SOL | Status |
|----------|------|-------------|--------|
| Solution 1 | Static | SOL 101 | ✓ Active |
| Solution 2 | Modal | SOL 103 | ✓ Active |
### Boundary Conditions
| Name | Type | Applied To |
|------|------|------------|
| Fixed_Root | SPC | Face_1 |
### Loads
| Name | Type | Magnitude | Direction |
|------|------|-----------|-----------|
| Tip_Force | FORCE | 500 N | -Z |
---
## 4. Available Results (from OP2)
| Result Type | Available | Subcases |
|-------------|-----------|----------|
| Displacement | ✓ | 1 |
| SPC Forces | ✓ | 1 |
| Stress (CHEXA) | ✓ | 1 |
| Stress (CPENTA) | ✓ | 1 |
| Strain Energy | ✗ | - |
| Frequencies | ✓ | 2 |
---
## 5. Optimization Recommendations
### Suggested Objectives
| Objective | Extractor | Source |
|-----------|-----------|--------|
| Minimize mass | E4: `extract_mass_from_bdf` | .dat |
| Maximize stiffness | E1: `extract_displacement` → k=F/δ | .op2 |
### Suggested Constraints
| Constraint | Type | Threshold | Extractor |
|------------|------|-----------|-----------|
| Max stress | less_than | 250 MPa | E3: `extract_solid_stress` |
### Recommended Protocol
- **Protocol 11 (Multi-Objective NSGA-II)** - Multiple competing objectives
- Multi-Solution: **Yes** (static + modal)
---
*Ready to create optimization study? Say "create study" to proceed.*
Saving the Report
MANDATORY: Save the introspection report to the study directory:
from pathlib import Path
def save_introspection_report(study_dir: Path, report_content: str):
"""Save MODEL_INTROSPECTION.md to study directory."""
report_path = study_dir / "MODEL_INTROSPECTION.md"
with open(report_path, 'w') as f:
f.write(report_content)
print(f"Saved introspection report: {report_path}")
## Error Handling
| Error | Recovery |
|-------|----------|
| File not found | Ask user for correct path |
| Invalid NX format | Suggest checking NX version compatibility |
| No expressions found | Guide user to create expressions in NX |
| Simulation incomplete | List missing components |
## Integration with Other Skills
After analysis, can chain to:
- `/create-study` - Create optimization based on findings
- `/configure-surrogate` - Setup NN if large-scale optimization needed
## Example Conversation
USER: Look at my NX model at studies/uav_arm_optimization/1_setup/model/Beam.prt
CLAUDE: I'll analyze your UAV arm model. Let me examine its structure...
[Runs analysis]
MODEL ANALYSIS REPORT
Model: Beam Location: studies/uav_arm_optimization/1_setup/model/
PARAMETRIC EXPRESSIONS
Found 4 controllable parameters:
| Name | Value | Bounds Suggestion |
|---|---|---|
| beam_half_core_thickness | 15.0 mm | [5, 25] |
| beam_face_thickness | 2.0 mm | [1, 5] |
| holes_diameter | 30.0 mm | [10, 50] |
| hole_count | 8 | [4, 12] |
SIMULATION SETUP
✓ Static Analysis (SOL 101) - for stress/displacement ✓ Modal Analysis (SOL 103) - for natural frequencies Material: Aluminum sandwich panel
RECOMMENDATION
This model is well-suited for multi-objective optimization:
- Objective 1: Minimize mass
- Objective 2: Maximize first natural frequency
- Constraint: Keep stress below yield strength
Would you like me to create an optimization study with these settings?
USER: Yes, but add a displacement constraint of 5mm max
CLAUDE: [Invokes create-study skill with analyzed parameters + user constraint]
## Notes
- Expression extraction requires NX to be running or using file parsing
- Some expressions may be formula-driven (not directly editable)
- Material properties may need separate handling
- Consider mesh quality when recommending optimization bounds