Skip to content

Commit 4a4b3b9

Browse files
committed
Various more changes.
1 parent faf317c commit 4a4b3b9

11 files changed

+1165
-2102
lines changed

notebooks/.notebook_shadow_copies/Sec_01_Load_and_Examine.md

Lines changed: 37 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ import iris
2222

2323
# import local routines handling access to some test data
2424
from testdata_fetching import lfric_filepth
25+
# from testdata_fetching import data_path
26+
# lfric_filepth = data_path / '20210324T0000Z_lf_ugrid_plev.nc'
27+
# assert lfric_filepth.exists()
2528
```
2629

2730
<!-- #region -->
@@ -41,188 +44,89 @@ with PARSE_UGRID_ON_LOAD.context():
4144
selected_cubes = iris.load_cubes(path, cube_constraints)
4245

4346
```
44-
45-
**Exercise : first import the `PARSE_UGRID_ON_LOAD` object from iris.experimental.ugrid.load**
4647
<!-- #endregion -->
4748

49+
### Enable UGRID loading
50+
We make some imports.
51+
52+
Most importantly, we need the `PARSE_UGRID_ON_LOAD` object from `iris.experimental.ugrid.load`
53+
4854
```python
55+
import iris
4956
from iris.experimental.ugrid.load import PARSE_UGRID_ON_LOAD
5057
```
5158

52-
<!-- #region -->
53-
---
54-
55-
The variable `lfric_filepath` is already set up, pointing to a suitable test file.
59+
### Load UGRID data from netCDF files.
60+
The variable `lfric_filepath` is defined in the tutorial helper code `testdata_fetching`:
61+
It points to a suitable test file.
5662

57-
**Exercise : Load all data from `lfric_filepath`, with the UGRID loading enabled, and print the first 10 cubes.**
58-
Use the plain 'load' method, as shown above.
59-
NOTE : ***expect this to take a few seconds to complete.***
63+
In this case, we use the plain `iris.load` function, as shown above.
6064

61-
<details><summary>Sample code solution <b>click to reveal</b></summary>
65+
NOTE : ***There are a lot of cubes: Expect this to take a few seconds, and only show a few of the cubes.***
6266

6367
```python
64-
with PARSE_UGRID_ON_LOAD.context():
65-
cubes = iris.load(lfric_)
6668

67-
cubes[:10]
6869
```
69-
</details>
70-
<!-- #endregion -->
7170

72-
```python
73-
# ... space for user code ...
7471

72+
```python
73+
print('loading...')
7574
with PARSE_UGRID_ON_LOAD.context():
7675
cubes = iris.load(lfric_filepth)
7776

78-
cubes[:10]
77+
print(f'\n... Loaded {len(cubes)} cubes.')
78+
print('Showing first 4:')
79+
cubes[:4]
7980
```
8081

8182

8283
**NOTEs :**
8384
* putting just `cubes` at the end triggers notebook printing output
84-
* this also means you can click on each cube to "expand" it into a detail view -- try it
85-
* the effect of `print(cubes)` is different -- try it
85+
* this also means you can click on each cube to "expand" it into a detail view -- ***try this***
86+
* the effect of `print(cubes)` is different -- ***try this***
87+
8688

87-
<!-- #region -->
8889
## Loading a single cube
8990
You can instead load a single cube directly from the file.
90-
This is considerably _faster_ in this case, since the whole file contains ~100 data-variables (i.e. diagnostics).
91+
This is considerably _faster_ in many cases, since a typical file may contain 100s data-variables (i.e. diagnostics).
9192

92-
**Load just the cube named `relative_humidity_at_screen_level`, from the same file, and show that.**
93+
### Load just "relative_humidity_wrt_water" data
94+
(From the same file)
9395
Hint : it's nicer to use the `load_cube` function
9496

95-
<details><summary>Sample code solution <b>click to reveal</b></summary>
96-
9797
```python
9898
with PARSE_UGRID_ON_LOAD.context():
99-
lfric_rh = iris.load_cube(lfric_filepth, "relative_humidity_at_screen_level")
99+
lfric_rh = iris.load_cube(lfric_filepth, "relative_humidity_wrt_water")
100100

