Granular.jl

Julia package for granular dynamics simulation
git clone git://src.adamsgaard.dk/Granular.jl # fast
git clone https://src.adamsgaard.dk/Granular.jl.git # slow
Log | Files | Refs | README | LICENSE Back to index

commit 8268169fbd4edcf11db3621ece0e1496d9b0e25d
parent 5ac16e5a720ebb6d1d93d253f3d8a06ab2800b3a
Author: Anders Damsgaard <anders@adamsgaard.dk>
Date:   Tue, 13 Jul 2021 14:58:58 +0200

include tangential interactions with non-rotating particles

to get the old rotate=false behavior physics, set both:
	grain.contact_dynamic_friction = 0.0
	grain.contact_viscosity_tangential = 0.0

Diffstat:
Msrc/interaction.jl | 120++++++++++++++++++++++++++++++-------------------------------------------------
1 file changed, 45 insertions(+), 75 deletions(-)

diff --git a/src/interaction.jl b/src/interaction.jl @@ -145,31 +145,23 @@ function interactGrains!(simulation::Simulation, i::Int, j::Int, ic::Int) simulation.grains[j].lin_vel[1:2] vel_n = dot(vel_lin, n) - if !simulation.grains[i].rotating && !simulation.grains[j].rotating - rotation = false + vel_t = dot(vel_lin, t) - + harmonicMean(r_i, r_j)*(simulation.grains[i].ang_vel[3] + + simulation.grains[j].ang_vel[3]) + + # Correct old tangential displacement for contact rotation and add new + δ_t0 = simulation.grains[i].contact_parallel_displacement[ic][1:2] + if !simulation.grains[i].compressive_failure[ic] + δ_t = dot(t, δ_t0 - (n*dot(n, δ_t0))) + vel_t*simulation.time_step else - rotation = true + # Use δ_t as total slip-distance vector + δ_t = δ_t0 .+ (vel_lin .+ vel_t.*t) .* simulation.time_step end - - if rotation - vel_t = dot(vel_lin, t) - - harmonicMean(r_i, r_j)*(simulation.grains[i].ang_vel[3] + - simulation.grains[j].ang_vel[3]) - - # Correct old tangential displacement for contact rotation and add new - δ_t0 = simulation.grains[i].contact_parallel_displacement[ic][1:2] - if !simulation.grains[i].compressive_failure[ic] - δ_t = dot(t, δ_t0 - (n*dot(n, δ_t0))) + vel_t*simulation.time_step - else - # Use δ_t as total slip-distance vector - δ_t = δ_t0 .+ (vel_lin .+ vel_t.*t) .* simulation.time_step - end - # Determine the contact rotation (2d) - θ_t = simulation.grains[i].contact_rotation[ic][3] + - (simulation.grains[j].ang_vel[3] - - simulation.grains[i].ang_vel[3]) * simulation.time_step - end + # Determine the contact rotation (2d) + θ_t = simulation.grains[i].contact_rotation[ic][3] + + (simulation.grains[j].ang_vel[3] - + simulation.grains[i].ang_vel[3]) * simulation.time_step # Effective radius R_ij = harmonicMean(r_i, r_j) @@ -198,30 +190,24 @@ function interactGrains!(simulation::Simulation, i::Int, j::Int, ic::Int) # Effective normal and tangential stiffness k_n = E * A_ij/R_ij #k_t = k_n*ν # Kneib et al 2016 - if rotation - k_t = k_n * 2. * (1. - ν^2.) / ((2. - ν) * (1. + ν)) # Obermayr 2011 - end + k_t = k_n * 2. * (1. - ν^2.) / ((2. - ν) * (1. + ν)) # Obermayr 2011 else # Micromechanical parameterization: k_n and k_t set explicitly k_n = harmonicMean(simulation.grains[i].contact_stiffness_normal, simulation.grains[j].contact_stiffness_normal) - if rotation - k_t = harmonicMean(simulation.grains[i].contact_stiffness_tangential, - simulation.grains[j].contact_stiffness_tangential) - end + k_t = harmonicMean(simulation.grains[i].contact_stiffness_tangential, + simulation.grains[j].contact_stiffness_tangential) end γ_n = harmonicMean(simulation.grains[i].contact_viscosity_normal, simulation.grains[j].contact_viscosity_normal) - if rotation - γ_t = harmonicMean(simulation.grains[i].contact_viscosity_tangential, - simulation.grains[j].contact_viscosity_tangential) + γ_t = harmonicMean(simulation.grains[i].contact_viscosity_tangential, + simulation.grains[j].contact_viscosity_tangential) - μ_d_minimum = min(simulation.grains[i].contact_dynamic_friction, - simulation.grains[j].contact_dynamic_friction) - end + μ_d_minimum = min(simulation.grains[i].contact_dynamic_friction, + simulation.grains[j].contact_dynamic_friction) # Determine contact forces if k_n ≈ 0. && γ_n ≈ 0. # No interaction @@ -257,39 +243,28 @@ function interactGrains!(simulation::Simulation, i::Int, j::Int, ic::Int) tensile_strength = min(simulation.grains[i].contact_age[ic]* simulation.grains[i].strength_heal_rate, simulation.grains[i].tensile_strength) - if rotation shear_strength = min(simulation.grains[i].contact_age[ic]* simulation.grains[i].strength_heal_rate, simulation.grains[i].shear_strength) - M_t = 0.0 - if tensile_strength > 0.0 - # Determine bending momentum on contact [N*m], - # (converting k_n to E to bar(k_n)) - M_t = (k_n*R_ij/(A_ij*(simulation.grains[i].contact_radius + + M_t = 0.0 + if tensile_strength > 0.0 + # Determine bending momentum on contact [N*m], + # (converting k_n to E to bar(k_n)) + M_t = (k_n*R_ij/(A_ij*(simulation.grains[i].contact_radius + simulation.grains[j].contact_radius)))*I_ij*θ_t - end end # Reset contact age (breaking bond) if bond strength is exceeded - if rotation - if δ_n >= 0.0 && norm(force_n)/A_ij + norm(M_t)*R_ij/I_ij > tensile_strength - force_n = 0. - force_t = 0. - simulation.grains[i].contacts[ic] = 0 # remove contact - simulation.grains[i].n_contacts -= 1 - simulation.grains[j].n_contacts -= 1 - end - else - if δ_n >= 0.0 && norm(force_n)/A_ij > tensile_strength - force_n = 0. - force_t = 0. - simulation.grains[i].contacts[ic] = 0 # remove contact - simulation.grains[i].n_contacts -= 1 - simulation.grains[j].n_contacts -= 1 - end + + if δ_n >= 0.0 && norm(force_n)/A_ij + norm(M_t)*R_ij/I_ij > tensile_strength + force_n = 0. + force_t = 0. + simulation.grains[i].contacts[ic] = 0 # remove contact + simulation.grains[i].n_contacts -= 1 + simulation.grains[j].n_contacts -= 1 end - if rotation && !simulation.grains[i].compressive_failure[ic] + if !simulation.grains[i].compressive_failure[ic] if k_t ≈ 0. && γ_t ≈ 0. # do nothing @@ -408,7 +383,7 @@ function interactGrains!(simulation::Simulation, i::Int, j::Int, ic::Int) end # Break bond under extension through bending failure - if δ_n < 0.0 && tensile_strength > 0.0 && rotation && + if δ_n < 0.0 && tensile_strength > 0.0 && shear_strength > 0.0 && norm(force_t)/A_ij > shear_strength force_n = 0. @@ -420,23 +395,18 @@ function interactGrains!(simulation::Simulation, i::Int, j::Int, ic::Int) simulation.grains[i].contact_age[ic] += simulation.time_step end - if rotation - if simulation.grains[i].compressive_failure[ic] - simulation.grains[i].contact_parallel_displacement[ic] = vecTo3d(δ_t) - else - simulation.grains[i].contact_parallel_displacement[ic] = vecTo3d(δ_t.*t) - end - simulation.grains[i].contact_rotation[ic] = [0., 0., θ_t] - - simulation.grains[i].force += vecTo3d(force_n.*n + force_t.*t); - simulation.grains[j].force -= vecTo3d(force_n.*n + force_t.*t); - - simulation.grains[i].torque[3] += -force_t*R_ij + M_t - simulation.grains[j].torque[3] += -force_t*R_ij - M_t + if simulation.grains[i].compressive_failure[ic] + simulation.grains[i].contact_parallel_displacement[ic] = vecTo3d(δ_t) else - simulation.grains[i].force += vecTo3d(force_n.*n); - simulation.grains[j].force -= vecTo3d(force_n.*n); + simulation.grains[i].contact_parallel_displacement[ic] = vecTo3d(δ_t.*t) end + simulation.grains[i].contact_rotation[ic] = [0., 0., θ_t] + + simulation.grains[i].force += vecTo3d(force_n.*n + force_t.*t); + simulation.grains[j].force -= vecTo3d(force_n.*n + force_t.*t); + + simulation.grains[i].torque[3] += -force_t*R_ij + M_t + simulation.grains[j].torque[3] += -force_t*R_ij - M_t simulation.grains[i].pressure += force_n/simulation.grains[i].side_surface_area;