Skip to content

Commit

Permalink
Simplify TimeVaryingInputs0D
Browse files Browse the repository at this point in the history
Recent PRs in `ClimaCore` and
`ClimaComms` (CliMA/ClimaCore.jl#2114 and
CliMA/ClimaComms.jl#103) changed how contexts
are adapted to GPUs. This, coupled with
CliMA/ClimaAtmos.jl#3522, prompted me to look
again at the `TimeVaryingInputs0D` struct.

This struct is used in two main ways:
- to set site-level forcings/parameters (in ClimaLand)
- to set fields that have constant value on the globe (e.g., CO2)

The previous implementation achieved GPU compatibility by moving
everything to the GPU. This is not a great idea when the operation being
performed is some variation of linear interpolation in one
dimension (time) and for just one data point, as there is nothing really
to be parallelized. This choice was made because initially this feature
was only used in single-site ClimaLand runs, where all we cared about
was to be able to run on GPU. The other day, I realized that I could
have GPU compatibility in a much simpler and more robust way by
leveraging the `fill!` function. With this commit, 0D interpolation (1D
in time, 0D spatially) is changed to be always on the CPU, and the
result is written to the Field (or destination in general) using
`fill!`.

As a result, the CUDA extension is no longer needed.
  • Loading branch information
Sbozzolo committed Jan 21, 2025
1 parent f080ba3 commit 33b8e57
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 87 deletions.
13 changes: 13 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@ ClimaUtilities.jl Release Notes
main
------

v0.1.21
------

#### Simplified `TimeVaryingInput0D`, removed `context` argument. PR [#148](https://github.com/CliMA/ClimaUtilities.jl/pull/148)

The need for a dedicated CUDA extension was by leveraging `ClimaCore` functions.
As a result, the code for `TimeVaryingInput0D` could be significantly
simplified, while attaining greater performance at the same time.

As a result, the keyword argument `context` is no longer required in
constructing this type of `TimeVaryingInput`s. In the future, the argument will
be removed.

v0.1.20
------

Expand Down
3 changes: 1 addition & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "ClimaUtilities"
uuid = "b3f4f4ca-9299-4f7f-bd9b-81e1242a7513"
authors = ["Gabriele Bozzola <[email protected]>", "Julia Sloan <[email protected]>"]
version = "0.1.20"
version = "0.1.21"

[deps]
Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
Expand All @@ -21,7 +21,6 @@ ClimaUtilitiesClimaCoreExt = "ClimaCore"
ClimaUtilitiesClimaCoreInterpolationsExt = ["ClimaCore", "Interpolations"]
ClimaUtilitiesClimaCoreNCDatasetsExt = ["ClimaCore", "NCDatasets"]
ClimaUtilitiesNCDatasetsExt = "NCDatasets"
ClimaUtilitiesCUDAExt = "CUDA"
ClimaUtilitiesClimaCoreTempestRemapExt = "ClimaCoreTempestRemap"

[compat]
Expand Down
2 changes: 1 addition & 1 deletion docs/src/inputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ regridding onto the computational domains (using [`Regridders`](@ref regridder_m

`TimeVaryingInputs` support:
- analytic functions of time;
- pairs of 1D arrays (for `PointSpaces`);
- pairs of 1D arrays (e.g., for `PointSpaces` or constant fields);
- 2/3D NetCDF files (including composing multiple variables from one or more files into one variable);
- linear interpolation in time (default), nearest neighbors, and "period filling";
- boundary conditions and repeating periodic data.
Expand Down
31 changes: 0 additions & 31 deletions ext/ClimaUtilitiesCUDAExt.jl

This file was deleted.

63 changes: 15 additions & 48 deletions ext/TimeVaryingInputs0DExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ module TimeVaryingInputs0DExt

import ClimaCore
import ClimaCore: ClimaComms
import ClimaCore: DeviceSideContext
import ClimaCore.Fields: Adapt

import ClimaUtilities.Utils:
Expand Down Expand Up @@ -35,7 +34,6 @@ struct InterpolatingTimeVaryingInput0D{
AA1 <: AbstractArray,
AA2 <: AbstractArray,
M <: AbstractInterpolationMethod,
CC <: ClimaComms.AbstractCommsContext,
R <: Tuple,
} <: AbstractTimeVaryingInput
# AA1 and AA2 could be different because of different FTs
Expand All @@ -49,9 +47,6 @@ struct InterpolatingTimeVaryingInput0D{
"""Interpolation method"""
method::M

"""ClimaComms context"""
context::CC

"""Range of times over which the interpolator is defined. range is always defined on the
CPU. Used by the in() function."""
range::R
Expand All @@ -66,23 +61,6 @@ function Base.in(time, itp::InterpolatingTimeVaryingInput0D)
return itp.range[1] <= time <= itp.range[2]
end


# GPU compatibility
function Adapt.adapt_structure(to, itp::InterpolatingTimeVaryingInput0D)
times = Adapt.adapt_structure(to, itp.times)
vals = Adapt.adapt_structure(to, itp.vals)
method = Adapt.adapt_structure(to, itp.method)
range = Adapt.adapt_structure(to, itp.range)
# On a GPU, we have a "ClimaCore.DeviceSideContext"
InterpolatingTimeVaryingInput0D(
times,
vals,
method,
DeviceSideContext(),
range,
)
end

function TimeVaryingInputs.evaluate!(
destination,
itp::InterpolatingTimeVaryingInput0D,
Expand All @@ -93,35 +71,29 @@ function TimeVaryingInputs.evaluate!(
if extrapolation_bc(itp.method) isa Throw
time in itp || error("TimeVaryingInput does not cover time $time")
end
TimeVaryingInputs.evaluate!(
ClimaComms.device(itp.context),
parent(destination),
itp,
time,
itp.method,
)
scalar_dest = [zero(eltype(destination))]

return nothing
end
TimeVaryingInputs.evaluate!(scalar_dest, itp, time, itp.method)
fill!(destination, scalar_dest[])

function TimeVaryingInputs.evaluate!(
device::ClimaComms.AbstractCPUDevice,
destination,
itp::InterpolatingTimeVaryingInput0D,
time,
args...;
kwargs...,
)
TimeVaryingInputs.evaluate!(parent(destination), itp, time, itp.method)
return nothing
end

function TimeVaryingInputs.TimeVaryingInput(
times::AbstractArray,
vals::AbstractArray;
context = nothing,
method::AbstractInterpolationMethod = LinearInterpolation(),
context = ClimaComms.context(),
)
########### DEPRECATED ###############
if !isnothing(context)
Base.depwarn(
"The keyword argument `context` is no longer required for TimeVaryingInputs. It will be removed.",
:TimeVaryingInput,
)
end
########### DEPRECATED ###############

issorted(times) || error("Can only interpolate with sorted times")
length(times) == length(vals) ||
error("times and vals have different lengths")
Expand All @@ -145,16 +117,11 @@ function TimeVaryingInputs.TimeVaryingInput(
end
end

# When device is CUDADevice, ArrayType will be a CUDADevice, so that times and vals get
# copied to the GPU.
ArrayType = ClimaComms.array_type(ClimaComms.device(context))

range = (times[begin], times[end])
return InterpolatingTimeVaryingInput0D(
ArrayType(times),
ArrayType(vals),
copy(times),
copy(vals),
method,
context,
range,
)
end
Expand Down
6 changes: 1 addition & 5 deletions test/time_varying_inputs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,13 @@ end
input = TimeVaryingInputs.TimeVaryingInput(
times,
vals;
context,
method = TimeVaryingInputs.NearestNeighbor(),
)

# Nearest neighbor interpolation with Flat
input_clamp = TimeVaryingInputs.TimeVaryingInput(
times,
vals;
context,
method = TimeVaryingInputs.NearestNeighbor(
TimeVaryingInputs.Flat(),
),
Expand All @@ -135,7 +133,6 @@ end
input_periodic_calendar = TimeVaryingInputs.TimeVaryingInput(
times,
vals;
context,
method = TimeVaryingInputs.NearestNeighbor(
TimeVaryingInputs.PeriodicCalendar(),
),
Expand All @@ -145,7 +142,6 @@ end
input_periodic_calendar_linear = TimeVaryingInputs.TimeVaryingInput(
times,
vals;
context,
method = TimeVaryingInputs.LinearInterpolation(
TimeVaryingInputs.PeriodicCalendar(),
),
Expand Down Expand Up @@ -226,7 +222,7 @@ end
@test Array(parent(dest))[1] == vals[10]

# Linear interpolation
input = TimeVaryingInputs.TimeVaryingInput(times, vals; context)
input = TimeVaryingInputs.TimeVaryingInput(times, vals)

TimeVaryingInputs.evaluate!(dest, input, 0.1)

Expand Down

0 comments on commit 33b8e57

Please sign in to comment.