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

+8 -1
View File
@@ -12,7 +12,7 @@ use serde::Serialize;
use fieldcraft_parallel as parallel;
use crate::cholesky::{Factor, FactorError, UpperColumns};
use crate::constraints::{Budget, Reduction, coupling_rows};
use crate::constraints::{Budget, Reduction, coupling_rows, symmetry_rows};
use crate::eigen::{Operator, Wanted, lanczos};
use crate::ldlt::{Kind, Symmetric};
use crate::ordering::nested_dissection;
@@ -342,6 +342,13 @@ pub(crate) struct Setup<'a> {
pub(crate) fn reduction(s: &Setup, values: bool, order: &[usize], budget: Budget, warnings: &mut Vec<String>) -> Result<Reduction> {
let mut rows = coupling_rows(s.model, s.resolved, s.mesh)?;
rows.extend(crate::tie::rows(s.model, s.resolved, s.mesh, warnings)?);
// Reference point directions exist when a coupling, tie or discrete element uses them.
let used: std::collections::BTreeSet<usize> = rows.iter().flat_map(|r| r.terms.iter().map(|t| t.0)).chain(s.mesh.discrete.dofs()).collect();
let node_dofs = s.mesh.layout.node_dofs();
// Boundary conditions first, as the elimination takes them.
let mut symmetry = symmetry_rows(s.model, s.resolved, s.mesh, s.step, |d| d < node_dofs || used.contains(&d))?;
symmetry.append(&mut rows);
let rows = symmetry;
Reduction::new(
&s.mesh.layout,
s.mesh.discrete.dofs(),