python-awips/examples/notebooks/Forecast_Model_Vertical_Sounding.ipynb

542 lines
917 KiB
Text
Raw Normal View History

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a name=\"top\"></a>\n",
"<div style=\"width:1000 px\">\n",
"\n",
"<div style=\"float:right; width:98 px; height:98px;\">\n",
"<img src=\"https://docs.unidata.ucar.edu/images/logos/unidata_logo_vertical_150x150.png\" alt=\"Unidata Logo\" style=\"height: 98px;\">\n",
"</div>\n",
"\n",
"# Forecast Model Vertical Sounding\n",
"**Python-AWIPS Tutorial Notebook**\n",
"\n",
"<div style=\"clear:both\"></div>\n",
"</div>\n",
"\n",
"---\n",
"\n",
"<div style=\"float:right; width:250 px\"><img src=\"../images/forecast_model_vert_sounding_preview.png\" alt=\"preview image of a model sounding skewt and hodograph\" style=\"height: 300px;\"></div>\n",
"\n",
"\n",
"# Objectives\n",
"\n",
"* Use python-awips to connect to an edex server\n",
"* Request data using the [ModelSounding class](http://unidata.github.io/python-awips/api/ModelSounding.html) in addition to using the normal [DataAccess class](http://unidata.github.io/python-awips/api/DataAccessLayer.html)\n",
"* Create and compare vertical sounding from different AWIPS model data with isobaric levels\n",
"* Use [Shapely Point geometry](https://shapely.readthedocs.io/en/stable/reference/shapely.Point.html) to define a point\n",
"* Convert between units when necessary\n",
"* Use MetPy to create [SkewT](https://unidata.github.io/MetPy/latest/api/generated/metpy.plots.SkewT.html) and [Hodograph](https://unidata.github.io/MetPy/latest/api/generated/metpy.plots.Hodograph.html) plots\n",
"\n",
"---"
]
},
{
"cell_type": "markdown",
"metadata": {
"toc": true
},
"source": [
"<h1>Table of Contents<span class=\"tocSkip\"></span></h1>\n",
"<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#Imports\" data-toc-modified-id=\"Imports-1\"><span class=\"toc-item-num\">1&nbsp;&nbsp;</span>Imports</a></span></li><li><span><a href=\"#EDEX-Connection\" data-toc-modified-id=\"EDEX-Connection-2\"><span class=\"toc-item-num\">2&nbsp;&nbsp;</span>EDEX Connection</a></span></li><li><span><a href=\"#Get-the-ModelSounding-Data\" data-toc-modified-id=\"Get-the-ModelSounding-Data-3\"><span class=\"toc-item-num\">3&nbsp;&nbsp;</span>Get the ModelSounding Data</a></span><ul class=\"toc-item\"><li><span><a href=\"#Surface-Level-Pressure-Request\" data-toc-modified-id=\"Surface-Level-Pressure-Request-3.1\"><span class=\"toc-item-num\">3.1&nbsp;&nbsp;</span>Surface Level Pressure Request</a></span></li><li><span><a href=\"#Initial-Population-of-Data-Arrays\" data-toc-modified-id=\"Initial-Population-of-Data-Arrays-3.2\"><span class=\"toc-item-num\">3.2&nbsp;&nbsp;</span>Initial Population of Data Arrays</a></span></li></ul></li><li><span><a href=\"#Skew-T/Log-P\" data-toc-modified-id=\"Skew-T/Log-P-4\"><span class=\"toc-item-num\">4&nbsp;&nbsp;</span>Skew-T/Log-P</a></span></li><li><span><a href=\"#Model-Sounding-Comparison\" data-toc-modified-id=\"Model-Sounding-Comparison-5\"><span class=\"toc-item-num\">5&nbsp;&nbsp;</span>Model Sounding Comparison</a></span></li></ul></div>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Imports\n",
"\n",
"The imports below are used throughout the notebook. Note the first import is coming directly from python-awips and allows us to connect to an EDEX server. The subsequent imports are for data manipulation and visualization. "
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"from awips.dataaccess import DataAccessLayer, ModelSounding\n",
"from awips import ThriftClient\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"from metpy.plots import SkewT, Hodograph\n",
"from metpy.units import units\n",
"from mpl_toolkits.axes_grid1.inset_locator import inset_axes\n",
"from math import sqrt\n",
"from datetime import datetime, timedelta\n",
"from shapely.geometry import Point, Polygon\n",
"import shapely.wkb\n",
"import timeit"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## EDEX Connection\n",
"\n",
"First we establish a connection to Unidata's public EDEX server. With that connection made, we can create a [new data request object](http://unidata.github.io/python-awips/api/IDataRequest.html) and set the data type to ***grid***. We are going to start with **NAM40** model data, and use this request to find the most recent forcast run and time."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Using NAM40 forecast time 2023-07-03 12:00:00\n"
]
}
],
"source": [
"server = 'edex-cloud.unidata.ucar.edu'\n",
"DataAccessLayer.changeEDEXHost(server)\n",
"\n",
"model=\"NAM40\"\n",
"\n",
"\n",
"# Get latest forecast cycle run\n",
"timeReq = DataAccessLayer.newDataRequest(\"grid\")\n",
"timeReq.setLocationNames(model)\n",
"cycles = DataAccessLayer.getAvailableTimes(timeReq, True)\n",
"times = DataAccessLayer.getAvailableTimes(timeReq)\n",
2018-10-15 08:25:13 -06:00
"fcstRun = DataAccessLayer.getForecastRun(cycles[-2], times)\n",
"\n",
"print(\"Using \" + model + \" forecast time \" + str(fcstRun[0]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Get the ModelSounding Data\n",
"\n",
"Here we set additional parameters and constraints that are necessary to request our [**ModelSounding**](http://unidata.github.io/python-awips/api/ModelSounding.html) data. In addition to the timeRange which we found in the previous step, we define the following to use:\n",
"- Geographic Point, defined in the order Lon, Lat\n",
"- Parameters we use for our eventual plots\n",
"\n",
"### Surface Level Pressure Request\n",
"\n",
"For this first request we'll do a single-record query for level = \"0.0FHAG\" to determine the surface pressure level."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"# Note the order is Lon,Lat and not Lat,Lon\n",
"point = Point(-104.67,39.87)\n",
"\n",
"# The parameter names for Temperature, Dewpoint, U and V Wind Components, and Pressure\n",
"use_parms = ['T','DpT','uW','vW','P']\n",
"use_level = \"0.0FHAG\"\n",
"sndObject = ModelSounding.getSounding(model, use_parms, \n",
" [\"0.0FHAG\"], point, timeRange=[fcstRun[0]])"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"parms = ['T','DpT','uW','vW']"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Initial Population of Data Arrays\n",
"\n",
"Create new arrays for pressure, temperature, dewpoint, and u/v wind components, and then populate them from the data returned in our first **ModelSounding** response object."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found surface record at 831.0MB\n"
]
}
],
"source": [
"p,t,d,u,v = [],[],[],[],[]\n",
"\n",
"if len(sndObject) > 0:\n",
" for time in sndObject._dataDict:\n",
" p.append(float(sndObject._dataDict[time][use_level]['P']))\n",
" t.append(float(sndObject._dataDict[time][use_level]['T']))\n",
" d.append(float(sndObject._dataDict[time][use_level]['DpT']))\n",
" u.append(float(sndObject._dataDict[time][use_level]['uW']))\n",
" v.append(float(sndObject._dataDict[time][use_level]['vW']))\n",
" print(\"Found surface record at \" + \"%.1f\" % p[0] + \"MB\")\n",
"else:\n",
" raise ValueError(\"sndObject returned empty for query [\" \n",
" + ', '.join(str(x) for x in (model, use_parms, point, use_level)) +\"]\")"
2018-10-15 08:25:13 -06:00
]
},
{
"cell_type": "code",
"execution_count": 6,
2018-10-15 08:25:13 -06:00
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Using 32 levels between 831.0 and 50.0MB\n"
2018-10-15 08:25:13 -06:00
]
}
],
"source": [
"\n",
"# Get isobaric levels with our requested parameters\n",
"levelReq = DataAccessLayer.newDataRequest(\"grid\", envelope=point)\n",
"levelReq.setLocationNames(model)\n",
"levelReq.setParameters('T','DpT','uW','vW')\n",
"availableLevels = DataAccessLayer.getAvailableLevels(levelReq)\n",
"\n",
"# Clean levels list of unit string (MB, FHAG, etc.)\n",
"levels = []\n",
"for lvl in availableLevels:\n",
" name=str(lvl)\n",
" if 'MB' in name and '_' not in name:\n",
" # If this level is above (less than in mb) our 0.0FHAG record\n",
" if float(name.replace('MB','')) < p[0]:\n",
" levels.append(lvl)\n",
"\n",
"# Get Sounding\n",
"sndObject = ModelSounding.getSounding(model, parms, levels, point, \n",
" timeRange=[fcstRun[0]])\n",
"\n",
"if not len(sndObject) > 0:\n",
" raise ValueError(\"sndObject returned empty for query [\" \n",
" + ', '.join(str(x) for x in (model, parms, point, levels)) +\"]\")\n",
" \n",
"for time in sndObject._dataDict:\n",
" for lvl in sndObject._dataDict[time].levels():\n",
" for parm in sndObject._dataDict[time][lvl].parameters():\n",
" if parm == \"T\":\n",
" t.append(float(sndObject._dataDict[time][lvl][parm]))\n",
" elif parm == \"DpT\":\n",
" d.append(float(sndObject._dataDict[time][lvl][parm]))\n",
" elif parm == 'uW':\n",
" u.append(float(sndObject._dataDict[time][lvl][parm]))\n",
" elif parm == 'vW':\n",
" v.append(float(sndObject._dataDict[time][lvl][parm]))\n",
" else:\n",
" print(\"WHAT IS THIS\")\n",
" print(sndObject._dataDict[time][lvl][parm])\n",
" # Pressure is our requested level rather than a returned parameter\n",
" p.append(float(lvl.replace('MB','')))\n",
"\n",
"# convert to numpy.array()\n",
"p = np.array(p, dtype=float)\n",
"t = (np.array(t, dtype=float) - 273.15) * units.degC\n",
"d = (np.array(d, dtype=float) - 273.15) * units.degC\n",
"u = (np.array(u, dtype=float) * units('m/s')).to('knots')\n",
"v = (np.array(v, dtype=float) * units('m/s')).to('knots')\n",
"w = np.sqrt(u**2 + v**2)\n",
"\n",
"print(\"Using \" + str(len(levels)) + \" levels between \" + \n",
" str(\"%.1f\" % max(p)) + \" and \" + str(\"%.1f\" % min(p)) + \"MB\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"\n",
"## Skew-T/Log-P"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 864x1008 with 2 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"plt.rcParams['figure.figsize'] = (12, 14)\n",
"\n",
"# Skew-T\n",
"skew = SkewT(rotation=45)\n",
"skew.plot(p, t, 'r', linewidth=2)\n",
"skew.plot(p, d, 'g', linewidth=2)\n",
"skew.plot_barbs(p, u, v)\n",
"skew.plot_dry_adiabats()\n",
"skew.plot_moist_adiabats()\n",
"skew.plot_mixing_lines(linestyle=':')\n",
"\n",
"skew.ax.set_ylim(1000, np.min(p))\n",
"skew.ax.set_xlim(-50, 40)\n",
"\n",
"# Title\n",
"plt.title( model + \" (\" + str(point) + \") \" + str(time.getRefTime()))\n",
"\n",
"# Hodograph\n",
"ax_hod = inset_axes(skew.ax, '40%', '40%', loc=2)\n",
"h = Hodograph(ax_hod, component_range=max(w.magnitude))\n",
"h.add_grid(increment=20)\n",
"h.plot_colormapped(u, v, w)\n",
"\n",
"# Dotted line at 0C isotherm\n",
"l = skew.ax.axvline(0, color='c', linestyle='-', linewidth=1)\n",
"\n",
"plt.show()"
]
2018-10-15 08:25:13 -06:00
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Model Sounding Comparison"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"scrolled": false
},
2018-10-15 08:25:13 -06:00
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Using RAP13 forecast time 2023-07-03 22:00:00\n",
"Found surface record at 835.8MB\n",
"Using 30 levels between 835.8 and 100.0MB\n"
2018-10-15 08:25:13 -06:00
]
},
{
"data": {
"image/png": "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
2018-10-15 08:25:13 -06:00
"text/plain": [
"<Figure size 864x1008 with 2 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Using GFS20 forecast time 2023-07-03 18:00:00\n",
"Found surface record at 839.9MB\n",
"Using 22 levels between 839.9 and 100.0MB\n"
2018-10-15 08:25:13 -06:00
]
},
{
"data": {
"image/png": "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
2018-10-15 08:25:13 -06:00
"text/plain": [
"<Figure size 864x1008 with 2 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Using NAM40 forecast time 2023-07-03 18:00:00\n",
"Found surface record at 831.5MB\n",
"Using 32 levels between 831.5 and 50.0MB\n"
2018-10-15 08:25:13 -06:00
]
},
{
"data": {
"image/png": "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
2018-10-15 08:25:13 -06:00
"text/plain": [
"<Figure size 864x1008 with 2 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"models = [\"RAP13\", \"GFS20\", \"NAM40\"]\n",
2018-10-15 08:25:13 -06:00
"parms = ['T','DpT','uW','vW']\n",
"\n",
"for modelName in models:\n",
" timeReq = DataAccessLayer.newDataRequest(\"grid\")\n",
" timeReq.setLocationNames(modelName)\n",
" cycles = DataAccessLayer.getAvailableTimes(timeReq, True)\n",
" times = DataAccessLayer.getAvailableTimes(timeReq)\n",
" fcstRun = DataAccessLayer.getForecastRun(cycles[-1], times)\n",
" print(\"Using \" + modelName + \" forecast time \" + str(fcstRun[0]))\n",
" \n",
" p,t,d,u,v = [],[],[],[],[]\n",
" use_parms = ['T','DpT','uW','vW','P']\n",
" use_level = \"0.0FHAG\"\n",
" \n",
" sndObject = ModelSounding.getSounding(modelName, use_parms, \n",
" [use_level], point, timeRange=[fcstRun[0]])\n",
" if len(sndObject) > 0:\n",
" for time in sndObject._dataDict:\n",
" p.append(float(sndObject._dataDict[time][use_level]['P']))\n",
" t.append(float(sndObject._dataDict[time][use_level]['T']))\n",
" d.append(float(sndObject._dataDict[time][use_level]['DpT']))\n",
" u.append(float(sndObject._dataDict[time][use_level]['uW']))\n",
" v.append(float(sndObject._dataDict[time][use_level]['vW']))\n",
" print(\"Found surface record at \" + \"%.1f\" % p[0] + \"MB\")\n",
" else:\n",
" raise ValueError(\"sndObject returned empty for query [\" \n",
" + ', '.join(str(x) for x in (modelName, use_parms, point, use_level)) +\"]\")\n",
" \n",
" # Get isobaric levels with our requested parameters\n",
" levelReq = DataAccessLayer.newDataRequest(\"grid\", envelope=point)\n",
" levelReq.setLocationNames(modelName)\n",
" levelReq.setParameters('T','DpT','uW','vW')\n",
" availableLevels = DataAccessLayer.getAvailableLevels(levelReq)\n",
" # Clean levels list of unit string (MB, FHAG, etc.)\n",
" levels = []\n",
" for lvl in availableLevels:\n",
" name=str(lvl)\n",
" if 'MB' in name and '_' not in name:\n",
" # If this level is above (less than in mb) our 0.0FHAG record\n",
" if float(name.replace('MB','')) < p[0]:\n",
" levels.append(lvl)\n",
" \n",
" # Get Sounding\n",
" sndObject = ModelSounding.getSounding(modelName, parms, levels, point, \n",
" timeRange=[fcstRun[0]])\n",
" if not len(sndObject) > 0:\n",
" raise ValueError(\"sndObject returned empty for query [\" \n",
" + ', '.join(str(x) for x in (modelName, parms, point, levels)) +\"]\")\n",
" for time in sndObject._dataDict:\n",
" for lvl in sndObject._dataDict[time].levels():\n",
" for parm in sndObject._dataDict[time][lvl].parameters():\n",
" if parm == \"T\":\n",
" t.append(float(sndObject._dataDict[time][lvl][parm]))\n",
" elif parm == \"DpT\":\n",
" d.append(float(sndObject._dataDict[time][lvl][parm]))\n",
" elif parm == 'uW':\n",
" u.append(float(sndObject._dataDict[time][lvl][parm]))\n",
" elif parm == 'vW':\n",
" v.append(float(sndObject._dataDict[time][lvl][parm]))\n",
" else:\n",
" print(\"WHAT IS THIS\")\n",
" print(sndObject._dataDict[time][lvl][parm])\n",
" # Pressure is our requested level rather than a returned parameter\n",
" p.append(float(lvl.replace('MB','')))\n",
"\n",
" # convert to numpy.array()\n",
" p = np.array(p, dtype=float)\n",
" t = (np.array(t, dtype=float) - 273.15) * units.degC\n",
" d = (np.array(d, dtype=float) - 273.15) * units.degC\n",
" u = (np.array(u, dtype=float) * units('m/s')).to('knots')\n",
" v = (np.array(v, dtype=float) * units('m/s')).to('knots')\n",
" w = np.sqrt(u**2 + v**2)\n",
"\n",
" print(\"Using \" + str(len(levels)) + \" levels between \" + \n",
" str(\"%.1f\" % max(p)) + \" and \" + str(\"%.1f\" % min(p)) + \"MB\")\n",
"\n",
" # Skew-T\n",
" plt.rcParams['figure.figsize'] = (12, 14)\n",
" skew = SkewT(rotation=45)\n",
" skew.plot(p, t, 'r', linewidth=2)\n",
" skew.plot(p, d, 'g', linewidth=2)\n",
" skew.plot_barbs(p, u, v)\n",
" skew.plot_dry_adiabats()\n",
" skew.plot_moist_adiabats()\n",
" skew.plot_mixing_lines(linestyle=':')\n",
" skew.ax.set_ylim(1000, 100)\n",
" skew.ax.set_xlim(-50, 40)\n",
" # Title\n",
" plt.title( modelName + \" (\" + str(point) + \") \" + str(time.getRefTime()))\n",
" # Hodograph\n",
" ax_hod = inset_axes(skew.ax, '40%', '40%', loc=2)\n",
" h = Hodograph(ax_hod, component_range=max(w.magnitude))\n",
" h.add_grid(increment=20)\n",
" h.plot_colormapped(u, v, w)\n",
" # Dotted line at 0C isotherm\n",
" l = skew.ax.axvline(0, color='c', linestyle='-', linewidth=1)\n",
" plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.5"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": true,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": true,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": true
}
},
"nbformat": 4,
"nbformat_minor": 1
}