Files
jyvikoandClaude Opus 5.5 7d419b73f4 mesh: the tet report carries the scaled Jacobian; both metrics tested on the same tets (#547)
The dihedral range and mesh.quality's scaled Jacobian were both right:
they are computed by the same function on the same final corners (tet4
and tet10 give identical numbers), but a dihedral range does not bound
the corner scaled Jacobian. A needle has dihedral angles near 60 and 90
degrees and a nearly flat apex corner. Before 417c0c88 sphere-on-plate
at size 4 had dihedrals 36.3-141.6 and 106 needles below SJ 0.2 (min
0.095); now 36.0-137.6 and min SJ 0.351.

The mesher's report now carries min_scaled_jacobian so it cannot read
as all-good while needles remain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-17 08:12:09 -04:00

34 lines
1.8 KiB
Rust

//! Sphere-on-plate at size 4 (#547): the tet mesher's report and `mesh.quality` measure the same
//! final elements, tet4 and tet10 alike, and no needle is left below the skill's scaled Jacobian
//! limit although every dihedral angle is fine.
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
use fieldcraft_engine::Session;
use fieldcraft_testkit::corpus;
use serde_json::json;
#[test]
fn sphere_on_plate_report_and_quality_agree() {
let parts = corpus::parts().unwrap();
let p = parts.iter().find(|p| p.name == "sphere-on-plate").unwrap();
let dir = std::env::temp_dir().join(format!("fieldcraft-tet-metric-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("part.solidcraft");
std::fs::write(&path, corpus::design_bytes(p).unwrap()).unwrap();
for order in ["linear", "quadratic"] {
let mut s = Session::default();
s.execute("geometry.open", &json!({"path": path})).unwrap();
let r = s.execute("mesh.tet.generate", &json!({"body": "Plate", "size": 4.0, "order": order})).unwrap();
let mesh = &r["bodies"][0]["quality"]["mesh"];
let q = s.execute("mesh.quality", &json!({})).unwrap();
let m = &q["metrics"];
let f = |v: &serde_json::Value| v.as_f64().unwrap();
assert_eq!(f(&mesh["min_dihedral"]), f(&m["min_dihedral"]["min"]), "{order}");
assert_eq!(f(&mesh["max_dihedral"]), f(&m["max_dihedral"]["max"]), "{order}");
assert_eq!(f(&mesh["min_scaled_jacobian"]), f(&m["scaled_jacobian"]["min"]), "{order}");
assert!(f(&mesh["min_dihedral"]) > 30.0 && f(&mesh["max_dihedral"]) < 145.0, "{order}: {mesh}");
assert!(f(&mesh["min_scaled_jacobian"]) >= 0.3, "{order}: {mesh}");
}
let _ = std::fs::remove_dir_all(&dir);
}