Skip to content

Commit 89b7887

Browse files
add revealable code
1 parent 2bb431d commit 89b7887

File tree

2 files changed

+359
-15
lines changed

2 files changed

+359
-15
lines changed

notebooks/.notebook_shadow_copies/Sec_05_Regridding.md

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,30 +136,75 @@ orography_on_mesh
136136
# Use %%timeit to investigate how much time it takes to initialise a regridder vs applying the regridder.
137137
```
138138

139+
<!-- #region -->
139140
## Exercise 1: Comparing regridding methods
140141

141142
By default, regridding uses the area weighted `conservative` method. We can also use the bilinear regridding method.
142143

143144
**Step 1:** Use the `method="bilinear"` keyword to initialise a bilinear `MeshToGridESMFRegridder` with arguments `mesh_cube` and `grid_cube`.
144145

146+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
147+
148+
```python
149+
bilinear_regridder = MeshToGridESMFRegridder(mesh_cube, grid_cube, method="bilinear")
150+
```
151+
</details>
152+
<!-- #endregion -->
153+
145154
```python
146155
bilinear_regridder = MeshToGridESMFRegridder(mesh_cube, grid_cube, method="bilinear")
147156
```
148157

158+
<!-- #region -->
149159
**Step 2:** Use this regridder to regrid `mesh_cube`.
150160

161+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
162+
163+
```python
164+
bilinear_regridded_orography = bilinear_regridder(mesh_cube)
165+
```
166+
</details>
167+
<!-- #endregion -->
168+
151169
```python
152170
bilinear_regridded_orography = bilinear_regridder(mesh_cube)
153171
```
154172

173+
<!-- #region -->
155174
**Step 3:** Compare this result with the result from the default area weighted conservative regridder.
156175

176+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
177+
178+
```python
179+
bilinear_diff = bilinear_regridded_orography - regridded_orography
180+
```
181+
</details>
182+
<!-- #endregion -->
183+
157184
```python
158185
bilinear_diff = bilinear_regridded_orography - regridded_orography
159186
```
160187

188+
<!-- #region -->
161189
**Step 4:** Plot the results and the difference using `iris.quickplot` and `matplotlib`.
162190

191+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
192+
193+
```python
194+
import iris.quickplot as iqplt
195+
import matplotlib.pyplot as plt
196+
197+
iqplt.pcolormesh(regridded_orography, cmap="terrain")
198+
plt.show()
199+
iqplt.pcolormesh(bilinear_regridded_orography, cmap="terrain")
200+
plt.show()
201+
bilinear_diff.long_name = "Difference in altitude"
202+
iqplt.pcolormesh(bilinear_diff, vmin=-400,vmax=400, cmap="seismic")
203+
plt.show()
204+
```
205+
</details>
206+
<!-- #endregion -->
207+
163208
```python
164209
import iris.quickplot as iqplt
165210
import matplotlib.pyplot as plt
@@ -181,6 +226,7 @@ plt.show()
181226
# - demonstrate that the data in the grid file was probably a result of regridding from the mesh file.
182227
```
183228

229+
<!-- #region -->
184230
## Exercise 2: Zonal means
185231

186232
For a latlon cube, a common operation is to collapse over longitude by taking an average. This is not possible for an LFRic style mesh cube since there is no independent longitude dimension to collapse. While it is possible to regrid to a latlon cube and then collapse, this introduces an additional step to the process. Instead, it is possible to simplify this into a single step by considering this as a regridding operation where the target cube contains multiple latitude bands.
@@ -190,6 +236,19 @@ Calculating zonal means can be done as a regridding operation where the zone is
190236

191237
**Step 1:** Define a latitude coordinate whose bounds are `[[-90, -60], [-60, -30], [-30, 0], [0, 30], [30, 60], [60, 90]]`. Remember to set the standard name to be `"latitude"` and the units to be `"degrees"`
192238

239+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
240+
241+
```python
242+
lat_bands = DimCoord(
243+
[-75, -45, -15, 15, 45, 75],
244+
bounds=[[-90, -60], [-60, -30], [-30, 0], [0, 30], [30, 60], [60, 90]],
245+
standard_name="latitude",
246+
units="degrees"
247+
)
248+
```
249+
</details>
250+
<!-- #endregion -->
251+
193252
```python
194253
lat_bands = DimCoord(
195254
[-75, -45, -15, 15, 45, 75],
@@ -199,21 +258,43 @@ lat_bands = DimCoord(
199258
)
200259
```
201260

261+
<!-- #region -->
202262
**Step 2:** Define a longitude coordinate whose bounds are `[[-180, 180]]`. Remember to set the standard name to be `"longitude"` and the units to be `"degrees"`
203263

264+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
265+
204266
```python
205267
lon_full = DimCoord(0, bounds=[[-180, 180]], standard_name="longitude", units="degrees")
206268
```
269+
</details>
270+
<!-- #endregion -->
207271

272+
```python
273+
lon_full = DimCoord(0, bounds=[[-180, 180]], standard_name="longitude", units="degrees")
274+
```
275+
276+
<!-- #region -->
208277
**Step 3:** Create a six celled cube (i.e. `Cube([[0, 0, 0, 0, 0, 0]])`) and attach the latitude and longitude coordinates to it.
209278

279+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
280+
281+
```python
282+
lat_band_cube = Cube([[0, 0, 0, 0, 0, 0]])
283+
lat_band_cube.add_dim_coord(lat_bands, 1)
284+
lat_band_cube.add_dim_coord(lon_full, 0)
285+
lat_band_cube
286+
```
287+
</details>
288+
<!-- #endregion -->
289+
210290
```python
211291
lat_band_cube = Cube([[0, 0, 0, 0, 0, 0]])
212292
lat_band_cube.add_dim_coord(lat_bands, 1)
213293
lat_band_cube.add_dim_coord(lon_full, 0)
214294
lat_band_cube
215295
```
216296

297+
<!-- #region -->
217298
**Step 4:** Create a regridder from `mesh_cube` to the single celled cube you created.
218299

219300
*Note:* ESMF represents all lines as sections of great circles rather than lines of constant latitude. This means that `MeshToGridESMFRegridder` would fail to properly handle such a large cell. We can solve this problem by using the `resolution` keyword. By providing a `resolution`, we divide each cell into as many sub-cells each bounded by the same latitude bounds.
@@ -222,24 +303,60 @@ If we initialise a regridder with `MeshToGridESMFRegridder(src_mesh, tgt_grid, r
222303

223304
Initialise a `MeshToGridESMFRegridder` with `mesh_cube` and your single celled cube as its arguments and with a `resolution=10` keyword.
224305

306+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
307+
308+
```python
309+
lat_band_mean_calculator_10 = MeshToGridESMFRegridder(mesh_cube, lat_band_cube, resolution=10)
310+
```
311+
</details>
312+
<!-- #endregion -->
313+
225314
```python
226315
lat_band_mean_calculator_10 = MeshToGridESMFRegridder(mesh_cube, lat_band_cube, resolution=10)
227316
```
228317

318+
<!-- #region -->
229319
**Step 5:** Apply this regridder to `mesh_cube` and print the data from this result (i.e. `print(result_cube.data)`) and plot with `iqplt.pcolormesh`.
230320

321+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
322+
231323
```python
232324
lat_band_mean_10 = lat_band_mean_calculator_10(mesh_cube)
233325
print(lat_band_mean_10.data)
234326
iqplt.pcolormesh(lat_band_mean_10)
235327
plt.gca().coastlines()
236328
plt.show()
237329
```
330+
</details>
331+
<!-- #endregion -->
238332

333+
```python
334+
lat_band_mean_10 = lat_band_mean_calculator_10(mesh_cube)
335+
print(lat_band_mean_10.data)
336+
iqplt.pcolormesh(lat_band_mean_10)
337+
plt.gca().coastlines()
338+
plt.show()
339+
```
340+
341+
<!-- #region -->
239342
**Step 6:** Repeat step 4 and 5 for `resolution=100`.
240343

241344
Note the difference in value. Also note that it takes more time to initialise a regridder with higher resolution. Higher resolutions ought to be more accurate but there is a tradeoff between performance and accuracy.
242345

346+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
347+
348+
```python
349+
lat_band_mean_calculator_100 = MeshToGridESMFRegridder(mesh_cube, lat_band_cube, resolution=100)
350+
lat_band_mean_100 = lat_band_mean_calculator_100(mesh_cube)
351+
print(lat_band_mean_100.data)
352+
353+
iqplt.pcolormesh(lat_band_mean_100)
354+
plt.gca().coastlines()
355+
plt.show()
356+
```
357+
</details>
358+
<!-- #endregion -->
359+
243360
```python
244361
lat_band_mean_calculator_100 = MeshToGridESMFRegridder(mesh_cube, lat_band_cube, resolution=100)
245362
lat_band_mean_100 = lat_band_mean_calculator_100(mesh_cube)
@@ -250,10 +367,32 @@ plt.gca().coastlines()
250367
plt.show()
251368
```
252369

370+
<!-- #region -->
253371
**Step 7:** Repeat steps 1 - 6 for latitude bounds `[[-90, 90]]`, longitude bounds `[[-40, 40]]` and resolutions 2 and 10.
254372

255373
*Note:* Unlike lines of constant latitude, lines of constant longitude are already great circle arcs.This might suggest that the `resolution` argument is unnnecessary, however these arcs are 180 degrees which ESMF is unable to represent so we still need a `resolution` of at least 2. In this case, an increase in resolution will not affect the accuracy since a resolution of 2 will already have maximum accuracy. Note how the results are the equal.
256374

375+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
376+
377+
```python
378+
lat_full = DimCoord(0, bounds=[[-90, 90]], standard_name="latitude", units="degrees")
379+
lon_band = DimCoord(0, bounds=[[-40, 40]], standard_name="longitude", units="degrees")
380+
381+
lon_band_cube = Cube([[0]])
382+
lon_band_cube.add_dim_coord(lat_full, 0)
383+
lon_band_cube.add_dim_coord(lon_band, 1)
384+
385+
lon_band_mean_calculator_2 = MeshToGridESMFRegridder(mesh_cube, lon_band_cube, resolution=2)
386+
lon_band_mean_2 = lon_band_mean_calculator_2(mesh_cube)
387+
print(lon_band_mean_2.data)
388+
389+
lon_band_mean_calculator_10 = MeshToGridESMFRegridder(mesh_cube, lon_band_cube, resolution=10)
390+
lon_band_mean_10 = lon_band_mean_calculator_10(mesh_cube)
391+
print(lon_band_mean_10.data)
392+
```
393+
</details>
394+
<!-- #endregion -->
395+
257396
```python
258397
lat_full = DimCoord(0, bounds=[[-90, 90]], standard_name="latitude", units="degrees")
259398
lon_band = DimCoord(0, bounds=[[-40, 40]], standard_name="longitude", units="degrees")
@@ -271,21 +410,45 @@ lon_band_mean_10 = lon_band_mean_calculator_10(mesh_cube)
271410
print(lon_band_mean_10.data)
272411
```
273412

413+
<!-- #region -->
274414
## Exercise 3: Hovmoller plots
275415

276416
If we have data on aditional dimensions, we can use the same approach as exercise 2 to produce a Hovmoller diagram. That is, if we have data that varies along time we can take the area weighted mean over latitude bands and plot the data aginst latitude and time (or similarly, we can plot against longitude and time).
277417

278418
**Step 1:** Load a cube with humidity data using the `testdata_fetching` function `lfric_rh_alltimes_3d`.
279419

420+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
421+
280422
```python
281423
from testdata_fetching import lfric_rh_alltimes_3d
282424

283425
humidity_cube = lfric_rh_alltimes_3d()
284426
humidity_cube
285427
```
428+
</details>
429+
<!-- #endregion -->
286430

431+
```python
432+
from testdata_fetching import lfric_rh_alltimes_3d
433+
434+
humidity_cube = lfric_rh_alltimes_3d()
435+
humidity_cube
436+
```
437+
438+
<!-- #region -->
287439
**Step 2:** Create a target cube whose latitude coordinate is derived from the UM cube loaded from `um_orography` and whose longitude coordinate has bounds `[[-180, 180]]`. This can be done by slicing a cube derived from `um_orography` (using the slice `[:, :1]` so that this dimension isnt collapsed), removing the longitude coordinate and adding a longitude coordinate with bounds `[[-180, 180]]` (you can reuse the coordinate from exercise 2).
288440

441+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
442+
443+
```python
444+
target_cube_lats = grid_cube[:,:1]
445+
target_cube_lats.remove_coord("longitude")
446+
target_cube_lats.add_dim_coord(lon_full, 1)
447+
target_cube_lats
448+
```
449+
</details>
450+
<!-- #endregion -->
451+
289452
```python
290453
target_cube_lats = grid_cube[:,:1]
291454
target_cube_lats.remove_coord("longitude")
@@ -302,8 +465,19 @@ target_cube_lats
302465
# target_cube_lons
303466
```
304467

468+
<!-- #region -->
305469
**Step 3:** Create a `MeshToGridESMFRegridder` regridder from the slice of the humidity cube onto the target cube. Set the resolution keyword to 500 (this should be good balance of accuracy and performance). Use this regridder to create a resulting cube.
306470

471+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
472+
473+
```python
474+
um_lat_band_mean_calculator = MeshToGridESMFRegridder(humidity_cube, target_cube_lats, resolution=500)
475+
um_lat_band_means = um_lat_band_mean_calculator(humidity_cube)
476+
um_lat_band_means
477+
```
478+
</details>
479+
<!-- #endregion -->
480+
307481
```python
308482
um_lat_band_mean_calculator = MeshToGridESMFRegridder(humidity_cube, target_cube_lats, resolution=500)
309483
um_lat_band_means = um_lat_band_mean_calculator(humidity_cube)
@@ -320,8 +494,21 @@ um_lat_band_means
320494
# um_lon_band_means
321495
```
322496

497+
<!-- #region -->
323498
**Step 4:** Plot the data in the resulting cube. This can be done with `iqplt.pcolormesh`. Note that the resulting cube will have an unnecessary dimension which will have to be sliced (using `[:, :, 0]`). Note that extra steps can be taken to format the dates for this plot.
324499

500+
<details><summary>Sample code solution : <b>click to reveal</b></summary>
501+
502+
```python
503+
import matplotlib.dates as mdates
504+
# We use a colormap which highlights fine details.
505+
iqplt.pcolormesh(um_lat_band_means[:, :, 0])
506+
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%D"))
507+
plt.show()
508+
```
509+
</details>
510+
<!-- #endregion -->
511+
325512
```python
326513
import matplotlib.dates as mdates
327514
# We use a colormap which highlights fine details.

0 commit comments

Comments
 (0)