Open vavrines opened 3 months ago
Hello @vavrines, Thank you for reaching out!
I am very interested in implementing this into Peridynamics.jl
.
Your code is very well structured and comfortable to read, so implementing it using your example should be feasible.
Do you have literature describing your thermo-mechanical coupling model?
Would you also be interested in us collaborating on a publication about this topic? We have good HPC access and can run large-scale simulations once the model works with the package.
@kaipartmann Thanks for the feedback! Basically we follow Chapter 13 in the monograph Peridynamic Theory and Its Applications. I'd love to work together with you. We'll first try to implement the thermal model. I'll let you know our process and there may be some beginner's questions in between. Our long-term plan is to do fluid-solid interaction by coupling CFD and PD codes.
@vavrines, this sounds like a good plan!
I recently talked with the developers of TrixiParticles.jl
.
Maybe their repo is also worth looking for you.
Using your example, I hacked something together. I am unsure if it works correctly - the code is probably full of bugs/errors. The structure of Peridynamics.jl
is currently not suited for coupled problems, so I had to override many functions, which resulted in a lot of complicated internal code. It also only works with the current state of the main
branch and is likely to break.
I am still in the process of reworking the internal structure of the package. I will consider how a coupled model could be easily implemented without changing many internal functions for the next version.
However, you can probably try this out for your model development. If you have questions, please do not hesitate to contact me.
The best thing is that you start from an empty new project and add the current main
branch of the package:
shell> mkdir pd_thermal_coupling
shell> cd pd_thermal_coupling
shell> julia
julia> ]
(@v1.10) pkg> activate .
(pd_thermal_coupling) pkg> add Peridynamics#main
Then you create the following file:
Then you can run a simulation with the new API of the package:
include("bb_thermal_coupling_model.jl")
l, Δx, δ = 1.0, 1/100, 3.015/100
pos, vol = uniform_box(l, 0.1l, 0.1l, Δx)
body = Body(BBTMaterial(), pos, vol)
# add material parameters as in your code
material!(body; horizon=3.015Δx, E=2.1e5, rho=8e-6, Gc=2.7, kc=51.9, aph=11.5e-6, cv=472)
point_set!(x -> x > 0.0, body, :heating_area)
point_set!(x -> x < -l/2+3Δx, body, :fixed_area)
# temperature boundary condition: increase temperature by 1e5 K/s
temperature_bc!(t -> 1e5 * t, body, :heating_area)
velocity_bc!(t -> 0.0, body, :fixed_area, :x)
vv = VelocityVerlet(steps=2000)
job = Job(body, vv; path=joinpath(@__DIR__, "thermal_coupling"))
@time submit(job);
I mainly defined a bond-based thermal material and added new internal methods for this material type.
struct BBTMaterial <: Peridynamics.AbstractMaterial end
The pflux
(thermal loop) is calculated in the pflux_point!
function:
function pflux_point!(s::BBTStorage, bd::Peridynamics.BondDiscretization, ::BBTMaterial,
param::BBTPointParameters, i::Int)
for bond_id in Peridynamics.each_bond_idx(bd, i)
bond = bd.bonds[bond_id]
j, L = bond.neighbor, bond.length
Δxijx = s.position[1, j] - s.position[1, i]
Δxijy = s.position[2, j] - s.position[2, i]
Δxijz = s.position[3, j] - s.position[3, i]
Δvijx = s.velocity[1, j] - s.velocity[1, i]
Δvijy = s.velocity[2, j] - s.velocity[2, i]
Δvijz = s.velocity[3, j] - s.velocity[3, i]
l = sqrt(Δxijx * Δxijx + Δxijy * Δxijy + Δxijz * Δxijz)
ev = (Δxijx * Δvijx + Δxijy * Δvijy + Δxijz * Δvijz) / l
Δtem = s.temperature[j] - s.temperature[i]
s.pflux[i] += s.bond_active[bond_id] * (param.kp * Δtem / L -
ev * 0.5 * param.bc * param.aph) * bd.volume[j]
end
return nothing
end
Then, the force density calculation of the plain BBMaterial
is extended to account for temperature changes:
function Peridynamics.force_density_point!(s::BBTStorage,
bd::Peridynamics.BondDiscretization,
::BBTMaterial, param::BBTPointParameters, i::Int)
for bond_id in Peridynamics.each_bond_idx(bd, i)
bond = bd.bonds[bond_id]
j, L = bond.neighbor, bond.length
# current bond length
Δxijx = s.position[1, j] - s.position[1, i]
Δxijy = s.position[2, j] - s.position[2, i]
Δxijz = s.position[3, j] - s.position[3, i]
l = sqrt(Δxijx * Δxijx + Δxijy * Δxijy + Δxijz * Δxijz)
# bond strain
εm = (l - L) / L
εt = 0.5 * (s.temperature[j] - s.temperature[i]) * param.aph
ε = εm + εt
# failure mechanism
if ε > param.εc && bond.fail_permit
s.bond_active[bond_id] = false
end
s.n_active_bonds[i] += s.bond_active[bond_id]
# update of force density
temp = s.bond_active[bond_id] * param.bc * ε / l * bd.volume[j]
s.b_int[1, i] += temp * Δxijx
s.b_int[2, i] += temp * Δxijy
s.b_int[3, i] += temp * Δxijz
end
return nothing
end
The other methods are mostly internal functions.
@vavrines I will introduce changes to the main branch in a few minutes that will break the provided code.
Therefore, I created a branch thermal_coupling
that works as described with the example.
So in the local environment just do
(pd_thermal_coupling) pkg> rm Peridynamics
(pd_thermal_coupling) pkg> add Peridynamics#thermal_coupling
Thank you for your assistance. I am a member of vavrines's team and am currently working on this project. I am benefiting greatly from reviewing your code.
@vavrines I will introduce changes to the main branch in a few minutes that will break the provided code. Therefore, I created a branch
thermal_coupling
that works as described with the example.So in the local environment just do
(pd_thermal_coupling) pkg> rm Peridynamics (pd_thermal_coupling) pkg> add Peridynamics#thermal_coupling
My apologies for the interruption, may I ask you a few questions?
Hello @ShiWeiHuH! I am happy that the example benefits you! :)
- I encountered a bug when trying out the “bb_thermal_coupling_model.jl” script. It prompted an UndefVarError: discretization_type not defined at line 63 of bb_thermal_coupling_model.jl.
It seems that you're encountering an issue with the branch on GitHub. Please try in the package mode
pkg> status
[4dc47793] Peridynamics v0.2.0 `https://github.com/kaipartmann/Peridynamics.jl.git#thermal_coupling`
and check if it reads thermal_coupling
at the end of the Peridynamics.jl
entry.
- I would like to know how the surface and volume corrections are implemented in the code, specifically in which function.
We currently do not have volume or surface corrections implemented. If you need that, I can add it. I tried to implement it before but did not finish to debug the code.
- During the thermal-structural coupling calculation, due to the presence of virtual layers, the domains for force and heat calculations should be different. Previously, we found that if this is not taken into account, there are significant calculation deviations, especially near the boundaries. In other words, during heat calculation, the displacement virtual layer needs to be excluded, and during force calculation, the temperature virtual layer needs to be excluded. Which specific function(s) need(s) to be modified for this setting?
This is very interesting, and I did not know that. I am very new to thermal models with peridynamics, so I am unsure if I correctly understand the actual consequences of this regarding the code. So, is it a problem if a point has some mechanical and thermal boundary conditions simultaneously? Can you highlight your implementation of these effects in the script you provided for me?
Hi, @kaipartmann.Thank you very much for your response. As for question 1: I'm very sorry, the bug was caused by my own operational mistake. It has been resolved now. Thank you for your guidance. As for question 2: With a sufficient number of PD points, surface corrections and volume corrections can also yield good calculation results. I'm also trying to make some modifications to enhance my understanding of your code. Your code is very inspiring, and I'm learning from it.
Hi, @kaipartmann. We have updated the init.jl file. In the new init.jl, compared to the original version, the main content remains unchanged, but detailed comments have been added. We have annotated the codes for handling the thermal domain and the mechanical domain separately, while also marking the codes for surface correction and volume correction. During thermal coupling calculations, it's not always the case that the mechanical domain and the thermal domain are different. If there are displacement or velocity boundary conditions, as well as temperature boundary conditions, it is necessary to add a fictitious layer. Only when the fictitious layers for thermal and deformation solutions are located at different positions, should the scenario of different domains for motion and heat transfer calculations be considered. There are also cases where both temperature and displacement or velocity boundary conditions are set in the same fictitious layer, such as in thermal pulling. On the side receiving the pulling force, it's possible to simultaneously set temperature and displacement boundary conditions. However, for the fixed end on the other side, there might not be temperature boundary conditions, leading to a scenario where the thermal and mechanical domains are different.
Hi @ShiWeiHuH,
Thank you for your updates in the init.jl file. I think I can now better understand what the fictitious layers do. I hope to get some time in the next few days to implement these into an updated version of the bb_thermal_coupling_model.jl
script. I am unsure how long it will take, but I will ping you if I encounter problems or have any questions.
Hi @ShiWeiHuH, Thank you for your updates in the init.jl file. I think I can now better understand what the fictitious layers do. I hope to get some time in the next few days to implement these into an updated version of the
bb_thermal_coupling_model.jl
script. I am unsure how long it will take, but I will ping you if I encounter problems or have any questions. Hello, @kaipartmann, I want to express my gratitude once again for your assistance. Over this period, I've been working on implementing surface and volume corrections based on your provided code, particularly focusing on the 'bond_discretization.jl' section. As a result, I've developed a 'modify.jl' file dedicated to this task. The basic functionality has been implemented. By executing the following three lines of code, we can derive the necessary correction coefficients. Here is the modified code :include("bb_thermal_coupling_model.jl") include("modify.jl") Peridynamics.get_git_info() = "*" l, Δx, δ = 1.0, 1/100, 3.015/100 pos, vol = uniform_box(l+6*Δx, 0.1l, 0.1l, Δx) body = Body(BBTMaterial(), pos, vol) # add material parameters as in your code material!(body; horizon=3.015*Δx, E=2.1e5, rho=8e-6, Gc=2.7, kc=51.9, aph=11.5e-6, cv=472) point_set!(x -> x < -l/2, body, :tem_bc) point_set!(x -> x > l/2, body, :fix_bc) # temperature boundary condition: increase temperature by 1e5 K/s temperature_bc!(t -> 1e5 * t, body, :tem_bc) velocity_bc!(t -> 0.0, body, :fix_bc, :x) mp = mpm_init(Dict(:dx => Δx, :horizon => 3.015*Δx, :emod => 2.1e5, :th_con => 51.9)) ### creat parameters for modify sbd = mbd_init(body, mp) ### creat the index and volume modify coefficient mm = undate_mbd(sbd, body, mp) ### creat surface coefficient vv = VelocityVerlet(steps=2000) job = Job(body, vv; path=joinpath(@__DIR__, "thermal_coupling"), fields=(:displacement, :damage)) @time submit(job)
This part is newly added:
mp = mpm_init(Dict(:dx => Δx, :horizon => 3.015*Δx, :emod => 2.1e5, :th_con => 51.9)) ### creat parameters for modify sbd = mbd_init(body, mp) ### creat the index and volume modify coefficient mm = undate_mbd(sbd, body, mp) ### creat surface coefficient
The modify.jl
using Peridynamics using NearestNeighbors
mutable struct Mbond neighbor::Int length::Float64 vol_m::Float64 ### voleme modify coefficient surf_th::Float64 ### surface modify coefficient of thermal zone surf_mh::Float64 ### surface modify coefficient of deformation zone end
struct MbondDiscretization <: Peridynamics.AbstractDiscretization bonds::Vector{Mbond} n_neighbors::Vector{Int} bond_ids::Vector{UnitRange{Int}} volume::Vector{Float64} end
struct Mparameters dx::Float64 δ::Float64 kc::Float64 # thermal conductivity kp::Float64 # microconductivity E::Float64 bc::Float64 end
function mpm_init(p::Dict{Symbol,Float64}) dx = p[:dx] δ = p[:horizon] kc = p[:th_con] kp = 6 kc / (π δ^4) E = p[:emod] bc = 12 E / (π δ^4) mpm = Mparameters(dx, δ, kc, kp, E, bc) return mpm end
function mbd_init(body::Body, mpm::Mparameters) bonds, n_neighbors = mfind_bonds(body, mpm) bond_ids = mfind_bond_ids(n_neighbors) volume = body.volume mbd = MbondDiscretization(bonds, n_neighbors, bond_ids,volume) return mbd end
function mfind_bonds(body::Body, mpm::Mparameters) balltree = BallTree(body.position) bonds = Vector{Mbond}() sizehint!(bonds, body.n_points * 100) n_neighbors = zeros(Int, body.n_points) for i in 1:body.n_points n_neighbors[i] = mfind_bonds!(bonds, balltree, body.position, mpm, i) end return bonds, n_neighbors end
function mfind_bonds!(bonds::Vector{Mbond}, balltree::BallTree, position::Matrix{Float64}, mpm::Mparameters, i::Int)
neigh_idxs_with_i = inrange(balltree, view(position, :, i), mpm.δ)
neigh_idxs = filter(x -> x != i, neigh_idxs_with_i)
for j in neigh_idxs
L = sqrt((position[1, j] - position[1, i])^2 +
(position[2, j] - position[2, i])^2 +
(position[3, j] - position[3, i])^2)
if L < (mpm.δ - 0.5 * mpm.dx)
vol_m = 1.0
elseif L < (mpm.δ + 0.5 * mpm.dx)
vol_m = (mpm.δ + 0.5 * mpm.dx - L) / mpm.dx
else
vol_m = 0.0
end
surf_th = 1.0
surf_mh = 1.0
push!(bonds, Mbond(j, L, vol_m, surf_th, surf_mh))
end
return length(neigh_idxs)
end
function mfind_bond_ids(n_neighbors::Vector{Int}) bond_ids = fill(0:0, length(n_neighbors)) bonds_start, bonds_end = 1, 0 for i in eachindex(n_neighbors) bonds_end = bonds_start + n_neighbors[i] - 1 bond_ids[i] = bonds_start:bonds_end bonds_start += n_neighbors[i] end return bond_ids end
function undate_mbd(mbd::MbondDiscretization, bo::Body, mpm::Mparameters)
tem = 0.001.*[sum(bo.position[:, i]) for i in 1:bo.n_points]
disx = copy(bo.position)
disx[1, :] .= 1.001 .* disx[1, :]
disy = copy(bo.position)
disy[2, :] .= 1.001 .* disy[2, :]
disz = copy(bo.position)
disz[3, :] .= 1.001 .* disz[3, :]
point_th = zeros(Float64, bo.n_points)
point_mx = zeros(Float64, bo.n_points)
point_my = zeros(Float64, bo.n_points)
point_mz = zeros(Float64, bo.n_points)
for i in 1:bo.n_points
pd_th = 0
pd_mechx = 0
pd_mechy = 0
pd_mechz = 0
for bond_id in meach_bond_idx(mbd, i)
bond = mbd.bonds[bond_id]
j, L = bond.neighbor, bond.length
if i in bo.point_sets[:fix_bc] || j in bo.point_sets[:fix_bc]
mfth = 0
else
mfth = 1
end
if i in bo.point_sets[:tem_bc] || j in bo.point_sets[:tem_bc]
mfmech = 0
else
mfmech = 1
end
nlengthx = sqrt((disx[1,j] - disx[1,i])^2 + (disx[2,j] - disx[2,i])^2 + (disx[3,j] - disx[3,i])^2)
nlengthy = sqrt((disy[1,j] - disy[1,i])^2 + (disy[2,j] - disy[2,i])^2 + (disy[3,j] - disy[3,i])^2)
nlengthz = sqrt((disz[1,j] - disz[1,i])^2 + (disz[2,j] - disz[2,i])^2 + (disz[3,j] - disz[3,i])^2)
pd_th += 0.25 * mpm.kp * (tem[j] - tem[i])^2 / L * mbd.volume[j] * bond.vol_m * mfth
pd_mechx += 0.25 * mpm.bc * ((nlengthx-L) / L)^2 * mbd.volume[j] * bond.vol_m * mfmech
pd_mechy += 0.25 * mpm.bc * ((nlengthy-L) / L)^2 * mbd.volume[j] * bond.vol_m * mfmech
pd_mechz += 0.25 * mpm.bc * ((nlengthz-L) / L)^2 * mbd.volume[j] * bond.vol_m * mfmech
end
if pd_th != 0
point_th[i,1] = 1e-6 * mpm.kc * 1.5 / pd_th
else
point_th[i,1] = 0
end
if pd_mechx != 0
point_mx[i,1] = 0.6 * 1e-6 * mpm.E / pd_mechx
else
point_mx[i,1] = 0
end
if pd_mechy != 0
point_my[i,1] = 0.6 * 1e-6 * mpm.E / pd_mechy
else
point_my[i,1] = 0
end
if pd_mechz != 0
point_mz[i,1] = 0.6 * 1e-6 * mpm.E / pd_mechz
else
point_mz[i,1] = 0
end
end
for i in 1:bo.n_points
for bond_id in meach_bond_idx(mbd, i)
bond = mbd.bonds[bond_id]
j, L = bond.neighbor, bond.length
bond.surf_th = 0.5 * (point_th[i]+point_th[j])
if abs(bo.position[3,j] - bo.position[3,i]) < 1e-10
if abs(bo.position[2,j] - bo.position[2,i]) < 1e-10
θ = 0
elseif abs(bo.position[1,j] - bo.position[1,i]) < 1e-10
θ = π/2
else
θ = atan(abs((bo.position[2,j] - bo.position[2,i])/(bo.position[1,j] - bo.position[1,i])))
end
ϕ = π/2
sx = (point_mx[i] + point_mx[j]) / 2
sy = (point_my[i] + point_my[j]) / 2
sz = (point_mz[i] + point_mz[j]) / 2
bond.surf_mh = sqrt(1/((cos(θ)*sin(ϕ)/sx)^2 + (sin(θ)*sin(ϕ)/sy)^2 + (cos(ϕ)/sz)^2))
elseif (abs(bo.position[2,j] - bo.position[2,i]) < 1e-10) && (abs(bo.position[1,j] - bo.position[1,i]) < 1e-10)
sz = (point_mz[i] + point_mz[j]) / 2
bond.surf_mh = sz
else
θ = atan(abs((bo.position[2,j] - bo.position[2,i])/(bo.position[1,j] - bo.position[1,i])))
ϕ = acos((bo.position[3,j] - bo.position[3,i])/L)
sx = (point_mx[i] + point_mx[j]) / 2
sy = (point_my[i] + point_my[j]) / 2
sz = (point_mz[i] + point_mz[j]) / 2
bond.surf_mh = sqrt(1/((cos(θ)*sin(ϕ)/sx)^2 + (sin(θ)*sin(ϕ)/sy)^2 + (cos(ϕ)/sz)^2))
end
end
end
return mbd
end
@inline meach_bond_idx(mbd::MbondDiscretization, point_id::Int) = mbd.bond_ids[point_id]
My next step is to pass the correction coefficients into 'bb_thermal_coupling_model.jl'.
Additionally, you mentioned that the time stepping schemes need to be rewritten. What are the main points to pay attention to in this part? I will try to proceed with it next.
Hi @ShiWeiHuH,
Thank you very much for providing your code!
First, I'm sorry about the bug with the get_git_info()
function. It has already been solved in the main branch.
I ran your code, and it should work fine. You are correct in bridging the parallel computation features with your newly defined MBondDiscretization
, because they cause problems when calculating the surface correction factors.
I encountered the same issue and am working on it (#73). I'm now prioritizing the implementation of the surface correction (see #74), and your assistance is greatly appreciated.
I already tried to do something similar to what you did, but my code still has some bugs. You can take a look at the surface_correction
branch in the file:
https://github.com/kaipartmann/Peridynamics.jl/blob/surface_correction/src/physics/bond_based_corrected.jl
These lines look very similar to your code:
https://github.com/kaipartmann/Peridynamics.jl/blob/1cb431789f94db74e4bd545b3e2284334054656c/src/physics/bond_based_corrected.jl#L205-L243
You can proceed by adding your MBondDiscretization
as a discretization method with
@inline function Peridynamics.init_discretization(body::Body{BBTMaterial}, args...)
return mbd_init(body, ...)
end
But your mbd_init
function needs to return a ChunkHandler
and has to be similar to:
https://github.com/kaipartmann/Peridynamics.jl/blob/a71541fc6ef511b92031305f95f42c922dfd7aee/src/discretizations/bond_discretization.jl#L15-L28
However, please note that in the main
branch, this process is already more straightforward when using the @storage
macro. It might be easier to proceed by copying some of the code from there.
If I am ready with #73, I can provide a new script of the current state that includes your modify.jl
with the thermal computation.
Hi @kaipartmann ,
Thanks for the tips! Besides of #73 and #74, please let us know when the main branch reaches a relatively stable time. It might not be a bad idea to start pulling things before we go too deep in the obsolete codes.
@kaipartmann
Thank you for your reply. After reviewing this portion of surface_correction
, It effectively modifies surface effects. 💯 🥇 👍
This approach reminds me of the method used in the 《Peridynamic Theory and Its Applications》. Volume and surface corrections are computed as coefficients for bond force calculation in each iteration. Even though the code in this book calculates correction coefficients with each iteration when computing forces, the calculations still rely on the coordinates of the initial PD points. Correction coefficients are a physical property that reflects the initial geometric characteristics, and once the geometric structure is generated, these coefficients remain fixed and do not change. Some subsequent articles have suggested that parameters such as correction coefficients should be precomputed, and then directly called in subsequent iterations, which can significantly reduce computational overhead. Inspired by the part of your code related to bond indexing and length handling, I attempted to precompute correction coefficients and then call them in each iteration.
Regarding the issue of different thermal dynamics in different regions, it can be addressed during surface correction. For example, in thermal dynamics computations, if any PD point of a bond lies within the virtual layer of displacement constraints, the correction coefficient is set to 0, thus eliminating the influence of the virtual layer. I will proceed with experimentation as you suggested.
Thanks again for your assistance. 👍
@ShiWeiHuH thank you for taking the time to review the code. Your assistance is greatly appreciated!
I wanted to do what you suggested but needed #73 solved for that. A halo exchange in the initialization phase is needed to calculate the bond correction factors, and I previously designed the exchange functions so that they would only work during the time integration. Therefore, I took this quick and dirty approach to calculate the factors during each time step because then it would be possible to exchange the values to the halo points.
I will try to add the surface correction as part of the BondSystem
. If I am ready, you can probably copy the code in bond_system.jl
and create a ThermalBondSystem
that handles thermal correction factors.
Unfortunately, the surface correction still has some bugs; I will explain this closer in #74 and ping you there.
@kaipartmann
Thank you. I understand what you mean now. My current approach is somewhat makeshift. Considering that the calculation of correction factors only occurs once at the beginning, I bypassed the issue of parallelization and simply calculated the correction factors separately and left them as is. It would be great if we could handle them uniformly within your parallel framework.
Today, I managed to integrate the computed correction factors into the coupling program via function calls. Similarly, it's not the most elegant solution, haha. Below is the code I modified. Take a look when you have time. Lastly, looking forward to your new code. Many thanks, as always.
I made just minor adjustments to bb_thermal_coupling_model.jl
.
I just added a function call in the heat flux and force calculations to incorporate the correction factors calculated in th.jl
and modify.jl
into the computations. (th.jl
and modify.jl
are both the same as yesterday, no changes.)
thermal flux
function pflux_point!(s::BBTStorage, bd::Peridynamics.BondDiscretization, ::BBTMaterial,
param::BBTPointParameters, i::Int)
for bond_id in Peridynamics.each_bond_idx(bd, i)
bond = bd.bonds[bond_id]
j, L = bond.neighbor, bond.length
############## introduced datas into the calculation #####newly added
mbond = get_init_mbd(mm, bond_id)
volm = mbond.vol_m
mof_th = mbond.surf_th
##############
Δxijx = s.position[1, j] - s.position[1, i]
Δxijy = s.position[2, j] - s.position[2, i]
Δxijz = s.position[3, j] - s.position[3, i]
Δvijx = s.velocity[1, j] - s.velocity[1, i]
Δvijy = s.velocity[2, j] - s.velocity[2, i]
Δvijz = s.velocity[3, j] - s.velocity[3, i]
l = sqrt(Δxijx * Δxijx + Δxijy * Δxijy + Δxijz * Δxijz)
ev = (Δxijx * Δvijx + Δxijy * Δvijy + Δxijz * Δvijz) / l
Δtem = s.temperature[j] - s.temperature[i]
s.pflux[i] += s.bond_active[bond_id] * (param.kp * Δtem / L -
ev * 0.5 * param.bc * param.aph) * bd.volume[j] * volm * mof_th ### modifys coefficient
end
return nothing
end
force density
function Peridynamics.force_density_point!(s::BBTStorage,
bd::Peridynamics.BondDiscretization,
::BBTMaterial, param::BBTPointParameters, i::Int)
for bond_id in Peridynamics.each_bond_idx(bd, i)
bond = bd.bonds[bond_id]
j, L = bond.neighbor, bond.length
######### introduced datas into the calculation#####newly added
mbond = get_init_mbd(mm, bond_id)
volm = mbond.vol_m
mof_mh = mbond.surf_mh
#########
# current bond length
Δxijx = s.position[1, j] - s.position[1, i]
Δxijy = s.position[2, j] - s.position[2, i]
Δxijz = s.position[3, j] - s.position[3, i]
l = sqrt(Δxijx * Δxijx + Δxijy * Δxijy + Δxijz * Δxijz)
# bond strain
εm = (l - L) / L
εt = 0.5 * (s.temperature[j] - s.temperature[i]) * param.aph
ε = εm + εt
# failure mechanism
if ε > param.εc && bond.fail_permit
s.bond_active[bond_id] = false
end
s.n_active_bonds[i] += s.bond_active[bond_id]
# update of force density
temp = s.bond_active[bond_id] * param.bc * ε / l * bd.volume[j] * volm * mof_mh ### modifys coefficient
s.b_int[1, i] += temp * Δxijx
s.b_int[2, i] += temp * Δxijy
s.b_int[3, i] += temp * Δxijz
end
return nothing
end
Function
#####newly added
@inline get_init_mbd(modifys_coefficients::MbondDiscretization, point_id::Int64) = modifys_coefficients.bonds[point_id]
@ShiWeiHuH @vavrines I have a question regarding your surface correction factors. In your code, you used:
0.6 * 1e-6 * mpm.E
How did you derive these analytical strain energy density? The surface correction works correctly with this value, but I would like to better understand the assumptions behind it.
Hi, @kaipartmann
You can take a look at this simple derivation.
In addition, I would like to ask you what is the command to execute multi-threading or multi-node parallelism.
Also, I see that you have corrected the surface effect, and it seems that the volume has not been corrected. After all, the volume at the boundary of the near-field domain is not necessarily complete.
Hi @ShiWeiHuH, Thank you very much for your detailed description! I added an issue (#94) because the OSBMaterial
allows for the use of arbitrary Poisson's ratios.
The parallelism functionality is implemented at a very high level. With the PointDecomposition
, the Body
is chopped into multiple BodyChunks
, where each chunk contains all relevant information for the simulation. Depending on the type of parallelism, either a ThreadsDataHandler
or a MPIDataHandler
is created that contain all the body chunks and all information for the simulation.
Then, everything is done on the body chunk level. For multithreading, each thread works on its chunk: https://github.com/kaipartmann/Peridynamics.jl/blob/9bb65ae8e467532ff53e34be67bd66e2434feb86/src/time_solvers/velocity_verlet.jl#L212-L233 For MPI, each process uses its chunk, and then the processes need to communicate to exchange the information of points at the chunk border (halo points): https://github.com/kaipartmann/Peridynamics.jl/blob/9bb65ae8e467532ff53e34be67bd66e2434feb86/src/time_solvers/velocity_verlet.jl#L250-L264
If you have further questions regarding the parallelism, please do not hesitate to contact me.
I did not include the volume correction because it needs a uniformly distributed point cloud to be correct, which is not guaranteed with the current approach of our package. If someone uses an arbitrary mesh with Abaqus and converts that into a point cloud, the volume correction will introduce errors, and the point spacing is unknown.
However, from our observations, the correspondence formulation is also very precise with arbitrary meshes, and the volume error had only a very negligible effect on the simulation results, so we did not prioritize implementing it.
Do you have observations on how much the volume error influences the simulation results in your thermo-mechanical coupled simulations? If you use the correspondence formulation instead of the bond-based formulation, all the corrections could theoretically be dismissed.
However, I have some ideas about how to guarantee that a point cloud is uniformly distributed with a given point spacing. This would again break the current API but make it possible to use volume correction if a point cloud is guaranteed to be uniform and to ignore it otherwise. I will open an issue and ping you if my idea is clearer.
Hi, @kaipartmann It's been a while!
I noticed that PD has a new version with many great features. That's fantastic!
I have a couple of questions:
Currently, I'm using single-thread computation with one region. If I want to switch to using 64 threads, should I set the environment variable NUM=64 first? Will this automatically divide the region into 64 blocks?
Can computation be resumed if it shuts down unexpectedly?
Hi @ShiWeiHuH, I am very happy you like the new features and changes we made in the last weeks!
To use multiple threads you can use a few different approaches, as also mentioned [here].(https://docs.julialang.org/en/v1/manual/multi-threading/#Starting-Julia-with-multiple-threads)
Use Julia command line options
julia -t 64
julia --threads 64
Specify the number of threads in the VSCode settings If you use VSCode, then you can specify the number of threads for a Julia REPL in the settings.
Setting an environment variable
JULIA_NUM_THREADS=64
You can check how many threads you use with
Threads.nthreads()
The body is then divided in different blocks with distribute_equally
https://github.com/kaipartmann/Peridynamics.jl/blob/bc81309d3057533e2c972a7b356d9f3be762a371/src/discretization/decomposition.jl#L18-L44
You can check the different regions with
body = ...
n_chunks = 64
point_decomp = Peridynamics.PointDecomposition(body, n_chunks)
point_decomp.decomp # Vector with n_chunks elements and a range of the point ids for each region
For now, it is not possible to resume simulations. The current approach is to capture as many bugs as possible before submitting the simulation job. If a simulation stops unexpectedly, all exported data up to this point is preserved.
However, the main reason I have not considered it for now is performance. It would be necessary to export the current state of the data handler regularly, which would then take a significant fraction of the simulation time (I estimate up to 50% for some setups).
I made an issue https://github.com/kaipartmann/Peridynamics.jl/issues/144, so maybe there is a way to do it efficiently, and it will be included in a future version!
Hi @kaipartmann
We're working on the thermo-mechanical coupling model. A script from scratch is here (https://github.com/vavrines/KitPD.jl/blob/main/couple/script.jl). We're just about to clean and refactor the codes. The idea is to reuse the structs and methods here as much as possible. I'd like to know if you're interested in implementing this functionality. If things go well, we should be able to contribute codes, but your assistance will likely be needed.