mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-23 11:02:36 +00:00
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.
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user