Skip to content

Commit 6f1a54e

Browse files
committed
Add custom fields for some materials
1 parent fc7ee87 commit 6f1a54e

File tree

7 files changed

+222
-35
lines changed

7 files changed

+222
-35
lines changed

src/auxiliary/io.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,9 @@ end
160160
end
161161

162162
function export_fields!(vtk, chunk, fields::Vector{Symbol}, t)
163+
(; mat, system, storage, paramsetup) = chunk
163164
for field in fields
164-
point_data = export_field(Val(field), chunk.mat, chunk.system, chunk.storage, t)
165+
point_data = export_field(Val(field), mat, system, storage, paramsetup, t)
165166
vtk[string(field), VTKPointData()] = point_data
166167
end
167168
return nothing
@@ -174,7 +175,7 @@ function export_fields!(vtk, chunk, fields_spec::Dict{Symbol,Vector{Symbol}}, t)
174175
end
175176

176177
# this function can be specialized for each field, even custom export fields can be written!
177-
function export_field(::Val{field}, mat, system, storage, t) where {field}
178+
function export_field(::Val{field}, mat, system, storage, paramsetup, t) where {field}
178179
return get_loc_point_data(storage, system, field)
179180
end
180181

src/physics/bond_based.jl

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -125,30 +125,36 @@ end
125125
@pointfield b_ext::Matrix{Float64}
126126
@pointfield density_matrix::Matrix{Float64}
127127
@pointfield damage::Vector{Float64}
128-
bond_stretch::Vector{Float64}
128+
bond_length::Vector{Float64}
129129
bond_active::Vector{Bool}
130130
@pointfield n_active_bonds::Vector{Int}
131+
@pointfield strain_energy_density::Vector{Float64}
131132
end
132133

133-
function init_field(::BBMaterial, ::AbstractTimeSolver, system::BondSystem,
134-
::Val{:bond_stretch})
134+
function init_field(::AbstractBondBasedMaterial, ::AbstractTimeSolver, system::BondSystem,
135+
::Val{:bond_length})
135136
return zeros(get_n_bonds(system))
136137
end
137138

139+
function init_field(::AbstractBondBasedMaterial, ::AbstractTimeSolver, system::BondSystem,
140+
::Val{:strain_energy_density})
141+
return zeros(get_n_loc_points(system))
142+
end
143+
138144
# Customized calc_failure to save the bond stretch ε for force density calculation
139145
function calc_failure!(storage::AbstractStorage, system::BondSystem,
140146
::AbstractBondBasedMaterial, ::CriticalStretch,
141147
paramsetup::AbstractParameterSetup, i)
142148
(; εc) = get_params(paramsetup, i)
143-
(; position, n_active_bonds, bond_active, bond_stretch) = storage
149+
(; position, n_active_bonds, bond_active, bond_length) = storage
144150
(; bonds) = system
145151
for bond_id in each_bond_idx(system, i)
146152
bond = bonds[bond_id]
147153
j, L = bond.neighbor, bond.length
148154
Δxij = get_vector_diff(position, i, j)
149155
l = norm(Δxij)
150156
ε = (l - L) / L
151-
bond_stretch[bond_id] = ε / l # note that this is ε / l!
157+
bond_length[bond_id] = l # store current bond length
152158
if ε > εc && bond.fail_permit
153159
bond_active[bond_id] = false
154160
end
@@ -159,34 +165,66 @@ end
159165

160166
function force_density_point!(storage::BBStorage, system::BondSystem, ::BBMaterial,
161167
params::StandardPointParameters, t, Δt, i)
162-
(; position, bond_stretch, bond_active, b_int) = storage
168+
(; position, bond_length, bond_active, b_int) = storage
163169
(; bonds, correction, volume) = system
164170
for bond_id in each_bond_idx(system, i)
165171
bond = bonds[bond_id]
166-
j = bond.neighbor
172+
j, L = bond.neighbor, bond.length
167173
Δxij = get_vector_diff(position, i, j)
168-
ε = bond_stretch[bond_id]
174+
l = bond_length[bond_id]
175+
ε = (l - L) / L
169176
ω = bond_active[bond_id] * surface_correction_factor(correction, bond_id)
170-
b = ω * params.bc * ε * volume[j] .* Δxij
177+
b = ω * params.bc * ε * volume[j] .* Δxij / l
171178
update_add_vector!(b_int, i, b)
172179
end
173180
return nothing
174181
end
175182

