# Model Introspection Research — Full Data Picture for Optimization Setup **Author:** NX Expert 🖥️ **Date:** 2026-02-14 **For:** Antoine Letarte, Atomizer Engineering Co. **Purpose:** Comprehensive framework for extracting complete model knowledge before optimization --- ## Executive Summary This document defines a **master introspection framework** that captures the full data picture of CAD/FEA models before optimization setup. The goal is to give Atomizer HQ complete knowledge of: - What can be optimized (design variables, constraints) - What physics governs the problem (BCs, loads, subcases, solver config) - What the baseline state is (geometry, mesh, materials, results) - How to extract objectives and constraints (result fields, quality metrics) **Output Format:** JSON schema (future-proof, efficient) **Integration Point:** Pre-optimization / Study setup phase **Extraction Methods:** NXOpen Python API + pyNastran + result file parsing --- ## 1. Current State Analysis ### 1.1 Existing Atomizer Introspection Atomizer already has three introspection scripts: | Script | Coverage | Gaps | |--------|----------|------| | `introspect_part.py` | Expressions, mass, materials, bodies, features, datums, units | No parametric relationships, no feature dependencies, no sketches | | `introspect_sim.py` | Solutions, BCs (partial), subcases (exploratory) | Limited BC extraction, no load details, no output requests | | `discover_model.py` | Intelligent scanning of expressions + solutions | Surface-level only, no deep FEA structure | **Strengths:** - Good coverage of geometric parameters (expressions) - Mass properties extraction working - Material assignments captured **Weaknesses:** - **No mesh quality metrics** (aspect ratio, jacobian, warpage, skew) - **No BC details** (applied nodes/elements, magnitudes, DOFs constrained) - **No load details** (force vectors, pressure values, enforced displacements) - **No solver configuration** (solution sequence, analysis type, convergence settings, output requests) - **No parametric dependencies** (which expressions drive which features) - **No sensitivity context** (mass vs stiffness vs frequency targets) - **No result baseline** (pre-optimization stress/displacement state) --- ## 2. Comprehensive Introspection Framework ### 2.1 Five Introspection Layers To capture the full data picture, introspection must cover five layers: ``` ┌─────────────────────────────────────────────────────────────┐ │ Layer 1: GEOMETRIC PARAMETERS │ │ What can change? Expressions, sketches, features │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Layer 2: FEA MODEL STRUCTURE │ │ Mesh, elements, materials, properties, quality │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Layer 3: SOLVER CONFIGURATION │ │ Solutions, subcases, BCs, loads, analysis types │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Layer 4: DEPENDENCIES & RELATIONSHIPS │ │ Feature tree, expression graph, BC-mesh links │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Layer 5: BASELINE RESULTS & SENSITIVITIES │ │ Pre-opt stress/displacement, mass sensitivities │ └─────────────────────────────────────────────────────────────┘ ``` --- ## 3. JSON Schema Design ### 3.1 Top-Level Structure ```json { "introspection_version": "1.0.0", "timestamp": "2026-02-14T18:37:00-05:00", "model_id": "bracket_v2", "files": { "geometry": "bracket.prt", "simulation": "bracket_sim1.sim", "fem": "bracket_fem1.fem", "idealized": "bracket_fem1_i.prt" }, "geometric_parameters": { ... }, "fea_model": { ... }, "solver_configuration": { ... }, "dependencies": { ... }, "baseline_results": { ... }, "optimization_context": { ... } } ``` ### 3.2 Layer 1: Geometric Parameters ```json "geometric_parameters": { "expressions": [ { "name": "thickness", "value": 3.0, "units": "mm", "formula": "3.0", "type": "scalar", "category": "user_defined", "is_constant": false, "part": "bracket.prt", "dependencies": ["p47", "p52"], // Internal expressions that reference this "driven_features": ["Extrude(2)", "Shell(1)"] // Features that use this expression } ], "sketches": [ { "name": "Sketch(1)", "constraints": [ { "type": "dimensional", "driven_by": "width", "entities": ["Line(1)"] } ], "parametric_dimensions": ["width", "height", "fillet_rad"] } ], "features": [ { "name": "Extrude(2)", "type": "NXOpen.Features.Extrude", "parameters": { "distance": "thickness * 2", "direction": [0, 0, 1] }, "suppressed": false, "parent_features": ["Sketch(1)"] } ], "mass_properties": { "mass_kg": 0.234, "volume_mm3": 85000.0, "surface_area_mm2": 15000.0, "center_of_gravity_mm": [12.3, 45.6, 78.9], "computed_at": "2026-02-14T18:37:00-05:00" }, "units": { "length": "Millimeter", "mass": "Kilogram", "force": "Newton", "system": "Metric (mm)" } } ``` ### 3.3 Layer 2: FEA Model Structure ```json "fea_model": { "mesh": { "total_nodes": 12450, "total_elements": 8234, "element_types": { "CTETRA": 7800, "CQUAD4": 434 }, "quality_metrics": { "aspect_ratio": { "min": 1.02, "max": 8.34, "average": 2.45, "std_dev": 1.23, "failed_elements": [] // Element IDs exceeding threshold }, "jacobian": { "min": 0.62, "max": 1.0, "failed_elements": [12, 456, 789] }, "warpage_degrees": { "max": 5.2, "threshold": 10.0, "failed_elements": [] }, "skew_degrees": { "max": 45.2, "threshold": 60.0 } } }, "materials": [ { "name": "Aluminum 6061-T6", "assigned_to": { "bodies": ["Body(1)"], "elements": "all" }, "properties": { "density_kg_mm3": 2.7e-6, "youngs_modulus_MPa": 68900.0, "poisson_ratio": 0.33, "yield_strength_MPa": 276.0, "ultimate_strength_MPa": 310.0, "thermal_expansion_K": 2.36e-5, "thermal_conductivity_W_mK": 167.0 }, "nastran_card": "MAT1" } ], "properties": [ { "id": 1, "name": "Shell_Prop_3mm", "type": "PSHELL", "element_type": "CQUAD4", "thickness_mm": 3.0, "material_id": 1, "assigned_elements": [1, 2, 3, "..."] } ], "collectors": [ { "name": "Shell_Mesh", "type": "2D_mesh", "element_count": 434, "property_assignment": "Shell_Prop_3mm" } ] } ``` ### 3.4 Layer 3: Solver Configuration ```json "solver_configuration": { "solutions": [ { "name": "Solution 1", "solution_sequence": "SOL 101", "analysis_type": "Static Linear", "solver": "NX Nastran", "subcases": [ { "id": 1, "name": "Subcase - Static 1", "load_set": "LoadSet 1", "constraint_set": "ConstraintSet 1", "output_requests": [ { "type": "DISPLACEMENT", "format": "OP2", "all_nodes": true }, { "type": "STRESS", "format": "OP2", "element_types": ["CTETRA", "CQUAD4"], "stress_type": "von_mises" } ] } ], "convergence_criteria": { "displacement_tolerance": 0.001, "force_tolerance": 0.01, "max_iterations": 100 }, "output_files": { "op2": "bracket_sim1_s1.op2", "f06": "bracket_sim1_s1.f06", "log": "bracket_sim1_s1.log" } } ], "boundary_conditions": { "constraints": [ { "name": "Fixed Constraint 1", "type": "SPC", "target": { "geometry_type": "face", "geometry_name": "Face(12)", "node_count": 145, "node_ids": [1, 2, 3, "..."] }, "constrained_dofs": [1, 2, 3, 4, 5, 6], // TX, TY, TZ, RX, RY, RZ "dof_names": ["TX", "TY", "TZ", "RX", "RY", "RZ"] } ], "loads": [ { "name": "Force 1", "type": "concentrated_force", "target": { "geometry_type": "vertex", "geometry_name": "Vertex(5)", "node_ids": [456] }, "magnitude_N": 1000.0, "direction": [0, -1, 0], "components": { "FX": 0.0, "FY": -1000.0, "FZ": 0.0 } }, { "name": "Pressure 1", "type": "surface_pressure", "target": { "geometry_type": "face", "geometry_name": "Face(8)", "element_count": 25, "element_ids": [100, 101, 102, "..."] }, "magnitude_MPa": 5.0, "direction": "normal" } ] } } ``` ### 3.5 Layer 4: Dependencies & Relationships ```json "dependencies": { "expression_graph": { "nodes": [ { "name": "thickness", "type": "root_parameter" }, { "name": "p47", "type": "derived", "formula": "thickness * 2" } ], "edges": [ { "from": "thickness", "to": "p47", "relationship": "drives" } ] }, "feature_tree": { "root": "Part", "children": [ { "name": "Sketch(1)", "driven_by": ["width", "height"], "children": [ { "name": "Extrude(2)", "driven_by": ["thickness"], "affects_mass": true, "affects_mesh": true } ] } ] }, "mesh_geometry_links": { "Face(12)": { "mesh_collectors": ["Shell_Mesh"], "elements": [1, 2, 3, "..."], "boundary_conditions": ["Fixed Constraint 1"] } }, "parameter_sensitivities": { "thickness": { "affects": { "mass": "linear", "stiffness": "nonlinear", "frequency": "sqrt" }, "estimated_impact": "high" } } } ``` ### 3.6 Layer 5: Baseline Results & Context ```json "baseline_results": { "pre_optimization_run": { "solution": "Solution 1", "subcase": 1, "timestamp": "2026-02-14T17:00:00-05:00", "converged": true, "iterations": 12 }, "displacement": { "max_magnitude_mm": 2.34, "max_node": 4567, "max_location": [45.2, 67.8, 12.3], "average_mm": 0.45 }, "stress": { "von_mises": { "max_MPa": 145.6, "max_element": 2345, "max_location": [12.1, 34.5, 56.7], "average_MPa": 45.2, "margin_of_safety": 0.89 // (Yield - Max) / Max } }, "frequency": { "mode_1_Hz": 123.4, "mode_2_Hz": 234.5, "mode_3_Hz": 456.7 } }, "optimization_context": { "potential_design_variables": [ { "name": "thickness", "current_value": 3.0, "units": "mm", "suggested_bounds": [1.5, 6.0], "rationale": "Drives mass and stiffness directly" } ], "potential_objectives": [ { "type": "minimize", "metric": "mass", "current_value": 0.234, "units": "kg" }, { "type": "minimize", "metric": "max_displacement", "current_value": 2.34, "units": "mm" } ], "potential_constraints": [ { "metric": "max_von_mises_stress", "limit": 200.0, "units": "MPa", "rationale": "Safety factor 1.5 on yield" }, { "metric": "min_frequency", "limit": 100.0, "units": "Hz", "rationale": "Avoid resonance below 100 Hz" } ], "recommended_study_type": "single_objective_mass_min", "estimated_fea_runtime_seconds": 45 } ``` --- ## 4. Extraction Methods — NXOpen & pyNastran Mapping ### 4.1 Geometric Parameters | Data | NXOpen API | Notes | |------|------------|-------| | Expressions | `part.Expressions` | Filter user vs internal (p0, p1, ...) | | Expression values | `expr.Value` | Current numeric value | | Expression formulas | `expr.RightHandSide` | String formula | | Expression units | `expr.Units.Name` | Unit object | | Feature list | `part.Features` | Iterator over all features | | Feature parameters | Feature-specific builders | Requires feature type dispatch | | Sketch constraints | `sketch.Constraints` | Dimensional, geometric, etc. | | Mass properties | `part.MeasureManager.NewMassProperties()` | Requires body list | | Body list | `part.Bodies` | Filter solid vs sheet | | Material assignment | `body.GetPhysicalMaterial()` | Per-body material | **Key Script:** Enhance `introspect_part.py` with: - Expression dependency graph (parse RHS formulas) - Feature-to-expression links (traverse feature parameters) - Sketch dimension extraction ### 4.2 FEA Model Structure | Data | NXOpen/pyNastran API | Notes | |------|----------------------|-------| | Node count | `femPart.FEModel.FenodeLabelMap.Size` | NXOpen CAE | | Element count | `femPart.FEModel.FeelementLabelMap.Size` | NXOpen CAE | | Element types | `pyNastran: bdf.elements` | Parse BDF for CTETRA, CQUAD4, etc. | | Mesh quality | `QualityAuditBuilder` | NXOpen CAE mesh audit | | Material properties | `pyNastran: bdf.materials[mat_id]` | Extract MAT1, MAT2 cards | | Property cards | `pyNastran: bdf.properties[prop_id]` | PSHELL, PSOLID, etc. | | Mesh collectors | `femPart.FEModel.MeshCollectors` | NXOpen CAE | **Key Script:** New `introspect_fem.py` using: - pyNastran BDF reading for full element/material data - NXOpen QualityAudit for mesh metrics - Mesh collector iteration ### 4.3 Solver Configuration | Data | NXOpen/BDF API | Notes | |------|----------------|-------| | Solutions | `simPart.Simulation.FindObject("Solution[...]")` | Pattern-based search | | Solution type | `solution.SolutionType` | SOL 101, 103, etc. | | Subcases | BDF parsing: `SUBCASE` cards | pyNastran | | Load sets | BDF parsing: `LOAD` cards | pyNastran | | Constraint sets | BDF parsing: `SPC` cards | pyNastran | | Output requests | BDF parsing: `DISPLACEMENT`, `STRESS` | pyNastran | | BC details | `simPart.Simulation` BC objects | NXOpen (limited) | | Load magnitudes | BDF parsing: `FORCE`, `PLOAD4` | pyNastran | **Key Script:** Enhance `introspect_sim.py` + new `introspect_bdf.py`: - Full BDF parsing for subcases, loads, BCs - Solution property extraction (convergence, output) ### 4.4 Dependencies & Relationships | Data | Extraction Method | Notes | |------|-------------------|-------| | Expression graph | Parse `expr.RightHandSide` | Regex to find referenced expressions | | Feature tree | `feature.GetParents()` | NXOpen feature relationships | | Feature-expression links | Feature parameter inspection | Type-specific (Extrude, Shell, etc.) | | Mesh-geometry links | `meshCollector.GetElements()` + geometry | NXOpen CAE | **Key Script:** New `build_dependency_graph.py`: - Graph structure (nodes = expressions/features, edges = dependencies) - Export as JSON adjacency list ### 4.5 Baseline Results | Data | Extraction Method | Notes | |------|-------------------|-------| | Displacement | `pyNastran: op2.displacements[subcase]` | OP2 result reading | | Stress | `pyNastran: op2.stress[subcase]` | Von Mises, principal | | Frequency | `pyNastran: op2.eigenvalues[subcase]` | Modal analysis | | Convergence | Parse `.f06` log file | Text parsing | **Key Script:** Use existing Atomizer extractors: - `extract_displacement.py` - `extract_von_mises_stress.py` - `extract_frequency.py` --- ## 5. Implementation Roadmap ### Phase 1: Enhanced Part Introspection (1-2 days) **Goal:** Capture full geometric parameter knowledge **Tasks:** 1. Enhance `introspect_part.py`: - Add expression dependency parsing (RHS formula analysis) - Add feature parameter extraction - Add sketch constraint extraction - Build parametric relationship graph **Output:** `part_introspection_v2.json` ### Phase 2: FEM Model Deep Dive (2-3 days) **Goal:** Full mesh, material, property extraction **Tasks:** 1. Create `introspect_fem.py`: - pyNastran BDF parsing for elements, materials, properties - NXOpen mesh quality audit - Mesh collector iteration - Element type distribution **Output:** `fem_introspection.json` ### Phase 3: Solver Configuration Capture (2-3 days) **Goal:** Complete BC, load, subcase, solution data **Tasks:** 1. Enhance `introspect_sim.py`: - BDF-based subcase extraction - Load/BC detail parsing (magnitudes, DOFs, targets) - Output request cataloging - Solution property extraction **Output:** `solver_introspection.json` ### Phase 4: Dependency Mapping (2 days) **Goal:** Build relationship graphs **Tasks:** 1. Create `build_dependency_graph.py`: - Expression graph construction - Feature tree traversal - Mesh-geometry linking - Sensitivity estimation (heuristic) **Output:** `dependency_graph.json` ### Phase 5: Baseline Results Integration (1 day) **Goal:** Pre-optimization state capture **Tasks:** 1. Create `extract_baseline_results.py`: - Run existing Atomizer extractors - Aggregate into baseline JSON - Compute margins of safety **Output:** `baseline_results.json` ### Phase 6: Master Introspection Orchestrator (2 days) **Goal:** Single command to run all introspection **Tasks:** 1. Create `run_full_introspection.py`: - Orchestrate all 5 phases - Merge JSON outputs into master schema - Validate schema completeness - Generate human-readable summary report **Output:** `model_introspection_FULL.json` + `introspection_summary.md` **Total Estimate:** 10-13 days for full implementation --- ## 6. Integration with Atomizer HQ ### 6.1 Usage Workflow ```bash # Pre-optimization introspection cd /path/to/study/1_setup/model python /atomizer/nx_journals/run_full_introspection.py bracket.prt bracket_sim1.sim # Output # → model_introspection_FULL.json # → introspection_summary.md ``` ### 6.2 Knowledge Base Population The full introspection JSON feeds Atomizer HQ with: - **Study Builder:** What design variables are available, suggested bounds - **Optimizer:** What constraints/objectives make sense, expected runtimes - **Reporter:** Baseline state for comparison, sensitivity context - **Manager:** Study complexity assessment, resource allocation ### 6.3 Automated Study Suggestions With full introspection, Atomizer can: - **Auto-suggest design variables** based on expression analysis - **Estimate optimization difficulty** based on parameter count, mesh size - **Recommend solver sequences** based on analysis type - **Validate study setup** before expensive FEA runs --- ## 7. Example: Bracket Study Introspection Output **Input:** - `bracket.prt` (geometry with expressions: thickness, width, height) - `bracket_sim1.sim` (static analysis, fixed face, force applied) - `bracket_fem1.fem` (CTETRA mesh, 8234 elements) **Introspection Output Highlights:** ```json { "model_id": "bracket_v2", "geometric_parameters": { "expressions": [ {"name": "thickness", "value": 3.0, "units": "mm", "driven_features": ["Extrude(2)", "Shell(1)"]}, {"name": "width", "value": 50.0, "units": "mm", "driven_features": ["Sketch(1)"]}, {"name": "height", "value": 100.0, "units": "mm", "driven_features": ["Sketch(1)"]} ], "mass_properties": {"mass_kg": 0.234} }, "fea_model": { "mesh": { "total_elements": 8234, "element_types": {"CTETRA": 8234}, "quality_metrics": { "aspect_ratio": {"average": 2.45, "max": 8.34} } } }, "solver_configuration": { "solutions": [ { "name": "Solution 1", "solution_sequence": "SOL 101", "subcases": [{"id": 1, "name": "Static 1"}] } ], "boundary_conditions": { "constraints": [{"name": "Fixed Constraint 1", "constrained_dofs": ["TX", "TY", "TZ", "RX", "RY", "RZ"]}], "loads": [{"name": "Force 1", "magnitude_N": 1000.0, "direction": [0, -1, 0]}] } }, "optimization_context": { "potential_design_variables": [ {"name": "thickness", "suggested_bounds": [1.5, 6.0]}, {"name": "width", "suggested_bounds": [30.0, 70.0]}, {"name": "height", "suggested_bounds": [80.0, 120.0]} ], "potential_objectives": [ {"type": "minimize", "metric": "mass", "current_value": 0.234} ], "recommended_study_type": "single_objective_mass_min" } } ``` **Human-Readable Summary:** ``` INTROSPECTION SUMMARY — bracket_v2 =================================== DESIGN SPACE - 3 user-defined expressions detected - Recommended design variables: thickness, width, height - Suggested bounds: thickness [1.5-6.0] mm, width [30-70] mm, height [80-120] mm FEA MODEL - Mesh: 8,234 CTETRA elements, 12,450 nodes - Quality: Avg aspect ratio 2.45 (acceptable), max 8.34 (borderline) - Material: Aluminum 6061-T6, E=68.9 GPa, ρ=2.7e-6 kg/mm³ PHYSICS - Analysis: SOL 101 (Static Linear) - Boundary conditions: 1 fixed constraint (Face 12), 1 force (1000 N, -Y direction) - Baseline: Max displacement 2.34 mm, Max stress 145.6 MPa (MoS = 0.89) OPTIMIZATION CONTEXT - Recommended study: Minimize mass - Constraints: Keep max stress < 200 MPa (safety factor 1.5) - Estimated FEA runtime: ~45 seconds per trial ``` --- ## 8. Future Enhancements ### 8.1 Advanced Introspection - **Topology optimization regions:** Identify design vs non-design space - **Composite layups:** Ply stack introspection for composite parts - **Thermal-structural coupling:** Multi-physics BC detection - **Contact detection:** Identify contact pairs, friction coefficients - **Dynamic loads:** PSD, time-history, random vibration ### 8.2 AI-Powered Analysis - **Sensitivity prediction:** ML model to estimate parameter sensitivities without running FEA - **Design variable clustering:** Auto-group correlated parameters - **Failure mode prediction:** Identify likely failure locations based on geometry/BCs ### 8.3 Live Introspection - **NX session monitoring:** Real-time introspection as model is edited - **Change detection:** Diff between introspection snapshots - **Validation alerts:** Warn when mesh degrades, BCs become invalid --- ## 9. Conclusion This master introspection framework transforms Atomizer from a study executor to an intelligent optimization assistant. By capturing the **full data picture**: 1. **Study setup becomes conversational** — "What can I optimize?" gets a real answer 2. **Validation is automatic** — Catch invalid BCs, bad mesh, missing materials before FEA runs 3. **Knowledge accumulates** — Every introspection feeds the Atomizer HQ knowledge base 4. **Optimization is smarter** — Suggested variables, bounds, objectives based on model analysis **Next Steps:** 1. Review this plan with Antoine 2. Prioritize phases (likely start with Phase 1-2) 3. Implement enhanced `introspect_part.py` + new `introspect_fem.py` 4. Test on existing Atomizer studies (M1 mirror, bracket, beam) 5. Iterate schema based on real-world usage --- **Status:** Research complete — awaiting approval to proceed with implementation. **Contact:** NX Expert 🖥️ | #nx-cad