Skip to content
Snippets Groups Projects
Commit 4ad42b92 authored by xo30xoqa's avatar xo30xoqa
Browse files

Big rearrange in the nature model to accommodate the @species syntax

Not yet functional!
parent ab698d68
No related branches found
No related tags found
No related merge requests found
......@@ -16,7 +16,7 @@ using
Agents,
ArgParse,
Dates,
GeoArrays,
GeoArrays, #XXX this is a big dependency - can we get rid of it?
Logging,
LoggingExtras,
Random,
......@@ -24,6 +24,7 @@ using
## define exported functions and variables
export
param,
simulate,
initialise,
stepsimulation!,
......@@ -42,9 +43,11 @@ include("core/landscape.jl")
include("farm/farm.jl")
include("crop/crops.jl")
include("nature/nature.jl")
include("nature/lifehistory.jl")
include("nature/ecologicaldata.jl")
include("nature/wolpertinger.jl")
include("nature/wyvern.jl")
#include("nature/species/skylark.jl")
#include("nature/species/wolpertinger.jl")
#include("nature/species/wyvern.jl")
include("core/simulation.jl")
end
......@@ -17,6 +17,7 @@ in a single object. The model landscape consists of a matrix of pixels.
struct Pixel
landcover::LandCover
fieldid::Union{Missing, UInt32}
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
end
......
......@@ -6,6 +6,18 @@
const POPFILE = "populations.csv"
const INDFILE = "individuals.csv"
"""
initecologicaldata()
Create output files for each data group collected by the nature model.
"""
function initecologicaldata()
newdataoutput(POPFILE, "Date;Species;Abundance", savepopulationdata,
param("nature.popoutfreq"))
newdataoutput(INDFILE, "Date;ID;X;Y;Species;Sex;Age;Energy",
saveindividualdata, param("nature.indoutfreq"))
end
"""
savepopulationdata(model)
......
### Persephone - a socio-economic-ecological model of European agricultural landscapes.
###
### This file contains a set of utility functions needed by species.
###
#TODO initrandompopulation
#TODO killanimal!
#TODO reproduce!
#TODO parentsalive?
......@@ -6,78 +6,46 @@
## An enum used to assign a sex to each animal
@enum Sex hermaphrodite male female
"""
Species
Species are differentiated by their name, and the functions used to
initialise their population and update each individual.
"""
struct Species
name::String
initpop!::Function # takes one argument: model
update!::Function # takes two arguments: animal, model
traits::Dict{String,Any} # a collection of species-specific traits
end
#TODO convert species into dicts
"""
Animal
This is the generic agent type for all animals. Species are differentiated
by the `species` struct passed by them during initialisation.
by trait dictionaries passed by them during initialisation.
"""
#XXX fix the @agent docstring issue (https://github.com/JuliaDynamics/Agents.jl/issues/715)
@agent Animal GridAgent{2} begin
species::Species
#XXX is it (performance-)wise to use a dict for the traits?
# Doesn't this rather obviate the point of having an agent struct?
traits::Dict{String,Any}
sex::Sex
age::Int32
energy::Int32
end
# This dict stores the definitions for all species that can be simulated.
# (The definitions are created in separate files and registered here.)
##TODO this needs to be rewritten to deal with the new @species macro
let specieslist = Dict{String, Species}()
"""
registerspecies(species)
This function has to be called by every species definition file
in order for the species to be used.
"""
global function registerspecies(s::Species)
specieslist[s.name] = s
end
"""
getspecies(name)
Returns the definition struct for the named species.
"""
global function getspecies(name::String)
specieslist[name]
### MACROS IMPLEMENTING THE DOMAIN-SPECIFIC LANGUAGE FOR DEFINING SPECIES
macro species(name, body)
funcname = "speciesfunction_"*name
quote
Core.@__doc__ function $(esc(funcname))()
$(esc(:name)) = string($(QuoteNode(name)))
$(esc(body))
vardict = Base.@locals
speciesdict = Dict{String,Any}()
for k in keys(vardict)
speciesdict[string(k)] = vardict[k]
end
return speciesdict
end
end
end
"""
newspecies(properties...)
A utility function to create and register a new species.
All function arguments are passed on to Species().
"""
function newspecies(properties...)
registerspecies(Species(properties...))
macro phase(name, body)
:($(esc(name)) = function(animal::Animal, model::AgentBasedModel) $body end)
end
"""
trait(animal, trait)
A utility function to return a trait value for this animal's species.
Returns nothing if the trait is not defined.
"""
function trait(animal::Animal, trait::String)
!(trait in keys(animal.species.traits)) && (return nothing)
return animal.species.traits[trait]
end
### FUNCTIONS INTEGRATING THE NATURE MODEL WITH THE REST OF PERSEPHONE
"""
stepagent!(animal, model)
......@@ -86,11 +54,7 @@ Update an animal by one day.
"""
function stepagent!(animal::Animal, model::AgentBasedModel)
animal.age += 1
animal.species.update!(animal,model)
if animal.energy <= 0
@debug "$(animal.species.name) $(animal.id) has died."
kill_agent!(animal, model)
end
animal.traits[animal.traits["phase"]](animal,model)
end
"""
......@@ -101,11 +65,10 @@ Initialise the model with all simulated animal populations.
function initnature!(model::AgentBasedModel)
# The config file determines which species are simulated in this run
for s in param("nature.targetspecies")
getspecies(s).initpop!(model)
funcname = Symbol("speciesfunction_"*s)
species = @eval $funcname()
species["initialise!"](model)
end
# Initialise the data output
newdataoutput(POPFILE, "Date;Species;Abundance", savepopulationdata,
param("nature.popoutfreq"))
newdataoutput(INDFILE, "Date;ID;X;Y;Species;Sex;Age;Energy",
saveindividualdata, param("nature.indoutfreq"))
initecologicaldata()
end
### Persephone - a socio-economic-ecological model of European agricultural landscapes.
###
### This file implements the macros needed for the species DSL.
###
#XXX configure species traits via a separate TOML file?
##TODO replace the current registerspecies()
function registerspecies(speciesdict)
println(speciesdict)
processeddict = Dict{String,Any}()
for k in keys(speciesdict)
processeddict[string(k)] = speciesdict[k]
end
processeddict["testphase"]()
end
##TODO docstring
macro species(name, body)
speciesfun = gensym()
quote
Core.@__doc__ $speciesfun = function()
$(esc(:name)) = string($(QuoteNode(name)))
$(esc(body))
return Base.@locals
end
registerspecies($speciesfun())
end
end
##TODO docstring
macro phase(name, body)
:($(esc(name)) = function(animal::Animal, model::AgentBasedModel) $body end)
#:($(esc(name)) = function() $body end) #for testing
end
......@@ -5,6 +5,8 @@
### Although I dare say the Wolpertinger is probably rather endangered...
###
##TODO convert to @species syntax
"""
initwolpertinger!(model)
......
......@@ -5,6 +5,8 @@
### Thankfully, wyverns are not a species we have to manage for...
###
##TODO convert to @species syntax
"""
initwyvern!(model)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment