Files
Atomizer/optimization_engine/hooks
Antoine 602560c46a feat: Add MLP surrogate with Turbo Mode for 100x faster optimization
Neural Acceleration (MLP Surrogate):
- Add run_nn_optimization.py with hybrid FEA/NN workflow
- MLP architecture: 4-layer (64->128->128->64) with BatchNorm/Dropout
- Three workflow modes:
  - --all: Sequential export->train->optimize->validate
  - --hybrid-loop: Iterative Train->NN->Validate->Retrain cycle
  - --turbo: Aggressive single-best validation (RECOMMENDED)
- Turbo mode: 5000 NN trials + 50 FEA validations in ~12 minutes
- Separate nn_study.db to avoid overloading dashboard

Performance Results (bracket_pareto_3obj study):
- NN prediction errors: mass 1-5%, stress 1-4%, stiffness 5-15%
- Found minimum mass designs at boundary (angle~30deg, thick~30mm)
- 100x speedup vs pure FEA exploration

Protocol Operating System:
- Add .claude/skills/ with Bootstrap, Cheatsheet, Context Loader
- Add docs/protocols/ with operations (OP_01-06) and system (SYS_10-14)
- Update SYS_14_NEURAL_ACCELERATION.md with MLP Turbo Mode docs

NX Automation:
- Add optimization_engine/hooks/ for NX CAD/CAE automation
- Add study_wizard.py for guided study creation
- Fix FEM mesh update: load idealized part before UpdateFemodel()

New Study:
- bracket_pareto_3obj: 3-objective Pareto (mass, stress, stiffness)
- 167 FEA trials + 5000 NN trials completed
- Demonstrates full hybrid workflow

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 20:01:59 -05:00
..

Atomizer NX Open Hooks

Direct Python hooks for NX CAD/CAE operations via NX Open API.

Overview

This module provides a clean Python API for manipulating NX parts programmatically. Each hook executes NX journals via run_journal.exe and returns structured JSON results.

Architecture

hooks/
├── __init__.py              # Main entry point
├── README.md                # This file
├── test_hooks.py            # Test script
└── nx_cad/                  # CAD manipulation hooks
    ├── __init__.py
    ├── part_manager.py      # Open/Close/Save parts
    ├── expression_manager.py # Get/Set expressions
    ├── geometry_query.py    # Mass properties, bodies
    └── feature_manager.py   # Suppress/Unsuppress features

Requirements

  • NX Installation: Siemens NX 2506 or compatible version
  • Environment Variable: NX_BIN_PATH (defaults to C:\Program Files\Siemens\NX2506\NXBIN)
  • Python: 3.8+ with atomizer conda environment

Quick Start

from optimization_engine.hooks.nx_cad import (
    part_manager,
    expression_manager,
    geometry_query,
    feature_manager,
)

# Path to your NX part
part_path = "C:/path/to/model.prt"

# Get all expressions
result = expression_manager.get_expressions(part_path)
if result["success"]:
    for name, expr in result["data"]["expressions"].items():
        print(f"{name} = {expr['value']} {expr['units']}")

# Get mass properties
result = geometry_query.get_mass_properties(part_path)
if result["success"]:
    print(f"Mass: {result['data']['mass']:.4f} kg")
    print(f"Material: {result['data']['material']}")

Module Reference

part_manager

Manage NX part files (open, close, save).

Function Description Returns
open_part(path) Open an NX part file Part info dict
close_part(path) Close an open part Success status
save_part(path) Save a part Success status
save_part_as(path, new_path) Save with new name Success status
get_part_info(path) Get part metadata Part info dict

Example:

from optimization_engine.hooks.nx_cad import part_manager

# Open a part
result = part_manager.open_part("C:/models/bracket.prt")
if result["success"]:
    print(f"Opened: {result['data']['part_name']}")
    print(f"Modified: {result['data']['is_modified']}")

# Save the part
result = part_manager.save_part("C:/models/bracket.prt")

# Save as new file
result = part_manager.save_part_as(
    "C:/models/bracket.prt",
    "C:/models/bracket_v2.prt"
)

expression_manager

Get and set NX expressions (design parameters).

Function Description Returns
get_expressions(path) Get all expressions Dict of expressions
get_expression(path, name) Get single expression Expression dict
set_expression(path, name, value) Set single expression Success status
set_expressions(path, dict) Set multiple expressions Success status

Example:

from optimization_engine.hooks.nx_cad import expression_manager

part = "C:/models/bracket.prt"

# Get all expressions
result = expression_manager.get_expressions(part)
if result["success"]:
    for name, expr in result["data"]["expressions"].items():
        print(f"{name} = {expr['value']} {expr['units']}")
        # Example output:
        # thickness = 5.0 MilliMeter
        # width = 50.0 MilliMeter

# Get specific expression
result = expression_manager.get_expression(part, "thickness")
if result["success"]:
    print(f"Thickness: {result['data']['value']} {result['data']['units']}")

# Set single expression
result = expression_manager.set_expression(part, "thickness", 7.5)

# Set multiple expressions (batch update)
result = expression_manager.set_expressions(part, {
    "thickness": 7.5,
    "width": 60.0,
    "height": 100.0
})
if result["success"]:
    print(f"Updated {result['data']['update_count']} expressions")

geometry_query

Query geometric properties (mass, volume, bodies).

