Granular.jl

Julia package for granular dynamics simulation
git clone git://src.adamsgaard.dk/Granular.jl
Log | Files | Refs | README | LICENSE

commit 8c6f1f493f21bb6512ce390951af2aa1e3d33bfd
parent 6e04488619808a281e658e6ca8a104354eacc98d
Author: Anders Damsgaard <andersd@riseup.net>
Date:   Tue,  2 May 2017 14:03:11 -0400

implement tangential viscosity and friction

Diffstat:
Msrc/interaction.jl | 110++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/simulation.jl | 8+++++---
Atest/collision-2floes-oblique.jl | 256+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtest/runtests.jl | 1+
4 files changed, 338 insertions(+), 37 deletions(-)

diff --git a/src/interaction.jl b/src/interaction.jl @@ -5,7 +5,8 @@ export interact! Resolve mechanical interaction between all particle pairs. """ function interact!(simulation::Simulation; - contact_model::String = "Linear Elastic No Tangential") + contact_normal_rheology::String = "Linear Elastic", + contact_tangential_rheology::String = "None") # IceFloe to grain collisions while !isempty(simulation.contact_pairs) @@ -15,7 +16,9 @@ function interact!(simulation::Simulation; pop!(simulation.contact_parallel_displacement) interactIceFloes!(simulation, contact_pair[1], contact_pair[2], overlap_vector, contact_parallel_displacement, - contact_model=contact_model) + contact_normal_rheology=contact_normal_rheology, + contact_tangential_rheology= + contact_tangential_rheology) end end @@ -26,34 +29,42 @@ function adds the compressive force of the interaction to the ice floe `pressure` field of mean compressive stress on the ice floe sides. """ function interactIceFloes!(simulation::Simulation, - i::Integer, j::Integer, + i::Int, j::Int, overlap_vector::Array{Float64, 1}, contact_parallel_displacement::Array{Float64, 1}; - contact_model::String = - "Linear Elastic No Tangential") + contact_normal_rheology::String = "Linear Elastic", + contact_tangential_rheology::String = "None") - force = zeros(2) + force_n = zeros(2) + force_t = zeros(2) - if contact_model == "None" - return nothing - - elseif contact_model == "Linear Elastic No Tangential" || - contact_model == "LinearElastic" + if contact_normal_rheology == "None" + # do nothing + elseif contact_normal_rheology == "Linear Elastic" force_n = interactNormalLinearElastic(simulation, i, j, overlap_vector) + else + error("Unknown contact_normal_rheology '$contact_normal_rheology'") + end - if contact_model == "Linear Elastic" - force_t, torque = interactTangentialLinearElasticFrictional( - simulation, i, j, - overlap_vector, - contact_parallel_displacement) - end - + if contact_tangential_rheology == "None" + # do nothing + elseif contact_tangential_rheology == "Linear Viscous Frictional" + force_t = interactTangentialLinearViscousFrictional(simulation, i, j, + overlap_vector, + force_n) else - error("Unknown contact_model interaction model '$contact_model'") + error("Unknown contact_tangential_rheology ", + "'$contact_tangential_rheology'") end - simulation.ice_floes[i].force += force_n; - simulation.ice_floes[j].force -= force_n; + simulation.ice_floes[i].force += force_n + force_t; + simulation.ice_floes[j].force -= force_n + force_t; + + if norm(force_t) > 0. + torque = -findTorque(simulation, overlap_vector, force_t, i, j) + simulation.ice_floes[i].torque += torque + simulation.ice_floes[j].torque += torque + end simulation.ice_floes[i].pressure += norm(force_n)/simulation.ice_floes[i].side_surface_area; @@ -67,7 +78,7 @@ Resolves linear-elastic interaction between two ice floes in the contact-normal direction. """ function interactNormalLinearElastic(simulation::Simulation, - i::Integer, j::Integer, + i::Int, j::Int, overlap_vector::vector) k_n_harmonic_mean = @@ -82,25 +93,56 @@ export interactTangentialLinearElastic Resolves linear-elastic interaction between two ice floes in the contact-parallel (tangential) direction. """ -function interactTangentialLinearElasticFrictional(simulation::Simulation, - i::Integer, j::Integer, - overlap_vector::vector, - contact_parallel_displacement::vector) +function interactTangentialLinearViscousFrictional(simulation::Simulation, + i::Int, j::Integer, + overlap_vector::vector, + force_n::vector) - k_t_harmonic_mean = - harmonicMean(simulation.ice_floes[i].contact_stiffness_tangential, - simulation.ice_floes[j].contact_stiffness_tangential) + contact_parallel_velocity = findContactParallelVelocity(simulation, i, j, + overlap_vector) - # correct displacement for contact rotation - n = overlap_vector/norm(overlap_vector) - contact_parallel_displacement -= (n * dot(n, contact_parallel_displacement)) + if norm(contact_parallel_velocity) ≈ 0. + return [0., 0.] + end + + gamma_t_harmonic_mean = harmonicMean( + simulation.ice_floes[i].contact_viscosity_tangential, + simulation.ice_floes[j].contact_viscosity_tangential) - force_t = k_t_harmonic_mean * contact_parallel_displacement + if norm(gamma_t_harmonic_mean) ≈ 0. + return [0., 0.] + end - return force, torque, contact_parallel_displacement + mu_d_minimum = min(simulation.ice_floes[i].contact_dynamic_friction, + simulation.ice_floes[j].contact_dynamic_friction) + return -min(norm(gamma_t_harmonic_mean*contact_parallel_velocity), + mu_d_minimum*norm(force_n))* + contact_parallel_velocity/norm(contact_parallel_velocity) end function harmonicMean(a::Any, b::Any) return 2.*a*b/(a + b) end + +function findTorque(simulation::Simulation, overlap_vector::vector, + force_t::vector, i::Int, j::Int) + n = overlap_vector/norm(overlap_vector) + return -findEffectiveRadius(simulation, i, j, overlap_vector)* + (n[1]*force_t[2] - n[2]*force_t[1]) +end + +function findEffectiveRadius(simulation::Simulation, i::Int, j::Int, + overlap_vector::vector) + return harmonicMean(simulation.ice_floes[i].contact_radius, + simulation.ice_floes[j].contact_radius) + - norm(overlap_vector)/2. +end + +function findContactParallelVelocity(simulation::Simulation, i::Int, j::Int, + overlap_vector::vector) + return simulation.ice_floes[i].lin_vel - + simulation.ice_floes[j].lin_vel + + findEffectiveRadius(simulation, i, j, overlap_vector)* + (simulation.ice_floes[i].ang_vel + simulation.ice_floes[j].ang_vel) +end diff --git a/src/simulation.jl b/src/simulation.jl @@ -89,8 +89,8 @@ function run!(simulation::Simulation; show_file_output::Bool=true, single_step::Bool=false, temporal_integration_method::String="Three-term Taylor", - contact_model::String="Three-term Taylor", - ) + contact_normal_rheology::String = "Linear Elastic", + contact_tangential_rheology::String = "None") if single_step && simulation.time >= simulation.time_total simulation.time_total += simulation.time_step @@ -122,7 +122,9 @@ function run!(simulation::Simulation; else findContacts!(simulation, method="all to all") end - interact!(simulation) + interact!(simulation, + contact_normal_rheology=contact_normal_rheology, + contact_tangential_rheology=contact_tangential_rheology) if typeof(simulation.ocean.input_file) != Bool addOceanDrag!(simulation) end diff --git a/test/collision-2floes-oblique.jl b/test/collision-2floes-oblique.jl @@ -0,0 +1,256 @@ +#!/usr/bin/env julia + +# Check for conservation of kinetic energy (=momentum) during a normal collision +# between two ice cylindrical ice floes + +info("#### $(basename(@__FILE__)) ####") + +verbose=false + +info("## Contact-normal elasticity only") +info("# One ice floe fixed") +sim = SeaIce.createSimulation(id="test") +SeaIce.addIceFloeCylindrical(sim, [0., 10.], 10., 1., verbose=verbose) +SeaIce.addIceFloeCylindrical(sim, [19., 0.], 10., 1., verbose=verbose) +sim.ice_floes[1].lin_vel[1] = 0.1 +sim.ice_floes[2].fixed = true + +E_kin_lin_init = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_init = SeaIce.totalIceFloeKineticRotationalEnergy(sim) + +# With decreasing timestep (epsilon towards 0), the explicit integration scheme +# should become more correct + +SeaIce.setTotalTime!(sim, 30.0) +#sim.file_time_step = 1. +sim_init = deepcopy(sim) + +info("Testing kinetic energy conservation with Two-term Taylor scheme") +SeaIce.setTimeStep!(sim, epsilon=0.07) +tol = 0.2 +info("Relative tolerance: $(tol*100.)% with time step: $(sim.time_step)") +SeaIce.run!(sim, temporal_integration_method="Two-term Taylor", + contact_tangential_rheology="None", verbose=verbose) + +E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim) +@test_approx_eq_eps E_kin_lin_init E_kin_lin_final E_kin_lin_init*tol +@test_approx_eq E_kin_rot_init E_kin_rot_final + + +info("Testing kinetic energy conservation with Two-term Taylor scheme") +sim = deepcopy(sim_init) +SeaIce.setTimeStep!(sim, epsilon=0.007) +tol = 0.02 +info("Relative tolerance: $(tol*100.)%") +SeaIce.run!(sim, temporal_integration_method="Two-term Taylor", + contact_tangential_rheology="None", verbose=verbose) + +E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim) +@test_approx_eq_eps E_kin_lin_init E_kin_lin_final E_kin_lin_init*tol +@test_approx_eq E_kin_rot_init E_kin_rot_final + + +info("Testing kinetic energy conservation with Three-term Taylor scheme") +sim = deepcopy(sim_init) +SeaIce.setTimeStep!(sim, epsilon=0.07) +tol = 0.01 +info("Relative tolerance: $(tol*100.)% with time step: $(sim.time_step)") +SeaIce.run!(sim, temporal_integration_method="Three-term Taylor", + contact_tangential_rheology="None", verbose=verbose) + +E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim) +@test_approx_eq_eps E_kin_lin_init E_kin_lin_final E_kin_lin_init*tol +@test_approx_eq E_kin_rot_init E_kin_rot_final + +info("# Ice floes free to move") + +sim = SeaIce.createSimulation(id="test") +SeaIce.addIceFloeCylindrical(sim, [0., 10.], 10., 1., verbose=verbose) +SeaIce.addIceFloeCylindrical(sim, [19.0, 0.], 10., 1., verbose=verbose) +sim.ice_floes[1].lin_vel[1] = 0.1 + +E_kin_lin_init = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_init = SeaIce.totalIceFloeKineticRotationalEnergy(sim) + +# With decreasing timestep (epsilon towards 0), the explicit integration scheme +# should become more correct + +SeaIce.setTotalTime!(sim, 30.0) +sim_init = deepcopy(sim) + +info("Testing kinetic energy conservation with Two-term Taylor scheme") +SeaIce.setTimeStep!(sim, epsilon=0.07) +tol = 0.2 +info("Relative tolerance: $(tol*100.)% with time step: $(sim.time_step)") +SeaIce.run!(sim, temporal_integration_method="Two-term Taylor", + contact_tangential_rheology="None", verbose=verbose) + +E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim) +@test_approx_eq_eps E_kin_lin_init E_kin_lin_final E_kin_lin_init*tol +@test_approx_eq E_kin_rot_init E_kin_rot_final + + +info("Testing kinetic energy conservation with Two-term Taylor scheme") +sim = deepcopy(sim_init) +SeaIce.setTimeStep!(sim, epsilon=0.007) +tol = 0.02 +info("Relative tolerance: $(tol*100.)%") +SeaIce.run!(sim, temporal_integration_method="Two-term Taylor", + contact_tangential_rheology="None", verbose=verbose) + +E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim) +@test_approx_eq_eps E_kin_lin_init E_kin_lin_final E_kin_lin_init*tol +@test_approx_eq E_kin_rot_init E_kin_rot_final + + +info("Testing kinetic energy conservation with Three-term Taylor scheme") +sim = deepcopy(sim_init) +SeaIce.setTimeStep!(sim, epsilon=0.07) +tol = 0.01 +info("Relative tolerance: $(tol*100.)% with time step: $(sim.time_step)") +SeaIce.run!(sim, temporal_integration_method="Three-term Taylor", + contact_tangential_rheology="None", verbose=verbose) + +E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim) +@test_approx_eq_eps E_kin_lin_init E_kin_lin_final E_kin_lin_init*tol +@test_approx_eq E_kin_rot_init E_kin_rot_final + + +info("## Contact-normal elasticity and tangential viscosity and friction") +info("# One ice floe fixed") +sim = SeaIce.createSimulation(id="test") +SeaIce.addIceFloeCylindrical(sim, [0., 10.], 10., 1., verbose=verbose) +SeaIce.addIceFloeCylindrical(sim, [19., 0.], 10., 1., verbose=verbose) +sim.ice_floes[1].lin_vel[1] = 0.1 +sim.ice_floes[2].fixed = true + +E_kin_lin_init = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_init = SeaIce.totalIceFloeKineticRotationalEnergy(sim) + +# With decreasing timestep (epsilon towards 0), the explicit integration scheme +# should become more correct + +SeaIce.setTotalTime!(sim, 30.0) +#sim.file_time_step = 1. +sim_init = deepcopy(sim) + +info("Testing kinetic energy conservation with Two-term Taylor scheme") +SeaIce.setTimeStep!(sim, epsilon=0.07) +tol = 0.5 +info("Relative tolerance: $(tol*100.)% with time step: $(sim.time_step)") +SeaIce.run!(sim, temporal_integration_method="Two-term Taylor", + contact_tangential_rheology="Linear Viscous Frictional", + verbose=verbose) + +@test sim.ice_floes[1].ang_pos > 0. +@test sim.ice_floes[1].ang_vel > 0. +@test sim.ice_floes[2].ang_pos ≈ 0. +@test sim.ice_floes[2].ang_vel ≈ 0. +E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim) +@test_approx_eq_eps E_kin_lin_init+E_kin_rot_init E_kin_lin_final+E_kin_rot_final E_kin_lin_init*tol + + +info("Testing kinetic energy conservation with Two-term Taylor scheme") +sim = deepcopy(sim_init) +SeaIce.setTimeStep!(sim, epsilon=0.007) +tol = 0.2 +info("Relative tolerance: $(tol*100.)%") +SeaIce.run!(sim, temporal_integration_method="Two-term Taylor", + contact_tangential_rheology="Linear Viscous Frictional", + verbose=verbose) + +@test sim.ice_floes[1].ang_pos > 0. +@test sim.ice_floes[1].ang_vel > 0. +@test sim.ice_floes[2].ang_pos ≈ 0. +@test sim.ice_floes[2].ang_vel ≈ 0. +E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim) +@test_approx_eq_eps E_kin_lin_init+E_kin_rot_init E_kin_lin_final+E_kin_rot_final E_kin_lin_init*tol + + +info("Testing kinetic energy conservation with Three-term Taylor scheme") +sim = deepcopy(sim_init) +SeaIce.setTimeStep!(sim, epsilon=0.07) +tol = 0.2 +info("Relative tolerance: $(tol*100.)% with time step: $(sim.time_step)") +SeaIce.run!(sim, temporal_integration_method="Three-term Taylor", + contact_tangential_rheology="Linear Viscous Frictional", + verbose=verbose) + +@test sim.ice_floes[1].ang_pos > 0. +@test sim.ice_floes[1].ang_vel > 0. +@test sim.ice_floes[2].ang_pos ≈ 0. +@test sim.ice_floes[2].ang_vel ≈ 0. +E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim) +@test_approx_eq_eps E_kin_lin_init+E_kin_rot_init E_kin_lin_final+E_kin_rot_final E_kin_lin_init*tol + +info("# Ice floes free to move") + +sim = SeaIce.createSimulation(id="test") +SeaIce.addIceFloeCylindrical(sim, [0., 10.], 10., 1., verbose=verbose) +SeaIce.addIceFloeCylindrical(sim, [19.0, 0.], 10., 1., verbose=verbose) +sim.ice_floes[1].lin_vel[1] = 0.1 + +E_kin_lin_init = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_init = SeaIce.totalIceFloeKineticRotationalEnergy(sim) + +# With decreasing timestep (epsilon towards 0), the explicit integration scheme +# should become more correct + +SeaIce.setTotalTime!(sim, 30.0) +sim_init = deepcopy(sim) + +info("Testing kinetic energy conservation with Two-term Taylor scheme") +SeaIce.setTimeStep!(sim, epsilon=0.07) +tol = 0.2 +info("Relative tolerance: $(tol*100.)% with time step: $(sim.time_step)") +SeaIce.run!(sim, temporal_integration_method="Two-term Taylor", + contact_tangential_rheology="Linear Viscous Frictional", + verbose=verbose) + +@test sim.ice_floes[1].ang_pos > 0. +@test sim.ice_floes[1].ang_vel > 0. +@test sim.ice_floes[2].ang_pos > 0. +@test sim.ice_floes[2].ang_vel > 0. +E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim) +@test_approx_eq_eps E_kin_lin_init+E_kin_rot_init E_kin_lin_final+E_kin_rot_final E_kin_lin_init*tol + +info("Testing kinetic energy conservation with Two-term Taylor scheme") +sim = deepcopy(sim_init) +SeaIce.setTimeStep!(sim, epsilon=0.007) +tol = 0.1 +info("Relative tolerance: $(tol*100.)%") +SeaIce.run!(sim, temporal_integration_method="Two-term Taylor", + contact_tangential_rheology="Linear Viscous Frictional", + verbose=verbose) + +E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim) +@test_approx_eq_eps E_kin_lin_init+E_kin_rot_init E_kin_lin_final+E_kin_rot_final E_kin_lin_init*tol + + +info("Testing kinetic energy conservation with Three-term Taylor scheme") +sim = deepcopy(sim_init) +SeaIce.setTimeStep!(sim, epsilon=0.07) +tol = 0.1 +info("Relative tolerance: $(tol*100.)% with time step: $(sim.time_step)") +SeaIce.run!(sim, temporal_integration_method="Three-term Taylor", + contact_tangential_rheology="Linear Viscous Frictional", + verbose=verbose) + +@test sim.ice_floes[1].ang_pos > 0. +@test sim.ice_floes[1].ang_vel > 0. +@test sim.ice_floes[2].ang_pos > 0. +@test sim.ice_floes[2].ang_vel > 0. +E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim) +E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim) +@test_approx_eq_eps E_kin_lin_init+E_kin_rot_init E_kin_lin_final+E_kin_rot_final E_kin_lin_init*tol diff --git a/test/runtests.jl b/test/runtests.jl @@ -3,6 +3,7 @@ using Base.Test include("contact-search-and-geometry.jl") include("collision-2floes-normal.jl") +include("collision-2floes-oblique.jl") include("netcdf.jl") include("vtk.jl") include("grid.jl")