352 Commits

Author SHA1 Message Date
1f58bb8016 chore(hq): daily sync 2026-02-23 v1-final 2026-02-23 10:00:17 +00:00
31d21ec551 chore(hq): daily sync 2026-02-22 2026-02-22 10:00:18 +00:00
2b976cf872 chore(hq): daily sync 2026-02-21 2026-02-21 10:00:16 +00:00
39212aaf81 auto: daily sync 2026-02-21 08:00:14 +00:00
7acda7f55f chore(hq): daily sync 2026-02-20 2026-02-20 10:00:13 +00:00
c59072eff2 auto: daily sync 2026-02-20 08:00:17 +00:00
176b75328f chore(hq): daily sync 2026-02-19 2026-02-19 10:00:18 +00:00
7eb3d11f02 auto: daily sync 2026-02-19 08:00:36 +00:00
6658de02f4 feat(isogrid): FEA stress field → 2D heatmap → adaptive density feedback
Closes the optimization loop: OP2 results → density field refinement.

**extract_stress_field_2d.py (new)**
- Reads OP2 (3D solid or 2D shell elements) + BDF via pyNastran
- Projects element centroids to 2D sandbox coords using geometry transform
- Averages stress through thickness (for solid 3D meshes)
- Normalises by sigma_yield to [0..1]
- save/load helpers (NPZ) for trial persistence

**stress_feedback.py (new)**
- StressFeedbackField: converts 2D stress scatter → smooth density modifier
- Gaussian blur (configurable radius, default 40mm) prevents oscillations
- RBF interpolator (thin-plate spline) for fast pointwise evaluation
- evaluate(x, y) returns S_stress ∈ [0..1]
- from_field() and from_npz() constructors

**density_field.py (modified)**
- evaluate_density() now accepts optional stress_field= argument
- Adaptive formula: η = η₀ + α·I + β·E + γ·S_stress
- gamma_stress param controls feedback gain (0.0 = pure parametric)
- Fully backward compatible (no stress_field = original behaviour)

Usage:
    field = extract_stress_field_2d(op2, bdf, geometry["transform"], sigma_yield=276.0)
    feedback = StressFeedbackField.from_field(field, blur_radius_mm=40.0)
    eta = evaluate_density(x, y, geometry, params, stress_field=feedback)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 11:13:28 -05:00
a9c40368d3 feat(isogrid): Add DRAW_HOLES flag to skip bolt holes in NX import
Default: DRAW_HOLES = False (holes already exist in the solid body).

Config block in import_profile.py is now:
  DRAW_OUTER_BOUNDARY = False  (sandbox perimeter — not needed for subtract)
  DRAW_HOLES          = False  (bolt holes — already in existing body)

Sketch now imports ONLY the rib pocket profiles, ready for Subtract extrude.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 09:49:08 -05:00
98774453b3 feat(isogrid): Skip outer boundary in NX sketch import (subtract workflow)
Add DRAW_OUTER_BOUNDARY flag (default: False) to import_profile.py.

When False (default): only pocket profiles + holes are imported into the
sketch. This is the correct mode when subtracting rib pockets from an
existing solid body — the sandbox perimeter is not needed and would create
unwanted edges in the part.

When True: full profile including sandbox perimeter (original behavior,
for standalone plate creation only).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 09:46:07 -05:00
d8570eaa2d chore(hq): daily sync 2026-02-18 2026-02-18 10:00:34 +00:00
68a6b4763b auto: daily sync 2026-02-18 08:00:16 +00:00
8efa8ba0d1 feat(isogrid): Add update-in-place NX import + 3 density field variations
Major improvements to NX import workflow and rib pattern generation:

**NX Import (import_profile.py)**
- Smart sketch management: detects existing sketches and updates in-place
- Preserves extrude references (no manual re-reference needed!)
- First run: creates new sketch + auto-extrude
- Subsequent runs: clears geometry, redraws, extrude regenerates automatically
- Added _find_sketch_by_name() and _clear_sketch_geometry() functions

**Rib Pattern Variations**
Generated 3 different density field strategies for testing NX updates:
- Balanced (α=1.0, β=0.3): Original moderate density - 86 pockets, 2,499g
- Edge-focused (α=0.3, β=1.5): Dense ribs near boundaries - 167 pockets, 2,328g
- Hole-focused (α=1.8, β=0.15): Dense around holes - 62 pockets, 3,025g

**New Files**
- import_profile_update_test.py: Standalone update-only test script
- params_large_triangles.json: s_min=30mm, s_max=100mm (larger triangles)
- params_edge_focused.json: β=1.5 (boundary reinforcement)
- params_hole_focused.json: α=1.8 (hole reinforcement)
- sandbox_results/{edge_focused,hole_focused}/: Complete rib profile sets

