{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Met Office UKV high-resolution atmosphere model data" ] }, { "cell_type": "markdown", "metadata": { "tags": [ "target/urban", "theme/exploration", "track/regular", "kernel/python" ] }, "source": [ "## Context\n", "### Purpose\n", "To load, plot, regrid and extract an urban region from the UKV gridded model data using the [Iris package](https://scitools-iris.readthedocs.io/en/stable/).\n", "\n", "### Sensor description\n", "Met Office UKV model data is fairly high resolution (approximately 1 km horizontal) and available over the whole of the UK for a variety of atmospheric variables at surface and pressure levels. A selection of variables has been\n", "made openly available as part of the Met Office contribution to the COVID 19 modelling effort {cite:p}`MetOffice2020`.\n", "\n", "This notebook uses a single sample data file for 1.5 m temperature included with the notebook.\n", "\n", "### Highlights\n", "* Data for the whole UK is loaded and plotted using Iris\n", "* Data is regridded to a geographic projection \n", "* A region over London is extracted\n", "\n", "### Contributions\n", "\n", "#### Dataset originator/creator\n", "* Met Office Informatics Lab (creator)\n", "* Microsoft (support)\n", "* European Regional Development Fund (support)\n", "\n", "#### Dataset authors\n", "* Met Office\n", "\n", ":::{important}\n", "Note this data should be used only for non-commercial purposes.\n", ":::" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Install and load libraries" ] }, { "cell_type": "code", "metadata": { "execution": { "iopub.execute_input": "2025-01-13T13:52:05.690239Z", "iopub.status.busy": "2025-01-13T13:52:05.690062Z", "iopub.status.idle": "2025-01-13T13:52:06.739341Z", "shell.execute_reply": "2025-01-13T13:52:06.738679Z" }, "tags": [ "hide-input" ] }, "source": [ "import os\n", "import iris\n", "import iris.analysis\n", "import iris.plot as iplt\n", "from iris.coords import DimCoord\n", "from iris.coord_systems import GeogCS\n", "from iris.cube import Cube\n", "\n", "from iris.fileformats.pp import EARTH_RADIUS\n", "\n", "import requests\n", "import urllib.request\n", "import pooch\n", "\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "import warnings\n", "warnings.filterwarnings(action='ignore')\n", "\n", "%matplotlib inline" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Set project structure" ] }, { "cell_type": "code", "metadata": { "execution": { "iopub.execute_input": "2025-01-13T13:52:06.742532Z", "iopub.status.busy": "2025-01-13T13:52:06.742021Z", "iopub.status.idle": "2025-01-13T13:52:06.745343Z", "shell.execute_reply": "2025-01-13T13:52:06.744795Z" } }, "source": [ "notebook_folder = './notebook'\n", "if not os.path.exists(notebook_folder):\n", " os.makedirs(notebook_folder)" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Retrieve and load a sample data file" ] }, { "cell_type": "code", "metadata": { "execution": { "iopub.execute_input": "2025-01-13T13:52:06.747879Z", "iopub.status.busy": "2025-01-13T13:52:06.747641Z", "iopub.status.idle": "2025-01-13T13:52:11.100060Z", "shell.execute_reply": "2025-01-13T13:52:11.099483Z" } }, "source": [ "filepath = 'https://metdatasa.blob.core.windows.net/covid19-response-non-commercial/metoffice_ukv_daily/t1o5m_mean/'\n", "filename = 'ukv_daily_t1o5m_mean_20150801.nc'\n", "\n", "response = requests.get(filepath+filename)\n", "if response.status_code == 200:\n", " urllib.request.urlretrieve(filepath+filename, os.path.join(notebook_folder, filename))\n", "else:\n", " pooch.retrieve(\n", " url=\"doi:10.5281/zenodo.7087009/ukv_daily_t1o5m_mean_20150801.nc\",\n", " known_hash=\"md5:b71e092ead092f419f12073ddf2d3256\",\n", " path=notebook_folder,\n", " fname=\"ukv_daily_t1o5m_mean_20150801.nc\"\n", " )" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "metadata": { "execution": { "iopub.execute_input": "2025-01-13T13:52:11.102631Z", "iopub.status.busy": "2025-01-13T13:52:11.102437Z", "iopub.status.idle": "2025-01-13T13:52:11.165874Z", "shell.execute_reply": "2025-01-13T13:52:11.165087Z" } }, "source": [ "air_temp = iris.load_cube(os.path.join(notebook_folder, filename))\n", "air_temp.coord('grid_latitude').guess_bounds()\n", "air_temp.coord('grid_longitude').guess_bounds()" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Visualisation\n", "\n", "Here we use the Iris wrapper to matplotlib pyplot to plot the gridded data with added gridlines and coastline." ] }, { "cell_type": "code", "metadata": { "execution": { "iopub.execute_input": "2025-01-13T13:52:11.168919Z", "iopub.status.busy": "2025-01-13T13:52:11.168708Z", "iopub.status.idle": "2025-01-13T13:52:17.469713Z", "shell.execute_reply": "2025-01-13T13:52:17.469085Z" }, "tags": [ "hide-input" ] }, "source": [ "plt.figure(figsize=(30, 10))\n", "iplt.pcolormesh(air_temp)\n", "plt.title(\"UKV Air temperature\", fontsize=\"xx-large\")\n", "cbar = plt.colorbar()\n", "cbar.set_label('Temperature (' + str(air_temp.units) + ')')\n", "ax = plt.gca()\n", "ax.coastlines(resolution=\"50m\")\n", "ax.gridlines()" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Regridding from Azimuthal equal-area projection to geographic" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Create a target cube with a lat-lon coord system for regrid\n", "\n", "It is filled with random data so we can plot it to check it looks correct." ] }, { "cell_type": "code", "metadata": { "execution": { "iopub.execute_input": "2025-01-13T13:52:17.473841Z", "iopub.status.busy": "2025-01-13T13:52:17.473465Z", "iopub.status.idle": "2025-01-13T13:52:17.489392Z", "shell.execute_reply": "2025-01-13T13:52:17.488913Z" } }, "source": [ "latitude = DimCoord(np.linspace(48.5, 59.5, 1222),\n", " standard_name='latitude',\n", " coord_system = GeogCS(EARTH_RADIUS),\n", " units='degrees')\n", "longitude = DimCoord(np.linspace(-10.5, 2.0, 1389),\n", " standard_name='longitude',\n", " coord_system = GeogCS(EARTH_RADIUS), \n", " units='degrees')\n", "global_cube = Cube(np.random.uniform(low=0.0, high=1.0, size=(1222, 1389)),\n", " dim_coords_and_dims=[(latitude, 0),\n", " (longitude, 1)])\n", "\n", "global_cube.coord('latitude').guess_bounds()\n", "global_cube.coord('longitude').guess_bounds()" ], "outputs": [], "execution_count": null }, { "cell_type": "code", "metadata": { "execution": { "iopub.execute_input": "2025-01-13T13:52:17.491652Z", "iopub.status.busy": "2025-01-13T13:52:17.491351Z", "iopub.status.idle": "2025-01-13T13:52:19.395379Z", "shell.execute_reply": "2025-01-13T13:52:19.394652Z" }, "tags": [ "hide-input" ] }, "source": [ "plt.figure(figsize=(30, 10))\n", "iplt.pcolormesh(global_cube)\n", "plt.title(\"Target global cube\", fontsize=\"xx-large\")\n", "ax = plt.gca()\n", "ax.coastlines(resolution=\"50m\")\n", "ax.gridlines()" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Perform the regridding from source data cube to target cube" ] }, { "cell_type": "code", "metadata": { "execution": { "iopub.execute_input": "2025-01-13T13:52:19.410499Z", "iopub.status.busy": "2025-01-13T13:52:19.409925Z", "iopub.status.idle": "2025-01-13T13:52:19.841735Z", "shell.execute_reply": "2025-01-13T13:52:19.841077Z" } }, "source": [ "# Note we need to use extrapolation masking in case regridded source data is actually smaller\n", "# than the target cube extents\n", "global_air_temp = air_temp.regrid(global_cube, iris.analysis.Linear(extrapolation_mode=\"mask\"))" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Plot the regridded data to check it is correct" ] }, { "cell_type": "code", "metadata": { "execution": { "iopub.execute_input": "2025-01-13T13:52:19.844664Z", "iopub.status.busy": "2025-01-13T13:52:19.844319Z", "iopub.status.idle": "2025-01-13T13:52:21.429659Z", "shell.execute_reply": "2025-01-13T13:52:21.429028Z" }, "tags": [ "hide-input" ] }, "source": [ "plt.figure(figsize=(30, 10))\n", "\n", "iplt.pcolormesh(global_air_temp)\n", "plt.title(\"UKV Air temperature on a global grid\", fontsize=\"xx-large\")\n", "cbar = plt.colorbar()\n", "cbar.set_label('Temperature (' + str(global_air_temp.units) + ')')\n", "ax = plt.gca()\n", "ax.coastlines(resolution=\"50m\")\n", "ax.gridlines()" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Extract the London Region\n", "\n", "### Use the Iris Intersection method and supply the region lat-lon bounds" ] }, { "cell_type": "code", "metadata": { "execution": { "iopub.execute_input": "2025-01-13T13:52:21.433828Z", "iopub.status.busy": "2025-01-13T13:52:21.433476Z", "iopub.status.idle": "2025-01-13T13:52:21.442190Z", "shell.execute_reply": "2025-01-13T13:52:21.441571Z" } }, "source": [ "min_lon = -0.52\n", "min_lat = 51.3\n", "max_lon = 0.3\n", "max_lat = 51.7\n", "\n", "air_temp_london = global_air_temp.intersection(longitude=(min_lon, max_lon), latitude=(min_lat, max_lat))" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Plot the results" ] }, { "cell_type": "code", "metadata": { "execution": { "iopub.execute_input": "2025-01-13T13:52:21.444631Z", "iopub.status.busy": "2025-01-13T13:52:21.444281Z", "iopub.status.idle": "2025-01-13T13:52:21.582441Z", "shell.execute_reply": "2025-01-13T13:52:21.581789Z" }, "tags": [ "hide-input" ] }, "source": [ "plt.figure(figsize=(20, 5))\n", "\n", "iplt.pcolormesh(air_temp_london)\n", "plt.title(\"UKV Air temperature for london\", fontsize=\"xx-large\")\n", "cbar = plt.colorbar()\n", "cbar.set_label('Temperature (' + str(air_temp_london.units) + ')')\n", "ax = plt.gca()\n", "ax.coastlines(resolution=\"50m\")\n", "ax.gridlines()\n", "\n", "plt.show()" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Save as a new NetCDF file" ] }, { "cell_type": "code", "metadata": { "execution": { "iopub.execute_input": "2025-01-13T13:52:21.584918Z", "iopub.status.busy": "2025-01-13T13:52:21.584539Z", "iopub.status.idle": "2025-01-13T13:52:21.596446Z", "shell.execute_reply": "2025-01-13T13:52:21.595816Z" } }, "source": [ "iris.save(air_temp_london, os.path.join(notebook_folder,'ukv_london_sample.nc'))" ], "outputs": [], "execution_count": null }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Summary\n", "\n", "This notebook has demonstrated the use of the `Iris` package to easily load, plot and manipulate gridded environmental NetCDF data." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Citing this Notebook" ] }, { "cell_type": "markdown", "metadata": {}, "source": "Please see [CITATION.cff](https://github.com/eds-book/1b8921af-e77f-4ccf-ae38-4813cdceba0f/blob/main/CITATION.cff) for the full citation information. The citation file can be exported to APA or BibTex formats (learn more [here](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-citation-files))." }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Additional information\n", "\n", "**Review**: This notebook has been reviewed by one or more members of the Environmental Data Science book community. The open review is available [here](https://github.com/alan-turing-institute/environmental-ds-book/pull/3).\n", "\n", "**License**: The code in this notebook is licensed under the MIT License. The Environmental Data Science book is licensed under the Creative Commons by Attribution 4.0 license. See further details [here](https://github.com/alan-turing-institute/environmental-ds-book/blob/main/LICENSE).\n", "\n", "**Contact**: If you have any suggestion or report an issue with this notebook, feel free to [create an issue](https://github.com/alan-turing-institute/environmental-ds-book/issues/new/choose) or send a direct message to [environmental.ds.book@gmail.com](mailto:environmental.ds.book@gmail.com)." ] }, { "cell_type": "code", "metadata": { "execution": { "iopub.execute_input": "2025-01-13T13:52:21.599053Z", "iopub.status.busy": "2025-01-13T13:52:21.598684Z", "iopub.status.idle": "2025-01-13T13:52:21.601864Z", "shell.execute_reply": "2025-01-13T13:52:21.601302Z" }, "tags": [ "remove-input" ] }, "source": [ "from datetime import date\n", "\n", "print('Notebook repository version: v2025.6.0')\n", "print(f'Last tested: {date.today()}')" ], "outputs": [], "execution_count": null } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.19" }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 4 }