forked from 1b-agent/fieldcraft-upstream
model: resolve_set_partial, and the rotating-node rule as Model::rotational_nodes
resolve_set_partial resolves the members of a set that are on the mesh, for display: a set with a missing member still shows what it has, where resolve_set refuses it. rotational_nodes is the check's rule for which nodes have rotations (shell and beam nodes, not those of 2D sections), so the viewport's symbols and the check agree. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
This commit is contained in:
1 parent
73f35bd7f7
commit
95c02bc728
3 files changed
+29
-7
No files matched your search
@@ -165,6 +165,17 @@ impl Model {
|
||||
Ok(resolved)
|
||||
}
|
||||
|
||||
/// The mesh nodes with rotational degrees of freedom: those of shells (2D elements that are
|
||||
/// not `planar`: plane stress, plane strain or axisymmetric) and of beams. Reference points
|
||||
/// rotate too.
|
||||
pub fn rotational_nodes(&self, planar: impl Fn(u32) -> bool) -> BTreeSet<u32> {
|
||||
self.elements
|
||||
.iter()
|
||||
.filter(|(l, e)| (e.kind.dimension() == 2 && !planar(**l)) || e.kind == ElementKind::Beam2)
|
||||
.flat_map(|(_, e)| e.nodes.iter().copied())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn analyze(&self) -> (Resolved, Vec<Diagnostic>) {
|
||||
let mut d = Diagnostics::default();
|
||||
let mut resolved = Resolved::default();
|
||||
@@ -381,13 +392,7 @@ impl Model {
|
||||
let has_rotations = |t: &Target| match t {
|
||||
Target::ReferencePoint(_) => true,
|
||||
Target::Set(s) => {
|
||||
let rotational: &BTreeSet<u32> = rotational.get_or_init(|| {
|
||||
self.elements
|
||||
.iter()
|
||||
.filter(|(l, e)| (e.kind.dimension() == 2 && !resolved.planar.contains_key(l)) || e.kind == ElementKind::Beam2)
|
||||
.flat_map(|(_, e)| e.nodes.iter().copied())
|
||||
.collect()
|
||||
});
|
||||
let rotational = rotational.get_or_init(|| self.rotational_nodes(|l| resolved.planar.contains_key(&l)));
|
||||
set_of(s).nodes.iter().any(|n| rotational.contains(n))
|
||||
}
|
||||
};
|
||||
|
||||
@@ -138,6 +138,13 @@ impl Model {
|
||||
if missing.is_empty() { Ok(resolved) } else { Err(Error::NotFound(format!("set `{name}`: {}", missing.join("; ")))) }
|
||||
}
|
||||
|
||||
/// Resolve one set against the current mesh, leaving out the members that are not on it
|
||||
/// (for display: a set with a missing member still shows what it has). `None` when there is
|
||||
/// no set called `name`.
|
||||
pub fn resolve_set_partial(&self, name: &str) -> Option<ResolvedSet> {
|
||||
self.sets.get(name).map(|set| self.resolve_definition(set).0)
|
||||
}
|
||||
|
||||
/// Resolve a definition, and list the members that are not on the mesh.
|
||||
pub(crate) fn resolve_definition(&self, set: &Set) -> (ResolvedSet, Vec<String>) {
|
||||
let c = &self.classification;
|
||||
|
||||
@@ -516,3 +516,13 @@ fn two_dimensional_models_resolve_edges_and_check_their_rules() {
|
||||
assert!(m.add_load("hostile", bad.clone()).is_err(), "{bad:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_resolves_what_is_on_the_mesh() {
|
||||
let mut m = defined();
|
||||
// A set with a node the mesh does not have: the check refuses it, the display shows the rest.
|
||||
m.add_set("half", Set { nodes: vec![1, 999], ..Set::default() }).unwrap();
|
||||
assert!(m.resolve_set("half").is_err());
|
||||
assert_eq!(m.resolve_set_partial("half").map(|r| r.nodes), Some(vec![1]));
|
||||
assert_eq!(m.resolve_set_partial("nope"), None);
|
||||
}
|
||||
Reference in new issue
Block a user