Granular.jl

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

commit 6a2b205579d371f3ce2760cc445517592956600c
parent b640f26eebec4330354379ec734a996089ec7def
Author: Anders Damsgaard <andersd@riseup.net>
Date:   Wed, 21 Feb 2018 11:28:03 -0500

Keep track of thermal energy on the particle level

Diffstat:
Msrc/datatypes.jl | 4++++
Msrc/grain.jl | 41+++++++++++++++++++++++++++++++++++++++--
Msrc/interaction.jl | 13+++++++++++--
Msrc/io.jl | 3+++
Mtest/collision-2floes-oblique.jl | 12+++++++++---
Mtest/vtk.jl | 2+-
6 files changed, 67 insertions(+), 8 deletions(-)

diff --git a/src/datatypes.jl b/src/datatypes.jl @@ -70,6 +70,8 @@ mutable struct GrainCylindrical ocean_stress::Vector{Float64} atmosphere_stress::Vector{Float64} + thermal_energy::Float64 + # Visualization parameters color::Int end @@ -153,6 +155,8 @@ mutable struct GrainArrays ocean_stress::Array{Float64, 2} atmosphere_stress::Array{Float64, 2} + thermal_energy::Vector{Float64} + color::Vector{Int} end diff --git a/src/grain.jl b/src/grain.jl @@ -25,7 +25,9 @@ export addGrainCylindrical! rotating, enabled, verbose, ocean_grid_pos, atmosphere_grid_pos, n_contact, granular_stress, ocean_stress, - atmosphere_stress]) + atmosphere_stress, + thermal_energy, + color]) Creates and adds a cylindrical grain to a simulation. Most of the arguments are optional, and come with default values. The only required arguments are @@ -99,6 +101,7 @@ are optional, and come with default values. The only required arguments are ocean drag [Pa]. * `atmosphere_stress::Vector{Float64} = [0., 0.]`: resultant stress on grain from atmosphere drag [Pa]. +* `thermal_energy::Float64 = 0.0`: thermal energy of grain [J]. * `color::Int=0`: type number, usually used for associating a color to the grain during visualization. @@ -170,6 +173,7 @@ function addGrainCylindrical!(simulation::Simulation, granular_stress::Vector{Float64} = [0., 0.], ocean_stress::Vector{Float64} = [0., 0.], atmosphere_stress::Vector{Float64} = [0., 0.], + thermal_energy::Float64 = 0., color::Int = 0) # Check input values @@ -267,6 +271,8 @@ function addGrainCylindrical!(simulation::Simulation, ocean_stress, atmosphere_stress, + thermal_energy, + color ) @@ -435,6 +441,9 @@ function convertGrainDataToArrays(simulation::Simulation) ## atmosphere_stress zeros(Float64, 3, length(simulation.grains)), + ## thermal_energy + Array{Float64}(length(simulation.grains)), + # Visualization parameters ## color Array{Int}(length(simulation.grains)), @@ -512,6 +521,8 @@ function convertGrainDataToArrays(simulation::Simulation) ifarr.atmosphere_stress[1:2, i] = simulation.grains[i].atmosphere_stress + ifarr.thermal_energy[i] = simulation.grains[i].thermal_energy + ifarr.color[i] = simulation.grains[i].color end @@ -578,6 +589,8 @@ function deleteGrainArrays!(ifarr::GrainArrays) ifarr.ocean_stress = f2 ifarr.atmosphere_stress = f2 + ifarr.thermal_energy = f1 + ifarr.color = i1 gc() nothing @@ -643,7 +656,9 @@ function printGrainInfo(f::GrainCylindrical) println(" granular_stress: $(f.granular_stress) Pa") println(" ocean_stress: $(f.ocean_stress) Pa") - println(" atmosphere_stress: $(f.atmosphere_stress) Pa") + println(" atmosphere_stress: $(f.atmosphere_stress) Pa\n") + + println(" thermal_energy: $(f.thermal_energy) J\n") println(" color: $(f.color)\n") nothing @@ -690,6 +705,26 @@ function totalGrainKineticRotationalEnergy(simulation::Simulation) return E_sum end +export grainThermalEnergy +"Returns the thermal energy of the grain, produced by Coulomb slip" +function grainThermalEnergy(grain::GrainCylindrical) + return grain.thermal_energy +end + +export totalGrainThermalEnergy +""" + totalGrainKineticTranslationalEnergy(simulation) + +Returns the sum of thermal energy of all grains in a simulation +""" +function totalGrainThermalEnergy(simulation::Simulation) + E_sum = 0. + for grain in simulation.grains + E_sum += grainThermalEnergy(grain) + end + return E_sum +end + export addBodyForce! """ setBodyForce!(grain, force) @@ -791,6 +826,8 @@ function compareGrains(if1::GrainCylindrical, if2::GrainCylindrical) @test if1.ocean_stress ≈ if2.ocean_stress @test if1.atmosphere_stress ≈ if2.atmosphere_stress + @test if1.thermal_energy ≈ if2.thermal_energy + @test if1.color ≈ if2.color nothing end diff --git a/src/interaction.jl b/src/interaction.jl @@ -256,9 +256,14 @@ function interactGrains!(simulation::Simulation, i::Int, j::Int, ic::Int) elseif k_t ≈ 0. && γ_t > 0. force_t = abs(γ_t * vel_t) + + # Coulomb slip if force_t > μ_d_minimum*abs(force_n) force_t = μ_d_minimum*abs(force_n) - simulation.grains[i].contact_age[ic] = -simulation.time_step + simulation.grains[i].contact_age[ic] = 0.0 + E_shear = abs(force_t)*vel_t*simulation.time_step + simulation.grains[i].thermal_energy += 0.5*E_shear + simulation.grains[j].thermal_energy += 0.5*E_shear end if vel_t > 0. force_t = -force_t @@ -268,10 +273,14 @@ function interactGrains!(simulation::Simulation, i::Int, j::Int, ic::Int) force_t = -k_t*δ_t - γ_t*vel_t + # Coulomb slip if abs(force_t) > μ_d_minimum*abs(force_n) force_t = μ_d_minimum*abs(force_n)*force_t/abs(force_t) δ_t = (-force_t - γ_t*vel_t)/k_t - simulation.grains[i].contact_age[ic] = -simulation.time_step + simulation.grains[i].contact_age[ic] = 0.0 + E_shear = abs(force_t)*vel_t*simulation.time_step + simulation.grains[i].thermal_energy += 0.5*E_shear + simulation.grains[j].thermal_energy += 0.5*E_shear end else diff --git a/src/io.jl b/src/io.jl @@ -428,6 +428,9 @@ function writeGrainVTK(simulation::Simulation, WriteVTK.vtk_point_data(vtkfile, ifarr.atmosphere_stress, "Atmosphere stress [Pa]") + WriteVTK.vtk_point_data(vtkfile, ifarr.thermal_energy, + "Thermal energy [J]") + WriteVTK.vtk_point_data(vtkfile, ifarr.color, "Color [-]") diff --git a/test/collision-2floes-oblique.jl b/test/collision-2floes-oblique.jl @@ -35,7 +35,11 @@ Granular.run!(sim, temporal_integration_method="Two-term Taylor", verbose=verbos E_kin_lin_final = Granular.totalGrainKineticTranslationalEnergy(sim) E_kin_rot_final = Granular.totalGrainKineticRotationalEnergy(sim) -@test E_kin_lin_init ≈ E_kin_lin_final atol=E_kin_lin_init*tol +E_thermal_final = Granular.totalGrainThermalEnergy(sim) +println(E_kin_lin_init) +println(E_kin_lin_final) +println(E_thermal_final) +@test E_kin_lin_init ≈ E_kin_lin_final+E_thermal_final atol=E_kin_lin_init*tol @test E_kin_rot_init ≈ E_kin_rot_final @@ -48,7 +52,8 @@ Granular.run!(sim, temporal_integration_method="Two-term Taylor", verbose=verbos E_kin_lin_final = Granular.totalGrainKineticTranslationalEnergy(sim) E_kin_rot_final = Granular.totalGrainKineticRotationalEnergy(sim) -@test E_kin_lin_init ≈ E_kin_lin_final atol=E_kin_lin_init*tol +E_thermal_final = Granular.totalGrainThermalEnergy(sim) +@test E_kin_lin_init ≈ E_kin_lin_final+E_thermal_final atol=E_kin_lin_init*tol @test E_kin_rot_init ≈ E_kin_rot_final @@ -61,7 +66,8 @@ Granular.run!(sim, temporal_integration_method="Three-term Taylor", verbose=verb E_kin_lin_final = Granular.totalGrainKineticTranslationalEnergy(sim) E_kin_rot_final = Granular.totalGrainKineticRotationalEnergy(sim) -@test E_kin_lin_init ≈ E_kin_lin_final atol=E_kin_lin_init*tol +E_thermal_final = Granular.totalGrainThermalEnergy(sim) +@test E_kin_lin_init ≈ E_kin_lin_final+E_thermal_final atol=E_kin_lin_init*tol @test E_kin_rot_init ≈ E_kin_rot_final info("# Ice floes free to move") diff --git a/test/vtk.jl b/test/vtk.jl @@ -29,7 +29,7 @@ end grainpath = "test/test.grains.1.vtu" grainchecksum = -"8ce4e4045d150fc75cdb4126edcb32cb4d09f297065602a075cbe34dceef27c7 " * +"f8aa4ab923b2466d7a6ffb835bfff4d0e0ff0a168ff267431a082bb3018caaa1 " * grainpath * "\n" graininteractionpath = "test/test.grain-interaction.1.vtp"