forked from 1b-agent/fieldcraft-upstream
engine: a mesh made before its seeds changed is out of date; a remesh names a type change
The setup checklist marks the mesh Outdated (a warm ⚠ in the browser, with what changed and where to remesh) when seeds, partitions or datum planes changed after the last mesher ran, and model.check warns (#342). Replacing a mesh asks with the element type change it makes, such as tet10 → tet4 (#343). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
464a4d50c1
commit
3eaca26246
4 files changed
+107
-6
No files matched your search
@@ -55,7 +55,10 @@ fn units(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
}
|
||||
|
||||
fn check(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
let diagnostics = s.model.check();
|
||||
let mut diagnostics = s.model.check();
|
||||
if let Some(why) = s.mesh_outdated() {
|
||||
diagnostics.push(fieldcraft_model::Diagnostic { severity: Severity::Warning, subject: "mesh".into(), message: why });
|
||||
}
|
||||
let errors = diagnostics.iter().filter(|d| d.severity == Severity::Error).count();
|
||||
let first_error = diagnostics.iter().find(|d| d.severity == Severity::Error).map(ToString::to_string);
|
||||
let progress = crate::progress::to_json(&s.progress_given(first_error));
|
||||
|
||||
@@ -102,6 +102,28 @@ fn design_bodies(s: &Session) -> Result<Vec<String>> {
|
||||
Ok(design.bodies.iter().map(|b| b.name.clone()).collect())
|
||||
}
|
||||
|
||||
/// Tetrahedra and hexahedra of either order: the kinds an order change swaps.
|
||||
fn family(k: ElementKind) -> Option<u8> {
|
||||
match k {
|
||||
ElementKind::Tet4 | ElementKind::Tet10 => Some(0),
|
||||
ElementKind::Hex8 | ElementKind::Hex20 => Some(1),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// The solid element type `command` makes with `params`, when it makes one type.
|
||||
fn made_kind(command: &str, params: &Value) -> Option<ElementKind> {
|
||||
match command {
|
||||
"mesh.tet.generate" => {
|
||||
Some(if params.get("order").and_then(Value::as_str) == Some("quadratic") { ElementKind::Tet10 } else { ElementKind::Tet4 })
|
||||
}
|
||||
"mesh.hex.generate" | "mesh.hex.sweep" | "mesh.hex.mapped" | "mesh.hex.blocks" => {
|
||||
Some(if params.get("order").and_then(Value::as_i64) == Some(2) { ElementKind::Hex20 } else { ElementKind::Hex8 })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// What running a meshing command would replace, for a confirmation before it runs.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Replacement {
|
||||
@@ -141,6 +163,14 @@ pub fn replacement(s: &Session, command: &str, params: &Value) -> Option<Replace
|
||||
}
|
||||
};
|
||||
let mut warnings = Vec::new();
|
||||
// The element type changing (tet10 → tet4 when the order is left out) is easy to miss.
|
||||
if let Some(new) = made_kind(command, params) {
|
||||
let old: BTreeSet<ElementKind> = removed.elements.iter().filter_map(|l| s.model.element(*l)).map(|e| e.kind).collect();
|
||||
let changed: Vec<&str> = old.iter().filter(|k| **k != new && family(**k) == family(new)).map(|k| k.name()).collect();
|
||||
if !changed.is_empty() {
|
||||
warnings.push(format!("The element type changes: {} → {}.", changed.join(", "), new.name()));
|
||||
}
|
||||
}
|
||||
let stale = s.model.sets_using(&removed);
|
||||
if !stale.is_empty() {
|
||||
warnings.push(format!("Sets that list its nodes or elements by label ({}) will name labels of the old mesh.", stale.join(", ")));
|
||||
@@ -194,6 +224,17 @@ mod tests {
|
||||
(dir, s)
|
||||
}
|
||||
|
||||
/// Remeshing without the order would turn tet10 into tet4: the question says so (#343).
|
||||
#[test]
|
||||
fn an_element_type_change_is_named() {
|
||||
let (_dir, mut s) = two_boxes();
|
||||
s.execute("mesh.tet.generate", &json!({"body": "Box", "size": 5, "order": "quadratic"})).unwrap();
|
||||
let r = replacement(&s, "mesh.tet.generate", &json!({"body": "Box", "size": 4})).unwrap();
|
||||
assert!(r.warnings.iter().any(|w| w == "The element type changes: tet10 → tet4."), "{r:?}");
|
||||
let same = replacement(&s, "mesh.tet.generate", &json!({"body": "Box", "order": "quadratic"})).unwrap();
|
||||
assert!(same.warnings.iter().all(|w| !w.contains("element type")), "{same:?}");
|
||||
}
|
||||
|
||||
/// A body's elements, by label.
|
||||
fn elements_of(s: &Session, body: &str) -> BTreeMap<u32, Element> {
|
||||
s.model.body_elements(body).into_iter().filter_map(|l| Some((l, s.model.element(l)?.clone()))).collect()
|
||||
|
||||
Reference in new issue
Block a user