Files
JuliaFEM.jl/test/dofs/test_mixeddof_vararg.jl
T
Jukka Aho 08f67d273d test(dofs): add mixed DOF vararg test
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.
2025-12-15 07:50:39 +02:00

167 lines
7.2 KiB
Julia
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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