COMPLETE PIPELINE VALIDATED: - Stress extraction: 197.65 MPa (CTETRA elements) ✓ - Displacement extraction: 0.322 mm ✓ - Model parameter updates in .prt files ✓ - Optuna optimization with TPE sampler ✓ - Constraint handling (displacement < 1.0 mm) ✓ - Results saved to CSV/JSON ✓ Test Results (5 trials): - All extractors working correctly - Parameters updated successfully - Constraints validated - History and summary files generated New Files: - examples/test_stress_displacement_optimization.py Complete pipeline test with stress + displacement - examples/test_displacement_optimization.py Displacement-only optimization test - examples/run_optimization_real.py Full example with all extractors - examples/check_op2.py OP2 diagnostic utility - examples/bracket/optimization_config_stress_displacement.json Config: minimize stress, constrain displacement - examples/bracket/optimization_config_displacement_only.json Config: minimize displacement only Updated: - .gitignore: Exclude NX output files and optimization results - examples/bracket/optimization_config.json: Updated paths Next Step: Integrate NX solver execution for real optimization
167 lines
5.4 KiB
Python
167 lines
5.4 KiB
Python
"""
|
|
Example: Running Complete Optimization WITH REAL OP2 EXTRACTION
|
|
|
|
This version uses real pyNastran extractors instead of dummy data.
|
|
|
|
Requirements:
|
|
- conda activate test_env (with pyNastran and optuna installed)
|
|
|
|
What this does:
|
|
1. Updates NX model parameters in the .prt file
|
|
2. Uses existing OP2 results (simulation step skipped for now)
|
|
3. Extracts REAL mass, stress, displacement from OP2
|
|
4. Runs Optuna optimization
|
|
|
|
Note: Since we're using the same OP2 file for all trials (no re-solving),
|
|
the results will be constant. This is just to test the pipeline.
|
|
For real optimization, you'd need to run NX solver for each trial.
|
|
"""
|
|
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
# Add project root to path
|
|
project_root = Path(__file__).parent.parent
|
|
sys.path.insert(0, str(project_root))
|
|
|
|
from optimization_engine.runner import OptimizationRunner
|
|
from optimization_engine.nx_updater import update_nx_model
|
|
from optimization_engine.result_extractors.extractors import (
|
|
mass_extractor,
|
|
stress_extractor,
|
|
displacement_extractor
|
|
)
|
|
|
|
|
|
# ==================================================
|
|
# STEP 1: Define model updater function
|
|
# ==================================================
|
|
def bracket_model_updater(design_vars: dict):
|
|
"""
|
|
Update the bracket model with new design variable values.
|
|
|
|
Args:
|
|
design_vars: Dict like {'tip_thickness': 22.5, 'support_angle': 35.0}
|
|
"""
|
|
prt_file = project_root / "examples/bracket/Bracket.prt"
|
|
|
|
print(f"\n[MODEL UPDATE] Updating {prt_file.name} with:")
|
|
for name, value in design_vars.items():
|
|
print(f" {name} = {value:.4f}")
|
|
|
|
# Update the .prt file with new parameter values
|
|
update_nx_model(prt_file, design_vars, backup=False)
|
|
|
|
print("[MODEL UPDATE] Complete")
|
|
|
|
|
|
# ==================================================
|
|
# STEP 2: Define simulation runner function
|
|
# ==================================================
|
|
def bracket_simulation_runner() -> Path:
|
|
"""
|
|
Run NX simulation and return path to result files.
|
|
|
|
For this demo, we just return the existing OP2 file.
|
|
In production, this would:
|
|
1. Run NX solver with updated model
|
|
2. Wait for completion
|
|
3. Return path to new OP2 file
|
|
"""
|
|
print("\n[SIMULATION] Running NX Nastran solver...")
|
|
print("[SIMULATION] (Using existing OP2 for demo - no actual solve)")
|
|
|
|
# Return path to existing OP2 file
|
|
result_file = project_root / "examples/bracket/bracket_sim1-solution_1.op2"
|
|
|
|
if not result_file.exists():
|
|
raise FileNotFoundError(f"Result file not found: {result_file}")
|
|
|
|
print(f"[SIMULATION] Results: {result_file.name}")
|
|
return result_file
|
|
|
|
|
|
# ==================================================
|
|
# MAIN: Run optimization
|
|
# ==================================================
|
|
if __name__ == "__main__":
|
|
print("="*60)
|
|
print("ATOMIZER - REAL OPTIMIZATION TEST")
|
|
print("="*60)
|
|
|
|
# Path to optimization configuration
|
|
config_path = project_root / "examples/bracket/optimization_config.json"
|
|
|
|
if not config_path.exists():
|
|
print(f"Error: Configuration file not found: {config_path}")
|
|
print("Please run the MCP build_optimization_config tool first.")
|
|
sys.exit(1)
|
|
|
|
print(f"\nConfiguration: {config_path}")
|
|
|
|
# Use REAL extractors
|
|
print("\nUsing REAL OP2 extractors (pyNastran)")
|
|
extractors = {
|
|
'mass_extractor': mass_extractor,
|
|
'stress_extractor': stress_extractor,
|
|
'displacement_extractor': displacement_extractor
|
|
}
|
|
|
|
# Create optimization runner
|
|
runner = OptimizationRunner(
|
|
config_path=config_path,
|
|
model_updater=bracket_model_updater,
|
|
simulation_runner=bracket_simulation_runner,
|
|
result_extractors=extractors
|
|
)
|
|
|
|
# Run optimization with just 5 trials for testing
|
|
print("\n" + "="*60)
|
|
print("Starting optimization with 5 trials (test mode)")
|
|
print("="*60)
|
|
print("\nNOTE: Since we're using the same OP2 file for all trials")
|
|
print("(not re-running solver), results will be constant.")
|
|
print("This is just to test the pipeline integration.")
|
|
print("="*60)
|
|
|
|
# Override n_trials for demo
|
|
runner.config['optimization_settings']['n_trials'] = 5
|
|
|
|
try:
|
|
# Run!
|
|
study = runner.run(study_name="bracket_real_extraction_test")
|
|
|
|
print("\n" + "="*60)
|
|
print("TEST COMPLETE - PIPELINE WORKS!")
|
|
print("="*60)
|
|
print(f"\nBest parameters found:")
|
|
for param, value in study.best_params.items():
|
|
print(f" {param}: {value:.4f}")
|
|
|
|
print(f"\nBest objective value: {study.best_value:.6f}")
|
|
|
|
print(f"\nResults saved to: {runner.output_dir}")
|
|
print(" - history.csv (all trials)")
|
|
print(" - history.json (detailed results)")
|
|
print(" - optimization_summary.json (best results)")
|
|
|
|
print("\n" + "="*60)
|
|
print("NEXT STEPS:")
|
|
print("="*60)
|
|
print("1. Check the history.csv to see extracted values")
|
|
print("2. Integrate NX solver execution (batch mode)")
|
|
print("3. Run real optimization with solver re-runs")
|
|
print("="*60)
|
|
|
|
except Exception as e:
|
|
print(f"\n{'='*60}")
|
|
print("ERROR DURING OPTIMIZATION")
|
|
print("="*60)
|
|
print(f"Error: {e}")
|
|
print("\nMake sure you're running in test_env with:")
|
|
print(" - pyNastran installed")
|
|
print(" - optuna installed")
|
|
print(" - pandas installed")
|
|
import traceback
|
|
traceback.print_exc()
|