docs: Major documentation overhaul - restructure folders, update tagline, add Getting Started guide
- Restructure docs/ folder (remove numeric prefixes): - 04_USER_GUIDES -> guides/ - 05_API_REFERENCE -> api/ - 06_PHYSICS -> physics/ - 07_DEVELOPMENT -> development/ - 08_ARCHIVE -> archive/ - 09_DIAGRAMS -> diagrams/ - Replace tagline 'Talk, don't click' with 'LLM-driven optimization framework' in 9 files - Create comprehensive docs/GETTING_STARTED.md: - Prerequisites and quick setup - Project structure overview - First study tutorial (Claude or manual) - Dashboard usage guide - Neural acceleration introduction - Rewrite docs/00_INDEX.md with correct paths and modern structure - Archive obsolete files: - 01_PROTOCOLS.md -> archive/historical/01_PROTOCOLS_legacy.md - 03_GETTING_STARTED.md -> archive/historical/ - ATOMIZER_PODCAST_BRIEFING.md -> archive/marketing/ - Update timestamps to 2026-01-20 across all key files - Update .gitignore to exclude docs/generated/ - Version bump: ATOMIZER_CONTEXT v1.8 -> v2.0
This commit is contained in:
449
docs/api/GNN_ARCHITECTURE.md
Normal file
449
docs/api/GNN_ARCHITECTURE.md
Normal file
@@ -0,0 +1,449 @@
|
||||
# GNN Architecture Deep Dive
|
||||
|
||||
**Technical documentation for AtomizerField Graph Neural Networks**
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
AtomizerField uses Graph Neural Networks (GNNs) to learn physics from FEA simulations. This document explains the architecture in detail.
|
||||
|
||||
---
|
||||
|
||||
## Why Graph Neural Networks?
|
||||
|
||||
FEA meshes are naturally graphs:
|
||||
- **Nodes** = Grid points (GRID cards in Nastran)
|
||||
- **Edges** = Element connectivity (CTETRA, CQUAD, etc.)
|
||||
- **Node features** = Position, BCs, material properties
|
||||
- **Edge features** = Element type, length, direction
|
||||
|
||||
Traditional neural networks (MLPs, CNNs) can't handle this irregular structure. GNNs can.
|
||||
|
||||
```
|
||||
FEA Mesh Graph
|
||||
═══════════════════════════════════════════════
|
||||
o───o (N1)──(N2)
|
||||
/│ │\ │╲ │╱
|
||||
o─┼───┼─o → (N3)──(N4)
|
||||
\│ │/ │╱ │╲
|
||||
o───o (N5)──(N6)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Model Architectures
|
||||
|
||||
### 1. Field Predictor GNN
|
||||
|
||||
Predicts complete displacement and stress fields.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Field Predictor GNN │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Input Encoding │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ Node Features (12D per node): │ │
|
||||
│ │ • Position (x, y, z) [3D] │ │
|
||||
│ │ • Material (E, nu, rho) [3D] │ │
|
||||
│ │ • Boundary conditions (fixed per DOF) [6D] │ │
|
||||
│ │ │ │
|
||||
│ │ Edge Features (5D per edge): │ │
|
||||
│ │ • Edge length [1D] │ │
|
||||
│ │ • Direction vector [3D] │ │
|
||||
│ │ • Element type [1D] │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ ↓ │
|
||||
│ Message Passing Layers (6 layers) │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ for layer in range(6): │ │
|
||||
│ │ h = MeshGraphConv(h, edge_index, edge_attr) │ │
|
||||
│ │ h = LayerNorm(h) │ │
|
||||
│ │ h = ReLU(h) │ │
|
||||
│ │ h = Dropout(h, p=0.1) │ │
|
||||
│ │ h = h + residual # Skip connection │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ ↓ │
|
||||
│ Output Heads │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ Displacement Head: │ │
|
||||
│ │ Linear(hidden → 64 → 6) # 6 DOF per node │ │
|
||||
│ │ │ │
|
||||
│ │ Stress Head: │ │
|
||||
│ │ Linear(hidden → 64 → 1) # Von Mises stress │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Output: [N_nodes, 7] (6 displacement + 1 stress) │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Parameters**: 718,221 trainable
|
||||
|
||||
### 2. Parametric Field Predictor GNN
|
||||
|
||||
Predicts scalar objectives directly from design parameters.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Parametric Field Predictor GNN │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Design Parameter Encoding │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ Design Params (4D): │ │
|
||||
│ │ • beam_half_core_thickness │ │
|
||||
│ │ • beam_face_thickness │ │
|
||||
│ │ • holes_diameter │ │
|
||||
│ │ • hole_count │ │
|
||||
│ │ │ │
|
||||
│ │ Design Encoder MLP: │ │
|
||||
│ │ Linear(4 → 64) → ReLU → Linear(64 → 128) │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ ↓ │
|
||||
│ Design-Conditioned GNN │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ # Broadcast design encoding to all nodes │ │
|
||||
│ │ node_features = node_features + design_encoding │ │
|
||||
│ │ │ │
|
||||
│ │ for layer in range(4): │ │
|
||||
│ │ h = GraphConv(h, edge_index) │ │
|
||||
│ │ h = BatchNorm(h) │ │
|
||||
│ │ h = ReLU(h) │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ ↓ │
|
||||
│ Global Pooling │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ mean_pool = global_mean_pool(h) # [batch, 128] │ │
|
||||
│ │ max_pool = global_max_pool(h) # [batch, 128] │ │
|
||||
│ │ design = design_encoding # [batch, 128] │ │
|
||||
│ │ │ │
|
||||
│ │ global_features = concat([mean_pool, max_pool, │ │
|
||||
│ │ design]) # [batch, 384]│ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ ↓ │
|
||||
│ Scalar Prediction Heads │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ MLP: Linear(384 → 128 → 64 → 4) │ │
|
||||
│ │ │ │
|
||||
│ │ Output: │ │
|
||||
│ │ [0] = mass (grams) │ │
|
||||
│ │ [1] = frequency (Hz) │ │
|
||||
│ │ [2] = max_displacement (mm) │ │
|
||||
│ │ [3] = max_stress (MPa) │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Output: [batch, 4] (4 objectives) │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Parameters**: ~500,000 trainable
|
||||
|
||||
---
|
||||
|
||||
## Message Passing
|
||||
|
||||
The core of GNNs is message passing. Here's how it works:
|
||||
|
||||
### Standard Message Passing
|
||||
|
||||
```python
|
||||
def message_passing(node_features, edge_index, edge_attr):
|
||||
"""
|
||||
node_features: [N_nodes, D_node]
|
||||
edge_index: [2, N_edges] # Source → Target
|
||||
edge_attr: [N_edges, D_edge]
|
||||
"""
|
||||
# Step 1: Compute messages
|
||||
source_nodes = node_features[edge_index[0]] # [N_edges, D_node]
|
||||
target_nodes = node_features[edge_index[1]] # [N_edges, D_node]
|
||||
|
||||
messages = MLP([source_nodes, target_nodes, edge_attr]) # [N_edges, D_msg]
|
||||
|
||||
# Step 2: Aggregate messages at each node
|
||||
aggregated = scatter_add(messages, edge_index[1]) # [N_nodes, D_msg]
|
||||
|
||||
# Step 3: Update node features
|
||||
updated = MLP([node_features, aggregated]) # [N_nodes, D_node]
|
||||
|
||||
return updated
|
||||
```
|
||||
|
||||
### Custom MeshGraphConv
|
||||
|
||||
We use a custom convolution that respects FEA mesh structure:
|
||||
|
||||
```python
|
||||
class MeshGraphConv(MessagePassing):
|
||||
"""
|
||||
Custom message passing for FEA meshes.
|
||||
Accounts for:
|
||||
- Edge lengths (stiffness depends on distance)
|
||||
- Element types (different physics for solid/shell/beam)
|
||||
- Direction vectors (anisotropic behavior)
|
||||
"""
|
||||
|
||||
def message(self, x_i, x_j, edge_attr):
|
||||
# x_i: Target node features
|
||||
# x_j: Source node features
|
||||
# edge_attr: Edge features (length, direction, type)
|
||||
|
||||
# Compute message
|
||||
edge_length = edge_attr[:, 0:1]
|
||||
edge_direction = edge_attr[:, 1:4]
|
||||
element_type = edge_attr[:, 4:5]
|
||||
|
||||
# Scale by inverse distance (like stiffness)
|
||||
distance_weight = 1.0 / (edge_length + 1e-6)
|
||||
|
||||
# Combine source and target features
|
||||
combined = torch.cat([x_i, x_j, edge_attr], dim=-1)
|
||||
message = self.mlp(combined) * distance_weight
|
||||
|
||||
return message
|
||||
|
||||
def aggregate(self, messages, index):
|
||||
# Sum messages at each node (like force equilibrium)
|
||||
return scatter_add(messages, index, dim=0)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Feature Engineering
|
||||
|
||||
### Node Features (12D)
|
||||
|
||||
| Feature | Dimensions | Range | Description |
|
||||
|---------|------------|-------|-------------|
|
||||
| Position (x, y, z) | 3 | Normalized | Node coordinates |
|
||||
| Material E | 1 | Log-scaled | Young's modulus |
|
||||
| Material nu | 1 | [0, 0.5] | Poisson's ratio |
|
||||
| Material rho | 1 | Log-scaled | Density |
|
||||
| BC_x, BC_y, BC_z | 3 | {0, 1} | Fixed translation |
|
||||
| BC_rx, BC_ry, BC_rz | 3 | {0, 1} | Fixed rotation |
|
||||
|
||||
### Edge Features (5D)
|
||||
|
||||
| Feature | Dimensions | Range | Description |
|
||||
|---------|------------|-------|-------------|
|
||||
| Length | 1 | Normalized | Edge length |
|
||||
| Direction | 3 | [-1, 1] | Unit direction vector |
|
||||
| Element type | 1 | Encoded | CTETRA=0, CHEXA=1, etc. |
|
||||
|
||||
### Normalization
|
||||
|
||||
```python
|
||||
def normalize_features(node_features, edge_features, stats):
|
||||
"""Normalize to zero mean, unit variance"""
|
||||
|
||||
# Node features
|
||||
node_features = (node_features - stats['node_mean']) / stats['node_std']
|
||||
|
||||
# Edge features (length uses log normalization)
|
||||
edge_features[:, 0] = torch.log(edge_features[:, 0] + 1e-6)
|
||||
edge_features = (edge_features - stats['edge_mean']) / stats['edge_std']
|
||||
|
||||
return node_features, edge_features
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Training Details
|
||||
|
||||
### Optimizer
|
||||
|
||||
```python
|
||||
optimizer = AdamW(
|
||||
model.parameters(),
|
||||
lr=1e-3,
|
||||
weight_decay=1e-4,
|
||||
betas=(0.9, 0.999)
|
||||
)
|
||||
```
|
||||
|
||||
### Learning Rate Schedule
|
||||
|
||||
```python
|
||||
scheduler = CosineAnnealingWarmRestarts(
|
||||
optimizer,
|
||||
T_0=50, # Restart every 50 epochs
|
||||
T_mult=2, # Double period after each restart
|
||||
eta_min=1e-6
|
||||
)
|
||||
```
|
||||
|
||||
### Data Augmentation
|
||||
|
||||
```python
|
||||
def augment_graph(data):
|
||||
"""Random augmentation for better generalization"""
|
||||
|
||||
# Random rotation (physics is rotation-invariant)
|
||||
if random.random() < 0.5:
|
||||
angle = random.uniform(0, 2 * math.pi)
|
||||
data = rotate_graph(data, angle, axis='z')
|
||||
|
||||
# Random noise (robustness)
|
||||
if random.random() < 0.3:
|
||||
data.x += torch.randn_like(data.x) * 0.01
|
||||
|
||||
return data
|
||||
```
|
||||
|
||||
### Batch Processing
|
||||
|
||||
```python
|
||||
from torch_geometric.data import DataLoader
|
||||
|
||||
loader = DataLoader(
|
||||
dataset,
|
||||
batch_size=32,
|
||||
shuffle=True,
|
||||
num_workers=4
|
||||
)
|
||||
|
||||
for batch in loader:
|
||||
# batch.x: [total_nodes, D_node]
|
||||
# batch.edge_index: [2, total_edges]
|
||||
# batch.batch: [total_nodes] - maps nodes to graphs
|
||||
predictions = model(batch)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Model Comparison
|
||||
|
||||
| Model | Parameters | Inference | Output | Use Case |
|
||||
|-------|------------|-----------|--------|----------|
|
||||
| Field Predictor | 718K | 50ms | Full field | When you need field visualization |
|
||||
| Parametric | 500K | 4.5ms | 4 scalars | Direct optimization (fastest) |
|
||||
| Ensemble (5x) | 2.5M | 25ms | 4 scalars + uncertainty | When confidence matters |
|
||||
|
||||
---
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
### PyTorch Geometric
|
||||
|
||||
We use [PyTorch Geometric](https://pytorch-geometric.readthedocs.io/) for GNN operations:
|
||||
|
||||
```python
|
||||
import torch_geometric
|
||||
from torch_geometric.nn import MessagePassing, global_mean_pool
|
||||
|
||||
# Version requirements
|
||||
# torch >= 2.0
|
||||
# torch_geometric >= 2.3
|
||||
```
|
||||
|
||||
### GPU Memory
|
||||
|
||||
| Model | Batch Size | GPU Memory |
|
||||
|-------|------------|------------|
|
||||
| Field Predictor | 16 | 4 GB |
|
||||
| Parametric | 32 | 2 GB |
|
||||
| Training | 16 | 8 GB |
|
||||
|
||||
### Checkpoints
|
||||
|
||||
```python
|
||||
# Save checkpoint
|
||||
torch.save({
|
||||
'model_state_dict': model.state_dict(),
|
||||
'optimizer_state_dict': optimizer.state_dict(),
|
||||
'config': model_config,
|
||||
'normalization_stats': stats,
|
||||
'epoch': epoch,
|
||||
'best_val_loss': best_loss
|
||||
}, 'checkpoint.pt')
|
||||
|
||||
# Load checkpoint
|
||||
checkpoint = torch.load('checkpoint.pt')
|
||||
model = ParametricFieldPredictor(**checkpoint['config'])
|
||||
model.load_state_dict(checkpoint['model_state_dict'])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Physics Interpretation
|
||||
|
||||
### Why GNNs Work for FEA
|
||||
|
||||
1. **Locality**: FEA solutions are local (nodes only affect neighbors)
|
||||
2. **Superposition**: Linear FEA is additive (sum of effects)
|
||||
3. **Equilibrium**: Force balance at each node (sum of messages = 0)
|
||||
|
||||
The GNN learns these principles:
|
||||
- Message passing ≈ Force distribution through elements
|
||||
- Aggregation ≈ Force equilibrium at nodes
|
||||
- Multiple layers ≈ Load path propagation
|
||||
|
||||
### Physical Constraints
|
||||
|
||||
The architecture enforces physics:
|
||||
|
||||
```python
|
||||
# Displacement at fixed nodes = 0
|
||||
displacement = model(data)
|
||||
fixed_mask = data.boundary_conditions > 0
|
||||
displacement[fixed_mask] = 0.0 # Hard constraint
|
||||
|
||||
# Stress-strain relationship (implicit)
|
||||
# Learned by the network through training
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Extension Points
|
||||
|
||||
### Adding New Element Types
|
||||
|
||||
```python
|
||||
# In data_loader.py
|
||||
ELEMENT_TYPES = {
|
||||
'CTETRA': 0,
|
||||
'CHEXA': 1,
|
||||
'CPENTA': 2,
|
||||
'CQUAD4': 3,
|
||||
'CTRIA3': 4,
|
||||
'CBAR': 5,
|
||||
'CBEAM': 6,
|
||||
# Add new types here
|
||||
'CTETRA10': 7, # New 10-node tetrahedron
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Output Heads
|
||||
|
||||
```python
|
||||
class CustomFieldPredictor(FieldPredictorGNN):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Add custom head for thermal analysis
|
||||
self.temperature_head = nn.Linear(hidden_channels, 1)
|
||||
|
||||
def forward(self, data):
|
||||
h = super().forward(data)
|
||||
|
||||
# Add temperature prediction
|
||||
temperature = self.temperature_head(h)
|
||||
return torch.cat([h, temperature], dim=-1)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
1. Battaglia et al. (2018) "Relational inductive biases, deep learning, and graph networks"
|
||||
2. Pfaff et al. (2021) "Learning Mesh-Based Simulation with Graph Networks"
|
||||
3. Sanchez-Gonzalez et al. (2020) "Learning to Simulate Complex Physics with Graph Networks"
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Neural Features Complete](NEURAL_FEATURES_COMPLETE.md) - Overview of all features
|
||||
- [Physics Loss Guide](PHYSICS_LOSS_GUIDE.md) - Loss function selection
|
||||
- [Neural Workflow Tutorial](NEURAL_WORKFLOW_TUTORIAL.md) - Step-by-step guide
|
||||
306
docs/api/NXOPEN_INTELLISENSE_SETUP.md
Normal file
306
docs/api/NXOPEN_INTELLISENSE_SETUP.md
Normal file
@@ -0,0 +1,306 @@
|
||||
# NXOpen Python Intellisense Setup
|
||||
|
||||
> **Status**: ✅ Implemented (2025-11-17)
|
||||
>
|
||||
> Enable intelligent code completion for NXOpen Python API using Siemens-provided stub files
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Siemens NX 2412 includes Python stub files (`.pyi`) that provide full type hints for the NXOpen API. These enable:
|
||||
|
||||
- **Autocomplete**: Suggestions for classes, methods, and properties
|
||||
- **Type Hints**: Parameter types and return values
|
||||
- **Documentation**: Inline docstrings and API descriptions
|
||||
- **Error Detection**: Type checking catches errors before runtime
|
||||
|
||||
This dramatically improves development speed and reduces NXOpen API lookup time.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Siemens NX 2412** (or later) installed with Programming Tools
|
||||
- **VSCode** with **Pylance extension** (usually installed with Python extension)
|
||||
- **Python 3.11** environment (required for NXOpen module compatibility)
|
||||
|
||||
---
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
### Step 0: Ensure Python 3.11 Environment
|
||||
|
||||
NXOpen modules are compiled for Python 3.11. **You must use Python 3.11**:
|
||||
|
||||
```bash
|
||||
# Check your Python version
|
||||
python --version # Should show: Python 3.11.x
|
||||
|
||||
# If using conda, upgrade atomizer environment:
|
||||
conda install -n atomizer python=3.11 -y
|
||||
```
|
||||
|
||||
### Step 1: Add NXOpen to Python Path
|
||||
|
||||
Create a `.pth` file in your Python environment's site-packages to enable NXOpen imports:
|
||||
|
||||
```bash
|
||||
# For atomizer environment:
|
||||
# Create file: C:\Users\<username>\anaconda3\envs\atomizer\Lib\site-packages\nxopen.pth
|
||||
# Contents:
|
||||
C:\Program Files\Siemens\NX2412\NXBIN\python
|
||||
```
|
||||
|
||||
This allows `import NXOpen` to work in your Python scripts!
|
||||
|
||||
### Step 2: Verify Stub Files Exist
|
||||
|
||||
Check that stub files are installed:
|
||||
|
||||
```bash
|
||||
# Windows path:
|
||||
dir "C:\Program Files\Siemens\NX2412\UGOPEN\pythonStubs\NXOpen"
|
||||
|
||||
# Should show: __init__.pyi and many module folders (CAE, Assemblies, etc.)
|
||||
```
|
||||
|
||||
**If missing**: Reinstall NX 2412 and ensure "Programming Tools" is checked during installation.
|
||||
|
||||
### Step 3: Configure VSCode
|
||||
|
||||
Update `.vscode/settings.json` in your Atomizer project:
|
||||
|
||||
```json
|
||||
{
|
||||
"python.analysis.typeCheckingMode": "basic",
|
||||
"python.analysis.stubPath": "C:\\Program Files\\Siemens\\NX2412\\UGOPEN\\pythonStubs"
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: Use double backslashes (`\\`) in Windows paths for JSON.
|
||||
|
||||
### Step 4: Restart VSCode
|
||||
|
||||
Close and reopen VSCode to load the new stub files.
|
||||
|
||||
### Step 5: Verify NXOpen Import and Intellisense Works
|
||||
|
||||
First, test that NXOpen can be imported:
|
||||
|
||||
```python
|
||||
python
|
||||
>>> import NXOpen
|
||||
>>> print("Success! NXOpen is available")
|
||||
>>> exit()
|
||||
```
|
||||
|
||||
Then test intellisense:
|
||||
|
||||
Open `tests/test_nxopen_intellisense.py` and verify:
|
||||
|
||||
1. **Import Autocomplete**:
|
||||
- Type `import NXOpen.` → Should suggest: Part, Session, CAE, Assemblies, etc.
|
||||
|
||||
2. **Method Autocomplete**:
|
||||
- Type `session.` → Should suggest: GetSession(), Parts, etc.
|
||||
- Type `expressions.` → Should suggest: FindObject, CreateExpression, etc.
|
||||
|
||||
3. **Parameter Hints**:
|
||||
- Hover over `CreateExpression()` → Shows parameter types and documentation
|
||||
|
||||
4. **Documentation Tooltips**:
|
||||
- Hover over any NXOpen class/method → Shows docstring
|
||||
|
||||
**If working**: ✅ Intellisense is configured correctly!
|
||||
|
||||
---
|
||||
|
||||
## What You Get
|
||||
|
||||
### Before Intellisense:
|
||||
```python
|
||||
import NXOpen
|
||||
session = NXOpen.Session.GetSession()
|
||||
# ❌ No suggestions when typing "session."
|
||||
# ❌ No parameter hints for methods
|
||||
# ❌ Must look up API in documentation
|
||||
```
|
||||
|
||||
### After Intellisense:
|
||||
```python
|
||||
import NXOpen
|
||||
session = NXOpen.Session.GetSession()
|
||||
# ✅ Type "session." → See: Parts, ListingWindow, LogFile, etc.
|
||||
# ✅ Type "session.Parts." → See: Work, Display, FindObject, etc.
|
||||
# ✅ Hover over methods → See parameter types and documentation
|
||||
# ✅ Catch type errors before running code
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Available Modules
|
||||
|
||||
The stub files cover **all** NXOpen modules:
|
||||
|
||||
**Core Modules**:
|
||||
- `NXOpen.Session` - NX session management
|
||||
- `NXOpen.Part` - Part objects and operations
|
||||
- `NXOpen.Assemblies` - Assembly operations
|
||||
|
||||
**CAE Modules**:
|
||||
- `NXOpen.CAE` - Finite element analysis
|
||||
- `NXOpen.CAE.FemPart` - FEM models
|
||||
- `NXOpen.CAE.SimSolution` - Solutions and solver control
|
||||
|
||||
**Design Modules**:
|
||||
- `NXOpen.Features` - Parametric features
|
||||
- `NXOpen.Sketches` - Sketch operations
|
||||
- `NXOpen.Modeling` - Modeling operations
|
||||
|
||||
**And many more**: Drafting, Display, Motion, Optimization, etc.
|
||||
|
||||
---
|
||||
|
||||
## Example: Using Intellisense During Development
|
||||
|
||||
### Scenario: Update Part Expression
|
||||
|
||||
**Without Intellisense** (manual lookup required):
|
||||
```python
|
||||
# 1. Google: "NXOpen get expression"
|
||||
# 2. Find documentation
|
||||
# 3. Copy method signature
|
||||
# 4. Hope you got it right
|
||||
work_part.Expressions.FindObject("tip_thickness")
|
||||
```
|
||||
|
||||
**With Intellisense** (guided development):
|
||||
```python
|
||||
# 1. Type "work_part.Exp" → Autocomplete suggests "Expressions"
|
||||
# 2. Type "work_part.Expressions." → See all methods
|
||||
# 3. Select "FindObject" → See parameter types
|
||||
# 4. Hover for documentation
|
||||
work_part.Expressions.FindObject("tip_thickness") # ✅ Correct!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Benefits for Atomizer Development
|
||||
|
||||
### 1. **Faster Development**
|
||||
- No context switching to documentation
|
||||
- Discover APIs as you type
|
||||
- Reduce typos and API misuse
|
||||
|
||||
### 2. **Better Code Quality**
|
||||
- Type checking catches errors early
|
||||
- Method signatures documented inline
|
||||
- Parameter validation before runtime
|
||||
|
||||
### 3. **LLM-Assisted Coding**
|
||||
When using Claude Code to develop Atomizer:
|
||||
- Claude can "see" NXOpen API structure via stub files
|
||||
- Better code generation suggestions
|
||||
- Reduced hallucination of API methods
|
||||
|
||||
### 4. **Onboarding**
|
||||
- New contributors learn NXOpen API faster
|
||||
- Inline documentation reduces learning curve
|
||||
- Explore API without leaving IDE
|
||||
|
||||
---
|
||||
|
||||
## Integration with Atomizer Workflow
|
||||
|
||||
### Journal Script Development
|
||||
|
||||
When writing NX journal scripts (`optimization_engine/solve_simulation.py`):
|
||||
|
||||
```python
|
||||
import NXOpen
|
||||
|
||||
theSession = NXOpen.Session.GetSession()
|
||||
workPart = theSession.Parts.Work
|
||||
|
||||
# Intellisense shows:
|
||||
# - workPart.Expressions.FindObject(...)
|
||||
# - workPart.Expressions.EditWithUnits(...)
|
||||
# - workPart.Update()
|
||||
# - workPart.Save(...)
|
||||
```
|
||||
|
||||
### LLM Code Generation
|
||||
|
||||
When LLM generates NXOpen code, stub files help:
|
||||
- Validate generated code against actual API
|
||||
- Suggest corrections for API misuse
|
||||
- Provide parameter type hints
|
||||
|
||||
### Future: NXOpen Documentation Integration
|
||||
|
||||
This is **Step 1** of NXOpen integration. Future work:
|
||||
|
||||
1. ✅ **Stub files for intellisense** (current)
|
||||
2. 🔜 **Documentation scraping** for LLM knowledge base
|
||||
3. 🔜 **Authenticated docs access** for latest API references
|
||||
4. 🔜 **LLM-generated journal scripts** with validation
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Intellisense Not Working
|
||||
|
||||
**Problem**: No autocomplete suggestions appear
|
||||
|
||||
**Solutions**:
|
||||
1. **Check Pylance Extension**: VSCode → Extensions → Search "Pylance" → Ensure installed
|
||||
2. **Verify Settings**: `.vscode/settings.json` has correct stub path
|
||||
3. **Check Python Interpreter**: VSCode bottom-left → Select correct Python environment
|
||||
4. **Restart VSCode**: Close all windows and reopen
|
||||
5. **Check Stub Path**: Ensure path exists and contains `NXOpen` folder
|
||||
|
||||
### Wrong Suggestions
|
||||
|
||||
**Problem**: Autocomplete shows incorrect or outdated methods
|
||||
|
||||
**Solution**: Ensure stub files match your NX version:
|
||||
- NX 2412 → Use `NX2412\ugopen\pythonStubs`
|
||||
- Different NX version → Update stub path in settings
|
||||
|
||||
### Type Errors Shown
|
||||
|
||||
**Problem**: Pylance shows type errors for valid code
|
||||
|
||||
**Solutions**:
|
||||
1. Set `"python.analysis.typeCheckingMode": "basic"` (not "strict")
|
||||
2. Add `# type: ignore` for false positives
|
||||
3. Update stub files if using newer NX version
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- **Siemens NX Documentation**: [PLM Portal](https://plm.sw.siemens.com)
|
||||
- **TheScriptingEngineer**: [Blog with NXOpen examples](https://thescriptingengineer.com)
|
||||
- **Pylance Documentation**: [VSCode Python](https://code.visualstudio.com/docs/python/editing)
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
Now that intellisense is configured:
|
||||
|
||||
1. **Try It**: Open `tests/test_nxopen_intellisense.py` and explore
|
||||
2. **Develop Faster**: Use autocomplete when writing journal scripts
|
||||
3. **Contribute**: Help improve Atomizer's NXOpen integration
|
||||
|
||||
**See**: [DEVELOPMENT_GUIDANCE.md](../DEVELOPMENT_GUIDANCE.md) for strategic roadmap including NXOpen documentation access.
|
||||
|
||||
---
|
||||
|
||||
**Implemented By**: Antoine Letarte
|
||||
**Date**: 2025-11-17
|
||||
**NX Version**: 2412
|
||||
**Status**: Production Ready
|
||||
335
docs/api/NXOPEN_RESOURCES.md
Normal file
335
docs/api/NXOPEN_RESOURCES.md
Normal file
@@ -0,0 +1,335 @@
|
||||
# NXOpen Resources and References
|
||||
|
||||
## Overview
|
||||
|
||||
This document lists valuable resources for NXOpen development that can inform our implementation without direct code copying.
|
||||
|
||||
---
|
||||
|
||||
## Primary Resources
|
||||
|
||||
### 1. **Official Siemens NXOpen API Documentation**
|
||||
|
||||
**URL**: https://docs.sw.siemens.com/en-US/doc/209349590/PL20231101866122454.custom_api.nxopen_net
|
||||
|
||||
**Usage**:
|
||||
- Primary reference for API syntax and methods
|
||||
- Official namespace documentation
|
||||
- Method signatures and return types
|
||||
- Parameter descriptions
|
||||
|
||||
**Integration Strategy**:
|
||||
- MCP tool `search_nxopen_docs` will fetch pages on-demand
|
||||
- Cache frequently-used API snippets locally
|
||||
- LLM can reference documentation when generating NXOpen code
|
||||
|
||||
---
|
||||
|
||||
### 2. **NXOpenTSE by The Scripting Engineer**
|
||||
|
||||
**GitHub**: https://github.com/theScriptingEngineer/nxopentse/tree/main
|
||||
**Documentation**: https://nxopentsedocumentation.thescriptingengineer.com/
|
||||
|
||||
#### About NXOpenTSE
|
||||
|
||||
NXOpenTSE is an open-source Python library that provides:
|
||||
- **High-level wrappers** around NXOpen API
|
||||
- **Utility functions** for common NX operations
|
||||
- **Well-documented examples** of NX automation patterns
|
||||
- **Best practices** for NX scripting
|
||||
|
||||
**License**: MIT (as of last check - verify before use)
|
||||
|
||||
#### Why NXOpenTSE is Valuable for Atomizer
|
||||
|
||||
1. **Reference for Design Patterns**:
|
||||
- How to structure NXOpen scripts
|
||||
- Error handling approaches
|
||||
- Session management patterns
|
||||
- Part loading/unloading workflows
|
||||
|
||||
2. **Understanding API Usage**:
|
||||
- See real-world examples of API calls
|
||||
- Learn parameter combinations that work
|
||||
- Understand method call sequences
|
||||
|
||||
3. **Avoiding Common Pitfalls**:
|
||||
- See solutions to typical problems
|
||||
- Learn about NX-specific gotchas
|
||||
- Understand threading/transaction requirements
|
||||
|
||||
4. **Inspiration for Features**:
|
||||
- Discover what's possible with NXOpen
|
||||
- See advanced techniques
|
||||
- Learn about lesser-known APIs
|
||||
|
||||
#### Integration Strategy for Atomizer
|
||||
|
||||
**Approach**: Reference, don't copy
|
||||
|
||||
```
|
||||
✅ DO:
|
||||
- Study NXOpenTSE documentation for understanding NX concepts
|
||||
- Reference example patterns when writing our own code
|
||||
- Learn from error handling approaches
|
||||
- Use as inspiration for our API wrapper design
|
||||
- Link to NXOpenTSE docs in our MCP system prompts
|
||||
- Ask LLM to "check NXOpenTSE documentation for similar examples"
|
||||
|
||||
❌ DON'T:
|
||||
- Copy code verbatim without attribution
|
||||
- Replicate their library structure
|
||||
- Import NXOpenTSE as a dependency (we build our own)
|
||||
- Reuse their code without understanding it
|
||||
```
|
||||
|
||||
#### Specific Areas to Reference
|
||||
|
||||
| Our Component | NXOpenTSE Reference Area | What to Learn |
|
||||
|--------------|-------------------------|---------------|
|
||||
| `nx_journals/update_and_solve.py` | Expression handling, part updates | How to safely modify expressions |
|
||||
| `nx_journals/api_dispatcher.py` | Session management | Best practices for NX session handling |
|
||||
| `mcp_server/tools/model_discovery.py` | Part file reading | How to extract model information |
|
||||
| `optimization_engine/result_extractors/` | CAE result reading | Methods for accessing simulation results |
|
||||
|
||||
---
|
||||
|
||||
## Using NXOpenTSE Documentation with MCP
|
||||
|
||||
### MCP System Prompt Extension
|
||||
|
||||
When generating NXOpen code, the LLM can be instructed to:
|
||||
|
||||
```markdown
|
||||
When writing NXOpen code:
|
||||
1. First check official Siemens NXOpen API docs for method signatures
|
||||
2. Reference NXOpenTSE documentation (https://nxopentsedocumentation.thescriptingengineer.com/)
|
||||
for real-world usage patterns and best practices
|
||||
3. Adapt patterns to our specific use case rather than copying directly
|
||||
4. Always include error handling and validation
|
||||
5. Add comments explaining NX-specific requirements
|
||||
```
|
||||
|
||||
### Example LLM Workflow
|
||||
|
||||
**User**: "I need to read all expressions from a .sim file"
|
||||
|
||||
**LLM Reasoning**:
|
||||
1. Check official API: `NXOpen.Part.Expressions`
|
||||
2. Look at NXOpenTSE example: https://nxopentsedocumentation.thescriptingengineer.com/expressions.html
|
||||
3. See pattern: Loop through `work_part.Expressions`, handle edge cases
|
||||
4. Adapt to our needs: Add filtering, type checking, JSON serialization
|
||||
|
||||
**Generated Code** (our implementation, inspired by reference):
|
||||
```python
|
||||
def get_expressions(sim_file_path: Path) -> dict:
|
||||
"""Extract all expressions from a .sim file."""
|
||||
import NXOpen
|
||||
|
||||
session = NXOpen.Session.GetSession()
|
||||
|
||||
# Load sim file
|
||||
part, status = session.Parts.OpenActiveDisplay(str(sim_file_path))
|
||||
|
||||
expressions = {}
|
||||
try:
|
||||
for expr in part.Expressions:
|
||||
# Filter out system expressions (start with underscore)
|
||||
if not expr.Name.startswith("_"):
|
||||
expressions[expr.Name] = {
|
||||
"value": expr.Value,
|
||||
"units": expr.Units if expr.Units else "",
|
||||
"type": str(expr.Type)
|
||||
}
|
||||
finally:
|
||||
# Clean up
|
||||
session.Parts.SetWork(None)
|
||||
|
||||
return expressions
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Additional Resources
|
||||
|
||||
### 3. **Eng-Tips NXOpen Forum**
|
||||
|
||||
**URL**: https://www.eng-tips.com/threadminder.cfm?pid=561
|
||||
|
||||
- Community Q&A
|
||||
- Troubleshooting help
|
||||
- User-contributed examples
|
||||
|
||||
### 4. **Stack Overflow - NXOpen Tag**
|
||||
|
||||
**URL**: https://stackoverflow.com/questions/tagged/nxopen
|
||||
|
||||
- Specific problem solutions
|
||||
- Code snippets for common tasks
|
||||
|
||||
### 5. **Siemens PLM Community Forums**
|
||||
|
||||
**URL**: https://community.sw.siemens.com/
|
||||
|
||||
- Official support
|
||||
- Product announcements
|
||||
- Beta access information
|
||||
|
||||
---
|
||||
|
||||
## Best Practices Learned from NXOpenTSE
|
||||
|
||||
### 1. **Session Management**
|
||||
|
||||
```python
|
||||
# Always get session at the start
|
||||
session = NXOpen.Session.GetSession()
|
||||
|
||||
# Always check if part is loaded
|
||||
if session.Parts.Work is None:
|
||||
raise ValueError("No work part loaded")
|
||||
```
|
||||
|
||||
### 2. **Error Handling**
|
||||
|
||||
```python
|
||||
# Wrap NX operations in try-finally for cleanup
|
||||
try:
|
||||
# NX operations here
|
||||
result = do_something()
|
||||
finally:
|
||||
# Always clean up, even on error
|
||||
if temp_part:
|
||||
session.Parts.CloseAll(NXOpen.BasePart.CloseWholeTree.True)
|
||||
```
|
||||
|
||||
### 3. **Expression Updates**
|
||||
|
||||
```python
|
||||
# Use Edit method for updating expressions
|
||||
expr = part.Expressions.FindObject("parameter_name")
|
||||
if expr:
|
||||
expr.Edit(new_value)
|
||||
else:
|
||||
# Create if doesn't exist
|
||||
unit = part.UnitCollection.FindObject("MilliMeter")
|
||||
part.Expressions.CreateExpression(unit, "parameter_name", str(new_value))
|
||||
```
|
||||
|
||||
### 4. **Simulation Solution Access**
|
||||
|
||||
```python
|
||||
# Access simulation objects safely
|
||||
sim_simulation = sim_part.Simulation
|
||||
if sim_simulation:
|
||||
solutions = sim_simulation.Solutions
|
||||
for solution in solutions:
|
||||
if solution.Name == target_name:
|
||||
# Found our solution
|
||||
pass
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Attribution and Licensing
|
||||
|
||||
### When Using Ideas from NXOpenTSE
|
||||
|
||||
1. **Add attribution in comments**:
|
||||
```python
|
||||
# Approach inspired by NXOpenTSE expression handling
|
||||
# See: https://nxopentsedocumentation.thescriptingengineer.com/expressions.html
|
||||
```
|
||||
|
||||
2. **Link in documentation**:
|
||||
- Acknowledge inspiration in our docs
|
||||
- Link to relevant NXOpenTSE pages
|
||||
- Credit The Scripting Engineer for educational resources
|
||||
|
||||
3. **Respect MIT License** (verify current license):
|
||||
- Give credit to original authors
|
||||
- Don't claim their work as ours
|
||||
- Contribute back to community if we find improvements
|
||||
|
||||
---
|
||||
|
||||
## Contributing to NXOpenTSE
|
||||
|
||||
If we discover useful patterns or fixes while building Atomizer:
|
||||
- Consider contributing examples back to NXOpenTSE
|
||||
- Report issues if we find documentation errors
|
||||
- Share knowledge with the NX scripting community
|
||||
|
||||
---
|
||||
|
||||
## Integration with Atomizer MCP
|
||||
|
||||
### MCP Tool: `search_nxopen_resources`
|
||||
|
||||
```python
|
||||
{
|
||||
"name": "search_nxopen_resources",
|
||||
"description": "Search NXOpen documentation and reference materials",
|
||||
"inputSchema": {
|
||||
"query": "How to update expressions in NX",
|
||||
"sources": ["official", "nxopentse", "community"],
|
||||
"return_examples": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```json
|
||||
{
|
||||
"official_docs": "https://docs.sw.siemens.com/.../Expressions",
|
||||
"nxopentse_example": "https://nxopentsedocumentation.thescriptingengineer.com/expressions.html",
|
||||
"code_pattern": "Use part.Expressions.CreateExpression() or FindObject().Edit()",
|
||||
"community_threads": [...]
|
||||
}
|
||||
```
|
||||
|
||||
### System Prompt Reference Section
|
||||
|
||||
```markdown
|
||||
## NXOpen Development Resources
|
||||
|
||||
When implementing NXOpen functionality:
|
||||
|
||||
1. **Official API**: Consult Siemens NXOpen .NET documentation for authoritative API reference
|
||||
2. **NXOpenTSE**: Reference https://nxopentsedocumentation.thescriptingengineer.com/ for:
|
||||
- Practical usage patterns
|
||||
- Common parameter combinations
|
||||
- Error handling approaches
|
||||
- Real-world examples
|
||||
3. **Adaptation**: Always adapt patterns to Atomizer's specific architecture rather than copying
|
||||
|
||||
Remember: NXOpenTSE is a reference for learning, not a dependency to import.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
**NXOpenTSE is invaluable** for accelerating Atomizer development by:
|
||||
- ✅ Showing proven patterns
|
||||
- ✅ Teaching NX best practices
|
||||
- ✅ Providing working examples to learn from
|
||||
- ✅ Documenting edge cases and gotchas
|
||||
|
||||
**We will use it as**:
|
||||
- 📚 Educational reference
|
||||
- 🎯 Design pattern inspiration
|
||||
- 🔍 Problem-solving resource
|
||||
- 🧭 Navigation aid through complex NXOpen API
|
||||
|
||||
**Not as**:
|
||||
- ❌ Code to copy-paste
|
||||
- ❌ Dependency to import
|
||||
- ❌ Replacement for understanding
|
||||
|
||||
This approach allows us to learn from the community while building something unique and tailored to Atomizer's specific optimization use case.
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-11-15
|
||||
**Maintainer**: Atomaster Development Team
|
||||
406
docs/api/NX_FILE_STRUCTURE_PROTOCOL.md
Normal file
406
docs/api/NX_FILE_STRUCTURE_PROTOCOL.md
Normal file
@@ -0,0 +1,406 @@
|
||||
# NX File Structure Protocol for Atomizer Studies
|
||||
|
||||
## Overview
|
||||
|
||||
This document defines the **mandatory file structure** for all NX Simcenter optimization studies. Following this protocol ensures optimization runs succeed without manual intervention.
|
||||
|
||||
## File Types and Purposes
|
||||
|
||||
### Part Files (.prt)
|
||||
|
||||
**Master Geometry File**: `<ModelName>.prt`
|
||||
- Contains parametric CAD geometry
|
||||
- Design variables are NX expressions
|
||||
- Primary file opened by NX during optimization
|
||||
|
||||
**Idealized Part File**: `<ModelName>_fem<N>_i.prt`
|
||||
- Auto-generated by NX during FEM idealization
|
||||
- Contains simplified geometry for meshing
|
||||
- Required for mesh regeneration
|
||||
- MUST be copied with the study
|
||||
|
||||
**Assembly Part File** (for assemblies): `<AssemblyName>.prt`
|
||||
- Top-level assembly structure
|
||||
- References component parts
|
||||
- Contains assembly constraints
|
||||
|
||||
### FEM Files (.fem)
|
||||
|
||||
**Part-Level FEM**: `<ModelName>_fem<N>.fem`
|
||||
- Mesh definition for single part
|
||||
- Material properties
|
||||
- Boundary conditions
|
||||
- Mesh parameters
|
||||
|
||||
**Assembly FEM** (.afem): `<AssemblyName>_fem<N>.afem`
|
||||
- Assembly-level FEM structure
|
||||
- Component FEM references
|
||||
- Contact definitions
|
||||
- Assembly-level boundary conditions
|
||||
- **Requires all component .fem files**
|
||||
|
||||
### Simulation Files (.sim)
|
||||
|
||||
**Simulation Setup**: `<ModelName>_sim<N>.sim`
|
||||
- Solution definitions (SOL 101, 103, etc.)
|
||||
- Load cases
|
||||
- Analysis types (static, modal, buckling, etc.)
|
||||
- Results configuration
|
||||
- References FEM file(s)
|
||||
|
||||
---
|
||||
|
||||
## Mandatory File Sets
|
||||
|
||||
### SINGLE PART ANALYSIS
|
||||
|
||||
**REQUIRED FILES** (All 4 must be present):
|
||||
|
||||
```
|
||||
1_setup/model/
|
||||
├── <ModelName>.prt # Master geometry (parametric)
|
||||
├── <ModelName>_fem1.fem # FEM mesh definition
|
||||
├── <ModelName>_fem1_i.prt # Idealized geometry (CRITICAL!)
|
||||
└── <ModelName>_sim1.sim # Simulation setup
|
||||
```
|
||||
|
||||
**Example** (Beam Study):
|
||||
```
|
||||
1_setup/model/
|
||||
├── Beam.prt
|
||||
├── Beam_fem1.fem
|
||||
├── Beam_fem1_i.prt ← Don't forget this!
|
||||
└── Beam_sim1.sim
|
||||
```
|
||||
|
||||
**Why _i.prt is Required**:
|
||||
- NX needs it to regenerate mesh when parameters change
|
||||
- Without it: "Unable to find idealized body" error
|
||||
- Generated once, reused for all trials
|
||||
- Must be version-controlled with study
|
||||
|
||||
---
|
||||
|
||||
### ASSEMBLY ANALYSIS
|
||||
|
||||
**REQUIRED FILES** (More complex):
|
||||
|
||||
```
|
||||
1_setup/model/
|
||||
├── <Assembly>.prt # Top assembly
|
||||
├── <Assembly>_fem1.afem # Assembly FEM (references below)
|
||||
├── <Assembly>_sim1.sim # Simulation setup
|
||||
│
|
||||
├── components/ # Component parts subdirectory
|
||||
│ ├── <Component1>.prt # Component part
|
||||
│ ├── <Component1>_fem1.fem # Component FEM
|
||||
│ ├── <Component1>_fem1_i.prt # Component idealized part
|
||||
│ │
|
||||
│ ├── <Component2>.prt
|
||||
│ ├── <Component2>_fem1.fem
|
||||
│ ├── <Component2>_fem1_i.prt
|
||||
│ │
|
||||
│ └── ... # Additional components
|
||||
```
|
||||
|
||||
**Example** (Bracket Assembly with 3 components):
|
||||
```
|
||||
1_setup/model/
|
||||
├── BracketAssembly.prt
|
||||
├── BracketAssembly_fem1.afem
|
||||
├── BracketAssembly_sim1.sim
|
||||
│
|
||||
└── components/
|
||||
├── Bracket.prt
|
||||
├── Bracket_fem1.fem
|
||||
├── Bracket_fem1_i.prt
|
||||
│
|
||||
├── Plate.prt
|
||||
├── Plate_fem1.fem
|
||||
├── Plate_fem1_i.prt
|
||||
│
|
||||
├── Bolt.prt
|
||||
├── Bolt_fem1.fem
|
||||
└── Bolt_fem1_i.prt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Naming Conventions
|
||||
|
||||
### Standard Naming Pattern
|
||||
|
||||
```
|
||||
<BaseName>_<FileType><Index>.<extension>
|
||||
|
||||
BaseName: Model/assembly name (e.g., "Beam", "BracketAssembly")
|
||||
FileType: fem, sim
|
||||
Index: Sequential number (1, 2, 3, ...)
|
||||
Extension: .fem, .afem, .sim, .prt
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
**Good**:
|
||||
- `Beam_fem1.fem` → First FEM file for Beam
|
||||
- `Beam_fem1_i.prt` → Idealized part for Beam FEM #1
|
||||
- `Beam_sim1.sim` → First simulation for Beam
|
||||
- `BracketAssembly_fem1.afem` → Assembly FEM
|
||||
|
||||
**Bad**:
|
||||
- `BeamFEM.fem` → Missing index
|
||||
- `Beam fem 1.fem` → Spaces not allowed
|
||||
- `beam_fem1.fem` → Inconsistent capitalization
|
||||
- `Beam_idealized.prt` → Non-standard naming
|
||||
|
||||
---
|
||||
|
||||
## Assembly FEM (.afem) Structure
|
||||
|
||||
### What Goes in .afem vs .fem
|
||||
|
||||
**Assembly FEM (.afem)**:
|
||||
- References to component .fem files
|
||||
- Contact pairs between components
|
||||
- Assembly-level boundary conditions
|
||||
- Component positioning/orientation
|
||||
- Assembly-level loads
|
||||
- Glue/weld connections
|
||||
|
||||
**Component FEM (.fem)**:
|
||||
- Individual component mesh
|
||||
- Component material properties
|
||||
- Component-specific boundary conditions
|
||||
- Local mesh refinement
|
||||
- Component-specific loads
|
||||
|
||||
### Assembly FEM Dependencies
|
||||
|
||||
**Critical**: `.afem` file MUST have:
|
||||
1. All referenced component `.prt` files
|
||||
2. All referenced component `.fem` files
|
||||
3. All referenced component `_i.prt` files
|
||||
4. Proper relative paths to components directory
|
||||
|
||||
**Path Configuration**:
|
||||
```
|
||||
# In .afem file, component references should use:
|
||||
./components/<Component>.prt
|
||||
./components/<Component>_fem1.fem
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Study Directory Structure
|
||||
|
||||
### Complete Single-Part Study
|
||||
|
||||
```
|
||||
study_name/
|
||||
├── 1_setup/
|
||||
│ ├── model/
|
||||
│ │ ├── <Model>.prt ← Master geometry
|
||||
│ │ ├── <Model>_fem1.fem ← FEM definition
|
||||
│ │ ├── <Model>_fem1_i.prt ← Idealized part (REQUIRED!)
|
||||
│ │ └── <Model>_sim1.sim ← Simulation setup
|
||||
│ ├── optimization_config.json
|
||||
│ └── workflow_config.json
|
||||
│
|
||||
├── 2_results/
|
||||
│ └── (generated during optimization)
|
||||
│
|
||||
└── run_optimization.py
|
||||
```
|
||||
|
||||
### Complete Assembly Study
|
||||
|
||||
```
|
||||
study_name/
|
||||
├── 1_setup/
|
||||
│ ├── model/
|
||||
│ │ ├── <Assembly>.prt
|
||||
│ │ ├── <Assembly>_fem1.afem
|
||||
│ │ ├── <Assembly>_sim1.sim
|
||||
│ │ │
|
||||
│ │ └── components/
|
||||
│ │ ├── <Comp1>.prt
|
||||
│ │ ├── <Comp1>_fem1.fem
|
||||
│ │ ├── <Comp1>_fem1_i.prt
|
||||
│ │ ├── <Comp2>.prt
|
||||
│ │ ├── <Comp2>_fem1.fem
|
||||
│ │ ├── <Comp2>_fem1_i.prt
|
||||
│ │ └── ...
|
||||
│ │
|
||||
│ ├── optimization_config.json
|
||||
│ └── workflow_config.json
|
||||
│
|
||||
├── 2_results/
|
||||
└── run_optimization.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Errors and Solutions
|
||||
|
||||
### Error: "Unable to find idealized body"
|
||||
|
||||
**Cause**: Missing `_fem1_i.prt` file
|
||||
**Solution**: Always copy the `_i.prt` file with your study
|
||||
|
||||
### Error: "Cannot open FEM file"
|
||||
|
||||
**Cause**: FEM file references missing component
|
||||
**Solution**: Verify all component `.fem` and `.prt` files are present
|
||||
|
||||
### Error: "Mesh regeneration failed"
|
||||
|
||||
**Cause**: Idealized part doesn't match current geometry
|
||||
**Solution**: Regenerate idealization in NX, copy new `_i.prt`
|
||||
|
||||
### Error: "Component not found in assembly"
|
||||
|
||||
**Cause**: Wrong path to components directory
|
||||
**Solution**: Ensure `components/` subdirectory structure is correct
|
||||
|
||||
---
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
### Before Creating Study
|
||||
|
||||
**Single Part**:
|
||||
- [ ] `<Model>.prt` exists
|
||||
- [ ] `<Model>_fem1.fem` exists
|
||||
- [ ] `<Model>_fem1_i.prt` exists (CRITICAL!)
|
||||
- [ ] `<Model>_sim1.sim` exists
|
||||
- [ ] All 4 files in same directory
|
||||
|
||||
**Assembly**:
|
||||
- [ ] `<Assembly>.prt` exists
|
||||
- [ ] `<Assembly>_fem1.afem` exists
|
||||
- [ ] `<Assembly>_sim1.sim` exists
|
||||
- [ ] `components/` directory exists
|
||||
- [ ] Each component has `.prt`, `.fem`, `_i.prt`
|
||||
- [ ] All component paths in `.afem` are correct
|
||||
|
||||
### After Copying Study
|
||||
|
||||
**Run Quick Test**:
|
||||
1. Open `<Model>.prt` in NX
|
||||
2. Open Simulation Navigator
|
||||
3. Solve simulation manually
|
||||
4. If it solves → files are correct
|
||||
5. If it fails → check error for missing files
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Always Copy Complete File Sets
|
||||
|
||||
Don't copy just `.prt` and `.sim`:
|
||||
```bash
|
||||
# Bad
|
||||
cp Model.prt new_study/
|
||||
cp Model_sim1.sim new_study/
|
||||
|
||||
# Good
|
||||
cp Model.prt Model_fem1.fem Model_fem1_i.prt Model_sim1.sim new_study/
|
||||
```
|
||||
|
||||
### 2. Preserve Directory Structure
|
||||
|
||||
For assemblies, maintain the `components/` structure:
|
||||
```bash
|
||||
# Create structure first
|
||||
mkdir -p new_study/1_setup/model/components
|
||||
|
||||
# Then copy files
|
||||
cp Assembly* new_study/1_setup/model/
|
||||
cp components/* new_study/1_setup/model/components/
|
||||
```
|
||||
|
||||
### 3. Version Control All Files
|
||||
|
||||
In git, track:
|
||||
- All `.prt` files (including `_i.prt`)
|
||||
- All `.fem` and `.afem` files
|
||||
- All `.sim` files
|
||||
- Do NOT use `.gitignore` to exclude `_i.prt`!
|
||||
|
||||
### 4. Document Component Dependencies
|
||||
|
||||
For assemblies, create a `COMPONENTS.md`:
|
||||
```markdown
|
||||
# Assembly Components
|
||||
|
||||
Main Assembly: BracketAssembly.prt
|
||||
|
||||
Components:
|
||||
1. Bracket.prt - Main structural member (parametric)
|
||||
2. Plate.prt - Mounting plate (parametric)
|
||||
3. Bolt.prt - M6 bolt (fixed geometry)
|
||||
|
||||
Contact Pairs:
|
||||
- Bracket <-> Plate: Bonded contact
|
||||
- Bolt <-> Bracket: Frictional (μ=0.3)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Advanced: Multi-Solution Studies
|
||||
|
||||
For studies with multiple analysis types (static + modal, etc.):
|
||||
|
||||
```
|
||||
1_setup/model/
|
||||
├── Model.prt
|
||||
├── Model_fem1.fem # Shared mesh
|
||||
├── Model_fem1_i.prt # Shared idealization
|
||||
├── Model_sim1.sim # Static analysis
|
||||
└── Model_sim2.sim # Modal analysis
|
||||
```
|
||||
|
||||
Both `.sim` files reference the same `.fem` and `_i.prt`.
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference Card
|
||||
|
||||
**Minimum Files for Single Part**:
|
||||
```
|
||||
✓ <Model>.prt
|
||||
✓ <Model>_fem1.fem
|
||||
✓ <Model>_fem1_i.prt ← Don't forget!
|
||||
✓ <Model>_sim1.sim
|
||||
```
|
||||
|
||||
**Minimum Files for Assembly**:
|
||||
```
|
||||
✓ <Assembly>.prt
|
||||
✓ <Assembly>_fem1.afem
|
||||
✓ <Assembly>_sim1.sim
|
||||
✓ components/<Comp1>.prt
|
||||
✓ components/<Comp1>_fem1.fem
|
||||
✓ components/<Comp1>_fem1_i.prt
|
||||
(repeat for each component)
|
||||
```
|
||||
|
||||
**Golden Rule**: If NX created it during meshing/simulation setup, you need to copy it for optimization!
|
||||
|
||||
---
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Planned protocol additions:
|
||||
- [ ] Multi-mesh assembly support
|
||||
- [ ] Submodeling workflows
|
||||
- [ ] Contact table definitions
|
||||
- [ ] Result mesh specification
|
||||
- [ ] Optimization-specific mesh controls
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-01-22
|
||||
**Version**: 1.0
|
||||
**Status**: MANDATORY for all studies
|
||||
419
docs/api/nx_integration.md
Normal file
419
docs/api/nx_integration.md
Normal file
@@ -0,0 +1,419 @@
|
||||
# NX Session Management
|
||||
|
||||
**Status**: Implemented
|
||||
**Version**: 1.0
|
||||
**Date**: 2025-11-20
|
||||
|
||||
## Problem
|
||||
|
||||
When running multiple optimizations concurrently or when a user has NX open for manual work, conflicts can occur:
|
||||
|
||||
1. **Multiple Optimizations**: Two optimization studies trying to modify the same model simultaneously
|
||||
2. **User's Interactive NX**: Batch optimization interfering with user's manual work
|
||||
3. **File Corruption**: Concurrent writes to .prt/.sim files causing corruption
|
||||
4. **License Conflicts**: Multiple NX instances competing for licenses
|
||||
5. **Journal Failures**: Journals trying to run on wrong NX session
|
||||
|
||||
## Solution: NX Session Manager
|
||||
|
||||
The `NXSessionManager` class provides intelligent session conflict prevention.
|
||||
|
||||
### Key Features
|
||||
|
||||
1. **Session Detection**
|
||||
- Detects all running NX processes (interactive + batch)
|
||||
- Identifies interactive vs batch sessions
|
||||
- Warns if user has NX open
|
||||
|
||||
2. **File Locking**
|
||||
- Exclusive locks on model files (.prt)
|
||||
- Prevents two optimizations from modifying same model
|
||||
- Queues trials if model is locked
|
||||
|
||||
3. **Process Queuing**
|
||||
- Limits concurrent NX batch sessions (default: 1)
|
||||
- Waits if max sessions reached
|
||||
- Automatic timeout and error handling
|
||||
|
||||
4. **Stale Lock Cleanup**
|
||||
- Detects crashed processes
|
||||
- Removes orphaned lock files
|
||||
- Prevents permanent deadlocks
|
||||
|
||||
## Architecture
|
||||
|
||||
### Session Manager Components
|
||||
|
||||
```python
|
||||
from optimization_engine.nx_session_manager import NXSessionManager
|
||||
|
||||
# Initialize
|
||||
session_mgr = NXSessionManager(
|
||||
lock_dir=Path.home() / ".atomizer" / "locks",
|
||||
max_concurrent_sessions=1, # Max parallel NX instances
|
||||
wait_timeout=300, # Max wait time (5 min)
|
||||
verbose=True
|
||||
)
|
||||
```
|
||||
|
||||
### Two-Level Locking
|
||||
|
||||
**Level 1: Model File Lock** (most important)
|
||||
```python
|
||||
# Ensures exclusive access to a specific model
|
||||
with session_mgr.acquire_model_lock(prt_file, study_name):
|
||||
# Update CAD model
|
||||
updater.update_expressions(params)
|
||||
|
||||
# Run simulation
|
||||
result = solver.run_simulation(sim_file)
|
||||
```
|
||||
|
||||
**Level 2: NX Session Lock** (optional)
|
||||
```python
|
||||
# Limits total concurrent NX batch instances
|
||||
with session_mgr.acquire_nx_session(study_name):
|
||||
# Run NX batch operation
|
||||
pass
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Example 1: Single Optimization (Recommended)
|
||||
|
||||
```python
|
||||
from optimization_engine.nx_solver import NXSolver
|
||||
from optimization_engine.nx_updater import NXParameterUpdater
|
||||
from optimization_engine.nx_session_manager import NXSessionManager
|
||||
|
||||
# Initialize components
|
||||
session_mgr = NXSessionManager(verbose=True)
|
||||
updater = NXParameterUpdater("model.prt")
|
||||
solver = NXSolver()
|
||||
|
||||
# Check for interactive NX sessions
|
||||
if session_mgr.is_nx_interactive_session_running():
|
||||
print("WARNING: NX is open! Close it before running optimization.")
|
||||
# You can choose to abort or continue
|
||||
|
||||
# Run trials with session management
|
||||
for trial in trials:
|
||||
with session_mgr.acquire_model_lock(prt_file, "my_study"):
|
||||
# Exclusive access to model - safe to modify
|
||||
updater.update_expressions(params)
|
||||
result = solver.run_simulation(sim_file)
|
||||
```
|
||||
|
||||
### Example 2: Multiple Concurrent Optimizations
|
||||
|
||||
```python
|
||||
# Study A (in one terminal)
|
||||
session_mgr_A = NXSessionManager()
|
||||
|
||||
with session_mgr_A.acquire_model_lock(model_A_prt, "study_A"):
|
||||
# Works on model A
|
||||
updater_A.update_expressions(params_A)
|
||||
solver_A.run_simulation(sim_A)
|
||||
|
||||
# Study B (in another terminal, simultaneously)
|
||||
session_mgr_B = NXSessionManager()
|
||||
|
||||
with session_mgr_B.acquire_model_lock(model_B_prt, "study_B"):
|
||||
# Works on model B (different model - no conflict)
|
||||
updater_B.update_expressions(params_B)
|
||||
solver_B.run_simulation(sim_B)
|
||||
|
||||
# If they try to use SAME model:
|
||||
with session_mgr_A.acquire_model_lock(model_SAME, "study_A"):
|
||||
pass # Acquires lock
|
||||
|
||||
with session_mgr_B.acquire_model_lock(model_SAME, "study_B"):
|
||||
# Waits here until study_A releases lock
|
||||
# Then proceeds safely
|
||||
pass
|
||||
```
|
||||
|
||||
### Example 3: Protection Against User's Interactive NX
|
||||
|
||||
```python
|
||||
session_mgr = NXSessionManager(verbose=True)
|
||||
|
||||
# Detect if user has NX open
|
||||
nx_sessions = session_mgr.get_running_nx_sessions()
|
||||
|
||||
for session in nx_sessions:
|
||||
print(f"Detected: {session.name} (PID {session.pid})")
|
||||
|
||||
if session_mgr.is_nx_interactive_session_running():
|
||||
print("Interactive NX session detected!")
|
||||
print("Recommend closing NX before running optimization.")
|
||||
|
||||
# Option 1: Abort
|
||||
raise RuntimeError("Close NX and try again")
|
||||
|
||||
# Option 2: Continue with warning
|
||||
print("Continuing anyway... (may cause conflicts)")
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Lock Directory
|
||||
|
||||
Default: `~/.atomizer/locks/`
|
||||
|
||||
Custom:
|
||||
```python
|
||||
session_mgr = NXSessionManager(
|
||||
lock_dir=Path("/custom/lock/dir")
|
||||
)
|
||||
```
|
||||
|
||||
### Concurrent Session Limit
|
||||
|
||||
Default: 1 (safest)
|
||||
|
||||
Allow multiple:
|
||||
```python
|
||||
session_mgr = NXSessionManager(
|
||||
max_concurrent_sessions=2 # Allow 2 parallel NX batches
|
||||
)
|
||||
```
|
||||
|
||||
**Warning**: Multiple concurrent NX sessions require multiple licenses!
|
||||
|
||||
### Wait Timeout
|
||||
|
||||
Default: 300 seconds (5 minutes)
|
||||
|
||||
Custom:
|
||||
```python
|
||||
session_mgr = NXSessionManager(
|
||||
wait_timeout=600 # Wait up to 10 minutes
|
||||
)
|
||||
```
|
||||
|
||||
## Integration with NXSolver
|
||||
|
||||
The `NXSolver` class has built-in session management:
|
||||
|
||||
```python
|
||||
from optimization_engine.nx_solver import NXSolver
|
||||
|
||||
solver = NXSolver(
|
||||
enable_session_management=True, # Default
|
||||
study_name="my_study"
|
||||
)
|
||||
|
||||
# Session management happens automatically
|
||||
result = solver.run_simulation(sim_file)
|
||||
```
|
||||
|
||||
**Note**: Full automatic integration is planned but not yet implemented. Currently, manual wrapping is recommended.
|
||||
|
||||
## Status Monitoring
|
||||
|
||||
### Get Current Status
|
||||
|
||||
```python
|
||||
report = session_mgr.get_status_report()
|
||||
print(report)
|
||||
```
|
||||
|
||||
Output:
|
||||
```
|
||||
======================================================================
|
||||
NX SESSION MANAGER STATUS
|
||||
======================================================================
|
||||
|
||||
Running NX Processes: 2
|
||||
PID 12345: ugraf.exe
|
||||
Working dir: C:/Users/username/project
|
||||
PID 12346: run_journal.exe
|
||||
|
||||
WARNING: Interactive NX session detected!
|
||||
Batch operations may conflict with user's work.
|
||||
|
||||
Active Optimization Sessions: 1/1
|
||||
my_study (PID 12347)
|
||||
|
||||
Active Lock Files: 1
|
||||
======================================================================
|
||||
```
|
||||
|
||||
### Cleanup Stale Locks
|
||||
|
||||
```python
|
||||
# Run at startup
|
||||
session_mgr.cleanup_stale_locks()
|
||||
```
|
||||
|
||||
Removes lock files from crashed processes.
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Lock Timeout
|
||||
|
||||
```python
|
||||
try:
|
||||
with session_mgr.acquire_model_lock(prt_file, study_name):
|
||||
# ... modify model ...
|
||||
pass
|
||||
except TimeoutError as e:
|
||||
print(f"Could not acquire model lock: {e}")
|
||||
print("Another optimization may be using this model.")
|
||||
# Handle error (skip trial, abort, etc.)
|
||||
```
|
||||
|
||||
### NX Session Timeout
|
||||
|
||||
```python
|
||||
try:
|
||||
with session_mgr.acquire_nx_session(study_name):
|
||||
# ... run NX batch ...
|
||||
pass
|
||||
except TimeoutError as e:
|
||||
print(f"Could not acquire NX session: {e}")
|
||||
print(f"Max concurrent sessions ({session_mgr.max_concurrent}) reached.")
|
||||
# Handle error
|
||||
```
|
||||
|
||||
## Platform Support
|
||||
|
||||
- ✅ **Windows**: Full support (uses `msvcrt` for file locking)
|
||||
- ✅ **Linux/Mac**: Full support (uses `fcntl` for file locking)
|
||||
- ✅ **Cross-Platform**: Lock files work across different OS instances
|
||||
|
||||
## Limitations
|
||||
|
||||
1. **Same Machine Only**: Session manager only prevents conflicts on the same machine
|
||||
- For networked optimizations, need distributed lock manager
|
||||
|
||||
2. **File System Required**: Requires writable lock directory
|
||||
- May not work on read-only filesystems
|
||||
|
||||
3. **Process Detection**: Relies on `psutil` for process detection
|
||||
- May miss processes in some edge cases
|
||||
|
||||
4. **Not Real-Time**: Lock checking has small latency
|
||||
- Not suitable for microsecond-level synchronization
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Always Use Model Locks
|
||||
|
||||
```python
|
||||
# GOOD: Protected
|
||||
with session_mgr.acquire_model_lock(prt_file, study_name):
|
||||
updater.update_expressions(params)
|
||||
|
||||
# BAD: Unprotected (race condition!)
|
||||
updater.update_expressions(params)
|
||||
```
|
||||
|
||||
### 2. Check for Interactive NX
|
||||
|
||||
```python
|
||||
# Before starting optimization
|
||||
if session_mgr.is_nx_interactive_session_running():
|
||||
print("WARNING: Close NX before running optimization!")
|
||||
# Decide: abort or continue with warning
|
||||
```
|
||||
|
||||
### 3. Cleanup on Startup
|
||||
|
||||
```python
|
||||
# At optimization start
|
||||
session_mgr = NXSessionManager()
|
||||
session_mgr.cleanup_stale_locks() # Remove crashed process locks
|
||||
```
|
||||
|
||||
### 4. Use Unique Study Names
|
||||
|
||||
```python
|
||||
# GOOD: Unique names
|
||||
solver_A = NXSolver(study_name="beam_optimization_trial_42")
|
||||
solver_B = NXSolver(study_name="plate_optimization_trial_15")
|
||||
|
||||
# BAD: Same name (confusing logs)
|
||||
solver_A = NXSolver(study_name="default_study")
|
||||
solver_B = NXSolver(study_name="default_study")
|
||||
```
|
||||
|
||||
### 5. Handle Timeouts Gracefully
|
||||
|
||||
```python
|
||||
try:
|
||||
with session_mgr.acquire_model_lock(prt_file, study_name):
|
||||
result = solver.run_simulation(sim_file)
|
||||
except TimeoutError:
|
||||
# Don't crash entire optimization!
|
||||
print("Lock timeout - skipping this trial")
|
||||
raise optuna.TrialPruned() # Optuna will continue
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Lock timeout" errors
|
||||
|
||||
**Cause**: Another process holds the lock longer than timeout
|
||||
|
||||
**Solutions**:
|
||||
1. Check if another optimization is running
|
||||
2. Increase timeout: `wait_timeout=600`
|
||||
3. Check for stale locks: `cleanup_stale_locks()`
|
||||
|
||||
### "Interactive NX session detected" warnings
|
||||
|
||||
**Cause**: User has NX open in GUI mode
|
||||
|
||||
**Solutions**:
|
||||
1. Close interactive NX before optimization
|
||||
2. Use different model files
|
||||
3. Continue with warning (risky!)
|
||||
|
||||
### Stale lock files
|
||||
|
||||
**Cause**: Optimization crashed without releasing locks
|
||||
|
||||
**Solution**:
|
||||
```python
|
||||
session_mgr.cleanup_stale_locks()
|
||||
```
|
||||
|
||||
### Multiple optimizations on different models still conflict
|
||||
|
||||
**Cause**: NX session limit reached
|
||||
|
||||
**Solution**:
|
||||
```python
|
||||
session_mgr = NXSessionManager(
|
||||
max_concurrent_sessions=2 # Allow 2 parallel NX instances
|
||||
)
|
||||
```
|
||||
|
||||
**Warning**: Requires 2 NX licenses!
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
- [ ] Distributed lock manager (for cluster computing)
|
||||
- [ ] Automatic NX session affinity (assign trials to specific NX instances)
|
||||
- [ ] License pool management
|
||||
- [ ] Network file lock support (for shared drives)
|
||||
- [ ] Real-time session monitoring dashboard
|
||||
- [ ] Automatic crash recovery
|
||||
|
||||
## Version History
|
||||
|
||||
### Version 1.0 (2025-11-20)
|
||||
- Initial implementation
|
||||
- Model file locking
|
||||
- NX session detection
|
||||
- Concurrent session limiting
|
||||
- Stale lock cleanup
|
||||
- Status reporting
|
||||
|
||||
---
|
||||
|
||||
**Implementation Status**: ✅ Core functionality complete
|
||||
**Testing Status**: ⚠️ Needs production testing
|
||||
**Documentation Status**: ✅ Complete
|
||||
144
docs/api/system_configuration.md
Normal file
144
docs/api/system_configuration.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# System Configuration
|
||||
|
||||
> **Critical**: These are the ONLY paths and environments to be used unless explicitly reconfigured by the user.
|
||||
|
||||
---
|
||||
|
||||
## Python Environment
|
||||
|
||||
**Environment Name**: `atomizer`
|
||||
|
||||
**Path**: `c:/Users/antoi/anaconda3/envs/atomizer/python.exe`
|
||||
|
||||
**Usage**: ALL Python scripts and commands MUST use this environment.
|
||||
|
||||
### Examples:
|
||||
```bash
|
||||
# Correct
|
||||
"c:/Users/antoi/anaconda3/envs/atomizer/python.exe" script.py
|
||||
|
||||
# WRONG - Never use test_env
|
||||
"c:/Users/antoi/anaconda3/envs/test_env/python.exe" script.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## NX/Simcenter Installation
|
||||
|
||||
**Active Installation**: NX 2412
|
||||
|
||||
**Base Path**: `C:\Program Files\Siemens\NX2412`
|
||||
|
||||
**Key Directories**:
|
||||
- NX Binaries: `C:\Program Files\Siemens\NX2412\NXBIN`
|
||||
- Material Library: `C:\Program Files\Siemens\NX2412\UGII\materials`
|
||||
- Python Stubs: `C:\Program Files\Siemens\NX2412\ugopen\pythonStubs`
|
||||
|
||||
### Critical Files:
|
||||
- **run_journal.exe**: `C:\Program Files\Siemens\NX2412\NXBIN\run_journal.exe`
|
||||
- **Material Library**: `C:\Program Files\Siemens\NX2412\UGII\materials\physicalmateriallibrary.xml`
|
||||
|
||||
### PROHIBITED Paths:
|
||||
- ❌ `C:\Program Files\Siemens\Simcenter3D_2412` - DO NOT USE
|
||||
- ❌ Any path containing "Simcenter3D" - DO NOT USE
|
||||
|
||||
**Reason**: NX2412 is the primary CAD/CAE environment. Simcenter3D_2412 is a separate installation and should not be accessed unless explicitly configured by the user.
|
||||
|
||||
---
|
||||
|
||||
## NX Journal Execution
|
||||
|
||||
**Command Template**:
|
||||
```bash
|
||||
"C:/Program Files/Siemens/NX2412/NXBIN/run_journal.exe" <journal_script.py> -args <arg1> <arg2>
|
||||
```
|
||||
|
||||
**Example**:
|
||||
```bash
|
||||
"C:/Program Files/Siemens/NX2412/NXBIN/run_journal.exe" "optimization_engine/import_expressions.py" -args "studies/beam/model/Beam.prt" "studies/beam/model/Beam_study_variables.exp"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## NXOpen Python Stubs (for Intellisense)
|
||||
|
||||
**Path**: `C:\Program Files\Siemens\NX2412\ugopen\pythonStubs`
|
||||
|
||||
**VSCode Configuration** (`.vscode/settings.json`):
|
||||
```json
|
||||
{
|
||||
"python.analysis.extraPaths": [
|
||||
"C:\\Program Files\\Siemens\\NX2412\\ugopen\\pythonStubs"
|
||||
],
|
||||
"python.analysis.typeCheckingMode": "basic"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Material Library Access
|
||||
|
||||
**Library File**: `C:\Program Files\Siemens\NX2412\UGII\materials\physicalmateriallibrary.xml`
|
||||
|
||||
**Format**: MatML XML format
|
||||
|
||||
**Properties Available**:
|
||||
- `Mass_Density__RHO__6` (kg/mm³)
|
||||
- `Youngs_Modulus_E__31` (Pa)
|
||||
- `PoissonsRatio` (dimensionless)
|
||||
- `Yield_Strength_32` (Pa)
|
||||
- `Thermal_Expansion_A__34` (1/°C)
|
||||
- `Thermal_Conductivity__K__35` (mW/mm/°C)
|
||||
- `Specific_Heat_CP__23` (mJ/kg/°C)
|
||||
|
||||
**Common Materials**:
|
||||
- AISI_Steel_1005 (E=200 GPa, ρ=7872 kg/m³, ν=0.25)
|
||||
- AISI_Steel_4340 (E=193 GPa, ρ=7850 kg/m³, ν=0.284)
|
||||
- Aluminum_6061-T6 (E=69 GPa, ρ=2700 kg/m³, ν=0.33)
|
||||
- Titanium_Ti-6Al-4V (E=114 GPa, ρ=4430 kg/m³, ν=0.34)
|
||||
|
||||
---
|
||||
|
||||
## Nastran Solver
|
||||
|
||||
**Solver Path**: Embedded in NX2412 installation
|
||||
|
||||
**Input Files**: `.dat` (Nastran bulk data)
|
||||
|
||||
**Output Files**:
|
||||
- `.op2` (binary results - use pyNastran)
|
||||
- `.f06` (text results - human readable)
|
||||
|
||||
**Material Units in .dat files**:
|
||||
- Young's Modulus: Pa (Pascals)
|
||||
- Density: kg/mm³
|
||||
- Poisson's Ratio: dimensionless
|
||||
|
||||
---
|
||||
|
||||
## Future Expansion
|
||||
|
||||
If using a different NX or Simcenter version, the user will explicitly configure:
|
||||
|
||||
1. Update this file with new paths
|
||||
2. Update `nx_updater.py` configuration
|
||||
3. Update `.vscode/settings.json` for new stub paths
|
||||
|
||||
**Until then**: ALWAYS use NX2412 paths as documented above.
|
||||
|
||||
---
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
Before running any NX-related operation, verify:
|
||||
|
||||
- ✅ Python command uses `atomizer` environment
|
||||
- ✅ NX paths point to `NX2412` (NOT Simcenter3D_2412)
|
||||
- ✅ Material library accessed from `NX2412\UGII\materials`
|
||||
- ✅ Journal script uses `NX2412\NXBIN\run_journal.exe`
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-11-17
|
||||
**Maintained By**: Antoine Letarte
|
||||
**Critical Importance**: HIGH - Incorrect paths will cause system failures
|
||||
Reference in New Issue
Block a user