Skip to content
Snippets Groups Projects
Commit 21ea890b authored by xo30xoqa's avatar xo30xoqa
Browse files

Wrote tests for the habitat macros, lots of bug fixes

Everything now seems to work as intended :-) (Although a lot of the
nature tests are still missing.)
parent 6af775fe
Branches
Tags
No related merge requests found
...@@ -55,7 +55,7 @@ end ...@@ -55,7 +55,7 @@ end
Wrap up the simulation. Currently doesn't do anything except print some information. Wrap up the simulation. Currently doesn't do anything except print some information.
""" """
function finalise(model::AgentBasedModel) function finalise(model::AgentBasedModel)
@info "Simulated $(model.date-param("core.startdate")) days." @info "Simulated $(model.date-param("core.startdate"))."
@info "Simulation run completed at $(Dates.now()),\nwrote output to $(param("core.outdir"))." @info "Simulation run completed at $(Dates.now()),\nwrote output to $(param("core.outdir"))."
#XXX is there anything to do here? #XXX is there anything to do here?
#genocide!(model) #genocide!(model)
...@@ -67,7 +67,7 @@ end ...@@ -67,7 +67,7 @@ end
Carry out a complete simulation run. Carry out a complete simulation run.
""" """
function simulate(config::String=PARAMFILE) function simulate(config::String=PARAMFILE)
model = initialise(config) model = initialise(config) #TODO add seed value
runtime = Dates.value(param("core.enddate")-param("core.startdate"))+1 runtime = Dates.value(param("core.enddate")-param("core.startdate"))+1
step!(model, dummystep, stepsimulation!, runtime) step!(model, dummystep, stepsimulation!, runtime)
finalise(model) finalise(model)
......
...@@ -100,7 +100,7 @@ of type `AgentBasedModel`). ...@@ -100,7 +100,7 @@ of type `AgentBasedModel`).
""" """
macro species(name, body) macro species(name, body)
quote quote
Core.@__doc__ function $(esc(name))(model::AgentBasedModel) Core.@__doc__ function $(esc(name))($(esc(:model))::AgentBasedModel)
$(esc(:name)) = string($(QuoteNode(name))) $(esc(:name)) = string($(QuoteNode(name)))
$(esc(body)) $(esc(body))
vardict = Base.@locals vardict = Base.@locals
......
...@@ -38,18 +38,18 @@ function initpopulation(habitatdescriptor::Function; ...@@ -38,18 +38,18 @@ function initpopulation(habitatdescriptor::Function;
for y in shuffle!(Vector(1:height)) for y in shuffle!(Vector(1:height))
if habitatdescriptor((x,y), model) if habitatdescriptor((x,y), model)
if pairs if pairs
add_agent!(Animal, (x,y), model, species, female, 0) add_agent!((x,y), Animal, model, species, female, 0)
add_agent!(Animal, (x,y), model, species, male, 0) add_agent!((x,y), Animal, model, species, male, 0)
n += 2 n += 2
else else
sex = asexual ? hermaphrodite : rand([male, female]) sex = asexual ? hermaphrodite : rand([male, female])
add_agent!(Animal, (x,y), model, species, sex, 0) add_agent!((x,y), Animal, model, species, sex, 0)
n += 1 n += 1
end end
end end
(n >= popsize) && break (popsize > 0 && n >= popsize) && break
end end
(n >= popsize) && break (popsize > 0 && n >= popsize) && break
end end
if lastn == n # prevent an infinite loop - we don't have a Cray... if lastn == n # prevent an infinite loop - we don't have a Cray...
@warn "There are not enough suitable locations for $(specname) in the landscape." @warn "There are not enough suitable locations for $(specname) in the landscape."
...@@ -62,18 +62,13 @@ function initpopulation(habitatdescriptor::Function; ...@@ -62,18 +62,13 @@ function initpopulation(habitatdescriptor::Function;
end end
""" """
initrandompopulation(popsize, asexual=true) initrandompopulation(popsize; kwargs...)
A simplified version of `initpopulation()`. Creates a function that initialises A simplified version of `initpopulation()`. Creates a function that initialises
`popsize` individuals, spread at random across the landscape. If `popsize` is less `popsize` individuals, spread at random across the landscape.
than 1, it is interpreted as a population density (i.e. 1 animal per `popsize` pixels).
""" """
function initrandompopulation(popsize::Union{Int64,Float64}; kwargs...) function initrandompopulation(popsize::Int64; kwargs...)
if popsize < 1.0 initpopulation(@habitat(true); popsize=popsize, kwargs...)
x, y = size(model.landscape)
popsize = round(x*y*popsize)
end
initpopulation(@habitat(true), popsize=Int(popsize), kwargs...)
end end
#XXX initpopulation with dispersal from an original source? #XXX initpopulation with dispersal from an original source?
...@@ -137,7 +132,7 @@ function countanimals(pos::Tuple{Int64,Int64}, model::AgentBasedModel, ...@@ -137,7 +132,7 @@ function countanimals(pos::Tuple{Int64,Int64}, model::AgentBasedModel,
speciesname::String, radius::Int64=0) speciesname::String, radius::Int64=0)
n = 0 n = 0
for a in nearby_animals(pos, model, radius) for a in nearby_animals(pos, model, radius)
model[a].traits.name == speciesname && (n += 1) a.traits["name"] == speciesname && (n += 1)
end end
return n return n
end end
...@@ -14,7 +14,7 @@ At the moment, this implementation is still in development. ...@@ -14,7 +14,7 @@ At the moment, this implementation is still in development.
""" """
@species Skylark begin @species Skylark begin
popdensity = 1/10000 popsize = Int(round(1/10000*reduce(*, size(model.landscape))))
lifeexpectancy = 365*5 lifeexpectancy = 365*5
eggharvestmortality = 0.9 eggharvestmortality = 0.9
......
...@@ -11,13 +11,13 @@ It is purported to have the body of a hare, the wings of a bird, and the antlers ...@@ -11,13 +11,13 @@ It is purported to have the body of a hare, the wings of a bird, and the antlers
of a deer. of a deer.
""" """
@species Wolpertinger begin @species Wolpertinger begin
popdensity = 1/100000 popsize = Int(round(1/100000*reduce(*, size(model.landscape))))
fecundity = 0.02 fecundity = 0.02
mortality = 0.015 mortality = 0.015
maxspeed = 5 maxspeed = 5
crowdingfactor = maxspeed*2 crowdingfactor = maxspeed*2
initialise! = initrandompopulation(popdensity) initialise! = initrandompopulation(popsize)
phase = "lifephase" phase = "lifephase"
""" """
......
...@@ -15,18 +15,18 @@ Create a 6x6 landscape with three land cover types for testing: ...@@ -15,18 +15,18 @@ Create a 6x6 landscape with three land cover types for testing:
F F G G G G F F G G G G
F F G G G G F F G G G G
""" """
function smalltestlandscape() function smalltestlandscape(agenttype::Type=Animal)
landscape = Matrix{Pixel}(undef, 6, 6) landscape = Matrix{Pixel}(undef, 6, 6)
for x in 1:6 for x in 1:6
for y in 1:6 for y in 1:6
(x in (1:2) || y in (1:4)) ? lc = Ps.forest : lc = Ps.grass (x in (1:2) || y in (1:4)) ? lc = Ps.forest : lc = Ps.grass
landscape[x,y] = Pixel(lc, 0, []) landscape[x,y] = Pixel(lc, missing, [])
end end
end end
landscape[6,4] = Pixel(Ps.water, 0, []) landscape[6,4] = Pixel(Ps.water, 0, [])
space = GridSpace(size(landscape), periodic=false) space = GridSpace(size(landscape), periodic=false)
properties = Dict{Symbol,Any}(:landscape=>landscape) properties = Dict{Symbol,Any}(:landscape=>landscape)
return AgentBasedModel(Animal, space, properties=properties, warn=false) return AgentBasedModel(agenttype, space, properties=properties, warn=false)
end end
@testset "Landscape initialisation" begin @testset "Landscape initialisation" begin
......
...@@ -8,39 +8,63 @@ ...@@ -8,39 +8,63 @@
end end
@testset "Habitat macros" begin @testset "Habitat macros" begin
#TODO # set up the testing landscape
model = smalltestlandscape(Union{Animal,FarmPlot})
model.landscape[6,6] = Pixel(Ps.agriculture, 1, [])
species::Dict{String,Any} = Dict("name"=>"test_animal")
add_agent!((6,6), FarmPlot, model, [(6,6)], Ps.wheat, 1.2, 3.4)
add_agent!((3,3), Animal, model, species, Ps.male, 1)
add_agent!((4,4), Animal, model, species, Ps.female, 1)
# create a set of habitat descriptors
h1 = @habitat(Ps.@landcover() == Ps.water)
h2 = @habitat(Ps.@croptype() == Ps.wheat &&
Ps.@cropheight() < 2)
h3 = @habitat(Ps.@distanceto(water) > 2 &&
Ps.@distancetoedge() <= 2)
h4 = @habitat(Ps.@countanimals("test_animal", 1) == 1)
# test the descriptors
@test h1((6,4), model) == true
@test h1((5,4), model) == false
@test h2((6,6), model) == true
@test h2((5,6), model) == false
@test h3((3,3), model) == true
@test h3((5,4), model) == false
@test h3((6,1), model) == false
@test h4((2,2), model) == true
@test h4((3,3), model) == false
@test h4((1,1), model) == false
end end
@testset "Species initialisation" begin @testset "Species initialisation" begin
model = smalltestlandscape() model = smalltestlandscape()
specname = "test_animal" spec = "test_animal"
species = Dict("name"=>specname) species::Dict{String,Any} = Dict("name"=>spec)
# create a set of initialisation functions # create a set of initialisation functions
initfun1 = Ps.initrandompopulation(10) initfun1 = Ps.initrandompopulation(10)
initfun2 = Ps.initrandompopulation(6*6*3, asexual=true) initfun2 = Ps.initrandompopulation(6*6*3, asexual=true)
initfun3 = Ps.initpopulation(@habitat(Ps.@landcover() == Ps.grass), pairs=true) initfun3 = Ps.initpopulation(@habitat(Ps.@landcover() == Ps.grass), pairs=true)
initfun4 = Ps.initpopulation(@habitat(Ps.@landcover() == Ps.water && initfun4 = Ps.initpopulation(@habitat(Ps.@landcover() == Ps.water &&
Ps.@countanimals(specname, 0) <= 5), Ps.@countanimals("test_animal", 0) < 5),
popsize=10) popsize=10)
# apply and test the initialisation functions # apply and test the initialisation functions
@test_logs (:info, "Initialised 10 $(specname)s.") initfun1(species, model) @test_logs (:info, "Initialised 10 $(spec)s.") initfun1(species, model)
@test all(a -> a.sex in (Ps.male, Ps.female), allagents(model)) @test all(a -> a.sex in (Ps.male, Ps.female), allagents(model))
genocide!(model) genocide!(model)
@test_logs (:info, "Initialised 108 $(specname)s.") initfun2(species, model) @test_logs (:info, "Initialised 108 $(spec)s.") initfun2(species, model)
@test countanimals((1,1), model, specname, 0) == countanimals((6,6), model, specname, 0) == 3 @test Ps.countanimals((1,1), model, spec, 0) == Ps.countanimals((6,6), model, spec, 0) == 3
@test Vector(nearby_animals((1,1), model, 0))[1].sex == Ps.hermaphrodite @test all(a -> a.sex == Ps.hermaphrodite, allagents(model))
genocide!(model) genocide!(model)
@test_logs (:info, "Initialised 16 $(specname)s.") initfun3(species, model) @test_logs (:info, "Initialised 16 $(spec)s.") initfun3(species, model)
@test countanimals((2,2), model, specname, 2) == countanimals((5,3), model, specname, 1) == 0 @test Ps.countanimals((2,2), model, spec, 2) == Ps.countanimals((5,3), model, spec, 1) == 0
@test countanimals((5,5), model, specname, 0) == countanimals((6,6), model, specname, 0) == 2 @test Ps.countanimals((5,5), model, spec, 0) == Ps.countanimals((6,6), model, spec, 0) == 2
a1, a2 = Vector(nearby_animals((6,6), model, 0)) a1, a2 = Ps.nearby_animals((6,6), model, 0)
@test a1.sex != a2.sex @test a1.sex != a2.sex
genocide!(model) genocide!(model)
@test_logs((:warn, "There are not enough suitable locations for $(specname) in the landscape."), @test_logs((:warn, "There are not enough suitable locations for $(spec) in the landscape."),
(:info, "Initialised 5 $(specname)s."), (:info, "Initialised 5 $(spec)s."),
initfun4(species, model)) initfun4(species, model))
@test countanimals((1,1), model, specname, 4) == 0 @test Ps.countanimals((1,1), model, spec, 4) == 0
@test countanimals((6,4), model, specname, 0) == 5 @test Ps.countanimals((6,4), model, spec, 0) == 5
end end
@testset "Population functions" begin @testset "Population functions" begin
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment