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:
152
optimization_engine/reporting/report_generator.py
Normal file
152
optimization_engine/reporting/report_generator.py
Normal file
@@ -0,0 +1,152 @@
|
||||
"""
|
||||
Generate human-readable optimization reports from incremental history JSON.
|
||||
|
||||
This script should be run automatically at the end of optimization, or manually
|
||||
to generate a report for any completed optimization study.
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any, List
|
||||
import numpy as np
|
||||
|
||||
|
||||
def generate_optimization_report(history_file: Path, target_value: float = None, tolerance: float = 0.1) -> str:
|
||||
"""
|
||||
Generate a comprehensive human-readable optimization report.
|
||||
|
||||
Args:
|
||||
history_file: Path to optimization_history_incremental.json
|
||||
target_value: Target objective value (if applicable)
|
||||
tolerance: Acceptable tolerance for success (default 0.1)
|
||||
|
||||
Returns:
|
||||
Report text as a string
|
||||
"""
|
||||
# Load history
|
||||
with open(history_file) as f:
|
||||
history = json.load(f)
|
||||
|
||||
if not history:
|
||||
return "No optimization history found."
|
||||
|
||||
report = []
|
||||
report.append('=' * 80)
|
||||
report.append('OPTIMIZATION REPORT')
|
||||
report.append('=' * 80)
|
||||
report.append('')
|
||||
|
||||
# Study information
|
||||
study_dir = history_file.parent.parent.parent
|
||||
study_name = study_dir.name
|
||||
report.append('STUDY INFORMATION')
|
||||
report.append('-' * 80)
|
||||
report.append(f'Study: {study_name}')
|
||||
report.append(f'Total trials: {len(history)}')
|
||||
report.append('')
|
||||
|
||||
# Design variables
|
||||
first_trial = history[0]
|
||||
design_vars = list(first_trial['design_variables'].keys())
|
||||
report.append('DESIGN VARIABLES')
|
||||
report.append('-' * 80)
|
||||
for var in design_vars:
|
||||
values = [t['design_variables'][var] for t in history]
|
||||
report.append(f' {var}:')
|
||||
report.append(f' Range: {min(values):.4f} - {max(values):.4f}')
|
||||
report.append(f' Mean: {np.mean(values):.4f}')
|
||||
report.append('')
|
||||
|
||||
# Objective results
|
||||
results = list(first_trial['results'].keys())
|
||||
report.append('OBJECTIVE RESULTS')
|
||||
report.append('-' * 80)
|
||||
for result in results:
|
||||
values = [t['results'][result] for t in history]
|
||||
report.append(f' {result}:')
|
||||
report.append(f' Range: {min(values):.4f} - {max(values):.4f}')
|
||||
report.append(f' Mean: {np.mean(values):.4f}')
|
||||
report.append(f' Std dev: {np.std(values):.4f}')
|
||||
report.append('')
|
||||
|
||||
# Best trial
|
||||
objectives = [t['objective'] for t in history]
|
||||
best_trial = history[np.argmin(objectives)]
|
||||
|
||||
report.append('BEST TRIAL')
|
||||
report.append('-' * 80)
|
||||
report.append(f'Trial #{best_trial["trial_number"]}')
|
||||
report.append(f' Objective value: {best_trial["objective"]:.4f}')
|
||||
report.append(' Design variables:')
|
||||
for var, value in best_trial['design_variables'].items():
|
||||
report.append(f' {var}: {value:.4f}')
|
||||
report.append(' Results:')
|
||||
for result, value in best_trial['results'].items():
|
||||
report.append(f' {result}: {value:.4f}')
|
||||
report.append('')
|
||||
|
||||
# Top 5 trials
|
||||
report.append('TOP 5 TRIALS (by objective value)')
|
||||
report.append('-' * 80)
|
||||
sorted_history = sorted(history, key=lambda x: x['objective'])
|
||||
for i, trial in enumerate(sorted_history[:5], 1):
|
||||
report.append(f'{i}. Trial #{trial["trial_number"]}: Objective = {trial["objective"]:.4f}')
|
||||
vars_str = ', '.join([f'{k}={v:.2f}' for k, v in trial['design_variables'].items()])
|
||||
report.append(f' {vars_str}')
|
||||
report.append('')
|
||||
|
||||
# Success assessment (if target provided)
|
||||
if target_value is not None:
|
||||
report.append('SUCCESS ASSESSMENT')
|
||||
report.append('-' * 80)
|
||||
best_objective = min(objectives)
|
||||
error = abs(best_objective - target_value)
|
||||
|
||||
if error <= tolerance:
|
||||
report.append(f'[SUCCESS] Target {target_value} achieved within tolerance {tolerance}!')
|
||||
report.append(f' Best objective: {best_objective:.4f}')
|
||||
report.append(f' Error: {error:.4f}')
|
||||
else:
|
||||
report.append(f'[INCOMPLETE] Target {target_value} not achieved')
|
||||
report.append(f' Best objective: {best_objective:.4f}')
|
||||
report.append(f' Error: {error:.4f}')
|
||||
report.append(f' Need {error - tolerance:.4f} improvement')
|
||||
report.append('')
|
||||
|
||||
report.append('=' * 80)
|
||||
|
||||
return '\n'.join(report)
|
||||
|
||||
|
||||
def main():
|
||||
"""Command-line interface for report generation."""
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python generate_report.py <history_file> [target_value] [tolerance]")
|
||||
print("Example: python generate_report.py studies/my_study/2_substudies/results/optimization_history_incremental.json 115.0 0.1")
|
||||
sys.exit(1)
|
||||
|
||||
history_file = Path(sys.argv[1])
|
||||
if not history_file.exists():
|
||||
print(f"Error: History file not found: {history_file}")
|
||||
sys.exit(1)
|
||||
|
||||
target_value = float(sys.argv[2]) if len(sys.argv) > 2 else None
|
||||
tolerance = float(sys.argv[3]) if len(sys.argv) > 3 else 0.1
|
||||
|
||||
# Generate report
|
||||
report = generate_optimization_report(history_file, target_value, tolerance)
|
||||
|
||||
# Save report
|
||||
report_file = history_file.parent / 'OPTIMIZATION_REPORT.txt'
|
||||
with open(report_file, 'w') as f:
|
||||
f.write(report)
|
||||
|
||||
# Print to console
|
||||
print(report)
|
||||
print()
|
||||
print(f"Report saved to: {report_file}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user