test(basis): add zero-cost basis test

Tests zero-allocation basis function evaluation.
Validates performance characteristics of basis functions.
This commit is contained in:
Jukka Aho
2025-12-15 07:46:36 +02:00
parent 41387bd1b2
commit b44f7b6d89
+93
View File
@@ -0,0 +1,93 @@
# Test that nbasis functions are zero-cost (compile to constants)
using Test
using JuliaFEM
@testset "nbasis API" begin
# Test that nbasis is exported and works
@test nbasis(Triangle{3}(), Lagrange{1}()) == 3
@test nbasis(Triangle{6}(), Lagrange{2}()) == 6
@test nbasis(Tetrahedron{4}(), Lagrange{1}()) == 4
@test nbasis(Tetrahedron{10}(), Lagrange{2}()) == 10
@test nbasis(Hexahedron{8}(), Lagrange{1}()) == 8
@test nbasis(Hexahedron{27}(), Lagrange{2}()) == 27
# Serendipity families
@test nbasis(Quadrilateral{8}(), Serendipity{2}()) == 8
@test nbasis(Hexahedron{20}(), Serendipity{2}()) == 20
end
@testset "nbasis is zero-cost" begin
# Verify that nbasis compiles to a constant
# We use @allocated to check - should be 0 bytes
@test (@allocated nbasis(Triangle{3}(), Lagrange{1}())) == 0
@test (@allocated nbasis(Tetrahedron{10}(), Lagrange{2}())) == 0
@test (@allocated nbasis(Quadrilateral{8}(), Serendipity{2}())) == 0
# Also verify with @code_llvm that it returns a constant
# (This would be done manually during development)
# @code_llvm nbasis(Triangle{3}(), Lagrange{1}()) # Should show: ret i64 3
end
@testset "validate_dof_consistency" begin
# Test that validation works correctly
# Valid cases (should not throw)
@test validate_dof_consistency(ScalarDOF(), Triangle{3}, Lagrange{1}) === nothing
# Invalid cases: wrong number of DOFs (should throw ArgumentError)
@test_throws ArgumentError validate_dof_consistency(
VectorDOF{2}(), # 2 components per node × 3 nodes = 6 DOFs
Triangle{3}, # 3 nodes
Lagrange{1} # 3 basis functions
# Mismatch: 6 DOFs ≠ 3 basis functions
)
@test_throws ArgumentError validate_dof_consistency(
VectorDOF{3}(), # 3 components per node × 10 nodes = 30 DOFs
Tetrahedron{10}, # 10 nodes
Lagrange{2} # 10 basis functions
# Mismatch: 30 DOFs ≠ 10 basis functions
)
# Test error message content for one case
ex = try
validate_dof_consistency(VectorDOF{2}(), Triangle{3}, Lagrange{1})
nothing
catch e
e
end
@test ex isa ArgumentError
@test occursin("3 basis functions", ex.msg)
@test occursin("6 DOFs", ex.msg)
@test occursin("Ciarlet triplet", ex.msg)
end
@testset "nbasis consistency with get_basis_functions" begin
# Verify that nbasis returns the same count as actual basis functions
using StaticArrays: SVector
using Tensors: Vec
test_cases = [
(Lagrange{1}, Triangle{3}, Vec(0.25, 0.25)),
(Lagrange{2}, Triangle{6}, Vec(1/3, 1/3)),
(Lagrange{1}, Tetrahedron{4}, Vec(0.25, 0.25, 0.25)),
(Lagrange{1}, Hexahedron{8}, Vec(0.0, 0.0, 0.0)),
]
for (basis_type, topo_type, xi) in test_cases
topo = topo_type()
basis = basis_type()
# Get actual basis function count
N_actual = get_basis_functions(topo, basis, xi)
n_actual = length(N_actual)
# Get count from nbasis
n_expected = nbasis(topo, basis)
@test n_actual == n_expected
end
end