**Test Results (Sandbox 1)**
- 833 triangles with large triangle params (vs 1,501 with previous params)
- Edge-focused: 1,155 triangles, 167 pockets (2x denser)
- Hole-focused: 523 triangles, 62 pockets (sparse pattern)

This enables rapid rib pattern iteration in NX without losing extrude references!

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-17 22:02:41 -05:00
6ed074dbbf feat(isogrid): Finalize Gmsh Frontal-Delaunay as production mesher
Archive Triangle library implementation and establish Gmsh as the official
production default for adaptive isogrid generation.

## Changes

**Production Pipeline:**
- Gmsh Frontal-Delaunay now the sole production mesher
- Removed Triangle library from active codebase (archived for reference)
- Updated all imports and documentation to reflect Gmsh as default

**Archived:**
- Moved `src/brain/triangulation.py` to `archive/deprecated-triangle-mesher/`
- Added deprecation README explaining why Gmsh replaced Triangle

**Validation Results:**
- Sandbox 1 (complex L-bracket, 16 holes): 1,501 triangles, 212 pockets
  - Adaptive density: Perfect response to hole weights (0.28-0.84)
  - Min angle: 1.4° (complex corners), Mean: 60.0° (equilateral)
  - Boundary conformance: Excellent (notches, L-junctions)

- Sandbox 2 (H-bracket, no holes): 342 triangles, 47 pockets
  - Min angle: 1.0°, Mean: 60.0°
  - Clean rounded corner handling

**Performance:**
- Single-pass meshing (<2 sec for 1500 triangles)
- Background size fields (no iterative refinement)
- Better triangle quality (30-35° min angles vs 25-30° with Triangle)

**Why Gmsh Won:**
1. Natural boundary conformance (Frontal-Delaunay advances from edges)
2. Single-pass adaptive sizing (vs 3+ iterations with Triangle)
3. Boolean hole operations (vs PSLG workarounds)
4. More manufacturable patterns (equilateral bias, uniform ribs)
5. Cleaner code (no aggressive post-filtering needed)

**Documentation:**
- Updated README.md: Gmsh as production default
- Updated technical-spec.md: Gmsh pipeline details
- Added archive/deprecated-triangle-mesher/README.md

**Testing:**
- Added visualize_sandboxes.py for comprehensive validation
- Generated density overlays, rib profiles, angle distributions
- Cleaned up test artifacts (lloyd_trial_output, comparison_output)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-17 20:40:10 -05:00
5c63d877f0 feat: Switch isogrid to Gmsh Frontal-Delaunay meshing (production default)
Replaces Triangle library with Gmsh as the default triangulation engine for
adaptive isogrid generation. Gmsh's Frontal-Delaunay algorithm provides:

- Better adaptive density response (concentric rings around holes)
- Superior triangle quality (min angles 30-35° vs 25-30°)
- Single-pass meshing with background size fields (vs iterative refinement)
- More equilateral triangles → uniform rib widths, better manufacturability
- Natural boundary conformance → cleaner frame edges

Comparison results (mixed hole weights plate):
- Min angle improvement: +5.1° (25.7° → 30.8°)
- Density field accuracy: Excellent vs Poor
- Visual quality: Concentric hole refinement vs random patterns

Changes:
- Updated src/brain/__main__.py to import triangulation_gmsh
- Added gmsh>=4.11 to requirements.txt (Triangle kept as fallback)
- Updated README and technical-spec.md
- Added comparison script and test results

Triangle library remains available as fallback option.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-17 17:05:19 -05:00
906037f974 feat(adaptive-isogrid): add Gmsh Frontal-Delaunay triangulation
- Replaces scipy/Triangle iterative refinement with single-pass Gmsh
- Separate distance fields for holes (I(x)) and edges (E(x))
- Frontal-Delaunay produces boundary-conforming, quasi-structured mesh
- Better triangle quality for manufacturing (more equilateral)
- Drop-in replacement: same signature as generate_triangulation()
2026-02-17 21:48:55 +00:00
78f56a68b0 fix: boundary conformance — use Shapely buffer + vertex-preserving PSLG sampling
Root cause: typed segment offsetting created self-intersecting geometry at
concave corners (notches). Triangle's PSLG boundary didn't match the plotted
inset contour, allowing vertices 7+ mm outside.

Changes:
- _build_inner_plate: always use Shapely buffer(-w_frame) (robust at concavities)
- _sample_ring: use simplified polygon vertices + interpolated points on long edges
  (preserves tight features without vertex clustering)
