refactor: Major reorganization of optimization_engine module structure
BREAKING CHANGE: Module paths have been reorganized for better maintainability. Backwards compatibility aliases with deprecation warnings are provided. New Structure: - core/ - Optimization runners (runner, intelligent_optimizer, etc.) - processors/ - Data processing - surrogates/ - Neural network surrogates - nx/ - NX/Nastran integration (solver, updater, session_manager) - study/ - Study management (creator, wizard, state, reset) - reporting/ - Reports and analysis (visualizer, report_generator) - config/ - Configuration management (manager, builder) - utils/ - Utilities (logger, auto_doc, etc.) - future/ - Research/experimental code Migration: - ~200 import changes across 125 files - All __init__.py files use lazy loading to avoid circular imports - Backwards compatibility layer supports old import paths with warnings - All existing functionality preserved To migrate existing code: OLD: from optimization_engine.nx_solver import NXSolver NEW: from optimization_engine.nx.solver import NXSolver OLD: from optimization_engine.runner import OptimizationRunner NEW: from optimization_engine.core.runner import OptimizationRunner 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,7 @@ This extractor reads expressions using the .exp export method for accuracy.
|
|||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Any
|
from typing import Dict, Any
|
||||||
from optimization_engine.nx_updater import NXParameterUpdater
|
from optimization_engine.nx.updater import NXParameterUpdater
|
||||||
|
|
||||||
|
|
||||||
def extract_expression(prt_file: Path, expression_name: str):
|
def extract_expression(prt_file: Path, expression_name: str):
|
||||||
|
|||||||
@@ -228,11 +228,11 @@ from pathlib import Path
|
|||||||
# Add optimization engine to path
|
# Add optimization engine to path
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
||||||
|
|
||||||
from optimization_engine.intelligent_optimizer import IntelligentOptimizer
|
from optimization_engine.core.intelligent_optimizer import IntelligentOptimizer
|
||||||
from optimization_engine.nx_updater import NXParameterUpdater
|
from optimization_engine.nx.updater import NXParameterUpdater
|
||||||
from optimization_engine.nx_solver import NXSolver
|
from optimization_engine.nx.solver import NXSolver
|
||||||
from optimization_engine.extractors.frequency_extractor import extract_first_frequency
|
from optimization_engine.extractors.frequency_extractor import extract_first_frequency
|
||||||
from optimization_engine.generate_report_markdown import generate_markdown_report
|
from optimization_engine.reporting.markdown_report import generate_markdown_report
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import matplotlib.pyplot as plt
|
|||||||
project_root = Path(__file__).parent
|
project_root = Path(__file__).parent
|
||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
from optimization_engine.active_learning_surrogate import (
|
from optimization_engine.processors.surrogates.active_learning_surrogate import (
|
||||||
ActiveLearningSurrogate,
|
ActiveLearningSurrogate,
|
||||||
extract_training_data_from_study
|
extract_training_data_from_study
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ project_root = Path(__file__).parent
|
|||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
sys.path.insert(0, str(project_root / 'atomizer-field'))
|
sys.path.insert(0, str(project_root / 'atomizer-field'))
|
||||||
|
|
||||||
from optimization_engine.simple_mlp_surrogate import SimpleSurrogate
|
from optimization_engine.processors.surrogates.simple_mlp_surrogate import SimpleSurrogate
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ def load_config_bounds(study_path: Path) -> dict:
|
|||||||
|
|
||||||
return bounds
|
return bounds
|
||||||
|
|
||||||
from optimization_engine.active_learning_surrogate import EnsembleMLP
|
from optimization_engine.processors.surrogates.active_learning_surrogate import EnsembleMLP
|
||||||
|
|
||||||
|
|
||||||
class ValidatedSurrogate:
|
class ValidatedSurrogate:
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import matplotlib.pyplot as plt
|
|||||||
project_root = Path(__file__).parent
|
project_root = Path(__file__).parent
|
||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
from optimization_engine.active_learning_surrogate import (
|
from optimization_engine.processors.surrogates.active_learning_surrogate import (
|
||||||
EnsembleMLP,
|
EnsembleMLP,
|
||||||
extract_training_data_from_study
|
extract_training_data_from_study
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import optuna
|
|||||||
project_root = Path(__file__).parent
|
project_root = Path(__file__).parent
|
||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
from optimization_engine.simple_mlp_surrogate import SimpleSurrogate
|
from optimization_engine.processors.surrogates.simple_mlp_surrogate import SimpleSurrogate
|
||||||
|
|
||||||
def load_fea_data_from_database(db_path: str, study_name: str):
|
def load_fea_data_from_database(db_path: str, study_name: str):
|
||||||
"""Load actual FEA results from database for comparison."""
|
"""Load actual FEA results from database for comparison."""
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ Expected behavior:
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import optuna
|
import optuna
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from optimization_engine.adaptive_characterization import CharacterizationStoppingCriterion
|
from optimization_engine.processors.adaptive_characterization import CharacterizationStoppingCriterion
|
||||||
from optimization_engine.landscape_analyzer import LandscapeAnalyzer
|
from optimization_engine.reporting.landscape_analyzer import LandscapeAnalyzer
|
||||||
|
|
||||||
|
|
||||||
def simple_smooth_function(trial):
|
def simple_smooth_function(trial):
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""Test neural surrogate integration."""
|
"""Test neural surrogate integration."""
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from optimization_engine.neural_surrogate import create_surrogate_for_study
|
from optimization_engine.processors.surrogates.neural_surrogate import create_surrogate_for_study
|
||||||
|
|
||||||
print("Testing Neural Surrogate Integration")
|
print("Testing Neural Surrogate Integration")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ project_root = Path(__file__).parent
|
|||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
sys.path.insert(0, str(project_root / 'atomizer-field'))
|
sys.path.insert(0, str(project_root / 'atomizer-field'))
|
||||||
|
|
||||||
from optimization_engine.neural_surrogate import create_parametric_surrogate_for_study
|
from optimization_engine.processors.surrogates.neural_surrogate import create_parametric_surrogate_for_study
|
||||||
|
|
||||||
# Create surrogate
|
# Create surrogate
|
||||||
print("Creating parametric surrogate...")
|
print("Creating parametric surrogate...")
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""Test parametric surrogate integration."""
|
"""Test parametric surrogate integration."""
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from optimization_engine.neural_surrogate import create_parametric_surrogate_for_study
|
from optimization_engine.processors.surrogates.neural_surrogate import create_parametric_surrogate_for_study
|
||||||
|
|
||||||
print("Testing Parametric Neural Surrogate")
|
print("Testing Parametric Neural Surrogate")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ from pathlib import Path
|
|||||||
# Add parent directory to path
|
# Add parent directory to path
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
||||||
|
|
||||||
from optimization_engine.runner import OptimizationRunner
|
from optimization_engine.core.runner import OptimizationRunner
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Run the optimization."""
|
"""Run the optimization."""
|
||||||
|
|||||||
@@ -963,7 +963,7 @@ async def convert_study_mesh(study_id: str):
|
|||||||
|
|
||||||
# Import mesh converter
|
# Import mesh converter
|
||||||
sys.path.append(str(Path(__file__).parent.parent.parent.parent.parent))
|
sys.path.append(str(Path(__file__).parent.parent.parent.parent.parent))
|
||||||
from optimization_engine.mesh_converter import convert_study_mesh
|
from optimization_engine.nx.mesh_converter import convert_study_mesh
|
||||||
|
|
||||||
# Convert mesh
|
# Convert mesh
|
||||||
output_path = convert_study_mesh(study_dir)
|
output_path = convert_study_mesh(study_dir)
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ from typing import Optional
|
|||||||
PROJECT_ROOT = Path(__file__).parent
|
PROJECT_ROOT = Path(__file__).parent
|
||||||
sys.path.insert(0, str(PROJECT_ROOT))
|
sys.path.insert(0, str(PROJECT_ROOT))
|
||||||
|
|
||||||
from optimization_engine.auto_trainer import AutoTrainer, check_training_status
|
from optimization_engine.processors.surrogates.auto_trainer import AutoTrainer, check_training_status
|
||||||
from optimization_engine.template_loader import (
|
from optimization_engine.config.template_loader import (
|
||||||
create_study_from_template,
|
create_study_from_template,
|
||||||
list_templates,
|
list_templates,
|
||||||
get_template
|
get_template
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ def setup_python_path():
|
|||||||
"""
|
"""
|
||||||
Add Atomizer root to Python path if not already present.
|
Add Atomizer root to Python path if not already present.
|
||||||
|
|
||||||
This allows imports like `from optimization_engine.runner import ...`
|
This allows imports like `from optimization_engine.core.runner import ...`
|
||||||
to work from anywhere in the project.
|
to work from anywhere in the project.
|
||||||
"""
|
"""
|
||||||
root = get_atomizer_root()
|
root = get_atomizer_root()
|
||||||
@@ -124,7 +124,7 @@ def ensure_imports():
|
|||||||
atomizer_paths.ensure_imports()
|
atomizer_paths.ensure_imports()
|
||||||
|
|
||||||
# Now you can import Atomizer modules
|
# Now you can import Atomizer modules
|
||||||
from optimization_engine.runner import OptimizationRunner
|
from optimization_engine.core.runner import OptimizationRunner
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
setup_python_path()
|
setup_python_path()
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ if sys.platform == 'win32':
|
|||||||
project_root = Path(__file__).parent.parent
|
project_root = Path(__file__).parent.parent
|
||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
from optimization_engine.research_agent import (
|
from optimization_engine.future.research_agent import (
|
||||||
ResearchAgent,
|
ResearchAgent,
|
||||||
ResearchFindings,
|
ResearchFindings,
|
||||||
KnowledgeGap,
|
KnowledgeGap,
|
||||||
|
|||||||
208
migrate_imports.py
Normal file
208
migrate_imports.py
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
optimization_engine Migration Script
|
||||||
|
=====================================
|
||||||
|
Automatically updates all imports across the codebase.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python migrate_imports.py --dry-run # Preview changes
|
||||||
|
python migrate_imports.py --execute # Apply changes
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Dict, List, Tuple
|
||||||
|
|
||||||
|
# Import mappings (old -> new) - using regex patterns
|
||||||
|
IMPORT_MAPPINGS = {
|
||||||
|
# =============================================================================
|
||||||
|
# CORE MODULE
|
||||||
|
# =============================================================================
|
||||||
|
r'from optimization_engine\.runner\b': 'from optimization_engine.core.runner',
|
||||||
|
r'from optimization_engine\.base_runner\b': 'from optimization_engine.core.base_runner',
|
||||||
|
r'from optimization_engine\.runner_with_neural\b': 'from optimization_engine.core.runner_with_neural',
|
||||||
|
r'from optimization_engine\.intelligent_optimizer\b': 'from optimization_engine.core.intelligent_optimizer',
|
||||||
|
r'from optimization_engine\.method_selector\b': 'from optimization_engine.core.method_selector',
|
||||||
|
r'from optimization_engine\.strategy_selector\b': 'from optimization_engine.core.strategy_selector',
|
||||||
|
r'from optimization_engine\.strategy_portfolio\b': 'from optimization_engine.core.strategy_portfolio',
|
||||||
|
r'from optimization_engine\.gradient_optimizer\b': 'from optimization_engine.core.gradient_optimizer',
|
||||||
|
r'import optimization_engine\.runner\b': 'import optimization_engine.core.runner',
|
||||||
|
r'import optimization_engine\.intelligent_optimizer\b': 'import optimization_engine.core.intelligent_optimizer',
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SURROGATES MODULE
|
||||||
|
# =============================================================================
|
||||||
|
r'from optimization_engine\.neural_surrogate\b': 'from optimization_engine.processors.surrogates.neural_surrogate',
|
||||||
|
r'from optimization_engine\.generic_surrogate\b': 'from optimization_engine.processors.surrogates.generic_surrogate',
|
||||||
|
r'from optimization_engine\.adaptive_surrogate\b': 'from optimization_engine.processors.surrogates.adaptive_surrogate',
|
||||||
|
r'from optimization_engine\.simple_mlp_surrogate\b': 'from optimization_engine.processors.surrogates.simple_mlp_surrogate',
|
||||||
|
r'from optimization_engine\.active_learning_surrogate\b': 'from optimization_engine.processors.surrogates.active_learning_surrogate',
|
||||||
|
r'from optimization_engine\.surrogate_tuner\b': 'from optimization_engine.processors.surrogates.surrogate_tuner',
|
||||||
|
r'from optimization_engine\.auto_trainer\b': 'from optimization_engine.processors.surrogates.auto_trainer',
|
||||||
|
r'from optimization_engine\.training_data_exporter\b': 'from optimization_engine.processors.surrogates.training_data_exporter',
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# NX MODULE
|
||||||
|
# =============================================================================
|
||||||
|
r'from optimization_engine\.nx_solver\b': 'from optimization_engine.nx.solver',
|
||||||
|
r'from optimization_engine\.nx_updater\b': 'from optimization_engine.nx.updater',
|
||||||
|
r'from optimization_engine\.nx_session_manager\b': 'from optimization_engine.nx.session_manager',
|
||||||
|
r'from optimization_engine\.solve_simulation\b': 'from optimization_engine.nx.solve_simulation',
|
||||||
|
r'from optimization_engine\.solve_simulation_simple\b': 'from optimization_engine.nx.solve_simulation_simple',
|
||||||
|
r'from optimization_engine\.model_cleanup\b': 'from optimization_engine.nx.model_cleanup',
|
||||||
|
r'from optimization_engine\.export_expressions\b': 'from optimization_engine.nx.export_expressions',
|
||||||
|
r'from optimization_engine\.import_expressions\b': 'from optimization_engine.nx.import_expressions',
|
||||||
|
r'from optimization_engine\.mesh_converter\b': 'from optimization_engine.nx.mesh_converter',
|
||||||
|
r'import optimization_engine\.nx_solver\b': 'import optimization_engine.nx.solver',
|
||||||
|
r'import optimization_engine\.nx_updater\b': 'import optimization_engine.nx.updater',
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# STUDY MODULE
|
||||||
|
# =============================================================================
|
||||||
|
r'from optimization_engine\.study_creator\b': 'from optimization_engine.study.creator',
|
||||||
|
r'from optimization_engine\.study_wizard\b': 'from optimization_engine.study.wizard',
|
||||||
|
r'from optimization_engine\.study_state\b': 'from optimization_engine.study.state',
|
||||||
|
r'from optimization_engine\.study_reset\b': 'from optimization_engine.study.reset',
|
||||||
|
r'from optimization_engine\.study_continuation\b': 'from optimization_engine.study.continuation',
|
||||||
|
r'from optimization_engine\.benchmarking_substudy\b': 'from optimization_engine.study.benchmarking',
|
||||||
|
r'from optimization_engine\.generate_history_from_trials\b': 'from optimization_engine.study.history_generator',
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# REPORTING MODULE
|
||||||
|
# =============================================================================
|
||||||
|
r'from optimization_engine\.generate_report\b': 'from optimization_engine.reporting.report_generator',
|
||||||
|
r'from optimization_engine\.generate_report_markdown\b': 'from optimization_engine.reporting.markdown_report',
|
||||||
|
r'from optimization_engine\.comprehensive_results_analyzer\b': 'from optimization_engine.reporting.results_analyzer',
|
||||||
|
r'from optimization_engine\.visualizer\b': 'from optimization_engine.reporting.visualizer',
|
||||||
|
r'from optimization_engine\.landscape_analyzer\b': 'from optimization_engine.reporting.landscape_analyzer',
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# CONFIG MODULE
|
||||||
|
# =============================================================================
|
||||||
|
r'from optimization_engine\.config_manager\b': 'from optimization_engine.config.manager',
|
||||||
|
r'from optimization_engine\.optimization_config_builder\b': 'from optimization_engine.config.builder',
|
||||||
|
r'from optimization_engine\.optimization_setup_wizard\b': 'from optimization_engine.config.setup_wizard',
|
||||||
|
r'from optimization_engine\.capability_matcher\b': 'from optimization_engine.config.capability_matcher',
|
||||||
|
r'from optimization_engine\.template_loader\b': 'from optimization_engine.config.template_loader',
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# UTILS MODULE
|
||||||
|
# =============================================================================
|
||||||
|
r'from optimization_engine\.logger\b': 'from optimization_engine.utils.logger',
|
||||||
|
r'from optimization_engine\.auto_doc\b': 'from optimization_engine.utils.auto_doc',
|
||||||
|
r'from optimization_engine\.realtime_tracking\b': 'from optimization_engine.utils.realtime_tracking',
|
||||||
|
r'from optimization_engine\.codebase_analyzer\b': 'from optimization_engine.utils.codebase_analyzer',
|
||||||
|
r'from optimization_engine\.pruning_logger\b': 'from optimization_engine.utils.pruning_logger',
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# FUTURE MODULE
|
||||||
|
# =============================================================================
|
||||||
|
r'from optimization_engine\.research_agent\b': 'from optimization_engine.future.research_agent',
|
||||||
|
r'from optimization_engine\.pynastran_research_agent\b': 'from optimization_engine.future.pynastran_research_agent',
|
||||||
|
r'from optimization_engine\.targeted_research_planner\b': 'from optimization_engine.future.targeted_research_planner',
|
||||||
|
r'from optimization_engine\.workflow_decomposer\b': 'from optimization_engine.future.workflow_decomposer',
|
||||||
|
r'from optimization_engine\.step_classifier\b': 'from optimization_engine.future.step_classifier',
|
||||||
|
r'from optimization_engine\.llm_optimization_runner\b': 'from optimization_engine.future.llm_optimization_runner',
|
||||||
|
r'from optimization_engine\.llm_workflow_analyzer\b': 'from optimization_engine.future.llm_workflow_analyzer',
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# EXTRACTORS/VALIDATORS additions
|
||||||
|
# =============================================================================
|
||||||
|
r'from optimization_engine\.op2_extractor\b': 'from optimization_engine.extractors.op2_extractor',
|
||||||
|
r'from optimization_engine\.extractor_library\b': 'from optimization_engine.extractors.extractor_library',
|
||||||
|
r'from optimization_engine\.simulation_validator\b': 'from optimization_engine.validators.simulation_validator',
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# PROCESSORS
|
||||||
|
# =============================================================================
|
||||||
|
r'from optimization_engine\.adaptive_characterization\b': 'from optimization_engine.processors.adaptive_characterization',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Also need to handle utils submodule imports that moved
|
||||||
|
UTILS_MAPPINGS = {
|
||||||
|
r'from optimization_engine\.utils\.nx_session_manager\b': 'from optimization_engine.nx.session_manager',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Combine all mappings
|
||||||
|
ALL_MAPPINGS = {**IMPORT_MAPPINGS, **UTILS_MAPPINGS}
|
||||||
|
|
||||||
|
def find_files(root: Path, extensions: List[str], exclude_dirs: List[str] = None) -> List[Path]:
|
||||||
|
"""Find all files with given extensions, excluding certain directories."""
|
||||||
|
if exclude_dirs is None:
|
||||||
|
exclude_dirs = ['optimization_engine_BACKUP', '.venv', 'node_modules', '__pycache__', '.git']
|
||||||
|
|
||||||
|
files = []
|
||||||
|
for ext in extensions:
|
||||||
|
for f in root.rglob(f'*{ext}'):
|
||||||
|
# Check if any excluded dir is in the path
|
||||||
|
if not any(excl in str(f) for excl in exclude_dirs):
|
||||||
|
files.append(f)
|
||||||
|
return files
|
||||||
|
|
||||||
|
def update_file(filepath: Path, mappings: Dict[str, str], dry_run: bool = True) -> Tuple[int, List[str]]:
|
||||||
|
"""Update imports in a single file."""
|
||||||
|
try:
|
||||||
|
content = filepath.read_text(encoding='utf-8', errors='ignore')
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ERROR reading {filepath}: {e}")
|
||||||
|
return 0, []
|
||||||
|
|
||||||
|
changes = []
|
||||||
|
new_content = content
|
||||||
|
|
||||||
|
for pattern, replacement in mappings.items():
|
||||||
|
matches = re.findall(pattern, content)
|
||||||
|
if matches:
|
||||||
|
new_content = re.sub(pattern, replacement, new_content)
|
||||||
|
changes.append(f" {pattern} -> {replacement} ({len(matches)} occurrences)")
|
||||||
|
|
||||||
|
if changes and not dry_run:
|
||||||
|
filepath.write_text(new_content, encoding='utf-8')
|
||||||
|
|
||||||
|
return len(changes), changes
|
||||||
|
|
||||||
|
def main():
|
||||||
|
dry_run = '--dry-run' in sys.argv or '--execute' not in sys.argv
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
print("=" * 60)
|
||||||
|
print("DRY RUN MODE - No files will be modified")
|
||||||
|
print("=" * 60)
|
||||||
|
else:
|
||||||
|
print("=" * 60)
|
||||||
|
print("EXECUTE MODE - Files will be modified!")
|
||||||
|
print("=" * 60)
|
||||||
|
confirm = input("Are you sure? (yes/no): ")
|
||||||
|
if confirm.lower() != 'yes':
|
||||||
|
print("Aborted.")
|
||||||
|
return
|
||||||
|
|
||||||
|
root = Path('.')
|
||||||
|
|
||||||
|
# Find all Python files
|
||||||
|
py_files = find_files(root, ['.py'])
|
||||||
|
print(f"\nFound {len(py_files)} Python files to check")
|
||||||
|
|
||||||
|
total_changes = 0
|
||||||
|
files_changed = 0
|
||||||
|
|
||||||
|
for filepath in sorted(py_files):
|
||||||
|
count, changes = update_file(filepath, ALL_MAPPINGS, dry_run)
|
||||||
|
if count > 0:
|
||||||
|
files_changed += 1
|
||||||
|
total_changes += count
|
||||||
|
print(f"\n{filepath} ({count} changes):")
|
||||||
|
for change in changes:
|
||||||
|
print(change)
|
||||||
|
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print(f"SUMMARY: {total_changes} changes in {files_changed} files")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
print("\nTo apply changes, run: python migrate_imports.py --execute")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -1,7 +1,165 @@
|
|||||||
"""
|
"""
|
||||||
Atomizer Optimization Engine
|
Atomizer Optimization Engine
|
||||||
|
============================
|
||||||
|
|
||||||
Core optimization logic with Optuna integration for NX Simcenter.
|
Structural optimization framework for Siemens NX.
|
||||||
|
|
||||||
|
New Module Structure (v2.0):
|
||||||
|
- core/ - Optimization runners
|
||||||
|
- processors/ - Data processing (surrogates, dynamic_response)
|
||||||
|
- nx/ - NX/Nastran integration
|
||||||
|
- study/ - Study management
|
||||||
|
- reporting/ - Reports and analysis
|
||||||
|
- config/ - Configuration
|
||||||
|
- extractors/ - Physics extraction (unchanged)
|
||||||
|
- insights/ - Visualizations (unchanged)
|
||||||
|
- gnn/ - Graph neural networks (unchanged)
|
||||||
|
- hooks/ - NX hooks (unchanged)
|
||||||
|
- utils/ - Utilities
|
||||||
|
- validators/ - Validation (unchanged)
|
||||||
|
|
||||||
|
Quick Start:
|
||||||
|
from optimization_engine.core import OptimizationRunner
|
||||||
|
from optimization_engine.nx import NXSolver
|
||||||
|
from optimization_engine.extractors import extract_displacement
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "0.1.0"
|
__version__ = '2.0.0'
|
||||||
|
|
||||||
|
import warnings as _warnings
|
||||||
|
import importlib as _importlib
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SUBMODULE LIST
|
||||||
|
# =============================================================================
|
||||||
|
_SUBMODULES = {
|
||||||
|
'core', 'processors', 'nx', 'study', 'reporting', 'config',
|
||||||
|
'extractors', 'insights', 'gnn', 'hooks', 'utils', 'validators',
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# BACKWARDS COMPATIBILITY LAYER
|
||||||
|
# =============================================================================
|
||||||
|
# These aliases allow old imports to work with deprecation warnings.
|
||||||
|
# Will be removed in v3.0.
|
||||||
|
|
||||||
|
_DEPRECATED_MAPPINGS = {
|
||||||
|
# Core
|
||||||
|
'runner': 'optimization_engine.core.runner',
|
||||||
|
'base_runner': 'optimization_engine.core.base_runner',
|
||||||
|
'intelligent_optimizer': 'optimization_engine.core.intelligent_optimizer',
|
||||||
|
'method_selector': 'optimization_engine.core.method_selector',
|
||||||
|
'strategy_selector': 'optimization_engine.core.strategy_selector',
|
||||||
|
'strategy_portfolio': 'optimization_engine.core.strategy_portfolio',
|
||||||
|
'gradient_optimizer': 'optimization_engine.core.gradient_optimizer',
|
||||||
|
'runner_with_neural': 'optimization_engine.core.runner_with_neural',
|
||||||
|
|
||||||
|
# Surrogates
|
||||||
|
'neural_surrogate': 'optimization_engine.processors.surrogates.neural_surrogate',
|
||||||
|
'generic_surrogate': 'optimization_engine.processors.surrogates.generic_surrogate',
|
||||||
|
'adaptive_surrogate': 'optimization_engine.processors.surrogates.adaptive_surrogate',
|
||||||
|
'simple_mlp_surrogate': 'optimization_engine.processors.surrogates.simple_mlp_surrogate',
|
||||||
|
'active_learning_surrogate': 'optimization_engine.processors.surrogates.active_learning_surrogate',
|
||||||
|
'surrogate_tuner': 'optimization_engine.processors.surrogates.surrogate_tuner',
|
||||||
|
'auto_trainer': 'optimization_engine.processors.surrogates.auto_trainer',
|
||||||
|
'training_data_exporter': 'optimization_engine.processors.surrogates.training_data_exporter',
|
||||||
|
|
||||||
|
# NX
|
||||||
|
'nx_solver': 'optimization_engine.nx.solver',
|
||||||
|
'nx_updater': 'optimization_engine.nx.updater',
|
||||||
|
'nx_session_manager': 'optimization_engine.nx.session_manager',
|
||||||
|
'solve_simulation': 'optimization_engine.nx.solve_simulation',
|
||||||
|
'solve_simulation_simple': 'optimization_engine.nx.solve_simulation_simple',
|
||||||
|
'model_cleanup': 'optimization_engine.nx.model_cleanup',
|
||||||
|
'export_expressions': 'optimization_engine.nx.export_expressions',
|
||||||
|
'import_expressions': 'optimization_engine.nx.import_expressions',
|
||||||
|
'mesh_converter': 'optimization_engine.nx.mesh_converter',
|
||||||
|
|
||||||
|
# Study
|
||||||
|
'study_creator': 'optimization_engine.study.creator',
|
||||||
|
'study_wizard': 'optimization_engine.study.wizard',
|
||||||
|
'study_state': 'optimization_engine.study.state',
|
||||||
|
'study_reset': 'optimization_engine.study.reset',
|
||||||
|
'study_continuation': 'optimization_engine.study.continuation',
|
||||||
|
'benchmarking_substudy': 'optimization_engine.study.benchmarking',
|
||||||
|
'generate_history_from_trials': 'optimization_engine.study.history_generator',
|
||||||
|
|
||||||
|
# Reporting
|
||||||
|
'generate_report': 'optimization_engine.reporting.report_generator',
|
||||||
|
'generate_report_markdown': 'optimization_engine.reporting.markdown_report',
|
||||||
|
'comprehensive_results_analyzer': 'optimization_engine.reporting.results_analyzer',
|
||||||
|
'visualizer': 'optimization_engine.reporting.visualizer',
|
||||||
|
'landscape_analyzer': 'optimization_engine.reporting.landscape_analyzer',
|
||||||
|
|
||||||
|
# Config
|
||||||
|
'config_manager': 'optimization_engine.config.manager',
|
||||||
|
'optimization_config_builder': 'optimization_engine.config.builder',
|
||||||
|
'optimization_setup_wizard': 'optimization_engine.config.setup_wizard',
|
||||||
|
'capability_matcher': 'optimization_engine.config.capability_matcher',
|
||||||
|
'template_loader': 'optimization_engine.config.template_loader',
|
||||||
|
|
||||||
|
# Utils
|
||||||
|
'logger': 'optimization_engine.utils.logger',
|
||||||
|
'auto_doc': 'optimization_engine.utils.auto_doc',
|
||||||
|
'realtime_tracking': 'optimization_engine.utils.realtime_tracking',
|
||||||
|
'codebase_analyzer': 'optimization_engine.utils.codebase_analyzer',
|
||||||
|
'pruning_logger': 'optimization_engine.utils.pruning_logger',
|
||||||
|
|
||||||
|
# Future
|
||||||
|
'research_agent': 'optimization_engine.future.research_agent',
|
||||||
|
'pynastran_research_agent': 'optimization_engine.future.pynastran_research_agent',
|
||||||
|
'targeted_research_planner': 'optimization_engine.future.targeted_research_planner',
|
||||||
|
'workflow_decomposer': 'optimization_engine.future.workflow_decomposer',
|
||||||
|
'step_classifier': 'optimization_engine.future.step_classifier',
|
||||||
|
|
||||||
|
# Extractors/Validators
|
||||||
|
'op2_extractor': 'optimization_engine.extractors.op2_extractor',
|
||||||
|
'extractor_library': 'optimization_engine.extractors.extractor_library',
|
||||||
|
'simulation_validator': 'optimization_engine.validators.simulation_validator',
|
||||||
|
|
||||||
|
# Processors
|
||||||
|
'adaptive_characterization': 'optimization_engine.processors.adaptive_characterization',
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# LAZY LOADING
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
def __getattr__(name):
|
||||||
|
"""Lazy import for submodules and backwards compatibility."""
|
||||||
|
# Handle submodule imports (e.g., from optimization_engine import core)
|
||||||
|
if name in _SUBMODULES:
|
||||||
|
return _importlib.import_module(f'optimization_engine.{name}')
|
||||||
|
|
||||||
|
# Handle deprecated imports with warnings
|
||||||
|
if name in _DEPRECATED_MAPPINGS:
|
||||||
|
new_module = _DEPRECATED_MAPPINGS[name]
|
||||||
|
_warnings.warn(
|
||||||
|
f"Importing '{name}' from optimization_engine is deprecated. "
|
||||||
|
f"Use '{new_module}' instead. "
|
||||||
|
f"This will be removed in v3.0.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2
|
||||||
|
)
|
||||||
|
return _importlib.import_module(new_module)
|
||||||
|
|
||||||
|
raise AttributeError(f"module 'optimization_engine' has no attribute '{name}'")
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
# Version
|
||||||
|
'__version__',
|
||||||
|
# Submodules
|
||||||
|
'core',
|
||||||
|
'processors',
|
||||||
|
'nx',
|
||||||
|
'study',
|
||||||
|
'reporting',
|
||||||
|
'config',
|
||||||
|
'extractors',
|
||||||
|
'insights',
|
||||||
|
'gnn',
|
||||||
|
'hooks',
|
||||||
|
'utils',
|
||||||
|
'validators',
|
||||||
|
]
|
||||||
|
|||||||
43
optimization_engine/config/__init__.py
Normal file
43
optimization_engine/config/__init__.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
"""
|
||||||
|
Configuration Management
|
||||||
|
========================
|
||||||
|
|
||||||
|
Configuration loading, validation, and building.
|
||||||
|
|
||||||
|
Modules:
|
||||||
|
- manager: ConfigManager for loading/saving configs
|
||||||
|
- builder: OptimizationConfigBuilder for creating configs
|
||||||
|
- setup_wizard: Interactive configuration setup
|
||||||
|
- capability_matcher: Match capabilities to requirements
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Lazy imports to avoid circular dependencies
|
||||||
|
def __getattr__(name):
|
||||||
|
if name == 'ConfigManager':
|
||||||
|
from .manager import ConfigManager
|
||||||
|
return ConfigManager
|
||||||
|
elif name == 'ConfigValidationError':
|
||||||
|
from .manager import ConfigValidationError
|
||||||
|
return ConfigValidationError
|
||||||
|
elif name == 'OptimizationConfigBuilder':
|
||||||
|
from .builder import OptimizationConfigBuilder
|
||||||
|
return OptimizationConfigBuilder
|
||||||
|
elif name == 'SetupWizard':
|
||||||
|
from .setup_wizard import SetupWizard
|
||||||
|
return SetupWizard
|
||||||
|
elif name == 'CapabilityMatcher':
|
||||||
|
from .capability_matcher import CapabilityMatcher
|
||||||
|
return CapabilityMatcher
|
||||||
|
elif name == 'TemplateLoader':
|
||||||
|
from .template_loader import TemplateLoader
|
||||||
|
return TemplateLoader
|
||||||
|
raise AttributeError(f"module 'optimization_engine.config' has no attribute '{name}'")
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'ConfigManager',
|
||||||
|
'ConfigValidationError',
|
||||||
|
'OptimizationConfigBuilder',
|
||||||
|
'SetupWizard',
|
||||||
|
'CapabilityMatcher',
|
||||||
|
'TemplateLoader',
|
||||||
|
]
|
||||||
@@ -12,8 +12,8 @@ Last Updated: 2025-01-16
|
|||||||
from typing import Dict, List, Any, Optional
|
from typing import Dict, List, Any, Optional
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from optimization_engine.workflow_decomposer import WorkflowStep
|
from optimization_engine.future.workflow_decomposer import WorkflowStep
|
||||||
from optimization_engine.codebase_analyzer import CodebaseCapabilityAnalyzer
|
from optimization_engine.utils.codebase_analyzer import CodebaseCapabilityAnalyzer
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -282,7 +282,7 @@ class CapabilityMatcher:
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Test the capability matcher."""
|
"""Test the capability matcher."""
|
||||||
from optimization_engine.workflow_decomposer import WorkflowDecomposer
|
from optimization_engine.future.workflow_decomposer import WorkflowDecomposer
|
||||||
|
|
||||||
print("Capability Matcher Test")
|
print("Capability Matcher Test")
|
||||||
print("=" * 80)
|
print("=" * 80)
|
||||||
@@ -5,7 +5,7 @@ ensuring consistency across all studies.
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
# In run_optimization.py
|
# In run_optimization.py
|
||||||
from optimization_engine.config_manager import ConfigManager
|
from optimization_engine.config.manager import ConfigManager
|
||||||
|
|
||||||
config_manager = ConfigManager(Path(__file__).parent / "1_setup" / "optimization_config.json")
|
config_manager = ConfigManager(Path(__file__).parent / "1_setup" / "optimization_config.json")
|
||||||
config_manager.load_config()
|
config_manager.load_config()
|
||||||
@@ -21,8 +21,8 @@ from typing import Dict, Any, List, Optional, Tuple
|
|||||||
import logging
|
import logging
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from optimization_engine.nx_updater import NXParameterUpdater
|
from optimization_engine.nx.updater import NXParameterUpdater
|
||||||
from optimization_engine.nx_solver import NXSolver
|
from optimization_engine.nx.solver import NXSolver
|
||||||
from optimization_engine.extractor_orchestrator import ExtractorOrchestrator
|
from optimization_engine.extractor_orchestrator import ExtractorOrchestrator
|
||||||
from optimization_engine.inline_code_generator import InlineCodeGenerator
|
from optimization_engine.inline_code_generator import InlineCodeGenerator
|
||||||
from optimization_engine.plugins.hook_manager import HookManager
|
from optimization_engine.plugins.hook_manager import HookManager
|
||||||
@@ -4,7 +4,7 @@ Template Loader for Atomizer Optimization Studies
|
|||||||
Creates new studies from templates with automatic folder structure creation.
|
Creates new studies from templates with automatic folder structure creation.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from optimization_engine.template_loader import create_study_from_template, list_templates
|
from optimization_engine.config.template_loader import create_study_from_template, list_templates
|
||||||
|
|
||||||
# List available templates
|
# List available templates
|
||||||
templates = list_templates()
|
templates = list_templates()
|
||||||
64
optimization_engine/core/__init__.py
Normal file
64
optimization_engine/core/__init__.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
"""
|
||||||
|
Optimization Engine Core
|
||||||
|
========================
|
||||||
|
|
||||||
|
Main optimization runners and algorithm selection.
|
||||||
|
|
||||||
|
Modules:
|
||||||
|
- runner: Main OptimizationRunner class
|
||||||
|
- base_runner: BaseRunner abstract class
|
||||||
|
- intelligent_optimizer: IMSO adaptive optimizer
|
||||||
|
- method_selector: Algorithm selection logic
|
||||||
|
- strategy_selector: Strategy portfolio management
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Lazy imports to avoid circular dependencies
|
||||||
|
def __getattr__(name):
|
||||||
|
if name == 'OptimizationRunner':
|
||||||
|
from .runner import OptimizationRunner
|
||||||
|
return OptimizationRunner
|
||||||
|
elif name == 'BaseRunner':
|
||||||
|
from .base_runner import BaseRunner
|
||||||
|
return BaseRunner
|
||||||
|
elif name == 'NeuralOptimizationRunner':
|
||||||
|
from .runner_with_neural import NeuralOptimizationRunner
|
||||||
|
return NeuralOptimizationRunner
|
||||||
|
elif name == 'IntelligentOptimizer':
|
||||||
|
from .intelligent_optimizer import IntelligentOptimizer
|
||||||
|
return IntelligentOptimizer
|
||||||
|
elif name == 'IMSO':
|
||||||
|
from .intelligent_optimizer import IMSO
|
||||||
|
return IMSO
|
||||||
|
elif name == 'MethodSelector':
|
||||||
|
from .method_selector import MethodSelector
|
||||||
|
return MethodSelector
|
||||||
|
elif name == 'select_method':
|
||||||
|
from .method_selector import select_method
|
||||||
|
return select_method
|
||||||
|
elif name == 'StrategySelector':
|
||||||
|
from .strategy_selector import StrategySelector
|
||||||
|
return StrategySelector
|
||||||
|
elif name == 'StrategyPortfolio':
|
||||||
|
from .strategy_portfolio import StrategyPortfolio
|
||||||
|
return StrategyPortfolio
|
||||||
|
elif name == 'GradientOptimizer':
|
||||||
|
from .gradient_optimizer import GradientOptimizer
|
||||||
|
return GradientOptimizer
|
||||||
|
elif name == 'LBFGSPolisher':
|
||||||
|
from .gradient_optimizer import LBFGSPolisher
|
||||||
|
return LBFGSPolisher
|
||||||
|
raise AttributeError(f"module 'optimization_engine.core' has no attribute '{name}'")
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'OptimizationRunner',
|
||||||
|
'BaseRunner',
|
||||||
|
'NeuralOptimizationRunner',
|
||||||
|
'IntelligentOptimizer',
|
||||||
|
'IMSO',
|
||||||
|
'MethodSelector',
|
||||||
|
'select_method',
|
||||||
|
'StrategySelector',
|
||||||
|
'StrategyPortfolio',
|
||||||
|
'GradientOptimizer',
|
||||||
|
'LBFGSPolisher',
|
||||||
|
]
|
||||||
@@ -6,13 +6,13 @@ by providing a config-driven optimization runner.
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
# In study's run_optimization.py (now ~50 lines instead of ~300):
|
# In study's run_optimization.py (now ~50 lines instead of ~300):
|
||||||
from optimization_engine.base_runner import ConfigDrivenRunner
|
from optimization_engine.core.base_runner import ConfigDrivenRunner
|
||||||
|
|
||||||
runner = ConfigDrivenRunner(__file__)
|
runner = ConfigDrivenRunner(__file__)
|
||||||
runner.run()
|
runner.run()
|
||||||
|
|
||||||
Or for custom extraction logic:
|
Or for custom extraction logic:
|
||||||
from optimization_engine.base_runner import BaseOptimizationRunner
|
from optimization_engine.core.base_runner import BaseOptimizationRunner
|
||||||
|
|
||||||
class MyStudyRunner(BaseOptimizationRunner):
|
class MyStudyRunner(BaseOptimizationRunner):
|
||||||
def extract_objectives(self, op2_file, dat_file, design_vars):
|
def extract_objectives(self, op2_file, dat_file, design_vars):
|
||||||
@@ -164,8 +164,8 @@ class BaseOptimizationRunner(ABC):
|
|||||||
if str(project_root) not in sys.path:
|
if str(project_root) not in sys.path:
|
||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
from optimization_engine.nx_solver import NXSolver
|
from optimization_engine.nx.solver import NXSolver
|
||||||
from optimization_engine.logger import get_logger
|
from optimization_engine.utils.logger import get_logger
|
||||||
|
|
||||||
self.results_dir.mkdir(exist_ok=True)
|
self.results_dir.mkdir(exist_ok=True)
|
||||||
self.logger = get_logger(self.study_name, study_dir=self.results_dir)
|
self.logger = get_logger(self.study_name, study_dir=self.results_dir)
|
||||||
@@ -10,8 +10,8 @@ Key Advantages over Derivative-Free Methods:
|
|||||||
- Can find precise local optima that sampling-based methods miss
|
- Can find precise local optima that sampling-based methods miss
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from optimization_engine.gradient_optimizer import GradientOptimizer
|
from optimization_engine.core.gradient_optimizer import GradientOptimizer
|
||||||
from optimization_engine.generic_surrogate import GenericSurrogate
|
from optimization_engine.processors.surrogates.generic_surrogate import GenericSurrogate
|
||||||
|
|
||||||
# Load trained surrogate
|
# Load trained surrogate
|
||||||
surrogate = GenericSurrogate(config)
|
surrogate = GenericSurrogate(config)
|
||||||
@@ -577,7 +577,7 @@ class MultiStartLBFGS:
|
|||||||
surrogate_path: Path to surrogate_best.pt
|
surrogate_path: Path to surrogate_best.pt
|
||||||
config: Optimization config dict
|
config: Optimization config dict
|
||||||
"""
|
"""
|
||||||
from optimization_engine.generic_surrogate import GenericSurrogate
|
from optimization_engine.processors.surrogates.generic_surrogate import GenericSurrogate
|
||||||
|
|
||||||
self.surrogate = GenericSurrogate(config)
|
self.surrogate = GenericSurrogate(config)
|
||||||
self.surrogate.load(surrogate_path)
|
self.surrogate.load(surrogate_path)
|
||||||
@@ -706,7 +706,7 @@ def run_lbfgs_polish(
|
|||||||
weights = [obj.get('weight', 1.0) for obj in config.get('objectives', [])]
|
weights = [obj.get('weight', 1.0) for obj in config.get('objectives', [])]
|
||||||
directions = [obj.get('direction', 'minimize') for obj in config.get('objectives', [])]
|
directions = [obj.get('direction', 'minimize') for obj in config.get('objectives', [])]
|
||||||
|
|
||||||
from optimization_engine.generic_surrogate import GenericSurrogate
|
from optimization_engine.processors.surrogates.generic_surrogate import GenericSurrogate
|
||||||
|
|
||||||
surrogate = GenericSurrogate(config)
|
surrogate = GenericSurrogate(config)
|
||||||
surrogate.load(surrogate_path)
|
surrogate.load(surrogate_path)
|
||||||
@@ -15,7 +15,7 @@ This module enables Atomizer to automatically adapt to different FEA problem
|
|||||||
types without requiring manual algorithm configuration.
|
types without requiring manual algorithm configuration.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from optimization_engine.intelligent_optimizer import IntelligentOptimizer
|
from optimization_engine.core.intelligent_optimizer import IntelligentOptimizer
|
||||||
|
|
||||||
optimizer = IntelligentOptimizer(
|
optimizer = IntelligentOptimizer(
|
||||||
study_name="my_study",
|
study_name="my_study",
|
||||||
@@ -35,18 +35,18 @@ from typing import Dict, Callable, Optional, Any
|
|||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from optimization_engine.landscape_analyzer import LandscapeAnalyzer, print_landscape_report
|
from optimization_engine.reporting.landscape_analyzer import LandscapeAnalyzer, print_landscape_report
|
||||||
from optimization_engine.strategy_selector import (
|
from optimization_engine.core.strategy_selector import (
|
||||||
IntelligentStrategySelector,
|
IntelligentStrategySelector,
|
||||||
create_sampler_from_config
|
create_sampler_from_config
|
||||||
)
|
)
|
||||||
from optimization_engine.strategy_portfolio import (
|
from optimization_engine.core.strategy_portfolio import (
|
||||||
StrategyTransitionManager,
|
StrategyTransitionManager,
|
||||||
AdaptiveStrategyCallback
|
AdaptiveStrategyCallback
|
||||||
)
|
)
|
||||||
from optimization_engine.adaptive_surrogate import AdaptiveExploitationCallback
|
from optimization_engine.processors.surrogates.adaptive_surrogate import AdaptiveExploitationCallback
|
||||||
from optimization_engine.adaptive_characterization import CharacterizationStoppingCriterion
|
from optimization_engine.processors.adaptive_characterization import CharacterizationStoppingCriterion
|
||||||
from optimization_engine.realtime_tracking import create_realtime_callback
|
from optimization_engine.utils.realtime_tracking import create_realtime_callback
|
||||||
|
|
||||||
|
|
||||||
class IntelligentOptimizer:
|
class IntelligentOptimizer:
|
||||||
@@ -13,7 +13,7 @@ Classes:
|
|||||||
- RuntimeAdvisor: Monitors optimization and suggests pivots
|
- RuntimeAdvisor: Monitors optimization and suggests pivots
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from optimization_engine.method_selector import AdaptiveMethodSelector
|
from optimization_engine.core.method_selector import AdaptiveMethodSelector
|
||||||
|
|
||||||
selector = AdaptiveMethodSelector()
|
selector = AdaptiveMethodSelector()
|
||||||
recommendation = selector.recommend(config_path)
|
recommendation = selector.recommend(config_path)
|
||||||
@@ -24,7 +24,7 @@ from datetime import datetime
|
|||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
from optimization_engine.plugins import HookManager
|
from optimization_engine.plugins import HookManager
|
||||||
from optimization_engine.training_data_exporter import create_exporter_from_config
|
from optimization_engine.processors.surrogates.training_data_exporter import create_exporter_from_config
|
||||||
|
|
||||||
|
|
||||||
class OptimizationRunner:
|
class OptimizationRunner:
|
||||||
@@ -733,7 +733,7 @@ class OptimizationRunner:
|
|||||||
if post_config.get('generate_plots', False):
|
if post_config.get('generate_plots', False):
|
||||||
print("\nGenerating visualization plots...")
|
print("\nGenerating visualization plots...")
|
||||||
try:
|
try:
|
||||||
from optimization_engine.visualizer import OptimizationVisualizer
|
from optimization_engine.reporting.visualizer import OptimizationVisualizer
|
||||||
|
|
||||||
formats = post_config.get('plot_formats', ['png', 'pdf'])
|
formats = post_config.get('plot_formats', ['png', 'pdf'])
|
||||||
visualizer = OptimizationVisualizer(self.output_dir)
|
visualizer = OptimizationVisualizer(self.output_dir)
|
||||||
@@ -752,7 +752,7 @@ class OptimizationRunner:
|
|||||||
if post_config.get('cleanup_models', False):
|
if post_config.get('cleanup_models', False):
|
||||||
print("\nCleaning up trial models...")
|
print("\nCleaning up trial models...")
|
||||||
try:
|
try:
|
||||||
from optimization_engine.model_cleanup import ModelCleanup
|
from optimization_engine.nx.model_cleanup import ModelCleanup
|
||||||
|
|
||||||
keep_n = post_config.get('keep_top_n_models', 10)
|
keep_n = post_config.get('keep_top_n_models', 10)
|
||||||
dry_run = post_config.get('cleanup_dry_run', False)
|
dry_run = post_config.get('cleanup_dry_run', False)
|
||||||
@@ -20,8 +20,8 @@ import numpy as np
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import optuna
|
import optuna
|
||||||
|
|
||||||
from optimization_engine.runner import OptimizationRunner
|
from optimization_engine.core.runner import OptimizationRunner
|
||||||
from optimization_engine.neural_surrogate import (
|
from optimization_engine.processors.surrogates.neural_surrogate import (
|
||||||
create_surrogate_from_config,
|
create_surrogate_from_config,
|
||||||
create_hybrid_optimizer_from_config,
|
create_hybrid_optimizer_from_config,
|
||||||
NeuralSurrogate,
|
NeuralSurrogate,
|
||||||
@@ -1,242 +1,278 @@
|
|||||||
"""
|
"""
|
||||||
Generic OP2 Extractor
|
Robust OP2 Extraction - Handles pyNastran FATAL flag issues gracefully.
|
||||||
====================
|
|
||||||
|
|
||||||
Reusable extractor for NX Nastran OP2 files using pyNastran.
|
This module provides a more robust OP2 extraction that:
|
||||||
Extracts mass properties, forces, displacements, stresses, etc.
|
1. Catches pyNastran FATAL flag exceptions
|
||||||
|
2. Checks if eigenvalues were actually extracted despite the flag
|
||||||
|
3. Falls back to F06 extraction if OP2 fails
|
||||||
|
4. Logs detailed failure information
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
extractor = OP2Extractor(op2_file="model.op2")
|
from optimization_engine.extractors.op2_extractor import robust_extract_first_frequency
|
||||||
mass = extractor.extract_mass()
|
|
||||||
forces = extractor.extract_grid_point_forces()
|
frequency = robust_extract_first_frequency(
|
||||||
|
op2_file=Path("results.op2"),
|
||||||
|
mode_number=1,
|
||||||
|
f06_file=Path("results.f06"), # Optional fallback
|
||||||
|
verbose=True
|
||||||
|
)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Any, Optional, List
|
from typing import Optional, Tuple
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
try:
|
|
||||||
from pyNastran.op2.op2 import read_op2
|
|
||||||
except ImportError:
|
|
||||||
raise ImportError("pyNastran is required. Install with: pip install pyNastran")
|
|
||||||
|
|
||||||
|
def robust_extract_first_frequency(
|
||||||
class OP2Extractor:
|
op2_file: Path,
|
||||||
"""
|
mode_number: int = 1,
|
||||||
Generic extractor for Nastran OP2 files.
|
f06_file: Optional[Path] = None,
|
||||||
|
verbose: bool = False
|
||||||
Supports:
|
|
||||||
- Mass properties
|
|
||||||
- Grid point forces
|
|
||||||
- Displacements
|
|
||||||
- Stresses
|
|
||||||
- Strains
|
|
||||||
- Element forces
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, op2_file: str):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
op2_file: Path to .op2 file
|
|
||||||
"""
|
|
||||||
self.op2_file = Path(op2_file)
|
|
||||||
self._op2_model = None
|
|
||||||
|
|
||||||
def _load_op2(self):
|
|
||||||
"""Lazy load OP2 file"""
|
|
||||||
if self._op2_model is None:
|
|
||||||
if not self.op2_file.exists():
|
|
||||||
raise FileNotFoundError(f"OP2 file not found: {self.op2_file}")
|
|
||||||
self._op2_model = read_op2(str(self.op2_file), debug=False)
|
|
||||||
return self._op2_model
|
|
||||||
|
|
||||||
def extract_mass(self, subcase_id: Optional[int] = None) -> Dict[str, Any]:
|
|
||||||
"""
|
|
||||||
Extract mass properties from OP2.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: {
|
|
||||||
'mass_kg': total mass in kg,
|
|
||||||
'mass_g': total mass in grams,
|
|
||||||
'cg': [x, y, z] center of gravity,
|
|
||||||
'inertia': 3x3 inertia matrix
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
op2 = self._load_op2()
|
|
||||||
|
|
||||||
# Get grid point weight (mass properties)
|
|
||||||
if not hasattr(op2, 'grid_point_weight') or not op2.grid_point_weight:
|
|
||||||
raise ValueError("No mass properties found in OP2 file")
|
|
||||||
|
|
||||||
gpw = op2.grid_point_weight
|
|
||||||
|
|
||||||
# Mass is typically in the first element of MO matrix (reference point mass)
|
|
||||||
# OP2 stores mass in ton, mm, sec units typically
|
|
||||||
mass_matrix = gpw.MO[0, 0] if hasattr(gpw, 'MO') else None
|
|
||||||
|
|
||||||
# Get reference point
|
|
||||||
if hasattr(gpw, 'reference_point') and gpw.reference_point:
|
|
||||||
ref_point = gpw.reference_point
|
|
||||||
else:
|
|
||||||
ref_point = 0
|
|
||||||
|
|
||||||
# Extract mass (convert based on units)
|
|
||||||
# Nastran default: ton-mm-sec → need to convert to kg
|
|
||||||
if mass_matrix is not None:
|
|
||||||
mass_ton = mass_matrix
|
|
||||||
mass_kg = mass_ton * 1000.0 # 1 ton = 1000 kg
|
|
||||||
else:
|
|
||||||
raise ValueError("Could not extract mass from OP2")
|
|
||||||
|
|
||||||
# Extract CG if available
|
|
||||||
cg = [0.0, 0.0, 0.0]
|
|
||||||
if hasattr(gpw, 'cg'):
|
|
||||||
cg = gpw.cg.tolist() if hasattr(gpw.cg, 'tolist') else list(gpw.cg)
|
|
||||||
|
|
||||||
return {
|
|
||||||
'mass_kg': mass_kg,
|
|
||||||
'mass_g': mass_kg * 1000.0,
|
|
||||||
'mass_ton': mass_ton,
|
|
||||||
'cg': cg,
|
|
||||||
'reference_point': ref_point,
|
|
||||||
'units': 'ton-mm-sec (converted to kg)',
|
|
||||||
}
|
|
||||||
|
|
||||||
def extract_grid_point_forces(
|
|
||||||
self,
|
|
||||||
subcase_id: Optional[int] = None,
|
|
||||||
component: str = "total" # total, fx, fy, fz, mx, my, mz
|
|
||||||
) -> Dict[str, Any]:
|
|
||||||
"""
|
|
||||||
Extract grid point forces from OP2.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
subcase_id: Subcase ID (if None, uses first available)
|
|
||||||
component: Force component to extract
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: {
|
|
||||||
'force': resultant force value,
|
|
||||||
'all_forces': list of forces at each grid point,
|
|
||||||
'max_force': maximum force,
|
|
||||||
'total_force': sum of all forces
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
op2 = self._load_op2()
|
|
||||||
|
|
||||||
if not hasattr(op2, 'grid_point_forces') or not op2.grid_point_forces:
|
|
||||||
raise ValueError("No grid point forces found in OP2 file")
|
|
||||||
|
|
||||||
# Get first subcase if not specified
|
|
||||||
if subcase_id is None:
|
|
||||||
subcase_id = list(op2.grid_point_forces.keys())[0]
|
|
||||||
|
|
||||||
gpf = op2.grid_point_forces[subcase_id]
|
|
||||||
|
|
||||||
# Extract forces based on component
|
|
||||||
# Grid point forces table typically has columns: fx, fy, fz, mx, my, mz
|
|
||||||
if component == "total":
|
|
||||||
# Calculate resultant force: sqrt(fx^2 + fy^2 + fz^2)
|
|
||||||
forces = np.sqrt(gpf.data[:, 0]**2 + gpf.data[:, 1]**2 + gpf.data[:, 2]**2)
|
|
||||||
elif component == "fx":
|
|
||||||
forces = gpf.data[:, 0]
|
|
||||||
elif component == "fy":
|
|
||||||
forces = gpf.data[:, 1]
|
|
||||||
elif component == "fz":
|
|
||||||
forces = gpf.data[:, 2]
|
|
||||||
else:
|
|
||||||
raise ValueError(f"Unknown component: {component}")
|
|
||||||
|
|
||||||
return {
|
|
||||||
'force': float(np.max(np.abs(forces))),
|
|
||||||
'all_forces': forces.tolist(),
|
|
||||||
'max_force': float(np.max(forces)),
|
|
||||||
'min_force': float(np.min(forces)),
|
|
||||||
'total_force': float(np.sum(forces)),
|
|
||||||
'component': component,
|
|
||||||
'subcase_id': subcase_id,
|
|
||||||
}
|
|
||||||
|
|
||||||
def extract_applied_loads(self, subcase_id: Optional[int] = None) -> Dict[str, Any]:
|
|
||||||
"""
|
|
||||||
Extract applied loads from OP2 file.
|
|
||||||
|
|
||||||
This attempts to get load vector information if available.
|
|
||||||
Note: Not all OP2 files contain this data.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: Load information
|
|
||||||
"""
|
|
||||||
op2 = self._load_op2()
|
|
||||||
|
|
||||||
# Try to get load vectors
|
|
||||||
if hasattr(op2, 'load_vectors') and op2.load_vectors:
|
|
||||||
if subcase_id is None:
|
|
||||||
subcase_id = list(op2.load_vectors.keys())[0]
|
|
||||||
|
|
||||||
lv = op2.load_vectors[subcase_id]
|
|
||||||
loads = lv.data
|
|
||||||
|
|
||||||
return {
|
|
||||||
'total_load': float(np.sum(np.abs(loads))),
|
|
||||||
'max_load': float(np.max(np.abs(loads))),
|
|
||||||
'load_resultant': float(np.linalg.norm(loads)),
|
|
||||||
'subcase_id': subcase_id,
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
# Fallback: use grid point forces as approximation
|
|
||||||
return self.extract_grid_point_forces(subcase_id)
|
|
||||||
|
|
||||||
|
|
||||||
def extract_mass_from_op2(op2_file: str) -> float:
|
|
||||||
"""
|
|
||||||
Convenience function to extract mass in kg.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
op2_file: Path to .op2 file
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Mass in kilograms
|
|
||||||
"""
|
|
||||||
extractor = OP2Extractor(op2_file)
|
|
||||||
result = extractor.extract_mass()
|
|
||||||
return result['mass_kg']
|
|
||||||
|
|
||||||
|
|
||||||
def extract_force_from_op2(
|
|
||||||
op2_file: str,
|
|
||||||
component: str = "fz"
|
|
||||||
) -> float:
|
) -> float:
|
||||||
"""
|
"""
|
||||||
Convenience function to extract force component.
|
Robustly extract natural frequency from OP2 file, handling pyNastran issues.
|
||||||
|
|
||||||
|
This function attempts multiple strategies:
|
||||||
|
1. Standard pyNastran OP2 reading
|
||||||
|
2. Force reading with debug=False to ignore FATAL flags
|
||||||
|
3. Partial OP2 reading (extract eigenvalues even if FATAL flag exists)
|
||||||
|
4. Fallback to F06 file parsing (if provided)
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
op2_file: Path to .op2 file
|
op2_file: Path to OP2 output file
|
||||||
component: Force component (fx, fy, fz, or total)
|
mode_number: Mode number to extract (1-based index)
|
||||||
|
f06_file: Optional F06 file for fallback extraction
|
||||||
|
verbose: Print detailed extraction information
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Force value
|
Natural frequency in Hz
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If frequency cannot be extracted by any method
|
||||||
"""
|
"""
|
||||||
extractor = OP2Extractor(op2_file)
|
from pyNastran.op2.op2 import OP2
|
||||||
result = extractor.extract_grid_point_forces(component=component)
|
|
||||||
return result['force']
|
if not op2_file.exists():
|
||||||
|
raise FileNotFoundError(f"OP2 file not found: {op2_file}")
|
||||||
|
|
||||||
|
# Strategy 1: Try standard OP2 reading
|
||||||
|
try:
|
||||||
|
if verbose:
|
||||||
|
print(f"[OP2 EXTRACT] Attempting standard read: {op2_file.name}")
|
||||||
|
|
||||||
|
model = OP2()
|
||||||
|
model.read_op2(str(op2_file))
|
||||||
|
|
||||||
|
if hasattr(model, 'eigenvalues') and len(model.eigenvalues) > 0:
|
||||||
|
frequency = _extract_frequency_from_model(model, mode_number)
|
||||||
|
if verbose:
|
||||||
|
print(f"[OP2 EXTRACT] ✓ Success (standard read): {frequency:.6f} Hz")
|
||||||
|
return frequency
|
||||||
|
else:
|
||||||
|
raise ValueError("No eigenvalues found in OP2 file")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
if verbose:
|
||||||
|
print(f"[OP2 EXTRACT] ✗ Standard read failed: {str(e)[:100]}")
|
||||||
|
|
||||||
|
# Check if this is a FATAL flag issue
|
||||||
|
is_fatal_flag = 'FATAL' in str(e) and 'op2_reader' in str(e.__class__.__module__)
|
||||||
|
|
||||||
|
if is_fatal_flag:
|
||||||
|
# Strategy 2: Try reading with more lenient settings
|
||||||
|
if verbose:
|
||||||
|
print(f"[OP2 EXTRACT] Detected pyNastran FATAL flag issue")
|
||||||
|
print(f"[OP2 EXTRACT] Attempting partial extraction...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
model = OP2()
|
||||||
|
# Try to read with debug=False and skip_undefined_matrices=True
|
||||||
|
model.read_op2(
|
||||||
|
str(op2_file),
|
||||||
|
debug=False,
|
||||||
|
skip_undefined_matrices=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if eigenvalues were extracted despite FATAL
|
||||||
|
if hasattr(model, 'eigenvalues') and len(model.eigenvalues) > 0:
|
||||||
|
frequency = _extract_frequency_from_model(model, mode_number)
|
||||||
|
if verbose:
|
||||||
|
print(f"[OP2 EXTRACT] ✓ Success (lenient mode): {frequency:.6f} Hz")
|
||||||
|
print(f"[OP2 EXTRACT] Note: pyNastran reported FATAL but data is valid!")
|
||||||
|
return frequency
|
||||||
|
|
||||||
|
except Exception as e2:
|
||||||
|
if verbose:
|
||||||
|
print(f"[OP2 EXTRACT] ✗ Lenient read also failed: {str(e2)[:100]}")
|
||||||
|
|
||||||
|
# Strategy 3: Fallback to F06 parsing
|
||||||
|
if f06_file and f06_file.exists():
|
||||||
|
if verbose:
|
||||||
|
print(f"[OP2 EXTRACT] Falling back to F06 extraction: {f06_file.name}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
frequency = extract_frequency_from_f06(f06_file, mode_number, verbose=verbose)
|
||||||
|
if verbose:
|
||||||
|
print(f"[OP2 EXTRACT] ✓ Success (F06 fallback): {frequency:.6f} Hz")
|
||||||
|
return frequency
|
||||||
|
|
||||||
|
except Exception as e3:
|
||||||
|
if verbose:
|
||||||
|
print(f"[OP2 EXTRACT] ✗ F06 extraction failed: {str(e3)}")
|
||||||
|
|
||||||
|
# All strategies failed
|
||||||
|
raise ValueError(
|
||||||
|
f"Could not extract frequency from OP2 file: {op2_file.name}. "
|
||||||
|
f"Original error: {str(e)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
def _extract_frequency_from_model(model, mode_number: int) -> float:
|
||||||
# Example usage
|
"""Extract frequency from loaded OP2 model."""
|
||||||
import sys
|
if not hasattr(model, 'eigenvalues') or len(model.eigenvalues) == 0:
|
||||||
if len(sys.argv) > 1:
|
raise ValueError("No eigenvalues found in model")
|
||||||
op2_file = sys.argv[1]
|
|
||||||
extractor = OP2Extractor(op2_file)
|
|
||||||
|
|
||||||
# Extract mass
|
# Get first subcase
|
||||||
mass_result = extractor.extract_mass()
|
subcase = list(model.eigenvalues.keys())[0]
|
||||||
print(f"Mass: {mass_result['mass_kg']:.6f} kg")
|
eig_obj = model.eigenvalues[subcase]
|
||||||
print(f"CG: {mass_result['cg']}")
|
|
||||||
|
|
||||||
# Extract forces
|
# Check if mode exists
|
||||||
try:
|
if mode_number > len(eig_obj.eigenvalues):
|
||||||
force_result = extractor.extract_grid_point_forces(component="fz")
|
raise ValueError(
|
||||||
print(f"Max Fz: {force_result['force']:.2f} N")
|
f"Mode {mode_number} not found. "
|
||||||
except ValueError as e:
|
f"Only {len(eig_obj.eigenvalues)} modes available"
|
||||||
print(f"Forces not available: {e}")
|
)
|
||||||
|
|
||||||
|
# Extract eigenvalue and convert to frequency
|
||||||
|
eigenvalue = eig_obj.eigenvalues[mode_number - 1]
|
||||||
|
angular_freq = np.sqrt(abs(eigenvalue)) # Use abs to handle numerical precision issues
|
||||||
|
frequency_hz = angular_freq / (2 * np.pi)
|
||||||
|
|
||||||
|
return float(frequency_hz)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_frequency_from_f06(
|
||||||
|
f06_file: Path,
|
||||||
|
mode_number: int = 1,
|
||||||
|
verbose: bool = False
|
||||||
|
) -> float:
|
||||||
|
"""
|
||||||
|
Extract natural frequency from F06 text file (fallback method).
|
||||||
|
|
||||||
|
Parses the F06 file to find eigenvalue results table and extracts frequency.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
f06_file: Path to F06 output file
|
||||||
|
mode_number: Mode number to extract (1-based index)
|
||||||
|
verbose: Print extraction details
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Natural frequency in Hz
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If frequency cannot be found in F06
|
||||||
|
"""
|
||||||
|
if not f06_file.exists():
|
||||||
|
raise FileNotFoundError(f"F06 file not found: {f06_file}")
|
||||||
|
|
||||||
|
with open(f06_file, 'r', encoding='latin-1', errors='ignore') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# Look for eigenvalue table
|
||||||
|
# Nastran F06 format has eigenvalue results like:
|
||||||
|
# R E A L E I G E N V A L U E S
|
||||||
|
# MODE EXTRACTION EIGENVALUE RADIANS CYCLES GENERALIZED GENERALIZED
|
||||||
|
# NO. ORDER MASS STIFFNESS
|
||||||
|
# 1 1 -6.602743E+04 2.569656E+02 4.089338E+01 1.000000E+00 6.602743E+04
|
||||||
|
|
||||||
|
lines = content.split('\n')
|
||||||
|
|
||||||
|
# Find eigenvalue table
|
||||||
|
eigenvalue_section_start = None
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if 'R E A L E I G E N V A L U E S' in line:
|
||||||
|
eigenvalue_section_start = i
|
||||||
|
break
|
||||||
|
|
||||||
|
if eigenvalue_section_start is None:
|
||||||
|
raise ValueError("Eigenvalue table not found in F06 file")
|
||||||
|
|
||||||
|
# Parse eigenvalue table (starts a few lines after header)
|
||||||
|
for i in range(eigenvalue_section_start + 3, min(eigenvalue_section_start + 100, len(lines))):
|
||||||
|
line = lines[i].strip()
|
||||||
|
|
||||||
|
if not line or line.startswith('1'): # Page break
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Parse line with mode data
|
||||||
|
parts = line.split()
|
||||||
|
if len(parts) >= 5:
|
||||||
|
try:
|
||||||
|
mode_num = int(parts[0])
|
||||||
|
if mode_num == mode_number:
|
||||||
|
# Frequency is in column 5 (CYCLES)
|
||||||
|
frequency = float(parts[4])
|
||||||
|
if verbose:
|
||||||
|
print(f"[F06 EXTRACT] Found mode {mode_num}: {frequency:.6f} Hz")
|
||||||
|
return frequency
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
raise ValueError(f"Mode {mode_number} not found in F06 eigenvalue table")
|
||||||
|
|
||||||
|
|
||||||
|
def validate_op2_file(op2_file: Path, f06_file: Optional[Path] = None) -> Tuple[bool, str]:
|
||||||
|
"""
|
||||||
|
Validate if an OP2 file contains usable eigenvalue data.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
op2_file: Path to OP2 file
|
||||||
|
f06_file: Optional F06 file for cross-reference
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(is_valid, message): Tuple of validation status and explanation
|
||||||
|
"""
|
||||||
|
if not op2_file.exists():
|
||||||
|
return False, f"OP2 file does not exist: {op2_file}"
|
||||||
|
|
||||||
|
if op2_file.stat().st_size == 0:
|
||||||
|
return False, "OP2 file is empty"
|
||||||
|
|
||||||
|
# Try to extract first frequency
|
||||||
|
try:
|
||||||
|
frequency = robust_extract_first_frequency(
|
||||||
|
op2_file,
|
||||||
|
mode_number=1,
|
||||||
|
f06_file=f06_file,
|
||||||
|
verbose=False
|
||||||
|
)
|
||||||
|
return True, f"Valid OP2 file (first frequency: {frequency:.6f} Hz)"
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return False, f"Cannot extract data from OP2: {str(e)}"
|
||||||
|
|
||||||
|
|
||||||
|
# Convenience function (same signature as old function for backward compatibility)
|
||||||
|
def extract_first_frequency(op2_file: Path, mode_number: int = 1) -> float:
|
||||||
|
"""
|
||||||
|
Extract first natural frequency (backward compatible with old function).
|
||||||
|
|
||||||
|
This is the simple version - just use robust_extract_first_frequency directly
|
||||||
|
for more control.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
op2_file: Path to OP2 file
|
||||||
|
mode_number: Mode number (1-based)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Frequency in Hz
|
||||||
|
"""
|
||||||
|
# Try to find F06 file in same directory
|
||||||
|
f06_file = op2_file.with_suffix('.f06')
|
||||||
|
|
||||||
|
return robust_extract_first_frequency(
|
||||||
|
op2_file,
|
||||||
|
mode_number=mode_number,
|
||||||
|
f06_file=f06_file if f06_file.exists() else None,
|
||||||
|
verbose=False
|
||||||
|
)
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import importlib.util
|
|||||||
import logging
|
import logging
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from optimization_engine.pynastran_research_agent import PyNastranResearchAgent, ExtractionPattern
|
from optimization_engine.future.pynastran_research_agent import PyNastranResearchAgent, ExtractionPattern
|
||||||
from optimization_engine.extractor_library import ExtractorLibrary, create_study_manifest
|
from optimization_engine.extractors.extractor_library import ExtractorLibrary, create_study_manifest
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ class StepClassifier:
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Test the step classifier."""
|
"""Test the step classifier."""
|
||||||
from optimization_engine.workflow_decomposer import WorkflowDecomposer
|
from optimization_engine.future.workflow_decomposer import WorkflowDecomposer
|
||||||
|
|
||||||
print("Step Classifier Test")
|
print("Step Classifier Test")
|
||||||
print("=" * 80)
|
print("=" * 80)
|
||||||
@@ -12,7 +12,7 @@ Last Updated: 2025-01-16
|
|||||||
from typing import List, Dict, Any
|
from typing import List, Dict, Any
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from optimization_engine.capability_matcher import CapabilityMatch, StepMatch
|
from optimization_engine.config.capability_matcher import CapabilityMatch, StepMatch
|
||||||
|
|
||||||
|
|
||||||
class TargetedResearchPlanner:
|
class TargetedResearchPlanner:
|
||||||
@@ -188,9 +188,9 @@ class TargetedResearchPlanner:
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Test the targeted research planner."""
|
"""Test the targeted research planner."""
|
||||||
from optimization_engine.codebase_analyzer import CodebaseCapabilityAnalyzer
|
from optimization_engine.utils.codebase_analyzer import CodebaseCapabilityAnalyzer
|
||||||
from optimization_engine.workflow_decomposer import WorkflowDecomposer
|
from optimization_engine.future.workflow_decomposer import WorkflowDecomposer
|
||||||
from optimization_engine.capability_matcher import CapabilityMatcher
|
from optimization_engine.config.capability_matcher import CapabilityMatcher
|
||||||
|
|
||||||
print("Targeted Research Planner Test")
|
print("Targeted Research Planner Test")
|
||||||
print("=" * 80)
|
print("=" * 80)
|
||||||
@@ -415,7 +415,7 @@ class ZernikeGNNOptimizer:
|
|||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
import re
|
import re
|
||||||
from optimization_engine.nx_solver import NXSolver
|
from optimization_engine.nx.solver import NXSolver
|
||||||
from optimization_engine.extractors import ZernikeExtractor
|
from optimization_engine.extractors import ZernikeExtractor
|
||||||
|
|
||||||
study_dir = Path(study_dir)
|
study_dir = Path(study_dir)
|
||||||
|
|||||||
51
optimization_engine/nx/__init__.py
Normal file
51
optimization_engine/nx/__init__.py
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
"""
|
||||||
|
NX Integration
|
||||||
|
==============
|
||||||
|
|
||||||
|
Siemens NX and Nastran integration modules.
|
||||||
|
|
||||||
|
Modules:
|
||||||
|
- solver: NXSolver for running simulations
|
||||||
|
- updater: NXParameterUpdater for design updates
|
||||||
|
- session_manager: NX session lifecycle management
|
||||||
|
- solve_simulation: Low-level simulation execution
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Lazy imports to avoid import errors when NX modules aren't available
|
||||||
|
def __getattr__(name):
|
||||||
|
if name == 'NXSolver':
|
||||||
|
from .solver import NXSolver
|
||||||
|
return NXSolver
|
||||||
|
elif name == 'run_nx_simulation':
|
||||||
|
from .solver import run_nx_simulation
|
||||||
|
return run_nx_simulation
|
||||||
|
elif name == 'NXParameterUpdater':
|
||||||
|
from .updater import NXParameterUpdater
|
||||||
|
return NXParameterUpdater
|
||||||
|
elif name == 'update_nx_model':
|
||||||
|
from .updater import update_nx_model
|
||||||
|
return update_nx_model
|
||||||
|
elif name == 'NXSessionManager':
|
||||||
|
from .session_manager import NXSessionManager
|
||||||
|
return NXSessionManager
|
||||||
|
elif name == 'NXSessionInfo':
|
||||||
|
from .session_manager import NXSessionInfo
|
||||||
|
return NXSessionInfo
|
||||||
|
elif name == 'ModelCleanup':
|
||||||
|
from .model_cleanup import ModelCleanup
|
||||||
|
return ModelCleanup
|
||||||
|
elif name == 'cleanup_substudy':
|
||||||
|
from .model_cleanup import cleanup_substudy
|
||||||
|
return cleanup_substudy
|
||||||
|
raise AttributeError(f"module 'optimization_engine.nx' has no attribute '{name}'")
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'NXSolver',
|
||||||
|
'run_nx_simulation',
|
||||||
|
'NXParameterUpdater',
|
||||||
|
'update_nx_model',
|
||||||
|
'NXSessionManager',
|
||||||
|
'NXSessionInfo',
|
||||||
|
'ModelCleanup',
|
||||||
|
'cleanup_substudy',
|
||||||
|
]
|
||||||
@@ -11,7 +11,7 @@ import subprocess
|
|||||||
import time
|
import time
|
||||||
import shutil
|
import shutil
|
||||||
import os
|
import os
|
||||||
from optimization_engine.nx_session_manager import NXSessionManager
|
from optimization_engine.nx.session_manager import NXSessionManager
|
||||||
|
|
||||||
|
|
||||||
class NXSolver:
|
class NXSolver:
|
||||||
@@ -1,278 +0,0 @@
|
|||||||
"""
|
|
||||||
Robust OP2 Extraction - Handles pyNastran FATAL flag issues gracefully.
|
|
||||||
|
|
||||||
This module provides a more robust OP2 extraction that:
|
|
||||||
1. Catches pyNastran FATAL flag exceptions
|
|
||||||
2. Checks if eigenvalues were actually extracted despite the flag
|
|
||||||
3. Falls back to F06 extraction if OP2 fails
|
|
||||||
4. Logs detailed failure information
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
from optimization_engine.op2_extractor import robust_extract_first_frequency
|
|
||||||
|
|
||||||
frequency = robust_extract_first_frequency(
|
|
||||||
op2_file=Path("results.op2"),
|
|
||||||
mode_number=1,
|
|
||||||
f06_file=Path("results.f06"), # Optional fallback
|
|
||||||
verbose=True
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Optional, Tuple
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
|
|
||||||
def robust_extract_first_frequency(
|
|
||||||
op2_file: Path,
|
|
||||||
mode_number: int = 1,
|
|
||||||
f06_file: Optional[Path] = None,
|
|
||||||
verbose: bool = False
|
|
||||||
) -> float:
|
|
||||||
"""
|
|
||||||
Robustly extract natural frequency from OP2 file, handling pyNastran issues.
|
|
||||||
|
|
||||||
This function attempts multiple strategies:
|
|
||||||
1. Standard pyNastran OP2 reading
|
|
||||||
2. Force reading with debug=False to ignore FATAL flags
|
|
||||||
3. Partial OP2 reading (extract eigenvalues even if FATAL flag exists)
|
|
||||||
4. Fallback to F06 file parsing (if provided)
|
|
||||||
|
|
||||||
Args:
|
|
||||||
op2_file: Path to OP2 output file
|
|
||||||
mode_number: Mode number to extract (1-based index)
|
|
||||||
f06_file: Optional F06 file for fallback extraction
|
|
||||||
verbose: Print detailed extraction information
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Natural frequency in Hz
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: If frequency cannot be extracted by any method
|
|
||||||
"""
|
|
||||||
from pyNastran.op2.op2 import OP2
|
|
||||||
|
|
||||||
if not op2_file.exists():
|
|
||||||
raise FileNotFoundError(f"OP2 file not found: {op2_file}")
|
|
||||||
|
|
||||||
# Strategy 1: Try standard OP2 reading
|
|
||||||
try:
|
|
||||||
if verbose:
|
|
||||||
print(f"[OP2 EXTRACT] Attempting standard read: {op2_file.name}")
|
|
||||||
|
|
||||||
model = OP2()
|
|
||||||
model.read_op2(str(op2_file))
|
|
||||||
|
|
||||||
if hasattr(model, 'eigenvalues') and len(model.eigenvalues) > 0:
|
|
||||||
frequency = _extract_frequency_from_model(model, mode_number)
|
|
||||||
if verbose:
|
|
||||||
print(f"[OP2 EXTRACT] ✓ Success (standard read): {frequency:.6f} Hz")
|
|
||||||
return frequency
|
|
||||||
else:
|
|
||||||
raise ValueError("No eigenvalues found in OP2 file")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
if verbose:
|
|
||||||
print(f"[OP2 EXTRACT] ✗ Standard read failed: {str(e)[:100]}")
|
|
||||||
|
|
||||||
# Check if this is a FATAL flag issue
|
|
||||||
is_fatal_flag = 'FATAL' in str(e) and 'op2_reader' in str(e.__class__.__module__)
|
|
||||||
|
|
||||||
if is_fatal_flag:
|
|
||||||
# Strategy 2: Try reading with more lenient settings
|
|
||||||
if verbose:
|
|
||||||
print(f"[OP2 EXTRACT] Detected pyNastran FATAL flag issue")
|
|
||||||
print(f"[OP2 EXTRACT] Attempting partial extraction...")
|
|
||||||
|
|
||||||
try:
|
|
||||||
model = OP2()
|
|
||||||
# Try to read with debug=False and skip_undefined_matrices=True
|
|
||||||
model.read_op2(
|
|
||||||
str(op2_file),
|
|
||||||
debug=False,
|
|
||||||
skip_undefined_matrices=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check if eigenvalues were extracted despite FATAL
|
|
||||||
if hasattr(model, 'eigenvalues') and len(model.eigenvalues) > 0:
|
|
||||||
frequency = _extract_frequency_from_model(model, mode_number)
|
|
||||||
if verbose:
|
|
||||||
print(f"[OP2 EXTRACT] ✓ Success (lenient mode): {frequency:.6f} Hz")
|
|
||||||
print(f"[OP2 EXTRACT] Note: pyNastran reported FATAL but data is valid!")
|
|
||||||
return frequency
|
|
||||||
|
|
||||||
except Exception as e2:
|
|
||||||
if verbose:
|
|
||||||
print(f"[OP2 EXTRACT] ✗ Lenient read also failed: {str(e2)[:100]}")
|
|
||||||
|
|
||||||
# Strategy 3: Fallback to F06 parsing
|
|
||||||
if f06_file and f06_file.exists():
|
|
||||||
if verbose:
|
|
||||||
print(f"[OP2 EXTRACT] Falling back to F06 extraction: {f06_file.name}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
frequency = extract_frequency_from_f06(f06_file, mode_number, verbose=verbose)
|
|
||||||
if verbose:
|
|
||||||
print(f"[OP2 EXTRACT] ✓ Success (F06 fallback): {frequency:.6f} Hz")
|
|
||||||
return frequency
|
|
||||||
|
|
||||||
except Exception as e3:
|
|
||||||
if verbose:
|
|
||||||
print(f"[OP2 EXTRACT] ✗ F06 extraction failed: {str(e3)}")
|
|
||||||
|
|
||||||
# All strategies failed
|
|
||||||
raise ValueError(
|
|
||||||
f"Could not extract frequency from OP2 file: {op2_file.name}. "
|
|
||||||
f"Original error: {str(e)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _extract_frequency_from_model(model, mode_number: int) -> float:
|
|
||||||
"""Extract frequency from loaded OP2 model."""
|
|
||||||
if not hasattr(model, 'eigenvalues') or len(model.eigenvalues) == 0:
|
|
||||||
raise ValueError("No eigenvalues found in model")
|
|
||||||
|
|
||||||
# Get first subcase
|
|
||||||
subcase = list(model.eigenvalues.keys())[0]
|
|
||||||
eig_obj = model.eigenvalues[subcase]
|
|
||||||
|
|
||||||
# Check if mode exists
|
|
||||||
if mode_number > len(eig_obj.eigenvalues):
|
|
||||||
raise ValueError(
|
|
||||||
f"Mode {mode_number} not found. "
|
|
||||||
f"Only {len(eig_obj.eigenvalues)} modes available"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Extract eigenvalue and convert to frequency
|
|
||||||
eigenvalue = eig_obj.eigenvalues[mode_number - 1]
|
|
||||||
angular_freq = np.sqrt(abs(eigenvalue)) # Use abs to handle numerical precision issues
|
|
||||||
frequency_hz = angular_freq / (2 * np.pi)
|
|
||||||
|
|
||||||
return float(frequency_hz)
|
|
||||||
|
|
||||||
|
|
||||||
def extract_frequency_from_f06(
|
|
||||||
f06_file: Path,
|
|
||||||
mode_number: int = 1,
|
|
||||||
verbose: bool = False
|
|
||||||
) -> float:
|
|
||||||
"""
|
|
||||||
Extract natural frequency from F06 text file (fallback method).
|
|
||||||
|
|
||||||
Parses the F06 file to find eigenvalue results table and extracts frequency.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
f06_file: Path to F06 output file
|
|
||||||
mode_number: Mode number to extract (1-based index)
|
|
||||||
verbose: Print extraction details
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Natural frequency in Hz
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: If frequency cannot be found in F06
|
|
||||||
"""
|
|
||||||
if not f06_file.exists():
|
|
||||||
raise FileNotFoundError(f"F06 file not found: {f06_file}")
|
|
||||||
|
|
||||||
with open(f06_file, 'r', encoding='latin-1', errors='ignore') as f:
|
|
||||||
content = f.read()
|
|
||||||
|
|
||||||
# Look for eigenvalue table
|
|
||||||
# Nastran F06 format has eigenvalue results like:
|
|
||||||
# R E A L E I G E N V A L U E S
|
|
||||||
# MODE EXTRACTION EIGENVALUE RADIANS CYCLES GENERALIZED GENERALIZED
|
|
||||||
# NO. ORDER MASS STIFFNESS
|
|
||||||
# 1 1 -6.602743E+04 2.569656E+02 4.089338E+01 1.000000E+00 6.602743E+04
|
|
||||||
|
|
||||||
lines = content.split('\n')
|
|
||||||
|
|
||||||
# Find eigenvalue table
|
|
||||||
eigenvalue_section_start = None
|
|
||||||
for i, line in enumerate(lines):
|
|
||||||
if 'R E A L E I G E N V A L U E S' in line:
|
|
||||||
eigenvalue_section_start = i
|
|
||||||
break
|
|
||||||
|
|
||||||
if eigenvalue_section_start is None:
|
|
||||||
raise ValueError("Eigenvalue table not found in F06 file")
|
|
||||||
|
|
||||||
# Parse eigenvalue table (starts a few lines after header)
|
|
||||||
for i in range(eigenvalue_section_start + 3, min(eigenvalue_section_start + 100, len(lines))):
|
|
||||||
line = lines[i].strip()
|
|
||||||
|
|
||||||
if not line or line.startswith('1'): # Page break
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Parse line with mode data
|
|
||||||
parts = line.split()
|
|
||||||
if len(parts) >= 5:
|
|
||||||
try:
|
|
||||||
mode_num = int(parts[0])
|
|
||||||
if mode_num == mode_number:
|
|
||||||
# Frequency is in column 5 (CYCLES)
|
|
||||||
frequency = float(parts[4])
|
|
||||||
if verbose:
|
|
||||||
print(f"[F06 EXTRACT] Found mode {mode_num}: {frequency:.6f} Hz")
|
|
||||||
return frequency
|
|
||||||
except (ValueError, IndexError):
|
|
||||||
continue
|
|
||||||
|
|
||||||
raise ValueError(f"Mode {mode_number} not found in F06 eigenvalue table")
|
|
||||||
|
|
||||||
|
|
||||||
def validate_op2_file(op2_file: Path, f06_file: Optional[Path] = None) -> Tuple[bool, str]:
|
|
||||||
"""
|
|
||||||
Validate if an OP2 file contains usable eigenvalue data.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
op2_file: Path to OP2 file
|
|
||||||
f06_file: Optional F06 file for cross-reference
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
(is_valid, message): Tuple of validation status and explanation
|
|
||||||
"""
|
|
||||||
if not op2_file.exists():
|
|
||||||
return False, f"OP2 file does not exist: {op2_file}"
|
|
||||||
|
|
||||||
if op2_file.stat().st_size == 0:
|
|
||||||
return False, "OP2 file is empty"
|
|
||||||
|
|
||||||
# Try to extract first frequency
|
|
||||||
try:
|
|
||||||
frequency = robust_extract_first_frequency(
|
|
||||||
op2_file,
|
|
||||||
mode_number=1,
|
|
||||||
f06_file=f06_file,
|
|
||||||
verbose=False
|
|
||||||
)
|
|
||||||
return True, f"Valid OP2 file (first frequency: {frequency:.6f} Hz)"
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
return False, f"Cannot extract data from OP2: {str(e)}"
|
|
||||||
|
|
||||||
|
|
||||||
# Convenience function (same signature as old function for backward compatibility)
|
|
||||||
def extract_first_frequency(op2_file: Path, mode_number: int = 1) -> float:
|
|
||||||
"""
|
|
||||||
Extract first natural frequency (backward compatible with old function).
|
|
||||||
|
|
||||||
This is the simple version - just use robust_extract_first_frequency directly
|
|
||||||
for more control.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
op2_file: Path to OP2 file
|
|
||||||
mode_number: Mode number (1-based)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Frequency in Hz
|
|
||||||
"""
|
|
||||||
# Try to find F06 file in same directory
|
|
||||||
f06_file = op2_file.with_suffix('.f06')
|
|
||||||
|
|
||||||
return robust_extract_first_frequency(
|
|
||||||
op2_file,
|
|
||||||
mode_number=mode_number,
|
|
||||||
f06_file=f06_file if f06_file.exists() else None,
|
|
||||||
verbose=False
|
|
||||||
)
|
|
||||||
25
optimization_engine/processors/__init__.py
Normal file
25
optimization_engine/processors/__init__.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
"""
|
||||||
|
Optimization Processors
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Data processing algorithms and ML models.
|
||||||
|
|
||||||
|
Submodules:
|
||||||
|
- surrogates/: Neural network surrogate models
|
||||||
|
- dynamic_response/: Dynamic response processing (random vib, sine sweep)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Lazy import for surrogates to avoid import errors
|
||||||
|
def __getattr__(name):
|
||||||
|
if name == 'surrogates':
|
||||||
|
from . import surrogates
|
||||||
|
return surrogates
|
||||||
|
elif name == 'AdaptiveCharacterization':
|
||||||
|
from .adaptive_characterization import AdaptiveCharacterization
|
||||||
|
return AdaptiveCharacterization
|
||||||
|
raise AttributeError(f"module 'optimization_engine.processors' has no attribute '{name}'")
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'surrogates',
|
||||||
|
'AdaptiveCharacterization',
|
||||||
|
]
|
||||||
79
optimization_engine/processors/surrogates/__init__.py
Normal file
79
optimization_engine/processors/surrogates/__init__.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
"""
|
||||||
|
Surrogate Models
|
||||||
|
================
|
||||||
|
|
||||||
|
Neural network and ML surrogate models for FEA acceleration.
|
||||||
|
|
||||||
|
Available modules:
|
||||||
|
- neural_surrogate: AtomizerField neural network surrogate
|
||||||
|
- generic_surrogate: Flexible surrogate interface
|
||||||
|
- adaptive_surrogate: Self-improving surrogate
|
||||||
|
- simple_mlp_surrogate: Simple multi-layer perceptron
|
||||||
|
- active_learning_surrogate: Active learning surrogate
|
||||||
|
- surrogate_tuner: Hyperparameter tuning
|
||||||
|
- auto_trainer: Automatic model training
|
||||||
|
- training_data_exporter: Export training data from studies
|
||||||
|
|
||||||
|
Note: Imports are done on-demand to avoid import errors from optional dependencies.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Lazy imports to avoid circular dependencies and optional dependency issues
|
||||||
|
def __getattr__(name):
|
||||||
|
"""Lazy import mechanism for surrogate modules."""
|
||||||
|
if name == 'NeuralSurrogate':
|
||||||
|
from .neural_surrogate import NeuralSurrogate
|
||||||
|
return NeuralSurrogate
|
||||||
|
elif name == 'create_surrogate_for_study':
|
||||||
|
from .neural_surrogate import create_surrogate_for_study
|
||||||
|
return create_surrogate_for_study
|
||||||
|
elif name == 'GenericSurrogate':
|
||||||
|
from .generic_surrogate import GenericSurrogate
|
||||||
|
return GenericSurrogate
|
||||||
|
elif name == 'ConfigDrivenSurrogate':
|
||||||
|
from .generic_surrogate import ConfigDrivenSurrogate
|
||||||
|
return ConfigDrivenSurrogate
|
||||||
|
elif name == 'create_surrogate':
|
||||||
|
from .generic_surrogate import create_surrogate
|
||||||
|
return create_surrogate
|
||||||
|
elif name == 'AdaptiveSurrogate':
|
||||||
|
from .adaptive_surrogate import AdaptiveSurrogate
|
||||||
|
return AdaptiveSurrogate
|
||||||
|
elif name == 'SimpleSurrogate':
|
||||||
|
from .simple_mlp_surrogate import SimpleSurrogate
|
||||||
|
return SimpleSurrogate
|
||||||
|
elif name == 'ActiveLearningSurrogate':
|
||||||
|
from .active_learning_surrogate import ActiveLearningSurrogate
|
||||||
|
return ActiveLearningSurrogate
|
||||||
|
elif name == 'SurrogateHyperparameterTuner':
|
||||||
|
from .surrogate_tuner import SurrogateHyperparameterTuner
|
||||||
|
return SurrogateHyperparameterTuner
|
||||||
|
elif name == 'tune_surrogate_for_study':
|
||||||
|
from .surrogate_tuner import tune_surrogate_for_study
|
||||||
|
return tune_surrogate_for_study
|
||||||
|
elif name == 'AutoTrainer':
|
||||||
|
from .auto_trainer import AutoTrainer
|
||||||
|
return AutoTrainer
|
||||||
|
elif name == 'TrainingDataExporter':
|
||||||
|
from .training_data_exporter import TrainingDataExporter
|
||||||
|
return TrainingDataExporter
|
||||||
|
elif name == 'create_exporter_from_config':
|
||||||
|
from .training_data_exporter import create_exporter_from_config
|
||||||
|
return create_exporter_from_config
|
||||||
|
|
||||||
|
raise AttributeError(f"module 'optimization_engine.processors.surrogates' has no attribute '{name}'")
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'NeuralSurrogate',
|
||||||
|
'create_surrogate_for_study',
|
||||||
|
'GenericSurrogate',
|
||||||
|
'ConfigDrivenSurrogate',
|
||||||
|
'create_surrogate',
|
||||||
|
'AdaptiveSurrogate',
|
||||||
|
'SimpleSurrogate',
|
||||||
|
'ActiveLearningSurrogate',
|
||||||
|
'SurrogateHyperparameterTuner',
|
||||||
|
'tune_surrogate_for_study',
|
||||||
|
'AutoTrainer',
|
||||||
|
'TrainingDataExporter',
|
||||||
|
'create_exporter_from_config',
|
||||||
|
]
|
||||||
@@ -11,7 +11,7 @@ Workflow:
|
|||||||
4. Deploy model for neural-accelerated optimization
|
4. Deploy model for neural-accelerated optimization
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from optimization_engine.auto_trainer import AutoTrainer
|
from optimization_engine.processors.surrogates.auto_trainer import AutoTrainer
|
||||||
|
|
||||||
trainer = AutoTrainer(
|
trainer = AutoTrainer(
|
||||||
study_name="uav_arm_optimization",
|
study_name="uav_arm_optimization",
|
||||||
@@ -6,7 +6,7 @@ by providing a fully config-driven neural surrogate system.
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
# In study's run_nn_optimization.py (now ~30 lines instead of ~600):
|
# In study's run_nn_optimization.py (now ~30 lines instead of ~600):
|
||||||
from optimization_engine.generic_surrogate import ConfigDrivenSurrogate
|
from optimization_engine.processors.surrogates.generic_surrogate import ConfigDrivenSurrogate
|
||||||
|
|
||||||
surrogate = ConfigDrivenSurrogate(__file__)
|
surrogate = ConfigDrivenSurrogate(__file__)
|
||||||
surrogate.run() # Handles --train, --turbo, --all flags automatically
|
surrogate.run() # Handles --train, --turbo, --all flags automatically
|
||||||
@@ -503,8 +503,8 @@ class ConfigDrivenSurrogate:
|
|||||||
if str(project_root) not in sys.path:
|
if str(project_root) not in sys.path:
|
||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
from optimization_engine.nx_solver import NXSolver
|
from optimization_engine.nx.solver import NXSolver
|
||||||
from optimization_engine.logger import get_logger
|
from optimization_engine.utils.logger import get_logger
|
||||||
|
|
||||||
self.results_dir.mkdir(exist_ok=True)
|
self.results_dir.mkdir(exist_ok=True)
|
||||||
self.logger = get_logger(self.study_name, study_dir=self.results_dir)
|
self.logger = get_logger(self.study_name, study_dir=self.results_dir)
|
||||||
@@ -12,7 +12,7 @@ Key Features:
|
|||||||
- Performance tracking and statistics
|
- Performance tracking and statistics
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from optimization_engine.neural_surrogate import NeuralSurrogate, create_surrogate_for_study
|
from optimization_engine.processors.surrogates.neural_surrogate import NeuralSurrogate, create_surrogate_for_study
|
||||||
|
|
||||||
# Create surrogate for UAV arm study
|
# Create surrogate for UAV arm study
|
||||||
surrogate = create_surrogate_for_study(
|
surrogate = create_surrogate_for_study(
|
||||||
@@ -12,7 +12,7 @@ This is much simpler than the GNN-based approach and works well when:
|
|||||||
- You want quick setup without mesh parsing pipeline
|
- You want quick setup without mesh parsing pipeline
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from optimization_engine.simple_mlp_surrogate import SimpleSurrogate, train_from_database
|
from optimization_engine.processors.surrogates.simple_mlp_surrogate import SimpleSurrogate, train_from_database
|
||||||
|
|
||||||
# Train from database
|
# Train from database
|
||||||
surrogate = train_from_database(
|
surrogate = train_from_database(
|
||||||
@@ -12,7 +12,7 @@ Key Features:
|
|||||||
5. Proper uncertainty quantification
|
5. Proper uncertainty quantification
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from optimization_engine.surrogate_tuner import SurrogateHyperparameterTuner
|
from optimization_engine.processors.surrogates.surrogate_tuner import SurrogateHyperparameterTuner
|
||||||
|
|
||||||
tuner = SurrogateHyperparameterTuner(
|
tuner = SurrogateHyperparameterTuner(
|
||||||
input_dim=11,
|
input_dim=11,
|
||||||
@@ -5,7 +5,7 @@ This module exports training data from Atomizer optimization runs for AtomizerFi
|
|||||||
It saves NX Nastran input (.dat) and output (.op2) files along with metadata for each trial.
|
It saves NX Nastran input (.dat) and output (.op2) files along with metadata for each trial.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from optimization_engine.training_data_exporter import create_exporter_from_config
|
from optimization_engine.processors.surrogates.training_data_exporter import create_exporter_from_config
|
||||||
|
|
||||||
exporter = create_exporter_from_config(config)
|
exporter = create_exporter_from_config(config)
|
||||||
if exporter:
|
if exporter:
|
||||||
44
optimization_engine/reporting/__init__.py
Normal file
44
optimization_engine/reporting/__init__.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
"""
|
||||||
|
Reporting & Analysis
|
||||||
|
====================
|
||||||
|
|
||||||
|
Report generation and results analysis.
|
||||||
|
|
||||||
|
Modules:
|
||||||
|
- report_generator: HTML/PDF report generation
|
||||||
|
- markdown_report: Markdown report format
|
||||||
|
- results_analyzer: Comprehensive results analysis
|
||||||
|
- visualizer: Plotting and visualization
|
||||||
|
- landscape_analyzer: Design space analysis
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Lazy imports to avoid import errors
|
||||||
|
def __getattr__(name):
|
||||||
|
if name == 'generate_optimization_report':
|
||||||
|
from .report_generator import generate_optimization_report
|
||||||
|
return generate_optimization_report
|
||||||
|
elif name == 'generate_markdown_report':
|
||||||
|
from .markdown_report import generate_markdown_report
|
||||||
|
return generate_markdown_report
|
||||||
|
elif name == 'MarkdownReportGenerator':
|
||||||
|
from .markdown_report import MarkdownReportGenerator
|
||||||
|
return MarkdownReportGenerator
|
||||||
|
elif name == 'ResultsAnalyzer':
|
||||||
|
from .results_analyzer import ResultsAnalyzer
|
||||||
|
return ResultsAnalyzer
|
||||||
|
elif name == 'Visualizer':
|
||||||
|
from .visualizer import Visualizer
|
||||||
|
return Visualizer
|
||||||
|
elif name == 'LandscapeAnalyzer':
|
||||||
|
from .landscape_analyzer import LandscapeAnalyzer
|
||||||
|
return LandscapeAnalyzer
|
||||||
|
raise AttributeError(f"module 'optimization_engine.reporting' has no attribute '{name}'")
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'generate_optimization_report',
|
||||||
|
'generate_markdown_report',
|
||||||
|
'MarkdownReportGenerator',
|
||||||
|
'ResultsAnalyzer',
|
||||||
|
'Visualizer',
|
||||||
|
'LandscapeAnalyzer',
|
||||||
|
]
|
||||||
@@ -35,11 +35,11 @@ from typing import Dict, Any, Optional
|
|||||||
# Add parent directory to path for imports
|
# Add parent directory to path for imports
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||||
|
|
||||||
from optimization_engine.llm_workflow_analyzer import LLMWorkflowAnalyzer
|
from optimization_engine.future.llm_workflow_analyzer import LLMWorkflowAnalyzer
|
||||||
from optimization_engine.llm_optimization_runner import LLMOptimizationRunner
|
from optimization_engine.future.llm_optimization_runner import LLMOptimizationRunner
|
||||||
from optimization_engine.runner import OptimizationRunner
|
from optimization_engine.core.runner import OptimizationRunner
|
||||||
from optimization_engine.nx_updater import NXParameterUpdater
|
from optimization_engine.nx.updater import NXParameterUpdater
|
||||||
from optimization_engine.nx_solver import NXSolver
|
from optimization_engine.nx.solver import NXSolver
|
||||||
|
|
||||||
# Setup logging
|
# Setup logging
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
|
|||||||
60
optimization_engine/study/__init__.py
Normal file
60
optimization_engine/study/__init__.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
"""
|
||||||
|
Study Management
|
||||||
|
================
|
||||||
|
|
||||||
|
Study creation, state management, and lifecycle.
|
||||||
|
|
||||||
|
Modules:
|
||||||
|
- creator: Study creation from templates
|
||||||
|
- wizard: Interactive study setup wizard
|
||||||
|
- state: Study state tracking
|
||||||
|
- reset: Study reset functionality
|
||||||
|
- continuation: Resume interrupted studies
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Lazy imports to avoid circular dependencies
|
||||||
|
def __getattr__(name):
|
||||||
|
if name == 'StudyCreator':
|
||||||
|
from .creator import StudyCreator
|
||||||
|
return StudyCreator
|
||||||
|
elif name == 'create_study':
|
||||||
|
from .creator import create_study
|
||||||
|
return create_study
|
||||||
|
elif name == 'StudyWizard':
|
||||||
|
from .wizard import StudyWizard
|
||||||
|
return StudyWizard
|
||||||
|
elif name == 'StudyState':
|
||||||
|
from .state import StudyState
|
||||||
|
return StudyState
|
||||||
|
elif name == 'StudyReset':
|
||||||
|
from .reset import StudyReset
|
||||||
|
return StudyReset
|
||||||
|
elif name == 'reset_study':
|
||||||
|
from .reset import reset_study
|
||||||
|
return reset_study
|
||||||
|
elif name == 'StudyContinuation':
|
||||||
|
from .continuation import StudyContinuation
|
||||||
|
return StudyContinuation
|
||||||
|
elif name == 'continue_study':
|
||||||
|
from .continuation import continue_study
|
||||||
|
return continue_study
|
||||||
|
elif name == 'BenchmarkingSubstudy':
|
||||||
|
from .benchmarking import BenchmarkingSubstudy
|
||||||
|
return BenchmarkingSubstudy
|
||||||
|
elif name == 'generate_history':
|
||||||
|
from .history_generator import generate_history
|
||||||
|
return generate_history
|
||||||
|
raise AttributeError(f"module 'optimization_engine.study' has no attribute '{name}'")
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'StudyCreator',
|
||||||
|
'create_study',
|
||||||
|
'StudyWizard',
|
||||||
|
'StudyState',
|
||||||
|
'StudyReset',
|
||||||
|
'reset_study',
|
||||||
|
'StudyContinuation',
|
||||||
|
'continue_study',
|
||||||
|
'BenchmarkingSubstudy',
|
||||||
|
'generate_history',
|
||||||
|
]
|
||||||
@@ -26,7 +26,7 @@ from typing import Dict, Any, List, Optional
|
|||||||
from dataclasses import dataclass, asdict
|
from dataclasses import dataclass, asdict
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from optimization_engine.optimization_setup_wizard import OptimizationSetupWizard, ModelIntrospection, OP2Introspection
|
from optimization_engine.config.setup_wizard import OptimizationSetupWizard, ModelIntrospection, OP2Introspection
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -5,7 +5,7 @@ This module provides a standardized way to continue optimization studies with
|
|||||||
additional trials, preserving all existing trial data and learned knowledge.
|
additional trials, preserving all existing trial data and learned knowledge.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from optimization_engine.study_continuation import continue_study
|
from optimization_engine.study.continuation import continue_study
|
||||||
|
|
||||||
continue_study(
|
continue_study(
|
||||||
study_dir=Path("studies/my_study"),
|
study_dir=Path("studies/my_study"),
|
||||||
@@ -22,7 +22,7 @@ from typing import Dict, Any, Optional, List
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from optimization_engine.benchmarking_substudy import BenchmarkingSubstudy, BenchmarkResults
|
from optimization_engine.study.benchmarking import BenchmarkingSubstudy, BenchmarkResults
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -318,7 +318,7 @@ class StudyCreator:
|
|||||||
readme.append("")
|
readme.append("")
|
||||||
readme.append("### 2. Run Benchmarking (Mandatory)")
|
readme.append("### 2. Run Benchmarking (Mandatory)")
|
||||||
readme.append("```python")
|
readme.append("```python")
|
||||||
readme.append("from optimization_engine.study_creator import StudyCreator")
|
readme.append("from optimization_engine.study.creator import StudyCreator")
|
||||||
readme.append("")
|
readme.append("")
|
||||||
readme.append("creator = StudyCreator()")
|
readme.append("creator = StudyCreator()")
|
||||||
readme.append(f"results = creator.run_benchmarking(")
|
readme.append(f"results = creator.run_benchmarking(")
|
||||||
@@ -11,7 +11,7 @@ A powerful, LLM-friendly wizard that automates the complete study creation workf
|
|||||||
This module is designed to work seamlessly with Claude Code skills.
|
This module is designed to work seamlessly with Claude Code skills.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from optimization_engine.study_wizard import StudyWizard
|
from optimization_engine.study.wizard import StudyWizard
|
||||||
|
|
||||||
wizard = StudyWizard(
|
wizard = StudyWizard(
|
||||||
study_name="my_optimization",
|
study_name="my_optimization",
|
||||||
@@ -960,8 +960,8 @@ import optuna
|
|||||||
from optuna.samplers import {sampler}
|
from optuna.samplers import {sampler}
|
||||||
|
|
||||||
# Core imports
|
# Core imports
|
||||||
from optimization_engine.nx_solver import NXSolver
|
from optimization_engine.nx.solver import NXSolver
|
||||||
from optimization_engine.logger import get_logger
|
from optimization_engine.utils.logger import get_logger
|
||||||
|
|
||||||
# Extractor imports
|
# Extractor imports
|
||||||
{chr(10).join(sorted(extractor_imports))}
|
{chr(10).join(sorted(extractor_imports))}
|
||||||
@@ -24,7 +24,7 @@ import sys
|
|||||||
project_root = Path(__file__).resolve().parents[2]
|
project_root = Path(__file__).resolve().parents[2]
|
||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
from optimization_engine.generic_surrogate import ConfigDrivenSurrogate
|
from optimization_engine.processors.surrogates.generic_surrogate import ConfigDrivenSurrogate
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import sys
|
|||||||
project_root = Path(__file__).resolve().parents[2]
|
project_root = Path(__file__).resolve().parents[2]
|
||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
from optimization_engine.base_runner import ConfigDrivenRunner
|
from optimization_engine.core.base_runner import ConfigDrivenRunner
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Atomizer Structured Logging System - Phase 1.3
|
|||||||
Provides consistent, production-ready logging across all optimization studies.
|
Provides consistent, production-ready logging across all optimization studies.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from optimization_engine.logger import get_logger
|
from optimization_engine.utils.logger import get_logger
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
logger.info("Starting optimization...")
|
logger.info("Starting optimization...")
|
||||||
@@ -70,7 +70,7 @@ def run_single_fea(args_tuple):
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
atomizer_config = None
|
atomizer_config = None
|
||||||
|
|
||||||
from optimization_engine.nx_solver import NXSolver
|
from optimization_engine.nx.solver import NXSolver
|
||||||
from optimization_engine.extractors.extract_displacement import extract_displacement
|
from optimization_engine.extractors.extract_displacement import extract_displacement
|
||||||
from optimization_engine.extractors.extract_von_mises_stress import extract_solid_stress
|
from optimization_engine.extractors.extract_von_mises_stress import extract_solid_stress
|
||||||
from optimization_engine.extractors.extract_frequency import extract_frequency
|
from optimization_engine.extractors.extract_frequency import extract_frequency
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ if sys.platform == 'win32':
|
|||||||
project_root = Path(__file__).parent.parent
|
project_root = Path(__file__).parent.parent
|
||||||
sys.path.insert(0, str(project_root))
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
from optimization_engine.research_agent import (
|
from optimization_engine.future.research_agent import (
|
||||||
ResearchAgent,
|
ResearchAgent,
|
||||||
ResearchFindings,
|
ResearchFindings,
|
||||||
KnowledgeGap,
|
KnowledgeGap,
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ from pathlib import Path
|
|||||||
|
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||||
|
|
||||||
from optimization_engine.optimization_setup_wizard import OptimizationSetupWizard
|
from optimization_engine.config.setup_wizard import OptimizationSetupWizard
|
||||||
from optimization_engine.llm_optimization_runner import LLMOptimizationRunner
|
from optimization_engine.future.llm_optimization_runner import LLMOptimizationRunner
|
||||||
from optimization_engine.nx_solver import NXSolver
|
from optimization_engine.nx.solver import NXSolver
|
||||||
from optimization_engine.nx_updater import NXParameterUpdater
|
from optimization_engine.nx.updater import NXParameterUpdater
|
||||||
|
|
||||||
|
|
||||||
def print_section(title: str):
|
def print_section(title: str):
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ sys.path.insert(0, str(Path(__file__).parent.parent))
|
|||||||
import atomizer_paths
|
import atomizer_paths
|
||||||
atomizer_paths.ensure_imports()
|
atomizer_paths.ensure_imports()
|
||||||
|
|
||||||
from optimization_engine.runner import OptimizationRunner
|
from optimization_engine.core.runner import OptimizationRunner
|
||||||
from optimization_engine.nx_solver import run_nx_simulation
|
from optimization_engine.nx.solver import run_nx_simulation
|
||||||
from optimization_engine.result_extractors.extractors import (
|
from optimization_engine.result_extractors.extractors import (
|
||||||
stress_extractor,
|
stress_extractor,
|
||||||
displacement_extractor
|
displacement_extractor
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from pathlib import Path
|
|||||||
# Add parent directory to path
|
# Add parent directory to path
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||||
|
|
||||||
from optimization_engine.study_creator import StudyCreator
|
from optimization_engine.study.creator import StudyCreator
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
# Setup logging
|
# Setup logging
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from pathlib import Path
|
|||||||
# Add parent directory to path
|
# Add parent directory to path
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||||
|
|
||||||
from optimization_engine.study_creator import StudyCreator
|
from optimization_engine.study.creator import StudyCreator
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
# Setup logging
|
# Setup logging
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||||
|
|
||||||
from optimization_engine.study_creator import StudyCreator
|
from optimization_engine.study.creator import StudyCreator
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||||
|
|
||||||
from optimization_engine.study_creator import StudyCreator
|
from optimization_engine.study.creator import StudyCreator
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from pathlib import Path
|
|||||||
# Add parent directory to path
|
# Add parent directory to path
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||||
|
|
||||||
from optimization_engine.llm_workflow_analyzer import LLMWorkflowAnalyzer
|
from optimization_engine.future.llm_workflow_analyzer import LLMWorkflowAnalyzer
|
||||||
|
|
||||||
|
|
||||||
def test_api_connection():
|
def test_api_connection():
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from pathlib import Path
|
|||||||
# Add parent directory to path
|
# Add parent directory to path
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||||
|
|
||||||
from optimization_engine.study_creator import StudyCreator
|
from optimization_engine.study.creator import StudyCreator
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
# Setup logging
|
# Setup logging
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ import json
|
|||||||
|
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||||
|
|
||||||
from optimization_engine.llm_optimization_runner import LLMOptimizationRunner
|
from optimization_engine.future.llm_optimization_runner import LLMOptimizationRunner
|
||||||
from optimization_engine.nx_solver import NXSolver
|
from optimization_engine.nx.solver import NXSolver
|
||||||
from optimization_engine.nx_updater import NXParameterUpdater
|
from optimization_engine.nx.updater import NXParameterUpdater
|
||||||
|
|
||||||
# LLM workflow for bracket optimization
|
# LLM workflow for bracket optimization
|
||||||
llm_workflow = {
|
llm_workflow = {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||||
|
|
||||||
from optimization_engine.llm_optimization_runner import LLMOptimizationRunner
|
from optimization_engine.future.llm_optimization_runner import LLMOptimizationRunner
|
||||||
|
|
||||||
# LLM workflow for bracket optimization
|
# LLM workflow for bracket optimization
|
||||||
# Goal: Maximize displacement while keeping stress below safety factor
|
# Goal: Maximize displacement while keeping stress below safety factor
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user