feat: Add AtomizerField training data export and intelligent model discovery

Major additions:
- Training data export system for AtomizerField neural network training
- Bracket stiffness optimization study with 50+ training samples
- Intelligent NX model discovery (auto-detect solutions, expressions, mesh)
- Result extractors module for displacement, stress, frequency, mass
- User-generated NX journals for advanced workflows
- Archive structure for legacy scripts and test outputs
- Protocol documentation and dashboard launcher

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-26 12:01:50 -05:00
parent a0c008a593
commit 2b3573ec42
949 changed files with 1405144 additions and 470 deletions

View File

@@ -0,0 +1,32 @@
Nastran BUFFSIZE=32769 $(c:/program files/siemens/nx2412/nxnastran/conf/nastran.rcf[1])
Nastran BUFFPOOL=20.0X $(c:/program files/siemens/nx2412/nxnastran/conf/nastran.rcf[4])
Nastran DIAGA=128 DIAGB=0 $(c:/program files/siemens/nx2412/nxnastran/conf/nastran.rcf[7])
Nastran REAL=8545370112 $(Memory limit for MPI and other specialized modules)
JID='C:\Users\antoi\Documents\Atomaste\Atomizer\studies\bracket_stiffness_optimization_atomizerfield\1_setup\model\bracket_sim1-solution_1.dat'
OUT='./bracket_sim1-solution_1'
MEM=3846123520
MACH='Intel64 Family 6 Model 183 Stepping 1'
OPER='Windows 10'
OSV=' '
MODEL='Intel(R) Core(TM) i7-14700HX (AntoineThinkpad)'
CONFIG=8666
NPROC=28
symbol=DELDIR='c:/program files/siemens/nx2412/nxnastran/scnas/nast/del' $(program default)
symbol=DEMODIR='c:/program files/siemens/nx2412/nxnastran/scnas/nast/demo' $(program default)
symbol=SSSALTERDIR='c:/program files/siemens/nx2412/nxnastran/scnas/nast/misc/sssalter' $(program default)
symbol=TPLDIR='c:/program files/siemens/nx2412/nxnastran/scnas/nast/tpl' $(program default)
SDIR='c:/users/antoi/appdata/local/temp/bracket_sim1-solution_1.T199472_25'
DBS='c:/users/antoi/appdata/local/temp/bracket_sim1-solution_1.T199472_25'
SCR=yes
SMEM=20.0X
NEWDEL='c:/program files/siemens/nx2412/nxnastran/scnas/em64tntl/SSS'
DEL='NXNDEF'
AUTH='29000@AntoineThinkpad'
AUTHQUE=0
MSGCAT='c:/program files/siemens/nx2412/nxnastran/scnas/em64tntl/analysis.msg'
MSGDEST='f06'
PROG=bundle
NEWS='c:/program files/siemens/nx2412/nxnastran/scnas/nast/news.txt'
UMATLIB='libnxumat.dll'
UCRPLIB='libucreep.dll'
USOLLIB='libusol.dll'

View File

