From eb3d2280bb3e09f5a8df1d8c88e28ca9136e977c Mon Sep 17 00:00:00 2001
From: Daniel Vedder <daniel.vedder@idiv.de>
Date: Thu, 8 Aug 2024 17:26:59 +0200
Subject: [PATCH] Added `@areaof()` macro and `isgrassland()` function

---
 src/core/utils.jl             | 10 ++++++++++
 src/crop/farmplot.jl          | 31 +++++++++++++++++++++++++------
 src/nature/populations.jl     |  4 ++--
 src/nature/species/skylark.jl |  2 +-
 4 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/src/core/utils.jl b/src/core/utils.jl
index ddffe48..27ef4d7 100644
--- a/src/core/utils.jl
+++ b/src/core/utils.jl
@@ -166,3 +166,13 @@ function bounds(x::Number; max::Number=Inf, min::Number=0)
         x < min ? min :
         x
 end
+
+"""
+    @areaof(npixels)
+
+Calculate the area of a given number of landscape pixels, knowing the resolution of the
+world map (requires the `model` object to be available).
+"""
+macro areaof(npixels)
+    :($(esc(npixels)) * $(esc(:model)).settings["world.mapresolution"]^2)
+end
diff --git a/src/crop/farmplot.jl b/src/crop/farmplot.jl
index 26eda95..d4b5787 100644
--- a/src/crop/farmplot.jl
+++ b/src/crop/farmplot.jl
@@ -12,7 +12,6 @@ mutable struct FarmPlot{T} <: ModelAgent
     const id::Int64
     pixels::Vector{Tuple{Int64, Int64}}
     farmer::Int64
-    croprotation::Vector{String}
     cropstate::T
 end
 
@@ -53,19 +52,39 @@ function harvest!(farmplot::FarmPlot{T}, model::SimulationModel) where T
     harvest!(farmplot.cropstate, model)  # TODO: multiply with area to return units of `g`
 end
 
+"""
+    @sow(cropname)
+
+Sow the named crop on the current field. Requires the variables `field` and `model`.
+"""
+macro sow(cropname)
+    :(sow!($(esc(:field)), $(esc(:model)), $(esc(cropname))))
+end
+
+"""
+    @harvest()
+
+Harvest the current field. Requires the variables `field` and `model`.
+"""
+macro harvest()
+    :(harvest!($(esc(:field)), $(esc(:model))))
+end
+
 ## UTILITY FUNCTIONS
 
 """
     isgrassland(farmplot, model)
 
-Classify a farmplot as grassland or not (i.e., is the landcover of >90% of its pixels grass?)
+Classify a farmplot as grassland or not (i.e., is the landcover of >80% of its pixels grass?)
 """
 function isgrassland(farmplot::FarmPlot, model::SimulationModel)
-    proportiongrass = count(pos -> @landcover() == grass, farmplot.pixels) / length(farmplot.pixels)
-    if proportiongrass > 0.9
+    proportiongrass = count(pos -> landcover(pos, model) == grass, farmplot.pixels) /
+        length(farmplot.pixels)
+    if proportiongrass > 0.8
         return true
-    elseif proportiongrass > 0.1
+    elseif proportiongrass > 0.2
         @warn "Unclear classification: farm plot $(farmplot.id) has $(proportiongrass*100)% grass."
+        proportiongrass >= 0.5 && return true
     end
     return false
 end
@@ -78,7 +97,7 @@ Calculate the average field size in hectares for the model landscape.
 function averagefieldsize(model::SimulationModel)
     sizes::Vector{Float64} = []
     for fp in model.farmplots
-        push!(sizes, length(fp.pixels)*@param(world.mapresolution)^2)
+        push!(sizes, @areaof(length(fp.pixels)))
     end
     return sum(sizes)/length(sizes) |> ha
 end
diff --git a/src/nature/populations.jl b/src/nature/populations.jl
index 2f45c71..144f046 100644
--- a/src/nature/populations.jl
+++ b/src/nature/populations.jl
@@ -84,7 +84,7 @@ function initpopulation!(species::Type, p::PopInitParams, model::SimulationModel
     lastn = 0
     width, height = size(model.landscape)
     if p.indarea > 0m²
-        pixelsperind = Int(round(p.indarea / @param(world.mapresolution)^2))
+        pixelsperind = Int(round(p.indarea / @areaof(1)))
     end
     while n == 0 || n < p.popsize
         for x in @shuffle!(Vector(1:width))
@@ -160,7 +160,7 @@ return the size as a plain number.
 function territorysize(a::Union{Animal,Int64}, model::SimulationModel,
                        units::Unitful.Units=ha, stripunits::Bool=false)
     a isa Int && (a = @animal(a))
-    size = length(a.territory) * @param(world.mapresolution)^2 |> Float64
+    size = length(a.territory) * @areaof(1) |> Float64
     stripunits ? ustrip(units, size) : size |> units
 end
 
diff --git a/src/nature/species/skylark.jl b/src/nature/species/skylark.jl
index ac582dc..feaa063 100644
--- a/src/nature/species/skylark.jl
+++ b/src/nature/species/skylark.jl
@@ -319,7 +319,7 @@ function findterritory(skylark::Skylark, model::SimulationModel)
             (isoccupied(model, "Skylark", c)) && continue
             push!(territory, c)
             quality = foragequality(skylark, model, c)
-            effectivesize += @param(world.mapresolution)^2*quality
+            effectivesize += @areaof(quality)
             (quality > 0) && (constrained = false)
             #XXX check for nesting habitats?
         end
-- 
GitLab