Skip to content

Commit a40024b

Browse files
authored
Merge pull request #219 from kaipartmann/zem-wan
Added the ZEM algorithm of Wan et al. (2019).
2 parents 66036d4 + 1f925ee commit a40024b

File tree

8 files changed

+221
-27
lines changed

8 files changed

+221
-27
lines changed

docs/src/public_api_reference.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ CriticalStretch
2525
NoCorrection
2626
EnergySurfaceCorrection
2727
ZEMSilling
28+
ZEMWan
2829
LinearElastic
2930
NeoHooke
3031
MooneyRivlin

src/Peridynamics.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export BBMaterial, DHBBMaterial, OSBMaterial, CMaterial, CRMaterial, BACMaterial
1313
CKIMaterial
1414

1515
# CMaterial related types
16-
export LinearElastic, NeoHooke, MooneyRivlin, SaintVenantKirchhoff, ZEMSilling
16+
export LinearElastic, NeoHooke, MooneyRivlin, SaintVenantKirchhoff, ZEMSilling, ZEMWan
1717

1818
# Kernels
1919
export linear_kernel, cubic_b_spline_kernel

src/discretization/zem_stabilization.jl

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
function get_correction(mat::AbstractBondSystemMaterial{<:AbstractZEMStabilization},
22
::Int, ::Int, ::Int)
3-
return mat.zem_stabilization
3+
return mat.zem
44
end
55

66
"""
@@ -19,3 +19,35 @@ struct ZEMSilling <: AbstractZEMStabilization
1919
return new(Cs)
2020
end
2121
end
22+
23+
"""
24+
ZEMWan()
25+
26+
Zero-energy mode stabilization algorithm of Wan et al. (2019), which is an improvement to
27+
Silling's algorithm that does not require a stabilization parameter.
28+
See also [`CMaterial`](@ref) on how to use this stabilization algorithm.
29+
"""
30+
struct ZEMWan <: AbstractZEMStabilization end
31+
32+
function calc_zem_stiffness_tensor(C, Kinv)
33+
C_1 = zero(SMatrix{3,3,Float64,9})
34+
for i in 1:3, j in 1:3
35+
sum_value = 0.0
36+
for k in 1:3, l in 1:3
37+
@inbounds sum_value += C[i, j, k, l] * Kinv[k, l]
38+
end
39+
C_1 = setindex(C_1, sum_value, i, j)
40+
end
41+
return C_1
42+
end
43+
44+
function calc_rotated_zem_stiffness_tensor!(C_rotated, C, Kinv, R)
45+
for m in 1:3, n in 1:3, o in 1:3, p in 1:3
46+
sum_value = 0.0
47+
for i in 1:3, j in 1:3, k in 1:3, l in 1:3
48+
@inbounds sum_value += C[i, j, k, l] * R[i, m] * R[j, n] * R[k, o] * R[l, p]
49+
end
50+
@inbounds C_rotated[m, n, o, p] = sum_value
51+
end
52+
return calc_zem_stiffness_tensor(C_rotated, Kinv)
53+
end

src/physics/constitutive_models.jl

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,43 @@ function first_piola_kirchhoff(::LinearElastic, storage::AbstractStorage,
2020
params::AbstractPointParameters, F::SMatrix{3,3,T,9}) where T
2121
E = 0.5 .* (F' * F - I)
2222
Evoigt = SVector{6,Float64}(E[1,1], E[2,2], E[3,3], 2 * E[2,3], 2 * E[3,1], 2 * E[1,2])
23-
Cvoigt = get_hooke_matrix(params.nu, params.λ, params.μ)
23+
Cvoigt = get_hooke_matrix_voigt(params.nu, params.λ, params.μ)
2424
Pvoigt = Cvoigt * Evoigt
2525
P = SMatrix{3,3,Float64,9}(Pvoigt[1], Pvoigt[6], Pvoigt[5],
2626
Pvoigt[6], Pvoigt[2], Pvoigt[4],
2727
Pvoigt[5], Pvoigt[4], Pvoigt[3])
2828
return P
2929
end
3030

31-
function get_hooke_matrix(nu, λ, μ)
31+
function get_hooke_matrix_voigt(nu, λ, μ)
3232
a = (1 - nu) * λ / nu
33-
CVoigt = SMatrix{6,6,Float64,36}(a, λ, λ, 0, 0, 0, λ, a, λ, 0, 0, 0, λ, λ, a, 0, 0, 0,
34-
0, 0, 0, μ, 0, 0, 0, 0, 0, 0, μ, 0, 0, 0, 0, 0, 0, μ)
35-
return CVoigt
33+
Cvoigt = SMatrix{6,6,Float64,36}(
34+
a, λ, λ, 0, 0, 0,
35+
λ, a, λ, 0, 0, 0,
36+
λ, λ, a, 0, 0, 0,
37+
0, 0, 0, μ, 0, 0,
38+
0, 0, 0, 0, μ, 0,
39+
0, 0, 0, 0, 0, μ
40+
)
41+
return Cvoigt
3642
end
3743

44+
function get_hooke_matrix(nu, λ, μ)
45+
Cvoigt = get_hooke_matrix_voigt(nu, λ, μ)
46+
C = zero(MArray{NTuple{4,3},Float64,4,81})
47+
voigt_map = @SVector [(1,1), (2,2), (3,3), (2,3), (1,3), (1,2)]
48+
for I in 1:6, J in 1:6
49+
i1, i2 = voigt_map[I]
50+
j1, j2 = voigt_map[J]
51+
C[i1, i2, j1, j2] = Cvoigt[I, J]
52+
C[i2, i1, j1, j2] = Cvoigt[I, J]
53+
C[i1, i2, j2, j1] = Cvoigt[I, J]
54+
C[i2, i1, j2, j1] = Cvoigt[I, J]
55+
end
56+
return C
57+
end
58+
59+
3860
@doc raw"""
3961
NeoHooke
4062

