mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-20 10:08:31 +00:00
refactor(materials): migrate PerfectPlasticity to compositional state design
Replace monolithic PlasticityState struct with compositional NamedTuple
state system and add new material trait system support.
- Remove PlasticityState struct (now using NamedTuple composition)
- Add supported_physics trait (Elasticity{3})
- Add required_state_variables trait (PlasticStrain, Backstress, EquivalentPlasticStrain)
- Change compute_stress to use NamedTuple for state_old and state_new
- Use get() with defaults for state extraction (handles empty initial state)
- Update state creation to use NamedTuple syntax (ε_p, α, κ)
- Remove state_type trait (replaced by required_state_variables)
This commit is contained in:
@@ -91,43 +91,9 @@ using LinearAlgebra
|
||||
# Load abstract types
|
||||
include("abstract_material.jl")
|
||||
|
||||
"""
|
||||
PlasticityState <: AbstractMaterialState
|
||||
|
||||
State variables for perfect plasticity model.
|
||||
|
||||
# Fields
|
||||
- `ε_p::SymmetricTensor{2,3,Float64,6}` - Plastic strain tensor
|
||||
- `α::SymmetricTensor{2,3,Float64,6}` - Backstress (kinematic hardening)
|
||||
- `κ::Float64` - Equivalent plastic strain (scalar)
|
||||
|
||||
# Notes
|
||||
Immutable for thread safety. Updates create new state.
|
||||
"""
|
||||
struct PlasticityState <: AbstractMaterialState
|
||||
ε_p::SymmetricTensor{2,3,Float64,6} # Plastic strain
|
||||
α::SymmetricTensor{2,3,Float64,6} # Backstress
|
||||
κ::Float64 # Equivalent plastic strain
|
||||
|
||||
function PlasticityState(ε_p::SymmetricTensor{2,3,Float64,6},
|
||||
α::SymmetricTensor{2,3,Float64,6},
|
||||
κ::Float64)
|
||||
κ ≥ 0.0 || throw(ArgumentError("Equivalent plastic strain must be non-negative, got κ = $κ"))
|
||||
new(ε_p, α, κ)
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
PlasticityState()
|
||||
|
||||
Initialize state with zero plastic strain and backstress.
|
||||
"""
|
||||
PlasticityState() = PlasticityState(zero(SymmetricTensor{2,3}),
|
||||
zero(SymmetricTensor{2,3}),
|
||||
0.0)
|
||||
|
||||
# Zero constructor for Base.zero compatibility
|
||||
Base.zero(::Type{PlasticityState}) = PlasticityState()
|
||||
# PlasticityState struct removed - now using compositional NamedTuple
|
||||
# State is represented as: (ε_p=SymmetricTensor{2,3}, α=SymmetricTensor{2,3}, κ=Float64)
|
||||
# This compositional design is inferred automatically from material traits
|
||||
|
||||
"""
|
||||
PerfectPlasticity <: AbstractPlasticMaterial
|
||||
@@ -217,8 +183,12 @@ PerfectPlasticity(; E::Real, ν::Real, σ_y::Real, H::Real) =
|
||||
# Trait declaration: PerfectPlasticity has strain-dependent tangent and state
|
||||
material_behavior(::PerfectPlasticity) = StatefulStrainDependent()
|
||||
|
||||
# State type trait: PerfectPlasticity uses PlasticityState
|
||||
state_type(::Type{PerfectPlasticity}) = PlasticityState
|
||||
# New trait system: Physics and state variable requirements
|
||||
# PerfectPlasticity supports 3D elasticity with J2 plasticity
|
||||
supported_physics(::PerfectPlasticity) = (Elasticity{3}(),)
|
||||
|
||||
# PerfectPlasticity requires three state variables (compositional design)
|
||||
required_state_variables(::PerfectPlasticity) = (PlasticStrain, Backstress, EquivalentPlasticStrain)
|
||||
|
||||
"""
|
||||
compute_stress(material::PerfectPlasticity,
|
||||
@@ -242,20 +212,20 @@ Compute stress and consistent tangent using radial return mapping.
|
||||
# Arguments
|
||||
- `material::PerfectPlasticity` - Material parameters
|
||||
- `ε::SymmetricTensor{2,3}` - Total strain tensor
|
||||
- `state_old::Union{Nothing,PlasticityState}` - Previous state (nothing = initial)
|
||||
- `state_old::NamedTuple` - Previous state (empty = initial): (ε_p, α, κ)
|
||||
- `Δt::Float64` - Time increment (unused for rate-independent plasticity)
|
||||
|
||||
# Returns
|
||||
- `σ::SymmetricTensor{2,3}` - Cauchy stress tensor
|
||||
- `𝔻::SymmetricTensor{4,3}` - Consistent tangent modulus
|
||||
- `state_new::PlasticityState` - Updated state
|
||||
- `state_new::NamedTuple` - Updated state: (ε_p, α, κ)
|
||||
|
||||
# Performance
|
||||
~200-500 ns per evaluation (elastic), ~300-600 ns (plastic)
|
||||
"""
|
||||
function compute_stress(material::PerfectPlasticity,
|
||||
ε::SymmetricTensor{2,3},
|
||||
state_old::Union{Nothing,PlasticityState}=nothing,
|
||||
state_old::NamedTuple=NamedTuple(),
|
||||
Δt::Float64=0.0)
|
||||
# Extract material parameters
|
||||
μ = material.μ
|
||||
@@ -263,15 +233,10 @@ function compute_stress(material::PerfectPlasticity,
|
||||
σ_y = material.σ_y
|
||||
H = material.H
|
||||
|
||||
# Initialize state if needed
|
||||
if state_old === nothing
|
||||
state_old = PlasticityState()
|
||||
end
|
||||
|
||||
# Extract old state
|
||||
ε_p_old = state_old.ε_p
|
||||
α_old = state_old.α
|
||||
κ_old = state_old.κ
|
||||
# Extract old state (with defaults for initial/empty state)
|
||||
ε_p_old = get(state_old, :ε_p, zero(SymmetricTensor{2,3}))
|
||||
α_old = get(state_old, :α, zero(SymmetricTensor{2,3}))
|
||||
κ_old = get(state_old, :κ, 0.0)
|
||||
|
||||
# Elastic strain
|
||||
ε_e = ε - ε_p_old
|
||||
@@ -295,7 +260,7 @@ function compute_stress(material::PerfectPlasticity,
|
||||
if f_trial ≤ 0.0
|
||||
# ==================== ELASTIC ====================
|
||||
σ = σ_trial
|
||||
state_new = state_old # No state change
|
||||
state_new = (ε_p=ε_p_old, α=α_old, κ=κ_old) # No state change
|
||||
|
||||
# Elastic tangent
|
||||
𝔻 = λ * I ⊗ I + 2μ * symmetric_identity_tensor()
|
||||
@@ -335,8 +300,8 @@ function compute_stress(material::PerfectPlasticity,
|
||||
# Update equivalent plastic strain
|
||||
κ_new = κ_old + Δλ
|
||||
|
||||
# New state
|
||||
state_new = PlasticityState(ε_p_new, α_new, κ_new)
|
||||
# New state (compositional NamedTuple)
|
||||
state_new = (ε_p=ε_p_new, α=α_new, κ=κ_new)
|
||||
|
||||
# Consistent tangent (elastoplastic)
|
||||
# For kinematic hardening: 𝔻^ep = 𝔻^e - (4μ²/(2μ + 2H/3)) · (n ⊗ n)
|
||||
|
||||
Reference in New Issue
Block a user