Grid Topology Overview#
Authors: Philip Chmielowiec, Orhan Eroglu
As discussed in our first notebook, UXarray uses the UGRID conventions as a foundation for represented Unstructured Grids. Here we’ll see how to access the underlying dimensions, coordinates, and connectivity variables that are available in UXarray.
Constructing the Grid Topology#
The grid topology is defined as a Grid
object in UXarray. A Grid
object can be created in different ways.
Constructing through uxarray.open_grid()
#
If the intent is to explore only the grid topology instead of having any data sets with it, analyzing data variables, etc., a standalone Grid
object can be instantiated as follows:
import uxarray
import uxarray as ux
# Base data path
base_path = "../../test/meshfiles/"
# Grid Path (MPAS Example)
grid_mpas_path = base_path + "/mpas/QU/mesh.QU.1920km.151026.nc"
grid_mpas = ux.open_grid(grid_mpas_path)
grid_mpas
<uxarray.Grid>
Original Grid Type: MPAS
Grid Dimensions:
* n_node: 320
* n_edge: 480
* n_face: 162
* n_max_face_nodes: 6
* n_max_face_edges: 6
* n_max_node_faces: 3
* two: 2
* n_nodes_per_face: (162,)
Grid Coordinates (Spherical):
* node_lon: (320,)
* node_lat: (320,)
* edge_lon: (480,)
* edge_lat: (480,)
* face_lon: (162,)
* face_lat: (162,)
Grid Coordinates (Cartesian):
* node_x: (320,)
* node_y: (320,)
* node_z: (320,)
* edge_x: (480,)
* edge_y: (480,)
* edge_z: (480,)
* face_x: (162,)
* face_y: (162,)
* face_z: (162,)
Grid Connectivity Variables:
* face_node_connectivity: (162, 6)
* face_edge_connectivity: (162, 6)
* edge_node_connectivity: (480, 2)
* edge_face_connectivity: (480, 2)
* node_face_connectivity: (320, 3)
Grid Descriptor Variables:
* edge_face_distances: (480,)
* edge_node_distances: (480,)
Constructing through UxDataset
#
If the intent is to have an unstructured grid-aware dataset, i.e. UxDataset
, and investigate the grid topology through it instead, the uxgrid
property can be used. To be more precise, when a UxDataset
object, or likewise UxDataArray
object, is generated (e.g. through uxarray.open_dataset()
), a Grid
object via UxDataset.uxgrid
, or UxDataArray.uxgrid
, property is also created automatically and assigned to the dataset or variable.
The grid topology can be seen through this property as follows:
# Data File Path (UGRID Example)
grid_ne30_path = base_path + "/ugrid/outCSne30/outCSne30.ug"
data_ne30_path = base_path + "/ugrid/outCSne30/outCSne30_vortex.nc"
uxds = ux.open_dataset(grid_ne30_path, data_ne30_path)
uxds.uxgrid
<uxarray.Grid>
Original Grid Type: UGRID
Grid Dimensions:
* n_node: 5402
* n_face: 5400
* n_max_face_nodes: 4
* n_nodes_per_face: (5400,)
Grid Coordinates (Spherical):
* node_lon: (5402,)
* node_lat: (5402,)
Grid Coordinates (Cartesian):
Grid Connectivity Variables:
* face_node_connectivity: (5400, 4)
Grid Descriptor Variables:
In addition, a previously-created Grid
object can always be assigned to a new UxDataset
as its uxgrid
property as follows:
uxds_mpas = ux.UxDataset(uxgrid=grid_mpas)
uxds_mpas.uxgrid
<uxarray.Grid>
Original Grid Type: MPAS
Grid Dimensions:
* n_node: 320
* n_edge: 480
* n_face: 162
* n_max_face_nodes: 6
* n_max_face_edges: 6
* n_max_node_faces: 3
* two: 2
* n_nodes_per_face: (162,)
Grid Coordinates (Spherical):
* node_lon: (320,)
* node_lat: (320,)
* edge_lon: (480,)
* edge_lat: (480,)
* face_lon: (162,)
* face_lat: (162,)
Grid Coordinates (Cartesian):
* node_x: (320,)
* node_y: (320,)
* node_z: (320,)
* edge_x: (480,)
* edge_y: (480,)
* edge_z: (480,)
* face_x: (162,)
* face_y: (162,)
* face_z: (162,)
Grid Connectivity Variables:
* face_node_connectivity: (162, 6)
* face_edge_connectivity: (162, 6)
* edge_node_connectivity: (480, 2)
* edge_face_connectivity: (480, 2)
* node_face_connectivity: (320, 3)
Grid Descriptor Variables:
* edge_face_distances: (480,)
* edge_node_distances: (480,)
Grid Attributes#
If our input grid contained additional attributes that were not representable by the UGRID conventions, they would be stored here
uxds.uxgrid.parsed_attrs
{}
uxds_mpas.uxgrid.parsed_attrs
{'on_a_sphere': 'YES',
'sphere_radius': 1.0,
'is_periodic': 'NO',
'history': 'MpasMeshConverter.x base_grids/x1.162.grid.nc base_meshes/x1.162.grid.nc',
'mesh_spec': '1.0',
'Conventions': 'MPAS',
'source': 'MpasMeshConverter.x',
'file_id': 'rku96q0z66'}
Grid Coordinates#
The coordinates by default are represented in terms of longitude and latitude.
uxds.uxgrid.node_lon
<xarray.DataArray 'node_lon' (n_node: 5402)> Size: 43kB array([-45. , 45. , 135. , ..., 141.09968961, 138.03317102, 135. ]) Dimensions without coordinates: n_node
uxds.uxgrid.node_lat
<xarray.DataArray 'node_lat' (n_node: 5402)> Size: 43kB [5402 values with dtype=float64] Dimensions without coordinates: n_node Attributes: standard_name: latitude long_name: latitude of 2D mesh nodes units: degrees_north
If you wish to use the Cartesian coordinate system, you can access the following attributes, which will internally construct a set of Cartesian coordinates derived from the previous set.
uxds.uxgrid.node_x
<xarray.DataArray 'node_x' (n_node: 5402)> Size: 43kB array([ 0.57735027, 0.57735027, -0.57735027, ..., -0.58878977, -0.57332232, -0.55611709]) Dimensions without coordinates: n_node Attributes: standard_name: x long name: Cartesian x location of the corner nodes of each face units: meters
uxds.uxgrid.node_y
<xarray.DataArray 'node_y' (n_node: 5402)> Size: 43kB array([-0.57735027, 0.57735027, 0.57735027, ..., 0.47509872, 0.51562103, 0.55611709]) Dimensions without coordinates: n_node Attributes: standard_name: y long name: Cartesian y location of the corner nodes of each face units: meters
uxds.uxgrid.node_z
<xarray.DataArray 'node_z' (n_node: 5402)> Size: 43kB array([-0.57735027, -0.57735027, -0.57735027, ..., 0.65391729, 0.63673894, 0.6176306 ]) Dimensions without coordinates: n_node Attributes: standard_name: z long name: Cartesian z location of the corner nodes of each face units: meters
Grid Connectivity#
Connectivity variables are used to describe how various geometric elements (nodes, faces, edges) can be manipulated and interconnected to represent the topology of the unstructured grid.
As described in the UGRID conventions, these connectivity variables are stored as integer arrays and may contain a Fill Value. UXarray standardizes both of these at the data loading step, meaning that the data type and fill value can always be guaranteed to be the following:
ux.INT_DTYPE
numpy.int64
ux.INT_FILL_VALUE
-9223372036854775808
Below we can see how to access these connectivity variables.
uxds.uxgrid.face_node_connectivity
<xarray.DataArray 'face_node_connectivity' (n_face: 5400, n_max_face_nodes: 4)> Size: 173kB array([[ 0, 8, 356, 124], [ 8, 9, 357, 356], [ 9, 10, 358, 357], ..., [5399, 5400, 299, 300], [5400, 5401, 298, 299], [5401, 297, 6, 298]]) Dimensions without coordinates: n_face, n_max_face_nodes Attributes: cf_role: face_node_connectivity start_index: 0 _FillValue: -9223372036854775808
uxds.uxgrid.n_nodes_per_face
<xarray.DataArray 'n_nodes_per_face' (n_face: 5400)> Size: 43kB array([4, 4, 4, ..., 4, 4, 4]) Dimensions without coordinates: n_face Attributes: cf_role: n_nodes_per_face long name: Number of nodes per face dtype: <class 'numpy.int64'>
uxds.uxgrid
<uxarray.Grid>
Original Grid Type: UGRID
Grid Dimensions:
* n_node: 5402
* n_face: 5400
* n_max_face_nodes: 4
* n_nodes_per_face: (5400,)
Grid Coordinates (Spherical):
* node_lon: (5402,)
* node_lat: (5402,)
Grid Coordinates (Cartesian):
* node_x: (5402,)
* node_y: (5402,)
* node_z: (5402,)
Grid Connectivity Variables:
* face_node_connectivity: (5400, 4)
Grid Descriptor Variables:
As we can see above, these are the only two connectivity variables listed. In addition to these, UXarray provides support for constructing additional connectivity variables.
uxds.uxgrid.edge_node_connectivity
<xarray.DataArray 'edge_node_connectivity' (n_edge: 10800, two: 2)> Size: 173kB array([[ 0, 8], [ 0, 123], [ 0, 124], ..., [5398, 5399], [5399, 5400], [5400, 5401]]) Dimensions without coordinates: n_edge, two Attributes: cf_role: edge_node_connectivity long name: Maps every edge to the two nodes that it connects. start_index: 0 dtype: <class 'numpy.int64'> inverse_indices: [ 0 25 369 ... 19 20 886] fill_value_mask: [False False False ... False False False]
uxds.uxgrid.face_edge_connectivity
<xarray.DataArray 'face_edge_connectivity' (n_face: 5400, n_max_face_edges: 4)> Size: 173kB array([[ 0, 25, 369, 2], [ 24, 28, 1056, 25], [ 27, 31, 1058, 28], ..., [10798, 889, 887, 892], [10799, 886, 884, 889], [ 883, 19, 20, 886]]) Dimensions without coordinates: n_face, n_max_face_edges Attributes: cf_role: face_edge_connectivity long name: Maps every face to its edges. start_index: 0 _FillValue: -9223372036854775808 dtype: <class 'numpy.int64'>
uxds.uxgrid
<uxarray.Grid>
Original Grid Type: UGRID
Grid Dimensions:
* n_node: 5402
* n_edge: 10800
* n_face: 5400
* n_max_face_nodes: 4
* n_max_face_edges: 4
* two: 2
* n_nodes_per_face: (5400,)
Grid Coordinates (Spherical):
* node_lon: (5402,)
* node_lat: (5402,)
Grid Coordinates (Cartesian):
* node_x: (5402,)
* node_y: (5402,)
* node_z: (5402,)
Grid Connectivity Variables:
* face_node_connectivity: (5400, 4)
* face_edge_connectivity: (5400, 4)
* edge_node_connectivity: (10800, 2)
Grid Descriptor Variables:
These additional variables are constructed upon calling their respective attributes and are now stored under the uxgrid
property. Additionally, the Mesh2_node_cart_x
, Mesh2_node_cart_y
, and Mesh2_node_cart_z
that we constructed earlier are now also shown here.
Grid Dimensions#
uxds.uxgrid.n_node
5402
uxds.uxgrid.n_edge
10800
uxds.uxgrid.n_face
5400
uxds.uxgrid.n_max_face_nodes
4
uxds.uxgrid.n_max_face_edges
4