From 6af775feaf764515146a737a1451523bff7389a0 Mon Sep 17 00:00:00 2001 From: Daniel Vedder <daniel.vedder@idiv.de> Date: Fri, 6 Jan 2023 15:03:47 +0100 Subject: [PATCH] Wrote tests for `initpopulation()` Still errors - looks like `@habitat` still needs fixing. --- src/nature/nature.jl | 20 ++++++++++++++++++-- src/nature/populations.jl | 16 +++++----------- test/nature_tests.jl | 40 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/nature/nature.jl b/src/nature/nature.jl index 186c476..f0d647a 100644 --- a/src/nature/nature.jl +++ b/src/nature/nature.jl @@ -89,7 +89,9 @@ There are two parameters that all species must define: - `initialise!` should specify a function that will be used to create the starting population for this species. This function must take two arguments, a species dict and an `AgentBasedModel` object. - The easiest way to create this function is by using `initpopultion()`. + The easiest way to create this function is by using `initpopulation()`. + (To save typing, `@initialise!()` can be called instead. It defines + this variable and calls `initpopulation()`, all in one go.) - `phase` should be a string specifying the name of the first phase that individuals of this species will be assigned to on birth. @@ -111,6 +113,16 @@ macro species(name, body) end end +""" + @initialise!(habitatdescriptor; kwargs...) + +This is a wrapper around `initpopulation()` that can be called within the body of a `@species` +definition block. It saves the user having to define the required `initialise!` variable by hand. +""" +macro initialise!(habitatdescriptor, kwargs...) + :($(esc(:initialise!)) = initpopulation($habitatdescriptor, $(kwargs...))) +end + """ @phase(name, body) @@ -248,7 +260,11 @@ circumvented by directly creating an equivalent function. macro habitat(body) quote function($(esc(:pos)), $(esc(:model))) - ($(esc(body))) ? return true : return false + if $(esc(body)) + return true + else + return false + end end end end diff --git a/src/nature/populations.jl b/src/nature/populations.jl index bd6577f..62ba4e1 100644 --- a/src/nature/populations.jl +++ b/src/nature/populations.jl @@ -68,18 +68,12 @@ A simplified version of `initpopulation()`. Creates a function that initialises `popsize` individuals, spread at random across the landscape. If `popsize` is less than 1, it is interpreted as a population density (i.e. 1 animal per `popsize` pixels). """ -function initrandompopulation(popsize::Union{Int64,Float64}, asexual::Bool=true) - function(species::Dict{String,Any}, model::AgentBasedModel) - if popsize < 1.0 - x, y = size(model.landscape) - popsize = Int(round(x*y*popsize)) - end - for i in 1:popsize - sex = asexual ? hermaphrodite : rand([male, female]) - add_agent!(Animal, model, species, sex, 0) - end - @info "Initialised $(popsize) $(species["name"])s." +function initrandompopulation(popsize::Union{Int64,Float64}; kwargs...) + if popsize < 1.0 + x, y = size(model.landscape) + popsize = round(x*y*popsize) end + initpopulation(@habitat(true), popsize=Int(popsize), kwargs...) end #XXX initpopulation with dispersal from an original source? diff --git a/test/nature_tests.jl b/test/nature_tests.jl index fb15b97..0cabc1d 100644 --- a/test/nature_tests.jl +++ b/test/nature_tests.jl @@ -7,4 +7,42 @@ #TODO end -#TODO +@testset "Habitat macros" begin + #TODO +end + +@testset "Species initialisation" begin + model = smalltestlandscape() + specname = "test_animal" + species = Dict("name"=>specname) + # create a set of initialisation functions + initfun1 = Ps.initrandompopulation(10) + initfun2 = Ps.initrandompopulation(6*6*3, asexual=true) + initfun3 = Ps.initpopulation(@habitat(Ps.@landcover() == Ps.grass), pairs=true) + initfun4 = Ps.initpopulation(@habitat(Ps.@landcover() == Ps.water && + Ps.@countanimals(specname, 0) <= 5), + popsize=10) + # apply and test the initialisation functions + @test_logs (:info, "Initialised 10 $(specname)s.") initfun1(species, model) + @test all(a -> a.sex in (Ps.male, Ps.female), allagents(model)) + genocide!(model) + @test_logs (:info, "Initialised 108 $(specname)s.") initfun2(species, model) + @test countanimals((1,1), model, specname, 0) == countanimals((6,6), model, specname, 0) == 3 + @test Vector(nearby_animals((1,1), model, 0))[1].sex == Ps.hermaphrodite + genocide!(model) + @test_logs (:info, "Initialised 16 $(specname)s.") initfun3(species, model) + @test countanimals((2,2), model, specname, 2) == countanimals((5,3), model, specname, 1) == 0 + @test countanimals((5,5), model, specname, 0) == countanimals((6,6), model, specname, 0) == 2 + a1, a2 = Vector(nearby_animals((6,6), model, 0)) + @test a1.sex != a2.sex + genocide!(model) + @test_logs((:warn, "There are not enough suitable locations for $(specname) in the landscape."), + (:info, "Initialised 5 $(specname)s."), + initfun4(species, model)) + @test countanimals((1,1), model, specname, 4) == 0 + @test countanimals((6,4), model, specname, 0) == 5 +end + +@testset "Population functions" begin + #TODO +end -- GitLab