Files
Atomizer/examples/test_journal_optimization.py

134 lines
4.2 KiB
Python
Raw Normal View History

feat: Add journal-based NX solver integration for optimization 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>
2025-11-15 12:23:57 -05:00
"""
Test: Complete Optimization with Journal-Based NX Solver
This tests the complete workflow:
1. Update model parameters in .prt
2. Solve via journal (using running NX GUI)
3. Extract results from OP2
4. Run optimization loop
REQUIREMENTS:
- Simcenter3D must be open (but no files need to be loaded)
- test_env conda environment activated
"""
from pathlib import Path
import sys
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
from optimization_engine.runner import OptimizationRunner
from optimization_engine.nx_updater import update_nx_model
from optimization_engine.nx_solver import run_nx_simulation
from optimization_engine.result_extractors.extractors import (
stress_extractor,
displacement_extractor
)
def bracket_model_updater(design_vars: dict):
"""Update bracket model parameters."""
prt_file = project_root / "examples/bracket/Bracket.prt"
print(f"\n[MODEL UPDATE] {prt_file.name}")
for name, value in design_vars.items():
print(f" {name} = {value:.4f}")
update_nx_model(prt_file, design_vars, backup=False)
def bracket_simulation_runner() -> Path:
"""
Run NX solver via journal on running NX GUI session.
This connects to the running Simcenter3D GUI and:
1. Opens the .sim file
2. Updates the FEM component
3. Solves the simulation
4. Returns path to .op2 file
"""
sim_file = project_root / "examples/bracket/Bracket_sim1.sim"
print("\n[SIMULATION] Running via journal on NX GUI...")
print(f" SIM file: {sim_file.name}")
try:
# Run solver via journal (connects to running NX GUI)
op2_file = run_nx_simulation(
sim_file=sim_file,
nastran_version="2412",
timeout=300, # 5 minute timeout
cleanup=True, # Clean up temp files
use_journal=True # Use journal mode (requires NX GUI open)
)
print(f"[SIMULATION] Complete! Results: {op2_file.name}")
return op2_file
except Exception as e:
print(f"[SIMULATION] FAILED: {e}")
raise
if __name__ == "__main__":
print("="*60)
print("JOURNAL-BASED OPTIMIZATION TEST")
print("="*60)
feat: Implement complete FEM regeneration workflow This commit completes the optimization loop infrastructure by implementing the full FEM regeneration workflow based on the user's working journal. ## Changes ### FEM Regeneration Workflow (solve_simulation.py) - Added STEP 1: Switch to Bracket.prt and update geometry - Uses SetActiveDisplay() to make Bracket.prt active - Calls UpdateManager.DoUpdate() to rebuild CAD geometry with new expressions - Added STEP 2: Switch to Bracket_fem1 and update FE model - Uses SetActiveDisplay() to make FEM active - Calls fEModel1.UpdateFemodel() to regenerate FEM with updated geometry - Added STEP 3: Switch back to sim part before solving - Close and reopen .sim file to force reload from disk ### Enhanced Journal Output (nx_solver.py) - Display journal stdout output for debugging - Shows all journal steps: geometry update, FEM regeneration, solve, save - Helps verify workflow execution ### Verification Tools - Added verify_parametric_link.py journal to check expression dependencies - Added FEM_REGENERATION_STATUS.md documenting the complete status ## Status ### ✅ Fully Functional Components 1. Parameter updates - nx_updater.py modifies .prt expressions 2. NX solver - ~4s per solve via journal 3. Result extraction - pyNastran reads .op2 files 4. History tracking - saves to JSON/CSV 5. Optimization loop - Optuna explores parameter space 6. **FEM regeneration workflow** - Journal executes all steps successfully ### ❌ Remaining Issue: Expressions Not Linked to Geometry The optimization returns identical stress values (197.89 MPa) for all trials because the Bracket.prt expressions are not referenced by any geometry features. Evidence: - Journal verification shows FEM update steps execute successfully - Feature dependency check shows no features reference the expressions - All optimization infrastructure is working correctly The code is ready - waiting for Bracket.prt to have its expressions properly linked to the geometry features in NX. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-15 12:43:31 -05:00
print("\nREQUIREMENTS:")
feat: Add journal-based NX solver integration for optimization 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>
2025-11-15 12:23:57 -05:00
print("- Simcenter3D must be OPEN (no files need to be loaded)")
print("- Will run 3 optimization trials")
print("- Each trial: update params -> solve via journal -> extract results")
print("="*60)
response = input("\nIs Simcenter3D open? (yes/no): ")
if response.lower() not in ['yes', 'y']:
print("Please open Simcenter3D and try again.")
sys.exit(0)
config_path = project_root / "examples/bracket/optimization_config_stress_displacement.json"
runner = OptimizationRunner(
config_path=config_path,
model_updater=bracket_model_updater,
simulation_runner=bracket_simulation_runner, # Journal-based solver!
result_extractors={
'stress_extractor': stress_extractor,
'displacement_extractor': displacement_extractor
}
)
# Run just 3 trials for testing
runner.config['optimization_settings']['n_trials'] = 3
print("\n" + "="*60)
print("Starting optimization with 3 trials")
print("Objective: Minimize max von Mises stress")
print("Constraint: Max displacement <= 1.0 mm")
print("Solver: Journal-based (using running NX GUI)")
print("="*60)
try:
study = runner.run(study_name="journal_solver_test")
print("\n" + "="*60)
print("OPTIMIZATION COMPLETE!")
print("="*60)
print(f"\nBest stress: {study.best_value:.2f} MPa")
print(f"\nBest parameters:")
for param, value in study.best_params.items():
print(f" {param}: {value:.4f}")
print(f"\nResults saved to: {runner.output_dir}")
print("\nCheck history.csv to see optimization progress!")
except Exception as e:
print(f"\n{'='*60}")
print("ERROR DURING OPTIMIZATION")
print("="*60)
print(f"{e}")
import traceback
traceback.print_exc()
print("\nMake sure:")
print(" - Simcenter3D is open and running")
print(" - .sim file is valid and solvable")
print(" - No other processes are locking the files")