- solve_simulation.py: FEM finder now excludes idealized parts, falls back to loading .fem - solve_simulation.py: hole_count written as [Constant] not [MilliMeter] in .exp - run_doe.py: dual logging to console + results/doe_run.log
Study: 01_doe_landscape — Hydrotech Beam
See ../../README.md for project overview.
Purpose
Map the design space of the Hydrotech sandwich I-beam to identify feasible regions, characterize variable sensitivities, and prepare data for Phase 2 (TPE optimization). This is Phase 1 of the two-phase strategy (DEC-HB-002).
Quick Facts
| Item | Value |
|---|---|
| Objective | Minimize mass (kg) |
| Constraints | Tip displacement ≤ 10 mm, Von Mises stress ≤ 130 MPa |
| Design variables | 4 (3 continuous + 1 integer) |
| Algorithm | Phase 1: LHS DoE (50 trials + 1 baseline) |
| Total budget | 51 evaluations |
| Constraint handling | Deb's feasibility rules (Optuna constraint interface) |
| Status | Code complete — ready for execution |
Design Variables (confirmed via NX binary introspection)
| ID | NX Expression | Range | Type | Baseline | Unit |
|---|---|---|---|---|---|
| DV1 | beam_half_core_thickness |
10–40 | Continuous | 25.162 | mm |
| DV2 | beam_face_thickness |
10–40 | Continuous | 21.504 | mm |
| DV3 | holes_diameter |
150–450 | Continuous | 300 | mm |
| DV4 | hole_count |
5–15 | Integer | 10 | — |
Usage
Prerequisites
pip install -r requirements.txt
Requires: Python 3.10+, optuna, scipy, numpy, pandas.
Development Run (stub solver)
# From the study directory:
cd projects/hydrotech-beam/studies/01_doe_landscape/
# Run with synthetic results (for pipeline testing):
python run_doe.py --backend stub
# With verbose logging:
python run_doe.py --backend stub -v
# Custom study name:
python run_doe.py --backend stub --study-name my_test_run
Production Run (NXOpen on Windows)
# On dalidou (Windows node with NX):
python run_doe.py --backend nxopen --model-dir "C:/path/to/syncthing/Beam"
Resume Interrupted Study
python run_doe.py --backend stub --resume --study-name hydrotech_beam_doe_phase1
CLI Options
| Flag | Default | Description |
|---|---|---|
--backend |
stub |
stub (testing) or nxopen (real NX) |
--model-dir |
— | Path to NX model files (required for nxopen) |
--study-name |
hydrotech_beam_doe_phase1 |
Optuna study name |
--n-samples |
50 | Number of LHS sample points |
--seed |
42 | Random seed for reproducibility |
--results-dir |
results/ |
Output directory |
--resume |
false | Resume existing study |
-v |
false | Verbose (DEBUG) logging |
Files
| File | Description |
|---|---|
run_doe.py |
Main entry point — orchestrates the DoE study |
sampling.py |
LHS generation with stratified integer sampling |
geometric_checks.py |
Pre-flight geometric feasibility filter |
nx_interface.py |
NX automation module (stub + NXOpen template) |
requirements.txt |
Python dependencies |
OPTIMIZATION_STRATEGY.md |
Full strategy document |
results/ |
Output directory (CSV, JSON, Optuna DB) |
Output Files
After a study run, results/ will contain:
| File | Description |
|---|---|
doe_results.csv |
All trials — DVs, objectives, constraints, status |
doe_summary.json |
Study metadata, statistics, best feasible design |
optuna_study.db |
SQLite database (Optuna persistence, resume support) |
Architecture
run_doe.py
├── sampling.py Generate 50 LHS + 1 baseline
│ └── scipy.stats.qmc.LatinHypercube
├── geometric_checks.py Pre-flight feasibility filter
│ ├── Hole overlap: span/(n-1) - d ≥ 30mm
│ └── Web clearance: 500 - 2·face - d > 0
├── nx_interface.py NX solver (stub or NXOpen)
│ ├── NXStubSolver → synthetic results (development)
│ └── NXOpenSolver → real NX Nastran SOL 101 (production)
└── Optuna study
├── SQLite storage (resume support)
├── Enqueued trials (deterministic LHS)
└── Deb's feasibility rules (constraint interface)
Pipeline per Trial
Trial N
│
├── 1. Suggest DVs (from enqueued LHS point)
│
├── 2. Geometric pre-check
│ ├── FAIL → record as infeasible, skip NX
│ └── PASS ↓
│
├── 3. NX evaluation
│ ├── Update expressions (exact NX names)
│ ├── Rebuild model
│ ├── Solve SOL 101
│ └── Extract: mass (p173), displacement, stress
│
├── 4. Record results + constraint violations
│
└── 5. Log to CSV + Optuna DB
Phase 1 → Phase 2 Gate Criteria
Before proceeding to Phase 2 (TPE optimization), these checks must pass:
| Check | Threshold | Action if FAIL |
|---|---|---|
| Feasible points found | ≥ 5 | Expand bounds or relax constraints (escalate to CEO) |
| NX solve success rate | ≥ 80% | Investigate failures, fix model, re-run |
| No systematic crashes at bounds | Visual check | Tighten bounds away from failure region |
Key Design Decisions
- Baseline as Trial 0 — LAC lesson: always validate baseline first
- Pre-flight geometric filter — catches infeasible geometry before NX (saves compute, avoids crashes)
- Stratified integer sampling — ensures all 11 hole_count levels (5-15) are covered
- Deb's feasibility rules — no penalty weight tuning; feasible always beats infeasible
- SQLite persistence — study can be interrupted and resumed
- No surrogates — LAC lesson: direct FEA via TPE beats surrogate + L-BFGS
NX Integration Notes
The nx_interface.py module provides:
NXStubSolver— synthetic results from simplified beam mechanics (for pipeline testing)NXOpenSolver— template for real NXOpen Python API integration (to be completed on Windows)
Expression names are exact from binary introspection. Critical: beam_lenght has a typo in NX (no 'h') — use exact spelling.
Outputs to extract from NX:
| Output | Source | Unit | Notes |
|---|---|---|---|
| Mass | Expression p173 |
kg | Direct read |
| Tip displacement | SOL 101 results | mm | TBD: sensor or .op2 parsing |
| Max VM stress | SOL 101 results | MPa | ⚠️ pyNastran returns kPa — divide by 1000 |
References
- OPTIMIZATION_STRATEGY.md — Full strategy document
- ../../BREAKDOWN.md — Tech Lead's technical analysis
- ../../DECISIONS.md — Decision log
- ../../CONTEXT.md — Project context & expression map
Code: 🏗️ Study Builder (Technical Lead) | Strategy: ⚡ Optimizer Agent | 2026-02-10