forked from 1b-agent/fieldcraft-upstream
engine, render: hidden bodies hide their mesh and results; solve totals without round-off
- DisplayMesh::from_model_hiding leaves out a hidden body's elements (and the nodes only they use); Session::hidden_elements names them, so the viewport, probing and headless pictures skip hidden bodies (#365). - A solve summary's applied and reaction totals set the round-off of cancelling sums to 0 (#319). - results::principal for the probe's principal stresses (#329). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
0966dfa2a6
commit
91e8467e4f
5 files changed
+61
-9
No files matched your search
@@ -207,6 +207,19 @@ fn run_all(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
Ok(json!({"steps": done}))
|
||||
}
|
||||
|
||||
/// A sum of nodal values with its round-off set to 0: a component below a billionth of the sum
|
||||
/// of the terms' magnitudes is what cancelling left (a balanced load sums to ~1e-11, not 0).
|
||||
fn settled(total: [f64; 3], terms: &[[f64; 3]]) -> [f64; 3] {
|
||||
let mut out = total;
|
||||
for (k, c) in out.iter_mut().enumerate() {
|
||||
let scale: f64 = terms.iter().filter_map(|t| t.get(k)).map(|x| x.abs()).filter(|x| x.is_finite()).sum();
|
||||
if c.abs() <= 1e-9 * scale {
|
||||
*c = 0.0;
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn largest(values: impl Iterator<Item = (u32, f64)>) -> Value {
|
||||
extreme(values, |v, b| v > b)
|
||||
}
|
||||
@@ -228,8 +241,8 @@ fn run_static(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
"factor_entries": r.stats.factor_entries,
|
||||
"max_displacement": largest(r.nodes.iter().zip(&r.displacement).map(|(l, u)| (*l, crate::results::magnitude(*u)))),
|
||||
"max_von_mises": largest(r.nodes.iter().zip(&r.von_mises).map(|(l, v)| (*l, *v))),
|
||||
"applied_total": r.applied_total,
|
||||
"reaction_total": r.reaction_total,
|
||||
"applied_total": settled(r.applied_total, &r.reaction),
|
||||
"reaction_total": settled(r.reaction_total, &r.reaction),
|
||||
"reference_points": r.reference_points.iter().map(|p| json!({
|
||||
"name": p.name,
|
||||
"label": p.label,
|
||||
@@ -272,8 +285,8 @@ fn run_nonlinear(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
"max_displacement": largest(r.nodes.iter().zip(&r.displacement).map(|(l, u)| (*l, crate::results::magnitude(*u)))),
|
||||
"max_von_mises": largest(r.nodes.iter().zip(&r.von_mises).map(|(l, v)| (*l, *v))),
|
||||
"max_plastic_strain": largest(r.elements.iter().flat_map(|e| e.plastic_strain.iter().map(|v| (e.label, *v)))),
|
||||
"applied_total": r.applied_total,
|
||||
"reaction_total": r.reaction_total,
|
||||
"applied_total": settled(r.applied_total, &r.reaction),
|
||||
"reaction_total": settled(r.reaction_total, &r.reaction),
|
||||
"reference_points": r.reference_points.iter().map(|p| json!({
|
||||
"name": p.name,
|
||||
"label": p.label,
|
||||
|
||||
@@ -141,6 +141,11 @@ impl Session {
|
||||
})
|
||||
}
|
||||
|
||||
/// The elements of the bodies the view hides: hiding a body hides its mesh and its results.
|
||||
pub fn hidden_elements(&self) -> std::collections::BTreeSet<u32> {
|
||||
self.view.hidden.iter().filter(|i| i.kind == ItemKind::Body).flat_map(|i| self.model.body_elements(&i.name)).collect()
|
||||
}
|
||||
|
||||
/// Whether the view shows item `name` of `kind`.
|
||||
pub fn shows(&self, kind: ItemKind, name: &str) -> bool {
|
||||
!self.view.is_hidden(kind, name)
|
||||
|
||||
@@ -621,6 +621,11 @@ pub(crate) fn inputs_fingerprint(model: &Model, step: &str) -> Option<u64> {
|
||||
Some(h.0.finish())
|
||||
}
|
||||
|
||||
/// The principal values of a stress (xx, yy, zz, xy, xz, yz), largest first.
|
||||
pub fn principal(t: &[f64; 6]) -> [f64; 3] {
|
||||
fieldcraft_fem::principal(t)
|
||||
}
|
||||
|
||||
pub fn magnitude(v: [f64; 3]) -> f64 {
|
||||
(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt()
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ pub struct Shown {
|
||||
|
||||
/// The model's display data with the open design's bodies and the imported surfaces.
|
||||
pub fn display(s: &Session) -> (DisplayMesh, Vec<String>) {
|
||||
let mut d = DisplayMesh::from_model(&s.model);
|
||||
let mut d = DisplayMesh::from_model_hiding(&s.model, &s.hidden_elements());
|
||||
let mut failed = Vec::new();
|
||||
for body in s.design.iter().flat_map(|d| &d.bodies).filter(|b| s.shows(fieldcraft_io::ItemKind::Body, &b.name)) {
|
||||
let mesh = body.measure().and_then(|m| body.tessellate(display_tolerance(&Aabb3 { min: m.bbox_min.into(), max: m.bbox_max.into() })));
|
||||
|
||||
Reference in new issue
Block a user