module SimpleCrop using Persefone: AnnualDate, FarmPlot, Length, cm, SimulationModel import Persefone: stepagent!, croptype, cropname, cropheight, cropcover, cropyield, sow!, harvest!, isharvestable using Unitful: @u_str # TODO: alternatively just use ALMaSS.CropType ? struct CropType name::String group::String minsowdate::Union{Missing,AnnualDate} maxsowdate::Union{Missing,AnnualDate} end cropname(ct::CropType) = ct.name mutable struct CropState 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 """ stepagent!(farmplot, 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