diff --git a/Project.toml b/Project.toml index 10e11cc5f83ee4dca77654ae4817288137df499d..7ed919c23cd1e7263a9b8ee27ecf4c985995b394 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Persefone" uuid = "039acd1d-2a07-4b33-b082-83a1ff0fd136" authors = ["Daniel Vedder <daniel.vedder@idiv.de>"] -version = "0.3.6" +version = "0.4.0" [deps] Agents = "46ada45e-f475-11e8-01d0-f70cc89e6671" diff --git a/src/Persefone.jl b/src/Persefone.jl index e02955ff3b27961baa22986d16a3c25f11287eac..cc6fef76642118c4b4c8c2b33fb756f8aa1992e2 100644 --- a/src/Persefone.jl +++ b/src/Persefone.jl @@ -110,7 +110,7 @@ include("nature/ecologicaldata.jl") # for f in readdir("nature/species", join=true) # endswith(f, ".jl") && include(f) # end -#include("nature/species/skylark.jl") +include("nature/species/skylark.jl") include("nature/species/wolpertinger.jl") include("nature/species/wyvern.jl") diff --git a/src/nature/nature.jl b/src/nature/nature.jl index b9e96ee85b2ac4c335e0ced081ae1d444ae55869..4fca51f3ded4ee9dd79429a8dfea10d54dfe5739 100644 --- a/src/nature/nature.jl +++ b/src/nature/nature.jl @@ -95,7 +95,7 @@ Run processes that affect all animals. function updatenature!(model::AgentBasedModel) # The migrant pool is sorted by date of return, so we can simply look at the top # of the stack to check whether any animals are returning today. - while !isempty(model.migrants) && model.migrants[1].second == model.date + while !isempty(model.migrants) && model.migrants[1].second <= model.date add_agent_pos!(model.migrants[1].first, model) @debug "$(animalid(model.migrants[1].first)) has returned." deleteat!(model.migrants, 1) diff --git a/src/nature/species/skylark.jl b/src/nature/species/skylark.jl index 98d71935b57d9e2ab79c1b0653cdbc13aa26807f..5b0a2e82cab5360c61a1737f6c77c50b38c11322 100644 --- a/src/nature/species/skylark.jl +++ b/src/nature/species/skylark.jl @@ -25,7 +25,7 @@ At the moment, this implementation is still in development. migrationdates = () habitats = @habitat((@landcover() == grass || - (@landcover() == agriculture && @croptype() != maize)) && + (@landcover() == agriculture && @cropname() != "maize")) && @distanceto(forest) > 5) @initialise(habitats, pairs=true, initfunction=initskylark) @@ -69,13 +69,18 @@ Initialise a skylark individual. Selects migration dates and checks if the bird should currently be on migration. """ function initskylark(animal::Animal, model::AgentBasedModel) + @debug "Added $(animalid(animal)) at $(animal.pos)" animal.migrationdates = migrationdates(animal, model) leave = animal.migrationdates[1] arrive = animal.migrationdates[2] m, d = monthday(model.date) migrate = (((m < arrive[1]) || (m == arrive[1] && d < arrive[2])) || ((m > leave[1]) || (m == leave[1] && d >= leave[2]))) - migrate && @migrate(Date(year(model.date)+year(1), arrive[1], arrive[2])) + if migrate + returndate = Date(year(model.date), arrive[1], arrive[2]) + model.date != @param(core.startdate) && (returndate += Year(1)) + @migrate(returndate) + end #TODO other stuff? end @@ -90,7 +95,7 @@ function migrationdates(skylark::Animal, model::AgentBasedModel) minarrive = skylark.sex == male ? (2, 15) : (3, 1) deltaleave = @rand(0:45) #XXX ought to be normally distributed deltaarrive = @rand(0:15) #XXX ought to be normally distributed - leave = monthday(Date(2000, minleave[1], minleave[2]) + Day(deltaleave)) - arrive = monthday(Date(2000, minarrive[1], minarrive[2]) + Day(deltaarrive)) + leave = monthday(Date(2001, minleave[1], minleave[2]) + Day(deltaleave)) + arrive = monthday(Date(2001, minarrive[1], minarrive[2]) + Day(deltaarrive)) (leave, arrive) end diff --git a/test/io_tests.jl b/test/io_tests.jl index aa45dd2dc483b78b9fee327eab0ac51652394d19..734ee7844566ddf2eb6cc01cd421204d9d253084 100644 --- a/test/io_tests.jl +++ b/test/io_tests.jl @@ -67,6 +67,8 @@ end @testset "Model object serialization" begin model = inittestmodel() Ps.createdatadir(@param(core.outdir), true) + originalenddate = @param(core.enddate) + @param(core.enddate) = Date(year(model.date), 2, 5) @test_logs((:debug, "Saved model object to results_testsuite/test.dat."), min_level=Logging.Debug, match_mode=:any, savemodelobject(model, "test")) @@ -75,11 +77,12 @@ end @test model.date == model2.date @test model.settings == model2.settings @test length(model.agents) == length(model2.agents) - simulate!(model) - simulate!(model2) + simulate!(Ps.withtestlogger(model)) + simulate!(Ps.withtestlogger(model2)) @test model.date == model2.date @test length(model.agents) == length(model2.agents) rm(@param(core.outdir), force=true, recursive=true) + @param(core.enddate) = originalenddate end @testset "Output visualisation" begin diff --git a/test/landscape_tests.jl b/test/landscape_tests.jl index aaf1f8e4628538c16601e2fdc20bdc67f18bbe8a..3a29f872a27dea2af4b5c60b662692dbd1caeae3 100644 --- a/test/landscape_tests.jl +++ b/test/landscape_tests.jl @@ -42,7 +42,8 @@ end @testset "Landscape functions" begin model = inittestmodel() - @test Ps.distanceto((2,3), model, Ps.forest) == 0 + @test Ps.distanceto((2,3), model, Ps.agriculture) == 0 + @test Ps.distanceto((2,3), model, Ps.forest) == 2 @test Ps.distanceto((2,3), model, Ps.grass) == 2 @test Ps.distanceto((2,3), model, Ps.water) == 4 @test Ps.distanceto((2,3), model, Ps.soil) == Inf diff --git a/test/nature_tests.jl b/test/nature_tests.jl index 1d6276b05a591bd374d4e18e2464182f9fcdb765..dddbb64ada3a88773f37efcdafbfab46e518a577 100644 --- a/test/nature_tests.jl +++ b/test/nature_tests.jl @@ -39,7 +39,7 @@ end species::Dict{String,Any} = Dict("name"=>spec) # create a set of initialisation functions initfun1 = Ps.initrandompopulation(10) - initfun2 = Ps.initrandompopulation(6*6*3, asexual=true) + initfun2 = Ps.initrandompopulation(8*8*3, asexual=true) initfun3 = Ps.initpopulation(@habitat(@landcover() == Ps.grass), pairs=true) initfun4 = Ps.initpopulation(@habitat(@landcover() == Ps.water && @countanimals(species="test_animal", radius=0) < 5), @@ -48,12 +48,12 @@ end @test_logs (:info, "Initialised 10 $(spec)s.") initfun1(species, model) @test all(a -> a.sex in (Ps.male, Ps.female), allagents(model)) genocide!(model) - @test_logs (:info, "Initialised 108 $(spec)s.") initfun2(species, model) + @test_logs (:info, "Initialised 192 $(spec)s.") initfun2(species, model) @test Ps.countanimals((1,1), model, species=spec, radius=0) == Ps.countanimals((6,6), model, species=spec, radius=0) == 3 @test all(a -> a.sex == Ps.hermaphrodite, allagents(model)) genocide!(model) - @test_logs (:info, "Initialised 16 $(spec)s.") initfun3(species, model) + @test_logs (:info, "Initialised 36 $(spec)s.") initfun3(species, model) @test Ps.countanimals((2,2), model, species=spec, radius=2) == Ps.countanimals((5,3), model, species=spec, radius=1) == 0 @test Ps.countanimals((5,5), model, species=spec, radius=0) == @@ -192,3 +192,30 @@ end #TODO end + +@testset "Skylark submodel" begin + # set up a modified test landscape + model = inittestmodel() + model.landscape[3,7] = Pixel(Ps.forest, missing, []) + species = Ps.Skylark(model) + # test migration + @test_logs((:info, "Initialised 2 Skylarks."), + (:debug, "Skylark 1 has migrated."), + (:debug, "Skylark 2 has migrated."), + min_level=Logging.Debug, match_mode=:any, + species["initialise!"](species, Ps.withtestlogger(model))) + @test nagents(model) == 0 + @test length(model.migrants) == 2 + @test model.migrants[1].first.sex != model.migrants[2].first.sex + for a in model.migrants + leave, arrive = a.first.migrationdates + @test leave[1] in (9, 10) || (leave[1] == 11 && leave[2] <= 15) + @test (arrive[1] == 2 && arrive[2] >= 15) || (arrive[1] == 3 && arrive[2] <= 15) + end + model.date = Date(year(model.date), 3, 17) + @test_logs((:debug, "Skylark 1 has returned."), + (:debug, "Skylark 2 has returned."), + min_level=Logging.Debug, match_mode=:any, + Ps.updatenature!(Ps.withtestlogger(model))) + #TODO +end diff --git a/test/runtests.jl b/test/runtests.jl index 78d32931d147e946905dfd86d639bf908cc6c397..4636903dfea5c7034e079cbae9f42b5eec5c95fc 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -58,20 +58,25 @@ end """ smalltestlandscape() -Create a 6x6 landscape with three land cover types for testing: +Create a 8x8 landscape with five land cover types for testing: - F F F F F F - F F F F F F - F F F F F F - F F F F F W - F F G G G G - F F G G G G + A A A A A A A A + A A A A A A A A + A A A A A A A A + A A A A A W A A + F F G G G G G G + F F G G G G G G + F F G G G G G G + B B B B B B B B """ function smalltestlandscape() - landscape = Matrix{Pixel}(undef, 6, 6) - for x in 1:6 - for y in 1:6 - (x in (1:2) || y in (1:4)) ? lc = Ps.forest : lc = Ps.grass + landscape = Matrix{Pixel}(undef, 8, 8) + for x in 1:8 + for y in 1:8 + (y in (1:4)) ? lc = Ps.agriculture : + (x in (1:2)) ? lc = Ps.forest : + (y == 8) ? lc = Ps.builtup : + lc = Ps.grass landscape[x,y] = Pixel(lc, missing, []) end end