Function Description Returns
get_mass_properties(path) Get mass, volume, area, centroid Properties dict
get_bodies(path) Get body count and types Bodies dict
get_volume(path) Get total volume Volume float
get_surface_area(path) Get total surface area Area float
get_material(path) Get material name Material string

Example:

from optimization_engine.hooks.nx_cad import geometry_query

part = "C:/models/bracket.prt"

# Get mass properties
result = geometry_query.get_mass_properties(part)
if result["success"]:
    data = result["data"]
    print(f"Mass: {data['mass']:.6f} {data['mass_unit']}")
    print(f"Volume: {data['volume']:.2f} {data['volume_unit']}")
    print(f"Surface Area: {data['surface_area']:.2f} {data['area_unit']}")
    print(f"Centroid: ({data['centroid']['x']:.2f}, "
          f"{data['centroid']['y']:.2f}, {data['centroid']['z']:.2f}) mm")
    print(f"Material: {data['material']}")
    # Example output:
    # Mass: 0.109838 kg
    # Volume: 39311.99 mm^3
    # Surface Area: 10876.71 mm^2
    # Centroid: (0.00, 42.30, 39.58) mm
    # Material: Aluminum_2014

# Get body information
result = geometry_query.get_bodies(part)
if result["success"]:
    print(f"Total bodies: {result['data']['count']}")
    print(f"Solid bodies: {result['data']['solid_count']}")

feature_manager

Suppress and unsuppress features for design exploration.

Function Description Returns
get_features(path) List all features Features list
get_feature_status(path, name) Check if suppressed Boolean
suppress_feature(path, name) Suppress a feature Success status
unsuppress_feature(path, name) Unsuppress a feature Success status
suppress_features(path, names) Suppress multiple Success status
unsuppress_features(path, names) Unsuppress multiple Success status

Example:

from optimization_engine.hooks.nx_cad import feature_manager

part = "C:/models/bracket.prt"

# List all features
result = feature_manager.get_features(part)
if result["success"]:
    print(f"Found {result['data']['count']} features")
    for feat in result["data"]["features"]:
        status = "suppressed" if feat["is_suppressed"] else "active"
        print(f"  {feat['name']} ({feat['type']}): {status}")

# Suppress a feature
result = feature_manager.suppress_feature(part, "FILLET(3)")
if result["success"]:
    print("Feature suppressed!")

# Unsuppress multiple features
result = feature_manager.unsuppress_features(part, ["FILLET(3)", "CHAMFER(1)"])

Return Format

All hook functions return a consistent dictionary structure:

{
    "success": bool,      # True if operation succeeded
    "error": str | None,  # Error message if failed
    "data": dict          # Operation-specific results
}

Error Handling:

result = expression_manager.get_expressions(part_path)

if not result["success"]:
    print(f"Error: {result['error']}")
    # Handle error...
else:
    # Process result["data"]...

NX Open API Reference

These hooks use the following NX Open APIs (verified via Siemens MCP documentation):

Hook NX Open API
Open part Session.Parts.OpenActiveDisplay()
Close part Part.Close()
Save part Part.Save(), Part.SaveAs()
Get expressions Part.Expressions collection
Set expression ExpressionCollection.Edit()
Update model Session.UpdateManager.DoUpdate()
Mass properties MeasureManager.NewMassProperties()
Get bodies Part.Bodies collection
Suppress feature Feature.Suppress()
Unsuppress feature Feature.Unsuppress()

Configuration

NX Path

Set the NX installation path via environment variable:

# Windows
set NX_BIN_PATH=C:\Program Files\Siemens\NX2506\NXBIN

# Or in Python before importing
import os
os.environ["NX_BIN_PATH"] = r"C:\Program Files\Siemens\NX2506\NXBIN"

Timeout

Journal execution has a default 2-minute timeout. For large parts, you may need to increase this in the hook source code.

Integration with Atomizer

These hooks are designed to integrate with Atomizer's optimization workflow:

# In run_optimization.py or custom extractor

from optimization_engine.hooks.nx_cad import expression_manager, geometry_query

def evaluate_design(part_path: str, params: dict) -> dict:
    """Evaluate a design point by updating NX model and extracting metrics."""

    # 1. Update design parameters
    result = expression_manager.set_expressions(part_path, params)
    if not result["success"]:
        raise RuntimeError(f"Failed to set expressions: {result['error']}")

    # 2. Extract mass (objective)
    result = geometry_query.get_mass_properties(part_path)
    if not result["success"]:
        raise RuntimeError(f"Failed to get mass: {result['error']}")

    return {
        "mass_kg": result["data"]["mass"],
        "volume_mm3": result["data"]["volume"],
        "material": result["data"]["material"]
    }

Testing

Run the test script to verify hooks work with your NX installation:

# Activate atomizer environment
conda activate atomizer

# Run tests with default bracket part
python -m optimization_engine.hooks.test_hooks

# Or specify a custom part
python -m optimization_engine.hooks.test_hooks "C:/path/to/your/part.prt"

Troubleshooting

"Part file not found"

  • Verify the path exists and is accessible
  • Use forward slashes or raw strings: r"C:\path\to\file.prt"

"Failed to open part"

  • Ensure NX license is available
  • Check NX_BIN_PATH environment variable
  • Verify NX version compatibility

"Expression not found"

  • Expression names are case-sensitive
  • Use get_expressions() to list available names

Journal execution timeout

  • Large parts may need longer timeout
  • Check NX is not displaying modal dialogs

Version History

Version Date Changes
1.0.0 2025-12-06 Initial release with CAD hooks

See Also