2025-12-07 05:51:49 -05:00
|
|
|
"""
|
|
|
|
|
Adaptive Method Selector for Atomizer Optimization
|
|
|
|
|
|
|
|
|
|
This module provides intelligent method selection based on:
|
|
|
|
|
1. Problem characteristics (static analysis from config)
|
|
|
|
|
2. Early exploration metrics (dynamic analysis from first N trials)
|
|
|
|
|
3. Runtime performance metrics (continuous monitoring)
|
|
|
|
|
|
|
|
|
|
Classes:
|
|
|
|
|
- ProblemProfiler: Analyzes optimization config to extract problem characteristics
|
|
|
|
|
- EarlyMetricsCollector: Computes metrics from initial FEA trials
|
|
|
|
|
- AdaptiveMethodSelector: Recommends optimization method and parameters
|
|
|
|
|
- RuntimeAdvisor: Monitors optimization and suggests pivots
|
|
|
|
|
|
|
|
|
|
Usage:
|
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>
2025-12-29 12:30:59 -05:00
|
|
|
from optimization_engine.core.method_selector import AdaptiveMethodSelector
|
2025-12-07 05:51:49 -05:00
|
|
|
|
|
|
|
|
selector = AdaptiveMethodSelector()
|
|
|
|
|
recommendation = selector.recommend(config_path)
|
|
|
|
|
print(recommendation['method']) # 'turbo', 'hybrid_loop', 'pure_fea', etc.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import json
|
|
|
|
|
import numpy as np
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
from typing import Dict, List, Optional, Any, Tuple
|
|
|
|
|
from dataclasses import dataclass, field, asdict
|
|
|
|
|
from enum import Enum
|
|
|
|
|
import sqlite3
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OptimizationMethod(Enum):
|
|
|
|
|
"""Available optimization methods."""
|
|
|
|
|
PURE_FEA = "pure_fea"
|
|
|
|
|
HYBRID_LOOP = "hybrid_loop"
|
|
|
|
|
TURBO = "turbo"
|
|
|
|
|
GNN_FIELD = "gnn_field"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
class ProblemProfile:
|
|
|
|
|
"""Static problem characteristics extracted from config."""
|
|
|
|
|
|
|
|
|
|
# Design space
|
|
|
|
|
n_variables: int = 0
|
|
|
|
|
variable_names: List[str] = field(default_factory=list)
|
|
|
|
|
variable_bounds: Dict[str, Tuple[float, float]] = field(default_factory=dict)
|
|
|
|
|
variable_types: Dict[str, str] = field(default_factory=dict) # 'continuous', 'discrete', 'categorical'
|
|
|
|
|
design_space_volume: float = 0.0 # Product of all ranges
|
|
|
|
|
|
|
|
|
|
# Objectives
|
|
|
|
|
n_objectives: int = 0
|
|
|
|
|
objective_names: List[str] = field(default_factory=list)
|
|
|
|
|
objective_goals: Dict[str, str] = field(default_factory=dict) # 'minimize', 'maximize'
|
|
|
|
|
|
|
|
|
|
# Constraints
|
|
|
|
|
n_constraints: int = 0
|
|
|
|
|
constraint_types: List[str] = field(default_factory=list) # 'less_than', 'greater_than', 'equal'
|
|
|
|
|
|
|
|
|
|
# Budget estimates
|
|
|
|
|
fea_time_estimate: float = 300.0 # seconds per FEA run
|
|
|
|
|
total_budget_hours: float = 8.0
|
|
|
|
|
max_fea_trials: int = 0 # Computed from budget
|
|
|
|
|
|
|
|
|
|
# Complexity indicators
|
|
|
|
|
is_multi_objective: bool = False
|
|
|
|
|
has_constraints: bool = False
|
|
|
|
|
expected_nonlinearity: str = "unknown" # 'low', 'medium', 'high', 'unknown'
|
|
|
|
|
|
|
|
|
|
# Neural acceleration hints
|
|
|
|
|
nn_enabled_in_config: bool = False
|
|
|
|
|
min_training_points: int = 50
|
|
|
|
|
|
|
|
|
|
def to_dict(self) -> dict:
|
|
|
|
|
return asdict(self)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
class EarlyMetrics:
|
|
|
|
|
"""Metrics computed from initial FEA exploration."""
|
|
|
|
|
|
|
|
|
|
n_trials_analyzed: int = 0
|
|
|
|
|
|
|
|
|
|
# Objective statistics
|
|
|
|
|
objective_means: Dict[str, float] = field(default_factory=dict)
|
|
|
|
|
objective_stds: Dict[str, float] = field(default_factory=dict)
|
|
|
|
|
objective_ranges: Dict[str, Tuple[float, float]] = field(default_factory=dict)
|
|
|
|
|
coefficient_of_variation: Dict[str, float] = field(default_factory=dict) # std/mean
|
|
|
|
|
|
|
|
|
|
# Correlation analysis
|
|
|
|
|
objective_correlations: Dict[str, float] = field(default_factory=dict) # pairwise
|
|
|
|
|
variable_objective_correlations: Dict[str, Dict[str, float]] = field(default_factory=dict)
|
|
|
|
|
|
|
|
|
|
# Feasibility
|
|
|
|
|
feasibility_rate: float = 1.0
|
|
|
|
|
n_feasible: int = 0
|
|
|
|
|
n_infeasible: int = 0
|
|
|
|
|
|
|
|
|
|
# Pareto analysis (multi-objective)
|
|
|
|
|
pareto_front_size: int = 0
|
|
|
|
|
pareto_growth_rate: float = 0.0 # New Pareto points per trial
|
|
|
|
|
|
|
|
|
|
# Response smoothness (NN suitability)
|
|
|
|
|
response_smoothness: float = 0.5 # 0-1, higher = smoother
|
|
|
|
|
lipschitz_estimate: Dict[str, float] = field(default_factory=dict)
|
|
|
|
|
|
|
|
|
|
# Variable sensitivity
|
|
|
|
|
variable_sensitivity: Dict[str, float] = field(default_factory=dict) # Variance-based
|
|
|
|
|
most_sensitive_variable: str = ""
|
|
|
|
|
|
|
|
|
|
# Clustering
|
|
|
|
|
design_clustering: str = "unknown" # 'clustered', 'scattered', 'unknown'
|
|
|
|
|
|
|
|
|
|
# NN fit quality (if trained)
|
|
|
|
|
nn_accuracy: Optional[float] = None # R² or similar
|
|
|
|
|
nn_mean_error: Optional[Dict[str, float]] = None
|
|
|
|
|
|
|
|
|
|
def to_dict(self) -> dict:
|
|
|
|
|
return asdict(self)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
class RuntimeMetrics:
|
|
|
|
|
"""Metrics collected during optimization runtime."""
|
|
|
|
|
|
|
|
|
|
timestamp: str = ""
|
|
|
|
|
trials_completed: int = 0
|
|
|
|
|
|
|
|
|
|
# Performance
|
|
|
|
|
fea_time_mean: float = 0.0
|
|
|
|
|
fea_time_std: float = 0.0
|
|
|
|
|
fea_failure_rate: float = 0.0
|
|
|
|
|
|
|
|
|
|
# Progress
|
|
|
|
|
pareto_size: int = 0
|
|
|
|
|
pareto_growth_rate: float = 0.0
|
|
|
|
|
best_objectives: Dict[str, float] = field(default_factory=dict)
|
|
|
|
|
improvement_rate: float = 0.0 # Best objective improvement per trial
|
|
|
|
|
|
|
|
|
|
# NN performance (if using hybrid/turbo)
|
|
|
|
|
nn_accuracy: Optional[float] = None
|
|
|
|
|
nn_accuracy_trend: str = "stable" # 'improving', 'stable', 'declining'
|
|
|
|
|
nn_predictions_count: int = 0
|
|
|
|
|
|
|
|
|
|
# Exploration vs exploitation
|
|
|
|
|
exploration_ratio: float = 0.5 # How much of design space explored
|
|
|
|
|
|
|
|
|
|
def to_dict(self) -> dict:
|
|
|
|
|
return asdict(self)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
class MethodRecommendation:
|
|
|
|
|
"""Output from the method selector."""
|
|
|
|
|
|
|
|
|
|
method: str
|
|
|
|
|
confidence: float # 0-1
|
|
|
|
|
parameters: Dict[str, Any] = field(default_factory=dict)
|
|
|
|
|
reasoning: str = ""
|
|
|
|
|
alternatives: List[Dict[str, Any]] = field(default_factory=list)
|
|
|
|
|
warnings: List[str] = field(default_factory=list)
|
|
|
|
|
|
|
|
|
|
def to_dict(self) -> dict:
|
|
|
|
|
return asdict(self)
|
|
|
|
|
|
|
|
|
|
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
@dataclass
|
|
|
|
|
class NNQualityMetrics:
|
|
|
|
|
"""NN surrogate quality metrics with relative thresholds.
|
|
|
|
|
|
|
|
|
|
Key insight: NN error should be compared to the coefficient of variation (CV)
|
|
|
|
|
of each objective to determine if the NN is learning the physics properly.
|
|
|
|
|
|
|
|
|
|
- If nn_error >> CV → NN is unreliable (not learning, just noise)
|
|
|
|
|
- If nn_error ≈ CV → NN captures the trend (hybrid recommended)
|
|
|
|
|
- If nn_error << CV → NN is excellent (turbo viable)
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
has_nn_data: bool = False
|
|
|
|
|
n_validations: int = 0
|
|
|
|
|
|
|
|
|
|
# Per-objective metrics
|
|
|
|
|
nn_errors: Dict[str, float] = field(default_factory=dict) # Absolute % error
|
|
|
|
|
cv_ratios: Dict[str, float] = field(default_factory=dict) # nn_error / (CV * 100)
|
|
|
|
|
expected_errors: Dict[str, float] = field(default_factory=dict) # Based on physics type
|
|
|
|
|
|
|
|
|
|
# Overall quality scores (0-1, higher = better)
|
|
|
|
|
overall_quality: float = 0.5
|
|
|
|
|
turbo_suitability: float = 0.0
|
|
|
|
|
hybrid_suitability: float = 0.5
|
|
|
|
|
|
|
|
|
|
# Physics type classification used
|
|
|
|
|
objective_types: Dict[str, str] = field(default_factory=dict) # 'linear', 'smooth', 'nonlinear', 'chaotic'
|
|
|
|
|
|
|
|
|
|
def to_dict(self) -> dict:
|
|
|
|
|
return asdict(self)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NNQualityAssessor:
|
|
|
|
|
"""Assesses NN surrogate quality relative to problem complexity.
|
|
|
|
|
|
|
|
|
|
Uses physics-based expected error thresholds rather than absolute values.
|
|
|
|
|
The key metric is the CV ratio: nn_error / coefficient_of_variation.
|
|
|
|
|
|
|
|
|
|
CV Ratio Interpretation:
|
|
|
|
|
- < 0.5 → NN is excellent (captures physics well beyond noise)
|
|
|
|
|
- 0.5-1 → NN is good (adds value for exploration)
|
|
|
|
|
- 1-2 → NN is marginal (use with validation)
|
|
|
|
|
- > 2 → NN is poor (not learning physics, use FEA)
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# Physics-based expected error thresholds
|
|
|
|
|
PHYSICS_THRESHOLDS = {
|
|
|
|
|
'linear': {'max_error': 2.0, 'cv_ratio_max': 0.5}, # mass, volume - deterministic
|
|
|
|
|
'smooth': {'max_error': 5.0, 'cv_ratio_max': 1.0}, # frequency, avg stress
|
|
|
|
|
'nonlinear': {'max_error': 10.0, 'cv_ratio_max': 2.0}, # max stress, stiffness
|
|
|
|
|
'chaotic': {'max_error': 20.0, 'cv_ratio_max': 3.0}, # contact, buckling, fracture
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Objective name to physics type classification
|
|
|
|
|
OBJECTIVE_CLASSIFICATION = {
|
|
|
|
|
# Linear (deterministic, easy to learn)
|
|
|
|
|
'mass': 'linear',
|
|
|
|
|
'volume': 'linear',
|
|
|
|
|
'weight': 'linear',
|
|
|
|
|
'area': 'linear',
|
|
|
|
|
|
|
|
|
|
# Smooth (well-behaved, moderate difficulty)
|
|
|
|
|
'frequency': 'smooth',
|
|
|
|
|
'fundamental_frequency': 'smooth',
|
|
|
|
|
'first_frequency': 'smooth',
|
|
|
|
|
'avg_stress': 'smooth',
|
|
|
|
|
'mean_stress': 'smooth',
|
|
|
|
|
'displacement': 'smooth',
|
|
|
|
|
'avg_displacement': 'smooth',
|
|
|
|
|
'compliance': 'smooth',
|
|
|
|
|
|
|
|
|
|
# Nonlinear (sensitive to details, harder to learn)
|
|
|
|
|
'stress': 'nonlinear',
|
|
|
|
|
'max_stress': 'nonlinear',
|
|
|
|
|
'von_mises': 'nonlinear',
|
|
|
|
|
'stiffness': 'nonlinear',
|
|
|
|
|
'max_displacement': 'nonlinear',
|
|
|
|
|
'strain_energy': 'nonlinear',
|
|
|
|
|
|
|
|
|
|
# Chaotic (highly nonlinear, very hard to learn)
|
|
|
|
|
'buckling': 'chaotic',
|
|
|
|
|
'contact_force': 'chaotic',
|
|
|
|
|
'fracture': 'chaotic',
|
|
|
|
|
'fatigue': 'chaotic',
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def collect(self, results_dir: Path, objective_names: List[str],
|
|
|
|
|
early_metrics: EarlyMetrics) -> NNQualityMetrics:
|
|
|
|
|
"""Collect NN quality metrics from validation reports and database.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
results_dir: Path to 2_results directory
|
|
|
|
|
objective_names: List of objective names from config
|
|
|
|
|
early_metrics: EarlyMetrics with coefficient_of_variation data
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
NNQualityMetrics with quality scores and recommendations
|
|
|
|
|
"""
|
|
|
|
|
metrics = NNQualityMetrics()
|
|
|
|
|
|
|
|
|
|
# 1. Try validation_report.json first (most reliable - has explicit FEA comparison)
|
|
|
|
|
validation_report = results_dir / "validation_report.json"
|
|
|
|
|
if validation_report.exists():
|
|
|
|
|
self._load_from_validation_report(validation_report, metrics, objective_names)
|
|
|
|
|
|
|
|
|
|
# 2. Try turbo_report.json (has per-iteration errors)
|
|
|
|
|
turbo_report = results_dir / "turbo_report.json"
|
|
|
|
|
if turbo_report.exists() and not metrics.has_nn_data:
|
|
|
|
|
self._load_from_turbo_report(turbo_report, metrics, objective_names)
|
|
|
|
|
|
|
|
|
|
# 3. Query Optuna database for nn_error_percent user attributes
|
|
|
|
|
db_path = results_dir / "study.db"
|
|
|
|
|
if db_path.exists() and not metrics.has_nn_data:
|
|
|
|
|
self._load_from_database(db_path, metrics, objective_names)
|
|
|
|
|
|
|
|
|
|
# 4. Compute relative metrics using CV from early_metrics
|
|
|
|
|
if metrics.has_nn_data and early_metrics.coefficient_of_variation:
|
|
|
|
|
self._compute_relative_metrics(metrics, early_metrics, objective_names)
|
|
|
|
|
|
|
|
|
|
return metrics
|
|
|
|
|
|
|
|
|
|
def _load_from_validation_report(self, report_path: Path, metrics: NNQualityMetrics,
|
|
|
|
|
objective_names: List[str]):
|
|
|
|
|
"""Load NN error data from validation_report.json."""
|
|
|
|
|
try:
|
|
|
|
|
with open(report_path) as f:
|
|
|
|
|
report = json.load(f)
|
|
|
|
|
|
|
|
|
|
metrics.n_validations = report.get('n_validated', 0)
|
|
|
|
|
|
|
|
|
|
# Get average errors per objective
|
|
|
|
|
avg_errors = report.get('average_errors_percent', {})
|
|
|
|
|
if avg_errors:
|
|
|
|
|
metrics.has_nn_data = True
|
|
|
|
|
for obj_name in objective_names:
|
|
|
|
|
# Try exact match or partial match
|
|
|
|
|
error = avg_errors.get(obj_name)
|
|
|
|
|
if error is None:
|
|
|
|
|
# Try partial match (e.g., 'mass' in 'total_mass')
|
|
|
|
|
for key, val in avg_errors.items():
|
|
|
|
|
if obj_name.lower() in key.lower() or key.lower() in obj_name.lower():
|
|
|
|
|
error = val
|
|
|
|
|
break
|
|
|
|
|
if error is not None:
|
|
|
|
|
metrics.nn_errors[obj_name] = float(error)
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
pass # Silently fail, try other sources
|
|
|
|
|
|
|
|
|
|
def _load_from_turbo_report(self, report_path: Path, metrics: NNQualityMetrics,
|
|
|
|
|
objective_names: List[str]):
|
|
|
|
|
"""Load NN error data from turbo_report.json."""
|
|
|
|
|
try:
|
|
|
|
|
with open(report_path) as f:
|
|
|
|
|
report = json.load(f)
|
|
|
|
|
|
|
|
|
|
metrics.n_validations = report.get('fea_validations', 0)
|
|
|
|
|
best_solutions = report.get('best_solutions', [])
|
|
|
|
|
|
|
|
|
|
if best_solutions:
|
|
|
|
|
metrics.has_nn_data = True
|
|
|
|
|
|
|
|
|
|
# Collect errors from all iterations
|
|
|
|
|
all_errors = []
|
|
|
|
|
for sol in best_solutions:
|
|
|
|
|
nn_error = sol.get('nn_error', [])
|
|
|
|
|
if nn_error:
|
|
|
|
|
all_errors.append(nn_error)
|
|
|
|
|
|
|
|
|
|
if all_errors:
|
|
|
|
|
# Average across all validations
|
|
|
|
|
avg_errors = np.mean(all_errors, axis=0)
|
|
|
|
|
# Map to objective names (turbo only tracks mass, stress typically)
|
|
|
|
|
for i, obj_name in enumerate(objective_names[:len(avg_errors)]):
|
|
|
|
|
metrics.nn_errors[obj_name] = float(avg_errors[i])
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def _load_from_database(self, db_path: Path, metrics: NNQualityMetrics,
|
|
|
|
|
objective_names: List[str]):
|
|
|
|
|
"""Load NN error data from Optuna database user attributes."""
|
|
|
|
|
try:
|
|
|
|
|
conn = sqlite3.connect(str(db_path))
|
|
|
|
|
cursor = conn.cursor()
|
|
|
|
|
|
|
|
|
|
# Query nn_error_percent from trial_user_attributes
|
|
|
|
|
cursor.execute("""
|
|
|
|
|
SELECT value_json FROM trial_user_attributes
|
|
|
|
|
WHERE key = 'nn_error_percent'
|
|
|
|
|
""")
|
|
|
|
|
|
|
|
|
|
all_errors = []
|
|
|
|
|
for (value_json,) in cursor.fetchall():
|
|
|
|
|
try:
|
|
|
|
|
errors = json.loads(value_json)
|
|
|
|
|
if isinstance(errors, list):
|
|
|
|
|
all_errors.append(errors)
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
conn.close()
|
|
|
|
|
|
|
|
|
|
if all_errors:
|
|
|
|
|
metrics.has_nn_data = True
|
|
|
|
|
metrics.n_validations = len(all_errors)
|
|
|
|
|
|
|
|
|
|
# Average across all validated trials
|
|
|
|
|
avg_errors = np.mean(all_errors, axis=0)
|
|
|
|
|
for i, obj_name in enumerate(objective_names[:len(avg_errors)]):
|
|
|
|
|
metrics.nn_errors[obj_name] = float(avg_errors[i])
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def _classify_objective(self, obj_name: str) -> str:
|
|
|
|
|
"""Classify objective by physics type."""
|
|
|
|
|
# Check exact match first
|
|
|
|
|
if obj_name in self.OBJECTIVE_CLASSIFICATION:
|
|
|
|
|
return self.OBJECTIVE_CLASSIFICATION[obj_name]
|
|
|
|
|
|
|
|
|
|
# Check partial match
|
|
|
|
|
obj_lower = obj_name.lower()
|
|
|
|
|
for key, obj_type in self.OBJECTIVE_CLASSIFICATION.items():
|
|
|
|
|
if key in obj_lower or obj_lower in key:
|
|
|
|
|
return obj_type
|
|
|
|
|
|
|
|
|
|
# Default to 'smooth' if unknown
|
|
|
|
|
return 'smooth'
|
|
|
|
|
|
|
|
|
|
def _compute_relative_metrics(self, metrics: NNQualityMetrics,
|
|
|
|
|
early_metrics: EarlyMetrics,
|
|
|
|
|
objective_names: List[str]):
|
|
|
|
|
"""Compute NN error relative to objective variability (CV)."""
|
|
|
|
|
|
|
|
|
|
for obj_name in objective_names:
|
|
|
|
|
nn_error = metrics.nn_errors.get(obj_name)
|
|
|
|
|
if nn_error is None:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
cv = early_metrics.coefficient_of_variation.get(obj_name, 0.1)
|
|
|
|
|
|
|
|
|
|
# Compute CV ratio (nn_error is %, cv is fraction)
|
|
|
|
|
# CV ratio = how many times larger is NN error than natural variability
|
|
|
|
|
if cv > 0.001:
|
|
|
|
|
cv_ratio = nn_error / (cv * 100)
|
|
|
|
|
else:
|
|
|
|
|
# Very low CV means linear/deterministic - use absolute error
|
|
|
|
|
cv_ratio = nn_error / 2.0 # Normalize to 2% baseline
|
|
|
|
|
|
|
|
|
|
metrics.cv_ratios[obj_name] = cv_ratio
|
|
|
|
|
|
|
|
|
|
# Classify and store
|
|
|
|
|
obj_type = self._classify_objective(obj_name)
|
|
|
|
|
metrics.objective_types[obj_name] = obj_type
|
|
|
|
|
metrics.expected_errors[obj_name] = self.PHYSICS_THRESHOLDS[obj_type]['max_error']
|
|
|
|
|
|
|
|
|
|
# Compute overall quality scores
|
|
|
|
|
self._compute_quality_scores(metrics)
|
|
|
|
|
|
|
|
|
|
def _compute_quality_scores(self, metrics: NNQualityMetrics):
|
|
|
|
|
"""Compute overall quality scores based on relative metrics."""
|
|
|
|
|
|
|
|
|
|
if not metrics.cv_ratios:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
quality_scores = []
|
|
|
|
|
turbo_scores = []
|
|
|
|
|
hybrid_scores = []
|
|
|
|
|
|
|
|
|
|
for obj_name, cv_ratio in metrics.cv_ratios.items():
|
|
|
|
|
obj_type = metrics.objective_types.get(obj_name, 'smooth')
|
|
|
|
|
threshold = self.PHYSICS_THRESHOLDS[obj_type]
|
|
|
|
|
|
|
|
|
|
# Quality: how well does NN error compare to expected max?
|
|
|
|
|
nn_error = metrics.nn_errors.get(obj_name, 0)
|
|
|
|
|
expected = threshold['max_error']
|
|
|
|
|
# Use sqrt to be less harsh on errors close to threshold
|
|
|
|
|
quality = max(0, min(1, 1 - (nn_error / expected) ** 0.5)) if expected > 0 else 0.5
|
|
|
|
|
quality_scores.append(quality)
|
|
|
|
|
|
|
|
|
|
# Turbo suitability: cv_ratio should be < cv_ratio_max
|
|
|
|
|
# Lower ratio = better (NN captures more than noise)
|
|
|
|
|
cv_max = threshold['cv_ratio_max']
|
|
|
|
|
turbo = max(0, min(1, 1 - cv_ratio / cv_max)) if cv_max > 0 else 0.5
|
|
|
|
|
turbo_scores.append(turbo)
|
|
|
|
|
|
|
|
|
|
# Hybrid suitability: more lenient threshold (2x)
|
|
|
|
|
# NN just needs to add some value
|
|
|
|
|
hybrid = max(0, min(1, 1 - cv_ratio / (cv_max * 2))) if cv_max > 0 else 0.5
|
|
|
|
|
hybrid_scores.append(hybrid)
|
|
|
|
|
|
|
|
|
|
metrics.overall_quality = float(np.mean(quality_scores)) if quality_scores else 0.5
|
|
|
|
|
metrics.turbo_suitability = float(np.mean(turbo_scores)) if turbo_scores else 0.0
|
|
|
|
|
metrics.hybrid_suitability = float(np.mean(hybrid_scores)) if hybrid_scores else 0.5
|
|
|
|
|
|
|
|
|
|
|
2025-12-07 05:51:49 -05:00
|
|
|
class ProblemProfiler:
|
|
|
|
|
"""Analyzes optimization config to extract problem characteristics."""
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.profile = ProblemProfile()
|
|
|
|
|
|
|
|
|
|
def analyze(self, config: dict) -> ProblemProfile:
|
|
|
|
|
"""
|
|
|
|
|
Analyze optimization config and return problem profile.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
config: Loaded optimization_config.json dict
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
ProblemProfile with extracted characteristics
|
|
|
|
|
"""
|
|
|
|
|
profile = ProblemProfile()
|
|
|
|
|
|
|
|
|
|
# Extract design variables
|
|
|
|
|
design_vars = config.get('design_variables', [])
|
|
|
|
|
profile.n_variables = len(design_vars)
|
2025-12-07 19:10:45 -05:00
|
|
|
# Support both 'parameter' and 'name' keys for variable naming
|
|
|
|
|
profile.variable_names = [v.get('parameter') or v.get('name') for v in design_vars]
|
2025-12-07 05:51:49 -05:00
|
|
|
|
|
|
|
|
volume = 1.0
|
|
|
|
|
for var in design_vars:
|
2025-12-07 19:10:45 -05:00
|
|
|
name = var.get('parameter') or var.get('name')
|
|
|
|
|
# Support both 'bounds' array and 'min'/'max' fields
|
|
|
|
|
if 'bounds' in var:
|
|
|
|
|
bounds = var['bounds']
|
|
|
|
|
else:
|
|
|
|
|
bounds = [var.get('min', 0), var.get('max', 1)]
|
2025-12-07 05:51:49 -05:00
|
|
|
profile.variable_bounds[name] = (bounds[0], bounds[1])
|
|
|
|
|
profile.variable_types[name] = var.get('type', 'continuous')
|
|
|
|
|
volume *= (bounds[1] - bounds[0])
|
|
|
|
|
profile.design_space_volume = volume
|
|
|
|
|
|
|
|
|
|
# Extract objectives
|
|
|
|
|
objectives = config.get('objectives', [])
|
|
|
|
|
profile.n_objectives = len(objectives)
|
|
|
|
|
profile.objective_names = [o['name'] for o in objectives]
|
2025-12-07 19:10:45 -05:00
|
|
|
# Support both 'goal' and 'direction' keys for objective direction
|
|
|
|
|
profile.objective_goals = {
|
|
|
|
|
o['name']: o.get('goal') or o.get('direction', 'minimize')
|
|
|
|
|
for o in objectives
|
|
|
|
|
}
|
2025-12-07 05:51:49 -05:00
|
|
|
profile.is_multi_objective = profile.n_objectives > 1
|
|
|
|
|
|
|
|
|
|
# Extract constraints
|
|
|
|
|
constraints = config.get('constraints', [])
|
|
|
|
|
profile.n_constraints = len(constraints)
|
|
|
|
|
profile.constraint_types = [c.get('type', 'less_than') for c in constraints]
|
|
|
|
|
profile.has_constraints = profile.n_constraints > 0
|
|
|
|
|
|
|
|
|
|
# Budget estimates
|
|
|
|
|
opt_settings = config.get('optimization_settings', {})
|
|
|
|
|
profile.fea_time_estimate = opt_settings.get('timeout_per_trial', 300)
|
|
|
|
|
profile.total_budget_hours = opt_settings.get('budget_hours', 8)
|
|
|
|
|
|
|
|
|
|
if profile.fea_time_estimate > 0:
|
|
|
|
|
profile.max_fea_trials = int(
|
|
|
|
|
(profile.total_budget_hours * 3600) / profile.fea_time_estimate
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Neural acceleration config
|
|
|
|
|
nn_config = config.get('neural_acceleration', {})
|
|
|
|
|
profile.nn_enabled_in_config = nn_config.get('enabled', False)
|
|
|
|
|
profile.min_training_points = nn_config.get('min_training_points', 50)
|
|
|
|
|
|
|
|
|
|
# Infer nonlinearity from physics type
|
|
|
|
|
sim_config = config.get('simulation', {})
|
|
|
|
|
analysis_types = sim_config.get('analysis_types', [])
|
|
|
|
|
|
|
|
|
|
if 'modal' in analysis_types or 'frequency' in str(analysis_types).lower():
|
|
|
|
|
profile.expected_nonlinearity = 'medium'
|
|
|
|
|
elif 'nonlinear' in str(analysis_types).lower():
|
|
|
|
|
profile.expected_nonlinearity = 'high'
|
|
|
|
|
else:
|
|
|
|
|
profile.expected_nonlinearity = 'low' # Static linear
|
|
|
|
|
|
|
|
|
|
self.profile = profile
|
|
|
|
|
return profile
|
|
|
|
|
|
|
|
|
|
def analyze_from_file(self, config_path: Path) -> ProblemProfile:
|
|
|
|
|
"""Load config from file and analyze."""
|
|
|
|
|
with open(config_path) as f:
|
|
|
|
|
config = json.load(f)
|
|
|
|
|
return self.analyze(config)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EarlyMetricsCollector:
|
|
|
|
|
"""Computes metrics from initial FEA exploration trials."""
|
|
|
|
|
|
|
|
|
|
def __init__(self, min_trials: int = 20):
|
|
|
|
|
self.min_trials = min_trials
|
|
|
|
|
self.metrics = EarlyMetrics()
|
|
|
|
|
|
|
|
|
|
def collect(self, db_path: Path, objective_names: List[str],
|
|
|
|
|
variable_names: List[str], constraints: List[dict] = None) -> EarlyMetrics:
|
|
|
|
|
"""
|
|
|
|
|
Collect metrics from study database.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
db_path: Path to study.db
|
|
|
|
|
objective_names: List of objective column names
|
|
|
|
|
variable_names: List of design variable names
|
|
|
|
|
constraints: List of constraint definitions from config
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
EarlyMetrics with computed statistics
|
|
|
|
|
"""
|
|
|
|
|
metrics = EarlyMetrics()
|
|
|
|
|
|
|
|
|
|
if not db_path.exists():
|
|
|
|
|
return metrics
|
|
|
|
|
|
|
|
|
|
# Load data from Optuna database
|
|
|
|
|
conn = sqlite3.connect(str(db_path))
|
|
|
|
|
cursor = conn.cursor()
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# Get completed trials from Optuna database
|
|
|
|
|
# Note: Optuna stores params in trial_params and objectives in trial_values
|
|
|
|
|
cursor.execute("""
|
|
|
|
|
SELECT trial_id FROM trials
|
|
|
|
|
WHERE state = 'COMPLETE'
|
|
|
|
|
""")
|
|
|
|
|
completed_trials = cursor.fetchall()
|
|
|
|
|
metrics.n_trials_analyzed = len(completed_trials)
|
|
|
|
|
|
|
|
|
|
if metrics.n_trials_analyzed < self.min_trials:
|
|
|
|
|
conn.close()
|
|
|
|
|
return metrics
|
|
|
|
|
|
|
|
|
|
# Extract trial data from trial_params and trial_values tables
|
|
|
|
|
trial_data = []
|
|
|
|
|
for (trial_id,) in completed_trials:
|
|
|
|
|
values = {}
|
|
|
|
|
|
|
|
|
|
# Get parameters
|
|
|
|
|
cursor.execute("""
|
|
|
|
|
SELECT param_name, param_value FROM trial_params
|
|
|
|
|
WHERE trial_id = ?
|
|
|
|
|
""", (trial_id,))
|
|
|
|
|
for name, value in cursor.fetchall():
|
|
|
|
|
try:
|
|
|
|
|
values[name] = float(value) if value is not None else None
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
# Get objectives from trial_values
|
|
|
|
|
cursor.execute("""
|
|
|
|
|
SELECT objective, value FROM trial_values
|
|
|
|
|
WHERE trial_id = ?
|
|
|
|
|
""", (trial_id,))
|
|
|
|
|
for idx, value in cursor.fetchall():
|
|
|
|
|
if idx < len(objective_names):
|
|
|
|
|
values[objective_names[idx]] = float(value) if value is not None else None
|
|
|
|
|
|
|
|
|
|
if values:
|
|
|
|
|
trial_data.append(values)
|
|
|
|
|
|
|
|
|
|
if not trial_data:
|
|
|
|
|
conn.close()
|
|
|
|
|
return metrics
|
|
|
|
|
|
|
|
|
|
# Compute objective statistics
|
|
|
|
|
for obj_name in objective_names:
|
|
|
|
|
obj_values = [t.get(obj_name) for t in trial_data if t.get(obj_name) is not None]
|
|
|
|
|
if obj_values:
|
|
|
|
|
metrics.objective_means[obj_name] = np.mean(obj_values)
|
|
|
|
|
metrics.objective_stds[obj_name] = np.std(obj_values)
|
|
|
|
|
metrics.objective_ranges[obj_name] = (min(obj_values), max(obj_values))
|
|
|
|
|
|
|
|
|
|
if metrics.objective_means[obj_name] != 0:
|
|
|
|
|
metrics.coefficient_of_variation[obj_name] = (
|
|
|
|
|
metrics.objective_stds[obj_name] /
|
|
|
|
|
abs(metrics.objective_means[obj_name])
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Compute correlations between objectives
|
|
|
|
|
if len(objective_names) >= 2:
|
|
|
|
|
for i, obj1 in enumerate(objective_names):
|
|
|
|
|
for obj2 in objective_names[i+1:]:
|
|
|
|
|
vals1 = [t.get(obj1) for t in trial_data]
|
|
|
|
|
vals2 = [t.get(obj2) for t in trial_data]
|
|
|
|
|
|
|
|
|
|
# Filter out None values
|
|
|
|
|
paired = [(v1, v2) for v1, v2 in zip(vals1, vals2)
|
|
|
|
|
if v1 is not None and v2 is not None]
|
|
|
|
|
|
|
|
|
|
if len(paired) > 5:
|
|
|
|
|
v1, v2 = zip(*paired)
|
|
|
|
|
corr = np.corrcoef(v1, v2)[0, 1]
|
|
|
|
|
metrics.objective_correlations[f"{obj1}_vs_{obj2}"] = corr
|
|
|
|
|
|
|
|
|
|
# Compute variable-objective correlations (sensitivity)
|
|
|
|
|
for var_name in variable_names:
|
|
|
|
|
metrics.variable_objective_correlations[var_name] = {}
|
|
|
|
|
var_values = [t.get(var_name) for t in trial_data]
|
|
|
|
|
|
|
|
|
|
for obj_name in objective_names:
|
|
|
|
|
obj_values = [t.get(obj_name) for t in trial_data]
|
|
|
|
|
|
|
|
|
|
paired = [(v, o) for v, o in zip(var_values, obj_values)
|
|
|
|
|
if v is not None and o is not None]
|
|
|
|
|
|
|
|
|
|
if len(paired) > 5:
|
|
|
|
|
v, o = zip(*paired)
|
|
|
|
|
corr = abs(np.corrcoef(v, o)[0, 1])
|
|
|
|
|
metrics.variable_objective_correlations[var_name][obj_name] = corr
|
|
|
|
|
|
|
|
|
|
# Compute overall variable sensitivity (average absolute correlation)
|
|
|
|
|
for var_name in variable_names:
|
|
|
|
|
correlations = list(metrics.variable_objective_correlations.get(var_name, {}).values())
|
|
|
|
|
if correlations:
|
|
|
|
|
metrics.variable_sensitivity[var_name] = np.mean(correlations)
|
|
|
|
|
|
|
|
|
|
if metrics.variable_sensitivity:
|
|
|
|
|
metrics.most_sensitive_variable = max(
|
|
|
|
|
metrics.variable_sensitivity,
|
|
|
|
|
key=metrics.variable_sensitivity.get
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Estimate response smoothness
|
|
|
|
|
# Higher CV suggests rougher landscape
|
|
|
|
|
avg_cv = np.mean(list(metrics.coefficient_of_variation.values())) if metrics.coefficient_of_variation else 0.5
|
|
|
|
|
metrics.response_smoothness = max(0, min(1, 1 - avg_cv))
|
|
|
|
|
|
|
|
|
|
# Feasibility analysis
|
|
|
|
|
if constraints:
|
|
|
|
|
n_feasible = 0
|
|
|
|
|
for trial in trial_data:
|
|
|
|
|
feasible = True
|
|
|
|
|
for constraint in constraints:
|
|
|
|
|
c_name = constraint.get('name')
|
|
|
|
|
c_type = constraint.get('type', 'less_than')
|
|
|
|
|
threshold = constraint.get('threshold')
|
|
|
|
|
|
|
|
|
|
value = trial.get(c_name)
|
|
|
|
|
if value is not None and threshold is not None:
|
|
|
|
|
if c_type == 'less_than' and value > threshold:
|
|
|
|
|
feasible = False
|
|
|
|
|
elif c_type == 'greater_than' and value < threshold:
|
|
|
|
|
feasible = False
|
|
|
|
|
|
|
|
|
|
if feasible:
|
|
|
|
|
n_feasible += 1
|
|
|
|
|
|
|
|
|
|
metrics.n_feasible = n_feasible
|
|
|
|
|
metrics.n_infeasible = len(trial_data) - n_feasible
|
|
|
|
|
metrics.feasibility_rate = n_feasible / len(trial_data) if trial_data else 1.0
|
|
|
|
|
|
|
|
|
|
conn.close()
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(f"Warning: Error collecting metrics: {e}")
|
|
|
|
|
conn.close()
|
|
|
|
|
|
|
|
|
|
self.metrics = metrics
|
|
|
|
|
return metrics
|
|
|
|
|
|
|
|
|
|
def estimate_nn_suitability(self) -> float:
|
|
|
|
|
"""
|
|
|
|
|
Estimate how suitable the problem is for neural network acceleration.
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
Score from 0-1, higher = more suitable
|
|
|
|
|
"""
|
|
|
|
|
score = 0.5 # Base score
|
|
|
|
|
|
|
|
|
|
# Smooth response is good for NN
|
|
|
|
|
score += 0.2 * self.metrics.response_smoothness
|
|
|
|
|
|
|
|
|
|
# High feasibility is good
|
|
|
|
|
score += 0.1 * self.metrics.feasibility_rate
|
|
|
|
|
|
|
|
|
|
# Enough training data
|
|
|
|
|
if self.metrics.n_trials_analyzed >= 50:
|
|
|
|
|
score += 0.1
|
|
|
|
|
if self.metrics.n_trials_analyzed >= 100:
|
|
|
|
|
score += 0.1
|
|
|
|
|
|
|
|
|
|
return min(1.0, max(0.0, score))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AdaptiveMethodSelector:
|
|
|
|
|
"""
|
|
|
|
|
Recommends optimization method based on problem characteristics and metrics.
|
|
|
|
|
|
|
|
|
|
The selector uses a scoring system to rank methods:
|
|
|
|
|
- Each method starts with a base score
|
|
|
|
|
- Scores are adjusted based on problem characteristics
|
|
|
|
|
- Early metrics further refine the recommendation
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
- NN quality metrics adjust confidence based on actual surrogate performance
|
2025-12-07 05:51:49 -05:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.profiler = ProblemProfiler()
|
|
|
|
|
self.metrics_collector = EarlyMetricsCollector()
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
self.nn_quality_assessor = NNQualityAssessor()
|
2025-12-07 05:51:49 -05:00
|
|
|
|
|
|
|
|
# Method base scores (can be tuned based on historical performance)
|
|
|
|
|
self.base_scores = {
|
|
|
|
|
OptimizationMethod.PURE_FEA: 0.5,
|
|
|
|
|
OptimizationMethod.HYBRID_LOOP: 0.6,
|
|
|
|
|
OptimizationMethod.TURBO: 0.7,
|
|
|
|
|
OptimizationMethod.GNN_FIELD: 0.4,
|
|
|
|
|
}
|
|
|
|
|
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
# Store last metrics for reporting
|
|
|
|
|
self.last_nn_quality: Optional[NNQualityMetrics] = None
|
|
|
|
|
self.last_early_metrics: Optional[EarlyMetrics] = None
|
|
|
|
|
|
2025-12-07 05:51:49 -05:00
|
|
|
def recommend(self, config: dict, db_path: Path = None,
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
early_metrics: EarlyMetrics = None,
|
|
|
|
|
results_dir: Path = None) -> MethodRecommendation:
|
2025-12-07 05:51:49 -05:00
|
|
|
"""
|
|
|
|
|
Generate method recommendation.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
config: Optimization config dict
|
|
|
|
|
db_path: Optional path to existing study.db for early metrics
|
|
|
|
|
early_metrics: Pre-computed early metrics (optional)
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
results_dir: Optional path to 2_results directory for NN quality data
|
2025-12-07 05:51:49 -05:00
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
MethodRecommendation with method, confidence, and parameters
|
|
|
|
|
"""
|
|
|
|
|
# Profile the problem
|
|
|
|
|
profile = self.profiler.analyze(config)
|
|
|
|
|
|
|
|
|
|
# Collect early metrics if database exists
|
|
|
|
|
if db_path and db_path.exists() and early_metrics is None:
|
|
|
|
|
early_metrics = self.metrics_collector.collect(
|
|
|
|
|
db_path,
|
|
|
|
|
profile.objective_names,
|
|
|
|
|
profile.variable_names,
|
|
|
|
|
config.get('constraints', [])
|
|
|
|
|
)
|
|
|
|
|
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
# Collect NN quality metrics if results directory exists
|
|
|
|
|
nn_quality = None
|
|
|
|
|
if results_dir is None and db_path:
|
|
|
|
|
results_dir = db_path.parent # study.db is typically in 2_results
|
|
|
|
|
|
|
|
|
|
if results_dir and results_dir.exists() and early_metrics:
|
|
|
|
|
nn_quality = self.nn_quality_assessor.collect(
|
|
|
|
|
results_dir,
|
|
|
|
|
profile.objective_names,
|
|
|
|
|
early_metrics
|
|
|
|
|
)
|
|
|
|
|
self.last_nn_quality = nn_quality
|
|
|
|
|
|
|
|
|
|
# Store early_metrics for reporting
|
|
|
|
|
self.last_early_metrics = early_metrics
|
|
|
|
|
|
|
|
|
|
# Score each method (now includes NN quality)
|
|
|
|
|
scores = self._score_methods(profile, early_metrics, nn_quality)
|
2025-12-07 05:51:49 -05:00
|
|
|
|
|
|
|
|
# Sort by score
|
|
|
|
|
ranked = sorted(scores.items(), key=lambda x: x[1]['score'], reverse=True)
|
|
|
|
|
|
|
|
|
|
# Build recommendation
|
|
|
|
|
best_method, best_info = ranked[0]
|
|
|
|
|
|
|
|
|
|
recommendation = MethodRecommendation(
|
|
|
|
|
method=best_method.value,
|
|
|
|
|
confidence=min(1.0, best_info['score']),
|
|
|
|
|
parameters=self._get_parameters(best_method, profile, early_metrics),
|
|
|
|
|
reasoning=best_info['reason'],
|
|
|
|
|
alternatives=[
|
|
|
|
|
{
|
|
|
|
|
'method': m.value,
|
|
|
|
|
'confidence': min(1.0, info['score']),
|
|
|
|
|
'reason': info['reason']
|
|
|
|
|
}
|
|
|
|
|
for m, info in ranked[1:3]
|
|
|
|
|
],
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
warnings=self._get_warnings(profile, early_metrics, nn_quality)
|
2025-12-07 05:51:49 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return recommendation
|
|
|
|
|
|
|
|
|
|
def _score_methods(self, profile: ProblemProfile,
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
metrics: EarlyMetrics = None,
|
|
|
|
|
nn_quality: NNQualityMetrics = None) -> Dict[OptimizationMethod, Dict]:
|
|
|
|
|
"""Score each method based on problem characteristics and NN quality."""
|
2025-12-07 05:51:49 -05:00
|
|
|
|
|
|
|
|
scores = {}
|
|
|
|
|
|
|
|
|
|
for method in OptimizationMethod:
|
|
|
|
|
score = self.base_scores[method]
|
|
|
|
|
reasons = []
|
|
|
|
|
|
|
|
|
|
# === TURBO MODE ===
|
|
|
|
|
if method == OptimizationMethod.TURBO:
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
# Good for: low-dimensional, smooth, sufficient budget, good NN quality
|
2025-12-07 05:51:49 -05:00
|
|
|
|
|
|
|
|
if profile.n_variables <= 5:
|
|
|
|
|
score += 0.15
|
|
|
|
|
reasons.append("low-dimensional design space")
|
|
|
|
|
elif profile.n_variables > 10:
|
|
|
|
|
score -= 0.2
|
|
|
|
|
reasons.append("high-dimensional (may struggle)")
|
|
|
|
|
|
|
|
|
|
if profile.max_fea_trials >= 50:
|
|
|
|
|
score += 0.1
|
|
|
|
|
reasons.append("sufficient FEA budget")
|
|
|
|
|
else:
|
|
|
|
|
score -= 0.15
|
|
|
|
|
reasons.append("limited FEA budget")
|
|
|
|
|
|
|
|
|
|
if metrics and metrics.response_smoothness > 0.7:
|
|
|
|
|
score += 0.15
|
|
|
|
|
reasons.append(f"smooth landscape ({metrics.response_smoothness:.0%})")
|
|
|
|
|
elif metrics and metrics.response_smoothness < 0.4:
|
|
|
|
|
score -= 0.2
|
|
|
|
|
reasons.append(f"rough landscape ({metrics.response_smoothness:.0%})")
|
|
|
|
|
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
# NEW: NN Quality-based adjustments using relative thresholds
|
|
|
|
|
if nn_quality and nn_quality.has_nn_data:
|
|
|
|
|
if nn_quality.turbo_suitability > 0.8:
|
|
|
|
|
score += 0.25
|
|
|
|
|
reasons.append(f"excellent NN quality ({nn_quality.turbo_suitability:.0%})")
|
|
|
|
|
elif nn_quality.turbo_suitability > 0.5:
|
|
|
|
|
score += 0.1
|
|
|
|
|
reasons.append(f"good NN quality ({nn_quality.turbo_suitability:.0%})")
|
|
|
|
|
elif nn_quality.turbo_suitability < 0.3:
|
|
|
|
|
score -= 0.25
|
|
|
|
|
reasons.append(f"poor NN quality ({nn_quality.turbo_suitability:.0%}) - use hybrid")
|
|
|
|
|
|
|
|
|
|
# Per-objective warnings for high CV ratios
|
|
|
|
|
for obj, cv_ratio in nn_quality.cv_ratios.items():
|
|
|
|
|
if cv_ratio > 2.0:
|
|
|
|
|
score -= 0.1
|
|
|
|
|
reasons.append(f"{obj}: NN error >> variability")
|
|
|
|
|
elif metrics and metrics.nn_accuracy and metrics.nn_accuracy > 0.9:
|
2025-12-07 05:51:49 -05:00
|
|
|
score += 0.1
|
|
|
|
|
reasons.append(f"excellent NN fit ({metrics.nn_accuracy:.0%})")
|
|
|
|
|
|
|
|
|
|
# === HYBRID LOOP ===
|
|
|
|
|
elif method == OptimizationMethod.HYBRID_LOOP:
|
|
|
|
|
# Good for: moderate complexity, unknown landscape, need safety
|
|
|
|
|
|
|
|
|
|
if 3 <= profile.n_variables <= 10:
|
|
|
|
|
score += 0.1
|
|
|
|
|
reasons.append("moderate dimensionality")
|
|
|
|
|
|
|
|
|
|
if metrics and 0.4 < metrics.response_smoothness < 0.8:
|
|
|
|
|
score += 0.1
|
|
|
|
|
reasons.append("uncertain landscape - hybrid adapts")
|
|
|
|
|
|
|
|
|
|
if profile.has_constraints and metrics and metrics.feasibility_rate < 0.9:
|
|
|
|
|
score += 0.1
|
|
|
|
|
reasons.append("constrained problem - safer approach")
|
|
|
|
|
|
|
|
|
|
if profile.max_fea_trials >= 30:
|
|
|
|
|
score += 0.05
|
|
|
|
|
reasons.append("adequate budget for iterations")
|
|
|
|
|
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
# NEW: NN Quality adjustments for hybrid
|
|
|
|
|
if nn_quality and nn_quality.has_nn_data:
|
|
|
|
|
if nn_quality.hybrid_suitability > 0.5:
|
|
|
|
|
score += 0.15
|
|
|
|
|
reasons.append("NN adds value with periodic retraining")
|
|
|
|
|
if nn_quality.turbo_suitability < 0.5:
|
|
|
|
|
score += 0.1
|
|
|
|
|
reasons.append("NN quality suggests hybrid over turbo")
|
|
|
|
|
|
2025-12-07 05:51:49 -05:00
|
|
|
# === PURE FEA ===
|
|
|
|
|
elif method == OptimizationMethod.PURE_FEA:
|
|
|
|
|
# Good for: small budget, highly nonlinear, rough landscape
|
|
|
|
|
|
|
|
|
|
if profile.max_fea_trials < 30:
|
|
|
|
|
score += 0.2
|
|
|
|
|
reasons.append("limited budget - no NN overhead")
|
|
|
|
|
|
|
|
|
|
if metrics and metrics.response_smoothness < 0.3:
|
|
|
|
|
score += 0.2
|
|
|
|
|
reasons.append("rough landscape - NN unreliable")
|
|
|
|
|
|
|
|
|
|
if profile.expected_nonlinearity == 'high':
|
|
|
|
|
score += 0.15
|
|
|
|
|
reasons.append("highly nonlinear physics")
|
|
|
|
|
|
|
|
|
|
if metrics and metrics.feasibility_rate < 0.5:
|
|
|
|
|
score += 0.1
|
|
|
|
|
reasons.append("many infeasible designs - need accurate FEA")
|
|
|
|
|
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
# NEW: NN Quality - if NN is truly poor, favor pure FEA
|
|
|
|
|
if nn_quality and nn_quality.has_nn_data:
|
|
|
|
|
if nn_quality.hybrid_suitability < 0.3:
|
|
|
|
|
score += 0.2
|
|
|
|
|
reasons.append("NN quality too low - prefer FEA")
|
|
|
|
|
|
2025-12-07 05:51:49 -05:00
|
|
|
# === GNN FIELD ===
|
|
|
|
|
elif method == OptimizationMethod.GNN_FIELD:
|
|
|
|
|
# Good for: high-dimensional, need field visualization
|
|
|
|
|
|
|
|
|
|
if profile.n_variables > 10:
|
|
|
|
|
score += 0.2
|
|
|
|
|
reasons.append("high-dimensional - GNN handles well")
|
|
|
|
|
|
|
|
|
|
# GNN is more advanced, only recommend if specifically needed
|
|
|
|
|
if profile.n_variables <= 5:
|
|
|
|
|
score -= 0.1
|
|
|
|
|
reasons.append("simple problem - MLP sufficient")
|
|
|
|
|
|
|
|
|
|
# Compile reason string
|
|
|
|
|
reason = "; ".join(reasons) if reasons else "default recommendation"
|
|
|
|
|
scores[method] = {'score': score, 'reason': reason}
|
|
|
|
|
|
|
|
|
|
return scores
|
|
|
|
|
|
|
|
|
|
def _get_parameters(self, method: OptimizationMethod,
|
|
|
|
|
profile: ProblemProfile,
|
|
|
|
|
metrics: EarlyMetrics = None) -> Dict[str, Any]:
|
|
|
|
|
"""Generate recommended parameters for the selected method."""
|
|
|
|
|
|
|
|
|
|
params = {}
|
|
|
|
|
|
|
|
|
|
if method == OptimizationMethod.TURBO:
|
|
|
|
|
# Scale NN trials based on dimensionality
|
|
|
|
|
base_nn_trials = 5000
|
|
|
|
|
if profile.n_variables <= 2:
|
|
|
|
|
nn_trials = base_nn_trials
|
|
|
|
|
elif profile.n_variables <= 5:
|
|
|
|
|
nn_trials = base_nn_trials * 2
|
|
|
|
|
else:
|
|
|
|
|
nn_trials = base_nn_trials * 3
|
|
|
|
|
|
|
|
|
|
params = {
|
|
|
|
|
'nn_trials': nn_trials,
|
|
|
|
|
'batch_size': 100,
|
|
|
|
|
'retrain_every': 10,
|
|
|
|
|
'epochs': 150 if metrics and metrics.n_trials_analyzed > 100 else 200
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
elif method == OptimizationMethod.HYBRID_LOOP:
|
|
|
|
|
params = {
|
|
|
|
|
'iterations': 5,
|
|
|
|
|
'nn_trials_per_iter': 500,
|
|
|
|
|
'validate_per_iter': 5,
|
|
|
|
|
'epochs': 300
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
elif method == OptimizationMethod.PURE_FEA:
|
|
|
|
|
# Choose sampler based on objectives
|
|
|
|
|
if profile.is_multi_objective:
|
|
|
|
|
sampler = 'NSGAIISampler'
|
|
|
|
|
else:
|
|
|
|
|
sampler = 'TPESampler'
|
|
|
|
|
|
|
|
|
|
params = {
|
|
|
|
|
'sampler': sampler,
|
|
|
|
|
'n_trials': min(100, profile.max_fea_trials),
|
|
|
|
|
'timeout_per_trial': profile.fea_time_estimate
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
elif method == OptimizationMethod.GNN_FIELD:
|
|
|
|
|
params = {
|
|
|
|
|
'model_type': 'parametric_gnn',
|
|
|
|
|
'initial_fea_trials': 100,
|
|
|
|
|
'nn_trials': 10000,
|
|
|
|
|
'epochs': 200
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return params
|
|
|
|
|
|
|
|
|
|
def _get_warnings(self, profile: ProblemProfile,
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
metrics: EarlyMetrics = None,
|
|
|
|
|
nn_quality: NNQualityMetrics = None) -> List[str]:
|
2025-12-07 05:51:49 -05:00
|
|
|
"""Generate warnings about potential issues."""
|
|
|
|
|
|
|
|
|
|
warnings = []
|
|
|
|
|
|
|
|
|
|
if profile.n_variables > 10:
|
|
|
|
|
warnings.append(
|
|
|
|
|
f"High-dimensional problem ({profile.n_variables} variables) - "
|
|
|
|
|
"consider dimensionality reduction or Latin Hypercube sampling"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if profile.max_fea_trials < 20:
|
|
|
|
|
warnings.append(
|
|
|
|
|
f"Very limited FEA budget ({profile.max_fea_trials} trials) - "
|
|
|
|
|
"neural acceleration may not have enough training data"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if metrics and metrics.feasibility_rate < 0.5:
|
|
|
|
|
warnings.append(
|
|
|
|
|
f"Low feasibility rate ({metrics.feasibility_rate:.0%}) - "
|
|
|
|
|
"consider relaxing constraints or narrowing design space"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if metrics and metrics.response_smoothness < 0.3:
|
|
|
|
|
warnings.append(
|
|
|
|
|
f"Rough objective landscape detected - "
|
|
|
|
|
"neural surrogate may have high prediction errors"
|
|
|
|
|
)
|
|
|
|
|
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
# NEW: NN Quality warnings
|
|
|
|
|
if nn_quality and nn_quality.has_nn_data:
|
|
|
|
|
# Per-objective quality warnings
|
|
|
|
|
for obj_name, cv_ratio in nn_quality.cv_ratios.items():
|
|
|
|
|
obj_type = nn_quality.objective_types.get(obj_name, 'smooth')
|
|
|
|
|
nn_error = nn_quality.nn_errors.get(obj_name, 0)
|
|
|
|
|
expected = nn_quality.expected_errors.get(obj_name, 5.0)
|
|
|
|
|
|
|
|
|
|
if cv_ratio > 2.0:
|
|
|
|
|
warnings.append(
|
|
|
|
|
f"{obj_name}: NN error ({nn_error:.1f}%) >> variability - "
|
|
|
|
|
f"NN not learning physics well for this {obj_type} objective"
|
|
|
|
|
)
|
|
|
|
|
elif nn_error > expected * 1.5:
|
|
|
|
|
warnings.append(
|
|
|
|
|
f"{obj_name}: NN error ({nn_error:.1f}%) above expected ({expected:.0f}%) - "
|
|
|
|
|
f"consider retraining or using hybrid mode"
|
|
|
|
|
)
|
|
|
|
|
|
2025-12-07 05:51:49 -05:00
|
|
|
return warnings
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RuntimeAdvisor:
|
|
|
|
|
"""
|
|
|
|
|
Monitors optimization runtime and suggests method pivots.
|
|
|
|
|
|
|
|
|
|
Call check_pivot() periodically during optimization to get
|
|
|
|
|
suggestions for method changes.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, check_interval: int = 10):
|
|
|
|
|
"""
|
|
|
|
|
Args:
|
|
|
|
|
check_interval: Check for pivots every N trials
|
|
|
|
|
"""
|
|
|
|
|
self.check_interval = check_interval
|
|
|
|
|
self.history: List[RuntimeMetrics] = []
|
|
|
|
|
self.pivot_suggestions: List[Dict] = []
|
|
|
|
|
|
|
|
|
|
def update(self, metrics: RuntimeMetrics):
|
|
|
|
|
"""Add new runtime metrics to history."""
|
|
|
|
|
metrics.timestamp = datetime.now().isoformat()
|
|
|
|
|
self.history.append(metrics)
|
|
|
|
|
|
|
|
|
|
def check_pivot(self, current_method: str) -> Optional[Dict]:
|
|
|
|
|
"""
|
|
|
|
|
Check if a method pivot should be suggested.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
current_method: Currently running method
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
Pivot suggestion dict or None
|
|
|
|
|
"""
|
|
|
|
|
if len(self.history) < 2:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
latest = self.history[-1]
|
|
|
|
|
previous = self.history[-2]
|
|
|
|
|
|
|
|
|
|
suggestion = None
|
|
|
|
|
|
|
|
|
|
# Check 1: NN accuracy declining
|
|
|
|
|
if latest.nn_accuracy_trend == 'declining':
|
|
|
|
|
if current_method == 'turbo':
|
|
|
|
|
suggestion = {
|
|
|
|
|
'suggest_pivot': True,
|
|
|
|
|
'from': current_method,
|
|
|
|
|
'to': 'hybrid_loop',
|
|
|
|
|
'reason': 'NN accuracy declining - switch to hybrid for more frequent retraining',
|
|
|
|
|
'urgency': 'medium'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Check 2: Pareto front stagnating
|
|
|
|
|
if latest.pareto_growth_rate < 0.01 and previous.pareto_growth_rate < 0.01:
|
|
|
|
|
suggestion = {
|
|
|
|
|
'suggest_pivot': True,
|
|
|
|
|
'from': current_method,
|
|
|
|
|
'to': 'increase_exploration',
|
|
|
|
|
'reason': 'Pareto front stagnating - consider increasing exploration',
|
|
|
|
|
'urgency': 'low'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Check 3: High FEA failure rate
|
|
|
|
|
if latest.fea_failure_rate > 0.2:
|
|
|
|
|
if current_method in ['turbo', 'hybrid_loop']:
|
|
|
|
|
suggestion = {
|
|
|
|
|
'suggest_pivot': True,
|
|
|
|
|
'from': current_method,
|
|
|
|
|
'to': 'pure_fea',
|
|
|
|
|
'reason': f'High FEA failure rate ({latest.fea_failure_rate:.0%}) - NN exploring invalid regions',
|
|
|
|
|
'urgency': 'high'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Check 4: Diminishing returns
|
|
|
|
|
if latest.improvement_rate < 0.001 and latest.trials_completed > 100:
|
|
|
|
|
suggestion = {
|
|
|
|
|
'suggest_pivot': True,
|
|
|
|
|
'from': current_method,
|
|
|
|
|
'to': 'stop_early',
|
|
|
|
|
'reason': 'Diminishing returns - consider stopping optimization',
|
|
|
|
|
'urgency': 'low'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if suggestion:
|
|
|
|
|
self.pivot_suggestions.append(suggestion)
|
|
|
|
|
|
|
|
|
|
return suggestion
|
|
|
|
|
|
|
|
|
|
def get_summary(self) -> Dict:
|
|
|
|
|
"""Get summary of runtime performance."""
|
|
|
|
|
if not self.history:
|
|
|
|
|
return {}
|
|
|
|
|
|
|
|
|
|
latest = self.history[-1]
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
'trials_completed': latest.trials_completed,
|
|
|
|
|
'pareto_size': latest.pareto_size,
|
|
|
|
|
'fea_time_mean': latest.fea_time_mean,
|
|
|
|
|
'fea_failure_rate': latest.fea_failure_rate,
|
|
|
|
|
'nn_accuracy': latest.nn_accuracy,
|
|
|
|
|
'pivot_suggestions_count': len(self.pivot_suggestions)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
def print_recommendation(rec: MethodRecommendation, profile: ProblemProfile = None,
|
|
|
|
|
nn_quality: NNQualityMetrics = None, early_metrics: EarlyMetrics = None):
|
|
|
|
|
"""Pretty-print a method recommendation with NN quality assessment."""
|
2025-12-07 05:51:49 -05:00
|
|
|
|
|
|
|
|
print("\n" + "=" * 70)
|
|
|
|
|
print(" OPTIMIZATION METHOD ADVISOR")
|
|
|
|
|
print("=" * 70)
|
|
|
|
|
|
|
|
|
|
if profile:
|
|
|
|
|
print("\nProblem Profile:")
|
|
|
|
|
print(f" Variables: {profile.n_variables} ({', '.join(profile.variable_names)})")
|
|
|
|
|
print(f" Objectives: {profile.n_objectives} ({', '.join(profile.objective_names)})")
|
|
|
|
|
print(f" Constraints: {profile.n_constraints}")
|
|
|
|
|
print(f" Max FEA budget: ~{profile.max_fea_trials} trials")
|
|
|
|
|
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
# NN Quality Assessment Section
|
|
|
|
|
if nn_quality and nn_quality.has_nn_data:
|
|
|
|
|
print("\nNN Quality Assessment:")
|
|
|
|
|
print(f" Validations analyzed: {nn_quality.n_validations}")
|
|
|
|
|
print()
|
|
|
|
|
|
|
|
|
|
# Build table header
|
|
|
|
|
print(" | Objective | NN Error | CV | Ratio | Type | Quality |")
|
|
|
|
|
print(" |---------------|----------|--------|-------|------------|---------|")
|
|
|
|
|
|
|
|
|
|
for obj_name in nn_quality.nn_errors.keys():
|
|
|
|
|
nn_error = nn_quality.nn_errors.get(obj_name, 0)
|
|
|
|
|
cv_ratio = nn_quality.cv_ratios.get(obj_name, 0)
|
|
|
|
|
obj_type = nn_quality.objective_types.get(obj_name, 'smooth')
|
|
|
|
|
|
|
|
|
|
# Get CV from early_metrics if available
|
|
|
|
|
cv_pct = 0.0
|
|
|
|
|
if early_metrics and early_metrics.coefficient_of_variation:
|
|
|
|
|
cv = early_metrics.coefficient_of_variation.get(obj_name, 0)
|
|
|
|
|
cv_pct = cv * 100 # Convert to percentage
|
|
|
|
|
|
|
|
|
|
# Quality indicator
|
|
|
|
|
if cv_ratio < 0.5:
|
|
|
|
|
quality = "✓ Great"
|
|
|
|
|
elif cv_ratio < 1.0:
|
|
|
|
|
quality = "✓ Good"
|
|
|
|
|
elif cv_ratio < 2.0:
|
|
|
|
|
quality = "~ OK"
|
|
|
|
|
else:
|
|
|
|
|
quality = "✗ Poor"
|
|
|
|
|
|
|
|
|
|
# Format row
|
|
|
|
|
print(f" | {obj_name[:13]:<13} | {nn_error:>6.1f}% | {cv_pct:>5.1f}% | {cv_ratio:>5.2f} | {obj_type:<10} | {quality:<7} |")
|
|
|
|
|
|
|
|
|
|
print()
|
|
|
|
|
print(f" Overall Quality: {nn_quality.overall_quality:.0%}")
|
|
|
|
|
print(f" Turbo Suitability: {nn_quality.turbo_suitability:.0%}")
|
|
|
|
|
print(f" Hybrid Suitability: {nn_quality.hybrid_suitability:.0%}")
|
|
|
|
|
|
2025-12-07 05:51:49 -05:00
|
|
|
print("\n" + "-" * 70)
|
|
|
|
|
print(f"\n RECOMMENDED: {rec.method.upper()}")
|
|
|
|
|
print(f" Confidence: {rec.confidence:.0%}")
|
|
|
|
|
print(f" Reason: {rec.reasoning}")
|
|
|
|
|
|
|
|
|
|
print("\n Suggested parameters:")
|
|
|
|
|
for key, value in rec.parameters.items():
|
|
|
|
|
print(f" --{key.replace('_', '-')}: {value}")
|
|
|
|
|
|
|
|
|
|
if rec.alternatives:
|
|
|
|
|
print("\n Alternatives:")
|
|
|
|
|
for alt in rec.alternatives:
|
|
|
|
|
print(f" - {alt['method']} ({alt['confidence']:.0%}): {alt['reason']}")
|
|
|
|
|
|
|
|
|
|
if rec.warnings:
|
|
|
|
|
print("\n Warnings:")
|
|
|
|
|
for warning in rec.warnings:
|
|
|
|
|
print(f" ! {warning}")
|
|
|
|
|
|
|
|
|
|
print("\n" + "=" * 70)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Convenience function for quick use
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
def recommend_method(config_path: Path, db_path: Path = None,
|
|
|
|
|
results_dir: Path = None) -> Tuple[MethodRecommendation, 'AdaptiveMethodSelector']:
|
2025-12-07 05:51:49 -05:00
|
|
|
"""
|
|
|
|
|
Quick method recommendation from config file.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
config_path: Path to optimization_config.json
|
|
|
|
|
db_path: Optional path to existing study.db
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
results_dir: Optional path to results directory (for NN quality assessment)
|
2025-12-07 05:51:49 -05:00
|
|
|
|
|
|
|
|
Returns:
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
Tuple of (MethodRecommendation, AdaptiveMethodSelector)
|
|
|
|
|
The selector contains last_nn_quality and last_early_metrics for display
|
2025-12-07 05:51:49 -05:00
|
|
|
"""
|
|
|
|
|
with open(config_path) as f:
|
|
|
|
|
config = json.load(f)
|
|
|
|
|
|
|
|
|
|
selector = AdaptiveMethodSelector()
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
rec = selector.recommend(config, db_path, early_metrics=None, results_dir=results_dir)
|
|
|
|
|
return rec, selector
|
2025-12-07 05:51:49 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
# Test with a sample config
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
if len(sys.argv) > 1:
|
|
|
|
|
config_path = Path(sys.argv[1])
|
|
|
|
|
db_path = Path(sys.argv[2]) if len(sys.argv) > 2 else None
|
|
|
|
|
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
# Infer results_dir from config_path location (typically in 1_setup)
|
|
|
|
|
results_dir = None
|
|
|
|
|
if config_path.parent.name == "1_setup":
|
|
|
|
|
results_dir = config_path.parent.parent / "2_results"
|
|
|
|
|
elif "2_results" in str(config_path):
|
|
|
|
|
results_dir = config_path.parent
|
|
|
|
|
|
|
|
|
|
rec, selector = recommend_method(config_path, db_path, results_dir)
|
2025-12-07 05:51:49 -05:00
|
|
|
|
|
|
|
|
# Also get profile for display
|
|
|
|
|
with open(config_path) as f:
|
|
|
|
|
config = json.load(f)
|
|
|
|
|
profiler = ProblemProfiler()
|
|
|
|
|
profile = profiler.analyze(config)
|
|
|
|
|
|
feat: Add NN Quality Assessor with relative accuracy thresholds
The Method Selector now uses relative accuracy thresholds to assess
NN suitability by comparing NN error to problem variability (CV ratio).
NNQualityAssessor features:
- Physics-based objective classification (linear, smooth, nonlinear, chaotic)
- CV ratio computation: nn_error / coefficient_of_variation
- Turbo suitability score based on relative thresholds
- Data collection from validation_report.json, turbo_report.json, and study.db
Quality thresholds by objective type:
- Linear (mass, volume): max 2% error, CV ratio < 0.5
- Smooth (frequency): max 5% error, CV ratio < 1.0
- Nonlinear (stress, stiffness): max 10% error, CV ratio < 2.0
- Chaotic (contact, buckling): max 20% error, CV ratio < 3.0
CLI output now includes:
- Per-objective NN quality table with error, CV, ratio, and quality indicator
- Turbo suitability and hybrid suitability percentages
- Warnings when NN error exceeds physics-based thresholds
Updated SYS_15_METHOD_SELECTOR.md to v2.0 with full NN Quality Assessment documentation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 06:38:25 -05:00
|
|
|
# Print with NN quality metrics if available
|
|
|
|
|
print_recommendation(
|
|
|
|
|
rec,
|
|
|
|
|
profile,
|
|
|
|
|
nn_quality=selector.last_nn_quality,
|
|
|
|
|
early_metrics=selector.last_early_metrics
|
|
|
|
|
)
|
2025-12-07 05:51:49 -05:00
|
|
|
else:
|
|
|
|
|
print("Usage: python method_selector.py <config_path> [db_path]")
|