Tet mesh quality: one validity criterion, Delaunay refinement, ODT, Klingner–Shewchuk, tet10

The end-to-end demo met a raw-CDT sliver that the validity gate accepted (exactly positive) and
the solver refused. Now:

- One validity criterion, `fieldcraft_model::admissible_jacobian` (normalized Jacobian above
  1e-12), used by the implicit solver (fem `positive_inverse`), the explicit tet4/hex8
  kinematics and the mesh gate, which proves it on the whole element (tet4: the solvers' own
  Jacobian; curved kinds: a Bernstein floor), so whatever passes the gate passes the solvers.
- CDT rounding repaired by flips on the rounded mesh (Diazzi et al. 2023 §5.1) instead of the
  ±2-ulp nudge.
- `fieldcraft-mesh::tet`: a mutable tetrahedral complex whose every change is a checked
  replacement (positive and admissible tetrahedra, faces matched with opposite orientation) with
  an exact undo log; edge removal (Klincsek), multi-face removal, Delaunay insertion with
  boundary faces, edge collapse; a curvature- and thickness-graded size field; constrained
  Delaunay refinement with encroachment splits; ODT smoothing; the Klingner–Shewchuk schedule;
  boundary vertices moved onto the exact B-rep surfaces at the end; tet10 with mid-edge nodes on
  the geometry.
- `mesh.tet.generate` gains size, order, quality, quality_target, curvature_angle, grading,
  max_passes, max_points and reports the CDT's and the mesh's quality; `solve.probe` takes a set
  and reports its largest von Mises stress.
- Oracle cases filleted-bracket-fillet-stress(-coarse): the fillet's peak von Mises stress on
  tet10 meshes of 2k and 13.5k elements, 213.3 MPa (a four-level study stays within 1.8%); the
  CDT cases keep the raw tetrahedralization.
- Corpus quality columns: all 20 valid parts mesh and pass the gate.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-14 08:28:49 -04:00
1 parent fed27d816d
commit 9469ac0853
53 files changed
+5880 -278

No files matched your search

