### Persefone.jl - a model of agricultural landscapes and ecosystems in Europe. ### ### This file includes the functions for collecting ecological output data, which ### are then passed on to the `core/output.jl`. ### """ initecologicaldata() Create output files for each data group collected by the nature model. """ function initecologicaldata(model::SimulationModel) newdataoutput!(model, "populations", ["Date", "Species", "Abundance"], @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 """ savepopulationdata(model) Return a data table (to be printed to `populations.csv`), giving the current date and population size for each animal species. May be called never, daily, monthly, yearly, or at the end of a simulation, depending on the parameter `nature.popoutfreq`. """ function savepopulationdata(model::SimulationModel) pops = Dict{String,Int}(s=>0 for s = @param(nature.targetspecies)) for a in model.animals isnothing(a) && continue pops[speciesof(a)] += 1 end for m in model.migrants pops[speciesof(m.first)] += 1 end data = [] for p in keys(pops) push!(data, [model.date, p, pops[p]]) end data end """ saveindividualdata(model) Return a data table (to be printed to `individuals.csv`), listing all properties of all animal individuals in the model. May be called never, daily, monthly, yearly, or at the end of a simulation, depending on the parameter `nature.indoutfreq`. WARNING: Produces very big files! """ function saveindividualdata(model::SimulationModel) data = [] for a in model.animals isnothing(a) && continue push!(data, [model.date,a.id,a.pos[1],a.pos[2],speciesof(a),a.sex,a.age]) end for m in model.migrants push!(data, [model.date, m[1].id, -1, -1, speciesof(m[1]), m[1].sex, m[1].age]) end data end ## SKYLARK DATA OUTPUT function initskylarkdata(model::SimulationModel) newdataoutput!(model, "skylark_abundance", ["Date", "TotalAbundance", "Mating", "Breeding", "Nonbreeding", "Juvenile", "Migrants"], "daily", skylarkabundance, skylarkpopulation) # newdataoutput!(model, "skylark_territories", ["Date", "ID", "X", "Y"], # skylarkterritories, "monthly") #TODO add plotting function newdataoutput!(model, "skylark_nests", ["Date", "ID", "X", "Y", "Landcover", "Crop"], "monthly", skylarknests) #TODO add plotting function # newdataoutput!(model, "skylark_mortality", ["Date", "N", "Cause"], # skylarkmortality, "daily") #TODO add plotting function end """ skylarkabundance(model) Save skylark abundance data, including total abundance and demographic data (abundances of breeding/non-breeding/juvenile/migrated individuals). """ function skylarkabundance(model::SimulationModel) pops = Dict{String,Int}("TotalAbundance" => 0, "Mating" => 0, "Breeding" => 0, "Nonbreeding" => 0, "Juvenile" => 0, "Migrants" => 0) for a in model.animals (isnothing(a) || speciesof(a) != "Skylark") && continue pops["TotalAbundance"] += 1 if a.phase == nonbreeding pops["Nonbreeding"] += 1 elseif a.phase in (territorysearch, matesearch) || (a.phase == occupation && a.mate == -1) pops["Mating"] += 1 else pops["Breeding"] += 1 end if a.sex == female && a.clutch > 0 pops["TotalAbundance"] += a.clutch pops["Juvenile"] += a.clutch end end for m in model.migrants if speciesof(m.first) == "Skylark" pops["TotalAbundance"] += 1 pops["Migrants"] += 1 end end return [[model.date, pops["TotalAbundance"], pops["Mating"], pops["Breeding"], pops["Nonbreeding"], pops["Juvenile"], pops["Migrants"]]] end """ skylarkterritories(model) Return a list of all coordinates occupied by a skylark territory, and the ID of the individual holding the territory. WARNING: produces very big files. """ function skylarkterritories(model::SimulationModel) #TODO is there a way of outputting this that takes less space? For example as a landscape-size # matrix where each position is the ID of the individual occupying this pixel? data = [] for a in model.animals (isnothing(a) || a.sex != male || speciesof(a) != "Skylark" || a.phase != occupation) && continue for pos in a.territory push!(data, [model.date, a.id, pos[1], pos[2]]) end end data end """ skylarknests(model) Return a list of coordinates of active skylark nests, and the habitat type they occupy. """ function skylarknests(model::SimulationModel) data = [] for a in model.animals (isnothing(a) || a.sex != female || speciesof(a) != "Skylark" || isempty(a.nest)) && continue push!(data, [model.date, a.id, a.nest[1], a.nest[2], landcover(a.nest, model), cropname(a.nest, model)]) end data end """ skylarkmortality(model) """ function skylarkmortality(model::SimulationModel) #TODO #XXX may require an additional feature in output.jl to account for a different output type end