Skip to content

Commit 8fe8f7a

Browse files
committed
regrid 2D data onto 2D space with LatLongZPoints
1 parent 485b8eb commit 8fe8f7a

File tree

3 files changed

+81
-37
lines changed

3 files changed

+81
-37
lines changed

NEWS.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ ClimaUtilities.jl Release Notes
44
main
55
------
66

7+
#### Allow regridding 2D data onto 2D spaces with LatLongZ coordinates. PR[#176](https://github.com/CliMA/ClimaUtilities.jl/pull/176)
8+
9+
Some 2D spaces use `LatLongPoint` coordinates and others use `LatLongZPoint`,
10+
depending on how they were constructed. Both cases are now supported, so we can
11+
read in 2D data onto a 2D space with either coordinate type.
12+
713
#### Interpolation method for InterpolationsRegridder
814

915
`InterpolationsRegridder` now accepts the new keyword argument
@@ -29,9 +35,9 @@ v0.1.23
2935

3036
#### Support for Box Interpolations Regridder. PR[#151](https://github.com/CliMA/ClimaUtilities.jl/pull/151)
3137

32-
`Regridders.IterpolationsRegridder` now supports regridding on
33-
`ClimaCore.Geometry.XYZPoint` objects which allows for interpolation
34-
onto boxes and single column simulations.
38+
`Regridders.IterpolationsRegridder` now supports regridding on
39+
`ClimaCore.Geometry.XYZPoint` objects which allows for interpolation
40+
onto boxes and single column simulations.
3541

3642
v0.1.22
3743
------

