diff --git a/docs/src/callbackmanager.md b/docs/src/callbackmanager.md index 3ad4307e..ff748caa 100644 --- a/docs/src/callbackmanager.md +++ b/docs/src/callbackmanager.md @@ -7,10 +7,12 @@ functions from Julia's [Dates](https://docs.julialang.org/en/v1/stdlib/Dates/) m ## CallbackManager API ```@docs +ClimaUtilities.CallbackManager.HourlyCallback +ClimaUtilities.CallbackManager.MonthlyCallback +ClimaUtilities.CallbackManager.Monthly +ClimaUtilities.CallbackManager.EveryTimestep ClimaUtilities.CallbackManager.to_datetime ClimaUtilities.CallbackManager.strdate_to_datetime ClimaUtilities.CallbackManager.datetime_to_strdate ClimaUtilities.CallbackManager.trigger_callback -ClimaUtilities.CallbackManager.Monthly -ClimaUtilities.CallbackManager.EveryTimestep ``` diff --git a/src/CallbackManager.jl b/src/CallbackManager.jl index bd38f24f..955336b6 100644 --- a/src/CallbackManager.jl +++ b/src/CallbackManager.jl @@ -8,64 +8,71 @@ module CallbackManager import Dates -export to_datetime, - strdate_to_datetime, - datetime_to_strdate, - trigger_callback, +export HourlyCallback, + MonthlyCallback, Monthly, - EveryTimestep + EveryTimestep, + trigger_callback, + to_datetime, + strdate_to_datetime, + datetime_to_strdate """ - to_datetime(date) + AbstractCallback +""" +abstract type AbstractCallback end -Convert a `DateTime`-like object (e.g. `DateTimeNoLeap`) to a `DateTime`. -We need this since some data files we use contain -`DateTimeNoLeap` objects for dates, which can't be used for math with `DateTime`s. -The `DateTimeNoLeap` type uses the Gregorian calendar without leap years, while -the `DateTime` type uses Gregorian calendar with leap years. +""" + HourlyCallback{FT} -For consistency, all input data files should have dates converted to `DateTime` -before being used in a simulation. +This is a callback type that triggers at intervals of 1h or multiple hours. +""" +@kwdef struct HourlyCallback{FT} <: AbstractCallback + """ Time interval at which the callback is triggered. """ + dt::FT = FT(1) # hours + """ Function to be called at each trigger. """ + func::Function = do_nothing + """ Reference date for the callback. """ + ref_date::Array = [Dates.DateTime(0)] + """ Whether the callback is active. """ + active::Bool = false + """ Data to be passed to the callback function. """ + data::Array = [] +end -This function is similar to `reinterpret` in CFTime.jl. +""" + MonthlyCallback{FT} -# Arguments -- `date`: `DateTime`-like object to be converted to `DateTime` +This is a callback type that triggers at intervals of 1 month or multiple months. """ -function to_datetime(date) - return Dates.DateTime( - Dates.year(date), - Dates.month(date), - Dates.day(date), - Dates.hour(date), - Dates.minute(date), - Dates.second(date), - Dates.millisecond(date), - ) +@kwdef struct MonthlyCallback{FT} <: AbstractCallback + """ Time interval at which the callback is triggered. """ + dt::FT = FT(1) # months + """ Function to be called at each trigger. """ + func::Function = do_nothing + """ Reference date for the callback. """ + ref_date::Array = [Dates.DateTime(0)] + """ Whether the callback is active. """ + active::Bool = false + """ Data to be passed to the callback function. """ + data::Array = [] end """ - strdate_to_datetime(strdate::String) + dt_cb(cb::HourlyCallback) + dt_cb(cb::MonthlyCallback) -Convert from String ("YYYYMMDD") to Date format, -required by the official AMIP input files. +This function returns the time interval for the callback. """ -strdate_to_datetime(strdate::String) = Dates.DateTime( - parse(Int, strdate[1:4]), - parse(Int, strdate[5:6]), - parse(Int, strdate[7:8]), -) +dt_cb(cb::HourlyCallback) = Dates.Hour(cb.dt) +dt_cb(cb::MonthlyCallback) = Dates.Month(cb.dt) -""" - datetime_to_strdate(datetime::Dates.DateTime) -Convert from DateTime to String ("YYYYMMDD") format. """ -datetime_to_strdate(datetime::Dates.DateTime) = - string(lpad(Dates.year(datetime), 4, "0")) * - string(string(lpad(Dates.month(datetime), 2, "0"))) * - string(lpad(Dates.day(datetime), 2, "0")) + AbstractFrequency +This is an abstract type for the frequency of a callback function. +""" abstract type AbstractFrequency end struct Monthly <: AbstractFrequency end struct EveryTimestep <: AbstractFrequency end @@ -105,4 +112,56 @@ function trigger_callback( end end +""" + to_datetime(date) + +Convert a `DateTime`-like object (e.g. `DateTimeNoLeap`) to a `DateTime`. +We need this since some data files we use contain +`DateTimeNoLeap` objects for dates, which can't be used for math with `DateTime`s. +The `DateTimeNoLeap` type uses the Gregorian calendar without leap years, while +the `DateTime` type uses Gregorian calendar with leap years. + +For consistency, all input data files should have dates converted to `DateTime` +before being used in a simulation. + +This function is similar to `reinterpret` in CFTime.jl. + +# Arguments +- `date`: `DateTime`-like object to be converted to `DateTime` +""" +function to_datetime(date) + return Dates.DateTime( + Dates.year(date), + Dates.month(date), + Dates.day(date), + Dates.hour(date), + Dates.minute(date), + Dates.second(date), + Dates.millisecond(date), + ) +end + +""" + strdate_to_datetime(strdate::String) + +Convert from String ("YYYYMMDD") to Date format, +required by the official AMIP input files. +""" +strdate_to_datetime(strdate::String) = Dates.DateTime( + parse(Int, strdate[1:4]), + parse(Int, strdate[5:6]), + parse(Int, strdate[7:8]), +) + +""" + datetime_to_strdate(datetime::Dates.DateTime) + +Convert from DateTime to String ("YYYYMMDD") format. +""" +datetime_to_strdate(datetime::Dates.DateTime) = + string(lpad(Dates.year(datetime), 4, "0")) * + string(string(lpad(Dates.month(datetime), 2, "0"))) * + string(lpad(Dates.day(datetime), 2, "0")) + + end # module CallbackManager