Skip to content

Commit e54ebd3

Browse files
authored
Merge pull request #13 from pp-mo/mesh_ideas
Added draft exploration of Iris mesh concepts.
2 parents 271bd08 + f98cfea commit e54ebd3

File tree

4 files changed

+601
-2
lines changed

4 files changed

+601
-2
lines changed
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
---
2+
jupyter:
3+
jupytext:
4+
text_representation:
5+
extension: .md
6+
format_name: markdown
7+
format_version: '1.3'
8+
jupytext_version: 1.14.4
9+
kernelspec:
10+
display_name: Python 3 (ipykernel)
11+
language: python
12+
name: python3
13+
---
14+
15+
# Bonus material : Demonstrating Iris mesh concepts
16+
17+
This notebook provides a brief glimpse into the content of a `cube.mesh`.
18+
19+
This is not usually relevant to ordinary data processing in Iris, or to plotting in PyVista.
20+
21+
Goals :
22+
* introduce mesh coordinates + connectivities
23+
* show real LFRic mesh structure on plots
24+
25+
```python
26+
import numpy as np
27+
from pv_conversions import pv_from_lfric_cube
28+
```
29+
30+
```python
31+
## TODO : remove later -- this bit is temporary, for initial testing with C48 data
32+
from testdata_fetching import switch_data
33+
switch_data(use_newer_smaller_c48_data=True)
34+
```
35+
36+
```python
37+
from testdata_fetching import lfric_rh_singletime_2d
38+
cube = lfric_rh_singletime_2d()
39+
print(cube)
40+
```
41+
42+
```python
43+
# Snapshot the original data range -- this is useful below
44+
data_min, data_max = cube.data.min(), cube.data.max()
45+
data_range = data_max - data_min
46+
```
47+
48+
```python
49+
# Calculate the coordinates of a cubesphere corner
50+
x_corner = 45.0
51+
y_corner = np.rad2deg(np.arctan(1.0 / np.sqrt(2)))
52+
y_corner, x_corner
53+
```
54+
55+
## Get coordinates of node locations, from the mesh.
56+
57+
```python
58+
x_nodes_coord = cube.mesh.coord(axis='x', include_nodes=True)
59+
y_nodes_coord = cube.mesh.coord(axis='y', include_nodes=True)
60+
x_nodes_coord
61+
```
62+
63+
---
64+
## Find the number of the node nearest one corner of the cubesphere
65+
66+
```python
67+
xx = x_nodes_coord.points
68+
yy = y_nodes_coord.points
69+
xy_dists = (xx - x_corner) ** 2 + (yy - y_corner) ** 2
70+
closest = np.min(xy_dists)
71+
i_node_nearest_corner = np.argmin(xy_dists)
72+
73+
# show the results
74+
print(
75+
'corner index :',
76+
i_node_nearest_corner
77+
)
78+
print('Some corner-distances around the corner node.. : ')
79+
print(' ', xy_dists[i_node_nearest_corner - 2:i_node_nearest_corner + 3]
80+
)
81+
```
82+
83+
---
84+
## Find the faces which touch that (corner) node
85+
86+
```python
87+
# (spoiler alert : if we specced the corner right, there are probably 3 of them)
88+
face_nodes = cube.mesh.face_node_connectivity.indices
89+
assert face_nodes.ndim == 2 and face_nodes.shape[1] == 4
90+
```
91+
92+
```python
93+
face_on_corner = np.any(face_nodes == i_node_nearest_corner, axis=1)
94+
corner_faces = np.where(face_on_corner)[0]
95+
print('corner face indices :', corner_faces)
96+
```
97+
98+
---
99+
## Modify the cube data, to "mark" those faces visibly, and display
100+
101+
```python
102+
marks = data_max + data_range * np.array([1.2, 1.3, 1.4])
103+
cube.data[corner_faces] = marks
104+
105+
# Plot the cube
106+
pv = pv_from_lfric_cube(cube)
107+
pv.plot(show_edges=True, jupyter_backend='static')
108+
```
109+
110+
---
111+
112+
## "Expand" these selected faces outwards
113+
.. to include all the faces adjacent to these ones ...
114+
115+
Using the `face_node_connectivity` array again.
116+
117+
```python
118+
# **First** find all points which are corners of those faces
119+
extended_points = cube.mesh.face_node_connectivity[corner_faces].indices
120+
extended_points
121+
```
122+
123+
```python
124+
# Tidy to get sorted + unique point indices
125+
extended_points = sorted(set(extended_points.flatten()))
126+
print(extended_points)
127+
```
128+
129+
```python
130+
# ... **Then** find all faces which use those points (as before)
131+
extended_faces = []
132+
for i_point in extended_points:
133+
face_touches_point = np.any(face_nodes == i_point, axis=1)
134+
extended_faces.extend(np.where(face_touches_point)[0])
135+
136+
# tidy for sorted + unique, again
137+
extended_faces = sorted(set(extended_faces))
138+
print(extended_faces)
139+
```
140+
141+
---
142+
### Mark all those faces too in the data
143+
Distinguishing "outer" and "inner".
144+
145+
And re-plot ...
146+
147+
```python
148+
cube.data[extended_faces] = data_max + data_range * 1.1
149+
cube.data[corner_faces] = data_max + data_range * np.array([1.4, 1.6, 1.8])
150+
pv = pv_from_lfric_cube(cube)
151+
pv.plot(show_edges=True, jupyter_backend='static')
152+
```
153+
154+
```python
155+
156+
```
157+
158+
```python
159+
160+
```

notebooks/.notebook_shadow_copies/Sec_02_Meshes.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,13 @@ pv.plot() #jupyter_backend='static')
108108

109109
```
110110

111-
### Todo : examine mesh content + demonstrate APIs
111+
### Investigate the Iris mesh content
112+
113+
Details of how the Iris mesh is constructed are not usually relevant to working with the cube data in Iris, nor to plotting it with PyVista.
114+
So that is beyond the scope of an introductory tutorial.
115+
116+
However, for those interested, bonus material is provided showing some of this [in this additional notebook](./Mesh_Connectivities_demo.ipynb)
117+
112118

113119

114120
## Plotting mesh data : minimal 3D visualisation of a 2D cube

0 commit comments

Comments
 (0)