mesh: platform-independent maths (libm) so meshes are bit-identical on macOS and Linux

The system maths library's sin, cos, atan2, log … are not correctly rounded and differ
between platforms: mesh.hex.generate gave the plate of the strong-relax test a different
mesh on Linux than on macOS (nodes from 2809 on), so the test passed on a Mac and failed
in CI. Every transcendental call in fieldcraft-mesh now goes through the libm crate (a
pure-Rust port of musl's), which gives the same bits everywhere.

Part of #438.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-16 18:30:00 -04:00
1 parent f297ffca3a
commit 700a7e3d10
15 files changed
+41 -30

No files matched your search

+3 -3
View File
@@ -551,7 +551,7 @@ pub fn project_mesh(t: &Topology, surface: &BoundarySurface, g: &dyn Geometry, o
*m = m.max(measured);
}
if let Some(l) = class_log.get_mut(cls[d]).filter(|_| len > tol) {
l.0 += measured.ln();
l.0 += libm::log(measured);
l.1 += 1;
}
}
@@ -598,7 +598,7 @@ pub fn project_mesh(t: &Topology, surface: &BoundarySurface, g: &dyn Geometry, o
let Some(nx) = g.normal(fa, qx) else { continue };
let h = dist(pa, qx);
if h > 0.5 * probe {
kappa = kappa.max(crate::vec3::dot(na, nx).clamp(-1.0, 1.0).acos() / h);
kappa = kappa.max(libm::acos(crate::vec3::dot(na, nx).clamp(-1.0, 1.0)) / h);
}
}
}
@@ -616,7 +616,7 @@ pub fn project_mesh(t: &Topology, surface: &BoundarySurface, g: &dyn Geometry, o
.zip(&class_max)
.zip(&class_arc)
.map(|((&(sum, k), &longest), &arc)| {
let mean = if k == 0 { 1.0 } else { (sum / k as f64).exp().round() };
let mean = if k == 0 { 1.0 } else { libm::exp(sum / k as f64).round() };
(mean.max((longest / MAX_STRETCH).ceil()) as usize).max(arc).clamp(1, crate::block::MAX_DIVISIONS)
})
.collect();