diff --git a/src/topology/hexahedra.jl b/src/topology/hexahedra.jl index f8a88fa..ea90af4 100644 --- a/src/topology/hexahedra.jl +++ b/src/topology/hexahedra.jl @@ -2,189 +2,47 @@ # License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE """ - Hexahedron <: AbstractTopology + Hexahedron{N} <: AbstractTopology{N} -Hexahedral element topology (3D tensor product). +Hexahedral (brick) topology with N nodes. -**Important:** This type defines ONLY the geometric shape. Node count is determined -by the interpolation scheme (basis functions): -- `Lagrange{Hexahedron, 1}` → 8 nodes (Q1, trilinear) -- `Serendipity{Hexahedron, 2}` → 20 nodes (Q2, no interior nodes) -- `Lagrange{Hexahedron, 2}` → 27 nodes (Q2, full tensor product) - -# Reference Element -``` - N8-------N7 - /| /| - / | / | - N5-------N6 | - | N4----|--N3 - | / | / - |/ |/ - N1-------N2 -``` - -# Standard Corner Node Positions (in [-1,1]³) -1. (-1, -1, -1) -2. ( 1, -1, -1) -3. ( 1, 1, -1) -4. (-1, 1, -1) -5. (-1, -1, 1) -6. ( 1, -1, 1) -7. ( 1, 1, 1) -8. (-1, 1, 1) - -# Topology Properties -- Dimension: 3 -- Corner nodes: 8 -- Edges: 12 -- Faces: 6 (quadrilateral) - -# Typical Usage -```julia -julia> topology = Hexahedron() -julia> dim(topology) -3 -julia> reference_coordinates(topology) # Corner nodes only -((-1.0, -1.0, -1.0), (1.0, -1.0, -1.0), ...) - -julia> basis = Lagrange{Hexahedron, 1}() -julia> nnodes(basis) # Trilinear: 8 nodes -8 - -julia> basis = Serendipity{Hexahedron, 2}() -julia> nnodes(basis) # Serendipity: 20 nodes (no interior) -20 - -julia> basis = Lagrange{Hexahedron, 2}() -julia> nnodes(basis) # Full Lagrange: 27 nodes (with interior) -27 -``` - -**Zero allocation:** All functions return compile-time sized tuples. - -See also: [`AbstractTopology`](@ref), [`Tetrahedron`](@ref), [`Lagrange`](@ref), [`Serendipity`](@ref) +# Node Count Variants +- `Hexahedron{8}` (alias `Hex8`): Linear hexahedron (P1 Lagrange) +- `Hexahedron{20}` (alias `Hex20`): Quadratic serendipity hexahedron (P2, no center nodes) +- `Hexahedron{27}` (alias `Hex27`): Quadratic full hexahedron (P2, includes center nodes) """ -struct Hexahedron <: AbstractTopology end +struct Hexahedron{N} <: AbstractTopology{N} end -dim(::Hexahedron) = 3 +const Hex8 = Hexahedron{8} +const Hex20 = Hexahedron{20} +const Hex27 = Hexahedron{27} -""" - reference_coordinates(::Hexahedron) +nnodes(::Hexahedron{N}) where {N} = N +dim(::Hexahedron{N}) where {N} = 3 -Get corner node positions for Hexahedron (8 vertices in [-1,1]³). -""" -function reference_coordinates(::Hexahedron) +function reference_coordinates(::Hexahedron{8}) return ( - (-1.0, -1.0, -1.0), # Node 1 - (1.0, -1.0, -1.0), # Node 2 - (1.0, 1.0, -1.0), # Node 3 - (-1.0, 1.0, -1.0), # Node 4 - (-1.0, -1.0, 1.0), # Node 5 - (1.0, -1.0, 1.0), # Node 6 - (1.0, 1.0, 1.0), # Node 7 - (-1.0, 1.0, 1.0), # Node 8 + (-1.0, -1.0, -1.0), (1.0, -1.0, -1.0), + (1.0, 1.0, -1.0), (-1.0, 1.0, -1.0), + (-1.0, -1.0, 1.0), (1.0, -1.0, 1.0), + (1.0, 1.0, 1.0), (-1.0, 1.0, 1.0) ) end -""" - edges(::Hexahedron) - -Edge connectivity for hexahedron (corner nodes). -""" -function edges(::Hexahedron) +function edges(::Hexahedron{N}) where {N} return ( - (1, 2), (2, 3), (3, 4), (4, 1), # Bottom face edges - (5, 6), (6, 7), (7, 8), (8, 5), # Top face edges - (1, 5), (2, 6), (3, 7), (4, 8), # Vertical edges + (1, 2), (2, 3), (3, 4), (4, 1), + (5, 6), (6, 7), (7, 8), (8, 5), + (1, 5), (2, 6), (3, 7), (4, 8) ) end -""" - faces(::Hexahedron) - -Face connectivity for hexahedron (quadrilateral faces, corner nodes). -""" -function faces(::Hexahedron) +function faces(::Hexahedron{N}) where {N} return ( - (1, 4, 3, 2), # Face 1: Bottom (-z) - (1, 2, 6, 5), # Face 2: Front (-y) - (2, 3, 7, 6), # Face 3: Right (+x) - (3, 4, 8, 7), # Face 4: Back (+y) - (4, 1, 5, 8), # Face 5: Left (-x) - (5, 6, 7, 8), # Face 6: Top (+z) + (1, 4, 3, 2), (5, 6, 7, 8), + (1, 2, 6, 5), (2, 3, 7, 6), + (3, 4, 8, 7), (4, 1, 5, 8) ) end -# ============================================================================ -# Deprecated aliases (for backwards compatibility) -# ============================================================================ - -""" - Hex8 - -**DEPRECATED:** Backward compatibility alias. Use `Hexahedron` with `Lagrange{Hexahedron, 1}`. - -The old `Hex8` conflated topology (hexahedron) with node count (8). -In the new architecture: -- Topology defines geometric shape only -- Basis functions determine node count - -This alias allows old code to work: -```julia -# Old style (still works) -element = Element(Hex8, (1, 2, 3, 4, 5, 6, 7, 8)) -# Internally converted to: -element = Element(Hexahedron, (1, 2, 3, 4, 5, 6, 7, 8)) # Infers Lagrange{Hexahedron, 1} -``` - -New code should use explicit topology + basis: -```julia -element = Element(Lagrange{Hexahedron, 1}, (1, 2, 3, 4, 5, 6, 7, 8)) -``` -""" -const Hex8 = Hexahedron - -""" - Hex20 - -**DEPRECATED:** Backward compatibility alias. Use `Hexahedron` with `Serendipity{Hexahedron, 2}`. - -20-node hexahedron with serendipity basis (NO interior nodes). - -This alias allows old code to work: -```julia -# Old style (still works) -element = Element(Hex20, (1, 2, ..., 20)) -# Internally converted to: -element = Element(Hexahedron, (1, 2, ..., 20)) # Infers Serendipity -``` - -New code should be explicit about basis family: -```julia -element = Element(Serendipity{Hexahedron, 2}, (1, 2, ..., 20)) -``` -""" -const Hex20 = Hexahedron # Same topology! Basis determines node pattern. - -""" - Hex27 - -**DEPRECATED:** Backward compatibility alias. Use `Hexahedron` with `Lagrange{Hexahedron, 2}`. - -27-node hexahedron with full tensor product basis (WITH interior nodes). - -This alias allows old code to work: -```julia -# Old style (still works) -element = Element(Hex27, (1, 2, ..., 27)) -# Internally converted to: -element = Element(Hexahedron, (1, 2, ..., 27)) # Infers Lagrange -``` - -New code should be explicit: -```julia -element = Element(Lagrange{Hexahedron, 2}, (1, 2, ..., 27)) -``` -""" -const Hex27 = Hexahedron # Same topology! Basis determines node pattern. +export Hex8, Hex20, Hex27