Skip to content

Commit f7b4508

Browse files
Julians42Sbozzolo
andcommitted
Add XYZPoint regridding interpolation
This commit adds support for `ClimaCore.Geometry.XYZPoint` to `InterpolationsRegridder` which was needed in order to support interpolation of observational data used for simulation forcing to single column models in ClimaAtmos. Note that because single column models are currently represented as boxes we needed support for XYZPoint and not ZPoint objects. As such data that is read into these objects must be expanded to include ``dummy" x and y dimensions. More generally, this addition supports interpolations over boxes. To be conservative by default we throw an error if extrapolating outside of the Z range of the data. For ERA5 however this might need to be changed to `Linear` extrapolation as typically simulations will have points closer to the ground than the lowest point in ERA5. Co-authored-by: Julian Schmitt <[email protected]> Co-authored-by: Gabriele Bozzola <[email protected]>
1 parent 2f119a7 commit f7b4508

File tree

6 files changed

+112
-3
lines changed

6 files changed

+112
-3
lines changed

NEWS.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ ClimaUtilities.jl Release Notes
33

44
main
55
------
6+
7+
v0.1.23
8+
------
9+
10+
#### Support for Box Interpolations Regridder. PR[#151](https://github.com/CliMA/ClimaUtilities.jl/pull/151)
11+
12+
`Regridders.IterpolationsRegridder` now supports regridding on
13+
`ClimaCore.Geometry.XYZPoint` objects which allows for interpolation
14+
onto boxes and single column simulations.
15+
616
v0.1.22
717
------
818

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ClimaUtilities"
22
uuid = "b3f4f4ca-9299-4f7f-bd9b-81e1242a7513"
33
authors = ["Gabriele Bozzola <[email protected]>", "Julia Sloan <[email protected]>"]
4-
version = "0.1.22"
4+
version = "0.1.23"
55

66
[deps]
77
Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"

docs/src/regridders.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Currently, `Regridders` comes with two implementations:
1212
directly with files.
1313
2. `InterpolationsRegridder` uses
1414
[Interpolations.jl](https://github.com/JuliaMath/Interpolations.jl) to
15-
perform non-conservative linear interpolation onto lat-long(-z) grids.
15+
perform non-conservative linear interpolation onto lat-long(-z) and x-y-z grids.
1616
`InterpolationsRegridder` works directly with data.
1717

1818
!!! note

ext/InterpolationsRegridderExt.jl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ end
3333
# should be first, so files will have longitude as first dimension.
3434
totuple(pt::ClimaCore.Geometry.LatLongZPoint) = pt.long, pt.lat, pt.z
3535
totuple(pt::ClimaCore.Geometry.LatLongPoint) = pt.long, pt.lat
36+
totuple(pt::ClimaCore.Geometry.XYZPoint) = pt.x, pt.y, pt.z
3637

3738
"""
3839
InterpolationsRegridder(target_space::ClimaCore.Spaces.AbstractSpace
@@ -77,8 +78,12 @@ function Regridders.InterpolationsRegridder(
7778
isnothing(extrapolation_bc) &&
7879
(extrapolation_bc = (Intp.Periodic(), Intp.Flat(), Intp.Throw()))
7980
isnothing(dim_increasing) && (dim_increasing = (true, true, true))
81+
elseif eltype(coordinates) <: ClimaCore.Geometry.XYZPoint
82+
isnothing(extrapolation_bc) &&
83+
(extrapolation_bc = (Intp.Flat(), Intp.Flat(), Intp.Throw()))
84+
isnothing(dim_increasing) && (dim_increasing = (true, true, true))
8085
else
81-
error("Only lat-long, lat-long-z spaces are supported")
86+
error("Only lat-long, lat-long-z, and x-y-z spaces are supported")
8287
end
8388

8489
return InterpolationsRegridder(

test/TestTools.jl

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import ClimaCore
22
import ClimaComms
3+
import ClimaCore: CommonSpaces, Grids
4+
35
@static pkgversion(ClimaComms) >= v"0.6" && ClimaComms.@import_required_backends
46

57
function make_spherical_space(FT; context = ClimaComms.context())
@@ -92,3 +94,51 @@ function make_regional_space(FT; context = ClimaComms.context())
9294
vertical = vert_center_space,
9395
)
9496
end
97+
98+
function make_box_space(FT; context = ClimaComms.context())
99+
helem = (10, 10)
100+
xrange = (0.0, 1.0)
101+
yrange = (0.0, 1.0)
102+
zrange = (0.0, 1.0)
103+
Nq = 4
104+
zelem = 10
105+
106+
vertical_domain = ClimaCore.Domains.IntervalDomain(
107+
ClimaCore.Geometry.ZPoint{FT}(zrange[1]),
108+
ClimaCore.Geometry.ZPoint{FT}(zrange[2]),
109+
boundary_names = (:bottom, :top),
110+
)
111+
112+
x_domain = ClimaCore.Domains.IntervalDomain(
113+
ClimaCore.Geometry.XPoint{FT}(xrange[1]),
114+
ClimaCore.Geometry.XPoint{FT}(xrange[2]),
115+
boundary_names = (:west, :east),
116+
)
117+
118+
y_domain = ClimaCore.Domains.IntervalDomain(
119+
ClimaCore.Geometry.YPoint{FT}(yrange[1]),
120+
ClimaCore.Geometry.YPoint{FT}(yrange[2]),
121+
boundary_names = (:south, :north),
122+
)
123+
124+
horzdomain = ClimaCore.Domains.RectangleDomain(x_domain, y_domain)
125+
horzmesh = ClimaCore.Meshes.RectilinearMesh(horzdomain, helem...)
126+
horztopology = ClimaCore.Topologies.Topology2D(context, horzmesh)
127+
quad = ClimaCore.Spaces.Quadratures.GLL{Nq}()
128+
horzspace = ClimaCore.Spaces.SpectralElementSpace2D(horztopology, quad)
129+
130+
vertmesh = ClimaCore.Meshes.IntervalMesh(vertical_domain, nelems = zelem)
131+
132+
vert_center_space = ClimaCore.Spaces.CenterFiniteDifferenceSpace(
133+
ClimaComms.device(context),
134+
vertmesh,
135+
)
136+
137+
hybrid = ClimaCore.Spaces.ExtrudedFiniteDifferenceSpace(
138+
horzspace,
139+
vert_center_space,
140+
)
141+
142+
return hybrid
143+
144+
end

test/regridders.jl

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,50 @@ end
215215
end
216216
end
217217

218+
@testset "InterpolationsRegridderXYZPoint" begin
219+
helem = (10, 10)
220+
Nq = 4
221+
zelem = 10
222+
FT = Float64 # test for Float64
223+
224+
x, y, z = collect(0.0:1:5), collect(0.0:1:6), collect(0.0:1:7)
225+
226+
dimensions3D = (x, y, z)
227+
size3D = (6, 7, 8)
228+
229+
data_x3D = zeros(size3D)
230+
data_y3D = zeros(size3D)
231+
data_z3D = zeros(size3D)
232+
233+
for i in 1:length(x)
234+
for j in 1:length(y)
235+
for k in 1:length(z)
236+
data_x3D[i, j, k] = x[i]
237+
data_y3D[i, j, k] = y[j]
238+
data_z3D[i, j, k] = z[k]
239+
end
240+
end
241+
end
242+
# create the box space with helper function
243+
spaces = make_box_space(Float64; context)
244+
# create interpolation object with InterpolationsRegridder for XYZPoint object
245+
reg_box = Regridders.InterpolationsRegridder(spaces)
246+
247+
regridded_x = Regridders.regrid(reg_box, data_x3D, dimensions3D)
248+
249+
regridded_y = Regridders.regrid(reg_box, data_y3D, dimensions3D)
250+
251+
regridded_z = Regridders.regrid(reg_box, data_z3D, dimensions3D)
252+
253+
err_x = reg_box.coordinates.x .- regridded_x
254+
err_y = reg_box.coordinates.y .- regridded_y
255+
err_z = reg_box.coordinates.z .- regridded_z
256+
257+
@test maximum(err_x) < 1e-5
258+
@test maximum(err_y) < 1e-5
259+
@test maximum(err_z) < 1e-5
260+
end
261+
218262
@testset "TempestRegridder" begin
219263
for FT in (Float32, Float64)
220264
data_path = joinpath(@__DIR__, "test_data", "era5_1979_1.0x1.0_lai.nc")

0 commit comments

Comments
 (0)