diff --git a/src/topology/api.jl b/src/topology/api.jl index 9ab6828..7c5b891 100644 --- a/src/topology/api.jl +++ b/src/topology/api.jl @@ -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 diff --git a/src/topology/hexahedra.jl b/src/topology/hexahedra.jl index ccd193d..fbde93d 100644 --- a/src/topology/hexahedra.jl +++ b/src/topology/hexahedra.jl @@ -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 diff --git a/src/topology/pyramids.jl b/src/topology/pyramids.jl index 51ec1ab..dea7813 100644 --- a/src/topology/pyramids.jl +++ b/src/topology/pyramids.jl @@ -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 diff --git a/src/topology/quadrilaterals.jl b/src/topology/quadrilaterals.jl index f06adfa..b893ec7 100644 --- a/src/topology/quadrilaterals.jl +++ b/src/topology/quadrilaterals.jl @@ -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 diff --git a/src/topology/segments.jl b/src/topology/segments.jl index 80cd2c4..cf0ddc1 100644 --- a/src/topology/segments.jl +++ b/src/topology/segments.jl @@ -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 diff --git a/src/topology/tetrahedra.jl b/src/topology/tetrahedra.jl index 1e4edc6..682331e 100644 --- a/src/topology/tetrahedra.jl +++ b/src/topology/tetrahedra.jl @@ -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 diff --git a/src/topology/topology.jl b/src/topology/topology.jl deleted file mode 100644 index 0b22373..0000000 --- a/src/topology/topology.jl +++ /dev/null @@ -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)) diff --git a/src/topology/triangles.jl b/src/topology/triangles.jl index 64cfae0..64170c3 100644 --- a/src/topology/triangles.jl +++ b/src/topology/triangles.jl @@ -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 diff --git a/src/topology/wedges.jl b/src/topology/wedges.jl index eb53d07..85eb1e4 100644 --- a/src/topology/wedges.jl +++ b/src/topology/wedges.jl @@ -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