mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-08-19 11:43:47 +00:00
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:
+176
-288
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user