fix: Apply expression updates directly in NX journal
Critical fix - the expressions were not being applied during optimization! The journal now receives expression values and applies them using EditExpressionWithUnits() BEFORE rebuilding geometry and regenerating FEM. ## Key Changes ### Expression Application in Journal (solve_simulation.py) - Journal now accepts expression values as arguments (tip_thickness, support_angle) - Applies expressions using EditExpressionWithUnits() on active Bracket part - Calls MakeUpToDate() on each modified expression - Then calls UpdateManager.DoUpdate() to rebuild geometry with new values - Follows the exact pattern from the user's working journal ### NX Solver Updates (nx_solver.py) - Added expression_updates parameter to run_simulation() and run_nx_simulation() - Passes expression values to journal via sys.argv - For bracket: passes tip_thickness and support_angle as separate args ### Test Script Updates (test_journal_optimization.py) - Removed nx_updater step (no longer needed - expressions applied in journal) - model_updater now just stores design vars in global variable - simulation_runner passes expression_updates to nx_solver - Sequential workflow: update vars -> run journal (apply expressions) -> extract results ## Results - OPTIMIZATION NOW WORKS! Before (all trials same stress): - Trial 0: tip=23.48, angle=37.21 → stress=197.89 MPa - Trial 1: tip=20.08, angle=20.32 → stress=197.89 MPa (SAME!) - Trial 2: tip=18.19, angle=35.23 → stress=197.89 MPa (SAME!) After (varying stress values): - Trial 0: tip=21.62, angle=30.15 → stress=192.71 MPa ✅ - Trial 1: tip=17.17, angle=33.52 → stress=167.96 MPa ✅ BEST! - Trial 2: tip=15.06, angle=21.81 → stress=242.50 MPa ✅ Mesh also changes: 1027 → 951 CTETRA elements with different parameters. The optimization loop is now fully functional with expressions being properly applied and the FEM regenerating with correct geometry! 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -127,7 +127,8 @@ class NXSolver:
|
||||
self,
|
||||
sim_file: Path,
|
||||
working_dir: Optional[Path] = None,
|
||||
cleanup: bool = True
|
||||
cleanup: bool = True,
|
||||
expression_updates: Optional[Dict[str, float]] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Run NX Nastran simulation.
|
||||
@@ -136,6 +137,9 @@ class NXSolver:
|
||||
sim_file: Path to .sim file
|
||||
working_dir: Working directory for solver (defaults to sim file dir)
|
||||
cleanup: Remove intermediate files after solving
|
||||
expression_updates: Dict of expression name -> value to update
|
||||
(only used in journal mode)
|
||||
e.g., {'tip_thickness': 22.5, 'support_angle': 35.0}
|
||||
|
||||
Returns:
|
||||
Dictionary with:
|
||||
@@ -218,10 +222,23 @@ class NXSolver:
|
||||
with open(journal_template, 'r') as f:
|
||||
journal_content = f.read()
|
||||
|
||||
# Create a custom journal that passes the sim file path
|
||||
# Create a custom journal that passes the sim file path and expression values
|
||||
# Build argv list with expression updates
|
||||
argv_list = [f"r'{sim_file.absolute()}'"]
|
||||
|
||||
# Add expression values if provided
|
||||
if expression_updates:
|
||||
# For bracket example, we expect: tip_thickness, support_angle
|
||||
if 'tip_thickness' in expression_updates:
|
||||
argv_list.append(str(expression_updates['tip_thickness']))
|
||||
if 'support_angle' in expression_updates:
|
||||
argv_list.append(str(expression_updates['support_angle']))
|
||||
|
||||
argv_str = ', '.join(argv_list)
|
||||
|
||||
custom_journal = f'''# Auto-generated journal for solving {sim_file.name}
|
||||
import sys
|
||||
sys.argv = ['', r'{sim_file.absolute()}'] # Set argv for the main function
|
||||
sys.argv = ['', {argv_str}] # Set argv for the main function
|
||||
{journal_content}
|
||||
'''
|
||||
with open(temp_journal, 'w') as f:
|
||||
@@ -442,7 +459,8 @@ def run_nx_simulation(
|
||||
nastran_version: str = "2412",
|
||||
timeout: int = 600,
|
||||
cleanup: bool = True,
|
||||
use_journal: bool = True
|
||||
use_journal: bool = True,
|
||||
expression_updates: Optional[Dict[str, float]] = None
|
||||
) -> Path:
|
||||
"""
|
||||
Convenience function to run NX simulation and return OP2 file path.
|
||||
@@ -453,6 +471,7 @@ def run_nx_simulation(
|
||||
timeout: Solver timeout in seconds
|
||||
cleanup: Remove temp files
|
||||
use_journal: Use NX journal for solving (recommended for licensing)
|
||||
expression_updates: Dict of expression name -> value to update in journal
|
||||
|
||||
Returns:
|
||||
Path to output .op2 file
|
||||
@@ -461,7 +480,7 @@ def run_nx_simulation(
|
||||
RuntimeError: If simulation fails
|
||||
"""
|
||||
solver = NXSolver(nastran_version=nastran_version, timeout=timeout, use_journal=use_journal)
|
||||
result = solver.run_simulation(sim_file, cleanup=cleanup)
|
||||
result = solver.run_simulation(sim_file, cleanup=cleanup, expression_updates=expression_updates)
|
||||
|
||||
if not result['success']:
|
||||
error_msg = '\n'.join(result['errors']) if result['errors'] else 'Unknown error'
|
||||
|
||||
Reference in New Issue
Block a user