tinclude tangential interactions with non-rotating particles - Granular.jl - Julia package for granular dynamics simulation
 (HTM) git clone git://src.adamsgaard.dk/Granular.jl
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 8268169fbd4edcf11db3621ece0e1496d9b0e25d
 (DIR) parent 5ac16e5a720ebb6d1d93d253f3d8a06ab2800b3a
 (HTM) Author: Anders Damsgaard <anders@adamsgaard.dk>
       Date:   Tue, 13 Jul 2021 14:58:58 +0200
       
       include tangential interactions with non-rotating particles
       
       tto get the old rotate=false behavior physics, set both:
               grain.contact_dynamic_friction = 0.0
               grain.contact_viscosity_tangential = 0.0
       
       Diffstat:
         M src/interaction.jl                  |     120 ++++++++++++-------------------
       
       1 file changed, 45 insertions(+), 75 deletions(-)
       ---
 (DIR) diff --git a/src/interaction.jl b/src/interaction.jl
       t@@ -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)
       t@@ -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
       t@@ -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
        
       t@@ -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.
       t@@ -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;