forked from 1b-agent/fieldcraft-upstream
Implicit solver: reference points, couplings, moments, wedge6 (M4) (#26)
* fem: wedge6 element (triangle × interval, 3 × 2 points), patch and cantilever tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * solver: reference points, kinematic and distributing couplings, moments by constraint elimination Coupled reference points get six degrees of freedom; kinematic couplings are rigid links, distributing couplings least-squares interpolation constraints. Every constraint row and prescribed value is eliminated master-slave (Abel-Shephard pivot choice), so the reduced matrix stays SPD; no coupling gives the old elimination bit for bit. Verified: rigid motion of a coupled block, clamping through a point, distributing tension vs pressure, bending and tube torsion. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * engine: reference point results in solve.static and solve.probe Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * docs: couplings, moments and wedge6 in the solver docs, literature and roadmap Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * solver: simplify constraint elimination and reference point plumbing Rows combine by one sort; T_f transposed once; K and M reduced in one pass on a shared pattern; prescribed motion computed once; reference point loads and BCs go through Resolved like node ones (Mesh::label_dofs); one dof-direction rule; StepResult::locate for probes; dead Csr::restrict removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * solver: refuse oversized reductions before allocating them A held distributing coupling point makes a dense (3N)^2 block; estimate it from the constraint rows and refuse it against the factorization's memory budget with a clear message, before anything is built. Other reductions with dependents count their entries first (stopping at the budget) and reserve fallibly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm --------- Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
18 files changed
+1502
-199
No files matched your search
@@ -7,7 +7,8 @@
|
||||
//!
|
||||
//! Formulations:
|
||||
//! - **full integration**: the rule that integrates the stiffness of an undistorted element
|
||||
//! exactly (1 point for tet4, 4 for tet10, 2 × 2 × 2 for hex8, 3 × 3 × 3 for hex20);
|
||||
//! exactly (1 point for tet4, 4 for tet10, 3 triangle points × 2 for wedge6, 2 × 2 × 2 for
|
||||
//! hex8, 3 × 3 × 3 for hex20);
|
||||
//! - **reduced integration** for hex20 (2 × 2 × 2), which avoids locking at the cost of one
|
||||
//! spurious mode that a mesh of more than one element restrains. Reduced hex8 needs hourglass
|
||||
//! control and is not offered here yet (it arrives with the explicit solver, Flanagan &
|
||||
@@ -43,6 +44,7 @@ use crate::{Error, Result};
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Family {
|
||||
Tetrahedron,
|
||||
Wedge,
|
||||
Hexahedron,
|
||||
}
|
||||
|
||||
@@ -67,7 +69,7 @@ pub struct ElementType {
|
||||
}
|
||||
|
||||
/// The element table.
|
||||
pub static ELEMENT_TYPES: [ElementType; 4] = [
|
||||
pub static ELEMENT_TYPES: [ElementType; 5] = [
|
||||
ElementType {
|
||||
kind: ElementKind::Tet4,
|
||||
family: Family::Tetrahedron,
|
||||
@@ -90,6 +92,17 @@ pub static ELEMENT_TYPES: [ElementType; 4] = [
|
||||
mass: Rule::TetConical(4),
|
||||
incompatible_modes: false,
|
||||
},
|
||||
ElementType {
|
||||
kind: ElementKind::Wedge6,
|
||||
family: Family::Wedge,
|
||||
nodes: 6,
|
||||
corners: 6,
|
||||
shape: shape::wedge6,
|
||||
full: Rule::Wedge,
|
||||
reduced: None,
|
||||
mass: Rule::Wedge,
|
||||
incompatible_modes: false,
|
||||
},
|
||||
ElementType {
|
||||
kind: ElementKind::Hex8,
|
||||
family: Family::Hexahedron,
|
||||
@@ -119,7 +132,7 @@ pub fn element_type(kind: ElementKind) -> Result<&'static ElementType> {
|
||||
ELEMENT_TYPES
|
||||
.iter()
|
||||
.find(|t| t.kind == kind)
|
||||
.ok_or_else(|| Error::NotSupported(format!("{} elements (the solver has tet4, tet10, hex8 and hex20 so far)", kind.name())))
|
||||
.ok_or_else(|| Error::NotSupported(format!("{} elements (the solver has tet4, tet10, wedge6, hex8 and hex20 so far)", kind.name())))
|
||||
}
|
||||
|
||||
/// How a solid element is formulated.
|
||||
@@ -565,6 +578,7 @@ pub fn extrapolation(ty: &ElementType, rule: Rule) -> Result<Extrapolation> {
|
||||
let c = ty.corners;
|
||||
let corner_basis = |xi: [f64; 3]| match ty.family {
|
||||
Family::Tetrahedron => shape::tet4(xi),
|
||||
Family::Wedge => shape::wedge6(xi),
|
||||
Family::Hexahedron => shape::hex8(xi),
|
||||
};
|
||||
let mut corner_rows = vec![0.0; c * g];
|
||||
|
||||
Reference in new issue
Block a user