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

Added world.mapdirectory parameter

Also updated CONTRIBUTORS.md, added a "none" option for
`core.logoutput`, and added type annotations to the Skylark struct
parent 6d12a003
Branches
Tags
No related merge requests found
...@@ -6,6 +6,24 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ...@@ -6,6 +6,24 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [v0.5.1] - unreleased
### Added
- `core.logoutput` parameter to define whether logs are printed to screen, file, none, or both
- `world.mapdirectory` parameter specifies the path to the directory in which
`landcovermap`, `farmfieldsmap`, and `weatherfile` are located
### Changed
### Deprecated
### Removed
### Fixed
## [v0.5.0] - 07-06-2024 ## [v0.5.0] - 07-06-2024
This release doesn't add much new functionality, but represents a major restructuring This release doesn't add much new functionality, but represents a major restructuring
...@@ -45,14 +63,10 @@ way the species definition macros work and are used. ...@@ -45,14 +63,10 @@ way the species definition macros work and are used.
- requires Julia 1.10 - requires Julia 1.10
### Deprecated
### Removed ### Removed
- Agents.jl dependency (including `AgentBasedModel` and functions for adding/moving/removing agents) - Agents.jl dependency (including `AgentBasedModel` and functions for adding/moving/removing agents)
### Fixed
## [v0.4.1] - 2023-11-14 ## [v0.4.1] - 2023-11-14
......
...@@ -2,28 +2,24 @@ ...@@ -2,28 +2,24 @@
### Lead developer ### Lead developer
- Daniel Vedder - Daniel Vedder (daniel.vedder@idiv.de)
### Supervisor
### Supporting developer(s) - Guy Pe'er (guy.peer@idiv.de)
- Lea Kolb
### Supporting developers
### Code reviewer - Marco Matthies
- Gabriel Díaz Iturry
- Ludmilla Figueiredo
### Code reviewers
### Supervisor - Ludmilla Figueiredo
- Marco Matthies
- Guy Pe'er
### Advisors ### Advisors
- Aletta Bonn - Aletta Bonn
- Kerstin Wiegand - Kerstin Wiegand
- Birgit Müller
MIT LICENSE MIT LICENSE
Copyright (c) 2022-2023 Daniel Vedder, Lea Kolb Copyright (c) 2022-2024 Persefone.jl developers
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
......
...@@ -86,4 +86,4 @@ You can then access all Persefone functions, such as `simulate()`. (See ...@@ -86,4 +86,4 @@ You can then access all Persefone functions, such as `simulate()`. (See
--- ---
© 2022-2023 the contributors (MIT license) © 2022-2024 the contributors (MIT license)
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
### ###
""" """
visualisemap(model, date, landcovermap) visualisemap(model, date, landcover)
Draw the model's land cover map and plot all individuals as points on it at Draw the model's land cover map and plot all individuals as points on it at
the specified date. If no date is passed, use the last date for which data the specified date. If no date is passed, use the last date for which data
...@@ -15,7 +15,10 @@ Returns a Makie figure object. ...@@ -15,7 +15,10 @@ Returns a Makie figure object.
function visualisemap(model::SimulationModel,date=nothing,landcover=nothing) function visualisemap(model::SimulationModel,date=nothing,landcover=nothing)
# load and plot the map # load and plot the map
# Note: if the landcover map is supplied, it needs to be rotr90'ed # Note: if the landcover map is supplied, it needs to be rotr90'ed
isnothing(landcover) && (landcover = rotr90(load(@param(world.landcovermap)))) if isnothing(landcover)
lcm = joinpath(@param(world.mapdirectory), @param(world.landcovermap))
landcover = rotr90(load(lcm))
end
f = Figure() f = Figure()
ax = Axis(f[1,1]) ax = Axis(f[1,1])
hidedecorations!(ax) hidedecorations!(ax)
......
...@@ -32,7 +32,7 @@ end ...@@ -32,7 +32,7 @@ end
""" """
modellogger(loglevel, outdir, output="both") modellogger(loglevel, outdir, output="both")
Create a logger object that writes output both to screen and to a logfile. Create a logger object that writes output to screen and/or a logfile.
This object is stored as `model.logger` and can then be used with `with_logger()`. This object is stored as `model.logger` and can then be used with `with_logger()`.
Note: requires [`createdatadir`](@ref) to be run first. Note: requires [`createdatadir`](@ref) to be run first.
""" """
...@@ -51,6 +51,8 @@ function modellogger(loglevel::String, outdir::String, output::String="both") ...@@ -51,6 +51,8 @@ function modellogger(loglevel::String, outdir::String, output::String="both")
return ConsoleLogger(logfile, loglevel) return ConsoleLogger(logfile, loglevel)
elseif output == "screen" elseif output == "screen"
return ConsoleLogger(stdout, loglevel) return ConsoleLogger(stdout, loglevel)
elseif output == "none"
return NullLogger()
else else
Base.error("Invalid log output target $output, should be file/screen/both.") Base.error("Invalid log output target $output, should be file/screen/both.")
end end
...@@ -95,8 +97,8 @@ function saveinputfiles(model::SimulationModel) ...@@ -95,8 +97,8 @@ function saveinputfiles(model::SimulationModel)
TOML.print(f, prepareTOML(model.settings)) TOML.print(f, prepareTOML(model.settings))
end end
# Copy the map files to the output folder # Copy the map files to the output folder
lcmap = @param(world.landcovermap) lcmap = joinpath(@param(world.mapdirectory), @param(world.landcovermap))
ffmap = @param(world.farmfieldsmap) ffmap = joinpath(@param(world.mapdirectory), @param(world.farmfieldsmap))
#TODO replace errors with exceptions #TODO replace errors with exceptions
!(isfile(lcmap)) && Base.error("The map file $(lcmap) doesn't exist.") !(isfile(lcmap)) && Base.error("The map file $(lcmap) doesn't exist.")
!(isfile(ffmap)) && Base.error("The map file $(ffmap) doesn't exist.") !(isfile(ffmap)) && Base.error("The map file $(ffmap) doesn't exist.")
......
...@@ -110,9 +110,11 @@ function initmodel(settings::Dict{String, Any}) ...@@ -110,9 +110,11 @@ function initmodel(settings::Dict{String, Any})
settings["core.outdir"], settings["core.outdir"],
settings["core.logoutput"]) settings["core.logoutput"])
with_logger(logger) do with_logger(logger) do
landscape = initlandscape(settings["world.landcovermap"], landscape = initlandscape(settings["world.mapdirectory"],
settings["world.landcovermap"],
settings["world.farmfieldsmap"]) settings["world.farmfieldsmap"])
weather = initweather(settings["world.weatherfile"], weather = initweather(joinpath(settings["world.mapdirectory"],
settings["world.weatherfile"]),
settings["core.startdate"], settings["core.startdate"],
settings["core.enddate"]) settings["core.enddate"])
crops = readcropparameters(settings["crop.cropfile"], crops = readcropparameters(settings["crop.cropfile"],
......
...@@ -4,13 +4,13 @@ ...@@ -4,13 +4,13 @@
### ###
skylarkhabitat = @habitat((@landcover() == grass || skylarkhabitat = @habitat((@landcover() == grass ||
# settle on grass or arable land (but not maize) # settle on grass or arable land (but not maize)
(@landcover() == agriculture && @cropname() != "maize")) && (@landcover() == agriculture && @cropname() != "maize")) &&
@distancetoedge() >= 5) # at least 50m from other habitats @distancetoedge() >= 5) # at least 50m from other habitats
#XXX this ought to check for distance to forest and builtup, #XXX this ought to check for distance to forest and builtup,
# but that's very expensive (see below) # but that's very expensive (see below)
# @distanceto(forest) > 5 && # at least 50m from forest edges # @distanceto(forest) > 5 && # at least 50m from forest edges
# @distanceto(builtup) > 5) # and from anthropogenic structures # @distanceto(builtup) > 5) # and from anthropogenic structures
""" """
Skylark Skylark
...@@ -30,32 +30,29 @@ At the moment, this implementation is still in development. ...@@ -30,32 +30,29 @@ At the moment, this implementation is still in development.
ISBN 3-89104-019-9 ISBN 3-89104-019-9
""" """
@species Skylark begin @species Skylark begin
#XXX use Unitful.jl #XXX use Unitful.jl
#TODO add type annotations
eggtime::Int64 = 11 # 11 days from laying to hatching eggtime::Int64 = 11 # 11 days from laying to hatching
eggpredationmortality::Float64 = 0.03 # per-day egg mortality from predation eggpredationmortality::Float64 = 0.03 # per-day egg mortality from predation
nestharvestmortality::Float64 = 0.9 # egg/nestling mortality after a harvest event (XXX guess) nestharvestmortality::Float64 = 0.9 # egg/nestling mortality after a harvest event (XXX guess)
nestlingtime = 7:11 # 7-11 days from hatching to leaving nest nestlingtime::Union{Int64,UnitRange{Int64}} = 7:11 # 7-11 days from hatching to leaving nest
nestlingpredationmortality::Float64 = 0.03 # per-day nestling mortality from predation nestlingpredationmortality::Float64 = 0.03 # per-day nestling mortality from predation
fledglingtime = 25:30 # 25-30 days from hatching to independence fledglingtime::Union{Int64,UnitRange{Int64}} = 25:30 # 25-30 days from hatching to independence
fledglingharvestmortality::Float64 = 0.5 # fledgling mortality after harvest fledglingharvestmortality::Float64 = 0.5 # fledgling mortality after harvest
fledglingpredationmortality::Float64 = 0.01 # per-day fledgling mortality from predation fledglingpredationmortality::Float64 = 0.01 # per-day fledgling mortality from predation
firstyearmortality::Float64 = 0.38 # total mortality in the first year after independence firstyearmortality::Float64 = 0.38 # total mortality in the first year after independence
migrationdates = () # is defined by each individual in @create(Skylark) migrationdates::Tuple = () # is defined by each individual in @create(Skylark)
migrationmortality::Float64 = 0.33 # chance of dying during the winter migrationmortality::Float64 = 0.33 # chance of dying during the winter
mate::Int64 = -1 # the agent ID of the mate (-1 if none) mate::Int64 = -1 # the agent ID of the mate (-1 if none)
nest = () # coordinates of current nest nest::Tuple = () # coordinates of current nest
nestingbegin = (April, 10) # begin nesting in the middle of April nestingbegin::Tuple{Int64,Int64} = (April, 10) # begin nesting in the middle of April
nestbuildingtime = 4:5 # 4-5 days needed to build a nest (doubled for first nest) nestbuildingtime::Union{Int64,UnitRange{Int64}} = 4:5 # 4-5 days needed to build a nest (doubled for first nest)
nestcompletion::Int64 = 0 # days left until the nest is built nestcompletion::Int64 = 0 # days left until the nest is built
eggsperclutch = 2:5 # 2-5 eggs laid per clutch eggsperclutch::Union{Int64,UnitRange{Int64}} = 2:5 # 2-5 eggs laid per clutch
clutch = [] # IDs of offspring in current clutch clutch::Vector{Int64} = Vector{Int64}() # IDs of offspring in current clutch
breedingdelay::Int64 = 18 # wait 18 days after hatching to start a new brood breedingdelay::Int64 = 18 # wait 18 days after hatching to start a new brood
nestingend::Int64 = July # last month of nesting nestingend::Int64 = July # last month of nesting
...@@ -68,7 +65,6 @@ As an egg, simply check for mortality and hatching. ...@@ -68,7 +65,6 @@ As an egg, simply check for mortality and hatching.
@phase Skylark egg begin @phase Skylark egg begin
@kill(self.eggpredationmortality, "predation") @kill(self.eggpredationmortality, "predation")
@respond(harvesting, @kill(self.nestharvestmortality, "harvest")) @respond(harvesting, @kill(self.nestharvestmortality, "harvest"))
if self.age == self.eggtime if self.age == self.eggtime
@setphase(nestling) @setphase(nestling)
end end
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
configfile = "src/parameters.toml" # location of the configuration file configfile = "src/parameters.toml" # location of the configuration file
outdir = "results" # location and name of the output folder outdir = "results" # location and name of the output folder
overwrite = "ask" # overwrite the output directory? (true/false/"ask") overwrite = "ask" # overwrite the output directory? (true/false/"ask")
logoutput = "both" # log output to screen/file/both logoutput = "both" # log output to screen/file/none/both
csvoutput = true # save collected data in CSV files csvoutput = true # save collected data in CSV files
visualise = true # generate result graphs visualise = true # generate result graphs
storedata = true # keep collected data in memory storedata = true # keep collected data in memory
...@@ -19,13 +19,14 @@ loglevel = "debug" # verbosity level: "debug", "info", "warn" ...@@ -19,13 +19,14 @@ loglevel = "debug" # verbosity level: "debug", "info", "warn"
processors = 2 # number of processors to use on parallel runs processors = 2 # number of processors to use on parallel runs
seed = 2 # seed value for the RNG (0 -> random value) seed = 2 # seed value for the RNG (0 -> random value)
startdate = 2022-01-01 # first day of the simulation startdate = 2022-01-01 # first day of the simulation
#enddate = 2022-12-31 # last day of the simulation enddate = 2022-12-31 # last day of the simulation
enddate = 2022-03-31 # last day of the simulation (test value) #enddate = 2022-03-31 # last day of the simulation (test value)
[world] [world]
landcovermap = "data/regions/jena-small/landcover.tif" # location of the landcover map mapdirectory = "data/regions/jena-small" # the directory in which all geographic data are stored
farmfieldsmap = "data/regions/jena-small/fields.tif" # location of the field geometry map landcovermap = "landcover.tif" # name of the landcover map in the map directory
weatherfile = "data/regions/jena-small/weather.csv" # location of the weather data file farmfieldsmap = "fields.tif" # name of the field geometry map in the map directory
weatherfile = "weather.csv" # name of the weather data file in the map directory
[farm] [farm]
farmmodel = "FieldManager" # which version of the farm model to use (not yet implemented) farmmodel = "FieldManager" # which version of the farm model to use (not yet implemented)
......
...@@ -38,13 +38,15 @@ mutable struct FarmEvent ...@@ -38,13 +38,15 @@ mutable struct FarmEvent
end end
""" """
initlandscape(landcovermap, farmfieldsmap) initlandscape(directory, landcovermap, farmfieldsmap)
Initialise the model landscape based on the map files specified in the Initialise the model landscape based on the map files specified in the
configuration. Returns a matrix of pixels. configuration. Returns a matrix of pixels.
""" """
function initlandscape(landcovermap::String, farmfieldsmap::String) function initlandscape(directory::String, landcovermap::String, farmfieldsmap::String)
@debug "Initialising landscape" @debug "Initialising landscape"
landcovermap = joinpath(directory, landcovermap)
farmfieldsmap = joinpath(directory, farmfieldsmap)
#TODO replace errors with exception #TODO replace errors with exception
!(isfile(landcovermap)) && Base.error("Landcover map $(landcovermap) doesn't exist.") !(isfile(landcovermap)) && Base.error("Landcover map $(landcovermap) doesn't exist.")
!(isfile(farmfieldsmap)) && Base.error("Field map $(farmfieldsmap) doesn't exist.") !(isfile(farmfieldsmap)) && Base.error("Field map $(farmfieldsmap) doesn't exist.")
......
...@@ -31,10 +31,12 @@ function inittestmodel(smallmap=true) ...@@ -31,10 +31,12 @@ function inittestmodel(smallmap=true)
if smallmap if smallmap
landscape = smalltestlandscape() landscape = smalltestlandscape()
else else
landscape = Ps.initlandscape(TESTSETTINGS["world.landcovermap"], landscape = Ps.initlandscape(TESTSETTINGS["world.mapdirectory"],
TESTSETTINGS["world.landcovermap"],
TESTSETTINGS["world.farmfieldsmap"]) TESTSETTINGS["world.farmfieldsmap"])
end end
weather = Ps.initweather(TESTSETTINGS["world.weatherfile"], weather = Ps.initweather(joinpath(TESTSETTINGS["world.mapdirectory"],
TESTSETTINGS["world.weatherfile"]),
TESTSETTINGS["core.startdate"], TESTSETTINGS["core.startdate"],
TESTSETTINGS["core.enddate"]) TESTSETTINGS["core.enddate"])
crops = Ps.readcropparameters(TESTSETTINGS["crop.cropfile"], crops = Ps.readcropparameters(TESTSETTINGS["crop.cropfile"],
......
...@@ -21,6 +21,7 @@ startdate = 2022-02-01 ...@@ -21,6 +21,7 @@ startdate = 2022-02-01
enddate = 2022-03-31 enddate = 2022-03-31
[world] [world]
mapdirectory = "."
landcovermap = "landcover_jena.tif" # location of the landcover map landcovermap = "landcover_jena.tif" # location of the landcover map
farmfieldsmap = "fields_jena.tif" # location of the field geometry map farmfieldsmap = "fields_jena.tif" # location of the field geometry map
weatherfile = "weather_jena.csv" # location of the weather data file weatherfile = "weather_jena.csv" # location of the weather data file
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment