# Analyze Optimization Workflow Skill **Last Updated**: November 23, 2025 **Version**: 2.0 - Phase 3.3 Integration You are analyzing a structural optimization request for the Atomizer system. When the user provides a request, break it down into atomic workflow steps and classify each step intelligently. ## Step Types **1. ENGINEERING FEATURES** - Complex FEA/CAE operations needing specialized knowledge: - Extract results from OP2 files using centralized extractors - Modify FEA properties (CBUSH/CBAR stiffness, PCOMP layup, material properties) - Run simulations (SOL101 static, SOL103 modal, etc.) - Create/modify geometry in NX - Multi-solution workflows (static + modal, thermal + structural) **2. INLINE CALCULATIONS** - Simple math operations (auto-generate Python): - Calculate average, min, max, sum - Compare values, compute ratios - Statistical operations **3. POST-PROCESSING HOOKS** - Custom calculations between FEA steps: - Custom objective functions combining multiple results - Data transformations - Filtering/aggregation logic **4. OPTIMIZATION** - Algorithm and configuration: - Single-objective: Optuna TPE, CMA-ES, Random Search - Multi-objective: NSGA-II (Protocol 11), NSGA-III, MOEA/D - Design variables and their ranges - Constraints and objectives ## Centralized Extractor Library **Location**: `optimization_engine/extractors/` Use these standardized extractors instead of custom OP2 code: ### Available Extractors: 1. **extract_displacement.py** - `extract_displacement(op2_file, subcase)` → max displacement in mm - Returns: `{'max_displacement': float, 'node_id': int}` 2. **extract_von_mises_stress.py** - `extract_solid_stress(op2_file, subcase, element_type)` → max von Mises stress in MPa - Element types: `'ctetra'`, `'chexa'`, `'cquad4'`, `'ctria3'` - Returns: `{'max_von_mises': float, 'element_id': int}` 3. **extract_frequency.py** - `extract_frequency(op2_file, subcase, mode_number)` → frequency in Hz - Returns: `{'frequency': float, 'mode': int, 'eigenvalue': float}` 4. **extract_mass_from_bdf.py** - `extract_mass_from_bdf(bdf_file)` → FEM mass in kg - Returns: `{'mass_kg': float, 'cg': [x, y, z], 'inertia': [[...]]}` 5. **extract_mass_from_expression.py** - `extract_mass_from_expression(prt_file, expression_name)` → CAD mass in kg - Returns: `float` (mass value from NX expression) 6. **op2_extractor.py** (Base Class) - `OP2Extractor` - Base class for custom extractors - Provides common OP2 file handling and error management ### Extractor Selection Guide: - **Displacement** → Use `extract_displacement` - **Von Mises Stress** (solids/shells) → Use `extract_solid_stress` - **Natural Frequency** (modal analysis) → Use `extract_frequency` - **Mass** (from FEM) → Use `extract_mass_from_bdf` - **Mass** (from CAD geometry) → Use `extract_mass_from_expression` ## Multi-Objective Optimization (Protocol 11) ### NSGA-II Configuration: ```python from optuna.samplers import NSGAIISampler study = optuna.create_study( study_name="study_name", storage="sqlite:///study.db", directions=['minimize', 'maximize'], # Semantic directions sampler=NSGAIISampler() ) ``` ### Key Concepts: - **Pareto Front**: Set of non-dominated solutions - **Semantic Directions**: `['minimize', 'maximize']` - NEVER use negative values - **Trade-offs**: Conflicting objectives (e.g., minimize mass vs maximize stiffness) - **Feasibility**: Solutions must satisfy all constraints - **Visualization**: Parallel Coordinates Plot + Pareto Front scatter plot ### Multi-Objective Return Format: ```python def objective(trial: optuna.Trial) -> tuple: """ Returns: (obj1, obj2): Tuple for NSGA-II """ # Extract objectives mass = extract_mass(...) # to minimize freq = extract_frequency(...) # to maximize # Return POSITIVE values - directions handled by study config return (mass, freq) ``` ### Common Pitfall - AVOID: ```python # ❌ WRONG: Using negative values to simulate maximization return (mass, -frequency) # Creates degenerate Pareto front # ✅ CORRECT: Use proper semantic directions return (mass, frequency) # Study configured with ['minimize', 'maximize'] ``` ## NX Multi-Solution Protocol **Critical Protocol**: When simulations have multiple solutions (e.g., Solution 1 = Static, Solution 2 = Modal): ### Required API: ```python # ✅ CORRECT: Use SolveAllSolutions() with Foreground mode result = nx_solver.run_simulation( sim_file=sim_file, working_dir=model_dir, expression_updates=design_vars, solution_name=None # Solve ALL solutions ) ``` ### Why This Matters: - `SolveChainOfSolutions()` with Background mode only solves the first solution - Causes stale OP2 files and identical results across trials - `SolveAllSolutions()` ensures all solutions complete before returning - See: `docs/NX_MULTI_SOLUTION_PROTOCOL.md` ## Dashboard Integration ### Visualization Features: 1. **Parallel Coordinates Plot** - Structure: Design Variables → Objectives → Constraints - Color-coded axes (blue/green/yellow) - Interactive trial selection - Feasibility coloring (green = feasible, red = infeasible) 2. **Pareto Front Plot** - 2D scatter for bi-objective problems - Shows trade-offs between objectives - Highlights non-dominated solutions 3. **Real-Time Updates** - WebSocket connection for live monitoring - Backend: FastAPI (port 8000) - Frontend: React + Vite (port 3003) ### Dashboard Access: ```bash # Backend cd atomizer-dashboard/backend && python -m uvicorn api.main:app --reload # Frontend cd atomizer-dashboard/frontend && npm run dev # Access: http://localhost:3003 ``` ## Important Distinctions ### Element Types: - CBUSH vs CBAR vs CBEAM are different 1D elements - CQUAD4 vs CTRIA3 are shell elements - CTETRA vs CHEXA are solid elements ### Result Types: - Element forces vs Reaction forces are DIFFERENT - Von Mises stress vs Principal stress - Displacement magnitude vs Component displacement ### Data Sources: - OP2 file (FEA results) → Use extractors - .prt expression (CAD parameters) → Use `extract_mass_from_expression` - .fem/.bdf file (FEM model) → Use `extract_mass_from_bdf` - Multi-solution OP2 files: `solution_1.op2`, `solution_2.op2` ### Optimization Algorithms: - **TPE** (Tree-structured Parzen Estimator): Single-objective, adaptive - **NSGA-II**: Multi-objective, Pareto-based - **CMA-ES**: Single-objective, gradient-free - **Random Search**: Baseline comparison ## Output Format Return a detailed JSON analysis with this structure: ```json { "engineering_features": [ { "action": "extract_frequency", "domain": "result_extraction", "description": "Extract fundamental frequency from modal analysis using centralized extractor", "params": { "extractor": "extract_frequency", "op2_file": "solution_2.op2", "subcase": 1, "mode_number": 1 }, "why_engineering": "Uses centralized extractor library for standardized OP2 extraction" }, { "action": "extract_mass", "domain": "result_extraction", "description": "Extract mass from CAD expression p173", "params": { "extractor": "extract_mass_from_expression", "prt_file": "Model.prt", "expression_name": "p173" }, "why_engineering": "Reads NX expression value directly from part file" } ], "inline_calculations": [ { "action": "convert_units", "description": "Convert mass from kg to grams", "params": { "input": "mass_kg", "operation": "multiply", "factor": 1000.0 }, "code_hint": "mass_g = mass_kg * 1000.0" } ], "post_processing_hooks": [], "optimization": { "protocol": "protocol_11_multi_objective", "algorithm": "NSGAIISampler", "type": "multi_objective", "design_variables": [ { "parameter": "beam_thickness", "type": "NX_expression", "bounds": [5.0, 10.0], "unit": "mm" } ], "objectives": [ { "name": "mass", "type": "minimize", "target": "mass_g", "unit": "g" }, { "name": "frequency", "type": "maximize", "target": "fundamental_freq", "unit": "Hz" } ], "constraints": [ { "name": "max_displacement", "type": "less_than", "threshold": 1.5, "unit": "mm" } ], "multi_solution_workflow": { "required": true, "solutions": ["static", "modal"], "protocol": "SolveAllSolutions with Foreground mode" } }, "dashboard": { "visualization": "parallel_coordinates + pareto_front", "backend_port": 8000, "frontend_port": 3003 }, "summary": { "total_steps": 3, "engineering_needed": 2, "auto_generate": 1, "uses_centralized_extractors": true, "multi_objective": true, "multi_solution_workflow": true, "research_needed": [] } } ``` ## Analysis Guidelines Be intelligent about: 1. **Extractor Selection** - Always prefer centralized extractors over custom OP2 code - Match extractor to result type (displacement, stress, frequency, mass) 2. **Multi-Objective Optimization** - Identify conflicting objectives requiring Pareto analysis - Use NSGA-II for 2-3 objectives - Use proper semantic directions (no negative values) 3. **Multi-Solution Workflows** - Detect when static + modal analysis is needed - Flag requirement for `SolveAllSolutions()` protocol - Identify separate OP2 files per solution 4. **Dashboard Integration** - Suggest parallel coordinates for high-dimensional problems - Recommend Pareto front visualization for multi-objective - Note real-time monitoring capability 5. **Protocol Selection** - Protocol 11: Multi-objective NSGA-II - Protocol 10: Single-objective with intelligent strategies - Legacy: Basic single-objective TPE Return ONLY the JSON analysis, no other text.