refactor: Archive experimental LLM features for MVP stability (Phase 1.1)
Moved experimental LLM integration code to optimization_engine/future/: - llm_optimization_runner.py - Runtime LLM API runner - llm_workflow_analyzer.py - Workflow analysis - inline_code_generator.py - Auto-generate calculations - hook_generator.py - Auto-generate hooks - report_generator.py - LLM report generation - extractor_orchestrator.py - Extractor orchestration Added comprehensive optimization_engine/future/README.md explaining: - MVP LLM strategy (Claude Code skills, not runtime LLM) - Why files were archived - When to revisit post-MVP - Production architecture reference Production runner confirmed: optimization_engine/runner.py is sole active runner. This establishes clear separation between: - Production code (stable, no runtime LLM dependencies) - Experimental code (archived for post-MVP exploration) Part of Phase 1: Core Stabilization & Organization for MVP Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
NX Nastran Solver Integration
|
||||
|
||||
Executes NX Nastran solver in batch mode for optimization loops.
|
||||
Includes session management to prevent conflicts with concurrent optimizations.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
@@ -10,6 +11,7 @@ import subprocess
|
||||
import time
|
||||
import shutil
|
||||
import os
|
||||
from optimization_engine.nx_session_manager import NXSessionManager
|
||||
|
||||
|
||||
class NXSolver:
|
||||
@@ -28,7 +30,9 @@ class NXSolver:
|
||||
nx_install_dir: Optional[Path] = None,
|
||||
nastran_version: str = "2412",
|
||||
timeout: int = 600,
|
||||
use_journal: bool = True
|
||||
use_journal: bool = True,
|
||||
enable_session_management: bool = True,
|
||||
study_name: str = "default_study"
|
||||
):
|
||||
"""
|
||||
Initialize NX Solver.
|
||||
@@ -38,10 +42,20 @@ class NXSolver:
|
||||
nastran_version: NX version (e.g., "2412", "2506")
|
||||
timeout: Maximum solver time in seconds (default: 10 minutes)
|
||||
use_journal: Use NX journal for solving (recommended for licensing)
|
||||
enable_session_management: Enable session conflict prevention (default: True)
|
||||
study_name: Name of the study (used for session tracking)
|
||||
"""
|
||||
self.nastran_version = nastran_version
|
||||
self.timeout = timeout
|
||||
self.use_journal = use_journal
|
||||
self.study_name = study_name
|
||||
|
||||
# Initialize session manager
|
||||
self.session_manager = None
|
||||
if enable_session_management:
|
||||
self.session_manager = NXSessionManager(verbose=True)
|
||||
# Clean up any stale locks from crashed processes
|
||||
self.session_manager.cleanup_stale_locks()
|
||||
|
||||
# Auto-detect NX installation
|
||||
if nx_install_dir is None:
|
||||
@@ -128,7 +142,8 @@ class NXSolver:
|
||||
sim_file: Path,
|
||||
working_dir: Optional[Path] = None,
|
||||
cleanup: bool = True,
|
||||
expression_updates: Optional[Dict[str, float]] = None
|
||||
expression_updates: Optional[Dict[str, float]] = None,
|
||||
solution_name: Optional[str] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Run NX Nastran simulation.
|
||||
@@ -140,6 +155,8 @@ class NXSolver:
|
||||
expression_updates: Dict of expression name -> value to update
|
||||
(only used in journal mode)
|
||||
e.g., {'tip_thickness': 22.5, 'support_angle': 35.0}
|
||||
solution_name: Specific solution to solve (e.g., "Solution_Normal_Modes")
|
||||
If None, solves all solutions. Only used in journal mode.
|
||||
|
||||
Returns:
|
||||
Dictionary with:
|
||||
@@ -148,6 +165,7 @@ class NXSolver:
|
||||
- log_file: Path to .log file
|
||||
- elapsed_time: Solve time in seconds
|
||||
- errors: List of error messages (if any)
|
||||
- solution_name: Name of the solution that was solved
|
||||
"""
|
||||
sim_file = Path(sim_file)
|
||||
if not sim_file.exists():
|
||||
@@ -174,13 +192,20 @@ class NXSolver:
|
||||
sim_file = dat_file
|
||||
|
||||
# Prepare output file names
|
||||
# When using journal mode with .sim files, output is named: <base>-solution_1.op2
|
||||
# When using journal mode with .sim files, output is named: <base>-solution_name.op2
|
||||
# When using direct mode with .dat files, output is named: <base>.op2
|
||||
base_name = sim_file.stem
|
||||
|
||||
if self.use_journal and sim_file.suffix == '.sim':
|
||||
# Journal mode: look for -solution_1 pattern
|
||||
output_base = f"{base_name.lower()}-solution_1"
|
||||
# Journal mode: determine solution-specific output name
|
||||
if solution_name:
|
||||
# Convert solution name to lowercase and replace spaces with underscores
|
||||
# E.g., "Solution_Normal_Modes" -> "solution_normal_modes"
|
||||
solution_suffix = solution_name.lower().replace(' ', '_')
|
||||
output_base = f"{base_name.lower()}-{solution_suffix}"
|
||||
else:
|
||||
# Default to solution_1
|
||||
output_base = f"{base_name.lower()}-solution_1"
|
||||
else:
|
||||
# Direct mode or .dat file
|
||||
output_base = base_name
|
||||
@@ -216,17 +241,21 @@ class NXSolver:
|
||||
with open(journal_template, 'r') as f:
|
||||
journal_content = f.read()
|
||||
|
||||
# Create a custom journal that passes the sim file path and expression values
|
||||
# Create a custom journal that passes the sim file path, solution name, and expression values
|
||||
# Build argv list with expression updates
|
||||
argv_list = [f"r'{sim_file.absolute()}'"]
|
||||
|
||||
# Add solution name if provided (passed as second argument)
|
||||
if solution_name:
|
||||
argv_list.append(f"'{solution_name}'")
|
||||
else:
|
||||
argv_list.append("None")
|
||||
|
||||
# Add expression values if provided
|
||||
# Pass all expressions as key=value pairs
|
||||
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']))
|
||||
for expr_name, expr_value in expression_updates.items():
|
||||
argv_list.append(f"'{expr_name}={expr_value}'")
|
||||
|
||||
argv_str = ', '.join(argv_list)
|
||||
|
||||
@@ -372,7 +401,8 @@ sys.argv = ['', {argv_str}] # Set argv for the main function
|
||||
'f06_file': f06_file if f06_file.exists() else None,
|
||||
'elapsed_time': elapsed_time,
|
||||
'errors': errors,
|
||||
'return_code': result.returncode
|
||||
'return_code': result.returncode,
|
||||
'solution_name': solution_name
|
||||
}
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
@@ -384,7 +414,8 @@ sys.argv = ['', {argv_str}] # Set argv for the main function
|
||||
'log_file': log_file if log_file.exists() else None,
|
||||
'elapsed_time': elapsed_time,
|
||||
'errors': [f'Solver timeout after {self.timeout}s'],
|
||||
'return_code': -1
|
||||
'return_code': -1,
|
||||
'solution_name': solution_name
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
@@ -396,7 +427,8 @@ sys.argv = ['', {argv_str}] # Set argv for the main function
|
||||
'log_file': None,
|
||||
'elapsed_time': elapsed_time,
|
||||
'errors': [str(e)],
|
||||
'return_code': -1
|
||||
'return_code': -1,
|
||||
'solution_name': solution_name
|
||||
}
|
||||
|
||||
def _check_solution_success(self, f06_file: Path, log_file: Path) -> bool:
|
||||
@@ -476,7 +508,8 @@ def run_nx_simulation(
|
||||
timeout: int = 600,
|
||||
cleanup: bool = True,
|
||||
use_journal: bool = True,
|
||||
expression_updates: Optional[Dict[str, float]] = None
|
||||
expression_updates: Optional[Dict[str, float]] = None,
|
||||
solution_name: Optional[str] = None
|
||||
) -> Path:
|
||||
"""
|
||||
Convenience function to run NX simulation and return OP2 file path.
|
||||
@@ -488,6 +521,7 @@ def run_nx_simulation(
|
||||
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
|
||||
solution_name: Specific solution to solve (e.g., "Solution_Normal_Modes")
|
||||
|
||||
Returns:
|
||||
Path to output .op2 file
|
||||
@@ -496,7 +530,12 @@ 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, expression_updates=expression_updates)
|
||||
result = solver.run_simulation(
|
||||
sim_file,
|
||||
cleanup=cleanup,
|
||||
expression_updates=expression_updates,
|
||||
solution_name=solution_name
|
||||
)
|
||||
|
||||
if not result['success']:
|
||||
error_msg = '\n'.join(result['errors']) if result['errors'] else 'Unknown error'
|
||||
|
||||
Reference in New Issue
Block a user