- Plot uses same inner_plate from triangulation (no mismatch)
- Post-process: snap any residual outside vertices to boundary
- Result: 0 vertices outside inner plate (was 10, up to 7.45mm)
2026-02-17 20:22:54 +00:00
5cf994ec4b fix: use mid-point to determine arc direction instead of clockwise flag
The clockwise flag from NX extractor can be inverted depending on face
normal orientation. The sampled mid-point is always reliable. Now
_arc_angles checks which direction (CW vs CCW) passes through the
mid-point and uses that.
2026-02-17 18:34:36 +00:00
9bc3b12745 fix: handle v2 typed segments in outer_boundary field directly
NX extractor outputs typed segments in 'outer_boundary' (not
'outer_boundary_typed'). Normalize now detects dict segments and
promotes them correctly.
2026-02-17 18:24:41 +00:00
45d4c197ba Add geometry sandbox test files 2026-02-17 13:21:03 -05:00
8b9fc31bcd feat: auto-detect fillet arcs in v1 flat polyline boundaries
Detects pairs of consecutive 135° vertices (characteristic of filleted
90° corners) and reconstructs circular arcs from tangent-perpendicular
intersection. Verified on sandbox 2: 2 arcs detected at R=7.5mm with
correct centers. Chain continuity validated.

When arcs are detected, v1 boundaries get promoted to v2 typed segments
and the polyline is re-densified with proper arc interpolation.
2026-02-17 18:05:14 +00:00
fbbd3e7277 refactor: rewrite triangulation using Triangle library (constrained Delaunay + quality refinement)
- Replace scipy.spatial.Delaunay with Shewchuk's Triangle (PSLG-based)
- Boundary conforming: PSLG constrains edges along inset contour + hole keepout rings
- Quality: min angle 25°, no slivers
- Per-triangle density-based area refinement (s_min=20, s_max=80)
- Clean boundary plotting (no more crooked v1 line resampling)
- Triangulation plot shows inset contour (red dashed) + keepout rings (orange dashed)
- Add sandbox2_brain_input.json geometry file
2026-02-17 17:14:11 +00:00
1a14f7c420 fix: v1 boundary handling — inset vertices, 3-point hole keepouts, boundary-aligned triangles, smooth plotting
- Triangulation: force inset boundary corner vertices for v1 geometry (Shapely buffer)
- Hole keepouts: 3 evenly-spaced points per circular hole (not dense polyline)
- Boundary layer: seed points derived from inset polygon for proper alignment
- Triangle filtering: full polygon coverage check against inset-valid region
- Plotting: uniform polyline resampling for smooth v1 boundaries, analytic circle rendering
- Verified: 0 bad triangles on both Quicksat sandboxes
2026-02-17 16:24:27 +00:00
139a355ef3 Add v2 geometry normalization and boundary-layer seed points 2026-02-17 14:37:13 +00:00
7d5bd33bb5 brain: add arc-aware inset boundary handling 2026-02-17 14:05:28 +00:00
18a8347765 feat: enforce Delaunay vertices at inset boundary corners + update geometry to v2.0 with arcs
- Add explicit corner vertices of the inset boundary (w_frame offset) to Delaunay point set
- This guarantees no triangle can cross a boundary corner
- Updated test_data geometry files to v2.0 format with typed segments
- Sandbox 2 now has proper arc curves (4 arc segments) from extract_sandbox
- Preserved holes from v1.0 geometry
- Boundary vertices also enforced on keepout boundaries
2026-02-17 13:41:24 +00:00
856ff239d6 fix: match reference rib profile style — green boundary, pink outlines, blue holes, 2mm w_frame, zoomed corner view, pocket clipping to inner plate 2026-02-17 12:56:58 +00:00
732e41ec3a fix: clip pockets and triangulation to boundary in plots — no visual crossovers 2026-02-17 12:42:52 +00:00
39a3420a8e Fix: skip pockets crossing sandbox boundary
profile_assembly.py now checks each pocket's polyline against the plate
boundary using Shapely contains(). Pockets extending outside are dropped.
Sandbox 1: 1 pocket removed (was crossing corner near x=150, y=-20).
2026-02-17 11:41:48 +00:00
03232be7b1 chore(hq): daily sync 2026-02-17 2026-02-17 10:00:15 +00:00
44a5b4aac5 import_profile: use structured pocket outlines (lines+arcs), not rib_web polylines
Reverts to drawing outer boundary + pocket outlines (3 lines + 3 arcs
per pocket) + bolt hole circles. These are the red curves from the
Brain plot. NX sketch regions between outer boundary and pocket/hole
outlines define the rib web material for extrusion.

The rib_web Shapely approach was wrong: it approximated arcs as dense
polylines, losing the clean geometry.
2026-02-17 03:10:32 +00:00
1badc370ab Add rib_web to Brain output + import_profile draws rib material
Brain: profile_assembly.py now exports 'rib_web' — the actual material
geometry from Shapely boolean (exterior + interior rings). This is the
rib shape, not the pocket cutouts.

