{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# PMV Storm Surge Alert Feed Generator\n", "\n", "Notebook to generate `pmv.xml` feed while `nowcast.workers.make_feeds`\n", "worker is in development." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import datetime\n", "import os\n", "from pprint import pprint\n", "\n", "import arrow\n", "import docutils.core\n", "from feedgen.feed import FeedGenerator\n", "import mako.template\n", "import netCDF4 as nc\n", "import numpy as np\n", "\n", "from salishsea_tools import (\n", " nc_tools,\n", " stormtools,\n", " unit_conversions,\n", " wind_tools,\n", ")\n", "from salishsea_tools.places import PLACES\n", "\n", "from nowcast import figures" ] }, { "cell_type": "code", "execution_count": 67, "metadata": { "collapsed": false }, "outputs": [], "source": [ "!sshfs skookum:/results results" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'forecast2/28dec15'" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "today = arrow.now('Canada/Pacific').floor('day')\n", "forecast = 'forecast2'\n", "run_date = today if forecast == 'forecast' else today.replace(days=-1)\n", "os.path.join(forecast, run_date.format('DDMMMYY').lower())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Calculating the Values to use in the Template\n", "\n", "The `nowcast.figures.plot_threshold_website()` has code\n", "(reproduced below) that calculates:\n", "* The maximum sea surface height in a `grid_T` run results file\n", "* The time at which it occurs" ] }, { "cell_type": "code", "execution_count": 69, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from importlib import reload\n", "reload(figures)\n", "reload(nc_tools)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "results/SalishSea/forecast2/28dec15/PointAtkinson.nc\n" ] } ], "source": [ "tide_gauge_stn = 'Point Atkinson'\n", "results_file = ('results/SalishSea/{forecast}/{dmy}/{}.nc'\n", " .format(tide_gauge_stn.replace(' ', ''), forecast=forecast, dmy=run_date.format('DDMMMYY').lower()))\n", "print(results_file)\n", "grid_T_15m = nc.Dataset(results_file)\n", "tidal_predictions = 'results/nowcast-sys/tools/SalishSeaNowcast/nowcast/tidal_predictions/'\n", "\n", "ssh_model, t_model = nc_tools.ssh_timeseries_at_point(grid_T_15m, 0, 0, datetimes=True)\n", "ttide = figures.get_tides(tide_gauge_stn, tidal_predictions)\n", "ssh_corr = figures.correct_model_ssh(ssh_model, t_model, ttide)\n", "max_ssh = np.max(ssh_corr) + PLACES[tide_gauge_stn]['mean sea lvl']\n", "max_ssh_time = t_model[np.argmax(ssh_corr)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "From those results we can calculate:\n", "* Maximum water level above chart datum in metres\n", "* Date and time of the maximum water level with the appropriate timezone indicated" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(4.7553470341415407, )" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "max_ssh, arrow.get(max_ssh_time).to('local')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Formating the date/time would be easy if it weren't for adding the timezone name:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'Wed Dec 30, 2015 09:07 [PST]'" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = arrow.get(max_ssh_time).to('local')\n", "'{datetime} [{tzname}]'.format(datetime=a.format('ddd MMM DD, YYYY HH:mm'), tzname=a.tzinfo.tzname(a.datetime))" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'late Wednesday morning'" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "unit_conversions.humanize_time_of_day(a)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "None\n" ] } ], "source": [ "risk_level = stormtools.storm_surge_risk_level('Point Atkinson', max_ssh, ttide)\n", "print(risk_level)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "results/forcing/atmospheric/GEM2.5/operational/ops_y2015m12d28.nc\n", "16 2015-12-28T08:00:00-08:00\n", "1.2647 -1.66118\n" ] } ], "source": [ "weather_path = 'results/forcing/atmospheric/GEM2.5/operational/fcst'\n", "weather = nc.Dataset(os.path.join(weather_path, '{:ops_y%Ym%md%d.nc}'.format(max_ssh_time)))\n", "\n", "print(os.path.join(weather_path, '{:ops_y%Ym%md%d.nc}'.format(max_ssh_time)))\n", "\n", "wind = nc_tools.uv_wind_timeseries_at_point(weather, *PLACES[tide_gauge_stn]['wind grid ji'])\n", "\n", "i_max_ssh_wind = np.asscalar(\n", " np.where(\n", " wind.time == arrow.get(\n", " max_ssh_time.year, max_ssh_time.month, max_ssh_time.day, max_ssh_time.hour))[0])\n", "\n", "print(i_max_ssh_wind, wind.time[i_max_ssh_wind].to('local'))\n", "print(wind.u[i_max_ssh_wind], wind.v[i_max_ssh_wind])" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "speed_dir(speed=2.0878163440105673, dir=307.28294024987326)" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wind_tools.wind_speed_dir(wind.u[i_max_ssh_wind], wind.v[i_max_ssh_wind])" ] }, { "cell_type": "code", "execution_count": 58, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(-0.64741606, -2.1173892)" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u_wind_4h_avg = np.mean(wind.u[max(i_max_ssh_wind-4, 0):i_max_ssh_wind])\n", "v_wind_4h_avg = np.mean(wind.v[max(i_max_ssh_wind-4, 0):i_max_ssh_wind])\n", "\n", "u_wind_4h_avg, v_wind_4h_avg" ] }, { "cell_type": "code", "execution_count": 59, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(2.2141555008127836, 252.99838623617447)" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wind_speed_4h_avg, wind_dir_4h_avg = wind_tools.wind_speed_dir(u_wind_4h_avg, v_wind_4h_avg)\n", "\n", "wind_speed_4h_avg, wind_dir_4h_avg" ] }, { "cell_type": "code", "execution_count": 60, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(7.9709598029260214, 4.3039739756619984)" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "unit_conversions.mps_kph(wind_speed_4h_avg), unit_conversions.mps_knots(wind_speed_4h_avg)" ] }, { "cell_type": "code", "execution_count": 61, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "17.001613763825532" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "unit_conversions.wind_to_from(wind_dir_4h_avg)" ] }, { "cell_type": "code", "execution_count": 62, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'NNE'" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "unit_conversions.bearing_heading(unit_conversions.wind_to_from(wind_dir_4h_avg))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Rendering the Template for the `summary` Element\n", "\n", "We'll start with a reStructuredText template based on `SalishSeaNowcast/nowcast/www/templates/surgetext.mako`:" ] }, { "cell_type": "code", "execution_count": 63, "metadata": { "collapsed": false }, "outputs": [], "source": [ "max_ssh_time_local = arrow.get(max_ssh_time).to('local')\n", "values = {\n", " 'city': 'Vancouver',\n", " 'tide_gauge_stn': 'Point Atkinson',\n", " 'conditions': {\n", " 'Point Atkinson': {\n", " 'risk_level': risk_level,\n", " 'max_ssh_msl': max_ssh,\n", " 'wind_speed_4h_avg_kph': unit_conversions.mps_kph(wind_speed_4h_avg),\n", " 'wind_speed_4h_avg_knots': unit_conversions.mps_knots(wind_speed_4h_avg),\n", " 'wind_dir_4h_avg_heading':unit_conversions.bearing_heading(\n", " unit_conversions.wind_to_from(wind_dir_4h_avg)),\n", " 'wind_dir_4h_avg_bearing': unit_conversions.wind_to_from(wind_dir_4h_avg),\n", " 'max_ssh_time': max_ssh_time_local,\n", " 'max_ssh_time_tzname': max_ssh_time_local.tzinfo.tzname(max_ssh_time_local.datetime),\n", " 'humanized_max_ssh_time': unit_conversions.humanize_time_of_day(max_ssh_time_local),\n", " },\n", " },\n", "}" ] }, { "cell_type": "code", "execution_count": 64, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(\"\\n\"\n", " '\\n'\n", " ' '\n", " 'tag:salishsea.eos.ubc.ca,2015-12-12:/storm-surge/atom/pmv/20151229183330\\n'\n", " ' Salish Sea NEMO Model Storm Surge Alerts for Port Metro '\n", " 'Vancouver\\n'\n", " ' 2015-12-29T18:33:30.766968+00:00\\n'\n", " ' \\n'\n", " ' Salish Sea MEOPAR Project\\n'\n", " ' http://salishsea.eos.ubc.ca/\\n'\n", " ' \\n'\n", " ' \\n'\n", " ' \\n'\n", " ' python-feedgen\\n'\n", " ' Copyright 2015, Salish Sea MEOPAR Project Contributors and The '\n", " 'University of British Columbia\\n'\n", " '\\n')\n" ] } ], "source": [ "fg = FeedGenerator()\n", "\n", "utcnow = arrow.utcnow()\n", "\n", "fg.title('Salish Sea NEMO Model Storm Surge Alerts for Port Metro Vancouver')\n", "fg.id(\n", " 'tag:salishsea.eos.ubc.ca,2015-12-12:/storm-surge/atom/pmv/{utcnow}'\n", " .format(utcnow=utcnow.format('YYYYMMDDHHmmss')))\n", "fg.language('en-ca')\n", "fg.author(name='Salish Sea MEOPAR Project', uri='http://salishsea.eos.ubc.ca/')\n", "fg.rights(\n", " 'Copyright {this_year}, Salish Sea MEOPAR Project Contributors and The University of British Columbia'\n", " .format(this_year=utcnow.year))\n", "fg.link(href='http://salishsea.eos.ubc.ca/storm-surge/atom/pmv.xml', rel='self', type='application/atom+xml')\n", "fg.link(href='http://salishsea.eos.ubc.ca/storm-surge/forecast.html', rel='related', type='text/html')\n", "\n", "if risk_level is not None:\n", " rendered_rst = mako.template.Template(\n", " filename='../../tools/SalishSeaNowcast/nowcast/www/templates/storm_surge_advisory.mako').render(**values)\n", " html = docutils.core.publish_parts(rendered_rst, writer_name='html')\n", " now = arrow.now()\n", " \n", " fe = fg.add_entry()\n", " fe.title('Storm Surge Alert for Point Atkinson')\n", " fe.id(\n", " 'tag:salishsea.eos.ubc.ca,{today}:/storm-surge/atom/pmv/{now}'\n", " .format(\n", " today=now.format('YYYY-MM-DD'),\n", " now=now.format('YYYYMMDDHHmmss')))\n", " fe.author(name='Salish Sea MEOPAR Project', uri='http://salishsea.eos.ubc.ca/')\n", " fe.content(html['body'], type='html')\n", " fe.link(\n", " rel='alternate', type='text/html',\n", " href='http://salishsea.eos.ubc.ca/nemo/results/{forecast}/publish_{day}.html'\n", " .format(forecast=forecast, day=today.replace(days=+1).format('DDMMMYY').lower()), \n", " )\n", "\n", "pprint(fg.atom_str(pretty=True).decode('utf8'))" ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "collapsed": true }, "outputs": [], "source": [ "fg.atom_file('pmv.xml', pretty=True)" ] }, { "cell_type": "code", "execution_count": 66, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\r", "pmv.xml 0% 0 0.0KB/s --:-- ETA\r", "pmv.xml 100% 818 0.8KB/s 00:00 \r\n" ] } ], "source": [ "!scp pmv.xml skookum:public_html/MEOPAR/nowcast/www/salishsea-site/site/storm-surge/atom/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On `skookum`:\n", "```\n", "scp /home/dlatorne/public_html/MEOPAR/nowcast/www/salishsea-site/site/storm-surge/atom/pmv.xml shelob:/www/salishsea/data/storm-surge/atom/\n", "```" ] } ], "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.5.1" } }, "nbformat": 4, "nbformat_minor": 0 }