Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
philipc2 committed Nov 29, 2023
2 parents 87335ee + 0fcdfa5 commit 167c6df
Show file tree
Hide file tree
Showing 2 changed files with 306 additions and 17 deletions.
305 changes: 299 additions & 6 deletions notebooks/01-intro/01-unstructured-grid-overview.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,309 @@
"---"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The goal of this notebook is to provide a brief overview of unstructured grids and provide a teaser of plotting with the UXarray package.\n",
"Contents:\n",
"1. Structured vs. Unstructured Grids\n",
"2. Structured Grids\n",
"3. Unstructured Grids\n",
"4. Why UXarrary for unstructured grids?\n",
"5. Loading and plotting a mesh with UXarray"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Structured vs Unstructured Grids\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It is important to understand this difference, before diving into unstructured grid:\n",
"\n",
"A structured grid is well-ordered, with a simple scheme used to label elements and identify neighbors, while an unstructured grid allows elements to be joined in any manner, requiring special lists to identify neighboring elements.\n",
"\n",
"Note that the focus here is on two dimensional grids in the climate and weather context, but the same concepts apply to three dimensional grids."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Structured Grid\n",
"A few advantages of structured grids are:\n",
"- Uniform Representation: Simplifies numerical methods and enhances result interpretation.\n",
" \n",
"- Efficient Numerics: Well-suited for finite-difference schemes, ensuring computational efficiency.\n",
" \n",
"- Simplified Interpolation: Straightforward interpolation facilitates integration of observational data and model outputs.\n",
" \n",
"- Boundary Handling: Ideal for regular boundaries, easing implementation of boundary conditions.\n",
" \n",
"- Optimized Parallel Computing: Regular structure supports efficient parallel computing for scalability."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This code below shows a structured mesh example over 2D earth geometry and plots random temperature data. \n",
"\n",
"Given the number of points in longitude and latitude direction, the code uses Numpy's meshgrid to generates a structured grid. The temperature data is then interpolated onto this grid, creating a smooth representation. Xarray is leveraged to organize the gridded data into a dataset, facilitating easy manipulation and visualization. The resulting plot showcases the data on this structure mesh, providing a clearer understanding of temperature variations across defined longitude and latitude ranges. Plotting the structured grid and the temperature data is done using Cartopy, a cartographic plotting library. \n",
"\n",
"There are many other libraries and ways to create a structured grids."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# code and content goes here"
],
"metadata": {
"collapsed": false
}
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import cartopy.crs as ccrs\n",
"import xarray as xr\n",
"\n",
"# Define the global domain\n",
"lat_range = [-90.0, 90.0]\n",
"lon_range = [-180.0, 180.0]\n",
"\n",
"# Create a structured grid. Note the number of points in each dimension\n",
"# There is not need to store the grid points in a separate array\n",
"# Also note that the grid points are evenly spaced and not connectivity information is needed\n",
"\n",
"num_lat_points = 20\n",
"num_lon_points = 30\n",
"\n",
"lats = np.linspace(lat_range[0], lat_range[1], num_lat_points)\n",
"lons = np.linspace(lon_range[0], lon_range[1], num_lon_points)\n",
"\n",
"lons_grid, lats_grid = np.meshgrid(lons, lats)\n",
"\n",
"# Generate random temperature data for each grid point\n",
"temperature_data = np.random.uniform(low=20, high=30, size=(num_lat_points, num_lon_points))\n",
"\n",
"# Create xarray Dataset\n",
"ds = xr.Dataset()\n",
"ds['temperature'] = (['lat', 'lon'], temperature_data)\n",
"ds['lon'] = lons\n",
"ds['lat'] = lats\n",
"\n",
"# Plot the structured grid using xarray\n",
"fig, ax = plt.subplots(subplot_kw={'projection': ccrs.PlateCarree()})\n",
"ax.set_global()\n",
"\n",
"# Plot world map lines\n",
"ax.coastlines()\n",
"ax.gridlines(draw_labels=True, dms=True, x_inline=False, y_inline=False)\n",
"\n",
"# Plot the structured grid\n",
"cs = ax.pcolormesh(ds['lon'], ds['lat'], ds['temperature'], cmap='coolwarm', shading='auto')\n",
"\n",
"# Colorbar\n",
"cbar = plt.colorbar(cs, ax=ax, label='Temperature (°C)')\n",
"\n",
"ax.set_title('Structured Grid Example')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Unstructured Grids"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"- Adaptability to complex geometries: Fits intricate shapes and boundaries\n",
"\n",
"- Often runs faster than structured grids: Requires fewer elements to achieve similar accuracy\n",
" \n",
"- Local refinement: Concentrates resolution on areas of interest\n",
" \n",
"- Flexibility in element types: Accommodates various element shapes\n",
" \n",
"- Efficient parallelization: Scales well to multiple processors\n",
" \n",
"- Suitability for dynamic simulations: Adapts to changing conditions"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are a variety of libraries and conventions for creating unstructured grids. Here we use a very basic standard python approach to showcase an unstructured grid: \n",
"\n",
"The code generates an unstructured grid over a rectangular domain defined by latitude and longitude ranges. It creates a set of points using matplotlib.tri.Triangulation. The resulting triangulation is then plotted using cartopy and matplotlib.\n",
"\n",
"The are many other types of elements that can be used to create unstructured grids. Polygonal elements are often used to represent complex geometries. Meshes often contain mixed elements with different types of elements used in different areas of the domain."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import cartopy.crs as ccrs\n",
"import matplotlib.tri as mtri\n",
"import xarray as xr\n",
"\n",
"# Generate random temperature data\n",
"np.random.seed(42)\n",
"num_points = 600\n",
"latitudes = np.random.uniform(low=-90, high=90, size=num_points)\n",
"longitudes = np.random.uniform(low=-180, high=180, size=num_points)\n",
"temperatures = np.random.uniform(low=-30, high=30, size=num_points)\n",
"\n",
"# Create xarray DataArray for temperature data\n",
"temperature_data = xr.DataArray(temperatures, dims='points', coords={'points': range(num_points)})\n",
"\n",
"# Perform Delaunay triangulation\n",
"triang = mtri.Triangulation(longitudes, latitudes)\n",
"\n",
"# Create xarray DataArray for triangulation coordinates\n",
"triang_data = xr.DataArray(np.column_stack([triang.x, triang.y]), dims=('points', 'coords'))\n",
"\n",
"# Plot the globe with unstructured mesh using xarray\n",
"fig, ax = plt.subplots(subplot_kw={'projection': ccrs.PlateCarree()})\n",
"ax.set_global()\n",
"\n",
"# Plot world map lines with prominent gridlines\n",
"ax.coastlines()\n",
"ax.gridlines(draw_labels=True, dms=True, x_inline=False, y_inline=False, linewidth=0.5) \n",
"\n",
"# Plot unstructured mesh with bold lines\n",
"ax.triplot(triang, 'ko-', markersize=1, linewidth=2, alpha=0.5 ) # Increase linewidth to see the triangles\n",
"\n",
"# Scatter plot with temperature data\n",
"sc = ax.scatter(longitudes, latitudes, c=temperature_data, cmap='coolwarm', s=10, transform=ccrs.PlateCarree())\n",
"\n",
"# Colorbar\n",
"cbar = plt.colorbar(sc, ax=ax, label='Temperature (°C)')\n",
"\n",
"ax.set_title('Unstructured Grid Example')\n",
"plt.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"NOTE: This is a very basic example of an unstructured grid with triangles. There are very specialized libraries to create unstructured grids. Often the region of interest is meshed with a finer resolution. The mesh is then coarsened in areas where the resolution is not needed. This is done to reduce the number of elements and improve computational efficiency."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Why UXarray for unstructured grids?\n",
"\n",
"- It inherits from Xarray, providing simplified data using familiar (Xarray like) data structures and operations.\n",
" \n",
"- Bring standardization to unstructured mesh support for climate data analysis and visualization.\n",
"\n",
"- Adherence to the UGrid specification for compatibility across a variety of mesh formats.\n",
"\n",
"- Optimized data structures and algorithms for handling large and complex unstructured datasets. \n",
"\n",
"- Enhanced Interoperability and Community Collaboration.\n",
"\n",
"- One interface for a variety of unstructured grid formats.\n",
"\n",
"There are unstructured grid format such as Exodus, SCRIP, MPAS, UGRID etc. UXarray is a library that can read and write many such unstructured grid formats. The specific focus of UXarray is to provide a common interface to access and operate on unstructured grids in the climate science community."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Loading and plotting NetCDF mesh and data with UXarray\n",
"\n",
"The code below loads an MPAS OCEAN mesh and plots it using the UXarray library plot function.\n",
"\n",
"MPAS or the Model for Prediction Across Scales provides a versatile and scalable framework for Earth system modeling, and the MPAS ocean mesh is a critical component for simulating ocean dynamics with adaptability to varying scales and regions. It is widely used in climate science research for a range of applications, from global climate simulations to regional oceanographic studies."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import uxarray as ux\n",
"import requests\n",
"\n",
"small_file_480km = requests.get(\n",
" \"https://web.lcrc.anl.gov/public/e3sm/inputdata/share/meshes/mpas/ocean/oQU480.230422.nc\"\n",
" ).content\n",
"\n",
"ds_small_480km = ux.open_dataset(small_file_480km, small_file_480km)\n",
"print(\"The mesh contains:\", ds_small_480km.uxgrid)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Plot data on a mesh with UXarray"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ds_small_480km.uxgrid.plot(title=\"MPAS OCEAN Unstructured Mesh Plot\", height=350, width=700)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now check the variables in the mesh dataset and plot one of the variables:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ds_small_480km"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ds_small_480km['bottomDepth'].plot.polygons(title=\"Bottom Depth Polygon Plot\", height=350, width=700)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebook serves as an introduction to unstructured grids and UXarray. For more information, please visit the UXarray documentation at https://uxarray.readthedocs.io/en/latest/ and specifically see the example section: https://uxarray.readthedocs.io/en/latest/examples.html\n",
"\n",
"The next sections will start with basic building blocks of UXarray and then slowly dive into more advanced features."
]
}
],
"metadata": {
Expand All @@ -42,7 +335,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.11"
"version": "3.11.4"
},
"nbdime-conflicts": {
"local_diff": [
Expand Down
18 changes: 7 additions & 11 deletions notebooks/03-uxarray-vis/01-grid-topology.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,13 @@
"source": [
"<div class=\"admonition alert alert-attention\">\n",
" <p class=\"admonition-title\" style=\"font-weight:bold\">How to plot through `Grid`, `UxDataset`, or `UxDataArray`?</p>\n",
" As the above `ux_grid` and `uxds` creation suggests, you may either have a `UxDataset` (or similarly `UxDataArray`), or a standalone `Grid` object. Visualization of the geometric elements of an unstructured grid is possible in all of these cases as follows:\n",
" <br>\n",
" <br>\n",
" `uxarray.Grid.plot.plotting_function()`\n",
" <br>\n",
" `uxarray.UxDataset.uxgrid.plot.plotting_function()` # Through `uxgrid` accessor\n",
" <br>\n",
" `uxarray.UxDataArray.uxgrid.plot.plotting_function()` # Through `uxgrid` accessor\n",
" <br>\n",
" <br>\n",
" We will demonstrate plotting functions using the standalone `ux_grid` thorughout this notebook.\n",
" As the above `ux_grid` and `uxds` creation suggests, you may either have a `UxDataset` (or similarly `UxDataArray`), or a standalone `Grid` object. Visualization\n",
"of the geometric elements of an unstructured grid is possible in all of these cases as follows (Through `uxgrid` accessor when it is a `UxDataset` or `UxDataArray`): <br />\n",
" \n",
"`uxarray.Grid.plot.plotting_function()` <br />\n",
"`uxarray.UxDataset.uxgrid.plot.plotting_function()` <br /> \n",
"`uxarray.UxDataArray.uxgrid.plot.plotting_function()` <br />\n",
"We will demonstrate plotting functions using the standalone `ux_grid` thorughout this notebook.\n",
"</div>"
]
},
Expand Down

0 comments on commit 167c6df

Please sign in to comment.