From 05a6f0bd3977aac3ac6bd6d1c9d481cbf77b25a9 Mon Sep 17 00:00:00 2001 From: Jukka Aho Date: Thu, 20 Nov 2025 16:56:43 +0200 Subject: [PATCH] test(continuum): Remove obsolete test_kernel_allocations.jl Deleted: test/domains/continuum/test_kernel_allocations.jl Reason: - Tested old assembly implementation (now deleted) - Replaced by new comprehensive test suite: * test_cache_updates.jl * test_compute_block.jl * test_full_assembly.jl * test_kernel_functions.jl New tests cover same functionality plus more with new architecture. Zero allocation property now verified in test_full_assembly.jl. --- .../continuum/test_kernel_allocations.jl | 257 ------------------ 1 file changed, 257 deletions(-) delete mode 100644 test/domains/continuum/test_kernel_allocations.jl diff --git a/test/domains/continuum/test_kernel_allocations.jl b/test/domains/continuum/test_kernel_allocations.jl deleted file mode 100644 index 9741178..0000000 --- a/test/domains/continuum/test_kernel_allocations.jl +++ /dev/null @@ -1,257 +0,0 @@ -# This file is a part of JuliaFEM. -# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md - -""" -Zero-allocation tests for ContinuumKernel. - -These tests verify that the kernel interface methods satisfy the zero-allocation -requirement, which is critical for performance in nonlinear solvers and time stepping. - -Test coverage: -1. dofs_per_node() - Pure function (no allocations expected) -2. get_dof_mapping!() - In-place DOF mapping (zero allocations) -3. compute_element_stiffness!() - In-place stiffness computation (zero allocations) - -All tests use @allocated macro to verify zero heap allocations. -""" - -using Test -using JuliaFEM -using LinearAlgebra - -@testset "ContinuumKernel Zero-Allocation Tests" begin - - # Create a simple test mesh (2×2×2 Hex8 cube) - function create_test_mesh() - # 8 nodes forming a unit cube (as Vec{3}) - nodes = Vec{3,Float64}[ - Vec{3}((0.0, 0.0, 0.0)), # 1 - Vec{3}((1.0, 0.0, 0.0)), # 2 - Vec{3}((1.0, 1.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, 0.0, 1.0)), # 6 - Vec{3}((1.0, 1.0, 1.0)), # 7 - Vec{3}((0.0, 1.0, 1.0)), # 8 - ] - - # Single Hex8 element (as NTuple{8,UInt32}) - connectivity = [NTuple{8,UInt32}((1, 2, 3, 4, 5, 6, 7, 8))] - - # Element sets - element_sets = Dict{Symbol,Set{UInt32}}(:all => Set(UInt32[1])) - - return Mesh{8,Hexahedron{8}}(nodes, connectivity, element_sets) - end - - # Create test kernel with LinearElastic material - function create_test_kernel() - formulation = ContinuumFormulation{FullThreeD}() - material = LinearElastic(E=210.0e9, ν=0.3) - field = Displacement{3}() - return ContinuumKernel(formulation, material, field) - end - - @testset "dofs_per_node() - Pure Function" begin - kernel = create_test_kernel() - - # First call (may allocate due to compilation) - ndofs = dofs_per_node(kernel) - @test ndofs == 3 - - # Second call should be zero-allocation - allocs = @allocated dofs_per_node(kernel) - @test allocs == 0 - - println(" ✓ dofs_per_node(): $(allocs) bytes allocated") - end - - @testset "get_dof_mapping!() - In-Place DOF Mapping" begin - kernel = create_test_kernel() - mesh = create_test_mesh() - - # Pre-allocate DOF buffer - nnodes_elem = 8 - ndofs_per_node = 3 - ndofs_elem = nnodes_elem * ndofs_per_node - dofs = zeros(Int, ndofs_elem) - - # First call (warm-up, may allocate due to compilation) - get_dof_mapping!(dofs, kernel, 1, mesh) - - # Verify correctness - @test length(dofs) == 24 - @test all(dofs .> 0) # All DOF indices should be positive - @test dofs[1:3] == [1, 2, 3] # Node 1: [ux, uy, uz] = [1, 2, 3] - @test dofs[4:6] == [4, 5, 6] # Node 2: [ux, uy, uz] = [4, 5, 6] - - # Second call should be zero-allocation - fill!(dofs, 0) # Reset - allocs = @allocated get_dof_mapping!(dofs, kernel, 1, mesh) - @test allocs == 0 - - # Verify result is still correct - @test dofs[1:3] == [1, 2, 3] - - println(" ✓ get_dof_mapping!(): $(allocs) bytes allocated") - end - - @testset "compute_element_stiffness!() - In-Place Stiffness [LinearElastic]" begin - kernel = create_test_kernel() - mesh = create_test_mesh() - - # Create element cache - element_cache = create_element_cache(mesh, kernel) - - # First call (warm-up, may allocate due to compilation) - compute_element_stiffness!(element_cache, kernel, 1, mesh) - - # Verify correctness - nnodes_elem = 8 - ndofs_elem = 24 - Ke = @view element_cache.Ke[1:ndofs_elem, 1:ndofs_elem] - fe = @view element_cache.fe[1:ndofs_elem] - - @test size(Ke) == (24, 24) - @test !any(isnan.(Ke)) - @test !any(isinf.(Ke)) - @test norm(Ke) > 0 # Stiffness should be non-zero - - # Stiffness matrix should be symmetric - @test norm(Ke - Ke') < 1e-10 * norm(Ke) - - # Second call should be zero-allocation - fill!(element_cache.Ke, 0.0) - fill!(element_cache.fe, 0.0) - - allocs = @allocated compute_element_stiffness!(element_cache, kernel, 1, mesh) - @test allocs == 0 - - # Verify result is still correct - Ke_after = @view element_cache.Ke[1:ndofs_elem, 1:ndofs_elem] - @test norm(Ke_after) > 0 - - println(" ✓ compute_element_stiffness!() [LinearElastic]: $(allocs) bytes allocated") - end - - @testset "compute_element_stiffness!() - In-Place Stiffness [NeoHookean]" begin - # Create kernel with NeoHookean material - formulation = ContinuumFormulation{FullThreeD}() - material = NeoHookean(E_mod=210.0e9, nu=0.3) - field = Displacement{3}() - kernel = ContinuumKernel(formulation, material, field) - - mesh = create_test_mesh() - element_cache = create_element_cache(mesh, kernel) - - # First call (warm-up, may allocate due to compilation) - compute_element_stiffness!(element_cache, kernel, 1, mesh) - - # Verify correctness - ndofs_elem = 24 - Ke = @view element_cache.Ke[1:ndofs_elem, 1:ndofs_elem] - - @test size(Ke) == (24, 24) - @test !any(isnan.(Ke)) - @test !any(isinf.(Ke)) - @test norm(Ke) > 0 - - # Second call should be zero-allocation - fill!(element_cache.Ke, 0.0) - fill!(element_cache.fe, 0.0) - - allocs = @allocated compute_element_stiffness!(element_cache, kernel, 1, mesh) - @test allocs == 0 - - # Verify result is still correct - Ke_after = @view element_cache.Ke[1:ndofs_elem, 1:ndofs_elem] - @test norm(Ke_after) > 0 - - println(" ✓ compute_element_stiffness!() [NeoHookean]: $(allocs) bytes allocated") - end - - @testset "Full Assembly Loop - Zero Allocations" begin - kernel = create_test_kernel() - mesh = create_test_mesh() - - # Create assembler and cache - assembler = COOAssembler() - cache = create_cache(assembler, mesh, kernel) - - # First assembly (warm-up) - reset!(cache) - assemble!(cache, assembler, kernel, mesh) - - # Second assembly should be zero-allocation - reset!(cache) - allocs = @allocated assemble!(cache, assembler, kernel, mesh) - - # Note: COOAssembler has ~1200 bytes overhead from cache.counter[] Ref updates - # This is assembler overhead, NOT kernel allocations (kernel has 0 bytes) - # We check that allocations are reasonable (< 2000 bytes) - @test allocs < 2000 - - println(" ✓ Full assembly loop: $(allocs) bytes allocated (assembler overhead, kernel=0)") - end - - @testset "Cache Reuse - Nonlinear Iteration Pattern" begin - kernel = create_test_kernel() - mesh = create_test_mesh() - - assembler = COOAssembler() - cache = create_cache(assembler, mesh, kernel) - - # Warm-up - reset!(cache) - assemble!(cache, assembler, kernel, mesh) - - # Simulate nonlinear iteration loop (10 iterations) - total_allocs = 0 - for iter in 1:10 - reset!(cache) - allocs = @allocated assemble!(cache, assembler, kernel, mesh) - total_allocs += allocs - end - - avg_allocs = total_allocs / 10 - @test avg_allocs < 2000 # Assembler overhead (kernel itself = 0 bytes) - - println(" ✓ 10 assembly iterations: $(total_allocs) bytes total, $(avg_allocs) bytes/iteration") - end - - @testset "Element Cache Creation - Correct Sizing" begin - kernel = create_test_kernel() - mesh = create_test_mesh() - - element_cache = create_element_cache(mesh, kernel) - - # Check sizes - max_nnodes_elem = 8 - ndofs_per_node = 3 - max_ndofs_elem = 24 - ndim = 3 - - @test size(element_cache.Ke) == (max_ndofs_elem, max_ndofs_elem) - @test size(element_cache.fe) == (max_ndofs_elem,) - @test size(element_cache.coords) == (max_nnodes_elem, ndim) - @test size(element_cache.dofs) == (max_ndofs_elem,) - - println(" ✓ ElementCache sized correctly: Ke=$(size(element_cache.Ke)), coords=$(size(element_cache.coords))") - end - -end - -println("\n" * "="^70) -println("ZERO-ALLOCATION TEST SUMMARY") -println("="^70) -println("All kernel interface methods verified for ZERO allocations:") -println(" ✓ dofs_per_node() - 0 bytes") -println(" ✓ get_dof_mapping!() - 0 bytes") -println(" ✓ compute_element_stiffness!() [LinearElastic] - 0 bytes") -println(" ✓ compute_element_stiffness!() [NeoHookean] - 0 bytes") -println() -println("Full assembly loop: ~1200 bytes (assembler overhead, NOT kernel)") -println(" - Kernel functions themselves: 0 bytes ✓") -println(" - Assembler cache management: ~1200 bytes (counter[] updates)") -println(" - This is acceptable for production use") -println("="^70)