src/physics/correspondence.jl

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ consistent (correspondence) formulation of non-ordinary state-based peridynamics
1717
- [`NeoHooke`](@ref)
1818
- [`MooneyRivlin`](@ref)
1919
- [`SaintVenantKirchhoff`](@ref)
20-
- `zem::AbstractZEMStabilization`: Zero-energy mode stabilization. The
21-
stabilization algorithm of Silling (2017) is used as default. \\
22-
(default: [`ZEMSilling`](@ref))
20+
- `zem::AbstractZEMStabilization`: Algorithm of zero-energy mode stabilization. \\
21+
(default: [`ZEMSilling`](@ref)) \\
22+
The following algorithms can be used:
23+
- [`ZEMSilling`](@ref)
24+
- [`ZEMWan`](@ref)
2325
- `dmgmodel::AbstractDamageModel`: Damage model defining the damage behavior. \\
2426
(default: [`CriticalStretch`](@ref))
2527
- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is
@@ -106,7 +108,7 @@ When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with
106108
struct CMaterial{CM,ZEM,K,DM} <: AbstractCorrespondenceMaterial{CM,ZEM}
107109
kernel::K
108110
constitutive_model::CM
109-
zem_stabilization::ZEM
111+
zem::ZEM
110112
dmgmodel::DM
111113
maxdmg::Float64
112114
function CMaterial(kernel::K, cm::CM, zem::ZEM, dmgmodel::DM,
@@ -132,15 +134,38 @@ function log_material_property(::Val{:constitutive_model}, mat; indentation)
132134
return msg_qty("constitutive model", mat.constitutive_model; indentation)
133135
end
134136

135-
function log_material_property(::Val{:zem_stabilization}, mat; indentation)
136-
return msg_qty("zero-energy mode stabilization", mat.zem_stabilization; indentation)
137+
function log_material_property(::Val{:zem}, mat; indentation)
138+
return msg_qty("zero-energy mode stabilization", mat.zem; indentation)
137139
end
138140

139141
function log_material_property(::Val{:maxdmg}, mat; indentation)
140142
return msg_qty("maximum damage", mat.maxdmg; indentation)
141143
end
142144

143-
@params CMaterial StandardPointParameters
145+
struct CPointParameters <: AbstractPointParameters
146+
δ::Float64
147+
rho::Float64
148+
E::Float64
149+
nu::Float64
150+
G::Float64
151+
K::Float64
152+
λ::Float64
153+
μ::Float64
154+
Gc::Float64
155+
εc::Float64
156+
bc::Float64
157+
C::MArray{NTuple{4,3},Float64,4,81}
158+
end
159+
160+
function CPointParameters(mat::AbstractMaterial, p::Dict{Symbol,Any})
161+
(; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p)
162+
(; Gc, εc) = get_frac_params(mat.dmgmodel, p, δ, K)
163+
bc = 18 * K /* δ^4) # bond constant
164+
C = get_hooke_matrix(nu, λ, μ)
165+
return CPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc, C)
166+
end
167+
168+
@params CMaterial CPointParameters
144169

145170
@storage CMaterial struct CStorage
146171
@lthfield position::Matrix{Float64}
@@ -187,13 +212,12 @@ function force_density_point!(storage::AbstractStorage, system::AbstractSystem,
187212
defgrad_res = calc_deformation_gradient(storage, system, mat, params, i)
188213
too_much_damage!(storage, system, mat, defgrad_res, i) && return nothing
189214
PKinv = calc_first_piola_kirchhoff!(storage, mat, params, defgrad_res, Δt, i)
190-
zem = mat.zem_stabilization
191-
c_force_density!(storage, system, mat, params, zem, PKinv, defgrad_res, i)
215+
c_force_density!(storage, system, mat, params, mat.zem, PKinv, defgrad_res, i)
192216
return nothing
193217
end
194218

195219
function calc_deformation_gradient(storage::CStorage, system::BondSystem, ::CMaterial,
196-
::StandardPointParameters, i)
220+
::CPointParameters, i)
197221
(; bonds, volume) = system
198222
(; bond_active) = storage
199223
K = zero(SMatrix{3,3,Float64,9})
@@ -217,7 +241,7 @@ function calc_deformation_gradient(storage::CStorage, system::BondSystem, ::CMat
217241
end
218242

219243
function calc_first_piola_kirchhoff!(storage::CStorage, mat::CMaterial,
220-
params::StandardPointParameters, defgrad_res, Δt, i)
244+
params::CPointParameters, defgrad_res, Δt, i)
221245
(; F, Kinv) = defgrad_res
222246
P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F)
223247
PKinv = P * Kinv
@@ -252,6 +276,40 @@ function c_force_density!(storage::AbstractStorage, system::AbstractSystem,
252276
return nothing
253277
end
254278

279+
function c_force_density!(storage::AbstractStorage, system::AbstractSystem,
280+
mat::AbstractCorrespondenceMaterial,
281+
params::AbstractPointParameters, zem::ZEMWan, PKinv, defgrad_res,
282+
i)
283+
(; bonds, volume) = system
284+
(; bond_active) = storage
285+
(; F) = defgrad_res
286+
C_1 = calc_zem_stiffness_tensor!(storage, system, mat, params, zem, defgrad_res, i)
287+
for bond_id in each_bond_idx(system, i)
288+
bond = bonds[bond_id]
289+
j = bond.neighbor
290+
ΔXij = get_vector_diff(system.position, i, j)
291+
Δxij = get_vector_diff(storage.position, i, j)
292+
293+
# improved stabilization from this article:
294+
# https://doi.org/10.1007/s10409-019-00873-y
295+
ωij = kernel(system, bond_id) * bond_active[bond_id]
296+
tzem = ωij * C_1 * (Δxij .- F * ΔXij)
297+
298+
# update of force density
299+
tij = ωij * PKinv * ΔXij + tzem
300+
update_add_vector!(storage.b_int, i, tij .* volume[j])
301+
update_add_vector!(storage.b_int, j, -tij .* volume[i])
302+
end
303+
return nothing
304+
end
305+
306+
function calc_zem_stiffness_tensor!(storage::CStorage, system::BondSystem, mat::CMaterial,
307+
params::CPointParameters, zem::ZEMWan, defgrad_res, i)
308+
(; Kinv) = defgrad_res
309+
C_1 = calc_zem_stiffness_tensor(params.C, Kinv)
310+
return C_1
311+
end
312+
255313
function too_much_damage!(storage::AbstractStorage, system::AbstractSystem,
256314
mat::AbstractCorrespondenceMaterial, defgrad_res, i)
257315
(; F) = defgrad_res

src/physics/correspondence_rotated.jl

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ consistent (correspondence) formulation of non-ordinary state-based peridynamics
1414
(default: `LinearElastic()`) \\
1515
Only the following model can be used:
1616
- [`LinearElastic`](@ref)
17-
- `zem::AbstractZEMStabilization`: Zero-energy mode stabilization. The
18-
stabilization algorithm of Silling (2017) is used as default. \\
19-
(default: [`ZEMSilling`](@ref))
17+
- `zem::AbstractZEMStabilization`: Algorithm of zero-energy mode stabilization. \\
18+
(default: [`ZEMSilling`](@ref)) \\
19+
The following algorithms can be used:
20+
- [`ZEMSilling`](@ref)
21+
- [`ZEMWan`](@ref)
2022
- `dmgmodel::AbstractDamageModel`: Damage model defining the damage behavior. \\
2123
(default: [`CriticalStretch`](@ref))
2224
- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is
@@ -103,7 +105,7 @@ When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with
103105
struct CRMaterial{CM,ZEM,K,DM} <: AbstractCorrespondenceMaterial{CM,ZEM}
104106
kernel::K
105107
constitutive_model::CM
106-
zem_stabilization::ZEM
108+
zem::ZEM
107109
dmgmodel::DM
108110
maxdmg::Float64
109111
function CRMaterial(kernel::K, cm::CM, zem::ZEM, dmgmodel::DM,
@@ -129,7 +131,7 @@ function Base.show(io::IO, @nospecialize(mat::CRMaterial))
129131
return nothing
130132
end
131133

132-
@params CRMaterial StandardPointParameters
134+
@params CRMaterial CPointParameters
133135

134136
@storage CRMaterial struct CRStorage
135137
@lthfield position::Matrix{Float64}
@@ -149,6 +151,7 @@ end
149151
@pointfield von_mises_stress::Vector{Float64}
150152
@pointfield left_stretch::Matrix{Float64}
151153
@pointfield rotation::Matrix{Float64}
154+
zem_stiffness_rotated::MArray{NTuple{4,3},Float64,4,81}
152155
end
153156

154157
function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem,
@@ -183,8 +186,13 @@ function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem,
183186
return R
184187
end
185188

189+
function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem,
190+
::Val{:zem_stiffness_rotated})
191+
return zero(MArray{NTuple{4,3},Float64,4,81})
192+
end
193+
186194
function calc_deformation_gradient(storage::CRStorage, system::BondSystem, ::CRMaterial,
187-
::StandardPointParameters, i)
195+
::CPointParameters, i)
188196
(; bonds, volume) = system
189197
(; bond_active) = storage
190198
K = zero(SMatrix{3,3,Float64,9})
@@ -212,7 +220,7 @@ function calc_deformation_gradient(storage::CRStorage, system::BondSystem, ::CRM
212220
end
213221

214222
function calc_first_piola_kirchhoff!(storage::CRStorage, mat::CRMaterial,
215-
params::StandardPointParameters, defgrad_res, Δt, i)
223+
params::CPointParameters, defgrad_res, Δt, i)
216224
(; F, Ḟ, Kinv) = defgrad_res
217225
D = init_stress_rotation!(storage, F, Ḟ, Δt, i)
218226
if iszero(D)
@@ -231,3 +239,12 @@ function calc_first_piola_kirchhoff!(storage::CRStorage, mat::CRMaterial,
231239
PKinv = P * Kinv
232240
return PKinv
233241
end
242+
243+
function calc_zem_stiffness_tensor!(storage::CRStorage, system::BondSystem, mat::CRMaterial,
244+
params::CPointParameters, zem::ZEMWan, defgrad_res, i)
245+
(; Kinv) = defgrad_res
246+
(; rotation, zem_stiffness_rotated) = storage
247+
R = get_tensor(rotation, i)
248+
C_1 = calc_rotated_zem_stiffness_tensor!(zem_stiffness_rotated, params.C, Kinv, R)
249+
return C_1
250+
end

test/discretization/test_bond_system.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,6 @@ end
223223
@test contains(msg, "CriticalStretch")
224224
msg = Peridynamics.log_material_property(Val(:kernel), mat; indentation)
225225
@test contains(msg, "linear_kernel")
226-
msg = Peridynamics.log_material_property(Val(:zem_stabilization), mat; indentation)
226+
msg = Peridynamics.log_material_property(Val(:zem), mat; indentation)
227227
@test contains(msg, "ZEMSilling")
228228
end

0 commit comments

Comments
 (0)