176183
function force_density_point!(storage::BBStorage, system::BondSystem, ::BBMaterial,
177184
paramhandler::ParameterHandler, t, Δt, i)
178-
(; position, bond_stretch, bond_active, b_int) = storage
185+
(; position, bond_length, bond_active, b_int) = storage
179186
(; bonds, correction, volume) = system
180187
params_i = get_params(paramhandler, i)
181188
for bond_id in each_bond_idx(system, i)
182189
bond = bonds[bond_id]
183-
j = bond.neighbor
190+
j, L = bond.neighbor, bond.length
184191
Δxij = get_vector_diff(position, i, j)
185-
ε = bond_stretch[bond_id]
192+
l = bond_length[bond_id]
193+
ε = (l - L) / L
186194
params_j = get_params(paramhandler, j)
187195
ω = bond_active[bond_id] * surface_correction_factor(correction, bond_id)
188-
b = ω * (params_i.bc + params_j.bc) / 2 * ε * volume[j] .* Δxij
196+
b = ω * (params_i.bc + params_j.bc) / 2 * ε * volume[j] .* Δxij / l
189197
update_add_vector!(b_int, i, b)
190198
end
191199
return nothing
192200
end
201+
202+
function strain_energy_density_point!(storage::AbstractStorage, system::BondSystem,
203+
::AbstractBondBasedMaterial,
204+
paramsetup::AbstractParameterSetup, i)
205+
(; bond_active, bond_length, strain_energy_density) = storage
206+
(; bonds, correction, volume) = system
207+
params_i = get_params(paramsetup, i)
208+
Ψ = 0.0
209+
for bond_id in each_bond_idx(system, i)
210+
bond = bonds[bond_id]
211+
j, L = bond.neighbor, bond.length
212+
l = bond_length[bond_id]
213+
ε = (l - L) / L
214+
params_j = get_params(paramsetup, j)
215+
ωij = bond_active[bond_id] * surface_correction_factor(correction, bond_id)
216+
bc = (params_i.bc + params_j.bc) / 2
217+
Ψ += 0.25 * ωij * bc * ε * ε * L * volume[j]
218+
end
219+
strain_energy_density[i] = Ψ
220+
return nothing
221+
end
222+
223+
function export_field(::Val{:strain_energy_density}, mat::AbstractBondBasedMaterial,
224+
system::BondSystem, storage::AbstractStorage,
225+
paramsetup::AbstractParameterSetup, t)
226+
for i in each_point_idx(system)
227+
strain_energy_density_point!(storage, system, mat, paramsetup, i)
228+
end
229+
return storage.strain_energy_density
230+
end

src/physics/correspondence.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ end
318318

319319
# calculate the von Mises stress from the Cauchy stress tensor just when exporting
320320
function export_field(::Val{:von_mises_stress}, ::CMaterial, system::BondSystem,
321-
storage::AbstractStorage, t)
321+
storage::AbstractStorage, ::AbstractParameterSetup, t)
322322
for i in each_point_idx(system)
323323
σ = get_tensor(storage.cauchy_stress, i)
324324
storage.von_mises_stress[i] = von_mises_stress(σ)

src/physics/correspondence_rotated.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ end
252252

253253
# calculate the von Mises stress from the Cauchy stress tensor just when exporting
254254
function export_field(::Val{:von_mises_stress}, ::CRMaterial, system::BondSystem,
255-
storage::AbstractStorage, t)
255+
storage::AbstractStorage, ::AbstractParameterSetup, t)
256256
for i in each_point_idx(system)
257257
σ = get_tensor(storage.unrotated_stress, i)
258258
T = rotate_stress(storage::AbstractStorage, σ, i)

