Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

replace TimeManager with CallbackManager module #108

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ ClimaUtilities.jl
to process input data and remap it onto the simulation grid.
- [`OutputPathGenerator`](https://clima.github.io/ClimaUtilities.jl/dev/outputpathgenerator/)
to prepare the output directory structure of a simulation.
- [`TimeManager`](https://clima.github.io/ClimaUtilities.jl/dev/timemanager/) to
- [`CallbackManager`](https://clima.github.io/ClimaUtilities.jl/dev/callbackmanager/) to
handle dates.

## ClimaUtilities.jl Developer Guidelines
Expand Down Expand Up @@ -178,6 +178,5 @@ two commits when the second just fixes the first).

The `Space` and `TimeVaryingInputs` modules were initially developed in the
context of [`ClimaLand`](https://github.com/CliMA/ClimaLand.jl), the
`TempestRegridder` and `TimeManager` ones were initially developed in
`TempestRegridder` and `CallbackManager` ones were initially developed in
[`ClimaCoupler`](https://github.com/CliMA/ClimaCoupler.jl).

2 changes: 1 addition & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pages = [
"DataHandling" => "datahandling.md",
"Regridders" => "regridders.md",
"OutputPathGenerator" => "outputpathgenerator.md",
"TimeManager" => "timemanager.md",
"CallbackManager" => "callbackmanager.md",
"Frequently Asked Questions" => "faqs.md",
]

Expand Down
18 changes: 18 additions & 0 deletions docs/src/callbackmanager.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# CallbackManager

This module contains functions that handle dates and times
in simulations. The functions in this module often call
functions from Julia's [Dates](https://docs.julialang.org/en/v1/stdlib/Dates/) module.

## 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!
```
16 changes: 0 additions & 16 deletions docs/src/timemanager.md

This file was deleted.

157 changes: 157 additions & 0 deletions src/CallbackManager.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
"""
CallbackManager

This module facilitates calendar functions and temporal interpolations
of data.
"""
module CallbackManager

import Dates

export HourlyCallback,
MonthlyCallback,
Monthly,
EveryTimestep,
trigger_callback!,
to_datetime,
strdate_to_datetime,
datetime_to_strdate

"""
AbstractCallback
"""
abstract type AbstractCallback end

"""
HourlyCallback{FT}

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 when the callback should be called. """
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

"""
MonthlyCallback{FT}

This is a callback type that triggers at intervals of 1 month or multiple months.
"""
@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

"""
dt_cb(cb::HourlyCallback)
dt_cb(cb::MonthlyCallback)

This function returns the time interval for the callback.
"""
dt_cb(cb::HourlyCallback) = Dates.Hour(cb.dt)
dt_cb(cb::MonthlyCallback) = Dates.Month(cb.dt)


"""
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

"""
trigger_callback!(callback, date_current)

If the callback is active and the current date is equal to or later than the
"next call" reference date/time, call the callback function and increment the
next call date based on the callback frequency. Otherwise, do nothing and leave
the next call date unchanged.

Note that the collection of data in `callback.data` must match the types, number,
and orderof arguments expected by `callback.func`.
"""
function trigger_callback!(callback::HourlyCallback, date_current)
if callback.active && date_current >= callback.ref_date[1]
callback.func(callback.data...)
callback.ref_date[1] += Dates.Hour(1)
end
end

function trigger_callback!(callback::MonthlyCallback, date_current)
if callback.active && date_current >= callback.ref_date[1]
callback.func(callback.data...)
callback.ref_date[1] += Dates.Month(1)
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
2 changes: 1 addition & 1 deletion src/ClimaUtilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module ClimaUtilities

include("Utils.jl")
include("MPIUtils.jl")
include("TimeManager.jl")
include("CallbackManager.jl")
include("DataStructures.jl")
include("FileReaders.jl")
include("Regridders.jl")
Expand Down
108 changes: 0 additions & 108 deletions src/TimeManager.jl

This file was deleted.

Loading
Loading