Implements NX solver integration that connects to running Simcenter3D GUI to solve simulations using the journal API. This approach handles licensing properly and ensures fresh output files are generated for each iteration. **New Components:** - optimization_engine/nx_solver.py: Main solver wrapper with auto-detection - optimization_engine/solve_simulation.py: NX journal script for batch solving - examples/test_journal_optimization.py: Complete optimization workflow test - examples/test_nx_solver.py: Solver integration tests - tests/journal_*.py: Reference journal files for NX automation **Key Features:** - Auto-detects NX installation and version - Connects to running NX GUI session (uses existing license) - Closes/reopens .sim files to force reload of updated .prt files - Deletes old output files to force fresh solves - Waits for background solve completion - Saves simulation to ensure all outputs are written - ~4 second solve time per iteration **Workflow:** 1. Update parameters in .prt file (nx_updater.py) 2. Close any open parts in NX session 3. Open .sim file fresh from disk (loads updated .prt) 4. Reload components and switch to FEM component 5. Solve in background mode 6. Save .sim file 7. Wait for .op2/.f06 to appear 8. Extract results from fresh .op2 **Tested:** - Multiple iteration loop (3+ iterations) - Files regenerated fresh each time (verified by timestamps) - Complete parameter update -> solve -> extract workflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
131 lines
3.5 KiB
Python
131 lines
3.5 KiB
Python
"""
|
|
Test NX Solver Integration
|
|
|
|
Tests running NX Nastran in batch mode.
|
|
"""
|
|
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
project_root = Path(__file__).parent.parent
|
|
sys.path.insert(0, str(project_root))
|
|
|
|
from optimization_engine.nx_solver import NXSolver, run_nx_simulation
|
|
|
|
|
|
def test_solver_basic():
|
|
"""Test basic solver execution."""
|
|
print("="*60)
|
|
print("TEST 1: Basic Solver Execution")
|
|
print("="*60)
|
|
|
|
sim_file = project_root / "examples/bracket/Bracket_sim1.sim"
|
|
|
|
if not sim_file.exists():
|
|
print(f"ERROR: Simulation file not found: {sim_file}")
|
|
return False
|
|
|
|
try:
|
|
# Initialize solver
|
|
solver = NXSolver(nastran_version="2412", timeout=300)
|
|
print(f"\nSolver initialized:")
|
|
print(f" NX Directory: {solver.nx_install_dir}")
|
|
print(f" Solver Exe: {solver.solver_exe}")
|
|
|
|
# Run simulation
|
|
result = solver.run_simulation(
|
|
sim_file=sim_file,
|
|
cleanup=False # Keep all files for inspection
|
|
)
|
|
|
|
print(f"\n{'='*60}")
|
|
print("SOLVER RESULT:")
|
|
print(f"{'='*60}")
|
|
print(f" Success: {result['success']}")
|
|
print(f" Time: {result['elapsed_time']:.1f}s")
|
|
print(f" OP2 file: {result['op2_file']}")
|
|
print(f" Return code: {result['return_code']}")
|
|
|
|
if result['errors']:
|
|
print(f"\n Errors:")
|
|
for error in result['errors']:
|
|
print(f" {error}")
|
|
|
|
return result['success']
|
|
|
|
except Exception as e:
|
|
print(f"\nERROR: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
|
|
def test_convenience_function():
|
|
"""Test convenience function."""
|
|
print("\n" + "="*60)
|
|
print("TEST 2: Convenience Function")
|
|
print("="*60)
|
|
|
|
sim_file = project_root / "examples/bracket/Bracket_sim1.sim"
|
|
|
|
try:
|
|
op2_file = run_nx_simulation(
|
|
sim_file=sim_file,
|
|
nastran_version="2412",
|
|
timeout=300,
|
|
cleanup=True
|
|
)
|
|
|
|
print(f"\nSUCCESS!")
|
|
print(f" OP2 file: {op2_file}")
|
|
print(f" File exists: {op2_file.exists()}")
|
|
print(f" File size: {op2_file.stat().st_size / 1024:.1f} KB")
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"\nFAILED: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("="*60)
|
|
print("NX SOLVER INTEGRATION TEST")
|
|
print("="*60)
|
|
print("\nThis will run NX Nastran solver in batch mode.")
|
|
print("Make sure:")
|
|
print(" 1. NX 2412 is installed")
|
|
print(" 2. No NX GUI sessions are using the .sim file")
|
|
print(" 3. You have write permissions in the bracket folder")
|
|
print("\n" + "="*60)
|
|
|
|
input("\nPress ENTER to continue or Ctrl+C to cancel...")
|
|
|
|
# Test 1: Basic execution
|
|
test1_result = test_solver_basic()
|
|
|
|
if test1_result:
|
|
# Test 2: Convenience function
|
|
test2_result = test_convenience_function()
|
|
|
|
if test2_result:
|
|
print("\n" + "="*60)
|
|
print("ALL TESTS PASSED ✓")
|
|
print("="*60)
|
|
print("\nNX solver integration is working!")
|
|
print("You can now use it in optimization loops.")
|
|
else:
|
|
print("\n" + "="*60)
|
|
print("TEST 2 FAILED")
|
|
print("="*60)
|
|
else:
|
|
print("\n" + "="*60)
|
|
print("TEST 1 FAILED - Skipping Test 2")
|
|
print("="*60)
|
|
print("\nCheck:")
|
|
print(" - NX installation path")
|
|
print(" - .sim file is valid")
|
|
print(" - NX license is available")
|