src/physics/dh_bond_based.jl

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -103,31 +103,24 @@ end
103103
@pointfield b_ext::Matrix{Float64}
104104
@pointfield density_matrix::Matrix{Float64}
105105
@pointfield damage::Vector{Float64}
106-
bond_stretch::Vector{Float64}
106+
bond_length::Vector{Float64}
107107
bond_active::Vector{Bool}
108108
@pointfield n_active_bonds::Vector{Int}
109-
end
110-
111-
function init_field(::DHBBMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int})
112-
return zeros(3, get_n_points(system))
113-
end
114-
115-
function init_field(::DHBBMaterial, ::AbstractTimeSolver, system::BondSystem,
116-
::Val{:bond_stretch})
117-
return zeros(get_n_bonds(system))
109+
@pointfield strain_energy_density::Vector{Float64}
118110
end
119111

120112
function force_density_point!(storage::DHBBStorage, system::BondSystem, ::DHBBMaterial,
121113
params::StandardPointParameters, t, Δt, i)
122-
(; position, bond_stretch, bond_active, b_int) = storage
114+
(; position, bond_length, bond_active, b_int) = storage
123115
(; bonds, correction, volume) = system
124116
for bond_id in each_bond_idx(system, i)
125117
bond = bonds[bond_id]
126-
j = bond.neighbor
118+
j, L = bond.neighbor, bond.length
127119
Δxij = get_vector_diff(position, i, j)
128-
ε = bond_stretch[bond_id]
120+
l = bond_length[bond_id]
121+
ε = (l - L) / L
129122
ω = bond_active[bond_id] * surface_correction_factor(correction, bond_id)
130-
b = ω * params.bc * ε .* Δxij
123+
b = ω * params.bc * ε .* Δxij / l
131124
update_add_vector!(b_int, i, b * volume[j])
132125
update_add_vector!(b_int, j, -b * volume[i])
133126
end
@@ -136,17 +129,18 @@ end
136129

137130
function force_density_point!(storage::DHBBStorage, system::BondSystem, ::DHBBMaterial,
138131
paramhandler::ParameterHandler, t, Δt, i)
139-
(; position, bond_stretch, bond_active, b_int) = storage
132+
(; position, bond_length, bond_active, b_int) = storage
140133
(; bonds, correction, volume) = system
141134
params_i = get_params(paramhandler, i)
142135
for bond_id in each_bond_idx(system, i)
143136
bond = bonds[bond_id]
144-
j = bond.neighbor
137+
j, L = bond.neighbor, bond.length
145138
Δxij = get_vector_diff(position, i, j)
146-
ε = bond_stretch[bond_id]
139+
l = bond_length[bond_id]
140+
ε = (l - L) / L
147141
params_j = get_params(paramhandler, j)
148142
ω = bond_active[bond_id] * surface_correction_factor(correction, bond_id)
149-
b = ω * (params_i.bc + params_j.bc) / 2 * ε .* Δxij
143+
b = ω * (params_i.bc + params_j.bc) / 2 * ε .* Δxij / l
150144
update_add_vector!(b_int, i, b * volume[j])
151145
update_add_vector!(b_int, j, -b * volume[i])
152146
end

src/physics/ordinary_state_based.jl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ OSBMaterial(; kwargs...) = OSBMaterial{NoCorrection}(; kwargs...)
109109
bond_length::Vector{Float64}
110110
bond_active::Vector{Bool}
111111
@pointfield n_active_bonds::Vector{Int}
112+
@pointfield strain_energy_density::Vector{Float64}
112113
end
113114

