mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-19 09:54:55 +00:00
feat(topology): Add element topology API with 17 reference element types
Create src/topology/api.jl defining element topology abstractions:
- AbstractTopology{N} base type (N = node count from mesh connectivity)
- Interface: nnodes(), dim(), reference_coordinates(), edges(), faces()
- 7 shape families: Segment, Triangle, Quadrilateral, Tetrahedron, Hexahedron, Pyramid, Wedge
- 17 concrete types: Seg2/3, Tri3/6/7, Quad4/8/9, Tet4/10, Hex8/20/27, Pyr5, Wedge6/15
Key design: Topology defines SHAPE (triangle), not node count. Node count
comes from basis order: Triangle + Lagrange{Triangle,1} → 3 nodes (Tri3),
Triangle + Lagrange{Triangle,2} → 6 nodes (Tri6). This enables clean
separation: Topology (shape) ≠ Basis (interpolation) ≠ Integration (quadrature).
Reference element coordinates defined for all topologies. Zero-allocation
API using tuples. Backward compatibility: Tri3/Quad4/Tet10 aliased to
shape names with implied basis.
Comprehensive documentation with theory and examples.
Part of systematic modular API architecture.
This commit is contained in:
@@ -0,0 +1,333 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
"""
|
||||
Topology API definitions.
|
||||
|
||||
This file defines element topology abstractions - the geometric shape and node ordering
|
||||
of finite elements in their reference configuration.
|
||||
|
||||
Must be included after core api.jl.
|
||||
"""
|
||||
|
||||
# ============================================================================
|
||||
# TOPOLOGY ABSTRACTIONS
|
||||
# ============================================================================
|
||||
|
||||
"""
|
||||
AbstractTopology
|
||||
|
||||
Abstract type for element topology (geometric shape and node ordering).
|
||||
|
||||
Topology defines the **shape** of an element in its reference (parametric) space:
|
||||
- Number of nodes
|
||||
- Reference element coordinates (ξ, η, ζ positions)
|
||||
- Edge connectivity (which nodes form edges)
|
||||
- Face connectivity (which nodes form faces, 3D only)
|
||||
- Spatial dimension (1D, 2D, or 3D)
|
||||
|
||||
# Interface Requirements
|
||||
|
||||
All topology types must implement:
|
||||
- `nnodes(topology)` - Number of nodes
|
||||
- `dim(topology)` - Spatial dimension (1, 2, or 3)
|
||||
- `reference_coordinates(topology)` - Node positions in reference element (returns tuple of tuples)
|
||||
- `edges(topology)` - Edge connectivity (returns tuple of tuples)
|
||||
- `faces(topology)` - Face connectivity (returns tuple of tuples, 3D only)
|
||||
|
||||
# Concrete Types
|
||||
|
||||
**1D (Lines):**
|
||||
- `Segment` - Generic 1D line segment
|
||||
|
||||
**2D (Surfaces):**
|
||||
- `Triangle` - 2D simplex (straight or curved edges)
|
||||
- `Quadrilateral` - 2D quadrilateral (straight or curved edges)
|
||||
|
||||
**3D (Volumes):**
|
||||
- `Tetrahedron` - 3D simplex (straight or curved faces)
|
||||
- `Hexahedron` - 3D brick (straight or curved faces)
|
||||
- `Pyramid` - 3D pyramid (quad base, triangular sides)
|
||||
- `Wedge` - 3D prism (triangular extrusion)
|
||||
|
||||
# Design Philosophy
|
||||
|
||||
**Key Insight:** Topology defines SHAPE, not node count!
|
||||
|
||||
Node count comes from the **basis function order**:
|
||||
- Linear basis (P=1): Corner nodes only
|
||||
- Quadratic basis (P=2): Corner + mid-edge nodes
|
||||
- Cubic basis (P=3): Corner + edge + face nodes
|
||||
|
||||
**Examples:**
|
||||
```julia
|
||||
# Triangle with different basis orders
|
||||
Triangle + Lagrange{Triangle, 1} → 3 nodes (corners)
|
||||
Triangle + Lagrange{Triangle, 2} → 6 nodes (corners + mid-edges)
|
||||
Triangle + Lagrange{Triangle, 3} → 10 nodes (corners + edges + interior)
|
||||
|
||||
# Quadrilateral with different basis types
|
||||
Quadrilateral + Lagrange{Quadrilateral, 1} → 4 nodes (corners)
|
||||
Quadrilateral + Serendipity{Quadrilateral, 2} → 8 nodes (corners + mid-edges, no center)
|
||||
Quadrilateral + Lagrange{Quadrilateral, 2} → 9 nodes (corners + mid-edges + center)
|
||||
```
|
||||
|
||||
**Separation of Concerns:**
|
||||
- Topology: "This is a triangle" (shape)
|
||||
- Basis: "This triangle has 6 nodes" (interpolation)
|
||||
- Integration: "Use 3-point Gauss rule" (numerical quadrature)
|
||||
|
||||
# Backward Compatibility
|
||||
|
||||
Old names like `Tri3`, `Quad4`, `Tet10` are **deprecated** but aliased:
|
||||
- `Tri3` → `Triangle` (with implied linear basis)
|
||||
- `Quad4` → `Quadrilateral` (with implied linear basis)
|
||||
- `Tet10` → `Tetrahedron` (with implied quadratic basis)
|
||||
|
||||
New code should use shape names (`Triangle`) with explicit basis specification.
|
||||
|
||||
# Reference Element Coordinates
|
||||
|
||||
Each topology has standard reference coordinates:
|
||||
|
||||
**Segment:** ξ ∈ [-1, 1]
|
||||
**Triangle:** (ξ, η) where ξ, η ≥ 0 and ξ + η ≤ 1
|
||||
**Quadrilateral:** (ξ, η) ∈ [-1, 1] × [-1, 1]
|
||||
**Tetrahedron:** (ξ, η, ζ) where ξ, η, ζ ≥ 0 and ξ + η + ζ ≤ 1
|
||||
**Hexahedron:** (ξ, η, ζ) ∈ [-1, 1]³
|
||||
**Pyramid:** (ξ, η, ζ) where (ξ, η) ∈ [-1, 1]² and ζ ∈ [0, 1], with ξ²+η² ≤ (1-ζ)²
|
||||
**Wedge:** (ξ, η, ζ) where (ξ, η) triangle and ζ ∈ [-1, 1]
|
||||
|
||||
# Usage
|
||||
|
||||
```julia
|
||||
# Query topology properties
|
||||
topology = Triangle()
|
||||
dim(topology) # 2
|
||||
reference_coordinates(topology) # ((0,0), (1,0), (0,1))
|
||||
edges(topology) # ((1,2), (2,3), (3,1))
|
||||
|
||||
# Topology is independent of basis order
|
||||
element_linear = Element(Triangle, Lagrange{Triangle,1}, (1,2,3)) # 3 nodes
|
||||
element_quad = Element(Triangle, Lagrange{Triangle,2}, (1,2,3,4,5,6)) # 6 nodes
|
||||
|
||||
# Both elements have the same topology (Triangle), different basis orders
|
||||
```
|
||||
|
||||
# See Also
|
||||
- [`dim`](@ref) - Spatial dimension
|
||||
- [`nnodes`](@ref) - Number of nodes (depends on basis, not topology!)
|
||||
- [`reference_coordinates`](@ref) - Reference element node positions
|
||||
- [`edges`](@ref) - Edge connectivity
|
||||
- [`faces`](@ref) - Face connectivity (3D only)
|
||||
- Architecture docs: `docs/book/element_architecture.md`
|
||||
|
||||
# Type Parameter
|
||||
|
||||
`AbstractTopology{N}` where `N` is the number of nodes. Node count comes from mesh connectivity.
|
||||
|
||||
# Examples
|
||||
```julia
|
||||
Triangle{3} <: AbstractTopology{3} # 3-node triangle (linear)
|
||||
Triangle{6} <: AbstractTopology{6} # 6-node triangle (quadratic)
|
||||
Hexahedron{8} <: AbstractTopology{8} # 8-node hex (linear)
|
||||
Hexahedron{20} <: AbstractTopology{20} # 20-node hex (quadratic serendipity)
|
||||
Hexahedron{27} <: AbstractTopology{27} # 27-node hex (quadratic full)
|
||||
```
|
||||
|
||||
# Rationale
|
||||
|
||||
Node count is included in the type parameter for compile-time performance optimization:
|
||||
- Enables `Val(N)` for zero-allocation ntuple operations
|
||||
- Allows loop unrolling for small N
|
||||
- Node count comes from mesh connectivity, not basis choice
|
||||
- See ADR-002 for detailed design rationale
|
||||
"""
|
||||
abstract type AbstractTopology{N} end
|
||||
|
||||
# ============================================================================
|
||||
# TOPOLOGY INTERFACE FUNCTIONS
|
||||
# ============================================================================
|
||||
|
||||
"""
|
||||
nnodes(topology::AbstractTopology{N}) -> Int
|
||||
|
||||
Number of nodes in the reference element.
|
||||
|
||||
This is a compile-time constant derived from the type parameter `N`.
|
||||
|
||||
# Examples
|
||||
|
||||
```julia
|
||||
nnodes(Triangle{3}()) # 3
|
||||
nnodes(Triangle{6}()) # 6
|
||||
nnodes(Quadrilateral{4}()) # 4
|
||||
nnodes(Quadrilateral{9}()) # 9
|
||||
nnodes(Hexahedron{8}()) # 8
|
||||
nnodes(Hexahedron{27}()) # 27
|
||||
```
|
||||
|
||||
# Implementation
|
||||
|
||||
The default implementation extracts `N` from the type parameter:
|
||||
```julia
|
||||
nnodes(::AbstractTopology{N}) where N = N
|
||||
```
|
||||
|
||||
Concrete types inherit this implementation automatically.
|
||||
"""
|
||||
nnodes(::AbstractTopology{N}) where N = N
|
||||
|
||||
"""
|
||||
dim(topology::AbstractTopology) -> Int
|
||||
|
||||
Spatial dimension of the topology (1, 2, or 3).
|
||||
|
||||
# Examples
|
||||
|
||||
```julia
|
||||
dim(Segment()) # 1
|
||||
dim(Triangle()) # 2
|
||||
dim(Quadrilateral()) # 2
|
||||
dim(Tetrahedron()) # 3
|
||||
dim(Hexahedron()) # 3
|
||||
dim(Pyramid()) # 3
|
||||
dim(Wedge()) # 3
|
||||
```
|
||||
|
||||
# Implementation
|
||||
|
||||
Each concrete topology type must provide:
|
||||
```julia
|
||||
dim(::Segment) = 1
|
||||
dim(::Triangle) = 2
|
||||
dim(::Tetrahedron) = 3
|
||||
# etc.
|
||||
```
|
||||
"""
|
||||
function dim end
|
||||
|
||||
"""
|
||||
reference_coordinates(topology::AbstractTopology) -> NTuple{N, NTuple{D, Float64}}
|
||||
|
||||
Reference element coordinates for the topology's nodes.
|
||||
|
||||
Returns a tuple of coordinate tuples, one per node.
|
||||
The actual number of nodes depends on the basis order (not shown here).
|
||||
|
||||
# Examples
|
||||
|
||||
```julia
|
||||
# Triangle (linear: 3 nodes, quadratic: 6 nodes, etc.)
|
||||
reference_coordinates(Triangle())
|
||||
# For linear basis (3 nodes):
|
||||
# ((0.0, 0.0), (1.0, 0.0), (0.0, 1.0))
|
||||
|
||||
# Quadrilateral (4 corner nodes minimum)
|
||||
reference_coordinates(Quadrilateral())
|
||||
# ((-1.0, -1.0), (1.0, -1.0), (1.0, 1.0), (-1.0, 1.0))
|
||||
```
|
||||
|
||||
# Note
|
||||
|
||||
This returns coordinates for **corner nodes** by default.
|
||||
Mid-edge and interior nodes are computed by the basis function module.
|
||||
|
||||
# Implementation
|
||||
|
||||
Each concrete topology type must provide:
|
||||
```julia
|
||||
reference_coordinates(::Triangle) = ((0.0, 0.0), (1.0, 0.0), (0.0, 1.0))
|
||||
reference_coordinates(::Quadrilateral) = ((-1.0, -1.0), (1.0, -1.0), (1.0, 1.0), (-1.0, 1.0))
|
||||
# etc.
|
||||
```
|
||||
"""
|
||||
function reference_coordinates end
|
||||
|
||||
"""
|
||||
edges(topology::AbstractTopology) -> NTuple{N, NTuple{2, Int}}
|
||||
|
||||
Edge connectivity for the topology.
|
||||
|
||||
Returns a tuple of 2-tuples, each containing node indices that form an edge.
|
||||
|
||||
# Examples
|
||||
|
||||
```julia
|
||||
# Triangle has 3 edges
|
||||
edges(Triangle()) # ((1,2), (2,3), (3,1))
|
||||
|
||||
# Quadrilateral has 4 edges
|
||||
edges(Quadrilateral()) # ((1,2), (2,3), (3,4), (4,1))
|
||||
|
||||
# Tetrahedron has 6 edges
|
||||
edges(Tetrahedron()) # ((1,2), (2,3), (3,1), (1,4), (2,4), (3,4))
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
||||
Edge connectivity is used for:
|
||||
- Surface extraction
|
||||
- Boundary condition application
|
||||
- Contact surface identification
|
||||
- Mesh refinement (edge splitting)
|
||||
|
||||
# Implementation
|
||||
|
||||
Each concrete topology type must provide:
|
||||
```julia
|
||||
edges(::Triangle) = ((1,2), (2,3), (3,1))
|
||||
edges(::Quadrilateral) = ((1,2), (2,3), (3,4), (4,1))
|
||||
# etc.
|
||||
```
|
||||
"""
|
||||
function edges end
|
||||
|
||||
"""
|
||||
faces(topology::AbstractTopology) -> NTuple{N, NTuple{M, Int}}
|
||||
|
||||
Face connectivity for 3D topologies.
|
||||
|
||||
Returns a tuple of tuples, each containing node indices that form a face.
|
||||
Only applicable to 3D topologies (Tetrahedron, Hexahedron, Pyramid, Wedge).
|
||||
|
||||
# Examples
|
||||
|
||||
```julia
|
||||
# Tetrahedron has 4 triangular faces
|
||||
faces(Tetrahedron())
|
||||
# ((1,3,2), (1,2,4), (1,4,3), (2,3,4))
|
||||
|
||||
# Hexahedron has 6 quadrilateral faces
|
||||
faces(Hexahedron())
|
||||
# ((1,4,3,2), (1,2,6,5), (2,3,7,6), (3,4,8,7), (4,1,5,8), (5,6,7,8))
|
||||
|
||||
# Pyramid has 1 quad base + 4 triangular sides
|
||||
faces(Pyramid())
|
||||
# ((1,4,3,2), (1,2,5), (2,3,5), (3,4,5), (4,1,5))
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
||||
Face connectivity is used for:
|
||||
- Surface element creation
|
||||
- Traction boundary conditions
|
||||
- Contact surface identification
|
||||
- Visualization
|
||||
- Mesh refinement (face splitting)
|
||||
|
||||
# Note
|
||||
|
||||
2D topologies do not have faces (they ARE faces).
|
||||
Calling `faces()` on 2D topology should error or return empty tuple.
|
||||
|
||||
# Implementation
|
||||
|
||||
Each concrete 3D topology type must provide:
|
||||
```julia
|
||||
faces(::Tetrahedron) = ((1,3,2), (1,2,4), (1,4,3), (2,3,4))
|
||||
faces(::Hexahedron) = ((1,4,3,2), (1,2,6,5), (2,3,7,6), (3,4,8,7), (4,1,5,8), (5,6,7,8))
|
||||
# etc.
|
||||
```
|
||||
"""
|
||||
function faces end
|
||||
Reference in New Issue
Block a user