Source code for fem2d.elements.trussNL

"""
Non-linear truss element module implementing a geometrically non-linear 2D truss element.
"""

import numpy as np
from fem2d.elements.element import ElementBase


[docs] class TrussElementNL(ElementBase): """ Geometrically nonlinear truss element using corotational formulation. Nodes have 2 translational DOFs: [ux, uy], with rotation index mapped to zero. Attributes ---------- material : ElasticMaterial Material definition for the element. area : float Cross-sectional area. L0 : float Initial (undeformed) length. Q : float Axial force (compression positive, tension negative). cx : float Current direction cosine along the global x-axis. cy : float Current direction cosine along the global y-axis. L : float Current deformed length. ke : numpy.ndarray or None Elastic stiffness matrix in global coordinates. kg : numpy.ndarray or None Geometric stiffness matrix in global coordinates. k_t : numpy.ndarray or None Tangent stiffness matrix in global coordinates. F_global : numpy.ndarray or None Internal force vector in global coordinates. """ def __init__(self, eid, node_i, node_j, material, area): """ Initialize a TrussElementNL. Parameters ---------- eid : int or str Unique identifier of the element. node_i : Node Start node. node_j : Node End node. material : ElasticMaterial Material definition. area : float Cross-sectional area. """ super().__init__(eid, node_i, node_j) self.material = material self.area = area # Store initial length (undeformed) self.L0 = self.length # computed by _update_geometry() in base class # State variables self.Q = 0.0 # axial force (compression positive, as in text) self.cx = self.cos # current direction cosines (initial) self.cy = self.sin self.L = self.L0 # current length self.ke = None # elastic stiffness matrix (global) self.kg = None # geometric stiffness matrix (global) self.k_t = None # tangent stiffness (global)
[docs] def update_state(self, global_disp): """ Given global displacement vector of the whole structure, extract this element's end displacements and update internal state (internal force, tangent stiffness). Parameters ---------- global_disp : numpy.ndarray Full global displacement vector of the structure. """ # End displacements in global coordinates (2 per node) u_i = global_disp[self.node_i.dofs] # [ux_i, uy_i] u_j = global_disp[self.node_j.dofs] # [ux_j, uy_j] # Current coordinates of nodes x_i = self.node_i.x + u_i[0] y_i = self.node_i.y + u_i[1] x_j = self.node_j.x + u_j[0] y_j = self.node_j.y + u_j[1] # Current length and direction cosines (Eqs. 10.20–10.22) dx = x_j - x_i dy = y_j - y_i self.L = np.hypot(dx, dy) if self.L == 0: self.cx = 1.0 self.cy = 0.0 else: self.cx = dx / self.L self.cy = dy / self.L # Axial deformation (shortening positive) – Eq. (10.15) u = self.L0 - self.L # Axial force (compression positive) – Eq. (10.18) self.Q = (self.material.E * self.area / self.L0) * u # Global internal force vector (size 4) – Eq. (10.24) F = np.array( [self.cx * self.Q, self.cy * self.Q, -self.cx * self.Q, -self.cy * self.Q] ) # Expand to 6x1 for assembly (mapping to [ux_i, uy_i, 0, ux_j, uy_j, 0]) self.F_global = np.zeros(6) self.F_global[[0, 1, 3, 4]] = F # Tangent stiffness matrix (global, 4x4) – Eq. (10.31) EA_L = self.material.E * self.area / self.L0 Q_L = self.Q / self.L c = self.cx s = self.cy # Elastic part (EA/L * T^T T) ke_local = EA_L * np.array( [ [c * c, c * s, -c * c, -c * s], [c * s, s * s, -c * s, -s * s], [-c * c, -c * s, c * c, c * s], [-c * s, -s * s, c * s, s * s], ] ) # Geometric part (Q/L * g) with g from Eq. (10.33) kg_local = Q_L * np.array( [ [-s * s, c * s, s * s, -c * s], [c * s, -c * c, -c * s, c * c], [s * s, -c * s, -s * s, c * s], [-c * s, c * c, c * s, -c * c], ] ) k_t_local = ke_local + kg_local # Expand to 6x6 (insert zeros for rotational DOFs) self.k_t = np.zeros((6, 6)) idx = [0, 1, 3, 4] for i, ii in enumerate(idx): for j, jj in enumerate(idx): self.k_t[ii, jj] = k_t_local[i, j]
[docs] def get_tangent_stiffness(self): """ Return the global tangent stiffness matrix of the element. Returns ------- numpy.ndarray 6x6 tangent stiffness matrix in global coordinates. """ return self.k_t
[docs] def get_internal_forces(self): """ Return the global internal force vector of the element. Returns ------- numpy.ndarray 6x1 global internal force vector. """ return self.F_global
[docs] def get_local_forces(self): """ Return local end forces as a 6‑component array: [Fx_i, Fy_i, Mz_i, Fx_j, Fy_j, Mz_j] Axial force Q is positive in compression. Returns ------- numpy.ndarray 6x1 force vector in local coordinates. """ return np.array([self.Q, 0.0, 0.0, -self.Q, 0.0, 0.0])