114115
function init_field(::OSBMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int})
@@ -120,6 +121,11 @@ function init_field(::OSBMaterial, ::AbstractTimeSolver, system::BondSystem,
120121
return zeros(get_n_bonds(system))
121122
end
122123

124+
function init_field(::OSBMaterial, ::AbstractTimeSolver, system::BondSystem,
125+
::Val{:strain_energy_density})
126+
return zeros(get_n_loc_points(system))
127+
end
128+
123129
# Customized calc_failure to save the bond length for force density calculation
124130
function calc_failure!(storage::OSBStorage, system::BondSystem,
125131
::OSBMaterial, ::CriticalStretch,
@@ -219,3 +225,34 @@ function calc_dilatation(storage::OSBStorage, system::BondSystem, mat::OSBMateri
219225
end
220226
return dil
221227
end
228+
229+
function export_field(::Val{:strain_energy_density}, mat::OSBMaterial, system::BondSystem,
230+
storage::AbstractStorage, paramsetup::AbstractParameterSetup, t)
231+
(; bond_active, bond_length, strain_energy_density) = storage
232+
(; bonds, correction, volume) = system
233+
strain_energy_density .= 0.0
234+
for i in each_point_idx(system)
235+
params_i = get_params(paramsetup, i)
236+
wvol = calc_weighted_volume(storage, system, mat, params_i, i)
237+
iszero(wvol) && continue
238+
dil = calc_dilatation(storage, system, mat, params_i, wvol, i)
239+
Ψvol = 0.5 * params_i.K * dil^2
240+
Ψdev = 0.0
241+
for bond_id in each_bond_idx(system, i)
242+
bond = bonds[bond_id]
243+
j, L = bond.neighbor, bond.length
244+
l = bond_length[bond_id]
245+
e = l - L
246+
edev = e - 1/3 * dil * L
247+
ωij = kernel(system, bond_id) * bond_active[bond_id]
248+
β = surface_correction_factor(correction, bond_id)
249+
params_j = get_params(paramsetup, j)
250+
G = (params_i.G + params_j.G) / 2
251+
cdev = 15.0 * G / (2 * wvol)
252+
Ψdev += cdev * ωij * β * edev * edev * volume[j]
253+
end
254+
Ψ = Ψvol + Ψdev
255+
strain_energy_density[i] = Ψ
256+
end
257+
return strain_energy_density
258+
end
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
@testsnippet PsiExport begin
2+
using Peridynamics.StaticArrays, Peridynamics.Printf
3+
mean(x) = sum(x) / length(x)
4+
function test_stendens(body, ts, F_a, Ψ_a, tols; testcase="")
5+
dh = Peridynamics.threads_data_handler(body, ts, 1)
6+
Peridynamics.initialize!(dh, ts)
7+
(; mat, system, storage, paramsetup) = dh.chunks[1]
8+
field = Val{:strain_energy_density}()
9+
10+
# no deformation -> no strain energy density
11+
storage.position .= system.position
12+
Ψ_0 = Peridynamics.export_field(field, mat, system, storage, paramsetup, 0.0)
13+
@test all(isapprox.(Ψ_0, 0.0; atol=eps()))
14+
15+
# apply deformation gradient F_a
16+
for i in Peridynamics.each_point_idx(system)
17+
Xi = Peridynamics.get_vector(system.position, i)
18+
xi = F_a * Xi
19+
Peridynamics.update_vector!(storage.position, i, xi)
20+
end
21+
Peridynamics.calc_force_density!(dh, 0.0, 0.0)
22+
23+
Ψ_pd = Peridynamics.export_field(field, mat, system, storage, paramsetup, 0.0)
24+
Ψ̂_pd = mean(Ψ_pd)
25+
ΔΨ = (Ψ_pd .- Ψ_a) ./ Ψ_a
26+
ΔΨ_max, ΔΨ_min = maximum(ΔΨ), minimum(ΔΨ)
27+
28+
# write detailed printed output that shows the calculation results
29+
println("-"^20 * " Ψ TEST " * "-"^20)
30+
if !isempty(testcase)
31+
@printf("Test case: %s\n", testcase)
32+
end
33+
@printf("material: %s\n", nameof(typeof(mat)))
34+
@printf("Expected Ψ: %.6g\n", Ψ_a)
35+
@printf("Calc. mean(Ψ): %.6g\n", Ψ̂_pd)
36+
@printf(" mean error: %7.2f %%\n", (Ψ̂_pd - Ψ_a) / Ψ_a * 100)
37+
@printf(" min rel. error: %7.2f %%\n", ΔΨ_min * 100)
38+
@printf(" max rel. error: %7.2f %%\n", ΔΨ_max * 100)
39+
println("-"^50)
40+
41+
@test ΔΨ_min > tols[1]
42+
@test ΔΨ_max < tols[2]
43+
return nothing
44+
end
45+
end
46+
47+
@testitem "Strain energy density export BBMaterial" setup=[PsiExport] begin
48+
Δx = 0.2
49+
horizon = 3.01Δx
50+
E = 210e9
51+
nu = 0.25
52+
λ = 1.05
53+
pos, vol = uniform_box(1,1,1,Δx)
54+
mat = BBMaterial{NoCorrection}()
55+
body = Body(mat, pos, vol)
56+
material!(body; horizon, rho=8000, E, nu)
57+
params = body.point_params[1]
58+
ts = VelocityVerlet(steps=1)
59+
60+
testcase = "homogeneous isotropic extension"
61+
ε = λ - 1
62+
F_a = @SMatrix0 0; 0 λ 0; 0 0 λ]
63+
Ψ_a = 9/2 * params.K * ε^2
64+
tols = (-0.9, 0.3)
65+
test_stendens(body, ts, F_a, Ψ_a, tols; testcase)
66+
67+
testcase = "pure shear deformation"
68+
β = 0.1
69+
F_a = @SMatrix [1 β 0; 0 1 0; 0 0 1]
70+
Ψ_a = 1/2 * params.G * β^2
71+
tols = (-0.9, 0.3)
72+
test_stendens(body, ts, F_a, Ψ_a, tols; testcase)
73+
74+
testcase = "uniform extension in x-direction"
75+
λ = 1.1
76+
ε = λ - 1
77+
F_a = @SMatrix0 0; 0 1 0; 0 0 1]
78+
Ψ_a = 3/5 * params.E * ε^2
79+
tols = (-0.9, 0.3)
80+
test_stendens(body, ts, F_a, Ψ_a, tols; testcase)
81+
end
82+
83+
@testitem "Strain energy density export OSBMaterial" setup=[PsiExport] begin
84+
Δx = 0.2
85+
horizon = 3.01Δx
86+
E = 210e9
87+
nu = 0.25
88+
λ = 1.05
89+
pos, vol = uniform_box(1,1,1,Δx)
90+
mat = OSBMaterial{NoCorrection}()
91+
body = Body(mat, pos, vol)
92+
material!(body; horizon, rho=8000, E, nu)
93+
params = body.point_params[1]
94+
ts = VelocityVerlet(steps=1)
95+
96+
testcase = "homogeneous isotropic extension"
97+
ε = λ - 1
98+
F_a = @SMatrix0 0; 0 λ 0; 0 0 λ]
99+
Ψ_a = 9/2 * params.K * ε^2
100+
tols = (-1e-5, 1e-5) # should be very accurate for a homogeneous iso. extension
101+
test_stendens(body, ts, F_a, Ψ_a, tols; testcase)
102+
103+
testcase = "pure shear deformation"
104+
β = 0.1
105+
F_a = @SMatrix [1 β 0; 0 1 0; 0 0 1]
106+
Ψ_a = 1/2 * params.G * β^2
107+
tols = (-0.4, 0.4) # higher errors
108+
test_stendens(body, ts, F_a, Ψ_a, tols; testcase)
109+
110+
testcase = "uniform extension in x-direction"
111+
λ = 1.1
112+
ε = λ - 1
113+
F_a = @SMatrix0 0; 0 1 0; 0 0 1]
114+
Ψ_a = 1/2 * params.λ * ε^2 + params.μ * ε^2
115+
tols = (-0.9, 0.3)
116+
test_stendens(body, ts, F_a, Ψ_a, tols; testcase)
117+
end

0 commit comments

Comments
 (0)