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