1+ @kwdef struct SimplePlastic{T} <: AbstractMaterial
2+ G:: T
3+ K:: T
4+ Y0:: T
5+ Hiso:: T
6+ κ∞:: T
7+ Hkin:: T
8+ β∞:: T
9+ end
10+
11+ function SimplePlastic (mp:: Plastic{Ela, Yld, Iso, Kin, Rat} ) where {
12+ Ela <: LinearElastic{<:Any, :isotropic} ,
13+ Yld <: VonMises ,
14+ Iso <: Tuple{<:Voce} ,
15+ Kin <: Tuple{<:ArmstrongFrederick} ,
16+ Rat <: RateIndependent
17+ }
18+
19+ E, ν = mp. elastic. p
20+ return SimplePlastic (;
21+ G = E/ (2 * (1 + ν)), K = E / (3 * (1 - 2 * ν)), Y0 = mp. yield. Y0,
22+ Hiso = only (mp. isotropic). Hiso, κ∞ = only (mp. isotropic). κ∞,
23+ Hkin = only (mp. kinematic). Hkin, β∞ = only (mp. kinematic). β∞)
24+ end
25+
26+ struct SimplePlasticState{T} <: AbstractMaterialState
27+ ϵp:: SymmetricTensor{2,3,T,6}
28+ β:: SymmetricTensor{2,3,T,6}
29+ κ:: T
30+ end
31+
32+ function MMB. initial_material_state (:: SimplePlastic )
33+ return SimplePlasticState (zero (SymmetricTensor{2 ,3 }), zero (SymmetricTensor{2 ,3 }), 0.0 )
34+ end
35+
36+ function MMB. material_response (m:: SimplePlastic , ϵ:: SymmetricTensor{2,3} , old:: SimplePlasticState , Δt, args... )
37+ σ_trial = 2 * m. G * dev (ϵ - old. ϵp) + 3 * m. K * vol (ϵ)
38+ ϕ_trial = vonmises (σ_trial - old. β) - (m. Y0 + old. κ)
39+ if ϕ_trial ≤ 0
40+ I2 = one (ϵ)
41+ IxI = I2 ⊗ I2
42+ I4 = one (SymmetricTensor{4 ,3 })
43+ E4 = 2 * m. G * (I4 - IxI/ 3 ) + m. K * IxI
44+ return σ_trial, E4, old
45+ else
46+ rf (x) = residual (x, m, ϵ, old)
47+ Δλ, ∂r∂x, converged = newtonsolve (rf, 0.0 )
48+ #=
49+ # Using bisection
50+ Δλ1, ∂r∂x1, converged = newtonsolve(rf, 0.0)
51+ # Workaround to avoid Δλ and ∂r∂x as `Core.Box`:ed
52+ Δλ, ∂r∂x = if !converged || Δλ1 < 0
53+ Δλ2 = bisect_solve(rf, ϕ_trial / m.G)
54+ ∂r∂x2 = ForwardDiff.derivative(rf, Δλ2)
55+ (Δλ2, ∂r∂x2)
56+ else
57+ (Δλ1, ∂r∂x1)
58+ end
59+ converged = true
60+ =#
61+
62+ if converged
63+ ∂σ∂ϵ = gradient (e -> calculate_sigma (Δλ, m, e, old), ϵ)
64+ ∂σ∂x, σ = gradient (x -> calculate_sigma (x, m, ϵ, old), Δλ, :all )
65+ ∂r∂ϵ = gradient (e -> residual (Δλ, m, e, old), ϵ)
66+ # drdϵ = 0 = ∂r∂ϵ + ∂r∂x * dxdϵ => dxdϵ = - inv(∂r∂x) * ∂r∂ϵ
67+ dσdϵ = ∂σ∂ϵ - (∂σ∂x / ∂r∂x) ⊗ ∂r∂ϵ
68+
69+ σdev, β, κ = calculate_evolution (Δλ, m, ϵ, old)
70+ ϵp = old. ϵp + Δλ * (3 / 2 ) * (σdev - β) / (m. Y0 + κ)
71+
72+ return σ, dσdϵ, SimplePlasticState (ϵp, β, κ)
73+
74+ else
75+ throw (MMB. NoLocalConvergence (" $(typeof (m)) : newtonsolve! didn't converge, ϵ = " , ϵ))
76+ end
77+ end
78+ end
79+
80+ function calculate_κ (Δλ, m:: SimplePlastic , old:: SimplePlasticState )
81+ return m. κ∞ * (old. κ + Δλ * m. Hiso) / (m. κ∞ + Δλ * m. Hiso)
82+ end
83+
84+ function dβ_fun (Δλ, m:: SimplePlastic , κ)
85+ return m. Y0 + κ + Δλ * m. Hkin * (m. β∞ + m. Y0 + κ) / m. β∞
86+ end
87+
88+ function calculate_sigma (Δλ, m:: SimplePlastic , ϵ:: SymmetricTensor , old:: SimplePlasticState )
89+ σdev, _, _ = calculate_evolution (Δλ, m, ϵ, old)
90+ return σdev + 3 * m. K * vol (ϵ)
91+ end
92+
93+ function calculate_evolution (Δλ, m:: SimplePlastic , ϵ:: SymmetricTensor , old:: SimplePlasticState )
94+ κ = calculate_κ (Δλ, m, old)
95+ dβ = dβ_fun (Δλ, m, κ)
96+ Y = m. Y0 + κ
97+ σdev = (2 * m. G * dev (ϵ) - 2 * m. G * (old. ϵp - (3 * Δλ / (2 * Y)) * (old. β * Y / dβ))) / (
98+ 1 + (3 * m. G * Δλ / Y) * (1 - Δλ * m. Hkin / dβ) )
99+ β = (old. β * Y + Δλ * m. Hkin * σdev) / dβ
100+ return σdev, β, κ
101+ end
102+
103+ function residual (Δλ, m:: SimplePlastic , ϵ:: SymmetricTensor , old:: SimplePlasticState )
104+ σdev, β, κ = calculate_evolution (Δλ, m, ϵ, old)
105+ Φ = vonmises (σdev - β) - (m. Y0 + κ)
106+ return Φ
107+ end
108+
109+ #=
110+ # Extra stability, but doesn't seem to be hit in normal cases.
111+ # Therefore, excluded as it is not tested.
112+ function bisect_solve(rf, x0::Number; maxiter = 200, tol = 1e-6)
113+ x_left = zero(x0)
114+ x_right = x0
115+ r_left = rf(x_left)
116+ @show r_left
117+ @assert r_left < 0 # No need for premature generalization...
118+
119+ # Move right untill r_right is above zero
120+ r_right = rf(x0)
121+ iter = 0
122+ while r_right < 0
123+ x_left = x_right
124+ x_right = 2*x_right
125+ r_right = rf(x_right)
126+ println(iter, ": ", (r_right, x_right), " (move right)")
127+ iter += 1
128+ iter > maxiter && error("Didn't converge (could not find positive value)")
129+ end
130+
131+ # Bisection
132+ for i in iter:maxiter
133+ # 0 = r_center ≈ r_left + (r_right - r_left) * (x_center - x_left) / (x_right - x_left)
134+ x_center = x_left - r_left * (x_right - x_left) / (r_right - r_left)
135+ r_center = rf(x_center)
136+ println(iter, ": ", (r_center, x_center), " (bisect)")
137+ abs(r_center) < tol && return x_center
138+ if r_center < 0
139+ x_left = x_center
140+ r_left = r_center
141+ else
142+ x_right = x_center
143+ r_right = r_center
144+ end
145+ end
146+ error("Did not find sufficiently small residual")
147+ end
148+ =#
0 commit comments