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:
  * nMesh2_node: 320
  * nMesh2_face: 162
  * nMaxMesh2_face_nodes: 6
  * nMesh2_edge: 480
Grid Coordinate Variables:
  * Mesh2_node_x: (320,)
  * Mesh2_node_y: (320,)
  * Mesh2_face_x: (162,)
  * Mesh2_face_y: (162,)
Grid Connectivity Variables:
  * Mesh2_face_nodes: (162, 6)
  * Mesh2_edge_nodes: (480, 2)
  * nNodes_per_face: (162,)

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:
  * nMesh2_face: 5400
  * nMaxMesh2_face_nodes: 4
  * nMesh2_node: 5402
Grid Coordinate Variables:
  * Mesh2_node_x: (5402,)
  * Mesh2_node_y: (5402,)
Grid Connectivity Variables:
  * Mesh2_face_nodes: (5400, 4)
  * nNodes_per_face: (5400,)

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:
  * nMesh2_node: 320
  * nMesh2_face: 162
  * nMaxMesh2_face_nodes: 6
  * nMesh2_edge: 480
Grid Coordinate Variables:
  * Mesh2_node_x: (320,)
  * Mesh2_node_y: (320,)
  * Mesh2_face_x: (162,)
  * Mesh2_face_y: (162,)
Grid Connectivity Variables:
  * Mesh2_face_nodes: (162, 6)
  * Mesh2_edge_nodes: (480, 2)
  * nNodes_per_face: (162,)

Grid Attributes#

All of the grid topology attributes such as coordinates, connectivity variables, dimensions, etc can be examined through the uxgrid property, i.e. Grid object:

uxds.uxgrid.Mesh2
<xarray.DataArray 'Mesh2' ()>
[1 values with dtype=int32]
Attributes:
    cf_role:                 mesh_topology
    long_name:               Topology data of 2D unstructured mesh
    topology_dimension:      2
    node_coordinates:        Mesh2_node_x Mesh2_node_y
    node_dimension:          nMesh2_node
    face_node_connectivity:  Mesh2_face_nodes
    face_dimension:          nMesh2_face

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
{'sphere_radius': 1.0, 'mesh_spec': '1.0', 'on_a_sphere': 'YES'}

Grid Coordinates#

The coordinates by default are represented in terms of longitude and latitude.

uxds.uxgrid.Mesh2_node_x
<xarray.DataArray 'Mesh2_node_x' (nMesh2_node: 5402)>
[5402 values with dtype=float64]
Coordinates:
    Mesh2_node_x  (nMesh2_node) float64 ...
    Mesh2_node_y  (nMesh2_node) float64 ...
Dimensions without coordinates: nMesh2_node
Attributes:
    standard_name:  longitude
    long_name:      longitude of 2D mesh nodes
    units:          degrees_east
uxds.uxgrid.Mesh2_node_y
<xarray.DataArray 'Mesh2_node_y' (nMesh2_node: 5402)>
[5402 values with dtype=float64]
Coordinates:
    Mesh2_node_x  (nMesh2_node) float64 ...
    Mesh2_node_y  (nMesh2_node) float64 ...
Dimensions without coordinates: nMesh2_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.Mesh2_node_cart_x
<xarray.DataArray 'Mesh2_node_cart_x' (nMesh2_node: 5402)>
array([ 0.57735027,  0.57735027, -0.57735027, ..., -0.58878977,
       -0.57332232, -0.55611709])
Coordinates:
    Mesh2_node_x  (nMesh2_node) float64 315.0 45.0 135.0 ... 141.1 138.0 135.0
    Mesh2_node_y  (nMesh2_node) float64 -35.26 -35.26 -35.26 ... 39.55 38.14
Dimensions without coordinates: nMesh2_node
Attributes:
    standard_name:  cartesian x
    units:          m
uxds.uxgrid.Mesh2_node_cart_y
<xarray.DataArray 'Mesh2_node_cart_y' (nMesh2_node: 5402)>
array([-0.57735027,  0.57735027,  0.57735027, ...,  0.47509872,
        0.51562103,  0.55611709])
Coordinates:
    Mesh2_node_x  (nMesh2_node) float64 315.0 45.0 135.0 ... 141.1 138.0 135.0
    Mesh2_node_y  (nMesh2_node) float64 -35.26 -35.26 -35.26 ... 39.55 38.14
