Skip to content
Snippets Groups Projects
Commit aea0e548 authored by xo30xoqa's avatar xo30xoqa
Browse files

Allow setting any parameters by arguments to simulate()/initialise()

parent 277780b8
Branches
Tags
No related merge requests found
...@@ -41,12 +41,12 @@ macro param(domainparam) ...@@ -41,12 +41,12 @@ macro param(domainparam)
end end
""" """
getsettings(configfile, seed=nothing) getsettings(configfile, userparams=Dict())
Combines all configuration options to produce a single settings dict. Combines all configuration options to produce a single settings dict.
Precedence: commandline parameters - user config file - default values Precedence: function arguments - commandline parameters - user config file - default values
""" """
function getsettings(configfile::String, seed::Union{Int64,Nothing}=nothing) function getsettings(configfile::String, userparams::Dict{String,Any}=Dict())
# read in and merge configurations from the commandline, the default config file # read in and merge configurations from the commandline, the default config file
# and a config file supplied by the user (via the --configfile option) # and a config file supplied by the user (via the --configfile option)
defaults::Dict{String, Any} = TOML.parsefile(PARAMFILE) |> flattenTOML defaults::Dict{String, Any} = TOML.parsefile(PARAMFILE) |> flattenTOML
...@@ -61,7 +61,9 @@ function getsettings(configfile::String, seed::Union{Int64,Nothing}=nothing) ...@@ -61,7 +61,9 @@ function getsettings(configfile::String, seed::Union{Int64,Nothing}=nothing)
end end
settings = deepcopy(defaults) settings = deepcopy(defaults)
for param in keys(defaults) for param in keys(defaults)
if split(param, ".")[2] in keys(commandline) if param in keys(userparams)
settings[param] = userparams[param]
elseif split(param, ".")[2] in keys(commandline)
settings[param] = commandline[split(param, ".")[2]] settings[param] = commandline[split(param, ".")[2]]
elseif !isnothing(configs) && param in keys(configs) elseif !isnothing(configs) && param in keys(configs)
settings[param] = configs[param] settings[param] = configs[param]
...@@ -73,7 +75,6 @@ function getsettings(configfile::String, seed::Union{Int64,Nothing}=nothing) ...@@ -73,7 +75,6 @@ function getsettings(configfile::String, seed::Union{Int64,Nothing}=nothing)
end end
end end
end end
!isnothing(seed) && (settings["core.seed"] = seed)
settings["internal.scanparams"] = scanparams settings["internal.scanparams"] = scanparams
preprocessparameters(settings, defaults["core.outdir"]) preprocessparameters(settings, defaults["core.outdir"])
end end
...@@ -85,6 +86,7 @@ Take the raw input parameters and process them where necessary (e.g. convert typ ...@@ -85,6 +86,7 @@ Take the raw input parameters and process them where necessary (e.g. convert typ
perform checks). This is a helper function for [`getsettings`](@ref). perform checks). This is a helper function for [`getsettings`](@ref).
""" """
function preprocessparameters(settings::Dict{String,Any}, defaultoutdir::String) function preprocessparameters(settings::Dict{String,Any}, defaultoutdir::String)
#TODO replace errors with exceptions
# miscellaneous processing # miscellaneous processing
(settings["core.seed"] == 0) && (settings["core.seed"] = abs(rand(RandomDevice(), Int32))) (settings["core.seed"] == 0) && (settings["core.seed"] = abs(rand(RandomDevice(), Int32)))
settings["world.mapresolution"] = settings["world.mapresolution"] * 1m settings["world.mapresolution"] = settings["world.mapresolution"] * 1m
...@@ -107,15 +109,15 @@ function preprocessparameters(settings::Dict{String,Any}, defaultoutdir::String) ...@@ -107,15 +109,15 @@ function preprocessparameters(settings::Dict{String,Any}, defaultoutdir::String)
settings["crop.cropdirectory"] = abspath(pkgdir(@__MODULE__), settings["crop.cropdirectory"]) settings["crop.cropdirectory"] = abspath(pkgdir(@__MODULE__), settings["crop.cropdirectory"])
@debug "Using package directory to load crop data: $(settings["crop.cropdirectory"])". @debug "Using package directory to load crop data: $(settings["crop.cropdirectory"])".
else else
Base.error("Couldn't find map directory $(settings["crop.cropdirectory"]).") Base.error("Couldn't find crop directory $(settings["crop.cropdirectory"]).")
end end
end end
# sanity checks # sanity checks
if settings["core.startdate"] > settings["core.enddate"] if settings["core.startdate"] > settings["core.enddate"]
Base.error("Enddate is earlier than startdate.") #TODO replace with exception Base.error("Enddate is earlier than startdate.")
end end
if !(settings["crop.cropmodel"] in AVAILABLE_CROPMODELS) if !(settings["crop.cropmodel"] in AVAILABLE_CROPMODELS)
error("crop.cropmodel = \"$(settings["crop.cropmodel"])\", but has to be one of: $AVAILABLE_CROPMODELS") Base.error("crop.cropmodel = \"$(settings["crop.cropmodel"])\", but has to be one of: $AVAILABLE_CROPMODELS")
end end
#FIXME enable parallelisation #FIXME enable parallelisation
# if !isempty(settings["internal.scanparams"]) && (nprocs() < 2) # if !isempty(settings["internal.scanparams"]) && (nprocs() < 2)
......
...@@ -47,15 +47,15 @@ function stepagent!(agent::ModelAgent, model::SimulationModel) ...@@ -47,15 +47,15 @@ function stepagent!(agent::ModelAgent, model::SimulationModel)
end end
""" """
simulate(config=PARAMFILE, seed=nothing) simulate(configfile=PARAMFILE, params=Dict())
Initialise one or more model objects and carry out a full simulation experiment, Initialise one or more model objects and carry out a full simulation experiment,
optionally specifying a configuration file and a seed for the RNG. optionally specifying a configuration file and/or specific parameters.
This is the default way to run a Persefone simulation. This is the default way to run a Persefone simulation.
""" """
function simulate(config::String=PARAMFILE, seed::Union{Int64,Nothing}=nothing) function simulate(;configfile::String=PARAMFILE, params::Dict{String,Any}=Dict{String,Any}())
models = initialise(config, seed) models = initialise(configfile=configfile, params=params)
isa(models, Vector) ? isa(models, Vector) ?
map(simulate!, models) : #TODO parallelise map(simulate!, models) : #TODO parallelise
simulate!(models) simulate!(models)
...@@ -68,25 +68,24 @@ Carry out a complete simulation run using a pre-initialised model object. ...@@ -68,25 +68,24 @@ Carry out a complete simulation run using a pre-initialised model object.
""" """
function simulate!(model::SimulationModel) function simulate!(model::SimulationModel)
@info "Simulation run started at $(Dates.now())." @info "Simulation run started at $(Dates.now())."
runtime = Dates.value(@param(core.enddate)-@param(core.startdate))+1 while model.date <= @param(core.enddate)
for d in 1:runtime
stepsimulation!(model) stepsimulation!(model)
end end
finalise!(model) finalise!(model)
end end
""" """
initialise(config=PARAMFILE, seed=nothing) initialise(configfile=PARAMFILE, params=Dict())
Initialise the model: read in parameters, create the output data directory, Initialise the model: read in parameters, create the output data directory,
and instantiate the SimulationModel object(s). Optionally allows specifying the and instantiate the SimulationModel object(s). Optionally allows specifying the
configuration file and overriding the `seed` parameter. This returns a single configuration file and overriding specific parameters. This returns a single
model object, unless the config file contains multiple values for one or more model object, unless the config file contains multiple values for one or more
parameters, in which case it creates a full-factorial simulation experiment parameters, in which case it creates a full-factorial simulation experiment
and returns a vector of model objects. and returns a vector of model objects.
""" """
function initialise(config::String=PARAMFILE, seed::Union{Int64,Nothing}=nothing) function initialise(;configfile::String=PARAMFILE, params::Dict{String,Any}=Dict{String,Any}())
settings = getsettings(config, seed) settings = getsettings(configfile, params)
scanparams = settings["internal.scanparams"] scanparams = settings["internal.scanparams"]
delete!(settings, "internal.scanparams") delete!(settings, "internal.scanparams")
isempty(scanparams) ? isempty(scanparams) ?
......
...@@ -4,8 +4,9 @@ ...@@ -4,8 +4,9 @@
### ###
@testset "Model initialisation" begin @testset "Model initialisation" begin
model = initialise(TESTPARAMETERS) model = initialise(TESTPARAMETERS, params=Dict("core.visualise"=>false))
@test typeof(model.settings) == Dict{String, Any} @test typeof(model.settings) == Dict{String, Any}
@test @param(core.visualise) == false
@test model.date == Date(2022,2,1) @test model.date == Date(2022,2,1)
@test typeof(model.landscape) == Matrix{Pixel} @test typeof(model.landscape) == Matrix{Pixel}
@test typeof(model.dataoutputs) == Dict{String,DataOutput} @test typeof(model.dataoutputs) == Dict{String,DataOutput}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment