Skip to content
Snippets Groups Projects
Commit 1a7ea283 authored by xo30xoqa's avatar xo30xoqa
Browse files

Simplified @populate macro

I now use parametric methods to store initialised parameter structs,
rather than creating a special registry for these with a closure.
parent d6edd35b
No related branches found
No related tags found
No related merge requests found
...@@ -77,9 +77,6 @@ Set the parameters that are used to initialise this species' population. ...@@ -77,9 +77,6 @@ Set the parameters that are used to initialise this species' population.
For parameter options, see [`PopInitParams`](@ref). For parameter options, see [`PopInitParams`](@ref).
""" """
macro populate(species, params) macro populate(species, params)
#TODO I think I can make this simpler by using parametric methods
# (see https://docs.julialang.org/en/v1/manual/methods/#Parametric-Methods,
# https://stackoverflow.com/questions/42283820/julia-difference-between-type-and-datatype)
println("Will register $(species).") println("Will register $(species).")
quote quote
# convert the macro body to a dict # convert the macro body to a dict
...@@ -87,7 +84,9 @@ macro populate(species, params) ...@@ -87,7 +84,9 @@ macro populate(species, params)
$(esc(params)) $(esc(params))
return Base.@locals return Base.@locals
end end
registerpopulationparams($(esc(species)), fun()) # construct a parametric method that returns a parameterised PopInitParams object
# when called with the species Type
$(esc(:populationparameters))(s::Type{$(esc(species))}) = PopInitParams(; fun()...)
end end
end end
......
...@@ -41,29 +41,7 @@ using [`@populate`](@ref). ...@@ -41,29 +41,7 @@ using [`@populate`](@ref).
asexual::Bool = false asexual::Bool = false
end end
""" populationparameters(t::Type) = @error("No population parameters defined for $(t), use @populate.")
A closure to store the parameters needed to initialise each species' population.
Users register a new set of parameters using [`@populate`](@ref).
"""
#TODO I think I can make this simpler by using parametric methods
# (see https://docs.julialang.org/en/v1/manual/methods/#Parametric-Methods,
# https://stackoverflow.com/questions/42283820/julia-difference-between-type-and-datatype)
let populationparams = Dict{String,Tuple{Type,PopInitParams}}()
global function getpopulationparams(species::String)
populationparams[species]
end
global function registerpopulationparams(species::Type{T}, initparams::Dict{Symbol,Any}) where T <: Animal
# convert the dict to an InitParam struct and save it
println("Registering $(species).")
#XXX why is this necessary?
spstrings = split(string(species), ".") # strip out the module name, if necessary
speciesstring = length(spstrings) == 1 ? spstrings[1] : spstrings[2]
populationparams[speciesstring] = (species, PopInitParams(; initparams...))
#populationparams[species] = NamedTuple(k => v for (k,v) in initparams)
end
end
""" """
initpopulation!(species, model) initpopulation!(species, model)
...@@ -72,11 +50,21 @@ Initialise the population of the given species, based on the parameters stored ...@@ -72,11 +50,21 @@ Initialise the population of the given species, based on the parameters stored
in [`PopInitParams`](@ref). Define these using [`@populate`](@ref). in [`PopInitParams`](@ref). Define these using [`@populate`](@ref).
""" """
function initpopulation!(species::String, model::SimulationModel) function initpopulation!(species::String, model::SimulationModel)
s, p = getpopulationparams(species) # species constructor and parameters # get the species Type from its namestring
speciestype = nothing
for name in names(Persefone, all=true)
string(name) == species && (speciestype = getfield(Persefone, name))
end
isnothing(speciestype) && @error "Species $species is not defined."
#XXX can we get rid of the Persefone.<species> in the speciestype?
@debug "Initialising population of $species/$speciestype."
# get the PopInitParams and check for validity
p = populationparameters(speciestype)
(p.popsize <= 0 && p.popdensity <= 0) && #XXX not sure what this would do (p.popsize <= 0 && p.popdensity <= 0) && #XXX not sure what this would do
@warn("initpopulation() called with popsize and popdensity both <= 0") @warn("initpopulation() called with popsize and popdensity both <= 0")
(p.popsize > 0 && p.popdensity > 0) && #XXX not sure what this would do (p.popsize > 0 && p.popdensity > 0) && #XXX not sure what this would do
@warn("initpopulation() called with popsize and popdensity both > 0") @warn("initpopulation() called with popsize and popdensity both > 0")
# create as many individuals as necessary in the landscape
n = 0 n = 0
lastn = 0 lastn = 0
width, height = size(model.landscape) width, height = size(model.landscape)
...@@ -86,8 +74,8 @@ function initpopulation!(species::String, model::SimulationModel) ...@@ -86,8 +74,8 @@ function initpopulation!(species::String, model::SimulationModel)
if p.habitat((x,y), model) && if p.habitat((x,y), model) &&
(p.popdensity <= 0 || @chance(1/p.popdensity)) #XXX what if pd==0? (p.popdensity <= 0 || @chance(1/p.popdensity)) #XXX what if pd==0?
if p.pairs if p.pairs
a1 = s(length(model.animals)+1, male, (-1, -1), (x,y), p.phase) a1 = speciestype(length(model.animals)+1, male, (-1, -1), (x,y), p.phase)
a2 = s(length(model.animals)+1, female, (-1, -1), (x,y), p.phase) a2 = speciestype(length(model.animals)+1, female, (-1, -1), (x,y), p.phase)
create!(a1, model) create!(a1, model)
create!(a2, model) create!(a2, model)
push!(model.animals, a1) push!(model.animals, a1)
...@@ -95,7 +83,7 @@ function initpopulation!(species::String, model::SimulationModel) ...@@ -95,7 +83,7 @@ function initpopulation!(species::String, model::SimulationModel)
n += 2 n += 2
else else
sex = p.asexual ? hermaphrodite : @rand([male, female]) sex = p.asexual ? hermaphrodite : @rand([male, female])
a = s(length(model.animals)+1, sex, (-1, -1), (x,y), p.phase) a = speciestype(length(model.animals)+1, sex, (-1, -1), (x,y), p.phase)
create!(a, model) create!(a, model)
push!(model.animals, a) push!(model.animals, a)
n += 1 n += 1
......
...@@ -21,6 +21,7 @@ mutable struct Pixel ...@@ -21,6 +21,7 @@ mutable struct Pixel
landcover::LandCover landcover::LandCover
fieldid::Union{Missing,Int64} fieldid::Union{Missing,Int64}
events::Vector{EventType} events::Vector{EventType}
#TODO add list of animal IDs
end end
""" """
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment