Granular.jl

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

commit 8b1cd340b84b6f8c0481f128f91a054872906aa8
parent 24ac44e780e53040fa737ea47821045f97588acd
Author: Anders Damsgaard <andersd@riseup.net>
Date:   Fri, 17 Nov 2017 13:24:47 -0500

implement several changes to file IO, use Gnuplot for plotting

Diffstat:
Adeps/build.jl | 41+++++++++++++++++++++++++++++++++++++++++
Msrc/grain.jl | 57+++++++++++++++++++++++++++++++++++++++------------------
Msrc/io.jl | 77++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Mtest/grain.jl | 25+++++++++++--------------
Mtest/jld.jl | 10++++++++++
5 files changed, 169 insertions(+), 41 deletions(-)

diff --git a/deps/build.jl b/deps/build.jl @@ -0,0 +1,41 @@ + +#!/usr/bin/env julia +using BinDeps +@BinDeps.setup + +import Compat +import Compat.Sys + +gnuplot = library_dependency("gnuplot") +imagemagick = library_dependency("imagemagick", aliases = ["ImageMagick"]) + +# Debian derivatives: https://www.debian.org/distrib/packages#search_packages +provides(AptGet, "gnuplot", gnuplot, os = :Linux) +provides(AptGet, "imagemagick", imagemagick, os = :Linux) + +# RHEL derivatives: http://rpm.pbone.net/index.php3/stat/2/simple/2 +provides(Yum, "gnuplot", gnuplot, os = :Linux) +provides(Yum, Dict("ImageMagick" => imagemagick), os = :Linux) + +# Arch: https://www.archlinux.org/packages/ +provides(Pacman, "gnuplot", gnuplot, os = :Linux) +provides(Pacman, "imagemagick", imagemagick, os = :Linux) + +# Mac: http://formulae.brew.sh/ +if Compat.Sys.isapple() + using Homebrew + provides(Homebrew.HB, "gnuplot", gnuplot, os = :Darwin) + provides(Homebrew.HB, "imagemagick", imagemagick, os = :Darwin) +end + +# Windows: http://software.opensuse.org/search +if Compat.Sys.iswindows() + using WinRPM + provides(WinRPM.RPM, "gnuplot", gnuplot, os = :Windows) + provides(WinRPM.RPM, "imagemagick", imagemagick, os = :Windows) +end + +@BinDeps.install Dict([ + (:gnuplot => :gnuplot), + (:imagemagick => :imagemagick), + ]) diff --git a/src/grain.jl b/src/grain.jl @@ -1,12 +1,6 @@ ## Manage grains in the model using Compat.Test -hasPyPlot = false -if typeof(Pkg.installed("PyPlot")) == VersionNumber - import PyPlot - hasPyPlot = true -end - export addGrainCylindrical! """ function addGrainCylindrical!(simulation, lin_pos, contact_radius, @@ -742,7 +736,8 @@ string, and the `filetype`, and is written to the current folder. true). * `skip_fixed::Bool`: ommit grains that are fixed in space from the size distribution (default = true). -* `logy::Bool`: plot y-axis in log scale. +* `log_y::Bool`: plot y-axis in log scale. +* `show_plot::Bool`: show plot in pop-up window in addition to writing to disk. """ function plotGrainSizeDistribution(simulation::Simulation; filename_postfix::String = "", @@ -752,12 +747,9 @@ function plotGrainSizeDistribution(simulation::Simulation; filetype::String = "png", verbose::Bool = true, skip_fixed::Bool = true, - log_y::Bool = true) + log_y::Bool = false, + show_plot::Bool = false) - if !hasPyPlot - error("Function not available because PyPlot is not installed") - return - end diameters = Float64[] for i=1:length(simulation.grains) if simulation.grains[i].fixed && skip_fixed @@ -771,14 +763,43 @@ function plotGrainSizeDistribution(simulation::Simulation; error("size_type '$size_type' not understood") end end - PyPlot.pygui(false) - PyPlot.figure(figsize=figsize) - PyPlot.plt[:hist](diameters, nbins, log=log_y) - PyPlot.xlabel("Diameter [m]") - PyPlot.ylabel("Count [-]") + filename = string(simulation.id * filename_postfix * "-grain-size-distribution." * filetype) - PyPlot.savefig(filename) + + # write data to temporary file on disk + datafile = Base.Filesystem.tempname() + writedlm(datafile, diameters) + gnuplotscript = Base.Filesystem.tempname() + + open(gnuplotscript, "w") do f + + write(f, """#!/usr/bin/env gnuplot + set out "$(filename)" + set xlabel "Diameter [m]" + set ylabel "Count [-]" + set style histogram + plot "$(datafile)" + """) + end + + try + run(`gnuplot $gnuplotscript`) + catch return_signal + if isa(return_signal, Base.UVError) + error("Could not launch external gnuplot process") + end + end + + + xlabel = "Diameter [m]" + ylabel = "Count [-]" + if log_y + error("Logarithmic axis scaling isn't yet supported with GR histograms") + # try anyway + GR.setscale(GR.OPTION_Y_LOG) + GR.setscale(GR.OPTION_FLIP_X) + end if verbose info(filename) end diff --git a/src/io.jl b/src/io.jl @@ -50,9 +50,14 @@ export readSimulation readSimulation(filename::String=""; verbose::Bool=true) -Read all content from `Simulation` from disk in JDL format. +Return `Simulation` content read from disk using the JDL format. + +# Arguments +* `filename::String`: path to file on disk containing the simulation + information. +* `verbose::Bool=true`: confirm to console that the file has been read. """ -function readSimulation(filename::String=""; +function readSimulation(filename::String; verbose::Bool=true) if !hasJLD warn("Package JLD not found. Simulation save/read not supported. " * @@ -60,8 +65,42 @@ function readSimulation(filename::String=""; "requirements with `Pkg.add(\"JLD\")`.") nothing else + return JLD.load(filename, "simulation") + if verbose + info("Read simulation from $filename") + end + end +end +""" + readSimulation(simulation::Simulation; + step::Integer = -1, + verbose::Bool = true) + +Read the simulation state from disk and return as new simulation object. + +# Arguments +* `simulation::Simulation`: use the `simulation.id` to determine the file name + to read from, and read information from the file into this object. +* `step::Integer=-1`: attempt to read this output file step. At its default + value (`-1`), the function will try to read the latest file, determined by + calling [`readSimulationStatus`](@ref). +* `verbose::Bool=true`: confirm to console that the file has been read. +""" +function readSimulation(simulation::Simulation; + step::Integer = -1, + verbose::Bool = true) + if !hasJLD + warn("Package JLD not found. Simulation save/read not supported. " * + "Please install JLD and its " * + "requirements with `Pkg.add(\"JLD\")`.") + nothing + else + if step == -1 + step = readSimulationStatus(simulation) + end + filename = string(simulation.id, "/", simulation.id, ".$step.jld") if verbose - info("reading simulation from $filename") + info("Read simulation from $filename") end return JLD.load(filename, "simulation") end @@ -86,18 +125,22 @@ function writeSimulationStatus(simulation::Simulation; simulation.time/simulation.time_total*100. float(simulation.file_number)]) if verbose - info("wrote status to $filename") + info("Wrote status to $filename") end nothing end export readSimulationStatus """ - readSimulationStatus(filename::String; - folder::String=".", - verbose::Bool=false) + readSimulationStatus(simulation_id[, folder, verbose]) -Write current simulation status to disk in a minimal txt file. +Read the current simulation status from disk (`<sim.id>/<sim.id>.status.txt`) +and return the last output file number. + +# Arguments +* `simulation_id::String`: the simulation identifying string. +* `folder::String="."`: the folder in which to search for the status file. +* `verbose::Bool=true`: show simulation status in console. """ function readSimulationStatus(simulation_id::String; folder::String=".", @@ -113,7 +156,23 @@ function readSimulationStatus(simulation_id::String; " complete: $(data[2])%\n" * " last output file: $(Int(round(data[3])))\n") end - return data[3] + return Int(round(data[3])) +""" + readSimulationStatus(simulation[, folder, verbose]) + +Read the current simulation status from disk (`<sim.id>/<sim.id>.status.txt`) +and return the last output file number. + +# Arguments +* `simulation::Simulation`: the simulation to read the status for. +* `folder::String="."`: the folder in which to search for the status file. +* `verbose::Bool=true`: show simulation status in console. +""" +end +function readSimulationStatus(sim::Simulation; + folder::String=".", + verbose::Bool=true) + readSimulationStatus(sim.id, folder=folder, verbose=verbose) end export status diff --git a/test/grain.jl b/test/grain.jl @@ -30,20 +30,17 @@ Granular.addGrainCylindrical!(sim, [ 0., 0.], 10., 1., verbose=false) Granular.addGrainCylindrical!(sim, [ 0., 0.], 10., 1., verbose=false) Granular.compareGrains(sim.grains[1], sim.grains[2]) -if typeof(Pkg.installed("PyPlot")) == VersionNumber - info("Testing GSD plotting ") - Granular.plotGrainSizeDistribution(sim) - rm("test-grain-size-distribution.png") - Granular.plotGrainSizeDistribution(sim, skip_fixed=false) - rm("test-grain-size-distribution.png") - Granular.plotGrainSizeDistribution(sim, log_y=false) - rm("test-grain-size-distribution.png") - Granular.plotGrainSizeDistribution(sim, size_type="areal") - rm("test-grain-size-distribution.png") - @test_throws ErrorException Granular.plotGrainSizeDistribution(sim, size_type="asdf") -else - @test_throws ErrorException Granular.plotGrainSizeDistribution(sim) -end +info("Testing GSD plotting ") +Granular.plotGrainSizeDistribution(sim) +@test isfile("test-grain-size-distribution.png") +rm("test-grain-size-distribution.png") +Granular.plotGrainSizeDistribution(sim, skip_fixed=false) +@test isfile("test-grain-size-distribution.png") +rm("test-grain-size-distribution.png") +Granular.plotGrainSizeDistribution(sim, size_type="areal") +@test isfile("test-grain-size-distribution.png") +rm("test-grain-size-distribution.png") +@test_throws ErrorException Granular.plotGrainSizeDistribution(sim, size_type="asdf") info("Testing external body force routines") sim = Granular.createSimulation(id="test") diff --git a/test/jld.jl b/test/jld.jl @@ -15,7 +15,17 @@ if typeof(Pkg.installed("JLD")) == VersionNumber Granular.writeVTK(sim, verbose=false) Granular.writeSimulation(sim) + Granular.writeSimulationStatus(sim) + info("Reading from JLD file by specifying the input file name") sim2 = Granular.readSimulation("./test/test.1.jld") Granular.compareSimulations(sim, sim2) + + info("Reading and overwriting from JLD file by simulation id") + sim3 = Granular.createSimulation("test") + @test 1 == Granular.readSimulationStatus(sim3) + sim3 = Granular.readSimulation(sim3) + Granular.compareSimulations(sim, sim3) + + rm("./test/test.1.jld") end