ext/InterpolationsRegridderExt.jl

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,23 @@ This function is allocating.
111111
"""
112112
function Regridders.regrid(regridder::InterpolationsRegridder, data, dimensions)
113113
FT = ClimaCore.Spaces.undertype(regridder.target_space)
114+
115+
# For a 2D space with LatLongZ coordinates, we need to drop the z dimension to regrid 2D data.
116+
if eltype(regridder.coordinates) <: ClimaCore.Geometry.LatLongZPoint &&
117+
!(
118+
regridder.target_space isa
119+
ClimaCore.Spaces.ExtrudedFiniteDifferenceSpace
120+
) &&
121+
length(dimensions) == 2
122+
123+
@warn "Regridding 2D data onto a 2D space with LatLongZ coordinates."
124+
coords = map(regridder.coordinates) do coord
125+
ClimaCore.Geometry.LatLongPoint(coord.lat, coord.long)
126+
end
127+
else
128+
coords = regridder.coordinates
129+
end
130+
114131
dimensions_FT = map(dimensions, regridder.dim_increasing) do dim, increasing
115132
!increasing ? reverse(FT.(dim)) : FT.(dim)
116133
end
@@ -135,7 +152,7 @@ function Regridders.regrid(regridder::InterpolationsRegridder, data, dimensions)
135152
# Move it to GPU (if needed)
136153
gpuitp = Adapt.adapt(ClimaComms.array_type(regridder.target_space), itp)
137154

138-
return map(regridder.coordinates) do coord
155+
return map(coords) do coord
139156
gpuitp(totuple(coord)...)
140157
end
141158
end

test/regridders.jl

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -205,27 +205,29 @@ end
205205

206206
coordinates = ClimaCore.Fields.coordinate_field(horzspace)
207207

208+
# Since lon uses periodic BCs but is not periodic itself, error is large at 180 degrees.
209+
# We check that the error is small at other indices, and that the values at -180 and 180 agree.
210+
function check_lon_error(coords_lon, lon_regrid)
211+
inds_normal = findall(!=(180), Array(parent(coords_lon)))
212+
err_lon = abs.(
213+
Array(parent(coords_lon))[inds_normal] .-
214+
Array(parent(lon_regrid))[inds_normal],
215+
)
216+
@test maximum(err_lon) < 1e-4
217+
218+
inds_lon_180 = findall(==(180), Array(parent(coords_lon)))
219+
inds_lon_neg180 = findall(==(-180), Array(parent(coords_lon)))
220+
err_lon_180 = abs.(
221+
Array(parent(lon_regrid))[inds_lon_180] .-
222+
Array(parent(coords_lon))[inds_lon_neg180],
223+
)
224+
@test maximum(err_lon_180) < 1e-5
225+
end
226+
208227
# Compute max err
209228
err_lat = abs.(coordinates.lat .- regridded_lat)
210229
@test maximum(err_lat) < 1e-5
211-
212-
# Since lon uses periodic BCs, error is large at 180 degrees.
213-
# We check that the error is small at other indices, and that the values at -180 and 180 agree.
214-
# Note that for data that is actually periodic, the error at 180 degrees will also be small.
215-
inds_normal = findall(!=(180), parent(coordinates.long))
216-
err_lon = abs.(
217-
parent(coordinates.long)[inds_normal] .-
218-
parent(regridded_lon)[inds_normal],
219-
)
220-
@test maximum(err_lon) < 1e-4
221-
222-
inds_lon_180 = findall(==(180), parent(coordinates.long))
223-
inds_lon_neg180 = findall(==(-180), parent(coordinates.long))
224-
err_lon_180 = abs.(
225-
parent(regridded_lon)[inds_lon_180] .-
226-
parent(coordinates.long)[inds_lon_neg180],
227-
)
228-
@test maximum(err_lon_180) < 1e-5
230+
check_lon_error(coordinates.long, regridded_lon)
229231

230232
# 3D space
231233
extrapolation_bc = (
@@ -273,28 +275,47 @@ end
273275

274276
# Compute max err
275277
err_lat = abs.(coordinates.lat .- regridded_lat)
276-
err_lon = abs.(coordinates.long .- regridded_lon)
277278
err_z = abs.(coordinates.z .- regridded_z)
278279

279280
@test maximum(err_lat) < 1e-5
280281
@test maximum(err_z) < 1e-5
282+
check_lon_error(coordinates.long, regridded_lon)
281283

282-
# Since lon uses periodic BCs but is not periodic itself, error is large at 180 degrees.
283-
# We check that the error is small at other indices, and that the values at -180 and 180 agree.
284-
inds_normal = findall(!=(180), parent(coordinates.long))
285-
err_lon = abs.(
286-
parent(coordinates.long)[inds_normal] .-
287-
parent(regridded_lon)[inds_normal],
284+
# 2D space with LatLongZ coordinates
285+
surface_space = ClimaCore.Spaces.level(hv_center_space, 1) # SpectralElementSpace2D with LatLongZPoint coordinates
286+
coordinates = ClimaCore.Fields.coordinate_field(surface_space)
287+
@assert !(
288+
surface_space isa ClimaCore.Spaces.ExtrudedFiniteDifferenceSpace
288289
)
289-
@test maximum(err_lon) < 1e-4
290+
@assert eltype(coordinates) <: ClimaCore.Geometry.LatLongZPoint
290291

291-
inds_lon_180 = findall(==(180), parent(coordinates.long))
292-
inds_lon_neg180 = findall(==(-180), parent(coordinates.long))
293-
err_lon_180 = abs.(
294-
parent(regridded_lon)[inds_lon_180] .-
295-
parent(coordinates.long)[inds_lon_neg180],
296-
)
297-
@test maximum(err_lon_180) < 1e-5
292+
# 3D data
293+
reg_2d = Regridders.InterpolationsRegridder(surface_space)
294+
295+
regridded_lat_3d = Regridders.regrid(reg_2d, data_lat3D, dimensions3D)
296+
regridded_lon_3d = Regridders.regrid(reg_2d, data_lon3D, dimensions3D)
297+
298+
# Compute max err
299+
err_lat = abs.(coordinates.lat .- regridded_lat_3d)
300+
@test maximum(err_lat) < 1e-5
301+
check_lon_error(coordinates.long, regridded_lon_3d)
302+
303+
# 2D data
304+
@test_logs (
305+
:warn,
306+
"Regridding 2D data onto a 2D space with LatLongZ coordinates.",
307+
) Regridders.regrid(reg_2d, data_lat2D, dimensions2D)
308+
@test_logs (
309+
:warn,
310+
"Regridding 2D data onto a 2D space with LatLongZ coordinates.",
311+
) Regridders.regrid(reg_2d, data_lon2D, dimensions2D)
312+
313+
regridded_lat_2d = Regridders.regrid(reg_2d, data_lat2D, dimensions2D)
314+
regridded_lon_2d = Regridders.regrid(reg_2d, data_lon2D, dimensions2D)
315+
316+
err_lat = abs.(coordinates.lat .- regridded_lat_2d)
317+
@test maximum(err_lat) < 1e-5
318+
check_lon_error(coordinates.long, regridded_lon_2d)
298319
end
299320
end
300321

0 commit comments

Comments
 (0)