Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

UXarray logo

MPAS Atmosphere

This recipe demonstrates how to create visualizations using 30km MPAS Atmosphere model output. We’ll explore techniques for visualizing atmospheric variables on both the primal and dual MPAS grids, focusing on relative humidity and vorticity at the 200hPa pressure level.

Visualization Objectives

This recipe will guide you through:

  • Creating polygon plots using the MPAS primal grid to visualize relative humidity at 200hPa

  • Developing polygon plots using the MPAS dual grid to visualize vorticity at 200hPa

  • Understanding the differences between primal and dual grid visualizations in MPAS


Relative Humidity

For visualizing relative humidity, we use the Primal MPAS grid, which is composed of hexagons.

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
File ~/micromamba/envs/unstructured-grid-viz-cookbook-dev/lib/python3.14/site-packages/xarray/core/dataset.py:1303, in Dataset._construct_dataarray(self, name)
   1301             variable = self._variables[name]
   1302         except KeyError:
-> 1303             _, name, variable = _get_virtual_variable(self._variables, name, self.sizes)
   1304 

KeyError: 'verticesOnEdge'

During handling of the above exception, another exception occurred:

KeyError                                  Traceback (most recent call last)
File ~/micromamba/envs/unstructured-grid-viz-cookbook-dev/lib/python3.14/site-packages/xarray/core/dataset.py:1421, in Dataset.__getitem__(self, key)
   1419                 if isinstance(key, tuple):
   1420                     message += f"\nHint: use a list to select multiple variables, for example `ds[{list(key)}]`"
-> 1421                 raise KeyError(message) from e
   1422 

File ~/micromamba/envs/unstructured-grid-viz-cookbook-dev/lib/python3.14/site-packages/xarray/core/dataset.py:1303, in Dataset._construct_dataarray(self, name)
   1301             variable = self._variables[name]
   1302         except KeyError:
-> 1303             _, name, variable = _get_virtual_variable(self._variables, name, self.sizes)
   1304 

File ~/micromamba/envs/unstructured-grid-viz-cookbook-dev/lib/python3.14/site-packages/xarray/core/dataset_utils.py:79, in _get_virtual_variable(variables, key, dim_sizes)
     78 if len(split_key) != 2:
---> 79     raise KeyError(key)
     81 ref_name, var_name = split_key

KeyError: 'verticesOnEdge'

The above exception was the direct cause of the following exception:

KeyError                                  Traceback (most recent call last)
Cell In[2], line 4
      1 grid_path = "../../meshfiles/x1.655362.grid.nc"
      2 data_path = "../../meshfiles/x1.655362.data.nc"
      3 
----> 4 uxds_primal = ux.open_dataset(grid_path, data_path)
      5 uxds_primal

File ~/micromamba/envs/unstructured-grid-viz-cookbook-dev/lib/python3.14/site-packages/uxarray/core/api.py:151, in open_dataset(grid_filename_or_obj, filename_or_obj, latlon, use_dual, grid_kwargs, **kwargs)
    146     warn('source_grid is no longer a supported kwarg',
    147          DeprecationWarning,
    148          stacklevel=2)
    150 # Grid definition
--> 151 uxgrid = open_grid(grid_filename_or_obj,
    152                    latlon=latlon,
    153                    use_dual=use_dual,
    154                    **grid_kwargs)
    156 # UxDataset
    157 ds = xr.open_dataset(filename_or_obj, decode_times=False,
    158                      **kwargs)  # type: ignore

File ~/micromamba/envs/unstructured-grid-viz-cookbook-dev/lib/python3.14/site-packages/uxarray/core/api.py:77, in open_grid(grid_filename_or_obj, latlon, use_dual, **kwargs)
     72 elif isinstance(grid_filename_or_obj, (str, Path, PurePath)):
     73     grid_ds = xr.open_dataset(grid_filename_or_obj,
     74                               decode_times=False,
     75                               **kwargs)
