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
import uxarray as ux
import cartopy.crs as ccrsRelative Humidity¶
For visualizing relative humidity, we use the Primal MPAS grid, which is composed of hexagons.
grid_path = "../../meshfiles/x1.655362.grid.nc"
data_path = "../../meshfiles/x1.655362.data.nc"
uxds_primal = ux.open_dataset(grid_path, data_path)
uxds_primal---------------------------------------------------------------------------
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',)?"uxds_primal['relhum_200hPa'][0].plot(projection=ccrs.Robinson(), backend='matplotlib', pixel_ratio=4.0, features=['coastline'], width=1000, height=500, cmap='viridis', title="30km Relative Humidity (MPAS Primal Grid)")Vorticity¶
For visualizing relative humidity, we use the Dual MPAS grid, which is composed of triangles.
grid_path = "../../meshfiles/x1.655362.grid.nc"
data_path = "../../meshfiles/x1.655362.data.nc"
uxds_dual = ux.open_dataset(grid_path, data_path, use_dual=True)
uxds_dual['vorticity_200hPa']uxds_dual['vorticity_200hPa'][0].plot(projection=ccrs.Robinson(), rasterize=True, backend='matplotlib', pixel_ratio=4.0, features=['coastline'], width=1000, height=500, cmap='coolwarm', title="30km Vorticity (MPAS Dual Grid)", clim=(-0.0001,0.0001))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.
(uxds_primal.uxgrid.subset.bounding_box(lon_bounds = (-1, 1), lat_bounds=(-0.5, 0.5)).plot(title="MPAS Primal Grid Structure", ) +
uxds_dual.uxgrid.subset.bounding_box(lon_bounds = (-1, 1), lat_bounds=(-0.5, 0.5)).plot(title="MPAS Dual Grid Structure")).cols(1).opts(fig_size=200)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.
(uxds_primal.uxgrid.subset.bounding_box(lon_bounds = (-1, 1), lat_bounds=(-0.5, 0.5)).plot() *
uxds_dual.uxgrid.subset.bounding_box(lon_bounds = (-1, 1), lat_bounds=(-0.5, 0.5)).plot()).opts(fig_size=200, title="Primal & Dual Grid Together")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.