101101
lfric_rh
102102
```
103-
---
104-
105-
**NOTEs :**
106-
* putting just `cubes` at the end triggers notebook printing output
107-
* the effect of `print(cubes)` is different -- try it
108-
</details>
109-
<!-- #endregion -->
110103

111-
```python
112-
with PARSE_UGRID_ON_LOAD.context():
113-
lfric_rh = iris.load_cube(lfric_filepth, "relative_humidity_at_screen_level")
104+
NOTEs :
105+
* putting just the `lfric_rh` variable at the end triggers notebook printing output
106+
* the effect of `print(lfric_rh)` is different -- ***try this***
114107

115-
lfric_rh
116-
```
117108

118109
```python
119110

120111
```
121112

122-
## What you initially notice about "mesh cubes"
113+
## What is notable about "mesh cubes"
123114

124-
The cube printout has a "Mesh" section, which displays the mesh info.
115+
In the cube printout above, _compared to regular UM-style data_, you can see that it has an additional section in the cube printout called "Mesh", which displays the mesh-specific info.
125116

126-
The cube itself now has some extra properties : `cube.mesh`, `cube.location` and `cube.mesh_dim()`
127-
(these are otherwise all `None`)
117+
The cube itself also now has some extra properties : `cube.mesh`, `cube.location` and `cube.mesh_dim()`
118+
(which are otherwise all `None`)
128119

129-
```python
130-
print("cube.mesh :")
131-
print(lfric_rh.mesh)
132-
print("\n-------")
133-
print("cube.location = ", lfric_rh.location)
134-
print(lfric_rh.mesh_dim())
135-
print("\n-------")
136-
help(lfric_rh.mesh_dim)
137-
print("cube.mesh_dim() = ", lfric_rh.mesh_dim())
138-
```
120+
Cubes with a mesh are known in Iris as "unstructured cubes" or "mesh cubes.
121+
They also always have a specific "mesh dimension": In the above example it is the _last_ cube dimension.
139122

140-
```python
141-
142-
```
143-
144-
<!-- #region tags=[] -->
145-
---
146-
147-
## Exercise: identifying mesh data
148-
**How, in your code, could you check whether a cube has structured or mesh-based data ?**
149-
150-
---
151-
152-
<details><summary><b>Sample code solution :</b> "check whether cube has structured data ?" <b>click to reveal</b></summary>
153-
154-
<br>
155123

156124
```python
157-
###-------------------------------
158-
### Utility Function
159-
#
160-
def is_meshcube(cube):
161-
return cube.mesh is not None
162-
163-
#-------------------------------
164-
### Testing ...
165-
#
166-
from iris.tests.stock import realistic_3d
167-
nonmesh_cube = realistic_3d()
168-
print('Cube: ', repr(nonmesh_cube), '\n - is_meshcube ?', is_meshcube(nonmesh_cube))
169-
170-
print()
171-
from iris.tests.stock.mesh import sample_mesh_cube
172-
mesh_cube = sample_mesh_cube()
173-
print('Cube: ', repr(mesh_cube), '\n - is_meshcube ?', is_meshcube(mesh_cube))
174-
175-
```
176-
---
177-
178-
**NOTE :**
179-
* **Try this code**, by pasting it into a code cell + running ...
180-
* try it also with the 'lfric_rh' cube
181-
</details>
182-
<!-- #endregion -->
183125

184-
```python
185-
# (space for user commands)
186-
# . . .
187126
```
188127

189-
## Question : what is `cube.mesh_dim` for ?
190-
191-
192-
<details><summary><b>Sample Answer :</b> what is cube.mesh_dim for ? <b>click to reveal</b></summary>
193-
It is a function which you call, returning an integer.
194-
<br/>The result tells you which cube dimension is the mesh dimension -- that is, the cube dimension which indexes the individual elements of the mesh
195-
196-
See [Iris API docs for `Cube.mesh_dim`](https://scitools-iris.readthedocs.io/en/latest/generated/api/iris/cube.html#iris.cube.Cube.mesh_dim)
197-
198-
</details>
199-
200-
201-
## Question : what does `cube.location` mean ?
202-
203-
<details><summary>Sample answer : <b>click to reveal</b></summary>
204-
It returns a string, "node", "edge" or "face", indicating the type of mesh element which the cube data is mapped to.
205-
206-
See in [Iris "Mesh Support" docs](https://scitools-iris.readthedocs.io/en/latest/further_topics/ugrid/data_model.html?highlight=location#the-basics)
207-
208-
</details>
209-
210-
211-
## Additional questions to consider ...
212-
213-
* what does `cube.mesh_dim` do when a cube *has* no mesh ?
214-
<details><summary>Sample answer : <b>click to reveal</b></summary>
215-
It returns `None`.
216-
</details>
217-
* what happens if there is more than one mesh, or mesh dimension ?
218-
<details><summary>Sample answer : <b>click to reveal</b></summary>
219-
A bit of a "trick question" !
220-
</br>In UGRID, a data-variable can have at most <i>one</i> location and mesh. Therefore, since each Iris cube represents a CF data-variable, it can only have one mesh, and one mesh dimension -- that of its location in the mesh.
221-
</details>
222-
223-
```python
224-
225-
```
128+
## Next notebook
129+
See the next section : [02 - Mesh concepts and Meshes in Iris](./Sec_02_Meshes.ipynb)
226130

227131
```python
228132

