# 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: 1. Identify available parametric expressions (potential design variables) 2. Understand the simulation setup (analysis types, boundary conditions) 3. Discover material properties 4. Identify extractable results from OP2 files 5. 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: 1. **Model Location**: - "Where is your NX model? (path to .prt file or study directory)" - Default: Look in `studies/*/1_setup/model/` 2. **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:** ```python 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: ```python # 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)**: ```python 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: ```python 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: ```python 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: 1. **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 2. **Load Cases**: Identify applied loads and boundary conditions 3. **Material Properties**: Extract material definitions ### Step 5: Generate Recommendations Based on analysis, recommend: 1. **Design Variables**: Which expressions are good candidates 2. **Objectives**: What can be optimized 3. **Constraints**: What should be bounded 4. **Protocol**: Which optimization protocol fits best ## Output Format Present analysis using the **MODEL_INTROSPECTION.md** format: ```markdown # 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: ```python 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