Files
Atomizer/docs/plans/NX_OPEN_AUTOMATION_ROADMAP.md
Antoine 0cb2808c44 feat: Add Phase 2 & 3 physics extractors for multi-physics optimization
Phase 2 - Structural Analysis:
- extract_principal_stress: σ1, σ2, σ3 principal stresses from OP2
- extract_strain_energy: Element and total strain energy
- extract_spc_forces: Reaction forces at boundary conditions

Phase 3 - Multi-Physics:
- extract_temperature: Nodal temperatures from thermal OP2 (SOL 153/159)
- extract_temperature_gradient: Thermal gradient approximation
- extract_heat_flux: Element heat flux from thermal analysis
- extract_modal_mass: Modal effective mass from F06 (SOL 103)
- get_first_frequency: Convenience function for first natural frequency

Documentation:
- Updated SYS_12_EXTRACTOR_LIBRARY.md with E12-E18 specifications
- Updated NX_OPEN_AUTOMATION_ROADMAP.md marking Phase 3 complete
- Added test_phase3_extractors.py for validation

All extractors follow consistent API pattern returning Dict with
success, data, and error fields for robust error handling.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 13:40:14 -05:00

718 lines
28 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Atomizer NX Open Automation Roadmap
## Plan de Match: Hooks, Extractors & Manipulators pour Optimisation FEA
**Date**: 2025-12-06
**Version**: 2.0 (merged with ATOMIZER_NXOPEN_MASTER_PLAN.md)
**Objectif**: Définir l'ensemble des fonctionnalités NX Open à implémenter pour un framework d'optimisation structurelle/thermique complet, basé sur la règle 80/20.
---
## Quick Reference: NX Open API Index
### Core Classes (verified via MCP)
| Class | Page ID | Primary Use |
|-------|---------|-------------|
| `NXOpen.Session` | a03318.html | Session singleton, part access |
| `NXOpen.Part` | a02434.html | Part operations, expressions |
| `NXOpen.BasePart` | a00266.html | Base class, common methods |
| `NXOpen.CAE.CaeSession` | a10510.html | CAE session, utilities |
| `NXOpen.CAE.FemPart` | - | FEM part, mesh access |
| `NXOpen.CAE.SimPart` | - | Simulation part, solutions |
### Key Collections & Managers (from NXOpen.Part)
| Manager | Access | Purpose |
|---------|--------|---------|
| `Expressions` | `part.Expressions` | Expression management |
| `MeasureManager` | `part.MeasureManager()` | Mass properties |
| `Bodies` | `part.Bodies()` | Body collection |
| `Features` | `part.Features()` | Feature collection |
| `MaterialManager` | `part.MaterialManager()` | Material assignment |
### CAE Managers (from NXOpen.CAE.CaeSession)
| Manager | Access | Purpose |
|---------|--------|---------|
| `MaterialUtils` | `cae_session.MaterialUtils()` | CAE material utilities |
| `AssociationUtils` | `cae_session.AssociationUtils()` | Geometry-FEM association |
| `PenetrationCheckManager` | `cae_session.PenetrationCheckManager()` | Contact check |
---
## 1. Analyse de l'Industrie MDO
### Fonctionnalités Standard (ce que font les concurrents)
| Fonctionnalité | HyperStudy | modeFRONTIER | HEEDS | OpenMDAO | Atomizer (actuel) |
|----------------|------------|--------------|-------|----------|-------------------|
| DOE (LHS, Sobol, etc.) | ✓ | ✓ | ✓ | ✓ | ✓ |
| Optimisation mono-objectif | ✓ | ✓ | ✓ | ✓ | ✓ |
| Multi-objectif (Pareto) | ✓ | ✓ | ✓ | ✓ | ✓ |
| Surrogate Models | ✓ | ✓ | ✓ | ✓ | ✓ (NN) |
| Kriging/Gaussian Process | ✓ | ✓ | ✓ | ✓ | ❌ |
| Robustesse/Fiabilité (RBDO) | ✓ | ✓ | ❌ | ✓ | ❌ |
| Sensibilité paramétrique | ✓ | ✓ | ✓ | ✓ | Partiel |
| Topology Optimization | ✓ | ❌ | ❌ | ❌ | ❌ |
| Workflow visuel | ✓ | ✓ | ✓ | ❌ | ❌ |
| Interface NX native | ❌ | ❌ | ✓ | ❌ | ✓ |
### Sources
- [Altair HyperStudy](https://altair.com/hyperstudy/)
- [modeFRONTIER](https://engineering.esteco.com/modefrontier/)
- [OpenMDAO](https://openmdao.org/)
- [M4 Engineering NXOpen Example](https://www.m4-engineering.com/automating-load-case-combination-and-enveloping-in-simcenter-3d-using-nxopen-python/)
---
## 2. Capacités Simcenter 13500
### Modules Disponibles avec ta Licence
| Module | Description | Utilisable pour Optimisation |
|--------|-------------|------------------------------|
| **NX Nastran Basic** | Static, Modal, Buckling | ✓ Priorité haute |
| **NX Nastran Dynamic** | Frequency/Transient Response | ✓ Priorité moyenne |
| **NX Nastran Thermal** | Heat Transfer (steady/transient) | ✓ Priorité haute |
| **NX Nastran Optimization** | SOL 200 (taille, forme) | ✓ Priorité moyenne |
| **Simcenter 3D Pre/Post** | Meshing, Results | ✓ Indispensable |
### Types d'Analyses Supportées
1. **Structurel Linéaire** (SOL 101)
- Static stress/displacement
- Reaction forces
2. **Modal** (SOL 103)
- Natural frequencies
- Mode shapes
- Modal effective mass
3. **Buckling** (SOL 105)
- Critical load factors
- Buckling mode shapes
4. **Thermique** (SOL 153/159)
- Steady-state heat transfer
- Transient thermal
- Thermal stress coupling
5. **Dynamique** (SOL 108/109/111/112)
- Frequency response
- Transient response
- Random response
---
## 3. Architecture des Hooks NX Open
### 3.1 Hooks de Manipulation CAD (Priorité 1)
```
optimization_engine/
└── hooks/
└── nx_cad/
├── __init__.py
├── part_manager.py # Open/Save/Close parts
├── expression_manager.py # Get/Set expressions
├── feature_manager.py # Suppress/Unsuppress features
├── geometry_query.py # Query geometry (mass, volume, area)
└── assembly_manager.py # Component positioning
```
| Hook | Description | API NX Open | Priorité |
|------|-------------|-------------|----------|
| `open_part(path)` | Ouvrir une pièce | `Session.Parts.OpenBase()` | P1 |
| `close_part(save=False)` | Fermer une pièce | `Part.Close()` | P1 |
| `set_expression(name, value)` | Modifier expression | `Expression.SetValue()` | P1 |
| `get_expression(name)` | Lire expression | `Expression.Value` | P1 |
| `update_model()` | Mettre à jour le modèle | `Session.UpdateManager.DoUpdate()` | P1 |
| `suppress_feature(name)` | Supprimer feature | `Feature.Suppress()` | P2 |
| `get_mass_properties()` | Masse, CG, inertie | `MeasureManager.NewMassProperties()` | P1 |
| `export_parasolid(path)` | Exporter géométrie | `Part.SaveAs()` | P2 |
### 3.2 Hooks FEM/Meshing (Priorité 2)
```
optimization_engine/
└── hooks/
└── nx_fem/
├── __init__.py
├── mesh_manager.py # Create/Update mesh
├── material_manager.py # Assign materials
├── property_manager.py # Shell/Solid properties
├── boundary_conditions.py # Loads & constraints
└── connection_manager.py # Connectors, contacts
```
| Hook | Description | API NX Open | Priorité |
|------|-------------|-------------|----------|
| `create_tet_mesh(body, size)` | Mailler en tétra | `MeshManager.CreateMesh3d()` | P1 |
| `update_mesh()` | Régénérer maillage | `FEModel.UpdateMesh()` | P1 |
| `set_material(mesh, mat_name)` | Assigner matériau | `PhysicalProperty.SetMaterial()` | P1 |
| `create_shell_property(t)` | Propriété shell | `PhysicalPropertyCollection.CreateShellProperty()` | P2 |
| `apply_force(nodes, vector)` | Appliquer force | `LoadCollection.CreateForce()` | P1 |
| `apply_constraint(nodes, dof)` | Appliquer contrainte | `ConstraintCollection.CreateConstraint()` | P1 |
| `create_contact(faces1, faces2)` | Contact surfaces | `ConnectionCollection.CreateSurfaceContact()` | P2 |
### 3.3 Hooks Simulation/Solve (Priorité 1)
```
optimization_engine/
└── hooks/
└── nx_sim/
├── __init__.py
├── solution_manager.py # Create/Run solutions
├── solve_manager.py # Submit solver jobs
└── result_manager.py # Access results
```
| Hook | Description | API NX Open | Priorité |
|------|-------------|-------------|----------|
| `create_solution(type, name)` | Créer solution | `SimSolutionCollection.CreateSolution()` | P1 |
| `solve(solution)` | Lancer solveur | `SimSolution.Solve()` | P1 |
| `solve_batch(bdf_path)` | Nastran en batch | `subprocess` + run_nastran | P1 |
| `get_solve_status()` | Statut du solve | `SimSolution.SolveStatus` | P1 |
| `export_bdf(path)` | Exporter deck Nastran | `SimSolution.ExportSolver()` | P1 |
---
## 4. Architecture des Extractors
### 4.0 Current Implementation Status (as of 2025-12-06)
```
optimization_engine/extractors/
├── __init__.py
├── extract_displacement.py # ✓ extract_displacement()
├── extract_von_mises_stress.py # ✓ extract_solid_stress()
├── extract_frequency.py # ✓ extract_frequency()
├── extract_mass.py # ✓ extract_generic()
├── extract_mass_from_bdf.py # ✓ extract_mass_from_bdf()
├── extract_mass_from_expression.py # ✓ extract_mass_from_expression()
├── extract_part_mass_material.py # ✓ PartMassExtractor (NX Open via journal)
├── bdf_mass_extractor.py # ✓ BDFMassExtractor class
├── op2_extractor.py # ✓ OP2Extractor class (mass, grid forces, loads)
├── field_data_extractor.py # ✓ FieldDataExtractor class
├── extract_zernike.py # ✓ ZernikeExtractor class (advanced)
├── extract_zernike_surface.py # ✓ SurfaceZernikeExtractor class
└── zernike_helpers.py # ✓ Helper functions
```
### 4.1 Extractors Structurels (Priorité 1)
| Extractor | Output | Source | Priorité | Status | File |
|-----------|--------|--------|----------|--------|------|
| `extract_displacement(op2, subcase)` | mm | OP2 | P1 | ✓ | extract_displacement.py |
| `extract_solid_stress(op2, subcase, elem_type)` | MPa | OP2 | P1 | ✓ | extract_von_mises_stress.py |
| `extract_mass_from_bdf(bdf)` | kg | BDF | P1 | ✓ | bdf_mass_extractor.py |
| `extract_mass_from_op2(op2)` | kg | OP2 | P1 | ✓ | op2_extractor.py |
| `extract_grid_point_forces(op2)` | N | OP2 | P1 | ✓ | op2_extractor.py |
| `extract_displacement_field(op2)` | [mm] | OP2 | P1 | ✓ | field_data_extractor.py |
| `extract_principal_stress(elem)` | MPa | OP2 | P2 | ❌ | - |
| `extract_strain(elem)` | - | OP2 | P2 | ❌ | - |
| `extract_strain_energy(elem)` | J | OP2 | P2 | ❌ | - |
### 4.2 Extractors Modaux (Priorité 2)
| Extractor | Output | Source | Priorité | Status | File |
|-----------|--------|--------|----------|--------|------|
| `extract_frequency(op2, subcase, mode)` | Hz | OP2 | P1 | ✓ | extract_frequency.py |
| `extract_modal_mass(mode)` | kg | F06 | P2 | ❌ | - |
| `extract_mode_shape(mode, nodes)` | [mm] | OP2 | P3 | ❌ | - |
| `extract_mac_matrix(modes)` | [0-1] | Calc | P3 | ❌ | - |
### 4.3 Extractors Thermiques (Priorité 2)
| Extractor | Output | Source | Priorité | Status | File |
|-----------|--------|--------|----------|--------|------|
| `extract_temperature(node)` | °C/K | OP2/F06 | P2 | ❌ | - |
| `extract_max_temperature()` | °C/K | OP2/F06 | P2 | ❌ | - |
| `extract_heat_flux(elem)` | W/m² | OP2/F06 | P2 | ❌ | - |
| `extract_thermal_stress(elem)` | MPa | OP2/F06 | P2 | ❌ | - |
### 4.4 Extractors Géométriques (CAD) (Priorité 1) - NX Open
| Extractor | Output | Source | Priorité | Status | File |
|-----------|--------|--------|----------|--------|------|
| `extract_part_mass_material(prt)` | kg, material | NX Open | P1 | ✓ | extract_part_mass_material.py |
| `extract_part_mass(prt)` | kg | NX Open | P1 | ✓ | extract_part_mass_material.py |
| `extract_part_material(prt)` | string | NX Open | P1 | ✓ | extract_part_mass_material.py |
| `extract_mass_from_expression(prt)` | kg | NX Open | P1 | ✓ | extract_mass_from_expression.py |
| `extract_volume()` | mm³ | NX Open | P2 | ❌ | - |
| `extract_surface_area()` | mm² | NX Open | P2 | ❌ | - |
| `extract_center_of_gravity()` | [mm] | NX Open | P2 | ❌ | - |
| `extract_inertia_tensor()` | kg·mm² | NX Open | P3 | ❌ | - |
**NX Open APIs for CAD Extraction**:
- `part.MeasureManager()` - Main entry point for mass properties
- `MeasureManager.NewMassProperties()` - Create mass measurement
- `MasProperties.Mass`, `.CenterOfGravity`, `.MomentsOfInertia`
### 4.5 Extractors Buckling (Priorité 3)
| Extractor | Output | Source | Priorité | Status | File |
|-----------|--------|--------|----------|--------|------|
| `extract_buckling_factor(mode)` | - | F06 | P3 | ❌ | - |
| `extract_critical_load()` | N | F06 | P3 | ❌ | - |
### 4.6 Extractors Zernike (Spécialisé Optique) ✓
| Extractor | Output | Source | Priorité | Status | File |
|-----------|--------|--------|----------|--------|------|
| `ZernikeExtractor.extract_subcase()` | coeffs | OP2 | P1 | ✓ | extract_zernike.py |
| `ZernikeExtractor.extract_relative()` | delta_coeffs | OP2 | P1 | ✓ | extract_zernike.py |
| `extract_zernike_from_op2()` | coeffs | OP2 | P1 | ✓ | extract_zernike.py |
| `extract_zernike_filtered_rms()` | RMS(nm) | OP2 | P1 | ✓ | extract_zernike.py |
| `SurfaceZernikeExtractor.extract_from_op2()` | coeffs | OP2 | P1 | ✓ | extract_zernike_surface.py |
**Usage**: Mirror/lens deformation optimization using Zernike polynomial decomposition
---
## 5. Manipulateurs Avancés
### 5.1 Manipulateurs de Forme (Shape Optimization)
```
optimization_engine/
└── manipulators/
├── morpher.py # Morphing mesh/géométrie
├── ffd.py # Free-Form Deformation
└── surface_offset.py # Offset surfaces
```
| Manipulator | Description | Priorité |
|-------------|-------------|----------|
| `morph_nodes(nodes, displacements)` | Morphing direct | P3 |
| `ffd_box(control_points)` | Déformation FFD | P3 |
| `offset_faces(faces, distance)` | Offset paramétrique | P2 |
### 5.2 Manipulateurs Topologiques (Future)
| Manipulator | Description | Priorité |
|-------------|-------------|----------|
| `apply_density_filter(elements)` | SIMP filtering | P4 |
| `extract_iso_surface(density)` | Topology to geometry | P4 |
| `create_lattice_infill(region)` | Lattice génération | P4 |
---
## 6. Plan d'Implémentation 80/20
### Phase 1: Fondations ✓ COMPLETED
**Objectif**: Stabiliser le workflow de base
| # | Tâche | Fichier | Status |
|---|-------|---------|--------|
| 1.1 | Expression manipulation via .exp file | `nx_updater.py` | ✓ |
| 1.2 | Mass extraction from BDF | `bdf_mass_extractor.py` | ✓ |
| 1.3 | Mass extraction from NX Open | `extract_part_mass_material.py` | ✓ |
| 1.4 | Displacement extraction | `extract_displacement.py` | ✓ |
| 1.5 | Von Mises stress extraction | `extract_von_mises_stress.py` | ✓ |
| 1.6 | Frequency extraction | `extract_frequency.py` | ✓ |
### Phase 1b: NX Open Hooks ✓ COMPLETED (2025-12-06)
**Objectif**: Create direct NX Open Python hooks for CAD/FEM operations
**Location**: `optimization_engine/hooks/nx_cad/`
| # | Tâche | API (verified via MCP) | Status | File |
|---|-------|------------------------|--------|------|
| 1b.1 | Hook: `open_part` / `close_part` / `save_part` | `Session.Parts.OpenBase()`, `Part.Close()`, `Part.Save()` | ✓ | part_manager.py |
| 1b.2 | Hook: `get_expression` / `set_expression` / `set_expressions` | `part.Expressions`, `Expressions.Edit()` | ✓ | expression_manager.py |
| 1b.3 | Hook: `update_model` (integrated) | `Session.UpdateManager.DoUpdate()` | ✓ | expression_manager.py |
| 1b.4 | Hook: `get_mass_properties` / `get_bodies` / `get_volume` | `MeasureManager.NewMassProperties()` | ✓ | geometry_query.py |
| 1b.5 | Hook: `suppress_feature` / `unsuppress_feature` | `Feature.Suppress()`, `Feature.Unsuppress()` | ✓ | feature_manager.py |
| 1b.6 | Hook: `save_part_as` (export) | `Part.SaveAs()` | ✓ | part_manager.py |
### Phase 2: Workflow Complet ✓ COMPLETED
**Objectif**: Automatiser le cycle CAD → FEM → Results
| # | Tâche | API / Fichier | Status |
|---|-------|---------------|--------|
| 2.1 | BDF export via NX Open | `solver_manager.export_bdf()` | ✓ |
| 2.2 | Batch solver launch | `subprocess` + NX run_solver | ✓ (external) |
| 2.3 | Principal stress extraction | `extract_principal_stress()` | ✓ |
| 2.4 | Strain energy extraction | `extract_strain_energy()` | ✓ |
| 2.5 | Reaction force extraction | `extract_spc_forces()` | ✓ |
| 2.6 | **Model Introspection** | `model_introspection.py` | ✓ |
**Files Created (2025-12-06):**
- `optimization_engine/hooks/nx_cae/solver_manager.py` - BDF export & solve hooks
- `optimization_engine/extractors/extract_principal_stress.py` - Principal stress (σ1, σ2, σ3)
- `optimization_engine/extractors/extract_strain_energy.py` - Element strain energy
- `optimization_engine/extractors/extract_spc_forces.py` - Reaction forces at BCs
- `optimization_engine/hooks/nx_cad/model_introspection.py` - **Comprehensive model introspection**
**Phase 2 Introspection Feature (2025-12-06):**
The model introspection module provides comprehensive extraction of:
- **Part (.prt)**: Expressions, bodies, mass properties, features, materials
- **Simulation (.sim)**: Solutions, boundary conditions, loads, materials, mesh info, output requests
- **Results (.op2)**: Available results (displacement, stress, strain, SPC forces, frequencies), subcases
Usage:
```python
from optimization_engine.hooks.nx_cad.model_introspection import (
introspect_part,
introspect_simulation,
introspect_op2,
introspect_study
)
# Introspect entire study
study_info = introspect_study("studies/my_study/")
```
### Phase 3: Multi-Physique ✓ COMPLETED (Core Extractors)
**Objectif**: Support thermique et dynamique
**Priority**: P1 (High) - Extends optimization to thermal/dynamic domains
| # | Tâche | API / Fichier | Status | Priority |
|---|-------|---------------|--------|----------|
| 3.1 | Temperature extraction | `extract_temperature.py` | ✓ | P1 |
| 3.2 | Thermal gradient extraction | `extract_temperature_gradient()` | ✓ | P1 |
| 3.3 | Thermal stress extraction | OP2 + thermal subcase | ✓ (via E3) | P1 |
| 3.4 | Modal mass extraction | `extract_modal_mass.py` | ✓ | P1 |
| 3.5 | Heat flux extraction | `extract_heat_flux()` | ✓ | P2 |
| 3.6 | Thermal BC setup hook | `NXOpen.CAE.LoadCollection` | ❌ | P2 |
| 3.7 | Thermo-mechanical coupling | Multi-step solve | ❌ | P3 |
**Files Created (2025-12-06):**
- `optimization_engine/extractors/extract_temperature.py` - Temperature, gradient, heat flux (E15-E17)
- `optimization_engine/extractors/extract_modal_mass.py` - Modal effective mass from F06 (E18)
- `optimization_engine/extractors/test_phase3_extractors.py` - Phase 3 test suite
**Phase 3 Implementation Guide:**
#### 3.1 Temperature Extraction
```python
# Target API (pyNastran)
from pyNastran.op2.op2 import read_op2
op2 = read_op2(op2_file)
temperatures = op2.temperatures # TEMP subcase results
def extract_temperature(op2_file, subcase=1, nodes=None):
"""Extract nodal temperatures from thermal analysis.
Returns:
dict: {
'max_temperature': float (°C or K),
'min_temperature': float,
'avg_temperature': float,
'temperatures': {node_id: temp, ...}
}
"""
```
#### 3.2 Thermal Gradient Extraction
```python
def extract_thermal_gradient(op2_file, subcase=1):
"""Extract temperature gradients from thermal analysis.
Returns:
dict: {
'max_gradient': float (K/mm),
'avg_gradient': float,
'gradient_location': int (element_id)
}
"""
```
#### 3.3 Thermal Stress Extraction
```python
def extract_thermal_stress(op2_file, subcase=1, element_type='ctetra'):
"""Extract stress from thermal-mechanical analysis.
Notes:
- Requires coupled thermal-structural solution
- Uses temperature field as load
Returns:
dict: Similar to extract_solid_stress but from thermal loading
"""
```
#### 3.4 Modal Mass Extraction
```python
def extract_modal_mass(f06_file, mode_number=1):
"""Extract modal effective mass from F06 file.
Returns:
dict: {
'modal_mass_x': float (kg),
'modal_mass_y': float,
'modal_mass_z': float,
'participation_factor': float
}
"""
```
**Expected Outputs After Phase 3:**
- New extractors: `extract_temperature.py`, `extract_thermal_gradient.py`, `extract_modal_mass.py`
- Updated protocol SYS_12: Add E15-E18 for thermal extractors
- New study templates: Thermal optimization, thermo-mechanical optimization
### Phase 4: AtomizerField Integration (from Master Plan)
**Objectif**: Neural network surrogate for field prediction
| # | Tâche | Description | Status |
|---|-------|-------------|--------|
| 4.1 | Mesh Graph Builder | GNN graph from FEM mesh | ❌ |
| 4.2 | Training Data Exporter | Mesh + BC + results package | ❌ |
| 4.3 | Field Mapper | GNN predictions → NX format | ❌ |
| 4.4 | Sample Validation | Check convergence/quality | ❌ |
### Phase 5: Surrogates & Advanced
**Objectif**: Kriging, topology, lattice
| # | Tâche | Status |
|---|-------|--------|
| 5.1 | Gaussian Process / Kriging surrogate | ❌ |
| 5.2 | SOL 200 interface (native topo) | ❌ |
| 5.3 | Lattice infill generation | ❌ |
| 5.4 | FFD morphing | ❌ |
---
## 7. Classes NX Open Clés (Verified via MCP)
### Session & Part Access
```python
import NXOpen
# Session singleton
session = NXOpen.Session.GetSession()
# Part access
work_part = session.Parts.Work # Current work part (Part object)
display_part = session.Parts.Display # Display part
all_parts = session.Parts # PartCollection
# Key Part methods (from a02434.html):
expressions = work_part.Expressions # ExpressionCollection
bodies = work_part.Bodies() # BodyCollection
features = work_part.Features() # FeatureCollection
measure_mgr = work_part.MeasureManager() # For mass properties
material_mgr = work_part.MaterialManager() # Material assignment
```
### Expression Manipulation
```python
# Find expression by name
expr = work_part.Expressions.FindObject("width")
# Get value
value = expr.Value # float
units = expr.Units # Unit object
# Set value (with units)
unit = work_part.UnitCollection.FindObject("MilliMeter")
work_part.Expressions.EditWithUnits(expr, unit, "50.0")
# Import from .exp file (batch update - robust method)
work_part.Expressions.ImportFromFile(
exp_path,
NXOpen.ExpressionCollection.ExportMode.Replace
)
# Update model after changes
session.UpdateManager.DoUpdate(session.SetUndoMark(...))
```
### Mass Properties
```python
# Create mass measurement
mass_props = work_part.MeasureManager().NewMassProperties(
accuracy, # int: 0.97-0.99 typical
infoUnits, # MassPropertiesInfo for units
bodies # Array of Body objects
)
# Get properties
mass = mass_props.Mass # float (kg)
cog = mass_props.CenterOfGravity # Point3d (x,y,z)
inertia = mass_props.MomentsOfInertia # Matrix3x3
volume = mass_props.Volume # float (mm³)
area = mass_props.SurfaceArea # float (mm²)
```
### CAE/FEM Access
```python
from NXOpen.CAE import CaeSession
# CAE session utilities (from a10510.html)
cae_session = session.CaeSession() # Returns CaeSession
# Key CaeSession methods:
material_utils = cae_session.MaterialUtils() # MaterialUtilities
association_utils = cae_session.AssociationUtils() # AssociationUtilities
mesh_mapping = cae_session.MeshMappingUtils() # MeshMapping.Utils
penetration_mgr = cae_session.PenetrationCheckManager() # PenetrationCheck.Manager
# FEM/SIM parts
fem_part = work_part # When .fem is work part
sim_part = work_part # When .sim is work part
# Access mesh (from FemPart)
mesh_manager = fem_part.MeshManager
for mesh in mesh_manager.GetMeshes():
nodes = mesh.GetNodes()
elements = mesh.GetElements()
# Access solutions (from SimPart)
sim_simulation = sim_part.FindObject("Simulation")
for solution in sim_simulation.Solutions:
name = solution.Name
sol_type = solution.SolutionType
solution.Solve() # Run solver
```
### Feature Manipulation
```python
# Get feature by name
feature = work_part.Features.FindObject("FEATURE_NAME")
# Suppress/unsuppress
feature.Suppress()
feature.Unsuppress()
# Get expression-linked features
for expr in feature.GetExpressions():
print(expr.Name, expr.Value)
```
---
## 8. Structure de Fichiers Finale
```
optimization_engine/
├── hooks/
│ ├── __init__.py
│ ├── nx_cad/
│ │ ├── __init__.py
│ │ ├── part_manager.py
│ │ ├── expression_manager.py
│ │ ├── feature_manager.py
│ │ ├── geometry_query.py
│ │ └── assembly_manager.py
│ ├── nx_fem/
│ │ ├── __init__.py
│ │ ├── mesh_manager.py
│ │ ├── material_manager.py
│ │ ├── property_manager.py
│ │ ├── boundary_conditions.py
│ │ └── connection_manager.py
│ └── nx_sim/
│ ├── __init__.py
│ ├── solution_manager.py
│ ├── solve_manager.py
│ └── result_manager.py
├── extractors/
│ ├── __init__.py
│ ├── displacement.py # ✓
│ ├── stress.py # À améliorer
│ ├── strain.py # Nouveau
│ ├── frequency.py # ✓
│ ├── modal_mass.py # Nouveau
│ ├── temperature.py # Nouveau
│ ├── reaction_force.py # Nouveau
│ ├── cad_mass.py # Nouveau (NX Open)
│ ├── cad_volume.py # Nouveau
│ └── zernike/ # ✓
└── manipulators/
├── __init__.py
├── morpher.py # Future
└── ffd.py # Future
```
---
## 9. Métriques de Succès
### Phase 1 Complete When: ✓ ACHIEVED
- [x] Peut ouvrir/fermer pièce NX via Python ✓ (part_manager.py)
- [x] Peut modifier expressions et update ✓ (expression_manager.py)
- [x] Peut extraire masse depuis CAD (pas BDF) ✓ (geometry_query.py)
- [x] Extrait stress max fiable de tous les éléments ✓ (extract_von_mises_stress.py)
### Phase 2 Complete When: ✓ ACHIEVED (2025-12-06)
- [x] Workflow complet: expression → BDF → solve → extract ✓
- [x] Support de toutes les contraintes mécaniques ✓ (principal stress, SPC forces)
- [x] Extraction de strain energy fonctionnelle ✓ (extract_strain_energy.py)
- [x] **Model Introspection**: Full model analysis capability ✓ (model_introspection.py)
### Phase 3 Complete When: ✓ CORE ACHIEVED (2025-12-06)
- [x] Temperature extraction from OP2 functional ✓ (extract_temperature.py)
- [x] Thermal gradient extraction functional ✓ (extract_temperature_gradient)
- [x] Heat flux extraction functional ✓ (extract_heat_flux)
- [x] Modal mass extraction from F06 functional ✓ (extract_modal_mass.py)
- [ ] At least one thermal optimization study runs successfully
- [ ] Thermo-mechanical coupling documented
- [ ] Thermal BC setup hook (NXOpen.CAE)
---
## 10. Références
### Documentation NX Open (via MCP)
**MCP Tools for NX Open Documentation**:
```
mcp__siemens-docs__nxopen_get_class(className) # Get class doc
mcp__siemens-docs__nxopen_get_index(indexType) # Browse class index
mcp__siemens-docs__nxopen_fetch_page(pagePath) # Fetch any page
mcp__siemens-docs__siemens_docs_list() # List available resources
```
**Key Page IDs**:
| Class | Page ID | URL Path |
|-------|---------|----------|
| Session | a03318.html | `/nxopen_python_ref/a03318.html` |
| Part | a02434.html | `/nxopen_python_ref/a02434.html` |
| BasePart | a00266.html | `/nxopen_python_ref/a00266.html` |
| CaeSession | a10510.html | `/nxopen_python_ref/a10510.html` |
| Class Index | classes.html | `/nxopen_python_ref/classes.html` |
| Function Index | functions_*.html | `/nxopen_python_ref/functions_m.html` (etc.) |
### Ressources Externes
- [NXJournaling.com](https://nxjournaling.com/) - NX Open examples and tutorials
- [NXOpen TSE](https://nxopentsedocumentation.thescriptingengineer.com/) - The Scripting Engineer docs
- [PyNastran Documentation](https://pynastran-git.readthedocs.io/) - OP2/BDF parsing
- [NAFEMS Python FEA Course](https://www.nafems.org/training/e-learning/python-for-fea-automation-and-optimization/)
### Papers & Academic
- Kriging for FEA Optimization: [Springer](https://link.springer.com/article/10.1007/s00158-019-02211-z)
- OpenMDAO Framework: [NASA Technical Report](https://openmdao.org/)
- SIMP Topology Optimization: Bendsøe & Sigmund methods
### Related Atomizer Documentation
- [ATOMIZER_NXOPEN_MASTER_PLAN.md](../07_DEVELOPMENT/ATOMIZER_NXOPEN_MASTER_PLAN.md) - Detailed API specs
- [SYS_12_EXTRACTOR_LIBRARY.md](../protocols/system/SYS_12_EXTRACTOR_LIBRARY.md) - Extractor catalog
- [MCP Server README](../../mcp-server/README.md) - Siemens docs proxy setup
---
## 11. Version History
| Version | Date | Changes |
|---------|------|---------|
| 1.0 | 2025-12-06 | Initial roadmap from industry research |
| 2.0 | 2025-12-06 | Merged with ATOMIZER_NXOPEN_MASTER_PLAN.md, added verified MCP API mappings, updated extractor status |
| 2.1 | 2025-12-06 | **Phase 1b Complete**: NX Open hooks implemented (part_manager, expression_manager, geometry_query, feature_manager) |
| 2.2 | 2025-12-06 | **Phase 2 Complete**: Principal stress, strain energy, SPC forces extractors + solver_manager |
| 2.3 | 2025-12-06 | **Model Introspection**: Added comprehensive model_introspection.py for full part/sim/op2 analysis |
| 2.4 | 2025-12-06 | **Phase 3 Prepared**: Detailed roadmap for thermal/dynamic extractors with implementation guide |
| 2.5 | 2025-12-06 | **Phase 3 Core Complete**: Temperature (E15-E17) and modal mass (E18) extractors implemented |
---
*Generated with assistance from Claude Code using MCP Siemens Documentation tools*