@@ -80,21 +80,209 @@ Regrid the given data as defined on the given dimensions to the `target_space` i
80
80
This function is allocating.
81
81
"""
82
82
function Regridders. regrid (regridder:: InterpolationsRegridder , data, dimensions)
83
+ # TODO : There is room for improvement in this function...
84
+
83
85
FT = ClimaCore. Spaces. undertype (regridder. target_space)
84
86
dimensions_FT = map (d -> FT .(d), dimensions)
85
87
86
- # Make a linear spline
87
- itp = Intp. extrapolate (
88
- Intp. interpolate (dimensions_FT, FT .(data), Intp. Gridded (Intp. Linear ())),
89
- regridder. extrapolation_bc,
88
+ coordinates = ClimaCore. Fields. coordinate_field (regridder. target_space)
89
+ device = ClimaComms. device (regridder. target_space)
90
+
91
+ has_3d_z = length (size (last (dimensions))) == 3
92
+ if eltype (coordinates) <: ClimaCore.Geometry.LatLongZPoint && has_3d_z
93
+ # If we have 3D altitudes, we do linear in the vertical and bilinear
94
+ # horizontal separately
95
+ @warn " Ignoring boundary conditions, implementing Periodic, Flat, Flat"
96
+
97
+ adapted_data = Adapt. adapt (ClimaComms. array_type (regridder. target_space), data)
98
+ xs, ys, zs = dimensions_FT
99
+ adapted_xs = Adapt. adapt (ClimaComms. array_type (regridder. target_space), xs)
100
+ adapted_ys = Adapt. adapt (ClimaComms. array_type (regridder. target_space), ys)
101
+ adapted_zs = Adapt. adapt (ClimaComms. array_type (regridder. target_space), zs)
102
+
103
+ return ClimaComms. allowscalar (ClimaComms. device (regridder. target_space)) do
104
+ map (regridder. coordinates) do coord
105
+ interpolation_3d_z (
106
+ adapted_data,
107
+ adapted_xs, adapted_ys, adapted_zs,
108
+ totuple (coord)... ,
109
+ )
110
+ end
111
+ end
112
+ else
113
+ # Make a linear spline
114
+ itp = Intp. extrapolate (
115
+ Intp. interpolate (
116
+ dimensions_FT,
117
+ FT .(data),
118
+ Intp. Gridded (Intp. Linear ()),
119
+ ),
120
+ regridder. extrapolation_bc,
121
+ )
122
+
123
+ # Move it to GPU (if needed)
124
+ gpuitp = Adapt. adapt (ClimaComms. array_type (regridder. target_space), itp)
125
+
126
+ return map (regridder. coordinates) do coord
127
+ gpuitp (totuple (coord)... )
128
+ end
129
+ end
130
+ end
131
+
132
+ """
133
+ interpolation_3d_z(data, xs, ys, zs, target_x, target_y, target_z)
134
+
135
+ Perform bilinear + vertical interpolation on a 3D dataset.
136
+
137
+ This function first performs linear interpolation along the z-axis at the four
138
+ corners of the cell containing the target (x, y) point. Then, it performs
139
+ bilinear interpolation in the x-y plane using the z-interpolated values.
140
+
141
+ Periodic is implemented on the x direction, Flat on the other ones.
142
+
143
+ # Arguments
144
+ - `data`: A 3D array of data values.
145
+ - `xs`: A vector of x-coordinates corresponding to the first dimension of `data`.
146
+ - `ys`: A vector of y-coordinates corresponding to the second dimension of `data`.
147
+ - `zs`: A 3D array of z-coordinates. `zs[i, j, :]` provides the z-coordinates for the data point `data[i, j, :]`.
148
+ - `target_x`: The x-coordinate of the target point.
149
+ - `target_y`: The y-coordinate of the target point.
150
+ - `target_z`: The z-coordinate of the target point.
151
+ """
152
+ function interpolation_3d_z (data, xs, ys, zs, target_x, target_y, target_z)
153
+ # Check boundaries
154
+ # if target_x < xs[begin] || target_x > xs[end]
155
+ # error(
156
+ # "target_x is out of bounds: $(target_x) not in [$(xs[1]), $(xs[end])]",
157
+ # )
158
+ # end
159
+ # if target_y < ys[begin] || target_y > ys[end]
160
+ # error(
161
+ # "target_y is out of bounds: $(target_y) not in [$(ys[1]), $(ys[end])]",
162
+ # )
163
+ # end
164
+
165
+ # Find nearest neighbors
166
+ x_period = xs[end ] - xs[begin ]
167
+ target_x = mod (target_x, x_period)
168
+
169
+ x_index = searchsortedfirst (xs, target_x)
170
+ y_index = searchsortedfirst (ys, target_y)
171
+
172
+ x0_index = x_index == 1 ? x_index : x_index - 1
173
+ x1_index = x0_index + 1
174
+
175
+ y0_index = y_index == 1 ? y_index : y_index - 1
176
+ # Flat
177
+ y0_index = clamp (y0_index, 1 , length (ys) - 1 )
178
+ y1_index = y0_index + 1
179
+ if y0_index == 1
180
+ target_y = ys[y0_index]
181
+ end
182
+ if y1_index == length (ys)
183
+ target_y = ys[y1_index]
184
+ end
185
+
186
+
187
+ # Interpolate in z-direction
188
+
189
+ z00 = @view zs[x0_index, y0_index, :]
190
+ z01 = @view zs[x0_index, y1_index, :]
191
+ z10 = @view zs[x1_index, y0_index, :]
192
+ z11 = @view zs[x1_index, y1_index, :]
193
+
194
+ f00 = linear_interp_z (view (data,x0_index, y0_index, :), z00, target_z)
195
+ f01 = linear_interp_z (view (data,x0_index, y1_index, :), z01, target_z)
196
+ f10 = linear_interp_z (view (data,x1_index, y0_index, :), z10, target_z)
197
+ f11 = linear_interp_z (view (data,x1_index, y1_index, :), z11, target_z)
198
+
199
+ # Bilinear interpolation in x-y plane
200
+ val = bilinear_interp (
201
+ f00,
202
+ f01,
203
+ f10,
204
+ f11,
205
+ xs[x0_index],
206
+ xs[x1_index],
207
+ ys[y0_index],
208
+ ys[y1_index],
209
+ target_x,
210
+ target_y,
90
211
)
91
212
92
- # Move it to GPU (if needed)
93
- gpuitp = Adapt. adapt (ClimaComms. array_type (regridder. target_space), itp)
213
+ return val
214
+ end
215
+
216
+ """
217
+ linear_interp_z(f, z, target_z)
218
+
219
+ Perform linear interpolation along the z-axis.
220
+
221
+ # Arguments
222
+ - `f`: A vector of function values corresponding to the z-coordinates in `z`.
223
+ - `z`: A vector of z-coordinates.
224
+ - `target_z`: The z-coordinate at which to interpolate.
225
+
226
+ # Returns
227
+ The linearly interpolated value at `target_z`.
228
+ """
229
+ function linear_interp_z (f, z, target_z)
230
+ # if target_z < z[begin] || target_z > z[end]
231
+ # error(
232
+ # "target_z is out of bounds: $(target_z) not in [$(z[1]), $(z[end])]",
233
+ # )
234
+ # end
235
+
236
+ index = searchsortedfirst (z, target_z)
237
+ # Handle edge cases for index
238
+ # Flat
239
+ if index == 1
240
+ z0 = z[index]
241
+ z1 = z[index + 1 ]
242
+ f0 = f[index]
243
+ f1 = f[index + 1 ]
244
+ else
245
+ z0 = z[index - 1 ]
246
+ z1 = z[index]
247
+ f0 = f[index - 1 ]
248
+ f1 = f[index]
249
+ end
94
250
95
- return map (regridder . coordinates) do coord
96
- gpuitp ( totuple (coord) ... )
251
+ if index == 1
252
+ target_z = z[index]
97
253
end
254
+ if index == length (z) - 1
255
+ target_z = z[index + 1 ]
256
+ end
257
+ val = f0 + (target_z - z0) / (z1 - z0) * (f1 - f0)
258
+ return val
259
+ end
260
+
261
+ """
262
+ bilinear_interp(f00, f01, f10, f11, x0, x1, y0, y1, target_x, target_y)
263
+
264
+ Perform bilinear interpolation on a 2D plane.
265
+
266
+ # Arguments
267
+ - `f00`: Function value at (x0, y0).
268
+ - `f01`: Function value at (x0, y1).
269
+ - `f10`: Function value at (x1, y0).
270
+ - `f11`: Function value at (x1, y1).
271
+ - `x0`: x-coordinate of the first corner.
272
+ - `x1`: x-coordinate of the second corner.
273
+ - `y0`: y-coordinate of the first corner.
274
+ - `y1`: y-coordinate of the second corner.
275
+ - `target_x`: The x-coordinate of the target point.
276
+ - `target_y`: The y-coordinate of the target point.
277
+ """
278
+ function bilinear_interp (f00, f01, f10, f11, x0, x1, y0, y1, target_x, target_y)
279
+ val = (
280
+ (x1 - target_x) * (y1 - target_y) / ((x1 - x0) * (y1 - y0)) * f00 +
281
+ (x1 - target_x) * (target_y - y0) / ((x1 - x0) * (y1 - y0)) * f01 +
282
+ (target_x - x0) * (y1 - target_y) / ((x1 - x0) * (y1 - y0)) * f10 +
283
+ (target_x - x0) * (target_y - y0) / ((x1 - x0) * (y1 - y0)) * f11
284
+ )
285
+ return val
98
286
end
99
287
100
288
end
0 commit comments