|
| 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 | +``` |
0 commit comments