refactor(topology): consolidate files and simplify documentation

Consolidate topology module by merging topology.jl into api.jl and
significantly simplify documentation across all topology files. Remove
verbose docstrings, examples, and design notes in favor of minimal,
code-focused documentation.

Major changes:
- Merge topology.jl into api.jl (delete topology.jl)
- Simplify docstrings in api.jl, triangles.jl, and tetrahedra.jl
- Remove verbose documentation from type aliases and functions
- Remove topology type parameter from entity types (Vertex, Edge, Face, Cell)
- Update all entity constructors to remove topology parameter
- Add entities dispatcher and helper functions to api.jl

File changes:
- api.jl: Simplified AbstractTopology docstring, added topological entities
  and helpers from topology.jl, added entities dispatcher
- triangles.jl: Removed verbose documentation
- tetrahedra.jl: Removed verbose documentation
- hexahedra.jl, pyramids.jl, quadrilaterals.jl, segments.jl, wedges.jl:
  Updated entity constructors to remove topology type parameter
- topology.jl: Deleted (content moved to api.jl)

Documentation philosophy:
- Keep docstrings minimal and code-focused
- Remove examples unless function use is unclear
- Move comprehensive documentation to website/docs, not in code
- Maintain essential type information and interface requirements
This commit is contained in:
Jukka Aho
2025-12-12 22:27:09 +02:00
parent b1292a0ee6
commit b9fafd4e09
9 changed files with 215 additions and 1189 deletions
+176 -288
View File
@@ -4,10 +4,10 @@
"""
Topology API definitions.
This file defines element topology abstractions - the geometric shape and node ordering
Defines element topology abstractions - geometric shape and node ordering
of finite elements in their reference configuration.
Must be included after core api.jl.
See `src/topology/README.md` for complete documentation.
"""
# ============================================================================
@@ -15,132 +15,32 @@ Must be included after core api.jl.
# ============================================================================
"""
AbstractTopology
AbstractTopology{N}
Abstract type for element topology (geometric shape and node ordering).
Topology defines the **shape** of an element in its reference (parametric) space:
- Reference element coordinates (ξ, η, ζ positions for its nodes)
- Edge connectivity (which nodes form edges)
- Face connectivity (which nodes form faces, 3D only)
- Spatial dimension (1D, 2D, or 3D)
Topology defines the **shape** of an element in reference space: coordinates,
edge/face connectivity, and spatial dimension.
# Type Parameter
- `N::Int`: Number of nodes (from mesh connectivity)
# 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 `SVector` of `Vec`)
- `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 interpolation.
Node count is part of the topology type parameter and comes from mesh connectivity,
while interpolation comes from the basis. Keep them separate so any topology can pair
with any basis family/order that makes sense.
**Examples:**
```julia
# Triangle with different basis orders
Triangle + Lagrange{1} → 3 nodes (corners)
Triangle + Lagrange{2} → 6 nodes (corners + mid-edges)
Triangle + Lagrange{3} → 10 nodes (corners + edges + interior)
# Quadrilateral with different basis families
Quadrilateral + Lagrange{1} → 4 nodes (corners)
Quadrilateral + Serendipity{2} → 8 nodes (corners + mid-edges, no center)
Quadrilateral + Lagrange{2} → 9 nodes (corners + mid-edges + center)
```
**Separation of Concerns:**
- Topology: "This is a triangle" (shape + node ownership in the mesh)
- Basis: "These are the interpolation functions over that topology"
- Integration: "Use 3-point Gauss rule" (numerical quadrature)
# Backward Compatibility
Old names like `Tri3`, `Quad4`, `Tet10` are **deprecated** but aliased:
- `Tri3` → `Triangle{3}`
- `Quad4` → `Quadrilateral{4}`
- `Tet10` → `Tetrahedron{10}`
New code should use shape names (`Triangle`, `Quadrilateral`, etc.) with explicit basis
specification passed separately.
# 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 (SVector of Vec)
- [`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.
- `reference_coordinates(topology)` - Node positions (SVector of Vec)
- `edges(topology)` - Edge connectivity (tuple of tuples)
- `faces(topology)` - Face connectivity (tuple of tuples, 3D only)
# 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)
Triangle{3} <: AbstractTopology{3} # 3-node triangle
Triangle{6} <: AbstractTopology{6} # 6-node triangle
Hexahedron{8} <: AbstractTopology{8} # 8-node hex
```
# 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
See `src/topology/README.md` for comprehensive documentation.
"""
abstract type AbstractTopology{N} end
@@ -149,213 +49,201 @@ abstract type AbstractTopology{N} end
# ============================================================================
"""
nnodes(topology::AbstractTopology{N}) -> Int
nnodes(topology) -> 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.
Number of nodes in the reference element (compile-time constant from type parameter N).
"""
nnodes(::AbstractTopology{N}) where N = N
"""
nnodes(::Type{<:AbstractTopology{N}}) -> Int
Number of nodes for a topology type (compile-time constant from type parameter).
# Examples
```julia
nnodes(Triangle{3}) # 3
nnodes(Triangle{6}) # 6
nnodes(Quadrilateral{4}) # 4
nnodes(Quadrilateral{9}) # 9
```
"""
nnodes(::Type{<:AbstractTopology{N}}) where N = N
"""
dim(topology::AbstractTopology) -> Int
nedges(topology) -> Int
Number of edges in the topology.
"""
nedges(t::AbstractTopology) = length(edges(t))
nedges(::Type{T}) where {T<:AbstractTopology} = length(edges(T()))
"""
nfaces(topology) -> Int
Number of faces in the topology (3D only).
"""
nfaces(t::AbstractTopology) = length(faces(t))
nfaces(::Type{T}) where {T<:AbstractTopology} = length(faces(T()))
"""
dim(topology) -> 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.
```
Each concrete topology must implement this.
"""
function dim end
"""
Base.ndims(topology::AbstractTopology) -> Int
Base.ndims(::Type{<:AbstractTopology}) -> Int
Base.ndims(topology) -> Int
Alias to `dim` for interoperability with Base API.
Alias to `dim` for Base API compatibility.
"""
Base.ndims(t::AbstractTopology) = dim(t)
Base.ndims(::Type{T}) where {T<:AbstractTopology} = dim(T())
"""
reference_coordinates(topology::AbstractTopology) -> SVector{N, Vec{D,Float64}}
reference_coordinates(topology) -> SVector{N, Vec{D,Float64}}
Reference element coordinates for the topology's nodes.
Returns an `SVector` of `Vec{D}` coordinate vectors, one per node.
The actual number of nodes depends on the basis order (not shown here).
Returns `SVector` of `Vec` coordinate vectors (zero allocation).
# Examples
```julia
# Triangle (linear: 3 nodes, quadratic: 6 nodes, etc.)
reference_coordinates(Triangle{3}())
# For linear basis (3 nodes):
# SVector(Vec{2,Float64}((0.0, 0.0)), Vec{2,Float64}((1.0, 0.0)), Vec{2,Float64}((0.0, 1.0)))
# Quadrilateral (4 corner nodes minimum)
reference_coordinates(Quadrilateral{4}())
# SVector(Vec{2,Float64}((-1.0, -1.0)), Vec{2,Float64}((1.0, -1.0)),
# Vec{2,Float64}((1.0, 1.0)), Vec{2,Float64}((-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) =
SVector(Vec{2,Float64}((0.0, 0.0)), Vec{2,Float64}((1.0, 0.0)), Vec{2,Float64}((0.0, 1.0)))
reference_coordinates(::Quadrilateral) =
SVector(Vec{2,Float64}((-1.0, -1.0)), Vec{2,Float64}((1.0, -1.0)),
Vec{2,Float64}((1.0, 1.0)), Vec{2,Float64}((-1.0, 1.0)))
# etc.
```
Each concrete topology must implement this.
"""
function reference_coordinates end
"""
edges(topology::AbstractTopology) -> NTuple{N, NTuple{2, Int}}
edges(topology) -> NTuple{M, NTuple{2, Int}}
Edge connectivity for the topology.
Edge connectivity (tuple of node index pairs).
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.
```
Each concrete topology must implement this.
"""
function edges end
"""
faces(topology::AbstractTopology) -> NTuple{N, NTuple{M, Int}}
faces(topology) -> NTuple{M, NTuple{K, Int}}
Face connectivity for 3D topologies.
Face connectivity for 3D topologies (tuple of node index tuples).
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.
```
Each concrete 3D topology must implement this.
"""
function faces end
"""
cells(topology) -> SVector{M, Cell}
Cell entities for the topology (typically one cell per element).
Each concrete topology must implement this.
"""
function cells end
"""
vertices(topology) -> SVector{M, Vertex}
Vertex entities for the topology.
Each concrete topology must implement this.
"""
function vertices end
# ============================================================================
# ENTITIES DISPATCHER
# ============================================================================
"""
entities(::Type{Topo}, ::Val{D}) where {Topo<:AbstractTopology, D}
Return entities of dimension D for the given topology.
Dispatches to dimension-specific functions:
- D=0 → vertices(topology)
- D=1 → edges(topology)
- D=2 → faces(topology)
- D=3 → cells(topology)
"""
entities(::Type{Topo}, ::Val{0}) where {Topo<:AbstractTopology} = vertices(Topo())
entities(::Type{Topo}, ::Val{1}) where {Topo<:AbstractTopology} = edges(Topo())
entities(::Type{Topo}, ::Val{2}) where {Topo<:AbstractTopology} = faces(Topo())
entities(::Type{Topo}, ::Val{3}) where {Topo<:AbstractTopology} = cells(Topo())
# Integer dimension interface
entities(topo::Type{<:AbstractTopology}, d::Int) = entities(topo, Val(d))
# ============================================================================
# TOPOLOGICAL ENTITIES - Typed structures for geometric primitives
# ============================================================================
"""
TopologicalEntity{D}
Abstract type for topological entities at dimension `D`.
# Type Parameters
- `D::Int`: Geometric dimension (0=vertex, 1=edge, 2=face, 3=cell)
# Concrete Types
- `Vertex`: 0-dimensional point entity
- `Edge`: 1-dimensional line entity (bounded by 2 vertices)
- `Face`: 2-dimensional surface entity (bounded by edges)
- `Cell`: 3-dimensional volume entity (bounded by faces)
"""
abstract type TopologicalEntity{D} end
"""
Vertex <: TopologicalEntity{0}
A 0-dimensional point entity (vertex/node).
"""
struct Vertex <: TopologicalEntity{0} end
"""
Edge <: TopologicalEntity{1}
A 1-dimensional line entity bounded by two vertices.
# Fields
- `vertices::NTuple{2, Int}`: Local vertex indices bounding this edge
"""
struct Edge <: TopologicalEntity{1}
vertices::NTuple{2, Int}
end
"""
Face <: TopologicalEntity{2}
A 2-dimensional surface entity bounded by edges.
# Fields
- `vertices::NTuple{N, Int}`: Local vertex indices bounding this face
"""
struct Face <: TopologicalEntity{2}
vertices::NTuple{N, Int} where N
end
"""
Cell <: TopologicalEntity{3}
A 3-dimensional volume entity (the element interior itself).
"""
struct Cell <: TopologicalEntity{3} end
# ============================================================================
# ENTITY DIMENSION QUERIES
# ============================================================================
"""
dim(::Type{<:TopologicalEntity{D}}) where D -> Int
Return the geometric dimension of an entity type.
"""
dim(::Type{<:TopologicalEntity{D}}) where {D} = D
# ============================================================================
# HELPER FUNCTIONS FOR ENTITY COUNTS
# ============================================================================
"""
nentities(::Type{Topo}, ::Type{<:TopologicalEntity{D}}) where {Topo<:AbstractTopology, D}
Return the number of entities of dimension D for the given topology.
"""
function nentities(::Type{Topo}, ::Type{E}) where {Topo<:AbstractTopology, E<:TopologicalEntity}
D = entity_dim(E)
return length(entities(Topo, D))
end
# Helper to extract dimension from entity type
entity_dim(::Type{<:Vertex}) = 0
entity_dim(::Type{<:Edge}) = 1
entity_dim(::Type{<:Face}) = 2
entity_dim(::Type{<:Cell}) = 3
+5 -5
View File
@@ -70,7 +70,7 @@ function reference_coordinates(::Hexahedron{27})
end
function edges(::T) where {T<:Hexahedron}
return SVector(Edge{T}.((
return SVector(Edge.((
(1, 2), (2, 3), (3, 4), (4, 1),
(5, 6), (6, 7), (7, 8), (8, 5),
(1, 5), (2, 6), (3, 7), (4, 8)
@@ -78,7 +78,7 @@ function edges(::T) where {T<:Hexahedron}
end
function faces(::T) where {T<:Hexahedron}
return SVector(Face{T}.((
return SVector(Face.((
(1, 4, 3, 2), (5, 6, 7, 8),
(1, 2, 6, 5), (2, 3, 7, 6),
(3, 4, 8, 7), (4, 1, 5, 8)
@@ -87,13 +87,13 @@ end
function vertices(::T) where {T<:Hexahedron}
return SVector(
Vertex{T}(), Vertex{T}(), Vertex{T}(), Vertex{T}(),
Vertex{T}(), Vertex{T}(), Vertex{T}(), Vertex{T}()
Vertex(), Vertex(), Vertex(), Vertex(),
Vertex(), Vertex(), Vertex(), Vertex()
)
end
function cells(::T) where {T<:Hexahedron}
return SVector(Cell{T}())
return SVector(Cell())
end
nvertices(::Hexahedron) = 8
+4 -4
View File
@@ -28,14 +28,14 @@ function reference_coordinates(::Pyramid{5})
end
function edges(::T) where {T<:Pyramid}
return SVector(Edge{T}.((
return SVector(Edge.((
(1, 2), (2, 3), (3, 4), (4, 1), # Base edges
(1, 5), (2, 5), (3, 5), (4, 5) # Edges to apex
)))
end
function faces(::T) where {T<:Pyramid}
return SVector(Face{T}.((
return SVector(Face.((
(1, 4, 3, 2), # Quad base
(1, 2, 5), # Triangle face 1
(2, 3, 5), # Triangle face 2
@@ -45,11 +45,11 @@ function faces(::T) where {T<:Pyramid}
end
function vertices(::T) where {T<:Pyramid}
return SVector(Vertex{T}(), Vertex{T}(), Vertex{T}(), Vertex{T}(), Vertex{T}())
return SVector(Vertex(), Vertex(), Vertex(), Vertex(), Vertex())
end
function cells(::T) where {T<:Pyramid}
return SVector(Cell{T}())
return SVector(Cell())
end
nvertices(::Pyramid) = 5
+4 -4
View File
@@ -57,22 +57,22 @@ function reference_coordinates(::Quadrilateral{9})
end
function edges(::T) where {T<:Quadrilateral}
return SVector(Edge{T}.((
return SVector(Edge.((
(1, 2), (2, 3),
(3, 4), (4, 1)
)))
end
function faces(::T) where {T<:Quadrilateral}
return SVector(Face{T}((1, 2, 3, 4)))
return SVector(Face((1, 2, 3, 4)))
end
function vertices(::T) where {T<:Quadrilateral}
return SVector(Vertex{T}(), Vertex{T}(), Vertex{T}(), Vertex{T}())
return SVector(Vertex(), Vertex(), Vertex(), Vertex())
end
function cells(::T) where {T<:Quadrilateral}
return SVector(Cell{T}())
return SVector(Cell())
end
nvertices(::Quadrilateral) = 4
+4 -4
View File
@@ -34,19 +34,19 @@ function reference_coordinates(::Segment{3})
end
function edges(::T) where {T<:Segment}
return SVector(Edge{T}((1, 2)))
return SVector(Edge((1, 2)))
end
function faces(::T) where {T<:Segment}
return SVector(Vertex{T}(), Vertex{T}()) # Endpoints are "faces" in 1D
return SVector(Vertex(), Vertex()) # Endpoints are "faces" in 1D
end
function vertices(::T) where {T<:Segment}
return SVector(Vertex{T}(), Vertex{T}())
return SVector(Vertex(), Vertex())
end
function cells(::T) where {T<:Segment}
return SVector(Cell{T}())
return SVector(Cell())
end
nvertices(::Segment) = 2
+6 -316
View File
@@ -2,69 +2,9 @@
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE
"""
Tetrahedron{N} <: AbstractTopology
Tetrahedron{N} <: AbstractTopology{N}
Parametric tetrahedral element topology (3D simplex).
The type parameter `N` specifies the total number of nodes in the element,
enabling compile-time dispatch and type-stable code generation.
# Type Parameter
- `N::Int`: Total number of nodes (4 or 10)
# Canonical Type Aliases
**Always use these aliases instead of constructing `Tetrahedron{N}` directly:**
- `Tet4 = Tetrahedron{4}` - Linear tetrahedron (P1, 4 corner nodes)
- `Tet10 = Tetrahedron{10}` - Quadratic tetrahedron (P2, 10 nodes: 4 corners + 6 edge midpoints)
# Why Parametric Types?
1. **Type Stability:** Each node count is a distinct type (`Tet4 !== Tet10`)
2. **Compile-Time Dispatch:** Kernel specialization for GPU performance
3. **Zero Allocation:** Node count known at compile time
4. **Clear API:** `nnodes(Tet10())` returns compile-time constant `10`
# Reference Element
```
N4 (0,0,1)
/|\\
/ | \\
/ | \\
/ | \\
N1---+----N3
(0,0,0) (0,1,0)
\\ /
\\/
N2 (1,0,0)
```
# Topology Properties
- Dimension: 3
- Corner nodes: 4
- Edges: 6
- Faces: 4 (triangular)
# Typical Usage
```julia
julia> topology = Tet10() # Use canonical alias
julia> nnodes(topology) # Returns compile-time constant
10
julia> Tet4 !== Tet10 # Type stability check
true
julia> reference_coordinates(Tet4()) # Corner nodes only
((0.0, 0.0, 0.0), (1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0))
```
# Design Notes
- Separates topology (geometric shape) from interpolation (basis functions)
- Corner node positions are ALWAYS the same (4 nodes)
- Intermediate nodes (edge midpoints) depend on `N` parameter
- Use `reference_coordinates(Tet10())` to get ALL 10 node positions
# Type Parameter
Node count comes from mesh connectivity. Type parameter enables compile-time optimization.
Tetrahedral topology with N nodes.
# Node Count Variants
- `Tetrahedron{4}` (alias `Tet4`): Linear tetrahedron (P1 Lagrange)
@@ -72,121 +12,12 @@ Node count comes from mesh connectivity. Type parameter enables compile-time opt
"""
struct Tetrahedron{N} <: AbstractTopology{N} end
# ============================================================================
# CANONICAL TYPE ALIASES (PRIMARY API)
# ============================================================================
"""
Tet4 = Tetrahedron{4}
Linear tetrahedron with 4 corner nodes (P1 interpolation).
**Reference Coordinates:**
- Node 1: (0.0, 0.0, 0.0) - Origin
- Node 2: (1.0, 0.0, 0.0) - Along ξ-axis
- Node 3: (0.0, 1.0, 0.0) - Along η-axis
- Node 4: (0.0, 0.0, 1.0) - Along ζ-axis
**Use this alias everywhere** instead of `Tetrahedron{4}`.
"""
const Tet4 = Tetrahedron{4}
"""
Tet10 = Tetrahedron{10}
Quadratic tetrahedron with 10 nodes (P2 interpolation).
**Node Layout:**
- Nodes 1-4: Corner nodes (same as Tet4)
- Nodes 5-10: Edge midpoints
**Use this alias everywhere** instead of `Tetrahedron{10}`.
"""
const Tet10 = Tetrahedron{10}
# ============================================================================
# CORE TOPOLOGY INTERFACE
# ============================================================================
"""
nnodes(::Tetrahedron{N}) where N -> Int
Return total number of nodes for parametric tetrahedron topology.
This is a **compile-time constant** enabling type-stable dispatch.
# Returns
- `N`: Node count specified by type parameter (4 or 10)
# Examples
```julia
julia> nnodes(Tet4()) # Returns compile-time constant 4
4
julia> nnodes(Tet10()) # Returns compile-time constant 10
10
julia> @allocated nnodes(Tet10()) # Zero allocation
0
```
# Performance Note
This function returns a compile-time constant, enabling:
- Zero-cost abstraction (compiler eliminates call)
- Fully specialized code generation
- Static memory allocation in GPU kernels
"""
nnodes(::Tetrahedron{N}) where {N} = N
"""
dim(::Tetrahedron{N}) where N -> Int
Return spatial dimension of tetrahedron reference element (always 3).
# Returns
- `3`: Tetrahedra exist in 3D space
# Examples
```julia
julia> dim(Tet4())
3
julia> dim(Tet10()) # Same for all tetrahedron types
3
```
"""
dim(::Tetrahedron{N}) where {N} = 3
# ============================================================================
# REFERENCE COORDINATES (Full Node Positions)
# ============================================================================
"""
reference_coordinates(::Tetrahedron{4}) -> SVector{4, Vec{3,Float64}}
Return reference coordinates for linear tetrahedron (Tet4) - 4 corner nodes only.
# Returns
Tuple of 4 coordinate triples: ((ξ₁, η₁, ζ₁), (ξ₂, η₂, ζ₂), (ξ₃, η₃, ζ₃), (ξ₄, η₄, ζ₄))
# Node Positions
```
N4 (0,0,1)
/|\\
/ | \\
/ | \\
/ | \\
N1---+----N3
(0,0,0) (0,1,0)
\\ /
\\/
N2 (1,0,0)
```
- Node 1: (0.0, 0.0, 0.0) - Origin
- Node 2: (1.0, 0.0, 0.0) - Along ξ-axis
- Node 3: (0.0, 1.0, 0.0) - Along η-axis
- Node 4: (0.0, 0.0, 1.0) - Along ζ-axis
"""
function reference_coordinates(::Tetrahedron{4})
return SVector(Vec{3,Float64}.((
(0.0, 0.0, 0.0), # N1: Corner at origin
@@ -196,20 +27,6 @@ function reference_coordinates(::Tetrahedron{4})
)))
end
"""
reference_coordinates(::Tetrahedron{10}) -> SVector{10, Vec{3,Float64}}
Return reference coordinates for quadratic tetrahedron (Tet10) - 10 nodes total.
# Node Layout
- Nodes 1-4: Corner nodes (same as Tet4)
- Node 5: Edge midpoint between N1-N2 (0.5, 0.0, 0.0)
- Node 6: Edge midpoint between N2-N3 (0.5, 0.5, 0.0)
- Node 7: Edge midpoint between N3-N1 (0.0, 0.5, 0.0)
- Node 8: Edge midpoint between N1-N4 (0.0, 0.0, 0.5)
- Node 9: Edge midpoint between N2-N4 (0.5, 0.0, 0.5)
- Node 10: Edge midpoint between N3-N4 (0.0, 0.5, 0.5)
"""
function reference_coordinates(::Tetrahedron{10})
return SVector(Vec{3,Float64}.((
(0.0, 0.0, 0.0), # N1: Corner
@@ -225,42 +42,8 @@ function reference_coordinates(::Tetrahedron{10})
)))
end
# ============================================================================
# TOPOLOGICAL CONNECTIVITY (Typed Entities)
# ============================================================================
"""
edges(::T) where T <: Tetrahedron -> SVector{6, Edge{T}}
Return typed edge entities for tetrahedron.
Returns an `SVector` of `Edge{T}` instances. Position in the vector IS the edge ID.
# Returns
6 edges, each containing the vertex indices that bound the edge:
- Edge 1: vertices (1, 2)
- Edge 2: vertices (2, 3)
- Edge 3: vertices (3, 1)
- Edge 4: vertices (1, 4)
- Edge 5: vertices (2, 4)
- Edge 6: vertices (3, 4)
# Examples
```julia
edges_list = edges(Tet4())
# edges_list[1] is Edge 1, bounded by vertices (1,2)
# edges_list[3] is Edge 3, bounded by vertices (3,1)
# Extract from DOF type
DOF{Vec{3}, Edge{Tet4}}
entity_list = entities(Edge{Tet4}) # Type carries all info!
```
# Note
Same for all tetrahedron types (Tet4, Tet10) - topologically identical.
"""
function edges(::T) where {T<:Tetrahedron}
return SVector(Edge{T}.((
return SVector(Edge.((
(1, 2),
(2, 3),
(3, 1),
@@ -270,36 +53,8 @@ function edges(::T) where {T<:Tetrahedron}
)))
end
"""
faces(::T) where T <: Tetrahedron -> SVector{4, Face{T}}
Return typed face entities for tetrahedron.
Returns an `SVector` of `Face{T}` instances. Position in the vector IS the face ID.
# Returns
4 triangular faces, each containing the vertex indices that bound the face:
- Face 1: vertices (1, 3, 2)
- Face 2: vertices (1, 2, 4)
- Face 3: vertices (2, 3, 4)
- Face 4: vertices (3, 1, 4)
# Examples
```julia
faces_list = faces(Tet4())
# faces_list[1] is Face 1, bounded by vertices (1,3,2)
# faces_list[4] is Face 4, bounded by vertices (3,1,4)
# Extract from DOF type
DOF{Vec{3}, Face{Tet4}}
entity_list = entities(Face{Tet4}) # Type carries all info!
```
# Note
Same for all tetrahedron types (Tet4, Tet10) - topologically identical.
"""
function faces(::T) where {T<:Tetrahedron}
return SVector(Face{T}.((
return SVector(Face.((
(1, 3, 2),
(1, 2, 4),
(2, 3, 4),
@@ -307,81 +62,16 @@ function faces(::T) where {T<:Tetrahedron}
)))
end
"""
vertices(::T) where T <: Tetrahedron -> SVector{4, Vertex{T}}
Return typed vertex entities for tetrahedron.
Returns an `SVector` of `Vertex{T}` instances. Position in the vector IS the vertex ID.
# Returns
4 vertices (the corner nodes)
# Examples
```julia
verts = vertices(Tet4())
# verts[1] is Vertex 1
# verts[2] is Vertex 2
# etc.
# Extract from DOF type (Lagrange elements)
DOF{Float64, Vertex{Tet4}}
entity_list = entities(Vertex{Tet4}) # Type carries all info!
```
"""
function vertices(::T) where {T<:Tetrahedron}
return SVector(Vertex{T}(), Vertex{T}(), Vertex{T}(), Vertex{T}())
return SVector(Vertex(), Vertex(), Vertex(), Vertex())
end
"""
cells(::T) where T <: Tetrahedron -> SVector{1, Cell{T}}
Return typed cell entity for tetrahedron (the element interior itself).
Returns an `SVector` with one `Cell{T}` instance (the tetrahedron volume).
# Examples
```julia
cell_list = cells(Tet4())
# cell_list[1] is the Cell (the tetrahedron interior)
# Extract from DOF type (DG elements)
DOF{Float64, Cell{Tet4}}
entity_list = entities(Cell{Tet4}) # Type carries all info!
```
"""
function cells(::T) where {T<:Tetrahedron}
return SVector(Cell{T}())
return SVector(Cell())
end
# ============================================================================
# ENTITY COUNT HELPERS
# ============================================================================
"""
nvertices(::Tetrahedron) -> Int
Return number of vertices (corner nodes) - always 4 for tetrahedra.
"""
nvertices(::Tetrahedron) = 4
"""
nedges(::Tetrahedron) -> Int
Return number of edges - always 6 for tetrahedra.
"""
nedges(::Tetrahedron) = 6
"""
nfaces(::Tetrahedron) -> Int
Return number of faces - always 4 for tetrahedra.
"""
nfaces(::Tetrahedron) = 4
# ============================================================================
# EXPORTS
# ============================================================================
# Export ONLY canonical aliases (not the parametric struct)
export Tet4, Tet10
-286
View File
@@ -1,286 +0,0 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
"""
Topology module - topological entities and helpers.
Abstract type and interface are defined in topology/api.jl.
This file defines the typed entity system for vertices, edges, faces, and cells.
"""
# NOTE: AbstractTopology{N} and interface functions (nnodes, dim, reference_coordinates, edges, faces)
# are now defined in topology/api.jl, which is included before this file in JuliaFEM.jl
# ============================================================================
# TOPOLOGICAL ENTITIES - Typed structures for geometric primitives
# ============================================================================
"""
TopologicalEntity{D, Topo}
Abstract type for topological entities at dimension `D` belonging to topology `Topo`.
# Type Parameters
- `D::Int`: Geometric dimension (0=vertex, 1=edge, 2=face, 3=cell)
- `Topo <: AbstractTopology`: The topology type this entity belongs to
# Concrete Types
- `Vertex{Topo}`: 0-dimensional point entity
- `Edge{Topo}`: 1-dimensional line entity (bounded by 2 vertices)
- `Face{Topo}`: 2-dimensional surface entity (bounded by edges)
- `Cell{Topo}`: 3-dimensional volume entity (bounded by faces)
# Philosophy
Entities are **topological** (connectivity) not **geometric** (coordinates).
They define "what connects to what" independent of "where things are".
# Usage with DOF System
The entity type encodes WHERE degrees of freedom live:
```julia
# Lagrange elements: DOFs on vertices
DOF{Float64, Vertex{Tet4}}
# Nedelec elements: DOFs on edges
DOF{Vec{3}, Edge{Tet4}}
# Raviart-Thomas elements: DOFs on faces
DOF{Vec{3}, Face{Tet4}}
# Discontinuous Galerkin: DOFs in cell interior
DOF{Float64, Cell{Tet4}}
```
The type parameter carries complete compile-time information:
- Quantity type (Float64, Vec{3}, etc.)
- Location (Vertex, Edge, Face, Cell)
- Topology (which element type)
# Entity Position as ID
Entities do NOT carry an explicit `id` field. Instead, position in the
returned vector IS the entity ID:
```julia
edge_list = entities(Edge{Tet4})
# edge_list[1] is Edge 1
# edge_list[2] is Edge 2
# etc.
```
This enables zero-allocation, type-stable queries.
"""
abstract type TopologicalEntity{D, Topo <: AbstractTopology} end
"""
Vertex{Topo} <: TopologicalEntity{0, Topo}
A 0-dimensional point entity (vertex/node).
Vertices are the corner points of an element. Position in the vertex
list IS the vertex ID (no explicit id field needed).
# Examples
```julia
vertex_list = vertices(Tet4())
# vertex_list[1] is Vertex 1 (at local index 1)
# vertex_list[2] is Vertex 2 (at local index 2)
# etc.
# Or use generic interface
vertices = entities(Vertex{Tet4})
```
"""
struct Vertex{Topo} <: TopologicalEntity{0, Topo} end
"""
Edge{Topo} <: TopologicalEntity{1, Topo}
A 1-dimensional line entity bounded by two vertices.
Edges connect pairs of vertices. Position in the edge list IS the edge ID.
# Fields
- `vertices::NTuple{2, Int}`: Local vertex indices bounding this edge
# Examples
```julia
edge_list = edges(Tet4())
# edge_list[1] is Edge 1, connects vertices edge_list[1].vertices
# edge_list[3] is Edge 3, connects vertices edge_list[3].vertices
# Or use generic interface
edges = entities(Edge{Tet4})
# Usage in DOF Systems
```julia
# Nedelec edge elements
DOF{Vec{3}, Edge{Tet4}} # Vector DOF on each edge of Tet4
```
"""
struct Edge{Topo} <: TopologicalEntity{1, Topo}
vertices::NTuple{2, Int}
end
"""
Face{Topo} <: TopologicalEntity{2, Topo}
A 2-dimensional surface entity bounded by edges.
Faces are surfaces (triangles, quadrilaterals) that bound a volume.
Position in the face list IS the face ID.
# Fields
- `vertices::NTuple{N, Int}`: Local vertex indices bounding this face (N=3 for triangle, N=4 for quad)
# Examples
```julia
face_list = faces(Tet4())
# face_list[1] is Face 1, vertices at face_list[1].vertices
# face_list[2] is Face 2, vertices at face_list[2].vertices
# Or use generic interface
faces = entities(Face{Tet4})
# Usage in DOF Systems
```julia
# Raviart-Thomas face elements
DOF{Vec{3}, Face{Tet4}} # Vector DOF on each face of Tet4
```
"""
struct Face{Topo} <: TopologicalEntity{2, Topo}
vertices::NTuple{N, Int} where N
end
"""
Cell{Topo} <: TopologicalEntity{3, Topo}
A 3-dimensional volume entity (the element interior itself).
For most elements, there is exactly one cell - the element itself.
Position in the cell list IS the cell ID (typically just one cell).
# Examples
```julia
cell_list = cells(Tet4())
# cell_list[1] is the Cell (the tetrahedron interior)
# Or use generic interface
cells = entities(Cell{Tet4})
# Usage in DOF Systems
```julia
# Discontinuous Galerkin elements
DOF{Float64, Cell{Tet4}} # Scalar DOF in element interior
```
"""
struct Cell{Topo} <: TopologicalEntity{3, Topo} end
# ============================================================================
# ENTITY DIMENSION QUERIES
# ============================================================================
"""
dim(::Type{<:TopologicalEntity{D}}) where D -> Int
Return the geometric dimension of an entity type.
# Examples
```julia
dim(Vertex{Tet4}) # 0
dim(Edge{Tet4}) # 1
dim(Face{Tet4}) # 2
dim(Cell{Tet4}) # 3
```
"""
dim(::Type{<:TopologicalEntity{D}}) where {D} = D
# ============================================================================
# ENTITY QUERIES - Type-based dispatch
# ============================================================================
"""
topology_type(::Type{<:TopologicalEntity{D, Topo}}) where {D, Topo}
Extract the topology type from an entity type.
# Examples
```julia
topology_type(Edge{Tet4}) # Tet4
topology_type(Face{Tet10}) # Tet10
topology_type(Vertex{Hex8}) # Hex8
```
"""
topology_type(::Type{<:TopologicalEntity{D, Topo}}) where {D, Topo} = Topo
"""
entities(::Type{Entity}) where Entity <: TopologicalEntity
Return a vector of all entities of the given type.
Topology is extracted from the entity type parameter - no need to pass it separately!
# Arguments
- `Entity`: Entity type (e.g., `Edge{Tet4}`, `Face{Tet4}`)
# Returns
`SVector` of entity instances. Position in vector IS the entity ID.
# Examples
```julia
# Direct entity queries (topology embedded in type)
vertices = entities(Vertex{Tet4}) # 4 vertices
edges = entities(Edge{Tet4}) # 6 edges
faces = entities(Face{Tet4}) # 4 faces
cells = entities(Cell{Tet4}) # 1 cell
# Extract from DOF type
dof_type = DOF{Vec{3}, Edge{Tet4}}
entity_type = typeof(dof_type).parameters[2] # Edge{Tet4}
edges = entities(entity_type) # Type carries all info!
```
# Design Philosophy
The entity type `Edge{Tet4}` already contains the topology `Tet4` as a type parameter.
No need to pass topology separately - just extract it from the type!
```julia
entities(Edge{Tet4}) # Type carries all information
entities(Face{Hex8}) # Clean and concise
```
# Implementation Note
Each topology type must provide `vertices()`, `edges()`, `faces()`, and optionally
`cells()` methods that return `SVector` of the corresponding entity types.
The generic `entities()` dispatcher extracts the topology and routes to these methods.
"""
function entities end
# Extract topology from entity type and dispatch
entities(::Type{Vertex{T}}) where {T<:AbstractTopology} = vertices(T())
entities(::Type{Edge{T}}) where {T<:AbstractTopology} = edges(T())
entities(::Type{Face{T}}) where {T<:AbstractTopology} = faces(T())
entities(::Type{Cell{T}}) where {T<:AbstractTopology} = cells(T())
# ============================================================================
# HELPER FUNCTIONS FOR ENTITY COUNTS
# ============================================================================
"""
nentities(::Type{Entity}) where Entity <: TopologicalEntity
Return the number of entities of the given type.
# Examples
```julia
nentities(Vertex{Tet4}) # 4
nentities(Edge{Tet4}) # 6
nentities(Face{Tet4}) # 4
nentities(Cell{Tet4}) # 1
```
"""
nentities(entity_type::Type{<:TopologicalEntity}) = length(entities(entity_type))
+11 -277
View File
@@ -2,213 +2,26 @@
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
"""
Triangle{N} <: AbstractTopology
Triangle{N} <: AbstractTopology{N}
Parametric triangular element topology in 2D.
Triangular topology with N nodes.
The type parameter `N` specifies the total number of nodes in the element,
enabling compile-time dispatch and type-stable code generation.
# Type Parameter
- `N::Int`: Total number of nodes (3, 6, 7, or 10)
# Canonical Type Aliases
**Always use these aliases instead of constructing `Triangle{N}` directly:**
- `Tri3 = Triangle{3}` - Linear triangle (P1, 3 corner nodes)
- `Tri6 = Triangle{6}` - Quadratic triangle (P2, 6 nodes: 3 corners + 3 edge midpoints)
- `Tri7 = Triangle{7}` - Quadratic triangle with centroid (3 corners + 3 edge midpoints + 1 center)
- `Tri10 = Triangle{10}` - Cubic triangle (P3, 10 nodes)
# Why Parametric Types?
1. **Type Stability:** Each node count is a distinct type (`Tri3 !== Tri6`)
2. **Compile-Time Dispatch:** Kernel specialization for GPU performance
3. **Zero Allocation:** Node count known at compile time
4. **Clear API:** `nnodes(Tri6())` returns compile-time constant `6`
# Reference Element
```
η
^
|
(0,1) N3
| \\
| \\
| \\
+---------> ξ
(0,0) (1,0)
N1 N2
```
# Topology Properties
- Dimension: 2
- Corner nodes: 3
- Edges: 3
- Faces: 1 (the element itself in 2D)
# Typical Usage
```julia
julia> topology = Tri6() # Use canonical alias
julia> nnodes(topology) # Returns compile-time constant
6
julia> Tri3 !== Tri6 # Type stability check
true
julia> reference_coordinates(Tri3()) # Corner nodes only
((0.0, 0.0), (1.0, 0.0), (0.0, 1.0))
```
# Design Notes
- Separates topology (geometric shape) from interpolation (basis functions)
- Corner node positions are ALWAYS the same (3 nodes)
- Intermediate nodes (edge/face) depend on `N` parameter
- Use `reference_coordinates(Tri6())` to get ALL 6 node positions
# Node Count Variants
- `Triangle{3}` (alias `Tri3`): Linear triangle (P1 Lagrange)
- `Triangle{6}` (alias `Tri6`): Quadratic triangle (P2 Lagrange)
- `Triangle{7}` (alias `Tri7`): Quadratic triangle with centroid (P2)
- `Triangle{10}` (alias `Tri10`): Cubic triangle (P3 Lagrange)
"""
struct Triangle{N} <: AbstractTopology{N} end
# ============================================================================
# CANONICAL TYPE ALIASES (PRIMARY API)
# ============================================================================
"""
Tri3 = Triangle{3}
Linear triangle with 3 corner nodes (P1 interpolation).
**Reference Coordinates:**
- Node 1: (0.0, 0.0) - Origin
- Node 2: (1.0, 0.0) - Along ξ-axis
- Node 3: (0.0, 1.0) - Along η-axis
**Use this alias everywhere** instead of `Triangle{3}`.
"""
const Tri3 = Triangle{3}
"""
Tri6 = Triangle{6}
Quadratic triangle with 6 nodes (P2 interpolation).
**Node Layout:**
- Nodes 1-3: Corner nodes (same as Tri3)
- Nodes 4-6: Edge midpoints
**Use this alias everywhere** instead of `Triangle{6}`.
"""
const Tri6 = Triangle{6}
"""
Tri7 = Triangle{7}
Quadratic triangle with 7 nodes (includes face centroid).
**Node Layout:**
- Nodes 1-3: Corner nodes
- Nodes 4-6: Edge midpoints
- Node 7: Face centroid
**Use this alias everywhere** instead of `Triangle{7}`.
"""
const Tri7 = Triangle{7}
"""
Tri10 = Triangle{10}
Cubic triangle with 10 nodes (P3 interpolation).
**Node Layout:**
- Nodes 1-3: Corner nodes
- Nodes 4-9: Two nodes per edge (at 1/3 and 2/3 positions)
- Node 10: Face centroid
**Use this alias everywhere** instead of `Triangle{10}`.
"""
const Tri10 = Triangle{10}
# ============================================================================
# CORE TOPOLOGY INTERFACE
# ============================================================================
"""
nnodes(::Triangle{N}) where N -> Int
Return total number of nodes for parametric triangle topology.
This is a **compile-time constant** enabling type-stable dispatch.
# Returns
- `N`: Node count specified by type parameter (3, 6, 7, or 10)
# Examples
```julia
julia> nnodes(Tri3()) # Returns compile-time constant 3
3
julia> nnodes(Tri6()) # Returns compile-time constant 6
6
julia> @allocated nnodes(Tri6()) # Zero allocation
0
```
# Performance Note
This function returns a compile-time constant, enabling:
- Zero-cost abstraction (compiler eliminates call)
- Fully specialized code generation
- Static memory allocation in GPU kernels
"""
nnodes(::Triangle{N}) where {N} = N
"""
dim(::Triangle{N}) where N -> Int
Return spatial dimension of triangle reference element (always 2).
# Returns
- `2`: Triangles exist in 2D space
# Examples
```julia
julia> dim(Tri3())
2
julia> dim(Tri10()) # Same for all triangle types
2
```
"""
dim(::Triangle{N}) where {N} = 2
# ============================================================================
# REFERENCE COORDINATES (Full Node Positions)
# ============================================================================
"""
reference_coordinates(::Triangle{3}) -> SVector{3, Vec{2,Float64}}
Return reference coordinates for linear triangle (Tri3) - 3 corner nodes only.
# Returns
Tuple of 3 coordinate pairs: ((ξ₁, η₁), (ξ₂, η₂), (ξ₃, η₃))
# Node Positions
```
η
^
|
(0,1) N3
| \\
| \\
| \\
+---------> ξ
(0,0) (1,0)
N1 N2
```
- Node 1: (0.0, 0.0) - Origin
- Node 2: (1.0, 0.0) - Along ξ-axis
- Node 3: (0.0, 1.0) - Along η-axis
"""
function reference_coordinates(::Triangle{3})
return SVector(Vec{2,Float64}.((
(0.0, 0.0), # N1: Corner at origin
@@ -217,18 +30,6 @@ function reference_coordinates(::Triangle{3})
)))
end
"""
reference_coordinates(::Triangle{6}) -> SVector{6, Vec{2,Float64}}
Return reference coordinates for quadratic triangle (Tri6) - 6 nodes total.
# Node Layout
- Nodes 1-3: Corner nodes (same as Tri3)
- Node 4: Edge midpoint between N1-N2 (0.5, 0.0)
- Node 5: Edge midpoint between N2-N3 (0.5, 0.5)
- Node 6: Edge midpoint between N3-N1 (0.0, 0.5)
"""
function reference_coordinates(::Triangle{6})
return SVector(Vec{2,Float64}.((
(0.0, 0.0), # N1: Corner
@@ -240,17 +41,6 @@ function reference_coordinates(::Triangle{6})
)))
end
"""
reference_coordinates(::Triangle{7}) -> SVector{7, Vec{2,Float64}}
Return reference coordinates for quadratic triangle with centroid (Tri7).
# Node Layout
- Nodes 1-3: Corner nodes
- Nodes 4-6: Edge midpoints
- Node 7: Face centroid (1/3, 1/3)
"""
function reference_coordinates(::Triangle{7})
return SVector(Vec{2,Float64}.((
(0.0, 0.0), # N1: Corner
@@ -263,20 +53,6 @@ function reference_coordinates(::Triangle{7})
)))
end
"""
reference_coordinates(::Triangle{10}) -> SVector{10, Vec{2,Float64}}
Return reference coordinates for cubic triangle (Tri10) - 10 nodes total.
# Node Layout
- Nodes 1-3: Corner nodes
- Nodes 4-9: Two nodes per edge (at 1/3 and 2/3)
- Edge 1-2: N4 (1/3, 0), N5 (2/3, 0)
- Edge 2-3: N6 (2/3, 1/3), N7 (1/3, 2/3)
- Edge 3-1: N8 (0, 2/3), N9 (0, 1/3)
- Node 10: Face centroid (1/3, 1/3)
"""
function reference_coordinates(::Triangle{10})
return SVector(Vec{2,Float64}.((
(0.0, 0.0), # N1: Corner
@@ -292,70 +68,28 @@ function reference_coordinates(::Triangle{10})
)))
end
# ============================================================================
# TOPOLOGICAL CONNECTIVITY (Corner Nodes Only)
# ============================================================================
"""
edges(::Triangle{N}) where N -> NTuple{3, NTuple{2, Int}}
Return edge connectivity (pairs of **corner node indices**) for triangle.
This is TOPOLOGICAL connectivity, independent of interpolation order.
# Returns
3-tuple of edge definitions:
- Edge 1: (1, 2) - Bottom edge (N1 → N2)
- Edge 2: (2, 3) - Diagonal edge (N2 → N3)
- Edge 3: (3, 1) - Left edge (N3 → N1)
# Note
- Only references **corner nodes** (1, 2, 3)
- Direction: Counter-clockwise
- Same for all triangle types (Tri3, Tri6, Tri7, Tri10)
"""
function edges(::T) where {T<:Triangle}
return SVector(Edge{T}.((
return SVector(Edge.((
(1, 2), # Edge 1: Bottom
(2, 3), # Edge 2: Diagonal
(3, 1) # Edge 3: Left
)))
end
"""
faces(::T) where T <: Triangle -> SVector{1, Face{T}}
Return face entity for triangle.
In 2D, the "face" is the element itself (all 3 **corner nodes**).
# Returns
1-element vector containing the triangular face
# Note
- Only references corner nodes
- Single face represents entire surface
- API consistency with 3D elements
"""
function faces(::T) where {T<:Triangle}
return SVector(Face{T}((1, 2, 3)))
return SVector(Face((1, 2, 3)))
end
function vertices(::T) where {T<:Triangle}
return SVector(Vertex{T}(), Vertex{T}(), Vertex{T}())
return SVector(Vertex(), Vertex(), Vertex())
end
function cells(::T) where {T<:Triangle}
return SVector(Cell{T}())
return SVector(Cell())
end
nvertices(::Triangle) = 3
nedges(::Triangle) = 3
nfaces(::Triangle) = 1
# ============================================================================
# EXPORTS
# ============================================================================
# Export ONLY canonical aliases (not the parametric struct)
export Tri3, Tri6, Tri7, Tri10
+5 -5
View File
@@ -52,7 +52,7 @@ function reference_coordinates(::Wedge{15})
end
function edges(::T) where {T<:Wedge}
return SVector(Edge{T}.((
return SVector(Edge.((
(1, 2), (2, 3), (3, 1), # Bottom triangle
(4, 5), (5, 6), (6, 4), # Top triangle
(1, 4), (2, 5), (3, 6) # Vertical edges
@@ -60,7 +60,7 @@ function edges(::T) where {T<:Wedge}
end
function faces(::T) where {T<:Wedge}
return SVector(Face{T}.((
return SVector(Face.((
(1, 3, 2), # Bottom triangle
(4, 5, 6), # Top triangle
(1, 2, 5, 4), # Quad face 1
@@ -71,13 +71,13 @@ end
function vertices(::T) where {T<:Wedge}
return SVector(
Vertex{T}(), Vertex{T}(), Vertex{T}(),
Vertex{T}(), Vertex{T}(), Vertex{T}()
Vertex(), Vertex(), Vertex(),
Vertex(), Vertex(), Vertex()
)
end
function cells(::T) where {T<:Wedge}
return SVector(Cell{T}())
return SVector(Cell())
end
nvertices(::Wedge) = 6