feat: Add comprehensive study management system

Implement study persistence and resumption capabilities for optimization workflows:

Features:
- Resume existing studies to add more trials
- Create new studies when topology/config changes
- Study metadata tracking (creation date, trials, config hash)
- SQLite database persistence for Optuna studies
- Configuration change detection with warnings
- List all available studies

Key Changes:
- Enhanced OptimizationRunner.run() with resume parameter
- Added _load_existing_study() for study resumption
- Added _save_study_metadata() for tracking
- Added _get_config_hash() to detect topology changes
- Added list_studies() to view all studies
- SQLite storage for study persistence

Updated Files:
- optimization_engine/runner.py: Core study management
- examples/test_journal_optimization.py: Interactive study management
- examples/study_management_example.py: Comprehensive examples

Usage Examples:
  # New study
  runner.run(study_name="bracket_v1", n_trials=50)

  # Resume study (add 25 more trials)
  runner.run(study_name="bracket_v1", n_trials=25, resume=True)

  # New study after topology change
  runner.run(study_name="bracket_v2", n_trials=50)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-15 13:02:15 -05:00
parent a267e2d6f0
commit 7d97ef1cb5
3 changed files with 548 additions and 23 deletions

View File

@@ -116,8 +116,57 @@ if __name__ == "__main__":
# Use the configured number of trials (50 by default)
n_trials = runner.config['optimization_settings']['n_trials']
# Check for existing studies
existing_studies = runner.list_studies()
print("\n" + "="*60)
print(f"Starting optimization with {n_trials} trials")
print("STUDY MANAGEMENT")
print("="*60)
if existing_studies:
print(f"\nFound {len(existing_studies)} existing studies:")
for study in existing_studies:
print(f" - {study['study_name']}: {study.get('total_trials', 0)} trials")
print("\nOptions:")
print("1. Create NEW study (fresh start)")
print("2. RESUME existing study (add more trials)")
choice = input("\nChoose option (1 or 2): ").strip()
if choice == '2':
# Resume existing study
if len(existing_studies) == 1:
study_name = existing_studies[0]['study_name']
print(f"\nResuming study: {study_name}")
else:
print("\nAvailable studies:")
for i, study in enumerate(existing_studies):
print(f"{i+1}. {study['study_name']}")
study_idx = int(input("Select study number: ")) - 1
study_name = existing_studies[study_idx]['study_name']
resume_mode = True
else:
# New study
study_name = input("\nEnter study name (default: bracket_stress_opt): ").strip()
if not study_name:
study_name = "bracket_stress_opt"
resume_mode = False
else:
print("\nNo existing studies found. Creating new study.")
study_name = input("\nEnter study name (default: bracket_stress_opt): ").strip()
if not study_name:
study_name = "bracket_stress_opt"
resume_mode = False
print("\n" + "="*60)
if resume_mode:
print(f"RESUMING STUDY: {study_name}")
print(f"Adding {n_trials} additional trials")
else:
print(f"STARTING NEW STUDY: {study_name}")
print(f"Running {n_trials} trials")
print("="*60)
print("Objective: Minimize max von Mises stress")
print("Constraint: Max displacement <= 1.0 mm")
print("Solver: Journal-based (using running NX GUI)")
@@ -125,7 +174,11 @@ if __name__ == "__main__":
print("="*60)
try:
study = runner.run(study_name="journal_solver_test")
study = runner.run(
study_name=study_name,
n_trials=n_trials,
resume=resume_mode
)
print("\n" + "="*60)
print("OPTIMIZATION COMPLETE!")