diff --git a/src/nature/macros.jl b/src/nature/macros.jl index 67a1abd60e01f55cad661f66427abf6b97b278da..c4be6866b518fc122e2f0d0f743306dfa681a059 100644 --- a/src/nature/macros.jl +++ b/src/nature/macros.jl @@ -77,9 +77,6 @@ Set the parameters that are used to initialise this species' population. For parameter options, see [`PopInitParams`](@ref). """ 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).") quote # convert the macro body to a dict @@ -87,7 +84,9 @@ macro populate(species, params) $(esc(params)) return Base.@locals 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 diff --git a/src/nature/populations.jl b/src/nature/populations.jl index 63b49bc3053db4c5c71eb9810ea3cff0e815971e..75a80c010656266b64b699fa391aca2140cba0fe 100644 --- a/src/nature/populations.jl +++ b/src/nature/populations.jl @@ -41,29 +41,7 @@ using [`@populate`](@ref). asexual::Bool = false end -""" -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 +populationparameters(t::Type) = @error("No population parameters defined for $(t), use @populate.") """ initpopulation!(species, model) @@ -72,11 +50,21 @@ Initialise the population of the given species, based on the parameters stored in [`PopInitParams`](@ref). Define these using [`@populate`](@ref). """ 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 @warn("initpopulation() called with popsize and popdensity both <= 0") (p.popsize > 0 && p.popdensity > 0) && #XXX not sure what this would do @warn("initpopulation() called with popsize and popdensity both > 0") + # create as many individuals as necessary in the landscape n = 0 lastn = 0 width, height = size(model.landscape) @@ -86,8 +74,8 @@ function initpopulation!(species::String, model::SimulationModel) if p.habitat((x,y), model) && (p.popdensity <= 0 || @chance(1/p.popdensity)) #XXX what if pd==0? if p.pairs - a1 = s(length(model.animals)+1, male, (-1, -1), (x,y), p.phase) - a2 = s(length(model.animals)+1, female, (-1, -1), (x,y), p.phase) + a1 = speciestype(length(model.animals)+1, male, (-1, -1), (x,y), p.phase) + a2 = speciestype(length(model.animals)+1, female, (-1, -1), (x,y), p.phase) create!(a1, model) create!(a2, model) push!(model.animals, a1) @@ -95,7 +83,7 @@ function initpopulation!(species::String, model::SimulationModel) n += 2 else 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) push!(model.animals, a) n += 1 diff --git a/src/world/landscape.jl b/src/world/landscape.jl index 50d93ad7b4360bf38b14c394e6b8bec5f3eddab2..9beb16daef112dd4b9aabaadb275678bc34bcda4 100644 --- a/src/world/landscape.jl +++ b/src/world/landscape.jl @@ -21,6 +21,7 @@ mutable struct Pixel landcover::LandCover fieldid::Union{Missing,Int64} events::Vector{EventType} + #TODO add list of animal IDs end """