notebooks/.notebook_shadow_copies/Sec_02_Meshes.md

Lines changed: 85 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -94,67 +94,122 @@ from testdata_fetching import lfric_rh_singletime_2d
9494
lfric_rh = lfric_rh_singletime_2d()
9595
```
9696

97-
**Print the cube, and its `cube.mesh`**
97+
**Print the cube**
98+
99+
```python tags=[]
100+
lfric_rh
101+
```
102+
103+
### What is special about "mesh cubes" ?
104+
105+
Compare the above to some UM data (e.g. `testdata_fetching.um_temp()`).
106+
107+
You should find that an 'unstructured' cube has some extra properties : `cube.mesh`, `cube.location` and `cube.mesh_dim()`
108+
98109

99110
```python
100-
print(lfric_rh)
101-
print('\n----\n')
111+
print("cube.mesh :")
102112
print(lfric_rh.mesh)
113+
print("\n-------")
114+
print("cube.location = ", lfric_rh.location)
115+
print(lfric_rh.mesh_dim())
116+
print("\n-------")
117+
help(lfric_rh.mesh_dim)
118+
print("cube.mesh_dim() = ", lfric_rh.mesh_dim())
103119
```
104120

105-
### Details of the Iris mesh content
121+
---
122+
**Additional Note:**
123+
As previously mentioned, every Iris mesh cube has a "mesh dimension".
124+
This is often the last cube dimension, and is typically "anonymous" -- i.e. it has no dimension coordinate.
106125

107-
How Iris represents the mesh is not usually very relevant to working with cube data in Iris, nor to plotting it with PyVista.
126+
127+
## Details of the Iris mesh content
128+
129+
Exactly ***how*** Iris represents a mesh is not usually very relevant to working with cube data in Iris, nor to plotting it with PyVista.
108130
So that is beyond the scope of an introductory tutorial.
109131

110132
However, for those interested, there is a bonus notebook showing some of this : ["Mesh_Connectivities_demo.ipynb"](./Mesh_Connectivities_demo.ipynb)
111133

112134

135+
<!-- #region tags=[] -->
136+
---
137+
138+
## Exercises : mesh data
113139

114-
### Plotting mesh data : minimal 3D visualisation of a 2D cube
140+
### Ex.1 : How to check whether a cube has structured or mesh-based data
141+
<!-- #endregion -->
115142

143+
```python tags=[]
144+
# ... space for user solution ...
145+
```
116146

117-
This is just a quick preview of the next section (Sec_03_Plotting), to show a basic 3D plot.
147+
```python tags=[]
148+
#
149+
# SAMPLE CODE SOLUTION
150+
#
118151

119152

120-
<!-- #region jp-MarkdownHeadingCollapsed=true tags=[] -->
121-
**Convert a cube to PyVista form for plotting**
153+
# Utility Function
154+
#
155+
def is_meshcube(cube):
156+
return cube.mesh is not None
122157

