Skip to content

Commit ad5659d

Browse files
committed
Add TimeVaryingInput0D support for ITime
Add tests for TimeVaryingInput0D for 0D TVI with times of floats, ITime with no epoch, and ITime with epoch. Tests 0d TVI of floats can evaluate at ITime inputs, floating point inputs, and tests that an error is thrown with a datetime input. Test that error is thrown when evaluating a TVI of ITimes with no epoch at a DateTime. Test that TVI of ITime with epoch can be evaluated at ITimes, floats, or DateTimes. Test that TVI of ITime with no epoch can be evaluated at ITimes or floats. Make all the above tests pass by adding conversions to the `evaluate!` methods. use date instead of DateTime apply suggested style change varname bugfix
1 parent 0e9390d commit ad5659d

File tree

2 files changed

+298
-170
lines changed

2 files changed

+298
-170
lines changed

ext/TimeVaryingInputs0DExt.jl

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,17 @@ import ClimaUtilities.TimeVaryingInputs: extrapolation_bc
2020
import ClimaUtilities.TimeVaryingInputs
2121

2222
import ClimaUtilities.TimeManager: ITime, date
23+
using Dates
2324

2425
"""
2526
InterpolatingTimeVaryingInput0D
2627
2728
The constructor for InterpolatingTimeVaryingInput0D is not supposed to be used directly, unless you
2829
know what you are doing.
2930
30-
`times` and `vales` may have different float types, but they must be the same length, and we
31+
`times` and `values` may have different types, but they must be the same length, and we
3132
assume that they have been sorted to be monotonically increasing in time, without repeated
32-
values for the same timestamp.
33+
values for the same timestamp. `times` can have elements of type `ITime` or floats
3334
"""
3435
struct InterpolatingTimeVaryingInput0D{
3536
AA1 <: AbstractArray,
@@ -107,9 +108,13 @@ function TimeVaryingInputs.TimeVaryingInput(
107108

108109
if extrapolation_bc(method) isa PeriodicCalendar
109110
if extrapolation_bc(method) isa PeriodicCalendar{Nothing}
110-
isequispaced(times) || error(
111-
"PeriodicCalendar() boundary condition cannot be used because data is defined at non uniform intervals of time",
111+
if !isequispaced(
112+
eltype(times) <: ITime ? [float.(promote(times...))...] : times,
112113
)
114+
error(
115+
"PeriodicCalendar() boundary condition cannot be used because data is defined at non uniform intervals of time",
116+
)
117+
end
113118
else
114119
# We have the period in PeriodicCalendar
115120
error(
@@ -197,9 +202,18 @@ function TimeVaryingInputs.evaluate!(
197202
# interpolation between t_init and t_end. In this case, y0 = vals[end], y1 =
198203
# vals[begin], t1 - t0 = dt, and time - t0 = time - t_end
199204
if time > t_end
200-
@. dest =
201-
itp.vals[end] +
202-
(itp.vals[begin] - itp.vals[end]) / dt * (time - t_end)
205+
if time isa ITime
206+
FT = eltype(itp.vals)
207+
@. dest =
208+
itp.vals[end] + FT(
209+
(itp.vals[begin] - itp.vals[end]) / float(dt) *
210+
float((time - t_end)),
211+
)
212+
else
213+
@. dest =
214+
itp.vals[end] +
215+
(itp.vals[begin] - itp.vals[end]) / dt * (time - t_end)
216+
end
203217
return nothing
204218
end
205219
end
@@ -213,7 +227,7 @@ end
213227

214228
function TimeVaryingInputs.evaluate!(
215229
destination,
216-
itp::InterpolatingTimeVaryingInput0D,
230+
itp::InterpolatingTimeVaryingInput0D{<:AbstractArray{<:Number}},
217231
time::ITime,
218232
args...;
219233
kwargs...,
@@ -227,4 +241,53 @@ function TimeVaryingInputs.evaluate!(
227241
)
228242
end
229243

244+
function TimeVaryingInputs.evaluate!(
245+
destination,
246+
itp::InterpolatingTimeVaryingInput0D{<:AbstractArray{<:ITime}},
247+
eval_date::DateTime,
248+
args...;
249+
kwargs...,
250+
)
251+
t0_date = date(itp.range[1])
252+
diff_ms = eval_date - t0_date
253+
converted_time =
254+
ITime(diff_ms.value; period = typeof(diff_ms)(1), epoch = t0_date)
255+
return TimeVaryingInputs.evaluate!(
256+
destination,
257+
itp,
258+
converted_time,
259+
args...;
260+
kwargs...,
261+
)
262+
263+
end
264+
265+
function TimeVaryingInputs.evaluate!(
266+
destination,
267+
itp::InterpolatingTimeVaryingInput0D{<:AbstractArray{<:ITime}},
268+
time::Number,
269+
args...;
270+
kwargs...,
271+
)
272+
converted_time = first(promote(ITime(time), itp.range[1]))
273+
return TimeVaryingInputs.evaluate!(
274+
destination,
275+
itp,
276+
converted_time,
277+
args...;
278+
kwargs...,
279+
)
280+
281+
end
282+
283+
TimeVaryingInputs.evaluate!(
284+
destination,
285+
itp::InterpolatingTimeVaryingInput0D{<:AbstractArray{<:Number}},
286+
time::DateTime,
287+
args...;
288+
kwargs...,
289+
) = error(
290+
"Cannot evaluate InterpolatingTimeVaryingInput0D with times as numbers and inputs as DateTime",
291+
)
292+
230293
end

0 commit comments

Comments
 (0)