From 61d605c74c1f68d93ff3145e0cef258ff2117cab Mon Sep 17 00:00:00 2001 From: Daniel Vedder <daniel.vedder@idiv.de> Date: Thu, 24 Nov 2022 17:27:05 +0100 Subject: [PATCH] Implemented config file reading and commandline argument parsing Borrowed quite a bit of code from GeMM here, that made it easier... --- Manifest.toml | 2 +- Project.toml | 3 ++ README.md | 5 ++- src/Persephone.jl | 19 +++++---- src/core/input.jl | 93 ++++++++++++++++++++++++++++++++++++++++++ src/core/simulation.jl | 10 +++-- 6 files changed, 118 insertions(+), 14 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index 6125adc..a0f42ca 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -2,7 +2,7 @@ julia_version = "1.8.2" manifest_format = "2.0" -project_hash = "3c3cc3b9de5c42b80fd17ce2f0cc11a00abed995" +project_hash = "72816161d7cf94aaf2f40b7992f0ee1d99e390ce" [[deps.Agents]] deps = ["CSV", "DataFrames", "DataStructures", "Distributed", "Downloads", "Graphs", "JLD2", "LazyArtifacts", "LightOSM", "LinearAlgebra", "Pkg", "ProgressMeter", "Random", "Requires", "Scratch", "StatsBase"] diff --git a/Project.toml b/Project.toml index 1eb36b7..fe8960a 100644 --- a/Project.toml +++ b/Project.toml @@ -6,4 +6,7 @@ version = "0.0.1" [deps] Agents = "46ada45e-f475-11e8-01d0-f70cc89e6671" ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63" +Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" diff --git a/README.md b/README.md index 9e45a83..60b723f 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,11 @@ It is currently in the very early stages of development. Install the latest version of the [Julia](https://julialang.org/downloads/) programming language. The recommended editors are [VSCode](https://www.julia-vscode.org/) or [Emacs](https://www.emacswiki.org/emacs/JuliaProgrammingLanguage) (see `docs/editors.md`). +To install package dependencies, open a Julia REPL and run +`using Pkg; Pkg.activate("."); Pkg.instantiate()`. Run the simulation by executing `run.jl` from the commandline, or loading it from -within a Julia REPL with `include("run.jl")`. All dependencies should be -automatically installed. +within a Julia REPL with `include("run.jl")`. This model uses the [Agents.jl](https://juliadynamics.github.io/Agents.jl/stable/) framework. diff --git a/src/Persephone.jl b/src/Persephone.jl index 7200d20..3be2462 100644 --- a/src/Persephone.jl +++ b/src/Persephone.jl @@ -15,23 +15,28 @@ module Persephone using Agents, ArgParse, - Logging + Dates, + Logging, + Random, + TOML ## define exported functions and variables export - simulate + simulate, + initsim, + runsim + +## The file that stores all default parameters +const paramfile = "src/parameters.toml" +## (DO NOT CHANGE THIS VALUE! Instead, specify simulation-specific configuration files +## by using the "--configfile" commandline argument, or when invoking simulate().) ## include all module files include("core/input.jl") - include("core/output.jl") - include("crop/crops.jl") - include("ecology/ecology.jl") - include("farm/farm.jl") - include("core/simulation.jl") end diff --git a/src/core/input.jl b/src/core/input.jl index e69de29..9d147fc 100644 --- a/src/core/input.jl +++ b/src/core/input.jl @@ -0,0 +1,93 @@ +### Persephone - a socio-economic-ecological model of European agricultural landscapes. +### +### This file includes functions for configuring the model and reading in map files. +### + +## Note: some of this code was adapted from the GeMM model +## (https://github.com/CCTB-Ecomods/gemm/blob/master/src/input.jl) + +""" + getsettings(configfile) + +Combines all configuration options to produce a single settings dict. +Precedence: commandline parameters - user config file - default values +""" +function getsettings(configfile::String) + # read in and merge configurations from the commandline, the default config file + # and a user-supplied config file + defaults = TOML.parsefile(configfile) + commandline = parsecommandline() + if haskey(commandline, "configfile") && isfile(commandline["configfile"]) + configs = TOML.parsefile(commandline["configfile"]) + else + configs = nothing + end + settings = deepcopy(defaults) + for domain in keys(defaults) + for param in keys(defaults[domain]) + if param in keys(commandline) + settings[domain][param] = commandline[param] + elseif !isnothing(configs) && param in keys(configs[domain]) + settings[domain][param] = configs[domain][param] + end + end + end + # pre-process certain parameters + if settings["core"]["seed"] == 0 + settings["core"]["seed"] = abs(rand(RandomDevice(), Int32)) + end + defaultoutdir = defaults["core"]["outdir"] + if settings["core"]["outdir"] == defaultoutdir + outdir = defaultoutdir*"_"*string(Dates.today())*"_s"*string(settings["core"]["seed"]) + settings["core"]["outdir"] = outdir + end + # Flags are automatically set to false by ArgParse if they are not given - + # this should not override a given config file value + if !commandline["quietmode"] && !isnothing(configs) && "quietmode" in keys(configs["core"]) && configs["core"]["quietmode"] + settings["core"]["quietmode"] = true + end + settings +end + +""" + parsecommandline() + +Certain software parameters can be set via the commandline. +""" +function parsecommandline() + s = ArgParseSettings() + @add_arg_table! s begin + "--configfile", "-c" + help = "name of the config file" + arg_type = String + required = false + "--seed", "-s" + help = "inital random seed" + arg_type = Int + "--mapfile", "-m" + help = "name of the map file" + arg_type = String + required = false + "--outdir", "-o" + help = "location of the output directory" + arg_type = String + required = false + "--loglevel", "-l" + help = "amount of logging: \"debug\", \"normal\", or \"errors\"" + arg_type = String + required = false + "--quietmode", "-q" + help = "quiet mode. Don't print output to screen." + action = :store_true + "--runtime", "-r" + help = "duration in days that the simulation will run" + arg_type = Int + required = false + end + args = parse_args(s) + for a in keys(args) + (args[a] == nothing) && delete!(args, a) + end + args +end + diff --git a/src/core/simulation.jl b/src/core/simulation.jl index 8445922..7ddda5e 100644 --- a/src/core/simulation.jl +++ b/src/core/simulation.jl @@ -3,7 +3,10 @@ ### This file includes the core functions for initialising and running simulations. ### -function initsim() +function initsim(config::String) + settings = getsettings(config) + TOML.print(settings) + Random.seed!(settings["core"]["seed"]) #TODO end @@ -11,10 +14,9 @@ function runsim() #TODO end -function simulate() - initsim() +function simulate(config::String=paramfile) + initsim(config) runsim() println("Simulation ran. Nothing happened. But it will!") - println("Simulation complete :-)") #TODO end -- GitLab