+1 -1
View File
@@ -1,3 +1,3 @@
[
{"command": "mesh.tet.generate", "params": {"body": "Cylinder", "tolerance": 0.05}, "id": "tet"}
{"command": "mesh.tet.generate", "params": {"body": "Cylinder", "tolerance": 0.05, "quality": false}, "id": "tet"}
]
+1 -1
View File
@@ -1,3 +1,3 @@
[
{"command": "mesh.tet.generate", "params": {"body": "Steps", "tolerance": 0.05}, "id": "tet"}
{"command": "mesh.tet.generate", "params": {"body": "Steps", "tolerance": 0.05, "quality": false}, "id": "tet"}
]
@@ -0,0 +1,12 @@
# Filleted L-bracket: peak stress on the fillet (coarse mesh)
The corpus part `filleted-bracket` (an 8 mm L-bracket with an R6 inside fillet and a hole through
each leg), built with SolidCraft from `design.json`. The foot face `F2:side:l1` is clamped and a
2 kN load in +x acts on the top face `F2:side:l5` (steel, E = 210 GPa, ν = 0.3). The leg bends
about its root, where the fillet concentrates the stress; beam theory gives about 197 MPa nominal
at the root (6FL/(bt²) with L = 42 mm, b = 40 mm, t = 8 mm).
`mesh.tet.generate` makes a quality tet10 mesh (size 16 mm, 90° per element along curved
faces), with the boundary and mid-edge nodes on the exact fillet cylinder. The peak nodal von
Mises stress on the fillet over a four-level study (sizes 16, 11.3, 8, 5.66 mm with 90°, 64°,
45°, 32°): 213.3, 210.6, 214.3, 213.3 MPa. The coarse and the fine level are the two cases.
@@ -0,0 +1,89 @@
{
"commands": [
{
"command": "sketch.create",
"params": {
"plane": "XY",
"name": "Profile"
}
},
{
"command": "sketch.line",
"params": {
"points": [
[
0,
0
],
[
60,
0
],
[
60,
8
],
[
8,
8
],
[
8,
50
],
[
0,
50
]
],
"closed": true
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.extrude",
"params": {
"distance": 40,
"body_name": "Bracket"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
8,
8,
20
]
],
"radius": 6
}
},
{
"command": "solid.hole",
"params": {
"position": [
40,
8,
20
],
"diameter": 8
}
},
{
"command": "solid.hole",
"params": {
"position": [
8,
32,
20
],
"diameter": 8
}
}
]
}
@@ -0,0 +1,38 @@
{
"title": "Filleted L-bracket under a side load: the peak von Mises stress on the R6 fillet, coarse tet10 mesh",
"kind": "theory",
"source": "mesh convergence of the finite element solution (P. J. Roache, Verification and Validation in Computational Science and Engineering, Hermosa, 1998, ch. 5): the bracket has no closed-form stress; the reference is the mesh-independent peak of a four-level study of quadratic tetrahedral meshes refined by √2 in size and in curvature resolution (README.md); equilibrium",
"slow": true,
"quantities": [
{
"id": "fillet_peak",
"quantity": "largest nodal von Mises stress on the fillet face (MPa)",
"measure": {
"command": "solve.probe",
"params": {
"step": "Load",
"set": "fillet"
},
"pointer": "/max_von_mises/value"
},
"value": 213.0,
"tolerance": {
"relative": 0.03
},
"reason": "the four-level study gives 213.3, 210.6, 214.3, 213.3 MPa (2k to 13.5k elements): the bending stress is converged across the fillet, and the peak nodal value moves only with which of the fillet's tessellation lines (fixed angles, through every level) carries the largest node, by under 2%"
},
{
"id": "reaction",
"quantity": "total reaction x (N)",
"measure": {
"from": "solve",
"pointer": "/reaction_total/0"
},
"value": -2000.0,
"tolerance": {
"relative": 1e-09
},
"reason": "equilibrium holds to rounding"
}
]
}
@@ -0,0 +1,13 @@
{
"note": "FieldCraft's accepted results for this case, written by `cargo xtask oracle --bless`. A result outside its band fails CI.",
"values": {
"fillet_peak": {
"band": 2.1330697455903942e-7,
"value": 213.30697455903942
},
"reaction": {
"band": 2.000000000000858e-6,
"value": -2000.0000000008579
}
}
}
@@ -0,0 +1,13 @@
[
{"command": "mesh.tet.generate", "params": {"body": "Bracket", "tolerance": 0.088, "size": 16.0, "curvature_angle": 90.0, "order": "quadratic"}, "id": "tet"},
{"command": "model.material.create", "params": {"name": "Steel", "elastic": {"type": "isotropic", "young": 210000, "poisson": 0.3}, "density": 7.85e-09}},
{"command": "model.set.create", "params": {"name": "all", "geometry": [{"body": "Bracket"}]}},
{"command": "model.set.create", "params": {"name": "foot", "geometry": [{"body": "Bracket", "face": "F2:side:l1"}]}},
{"command": "model.set.create", "params": {"name": "top", "geometry": [{"body": "Bracket", "face": "F2:side:l5"}]}},
{"command": "model.set.create", "params": {"name": "fillet", "geometry": [{"body": "Bracket", "face": "F3:blend:F2:side:l3|F2:side:l4"}]}},
{"command": "model.section.create", "params": {"name": "solid", "set": "all", "material": "Steel", "kind": {"type": "solid"}}},
{"command": "model.boundary_condition.create", "params": {"name": "clamp", "type": "fixed", "target": {"set": "foot"}}},
{"command": "model.load.create", "params": {"name": "push", "type": "force", "target": {"set": "top"}, "vector": [2000, 0, 0]}},
{"command": "model.step.create", "params": {"name": "Load", "procedure": {"type": "static"}, "boundary_conditions": ["clamp"], "loads": ["push"]}},
{"command": "solve.static", "params": {}, "id": "solve"}
]
@@ -0,0 +1,12 @@
# Filleted L-bracket: peak stress on the fillet (fine mesh)
The corpus part `filleted-bracket` (an 8 mm L-bracket with an R6 inside fillet and a hole through
each leg), built with SolidCraft from `design.json`. The foot face `F2:side:l1` is clamped and a
2 kN load in +x acts on the top face `F2:side:l5` (steel, E = 210 GPa, ν = 0.3). The leg bends
about its root, where the fillet concentrates the stress; beam theory gives about 197 MPa nominal
at the root (6FL/(bt²) with L = 42 mm, b = 40 mm, t = 8 mm).
`mesh.tet.generate` makes a quality tet10 mesh (size 5.66 mm, 31.8° per element along curved
faces), with the boundary and mid-edge nodes on the exact fillet cylinder. The peak nodal von
Mises stress on the fillet over a four-level study (sizes 16, 11.3, 8, 5.66 mm with 90°, 64°,
45°, 32°): 213.3, 210.6, 214.3, 213.3 MPa. The coarse and the fine level are the two cases.
@@ -0,0 +1,89 @@
{
"commands": [
{
"command": "sketch.create",
"params": {
"plane": "XY",
"name": "Profile"
}
},
{
"command": "sketch.line",
"params": {
"points": [
[
0,
0
],
[
60,
0
],
[
60,
8
],
[
8,
8
],
[
8,
50
],
[
0,
50
]
],
"closed": true
}
},
{
"command": "sketch.finish",
"params": {}
},
{
"command": "solid.extrude",
"params": {
"distance": 40,
"body_name": "Bracket"
}
},
{
"command": "solid.fillet",
"params": {
"edges": [
[
8,
8,
20
]
],
"radius": 6
}
},
{
"command": "solid.hole",
"params": {
"position": [
40,
8,
20
],
"diameter": 8
}
},
{
"command": "solid.hole",
"params": {
"position": [
8,
32,
20
],
"diameter": 8
}
}
]
}
@@ -0,0 +1,38 @@
{
"title": "Filleted L-bracket under a side load: the peak von Mises stress on the R6 fillet, fine tet10 mesh",
"kind": "theory",
"source": "mesh convergence of the finite element solution (P. J. Roache, Verification and Validation in Computational Science and Engineering, Hermosa, 1998, ch. 5): the bracket has no closed-form stress; the reference is the mesh-independent peak of a four-level study of quadratic tetrahedral meshes refined by √2 in size and in curvature resolution (README.md); equilibrium",
"slow": true,
"quantities": [
{
"id": "fillet_peak",
"quantity": "largest nodal von Mises stress on the fillet face (MPa)",
"measure": {
"command": "solve.probe",
"params": {
"step": "Load",
"set": "fillet"
},
"pointer": "/max_von_mises/value"
},
"value": 213.0,
"tolerance": {
"relative": 0.03
},
"reason": "the four-level study gives 213.3, 210.6, 214.3, 213.3 MPa (2k to 13.5k elements): the bending stress is converged across the fillet, and the peak nodal value moves only with which of the fillet's tessellation lines (fixed angles, through every level) carries the largest node, by under 2%"
},
{
"id": "reaction",
"quantity": "total reaction x (N)",
"measure": {
"from": "solve",
"pointer": "/reaction_total/0"
},
"value": -2000.0,
"tolerance": {
"relative": 1e-09
},
"reason": "equilibrium holds to rounding"
}
]
}
@@ -0,0 +1,13 @@
{
"note": "FieldCraft's accepted results for this case, written by `cargo xtask oracle --bless`. A result outside its band fails CI.",
"values": {
"fillet_peak": {
"band": 2.1330693756948646e-7,
"value": 213.30693756948645
},
"reaction": {
"band": 2.0000000000001007e-6,
"value": -2000.0000000001007
}
}
}
@@ -0,0 +1,13 @@
[
{"command": "mesh.tet.generate", "params": {"body": "Bracket", "tolerance": 0.088, "size": 5.65685424949238, "curvature_angle": 31.819805153394636, "order": "quadratic"}, "id": "tet"},
{"command": "model.material.create", "params": {"name": "Steel", "elastic": {"type": "isotropic", "young": 210000, "poisson": 0.3}, "density": 7.85e-09}},
{"command": "model.set.create", "params": {"name": "all", "geometry": [{"body": "Bracket"}]}},
{"command": "model.set.create", "params": {"name": "foot", "geometry": [{"body": "Bracket", "face": "F2:side:l1"}]}},
{"command": "model.set.create", "params": {"name": "top", "geometry": [{"body": "Bracket", "face": "F2:side:l5"}]}},
{"command": "model.set.create", "params": {"name": "fillet", "geometry": [{"body": "Bracket", "face": "F3:blend:F2:side:l3|F2:side:l4"}]}},
{"command": "model.section.create", "params": {"name": "solid", "set": "all", "material": "Steel", "kind": {"type": "solid"}}},
{"command": "model.boundary_condition.create", "params": {"name": "clamp", "type": "fixed", "target": {"set": "foot"}}},
{"command": "model.load.create", "params": {"name": "push", "type": "force", "target": {"set": "top"}, "vector": [2000, 0, 0]}},
{"command": "model.step.create", "params": {"name": "Load", "procedure": {"type": "static"}, "boundary_conditions": ["clamp"], "loads": ["push"]}},
{"command": "solve.static", "params": {}, "id": "solve"}
]