solver, decks: symmetry about an inclined plane (#242)

The symmetry condition takes any plane normal ({"normal": [nx, ny, nz]}).
An inclined one holds n·u = 0 and, at shell, beam and reference point
nodes, the rotations about the two in-plane axes: constraint rows the
implicit elimination already handles, its support forces reported as
reactions. Decks: Abaqus *EQUATION, Nastran MPC sets per subcase, LS-DYNA
*BOUNDARY_SPC in a *DEFINE_COORDINATE_SYSTEM along the normal.

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 10:38:20 -04:00
1 parent a079e51f9d
commit ac1037e1af
11 files changed
+1009 -53

No files matched your search

+1 -14
View File
@@ -354,19 +354,6 @@ fn scan<T>(items: &[T]) -> impl Iterator<Item = &T> {
items.iter().step_by(items.len().div_ceil(MAX_SCAN).max(1))
}
/// The nodes that can rotate: shell and beam nodes (not those of 2D sections: plane stress,
/// plane strain, axisymmetric), as the model check counts them.
fn rotating_nodes(model: &Model) -> BTreeSet<u32> {
let planar: BTreeSet<u32> = model
.sections()
.values()
.filter(|s| s.kind.extent().is_some())
.filter_map(|s| model.resolve_set_partial(&s.set))
.flat_map(|r| r.elements)
.collect();
model.rotational_nodes(|l| planar.contains(&l))
}
/// The corner node labels of an element face, in the face's order.
fn face_corners(model: &Model, f: ElementFace) -> Option<Vec<u32>> {
let kind = model.element(f.element)?.kind;
@@ -589,7 +576,7 @@ impl Builder<'_> {
}
let (spots, total) = self.spots(bc.target());
if dofs & 0b111_000 != 0 && self.rotating.is_none() {
self.rotating = Some(rotating_nodes(self.model));
self.rotating = Some(self.model.rotating_nodes());
}
let none = BTreeSet::new();
let rotating = self.rotating.as_ref().unwrap_or(&none);