From 72f6c9006b3fa9d434dedac2dbcaca0afddb6fdd Mon Sep 17 00:00:00 2001 From: Daniel Vedder <daniel.vedder@idiv.de> Date: Wed, 21 Dec 2022 16:31:59 +0100 Subject: [PATCH] Wrote a first version of the events system --- src/core/landscape.jl | 45 ++++++++++++++++++++++++++++++++++++------ src/core/simulation.jl | 5 +++-- src/crop/crops.jl | 13 ++++++++++++ src/nature/nature.jl | 3 ++- 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/core/landscape.jl b/src/core/landscape.jl index aff4e57..959aef5 100644 --- a/src/core/landscape.jl +++ b/src/core/landscape.jl @@ -8,6 +8,8 @@ ## Do not change the order of this enum, or initlandscape() will break! @enum LandCover nodata forest grass water builtup soil agriculture +@enum LandscapeEvent test tillage fertiliser pesticide harvest + """ Pixel @@ -18,8 +20,7 @@ in a single object. The model landscape consists of a matrix of pixels. mutable struct Pixel landcover::LandCover fieldid::Union{Missing,Int64} - events::Vector{Symbol} #TODO implement the rest of the events system - #FIXME actually this is stupid - I don't want a field ID, I want a field object + events::Vector{Tuple{LandscapeEvent,Int64}} end """ @@ -49,6 +50,27 @@ function initlandscape() return landscape end +""" + updatelandscape!(model) + +Update the model landscape. (Currently only removes old events.) +""" +function updatelandscape!(model::AgentBasedModel) + #FIXME This is really slow?! + # Instead of cycling through every pixel every time, I should keep a list of active + # events, and cycle through those + width, height = size(model.landscape) + for x in 1:width + for y in 1:height + newevents::Vector{Tuple{LandscapeEvent,Int64}} = [] + for e in model.landscape[x,y].events + # only keep events that still have a duration > 1 day + (e[2] > 1) && push!(newevents, (e[1], e[2]-1)) + end + model.landscape[x,y].events = newevents + end + end +end """ landcover(model, position) @@ -60,10 +82,21 @@ function landcover(model::AgentBasedModel, pos::Tuple{Int64,Int64}) end """ - fieldid(model, position) + farmplot(model, position) -Return the UID of the field at this position (utility wrapper). +Return the farm plot at this position (utility wrapper). """ -function fieldid(model::AgentBasedModel, pos::Tuple{Int64,Int64}) - model.landscape[pos...].fieldid +function farmplot(model::AgentBasedModel, pos::Tuple{Int64,Int64}) + model[model.landscape[pos...].fieldid] end + +""" + createevent(model, pos, name, duration=1) + +Add a landscape event to the pixel at the specified site. +""" +function createevent(model::AgentBasedModel, pos::Tuple{Int64,Int64}, + name::LandscapeEvent, duration::Int64=1) + push!(model.landscape[pos...].events, (name, duration)) +end + diff --git a/src/core/simulation.jl b/src/core/simulation.jl index 3ee8fe7..525e76e 100644 --- a/src/core/simulation.jl +++ b/src/core/simulation.jl @@ -37,10 +37,11 @@ Execute one update of the model. """ function stepsimulation!(model::AgentBasedModel) @info "Simulating day $(model.date)." - for a in Schedulers.ByType((Farmer,Animal,FarmPlot), true)(model) + for a in Schedulers.ByType((Farmer,FarmPlot,Animal), true)(model) #The animal may have been killed, so we need a try/catch - try stepagent!(getindex(model, a), model) catch keyerror end + try stepagent!(model[a], model) catch keyerror end end + #updatelandscape!(model) outputdata(model) model.date += Day(1) end diff --git a/src/crop/crops.jl b/src/crop/crops.jl index ccae89b..709a203 100644 --- a/src/crop/crops.jl +++ b/src/crop/crops.jl @@ -86,3 +86,16 @@ function averagefieldsize(model::AgentBasedModel) round(sum(sizes)/size(sizes)[1], digits=2) #sizes end + + +""" + applyevent(model, farmplotid, name, duration=1) + +Apply an event to all pixels in a farm plot. +""" +function applyevent(model::AgentBasedModel, farmplotid::Int64, + name::LandscapeEvent, duration::Int64=1) + for p in model[farmplotid].pixels + createevent(model, p, name, duration) + end +end diff --git a/src/nature/nature.jl b/src/nature/nature.jl index 39e388e..9fe3f27 100644 --- a/src/nature/nature.jl +++ b/src/nature/nature.jl @@ -122,7 +122,8 @@ This can only be used nested within `@phase`. """ macro respond(eventname, body) quote - if $(esc(eventname)) in @here(events) + #TODO test this + if any(e -> e[1] == $(esc(eventname)), @here(events)) $body end end -- GitLab