Strain and stress recovery#
femorph-solver recovers elastic strain from a displacement field via
femorph_solver.Model.eel(). The evaluation uses
at each element’s own node positions \(\xi_\text{node}\) — i.e. direct nodal evaluation of \(\varepsilon = B u_e\), not Gauss-point sampling followed by extrapolation. For uniform-strain fields the two approaches agree exactly; for general fields they converge with mesh refinement.
Voigt convention#
Every strain tensor returned by femorph-solver is 6-component Voigt with engineering shears:
with \(\gamma_{xy} = 2\varepsilon_{xy}\) (canonical Voigt strain layout).
API#
u = static.displacement # from solve_static / Model.solve
eps = m.eel(u) # (n_nodes_global, 6), nodal-averaged
eps_x = eps[:, 0] # ε_xx at every node
gamma_xy = eps[:, 3] # engineering shear
From a mode shape#
Strain can be recovered from any valid displacement vector, including an eigenvector column from a modal solve:
modal = solve_modal(K, M, prescribed=fixed, n_modes=10,
eigen_solver="arpack", sigma=-1.0)
eps_mode7 = m.eel(modal.mode_shapes[:, 7])
Public per-node helpers#
The femorph_solver.recover module exposes (n_points, 6)
Voigt strain and stress at every grid node, with multi-element
nodes averaged in place (unweighted, same convention as MAPDL’s
PRNSOL):
from femorph_solver.recover import (
compute_nodal_strain,
compute_nodal_stress,
stress_invariants,
)
u = static.displacement # DOF-indexed displacement
eps = compute_nodal_strain(m, u) # (n_points, 6) Voigt strain
sig = compute_nodal_stress(m, u) # (n_points, 6) Voigt stress
inv = stress_invariants(sig) # von_mises, s1/s2/s3, ...
Both helpers walk every element once, evaluate \(\varepsilon = B(\xi_\text{node})\,u_e\) at the element’s own nodes, optionally apply the per-material \(\sigma = C\varepsilon\), and average across every element that touches a node. Nodes with no incident element come back as zeros.
Stress recovery#
Stress \(\sigma = C \varepsilon\) is also available as a direct contraction from the elastic moduli when only one element’s elasticity matrix is in hand. For an isotropic Hooke’s law:
from femorph_solver.elements.hex8 import _elastic_matrix
C = _elastic_matrix(E=2.1e11, nu=0.30) # 6x6 isotropic
sigma = eps @ C.T # (n_nodes, 6)
Element-specific notes#
Solids (HEX8 / HEX20 / TET10) return 3-D Voigt as described above.
Shells (QUAD4_SHELL) return membrane + bending + transverse-shear components; details on the QUAD4_SHELL — 4-node Mindlin–Reissner shell reference page.
Beams, trusses, springs — currently return placeholder arrays; their strain / stress output is on the roadmap.
See also#
Result objects — source
displacement/mode_shapesvectors.Visualisation and export — attaching the strain array to the model grid for a pyvista colour plot.