From 32434567dc4882ace95c3a4ce9a7157fca1d6570 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Sat, 19 Oct 2024 14:33:48 +0200 Subject: [PATCH 01/40] Renaming NOSB* -> CC* --- docs/src/api_reference.md | 2 +- docs/src/literate/tutorial_wave_interface.jl | 2 +- src/Peridynamics.jl | 2 +- src/auxiliary/precompile_workload.jl | 6 +-- src/physics/correspondence.jl | 44 ++++++++++---------- test/auxiliary/test_io.jl | 8 ++-- test/integration/b_int_correspondence.jl | 4 +- test/integration/mpi_threads_comparison.jl | 14 +++---- test/integration/symmetry_correspondence.jl | 8 ++-- 9 files changed, 45 insertions(+), 45 deletions(-) diff --git a/docs/src/api_reference.md b/docs/src/api_reference.md index c797e380..10300587 100644 --- a/docs/src/api_reference.md +++ b/docs/src/api_reference.md @@ -12,7 +12,7 @@ Pages = ["api_reference.md"] ```@docs BBMaterial OSBMaterial -NOSBMaterial +CCMaterial CKIMaterial ``` diff --git a/docs/src/literate/tutorial_wave_interface.jl b/docs/src/literate/tutorial_wave_interface.jl index 4fbefb4e..a4a21a1a 100644 --- a/docs/src/literate/tutorial_wave_interface.jl +++ b/docs/src/literate/tutorial_wave_interface.jl @@ -19,7 +19,7 @@ npyz = 4 # With these parameters we now create a body, here using the non-ordinary state-based # correspondence formulation. pos, vol = uniform_box(lx, lyz, lyz, Δx) -body = Body(NOSBMaterial(), pos, vol) +body = Body(CCMaterial(), pos, vol) # Again, failure is not allowed in the whole body. failure_permit!(body, false) diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index c3c3a4e8..f315dd79 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -9,7 +9,7 @@ end import LibGit2, Dates # Material models -export BBMaterial, OSBMaterial, NOSBMaterial, CKIMaterial +export BBMaterial, OSBMaterial, CCMaterial, CKIMaterial # Systems related types export NoCorrection, EnergySurfaceCorrection diff --git a/src/auxiliary/precompile_workload.jl b/src/auxiliary/precompile_workload.jl index af9b9b38..8ae053ed 100644 --- a/src/auxiliary/precompile_workload.jl +++ b/src/auxiliary/precompile_workload.jl @@ -10,7 +10,7 @@ pos2, vol2 = uniform_box(1, 1, 1, 0.5; center=(-0.5, 0.5, 0.5)) path_bb = joinpath(root, "BB") path_osb = joinpath(root, "OSB") - path_nosb = joinpath(root, "NOSB") + path_cc = joinpath(root, "CC") path_ms = joinpath(root, "MS") @compile_workload begin @@ -43,7 +43,7 @@ velocity_bc!(t -> -1, b2, :set_a, :x) velocity_bc!(t -> 1, b2, :set_b, 1) - b3 = Body(NOSBMaterial(), pos1, vol1) + b3 = Body(CCMaterial(), pos1, vol1) material!(b3; horizon=2, E=2.1e5, nu=0.25, rho=8e-6, Gc=2.7) point_set!(p -> p[1] ≤ 0.5, b3, :set_a) point_set!(x -> x > 0.5, b3, :set_b) @@ -65,7 +65,7 @@ submit(Job(b1, vv; path=path_bb, freq=1); quiet=true) submit(Job(b2, vv; path=path_osb, freq=1); quiet=true) - submit(Job(b3, vv; path=path_nosb, freq=1); quiet=true) + submit(Job(b3, vv; path=path_cc, freq=1); quiet=true) submit(Job(ms, vv; path=path_ms, freq=1); quiet=true) end diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index 8708477b..18c76c5e 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -1,5 +1,5 @@ """ - NOSBMaterial(; maxdmg, maxjacobi, corr) + CCMaterial(; maxdmg, maxjacobi, corr) A material type used to assign the material of a [`Body`](@ref) with the local continuum consistent (correspondence) formulation of non-ordinary state-based peridynamics. @@ -24,14 +24,14 @@ consistent (correspondence) formulation of non-ordinary state-based peridynamics # Examples ```julia-repl -julia> mat = NOSBMaterial() -NOSBMaterial(maxdmg=0.95, maxjacobi=1.03, corr=100.0) +julia> mat = CCMaterial() +CCMaterial(maxdmg=0.95, maxjacobi=1.03, corr=100.0) ``` --- ```julia -NOSBMaterial +CCMaterial ``` Material type for the local continuum consistent (correspondence) formulation of @@ -46,7 +46,7 @@ non-ordinary state-based peridynamics. constructor docs for more informations. # Allowed material parameters -When using [`material!`](@ref) on a [`Body`](@ref) with `NOSBMaterial`, then the following +When using [`material!`](@ref) on a [`Body`](@ref) with `CCMaterial`, then the following parameters are allowed: - `horizon::Float64`: Radius of point interactions - `rho::Float64`: Density @@ -57,7 +57,7 @@ parameters are allowed: # Allowed export fields When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with -`NOSBMaterial`, the following fields are allowed: +`CCMaterial`, the following fields are allowed: - `position::Matrix{Float64}`: Position of each point - `displacement::Matrix{Float64}`: Displacement of each point - `velocity::Matrix{Float64}`: Velocity of each point @@ -68,19 +68,19 @@ When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with - `damage::Vector{Float64}`: Damage of each point - `n_active_bonds::Vector{Int}`: Number of intact bonds of each point """ -Base.@kwdef struct NOSBMaterial <: AbstractBondSystemMaterial{NoCorrection} +Base.@kwdef struct CCMaterial <: AbstractBondSystemMaterial{NoCorrection} maxdmg::Float64 = 0.95 maxjacobi::Float64 = 1.03 corr::Float64 = 100.0 end -function Base.show(io::IO, @nospecialize(mat::NOSBMaterial)) +function Base.show(io::IO, @nospecialize(mat::CCMaterial)) print(io, typeof(mat)) print(io, msg_fields_in_brackets(mat)) return nothing end -struct NOSBPointParameters <: AbstractPointParameters +struct CCPointParameters <: AbstractPointParameters δ::Float64 rho::Float64 E::Float64 @@ -94,16 +94,16 @@ struct NOSBPointParameters <: AbstractPointParameters bc::Float64 end -function NOSBPointParameters(mat::NOSBMaterial, p::Dict{Symbol,Any}) +function CCPointParameters(mat::CCMaterial, p::Dict{Symbol,Any}) (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) (; Gc, εc) = get_frac_params(p, δ, K) bc = 18 * K / (π * δ^4) # bond constant - return NOSBPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) + return CCPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) end -@params NOSBMaterial NOSBPointParameters +@params CCMaterial CCPointParameters -@storage NOSBMaterial struct NOSBStorage <: AbstractStorage +@storage CCMaterial struct CCStorage <: AbstractStorage @lthfield position::Matrix{Float64} @pointfield displacement::Matrix{Float64} @pointfield velocity::Matrix{Float64} @@ -119,19 +119,19 @@ end @pointfield n_active_bonds::Vector{Int} end -function init_field(::NOSBMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int}) +function init_field(::CCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int}) return zeros(3, get_n_points(system)) end -function force_density_point!(storage::NOSBStorage, system::BondSystem, mat::NOSBMaterial, +function force_density_point!(storage::CCStorage, system::BondSystem, mat::CCMaterial, paramhandler::AbstractParameterHandler, i::Int) params = get_params(paramhandler, i) force_density_point!(storage, system, mat, params, i) return nothing end -function force_density_point!(storage::NOSBStorage, system::BondSystem, mat::NOSBMaterial, - params::NOSBPointParameters, i::Int) +function force_density_point!(storage::CCStorage, system::BondSystem, mat::CCMaterial, + params::CCPointParameters, i::Int) F, Kinv, ω0 = calc_deformation_gradient(storage, system, mat, params, i) if storage.damage[i] > mat.maxdmg || containsnan(F) kill_point!(storage, system, i) @@ -167,12 +167,12 @@ function force_density_point!(storage::NOSBStorage, system::BondSystem, mat::NOS return nothing end -@inline function influence_function(::NOSBMaterial, params::NOSBPointParameters, L::Float64) +@inline function influence_function(::CCMaterial, params::CCPointParameters, L::Float64) return params.δ / L end -function calc_deformation_gradient(storage::NOSBStorage, system::BondSystem, - mat::NOSBMaterial, params::NOSBPointParameters, i::Int) +function calc_deformation_gradient(storage::CCStorage, system::BondSystem, + mat::CCMaterial, params::CCPointParameters, i::Int) K = zeros(SMatrix{3,3}) _F = zeros(SMatrix{3,3}) ω0 = 0.0 @@ -193,8 +193,8 @@ function calc_deformation_gradient(storage::NOSBStorage, system::BondSystem, return F, Kinv, ω0 end -function calc_first_piola_stress(F::SMatrix{3,3}, mat::NOSBMaterial, - params::NOSBPointParameters) +function calc_first_piola_stress(F::SMatrix{3,3}, mat::CCMaterial, + params::CCPointParameters) J = det(F) J < eps() && return zero(SMatrix{3,3}) J > mat.maxjacobi && return zero(SMatrix{3,3}) diff --git a/test/auxiliary/test_io.jl b/test/auxiliary/test_io.jl index 1a8fe196..6b11ba7c 100644 --- a/test/auxiliary/test_io.jl +++ b/test/auxiliary/test_io.jl @@ -209,17 +209,17 @@ # setup bbb = Body(BBMaterial(), rand(3, 10), rand(10)) bosb = Body(OSBMaterial(), rand(3, 10), rand(10)) - bnosb = Body(NOSBMaterial(), rand(3, 10), rand(10)) - ms = MultibodySetup(:a => bbb, :b => bosb, :c => bnosb) + bcc = Body(CCMaterial(), rand(3, 10), rand(10)) + ms = MultibodySetup(:a => bbb, :b => bosb, :c => bcc) vv = VelocityVerlet(steps=1) dr = DynamicRelaxation(steps=1) tests_body_specific(bbb, vv) tests_body_specific(bosb, vv) - tests_body_specific(bnosb, vv) + tests_body_specific(bcc, vv) tests_body_specific(bbb, dr) tests_body_specific(bosb, dr) - tests_body_specific(bnosb, dr) + tests_body_specific(bcc, dr) tests_multibody_specific(ms, vv) diff --git a/test/integration/b_int_correspondence.jl b/test/integration/b_int_correspondence.jl index d64d26c1..a0c24388 100644 --- a/test/integration/b_int_correspondence.jl +++ b/test/integration/b_int_correspondence.jl @@ -4,7 +4,7 @@ 0.0 0.0 0.0 1.0 2.0] volume = fill(1.0, 5) δ = 1.5 - body = Body(NOSBMaterial(), ref_position, volume) + body = Body(CCMaterial(), ref_position, volume) material!(body, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) failure_permit!(body, false) @@ -36,7 +36,7 @@ end 0.0 0.0 0.0 1.0 2.0] volume = fill(1.0, 5) δ = 1.5 - body = Body(NOSBMaterial(), ref_position, volume) + body = Body(CCMaterial(), ref_position, volume) point_set!(body, :a, [1]) point_set!(body, :b, [2,3,4,5]) material!(body, :a, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) diff --git a/test/integration/mpi_threads_comparison.jl b/test/integration/mpi_threads_comparison.jl index ea5505fa..a57fcf47 100644 --- a/test/integration/mpi_threads_comparison.jl +++ b/test/integration/mpi_threads_comparison.jl @@ -199,18 +199,18 @@ end rm(root; recursive=true, force=true) end -@testitem "MPI-Threads comparison NOSBMaterial" begin +@testitem "MPI-Threads comparison CCMaterial" begin root = joinpath(@__DIR__, "temp_mpi_threads_comparison_cc") path_threads = joinpath(root, "results_threads") path_threads_vtk = joinpath(path_threads, "vtk") path_mpi = joinpath(root, "results_mpi") path_mpi_vtk = joinpath(path_mpi, "vtk") - function sim_nosb(N::Int, path::String) + function sim_cc(N::Int, path::String) l, Δx, δ, a = 1.0, 1/N, 3.015/N, 0.5 pos, vol = uniform_box(l, l, 0.1l, Δx) ids = sortperm(pos[2,:]) - b = Body(NOSBMaterial(), pos[:, ids], vol[ids]) + b = Body(CCMaterial(), pos[:, ids], vol[ids]) material!(b; horizon=3.015Δx, E=2.1e5, nu=0.25, rho=8e-6, Gc=2.7) point_set!(p -> p[1] ≤ -l/2+a && 0 ≤ p[2] ≤ 2δ, b, :set_a) point_set!(p -> p[1] ≤ -l/2+a && -2δ ≤ p[2] < 0, b, :set_b) @@ -224,15 +224,15 @@ end submit(job) return nothing end - sim_nosb(30, path_threads) + sim_cc(30, path_threads) mpi_cmd = """ using Peridynamics - function sim_nosb(N::Int, path::String) + function sim_cc(N::Int, path::String) l, Δx, δ, a = 1.0, 1/N, 3.015/N, 0.5 pos, vol = uniform_box(l, l, 0.1l, Δx) ids = sortperm(pos[2,:]) - b = Body(NOSBMaterial(), pos[:, ids], vol[ids]) + b = Body(CCMaterial(), pos[:, ids], vol[ids]) material!(b; horizon=3.015Δx, E=2.1e5, nu=0.25, rho=8e-6, Gc=2.7) point_set!(p -> p[1] ≤ -l/2+a && 0 ≤ p[2] ≤ 2δ, b, :set_a) point_set!(p -> p[1] ≤ -l/2+a && -2δ ≤ p[2] < 0, b, :set_b) @@ -246,7 +246,7 @@ end submit(job) return nothing end - sim_nosb(30, "$path_mpi") + sim_cc(30, "$path_mpi") """ run(`$(Peridynamics.MPI.mpiexec()) -n 2 $(Base.julia_cmd()) --project -e $(mpi_cmd)`) diff --git a/test/integration/symmetry_correspondence.jl b/test/integration/symmetry_correspondence.jl index d6c7237f..a141c658 100644 --- a/test/integration/symmetry_correspondence.jl +++ b/test/integration/symmetry_correspondence.jl @@ -1,4 +1,4 @@ -@testitem "symmetry NOSBMaterial VelocityVerlet" begin +@testitem "symmetry CCMaterial VelocityVerlet" begin # simulation Δx = 0.2 width = 1 @@ -8,7 +8,7 @@ pos = hcat(([x;y;z] for x in grid for y in grid for z in grid)...) n_points = size(pos, 2) vol = fill(Δx^3, n_points) - body = Body(NOSBMaterial(), pos, vol) + body = Body(CCMaterial(), pos, vol) failure_permit!(body, false) material!(body, horizon=3.015Δx, rho=7850, E=210e9, nu=0.25, Gc=1) point_set!(z -> z > width/2 - 0.6Δx, body, :set_a) @@ -57,7 +57,7 @@ rm(temp_root; recursive=true, force=true) end -@testitem "symmetry NOSBMaterial DynamicRelaxation" begin +@testitem "symmetry CCMaterial DynamicRelaxation" begin # simulation Δx = 0.2 width = 1 @@ -67,7 +67,7 @@ end pos = hcat(([x;y;z] for x in grid for y in grid for z in grid)...) n_points = size(pos, 2) vol = fill(Δx^3, n_points) - body = Body(NOSBMaterial(), pos, vol) + body = Body(CCMaterial(), pos, vol) failure_permit!(body, false) material!(body, horizon=3.015Δx, rho=7850, E=210e9, nu=0.25, Gc=1) point_set!(z -> z > width/2 - 0.6Δx, body, :set_a) From f7539e118f29e1a5e74d3c5e856b6425e73c6004 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Sat, 19 Oct 2024 14:55:33 +0200 Subject: [PATCH 02/40] =?UTF-8?q?Add=20time=20`t`=20and=20time=20step=20`?= =?UTF-8?q?=CE=94t`=20to=20force=20density=20calculation=20functions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/discretization/bond_system.jl | 6 +++--- src/discretization/interaction_system.jl | 6 +++--- src/physics/bond_based.jl | 4 ++-- src/physics/continuum_kinematics_inspired.jl | 20 +++++++++---------- src/physics/correspondence.jl | 14 ++++++------- src/physics/ordinary_state_based.jl | 10 +++++----- src/time_solvers/dynamic_relaxation.jl | 2 +- src/time_solvers/velocity_verlet.jl | 6 +++--- test/integration/b_int_bond_based.jl | 4 ++-- test/integration/b_int_continuum_inspired.jl | 4 ++-- test/integration/b_int_correspondence.jl | 4 ++-- .../integration/b_int_ordinary_state_based.jl | 4 ++-- test/integration/test_material.jl | 2 +- 13 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/discretization/bond_system.jl b/src/discretization/bond_system.jl index 04b3262e..f4de0921 100644 --- a/src/discretization/bond_system.jl +++ b/src/discretization/bond_system.jl @@ -196,17 +196,17 @@ function calc_timestep_point(bd::BondSystem, params::AbstractPointParameters, po return sqrt(2 * params.rho / dtsum) end -function calc_force_density!(chunk::AbstractBodyChunk{S,M}) where {S<:BondSystem,M} +function calc_force_density!(chunk::AbstractBodyChunk{<:BondSystem}, t, Δt) (; system, mat, paramsetup, storage) = chunk storage.b_int .= 0 storage.n_active_bonds .= 0 for point_id in each_point_idx(chunk) - force_density_point!(storage, system, mat, paramsetup, point_id) + force_density_point!(storage, system, mat, paramsetup, t, Δt, point_id) end return nothing end -@inline function calc_damage!(chunk::AbstractBodyChunk{S,M}) where {S<:BondSystem,M} +@inline function calc_damage!(chunk::AbstractBodyChunk{<:BondSystem}) (; n_neighbors) = chunk.system (; n_active_bonds, damage) = chunk.storage for point_id in each_point_idx(chunk) diff --git a/src/discretization/interaction_system.jl b/src/discretization/interaction_system.jl index 7a8fc05e..9338d695 100644 --- a/src/discretization/interaction_system.jl +++ b/src/discretization/interaction_system.jl @@ -354,17 +354,17 @@ function calc_timestep_point(system::InteractionSystem, params::AbstractPointPar return sqrt(2 * params.rho / dtsum) end -function calc_force_density!(chunk::AbstractBodyChunk{S,M}) where {S<:InteractionSystem,M} +function calc_force_density!(chunk::AbstractBodyChunk{<:InteractionSystem}, t, Δt) (; system, mat, paramsetup, storage) = chunk storage.b_int .= 0 storage.n_active_one_nis .= 0 for point_id in each_point_idx(chunk) - force_density_point!(storage, system, mat, paramsetup, point_id) + force_density_point!(storage, system, mat, paramsetup, t, Δt, point_id) end return nothing end -@inline function calc_damage!(chunk::AbstractBodyChunk{S,M}) where {S<:InteractionSystem,M} +@inline function calc_damage!(chunk::AbstractBodyChunk{<:InteractionSystem}) (; n_one_nis) = chunk.system (; n_active_one_nis, damage) = chunk.storage for point_id in each_point_idx(chunk) diff --git a/src/physics/bond_based.jl b/src/physics/bond_based.jl index e872ac6b..2bb1e003 100644 --- a/src/physics/bond_based.jl +++ b/src/physics/bond_based.jl @@ -108,7 +108,7 @@ end end function force_density_point!(storage::BBStorage, system::BondSystem, ::BBMaterial, - params::BBPointParameters, i::Int) + params::BBPointParameters, t, Δt, i) for bond_id in each_bond_idx(system, i) bond = system.bonds[bond_id] j, L = bond.neighbor, bond.length @@ -125,7 +125,7 @@ function force_density_point!(storage::BBStorage, system::BondSystem, ::BBMateri end function force_density_point!(storage::BBStorage, system::BondSystem, ::BBMaterial, - paramhandler::ParameterHandler, i::Int) + paramhandler::ParameterHandler, t, Δt, i) params_i = get_params(paramhandler, i) for bond_id in each_bond_idx(system, i) bond = system.bonds[bond_id] diff --git a/src/physics/continuum_kinematics_inspired.jl b/src/physics/continuum_kinematics_inspired.jl index c46fa768..83a9c1cc 100644 --- a/src/physics/continuum_kinematics_inspired.jl +++ b/src/physics/continuum_kinematics_inspired.jl @@ -97,15 +97,15 @@ end end function force_density_point!(storage::CKIStorage, system::InteractionSystem, - mat::CKIMaterial, params::AbstractParameterSetup, i::Int) - force_density_point_one_ni!(storage, system, mat, params, i) - has_two_nis(params) && force_density_point_two_ni!(storage, system, mat, params, i) - has_three_nis(params) && force_density_point_three_ni!(storage, system, mat, params, i) + mat::CKIMaterial, params::AbstractParameterSetup, t, Δt, i) + force_density_point_one_ni!(storage, system, mat, params, t, Δt, i) + has_two_nis(params) && force_density_point_two_ni!(storage, system, mat, params, t, Δt, i) + has_three_nis(params) && force_density_point_three_ni!(storage, system, mat, params, t, Δt, i) return nothing end function force_density_point_one_ni!(storage::CKIStorage, system::InteractionSystem, - ::CKIMaterial, params::CKIPointParameters, i::Int) + ::CKIMaterial, params::CKIPointParameters, t, Δt, i) for one_ni_id in each_one_ni_idx(system, i) one_ni = system.one_nis[one_ni_id] j, L = one_ni.neighbor, one_ni.length @@ -121,7 +121,7 @@ function force_density_point_one_ni!(storage::CKIStorage, system::InteractionSys end function force_density_point_one_ni!(storage::CKIStorage, system::InteractionSystem, - ::CKIMaterial, paramhandler::ParameterHandler, i::Int) + ::CKIMaterial, paramhandler::ParameterHandler, t, Δt, i) params_i = get_params(paramhandler, i) for one_ni_id in each_one_ni_idx(system, i) one_ni = system.one_nis[one_ni_id] @@ -139,7 +139,7 @@ function force_density_point_one_ni!(storage::CKIStorage, system::InteractionSys end function force_density_point_two_ni!(storage::CKIStorage, system::InteractionSystem, - ::CKIMaterial, params::CKIPointParameters, i::Int) + ::CKIMaterial, params::CKIPointParameters, t, Δt, i) for two_ni_id in each_two_ni_idx(system, i) two_ni = system.two_nis[two_ni_id] oni_j_id, oni_k_id, surface_ref = two_ni.oni_j, two_ni.oni_k, two_ni.surface @@ -176,7 +176,7 @@ function force_density_point_two_ni!(storage::CKIStorage, system::InteractionSys end function force_density_point_two_ni!(storage::CKIStorage, system::InteractionSystem, - ::CKIMaterial, paramhandler::ParameterHandler, i::Int) + ::CKIMaterial, paramhandler::ParameterHandler, t, Δt, i) params_i = get_params(paramhandler, i) for two_ni_id in each_two_ni_idx(system, i) two_ni = system.two_nis[two_ni_id] @@ -216,7 +216,7 @@ function force_density_point_two_ni!(storage::CKIStorage, system::InteractionSys end function force_density_point_three_ni!(storage::CKIStorage, system::InteractionSystem, - ::CKIMaterial, params::CKIPointParameters, i::Int) + ::CKIMaterial, params::CKIPointParameters, t, Δt, i) for three_ni_id in each_three_ni_idx(system, i) three_ni = system.three_nis[three_ni_id] oni_j_id = three_ni.oni_j @@ -276,7 +276,7 @@ end function force_density_point_three_ni!(storage::CKIStorage, system::InteractionSystem, ::CKIMaterial, paramhandler::ParameterHandler, - i::Int) + t, Δt, i) params_i = get_params(paramhandler, i) for three_ni_id in each_three_ni_idx(system, i) three_ni = system.three_nis[three_ni_id] diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index 18c76c5e..bd8a215e 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -124,14 +124,14 @@ function init_field(::CCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Va end function force_density_point!(storage::CCStorage, system::BondSystem, mat::CCMaterial, - paramhandler::AbstractParameterHandler, i::Int) + paramhandler::AbstractParameterHandler, t, Δt, i) params = get_params(paramhandler, i) - force_density_point!(storage, system, mat, params, i) + force_density_point!(storage, system, mat, params, t, Δt, i) return nothing end function force_density_point!(storage::CCStorage, system::BondSystem, mat::CCMaterial, - params::CCPointParameters, i::Int) + params::CCPointParameters, t, Δt, i) F, Kinv, ω0 = calc_deformation_gradient(storage, system, mat, params, i) if storage.damage[i] > mat.maxdmg || containsnan(F) kill_point!(storage, system, i) @@ -167,12 +167,12 @@ function force_density_point!(storage::CCStorage, system::BondSystem, mat::CCMat return nothing end -@inline function influence_function(::CCMaterial, params::CCPointParameters, L::Float64) +@inline function influence_function(::CCMaterial, params::CCPointParameters, L) return params.δ / L end -function calc_deformation_gradient(storage::CCStorage, system::BondSystem, - mat::CCMaterial, params::CCPointParameters, i::Int) +function calc_deformation_gradient(storage::CCStorage, system::BondSystem, mat::CCMaterial, + params::CCPointParameters, i) K = zeros(SMatrix{3,3}) _F = zeros(SMatrix{3,3}) ω0 = 0.0 @@ -213,7 +213,7 @@ function containsnan(K::T) where {T<:AbstractArray} return false end -function kill_point!(s::AbstractStorage, bd::BondSystem, i::Int) +function kill_point!(s::AbstractStorage, bd::BondSystem, i) s.bond_active[each_bond_idx(bd, i)] .= false s.n_active_bonds[i] = 0 return nothing diff --git a/src/physics/ordinary_state_based.jl b/src/physics/ordinary_state_based.jl index d92d86e8..e1ff8639 100644 --- a/src/physics/ordinary_state_based.jl +++ b/src/physics/ordinary_state_based.jl @@ -102,7 +102,7 @@ function init_field(::OSBMaterial, ::AbstractTimeSolver, system::BondSystem, ::V end function force_density_point!(storage::OSBStorage, system::BondSystem, mat::OSBMaterial, - params::OSBPointParameters, i::Int) + params::OSBPointParameters, t, Δt, i) wvol = calc_weighted_volume(storage, system, mat, params, i) iszero(wvol) && return nothing dil = calc_dilatation(storage, system, mat, params, wvol, i) @@ -125,7 +125,7 @@ function force_density_point!(storage::OSBStorage, system::BondSystem, mat::OSBM end function force_density_point!(storage::OSBStorage, system::BondSystem, mat::OSBMaterial, - paramhandler::ParameterHandler, i::Int) + paramhandler::ParameterHandler, t, Δt, i) params_i = get_params(paramhandler, i) wvol = calc_weighted_volume(storage, system, mat, params_i, i) iszero(wvol) && return nothing @@ -149,12 +149,12 @@ function force_density_point!(storage::OSBStorage, system::BondSystem, mat::OSBM return nothing end -@inline function influence_function(::OSBMaterial, params::OSBPointParameters, L::Float64) +@inline function influence_function(::OSBMaterial, params::OSBPointParameters, L) return params.δ / L end function calc_weighted_volume(storage::OSBStorage, system::BondSystem, mat::OSBMaterial, - params::OSBPointParameters, i::Int) + params::OSBPointParameters, i) wvol = 0.0 for bond_id in each_bond_idx(system, i) bond = system.bonds[bond_id] @@ -169,7 +169,7 @@ function calc_weighted_volume(storage::OSBStorage, system::BondSystem, mat::OSBM end function calc_dilatation(storage::OSBStorage, system::BondSystem, mat::OSBMaterial, - params::OSBPointParameters, wvol::Float64, i::Int) + params::OSBPointParameters, wvol, i) dil = 0.0 c1 = 3.0 / wvol for bond_id in each_bond_idx(system, i) diff --git a/src/time_solvers/dynamic_relaxation.jl b/src/time_solvers/dynamic_relaxation.jl index 9e0e648f..d450b334 100644 --- a/src/time_solvers/dynamic_relaxation.jl +++ b/src/time_solvers/dynamic_relaxation.jl @@ -175,7 +175,7 @@ function relaxation_timestep!(dh::AbstractThreadsBodyDataHandler, end @threads :static for chunk_id in eachindex(dh.chunks) exchange_loc_to_halo!(dh, chunk_id) - calc_force_density!(dh.chunks[chunk_id]) + calc_force_density!(dh.chunks[chunk_id], t, Δt) end @threads :static for chunk_id in eachindex(dh.chunks) exchange_halo_to_loc!(dh, chunk_id) diff --git a/src/time_solvers/velocity_verlet.jl b/src/time_solvers/velocity_verlet.jl index f62b0b99..f7521cdb 100644 --- a/src/time_solvers/velocity_verlet.jl +++ b/src/time_solvers/velocity_verlet.jl @@ -189,7 +189,7 @@ function verlet_timestep!(dh::AbstractThreadsBodyDataHandler, options::AbstractJ end @threads :static for chunk_id in eachindex(dh.chunks) exchange_loc_to_halo!(dh, chunk_id) - calc_force_density!(dh.chunks[chunk_id]) + calc_force_density!(dh.chunks[chunk_id], t, Δt) end @threads :static for chunk_id in eachindex(dh.chunks) exchange_halo_to_loc!(dh, chunk_id) @@ -214,7 +214,7 @@ function verlet_timestep!(dh::AbstractThreadsMultibodyDataHandler, end @threads :static for chunk_id in eachindex(body_dh.chunks) exchange_loc_to_halo!(body_dh, chunk_id) - calc_force_density!(body_dh.chunks[chunk_id]) + calc_force_density!(body_dh.chunks[chunk_id], t, Δt) end end update_caches!(dh) @@ -241,7 +241,7 @@ function verlet_timestep!(dh::AbstractMPIBodyDataHandler, options::AbstractJobOp @timeit_debug TO "apply_boundary_conditions!" apply_boundary_conditions!(chunk, t) @timeit_debug TO "update_disp_and_pos!" update_disp_and_pos!(chunk, Δt) @timeit_debug TO "exchange_loc_to_halo!" exchange_loc_to_halo!(dh) - @timeit_debug TO "calc_force_density!" calc_force_density!(chunk) + @timeit_debug TO "calc_force_density!" calc_force_density!(chunk, t, Δt) @timeit_debug TO "exchange_halo_to_loc!" exchange_halo_to_loc!(dh) @timeit_debug TO "calc_damage!" calc_damage!(chunk) @timeit_debug TO "update_acc_and_vel!" update_acc_and_vel!(chunk, Δt½) diff --git a/test/integration/b_int_bond_based.jl b/test/integration/b_int_bond_based.jl index c0745eea..08956302 100644 --- a/test/integration/b_int_bond_based.jl +++ b/test/integration/b_int_bond_based.jl @@ -19,7 +19,7 @@ # Point 2 with v_z = 1 m/s with Δt = 0.0015 s position[1, 2] = 1.0015 - Peridynamics.calc_force_density!(chunk) + Peridynamics.calc_force_density!(chunk, 0, 0) b12 = 18 * E / (3 * (1 - 2 * 0.25)) / (π * δ^4) * 1.0015 * 0.0015/1.0015 * 1.0 @test b_int ≈ [b12 -b12; 0.0 0.0; 0.0 0.0] @@ -51,7 +51,7 @@ end # Point 2 with v_z = 1 m/s with Δt = 0.0015 s position[1, 2] = 1.0015 - Peridynamics.calc_force_density!(chunk) + Peridynamics.calc_force_density!(chunk, 0, 0) b12 = 18 * E / (3 * (1 - 2 * 0.25)) / (π * δ^4) * 1.0015 * 0.0015/1.0015 * 1.0 @test b_int ≈ [b12 -b12; 0.0 0.0; 0.0 0.0] diff --git a/test/integration/b_int_continuum_inspired.jl b/test/integration/b_int_continuum_inspired.jl index 7760ff6a..2513bc5e 100644 --- a/test/integration/b_int_continuum_inspired.jl +++ b/test/integration/b_int_continuum_inspired.jl @@ -21,7 +21,7 @@ # Point 2 with v_z = 1 m/s with Δt = 0.0015 s position[1, 2] = 1.0015 - Peridynamics.calc_force_density!(chunk) + Peridynamics.calc_force_density!(chunk, 0, 0) @test b_int[:,1] ≈ [1.0000000000000625e9, 4.0060000000002503e8, 4.0060000000002503e8] @test b_int[:,2] ≈ [-1.449731150462047e9, 2.245287820579052e8, 2.245287820579052e8] @@ -54,7 +54,7 @@ end # Point 2 with v_z = 1 m/s with Δt = 0.0015 s position[1, 2] = 1.0015 - Peridynamics.calc_force_density!(chunk) + Peridynamics.calc_force_density!(chunk, 0, 0) @test b_int[:,1] ≈ [1.0000000000000625e9, 4.0060000000002503e8, 4.0060000000002503e8] @test b_int[:,2] ≈ [-1.449731150462047e9, 2.245287820579052e8, 2.245287820579052e8] diff --git a/test/integration/b_int_correspondence.jl b/test/integration/b_int_correspondence.jl index a0c24388..392626ec 100644 --- a/test/integration/b_int_correspondence.jl +++ b/test/integration/b_int_correspondence.jl @@ -21,7 +21,7 @@ # Point 2 with v_z = 1 m/s with Δt = 0.0015 s position[1, 2] = 1.0015 - Peridynamics.calc_force_density!(chunk) + Peridynamics.calc_force_density!(chunk, 0, 0) @test b_int[:,1] ≈ [0.007185432432164514, 0.0023974081843325646, 0.0023974081843347313] @test b_int[:,2] ≈ [-0.007185432432123352, -9.047513544240966e-15, -6.0453612662025915e-15] @@ -54,7 +54,7 @@ end # Point 2 with v_z = 1 m/s with Δt = 0.0015 s position[1, 2] = 1.0015 - Peridynamics.calc_force_density!(chunk) + Peridynamics.calc_force_density!(chunk, 0, 0) @test b_int[:,1] ≈ [0.007185432432164514, 0.0023974081843325646, 0.0023974081843347313] @test b_int[:,2] ≈ [-0.007185432432123352, -9.047513544240966e-15, -6.0453612662025915e-15] diff --git a/test/integration/b_int_ordinary_state_based.jl b/test/integration/b_int_ordinary_state_based.jl index fbc530ce..d8debcb8 100644 --- a/test/integration/b_int_ordinary_state_based.jl +++ b/test/integration/b_int_ordinary_state_based.jl @@ -20,7 +20,7 @@ # Point 2 with v_z = 1 m/s with Δt = 0.0015 s position[1, 2] = 1.0015 - Peridynamics.calc_force_density!(chunk) + Peridynamics.calc_force_density!(chunk, 0, 0) b12 = 3.780000000000143e9 @test b_int ≈ [b12 -b12; 0.0 0.0; 0.0 0.0] @@ -51,7 +51,7 @@ end # Point 2 with v_z = 1 m/s with Δt = 0.0015 s position[1, 2] = 1.0015 - Peridynamics.calc_force_density!(chunk) + Peridynamics.calc_force_density!(chunk, 0, 0) b1 = 4.252500000000161e9 b2 = 2.1262500000000806e9 diff --git a/test/integration/test_material.jl b/test/integration/test_material.jl index 4d9c68de..d3954b25 100644 --- a/test/integration/test_material.jl +++ b/test/integration/test_material.jl @@ -40,7 +40,7 @@ function Peridynamics.init_field(::TestMaterial, ::Peridynamics.VelocityVerlet, end function Peridynamics.force_density_point!(storage::TestStorage, system::Peridynamics.BondSystem, ::TestMaterial, - params::TestPointParameters, i::Int) + params::TestPointParameters, t, Δt, i) for bond_id in Peridynamics.each_bond_idx(system, i) bond = system.bonds[bond_id] j, L = bond.neighbor, bond.length From 7c835a9860a155a51fb37919b87c64752649d301 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Mon, 21 Oct 2024 08:46:09 +0200 Subject: [PATCH 03/40] Enhance CCMaterial: rm `maxjacobi` and add other fields --- src/Peridynamics.jl | 11 ++++ src/discretization/zem_stabilization.jl | 12 ++++ src/physics/constitutive_models.jl | 27 ++++++++ src/physics/correspondence.jl | 41 ++++++------ src/physics/stress_integration.jl | 86 +++++++++++++++++++++++++ 5 files changed, 159 insertions(+), 18 deletions(-) create mode 100644 src/discretization/zem_stabilization.jl create mode 100644 src/physics/constitutive_models.jl create mode 100644 src/physics/stress_integration.jl diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index f315dd79..c349c7d3 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -11,6 +11,9 @@ import LibGit2, Dates # Material models export BBMaterial, OSBMaterial, CCMaterial, CKIMaterial +# CCMaterial related types +export NoRotation, FlanaganTaylorRotation, NeoHookeNonlinear, SaintVenantKirchhoff + # Systems related types export NoCorrection, EnergySurfaceCorrection @@ -65,6 +68,11 @@ abstract type AbstractCorrection end abstract type AbstractStorage end abstract type AbstractCondition end abstract type AbstractBondSystemMaterial{Correction} <: AbstractMaterial end +abstract type AbstractCorrespondenceMaterial{CM,SI,ZEM} <: + AbstractBondSystemMaterial{ZEM} end +abstract type AbstractConstitutiveModel end +abstract type AbstractStressIntegration end +abstract type AbstractZEMStabilization <: AbstractCorrection end abstract type AbstractInteractionSystemMaterial <: AbstractMaterial end include("auxiliary/function_arguments.jl") @@ -88,6 +96,7 @@ include("discretization/decomposition.jl") include("discretization/chunk_handler.jl") include("discretization/bond_system.jl") include("discretization/bond_system_corrections.jl") +include("discretization/zem_stabilization.jl") include("discretization/interaction_system.jl") include("discretization/body_chunk.jl") @@ -111,6 +120,8 @@ include("time_solvers/dynamic_relaxation.jl") include("physics/bond_based.jl") include("physics/continuum_kinematics_inspired.jl") include("physics/ordinary_state_based.jl") +include("physics/stress_integration.jl") +include("physics/constitutive_models.jl") include("physics/correspondence.jl") include("VtkReader/VtkReader.jl") diff --git a/src/discretization/zem_stabilization.jl b/src/discretization/zem_stabilization.jl new file mode 100644 index 00000000..518eaf29 --- /dev/null +++ b/src/discretization/zem_stabilization.jl @@ -0,0 +1,12 @@ +struct NoZEMStabilization <: AbstractZEMStabilization end + +function calc_zem_force_density(::NoZEMStabilization, args...) + return zeros(SVector{3}) +end + +function get_correction(::AbstractBondSystemMaterial{NoZEMStabilization}, + n_loc_points::Int, n_points::Int, n_bonds::Int) + return NoZEMStabilization() +end + +struct SillingZEMStabilization <: AbstractZEMStabilization end diff --git a/src/physics/constitutive_models.jl b/src/physics/constitutive_models.jl new file mode 100644 index 00000000..367f963a --- /dev/null +++ b/src/physics/constitutive_models.jl @@ -0,0 +1,27 @@ +struct NeoHookeNonlinear <: AbstractConstitutiveModel end + +function cauchy_stress(::NeoHookeNonlinear, storage::AbstractStorage, + params::AbstractPointParameters, F::SMatrix{3,3}) + J = det(F) + J < eps() && return zero(SMatrix{3,3}) + C = F' * F + Cinv = inv(C) + S = params.G .* (I - 1 / 3 .* tr(C) .* Cinv) .* J^(-2 / 3) .+ + params.K / 4 .* (J^2 - J^(-2)) .* Cinv + P = F * S + σ = 1/J .* P * F' + return σ +end + +struct SaintVenantKirchhoff <: AbstractConstitutiveModel end + +function cauchy_stress(::SaintVenantKirchhoff, storage::AbstractStorage, + params::AbstractPointParameters, F::SMatrix{3,3}) + J = det(F) + J < eps() && return zero(SMatrix{3,3}) + E = 0.5 .* (F' * F - I) + S = params.λ * tr(E) * I + 2 * params.μ * E + P = F * S + σ = 1/J .* P * F' + return σ +end diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index bd8a215e..aa2997cf 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -1,5 +1,5 @@ """ - CCMaterial(; maxdmg, maxjacobi, corr) + CCMaterial(; maxdmg, zem_fac) A material type used to assign the material of a [`Body`](@ref) with the local continuum consistent (correspondence) formulation of non-ordinary state-based peridynamics. @@ -9,23 +9,20 @@ consistent (correspondence) formulation of non-ordinary state-based peridynamics exceeded, all bonds of that point are broken because the deformation gradient would then possibly contain `NaN` values. (default: `0.95`) -- `maxjacobi::Float64`: Maximum value of the Jacobi determinant. If this value is exceeded, - all bonds of that point are broken. - (default: `1.03`) -- `corr::Float64`: Correction factor used for zero-energy mode stabilization. The +- `zem_fac::Float64`: Correction factor used for zero-energy mode stabilization. The stabilization algorithm of Silling (2017) is used. (default: `100.0`) !!! note "Stability of fracture simulations" This formulation is known to be not suitable for fracture simultations without stabilization of the zero-energy modes. Therefore be careful when doing fracture - simulations and try out different paremeters for `maxdmg`, `maxjacobi`, and `corr`. + simulations and try out different parameters for `maxdmg` and `zem_fac`. # Examples ```julia-repl julia> mat = CCMaterial() -CCMaterial(maxdmg=0.95, maxjacobi=1.03, corr=100.0) +CCMaterial(maxdmg=0.95, zem_fac=100.0) ``` --- @@ -40,9 +37,7 @@ non-ordinary state-based peridynamics. # Fields - `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. See the constructor docs for more informations. -- `maxjacobi::Float64`: Maximum value of the Jacobi determinant. See the constructor docs - for more informations. -- `corr::Float64`: Correction factor used for zero-energy mode stabilization. See the +- `zem_fac::Float64`: Correction factor used for zero-energy mode stabilization. See the constructor docs for more informations. # Allowed material parameters @@ -68,18 +63,28 @@ When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with - `damage::Vector{Float64}`: Damage of each point - `n_active_bonds::Vector{Int}`: Number of intact bonds of each point """ -Base.@kwdef struct CCMaterial <: AbstractBondSystemMaterial{NoCorrection} - maxdmg::Float64 = 0.95 - maxjacobi::Float64 = 1.03 - corr::Float64 = 100.0 +struct CCMaterial{CM,SI,ZEM} <: AbstractCorrespondenceMaterial{CM,SI,ZEM} + constitutive_model::CM + stress_integration::SI + zem_stabilization::ZEM + maxdmg::Float64 + function CCMaterial(cm::CM, si::SI, zem::ZEM, maxdmg::Real) where {CM,SI,ZEM} + return new{CM,SI,ZEM}(cm, si, zem, maxdmg) + end end function Base.show(io::IO, @nospecialize(mat::CCMaterial)) print(io, typeof(mat)) - print(io, msg_fields_in_brackets(mat)) + print(io, msg_fields_in_brackets(mat, (:maxdmg,))) return nothing end +function CCMaterial(; model::AbstractConstitutiveModel=NeoHookeNonlinear(), + stressint::AbstractStressIntegration=NoRotation(), + zem::AbstractZEMStabilization=NoZEMStabilization(), maxdmg::Real=0.85) + return CCMaterial(model, stressint, zem, maxdmg) +end + struct CCPointParameters <: AbstractPointParameters δ::Float64 rho::Float64 @@ -154,10 +159,11 @@ function force_density_point!(storage::CCStorage, system::BondSystem, mat::CCMat # stabilization ωij = influence_function(mat, params, L) * storage.bond_active[bond_id] - Tij = mat.corr .* params.bc * ωij / ω0 .* (Δxij .- F * ΔXij) + # Tij = mat.corr .* params.bc * ωij / ω0 .* (Δxij .- F * ΔXij) + tzem = calc_zem_force_density(mat.zem_stabilization, ωij) # update of force density - tij = ωij * PKinv * ΔXij + Tij + tij = ωij * PKinv * ΔXij + tzem if containsnan(tij) tij = zero(SMatrix{3,3}) end @@ -197,7 +203,6 @@ function calc_first_piola_stress(F::SMatrix{3,3}, mat::CCMaterial, params::CCPointParameters) J = det(F) J < eps() && return zero(SMatrix{3,3}) - J > mat.maxjacobi && return zero(SMatrix{3,3}) C = F' * F Cinv = inv(C) S = params.G .* (I - 1 / 3 .* tr(C) .* Cinv) .* J^(-2 / 3) .+ diff --git a/src/physics/stress_integration.jl b/src/physics/stress_integration.jl new file mode 100644 index 00000000..3defd5e2 --- /dev/null +++ b/src/physics/stress_integration.jl @@ -0,0 +1,86 @@ +struct NoRotation <: AbstractStressIntegration end + +function init_stress_integration!(::AbstractStorage, ::NoRotation, F::SMatrix{3,3}, + Ḟ::SMatrix{3,3}, Δt::Float64, i::Int) + return nothing +end + +function stress_integration(::AbstractStorage, ::NoRotation, σ::SMatrix{3,3}, + Δt::Float64, i::Int) + return σ +end + +struct FlanaganTaylorRotation <: AbstractStressIntegration end + +function init_stress_integration!(storage::AbstractStorage, ::FlanaganTaylorRotation, + F::SMatrix{3,3}, Ḟ::SMatrix{3,3}, Δt::Float64, i::Int) + # inverse of the deformation gradient + F⁻¹ = inv(F) + + # Eulerian velocity gradient [FT87, eq. (3)] + L = Ḟ * F⁻¹ + + # rate-of-deformation tensor D + D = 0.5 .* (L + L') + + # spin tensor W + W = 0.5 .* (L - L') + + # left stretch V + V = get_tensor(storage.left_stretch, i) + + # vector z [FT87, eq. (13)] + z_x = - V[1,3] * D[2,1] - V[2,3] * D[2,2] - + V[3,3] * D[2,3] + V[1,2] * D[3,1] + + V[2,2] * D[3,2] + V[3,2] * D[3,3] + z_y = V[1,3] * D[1,1] + V[2,3] * D[1,2] + + V[3,3] * D[1,3] - V[1,1] * D[3,1] - + V[2,1] * D[3,2] - V[3,1] * D[3,3] + z_z = - V[1,2] * D[1,1] - V[2,2] * D[1,2] - + V[3,2] * D[1,3] + V[1,1] * D[2,1] + + V[2,1] * D[2,2] + V[3,1] * D[2,3] + z = SVector{3}(z_x, z_y, z_z) + + # w = -1/2 * \epsilon_{ijk} * W_{jk} [FT87, eq. (11)] + w = 0.5 .* SVector{3}(W[3,2] - W[2,3], W[1,3] - W[3,1], W[2,1] - W[1,2]) + + # ω = w + (I * tr(V) - V)^(-1) * z [FT87, eq. (12)] + ω = w + inv(I * tr(V) - V) * z + + # Ω [FT87, eq. (10)] + Ωtens = SMatrix{3,3}(0.0, -ω[3], ω[2], ω[3], 0.0, -ω[1], -ω[2], ω[1], 0.0) + Ω² = dot(ω, ω) + Ω = sqrt(Ω²) + + # compute Q with [FT87, eq. (44)] + if Ω² > 1e-30 # avoid a potential divide-by-zero + fac1 = sin(Δt * Ω) / Ω + fac2 = -(1.0 - cos(Δt * Ω)) / Ω² + Ωtens² = Ωtens * Ωtens + Q = I + fac1 .* Ωtens + fac2 .* Ωtens² + else + Q = SMatrix{3,3}(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) + end + + # compute Rotation of new step [FT87, eq. (36)] + R = get_tensor(storage.rotation, i) + Rₙ₊₁ = Q * R + + # compute step 4 of [FT87] + V̇ = L * V - V * Ωtens + + # compute step 5 of [FT87] + Vₙ₊₁ = V + Δt * V̇ + + # update rotation and left stretch + update_tensor!(storage.rotation, i, Rₙ₊₁) + update_tensor!(storage.left_stretch, i, Vₙ₊₁) + return nothing +end + +function stress_integration(storage::AbstractStorage, ::FlanaganTaylorRotation, + σ::SMatrix{3,3}, Δt::Float64, i::Int) + R = get_tensor(storage.rotation, i) + T = R * σ * R' + return T +end From c63c798ad753369684d7f5f4708adc201973472c Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Mon, 21 Oct 2024 13:35:13 +0200 Subject: [PATCH 04/40] Add benchmark suite & mode I benchmark --- benchmark/Project.toml | 3 +++ benchmark/benchmarks.jl | 13 +++++++++++++ benchmark/mode_i.jl | 18 ++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 benchmark/Project.toml create mode 100644 benchmark/benchmarks.jl create mode 100644 benchmark/mode_i.jl diff --git a/benchmark/Project.toml b/benchmark/Project.toml new file mode 100644 index 00000000..e89fa026 --- /dev/null +++ b/benchmark/Project.toml @@ -0,0 +1,3 @@ +[deps] +BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" +Peridynamics = "4dc47793-80f3-4232-b30e-ca78ca9d621b" diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl new file mode 100644 index 00000000..e2e5f1a1 --- /dev/null +++ b/benchmark/benchmarks.jl @@ -0,0 +1,13 @@ +import Pkg; Pkg.activate(@__DIR__) + +using BenchmarkTools, StatsPlots +using Peridynamics + +const SUITE = BenchmarkGroup() + +include(joinpath(@__DIR__, "mode_i.jl")) + +SUITE["mode_i"] = BenchmarkGroup() +SUITE["mode_i"]["BBMaterial, 40"] = mode_i(BBMaterial(), 40) +SUITE["mode_i"]["OSBMaterial, 40"] = mode_i(OSBMaterial(), 40) +SUITE["mode_i"]["CCMaterial, 40"] = mode_i(NOSBMaterial(), 40) diff --git a/benchmark/mode_i.jl b/benchmark/mode_i.jl new file mode 100644 index 00000000..37442052 --- /dev/null +++ b/benchmark/mode_i.jl @@ -0,0 +1,18 @@ + +function mode_i(mat, npyz) + l, Δx, δ, a = 1.0, 1/npyz, 3.015/npyz, 0.5 + pos, vol = uniform_box(l, l, 0.1l, Δx) + ids = sortperm(pos[2,:]) + body = Body(mat, pos[:, ids], vol[ids]) + material!(body; horizon=3.015Δx, E=2.1e5, nu=0.25, rho=8e-6, Gc=2.7) + point_set!(p -> p[1] ≤ -l/2+a && 0 ≤ p[2] ≤ 2δ, body, :set_a) + point_set!(p -> p[1] ≤ -l/2+a && -2δ ≤ p[2] < 0, body, :set_b) + precrack!(body, :set_a, :set_b) + point_set!(p -> p[2] > l/2-Δx, body, :set_top) + point_set!(p -> p[2] < -l/2+Δx, body, :set_bottom) + velocity_bc!(t -> -30, body, :set_bottom, :y) + velocity_bc!(t -> 30, body, :set_top, :y) + vv = VelocityVerlet(steps=2000) + job = Job(body, vv; path=joinpath(@__DIR__, "results", "mode_i-BB-npyz$(npyz)")) + return @benchmarkable submit($job) +end From dd7978403dfe55f3bb17d0ff83a15db30b4d995d Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Mon, 21 Oct 2024 13:40:03 +0200 Subject: [PATCH 05/40] Remove StatsPlots --- benchmark/benchmarks.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl index e2e5f1a1..8e47d8db 100644 --- a/benchmark/benchmarks.jl +++ b/benchmark/benchmarks.jl @@ -1,6 +1,6 @@ import Pkg; Pkg.activate(@__DIR__) -using BenchmarkTools, StatsPlots +using BenchmarkTools using Peridynamics const SUITE = BenchmarkGroup() From e5d4f9d9a57e6a81862147452eb89017fbe867aa Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Thu, 24 Oct 2024 15:14:30 +0200 Subject: [PATCH 06/40] Allow materials with parameters --- src/core/parameters.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 7446f78c..2a9a5d28 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -48,6 +48,7 @@ function macrocheck_input_material(material) material isa Symbol && return nothing (material isa Expr && material.head === :.) && return nothing (material isa Expr && material.head === :escape) && return nothing + (material isa Expr && material.head === :curly) && return nothing return throw(ArgumentError("argument `$material` is not a valid material input!\n")) end From 55315383b8660198be491cd3c0dd8ec97976ac99 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Thu, 24 Oct 2024 15:15:32 +0200 Subject: [PATCH 07/40] Improve benchmarks --- benchmark/benchmarks.jl | 6 +++--- benchmark/mode_i.jl | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl index 8e47d8db..2aab901f 100644 --- a/benchmark/benchmarks.jl +++ b/benchmark/benchmarks.jl @@ -8,6 +8,6 @@ const SUITE = BenchmarkGroup() include(joinpath(@__DIR__, "mode_i.jl")) SUITE["mode_i"] = BenchmarkGroup() -SUITE["mode_i"]["BBMaterial, 40"] = mode_i(BBMaterial(), 40) -SUITE["mode_i"]["OSBMaterial, 40"] = mode_i(OSBMaterial(), 40) -SUITE["mode_i"]["CCMaterial, 40"] = mode_i(NOSBMaterial(), 40) +SUITE["mode_i"]["BBMaterial, 40"] = @benchmarkable submit(mode_i(BBMaterial(), 40)) +SUITE["mode_i"]["OSBMaterial, 40"] = @benchmarkable submit(mode_i(OSBMaterial(), 40)) +SUITE["mode_i"]["CCMaterial, 40"] = @benchmarkable submit(mode_i(CCMaterial(), 40)) diff --git a/benchmark/mode_i.jl b/benchmark/mode_i.jl index 37442052..b483d3c6 100644 --- a/benchmark/mode_i.jl +++ b/benchmark/mode_i.jl @@ -1,3 +1,4 @@ +using Peridynamics function mode_i(mat, npyz) l, Δx, δ, a = 1.0, 1/npyz, 3.015/npyz, 0.5 @@ -13,6 +14,7 @@ function mode_i(mat, npyz) velocity_bc!(t -> -30, body, :set_bottom, :y) velocity_bc!(t -> 30, body, :set_top, :y) vv = VelocityVerlet(steps=2000) - job = Job(body, vv; path=joinpath(@__DIR__, "results", "mode_i-BB-npyz$(npyz)")) - return @benchmarkable submit($job) + path = joinpath(@__DIR__, "results", "mode_i") + job = Job(body, vv; path) + return job end From c04b5a7951341c0906f191fb40d81a31411c407c Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Thu, 24 Oct 2024 15:17:56 +0200 Subject: [PATCH 08/40] Major changes regarding correspondence materials --- src/Peridynamics.jl | 11 +- src/auxiliary/nans.jl | 6 + src/auxiliary/static_arrays.jl | 19 +++ src/discretization/zem_stabilization.jl | 19 +-- src/physics/correspondence.jl | 169 +++++++++++++----------- src/physics/stress.jl | 9 ++ src/physics/stress_integration.jl | 86 ------------ 7 files changed, 141 insertions(+), 178 deletions(-) create mode 100644 src/auxiliary/nans.jl create mode 100644 src/auxiliary/static_arrays.jl create mode 100644 src/physics/stress.jl delete mode 100644 src/physics/stress_integration.jl diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index c349c7d3..01fd0d8e 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -9,10 +9,10 @@ end import LibGit2, Dates # Material models -export BBMaterial, OSBMaterial, CCMaterial, CKIMaterial +export BBMaterial, OSBMaterial, CCMaterial, CCNRMaterial, CKIMaterial # CCMaterial related types -export NoRotation, FlanaganTaylorRotation, NeoHookeNonlinear, SaintVenantKirchhoff +export NeoHookeNonlinear, SaintVenantKirchhoff, ZEMSilling # Systems related types export NoCorrection, EnergySurfaceCorrection @@ -68,8 +68,7 @@ abstract type AbstractCorrection end abstract type AbstractStorage end abstract type AbstractCondition end abstract type AbstractBondSystemMaterial{Correction} <: AbstractMaterial end -abstract type AbstractCorrespondenceMaterial{CM,SI,ZEM} <: - AbstractBondSystemMaterial{ZEM} end +abstract type AbstractCorrespondenceMaterial{CM,ZEM} <: AbstractBondSystemMaterial{ZEM} end abstract type AbstractConstitutiveModel end abstract type AbstractStressIntegration end abstract type AbstractZEMStabilization <: AbstractCorrection end @@ -80,10 +79,13 @@ include("auxiliary/io.jl") include("auxiliary/logs.jl") include("auxiliary/mpi.jl") include("auxiliary/errors.jl") +include("auxiliary/static_arrays.jl") +include("auxiliary/nans.jl") include("physics/boundary_conditions.jl") include("physics/initial_conditions.jl") include("physics/material_parameters.jl") +include("physics/stress.jl") include("physics/fracture.jl") include("physics/short_range_force_contact.jl") @@ -120,7 +122,6 @@ include("time_solvers/dynamic_relaxation.jl") include("physics/bond_based.jl") include("physics/continuum_kinematics_inspired.jl") include("physics/ordinary_state_based.jl") -include("physics/stress_integration.jl") include("physics/constitutive_models.jl") include("physics/correspondence.jl") diff --git a/src/auxiliary/nans.jl b/src/auxiliary/nans.jl new file mode 100644 index 00000000..b6116d76 --- /dev/null +++ b/src/auxiliary/nans.jl @@ -0,0 +1,6 @@ +function containsnan(K::T) where {T<:AbstractArray} + @simd for i in eachindex(K) + isnan(K[i]) && return true + end + return false +end diff --git a/src/auxiliary/static_arrays.jl b/src/auxiliary/static_arrays.jl new file mode 100644 index 00000000..779ae6af --- /dev/null +++ b/src/auxiliary/static_arrays.jl @@ -0,0 +1,19 @@ + +@inline function get_tensor(T::AbstractMatrix, i::Int) + 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], + T[8, i], T[9, i]) + return tensor +end + +@inline function update_tensor!(Tₙ::AbstractMatrix, i::Int, Tₙ₊₁::SMatrix{3,3}) + Tₙ[1, i] = Tₙ₊₁[1, 1] + Tₙ[2, i] = Tₙ₊₁[1, 2] + Tₙ[3, i] = Tₙ₊₁[1, 3] + Tₙ[4, i] = Tₙ₊₁[2, 1] + Tₙ[5, i] = Tₙ₊₁[2, 2] + Tₙ[6, i] = Tₙ₊₁[2, 3] + Tₙ[7, i] = Tₙ₊₁[3, 1] + Tₙ[8, i] = Tₙ₊₁[3, 2] + Tₙ[9, i] = Tₙ₊₁[3, 3] + return nothing +end diff --git a/src/discretization/zem_stabilization.jl b/src/discretization/zem_stabilization.jl index 518eaf29..720d9056 100644 --- a/src/discretization/zem_stabilization.jl +++ b/src/discretization/zem_stabilization.jl @@ -1,12 +1,13 @@ -struct NoZEMStabilization <: AbstractZEMStabilization end - -function calc_zem_force_density(::NoZEMStabilization, args...) - return zeros(SVector{3}) +function get_correction(mat::AbstractBondSystemMaterial{<:AbstractZEMStabilization}, + ::Int, ::Int, ::Int) + return mat.zem_stabilization end -function get_correction(::AbstractBondSystemMaterial{NoZEMStabilization}, - n_loc_points::Int, n_points::Int, n_bonds::Int) - return NoZEMStabilization() -end +""" + ZEMSilling(; Cs=0.0) -struct SillingZEMStabilization <: AbstractZEMStabilization end +TODO +""" +@kwdef struct ZEMSilling <: AbstractZEMStabilization + Cs::Float64 = 0.0 +end diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index aa2997cf..23aecee2 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -1,5 +1,5 @@ """ - CCMaterial(; maxdmg, zem_fac) + CCMaterial(; maxdmg, zem) A material type used to assign the material of a [`Body`](@ref) with the local continuum consistent (correspondence) formulation of non-ordinary state-based peridynamics. @@ -9,20 +9,20 @@ consistent (correspondence) formulation of non-ordinary state-based peridynamics exceeded, all bonds of that point are broken because the deformation gradient would then possibly contain `NaN` values. (default: `0.95`) -- `zem_fac::Float64`: Correction factor used for zero-energy mode stabilization. The - stabilization algorithm of Silling (2017) is used. - (default: `100.0`) +- `zem::AbstractZEMStabilization`: zero-energy mode stabilization. The + stabilization algorithm of Silling (2017) is used as default. + (default: `ZEMSilling()`) !!! note "Stability of fracture simulations" This formulation is known to be not suitable for fracture simultations without stabilization of the zero-energy modes. Therefore be careful when doing fracture - simulations and try out different parameters for `maxdmg` and `zem_fac`. + simulations and try out different parameters for `maxdmg` and `zem`. # Examples ```julia-repl julia> mat = CCMaterial() -CCMaterial(maxdmg=0.95, zem_fac=100.0) +CCMaterial(maxdmg=0.95, zem_fac=ZEMSilling()) ``` --- @@ -63,13 +63,12 @@ When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with - `damage::Vector{Float64}`: Damage of each point - `n_active_bonds::Vector{Int}`: Number of intact bonds of each point """ -struct CCMaterial{CM,SI,ZEM} <: AbstractCorrespondenceMaterial{CM,SI,ZEM} +struct CCMaterial{CM,ZEM} <: AbstractCorrespondenceMaterial{CM,ZEM} constitutive_model::CM - stress_integration::SI zem_stabilization::ZEM maxdmg::Float64 - function CCMaterial(cm::CM, si::SI, zem::ZEM, maxdmg::Real) where {CM,SI,ZEM} - return new{CM,SI,ZEM}(cm, si, zem, maxdmg) + function CCMaterial(cm::CM, zem::ZEM, maxdmg::Real) where {CM,ZEM} + return new{CM,ZEM}(cm, zem, maxdmg) end end @@ -80,9 +79,8 @@ function Base.show(io::IO, @nospecialize(mat::CCMaterial)) end function CCMaterial(; model::AbstractConstitutiveModel=NeoHookeNonlinear(), - stressint::AbstractStressIntegration=NoRotation(), - zem::AbstractZEMStabilization=NoZEMStabilization(), maxdmg::Real=0.85) - return CCMaterial(model, stressint, zem, maxdmg) + zem::AbstractZEMStabilization=ZEMSilling(), maxdmg::Real=0.85) + return CCMaterial(model, zem, maxdmg) end struct CCPointParameters <: AbstractPointParameters @@ -108,7 +106,7 @@ end @params CCMaterial CCPointParameters -@storage CCMaterial struct CCStorage <: AbstractStorage +@storage CCMaterial struct CCStorage @lthfield position::Matrix{Float64} @pointfield displacement::Matrix{Float64} @pointfield velocity::Matrix{Float64} @@ -122,12 +120,28 @@ end @pointfield damage::Vector{Float64} bond_active::Vector{Bool} @pointfield n_active_bonds::Vector{Int} + @pointfield stress::Matrix{Float64} + @pointfield von_mises_stress::Vector{Float64} end function init_field(::CCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int}) return zeros(3, get_n_points(system)) end +function init_field(::CCMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:velocity}) + return zeros(3, get_n_points(system)) +end + +function init_field(::CCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:stress}) + return zeros(9, get_n_loc_points(system)) +end + +function init_field(::CCMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:von_mises_stress}) + return zeros(get_n_loc_points(system)) +end + function force_density_point!(storage::CCStorage, system::BondSystem, mat::CCMaterial, paramhandler::AbstractParameterHandler, t, Δt, i) params = get_params(paramhandler, i) @@ -137,39 +151,11 @@ end function force_density_point!(storage::CCStorage, system::BondSystem, mat::CCMaterial, params::CCPointParameters, t, Δt, i) - F, Kinv, ω0 = calc_deformation_gradient(storage, system, mat, params, i) - if storage.damage[i] > mat.maxdmg || containsnan(F) - kill_point!(storage, system, i) - return nothing - end - P = calc_first_piola_stress(F, mat, params) - if iszero(P) || containsnan(P) - kill_point!(storage, system, i) - return nothing - end - PKinv = P * Kinv - for bond_id in each_bond_idx(system, i) - bond = system.bonds[bond_id] - j, L = bond.neighbor, bond.length - ΔXij = get_coordinates_diff(system, i, j) - Δxij = get_coordinates_diff(storage, i, j) - l = norm(Δxij) - ε = (l - L) / L - stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - - # stabilization - ωij = influence_function(mat, params, L) * storage.bond_active[bond_id] - # Tij = mat.corr .* params.bc * ωij / ω0 .* (Δxij .- F * ΔXij) - tzem = calc_zem_force_density(mat.zem_stabilization, ωij) - - # update of force density - tij = ωij * PKinv * ΔXij + tzem - if containsnan(tij) - tij = zero(SMatrix{3,3}) - end - update_add_b_int!(storage, i, tij .* system.volume[j]) - update_add_b_int!(storage, j, -tij .* system.volume[i]) - end + defgrad_res = calc_deformation_gradient(storage, system, mat, params, i) + too_much_damage!(storage, system, mat, defgrad_res, i) && return nothing + PKinv = calc_first_piola_kirchhoff!(storage, mat, params, defgrad_res, Δt, i) + zem = mat.zem_stabilization + cc_force_density!(storage, system, mat, params, zem, PKinv, defgrad_res, i) return nothing end @@ -177,49 +163,76 @@ end return params.δ / L end -function calc_deformation_gradient(storage::CCStorage, system::BondSystem, mat::CCMaterial, - params::CCPointParameters, i) - K = zeros(SMatrix{3,3}) - _F = zeros(SMatrix{3,3}) +function calc_deformation_gradient(storage::CCStorage, system::BondSystem, + mat::CCMaterial, params::CCPointParameters, i) + (; bonds, volume) = system + (; bond_active) = storage + K = zero(SMatrix{3,3,Float64,9}) + _F = zero(SMatrix{3,3,Float64,9}) ω0 = 0.0 for bond_id in each_bond_idx(system, i) - bond = system.bonds[bond_id] + bond = bonds[bond_id] j, L = bond.neighbor, bond.length - ΔXij = get_coordinates_diff(system, i, j) - Δxij = get_coordinates_diff(storage, i, j) - Vj = system.volume[j] - ωij = influence_function(mat, params, L) * storage.bond_active[bond_id] + ΔXij = get_diff(system.position, i, j) + Δxij = get_diff(storage.position, i, j) + ωij = influence_function(mat, params, L) * bond_active[bond_id] ω0 += ωij - temp = ωij * Vj - K += temp * ΔXij * ΔXij' - _F += temp * Δxij * ΔXij' + temp = ωij * volume[j] + K += temp * (ΔXij * ΔXij') + _F += temp * (Δxij * ΔXij') end Kinv = inv(K) F = _F * Kinv - return F, Kinv, ω0 + return (; F, Kinv, ω0) end -function calc_first_piola_stress(F::SMatrix{3,3}, mat::CCMaterial, - params::CCPointParameters) - J = det(F) - J < eps() && return zero(SMatrix{3,3}) - C = F' * F - Cinv = inv(C) - S = params.G .* (I - 1 / 3 .* tr(C) .* Cinv) .* J^(-2 / 3) .+ - params.K / 4 .* (J^2 - J^(-2)) .* Cinv - P = F * S - return P +function calc_first_piola_kirchhoff!(storage::CCStorage, mat::CCMaterial, + params::CCPointParameters, defgrad_res, Δt, i) + (; F, Kinv) = defgrad_res + σ = cauchy_stress(mat.constitutive_model, storage, params, F) + update_tensor!(storage.stress, i, σ) + storage.von_mises_stress[i] = von_mises_stress(σ) + P = det(F) * σ * inv(F)' + PKinv = P * Kinv + return PKinv end -function containsnan(K::T) where {T<:AbstractArray} - @simd for i in eachindex(K) - isnan(K[i]) && return true +function cc_force_density!(storage::CCStorage, system::BondSystem, mat::CCMaterial, + params::CCPointParameters, zem_correction::ZEMSilling, + PKinv::SMatrix, defgrad_res, i) + (; bonds, volume) = system + (; bond_active) = storage + (; F, ω0) = defgrad_res + (; Cs) = zem_correction + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j, L = bond.neighbor, bond.length + ΔXij = get_coordinates_diff(system, i, j) + Δxij = get_coordinates_diff(storage, i, j) + l = norm(Δxij) + ε = (l - L) / L + stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + + # stabilization + ωij = influence_function(mat, params, L) * bond_active[bond_id] + tzem = Cs .* params.bc * ωij / ω0 .* (Δxij .- F * ΔXij) + + # update of force density + tij = ωij * PKinv * ΔXij + tzem + update_add_b_int!(storage, i, tij .* volume[j]) + update_add_b_int!(storage, j, -tij .* volume[i]) end - return false + return nothing end -function kill_point!(s::AbstractStorage, bd::BondSystem, i) - s.bond_active[each_bond_idx(bd, i)] .= false - s.n_active_bonds[i] = 0 - return nothing +function too_much_damage!(storage::CCStorage, system::BondSystem, mat::CCMaterial, + defgrad_res, i) + (; F) = defgrad_res + if storage.damage[i] > mat.maxdmg || containsnan(F) + # kill all bonds of this point + storage.bond_active[each_bond_idx(system, i)] .= false + storage.n_active_bonds[i] = 0 + return true + end + return false end diff --git a/src/physics/stress.jl b/src/physics/stress.jl new file mode 100644 index 00000000..7d9c3d24 --- /dev/null +++ b/src/physics/stress.jl @@ -0,0 +1,9 @@ +function von_mises_stress(σ) + σx, σy, σz = σ[1], σ[5], σ[9] + τxy, τxz, τyz = σ[4], σ[7], σ[8] + a = σx * σx + σy * σy + σz * σz + b = - σx * σy - σx * σz - σy * σz + c = 3 * (τxy * τxy + τxz * τxz + τyz * τyz) + σvm = √(a + b + c) + return σvm +end diff --git a/src/physics/stress_integration.jl b/src/physics/stress_integration.jl deleted file mode 100644 index 3defd5e2..00000000 --- a/src/physics/stress_integration.jl +++ /dev/null @@ -1,86 +0,0 @@ -struct NoRotation <: AbstractStressIntegration end - -function init_stress_integration!(::AbstractStorage, ::NoRotation, F::SMatrix{3,3}, - Ḟ::SMatrix{3,3}, Δt::Float64, i::Int) - return nothing -end - -function stress_integration(::AbstractStorage, ::NoRotation, σ::SMatrix{3,3}, - Δt::Float64, i::Int) - return σ -end - -struct FlanaganTaylorRotation <: AbstractStressIntegration end - -function init_stress_integration!(storage::AbstractStorage, ::FlanaganTaylorRotation, - F::SMatrix{3,3}, Ḟ::SMatrix{3,3}, Δt::Float64, i::Int) - # inverse of the deformation gradient - F⁻¹ = inv(F) - - # Eulerian velocity gradient [FT87, eq. (3)] - L = Ḟ * F⁻¹ - - # rate-of-deformation tensor D - D = 0.5 .* (L + L') - - # spin tensor W - W = 0.5 .* (L - L') - - # left stretch V - V = get_tensor(storage.left_stretch, i) - - # vector z [FT87, eq. (13)] - z_x = - V[1,3] * D[2,1] - V[2,3] * D[2,2] - - V[3,3] * D[2,3] + V[1,2] * D[3,1] + - V[2,2] * D[3,2] + V[3,2] * D[3,3] - z_y = V[1,3] * D[1,1] + V[2,3] * D[1,2] + - V[3,3] * D[1,3] - V[1,1] * D[3,1] - - V[2,1] * D[3,2] - V[3,1] * D[3,3] - z_z = - V[1,2] * D[1,1] - V[2,2] * D[1,2] - - V[3,2] * D[1,3] + V[1,1] * D[2,1] + - V[2,1] * D[2,2] + V[3,1] * D[2,3] - z = SVector{3}(z_x, z_y, z_z) - - # w = -1/2 * \epsilon_{ijk} * W_{jk} [FT87, eq. (11)] - w = 0.5 .* SVector{3}(W[3,2] - W[2,3], W[1,3] - W[3,1], W[2,1] - W[1,2]) - - # ω = w + (I * tr(V) - V)^(-1) * z [FT87, eq. (12)] - ω = w + inv(I * tr(V) - V) * z - - # Ω [FT87, eq. (10)] - Ωtens = SMatrix{3,3}(0.0, -ω[3], ω[2], ω[3], 0.0, -ω[1], -ω[2], ω[1], 0.0) - Ω² = dot(ω, ω) - Ω = sqrt(Ω²) - - # compute Q with [FT87, eq. (44)] - if Ω² > 1e-30 # avoid a potential divide-by-zero - fac1 = sin(Δt * Ω) / Ω - fac2 = -(1.0 - cos(Δt * Ω)) / Ω² - Ωtens² = Ωtens * Ωtens - Q = I + fac1 .* Ωtens + fac2 .* Ωtens² - else - Q = SMatrix{3,3}(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) - end - - # compute Rotation of new step [FT87, eq. (36)] - R = get_tensor(storage.rotation, i) - Rₙ₊₁ = Q * R - - # compute step 4 of [FT87] - V̇ = L * V - V * Ωtens - - # compute step 5 of [FT87] - Vₙ₊₁ = V + Δt * V̇ - - # update rotation and left stretch - update_tensor!(storage.rotation, i, Rₙ₊₁) - update_tensor!(storage.left_stretch, i, Vₙ₊₁) - return nothing -end - -function stress_integration(storage::AbstractStorage, ::FlanaganTaylorRotation, - σ::SMatrix{3,3}, Δt::Float64, i::Int) - R = get_tensor(storage.rotation, i) - T = R * σ * R' - return T -end From df49615a45dfa5e1a2b23ee93e1a8b62f21ca8a2 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Thu, 24 Oct 2024 15:23:08 +0200 Subject: [PATCH 09/40] Remove undefined export --- src/Peridynamics.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index 01fd0d8e..ae4eb97c 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -9,7 +9,7 @@ end import LibGit2, Dates # Material models -export BBMaterial, OSBMaterial, CCMaterial, CCNRMaterial, CKIMaterial +export BBMaterial, OSBMaterial, CCMaterial, CKIMaterial # CCMaterial related types export NeoHookeNonlinear, SaintVenantKirchhoff, ZEMSilling From 4f4ab1907c1aa786cd31962a58ec6373abf10db0 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Fri, 25 Oct 2024 18:44:12 +0200 Subject: [PATCH 10/40] Smaller fixes to CCMaterial --- src/discretization/zem_stabilization.jl | 7 +++++-- src/physics/correspondence.jl | 5 ----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/discretization/zem_stabilization.jl b/src/discretization/zem_stabilization.jl index 720d9056..b0c26a93 100644 --- a/src/discretization/zem_stabilization.jl +++ b/src/discretization/zem_stabilization.jl @@ -8,6 +8,9 @@ end TODO """ -@kwdef struct ZEMSilling <: AbstractZEMStabilization - Cs::Float64 = 0.0 +struct ZEMSilling <: AbstractZEMStabilization + Cs::Float64 + function ZEMSilling(; Cs::Real=100.0) + return new(Cs) + end end diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index 23aecee2..d5690fa9 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -128,11 +128,6 @@ function init_field(::CCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Va return zeros(3, get_n_points(system)) end -function init_field(::CCMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:velocity}) - return zeros(3, get_n_points(system)) -end - function init_field(::CCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:stress}) return zeros(9, get_n_loc_points(system)) end From 49202da09f77772613edae381500421713883ec2 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Fri, 25 Oct 2024 18:45:06 +0200 Subject: [PATCH 11/40] First working draft, wave speed not correct (15% error) --- src/Peridynamics.jl | 6 +- src/discretization/bond_associated_system.jl | 158 ++++++++++++ src/discretization/bond_system.jl | 35 +-- src/physics/bond_associated_correspondence.jl | 236 ++++++++++++++++++ .../test_bond_associated_system.jl | 71 ++++++ 5 files changed, 488 insertions(+), 18 deletions(-) create mode 100644 src/discretization/bond_associated_system.jl create mode 100644 src/physics/bond_associated_correspondence.jl create mode 100644 test/discretization/test_bond_associated_system.jl diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index ae4eb97c..e7a605f9 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -9,7 +9,7 @@ end import LibGit2, Dates # Material models -export BBMaterial, OSBMaterial, CCMaterial, CKIMaterial +export BBMaterial, OSBMaterial, CCMaterial, BACCMaterial, CKIMaterial # CCMaterial related types export NeoHookeNonlinear, SaintVenantKirchhoff, ZEMSilling @@ -53,6 +53,7 @@ abstract type AbstractTimeSolver end abstract type AbstractJob end abstract type AbstractJobOptions end abstract type AbstractSystem end +abstract type AbstractBondSystem <: AbstractSystem end abstract type AbstractPredefinedCrack end abstract type AbstractBodyChunk{S<:AbstractSystem,T<:AbstractMaterial} end abstract type AbstractParameterHandler <: AbstractParameterSetup end @@ -69,6 +70,7 @@ abstract type AbstractStorage end abstract type AbstractCondition end abstract type AbstractBondSystemMaterial{Correction} <: AbstractMaterial end abstract type AbstractCorrespondenceMaterial{CM,ZEM} <: AbstractBondSystemMaterial{ZEM} end +abstract type AbstractBondAssociatedSystemMaterial <: AbstractMaterial end abstract type AbstractConstitutiveModel end abstract type AbstractStressIntegration end abstract type AbstractZEMStabilization <: AbstractCorrection end @@ -99,6 +101,7 @@ include("discretization/chunk_handler.jl") include("discretization/bond_system.jl") include("discretization/bond_system_corrections.jl") include("discretization/zem_stabilization.jl") +include("discretization/bond_associated_system.jl") include("discretization/interaction_system.jl") include("discretization/body_chunk.jl") @@ -124,6 +127,7 @@ include("physics/continuum_kinematics_inspired.jl") include("physics/ordinary_state_based.jl") include("physics/constitutive_models.jl") include("physics/correspondence.jl") +include("physics/bond_associated_correspondence.jl") include("VtkReader/VtkReader.jl") using .VtkReader diff --git a/src/discretization/bond_associated_system.jl b/src/discretization/bond_associated_system.jl new file mode 100644 index 00000000..f34121e4 --- /dev/null +++ b/src/discretization/bond_associated_system.jl @@ -0,0 +1,158 @@ + +struct BondAssociatedSystem <: AbstractBondSystem + position::Matrix{Float64} + volume::Vector{Float64} + bonds::Vector{Bond} + n_neighbors::Vector{Int} + bond_ids::Vector{UnitRange{Int}} + intersection_bond_ids::Vector{Vector{Int}} + hood_volume::Vector{Float64} + ba_hood_volume::Vector{Float64} + chunk_handler::ChunkHandler +end + +function BondAssociatedSystem(body::AbstractBody, pd::PointDecomposition, chunk_id::Int) + check_bond_associated_system_compat(body.mat) + loc_points = pd.decomp[chunk_id] + bonds, n_neighbors = find_bonds(body, loc_points) + bond_ids = find_bond_ids(n_neighbors) + intersection_bond_ids = find_intersection_bond_ids(body, loc_points, bonds, bond_ids) + chunk_handler = get_chunk_handler(bonds, pd, chunk_id) + localize!(bonds, chunk_handler.localizer) + position, volume = get_pos_and_vol_chunk(body, chunk_handler.point_ids) + hood_volume = zeros(get_n_points(chunk_handler)) + ba_hood_volume = zeros(length(bonds)) + bas = BondAssociatedSystem(position, volume, bonds, n_neighbors, bond_ids, + intersection_bond_ids, hood_volume, ba_hood_volume, + chunk_handler) + return bas +end + +function get_system(body::AbstractBody{Material}, pd::PointDecomposition, + chunk_id::Int) where {Material<:AbstractBondAssociatedSystemMaterial} + return BondAssociatedSystem(body, pd, chunk_id) +end + +@inline function system_type(::AbstractBondAssociatedSystemMaterial) + return BondAssociatedSystem +end + +function check_bond_associated_system_compat(::M) where {M<:AbstractMaterial} + msg = "body with material `$(M)` incompatible to `BondAssociatedSystem`!\n" + msg *= "The material has to be a subtype of `AbstractBondAssociatedSystemMaterial`!\n" + return throw(ArgumentError(msg)) +end + +function check_bond_associated_system_compat(::AbstractBondAssociatedSystemMaterial) + return nothing +end + +function find_intersection_bond_ids(body, loc_points, bonds, bond_ids) + intersection_bond_ids = Vector{Vector{Int}}(undef, length(bonds)) + for (li, i) in enumerate(loc_points) + δ = get_point_param(body, :δ, i) + δ² = 1.1δ * 1.1δ + bond_ids_of_i = bond_ids[li] + for bond_id in bond_ids_of_i + bond = bonds[bond_id] + j = bond.neighbor + Xj = get_coordinates(body, j) + intersecting_bonds = Vector{Int}() + for (ibond_id, bond_id) in enumerate(bond_ids_of_i) + bond = bonds[bond_id] + jj = bond.neighbor + Xjj = get_coordinates(body, jj) + ΔX = Xj - Xjj + L² = dot(ΔX, ΔX) + if L² < δ² + push!(intersecting_bonds, ibond_id) + end + end + intersection_bond_ids[bond_id] = intersecting_bonds + end + end + return intersection_bond_ids +end + +@inline function each_intersecting_bond_idx(system::BondAssociatedSystem, point_id::Int, + bond_id::Int) + return view(each_bond_idx(system, point_id), system.intersection_bond_ids[bond_id]) +end + +function calc_hood_volumes!(chunk::AbstractBodyChunk{<:BondAssociatedSystem}) + (; mat, paramsetup, system, storage) = chunk + (; volume, bonds, hood_volume, ba_hood_volume) = system + (; bond_active) = storage + + for i in each_point_idx(chunk) + _hood_volume = 0.0 # volume[i] + params = get_params(paramsetup, i) + for bond_idx in each_bond_idx(system, i) + bond = bonds[bond_idx] + j, L = bond.neighbor, bond.length + ωij = influence_function(mat, params, L) * bond_active[bond_idx] + _hood_volume += ωij * volume[j] + _ba_hood_volume = 0.0 + for i_bond_idx in each_intersecting_bond_idx(system, i, bond_idx) + i_bond = bonds[i_bond_idx] + jj, LL = i_bond.neighbor, i_bond.length + ωijj = influence_function(mat, params, LL) * bond_active[i_bond_idx] + _ba_hood_volume += ωijj * volume[jj] + end + ba_hood_volume[bond_idx] = _ba_hood_volume + end + hood_volume[i] = _hood_volume + end + + return nothing +end + +@inline get_hood_volume(chunk::AbstractBodyChunk) = chunk.system.hood_volume + +function initialize!(dh::AbstractThreadsBodyDataHandler{<:BondAssociatedSystem}, + ::AbstractTimeSolver) + @threads :static for chunk in dh.chunks + calc_hood_volumes!(chunk) + end + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_loc_to_halo!(get_hood_volume, dh, chunk_id) + end + return nothing +end + +function initialize!(dh::AbstractMPIBodyDataHandler{<:BondAssociatedSystem}, + ::AbstractTimeSolver) + calc_hood_volumes!(dh.chunk) + exchange_loc_to_halo!(get_hood_volume, dh) + return nothing +end + +@inline function volume_fraction_factor(system::BondAssociatedSystem, point_idx::Int, + bond_idx::Int) + return system.ba_hood_volume[bond_idx] / system.hood_volume[point_idx] +end + +function req_point_data_fields_fracture(::Type{<:AbstractBondAssociatedSystemMaterial}) + return (:damage, :n_active_bonds) +end + +function req_bond_data_fields_fracture(::Type{<:AbstractBondAssociatedSystemMaterial}) + return (:bond_active,) +end + +function req_data_fields_fracture(::Type{<:AbstractBondAssociatedSystemMaterial}) + return () +end + +function required_point_parameters(::Type{<:AbstractBondAssociatedSystemMaterial}) + return (:δ, :rho, elasticity_parameters()...) +end + +function get_required_point_parameters(::AbstractBondAssociatedSystemMaterial, + p::Dict{Symbol,Any}) + return (; get_horizon(p)..., get_density(p)..., get_elastic_params(p)...) +end + +function allowed_material_kwargs(::AbstractBondAssociatedSystemMaterial) + return (discretization_kwargs()..., elasticity_kwargs()..., fracture_kwargs()...) +end diff --git a/src/discretization/bond_system.jl b/src/discretization/bond_system.jl index f4de0921..7dc24b25 100644 --- a/src/discretization/bond_system.jl +++ b/src/discretization/bond_system.jl @@ -4,7 +4,7 @@ struct Bond fail_permit::Bool end -struct BondSystem{Correction<:AbstractCorrection} <: AbstractSystem +struct BondSystem{Correction<:AbstractCorrection} <: AbstractBondSystem position::Matrix{Float64} volume::Vector{Float64} bonds::Vector{Bond} @@ -157,7 +157,7 @@ function find_halo_points(bonds::Vector{Bond}, loc_points::UnitRange{Int}) return halo_points end -@inline each_bond_idx(bd::BondSystem, point_id::Int) = bd.bond_ids[point_id] +@inline each_bond_idx(system::AbstractBondSystem, point_id::Int) = system.bond_ids[point_id] function localize!(bonds::Vector{Bond}, localizer::Dict{Int,Int}) for i in eachindex(bonds) @@ -167,8 +167,8 @@ function localize!(bonds::Vector{Bond}, localizer::Dict{Int,Int}) return nothing end -function break_bonds!(storage::AbstractStorage, system::BondSystem, set_a::Vector{Int}, - set_b::Vector{Int}) +function break_bonds!(storage::AbstractStorage, system::AbstractBondSystem, + set_a::Vector{Int}, set_b::Vector{Int}) storage.n_active_bonds .= 0 for point_id in each_point_idx(system) for bond_id in each_bond_idx(system, point_id) @@ -187,16 +187,17 @@ function break_bonds!(storage::AbstractStorage, system::BondSystem, set_a::Vecto return nothing end -function calc_timestep_point(bd::BondSystem, params::AbstractPointParameters, point_id::Int) +function calc_timestep_point(system::AbstractBondSystem, params::AbstractPointParameters, + point_id::Int) dtsum = 0.0 - for bond_id in each_bond_idx(bd, point_id) - bond = bd.bonds[bond_id] - dtsum += bd.volume[bond.neighbor] * params.bc / bond.length + for bond_id in each_bond_idx(system, point_id) + bond = system.bonds[bond_id] + dtsum += system.volume[bond.neighbor] * params.bc / bond.length end return sqrt(2 * params.rho / dtsum) end -function calc_force_density!(chunk::AbstractBodyChunk{<:BondSystem}, t, Δt) +function calc_force_density!(chunk::AbstractBodyChunk{<:AbstractBondSystem}, t, Δt) (; system, mat, paramsetup, storage) = chunk storage.b_int .= 0 storage.n_active_bonds .= 0 @@ -206,7 +207,7 @@ function calc_force_density!(chunk::AbstractBodyChunk{<:BondSystem}, t, Δt) return nothing end -@inline function calc_damage!(chunk::AbstractBodyChunk{<:BondSystem}) +@inline function calc_damage!(chunk::AbstractBodyChunk{<:AbstractBondSystem}) (; n_neighbors) = chunk.system (; n_active_bonds, damage) = chunk.storage for point_id in each_point_idx(chunk) @@ -215,7 +216,7 @@ end return nothing end -@inline function stretch_based_failure!(storage::AbstractStorage, ::BondSystem, +@inline function stretch_based_failure!(storage::AbstractStorage, ::AbstractBondSystem, bond::Bond, params::AbstractPointParameters, ε::Float64, i::Int, bond_id::Int) if ε > params.εc && bond.fail_permit @@ -229,8 +230,8 @@ end return storage.bond_active[bond_id] end -function log_system(::Type{B}, options::AbstractJobOptions, - dh::AbstractDataHandler) where {B<:BondSystem} +function log_system(::Type{System}, options::AbstractJobOptions, + dh::AbstractDataHandler) where {System<:AbstractBondSystem} n_bonds = calc_n_bonds(dh) msg = "BOND SYSTEM" body_name = string(get_body_name(dh)) @@ -254,15 +255,15 @@ function calc_n_bonds(dh::AbstractMPIBodyDataHandler) return n_bonds end -function init_field_system(system::BondSystem, ::Val{:bond_active}) +function init_field_system(system::AbstractBondSystem, ::Val{:bond_active}) return ones(Bool, get_n_bonds(system)) end -function init_field_system(system::BondSystem, ::Val{:n_active_bonds}) +function init_field_system(system::AbstractBondSystem, ::Val{:n_active_bonds}) return copy(system.n_neighbors) end -function init_field_system(system::BondSystem, ::Val{:damage}) +function init_field_system(system::AbstractBondSystem, ::Val{:damage}) return zeros(get_n_loc_points(system)) end @@ -290,4 +291,4 @@ function allowed_material_kwargs(::AbstractBondSystemMaterial) return (discretization_kwargs()..., elasticity_kwargs()..., fracture_kwargs()...) end -@inline get_n_bonds(system::BondSystem) = length(system.bonds) +@inline get_n_bonds(system::AbstractBondSystem) = length(system.bonds) diff --git a/src/physics/bond_associated_correspondence.jl b/src/physics/bond_associated_correspondence.jl new file mode 100644 index 00000000..c9662c86 --- /dev/null +++ b/src/physics/bond_associated_correspondence.jl @@ -0,0 +1,236 @@ +""" + CCMaterial(; maxdmg, zem) + +A material type used to assign the material of a [`Body`](@ref) with the local continuum +consistent (correspondence) formulation of non-ordinary state-based peridynamics. + +# Keywords +- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is + exceeded, all bonds of that point are broken because the deformation gradient would then + possibly contain `NaN` values. + (default: `0.95`) +- `zem::AbstractZEMStabilization`: zero-energy mode stabilization. The + stabilization algorithm of Silling (2017) is used as default. + (default: `ZEMSilling()`) + +!!! note "Stability of fracture simulations" + This formulation is known to be not suitable for fracture simultations without + stabilization of the zero-energy modes. Therefore be careful when doing fracture + simulations and try out different parameters for `maxdmg` and `zem`. + +# Examples + +```julia-repl +julia> mat = CCMaterial() +CCMaterial(maxdmg=0.95, zem_fac=ZEMSilling()) +``` + +--- + +```julia +CCMaterial +``` + +Material type for the local continuum consistent (correspondence) formulation of +non-ordinary state-based peridynamics. + +# Fields +- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. See the + constructor docs for more informations. +- `zem_fac::Float64`: Correction factor used for zero-energy mode stabilization. See the + constructor docs for more informations. + +# Allowed material parameters +When using [`material!`](@ref) on a [`Body`](@ref) with `CCMaterial`, then the following +parameters are allowed: +- `horizon::Float64`: Radius of point interactions +- `rho::Float64`: Density +- `E::Float64`: Young's modulus +- `nu::Float64`: Poisson's ratio +- `Gc::Float64`: Critical energy release rate +- `epsilon_c::Float64`: Critical strain + +# Allowed export fields +When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with +`CCMaterial`, the following fields are allowed: +- `position::Matrix{Float64}`: Position of each point +- `displacement::Matrix{Float64}`: Displacement of each point +- `velocity::Matrix{Float64}`: Velocity of each point +- `velocity_half::Matrix{Float64}`: Velocity parameter for Verlet time solver +- `acceleration::Matrix{Float64}`: Acceleration of each point +- `b_int::Matrix{Float64}`: Internal force density of each point +- `b_ext::Matrix{Float64}`: External force density of each point +- `damage::Vector{Float64}`: Damage of each point +- `n_active_bonds::Vector{Int}`: Number of intact bonds of each point +""" +struct BACCMaterial{CM} <: AbstractBondAssociatedSystemMaterial + constitutive_model::CM + maxdmg::Float64 + function BACCMaterial(cm::CM, maxdmg::Real) where {CM} + return new{CM}(cm, maxdmg) + end +end + +function Base.show(io::IO, @nospecialize(mat::BACCMaterial)) + print(io, typeof(mat)) + print(io, msg_fields_in_brackets(mat, (:maxdmg,))) + return nothing +end + +function BACCMaterial(; model::AbstractConstitutiveModel=NeoHookeNonlinear(), + maxdmg::Real=0.85) + return BACCMaterial(model, maxdmg) +end + +struct BACCPointParameters <: AbstractPointParameters + δ::Float64 + rho::Float64 + E::Float64 + nu::Float64 + G::Float64 + K::Float64 + λ::Float64 + μ::Float64 + Gc::Float64 + εc::Float64 + bc::Float64 +end + +function BACCPointParameters(mat::BACCMaterial, p::Dict{Symbol,Any}) + (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) + (; Gc, εc) = get_frac_params(p, δ, K) + bc = 18 * K / (π * δ^4) # bond constant + return BACCPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) +end + +@params BACCMaterial BACCPointParameters + +@storage BACCMaterial struct BACCStorage + @lthfield position::Matrix{Float64} + @pointfield displacement::Matrix{Float64} + @pointfield velocity::Matrix{Float64} + @pointfield velocity_half::Matrix{Float64} + @pointfield velocity_half_old::Matrix{Float64} + @pointfield acceleration::Matrix{Float64} + @htlfield b_int::Matrix{Float64} + @pointfield b_int_old::Matrix{Float64} + @pointfield b_ext::Matrix{Float64} + @pointfield density_matrix::Matrix{Float64} + @pointfield damage::Vector{Float64} + bond_active::Vector{Bool} + @pointfield n_active_bonds::Vector{Int} + @pointfield stress::Matrix{Float64} + @pointfield von_mises_stress::Vector{Float64} +end + +function init_field(::BACCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, + ::Val{:b_int}) + return zeros(3, get_n_points(system)) +end + +function init_field(::BACCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, + ::Val{:stress}) + return zeros(9, get_n_loc_points(system)) +end + +function init_field(::BACCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, + ::Val{:von_mises_stress}) + return zeros(get_n_loc_points(system)) +end + +# function calc_force_density!(chunk::AbstractBodyChunk{S,M}, +# Δt::Float64) where {S<:BondAssociatedSystem,M<:BANOSBMaterial} +# (; system, mat, paramsetup, storage) = chunk +# storage.b_int .= 0 +# storage.n_active_bonds .= 0 +# for point_id in each_point_idx(chunk) +# force_density_point!(storage, system, mat, paramsetup, Δt, point_id) +# end +# return nothing +# end + +function force_density_point!(storage::BACCStorage, system::BondAssociatedSystem, + mat::BACCMaterial, paramhandler::AbstractParameterHandler, + t, Δt, i) + params = get_params(paramhandler, i) + force_density_point!(storage, system, mat, params, t, Δt, i) + return nothing +end + +function force_density_point!(storage::BACCStorage, system::BondAssociatedSystem, + mat::BACCMaterial, params::BACCPointParameters, t, Δt, i) + for bond_idx in each_bond_idx(system, i) + force_density_bond!(storage, system, mat, params, t, Δt, i, bond_idx) + end + return nothing +end + +function force_density_bond!(storage::BACCStorage, system::BondAssociatedSystem, + mat::BACCMaterial, params::BACCPointParameters, t, Δt, i, + bond_idx) + defgrad_res = calc_deformation_gradient(storage, system, mat, params, i, bond_idx) + (; F) = defgrad_res + if containsnan(F) || storage.damage[i] > mat.maxdmg + storage.bond_active[bond_idx] = false + return nothing + end + PKinv = calc_first_piola_kirchhoff!(storage, mat, params, defgrad_res, Δt, i, bond_idx) + + bond = system.bonds[bond_idx] + j, L = bond.neighbor, bond.length + ΔXij = get_coordinates_diff(system, i, j) + Δxij = get_coordinates_diff(storage, i, j) + l = norm(Δxij) + ε = (l - L) / L + stretch_based_failure!(storage, system, bond, params, ε, i, bond_idx) + + ωij = influence_function(mat, params, L) * storage.bond_active[bond_idx] + ϕi = volume_fraction_factor(system, i, bond_idx) + tij = ϕi * ωij * PKinv * ΔXij + # tij = ωij * PKinv * ΔXij + update_add_b_int!(storage, i, tij .* system.volume[j]) + update_add_b_int!(storage, j, -tij .* system.volume[i]) + return nothing +end + + +@inline function influence_function(::BACCMaterial, params::BACCPointParameters, + L::Float64) + return params.δ / L +end + +function calc_deformation_gradient(storage::BACCStorage, system::BondAssociatedSystem, + mat::BACCMaterial, params::BACCPointParameters, i, + bond_idx) + (; bonds, volume) = system + (; bond_active) = storage + K = zero(SMatrix{3,3,Float64,9}) + _F = zero(SMatrix{3,3,Float64,9}) + for bond_id in each_intersecting_bond_idx(system, i, bond_idx) + bond = bonds[bond_id] + j, L = bond.neighbor, bond.length + ΔXij = get_diff(system.position, i, j) + Δxij = get_diff(storage.position, i, j) + + temp = influence_function(mat, params, L) * volume[j] + K += temp * (ΔXij * ΔXij') + + temp = influence_function(mat, params, L) * bond_active[bond_id] * volume[j] + _F += temp * (Δxij * ΔXij') + end + Kinv = inv(K) + F = _F * Kinv + return (; F, Kinv) +end + +function calc_first_piola_kirchhoff!(storage::BACCStorage, mat::BACCMaterial, + params::BACCPointParameters, defgrad_res, Δt, i, + bond_idx) + (; F, Kinv) = defgrad_res + σ = cauchy_stress(mat.constitutive_model, storage, params, F) + # update_tensor!(storage.stress, i, σ) + # storage.von_mises_stress[i] = von_mises_stress(σ) + P = det(F) * σ * inv(F)' + PKinv = P * Kinv + return PKinv +end diff --git a/test/discretization/test_bond_associated_system.jl b/test/discretization/test_bond_associated_system.jl new file mode 100644 index 00000000..0834802f --- /dev/null +++ b/test/discretization/test_bond_associated_system.jl @@ -0,0 +1,71 @@ +@testitem "bond-associated family" begin + # setup + position = [0.0 1.0 0.0 0.0 + 0.0 0.0 1.0 0.0 + 0.0 0.0 0.0 1.0] + volume = [1.1, 1.2, 1.3, 1.4] + mat = BACCMaterial() + body = Body(mat, position, volume) + material!(body, horizon=2, rho=1, E=1, nu=0.25, Gc=1) + pd = Peridynamics.PointDecomposition(body, 1) + + # 1 + system = Peridynamics.BondAssociatedSystem(body, pd, 1) + + @test system.position == position + @test system.volume == volume + @test system.bonds == [ + Peridynamics.Bond(2, 1.0, true), + Peridynamics.Bond(3, 1.0, true), + Peridynamics.Bond(4, 1.0, true), + Peridynamics.Bond(1, 1.0, true), + Peridynamics.Bond(3, √2, true), + Peridynamics.Bond(4, √2, true), + Peridynamics.Bond(1, 1.0, true), + Peridynamics.Bond(2, √2, true), + Peridynamics.Bond(4, √2, true), + Peridynamics.Bond(1, 1.0, true), + Peridynamics.Bond(2, √2, true), + Peridynamics.Bond(3, √2, true), + ] + @test system.n_neighbors == [3, 3, 3, 3] + @test system.bond_ids == [1:3, 4:6, 7:9, 10:12] + +end + +@testitem "intersection bond ids" begin + pos, vol = uniform_box(1, 0.25, 0.25, 0.25) + body = Body(BACCMaterial(), pos, vol) + material!(body, horizon=0.5, rho=1, E=1, nu=0.25, Gc=1) + + pd = Peridynamics.PointDecomposition(body, 1) + + bas = Peridynamics.get_system(body, pd, 1) + (; bonds, bond_ids, intersection_bond_ids) = bas + + @test bonds == [ + Peridynamics.Bond(2, 0.25, true) + Peridynamics.Bond(3, 0.5, true) + Peridynamics.Bond(1, 0.25, true) + Peridynamics.Bond(3, 0.25, true) + Peridynamics.Bond(4, 0.5, true) + Peridynamics.Bond(1, 0.5, true) + Peridynamics.Bond(2, 0.25, true) + Peridynamics.Bond(4, 0.25, true) + Peridynamics.Bond(2, 0.5, true) + Peridynamics.Bond(3, 0.25, true) + ] + @test bond_ids == [1:2, 3:5, 6:8, 9:10] + @test intersection_bond_ids == [[2], [1], [], [3], [2], [2], [1], [], [2], [1]] + + for i in Peridynamics.each_point_idx(system) + for bond_idx in Peridynamics.each_bond_idx(system, i) + # bond = bonds[bond_idx] + # j = bond.neighbor + for babond_idx in Peridynamics.each_intersecting_bond_idx(system, i, bond_idx) + + end + end + end + +end From 725d0033455ccf5c1b99c00e9d63306cf5b21e2d Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Fri, 25 Oct 2024 18:48:07 +0200 Subject: [PATCH 12/40] Renaming --- .../{bond_associated_correspondence.jl => ba_correspondence.jl} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/physics/{bond_associated_correspondence.jl => ba_correspondence.jl} (100%) diff --git a/src/physics/bond_associated_correspondence.jl b/src/physics/ba_correspondence.jl similarity index 100% rename from src/physics/bond_associated_correspondence.jl rename to src/physics/ba_correspondence.jl From c9806623b895979e32a1ef6436227a1b97492582 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Fri, 25 Oct 2024 18:54:00 +0200 Subject: [PATCH 13/40] Copy-n-past bacc model as start for bark material --- src/Peridynamics.jl | 5 +- src/physics/bark_correspondence.jl | 236 +++++++++++++++++++++++++++++ 2 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 src/physics/bark_correspondence.jl diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index e7a605f9..4db4e469 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -9,7 +9,7 @@ end import LibGit2, Dates # Material models -export BBMaterial, OSBMaterial, CCMaterial, BACCMaterial, CKIMaterial +export BBMaterial, OSBMaterial, CCMaterial, BACCMaterial, BARKCCMaterial, CKIMaterial # CCMaterial related types export NeoHookeNonlinear, SaintVenantKirchhoff, ZEMSilling @@ -127,7 +127,8 @@ include("physics/continuum_kinematics_inspired.jl") include("physics/ordinary_state_based.jl") include("physics/constitutive_models.jl") include("physics/correspondence.jl") -include("physics/bond_associated_correspondence.jl") +include("physics/ba_correspondence.jl") +include("physics/bark_correspondence.jl") include("VtkReader/VtkReader.jl") using .VtkReader diff --git a/src/physics/bark_correspondence.jl b/src/physics/bark_correspondence.jl new file mode 100644 index 00000000..b9be7983 --- /dev/null +++ b/src/physics/bark_correspondence.jl @@ -0,0 +1,236 @@ +""" + BARKCCMaterial(; maxdmg, zem) + +A material type used to assign the material of a [`Body`](@ref) with the local continuum +consistent (correspondence) formulation of non-ordinary state-based peridynamics. + +# Keywords +- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is + exceeded, all bonds of that point are broken because the deformation gradient would then + possibly contain `NaN` values. + (default: `0.95`) +- `zem::AbstractZEMStabilization`: zero-energy mode stabilization. The + stabilization algorithm of Silling (2017) is used as default. + (default: `ZEMSilling()`) + +!!! note "Stability of fracture simulations" + This formulation is known to be not suitable for fracture simultations without + stabilization of the zero-energy modes. Therefore be careful when doing fracture + simulations and try out different parameters for `maxdmg` and `zem`. + +# Examples + +```julia-repl +julia> mat = CCMaterial() +CCMaterial(maxdmg=0.95, zem_fac=ZEMSilling()) +``` + +--- + +```julia +CCMaterial +``` + +Material type for the local continuum consistent (correspondence) formulation of +non-ordinary state-based peridynamics. + +# Fields +- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. See the + constructor docs for more informations. +- `zem_fac::Float64`: Correction factor used for zero-energy mode stabilization. See the + constructor docs for more informations. + +# Allowed material parameters +When using [`material!`](@ref) on a [`Body`](@ref) with `CCMaterial`, then the following +parameters are allowed: +- `horizon::Float64`: Radius of point interactions +- `rho::Float64`: Density +- `E::Float64`: Young's modulus +- `nu::Float64`: Poisson's ratio +- `Gc::Float64`: Critical energy release rate +- `epsilon_c::Float64`: Critical strain + +# Allowed export fields +When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with +`CCMaterial`, the following fields are allowed: +- `position::Matrix{Float64}`: Position of each point +- `displacement::Matrix{Float64}`: Displacement of each point +- `velocity::Matrix{Float64}`: Velocity of each point +- `velocity_half::Matrix{Float64}`: Velocity parameter for Verlet time solver +- `acceleration::Matrix{Float64}`: Acceleration of each point +- `b_int::Matrix{Float64}`: Internal force density of each point +- `b_ext::Matrix{Float64}`: External force density of each point +- `damage::Vector{Float64}`: Damage of each point +- `n_active_bonds::Vector{Int}`: Number of intact bonds of each point +""" +struct BARKCCMaterial{CM} <: AbstractBondAssociatedSystemMaterial + constitutive_model::CM + maxdmg::Float64 + function BARKCCMaterial(cm::CM, maxdmg::Real) where {CM} + return new{CM}(cm, maxdmg) + end +end + +function Base.show(io::IO, @nospecialize(mat::BARKCCMaterial)) + print(io, typeof(mat)) + print(io, msg_fields_in_brackets(mat, (:maxdmg,))) + return nothing +end + +function BARKCCMaterial(; model::AbstractConstitutiveModel=NeoHookeNonlinear(), + maxdmg::Real=0.85) + return BARKCCMaterial(model, maxdmg) +end + +struct BARKCCPointParameters <: AbstractPointParameters + δ::Float64 + rho::Float64 + E::Float64 + nu::Float64 + G::Float64 + K::Float64 + λ::Float64 + μ::Float64 + Gc::Float64 + εc::Float64 + bc::Float64 +end + +function BARKCCPointParameters(mat::BARKCCMaterial, p::Dict{Symbol,Any}) + (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) + (; Gc, εc) = get_frac_params(p, δ, K) + bc = 18 * K / (π * δ^4) # bond constant + return BARKCCPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) +end + +@params BARKCCMaterial BARKCCPointParameters + +@storage BARKCCMaterial struct BARKCCStorage + @lthfield position::Matrix{Float64} + @pointfield displacement::Matrix{Float64} + @pointfield velocity::Matrix{Float64} + @pointfield velocity_half::Matrix{Float64} + @pointfield velocity_half_old::Matrix{Float64} + @pointfield acceleration::Matrix{Float64} + @htlfield b_int::Matrix{Float64} + @pointfield b_int_old::Matrix{Float64} + @pointfield b_ext::Matrix{Float64} + @pointfield density_matrix::Matrix{Float64} + @pointfield damage::Vector{Float64} + bond_active::Vector{Bool} + @pointfield n_active_bonds::Vector{Int} + @pointfield stress::Matrix{Float64} + @pointfield von_mises_stress::Vector{Float64} +end + +function init_field(::BARKCCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, + ::Val{:b_int}) + return zeros(3, get_n_points(system)) +end + +function init_field(::BARKCCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, + ::Val{:stress}) + return zeros(9, get_n_loc_points(system)) +end + +function init_field(::BARKCCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, + ::Val{:von_mises_stress}) + return zeros(get_n_loc_points(system)) +end + +# function calc_force_density!(chunk::AbstractBodyChunk{S,M}, +# Δt::Float64) where {S<:BondAssociatedSystem,M<:BANOSBMaterial} +# (; system, mat, paramsetup, storage) = chunk +# storage.b_int .= 0 +# storage.n_active_bonds .= 0 +# for point_id in each_point_idx(chunk) +# force_density_point!(storage, system, mat, paramsetup, Δt, point_id) +# end +# return nothing +# end + +function force_density_point!(storage::BARKCCStorage, system::BondAssociatedSystem, + mat::BARKCCMaterial, paramhandler::AbstractParameterHandler, + t, Δt, i) + params = get_params(paramhandler, i) + force_density_point!(storage, system, mat, params, t, Δt, i) + return nothing +end + +function force_density_point!(storage::BARKCCStorage, system::BondAssociatedSystem, + mat::BARKCCMaterial, params::BARKCCPointParameters, t, Δt, i) + for bond_idx in each_bond_idx(system, i) + force_density_bond!(storage, system, mat, params, t, Δt, i, bond_idx) + end + return nothing +end + +function force_density_bond!(storage::BARKCCStorage, system::BondAssociatedSystem, + mat::BARKCCMaterial, params::BARKCCPointParameters, t, Δt, i, + bond_idx) + defgrad_res = calc_deformation_gradient(storage, system, mat, params, i, bond_idx) + (; F) = defgrad_res + if containsnan(F) || storage.damage[i] > mat.maxdmg + storage.bond_active[bond_idx] = false + return nothing + end + PKinv = calc_first_piola_kirchhoff!(storage, mat, params, defgrad_res, Δt, i, bond_idx) + + bond = system.bonds[bond_idx] + j, L = bond.neighbor, bond.length + ΔXij = get_coordinates_diff(system, i, j) + Δxij = get_coordinates_diff(storage, i, j) + l = norm(Δxij) + ε = (l - L) / L + stretch_based_failure!(storage, system, bond, params, ε, i, bond_idx) + + ωij = influence_function(mat, params, L) * storage.bond_active[bond_idx] + ϕi = volume_fraction_factor(system, i, bond_idx) + tij = ϕi * ωij * PKinv * ΔXij + # tij = ωij * PKinv * ΔXij + update_add_b_int!(storage, i, tij .* system.volume[j]) + update_add_b_int!(storage, j, -tij .* system.volume[i]) + return nothing +end + + +@inline function influence_function(::BARKCCMaterial, params::BARKCCPointParameters, + L::Float64) + return params.δ / L +end + +function calc_deformation_gradient(storage::BARKCCStorage, system::BondAssociatedSystem, + mat::BARKCCMaterial, params::BARKCCPointParameters, i, + bond_idx) + (; bonds, volume) = system + (; bond_active) = storage + K = zero(SMatrix{3,3,Float64,9}) + _F = zero(SMatrix{3,3,Float64,9}) + for bond_id in each_intersecting_bond_idx(system, i, bond_idx) + bond = bonds[bond_id] + j, L = bond.neighbor, bond.length + ΔXij = get_diff(system.position, i, j) + Δxij = get_diff(storage.position, i, j) + + temp = influence_function(mat, params, L) * volume[j] + K += temp * (ΔXij * ΔXij') + + temp = influence_function(mat, params, L) * bond_active[bond_id] * volume[j] + _F += temp * (Δxij * ΔXij') + end + Kinv = inv(K) + F = _F * Kinv + return (; F, Kinv) +end + +function calc_first_piola_kirchhoff!(storage::BARKCCStorage, mat::BARKCCMaterial, + params::BARKCCPointParameters, defgrad_res, Δt, i, + bond_idx) + (; F, Kinv) = defgrad_res + σ = cauchy_stress(mat.constitutive_model, storage, params, F) + # update_tensor!(storage.stress, i, σ) + # storage.von_mises_stress[i] = von_mises_stress(σ) + P = det(F) * σ * inv(F)' + PKinv = P * Kinv + return PKinv +end From 765ab9229f32655aec82c6e6bbfdad3cb39d4060 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Sat, 26 Oct 2024 00:13:06 +0200 Subject: [PATCH 14/40] Simplify neighborhood volumes calculation --- src/discretization/bond_associated_system.jl | 44 +++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/src/discretization/bond_associated_system.jl b/src/discretization/bond_associated_system.jl index f34121e4..267e7b34 100644 --- a/src/discretization/bond_associated_system.jl +++ b/src/discretization/bond_associated_system.jl @@ -80,24 +80,20 @@ end end function calc_hood_volumes!(chunk::AbstractBodyChunk{<:BondAssociatedSystem}) - (; mat, paramsetup, system, storage) = chunk + (; system) = chunk (; volume, bonds, hood_volume, ba_hood_volume) = system - (; bond_active) = storage for i in each_point_idx(chunk) - _hood_volume = 0.0 # volume[i] - params = get_params(paramsetup, i) + _hood_volume = volume[i] for bond_idx in each_bond_idx(system, i) bond = bonds[bond_idx] - j, L = bond.neighbor, bond.length - ωij = influence_function(mat, params, L) * bond_active[bond_idx] - _hood_volume += ωij * volume[j] + j = bond.neighbor + _hood_volume += volume[j] _ba_hood_volume = 0.0 for i_bond_idx in each_intersecting_bond_idx(system, i, bond_idx) i_bond = bonds[i_bond_idx] - jj, LL = i_bond.neighbor, i_bond.length - ωijj = influence_function(mat, params, LL) * bond_active[i_bond_idx] - _ba_hood_volume += ωijj * volume[jj] + jj = i_bond.neighbor + _ba_hood_volume += volume[jj] end ba_hood_volume[bond_idx] = _ba_hood_volume end @@ -107,6 +103,34 @@ function calc_hood_volumes!(chunk::AbstractBodyChunk{<:BondAssociatedSystem}) return nothing end +# function calc_hood_volumes!(chunk::AbstractBodyChunk{<:BondAssociatedSystem}) +# (; mat, paramsetup, system, storage) = chunk +# (; volume, bonds, hood_volume, ba_hood_volume) = system +# (; bond_active) = storage + +# for i in each_point_idx(chunk) +# _hood_volume = 0.0 # volume[i] +# params = get_params(paramsetup, i) +# for bond_idx in each_bond_idx(system, i) +# bond = bonds[bond_idx] +# j, L = bond.neighbor, bond.length +# ωij = influence_function(mat, params, L) * bond_active[bond_idx] +# _hood_volume += ωij * volume[j] +# _ba_hood_volume = 0.0 +# for i_bond_idx in each_intersecting_bond_idx(system, i, bond_idx) +# i_bond = bonds[i_bond_idx] +# jj, LL = i_bond.neighbor, i_bond.length +# ωijj = influence_function(mat, params, LL) * bond_active[i_bond_idx] +# _ba_hood_volume += ωijj * volume[jj] +# end +# ba_hood_volume[bond_idx] = _ba_hood_volume +# end +# hood_volume[i] = _hood_volume +# end + +# return nothing +# end + @inline get_hood_volume(chunk::AbstractBodyChunk) = chunk.system.hood_volume function initialize!(dh::AbstractThreadsBodyDataHandler{<:BondAssociatedSystem}, From 7dbce7a6618c2b630d025fe5945b319231b7e20a Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Thu, 31 Oct 2024 09:03:39 +0100 Subject: [PATCH 15/40] Minor enhancements --- src/discretization/bond_associated_system.jl | 4 +- src/physics/ba_correspondence.jl | 5 +- src/physics/bark_correspondence.jl | 115 ++++++++++++++----- 3 files changed, 88 insertions(+), 36 deletions(-) diff --git a/src/discretization/bond_associated_system.jl b/src/discretization/bond_associated_system.jl index 267e7b34..58737df1 100644 --- a/src/discretization/bond_associated_system.jl +++ b/src/discretization/bond_associated_system.jl @@ -50,8 +50,8 @@ end function find_intersection_bond_ids(body, loc_points, bonds, bond_ids) intersection_bond_ids = Vector{Vector{Int}}(undef, length(bonds)) for (li, i) in enumerate(loc_points) - δ = get_point_param(body, :δ, i) - δ² = 1.1δ * 1.1δ + δ = 1.01 * get_point_param(body, :δ, i) + δ² = δ * δ bond_ids_of_i = bond_ids[li] for bond_id in bond_ids_of_i bond = bonds[bond_id] diff --git a/src/physics/ba_correspondence.jl b/src/physics/ba_correspondence.jl index c9662c86..4ce1afed 100644 --- a/src/physics/ba_correspondence.jl +++ b/src/physics/ba_correspondence.jl @@ -211,11 +211,8 @@ function calc_deformation_gradient(storage::BACCStorage, system::BondAssociatedS j, L = bond.neighbor, bond.length ΔXij = get_diff(system.position, i, j) Δxij = get_diff(storage.position, i, j) - - temp = influence_function(mat, params, L) * volume[j] - K += temp * (ΔXij * ΔXij') - temp = influence_function(mat, params, L) * bond_active[bond_id] * volume[j] + K += temp * (ΔXij * ΔXij') _F += temp * (Δxij * ΔXij') end Kinv = inv(K) diff --git a/src/physics/bark_correspondence.jl b/src/physics/bark_correspondence.jl index b9be7983..a46a42d4 100644 --- a/src/physics/bark_correspondence.jl +++ b/src/physics/bark_correspondence.jl @@ -121,6 +121,7 @@ end @pointfield n_active_bonds::Vector{Int} @pointfield stress::Matrix{Float64} @pointfield von_mises_stress::Vector{Float64} + @lthfield defgrad::Matrix{Float64} end function init_field(::BARKCCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, @@ -138,16 +139,79 @@ function init_field(::BARKCCMaterial, ::AbstractTimeSolver, system::BondAssociat return zeros(get_n_loc_points(system)) end -# function calc_force_density!(chunk::AbstractBodyChunk{S,M}, -# Δt::Float64) where {S<:BondAssociatedSystem,M<:BANOSBMaterial} -# (; system, mat, paramsetup, storage) = chunk -# storage.b_int .= 0 -# storage.n_active_bonds .= 0 -# for point_id in each_point_idx(chunk) -# force_density_point!(storage, system, mat, paramsetup, Δt, point_id) -# end -# return nothing -# end +function init_field(::BARKCCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, + ::Val{:defgrad}) + return zeros(9, get_n_points(system)) +end + +# TODO: split the verlet timestep into 3 parts for threading, improve code reusability! +function verlet_timestep!(dh::AbstractThreadsBodyDataHandler{Sys,M}, + options::AbstractJobOptions, Δt::Float64, Δt½::Float64, + n::Int) where {Sys<:BondAssociatedSystem,M<:BARKCCMaterial} + t = n * Δt + @threads :static for chunk_id in eachindex(dh.chunks) + chunk = dh.chunks[chunk_id] + update_vel_half!(chunk, Δt½) + apply_boundary_conditions!(chunk, t) + update_disp_and_pos!(chunk, Δt) + end + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_loc_to_halo!(dh, chunk_id, (:position,)) + calc_deformation_gradient!(dh.chunks[chunk_id], t, Δt) + end + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_loc_to_halo!(dh, chunk_id, (:defgrad,)) + calc_force_density!(dh.chunks[chunk_id], t, Δt) + end + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_halo_to_loc!(dh, chunk_id) + chunk = dh.chunks[chunk_id] + calc_damage!(chunk) + update_acc_and_vel!(chunk, Δt½) + export_results(dh, options, chunk_id, n, t) + end + return nothing +end + +function calc_deformation_gradient!(chunk::AbstractBodyChunk{S,M}, t, + Δt) where {S<:BondAssociatedSystem,M<:BARKCCMaterial} + (; system, mat, paramsetup, storage) = chunk + for i in each_point_idx(chunk) + calc_deformation_gradient_point!(storage, system, mat, paramsetup, i) + end + return nothing +end + +function calc_deformation_gradient_point!(storage::BARKCCStorage, + system::BondAssociatedSystem, mat::BARKCCMaterial, + paramhandler::AbstractParameterHandler, i) + params = get_params(paramhandler, i) + calc_deformation_gradient_point!(storage, system, mat, params, i) + return nothing +end + +function calc_deformation_gradient_point!(storage::BARKCCStorage, + system::BondAssociatedSystem, mat::BARKCCMaterial, + params::BARKCCPointParameters, i) + (; bonds, volume) = system + (; bond_active) = storage + K = zero(SMatrix{3,3,Float64,9}) + _F = zero(SMatrix{3,3,Float64,9}) + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j, L = bond.neighbor, bond.length + ΔXij = get_diff(system.position, i, j) + Δxij = get_diff(storage.position, i, j) + ωij = influence_function(mat, params, L) * bond_active[bond_id] + temp = ωij * volume[j] + K += temp * (ΔXij * ΔXij') + _F += temp * (Δxij * ΔXij') + end + Kinv = inv(K) + F = _F * Kinv + update_tensor!(storage.defgrad, i, F) + return nothing +end function force_density_point!(storage::BARKCCStorage, system::BondAssociatedSystem, mat::BARKCCMaterial, paramhandler::AbstractParameterHandler, @@ -168,7 +232,7 @@ end function force_density_bond!(storage::BARKCCStorage, system::BondAssociatedSystem, mat::BARKCCMaterial, params::BARKCCPointParameters, t, Δt, i, bond_idx) - defgrad_res = calc_deformation_gradient(storage, system, mat, params, i, bond_idx) + Fb = calc_deformation_gradient(storage, system, mat, params, i, bond_idx) (; F) = defgrad_res if containsnan(F) || storage.damage[i] > mat.maxdmg storage.bond_active[bond_idx] = false @@ -202,25 +266,16 @@ end function calc_deformation_gradient(storage::BARKCCStorage, system::BondAssociatedSystem, mat::BARKCCMaterial, params::BARKCCPointParameters, i, bond_idx) - (; bonds, volume) = system - (; bond_active) = storage - K = zero(SMatrix{3,3,Float64,9}) - _F = zero(SMatrix{3,3,Float64,9}) - for bond_id in each_intersecting_bond_idx(system, i, bond_idx) - bond = bonds[bond_id] - j, L = bond.neighbor, bond.length - ΔXij = get_diff(system.position, i, j) - Δxij = get_diff(storage.position, i, j) - - temp = influence_function(mat, params, L) * volume[j] - K += temp * (ΔXij * ΔXij') - - temp = influence_function(mat, params, L) * bond_active[bond_id] * volume[j] - _F += temp * (Δxij * ΔXij') - end - Kinv = inv(K) - F = _F * Kinv - return (; F, Kinv) + Fi = get_tensor(storage.defgrad, i) + bond = system.bonds[bond_idx] + j, L = bond.neighbor, bond.length + Fj = get_tensor(storage.defgrad, j) + F̂ = (Fi + Fj) ./ 2 + ΔXij = get_coordinates_diff(system, i, j) + Δxij = get_coordinates_diff(storage, i, j) + ΔFij = (Δxij - F̂ * ΔXij) * ΔXij' ./ (L * L) + Fb = Fj + ΔFij + return Fb end function calc_first_piola_kirchhoff!(storage::BARKCCStorage, mat::BARKCCMaterial, From cb9259b65bc2de4b8d671504571b74753e6def40 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Thu, 7 Nov 2024 15:16:53 +0100 Subject: [PATCH 16/40] Renaming CC -> C --- benchmark/benchmarks.jl | 2 +- docs/src/api_reference.md | 2 +- docs/src/literate/tutorial_wave_interface.jl | 2 +- src/Peridynamics.jl | 4 +- src/auxiliary/precompile_workload.jl | 2 +- src/physics/ba_correspondence.jl | 61 +++++++-------- src/physics/bark_correspondence.jl | 76 +++++++++---------- src/physics/correspondence.jl | 60 +++++++-------- test/auxiliary/test_io.jl | 2 +- .../test_bond_associated_system.jl | 20 ++--- test/integration/b_int_correspondence.jl | 4 +- test/integration/mpi_threads_comparison.jl | 6 +- test/integration/symmetry_correspondence.jl | 8 +- 13 files changed, 125 insertions(+), 124 deletions(-) diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl index 2aab901f..f25dfb87 100644 --- a/benchmark/benchmarks.jl +++ b/benchmark/benchmarks.jl @@ -10,4 +10,4 @@ include(joinpath(@__DIR__, "mode_i.jl")) SUITE["mode_i"] = BenchmarkGroup() SUITE["mode_i"]["BBMaterial, 40"] = @benchmarkable submit(mode_i(BBMaterial(), 40)) SUITE["mode_i"]["OSBMaterial, 40"] = @benchmarkable submit(mode_i(OSBMaterial(), 40)) -SUITE["mode_i"]["CCMaterial, 40"] = @benchmarkable submit(mode_i(CCMaterial(), 40)) +SUITE["mode_i"]["CMaterial, 40"] = @benchmarkable submit(mode_i(CMaterial(), 40)) diff --git a/docs/src/api_reference.md b/docs/src/api_reference.md index 10300587..5e684b74 100644 --- a/docs/src/api_reference.md +++ b/docs/src/api_reference.md @@ -12,7 +12,7 @@ Pages = ["api_reference.md"] ```@docs BBMaterial OSBMaterial -CCMaterial +CMaterial CKIMaterial ``` diff --git a/docs/src/literate/tutorial_wave_interface.jl b/docs/src/literate/tutorial_wave_interface.jl index a4a21a1a..27445c5d 100644 --- a/docs/src/literate/tutorial_wave_interface.jl +++ b/docs/src/literate/tutorial_wave_interface.jl @@ -19,7 +19,7 @@ npyz = 4 # With these parameters we now create a body, here using the non-ordinary state-based # correspondence formulation. pos, vol = uniform_box(lx, lyz, lyz, Δx) -body = Body(CCMaterial(), pos, vol) +body = Body(CMaterial(), pos, vol) # Again, failure is not allowed in the whole body. failure_permit!(body, false) diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index 4db4e469..21b31d00 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -9,9 +9,9 @@ end import LibGit2, Dates # Material models -export BBMaterial, OSBMaterial, CCMaterial, BACCMaterial, BARKCCMaterial, CKIMaterial +export BBMaterial, OSBMaterial, CMaterial, BACMaterial, BARKCMaterial, CKIMaterial -# CCMaterial related types +# CMaterial related types export NeoHookeNonlinear, SaintVenantKirchhoff, ZEMSilling # Systems related types diff --git a/src/auxiliary/precompile_workload.jl b/src/auxiliary/precompile_workload.jl index 8ae053ed..30bad6a0 100644 --- a/src/auxiliary/precompile_workload.jl +++ b/src/auxiliary/precompile_workload.jl @@ -43,7 +43,7 @@ velocity_bc!(t -> -1, b2, :set_a, :x) velocity_bc!(t -> 1, b2, :set_b, 1) - b3 = Body(CCMaterial(), pos1, vol1) + b3 = Body(CMaterial(), pos1, vol1) material!(b3; horizon=2, E=2.1e5, nu=0.25, rho=8e-6, Gc=2.7) point_set!(p -> p[1] ≤ 0.5, b3, :set_a) point_set!(x -> x > 0.5, b3, :set_b) diff --git a/src/physics/ba_correspondence.jl b/src/physics/ba_correspondence.jl index 4ce1afed..27b593be 100644 --- a/src/physics/ba_correspondence.jl +++ b/src/physics/ba_correspondence.jl @@ -1,5 +1,5 @@ """ - CCMaterial(; maxdmg, zem) + CMaterial(; maxdmg, zem) A material type used to assign the material of a [`Body`](@ref) with the local continuum consistent (correspondence) formulation of non-ordinary state-based peridynamics. @@ -21,14 +21,14 @@ consistent (correspondence) formulation of non-ordinary state-based peridynamics # Examples ```julia-repl -julia> mat = CCMaterial() -CCMaterial(maxdmg=0.95, zem_fac=ZEMSilling()) +julia> mat = CMaterial() +CMaterial(maxdmg=0.95, zem_fac=ZEMSilling()) ``` --- ```julia -CCMaterial +CMaterial ``` Material type for the local continuum consistent (correspondence) formulation of @@ -41,7 +41,7 @@ non-ordinary state-based peridynamics. constructor docs for more informations. # Allowed material parameters -When using [`material!`](@ref) on a [`Body`](@ref) with `CCMaterial`, then the following +When using [`material!`](@ref) on a [`Body`](@ref) with `CMaterial`, then the following parameters are allowed: - `horizon::Float64`: Radius of point interactions - `rho::Float64`: Density @@ -52,7 +52,7 @@ parameters are allowed: # Allowed export fields When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with -`CCMaterial`, the following fields are allowed: +`CMaterial`, the following fields are allowed: - `position::Matrix{Float64}`: Position of each point - `displacement::Matrix{Float64}`: Displacement of each point - `velocity::Matrix{Float64}`: Velocity of each point @@ -63,26 +63,26 @@ When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with - `damage::Vector{Float64}`: Damage of each point - `n_active_bonds::Vector{Int}`: Number of intact bonds of each point """ -struct BACCMaterial{CM} <: AbstractBondAssociatedSystemMaterial +struct BACMaterial{CM} <: AbstractBondAssociatedSystemMaterial constitutive_model::CM maxdmg::Float64 - function BACCMaterial(cm::CM, maxdmg::Real) where {CM} + function BACMaterial(cm::CM, maxdmg::Real) where {CM} return new{CM}(cm, maxdmg) end end -function Base.show(io::IO, @nospecialize(mat::BACCMaterial)) +function Base.show(io::IO, @nospecialize(mat::BACMaterial)) print(io, typeof(mat)) print(io, msg_fields_in_brackets(mat, (:maxdmg,))) return nothing end -function BACCMaterial(; model::AbstractConstitutiveModel=NeoHookeNonlinear(), +function BACMaterial(; model::AbstractConstitutiveModel=NeoHookeNonlinear(), maxdmg::Real=0.85) - return BACCMaterial(model, maxdmg) + return BACMaterial(model, maxdmg) end -struct BACCPointParameters <: AbstractPointParameters +struct BACPointParameters <: AbstractPointParameters δ::Float64 rho::Float64 E::Float64 @@ -96,16 +96,17 @@ struct BACCPointParameters <: AbstractPointParameters bc::Float64 end -function BACCPointParameters(mat::BACCMaterial, p::Dict{Symbol,Any}) +function BACPointParameters(mat::BACMaterial, p::Dict{Symbol,Any}) (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) (; Gc, εc) = get_frac_params(p, δ, K) bc = 18 * K / (π * δ^4) # bond constant - return BACCPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) + return BACPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) end -@params BACCMaterial BACCPointParameters -@storage BACCMaterial struct BACCStorage +@params BACMaterial BACPointParameters + +@storage BACMaterial struct BACStorage @lthfield position::Matrix{Float64} @pointfield displacement::Matrix{Float64} @pointfield velocity::Matrix{Float64} @@ -123,17 +124,17 @@ end @pointfield von_mises_stress::Vector{Float64} end -function init_field(::BACCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, +function init_field(::BACMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, ::Val{:b_int}) return zeros(3, get_n_points(system)) end -function init_field(::BACCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, +function init_field(::BACMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, ::Val{:stress}) return zeros(9, get_n_loc_points(system)) end -function init_field(::BACCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, +function init_field(::BACMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, ::Val{:von_mises_stress}) return zeros(get_n_loc_points(system)) end @@ -149,24 +150,24 @@ end # return nothing # end -function force_density_point!(storage::BACCStorage, system::BondAssociatedSystem, - mat::BACCMaterial, paramhandler::AbstractParameterHandler, +function force_density_point!(storage::BACStorage, system::BondAssociatedSystem, + mat::BACMaterial, paramhandler::AbstractParameterHandler, t, Δt, i) params = get_params(paramhandler, i) force_density_point!(storage, system, mat, params, t, Δt, i) return nothing end -function force_density_point!(storage::BACCStorage, system::BondAssociatedSystem, - mat::BACCMaterial, params::BACCPointParameters, t, Δt, i) +function force_density_point!(storage::BACStorage, system::BondAssociatedSystem, + mat::BACMaterial, params::BACPointParameters, t, Δt, i) for bond_idx in each_bond_idx(system, i) force_density_bond!(storage, system, mat, params, t, Δt, i, bond_idx) end return nothing end -function force_density_bond!(storage::BACCStorage, system::BondAssociatedSystem, - mat::BACCMaterial, params::BACCPointParameters, t, Δt, i, +function force_density_bond!(storage::BACStorage, system::BondAssociatedSystem, + mat::BACMaterial, params::BACPointParameters, t, Δt, i, bond_idx) defgrad_res = calc_deformation_gradient(storage, system, mat, params, i, bond_idx) (; F) = defgrad_res @@ -194,13 +195,13 @@ function force_density_bond!(storage::BACCStorage, system::BondAssociatedSystem, end -@inline function influence_function(::BACCMaterial, params::BACCPointParameters, +@inline function influence_function(::BACMaterial, params::BACPointParameters, L::Float64) return params.δ / L end -function calc_deformation_gradient(storage::BACCStorage, system::BondAssociatedSystem, - mat::BACCMaterial, params::BACCPointParameters, i, +function calc_deformation_gradient(storage::BACStorage, system::BondAssociatedSystem, + mat::BACMaterial, params::BACPointParameters, i, bond_idx) (; bonds, volume) = system (; bond_active) = storage @@ -220,8 +221,8 @@ function calc_deformation_gradient(storage::BACCStorage, system::BondAssociatedS return (; F, Kinv) end -function calc_first_piola_kirchhoff!(storage::BACCStorage, mat::BACCMaterial, - params::BACCPointParameters, defgrad_res, Δt, i, +function calc_first_piola_kirchhoff!(storage::BACStorage, mat::BACMaterial, + params::BACPointParameters, defgrad_res, Δt, i, bond_idx) (; F, Kinv) = defgrad_res σ = cauchy_stress(mat.constitutive_model, storage, params, F) diff --git a/src/physics/bark_correspondence.jl b/src/physics/bark_correspondence.jl index a46a42d4..8e8f2e0b 100644 --- a/src/physics/bark_correspondence.jl +++ b/src/physics/bark_correspondence.jl @@ -1,5 +1,5 @@ """ - BARKCCMaterial(; maxdmg, zem) + BARKCMaterial(; maxdmg, zem) A material type used to assign the material of a [`Body`](@ref) with the local continuum consistent (correspondence) formulation of non-ordinary state-based peridynamics. @@ -21,14 +21,14 @@ consistent (correspondence) formulation of non-ordinary state-based peridynamics # Examples ```julia-repl -julia> mat = CCMaterial() -CCMaterial(maxdmg=0.95, zem_fac=ZEMSilling()) +julia> mat = CMaterial() +CMaterial(maxdmg=0.95, zem_fac=ZEMSilling()) ``` --- ```julia -CCMaterial +CMaterial ``` Material type for the local continuum consistent (correspondence) formulation of @@ -41,7 +41,7 @@ non-ordinary state-based peridynamics. constructor docs for more informations. # Allowed material parameters -When using [`material!`](@ref) on a [`Body`](@ref) with `CCMaterial`, then the following +When using [`material!`](@ref) on a [`Body`](@ref) with `CMaterial`, then the following parameters are allowed: - `horizon::Float64`: Radius of point interactions - `rho::Float64`: Density @@ -52,7 +52,7 @@ parameters are allowed: # Allowed export fields When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with -`CCMaterial`, the following fields are allowed: +`CMaterial`, the following fields are allowed: - `position::Matrix{Float64}`: Position of each point - `displacement::Matrix{Float64}`: Displacement of each point - `velocity::Matrix{Float64}`: Velocity of each point @@ -63,26 +63,26 @@ When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with - `damage::Vector{Float64}`: Damage of each point - `n_active_bonds::Vector{Int}`: Number of intact bonds of each point """ -struct BARKCCMaterial{CM} <: AbstractBondAssociatedSystemMaterial +struct BARKCMaterial{CM} <: AbstractBondAssociatedSystemMaterial constitutive_model::CM maxdmg::Float64 - function BARKCCMaterial(cm::CM, maxdmg::Real) where {CM} + function BARKCMaterial(cm::CM, maxdmg::Real) where {CM} return new{CM}(cm, maxdmg) end end -function Base.show(io::IO, @nospecialize(mat::BARKCCMaterial)) +function Base.show(io::IO, @nospecialize(mat::BARKCMaterial)) print(io, typeof(mat)) print(io, msg_fields_in_brackets(mat, (:maxdmg,))) return nothing end -function BARKCCMaterial(; model::AbstractConstitutiveModel=NeoHookeNonlinear(), +function BARKCMaterial(; model::AbstractConstitutiveModel=NeoHookeNonlinear(), maxdmg::Real=0.85) - return BARKCCMaterial(model, maxdmg) + return BARKCMaterial(model, maxdmg) end -struct BARKCCPointParameters <: AbstractPointParameters +struct BARKCPointParameters <: AbstractPointParameters δ::Float64 rho::Float64 E::Float64 @@ -96,16 +96,16 @@ struct BARKCCPointParameters <: AbstractPointParameters bc::Float64 end -function BARKCCPointParameters(mat::BARKCCMaterial, p::Dict{Symbol,Any}) +function BARKCPointParameters(mat::BARKCMaterial, p::Dict{Symbol,Any}) (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) (; Gc, εc) = get_frac_params(p, δ, K) bc = 18 * K / (π * δ^4) # bond constant - return BARKCCPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) + return BARKCPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) end -@params BARKCCMaterial BARKCCPointParameters +@params BARKCMaterial BARKCPointParameters -@storage BARKCCMaterial struct BARKCCStorage +@storage BARKCMaterial struct BARKCStorage @lthfield position::Matrix{Float64} @pointfield displacement::Matrix{Float64} @pointfield velocity::Matrix{Float64} @@ -124,22 +124,22 @@ end @lthfield defgrad::Matrix{Float64} end -function init_field(::BARKCCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, +function init_field(::BARKCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, ::Val{:b_int}) return zeros(3, get_n_points(system)) end -function init_field(::BARKCCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, +function init_field(::BARKCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, ::Val{:stress}) return zeros(9, get_n_loc_points(system)) end -function init_field(::BARKCCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, +function init_field(::BARKCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, ::Val{:von_mises_stress}) return zeros(get_n_loc_points(system)) end -function init_field(::BARKCCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, +function init_field(::BARKCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, ::Val{:defgrad}) return zeros(9, get_n_points(system)) end @@ -147,7 +147,7 @@ end # TODO: split the verlet timestep into 3 parts for threading, improve code reusability! function verlet_timestep!(dh::AbstractThreadsBodyDataHandler{Sys,M}, options::AbstractJobOptions, Δt::Float64, Δt½::Float64, - n::Int) where {Sys<:BondAssociatedSystem,M<:BARKCCMaterial} + n::Int) where {Sys<:BondAssociatedSystem,M<:BARKCMaterial} t = n * Δt @threads :static for chunk_id in eachindex(dh.chunks) chunk = dh.chunks[chunk_id] @@ -174,7 +174,7 @@ function verlet_timestep!(dh::AbstractThreadsBodyDataHandler{Sys,M}, end function calc_deformation_gradient!(chunk::AbstractBodyChunk{S,M}, t, - Δt) where {S<:BondAssociatedSystem,M<:BARKCCMaterial} + Δt) where {S<:BondAssociatedSystem,M<:BARKCMaterial} (; system, mat, paramsetup, storage) = chunk for i in each_point_idx(chunk) calc_deformation_gradient_point!(storage, system, mat, paramsetup, i) @@ -182,17 +182,17 @@ function calc_deformation_gradient!(chunk::AbstractBodyChunk{S,M}, t, return nothing end -function calc_deformation_gradient_point!(storage::BARKCCStorage, - system::BondAssociatedSystem, mat::BARKCCMaterial, +function calc_deformation_gradient_point!(storage::BARKCStorage, + system::BondAssociatedSystem, mat::BARKCMaterial, paramhandler::AbstractParameterHandler, i) params = get_params(paramhandler, i) calc_deformation_gradient_point!(storage, system, mat, params, i) return nothing end -function calc_deformation_gradient_point!(storage::BARKCCStorage, - system::BondAssociatedSystem, mat::BARKCCMaterial, - params::BARKCCPointParameters, i) +function calc_deformation_gradient_point!(storage::BARKCStorage, + system::BondAssociatedSystem, mat::BARKCMaterial, + params::BARKCPointParameters, i) (; bonds, volume) = system (; bond_active) = storage K = zero(SMatrix{3,3,Float64,9}) @@ -213,24 +213,24 @@ function calc_deformation_gradient_point!(storage::BARKCCStorage, return nothing end -function force_density_point!(storage::BARKCCStorage, system::BondAssociatedSystem, - mat::BARKCCMaterial, paramhandler::AbstractParameterHandler, +function force_density_point!(storage::BARKCStorage, system::BondAssociatedSystem, + mat::BARKCMaterial, paramhandler::AbstractParameterHandler, t, Δt, i) params = get_params(paramhandler, i) force_density_point!(storage, system, mat, params, t, Δt, i) return nothing end -function force_density_point!(storage::BARKCCStorage, system::BondAssociatedSystem, - mat::BARKCCMaterial, params::BARKCCPointParameters, t, Δt, i) +function force_density_point!(storage::BARKCStorage, system::BondAssociatedSystem, + mat::BARKCMaterial, params::BARKCPointParameters, t, Δt, i) for bond_idx in each_bond_idx(system, i) force_density_bond!(storage, system, mat, params, t, Δt, i, bond_idx) end return nothing end -function force_density_bond!(storage::BARKCCStorage, system::BondAssociatedSystem, - mat::BARKCCMaterial, params::BARKCCPointParameters, t, Δt, i, +function force_density_bond!(storage::BARKCStorage, system::BondAssociatedSystem, + mat::BARKCMaterial, params::BARKCPointParameters, t, Δt, i, bond_idx) Fb = calc_deformation_gradient(storage, system, mat, params, i, bond_idx) (; F) = defgrad_res @@ -258,13 +258,13 @@ function force_density_bond!(storage::BARKCCStorage, system::BondAssociatedSyste end -@inline function influence_function(::BARKCCMaterial, params::BARKCCPointParameters, +@inline function influence_function(::BARKCMaterial, params::BARKCPointParameters, L::Float64) return params.δ / L end -function calc_deformation_gradient(storage::BARKCCStorage, system::BondAssociatedSystem, - mat::BARKCCMaterial, params::BARKCCPointParameters, i, +function calc_deformation_gradient(storage::BARKCStorage, system::BondAssociatedSystem, + mat::BARKCMaterial, params::BARKCPointParameters, i, bond_idx) Fi = get_tensor(storage.defgrad, i) bond = system.bonds[bond_idx] @@ -278,8 +278,8 @@ function calc_deformation_gradient(storage::BARKCCStorage, system::BondAssociate return Fb end -function calc_first_piola_kirchhoff!(storage::BARKCCStorage, mat::BARKCCMaterial, - params::BARKCCPointParameters, defgrad_res, Δt, i, +function calc_first_piola_kirchhoff!(storage::BARKCStorage, mat::BARKCMaterial, + params::BARKCPointParameters, defgrad_res, Δt, i, bond_idx) (; F, Kinv) = defgrad_res σ = cauchy_stress(mat.constitutive_model, storage, params, F) diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index d5690fa9..b1224344 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -1,5 +1,5 @@ """ - CCMaterial(; maxdmg, zem) + CMaterial(; maxdmg, zem) A material type used to assign the material of a [`Body`](@ref) with the local continuum consistent (correspondence) formulation of non-ordinary state-based peridynamics. @@ -21,14 +21,14 @@ consistent (correspondence) formulation of non-ordinary state-based peridynamics # Examples ```julia-repl -julia> mat = CCMaterial() -CCMaterial(maxdmg=0.95, zem_fac=ZEMSilling()) +julia> mat = CMaterial() +CMaterial(maxdmg=0.95, zem_fac=ZEMSilling()) ``` --- ```julia -CCMaterial +CMaterial ``` Material type for the local continuum consistent (correspondence) formulation of @@ -41,7 +41,7 @@ non-ordinary state-based peridynamics. constructor docs for more informations. # Allowed material parameters -When using [`material!`](@ref) on a [`Body`](@ref) with `CCMaterial`, then the following +When using [`material!`](@ref) on a [`Body`](@ref) with `CMaterial`, then the following parameters are allowed: - `horizon::Float64`: Radius of point interactions - `rho::Float64`: Density @@ -52,7 +52,7 @@ parameters are allowed: # Allowed export fields When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with -`CCMaterial`, the following fields are allowed: +`CMaterial`, the following fields are allowed: - `position::Matrix{Float64}`: Position of each point - `displacement::Matrix{Float64}`: Displacement of each point - `velocity::Matrix{Float64}`: Velocity of each point @@ -63,27 +63,27 @@ When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with - `damage::Vector{Float64}`: Damage of each point - `n_active_bonds::Vector{Int}`: Number of intact bonds of each point """ -struct CCMaterial{CM,ZEM} <: AbstractCorrespondenceMaterial{CM,ZEM} +struct CMaterial{CM,ZEM} <: AbstractCorrespondenceMaterial{CM,ZEM} constitutive_model::CM zem_stabilization::ZEM maxdmg::Float64 - function CCMaterial(cm::CM, zem::ZEM, maxdmg::Real) where {CM,ZEM} + function CMaterial(cm::CM, zem::ZEM, maxdmg::Real) where {CM,ZEM} return new{CM,ZEM}(cm, zem, maxdmg) end end -function Base.show(io::IO, @nospecialize(mat::CCMaterial)) +function Base.show(io::IO, @nospecialize(mat::CMaterial)) print(io, typeof(mat)) print(io, msg_fields_in_brackets(mat, (:maxdmg,))) return nothing end -function CCMaterial(; model::AbstractConstitutiveModel=NeoHookeNonlinear(), +function CMaterial(; model::AbstractConstitutiveModel=NeoHookeNonlinear(), zem::AbstractZEMStabilization=ZEMSilling(), maxdmg::Real=0.85) - return CCMaterial(model, zem, maxdmg) + return CMaterial(model, zem, maxdmg) end -struct CCPointParameters <: AbstractPointParameters +struct CPointParameters <: AbstractPointParameters δ::Float64 rho::Float64 E::Float64 @@ -97,16 +97,16 @@ struct CCPointParameters <: AbstractPointParameters bc::Float64 end -function CCPointParameters(mat::CCMaterial, p::Dict{Symbol,Any}) +function CPointParameters(mat::CMaterial, p::Dict{Symbol,Any}) (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) (; Gc, εc) = get_frac_params(p, δ, K) bc = 18 * K / (π * δ^4) # bond constant - return CCPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) + return CPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) end -@params CCMaterial CCPointParameters +@params CMaterial CPointParameters -@storage CCMaterial struct CCStorage +@storage CMaterial struct CStorage @lthfield position::Matrix{Float64} @pointfield displacement::Matrix{Float64} @pointfield velocity::Matrix{Float64} @@ -124,28 +124,28 @@ end @pointfield von_mises_stress::Vector{Float64} end -function init_field(::CCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int}) +function init_field(::CMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int}) return zeros(3, get_n_points(system)) end -function init_field(::CCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:stress}) +function init_field(::CMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:stress}) return zeros(9, get_n_loc_points(system)) end -function init_field(::CCMaterial, ::AbstractTimeSolver, system::BondSystem, +function init_field(::CMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:von_mises_stress}) return zeros(get_n_loc_points(system)) end -function force_density_point!(storage::CCStorage, system::BondSystem, mat::CCMaterial, +function force_density_point!(storage::CStorage, system::BondSystem, mat::CMaterial, paramhandler::AbstractParameterHandler, t, Δt, i) params = get_params(paramhandler, i) force_density_point!(storage, system, mat, params, t, Δt, i) return nothing end -function force_density_point!(storage::CCStorage, system::BondSystem, mat::CCMaterial, - params::CCPointParameters, t, Δt, i) +function force_density_point!(storage::CStorage, system::BondSystem, mat::CMaterial, + params::CPointParameters, t, Δt, i) defgrad_res = calc_deformation_gradient(storage, system, mat, params, i) too_much_damage!(storage, system, mat, defgrad_res, i) && return nothing PKinv = calc_first_piola_kirchhoff!(storage, mat, params, defgrad_res, Δt, i) @@ -154,12 +154,12 @@ function force_density_point!(storage::CCStorage, system::BondSystem, mat::CCMat return nothing end -@inline function influence_function(::CCMaterial, params::CCPointParameters, L) +@inline function influence_function(::CMaterial, params::CPointParameters, L) return params.δ / L end -function calc_deformation_gradient(storage::CCStorage, system::BondSystem, - mat::CCMaterial, params::CCPointParameters, i) +function calc_deformation_gradient(storage::CStorage, system::BondSystem, + mat::CMaterial, params::CPointParameters, i) (; bonds, volume) = system (; bond_active) = storage K = zero(SMatrix{3,3,Float64,9}) @@ -181,8 +181,8 @@ function calc_deformation_gradient(storage::CCStorage, system::BondSystem, return (; F, Kinv, ω0) end -function calc_first_piola_kirchhoff!(storage::CCStorage, mat::CCMaterial, - params::CCPointParameters, defgrad_res, Δt, i) +function calc_first_piola_kirchhoff!(storage::CStorage, mat::CMaterial, + params::CPointParameters, defgrad_res, Δt, i) (; F, Kinv) = defgrad_res σ = cauchy_stress(mat.constitutive_model, storage, params, F) update_tensor!(storage.stress, i, σ) @@ -192,8 +192,8 @@ function calc_first_piola_kirchhoff!(storage::CCStorage, mat::CCMaterial, return PKinv end -function cc_force_density!(storage::CCStorage, system::BondSystem, mat::CCMaterial, - params::CCPointParameters, zem_correction::ZEMSilling, +function cc_force_density!(storage::CStorage, system::BondSystem, mat::CMaterial, + params::CPointParameters, zem_correction::ZEMSilling, PKinv::SMatrix, defgrad_res, i) (; bonds, volume) = system (; bond_active) = storage @@ -220,7 +220,7 @@ function cc_force_density!(storage::CCStorage, system::BondSystem, mat::CCMateri return nothing end -function too_much_damage!(storage::CCStorage, system::BondSystem, mat::CCMaterial, +function too_much_damage!(storage::CStorage, system::BondSystem, mat::CMaterial, defgrad_res, i) (; F) = defgrad_res if storage.damage[i] > mat.maxdmg || containsnan(F) diff --git a/test/auxiliary/test_io.jl b/test/auxiliary/test_io.jl index 6b11ba7c..d383c0ed 100644 --- a/test/auxiliary/test_io.jl +++ b/test/auxiliary/test_io.jl @@ -209,7 +209,7 @@ # setup bbb = Body(BBMaterial(), rand(3, 10), rand(10)) bosb = Body(OSBMaterial(), rand(3, 10), rand(10)) - bcc = Body(CCMaterial(), rand(3, 10), rand(10)) + bcc = Body(CMaterial(), rand(3, 10), rand(10)) ms = MultibodySetup(:a => bbb, :b => bosb, :c => bcc) vv = VelocityVerlet(steps=1) dr = DynamicRelaxation(steps=1) diff --git a/test/discretization/test_bond_associated_system.jl b/test/discretization/test_bond_associated_system.jl index 0834802f..5961f85f 100644 --- a/test/discretization/test_bond_associated_system.jl +++ b/test/discretization/test_bond_associated_system.jl @@ -4,7 +4,7 @@ 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0] volume = [1.1, 1.2, 1.3, 1.4] - mat = BACCMaterial() + mat = BACMaterial() body = Body(mat, position, volume) material!(body, horizon=2, rho=1, E=1, nu=0.25, Gc=1) pd = Peridynamics.PointDecomposition(body, 1) @@ -35,7 +35,7 @@ end @testitem "intersection bond ids" begin pos, vol = uniform_box(1, 0.25, 0.25, 0.25) - body = Body(BACCMaterial(), pos, vol) + body = Body(BACMaterial(), pos, vol) material!(body, horizon=0.5, rho=1, E=1, nu=0.25, Gc=1) pd = Peridynamics.PointDecomposition(body, 1) @@ -58,14 +58,14 @@ end @test bond_ids == [1:2, 3:5, 6:8, 9:10] @test intersection_bond_ids == [[2], [1], [], [3], [2], [2], [1], [], [2], [1]] - for i in Peridynamics.each_point_idx(system) - for bond_idx in Peridynamics.each_bond_idx(system, i) - # bond = bonds[bond_idx] - # j = bond.neighbor - for babond_idx in Peridynamics.each_intersecting_bond_idx(system, i, bond_idx) + # for i in Peridynamics.each_point_idx(system) + # for bond_idx in Peridynamics.each_bond_idx(system, i) + # # bond = bonds[bond_idx] + # # j = bond.neighbor + # for babond_idx in Peridynamics.each_intersecting_bond_idx(system, i, bond_idx) - end - end - end + # end + # end + # end end diff --git a/test/integration/b_int_correspondence.jl b/test/integration/b_int_correspondence.jl index 392626ec..b18f966b 100644 --- a/test/integration/b_int_correspondence.jl +++ b/test/integration/b_int_correspondence.jl @@ -4,7 +4,7 @@ 0.0 0.0 0.0 1.0 2.0] volume = fill(1.0, 5) δ = 1.5 - body = Body(CCMaterial(), ref_position, volume) + body = Body(CMaterial(), ref_position, volume) material!(body, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) failure_permit!(body, false) @@ -36,7 +36,7 @@ end 0.0 0.0 0.0 1.0 2.0] volume = fill(1.0, 5) δ = 1.5 - body = Body(CCMaterial(), ref_position, volume) + body = Body(CMaterial(), ref_position, volume) point_set!(body, :a, [1]) point_set!(body, :b, [2,3,4,5]) material!(body, :a, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) diff --git a/test/integration/mpi_threads_comparison.jl b/test/integration/mpi_threads_comparison.jl index a57fcf47..a8646f8a 100644 --- a/test/integration/mpi_threads_comparison.jl +++ b/test/integration/mpi_threads_comparison.jl @@ -199,7 +199,7 @@ end rm(root; recursive=true, force=true) end -@testitem "MPI-Threads comparison CCMaterial" begin +@testitem "MPI-Threads comparison CMaterial" begin root = joinpath(@__DIR__, "temp_mpi_threads_comparison_cc") path_threads = joinpath(root, "results_threads") path_threads_vtk = joinpath(path_threads, "vtk") @@ -210,7 +210,7 @@ end l, Δx, δ, a = 1.0, 1/N, 3.015/N, 0.5 pos, vol = uniform_box(l, l, 0.1l, Δx) ids = sortperm(pos[2,:]) - b = Body(CCMaterial(), pos[:, ids], vol[ids]) + b = Body(CMaterial(), pos[:, ids], vol[ids]) material!(b; horizon=3.015Δx, E=2.1e5, nu=0.25, rho=8e-6, Gc=2.7) point_set!(p -> p[1] ≤ -l/2+a && 0 ≤ p[2] ≤ 2δ, b, :set_a) point_set!(p -> p[1] ≤ -l/2+a && -2δ ≤ p[2] < 0, b, :set_b) @@ -232,7 +232,7 @@ end l, Δx, δ, a = 1.0, 1/N, 3.015/N, 0.5 pos, vol = uniform_box(l, l, 0.1l, Δx) ids = sortperm(pos[2,:]) - b = Body(CCMaterial(), pos[:, ids], vol[ids]) + b = Body(CMaterial(), pos[:, ids], vol[ids]) material!(b; horizon=3.015Δx, E=2.1e5, nu=0.25, rho=8e-6, Gc=2.7) point_set!(p -> p[1] ≤ -l/2+a && 0 ≤ p[2] ≤ 2δ, b, :set_a) point_set!(p -> p[1] ≤ -l/2+a && -2δ ≤ p[2] < 0, b, :set_b) diff --git a/test/integration/symmetry_correspondence.jl b/test/integration/symmetry_correspondence.jl index a141c658..5f0cffec 100644 --- a/test/integration/symmetry_correspondence.jl +++ b/test/integration/symmetry_correspondence.jl @@ -1,4 +1,4 @@ -@testitem "symmetry CCMaterial VelocityVerlet" begin +@testitem "symmetry CMaterial VelocityVerlet" begin # simulation Δx = 0.2 width = 1 @@ -8,7 +8,7 @@ pos = hcat(([x;y;z] for x in grid for y in grid for z in grid)...) n_points = size(pos, 2) vol = fill(Δx^3, n_points) - body = Body(CCMaterial(), pos, vol) + body = Body(CMaterial(), pos, vol) failure_permit!(body, false) material!(body, horizon=3.015Δx, rho=7850, E=210e9, nu=0.25, Gc=1) point_set!(z -> z > width/2 - 0.6Δx, body, :set_a) @@ -57,7 +57,7 @@ rm(temp_root; recursive=true, force=true) end -@testitem "symmetry CCMaterial DynamicRelaxation" begin +@testitem "symmetry CMaterial DynamicRelaxation" begin # simulation Δx = 0.2 width = 1 @@ -67,7 +67,7 @@ end pos = hcat(([x;y;z] for x in grid for y in grid for z in grid)...) n_points = size(pos, 2) vol = fill(Δx^3, n_points) - body = Body(CCMaterial(), pos, vol) + body = Body(CMaterial(), pos, vol) failure_permit!(body, false) material!(body, horizon=3.015Δx, rho=7850, E=210e9, nu=0.25, Gc=1) point_set!(z -> z > width/2 - 0.6Δx, body, :set_a) From 6ec797958b132e5f819e5f965f5320f44eaef514 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Thu, 7 Nov 2024 15:46:13 +0100 Subject: [PATCH 17/40] Remove `bark_correspondence` --- src/Peridynamics.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index 21b31d00..295b18f8 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -128,7 +128,6 @@ include("physics/ordinary_state_based.jl") include("physics/constitutive_models.jl") include("physics/correspondence.jl") include("physics/ba_correspondence.jl") -include("physics/bark_correspondence.jl") include("VtkReader/VtkReader.jl") using .VtkReader From dc2809d6c4f6830a5818ce11b97a57ea4ea305d0 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Thu, 7 Nov 2024 15:47:01 +0100 Subject: [PATCH 18/40] Make bond horizon a point parameter --- src/discretization/bond_associated_system.jl | 26 ++++++++++++++----- src/physics/ba_correspondence.jl | 6 ++--- .../test_bond_associated_system.jl | 5 ++-- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/discretization/bond_associated_system.jl b/src/discretization/bond_associated_system.jl index 58737df1..b3a93b1a 100644 --- a/src/discretization/bond_associated_system.jl +++ b/src/discretization/bond_associated_system.jl @@ -50,8 +50,8 @@ end function find_intersection_bond_ids(body, loc_points, bonds, bond_ids) intersection_bond_ids = Vector{Vector{Int}}(undef, length(bonds)) for (li, i) in enumerate(loc_points) - δ = 1.01 * get_point_param(body, :δ, i) - δ² = δ * δ + δb = get_point_param(body, :δb, i) + δb² = δb * δb bond_ids_of_i = bond_ids[li] for bond_id in bond_ids_of_i bond = bonds[bond_id] @@ -64,7 +64,7 @@ function find_intersection_bond_ids(body, loc_points, bonds, bond_ids) Xjj = get_coordinates(body, jj) ΔX = Xj - Xjj L² = dot(ΔX, ΔX) - if L² < δ² + if L² < δb² push!(intersecting_bonds, ibond_id) end end @@ -169,14 +169,28 @@ function req_data_fields_fracture(::Type{<:AbstractBondAssociatedSystemMaterial} end function required_point_parameters(::Type{<:AbstractBondAssociatedSystemMaterial}) - return (:δ, :rho, elasticity_parameters()...) + return (:δ, :δb, :rho, elasticity_parameters()...) end function get_required_point_parameters(::AbstractBondAssociatedSystemMaterial, p::Dict{Symbol,Any}) - return (; get_horizon(p)..., get_density(p)..., get_elastic_params(p)...) + δ_params = get_horizon(p) + δb_params = get_bond_horizon(p, δ_params.δ) + return (; δ_params..., δb_params..., get_density(p)..., get_elastic_params(p)...) +end + +function get_bond_horizon(p::Dict{Symbol,Any}, δ::Float64) + δb::Float64 = float(get(p, :bond_horizon, δ)) + if δb ≤ 0 + throw(ArgumentError("`bond_horizon` should be larger than zero!\n")) + end + if δb < δ + @warn "a small bond horizon < δ will possibly lead to numerical instabilities!" + end + return (; δb) end function allowed_material_kwargs(::AbstractBondAssociatedSystemMaterial) - return (discretization_kwargs()..., elasticity_kwargs()..., fracture_kwargs()...) + return (discretization_kwargs()..., elasticity_kwargs()..., fracture_kwargs()..., + :bond_horizon) end diff --git a/src/physics/ba_correspondence.jl b/src/physics/ba_correspondence.jl index 27b593be..d8a7b293 100644 --- a/src/physics/ba_correspondence.jl +++ b/src/physics/ba_correspondence.jl @@ -84,6 +84,7 @@ end struct BACPointParameters <: AbstractPointParameters δ::Float64 + δb::Float64 rho::Float64 E::Float64 nu::Float64 @@ -97,13 +98,12 @@ struct BACPointParameters <: AbstractPointParameters end function BACPointParameters(mat::BACMaterial, p::Dict{Symbol,Any}) - (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) + (; δ, δb, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) (; Gc, εc) = get_frac_params(p, δ, K) bc = 18 * K / (π * δ^4) # bond constant - return BACPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) + return BACPointParameters(δ, δb, rho, E, nu, G, K, λ, μ, Gc, εc, bc) end - @params BACMaterial BACPointParameters @storage BACMaterial struct BACStorage diff --git a/test/discretization/test_bond_associated_system.jl b/test/discretization/test_bond_associated_system.jl index 5961f85f..d734146b 100644 --- a/test/discretization/test_bond_associated_system.jl +++ b/test/discretization/test_bond_associated_system.jl @@ -36,7 +36,7 @@ end @testitem "intersection bond ids" begin pos, vol = uniform_box(1, 0.25, 0.25, 0.25) body = Body(BACMaterial(), pos, vol) - material!(body, horizon=0.5, rho=1, E=1, nu=0.25, Gc=1) + material!(body, horizon=0.5, bond_horizon=0.5, rho=1, E=1, nu=0.25, Gc=1) pd = Peridynamics.PointDecomposition(body, 1) @@ -56,7 +56,8 @@ end Peridynamics.Bond(3, 0.25, true) ] @test bond_ids == [1:2, 3:5, 6:8, 9:10] - @test intersection_bond_ids == [[2], [1], [], [3], [2], [2], [1], [], [2], [1]] + i_bond_ids = [[1, 2], [1, 2], [1], [2, 3], [2, 3], [1, 2], [1, 2], [3], [1, 2], [1, 2]] + @test intersection_bond_ids == i_bond_ids # for i in Peridynamics.each_point_idx(system) # for bond_idx in Peridynamics.each_bond_idx(system, i) From fb75d89f9e87d4f33c31acb5b8183faf40ea58d6 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Thu, 7 Nov 2024 15:50:52 +0100 Subject: [PATCH 19/40] Minor cleanup --- src/physics/ba_correspondence.jl | 12 ------------ src/physics/correspondence.jl | 4 ++-- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/physics/ba_correspondence.jl b/src/physics/ba_correspondence.jl index d8a7b293..c96c978c 100644 --- a/src/physics/ba_correspondence.jl +++ b/src/physics/ba_correspondence.jl @@ -139,17 +139,6 @@ function init_field(::BACMaterial, ::AbstractTimeSolver, system::BondAssociatedS return zeros(get_n_loc_points(system)) end -# function calc_force_density!(chunk::AbstractBodyChunk{S,M}, -# Δt::Float64) where {S<:BondAssociatedSystem,M<:BANOSBMaterial} -# (; system, mat, paramsetup, storage) = chunk -# storage.b_int .= 0 -# storage.n_active_bonds .= 0 -# for point_id in each_point_idx(chunk) -# force_density_point!(storage, system, mat, paramsetup, Δt, point_id) -# end -# return nothing -# end - function force_density_point!(storage::BACStorage, system::BondAssociatedSystem, mat::BACMaterial, paramhandler::AbstractParameterHandler, t, Δt, i) @@ -188,7 +177,6 @@ function force_density_bond!(storage::BACStorage, system::BondAssociatedSystem, ωij = influence_function(mat, params, L) * storage.bond_active[bond_idx] ϕi = volume_fraction_factor(system, i, bond_idx) tij = ϕi * ωij * PKinv * ΔXij - # tij = ωij * PKinv * ΔXij update_add_b_int!(storage, i, tij .* system.volume[j]) update_add_b_int!(storage, j, -tij .* system.volume[i]) return nothing diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index b1224344..ffea9431 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -150,7 +150,7 @@ function force_density_point!(storage::CStorage, system::BondSystem, mat::CMater too_much_damage!(storage, system, mat, defgrad_res, i) && return nothing PKinv = calc_first_piola_kirchhoff!(storage, mat, params, defgrad_res, Δt, i) zem = mat.zem_stabilization - cc_force_density!(storage, system, mat, params, zem, PKinv, defgrad_res, i) + c_force_density!(storage, system, mat, params, zem, PKinv, defgrad_res, i) return nothing end @@ -192,7 +192,7 @@ function calc_first_piola_kirchhoff!(storage::CStorage, mat::CMaterial, return PKinv end -function cc_force_density!(storage::CStorage, system::BondSystem, mat::CMaterial, +function c_force_density!(storage::CStorage, system::BondSystem, mat::CMaterial, params::CPointParameters, zem_correction::ZEMSilling, PKinv::SMatrix, defgrad_res, i) (; bonds, volume) = system From 1fc187514405392dd609c5fc1ea4712c1d06d411 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Thu, 7 Nov 2024 15:51:42 +0100 Subject: [PATCH 20/40] Remove `bark_correspondence` --- src/physics/bark_correspondence.jl | 291 ----------------------------- 1 file changed, 291 deletions(-) delete mode 100644 src/physics/bark_correspondence.jl diff --git a/src/physics/bark_correspondence.jl b/src/physics/bark_correspondence.jl deleted file mode 100644 index 8e8f2e0b..00000000 --- a/src/physics/bark_correspondence.jl +++ /dev/null @@ -1,291 +0,0 @@ -""" - BARKCMaterial(; maxdmg, zem) - -A material type used to assign the material of a [`Body`](@ref) with the local continuum -consistent (correspondence) formulation of non-ordinary state-based peridynamics. - -# Keywords -- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is - exceeded, all bonds of that point are broken because the deformation gradient would then - possibly contain `NaN` values. - (default: `0.95`) -- `zem::AbstractZEMStabilization`: zero-energy mode stabilization. The - stabilization algorithm of Silling (2017) is used as default. - (default: `ZEMSilling()`) - -!!! note "Stability of fracture simulations" - This formulation is known to be not suitable for fracture simultations without - stabilization of the zero-energy modes. Therefore be careful when doing fracture - simulations and try out different parameters for `maxdmg` and `zem`. - -# Examples - -```julia-repl -julia> mat = CMaterial() -CMaterial(maxdmg=0.95, zem_fac=ZEMSilling()) -``` - ---- - -```julia -CMaterial -``` - -Material type for the local continuum consistent (correspondence) formulation of -non-ordinary state-based peridynamics. - -# Fields -- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. See the - constructor docs for more informations. -- `zem_fac::Float64`: Correction factor used for zero-energy mode stabilization. See the - constructor docs for more informations. - -# Allowed material parameters -When using [`material!`](@ref) on a [`Body`](@ref) with `CMaterial`, then the following -parameters are allowed: -- `horizon::Float64`: Radius of point interactions -- `rho::Float64`: Density -- `E::Float64`: Young's modulus -- `nu::Float64`: Poisson's ratio -- `Gc::Float64`: Critical energy release rate -- `epsilon_c::Float64`: Critical strain - -# Allowed export fields -When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with -`CMaterial`, the following fields are allowed: -- `position::Matrix{Float64}`: Position of each point -- `displacement::Matrix{Float64}`: Displacement of each point -- `velocity::Matrix{Float64}`: Velocity of each point -- `velocity_half::Matrix{Float64}`: Velocity parameter for Verlet time solver -- `acceleration::Matrix{Float64}`: Acceleration of each point -- `b_int::Matrix{Float64}`: Internal force density of each point -- `b_ext::Matrix{Float64}`: External force density of each point -- `damage::Vector{Float64}`: Damage of each point -- `n_active_bonds::Vector{Int}`: Number of intact bonds of each point -""" -struct BARKCMaterial{CM} <: AbstractBondAssociatedSystemMaterial - constitutive_model::CM - maxdmg::Float64 - function BARKCMaterial(cm::CM, maxdmg::Real) where {CM} - return new{CM}(cm, maxdmg) - end -end - -function Base.show(io::IO, @nospecialize(mat::BARKCMaterial)) - print(io, typeof(mat)) - print(io, msg_fields_in_brackets(mat, (:maxdmg,))) - return nothing -end - -function BARKCMaterial(; model::AbstractConstitutiveModel=NeoHookeNonlinear(), - maxdmg::Real=0.85) - return BARKCMaterial(model, maxdmg) -end - -struct BARKCPointParameters <: AbstractPointParameters - δ::Float64 - rho::Float64 - E::Float64 - nu::Float64 - G::Float64 - K::Float64 - λ::Float64 - μ::Float64 - Gc::Float64 - εc::Float64 - bc::Float64 -end - -function BARKCPointParameters(mat::BARKCMaterial, p::Dict{Symbol,Any}) - (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) - (; Gc, εc) = get_frac_params(p, δ, K) - bc = 18 * K / (π * δ^4) # bond constant - return BARKCPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) -end - -@params BARKCMaterial BARKCPointParameters - -@storage BARKCMaterial struct BARKCStorage - @lthfield position::Matrix{Float64} - @pointfield displacement::Matrix{Float64} - @pointfield velocity::Matrix{Float64} - @pointfield velocity_half::Matrix{Float64} - @pointfield velocity_half_old::Matrix{Float64} - @pointfield acceleration::Matrix{Float64} - @htlfield b_int::Matrix{Float64} - @pointfield b_int_old::Matrix{Float64} - @pointfield b_ext::Matrix{Float64} - @pointfield density_matrix::Matrix{Float64} - @pointfield damage::Vector{Float64} - bond_active::Vector{Bool} - @pointfield n_active_bonds::Vector{Int} - @pointfield stress::Matrix{Float64} - @pointfield von_mises_stress::Vector{Float64} - @lthfield defgrad::Matrix{Float64} -end - -function init_field(::BARKCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, - ::Val{:b_int}) - return zeros(3, get_n_points(system)) -end - -function init_field(::BARKCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, - ::Val{:stress}) - return zeros(9, get_n_loc_points(system)) -end - -function init_field(::BARKCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, - ::Val{:von_mises_stress}) - return zeros(get_n_loc_points(system)) -end - -function init_field(::BARKCMaterial, ::AbstractTimeSolver, system::BondAssociatedSystem, - ::Val{:defgrad}) - return zeros(9, get_n_points(system)) -end - -# TODO: split the verlet timestep into 3 parts for threading, improve code reusability! -function verlet_timestep!(dh::AbstractThreadsBodyDataHandler{Sys,M}, - options::AbstractJobOptions, Δt::Float64, Δt½::Float64, - n::Int) where {Sys<:BondAssociatedSystem,M<:BARKCMaterial} - t = n * Δt - @threads :static for chunk_id in eachindex(dh.chunks) - chunk = dh.chunks[chunk_id] - update_vel_half!(chunk, Δt½) - apply_boundary_conditions!(chunk, t) - update_disp_and_pos!(chunk, Δt) - end - @threads :static for chunk_id in eachindex(dh.chunks) - exchange_loc_to_halo!(dh, chunk_id, (:position,)) - calc_deformation_gradient!(dh.chunks[chunk_id], t, Δt) - end - @threads :static for chunk_id in eachindex(dh.chunks) - exchange_loc_to_halo!(dh, chunk_id, (:defgrad,)) - calc_force_density!(dh.chunks[chunk_id], t, Δt) - end - @threads :static for chunk_id in eachindex(dh.chunks) - exchange_halo_to_loc!(dh, chunk_id) - chunk = dh.chunks[chunk_id] - calc_damage!(chunk) - update_acc_and_vel!(chunk, Δt½) - export_results(dh, options, chunk_id, n, t) - end - return nothing -end - -function calc_deformation_gradient!(chunk::AbstractBodyChunk{S,M}, t, - Δt) where {S<:BondAssociatedSystem,M<:BARKCMaterial} - (; system, mat, paramsetup, storage) = chunk - for i in each_point_idx(chunk) - calc_deformation_gradient_point!(storage, system, mat, paramsetup, i) - end - return nothing -end - -function calc_deformation_gradient_point!(storage::BARKCStorage, - system::BondAssociatedSystem, mat::BARKCMaterial, - paramhandler::AbstractParameterHandler, i) - params = get_params(paramhandler, i) - calc_deformation_gradient_point!(storage, system, mat, params, i) - return nothing -end - -function calc_deformation_gradient_point!(storage::BARKCStorage, - system::BondAssociatedSystem, mat::BARKCMaterial, - params::BARKCPointParameters, i) - (; bonds, volume) = system - (; bond_active) = storage - K = zero(SMatrix{3,3,Float64,9}) - _F = zero(SMatrix{3,3,Float64,9}) - for bond_id in each_bond_idx(system, i) - bond = bonds[bond_id] - j, L = bond.neighbor, bond.length - ΔXij = get_diff(system.position, i, j) - Δxij = get_diff(storage.position, i, j) - ωij = influence_function(mat, params, L) * bond_active[bond_id] - temp = ωij * volume[j] - K += temp * (ΔXij * ΔXij') - _F += temp * (Δxij * ΔXij') - end - Kinv = inv(K) - F = _F * Kinv - update_tensor!(storage.defgrad, i, F) - return nothing -end - -function force_density_point!(storage::BARKCStorage, system::BondAssociatedSystem, - mat::BARKCMaterial, paramhandler::AbstractParameterHandler, - t, Δt, i) - params = get_params(paramhandler, i) - force_density_point!(storage, system, mat, params, t, Δt, i) - return nothing -end - -function force_density_point!(storage::BARKCStorage, system::BondAssociatedSystem, - mat::BARKCMaterial, params::BARKCPointParameters, t, Δt, i) - for bond_idx in each_bond_idx(system, i) - force_density_bond!(storage, system, mat, params, t, Δt, i, bond_idx) - end - return nothing -end - -function force_density_bond!(storage::BARKCStorage, system::BondAssociatedSystem, - mat::BARKCMaterial, params::BARKCPointParameters, t, Δt, i, - bond_idx) - Fb = calc_deformation_gradient(storage, system, mat, params, i, bond_idx) - (; F) = defgrad_res - if containsnan(F) || storage.damage[i] > mat.maxdmg - storage.bond_active[bond_idx] = false - return nothing - end - PKinv = calc_first_piola_kirchhoff!(storage, mat, params, defgrad_res, Δt, i, bond_idx) - - bond = system.bonds[bond_idx] - j, L = bond.neighbor, bond.length - ΔXij = get_coordinates_diff(system, i, j) - Δxij = get_coordinates_diff(storage, i, j) - l = norm(Δxij) - ε = (l - L) / L - stretch_based_failure!(storage, system, bond, params, ε, i, bond_idx) - - ωij = influence_function(mat, params, L) * storage.bond_active[bond_idx] - ϕi = volume_fraction_factor(system, i, bond_idx) - tij = ϕi * ωij * PKinv * ΔXij - # tij = ωij * PKinv * ΔXij - update_add_b_int!(storage, i, tij .* system.volume[j]) - update_add_b_int!(storage, j, -tij .* system.volume[i]) - return nothing -end - - -@inline function influence_function(::BARKCMaterial, params::BARKCPointParameters, - L::Float64) - return params.δ / L -end - -function calc_deformation_gradient(storage::BARKCStorage, system::BondAssociatedSystem, - mat::BARKCMaterial, params::BARKCPointParameters, i, - bond_idx) - Fi = get_tensor(storage.defgrad, i) - bond = system.bonds[bond_idx] - j, L = bond.neighbor, bond.length - Fj = get_tensor(storage.defgrad, j) - F̂ = (Fi + Fj) ./ 2 - ΔXij = get_coordinates_diff(system, i, j) - Δxij = get_coordinates_diff(storage, i, j) - ΔFij = (Δxij - F̂ * ΔXij) * ΔXij' ./ (L * L) - Fb = Fj + ΔFij - return Fb -end - -function calc_first_piola_kirchhoff!(storage::BARKCStorage, mat::BARKCMaterial, - params::BARKCPointParameters, defgrad_res, Δt, i, - bond_idx) - (; F, Kinv) = defgrad_res - σ = cauchy_stress(mat.constitutive_model, storage, params, F) - # update_tensor!(storage.stress, i, σ) - # storage.von_mises_stress[i] = von_mises_stress(σ) - P = det(F) * σ * inv(F)' - PKinv = P * Kinv - return PKinv -end From 2f02032b271c81ad5d7e6456efc9cf8f80bc90d9 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Fri, 8 Nov 2024 12:34:08 +0100 Subject: [PATCH 21/40] Remove undefined export --- src/Peridynamics.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index 295b18f8..d2327d85 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -9,7 +9,7 @@ end import LibGit2, Dates # Material models -export BBMaterial, OSBMaterial, CMaterial, BACMaterial, BARKCMaterial, CKIMaterial +export BBMaterial, OSBMaterial, CMaterial, BACMaterial, CKIMaterial # CMaterial related types export NeoHookeNonlinear, SaintVenantKirchhoff, ZEMSilling From d6441956a53cfb5284e28d8f23f2b84c955ad072 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Fri, 8 Nov 2024 13:33:29 +0100 Subject: [PATCH 22/40] Exchange now part of force density calculation --- src/core/mpi_body_data_handler.jl | 8 +++ src/core/threads_body_data_handler.jl | 11 ++++ src/core/threads_multibody_data_handler.jl | 11 ++++ src/time_solvers/dynamic_relaxation.jl | 27 ++++++-- src/time_solvers/velocity_verlet.jl | 17 ++--- test/integration/mpi_threads_comparison.jl | 74 ++++++++++++++++++++++ 6 files changed, 128 insertions(+), 20 deletions(-) diff --git a/src/core/mpi_body_data_handler.jl b/src/core/mpi_body_data_handler.jl index a9c025cb..5c532407 100644 --- a/src/core/mpi_body_data_handler.jl +++ b/src/core/mpi_body_data_handler.jl @@ -341,6 +341,14 @@ function recv_htl!(get_field_function::F, dh::MPIBodyDataHandler, return nothing end +function calc_force_density!(dh::MPIBodyDataHandler, Δt, t) + (; chunk) = dh + @timeit_debug TO "exchange_loc_to_halo!" exchange_loc_to_halo!(dh) + @timeit_debug TO "calc_force_density!" calc_force_density!(chunk, t, Δt) + @timeit_debug TO "exchange_halo_to_loc!" exchange_halo_to_loc!(dh) + return nothing +end + function export_results(dh::MPIBodyDataHandler, options::AbstractJobOptions, n::Int, t::Float64) options.export_allowed || return nothing diff --git a/src/core/threads_body_data_handler.jl b/src/core/threads_body_data_handler.jl index 3f63c099..71b1ca66 100644 --- a/src/core/threads_body_data_handler.jl +++ b/src/core/threads_body_data_handler.jl @@ -157,6 +157,17 @@ function exchange_halo_to_loc!(get_field_function::F, dh::ThreadsBodyDataHandler return nothing end +function calc_force_density!(dh::ThreadsBodyDataHandler, Δt, t) + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_loc_to_halo!(dh, chunk_id) + calc_force_density!(dh.chunks[chunk_id], t, Δt) + end + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_halo_to_loc!(dh, chunk_id) + end + return nothing +end + function export_results(dh::ThreadsBodyDataHandler, options::AbstractJobOptions, chunk_id::Int, timestep::Int, time::Float64) options.export_allowed || return nothing diff --git a/src/core/threads_multibody_data_handler.jl b/src/core/threads_multibody_data_handler.jl index e7e1d425..9df0c623 100644 --- a/src/core/threads_multibody_data_handler.jl +++ b/src/core/threads_multibody_data_handler.jl @@ -33,6 +33,17 @@ end @inline each_body_name(dh::ThreadsMultibodyDataHandler) = dh.body_names @inline each_body_idx(dh::ThreadsMultibodyDataHandler) = eachindex(dh.body_dhs) +function calc_force_density!(dh::ThreadsMultibodyDataHandler, Δt, t) + for body_idx in each_body_idx(dh) + body_dh = get_body_dh(dh, body_idx) + @threads :static for chunk_id in eachindex(body_dh.chunks) + exchange_loc_to_halo!(body_dh, chunk_id) + calc_force_density!(body_dh.chunks[chunk_id], t, Δt) + end + end + return nothing +end + function update_caches!(dh::ThreadsMultibodyDataHandler) for body_idx in each_body_idx(dh) body_dh = get_body_dh(dh, body_idx) diff --git a/src/time_solvers/dynamic_relaxation.jl b/src/time_solvers/dynamic_relaxation.jl index d450b334..ed792e24 100644 --- a/src/time_solvers/dynamic_relaxation.jl +++ b/src/time_solvers/dynamic_relaxation.jl @@ -165,20 +165,15 @@ end end function relaxation_timestep!(dh::AbstractThreadsBodyDataHandler, - options::AbstractJobOptions, - Δt::Float64, n::Int) + options::AbstractJobOptions, Δt, n) t = n * Δt @threads :static for chunk_id in eachindex(dh.chunks) chunk = dh.chunks[chunk_id] apply_boundary_conditions!(chunk, t) update_disp_and_pos!(chunk, Δt) end + calc_force_density!(dh, Δt, t) @threads :static for chunk_id in eachindex(dh.chunks) - exchange_loc_to_halo!(dh, chunk_id) - calc_force_density!(dh.chunks[chunk_id], t, Δt) - end - @threads :static for chunk_id in eachindex(dh.chunks) - exchange_halo_to_loc!(dh, chunk_id) chunk = dh.chunks[chunk_id] calc_damage!(chunk) cn = calc_damping(chunk, Δt) @@ -192,6 +187,24 @@ function relaxation_timestep!(dh::AbstractThreadsBodyDataHandler, return nothing end +function relaxation_timestep!(dh::AbstractMPIBodyDataHandler, + options::AbstractJobOptions, Δt, n) + t = n * Δt + (; chunk) = dh + @timeit_debug TO "apply_boundary_conditions!" apply_boundary_conditions!(chunk, t) + @timeit_debug TO "update_disp_and_pos!" update_disp_and_pos!(chunk, Δt) + calc_force_density!(dh, Δt, t) + @timeit_debug TO "calc_damage!" calc_damage!(chunk) + @timeit_debug TO "relaxation_step!" if n == 1 + relaxation_first_step!(chunk, Δt) + else + cn = calc_damping(chunk, Δt) + relaxation_step!(chunk, Δt, cn) + end + @timeit_debug TO "export_results" export_results(dh, options, chunk_id, n, t) + return nothing +end + function calc_damping(chunk::AbstractBodyChunk, Δt::Float64) s = chunk.storage cn1 = 0.0 diff --git a/src/time_solvers/velocity_verlet.jl b/src/time_solvers/velocity_verlet.jl index f7521cdb..6eaae2ce 100644 --- a/src/time_solvers/velocity_verlet.jl +++ b/src/time_solvers/velocity_verlet.jl @@ -187,12 +187,8 @@ function verlet_timestep!(dh::AbstractThreadsBodyDataHandler, options::AbstractJ apply_boundary_conditions!(chunk, t) update_disp_and_pos!(chunk, Δt) end + calc_force_density!(dh, t, Δt) @threads :static for chunk_id in eachindex(dh.chunks) - exchange_loc_to_halo!(dh, chunk_id) - calc_force_density!(dh.chunks[chunk_id], t, Δt) - end - @threads :static for chunk_id in eachindex(dh.chunks) - exchange_halo_to_loc!(dh, chunk_id) chunk = dh.chunks[chunk_id] calc_damage!(chunk) update_acc_and_vel!(chunk, Δt½) @@ -202,7 +198,7 @@ function verlet_timestep!(dh::AbstractThreadsBodyDataHandler, options::AbstractJ end function verlet_timestep!(dh::AbstractThreadsMultibodyDataHandler, - options::AbstractJobOptions, Δt::Float64, Δt½::Float64, n::Int) + options::AbstractJobOptions, Δt, Δt½, n) t = n * Δt for body_idx in each_body_idx(dh) body_dh = get_body_dh(dh, body_idx) @@ -212,11 +208,8 @@ function verlet_timestep!(dh::AbstractThreadsMultibodyDataHandler, apply_boundary_conditions!(chunk, t) update_disp_and_pos!(chunk, Δt) end - @threads :static for chunk_id in eachindex(body_dh.chunks) - exchange_loc_to_halo!(body_dh, chunk_id) - calc_force_density!(body_dh.chunks[chunk_id], t, Δt) - end end + calc_force_density!(dh, Δt, t) update_caches!(dh) calc_contact_force_densities!(dh) for body_idx in each_body_idx(dh) @@ -240,9 +233,7 @@ function verlet_timestep!(dh::AbstractMPIBodyDataHandler, options::AbstractJobOp @timeit_debug TO "update_vel_half!" update_vel_half!(chunk, Δt½) @timeit_debug TO "apply_boundary_conditions!" apply_boundary_conditions!(chunk, t) @timeit_debug TO "update_disp_and_pos!" update_disp_and_pos!(chunk, Δt) - @timeit_debug TO "exchange_loc_to_halo!" exchange_loc_to_halo!(dh) - @timeit_debug TO "calc_force_density!" calc_force_density!(chunk, t, Δt) - @timeit_debug TO "exchange_halo_to_loc!" exchange_halo_to_loc!(dh) + calc_force_density!(dh, Δt, t) @timeit_debug TO "calc_damage!" calc_damage!(chunk) @timeit_debug TO "update_acc_and_vel!" update_acc_and_vel!(chunk, Δt½) @timeit_debug TO "export_results" export_results(dh, options, n, t) diff --git a/test/integration/mpi_threads_comparison.jl b/test/integration/mpi_threads_comparison.jl index a8646f8a..4e670842 100644 --- a/test/integration/mpi_threads_comparison.jl +++ b/test/integration/mpi_threads_comparison.jl @@ -65,6 +65,80 @@ rm(root; recursive=true, force=true) end +@testitem "MPI-Threads comparison BBMaterial{NoCorrection} DynamicRelaxation" begin + root = joinpath(@__DIR__, "temp_mpi_threads_comparison_bbncdr") + path_threads = joinpath(root, "results_threads") + path_threads_vtk = joinpath(path_threads, "vtk") + path_mpi = joinpath(root, "results_mpi") + path_mpi_vtk = joinpath(path_mpi, "vtk") + + function sim_bb(N::Int, path::String) + l, Δx, δ, a = 100.0, 100.0/N, 3.015/N, 50.0 + pos, vol = uniform_box(l, l, 0.1l, Δx) + ids = sortperm(pos[2,:]) + body = Body(BBMaterial(), pos[:, ids], vol[ids]) + failure_permit!(body, false) + material!(body; horizon=3.015Δx, E=2.1e5, rho=8e-6, Gc=2.7) + point_set!(p -> p[1] ≤ -l/2+a && 0 ≤ p[2] ≤ 2δ, body, :set_a) + point_set!(p -> p[1] ≤ -l/2+a && -2δ ≤ p[2] < 0, body, :set_b) + precrack!(body, :set_a, :set_b) + point_set!(p -> p[2] > l/2-Δx, body, :set_top) + point_set!(p -> p[2] < -l/2+Δx, body, :set_bottom) + forcedensity_bc!(t -> -1e3, body, :set_bottom, :y) + forcedensity_bc!(t -> 1e3, body, :set_top, :y) + solver = DynamicRelaxation(steps=200, damping_factor=0.05) + job = Job(body, solver; path=path, freq=200) + submit(job) + return nothing + end + sim_bb(30, path_threads) + + mpi_cmd = """ + using Peridynamics + function sim_bb(N::Int, path::String) + l, Δx, δ, a = 100.0, 100.0/N, 3.015/N, 50.0 + pos, vol = uniform_box(l, l, 0.1l, Δx) + ids = sortperm(pos[2,:]) + body = Body(BBMaterial(), pos[:, ids], vol[ids]) + failure_permit!(body, false) + material!(body; horizon=3.015Δx, E=2.1e5, rho=8e-6, Gc=2.7) + point_set!(p -> p[1] ≤ -l/2+a && 0 ≤ p[2] ≤ 2δ, body, :set_a) + point_set!(p -> p[1] ≤ -l/2+a && -2δ ≤ p[2] < 0, body, :set_b) + precrack!(body, :set_a, :set_b) + point_set!(p -> p[2] > l/2-Δx, body, :set_top) + point_set!(p -> p[2] < -l/2+Δx, body, :set_bottom) + forcedensity_bc!(t -> -1e3, body, :set_bottom, :y) + forcedensity_bc!(t -> 1e3, body, :set_top, :y) + solver = DynamicRelaxation(steps=200, damping_factor=0.05) + job = Job(body, solver; path=path, freq=200) + submit(job) + return nothing + end + sim_bb(30, "$path_mpi") + """ + run(`$(Peridynamics.MPI.mpiexec()) -n 2 $(Base.julia_cmd()) --project -e $(mpi_cmd)`) + + @test isdir(path_threads_vtk) + @test isdir(path_mpi_vtk) + vtk_files_threads = Peridynamics.find_vtk_files(path_threads_vtk) + vtk_files_mpi = Peridynamics.find_vtk_files(path_mpi_vtk) + @test length(vtk_files_mpi) == length(vtk_files_threads) == 2 + for i in eachindex(vtk_files_threads, vtk_files_mpi) + res_threads = read_vtk(vtk_files_threads[i]) + res_mpi = read_vtk(vtk_files_mpi[i]) + for key in keys(res_threads) + res_threads_qty = res_threads[key] + res_mpi_qty = res_mpi[key] + Δe = maximum(abs.(res_threads_qty .- res_mpi_qty)) + #TODO: why is this error so high? + # See also: https://github.com/kaipartmann/Peridynamics.jl/issues/187 + @test Δe < 0.02 + end + end + + rm(root; recursive=true, force=true) +end + @testitem "MPI-Threads comparison BBMaterial{EnergySurfaceCorrection}" begin root = joinpath(@__DIR__, "temp_mpi_threads_comparison_bbesc") path_threads = joinpath(root, "results_threads") From e984e4cf35800bd38b23b787fc2e2c1a81403844 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Fri, 8 Nov 2024 13:34:00 +0100 Subject: [PATCH 23/40] Minor fix --- src/time_solvers/dynamic_relaxation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/time_solvers/dynamic_relaxation.jl b/src/time_solvers/dynamic_relaxation.jl index ed792e24..53f61d16 100644 --- a/src/time_solvers/dynamic_relaxation.jl +++ b/src/time_solvers/dynamic_relaxation.jl @@ -201,7 +201,7 @@ function relaxation_timestep!(dh::AbstractMPIBodyDataHandler, cn = calc_damping(chunk, Δt) relaxation_step!(chunk, Δt, cn) end - @timeit_debug TO "export_results" export_results(dh, options, chunk_id, n, t) + @timeit_debug TO "export_results" export_results(dh, options, n, t) return nothing end From 55b433f3b5738f0d0f993688f0d2d6695b320ad6 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Fri, 8 Nov 2024 13:59:29 +0100 Subject: [PATCH 24/40] Change args order for consistency --- src/core/mpi_body_data_handler.jl | 2 +- src/core/threads_body_data_handler.jl | 2 +- src/core/threads_multibody_data_handler.jl | 2 +- src/time_solvers/dynamic_relaxation.jl | 4 ++-- src/time_solvers/velocity_verlet.jl | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core/mpi_body_data_handler.jl b/src/core/mpi_body_data_handler.jl index 5c532407..8406f086 100644 --- a/src/core/mpi_body_data_handler.jl +++ b/src/core/mpi_body_data_handler.jl @@ -341,7 +341,7 @@ function recv_htl!(get_field_function::F, dh::MPIBodyDataHandler, return nothing end -function calc_force_density!(dh::MPIBodyDataHandler, Δt, t) +function calc_force_density!(dh::MPIBodyDataHandler, t, Δt) (; chunk) = dh @timeit_debug TO "exchange_loc_to_halo!" exchange_loc_to_halo!(dh) @timeit_debug TO "calc_force_density!" calc_force_density!(chunk, t, Δt) diff --git a/src/core/threads_body_data_handler.jl b/src/core/threads_body_data_handler.jl index 71b1ca66..930e8e8e 100644 --- a/src/core/threads_body_data_handler.jl +++ b/src/core/threads_body_data_handler.jl @@ -157,7 +157,7 @@ function exchange_halo_to_loc!(get_field_function::F, dh::ThreadsBodyDataHandler return nothing end -function calc_force_density!(dh::ThreadsBodyDataHandler, Δt, t) +function calc_force_density!(dh::ThreadsBodyDataHandler, t, Δt) @threads :static for chunk_id in eachindex(dh.chunks) exchange_loc_to_halo!(dh, chunk_id) calc_force_density!(dh.chunks[chunk_id], t, Δt) diff --git a/src/core/threads_multibody_data_handler.jl b/src/core/threads_multibody_data_handler.jl index 9df0c623..8fbf8767 100644 --- a/src/core/threads_multibody_data_handler.jl +++ b/src/core/threads_multibody_data_handler.jl @@ -33,7 +33,7 @@ end @inline each_body_name(dh::ThreadsMultibodyDataHandler) = dh.body_names @inline each_body_idx(dh::ThreadsMultibodyDataHandler) = eachindex(dh.body_dhs) -function calc_force_density!(dh::ThreadsMultibodyDataHandler, Δt, t) +function calc_force_density!(dh::ThreadsMultibodyDataHandler, t, Δt) for body_idx in each_body_idx(dh) body_dh = get_body_dh(dh, body_idx) @threads :static for chunk_id in eachindex(body_dh.chunks) diff --git a/src/time_solvers/dynamic_relaxation.jl b/src/time_solvers/dynamic_relaxation.jl index 53f61d16..cdb661d4 100644 --- a/src/time_solvers/dynamic_relaxation.jl +++ b/src/time_solvers/dynamic_relaxation.jl @@ -172,7 +172,7 @@ function relaxation_timestep!(dh::AbstractThreadsBodyDataHandler, apply_boundary_conditions!(chunk, t) update_disp_and_pos!(chunk, Δt) end - calc_force_density!(dh, Δt, t) + calc_force_density!(dh, t, Δt) @threads :static for chunk_id in eachindex(dh.chunks) chunk = dh.chunks[chunk_id] calc_damage!(chunk) @@ -193,7 +193,7 @@ function relaxation_timestep!(dh::AbstractMPIBodyDataHandler, (; chunk) = dh @timeit_debug TO "apply_boundary_conditions!" apply_boundary_conditions!(chunk, t) @timeit_debug TO "update_disp_and_pos!" update_disp_and_pos!(chunk, Δt) - calc_force_density!(dh, Δt, t) + calc_force_density!(dh, t, Δt) @timeit_debug TO "calc_damage!" calc_damage!(chunk) @timeit_debug TO "relaxation_step!" if n == 1 relaxation_first_step!(chunk, Δt) diff --git a/src/time_solvers/velocity_verlet.jl b/src/time_solvers/velocity_verlet.jl index 6eaae2ce..471a4f8c 100644 --- a/src/time_solvers/velocity_verlet.jl +++ b/src/time_solvers/velocity_verlet.jl @@ -209,7 +209,7 @@ function verlet_timestep!(dh::AbstractThreadsMultibodyDataHandler, update_disp_and_pos!(chunk, Δt) end end - calc_force_density!(dh, Δt, t) + calc_force_density!(dh, t, Δt) update_caches!(dh) calc_contact_force_densities!(dh) for body_idx in each_body_idx(dh) @@ -233,7 +233,7 @@ function verlet_timestep!(dh::AbstractMPIBodyDataHandler, options::AbstractJobOp @timeit_debug TO "update_vel_half!" update_vel_half!(chunk, Δt½) @timeit_debug TO "apply_boundary_conditions!" apply_boundary_conditions!(chunk, t) @timeit_debug TO "update_disp_and_pos!" update_disp_and_pos!(chunk, Δt) - calc_force_density!(dh, Δt, t) + calc_force_density!(dh, t, Δt) @timeit_debug TO "calc_damage!" calc_damage!(chunk) @timeit_debug TO "update_acc_and_vel!" update_acc_and_vel!(chunk, Δt½) @timeit_debug TO "export_results" export_results(dh, options, n, t) From 08fcfa36ed0492785567493576bd42a173e7c406 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Tue, 12 Nov 2024 00:06:15 +0100 Subject: [PATCH 25/40] Dirty draft of RKC-PD --- src/Peridynamics.jl | 3 +- src/auxiliary/nans.jl | 8 + src/auxiliary/static_arrays.jl | 17 + src/physics/rk_correspondence.jl | 599 +++++++++++++++++++++++++++++++ 4 files changed, 626 insertions(+), 1 deletion(-) create mode 100644 src/physics/rk_correspondence.jl diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index d2327d85..01f1b747 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -9,7 +9,7 @@ end import LibGit2, Dates # Material models -export BBMaterial, OSBMaterial, CMaterial, BACMaterial, CKIMaterial +export BBMaterial, OSBMaterial, CMaterial, BACMaterial, RKCMaterial, CKIMaterial # CMaterial related types export NeoHookeNonlinear, SaintVenantKirchhoff, ZEMSilling @@ -128,6 +128,7 @@ include("physics/ordinary_state_based.jl") include("physics/constitutive_models.jl") include("physics/correspondence.jl") include("physics/ba_correspondence.jl") +include("physics/rk_correspondence.jl") include("VtkReader/VtkReader.jl") using .VtkReader diff --git a/src/auxiliary/nans.jl b/src/auxiliary/nans.jl index b6116d76..45c16887 100644 --- a/src/auxiliary/nans.jl +++ b/src/auxiliary/nans.jl @@ -4,3 +4,11 @@ function containsnan(K::T) where {T<:AbstractArray} end return false end + +function nancheck(chunk::AbstractBodyChunk, t) + if containsnan(chunk.storage.b_int) + msg = "NaN's found in field `b_int` at simulation time $(t)!\n" + error(msg) + end + return nothing +end diff --git a/src/auxiliary/static_arrays.jl b/src/auxiliary/static_arrays.jl index 779ae6af..79373128 100644 --- a/src/auxiliary/static_arrays.jl +++ b/src/auxiliary/static_arrays.jl @@ -17,3 +17,20 @@ end Tₙ[9, i] = Tₙ₊₁[3, 3] return nothing end + +@inline function get_vector(M::AbstractMatrix, i::Int) + V = SVector{3}(M[1, i], M[2, i], M[3, i]) + return V +end + +@inline function update_vector!(Mₙ::AbstractMatrix, i::Int, Vₙ₊₁::SVector{3}) + Mₙ[1, i] = Vₙ₊₁[1] + Mₙ[2, i] = Vₙ₊₁[2] + Mₙ[3, i] = Vₙ₊₁[3] + return nothing +end + +@inline function get_vector_diff(M::AbstractMatrix, i::Int, j::Int) + V = SVector{3}(M[1, j] - M[1, i], M[2, j] - M[2, i], M[3, j] - M[3, i]) + return V +end diff --git a/src/physics/rk_correspondence.jl b/src/physics/rk_correspondence.jl new file mode 100644 index 00000000..e34fd202 --- /dev/null +++ b/src/physics/rk_correspondence.jl @@ -0,0 +1,599 @@ +""" + RKCMaterial(; maxdmg, zem) + +A material type used to assign the material of a [`Body`](@ref) with the local continuum +consistent (correspondence) formulation of non-ordinary state-based peridynamics. + +# Keywords +- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is + exceeded, all bonds of that point are broken because the deformation gradient would then + possibly contain `NaN` values. + (default: `0.95`) +- `zem::AbstractZEMStabilization`: zero-energy mode stabilization. The + stabilization algorithm of Silling (2017) is used as default. + (default: `ZEMSilling()`) + +!!! note "Stability of fracture simulations" + This formulation is known to be not suitable for fracture simultations without + stabilization of the zero-energy modes. Therefore be careful when doing fracture + simulations and try out different parameters for `maxdmg` and `zem`. + +# Examples + +```julia-repl +julia> mat = RKCMaterial() +RKCMaterial(maxdmg=0.95, zem_fac=ZEMSilling()) +``` + +--- + +```julia +RKCMaterial +``` + +Material type for the local continuum consistent (correspondence) formulation of +non-ordinary state-based peridynamics. + +# Fields +- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. See the + constructor docs for more informations. +- `zem_fac::Float64`: Correction factor used for zero-energy mode stabilization. See the + constructor docs for more informations. + +# Allowed material parameters +When using [`material!`](@ref) on a [`Body`](@ref) with `RKCMaterial`, then the following +parameters are allowed: +- `horizon::Float64`: Radius of point interactions +- `rho::Float64`: Density +- `E::Float64`: Young's modulus +- `nu::Float64`: Poisson's ratio +- `Gc::Float64`: Critical energy release rate +- `epsilon_c::Float64`: Critical strain + +# Allowed export fields +When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with +`RKCMaterial`, the following fields are allowed: +- `position::Matrix{Float64}`: Position of each point +- `displacement::Matrix{Float64}`: Displacement of each point +- `velocity::Matrix{Float64}`: Velocity of each point +- `velocity_half::Matrix{Float64}`: Velocity parameter for Verlet time solver +- `acceleration::Matrix{Float64}`: Acceleration of each point +- `b_int::Matrix{Float64}`: Internal force density of each point +- `b_ext::Matrix{Float64}`: External force density of each point +- `damage::Vector{Float64}`: Damage of each point +- `n_active_bonds::Vector{Int}`: Number of intact bonds of each point +""" +struct RKCMaterial{CM} <: AbstractCorrespondenceMaterial{CM,NoCorrection} + constitutive_model::CM + maxdmg::Float64 + accuracy_order::Int + function RKCMaterial(cm::CM, maxdmg::Real, accuracy_order::Int) where {CM} + return new{CM}(cm, maxdmg, accuracy_order) + end +end + +function Base.show(io::IO, @nospecialize(mat::RKCMaterial)) + print(io, typeof(mat)) + print(io, msg_fields_in_brackets(mat, (:maxdmg,))) + return nothing +end + +function RKCMaterial(; model::AbstractConstitutiveModel=SaintVenantKirchhoff(), + maxdmg::Real=0.85, accuracy_order::Int=2) + return RKCMaterial(model, maxdmg, accuracy_order) +end + +struct RKCPointParameters <: AbstractPointParameters + δ::Float64 + rho::Float64 + E::Float64 + nu::Float64 + G::Float64 + K::Float64 + λ::Float64 + μ::Float64 + Gc::Float64 + εc::Float64 + bc::Float64 +end + +function RKCPointParameters(mat::RKCMaterial, p::Dict{Symbol,Any}) + (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) + (; Gc, εc) = get_frac_params(p, δ, K) + bc = 18 * K / (π * δ^4) # bond constant + return RKCPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) +end + +@params RKCMaterial RKCPointParameters + +@storage RKCMaterial struct RKCStorage + @lthfield position::Matrix{Float64} + @pointfield displacement::Matrix{Float64} + @pointfield velocity::Matrix{Float64} + @pointfield velocity_half::Matrix{Float64} + @pointfield velocity_half_old::Matrix{Float64} + @pointfield acceleration::Matrix{Float64} + @htlfield b_int::Matrix{Float64} + @pointfield b_int_old::Matrix{Float64} + @pointfield b_ext::Matrix{Float64} + @pointfield density_matrix::Matrix{Float64} + @pointfield damage::Vector{Float64} + bond_active::Vector{Bool} + @pointfield n_active_bonds::Vector{Int} + @pointfield damage_changed::Vector{Bool} + @pointfield pk1::Matrix{Float64} + # @pointfield stress::Matrix{Float64} + # @pointfield von_mises_stress::Vector{Float64} + @lthfield defgrad::Matrix{Float64} + @lthfield weighted_volume::Vector{Float64} + gradient_weight::Matrix{Float64} +end + +# function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, +# ::Val{:displacement}) +# return zeros(3, get_n_points(system)) +# end + +function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int}) + return zeros(3, get_n_points(system)) +end + +function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:damage_changed}) + return ones(Bool, get_n_loc_points(system)) +end + +function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:pk1}) + return zeros(9, get_n_loc_points(system)) +end + +# function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, +# ::Val{:von_mises_stress}) +# return zeros(get_n_loc_points(system)) +# end + +function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:defgrad}) + return zeros(9, get_n_points(system)) +end + +function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:weighted_volume}) + return zeros(get_n_points(system)) +end + +function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:gradient_weight}) + return zeros(3, get_n_bonds(system)) +end + +# function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, +# ::Val{:first_piola_kirchhoff}) +# return zeros(9, get_n_points(system)) +# end + +function initialize!(chunk::BodyChunk{<:BondSystem,<:RKCMaterial}) + chunk.storage.damage_changed .= true + return nothing +end + +@inline function calc_damage!(chunk::BodyChunk{<:BondSystem,<:RKCMaterial}) + (; n_neighbors) = chunk.system + (; n_active_bonds, damage, damage_changed) = chunk.storage + for point_id in each_point_idx(chunk) + old_damage = damage[point_id] + new_damage = 1 - n_active_bonds[point_id] / n_neighbors[point_id] + if new_damage > old_damage + damage_changed[point_id] = true + else + damage_changed[point_id] = false + end + damage[point_id] = new_damage + end + return nothing +end + +function calc_force_density!(dh::ThreadsBodyDataHandler{<:BondSystem,<:RKCMaterial}, t, Δt) + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_loc_to_halo!(dh, chunk_id, :position) + end + @threads :static for chunk_id in eachindex(dh.chunks) + calc_weights_and_defgrad!(dh.chunks[chunk_id], t, Δt) + end + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_loc_to_halo!(dh, chunk_id, (:defgrad, :weighted_volume)) + end + @threads :static for chunk_id in eachindex(dh.chunks) + chunk = dh.chunks[chunk_id] + calc_force_density!(chunk, t, Δt) + nancheck(chunk, t) + end + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_halo_to_loc!(dh, chunk_id) + end + return nothing +end + +#TODO +function calc_force_density!(dh::MPIBodyDataHandler{<:BondSystem,<:RKCMaterial}, t, Δt) + (; chunk) = dh + exchange_loc_to_halo!(dh) + calc_weights_and_defgrad!(chunk, t, Δt) + exchange_loc_to_halo!(dh, :defgrad) + calc_force_density!(chunk, t, Δt) + forcedensity_nancheck(chunk, t) + exchange_halo_to_loc!(dh) + return nothing +end + +# function calc_force_density!(chunk::AbstractBodyChunk{<:AbstractBondSystem,<:RKCMaterial}, +# t, Δt) +# (; system, mat, paramsetup, storage) = chunk +# storage.b_int .= 0 +# storage.n_active_bonds .= 0 +# calc_gradient_weights!(storage, system, mat, paramsetup) +# for point_id in each_point_idx(chunk) +# force_density_point!(storage, system, mat, paramsetup, t, Δt, point_id) +# end +# return nothing +# end + +function calc_weights_and_defgrad!(chunk::BodyChunk{<:BondSystem,<:RKCMaterial}, t, Δt) + (; system, mat, paramsetup, storage) = chunk + calc_gradient_weights!(storage, system, mat, paramsetup) + calc_deformation_gradients!(storage, system, mat, paramsetup, t, Δt) + return nothing +end + +function calc_gradient_weights!(storage::RKCStorage, system::BondSystem, mat::RKCMaterial, + paramsetup::AbstractParameterSetup) + (; bonds, volume) = system + (; bond_active, gradient_weight, damage_changed, weighted_volume) = storage + (; accuracy_order) = mat + q_dim = get_q_dim(accuracy_order) + + Q∇ᵀ = get_q_triangle(accuracy_order) + + for i in each_point_idx(system) + if damage_changed[i] + params = get_params(paramsetup, i) + (; δ) = params + + # calculate moment matrix M + M = zero(SMatrix{q_dim,q_dim,Float64,q_dim*q_dim}) + wi = 0.0 + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j, L = bond.neighbor, bond.length + ΔXij = get_diff(system.position, i, j) + Q = get_q_matrix(accuracy_order, ΔXij, δ) + ωij = influence_function(mat, params, L) * bond_active[bond_id] + temp = ωij * volume[j] + M += temp * (Q * Q') + wi += temp + end + weighted_volume[i] = wi + + # calculate inverse of moment matrix, must be a full rank matrix! + # regularization_term = 1e-6 * δ * δ * δ + # M += regularization_term * I + # Minv = inv(M) + U, S, V = svd(M) + threshold = 1e-6 * δ * δ * δ + Sinv = Diagonal([s > threshold ? 1/s : 0 for s in S]) + Minv = V * Sinv * U' + + # calculate gradient weights Φ + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j, L = bond.neighbor, bond.length + ΔXij = get_diff(system.position, i, j) + Q = get_q_matrix(accuracy_order, ΔXij, δ) + ωij = influence_function(mat, params, L) * bond_active[bond_id] + MinvQ = Minv * Q + Φ = ωij * (Q∇ᵀ * MinvQ) + gradient_weight[1, bond_id] = Φ[1] + gradient_weight[2, bond_id] = Φ[2] + gradient_weight[3, bond_id] = Φ[3] + end + end + end + + return nothing +end + +@inline each_monomial(N::Int) = each_monomial(Val(N)) + +@inline function each_monomial(::Val{N}) where {N} + monomials = Tuple((p1,p2,p3) for i in 1:N + for p1 in i:-1:0 + for p2 in (i - p1):-1:0 + for p3 in i - p1 - p2) + return monomials +end + +@inline function each_monomial(::Val{1}) + return ((1, 0, 0), (0, 1, 0), (0, 0, 1)) +end + +@inline function each_monomial(::Val{2}) + return ((1, 0, 0), (0, 1, 0), (0, 0, 1), (2, 0, 0), (1, 1, 0), (1, 0, 1), (0, 2, 0), + (0, 1, 1), (0, 0, 2)) +end + +@inline get_q_dim(accuracy_order) = length(each_monomial(accuracy_order)) + +@inline get_q_matrix(N::Int, ΔX::AbstractArray, δ::Real) = get_q_matrix(Val(N), ΔX, δ) + +@inline function get_q_matrix(n::Val{N}, ΔX::AbstractArray, δ::Real) where {N} + a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ + _Q = (a1^p1 * a2^p2 * a3^p3 for (p1, p2, p3) in each_monomial(n)) + q_dims = get_q_dim(n) + Q = SVector{q_dims}(_Q...) + return Q +end + +# @inline function get_q_matrix(::Val{1}, ΔX::AbstractArray, δ::Real) +# a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ +# Q = SVector{3}(a1, a2, a3) +# return Q +# end + +# @inline function get_q_matrix(::Val{2}, ΔX::AbstractArray, δ::Real) +# a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ +# Q = SVector{9}(a1, a2, a3, a1*a1, a1*a2, a1*a3, a2*a2, a2*a3, a3*a3) +# return Q +# end + +# function get_q_matrix2(accuracy_order::Int, ΔX::AbstractArray, δ::Real) +# q_dim = get_q_dim(accuracy_order) +# Q = @MVector zeros(Float64, q_dim) +# counter = 1 +# for this_order in 1:accuracy_order +# for p1 in this_order:-1:0 +# for p2 in (this_order - p1):-1:0 +# p3 = this_order - p1 - p2 +# Q[counter] = 1.0 +# for _ in 1:p1 +# Q[counter] *= ΔX[1] / δ +# end +# for _ in 1:p2 +# Q[counter] *= ΔX[2] / δ +# end +# for _ in 1:p3 +# Q[counter] *= ΔX[3] / δ +# end +# counter += 1 +# end +# end +# end +# return Q +# end + +@inline get_q_triangle(N::Int) = get_q_triangle(Val(N)) + +function get_q_triangle(::Val{1}) + Q∇ᵀ = SMatrix{3,3,Int,9}(1, 0, 0, + 0, 1, 0, + 0, 0, 1) + return Q∇ᵀ +end + +function get_q_triangle(::Val{2}) + Q∇ᵀ = SMatrix{3,9,Int,27}(1, 0, 0, + 0, 1, 0, + 0, 0, 1, + 0, 0, 0, + 0, 0, 0, + 0, 0, 0, + 0, 0, 0, + 0, 0, 0, + 0, 0, 0) + return Q∇ᵀ +end + +function get_q_triangle(::Val{N}) where {N} + msg = "RK kernel only implemented for `accuracy_order ∈ {1,2}`!\n" + return throw(ArgumentError(msg)) +end + +function calc_deformation_gradients!(storage::RKCStorage, system::BondSystem, ::RKCMaterial, + ::AbstractParameterSetup, t, Δt) + (; bonds, volume) = system + (; gradient_weight, defgrad) = storage + + for i in each_point_idx(system) + # F = zero(SMatrix{3,3,Float64,9}) + I + F = SMatrix{3,3,Float64,9}(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j = bond.neighbor + ΔXij = get_vector_diff(system.position, i, j) + Δxij = get_vector_diff(storage.position, i, j) + ΔUij = Δxij - ΔXij + Φij = get_vector(gradient_weight, bond_id) + # F += (ΔUij * Φij') * volume[j] + F += (Φij * ΔUij') * volume[j] + end + update_tensor!(defgrad, i, F) + end + return nothing +end + +function force_density_point!(storage::RKCStorage, system::BondSystem, mat::RKCMaterial, + paramhandler::AbstractParameterHandler, t, Δt, i) + params = get_params(paramhandler, i) + force_density_point!(storage, system, mat, params, t, Δt, i) + return nothing +end + +function force_density_point!(storage::RKCStorage, system::BondSystem, mat::RKCMaterial, + params::RKCPointParameters, t, Δt, i) + (; bonds, volume) = system + (; gradient_weight, defgrad, bond_active, weighted_volume) = storage + Fi = get_tensor(defgrad, i) + too_much_damage!(storage, system, mat, Fi, i) && return nothing + Pi = calc_first_piola_kirchhoff(storage, mat, params, Fi) + + # Standard RK + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j, L = bond.neighbor, bond.length + Δxij = get_coordinates_diff(storage, i, j) + l = norm(Δxij) + ε = (l - L) / L + stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + + # if bond_active[bond_id] + Φij = get_vector(gradient_weight, bond_id) + Fj = get_tensor(defgrad, j) + Pj = calc_first_piola_kirchhoff(storage, mat, params, Fj) + ΔPij = Pj - Pi + tij = 1e1 * (ΔPij * Φij) * volume[j] + update_add_b_int!(storage, i, tij) + # end + end + + # BA-Stabilized RK + # for bond_id in each_bond_idx(system, i) + # bond = bonds[bond_id] + # j, L = bond.neighbor, bond.length + # ΔXij = get_coordinates_diff(system, i, j) + # Δxij = get_coordinates_diff(storage, i, j) + # l = norm(Δxij) + # ε = (l - L) / L + # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + + # Φij = get_vector(gradient_weight, bond_id) + # Fj = get_tensor(defgrad, j) + # ΔFij = (Δxij - 0.5 * (Fi + Fj) * ΔXij) * ΔXij' / (L * L) + # # Fij = Fj + ΔFij + # Fij = 0.5 * (Fi + Fj) + ΔFij + # Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) * bond_active[bond_id] + # ΔPij = Pij - Pi + # tij = (ΔPij * Φij) * volume[j] + # update_add_b_int!(storage, i, tij) + # end + + # Nodal quadrature + # Stress integral SI + # wi = weighted_volume[i] + # SI = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + # for bond_id in each_bond_idx(system, i) + # bond = bonds[bond_id] + # j, L = bond.neighbor, bond.length + # ΔXij = get_coordinates_diff(system, i, j) + # Δxij = get_coordinates_diff(storage, i, j) + # l = norm(Δxij) + # ε = (l - L) / L + # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + + # if bond_active[bond_id] + # Fj = get_tensor(defgrad, j) + # Fb = 0.5 * (Fi + Fj) + # ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) + # Fij = Fb + ΔFij + # Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) + # ΔPij = Pij - Pi + # Tempij = I - ΔXij * ΔXij' / (L * L) + # wj = weighted_volume[j] + # ϕ = influence_function(mat, params, L) * (0.5 / wi + 0.5 / wj) * volume[j] + # SI += ϕ * (ΔPij * Tempij) + # end + # end + + # for bond_id in each_bond_idx(system, i) + # if bond_active[bond_id] + # bond = bonds[bond_id] + # j, L = bond.neighbor, bond.length + # ΔXij = get_coordinates_diff(system, i, j) + # Δxij = get_coordinates_diff(storage, i, j) + # Fj = get_tensor(defgrad, j) + # Fb = 0.5 * (Fi + Fj) + # ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) + # Fij = Fb + ΔFij + # Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) + # ΔPij = Pij - Pi + + # Φij = get_vector(gradient_weight, bond_id) + # ω = influence_function(mat, params, L) + # tij = ω / wi * (ΔPij * Φij) / (L * L) + SI * Φij + # update_add_b_int!(storage, i, tij * volume[j]) + # update_add_b_int!(storage, i, -tij * volume[i]) + # end + # end + + return nothing +end + +@inline function influence_function(::RKCMaterial, params::RKCPointParameters, L) + ξ = L / params.δ + if 0 < ξ ≤ 0.5 + return 2/3 - 4 * ξ^2 + 4 * ξ^3 + elseif 0.5 < ξ ≤ 1 + return 4/3 - 4 * ξ + 4 * ξ^2 - 4/3 * ξ^3 + else + return 0 + end +end + +# function calc_deformation_gradient(storage::RKCStorage, system::BondSystem, +# mat::RKCMaterial, params::RKCPointParameters, i) +# (; bonds, volume) = system +# (; displacement, gradient_weight) = storage +# F = zero(SMatrix{3,3,Float64,9}) +# for bond_id in each_bond_idx(system, i) +# bond = bonds[bond_id] +# j = bond.neighbor +# Δuij = get_vector_diff(displacement, i, j) +# Φij = get_vector(gradient_weight, bond_id) +# F += (Δuij * Φij') * volume[j] +# end +# return F +# end + +function calc_first_piola_kirchhoff(storage::RKCStorage, mat::RKCMaterial, + params::RKCPointParameters, F) + # σ = cauchy_stress(mat.constitutive_model, storage, params, F) + # P = det(F) * σ * inv(F)' + J = det(F) + J < eps() && return zero(SMatrix{3,3}) + E = 0.5 .* (F' * F - I) + S = params.λ * tr(E) * I + 2 * params.μ * E + P = F * S + return P +end + +# function rkc_force_density!(storage::RKCStorage, system::BondSystem, mat::RKCMaterial, +# params::RKCPointParameters, PKinv::SMatrix, i) +# (; bonds, volume) = system +# (; bond_active) = storage +# for bond_id in each_bond_idx(system, i) +# bond = bonds[bond_id] +# j, L = bond.neighbor, bond.length +# ΔXij = get_coordinates_diff(system, i, j) +# Δxij = get_coordinates_diff(storage, i, j) +# l = norm(Δxij) +# ε = (l - L) / L +# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + +# # stabilization +# ωij = influence_function(mat, params, L) * bond_active[bond_id] + +# # update of force density +# tij = ωij * PKinv * ΔXij +# update_add_b_int!(storage, i, tij .* volume[j]) +# update_add_b_int!(storage, j, -tij .* volume[i]) +# end +# return nothing +# end + +function too_much_damage!(storage::RKCStorage, system::BondSystem, mat::RKCMaterial, F, i) + if storage.damage[i] > mat.maxdmg || containsnan(F) + # kill all bonds of this point + storage.bond_active[each_bond_idx(system, i)] .= false + storage.n_active_bonds[i] = 0 + return true + end + return false +end From 2a8871c3cdc5629a4c5b3effbc9bb2278b9782bd Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Tue, 12 Nov 2024 12:26:22 +0100 Subject: [PATCH 26/40] Minor improvements --- src/physics/rk_correspondence.jl | 64 ++++++++++++++++---------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/physics/rk_correspondence.jl b/src/physics/rk_correspondence.jl index e34fd202..40e0a29f 100644 --- a/src/physics/rk_correspondence.jl +++ b/src/physics/rk_correspondence.jl @@ -226,18 +226,6 @@ function calc_force_density!(dh::MPIBodyDataHandler{<:BondSystem,<:RKCMaterial}, return nothing end -# function calc_force_density!(chunk::AbstractBodyChunk{<:AbstractBondSystem,<:RKCMaterial}, -# t, Δt) -# (; system, mat, paramsetup, storage) = chunk -# storage.b_int .= 0 -# storage.n_active_bonds .= 0 -# calc_gradient_weights!(storage, system, mat, paramsetup) -# for point_id in each_point_idx(chunk) -# force_density_point!(storage, system, mat, paramsetup, t, Δt, point_id) -# end -# return nothing -# end - function calc_weights_and_defgrad!(chunk::BodyChunk{<:BondSystem,<:RKCMaterial}, t, Δt) (; system, mat, paramsetup, storage) = chunk calc_gradient_weights!(storage, system, mat, paramsetup) @@ -266,9 +254,10 @@ function calc_gradient_weights!(storage::RKCStorage, system::BondSystem, mat::RK bond = bonds[bond_id] j, L = bond.neighbor, bond.length ΔXij = get_diff(system.position, i, j) - Q = get_q_matrix(accuracy_order, ΔXij, δ) + Q = get_q_vector(accuracy_order, ΔXij, δ) ωij = influence_function(mat, params, L) * bond_active[bond_id] temp = ωij * volume[j] + # M += temp * (Q * Q') / δ M += temp * (Q * Q') wi += temp end @@ -280,7 +269,8 @@ function calc_gradient_weights!(storage::RKCStorage, system::BondSystem, mat::RK # Minv = inv(M) U, S, V = svd(M) threshold = 1e-6 * δ * δ * δ - Sinv = Diagonal([s > threshold ? 1/s : 0 for s in S]) + _S_ = SVector{q_dim,Float64}((s > threshold ? s : 0) for s in S) + Sinv = Diagonal{Float64,SVector{9,Float64}}(_S_) Minv = V * Sinv * U' # calculate gradient weights Φ @@ -288,7 +278,7 @@ function calc_gradient_weights!(storage::RKCStorage, system::BondSystem, mat::RK bond = bonds[bond_id] j, L = bond.neighbor, bond.length ΔXij = get_diff(system.position, i, j) - Q = get_q_matrix(accuracy_order, ΔXij, δ) + Q = get_q_vector(accuracy_order, ΔXij, δ) ωij = influence_function(mat, params, L) * bond_active[bond_id] MinvQ = Minv * Q Φ = ωij * (Q∇ᵀ * MinvQ) @@ -323,9 +313,9 @@ end @inline get_q_dim(accuracy_order) = length(each_monomial(accuracy_order)) -@inline get_q_matrix(N::Int, ΔX::AbstractArray, δ::Real) = get_q_matrix(Val(N), ΔX, δ) +@inline get_q_vector(N::Int, ΔX::AbstractArray, δ::Real) = get_q_vector(Val(N), ΔX, δ) -@inline function get_q_matrix(n::Val{N}, ΔX::AbstractArray, δ::Real) where {N} +@inline function get_q_vector(n::Val{N}, ΔX::AbstractArray, δ::Real) where {N} a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ _Q = (a1^p1 * a2^p2 * a3^p3 for (p1, p2, p3) in each_monomial(n)) q_dims = get_q_dim(n) @@ -333,19 +323,20 @@ end return Q end -# @inline function get_q_matrix(::Val{1}, ΔX::AbstractArray, δ::Real) -# a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ -# Q = SVector{3}(a1, a2, a3) -# return Q -# end +@inline function get_q_vector(::Val{1}, ΔX::AbstractArray, δ::Real) + a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ + Q = SVector{3}(a1, a2, a3) + return Q +end -# @inline function get_q_matrix(::Val{2}, ΔX::AbstractArray, δ::Real) -# a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ -# Q = SVector{9}(a1, a2, a3, a1*a1, a1*a2, a1*a3, a2*a2, a2*a3, a3*a3) -# return Q -# end +@inline function get_q_vector(::Val{2}, ΔX::AbstractArray, δ::Real) + a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ + Q = SVector{9}(a1, a2, a3, a1*a1, a1*a2, a1*a3, a2*a2, a2*a3, a3*a3) + # Q = SVector{9}(a1, a2, a3, a1*a1, a2*a2, a3*a3, a1*a2, a1*a3, a2*a3) + return Q +end -# function get_q_matrix2(accuracy_order::Int, ΔX::AbstractArray, δ::Real) +# function get_q_vector2(accuracy_order::Int, ΔX::AbstractArray, δ::Real) # q_dim = get_q_dim(accuracy_order) # Q = @MVector zeros(Float64, q_dim) # counter = 1 @@ -412,8 +403,7 @@ function calc_deformation_gradients!(storage::RKCStorage, system::BondSystem, :: Δxij = get_vector_diff(storage.position, i, j) ΔUij = Δxij - ΔXij Φij = get_vector(gradient_weight, bond_id) - # F += (ΔUij * Φij') * volume[j] - F += (Φij * ΔUij') * volume[j] + F += (ΔUij * Φij') * volume[j] end update_tensor!(defgrad, i, F) end @@ -432,8 +422,18 @@ function force_density_point!(storage::RKCStorage, system::BondSystem, mat::RKCM (; bonds, volume) = system (; gradient_weight, defgrad, bond_active, weighted_volume) = storage Fi = get_tensor(defgrad, i) - too_much_damage!(storage, system, mat, Fi, i) && return nothing + # println("Deformation gradient Fi at point $i:") + # display(Fi) + + # too_much_damage!(storage, system, mat, Fi, i) && return nothing + if too_much_damage!(storage, system, mat, Fi, i) + # println("Too much damage at point $i") + return nothing + end + Pi = calc_first_piola_kirchhoff(storage, mat, params, Fi) + # println("First Piola Kirchhoff stress tensor Pi at point $i:") + # display(Pi) # Standard RK for bond_id in each_bond_idx(system, i) @@ -449,7 +449,7 @@ function force_density_point!(storage::RKCStorage, system::BondSystem, mat::RKCM Fj = get_tensor(defgrad, j) Pj = calc_first_piola_kirchhoff(storage, mat, params, Fj) ΔPij = Pj - Pi - tij = 1e1 * (ΔPij * Φij) * volume[j] + tij = (ΔPij * Φij) * volume[j] update_add_b_int!(storage, i, tij) # end end From 906dee8823e08e5a4973f63078ee0800e232b203 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Wed, 13 Nov 2024 16:08:27 +0100 Subject: [PATCH 27/40] Refactor stress calculations to use first Piola-Kirchhoff stress and update cauchy_stress function --- src/physics/ba_correspondence.jl | 5 +---- src/physics/constitutive_models.jl | 14 ++++++-------- src/physics/correspondence.jl | 6 +++--- src/physics/stress.jl | 6 ++++++ 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/physics/ba_correspondence.jl b/src/physics/ba_correspondence.jl index c96c978c..93bb1fe2 100644 --- a/src/physics/ba_correspondence.jl +++ b/src/physics/ba_correspondence.jl @@ -213,10 +213,7 @@ function calc_first_piola_kirchhoff!(storage::BACStorage, mat::BACMaterial, params::BACPointParameters, defgrad_res, Δt, i, bond_idx) (; F, Kinv) = defgrad_res - σ = cauchy_stress(mat.constitutive_model, storage, params, F) - # update_tensor!(storage.stress, i, σ) - # storage.von_mises_stress[i] = von_mises_stress(σ) - P = det(F) * σ * inv(F)' + P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) PKinv = P * Kinv return PKinv end diff --git a/src/physics/constitutive_models.jl b/src/physics/constitutive_models.jl index 367f963a..987c24cc 100644 --- a/src/physics/constitutive_models.jl +++ b/src/physics/constitutive_models.jl @@ -1,7 +1,7 @@ struct NeoHookeNonlinear <: AbstractConstitutiveModel end -function cauchy_stress(::NeoHookeNonlinear, storage::AbstractStorage, - params::AbstractPointParameters, F::SMatrix{3,3}) +function first_piola_kirchhoff(::NeoHookeNonlinear, storage::AbstractStorage, + params::AbstractPointParameters, F::SMatrix{3,3}) J = det(F) J < eps() && return zero(SMatrix{3,3}) C = F' * F @@ -9,19 +9,17 @@ function cauchy_stress(::NeoHookeNonlinear, storage::AbstractStorage, S = params.G .* (I - 1 / 3 .* tr(C) .* Cinv) .* J^(-2 / 3) .+ params.K / 4 .* (J^2 - J^(-2)) .* Cinv P = F * S - σ = 1/J .* P * F' - return σ + return P end struct SaintVenantKirchhoff <: AbstractConstitutiveModel end -function cauchy_stress(::SaintVenantKirchhoff, storage::AbstractStorage, - params::AbstractPointParameters, F::SMatrix{3,3}) +function first_piola_kirchhoff(::SaintVenantKirchhoff, storage::AbstractStorage, + params::AbstractPointParameters, F::SMatrix{3,3}) J = det(F) J < eps() && return zero(SMatrix{3,3}) E = 0.5 .* (F' * F - I) S = params.λ * tr(E) * I + 2 * params.μ * E P = F * S - σ = 1/J .* P * F' - return σ + return P end diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index ffea9431..9c217b34 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -184,11 +184,11 @@ end function calc_first_piola_kirchhoff!(storage::CStorage, mat::CMaterial, params::CPointParameters, defgrad_res, Δt, i) (; F, Kinv) = defgrad_res - σ = cauchy_stress(mat.constitutive_model, storage, params, F) + P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) + PKinv = P * Kinv + σ = cauchy_stress(P, F) update_tensor!(storage.stress, i, σ) storage.von_mises_stress[i] = von_mises_stress(σ) - P = det(F) * σ * inv(F)' - PKinv = P * Kinv return PKinv end diff --git a/src/physics/stress.jl b/src/physics/stress.jl index 7d9c3d24..265cace0 100644 --- a/src/physics/stress.jl +++ b/src/physics/stress.jl @@ -7,3 +7,9 @@ function von_mises_stress(σ) σvm = √(a + b + c) return σvm end + +function cauchy_stress(P, F) + J = det(F) + σ = 1/J .* P * F' + return σ +end From 753767951e72fccc3c23efc4e6342093456cc966 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Thu, 14 Nov 2024 09:42:12 +0100 Subject: [PATCH 28/40] Add kernels to materials and precalculate in bond systems --- src/discretization/body.jl | 4 +++ src/discretization/bond_associated_system.jl | 4 ++- src/discretization/bond_system.jl | 27 +++++++++++++++++++- src/discretization/kernels.jl | 14 ++++++++++ src/physics/ba_correspondence.jl | 24 ++++++++--------- src/physics/correspondence.jl | 20 +++++++-------- src/physics/ordinary_state_based.jl | 22 ++++++++-------- 7 files changed, 78 insertions(+), 37 deletions(-) create mode 100644 src/discretization/kernels.jl diff --git a/src/discretization/body.jl b/src/discretization/body.jl index d4c547d2..35549e28 100644 --- a/src/discretization/body.jl +++ b/src/discretization/body.jl @@ -225,6 +225,10 @@ function pre_submission_check(body::Body; body_in_multibody_setup::Bool=false) return nothing end +@inline function get_point_param(b::AbstractBody, i::Int) + return b.point_params[b.params_map[i]] +end + @inline function get_point_param(b::AbstractBody, key::Symbol, i::Int) return getfield(b.point_params[b.params_map[i]], key) end diff --git a/src/discretization/bond_associated_system.jl b/src/discretization/bond_associated_system.jl index b3a93b1a..8ce2dcd6 100644 --- a/src/discretization/bond_associated_system.jl +++ b/src/discretization/bond_associated_system.jl @@ -8,6 +8,7 @@ struct BondAssociatedSystem <: AbstractBondSystem intersection_bond_ids::Vector{Vector{Int}} hood_volume::Vector{Float64} ba_hood_volume::Vector{Float64} + kernels::Vector{Float64} chunk_handler::ChunkHandler end @@ -22,8 +23,9 @@ function BondAssociatedSystem(body::AbstractBody, pd::PointDecomposition, chunk_ position, volume = get_pos_and_vol_chunk(body, chunk_handler.point_ids) hood_volume = zeros(get_n_points(chunk_handler)) ba_hood_volume = zeros(length(bonds)) + kernels = find_kernels(body, chunk_handler, bonds, bond_ids) bas = BondAssociatedSystem(position, volume, bonds, n_neighbors, bond_ids, - intersection_bond_ids, hood_volume, ba_hood_volume, + intersection_bond_ids, hood_volume, ba_hood_volume, kernels, chunk_handler) return bas end diff --git a/src/discretization/bond_system.jl b/src/discretization/bond_system.jl index 7dc24b25..feb34121 100644 --- a/src/discretization/bond_system.jl +++ b/src/discretization/bond_system.jl @@ -10,6 +10,7 @@ struct BondSystem{Correction<:AbstractCorrection} <: AbstractBondSystem bonds::Vector{Bond} n_neighbors::Vector{Int} bond_ids::Vector{UnitRange{Int}} + kernels::Vector{Float64} correction::Correction chunk_handler::ChunkHandler end @@ -23,7 +24,8 @@ function BondSystem(body::AbstractBody, pd::PointDecomposition, chunk_id::Int) position, volume = get_pos_and_vol_chunk(body, chunk_handler.point_ids) correction = get_correction(body.mat, chunk_handler.n_loc_points, length(chunk_handler.point_ids), length(bonds)) - system = BondSystem(position, volume, bonds, n_neighbors, bond_ids, correction, + kernels = find_kernels(body, chunk_handler, bonds, bond_ids) + system = BondSystem(position, volume, bonds, n_neighbors, bond_ids, kernels, correction, chunk_handler) return system end @@ -146,6 +148,29 @@ function get_chunk_handler(bonds::Vector{Bond}, pd::PointDecomposition, chunk_id localizer) end +function find_kernels(body::AbstractBody, chunk_handler::ChunkHandler, bonds::Vector{Bond}, + bond_ids::Vector{UnitRange{Int}}) + hasproperty(body.mat, :kernel) || return Vector{Float64}() + kernels = zeros(length(bonds)) + for i in each_point_idx(chunk_handler) + params = get_point_param(body, i) + for bond_id in bond_ids[i] + bond = bonds[bond_id] + kernels[bond_id] = get_kernel(body.mat, params, bond.length) + end + end + return kernels +end + +function get_kernel(mat::AbstractMaterial, params::AbstractPointParameters, L) + ω = mat.kernel(params.δ, L) + return ω +end + +@inline function kernel(system::AbstractBondSystem, bond_id::Int) + return system.kernels[bond_id] +end + function find_halo_points(bonds::Vector{Bond}, loc_points::UnitRange{Int}) halo_points = Vector{Int}() for bond in bonds diff --git a/src/discretization/kernels.jl b/src/discretization/kernels.jl new file mode 100644 index 00000000..547828a6 --- /dev/null +++ b/src/discretization/kernels.jl @@ -0,0 +1,14 @@ +# peridynamic kernels / influence functions for arbitrary bond systems + +@inline linear_kernel(δ, L) = δ / L + +@inline function cubic_b_spline(δ, L) + ξ = L / δ + if 0 < ξ ≤ 0.5 + return 2/3 - 4 * ξ^2 + 4 * ξ^3 + elseif 0.5 < ξ ≤ 1 + return 4/3 - 4 * ξ + 4 * ξ^2 - 4/3 * ξ^3 + else + return 0 + end +end diff --git a/src/physics/ba_correspondence.jl b/src/physics/ba_correspondence.jl index 93bb1fe2..f9e98ee6 100644 --- a/src/physics/ba_correspondence.jl +++ b/src/physics/ba_correspondence.jl @@ -63,11 +63,12 @@ When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with - `damage::Vector{Float64}`: Damage of each point - `n_active_bonds::Vector{Int}`: Number of intact bonds of each point """ -struct BACMaterial{CM} <: AbstractBondAssociatedSystemMaterial +struct BACMaterial{CM,K} <: AbstractBondAssociatedSystemMaterial + kernel::K constitutive_model::CM maxdmg::Float64 - function BACMaterial(cm::CM, maxdmg::Real) where {CM} - return new{CM}(cm, maxdmg) + function BACMaterial(kernel::K, cm::CM, maxdmg::Real) where {K,CM} + return new{CM,K}(kernel, cm, maxdmg) end end @@ -77,9 +78,10 @@ function Base.show(io::IO, @nospecialize(mat::BACMaterial)) return nothing end -function BACMaterial(; model::AbstractConstitutiveModel=NeoHookeNonlinear(), - maxdmg::Real=0.85) - return BACMaterial(model, maxdmg) +function BACMaterial(; kernel::Function=linear_kernel, + model::AbstractConstitutiveModel=NeoHookeNonlinear(), + maxdmg::Real=0.85) + return BACMaterial(kernel, model, maxdmg) end struct BACPointParameters <: AbstractPointParameters @@ -174,7 +176,7 @@ function force_density_bond!(storage::BACStorage, system::BondAssociatedSystem, ε = (l - L) / L stretch_based_failure!(storage, system, bond, params, ε, i, bond_idx) - ωij = influence_function(mat, params, L) * storage.bond_active[bond_idx] + ωij = kernel(system, bond_idx) * storage.bond_active[bond_idx] ϕi = volume_fraction_factor(system, i, bond_idx) tij = ϕi * ωij * PKinv * ΔXij update_add_b_int!(storage, i, tij .* system.volume[j]) @@ -182,12 +184,6 @@ function force_density_bond!(storage::BACStorage, system::BondAssociatedSystem, return nothing end - -@inline function influence_function(::BACMaterial, params::BACPointParameters, - L::Float64) - return params.δ / L -end - function calc_deformation_gradient(storage::BACStorage, system::BondAssociatedSystem, mat::BACMaterial, params::BACPointParameters, i, bond_idx) @@ -200,7 +196,7 @@ function calc_deformation_gradient(storage::BACStorage, system::BondAssociatedSy j, L = bond.neighbor, bond.length ΔXij = get_diff(system.position, i, j) Δxij = get_diff(storage.position, i, j) - temp = influence_function(mat, params, L) * bond_active[bond_id] * volume[j] + temp = kernel(system, bond_id) * bond_active[bond_id] * volume[j] K += temp * (ΔXij * ΔXij') _F += temp * (Δxij * ΔXij') end diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index 9c217b34..5a9a1c5d 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -63,12 +63,13 @@ When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with - `damage::Vector{Float64}`: Damage of each point - `n_active_bonds::Vector{Int}`: Number of intact bonds of each point """ -struct CMaterial{CM,ZEM} <: AbstractCorrespondenceMaterial{CM,ZEM} +struct CMaterial{CM,ZEM,K} <: AbstractCorrespondenceMaterial{CM,ZEM} + kernel::K constitutive_model::CM zem_stabilization::ZEM maxdmg::Float64 - function CMaterial(cm::CM, zem::ZEM, maxdmg::Real) where {CM,ZEM} - return new{CM,ZEM}(cm, zem, maxdmg) + function CMaterial(kernel::K, cm::CM, zem::ZEM, maxdmg::Real) where {CM,ZEM,K} + return new{CM,ZEM,K}(kernel, cm, zem, maxdmg) end end @@ -78,9 +79,10 @@ function Base.show(io::IO, @nospecialize(mat::CMaterial)) return nothing end -function CMaterial(; model::AbstractConstitutiveModel=NeoHookeNonlinear(), +function CMaterial(; kernel::Function=linear_kernel, + model::AbstractConstitutiveModel=NeoHookeNonlinear(), zem::AbstractZEMStabilization=ZEMSilling(), maxdmg::Real=0.85) - return CMaterial(model, zem, maxdmg) + return CMaterial(kernel, model, zem, maxdmg) end struct CPointParameters <: AbstractPointParameters @@ -154,10 +156,6 @@ function force_density_point!(storage::CStorage, system::BondSystem, mat::CMater return nothing end -@inline function influence_function(::CMaterial, params::CPointParameters, L) - return params.δ / L -end - function calc_deformation_gradient(storage::CStorage, system::BondSystem, mat::CMaterial, params::CPointParameters, i) (; bonds, volume) = system @@ -170,7 +168,7 @@ function calc_deformation_gradient(storage::CStorage, system::BondSystem, j, L = bond.neighbor, bond.length ΔXij = get_diff(system.position, i, j) Δxij = get_diff(storage.position, i, j) - ωij = influence_function(mat, params, L) * bond_active[bond_id] + ωij = kernel(system, bond_id) * bond_active[bond_id] ω0 += ωij temp = ωij * volume[j] K += temp * (ΔXij * ΔXij') @@ -209,7 +207,7 @@ function c_force_density!(storage::CStorage, system::BondSystem, mat::CMaterial, stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) # stabilization - ωij = influence_function(mat, params, L) * bond_active[bond_id] + ωij = kernel(system, bond_id) * bond_active[bond_id] tzem = Cs .* params.bc * ωij / ω0 .* (Δxij .- F * ΔXij) # update of force density diff --git a/src/physics/ordinary_state_based.jl b/src/physics/ordinary_state_based.jl index e1ff8639..b38ff773 100644 --- a/src/physics/ordinary_state_based.jl +++ b/src/physics/ordinary_state_based.jl @@ -54,9 +54,15 @@ When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with - `damage::Vector{Float64}`: Damage of each point - `n_active_bonds::Vector{Int}`: Number of intact bonds of each point """ -struct OSBMaterial{Correction} <: AbstractBondSystemMaterial{Correction} end +struct OSBMaterial{Correction,K} <: AbstractBondSystemMaterial{Correction} + kernel::K + function OSBMaterial{Correction}(kernel::K) where {Correction,K} + return new{Correction,K}(kernel) + end +end -OSBMaterial() = OSBMaterial{NoCorrection}() +OSBMaterial{C}(; kernel::F=linear_kernel) where{C,F} = OSBMaterial{C}(kernel) +OSBMaterial(; kwargs...) = OSBMaterial{NoCorrection}(; kwargs...) struct OSBPointParameters <: AbstractPointParameters δ::Float64 @@ -115,7 +121,7 @@ function force_density_point!(storage::OSBStorage, system::BondSystem, mat::OSBM l = norm(Δxij) ε = (l - L) / L stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - p_int = influence_function(mat, params, L) * bond_failure(storage, bond_id) * + p_int = kernel(system, bond_id) * bond_failure(storage, bond_id) * surface_correction_factor(system.correction, bond_id) * (c2 * L + c1 * (l - L)) / l .* Δxij update_add_b_int!(storage, i, p_int .* system.volume[j]) @@ -140,7 +146,7 @@ function force_density_point!(storage::OSBStorage, system::BondSystem, mat::OSBM params_j = get_params(paramhandler, j) c1 = 15.0 * (params_i.G + params_j.G) / (2 * wvol) c2 = dil * (3.0 * (params_i.K + params_j.K) / (2 * wvol) - c1 / 3.0) - p_int = influence_function(mat, params_i, L) * bond_failure(storage, bond_id) * + p_int = kernel(system, bond_id) * bond_failure(storage, bond_id) * surface_correction_factor(system.correction, bond_id) * (c2 * L + c1 * (l - L)) / l .* Δxij update_add_b_int!(storage, i, p_int .* system.volume[j]) @@ -149,10 +155,6 @@ function force_density_point!(storage::OSBStorage, system::BondSystem, mat::OSBM return nothing end -@inline function influence_function(::OSBMaterial, params::OSBPointParameters, L) - return params.δ / L -end - function calc_weighted_volume(storage::OSBStorage, system::BondSystem, mat::OSBMaterial, params::OSBPointParameters, i) wvol = 0.0 @@ -162,7 +164,7 @@ function calc_weighted_volume(storage::OSBStorage, system::BondSystem, mat::OSBM ΔXij = get_coordinates_diff(system, i, j) ΔXij_sq = dot(ΔXij, ΔXij) scfactor = surface_correction_factor(system.correction, bond_id) - ωij = influence_function(mat, params, L) * storage.bond_active[bond_id] * scfactor + ωij = kernel(system, bond_id) * storage.bond_active[bond_id] * scfactor wvol += ωij * ΔXij_sq * system.volume[j] end return wvol @@ -178,7 +180,7 @@ function calc_dilatation(storage::OSBStorage, system::BondSystem, mat::OSBMateri Δxij = get_coordinates_diff(storage, i, j) l = norm(Δxij) scfactor = surface_correction_factor(system.correction, bond_id) - ωij = influence_function(mat, params, L) * storage.bond_active[bond_id] * scfactor + ωij = kernel(system, bond_id) * storage.bond_active[bond_id] * scfactor dil += ωij * c1 * L * (l - L) * system.volume[j] end return dil From fd39126e741d35bd8a6d892b2364928aaa9b5eca Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Mon, 18 Nov 2024 14:53:01 +0100 Subject: [PATCH 29/40] Working draft / wave speed wrong --- src/Peridynamics.jl | 5 +- src/physics/ns_correspondence.jl | 508 ++++++++++++++++++++ src/physics/rk_correspondence.jl | 299 ++++++------ test/integration/b_int_rk_correspondence.jl | 44 ++ test/physics/test_rk_correspondence.jl | 206 ++++++++ 5 files changed, 902 insertions(+), 160 deletions(-) create mode 100644 src/physics/ns_correspondence.jl create mode 100644 test/integration/b_int_rk_correspondence.jl create mode 100644 test/physics/test_rk_correspondence.jl diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index 01f1b747..9e32a342 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -9,7 +9,8 @@ end import LibGit2, Dates # Material models -export BBMaterial, OSBMaterial, CMaterial, BACMaterial, RKCMaterial, CKIMaterial +export BBMaterial, OSBMaterial, CMaterial, BACMaterial, RKCMaterial, NSCMaterial, + CKIMaterial # CMaterial related types export NeoHookeNonlinear, SaintVenantKirchhoff, ZEMSilling @@ -98,6 +99,7 @@ include("discretization/body.jl") include("discretization/multibody_setup.jl") include("discretization/decomposition.jl") include("discretization/chunk_handler.jl") +include("discretization/kernels.jl") include("discretization/bond_system.jl") include("discretization/bond_system_corrections.jl") include("discretization/zem_stabilization.jl") @@ -127,6 +129,7 @@ include("physics/continuum_kinematics_inspired.jl") include("physics/ordinary_state_based.jl") include("physics/constitutive_models.jl") include("physics/correspondence.jl") +include("physics/ns_correspondence.jl") include("physics/ba_correspondence.jl") include("physics/rk_correspondence.jl") diff --git a/src/physics/ns_correspondence.jl b/src/physics/ns_correspondence.jl new file mode 100644 index 00000000..75e4f338 --- /dev/null +++ b/src/physics/ns_correspondence.jl @@ -0,0 +1,508 @@ +""" + NSCMaterial(; maxdmg, zem) + +A material type used to assign the material of a [`Body`](@ref) with the local continuum +consistent (correspondence) formulation of non-ordinary state-based peridynamics. + +# Keywords +- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is + exceeded, all bonds of that point are broken because the deformation gradient would then + possibly contain `NaN` values. + (default: `0.95`) + +# Examples + +```julia-repl +julia> mat = NSCMaterial() +NSCMaterial(maxdmg=0.95) +``` + +--- + +```julia +NSCMaterial +``` + +Material type for the local continuum consistent (correspondence) formulation of +non-ordinary state-based peridynamics. + +# Fields +- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. See the + constructor docs for more informations. + +# Allowed material parameters +When using [`material!`](@ref) on a [`Body`](@ref) with `NSCMaterial`, then the following +parameters are allowed: +- `horizon::Float64`: Radius of point interactions +- `rho::Float64`: Density +- `E::Float64`: Young's modulus +- `nu::Float64`: Poisson's ratio +- `Gc::Float64`: Critical energy release rate +- `epsilon_c::Float64`: Critical strain + +# Allowed export fields +When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with +`NSCMaterial`, the following fields are allowed: +- `position::Matrix{Float64}`: Position of each point +- `displacement::Matrix{Float64}`: Displacement of each point +- `velocity::Matrix{Float64}`: Velocity of each point +- `velocity_half::Matrix{Float64}`: Velocity parameter for Verlet time solver +- `acceleration::Matrix{Float64}`: Acceleration of each point +- `b_int::Matrix{Float64}`: Internal force density of each point +- `b_ext::Matrix{Float64}`: External force density of each point +- `damage::Vector{Float64}`: Damage of each point +- `n_active_bonds::Vector{Int}`: Number of intact bonds of each point +""" +struct NSCMaterial{CM,K} <: AbstractCorrespondenceMaterial{CM,NoCorrection} + kernel::K + constitutive_model::CM + maxdmg::Float64 + function NSCMaterial(kernel::K, cm::CM, maxdmg::Real) where {CM,K} + return new{CM,K}(cm, maxdmg) + end +end + +function Base.show(io::IO, @nospecialize(mat::NSCMaterial)) + print(io, typeof(mat)) + print(io, msg_fields_in_brackets(mat, (:maxdmg,))) + return nothing +end + +function NSCMaterial(; kernel::Function=cubic_b_spline, + model::AbstractConstitutiveModel=SaintVenantKirchhoff(), + maxdmg::Real=0.85) + return NSCMaterial(kernel, model, maxdmg) +end + +struct NSCPointParameters <: AbstractPointParameters + δ::Float64 + rho::Float64 + E::Float64 + nu::Float64 + G::Float64 + K::Float64 + λ::Float64 + μ::Float64 + Gc::Float64 + εc::Float64 + bc::Float64 +end + +function NSCPointParameters(mat::NSCMaterial, p::Dict{Symbol,Any}) + (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) + (; Gc, εc) = get_frac_params(p, δ, K) + bc = 18 * K / (π * δ^4) # bond constant + return NSCPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) +end + +@params NSCMaterial NSCPointParameters + +@storage NSCMaterial struct NSCStorage + @lthfield position::Matrix{Float64} + @pointfield displacement::Matrix{Float64} + @pointfield velocity::Matrix{Float64} + @pointfield velocity_half::Matrix{Float64} + @pointfield velocity_half_old::Matrix{Float64} + @pointfield acceleration::Matrix{Float64} + @htlfield b_int::Matrix{Float64} + @pointfield b_int_old::Matrix{Float64} + @pointfield b_ext::Matrix{Float64} + @pointfield density_matrix::Matrix{Float64} + @pointfield damage::Vector{Float64} + bond_active::Vector{Bool} + @pointfield n_active_bonds::Vector{Int} + @pointfield damage_changed::Vector{Bool} + @pointfield stress::Matrix{Float64} + @pointfield von_mises_stress::Vector{Float64} + @lthfield defgrad::Matrix{Float64} + @lthfield weighted_volume::Vector{Float64} + gradient_weight::Matrix{Float64} +end + +function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int}) + return zeros(3, get_n_points(system)) +end + +function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:damage_changed}) + return ones(Bool, get_n_loc_points(system)) +end + +function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:stress}) + return zeros(9, get_n_loc_points(system)) +end + +function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:von_mises_stress}) + return zeros(get_n_loc_points(system)) +end + +function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:defgrad}) + return zeros(9, get_n_points(system)) +end + +function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:weighted_volume}) + return zeros(get_n_points(system)) +end + +function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:gradient_weight}) + return zeros(3, get_n_bonds(system)) +end + +function initialize!(chunk::BodyChunk{<:BondSystem,<:NSCMaterial}) + chunk.storage.damage_changed .= true + return nothing +end + +@inline function calc_damage!(chunk::BodyChunk{<:BondSystem,<:NSCMaterial}) + (; n_neighbors) = chunk.system + (; n_active_bonds, damage, damage_changed) = chunk.storage + for point_id in each_point_idx(chunk) + old_damage = damage[point_id] + new_damage = 1 - n_active_bonds[point_id] / n_neighbors[point_id] + if new_damage > old_damage + damage_changed[point_id] = true + else + damage_changed[point_id] = false + end + damage[point_id] = new_damage + end + return nothing +end + +function calc_force_density!(dh::ThreadsBodyDataHandler{<:BondSystem,<:NSCMaterial}, t, Δt) + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_loc_to_halo!(dh, chunk_id, :position) + end + @threads :static for chunk_id in eachindex(dh.chunks) + calc_weights_and_defgrad!(dh.chunks[chunk_id], t, Δt) + end + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_loc_to_halo!(dh, chunk_id, (:defgrad, :weighted_volume)) + end + @threads :static for chunk_id in eachindex(dh.chunks) + chunk = dh.chunks[chunk_id] + calc_force_density!(chunk, t, Δt) + # nancheck(chunk, t) + end + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_halo_to_loc!(dh, chunk_id) + end + return nothing +end + +function calc_force_density!(dh::MPIBodyDataHandler{<:BondSystem,<:NSCMaterial}, t, Δt) + (; chunk) = dh + exchange_loc_to_halo!(dh, :position) + calc_weights_and_defgrad!(chunk, t, Δt) + exchange_loc_to_halo!(dh, (:defgrad, :weighted_volume)) + calc_force_density!(chunk, t, Δt) + nancheck(chunk, t) + exchange_halo_to_loc!(dh) + return nothing +end + +function calc_weights_and_defgrad!(chunk::BodyChunk{<:BondSystem,<:NSCMaterial}, t, Δt) + (; system, mat, paramsetup, storage) = chunk + for i in each_point_idx(system) + calc_weights_and_defgrad!(storage, system, mat, paramsetup, t, Δt, i) + end + return nothing +end + +function calc_weights_and_defgrad!(storage::NSCStorage, system::BondSystem, + mat::NSCMaterial, paramhandler::AbstractParameterHandler, + t, Δt, i) + params = get_params(paramhandler, i) + calc_weights_and_defgrad!(storage, system, mat, params, t, Δt, i) + return nothing +end + +function calc_weights_and_defgrad!(storage::NSCStorage, system::BondSystem, + mat::NSCMaterial, params::NSCPointParameters, t, Δt, i) + (; bonds, volume) = system + (; bond_active, weighted_volume, gradient_weight, damage_changed) = storage + + K = zero(SMatrix{3,3,Float64,9}) + _F = zero(SMatrix{3,3,Float64,9}) + wi = 0.0 + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j = bond.neighbor + ΔXij = get_diff(system.position, i, j) + Δxij = get_diff(storage.position, i, j) + ωij = kernel(system, bond_id) * bond_active[bond_id] + temp = ωij * volume[j] + K += temp * (ΔXij * ΔXij') + _F += temp * (Δxij * ΔXij') + wi += temp + end + Kinv = inv(K) + F = _F * Kinv + update_tensor!(storage.defgrad, i, F) + weighted_volume[i] = wi + + damage_changed[i] || return nothing + + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j = bond.neighbor + ΔXij = get_diff(system.position, i, j) + ωij = kernel(system, bond_id) * bond_active[bond_id] + temp = ωij * volume[j] + Ψ = temp * (Kinv * ΔXij) + update_vector!(gradient_weight, bond_id, Ψ) + end + + return nothing +end + +@inline function influence_function(::NSCMaterial, params::NSCPointParameters, L) + ξ = L / params.δ + if 0 < ξ ≤ 0.5 + return 2/3 - 4 * ξ^2 + 4 * ξ^3 + elseif 0.5 < ξ ≤ 1 + return 4/3 - 4 * ξ + 4 * ξ^2 - 4/3 * ξ^3 + else + return 0 + end +end + +function force_density_point!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, + paramhandler::AbstractParameterHandler, t, Δt, i) + params = get_params(paramhandler, i) + force_density_point!(storage, system, mat, params, t, Δt, i) + return nothing +end + +function force_density_point!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, + params::NSCPointParameters, t, Δt, i) + Fi = get_tensor(storage.defgrad, i) + too_much_damage!(storage, system, mat, Fi, i) && return nothing + P = calc_first_piola_kirchhoff!(storage, mat, params, Fi, Δt, i) + nsc_force_density!(storage, system, mat, params, P, i) + return nothing +end + +function calc_first_piola_kirchhoff!(storage::NSCStorage, mat::NSCMaterial, + params::NSCPointParameters, F, Δt, i) + P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) + σ = cauchy_stress(P, F) + update_tensor!(storage.stress, i, σ) + storage.von_mises_stress[i] = von_mises_stress(σ) + return P +end + +function calc_first_piola_kirchhoff(storage::NSCStorage, mat::NSCMaterial, + params::NSCPointParameters, F) + P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) + return P +end + +# Working version!!! +function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, + params::NSCPointParameters, P::SMatrix, i) + (; bonds, volume) = system + (; bond_active, gradient_weight) = storage + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j, L = bond.neighbor, bond.length + Δxij = get_coordinates_diff(storage, i, j) + l = norm(Δxij) + ε = (l - L) / L + stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + if bond_active[bond_id] + Ψ = get_vector(gradient_weight, bond_id) + tij = (P * Ψ) / volume[j] + update_add_b_int!(storage, i, tij .* volume[j]) + update_add_b_int!(storage, j, -tij .* volume[i]) + end + end + return nothing +end + +# NODALLY STABLIZIED VERSION!!! WORKING, BUT NOT SURE IF CORRECT! +# function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, +# params::NSCPointParameters, P::SMatrix, i) +# (; bonds, volume) = system +# (; bond_active, gradient_weight, defgrad) = storage +# Fi = get_tensor(defgrad, i) +# too_much_damage!(storage, system, mat, Fi, i) && return nothing +# for bond_id in each_bond_idx(system, i) +# bond = bonds[bond_id] +# j, L = bond.neighbor, bond.length +# Δxij = get_coordinates_diff(storage, i, j) +# l = norm(Δxij) +# ε = (l - L) / L +# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) +# if bond_active[bond_id] +# ΔXij = get_coordinates_diff(system, i, j) +# Fj = get_tensor(defgrad, j) +# Fb = 0.5 * (Fi + Fj) +# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) +# Fij = Fb + ΔFij +# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) +# Ψ = get_vector(gradient_weight, bond_id) +# tij = (Pij * Ψ) / volume[j] +# update_add_b_int!(storage, i, tij .* volume[j]) +# update_add_b_int!(storage, j, -tij .* volume[i]) +# end +# end +# return nothing +# end + + +# PERIDIGM VERSION +# function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, +# params::NSCPointParameters, P::SMatrix, i) +# (; bonds, volume) = system +# (; bond_active, gradient_weight, defgrad, weighted_volume) = storage +# Fi = get_tensor(defgrad, i) +# wi = weighted_volume[i] +# SI = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) +# for bond_id in each_bond_idx(system, i) +# bond = bonds[bond_id] +# j, L = bond.neighbor, bond.length +# ΔXij = get_coordinates_diff(system, i, j) +# Δxij = get_coordinates_diff(storage, i, j) +# l = norm(Δxij) +# ε = (l - L) / L +# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + +# Fj = get_tensor(defgrad, j) +# Fb = 0.5 * (Fi + Fj) +# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) +# Fij = Fb + ΔFij +# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) +# # update_tensor!(first_piola_kirchhoff, bond_id, Pij) +# # ΔPij = Pij - Pi +# Tempij = (I - ΔXij * ΔXij') / (L * L) +# ωij = influence_function(mat, params, L) * bond_active[bond_id] +# wj = weighted_volume[j] +# ϕ = volume[j] * ωij * (0.5 / wi + 0.5 / wj) +# SI += ϕ * (Pij * Tempij) +# end +# for bond_id in each_bond_idx(system, i) +# bond = bonds[bond_id] +# j, L = bond.neighbor, bond.length +# ΔXij = get_coordinates_diff(system, i, j) +# Δxij = get_coordinates_diff(storage, i, j) +# Fj = get_tensor(defgrad, j) +# Fb = 0.5 * (Fi + Fj) +# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) +# Fij = Fb + ΔFij +# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) +# Φij = get_vector(gradient_weight, bond_id) +# ωij = influence_function(mat, params, L) * bond_active[bond_id] +# tij = (SI * Φij) / volume[j] + ωij / (wi * L * L) * (Pij * ΔXij) +# update_add_b_int!(storage, i, tij * volume[j]) +# update_add_b_int!(storage, j, -tij * volume[i]) +# end +# return nothing +# end + +# NODALLY STABLIZIED VERSION WRONG? +# function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, +# params::NSCPointParameters, P::SMatrix, i) +# (; bonds, volume) = system +# (; bond_active, gradient_weight, defgrad, weighted_volume) = storage +# Fi = get_tensor(defgrad, i) +# Vi = volume[i] +# wi = weighted_volume[i] + +# for bond_id_j in each_bond_idx(system, i) +# bond_ij = bonds[bond_id_j] +# j, Lij = bond_ij.neighbor, bond_ij.length +# ΔXij = get_coordinates_diff(storage, i, j) +# Δxij = get_coordinates_diff(storage, i, j) +# lij = norm(Δxij) +# ε = (lij - Lij) / Lij +# stretch_based_failure!(storage, system, bond_ij, params, ε, i, bond_id_j) + +# ωij = influence_function(mat, params, Lij) +# Vj, wj = volume[j], weighted_volume[j] +# Ṽij = (Vi * Vj) / 2 * (ωij / wj + ωij / wi) +# Ψij = get_vector(gradient_weight, bond_id_j) +# Fj = get_tensor(defgrad, j) +# Fij = 0.5 * (Fi + Fj) +# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) + +# Tcor = Ṽij * (Pij * ΔXij) / (Vj * Vi * Lij * Lij) + +# Tave = zero(SVector{3,Float64}) +# for bond_id_k in each_bond_idx(system, i) +# bond_ik = bonds[bond_id_k] +# k, Lik = bond_ik.neighbor, bond_ik.length +# ωik = influence_function(mat, params, Lik) +# Vk, wk = volume[k], weighted_volume[k] +# Ṽik = (Vi * Vk) / 2 * (ωik / wk + ωij / wi) +# Fk = get_tensor(defgrad, k) +# Fik = 0.5 * (Fi + Fk) +# Pik = calc_first_piola_kirchhoff(storage, mat, params, Fik) +# Tave += Ṽik * (Pik * Ψij) / (Vj * Vi) +# ΔXΔXΨ = (ΔXij * ΔXij') * Ψij +# Tcor -= Ṽik * (Pik * ΔXΔXΨ) / (Vj * Vi * Lik * Lik) +# end + +# T = Tave + Tcor +# update_add_b_int!(storage, i, T .* volume[j]) +# update_add_b_int!(storage, j, -T .* volume[i]) +# end +# return nothing +# end + + # Tcor2 = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + # for bond_id in each_bond_idx(system, i) + # bond = bonds[bond_id] + # j, L = bond.neighbor, bond.length + # ΔXij = get_coordinates_diff(system, i, j) + # Δxij = get_coordinates_diff(storage, i, j) + # l = norm(Δxij) + # ε = (l - L) / L + # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + + # if bond_active[bond_id] + # ωij = influence_function(mat, params, L) + # Vj, wj = volume[j], weighted_volume[j] + # Ṽij = (Vi * Vj) / 2 * (ωij / wi + ωij / wj) + + # Fj = get_tensor(defgrad, j) + # Fb = 0.5 * (Fi + Fj) + # Pb = calc_first_piola_kirchhoff(storage, mat, params, Fb) + + # temp = Ṽij / (Vi * Vj * L * L) + # Ψ = get_vector(gradient_weight, bond_id) + # ΔXΨ = (ΔXij * ΔXij') * Ψ + # Tcor2 += temp * (P * ΔXΨ) + # end + # end + + # for bond_id in each_bond_idx(system, i) + # if bond_active[bond_id] + # bond = bonds[bond_id] + # j, L = bond.neighbor, bond.length + # ΔXij = get_coordinates_diff(system, i, j) + # Δxij = get_coordinates_diff(storage, i, j) + + # # update of force density + # Ψ = get_vector(gradient_weight, bond_id) + # tij = (P * Ψ) / volume[j] + # update_add_b_int!(storage, i, tij .* volume[j]) + # update_add_b_int!(storage, j, -tij .* volume[i]) + # end + # end +# return nothing +# end + +function too_much_damage!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, F, i) + if storage.damage[i] > mat.maxdmg || containsnan(F) + # kill all bonds of this point + storage.bond_active[each_bond_idx(system, i)] .= false + storage.n_active_bonds[i] = 0 + return true + end + return false +end diff --git a/src/physics/rk_correspondence.jl b/src/physics/rk_correspondence.jl index 40e0a29f..124dac62 100644 --- a/src/physics/rk_correspondence.jl +++ b/src/physics/rk_correspondence.jl @@ -63,12 +63,13 @@ When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with - `damage::Vector{Float64}`: Damage of each point - `n_active_bonds::Vector{Int}`: Number of intact bonds of each point """ -struct RKCMaterial{CM} <: AbstractCorrespondenceMaterial{CM,NoCorrection} +struct RKCMaterial{CM,K} <: AbstractCorrespondenceMaterial{CM,NoCorrection} + kernel::K constitutive_model::CM maxdmg::Float64 accuracy_order::Int - function RKCMaterial(cm::CM, maxdmg::Real, accuracy_order::Int) where {CM} - return new{CM}(cm, maxdmg, accuracy_order) + function RKCMaterial(kernel::K, cm::CM, maxdmg::Real, accuracy_order::Int) where {CM,K} + return new{CM,K}(kernel, cm, maxdmg, accuracy_order) end end @@ -78,9 +79,10 @@ function Base.show(io::IO, @nospecialize(mat::RKCMaterial)) return nothing end -function RKCMaterial(; model::AbstractConstitutiveModel=SaintVenantKirchhoff(), +function RKCMaterial(; kernel::Function=cubic_b_spline, + model::AbstractConstitutiveModel=SaintVenantKirchhoff(), maxdmg::Real=0.85, accuracy_order::Int=2) - return RKCMaterial(model, maxdmg, accuracy_order) + return RKCMaterial(kernel, model, maxdmg, accuracy_order) end struct RKCPointParameters <: AbstractPointParameters @@ -127,6 +129,7 @@ end @lthfield defgrad::Matrix{Float64} @lthfield weighted_volume::Vector{Float64} gradient_weight::Matrix{Float64} + first_piola_kirchhoff::Matrix{Float64} end # function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, @@ -167,10 +170,10 @@ function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, return zeros(3, get_n_bonds(system)) end -# function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, -# ::Val{:first_piola_kirchhoff}) -# return zeros(9, get_n_points(system)) -# end +function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:first_piola_kirchhoff}) + return zeros(9, get_n_bonds(system)) +end function initialize!(chunk::BodyChunk{<:BondSystem,<:RKCMaterial}) chunk.storage.damage_changed .= true @@ -214,14 +217,13 @@ function calc_force_density!(dh::ThreadsBodyDataHandler{<:BondSystem,<:RKCMateri return nothing end -#TODO function calc_force_density!(dh::MPIBodyDataHandler{<:BondSystem,<:RKCMaterial}, t, Δt) (; chunk) = dh exchange_loc_to_halo!(dh) calc_weights_and_defgrad!(chunk, t, Δt) - exchange_loc_to_halo!(dh, :defgrad) + exchange_loc_to_halo!(dh, (:defgrad, :weighted_volume)) calc_force_density!(chunk, t, Δt) - forcedensity_nancheck(chunk, t) + nancheck(chunk, t) exchange_halo_to_loc!(dh) return nothing end @@ -252,16 +254,16 @@ function calc_gradient_weights!(storage::RKCStorage, system::BondSystem, mat::RK wi = 0.0 for bond_id in each_bond_idx(system, i) bond = bonds[bond_id] - j, L = bond.neighbor, bond.length + j = bond.neighbor ΔXij = get_diff(system.position, i, j) - Q = get_q_vector(accuracy_order, ΔXij, δ) - ωij = influence_function(mat, params, L) * bond_active[bond_id] + Q = get_monomial_vector(accuracy_order, ΔXij, δ) + ωij = kernel(system, bond_id) * bond_active[bond_id] temp = ωij * volume[j] - # M += temp * (Q * Q') / δ M += temp * (Q * Q') wi += temp end weighted_volume[i] = wi + # @infiltrate # calculate inverse of moment matrix, must be a full rank matrix! # regularization_term = 1e-6 * δ * δ * δ @@ -270,21 +272,21 @@ function calc_gradient_weights!(storage::RKCStorage, system::BondSystem, mat::RK U, S, V = svd(M) threshold = 1e-6 * δ * δ * δ _S_ = SVector{q_dim,Float64}((s > threshold ? s : 0) for s in S) - Sinv = Diagonal{Float64,SVector{9,Float64}}(_S_) + Sinv = Diagonal{Float64,SVector{q_dim,Float64}}(_S_) Minv = V * Sinv * U' # calculate gradient weights Φ for bond_id in each_bond_idx(system, i) bond = bonds[bond_id] - j, L = bond.neighbor, bond.length + j = bond.neighbor ΔXij = get_diff(system.position, i, j) - Q = get_q_vector(accuracy_order, ΔXij, δ) - ωij = influence_function(mat, params, L) * bond_active[bond_id] + Q = get_monomial_vector(accuracy_order, ΔXij, δ) + ωij = kernel(system, bond_id) * bond_active[bond_id] + # temp = ωij * volume[j] + temp = ωij / δ * volume[j] MinvQ = Minv * Q - Φ = ωij * (Q∇ᵀ * MinvQ) - gradient_weight[1, bond_id] = Φ[1] - gradient_weight[2, bond_id] = Φ[2] - gradient_weight[3, bond_id] = Φ[3] + Φ = temp * (Q∇ᵀ * MinvQ) + update_vector!(gradient_weight, bond_id, Φ) end end end @@ -313,54 +315,32 @@ end @inline get_q_dim(accuracy_order) = length(each_monomial(accuracy_order)) -@inline get_q_vector(N::Int, ΔX::AbstractArray, δ::Real) = get_q_vector(Val(N), ΔX, δ) +@inline function get_monomial_vector(N::Int, ΔX::AbstractArray, δ::Real) + return get_monomial_vector(Val(N), ΔX, δ) +end -@inline function get_q_vector(n::Val{N}, ΔX::AbstractArray, δ::Real) where {N} +@inline function get_monomial_vector(n::Val{N}, ΔX::AbstractArray, δ::Real) where {N} a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ _Q = (a1^p1 * a2^p2 * a3^p3 for (p1, p2, p3) in each_monomial(n)) q_dims = get_q_dim(n) - Q = SVector{q_dims}(_Q...) + Q = SVector{q_dims,eltype(ΔX)}(_Q...) return Q end -@inline function get_q_vector(::Val{1}, ΔX::AbstractArray, δ::Real) +@inline function get_monomial_vector(::Val{1}, ΔX::AbstractArray, δ::Real) a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ - Q = SVector{3}(a1, a2, a3) + Q = SVector{3,eltype(ΔX)}(a1, a2, a3) return Q end -@inline function get_q_vector(::Val{2}, ΔX::AbstractArray, δ::Real) +@inline function get_monomial_vector(::Val{2}, ΔX::AbstractArray, δ::Real) a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ - Q = SVector{9}(a1, a2, a3, a1*a1, a1*a2, a1*a3, a2*a2, a2*a3, a3*a3) + Q = SVector{9,eltype(ΔX)}(a1, a2, a3, a1*a1, a1*a2, a1*a3, a2*a2, a2*a3, a3*a3) + # a1, a2, a3 = ΔX[1], ΔX[2], ΔX[3] # Q = SVector{9}(a1, a2, a3, a1*a1, a2*a2, a3*a3, a1*a2, a1*a3, a2*a3) return Q end -# function get_q_vector2(accuracy_order::Int, ΔX::AbstractArray, δ::Real) -# q_dim = get_q_dim(accuracy_order) -# Q = @MVector zeros(Float64, q_dim) -# counter = 1 -# for this_order in 1:accuracy_order -# for p1 in this_order:-1:0 -# for p2 in (this_order - p1):-1:0 -# p3 = this_order - p1 - p2 -# Q[counter] = 1.0 -# for _ in 1:p1 -# Q[counter] *= ΔX[1] / δ -# end -# for _ in 1:p2 -# Q[counter] *= ΔX[2] / δ -# end -# for _ in 1:p3 -# Q[counter] *= ΔX[3] / δ -# end -# counter += 1 -# end -# end -# end -# return Q -# end - @inline get_q_triangle(N::Int) = get_q_triangle(Val(N)) function get_q_triangle(::Val{1}) @@ -391,22 +371,52 @@ end function calc_deformation_gradients!(storage::RKCStorage, system::BondSystem, ::RKCMaterial, ::AbstractParameterSetup, t, Δt) (; bonds, volume) = system - (; gradient_weight, defgrad) = storage + (; gradient_weight, defgrad, bond_active) = storage for i in each_point_idx(system) - # F = zero(SMatrix{3,3,Float64,9}) + I + ## RK F = SMatrix{3,3,Float64,9}(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) + # F = MMatrix{3,3,Float64,9}(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) for bond_id in each_bond_idx(system, i) - bond = bonds[bond_id] - j = bond.neighbor - ΔXij = get_vector_diff(system.position, i, j) - Δxij = get_vector_diff(storage.position, i, j) - ΔUij = Δxij - ΔXij - Φij = get_vector(gradient_weight, bond_id) - F += (ΔUij * Φij') * volume[j] + if bond_active[bond_id] + bond = bonds[bond_id] + j = bond.neighbor + ΔXij = get_vector_diff(system.position, i, j) + Δxij = get_vector_diff(storage.position, i, j) + ΔUij = Δxij - ΔXij + Φij = get_vector(gradient_weight, bond_id) + F += (ΔUij * Φij') * volume[j] + # #-- + # for m ∈ axes(F, 1) + # for n ∈ axes(F, 2) + # F[n, m] += ΔUij[m] * Φij[n] * volume[j] + # end + # end + #-- + end end + # _F = SMatrix{3,3,Float64,9}(F) + # update_tensor!(defgrad, i, _F) update_tensor!(defgrad, i, F) + + ## correspondence + # K = zero(SMatrix{3,3,Float64,9}) + # _F = zero(SMatrix{3,3,Float64,9}) + # for bond_id in each_bond_idx(system, i) + # bond = bonds[bond_id] + # j = bond.neighbor + # ΔXij = get_vector_diff(system.position, i, j) + # Δxij = get_vector_diff(storage.position, i, j) + # ωij = kernel(system, bond_id) #* storage.bond_active[bond_id] + # temp = ωij * volume[j] + # K += temp * (ΔXij * ΔXij') + # _F += temp * (Δxij * ΔXij') + # end + # Kinv = inv(K) + # F = _F * Kinv + # update_tensor!(defgrad, i, F) end + return nothing end @@ -421,64 +431,33 @@ function force_density_point!(storage::RKCStorage, system::BondSystem, mat::RKCM params::RKCPointParameters, t, Δt, i) (; bonds, volume) = system (; gradient_weight, defgrad, bond_active, weighted_volume) = storage + (; first_piola_kirchhoff) = storage Fi = get_tensor(defgrad, i) - # println("Deformation gradient Fi at point $i:") - # display(Fi) - - # too_much_damage!(storage, system, mat, Fi, i) && return nothing - if too_much_damage!(storage, system, mat, Fi, i) - # println("Too much damage at point $i") - return nothing - end - - Pi = calc_first_piola_kirchhoff(storage, mat, params, Fi) - # println("First Piola Kirchhoff stress tensor Pi at point $i:") - # display(Pi) + too_much_damage!(storage, system, mat, Fi, i) && return nothing + # Pi = calc_first_piola_kirchhoff(storage, mat, params, Fi) # Standard RK - for bond_id in each_bond_idx(system, i) - bond = bonds[bond_id] - j, L = bond.neighbor, bond.length - Δxij = get_coordinates_diff(storage, i, j) - l = norm(Δxij) - ε = (l - L) / L - stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - - # if bond_active[bond_id] - Φij = get_vector(gradient_weight, bond_id) - Fj = get_tensor(defgrad, j) - Pj = calc_first_piola_kirchhoff(storage, mat, params, Fj) - ΔPij = Pj - Pi - tij = (ΔPij * Φij) * volume[j] - update_add_b_int!(storage, i, tij) - # end - end - - # BA-Stabilized RK # for bond_id in each_bond_idx(system, i) # bond = bonds[bond_id] # j, L = bond.neighbor, bond.length - # ΔXij = get_coordinates_diff(system, i, j) # Δxij = get_coordinates_diff(storage, i, j) # l = norm(Δxij) # ε = (l - L) / L # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - # Φij = get_vector(gradient_weight, bond_id) - # Fj = get_tensor(defgrad, j) - # ΔFij = (Δxij - 0.5 * (Fi + Fj) * ΔXij) * ΔXij' / (L * L) - # # Fij = Fj + ΔFij - # Fij = 0.5 * (Fi + Fj) + ΔFij - # Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) * bond_active[bond_id] - # ΔPij = Pij - Pi - # tij = (ΔPij * Φij) * volume[j] - # update_add_b_int!(storage, i, tij) + # # if bond_active[bond_id] + # Φij = get_vector(gradient_weight, bond_id) + # # Fj = get_tensor(defgrad, j) + # # Pj = calc_first_piola_kirchhoff(storage, mat, params, Fj) + # # ΔPij = Pj - Pi + # # tij = (ΔPij * Φij) * volume[j] #* bond_active[bond_id] + # tij = (Pi * Φij) / volume[j] #* bond_active[bond_id] + # update_add_b_int!(storage, i, tij * volume[j]) + # update_add_b_int!(storage, j, -tij * volume[i]) + # # end # end - # Nodal quadrature - # Stress integral SI - # wi = weighted_volume[i] - # SI = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + # BA-Stabilized RK # for bond_id in each_bond_idx(system, i) # bond = bonds[bond_id] # j, L = bond.neighbor, bond.length @@ -488,53 +467,61 @@ function force_density_point!(storage::RKCStorage, system::BondSystem, mat::RKCM # ε = (l - L) / L # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - # if bond_active[bond_id] - # Fj = get_tensor(defgrad, j) - # Fb = 0.5 * (Fi + Fj) - # ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) - # Fij = Fb + ΔFij - # Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) - # ΔPij = Pij - Pi - # Tempij = I - ΔXij * ΔXij' / (L * L) - # wj = weighted_volume[j] - # ϕ = influence_function(mat, params, L) * (0.5 / wi + 0.5 / wj) * volume[j] - # SI += ϕ * (ΔPij * Tempij) - # end + # Φij = get_vector(gradient_weight, bond_id) + # Fj = get_tensor(defgrad, j) + # Fb = 0.5 * (Fi + Fj) + # ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) + # Fij = Fj + ΔFij + # Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) * bond_active[bond_id] + # tij = (Pij * Φij) + # update_add_b_int!(storage, i, tij * volume[j]) + # update_add_b_int!(storage, j, -(Pi * Φij) * volume[i]) # end - # for bond_id in each_bond_idx(system, i) - # if bond_active[bond_id] - # bond = bonds[bond_id] - # j, L = bond.neighbor, bond.length - # ΔXij = get_coordinates_diff(system, i, j) - # Δxij = get_coordinates_diff(storage, i, j) - # Fj = get_tensor(defgrad, j) - # Fb = 0.5 * (Fi + Fj) - # ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) - # Fij = Fb + ΔFij - # Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) - # ΔPij = Pij - Pi - - # Φij = get_vector(gradient_weight, bond_id) - # ω = influence_function(mat, params, L) - # tij = ω / wi * (ΔPij * Φij) / (L * L) + SI * Φij - # update_add_b_int!(storage, i, tij * volume[j]) - # update_add_b_int!(storage, i, -tij * volume[i]) - # end - # end + # Nodal quadrature peridigm + # Stress integral SI + wi = weighted_volume[i] + SI = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j, L = bond.neighbor, bond.length + ΔXij = get_coordinates_diff(system, i, j) + Δxij = get_coordinates_diff(storage, i, j) + l = norm(Δxij) + ε = (l - L) / L + stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - return nothing -end + # if bond_active[bond_id] + Fj = get_tensor(defgrad, j) + Fb = 0.5 * (Fi + Fj) + ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) + Fij = Fb + ΔFij + Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) + update_tensor!(first_piola_kirchhoff, bond_id, Pij) + Tempij = (I - ΔXij * ΔXij') / (L * L) + ωij = kernel(system, bond_id) * bond_active[bond_id] + wj = weighted_volume[j] + ϕ = volume[j] * ωij * (0.5 / wi + 0.5 / wj) + SI += ϕ * (Pij * Tempij) + # end + end + # @show SI -@inline function influence_function(::RKCMaterial, params::RKCPointParameters, L) - ξ = L / params.δ - if 0 < ξ ≤ 0.5 - return 2/3 - 4 * ξ^2 + 4 * ξ^3 - elseif 0.5 < ξ ≤ 1 - return 4/3 - 4 * ξ + 4 * ξ^2 - 4/3 * ξ^3 - else - return 0 + for bond_id in each_bond_idx(system, i) + if bond_active[bond_id] + bond = bonds[bond_id] + j, L = bond.neighbor, bond.length + ΔXij = get_coordinates_diff(system, i, j) + Pij = get_tensor(first_piola_kirchhoff, bond_id) + Φij = get_vector(gradient_weight, bond_id) + ωij = kernel(system, bond_id) * bond_active[bond_id] + tij = SI * Φij + ωij / (wi * L * L) * (Pij * ΔXij) + update_add_b_int!(storage, i, tij * volume[j]) + update_add_b_int!(storage, j, -tij * volume[i]) + end end + + return nothing end # function calc_deformation_gradient(storage::RKCStorage, system::BondSystem, @@ -554,13 +541,7 @@ end function calc_first_piola_kirchhoff(storage::RKCStorage, mat::RKCMaterial, params::RKCPointParameters, F) - # σ = cauchy_stress(mat.constitutive_model, storage, params, F) - # P = det(F) * σ * inv(F)' - J = det(F) - J < eps() && return zero(SMatrix{3,3}) - E = 0.5 .* (F' * F - I) - S = params.λ * tr(E) * I + 2 * params.μ * E - P = F * S + P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) return P end diff --git a/test/integration/b_int_rk_correspondence.jl b/test/integration/b_int_rk_correspondence.jl new file mode 100644 index 00000000..bcc7b16c --- /dev/null +++ b/test/integration/b_int_rk_correspondence.jl @@ -0,0 +1,44 @@ +@testitem "Internal force density correspondence" begin + # using Peridynamics, Test + ref_position = [0.0 1.0 0.0 + 0.0 0.0 1.0 + 0.0 0.0 0.0] + # ref_position = [0.0 1.0 0.0 0.0 2.0 + # 0.0 0.0 1.0 0.0 2.0 + # 0.0 0.0 0.0 1.0 2.0] + volume = fill(1.0, 3) + δ = 1.5 + body = Body(RKCMaterial(), ref_position, volume) + material!(body, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) + failure_permit!(body, false) + + dh = Peridynamics.threads_data_handler(body, VelocityVerlet(steps=1), 2) + chunk1 = dh.chunks[1] + (; mat, storage, system, paramsetup) = chunk + params = paramsetup + (; position) = storage + position[1, 1] = -0.0015 + + # chunk = dh.chunks[2] + # (; mat, storage, system, paramsetup) = chunk + # params = paramsetup + # (; position, b_int, defgrad) = storage + # # position[1, 3] = 1.0015 + + # @test position == ref_position + # @test b_int == zeros(3, 5) + + # # Boundary Condition: + # # Point 2 with v_z = 1 m/s with Δt = 0.0015 s + # position[1, 2] = 1.0015 + + Peridynamics.calc_force_density!(dh, 0, 0) + + # @test defgrad ≈ 0 + + # @test b_int[:,1] ≈ [0.007185432432164514, 0.0023974081843325646, 0.0023974081843347313] + # @test b_int[:,2] ≈ [-0.007185432432123352, -9.047513544240966e-15, -6.0453612662025915e-15] + # @test b_int[:,3] ≈ [-2.077199268438824e-14, -0.002397408184361381, 3.2228109102914035e-14] + # @test b_int[:,4] ≈ [-2.0389697546832128e-14, 3.786380931014577e-14, -0.002397408184360914] + # @test b_int[:,5] ≈ [0.0, 0.0, 0.0] +end diff --git a/test/physics/test_rk_correspondence.jl b/test/physics/test_rk_correspondence.jl new file mode 100644 index 00000000..7bbdc2f4 --- /dev/null +++ b/test/physics/test_rk_correspondence.jl @@ -0,0 +1,206 @@ +# Write a unit test for the qmatrix calculation of the RKMaterial +@testitem "Monomial vector Q" begin + # CPP code as reference: + # // calculate dimension of Q vector + # Qdim = 0; + # for(thisOrder=1; thisOrder<=accuracyOrder; thisOrder++){ + # for(p1=thisOrder; p1>=0; p1--){ // x-power + # for(p2=thisOrder-p1; p2>=0; p2--){ // y-power + # p3=thisOrder-p1-p2; //z-power + # Qdim++; + # } + # } + # } + # // Calculate Q for this bond + # counter = 0; + # for(thisOrder=1; thisOrder<=accuracyOrder; thisOrder++){ + # for(p1=thisOrder; p1>=0; p1--){ // x-power + # for(p2=thisOrder-p1; p2>=0; p2--){ // y-power + # p3=thisOrder-p1-p2; //z-power + + # Q[counter] = 1.0; + # for(i=0; i δ, :rho => 1, :E => 1, :nu => 0.25, :Gc => 1.0) + params = Peridynamics.RKCPointParameters(mat, kwargs) + + L = 0.0 + ω_a = 0.0 + @test Peridynamics.get_kernel(mat, params, L) ≈ ω_a + + L = 1/4 + ω_a = 2/3 - 4 * (L/δ)^2 + 4 * (L/δ)^3 + @test Peridynamics.get_kernel(mat, params, L) ≈ ω_a + + L = 1/2 + ω_a = 2/3 - 4 * (L/δ)^2 + 4 * (L/δ)^3 + @test Peridynamics.get_kernel(mat, params, L) ≈ ω_a + + L = 3/4 + ω_a = 4/3 - 4 * (L/δ) + 4 * (L/δ)^2 - 4/3 * (L/δ)^3 + @test Peridynamics.get_kernel(mat, params, L) ≈ ω_a + + L = 1 + ω_a = 4/3 - 4 * (L/δ) + 4 * (L/δ)^2 - 4/3 * (L/δ)^3 + @test Peridynamics.get_kernel(mat, params, L) ≈ ω_a + + @test Peridynamics.get_kernel(mat, params, 1.5) ≈ 0.0 + @test Peridynamics.get_kernel(mat, params, -1.0) ≈ 0.0 +end + +@testitem "Gradient weights Φ" begin + using Peridynamics, Test + using Peridynamics: get_diff, get_monomial_vector, each_bond_idx, influence_function, + threads_data_handler, Bond + using Peridynamics.StaticArrays + # setup + ref_position = [0.0 1.0 0.0 + 0.0 0.0 1.0 + 0.0 0.0 0.0] + volume = fill(1.0, 3) + δ = 1.5 + mat = RKCMaterial() + body = Body(mat, ref_position, volume) + material!(body, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) + failure_permit!(body, false) + dh = threads_data_handler(body, VelocityVerlet(steps=1), 1) + chunk = dh.chunks[1] + (; mat, storage, system, paramsetup) = chunk + + # @test system.bonds == [ + # Bond(2, 1.0, false), # point 1 + # Bond(3, 1.0, false), + # Bond(1, 1.0, false), # point 2 + # Bond(3, √2, false), + # Bond(1, 1.0, false), # point 3 + # Bond(2, √2, false), + # ] + + # @test storage.gradient_weight == zeros(3, 6) + + Peridynamics.calc_gradient_weights!(storage, system, mat, paramsetup) + + # my old version with temp = ωij * volume[j] + # Φ = storage.gradient_weight + # @test Φ[:,1] ≈ [0.0010437031893788147, 0.0, 0.0] + # @test Φ[:,2] ≈ [0.0, 0.0010437031893788147, 0.0] + # @test Φ[:,3] ≈ [-0.0010489745520712516, 5.271362692436961e-6, 0.0] + # @test Φ[:,4] ≈ [-5.332802053265902e-6, 6.143936082888219e-8, 0.0] + # @test Φ[:,5] ≈ [5.27136269243702e-6, -0.0010489745520712514, 0.0] + # @test Φ[:,6] ≈ [6.143936082888247e-8, -5.332802053265901e-6, 0.0] + + # PeriLab version temp = ωij / δ + Φ = storage.gradient_weight + @test Φ[:,1] ≈ [0.0006958021262525432, 0.0, 0.0] + @test Φ[:,2] ≈ [0.0, 0.0006958021262525432, 0.0] + @test Φ[:,3] ≈ [-0.0006993163680475011, 3.5142417949579743e-6, 0.0] + @test Φ[:,4] ≈ [-3.5552013688439347e-6, 4.095957388592146e-8, 0.0] + @test Φ[:,5] ≈ [3.514241794958013e-6, -0.0006993163680475009, 0.0] + @test Φ[:,6] ≈ [4.095957388592165e-8, -3.555201368843933e-6, 0.0] + + #= + using BenchmarkTools + @btime Peridynamics.calc_gradient_weights!($storage, $system, $mat, $paramsetup) + =# + + storage.position[:, 1] += [-0.001, -0.001, -0.001] + storage.position[:, 2] += [0.001, 0.0, 0.0] + storage.position[:, 3] += [0.0, 0.001, 0.0] + + F = storage.defgrad + @test F == zeros(9, 3) + + Peridynamics.calc_deformation_gradients!(storage, system, mat, paramsetup, 0.0, 0.0) + + # my old version + # @test F[:, 1] ≈ [1.0000013916042525, 6.958021262525431e-7, 0.0, + # 6.958021262525431e-7, 1.0000013916042525, 0.0, + # 6.958021262525431e-7, 6.958021262525431e-7, 1.0] + # @test F[:, 2] ≈ [1.0000014021879375, -7.069443163801091e-9, 0.0, + # 6.957611666786575e-7, 0.9999999965267178, 0.0, + # 6.993163680475011e-7, -3.514241794957974e-9, 1.0] + # @test F[:, 3] ≈ [0.9999999965267178, 6.957611666786573e-7, 0.0, + # -7.069443163801169e-9, 1.0000014021879375, 0.0, + # -3.514241794958013e-9, 6.993163680475009e-7, 1.0] + + # PeriLab version + @test F[:, 1] ≈ [1.0000013916042525, 6.958021262525431e-7, 6.958021262525431e-7, + 6.958021262525431e-7, 1.0000013916042525, 6.958021262525431e-7, + 0.0, 0.0, 1.0] + @test F[:, 2] ≈ [1.0000014021879375, 6.957611666786575e-7, 6.993163680475011e-7, + -7.069443163801091e-9, 0.9999999965267178, -3.514241794957974e-9, + 0.0, 0.0, 1.0] + @test F[:, 3] ≈ [0.9999999965267178, -7.069443163801169e-9, -3.514241794958013e-9, + 6.957611666786573e-7, 1.0000014021879375, 6.993163680475009e-7, + 0.0, 0.0, 1.0] + + + #= + using BenchmarkTools + @btime Peridynamics.calc_deformation_gradients!($storage, $system, $mat, $paramsetup, $0.0, $0.0) + =# +end From c87e24c374d9c12433ff4e4cfae0ce12a9e6403d Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Wed, 20 Nov 2024 13:25:25 +0100 Subject: [PATCH 30/40] Working version for small deformations --- src/physics/ns_correspondence.jl | 124 +++++++++++++++++++++++++------ 1 file changed, 100 insertions(+), 24 deletions(-) diff --git a/src/physics/ns_correspondence.jl b/src/physics/ns_correspondence.jl index 75e4f338..6390c8e6 100644 --- a/src/physics/ns_correspondence.jl +++ b/src/physics/ns_correspondence.jl @@ -58,7 +58,7 @@ struct NSCMaterial{CM,K} <: AbstractCorrespondenceMaterial{CM,NoCorrection} constitutive_model::CM maxdmg::Float64 function NSCMaterial(kernel::K, cm::CM, maxdmg::Real) where {CM,K} - return new{CM,K}(cm, maxdmg) + return new{CM,K}(kernel, cm, maxdmg) end end @@ -117,6 +117,7 @@ end @lthfield defgrad::Matrix{Float64} @lthfield weighted_volume::Vector{Float64} gradient_weight::Matrix{Float64} + first_piola_kirchhoff::Matrix{Float64} end function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int}) @@ -152,6 +153,11 @@ function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, return zeros(3, get_n_bonds(system)) end +function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:first_piola_kirchhoff}) + return zeros(9, get_n_bonds(system)) +end + function initialize!(chunk::BodyChunk{<:BondSystem,<:NSCMaterial}) chunk.storage.damage_changed .= true return nothing @@ -186,7 +192,7 @@ function calc_force_density!(dh::ThreadsBodyDataHandler{<:BondSystem,<:NSCMateri @threads :static for chunk_id in eachindex(dh.chunks) chunk = dh.chunks[chunk_id] calc_force_density!(chunk, t, Δt) - # nancheck(chunk, t) + nancheck(chunk, t) end @threads :static for chunk_id in eachindex(dh.chunks) exchange_halo_to_loc!(dh, chunk_id) @@ -252,7 +258,7 @@ function calc_weights_and_defgrad!(storage::NSCStorage, system::BondSystem, j = bond.neighbor ΔXij = get_diff(system.position, i, j) ωij = kernel(system, bond_id) * bond_active[bond_id] - temp = ωij * volume[j] + temp = ωij Ψ = temp * (Kinv * ΔXij) update_vector!(gradient_weight, bond_id, Ψ) end @@ -260,17 +266,6 @@ function calc_weights_and_defgrad!(storage::NSCStorage, system::BondSystem, return nothing end -@inline function influence_function(::NSCMaterial, params::NSCPointParameters, L) - ξ = L / params.δ - if 0 < ξ ≤ 0.5 - return 2/3 - 4 * ξ^2 + 4 * ξ^3 - elseif 0.5 < ξ ≤ 1 - return 4/3 - 4 * ξ + 4 * ξ^2 - 4/3 * ξ^3 - else - return 0 - end -end - function force_density_point!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, paramhandler::AbstractParameterHandler, t, Δt, i) params = get_params(paramhandler, i) @@ -280,10 +275,11 @@ end function force_density_point!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, params::NSCPointParameters, t, Δt, i) - Fi = get_tensor(storage.defgrad, i) - too_much_damage!(storage, system, mat, Fi, i) && return nothing - P = calc_first_piola_kirchhoff!(storage, mat, params, Fi, Δt, i) - nsc_force_density!(storage, system, mat, params, P, i) + # Fi = get_tensor(storage.defgrad, i) + # too_much_damage!(storage, system, mat, Fi, i) && return nothing + # P = calc_first_piola_kirchhoff!(storage, mat, params, Fi, Δt, i) + # nsc_force_density!(storage, system, mat, params, P, i) + nsc_force_density!(storage, system, mat, params, i) return nothing end @@ -303,22 +299,102 @@ function calc_first_piola_kirchhoff(storage::NSCStorage, mat::NSCMaterial, end # Working version!!! +# function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, +# params::NSCPointParameters, P::SMatrix, i) +# (; bonds, volume) = system +# (; bond_active, gradient_weight) = storage +# for bond_id in each_bond_idx(system, i) +# bond = bonds[bond_id] +# j, L = bond.neighbor, bond.length +# Δxij = get_coordinates_diff(storage, i, j) +# l = norm(Δxij) +# ε = (l - L) / L +# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) +# if bond_active[bond_id] +# Ψ = get_vector(gradient_weight, bond_id) +# tij = P * Ψ +# update_add_b_int!(storage, i, tij .* volume[j]) +# update_add_b_int!(storage, j, -tij .* volume[i]) +# end +# end +# return nothing +# end + +# function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, +# params::NSCPointParameters, i) +# (; bonds, volume) = system +# (; bond_active, gradient_weight, defgrad) = storage +# Fi = get_tensor(defgrad, i) +# too_much_damage!(storage, system, mat, Fi, i) && return nothing +# for bond_id in each_bond_idx(system, i) +# bond = bonds[bond_id] +# j, L = bond.neighbor, bond.length +# Δxij = get_coordinates_diff(storage, i, j) +# l = norm(Δxij) +# ε = (l - L) / L +# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) +# if bond_active[bond_id] +# Fj = get_tensor(defgrad, j) +# Fb = 0.5 * (Fi + Fj) +# ΔXij = get_coordinates_diff(system, i, j) +# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) +# Fij = Fb + ΔFij +# P = calc_first_piola_kirchhoff(storage, mat, params, Fij) +# Ψ = get_vector(gradient_weight, bond_id) +# tij = P * Ψ +# update_add_b_int!(storage, i, tij .* volume[j]) +# update_add_b_int!(storage, j, -tij .* volume[i]) +# end +# end +# return nothing +# end + function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, - params::NSCPointParameters, P::SMatrix, i) + params::NSCPointParameters, i) (; bonds, volume) = system - (; bond_active, gradient_weight) = storage + (; bond_active, gradient_weight, defgrad, weighted_volume) = storage + + Fi = get_tensor(defgrad, i) + too_much_damage!(storage, system, mat, Fi, i) && return nothing + + # Stress integral SI + wi = weighted_volume[i] + SI = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) for bond_id in each_bond_idx(system, i) bond = bonds[bond_id] j, L = bond.neighbor, bond.length + ΔXij = get_coordinates_diff(system, i, j) Δxij = get_coordinates_diff(storage, i, j) l = norm(Δxij) ε = (l - L) / L stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + + if bond_active[bond_id] + Fj = get_tensor(defgrad, j) + Fb = 0.5 * (Fi + Fj) + ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) + Fij = Fb + ΔFij + Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) + update_tensor!(storage.first_piola_kirchhoff, bond_id, Pij) + Tempij = I - (ΔXij * ΔXij') / (L * L) + ωij = kernel(system, bond_id) + wj = weighted_volume[j] + ϕ = volume[j] * ωij * (0.5 / wi + 0.5 / wj) + SI += ϕ * (Pij * Tempij) + end + end + + for bond_id in each_bond_idx(system, i) if bond_active[bond_id] - Ψ = get_vector(gradient_weight, bond_id) - tij = (P * Ψ) / volume[j] - update_add_b_int!(storage, i, tij .* volume[j]) - update_add_b_int!(storage, j, -tij .* volume[i]) + bond = bonds[bond_id] + j, L = bond.neighbor, bond.length + ΔXij = get_coordinates_diff(system, i, j) + Pij = get_tensor(storage.first_piola_kirchhoff, bond_id) + Φij = get_vector(gradient_weight, bond_id) + ωij = kernel(system, bond_id) + tij = ωij / (wi * L * L) * (Pij * ΔXij) + SI * Φij + update_add_b_int!(storage, i, tij * volume[j]) + update_add_b_int!(storage, j, -tij * volume[i]) end end return nothing From 536606b05214ba4e14091c55e263b7d1aeaae822 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Wed, 20 Nov 2024 15:38:19 +0100 Subject: [PATCH 31/40] NSC-model is now working; problems with large deformations --- src/Peridynamics.jl | 3 +- src/physics/ns_correspondence.jl | 19 +- src/physics/ns_correspondence_rotated.jl | 674 +++++++++++++++++++++++ src/physics/stress.jl | 77 +++ 4 files changed, 762 insertions(+), 11 deletions(-) create mode 100644 src/physics/ns_correspondence_rotated.jl diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index 9e32a342..f8b0c6a1 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -10,7 +10,7 @@ import LibGit2, Dates # Material models export BBMaterial, OSBMaterial, CMaterial, BACMaterial, RKCMaterial, NSCMaterial, - CKIMaterial + NSCRMaterial, CKIMaterial # CMaterial related types export NeoHookeNonlinear, SaintVenantKirchhoff, ZEMSilling @@ -130,6 +130,7 @@ include("physics/ordinary_state_based.jl") include("physics/constitutive_models.jl") include("physics/correspondence.jl") include("physics/ns_correspondence.jl") +include("physics/ns_correspondence_rotated.jl") include("physics/ba_correspondence.jl") include("physics/rk_correspondence.jl") diff --git a/src/physics/ns_correspondence.jl b/src/physics/ns_correspondence.jl index 6390c8e6..285005b1 100644 --- a/src/physics/ns_correspondence.jl +++ b/src/physics/ns_correspondence.jl @@ -258,7 +258,7 @@ function calc_weights_and_defgrad!(storage::NSCStorage, system::BondSystem, j = bond.neighbor ΔXij = get_diff(system.position, i, j) ωij = kernel(system, bond_id) * bond_active[bond_id] - temp = ωij + temp = ωij * volume[j] Ψ = temp * (Kinv * ΔXij) update_vector!(gradient_weight, bond_id, Ψ) end @@ -359,7 +359,7 @@ function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMat # Stress integral SI wi = weighted_volume[i] - SI = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + ∑P = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) for bond_id in each_bond_idx(system, i) bond = bonds[bond_id] j, L = bond.neighbor, bond.length @@ -372,15 +372,14 @@ function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMat if bond_active[bond_id] Fj = get_tensor(defgrad, j) Fb = 0.5 * (Fi + Fj) - ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) + ΔXijLL = ΔXij' / (L * L) + ΔFij = (Δxij - Fb * ΔXij) * ΔXijLL Fij = Fb + ΔFij Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) update_tensor!(storage.first_piola_kirchhoff, bond_id, Pij) - Tempij = I - (ΔXij * ΔXij') / (L * L) - ωij = kernel(system, bond_id) - wj = weighted_volume[j] - ϕ = volume[j] * ωij * (0.5 / wi + 0.5 / wj) - SI += ϕ * (Pij * Tempij) + Tempij = I - ΔXij * ΔXijLL + ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) + ∑P += ω̃ij * (Pij * Tempij) end end @@ -391,8 +390,8 @@ function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMat ΔXij = get_coordinates_diff(system, i, j) Pij = get_tensor(storage.first_piola_kirchhoff, bond_id) Φij = get_vector(gradient_weight, bond_id) - ωij = kernel(system, bond_id) - tij = ωij / (wi * L * L) * (Pij * ΔXij) + SI * Φij + ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) + tij = ω̃ij / (L * L) * (Pij * ΔXij) + ∑P * Φij update_add_b_int!(storage, i, tij * volume[j]) update_add_b_int!(storage, j, -tij * volume[i]) end diff --git a/src/physics/ns_correspondence_rotated.jl b/src/physics/ns_correspondence_rotated.jl new file mode 100644 index 00000000..3aa2938e --- /dev/null +++ b/src/physics/ns_correspondence_rotated.jl @@ -0,0 +1,674 @@ +""" + NSCRMaterial(; maxdmg, zem) + +A material type used to assign the material of a [`Body`](@ref) with the local continuum +consistent (correspondence) formulation of non-ordinary state-based peridynamics. + +# Keywords +- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is + exceeded, all bonds of that point are broken because the deformation gradient would then + possibly contain `NaN` values. + (default: `0.95`) + +# Examples + +```julia-repl +julia> mat = NSCRMaterial() +NSCRMaterial(maxdmg=0.95) +``` + +--- + +```julia +NSCRMaterial +``` + +Material type for the local continuum consistent (correspondence) formulation of +non-ordinary state-based peridynamics. + +# Fields +- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. See the + constructor docs for more informations. + +# Allowed material parameters +When using [`material!`](@ref) on a [`Body`](@ref) with `NSCRMaterial`, then the following +parameters are allowed: +- `horizon::Float64`: Radius of point interactions +- `rho::Float64`: Density +- `E::Float64`: Young's modulus +- `nu::Float64`: Poisson's ratio +- `Gc::Float64`: Critical energy release rate +- `epsilon_c::Float64`: Critical strain + +# Allowed export fields +When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with +`NSCRMaterial`, the following fields are allowed: +- `position::Matrix{Float64}`: Position of each point +- `displacement::Matrix{Float64}`: Displacement of each point +- `velocity::Matrix{Float64}`: Velocity of each point +- `velocity_half::Matrix{Float64}`: Velocity parameter for Verlet time solver +- `acceleration::Matrix{Float64}`: Acceleration of each point +- `b_int::Matrix{Float64}`: Internal force density of each point +- `b_ext::Matrix{Float64}`: External force density of each point +- `damage::Vector{Float64}`: Damage of each point +- `n_active_bonds::Vector{Int}`: Number of intact bonds of each point +""" +struct NSCRMaterial{CM,K} <: AbstractCorrespondenceMaterial{CM,NoCorrection} + kernel::K + constitutive_model::CM + maxdmg::Float64 + function NSCRMaterial(kernel::K, cm::CM, maxdmg::Real) where {CM,K} + return new{CM,K}(kernel, cm, maxdmg) + end +end + +function Base.show(io::IO, @nospecialize(mat::NSCRMaterial)) + print(io, typeof(mat)) + print(io, msg_fields_in_brackets(mat, (:maxdmg,))) + return nothing +end + +function NSCRMaterial(; kernel::Function=cubic_b_spline, + model::AbstractConstitutiveModel=SaintVenantKirchhoff(), + maxdmg::Real=0.85) + return NSCRMaterial(kernel, model, maxdmg) +end + +struct NSCRPointParameters <: AbstractPointParameters + δ::Float64 + rho::Float64 + E::Float64 + nu::Float64 + G::Float64 + K::Float64 + λ::Float64 + μ::Float64 + Gc::Float64 + εc::Float64 + bc::Float64 +end + +function NSCRPointParameters(mat::NSCRMaterial, p::Dict{Symbol,Any}) + (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) + (; Gc, εc) = get_frac_params(p, δ, K) + bc = 18 * K / (π * δ^4) # bond constant + return NSCRPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) +end + +@params NSCRMaterial NSCRPointParameters + +@storage NSCRMaterial struct NSCRStorage + @lthfield position::Matrix{Float64} + @pointfield displacement::Matrix{Float64} + @lthfield velocity::Matrix{Float64} + @pointfield velocity_half::Matrix{Float64} + @pointfield velocity_half_old::Matrix{Float64} + @pointfield acceleration::Matrix{Float64} + @htlfield b_int::Matrix{Float64} + @pointfield b_int_old::Matrix{Float64} + @pointfield b_ext::Matrix{Float64} + @pointfield density_matrix::Matrix{Float64} + @pointfield damage::Vector{Float64} + bond_active::Vector{Bool} + @pointfield n_active_bonds::Vector{Int} + @pointfield damage_changed::Vector{Bool} + @pointfield stress::Matrix{Float64} + @pointfield von_mises_stress::Vector{Float64} + @lthfield defgrad::Matrix{Float64} + @lthfield defgrad_dot::Matrix{Float64} + @lthfield weighted_volume::Vector{Float64} + gradient_weight::Matrix{Float64} + rotation::Matrix{Float64} + left_stretch::Matrix{Float64} + first_piola_kirchhoff::Matrix{Float64} +end + +function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:velocity}) + return zeros(3, get_n_points(system)) +end + +function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int}) + return zeros(3, get_n_points(system)) +end + +function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:damage_changed}) + return ones(Bool, get_n_loc_points(system)) +end + +function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:stress}) + return zeros(9, get_n_loc_points(system)) +end + +function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:von_mises_stress}) + return zeros(get_n_loc_points(system)) +end + +function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:rotation}) + R = zeros(9, get_n_bonds(system)) + R[[1, 5, 9], :] .= 1.0 + return R +end + +function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:left_stretch}) + V = zeros(9, get_n_bonds(system)) + V[[1, 5, 9], :] .= 1.0 + return V +end + +function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:defgrad}) + return zeros(9, get_n_points(system)) +end + +function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:defgrad_dot}) + return zeros(9, get_n_points(system)) +end + +function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:weighted_volume}) + return zeros(get_n_points(system)) +end + +function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:gradient_weight}) + return zeros(3, get_n_bonds(system)) +end + +function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:first_piola_kirchhoff}) + return zeros(9, get_n_bonds(system)) +end + +function initialize!(chunk::BodyChunk{<:BondSystem,<:NSCRMaterial}) + chunk.storage.damage_changed .= true + return nothing +end + +@inline function calc_damage!(chunk::BodyChunk{<:BondSystem,<:NSCRMaterial}) + (; n_neighbors) = chunk.system + (; n_active_bonds, damage, damage_changed) = chunk.storage + for point_id in each_point_idx(chunk) + old_damage = damage[point_id] + new_damage = 1 - n_active_bonds[point_id] / n_neighbors[point_id] + if new_damage > old_damage + damage_changed[point_id] = true + else + damage_changed[point_id] = false + end + damage[point_id] = new_damage + end + return nothing +end + +function calc_force_density!(dh::ThreadsBodyDataHandler{<:BondSystem,<:NSCRMaterial}, t, Δt) + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_loc_to_halo!(dh, chunk_id, (:position, :velocity)) + end + @threads :static for chunk_id in eachindex(dh.chunks) + calc_weights_and_defgrad!(dh.chunks[chunk_id], t, Δt) + end + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_loc_to_halo!(dh, chunk_id, (:defgrad, :defgrad_dot, :weighted_volume)) + end + @threads :static for chunk_id in eachindex(dh.chunks) + chunk = dh.chunks[chunk_id] + calc_force_density!(chunk, t, Δt) + nancheck(chunk, t) + end + @threads :static for chunk_id in eachindex(dh.chunks) + exchange_halo_to_loc!(dh, chunk_id) + end + return nothing +end + +function calc_force_density!(dh::MPIBodyDataHandler{<:BondSystem,<:NSCRMaterial}, t, Δt) + (; chunk) = dh + exchange_loc_to_halo!(dh, (:position, :velocity)) + calc_weights_and_defgrad!(chunk, t, Δt) + exchange_loc_to_halo!(dh, (:defgrad, :defgrad_dot, :weighted_volume)) + calc_force_density!(chunk, t, Δt) + nancheck(chunk, t) + exchange_halo_to_loc!(dh) + return nothing +end + +function calc_weights_and_defgrad!(chunk::BodyChunk{<:BondSystem,<:NSCRMaterial}, t, Δt) + (; system, mat, paramsetup, storage) = chunk + for i in each_point_idx(system) + calc_weights_and_defgrad!(storage, system, mat, paramsetup, t, Δt, i) + end + return nothing +end + +function calc_weights_and_defgrad!(storage::NSCRStorage, system::BondSystem, + mat::NSCRMaterial, paramhandler::AbstractParameterHandler, + t, Δt, i) + params = get_params(paramhandler, i) + calc_weights_and_defgrad!(storage, system, mat, params, t, Δt, i) + return nothing +end + +function calc_weights_and_defgrad!(storage::NSCRStorage, system::BondSystem, + mat::NSCRMaterial, params::NSCRPointParameters, t, Δt, i) + (; bonds, volume) = system + (; bond_active, weighted_volume, gradient_weight, damage_changed) = storage + + K = zero(SMatrix{3,3,Float64,9}) + _F = zero(SMatrix{3,3,Float64,9}) + _Ḟ = zero(SMatrix{3,3,Float64,9}) + wi = 0.0 + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j = bond.neighbor + ΔXij = get_diff(system.position, i, j) + Δxij = get_diff(storage.position, i, j) + Δvij = get_diff(storage.velocity, i, j) + ωij = kernel(system, bond_id) * bond_active[bond_id] + temp = ωij * volume[j] + K += temp * (ΔXij * ΔXij') + _F += temp * (Δxij * ΔXij') + _Ḟ += temp * (Δvij * ΔXij') + wi += temp + end + Kinv = inv(K) + F = _F * Kinv + Ḟ = _Ḟ * Kinv + update_tensor!(storage.defgrad, i, F) + update_tensor!(storage.defgrad_dot, i, Ḟ) + weighted_volume[i] = wi + + damage_changed[i] || return nothing + + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j = bond.neighbor + ΔXij = get_diff(system.position, i, j) + ωij = kernel(system, bond_id) * bond_active[bond_id] + temp = ωij * volume[j] + Ψ = temp * (Kinv * ΔXij) + update_vector!(gradient_weight, bond_id, Ψ) + end + + return nothing +end + +function force_density_point!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, + paramhandler::AbstractParameterHandler, t, Δt, i) + params = get_params(paramhandler, i) + force_density_point!(storage, system, mat, params, t, Δt, i) + return nothing +end + +function force_density_point!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, + params::NSCRPointParameters, t, Δt, i) + # Fi = get_tensor(storage.defgrad, i) + # too_much_damage!(storage, system, mat, Fi, i) && return nothing + # P = calc_first_piola_kirchhoff!(storage, mat, params, Fi, Δt, i) + # nsc_force_density!(storage, system, mat, params, P, i) + # nsc_force_density!(storage, system, mat, params, i) + + (; bonds, volume) = system + (; bond_active, gradient_weight, defgrad, defgrad_dot, weighted_volume) = storage + + Fi = get_tensor(defgrad, i) + Ḟi = get_tensor(defgrad_dot, i) + # too_much_damage!(storage, system, mat, Fi, i) && return nothing + + # Stress integral ∑P + wi = weighted_volume[i] + ∑P = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j, L = bond.neighbor, bond.length + Δxij = get_coordinates_diff(storage, i, j) + l = norm(Δxij) + ε = (l - L) / L + stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + + if bond_active[bond_id] + ΔXij = get_coordinates_diff(system, i, j) + Δvij = get_diff(storage.velocity, i, j) + Fj = get_tensor(defgrad, j) + Ḟj = get_tensor(defgrad_dot, j) + Fb = 0.5 * (Fi + Fj) + Ḟb = 0.5 * (Ḟi + Ḟj) + ΔXijLL = ΔXij' / (L * L) + ΔFij = (Δxij - Fb * ΔXij) * ΔXijLL + ΔḞij = (Δvij - Ḟb * ΔXij) * ΔXijLL + Fij = Fb + ΔFij + Ḟij = Ḟb + ΔḞij + Pij = calc_first_piola_kirchhoff!(storage, mat, params, Fij, Ḟij, Δt, bond_id) + Tempij = I - ΔXij * ΔXijLL + ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) + ∑P += ω̃ij * (Pij * Tempij) + end + end + + for bond_id in each_bond_idx(system, i) + if bond_active[bond_id] + bond = bonds[bond_id] + j, L = bond.neighbor, bond.length + ΔXij = get_coordinates_diff(system, i, j) + Pij = get_tensor(storage.first_piola_kirchhoff, bond_id) + Φij = get_vector(gradient_weight, bond_id) + ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) + tij = ω̃ij / (L * L) * (Pij * ΔXij) + ∑P * Φij + update_add_b_int!(storage, i, tij * volume[j]) + update_add_b_int!(storage, j, -tij * volume[i]) + end + end + + return nothing +end + +# function calc_first_piola_kirchhoff!(storage::NSCRStorage, mat::NSCRMaterial, +# params::NSCRPointParameters, F, Δt, i) +# P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) +# σ = cauchy_stress(P, F) +# update_tensor!(storage.stress, i, σ) +# storage.von_mises_stress[i] = von_mises_stress(σ) +# return P +# end + +function calc_first_piola_kirchhoff!(storage::NSCRStorage, mat::NSCRMaterial, + params::NSCRPointParameters, F, Ḟ, Δt, i) + P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) + σ = cauchy_stress(P, F) + init_stress_rotation!(storage, F, Ḟ, Δt, i) + T = rotate_stress(storage, σ, i) + P = first_piola_kirchhoff(T, F) + update_tensor!(storage.first_piola_kirchhoff, i, P) + return P +end + +# Working version!!! +# function nsc_force_density!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, +# params::NSCRPointParameters, P::SMatrix, i) +# (; bonds, volume) = system +# (; bond_active, gradient_weight) = storage +# for bond_id in each_bond_idx(system, i) +# bond = bonds[bond_id] +# j, L = bond.neighbor, bond.length +# Δxij = get_coordinates_diff(storage, i, j) +# l = norm(Δxij) +# ε = (l - L) / L +# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) +# if bond_active[bond_id] +# Ψ = get_vector(gradient_weight, bond_id) +# tij = P * Ψ +# update_add_b_int!(storage, i, tij .* volume[j]) +# update_add_b_int!(storage, j, -tij .* volume[i]) +# end +# end +# return nothing +# end + +# function nsc_force_density!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, +# params::NSCRPointParameters, i) +# (; bonds, volume) = system +# (; bond_active, gradient_weight, defgrad) = storage +# Fi = get_tensor(defgrad, i) +# too_much_damage!(storage, system, mat, Fi, i) && return nothing +# for bond_id in each_bond_idx(system, i) +# bond = bonds[bond_id] +# j, L = bond.neighbor, bond.length +# Δxij = get_coordinates_diff(storage, i, j) +# l = norm(Δxij) +# ε = (l - L) / L +# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) +# if bond_active[bond_id] +# Fj = get_tensor(defgrad, j) +# Fb = 0.5 * (Fi + Fj) +# ΔXij = get_coordinates_diff(system, i, j) +# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) +# Fij = Fb + ΔFij +# P = calc_first_piola_kirchhoff(storage, mat, params, Fij) +# Ψ = get_vector(gradient_weight, bond_id) +# tij = P * Ψ +# update_add_b_int!(storage, i, tij .* volume[j]) +# update_add_b_int!(storage, j, -tij .* volume[i]) +# end +# end +# return nothing +# end + +# function nsc_force_density!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, +# params::NSCRPointParameters, i) +# (; bonds, volume) = system +# (; bond_active, gradient_weight, defgrad, weighted_volume) = storage + +# Fi = get_tensor(defgrad, i) +# too_much_damage!(storage, system, mat, Fi, i) && return nothing + +# # Stress integral SI +# wi = weighted_volume[i] +# SI = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) +# for bond_id in each_bond_idx(system, i) +# bond = bonds[bond_id] +# j, L = bond.neighbor, bond.length +# ΔXij = get_coordinates_diff(system, i, j) +# Δxij = get_coordinates_diff(storage, i, j) +# l = norm(Δxij) +# ε = (l - L) / L +# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + +# if bond_active[bond_id] +# Fj = get_tensor(defgrad, j) +# Fb = 0.5 * (Fi + Fj) +# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) +# Fij = Fb + ΔFij +# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) +# update_tensor!(storage.first_piola_kirchhoff, bond_id, Pij) +# Tempij = I - (ΔXij * ΔXij') / (L * L) +# ωij = kernel(system, bond_id) +# wj = weighted_volume[j] +# ϕ = volume[j] * ωij * (0.5 / wi + 0.5 / wj) +# SI += ϕ * (Pij * Tempij) +# end +# end + +# for bond_id in each_bond_idx(system, i) +# if bond_active[bond_id] +# bond = bonds[bond_id] +# j, L = bond.neighbor, bond.length +# ΔXij = get_coordinates_diff(system, i, j) +# Pij = get_tensor(storage.first_piola_kirchhoff, bond_id) +# Φij = get_vector(gradient_weight, bond_id) +# ωij = kernel(system, bond_id) +# tij = ωij / (wi * L * L) * (Pij * ΔXij) + SI * Φij +# update_add_b_int!(storage, i, tij * volume[j]) +# update_add_b_int!(storage, j, -tij * volume[i]) +# end +# end +# return nothing +# end + +# NODALLY STABLIZIED VERSION!!! WORKING, BUT NOT SURE IF CORRECT! +# function nsc_force_density!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, +# params::NSCRPointParameters, P::SMatrix, i) +# (; bonds, volume) = system +# (; bond_active, gradient_weight, defgrad) = storage +# Fi = get_tensor(defgrad, i) +# too_much_damage!(storage, system, mat, Fi, i) && return nothing +# for bond_id in each_bond_idx(system, i) +# bond = bonds[bond_id] +# j, L = bond.neighbor, bond.length +# Δxij = get_coordinates_diff(storage, i, j) +# l = norm(Δxij) +# ε = (l - L) / L +# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) +# if bond_active[bond_id] +# ΔXij = get_coordinates_diff(system, i, j) +# Fj = get_tensor(defgrad, j) +# Fb = 0.5 * (Fi + Fj) +# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) +# Fij = Fb + ΔFij +# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) +# Ψ = get_vector(gradient_weight, bond_id) +# tij = (Pij * Ψ) / volume[j] +# update_add_b_int!(storage, i, tij .* volume[j]) +# update_add_b_int!(storage, j, -tij .* volume[i]) +# end +# end +# return nothing +# end + + +# PERIDIGM VERSION +# function nsc_force_density!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, +# params::NSCRPointParameters, P::SMatrix, i) +# (; bonds, volume) = system +# (; bond_active, gradient_weight, defgrad, weighted_volume) = storage +# Fi = get_tensor(defgrad, i) +# wi = weighted_volume[i] +# SI = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) +# for bond_id in each_bond_idx(system, i) +# bond = bonds[bond_id] +# j, L = bond.neighbor, bond.length +# ΔXij = get_coordinates_diff(system, i, j) +# Δxij = get_coordinates_diff(storage, i, j) +# l = norm(Δxij) +# ε = (l - L) / L +# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + +# Fj = get_tensor(defgrad, j) +# Fb = 0.5 * (Fi + Fj) +# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) +# Fij = Fb + ΔFij +# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) +# # update_tensor!(first_piola_kirchhoff, bond_id, Pij) +# # ΔPij = Pij - Pi +# Tempij = (I - ΔXij * ΔXij') / (L * L) +# ωij = influence_function(mat, params, L) * bond_active[bond_id] +# wj = weighted_volume[j] +# ϕ = volume[j] * ωij * (0.5 / wi + 0.5 / wj) +# SI += ϕ * (Pij * Tempij) +# end +# for bond_id in each_bond_idx(system, i) +# bond = bonds[bond_id] +# j, L = bond.neighbor, bond.length +# ΔXij = get_coordinates_diff(system, i, j) +# Δxij = get_coordinates_diff(storage, i, j) +# Fj = get_tensor(defgrad, j) +# Fb = 0.5 * (Fi + Fj) +# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) +# Fij = Fb + ΔFij +# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) +# Φij = get_vector(gradient_weight, bond_id) +# ωij = influence_function(mat, params, L) * bond_active[bond_id] +# tij = (SI * Φij) / volume[j] + ωij / (wi * L * L) * (Pij * ΔXij) +# update_add_b_int!(storage, i, tij * volume[j]) +# update_add_b_int!(storage, j, -tij * volume[i]) +# end +# return nothing +# end + +# NODALLY STABLIZIED VERSION WRONG? +# function nsc_force_density!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, +# params::NSCRPointParameters, P::SMatrix, i) +# (; bonds, volume) = system +# (; bond_active, gradient_weight, defgrad, weighted_volume) = storage +# Fi = get_tensor(defgrad, i) +# Vi = volume[i] +# wi = weighted_volume[i] + +# for bond_id_j in each_bond_idx(system, i) +# bond_ij = bonds[bond_id_j] +# j, Lij = bond_ij.neighbor, bond_ij.length +# ΔXij = get_coordinates_diff(storage, i, j) +# Δxij = get_coordinates_diff(storage, i, j) +# lij = norm(Δxij) +# ε = (lij - Lij) / Lij +# stretch_based_failure!(storage, system, bond_ij, params, ε, i, bond_id_j) + +# ωij = influence_function(mat, params, Lij) +# Vj, wj = volume[j], weighted_volume[j] +# Ṽij = (Vi * Vj) / 2 * (ωij / wj + ωij / wi) +# Ψij = get_vector(gradient_weight, bond_id_j) +# Fj = get_tensor(defgrad, j) +# Fij = 0.5 * (Fi + Fj) +# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) + +# Tcor = Ṽij * (Pij * ΔXij) / (Vj * Vi * Lij * Lij) + +# Tave = zero(SVector{3,Float64}) +# for bond_id_k in each_bond_idx(system, i) +# bond_ik = bonds[bond_id_k] +# k, Lik = bond_ik.neighbor, bond_ik.length +# ωik = influence_function(mat, params, Lik) +# Vk, wk = volume[k], weighted_volume[k] +# Ṽik = (Vi * Vk) / 2 * (ωik / wk + ωij / wi) +# Fk = get_tensor(defgrad, k) +# Fik = 0.5 * (Fi + Fk) +# Pik = calc_first_piola_kirchhoff(storage, mat, params, Fik) +# Tave += Ṽik * (Pik * Ψij) / (Vj * Vi) +# ΔXΔXΨ = (ΔXij * ΔXij') * Ψij +# Tcor -= Ṽik * (Pik * ΔXΔXΨ) / (Vj * Vi * Lik * Lik) +# end + +# T = Tave + Tcor +# update_add_b_int!(storage, i, T .* volume[j]) +# update_add_b_int!(storage, j, -T .* volume[i]) +# end +# return nothing +# end + + # Tcor2 = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + # for bond_id in each_bond_idx(system, i) + # bond = bonds[bond_id] + # j, L = bond.neighbor, bond.length + # ΔXij = get_coordinates_diff(system, i, j) + # Δxij = get_coordinates_diff(storage, i, j) + # l = norm(Δxij) + # ε = (l - L) / L + # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + + # if bond_active[bond_id] + # ωij = influence_function(mat, params, L) + # Vj, wj = volume[j], weighted_volume[j] + # Ṽij = (Vi * Vj) / 2 * (ωij / wi + ωij / wj) + + # Fj = get_tensor(defgrad, j) + # Fb = 0.5 * (Fi + Fj) + # Pb = calc_first_piola_kirchhoff(storage, mat, params, Fb) + + # temp = Ṽij / (Vi * Vj * L * L) + # Ψ = get_vector(gradient_weight, bond_id) + # ΔXΨ = (ΔXij * ΔXij') * Ψ + # Tcor2 += temp * (P * ΔXΨ) + # end + # end + + # for bond_id in each_bond_idx(system, i) + # if bond_active[bond_id] + # bond = bonds[bond_id] + # j, L = bond.neighbor, bond.length + # ΔXij = get_coordinates_diff(system, i, j) + # Δxij = get_coordinates_diff(storage, i, j) + + # # update of force density + # Ψ = get_vector(gradient_weight, bond_id) + # tij = (P * Ψ) / volume[j] + # update_add_b_int!(storage, i, tij .* volume[j]) + # update_add_b_int!(storage, j, -tij .* volume[i]) + # end + # end +# return nothing +# end + +function too_much_damage!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, F, i) + if storage.damage[i] > mat.maxdmg || containsnan(F) + # kill all bonds of this point + storage.bond_active[each_bond_idx(system, i)] .= false + storage.n_active_bonds[i] = 0 + return true + end + return false +end diff --git a/src/physics/stress.jl b/src/physics/stress.jl index 265cace0..54a2e29a 100644 --- a/src/physics/stress.jl +++ b/src/physics/stress.jl @@ -13,3 +13,80 @@ function cauchy_stress(P, F) σ = 1/J .* P * F' return σ end + +function first_piola_kirchhoff(σ, F) + J = det(F) + P = J * σ * inv(F)' + return P +end + +function init_stress_rotation!(storage::AbstractStorage, F, Ḟ, Δt, i) + # inverse of the deformation gradient + F⁻¹ = inv(F) + + # Eulerian velocity gradient [FT87, eq. (3)] + L = Ḟ * F⁻¹ + + # rate-of-deformation tensor D + D = 0.5 .* (L + L') + + # spin tensor W + W = 0.5 .* (L - L') + + # left stretch V + V = get_tensor(storage.left_stretch, i) + + # vector z [FT87, eq. (13)] + z_x = - V[1,3] * D[2,1] - V[2,3] * D[2,2] - + V[3,3] * D[2,3] + V[1,2] * D[3,1] + + V[2,2] * D[3,2] + V[3,2] * D[3,3] + z_y = V[1,3] * D[1,1] + V[2,3] * D[1,2] + + V[3,3] * D[1,3] - V[1,1] * D[3,1] - + V[2,1] * D[3,2] - V[3,1] * D[3,3] + z_z = - V[1,2] * D[1,1] - V[2,2] * D[1,2] - + V[3,2] * D[1,3] + V[1,1] * D[2,1] + + V[2,1] * D[2,2] + V[3,1] * D[2,3] + z = SVector{3}(z_x, z_y, z_z) + + # w = -1/2 * \epsilon_{ijk} * W_{jk} [FT87, eq. (11)] + w = 0.5 .* SVector{3}(W[3,2] - W[2,3], W[1,3] - W[3,1], W[2,1] - W[1,2]) + + # ω = w + (I * tr(V) - V)^(-1) * z [FT87, eq. (12)] + ω = w + inv(I * tr(V) - V) * z + + # Ω [FT87, eq. (10)] + Ωtens = SMatrix{3,3}(0.0, -ω[3], ω[2], ω[3], 0.0, -ω[1], -ω[2], ω[1], 0.0) + Ω² = dot(ω, ω) + Ω = sqrt(Ω²) + + # compute Q with [FT87, eq. (44)] + if Ω² > 1e-30 # avoid a potential divide-by-zero + fac1 = sin(Δt * Ω) / Ω + fac2 = -(1.0 - cos(Δt * Ω)) / Ω² + Ωtens² = Ωtens * Ωtens + Q = I + fac1 .* Ωtens + fac2 .* Ωtens² + else + Q = SMatrix{3,3}(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) + end + + # compute Rotation of new step [FT87, eq. (36)] + R = get_tensor(storage.rotation, i) + Rₙ₊₁ = Q * R + + # compute step 4 of [FT87] + V̇ = L * V - V * Ωtens + + # compute step 5 of [FT87] + Vₙ₊₁ = V + Δt * V̇ + + # update rotation and left stretch + update_tensor!(storage.rotation, i, Rₙ₊₁) + update_tensor!(storage.left_stretch, i, Vₙ₊₁) + return nothing +end + +function rotate_stress(storage::AbstractStorage, σ, i) + R = get_tensor(storage.rotation, i) + T = R * σ * R' + return T +end From dea94e01efd1166df875b5d3ad712781bfcb486a Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Fri, 22 Nov 2024 09:04:31 +0100 Subject: [PATCH 32/40] Improved edge case handling --- src/auxiliary/static_arrays.jl | 8 ++++++++ src/physics/ns_correspondence_rotated.jl | 12 +++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/auxiliary/static_arrays.jl b/src/auxiliary/static_arrays.jl index 79373128..c24a3e47 100644 --- a/src/auxiliary/static_arrays.jl +++ b/src/auxiliary/static_arrays.jl @@ -34,3 +34,11 @@ end V = SVector{3}(M[1, j] - M[1, i], M[2, j] - M[2, i], M[3, j] - M[3, i]) return V end + +function invreg(M::StaticMatrix{N,N,T}, threshold::Real=eps()) where {N,T} + U, S, V = svd(M) + Sinvreg = SVector{N,T}((s > threshold ? 1/s : 0) for s in S) + Sinv = Diagonal{T,SVector{N,T}}(Sinvreg) + Minv = V * Sinv * U' + return Minv +end diff --git a/src/physics/ns_correspondence_rotated.jl b/src/physics/ns_correspondence_rotated.jl index 3aa2938e..4db7d75d 100644 --- a/src/physics/ns_correspondence_rotated.jl +++ b/src/physics/ns_correspondence_rotated.jl @@ -277,7 +277,7 @@ function calc_weights_and_defgrad!(storage::NSCRStorage, system::BondSystem, _Ḟ += temp * (Δvij * ΔXij') wi += temp end - Kinv = inv(K) + Kinv = invreg(K) F = _F * Kinv Ḟ = _Ḟ * Kinv update_tensor!(storage.defgrad, i, F) @@ -346,7 +346,10 @@ function force_density_point!(storage::NSCRStorage, system::BondSystem, mat::NSC Ḟij = Ḟb + ΔḞij Pij = calc_first_piola_kirchhoff!(storage, mat, params, Fij, Ḟij, Δt, bond_id) Tempij = I - ΔXij * ΔXijLL - ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) + # ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) + wj = weighted_volume[j] + ϕ = (wi > 0 && wj > 0) ? (0.5 / wi + 0.5 / wj) : 0.0 + ω̃ij = kernel(system, bond_id) * ϕ ∑P += ω̃ij * (Pij * Tempij) end end @@ -358,7 +361,10 @@ function force_density_point!(storage::NSCRStorage, system::BondSystem, mat::NSC ΔXij = get_coordinates_diff(system, i, j) Pij = get_tensor(storage.first_piola_kirchhoff, bond_id) Φij = get_vector(gradient_weight, bond_id) - ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) + # ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) + wj = weighted_volume[j] + ϕ = (wi > 0 && wj > 0) ? (0.5 / wi + 0.5 / wj) : 0.0 + ω̃ij = kernel(system, bond_id) * ϕ tij = ω̃ij / (L * L) * (Pij * ΔXij) + ∑P * Φij update_add_b_int!(storage, i, tij * volume[j]) update_add_b_int!(storage, j, -tij * volume[i]) From f1a3753869a3238a9655acfe56f392f3e773b48b Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Tue, 3 Dec 2024 11:44:54 +0100 Subject: [PATCH 33/40] documentation updates --- src/physics/correspondence.jl | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index 5a9a1c5d..45af5849 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -1,20 +1,24 @@ """ - CMaterial(; maxdmg, zem) + CMaterial(; kernel, model, zem, maxdmg) A material type used to assign the material of a [`Body`](@ref) with the local continuum consistent (correspondence) formulation of non-ordinary state-based peridynamics. # Keywords +- `kernel::Function`: Kernel function used for weighting the interactions between points. + (default: `linear_kernel`) +- `model::AbstractConstitutiveModel`: Constitutive model defining the material behavior. + (default: `NeoHookeNonlinear()`) +- `zem::AbstractZEMStabilization`: Zero-energy mode stabilization. The + stabilization algorithm of Silling (2017) is used as default. + (default: `ZEMSilling()`) - `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is exceeded, all bonds of that point are broken because the deformation gradient would then possibly contain `NaN` values. - (default: `0.95`) -- `zem::AbstractZEMStabilization`: zero-energy mode stabilization. The - stabilization algorithm of Silling (2017) is used as default. - (default: `ZEMSilling()`) + (default: `0.85`) !!! note "Stability of fracture simulations" - This formulation is known to be not suitable for fracture simultations without + This formulation is known to be not suitable for fracture simulations without stabilization of the zero-energy modes. Therefore be careful when doing fracture simulations and try out different parameters for `maxdmg` and `zem`. @@ -22,7 +26,7 @@ consistent (correspondence) formulation of non-ordinary state-based peridynamics ```julia-repl julia> mat = CMaterial() -CMaterial(maxdmg=0.95, zem_fac=ZEMSilling()) +CMaterial(maxdmg=0.85, zem=ZEMSilling()) ``` --- @@ -35,10 +39,14 @@ Material type for the local continuum consistent (correspondence) formulation of non-ordinary state-based peridynamics. # Fields +- `kernel::Function`: Kernel function used for weighting the interactions between points. + See the constructor docs for more informations. +- `model::AbstractConstitutiveModel`: Constitutive model defining the material behavior. See + the constructor docs for more informations. +- `zem::AbstractZEMStabilization`: Zero-energy mode stabilization. See the constructor docs + for more informations. - `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. See the constructor docs for more informations. -- `zem_fac::Float64`: Correction factor used for zero-energy mode stabilization. See the - constructor docs for more informations. # Allowed material parameters When using [`material!`](@ref) on a [`Body`](@ref) with `CMaterial`, then the following @@ -191,8 +199,8 @@ function calc_first_piola_kirchhoff!(storage::CStorage, mat::CMaterial, end function c_force_density!(storage::CStorage, system::BondSystem, mat::CMaterial, - params::CPointParameters, zem_correction::ZEMSilling, - PKinv::SMatrix, defgrad_res, i) + params::CPointParameters, zem_correction::ZEMSilling, + PKinv::SMatrix, defgrad_res, i) (; bonds, volume) = system (; bond_active) = storage (; F, ω0) = defgrad_res From 8d12c8a620462dba437e2372afd5355b174e1f56 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Tue, 3 Dec 2024 12:30:07 +0100 Subject: [PATCH 34/40] Improved correspondence material interface --- src/Peridynamics.jl | 5 +- src/discretization/bond_system.jl | 1 + src/physics/correspondence.jl | 29 ++-- src/physics/correspondence_rotated.jl | 214 ++++++++++++++++++++++++++ 4 files changed, 234 insertions(+), 15 deletions(-) create mode 100644 src/physics/correspondence_rotated.jl diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index f8b0c6a1..6f865f1d 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -9,8 +9,8 @@ end import LibGit2, Dates # Material models -export BBMaterial, OSBMaterial, CMaterial, BACMaterial, RKCMaterial, NSCMaterial, - NSCRMaterial, CKIMaterial +export BBMaterial, OSBMaterial, CMaterial, CRMaterial, BACMaterial, RKCMaterial, + NSCMaterial, NSCRMaterial, CKIMaterial # CMaterial related types export NeoHookeNonlinear, SaintVenantKirchhoff, ZEMSilling @@ -129,6 +129,7 @@ include("physics/continuum_kinematics_inspired.jl") include("physics/ordinary_state_based.jl") include("physics/constitutive_models.jl") include("physics/correspondence.jl") +include("physics/correspondence_rotated.jl") include("physics/ns_correspondence.jl") include("physics/ns_correspondence_rotated.jl") include("physics/ba_correspondence.jl") diff --git a/src/discretization/bond_system.jl b/src/discretization/bond_system.jl index feb34121..a341536a 100644 --- a/src/discretization/bond_system.jl +++ b/src/discretization/bond_system.jl @@ -229,6 +229,7 @@ function calc_force_density!(chunk::AbstractBodyChunk{<:AbstractBondSystem}, t, for point_id in each_point_idx(chunk) force_density_point!(storage, system, mat, paramsetup, t, Δt, point_id) end + nancheck(chunk, t) return nothing end diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index 45af5849..76e19b6c 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -147,15 +147,17 @@ function init_field(::CMaterial, ::AbstractTimeSolver, system::BondSystem, return zeros(get_n_loc_points(system)) end -function force_density_point!(storage::CStorage, system::BondSystem, mat::CMaterial, +function force_density_point!(storage::AbstractStorage, system::AbstractSystem, + mat::AbstractCorrespondenceMaterial, paramhandler::AbstractParameterHandler, t, Δt, i) params = get_params(paramhandler, i) force_density_point!(storage, system, mat, params, t, Δt, i) return nothing end -function force_density_point!(storage::CStorage, system::BondSystem, mat::CMaterial, - params::CPointParameters, t, Δt, i) +function force_density_point!(storage::AbstractStorage, system::AbstractSystem, + mat::AbstractCorrespondenceMaterial, + params::AbstractPointParameters, t, Δt, i) defgrad_res = calc_deformation_gradient(storage, system, mat, params, i) too_much_damage!(storage, system, mat, defgrad_res, i) && return nothing PKinv = calc_first_piola_kirchhoff!(storage, mat, params, defgrad_res, Δt, i) @@ -164,8 +166,8 @@ function force_density_point!(storage::CStorage, system::BondSystem, mat::CMater return nothing end -function calc_deformation_gradient(storage::CStorage, system::BondSystem, - mat::CMaterial, params::CPointParameters, i) +function calc_deformation_gradient(storage::CStorage, system::BondSystem, ::CMaterial, + ::CPointParameters, i) (; bonds, volume) = system (; bond_active) = storage K = zero(SMatrix{3,3,Float64,9}) @@ -173,14 +175,15 @@ function calc_deformation_gradient(storage::CStorage, system::BondSystem, ω0 = 0.0 for bond_id in each_bond_idx(system, i) bond = bonds[bond_id] - j, L = bond.neighbor, bond.length + j = bond.neighbor ΔXij = get_diff(system.position, i, j) Δxij = get_diff(storage.position, i, j) ωij = kernel(system, bond_id) * bond_active[bond_id] ω0 += ωij temp = ωij * volume[j] - K += temp * (ΔXij * ΔXij') - _F += temp * (Δxij * ΔXij') + ΔXijt = ΔXij' + K += temp * (ΔXij * ΔXijt) + _F += temp * (Δxij * ΔXijt) end Kinv = inv(K) F = _F * Kinv @@ -198,9 +201,9 @@ function calc_first_piola_kirchhoff!(storage::CStorage, mat::CMaterial, return PKinv end -function c_force_density!(storage::CStorage, system::BondSystem, mat::CMaterial, - params::CPointParameters, zem_correction::ZEMSilling, - PKinv::SMatrix, defgrad_res, i) +function c_force_density!(storage::AbstractStorage, system::AbstractSystem, + ::AbstractCorrespondenceMaterial, params::AbstractPointParameters, + zem_correction::ZEMSilling, PKinv, defgrad_res, i) (; bonds, volume) = system (; bond_active) = storage (; F, ω0) = defgrad_res @@ -226,8 +229,8 @@ function c_force_density!(storage::CStorage, system::BondSystem, mat::CMaterial, return nothing end -function too_much_damage!(storage::CStorage, system::BondSystem, mat::CMaterial, - defgrad_res, i) +function too_much_damage!(storage::AbstractStorage, system::AbstractSystem, + mat::AbstractCorrespondenceMaterial, defgrad_res, i) (; F) = defgrad_res if storage.damage[i] > mat.maxdmg || containsnan(F) # kill all bonds of this point diff --git a/src/physics/correspondence_rotated.jl b/src/physics/correspondence_rotated.jl new file mode 100644 index 00000000..dcad646b --- /dev/null +++ b/src/physics/correspondence_rotated.jl @@ -0,0 +1,214 @@ +""" + CRMaterial(; kernel, model, zem, maxdmg) + +A material type used to assign the material of a [`Body`](@ref) with the local continuum +consistent (correspondence) formulation of non-ordinary state-based peridynamics. + +# Keywords +- `kernel::Function`: Kernel function used for weighting the interactions between points. + (default: `linear_kernel`) +- `model::AbstractConstitutiveModel`: Constitutive model defining the material behavior. + (default: `NeoHookeNonlinear()`) +- `zem::AbstractZEMStabilization`: Zero-energy mode stabilization. The + stabilization algorithm of Silling (2017) is used as default. + (default: `ZEMSilling()`) +- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is + exceeded, all bonds of that point are broken because the deformation gradient would then + possibly contain `NaN` values. + (default: `0.85`) + +!!! note "Stability of fracture simulations" + This formulation is known to be not suitable for fracture simulations without + stabilization of the zero-energy modes. Therefore be careful when doing fracture + simulations and try out different parameters for `maxdmg` and `zem`. + +# Examples + +```julia-repl +julia> mat = CRMaterial() +CRMaterial(maxdmg=0.85, zem=ZEMSilling()) +``` + +--- + +```julia +CRMaterial +``` + +Material type for the local continuum consistent (correspondence) formulation of +non-ordinary state-based peridynamics. + +# Fields +- `kernel::Function`: Kernel function used for weighting the interactions between points. + See the constructor docs for more informations. +- `model::AbstractConstitutiveModel`: Constitutive model defining the material behavior. See + the constructor docs for more informations. +- `zem::AbstractZEMStabilization`: Zero-energy mode stabilization. See the constructor docs + for more informations. +- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. See the + constructor docs for more informations. + +# Allowed material parameters +When using [`material!`](@ref) on a [`Body`](@ref) with `CMaterial`, then the following +parameters are allowed: +- `horizon::Float64`: Radius of point interactions +- `rho::Float64`: Density +- `E::Float64`: Young's modulus +- `nu::Float64`: Poisson's ratio +- `Gc::Float64`: Critical energy release rate +- `epsilon_c::Float64`: Critical strain + +# Allowed export fields +When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with +`CMaterial`, the following fields are allowed: +- `position::Matrix{Float64}`: Position of each point +- `displacement::Matrix{Float64}`: Displacement of each point +- `velocity::Matrix{Float64}`: Velocity of each point +- `velocity_half::Matrix{Float64}`: Velocity parameter for Verlet time solver +- `acceleration::Matrix{Float64}`: Acceleration of each point +- `b_int::Matrix{Float64}`: Internal force density of each point +- `b_ext::Matrix{Float64}`: External force density of each point +- `damage::Vector{Float64}`: Damage of each point +- `n_active_bonds::Vector{Int}`: Number of intact bonds of each point +""" +struct CRMaterial{CM,ZEM,K} <: AbstractCorrespondenceMaterial{CM,ZEM} + kernel::K + constitutive_model::CM + zem_stabilization::ZEM + maxdmg::Float64 + function CRMaterial(kernel::K, cm::CM, zem::ZEM, maxdmg::Real) where {CM,ZEM,K} + return new{CM,ZEM,K}(kernel, cm, zem, maxdmg) + end +end + +function Base.show(io::IO, @nospecialize(mat::CRMaterial)) + print(io, typeof(mat)) + print(io, msg_fields_in_brackets(mat, (:maxdmg,))) + return nothing +end + +function CRMaterial(; kernel::Function=linear_kernel, + model::AbstractConstitutiveModel=NeoHookeNonlinear(), + zem::AbstractZEMStabilization=ZEMSilling(), maxdmg::Real=0.85) + return CRMaterial(kernel, model, zem, maxdmg) +end + +# TODO: remove the function `material_type` from `@params` macro, then point parameters can +# be reused by other material types +struct CRPointParameters <: AbstractPointParameters + δ::Float64 + rho::Float64 + E::Float64 + nu::Float64 + G::Float64 + K::Float64 + λ::Float64 + μ::Float64 + Gc::Float64 + εc::Float64 + bc::Float64 +end + +function CRPointParameters(mat::CRMaterial, p::Dict{Symbol,Any}) + (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) + (; Gc, εc) = get_frac_params(p, δ, K) + bc = 18 * K / (π * δ^4) # bond constant + return CRPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) +end + +@params CRMaterial CRPointParameters + +@storage CRMaterial struct CRStorage + @lthfield position::Matrix{Float64} + @pointfield displacement::Matrix{Float64} + @lthfield velocity::Matrix{Float64} + @pointfield velocity_half::Matrix{Float64} + @pointfield velocity_half_old::Matrix{Float64} + @pointfield acceleration::Matrix{Float64} + @htlfield b_int::Matrix{Float64} + @pointfield b_int_old::Matrix{Float64} + @pointfield b_ext::Matrix{Float64} + @pointfield density_matrix::Matrix{Float64} + @pointfield damage::Vector{Float64} + bond_active::Vector{Bool} + @pointfield n_active_bonds::Vector{Int} + @pointfield stress::Matrix{Float64} + @pointfield von_mises_stress::Vector{Float64} + @pointfield left_stretch::Matrix{Float64} + @pointfield rotation::Matrix{Float64} +end + +function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:velocity}) + return zeros(3, get_n_points(system)) +end + +function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int}) + return zeros(3, get_n_points(system)) +end + +function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:stress}) + return zeros(9, get_n_loc_points(system)) +end + +function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:von_mises_stress}) + return zeros(get_n_loc_points(system)) +end + +function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:left_stretch}) + V = zeros(9, get_n_loc_points(system)) + V[[1, 5, 9], :] .= 1.0 + return V +end + +function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:rotation}) + R = zeros(9, get_n_loc_points(system)) + R[[1, 5, 9], :] .= 1.0 + return R +end + +function calc_deformation_gradient(storage::CRStorage, system::BondSystem, + ::CRMaterial, ::CRPointParameters, i) + (; bonds, volume) = system + (; bond_active) = storage + K = zero(SMatrix{3,3,Float64,9}) + _F = zero(SMatrix{3,3,Float64,9}) + _Ḟ = zero(SMatrix{3,3,Float64,9}) + ω0 = 0.0 + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j = bond.neighbor + ΔXij = get_diff(system.position, i, j) + Δxij = get_diff(storage.position, i, j) + Δvij = get_diff(storage.velocity, i, j) + ωij = kernel(system, bond_id) * bond_active[bond_id] + ω0 += ωij + temp = ωij * volume[j] + ΔXijt = ΔXij' + K += temp * (ΔXij * ΔXijt) + _F += temp * (Δxij * ΔXijt) + _Ḟ += temp * (Δvij * ΔXijt) + end + Kinv = inv(K) + F = _F * Kinv + Ḟ = _Ḟ * Kinv + return (; F, Ḟ, Kinv, ω0) +end + +function calc_first_piola_kirchhoff!(storage::CRStorage, mat::CRMaterial, + params::CRPointParameters, defgrad_res, Δt, i) + (; F, Ḟ, Kinv) = defgrad_res + _P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) + _σ = cauchy_stress(_P, F) + init_stress_rotation!(storage, F, Ḟ, Δt, i) + T = rotate_stress(storage, _σ, i) + P = first_piola_kirchhoff(T, F) + PKinv = P * Kinv + σ = cauchy_stress(P, F) + update_tensor!(storage.stress, i, σ) + storage.von_mises_stress[i] = von_mises_stress(σ) + return PKinv +end From ae311e1717d58ddeffe8a6b0dfc6e39d7b600fb1 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Thu, 6 Feb 2025 13:55:44 +0100 Subject: [PATCH 35/40] Experimental drafts and enhancements --- Project.toml | 2 + src/Peridynamics.jl | 2 + src/physics/ba_correspondence.jl | 9 +- src/physics/constitutive_models.jl | 48 +++- src/physics/correspondence.jl | 26 +- src/physics/correspondence_rotated.jl | 45 +++- src/physics/ns_correspondence.jl | 15 +- src/physics/ns_correspondence_rotated.jl | 220 ++++++++++++--- src/physics/rk_correspondence.jl | 284 ++++++++++++-------- src/physics/stress.jl | 12 +- src/time_solvers/velocity_verlet.jl | 5 +- test/integration/b_int_rk_correspondence.jl | 6 +- test/physics/test_rk_correspondence.jl | 220 ++++++++++++--- 13 files changed, 679 insertions(+), 215 deletions(-) diff --git a/Project.toml b/Project.toml index eaeffe90..d2ec45b9 100644 --- a/Project.toml +++ b/Project.toml @@ -8,6 +8,7 @@ AbaqusReader = "bc6b9049-e460-56d6-94b4-a597b2c0390d" Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +Infiltrator = "5903a43b-9cc3-4c30-8d17-598619ec4e9b" LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433" LightXML = "9c8b4983-aa76-5018-a973-4c85ecc9e179" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" @@ -26,6 +27,7 @@ AbaqusReader = "0.2" Base64 = "1.8" CodecZlib = "0.7" Dates = "1.8" +Infiltrator = "1.8.3" LibGit2 = "1.8" LightXML = "0.9" LinearAlgebra = "1.8" diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index 6f865f1d..dd07b827 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -6,6 +6,8 @@ using Base.Threads, Printf, LinearAlgebra, StaticArrays, PointNeighbors, Progres using ThreadPinning end +using Infiltrator + import LibGit2, Dates # Material models diff --git a/src/physics/ba_correspondence.jl b/src/physics/ba_correspondence.jl index f9e98ee6..113afc38 100644 --- a/src/physics/ba_correspondence.jl +++ b/src/physics/ba_correspondence.jl @@ -193,12 +193,13 @@ function calc_deformation_gradient(storage::BACStorage, system::BondAssociatedSy _F = zero(SMatrix{3,3,Float64,9}) for bond_id in each_intersecting_bond_idx(system, i, bond_idx) bond = bonds[bond_id] - j, L = bond.neighbor, bond.length + j = bond.neighbor ΔXij = get_diff(system.position, i, j) Δxij = get_diff(storage.position, i, j) - temp = kernel(system, bond_id) * bond_active[bond_id] * volume[j] - K += temp * (ΔXij * ΔXij') - _F += temp * (Δxij * ΔXij') + ωijV = kernel(system, bond_id) * volume[j] + ωijωDV = ωijV * bond_active[bond_id] + K += ωijV * (ΔXij * ΔXij') + _F += ωijωDV * (Δxij * ΔXij') end Kinv = inv(K) F = _F * Kinv diff --git a/src/physics/constitutive_models.jl b/src/physics/constitutive_models.jl index 987c24cc..648e0037 100644 --- a/src/physics/constitutive_models.jl +++ b/src/physics/constitutive_models.jl @@ -1,9 +1,46 @@ +struct LinearElastic <: AbstractConstitutiveModel end + +function first_piola_kirchhoff(::LinearElastic, storage::AbstractStorage, + params::AbstractPointParameters, F::SMatrix{3,3,T,9}) where T + # J = det(F) + # J < eps() && return zero(SMatrix{3,3,T,9}) + # isnan(J) && return zero(SMatrix{3,3,T,9}) + E = 0.5 .* (F' * F - I) + 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]) + Cvoigt = get_hooke_matrix(params.nu, params.λ, params.μ) + Pvoigt = Cvoigt * Evoigt + P = SMatrix{3,3,Float64,9}(Pvoigt[1], Pvoigt[6], Pvoigt[5], + Pvoigt[6], Pvoigt[2], Pvoigt[4], + Pvoigt[5], Pvoigt[4], Pvoigt[3]) + return P +end + +function get_hooke_matrix(nu, λ, μ) + a = (1 - nu) * λ / nu + CVoigt = SMatrix{6,6,Float64,36}(a, λ, λ, 0, 0, 0, λ, a, λ, 0, 0, 0, λ, λ, a, 0, 0, 0, + 0, 0, 0, μ, 0, 0, 0, 0, 0, 0, μ, 0, 0, 0, 0, 0, 0, μ) + return CVoigt +end + +struct NeoHookeViera <: AbstractConstitutiveModel end + +function first_piola_kirchhoff(::NeoHookeViera, storage::AbstractStorage, + params::AbstractPointParameters, F::SMatrix{3,3,T,9}) where T + J = det(F) + # J < eps() && return zero(SMatrix{3,3,T,9}) + Cinv = inv(F' * F) + S = params.μ * (I - Cinv) + params.λ * log(J) * Cinv + P = F * S + return P +end + struct NeoHookeNonlinear <: AbstractConstitutiveModel end function first_piola_kirchhoff(::NeoHookeNonlinear, storage::AbstractStorage, - params::AbstractPointParameters, F::SMatrix{3,3}) + params::AbstractPointParameters, F::SMatrix{3,3,T,9}) where T J = det(F) - J < eps() && return zero(SMatrix{3,3}) + # J < eps() && return zero(SMatrix{3,3,T,9}) + # isnan(J) && return zero(SMatrix{3,3,T,9}) C = F' * F Cinv = inv(C) S = params.G .* (I - 1 / 3 .* tr(C) .* Cinv) .* J^(-2 / 3) .+ @@ -15,9 +52,10 @@ end struct SaintVenantKirchhoff <: AbstractConstitutiveModel end function first_piola_kirchhoff(::SaintVenantKirchhoff, storage::AbstractStorage, - params::AbstractPointParameters, F::SMatrix{3,3}) - J = det(F) - J < eps() && return zero(SMatrix{3,3}) + params::AbstractPointParameters, F::SMatrix{3,3,T,9}) where T + # J = det(F) + # J < eps() && return zero(SMatrix{3,3,T,9}) + # isnan(J) && return zero(SMatrix{3,3,T,9}) E = 0.5 .* (F' * F - I) S = params.λ * tr(E) * I + 2 * params.μ * E P = F * S diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index 76e19b6c..68d4d338 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -158,6 +158,7 @@ end function force_density_point!(storage::AbstractStorage, system::AbstractSystem, mat::AbstractCorrespondenceMaterial, params::AbstractPointParameters, t, Δt, i) + calc_failure_point!(storage, system, mat, params, i) defgrad_res = calc_deformation_gradient(storage, system, mat, params, i) too_much_damage!(storage, system, mat, defgrad_res, i) && return nothing PKinv = calc_first_piola_kirchhoff!(storage, mat, params, defgrad_res, Δt, i) @@ -166,6 +167,18 @@ function force_density_point!(storage::AbstractStorage, system::AbstractSystem, return nothing end +function calc_failure_point!(storage, system, mat, params, i) + for bond_id in each_bond_idx(system, i) + bond = system.bonds[bond_id] + j, L = bond.neighbor, bond.length + Δxij = get_coordinates_diff(storage, i, j) + l = norm(Δxij) + ε = (l - L) / L + stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + end + return nothing +end + function calc_deformation_gradient(storage::CStorage, system::BondSystem, ::CMaterial, ::CPointParameters, i) (; bonds, volume) = system @@ -213,9 +226,9 @@ function c_force_density!(storage::AbstractStorage, system::AbstractSystem, j, L = bond.neighbor, bond.length ΔXij = get_coordinates_diff(system, i, j) Δxij = get_coordinates_diff(storage, i, j) - l = norm(Δxij) - ε = (l - L) / L - stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + # l = norm(Δxij) + # ε = (l - L) / L + # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) # stabilization ωij = kernel(system, bond_id) * bond_active[bond_id] @@ -232,6 +245,13 @@ end function too_much_damage!(storage::AbstractStorage, system::AbstractSystem, mat::AbstractCorrespondenceMaterial, defgrad_res, i) (; F) = defgrad_res + # @infiltrate storage.n_active_bonds[i] ≤ 3 + # if storage.n_active_bonds[i] ≤ 3 || storage.damage[i] > mat.maxdmg || containsnan(F) + # # kill all bonds of this point + # storage.bond_active[each_bond_idx(system, i)] .= false + # storage.n_active_bonds[i] = 0 + # return true + # end if storage.damage[i] > mat.maxdmg || containsnan(F) # kill all bonds of this point storage.bond_active[each_bond_idx(system, i)] .= false diff --git a/src/physics/correspondence_rotated.jl b/src/physics/correspondence_rotated.jl index dcad646b..ba8deff3 100644 --- a/src/physics/correspondence_rotated.jl +++ b/src/physics/correspondence_rotated.jl @@ -121,8 +121,8 @@ end @storage CRMaterial struct CRStorage @lthfield position::Matrix{Float64} @pointfield displacement::Matrix{Float64} - @lthfield velocity::Matrix{Float64} - @pointfield velocity_half::Matrix{Float64} + @pointfield velocity::Matrix{Float64} + @lthfield velocity_half::Matrix{Float64} @pointfield velocity_half_old::Matrix{Float64} @pointfield acceleration::Matrix{Float64} @htlfield b_int::Matrix{Float64} @@ -139,7 +139,7 @@ end end function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:velocity}) + ::Val{:velocity_half}) return zeros(3, get_n_points(system)) end @@ -183,7 +183,7 @@ function calc_deformation_gradient(storage::CRStorage, system::BondSystem, j = bond.neighbor ΔXij = get_diff(system.position, i, j) Δxij = get_diff(storage.position, i, j) - Δvij = get_diff(storage.velocity, i, j) + Δvij = get_diff(storage.velocity_half, i, j) ωij = kernel(system, bond_id) * bond_active[bond_id] ω0 += ωij temp = ωij * volume[j] @@ -198,17 +198,38 @@ function calc_deformation_gradient(storage::CRStorage, system::BondSystem, return (; F, Ḟ, Kinv, ω0) end -function calc_first_piola_kirchhoff!(storage::CRStorage, mat::CRMaterial, +# function calc_first_piola_kirchhoff!(storage::CRStorage, mat::CRMaterial, +# params::CRPointParameters, defgrad_res, Δt, i) +# (; F, Ḟ, Kinv) = defgrad_res +# _P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) +# _σ = cauchy_stress(_P, F) +# init_stress_rotation!(storage, F, Ḟ, Δt, i) +# T = rotate_stress(storage, _σ, i) +# P = first_piola_kirchhoff(T, F) +# PKinv = P * Kinv +# σ = cauchy_stress(P, F) +# update_tensor!(storage.stress, i, σ) +# storage.von_mises_stress[i] = von_mises_stress(σ) +# return PKinv +# end + +function calc_first_piola_kirchhoff!(storage::CRStorage, ::CRMaterial, params::CRPointParameters, defgrad_res, Δt, i) (; F, Ḟ, Kinv) = defgrad_res - _P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) - _σ = cauchy_stress(_P, F) - init_stress_rotation!(storage, F, Ḟ, Δt, i) - T = rotate_stress(storage, _σ, i) + D = init_stress_rotation!(storage, F, Ḟ, Δt, i) + if iszero(D) + storage.von_mises_stress[i] = 0.0 + return zero(SMatrix{3,3,Float64,9}) + end + Δε = D * Δt + Δθ = tr(Δε) + Δεᵈᵉᵛ = Δε - Δθ / 3 * I + σ = get_tensor(storage.stress, i) + σₙ₊₁ = σ + 2 * params.G * Δεᵈᵉᵛ + params.K * Δθ * I + update_tensor!(storage.stress, i, σₙ₊₁) + T = rotate_stress(storage, σₙ₊₁, i) + storage.von_mises_stress[i] = von_mises_stress(T) P = first_piola_kirchhoff(T, F) PKinv = P * Kinv - σ = cauchy_stress(P, F) - update_tensor!(storage.stress, i, σ) - storage.von_mises_stress[i] = von_mises_stress(σ) return PKinv end diff --git a/src/physics/ns_correspondence.jl b/src/physics/ns_correspondence.jl index 285005b1..aac74260 100644 --- a/src/physics/ns_correspondence.jl +++ b/src/physics/ns_correspondence.jl @@ -258,6 +258,7 @@ function calc_weights_and_defgrad!(storage::NSCStorage, system::BondSystem, j = bond.neighbor ΔXij = get_diff(system.position, i, j) ωij = kernel(system, bond_id) * bond_active[bond_id] + # temp = ωij temp = ωij * volume[j] Ψ = temp * (Kinv * ΔXij) update_vector!(gradient_weight, bond_id, Ψ) @@ -355,7 +356,7 @@ function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMat (; bond_active, gradient_weight, defgrad, weighted_volume) = storage Fi = get_tensor(defgrad, i) - too_much_damage!(storage, system, mat, Fi, i) && return nothing + # too_much_damage!(storage, system, mat, Fi, i) && return nothing # Stress integral SI wi = weighted_volume[i] @@ -378,8 +379,11 @@ function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMat Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) update_tensor!(storage.first_piola_kirchhoff, bond_id, Pij) Tempij = I - ΔXij * ΔXijLL - ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) - ∑P += ω̃ij * (Pij * Tempij) + wj = weighted_volume[j] + ϕ = (wi > 0 && wj > 0) ? (0.5 / wi + 0.5 / wj) : 0.0 + ω̃ij = kernel(system, bond_id) * ϕ + ∑Pij = ω̃ij * (Pij * Tempij) + ∑P += ∑Pij end end @@ -390,7 +394,9 @@ function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMat ΔXij = get_coordinates_diff(system, i, j) Pij = get_tensor(storage.first_piola_kirchhoff, bond_id) Φij = get_vector(gradient_weight, bond_id) - ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) + wj = weighted_volume[j] + ϕ = (wi > 0 && wj > 0) ? (0.5 / wi + 0.5 / wj) : 0.0 + ω̃ij = kernel(system, bond_id) * ϕ tij = ω̃ij / (L * L) * (Pij * ΔXij) + ∑P * Φij update_add_b_int!(storage, i, tij * volume[j]) update_add_b_int!(storage, j, -tij * volume[i]) @@ -399,6 +405,7 @@ function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMat return nothing end + # NODALLY STABLIZIED VERSION!!! WORKING, BUT NOT SURE IF CORRECT! # function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, # params::NSCPointParameters, P::SMatrix, i) diff --git a/src/physics/ns_correspondence_rotated.jl b/src/physics/ns_correspondence_rotated.jl index 4db7d75d..5d333bba 100644 --- a/src/physics/ns_correspondence_rotated.jl +++ b/src/physics/ns_correspondence_rotated.jl @@ -100,8 +100,8 @@ end @storage NSCRMaterial struct NSCRStorage @lthfield position::Matrix{Float64} @pointfield displacement::Matrix{Float64} - @lthfield velocity::Matrix{Float64} - @pointfield velocity_half::Matrix{Float64} + @pointfield velocity::Matrix{Float64} + @lthfield velocity_half::Matrix{Float64} @pointfield velocity_half_old::Matrix{Float64} @pointfield acceleration::Matrix{Float64} @htlfield b_int::Matrix{Float64} @@ -112,19 +112,21 @@ end bond_active::Vector{Bool} @pointfield n_active_bonds::Vector{Int} @pointfield damage_changed::Vector{Bool} - @pointfield stress::Matrix{Float64} - @pointfield von_mises_stress::Vector{Float64} + # @pointfield stress::Matrix{Float64} + # @pointfield von_mises_stress::Vector{Float64} @lthfield defgrad::Matrix{Float64} @lthfield defgrad_dot::Matrix{Float64} @lthfield weighted_volume::Vector{Float64} gradient_weight::Matrix{Float64} rotation::Matrix{Float64} left_stretch::Matrix{Float64} + unrot_rate_of_deformation::Matrix{Float64} + bond_stress::Matrix{Float64} first_piola_kirchhoff::Matrix{Float64} end function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:velocity}) + ::Val{:velocity_half}) return zeros(3, get_n_points(system)) end @@ -161,6 +163,11 @@ function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, return V end +function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:unrot_rate_of_deformation}) + return zeros(9, get_n_bonds(system)) +end + function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:defgrad}) return zeros(9, get_n_points(system)) @@ -186,30 +193,45 @@ function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, return zeros(9, get_n_bonds(system)) end +function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, + ::Val{:bond_stress}) + return zeros(9, get_n_bonds(system)) +end + function initialize!(chunk::BodyChunk{<:BondSystem,<:NSCRMaterial}) chunk.storage.damage_changed .= true return nothing end @inline function calc_damage!(chunk::BodyChunk{<:BondSystem,<:NSCRMaterial}) - (; n_neighbors) = chunk.system - (; n_active_bonds, damage, damage_changed) = chunk.storage - for point_id in each_point_idx(chunk) - old_damage = damage[point_id] - new_damage = 1 - n_active_bonds[point_id] / n_neighbors[point_id] + (; system, storage, paramsetup) = chunk + (; n_neighbors, bonds) = system + (; n_active_bonds, damage, damage_changed) = storage + for i in each_point_idx(chunk) + params = get_params(paramsetup, i) + for bond_id in each_bond_idx(system, i) + bond = bonds[bond_id] + j, L = bond.neighbor, bond.length + Δxij = get_coordinates_diff(storage, i, j) + l = norm(Δxij) + ε = (l - L) / L + stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + end + old_damage = damage[i] + new_damage = 1 - n_active_bonds[i] / n_neighbors[i] if new_damage > old_damage - damage_changed[point_id] = true + damage_changed[i] = true else - damage_changed[point_id] = false + damage_changed[i] = false end - damage[point_id] = new_damage + damage[i] = new_damage end return nothing end function calc_force_density!(dh::ThreadsBodyDataHandler{<:BondSystem,<:NSCRMaterial}, t, Δt) @threads :static for chunk_id in eachindex(dh.chunks) - exchange_loc_to_halo!(dh, chunk_id, (:position, :velocity)) + exchange_loc_to_halo!(dh, chunk_id, (:position, :velocity_half)) end @threads :static for chunk_id in eachindex(dh.chunks) calc_weights_and_defgrad!(dh.chunks[chunk_id], t, Δt) @@ -230,7 +252,7 @@ end function calc_force_density!(dh::MPIBodyDataHandler{<:BondSystem,<:NSCRMaterial}, t, Δt) (; chunk) = dh - exchange_loc_to_halo!(dh, (:position, :velocity)) + exchange_loc_to_halo!(dh, (:position, :velocity_half)) calc_weights_and_defgrad!(chunk, t, Δt) exchange_loc_to_halo!(dh, (:defgrad, :defgrad_dot, :weighted_volume)) calc_force_density!(chunk, t, Δt) @@ -242,14 +264,15 @@ end function calc_weights_and_defgrad!(chunk::BodyChunk{<:BondSystem,<:NSCRMaterial}, t, Δt) (; system, mat, paramsetup, storage) = chunk for i in each_point_idx(system) + calc_failure_point!(storage, system, mat, paramsetup, i) calc_weights_and_defgrad!(storage, system, mat, paramsetup, t, Δt, i) end return nothing end function calc_weights_and_defgrad!(storage::NSCRStorage, system::BondSystem, - mat::NSCRMaterial, paramhandler::AbstractParameterHandler, - t, Δt, i) + mat::NSCRMaterial, + paramhandler::AbstractParameterHandler, t, Δt, i) params = get_params(paramhandler, i) calc_weights_and_defgrad!(storage, system, mat, params, t, Δt, i) return nothing @@ -269,7 +292,7 @@ function calc_weights_and_defgrad!(storage::NSCRStorage, system::BondSystem, j = bond.neighbor ΔXij = get_diff(system.position, i, j) Δxij = get_diff(storage.position, i, j) - Δvij = get_diff(storage.velocity, i, j) + Δvij = get_diff(storage.velocity_half, i, j) ωij = kernel(system, bond_id) * bond_active[bond_id] temp = ωij * volume[j] K += temp * (ΔXij * ΔXij') @@ -277,7 +300,7 @@ function calc_weights_and_defgrad!(storage::NSCRStorage, system::BondSystem, _Ḟ += temp * (Δvij * ΔXij') wi += temp end - Kinv = invreg(K) + Kinv = inv(K) F = _F * Kinv Ḟ = _Ḟ * Kinv update_tensor!(storage.defgrad, i, F) @@ -328,13 +351,13 @@ function force_density_point!(storage::NSCRStorage, system::BondSystem, mat::NSC bond = bonds[bond_id] j, L = bond.neighbor, bond.length Δxij = get_coordinates_diff(storage, i, j) - l = norm(Δxij) - ε = (l - L) / L - stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + # l = norm(Δxij) + # ε = (l - L) / L + # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) if bond_active[bond_id] ΔXij = get_coordinates_diff(system, i, j) - Δvij = get_diff(storage.velocity, i, j) + Δvij = get_diff(storage.velocity_half, i, j) Fj = get_tensor(defgrad, j) Ḟj = get_tensor(defgrad_dot, j) Fb = 0.5 * (Fi + Fj) @@ -375,25 +398,156 @@ function force_density_point!(storage::NSCRStorage, system::BondSystem, mat::NSC end # function calc_first_piola_kirchhoff!(storage::NSCRStorage, mat::NSCRMaterial, -# params::NSCRPointParameters, F, Δt, i) +# params::NSCRPointParameters, F, Ḟ, Δt, i) # P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) # σ = cauchy_stress(P, F) -# update_tensor!(storage.stress, i, σ) -# storage.von_mises_stress[i] = von_mises_stress(σ) +# init_stress_rotation!(storage, F, Ḟ, Δt, i) +# T = rotate_stress(storage, σ, i) +# P = first_piola_kirchhoff(T, F) +# update_tensor!(storage.first_piola_kirchhoff, i, P) # return P # end -function calc_first_piola_kirchhoff!(storage::NSCRStorage, mat::NSCRMaterial, - params::NSCRPointParameters, F, Ḟ, Δt, i) - P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) - σ = cauchy_stress(P, F) - init_stress_rotation!(storage, F, Ḟ, Δt, i) - T = rotate_stress(storage, σ, i) +function calc_first_piola_kirchhoff!(storage::NSCRStorage, ::NSCRMaterial, + params::NSCRPointParameters, F, Ḟ, Δt, bond_id) + D = init_stress_rotation!(storage, F, Ḟ, Δt, bond_id) + Δε = D * Δt + Δθ = tr(Δε) + Δεᵈᵉᵛ = Δε - Δθ / 3 * I + σ = get_tensor(storage.bond_stress, bond_id) + σₙ₊₁ = σ + 2 * params.G * Δεᵈᵉᵛ + params.K * Δθ * I + update_tensor!(storage.bond_stress, bond_id, σₙ₊₁) + T = rotate_stress(storage, σₙ₊₁, bond_id) P = first_piola_kirchhoff(T, F) - update_tensor!(storage.first_piola_kirchhoff, i, P) + update_tensor!(storage.first_piola_kirchhoff, bond_id, P) return P end +# function calc_first_piola_kirchhoff!(storage, mat, params, F, Ḟ, Δt, i) +# 𝐋 = @MMatrix zeros(3,3) +# RoD = @MMatrix zeros(3,3) +# Spin = @MMatrix zeros(3,3) +# left_stretch = @MMatrix zeros(3,3) +# z = @MVector zeros(3) +# w = @MVector zeros(3) +# 𝛀Tens = @MMatrix zeros(3,3) +# Qmatrix = @MMatrix zeros(3,3) +# rot_tens_ = @MMatrix zeros(3,3) +# 𝛔_unrot = @MMatrix zeros(3,3) +# tempVec = @MMatrix zeros(3,3) +# 𝐅 = F +# 𝐅dot = Ḟ +# 𝐋 = 𝐅dot * inv(𝐅) +# RoD = 1/2 * (𝐋 + transpose(𝐋)) +# Spin = 1/2 * (𝐋 - transpose(𝐋)) +# left_stretch[1,1] = storage.left_stretch[1,i] +# left_stretch[1,2] = storage.left_stretch[2,i] +# left_stretch[1,3] = storage.left_stretch[3,i] +# left_stretch[2,1] = storage.left_stretch[4,i] +# left_stretch[2,2] = storage.left_stretch[5,i] +# left_stretch[2,3] = storage.left_stretch[6,i] +# left_stretch[3,1] = storage.left_stretch[7,i] +# left_stretch[3,2] = storage.left_stretch[8,i] +# left_stretch[3,3] = storage.left_stretch[9,i] +# z[1] = - storage.left_stretch[3, i] * RoD[4] - storage.left_stretch[6, i] * RoD[5] - +# storage.left_stretch[9, i] * RoD[6] + storage.left_stretch[2, i] * RoD[7] + +# storage.left_stretch[5, i] * RoD[8] + storage.left_stretch[8, i] * RoD[9]; +# z[2] = storage.left_stretch[3, i] * RoD[1] + storage.left_stretch[6, i] * RoD[2] + +# storage.left_stretch[9, i] * RoD[3] - storage.left_stretch[1, i] * RoD[7] - +# storage.left_stretch[4, i] * RoD[8] - storage.left_stretch[7, i] * RoD[9]; +# z[3] = - storage.left_stretch[2, i] * RoD[1] - storage.left_stretch[5, i] * RoD[2] - +# storage.left_stretch[8, i] * RoD[3] + storage.left_stretch[1, i] * RoD[4] + +# storage.left_stretch[4, i] * RoD[5] + storage.left_stretch[7, i] * RoD[6]; +# w[1] = 0.5 * (Spin[3,2] - Spin[2,3]) +# w[2] = 0.5 * (Spin[1,3] - Spin[3,1]) +# w[3] = 0.5 * (Spin[2,1] - Spin[1,2]) +# traceV = storage.left_stretch[1, i] + storage.left_stretch[5, i] + storage.left_stretch[9, i] +# omega = w + inv(traceV * I - left_stretch) * z +# 𝛀Tens[1,1] = 0.0 +# 𝛀Tens[1,2] = -omega[3] +# 𝛀Tens[1,3] = omega[2] +# 𝛀Tens[2,1] = omega[3] +# 𝛀Tens[2,2] = 0.0 +# 𝛀Tens[2,3] = -omega[1] +# 𝛀Tens[3,1] = -omega[2] +# 𝛀Tens[3,2] = omega[1] +# 𝛀Tens[3,3] = 0.0 +# ΩSq = omega[1]^2 + omega[2]^2 + omega[3]^2 +# Ω = sqrt(ΩSq) +# if ΩSq > 1e-16 && Ω !== Inf +# scfac1 = sin(Δt * Ω) / Ω +# scfac2 = -(1 - cos(Δt * Ω)) / ΩSq +# 𝛀TensSq = 𝛀Tens * 𝛀Tens +# Qmatrix = I + scfac1 * 𝛀Tens + scfac2 * 𝛀TensSq +# else +# Qmatrix .= 0. +# Qmatrix[1,1] = 1.0 +# Qmatrix[2,2] = 1.0 +# Qmatrix[3,3] = 1.0 +# end +# rot_tens_[1,1] = storage.rotation[1,i] +# rot_tens_[1,2] = storage.rotation[2,i] +# rot_tens_[1,3] = storage.rotation[3,i] +# rot_tens_[2,1] = storage.rotation[4,i] +# rot_tens_[2,2] = storage.rotation[5,i] +# rot_tens_[2,3] = storage.rotation[6,i] +# rot_tens_[3,1] = storage.rotation[7,i] +# rot_tens_[3,2] = storage.rotation[8,i] +# rot_tens_[3,3] = storage.rotation[9,i] +# rot_tens = Qmatrix * rot_tens_ +# storage.rotation[1,i] = rot_tens[1,1] +# storage.rotation[2,i] = rot_tens[1,2] +# storage.rotation[3,i] = rot_tens[1,3] +# storage.rotation[4,i] = rot_tens[2,1] +# storage.rotation[5,i] = rot_tens[2,2] +# storage.rotation[6,i] = rot_tens[2,3] +# storage.rotation[7,i] = rot_tens[3,1] +# storage.rotation[8,i] = rot_tens[3,2] +# storage.rotation[9,i] = rot_tens[3,3] +# Vdot = 𝐋 * left_stretch - left_stretch * 𝛀Tens +# storage.left_stretch[1,i] += Δt * Vdot[1,1] +# storage.left_stretch[2,i] += Δt * Vdot[1,2] +# storage.left_stretch[3,i] += Δt * Vdot[1,3] +# storage.left_stretch[4,i] += Δt * Vdot[2,1] +# storage.left_stretch[5,i] += Δt * Vdot[2,2] +# storage.left_stretch[6,i] += Δt * Vdot[2,3] +# storage.left_stretch[7,i] += Δt * Vdot[3,1] +# storage.left_stretch[8,i] += Δt * Vdot[3,2] +# storage.left_stretch[9,i] += Δt * Vdot[3,3] +# tempVec = RoD * rot_tens +# UnRotRoD = transpose(rot_tens) * tempVec +# strainInc = UnRotRoD * Δt +# deviatoricStrain = copy(strainInc) +# dilatation = strainInc[1,1] + strainInc[2,2] + strainInc[3,3] +# deviatoricStrain[1,1] -= dilatation/3 +# deviatoricStrain[2,2] -= dilatation/3 +# deviatoricStrain[3,3] -= dilatation/3 +# storage.bond_stress[1,i] += deviatoricStrain[1,1] * 2 * params.G + params.K * dilatation +# storage.bond_stress[2,i] += deviatoricStrain[1,2] * 2 * params.G +# storage.bond_stress[3,i] += deviatoricStrain[1,3] * 2 * params.G +# storage.bond_stress[4,i] += deviatoricStrain[2,1] * 2 * params.G +# storage.bond_stress[5,i] += deviatoricStrain[2,2] * 2 * params.G + params.K * dilatation +# storage.bond_stress[6,i] += deviatoricStrain[2,3] * 2 * params.G +# storage.bond_stress[7,i] += deviatoricStrain[3,1] * 2 * params.G +# storage.bond_stress[8,i] += deviatoricStrain[3,2] * 2 * params.G +# storage.bond_stress[9,i] += deviatoricStrain[3,3] * 2 * params.G + params.K * dilatation +# 𝛔_unrot[1,1] = storage.bond_stress[1,i] +# 𝛔_unrot[1,2] = storage.bond_stress[2,i] +# 𝛔_unrot[1,3] = storage.bond_stress[3,i] +# 𝛔_unrot[2,1] = storage.bond_stress[4,i] +# 𝛔_unrot[2,2] = storage.bond_stress[5,i] +# 𝛔_unrot[2,3] = storage.bond_stress[6,i] +# 𝛔_unrot[3,1] = storage.bond_stress[7,i] +# 𝛔_unrot[3,2] = storage.bond_stress[8,i] +# 𝛔_unrot[3,3] = storage.bond_stress[9,i] +# tempVec = 𝛔_unrot * transpose(rot_tens) +# T = rot_tens * tempVec +# J = det(F) +# P = J * T * inv(F)' +# update_tensor!(storage.first_piola_kirchhoff, i, SMatrix{3,3,Float64,9}(P)) +# return P +# end + # Working version!!! # function nsc_force_density!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, # params::NSCRPointParameters, P::SMatrix, i) diff --git a/src/physics/rk_correspondence.jl b/src/physics/rk_correspondence.jl index 124dac62..e765f564 100644 --- a/src/physics/rk_correspondence.jl +++ b/src/physics/rk_correspondence.jl @@ -180,18 +180,44 @@ function initialize!(chunk::BodyChunk{<:BondSystem,<:RKCMaterial}) return nothing end +# @inline function calc_damage!(chunk::BodyChunk{<:BondSystem,<:RKCMaterial}) +# (; n_neighbors) = chunk.system +# (; n_active_bonds, damage, damage_changed) = chunk.storage +# for point_id in each_point_idx(chunk) +# old_damage = damage[point_id] +# new_damage = 1 - n_active_bonds[point_id] / n_neighbors[point_id] +# if new_damage > old_damage +# damage_changed[point_id] = true +# else +# damage_changed[point_id] = false +# end +# damage[point_id] = new_damage +# end +# return nothing +# end + @inline function calc_damage!(chunk::BodyChunk{<:BondSystem,<:RKCMaterial}) - (; n_neighbors) = chunk.system - (; n_active_bonds, damage, damage_changed) = chunk.storage - for point_id in each_point_idx(chunk) - old_damage = damage[point_id] - new_damage = 1 - n_active_bonds[point_id] / n_neighbors[point_id] + (; system, storage, paramsetup) = chunk + (; n_neighbors, bonds) = system + (; n_active_bonds, damage, damage_changed) = storage + for i in each_point_idx(chunk) + # params = get_params(paramsetup, i) + # for bond_id in each_bond_idx(system, i) + # bond = bonds[bond_id] + # j, L = bond.neighbor, bond.length + # Δxij = get_coordinates_diff(storage, i, j) + # l = norm(Δxij) + # ε = (l - L) / L + # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + # end + old_damage = damage[i] + new_damage = 1 - n_active_bonds[i] / n_neighbors[i] if new_damage > old_damage - damage_changed[point_id] = true + damage_changed[i] = true else - damage_changed[point_id] = false + damage_changed[i] = false end - damage[point_id] = new_damage + damage[i] = new_damage end return nothing end @@ -219,7 +245,7 @@ end function calc_force_density!(dh::MPIBodyDataHandler{<:BondSystem,<:RKCMaterial}, t, Δt) (; chunk) = dh - exchange_loc_to_halo!(dh) + exchange_loc_to_halo!(dh, (:position,)) calc_weights_and_defgrad!(chunk, t, Δt) exchange_loc_to_halo!(dh, (:defgrad, :weighted_volume)) calc_force_density!(chunk, t, Δt) @@ -257,23 +283,16 @@ function calc_gradient_weights!(storage::RKCStorage, system::BondSystem, mat::RK j = bond.neighbor ΔXij = get_diff(system.position, i, j) Q = get_monomial_vector(accuracy_order, ΔXij, δ) - ωij = kernel(system, bond_id) * bond_active[bond_id] + ωij = kernel(system, bond_id) #* bond_active[bond_id] temp = ωij * volume[j] M += temp * (Q * Q') wi += temp end weighted_volume[i] = wi - # @infiltrate # calculate inverse of moment matrix, must be a full rank matrix! - # regularization_term = 1e-6 * δ * δ * δ - # M += regularization_term * I - # Minv = inv(M) - U, S, V = svd(M) threshold = 1e-6 * δ * δ * δ - _S_ = SVector{q_dim,Float64}((s > threshold ? s : 0) for s in S) - Sinv = Diagonal{Float64,SVector{q_dim,Float64}}(_S_) - Minv = V * Sinv * U' + Minv = invreg(M, threshold) # calculate gradient weights Φ for bond_id in each_bond_idx(system, i) @@ -282,10 +301,22 @@ function calc_gradient_weights!(storage::RKCStorage, system::BondSystem, mat::RK ΔXij = get_diff(system.position, i, j) Q = get_monomial_vector(accuracy_order, ΔXij, δ) ωij = kernel(system, bond_id) * bond_active[bond_id] - # temp = ωij * volume[j] temp = ωij / δ * volume[j] MinvQ = Minv * Q Φ = temp * (Q∇ᵀ * MinvQ) + #--- + # Φ1 = 0.0 + # Φ2 = 0.0 + # Φ3 = 0.0 + # for m in 1:q_dim + # Φ1 += temp * Minv[1, m] * Q[m] + # Φ2 += temp * Minv[2, m] * Q[m] + # Φ3 += temp * Minv[3, m] * Q[m] + # end + # Φm = SVector{3,Float64}(Φ1, Φ2, Φ3) + # @assert isapprox(Φ, Φm) + # @show Φ, Φm + #--- update_vector!(gradient_weight, bond_id, Φ) end end @@ -336,8 +367,6 @@ end @inline function get_monomial_vector(::Val{2}, ΔX::AbstractArray, δ::Real) a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ Q = SVector{9,eltype(ΔX)}(a1, a2, a3, a1*a1, a1*a2, a1*a3, a2*a2, a2*a3, a3*a3) - # a1, a2, a3 = ΔX[1], ΔX[2], ΔX[3] - # Q = SVector{9}(a1, a2, a3, a1*a1, a2*a2, a3*a3, a1*a2, a1*a3, a2*a3) return Q end @@ -368,17 +397,23 @@ function get_q_triangle(::Val{N}) where {N} return throw(ArgumentError(msg)) end +# function invert_moment_matrix(M::StaticMatrix{N,N,T}, threshold::Real) where {N,T} +# U, S, V = svd(M) +# Sinvreg = SVector{N,T}((s > threshold ? 1/s : 0) for s in S) +# Sinv = Diagonal{T,SVector{N,T}}(Sinvreg) +# Minv = V * Sinv * U' +# return Minv +# end + function calc_deformation_gradients!(storage::RKCStorage, system::BondSystem, ::RKCMaterial, ::AbstractParameterSetup, t, Δt) (; bonds, volume) = system (; gradient_weight, defgrad, bond_active) = storage for i in each_point_idx(system) - ## RK F = SMatrix{3,3,Float64,9}(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) - # F = MMatrix{3,3,Float64,9}(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) for bond_id in each_bond_idx(system, i) - if bond_active[bond_id] + # if bond_active[bond_id] bond = bonds[bond_id] j = bond.neighbor ΔXij = get_vector_diff(system.position, i, j) @@ -386,35 +421,9 @@ function calc_deformation_gradients!(storage::RKCStorage, system::BondSystem, :: ΔUij = Δxij - ΔXij Φij = get_vector(gradient_weight, bond_id) F += (ΔUij * Φij') * volume[j] - # #-- - # for m ∈ axes(F, 1) - # for n ∈ axes(F, 2) - # F[n, m] += ΔUij[m] * Φij[n] * volume[j] - # end - # end - #-- - end + # end end - # _F = SMatrix{3,3,Float64,9}(F) - # update_tensor!(defgrad, i, _F) update_tensor!(defgrad, i, F) - - ## correspondence - # K = zero(SMatrix{3,3,Float64,9}) - # _F = zero(SMatrix{3,3,Float64,9}) - # for bond_id in each_bond_idx(system, i) - # bond = bonds[bond_id] - # j = bond.neighbor - # ΔXij = get_vector_diff(system.position, i, j) - # Δxij = get_vector_diff(storage.position, i, j) - # ωij = kernel(system, bond_id) #* storage.bond_active[bond_id] - # temp = ωij * volume[j] - # K += temp * (ΔXij * ΔXij') - # _F += temp * (Δxij * ΔXij') - # end - # Kinv = inv(K) - # F = _F * Kinv - # update_tensor!(defgrad, i, F) end return nothing @@ -429,11 +438,11 @@ end function force_density_point!(storage::RKCStorage, system::BondSystem, mat::RKCMaterial, params::RKCPointParameters, t, Δt, i) - (; bonds, volume) = system - (; gradient_weight, defgrad, bond_active, weighted_volume) = storage - (; first_piola_kirchhoff) = storage - Fi = get_tensor(defgrad, i) - too_much_damage!(storage, system, mat, Fi, i) && return nothing + # (; bonds, volume) = system + # (; gradient_weight, defgrad, bond_active, weighted_volume) = storage + # (; first_piola_kirchhoff) = storage + # Fi = get_tensor(defgrad, i) + # too_much_damage!(storage, system, mat, Fi, i) && return nothing # Pi = calc_first_piola_kirchhoff(storage, mat, params, Fi) # Standard RK @@ -445,16 +454,18 @@ function force_density_point!(storage::RKCStorage, system::BondSystem, mat::RKCM # ε = (l - L) / L # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - # # if bond_active[bond_id] + # if bond_active[bond_id] + # Fj = get_tensor(defgrad, j) + # Fb = 0.5 * (Fi + Fj) + # ΔXij = get_coordinates_diff(system, i, j) + # ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) + # Fij = Fb + ΔFij + # Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) # Φij = get_vector(gradient_weight, bond_id) - # # Fj = get_tensor(defgrad, j) - # # Pj = calc_first_piola_kirchhoff(storage, mat, params, Fj) - # # ΔPij = Pj - Pi - # # tij = (ΔPij * Φij) * volume[j] #* bond_active[bond_id] - # tij = (Pi * Φij) / volume[j] #* bond_active[bond_id] + # tij = Pij * Φij # update_add_b_int!(storage, i, tij * volume[j]) # update_add_b_int!(storage, j, -tij * volume[i]) - # # end + # end # end # BA-Stabilized RK @@ -479,66 +490,117 @@ function force_density_point!(storage::RKCStorage, system::BondSystem, mat::RKCM # end # Nodal quadrature peridigm - # Stress integral SI - wi = weighted_volume[i] - SI = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + # (; bonds, volume) = system + # (; bond_active, gradient_weight, defgrad, weighted_volume) = storage + + # Fi = get_tensor(defgrad, i) + # # too_much_damage!(storage, system, mat, Fi, i) && return nothing + + # # Stress integral + # wi = weighted_volume[i] + # ∑P = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + # for bond_id in each_bond_idx(system, i) + # bond = bonds[bond_id] + # j, L = bond.neighbor, bond.length + # ΔXij = get_coordinates_diff(system, i, j) + # Δxij = get_coordinates_diff(storage, i, j) + # l = norm(Δxij) + # ε = (l - L) / L + # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + + # if bond_active[bond_id] + # Fj = get_tensor(defgrad, j) + # Fb = 0.5 * (Fi + Fj) + # ΔXijLL = ΔXij' / (L * L) + # ΔFij = (Δxij - Fb * ΔXij) * ΔXijLL + # Fij = Fb + ΔFij + # Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) + # update_tensor!(storage.first_piola_kirchhoff, bond_id, Pij) + # Tempij = I - ΔXij * ΔXijLL + # # ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) + # wj = weighted_volume[j] + # ϕ = (wi > 0 && wj > 0) ? (0.5 / wi + 0.5 / wj) : 0.0 + # ω̃ij = kernel(system, bond_id) * ϕ + # ∑Pij = ω̃ij * (Pij * Tempij) + # ∑P += ∑Pij + # end + # end + + # for bond_id in each_bond_idx(system, i) + # if bond_active[bond_id] + # bond = bonds[bond_id] + # j, L = bond.neighbor, bond.length + # ΔXij = get_coordinates_diff(system, i, j) + # Pij = get_tensor(storage.first_piola_kirchhoff, bond_id) + # Φij = get_vector(gradient_weight, bond_id) + # # ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) + # wj = weighted_volume[j] + # ϕ = (wi > 0 && wj > 0) ? (0.5 / wi + 0.5 / wj) : 0.0 + # ω̃ij = kernel(system, bond_id) * ϕ + # tij = ω̃ij / (L * L) * (Pij * ΔXij) + ∑P * Φij + # update_add_b_int!(storage, i, tij * volume[j]) + # update_add_b_int!(storage, j, -tij * volume[i]) + # end + # end + # return nothing + + + ## My understanding of the equations + # wi = weighted_volume[i] + # Vi = volume[i] + # ∑ωPV = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + # ∑ωPcorr = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + # for bond_id in each_bond_idx(system, i) + # bond = bonds[bond_id] + # j, L = bond.neighbor, bond.length + # Δxij = get_coordinates_diff(storage, i, j) + # l = norm(Δxij) + # ε = (l - L) / L + # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + + # if bond_active[bond_id] + # Vj = volume[j] + # ΔXij = get_coordinates_diff(system, i, j) + # Fj = get_tensor(defgrad, j) + # Fb = 0.5 * (Fi + Fj) + # ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) + # Fij = Fb + ΔFij + # Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) + # update_tensor!(first_piola_kirchhoff, bond_id, Pij) + + # ωij = kernel(system, bond_id) + # ωPV = ωij * Pij * Vj + # ∑ωPV += ωPV + # ∑ωPcorr += ωPV * (ΔXij * ΔXij') / (L * L) + # # wj = weighted_volume[j] + # # ϕ = volume[j] * ωij * (0.5 / wi + 0.5 / wj) + # # SI += ϕ * (Pij * Tempij) + # end + # end + + ### my newest approach + (; bonds, volume) = system + (; gradient_weight, defgrad, bond_active, weighted_volume) = storage + Fi = get_tensor(defgrad, i) + Pi = calc_first_piola_kirchhoff(storage, mat, params, Fi) + for bond_id in each_bond_idx(system, i) bond = bonds[bond_id] - j, L = bond.neighbor, bond.length - ΔXij = get_coordinates_diff(system, i, j) - Δxij = get_coordinates_diff(storage, i, j) - l = norm(Δxij) - ε = (l - L) / L - stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - + j = bond.neighbor # if bond_active[bond_id] Fj = get_tensor(defgrad, j) - Fb = 0.5 * (Fi + Fj) - ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) - Fij = Fb + ΔFij - Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) - update_tensor!(first_piola_kirchhoff, bond_id, Pij) - Tempij = (I - ΔXij * ΔXij') / (L * L) - ωij = kernel(system, bond_id) * bond_active[bond_id] - wj = weighted_volume[j] - ϕ = volume[j] * ωij * (0.5 / wi + 0.5 / wj) - SI += ϕ * (Pij * Tempij) - # end - end - # @show SI - - for bond_id in each_bond_idx(system, i) - if bond_active[bond_id] - bond = bonds[bond_id] - j, L = bond.neighbor, bond.length - ΔXij = get_coordinates_diff(system, i, j) - Pij = get_tensor(first_piola_kirchhoff, bond_id) + Pj = calc_first_piola_kirchhoff(storage, mat, params, Fj) Φij = get_vector(gradient_weight, bond_id) - ωij = kernel(system, bond_id) * bond_active[bond_id] - tij = SI * Φij + ωij / (wi * L * L) * (Pij * ΔXij) + tij = (Pj - Pi) * Φij + # tij = Pi * Φij update_add_b_int!(storage, i, tij * volume[j]) update_add_b_int!(storage, j, -tij * volume[i]) - end + # end end return nothing end -# function calc_deformation_gradient(storage::RKCStorage, system::BondSystem, -# mat::RKCMaterial, params::RKCPointParameters, i) -# (; bonds, volume) = system -# (; displacement, gradient_weight) = storage -# F = zero(SMatrix{3,3,Float64,9}) -# for bond_id in each_bond_idx(system, i) -# bond = bonds[bond_id] -# j = bond.neighbor -# Δuij = get_vector_diff(displacement, i, j) -# Φij = get_vector(gradient_weight, bond_id) -# F += (Δuij * Φij') * volume[j] -# end -# return F -# end - function calc_first_piola_kirchhoff(storage::RKCStorage, mat::RKCMaterial, params::RKCPointParameters, F) P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) diff --git a/src/physics/stress.jl b/src/physics/stress.jl index 54a2e29a..504e7dd7 100644 --- a/src/physics/stress.jl +++ b/src/physics/stress.jl @@ -23,6 +23,12 @@ end function init_stress_rotation!(storage::AbstractStorage, F, Ḟ, Δt, i) # inverse of the deformation gradient F⁻¹ = inv(F) + if containsnan(F⁻¹) + OTensor = zero(SMatrix{3,3,Float64,9}) + update_tensor!(storage.rotation, i, OTensor) + update_tensor!(storage.left_stretch, i, OTensor) + return OTensor + end # Eulerian velocity gradient [FT87, eq. (3)] L = Ḟ * F⁻¹ @@ -79,10 +85,14 @@ function init_stress_rotation!(storage::AbstractStorage, F, Ḟ, Δt, i) # compute step 5 of [FT87] Vₙ₊₁ = V + Δt * V̇ + # compute the unrotated rate of deformation + Dᵣ = Rₙ₊₁' * D * Rₙ₊₁ + # update rotation and left stretch update_tensor!(storage.rotation, i, Rₙ₊₁) update_tensor!(storage.left_stretch, i, Vₙ₊₁) - return nothing + # update_tensor!(storage.unrot_rate_of_deformation, i, Dᵣ) + return Dᵣ end function rotate_stress(storage::AbstractStorage, σ, i) diff --git a/src/time_solvers/velocity_verlet.jl b/src/time_solvers/velocity_verlet.jl index 471a4f8c..fa7cc870 100644 --- a/src/time_solvers/velocity_verlet.jl +++ b/src/time_solvers/velocity_verlet.jl @@ -207,6 +207,7 @@ function verlet_timestep!(dh::AbstractThreadsMultibodyDataHandler, update_vel_half!(chunk, Δt½) apply_boundary_conditions!(chunk, t) update_disp_and_pos!(chunk, Δt) + calc_damage!(chunk) end end calc_force_density!(dh, t, Δt) @@ -214,11 +215,11 @@ function verlet_timestep!(dh::AbstractThreadsMultibodyDataHandler, calc_contact_force_densities!(dh) for body_idx in each_body_idx(dh) body_dh = get_body_dh(dh, body_idx) - body_name = get_body_name(dh, body_idx) + # body_name = get_body_name(dh, body_idx) @threads :static for chunk_id in eachindex(body_dh.chunks) exchange_halo_to_loc!(body_dh, chunk_id) chunk = body_dh.chunks[chunk_id] - calc_damage!(chunk) + # calc_damage!(chunk) update_acc_and_vel!(chunk, Δt½) export_results(body_dh, options, chunk_id, n, t) end diff --git a/test/integration/b_int_rk_correspondence.jl b/test/integration/b_int_rk_correspondence.jl index bcc7b16c..51173b28 100644 --- a/test/integration/b_int_rk_correspondence.jl +++ b/test/integration/b_int_rk_correspondence.jl @@ -1,4 +1,4 @@ -@testitem "Internal force density correspondence" begin +@testitem "Internal force density rk-correspondence" begin # using Peridynamics, Test ref_position = [0.0 1.0 0.0 0.0 0.0 1.0 @@ -14,7 +14,7 @@ dh = Peridynamics.threads_data_handler(body, VelocityVerlet(steps=1), 2) chunk1 = dh.chunks[1] - (; mat, storage, system, paramsetup) = chunk + (; mat, storage, system, paramsetup) = chunk1 params = paramsetup (; position) = storage position[1, 1] = -0.0015 @@ -32,7 +32,7 @@ # # Point 2 with v_z = 1 m/s with Δt = 0.0015 s # position[1, 2] = 1.0015 - Peridynamics.calc_force_density!(dh, 0, 0) + # Peridynamics.calc_force_density!(dh, 0, 0) # @test defgrad ≈ 0 diff --git a/test/physics/test_rk_correspondence.jl b/test/physics/test_rk_correspondence.jl index 7bbdc2f4..a71988fb 100644 --- a/test/physics/test_rk_correspondence.jl +++ b/test/physics/test_rk_correspondence.jl @@ -1,5 +1,7 @@ # Write a unit test for the qmatrix calculation of the RKMaterial @testitem "Monomial vector Q" begin + using Peridynamics.StaticArrays + # CPP code as reference: # // calculate dimension of Q vector # Qdim = 0; @@ -66,6 +68,47 @@ return Q end + # perilab function as a test: + function calculate_Q( + accuracy_order::Int64, + dof::Int64, + bond_geometry::Vector{Float64}, + horizon::Union{Int64,Float64}, + Q::Vector{Float64}, + ) + counter = 0 + p = @MVector zeros(Int64, dof) + for this_order = 1:accuracy_order + for p[1] = this_order:-1:0 + if dof == 3 + for p[2] = this_order-p[1]:-1:0 + p[3] = this_order - p[1] - p[2] + # Calculate the product for Q[counter] + counter += 1 + Q[counter] = prod_Q(bond_geometry, horizon, p, Q[counter]) + end + else + p[2] = this_order - p[1] + counter += 1 + Q[counter] = prod_Q(bond_geometry, horizon, p, Q[counter]) + end + end + end + return Q + end + + function prod_Q(bond_geometry, horizon, p, Q) + Q = 1 + @inbounds @fastmath for m ∈ axes(p, 1) + @views @inbounds @fastmath for pc = 1:p[m] + Q *= bond_geometry[m] / horizon + end + end + return Q + end + + + # test cases for q_vector undeformed_bond_and_horizon = [ ([0.0, 0.0, 0.0], 1.0), @@ -76,8 +119,11 @@ for m in (1,2,3) for (ΔX, δ) in undeformed_bond_and_horizon Q_peridigm = q_vector(ΔX, δ, m) + Q_perilab = calculate_Q(m, 3, ΔX, δ, zeros(size(Q_peridigm))) Q_peridynamics = Peridynamics.get_monomial_vector(Val(m), ΔX, δ) + @test Q_peridigm ≈ Q_perilab @test Q_peridigm ≈ Q_peridynamics + @test Q_perilab ≈ Q_peridynamics end end end @@ -131,50 +177,50 @@ end chunk = dh.chunks[1] (; mat, storage, system, paramsetup) = chunk - # @test system.bonds == [ - # Bond(2, 1.0, false), # point 1 - # Bond(3, 1.0, false), - # Bond(1, 1.0, false), # point 2 - # Bond(3, √2, false), - # Bond(1, 1.0, false), # point 3 - # Bond(2, √2, false), - # ] + @test system.bonds == [ + Bond(2, 1.0, false), # point 1 + Bond(3, 1.0, false), + Bond(1, 1.0, false), # point 2 + Bond(3, √2, false), + Bond(1, 1.0, false), # point 3 + Bond(2, √2, false), + ] - # @test storage.gradient_weight == zeros(3, 6) + @test storage.gradient_weight == zeros(3, 6) Peridynamics.calc_gradient_weights!(storage, system, mat, paramsetup) # my old version with temp = ωij * volume[j] # Φ = storage.gradient_weight - # @test Φ[:,1] ≈ [0.0010437031893788147, 0.0, 0.0] - # @test Φ[:,2] ≈ [0.0, 0.0010437031893788147, 0.0] - # @test Φ[:,3] ≈ [-0.0010489745520712516, 5.271362692436961e-6, 0.0] - # @test Φ[:,4] ≈ [-5.332802053265902e-6, 6.143936082888219e-8, 0.0] - # @test Φ[:,5] ≈ [5.27136269243702e-6, -0.0010489745520712514, 0.0] - # @test Φ[:,6] ≈ [6.143936082888247e-8, -5.332802053265901e-6, 0.0] + # @test Φ[:,1] ≈ [0.5000000000000001, 0.0, 0.0] + # @test Φ[:,2] ≈ [0.0, 0.5000000000000001, 0.0] + # @test Φ[:,3] ≈ [-0.5000000000000004, -0.3333333333333337, 0.0] + # @test Φ[:,4] ≈ [-3.469446951953614e-18, 0.33333333333333365, 0.0] + # @test Φ[:,5] ≈ [-0.33333333333333054, -0.5000000000000009, 0.0] + # @test Φ[:,6] ≈ [0.3333333333333338, 7.728193085476676e-16, 0.0] # PeriLab version temp = ωij / δ - Φ = storage.gradient_weight - @test Φ[:,1] ≈ [0.0006958021262525432, 0.0, 0.0] - @test Φ[:,2] ≈ [0.0, 0.0006958021262525432, 0.0] - @test Φ[:,3] ≈ [-0.0006993163680475011, 3.5142417949579743e-6, 0.0] - @test Φ[:,4] ≈ [-3.5552013688439347e-6, 4.095957388592146e-8, 0.0] - @test Φ[:,5] ≈ [3.514241794958013e-6, -0.0006993163680475009, 0.0] - @test Φ[:,6] ≈ [4.095957388592165e-8, -3.555201368843933e-6, 0.0] + # Φ = storage.gradient_weight + # @test Φ[:,1] ≈ [0.0006958021262525432, 0.0, 0.0] + # @test Φ[:,2] ≈ [0.0, 0.0006958021262525432, 0.0] + # @test Φ[:,3] ≈ [-0.0006993163680475011, 3.5142417949579743e-6, 0.0] + # @test Φ[:,4] ≈ [-3.5552013688439347e-6, 4.095957388592146e-8, 0.0] + # @test Φ[:,5] ≈ [3.514241794958013e-6, -0.0006993163680475009, 0.0] + # @test Φ[:,6] ≈ [4.095957388592165e-8, -3.555201368843933e-6, 0.0] #= using BenchmarkTools @btime Peridynamics.calc_gradient_weights!($storage, $system, $mat, $paramsetup) =# - storage.position[:, 1] += [-0.001, -0.001, -0.001] - storage.position[:, 2] += [0.001, 0.0, 0.0] - storage.position[:, 3] += [0.0, 0.001, 0.0] + # storage.position[:, 1] += [-0.001, -0.001, -0.001] + # storage.position[:, 2] += [0.001, 0.0, 0.0] + # storage.position[:, 3] += [0.0, 0.001, 0.0] - F = storage.defgrad - @test F == zeros(9, 3) + # F = storage.defgrad + # @test F == zeros(9, 3) - Peridynamics.calc_deformation_gradients!(storage, system, mat, paramsetup, 0.0, 0.0) + # Peridynamics.calc_deformation_gradients!(storage, system, mat, paramsetup, 0.0, 0.0) # my old version # @test F[:, 1] ≈ [1.0000013916042525, 6.958021262525431e-7, 0.0, @@ -188,19 +234,119 @@ end # -3.514241794958013e-9, 6.993163680475009e-7, 1.0] # PeriLab version - @test F[:, 1] ≈ [1.0000013916042525, 6.958021262525431e-7, 6.958021262525431e-7, - 6.958021262525431e-7, 1.0000013916042525, 6.958021262525431e-7, - 0.0, 0.0, 1.0] - @test F[:, 2] ≈ [1.0000014021879375, 6.957611666786575e-7, 6.993163680475011e-7, - -7.069443163801091e-9, 0.9999999965267178, -3.514241794957974e-9, - 0.0, 0.0, 1.0] - @test F[:, 3] ≈ [0.9999999965267178, -7.069443163801169e-9, -3.514241794958013e-9, - 6.957611666786573e-7, 1.0000014021879375, 6.993163680475009e-7, - 0.0, 0.0, 1.0] + # @test F[:, 1] ≈ [1.0000013916042525, 6.958021262525431e-7, 6.958021262525431e-7, + # 6.958021262525431e-7, 1.0000013916042525, 6.958021262525431e-7, + # 0.0, 0.0, 1.0] + # @test F[:, 2] ≈ [1.0000014021879375, 6.957611666786575e-7, 6.993163680475011e-7, + # -7.069443163801091e-9, 0.9999999965267178, -3.514241794957974e-9, + # 0.0, 0.0, 1.0] + # @test F[:, 3] ≈ [0.9999999965267178, -7.069443163801169e-9, -3.514241794958013e-9, + # 6.957611666786573e-7, 1.0000014021879375, 6.993163680475009e-7, + # 0.0, 0.0, 1.0] #= using BenchmarkTools @btime Peridynamics.calc_deformation_gradients!($storage, $system, $mat, $paramsetup, $0.0, $0.0) =# + + + #--- My own testing + + # ξ12 = 1/1.5 + # ω12 = ω13 = 4/3 - 4 * ξ12 + 4 * ξ12^2 - 4/3 * ξ12^3 + # ΔX12 = SVector{3}([1.0, 0.0, 0.0]) + # ΔX13 = SVector{3}([0.0, 1.0, 0.0]) + # Q12 = SVector{9}([1.0, 0.0, 0.0, 1, 0.0, 0.0, 0.0, 0.0, 0.0]) + # # Q12 = copy(ΔX12) + # Q13 = SVector{9}([0.0, 1.0, 0.0, 0.0, 1, 0.0, 0.0, 0.0, 0.0]) + # # Q13 = copy(ΔX13) + # V1 = V2 = V3 = 1.0 + # M1 = ω12 * (Q12 * Q12') * V2 + ω13 * (Q13 * Q13') * V3 + + # threshold = 1e-6 * δ^3 + # M1inv = Peridynamics.invert_moment_matrix(M1, threshold) + + # Q∇ᵀ = SMatrix{3,9,Int,27}(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + # 0, 0, 0, 0, 0, 0) + # # Q∇ᵀ = SMatrix{3,3,Int,9}(1, 0, 0, 0, 1, 0, 0, 0, 1) + + + # Φ12 = ω12 * Q∇ᵀ * M1inv * Q12 + # Φ13 = ω13 * Q∇ᵀ * M1inv * Q13 + # @test Φ[:,1] ≈ Φ12 + # @test Φ[:,2] ≈ Φ13 + +end + +@testitem "Damage changed" begin + # setup + ref_position = [0.0 1.0 0.0 + 0.0 0.0 1.0 + 0.0 0.0 0.0] + volume = fill(1.0, 3) + δ = 1.5 + mat = RKCMaterial() + body = Body(mat, ref_position, volume) + material!(body, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) + failure_permit!(body, false) + dh = Peridynamics.threads_data_handler(body, VelocityVerlet(steps=1), 1) + chunk = dh.chunks[1] + (; mat, storage, system, paramsetup) = chunk + + # initial value should be `true` + @test storage.damage_changed == [true, true, true] + + # after first damage calculation this should be `false` + Peridynamics.calc_damage!(chunk) + @test storage.damage_changed == [false, false, false] + + # damage a bond: + @test storage.bond_active[1] == true + storage.bond_active[1] = false + @test storage.bond_active[1] == false + @test storage.n_active_bonds[1] == 2 + storage.n_active_bonds[1] -= 1 + @test storage.n_active_bonds[1] == 1 + + Peridynamics.calc_damage!(chunk) + @test storage.damage_changed == [true, false, false] +end + +@testitem "accuracy_order = 1" begin + # setup + ref_position = [0.0 1.0 0.0 + 0.0 0.0 1.0 + 0.0 0.0 0.0] + volume = fill(1.0, 3) + δ = 1.5 + mat_rk = RKCMaterial(accuracy_order=1) + body_kr = Body(mat_rk, ref_position, volume) + material!(body_kr, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) + failure_permit!(body_kr, false) + dh_rk = Peridynamics.threads_data_handler(body_kr, VelocityVerlet(steps=1), 1) + chunk_rk = dh_rk.chunks[1] + body_c = Body(CMaterial(), ref_position, volume) + material!(body_c, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) + failure_permit!(body_c, false) + dh_c = Peridynamics.threads_data_handler(body_c, VelocityVerlet(steps=1), 1) + chunk_c = dh_c.chunks[1] + + (; mat, storage, system, paramsetup) = chunk_rk + Peridynamics.calc_gradient_weights!(storage, system, mat, paramsetup) + +end + + +##---- + +Φ = rand(3) +ΔU = rand(3) +F1 = ΔU * Φ' +F2 = zeros(3,3) +for i in 1:3 + F2[i,1] = ΔU[i] * Φ[1] + F2[i,2] = ΔU[i] * Φ[2] + F2[i,3] = ΔU[i] * Φ[3] end +F1 ≈ F2 From 9d24663b9ad7a341c17fd3d4f8c227a1523344f8 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Fri, 7 Feb 2025 09:49:54 +0100 Subject: [PATCH 36/40] Cleanup + docs --- Project.toml | 2 - src/Peridynamics.jl | 9 +- src/discretization/bond_associated_system.jl | 28 - src/discretization/zem_stabilization.jl | 9 +- src/physics/ba_correspondence.jl | 41 +- src/physics/constitutive_models.jl | 15 +- src/physics/correspondence.jl | 37 +- src/physics/correspondence_rotated.jl | 235 ------ src/physics/ns_correspondence.jl | 590 ------------- src/physics/ns_correspondence_rotated.jl | 834 ------------------- src/physics/rk_correspondence.jl | 642 -------------- src/time_solvers/velocity_verlet.jl | 4 +- test/integration/b_int_correspondence.jl | 4 +- test/integration/b_int_rk_correspondence.jl | 44 - test/integration/mpi_threads_comparison.jl | 2 +- test/integration/symmetry_correspondence.jl | 6 +- test/physics/test_rk_correspondence.jl | 352 -------- 17 files changed, 51 insertions(+), 2803 deletions(-) delete mode 100644 src/physics/correspondence_rotated.jl delete mode 100644 src/physics/ns_correspondence.jl delete mode 100644 src/physics/ns_correspondence_rotated.jl delete mode 100644 src/physics/rk_correspondence.jl delete mode 100644 test/integration/b_int_rk_correspondence.jl delete mode 100644 test/physics/test_rk_correspondence.jl diff --git a/Project.toml b/Project.toml index d2ec45b9..eaeffe90 100644 --- a/Project.toml +++ b/Project.toml @@ -8,7 +8,6 @@ AbaqusReader = "bc6b9049-e460-56d6-94b4-a597b2c0390d" Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" -Infiltrator = "5903a43b-9cc3-4c30-8d17-598619ec4e9b" LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433" LightXML = "9c8b4983-aa76-5018-a973-4c85ecc9e179" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" @@ -27,7 +26,6 @@ AbaqusReader = "0.2" Base64 = "1.8" CodecZlib = "0.7" Dates = "1.8" -Infiltrator = "1.8.3" LibGit2 = "1.8" LightXML = "0.9" LinearAlgebra = "1.8" diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index dd07b827..0f43493f 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -6,13 +6,10 @@ using Base.Threads, Printf, LinearAlgebra, StaticArrays, PointNeighbors, Progres using ThreadPinning end -using Infiltrator - import LibGit2, Dates # Material models -export BBMaterial, OSBMaterial, CMaterial, CRMaterial, BACMaterial, RKCMaterial, - NSCMaterial, NSCRMaterial, CKIMaterial +export BBMaterial, OSBMaterial, CMaterial, BACMaterial, CKIMaterial # CMaterial related types export NeoHookeNonlinear, SaintVenantKirchhoff, ZEMSilling @@ -131,11 +128,7 @@ include("physics/continuum_kinematics_inspired.jl") include("physics/ordinary_state_based.jl") include("physics/constitutive_models.jl") include("physics/correspondence.jl") -include("physics/correspondence_rotated.jl") -include("physics/ns_correspondence.jl") -include("physics/ns_correspondence_rotated.jl") include("physics/ba_correspondence.jl") -include("physics/rk_correspondence.jl") include("VtkReader/VtkReader.jl") using .VtkReader diff --git a/src/discretization/bond_associated_system.jl b/src/discretization/bond_associated_system.jl index 8ce2dcd6..8a3d0a6f 100644 --- a/src/discretization/bond_associated_system.jl +++ b/src/discretization/bond_associated_system.jl @@ -105,34 +105,6 @@ function calc_hood_volumes!(chunk::AbstractBodyChunk{<:BondAssociatedSystem}) return nothing end -# function calc_hood_volumes!(chunk::AbstractBodyChunk{<:BondAssociatedSystem}) -# (; mat, paramsetup, system, storage) = chunk -# (; volume, bonds, hood_volume, ba_hood_volume) = system -# (; bond_active) = storage - -# for i in each_point_idx(chunk) -# _hood_volume = 0.0 # volume[i] -# params = get_params(paramsetup, i) -# for bond_idx in each_bond_idx(system, i) -# bond = bonds[bond_idx] -# j, L = bond.neighbor, bond.length -# ωij = influence_function(mat, params, L) * bond_active[bond_idx] -# _hood_volume += ωij * volume[j] -# _ba_hood_volume = 0.0 -# for i_bond_idx in each_intersecting_bond_idx(system, i, bond_idx) -# i_bond = bonds[i_bond_idx] -# jj, LL = i_bond.neighbor, i_bond.length -# ωijj = influence_function(mat, params, LL) * bond_active[i_bond_idx] -# _ba_hood_volume += ωijj * volume[jj] -# end -# ba_hood_volume[bond_idx] = _ba_hood_volume -# end -# hood_volume[i] = _hood_volume -# end - -# return nothing -# end - @inline get_hood_volume(chunk::AbstractBodyChunk) = chunk.system.hood_volume function initialize!(dh::AbstractThreadsBodyDataHandler{<:BondAssociatedSystem}, diff --git a/src/discretization/zem_stabilization.jl b/src/discretization/zem_stabilization.jl index b0c26a93..7be22cd7 100644 --- a/src/discretization/zem_stabilization.jl +++ b/src/discretization/zem_stabilization.jl @@ -4,9 +4,14 @@ function get_correction(mat::AbstractBondSystemMaterial{<:AbstractZEMStabilizati end """ - ZEMSilling(; Cs=0.0) + ZEMSilling(; Cs) -TODO +Zero-energy mode stabilization algorithm of Silling (2017). This is necessary for the +correspondence formulation to stabilize the zero-energy modes. +See also [`CMaterial`](@ref) on how to use this stabilization algorithm. + +# Keywords +- `Cs::Real`: Stabilization factor. (default: `100.0`) """ struct ZEMSilling <: AbstractZEMStabilization Cs::Float64 diff --git a/src/physics/ba_correspondence.jl b/src/physics/ba_correspondence.jl index 113afc38..098f9491 100644 --- a/src/physics/ba_correspondence.jl +++ b/src/physics/ba_correspondence.jl @@ -1,47 +1,46 @@ """ - CMaterial(; maxdmg, zem) + BACMaterial(; kernel, model, maxdmg) -A material type used to assign the material of a [`Body`](@ref) with the local continuum -consistent (correspondence) formulation of non-ordinary state-based peridynamics. +A material type used to assign the material of a [`Body`](@ref) with the bond-associated +correspondence formulation of Chen and Spencer (2019). # Keywords +- `kernel::Function`: Kernel function used for weighting the interactions between points. + (default: `linear_kernel`) +- `model::AbstractConstitutiveModel`: Constitutive model defining the material behavior. + (default: `LinearElastic()`) - `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is exceeded, all bonds of that point are broken because the deformation gradient would then possibly contain `NaN` values. - (default: `0.95`) -- `zem::AbstractZEMStabilization`: zero-energy mode stabilization. The - stabilization algorithm of Silling (2017) is used as default. - (default: `ZEMSilling()`) - -!!! note "Stability of fracture simulations" - This formulation is known to be not suitable for fracture simultations without - stabilization of the zero-energy modes. Therefore be careful when doing fracture - simulations and try out different parameters for `maxdmg` and `zem`. + (default: `0.85`) # Examples ```julia-repl -julia> mat = CMaterial() +julia> mat = BACMaterial() CMaterial(maxdmg=0.95, zem_fac=ZEMSilling()) ``` --- ```julia -CMaterial +BACMaterial{CM,K} ``` -Material type for the local continuum consistent (correspondence) formulation of -non-ordinary state-based peridynamics. +Material type for the bond-associated correspondence formulation of Chen and Spencer (2019). + +# Type Parameters +- `CM`: A constitutive model type. See the constructor docs for more informations. +- `K`: A kernel function type. See the constructor docs for more informations. # Fields +- `kernel::Function`: Kernel function used for weighting the interactions between points. +- `model::AbstractConstitutiveModel`: Constitutive model defining the material behavior. - `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. See the constructor docs for more informations. -- `zem_fac::Float64`: Correction factor used for zero-energy mode stabilization. See the - constructor docs for more informations. # Allowed material parameters -When using [`material!`](@ref) on a [`Body`](@ref) with `CMaterial`, then the following +When using [`material!`](@ref) on a [`Body`](@ref) with `BACMaterial`, then the following parameters are allowed: - `horizon::Float64`: Radius of point interactions - `rho::Float64`: Density @@ -52,7 +51,7 @@ parameters are allowed: # Allowed export fields When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with -`CMaterial`, the following fields are allowed: +`BACMaterial`, the following fields are allowed: - `position::Matrix{Float64}`: Position of each point - `displacement::Matrix{Float64}`: Displacement of each point - `velocity::Matrix{Float64}`: Velocity of each point @@ -79,7 +78,7 @@ function Base.show(io::IO, @nospecialize(mat::BACMaterial)) end function BACMaterial(; kernel::Function=linear_kernel, - model::AbstractConstitutiveModel=NeoHookeNonlinear(), + model::AbstractConstitutiveModel=LinearElastic(), maxdmg::Real=0.85) return BACMaterial(kernel, model, maxdmg) end diff --git a/src/physics/constitutive_models.jl b/src/physics/constitutive_models.jl index 648e0037..dc65c453 100644 --- a/src/physics/constitutive_models.jl +++ b/src/physics/constitutive_models.jl @@ -2,9 +2,6 @@ struct LinearElastic <: AbstractConstitutiveModel end function first_piola_kirchhoff(::LinearElastic, storage::AbstractStorage, params::AbstractPointParameters, F::SMatrix{3,3,T,9}) where T - # J = det(F) - # J < eps() && return zero(SMatrix{3,3,T,9}) - # isnan(J) && return zero(SMatrix{3,3,T,9}) E = 0.5 .* (F' * F - I) 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]) Cvoigt = get_hooke_matrix(params.nu, params.λ, params.μ) @@ -22,12 +19,11 @@ function get_hooke_matrix(nu, λ, μ) return CVoigt end -struct NeoHookeViera <: AbstractConstitutiveModel end +struct NeoHooke <: AbstractConstitutiveModel end -function first_piola_kirchhoff(::NeoHookeViera, storage::AbstractStorage, +function first_piola_kirchhoff(::NeoHooke, storage::AbstractStorage, params::AbstractPointParameters, F::SMatrix{3,3,T,9}) where T J = det(F) - # J < eps() && return zero(SMatrix{3,3,T,9}) Cinv = inv(F' * F) S = params.μ * (I - Cinv) + params.λ * log(J) * Cinv P = F * S @@ -39,8 +35,8 @@ struct NeoHookeNonlinear <: AbstractConstitutiveModel end function first_piola_kirchhoff(::NeoHookeNonlinear, storage::AbstractStorage, params::AbstractPointParameters, F::SMatrix{3,3,T,9}) where T J = det(F) - # J < eps() && return zero(SMatrix{3,3,T,9}) - # isnan(J) && return zero(SMatrix{3,3,T,9}) + J < eps() && return zero(SMatrix{3,3,T,9}) + isnan(J) && return zero(SMatrix{3,3,T,9}) C = F' * F Cinv = inv(C) S = params.G .* (I - 1 / 3 .* tr(C) .* Cinv) .* J^(-2 / 3) .+ @@ -53,9 +49,6 @@ struct SaintVenantKirchhoff <: AbstractConstitutiveModel end function first_piola_kirchhoff(::SaintVenantKirchhoff, storage::AbstractStorage, params::AbstractPointParameters, F::SMatrix{3,3,T,9}) where T - # J = det(F) - # J < eps() && return zero(SMatrix{3,3,T,9}) - # isnan(J) && return zero(SMatrix{3,3,T,9}) E = 0.5 .* (F' * F - I) S = params.λ * tr(E) * I + 2 * params.μ * E P = F * S diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index 68d4d338..4f513b04 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -8,7 +8,7 @@ consistent (correspondence) formulation of non-ordinary state-based peridynamics - `kernel::Function`: Kernel function used for weighting the interactions between points. (default: `linear_kernel`) - `model::AbstractConstitutiveModel`: Constitutive model defining the material behavior. - (default: `NeoHookeNonlinear()`) + (default: `LinearElastic()`) - `zem::AbstractZEMStabilization`: Zero-energy mode stabilization. The stabilization algorithm of Silling (2017) is used as default. (default: `ZEMSilling()`) @@ -32,12 +32,18 @@ CMaterial(maxdmg=0.85, zem=ZEMSilling()) --- ```julia -CMaterial +CMaterial{CM,ZEM,K} ``` Material type for the local continuum consistent (correspondence) formulation of non-ordinary state-based peridynamics. +# Type Parameters +- `CM`: A constitutive model type. See the constructor docs for more informations. +- `ZEM`: A zero-energy mode stabilization type. See the constructor docs for more + informations. +- `K`: A kernel function type. See the constructor docs for more informations. + # Fields - `kernel::Function`: Kernel function used for weighting the interactions between points. See the constructor docs for more informations. @@ -88,7 +94,7 @@ function Base.show(io::IO, @nospecialize(mat::CMaterial)) end function CMaterial(; kernel::Function=linear_kernel, - model::AbstractConstitutiveModel=NeoHookeNonlinear(), + model::AbstractConstitutiveModel=LinearElastic(), zem::AbstractZEMStabilization=ZEMSilling(), maxdmg::Real=0.85) return CMaterial(kernel, model, zem, maxdmg) end @@ -158,7 +164,6 @@ end function force_density_point!(storage::AbstractStorage, system::AbstractSystem, mat::AbstractCorrespondenceMaterial, params::AbstractPointParameters, t, Δt, i) - calc_failure_point!(storage, system, mat, params, i) defgrad_res = calc_deformation_gradient(storage, system, mat, params, i) too_much_damage!(storage, system, mat, defgrad_res, i) && return nothing PKinv = calc_first_piola_kirchhoff!(storage, mat, params, defgrad_res, Δt, i) @@ -167,18 +172,6 @@ function force_density_point!(storage::AbstractStorage, system::AbstractSystem, return nothing end -function calc_failure_point!(storage, system, mat, params, i) - for bond_id in each_bond_idx(system, i) - bond = system.bonds[bond_id] - j, L = bond.neighbor, bond.length - Δxij = get_coordinates_diff(storage, i, j) - l = norm(Δxij) - ε = (l - L) / L - stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - end - return nothing -end - function calc_deformation_gradient(storage::CStorage, system::BondSystem, ::CMaterial, ::CPointParameters, i) (; bonds, volume) = system @@ -226,9 +219,9 @@ function c_force_density!(storage::AbstractStorage, system::AbstractSystem, j, L = bond.neighbor, bond.length ΔXij = get_coordinates_diff(system, i, j) Δxij = get_coordinates_diff(storage, i, j) - # l = norm(Δxij) - # ε = (l - L) / L - # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) + l = norm(Δxij) + ε = (l - L) / L + stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) # stabilization ωij = kernel(system, bond_id) * bond_active[bond_id] @@ -245,13 +238,7 @@ end function too_much_damage!(storage::AbstractStorage, system::AbstractSystem, mat::AbstractCorrespondenceMaterial, defgrad_res, i) (; F) = defgrad_res - # @infiltrate storage.n_active_bonds[i] ≤ 3 # if storage.n_active_bonds[i] ≤ 3 || storage.damage[i] > mat.maxdmg || containsnan(F) - # # kill all bonds of this point - # storage.bond_active[each_bond_idx(system, i)] .= false - # storage.n_active_bonds[i] = 0 - # return true - # end if storage.damage[i] > mat.maxdmg || containsnan(F) # kill all bonds of this point storage.bond_active[each_bond_idx(system, i)] .= false diff --git a/src/physics/correspondence_rotated.jl b/src/physics/correspondence_rotated.jl deleted file mode 100644 index ba8deff3..00000000 --- a/src/physics/correspondence_rotated.jl +++ /dev/null @@ -1,235 +0,0 @@ -""" - CRMaterial(; kernel, model, zem, maxdmg) - -A material type used to assign the material of a [`Body`](@ref) with the local continuum -consistent (correspondence) formulation of non-ordinary state-based peridynamics. - -# Keywords -- `kernel::Function`: Kernel function used for weighting the interactions between points. - (default: `linear_kernel`) -- `model::AbstractConstitutiveModel`: Constitutive model defining the material behavior. - (default: `NeoHookeNonlinear()`) -- `zem::AbstractZEMStabilization`: Zero-energy mode stabilization. The - stabilization algorithm of Silling (2017) is used as default. - (default: `ZEMSilling()`) -- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is - exceeded, all bonds of that point are broken because the deformation gradient would then - possibly contain `NaN` values. - (default: `0.85`) - -!!! note "Stability of fracture simulations" - This formulation is known to be not suitable for fracture simulations without - stabilization of the zero-energy modes. Therefore be careful when doing fracture - simulations and try out different parameters for `maxdmg` and `zem`. - -# Examples - -```julia-repl -julia> mat = CRMaterial() -CRMaterial(maxdmg=0.85, zem=ZEMSilling()) -``` - ---- - -```julia -CRMaterial -``` - -Material type for the local continuum consistent (correspondence) formulation of -non-ordinary state-based peridynamics. - -# Fields -- `kernel::Function`: Kernel function used for weighting the interactions between points. - See the constructor docs for more informations. -- `model::AbstractConstitutiveModel`: Constitutive model defining the material behavior. See - the constructor docs for more informations. -- `zem::AbstractZEMStabilization`: Zero-energy mode stabilization. See the constructor docs - for more informations. -- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. See the - constructor docs for more informations. - -# Allowed material parameters -When using [`material!`](@ref) on a [`Body`](@ref) with `CMaterial`, then the following -parameters are allowed: -- `horizon::Float64`: Radius of point interactions -- `rho::Float64`: Density -- `E::Float64`: Young's modulus -- `nu::Float64`: Poisson's ratio -- `Gc::Float64`: Critical energy release rate -- `epsilon_c::Float64`: Critical strain - -# Allowed export fields -When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with -`CMaterial`, the following fields are allowed: -- `position::Matrix{Float64}`: Position of each point -- `displacement::Matrix{Float64}`: Displacement of each point -- `velocity::Matrix{Float64}`: Velocity of each point -- `velocity_half::Matrix{Float64}`: Velocity parameter for Verlet time solver -- `acceleration::Matrix{Float64}`: Acceleration of each point -- `b_int::Matrix{Float64}`: Internal force density of each point -- `b_ext::Matrix{Float64}`: External force density of each point -- `damage::Vector{Float64}`: Damage of each point -- `n_active_bonds::Vector{Int}`: Number of intact bonds of each point -""" -struct CRMaterial{CM,ZEM,K} <: AbstractCorrespondenceMaterial{CM,ZEM} - kernel::K - constitutive_model::CM - zem_stabilization::ZEM - maxdmg::Float64 - function CRMaterial(kernel::K, cm::CM, zem::ZEM, maxdmg::Real) where {CM,ZEM,K} - return new{CM,ZEM,K}(kernel, cm, zem, maxdmg) - end -end - -function Base.show(io::IO, @nospecialize(mat::CRMaterial)) - print(io, typeof(mat)) - print(io, msg_fields_in_brackets(mat, (:maxdmg,))) - return nothing -end - -function CRMaterial(; kernel::Function=linear_kernel, - model::AbstractConstitutiveModel=NeoHookeNonlinear(), - zem::AbstractZEMStabilization=ZEMSilling(), maxdmg::Real=0.85) - return CRMaterial(kernel, model, zem, maxdmg) -end - -# TODO: remove the function `material_type` from `@params` macro, then point parameters can -# be reused by other material types -struct CRPointParameters <: AbstractPointParameters - δ::Float64 - rho::Float64 - E::Float64 - nu::Float64 - G::Float64 - K::Float64 - λ::Float64 - μ::Float64 - Gc::Float64 - εc::Float64 - bc::Float64 -end - -function CRPointParameters(mat::CRMaterial, p::Dict{Symbol,Any}) - (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) - (; Gc, εc) = get_frac_params(p, δ, K) - bc = 18 * K / (π * δ^4) # bond constant - return CRPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) -end - -@params CRMaterial CRPointParameters - -@storage CRMaterial struct CRStorage - @lthfield position::Matrix{Float64} - @pointfield displacement::Matrix{Float64} - @pointfield velocity::Matrix{Float64} - @lthfield velocity_half::Matrix{Float64} - @pointfield velocity_half_old::Matrix{Float64} - @pointfield acceleration::Matrix{Float64} - @htlfield b_int::Matrix{Float64} - @pointfield b_int_old::Matrix{Float64} - @pointfield b_ext::Matrix{Float64} - @pointfield density_matrix::Matrix{Float64} - @pointfield damage::Vector{Float64} - bond_active::Vector{Bool} - @pointfield n_active_bonds::Vector{Int} - @pointfield stress::Matrix{Float64} - @pointfield von_mises_stress::Vector{Float64} - @pointfield left_stretch::Matrix{Float64} - @pointfield rotation::Matrix{Float64} -end - -function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:velocity_half}) - return zeros(3, get_n_points(system)) -end - -function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int}) - return zeros(3, get_n_points(system)) -end - -function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:stress}) - return zeros(9, get_n_loc_points(system)) -end - -function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:von_mises_stress}) - return zeros(get_n_loc_points(system)) -end - -function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:left_stretch}) - V = zeros(9, get_n_loc_points(system)) - V[[1, 5, 9], :] .= 1.0 - return V -end - -function init_field(::CRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:rotation}) - R = zeros(9, get_n_loc_points(system)) - R[[1, 5, 9], :] .= 1.0 - return R -end - -function calc_deformation_gradient(storage::CRStorage, system::BondSystem, - ::CRMaterial, ::CRPointParameters, i) - (; bonds, volume) = system - (; bond_active) = storage - K = zero(SMatrix{3,3,Float64,9}) - _F = zero(SMatrix{3,3,Float64,9}) - _Ḟ = zero(SMatrix{3,3,Float64,9}) - ω0 = 0.0 - for bond_id in each_bond_idx(system, i) - bond = bonds[bond_id] - j = bond.neighbor - ΔXij = get_diff(system.position, i, j) - Δxij = get_diff(storage.position, i, j) - Δvij = get_diff(storage.velocity_half, i, j) - ωij = kernel(system, bond_id) * bond_active[bond_id] - ω0 += ωij - temp = ωij * volume[j] - ΔXijt = ΔXij' - K += temp * (ΔXij * ΔXijt) - _F += temp * (Δxij * ΔXijt) - _Ḟ += temp * (Δvij * ΔXijt) - end - Kinv = inv(K) - F = _F * Kinv - Ḟ = _Ḟ * Kinv - return (; F, Ḟ, Kinv, ω0) -end - -# function calc_first_piola_kirchhoff!(storage::CRStorage, mat::CRMaterial, -# params::CRPointParameters, defgrad_res, Δt, i) -# (; F, Ḟ, Kinv) = defgrad_res -# _P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) -# _σ = cauchy_stress(_P, F) -# init_stress_rotation!(storage, F, Ḟ, Δt, i) -# T = rotate_stress(storage, _σ, i) -# P = first_piola_kirchhoff(T, F) -# PKinv = P * Kinv -# σ = cauchy_stress(P, F) -# update_tensor!(storage.stress, i, σ) -# storage.von_mises_stress[i] = von_mises_stress(σ) -# return PKinv -# end - -function calc_first_piola_kirchhoff!(storage::CRStorage, ::CRMaterial, - params::CRPointParameters, defgrad_res, Δt, i) - (; F, Ḟ, Kinv) = defgrad_res - D = init_stress_rotation!(storage, F, Ḟ, Δt, i) - if iszero(D) - storage.von_mises_stress[i] = 0.0 - return zero(SMatrix{3,3,Float64,9}) - end - Δε = D * Δt - Δθ = tr(Δε) - Δεᵈᵉᵛ = Δε - Δθ / 3 * I - σ = get_tensor(storage.stress, i) - σₙ₊₁ = σ + 2 * params.G * Δεᵈᵉᵛ + params.K * Δθ * I - update_tensor!(storage.stress, i, σₙ₊₁) - T = rotate_stress(storage, σₙ₊₁, i) - storage.von_mises_stress[i] = von_mises_stress(T) - P = first_piola_kirchhoff(T, F) - PKinv = P * Kinv - return PKinv -end diff --git a/src/physics/ns_correspondence.jl b/src/physics/ns_correspondence.jl deleted file mode 100644 index aac74260..00000000 --- a/src/physics/ns_correspondence.jl +++ /dev/null @@ -1,590 +0,0 @@ -""" - NSCMaterial(; maxdmg, zem) - -A material type used to assign the material of a [`Body`](@ref) with the local continuum -consistent (correspondence) formulation of non-ordinary state-based peridynamics. - -# Keywords -- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is - exceeded, all bonds of that point are broken because the deformation gradient would then - possibly contain `NaN` values. - (default: `0.95`) - -# Examples - -```julia-repl -julia> mat = NSCMaterial() -NSCMaterial(maxdmg=0.95) -``` - ---- - -```julia -NSCMaterial -``` - -Material type for the local continuum consistent (correspondence) formulation of -non-ordinary state-based peridynamics. - -# Fields -- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. See the - constructor docs for more informations. - -# Allowed material parameters -When using [`material!`](@ref) on a [`Body`](@ref) with `NSCMaterial`, then the following -parameters are allowed: -- `horizon::Float64`: Radius of point interactions -- `rho::Float64`: Density -- `E::Float64`: Young's modulus -- `nu::Float64`: Poisson's ratio -- `Gc::Float64`: Critical energy release rate -- `epsilon_c::Float64`: Critical strain - -# Allowed export fields -When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with -`NSCMaterial`, the following fields are allowed: -- `position::Matrix{Float64}`: Position of each point -- `displacement::Matrix{Float64}`: Displacement of each point -- `velocity::Matrix{Float64}`: Velocity of each point -- `velocity_half::Matrix{Float64}`: Velocity parameter for Verlet time solver -- `acceleration::Matrix{Float64}`: Acceleration of each point -- `b_int::Matrix{Float64}`: Internal force density of each point -- `b_ext::Matrix{Float64}`: External force density of each point -- `damage::Vector{Float64}`: Damage of each point -- `n_active_bonds::Vector{Int}`: Number of intact bonds of each point -""" -struct NSCMaterial{CM,K} <: AbstractCorrespondenceMaterial{CM,NoCorrection} - kernel::K - constitutive_model::CM - maxdmg::Float64 - function NSCMaterial(kernel::K, cm::CM, maxdmg::Real) where {CM,K} - return new{CM,K}(kernel, cm, maxdmg) - end -end - -function Base.show(io::IO, @nospecialize(mat::NSCMaterial)) - print(io, typeof(mat)) - print(io, msg_fields_in_brackets(mat, (:maxdmg,))) - return nothing -end - -function NSCMaterial(; kernel::Function=cubic_b_spline, - model::AbstractConstitutiveModel=SaintVenantKirchhoff(), - maxdmg::Real=0.85) - return NSCMaterial(kernel, model, maxdmg) -end - -struct NSCPointParameters <: AbstractPointParameters - δ::Float64 - rho::Float64 - E::Float64 - nu::Float64 - G::Float64 - K::Float64 - λ::Float64 - μ::Float64 - Gc::Float64 - εc::Float64 - bc::Float64 -end - -function NSCPointParameters(mat::NSCMaterial, p::Dict{Symbol,Any}) - (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) - (; Gc, εc) = get_frac_params(p, δ, K) - bc = 18 * K / (π * δ^4) # bond constant - return NSCPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) -end - -@params NSCMaterial NSCPointParameters - -@storage NSCMaterial struct NSCStorage - @lthfield position::Matrix{Float64} - @pointfield displacement::Matrix{Float64} - @pointfield velocity::Matrix{Float64} - @pointfield velocity_half::Matrix{Float64} - @pointfield velocity_half_old::Matrix{Float64} - @pointfield acceleration::Matrix{Float64} - @htlfield b_int::Matrix{Float64} - @pointfield b_int_old::Matrix{Float64} - @pointfield b_ext::Matrix{Float64} - @pointfield density_matrix::Matrix{Float64} - @pointfield damage::Vector{Float64} - bond_active::Vector{Bool} - @pointfield n_active_bonds::Vector{Int} - @pointfield damage_changed::Vector{Bool} - @pointfield stress::Matrix{Float64} - @pointfield von_mises_stress::Vector{Float64} - @lthfield defgrad::Matrix{Float64} - @lthfield weighted_volume::Vector{Float64} - gradient_weight::Matrix{Float64} - first_piola_kirchhoff::Matrix{Float64} -end - -function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int}) - return zeros(3, get_n_points(system)) -end - -function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:damage_changed}) - return ones(Bool, get_n_loc_points(system)) -end - -function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:stress}) - return zeros(9, get_n_loc_points(system)) -end - -function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:von_mises_stress}) - return zeros(get_n_loc_points(system)) -end - -function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:defgrad}) - return zeros(9, get_n_points(system)) -end - -function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:weighted_volume}) - return zeros(get_n_points(system)) -end - -function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:gradient_weight}) - return zeros(3, get_n_bonds(system)) -end - -function init_field(::NSCMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:first_piola_kirchhoff}) - return zeros(9, get_n_bonds(system)) -end - -function initialize!(chunk::BodyChunk{<:BondSystem,<:NSCMaterial}) - chunk.storage.damage_changed .= true - return nothing -end - -@inline function calc_damage!(chunk::BodyChunk{<:BondSystem,<:NSCMaterial}) - (; n_neighbors) = chunk.system - (; n_active_bonds, damage, damage_changed) = chunk.storage - for point_id in each_point_idx(chunk) - old_damage = damage[point_id] - new_damage = 1 - n_active_bonds[point_id] / n_neighbors[point_id] - if new_damage > old_damage - damage_changed[point_id] = true - else - damage_changed[point_id] = false - end - damage[point_id] = new_damage - end - return nothing -end - -function calc_force_density!(dh::ThreadsBodyDataHandler{<:BondSystem,<:NSCMaterial}, t, Δt) - @threads :static for chunk_id in eachindex(dh.chunks) - exchange_loc_to_halo!(dh, chunk_id, :position) - end - @threads :static for chunk_id in eachindex(dh.chunks) - calc_weights_and_defgrad!(dh.chunks[chunk_id], t, Δt) - end - @threads :static for chunk_id in eachindex(dh.chunks) - exchange_loc_to_halo!(dh, chunk_id, (:defgrad, :weighted_volume)) - end - @threads :static for chunk_id in eachindex(dh.chunks) - chunk = dh.chunks[chunk_id] - calc_force_density!(chunk, t, Δt) - nancheck(chunk, t) - end - @threads :static for chunk_id in eachindex(dh.chunks) - exchange_halo_to_loc!(dh, chunk_id) - end - return nothing -end - -function calc_force_density!(dh::MPIBodyDataHandler{<:BondSystem,<:NSCMaterial}, t, Δt) - (; chunk) = dh - exchange_loc_to_halo!(dh, :position) - calc_weights_and_defgrad!(chunk, t, Δt) - exchange_loc_to_halo!(dh, (:defgrad, :weighted_volume)) - calc_force_density!(chunk, t, Δt) - nancheck(chunk, t) - exchange_halo_to_loc!(dh) - return nothing -end - -function calc_weights_and_defgrad!(chunk::BodyChunk{<:BondSystem,<:NSCMaterial}, t, Δt) - (; system, mat, paramsetup, storage) = chunk - for i in each_point_idx(system) - calc_weights_and_defgrad!(storage, system, mat, paramsetup, t, Δt, i) - end - return nothing -end - -function calc_weights_and_defgrad!(storage::NSCStorage, system::BondSystem, - mat::NSCMaterial, paramhandler::AbstractParameterHandler, - t, Δt, i) - params = get_params(paramhandler, i) - calc_weights_and_defgrad!(storage, system, mat, params, t, Δt, i) - return nothing -end - -function calc_weights_and_defgrad!(storage::NSCStorage, system::BondSystem, - mat::NSCMaterial, params::NSCPointParameters, t, Δt, i) - (; bonds, volume) = system - (; bond_active, weighted_volume, gradient_weight, damage_changed) = storage - - K = zero(SMatrix{3,3,Float64,9}) - _F = zero(SMatrix{3,3,Float64,9}) - wi = 0.0 - for bond_id in each_bond_idx(system, i) - bond = bonds[bond_id] - j = bond.neighbor - ΔXij = get_diff(system.position, i, j) - Δxij = get_diff(storage.position, i, j) - ωij = kernel(system, bond_id) * bond_active[bond_id] - temp = ωij * volume[j] - K += temp * (ΔXij * ΔXij') - _F += temp * (Δxij * ΔXij') - wi += temp - end - Kinv = inv(K) - F = _F * Kinv - update_tensor!(storage.defgrad, i, F) - weighted_volume[i] = wi - - damage_changed[i] || return nothing - - for bond_id in each_bond_idx(system, i) - bond = bonds[bond_id] - j = bond.neighbor - ΔXij = get_diff(system.position, i, j) - ωij = kernel(system, bond_id) * bond_active[bond_id] - # temp = ωij - temp = ωij * volume[j] - Ψ = temp * (Kinv * ΔXij) - update_vector!(gradient_weight, bond_id, Ψ) - end - - return nothing -end - -function force_density_point!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, - paramhandler::AbstractParameterHandler, t, Δt, i) - params = get_params(paramhandler, i) - force_density_point!(storage, system, mat, params, t, Δt, i) - return nothing -end - -function force_density_point!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, - params::NSCPointParameters, t, Δt, i) - # Fi = get_tensor(storage.defgrad, i) - # too_much_damage!(storage, system, mat, Fi, i) && return nothing - # P = calc_first_piola_kirchhoff!(storage, mat, params, Fi, Δt, i) - # nsc_force_density!(storage, system, mat, params, P, i) - nsc_force_density!(storage, system, mat, params, i) - return nothing -end - -function calc_first_piola_kirchhoff!(storage::NSCStorage, mat::NSCMaterial, - params::NSCPointParameters, F, Δt, i) - P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) - σ = cauchy_stress(P, F) - update_tensor!(storage.stress, i, σ) - storage.von_mises_stress[i] = von_mises_stress(σ) - return P -end - -function calc_first_piola_kirchhoff(storage::NSCStorage, mat::NSCMaterial, - params::NSCPointParameters, F) - P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) - return P -end - -# Working version!!! -# function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, -# params::NSCPointParameters, P::SMatrix, i) -# (; bonds, volume) = system -# (; bond_active, gradient_weight) = storage -# for bond_id in each_bond_idx(system, i) -# bond = bonds[bond_id] -# j, L = bond.neighbor, bond.length -# Δxij = get_coordinates_diff(storage, i, j) -# l = norm(Δxij) -# ε = (l - L) / L -# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) -# if bond_active[bond_id] -# Ψ = get_vector(gradient_weight, bond_id) -# tij = P * Ψ -# update_add_b_int!(storage, i, tij .* volume[j]) -# update_add_b_int!(storage, j, -tij .* volume[i]) -# end -# end -# return nothing -# end - -# function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, -# params::NSCPointParameters, i) -# (; bonds, volume) = system -# (; bond_active, gradient_weight, defgrad) = storage -# Fi = get_tensor(defgrad, i) -# too_much_damage!(storage, system, mat, Fi, i) && return nothing -# for bond_id in each_bond_idx(system, i) -# bond = bonds[bond_id] -# j, L = bond.neighbor, bond.length -# Δxij = get_coordinates_diff(storage, i, j) -# l = norm(Δxij) -# ε = (l - L) / L -# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) -# if bond_active[bond_id] -# Fj = get_tensor(defgrad, j) -# Fb = 0.5 * (Fi + Fj) -# ΔXij = get_coordinates_diff(system, i, j) -# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) -# Fij = Fb + ΔFij -# P = calc_first_piola_kirchhoff(storage, mat, params, Fij) -# Ψ = get_vector(gradient_weight, bond_id) -# tij = P * Ψ -# update_add_b_int!(storage, i, tij .* volume[j]) -# update_add_b_int!(storage, j, -tij .* volume[i]) -# end -# end -# return nothing -# end - -function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, - params::NSCPointParameters, i) - (; bonds, volume) = system - (; bond_active, gradient_weight, defgrad, weighted_volume) = storage - - Fi = get_tensor(defgrad, i) - # too_much_damage!(storage, system, mat, Fi, i) && return nothing - - # Stress integral SI - wi = weighted_volume[i] - ∑P = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) - for bond_id in each_bond_idx(system, i) - bond = bonds[bond_id] - j, L = bond.neighbor, bond.length - ΔXij = get_coordinates_diff(system, i, j) - Δxij = get_coordinates_diff(storage, i, j) - l = norm(Δxij) - ε = (l - L) / L - stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - - if bond_active[bond_id] - Fj = get_tensor(defgrad, j) - Fb = 0.5 * (Fi + Fj) - ΔXijLL = ΔXij' / (L * L) - ΔFij = (Δxij - Fb * ΔXij) * ΔXijLL - Fij = Fb + ΔFij - Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) - update_tensor!(storage.first_piola_kirchhoff, bond_id, Pij) - Tempij = I - ΔXij * ΔXijLL - wj = weighted_volume[j] - ϕ = (wi > 0 && wj > 0) ? (0.5 / wi + 0.5 / wj) : 0.0 - ω̃ij = kernel(system, bond_id) * ϕ - ∑Pij = ω̃ij * (Pij * Tempij) - ∑P += ∑Pij - end - end - - for bond_id in each_bond_idx(system, i) - if bond_active[bond_id] - bond = bonds[bond_id] - j, L = bond.neighbor, bond.length - ΔXij = get_coordinates_diff(system, i, j) - Pij = get_tensor(storage.first_piola_kirchhoff, bond_id) - Φij = get_vector(gradient_weight, bond_id) - wj = weighted_volume[j] - ϕ = (wi > 0 && wj > 0) ? (0.5 / wi + 0.5 / wj) : 0.0 - ω̃ij = kernel(system, bond_id) * ϕ - tij = ω̃ij / (L * L) * (Pij * ΔXij) + ∑P * Φij - update_add_b_int!(storage, i, tij * volume[j]) - update_add_b_int!(storage, j, -tij * volume[i]) - end - end - return nothing -end - - -# NODALLY STABLIZIED VERSION!!! WORKING, BUT NOT SURE IF CORRECT! -# function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, -# params::NSCPointParameters, P::SMatrix, i) -# (; bonds, volume) = system -# (; bond_active, gradient_weight, defgrad) = storage -# Fi = get_tensor(defgrad, i) -# too_much_damage!(storage, system, mat, Fi, i) && return nothing -# for bond_id in each_bond_idx(system, i) -# bond = bonds[bond_id] -# j, L = bond.neighbor, bond.length -# Δxij = get_coordinates_diff(storage, i, j) -# l = norm(Δxij) -# ε = (l - L) / L -# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) -# if bond_active[bond_id] -# ΔXij = get_coordinates_diff(system, i, j) -# Fj = get_tensor(defgrad, j) -# Fb = 0.5 * (Fi + Fj) -# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) -# Fij = Fb + ΔFij -# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) -# Ψ = get_vector(gradient_weight, bond_id) -# tij = (Pij * Ψ) / volume[j] -# update_add_b_int!(storage, i, tij .* volume[j]) -# update_add_b_int!(storage, j, -tij .* volume[i]) -# end -# end -# return nothing -# end - - -# PERIDIGM VERSION -# function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, -# params::NSCPointParameters, P::SMatrix, i) -# (; bonds, volume) = system -# (; bond_active, gradient_weight, defgrad, weighted_volume) = storage -# Fi = get_tensor(defgrad, i) -# wi = weighted_volume[i] -# SI = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) -# for bond_id in each_bond_idx(system, i) -# bond = bonds[bond_id] -# j, L = bond.neighbor, bond.length -# ΔXij = get_coordinates_diff(system, i, j) -# Δxij = get_coordinates_diff(storage, i, j) -# l = norm(Δxij) -# ε = (l - L) / L -# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - -# Fj = get_tensor(defgrad, j) -# Fb = 0.5 * (Fi + Fj) -# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) -# Fij = Fb + ΔFij -# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) -# # update_tensor!(first_piola_kirchhoff, bond_id, Pij) -# # ΔPij = Pij - Pi -# Tempij = (I - ΔXij * ΔXij') / (L * L) -# ωij = influence_function(mat, params, L) * bond_active[bond_id] -# wj = weighted_volume[j] -# ϕ = volume[j] * ωij * (0.5 / wi + 0.5 / wj) -# SI += ϕ * (Pij * Tempij) -# end -# for bond_id in each_bond_idx(system, i) -# bond = bonds[bond_id] -# j, L = bond.neighbor, bond.length -# ΔXij = get_coordinates_diff(system, i, j) -# Δxij = get_coordinates_diff(storage, i, j) -# Fj = get_tensor(defgrad, j) -# Fb = 0.5 * (Fi + Fj) -# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) -# Fij = Fb + ΔFij -# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) -# Φij = get_vector(gradient_weight, bond_id) -# ωij = influence_function(mat, params, L) * bond_active[bond_id] -# tij = (SI * Φij) / volume[j] + ωij / (wi * L * L) * (Pij * ΔXij) -# update_add_b_int!(storage, i, tij * volume[j]) -# update_add_b_int!(storage, j, -tij * volume[i]) -# end -# return nothing -# end - -# NODALLY STABLIZIED VERSION WRONG? -# function nsc_force_density!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, -# params::NSCPointParameters, P::SMatrix, i) -# (; bonds, volume) = system -# (; bond_active, gradient_weight, defgrad, weighted_volume) = storage -# Fi = get_tensor(defgrad, i) -# Vi = volume[i] -# wi = weighted_volume[i] - -# for bond_id_j in each_bond_idx(system, i) -# bond_ij = bonds[bond_id_j] -# j, Lij = bond_ij.neighbor, bond_ij.length -# ΔXij = get_coordinates_diff(storage, i, j) -# Δxij = get_coordinates_diff(storage, i, j) -# lij = norm(Δxij) -# ε = (lij - Lij) / Lij -# stretch_based_failure!(storage, system, bond_ij, params, ε, i, bond_id_j) - -# ωij = influence_function(mat, params, Lij) -# Vj, wj = volume[j], weighted_volume[j] -# Ṽij = (Vi * Vj) / 2 * (ωij / wj + ωij / wi) -# Ψij = get_vector(gradient_weight, bond_id_j) -# Fj = get_tensor(defgrad, j) -# Fij = 0.5 * (Fi + Fj) -# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) - -# Tcor = Ṽij * (Pij * ΔXij) / (Vj * Vi * Lij * Lij) - -# Tave = zero(SVector{3,Float64}) -# for bond_id_k in each_bond_idx(system, i) -# bond_ik = bonds[bond_id_k] -# k, Lik = bond_ik.neighbor, bond_ik.length -# ωik = influence_function(mat, params, Lik) -# Vk, wk = volume[k], weighted_volume[k] -# Ṽik = (Vi * Vk) / 2 * (ωik / wk + ωij / wi) -# Fk = get_tensor(defgrad, k) -# Fik = 0.5 * (Fi + Fk) -# Pik = calc_first_piola_kirchhoff(storage, mat, params, Fik) -# Tave += Ṽik * (Pik * Ψij) / (Vj * Vi) -# ΔXΔXΨ = (ΔXij * ΔXij') * Ψij -# Tcor -= Ṽik * (Pik * ΔXΔXΨ) / (Vj * Vi * Lik * Lik) -# end - -# T = Tave + Tcor -# update_add_b_int!(storage, i, T .* volume[j]) -# update_add_b_int!(storage, j, -T .* volume[i]) -# end -# return nothing -# end - - # Tcor2 = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) - # for bond_id in each_bond_idx(system, i) - # bond = bonds[bond_id] - # j, L = bond.neighbor, bond.length - # ΔXij = get_coordinates_diff(system, i, j) - # Δxij = get_coordinates_diff(storage, i, j) - # l = norm(Δxij) - # ε = (l - L) / L - # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - - # if bond_active[bond_id] - # ωij = influence_function(mat, params, L) - # Vj, wj = volume[j], weighted_volume[j] - # Ṽij = (Vi * Vj) / 2 * (ωij / wi + ωij / wj) - - # Fj = get_tensor(defgrad, j) - # Fb = 0.5 * (Fi + Fj) - # Pb = calc_first_piola_kirchhoff(storage, mat, params, Fb) - - # temp = Ṽij / (Vi * Vj * L * L) - # Ψ = get_vector(gradient_weight, bond_id) - # ΔXΨ = (ΔXij * ΔXij') * Ψ - # Tcor2 += temp * (P * ΔXΨ) - # end - # end - - # for bond_id in each_bond_idx(system, i) - # if bond_active[bond_id] - # bond = bonds[bond_id] - # j, L = bond.neighbor, bond.length - # ΔXij = get_coordinates_diff(system, i, j) - # Δxij = get_coordinates_diff(storage, i, j) - - # # update of force density - # Ψ = get_vector(gradient_weight, bond_id) - # tij = (P * Ψ) / volume[j] - # update_add_b_int!(storage, i, tij .* volume[j]) - # update_add_b_int!(storage, j, -tij .* volume[i]) - # end - # end -# return nothing -# end - -function too_much_damage!(storage::NSCStorage, system::BondSystem, mat::NSCMaterial, F, i) - if storage.damage[i] > mat.maxdmg || containsnan(F) - # kill all bonds of this point - storage.bond_active[each_bond_idx(system, i)] .= false - storage.n_active_bonds[i] = 0 - return true - end - return false -end diff --git a/src/physics/ns_correspondence_rotated.jl b/src/physics/ns_correspondence_rotated.jl deleted file mode 100644 index 5d333bba..00000000 --- a/src/physics/ns_correspondence_rotated.jl +++ /dev/null @@ -1,834 +0,0 @@ -""" - NSCRMaterial(; maxdmg, zem) - -A material type used to assign the material of a [`Body`](@ref) with the local continuum -consistent (correspondence) formulation of non-ordinary state-based peridynamics. - -# Keywords -- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is - exceeded, all bonds of that point are broken because the deformation gradient would then - possibly contain `NaN` values. - (default: `0.95`) - -# Examples - -```julia-repl -julia> mat = NSCRMaterial() -NSCRMaterial(maxdmg=0.95) -``` - ---- - -```julia -NSCRMaterial -``` - -Material type for the local continuum consistent (correspondence) formulation of -non-ordinary state-based peridynamics. - -# Fields -- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. See the - constructor docs for more informations. - -# Allowed material parameters -When using [`material!`](@ref) on a [`Body`](@ref) with `NSCRMaterial`, then the following -parameters are allowed: -- `horizon::Float64`: Radius of point interactions -- `rho::Float64`: Density -- `E::Float64`: Young's modulus -- `nu::Float64`: Poisson's ratio -- `Gc::Float64`: Critical energy release rate -- `epsilon_c::Float64`: Critical strain - -# Allowed export fields -When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with -`NSCRMaterial`, the following fields are allowed: -- `position::Matrix{Float64}`: Position of each point -- `displacement::Matrix{Float64}`: Displacement of each point -- `velocity::Matrix{Float64}`: Velocity of each point -- `velocity_half::Matrix{Float64}`: Velocity parameter for Verlet time solver -- `acceleration::Matrix{Float64}`: Acceleration of each point -- `b_int::Matrix{Float64}`: Internal force density of each point -- `b_ext::Matrix{Float64}`: External force density of each point -- `damage::Vector{Float64}`: Damage of each point -- `n_active_bonds::Vector{Int}`: Number of intact bonds of each point -""" -struct NSCRMaterial{CM,K} <: AbstractCorrespondenceMaterial{CM,NoCorrection} - kernel::K - constitutive_model::CM - maxdmg::Float64 - function NSCRMaterial(kernel::K, cm::CM, maxdmg::Real) where {CM,K} - return new{CM,K}(kernel, cm, maxdmg) - end -end - -function Base.show(io::IO, @nospecialize(mat::NSCRMaterial)) - print(io, typeof(mat)) - print(io, msg_fields_in_brackets(mat, (:maxdmg,))) - return nothing -end - -function NSCRMaterial(; kernel::Function=cubic_b_spline, - model::AbstractConstitutiveModel=SaintVenantKirchhoff(), - maxdmg::Real=0.85) - return NSCRMaterial(kernel, model, maxdmg) -end - -struct NSCRPointParameters <: AbstractPointParameters - δ::Float64 - rho::Float64 - E::Float64 - nu::Float64 - G::Float64 - K::Float64 - λ::Float64 - μ::Float64 - Gc::Float64 - εc::Float64 - bc::Float64 -end - -function NSCRPointParameters(mat::NSCRMaterial, p::Dict{Symbol,Any}) - (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) - (; Gc, εc) = get_frac_params(p, δ, K) - bc = 18 * K / (π * δ^4) # bond constant - return NSCRPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) -end - -@params NSCRMaterial NSCRPointParameters - -@storage NSCRMaterial struct NSCRStorage - @lthfield position::Matrix{Float64} - @pointfield displacement::Matrix{Float64} - @pointfield velocity::Matrix{Float64} - @lthfield velocity_half::Matrix{Float64} - @pointfield velocity_half_old::Matrix{Float64} - @pointfield acceleration::Matrix{Float64} - @htlfield b_int::Matrix{Float64} - @pointfield b_int_old::Matrix{Float64} - @pointfield b_ext::Matrix{Float64} - @pointfield density_matrix::Matrix{Float64} - @pointfield damage::Vector{Float64} - bond_active::Vector{Bool} - @pointfield n_active_bonds::Vector{Int} - @pointfield damage_changed::Vector{Bool} - # @pointfield stress::Matrix{Float64} - # @pointfield von_mises_stress::Vector{Float64} - @lthfield defgrad::Matrix{Float64} - @lthfield defgrad_dot::Matrix{Float64} - @lthfield weighted_volume::Vector{Float64} - gradient_weight::Matrix{Float64} - rotation::Matrix{Float64} - left_stretch::Matrix{Float64} - unrot_rate_of_deformation::Matrix{Float64} - bond_stress::Matrix{Float64} - first_piola_kirchhoff::Matrix{Float64} -end - -function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:velocity_half}) - return zeros(3, get_n_points(system)) -end - -function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int}) - return zeros(3, get_n_points(system)) -end - -function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:damage_changed}) - return ones(Bool, get_n_loc_points(system)) -end - -function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:stress}) - return zeros(9, get_n_loc_points(system)) -end - -function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:von_mises_stress}) - return zeros(get_n_loc_points(system)) -end - -function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:rotation}) - R = zeros(9, get_n_bonds(system)) - R[[1, 5, 9], :] .= 1.0 - return R -end - -function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:left_stretch}) - V = zeros(9, get_n_bonds(system)) - V[[1, 5, 9], :] .= 1.0 - return V -end - -function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:unrot_rate_of_deformation}) - return zeros(9, get_n_bonds(system)) -end - -function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:defgrad}) - return zeros(9, get_n_points(system)) -end - -function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:defgrad_dot}) - return zeros(9, get_n_points(system)) -end - -function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:weighted_volume}) - return zeros(get_n_points(system)) -end - -function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:gradient_weight}) - return zeros(3, get_n_bonds(system)) -end - -function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:first_piola_kirchhoff}) - return zeros(9, get_n_bonds(system)) -end - -function init_field(::NSCRMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:bond_stress}) - return zeros(9, get_n_bonds(system)) -end - -function initialize!(chunk::BodyChunk{<:BondSystem,<:NSCRMaterial}) - chunk.storage.damage_changed .= true - return nothing -end - -@inline function calc_damage!(chunk::BodyChunk{<:BondSystem,<:NSCRMaterial}) - (; system, storage, paramsetup) = chunk - (; n_neighbors, bonds) = system - (; n_active_bonds, damage, damage_changed) = storage - for i in each_point_idx(chunk) - params = get_params(paramsetup, i) - for bond_id in each_bond_idx(system, i) - bond = bonds[bond_id] - j, L = bond.neighbor, bond.length - Δxij = get_coordinates_diff(storage, i, j) - l = norm(Δxij) - ε = (l - L) / L - stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - end - old_damage = damage[i] - new_damage = 1 - n_active_bonds[i] / n_neighbors[i] - if new_damage > old_damage - damage_changed[i] = true - else - damage_changed[i] = false - end - damage[i] = new_damage - end - return nothing -end - -function calc_force_density!(dh::ThreadsBodyDataHandler{<:BondSystem,<:NSCRMaterial}, t, Δt) - @threads :static for chunk_id in eachindex(dh.chunks) - exchange_loc_to_halo!(dh, chunk_id, (:position, :velocity_half)) - end - @threads :static for chunk_id in eachindex(dh.chunks) - calc_weights_and_defgrad!(dh.chunks[chunk_id], t, Δt) - end - @threads :static for chunk_id in eachindex(dh.chunks) - exchange_loc_to_halo!(dh, chunk_id, (:defgrad, :defgrad_dot, :weighted_volume)) - end - @threads :static for chunk_id in eachindex(dh.chunks) - chunk = dh.chunks[chunk_id] - calc_force_density!(chunk, t, Δt) - nancheck(chunk, t) - end - @threads :static for chunk_id in eachindex(dh.chunks) - exchange_halo_to_loc!(dh, chunk_id) - end - return nothing -end - -function calc_force_density!(dh::MPIBodyDataHandler{<:BondSystem,<:NSCRMaterial}, t, Δt) - (; chunk) = dh - exchange_loc_to_halo!(dh, (:position, :velocity_half)) - calc_weights_and_defgrad!(chunk, t, Δt) - exchange_loc_to_halo!(dh, (:defgrad, :defgrad_dot, :weighted_volume)) - calc_force_density!(chunk, t, Δt) - nancheck(chunk, t) - exchange_halo_to_loc!(dh) - return nothing -end - -function calc_weights_and_defgrad!(chunk::BodyChunk{<:BondSystem,<:NSCRMaterial}, t, Δt) - (; system, mat, paramsetup, storage) = chunk - for i in each_point_idx(system) - calc_failure_point!(storage, system, mat, paramsetup, i) - calc_weights_and_defgrad!(storage, system, mat, paramsetup, t, Δt, i) - end - return nothing -end - -function calc_weights_and_defgrad!(storage::NSCRStorage, system::BondSystem, - mat::NSCRMaterial, - paramhandler::AbstractParameterHandler, t, Δt, i) - params = get_params(paramhandler, i) - calc_weights_and_defgrad!(storage, system, mat, params, t, Δt, i) - return nothing -end - -function calc_weights_and_defgrad!(storage::NSCRStorage, system::BondSystem, - mat::NSCRMaterial, params::NSCRPointParameters, t, Δt, i) - (; bonds, volume) = system - (; bond_active, weighted_volume, gradient_weight, damage_changed) = storage - - K = zero(SMatrix{3,3,Float64,9}) - _F = zero(SMatrix{3,3,Float64,9}) - _Ḟ = zero(SMatrix{3,3,Float64,9}) - wi = 0.0 - for bond_id in each_bond_idx(system, i) - bond = bonds[bond_id] - j = bond.neighbor - ΔXij = get_diff(system.position, i, j) - Δxij = get_diff(storage.position, i, j) - Δvij = get_diff(storage.velocity_half, i, j) - ωij = kernel(system, bond_id) * bond_active[bond_id] - temp = ωij * volume[j] - K += temp * (ΔXij * ΔXij') - _F += temp * (Δxij * ΔXij') - _Ḟ += temp * (Δvij * ΔXij') - wi += temp - end - Kinv = inv(K) - F = _F * Kinv - Ḟ = _Ḟ * Kinv - update_tensor!(storage.defgrad, i, F) - update_tensor!(storage.defgrad_dot, i, Ḟ) - weighted_volume[i] = wi - - damage_changed[i] || return nothing - - for bond_id in each_bond_idx(system, i) - bond = bonds[bond_id] - j = bond.neighbor - ΔXij = get_diff(system.position, i, j) - ωij = kernel(system, bond_id) * bond_active[bond_id] - temp = ωij * volume[j] - Ψ = temp * (Kinv * ΔXij) - update_vector!(gradient_weight, bond_id, Ψ) - end - - return nothing -end - -function force_density_point!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, - paramhandler::AbstractParameterHandler, t, Δt, i) - params = get_params(paramhandler, i) - force_density_point!(storage, system, mat, params, t, Δt, i) - return nothing -end - -function force_density_point!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, - params::NSCRPointParameters, t, Δt, i) - # Fi = get_tensor(storage.defgrad, i) - # too_much_damage!(storage, system, mat, Fi, i) && return nothing - # P = calc_first_piola_kirchhoff!(storage, mat, params, Fi, Δt, i) - # nsc_force_density!(storage, system, mat, params, P, i) - # nsc_force_density!(storage, system, mat, params, i) - - (; bonds, volume) = system - (; bond_active, gradient_weight, defgrad, defgrad_dot, weighted_volume) = storage - - Fi = get_tensor(defgrad, i) - Ḟi = get_tensor(defgrad_dot, i) - # too_much_damage!(storage, system, mat, Fi, i) && return nothing - - # Stress integral ∑P - wi = weighted_volume[i] - ∑P = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) - for bond_id in each_bond_idx(system, i) - bond = bonds[bond_id] - j, L = bond.neighbor, bond.length - Δxij = get_coordinates_diff(storage, i, j) - # l = norm(Δxij) - # ε = (l - L) / L - # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - - if bond_active[bond_id] - ΔXij = get_coordinates_diff(system, i, j) - Δvij = get_diff(storage.velocity_half, i, j) - Fj = get_tensor(defgrad, j) - Ḟj = get_tensor(defgrad_dot, j) - Fb = 0.5 * (Fi + Fj) - Ḟb = 0.5 * (Ḟi + Ḟj) - ΔXijLL = ΔXij' / (L * L) - ΔFij = (Δxij - Fb * ΔXij) * ΔXijLL - ΔḞij = (Δvij - Ḟb * ΔXij) * ΔXijLL - Fij = Fb + ΔFij - Ḟij = Ḟb + ΔḞij - Pij = calc_first_piola_kirchhoff!(storage, mat, params, Fij, Ḟij, Δt, bond_id) - Tempij = I - ΔXij * ΔXijLL - # ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) - wj = weighted_volume[j] - ϕ = (wi > 0 && wj > 0) ? (0.5 / wi + 0.5 / wj) : 0.0 - ω̃ij = kernel(system, bond_id) * ϕ - ∑P += ω̃ij * (Pij * Tempij) - end - end - - for bond_id in each_bond_idx(system, i) - if bond_active[bond_id] - bond = bonds[bond_id] - j, L = bond.neighbor, bond.length - ΔXij = get_coordinates_diff(system, i, j) - Pij = get_tensor(storage.first_piola_kirchhoff, bond_id) - Φij = get_vector(gradient_weight, bond_id) - # ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) - wj = weighted_volume[j] - ϕ = (wi > 0 && wj > 0) ? (0.5 / wi + 0.5 / wj) : 0.0 - ω̃ij = kernel(system, bond_id) * ϕ - tij = ω̃ij / (L * L) * (Pij * ΔXij) + ∑P * Φij - update_add_b_int!(storage, i, tij * volume[j]) - update_add_b_int!(storage, j, -tij * volume[i]) - end - end - - return nothing -end - -# function calc_first_piola_kirchhoff!(storage::NSCRStorage, mat::NSCRMaterial, -# params::NSCRPointParameters, F, Ḟ, Δt, i) -# P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) -# σ = cauchy_stress(P, F) -# init_stress_rotation!(storage, F, Ḟ, Δt, i) -# T = rotate_stress(storage, σ, i) -# P = first_piola_kirchhoff(T, F) -# update_tensor!(storage.first_piola_kirchhoff, i, P) -# return P -# end - -function calc_first_piola_kirchhoff!(storage::NSCRStorage, ::NSCRMaterial, - params::NSCRPointParameters, F, Ḟ, Δt, bond_id) - D = init_stress_rotation!(storage, F, Ḟ, Δt, bond_id) - Δε = D * Δt - Δθ = tr(Δε) - Δεᵈᵉᵛ = Δε - Δθ / 3 * I - σ = get_tensor(storage.bond_stress, bond_id) - σₙ₊₁ = σ + 2 * params.G * Δεᵈᵉᵛ + params.K * Δθ * I - update_tensor!(storage.bond_stress, bond_id, σₙ₊₁) - T = rotate_stress(storage, σₙ₊₁, bond_id) - P = first_piola_kirchhoff(T, F) - update_tensor!(storage.first_piola_kirchhoff, bond_id, P) - return P -end - -# function calc_first_piola_kirchhoff!(storage, mat, params, F, Ḟ, Δt, i) -# 𝐋 = @MMatrix zeros(3,3) -# RoD = @MMatrix zeros(3,3) -# Spin = @MMatrix zeros(3,3) -# left_stretch = @MMatrix zeros(3,3) -# z = @MVector zeros(3) -# w = @MVector zeros(3) -# 𝛀Tens = @MMatrix zeros(3,3) -# Qmatrix = @MMatrix zeros(3,3) -# rot_tens_ = @MMatrix zeros(3,3) -# 𝛔_unrot = @MMatrix zeros(3,3) -# tempVec = @MMatrix zeros(3,3) -# 𝐅 = F -# 𝐅dot = Ḟ -# 𝐋 = 𝐅dot * inv(𝐅) -# RoD = 1/2 * (𝐋 + transpose(𝐋)) -# Spin = 1/2 * (𝐋 - transpose(𝐋)) -# left_stretch[1,1] = storage.left_stretch[1,i] -# left_stretch[1,2] = storage.left_stretch[2,i] -# left_stretch[1,3] = storage.left_stretch[3,i] -# left_stretch[2,1] = storage.left_stretch[4,i] -# left_stretch[2,2] = storage.left_stretch[5,i] -# left_stretch[2,3] = storage.left_stretch[6,i] -# left_stretch[3,1] = storage.left_stretch[7,i] -# left_stretch[3,2] = storage.left_stretch[8,i] -# left_stretch[3,3] = storage.left_stretch[9,i] -# z[1] = - storage.left_stretch[3, i] * RoD[4] - storage.left_stretch[6, i] * RoD[5] - -# storage.left_stretch[9, i] * RoD[6] + storage.left_stretch[2, i] * RoD[7] + -# storage.left_stretch[5, i] * RoD[8] + storage.left_stretch[8, i] * RoD[9]; -# z[2] = storage.left_stretch[3, i] * RoD[1] + storage.left_stretch[6, i] * RoD[2] + -# storage.left_stretch[9, i] * RoD[3] - storage.left_stretch[1, i] * RoD[7] - -# storage.left_stretch[4, i] * RoD[8] - storage.left_stretch[7, i] * RoD[9]; -# z[3] = - storage.left_stretch[2, i] * RoD[1] - storage.left_stretch[5, i] * RoD[2] - -# storage.left_stretch[8, i] * RoD[3] + storage.left_stretch[1, i] * RoD[4] + -# storage.left_stretch[4, i] * RoD[5] + storage.left_stretch[7, i] * RoD[6]; -# w[1] = 0.5 * (Spin[3,2] - Spin[2,3]) -# w[2] = 0.5 * (Spin[1,3] - Spin[3,1]) -# w[3] = 0.5 * (Spin[2,1] - Spin[1,2]) -# traceV = storage.left_stretch[1, i] + storage.left_stretch[5, i] + storage.left_stretch[9, i] -# omega = w + inv(traceV * I - left_stretch) * z -# 𝛀Tens[1,1] = 0.0 -# 𝛀Tens[1,2] = -omega[3] -# 𝛀Tens[1,3] = omega[2] -# 𝛀Tens[2,1] = omega[3] -# 𝛀Tens[2,2] = 0.0 -# 𝛀Tens[2,3] = -omega[1] -# 𝛀Tens[3,1] = -omega[2] -# 𝛀Tens[3,2] = omega[1] -# 𝛀Tens[3,3] = 0.0 -# ΩSq = omega[1]^2 + omega[2]^2 + omega[3]^2 -# Ω = sqrt(ΩSq) -# if ΩSq > 1e-16 && Ω !== Inf -# scfac1 = sin(Δt * Ω) / Ω -# scfac2 = -(1 - cos(Δt * Ω)) / ΩSq -# 𝛀TensSq = 𝛀Tens * 𝛀Tens -# Qmatrix = I + scfac1 * 𝛀Tens + scfac2 * 𝛀TensSq -# else -# Qmatrix .= 0. -# Qmatrix[1,1] = 1.0 -# Qmatrix[2,2] = 1.0 -# Qmatrix[3,3] = 1.0 -# end -# rot_tens_[1,1] = storage.rotation[1,i] -# rot_tens_[1,2] = storage.rotation[2,i] -# rot_tens_[1,3] = storage.rotation[3,i] -# rot_tens_[2,1] = storage.rotation[4,i] -# rot_tens_[2,2] = storage.rotation[5,i] -# rot_tens_[2,3] = storage.rotation[6,i] -# rot_tens_[3,1] = storage.rotation[7,i] -# rot_tens_[3,2] = storage.rotation[8,i] -# rot_tens_[3,3] = storage.rotation[9,i] -# rot_tens = Qmatrix * rot_tens_ -# storage.rotation[1,i] = rot_tens[1,1] -# storage.rotation[2,i] = rot_tens[1,2] -# storage.rotation[3,i] = rot_tens[1,3] -# storage.rotation[4,i] = rot_tens[2,1] -# storage.rotation[5,i] = rot_tens[2,2] -# storage.rotation[6,i] = rot_tens[2,3] -# storage.rotation[7,i] = rot_tens[3,1] -# storage.rotation[8,i] = rot_tens[3,2] -# storage.rotation[9,i] = rot_tens[3,3] -# Vdot = 𝐋 * left_stretch - left_stretch * 𝛀Tens -# storage.left_stretch[1,i] += Δt * Vdot[1,1] -# storage.left_stretch[2,i] += Δt * Vdot[1,2] -# storage.left_stretch[3,i] += Δt * Vdot[1,3] -# storage.left_stretch[4,i] += Δt * Vdot[2,1] -# storage.left_stretch[5,i] += Δt * Vdot[2,2] -# storage.left_stretch[6,i] += Δt * Vdot[2,3] -# storage.left_stretch[7,i] += Δt * Vdot[3,1] -# storage.left_stretch[8,i] += Δt * Vdot[3,2] -# storage.left_stretch[9,i] += Δt * Vdot[3,3] -# tempVec = RoD * rot_tens -# UnRotRoD = transpose(rot_tens) * tempVec -# strainInc = UnRotRoD * Δt -# deviatoricStrain = copy(strainInc) -# dilatation = strainInc[1,1] + strainInc[2,2] + strainInc[3,3] -# deviatoricStrain[1,1] -= dilatation/3 -# deviatoricStrain[2,2] -= dilatation/3 -# deviatoricStrain[3,3] -= dilatation/3 -# storage.bond_stress[1,i] += deviatoricStrain[1,1] * 2 * params.G + params.K * dilatation -# storage.bond_stress[2,i] += deviatoricStrain[1,2] * 2 * params.G -# storage.bond_stress[3,i] += deviatoricStrain[1,3] * 2 * params.G -# storage.bond_stress[4,i] += deviatoricStrain[2,1] * 2 * params.G -# storage.bond_stress[5,i] += deviatoricStrain[2,2] * 2 * params.G + params.K * dilatation -# storage.bond_stress[6,i] += deviatoricStrain[2,3] * 2 * params.G -# storage.bond_stress[7,i] += deviatoricStrain[3,1] * 2 * params.G -# storage.bond_stress[8,i] += deviatoricStrain[3,2] * 2 * params.G -# storage.bond_stress[9,i] += deviatoricStrain[3,3] * 2 * params.G + params.K * dilatation -# 𝛔_unrot[1,1] = storage.bond_stress[1,i] -# 𝛔_unrot[1,2] = storage.bond_stress[2,i] -# 𝛔_unrot[1,3] = storage.bond_stress[3,i] -# 𝛔_unrot[2,1] = storage.bond_stress[4,i] -# 𝛔_unrot[2,2] = storage.bond_stress[5,i] -# 𝛔_unrot[2,3] = storage.bond_stress[6,i] -# 𝛔_unrot[3,1] = storage.bond_stress[7,i] -# 𝛔_unrot[3,2] = storage.bond_stress[8,i] -# 𝛔_unrot[3,3] = storage.bond_stress[9,i] -# tempVec = 𝛔_unrot * transpose(rot_tens) -# T = rot_tens * tempVec -# J = det(F) -# P = J * T * inv(F)' -# update_tensor!(storage.first_piola_kirchhoff, i, SMatrix{3,3,Float64,9}(P)) -# return P -# end - -# Working version!!! -# function nsc_force_density!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, -# params::NSCRPointParameters, P::SMatrix, i) -# (; bonds, volume) = system -# (; bond_active, gradient_weight) = storage -# for bond_id in each_bond_idx(system, i) -# bond = bonds[bond_id] -# j, L = bond.neighbor, bond.length -# Δxij = get_coordinates_diff(storage, i, j) -# l = norm(Δxij) -# ε = (l - L) / L -# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) -# if bond_active[bond_id] -# Ψ = get_vector(gradient_weight, bond_id) -# tij = P * Ψ -# update_add_b_int!(storage, i, tij .* volume[j]) -# update_add_b_int!(storage, j, -tij .* volume[i]) -# end -# end -# return nothing -# end - -# function nsc_force_density!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, -# params::NSCRPointParameters, i) -# (; bonds, volume) = system -# (; bond_active, gradient_weight, defgrad) = storage -# Fi = get_tensor(defgrad, i) -# too_much_damage!(storage, system, mat, Fi, i) && return nothing -# for bond_id in each_bond_idx(system, i) -# bond = bonds[bond_id] -# j, L = bond.neighbor, bond.length -# Δxij = get_coordinates_diff(storage, i, j) -# l = norm(Δxij) -# ε = (l - L) / L -# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) -# if bond_active[bond_id] -# Fj = get_tensor(defgrad, j) -# Fb = 0.5 * (Fi + Fj) -# ΔXij = get_coordinates_diff(system, i, j) -# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) -# Fij = Fb + ΔFij -# P = calc_first_piola_kirchhoff(storage, mat, params, Fij) -# Ψ = get_vector(gradient_weight, bond_id) -# tij = P * Ψ -# update_add_b_int!(storage, i, tij .* volume[j]) -# update_add_b_int!(storage, j, -tij .* volume[i]) -# end -# end -# return nothing -# end - -# function nsc_force_density!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, -# params::NSCRPointParameters, i) -# (; bonds, volume) = system -# (; bond_active, gradient_weight, defgrad, weighted_volume) = storage - -# Fi = get_tensor(defgrad, i) -# too_much_damage!(storage, system, mat, Fi, i) && return nothing - -# # Stress integral SI -# wi = weighted_volume[i] -# SI = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) -# for bond_id in each_bond_idx(system, i) -# bond = bonds[bond_id] -# j, L = bond.neighbor, bond.length -# ΔXij = get_coordinates_diff(system, i, j) -# Δxij = get_coordinates_diff(storage, i, j) -# l = norm(Δxij) -# ε = (l - L) / L -# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - -# if bond_active[bond_id] -# Fj = get_tensor(defgrad, j) -# Fb = 0.5 * (Fi + Fj) -# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) -# Fij = Fb + ΔFij -# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) -# update_tensor!(storage.first_piola_kirchhoff, bond_id, Pij) -# Tempij = I - (ΔXij * ΔXij') / (L * L) -# ωij = kernel(system, bond_id) -# wj = weighted_volume[j] -# ϕ = volume[j] * ωij * (0.5 / wi + 0.5 / wj) -# SI += ϕ * (Pij * Tempij) -# end -# end - -# for bond_id in each_bond_idx(system, i) -# if bond_active[bond_id] -# bond = bonds[bond_id] -# j, L = bond.neighbor, bond.length -# ΔXij = get_coordinates_diff(system, i, j) -# Pij = get_tensor(storage.first_piola_kirchhoff, bond_id) -# Φij = get_vector(gradient_weight, bond_id) -# ωij = kernel(system, bond_id) -# tij = ωij / (wi * L * L) * (Pij * ΔXij) + SI * Φij -# update_add_b_int!(storage, i, tij * volume[j]) -# update_add_b_int!(storage, j, -tij * volume[i]) -# end -# end -# return nothing -# end - -# NODALLY STABLIZIED VERSION!!! WORKING, BUT NOT SURE IF CORRECT! -# function nsc_force_density!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, -# params::NSCRPointParameters, P::SMatrix, i) -# (; bonds, volume) = system -# (; bond_active, gradient_weight, defgrad) = storage -# Fi = get_tensor(defgrad, i) -# too_much_damage!(storage, system, mat, Fi, i) && return nothing -# for bond_id in each_bond_idx(system, i) -# bond = bonds[bond_id] -# j, L = bond.neighbor, bond.length -# Δxij = get_coordinates_diff(storage, i, j) -# l = norm(Δxij) -# ε = (l - L) / L -# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) -# if bond_active[bond_id] -# ΔXij = get_coordinates_diff(system, i, j) -# Fj = get_tensor(defgrad, j) -# Fb = 0.5 * (Fi + Fj) -# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) -# Fij = Fb + ΔFij -# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) -# Ψ = get_vector(gradient_weight, bond_id) -# tij = (Pij * Ψ) / volume[j] -# update_add_b_int!(storage, i, tij .* volume[j]) -# update_add_b_int!(storage, j, -tij .* volume[i]) -# end -# end -# return nothing -# end - - -# PERIDIGM VERSION -# function nsc_force_density!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, -# params::NSCRPointParameters, P::SMatrix, i) -# (; bonds, volume) = system -# (; bond_active, gradient_weight, defgrad, weighted_volume) = storage -# Fi = get_tensor(defgrad, i) -# wi = weighted_volume[i] -# SI = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) -# for bond_id in each_bond_idx(system, i) -# bond = bonds[bond_id] -# j, L = bond.neighbor, bond.length -# ΔXij = get_coordinates_diff(system, i, j) -# Δxij = get_coordinates_diff(storage, i, j) -# l = norm(Δxij) -# ε = (l - L) / L -# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - -# Fj = get_tensor(defgrad, j) -# Fb = 0.5 * (Fi + Fj) -# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) -# Fij = Fb + ΔFij -# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) -# # update_tensor!(first_piola_kirchhoff, bond_id, Pij) -# # ΔPij = Pij - Pi -# Tempij = (I - ΔXij * ΔXij') / (L * L) -# ωij = influence_function(mat, params, L) * bond_active[bond_id] -# wj = weighted_volume[j] -# ϕ = volume[j] * ωij * (0.5 / wi + 0.5 / wj) -# SI += ϕ * (Pij * Tempij) -# end -# for bond_id in each_bond_idx(system, i) -# bond = bonds[bond_id] -# j, L = bond.neighbor, bond.length -# ΔXij = get_coordinates_diff(system, i, j) -# Δxij = get_coordinates_diff(storage, i, j) -# Fj = get_tensor(defgrad, j) -# Fb = 0.5 * (Fi + Fj) -# ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) -# Fij = Fb + ΔFij -# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) -# Φij = get_vector(gradient_weight, bond_id) -# ωij = influence_function(mat, params, L) * bond_active[bond_id] -# tij = (SI * Φij) / volume[j] + ωij / (wi * L * L) * (Pij * ΔXij) -# update_add_b_int!(storage, i, tij * volume[j]) -# update_add_b_int!(storage, j, -tij * volume[i]) -# end -# return nothing -# end - -# NODALLY STABLIZIED VERSION WRONG? -# function nsc_force_density!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, -# params::NSCRPointParameters, P::SMatrix, i) -# (; bonds, volume) = system -# (; bond_active, gradient_weight, defgrad, weighted_volume) = storage -# Fi = get_tensor(defgrad, i) -# Vi = volume[i] -# wi = weighted_volume[i] - -# for bond_id_j in each_bond_idx(system, i) -# bond_ij = bonds[bond_id_j] -# j, Lij = bond_ij.neighbor, bond_ij.length -# ΔXij = get_coordinates_diff(storage, i, j) -# Δxij = get_coordinates_diff(storage, i, j) -# lij = norm(Δxij) -# ε = (lij - Lij) / Lij -# stretch_based_failure!(storage, system, bond_ij, params, ε, i, bond_id_j) - -# ωij = influence_function(mat, params, Lij) -# Vj, wj = volume[j], weighted_volume[j] -# Ṽij = (Vi * Vj) / 2 * (ωij / wj + ωij / wi) -# Ψij = get_vector(gradient_weight, bond_id_j) -# Fj = get_tensor(defgrad, j) -# Fij = 0.5 * (Fi + Fj) -# Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) - -# Tcor = Ṽij * (Pij * ΔXij) / (Vj * Vi * Lij * Lij) - -# Tave = zero(SVector{3,Float64}) -# for bond_id_k in each_bond_idx(system, i) -# bond_ik = bonds[bond_id_k] -# k, Lik = bond_ik.neighbor, bond_ik.length -# ωik = influence_function(mat, params, Lik) -# Vk, wk = volume[k], weighted_volume[k] -# Ṽik = (Vi * Vk) / 2 * (ωik / wk + ωij / wi) -# Fk = get_tensor(defgrad, k) -# Fik = 0.5 * (Fi + Fk) -# Pik = calc_first_piola_kirchhoff(storage, mat, params, Fik) -# Tave += Ṽik * (Pik * Ψij) / (Vj * Vi) -# ΔXΔXΨ = (ΔXij * ΔXij') * Ψij -# Tcor -= Ṽik * (Pik * ΔXΔXΨ) / (Vj * Vi * Lik * Lik) -# end - -# T = Tave + Tcor -# update_add_b_int!(storage, i, T .* volume[j]) -# update_add_b_int!(storage, j, -T .* volume[i]) -# end -# return nothing -# end - - # Tcor2 = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) - # for bond_id in each_bond_idx(system, i) - # bond = bonds[bond_id] - # j, L = bond.neighbor, bond.length - # ΔXij = get_coordinates_diff(system, i, j) - # Δxij = get_coordinates_diff(storage, i, j) - # l = norm(Δxij) - # ε = (l - L) / L - # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - - # if bond_active[bond_id] - # ωij = influence_function(mat, params, L) - # Vj, wj = volume[j], weighted_volume[j] - # Ṽij = (Vi * Vj) / 2 * (ωij / wi + ωij / wj) - - # Fj = get_tensor(defgrad, j) - # Fb = 0.5 * (Fi + Fj) - # Pb = calc_first_piola_kirchhoff(storage, mat, params, Fb) - - # temp = Ṽij / (Vi * Vj * L * L) - # Ψ = get_vector(gradient_weight, bond_id) - # ΔXΨ = (ΔXij * ΔXij') * Ψ - # Tcor2 += temp * (P * ΔXΨ) - # end - # end - - # for bond_id in each_bond_idx(system, i) - # if bond_active[bond_id] - # bond = bonds[bond_id] - # j, L = bond.neighbor, bond.length - # ΔXij = get_coordinates_diff(system, i, j) - # Δxij = get_coordinates_diff(storage, i, j) - - # # update of force density - # Ψ = get_vector(gradient_weight, bond_id) - # tij = (P * Ψ) / volume[j] - # update_add_b_int!(storage, i, tij .* volume[j]) - # update_add_b_int!(storage, j, -tij .* volume[i]) - # end - # end -# return nothing -# end - -function too_much_damage!(storage::NSCRStorage, system::BondSystem, mat::NSCRMaterial, F, i) - if storage.damage[i] > mat.maxdmg || containsnan(F) - # kill all bonds of this point - storage.bond_active[each_bond_idx(system, i)] .= false - storage.n_active_bonds[i] = 0 - return true - end - return false -end diff --git a/src/physics/rk_correspondence.jl b/src/physics/rk_correspondence.jl deleted file mode 100644 index e765f564..00000000 --- a/src/physics/rk_correspondence.jl +++ /dev/null @@ -1,642 +0,0 @@ -""" - RKCMaterial(; maxdmg, zem) - -A material type used to assign the material of a [`Body`](@ref) with the local continuum -consistent (correspondence) formulation of non-ordinary state-based peridynamics. - -# Keywords -- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is - exceeded, all bonds of that point are broken because the deformation gradient would then - possibly contain `NaN` values. - (default: `0.95`) -- `zem::AbstractZEMStabilization`: zero-energy mode stabilization. The - stabilization algorithm of Silling (2017) is used as default. - (default: `ZEMSilling()`) - -!!! note "Stability of fracture simulations" - This formulation is known to be not suitable for fracture simultations without - stabilization of the zero-energy modes. Therefore be careful when doing fracture - simulations and try out different parameters for `maxdmg` and `zem`. - -# Examples - -```julia-repl -julia> mat = RKCMaterial() -RKCMaterial(maxdmg=0.95, zem_fac=ZEMSilling()) -``` - ---- - -```julia -RKCMaterial -``` - -Material type for the local continuum consistent (correspondence) formulation of -non-ordinary state-based peridynamics. - -# Fields -- `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. See the - constructor docs for more informations. -- `zem_fac::Float64`: Correction factor used for zero-energy mode stabilization. See the - constructor docs for more informations. - -# Allowed material parameters -When using [`material!`](@ref) on a [`Body`](@ref) with `RKCMaterial`, then the following -parameters are allowed: -- `horizon::Float64`: Radius of point interactions -- `rho::Float64`: Density -- `E::Float64`: Young's modulus -- `nu::Float64`: Poisson's ratio -- `Gc::Float64`: Critical energy release rate -- `epsilon_c::Float64`: Critical strain - -# Allowed export fields -When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with -`RKCMaterial`, the following fields are allowed: -- `position::Matrix{Float64}`: Position of each point -- `displacement::Matrix{Float64}`: Displacement of each point -- `velocity::Matrix{Float64}`: Velocity of each point -- `velocity_half::Matrix{Float64}`: Velocity parameter for Verlet time solver -- `acceleration::Matrix{Float64}`: Acceleration of each point -- `b_int::Matrix{Float64}`: Internal force density of each point -- `b_ext::Matrix{Float64}`: External force density of each point -- `damage::Vector{Float64}`: Damage of each point -- `n_active_bonds::Vector{Int}`: Number of intact bonds of each point -""" -struct RKCMaterial{CM,K} <: AbstractCorrespondenceMaterial{CM,NoCorrection} - kernel::K - constitutive_model::CM - maxdmg::Float64 - accuracy_order::Int - function RKCMaterial(kernel::K, cm::CM, maxdmg::Real, accuracy_order::Int) where {CM,K} - return new{CM,K}(kernel, cm, maxdmg, accuracy_order) - end -end - -function Base.show(io::IO, @nospecialize(mat::RKCMaterial)) - print(io, typeof(mat)) - print(io, msg_fields_in_brackets(mat, (:maxdmg,))) - return nothing -end - -function RKCMaterial(; kernel::Function=cubic_b_spline, - model::AbstractConstitutiveModel=SaintVenantKirchhoff(), - maxdmg::Real=0.85, accuracy_order::Int=2) - return RKCMaterial(kernel, model, maxdmg, accuracy_order) -end - -struct RKCPointParameters <: AbstractPointParameters - δ::Float64 - rho::Float64 - E::Float64 - nu::Float64 - G::Float64 - K::Float64 - λ::Float64 - μ::Float64 - Gc::Float64 - εc::Float64 - bc::Float64 -end - -function RKCPointParameters(mat::RKCMaterial, p::Dict{Symbol,Any}) - (; δ, rho, E, nu, G, K, λ, μ) = get_required_point_parameters(mat, p) - (; Gc, εc) = get_frac_params(p, δ, K) - bc = 18 * K / (π * δ^4) # bond constant - return RKCPointParameters(δ, rho, E, nu, G, K, λ, μ, Gc, εc, bc) -end - -@params RKCMaterial RKCPointParameters - -@storage RKCMaterial struct RKCStorage - @lthfield position::Matrix{Float64} - @pointfield displacement::Matrix{Float64} - @pointfield velocity::Matrix{Float64} - @pointfield velocity_half::Matrix{Float64} - @pointfield velocity_half_old::Matrix{Float64} - @pointfield acceleration::Matrix{Float64} - @htlfield b_int::Matrix{Float64} - @pointfield b_int_old::Matrix{Float64} - @pointfield b_ext::Matrix{Float64} - @pointfield density_matrix::Matrix{Float64} - @pointfield damage::Vector{Float64} - bond_active::Vector{Bool} - @pointfield n_active_bonds::Vector{Int} - @pointfield damage_changed::Vector{Bool} - @pointfield pk1::Matrix{Float64} - # @pointfield stress::Matrix{Float64} - # @pointfield von_mises_stress::Vector{Float64} - @lthfield defgrad::Matrix{Float64} - @lthfield weighted_volume::Vector{Float64} - gradient_weight::Matrix{Float64} - first_piola_kirchhoff::Matrix{Float64} -end - -# function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, -# ::Val{:displacement}) -# return zeros(3, get_n_points(system)) -# end - -function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:b_int}) - return zeros(3, get_n_points(system)) -end - -function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:damage_changed}) - return ones(Bool, get_n_loc_points(system)) -end - -function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, ::Val{:pk1}) - return zeros(9, get_n_loc_points(system)) -end - -# function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, -# ::Val{:von_mises_stress}) -# return zeros(get_n_loc_points(system)) -# end - -function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:defgrad}) - return zeros(9, get_n_points(system)) -end - -function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:weighted_volume}) - return zeros(get_n_points(system)) -end - -function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:gradient_weight}) - return zeros(3, get_n_bonds(system)) -end - -function init_field(::RKCMaterial, ::AbstractTimeSolver, system::BondSystem, - ::Val{:first_piola_kirchhoff}) - return zeros(9, get_n_bonds(system)) -end - -function initialize!(chunk::BodyChunk{<:BondSystem,<:RKCMaterial}) - chunk.storage.damage_changed .= true - return nothing -end - -# @inline function calc_damage!(chunk::BodyChunk{<:BondSystem,<:RKCMaterial}) -# (; n_neighbors) = chunk.system -# (; n_active_bonds, damage, damage_changed) = chunk.storage -# for point_id in each_point_idx(chunk) -# old_damage = damage[point_id] -# new_damage = 1 - n_active_bonds[point_id] / n_neighbors[point_id] -# if new_damage > old_damage -# damage_changed[point_id] = true -# else -# damage_changed[point_id] = false -# end -# damage[point_id] = new_damage -# end -# return nothing -# end - -@inline function calc_damage!(chunk::BodyChunk{<:BondSystem,<:RKCMaterial}) - (; system, storage, paramsetup) = chunk - (; n_neighbors, bonds) = system - (; n_active_bonds, damage, damage_changed) = storage - for i in each_point_idx(chunk) - # params = get_params(paramsetup, i) - # for bond_id in each_bond_idx(system, i) - # bond = bonds[bond_id] - # j, L = bond.neighbor, bond.length - # Δxij = get_coordinates_diff(storage, i, j) - # l = norm(Δxij) - # ε = (l - L) / L - # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - # end - old_damage = damage[i] - new_damage = 1 - n_active_bonds[i] / n_neighbors[i] - if new_damage > old_damage - damage_changed[i] = true - else - damage_changed[i] = false - end - damage[i] = new_damage - end - return nothing -end - -function calc_force_density!(dh::ThreadsBodyDataHandler{<:BondSystem,<:RKCMaterial}, t, Δt) - @threads :static for chunk_id in eachindex(dh.chunks) - exchange_loc_to_halo!(dh, chunk_id, :position) - end - @threads :static for chunk_id in eachindex(dh.chunks) - calc_weights_and_defgrad!(dh.chunks[chunk_id], t, Δt) - end - @threads :static for chunk_id in eachindex(dh.chunks) - exchange_loc_to_halo!(dh, chunk_id, (:defgrad, :weighted_volume)) - end - @threads :static for chunk_id in eachindex(dh.chunks) - chunk = dh.chunks[chunk_id] - calc_force_density!(chunk, t, Δt) - nancheck(chunk, t) - end - @threads :static for chunk_id in eachindex(dh.chunks) - exchange_halo_to_loc!(dh, chunk_id) - end - return nothing -end - -function calc_force_density!(dh::MPIBodyDataHandler{<:BondSystem,<:RKCMaterial}, t, Δt) - (; chunk) = dh - exchange_loc_to_halo!(dh, (:position,)) - calc_weights_and_defgrad!(chunk, t, Δt) - exchange_loc_to_halo!(dh, (:defgrad, :weighted_volume)) - calc_force_density!(chunk, t, Δt) - nancheck(chunk, t) - exchange_halo_to_loc!(dh) - return nothing -end - -function calc_weights_and_defgrad!(chunk::BodyChunk{<:BondSystem,<:RKCMaterial}, t, Δt) - (; system, mat, paramsetup, storage) = chunk - calc_gradient_weights!(storage, system, mat, paramsetup) - calc_deformation_gradients!(storage, system, mat, paramsetup, t, Δt) - return nothing -end - -function calc_gradient_weights!(storage::RKCStorage, system::BondSystem, mat::RKCMaterial, - paramsetup::AbstractParameterSetup) - (; bonds, volume) = system - (; bond_active, gradient_weight, damage_changed, weighted_volume) = storage - (; accuracy_order) = mat - q_dim = get_q_dim(accuracy_order) - - Q∇ᵀ = get_q_triangle(accuracy_order) - - for i in each_point_idx(system) - if damage_changed[i] - params = get_params(paramsetup, i) - (; δ) = params - - # calculate moment matrix M - M = zero(SMatrix{q_dim,q_dim,Float64,q_dim*q_dim}) - wi = 0.0 - for bond_id in each_bond_idx(system, i) - bond = bonds[bond_id] - j = bond.neighbor - ΔXij = get_diff(system.position, i, j) - Q = get_monomial_vector(accuracy_order, ΔXij, δ) - ωij = kernel(system, bond_id) #* bond_active[bond_id] - temp = ωij * volume[j] - M += temp * (Q * Q') - wi += temp - end - weighted_volume[i] = wi - - # calculate inverse of moment matrix, must be a full rank matrix! - threshold = 1e-6 * δ * δ * δ - Minv = invreg(M, threshold) - - # calculate gradient weights Φ - for bond_id in each_bond_idx(system, i) - bond = bonds[bond_id] - j = bond.neighbor - ΔXij = get_diff(system.position, i, j) - Q = get_monomial_vector(accuracy_order, ΔXij, δ) - ωij = kernel(system, bond_id) * bond_active[bond_id] - temp = ωij / δ * volume[j] - MinvQ = Minv * Q - Φ = temp * (Q∇ᵀ * MinvQ) - #--- - # Φ1 = 0.0 - # Φ2 = 0.0 - # Φ3 = 0.0 - # for m in 1:q_dim - # Φ1 += temp * Minv[1, m] * Q[m] - # Φ2 += temp * Minv[2, m] * Q[m] - # Φ3 += temp * Minv[3, m] * Q[m] - # end - # Φm = SVector{3,Float64}(Φ1, Φ2, Φ3) - # @assert isapprox(Φ, Φm) - # @show Φ, Φm - #--- - update_vector!(gradient_weight, bond_id, Φ) - end - end - end - - return nothing -end - -@inline each_monomial(N::Int) = each_monomial(Val(N)) - -@inline function each_monomial(::Val{N}) where {N} - monomials = Tuple((p1,p2,p3) for i in 1:N - for p1 in i:-1:0 - for p2 in (i - p1):-1:0 - for p3 in i - p1 - p2) - return monomials -end - -@inline function each_monomial(::Val{1}) - return ((1, 0, 0), (0, 1, 0), (0, 0, 1)) -end - -@inline function each_monomial(::Val{2}) - return ((1, 0, 0), (0, 1, 0), (0, 0, 1), (2, 0, 0), (1, 1, 0), (1, 0, 1), (0, 2, 0), - (0, 1, 1), (0, 0, 2)) -end - -@inline get_q_dim(accuracy_order) = length(each_monomial(accuracy_order)) - -@inline function get_monomial_vector(N::Int, ΔX::AbstractArray, δ::Real) - return get_monomial_vector(Val(N), ΔX, δ) -end - -@inline function get_monomial_vector(n::Val{N}, ΔX::AbstractArray, δ::Real) where {N} - a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ - _Q = (a1^p1 * a2^p2 * a3^p3 for (p1, p2, p3) in each_monomial(n)) - q_dims = get_q_dim(n) - Q = SVector{q_dims,eltype(ΔX)}(_Q...) - return Q -end - -@inline function get_monomial_vector(::Val{1}, ΔX::AbstractArray, δ::Real) - a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ - Q = SVector{3,eltype(ΔX)}(a1, a2, a3) - return Q -end - -@inline function get_monomial_vector(::Val{2}, ΔX::AbstractArray, δ::Real) - a1, a2, a3 = ΔX[1] / δ, ΔX[2] / δ, ΔX[3] / δ - Q = SVector{9,eltype(ΔX)}(a1, a2, a3, a1*a1, a1*a2, a1*a3, a2*a2, a2*a3, a3*a3) - return Q -end - -@inline get_q_triangle(N::Int) = get_q_triangle(Val(N)) - -function get_q_triangle(::Val{1}) - Q∇ᵀ = SMatrix{3,3,Int,9}(1, 0, 0, - 0, 1, 0, - 0, 0, 1) - return Q∇ᵀ -end - -function get_q_triangle(::Val{2}) - Q∇ᵀ = SMatrix{3,9,Int,27}(1, 0, 0, - 0, 1, 0, - 0, 0, 1, - 0, 0, 0, - 0, 0, 0, - 0, 0, 0, - 0, 0, 0, - 0, 0, 0, - 0, 0, 0) - return Q∇ᵀ -end - -function get_q_triangle(::Val{N}) where {N} - msg = "RK kernel only implemented for `accuracy_order ∈ {1,2}`!\n" - return throw(ArgumentError(msg)) -end - -# function invert_moment_matrix(M::StaticMatrix{N,N,T}, threshold::Real) where {N,T} -# U, S, V = svd(M) -# Sinvreg = SVector{N,T}((s > threshold ? 1/s : 0) for s in S) -# Sinv = Diagonal{T,SVector{N,T}}(Sinvreg) -# Minv = V * Sinv * U' -# return Minv -# end - -function calc_deformation_gradients!(storage::RKCStorage, system::BondSystem, ::RKCMaterial, - ::AbstractParameterSetup, t, Δt) - (; bonds, volume) = system - (; gradient_weight, defgrad, bond_active) = storage - - for i in each_point_idx(system) - F = SMatrix{3,3,Float64,9}(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) - for bond_id in each_bond_idx(system, i) - # if bond_active[bond_id] - bond = bonds[bond_id] - j = bond.neighbor - ΔXij = get_vector_diff(system.position, i, j) - Δxij = get_vector_diff(storage.position, i, j) - ΔUij = Δxij - ΔXij - Φij = get_vector(gradient_weight, bond_id) - F += (ΔUij * Φij') * volume[j] - # end - end - update_tensor!(defgrad, i, F) - end - - return nothing -end - -function force_density_point!(storage::RKCStorage, system::BondSystem, mat::RKCMaterial, - paramhandler::AbstractParameterHandler, t, Δt, i) - params = get_params(paramhandler, i) - force_density_point!(storage, system, mat, params, t, Δt, i) - return nothing -end - -function force_density_point!(storage::RKCStorage, system::BondSystem, mat::RKCMaterial, - params::RKCPointParameters, t, Δt, i) - # (; bonds, volume) = system - # (; gradient_weight, defgrad, bond_active, weighted_volume) = storage - # (; first_piola_kirchhoff) = storage - # Fi = get_tensor(defgrad, i) - # too_much_damage!(storage, system, mat, Fi, i) && return nothing - # Pi = calc_first_piola_kirchhoff(storage, mat, params, Fi) - - # Standard RK - # for bond_id in each_bond_idx(system, i) - # bond = bonds[bond_id] - # j, L = bond.neighbor, bond.length - # Δxij = get_coordinates_diff(storage, i, j) - # l = norm(Δxij) - # ε = (l - L) / L - # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - - # if bond_active[bond_id] - # Fj = get_tensor(defgrad, j) - # Fb = 0.5 * (Fi + Fj) - # ΔXij = get_coordinates_diff(system, i, j) - # ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) - # Fij = Fb + ΔFij - # Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) - # Φij = get_vector(gradient_weight, bond_id) - # tij = Pij * Φij - # update_add_b_int!(storage, i, tij * volume[j]) - # update_add_b_int!(storage, j, -tij * volume[i]) - # end - # end - - # BA-Stabilized RK - # for bond_id in each_bond_idx(system, i) - # bond = bonds[bond_id] - # j, L = bond.neighbor, bond.length - # ΔXij = get_coordinates_diff(system, i, j) - # Δxij = get_coordinates_diff(storage, i, j) - # l = norm(Δxij) - # ε = (l - L) / L - # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - - # Φij = get_vector(gradient_weight, bond_id) - # Fj = get_tensor(defgrad, j) - # Fb = 0.5 * (Fi + Fj) - # ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) - # Fij = Fj + ΔFij - # Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) * bond_active[bond_id] - # tij = (Pij * Φij) - # update_add_b_int!(storage, i, tij * volume[j]) - # update_add_b_int!(storage, j, -(Pi * Φij) * volume[i]) - # end - - # Nodal quadrature peridigm - # (; bonds, volume) = system - # (; bond_active, gradient_weight, defgrad, weighted_volume) = storage - - # Fi = get_tensor(defgrad, i) - # # too_much_damage!(storage, system, mat, Fi, i) && return nothing - - # # Stress integral - # wi = weighted_volume[i] - # ∑P = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) - # for bond_id in each_bond_idx(system, i) - # bond = bonds[bond_id] - # j, L = bond.neighbor, bond.length - # ΔXij = get_coordinates_diff(system, i, j) - # Δxij = get_coordinates_diff(storage, i, j) - # l = norm(Δxij) - # ε = (l - L) / L - # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - - # if bond_active[bond_id] - # Fj = get_tensor(defgrad, j) - # Fb = 0.5 * (Fi + Fj) - # ΔXijLL = ΔXij' / (L * L) - # ΔFij = (Δxij - Fb * ΔXij) * ΔXijLL - # Fij = Fb + ΔFij - # Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) - # update_tensor!(storage.first_piola_kirchhoff, bond_id, Pij) - # Tempij = I - ΔXij * ΔXijLL - # # ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) - # wj = weighted_volume[j] - # ϕ = (wi > 0 && wj > 0) ? (0.5 / wi + 0.5 / wj) : 0.0 - # ω̃ij = kernel(system, bond_id) * ϕ - # ∑Pij = ω̃ij * (Pij * Tempij) - # ∑P += ∑Pij - # end - # end - - # for bond_id in each_bond_idx(system, i) - # if bond_active[bond_id] - # bond = bonds[bond_id] - # j, L = bond.neighbor, bond.length - # ΔXij = get_coordinates_diff(system, i, j) - # Pij = get_tensor(storage.first_piola_kirchhoff, bond_id) - # Φij = get_vector(gradient_weight, bond_id) - # # ω̃ij = kernel(system, bond_id) * (0.5 / wi + 0.5 / weighted_volume[j]) - # wj = weighted_volume[j] - # ϕ = (wi > 0 && wj > 0) ? (0.5 / wi + 0.5 / wj) : 0.0 - # ω̃ij = kernel(system, bond_id) * ϕ - # tij = ω̃ij / (L * L) * (Pij * ΔXij) + ∑P * Φij - # update_add_b_int!(storage, i, tij * volume[j]) - # update_add_b_int!(storage, j, -tij * volume[i]) - # end - # end - # return nothing - - - ## My understanding of the equations - # wi = weighted_volume[i] - # Vi = volume[i] - # ∑ωPV = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) - # ∑ωPcorr = SMatrix{3,3,Float64,9}(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) - # for bond_id in each_bond_idx(system, i) - # bond = bonds[bond_id] - # j, L = bond.neighbor, bond.length - # Δxij = get_coordinates_diff(storage, i, j) - # l = norm(Δxij) - # ε = (l - L) / L - # stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - - # if bond_active[bond_id] - # Vj = volume[j] - # ΔXij = get_coordinates_diff(system, i, j) - # Fj = get_tensor(defgrad, j) - # Fb = 0.5 * (Fi + Fj) - # ΔFij = (Δxij - Fb * ΔXij) * ΔXij' / (L * L) - # Fij = Fb + ΔFij - # Pij = calc_first_piola_kirchhoff(storage, mat, params, Fij) - # update_tensor!(first_piola_kirchhoff, bond_id, Pij) - - # ωij = kernel(system, bond_id) - # ωPV = ωij * Pij * Vj - # ∑ωPV += ωPV - # ∑ωPcorr += ωPV * (ΔXij * ΔXij') / (L * L) - # # wj = weighted_volume[j] - # # ϕ = volume[j] * ωij * (0.5 / wi + 0.5 / wj) - # # SI += ϕ * (Pij * Tempij) - # end - # end - - ### my newest approach - (; bonds, volume) = system - (; gradient_weight, defgrad, bond_active, weighted_volume) = storage - Fi = get_tensor(defgrad, i) - Pi = calc_first_piola_kirchhoff(storage, mat, params, Fi) - - for bond_id in each_bond_idx(system, i) - bond = bonds[bond_id] - j = bond.neighbor - # if bond_active[bond_id] - Fj = get_tensor(defgrad, j) - Pj = calc_first_piola_kirchhoff(storage, mat, params, Fj) - Φij = get_vector(gradient_weight, bond_id) - tij = (Pj - Pi) * Φij - # tij = Pi * Φij - update_add_b_int!(storage, i, tij * volume[j]) - update_add_b_int!(storage, j, -tij * volume[i]) - # end - end - - return nothing -end - -function calc_first_piola_kirchhoff(storage::RKCStorage, mat::RKCMaterial, - params::RKCPointParameters, F) - P = first_piola_kirchhoff(mat.constitutive_model, storage, params, F) - return P -end - -# function rkc_force_density!(storage::RKCStorage, system::BondSystem, mat::RKCMaterial, -# params::RKCPointParameters, PKinv::SMatrix, i) -# (; bonds, volume) = system -# (; bond_active) = storage -# for bond_id in each_bond_idx(system, i) -# bond = bonds[bond_id] -# j, L = bond.neighbor, bond.length -# ΔXij = get_coordinates_diff(system, i, j) -# Δxij = get_coordinates_diff(storage, i, j) -# l = norm(Δxij) -# ε = (l - L) / L -# stretch_based_failure!(storage, system, bond, params, ε, i, bond_id) - -# # stabilization -# ωij = influence_function(mat, params, L) * bond_active[bond_id] - -# # update of force density -# tij = ωij * PKinv * ΔXij -# update_add_b_int!(storage, i, tij .* volume[j]) -# update_add_b_int!(storage, j, -tij .* volume[i]) -# end -# return nothing -# end - -function too_much_damage!(storage::RKCStorage, system::BondSystem, mat::RKCMaterial, F, i) - if storage.damage[i] > mat.maxdmg || containsnan(F) - # kill all bonds of this point - storage.bond_active[each_bond_idx(system, i)] .= false - storage.n_active_bonds[i] = 0 - return true - end - return false -end diff --git a/src/time_solvers/velocity_verlet.jl b/src/time_solvers/velocity_verlet.jl index fa7cc870..edaf4253 100644 --- a/src/time_solvers/velocity_verlet.jl +++ b/src/time_solvers/velocity_verlet.jl @@ -207,7 +207,6 @@ function verlet_timestep!(dh::AbstractThreadsMultibodyDataHandler, update_vel_half!(chunk, Δt½) apply_boundary_conditions!(chunk, t) update_disp_and_pos!(chunk, Δt) - calc_damage!(chunk) end end calc_force_density!(dh, t, Δt) @@ -215,11 +214,10 @@ function verlet_timestep!(dh::AbstractThreadsMultibodyDataHandler, calc_contact_force_densities!(dh) for body_idx in each_body_idx(dh) body_dh = get_body_dh(dh, body_idx) - # body_name = get_body_name(dh, body_idx) @threads :static for chunk_id in eachindex(body_dh.chunks) exchange_halo_to_loc!(body_dh, chunk_id) chunk = body_dh.chunks[chunk_id] - # calc_damage!(chunk) + calc_damage!(chunk) update_acc_and_vel!(chunk, Δt½) export_results(body_dh, options, chunk_id, n, t) end diff --git a/test/integration/b_int_correspondence.jl b/test/integration/b_int_correspondence.jl index b18f966b..d607cfb4 100644 --- a/test/integration/b_int_correspondence.jl +++ b/test/integration/b_int_correspondence.jl @@ -4,7 +4,7 @@ 0.0 0.0 0.0 1.0 2.0] volume = fill(1.0, 5) δ = 1.5 - body = Body(CMaterial(), ref_position, volume) + body = Body(CMaterial(model=NeoHookeNonlinear()), ref_position, volume) material!(body, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) failure_permit!(body, false) @@ -36,7 +36,7 @@ end 0.0 0.0 0.0 1.0 2.0] volume = fill(1.0, 5) δ = 1.5 - body = Body(CMaterial(), ref_position, volume) + body = Body(CMaterial(model=NeoHookeNonlinear()), ref_position, volume) point_set!(body, :a, [1]) point_set!(body, :b, [2,3,4,5]) material!(body, :a, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) diff --git a/test/integration/b_int_rk_correspondence.jl b/test/integration/b_int_rk_correspondence.jl deleted file mode 100644 index 51173b28..00000000 --- a/test/integration/b_int_rk_correspondence.jl +++ /dev/null @@ -1,44 +0,0 @@ -@testitem "Internal force density rk-correspondence" begin - # using Peridynamics, Test - ref_position = [0.0 1.0 0.0 - 0.0 0.0 1.0 - 0.0 0.0 0.0] - # ref_position = [0.0 1.0 0.0 0.0 2.0 - # 0.0 0.0 1.0 0.0 2.0 - # 0.0 0.0 0.0 1.0 2.0] - volume = fill(1.0, 3) - δ = 1.5 - body = Body(RKCMaterial(), ref_position, volume) - material!(body, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) - failure_permit!(body, false) - - dh = Peridynamics.threads_data_handler(body, VelocityVerlet(steps=1), 2) - chunk1 = dh.chunks[1] - (; mat, storage, system, paramsetup) = chunk1 - params = paramsetup - (; position) = storage - position[1, 1] = -0.0015 - - # chunk = dh.chunks[2] - # (; mat, storage, system, paramsetup) = chunk - # params = paramsetup - # (; position, b_int, defgrad) = storage - # # position[1, 3] = 1.0015 - - # @test position == ref_position - # @test b_int == zeros(3, 5) - - # # Boundary Condition: - # # Point 2 with v_z = 1 m/s with Δt = 0.0015 s - # position[1, 2] = 1.0015 - - # Peridynamics.calc_force_density!(dh, 0, 0) - - # @test defgrad ≈ 0 - - # @test b_int[:,1] ≈ [0.007185432432164514, 0.0023974081843325646, 0.0023974081843347313] - # @test b_int[:,2] ≈ [-0.007185432432123352, -9.047513544240966e-15, -6.0453612662025915e-15] - # @test b_int[:,3] ≈ [-2.077199268438824e-14, -0.002397408184361381, 3.2228109102914035e-14] - # @test b_int[:,4] ≈ [-2.0389697546832128e-14, 3.786380931014577e-14, -0.002397408184360914] - # @test b_int[:,5] ≈ [0.0, 0.0, 0.0] -end diff --git a/test/integration/mpi_threads_comparison.jl b/test/integration/mpi_threads_comparison.jl index 4e670842..7821a20d 100644 --- a/test/integration/mpi_threads_comparison.jl +++ b/test/integration/mpi_threads_comparison.jl @@ -132,7 +132,7 @@ end Δe = maximum(abs.(res_threads_qty .- res_mpi_qty)) #TODO: why is this error so high? # See also: https://github.com/kaipartmann/Peridynamics.jl/issues/187 - @test Δe < 0.02 + @test Δe < 0.03 end end diff --git a/test/integration/symmetry_correspondence.jl b/test/integration/symmetry_correspondence.jl index 5f0cffec..342e8da7 100644 --- a/test/integration/symmetry_correspondence.jl +++ b/test/integration/symmetry_correspondence.jl @@ -8,13 +8,13 @@ pos = hcat(([x;y;z] for x in grid for y in grid for z in grid)...) n_points = size(pos, 2) vol = fill(Δx^3, n_points) - body = Body(CMaterial(), pos, vol) + body = Body(CMaterial(model=NeoHookeNonlinear()), pos, vol) failure_permit!(body, false) material!(body, horizon=3.015Δx, rho=7850, E=210e9, nu=0.25, Gc=1) point_set!(z -> z > width/2 - 0.6Δx, body, :set_a) point_set!(z -> z < -width/2 + 0.6Δx, body, :set_b) - velocity_bc!(t -> 100, body, :set_a, :z) - velocity_bc!(t -> -100, body, :set_b, :z) + velocity_bc!(t -> 10, body, :set_a, :z) + velocity_bc!(t -> -10, body, :set_b, :z) vv = VelocityVerlet(steps=100) temp_root = joinpath(@__DIR__, "temp_root_symmetry_test_cc_vv") rm(temp_root; recursive=true, force=true) diff --git a/test/physics/test_rk_correspondence.jl b/test/physics/test_rk_correspondence.jl deleted file mode 100644 index a71988fb..00000000 --- a/test/physics/test_rk_correspondence.jl +++ /dev/null @@ -1,352 +0,0 @@ -# Write a unit test for the qmatrix calculation of the RKMaterial -@testitem "Monomial vector Q" begin - using Peridynamics.StaticArrays - - # CPP code as reference: - # // calculate dimension of Q vector - # Qdim = 0; - # for(thisOrder=1; thisOrder<=accuracyOrder; thisOrder++){ - # for(p1=thisOrder; p1>=0; p1--){ // x-power - # for(p2=thisOrder-p1; p2>=0; p2--){ // y-power - # p3=thisOrder-p1-p2; //z-power - # Qdim++; - # } - # } - # } - # // Calculate Q for this bond - # counter = 0; - # for(thisOrder=1; thisOrder<=accuracyOrder; thisOrder++){ - # for(p1=thisOrder; p1>=0; p1--){ // x-power - # for(p2=thisOrder-p1; p2>=0; p2--){ // y-power - # p3=thisOrder-p1-p2; //z-power - - # Q[counter] = 1.0; - # for(i=0; i δ, :rho => 1, :E => 1, :nu => 0.25, :Gc => 1.0) - params = Peridynamics.RKCPointParameters(mat, kwargs) - - L = 0.0 - ω_a = 0.0 - @test Peridynamics.get_kernel(mat, params, L) ≈ ω_a - - L = 1/4 - ω_a = 2/3 - 4 * (L/δ)^2 + 4 * (L/δ)^3 - @test Peridynamics.get_kernel(mat, params, L) ≈ ω_a - - L = 1/2 - ω_a = 2/3 - 4 * (L/δ)^2 + 4 * (L/δ)^3 - @test Peridynamics.get_kernel(mat, params, L) ≈ ω_a - - L = 3/4 - ω_a = 4/3 - 4 * (L/δ) + 4 * (L/δ)^2 - 4/3 * (L/δ)^3 - @test Peridynamics.get_kernel(mat, params, L) ≈ ω_a - - L = 1 - ω_a = 4/3 - 4 * (L/δ) + 4 * (L/δ)^2 - 4/3 * (L/δ)^3 - @test Peridynamics.get_kernel(mat, params, L) ≈ ω_a - - @test Peridynamics.get_kernel(mat, params, 1.5) ≈ 0.0 - @test Peridynamics.get_kernel(mat, params, -1.0) ≈ 0.0 -end - -@testitem "Gradient weights Φ" begin - using Peridynamics, Test - using Peridynamics: get_diff, get_monomial_vector, each_bond_idx, influence_function, - threads_data_handler, Bond - using Peridynamics.StaticArrays - # setup - ref_position = [0.0 1.0 0.0 - 0.0 0.0 1.0 - 0.0 0.0 0.0] - volume = fill(1.0, 3) - δ = 1.5 - mat = RKCMaterial() - body = Body(mat, ref_position, volume) - material!(body, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) - failure_permit!(body, false) - dh = threads_data_handler(body, VelocityVerlet(steps=1), 1) - chunk = dh.chunks[1] - (; mat, storage, system, paramsetup) = chunk - - @test system.bonds == [ - Bond(2, 1.0, false), # point 1 - Bond(3, 1.0, false), - Bond(1, 1.0, false), # point 2 - Bond(3, √2, false), - Bond(1, 1.0, false), # point 3 - Bond(2, √2, false), - ] - - @test storage.gradient_weight == zeros(3, 6) - - Peridynamics.calc_gradient_weights!(storage, system, mat, paramsetup) - - # my old version with temp = ωij * volume[j] - # Φ = storage.gradient_weight - # @test Φ[:,1] ≈ [0.5000000000000001, 0.0, 0.0] - # @test Φ[:,2] ≈ [0.0, 0.5000000000000001, 0.0] - # @test Φ[:,3] ≈ [-0.5000000000000004, -0.3333333333333337, 0.0] - # @test Φ[:,4] ≈ [-3.469446951953614e-18, 0.33333333333333365, 0.0] - # @test Φ[:,5] ≈ [-0.33333333333333054, -0.5000000000000009, 0.0] - # @test Φ[:,6] ≈ [0.3333333333333338, 7.728193085476676e-16, 0.0] - - # PeriLab version temp = ωij / δ - # Φ = storage.gradient_weight - # @test Φ[:,1] ≈ [0.0006958021262525432, 0.0, 0.0] - # @test Φ[:,2] ≈ [0.0, 0.0006958021262525432, 0.0] - # @test Φ[:,3] ≈ [-0.0006993163680475011, 3.5142417949579743e-6, 0.0] - # @test Φ[:,4] ≈ [-3.5552013688439347e-6, 4.095957388592146e-8, 0.0] - # @test Φ[:,5] ≈ [3.514241794958013e-6, -0.0006993163680475009, 0.0] - # @test Φ[:,6] ≈ [4.095957388592165e-8, -3.555201368843933e-6, 0.0] - - #= - using BenchmarkTools - @btime Peridynamics.calc_gradient_weights!($storage, $system, $mat, $paramsetup) - =# - - # storage.position[:, 1] += [-0.001, -0.001, -0.001] - # storage.position[:, 2] += [0.001, 0.0, 0.0] - # storage.position[:, 3] += [0.0, 0.001, 0.0] - - # F = storage.defgrad - # @test F == zeros(9, 3) - - # Peridynamics.calc_deformation_gradients!(storage, system, mat, paramsetup, 0.0, 0.0) - - # my old version - # @test F[:, 1] ≈ [1.0000013916042525, 6.958021262525431e-7, 0.0, - # 6.958021262525431e-7, 1.0000013916042525, 0.0, - # 6.958021262525431e-7, 6.958021262525431e-7, 1.0] - # @test F[:, 2] ≈ [1.0000014021879375, -7.069443163801091e-9, 0.0, - # 6.957611666786575e-7, 0.9999999965267178, 0.0, - # 6.993163680475011e-7, -3.514241794957974e-9, 1.0] - # @test F[:, 3] ≈ [0.9999999965267178, 6.957611666786573e-7, 0.0, - # -7.069443163801169e-9, 1.0000014021879375, 0.0, - # -3.514241794958013e-9, 6.993163680475009e-7, 1.0] - - # PeriLab version - # @test F[:, 1] ≈ [1.0000013916042525, 6.958021262525431e-7, 6.958021262525431e-7, - # 6.958021262525431e-7, 1.0000013916042525, 6.958021262525431e-7, - # 0.0, 0.0, 1.0] - # @test F[:, 2] ≈ [1.0000014021879375, 6.957611666786575e-7, 6.993163680475011e-7, - # -7.069443163801091e-9, 0.9999999965267178, -3.514241794957974e-9, - # 0.0, 0.0, 1.0] - # @test F[:, 3] ≈ [0.9999999965267178, -7.069443163801169e-9, -3.514241794958013e-9, - # 6.957611666786573e-7, 1.0000014021879375, 6.993163680475009e-7, - # 0.0, 0.0, 1.0] - - - #= - using BenchmarkTools - @btime Peridynamics.calc_deformation_gradients!($storage, $system, $mat, $paramsetup, $0.0, $0.0) - =# - - - #--- My own testing - - # ξ12 = 1/1.5 - # ω12 = ω13 = 4/3 - 4 * ξ12 + 4 * ξ12^2 - 4/3 * ξ12^3 - # ΔX12 = SVector{3}([1.0, 0.0, 0.0]) - # ΔX13 = SVector{3}([0.0, 1.0, 0.0]) - # Q12 = SVector{9}([1.0, 0.0, 0.0, 1, 0.0, 0.0, 0.0, 0.0, 0.0]) - # # Q12 = copy(ΔX12) - # Q13 = SVector{9}([0.0, 1.0, 0.0, 0.0, 1, 0.0, 0.0, 0.0, 0.0]) - # # Q13 = copy(ΔX13) - # V1 = V2 = V3 = 1.0 - # M1 = ω12 * (Q12 * Q12') * V2 + ω13 * (Q13 * Q13') * V3 - - # threshold = 1e-6 * δ^3 - # M1inv = Peridynamics.invert_moment_matrix(M1, threshold) - - # Q∇ᵀ = SMatrix{3,9,Int,27}(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - # 0, 0, 0, 0, 0, 0) - # # Q∇ᵀ = SMatrix{3,3,Int,9}(1, 0, 0, 0, 1, 0, 0, 0, 1) - - - # Φ12 = ω12 * Q∇ᵀ * M1inv * Q12 - # Φ13 = ω13 * Q∇ᵀ * M1inv * Q13 - # @test Φ[:,1] ≈ Φ12 - # @test Φ[:,2] ≈ Φ13 - -end - -@testitem "Damage changed" begin - # setup - ref_position = [0.0 1.0 0.0 - 0.0 0.0 1.0 - 0.0 0.0 0.0] - volume = fill(1.0, 3) - δ = 1.5 - mat = RKCMaterial() - body = Body(mat, ref_position, volume) - material!(body, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) - failure_permit!(body, false) - dh = Peridynamics.threads_data_handler(body, VelocityVerlet(steps=1), 1) - chunk = dh.chunks[1] - (; mat, storage, system, paramsetup) = chunk - - # initial value should be `true` - @test storage.damage_changed == [true, true, true] - - # after first damage calculation this should be `false` - Peridynamics.calc_damage!(chunk) - @test storage.damage_changed == [false, false, false] - - # damage a bond: - @test storage.bond_active[1] == true - storage.bond_active[1] = false - @test storage.bond_active[1] == false - @test storage.n_active_bonds[1] == 2 - storage.n_active_bonds[1] -= 1 - @test storage.n_active_bonds[1] == 1 - - Peridynamics.calc_damage!(chunk) - @test storage.damage_changed == [true, false, false] -end - -@testitem "accuracy_order = 1" begin - # setup - ref_position = [0.0 1.0 0.0 - 0.0 0.0 1.0 - 0.0 0.0 0.0] - volume = fill(1.0, 3) - δ = 1.5 - mat_rk = RKCMaterial(accuracy_order=1) - body_kr = Body(mat_rk, ref_position, volume) - material!(body_kr, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) - failure_permit!(body_kr, false) - dh_rk = Peridynamics.threads_data_handler(body_kr, VelocityVerlet(steps=1), 1) - chunk_rk = dh_rk.chunks[1] - body_c = Body(CMaterial(), ref_position, volume) - material!(body_c, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) - failure_permit!(body_c, false) - dh_c = Peridynamics.threads_data_handler(body_c, VelocityVerlet(steps=1), 1) - chunk_c = dh_c.chunks[1] - - (; mat, storage, system, paramsetup) = chunk_rk - Peridynamics.calc_gradient_weights!(storage, system, mat, paramsetup) - -end - - -##---- - -Φ = rand(3) -ΔU = rand(3) -F1 = ΔU * Φ' -F2 = zeros(3,3) -for i in 1:3 - F2[i,1] = ΔU[i] * Φ[1] - F2[i,2] = ΔU[i] * Φ[2] - F2[i,3] = ΔU[i] * Φ[3] -end -F1 ≈ F2 From ca4ec19962e0097e3107d361e145c6e65c8a32e9 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Fri, 7 Feb 2025 10:06:00 +0100 Subject: [PATCH 37/40] Add docstrings --- docs/src/api_reference.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/src/api_reference.md b/docs/src/api_reference.md index 5e684b74..9860ed8b 100644 --- a/docs/src/api_reference.md +++ b/docs/src/api_reference.md @@ -13,13 +13,15 @@ Pages = ["api_reference.md"] BBMaterial OSBMaterial CMaterial +BACMaterial CKIMaterial ``` -## System related types +## System or material related types ```@docs NoCorrection EnergySurfaceCorrection +ZEMSilling ``` ## Discretization From 24829277ed1ec3ec63a6d35d66588a248e28a1af Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Fri, 7 Feb 2025 11:43:07 +0100 Subject: [PATCH 38/40] Use `mktempdir` for every temporary directory in tests --- src/auxiliary/precompile_workload.jl | 4 +- test/VtkReader/test_read_vtk.jl | 48 ++++++------------- test/auxiliary/test_io.jl | 10 +--- test/auxiliary/test_process_each_export.jl | 12 +---- test/integration/material_interface.jl | 4 +- test/integration/mpi_threads_comparison.jl | 20 ++------ test/integration/symmetry_bond_based.jl | 12 +---- .../symmetry_continuum_inspired.jl | 12 +---- test/integration/symmetry_correspondence.jl | 12 +---- .../symmetry_ordinary_state_based.jl | 12 +---- 10 files changed, 33 insertions(+), 113 deletions(-) diff --git a/src/auxiliary/precompile_workload.jl b/src/auxiliary/precompile_workload.jl index 30bad6a0..45ad8dfb 100644 --- a/src/auxiliary/precompile_workload.jl +++ b/src/auxiliary/precompile_workload.jl @@ -5,7 +5,7 @@ msg *= "Trigger package precompilation manually and then restart the mpirun!\n" error(msg) end - root = joinpath(@__DIR__, "temp_precompilation") + root = mktempdir() pos1, vol1 = uniform_box(1, 1, 1, 0.5; center=(0.5, 0.5, 0.5)) pos2, vol2 = uniform_box(1, 1, 1, 0.5; center=(-0.5, 0.5, 0.5)) path_bb = joinpath(root, "BB") @@ -68,6 +68,4 @@ submit(Job(b3, vv; path=path_cc, freq=1); quiet=true) submit(Job(ms, vv; path=path_ms, freq=1); quiet=true) end - - rm(root; recursive=true, force=true) end diff --git a/test/VtkReader/test_read_vtk.jl b/test/VtkReader/test_read_vtk.jl index 9ba7bee6..21a3ec2e 100644 --- a/test/VtkReader/test_read_vtk.jl +++ b/test/VtkReader/test_read_vtk.jl @@ -3,9 +3,9 @@ @testitem "read complete results" begin using Peridynamics.WriteVTK - bname = joinpath(@__DIR__, "vtk_test_1") + root = mktempdir() + bname = joinpath(root, "vtk_test_1") name = bname * ".vtu" - isfile(name) && rm(name) n_points = 10 position = rand(3, n_points) cells = [MeshCell(VTKCellTypes.VTK_VERTEX, (j,)) for j in 1:n_points] @@ -26,17 +26,15 @@ @test result[:Time] == [time] @test result[:Damage] == damage @test result[:Displacement] == displacement - - rm(name) end #-- read incomplete results @testitem "read incomplete results" begin using Peridynamics.WriteVTK - bname = joinpath(@__DIR__, "vtk_test_2") + root = mktempdir() + bname = joinpath(root, "vtk_test_2") name = bname * ".vtu" - isfile(name) && rm(name) n_points = 10 position = rand(3, n_points) cells = [MeshCell(VTKCellTypes.VTK_VERTEX, (j,)) for j in 1:n_points] @@ -58,8 +56,6 @@ end @test result[:damage] == damage @test result[:random_point_data] == random_point_data @test result[:random_field_data] == random_field_data - - rm(name) end @testitem "wrong file type" begin @@ -69,9 +65,9 @@ end @testitem "corrupt file raw encoding" begin using Peridynamics.WriteVTK - bname = joinpath(@__DIR__, "vtk_test_3") + root = mktempdir() + bname = joinpath(root, "vtk_test_3") name = bname * ".vtu" - isfile(name) && rm(name) n_points = 10 position = rand(3, n_points) cells = [MeshCell(VTKCellTypes.VTK_VERTEX, (j,)) for j in 1:n_points] @@ -92,16 +88,14 @@ end end @test_throws ErrorException read_vtk(name) - - rm(name) end @testitem "corrupt file offset marker" begin using Peridynamics.WriteVTK - bname = joinpath(@__DIR__, "vtk_test_4") + root = mktempdir() + bname = joinpath(root, "vtk_test_4") name = bname * ".vtu" - isfile(name) && rm(name) n_points = 10 position = rand(3, n_points) cells = [MeshCell(VTKCellTypes.VTK_VERTEX, (j,)) for j in 1:n_points] @@ -122,17 +116,15 @@ end end @test_throws ErrorException read_vtk(name) - - rm(name) end #-- corrupt file @testitem "corrupt file appended data" begin using Peridynamics.WriteVTK - bname = joinpath(@__DIR__, "vtk_test_5") + root = mktempdir() + bname = joinpath(root, "vtk_test_5") name = bname * ".vtu" - isfile(name) && rm(name) n_points = 10 position = rand(3, n_points) cells = [MeshCell(VTKCellTypes.VTK_VERTEX, (j,)) for j in 1:n_points] @@ -153,18 +145,14 @@ end end @test_throws ErrorException read_vtk(name) - - rm(name) end @testitem "read pvtu file" begin using Peridynamics.WriteVTK - root = joinpath(@__DIR__, "tempdir_1") - isdir(root) && rm(root; recursive=true, force=true) + root = mktempdir() bname = joinpath(root, "vtk_test") name = bname * ".pvtu" - isfile(name) && rm(name) n_points = 10 n_parts = 3 position = [rand(3, n_points) for _ in 1:n_parts] @@ -189,18 +177,14 @@ end @test result[:displacement] ≈ reduce(hcat, displacement) @test result[:integer_test] ≈ reduce(vcat, integer_test) @test result[:time] ≈ [time] - - rm(root; recursive=true, force=true) end @testitem "read pvtu files with nothing exported" begin using Peridynamics.WriteVTK - root = joinpath(@__DIR__, "tempdir_2") - isdir(root) && rm(root; recursive=true, force=true) + root = mktempdir() bname = joinpath(root, "vtk_test") name = bname * ".pvtu" - isfile(name) && rm(name) n_points = 10 n_parts = 3 position = [rand(3, n_points) for _ in 1:n_parts] @@ -213,16 +197,14 @@ end result = read_vtk(name) @test result[:position] ≈ reduce(hcat, position) - - rm(root; recursive=true, force=true) end @testitem "read vtu files with nothing exported" begin using Peridynamics.WriteVTK - bname = joinpath(@__DIR__, "vtk_test_6") + root = mktempdir() + bname = joinpath(root, "vtk_test_6") name = bname * ".vtu" - isfile(name) && rm(name) n_points = 10 position = rand(3, n_points) cells = [MeshCell(VTKCellTypes.VTK_VERTEX, (j,)) for j in 1:n_points] @@ -232,6 +214,4 @@ end @test typeof(result) == Dict{Symbol,VecOrMat{Float64}} @test result[:position] == position - - rm(name) end diff --git a/test/auxiliary/test_io.jl b/test/auxiliary/test_io.jl index d383c0ed..dc5d3303 100644 --- a/test/auxiliary/test_io.jl +++ b/test/auxiliary/test_io.jl @@ -244,8 +244,7 @@ end @testitem "export_results Body" begin - temp_root = joinpath(@__DIR__, "temp_root_export_results_test_body") - rm(temp_root; recursive=true, force=true) + temp_root = mktempdir() pos, vol = uniform_box(1, 1, 1, 0.5) body = Body(BBMaterial(), pos, vol) @@ -283,13 +282,10 @@ end @test r[:displacement] ≈ u_rand @test r[:damage] == zeros(8) @test r[:time] == [t] - - rm(temp_root; recursive=true, force=true) end @testitem "export_results MultibodySetup" begin - temp_root = joinpath(@__DIR__, "temp_root_export_results_test_multibody") - rm(temp_root; recursive=true, force=true) + temp_root = mktempdir() pos_a, vol_a = uniform_box(1, 1, 1, 0.5) body_a = Body(BBMaterial(), pos_a, vol_a) @@ -359,6 +355,4 @@ end @test r_b[:displacement] ≈ u_rand_b @test r_b[:damage] == zeros(8) @test r_b[:time] == [t] - - rm(temp_root; recursive=true, force=true) end diff --git a/test/auxiliary/test_process_each_export.jl b/test/auxiliary/test_process_each_export.jl index 9aceacaf..e97545d7 100644 --- a/test/auxiliary/test_process_each_export.jl +++ b/test/auxiliary/test_process_each_export.jl @@ -1,6 +1,5 @@ @testitem "process_each_export" begin - root = joinpath(@__DIR__, "temp_root_proc_each_export") - isdir(root) && rm(root; recursive=true, force=true) + root = mktempdir() root_post_threads = joinpath(root, "post_threads") mkpath(root_post_threads) root_post_serial = joinpath(root, "post_serial") @@ -83,17 +82,12 @@ file_3_mpi = joinpath(root_post_mpi, "max_displacement_3.txt") @test isfile(file_3_mpi) @test contains(read(file_3_mpi, String), "maximum displacement x: 2.4") - - rm(root; recursive=true, force=true) end @testitem "find_vtk_files" begin - root = joinpath(@__DIR__, "temp_root_find_vtk_files") - isdir(root) && rm(root; recursive=true, force=true) - + root = mktempdir() vtk_files_unsorted = ["timestep_123.pvtu", "abcd_timestep_000005.pvtu", "timestep_02.pvtu", "_1.pvtu"] - mkpath(root) for file in vtk_files_unsorted open(joinpath(root, file), "w+") do io write(io, "") @@ -103,6 +97,4 @@ end vtk_files = Peridynamics.find_vtk_files(root) @test basename.(vtk_files) == ["_1.pvtu", "timestep_02.pvtu", "abcd_timestep_000005.pvtu", "timestep_123.pvtu"] - - rm(root; recursive=true, force=true) end diff --git a/test/integration/material_interface.jl b/test/integration/material_interface.jl index 2b795e1d..2e9fae73 100644 --- a/test/integration/material_interface.jl +++ b/test/integration/material_interface.jl @@ -539,7 +539,7 @@ end @testitem "TestMaterial full simulation" begin include("test_material.jl") - root = joinpath(@__DIR__, "temp_testmaterial_full_simulation") + root = mktempdir() path_vtk = joinpath(root, "vtk") N = 10 @@ -562,6 +562,4 @@ end @test isdir(path_vtk) vtk_files = Peridynamics.find_vtk_files(path_vtk) @test length(vtk_files) == 3 - - rm(root; recursive=true, force=true) end diff --git a/test/integration/mpi_threads_comparison.jl b/test/integration/mpi_threads_comparison.jl index 7821a20d..8fdf5ab7 100644 --- a/test/integration/mpi_threads_comparison.jl +++ b/test/integration/mpi_threads_comparison.jl @@ -1,5 +1,5 @@ @testitem "MPI-Threads comparison BBMaterial{NoCorrection}" begin - root = joinpath(@__DIR__, "temp_mpi_threads_comparison_bbnc") + root = mktempdir() path_threads = joinpath(root, "results_threads") path_threads_vtk = joinpath(path_threads, "vtk") path_mpi = joinpath(root, "results_mpi") @@ -61,12 +61,10 @@ @test res_threads[key] ≈ res_mpi[key] end end - - rm(root; recursive=true, force=true) end @testitem "MPI-Threads comparison BBMaterial{NoCorrection} DynamicRelaxation" begin - root = joinpath(@__DIR__, "temp_mpi_threads_comparison_bbncdr") + root = mktempdir() path_threads = joinpath(root, "results_threads") path_threads_vtk = joinpath(path_threads, "vtk") path_mpi = joinpath(root, "results_mpi") @@ -135,12 +133,10 @@ end @test Δe < 0.03 end end - - rm(root; recursive=true, force=true) end @testitem "MPI-Threads comparison BBMaterial{EnergySurfaceCorrection}" begin - root = joinpath(@__DIR__, "temp_mpi_threads_comparison_bbesc") + root = mktempdir() path_threads = joinpath(root, "results_threads") path_threads_vtk = joinpath(path_threads, "vtk") path_mpi = joinpath(root, "results_mpi") @@ -202,12 +198,10 @@ end @test res_threads[key] ≈ res_mpi[key] end end - - rm(root; recursive=true, force=true) end @testitem "MPI-Threads comparison OSBMaterial" begin - root = joinpath(@__DIR__, "temp_mpi_threads_comparison_osb") + root = mktempdir() path_threads = joinpath(root, "results_threads") path_threads_vtk = joinpath(path_threads, "vtk") path_mpi = joinpath(root, "results_mpi") @@ -269,12 +263,10 @@ end @test res_threads[key] ≈ res_mpi[key] end end - - rm(root; recursive=true, force=true) end @testitem "MPI-Threads comparison CMaterial" begin - root = joinpath(@__DIR__, "temp_mpi_threads_comparison_cc") + root = mktempdir() path_threads = joinpath(root, "results_threads") path_threads_vtk = joinpath(path_threads, "vtk") path_mpi = joinpath(root, "results_mpi") @@ -336,6 +328,4 @@ end @test res_threads[key] ≈ res_mpi[key] end end - - rm(root; recursive=true, force=true) end diff --git a/test/integration/symmetry_bond_based.jl b/test/integration/symmetry_bond_based.jl index d3325f23..86dfe151 100644 --- a/test/integration/symmetry_bond_based.jl +++ b/test/integration/symmetry_bond_based.jl @@ -16,8 +16,7 @@ velocity_bc!(t -> 100, body, :set_a, :z) velocity_bc!(t -> -100, body, :set_b, :z) vv = VelocityVerlet(steps=100) - temp_root = joinpath(@__DIR__, "temp_root_symmetry_test_bb_vv") - rm(temp_root; recursive=true, force=true) + temp_root = mktempdir() job = Job(body, vv; path=temp_root, freq=10) dh = Peridynamics.submit_threads(job, 1) @@ -62,9 +61,6 @@ @test abs(end_displacement[d, i]) > 0 end end - - # delete all simulation files - rm(temp_root; recursive=true, force=true) end @testitem "symmetry BBMaterial DynamicRelaxation" begin @@ -85,8 +81,7 @@ end forcedensity_bc!(t -> 1e10, body, :set_a, :z) forcedensity_bc!(t -> -1e10, body, :set_b, :z) dr = DynamicRelaxation(steps=100) - temp_root = joinpath(@__DIR__, "temp_root_symmetry_test_bb_dr") - rm(temp_root; recursive=true, force=true) + temp_root = mktempdir() job = Job(body, dr; path=temp_root, freq=10) dh = Peridynamics.submit_threads(job, 1) @@ -121,7 +116,4 @@ end @test abs(end_displacement[d, i]) > 0 end end - - # delete all simulation files - rm(temp_root; recursive=true, force=true) end diff --git a/test/integration/symmetry_continuum_inspired.jl b/test/integration/symmetry_continuum_inspired.jl index 5b12131e..8cf8ccde 100644 --- a/test/integration/symmetry_continuum_inspired.jl +++ b/test/integration/symmetry_continuum_inspired.jl @@ -17,8 +17,7 @@ velocity_bc!(t -> 100, body, :set_a, :z) velocity_bc!(t -> -100, body, :set_b, :z) vv = VelocityVerlet(steps=20) - temp_root = joinpath(@__DIR__, "temp_root_symmetry_test_cki_vv") - rm(temp_root; recursive=true, force=true) + temp_root = mktempdir() job = Job(body, vv; path=temp_root, freq=10) dh = Peridynamics.submit_threads(job, 1) @@ -59,9 +58,6 @@ @test abs(end_displacement[d, i]) > 0 end end - - # delete all simulation files - rm(temp_root; recursive=true, force=true) end @testitem "symmetry CKIMaterial DynamicRelaxation" begin @@ -83,8 +79,7 @@ end forcedensity_bc!(t -> 1e10, body, :set_a, :z) forcedensity_bc!(t -> -1e10, body, :set_b, :z) dr = DynamicRelaxation(steps=20) - temp_root = joinpath(@__DIR__, "temp_root_symmetry_test_cki_dr") - rm(temp_root; recursive=true, force=true) + temp_root = mktempdir() job = Job(body, dr; path=temp_root, freq=10) dh = Peridynamics.submit_threads(job, 1) @@ -125,7 +120,4 @@ end @test abs(end_displacement[d, i]) > 0 end end - - # delete all simulation files - rm(temp_root; recursive=true, force=true) end diff --git a/test/integration/symmetry_correspondence.jl b/test/integration/symmetry_correspondence.jl index 342e8da7..f868fe4f 100644 --- a/test/integration/symmetry_correspondence.jl +++ b/test/integration/symmetry_correspondence.jl @@ -16,8 +16,7 @@ velocity_bc!(t -> 10, body, :set_a, :z) velocity_bc!(t -> -10, body, :set_b, :z) vv = VelocityVerlet(steps=100) - temp_root = joinpath(@__DIR__, "temp_root_symmetry_test_cc_vv") - rm(temp_root; recursive=true, force=true) + temp_root = mktempdir() job = Job(body, vv; path=temp_root, freq=10) dh = Peridynamics.submit_threads(job, 1) @@ -52,9 +51,6 @@ @test abs(end_displacement[d, i]) > 0 end end - - # delete all simulation files - rm(temp_root; recursive=true, force=true) end @testitem "symmetry CMaterial DynamicRelaxation" begin @@ -75,8 +71,7 @@ end forcedensity_bc!(t -> 1e10, body, :set_a, :z) forcedensity_bc!(t -> -1e10, body, :set_b, :z) dr = DynamicRelaxation(steps=100) - temp_root = joinpath(@__DIR__, "temp_root_symmetry_test_cc_dr") - rm(temp_root; recursive=true, force=true) + temp_root = mktempdir() job = Job(body, dr; path=temp_root, freq=10) dh = Peridynamics.submit_threads(job, 1) @@ -111,7 +106,4 @@ end @test abs(end_displacement[d, i]) > 0 end end - - # delete all simulation files - rm(temp_root; recursive=true, force=true) end diff --git a/test/integration/symmetry_ordinary_state_based.jl b/test/integration/symmetry_ordinary_state_based.jl index e4edfbb4..92d6d5fc 100644 --- a/test/integration/symmetry_ordinary_state_based.jl +++ b/test/integration/symmetry_ordinary_state_based.jl @@ -16,8 +16,7 @@ velocity_bc!(t -> 100, body, :set_a, :z) velocity_bc!(t -> -100, body, :set_b, :z) vv = VelocityVerlet(steps=100) - temp_root = joinpath(@__DIR__, "temp_root_symmetry_test_osb_vv") - rm(temp_root; recursive=true, force=true) + temp_root = mktempdir() job = Job(body, vv; path=temp_root, freq=10) dh = Peridynamics.submit_threads(job, 1) @@ -52,9 +51,6 @@ @test abs(end_displacement[d, i]) > 0 end end - - # delete all simulation files - rm(temp_root; recursive=true, force=true) end @testitem "symmetry OSBMaterial DynamicRelaxation" begin @@ -75,8 +71,7 @@ end forcedensity_bc!(t -> 1e10, body, :set_a, :z) forcedensity_bc!(t -> -1e10, body, :set_b, :z) dr = DynamicRelaxation(steps=100) - temp_root = joinpath(@__DIR__, "temp_root_symmetry_test_osb_dr") - rm(temp_root; recursive=true, force=true) + temp_root = mktempdir() job = Job(body, dr; path=temp_root, freq=10) dh = Peridynamics.submit_threads(job, 1) @@ -111,7 +106,4 @@ end @test abs(end_displacement[d, i]) > 0 end end - - # delete all simulation files - rm(temp_root; recursive=true, force=true) end From 32aab079df7c700daf1430e59eebf6707d2f9467 Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Fri, 7 Feb 2025 14:34:08 +0100 Subject: [PATCH 39/40] Cleanup and docs for constitutive models --- docs/src/api_reference.md | 6 ++ src/Peridynamics.jl | 5 +- src/discretization/kernels.jl | 31 +++++++- src/physics/constitutive_models.jl | 82 ++++++++++++++++++++- src/physics/correspondence.jl | 20 +++-- test/integration/b_int_correspondence.jl | 4 +- test/integration/symmetry_correspondence.jl | 2 +- 7 files changed, 136 insertions(+), 14 deletions(-) diff --git a/docs/src/api_reference.md b/docs/src/api_reference.md index 9860ed8b..ca87e722 100644 --- a/docs/src/api_reference.md +++ b/docs/src/api_reference.md @@ -22,6 +22,12 @@ CKIMaterial NoCorrection EnergySurfaceCorrection ZEMSilling +LinearElastic +NeoHooke +MooneyRivlin +SaintVenantKirchhoff +linear_kernel +cubic_b_spline_kernel ``` ## Discretization diff --git a/src/Peridynamics.jl b/src/Peridynamics.jl index 0f43493f..602a057c 100644 --- a/src/Peridynamics.jl +++ b/src/Peridynamics.jl @@ -12,7 +12,10 @@ import LibGit2, Dates export BBMaterial, OSBMaterial, CMaterial, BACMaterial, CKIMaterial # CMaterial related types -export NeoHookeNonlinear, SaintVenantKirchhoff, ZEMSilling +export LinearElastic, NeoHooke, MooneyRivlin, SaintVenantKirchhoff, ZEMSilling + +# Kernels +export linear_kernel, cubic_b_spline_kernel # Systems related types export NoCorrection, EnergySurfaceCorrection diff --git a/src/discretization/kernels.jl b/src/discretization/kernels.jl index 547828a6..2c977a4b 100644 --- a/src/discretization/kernels.jl +++ b/src/discretization/kernels.jl @@ -1,8 +1,35 @@ -# peridynamic kernels / influence functions for arbitrary bond systems +@doc raw""" + linear_kernel(δ, L) +A linear kernel function ``\omega`` (also called influence function) used for weighting the +bonds in a family. The kernel function is defined as +```math +\omega = \frac{\delta}{L} \; , +``` +with the horizon ``\delta`` and the initial bond length ``L``. +""" @inline linear_kernel(δ, L) = δ / L -@inline function cubic_b_spline(δ, L) +@doc raw""" + cubic_b_spline_kernel(δ, L) + +A cubic B-spline kernel function ``\omega`` used for weighting the bonds in a family. +The kernel function is defined as +```math +\begin{aligned} +\xi &= \frac{L}{\delta} \; , \\ +\omega &= \left\{ + \begin{array}{ll} + \frac{2}{3} - 4 \xi^2 + 4 \xi^3 & \quad \text{if} \; 0 < \xi \leq 0.5 \; , \\[3pt] + \frac{4}{3} - 4 \xi + 4 \xi^2 - \frac{4}{3} \xi^3 & \quad \text{if} \; 0.5 < \xi \leq 1 \; , \\[3pt] + 0 & \quad \text{else} \; , + \end{array} + \right. +\end{aligned} +``` +with the horizon ``\delta`` and the initial bond length ``L``. +""" +@inline function cubic_b_spline_kernel(δ, L) ξ = L / δ if 0 < ξ ≤ 0.5 return 2/3 - 4 * ξ^2 + 4 * ξ^3 diff --git a/src/physics/constitutive_models.jl b/src/physics/constitutive_models.jl index dc65c453..100754f2 100644 --- a/src/physics/constitutive_models.jl +++ b/src/physics/constitutive_models.jl @@ -1,3 +1,19 @@ +@doc raw""" + LinearElastic + +Linear elastic constitutive model that can be specified when using a [`CMaterial`](@ref) and +[`BACMaterial`](@ref). +The first Piola-Kirchhoff stress ``\boldsymbol{P}`` is given by +```math +\boldsymbol{P} = \mathbb{C} : \boldsymbol{E} \; , +``` +with the elastic stiffness tensor ``\mathbb{C}`` and the Green-Lagrange strain tensor +``\boldsymbol{E}`` with +```math +\boldsymbol{E} = \frac{1}{2} \left( \boldsymbol{F}^{\top} \boldsymbol{F} - \boldsymbol{I} + \right) \; . +``` +""" struct LinearElastic <: AbstractConstitutiveModel end function first_piola_kirchhoff(::LinearElastic, storage::AbstractStorage, @@ -19,6 +35,25 @@ function get_hooke_matrix(nu, λ, μ) return CVoigt end +@doc raw""" + NeoHooke + +Neo-Hookean constitutive model that can be specified when using a [`CMaterial`](@ref) and +[`BACMaterial`](@ref). +The first Piola-Kirchhoff stress ``\boldsymbol{P}`` is given by +```math +\begin{aligned} +\boldsymbol{C} &= \boldsymbol{F}^{\top} \boldsymbol{F} \; , \\ +\boldsymbol{S} &= \mu \left( \boldsymbol{I} - \boldsymbol{C}^{-1} \right) + + \lambda \log(J) \boldsymbol{C}^{-1} \; , \\ +\boldsymbol{P} &= \boldsymbol{F} \, \boldsymbol{S} \; , +\end{aligned} +``` +with the deformation gradient ``\boldsymbol{F}``, the right Cauchy-Green deformation tensor +``\boldsymbol{C}``, the Jacobian ``J = \mathrm{det}(\boldsymbol{F})``, the second +Piola-Kirchhoff stress ``\boldsymbol{S}``, and the first and second Lamé parameters +``\lambda`` and ``\mu``. +""" struct NeoHooke <: AbstractConstitutiveModel end function first_piola_kirchhoff(::NeoHooke, storage::AbstractStorage, @@ -30,9 +65,33 @@ function first_piola_kirchhoff(::NeoHooke, storage::AbstractStorage, return P end -struct NeoHookeNonlinear <: AbstractConstitutiveModel end +@doc raw""" + MooneyRivlin + +Mooney-Rivlin constitutive model that can be specified when using a [`CMaterial`](@ref) and +[`BACMaterial`](@ref). +The first Piola-Kirchhoff stress ``\boldsymbol{P}`` is given by +```math +\begin{aligned} +\boldsymbol{C} &= \boldsymbol{F}^{\top} \boldsymbol{F} \; , \\ +\boldsymbol{S} &= G \left( \boldsymbol{I} - \frac{1}{3} \mathrm{tr}(\boldsymbol{C}) + \boldsymbol{C}^{-1} \right) \cdot J^{-\frac{2}{3}} + + \frac{K}{4} \left( J^2 - J^{-2} \right) \boldsymbol{C}^{-1} \; , \\ +\boldsymbol{P} &= \boldsymbol{F} \, \boldsymbol{S} \; , +\end{aligned} +``` +with the deformation gradient ``\boldsymbol{F}``, the right Cauchy-Green deformation tensor +``\boldsymbol{C}``, the Jacobian ``J = \mathrm{det}(\boldsymbol{F})``, the second +Piola-Kirchhoff stress ``\boldsymbol{S}``, the shear modulus ``G``, and the +bulk modulus ``K``. -function first_piola_kirchhoff(::NeoHookeNonlinear, storage::AbstractStorage, +# Error handling +If the Jacobian ``J`` is smaller than the machine precision `eps()` or a `NaN`, the first +Piola-Kirchhoff stress tensor is defined as ``\boldsymbol{P} = \boldsymbol{0}``. +""" +struct MooneyRivlin <: AbstractConstitutiveModel end + +function first_piola_kirchhoff(::MooneyRivlin, storage::AbstractStorage, params::AbstractPointParameters, F::SMatrix{3,3,T,9}) where T J = det(F) J < eps() && return zero(SMatrix{3,3,T,9}) @@ -45,6 +104,25 @@ function first_piola_kirchhoff(::NeoHookeNonlinear, storage::AbstractStorage, return P end +@doc raw""" + SaintVenantKirchhoff + +Saint-Venant-Kirchhoff constitutive model that can be specified when using a +[`CMaterial`](@ref) and [`BACMaterial`](@ref). +The first Piola-Kirchhoff stress ``\boldsymbol{P}`` is given by +```math +\begin{aligned} +\boldsymbol{E} &= \frac{1}{2} \left( \boldsymbol{F}^{\top} \boldsymbol{F} - \boldsymbol{I} + \right) \; , \\ +\boldsymbol{S} &= \lambda \, \mathrm{tr}(\boldsymbol{E}) \, \boldsymbol{I} + + 2 \mu \boldsymbol{E} \; , \\ +\boldsymbol{P} &= \boldsymbol{F} \, \boldsymbol{S} \; , +\end{aligned} +``` +with the deformation gradient ``\boldsymbol{F}``, the Green-Lagrange strain tensor +``\boldsymbol{E}``, the second Piola-Kirchhoff stress ``\boldsymbol{S}``, and the first and +second Lamé parameters ``\lambda`` and ``\mu``. +""" struct SaintVenantKirchhoff <: AbstractConstitutiveModel end function first_piola_kirchhoff(::SaintVenantKirchhoff, storage::AbstractStorage, diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index 4f513b04..26b85239 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -5,16 +5,24 @@ A material type used to assign the material of a [`Body`](@ref) with the local c consistent (correspondence) formulation of non-ordinary state-based peridynamics. # Keywords -- `kernel::Function`: Kernel function used for weighting the interactions between points. - (default: `linear_kernel`) -- `model::AbstractConstitutiveModel`: Constitutive model defining the material behavior. - (default: `LinearElastic()`) +- `kernel::Function`: Kernel function used for weighting the interactions between points. \\ + (default: `linear_kernel`) \\ + The following kernels can be used: + - [`linear_kernel`](@ref) + - [`cubic_b_spline_kernel`](@ref) +- `model::AbstractConstitutiveModel`: Constitutive model defining the material behavior. \\ + (default: `LinearElastic()`) \\ + The following models can be used: + - [`LinearElastic`](@ref) + - [`NeoHooke`](@ref) + - [`MooneyRivlin`](@ref) + - [`SaintVenantKirchhoff`](@ref) - `zem::AbstractZEMStabilization`: Zero-energy mode stabilization. The - stabilization algorithm of Silling (2017) is used as default. + stabilization algorithm of Silling (2017) is used as default. \\ (default: `ZEMSilling()`) - `maxdmg::Float64`: Maximum value of damage a point is allowed to obtain. If this value is exceeded, all bonds of that point are broken because the deformation gradient would then - possibly contain `NaN` values. + possibly contain `NaN` values. \\ (default: `0.85`) !!! note "Stability of fracture simulations" diff --git a/test/integration/b_int_correspondence.jl b/test/integration/b_int_correspondence.jl index d607cfb4..cf811cf4 100644 --- a/test/integration/b_int_correspondence.jl +++ b/test/integration/b_int_correspondence.jl @@ -4,7 +4,7 @@ 0.0 0.0 0.0 1.0 2.0] volume = fill(1.0, 5) δ = 1.5 - body = Body(CMaterial(model=NeoHookeNonlinear()), ref_position, volume) + body = Body(CMaterial(model=MooneyRivlin()), ref_position, volume) material!(body, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) failure_permit!(body, false) @@ -36,7 +36,7 @@ end 0.0 0.0 0.0 1.0 2.0] volume = fill(1.0, 5) δ = 1.5 - body = Body(CMaterial(model=NeoHookeNonlinear()), ref_position, volume) + body = Body(CMaterial(model=MooneyRivlin()), ref_position, volume) point_set!(body, :a, [1]) point_set!(body, :b, [2,3,4,5]) material!(body, :a, horizon=δ, rho=1, E=1, nu=0.25, Gc=1.0) diff --git a/test/integration/symmetry_correspondence.jl b/test/integration/symmetry_correspondence.jl index f868fe4f..4c0841f5 100644 --- a/test/integration/symmetry_correspondence.jl +++ b/test/integration/symmetry_correspondence.jl @@ -8,7 +8,7 @@ pos = hcat(([x;y;z] for x in grid for y in grid for z in grid)...) n_points = size(pos, 2) vol = fill(Δx^3, n_points) - body = Body(CMaterial(model=NeoHookeNonlinear()), pos, vol) + body = Body(CMaterial(model=MooneyRivlin()), pos, vol) failure_permit!(body, false) material!(body, horizon=3.015Δx, rho=7850, E=210e9, nu=0.25, Gc=1) point_set!(z -> z > width/2 - 0.6Δx, body, :set_a) From 49fe7fd60983e66fbd8f766a001444dc52815a4a Mon Sep 17 00:00:00 2001 From: Kai Partmann Date: Fri, 7 Feb 2025 15:29:53 +0100 Subject: [PATCH 40/40] Add new export fields to docs of CMaterial --- src/physics/correspondence.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/physics/correspondence.jl b/src/physics/correspondence.jl index 26b85239..33a75458 100644 --- a/src/physics/correspondence.jl +++ b/src/physics/correspondence.jl @@ -84,6 +84,8 @@ When specifying the `fields` keyword of [`Job`](@ref) for a [`Body`](@ref) with - `b_ext::Matrix{Float64}`: External force density of each point - `damage::Vector{Float64}`: Damage of each point - `n_active_bonds::Vector{Int}`: Number of intact bonds of each point +- `stress::Matrix{Float64}`: Stress tensor of each point +- `von_mises_stress::Vector{Float64}`: Von Mises stress of each point """ struct CMaterial{CM,ZEM,K} <: AbstractCorrespondenceMaterial{CM,ZEM} kernel::K