Skip to content

Commit 2f3502c

Browse files
authored
Merge pull request #220 from kaipartmann/rk
Reproducing kernel peridynamics formulation
2 parents 7c3a080 + f354022 commit 2f3502c

24 files changed

+2242
-76
lines changed

docs/src/private_api_reference.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Peridynamics.apply_precrack!
2525
Peridynamics.point_sets_intersect
2626
Peridynamics.velocity_databc!
2727
Peridynamics.forcedensity_databc!
28+
Peridynamics.invreg
2829
2930
Peridynamics.InterfaceError
3031
Peridynamics.HaloExchange
@@ -55,4 +56,5 @@ Peridynamics.PosDepSingleDimIC
5556
Peridynamics.ShortRangeForceContact
5657
5758
Peridynamics.@storage
59+
Peridynamics.@autoinfiltrate
5860
```

docs/src/public_api_reference.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ CMaterial
1717
CRMaterial
1818
BACMaterial
1919
CKIMaterial
20+
RKCMaterial
21+
RKCRMaterial
2022
```
2123

2224
## System or material related types
@@ -30,8 +32,10 @@ LinearElastic
3032
NeoHooke
3133
MooneyRivlin
3234
SaintVenantKirchhoff
35+
const_one_kernel
3336
linear_kernel
3437
cubic_b_spline_kernel
38+
cubic_b_spline_kernel_norm
3539
```
3640

3741
## Discretization

src/Peridynamics.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ import LibGit2, Dates
1010

1111
# Material models
1212
export BBMaterial, DHBBMaterial, OSBMaterial, CMaterial, CRMaterial, BACMaterial,
13-
CKIMaterial
13+
CKIMaterial, RKCMaterial, RKCRMaterial
1414

1515
# CMaterial related types
1616
export LinearElastic, NeoHooke, MooneyRivlin, SaintVenantKirchhoff, ZEMSilling, ZEMWan
1717

1818
# Kernels
19-
export linear_kernel, cubic_b_spline_kernel
19+
export const_one_kernel, linear_kernel, cubic_b_spline_kernel, cubic_b_spline_kernel_norm
2020

2121
# Damage models
2222
export CriticalStretch
@@ -78,6 +78,7 @@ abstract type AbstractCondition end
7878
abstract type AbstractBondSystemMaterial{Correction} <: AbstractMaterial end
7979
abstract type AbstractBondBasedMaterial{CM} <: AbstractBondSystemMaterial{CM} end
8080
abstract type AbstractCorrespondenceMaterial{CM,ZEM} <: AbstractBondSystemMaterial{ZEM} end
81+
abstract type AbstractRKCMaterial{CM,C} <: AbstractBondSystemMaterial{C} end
8182
abstract type AbstractBondAssociatedSystemMaterial <: AbstractMaterial end
8283
abstract type AbstractConstitutiveModel end
8384
abstract type AbstractStressIntegration end
@@ -93,6 +94,7 @@ include("auxiliary/mpi.jl")
9394
include("auxiliary/errors.jl")
9495
include("auxiliary/static_arrays.jl")
9596
include("auxiliary/nans.jl")
97+
include("auxiliary/autoinfiltrate.jl")
9698

9799
include("physics/boundary_conditions.jl")
98100
include("physics/initial_conditions.jl")
@@ -140,6 +142,8 @@ include("physics/ordinary_state_based.jl")
140142
include("physics/constitutive_models.jl")
141143
include("physics/correspondence.jl")
142144
include("physics/correspondence_rotated.jl")
145+
include("physics/rk_correspondence.jl")
146+
include("physics/rk_correspondence_rotated.jl")
143147
include("physics/ba_correspondence.jl")
144148

145149
include("VtkReader/VtkReader.jl")

src/auxiliary/autoinfiltrate.jl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
@autoinfiltrate
3+
@autoinfiltrate condition::Bool
4+
5+
$(internal_api_warning())
6+
7+
Invoke the `@infiltrate` macro of the package Infiltrator.jl to create a breakpoint for
8+
ad-hoc interactive debugging in the REPL. If the optional argument `condition` is given, the
9+
breakpoint is only enabled if `condition` evaluates to `true`.
10+
11+
As opposed to using `Infiltrator.@infiltrate` directly, this macro does not require
12+
Infiltrator.jl to be added as a dependency to Peridynamics.jl. As a bonus, the macro will
13+
also attempt to load the Infiltrator module if it has not yet been loaded manually.
14+
15+
Note: For this macro to work, the Infiltrator.jl package needs to be installed in your
16+
current Julia environment stack.
17+
18+
See also: [Infiltrator.jl](https://github.com/JuliaDebug/Infiltrator.jl)
19+
"""
20+
macro autoinfiltrate(condition=true)
21+
pkgid = Base.PkgId(Base.UUID("5903a43b-9cc3-4c30-8d17-598619ec4e9b"), "Infiltrator")
22+
if !haskey(Base.loaded_modules, pkgid)
23+
try
24+
Base.eval(Main, :(using Infiltrator))
25+
catch
26+
end
27+
end
28+
i = get(Base.loaded_modules, pkgid, nothing)
29+
lnn = LineNumberNode(__source__.line, __source__.file)
30+
error_msg = "Cannot load Infiltrator.jl!"
31+
error_msg *= "Make sure it is included in your environment stack."
32+
isnothing(i) && return Expr(:macrocall, Symbol("@warn"), lnn, error_msg)
33+
return Expr(:macrocall, Expr(:., i, QuoteNode(Symbol("@infiltrate"))), lnn,
34+
esc(condition))
35+
end

src/auxiliary/nans.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ function containsnan(K::T) where {T<:AbstractArray}
55
return false
66
end
77

8-
function nancheck(chunk::AbstractBodyChunk, t)
8+
function nancheck(chunk::AbstractBodyChunk, t, Δt)
99
if containsnan(chunk.storage.b_int)
10-
msg = "NaN's found in field `b_int` at simulation time $(t)!\n"
10+
n = (t > 0 && Δt > 0) ? Int(t ÷ Δt) : 0
11+
msg = "NaN's found in field `b_int` at simulation time $(t), step $(n)!\n"
1112
error(msg)
1213
end
1314
return nothing

src/auxiliary/static_arrays.jl

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,64 @@
11

2-
@inline function get_tensor(T::AbstractMatrix, i::Int)
3-
tensor = SMatrix{3,3}(T[1, i], T[2, i], T[3, i], T[4, i], T[5, i], T[6, i], T[7, i],
4-
T[8, i], T[9, i])
2+
@inline function get_tensor(Mₙ::AbstractMatrix{T}, i::Int) where {T}
3+
tensor = SMatrix{3,3,T,9}(Mₙ[1, i], Mₙ[2, i], Mₙ[3, i], Mₙ[4, i], Mₙ[5, i], Mₙ[6, i],
4+
Mₙ[7, i], Mₙ[8, i], Mₙ[9, i])
55
return tensor
66
end
77

8-
@inline function update_tensor!(Tₙ::AbstractMatrix, i::Int, Tₙ₊₁::SMatrix{3,3})
9-
Tₙ[1, i] = Tₙ₊₁[1, 1]
10-
Tₙ[2, i] = Tₙ₊₁[1, 2]
11-
Tₙ[3, i] = Tₙ₊₁[1, 3]
12-
Tₙ[4, i] = Tₙ₊₁[2, 1]
13-
Tₙ[5, i] = Tₙ₊₁[2, 2]
14-
Tₙ[6, i] = Tₙ₊₁[2, 3]
15-
Tₙ[7, i] = Tₙ₊₁[3, 1]
16-
Tₙ[8, i] = Tₙ₊₁[3, 2]
17-
Tₙ[9, i] = Tₙ₊₁[3, 3]
8+
@inline function update_tensor!(Mₙ::AbstractMatrix{T}, i::Int,
9+
Tₙ₊₁::StaticMatrix{3,3,T}) where {T}
10+
Mₙ[1, i] = Tₙ₊₁[1]
11+
Mₙ[2, i] = Tₙ₊₁[2]
12+
Mₙ[3, i] = Tₙ₊₁[3]
13+
Mₙ[4, i] = Tₙ₊₁[4]
14+
Mₙ[5, i] = Tₙ₊₁[5]
15+
Mₙ[6, i] = Tₙ₊₁[6]
16+
Mₙ[7, i] = Tₙ₊₁[7]
17+
Mₙ[8, i] = Tₙ₊₁[8]
18+
Mₙ[9, i] = Tₙ₊₁[9]
1819
return nothing
1920
end
2021

21-
@inline function get_vector(M::AbstractMatrix, i::Int)
22-
return SVector{3}(M[1, i], M[2, i], M[3, i])
22+
@inline function get_vector(M::AbstractMatrix{T}, i::Int) where {T}
23+
return SVector{3,T}(M[1, i], M[2, i], M[3, i])
2324
end
2425

25-
@inline function update_vector!(Mₙ::AbstractMatrix, i::Int, Vₙ₊₁::SVector{3})
26+
@inline function update_vector!(Mₙ::AbstractMatrix{T}, i::Int,
27+
Vₙ₊₁::StaticVector{3,T}) where {T}
2628
Mₙ[1, i] = Vₙ₊₁[1]
2729
Mₙ[2, i] = Vₙ₊₁[2]
2830
Mₙ[3, i] = Vₙ₊₁[3]
2931
return nothing
3032
end
3133

32-
@inline function update_add_vector!(Mₙ::AbstractMatrix, i::Int, Vₙ₊₁::SVector{3})
34+
@inline function update_add_vector!(Mₙ::AbstractMatrix{T}, i::Int,
35+
Vₙ₊₁::StaticVector{3,T}) where {T}
3336
Mₙ[1, i] += Vₙ₊₁[1]
3437
Mₙ[2, i] += Vₙ₊₁[2]
3538
Mₙ[3, i] += Vₙ₊₁[3]
3639
return nothing
3740
end
3841

39-
@inline function get_vector_diff(M::AbstractMatrix, i::Int, j::Int)
40-
return SVector{3}(M[1, j] - M[1, i], M[2, j] - M[2, i], M[3, j] - M[3, i])
42+
@inline function get_vector_diff(M::AbstractMatrix{T}, i::Int, j::Int) where {T}
43+
return SVector{3,T}(M[1, j] - M[1, i], M[2, j] - M[2, i], M[3, j] - M[3, i])
4144
end
4245

46+
"""
47+
invreg(M::StaticMatrix{N,N,T}, threshold::Real=eps()) where {N,T}
48+
49+
Computes the pseudo-inverse of a square static matrix `M` using singular value
50+
decomposition (SVD) with regularization. The regularization is applied to the
51+
singular values, where singular values below the specified `threshold` are set
52+
to zero in the pseudo-inverse. This helps to avoid numerical instability and
53+
ill-conditioning in the inversion process.
54+
55+
# Arguments
56+
- `M::StaticMatrix{N,N,T}`: The square `N`×`N` static matrix with element type `T` to be
57+
inverted.
58+
- `threshold::Real=eps()`: The threshold value for regularization, should be a positive
59+
real number between 0 and 1. Singular values below this threshold are set to zero in the
60+
pseudo-inverse.
61+
"""
4362
function invreg(M::StaticMatrix{N,N,T}, threshold::Real=eps()) where {N,T}
4463
U, S, V = svd(M)
4564
Sinvreg = SVector{N,T}((s > threshold ? 1/s : 0) for s in S)

src/discretization/bond_system.jl

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ function find_bonds!(bonds::Vector{Bond}, nhs::PointNeighbors.GridNeighborhoodSe
116116
end
117117

118118
@inline function check_point_duplicates(L::Float64, i::Int, j::Int)
119-
if L == 0
119+
if L < eps()
120120
msg = "point duplicate found!\n"
121121
msg *= "Point #$(i) has a duplicate #$(j) which will lead to `NaN`s!\n"
122122
error(msg)
@@ -232,18 +232,18 @@ end
232232
function break_bonds!(storage::AbstractStorage, system::AbstractBondSystem,
233233
set_a::Vector{Int}, set_b::Vector{Int})
234234
storage.n_active_bonds .= 0
235-
for point_id in each_point_idx(system)
236-
for bond_id in each_bond_idx(system, point_id)
235+
for i in each_point_idx(system)
236+
for bond_id in each_bond_idx(system, i)
237237
bond = system.bonds[bond_id]
238238
neighbor_id = bond.neighbor
239-
point_in_a = in(point_id, set_a)
240-
point_in_b = in(point_id, set_b)
239+
point_in_a = in(i, set_a)
240+
point_in_b = in(i, set_b)
241241
neigh_in_a = in(neighbor_id, set_a)
242242
neigh_in_b = in(neighbor_id, set_b)
243243
if (point_in_a && neigh_in_b) || (point_in_b && neigh_in_a)
244244
storage.bond_active[bond_id] = false
245245
end
246-
storage.n_active_bonds[point_id] += storage.bond_active[bond_id]
246+
storage.n_active_bonds[i] += storage.bond_active[bond_id]
247247
end
248248
end
249249
return nothing
@@ -264,12 +264,22 @@ function calc_force_density!(chunk::AbstractBodyChunk{<:AbstractBondSystem}, t,
264264
(; dmgmodel) = mat
265265
storage.b_int .= 0
266266
storage.n_active_bonds .= 0
267-
for point_id in each_point_idx(chunk)
268-
calc_failure!(storage, system, mat, dmgmodel, paramsetup, point_id)
269-
calc_damage!(storage, system, mat, dmgmodel, paramsetup, point_id)
270-
force_density_point!(storage, system, mat, paramsetup, t, Δt, point_id)
267+
for i in each_point_idx(chunk)
268+
calc_failure!(storage, system, mat, dmgmodel, paramsetup, i)
269+
calc_damage!(storage, system, mat, dmgmodel, paramsetup, i)
270+
force_density_point!(storage, system, mat, paramsetup, t, Δt, i)
271271
end
272-
nancheck(chunk, t)
272+
nancheck(chunk, t, Δt)
273+
return nothing
274+
end
275+
276+
# a placeholder function for all force density calculations with multiple parameters that
277+
# are not specifially handled by the material
278+
function force_density_point!(storage::AbstractStorage, system::AbstractBondSystem,
279+
mat::AbstractBondSystemMaterial,
280+
paramhandler::AbstractParameterHandler, t, Δt, i)
281+
params = get_params(paramhandler, i)
282+
force_density_point!(storage, system, mat, params, t, Δt, i)
273283
return nothing
274284
end
275285

@@ -393,7 +403,9 @@ function log_material_property(::Val{:kernel}, mat::AbstractBondSystemMaterial;
393403
return msg
394404
end
395405

396-
function log_material(mat::M; indentation::Int=2) where {M<:AbstractCorrespondenceMaterial}
406+
function log_material(mat::M;
407+
indentation::Int=2) where {M<:Union{AbstractCorrespondenceMaterial,
408+
AbstractRKCMaterial}}
397409
msg = msg_qty("material type", nameof(M); indentation)
398410
for prop in fieldnames(M)
399411
msg *= log_material_property(Val(prop), mat; indentation)

src/discretization/interaction_system.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ function calc_force_density!(chunk::AbstractBodyChunk{<:InteractionSystem}, t,
427427
calc_damage!(storage, system, mat, dmgmodel, paramsetup, point_id)
428428
force_density_point!(storage, system, mat, paramsetup, t, Δt, point_id)
429429
end
430-
nancheck(chunk, t)
430+
nancheck(chunk, t, Δt)
431431
return nothing
432432
end
433433

src/discretization/kernels.jl

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
@doc raw"""
2+
const_one_kernel(δ, L)
3+
4+
A kernel function ``\omega`` (also called influence function) used for weighting the
5+
bonds in a family. The kernel function is simply defined as a constant value 1:
6+
```math
7+
\omega = 1
8+
```
9+
"""
10+
@inline const_one_kernel(δ, L) = 1
11+
112
@doc raw"""
213
linear_kernel(δ, L)
314
@@ -39,3 +50,35 @@ with the horizon ``\delta`` and the initial bond length ``L``.
3950
return 0
4051
end
4152
end
53+
54+
@doc raw"""
55+
cubic_b_spline_kernel_norm(δ, L)
56+
57+
A cubic B-spline kernel function ``\omega`` used for weighting the bonds in a family.
58+
The kernel function is defined as
59+
```math
60+
\begin{aligned}
61+
\xi &= \frac{L}{\delta} \; , \\
62+
\omega &= \frac{8}{\pi \, \delta^3} \cdot \left\{
63+
\begin{array}{ll}
64+
1 - 6 \xi^2 + 6 \xi^3 & \quad \text{if} \; 0 < \xi \leq 0.5 \; , \\[3pt]
65+
2 (1 - \xi)^3 & \quad \text{if} \; 0.5 < \xi \leq 1 \; , \\[3pt]
66+
0 & \quad \text{else} \; ,
67+
\end{array}
68+
\right.
69+
\end{aligned}
70+
```
71+
with the horizon ``\delta`` and the initial bond length ``L``. This kernel is properly
72+
normalized to satisfy the condition ``\int_{\mathcal{H}(X)} \omega(\Delta X) dV' = 1``.
73+
"""
74+
@inline function cubic_b_spline_kernel_norm(δ, L)
75+
ξ = L / δ
76+
C = 8.0/* δ^3)
77+
if 0 < ξ 0.5
78+
return C * (1 - 6 * ξ^2 + 6 * ξ^3)
79+
elseif 0.5 < ξ 1
80+
return C * 2 * (1 - ξ)^3
81+
else
82+
return 0
83+
end
84+
end

src/physics/ba_correspondence.jl

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -189,14 +189,6 @@ function init_field(::BACMaterial, ::AbstractTimeSolver, system::BondAssociatedS
189189
return zeros(get_n_loc_points(system))
190190
end
191191

192-
function force_density_point!(storage::BACStorage, system::BondAssociatedSystem,
193-
mat::BACMaterial, paramhandler::AbstractParameterHandler,
194-
t, Δt, i)
195-
params = get_params(paramhandler, i)
196-
force_density_point!(storage, system, mat, params, t, Δt, i)
197-
return nothing
198-
end
199-
200192
function force_density_point!(storage::BACStorage, system::BondAssociatedSystem,
201193
mat::BACMaterial, params::BACPointParameters, t, Δt, i)
202194
for bond_idx in each_bond_idx(system, i)

0 commit comments

Comments
 (0)