---> 77     uxgrid = Grid.from_dataset(grid_ds, use_dual=use_dual)
     79 elif isinstance(grid_filename_or_obj,
     80                 (list, tuple, np.ndarray, xr.DataArray)):
     81     uxgrid = Grid.from_face_vertices(grid_filename_or_obj, latlon=latlon)

File ~/micromamba/envs/unstructured-grid-viz-cookbook-dev/lib/python3.14/site-packages/uxarray/grid/grid.py:148, in Grid.from_dataset(cls, dataset, use_dual)
    146     grid_ds, source_dims_dict = _read_ugrid(dataset)
    147 elif source_grid_spec == "MPAS":
--> 148     grid_ds, source_dims_dict = _read_mpas(dataset, use_dual=use_dual)
    149 elif source_grid_spec == "Shapefile":
    150     raise ValueError("Shapefiles not yet supported")

File ~/micromamba/envs/unstructured-grid-viz-cookbook-dev/lib/python3.14/site-packages/uxarray/io/_mpas.py:401, in _read_mpas(ext_ds, use_dual)
    398     source_dim_map = _dual_to_ugrid(ext_ds, ds)
    399 # convert primal-mesh to UGRID
    400 else:
--> 401     source_dim_map = _primal_to_ugrid(ext_ds, ds)
    403 return ds, source_dim_map

File ~/micromamba/envs/unstructured-grid-viz-cookbook-dev/lib/python3.14/site-packages/uxarray/io/_mpas.py:102, in _primal_to_ugrid(in_ds, out_ds)
     92 out_ds["Mesh2_face_nodes"] = xr.DataArray(
     93     data=verticesOnCell,
     94     dims=["nMesh2_face", "nMaxMesh2_face_nodes"],
   (...)     98         "start_index": INT_DTYPE(0)
     99     })
    101 # vertex indices that saddle a given edge
--> 102 verticesOnEdge = np.array(in_ds['verticesOnEdge'].values, dtype=INT_DTYPE)
    104 # replace missing/zero values with fill value
    105 verticesOnEdge = _replace_zeros(verticesOnEdge)

File ~/micromamba/envs/unstructured-grid-viz-cookbook-dev/lib/python3.14/site-packages/xarray/core/dataset.py:1421, in Dataset.__getitem__(self, key)
   1417 
   1418                 # If someone attempts `ds['foo' , 'bar']` instead of `ds[['foo', 'bar']]`
   1419                 if isinstance(key, tuple):
   1420                     message += f"\nHint: use a list to select multiple variables, for example `ds[{list(key)}]`"
-> 1421                 raise KeyError(message) from e
   1422 
   1423         if utils.iterable_of_hashable(key):
   1424             return self._copy_listed(key)

KeyError: "No variable named 'verticesOnEdge'. Did you mean one of ('verticesOnCell',)?"

Vorticity

For visualizing relative humidity, we use the Dual MPAS grid, which is composed of triangles.

MPAS Dual & Primal Grids

The Model for Prediction Across Scales (MPAS) utilizes two complementary grid structures for atmospheric modeling: the primal grid and the dual grid. The primal grid consists of hexagonal cells that form the primary computational mesh, while the dual grid is composed of triangular cells that connect the centers of the primary hexagons.

In the primal grid structure, scalar quantities like relative humidity are naturally represented at the centers of the hexagonal cells. The dual grid, with its triangular elements, is particularly well-suited for vector quantities and derived fields such as vorticity.

Below, we visualize both grid structures to illustrate their complementary nature.

The visualization below demonstrates the intricate geometric relationship between MPAS primal and dual grids. By overlaying both grid structures, we can observe how the vertices of each hexagonal cell in the primal grid serve as the cell centers for the triangular elements of the dual grid. Conversely, the vertices of the triangular cells in the dual grid correspond to the centers of the hexagonal cells in the primal grid.

3.75km Visualization

For another example of MPAS grid visualization, readers can refer to the UXarray documentation showcasing a 3.75km resolution grid

This example demonstrates MPAS visualization at a higher resolution compared to the 30km grid shown in this recipe.