forked from 1b-agent/fieldcraft-upstream
1D elements I: trusses (rod2, rod3), point masses, rotary inertia, springs and dashpots (#38)
* Model, fem and decks: point masses, rotary inertia, springs, dashpots and rod3 trusses Model: PointMass and Spring definitions (spring | dashpot; to ground or two-point; along a degree of freedom, a vector or the line of the ends) on a set or reference point, resolved per node; ElementKind::Rod3. fem: rod2/rod3 truss kernel on Basis::Line2/Line3 declaring ElementDofs (translations). Decks: Abaqus T3D3, MASS, ROTARYI, SPRING1/2/A, DASHPOT1/2/A; Nastran CONM1, CELAS2, CDAMP2; LS-DYNA ELEMENT_MASS/INERTIA and ELEMENT_DISCRETE; what a format cannot take is reported. Commands model.mass.* and model.spring.*. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * Implicit solver: trusses, point masses, rotary inertia and springs on the DofLayout Trusses declare their translations like solids; point masses, inertia and springs ask the layout for the kinds they need at their nodes (translations, rotations), and reference points they use get six degrees of freedom. The matrix pattern takes rows for those points; dashpots are ignored with a warning. Existing results are bit-identical (hash-checked). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * Explicit solver: trusses, point masses, springs and dashpots on the node-major layout Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * docs: fem.md on trusses and discrete elements in the layout; regenerate features.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * docs: trusses in plane models and corotational explicit trusses 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:
53 files changed
+3626
-110
No files matched your search
@@ -14,6 +14,7 @@ pub struct Node {
|
||||
|
||||
/// Element topology. Node order is corners first, then mid-side nodes, with positive volume for
|
||||
/// a right-handed ordering:
|
||||
/// - rod3: the two ends, then the middle node;
|
||||
/// - tet10: mid-side nodes 5–10 on edges 1-2, 2-3, 3-1, 1-4, 2-4, 3-4;
|
||||
/// - wedge6: triangle 1-2-3, then 4-5-6 on the side its right-hand normal points to;
|
||||
/// - hex8/hex20: face 1-2-3-4, then 5-6-7-8 above it; hex20's mid-side nodes 9–12 lie on the
|
||||
@@ -25,8 +26,10 @@ pub struct Node {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ElementKind {
|
||||
/// Two-node axial member.
|
||||
/// Two-node axial member (truss).
|
||||
Rod2,
|
||||
/// Three-node axial member (quadratic truss, straight or curved).
|
||||
Rod3,
|
||||
/// Two-node beam.
|
||||
Beam2,
|
||||
/// Three-node triangle (shell or membrane).
|
||||
@@ -50,8 +53,9 @@ pub enum ElementKind {
|
||||
}
|
||||
|
||||
impl ElementKind {
|
||||
pub const ALL: [ElementKind; 11] = [
|
||||
pub const ALL: [ElementKind; 12] = [
|
||||
ElementKind::Rod2,
|
||||
ElementKind::Rod3,
|
||||
ElementKind::Beam2,
|
||||
ElementKind::Tri3,
|
||||
ElementKind::Tri6,
|
||||
@@ -67,7 +71,7 @@ impl ElementKind {
|
||||
pub fn node_count(self) -> usize {
|
||||
match self {
|
||||
ElementKind::Rod2 | ElementKind::Beam2 => 2,
|
||||
ElementKind::Tri3 => 3,
|
||||
ElementKind::Rod3 | ElementKind::Tri3 => 3,
|
||||
ElementKind::Quad4 | ElementKind::Tet4 => 4,
|
||||
ElementKind::Tri6 | ElementKind::Wedge6 => 6,
|
||||
ElementKind::Quad8 | ElementKind::Hex8 => 8,
|
||||
@@ -79,7 +83,7 @@ impl ElementKind {
|
||||
/// Corner nodes: the first ones in the node list (the rest are mid-side nodes).
|
||||
pub fn corner_count(self) -> usize {
|
||||
match self {
|
||||
ElementKind::Rod2 | ElementKind::Beam2 => 2,
|
||||
ElementKind::Rod2 | ElementKind::Rod3 | ElementKind::Beam2 => 2,
|
||||
ElementKind::Tri3 | ElementKind::Tri6 => 3,
|
||||
ElementKind::Quad4 | ElementKind::Quad8 | ElementKind::Tet4 | ElementKind::Tet10 => 4,
|
||||
ElementKind::Wedge6 => 6,
|
||||
@@ -95,7 +99,7 @@ impl ElementKind {
|
||||
/// Topological dimension: 1 for line elements, 2 for shells, 3 for solids.
|
||||
pub fn dimension(self) -> u8 {
|
||||
match self {
|
||||
ElementKind::Rod2 | ElementKind::Beam2 => 1,
|
||||
ElementKind::Rod2 | ElementKind::Rod3 | ElementKind::Beam2 => 1,
|
||||
ElementKind::Tri3 | ElementKind::Tri6 | ElementKind::Quad4 | ElementKind::Quad8 => 2,
|
||||
ElementKind::Tet4 | ElementKind::Tet10 | ElementKind::Wedge6 | ElementKind::Hex8 | ElementKind::Hex20 => 3,
|
||||
}
|
||||
@@ -105,6 +109,7 @@ impl ElementKind {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
ElementKind::Rod2 => "rod2",
|
||||
ElementKind::Rod3 => "rod3",
|
||||
ElementKind::Beam2 => "beam2",
|
||||
ElementKind::Tri3 => "tri3",
|
||||
ElementKind::Tri6 => "tri6",
|
||||
@@ -134,7 +139,7 @@ impl ElementKind {
|
||||
/// - Line elements have none.
|
||||
pub fn faces(self) -> &'static [&'static [usize]] {
|
||||
match self {
|
||||
ElementKind::Rod2 | ElementKind::Beam2 => &[],
|
||||
ElementKind::Rod2 | ElementKind::Rod3 | ElementKind::Beam2 => &[],
|
||||
ElementKind::Tri3 => &[&[0, 1, 2], &[0, 2, 1]],
|
||||
ElementKind::Tri6 => &[&[0, 1, 2, 3, 4, 5], &[0, 2, 1, 5, 4, 3]],
|
||||
ElementKind::Quad4 => &[&[0, 1, 2, 3], &[0, 3, 2, 1]],
|
||||
@@ -160,6 +165,7 @@ impl ElementKind {
|
||||
pub fn edges(self) -> &'static [&'static [usize]] {
|
||||
match self {
|
||||
ElementKind::Rod2 | ElementKind::Beam2 => &[&[0, 1]],
|
||||
ElementKind::Rod3 => &[&[0, 1, 2]],
|
||||
ElementKind::Tri3 => &[&[0, 1], &[1, 2], &[2, 0]],
|
||||
ElementKind::Tri6 => &[&[0, 1, 3], &[1, 2, 4], &[2, 0, 5]],
|
||||
ElementKind::Quad4 => &[&[0, 1], &[1, 2], &[2, 3], &[3, 0]],
|
||||
@@ -357,7 +363,7 @@ mod tests {
|
||||
/// Reference coordinates with positive volume for each kind (mid-side nodes at edge midpoints).
|
||||
fn reference(kind: ElementKind) -> Vec<[f64; 3]> {
|
||||
let corners: Vec<[f64; 3]> = match kind {
|
||||
ElementKind::Rod2 | ElementKind::Beam2 => vec![[0., 0., 0.], [1., 0., 0.]],
|
||||
ElementKind::Rod2 | ElementKind::Rod3 | ElementKind::Beam2 => vec![[0., 0., 0.], [1., 0., 0.]],
|
||||
ElementKind::Tri3 | ElementKind::Tri6 => vec![[0., 0., 0.], [1., 0., 0.], [0., 1., 0.]],
|
||||
ElementKind::Quad4 | ElementKind::Quad8 => vec![[0., 0., 0.], [1., 0., 0.], [1., 1., 0.], [0., 1., 0.]],
|
||||
ElementKind::Tet4 | ElementKind::Tet10 => vec![[0., 0., 0.], [1., 0., 0.], [0., 1., 0.], [0., 0., 1.]],
|
||||
|
||||
Reference in new issue
Block a user