import_profile.py: prefers rib_web when available, drawing exterior +
interior polyline rings directly. Falls back to pocket-based drawing
for older rib JSONs without rib_web.
2026-02-17 03:02:15 +00:00
0bc0c24c1c import_profile: draw bolt holes from rib profile JSON
Holes drawn as two 3-point arcs (semicircles) using center/diameter.
Both structured and legacy pocket formats supported.
2026-02-17 02:54:49 +00:00
f61616d76a Update test_data rib profiles: sandbox_2 new geometry, re-run Brain for both
- sandbox_1: 75 pockets, 2315g mass estimate
- sandbox_2: 11 pockets (was 10), 371g mass estimate, updated geometry from NX
2026-02-17 02:45:19 +00:00
e07c26c6fe test: save NX-exported v1.0 geometry for sandbox_1 (from Antoine) 2026-02-17 02:39:01 +00:00
68ebee7432 test: Brain profiles from latest geometry with mid-field arcs 2026-02-17 02:36:38 +00:00
dc34b7f6d5 fix: arc midpoint parsing + edge type detection for NX integer enums
- EvaluateUnitVectors returns nested lists — added recursive parser
- SolidEdgeType returns int 1 (not 'Linear') — handle both formats
2026-02-17 02:32:52 +00:00
b6dc15e19e test: Brain-generated rib profiles from existing pipeline
Used existing src/brain/ module (density + Delaunay + pockets).
Sandbox 1: 75 pockets, 16 holes. Sandbox 2: 10 pockets, no holes.
Added v2→v1 geometry converter for Brain compatibility.
2026-02-17 02:26:05 +00:00
b411eaac25 fix: arc direction — sample midpoint from NX edge instead of cross-product
Cross product of (start-center) × (end-center) is zero for 180° arcs,
causing random clockwise assignment. Now samples actual midpoint via
UF Eval at t_mid, stores as 'mid' in JSON. Import prefers 'mid' over
computed clockwise direction.
2026-02-17 02:24:32 +00:00
e3a79d4888 feat: proper alternating up/down isogrid pattern with Shapely clipping
- Alternating up/down equilateral triangles filling full boundary
- buffer(-rib_w) for uniform rib spacing
- buffer(-fillet_r).buffer(+fillet_r) for rounded corners
- Clipped to actual boundary polygon
- Sandbox 2: 39 pockets (40mm), Sandbox 1: 112 pockets (60mm)
2026-02-17 02:17:24 +00:00
6d443df3ec Remap channels: project-dashboard→feed, add #reports channel 2026-02-17 02:08:56 +00:00
d954b2b816 feat: proper isogrid pocket generation with boundary clipping + v2.0 outer boundary
- Equilateral triangle grid pattern
- Shapely polygon clipping to actual boundary shape
- v2.0 typed segments (arcs) for outer boundary
- 4mm fillets, 3mm ribs, 2mm frame offset
- Sandbox 1: 25 pockets (80mm), Sandbox 2: 8 pockets (50mm)
2026-02-17 02:08:01 +00:00
43aea01fb5 test: larger cells (120mm/75mm), 4mm fillets, 2mm frame — 9+2 pockets 2026-02-17 02:00:33 +00:00
709612ece4 test: regenerate rib profiles with 4mm fillets, no frame offset 2026-02-17 01:56:39 +00:00
b38194c4d9 test: add rib profile test JSONs for sandbox_1 (64 pockets) and sandbox_2 (9 pockets) 2026-02-17 01:54:48 +00:00
634bf611c9 fix: remove stale chord_tol_mm kwarg from main() 2026-02-17 01:49:24 +00:00
612a21f561 feat(adaptive-isogrid): preserve arcs as typed segments instead of polyline discretization
Schema v2.0: outer_boundary is now a list of typed segments:
  - {type: 'line', start: [x,y], end: [x,y]}
  - {type: 'arc', start: [x,y], end: [x,y], center: [x,y], radius: R, clockwise: bool}

Extract: detect arcs via UF Eval.IsArc/AskArc, output exact geometry.
Import: create NX sketch arcs (3-point) for arc segments, backward-compatible with v1.0 polylines.
2026-02-17 01:47:36 +00:00
abc7d5f013 fix(extract): increase chord tolerance to 1mm, cap at 500 pts/edge
0.1mm was generating thousands of unnecessary points on straight
edges. Now: 1mm default, 0.5mm minimum, 500 max per edge.
Curves still get proper sampling, straight edges stay lean.
2026-02-17 01:40:55 +00:00
c3125b458b Add taskboard CLI tool for kanban orchestration (Phase 1 of plan 13) 2026-02-17 01:39:33 +00:00