Files
JuliaFEM.jl/src/basis/basis_generated.jl
T
Jukka Aho e0d81543f6 refactor(basis): Rename and rewrite lagrange_* files to basis_* with new API
Deleted files:
- src/basis/lagrange_generated.jl (451 lines) - Old generated basis implementations
- src/basis/lagrange_generator.jl (904 lines) - Old generator with complex dispatch

New files:
- src/basis/basis_generated.jl (461 lines) - New generated implementations using get_basis_functions/derivatives API
- src/basis/basis_generator.jl (622 lines) - Simplified generator with VandermondeBasisDescription

Key changes:
- Generator: Simplified from 904 → 622 lines, removed complex dispatch logic
- Generated: New API using get_basis_functions(topology, Lagrange{P}, xi) instead of eval_basis!(Lagrange{T,P}, xi)
- Return types: NTuple → SVector for type stability and StaticArrays compatibility
- Numerical filtering: Added round_coefficient for clean fractions (1/2, 1/3, 1/18, etc.)
- Basis descriptions: Uses VandermondeBasisDescription for element metadata

Net result: 1355 lines removed, 1083 lines added (272 line reduction with cleaner design)
2025-11-21 00:35:33 +02:00

462 lines
39 KiB
Julia

# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE
# ============================================================================
# AUTO-GENERATED BASIS FUNCTIONS (All Families)
# ============================================================================
# Generated by: src/basis/basis_generator.jl
# WARNING: DO NOT EDIT MANUALLY
#
# This file contains generated basis function implementations for:
# - Lagrange bases (standard nodal interpolation)
# - Serendipity bases (reduced tensor-product for quads/hexes)
# - Future: Hierarchical, modal, and exotic basis families
#
# Return Types:
# get_basis_functions → SVector{N, Float64}
# get_basis_derivatives → SVector{N, Vec{D, Float64}}
#
# Why SVector? Enables natural vector operations:
# u_interp = dot(node_values, N)
# grad_u = sum(node_values[i] * dN[i] for i in 1:N)
# ──────────────────────────────────────────────────────────────────────────────
# Lagrange{1} on Seg2: 2-node linear segment element
# (legacy name: Seg2)
@inline function get_basis_functions(::Seg2, ::Lagrange{1}, xi::Vec{1, T}) where T
(u,) = xi
N1 = 1/2 - 1/2 * u
N2 = 1/2 + 1/2 * u
return SVector{2, T}(N1, N2)
end
@inline function get_basis_derivatives(::Seg2, ::Lagrange{1}, xi::Vec{1, T}) where T
(u,) = xi
dN1 = Vec{1, T}((-1/2,))
dN2 = Vec{1, T}((1/2,))
return SVector{2, Vec{1, T}}(dN1, dN2)
end
# ──────────────────────────────────────────────────────────────────────────────
# Lagrange{2} on Seg3: 3-node quadratic segment element
# (legacy name: Seg3)
@inline function get_basis_functions(::Seg3, ::Lagrange{2}, xi::Vec{1, T}) where T
(u,) = xi
N1 = -1/2 * u + 1/2 * u ^ 2
N2 = 1/2 * u + 1/2 * u ^ 2
N3 = 1 - u ^ 2
return SVector{3, T}(N1, N2, N3)
end
@inline function get_basis_derivatives(::Seg3, ::Lagrange{2}, xi::Vec{1, T}) where T
(u,) = xi
dN1 = Vec{1, T}((-1/2 + u,))
dN2 = Vec{1, T}((1/2 + u,))
dN3 = Vec{1, T}((-2 * u,))
return SVector{3, Vec{1, T}}(dN1, dN2, dN3)
end
# ──────────────────────────────────────────────────────────────────────────────
# Lagrange{1} on Tri3: 3-node linear triangular element
# (legacy name: Tri3)
@inline function get_basis_functions(::Tri3, ::Lagrange{1}, xi::Vec{2, T}) where T
(u, v) = xi
N1 = 1 - u - v
N2 = u
N3 = v
return SVector{3, T}(N1, N2, N3)
end
@inline function get_basis_derivatives(::Tri3, ::Lagrange{1}, xi::Vec{2, T}) where T
(u, v) = xi
dN1 = Vec{2, T}((-1, -1))
dN2 = Vec{2, T}((1, 0))
dN3 = Vec{2, T}((0, 1))
return SVector{3, Vec{2, T}}(dN1, dN2, dN3)
end
# ──────────────────────────────────────────────────────────────────────────────
# Lagrange{2} on Tri6: 6-node quadratic triangular element
# (legacy name: Tri6)
@inline function get_basis_functions(::Tri6, ::Lagrange{2}, xi::Vec{2, T}) where T
(u, v) = xi
N1 = 1 - 3 * u - 3 * v + 2 * u ^ 2 + 4 * u * v + 2 * v ^ 2
N2 = -u + 2 * u ^ 2
N3 = -v + 2 * v ^ 2
N4 = 4 * u - 4 * u ^ 2 - 4 * u * v
N5 = 4 * u * v
N6 = 4 * v - 4 * u * v - 4 * v ^ 2
return SVector{6, T}(N1, N2, N3, N4, N5, N6)
end
@inline function get_basis_derivatives(::Tri6, ::Lagrange{2}, xi::Vec{2, T}) where T
(u, v) = xi
dN1 = Vec{2, T}((-3 + 4 * u + 4 * v, -3 + 4 * u + 4 * v))
dN2 = Vec{2, T}((-1 + 4 * u, 0))
dN3 = Vec{2, T}((0, -1 + 4 * v))
dN4 = Vec{2, T}((4 - 8 * u - 4 * v, -4 * u))
dN5 = Vec{2, T}((4 * v, 4 * u))
dN6 = Vec{2, T}((-4 * v, 4 - 4 * u - 8 * v))
return SVector{6, Vec{2, T}}(dN1, dN2, dN3, dN4, dN5, dN6)
end
# ──────────────────────────────────────────────────────────────────────────────
# Lagrange{1} on Quad4: 4-node bilinear quadrilateral element
# (legacy name: Quad4)
@inline function get_basis_functions(::Quad4, ::Lagrange{1}, xi::Vec{2, T}) where T
(u, v) = xi
N1 = 1/4 - 1/4 * u - 1/4 * v + 1/4 * u * v
N2 = 1/4 + 1/4 * u - 1/4 * v - 1/4 * u * v
N3 = 1/4 + 1/4 * u + 1/4 * v + 1/4 * u * v
N4 = 1/4 - 1/4 * u + 1/4 * v - 1/4 * u * v
return SVector{4, T}(N1, N2, N3, N4)
end
@inline function get_basis_derivatives(::Quad4, ::Lagrange{1}, xi::Vec{2, T}) where T
(u, v) = xi
dN1 = Vec{2, T}((-1/4 + 1/4 * v, -1/4 + 1/4 * u))
dN2 = Vec{2, T}((1/4 - 1/4 * v, -1/4 - 1/4 * u))
dN3 = Vec{2, T}((1/4 + 1/4 * v, 1/4 + 1/4 * u))
dN4 = Vec{2, T}((-1/4 - 1/4 * v, 1/4 - 1/4 * u))
return SVector{4, Vec{2, T}}(dN1, dN2, dN3, dN4)
end
# ──────────────────────────────────────────────────────────────────────────────
# Serendipity{2} on Quad8: 8-node serendipity quadrilateral element
# (legacy name: Quad8)
@inline function get_basis_functions(::Quad8, ::Serendipity{2}, xi::Vec{2, T}) where T
(u, v) = xi
N1 = -1/4 + 1/4 * u ^ 2 + 1/4 * u * v + 1/4 * v ^ 2 - 1/4 * u ^ 2 * v - 1/4 * u * v ^ 2
N2 = -1/4 + 1/4 * u ^ 2 - 1/4 * u * v + 1/4 * v ^ 2 - 1/4 * u ^ 2 * v + 1/4 * u * v ^ 2
N3 = -1/4 + 1/4 * u ^ 2 + 1/4 * u * v + 1/4 * v ^ 2 + 1/4 * u ^ 2 * v + 1/4 * u * v ^ 2
N4 = -1/4 + 1/4 * u ^ 2 - 1/4 * u * v + 1/4 * v ^ 2 + 1/4 * u ^ 2 * v - 1/4 * u * v ^ 2
N5 = 1/2 - 1/2 * v - 1/2 * u ^ 2 + 1/2 * u ^ 2 * v
N6 = 1/2 + 1/2 * u - 1/2 * v ^ 2 - 1/2 * u * v ^ 2
N7 = 1/2 + 1/2 * v - 1/2 * u ^ 2 - 1/2 * u ^ 2 * v
N8 = 1/2 - 1/2 * u - 1/2 * v ^ 2 + 1/2 * u * v ^ 2
return SVector{8, T}(N1, N2, N3, N4, N5, N6, N7, N8)
end
@inline function get_basis_derivatives(::Quad8, ::Serendipity{2}, xi::Vec{2, T}) where T
(u, v) = xi
dN1 = Vec{2, T}((1/2 * u + 1/4 * v - 1/2 * u * v - 1/4 * v ^ 2, 1/4 * u + 1/2 * v - 1/4 * u ^ 2 - 1/2 * u * v))
dN2 = Vec{2, T}((1/2 * u - 1/4 * v - 1/2 * u * v + 1/4 * v ^ 2, -1/4 * u + 1/2 * v - 1/4 * u ^ 2 + 1/2 * u * v))
dN3 = Vec{2, T}((1/2 * u + 1/4 * v + 1/2 * u * v + 1/4 * v ^ 2, 1/4 * u + 1/2 * v + 1/4 * u ^ 2 + 1/2 * u * v))
dN4 = Vec{2, T}((1/2 * u - 1/4 * v + 1/2 * u * v - 1/4 * v ^ 2, -1/4 * u + 1/2 * v + 1/4 * u ^ 2 - 1/2 * u * v))
dN5 = Vec{2, T}((-u + u * v, -1/2 + 1/2 * u ^ 2))
dN6 = Vec{2, T}((1/2 - 1/2 * v ^ 2, -v - u * v))
dN7 = Vec{2, T}((-u - u * v, 1/2 - 1/2 * u ^ 2))
dN8 = Vec{2, T}((-1/2 + 1/2 * v ^ 2, -v + u * v))
return SVector{8, Vec{2, T}}(dN1, dN2, dN3, dN4, dN5, dN6, dN7, dN8)
end
# ──────────────────────────────────────────────────────────────────────────────
# Lagrange{2} on Quad9: 9-node biquadratic quadrilateral element
# (legacy name: Quad9)
@inline function get_basis_functions(::Quad9, ::Lagrange{2}, xi::Vec{2, T}) where T
(u, v) = xi
N1 = 1/4 * u * v - 1/4 * u ^ 2 * v - 1/4 * u * v ^ 2 + 1/4 * u ^ 2 * v ^ 2
N2 = -1/4 * u * v - 1/4 * u ^ 2 * v + 1/4 * u * v ^ 2 + 1/4 * u ^ 2 * v ^ 2
N3 = 1/4 * u * v + 1/4 * u ^ 2 * v + 1/4 * u * v ^ 2 + 1/4 * u ^ 2 * v ^ 2
N4 = -1/4 * u * v + 1/4 * u ^ 2 * v - 1/4 * u * v ^ 2 + 1/4 * u ^ 2 * v ^ 2
N5 = -1/2 * v + 1/2 * v ^ 2 + 1/2 * u ^ 2 * v - 1/2 * u ^ 2 * v ^ 2
N6 = 1/2 * u + 1/2 * u ^ 2 - 1/2 * u * v ^ 2 - 1/2 * u ^ 2 * v ^ 2
N7 = 1/2 * v + 1/2 * v ^ 2 - 1/2 * u ^ 2 * v - 1/2 * u ^ 2 * v ^ 2
N8 = -1/2 * u + 1/2 * u ^ 2 + 1/2 * u * v ^ 2 - 1/2 * u ^ 2 * v ^ 2
N9 = 1 - u ^ 2 - v ^ 2 + u ^ 2 * v ^ 2
return SVector{9, T}(N1, N2, N3, N4, N5, N6, N7, N8, N9)
end
@inline function get_basis_derivatives(::Quad9, ::Lagrange{2}, xi::Vec{2, T}) where T
(u, v) = xi
dN1 = Vec{2, T}((1/4 * v - 1/2 * u * v - 1/4 * v ^ 2 + 1/2 * u * v ^ 2, 1/4 * u - 1/4 * u ^ 2 - 1/2 * u * v + 1/2 * u ^ 2 * v))
dN2 = Vec{2, T}((-1/4 * v - 1/2 * u * v + 1/4 * v ^ 2 + 1/2 * u * v ^ 2, -1/4 * u - 1/4 * u ^ 2 + 1/2 * u * v + 1/2 * u ^ 2 * v))
dN3 = Vec{2, T}((1/4 * v + 1/2 * u * v + 1/4 * v ^ 2 + 1/2 * u * v ^ 2, 1/4 * u + 1/4 * u ^ 2 + 1/2 * u * v + 1/2 * u ^ 2 * v))
dN4 = Vec{2, T}((-1/4 * v + 1/2 * u * v - 1/4 * v ^ 2 + 1/2 * u * v ^ 2, -1/4 * u + 1/4 * u ^ 2 - 1/2 * u * v + 1/2 * u ^ 2 * v))
dN5 = Vec{2, T}((u * v - u * v ^ 2, -1/2 + v + 1/2 * u ^ 2 - u ^ 2 * v))
dN6 = Vec{2, T}((1/2 + u - 1/2 * v ^ 2 - u * v ^ 2, -u * v - u ^ 2 * v))
dN7 = Vec{2, T}((-u * v - u * v ^ 2, 1/2 + v - 1/2 * u ^ 2 - u ^ 2 * v))
dN8 = Vec{2, T}((-1/2 + u + 1/2 * v ^ 2 - u * v ^ 2, u * v - u ^ 2 * v))
dN9 = Vec{2, T}((-2 * u + 2 * u * v ^ 2, -2 * v + 2 * u ^ 2 * v))
return SVector{9, Vec{2, T}}(dN1, dN2, dN3, dN4, dN5, dN6, dN7, dN8, dN9)
end
# ──────────────────────────────────────────────────────────────────────────────
# Lagrange{1} on Tet4: 4-node linear tetrahedral element
# (legacy name: Tet4)
@inline function get_basis_functions(::Tet4, ::Lagrange{1}, xi::Vec{3, T}) where T
(u, v, w) = xi
N1 = 1 - u - v - w
N2 = u
N3 = v
N4 = w
return SVector{4, T}(N1, N2, N3, N4)
end
@inline function get_basis_derivatives(::Tet4, ::Lagrange{1}, xi::Vec{3, T}) where T
(u, v, w) = xi
dN1 = Vec{3, T}((-1, -1, -1))
dN2 = Vec{3, T}((1, 0, 0))
dN3 = Vec{3, T}((0, 1, 0))
dN4 = Vec{3, T}((0, 0, 1))
return SVector{4, Vec{3, T}}(dN1, dN2, dN3, dN4)
end
# ──────────────────────────────────────────────────────────────────────────────
# Lagrange{2} on Tet10: 10-node quadratic tetrahedral element
# (legacy name: Tet10)
@inline function get_basis_functions(::Tet10, ::Lagrange{2}, xi::Vec{3, T}) where T
(u, v, w) = xi
N1 = 1 - 3 * u - 3 * v - 3 * w + 2 * u ^ 2 + 2 * v ^ 2 + 2 * w ^ 2 + 4 * u * v + 4 * u * w + 4 * v * w
N2 = -u + 2 * u ^ 2
N3 = -v + 2 * v ^ 2
N4 = -w + 2 * w ^ 2
N5 = 4 * u - 4 * u ^ 2 - 4 * u * v - 4 * u * w
N6 = 4 * u * v
N7 = 4 * v - 4 * v ^ 2 - 4 * u * v - 4 * v * w
N8 = 4 * w - 4 * w ^ 2 - 4 * u * w - 4 * v * w
N9 = 4 * u * w
N10 = 4 * v * w
return SVector{10, T}(N1, N2, N3, N4, N5, N6, N7, N8, N9, N10)
end
@inline function get_basis_derivatives(::Tet10, ::Lagrange{2}, xi::Vec{3, T}) where T
(u, v, w) = xi
dN1 = Vec{3, T}((-3 + 4 * u + 4 * v + 4 * w, -3 + 4 * v + 4 * u + 4 * w, -3 + 4 * w + 4 * u + 4 * v))
dN2 = Vec{3, T}((-1 + 4 * u, 0, 0))
dN3 = Vec{3, T}((0, -1 + 4 * v, 0))
dN4 = Vec{3, T}((0, 0, -1 + 4 * w))
dN5 = Vec{3, T}((4 - 8 * u - 4 * v - 4 * w, -4 * u, -4 * u))
dN6 = Vec{3, T}((4 * v, 4 * u, 0))
dN7 = Vec{3, T}((-4 * v, 4 - 8 * v - 4 * u - 4 * w, -4 * v))
dN8 = Vec{3, T}((-4 * w, -4 * w, 4 - 8 * w - 4 * u - 4 * v))
dN9 = Vec{3, T}((4 * w, 0, 4 * u))
dN10 = Vec{3, T}((0, 4 * w, 4 * v))
return SVector{10, Vec{3, T}}(dN1, dN2, dN3, dN4, dN5, dN6, dN7, dN8, dN9, dN10)
end
# ──────────────────────────────────────────────────────────────────────────────
# Lagrange{1} on Hex8: 8-node trilinear hexahedral element
# (legacy name: Hex8)
@inline function get_basis_functions(::Hex8, ::Lagrange{1}, xi::Vec{3, T}) where T
(u, v, w) = xi
N1 = 1/8 - 1/8 * u - 1/8 * v - 1/8 * w + 1/8 * u * v + 1/8 * u * w + 1/8 * v * w - 1/8 * u * v * w
N2 = 1/8 + 1/8 * u - 1/8 * v - 1/8 * w - 1/8 * u * v - 1/8 * u * w + 1/8 * v * w + 1/8 * u * v * w
N3 = 1/8 + 1/8 * u + 1/8 * v - 1/8 * w + 1/8 * u * v - 1/8 * u * w - 1/8 * v * w - 1/8 * u * v * w
N4 = 1/8 - 1/8 * u + 1/8 * v - 1/8 * w - 1/8 * u * v + 1/8 * u * w - 1/8 * v * w + 1/8 * u * v * w
N5 = 1/8 - 1/8 * u - 1/8 * v + 1/8 * w + 1/8 * u * v - 1/8 * u * w - 1/8 * v * w + 1/8 * u * v * w
N6 = 1/8 + 1/8 * u - 1/8 * v + 1/8 * w - 1/8 * u * v + 1/8 * u * w - 1/8 * v * w - 1/8 * u * v * w
N7 = 1/8 + 1/8 * u + 1/8 * v + 1/8 * w + 1/8 * u * v + 1/8 * u * w + 1/8 * v * w + 1/8 * u * v * w
N8 = 1/8 - 1/8 * u + 1/8 * v + 1/8 * w - 1/8 * u * v - 1/8 * u * w + 1/8 * v * w - 1/8 * u * v * w
return SVector{8, T}(N1, N2, N3, N4, N5, N6, N7, N8)
end
@inline function get_basis_derivatives(::Hex8, ::Lagrange{1}, xi::Vec{3, T}) where T
(u, v, w) = xi
dN1 = Vec{3, T}((-1/8 + 1/8 * v + 1/8 * w - 1/8 * v * w, -1/8 + 1/8 * u + 1/8 * w - 1/8 * u * w, -1/8 + 1/8 * u + 1/8 * v - 1/8 * u * v))
dN2 = Vec{3, T}((1/8 - 1/8 * v - 1/8 * w + 1/8 * v * w, -1/8 - 1/8 * u + 1/8 * w + 1/8 * u * w, -1/8 - 1/8 * u + 1/8 * v + 1/8 * u * v))
dN3 = Vec{3, T}((1/8 + 1/8 * v - 1/8 * w - 1/8 * v * w, 1/8 + 1/8 * u - 1/8 * w - 1/8 * u * w, -1/8 - 1/8 * u - 1/8 * v - 1/8 * u * v))
dN4 = Vec{3, T}((-1/8 - 1/8 * v + 1/8 * w + 1/8 * v * w, 1/8 - 1/8 * u - 1/8 * w + 1/8 * u * w, -1/8 + 1/8 * u - 1/8 * v + 1/8 * u * v))
dN5 = Vec{3, T}((-1/8 + 1/8 * v - 1/8 * w + 1/8 * v * w, -1/8 + 1/8 * u - 1/8 * w + 1/8 * u * w, 1/8 - 1/8 * u - 1/8 * v + 1/8 * u * v))
dN6 = Vec{3, T}((1/8 - 1/8 * v + 1/8 * w - 1/8 * v * w, -1/8 - 1/8 * u - 1/8 * w - 1/8 * u * w, 1/8 + 1/8 * u - 1/8 * v - 1/8 * u * v))
dN7 = Vec{3, T}((1/8 + 1/8 * v + 1/8 * w + 1/8 * v * w, 1/8 + 1/8 * u + 1/8 * w + 1/8 * u * w, 1/8 + 1/8 * u + 1/8 * v + 1/8 * u * v))
dN8 = Vec{3, T}((-1/8 - 1/8 * v - 1/8 * w - 1/8 * v * w, 1/8 - 1/8 * u + 1/8 * w - 1/8 * u * w, 1/8 - 1/8 * u + 1/8 * v - 1/8 * u * v))
return SVector{8, Vec{3, T}}(dN1, dN2, dN3, dN4, dN5, dN6, dN7, dN8)
end
# ──────────────────────────────────────────────────────────────────────────────
# Serendipity{2} on Hex20: 20-node serendipity hexahedral element
# (legacy name: Hex20)
@inline function get_basis_functions(::Hex20, ::Serendipity{2}, xi::Vec{3, T}) where T
(u, v, w) = xi
N1 = -1/4 + 1/8 * u + 1/8 * v + 1/8 * w + 1/12 * u * v + 1/12 * u * w + 1/12 * v * w + 1/8 * u ^ 2 + 1/8 * v ^ 2 + 1/8 * w ^ 2 - 1/8 * u ^ 2 * v - 1/8 * u * v ^ 2 - 1/8 * u ^ 2 * w - 1/8 * u * w ^ 2 - 1/8 * v ^ 2 * w - 1/8 * v * w ^ 2
N2 = -1/4 - 1/8 * u + 1/8 * v + 1/8 * w - 1/12 * u * v - 1/12 * u * w + 1/12 * v * w + 1/8 * u ^ 2 + 1/8 * v ^ 2 + 1/8 * w ^ 2 - 1/8 * u ^ 2 * v + 1/8 * u * v ^ 2 - 1/8 * u ^ 2 * w + 1/8 * u * w ^ 2 - 1/8 * v ^ 2 * w - 1/8 * v * w ^ 2
N3 = -1/4 - 1/8 * u - 1/8 * v + 1/8 * w + 1/12 * u * v - 1/12 * u * w - 1/12 * v * w + 1/8 * u ^ 2 + 1/8 * v ^ 2 + 1/8 * w ^ 2 + 1/8 * u ^ 2 * v + 1/8 * u * v ^ 2 - 1/8 * u ^ 2 * w + 1/8 * u * w ^ 2 - 1/8 * v ^ 2 * w + 1/8 * v * w ^ 2
N4 = -1/4 + 1/8 * u - 1/8 * v + 1/8 * w - 1/12 * u * v + 1/12 * u * w - 1/12 * v * w + 1/8 * u ^ 2 + 1/8 * v ^ 2 + 1/8 * w ^ 2 + 1/8 * u ^ 2 * v - 1/8 * u * v ^ 2 - 1/8 * u ^ 2 * w - 1/8 * u * w ^ 2 - 1/8 * v ^ 2 * w + 1/8 * v * w ^ 2
N5 = -1/4 + 1/8 * u + 1/8 * v - 1/8 * w + 1/12 * u * v - 1/12 * u * w - 1/12 * v * w + 1/8 * u ^ 2 + 1/8 * v ^ 2 + 1/8 * w ^ 2 - 1/8 * u ^ 2 * v - 1/8 * u * v ^ 2 + 1/8 * u ^ 2 * w - 1/8 * u * w ^ 2 + 1/8 * v ^ 2 * w - 1/8 * v * w ^ 2
N6 = -1/4 - 1/8 * u + 1/8 * v - 1/8 * w - 1/12 * u * v + 1/12 * u * w - 1/12 * v * w + 1/8 * u ^ 2 + 1/8 * v ^ 2 + 1/8 * w ^ 2 - 1/8 * u ^ 2 * v + 1/8 * u * v ^ 2 + 1/8 * u ^ 2 * w + 1/8 * u * w ^ 2 + 1/8 * v ^ 2 * w - 1/8 * v * w ^ 2
N7 = -1/4 - 1/8 * u - 1/8 * v - 1/8 * w + 1/12 * u * v + 1/12 * u * w + 1/12 * v * w + 1/8 * u ^ 2 + 1/8 * v ^ 2 + 1/8 * w ^ 2 + 1/8 * u ^ 2 * v + 1/8 * u * v ^ 2 + 1/8 * u ^ 2 * w + 1/8 * u * w ^ 2 + 1/8 * v ^ 2 * w + 1/8 * v * w ^ 2
N8 = -1/4 + 1/8 * u - 1/8 * v - 1/8 * w - 1/12 * u * v - 1/12 * u * w + 1/12 * v * w + 1/8 * u ^ 2 + 1/8 * v ^ 2 + 1/8 * w ^ 2 + 1/8 * u ^ 2 * v - 1/8 * u * v ^ 2 + 1/8 * u ^ 2 * w - 1/8 * u * w ^ 2 + 1/8 * v ^ 2 * w + 1/8 * v * w ^ 2
N9 = 1/4 - 1/4 * v - 1/4 * w + 1/12 * v * w - 1/4 * u ^ 2 + 1/4 * u ^ 2 * v + 1/4 * u ^ 2 * w
N10 = 1/4 + 1/4 * u - 1/4 * w - 1/12 * u * w - 1/4 * v ^ 2 - 1/4 * u * v ^ 2 + 1/4 * v ^ 2 * w
N11 = 1/4 + 1/4 * v - 1/4 * w - 1/12 * v * w - 1/4 * u ^ 2 - 1/4 * u ^ 2 * v + 1/4 * u ^ 2 * w
N12 = 1/4 - 1/4 * u - 1/4 * w + 1/12 * u * w - 1/4 * v ^ 2 + 1/4 * u * v ^ 2 + 1/4 * v ^ 2 * w
N13 = 1/4 - 1/4 * v + 1/4 * w - 1/12 * v * w - 1/4 * u ^ 2 + 1/4 * u ^ 2 * v - 1/4 * u ^ 2 * w
N14 = 1/4 + 1/4 * u + 1/4 * w + 1/12 * u * w - 1/4 * v ^ 2 - 1/4 * u * v ^ 2 - 1/4 * v ^ 2 * w
N15 = 1/4 + 1/4 * v + 1/4 * w + 1/12 * v * w - 1/4 * u ^ 2 - 1/4 * u ^ 2 * v - 1/4 * u ^ 2 * w
N16 = 1/4 - 1/4 * u + 1/4 * w - 1/12 * u * w - 1/4 * v ^ 2 + 1/4 * u * v ^ 2 - 1/4 * v ^ 2 * w
N17 = 1/4 - 1/4 * u - 1/4 * v + 1/12 * u * v - 1/4 * w ^ 2 + 1/4 * u * w ^ 2 + 1/4 * v * w ^ 2
N18 = 1/4 + 1/4 * u - 1/4 * v - 1/12 * u * v - 1/4 * w ^ 2 - 1/4 * u * w ^ 2 + 1/4 * v * w ^ 2
N19 = 1/4 + 1/4 * u + 1/4 * v + 1/12 * u * v - 1/4 * w ^ 2 - 1/4 * u * w ^ 2 - 1/4 * v * w ^ 2
N20 = 1/4 - 1/4 * u + 1/4 * v - 1/12 * u * v - 1/4 * w ^ 2 + 1/4 * u * w ^ 2 - 1/4 * v * w ^ 2
return SVector{20, T}(N1, N2, N3, N4, N5, N6, N7, N8, N9, N10, N11, N12, N13, N14, N15, N16, N17, N18, N19, N20)
end
@inline function get_basis_derivatives(::Hex20, ::Serendipity{2}, xi::Vec{3, T}) where T
(u, v, w) = xi
dN1 = Vec{3, T}((1/8 + 1/12 * v + 1/12 * w + 1/4 * u - 1/4 * u * v - 1/8 * v ^ 2 - 1/4 * u * w - 1/8 * w ^ 2, 1/8 + 1/12 * u + 1/12 * w + 1/4 * v - 1/8 * u ^ 2 - 1/4 * u * v - 1/4 * v * w - 1/8 * w ^ 2, 1/8 + 1/12 * u + 1/12 * v + 1/4 * w - 1/8 * u ^ 2 - 1/4 * u * w - 1/8 * v ^ 2 - 1/4 * v * w))
dN2 = Vec{3, T}((-1/8 - 1/12 * v - 1/12 * w + 1/4 * u - 1/4 * u * v + 1/8 * v ^ 2 - 1/4 * u * w + 1/8 * w ^ 2, 1/8 - 1/12 * u + 1/12 * w + 1/4 * v - 1/8 * u ^ 2 + 1/4 * u * v - 1/4 * v * w - 1/8 * w ^ 2, 1/8 - 1/12 * u + 1/12 * v + 1/4 * w - 1/8 * u ^ 2 + 1/4 * u * w - 1/8 * v ^ 2 - 1/4 * v * w))
dN3 = Vec{3, T}((-1/8 + 1/12 * v - 1/12 * w + 1/4 * u + 1/4 * u * v + 1/8 * v ^ 2 - 1/4 * u * w + 1/8 * w ^ 2, -1/8 + 1/12 * u - 1/12 * w + 1/4 * v + 1/8 * u ^ 2 + 1/4 * u * v - 1/4 * v * w + 1/8 * w ^ 2, 1/8 - 1/12 * u - 1/12 * v + 1/4 * w - 1/8 * u ^ 2 + 1/4 * u * w - 1/8 * v ^ 2 + 1/4 * v * w))
dN4 = Vec{3, T}((1/8 - 1/12 * v + 1/12 * w + 1/4 * u + 1/4 * u * v - 1/8 * v ^ 2 - 1/4 * u * w - 1/8 * w ^ 2, -1/8 - 1/12 * u - 1/12 * w + 1/4 * v + 1/8 * u ^ 2 - 1/4 * u * v - 1/4 * v * w + 1/8 * w ^ 2, 1/8 + 1/12 * u - 1/12 * v + 1/4 * w - 1/8 * u ^ 2 - 1/4 * u * w - 1/8 * v ^ 2 + 1/4 * v * w))
dN5 = Vec{3, T}((1/8 + 1/12 * v - 1/12 * w + 1/4 * u - 1/4 * u * v - 1/8 * v ^ 2 + 1/4 * u * w - 1/8 * w ^ 2, 1/8 + 1/12 * u - 1/12 * w + 1/4 * v - 1/8 * u ^ 2 - 1/4 * u * v + 1/4 * v * w - 1/8 * w ^ 2, -1/8 - 1/12 * u - 1/12 * v + 1/4 * w + 1/8 * u ^ 2 - 1/4 * u * w + 1/8 * v ^ 2 - 1/4 * v * w))
dN6 = Vec{3, T}((-1/8 - 1/12 * v + 1/12 * w + 1/4 * u - 1/4 * u * v + 1/8 * v ^ 2 + 1/4 * u * w + 1/8 * w ^ 2, 1/8 - 1/12 * u - 1/12 * w + 1/4 * v - 1/8 * u ^ 2 + 1/4 * u * v + 1/4 * v * w - 1/8 * w ^ 2, -1/8 + 1/12 * u - 1/12 * v + 1/4 * w + 1/8 * u ^ 2 + 1/4 * u * w + 1/8 * v ^ 2 - 1/4 * v * w))
dN7 = Vec{3, T}((-1/8 + 1/12 * v + 1/12 * w + 1/4 * u + 1/4 * u * v + 1/8 * v ^ 2 + 1/4 * u * w + 1/8 * w ^ 2, -1/8 + 1/12 * u + 1/12 * w + 1/4 * v + 1/8 * u ^ 2 + 1/4 * u * v + 1/4 * v * w + 1/8 * w ^ 2, -1/8 + 1/12 * u + 1/12 * v + 1/4 * w + 1/8 * u ^ 2 + 1/4 * u * w + 1/8 * v ^ 2 + 1/4 * v * w))
dN8 = Vec{3, T}((1/8 - 1/12 * v - 1/12 * w + 1/4 * u + 1/4 * u * v - 1/8 * v ^ 2 + 1/4 * u * w - 1/8 * w ^ 2, -1/8 - 1/12 * u + 1/12 * w + 1/4 * v + 1/8 * u ^ 2 - 1/4 * u * v + 1/4 * v * w + 1/8 * w ^ 2, -1/8 - 1/12 * u + 1/12 * v + 1/4 * w + 1/8 * u ^ 2 - 1/4 * u * w + 1/8 * v ^ 2 + 1/4 * v * w))
dN9 = Vec{3, T}((-1/2 * u + 1/2 * u * v + 1/2 * u * w, -1/4 + 1/12 * w + 1/4 * u ^ 2, -1/4 + 1/12 * v + 1/4 * u ^ 2))
dN10 = Vec{3, T}((1/4 - 1/12 * w - 1/4 * v ^ 2, -1/2 * v - 1/2 * u * v + 1/2 * v * w, -1/4 - 1/12 * u + 1/4 * v ^ 2))
dN11 = Vec{3, T}((-1/2 * u - 1/2 * u * v + 1/2 * u * w, 1/4 - 1/12 * w - 1/4 * u ^ 2, -1/4 - 1/12 * v + 1/4 * u ^ 2))
dN12 = Vec{3, T}((-1/4 + 1/12 * w + 1/4 * v ^ 2, -1/2 * v + 1/2 * u * v + 1/2 * v * w, -1/4 + 1/12 * u + 1/4 * v ^ 2))
dN13 = Vec{3, T}((-1/2 * u + 1/2 * u * v - 1/2 * u * w, -1/4 - 1/12 * w + 1/4 * u ^ 2, 1/4 - 1/12 * v - 1/4 * u ^ 2))
dN14 = Vec{3, T}((1/4 + 1/12 * w - 1/4 * v ^ 2, -1/2 * v - 1/2 * u * v - 1/2 * v * w, 1/4 + 1/12 * u - 1/4 * v ^ 2))
dN15 = Vec{3, T}((-1/2 * u - 1/2 * u * v - 1/2 * u * w, 1/4 + 1/12 * w - 1/4 * u ^ 2, 1/4 + 1/12 * v - 1/4 * u ^ 2))
dN16 = Vec{3, T}((-1/4 - 1/12 * w + 1/4 * v ^ 2, -1/2 * v + 1/2 * u * v - 1/2 * v * w, 1/4 - 1/12 * u - 1/4 * v ^ 2))
dN17 = Vec{3, T}((-1/4 + 1/12 * v + 1/4 * w ^ 2, -1/4 + 1/12 * u + 1/4 * w ^ 2, -1/2 * w + 1/2 * u * w + 1/2 * v * w))
dN18 = Vec{3, T}((1/4 - 1/12 * v - 1/4 * w ^ 2, -1/4 - 1/12 * u + 1/4 * w ^ 2, -1/2 * w - 1/2 * u * w + 1/2 * v * w))
dN19 = Vec{3, T}((1/4 + 1/12 * v - 1/4 * w ^ 2, 1/4 + 1/12 * u - 1/4 * w ^ 2, -1/2 * w - 1/2 * u * w - 1/2 * v * w))
dN20 = Vec{3, T}((-1/4 - 1/12 * v + 1/4 * w ^ 2, 1/4 - 1/12 * u - 1/4 * w ^ 2, -1/2 * w + 1/2 * u * w - 1/2 * v * w))
return SVector{20, Vec{3, T}}(dN1, dN2, dN3, dN4, dN5, dN6, dN7, dN8, dN9, dN10, dN11, dN12, dN13, dN14, dN15, dN16, dN17, dN18, dN19, dN20)
end
# ──────────────────────────────────────────────────────────────────────────────
# Lagrange{2} on Hex27: 27-node triquadratic hexahedral element
# (legacy name: Hex27)
@inline function get_basis_functions(::Hex27, ::Lagrange{2}, xi::Vec{3, T}) where T
(u, v, w) = xi
N1 = 1/18 * u + 1/18 * v + 1/18 * w - 1/12 * u ^ 2 * v - 1/12 * u * v ^ 2 - 1/12 * u ^ 2 * w - 1/12 * u * w ^ 2 - 1/12 * v ^ 2 * w - 1/12 * v * w ^ 2 + 1/8 * u ^ 2 * v * w + 1/8 * u * v ^ 2 * w + 1/8 * u * v * w ^ 2 + 1/8 * u ^ 2 * v ^ 2 * w ^ 2
N2 = -1/18 * u + 1/18 * v + 1/18 * w - 1/12 * u ^ 2 * v + 1/12 * u * v ^ 2 - 1/12 * u ^ 2 * w + 1/12 * u * w ^ 2 - 1/12 * v ^ 2 * w - 1/12 * v * w ^ 2 + 1/8 * u ^ 2 * v * w - 1/8 * u * v ^ 2 * w - 1/8 * u * v * w ^ 2 + 1/8 * u ^ 2 * v ^ 2 * w ^ 2
N3 = -1/18 * u - 1/18 * v + 1/18 * w + 1/12 * u ^ 2 * v + 1/12 * u * v ^ 2 - 1/12 * u ^ 2 * w + 1/12 * u * w ^ 2 - 1/12 * v ^ 2 * w + 1/12 * v * w ^ 2 - 1/8 * u ^ 2 * v * w - 1/8 * u * v ^ 2 * w + 1/8 * u * v * w ^ 2 + 1/8 * u ^ 2 * v ^ 2 * w ^ 2
N4 = 1/18 * u - 1/18 * v + 1/18 * w + 1/12 * u ^ 2 * v - 1/12 * u * v ^ 2 - 1/12 * u ^ 2 * w - 1/12 * u * w ^ 2 - 1/12 * v ^ 2 * w + 1/12 * v * w ^ 2 - 1/8 * u ^ 2 * v * w + 1/8 * u * v ^ 2 * w - 1/8 * u * v * w ^ 2 + 1/8 * u ^ 2 * v ^ 2 * w ^ 2
N5 = 1/18 * u + 1/18 * v - 1/18 * w - 1/12 * u ^ 2 * v - 1/12 * u * v ^ 2 + 1/12 * u ^ 2 * w - 1/12 * u * w ^ 2 + 1/12 * v ^ 2 * w - 1/12 * v * w ^ 2 - 1/8 * u ^ 2 * v * w - 1/8 * u * v ^ 2 * w + 1/8 * u * v * w ^ 2 + 1/8 * u ^ 2 * v ^ 2 * w ^ 2
N6 = -1/18 * u + 1/18 * v - 1/18 * w - 1/12 * u ^ 2 * v + 1/12 * u * v ^ 2 + 1/12 * u ^ 2 * w + 1/12 * u * w ^ 2 + 1/12 * v ^ 2 * w - 1/12 * v * w ^ 2 - 1/8 * u ^ 2 * v * w + 1/8 * u * v ^ 2 * w - 1/8 * u * v * w ^ 2 + 1/8 * u ^ 2 * v ^ 2 * w ^ 2
N7 = -1/18 * u - 1/18 * v - 1/18 * w + 1/12 * u ^ 2 * v + 1/12 * u * v ^ 2 + 1/12 * u ^ 2 * w + 1/12 * u * w ^ 2 + 1/12 * v ^ 2 * w + 1/12 * v * w ^ 2 + 1/8 * u ^ 2 * v * w + 1/8 * u * v ^ 2 * w + 1/8 * u * v * w ^ 2 + 1/8 * u ^ 2 * v ^ 2 * w ^ 2
N8 = 1/18 * u - 1/18 * v - 1/18 * w + 1/12 * u ^ 2 * v - 1/12 * u * v ^ 2 + 1/12 * u ^ 2 * w - 1/12 * u * w ^ 2 + 1/12 * v ^ 2 * w + 1/12 * v * w ^ 2 + 1/8 * u ^ 2 * v * w - 1/8 * u * v ^ 2 * w - 1/8 * u * v * w ^ 2 + 1/8 * u ^ 2 * v ^ 2 * w ^ 2
N9 = -1/9 * v - 1/9 * w + 1/4 * v * w + 1/6 * u ^ 2 * v + 1/6 * u ^ 2 * w - 1/12 * v ^ 2 * w - 1/12 * v * w ^ 2 + 1/4 * v ^ 2 * w ^ 2 - 1/4 * u ^ 2 * v * w - 1/4 * u ^ 2 * v ^ 2 * w ^ 2
N10 = 1/9 * u - 1/9 * w - 1/4 * u * w - 1/6 * u * v ^ 2 - 1/12 * u ^ 2 * w + 1/12 * u * w ^ 2 + 1/6 * v ^ 2 * w + 1/4 * u ^ 2 * w ^ 2 + 1/4 * u * v ^ 2 * w - 1/4 * u ^ 2 * v ^ 2 * w ^ 2
N11 = 1/9 * v - 1/9 * w - 1/4 * v * w - 1/6 * u ^ 2 * v + 1/6 * u ^ 2 * w - 1/12 * v ^ 2 * w + 1/12 * v * w ^ 2 + 1/4 * v ^ 2 * w ^ 2 + 1/4 * u ^ 2 * v * w - 1/4 * u ^ 2 * v ^ 2 * w ^ 2
N12 = -1/9 * u - 1/9 * w + 1/4 * u * w + 1/6 * u * v ^ 2 - 1/12 * u ^ 2 * w - 1/12 * u * w ^ 2 + 1/6 * v ^ 2 * w + 1/4 * u ^ 2 * w ^ 2 - 1/4 * u * v ^ 2 * w - 1/4 * u ^ 2 * v ^ 2 * w ^ 2
N13 = -1/9 * v + 1/9 * w - 1/4 * v * w + 1/6 * u ^ 2 * v - 1/6 * u ^ 2 * w + 1/12 * v ^ 2 * w - 1/12 * v * w ^ 2 + 1/4 * v ^ 2 * w ^ 2 + 1/4 * u ^ 2 * v * w - 1/4 * u ^ 2 * v ^ 2 * w ^ 2
N14 = 1/9 * u + 1/9 * w + 1/4 * u * w - 1/6 * u * v ^ 2 + 1/12 * u ^ 2 * w + 1/12 * u * w ^ 2 - 1/6 * v ^ 2 * w + 1/4 * u ^ 2 * w ^ 2 - 1/4 * u * v ^ 2 * w - 1/4 * u ^ 2 * v ^ 2 * w ^ 2
N15 = 1/9 * v + 1/9 * w + 1/4 * v * w - 1/6 * u ^ 2 * v - 1/6 * u ^ 2 * w + 1/12 * v ^ 2 * w + 1/12 * v * w ^ 2 + 1/4 * v ^ 2 * w ^ 2 - 1/4 * u ^ 2 * v * w - 1/4 * u ^ 2 * v ^ 2 * w ^ 2
N16 = -1/9 * u + 1/9 * w - 1/4 * u * w + 1/6 * u * v ^ 2 + 1/12 * u ^ 2 * w - 1/12 * u * w ^ 2 - 1/6 * v ^ 2 * w + 1/4 * u ^ 2 * w ^ 2 + 1/4 * u * v ^ 2 * w - 1/4 * u ^ 2 * v ^ 2 * w ^ 2
N17 = -1/9 * u - 1/9 * v + 1/4 * u * v - 1/12 * u ^ 2 * v - 1/12 * u * v ^ 2 + 1/6 * u * w ^ 2 + 1/6 * v * w ^ 2 + 1/4 * u ^ 2 * v ^ 2 - 1/4 * u * v * w ^ 2 - 1/4 * u ^ 2 * v ^ 2 * w ^ 2
N18 = 1/9 * u - 1/9 * v - 1/4 * u * v - 1/12 * u ^ 2 * v + 1/12 * u * v ^ 2 - 1/6 * u * w ^ 2 + 1/6 * v * w ^ 2 + 1/4 * u ^ 2 * v ^ 2 + 1/4 * u * v * w ^ 2 - 1/4 * u ^ 2 * v ^ 2 * w ^ 2
N19 = 1/9 * u + 1/9 * v + 1/4 * u * v + 1/12 * u ^ 2 * v + 1/12 * u * v ^ 2 - 1/6 * u * w ^ 2 - 1/6 * v * w ^ 2 + 1/4 * u ^ 2 * v ^ 2 - 1/4 * u * v * w ^ 2 - 1/4 * u ^ 2 * v ^ 2 * w ^ 2
N20 = -1/9 * u + 1/9 * v - 1/4 * u * v + 1/12 * u ^ 2 * v - 1/12 * u * v ^ 2 + 1/6 * u * w ^ 2 - 1/6 * v * w ^ 2 + 1/4 * u ^ 2 * v ^ 2 + 1/4 * u * v * w ^ 2 - 1/4 * u ^ 2 * v ^ 2 * w ^ 2
N21 = -5/18 * w + 1/2 * w ^ 2 + 1/6 * u ^ 2 * w + 1/6 * v ^ 2 * w - 1/2 * u ^ 2 * w ^ 2 - 1/2 * v ^ 2 * w ^ 2 + 1/2 * u ^ 2 * v ^ 2 * w ^ 2
N22 = 5/18 * w + 1/2 * w ^ 2 - 1/6 * u ^ 2 * w - 1/6 * v ^ 2 * w - 1/2 * u ^ 2 * w ^ 2 - 1/2 * v ^ 2 * w ^ 2 + 1/2 * u ^ 2 * v ^ 2 * w ^ 2
N23 = -5/18 * v + 1/2 * v ^ 2 + 1/6 * u ^ 2 * v + 1/6 * v * w ^ 2 - 1/2 * u ^ 2 * v ^ 2 - 1/2 * v ^ 2 * w ^ 2 + 1/2 * u ^ 2 * v ^ 2 * w ^ 2
N24 = 5/18 * v + 1/2 * v ^ 2 - 1/6 * u ^ 2 * v - 1/6 * v * w ^ 2 - 1/2 * u ^ 2 * v ^ 2 - 1/2 * v ^ 2 * w ^ 2 + 1/2 * u ^ 2 * v ^ 2 * w ^ 2
N25 = -5/18 * u + 1/2 * u ^ 2 + 1/6 * u * v ^ 2 + 1/6 * u * w ^ 2 - 1/2 * u ^ 2 * v ^ 2 - 1/2 * u ^ 2 * w ^ 2 + 1/2 * u ^ 2 * v ^ 2 * w ^ 2
N26 = 5/18 * u + 1/2 * u ^ 2 - 1/6 * u * v ^ 2 - 1/6 * u * w ^ 2 - 1/2 * u ^ 2 * v ^ 2 - 1/2 * u ^ 2 * w ^ 2 + 1/2 * u ^ 2 * v ^ 2 * w ^ 2
N27 = 1 - u ^ 2 - v ^ 2 - w ^ 2 + u ^ 2 * v ^ 2 + u ^ 2 * w ^ 2 + v ^ 2 * w ^ 2 - u ^ 2 * v ^ 2 * w ^ 2
return SVector{27, T}(N1, N2, N3, N4, N5, N6, N7, N8, N9, N10, N11, N12, N13, N14, N15, N16, N17, N18, N19, N20, N21, N22, N23, N24, N25, N26, N27)
end
@inline function get_basis_derivatives(::Hex27, ::Lagrange{2}, xi::Vec{3, T}) where T
(u, v, w) = xi
dN1 = Vec{3, T}((1/18 - 1/6 * u * v - 1/12 * v ^ 2 - 1/6 * u * w - 1/12 * w ^ 2 + 1/4 * u * v * w + 1/8 * v ^ 2 * w + 1/8 * v * w ^ 2 + 1/4 * u * v ^ 2 * w ^ 2, 1/18 - 1/12 * u ^ 2 - 1/6 * u * v - 1/6 * v * w - 1/12 * w ^ 2 + 1/8 * u ^ 2 * w + 1/4 * u * v * w + 1/8 * u * w ^ 2 + 1/4 * u ^ 2 * v * w ^ 2, 1/18 - 1/12 * u ^ 2 - 1/6 * u * w - 1/12 * v ^ 2 - 1/6 * v * w + 1/8 * u ^ 2 * v + 1/8 * u * v ^ 2 + 1/4 * u * v * w + 1/4 * u ^ 2 * v ^ 2 * w))
dN2 = Vec{3, T}((-1/18 - 1/6 * u * v + 1/12 * v ^ 2 - 1/6 * u * w + 1/12 * w ^ 2 + 1/4 * u * v * w - 1/8 * v ^ 2 * w - 1/8 * v * w ^ 2 + 1/4 * u * v ^ 2 * w ^ 2, 1/18 - 1/12 * u ^ 2 + 1/6 * u * v - 1/6 * v * w - 1/12 * w ^ 2 + 1/8 * u ^ 2 * w - 1/4 * u * v * w - 1/8 * u * w ^ 2 + 1/4 * u ^ 2 * v * w ^ 2, 1/18 - 1/12 * u ^ 2 + 1/6 * u * w - 1/12 * v ^ 2 - 1/6 * v * w + 1/8 * u ^ 2 * v - 1/8 * u * v ^ 2 - 1/4 * u * v * w + 1/4 * u ^ 2 * v ^ 2 * w))
dN3 = Vec{3, T}((-1/18 + 1/6 * u * v + 1/12 * v ^ 2 - 1/6 * u * w + 1/12 * w ^ 2 - 1/4 * u * v * w - 1/8 * v ^ 2 * w + 1/8 * v * w ^ 2 + 1/4 * u * v ^ 2 * w ^ 2, -1/18 + 1/12 * u ^ 2 + 1/6 * u * v - 1/6 * v * w + 1/12 * w ^ 2 - 1/8 * u ^ 2 * w - 1/4 * u * v * w + 1/8 * u * w ^ 2 + 1/4 * u ^ 2 * v * w ^ 2, 1/18 - 1/12 * u ^ 2 + 1/6 * u * w - 1/12 * v ^ 2 + 1/6 * v * w - 1/8 * u ^ 2 * v - 1/8 * u * v ^ 2 + 1/4 * u * v * w + 1/4 * u ^ 2 * v ^ 2 * w))
dN4 = Vec{3, T}((1/18 + 1/6 * u * v - 1/12 * v ^ 2 - 1/6 * u * w - 1/12 * w ^ 2 - 1/4 * u * v * w + 1/8 * v ^ 2 * w - 1/8 * v * w ^ 2 + 1/4 * u * v ^ 2 * w ^ 2, -1/18 + 1/12 * u ^ 2 - 1/6 * u * v - 1/6 * v * w + 1/12 * w ^ 2 - 1/8 * u ^ 2 * w + 1/4 * u * v * w - 1/8 * u * w ^ 2 + 1/4 * u ^ 2 * v * w ^ 2, 1/18 - 1/12 * u ^ 2 - 1/6 * u * w - 1/12 * v ^ 2 + 1/6 * v * w - 1/8 * u ^ 2 * v + 1/8 * u * v ^ 2 - 1/4 * u * v * w + 1/4 * u ^ 2 * v ^ 2 * w))
dN5 = Vec{3, T}((1/18 - 1/6 * u * v - 1/12 * v ^ 2 + 1/6 * u * w - 1/12 * w ^ 2 - 1/4 * u * v * w - 1/8 * v ^ 2 * w + 1/8 * v * w ^ 2 + 1/4 * u * v ^ 2 * w ^ 2, 1/18 - 1/12 * u ^ 2 - 1/6 * u * v + 1/6 * v * w - 1/12 * w ^ 2 - 1/8 * u ^ 2 * w - 1/4 * u * v * w + 1/8 * u * w ^ 2 + 1/4 * u ^ 2 * v * w ^ 2, -1/18 + 1/12 * u ^ 2 - 1/6 * u * w + 1/12 * v ^ 2 - 1/6 * v * w - 1/8 * u ^ 2 * v - 1/8 * u * v ^ 2 + 1/4 * u * v * w + 1/4 * u ^ 2 * v ^ 2 * w))
dN6 = Vec{3, T}((-1/18 - 1/6 * u * v + 1/12 * v ^ 2 + 1/6 * u * w + 1/12 * w ^ 2 - 1/4 * u * v * w + 1/8 * v ^ 2 * w - 1/8 * v * w ^ 2 + 1/4 * u * v ^ 2 * w ^ 2, 1/18 - 1/12 * u ^ 2 + 1/6 * u * v + 1/6 * v * w - 1/12 * w ^ 2 - 1/8 * u ^ 2 * w + 1/4 * u * v * w - 1/8 * u * w ^ 2 + 1/4 * u ^ 2 * v * w ^ 2, -1/18 + 1/12 * u ^ 2 + 1/6 * u * w + 1/12 * v ^ 2 - 1/6 * v * w - 1/8 * u ^ 2 * v + 1/8 * u * v ^ 2 - 1/4 * u * v * w + 1/4 * u ^ 2 * v ^ 2 * w))
dN7 = Vec{3, T}((-1/18 + 1/6 * u * v + 1/12 * v ^ 2 + 1/6 * u * w + 1/12 * w ^ 2 + 1/4 * u * v * w + 1/8 * v ^ 2 * w + 1/8 * v * w ^ 2 + 1/4 * u * v ^ 2 * w ^ 2, -1/18 + 1/12 * u ^ 2 + 1/6 * u * v + 1/6 * v * w + 1/12 * w ^ 2 + 1/8 * u ^ 2 * w + 1/4 * u * v * w + 1/8 * u * w ^ 2 + 1/4 * u ^ 2 * v * w ^ 2, -1/18 + 1/12 * u ^ 2 + 1/6 * u * w + 1/12 * v ^ 2 + 1/6 * v * w + 1/8 * u ^ 2 * v + 1/8 * u * v ^ 2 + 1/4 * u * v * w + 1/4 * u ^ 2 * v ^ 2 * w))
dN8 = Vec{3, T}((1/18 + 1/6 * u * v - 1/12 * v ^ 2 + 1/6 * u * w - 1/12 * w ^ 2 + 1/4 * u * v * w - 1/8 * v ^ 2 * w - 1/8 * v * w ^ 2 + 1/4 * u * v ^ 2 * w ^ 2, -1/18 + 1/12 * u ^ 2 - 1/6 * u * v + 1/6 * v * w + 1/12 * w ^ 2 + 1/8 * u ^ 2 * w - 1/4 * u * v * w - 1/8 * u * w ^ 2 + 1/4 * u ^ 2 * v * w ^ 2, -1/18 + 1/12 * u ^ 2 - 1/6 * u * w + 1/12 * v ^ 2 + 1/6 * v * w + 1/8 * u ^ 2 * v - 1/8 * u * v ^ 2 - 1/4 * u * v * w + 1/4 * u ^ 2 * v ^ 2 * w))
dN9 = Vec{3, T}((1/3 * u * v + 1/3 * u * w - 1/2 * u * v * w - 1/2 * u * v ^ 2 * w ^ 2, -1/9 + 1/4 * w + 1/6 * u ^ 2 - 1/6 * v * w - 1/12 * w ^ 2 + 1/2 * v * w ^ 2 - 1/4 * u ^ 2 * w - 1/2 * u ^ 2 * v * w ^ 2, -1/9 + 1/4 * v + 1/6 * u ^ 2 - 1/12 * v ^ 2 - 1/6 * v * w + 1/2 * v ^ 2 * w - 1/4 * u ^ 2 * v - 1/2 * u ^ 2 * v ^ 2 * w))
dN10 = Vec{3, T}((1/9 - 1/4 * w - 1/6 * v ^ 2 - 1/6 * u * w + 1/12 * w ^ 2 + 1/2 * u * w ^ 2 + 1/4 * v ^ 2 * w - 1/2 * u * v ^ 2 * w ^ 2, -1/3 * u * v + 1/3 * v * w + 1/2 * u * v * w - 1/2 * u ^ 2 * v * w ^ 2, -1/9 - 1/4 * u - 1/12 * u ^ 2 + 1/6 * u * w + 1/6 * v ^ 2 + 1/2 * u ^ 2 * w + 1/4 * u * v ^ 2 - 1/2 * u ^ 2 * v ^ 2 * w))
dN11 = Vec{3, T}((-1/3 * u * v + 1/3 * u * w + 1/2 * u * v * w - 1/2 * u * v ^ 2 * w ^ 2, 1/9 - 1/4 * w - 1/6 * u ^ 2 - 1/6 * v * w + 1/12 * w ^ 2 + 1/2 * v * w ^ 2 + 1/4 * u ^ 2 * w - 1/2 * u ^ 2 * v * w ^ 2, -1/9 - 1/4 * v + 1/6 * u ^ 2 - 1/12 * v ^ 2 + 1/6 * v * w + 1/2 * v ^ 2 * w + 1/4 * u ^ 2 * v - 1/2 * u ^ 2 * v ^ 2 * w))
dN12 = Vec{3, T}((-1/9 + 1/4 * w + 1/6 * v ^ 2 - 1/6 * u * w - 1/12 * w ^ 2 + 1/2 * u * w ^ 2 - 1/4 * v ^ 2 * w - 1/2 * u * v ^ 2 * w ^ 2, 1/3 * u * v + 1/3 * v * w - 1/2 * u * v * w - 1/2 * u ^ 2 * v * w ^ 2, -1/9 + 1/4 * u - 1/12 * u ^ 2 - 1/6 * u * w + 1/6 * v ^ 2 + 1/2 * u ^ 2 * w - 1/4 * u * v ^ 2 - 1/2 * u ^ 2 * v ^ 2 * w))
dN13 = Vec{3, T}((1/3 * u * v - 1/3 * u * w + 1/2 * u * v * w - 1/2 * u * v ^ 2 * w ^ 2, -1/9 - 1/4 * w + 1/6 * u ^ 2 + 1/6 * v * w - 1/12 * w ^ 2 + 1/2 * v * w ^ 2 + 1/4 * u ^ 2 * w - 1/2 * u ^ 2 * v * w ^ 2, 1/9 - 1/4 * v - 1/6 * u ^ 2 + 1/12 * v ^ 2 - 1/6 * v * w + 1/2 * v ^ 2 * w + 1/4 * u ^ 2 * v - 1/2 * u ^ 2 * v ^ 2 * w))
dN14 = Vec{3, T}((1/9 + 1/4 * w - 1/6 * v ^ 2 + 1/6 * u * w + 1/12 * w ^ 2 + 1/2 * u * w ^ 2 - 1/4 * v ^ 2 * w - 1/2 * u * v ^ 2 * w ^ 2, -1/3 * u * v - 1/3 * v * w - 1/2 * u * v * w - 1/2 * u ^ 2 * v * w ^ 2, 1/9 + 1/4 * u + 1/12 * u ^ 2 + 1/6 * u * w - 1/6 * v ^ 2 + 1/2 * u ^ 2 * w - 1/4 * u * v ^ 2 - 1/2 * u ^ 2 * v ^ 2 * w))
dN15 = Vec{3, T}((-1/3 * u * v - 1/3 * u * w - 1/2 * u * v * w - 1/2 * u * v ^ 2 * w ^ 2, 1/9 + 1/4 * w - 1/6 * u ^ 2 + 1/6 * v * w + 1/12 * w ^ 2 + 1/2 * v * w ^ 2 - 1/4 * u ^ 2 * w - 1/2 * u ^ 2 * v * w ^ 2, 1/9 + 1/4 * v - 1/6 * u ^ 2 + 1/12 * v ^ 2 + 1/6 * v * w + 1/2 * v ^ 2 * w - 1/4 * u ^ 2 * v - 1/2 * u ^ 2 * v ^ 2 * w))
dN16 = Vec{3, T}((-1/9 - 1/4 * w + 1/6 * v ^ 2 + 1/6 * u * w - 1/12 * w ^ 2 + 1/2 * u * w ^ 2 + 1/4 * v ^ 2 * w - 1/2 * u * v ^ 2 * w ^ 2, 1/3 * u * v - 1/3 * v * w + 1/2 * u * v * w - 1/2 * u ^ 2 * v * w ^ 2, 1/9 - 1/4 * u + 1/12 * u ^ 2 - 1/6 * u * w - 1/6 * v ^ 2 + 1/2 * u ^ 2 * w + 1/4 * u * v ^ 2 - 1/2 * u ^ 2 * v ^ 2 * w))
dN17 = Vec{3, T}((-1/9 + 1/4 * v - 1/6 * u * v - 1/12 * v ^ 2 + 1/6 * w ^ 2 + 1/2 * u * v ^ 2 - 1/4 * v * w ^ 2 - 1/2 * u * v ^ 2 * w ^ 2, -1/9 + 1/4 * u - 1/12 * u ^ 2 - 1/6 * u * v + 1/6 * w ^ 2 + 1/2 * u ^ 2 * v - 1/4 * u * w ^ 2 - 1/2 * u ^ 2 * v * w ^ 2, 1/3 * u * w + 1/3 * v * w - 1/2 * u * v * w - 1/2 * u ^ 2 * v ^ 2 * w))
dN18 = Vec{3, T}((1/9 - 1/4 * v - 1/6 * u * v + 1/12 * v ^ 2 - 1/6 * w ^ 2 + 1/2 * u * v ^ 2 + 1/4 * v * w ^ 2 - 1/2 * u * v ^ 2 * w ^ 2, -1/9 - 1/4 * u - 1/12 * u ^ 2 + 1/6 * u * v + 1/6 * w ^ 2 + 1/2 * u ^ 2 * v + 1/4 * u * w ^ 2 - 1/2 * u ^ 2 * v * w ^ 2, -1/3 * u * w + 1/3 * v * w + 1/2 * u * v * w - 1/2 * u ^ 2 * v ^ 2 * w))
dN19 = Vec{3, T}((1/9 + 1/4 * v + 1/6 * u * v + 1/12 * v ^ 2 - 1/6 * w ^ 2 + 1/2 * u * v ^ 2 - 1/4 * v * w ^ 2 - 1/2 * u * v ^ 2 * w ^ 2, 1/9 + 1/4 * u + 1/12 * u ^ 2 + 1/6 * u * v - 1/6 * w ^ 2 + 1/2 * u ^ 2 * v - 1/4 * u * w ^ 2 - 1/2 * u ^ 2 * v * w ^ 2, -1/3 * u * w - 1/3 * v * w - 1/2 * u * v * w - 1/2 * u ^ 2 * v ^ 2 * w))
dN20 = Vec{3, T}((-1/9 - 1/4 * v + 1/6 * u * v - 1/12 * v ^ 2 + 1/6 * w ^ 2 + 1/2 * u * v ^ 2 + 1/4 * v * w ^ 2 - 1/2 * u * v ^ 2 * w ^ 2, 1/9 - 1/4 * u + 1/12 * u ^ 2 - 1/6 * u * v - 1/6 * w ^ 2 + 1/2 * u ^ 2 * v + 1/4 * u * w ^ 2 - 1/2 * u ^ 2 * v * w ^ 2, 1/3 * u * w - 1/3 * v * w + 1/2 * u * v * w - 1/2 * u ^ 2 * v ^ 2 * w))
dN21 = Vec{3, T}((1/3 * u * w - u * w ^ 2 + u * v ^ 2 * w ^ 2, 1/3 * v * w - v * w ^ 2 + u ^ 2 * v * w ^ 2, -5/18 + w + 1/6 * u ^ 2 + 1/6 * v ^ 2 - u ^ 2 * w - v ^ 2 * w + u ^ 2 * v ^ 2 * w))
dN22 = Vec{3, T}((-1/3 * u * w - u * w ^ 2 + u * v ^ 2 * w ^ 2, -1/3 * v * w - v * w ^ 2 + u ^ 2 * v * w ^ 2, 5/18 + w - 1/6 * u ^ 2 - 1/6 * v ^ 2 - u ^ 2 * w - v ^ 2 * w + u ^ 2 * v ^ 2 * w))
dN23 = Vec{3, T}((1/3 * u * v - u * v ^ 2 + u * v ^ 2 * w ^ 2, -5/18 + v + 1/6 * u ^ 2 + 1/6 * w ^ 2 - u ^ 2 * v - v * w ^ 2 + u ^ 2 * v * w ^ 2, 1/3 * v * w - v ^ 2 * w + u ^ 2 * v ^ 2 * w))
dN24 = Vec{3, T}((-1/3 * u * v - u * v ^ 2 + u * v ^ 2 * w ^ 2, 5/18 + v - 1/6 * u ^ 2 - 1/6 * w ^ 2 - u ^ 2 * v - v * w ^ 2 + u ^ 2 * v * w ^ 2, -1/3 * v * w - v ^ 2 * w + u ^ 2 * v ^ 2 * w))
dN25 = Vec{3, T}((-5/18 + u + 1/6 * v ^ 2 + 1/6 * w ^ 2 - u * v ^ 2 - u * w ^ 2 + u * v ^ 2 * w ^ 2, 1/3 * u * v - u ^ 2 * v + u ^ 2 * v * w ^ 2, 1/3 * u * w - u ^ 2 * w + u ^ 2 * v ^ 2 * w))
dN26 = Vec{3, T}((5/18 + u - 1/6 * v ^ 2 - 1/6 * w ^ 2 - u * v ^ 2 - u * w ^ 2 + u * v ^ 2 * w ^ 2, -1/3 * u * v - u ^ 2 * v + u ^ 2 * v * w ^ 2, -1/3 * u * w - u ^ 2 * w + u ^ 2 * v ^ 2 * w))
dN27 = Vec{3, T}((-2 * u + 2 * u * v ^ 2 + 2 * u * w ^ 2 - 2 * u * v ^ 2 * w ^ 2, -2 * v + 2 * u ^ 2 * v + 2 * v * w ^ 2 - 2 * u ^ 2 * v * w ^ 2, -2 * w + 2 * u ^ 2 * w + 2 * v ^ 2 * w - 2 * u ^ 2 * v ^ 2 * w))
return SVector{27, Vec{3, T}}(dN1, dN2, dN3, dN4, dN5, dN6, dN7, dN8, dN9, dN10, dN11, dN12, dN13, dN14, dN15, dN16, dN17, dN18, dN19, dN20, dN21, dN22, dN23, dN24, dN25, dN26, dN27)
end
# ──────────────────────────────────────────────────────────────────────────────
# Lagrange{1} on Pyr5: 5-node linear pyramid element
# (legacy name: Pyr5)
@inline function get_basis_functions(::Pyr5, ::Lagrange{1}, xi::Vec{3, T}) where T
(u, v, w) = xi
N1 = 1/4 - 1/4 * u - 1/4 * v - 1/4 * w
N2 = 1/4 + 1/4 * u - 1/4 * v - 1/4 * w
N3 = 1/4 + 1/4 * u + 1/4 * v - 1/4 * w
N4 = 1/4 - 1/4 * u + 1/4 * v - 1/4 * w
N5 = w
return SVector{5, T}(N1, N2, N3, N4, N5)
end
@inline function get_basis_derivatives(::Pyr5, ::Lagrange{1}, xi::Vec{3, T}) where T
(u, v, w) = xi
dN1 = Vec{3, T}((-1/4, -1/4, -1/4))
dN2 = Vec{3, T}((1/4, -1/4, -1/4))
dN3 = Vec{3, T}((1/4, 1/4, -1/4))
dN4 = Vec{3, T}((-1/4, 1/4, -1/4))
dN5 = Vec{3, T}((0, 0, 1))
return SVector{5, Vec{3, T}}(dN1, dN2, dN3, dN4, dN5)
end
# ──────────────────────────────────────────────────────────────────────────────
# Lagrange{1} on Wedge6: 6-node linear wedge (prism) element
# (legacy name: Wedge6)
@inline function get_basis_functions(::Wedge6, ::Lagrange{1}, xi::Vec{3, T}) where T
(u, v, w) = xi
N1 = 1/2 - 1/2 * u - 1/2 * v - 1/2 * w + 1/2 * u * w + 1/2 * v * w
N2 = 1/2 * u - 1/2 * u * w
N3 = 1/2 * v - 1/2 * v * w
N4 = 1/2 - 1/2 * u - 1/2 * v + 1/2 * w - 1/2 * u * w - 1/2 * v * w
N5 = 1/2 * u + 1/2 * u * w
N6 = 1/2 * v + 1/2 * v * w
return SVector{6, T}(N1, N2, N3, N4, N5, N6)
end
@inline function get_basis_derivatives(::Wedge6, ::Lagrange{1}, xi::Vec{3, T}) where T
(u, v, w) = xi
dN1 = Vec{3, T}((-1/2 + 1/2 * w, -1/2 + 1/2 * w, -1/2 + 1/2 * u + 1/2 * v))
dN2 = Vec{3, T}((1/2 - 1/2 * w, 0, -1/2 * u))
dN3 = Vec{3, T}((0, 1/2 - 1/2 * w, -1/2 * v))
dN4 = Vec{3, T}((-1/2 - 1/2 * w, -1/2 - 1/2 * w, 1/2 - 1/2 * u - 1/2 * v))
dN5 = Vec{3, T}((1/2 + 1/2 * w, 0, 1/2 * u))
dN6 = Vec{3, T}((0, 1/2 + 1/2 * w, 1/2 * v))
return SVector{6, Vec{3, T}}(dN1, dN2, dN3, dN4, dN5, dN6)
end