diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
deleted file mode 100644
index 95ed0dd..0000000
--- a/.pre-commit-config.yaml
+++ /dev/null
@@ -1,25 +0,0 @@
-# See https://pre-commit.com for more information
-# See https://pre-commit.com/hooks.html for more hooks
-repos:
-- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v3.2.0
- hooks:
- - id: trailing-whitespace
- - id: end-of-file-fixer
- - id: check-yaml
- - id: check-added-large-files
- - id: check-ast
- - id: check-case-conflict
- - id: check-json
- - id: check-merge-conflict
- - id: mixed-line-ending
- - id: requirements-txt-fixer
- - id: trailing-whitespace
-- repo: https://github.com/psf/black
- rev: 23.7.0
- hooks:
- - id: black
- - id: black-jupyter
-
-default_language_version:
- python: python3.9
diff --git a/QRcode.png b/QRcode.png
deleted file mode 100644
index a862eaa..0000000
Binary files a/QRcode.png and /dev/null differ
diff --git a/notebooks/access-analyse_temperature.ipynb b/notebooks/access-analyse_temperature.ipynb
deleted file mode 100644
index b073366..0000000
--- a/notebooks/access-analyse_temperature.ipynb
+++ /dev/null
@@ -1,3982 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "id": "b4ea1def-a0b9-4130-9343-dd53fc4c77d3",
- "metadata": {},
- "source": [
- "# Accessing data on Object Store from any platform"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "47e738cd-2b6f-474c-b269-30ebbd48f88d",
- "metadata": {},
- "source": [
- "## Objective: The purpose of this notebook is to demonstrate how to access data stored on Object Storage.\n",
- "### This notebook will work on three different platforms (DataLabs, JASMIN Notebook Service and Google Colab). To use this notebook please select the following python environments:\n",
- "- DataLabs: Python 3 (ipykernel)\n",
- "- JASMIN Notebook Service: Python 3 + Jaspy\n",
- "- Google Colab*: Default environment\n",
- "*For running this notebook in Google Colab, please remember to create a copy of the notebook before running it. Then the associated catalogue yaml (catalogue_temperature.yaml) file should be uploaded to the file system, otherwise the notebook will fail."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "59778028-179e-4ac9-a3b3-7c4bfa05708b",
- "metadata": {},
- "source": [
- "## Install the required packages\n",
- "### Install the required packages using the following command after selecting the basic python3 envionments listed in the cell above based on the platform you are using. Although we do not set up virtual environment for this notebook, if needed, please read the following links for more details on setting up virtual environments on the different platforms:\n",
- "- DataLabs: https://datalab-docs.datalabs.ceh.ac.uk/tutorials/getting-started-jupyter/create-conda-environment.html\n",
- "- JASMIN Notebook Service: https://help.jasmin.ac.uk/article/5084-creating-a-virtual-environment-in-the-jasmin-notebooks-service\n",
- "- Google Colab: https://colab.research.google.com/drive/1Vg005uKhgt-ZwyQ11-BGceqY0q07qIzF"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "ba44868a-8e67-4489-9253-fdf866a3bbfa",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Requirement already satisfied: s3fs in /opt/conda/lib/python3.9/site-packages (2023.10.0)\n",
- "Requirement already satisfied: zarr in /opt/conda/lib/python3.9/site-packages (2.16.1)\n",
- "Requirement already satisfied: intake in /opt/conda/lib/python3.9/site-packages (0.7.0)\n",
- "Requirement already satisfied: intake-xarray in /opt/conda/lib/python3.9/site-packages (0.7.0)\n",
- "Requirement already satisfied: fsspec==2023.10.0 in /opt/conda/lib/python3.9/site-packages (from s3fs) (2023.10.0)\n",
- "Requirement already satisfied: aiohttp!=4.0.0a0,!=4.0.0a1 in /opt/conda/lib/python3.9/site-packages (from s3fs) (3.7.4.post0)\n",
- "Requirement already satisfied: aiobotocore~=2.7.0 in /opt/conda/lib/python3.9/site-packages (from s3fs) (2.7.0)\n",
- "Requirement already satisfied: numpy!=1.21.0,>=1.20 in /opt/conda/lib/python3.9/site-packages (from zarr) (1.26.1)\n",
- "Requirement already satisfied: fasteners in /opt/conda/lib/python3.9/site-packages (from zarr) (0.19)\n",
- "Requirement already satisfied: numcodecs>=0.10.0 in /opt/conda/lib/python3.9/site-packages (from zarr) (0.12.1)\n",
- "Requirement already satisfied: asciitree in /opt/conda/lib/python3.9/site-packages (from zarr) (0.3.3)\n",
- "Requirement already satisfied: pyyaml in /opt/conda/lib/python3.9/site-packages (from intake) (5.4.1)\n",
- "Requirement already satisfied: entrypoints in /opt/conda/lib/python3.9/site-packages (from intake) (0.3)\n",
- "Requirement already satisfied: appdirs in /opt/conda/lib/python3.9/site-packages (from intake) (1.4.4)\n",
- "Requirement already satisfied: jinja2 in /opt/conda/lib/python3.9/site-packages (from intake) (3.0.1)\n",
- "Requirement already satisfied: requests in /opt/conda/lib/python3.9/site-packages (from intake) (2.26.0)\n",
- "Requirement already satisfied: msgpack in /opt/conda/lib/python3.9/site-packages (from intake) (1.0.2)\n",
- "Requirement already satisfied: dask in /opt/conda/lib/python3.9/site-packages (from intake) (2021.6.2)\n",
- "Requirement already satisfied: xarray>=02022 in /opt/conda/lib/python3.9/site-packages (from intake-xarray) (2023.10.1)\n",
- "Requirement already satisfied: netcdf4 in /opt/conda/lib/python3.9/site-packages (from intake-xarray) (1.6.5)\n",
- "Requirement already satisfied: botocore<1.31.65,>=1.31.16 in /opt/conda/lib/python3.9/site-packages (from aiobotocore~=2.7.0->s3fs) (1.31.64)\n",
- "Requirement already satisfied: wrapt<2.0.0,>=1.10.10 in /opt/conda/lib/python3.9/site-packages (from aiobotocore~=2.7.0->s3fs) (1.15.0)\n",
- "Requirement already satisfied: aioitertools<1.0.0,>=0.5.1 in /opt/conda/lib/python3.9/site-packages (from aiobotocore~=2.7.0->s3fs) (0.11.0)\n",
- "Requirement already satisfied: async-timeout<4.0,>=3.0 in /opt/conda/lib/python3.9/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs) (3.0.1)\n",
- "Requirement already satisfied: attrs>=17.3.0 in /opt/conda/lib/python3.9/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs) (21.2.0)\n",
- "Requirement already satisfied: typing-extensions>=3.6.5 in /opt/conda/lib/python3.9/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs) (4.8.0)\n",
- "Requirement already satisfied: chardet<5.0,>=2.0 in /opt/conda/lib/python3.9/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs) (4.0.0)\n",
- "Requirement already satisfied: multidict<7.0,>=4.5 in /opt/conda/lib/python3.9/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs) (5.1.0)\n",
- "Requirement already satisfied: yarl<2.0,>=1.0 in /opt/conda/lib/python3.9/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs) (1.6.3)\n",
- "Requirement already satisfied: python-dateutil<3.0.0,>=2.1 in /opt/conda/lib/python3.9/site-packages (from botocore<1.31.65,>=1.31.16->aiobotocore~=2.7.0->s3fs) (2.8.2)\n",
- "Requirement already satisfied: urllib3<1.27,>=1.25.4 in /opt/conda/lib/python3.9/site-packages (from botocore<1.31.65,>=1.31.16->aiobotocore~=2.7.0->s3fs) (1.26.7)\n",
- "Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /opt/conda/lib/python3.9/site-packages (from botocore<1.31.65,>=1.31.16->aiobotocore~=2.7.0->s3fs) (1.0.1)\n",
- "Requirement already satisfied: cloudpickle>=1.1.1 in /opt/conda/lib/python3.9/site-packages (from dask->intake) (2.0.0)\n",
- "Requirement already satisfied: partd>=0.3.10 in /opt/conda/lib/python3.9/site-packages (from dask->intake) (1.2.0)\n",
- "Requirement already satisfied: toolz>=0.8.2 in /opt/conda/lib/python3.9/site-packages (from dask->intake) (0.11.1)\n",
- "Requirement already satisfied: locket in /opt/conda/lib/python3.9/site-packages (from partd>=0.3.10->dask->intake) (0.2.0)\n",
- "Requirement already satisfied: six>=1.5 in /opt/conda/lib/python3.9/site-packages (from python-dateutil<3.0.0,>=2.1->botocore<1.31.65,>=1.31.16->aiobotocore~=2.7.0->s3fs) (1.16.0)\n",
- "Requirement already satisfied: packaging>=21.3 in /opt/conda/lib/python3.9/site-packages (from xarray>=02022->intake-xarray) (23.2)\n",
- "Requirement already satisfied: pandas>=1.4 in /opt/conda/lib/python3.9/site-packages (from xarray>=02022->intake-xarray) (2.1.2)\n",
- "Requirement already satisfied: tzdata>=2022.1 in /opt/conda/lib/python3.9/site-packages (from pandas>=1.4->xarray>=02022->intake-xarray) (2023.3)\n",
- "Requirement already satisfied: pytz>=2020.1 in /opt/conda/lib/python3.9/site-packages (from pandas>=1.4->xarray>=02022->intake-xarray) (2021.1)\n",
- "Requirement already satisfied: idna>=2.0 in /opt/conda/lib/python3.9/site-packages (from yarl<2.0,>=1.0->aiohttp!=4.0.0a0,!=4.0.0a1->s3fs) (3.1)\n",
- "Requirement already satisfied: MarkupSafe>=2.0 in /opt/conda/lib/python3.9/site-packages (from jinja2->intake) (2.0.1)\n",
- "Requirement already satisfied: certifi in /opt/conda/lib/python3.9/site-packages (from netcdf4->intake-xarray) (2021.5.30)\n",
- "Requirement already satisfied: cftime in /opt/conda/lib/python3.9/site-packages (from netcdf4->intake-xarray) (1.6.3)\n",
- "Requirement already satisfied: charset-normalizer~=2.0.0 in /opt/conda/lib/python3.9/site-packages (from requests->intake) (2.0.0)\n"
- ]
- }
- ],
- "source": [
- "!pip install s3fs zarr intake intake-xarray"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "c662e77a-6941-4192-aabf-dc7e93888e08",
- "metadata": {},
- "source": [
- "## Import the required packages"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "6c717597-94d8-4cc2-a43b-d984667b6bde",
- "metadata": {},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "/opt/conda/lib/python3.9/site-packages/pandas/core/computation/expressions.py:21: UserWarning: Pandas requires version '2.8.0' or newer of 'numexpr' (version '2.7.3' currently installed).\n",
- " from pandas.core.computation.check import NUMEXPR_INSTALLED\n",
- "/opt/conda/lib/python3.9/site-packages/pandas/core/arrays/masked.py:62: UserWarning: Pandas requires version '1.3.4' or newer of 'bottleneck' (version '1.3.2' currently installed).\n",
- " from pandas.core import (\n"
- ]
- }
- ],
- "source": [
- "import numpy as np\n",
- "import pandas as pd\n",
- "import intake\n",
- "import intake_xarray\n",
- "import s3fs\n",
- "import xarray as xr\n",
- "from datetime import datetime\n",
- "import io\n",
- "import json\n",
- "import requests\n",
- "import zipfile\n",
- "import matplotlib.pyplot as plt"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "08a62618-b340-47f6-ac90-516c775c1076",
- "metadata": {},
- "source": [
- "## Accessing Station Observations\n",
- "### We will be accessing observed variable of Daily Maximum Temperature Air (TA_MAX) from 2016--2022 for one of the COSMOS station (ALIC1) directly from COSMOS API"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "6f95e0fe-c687-4571-b7ea-7c7ede3bb33b",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Pre-written functions for accessing COSMOS data.\n",
- "# Please see https://cosmos-api.ceh.ac.uk/python_examples for code examples\n",
- "# Please see https://cosmos-api.ceh.ac.uk/docs for more details\n",
- "\n",
- "\n",
- "def get_api_response(url, csv=False):\n",
- " \"\"\"Helper function to send request to API and get the response\n",
- "\n",
- " :param str url: The URL of the API request\n",
- " :param bool csv: Whether this is a CSV request. Default False.\n",
- " :return: API response\n",
- " \"\"\"\n",
- " # Send request and read response\n",
- " print(url)\n",
- " response = requests.get(url)\n",
- "\n",
- " if csv:\n",
- " return response\n",
- " else:\n",
- " # Decode from JSON to Python dictionary\n",
- " return json.loads(response.content)\n",
- "\n",
- "\n",
- "def get_collection_parameter_info(params):\n",
- " \"\"\"A function for wrangling the collection information into a more visually appealing format!\"\"\"\n",
- " df = pd.DataFrame.from_dict(params)\n",
- " df = df.T[[\"label\", \"description\", \"unit\", \"sensorInfo\"]]\n",
- "\n",
- " df[\"unit_symbol\"] = df[\"unit\"].apply(lambda x: x[\"symbol\"][\"value\"])\n",
- " df[\"unit_label\"] = df[\"unit\"].apply(lambda x: x[\"label\"])\n",
- " df[\"sensor_depth\"] = df[\"sensorInfo\"].apply(\n",
- " lambda x: None if pd.isna(x) else x[\"sensor_depth\"][\"value\"]\n",
- " )\n",
- "\n",
- " df = df.drop([\"sensorInfo\", \"unit\"], axis=1)\n",
- "\n",
- " return df\n",
- "\n",
- "\n",
- "def format_datetime(dt):\n",
- " return dt.strftime(\"%Y-%m-%dT%H:%M:%SZ\")\n",
- "\n",
- "\n",
- "def read_json_collection_data(json_response):\n",
- " \"\"\"Wrangle the response JSON from a COSMOS-API data collection request into a more usable format - in this case a Pandas Dataframe\n",
- "\n",
- " :param dict json_response: The JSON response dictionary returned from a COSMOS-API data collection request\n",
- " :return: Dataframe of data\n",
- " :rtype: pd.DataFrame\n",
- " \"\"\"\n",
- " # The response is a list of dictionaries, one for each requested site\n",
- "\n",
- " # You can choose how you want to build your dataframes. Here, I'm just loading all stations into one big dataframe.\n",
- " # But you could modify this for your own use cases. For example you might want to build a dictionary of {site_id: dataframe}\n",
- " # to keep site data separate, etc.\n",
- " master_df = pd.DataFrame()\n",
- "\n",
- " for site_data in resp[\"coverages\"]:\n",
- " # Read the site ID\n",
- " site_id = site_data[\"dct:identifier\"]\n",
- "\n",
- " # Read the time stamps of each data point\n",
- " time_values = pd.DatetimeIndex(site_data[\"domain\"][\"axes\"][\"t\"][\"values\"])\n",
- "\n",
- " # Now read the values for each requested parameter at each of the time stamps\n",
- " param_values = {\n",
- " param_name: param_data[\"values\"]\n",
- " for param_name, param_data in site_data[\"ranges\"].items()\n",
- " }\n",
- "\n",
- " # And put everything into a dataframe\n",
- " site_df = pd.DataFrame.from_dict(param_values)\n",
- " site_df[\"datetime\"] = time_values\n",
- " site_df[\"site_id\"] = site_id\n",
- "\n",
- " site_df = site_df.set_index([\"datetime\", \"site_id\"])\n",
- " master_df = pd.concat([master_df, site_df])\n",
- "\n",
- " return master_df"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "b9429ffa-f17d-46d6-b0c9-ba70ecf7176d",
- "metadata": {},
- "outputs": [],
- "source": [
- "# We need to extract \"ta_max\" parameter for COSMOS station \"ALIC1\" over the period of 2016 -- 2022\n",
- "start_date = format_datetime(datetime(2016, 1, 1))\n",
- "end_date = format_datetime(datetime(2022, 12, 31))\n",
- "query_date_range = f\"{start_date}/{end_date}\"\n",
- "param_name = [\n",
- " \"ta_max\",\n",
- "]\n",
- "site_nm = \"ALIC1\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "id": "7a9d6405-f4a7-4774-aad8-76a155e4e92b",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "https://cosmos-api.ceh.ac.uk/collections/1D/locations\n"
- ]
- },
- {
- "data": {
- "text/html": [
- "
\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " \n",
- " site_name \n",
- " coordinates \n",
- " start_date \n",
- " end_date \n",
- " altitude \n",
- " bulk_density \n",
- " bulk_density_sd \n",
- " land_cover \n",
- " lattice_water \n",
- " lattice_water_sd \n",
- " soil_organic_carbon \n",
- " soil_organic_carbon_sd \n",
- " soil_type \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " ALIC1 \n",
- " Alice Holt \n",
- " [51.153551, -0.858232] \n",
- " 2015-03-06T13:30:00Z \n",
- " 2023-11-16T00:00:00Z \n",
- " 80.0 \n",
- " 0.84 \n",
- " None \n",
- " Broadleaf woodland \n",
- " 0.025 \n",
- " None \n",
- " 0.042 \n",
- " None \n",
- " Mineral soil \n",
- " \n",
- " \n",
- "
\n",
- "
"
- ],
- "text/plain": [
- " site_name coordinates start_date \\\n",
- "ALIC1 Alice Holt [51.153551, -0.858232] 2015-03-06T13:30:00Z \n",
- "\n",
- " end_date altitude bulk_density bulk_density_sd \\\n",
- "ALIC1 2023-11-16T00:00:00Z 80.0 0.84 None \n",
- "\n",
- " land_cover lattice_water lattice_water_sd soil_organic_carbon \\\n",
- "ALIC1 Broadleaf woodland 0.025 None 0.042 \n",
- "\n",
- " soil_organic_carbon_sd soil_type \n",
- "ALIC1 None Mineral soil "
- ]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# First we get the metadata for the COSMOS station\n",
- "BASE_URL = \"https://cosmos-api.ceh.ac.uk\"\n",
- "site_info_url = f\"{BASE_URL}/collections/1D/locations\"\n",
- "site_info_response = get_api_response(site_info_url)\n",
- "\n",
- "site_info = {}\n",
- "for site in site_info_response[\"features\"]:\n",
- " site_id = site[\"id\"]\n",
- " site_name = site[\"properties\"][\"label\"]\n",
- " coordinates = site[\"geometry\"][\"coordinates\"]\n",
- " date_range = site[\"properties\"][\"datetime\"]\n",
- " start_date, end_date = date_range.split(\"/\")\n",
- "\n",
- " other_info = site[\"properties\"][\"siteInfo\"]\n",
- " other_info = {key: d[\"value\"] for key, d in other_info.items()}\n",
- "\n",
- " site_info[site_id] = {\n",
- " \"site_name\": site_name,\n",
- " \"coordinates\": coordinates,\n",
- " \"start_date\": start_date,\n",
- " \"end_date\": end_date,\n",
- " } | other_info\n",
- "\n",
- "site_info_df = pd.DataFrame.from_dict(site_info).T\n",
- "s_df = site_info_df[site_info_df.index == site_nm]\n",
- "s_df"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "id": "35ca582f-63a5-4117-9032-c6cd19dccdda",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "COMOS Site ALIC1 Latitude: 51.153551 Longitude: -0.858232\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "/tmp/ipykernel_1224/733139797.py:3: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n",
- " site_latitude = s_df[\"coordinates\"][0][0]\n",
- "/tmp/ipykernel_1224/733139797.py:4: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n",
- " site_longitude = s_df[\"coordinates\"][0][1]\n"
- ]
- }
- ],
- "source": [
- "# Extracting the COSMOS station latitude and longitude from the whole metadata list\n",
- "# COSMOS station latitude and longitude is required to calculate the nearest grid point on the CHESS grid to extract corresponding model data\n",
- "site_latitude = s_df[\"coordinates\"][0][0]\n",
- "site_longitude = s_df[\"coordinates\"][0][1]\n",
- "print(\n",
- " \"COMOS Site \"\n",
- " + site_nm\n",
- " + \" Latitude: \"\n",
- " + str(site_latitude)\n",
- " + \" Longitude: \"\n",
- " + str(site_longitude)\n",
- ")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "id": "9730e8c6-a4e1-41ea-9d0e-7203a1d2a8ea",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "https://cosmos-api.ceh.ac.uk/collections/1D/locations/ALIC1?datetime=2016-01-01T00:00:00Z/2022-12-31T00:00:00Z¶meter-name=ta_max\n"
- ]
- },
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " \n",
- " datetime \n",
- " site_id \n",
- " ta_max \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " 0 \n",
- " 2016-01-01 00:00:00+00:00 \n",
- " ALIC1 \n",
- " 8.6 \n",
- " \n",
- " \n",
- " 1 \n",
- " 2016-01-02 00:00:00+00:00 \n",
- " ALIC1 \n",
- " 10.7 \n",
- " \n",
- " \n",
- " 2 \n",
- " 2016-01-03 00:00:00+00:00 \n",
- " ALIC1 \n",
- " 8.9 \n",
- " \n",
- " \n",
- " 3 \n",
- " 2016-01-04 00:00:00+00:00 \n",
- " ALIC1 \n",
- " 9.7 \n",
- " \n",
- " \n",
- " 4 \n",
- " 2016-01-05 00:00:00+00:00 \n",
- " ALIC1 \n",
- " 8.2 \n",
- " \n",
- " \n",
- " ... \n",
- " ... \n",
- " ... \n",
- " ... \n",
- " \n",
- " \n",
- " 2552 \n",
- " 2022-12-27 00:00:00+00:00 \n",
- " ALIC1 \n",
- " 10.3 \n",
- " \n",
- " \n",
- " 2553 \n",
- " 2022-12-28 00:00:00+00:00 \n",
- " ALIC1 \n",
- " 11.4 \n",
- " \n",
- " \n",
- " 2554 \n",
- " 2022-12-29 00:00:00+00:00 \n",
- " ALIC1 \n",
- " 9.7 \n",
- " \n",
- " \n",
- " 2555 \n",
- " 2022-12-30 00:00:00+00:00 \n",
- " ALIC1 \n",
- " 12.6 \n",
- " \n",
- " \n",
- " 2556 \n",
- " 2022-12-31 00:00:00+00:00 \n",
- " ALIC1 \n",
- " 13.4 \n",
- " \n",
- " \n",
- "
\n",
- "
2557 rows × 3 columns
\n",
- "
"
- ],
- "text/plain": [
- " datetime site_id ta_max\n",
- "0 2016-01-01 00:00:00+00:00 ALIC1 8.6\n",
- "1 2016-01-02 00:00:00+00:00 ALIC1 10.7\n",
- "2 2016-01-03 00:00:00+00:00 ALIC1 8.9\n",
- "3 2016-01-04 00:00:00+00:00 ALIC1 9.7\n",
- "4 2016-01-05 00:00:00+00:00 ALIC1 8.2\n",
- "... ... ... ...\n",
- "2552 2022-12-27 00:00:00+00:00 ALIC1 10.3\n",
- "2553 2022-12-28 00:00:00+00:00 ALIC1 11.4\n",
- "2554 2022-12-29 00:00:00+00:00 ALIC1 9.7\n",
- "2555 2022-12-30 00:00:00+00:00 ALIC1 12.6\n",
- "2556 2022-12-31 00:00:00+00:00 ALIC1 13.4\n",
- "\n",
- "[2557 rows x 3 columns]"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "(2557, 3)\n"
- ]
- }
- ],
- "source": [
- "# Extracting COSMOS TA_MAX data for the station over the required period into a pandas dataframe\n",
- "query_url = f'{BASE_URL}/collections/1D/locations/{site_nm}?datetime={query_date_range}¶meter-name={\",\".join(param_name)}'\n",
- "resp = get_api_response(query_url)\n",
- "df = read_json_collection_data(resp)\n",
- "df = df.reset_index()\n",
- "display(df)\n",
- "print(df.shape)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "id": "62ab39e1-e9ff-4c84-a1a8-615852f3180e",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " \n",
- " ta_max \n",
- " \n",
- " \n",
- " datetime \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " 1 \n",
- " 7.479724 \n",
- " \n",
- " \n",
- " 2 \n",
- " 8.883418 \n",
- " \n",
- " \n",
- " 3 \n",
- " 10.689401 \n",
- " \n",
- " \n",
- " 4 \n",
- " 13.544762 \n",
- " \n",
- " \n",
- " 5 \n",
- " 17.071429 \n",
- " \n",
- " \n",
- " 6 \n",
- " 19.841905 \n",
- " \n",
- " \n",
- " 7 \n",
- " 21.749462 \n",
- " \n",
- " \n",
- " 8 \n",
- " 21.487097 \n",
- " \n",
- " \n",
- " 9 \n",
- " 18.777143 \n",
- " \n",
- " \n",
- " 10 \n",
- " 14.853456 \n",
- " \n",
- " \n",
- " 11 \n",
- " 10.685238 \n",
- " \n",
- " \n",
- " 12 \n",
- " 8.682488 \n",
- " \n",
- " \n",
- "
\n",
- "
"
- ],
- "text/plain": [
- " ta_max\n",
- "datetime \n",
- "1 7.479724\n",
- "2 8.883418\n",
- "3 10.689401\n",
- "4 13.544762\n",
- "5 17.071429\n",
- "6 19.841905\n",
- "7 21.749462\n",
- "8 21.487097\n",
- "9 18.777143\n",
- "10 14.853456\n",
- "11 10.685238\n",
- "12 8.682488"
- ]
- },
- "execution_count": 8,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# Calculating monthly climatological values of TA_MAX for the station over 2016--2022\n",
- "df_site = (\n",
- " df.groupby(pd.PeriodIndex(df[\"datetime\"], freq=\"M\"))[\"ta_max\"].mean().reset_index()\n",
- ")\n",
- "df_site[\"datetime\"] = df_site.datetime.dt.to_timestamp()\n",
- "df_site = df_site.groupby(df_site[\"datetime\"].dt.month).mean(\"ta_max\")\n",
- "df_site"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "0e447fa5-2f4c-4bfb-a776-b3eb6d86b47f",
- "metadata": {},
- "source": [
- "## Accessing Model Data from JASMIN Object Store\n",
- "### In this notebook we will be accessing CHESS-SCAPE data that has been stored in the JASMIN Object Store tenancy and made open READ access to all. For more information about CHESS-SCAPE data, please see https://catalogue.ceda.ac.uk/uuid/8194b416cbee482b89e0dfbe17c5786c. We will be extracting the Daily Maximum Surface Air Temperature (TASMAX) at the grid point nearest to the COSMOS Station ALIC1 for the period 2016--2022 for all ensemble members available. "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "f52a28b4-0beb-458a-adc1-9376d3560cd5",
- "metadata": {},
- "source": [
- "### Exploring the bucket with s3fs"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "id": "dfa0f727-e1ba-4da8-ab47-92e45226f279",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "['ens01-year100kmchunk/hurs_01_year100km.zarr',\n",
- " 'ens01-year100kmchunk/huss_01_year100km.zarr',\n",
- " 'ens01-year100kmchunk/pr_01_year100km.zarr',\n",
- " 'ens01-year100kmchunk/psurf_01_year100km.zarr',\n",
- " 'ens01-year100kmchunk/rlds_01_year100km.zarr',\n",
- " 'ens01-year100kmchunk/rsds_01_year100km.zarr',\n",
- " 'ens01-year100kmchunk/sfcWind_01_year100km.zarr',\n",
- " 'ens01-year100kmchunk/tmax_01_year100km.zarr',\n",
- " 'ens01-year100kmchunk/tmean_01_year100km.zarr',\n",
- " 'ens01-year100kmchunk/tmin_01_year100km.zarr']"
- ]
- },
- "execution_count": 9,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# s3fs is a python package that allows you to not only read the data but also explore the tenancy (chess-scape-o)\n",
- "# Here we will be using s3fs to list the bucket and not read the data, we read the data using intake package shown below\n",
- "# For more information please see: https://pypi.org/project/s3fs/\n",
- "s3 = s3fs.S3FileSystem(anon=True, client_kwargs={'endpoint_url': \"https://chess-scape-o.s3-ext.jc.rl.ac.uk\"})\n",
- "s3.ls('s3://ens01-year100kmchunk/')\n",
- "# In the output you see that within in the chess-scape-o tenancy, a bucket called ens01-year100kmchunk\n",
- "# has 10 different zarr files for different 10 different variables. This is for a single chunk type tested."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "669c664d-4100-440a-8e76-445921842a5a",
- "metadata": {},
- "source": [
- "### Setup Intake Catalogue"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "id": "1e7b1140-74cc-45cb-999b-d1d89f42c8db",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "application/yaml": "catalogue:\n args:\n path: ./catalogue.yaml\n description: ''\n driver: intake.catalog.local.YAMLFileCatalog\n metadata: {}\n",
- "text/plain": [
- "catalogue:\n",
- " args:\n",
- " path: ./catalogue.yaml\n",
- " description: ''\n",
- " driver: intake.catalog.local.YAMLFileCatalog\n",
- " metadata: {}\n"
- ]
- },
- "metadata": {
- "application/json": {
- "root": "catalogue"
- }
- },
- "output_type": "display_data"
- }
- ],
- "source": [
- "# The intake catalogue defines the endpoints that should be used to access specific datasets on the object storage.\n",
- "# For any dataset that is not open READ access, you would also need to provide required credentials\n",
- "catalogue = intake.open_catalog(\"./catalogue.yaml\")\n",
- "catalogue"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "5b59b9bd-0739-4200-bfc3-d4f6f4e83684",
- "metadata": {},
- "source": [
- "### Accessing data for the ensemble members and the associated metadata\n",
- "#### We have not activated any Dask Cluster for this notebook. This notebook will run without any Dask Cluster activated. However, if a Dask Cluster is available on the platform you are using, you may initalise a dask client and the rest of the notebook will run as the same. For using Dask Client on the different platforms, please see the links below:\n",
- "- DataLabs: https://datalab-docs.datalabs.ceh.ac.uk/tutorials/datalabs-dask-cluster/index.html\n",
- "- JASMIN Notebook Service: https://github.com/cedadev/jasmin-daskgateway\n",
- "- Google Colab: https://saturncloud.io/docs/using-saturn-cloud/external-connect/colab_external_connect/"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "id": "fd3612d8-058d-44b6-a49d-7327409d2f48",
- "metadata": {},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "/opt/conda/lib/python3.9/site-packages/scipy/__init__.py:146: UserWarning: A NumPy version >=1.16.5 and <1.23.0 is required for this version of SciPy (detected version 1.26.1\n",
- " warnings.warn(f\"A NumPy version >={np_minversion} and <{np_maxversion}\"\n"
- ]
- },
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "
<xarray.Dataset>\n",
- "Dimensions: (y: 1057, x: 656, time: 36000)\n",
- "Coordinates:\n",
- " * time (time) object 1980-12-01 12:00:00 ... 2080-11-30 12:00:00\n",
- " * x (x) float32 500.0 1.5e+03 2.5e+03 ... 6.535e+05 6.545e+05 6.555e+05\n",
- " * y (y) float32 500.0 1.5e+03 2.5e+03 ... 1.054e+06 1.056e+06 1.056e+06\n",
- "Data variables:\n",
- " lat (y, x) float32 dask.array<chunksize=(100, 100), meta=np.ndarray>\n",
- " lon (y, x) float32 dask.array<chunksize=(100, 100), meta=np.ndarray>\n",
- " tasmax (time, y, x) float32 dask.array<chunksize=(360, 100, 100), meta=np.ndarray>\n",
- "Attributes:\n",
- " CDI: Climate Data Interface version 1.9.8 (https://mpimet.mpg.de...\n",
- " CDO: Climate Data Operators version 1.9.8 (https://mpimet.mpg.de...\n",
- " Conventions: CF-1.6\n",
- " NCO: 4.7.3\n",
- " contact: emrobi@ceh.ac.uk\n",
- " history: Fri Mar 19 15:18:41 2021: cdo --sortname -add /gws/nopw/j04...\n",
- " institution: CEH Wallingford - NERC\n",
- " project: UK-SCAPE: SPEED Dimensions:
Coordinates: (3)
time
(time)
object
1980-12-01 12:00:00 ... 2080-11-...
axis : T standard_name : time array([cftime.Datetime360Day(1980, 12, 1, 12, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(1980, 12, 2, 12, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(1980, 12, 3, 12, 0, 0, 0, has_year_zero=True),\n",
- " ...,\n",
- " cftime.Datetime360Day(2080, 11, 28, 12, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(2080, 11, 29, 12, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(2080, 11, 30, 12, 0, 0, 0, has_year_zero=True)],\n",
- " dtype=object) x
(x)
float32
500.0 1.5e+03 ... 6.555e+05
array([5.000e+02, 1.500e+03, 2.500e+03, ..., 6.535e+05, 6.545e+05, 6.555e+05],\n",
- " dtype=float32) y
(y)
float32
500.0 1.5e+03 ... 1.056e+06
array([5.0000e+02, 1.5000e+03, 2.5000e+03, ..., 1.0545e+06, 1.0555e+06,\n",
- " 1.0565e+06], dtype=float32) Data variables: (3)
lat
(y, x)
float32
dask.array<chunksize=(100, 100), meta=np.ndarray>
standard_name : latitude units : degrees east \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " Array Chunk \n",
- " \n",
- " \n",
- " Bytes 2.65 MiB 39.06 kiB \n",
- " Shape (1057, 656) (100, 100) \n",
- " Count 78 Tasks 77 Chunks \n",
- " Type float32 numpy.ndarray \n",
- " \n",
- "
\n",
- " \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " 656 \n",
- " 1057 \n",
- " \n",
- " \n",
- " \n",
- "
lon
(y, x)
float32
dask.array<chunksize=(100, 100), meta=np.ndarray>
standard_name : longitude units : degrees east \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " Array Chunk \n",
- " \n",
- " \n",
- " Bytes 2.65 MiB 39.06 kiB \n",
- " Shape (1057, 656) (100, 100) \n",
- " Count 78 Tasks 77 Chunks \n",
- " Type float32 numpy.ndarray \n",
- " \n",
- "
\n",
- " \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " 656 \n",
- " 1057 \n",
- " \n",
- " \n",
- " \n",
- "
tasmax
(time, y, x)
float32
dask.array<chunksize=(360, 100, 100), meta=np.ndarray>
long_name : Maximum air temperature standard_name : air_temperature units : K \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " Array Chunk \n",
- " \n",
- " \n",
- " Bytes 92.99 GiB 13.73 MiB \n",
- " Shape (36000, 1057, 656) (360, 100, 100) \n",
- " Count 7701 Tasks 7700 Chunks \n",
- " Type float32 numpy.ndarray \n",
- " \n",
- "
\n",
- " \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " 656 \n",
- " 1057 \n",
- " 36000 \n",
- " \n",
- " \n",
- " \n",
- "
Indexes: (3)
PandasIndex
PandasIndex(CFTimeIndex([1980-12-01 12:00:00, 1980-12-02 12:00:00, 1980-12-03 12:00:00,\n",
- " 1980-12-04 12:00:00, 1980-12-05 12:00:00, 1980-12-06 12:00:00,\n",
- " 1980-12-07 12:00:00, 1980-12-08 12:00:00, 1980-12-09 12:00:00,\n",
- " 1980-12-10 12:00:00,\n",
- " ...\n",
- " 2080-11-21 12:00:00, 2080-11-22 12:00:00, 2080-11-23 12:00:00,\n",
- " 2080-11-24 12:00:00, 2080-11-25 12:00:00, 2080-11-26 12:00:00,\n",
- " 2080-11-27 12:00:00, 2080-11-28 12:00:00, 2080-11-29 12:00:00,\n",
- " 2080-11-30 12:00:00],\n",
- " dtype='object', length=36000, calendar='360_day', freq='D')) PandasIndex
PandasIndex(Index([ 500.0, 1500.0, 2500.0, 3500.0, 4500.0, 5500.0, 6500.0,\n",
- " 7500.0, 8500.0, 9500.0,\n",
- " ...\n",
- " 646500.0, 647500.0, 648500.0, 649500.0, 650500.0, 651500.0, 652500.0,\n",
- " 653500.0, 654500.0, 655500.0],\n",
- " dtype='float32', name='x', length=656)) PandasIndex
PandasIndex(Index([ 500.0, 1500.0, 2500.0, 3500.0, 4500.0, 5500.0,\n",
- " 6500.0, 7500.0, 8500.0, 9500.0,\n",
- " ...\n",
- " 1047500.0, 1048500.0, 1049500.0, 1050500.0, 1051500.0, 1052500.0,\n",
- " 1053500.0, 1054500.0, 1055500.0, 1056500.0],\n",
- " dtype='float32', name='y', length=1057)) Attributes: (8)
CDI : Climate Data Interface version 1.9.8 (https://mpimet.mpg.de/cdi) CDO : Climate Data Operators version 1.9.8 (https://mpimet.mpg.de/cdo) Conventions : CF-1.6 NCO : 4.7.3 contact : emrobi@ceh.ac.uk history : Fri Mar 19 15:18:41 2021: cdo --sortname -add /gws/nopw/j04/hydro_jules/data/uk/driving_data/ukcp18_1km/rcp85/01/daily/tasmax/ukcp18_rcp85_land-rcm_uk_1km_01_v20190731_tasmax_198012.nc /work/scratch-nopw/emrobi/UKCP18/ukcp18_1km/tmp/delta_85_01_198012.nc /work/scratch-nopw/emrobi/UKCP18/ukcp18_1km/rcp85_bias_corrected/01/daily/tasmax/ukcp18_rcp85_land-rcm_uk_1km_01_v20190731_tasmax_bias_corrected_198012.nc\n",
- "Thu Feb 27 20:18:21 2020: ncatted -a _FillValue,tasmax,o,f,-1e20 /work/scratch/emrobi/UKCP18/land-rcm/uk/1km/rcp85/01/v20190731/ukcp18_rcp85_land-rcm_uk_1km_01_v20190731_tasmax_198012.nc institution : CEH Wallingford - NERC project : UK-SCAPE: SPEED "
- ],
- "text/plain": [
- "\n",
- "Dimensions: (y: 1057, x: 656, time: 36000)\n",
- "Coordinates:\n",
- " * time (time) object 1980-12-01 12:00:00 ... 2080-11-30 12:00:00\n",
- " * x (x) float32 500.0 1.5e+03 2.5e+03 ... 6.535e+05 6.545e+05 6.555e+05\n",
- " * y (y) float32 500.0 1.5e+03 2.5e+03 ... 1.054e+06 1.056e+06 1.056e+06\n",
- "Data variables:\n",
- " lat (y, x) float32 dask.array\n",
- " lon (y, x) float32 dask.array\n",
- " tasmax (time, y, x) float32 dask.array\n",
- "Attributes:\n",
- " CDI: Climate Data Interface version 1.9.8 (https://mpimet.mpg.de...\n",
- " CDO: Climate Data Operators version 1.9.8 (https://mpimet.mpg.de...\n",
- " Conventions: CF-1.6\n",
- " NCO: 4.7.3\n",
- " contact: emrobi@ceh.ac.uk\n",
- " history: Fri Mar 19 15:18:41 2021: cdo --sortname -add /gws/nopw/j04...\n",
- " institution: CEH Wallingford - NERC\n",
- " project: UK-SCAPE: SPEED"
- ]
- },
- "execution_count": 11,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# We are accessing TASMAX for the Ensemble member #01 from the catalogue\n",
- "# We are using the mid-sized chunk type for the dataset\n",
- "# For more information about different chunk sizes and their performance, please see the GitHub README.\n",
- "chess_data_01 = catalogue.e01_tmax_year100km.to_dask()\n",
- "chess_data_01"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "id": "8cc750e7-4d4f-4bc6-a433-05f490751b0d",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "
<xarray.Dataset>\n",
- "Dimensions: (y: 1057, x: 656, time: 36000)\n",
- "Coordinates:\n",
- " lat (y, x) float32 dask.array<chunksize=(100, 100), meta=np.ndarray>\n",
- " lon (y, x) float32 dask.array<chunksize=(100, 100), meta=np.ndarray>\n",
- " * time (time) object 1980-12-01 12:00:00 ... 2080-11-30 12:00:00\n",
- " * x (x) float32 500.0 1.5e+03 2.5e+03 ... 6.535e+05 6.545e+05 6.555e+05\n",
- " * y (y) float32 500.0 1.5e+03 2.5e+03 ... 1.054e+06 1.056e+06 1.056e+06\n",
- "Data variables:\n",
- " tasmax (time, y, x) float32 dask.array<chunksize=(360, 100, 100), meta=np.ndarray>\n",
- "Attributes:\n",
- " CDI: Climate Data Interface version 1.9.8 (https://mpimet.mpg.de...\n",
- " CDO: Climate Data Operators version 1.9.8 (https://mpimet.mpg.de...\n",
- " Conventions: CF-1.6\n",
- " NCO: 4.7.3\n",
- " contact: emrobi@ceh.ac.uk\n",
- " history: Fri Mar 19 15:18:41 2021: cdo --sortname -add /gws/nopw/j04...\n",
- " institution: CEH Wallingford - NERC\n",
- " project: UK-SCAPE: SPEED Dimensions:
Coordinates: (5)
lat
(y, x)
float32
dask.array<chunksize=(100, 100), meta=np.ndarray>
standard_name : latitude units : degrees east \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " Array Chunk \n",
- " \n",
- " \n",
- " Bytes 2.65 MiB 39.06 kiB \n",
- " Shape (1057, 656) (100, 100) \n",
- " Count 78 Tasks 77 Chunks \n",
- " Type float32 numpy.ndarray \n",
- " \n",
- "
\n",
- " \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " 656 \n",
- " 1057 \n",
- " \n",
- " \n",
- " \n",
- "
lon
(y, x)
float32
dask.array<chunksize=(100, 100), meta=np.ndarray>
standard_name : longitude units : degrees east \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " Array Chunk \n",
- " \n",
- " \n",
- " Bytes 2.65 MiB 39.06 kiB \n",
- " Shape (1057, 656) (100, 100) \n",
- " Count 78 Tasks 77 Chunks \n",
- " Type float32 numpy.ndarray \n",
- " \n",
- "
\n",
- " \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " 656 \n",
- " 1057 \n",
- " \n",
- " \n",
- " \n",
- "
time
(time)
object
1980-12-01 12:00:00 ... 2080-11-...
axis : T standard_name : time array([cftime.Datetime360Day(1980, 12, 1, 12, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(1980, 12, 2, 12, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(1980, 12, 3, 12, 0, 0, 0, has_year_zero=True),\n",
- " ...,\n",
- " cftime.Datetime360Day(2080, 11, 28, 12, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(2080, 11, 29, 12, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(2080, 11, 30, 12, 0, 0, 0, has_year_zero=True)],\n",
- " dtype=object) x
(x)
float32
500.0 1.5e+03 ... 6.555e+05
array([5.000e+02, 1.500e+03, 2.500e+03, ..., 6.535e+05, 6.545e+05, 6.555e+05],\n",
- " dtype=float32) y
(y)
float32
500.0 1.5e+03 ... 1.056e+06
array([5.0000e+02, 1.5000e+03, 2.5000e+03, ..., 1.0545e+06, 1.0555e+06,\n",
- " 1.0565e+06], dtype=float32) Data variables: (1)
Indexes: (3)
PandasIndex
PandasIndex(CFTimeIndex([1980-12-01 12:00:00, 1980-12-02 12:00:00, 1980-12-03 12:00:00,\n",
- " 1980-12-04 12:00:00, 1980-12-05 12:00:00, 1980-12-06 12:00:00,\n",
- " 1980-12-07 12:00:00, 1980-12-08 12:00:00, 1980-12-09 12:00:00,\n",
- " 1980-12-10 12:00:00,\n",
- " ...\n",
- " 2080-11-21 12:00:00, 2080-11-22 12:00:00, 2080-11-23 12:00:00,\n",
- " 2080-11-24 12:00:00, 2080-11-25 12:00:00, 2080-11-26 12:00:00,\n",
- " 2080-11-27 12:00:00, 2080-11-28 12:00:00, 2080-11-29 12:00:00,\n",
- " 2080-11-30 12:00:00],\n",
- " dtype='object', length=36000, calendar='360_day', freq='D')) PandasIndex
PandasIndex(Index([ 500.0, 1500.0, 2500.0, 3500.0, 4500.0, 5500.0, 6500.0,\n",
- " 7500.0, 8500.0, 9500.0,\n",
- " ...\n",
- " 646500.0, 647500.0, 648500.0, 649500.0, 650500.0, 651500.0, 652500.0,\n",
- " 653500.0, 654500.0, 655500.0],\n",
- " dtype='float32', name='x', length=656)) PandasIndex
PandasIndex(Index([ 500.0, 1500.0, 2500.0, 3500.0, 4500.0, 5500.0,\n",
- " 6500.0, 7500.0, 8500.0, 9500.0,\n",
- " ...\n",
- " 1047500.0, 1048500.0, 1049500.0, 1050500.0, 1051500.0, 1052500.0,\n",
- " 1053500.0, 1054500.0, 1055500.0, 1056500.0],\n",
- " dtype='float32', name='y', length=1057)) Attributes: (8)
CDI : Climate Data Interface version 1.9.8 (https://mpimet.mpg.de/cdi) CDO : Climate Data Operators version 1.9.8 (https://mpimet.mpg.de/cdo) Conventions : CF-1.6 NCO : 4.7.3 contact : emrobi@ceh.ac.uk history : Fri Mar 19 15:18:41 2021: cdo --sortname -add /gws/nopw/j04/hydro_jules/data/uk/driving_data/ukcp18_1km/rcp85/01/daily/tasmax/ukcp18_rcp85_land-rcm_uk_1km_01_v20190731_tasmax_198012.nc /work/scratch-nopw/emrobi/UKCP18/ukcp18_1km/tmp/delta_85_01_198012.nc /work/scratch-nopw/emrobi/UKCP18/ukcp18_1km/rcp85_bias_corrected/01/daily/tasmax/ukcp18_rcp85_land-rcm_uk_1km_01_v20190731_tasmax_bias_corrected_198012.nc\n",
- "Thu Feb 27 20:18:21 2020: ncatted -a _FillValue,tasmax,o,f,-1e20 /work/scratch/emrobi/UKCP18/land-rcm/uk/1km/rcp85/01/v20190731/ukcp18_rcp85_land-rcm_uk_1km_01_v20190731_tasmax_198012.nc institution : CEH Wallingford - NERC project : UK-SCAPE: SPEED "
- ],
- "text/plain": [
- "\n",
- "Dimensions: (y: 1057, x: 656, time: 36000)\n",
- "Coordinates:\n",
- " lat (y, x) float32 dask.array\n",
- " lon (y, x) float32 dask.array\n",
- " * time (time) object 1980-12-01 12:00:00 ... 2080-11-30 12:00:00\n",
- " * x (x) float32 500.0 1.5e+03 2.5e+03 ... 6.535e+05 6.545e+05 6.555e+05\n",
- " * y (y) float32 500.0 1.5e+03 2.5e+03 ... 1.054e+06 1.056e+06 1.056e+06\n",
- "Data variables:\n",
- " tasmax (time, y, x) float32 dask.array\n",
- "Attributes:\n",
- " CDI: Climate Data Interface version 1.9.8 (https://mpimet.mpg.de...\n",
- " CDO: Climate Data Operators version 1.9.8 (https://mpimet.mpg.de...\n",
- " Conventions: CF-1.6\n",
- " NCO: 4.7.3\n",
- " contact: emrobi@ceh.ac.uk\n",
- " history: Fri Mar 19 15:18:41 2021: cdo --sortname -add /gws/nopw/j04...\n",
- " institution: CEH Wallingford - NERC\n",
- " project: UK-SCAPE: SPEED"
- ]
- },
- "execution_count": 12,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# CHESS-SCAPE is on the British National Grid with Easting and Northing Coordinates.\n",
- "# We also set the latitude and longitude as coordinates\n",
- "chess_data_01 = chess_data_01.set_coords((\"lat\", \"lon\"))\n",
- "chess_data_01"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 13,
- "id": "ccca7cf2-e13d-4a52-af53-2f4d5b01b0ac",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "
<xarray.DataArray 'tasmax' (time: 2520, y: 1057, x: 656)>\n",
- "dask.array<getitem, shape=(2520, 1057, 656), dtype=float32, chunksize=(360, 100, 100), chunktype=numpy.ndarray>\n",
- "Coordinates:\n",
- " lat (y, x) float32 dask.array<chunksize=(100, 100), meta=np.ndarray>\n",
- " lon (y, x) float32 dask.array<chunksize=(100, 100), meta=np.ndarray>\n",
- " * time (time) object 2016-01-01 12:00:00 ... 2022-12-30 12:00:00\n",
- " * x (x) float32 500.0 1.5e+03 2.5e+03 ... 6.535e+05 6.545e+05 6.555e+05\n",
- " * y (y) float32 500.0 1.5e+03 2.5e+03 ... 1.054e+06 1.056e+06 1.056e+06\n",
- "Attributes:\n",
- " long_name: Maximum air temperature\n",
- " standard_name: air_temperature\n",
- " units: K dask.array<chunksize=(330, 100, 100), meta=np.ndarray>
\n",
- "\n",
- "\n",
- "\n",
- " \n",
- " Array Chunk \n",
- " \n",
- " \n",
- " Bytes 6.51 GiB 13.73 MiB \n",
- " Shape (2520, 1057, 656) (360, 100, 100) \n",
- " Count 8317 Tasks 616 Chunks \n",
- " Type float32 numpy.ndarray \n",
- " \n",
- "
\n",
- " \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " 656 \n",
- " 1057 \n",
- " 2520 \n",
- " \n",
- " \n",
- " \n",
- "
Coordinates: (5)
lat
(y, x)
float32
dask.array<chunksize=(100, 100), meta=np.ndarray>
standard_name : latitude units : degrees east \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " Array Chunk \n",
- " \n",
- " \n",
- " Bytes 2.65 MiB 39.06 kiB \n",
- " Shape (1057, 656) (100, 100) \n",
- " Count 78 Tasks 77 Chunks \n",
- " Type float32 numpy.ndarray \n",
- " \n",
- "
\n",
- " \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " 656 \n",
- " 1057 \n",
- " \n",
- " \n",
- " \n",
- "
lon
(y, x)
float32
dask.array<chunksize=(100, 100), meta=np.ndarray>
standard_name : longitude units : degrees east \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " Array Chunk \n",
- " \n",
- " \n",
- " Bytes 2.65 MiB 39.06 kiB \n",
- " Shape (1057, 656) (100, 100) \n",
- " Count 78 Tasks 77 Chunks \n",
- " Type float32 numpy.ndarray \n",
- " \n",
- "
\n",
- " \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " 656 \n",
- " 1057 \n",
- " \n",
- " \n",
- " \n",
- "
time
(time)
object
2016-01-01 12:00:00 ... 2022-12-...
axis : T standard_name : time array([cftime.Datetime360Day(2016, 1, 1, 12, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(2016, 1, 2, 12, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(2016, 1, 3, 12, 0, 0, 0, has_year_zero=True), ...,\n",
- " cftime.Datetime360Day(2022, 12, 28, 12, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(2022, 12, 29, 12, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(2022, 12, 30, 12, 0, 0, 0, has_year_zero=True)],\n",
- " dtype=object) x
(x)
float32
500.0 1.5e+03 ... 6.555e+05
array([5.000e+02, 1.500e+03, 2.500e+03, ..., 6.535e+05, 6.545e+05, 6.555e+05],\n",
- " dtype=float32) y
(y)
float32
500.0 1.5e+03 ... 1.056e+06
array([5.0000e+02, 1.5000e+03, 2.5000e+03, ..., 1.0545e+06, 1.0555e+06,\n",
- " 1.0565e+06], dtype=float32) Indexes: (3)
PandasIndex
PandasIndex(CFTimeIndex([2016-01-01 12:00:00, 2016-01-02 12:00:00, 2016-01-03 12:00:00,\n",
- " 2016-01-04 12:00:00, 2016-01-05 12:00:00, 2016-01-06 12:00:00,\n",
- " 2016-01-07 12:00:00, 2016-01-08 12:00:00, 2016-01-09 12:00:00,\n",
- " 2016-01-10 12:00:00,\n",
- " ...\n",
- " 2022-12-21 12:00:00, 2022-12-22 12:00:00, 2022-12-23 12:00:00,\n",
- " 2022-12-24 12:00:00, 2022-12-25 12:00:00, 2022-12-26 12:00:00,\n",
- " 2022-12-27 12:00:00, 2022-12-28 12:00:00, 2022-12-29 12:00:00,\n",
- " 2022-12-30 12:00:00],\n",
- " dtype='object', length=2520, calendar='360_day', freq='D')) PandasIndex
PandasIndex(Index([ 500.0, 1500.0, 2500.0, 3500.0, 4500.0, 5500.0, 6500.0,\n",
- " 7500.0, 8500.0, 9500.0,\n",
- " ...\n",
- " 646500.0, 647500.0, 648500.0, 649500.0, 650500.0, 651500.0, 652500.0,\n",
- " 653500.0, 654500.0, 655500.0],\n",
- " dtype='float32', name='x', length=656)) PandasIndex
PandasIndex(Index([ 500.0, 1500.0, 2500.0, 3500.0, 4500.0, 5500.0,\n",
- " 6500.0, 7500.0, 8500.0, 9500.0,\n",
- " ...\n",
- " 1047500.0, 1048500.0, 1049500.0, 1050500.0, 1051500.0, 1052500.0,\n",
- " 1053500.0, 1054500.0, 1055500.0, 1056500.0],\n",
- " dtype='float32', name='y', length=1057)) Attributes: (3)
long_name : Maximum air temperature standard_name : air_temperature units : K "
- ],
- "text/plain": [
- "\n",
- "dask.array\n",
- "Coordinates:\n",
- " lat (y, x) float32 dask.array\n",
- " lon (y, x) float32 dask.array\n",
- " * time (time) object 2016-01-01 12:00:00 ... 2022-12-30 12:00:00\n",
- " * x (x) float32 500.0 1.5e+03 2.5e+03 ... 6.535e+05 6.545e+05 6.555e+05\n",
- " * y (y) float32 500.0 1.5e+03 2.5e+03 ... 1.054e+06 1.056e+06 1.056e+06\n",
- "Attributes:\n",
- " long_name: Maximum air temperature\n",
- " standard_name: air_temperature\n",
- " units: K"
- ]
- },
- "execution_count": 13,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# Slicing for the time period 2016--2022\n",
- "chess_data_01 = chess_data_01[\"tasmax\"].sel(time=slice(\"2016-01-01\", \"2022-12-30\"))\n",
- "chess_data_01"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 14,
- "id": "2e212822-7feb-4442-8707-802119fb3cc4",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Extracting data for the other ensemble members\n",
- "# Ensemble member #04\n",
- "chess_data_04 = catalogue.e04_tmax_year100km.to_dask()\n",
- "chess_data_04 = chess_data_04.set_coords((\"lat\", \"lon\"))\n",
- "chess_data_04 = chess_data_04[\"tasmax\"].sel(time=slice(\"2016-01-01\", \"2022-12-30\"))\n",
- "\n",
- "# Ensemble member #06\n",
- "chess_data_06 = catalogue.e06_tmax_year100km.to_dask()\n",
- "chess_data_06 = chess_data_06.set_coords((\"lat\", \"lon\"))\n",
- "chess_data_06 = chess_data_06[\"tasmax\"].sel(time=slice(\"2016-01-01\", \"2022-12-30\"))\n",
- "\n",
- "# Ensemble member #15\n",
- "chess_data_15 = catalogue.e15_tmax_year100km.to_dask()\n",
- "chess_data_15 = chess_data_15.set_coords((\"lat\", \"lon\"))\n",
- "chess_data_15 = chess_data_15[\"tasmax\"].sel(time=slice(\"2016-01-01\", \"2022-12-30\"))"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "e7899fb0-968f-4874-a300-e6406ba67da0",
- "metadata": {},
- "source": [
- "### Deriving the Observed Station nearest grid point on the Gridded Dataset"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 15,
- "id": "164cdd80-3ff7-4b97-8993-ca1a30b9016e",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Function to derive the data for the nearest grid point to the station lat lon\n",
- "def find_chess_tile(lat, lon, latlon_ref):\n",
- " \"\"\"\n",
- " Created by Doran Khamis (dorkha@ceh.ac.uk)\n",
- " Function to calculate the nearest grid point\n",
- " of a given lat lon value within a gridded dataset\n",
- " The input data is the latitude, longitude of the station\n",
- " and the grid reference (latlon_ref) of the gridded dataset\n",
- " The function returns the y and x index for the gridded dataset\n",
- " which can be used to derive the nearest grid point\n",
- " This function assumes equal length lat/lon vectors in latlon_ref\n",
- " \"\"\"\n",
- " dist_diff = np.sqrt(\n",
- " np.square(latlon_ref.lat.values - lat) + np.square(latlon_ref.lon.values - lon)\n",
- " )\n",
- " chesstile_yx = np.where(dist_diff == np.min(dist_diff))\n",
- " return chesstile_yx"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 16,
- "id": "57e6fa80-4ebd-4ef2-85ff-32e650d0beca",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "
<xarray.DataArray 'tasmax' (y: 1057, x: 656)>\n",
- "dask.array<getitem, shape=(1057, 656), dtype=float32, chunksize=(100, 100), chunktype=numpy.ndarray>\n",
- "Coordinates:\n",
- " lat (y, x) float32 dask.array<chunksize=(100, 100), meta=np.ndarray>\n",
- " lon (y, x) float32 dask.array<chunksize=(100, 100), meta=np.ndarray>\n",
- " time object 2016-01-01 12:00:00\n",
- " * x (x) float32 500.0 1.5e+03 2.5e+03 ... 6.535e+05 6.545e+05 6.555e+05\n",
- " * y (y) float32 500.0 1.5e+03 2.5e+03 ... 1.054e+06 1.056e+06 1.056e+06\n",
- "Attributes:\n",
- " long_name: Maximum air temperature\n",
- " standard_name: air_temperature\n",
- " units: K dask.array<chunksize=(100, 100), meta=np.ndarray>
\n",
- "\n",
- "\n",
- "\n",
- " \n",
- " Array Chunk \n",
- " \n",
- " \n",
- " Bytes 2.65 MiB 39.06 kiB \n",
- " Shape (1057, 656) (100, 100) \n",
- " Count 8394 Tasks 77 Chunks \n",
- " Type float32 numpy.ndarray \n",
- " \n",
- "
\n",
- " \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " 656 \n",
- " 1057 \n",
- " \n",
- " \n",
- " \n",
- "
Coordinates: (5)
lat
(y, x)
float32
dask.array<chunksize=(100, 100), meta=np.ndarray>
standard_name : latitude units : degrees east \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " Array Chunk \n",
- " \n",
- " \n",
- " Bytes 2.65 MiB 39.06 kiB \n",
- " Shape (1057, 656) (100, 100) \n",
- " Count 78 Tasks 77 Chunks \n",
- " Type float32 numpy.ndarray \n",
- " \n",
- "
\n",
- " \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " 656 \n",
- " 1057 \n",
- " \n",
- " \n",
- " \n",
- "
lon
(y, x)
float32
dask.array<chunksize=(100, 100), meta=np.ndarray>
standard_name : longitude units : degrees east \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " Array Chunk \n",
- " \n",
- " \n",
- " Bytes 2.65 MiB 39.06 kiB \n",
- " Shape (1057, 656) (100, 100) \n",
- " Count 78 Tasks 77 Chunks \n",
- " Type float32 numpy.ndarray \n",
- " \n",
- "
\n",
- " \n",
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- "\n",
- " \n",
- " 656 \n",
- " 1057 \n",
- " \n",
- " \n",
- " \n",
- "
time
()
object
2016-01-01 12:00:00
axis : T standard_name : time array(cftime.Datetime360Day(2016, 1, 1, 12, 0, 0, 0, has_year_zero=True),\n",
- " dtype=object) x
(x)
float32
500.0 1.5e+03 ... 6.555e+05
array([5.000e+02, 1.500e+03, 2.500e+03, ..., 6.535e+05, 6.545e+05, 6.555e+05],\n",
- " dtype=float32) y
(y)
float32
500.0 1.5e+03 ... 1.056e+06
array([5.0000e+02, 1.5000e+03, 2.5000e+03, ..., 1.0545e+06, 1.0555e+06,\n",
- " 1.0565e+06], dtype=float32) Indexes: (2)
PandasIndex
PandasIndex(Index([ 500.0, 1500.0, 2500.0, 3500.0, 4500.0, 5500.0, 6500.0,\n",
- " 7500.0, 8500.0, 9500.0,\n",
- " ...\n",
- " 646500.0, 647500.0, 648500.0, 649500.0, 650500.0, 651500.0, 652500.0,\n",
- " 653500.0, 654500.0, 655500.0],\n",
- " dtype='float32', name='x', length=656)) PandasIndex
PandasIndex(Index([ 500.0, 1500.0, 2500.0, 3500.0, 4500.0, 5500.0,\n",
- " 6500.0, 7500.0, 8500.0, 9500.0,\n",
- " ...\n",
- " 1047500.0, 1048500.0, 1049500.0, 1050500.0, 1051500.0, 1052500.0,\n",
- " 1053500.0, 1054500.0, 1055500.0, 1056500.0],\n",
- " dtype='float32', name='y', length=1057)) Attributes: (3)
long_name : Maximum air temperature standard_name : air_temperature units : K "
- ],
- "text/plain": [
- "\n",
- "dask.array\n",
- "Coordinates:\n",
- " lat (y, x) float32 dask.array\n",
- " lon (y, x) float32 dask.array\n",
- " time object 2016-01-01 12:00:00\n",
- " * x (x) float32 500.0 1.5e+03 2.5e+03 ... 6.535e+05 6.545e+05 6.555e+05\n",
- " * y (y) float32 500.0 1.5e+03 2.5e+03 ... 1.054e+06 1.056e+06 1.056e+06\n",
- "Attributes:\n",
- " long_name: Maximum air temperature\n",
- " standard_name: air_temperature\n",
- " units: K"
- ]
- },
- "execution_count": 16,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# We create a temporary CHESS-SCAPE gridded dataset array\n",
- "chess_tmp = chess_data_01[0, :, :]\n",
- "chess_tmp"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 17,
- "id": "98cd3f5f-41ae-47c4-9e97-736477f71b61",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[140] [479]\n"
- ]
- }
- ],
- "source": [
- "# Extracting the x and y indices which point to the nearest grid point of the COSMOS station\n",
- "y, x = find_chess_tile(site_latitude, site_longitude, chess_tmp)\n",
- "print(y, x)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 18,
- "id": "b530c3f6-842f-43ac-b45d-f66a25f260ed",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Deleting the temporary array\n",
- "del chess_tmp"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ebea9028-9c63-430e-9273-91493dad1196",
- "metadata": {},
- "source": [
- "### Extracting the model ensemble data for the grid point nearest to the observed station"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 19,
- "id": "fc2ea110-a52f-4bb5-9024-65c0cd5f9d0c",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Creating arrays for day, month and year from the time index\n",
- "day = np.array([i.day for i in chess_data_01.time.values])\n",
- "month = np.array([i.month for i in chess_data_01.time.values])\n",
- "year = np.array([i.year for i in chess_data_01.time.values])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 20,
- "id": "55714bc0-6a8f-448b-ab31-91153ac6394c",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Indexing the CHESS-SCAPE data with the x and y coordinates nearest to the observed station\n",
- "ens = [\"ENS01\", \"ENS04\", \"ENS06\", \"ENS15\"]\n",
- "chess_site_data = np.zeros((len(ens), len(day)))\n",
- "chess_site_data[0, :] = chess_data_01[:, y, x].squeeze().values\n",
- "chess_site_data[1, :] = chess_data_04[:, y, x].squeeze().values\n",
- "chess_site_data[2, :] = chess_data_06[:, y, x].squeeze().values\n",
- "chess_site_data[3, :] = chess_data_15[:, y, x].squeeze().values"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 21,
- "id": "0bf8f675-c693-43e2-a588-d7e43db09ec2",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Converting CHESS-SCAPE temperature from Kelvin to deg Celsius\n",
- "chess_site_data = chess_site_data - 273.15"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 22,
- "id": "2810088c-8974-4ad8-8de7-c5d24754ee78",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " \n",
- " YEAR \n",
- " MONTH \n",
- " DAY \n",
- " ENS01 \n",
- " ENS04 \n",
- " ENS06 \n",
- " ENS15 \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " 0 \n",
- " 2016.0 \n",
- " 1.0 \n",
- " 1.0 \n",
- " 8.469476 \n",
- " 10.387781 \n",
- " 2.881372 \n",
- " 9.451196 \n",
- " \n",
- " \n",
- " 1 \n",
- " 2016.0 \n",
- " 1.0 \n",
- " 2.0 \n",
- " 9.242853 \n",
- " 8.467340 \n",
- " 6.806024 \n",
- " 10.261072 \n",
- " \n",
- " \n",
- " 2 \n",
- " 2016.0 \n",
- " 1.0 \n",
- " 3.0 \n",
- " 10.037408 \n",
- " 4.452875 \n",
- " 5.930597 \n",
- " 8.856165 \n",
- " \n",
- " \n",
- " 3 \n",
- " 2016.0 \n",
- " 1.0 \n",
- " 4.0 \n",
- " 6.358728 \n",
- " 4.522943 \n",
- " 4.312189 \n",
- " 6.318750 \n",
- " \n",
- " \n",
- " 4 \n",
- " 2016.0 \n",
- " 1.0 \n",
- " 5.0 \n",
- " 6.984888 \n",
- " 2.625421 \n",
- " 1.373346 \n",
- " 7.547205 \n",
- " \n",
- " \n",
- " ... \n",
- " ... \n",
- " ... \n",
- " ... \n",
- " ... \n",
- " ... \n",
- " ... \n",
- " ... \n",
- " \n",
- " \n",
- " 2515 \n",
- " 2022.0 \n",
- " 12.0 \n",
- " 26.0 \n",
- " 11.695123 \n",
- " 7.517450 \n",
- " 10.040674 \n",
- " 6.743341 \n",
- " \n",
- " \n",
- " 2516 \n",
- " 2022.0 \n",
- " 12.0 \n",
- " 27.0 \n",
- " 7.335809 \n",
- " 11.334253 \n",
- " 9.427026 \n",
- " 7.944208 \n",
- " \n",
- " \n",
- " 2517 \n",
- " 2022.0 \n",
- " 12.0 \n",
- " 28.0 \n",
- " 10.932184 \n",
- " 8.553369 \n",
- " 5.844202 \n",
- " 7.643549 \n",
- " \n",
- " \n",
- " 2518 \n",
- " 2022.0 \n",
- " 12.0 \n",
- " 29.0 \n",
- " 10.518945 \n",
- " 7.154962 \n",
- " 7.586847 \n",
- " 5.023523 \n",
- " \n",
- " \n",
- " 2519 \n",
- " 2022.0 \n",
- " 12.0 \n",
- " 30.0 \n",
- " 10.549493 \n",
- " 7.390710 \n",
- " 10.485040 \n",
- " 5.607843 \n",
- " \n",
- " \n",
- "
\n",
- "
2520 rows × 7 columns
\n",
- "
"
- ],
- "text/plain": [
- " YEAR MONTH DAY ENS01 ENS04 ENS06 ENS15\n",
- "0 2016.0 1.0 1.0 8.469476 10.387781 2.881372 9.451196\n",
- "1 2016.0 1.0 2.0 9.242853 8.467340 6.806024 10.261072\n",
- "2 2016.0 1.0 3.0 10.037408 4.452875 5.930597 8.856165\n",
- "3 2016.0 1.0 4.0 6.358728 4.522943 4.312189 6.318750\n",
- "4 2016.0 1.0 5.0 6.984888 2.625421 1.373346 7.547205\n",
- "... ... ... ... ... ... ... ...\n",
- "2515 2022.0 12.0 26.0 11.695123 7.517450 10.040674 6.743341\n",
- "2516 2022.0 12.0 27.0 7.335809 11.334253 9.427026 7.944208\n",
- "2517 2022.0 12.0 28.0 10.932184 8.553369 5.844202 7.643549\n",
- "2518 2022.0 12.0 29.0 10.518945 7.154962 7.586847 5.023523\n",
- "2519 2022.0 12.0 30.0 10.549493 7.390710 10.485040 5.607843\n",
- "\n",
- "[2520 rows x 7 columns]"
- ]
- },
- "execution_count": 22,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# Creating a pandas dataframe for CHESS-SCAPE ensemble TASMAX\n",
- "f = np.vstack((year, month, day, chess_site_data))\n",
- "df = pd.DataFrame(f.T, columns=[\"YEAR\", \"MONTH\", \"DAY\"] + ens)\n",
- "df"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 23,
- "id": "b2240eed-e862-4ef4-b265-64a74ac4f0d0",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "
\n",
- " \n",
- " \n",
- " \n",
- " ENS01 \n",
- " ENS04 \n",
- " ENS06 \n",
- " ENS15 \n",
- " \n",
- " \n",
- " MONTH \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " 1.0 \n",
- " 8.199085 \n",
- " 7.225493 \n",
- " 7.370226 \n",
- " 6.386664 \n",
- " \n",
- " \n",
- " 2.0 \n",
- " 7.908752 \n",
- " 7.396607 \n",
- " 6.743253 \n",
- " 7.388288 \n",
- " \n",
- " \n",
- " 3.0 \n",
- " 10.210987 \n",
- " 10.479619 \n",
- " 9.844518 \n",
- " 10.104133 \n",
- " \n",
- " \n",
- " 4.0 \n",
- " 12.819470 \n",
- " 13.400659 \n",
- " 12.973615 \n",
- " 12.981180 \n",
- " \n",
- " \n",
- " 5.0 \n",
- " 16.253889 \n",
- " 17.441104 \n",
- " 16.428872 \n",
- " 16.286755 \n",
- " \n",
- " \n",
- " 6.0 \n",
- " 20.577827 \n",
- " 19.185257 \n",
- " 20.710894 \n",
- " 21.569696 \n",
- " \n",
- " \n",
- " 7.0 \n",
- " 23.490857 \n",
- " 21.457086 \n",
- " 25.016401 \n",
- " 23.415034 \n",
- " \n",
- " \n",
- " 8.0 \n",
- " 23.007554 \n",
- " 21.511500 \n",
- " 25.052005 \n",
- " 22.698149 \n",
- " \n",
- " \n",
- " 9.0 \n",
- " 20.052419 \n",
- " 19.290494 \n",
- " 20.566005 \n",
- " 19.663535 \n",
- " \n",
- " \n",
- " 10.0 \n",
- " 14.997889 \n",
- " 14.631403 \n",
- " 15.084459 \n",
- " 15.343498 \n",
- " \n",
- " \n",
- " 11.0 \n",
- " 11.058280 \n",
- " 10.899864 \n",
- " 11.144928 \n",
- " 10.397077 \n",
- " \n",
- " \n",
- " 12.0 \n",
- " 8.552765 \n",
- " 8.235628 \n",
- " 8.761400 \n",
- " 7.872899 \n",
- " \n",
- " \n",
- "
\n",
- "
"
- ],
- "text/plain": [
- " ENS01 ENS04 ENS06 ENS15\n",
- "MONTH \n",
- "1.0 8.199085 7.225493 7.370226 6.386664\n",
- "2.0 7.908752 7.396607 6.743253 7.388288\n",
- "3.0 10.210987 10.479619 9.844518 10.104133\n",
- "4.0 12.819470 13.400659 12.973615 12.981180\n",
- "5.0 16.253889 17.441104 16.428872 16.286755\n",
- "6.0 20.577827 19.185257 20.710894 21.569696\n",
- "7.0 23.490857 21.457086 25.016401 23.415034\n",
- "8.0 23.007554 21.511500 25.052005 22.698149\n",
- "9.0 20.052419 19.290494 20.566005 19.663535\n",
- "10.0 14.997889 14.631403 15.084459 15.343498\n",
- "11.0 11.058280 10.899864 11.144928 10.397077\n",
- "12.0 8.552765 8.235628 8.761400 7.872899"
- ]
- },
- "execution_count": 23,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# Calculating monthly climatology of TASMAX for all the ensemble members\n",
- "df_model = df.groupby([\"YEAR\", \"MONTH\"])[ens].mean()\n",
- "df_model = df_model.groupby([\"MONTH\"])[ens].mean()\n",
- "df_model"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "0a74cf1d-0e6e-4eaf-95b7-d2f54a5467a2",
- "metadata": {},
- "source": [
- "### Comparing observations against modelled ensemble projection"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 24,
- "id": "5f1326ef-b00b-4157-95c1-6f1bb9042897",
- "metadata": {},
- "outputs": [],
- "source": [
- "# For plotting the data in the notebook\n",
- "%matplotlib inline"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 25,
- "id": "4edce09f-9dbf-4561-a168-7e36dbf88db8",
- "metadata": {},
- "outputs": [],
- "source": [
- "# List of months\n",
- "months = [\n",
- " \"JAN\",\n",
- " \"FEB\",\n",
- " \"MAR\",\n",
- " \"APR\",\n",
- " \"MAY\",\n",
- " \"JUN\",\n",
- " \"JUL\",\n",
- " \"AUG\",\n",
- " \"SEP\",\n",
- " \"OCT\",\n",
- " \"NOV\",\n",
- " \"DEC\",\n",
- "]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 26,
- "id": "45499c97-d399-4f49-82bc-c08dc2969668",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Calculating model ensemble mean, minimum and maximum\n",
- "df_model_max = df_model.max(axis=1)\n",
- "df_model_min = df_model.min(axis=1)\n",
- "df_model_mn = df_model.mean(axis=1)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 27,
- "id": "b338c195-f48d-4e7b-b4b7-29c573222766",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "image/png": "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\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "needs_background": "light"
- },
- "output_type": "display_data"
- }
- ],
- "source": [
- "# Plotting monthly climatology of Daily Maximum Air Temperature from COSMOS station ALIC1 and nearest grid point on CHESS-SCAPE averaged over 2016--2022\n",
- "fig = plt.figure(figsize=(10, 6))\n",
- "plt.plot(months, df_site.values, color=\"k\", lw=3, label=\"OBSERVED\")\n",
- "plt.plot(months, df_model_mn.values, color=\"b\", ls=\"--\", lw=2, label=\"MODEL MEAN\")\n",
- "plt.fill_between(\n",
- " months,\n",
- " df_model_min.values,\n",
- " df_model_max.values,\n",
- " color=\"b\",\n",
- " alpha=0.3,\n",
- " label=\"MODEL SPREAD\",\n",
- ")\n",
- "plt.ylabel(\"Daily Maximum Air Temperature ($^\\circ$C)\", fontsize=15)\n",
- "plt.yticks(np.arange(7, 26, 2), fontsize=15)\n",
- "plt.xticks(fontsize=15)\n",
- "plt.legend(loc=\"upper left\", fontsize=15)\n",
- "plt.title(site_nm + \" - Monthly Climatology 2016 - 2022\", fontsize=20)\n",
- "plt.show()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "e2acb35c-e750-439a-bcd0-2ee1b324a185",
- "metadata": {},
- "outputs": [],
- "source": []
- }
- ],
- "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.6"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/notebooks/catalogue_temperature.yaml b/notebooks/catalogue_temperature.yaml
deleted file mode 100644
index e0b54d0..0000000
--- a/notebooks/catalogue_temperature.yaml
+++ /dev/null
@@ -1,45 +0,0 @@
-sources:
- e01_tmax_year100km:
- description: Maximum Temperature for ens-01 in yearly 100km chunks
- driver: zarr
- args:
- urlpath: 's3://ens01-year100kmchunk/tmax_01_year100km.zarr'
- consolidated: False
- storage_options:
- anon: True
- use_ssl: True
- client_kwargs:
- endpoint_url: 'https://chess-scape-o.s3-ext.jc.rl.ac.uk'
- e04_tmax_year100km:
- description: Maximum Temperature for ens-04 in yearly 100km chunks
- driver: zarr
- args:
- urlpath: 's3://ens04-year100kmchunk/tmax_04_year100km.zarr'
- consolidated: False
- storage_options:
- anon: True
- use_ssl: True
- client_kwargs:
- endpoint_url: 'https://chess-scape-o.s3-ext.jc.rl.ac.uk'
- e06_tmax_year100km:
- description: Maximum Temperature for ens-06 in yearly 100km chunks
- driver: zarr
- args:
- urlpath: 's3://ens06-year100kmchunk/tmax_06_year100km.zarr'
- consolidated: False
- storage_options:
- anon: True
- use_ssl: True
- client_kwargs:
- endpoint_url: 'https://chess-scape-o.s3-ext.jc.rl.ac.uk'
- e15_tmax_year100km:
- description: Maximum Temperature for ens-15 in yearly 100km chunks
- driver: zarr
- args:
- urlpath: 's3://ens15-year100kmchunk/tmax_15_year100km.zarr'
- consolidated: False
- storage_options:
- anon: True
- use_ssl: True
- client_kwargs:
- endpoint_url: 'https://chess-scape-o.s3-ext.jc.rl.ac.uk'
diff --git a/notebooks/pangeo-forge_testing.ipynb b/notebooks/pangeo-forge_testing.ipynb
deleted file mode 100644
index ab261bf..0000000
--- a/notebooks/pangeo-forge_testing.ipynb
+++ /dev/null
@@ -1,837 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "a46a32ac-ba6f-4e52-ad08-a8d3a67a24ad",
- "metadata": {},
- "outputs": [],
- "source": [
- "import os\n",
- "import s3fs\n",
- "import xarray as xr\n",
- "import apache_beam as beam\n",
- "from pangeo_forge_recipes.storage import FSSpecTarget\n",
- "from pangeo_forge_recipes.patterns import ConcatDim, FilePattern\n",
- "from pangeo_forge_recipes.transforms import OpenWithXarray, StoreToZarr"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "8ce7e6df-b098-42dc-8684-d8f195116f49",
- "metadata": {},
- "source": [
- "Example notebook for converting and rechunking gridded netcdf data ready for object storage, using pangeo-forge-recipes. Please note that his notebook is intended to serve as an example only, and be adapted for your own datasets."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "76190116-7090-4590-9204-dbb0a4c756bc",
- "metadata": {},
- "source": [
- "The files are organised as one file per RCM/ensemble member (12 in total)."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "c31a048f-9a69-41bb-a817-8bfc4fe63349",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "G2G_DailyRiverFlow_NATURAL_RCM01_19801201_20801130.nc\n",
- "G2G_DailyRiverFlow_NATURAL_RCM04_19801201_20801130.nc\n",
- "G2G_DailyRiverFlow_NATURAL_RCM05_19801201_20801130.nc\n",
- "G2G_DailyRiverFlow_NATURAL_RCM06_19801201_20801130.nc\n",
- "G2G_DailyRiverFlow_NATURAL_RCM07_19801201_20801130.nc\n",
- "G2G_DailyRiverFlow_NATURAL_RCM08_19801201_20801130.nc\n",
- "G2G_DailyRiverFlow_NATURAL_RCM09_19801201_20801130.nc\n",
- "G2G_DailyRiverFlow_NATURAL_RCM10_19801201_20801130.nc\n",
- "G2G_DailyRiverFlow_NATURAL_RCM11_19801201_20801130.nc\n",
- "G2G_DailyRiverFlow_NATURAL_RCM12_19801201_20801130.nc\n",
- "G2G_DailyRiverFlow_NATURAL_RCM13_19801201_20801130.nc\n",
- "G2G_DailyRiverFlow_NATURAL_RCM15_19801201_20801130.nc\n"
- ]
- }
- ],
- "source": [
- "!ls ../data/G2G/preproc"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "f57856bb-aa4b-4542-ab07-9d1388138ffe",
- "metadata": {},
- "source": [
- "One of the files looks like:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "568dff82-3780-4f4b-9073-1efb56a5d098",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "netcdf G2G_DailyRiverFlow_NATURAL_RCM01_19801201_20801130 {\n",
- "dimensions:\n",
- "\tTime = UNLIMITED ; // (36000 currently)\n",
- "\tRCM = 1 ;\n",
- "\tNorthing = 1000 ;\n",
- "\tEasting = 700 ;\n",
- "variables:\n",
- "\tstring RCM(RCM) ;\n",
- "\tfloat Northing(Northing) ;\n",
- "\t\tNorthing:_FillValue = NaNf ;\n",
- "\t\tNorthing:standard_name = \"Northing\" ;\n",
- "\t\tNorthing:axis = \"Y\" ;\n",
- "\t\tNorthing:units = \"GB National Grid\" ;\n",
- "\tfloat Easting(Easting) ;\n",
- "\t\tEasting:_FillValue = NaNf ;\n",
- "\t\tEasting:standard_name = \"Easting\" ;\n",
- "\t\tEasting:axis = \"X\" ;\n",
- "\t\tEasting:units = \"GB National Grid\" ;\n",
- "\tfloat Time(Time) ;\n",
- "\t\tTime:_FillValue = NaNf ;\n",
- "\t\tTime:standard_name = \"Time\" ;\n",
- "\t\tTime:axis = \"T\" ;\n",
- "\t\tTime:units = \"days since 1961-01-01\" ;\n",
- "\t\tTime:calendar = \"360_day\" ;\n",
- "\tfloat dmflow(RCM, Time, Northing, Easting) ;\n",
- "\t\tdmflow:_FillValue = -999.f ;\n",
- "\t\tdmflow:units = \"m3 s-1\" ;\n",
- "\t\tdmflow:standard_name = \"dmflow\" ;\n",
- "\t\tdmflow:long_name = \"Daily mean river flow\" ;\n",
- "\t\tdmflow:missing_value = -999.f ;\n",
- "}\n"
- ]
- }
- ],
- "source": [
- "!ncdump -h ../data/G2G/preproc/G2G_DailyRiverFlow_NATURAL_RCM01_19801201_20801130.nc"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "08611a59-ba4a-482b-bf24-c970b3b310cb",
- "metadata": {},
- "source": [
- "--- "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "9258e6ab-8955-4721-9d4b-50c515158dd2",
- "metadata": {},
- "source": [
- "First step is to define a 'ConcatDim' object/variable which contains the name of the dimension along which we want to concatenate the files, the values of the dimensions in the files (in the order that we'd like them contacatenate?) and the number of dimension elements within each file, if it is constant (e.g. for monthly files on a 360 calendar this would be 30). "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "35263bd5-cdc8-4285-8b67-3d73d3ad5b10",
- "metadata": {},
- "outputs": [],
- "source": [
- "RCMs = [\"01\", \"04\", \"05\", \"06\", \"07\", \"08\", \"09\", \"10\", \"11\", \"12\", \"13\", \"15\"]\n",
- "RCM_concat_dim = ConcatDim(\"RCM\", RCMs, nitems_per_file=1)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "69a0d33a-381e-42af-a3dc-0b51e3a03035",
- "metadata": {},
- "source": [
- "Next, we define the function that translates a given RCM into a file path. The function must have the same number of arguments as the number of Combine Dimensions and the name of the argument must match the name of the the Combine Dimension."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "2947483a-ee40-4ffb-8aa5-d86b9e17dd9b",
- "metadata": {},
- "outputs": [],
- "source": [
- "indir = \"/home/users/mattjbr/object_storage/data/G2G/preproc\"\n",
- "pre = \"G2G_DailyRiverFlow_NATURAL_RCM\"\n",
- "suf = \"_19801201_20801130.nc\"\n",
- "\n",
- "\n",
- "def make_path(RCM):\n",
- " return os.path.join(indir, pre + RCM + suf)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ce5eabc2-9bb8-4a87-8ccb-90d82318a56e",
- "metadata": {},
- "source": [
- "Then these are put into a FilePattern object"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "f996bf94-a0d2-4d6b-8a52-135795528084",
- "metadata": {},
- "outputs": [],
- "source": [
- "pattern = FilePattern(make_path, RCM_concat_dim)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "0e9ed41d-f70e-4a08-aa9c-dfeb673c1369",
- "metadata": {},
- "source": [
- "Next, we prune the FilePattern for testing"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "id": "62469968-65c1-4839-8c78-07dcd55d3436",
- "metadata": {},
- "outputs": [],
- "source": [
- "pattern_pruned = pattern.prune()"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "abc38e31-3665-466a-a38b-cd78a901d668",
- "metadata": {},
- "source": [
- "And create the test recipe, outputting to local disk, and specifying the chunks to rechunk the dataset to"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "534fe305-f59f-4a12-9286-929b96b74578",
- "metadata": {},
- "outputs": [],
- "source": [
- "target_root = (\n",
- " \"/users/sgsys/matbro/object_storage/object_storage/data/output\" ## output folder\n",
- ")\n",
- "tn = \"test.zarr\" ## output filename\n",
- "\n",
- "target_chunks = {\n",
- " \"RCM\": 1,\n",
- " \"Time\": 360,\n",
- " \"Northing\": 100,\n",
- " \"Easting\": 100,\n",
- "} ## length of each dimension of the desired chunks\n",
- "\n",
- "transforms = (\n",
- " beam.Create(pattern_pruned.items())\n",
- " | OpenWithXarray(file_type=pattern_pruned.file_type)\n",
- " | StoreToZarr(\n",
- " target_root=target_root,\n",
- " store_name=tn,\n",
- " combine_dims=pattern.combine_dim_keys,\n",
- " target_chunks=target_chunks,\n",
- " )\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "442dd386-fc63-418c-8bca-8e5d69eceb32",
- "metadata": {},
- "source": [
- "Run the recipe in parallel"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "f420e4cb-6750-48a6-82ce-1cae2fd5d5d8",
- "metadata": {},
- "outputs": [],
- "source": [
- "from apache_beam.options.pipeline_options import PipelineOptions\n",
- "\n",
- "beam_options = PipelineOptions(\n",
- " direct_num_workers=8, direct_running_mode=\"multi_processing\"\n",
- ")\n",
- "with beam.Pipeline(options=beam_options) as p:\n",
- " p | transforms"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "7e42995e-3219-4fe3-abc5-dd4cd577d2e1",
- "metadata": {},
- "source": [
- "Alternatively, the converted dataset can be output direct to object storage, however this is quite buggy with the beam's 'Direct' runner, and tends to stall out. Future work will look at using beam's other runners."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "593ec147-47c3-43a6-b039-cd29bb233bf6",
- "metadata": {},
- "outputs": [],
- "source": [
- "fs = s3fs.S3FileSystem(\n",
- " anon=False,\n",
- " key=\"xxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n",
- " secret=\"yyyyyyyyyyyyyyyyyyyyyyyyyyy\",\n",
- " client_kwargs={\"endpoint_url\": \"https://chess-scape-o.s3-ext.jc.rl.ac.uk\"},\n",
- ")\n",
- "\n",
- "target_root = FSSpecTarget(fs=fs, root_path=\"s3://g2g-test\")\n",
- "tn = \"test.zarr\"\n",
- "\n",
- "target_chunks = {\n",
- " \"RCM\": 1,\n",
- " \"Time\": 360,\n",
- " \"Northing\": 100,\n",
- " \"Easting\": 100,\n",
- "} ## length of each dimension of the desired chunks\n",
- "\n",
- "transforms = (\n",
- " beam.Create(pattern_pruned.items())\n",
- " | OpenWithXarray(file_type=pattern_pruned.file_type)\n",
- " | StoreToZarr(\n",
- " target_root=target_root,\n",
- " store_name=tn,\n",
- " combine_dims=pattern.combine_dim_keys,\n",
- " target_chunks=target_chunks,\n",
- " )\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "dbc8638e-a6b4-43ad-88df-cf63825812d6",
- "metadata": {},
- "source": [
- "-------------"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "2839cf2d-bee7-4620-8354-71dccbfd4ada",
- "metadata": {},
- "source": [
- "Check the output dataset:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "id": "8f4542fa-159d-4540-967a-b555aad5c473",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "
<xarray.Dataset>\n",
- "Dimensions: (Easting: 700, Northing: 1000, RCM: 2, Time: 36000)\n",
- "Coordinates:\n",
- " * Easting (Easting) float32 500.0 1.5e+03 2.5e+03 ... 6.985e+05 6.995e+05\n",
- " * Northing (Northing) float32 9.995e+05 9.985e+05 9.975e+05 ... 1.5e+03 500.0\n",
- " * RCM (RCM) int64 1 4\n",
- " * Time (Time) object 1980-12-01 00:00:00 ... 2080-11-30 00:00:00\n",
- "Data variables:\n",
- " dmflow (RCM, Time, Northing, Easting) float32 ... Dimensions: Easting : 700Northing : 1000RCM : 2Time : 36000
Coordinates: (4)
Easting
(Easting)
float32
500.0 1.5e+03 ... 6.995e+05
axis : X standard_name : Easting units : GB National Grid array([5.000e+02, 1.500e+03, 2.500e+03, ..., 6.975e+05, 6.985e+05, 6.995e+05],\n",
- " dtype=float32) Northing
(Northing)
float32
9.995e+05 9.985e+05 ... 500.0
axis : Y standard_name : Northing units : GB National Grid array([9.995e+05, 9.985e+05, 9.975e+05, ..., 2.500e+03, 1.500e+03, 5.000e+02],\n",
- " dtype=float32) RCM
(RCM)
int64
1 4
Time
(Time)
object
1980-12-01 00:00:00 ... 2080-11-...
axis : T standard_name : Time array([cftime.Datetime360Day(1980, 12, 1, 0, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(1980, 12, 2, 0, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(1980, 12, 3, 0, 0, 0, 0, has_year_zero=True), ...,\n",
- " cftime.Datetime360Day(2080, 11, 28, 0, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(2080, 11, 29, 0, 0, 0, 0, has_year_zero=True),\n",
- " cftime.Datetime360Day(2080, 11, 30, 0, 0, 0, 0, has_year_zero=True)],\n",
- " dtype=object) Data variables: (1)
Indexes: (4)
PandasIndex
PandasIndex(Float64Index([ 500.0, 1500.0, 2500.0, 3500.0, 4500.0, 5500.0,\n",
- " 6500.0, 7500.0, 8500.0, 9500.0,\n",
- " ...\n",
- " 690500.0, 691500.0, 692500.0, 693500.0, 694500.0, 695500.0,\n",
- " 696500.0, 697500.0, 698500.0, 699500.0],\n",
- " dtype='float64', name='Easting', length=700)) PandasIndex
PandasIndex(Float64Index([999500.0, 998500.0, 997500.0, 996500.0, 995500.0, 994500.0,\n",
- " 993500.0, 992500.0, 991500.0, 990500.0,\n",
- " ...\n",
- " 9500.0, 8500.0, 7500.0, 6500.0, 5500.0, 4500.0,\n",
- " 3500.0, 2500.0, 1500.0, 500.0],\n",
- " dtype='float64', name='Northing', length=1000)) PandasIndex
PandasIndex(Int64Index([1, 4], dtype='int64', name='RCM')) PandasIndex
PandasIndex(CFTimeIndex([1980-12-01 00:00:00, 1980-12-02 00:00:00, 1980-12-03 00:00:00,\n",
- " 1980-12-04 00:00:00, 1980-12-05 00:00:00, 1980-12-06 00:00:00,\n",
- " 1980-12-07 00:00:00, 1980-12-08 00:00:00, 1980-12-09 00:00:00,\n",
- " 1980-12-10 00:00:00,\n",
- " ...\n",
- " 2080-11-21 00:00:00, 2080-11-22 00:00:00, 2080-11-23 00:00:00,\n",
- " 2080-11-24 00:00:00, 2080-11-25 00:00:00, 2080-11-26 00:00:00,\n",
- " 2080-11-27 00:00:00, 2080-11-28 00:00:00, 2080-11-29 00:00:00,\n",
- " 2080-11-30 00:00:00],\n",
- " dtype='object', length=36000, calendar='360_day', freq='D')) Attributes: (0)
"
- ],
- "text/plain": [
- "\n",
- "Dimensions: (Easting: 700, Northing: 1000, RCM: 2, Time: 36000)\n",
- "Coordinates:\n",
- " * Easting (Easting) float32 500.0 1.5e+03 2.5e+03 ... 6.985e+05 6.995e+05\n",
- " * Northing (Northing) float32 9.995e+05 9.985e+05 9.975e+05 ... 1.5e+03 500.0\n",
- " * RCM (RCM) int64 1 4\n",
- " * Time (Time) object 1980-12-01 00:00:00 ... 2080-11-30 00:00:00\n",
- "Data variables:\n",
- " dmflow (RCM, Time, Northing, Easting) float32 ..."
- ]
- },
- "execution_count": 11,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "xr.open_dataset(\"/work/scratch-pw2/mattjbr/testoutput.zarr\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 15,
- "id": "92271486-2187-442d-804d-8f1624d454f7",
- "metadata": {},
- "outputs": [],
- "source": [
- "import zarr\n",
- "\n",
- "tzar = zarr.open(\"/work/scratch-pw2/mattjbr/testoutput.zarr/dmflow\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 16,
- "id": "4eca21b0-26b0-4754-9d82-cb75b985d267",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "Type zarr.core.Array Data type float32 Shape (2, 36000, 1000, 700) Chunk shape (1, 360, 100, 100) Order C Read-only False Compressor Blosc(cname='lz4', clevel=5, shuffle=SHUFFLE, blocksize=0) Store type zarr.storage.DirectoryStore No. bytes 201600000000 (187.8G) No. bytes stored 31345654783 (29.2G) Storage ratio 6.4 Chunks initialized 14000/14000
"
- ],
- "text/plain": [
- "Type : zarr.core.Array\n",
- "Data type : float32\n",
- "Shape : (2, 36000, 1000, 700)\n",
- "Chunk shape : (1, 360, 100, 100)\n",
- "Order : C\n",
- "Read-only : False\n",
- "Compressor : Blosc(cname='lz4', clevel=5, shuffle=SHUFFLE, blocksize=0)\n",
- "Store type : zarr.storage.DirectoryStore\n",
- "No. bytes : 201600000000 (187.8G)\n",
- "No. bytes stored : 31345654783 (29.2G)\n",
- "Storage ratio : 6.4\n",
- "Chunks initialized : 14000/14000"
- ]
- },
- "execution_count": 16,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "tzar.info"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "05fc5ff2-9411-4d53-962d-8c01811c2fe8",
- "metadata": {},
- "outputs": [],
- "source": []
- }
- ],
- "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.16"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/scripts/G2G/convert_G2G_beam.sbatch b/scripts/G2G/convert_G2G_beam.sbatch
index 29fb3da..54ddb50 100644
--- a/scripts/G2G/convert_G2G_beam.sbatch
+++ b/scripts/G2G/convert_G2G_beam.sbatch
@@ -14,4 +14,4 @@ export PATH=/home/users/mattjbr/miniconda3/bin:$PATH
source /home/users/mattjbr/miniconda3/bin/activate apache
# run script
-/home/users/mattjbr/miniconda3/envs/apache/bin/ipython /gws/nopw/j04/ceh_generic/matbro/object_storage/scripts/convert_G2G_beam.py
+/home/users/mattjbr/miniconda3/envs/apache/bin/ipython /gws/nopw/j04/ceh_generic/matbro/dri_gridded_data/scripts/G2G/convert_G2G_beam.py
diff --git a/scripts/convert_GEAR_beam.sbatch b/scripts/GEAR/convert_GEAR_beam.sbatch
similarity index 88%
rename from scripts/convert_GEAR_beam.sbatch
rename to scripts/GEAR/convert_GEAR_beam.sbatch
index 5a9638a..2515ddb 100644
--- a/scripts/convert_GEAR_beam.sbatch
+++ b/scripts/GEAR/convert_GEAR_beam.sbatch
@@ -14,4 +14,4 @@ export PATH=/home/users/mattjbr/miniconda3/bin:$PATH
source /home/users/mattjbr/miniconda3/bin/activate gear
# run script, ensuring correct env is picked up
-/home/users/mattjbr/miniconda3/envs/gear/bin/ipython /gws/nopw/j04/fdri/users/matbro/dri_gridded_data/scripts/convert_GEAR_beam.py
+/home/users/mattjbr/miniconda3/envs/gear/bin/ipython /gws/nopw/j04/fdri/users/matbro/dri_gridded_data/scripts/GEAR/convert_GEAR_beam.py