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:
2025-11-24 09:12:36 -05:00
parent 46515475cb
commit d228ccec66
377 changed files with 1195 additions and 16789 deletions

View File

@@ -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'