module SimpleCrop using Persefone: AbstractCropState, AbstractCropType, AnnualDate, Length, cm, SoilType, SimulationModel import Persefone: stepagent!, croptype, cropname, cropheight, cropcover, cropyield, makecropstate, sow!, harvest!, isharvestable using Unitful: @u_str # TODO: alternatively just use ALMaSS.CropType ? struct CropType <: AbstractCropType name::String group::String minsowdate::Union{Missing,AnnualDate} maxsowdate::Union{Missing,AnnualDate} end cropname(ct::CropType) = ct.name mutable struct CropState <: AbstractCropState croptype::CropType height::Length{Float64} end croptype(cs::CropState) = cs.croptype cropname(cs::CropState) = cropname(croptype(cs)) cropheight(cs::CropState) = cs.height cropcover(cs::CropState) = 0.0 cropyield(cs::CropState) = 0.0 # TODO: units? isharvestable(cs::CropState) = true makecropstate(crop_type::CropType, model::SimulationModel, soiltype::SoilType) = CropState(crop_type, 0.0cm) """ stepagent!(cropstate, model) Update a crop state by one day. """ function stepagent!(cs::CropState, model::SimulationModel) # height undergoes random diffusion, bounded by 0 delta_height = (2 * rand() - 1) * cm cs.height = max(0.0cm, cs.height + delta_height) end """ sow!(cropstate, model, cropname) Change the cropstate to sow the specified crop. """ function sow!(cs::CropState, model::SimulationModel, cropname::String) cs.croptype = model.crops[cropname] cs.height = 0.0cm end """ harvest!(cropstate, model) Harvest the crop of this cropstate. """ function harvest!(cs::CropState, model::SimulationModel) # TODO: set cs.croptype ? # TODO: this 1.0g/cm/m^2 height_to_yield factor should be a param # for every crop type yield = cs.height * 1.0u"g/cm/m^2" cs.height = 5.0cm return yield end end # module SimpleCrop