Something went wrong on our end
-
Marco Matthies authoredMarco Matthies authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
cropmodels.jl 3.92 KiB
### 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