From d18622d41c2f1781178d691009e0a33a88104fa7 Mon Sep 17 00:00:00 2001 From: Jukka Aho Date: Sun, 9 Nov 2025 05:58:34 +0200 Subject: [PATCH] feat(topology): Complete topology library with all element types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Implemented 14 additional topology types with zero-allocation interfaces** This completes the topology module with all standard FEM element types from 1D to 3D, both linear and quadratic variants. ## New Topologies ### 1D Elements (Segments) - Seg2: 2-node linear segment - Seg3: 3-node quadratic segment ### 2D Elements **Triangles:** - Tri6: 6-node quadratic triangle - Tri7: 7-node quadratic triangle (with center node) **Quadrilaterals:** - Quad8: 8-node quadratic quad (Serendipity) - Quad9: 9-node quadratic quad (with center node) ### 3D Elements **Tetrahedra:** - Tet4: 4-node linear tetrahedron - Tet10: 10-node quadratic tetrahedron **Hexahedra:** - Hex8: 8-node linear hexahedron - Hex20: 20-node biquadratic hexahedron (Serendipity) - Hex27: 27-node quadratic hexahedron (with face/volume nodes) **Pyramids:** - Pyr5: 5-node linear pyramid **Wedges/Prisms:** - Wedge6: 6-node linear wedge - Wedge15: 15-node quadratic wedge ## Design Principles **Zero-allocation throughout:** - reference_coordinates() → NTuple{N, NTuple{D, Float64}} - edges() → NTuple{Ne, Tuple{Int, Int}} - faces() → NTuple{Nf, NTuple{Nn, Int}} or NTuple{Nf, Tuple{Vararg{Int}}} All topology data is stack-allocated, compile-time sized tuples. No heap allocations in hot assembly loops. **Reference coordinates extracted from existing basis files:** - src/basis/lagrange_segments.jl - src/basis/lagrange_triangles.jl - src/basis/lagrange_quadrangles.jl - src/basis/lagrange_tetrahedrons.jl - src/basis/lagrange_hexahedrons.jl - src/basis/lagrange_pyramids.jl - src/basis/lagrange_wedges.jl **Complete topology coverage:** - 1D: linear and quadratic segments - 2D: triangles (3,6,7 nodes), quads (4,8,9 nodes) - 3D: tets (4,10), hexes (8,20,27), pyramids (5), wedges (6,15) This matches the rich set of elements JuliaFEM supported historically. ## Implementation Notes **Edge/Face Connectivity:** - edges(): Corner nodes only (defines element boundary) - faces(): For 2D elements, all nodes; for 3D elements, corner nodes of each face - Consistent with standard FEM conventions **Pyramid Special Case:** - Pyr5 uses Code Aster convention (from lagrange_pyramids.jl) - Base at z=-1, apex at z=+1 - Mixed face types: 1 quad base + 4 triangular faces **Wedge/Prism Special Case:** - Triangular cross-section extruded along w-axis - Mixed face types: 2 triangular + 3 quadrilateral faces ## Status Total topology types: 17 (Seg2, Seg3, Tri3, Tri6, Tri7, Quad4, Quad8, Quad9, Tet4, Tet10, Hex8, Hex20, Hex27, Pyr5, Wedge6, Wedge15) **Not yet integrated** into src/JuliaFEM.jl (staged approach). ## Next Steps 1. Update topology.jl to export all types 2. Update src/JuliaFEM.jl to include all topology files 3. Add integration rules for all topologies in src/integration/gauss.jl 4. Generate Lagrange basis functions for all topologies ## References - Existing basis files in src/basis/ (reference coordinate source) - Abaqus Theory Manual (standard element definitions) - Code Aster documentation (pyramid element convention) - TECHNICAL_VISION.md (zero-allocation design philosophy) --- src/topology/hex20.jl | 92 ++++++++++++++++++++++++++++++++++++ src/topology/hex27.jl | 101 ++++++++++++++++++++++++++++++++++++++++ src/topology/hex8.jl | 75 +++++++++++++++++++++++++++++ src/topology/pyr5.jl | 81 ++++++++++++++++++++++++++++++++ src/topology/quad8.jl | 64 +++++++++++++++++++++++++ src/topology/quad9.jl | 65 ++++++++++++++++++++++++++ src/topology/seg2.jl | 49 +++++++++++++++++++ src/topology/seg3.jl | 49 +++++++++++++++++++ src/topology/tet10.jl | 82 ++++++++++++++++++++++++++++++++ src/topology/tet4.jl | 74 +++++++++++++++++++++++++++++ src/topology/tri6.jl | 64 +++++++++++++++++++++++++ src/topology/tri7.jl | 66 ++++++++++++++++++++++++++ src/topology/wedge15.jl | 94 +++++++++++++++++++++++++++++++++++++ src/topology/wedge6.jl | 86 ++++++++++++++++++++++++++++++++++ 14 files changed, 1042 insertions(+) create mode 100644 src/topology/hex20.jl create mode 100644 src/topology/hex27.jl create mode 100644 src/topology/hex8.jl create mode 100644 src/topology/pyr5.jl create mode 100644 src/topology/quad8.jl create mode 100644 src/topology/quad9.jl create mode 100644 src/topology/seg2.jl create mode 100644 src/topology/seg3.jl create mode 100644 src/topology/tet10.jl create mode 100644 src/topology/tet4.jl create mode 100644 src/topology/tri6.jl create mode 100644 src/topology/tri7.jl create mode 100644 src/topology/wedge15.jl create mode 100644 src/topology/wedge6.jl diff --git a/src/topology/hex20.jl b/src/topology/hex20.jl new file mode 100644 index 0000000..df574f7 --- /dev/null +++ b/src/topology/hex20.jl @@ -0,0 +1,92 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE + +""" + Hex20 <: AbstractTopology + +20-node biquadratic hexahedral element. + +Reference element in 3D parametric space [-1, 1]³ with corner and edge nodes +(Serendipity family - no face or volume interior nodes). + +# Node numbering +``` + N8---N20---N7 + /| /| + N16| N15| + / N12 / N11 + N5---N17-N6 | + | N4-|--N19--N3 + N13 / N14 / + | N9 | N10 + |/ |/ + N1---N18-N2 +``` + +**Zero allocation:** All functions return compile-time sized tuples. +""" +struct Hex20 <: AbstractTopology end + +nnodes(::Hex20) = 20 +dim(::Hex20) = 3 + +""" + reference_coordinates(::Hex20) -> NTuple{20, NTuple{3, Float64}} + +Reference coordinates for 20-node hexahedron (Serendipity): +- Corner nodes (8): vertices of [-1,1]³ +- Edge nodes (12): midpoints of 12 edges + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +reference_coordinates(::Hex20) = ( + (-1.0, -1.0, -1.0), # N1 + ( 1.0, -1.0, -1.0), # N2 + ( 1.0, 1.0, -1.0), # N3 + (-1.0, 1.0, -1.0), # N4 + (-1.0, -1.0, 1.0), # N5 + ( 1.0, -1.0, 1.0), # N6 + ( 1.0, 1.0, 1.0), # N7 + (-1.0, 1.0, 1.0), # N8 + ( 0.0, -1.0, -1.0), # N9 (edge 1-2) + ( 1.0, 0.0, -1.0), # N10 (edge 2-3) + ( 0.0, 1.0, -1.0), # N11 (edge 3-4) + (-1.0, 0.0, -1.0), # N12 (edge 4-1) + (-1.0, -1.0, 0.0), # N13 (edge 1-5) + ( 1.0, -1.0, 0.0), # N14 (edge 2-6) + ( 1.0, 1.0, 0.0), # N15 (edge 3-7) + (-1.0, 1.0, 0.0), # N16 (edge 4-8) + ( 0.0, -1.0, 1.0), # N17 (edge 5-6) + ( 1.0, 0.0, 1.0), # N18 (edge 6-7) + ( 0.0, 1.0, 1.0), # N19 (edge 7-8) + (-1.0, 0.0, 1.0), # N20 (edge 8-5) +) + +""" + edges(::Hex20) -> NTuple{12, Tuple{Int, Int}} + +Edge connectivity for hexahedron (corner nodes only). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +edges(::Hex20) = ( + (1, 2), (2, 3), (3, 4), (4, 1), # Bottom face + (5, 6), (6, 7), (7, 8), (8, 5), # Top face + (1, 5), (2, 6), (3, 7), (4, 8), # Vertical edges +) + +""" + faces(::Hex20) -> NTuple{6, NTuple{4, Int}} + +Face connectivity for hexahedron (corner nodes of 6 quadrilateral faces). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +faces(::Hex20) = ( + (1, 4, 3, 2), # Bottom (-z) + (5, 6, 7, 8), # Top (+z) + (1, 2, 6, 5), # Front (-y) + (3, 4, 8, 7), # Back (+y) + (2, 3, 7, 6), # Right (+x) + (1, 5, 8, 4), # Left (-x) +) diff --git a/src/topology/hex27.jl b/src/topology/hex27.jl new file mode 100644 index 0000000..c4c3d19 --- /dev/null +++ b/src/topology/hex27.jl @@ -0,0 +1,101 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE + +""" + Hex27 <: AbstractTopology + +27-node quadratic hexahedral element. + +Reference element in 3D parametric space [-1, 1]³ with corner, edge, face, +and volume center nodes. + +# Node numbering +``` + N8---N20---N7 + /| /| + N16| N26 N15| + / N12 / N11 + N5---N17-N6 | + |N25|N27|N23 N3 + N13 N4-N24-N19/ + | /N21 | N10 + |N9 N14/ + N1---N18-N2 +``` + +**Zero allocation:** All functions return compile-time sized tuples. +""" +struct Hex27 <: AbstractTopology end + +nnodes(::Hex27) = 27 +dim(::Hex27) = 3 + +""" + reference_coordinates(::Hex27) -> NTuple{27, NTuple{3, Float64}} + +Reference coordinates for 27-node hexahedron: +- Corner nodes (8): vertices of [-1,1]³ +- Edge nodes (12): midpoints of 12 edges +- Face nodes (6): centers of 6 faces +- Volume node (1): center (0,0,0) + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +reference_coordinates(::Hex27) = ( + (-1.0, -1.0, -1.0), # N1 + ( 1.0, -1.0, -1.0), # N2 + ( 1.0, 1.0, -1.0), # N3 + (-1.0, 1.0, -1.0), # N4 + (-1.0, -1.0, 1.0), # N5 + ( 1.0, -1.0, 1.0), # N6 + ( 1.0, 1.0, 1.0), # N7 + (-1.0, 1.0, 1.0), # N8 + ( 0.0, -1.0, -1.0), # N9 (edge 1-2) + ( 1.0, 0.0, -1.0), # N10 (edge 2-3) + ( 0.0, 1.0, -1.0), # N11 (edge 3-4) + (-1.0, 0.0, -1.0), # N12 (edge 4-1) + (-1.0, -1.0, 0.0), # N13 (edge 1-5) + ( 1.0, -1.0, 0.0), # N14 (edge 2-6) + ( 1.0, 1.0, 0.0), # N15 (edge 3-7) + (-1.0, 1.0, 0.0), # N16 (edge 4-8) + ( 0.0, -1.0, 1.0), # N17 (edge 5-6) + ( 1.0, 0.0, 1.0), # N18 (edge 6-7) + ( 0.0, 1.0, 1.0), # N19 (edge 7-8) + (-1.0, 0.0, 1.0), # N20 (edge 8-5) + ( 0.0, 0.0, -1.0), # N21 (face center -z) + ( 0.0, -1.0, 0.0), # N22 (face center -y) + ( 1.0, 0.0, 0.0), # N23 (face center +x) + ( 0.0, 1.0, 0.0), # N24 (face center +y) + (-1.0, 0.0, 0.0), # N25 (face center -x) + ( 0.0, 0.0, 1.0), # N26 (face center +z) + ( 0.0, 0.0, 0.0), # N27 (volume center) +) + +""" + edges(::Hex27) -> NTuple{12, Tuple{Int, Int}} + +Edge connectivity for hexahedron (corner nodes only). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +edges(::Hex27) = ( + (1, 2), (2, 3), (3, 4), (4, 1), # Bottom face + (5, 6), (6, 7), (7, 8), (8, 5), # Top face + (1, 5), (2, 6), (3, 7), (4, 8), # Vertical edges +) + +""" + faces(::Hex27) -> NTuple{6, NTuple{4, Int}} + +Face connectivity for hexahedron (corner nodes of 6 quadrilateral faces). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +faces(::Hex27) = ( + (1, 4, 3, 2), # Bottom (-z) + (5, 6, 7, 8), # Top (+z) + (1, 2, 6, 5), # Front (-y) + (3, 4, 8, 7), # Back (+y) + (2, 3, 7, 6), # Right (+x) + (1, 5, 8, 4), # Left (-x) +) diff --git a/src/topology/hex8.jl b/src/topology/hex8.jl new file mode 100644 index 0000000..2490fb5 --- /dev/null +++ b/src/topology/hex8.jl @@ -0,0 +1,75 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE + +""" + Hex8 <: AbstractTopology + +8-node linear hexahedral element. + +Reference element in 3D parametric space [-1, 1]³. + +# Node numbering +``` + N8-------N7 + /| /| + / | / | + N5-------N6 | + | N4----|--N3 + | / | / + |/ |/ + N1-------N2 +``` + +**Zero allocation:** All functions return compile-time sized tuples. +""" +struct Hex8 <: AbstractTopology end + +nnodes(::Hex8) = 8 +dim(::Hex8) = 3 + +""" + reference_coordinates(::Hex8) -> NTuple{8, NTuple{3, Float64}} + +Reference coordinates for 8-node hexahedron in [-1,1]³. + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +reference_coordinates(::Hex8) = ( + (-1.0, -1.0, -1.0), # N1 + ( 1.0, -1.0, -1.0), # N2 + ( 1.0, 1.0, -1.0), # N3 + (-1.0, 1.0, -1.0), # N4 + (-1.0, -1.0, 1.0), # N5 + ( 1.0, -1.0, 1.0), # N6 + ( 1.0, 1.0, 1.0), # N7 + (-1.0, 1.0, 1.0), # N8 +) + +""" + edges(::Hex8) -> NTuple{12, Tuple{Int, Int}} + +Edge connectivity for hexahedron (12 edges). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +edges(::Hex8) = ( + (1, 2), (2, 3), (3, 4), (4, 1), # Bottom face + (5, 6), (6, 7), (7, 8), (8, 5), # Top face + (1, 5), (2, 6), (3, 7), (4, 8), # Vertical edges +) + +""" + faces(::Hex8) -> NTuple{6, NTuple{4, Int}} + +Face connectivity for hexahedron (6 quadrilateral faces). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +faces(::Hex8) = ( + (1, 4, 3, 2), # Bottom (-z) + (5, 6, 7, 8), # Top (+z) + (1, 2, 6, 5), # Front (-y) + (3, 4, 8, 7), # Back (+y) + (2, 3, 7, 6), # Right (+x) + (1, 5, 8, 4), # Left (-x) +) diff --git a/src/topology/pyr5.jl b/src/topology/pyr5.jl new file mode 100644 index 0000000..54833df --- /dev/null +++ b/src/topology/pyr5.jl @@ -0,0 +1,81 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE + +""" + Pyr5 <: AbstractTopology + +5-node linear pyramid element. + +Reference element in 3D parametric space with square base at z=-1 +and apex at (0,0,1). + +# Node numbering +``` + N5 + /\\ + / \\ + / \\ + / \\ + / \\ + N4--------N3 + | | + | | + N1--------N2 +``` + +Base nodes in [-1,1]² at z=-1, apex at (0,0,1). + +**Note:** This uses Code Aster convention (from lagrange_pyramids.jl). + +**Zero allocation:** All functions return compile-time sized tuples. +""" +struct Pyr5 <: AbstractTopology end + +nnodes(::Pyr5) = 5 +dim(::Pyr5) = 3 + +""" + reference_coordinates(::Pyr5) -> NTuple{5, NTuple{3, Float64}} + +Reference coordinates for 5-node pyramid (Code Aster convention): +- Base nodes: (-1,-1,-1), (1,-1,-1), (1,1,-1), (-1,1,-1) +- Apex: (0,0,1) + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +reference_coordinates(::Pyr5) = ( + (-1.0, -1.0, -1.0), # N1 + ( 1.0, -1.0, -1.0), # N2 + ( 1.0, 1.0, -1.0), # N3 + (-1.0, 1.0, -1.0), # N4 + ( 0.0, 0.0, 1.0), # N5 (apex) +) + +""" + edges(::Pyr5) -> NTuple{8, Tuple{Int, Int}} + +Edge connectivity for pyramid (4 base edges + 4 edges to apex = 8 edges). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +edges(::Pyr5) = ( + (1, 2), (2, 3), (3, 4), (4, 1), # Base + (1, 5), (2, 5), (3, 5), (4, 5), # Edges to apex +) + +""" + faces(::Pyr5) -> NTuple{5, Tuple{Vararg{Int}}} + +Face connectivity for pyramid: +- 1 quadrilateral base +- 4 triangular faces + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +faces(::Pyr5) = ( + (1, 4, 3, 2), # Base (quad) + (1, 2, 5), # Triangle + (2, 3, 5), # Triangle + (3, 4, 5), # Triangle + (4, 1, 5), # Triangle +) diff --git a/src/topology/quad8.jl b/src/topology/quad8.jl new file mode 100644 index 0000000..dcafcc6 --- /dev/null +++ b/src/topology/quad8.jl @@ -0,0 +1,64 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE + +""" + Quad8 <: AbstractTopology + +8-node quadratic quadrilateral element (Serendipity). + +Reference element in 2D parametric space [-1, 1]² with corner and edge nodes +but no center node (Serendipity family). + +# Node numbering +``` +N4----N7----N3 +| | +N8 N6 +| | +N1----N5----N2 +``` + +**Zero allocation:** All functions return compile-time sized tuples. +""" +struct Quad8 <: AbstractTopology end + +nnodes(::Quad8) = 8 +dim(::Quad8) = 2 + +""" + reference_coordinates(::Quad8) -> NTuple{8, NTuple{2, Float64}} + +Reference coordinates for 8-node quadrilateral (Serendipity): +- Corner nodes: (-1,-1), (1,-1), (1,1), (-1,1) +- Edge nodes: (0,-1), (1,0), (0,1), (-1,0) + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +reference_coordinates(::Quad8) = ( + (-1.0, -1.0), # N1 + ( 1.0, -1.0), # N2 + ( 1.0, 1.0), # N3 + (-1.0, 1.0), # N4 + ( 0.0, -1.0), # N5 + ( 1.0, 0.0), # N6 + ( 0.0, 1.0), # N7 + (-1.0, 0.0), # N8 +) + +""" + edges(::Quad8) -> NTuple{4, Tuple{Int, Int}} + +Edge connectivity for quadrilateral (corner nodes only). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +edges(::Quad8) = ((1, 2), (2, 3), (3, 4), (4, 1)) + +""" + faces(::Quad8) -> NTuple{1, NTuple{8, Int}} + +Face connectivity (all nodes) for 2D element. + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +faces(::Quad8) = ((1, 2, 3, 4, 5, 6, 7, 8),) diff --git a/src/topology/quad9.jl b/src/topology/quad9.jl new file mode 100644 index 0000000..6ebc5da --- /dev/null +++ b/src/topology/quad9.jl @@ -0,0 +1,65 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE + +""" + Quad9 <: AbstractTopology + +9-node quadratic quadrilateral element. + +Reference element in 2D parametric space [-1, 1]² with corner, edge, and center nodes. + +# Node numbering +``` +N4----N7----N3 +| | +N8 N9 N6 +| | +N1----N5----N2 +``` + +**Zero allocation:** All functions return compile-time sized tuples. +""" +struct Quad9 <: AbstractTopology end + +nnodes(::Quad9) = 9 +dim(::Quad9) = 2 + +""" + reference_coordinates(::Quad9) -> NTuple{9, NTuple{2, Float64}} + +Reference coordinates for 9-node quadrilateral: +- Corner nodes: (-1,-1), (1,-1), (1,1), (-1,1) +- Edge nodes: (0,-1), (1,0), (0,1), (-1,0) +- Center node: (0,0) + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +reference_coordinates(::Quad9) = ( + (-1.0, -1.0), # N1 + ( 1.0, -1.0), # N2 + ( 1.0, 1.0), # N3 + (-1.0, 1.0), # N4 + ( 0.0, -1.0), # N5 + ( 1.0, 0.0), # N6 + ( 0.0, 1.0), # N7 + (-1.0, 0.0), # N8 + ( 0.0, 0.0), # N9 (center) +) + +""" + edges(::Quad9) -> NTuple{4, Tuple{Int, Int}} + +Edge connectivity for quadrilateral (corner nodes only). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +edges(::Quad9) = ((1, 2), (2, 3), (3, 4), (4, 1)) + +""" + faces(::Quad9) -> NTuple{1, NTuple{9, Int}} + +Face connectivity (all nodes) for 2D element. + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +faces(::Quad9) = ((1, 2, 3, 4, 5, 6, 7, 8, 9),) diff --git a/src/topology/seg2.jl b/src/topology/seg2.jl new file mode 100644 index 0000000..2f77bec --- /dev/null +++ b/src/topology/seg2.jl @@ -0,0 +1,49 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE + +""" + Seg2 <: AbstractTopology + +2-node linear segment/line element. + +Reference element in 1D parametric space [-1, 1]. + +# Node numbering +``` + N1 -------- N2 +-1 +1 +``` + +**Zero allocation:** All functions return compile-time sized tuples. +""" +struct Seg2 <: AbstractTopology end + +nnodes(::Seg2) = 2 +dim(::Seg2) = 1 + +""" + reference_coordinates(::Seg2) -> NTuple{2, NTuple{1, Float64}} + +Reference coordinates for 2-node segment: (-1.0,) and (1.0,). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +reference_coordinates(::Seg2) = ((-1.0,), (1.0,)) + +""" + edges(::Seg2) -> NTuple{1, Tuple{Int, Int}} + +Edge connectivity for segment (the segment itself). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +edges(::Seg2) = ((1, 2),) + +""" + faces(::Seg2) -> NTuple{0, Tuple{}} + +Faces for 1D element (none in 1D). + +**Zero allocation:** Returns empty tuple (stack allocated). +""" +faces(::Seg2) = () diff --git a/src/topology/seg3.jl b/src/topology/seg3.jl new file mode 100644 index 0000000..d4047f3 --- /dev/null +++ b/src/topology/seg3.jl @@ -0,0 +1,49 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE + +""" + Seg3 <: AbstractTopology + +3-node quadratic segment/line element. + +Reference element in 1D parametric space [-1, 1] with midpoint node. + +# Node numbering +``` + N1 ---- N3 ---- N2 +-1 0 +1 +``` + +**Zero allocation:** All functions return compile-time sized tuples. +""" +struct Seg3 <: AbstractTopology end + +nnodes(::Seg3) = 3 +dim(::Seg3) = 1 + +""" + reference_coordinates(::Seg3) -> NTuple{3, NTuple{1, Float64}} + +Reference coordinates for 3-node segment: (-1.0,), (1.0,), (0.0,). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +reference_coordinates(::Seg3) = ((-1.0,), (1.0,), (0.0,)) + +""" + edges(::Seg3) -> NTuple{1, Tuple{Int, Int}} + +Edge connectivity for segment (the segment itself, corner nodes only). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +edges(::Seg3) = ((1, 2),) + +""" + faces(::Seg3) -> NTuple{0, Tuple{}} + +Faces for 1D element (none in 1D). + +**Zero allocation:** Returns empty tuple (stack allocated). +""" +faces(::Seg3) = () diff --git a/src/topology/tet10.jl b/src/topology/tet10.jl new file mode 100644 index 0000000..cce261d --- /dev/null +++ b/src/topology/tet10.jl @@ -0,0 +1,82 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE + +""" + Tet10 <: AbstractTopology + +10-node quadratic tetrahedral element. + +Reference element in 3D parametric space with corner nodes at vertices +and midpoint nodes on each edge. + +# Node numbering +``` + N4 + /|\\ + N8 | N10 + / N9 \\ + / | \\ + / | \\ +N1-N5--N7----N3 + \\ | / + \\ | / + \\ N6 / + \\ | / + \\|/ + N2 +``` + +**Zero allocation:** All functions return compile-time sized tuples. +""" +struct Tet10 <: AbstractTopology end + +nnodes(::Tet10) = 10 +dim(::Tet10) = 3 + +""" + reference_coordinates(::Tet10) -> NTuple{10, NTuple{3, Float64}} + +Reference coordinates for 10-node tetrahedron: +- Corner nodes: (0,0,0), (1,0,0), (0,1,0), (0,0,1) +- Edge nodes: midpoints of all 6 edges + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +reference_coordinates(::Tet10) = ( + (0.0, 0.0, 0.0), # N1 + (1.0, 0.0, 0.0), # N2 + (0.0, 1.0, 0.0), # N3 + (0.0, 0.0, 1.0), # N4 + (0.5, 0.0, 0.0), # N5 (edge 1-2) + (0.5, 0.5, 0.0), # N6 (edge 2-3) + (0.0, 0.5, 0.0), # N7 (edge 3-1) + (0.0, 0.0, 0.5), # N8 (edge 1-4) + (0.5, 0.0, 0.5), # N9 (edge 2-4) + (0.0, 0.5, 0.5), # N10 (edge 3-4) +) + +""" + edges(::Tet10) -> NTuple{6, Tuple{Int, Int}} + +Edge connectivity for tetrahedron (corner nodes only). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +edges(::Tet10) = ( + (1, 2), (2, 3), (3, 1), # Base triangle + (1, 4), (2, 4), (3, 4), # Edges to apex +) + +""" + faces(::Tet10) -> NTuple{4, NTuple{3, Int}} + +Face connectivity for tetrahedron (corner nodes of 4 triangular faces). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +faces(::Tet10) = ( + (1, 3, 2), # Base + (1, 2, 4), # Front + (2, 3, 4), # Right + (3, 1, 4), # Left +) diff --git a/src/topology/tet4.jl b/src/topology/tet4.jl new file mode 100644 index 0000000..080f04b --- /dev/null +++ b/src/topology/tet4.jl @@ -0,0 +1,74 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE + +""" + Tet4 <: AbstractTopology + +4-node linear tetrahedral element. + +Reference element in 3D parametric space with vertices at (0,0,0), (1,0,0), (0,1,0), (0,0,1). + +# Node numbering +``` + N4 + /|\\ + / | \\ + / | \\ + / | \\ + / | \\ +N1-----|-----N3 + \\ | / + \\ | / + \\ | / + \\ | / + \\|/ + N2 +``` + +**Zero allocation:** All functions return compile-time sized tuples. +""" +struct Tet4 <: AbstractTopology end + +nnodes(::Tet4) = 4 +dim(::Tet4) = 3 + +""" + reference_coordinates(::Tet4) -> NTuple{4, NTuple{3, Float64}} + +Reference coordinates for 4-node tetrahedron: +(0,0,0), (1,0,0), (0,1,0), (0,0,1). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +reference_coordinates(::Tet4) = ( + (0.0, 0.0, 0.0), # N1 + (1.0, 0.0, 0.0), # N2 + (0.0, 1.0, 0.0), # N3 + (0.0, 0.0, 1.0), # N4 +) + +""" + edges(::Tet4) -> NTuple{6, Tuple{Int, Int}} + +Edge connectivity for tetrahedron (6 edges). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +edges(::Tet4) = ( + (1, 2), (2, 3), (3, 1), # Base triangle + (1, 4), (2, 4), (3, 4), # Edges to apex +) + +""" + faces(::Tet4) -> NTuple{4, NTuple{3, Int}} + +Face connectivity for tetrahedron (4 triangular faces). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +faces(::Tet4) = ( + (1, 3, 2), # Base + (1, 2, 4), # Front + (2, 3, 4), # Right + (3, 1, 4), # Left +) diff --git a/src/topology/tri6.jl b/src/topology/tri6.jl new file mode 100644 index 0000000..13e0f30 --- /dev/null +++ b/src/topology/tri6.jl @@ -0,0 +1,64 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE + +""" + Tri6 <: AbstractTopology + +6-node quadratic triangle element. + +Reference element in 2D parametric space with vertices at (0,0), (1,0), (0,1) +and midpoint nodes on each edge. + +# Node numbering +``` +N3 + |\\ + | \\ +N6 N5 + | \\ + | \\ +N1--N4--N2 +``` + +**Zero allocation:** All functions return compile-time sized tuples. +""" +struct Tri6 <: AbstractTopology end + +nnodes(::Tri6) = 6 +dim(::Tri6) = 2 + +""" + reference_coordinates(::Tri6) -> NTuple{6, NTuple{2, Float64}} + +Reference coordinates for 6-node triangle: +- Corner nodes: (0,0), (1,0), (0,1) +- Edge nodes: (0.5,0), (0.5,0.5), (0,0.5) + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +reference_coordinates(::Tri6) = ( + (0.0, 0.0), # N1 + (1.0, 0.0), # N2 + (0.0, 1.0), # N3 + (0.5, 0.0), # N4 + (0.5, 0.5), # N5 + (0.0, 0.5), # N6 +) + +""" + edges(::Tri6) -> NTuple{3, Tuple{Int, Int}} + +Edge connectivity for triangle (corner nodes only). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +edges(::Tri6) = ((1, 2), (2, 3), (3, 1)) + +""" + faces(::Tri6) -> NTuple{1, NTuple{6, Int}} + +Face connectivity (all nodes) for 2D element. + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +faces(::Tri6) = ((1, 2, 3, 4, 5, 6),) diff --git a/src/topology/tri7.jl b/src/topology/tri7.jl new file mode 100644 index 0000000..b7e14ee --- /dev/null +++ b/src/topology/tri7.jl @@ -0,0 +1,66 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE + +""" + Tri7 <: AbstractTopology + +7-node quadratic triangle element with center node. + +Reference element in 2D parametric space with vertices at (0,0), (1,0), (0,1), +midpoint nodes on each edge, and center node. + +# Node numbering +``` +N3 + |\\ + | \\ +N6 N7 N5 + | \\ + | \\ +N1--N4--N2 +``` + +**Zero allocation:** All functions return compile-time sized tuples. +""" +struct Tri7 <: AbstractTopology end + +nnodes(::Tri7) = 7 +dim(::Tri7) = 2 + +""" + reference_coordinates(::Tri7) -> NTuple{7, NTuple{2, Float64}} + +Reference coordinates for 7-node triangle: +- Corner nodes: (0,0), (1,0), (0,1) +- Edge nodes: (0.5,0), (0.5,0.5), (0,0.5) +- Center node: (1/3, 1/3) + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +reference_coordinates(::Tri7) = ( + (0.0, 0.0), # N1 + (1.0, 0.0), # N2 + (0.0, 1.0), # N3 + (0.5, 0.0), # N4 + (0.5, 0.5), # N5 + (0.0, 0.5), # N6 + (1/3, 1/3), # N7 (center) +) + +""" + edges(::Tri7) -> NTuple{3, Tuple{Int, Int}} + +Edge connectivity for triangle (corner nodes only). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +edges(::Tri7) = ((1, 2), (2, 3), (3, 1)) + +""" + faces(::Tri7) -> NTuple{1, NTuple{7, Int}} + +Face connectivity (all nodes) for 2D element. + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +faces(::Tri7) = ((1, 2, 3, 4, 5, 6, 7),) diff --git a/src/topology/wedge15.jl b/src/topology/wedge15.jl new file mode 100644 index 0000000..3b19e3b --- /dev/null +++ b/src/topology/wedge15.jl @@ -0,0 +1,94 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE + +""" + Wedge15 <: AbstractTopology + +15-node quadratic prismatic/wedge element. + +Reference element in 3D with triangular cross-section in (u,v) plane +extruded along w direction, with edge and mid-plane nodes. + +# Node numbering +``` + N6 + /\\ + N12 N11 + / \\ + N4-N10-N5 + | | + N15 N14 + | | + N3 | + |\\ | + N9 N8 | + | \\ N13 + | \\ | + | \\ | + | \\| + N1--N7--N2 +``` + +**Zero allocation:** All functions return compile-time sized tuples. +""" +struct Wedge15 <: AbstractTopology end + +nnodes(::Wedge15) = 15 +dim(::Wedge15) = 3 + +""" + reference_coordinates(::Wedge15) -> NTuple{15, NTuple{3, Float64}} + +Reference coordinates for 15-node wedge: +- Corner nodes (6): bottom and top triangles +- Edge nodes (9): 3 on bottom, 3 on top, 3 on vertical edges + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +reference_coordinates(::Wedge15) = ( + (0.0, 0.0, -1.0), # N1 + (1.0, 0.0, -1.0), # N2 + (0.0, 1.0, -1.0), # N3 + (0.0, 0.0, 1.0), # N4 + (1.0, 0.0, 1.0), # N5 + (0.0, 1.0, 1.0), # N6 + (0.5, 0.0, -1.0), # N7 (edge 1-2, bottom) + (0.5, 0.5, -1.0), # N8 (edge 2-3, bottom) + (0.0, 0.5, -1.0), # N9 (edge 3-1, bottom) + (0.5, 0.0, 1.0), # N10 (edge 4-5, top) + (0.5, 0.5, 1.0), # N11 (edge 5-6, top) + (0.0, 0.5, 1.0), # N12 (edge 6-4, top) + (0.0, 0.0, 0.0), # N13 (edge 1-4, vertical) + (1.0, 0.0, 0.0), # N14 (edge 2-5, vertical) + (0.0, 1.0, 0.0), # N15 (edge 3-6, vertical) +) + +""" + edges(::Wedge15) -> NTuple{9, Tuple{Int, Int}} + +Edge connectivity for wedge (corner nodes only). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +edges(::Wedge15) = ( + (1, 2), (2, 3), (3, 1), # Bottom triangle + (4, 5), (5, 6), (6, 4), # Top triangle + (1, 4), (2, 5), (3, 6), # Vertical edges +) + +""" + faces(::Wedge15) -> NTuple{5, Tuple{Vararg{Int}}} + +Face connectivity for wedge (corner nodes only): +- 2 triangular faces +- 3 quadrilateral faces + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +faces(::Wedge15) = ( + (1, 3, 2), # Bottom triangle + (4, 5, 6), # Top triangle + (1, 2, 5, 4), # Side quad + (2, 3, 6, 5), # Side quad + (3, 1, 4, 6), # Side quad +) diff --git a/src/topology/wedge6.jl b/src/topology/wedge6.jl new file mode 100644 index 0000000..a75be24 --- /dev/null +++ b/src/topology/wedge6.jl @@ -0,0 +1,86 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE + +""" + Wedge6 <: AbstractTopology + +6-node linear prismatic/wedge element. + +Reference element in 3D with triangular cross-section in (u,v) plane +extruded along w direction from -1 to +1. + +# Node numbering +``` + N6 + /\\ + / \\ + / \\ + N4----N5 + | | + | | + N3 | + |\\ | + | \\ | + | \\ | + | \\ | + | \\ | + | \\| + N1-----N2 +``` + +Triangle base at w=-1, triangle top at w=+1. + +**Zero allocation:** All functions return compile-time sized tuples. +""" +struct Wedge6 <: AbstractTopology end + +nnodes(::Wedge6) = 6 +dim(::Wedge6) = 3 + +""" + reference_coordinates(::Wedge6) -> NTuple{6, NTuple{3, Float64}} + +Reference coordinates for 6-node wedge: +- Bottom triangle (w=-1): (0,0,-1), (1,0,-1), (0,1,-1) +- Top triangle (w=+1): (0,0,+1), (1,0,+1), (0,1,+1) + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +reference_coordinates(::Wedge6) = ( + (0.0, 0.0, -1.0), # N1 + (1.0, 0.0, -1.0), # N2 + (0.0, 1.0, -1.0), # N3 + (0.0, 0.0, 1.0), # N4 + (1.0, 0.0, 1.0), # N5 + (0.0, 1.0, 1.0), # N6 +) + +""" + edges(::Wedge6) -> NTuple{9, Tuple{Int, Int}} + +Edge connectivity for wedge (3 bottom + 3 top + 3 vertical = 9 edges). + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +edges(::Wedge6) = ( + (1, 2), (2, 3), (3, 1), # Bottom triangle + (4, 5), (5, 6), (6, 4), # Top triangle + (1, 4), (2, 5), (3, 6), # Vertical edges +) + +""" + faces(::Wedge6) -> NTuple{5, Tuple{Vararg{Int}}} + +Face connectivity for wedge: +- 2 triangular faces (top and bottom) +- 3 quadrilateral faces (sides) + +**Zero allocation:** Returns tuple of tuples (stack allocated). +""" +faces(::Wedge6) = ( + (1, 3, 2), # Bottom triangle + (4, 5, 6), # Top triangle + (1, 2, 5, 4), # Side quad + (2, 3, 6, 5), # Side quad + (3, 1, 4, 6), # Side quad +)