### Persefone.jl - a model of agricultural landscapes and ecosystems in Europe. ### ### Functions for switchable crop models. ### using StatsBase: mode """ initfields!(cropmodel, cropfile, growthfile) Initialise the crop model. Returns the crop types available in the simulation, as well as the types `Tcroptype` and `Tcropstate`. """ function initcropmodel(cropmodel::AbstractString, cropdirectory::AbstractString) if cropmodel == "almass" Tcroptype = ALMaSS.CropType Tcropstate = ALMaSS.CropState crops = ALMaSS.readcropparameters(cropdirectory) elseif cropmodel == "simple" Tcroptype = SimpleCrop.CropType Tcropstate = SimpleCrop.CropState crops_almass = ALMaSS.readcropparameters(cropdirectory) crops = Dict(name => SimpleCrop.CropType(ct.name, ct.group, ct.minsowdate, ct.maxsowdate) for (name, ct) in crops_almass) elseif cropmodel == "aquacrop" Tcroptype = AquaCropWrapper.CropType Tcropstate = AquaCropWrapper.CropState crops = AquaCropWrapper.readcropparameters(cropdirectory) else error("initcropmodel: no implementation for crop model '$cropmodel'") end return crops, Tcroptype, Tcropstate end """ initfields!(model) Initialise the farm plots in the simulation model. """ function initfields!(model::SimulationModel) convertid = Dict{Int64,Int64}() width, height = size(model.landscape) for x in 1:width for y in 1:height # for each pixel, we need to extract the field ID given by the map input # file, and convert it into an internal object ID for `model.farmplots` rawid = model.landscape[x,y].fieldid (ismissing(rawid)) && continue if rawid in keys(convertid) objectid = convertid[rawid] model.landscape[x,y].fieldid = objectid push!(model.farmplots[objectid].pixels, (x,y)) else soiltype = model.landscape[x,y].soiltype cropstate = makecropstate(model, soiltype) fp = FarmPlot(length(model.farmplots) + 1, [(x, y)], -1, soiltype, cropstate) push!(model.farmplots, fp) model.landscape[x,y].fieldid = fp.id convertid[rawid] = fp.id end end end # Adjust farmplot soil type to most common soil type of its # pixels, and set the cropstate soil type to this as well. for fp in model.farmplots fp.soiltype = mode(map(p -> model.landscape[p[1], p[2]].soiltype, fp.pixels)) set_cropstate_soiltype!(fp, model) end @info "Initialised $(length(model.farmplots)) farm plots." end # TODO: this function should be moved to the individual crop models, # and overloaded on the type of cropstate """ set_cropstate_soiltype!(farmplot, model) """ function set_cropstate_soiltype!(farmplot::FarmPlot, model::SimulationModel) if @param(crop.cropmodel) == "aquacrop" farmplot.cropstate.soiltype = farmplot.soiltype else # do nothing for other cropmodels end end """ makecropstate(model, soiltype) An internal utility function to initialise one instance of the configured crop growth model. """ function makecropstate(model::SimulationModel, soiltype::SoilType) if @param(crop.cropmodel) == "almass" phase = (month(model.date) < 3 ? ALMaSS.janfirst : ALMaSS.marchfirst) cs = ALMaSS.CropState( croptype = model.crops["natural grass"], phase = phase, ) elseif @param(crop.cropmodel) == "simple" cs = SimpleCrop.CropState( model.crops["natural grass"], 0.0m ) elseif @param(crop.cropmodel) == "aquacrop" croptype = model.crops["natural grass"] cs = AquaCropWrapper.CropState(croptype, soiltype, model) else Base.error("Unhandled crop model '$(@param(crop.cropmodel))' in makecropstate().") end return cs end