diff --git a/docs/src/developing.md b/docs/src/developing.md index 89ca256aa8135967573ce1e499c23af173f3ff96..7e2c3c63ceb2fb1037ba9022ef6293ee2a5ed8aa 100644 --- a/docs/src/developing.md +++ b/docs/src/developing.md @@ -129,3 +129,25 @@ To build the documentation, run `make docs`, or `cd docs; julia builddocs.jl` Persefone uses [Makie](https://makie.org/) as a plotting library to generate its output graphics. Additionally, Persefone Desktop uses [QML.jl](https://github.com/JuliaGraphics/QML.jl) to create its graphical user interface. + +### Unitful.jl + +Throughout the source code, variables can be tagged with their appropriate units using +the [Unitful.jl](https://painterqubits.github.io/Unitful.jl/stable/) library. This makes +the code easier to understand, and also allows automatic unit conversion: + +```julia +julia> 1ha == 10000m² +true + +julia> 2km |> m +2000 m + +julia> 2km / 10m +200.0 +``` + +Within Persefone, the following units and dimensions have been imported for direct usage: +`cm`, `m`, `km`, `m²`, `ha`, `km²`, `Length`, `Area`. For a full list of supported units, +see [here](https://github.com/PainterQubits/Unitful.jl/blob/master/src/pkgdefaults.jl). +To define new units, see [the documentation](https://painterqubits.github.io/Unitful.jl/stable/newunits/). diff --git a/src/nature/species/skylark.jl b/src/nature/species/skylark.jl index b639630b22f5a3b891308e1f04b69a7286a5e21d..9f4e2e7ce5e300db45e441552c74fc2e8e70a7a4 100644 --- a/src/nature/species/skylark.jl +++ b/src/nature/species/skylark.jl @@ -3,11 +3,10 @@ ### This file holds the code for the Eurasian Skylark (Alauda arvensis). ### -#XXX global variable +#XXX global variable/function skylarkhabitat = @habitat((@landcover() == grass || - # settle on grass or arable land (but not maize) (@landcover() == agriculture && @cropname() != "maize")) && - @distancetoedge() > 50m) # at least 50m from other habitats + @distancetoedge() > 50m) #XXX this ought to check for distance to forest and builtup, # but that's very expensive (see below) # @distanceto(forest) > 5 && # at least 50m from forest edges diff --git a/test/landscape_tests.jl b/test/landscape_tests.jl index 10bd212907286e3ffd36330eaf4b77595ce5dbcc..b82576512052685ee743d91ff42a5f3dfdfcfeb4 100644 --- a/test/landscape_tests.jl +++ b/test/landscape_tests.jl @@ -47,14 +47,14 @@ end @test Ps.directionto((2,3), model, Ps.grass) == (1,2) @test Ps.directionto((2,3), model, Ps.water) == (4,1) @test Ps.directionto((2,3), model, Ps.soil) == nothing - @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.agriculture) == 0m + @test Ps.distanceto((2,3), model, Ps.forest) == 20m + @test Ps.distanceto((2,3), model, Ps.grass) == 20m + @test Ps.distanceto((2,3), model, Ps.water) == 40m @test Ps.distanceto((2,3), model, Ps.soil) == Inf - @test Ps.distancetoedge((1,1), model) == 4 - @test Ps.distancetoedge((4,4), model) == 1 - @test Ps.distancetoedge((6,6), model) == 2 + @test Ps.distancetoedge((1,1), model) == 40m + @test Ps.distancetoedge((4,4), model) == 10m + @test Ps.distancetoedge((6,6), model) == 20m end @testset "Weather initialisation" begin diff --git a/test/nature_tests.jl b/test/nature_tests.jl index da1c81cbfc8ddc03fdb7e220188aaae7d800cfc8..5d84ac9400fb894ed5d2fff4778763a5d34f15df 100644 --- a/test/nature_tests.jl +++ b/test/nature_tests.jl @@ -57,11 +57,11 @@ end) # end eval # create a set of habitat descriptors h1 = @habitat(@landcover() == Ps.water) h2 = @habitat(@cropname() == "winter wheat" && - @cropheight() < 2) - h3 = @habitat(@distanceto(Ps.water) > 2 && - @distancetoedge() <= 2) + @cropheight() < 2) #XXX randomly chosen value + h3 = @habitat(@distanceto(Ps.water) > 20m && + @distancetoedge() <= 20m) #FIXME nested macros don't work properly, counting seems wrong - h4 = @habitat(@countanimals(radius=1) == 1) + h4 = @habitat(@countanimals(radius=10m) == 1) # test the descriptors @test h1((6,4), model) == true @test h1((5,4), model) == false @@ -94,12 +94,12 @@ end # initialisation parameters, set 3 initparams3 = Ps.PopInitParams(birthphase = Ps.life, initphase = Ps.life, pairs = true, habitat = @habitat(@landcover() == Ps.grass)) - @test_logs((:warn, "initpopulation!() called with popsize and popdensity both <= 0"), + @test_logs((:warn, "initpopulation!() called with popsize and indarea both <= 0"), (:info, "Initialised 36 Mermaids."), Ps.initpopulation!(Ps.Mermaid, initparams3, model)) - @test Ps.countanimals((2,2), model, radius=2) == Ps.countanimals((5,3), model, radius=1) == 0 + @test Ps.countanimals((2,2), model, radius=20m) == Ps.countanimals((5,3), model, radius=10m) == 0 @test Ps.countanimals((5,5), model) == Ps.countanimals((6,6), model) == 2 - a1, a2 = Ps.nearby_animals((6,6), model, radius=0) + a1, a2 = Ps.nearby_animals((6,6), model, radius=0m) @test a1.sex != a2.sex Ps.killallanimals!(model) # initialisation parameters, set 4 @@ -109,7 +109,7 @@ end @test_logs((:warn, "There are not enough suitable locations for Mermaid in the landscape."), (:info, "Initialised 5 Mermaids."), Ps.initpopulation!(Ps.Mermaid, initparams4, model)) - @test Ps.countanimals((1,1), model, radius=4) == 0 + @test Ps.countanimals((1,1), model, radius=40m) == 0 @test Ps.countanimals((6,4), model) == 5 end @@ -124,11 +124,11 @@ end @test_logs((:debug, "Created Mermaid 1."), min_level=Logging.Debug, Ps.create!(mermaid, Ps.withtestlogger(model))) # test population initialisation - @test_logs((:warn, "initpopulation!() called with popsize and popdensity both <= 0"), + @test_logs((:warn, "initpopulation!() called with popsize and indarea both <= 0"), (:info, "Initialised 2 Mermaids."), Ps.initpopulation!("Mermaid", model)) @test Ps.nagents(model) == 2 - @test Ps.countanimals((1,1), model, radius=4) == 0 + @test Ps.countanimals((1,1), model, radius=40m) == 0 @test Ps.countanimals(pond, model) == 2 @test model.animals[1].age == 0 # test event handling @@ -226,6 +226,8 @@ end @testset "Skylark submodel" begin # set up a modified test landscape model = inittestmodel() + #FIXME the tests here fail if @distancetoedge >= 50m in `skylarkhabitat`, + # as no individuals are initialised for x in 1:6 for y in 5:6 model.landscape[x,y] = Pixel(Ps.agriculture, missing, [], []) diff --git a/test/runtests.jl b/test/runtests.jl index 8540f05b24689f69b43ef6a28169b1e4a2b68e34..6bf31e2bf18b1c8bfb4e10cc0fd00a755f347461 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -20,6 +20,10 @@ const Ps = Persefone const TESTPARAMETERS = joinpath(pkgdir(Persefone), "test/test_parameters.toml") const TESTSETTINGS = Ps.getsettings(TESTPARAMETERS) +import Unitful: cm, m, km, ha, Length, Area +const m² = m^2 +const km² = km^2 + """ inittestmodel(smallmap=true) diff --git a/test/test_parameters.toml b/test/test_parameters.toml index 33413f85989fe7c08935a3c87020d09cb005167b..4d88eb3bf0deeee889c106ce4ff90329e1706a89 100644 --- a/test/test_parameters.toml +++ b/test/test_parameters.toml @@ -21,7 +21,8 @@ startdate = 2022-02-01 enddate = 2022-03-31 [world] -mapdirectory = "." +mapdirectory = "." # the directory in which all geographic data are stored +mapresolution = 10 # map resolution in meters landcovermap = "landcover_jena.tif" # location of the landcover map farmfieldsmap = "fields_jena.tif" # location of the field geometry map weatherfile = "weather_jena.csv" # location of the weather data file @@ -30,7 +31,8 @@ weatherfile = "weather_jena.csv" # location of the weather data file farmmodel = "FieldManager" # which version of the farm model to use (not yet implemented) [nature] -targetspecies = ["Wolpertinger", "Wyvern"] # list of target species to simulate +targetspecies = ["Wolpertinger", "Wyvern"] # list of target species to simulate - example species +#targetspecies = ["Skylark"] # list of target species to simulate popoutfreq = "daily" # output frequency population-level data, daily/monthly/yearly/end/never indoutfreq = "daily" # output frequency individual-level data, daily/monthly/yearly/end/never insectmodel = ["season", "habitat", "pesticides"] # which factors affect insect growth ("weather" is not yet implemented)