228 lines
10 KiB
Markdown
228 lines
10 KiB
Markdown
# Technical Breakdown — Adaptive Isogrid Plate Lightweighting
|
||
|
||
**Project:** Isogrid Dev Plate
|
||
**Author:** Technical Lead 🔧
|
||
**Date:** 2026-02-18
|
||
**Status:** Architecture complete — Campaign 01 ready to run
|
||
|
||
---
|
||
|
||
## 1. Problem Formulation
|
||
|
||
### 1.1 Structural Configuration
|
||
|
||
Flat plate with bolt holes, optimized by replacing solid material with an adaptive triangular isogrid.
|
||
- 2 sandbox regions (sandbox_1, sandbox_2) — where ribs are generated and changed each iteration
|
||
- Bolt holes: excluded from pocket generation (keepout zone around each hole)
|
||
- Plate material: AL7075-T6 (confirmed 2026-02-18 — see material discrepancy note in §4.2)
|
||
- 3D solid FEA already run (CHEXA/CTETRA, SOL 101)
|
||
|
||
### 1.2 Objective Function
|
||
|
||
**Single-objective: minimize total plate mass.**
|
||
|
||
```
|
||
minimize: mass(params)
|
||
subject to: max_von_mises ≤ σ_allow = 100.6 MPa
|
||
```
|
||
|
||
> **No displacement constraint** — confirmed by Antoine 2026-02-18.
|
||
|
||
The penalty approach:
|
||
```python
|
||
penalty = 0.0
|
||
if max_stress > sigma_allow:
|
||
penalty += 1e4 * ((max_stress / sigma_allow) - 1.0) ** 2
|
||
return mass_kg + penalty
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Design Variable Classification
|
||
|
||
### 2.1 Optimized Variables (8) — Atomizer design space
|
||
|
||
These directly control rib pattern shape and density. Every trial samples all 8.
|
||
|
||
| Variable | Range | Description |
|
||
|----------|-------|-------------|
|
||
| `eta_0` | [0.0, 0.4] | Baseline density offset — global rib density floor |
|
||
| `alpha` | [0.3, 2.0] | Hole influence scale — how much ribs cluster around holes |
|
||
| `beta` | [0.0, 1.0] | Edge influence scale — how much ribs reinforce the perimeter |
|
||
| `gamma_stress` | [0.0, 1.5] | Stress feedback gain — how much FEA stress adds density |
|
||
| `R_0` | [10, 100] mm | Base influence radius — how far hole influence spreads |
|
||
| `R_edge` | [5, 40] mm | Edge influence radius — depth of perimeter reinforcement band |
|
||
| `s_min` | [15, 35] mm | Minimum triangle edge length → densest zone spacing (manufacturing floor: 15 mm) |
|
||
| `s_max` | [40, 60] mm | Maximum triangle edge length → sparsest zone spacing (lower bound 40 guarantees s_min < s_max) |
|
||
|
||
**Total: 8 continuous variables.** Manageable for Optuna TPE; expect useful signal in 50–100 trials, convergence in 200–500.
|
||
|
||
### 2.2 Manufacturing Constraints (Fixed) — NOT optimized
|
||
|
||
These are set from machining requirements and are fixed for the entire campaign.
|
||
They can be adjusted between campaigns if the process changes.
|
||
|
||
| Parameter | Fixed Value | Why Fixed | Manufacturing Basis |
|
||
|-----------|------------|-----------|---------------------|
|
||
| `t_min` | 2.5 mm | Minimum rib thickness: thinner ribs are not machinable and would break | CNC milling minimum land width |
|
||
| `t_0` | 3.5 mm | Nominal rib thickness: baseline starting width before density scaling | Design intent |
|
||
| `w_frame` | 5.0 mm | Perimeter frame width: solid band around the sandbox boundary | Edge seal, clamping, aesthetics |
|
||
| `r_f` | 1.5 mm | Pocket fillet radius: corner radius on each pocket. **Sole pocket size filter.** | = tool radius. Smaller → need smaller endmill |
|
||
| `d_keep` | 1.2× | Hole keepout multiplier: minimum clear distance = 1.2 × hole diameter | Prevents thin walls around bolt holes |
|
||
| `min_triangle_area` | 25.0 mm² | Minimum pocketable triangle area | Below this: too small to machine → skip as solid |
|
||
|
||
> To change manufacturing constraints for a campaign, edit `MANUFACTURING_CONSTRAINTS` in
|
||
> `optimization_engine/isogrid/study.py` and document the change here.
|
||
|
||
### 2.3 Math/Model Constants (Fixed) — NOT optimized
|
||
|
||
These govern the mathematical form of the density field. Fixed at well-behaved defaults.
|
||
Changing them would fundamentally change the shape of the density function.
|
||
|
||
| Parameter | Fixed Value | Description |
|
||
|-----------|------------|-------------|
|
||
| `p` | 2.0 | Gaussian decay exponent (p=2 → smooth Gaussian, p=1 → exponential, p=4 → box-like) |
|
||
| `kappa` | 1.0 | Weight-to-radius coupling: heavier holes get proportionally larger influence radius |
|
||
| `gamma` | 1.0 | Density-to-thickness coupling: t(x) = t₀ × (1 + γ·η) |
|
||
|
||
> Note: `gamma` here is the rib-thickness coupling, distinct from `gamma_stress` (stress feedback gain).
|
||
|
||
---
|
||
|
||
## 3. Density Field Formulation
|
||
|
||
The full adaptive formula with stress feedback:
|
||
|
||
```
|
||
η(x,y) = clamp(0, 1, η₀ + α·I(x) + β·E(x) + γ_stress·S_stress(x))
|
||
```
|
||
|
||
Where:
|
||
- `I(x) = Σᵢ wᵢ · exp(-(dᵢ/Rᵢ)^p)` — hole influence (sum over all bolt holes)
|
||
- `E(x) = exp(-(d_edge/R_edge)^p)` — edge reinforcement
|
||
- `S_stress(x)` — normalized FEA stress field from previous trial, ∈ [0..1]
|
||
- `Rᵢ = R₀ · (1 + κ · wᵢ)` — per-hole radius scales with hole weight
|
||
|
||
Local spacing: `s(x) = s_max - (s_max - s_min) · η(x)`
|
||
Local rib thickness: `t(x) = clip(t₀ · (1 + γ · η(x)), t_min, t_max)`
|
||
|
||
---
|
||
|
||
## 4. FEA Pipeline Status
|
||
|
||
### 4.1 What Is Done
|
||
|
||
| Step | Status | Notes |
|
||
|------|--------|-------|
|
||
| NX geometry extraction (`extract_sandbox.py`) | ✅ Done | geometry_sandbox_1.json, geometry_sandbox_2.json |
|
||
| Python Brain (density → profile) | ✅ Done | Gmsh Frontal-Delaunay, Shapely pockets |
|
||
| NX rib import (`import_profile.py`) | ✅ Done | Update-in-place, preserves extrude reference |
|
||
| 3D solid FEA (manual baseline) | ✅ Done | OP2 results available |
|
||
| Stress field extraction (OP2 → 2D) | ✅ Done | `optimization_engine/extractors/extract_stress_field_2d.py` |
|
||
| Stress feedback field | ✅ Done | `optimization_engine/isogrid/stress_feedback.py` |
|
||
| Atomizer study wiring | ✅ Done | `studies/01_v1_tpe/run_optimization.py` |
|
||
| Campaign 01 execution | 🔴 Not started | Run `run_optimization.py` |
|
||
|
||
### 4.2 FEA Configuration
|
||
|
||
- **Solver:** NX Nastran, SOL 101 (linear static)
|
||
- **Elements:** 3D solid (CHEXA, CTETRA, CPENTA)
|
||
- **Stress units:** NX kg-mm-s outputs kPa → extractor divides by 1000 → MPa
|
||
- **Material (optimization):** AL7075-T6 — σ_yield = 503 MPa, ρ = 2810 kg/m³, SF = 5 → σ_allow = 100.6 MPa
|
||
- **Sandbox regions:** 2 (sandbox_1 is larger, sandbox_2 is smaller patch)
|
||
|
||
> ⚠️ **Material discrepancy (Gap G-01):** The NX FEM model (MAT1 card in the DAT file) uses
|
||
> E = 68.98 GPa and ρ = 2.711×10⁻⁶ kg/mm³, which correspond to **AL6061-T6** properties.
|
||
> Optimization allowables and mass targets are based on **AL7075-T6** as confirmed by Antoine.
|
||
> This discrepancy means FEA stiffness/mass are slightly underestimated.
|
||
> Tracked as G-01 in CONTEXT.md — update MAT1 card before next FEA campaign.
|
||
|
||
### 4.3 Key FEA Files
|
||
|
||
**NX model (reference copies — do NOT modify):**
|
||
```
|
||
projects/isogrid-dev-plate/models/
|
||
├── ACS_Stack_Main_Plate_Iso_Project.prt ← Geometry part
|
||
├── ACS_Stack_Main_Plate_Iso_project_fem2_i.prt ← Idealized part (CRITICAL for mesh update)
|
||
├── ACS_Stack_Main_Plate_Iso_project_fem2.fem ← FEM (3D solid, CHEXA/CTETRA)
|
||
├── ACS_Stack_Main_Plate_Iso_project_sim2.sim ← SOL 101 simulation
|
||
└── acs_stack_main_plate_iso_project_sim2-solution_1.op2 ← Baseline FEA results
|
||
```
|
||
|
||
**Working copies (used by optimizer):**
|
||
```
|
||
studies/01_v1_tpe/1_setup/model/
|
||
├── ACS_Stack_Main_Plate_Iso_Project.prt
|
||
├── ACS_Stack_Main_Plate_Iso_project_fem2_i.prt
|
||
├── ACS_Stack_Main_Plate_Iso_project_fem2.fem
|
||
├── ACS_Stack_Main_Plate_Iso_project_sim2.sim
|
||
└── adaptive_isogrid_data/
|
||
├── geometry_sandbox_1.json ← Sandbox boundary + holes
|
||
└── geometry_sandbox_2.json
|
||
```
|
||
|
||
**Python Brain (canonical location):**
|
||
```
|
||
optimization_engine/isogrid/
|
||
├── density_field.py ← η(x) field computation
|
||
├── triangulation.py ← Gmsh Frontal-Delaunay mesh
|
||
├── pocket_profiles.py ← Inset + fillet pockets
|
||
├── stress_feedback.py ← StressFeedbackField (RBF interpolator)
|
||
└── study.py ← PARAM_SPACE, MANUFACTURING_CONSTRAINTS, MATERIAL
|
||
|
||
optimization_engine/extractors/
|
||
└── extract_stress_field_2d.py ← OP2+BDF → 2D stress field
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Rib Pattern Variants Tested
|
||
|
||
Three density field configurations were tested for visual review in NX:
|
||
|
||
| Variant | α | β | Pockets (S1+S2) | Mass Est. | Character |
|
||
|---------|---|---|----------------|-----------|-----------|
|
||
| Balanced | 1.0 | 0.3 | 86 + 33 = 119 | ~2,790g | Good general pattern |
|
||
| Edge-focused | 0.3 | 1.5 | 167 + 10 = 177 | ~2,328g | Dense perimeter, sparse center |
|
||
| Hole-focused | 1.8 | 0.15 | 62 + 37 = 99 | ~3,025g | Dense around holes, thin edges |
|
||
|
||
All three were imported to NX using the update-in-place workflow (sketch preserved, extrude reference maintained).
|
||
|
||
---
|
||
|
||
## 6. Algorithm Recommendation
|
||
|
||
**Optuna TPE (Tree-structured Parzen Estimator)** — standard Atomizer configuration.
|
||
|
||
| Property | Value |
|
||
|----------|-------|
|
||
| Design variables | 8 continuous |
|
||
| Objective | 1 (minimize mass) |
|
||
| Constraint | 1 (stress — penalty-based; no displacement constraint) |
|
||
| Trials budget | 200 (Campaign 01) |
|
||
| Estimated iteration time | ~90–120 sec (NX mesh + Nastran + extract) |
|
||
| Total runtime estimate | ~8–10 hours for 200 trials |
|
||
|
||
In V1, `gamma_stress` is sampled by TPE but has no effect (no S_prev stress field available).
|
||
In V2 (sequential seeding), S_prev is loaded from the globally best previous trial; `gamma_stress`
|
||
then actively reshapes the density field toward high-stress zones. No extra FEA per trial.
|
||
|
||
---
|
||
|
||
## 7. Next Steps
|
||
|
||
| Priority | Action | Status |
|
||
|----------|--------|--------|
|
||
| ✅ DONE | `studies/01_v1_tpe/run_optimization.py` created | — |
|
||
| ✅ DONE | Material confirmed: AL7075-T6, σ_allow = 100.6 MPa (SF=5) | — |
|
||
| ✅ DONE | Model files copied to `studies/01_v1_tpe/1_setup/model/` | — |
|
||
| ✅ DONE | Geometry JSONs in `1_setup/model/adaptive_isogrid_data/` | — |
|
||
| 🔴 HIGH | Run Campaign 01: `python studies/01_v1_tpe/run_optimization.py` | Pending |
|
||
| 🟡 MED | Update MAT1 card in NX model to AL7075-T6 properties (Gap G-01) | Pending |
|
||
| 🟡 MED | Extract baseline solid plate mass (Gap G-02) | Pending |
|
||
| 🟢 LOW | Benchmark single iteration time for runtime planning | Pending |
|
||
|
||
---
|
||
|
||
*Technical Lead 🔧 — 8 parameters, physics-driven, stress-only constraint, ready to run.*
|