tune(brain): uniform triangulation + bigger spacing for r_f=6mm fillets

- Switched to uniform triangulation (no density-adaptive refinement for
  initial pass — saves that for stress-informed iterations)
- s_min=45mm, s_max=55mm (was 12/35) — larger triangles fit 6mm fillets
- Boss keepout circles: 12 segments (was 32) — less boundary clutter
- Fillet must be >= 80% of r_f at every corner or pocket is skipped
- Result: 75 pockets, 481 NX entities, min fillet 4.85mm, mass 4066g
- adaptive_density=True param enables density refinement for future stress iterations
This commit is contained in:
2026-02-16 20:51:20 +00:00
parent 30981fa066
commit 239e2f01a9
3 changed files with 5797 additions and 1531 deletions

View File

@@ -37,8 +37,8 @@ DEFAULT_PARAMS = {
'p': 2.0, 'p': 2.0,
'beta': 0.3, 'beta': 0.3,
'R_edge': 15.0, 'R_edge': 15.0,
's_min': 12.0, 's_min': 45.0,
's_max': 35.0, 's_max': 55.0,
't_min': 2.5, 't_min': 2.5,
't_0': 3.0, 't_0': 3.0,
'gamma': 1.0, 'gamma': 1.0,

View File

@@ -84,7 +84,7 @@ def build_pslg(geometry, params):
# r_boss = r_hole + d_keep * hole_diameter / 2 # r_boss = r_hole + d_keep * hole_diameter / 2
hole_radius = diameter / 2.0 hole_radius = diameter / 2.0
boss_radius = hole_radius + keepout_dist boss_radius = hole_radius + keepout_dist
keepout_boundary = sample_circle(hole['center'], boss_radius, num_points=32) keepout_boundary = sample_circle(hole['center'], boss_radius, num_points=12)
else: else:
# Fallback for non-circular holes # Fallback for non-circular holes
keepout_boundary = offset_polygon(hole['boundary'], keepout_dist, inward=False) keepout_boundary = offset_polygon(hole['boundary'], keepout_dist, inward=False)
@@ -169,36 +169,39 @@ def generate_triangulation(geometry, params, max_refinement_passes=3):
""" """
pslg = build_pslg(geometry, params) pslg = build_pslg(geometry, params)
# Initial triangulation with global max area # Use s_min as the uniform target spacing for initial/non-adaptive pass.
s_max = params['s_max'] # Density-adaptive refinement only kicks in when stress results are
global_max_area = (np.sqrt(3) / 4.0) * s_max**2 # available (future iterations). For now, uniform triangles everywhere.
s_target = params['s_min']
use_adaptive = params.get('adaptive_density', False)
# Triangle options: p=PSLG, q30=min angle 30°, a=area constraint, D=conforming Delaunay # Target equilateral triangle area for the chosen spacing
result = tr.triangulate(pslg, f'pq30Da{global_max_area:.1f}') target_area = (np.sqrt(3) / 4.0) * s_target**2
# Iterative refinement based on density field # Triangle options: p=PSLG, q30=min angle 30°, a=area constraint, D=conforming
for iteration in range(max_refinement_passes): result = tr.triangulate(pslg, f'pq30Da{target_area:.1f}')
verts = result['vertices']
tris = result['triangles']
areas = compute_triangle_areas(verts, tris) if use_adaptive:
centroids = compute_centroids(verts, tris) # Iterative density-adaptive refinement (for stress-informed passes)
for iteration in range(max_refinement_passes):
verts = result['vertices']
tris = result['triangles']
# Compute target area for each triangle based on density at centroid areas = compute_triangle_areas(verts, tris)
target_areas = np.array([ centroids = compute_centroids(verts, tris)
(np.sqrt(3) / 4.0) * density_to_spacing(
evaluate_density(cx, cy, geometry, params), params
)**2
for cx, cy in centroids
])
# Check if all triangles satisfy constraints (20% tolerance) target_areas = np.array([
if np.all(areas <= target_areas * 1.2): (np.sqrt(3) / 4.0) * density_to_spacing(
break evaluate_density(cx, cy, geometry, params), params
)**2
for cx, cy in centroids
])
# Set per-triangle max area and refine if np.all(areas <= target_areas * 1.2):
result['triangle_max_area'] = target_areas break
result = tr.triangulate(result, 'rpq30D')
result['triangle_max_area'] = target_areas
result = tr.triangulate(result, 'rpq30D')
min_triangle_area = params.get('min_triangle_area', 20.0) min_triangle_area = params.get('min_triangle_area', 20.0)
result = filter_small_triangles(result, min_triangle_area) result = filter_small_triangles(result, min_triangle_area)

File diff suppressed because it is too large Load Diff