### Persefone.jl - a model of agricultural landscapes and ecosystems in Europe. ### ### This file is responsible for managing the animal modules and contains functions ### and types integrating the nature submodel with the rest of Persefone. ### ## An enum used to assign a sex to each animal @enum Sex hermaphrodite male female #XXX hermaphrodite probably is not needed and its implementation is iffy """ Animal This is the generic agent type for all animals. Individual species are created using the [`@species`](@ref) macro. All species contain the following fields: - `id` An integer unique identifier for this individual. - `sex` male, female, or hermaphrodite. - `parents` The IDs of the individual's parents. - `pos` An (x, y) coordinate tuple. - `age` The age of the individual in days. - `phase` The update function to be called during the individual's current life phase. - `energy` A [DEBparameters](@ref) struct for calculating energy budgets. - `offspring` A vector containing the IDs of an individual's children. """ abstract type Animal <: ModelAgent end """ speciesof(animal) Return the species name of this animal as a string. """ function speciesof(a::Animal) string(typeof(a)) end """ animalid(animal) A small utility function to return a string with the species name and ID of an animal. """ function animalid(a::Animal) return "$(speciesof(a)) $(a.id)" end """ stepagent!(animal, model) Update an animal by one day, executing it's currently active phase function. """ function stepagent!(animal::Animal, model::SimulationModel) animal.age += 1 animal.phase(animal, model) end """ initnature!(model) Initialise the model with all simulated animal populations. """ function initnature!(model::SimulationModel) # The config file determines which species are simulated in this run for speciesname in @param(nature.targetspecies) # Call each species' initialisation function @eval $(Symbol(speciesname))().initialise!($(Symbol(speciesname)), model) end # Initialise the data output initecologicaldata(model) end """ updatenature!(model) Run processes that affect all animals. """ function updatenature!(model::SimulationModel) # Update all animals. Dead animals are replaced by `nothing`, we can skip these. #XXX I assume that keeping all those `nothing`s in the animal vector won't lead # to memory bloat, but I will have to check that. for a in model.animals !isnothing(a) && stepagent!(a, model) end # The migrant pool is sorted by date of return, so we can simply look at the top # of the stack to check whether any animals are returning today. while !isempty(model.migrants) && model.migrants[1].second <= model.date returnee = model.migrants[1].first model.animals[returnee.id] = returnee @debug "$(animalid(returnee)) has returned." deleteat!(model.migrants, 1) end end