From e5e9dee48f3c40f712c6c99f7a852ae839986d16 Mon Sep 17 00:00:00 2001 From: Daniel Vedder <daniel.vedder@idiv.de> Date: Fri, 9 Aug 2024 17:46:28 +0200 Subject: [PATCH] Made farm model configurable closes #69 --- src/core/utils.jl | 4 ++++ src/farm/farm.jl | 46 +++++++++++++++++++++++++++--------- src/nature/ecologicaldata.jl | 2 +- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/core/utils.jl b/src/core/utils.jl index 976b5aa..25d1b1d 100644 --- a/src/core/utils.jl +++ b/src/core/utils.jl @@ -165,6 +165,10 @@ A utility function to make sure that a number is within a given set of bounds. Returns `max`/`min` if `x` is greater/less than this. """ function bounds(x::Number; max::Number=Inf, min::Number=0) + if unit(x) != NoUnits + max = max*unit(x) + min = min*unit(x) + end x > max ? max : x < min ? min : x diff --git a/src/farm/farm.jl b/src/farm/farm.jl index 7a3ad80..5d024dd 100644 --- a/src/farm/farm.jl +++ b/src/farm/farm.jl @@ -3,6 +3,31 @@ ### This file is responsible for managing the farm module(s). ### + +## GENERIC TYPES AND FUNCTIONS + +"This is the agent type for the farm ABM." +abstract type Farmer <: ModelAgent end + +stepagent!(f::Farmer, model::SimulationModel) = + @error "Farmer type $(typeof(f)) has no stepagent!() method." + +""" + initfarms!(model) + +Initialise the model with a set of farm agents, depending on the configured farm model. +""" +function initfarms!(model::SimulationModel) + if @param(farm.farmmodel) == "BasicFarmer" + initbasicfarms!(model) + else + Base.error("Farm model $(@param(farm.farmmodel)) doesn't exist.") + end +end + + +## BASIC FARM MODEL + #XXX Initially, we're only working with a single simple crop rotation. # Later on, we need to figure out how to integrate several. const CROPROTATION = ["winter rape", "winter wheat", "maize", "winter barley"] @@ -10,12 +35,11 @@ const CROPROTATION = ["winter rape", "winter wheat", "maize", "winter barley"] #FIXME Currently, this is specific to the ALMaSS model. We need to figure out how to generalise it. """ - Farmer + BasicFarmer -This is the agent type for the farm ABM. +The BasicFarmer type simply applies a set crop rotation to his fields and keeps track of income. """ -mutable struct Farmer <: ModelAgent - #XXX make this into an abstract type and create subtypes for different farm submodels? (#69) +mutable struct BasicFarmer <: Farmer const id::Int64 # farmplots owned by this farmer and their associated crop rotations and next sowing date fields::Vector{Int64} @@ -29,7 +53,7 @@ end Update a farmer by one day. Cycle through all fields and see what management is needed. """ -function stepagent!(farmer::Farmer, model::SimulationModel) +function stepagent!(farmer::BasicFarmer, model::SimulationModel) for f in farmer.fields field = model.farmplots[f] ctype = croptype(field) @@ -50,13 +74,13 @@ function stepagent!(farmer::Farmer, model::SimulationModel) end """ - initfarms!(model) + initbasicfarms!(model) -Initialise the model with a set of farm agents. +Initialise the basic farm model. All fields are controlled by a single farmer actor +and are assigned as grassland, set-aside, or arable land with a crop rotation. """ -function initfarms!(model::SimulationModel) - #XXX initially, we only have one farmer controlling all fields in the region - farmer = Farmer(1, collect(1:length(model.farmplots)), Dict(), Dict(), 0) +function initbasicfarms!(model::SimulationModel) + farmer = BasicFarmer(1, collect(1:length(model.farmplots)), Dict(), Dict(), 0) model.farmers = [farmer] setasides = findsetasides(farmer, model) for field in model.farmplots @@ -83,7 +107,7 @@ end 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) +function findsetasides(farmer::BasicFarmer, model::SimulationModel) @param(farm.setaside) == 0 && return [] croparea = @areaof(sum(f -> isgrassland(f, model) ? 0 : length(f.pixels), model.farmplots[farmer.fields])) diff --git a/src/nature/ecologicaldata.jl b/src/nature/ecologicaldata.jl index 3a1e538..15527ca 100644 --- a/src/nature/ecologicaldata.jl +++ b/src/nature/ecologicaldata.jl @@ -69,7 +69,7 @@ function initskylarkdata(model::SimulationModel) newdataoutput!(model, "skylark_abundance", ["Date", "TotalAbundance", "Mating", "Breeding", "Nonbreeding", "Juvenile", "Migrants"], - "daily", skylarkabundance, skylarkpopulation) + @param(nature.popoutfreq), skylarkabundance, skylarkpopulation) # newdataoutput!(model, "skylark_territories", ["Date", "ID", "X", "Y"], # skylarkterritories, "monthly") #TODO add plotting function newdataoutput!(model, "skylark_breeding", -- GitLab