Note
Go to the end to download the full example code.
HEX8 reference geometry — nodes, shape functions, Gauss points#
Renders the 8-node trilinear hexahedron’s reference element \(\hat\Omega = [-1, 1]^3\) with three layers of annotation:
Corner nodes with their natural-coordinate triplets \((\xi_i, \eta_i, \zeta_i) \in \{-1, +1\}^3\).
Trilinear Lagrange shape functions
\[N_i(\xi, \eta, \zeta) = \tfrac{1}{8}(1 + \xi_i\xi)(1 + \eta_i\eta)(1 + \zeta_i\zeta), \qquad i = 1, \ldots, 8,\]evaluated on a sampling lattice and visualised by colouring the reference cube faces with \(N_1(\xi, \eta, \zeta)\).
2×2×2 Gauss-Legendre integration points at \((\xi, \eta, \zeta) \in \{-1, +1\}/\sqrt{3}\), used by the stiffness and consistent-mass integrals on this element.
References#
Hughes, T. J. R. (2000) The Finite Element Method — Linear Static and Dynamic Finite Element Analysis, Dover, §3.1 (trilinear shape functions); §3.10 (Gauss-Legendre quadrature).
Cook, R. D., Malkus, D. S., Plesha, M. E., Witt, R. J. (2002) Concepts and Applications of Finite Element Analysis, 4th ed., Wiley, §6.2.
Zienkiewicz, O. C. and Taylor, R. L. (2013) The Finite Element Method: Its Basis and Fundamentals, 7th ed., Butterworth- Heinemann, §6.
Implementation: femorph_solver.elements.hex8.Hex8.
from __future__ import annotations
import numpy as np
import pyvista as pv
Reference cube as a single-cell pyvista UnstructuredGrid#
Native HEX8 corner ordering (ξ, η, ζ) ∈ {-1, +1}^3 follows the
standard isoparametric convention — VTK_HEXAHEDRON’s node order
matches it, so we author the geometry once and visualise directly.
corners = 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,
)
cells = np.hstack([[8], np.arange(8, dtype=np.int64)])
cell_types = np.array([pv.CellType.HEXAHEDRON], dtype=np.uint8)
ref_cube = pv.UnstructuredGrid(cells, cell_types, corners)
Shape function \(N_1\) over a sampling lattice#
Sample \(N_1(\xi, \eta, \zeta) = \tfrac18 (1 - \xi)(1 - \eta)
(1 - \zeta)\) on a 21^3 lattice and store as a StructuredGrid
point array. Slicing through the volume gives 2D contour-friendly
views.
2×2×2 Gauss-Legendre integration points#
Render the figure#
Three glyphs share the same scene: the reference-cube wireframe (black), an \(N_1\) slice through the centre (warm colormap), and the eight Gauss points as red spheres.
plotter = pv.Plotter(off_screen=True, window_size=(640, 480))
plotter.add_mesh(
ref_cube,
style="wireframe",
color="black",
line_width=2,
label="reference element",
)
slc = sample.slice_orthogonal(x=0.0, y=0.0, z=0.0)
plotter.add_mesh(
slc,
scalars="N_1",
cmap="plasma",
show_edges=False,
opacity=0.85,
scalar_bar_args={"title": "N_1(ξ, η, ζ)"},
)
plotter.add_points(
gauss,
render_points_as_spheres=True,
point_size=20,
color="#d62728",
label="Gauss points (2×2×2)",
)
# Corner-node spheres
plotter.add_points(
corners,
render_points_as_spheres=True,
point_size=14,
color="black",
label="corner nodes",
)
plotter.add_axes(line_width=4, color="black")
plotter.view_isometric()
plotter.camera.zoom(1.1)
plotter.add_legend(face=None, size=(0.18, 0.10), bcolor="white")
plotter.show()

Verify the partition of unity#
At any point inside \(\hat\Omega\) the eight shape functions must sum to one. Sampling \(N_i(\xi_q, \eta_q, \zeta_q)\) at every Gauss point and asserting \(\sum_i N_i = 1\) is a minimal sanity check — failure would point to a typo in the kernel’s shape-function evaluation.
xi_i, eta_i, zeta_i = corners.T
sums = np.array(
[
sum(
(1 + xi_i * a) * (1 + eta_i * b) * (1 + zeta_i * c) / 8.0
for a, b, c in [(g[0], g[1], g[2])]
).sum()
for g in gauss
]
)
print("partition-of-unity Σ N_i at each Gauss point:")
for q, s in zip(gauss, sums, strict=True):
print(f" ξ={q[0]:+.4f} η={q[1]:+.4f} ζ={q[2]:+.4f} Σ={s:.15f}")
np.testing.assert_allclose(sums, 1.0, atol=1.0e-14)
print("OK — all 8 shape functions sum to 1 at every Gauss point.")
partition-of-unity Σ N_i at each Gauss point:
ξ=-0.5774 η=-0.5774 ζ=-0.5774 Σ=1.000000000000000
ξ=-0.5774 η=-0.5774 ζ=+0.5774 Σ=1.000000000000000
ξ=-0.5774 η=+0.5774 ζ=-0.5774 Σ=1.000000000000000
ξ=-0.5774 η=+0.5774 ζ=+0.5774 Σ=1.000000000000000
ξ=+0.5774 η=-0.5774 ζ=-0.5774 Σ=1.000000000000000
ξ=+0.5774 η=-0.5774 ζ=+0.5774 Σ=1.000000000000000
ξ=+0.5774 η=+0.5774 ζ=-0.5774 Σ=1.000000000000000
ξ=+0.5774 η=+0.5774 ζ=+0.5774 Σ=1.000000000000000
OK — all 8 shape functions sum to 1 at every Gauss point.
Total running time of the script: (0 minutes 0.204 seconds)