forked from 1b-agent/fieldcraft-upstream
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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
This commit is contained in:
1 parent
fed27d816d
commit
9469ac0853
53 files changed
+5880
-278
No files matched your search
@@ -30,7 +30,7 @@
|
||||
|
||||
use fieldcraft_model::Elastic;
|
||||
|
||||
use crate::dense::inverse3;
|
||||
use crate::dense::positive_inverse;
|
||||
use crate::material::Elasticity;
|
||||
use crate::quadrature::Rule;
|
||||
use crate::shape::{self, HEX_CORNERS};
|
||||
@@ -72,11 +72,7 @@ impl UniformStrain<8> {
|
||||
}
|
||||
}
|
||||
}
|
||||
let (inv, det) = inverse3(&j).ok_or_else(|| degenerate("hex8"))?;
|
||||
let norms: f64 = j.iter().map(|r| (r[0] * r[0] + r[1] * r[1] + r[2] * r[2]).sqrt()).product();
|
||||
if !(det > 1e-12 * norms) {
|
||||
return Err(degenerate("hex8"));
|
||||
}
|
||||
let (inv, det) = positive_inverse(&j).ok_or_else(|| degenerate("hex8"))?;
|
||||
let w = det * p.weight;
|
||||
volume += w;
|
||||
for (((bi, vi), d), n) in b.iter_mut().zip(nodal_volume.iter_mut()).zip(s.derivatives()).zip(s.values()) {
|
||||
@@ -172,15 +168,9 @@ impl UniformStrain<4> {
|
||||
/// The linear tetrahedron of corners `xyz` (the model's tet4 node order).
|
||||
pub fn tet4(xyz: &[[f64; 3]; 4]) -> Result<Tet4> {
|
||||
fieldcraft_model::check_coordinates(xyz.as_flattened()).map_err(|e| Error::Invalid(e.to_string()))?;
|
||||
let [x0, x1, x2, x3] = *xyz;
|
||||
let e = |x: [f64; 3]| [x[0] - x0[0], x[1] - x0[1], x[2] - x0[2]];
|
||||
// J[a][c] = ∂x_c/∂ξ_a: the edges from corner 1.
|
||||
let j = [e(x1), e(x2), e(x3)];
|
||||
let (inv, det) = inverse3(&j).ok_or_else(|| degenerate("tet4"))?;
|
||||
let norms: f64 = j.iter().map(|r| (r[0] * r[0] + r[1] * r[1] + r[2] * r[2]).sqrt()).product();
|
||||
if !(det > 1e-12 * norms) {
|
||||
return Err(degenerate("tet4"));
|
||||
}
|
||||
let j = fieldcraft_model::tet4_jacobian(xyz);
|
||||
let (inv, det) = positive_inverse(&j).ok_or_else(|| degenerate("tet4"))?;
|
||||
let volume = det / 6.0;
|
||||
let s = shape::tet4([0.25; 3]);
|
||||
let mut b = [[0.0; 3]; 4];
|
||||
|
||||
Reference in new issue
Block a user