mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-23 11:02:36 +00:00
08f67d273d
New 166-line test file for variadic MixedDOF type system: - Tests type-level multi-field composition with @MixedDOF macro - Validates DOF indices structure (tuple of tuples, not NamedTuple) - Tests DOF sharing between elements for different entity types - Compares MixedDOF (vararg) vs NamedTuple approaches - Demonstrates 4-field mixed system: Temperature, Displacement, Pressure, Electric potential on different entities Validates variadic approach to multi-field elements where DOF types are mixed as type parameters rather than named fields.
167 lines
7.2 KiB
Julia
167 lines
7.2 KiB
Julia
# This file is a part of JuliaFEM.
|
||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE
|
||
|
||
"""
|
||
Test for variadic MixedDOF type - combining multiple DOF types at type level.
|
||
|
||
This demonstrates the **vararg** approach to multi-field elements, where you
|
||
mix DOF types together as type parameters (not with field names).
|
||
"""
|
||
|
||
using Test
|
||
using JuliaFEM
|
||
using JuliaFEM: Vertex, Edge, Cell, DOF, MixedDOF, create_elements!
|
||
using Tensors
|
||
|
||
@testset "🎯 MixedDOF: Variadic Multi-Field Elements" begin
|
||
|
||
# Create minimal mesh: 2 tetrahedra sharing a face
|
||
# Nodes: 1-5 (vertex IDs)
|
||
nodes = [
|
||
Vec(0.0, 0.0, 0.0), # 1
|
||
Vec(1.0, 0.0, 0.0), # 2
|
||
Vec(0.0, 1.0, 0.0), # 3
|
||
Vec(0.0, 0.0, 1.0), # 4
|
||
Vec(1.0, 1.0, 1.0), # 5
|
||
]
|
||
|
||
connectivity = [
|
||
(UInt32(1), UInt32(2), UInt32(3), UInt32(4)), # Tet 1
|
||
(UInt32(2), UInt32(3), UInt32(4), UInt32(5)), # Tet 2
|
||
]
|
||
|
||
mesh = Mesh{4, Tetrahedron{4}}(nodes, connectivity)
|
||
|
||
println("\n" * "="^70)
|
||
println("🎯 VARIADIC MixedDOF: Type-Level Multi-Field Composition")
|
||
println("="^70)
|
||
|
||
# ========================================================================
|
||
# Define MixedDOF with 4 fields (NO field names, just types!)
|
||
# ========================================================================
|
||
|
||
println("\n📋 Defining MixedDOF (variadic, type-level)...")
|
||
|
||
# Simple syntax - no need to repeat DOF!
|
||
mixed_type = @MixedDOF{
|
||
(Float64, Vertex), # Field 1: Temperature at vertices
|
||
(Vec{3}, Vertex), # Field 2: Displacement at vertices
|
||
(Float64, Cell), # Field 3: Pressure at cells
|
||
(Float64, Edge) # Field 4: Electric potential on edges
|
||
}
|
||
|
||
println(" Type: $mixed_type")
|
||
println(" ✓ 4 DOF types mixed together")
|
||
println(" ✓ Access by position (tuple unpacking)")
|
||
println(" ✓ Simple syntax: @MixedDOF{(Float64, Vertex), (Vec{3}, Vertex), ...}")
|
||
|
||
# ========================================================================
|
||
# Create elements with MixedDOF
|
||
# ========================================================================
|
||
|
||
println("\n🏗️ Creating elements...")
|
||
|
||
eltype = Element{Tetrahedron{4}, Lagrange{1}, mixed_type}
|
||
elements, mgr = create_elements!(mesh, eltype)
|
||
|
||
println(" ✓ Created $(length(elements)) elements")
|
||
@test length(elements) == 2
|
||
|
||
# ========================================================================
|
||
# Test DOF indices structure (tuple of tuples, NOT NamedTuple!)
|
||
# ========================================================================
|
||
|
||
println("\n🔍 Examining DOF indices...")
|
||
|
||
elem = first(elements)
|
||
println(" Element 1 DOF indices type: $(typeof(elem.dof_indices))")
|
||
@test elem.dof_indices isa Tuple
|
||
@test length(elem.dof_indices) == 4 # 4 fields
|
||
|
||
# Unpack by position
|
||
T_dofs, u_dofs, p_dofs, φ_dofs = elem.dof_indices
|
||
|
||
println(" ✓ Temperature DOFs: $T_dofs")
|
||
println(" ✓ Displacement DOFs: $u_dofs")
|
||
println(" ✓ Pressure DOFs: $p_dofs")
|
||
println(" ✓ Electric DOFs: $φ_dofs")
|
||
|
||
# Validate structure
|
||
@test length(T_dofs) == 4 # 4 vertices
|
||
@test length(u_dofs) == 12 # 4 vertices × 3 components
|
||
@test length(p_dofs) == 1 # 1 cell (discontinuous)
|
||
@test length(φ_dofs) == 6 # 6 edges
|
||
|
||
# ========================================================================
|
||
# Test DOF sharing between elements
|
||
# ========================================================================
|
||
|
||
println("\n🔗 Testing DOF sharing...")
|
||
|
||
elem2 = elements[2]
|
||
T_dofs2, u_dofs2, p_dofs2, φ_dofs2 = elem2.dof_indices
|
||
|
||
# Vertices 2,3,4 are shared → same DOF indices
|
||
shared_nodes_overlap = !isempty(intersect(T_dofs, T_dofs2))
|
||
@test shared_nodes_overlap
|
||
println(" ✓ Shared vertices have same temperature DOFs")
|
||
|
||
# Cell DOFs are unique (no sharing)
|
||
@test isempty(intersect(p_dofs, p_dofs2))
|
||
println(" ✓ Cell DOFs are unique (discontinuous)")
|
||
|
||
# Edge DOFs: Some edges are shared
|
||
shared_edges_overlap = !isempty(intersect(φ_dofs, φ_dofs2))
|
||
@test shared_edges_overlap
|
||
println(" ✓ Shared edges have same electric DOFs")
|
||
|
||
# ========================================================================
|
||
# Total system DOFs
|
||
# ========================================================================
|
||
|
||
println("\n📊 System summary:")
|
||
|
||
all_T_dofs = unique(vcat([collect(elem.dof_indices[1]) for elem in elements]...))
|
||
all_u_dofs = unique(vcat([collect(elem.dof_indices[2]) for elem in elements]...))
|
||
all_p_dofs = unique(vcat([collect(elem.dof_indices[3]) for elem in elements]...))
|
||
all_φ_dofs = unique(vcat([collect(elem.dof_indices[4]) for elem in elements]...))
|
||
|
||
println(" Temperature DOFs: $(length(all_T_dofs)) (5 unique vertices)")
|
||
println(" Displacement DOFs: $(length(all_u_dofs)) (5 vertices × 3)")
|
||
println(" Pressure DOFs: $(length(all_p_dofs)) (2 cells, no sharing)")
|
||
println(" Electric DOFs: $(length(all_φ_dofs)) (9 unique edges)")
|
||
|
||
total_dofs = length(all_T_dofs) + length(all_u_dofs) + length(all_p_dofs) + length(all_φ_dofs)
|
||
println(" ────────────────────────────")
|
||
println(" TOTAL: $total_dofs DOFs")
|
||
|
||
@test length(all_T_dofs) == 5
|
||
@test length(all_u_dofs) == 15
|
||
@test length(all_p_dofs) == 2
|
||
@test length(all_φ_dofs) == 9
|
||
@test total_dofs == 31
|
||
|
||
# ========================================================================
|
||
# Compare: MixedDOF vs NamedTuple
|
||
# ========================================================================
|
||
|
||
println("\n💡 COMPARISON: MixedDOF vs NamedTuple")
|
||
println(" ┌─────────────────────────────────────────────────────────┐")
|
||
println(" │ MixedDOF (vararg): │")
|
||
println(" │ - Type-level composition │")
|
||
println(" │ - Access by position: T_dofs, u_dofs, ... = elem.dof_indices │")
|
||
println(" │ - More compact type signature │")
|
||
println(" │ │")
|
||
println(" │ NamedTuple: │")
|
||
println(" │ - Named fields │")
|
||
println(" │ - Access by name: elem.dof_indices.T, .u, .p, .φ │")
|
||
println(" │ - More readable, self-documenting │")
|
||
println(" │ │")
|
||
println(" │ BOTH ARE SUPPORTED! Choose based on preference. │")
|
||
println(" └─────────────────────────────────────────────────────────┘")
|
||
|
||
println("\n" * "="^70)
|
||
println("✅ ALL TESTS PASSED: Variadic MixedDOF works!")
|
||
println("="^70)
|
||
end
|