Skip to content
Snippets Groups Projects
Commit 778d6e37 authored by xo30xoqa's avatar xo30xoqa
Browse files

Added automatic conversion of Tuple{Int64,Int64} to AnnualDate

parent 2fccb9f8
No related branches found
No related tags found
No related merge requests found
......@@ -149,3 +149,10 @@ julia> 2km / 10m
Within Persefone, the following units and dimensions have been imported for direct usage:
`cm`, `m`, `km`, `m²`, `ha`, `km²`, `mg`, `g`, `kg`, `Length`, `Area`, `Mass`.
### Dates
Persefone expands the default [Dates](https://docs.julialang.org/en/v1/stdlib/Dates/) library
with the [`AnnualDate`](@ref) type, which can be used to store dates that recur every year
(e.g. migration or harvest). `AnnualDates` can be compared and added/subtracted just as normal
dates. Use [`thisyear()`](@ref) to convert an `AnnualDate` to a `Date`.
......@@ -9,7 +9,7 @@ This file defines the module, including all exported symbols and two high-level
```@autodocs
Modules = [Persefone]
Pages = ["Persefone.jl"]
Pages = ["Persefone.jl", "core/utils.jl"]
```
## simulation.jl
......
......@@ -8,10 +8,11 @@
import Unitful: cm, m, km, ha, mg, g, kg, Length, Area, Mass
const = m^2
const km² = km^2
import Base./ # enable division with different length/area unit types
/(x::S,y::T) where {S<:Length, T<:Length} = (upreferred(x)/m) / (upreferred(y)/m)
/(x::S,y::T) where {S<:Area, T<:Area} = (upreferred(x)/) / (upreferred(y)/)
/(x::S,y::T) where {S<:Mass, T<:Mass} = (upreferred(x)/g) / (upreferred(y)/g)
# enable division with different length/area unit types
Base.:(/)(x::S,y::T) where {S<:Length, T<:Length} = (upreferred(x)/m) / (upreferred(y)/m)
Base.:(/)(x::S,y::T) where {S<:Area, T<:Area} = (upreferred(x)/) / (upreferred(y)/)
Base.:(/)(x::S,y::T) where {S<:Mass, T<:Mass} = (upreferred(x)/g) / (upreferred(y)/g)
## Utility type and function for working wth recurring dates
......@@ -20,6 +21,8 @@ import Base./ # enable division with different length/area unit types
A type to handle recurring dates (e.g. migration, harvest).
Stores a month and a day, and can be compared against normal dates.
To save typing, a Tuple{Int64,Int64} is automatically converted to an
AnnualDate, allowing this syntax: `nestingend::AnnualDate = (August, 15)`.
"""
mutable struct AnnualDate
month::Int64
......@@ -30,18 +33,31 @@ mutable struct AnnualDate
if !(0 < month <= 12)
Base.error("AnnualDate: month $month is out of range.") #TODO replace with exception
elseif !(0 < day <= 31)
# not strictly accurate (AnnualDate(February, 30) is possible), but good enough
Base.error("AnnualDate: day $day is out of range.") #TODO replace with exception
else
new(month, day)
end
end
# (automatically) convert integer tuples to AnnualDate.
# Allows writing `(August, 2)` instead of `AnnualDate(August, 2)` where an AnnualDate is expected.
AnnualDate(ad::Tuple{Int64,Int64}) = AnnualDate(ad...)
Base.convert(::Type{AnnualDate}, ad::Tuple{Int64,Int64}) = AnnualDate(ad)
# Interface with Dates
AnnualDate(date::Date) = AnnualDate(month(date), day(date))
Dates.month(ad::AnnualDate) = ad.month
Dates.day(ad::AnnualDate) = ad.day
# Instantiate a recurring date for a given year
"""
thisyear(annualdate, model)
nextyear(annualdate, model)
lastyear(annualdate, model)
Convert an AnnualDate to a Date, using the current/next/previous year of the simulation run.
"""
thisyear(ad::AnnualDate, model::SimulationModel) = Date(year(model.date), ad.month, ad.day)
nextyear(ad::AnnualDate, model::SimulationModel) = Date(year(model.date)+1, ad.month, ad.day)
lastyear(ad::AnnualDate, model::SimulationModel) = Date(year(model.date)-1, ad.month, ad.day)
......
......@@ -495,8 +495,7 @@ end
"""
@thisyear(annualdate)
Construct a date object referring to the current model year from an AnnualDate
(== Tuple{Int64,Int64}).
Construct a date object referring to the current model year from an AnnualDate.
"""
macro thisyear(annualdate)
:(thisyear($(esc(annualdate)), $(esc(:model))))
......@@ -505,9 +504,17 @@ end
"""
@nextyear(annualdate)
Construct a date object referring to the next year in the model from an AnnualDate
(== Tuple{Int64,Int64}).
Construct a date object referring to the next year in the model from an AnnualDate.
"""
macro nextyear(annualdate)
:(nextyear($(esc(annualdate)), $(esc(:model))))
end
"""
@lastyear(annualdate)
Construct a date object referring to the last year in the model from an AnnualDate.
"""
macro lastyear(annualdate)
:(lastyear($(esc(annualdate)), $(esc(:model))))
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment