mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-10-02 14:23:58 +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
|
||||
|
||||
Reference in New Issue
Block a user