Files
Atomizer/optimization_engine/template_loader.py
Anto01 a0c008a593 feat: Add neural loop automation - templates, auto-trainer, CLI
Closes the neural training loop with automated workflow:
- atomizer.py: One-command neural workflow CLI
- auto_trainer.py: Auto-training trigger system (50pt threshold)
- template_loader.py: Study creation from templates
- study_reset.py: Study reset/cleanup utility
- 3 templates: beam stiffness, bracket stress, frequency tuning
- State assessment document (Nov 25)

Usage: python atomizer.py neural-optimize --study my_study --trials 500

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 07:53:00 -05:00

384 lines
11 KiB
Python

"""
Template Loader for Atomizer Optimization Studies
Creates new studies from templates with automatic folder structure creation.
Usage:
from optimization_engine.template_loader import create_study_from_template, list_templates
# List available templates
templates = list_templates()
# Create a new study from template
create_study_from_template(
template_name="beam_stiffness_optimization",
study_name="my_beam_study"
)
"""
import json
import shutil
from pathlib import Path
from typing import Dict, Any, List, Optional
from datetime import datetime
TEMPLATES_DIR = Path(__file__).parent.parent / "templates"
STUDIES_DIR = Path(__file__).parent.parent / "studies"
def list_templates() -> List[Dict[str, Any]]:
"""
List all available templates.
Returns:
List of template metadata dictionaries
"""
templates = []
if not TEMPLATES_DIR.exists():
return templates
for template_file in TEMPLATES_DIR.glob("*.json"):
try:
with open(template_file, 'r') as f:
config = json.load(f)
template_info = config.get("template_info", {})
templates.append({
"name": template_file.stem,
"description": config.get("description", "No description"),
"category": template_info.get("category", "general"),
"analysis_type": template_info.get("analysis_type", "unknown"),
"objectives": len(config.get("objectives", [])),
"design_variables": len(config.get("design_variables", [])),
"path": str(template_file)
})
except Exception as e:
print(f"Warning: Could not load template {template_file}: {e}")
return templates
def get_template(template_name: str) -> Optional[Dict[str, Any]]:
"""
Load a template by name.
Args:
template_name: Name of the template (without .json extension)
Returns:
Template configuration dictionary or None if not found
"""
template_path = TEMPLATES_DIR / f"{template_name}.json"
if not template_path.exists():
# Try with .json extension already included
template_path = TEMPLATES_DIR / template_name
if not template_path.exists():
return None
with open(template_path, 'r') as f:
return json.load(f)
def create_study_from_template(
template_name: str,
study_name: str,
studies_dir: Optional[Path] = None,
overrides: Optional[Dict[str, Any]] = None
) -> Path:
"""
Create a new study from a template.
Args:
template_name: Name of the template to use
study_name: Name for the new study
studies_dir: Base directory for studies (default: studies/)
overrides: Dictionary of config values to override
Returns:
Path to the created study directory
Raises:
FileNotFoundError: If template doesn't exist
FileExistsError: If study already exists
"""
if studies_dir is None:
studies_dir = STUDIES_DIR
studies_dir = Path(studies_dir)
# Load template
template = get_template(template_name)
if template is None:
available = [t["name"] for t in list_templates()]
raise FileNotFoundError(
f"Template '{template_name}' not found. "
f"Available templates: {available}"
)
# Check if study already exists
study_path = studies_dir / study_name
if study_path.exists():
raise FileExistsError(
f"Study '{study_name}' already exists at {study_path}. "
"Choose a different name or delete the existing study."
)
# Create study directory structure
setup_dir = study_path / "1_setup"
model_dir = setup_dir / "model"
results_dir = study_path / "2_results"
setup_dir.mkdir(parents=True)
model_dir.mkdir()
results_dir.mkdir()
# Customize template for this study
config = template.copy()
config["study_name"] = study_name
config["created_from_template"] = template_name
config["created_at"] = datetime.now().isoformat()
# Update training data export path
if "training_data_export" in config:
export_dir = config["training_data_export"].get("export_dir", "")
if "${study_name}" in export_dir:
config["training_data_export"]["export_dir"] = export_dir.replace(
"${study_name}", study_name
)
# Apply overrides
if overrides:
_deep_update(config, overrides)
# Write configuration
config_path = setup_dir / "optimization_config.json"
with open(config_path, 'w') as f:
json.dump(config, f, indent=2)
# Create run_optimization.py
run_script_content = _generate_run_script(study_name, config)
run_script_path = study_path / "run_optimization.py"
with open(run_script_path, 'w') as f:
f.write(run_script_content)
# Create README.md
readme_content = _generate_study_readme(study_name, config, template_name)
readme_path = study_path / "README.md"
with open(readme_path, 'w') as f:
f.write(readme_content)
print(f"Created study '{study_name}' from template '{template_name}'")
print(f" Location: {study_path}")
print(f" Config: {config_path}")
print(f"\nNext steps:")
print(f" 1. Add your NX model files to: {model_dir}")
print(f" 2. Update design variable bounds in optimization_config.json")
print(f" 3. Run: python {run_script_path} --trials 50")
return study_path
def _deep_update(base: Dict, updates: Dict) -> Dict:
"""Recursively update a dictionary."""
for key, value in updates.items():
if key in base and isinstance(base[key], dict) and isinstance(value, dict):
_deep_update(base[key], value)
else:
base[key] = value
return base
def _generate_run_script(study_name: str, config: Dict[str, Any]) -> str:
"""Generate the run_optimization.py script for a study."""
return f'''"""
Optimization Runner for {study_name}
Auto-generated from template: {config.get('created_from_template', 'unknown')}
Created: {config.get('created_at', 'unknown')}
Usage:
python run_optimization.py --trials 50
python run_optimization.py --trials 25 --resume
python run_optimization.py --trials 100 --enable-nn
"""
import sys
import argparse
from pathlib import Path
# Add project root to path
project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root))
from optimization_engine.study_runner import run_study
def main():
parser = argparse.ArgumentParser(description="{config.get('description', study_name)}")
parser.add_argument('--trials', type=int, default=30, help='Number of trials to run')
parser.add_argument('--resume', action='store_true', help='Resume existing study')
parser.add_argument('--enable-nn', action='store_true', help='Enable neural network acceleration')
parser.add_argument('--validate-only', action='store_true', help='Only validate setup, do not run')
args = parser.parse_args()
study_dir = Path(__file__).parent
config_path = study_dir / "1_setup" / "optimization_config.json"
if args.validate_only:
from optimization_engine.validators import validate_study
result = validate_study("{study_name}")
print(result)
return
run_study(
config_path=config_path,
n_trials=args.trials,
resume=args.resume,
enable_neural=args.enable_nn
)
if __name__ == "__main__":
main()
'''
def _generate_study_readme(study_name: str, config: Dict[str, Any], template_name: str) -> str:
"""Generate a README.md for the study."""
objectives = config.get("objectives", [])
design_vars = config.get("design_variables", [])
constraints = config.get("constraints", [])
obj_list = "\n".join([f"- **{o.get('name', 'unnamed')}**: {o.get('goal', 'minimize')} - {o.get('description', '')}" for o in objectives])
dv_list = "\n".join([f"- **{d.get('parameter', 'unnamed')}**: [{d.get('bounds', [0, 1])[0]}, {d.get('bounds', [0, 1])[1]}] - {d.get('description', '')}" for d in design_vars])
const_list = "\n".join([f"- **{c.get('name', 'unnamed')}**: {c.get('type', 'less_than')} {c.get('threshold', 0)} - {c.get('description', '')}" for c in constraints])
return f'''# {study_name}
{config.get('description', 'Optimization study')}
**Template**: {template_name}
**Created**: {config.get('created_at', 'unknown')}
## Engineering Context
{config.get('engineering_context', 'No context provided')}
## Objectives
{obj_list if obj_list else 'None defined'}
## Design Variables
{dv_list if dv_list else 'None defined'}
## Constraints
{const_list if const_list else 'None defined'}
## Setup Instructions
1. **Add NX Model Files**
Copy your NX part (.prt), simulation (.sim), and FEM (.fem) files to:
```
1_setup/model/
```
2. **Configure Design Variables**
Edit `1_setup/optimization_config.json`:
- Ensure `design_variables[].parameter` matches your NX expression names
- Adjust bounds to your design space
3. **Validate Setup**
```bash
python run_optimization.py --validate-only
```
## Running the Optimization
### Basic Run
```bash
python run_optimization.py --trials 50
```
### Resume Interrupted Run
```bash
python run_optimization.py --trials 25 --resume
```
### With Neural Network Acceleration
```bash
python run_optimization.py --trials 100 --enable-nn
```
## Results
After optimization, results are saved in `2_results/`:
- `study.db` - Optuna database with all trials
- `history.json` - Trial history
- `optimization_summary.json` - Summary with best parameters
## Visualization
View results with Optuna Dashboard:
```bash
optuna-dashboard sqlite:///2_results/study.db
```
Or generate a report:
```bash
python -m optimization_engine.generate_report {study_name}
```
'''
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Atomizer Template Loader")
subparsers = parser.add_subparsers(dest="command", help="Commands")
# List templates
list_parser = subparsers.add_parser("list", help="List available templates")
# Create study
create_parser = subparsers.add_parser("create", help="Create study from template")
create_parser.add_argument("--template", "-t", required=True, help="Template name")
create_parser.add_argument("--name", "-n", required=True, help="Study name")
args = parser.parse_args()
if args.command == "list":
templates = list_templates()
if not templates:
print("No templates found in templates/")
else:
print("Available templates:")
print("-" * 60)
for t in templates:
print(f" {t['name']}")
print(f" {t['description']}")
print(f" Category: {t['category']} | Analysis: {t['analysis_type']}")
print(f" Design vars: {t['design_variables']} | Objectives: {t['objectives']}")
print()
elif args.command == "create":
try:
study_path = create_study_from_template(
template_name=args.template,
study_name=args.name
)
except (FileNotFoundError, FileExistsError) as e:
print(f"Error: {e}")
sys.exit(1)
else:
parser.print_help()