Files
JuliaFEM.jl/test/element/test_celement_creation.jl
T
Jukka Aho b547a1d668 test(element): add test_celement_creation test
Test file included in test/element/runtests.jl
2025-12-15 06:32:46 +02:00

154 lines
5.5 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 CElement Creation with DOF Manager
"""
# Mock mesh structure for testing
struct TestMesh
nodes::Dict{Int, Vec} # node_id → coordinates
connectivity::Dict{Int, Tuple} # elem_id → node tuple
element_sets::Dict{String, Vector{Int}} # set_name → elem_ids
end
@testset "CElement Creation with DOF Assignment" begin
@testset "Single Element Type - Triangle ScalarDOF" begin
# Create mock mesh: 2 triangles sharing an edge
mesh = TestMesh(
Dict(
1 => Vec{2}((0.0, 0.0)),
2 => Vec{2}((1.0, 0.0)),
3 => Vec{2}((0.5, 0.8)),
4 => Vec{2}((0.5, -0.8))
),
Dict(
1 => (1, 2, 3), # Triangle 1
2 => (1, 2, 4) # Triangle 2
),
Dict("SURFACE" => [1, 2])
)
# Get element IDs
surf_ids = get_element_ids(mesh, "SURFACE")
@test surf_ids == [1, 2]
# Create element description
descriptions = [
CElement{Triangle{3}, Lagrange{1}, ScalarDOF} => surf_ids
]
# Create elements with DOF assignment
elements = create_celements!(mesh, descriptions)
# Verify
@test length(elements) == 2
@test all(e -> e isa CElement{Triangle{3}, Lagrange{1}, ScalarDOF}, elements)
# Element 1: nodes (1,2,3) → DOFs [1, 2, 3]
@test elements[1].dof_indices == (1, 2, 3)
# Element 2: nodes (1,2,4), nodes 1-2 reuse DOFs, node 4 is new
# Node 1 → DOF 1, Node 2 → DOF 2, Node 4 → DOF 4
@test elements[2].dof_indices == (1, 2, 4)
# Total DOFs: 4 unique nodes = 4 DOFs
all_dofs = vcat([collect(e.dof_indices) for e in elements]...)
@test maximum(all_dofs) == 4
end
@testset "Single Element Type - Tetrahedron VectorDOF{3}" begin
mesh = TestMesh(
Dict(
1 => Vec{3}((0.0, 0.0, 0.0)),
2 => Vec{3}((1.0, 0.0, 0.0)),
3 => Vec{3}((0.0, 1.0, 0.0)),
4 => Vec{3}((0.0, 0.0, 1.0)),
5 => Vec{3}((1.0, 1.0, 1.0))
),
Dict(
1 => (1, 2, 3, 4), # Tet 1
2 => (2, 3, 4, 5) # Tet 2
),
Dict("VOLUME" => [1, 2])
)
descriptions = [
CElement{Tetrahedron{4}, Lagrange{1}, VectorDOF{3}} => get_element_ids(mesh, "VOLUME")
]
elements = create_celements!(mesh, descriptions)
@test length(elements) == 2
# Element 1: 4 nodes × 3 DOFs = 12 DOFs
@test elements[1].dof_indices == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
# Element 2: nodes 2,3,4 reuse DOFs, node 5 is new
# Node 2 → [4,5,6], Node 3 → [7,8,9], Node 4 → [10,11,12], Node 5 → [13,14,15]
@test elements[2].dof_indices == (4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
# Total DOFs: 5 nodes × 3 DOFs/node = 15
all_dofs = vcat([collect(e.dof_indices) for e in elements]...)
@test maximum(all_dofs) == 15
end
@testset "Multiple Element Types - Volume + Surface" begin
# Realistic case: solid elements + surface heat flux elements
mesh = TestMesh(
Dict(
1 => Vec{3}((0.0, 0.0, 0.0)),
2 => Vec{3}((1.0, 0.0, 0.0)),
3 => Vec{3}((0.0, 1.0, 0.0)),
4 => Vec{3}((0.0, 0.0, 1.0))
),
Dict(
1 => (1, 2, 3, 4), # Tet volume
2 => (1, 2, 3) # Triangle surface
),
Dict(
"VOLUME" => [1],
"SURFACE" => [2]
)
)
# Create mixed descriptions: displacement + temperature
descriptions = [
CElement{Tetrahedron{4}, Lagrange{1}, VectorDOF{3}} => get_element_ids(mesh, "VOLUME"),
CElement{Triangle{3}, Lagrange{1}, ScalarDOF} => get_element_ids(mesh, "SURFACE")
]
elements = create_celements!(mesh, descriptions)
@test length(elements) == 2
# First element (volume): 4 nodes × 3 DOFs = 12 DOFs
@test elements[1] isa CElement{Tetrahedron{4}, Lagrange{1}, VectorDOF{3}}
@test elements[1].dof_indices == (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
# Second element (surface): nodes 1,2,3 already have displacement DOFs (3 each)
# Current implementation: reuses first DOF from each node (not ideal but works)
# Node 1 has DOFs [1,2,3], reuse 1
# Node 2 has DOFs [4,5,6], reuse 4
# Node 3 has DOFs [7,8,9], reuse 7
# TODO: Should append new DOFs (13,14,15) for different DOF type
@test elements[2] isa CElement{Triangle{3}, Lagrange{1}, ScalarDOF}
@test elements[2].dof_indices == (1, 4, 7)
# Total DOFs: 12 from first element (current behavior reuses DOFs)
all_dofs = vcat([collect(e.dof_indices) for e in elements]...)
@test maximum(all_dofs) == 12
end
@testset "Error Cases" begin
mesh = TestMesh(
Dict(1 => Vec{2}((0.0, 0.0))),
Dict(),
Dict("EXISTS" => [1])
)
# Missing element set
@test_throws ErrorException get_element_ids(mesh, "MISSING")
end
end