123-
There are as yet *no* facilities in Iris for plotting unstructed cubes.
124-
We can do that using PyVista, but we need first to convert the data to a PyVista format.
158+
#-------------------------------
159+
### Testing ...
160+
#
161+
from iris.tests.stock import realistic_3d
162+
nonmesh_cube = realistic_3d()
163+
print('Cube: ', repr(nonmesh_cube), '\n - is_meshcube ?', is_meshcube(nonmesh_cube))
125164

126-
So first,
127-
**Import the routine** `pv_conversions.pv_from_lfric_cube` **(provided here in the tutorial).
128-
And call that..**
165+
print()
166+
from iris.tests.stock.mesh import sample_mesh_cube
167+
mesh_cube = sample_mesh_cube()
168+
print('Cube: ', repr(mesh_cube), '\n - is_meshcube ?', is_meshcube(mesh_cube))
169+
```
129170

171+
<!-- #region tags=[] -->
172+
---
173+
***try this also*** with the 'lfric_rh' cube
130174
<!-- #endregion -->
131175

132176
```python
133-
from pv_conversions import pv_from_lfric_cube
134177

135-
pv = pv_from_lfric_cube(rh_t0)
136178
```
137179

138-
This produces a PyVista ["PolyData" object](https://docs.pyvista.org/api/core/_autosummary/pyvista.PolyData.html#pyvista-polydata).
139-
Which is a thing we can plot, by simply calling its `.plot()` method.
180+
### Question : what is `cube.mesh_dim` for ?
140181

141182

142-
---
183+
<details><summary>Sample Answer : <b>click to reveal</b></summary>
184+
It is a function which you call, returning an integer.
185+
<br/>The result tells you which cube dimension is the mesh dimension -- that is, the cube dimension which indexes the individual elements of the mesh
143186

144-
**Call the `plot` routine of the PolyData object. An output should appear.**
187+
See [Iris API docs for `Cube.mesh_dim`](https://scitools-iris.readthedocs.io/en/latest/generated/api/iris/cube.html#iris.cube.Cube.mesh_dim)
188+
189+
</details>
190+
191+
192+
### Question : what does `cube.location` mean ?
193+
194+
<details><summary>Sample answer : <b>click to reveal</b></summary>
195+
It returns a string, "node", "edge" or "face", indicating the type of mesh element which the cube data is mapped to.
196+
197+
See in [Iris "Mesh Support" docs](https://scitools-iris.readthedocs.io/en/latest/further_topics/ugrid/data_model.html?highlight=location#the-basics)
198+
199+
</details>
145200

146-
```python
147-
pv.plot()
148-
```
149201

150-
**NOTES**:
151-
* this plot is interactive -- try dragging to rotate, and the mouse scroll-wheel to zoom
152-
* this obviously causes some clutter and uses up some space (e.g. you can't easily scroll past it)
153-
* To ***remove*** a plot output, use "Clear Output" from the "Edit" menu (or from right-click on the cell)
154-
* alternatively, set the keyword `jupyter_backend='static'` in the command, for output as a plain image
202+
### Additional questions to consider ...
155203

156-
There are a lot more keywords available to [the `PolyData.plot()` method](https://docs.pyvista.org/api/core/_autosummary/pyvista.PolyData.plot.html), but it is not ideal to overcomplicate these calls.
157-
Finer control is better achieved in a different ways : See more detail on plotting in [the Plotting section](./Sec_03_Plotting.ipynb).
204+
* what does `cube.mesh_dim` do when a cube *has* no mesh ?
205+
<details><summary>Sample answer : <b>click to reveal</b></summary>
206+
It returns `None`.
207+
</details>
208+
* what happens if there is more than one mesh, or mesh dimension ?
209+
<details><summary>Sample answer : <b>click to reveal</b></summary>
210+
A bit of a "trick question" !
211+
</br>In UGRID, a data-variable can have at most <i>one</i> location and mesh. Therefore, since each Iris cube represents a CF data-variable, it can only have one mesh, and one mesh dimension -- that of its location in the mesh.
212+
</details>
158213

159214

160215
## Next notebook

0 commit comments

Comments
 (0)