From ffcc82d61e823cc0600e3e06ae157292c258c230 Mon Sep 17 00:00:00 2001 From: Jukka Aho Date: Sat, 9 May 2026 18:25:24 +0300 Subject: [PATCH] chore(test): remove legacy DOF connectivity regression Delete Dict-era connectivity tests superseded by `DOFHandler` coverage. - Drop `test/dofs/test_dof_connectivity.jl`. --- test/dofs/test_dof_connectivity.jl | 305 ----------------------------- 1 file changed, 305 deletions(-) delete mode 100644 test/dofs/test_dof_connectivity.jl diff --git a/test/dofs/test_dof_connectivity.jl b/test/dofs/test_dof_connectivity.jl deleted file mode 100644 index ff4d28e..0000000 --- a/test/dofs/test_dof_connectivity.jl +++ /dev/null @@ -1,305 +0,0 @@ -# This file is a part of JuliaFEM. -# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md - -""" -Unit tests for DOF connectivity structures. - -Tests: -1. DOFElementConnection creation and access -2. DOFConnectivity building and access -3. DOFConnectivityGPU building and access -4. Zero-allocation verification -5. GPU compatibility (bits types) -""" - -using Test -using JuliaFEM -using JuliaFEM: DOFElementConnection, DOFConnectivity, DOFConnectivityGPU -using JuliaFEM: build_dof_connectivity, build_dof_connectivity_gpu -using JuliaFEM: connection_count, is_empty, elem_id, local_dof_idx -using JuliaFEM: DOFManager, create_elements!, @DOFSet, DOF, Displacement, Vertex -using BenchmarkTools - -@testset "DOF Connectivity" begin - println("\n" * "="^70) - println("DOF CONNECTIVITY TESTS") - println("="^70) - - # ======================================================================== - # 1. DOFElementConnection - # ======================================================================== - - @testset "DOFElementConnection" begin - println("\n[1] Testing DOFElementConnection...") - - # Create connection - conn = DOFElementConnection(5, 12) - @test elem_id(conn) == 5 - @test local_dof_idx(conn) == 12 - - # Test type (bits type for GPU) - # Note: isbits() checks if an instance is a bits type (immutable, no pointers) - # DOFElementConnection is a struct with Int32 and Int16 fields - it IS a bits type - @test isbits(conn) - # Verify it's a struct (not mutable struct) - @test DOFElementConnection isa Type - - # Test range validation - @test_throws ErrorException DOFElementConnection(0, 1) - @test_throws ErrorException DOFElementConnection(typemax(Int32) + 1, 1) - @test_throws ErrorException DOFElementConnection(1, 0) - @test_throws ErrorException DOFElementConnection(1, typemax(Int16) + 1) - - println(" ✓ DOFElementConnection working") - end - - # ======================================================================== - # 2. DOFConnectivity (CPU Version) - # ======================================================================== - - @testset "DOFConnectivity - CPU" begin - println("\n[2] Testing DOFConnectivity (CPU)...") - - # Create simple test mesh: 2 elements sharing a node - # Element 1: nodes [1, 2, 3] → DOFs [1, 2, 3, 4, 5, 6, 7, 8, 9] - # Element 2: nodes [2, 4, 5] → DOFs [4, 5, 6, 10, 11, 12, 13, 14, 15] - # DOF 4, 5, 6 are shared (node 2) - - # Create DOF manager - mgr = DOFManager() - - # Create elements manually (simplified for testing) - S = @DOFSet{u::DOF{Displacement{3}, Vertex}} - ElemType = Element{Triangle{3}, Lagrange{1}, S} - - # Element 1: DOFs 1-9 (3 nodes × 3 DOFs) - elem1 = ElemType(UInt(1), (UInt64(1), UInt64(2), UInt64(3), UInt64(4), UInt64(5), UInt64(6), UInt64(7), UInt64(8), UInt64(9))) - - # Element 2: DOFs 4-6, 10-15 (shares node 2 with elem1) - elem2 = ElemType(UInt(2), (UInt64(4), UInt64(5), UInt64(6), UInt64(10), UInt64(11), UInt64(12), UInt64(13), UInt64(14), UInt64(15))) - - elements = [elem1, elem2] - - # Set total DOFs in manager - mgr.total_dofs = 15 - - # Build connectivity - connectivity = build_dof_connectivity(elements, mgr) - - @test connectivity.n_total_dofs == 15 - @test length(connectivity) == 15 - - # Test shared DOFs (4, 5, 6) - @test connection_count(connectivity, 4) == 2 # In both elements - @test connection_count(connectivity, 5) == 2 - @test connection_count(connectivity, 6) == 2 - - # Test unique DOFs - @test connection_count(connectivity, 1) == 1 # Only in elem1 - @test connection_count(connectivity, 10) == 1 # Only in elem2 - - # Test connections - conns_4 = connectivity[4] - @test length(conns_4) == 2 - @test elem_id(conns_4[1]) in [1, 2] - @test elem_id(conns_4[2]) in [1, 2] - @test elem_id(conns_4[1]) != elem_id(conns_4[2]) - - # Test empty DOFs (if any) - # DOFs 16+ don't exist, but we only built for 1-15 - # Test that accessing valid DOFs works - @test !is_empty(connectivity, 1) - @test !is_empty(connectivity, 4) - - println(" ✓ DOFConnectivity (CPU) working") - end - - # ======================================================================== - # 3. DOFConnectivityGPU - # ======================================================================== - - @testset "DOFConnectivityGPU" begin - println("\n[3] Testing DOFConnectivityGPU...") - - # Same test case as CPU version - mgr = DOFManager() - mgr.total_dofs = 15 - - S = @DOFSet{u::DOF{Displacement{3}, Vertex}} - ElemType = Element{Triangle{3}, Lagrange{1}, S} - elem1 = ElemType(UInt(1), (UInt64(1), UInt64(2), UInt64(3), UInt64(4), UInt64(5), UInt64(6), UInt64(7), UInt64(8), UInt64(9))) - elem2 = ElemType(UInt(2), (UInt64(4), UInt64(5), UInt64(6), UInt64(10), UInt64(11), UInt64(12), UInt64(13), UInt64(14), UInt64(15))) - elements = [elem1, elem2] - - # Build GPU connectivity - connectivity_gpu = build_dof_connectivity_gpu(elements, mgr, max_connections=10) - - @test connectivity_gpu.n_total_dofs == 15 - @test connectivity_gpu.max_connections == 10 - @test size(connectivity_gpu.elem_ids) == (10, 15) - @test size(connectivity_gpu.local_indices) == (10, 15) - @test length(connectivity_gpu.counts) == 15 - - # Test shared DOFs - @test connection_count(connectivity_gpu, 4) == 2 - @test connection_count(connectivity_gpu, 5) == 2 - @test connection_count(connectivity_gpu, 6) == 2 - - # Test unique DOFs - @test connection_count(connectivity_gpu, 1) == 1 - @test connection_count(connectivity_gpu, 10) == 1 - - # Test data access - @test connectivity_gpu.elem_ids[1, 4] in [1, 2] - @test connectivity_gpu.elem_ids[2, 4] in [1, 2] - @test connectivity_gpu.elem_ids[1, 4] != connectivity_gpu.elem_ids[2, 4] - - # Test array types (GPU-compatible - all bits types) - @test eltype(connectivity_gpu.elem_ids) == Int32 - @test eltype(connectivity_gpu.local_indices) == Int16 - @test eltype(connectivity_gpu.counts) == Int32 - # Verify arrays are standard Julia arrays (contiguous by default for Matrix/Vector) - @test connectivity_gpu.elem_ids isa Matrix{Int32} - @test connectivity_gpu.local_indices isa Matrix{Int16} - @test connectivity_gpu.counts isa Vector{Int32} - - println(" ✓ DOFConnectivityGPU working") - end - - # ======================================================================== - # 4. Zero-Allocation Verification - # ======================================================================== - - @testset "Zero-Allocation Access" begin - println("\n[4] Testing zero-allocation access...") - - # Build connectivity - # Create 8 elements: 8 × 12 = 96 DOFs (within 100) - mgr = DOFManager() - mgr.total_dofs = 120 # Enough for 8 elements - - S = @DOFSet{u::DOF{Displacement{3}, Vertex}} - ElemType = Element{Tetrahedron{4}, Lagrange{1}, S} - - # Create 8 elements with DOFs - elements = ElemType[] - for i in 1:8 - # Each element: 12 DOFs (4 nodes × 3) - start_dof = (i - 1) * 12 + 1 - dofs = tuple((UInt64(d) for d in start_dof:(start_dof + 11))...) - push!(elements, ElemType(UInt(i), dofs)) - end - - connectivity = build_dof_connectivity(elements, mgr) - - # Warm-up (ensure compilation) - n_warmup = min(96, connectivity.n_total_dofs) - for dof_i in 1:n_warmup - _ = connectivity[dof_i] - _ = connection_count(connectivity, dof_i) - end - - # Test on subset of DOFs that have connections - n_test = 96 # All DOFs from 8 elements - - # Test access allocations (define function in global scope for @benchmark) - test_access_func = let conn = connectivity, n = n_test - function() - @inbounds for dof_i in 1:n - connections = conn[dof_i] - count = length(connections) - for c in connections - _ = elem_id(c) - _ = local_dof_idx(c) - end - end - end - end - - result = @benchmark $test_access_func() - - println(" Access allocations: $(result.allocs)") - println(" Access memory: $(result.memory) bytes") - - # Should be zero allocations after warmup - @test result.allocs == 0 - @test result.memory == 0 - - println(" ✓ Zero-allocation access verified") - end - - # ======================================================================== - # 5. Edge Cases - # ======================================================================== - - @testset "Edge Cases" begin - println("\n[5] Testing edge cases...") - - # Empty elements - mgr = DOFManager() - mgr.total_dofs = 0 - connectivity = build_dof_connectivity(Element[], mgr) - @test connectivity.n_total_dofs == 0 - @test length(connectivity.dof_to_elements) == 0 - - # Single element - mgr = DOFManager() - mgr.total_dofs = 12 - S = @DOFSet{u::DOF{Displacement{3}, Vertex}} - ElemType = Element{Tetrahedron{4}, Lagrange{1}, S} - elem = ElemType(UInt(1), (UInt64(1), UInt64(2), UInt64(3), UInt64(4), UInt64(5), UInt64(6), UInt64(7), UInt64(8), UInt64(9), UInt64(10), UInt64(11), UInt64(12))) - connectivity = build_dof_connectivity([elem], mgr) - @test connectivity.n_total_dofs == 12 - @test all(count -> count == 1, [connection_count(connectivity, i) for i in 1:12]) - - # Invalid DOF index - mgr2 = DOFManager() - mgr2.total_dofs = 10 - elem_invalid = ElemType(UInt(1), (UInt64(1), UInt64(2), UInt64(3), UInt64(4), UInt64(5), UInt64(6), UInt64(7), UInt64(8), UInt64(9), UInt64(10), UInt64(11), UInt64(12))) # DOF 11, 12 invalid - @test_throws ErrorException build_dof_connectivity([elem_invalid], mgr2) - - println(" ✓ Edge cases handled") - end - - # ======================================================================== - # 6. GPU Compatibility - # ======================================================================== - - @testset "GPU Compatibility" begin - println("\n[6] Testing GPU compatibility...") - - # Test that DOFElementConnection is a bits type (GPU-compatible) - conn_test = DOFElementConnection(1, 1) - @test isbits(conn_test) - # Verify it's a struct type (not mutable) - @test DOFElementConnection isa Type - - # Test that GPU connectivity arrays are transferable - mgr = DOFManager() - mgr.total_dofs = 50 - S = @DOFSet{u::DOF{Displacement{3}, Vertex}} - ElemType = Element{Tetrahedron{4}, Lagrange{1}, S} - elements = [ElemType(UInt(i), tuple((UInt64(d) for d in 1:12)...)) for i in 1:5] - - conn_gpu = build_dof_connectivity_gpu(elements, mgr, max_connections=10) - - # All array element types should be bits types (for GPU transfer) - # Test with instances, not types - @test isbits(Int32(1)) - @test isbits(Int16(1)) - @test eltype(conn_gpu.elem_ids) == Int32 - @test eltype(conn_gpu.local_indices) == Int16 - @test eltype(conn_gpu.counts) == Int32 - - # Arrays should be standard Julia arrays (contiguous by default) - @test conn_gpu.elem_ids isa Matrix{Int32} - @test conn_gpu.local_indices isa Matrix{Int16} - @test conn_gpu.counts isa Vector{Int32} - - println(" ✓ GPU compatibility verified") - end - - println("\n" * "="^70) - println("ALL TESTS PASSED") - println("="^70) -end