feat: Add Protocol 13 adaptive optimization, Plotly charts, and dashboard improvements
## Protocol 13: Adaptive Multi-Objective Optimization - Iterative FEA + Neural Network surrogate workflow - Initial FEA sampling, NN training, NN-accelerated search - FEA validation of top NN predictions, retraining loop - adaptive_state.json tracks iteration history and best values - M1 mirror study (V11) with 103 FEA, 3000 NN trials ## Dashboard Visualization Enhancements - Added Plotly.js interactive charts (parallel coords, Pareto, convergence) - Lazy loading with React.lazy() for performance - Code splitting: plotly.js-basic-dist (~1MB vs 3.5MB) - Chart library toggle (Recharts default, Plotly on-demand) - ExpandableChart component for full-screen modal views - ConsoleOutput component for real-time log viewing ## Documentation - Protocol 13 detailed documentation - Dashboard visualization guide - Plotly components README - Updated run-optimization skill with Mode 5 (adaptive) ## Bug Fixes - Fixed TypeScript errors in dashboard components - Fixed Card component to accept ReactNode title - Removed unused imports across components 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -416,6 +416,78 @@ def _validate_sim_file(sim_path: Path, result: ModelValidationResult):
|
||||
suggestion="Verify simulation setup in NX"
|
||||
))
|
||||
|
||||
# Check for assembly FEM - detect missing assembly .prt file
|
||||
_validate_assembly_components(sim_path, result)
|
||||
|
||||
|
||||
def _validate_assembly_components(sim_path: Path, result: ModelValidationResult):
|
||||
"""
|
||||
Validate that all .prt files required by an assembly FEM are present.
|
||||
|
||||
Assembly FEM (.afm) files reference:
|
||||
- The assembly .prt file (e.g., ASSY_M1.prt)
|
||||
- Component part files (e.g., M1_Blank.prt)
|
||||
- Component FEM idealized parts (e.g., M1_Blank_fem1_i.prt)
|
||||
|
||||
This function detects when the main assembly .prt file is missing.
|
||||
"""
|
||||
model_dir = sim_path.parent
|
||||
sim_stem = sim_path.stem # e.g., "ASSY_M1_assyfem1_sim1"
|
||||
|
||||
# Check if this is an assembly FEM by looking for _assyfem pattern
|
||||
if '_assyfem' not in sim_stem.lower():
|
||||
return # Not an assembly FEM
|
||||
|
||||
# Extract assembly name from sim file: ASSY_M1_assyfem1_sim1 -> ASSY_M1
|
||||
# Pattern: {ASSY_NAME}_assyfem{N}_sim{M}.sim
|
||||
import re
|
||||
match = re.match(r'^(.+?)_assyfem\d+', sim_stem, re.IGNORECASE)
|
||||
if not match:
|
||||
return
|
||||
|
||||
assembly_name = match.group(1) # e.g., "ASSY_M1"
|
||||
expected_assy_prt = f"{assembly_name}.prt"
|
||||
expected_assy_path = model_dir / expected_assy_prt
|
||||
|
||||
# Check if assembly .prt file exists
|
||||
if not expected_assy_path.exists():
|
||||
# Try case-insensitive search
|
||||
all_prts = list(model_dir.glob("*.prt"))
|
||||
matching = [p for p in all_prts if p.stem.lower() == assembly_name.lower()]
|
||||
|
||||
if not matching:
|
||||
result.errors.append(ModelError(
|
||||
component="assembly",
|
||||
message=f"CRITICAL: Assembly part file missing: {expected_assy_prt}",
|
||||
suggestion=f"Copy {expected_assy_prt} from the source model directory to {model_dir}"
|
||||
))
|
||||
|
||||
# Also warn about potential related files
|
||||
result.warnings.append(ModelWarning(
|
||||
component="assembly",
|
||||
message=f"Assembly FEM requires all component .prt and .fem files",
|
||||
suggestion="Ensure ALL .prt, .fem, and _i.prt files from the source are copied"
|
||||
))
|
||||
else:
|
||||
# Assembly .prt exists - verify it's readable
|
||||
if not os.access(expected_assy_path, os.R_OK):
|
||||
result.errors.append(ModelError(
|
||||
component="assembly",
|
||||
message=f"Assembly part file not readable: {expected_assy_prt}",
|
||||
suggestion="Check file permissions"
|
||||
))
|
||||
|
||||
# Also check for the .afm file
|
||||
afm_name = f"{assembly_name}_assyfem1.afm" # Common pattern
|
||||
# Try to find any .afm file
|
||||
afm_files = list(model_dir.glob("*.afm"))
|
||||
if not afm_files:
|
||||
result.warnings.append(ModelWarning(
|
||||
component="assembly",
|
||||
message="No .afm file found for assembly FEM",
|
||||
suggestion="The .afm file may be created on first solve"
|
||||
))
|
||||
|
||||
|
||||
def _validate_file_relationships(result: ModelValidationResult):
|
||||
"""Validate relationships between model files."""
|
||||
|
||||
Reference in New Issue
Block a user