refactor: Major reorganization of optimization_engine module structure
BREAKING CHANGE: Module paths have been reorganized for better maintainability. Backwards compatibility aliases with deprecation warnings are provided. New Structure: - core/ - Optimization runners (runner, intelligent_optimizer, etc.) - processors/ - Data processing - surrogates/ - Neural network surrogates - nx/ - NX/Nastran integration (solver, updater, session_manager) - study/ - Study management (creator, wizard, state, reset) - reporting/ - Reports and analysis (visualizer, report_generator) - config/ - Configuration management (manager, builder) - utils/ - Utilities (logger, auto_doc, etc.) - future/ - Research/experimental code Migration: - ~200 import changes across 125 files - All __init__.py files use lazy loading to avoid circular imports - Backwards compatibility layer supports old import paths with warnings - All existing functionality preserved To migrate existing code: OLD: from optimization_engine.nx_solver import NXSolver NEW: from optimization_engine.nx.solver import NXSolver OLD: from optimization_engine.runner import OptimizationRunner NEW: from optimization_engine.core.runner import OptimizationRunner 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
214
optimization_engine/validators/simulation_validator.py
Normal file
214
optimization_engine/validators/simulation_validator.py
Normal file
@@ -0,0 +1,214 @@
|
||||
"""
|
||||
Simulation Validator - Validates design parameters before running FEA simulations.
|
||||
|
||||
This module helps prevent simulation failures by:
|
||||
1. Checking if geometry will be valid
|
||||
2. Validating parameter combinations
|
||||
3. Providing actionable error messages
|
||||
4. Detecting likely failure modes
|
||||
|
||||
Usage:
|
||||
validator = SimulationValidator(model_type='circular_plate')
|
||||
is_valid, warnings = validator.validate(design_variables)
|
||||
if not is_valid:
|
||||
print(f"Invalid parameters: {warnings}")
|
||||
"""
|
||||
|
||||
from typing import Dict, Tuple, List
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class SimulationValidator:
|
||||
"""Validates design parameters before running simulations."""
|
||||
|
||||
def __init__(self, model_type: str = 'generic', verbose: bool = True):
|
||||
"""
|
||||
Initialize validator for specific model type.
|
||||
|
||||
Args:
|
||||
model_type: Type of FEA model ('circular_plate', 'beam', etc.)
|
||||
verbose: Print validation warnings
|
||||
"""
|
||||
self.model_type = model_type
|
||||
self.verbose = verbose
|
||||
|
||||
# Model-specific validation rules
|
||||
self.validation_rules = self._get_validation_rules(model_type)
|
||||
|
||||
def _get_validation_rules(self, model_type: str) -> Dict:
|
||||
"""Get validation rules for specific model type."""
|
||||
|
||||
if model_type == 'circular_plate':
|
||||
# NOTE: Only use parameter bounds for validation
|
||||
# No arbitrary aspect ratio checks - let Optuna explore the full parameter space
|
||||
# Modal analysis is robust and doesn't need strict aspect ratio limits
|
||||
return {}
|
||||
|
||||
# Generic rules for unknown models
|
||||
return {}
|
||||
|
||||
def validate(
|
||||
self,
|
||||
design_variables: Dict[str, float],
|
||||
strict: bool = False
|
||||
) -> Tuple[bool, List[str]]:
|
||||
"""
|
||||
Validate design variables before simulation.
|
||||
|
||||
Args:
|
||||
design_variables: Dict of parameter names to values
|
||||
strict: If True, reject on soft limit violations (warnings)
|
||||
|
||||
Returns:
|
||||
(is_valid, warnings_list)
|
||||
- is_valid: True if parameters are acceptable
|
||||
- warnings_list: List of warning/error messages
|
||||
"""
|
||||
warnings = []
|
||||
is_valid = True
|
||||
|
||||
# Check each parameter
|
||||
for param_name, value in design_variables.items():
|
||||
if param_name not in self.validation_rules:
|
||||
continue # No rules for this parameter
|
||||
|
||||
rules = self.validation_rules[param_name]
|
||||
|
||||
# Hard limits (always reject)
|
||||
if value < rules.get('min', float('-inf')):
|
||||
is_valid = False
|
||||
warnings.append(
|
||||
f"INVALID: {param_name}={value:.2f} < min={rules['min']:.2f}. "
|
||||
f"{rules.get('reason', '')}"
|
||||
)
|
||||
|
||||
if value > rules.get('max', float('inf')):
|
||||
is_valid = False
|
||||
warnings.append(
|
||||
f"INVALID: {param_name}={value:.2f} > max={rules['max']:.2f}. "
|
||||
f"{rules.get('reason', '')}"
|
||||
)
|
||||
|
||||
# Soft limits (warnings, may cause issues)
|
||||
if 'soft_min' in rules and value < rules['soft_min']:
|
||||
msg = (
|
||||
f"WARNING: {param_name}={value:.2f} < recommended={rules['soft_min']:.2f}. "
|
||||
f"{rules.get('reason', 'May cause simulation issues')}"
|
||||
)
|
||||
warnings.append(msg)
|
||||
if strict:
|
||||
is_valid = False
|
||||
|
||||
if 'soft_max' in rules and value > rules['soft_max']:
|
||||
msg = (
|
||||
f"WARNING: {param_name}={value:.2f} > recommended={rules['soft_max']:.2f}. "
|
||||
f"{rules.get('reason', 'May cause simulation issues')}"
|
||||
)
|
||||
warnings.append(msg)
|
||||
if strict:
|
||||
is_valid = False
|
||||
|
||||
# Model-specific combined checks can be added here if needed
|
||||
# For now, rely only on parameter bounds (no arbitrary physics checks)
|
||||
|
||||
# Print warnings if verbose
|
||||
if self.verbose and warnings:
|
||||
print(f"\n[VALIDATOR] Validation results:")
|
||||
for warning in warnings:
|
||||
print(f" {warning}")
|
||||
|
||||
return is_valid, warnings
|
||||
|
||||
def _validate_circular_plate_aspect_ratio(
|
||||
self,
|
||||
design_variables: Dict[str, float]
|
||||
) -> tuple[bool, List[str]]:
|
||||
"""Check circular plate aspect ratio (diameter/thickness).
|
||||
|
||||
Returns:
|
||||
(is_valid, warnings): Tuple of validation status and warning messages
|
||||
"""
|
||||
warnings = []
|
||||
is_valid = True
|
||||
|
||||
diameter = design_variables.get('inner_diameter')
|
||||
thickness = design_variables.get('plate_thickness')
|
||||
|
||||
if diameter and thickness:
|
||||
aspect_ratio = diameter / thickness
|
||||
|
||||
rules = self.validation_rules.get('aspect_ratio', {})
|
||||
min_aspect = rules.get('min', 0)
|
||||
max_aspect = rules.get('max', float('inf'))
|
||||
|
||||
if aspect_ratio > max_aspect:
|
||||
is_valid = False # FIX: Make this a hard rejection
|
||||
warnings.append(
|
||||
f"INVALID: Aspect ratio {aspect_ratio:.1f} > {max_aspect:.1f}. "
|
||||
f"Very thin plate will cause numerical instability."
|
||||
)
|
||||
elif aspect_ratio < min_aspect:
|
||||
is_valid = False # FIX: Make this a hard rejection
|
||||
warnings.append(
|
||||
f"INVALID: Aspect ratio {aspect_ratio:.1f} < {min_aspect:.1f}. "
|
||||
f"Very thick plate will have poor mesh quality."
|
||||
)
|
||||
|
||||
return is_valid, warnings
|
||||
|
||||
def suggest_corrections(
|
||||
self,
|
||||
design_variables: Dict[str, float]
|
||||
) -> Dict[str, float]:
|
||||
"""
|
||||
Suggest corrected parameters that are more likely to succeed.
|
||||
|
||||
Args:
|
||||
design_variables: Original parameters
|
||||
|
||||
Returns:
|
||||
Corrected parameters (clamped to safe ranges)
|
||||
"""
|
||||
corrected = design_variables.copy()
|
||||
|
||||
for param_name, value in design_variables.items():
|
||||
if param_name not in self.validation_rules:
|
||||
continue
|
||||
|
||||
rules = self.validation_rules[param_name]
|
||||
|
||||
# Clamp to soft limits (safer range)
|
||||
soft_min = rules.get('soft_min', rules.get('min', float('-inf')))
|
||||
soft_max = rules.get('soft_max', rules.get('max', float('inf')))
|
||||
|
||||
if value < soft_min:
|
||||
corrected[param_name] = soft_min
|
||||
if self.verbose:
|
||||
print(f"[VALIDATOR] Corrected {param_name}: {value:.2f} -> {soft_min:.2f}")
|
||||
|
||||
if value > soft_max:
|
||||
corrected[param_name] = soft_max
|
||||
if self.verbose:
|
||||
print(f"[VALIDATOR] Corrected {param_name}: {value:.2f} -> {soft_max:.2f}")
|
||||
|
||||
return corrected
|
||||
|
||||
|
||||
def validate_before_simulation(
|
||||
design_variables: Dict[str, float],
|
||||
model_type: str = 'circular_plate',
|
||||
strict: bool = False
|
||||
) -> Tuple[bool, List[str]]:
|
||||
"""
|
||||
Convenience function for quick validation.
|
||||
|
||||
Args:
|
||||
design_variables: Parameters to validate
|
||||
model_type: Type of FEA model
|
||||
strict: Reject on warnings (not just errors)
|
||||
|
||||
Returns:
|
||||
(is_valid, warnings)
|
||||
"""
|
||||
validator = SimulationValidator(model_type=model_type, verbose=False)
|
||||
return validator.validate(design_variables, strict=strict)
|
||||
Reference in New Issue
Block a user