{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 02_GriddedDiagnostics_Dewpoint_ERA5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## In this notebook, we'll cover the following:\n", "1. Select a date and access an ERA5 Dataset\n", "2. Subset the desired Datasets along their dimensions\n", "3. Calculate and visualize dewpoint." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 0) Imports " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import xarray as xr\n", "import pandas as pd\n", "import numpy as np\n", "from datetime import datetime as dt\n", "from metpy.units import units\n", "import metpy.calc as mpcalc\n", "import cartopy.crs as ccrs\n", "import cartopy.feature as cfeature\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1) Specify a starting and ending date/time, regional extent, vertical levels, and access the ERA5" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Areal extent\n", "lonW = -105\n", "lonE = -90\n", "latS = 31\n", "latN = 39\n", "cLat, cLon = (latS + latN)/2, (lonW + lonE)/2\n", "\n", "# Recall that in ERA5, longitudes run between 0 and 360, not -180 and 180\n", "if (lonW < 0 ):\n", " lonW = lonW + 360\n", "if (lonE < 0 ):\n", " lonE = lonE + 360\n", " \n", "expand = 1\n", "latRange = np.arange(latS - expand,latN + expand,.25) # expand the data range a bit beyond the plot range\n", "lonRange = np.arange((lonW - expand),(lonE + expand),.25) # Need to match longitude values to those of the coordinate variable\n", "\n", "# Vertical level specification\n", "pLevel = 925\n", "levStr = f'{pLevel}'\n", "\n", "startYear = 2013\n", "startMonth = 5\n", "startDay = 31\n", "startHour = 12\n", "startMinute = 0\n", "startDateTime = dt(startYear,startMonth,startDay, startHour, startMinute)\n", "\n", "endYear = 2013\n", "endMonth = 5\n", "endDay = 31\n", "endHour = 18\n", "endMinute = 0\n", "endDateTime = dt(endYear,endMonth,endDay, endHour, endMinute)\n", "\n", "delta_time = endDateTime - startDateTime\n", "time_range_max = 7*86400\n", "\n", "if (delta_time.total_seconds() > time_range_max):\n", " raise RuntimeError(\"Your time range must not exceed 7 days. Go back and try again.\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Wb2EndDate = dt(2023,1,10)\n", "if (endDateTime <= Wb2EndDate):\n", " ds = xr.open_dataset(\n", " 'gs://weatherbench2/datasets/era5/1959-2023_01_10-wb13-6h-1440x721.zarr', \n", " chunks={'time': 48},\n", " consolidated=True,\n", " engine='zarr'\n", ")\n", "else: \n", " import glob, os\n", " input_directory = '/free/ktyle/era5'\n", " files = glob.glob(os.path.join(input_directory,'*.nc'))\n", " varDict = {'valid_time': 'time', \n", " 'pressure_level': 'level',\n", " 'msl': 'mean_sea_level_pressure',\n", " 'q': 'specific_humidity',\n", " 't': 'temperature',\n", " 'u': 'u_component_of_wind',\n", " 'v': 'v_component_of_wind',\n", " 'w': 'vertical_velocity',\n", " 'z': 'geopotential'}\n", " dimDict = {'valid_time': 'time',\n", " 'pressure_level': 'level'}\n", " ds = xr.open_mfdataset(files).rename_dims(dimDict).rename_vars(varDict)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Examine the `Dataset`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ds" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 2) Specify a date/time range, and subset the desired `Dataset`s along their dimensions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create a list of date and times based on what we specified for the initial and final times, using Pandas' date_range function" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dateList = pd.date_range(startDateTime, endDateTime,freq=\"6h\")\n", "dateList" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will calculate dewpoint, which depends on temperature and specific humidity (and also pressure, as we will see), so read in those arrays. Read in U and V as well if we wish to visualize wind vectors." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Now create objects for our desired DataArrays based on the coordinates we have subsetted." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Data variable selection\n", "Q = ds['specific_humidity'].sel(time=dateList,level=pLevel,latitude=latRange,longitude=lonRange).compute()\n", "T = ds['temperature'].sel(time=dateList,level=pLevel,latitude=latRange,longitude=lonRange).compute()\n", "U = ds['u_component_of_wind'].sel(time=dateList,level=pLevel,latitude=latRange,longitude=lonRange).compute()\n", "V = ds['v_component_of_wind'].sel(time=dateList,level=pLevel,latitude=latRange,longitude=lonRange).compute()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Define our subsetted coordinate arrays of lat and lon. Pull them from any of the DataArrays. We'll need to pass these into the contouring functions later on." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lats = T.latitude\n", "lons = T.longitude" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 3) Calculate and visualize dewpoint." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's examine the MetPy diagnostic that calculates dewpoint if specific humidity is available:\n", "[Dewpoint from specific humidity](https://unidata.github.io/MetPy/latest/api/generated/metpy.calc.dewpoint_from_specific_humidity.html)