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

Made data outputs a model property

parent 6078618e
Branches
No related tags found
No related merge requests found
......@@ -30,6 +30,7 @@ export
FarmPlot,
Animal,
Farmer,
DataOutput,
#macros
@param,
@species,
......
......@@ -82,58 +82,50 @@ struct DataOutput
frequency::String
end
let outputregistry = Vector{DataOutput}(),
nextmonthlyoutput = today(),
nextyearlyoutput = today()
"""
newdataoutput(model, filename, header, outputfunction, frequency)
"""
newdataoutput(model, filename, header, outputfunction, frequency)
Create and register a new data output. This function must be called by all submodels
that want to have their output functions called regularly.
"""
global function newdataoutput(model::AgentBasedModel, filename::String, header::String,
outputfunction::Function, frequency::String)
if !(frequency in ("daily", "monthly", "yearly", "end", "never"))
Base.error("Invalid frequency '$frequency' for $filename.")
end
ndo = DataOutput(filename, header, outputfunction, frequency)
append!(outputregistry, [ndo])
if frequency != "never"
open(joinpath(@param(core.outdir), filename), "w") do f
println(f, header)
end
Create and register a new data output. This function must be called by all submodels
that want to have their output functions called regularly.
"""
function newdataoutput(model::AgentBasedModel, filename::String, header::String,
outputfunction::Function, frequency::String)
if !(frequency in ("daily", "monthly", "yearly", "end", "never"))
Base.error("Invalid frequency '$frequency' for $filename.")
end
ndo = DataOutput(filename, header, outputfunction, frequency)
append!(model.dataoutputs, [ndo])
if frequency != "never"
open(joinpath(@param(core.outdir), filename), "w") do f
println(f, header)
end
end
end
"""
outputdata(model)
Cycle through all registered data outputs and activate them according to their
configured frequency.
"""
global function outputdata(model::AgentBasedModel)
#XXX all output functions are run on the first update (regardless of frequency)
# -> should they all be run on the last update, too?
if model.date == @param(core.startdate)
nextmonthlyoutput = model.date
nextyearlyoutput = model.date
end
for output in outputregistry
(output.frequency == "never") && continue
# check if this output should be activated today
if (output.frequency == "daily") ||
(output.frequency == "monthly" && model.date == nextmonthlyoutput) ||
(output.frequency == "yearly" && model.date == nextyearlyoutput) ||
(output.frequency == "end" && model.date == @param(core.enddate))
open(joinpath(@param(core.outdir), output.filename), "a") do f
outstring = output.outputfunction(model)
(outstring[end] != '\n') && (outstring *= '\n')
print(f, outstring)
end
end
"""
outputdata(model)
Cycle through all registered data outputs and activate them according to their
configured frequency.
"""
function outputdata(model::AgentBasedModel)
#XXX all output functions are run on the first update (regardless of frequency)
# -> should they all be run on the last update, too?
startdate = @param(core.startdate)
isnextmonth = d -> (day(d) == day(startdate))
isnextyear = d -> (month(d) == month(startdate) && day(d) == day(startdate))
for output in model.dataoutputs
(output.frequency == "never") && continue
# check if this output should be activated today
if (output.frequency == "daily") ||
(output.frequency == "monthly" && isnextmonth(model.date)) ||
(output.frequency == "yearly" && isnextyear(model.date)) ||
(output.frequency == "end" && model.date == @param(core.enddate))
open(joinpath(@param(core.outdir), output.filename), "a") do f
outstring = output.outputfunction(model)
(outstring[end] != '\n') && (outstring *= '\n')
print(f, outstring)
end
end
(model.date == nextmonthlyoutput) && (nextmonthlyoutput = model.date + Month(1))
(model.date == nextyearlyoutput) && (nextyearlyoutput = model.date + Year(1))
end
end
......@@ -22,11 +22,13 @@ function initialise(config::String=PARAMFILE, seed::Union{Int64,Nothing}=nothing
settings = getsettings(config, seed)
Random.seed!(settings["core"]["seed"])
events = Vector{FarmEvent}()
dataoutputs = Vector{DataOutput}()
landscape = initlandscape(settings["core"]["landcovermap"], settings["core"]["farmfieldsmap"])
space = GridSpace(size(landscape), periodic=false)
properties = Dict{Symbol,Any}(:settings=>settings,
:date=>settings["core"]["startdate"],
:landscape=>landscape,
:dataoutputs=>dataoutputs,
:events=>events)
@debug "Setting up model."
model = AgentBasedModel(Union{Farmer,Animal,FarmPlot}, space, properties=properties,
......
......@@ -12,8 +12,8 @@ const INDFILE = "individuals.csv"
Create output files for each data group collected by the nature model.
"""
function initecologicaldata(model::AgentBasedModel)
newdataoutput(model, POPFILE, "Date;Species;Abundance", savepopulationdata,
@param(nature.popoutfreq))
newdataoutput(model, POPFILE, "Date;Species;Abundance",
savepopulationdata, @param(nature.popoutfreq))
newdataoutput(model, INDFILE, "Date;ID;X;Y;Species;Sex;Age",
saveindividualdata, @param(nature.indoutfreq))
end
......
......@@ -14,21 +14,23 @@
end
@testset "Output functions" begin
properties = Dict{Symbol,Any}(:settings=>TESTSETTINGS)
properties = Dict{Symbol,Any}(:settings=>TESTSETTINGS,
:dataoutputs=>Vector{DataOutput}())
space = GridSpace((10,10), periodic=false)
model = AgentBasedModel(Animal, space, properties=properties, warn=false)
# test that the output directory is created with all files
outdir = @param(core.outdir)
logstring = "Setting up output directory results_testsuite_$(Dates.today())_s1"
@test_logs (:debug, logstring) min_level=Logging.Debug Ps.setupdatadir(model)
@test isdir(@param(core.outdir))
@test isfile(joinpath(@param(core.outdir), @param(core.landcovermap)))
@test isfile(joinpath(@param(core.outdir), @param(core.farmfieldsmap)))
@test isfile(joinpath(@param(core.outdir), @param(core.configfile)))
@test isfile(joinpath(@param(core.outdir), Ps.LOGFILE))
@test isdir(outdir)
@test isfile(joinpath(outdir, @param(core.landcovermap)))
@test isfile(joinpath(outdir, @param(core.farmfieldsmap)))
@test isfile(joinpath(outdir, @param(core.configfile)))
@test isfile(joinpath(outdir, Ps.LOGFILE))
# check whether the overwrite warning/protection works
logstring = "Overwriting existing output directory $(@param(core.outdir))."
logstring = "Overwriting existing output directory $(outdir)."
@test_logs (:warn, logstring) match_mode=:any Ps.setupdatadir(model)
#TODO test overwrite protection (requires parameter mutability)
rm(@param(core.outdir), force=true, recursive=true)
rm(outdir, force=true, recursive=true)
#TODO test that creating a DataOutput works, and outputs data with the required frequency
end
......@@ -59,6 +59,7 @@ end
properties = Dict{Symbol,Any}(:date=>Date(2022, 1, 1),
:landscape=>landscape,
:events=>Vector{FarmEvent}(),
:dataoutputs=>Vector{DataOutput}(),
:settings=>TESTSETTINGS)
model = AgentBasedModel(Union{Farmer,Animal,FarmPlot}, space,
properties=properties, warn=false)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment