Destaggering and vertically interpolating dask
data using xgcm
¶
In this tutorial, we will show you how to leverage the xWRF
accessors and the xWRF
-provided COMODO-compliant attributes in order to destagger the WRF output and interpolate it vertically using dask
and xgcm
.
Loading the data¶
First of all, we load the data and use the simple .xwrf.postprocess()
API and dask
-enable the dataset by passing open_dataset
the chunkgs
kwarg. In a real-world scenario, you might want to spawn a Cluster in order to speed up calculations.
import xwrf
ds = xwrf.tutorial.open_dataset("wrfout", chunks='auto').xwrf.postprocess()
ds
---------------------------------------------------------------------------
HTTPError Traceback (most recent call last)
Cell In[1], line 2
1 import xwrf
----> 2 ds = xwrf.tutorial.open_dataset("wrfout", chunks='auto').xwrf.postprocess()
3 ds
File ~/checkouts/readthedocs.org/user_builds/xwrf/checkouts/latest/xwrf/tutorial.py:113, in open_dataset(name, cache, cache_dir, engine, **kws)
110 url = f'{base_url}/raw/{version}/{path}'
112 # retrieve the file
--> 113 filepath = pooch.retrieve(url=url, known_hash=None, path=cache_dir)
114 ds = xr.open_dataset(filepath, engine=engine, **kws)
115 if not cache:
File ~/checkouts/readthedocs.org/user_builds/xwrf/conda/latest/lib/python3.10/site-packages/pooch/core.py:239, in retrieve(url, known_hash, fname, path, processor, downloader, progressbar)
236 if downloader is None:
237 downloader = choose_downloader(url, progressbar=progressbar)
--> 239 stream_download(url, full_path, known_hash, downloader, pooch=None)
241 if known_hash is None:
242 get_logger().info(
243 "SHA256 hash of downloaded file: %s\n"
244 "Use this value as the 'known_hash' argument of 'pooch.retrieve'"
(...)
247 file_hash(str(full_path)),
248 )
File ~/checkouts/readthedocs.org/user_builds/xwrf/conda/latest/lib/python3.10/site-packages/pooch/core.py:807, in stream_download(url, fname, known_hash, downloader, pooch, retry_if_failed)
803 try:
804 # Stream the file to a temporary so that we can safely check its
805 # hash before overwriting the original.
806 with temporary_file(path=str(fname.parent)) as tmp:
--> 807 downloader(url, tmp, pooch)
808 hash_matches(tmp, known_hash, strict=True, source=str(fname.name))
809 shutil.move(tmp, str(fname))
File ~/checkouts/readthedocs.org/user_builds/xwrf/conda/latest/lib/python3.10/site-packages/pooch/downloaders.py:221, in HTTPDownloader.__call__(self, url, output_file, pooch, check_only)
219 try:
220 response = requests.get(url, timeout=timeout, **kwargs)
--> 221 response.raise_for_status()
222 content = response.iter_content(chunk_size=self.chunk_size)
223 total = int(response.headers.get("content-length", 0))
File ~/checkouts/readthedocs.org/user_builds/xwrf/conda/latest/lib/python3.10/site-packages/requests/models.py:1024, in Response.raise_for_status(self)
1019 http_error_msg = (
1020 f"{self.status_code} Server Error: {reason} for url: {self.url}"
1021 )
1023 if http_error_msg:
-> 1024 raise HTTPError(http_error_msg, response=self)
HTTPError: 403 Client Error: Forbidden for url: https://raw.githubusercontent.com/xarray-contrib/xwrf-data/main/data/wrfout_d01_2099-10-01_00%3A00%3A00.nc
Destaggering¶
If we naively try to calculate the wind speed from the U
and V
components, we get an error due to them having different shapes.
from metpy.calc import wind_speed
wind_speed(ds.U, ds.V)
Upon investigating the wind components, we can see that they are defined on the WRF
-internal Arakawa-C grid, which causes the shapes to differ.
ds.U.sizes, ds.V.sizes
Destaggering is done in no time at all using the handy .xwrf
accessor. We can now decide whether to destagger the whole Dataset
…
destaggered = ds.xwrf.destagger().metpy.quantify()
destaggered['wind_speed'] = wind_speed(destaggered.U, destaggered.V)
destaggered.wind_speed
… or whether we just want to destagger the two individual DataArrays
.
ds = ds.metpy.quantify()
wind_speed(ds.U.xwrf.destagger(), ds.V.xwrf.destagger())
Vertical interpolation using xgcm
¶
We have now calculated the wind speed for the whole model domain. However, the z-layers are still in the native WRF sigma coordinate, which is of no practical use to us. So, in order to be able to analyze this data properly, we have to interpolate it onto pressure levels.
But, since xWRF
prepared the dataset with the appropriate COMODO (and units
) attributes, we can simply use xgcm
with its Grid.transform
function to solve this problem! However, since it doesn’t understand units yet, we have to work around it a bit:
import xgcm
import numpy as np
import pint_xarray
target_levels = np.array([250.]) # in hPa
air_pressure = destaggered.air_pressure.pint.to('hPa').metpy.dequantify()
grid = xgcm.Grid(destaggered, periodic=False)
_wind_speed = grid.transform(destaggered.wind_speed.metpy.dequantify(), 'Z', target_levels, target_data=air_pressure, method='log')
_wind_speed = _wind_speed.compute()
Finally, we can plot the result using hvplot
.
import hvplot.xarray
_wind_speed.hvplot.quadmesh(
x='XLONG',
y='XLAT',
title='Wind speed at 250 hPa',
geo=True,
project=True,
alpha=0.9,
cmap='inferno',
clim=(_wind_speed.min().item(), _wind_speed.max().item()),
clabel='wind speed [m/s]',
tiles='OSM',
dynamic=False
)