forked from 1b-agent/fieldcraft-upstream
Element quality metrics and the certified validity gate (mesh.quality) (#12)
* mesh: element quality metrics and a certified Jacobian validity check Bernstein-form Jacobian determinants for tet4/tet10/wedge6/hex8/hex20, certified by bounds and subdivision (Johnen-Remacle-Geuzaine 2013); Shewchuk 2002 tet metrics, Knupp 2001 hex/wedge/quad metrics; quality report and the validity gate meshers run on their output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * engine: mesh.quality command; model documents its node order mesh.quality reports certified validity, volume and per-metric statistics with fixed-range histograms. The model's ElementKind doc states the Abaqus/VTK node order and that deck code reorders formats like Nastran CHEXA20. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * quality: simplify after review; exact orient3d for tet4; gate on raw mesher arrays - tet4 validity from the exact orient3d of the input coordinates - validity_gate_elements takes (label, kind, coordinates) straight from a mesher - one Jacobian per solid; certify caches piece bounds; product weights precomputed - model::check_coordinates shared by set_node and quality; ElementKind is Ord - engine: shared labels() parameter parser Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm --------- Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
15 files changed
+1981
-17
No files matched your search
@@ -4,6 +4,7 @@ mod geometry;
|
||||
mod mesh;
|
||||
mod model;
|
||||
|
||||
use modelcraft_model::MAX_LABEL;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{CommandSpec, EngineError, Result};
|
||||
@@ -18,6 +19,7 @@ pub static ALL: &[CommandSpec] = &[
|
||||
mesh::NODE_REMOVE,
|
||||
mesh::ELEMENT_ADD,
|
||||
mesh::ELEMENT_REMOVE,
|
||||
mesh::QUALITY,
|
||||
];
|
||||
|
||||
/// A required label parameter (1..=u32::MAX; the model checks its own range).
|
||||
@@ -38,3 +40,16 @@ pub(crate) fn xyz(p: &Value, key: &str) -> Result<[f64; 3]> {
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// A required list of labels (each in 1..=MAX_LABEL), at most `max_len` long.
|
||||
pub(crate) fn labels(p: &Value, key: &str, max_len: usize) -> Result<Vec<u32>> {
|
||||
let raw = p
|
||||
.get(key)
|
||||
.and_then(Value::as_array)
|
||||
.filter(|a| a.len() <= max_len)
|
||||
.ok_or_else(|| EngineError::Params(format!("`{key}` must be a list of at most {max_len} labels")))?;
|
||||
raw.iter()
|
||||
.map(|v| v.as_u64().and_then(|n| u32::try_from(n).ok()).filter(|n| (1..=MAX_LABEL).contains(n)))
|
||||
.collect::<Option<Vec<u32>>>()
|
||||
.ok_or_else(|| EngineError::Params(format!("`{key}` must be labels in 1..={MAX_LABEL}")))
|
||||
}
|
||||
Reference in new issue
Block a user