Neural Acceleration (MLP Surrogate): - Add run_nn_optimization.py with hybrid FEA/NN workflow - MLP architecture: 4-layer (64->128->128->64) with BatchNorm/Dropout - Three workflow modes: - --all: Sequential export->train->optimize->validate - --hybrid-loop: Iterative Train->NN->Validate->Retrain cycle - --turbo: Aggressive single-best validation (RECOMMENDED) - Turbo mode: 5000 NN trials + 50 FEA validations in ~12 minutes - Separate nn_study.db to avoid overloading dashboard Performance Results (bracket_pareto_3obj study): - NN prediction errors: mass 1-5%, stress 1-4%, stiffness 5-15% - Found minimum mass designs at boundary (angle~30deg, thick~30mm) - 100x speedup vs pure FEA exploration Protocol Operating System: - Add .claude/skills/ with Bootstrap, Cheatsheet, Context Loader - Add docs/protocols/ with operations (OP_01-06) and system (SYS_10-14) - Update SYS_14_NEURAL_ACCELERATION.md with MLP Turbo Mode docs NX Automation: - Add optimization_engine/hooks/ for NX CAD/CAE automation - Add study_wizard.py for guided study creation - Fix FEM mesh update: load idealized part before UpdateFemodel() New Study: - bracket_pareto_3obj: 3-objective Pareto (mass, stress, stiffness) - 167 FEA trials + 5000 NN trials completed - Demonstrates full hybrid workflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
122 lines
3.7 KiB
Python
122 lines
3.7 KiB
Python
"""Test model introspection module."""
|
|
|
|
import json
|
|
import glob
|
|
from pathlib import Path
|
|
|
|
# Add project root to path
|
|
import sys
|
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
|
|
|
from optimization_engine.hooks.nx_cad.model_introspection import (
|
|
introspect_op2,
|
|
introspect_study,
|
|
)
|
|
|
|
|
|
def test_op2_introspection():
|
|
"""Test OP2 introspection on bracket study."""
|
|
print("=" * 60)
|
|
print("OP2 INTROSPECTION TEST")
|
|
print("=" * 60)
|
|
|
|
# Find bracket OP2 files
|
|
op2_files = glob.glob(
|
|
"C:/Users/Antoine/Atomizer/studies/bracket_stiffness_optimization_V3/**/*.op2",
|
|
recursive=True
|
|
)
|
|
|
|
print(f"\nFound {len(op2_files)} OP2 files")
|
|
for f in op2_files[:5]:
|
|
print(f" - {Path(f).name}")
|
|
|
|
if not op2_files:
|
|
print("No OP2 files found!")
|
|
return
|
|
|
|
# Introspect first OP2
|
|
print(f"\nIntrospecting: {Path(op2_files[0]).name}")
|
|
result = introspect_op2(op2_files[0])
|
|
|
|
if not result["success"]:
|
|
print(f"ERROR: {result['error']}")
|
|
return
|
|
|
|
data = result["data"]
|
|
|
|
# Print results
|
|
print(f"\nFile Info:")
|
|
print(f" Size: {data['file_info']['size_mb']:.2f} MB")
|
|
print(f" Subcases: {data['subcases']}")
|
|
|
|
print(f"\nAvailable Results:")
|
|
for r_type, info in data["results"].items():
|
|
status = "YES" if info["available"] else "no"
|
|
extra = ""
|
|
if info["available"]:
|
|
if "element_types" in info and info["element_types"]:
|
|
extra = f" ({', '.join(info['element_types'][:3])})"
|
|
elif "subcases" in info and info["subcases"]:
|
|
extra = f" (subcases: {info['subcases'][:3]})"
|
|
print(f" {r_type:20s}: {status:4s} {extra}")
|
|
|
|
print(f"\nMesh Info:")
|
|
print(f" Nodes: {data['mesh']['node_count']}")
|
|
print(f" Elements: {data['mesh']['element_count']}")
|
|
if data['mesh']['element_types']:
|
|
print(f" Element types: {list(data['mesh']['element_types'].keys())[:5]}")
|
|
|
|
print(f"\nExtractable results: {data['extractable']}")
|
|
|
|
|
|
def test_study_introspection():
|
|
"""Test study directory introspection."""
|
|
print("\n" + "=" * 60)
|
|
print("STUDY INTROSPECTION TEST")
|
|
print("=" * 60)
|
|
|
|
study_dir = "C:/Users/Antoine/Atomizer/studies/bracket_stiffness_optimization_V3"
|
|
print(f"\nIntrospecting study: {study_dir}")
|
|
|
|
result = introspect_study(study_dir)
|
|
|
|
if not result["success"]:
|
|
print(f"ERROR: {result['error']}")
|
|
return
|
|
|
|
data = result["data"]
|
|
|
|
print(f"\nStudy Summary:")
|
|
print(f" Parts (.prt): {data['summary']['part_count']}")
|
|
print(f" Simulations (.sim): {data['summary']['simulation_count']}")
|
|
print(f" Results (.op2): {data['summary']['results_count']}")
|
|
print(f" Has config: {data['summary']['has_config']}")
|
|
|
|
print(f"\nParts found:")
|
|
for p in data["parts"][:5]:
|
|
print(f" - {Path(p['path']).name}")
|
|
|
|
print(f"\nSimulations found:")
|
|
for s in data["simulations"][:5]:
|
|
print(f" - {Path(s['path']).name}")
|
|
|
|
if data["config"]:
|
|
print(f"\nOptimization Config:")
|
|
config = data["config"]
|
|
if "variables" in config:
|
|
print(f" Variables: {len(config['variables'])}")
|
|
for v in config["variables"][:3]:
|
|
print(f" - {v.get('name', 'unnamed')}: [{v.get('lower')}, {v.get('upper')}]")
|
|
if "objectives" in config:
|
|
print(f" Objectives: {len(config['objectives'])}")
|
|
for o in config["objectives"][:3]:
|
|
print(f" - {o.get('name', 'unnamed')} ({o.get('direction', 'minimize')})")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
test_op2_introspection()
|
|
test_study_introspection()
|
|
print("\n" + "=" * 60)
|
|
print("INTROSPECTION TESTS COMPLETE")
|
|
print("=" * 60)
|