SOLID185 — 8-node hex solid#
Kinematics. Trilinear isoparametric 8-node hexahedron; three translational DOFs per node (\(u_x, u_y, u_z\)); 24 DOFs per element.
Stiffness. Displacement-based continuum formulation \(K_e = \int_{\Omega_e} B^\top C B \, \mathrm{d}V\), integrated on the reference cube \([-1, 1]^3\) with 2×2×2 Gauss-Legendre.
Mass. Consistent \(M_e = \int_{\Omega_e} \rho N^\top N \, \mathrm{d}V\), same integration rule. Row-sum lumping available.
MAPDL compatibility. Reproduces SOLID185 at KEYOPT(2) = 0 (Hughes B-bar, the MAPDL default) and KEYOPT(2) = 3 (simplified enhanced assumed strain, Simo–Rifai).
Kinematics and shape functions#
The formulation below is the standard isoparametric continuum brick
documented in every FEM textbook [Bathe2014] [Hughes1987]
[ZTZ2013] [Cook2001]; we give it here in a form that maps
line-by-line to the implementation in
femorph_solver.elements.solid185.
On the reference cube with natural coordinates \((\xi, \eta, \zeta) \in [-1, 1]^3\), trilinear shape functions
are associated with the eight corner nodes \((\xi_i, \eta_i, \zeta_i) \in \{\pm 1\}^3\). The isoparametric map takes the reference cube to the physical hex:
The node-ordering convention matches MAPDL and VTK_HEXAHEDRON: corners of the bottom face (\(\zeta = -1\)) first in CCW order, then the top face.
Jacobian and strain-displacement matrix#
Derivatives of \(N_i\) with respect to physical coordinates are recovered via the Jacobian of the isoparametric map,
Small-strain Voigt notation with engineering shear gives \(\varepsilon = [\varepsilon_{xx},\ \varepsilon_{yy},\ \varepsilon_{zz},\ \gamma_{xy},\ \gamma_{yz},\ \gamma_{xz}]^\top\) and the 6 × 24 strain-displacement matrix
Stacking \(B = [B_1 \,|\, B_2 \,|\, \dots \,|\, B_8]\) produces the full 6 × 24 block.
Isotropic constitutive matrix#
For linear isotropic elasticity with Lamé parameters \(\lambda = \frac{E\nu}{(1+\nu)(1-2\nu)}\) and shear modulus \(\mu = G = \frac{E}{2(1+\nu)}\),
Gauss-Legendre quadrature on \([-1, 1]^3\)#
The 2 × 2 × 2 tensor-product rule uses 8 points at \((\pm 1/\sqrt{3}, \pm 1/\sqrt{3}, \pm 1/\sqrt{3})\) with unit weights. The rule is exact for polynomial integrands up to degree 3 in each direction — enough to integrate the \(B^\top C B\) product exactly on undistorted hexes. Physical volume integration picks up the determinant of \(J\):
Numpy walk-through (plain displacement formulation)#
The following pure-numpy listing assembles \(K_e\) for a unit cube made of generic steel (E = 210 GPa, ν = 0.30). Running it on a 24-DOF element produces a symmetric matrix with six exact rigid-body zero eigenvalues and eighteen non-zero elastic modes.
import numpy as np
# 2x2x2 Gauss-Legendre on [-1, 1]^3.
g = 1.0 / np.sqrt(3.0)
gp = np.array([(-g,-g,-g), (+g,-g,-g), (+g,+g,-g), (-g,+g,-g),
(-g,-g,+g), (+g,-g,+g), (+g,+g,+g), (-g,+g,+g)])
w = np.ones(8)
# Natural coordinates of the 8 nodes (MAPDL / VTK order).
xi_n = np.array([(-1,-1,-1), (+1,-1,-1), (+1,+1,-1), (-1,+1,-1),
(-1,-1,+1), (+1,-1,+1), (+1,+1,+1), (-1,+1,+1)],
dtype=float)
def shape_and_derivs(xi, eta, zeta):
N = 0.125 * (1 + xi_n[:, 0] * xi) \
* (1 + xi_n[:, 1] * eta) \
* (1 + xi_n[:, 2] * zeta)
dN = np.empty((8, 3))
dN[:, 0] = 0.125 * xi_n[:, 0] * (1 + xi_n[:, 1] * eta) * (1 + xi_n[:, 2] * zeta)
dN[:, 1] = 0.125 * xi_n[:, 1] * (1 + xi_n[:, 0] * xi) * (1 + xi_n[:, 2] * zeta)
dN[:, 2] = 0.125 * xi_n[:, 2] * (1 + xi_n[:, 0] * xi) * (1 + xi_n[:, 1] * eta)
return N, dN
# Unit cube nodes.
X = np.array([(0,0,0), (1,0,0), (1,1,0), (0,1,0),
(0,0,1), (1,0,1), (1,1,1), (0,1,1)], dtype=float)
E, nu = 2.1e11, 0.30
lam = E*nu / ((1+nu)*(1-2*nu))
mu = E / (2*(1+nu))
C = np.diag([lam+2*mu, lam+2*mu, lam+2*mu, mu, mu, mu]).astype(float)
C[:3, :3] += lam * (1 - np.eye(3)) # off-diagonal λ coupling of ε_ii
K = np.zeros((24, 24))
for (xi, eta, zeta), wi in zip(gp, w):
_, dNdxi = shape_and_derivs(xi, eta, zeta)
J = dNdxi.T @ X
detJ = np.linalg.det(J)
dNdx = np.linalg.solve(J, dNdxi.T).T
B = np.zeros((6, 24))
for i in range(8):
col = 3 * i
B[0, col + 0] = dNdx[i, 0]
B[1, col + 1] = dNdx[i, 1]
B[2, col + 2] = dNdx[i, 2]
B[3, col + 0] = dNdx[i, 1]
B[3, col + 1] = dNdx[i, 0]
B[4, col + 1] = dNdx[i, 2]
B[4, col + 2] = dNdx[i, 1]
B[5, col + 0] = dNdx[i, 2]
B[5, col + 2] = dNdx[i, 0]
K += B.T @ C @ B * detJ * wi
eig = np.sort(np.linalg.eigvalsh(K))
# eig[:6] ≈ 0 # six rigid-body modes
# eig[6:] > 0 # 18 elastic modes
Volumetric locking and Hughes B-bar#
The plain displacement formulation above suffers from volumetric locking as \(\nu \to 1/2\) or when the strain field has a strong volumetric component that the trilinear kinematics cannot accommodate. Hughes’s selective reduced integration [Hughes1980] projects the volumetric strain component onto the element-constant subspace:
where \(b_{i,k} = \partial_{x_k} N_i\) and \(\bar{b}_k = \frac{1}{V_e} \int_{\Omega_e} b_{i,k} \, \mathrm{d}V\) is the volume-averaged derivative. In practice the correction is implemented in closed form as
with \(S = \sum_g b(\xi_g)\lvert J(\xi_g)\rvert w_g\) and \(H = \sum_g b(\xi_g)b(\xi_g)^\top \lvert J(\xi_g)\rvert w_g\), where \(b(\xi_g)\) is the 24-vector of volumetric derivatives at Gauss point \(\xi_g\). This is the MAPDL KEYOPT(2) = 0 default and femorph-solver’s “full” formulation.
Enhanced assumed strain (Simo–Rifai)#
An alternative cure for volumetric and shear locking replaces the compatible strain \(\varepsilon = B u_e\) with an enhanced decomposition
where \(\alpha\) is a set of per-element strain parameters and \(G(\xi)\) is a 9-column enhancement matrix constructed from hierarchic bubble functions [SimoRifai1990]. Static condensation eliminates \(\alpha\) at the element level, producing the enhanced stiffness
with
where \(\Gamma(\xi) = j_0 \, J_0^{-1}\, G(\xi)\, / \lvert J(\xi)\rvert\) is the enhancement in current-configuration coordinates under the Pian–Tong \(j_0 / j\) scaling.
femorph-solver implements this exactly under
_SOLID185_FORMULATION = "enhanced_strain", matching MAPDL’s
simplified EAS (KEYOPT(2) = 3) element-wise to machine precision on
regular hexes.
Mass matrix#
Consistent mass uses the same integration rule:
Row-sum lumping \(M_e^{\text{lump}} = \text{diag}\bigl(\sum_j
M_{e,ij}\bigr)\) is available via mass_matrix
with lumped=True.
Formulation flag#
Name |
MAPDL KEYOPT(2) |
Description |
|---|---|---|
|
0 (default) |
2×2×2 Gauss + Hughes volumetric B-bar. Default, matches MAPDL bit-exact on regular hexes. |
|
3 |
Simo–Rifai EAS with 9 enhancement modes and Pian–Tong \(j_0 / j\) scaling. Cures both shear and volumetric locking; recovers >95 % of the Euler–Bernoulli tip deflection on a slender cantilever with one element through the thickness (vs <50 % for plain 2×2×2). |
Set the formulation via the material dictionary:
import femorph_solver
m = femorph_solver.Model()
m.et(1, "SOLID185")
m.mp("EX", 1, 2.1e11)
m.mp("PRXY", 1, 0.30)
m.materials[1]["_SOLID185_FORMULATION"] = "enhanced_strain"
Validation#
Rigid-body modes. On any undistorted hex, \(K_e\) should have exactly six zero eigenvalues (three translations + three rotations) and eighteen non-zero elastic modes. Verify directly:
import numpy as np
from femorph_solver.elements import get
SOLID185 = get("SOLID185")
X = np.array([(0,0,0), (1,0,0), (1,1,0), (0,1,0),
(0,0,1), (1,0,1), (1,1,1), (0,1,1)], dtype=float)
K = SOLID185.ke(X, {"EX": 2.1e11, "PRXY": 0.30}, np.empty(0))
eig = np.sort(np.linalg.eigvalsh(K))
assert np.allclose(eig[:6], 0, atol=1e-4 * eig[-1]) # 6 rigid-body modes
assert (eig[6:] > 0).all() # 18 elastic modes
Cantilever tip deflection. For a slender cantilever (\(L \gg h\)) with tip load \(P\), Euler–Bernoulli theory gives \(u_\text{tip} = P L^3 / (3 E I)\). A single hex through the thickness reaches this limit to within a few percent under the EAS formulation; the plain-displacement formulation severely under-predicts due to shear locking. The MacNeal–Harder benchmark set [MacNealHarder1985] ships the canonical variants of this problem; the SOLID185 gallery runs the slender-cantilever version end-to-end.
MAPDL parity. femorph-solver’s SOLID185 matches MAPDL (KEYOPT(2) = 0) on the bundled quarter-arc sector to machine precision — see the SOLID185 cyclic-modal parity test.
API reference#
- class femorph_solver.elements.solid185.SOLID185[source]#
Bases:
ElementBase- static eel_batch(coords: ndarray, u_e: ndarray) ndarray | None[source]#
Per-element elastic strain at every element node.
coordsis(n_elem, 8, 3)andu_eis(n_elem, 24)— the element DOF vector laid out as[ux0, uy0, uz0, ux1, …]. Returns(n_elem, 8, 6)with Voigt components[εxx, εyy, εzz, γxy, γyz, γxz](engineering shears), orNoneif the C++ extension is unavailable.
- 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 MAPDL property names as keys (EX, PRXY, DENS, ...))
real (1-D array of real constants)
- static ke_batch(coords: ndarray, material: dict[str, float], real: ndarray) ndarray | None[source]#
Vectorized Ke over
(n_elem, 8, 3)coords.Routes to the C++ B-bar kernel on the default path, to plain Gauss when the
plain_gaussflag is set, and returnsNonefor EAS (Python-only for now) so the assembler falls back to per-elementke()dispatch.
References#
Bathe, K.-J. (2014). Finite Element Procedures, 2nd ed. Prentice-Hall / Klaus-Jürgen Bathe. Chapters 4 (isoparametric elements) and 6 (continuum). https://www.klausjurgenbathe.com/fepbook/
Hughes, T. J. R. (1987). The Finite Element Method: Linear Static and Dynamic Finite Element Analysis. Prentice-Hall; Dover reprint 2000 (ISBN 0-486-41181-8). Chapter 3 (isoparametric formulation), §4.5 (selective reduced integration). https://store.doverpublications.com/0486411818.html
Hughes, T. J. R. (1980). “Generalization of selective integration procedures to anisotropic and nonlinear media.” International Journal for Numerical Methods in Engineering 15, 1413–1418. https://doi.org/10.1002/nme.1620150914
Simo, J. C. and Rifai, M. S. (1990). “A class of mixed assumed strain methods and the method of incompatible modes.” International Journal for Numerical Methods in Engineering 29, 1595–1638. https://doi.org/10.1002/nme.1620290802
MacNeal, R. H. and Harder, R. L. (1985). “A proposed standard set of problems to test finite element accuracy.” Finite Elements in Analysis and Design 1 (1), 3–20. https://doi.org/10.1016/0168-874X(85)90003-4
Zienkiewicz, O. C., Taylor, R. L., and Zhu, J. Z. (2013). The Finite Element Method: Its Basis and Fundamentals, 7th ed. Butterworth-Heinemann (Elsevier). https://doi.org/10.1016/C2009-0-24909-9
Cook, R. D., Malkus, D. S., Plesha, M. E., and Witt, R. J. (2001). Concepts and Applications of Finite Element Analysis, 4th ed. Wiley. ISBN 978-0-471-35605-9. https://www.wiley.com/en-us/Concepts+and+Applications+of+Finite+Element+Analysis%2C+4th+Edition-p-9780471356059