diff --git a/src/core/output.jl b/src/core/output.jl index 555c4bed63baff1a37c0ccdd9abba4932878c838..d59eb3d91f885d545d21132b27955698bb0cfe1b 100644 --- a/src/core/output.jl +++ b/src/core/output.jl @@ -194,7 +194,7 @@ function newdataoutput!(model::SimulationModel, name::String, end end end - ndo = DataOutput(frequency, [[]], df, outputfunction, plotfunction) + ndo = DataOutput(frequency, [], df, outputfunction, plotfunction) model.dataoutputs[name] = ndo end @@ -221,7 +221,7 @@ function outputdata(model::SimulationModel, force=false) (output.frequency == "yearly" && isnextyear(model.date)) || (output.frequency == "end" && model.date == @param(core.enddate)) !isnothing(output.outputfunction) && (output.databuffer = output.outputfunction(model)) - isempty(output.databuffer) && continue + (isempty(output.databuffer) || output.databuffer == [[]]) && continue if @param(core.csvoutput) open(joinpath(@param(core.outdir), o*".csv"), "a") do f for row in output.databuffer @@ -234,17 +234,17 @@ function outputdata(model::SimulationModel, force=false) push!(output.datastore, row) end end - output.databuffer = [[]] + output.databuffer = [] end end end """ - record(model, outputname, data) + record!(model, outputname, data) Append an observation vector to the given output. """ -function record(model::SimulationModel, outputname::String, data::Vector) +function record!(model::SimulationModel, outputname::String, data::Vector) push!(model.dataoutputs[outputname].databuffer, data) end diff --git a/src/nature/ecologicaldata.jl b/src/nature/ecologicaldata.jl index c350b9926cbd14158b2f2e10e6c2acb98645c20f..8f0b7e8bc38d08228dc688609519cdb552e28055 100644 --- a/src/nature/ecologicaldata.jl +++ b/src/nature/ecologicaldata.jl @@ -14,6 +14,7 @@ function initecologicaldata(model::SimulationModel) @param(nature.popoutfreq), savepopulationdata, populationtrends) newdataoutput!(model, "individuals", ["Date","ID","X","Y","Species","Sex","Age"], @param(nature.indoutfreq), saveindividualdata, visualisemap) + newdataoutput!(model, "mortality", ["Date", "Species", "Cause"], @param(nature.popoutfreq)) initskylarkdata(model) end diff --git a/src/nature/individuals.jl b/src/nature/individuals.jl index 934d219381825082a6ce56d8710e19d14c61d9d1..7cb9da522187bde26c3344556c325faa361e4e44 100644 --- a/src/nature/individuals.jl +++ b/src/nature/individuals.jl @@ -47,6 +47,7 @@ function kill!(animal::Animal, model::SimulationModel, # print the epitaph and remove the animal from the model postfix = isempty(cause) ? "." : " from $cause." @debug "$(animalid(animal)) has died$(postfix)" + @record("mortality", [model.date, speciesof(animal), cause]) model.animals[animal.id] = nothing return true end diff --git a/src/nature/macros.jl b/src/nature/macros.jl index 14a81d3f2546b0c9f217f010b0a603e48374dc58..250d688940d815ef7b87284aecc59a8a300aba52 100644 --- a/src/nature/macros.jl +++ b/src/nature/macros.jl @@ -496,6 +496,7 @@ end @thisyear(annualdate) Construct a date object referring to the current model year from an AnnualDate. +Only use in scopes where `model` is available. """ macro thisyear(annualdate) :(thisyear($(esc(annualdate)), $(esc(:model)))) @@ -505,6 +506,7 @@ end @nextyear(annualdate) Construct a date object referring to the next year in the model from an AnnualDate. +Only use in scopes where `model` is available. """ macro nextyear(annualdate) :(nextyear($(esc(annualdate)), $(esc(:model)))) @@ -514,7 +516,26 @@ end @lastyear(annualdate) Construct a date object referring to the last year in the model from an AnnualDate. +Only use in scopes where `model` is available. """ macro lastyear(annualdate) :(lastyear($(esc(annualdate)), $(esc(:model)))) end + +""" + @record(outputname, data) + +Record an observation / data point. Only use in scopes where `model` is available. +""" +macro record(args...) + :(record!($(esc(:model)), $(map(esc, args)...))) +end + +""" + @destroynest(reason) + +Utility wrapper for `destroynest!()` in the Skylark model. +""" +macro destroynest(reason) + :(destroynest!($(esc(:self)), $(esc(:model)), $(esc(reason)))) +end diff --git a/src/nature/species/skylark.jl b/src/nature/species/skylark.jl index cced0226228e00d7f72de96d8d6c4fc4dff8fb91..547f1cd2b0f702932ea29dbdfadfd979007f3feb 100644 --- a/src/nature/species/skylark.jl +++ b/src/nature/species/skylark.jl @@ -229,8 +229,8 @@ Females that have found a partner build a nest and lay eggs in a suitable locati self.timer -= 1 end # tillage and harvest destroys the nest - @respond(tillage, destroynest!(self, "tillage")) - @respond(harvesting, destroynest!(self, "harvesting")) + @respond(tillage, @destroynest("tillage")) + @respond(harvesting, @destroynest("harvesting")) end """ @@ -243,24 +243,27 @@ chicks are independent or in case of brood loss. self.timer += 1 #TODO this should be habitat-dependent! if self.timer <= self.eggtime - @chance(self.eggpredationmortality) && destroynest!(self, "predation") + @chance(self.eggpredationmortality) && @destroynest("predation") elseif self.timer <= self.eggtime + self.nestlingtime - @chance(self.nestlingpredationmortality) && destroynest!(self, "predation") + @chance(self.nestlingpredationmortality) && @destroynest("predation") elseif self.timer <= self.eggtime + self.nestlingtime + self.fledglingtime - @chance(self.fledglingpredationmortality) && destroynest!(self, "predation") + @chance(self.fledglingpredationmortality) && @destroynest("predation") else # create new young, reset timer and clutch counter for o in 1:self.clutch #XXX is this the best way of doing first-year mortality? - @chance(self.firstyearmortality) ? - @debug("A skylark has died from first year mortality") : + if @chance(self.firstyearmortality) + @debug("A skylark has died from first year mortality") + @record("mortality", [model.date, "Skylark", "firstyearmortality"]) + else @reproduce(1, self.mate) + end end self.clutch = 0 end if self.clutch > 0 # tillage and harvest destroys the nest - @respond(tillage, destroynest!(self, "tillage")) - @respond(harvesting, destroynest!(self, "harvesting")) + @respond(tillage, @destroynest("tillage")) + @respond(harvesting, @destroynest("harvesting")) else # restart breeding cycle if there is time self.timer = 0 self.nest = () @@ -358,16 +361,20 @@ function allowsnesting(skylark::Skylark, model::SimulationModel, pos::Tuple{Int6 end """ - destroynest!(skylark, reason) + destroynest!(skylark, model, reason) Remove the skylark's nest and offspring due to disturbance or predation. """ -function destroynest!(self::Skylark, reason::String) +function destroynest!(self::Skylark, model::SimulationModel, reason::String) + for c in self.clutch + @record("mortality", [model.date, "Skylark", reason]) + end self.nest = () self.clutch = 0 @debug("$(animalid(self)) had her nest destroyed by $reason.") end + ## INITIALISATION """