From ead084439c1f766e5f888b5d23d838d5aa43f93c Mon Sep 17 00:00:00 2001 From: Daniel Vedder <daniel.vedder@idiv.de> Date: Thu, 8 Aug 2024 16:28:48 +0200 Subject: [PATCH] Continued work on farm model (doesn't run yet) --- src/crop/farmplot.jl | 13 +++++++- src/farm/farm.jl | 75 ++++++++++++++++++++++++++++++++++++++------ src/parameters.toml | 3 +- 3 files changed, 80 insertions(+), 11 deletions(-) diff --git a/src/crop/farmplot.jl b/src/crop/farmplot.jl index 35061b3..26eda95 100644 --- a/src/crop/farmplot.jl +++ b/src/crop/farmplot.jl @@ -55,8 +55,19 @@ end ## UTILITY FUNCTIONS +""" + isgrassland(farmplot, model) + +Classify a farmplot as grassland or not (i.e., is the landcover of >90% of its pixels grass?) +""" function isgrassland(farmplot::FarmPlot, model::SimulationModel) - #TODO + proportiongrass = count(pos -> @landcover() == grass, farmplot.pixels) / length(farmplot.pixels) + if proportiongrass > 0.9 + return true + elseif proportiongrass > 0.1 + @warn "Unclear classification: farm plot $(farmplot.id) has $(proportiongrass*100)% grass." + end + return false end """ diff --git a/src/farm/farm.jl b/src/farm/farm.jl index 29390ed..108f2ef 100644 --- a/src/farm/farm.jl +++ b/src/farm/farm.jl @@ -3,9 +3,6 @@ ### This file is responsible for managing the farm module(s). ### -###XXXXXXX In future, I want to expand Persefone into a proper ABM with multiple farm actors. -###XXXXXXX However, at the moment, all fields are controlled centrally -> see farm/farm.jl - """ Farmer @@ -24,11 +21,17 @@ end Update a farmer by one day. """ function stepagent!(farmer::Farmer, model::SimulationModel) - #TODO - # - check each field, whether it can be harvested - # - if so, harvest it and set its crop to "no growth" - # - [later: calculate income based on yield and annual price] - # - if a field has been harvested, check if the next crop can be sown + for f in farmer.fields + field = model.farmplots[f] + ctype = croptype(field) + if ctype.group != "semi-natural" && isharvestable(field) #TODO implement + harvest!(field, model) + #XXX later: calculate income based on yield and annual price + (ctype.group != "grass") && @sow("no growth") + elseif cropname(field) == "no growth" + #TODO if a field has been harvested, check if the next crop can be sown + end + end end """ @@ -37,5 +40,59 @@ end Initialise the model with a set of farm agents. """ function initfarms!(model::SimulationModel) - #TODO + #XXX initially, we only have one farmer controlling all fields in the region + farmer = Farmer(1, collect(1:length(model.farmplots)), 0) + model.farmers = [farmer] + setasides = findsetasides(farmer, model) #TODO implement + for field in model.farmplots + if isgrassland(field) + @sow("permanent grassland (seeded)") + elseif field.id in setasides + @sow("permanent set-aside") + else + @sow("no growth") + end + end +end + +""" + findsetasides(farmer, model) + +Return a vector of field IDs that this farmer should keep fallow to satisfy the configured +set-aside rules. +""" +function findsetasides(farmer::Farmer, model::SimulationModel) + @param(farm.setaside) == 0 && return [] + croparea = reduce(f -> isgrassland(f) ? 0 : length(f.pixels), model.farmplots[farmer.fields]) * + @param(world.mapresolution)^2 + setasidearea = 0m² + setasides = [] + for f in farmer.fields #XXX should be sorted smallest-largest for highest efficiency + field = model.farmplots[f] + isgrassland(f) && continue + push!(setasides, f) + setasidearea += length(field.pixels)*@param(world.mapresolution)^2 + if setasidearea >= croparea*@param(farm.setaside) + @debug "Farmer $(farmer.id) has set aside $(setasidearea |> ha)." + return setasides + end + end +end + +""" + @sow(cropname) + +Sow the named crop on the current field. Requires the variables `field` and `model`. +""" +macro sow(cropname) + :(sow!($(esc(:field)), $(esc(:model)), $(esc(cropname)))) +end + +""" + @harvest() + +Harvest the current field. Requires the variables `field` and `model`. +""" +macro harvest() + :(harvest!($(esc(:field)), $(esc(:model)))) end diff --git a/src/parameters.toml b/src/parameters.toml index ee391ab..9a5920f 100644 --- a/src/parameters.toml +++ b/src/parameters.toml @@ -31,7 +31,8 @@ weatherfile = "weather.csv" # name of the weather data file in the map directory [farm] farmmodel = "FieldManager" # which version of the farm model to use (not yet implemented) - +setaside = 0.04 # proportion of farm area set aside as fallow + [nature] #targetspecies = ["Wolpertinger", "Wyvern"] # list of target species to simulate - example species targetspecies = ["Skylark"] # list of target species to simulate -- GitLab