@@ -0,0 +1,91 @@
"""
NX Journal - Export Displacement Field for Bracket Stiffness Analysis
=====================================================================
This journal exports the z-displacement field from a ResultProbe to a .fld file.
Usage:
run_journal.exe export_displacement_field.py [sim_file_path]
If sim_file_path is not provided, uses Bracket_sim1.sim in the same directory.
"""
import sys
import math
from pathlib import Path
import NXOpen
import NXOpen.CAE
import NXOpen.Fields
def main(args):
"""
Export displacement field from NX simulation results.
Args:
args: Command line arguments, optionally including sim file path
The ResultProbe should already be defined in the simulation file
with z-displacement as the measured quantity.
"""
theSession = NXOpen.Session.GetSession()
# Determine sim file to open
if len(args) > 0:
sim_file = Path(args[0])
else:
# Default: Bracket_sim1.sim in same directory as this journal
journal_dir = Path(__file__).parent
sim_file = journal_dir / "Bracket_sim1.sim"
if not sim_file.exists():
print(f"ERROR: Simulation file not found: {sim_file}")
return 1
# Open the simulation file
print(f"Opening simulation: {sim_file}")
try:
basePart1, partLoadStatus1 = theSession.Parts.OpenBaseDisplay(str(sim_file))
partLoadStatus1.Dispose()
except Exception as e:
print(f"ERROR: Failed to open simulation: {e}")
return 1
workSimPart = theSession.Parts.BaseWork
if workSimPart is None:
print("ERROR: No work part loaded after opening simulation.")
return 1
# Get the FieldManager
fieldManager = workSimPart.FindObject("FieldManager")
if fieldManager is None:
print("ERROR: FieldManager not found. Make sure simulation results are loaded.")
return 1
# Find the ResultProbe (should be pre-configured for z-displacement)
resultProbe = fieldManager.FindObject("ResultProbe")
if resultProbe is None:
print("ERROR: ResultProbe not found. Please create a ResultProbe for z-displacement.")
return 1
# Prepare probe array for export
probes = [NXOpen.CAE.ResultProbe.Null] * 1
probes[0] = resultProbe
# Determine output file path (same directory as this journal)
journal_dir = Path(__file__).parent
output_file = journal_dir / "export_field_dz.fld"
# Export to field file
print(f"Exporting displacement field to: {output_file}")
theSession.ResultManager.ExportProbesToFieldFile(probes, str(output_file))
print(f"[OK] Successfully exported displacement field")
print(f" Output: {output_file}")
return 0
if __name__ == '__main__':
exit_code = main(sys.argv[1:])
sys.exit(exit_code)

View File

@@ -0,0 +1,48 @@
FIELD: [ResultProbe] : [TABLE]
FIELD LOCK STATE: [NO]
DUPLICATE_VALUE_OPTION: [0]
PARAMETERIZE INDEPENDENT DOMAIN: [NO]
PERSIST INTERPOL: [NO]
CREATE INTERPOLATOR: [NO]
FALLBACK DEFAULT INTERPOLATOR: [YES]
INTERPOL: [4]
VALUES OUTSIDE: [2]
REMOVE DELAUNAY SLIVERS: [NO]
INDEP VAR: [step] : [] : [] : [0]
BOUNDS: [0] : [YES] : [0] : [YES] : [27] : [0]
INDEP VAR: [node_id] : [] : [] : [5]
BOUNDS: [3] : [YES] : [413] : [YES] : [27] : [407]
DEP VAR: [x] : [Length] : [mm] : [0]
DESCRIPTION: ResultProbe
DESCRIPTION: dz
DESCRIPTION: 21-Nov-25
DESCRIPTION: 19:25:36
START DATA
0, 407, -0.0941346362233162
0, 408, -0.0937454551458359
0, 409, -0.0935764610767365
0, 410, -0.0935385450720787
0, 411, -0.0980110093951225
0, 412, -0.0959530174732208
0, 413, -0.094814196228981
0, 3, -0.10150358080864
0, 6, -0.101503469049931
0, 14, -0.0935568511486053
0, 11, -0.0935568138957024
0, 113, -0.0937929674983025
0, 114, -0.0942020565271378
0, 115, -0.0935586988925934
0, 116, -0.0936075374484062
0, 117, -0.0979839861392975
0, 118, -0.0960513949394226
0, 119, -0.0949068069458008
0, 52, -0.101693071424961
0, 145, -0.0942021608352661
0, 146, -0.093793049454689
0, 147, -0.0935587361454964
0, 148, -0.093607597053051
0, 149, -0.0979839861392975
0, 150, -0.0960515514016151
0, 151, -0.0949069485068321
0, 122, -0.0935398191213608
END DATA

View File

@@ -0,0 +1,151 @@
{
"study_name": "bracket_stiffness_optimization_atomizerfield",
"description": "Bracket Stiffness Optimization with AtomizerField Neural Acceleration - Multi-objective optimization of bracket geometry for maximum stiffness and minimum mass",
"engineering_context": "L-bracket optimization for mounting applications. Uses AtomizerField neural surrogate for accelerated optimization after initial FEA exploration phase.",
"template_info": {
"category": "structural",
"analysis_type": "static",
"typical_applications": ["mounting brackets", "L-brackets", "support structures"],
"based_on": "bracket_stiffness_optimization_V3",
"neural_enabled": true
},
"optimization_settings": {
"protocol": "protocol_11_multi_objective",
"n_trials": 100,
"sampler": "NSGAIISampler",
"pruner": null,
"timeout_per_trial": 400,
"fea_exploration_trials": 50,
"neural_acceleration_trials": 50
},
"design_variables": [
{
"parameter": "support_angle",
"bounds": [20, 70],
"description": "Angle of the support arm (degrees)",
"units": "degrees"
},
{
"parameter": "tip_thickness",
"bounds": [30, 60],
"description": "Thickness at the bracket tip (mm)",
"units": "mm"
}
],
"objectives": [
{
"name": "stiffness",
"goal": "maximize",
"weight": 1.0,
"description": "Structural stiffness (inverse of max displacement)",
"extraction": {
"action": "extract_displacement",
"domain": "result_extraction",
"params": {
"result_type": "displacement",
"metric": "max",
"invert_for_stiffness": true
}
}
},
{
"name": "mass",
"goal": "minimize",
"weight": 0.1,
"description": "Total bracket mass (kg)",
"extraction": {
"action": "extract_mass",
"domain": "result_extraction",
"params": {
"result_type": "mass",
"metric": "total"
}
}
}
],
"constraints": [
{
"name": "mass_limit",
"type": "less_than",
"threshold": 0.2,
"description": "Maximum mass constraint (kg)",
"extraction": {
"action": "extract_mass",
"domain": "result_extraction",
"params": {
"result_type": "mass",
"metric": "total"
}
}
}
],
"simulation": {
"model_file": "Bracket.prt",
"sim_file": "Bracket_sim1.sim",
"fem_file": "Bracket_fem1.fem",
"solver": "nastran",
"analysis_types": ["static"],
"solution_name": "Solution 1",
"dat_file": "bracket_sim1-solution_1.dat",
"op2_file": "bracket_sim1-solution_1.op2",
"field_export_journal": "export_displacement_field.py",
"field_output_file": "export_field_dz.fld"
},
"result_extraction": {
"mass": {
"method": "bdf_mass_extractor",
"source": "bracket_sim1-solution_1.dat",
"extractor_module": "optimization_engine.extractors.bdf_mass_extractor",
"function": "extract_mass_from_bdf",
"output_unit": "kg"
},
"stiffness": {
"method": "stiffness_calculator",
"displacement_source": "export_field_dz.fld",
"force_source": "bracket_sim1-solution_1.op2",
"extractor_module": "optimization_engine.extractors.stiffness_calculator",
"force_component": "fz",
"displacement_component": "z",
"output_unit": "N/mm"
},
"displacement": {
"method": "op2_displacement",
"source": "bracket_sim1-solution_1.op2",
"extractor_module": "optimization_engine.extractors.extract_displacement",
"function": "extract_displacement",
"output_unit": "mm"
}
},
"reporting": {
"generate_plots": true,
"save_incremental": true,
"llm_summary": true,
"generate_pareto_front": true
},
"training_data_export": {
"enabled": true,
"export_dir": "atomizer_field_training_data/bracket_stiffness_optimization_atomizerfield",
"export_every_n_trials": 1,
"include_mesh": true,
"compress": false
},
"neural_acceleration": {
"enabled": true,
"min_training_points": 50,
"auto_train": true,
"epochs": 100,
"validation_split": 0.2,
"retrain_threshold": 25,
"model_type": "parametric"
}
}

View File

@@ -0,0 +1,48 @@
# Dashboard Access
## Quick Links
| Dashboard | URL | Purpose |
|-----------|-----|---------|
| **Atomizer Dashboard** | [http://localhost:3003](http://localhost:3003) | Live Pareto plots, optimization monitoring |
| **Optuna Dashboard** | [http://localhost:8081](http://localhost:8081) | Trial history, hyperparameter importance |
## Starting the Dashboards
### Atomizer Dashboard (Recommended)
```bash
# From project root - Terminal 1 (backend)
cd atomizer-dashboard/backend
python -m uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload
# From project root - Terminal 2 (frontend)
cd atomizer-dashboard/frontend
npm run dev
```
### Optuna Dashboard (This Study Only)
```bash
# From this study directory
optuna-dashboard sqlite:///2_results/study.db --port 8081
# Or from project root
optuna-dashboard sqlite:///studies/bracket_stiffness_optimization_atomizerfield/2_results/study.db --port 8081
```
## What Each Dashboard Shows
### Atomizer Dashboard (localhost:3003)
- **Pareto Front**: Interactive scatter plot of stiffness vs mass
- **Parallel Coordinates**: Visualize how design variables affect objectives
- **Study List**: Compare multiple optimization studies
- **Trial Progress**: Real-time updates during optimization
### Optuna Dashboard (localhost:8081)
- **Trial History**: Complete log of all trials with parameters and values
- **Hyperparameter Importance**: Which variables matter most
- **Optimization History**: Convergence over time
- **Slice Plots**: 1D parameter sensitivity
---
**Tip**: The Atomizer Dashboard connects to any running study automatically. The Optuna Dashboard is study-specific and requires the database path.

View File

@@ -0,0 +1,449 @@
# Bracket Stiffness Optimization - AtomizerField
Multi-objective bracket geometry optimization with neural network acceleration.
**Created**: 2025-11-26
**Protocol**: Protocol 11 (Multi-Objective NSGA-II)
**Status**: Ready to Run
---
## 1. Engineering Problem
### 1.1 Objective
Optimize an L-bracket mounting structure to maximize structural stiffness while minimizing mass, subject to manufacturing constraints.
### 1.2 Physical System
- **Component**: L-shaped mounting bracket
- **Material**: Steel (density ρ defined in NX model)
- **Loading**: Static force applied in Z-direction
- **Boundary Conditions**: Fixed support at mounting face
- **Analysis Type**: Linear static (Nastran SOL 101)
---
## 2. Mathematical Formulation
### 2.1 Objectives
| Objective | Goal | Weight | Formula | Units |
|-----------|------|--------|---------|-------|
| Stiffness | maximize | 1.0 | $k = \frac{F}{\delta_{max}}$ | N/mm |
| Mass | minimize | 0.1 | $m = \sum_{e} \rho_e V_e$ | kg |
Where:
- $k$ = structural stiffness
- $F$ = applied force magnitude (N)
- $\delta_{max}$ = maximum absolute displacement (mm)
- $\rho_e$ = element material density (kg/mm³)
- $V_e$ = element volume (mm³)
### 2.2 Design Variables
| Parameter | Symbol | Bounds | Units | Description |
|-----------|--------|--------|-------|-------------|
| Support Angle | $\theta$ | [20, 70] | degrees | Angle of the support arm relative to base |
| Tip Thickness | $t$ | [30, 60] | mm | Thickness at the bracket tip |
**Design Space**:
$$\mathbf{x} = [\theta, t]^T \in \mathbb{R}^2$$
$$20 \leq \theta \leq 70$$
$$30 \leq t \leq 60$$
### 2.3 Constraints
| Constraint | Type | Formula | Threshold | Handling |
|------------|------|---------|-----------|----------|
| Mass Limit | Inequality | $g_1(\mathbf{x}) = m - m_{max}$ | $m_{max} = 0.2$ kg | Infeasible if violated |
**Feasible Region**:
$$\mathcal{F} = \{\mathbf{x} : g_1(\mathbf{x}) \leq 0\}$$
### 2.4 Multi-Objective Formulation
**Pareto Optimization Problem**:
$$\max_{\mathbf{x} \in \mathcal{F}} \quad k(\mathbf{x})$$
$$\min_{\mathbf{x} \in \mathcal{F}} \quad m(\mathbf{x})$$
**Pareto Dominance**: Solution $\mathbf{x}_1$ dominates $\mathbf{x}_2$ if:
- $k(\mathbf{x}_1) \geq k(\mathbf{x}_2)$ and $m(\mathbf{x}_1) \leq m(\mathbf{x}_2)$
- With at least one strict inequality
---
## 3. Optimization Algorithm
### 3.1 NSGA-II Configuration
| Parameter | Value | Description |
|-----------|-------|-------------|
| Algorithm | NSGA-II | Non-dominated Sorting Genetic Algorithm II |
| Population | auto | Managed by Optuna |
| Directions | `['maximize', 'minimize']` | (stiffness, mass) |
| Sampler | `NSGAIISampler` | Multi-objective sampler |
| Trials | 100 | 50 FEA + 50 neural |
**NSGA-II Properties**:
- Fast non-dominated sorting: $O(MN^2)$ where $M$ = objectives, $N$ = population
- Crowding distance for diversity preservation
- Binary tournament selection with crowding comparison
### 3.2 Return Format
```python
def objective(trial) -> Tuple[float, float]:
# ... simulation and extraction ...
return (stiffness, mass) # Tuple, NOT negated
```
---
## 4. Simulation Pipeline
### 4.1 Trial Execution Flow
```
┌─────────────────────────────────────────────────────────────────────┐
│ TRIAL n EXECUTION │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. OPTUNA SAMPLES (NSGA-II) │
│ θ = trial.suggest_float("support_angle", 20, 70) │
│ t = trial.suggest_float("tip_thickness", 30, 60) │
│ │
│ 2. NX PARAMETER UPDATE │
│ Module: optimization_engine/nx_updater.py │
│ Action: Bracket.prt expressions ← {θ, t} │
│ │
│ 3. HOOK: PRE_SOLVE │
│ → Log trial start, validate design bounds │
│ │
│ 4. NX SIMULATION (Nastran SOL 101) │
│ Module: optimization_engine/solve_simulation.py │
│ Input: Bracket_sim1.sim │
│ Output: .dat, .op2, .f06 │
│ │
│ 5. HOOK: POST_SOLVE │
│ → Run export_displacement_field.py │
│ → Generate export_field_dz.fld │
│ │
│ 6. RESULT EXTRACTION │
│ Mass ← bdf_mass_extractor(.dat) │
│ Stiffness ← stiffness_calculator(.fld, .op2) │
│ │
│ 7. HOOK: POST_EXTRACTION │
│ → Export BDF/OP2 to training data directory │
│ │
│ 8. CONSTRAINT EVALUATION │
│ mass ≤ 0.2 kg → feasible/infeasible │
│ │
│ 9. RETURN TO OPTUNA │
│ return (stiffness, mass) │
│ │
└─────────────────────────────────────────────────────────────────────┘
```
### 4.2 Hooks Configuration
| Hook Point | Function | Purpose |
|------------|----------|---------|
| `PRE_SOLVE` | `log_trial_start()` | Log design variables, trial number |
| `POST_SOLVE` | `export_field_data()` | Run NX journal for .fld export |
| `POST_EXTRACTION` | `export_training_data()` | Save BDF/OP2 for neural training |
---
## 5. Result Extraction Methods
### 5.1 Mass Extraction
| Attribute | Value |
|-----------|-------|
| **Extractor** | `bdf_mass_extractor` |
| **Module** | `optimization_engine.extractors.bdf_mass_extractor` |
| **Function** | `extract_mass_from_bdf()` |
| **Source** | `bracket_sim1-solution_1.dat` |
| **Output** | kg |
**Algorithm**:
$$m = \sum_{e=1}^{N_{elem}} m_e = \sum_{e=1}^{N_{elem}} \rho_e \cdot V_e$$
Where element volume $V_e$ is computed from BDF geometry (CTETRA, CHEXA, etc.).
**Code**:
```python
from optimization_engine.extractors.bdf_mass_extractor import extract_mass_from_bdf
mass_kg = extract_mass_from_bdf("1_setup/model/bracket_sim1-solution_1.dat")
```
### 5.2 Stiffness Extraction
| Attribute | Value |
|-----------|-------|
| **Extractor** | `stiffness_calculator` |
| **Module** | `optimization_engine.extractors.stiffness_calculator` |
| **Displacement Source** | `export_field_dz.fld` |
| **Force Source** | `bracket_sim1-solution_1.op2` |
| **Components** | Force: $F_z$, Displacement: $\delta_z$ |
| **Output** | N/mm |
**Algorithm**:
$$k = \frac{F_z}{\delta_{max,z}}$$
Where:
- $F_z$ = applied force in Z-direction (extracted from OP2 OLOAD resultant)
- $\delta_{max,z} = \max_{i \in nodes} |u_{z,i}|$ (from field export)
**Code**:
```python
from optimization_engine.extractors.stiffness_calculator import StiffnessCalculator
calculator = StiffnessCalculator(
field_file="1_setup/model/export_field_dz.fld",
op2_file="1_setup/model/bracket_sim1-solution_1.op2",
force_component="fz",
displacement_component="z"
)
result = calculator.calculate()
stiffness = result['stiffness'] # N/mm
```
### 5.3 Field Data Format
**NX Field Export** (.fld):
```
FIELD: [ResultProbe] : [TABLE]
RESULT TYPE: Displacement
COMPONENT: Z
START DATA
step, node_id, value
0, 396, -0.086716040968895
0, 397, -0.091234567890123
...
END DATA
```
---
## 6. Neural Acceleration (AtomizerField)
### 6.1 Configuration
| Setting | Value | Description |
|---------|-------|-------------|
| `enabled` | `true` | Neural surrogate active |
| `min_training_points` | 50 | FEA trials before auto-training |
| `auto_train` | `true` | Trigger training automatically |
| `epochs` | 100 | Training epochs |
| `validation_split` | 0.2 | 20% holdout for validation |
| `retrain_threshold` | 25 | Retrain after N new FEA points |
| `model_type` | `parametric` | Input: design params only |
### 6.2 Surrogate Model
**Input**: $\mathbf{x} = [\theta, t]^T \in \mathbb{R}^2$
**Output**: $\hat{\mathbf{y}} = [\hat{k}, \hat{m}]^T \in \mathbb{R}^2$
**Architecture**: Parametric neural network (MLP)
**Training Objective**:
$$\mathcal{L} = \frac{1}{N} \sum_{i=1}^{N} \left[ (k_i - \hat{k}_i)^2 + (m_i - \hat{m}_i)^2 \right]$$
### 6.3 Training Data Location
```
atomizer_field_training_data/bracket_stiffness_optimization_atomizerfield/
├── trial_0001/
│ ├── input/model.bdf # Mesh + design parameters
│ ├── output/model.op2 # FEA displacement/stress results
│ └── metadata.json # {support_angle, tip_thickness, stiffness, mass}
├── trial_0002/
└── ...
```
### 6.4 Expected Performance
| Metric | Value |
|--------|-------|
| FEA time per trial | 10-30 min |
| Neural time per trial | ~4.5 ms |
| Speedup | ~2,200x |
| Expected R² | > 0.95 (after 50 samples) |
---
## 7. Study File Structure
```
bracket_stiffness_optimization_atomizerfield/
├── 1_setup/ # INPUT CONFIGURATION
│ ├── model/ # NX Model Files
│ │ ├── Bracket.prt # Parametric part
│ │ │ └── Expressions: support_angle, tip_thickness
│ │ ├── Bracket_sim1.sim # Simulation (SOL 101)
│ │ ├── Bracket_fem1.fem # FEM mesh (auto-updated)
│ │ ├── bracket_sim1-solution_1.dat # Nastran BDF input
│ │ ├── bracket_sim1-solution_1.op2 # Binary results
│ │ ├── bracket_sim1-solution_1.f06 # Text summary
│ │ ├── export_displacement_field.py # Field export journal
│ │ └── export_field_dz.fld # Z-displacement field
│ │
│ ├── optimization_config.json # Study configuration
│ └── workflow_config.json # Workflow metadata
├── 2_results/ # OUTPUT (auto-generated)
│ ├── study.db # Optuna SQLite database
│ ├── optimization_history.json # Trial history
│ ├── pareto_front.json # Pareto-optimal solutions
│ ├── optimization.log # Structured log
│ └── reports/ # Generated reports
│ └── optimization_report.md # Full results report
├── run_optimization.py # Entry point
├── reset_study.py # Database reset
└── README.md # This blueprint
```
---
## 8. Results Location
After optimization completes, results will be generated in `2_results/`:
| File | Description | Format |
|------|-------------|--------|
| `study.db` | Optuna database with all trials | SQLite |
| `optimization_history.json` | Full trial history | JSON |
| `pareto_front.json` | Pareto-optimal solutions | JSON |
| `optimization.log` | Execution log | Text |
| `reports/optimization_report.md` | **Full Results Report** | Markdown |
### 8.1 Results Report Contents
The generated `optimization_report.md` will contain:
1. **Optimization Summary** - Best solutions, convergence status
2. **Pareto Front Analysis** - All non-dominated solutions with trade-off visualization
3. **Parameter Correlations** - Design variable vs objective relationships
4. **Convergence History** - Objective values over trials
5. **Constraint Satisfaction** - Feasibility statistics
6. **Neural Surrogate Performance** - Training loss, validation R², prediction accuracy
7. **Algorithm Statistics** - NSGA-II population diversity, hypervolume indicator
8. **Recommendations** - Suggested optimal configurations
---
## 9. Quick Start
### Staged Workflow (Recommended)
```bash
# STAGE 1: DISCOVER - Clean old files, run ONE solve, discover available outputs
python run_optimization.py --discover
# STAGE 2: VALIDATE - Run single trial to validate extraction works
python run_optimization.py --validate
# STAGE 3: TEST - Run 3-trial integration test
python run_optimization.py --test
# STAGE 4: TRAIN - Collect FEA training data for neural surrogate
python run_optimization.py --train --trials 50
# STAGE 5: RUN - Official optimization
python run_optimization.py --run --trials 100
# With neural acceleration (after training)
python run_optimization.py --run --trials 100 --enable-nn --resume
```
### Stage Descriptions
| Stage | Command | Purpose | When to Use |
|-------|---------|---------|-------------|
| **DISCOVER** | `--discover` | Scan model, clean files, run 1 solve, report outputs | First time setup |
| **VALIDATE** | `--validate` | Run 1 trial with full extraction pipeline | After discover |
| **TEST** | `--test` | Run 3 trials, check consistency | Before long runs |
| **TRAIN** | `--train` | Collect FEA data for neural network | Building surrogate |
| **RUN** | `--run` | Official optimization | Production runs |
### Additional Options
```bash
# Clean old Nastran files before any stage
python run_optimization.py --discover --clean
# Resume from existing study
python run_optimization.py --run --trials 50 --resume
# Reset study (delete database)
python reset_study.py
python reset_study.py --clean # Also clean Nastran files
```
---
## 10. Dashboard Access
### Live Monitoring
| Dashboard | URL | Purpose |
|-----------|-----|---------|
| **Atomizer Dashboard** | [http://localhost:3003](http://localhost:3003) | Live optimization monitoring, Pareto plots |
| **Optuna Dashboard** | [http://localhost:8081](http://localhost:8081) | Trial history, hyperparameter importance |
### Starting Dashboards
```bash
# Start Atomizer Dashboard (from project root)
cd atomizer-dashboard/frontend && npm run dev
cd atomizer-dashboard/backend && python -m uvicorn api.main:app --port 8000
# Start Optuna Dashboard (for this study)
optuna-dashboard sqlite:///2_results/study.db --port 8081
```
### What You'll See
**Atomizer Dashboard** (localhost:3003):
- Real-time Pareto front visualization
- Parallel coordinates plot for design variables
- Trial progress and success/failure rates
- Study comparison across multiple optimizations
**Optuna Dashboard** (localhost:8081):
- Trial history with all parameters and objectives
- Hyperparameter importance analysis
- Optimization history plots
- Slice plots for parameter sensitivity
---
## 11. Configuration Reference
**File**: `1_setup/optimization_config.json`
| Section | Key | Description |
|---------|-----|-------------|
| `optimization_settings.protocol` | `protocol_11_multi_objective` | Algorithm selection |
| `optimization_settings.sampler` | `NSGAIISampler` | Optuna sampler |
| `optimization_settings.n_trials` | `100` | Total trials |
| `design_variables[]` | `[support_angle, tip_thickness]` | Params to optimize |
| `objectives[]` | `[stiffness, mass]` | Objectives with goals |
| `constraints[]` | `[mass_limit]` | Constraints with thresholds |
| `result_extraction.*` | Extractor configs | How to get results |
| `neural_acceleration.*` | Neural settings | AtomizerField config |
| `training_data_export.*` | Export settings | Training data location |
---
## 12. References
- **Deb, K. et al.** (2002). A Fast and Elitist Multiobjective Genetic Algorithm: NSGA-II. *IEEE Transactions on Evolutionary Computation*.
- **pyNastran Documentation**: BDF/OP2 parsing
- **Optuna Documentation**: Multi-objective optimization with NSGA-II

View File

@@ -0,0 +1,51 @@
"""Reset bracket stiffness optimization study by deleting database and optionally cleaning Nastran files."""
import optuna
from pathlib import Path
import argparse
study_dir = Path(__file__).parent
storage = f"sqlite:///{study_dir / '2_results' / 'study.db'}"
study_name = "bracket_stiffness_optimization_atomizerfield"
def clean_nastran_files():
"""Remove old Nastran solver output files."""
model_dir = study_dir / "1_setup" / "model"
nastran_extensions = ['*.op2', '*.f06', '*.log', '*.f04', '*.pch', '*.DBALL', '*.MASTER', '*.asg', '*.diag']
temp_patterns = ['_temp*.txt', '*_temp_*']
deleted = []
for pattern in nastran_extensions + temp_patterns:
for f in model_dir.glob(pattern):
try:
f.unlink()
deleted.append(f.name)
except Exception as e:
print(f"[WARNING] Could not delete {f.name}: {e}")
return deleted
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Reset bracket optimization study")
parser.add_argument('--clean', action='store_true', help='Also clean Nastran output files')
parser.add_argument('--clean-only', action='store_true', help='Only clean Nastran files, keep database')
args = parser.parse_args()
if not args.clean_only:
try:
optuna.delete_study(study_name=study_name, storage=storage)
print(f"[OK] Deleted study: {study_name}")
except KeyError:
print(f"[INFO] Study '{study_name}' not found (database may not exist)")
except Exception as e:
print(f"[ERROR] Error: {e}")
if args.clean or args.clean_only:
deleted = clean_nastran_files()
if deleted:
print(f"[OK] Deleted {len(deleted)} Nastran files:")
for f in deleted[:5]:
print(f" - {f}")
if len(deleted) > 5:
print(f" ... and {len(deleted) - 5} more")
else:
print("[INFO] No Nastran files to clean")

File diff suppressed because it is too large Load Diff