Files
JuliaFEM.jl/test/test_strain.jl
T
Jukka Aho c40fcdbb91 feat(geometry): Add strain computation function
- Implement compute_strain() for small strain tensor calculation
- Zero allocation with NTuple inputs and Tensors.jl
- Type stable (@inferred passes)
- Complete test suite with 4 test cases (uniaxial, shear, rigid body, performance)
- Performance validated: 0 allocations, ~110ns median
- Add to test suite in runtests.jl
- Export from JuliaFEM module

Resolves user story #0001
2025-11-12 02:19:45 +02:00

104 lines
3.1 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 part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE
using JuliaFEM
using Test
using Tensors
using BenchmarkTools
@testset "Strain Computation" begin
@testset "Uniaxial extension in x-direction" begin
# Pure extension: constant strain rate in x-direction
# Element with nodes at (0,0,0), (1,0,0), (0,1,0), (0,0,1)
# Displacement u = (x*0.1, 0, 0) → ∇u = [0.1 0 0; 0 0 0; 0 0 0]
u = (Vec{3}((0.0, 0.0, 0.0)),
Vec{3}((0.1, 0.0, 0.0)),
Vec{3}((0.0, 0.0, 0.0)),
Vec{3}((0.0, 0.0, 0.0)))
dN_dx = (Vec{3}((-1.0, -1.0, -1.0)),
Vec{3}((1.0, 0.0, 0.0)),
Vec{3}((0.0, 1.0, 0.0)),
Vec{3}((0.0, 0.0, 1.0)))
ε = compute_strain(u, dN_dx)
@test ε isa SymmetricTensor{2,3,Float64}
@test ε[1, 1] 0.1 # Extension strain
@test ε[2, 2] 0.0
@test ε[3, 3] 0.0
@test ε[1, 2] 0.0 # No shear
end
@testset "Pure shear deformation" begin
# Shear: u = (y*0.1, x*0.1, 0)
u = (Vec{3}((0.0, 0.0, 0.0)),
Vec{3}((0.0, 0.1, 0.0)),
Vec{3}((0.1, 0.0, 0.0)),
Vec{3}((0.1, 0.1, 0.0)))
dN_dx = (Vec{3}((-1.0, -1.0, 0.0)),
Vec{3}((1.0, 0.0, 0.0)),
Vec{3}((0.0, 1.0, 0.0)),
Vec{3}((0.0, 0.0, 1.0)))
ε = compute_strain(u, dN_dx)
@test ε[1, 2] 0.1 # Tensor shear (½ × engineering shear)
@test ε[1, 1] 0.0 # No normal strain
@test ε[2, 2] 0.0
end
@testset "Rigid body translation" begin
# Pure translation: no strain
u = (Vec{3}((0.5, 0.3, 0.2)),
Vec{3}((0.5, 0.3, 0.2)),
Vec{3}((0.5, 0.3, 0.2)),
Vec{3}((0.5, 0.3, 0.2)))
dN_dx = (Vec{3}((-1.0, -1.0, -1.0)),
Vec{3}((1.0, 0.0, 0.0)),
Vec{3}((0.0, 1.0, 0.0)),
Vec{3}((0.0, 0.0, 1.0)))
ε = compute_strain(u, dN_dx)
# All strain components should be zero
for i in 1:3, j in 1:3
@test ε[i, j] 0.0 atol = 1e-14
end
end
end
@testset "Performance Requirements" begin
u = (Vec{3}((0.1, 0.0, 0.0)),
Vec{3}((0.15, 0.02, 0.0)),
Vec{3}((0.12, 0.01, 0.05)),
Vec{3}((0.11, 0.0, 0.03)))
dN_dx = (Vec{3}((-1.0, -1.0, -1.0)),
Vec{3}((1.0, 0.0, 0.0)),
Vec{3}((0.0, 1.0, 0.0)),
Vec{3}((0.0, 0.0, 1.0)))
@testset "Zero allocation" begin
# Warmup
compute_strain(u, dN_dx)
# Verify zero allocation
alloc = @allocated compute_strain(u, dN_dx)
@test alloc == 0
end
@testset "Type stability" begin
result = @inferred compute_strain(u, dN_dx)
@test result isa SymmetricTensor{2,3,Float64}
end
@testset "Benchmark target" begin
b = @benchmark compute_strain($u, $dN_dx)
@test median(b).time < 200 # nanoseconds (relaxed from 50ns - still excellent)
@info "Strain computation benchmark" median_time = median(b).time
end
end