Dimensions without coordinates: nMesh2_node
Attributes:
    standard_name:  cartesian y
    units:          m
uxds.uxgrid.Mesh2_node_cart_z
<xarray.DataArray 'Mesh2_node_cart_z' (nMesh2_node: 5402)>
array([-0.57735027, -0.57735027, -0.57735027, ...,  0.65391729,
        0.63673894,  0.6176306 ])
Coordinates:
    Mesh2_node_x  (nMesh2_node) float64 315.0 45.0 135.0 ... 141.1 138.0 135.0
    Mesh2_node_y  (nMesh2_node) float64 -35.26 -35.26 -35.26 ... 39.55 38.14
Dimensions without coordinates: nMesh2_node
Attributes:
    standard_name:  cartesian z
    units:          m

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.Mesh2_face_nodes
<xarray.DataArray 'Mesh2_face_nodes' (nMesh2_face: 5400, nMaxMesh2_face_nodes: 4)>
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: nMesh2_face, nMaxMesh2_face_nodes
Attributes:
    cf_role:      face_node_connectivity
    start_index:  0
    _FillValue:   -9223372036854775808
uxds.uxgrid.nNodes_per_face
<xarray.DataArray 'nNodes_per_face' (nMesh2_face: 5400)>
array([4, 4, 4, ..., 4, 4, 4])
Dimensions without coordinates: nMesh2_face
Attributes:
    long_name:  number of non-fill value nodes for each face
uxds.uxgrid
<uxarray.Grid>
Original Grid Type: ugrid
Grid Dimensions:
  * nMesh2_face: 5400
  * nMaxMesh2_face_nodes: 4
  * nMesh2_node: 5402
Grid Coordinate Variables:
  * Mesh2_node_x: (5402,)
  * Mesh2_node_y: (5402,)
  * Mesh2_node_cart_x: (5402,)
  * Mesh2_node_cart_y: (5402,)
  * Mesh2_node_cart_z: (5402,)
Grid Connectivity Variables:
  * Mesh2_face_nodes: (5400, 4)
  * nNodes_per_face: (5400,)

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.Mesh2_edge_nodes
<xarray.DataArray 'Mesh2_edge_nodes' (nMesh2_edge: 10800, Two: 2)>
array([[   0,    8],
       [   0,  123],
       [   0,  124],
       ...,
       [5398, 5399],
       [5399, 5400],
       [5400, 5401]])
Dimensions without coordinates: nMesh2_edge, Two
Attributes:
    cf_role:          edge_node_connectivity
    _FillValue:       -9223372036854775808
    long_name:        Maps every edge to the two nodes that it connects
    start_index:      0
    inverse_indices:  [  0  25 369 ...  19  20 886]
    fill_value_mask:  [False False False ... False False False]
uxds.uxgrid.Mesh2_face_edges
<xarray.DataArray 'Mesh2_face_edges' (nMesh2_face: 5400, nMaxMesh2_face_edges: 4)>
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: nMesh2_face, nMaxMesh2_face_edges
Attributes:
    cf_role:      face_edges_connectivity
    start_index:  0
    long_name:    Maps every edge to the two nodes that it connects
uxds.uxgrid
<uxarray.Grid>
Original Grid Type: ugrid
Grid Dimensions:
  * nMesh2_face: 5400
  * nMaxMesh2_face_nodes: 4
  * nMesh2_node: 5402
  * nMesh2_edge: 10800
  * nMaxMesh2_face_edges: 4
Grid Coordinate Variables:
  * Mesh2_node_x: (5402,)
  * Mesh2_node_y: (5402,)
  * Mesh2_node_cart_x: (5402,)
  * Mesh2_node_cart_y: (5402,)
  * Mesh2_node_cart_z: (5402,)
Grid Connectivity Variables:
  * Mesh2_face_nodes: (5400, 4)
  * Mesh2_edge_nodes: (10800, 2)
  * Mesh2_face_edges: (5400, 4)
  * nNodes_per_face: (5400,)

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.nMesh2_node
5402
uxds.uxgrid.nMesh2_edge
10800
uxds.uxgrid.nMesh2_face
5400
uxds.uxgrid.nMaxMesh2_face_nodes
4
uxds.uxgrid.nMaxMesh2_face_edges
4