diff --git a/test/materials/test_global_material_cache.jl b/test/materials/test_global_material_cache.jl new file mode 100644 index 0000000..a28e5c9 --- /dev/null +++ b/test/materials/test_global_material_cache.jl @@ -0,0 +1,98 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md + +using Test +using JuliaFEM +using Tensors + +@testset "Global Material Cache" begin + @testset "Basic construction" begin + # Test stateless material + mat = LinearElastic(E=210e9, ν=0.3) + cache = create_global_material_cache(mat, n_ips=4, n_elems=10) + + @test cache isa GlobalMaterialCache + @test size(cache.states) == (4, 10) + @test size(cache.states_old) == (4, 10) + + # All states should be empty NamedTuple for stateless + for elem_id in 1:10, ip in 1:4 + @test get_state(cache, ip, elem_id) === NamedTuple() + @test get_old_state(cache, ip, elem_id) === NamedTuple() + end + end + + @testset "State access and update" begin + # Create a simple stateful cache + StateType = NamedTuple{(:κ,), Tuple{Float64}} + cache = GlobalMaterialCache{StateType}(2, 3) # 2 IPs, 3 elements + + # Test initial zeros + @test get_state(cache, 1, 1).κ == 0.0 + @test get_state(cache, 2, 3).κ == 0.0 + + # Set a state + set_state!(cache, 1, 2, (κ=0.5,)) + @test get_state(cache, 1, 2).κ == 0.5 + @test get_old_state(cache, 1, 2).κ == 0.0 # Old unchanged + + # Update cache (copy current → old) + update_cache!(cache) + @test get_old_state(cache, 1, 2).κ == 0.5 # Now matches current + + # Modify current + set_state!(cache, 1, 2, (κ=0.8,)) + @test get_state(cache, 1, 2).κ == 0.8 + @test get_old_state(cache, 1, 2).κ == 0.5 # Still from previous step + + # Reset + reset_cache!(cache) + @test get_state(cache, 1, 2).κ == 0.0 + @test get_old_state(cache, 1, 2).κ == 0.0 + end + + @testset "State variable helpers" begin + # Create cache with plasticity-like state + StateType = NamedTuple{(:ε_p, :α, :κ), Tuple{SymmetricTensor{2,3,Float64,6}, SymmetricTensor{2,3,Float64,6}, Float64}} + cache = GlobalMaterialCache{StateType}(1, 1) + + # Set a complex state + ε_p_val = SymmetricTensor{2,3}((0.001, 0.0, 0.0, 0.0, 0.0, 0.0)) + α_val = SymmetricTensor{2,3}((100e6, 0.0, 0.0, 0.0, 0.0, 0.0)) + κ_val = 0.01 + state = (ε_p=ε_p_val, α=α_val, κ=κ_val) + set_state!(cache, 1, 1, state) + + # Get state and extract variables + retrieved_state = get_state(cache, 1, 1) + extracted_ε_p = get_state_variable(retrieved_state, PlasticStrain) + extracted_α = get_state_variable(retrieved_state, Backstress) + extracted_κ = get_state_variable(retrieved_state, EquivalentPlasticStrain) + + @test extracted_ε_p == ε_p_val + @test extracted_α == α_val + @test extracted_κ == κ_val + + # Test immutable update + new_κ = 0.02 + new_state = set_state_variable(retrieved_state, EquivalentPlasticStrain, new_κ) + @test new_state.κ == new_κ + @test new_state.ε_p == ε_p_val # Unchanged + @test new_state.α == α_val # Unchanged + + # Original unchanged (immutable) + @test retrieved_state.κ == κ_val + end + + @testset "Integration with traits" begin + # Verify that cache creation uses material traits correctly + mat = LinearElastic(E=210e9, ν=0.3) + + # Material should be stateless + @test required_state_variables(mat) === () + + # Cache should be empty + cache = create_global_material_cache(mat, n_ips=2, n_elems=5) + @test cache isa GlobalMaterialCache{NamedTuple{(),Tuple{}}} + end +end