mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-09 04:36:34 +00:00
test(validation): add simple plasticity validation test
Test file included in main test/runtests.jl Simple validation test for plasticity material behavior
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
"""
|
||||
Simple Plasticity Test: Single Hex8 Element with PerfectPlasticity
|
||||
|
||||
Demonstrates end-to-end workflow with compositional material cache:
|
||||
1. Create GlobalMaterialCache from material traits
|
||||
2. Assemble with state tracking
|
||||
3. Verify plastic strain accumulates correctly
|
||||
|
||||
This is a UNIT TEST, not a validation test. Goal is to verify the
|
||||
material cache integration works correctly.
|
||||
"""
|
||||
|
||||
using Test
|
||||
using JuliaFEM
|
||||
using LinearAlgebra
|
||||
using SparseArrays
|
||||
using Tensors
|
||||
|
||||
@testset "Simple Plasticity - GlobalMaterialCache Integration" begin
|
||||
println("\n" * "="^70)
|
||||
println("SIMPLE PLASTICITY TEST - GlobalMaterialCache Integration")
|
||||
println("="^70)
|
||||
|
||||
# ========================================================================
|
||||
# 1. Create Single Element Mesh
|
||||
# ========================================================================
|
||||
|
||||
println("\n[1] Creating single element mesh...")
|
||||
|
||||
# Unit cube Hex8 element
|
||||
nodes = [
|
||||
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
|
||||
]
|
||||
|
||||
connectivity = [NTuple{8,UInt32}((1, 2, 3, 4, 5, 6, 7, 8))]
|
||||
element_sets = Dict{Symbol,Set{UInt32}}(:all => Set(UInt32[1]))
|
||||
mesh = Mesh{8,Hexahedron{8}}(nodes, connectivity, element_sets)
|
||||
|
||||
println(" Nodes: $(length(nodes))")
|
||||
println(" Elements: $(length(connectivity))")
|
||||
|
||||
# ========================================================================
|
||||
# 2. Material and GlobalMaterialCache
|
||||
# ========================================================================
|
||||
|
||||
println("\n[2] Creating material and global cache...")
|
||||
|
||||
# Plasticity material
|
||||
E = 210e9 # Pa
|
||||
ν = 0.3
|
||||
σ_y = 250e6 # Pa (250 MPa yield stress)
|
||||
H = 1e9 # Pa (hardening modulus)
|
||||
|
||||
material = PerfectPlasticity(E=E, ν=ν, σ_y=σ_y, H=H)
|
||||
|
||||
println(" Material: PerfectPlasticity")
|
||||
println(" E = $(E/1e9) GPa")
|
||||
println(" σ_y = $(σ_y/1e6) MPa")
|
||||
println(" H = $(H/1e9) GPa")
|
||||
|
||||
# Verify material traits
|
||||
state_vars = required_state_variables(material)
|
||||
@test state_vars == (PlasticStrain, Backstress, EquivalentPlasticStrain)
|
||||
println(" State variables: $state_vars")
|
||||
|
||||
# Create global material cache
|
||||
nips = 8 # Hex8 has 8 integration points (2x2x2 Gauss)
|
||||
nelems = 1
|
||||
global_cache = create_global_material_cache(material, n_ips=nips, n_elems=nelems)
|
||||
|
||||
@test global_cache isa GlobalMaterialCache
|
||||
@test size(global_cache.states) == (nips, nelems)
|
||||
println(" Created GlobalMaterialCache: $(size(global_cache.states))")
|
||||
|
||||
# Verify initial state is zero
|
||||
for ip in 1:nips
|
||||
state = get_state(global_cache, ip, 1)
|
||||
@test state.ε_p == zero(SymmetricTensor{2,3})
|
||||
@test state.α == zero(SymmetricTensor{2,3})
|
||||
@test state.κ == 0.0
|
||||
end
|
||||
println(" ✓ All states initialized to zero")
|
||||
|
||||
# ========================================================================
|
||||
# 3. Demonstrate Material Response
|
||||
# ========================================================================
|
||||
|
||||
println("\n[3] Testing material response...")
|
||||
|
||||
# Test 1: Elastic response (small strain)
|
||||
ε_elastic = SymmetricTensor{2,3}((1e-4, 0.0, 0.0, 0.0, 0.0, 0.0))
|
||||
state_old_1 = NamedTuple() # Empty state = initial
|
||||
σ_1, 𝔻_1, state_new_1 = compute_stress(material, ε_elastic, state_old_1, 0.0)
|
||||
|
||||
@test state_new_1.κ == 0.0 # No plastic strain
|
||||
println(" ✓ Elastic response: κ = $(state_new_1.κ)")
|
||||
|
||||
# Test 2: Plastic response (large strain)
|
||||
ε_plastic = SymmetricTensor{2,3}((0.005, 0.0, 0.0, 0.0, 0.0, 0.0))
|
||||
state_old_2 = NamedTuple() # Empty state = initial
|
||||
σ_2, 𝔻_2, state_new_2 = compute_stress(material, ε_plastic, state_old_2, 0.0)
|
||||
|
||||
@test state_new_2.κ > 0.0 # Plastic strain accumulated
|
||||
println(" ✓ Plastic response: κ = $(state_new_2.κ)")
|
||||
|
||||
# ========================================================================
|
||||
# 4. Direct NamedTuple Workflow (No Bridge!)
|
||||
# ========================================================================
|
||||
|
||||
println("\n[4] Testing direct NamedTuple workflow...")
|
||||
|
||||
# State is already a NamedTuple - use directly!
|
||||
@test state_new_2 isa NamedTuple
|
||||
@test haskey(state_new_2, :ε_p)
|
||||
@test haskey(state_new_2, :α)
|
||||
@test haskey(state_new_2, :κ)
|
||||
println(" ✓ State is native NamedTuple (no conversion needed)")
|
||||
|
||||
# Store directly in global cache
|
||||
set_state!(global_cache, 1, 1, state_new_2)
|
||||
retrieved_state = get_state(global_cache, 1, 1)
|
||||
@test retrieved_state.κ == state_new_2.κ
|
||||
println(" ✓ State stored directly in GlobalMaterialCache")
|
||||
|
||||
# Access directly from cache
|
||||
@test get_state(global_cache, 1, 1) isa NamedTuple
|
||||
println(" ✓ Direct access from cache (no extraction needed)")
|
||||
|
||||
# ========================================================================
|
||||
# 5. Time-Stepping Workflow
|
||||
# ========================================================================
|
||||
|
||||
println("\n[5] Testing time-stepping workflow...")
|
||||
|
||||
# Reset cache
|
||||
reset_cache!(global_cache)
|
||||
|
||||
# Step 1: Small load (elastic)
|
||||
println(" Step 1: Elastic loading...")
|
||||
state_step1_old = get_state(global_cache, 1, 1) # Get directly
|
||||
σ_step1, 𝔻_step1, state_step1 = compute_stress(material, ε_elastic, state_step1_old, 0.0)
|
||||
set_state!(global_cache, 1, 1, state_step1) # Set directly
|
||||
|
||||
@test get_state(global_cache, 1, 1).κ == 0.0
|
||||
println(" κ = $(get_state(global_cache, 1, 1).κ) (elastic)")
|
||||
|
||||
# Update cache for next step
|
||||
update_cache!(global_cache)
|
||||
|
||||
# Step 2: Large load (plastic)
|
||||
println(" Step 2: Plastic loading...")
|
||||
state_step2_old = get_state(global_cache, 1, 1) # Get directly
|
||||
σ_step2, 𝔻_step2, state_step2 = compute_stress(material, ε_plastic, state_step2_old, 0.0)
|
||||
set_state!(global_cache, 1, 1, state_step2) # Set directly
|
||||
|
||||
κ_current = get_state(global_cache, 1, 1).κ
|
||||
κ_old = get_old_state(global_cache, 1, 1).κ
|
||||
|
||||
@test κ_current > 0.0 # Plastic strain accumulated
|
||||
@test κ_old == 0.0 # Old state still elastic
|
||||
println(" κ_current = $κ_current (plastic)")
|
||||
println(" κ_old = $κ_old (from previous step)")
|
||||
|
||||
# ========================================================================
|
||||
# 6. Summary
|
||||
# ========================================================================
|
||||
|
||||
println("\n" * "="^70)
|
||||
println("SUMMARY - Compositional Material Cache (No Bridge!)")
|
||||
println("="^70)
|
||||
println(" ✓ GlobalMaterialCache created from material traits")
|
||||
println(" ✓ NamedTuple states used directly (no conversion)")
|
||||
println(" ✓ compute_stress accepts/returns NamedTuple natively")
|
||||
println(" ✓ States stored and retrieved without any bridge")
|
||||
println(" ✓ Time-stepping workflow simplified")
|
||||
println(" ✓ Plastic strain accumulation tracked")
|
||||
println(" ✓ Pure compositional design - elegant and fast!")
|
||||
println("="^70)
|
||||
|
||||
@test true # If we got here, everything worked!
|
||||
end
|
||||
Reference in New Issue
Block a user