SPRING — 3-D 2-node longitudinal spring#

Kinematics. Two-node spring oriented along \(I \to J\); three translational DOFs per node; 6 DOFs per element. No bending, torsion, or mass — the longitudinal spring is stiffness-only.

Stiffness. Closed-form \(K_e = K \begin{bmatrix} C & -C \\ -C & C \end{bmatrix}\) with \(C = \hat{d} \hat{d}^\top\).

Mass. Zero by convention (me returns a 6 × 6 zero matrix so the assembler can dispatch uniformly).

Modes. Only the longitudinal mode is implemented; torsional and 2-D planar variants are separate code paths and roadmap.


Longitudinal spring#

A spring is the discrete analogue of a truss whose only “material” property is the stiffness \(K\) (force per length); compared to TRUSS2, there is no cross-section area, no length in the \(E A / L\) sense — just a scalar spring constant [Cook2001].

Taking \(\hat{d} = (d_x, d_y, d_z)\) as the unit vector along \(I \to J\), the axial displacement at each end projects onto \(\hat{d}\) to give a 1-D spring acting in that direction. The element stiffness in global coordinates is

\[\begin{split}K_e = K \begin{bmatrix} \phantom{-}C & -C \\ -C & \phantom{-}C \end{bmatrix}, \qquad C_{jk} = d_j\, d_k,\end{split}\]

directly analogous to the TRUSS2 formula with \(E A / L\) replaced by \(K\). \(K_e\) has rank 1 (the single stretching mode); five zero eigenvalues correspond to the allowed rigid-body / transverse translations.

Real constants#

Slot

Symbol

Meaning

real[0]

\(K\)

Spring stiffness (force / length). Mandatory.

real[1]

CV1

Linear damping (force · time / length). Parsed but not used by \(K_e\); consumed by transient damping paths when available.

real[2]

CV2

Non-linear cubic damping. Parsed but not used.

real[3]

IL

Initial length. Parsed but ignored; the reference length is the nodal distance.

Numpy walk-through#

import numpy as np

K_spring = 1.0e6                       # N / m
X = np.array([[0.0, 0.0, 0.0],
              [1.0, 0.0, 0.0]])

d = X[1] - X[0]
L = float(np.linalg.norm(d))
dhat = d / L

Cproj = np.outer(dhat, dhat)           # 3x3
K = K_spring * np.block([[ Cproj, -Cproj],
                         [-Cproj,  Cproj]])
# Eigvals: [0, 0, 0, 0, 0, 2 * K_spring]
# Zero mass:
M = np.zeros((6, 6))

Validation#

Single-element stretch. A 1-D spring of stiffness \(K\) with one end pinned and a unit force on the other produces \(u = 1 / K\). Rotate the element to any orientation in 3-D; the analytic result is unchanged.

API reference#

class femorph_solver.elements.spring.Spring[source]#

Bases: ElementBase

static ke(coords: ndarray, material: dict[str, float], real: ndarray) ndarray[source]#

Return the element stiffness matrix in global DOF ordering.

Parameters:
  • coords ((n_nodes, 3) float64)

  • material (mapping with property names as keys ("EX", "PRXY", "DENS", …))

  • real (1-D array of real constants)

static me(coords: ndarray, material: dict[str, float], real: ndarray, lumped: bool = False) ndarray[source]#

Return the element mass matrix in global DOF ordering.

References#

[Cook2001]

Cook, R. D., Malkus, D. S., Plesha, M. E., and Witt, R. J. (2001). Concepts and Applications of Finite Element Analysis, 4th ed. Wiley. Ch. 2 (spring / bar elements). https://www.wiley.com/en-us/Concepts+and+Applications+of+Finite+Element+Analysis%2C+4th+Edition-p-9780471356059