From f0ebf5582c88cf877993b60ad5de3fb89d73bdf1 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Thu, 30 Mar 2023 09:39:35 +0200 Subject: [PATCH 01/77] add ptolemy as a dep --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index c7d2275..13fe652 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,6 +57,9 @@ lint = [ "black", "ruff" ] +geo = [ + "ptolemy-iamc @ git+https://github.com/gidden/ptolemy.git", +] [project.scripts] aneris = "aneris.cli:main" From 2c803deb39d327bad6c1a6d2a1807d98cd3cca61 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Mon, 3 Apr 2023 10:08:29 +0200 Subject: [PATCH 02/77] add initial gridding routine --- pyproject.toml | 3 ++ src/aneris/errors.py | 18 +++++++++++ src/aneris/grid.py | 75 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 src/aneris/grid.py diff --git a/pyproject.toml b/pyproject.toml index 13fe652..c1218be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,6 +59,9 @@ lint = [ ] geo = [ "ptolemy-iamc @ git+https://github.com/gidden/ptolemy.git", + "pycountry", + "xarray", + "dask", ] [project.scripts] diff --git a/src/aneris/errors.py b/src/aneris/errors.py index 583a717..36de0f3 100644 --- a/src/aneris/errors.py +++ b/src/aneris/errors.py @@ -20,3 +20,21 @@ class MissingHarmonisationYear(ValueError): """ Error raised when the harmonisation year is missing. """ + + +class MissingColumns(ValueError): + """ + Error raised when a column of dataframe is expected but missing. + """ + + +class MissingDimension(ValueError): + """ + Error raised when a spatial dimension is expected but missing. + """ + + +class MissingCoordinateValue(ValueError): + """ + Error raised when a spatial dimension is expected but missing. + """ diff --git a/src/aneris/grid.py b/src/aneris/grid.py new file mode 100644 index 0000000..8a358e9 --- /dev/null +++ b/src/aneris/grid.py @@ -0,0 +1,75 @@ +import numpy as np +import ptolemy as pt +import pycountry +import xarray as xr + +from aneris import utils +from aneris.errors import MissingColumns, MissingCoordinateValue, MissingDimension + + +def check_coord_overlap( + x, y, coord, x_strict=False, y_strict=False, strict=False, warn=False +): + x, y = set(np.unique(x[coord])), set(np.unique(y[coord])) + msg = "" + if strict: + x_strict, y_strict = True, True + if x_strict and x - y: + missing = x - y + if coord == "iso": + missing = [pycountry.countries.get(alpha_3=c).name for c in missing] + msg += f"Missing from x {coord}: {missing}\n" + if y_strict and y - x: + missing = y - x + if coord == "iso": + missing = [pycountry.countries.get(alpha_3=c).name for c in missing] + msg += f"Missing from y {coord}: {missing}\n" + if msg and not warn: + raise MissingCoordinateValue(msg) + elif msg and warn: + utils.logger().warning(msg) + + +def grid( + df, + proxy, + idx_raster, + value_col="value", + shape_col="iso", + extra_coords=["year", "gas", "sector"], + as_flux=False, +): + # TODO: add docstrings + # Note that area normalization has been kept with `as_flux`, but other unit conversions need to happen outside + # this function: kg_per_mt = 1e9, s_per_yr = 365 * 24 * 60 * 60 + # Otherwise, operates as currently in `prototype_gridding.ipynb` + df_dim_diff = set(extra_coords + [value_col, shape_col]).difference(set(df.columns)) + if df_dim_diff: + raise MissingColumns(f"df missing columns: {df_dim_diff}") + proxy_dim_diff = set(extra_coords + ["lat", "lon"]).difference(set(proxy.dims)) + if proxy_dim_diff: + raise MissingDimension(f"proxy missing dimensions: {proxy_dim_diff}") + idxr_dim_diff = set([shape_col] + ["lat", "lon"]).difference(set(idx_raster.dims)) + if idxr_dim_diff: + raise MissingDimension(f"idx_raster missing dimensions: {idxr_dim_diff}") + + map_data = pt.df_to_weighted_raster( + df, + xr.where(idx_raster > 0, 1, np.nan), + col=value_col, + extra_coords=extra_coords, + ) + weighted_proxy = idx_raster * proxy + normalized_proxy = weighted_proxy / weighted_proxy.sum(dim=["lat", "lon"]) + + for coord in ["gas", "sector", "year"]: + check_coord_overlap(normalized_proxy, map_data, coord, strict=True) + # warn here because sometimes we have more small countries than data + check_coord_overlap(normalized_proxy, map_data, "iso", x_strict=True, warn=True) + check_coord_overlap(normalized_proxy, map_data, "iso", y_strict=True) + + result = (map_data * normalized_proxy).sum(dim="iso")[value_col] + if as_flux: + lat_areas_in_m2 = xr.DataArray.from_series(pt.cell_area_from_file(proxy)) + result /= lat_areas_in_m2 + return result From 53131c8d9f980a89fd23a5191971219ca628ec30 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Mon, 3 Apr 2023 10:12:41 +0200 Subject: [PATCH 03/77] some clean up with remaining iso col --- src/aneris/grid.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 8a358e9..f32507a 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -7,13 +7,10 @@ from aneris.errors import MissingColumns, MissingCoordinateValue, MissingDimension -def check_coord_overlap( - x, y, coord, x_strict=False, y_strict=False, strict=False, warn=False -): +def check_coord_overlap(x, y, coord, x_strict=False, y_strict=False, warn=False): + # TODO: add docs and try to generalize iso coord logic x, y = set(np.unique(x[coord])), set(np.unique(y[coord])) msg = "" - if strict: - x_strict, y_strict = True, True if x_strict and x - y: missing = x - y if coord == "iso": @@ -62,13 +59,15 @@ def grid( weighted_proxy = idx_raster * proxy normalized_proxy = weighted_proxy / weighted_proxy.sum(dim=["lat", "lon"]) - for coord in ["gas", "sector", "year"]: - check_coord_overlap(normalized_proxy, map_data, coord, strict=True) + for coord in extra_coords: + check_coord_overlap( + normalized_proxy, map_data, coord, x_strict=True, y_strict=True + ) + check_coord_overlap(normalized_proxy, map_data, shape_col, y_strict=True) # warn here because sometimes we have more small countries than data - check_coord_overlap(normalized_proxy, map_data, "iso", x_strict=True, warn=True) - check_coord_overlap(normalized_proxy, map_data, "iso", y_strict=True) + check_coord_overlap(normalized_proxy, map_data, shape_col, x_strict=True, warn=True) - result = (map_data * normalized_proxy).sum(dim="iso")[value_col] + result = (map_data * normalized_proxy).sum(dim=shape_col)[value_col] if as_flux: lat_areas_in_m2 = xr.DataArray.from_series(pt.cell_area_from_file(proxy)) result /= lat_areas_in_m2 From d4ca804a54cc42827d2c0266ddc375bdfd4c3b76 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Mon, 3 Apr 2023 10:13:49 +0200 Subject: [PATCH 04/77] stickler --- src/aneris/grid.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index f32507a..f3899a5 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -37,8 +37,9 @@ def grid( as_flux=False, ): # TODO: add docstrings - # Note that area normalization has been kept with `as_flux`, but other unit conversions need to happen outside - # this function: kg_per_mt = 1e9, s_per_yr = 365 * 24 * 60 * 60 + # Note that area normalization has been kept with `as_flux`, + # but other unit conversions need to happen outside this function: + # kg_per_mt = 1e9, s_per_yr = 365 * 24 * 60 * 60 # Otherwise, operates as currently in `prototype_gridding.ipynb` df_dim_diff = set(extra_coords + [value_col, shape_col]).difference(set(df.columns)) if df_dim_diff: From 83e8c6c41d9f8d71e6ae14a0747a3cc85a16744b Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Tue, 11 Apr 2023 15:43:52 +0200 Subject: [PATCH 05/77] update for xarray reqs --- src/aneris/grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index f3899a5..f8f2ba1 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -71,5 +71,5 @@ def grid( result = (map_data * normalized_proxy).sum(dim=shape_col)[value_col] if as_flux: lat_areas_in_m2 = xr.DataArray.from_series(pt.cell_area_from_file(proxy)) - result /= lat_areas_in_m2 + result = result / lat_areas_in_m2 return result From 00d96f277942f33c120854cd3f164e6b9548980a Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Tue, 11 Apr 2023 15:44:19 +0200 Subject: [PATCH 06/77] add example notebook --- notebooks/grid.ipynb | 1794 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1794 insertions(+) create mode 100644 notebooks/grid.ipynb diff --git a/notebooks/grid.ipynb b/notebooks/grid.ipynb new file mode 100644 index 0000000..60feb75 --- /dev/null +++ b/notebooks/grid.ipynb @@ -0,0 +1,1794 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "d11922d5", + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": [ + "if (typeof IPython !== 'undefined') { IPython.OutputArea.prototype._should_scroll = function(lines){ return false; }}" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import pyam\n", + "\n", + "import numpy as np\n", + "import xarray as xr\n", + "\n", + "from aneris.grid import grid\n", + "from pathlib import Path" + ] + }, + { + "cell_type": "markdown", + "id": "c8ae2da3", + "metadata": {}, + "source": [ + "# Data Set Up" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "8d2a7ee1", + "metadata": {}, + "outputs": [], + "source": [ + "base_path = Path(\n", + " \"C:/Users/gidden/IIASA/RESCUE - Documents/WP 1/data/gridding_process_files\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9d3b2ee0", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\gidden\\Miniconda3\\envs\\aneris\\lib\\site-packages\\xarray\\backends\\plugins.py:71: RuntimeWarning: Engine 'cfgrib' loading failed:\n", + "Cannot find the ecCodes library\n", + " warnings.warn(f\"Engine {name!r} loading failed:\\n{ex}\", RuntimeWarning)\n", + "pyam - INFO: Running in a notebook, setting up a basic logging at level INFO\n", + "pyam.core - INFO: Reading file C:\\Users\\gidden\\IIASA\\RESCUE - Documents\\WP 1\\data\\gridding_process_files\\..\\iam_files\\cmip6\\REMIND-MAGPIE_SSP5-34-OS\\B.REMIND-MAGPIE_Harmonized-DB_emissions_downscaled.csv\n" + ] + } + ], + "source": [ + "idxr = xr.open_dataarray(base_path / \"iso_mask.nc\", chunks={\"iso\": 10})\n", + "proxy = xr.open_dataarray(\n", + " base_path / \"proxy_rasters/anthro_CO2.nc\", chunks={\"year\": 1, \"sector\": 1}\n", + ")\n", + "df = pyam.IamDataFrame(\n", + " base_path\n", + " / \"../iam_files/cmip6/REMIND-MAGPIE_SSP5-34-OS/B.REMIND-MAGPIE_Harmonized-DB_emissions_downscaled.csv\",\n", + " region=\"iso\",\n", + ").data" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "0fa05620", + "metadata": {}, + "outputs": [], + "source": [ + "sector_mapping = {\n", + " \"Aircraft\": \"AIR\",\n", + " \"International Shipping\": \"SHP\",\n", + " \"Agricultural Waste Burning\": \"AWB\",\n", + " \"Agriculture\": \"AGR\",\n", + " \"Energy Sector\": \"ENE\",\n", + " \"Forest Burning\": \"FRTB\",\n", + " \"Grassland Burning\": \"GRSB\",\n", + " \"Industrial Sector\": \"IND\",\n", + " \"Peat Burning\": \"PEAT\",\n", + " \"Residential Commercial Other\": \"RCO\",\n", + " \"Solvents Production and Application\": \"SLV\",\n", + " \"Transportation Sector\": \"TRA\",\n", + " \"Waste\": \"WST\",\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "2dd23f33", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\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", + "
modelscenarioisovariableunityearvaluegassector
410REMIND-MAGPIESSP5-34-OS-V25abwCEDS+|9+ Sectors|Emissions|CO2|Agriculture|Har...Mt CO2/yr20150.0CO2AGR
411REMIND-MAGPIESSP5-34-OS-V25abwCEDS+|9+ Sectors|Emissions|CO2|Agriculture|Har...Mt CO2/yr20200.0CO2AGR
412REMIND-MAGPIESSP5-34-OS-V25abwCEDS+|9+ Sectors|Emissions|CO2|Agriculture|Har...Mt CO2/yr20300.0CO2AGR
413REMIND-MAGPIESSP5-34-OS-V25abwCEDS+|9+ Sectors|Emissions|CO2|Agriculture|Har...Mt CO2/yr20400.0CO2AGR
414REMIND-MAGPIESSP5-34-OS-V25abwCEDS+|9+ Sectors|Emissions|CO2|Agriculture|Har...Mt CO2/yr20500.0CO2AGR
\n", + "
" + ], + "text/plain": [ + " model scenario iso \\\n", + "410 REMIND-MAGPIE SSP5-34-OS-V25 abw \n", + "411 REMIND-MAGPIE SSP5-34-OS-V25 abw \n", + "412 REMIND-MAGPIE SSP5-34-OS-V25 abw \n", + "413 REMIND-MAGPIE SSP5-34-OS-V25 abw \n", + "414 REMIND-MAGPIE SSP5-34-OS-V25 abw \n", + "\n", + " variable unit year \\\n", + "410 CEDS+|9+ Sectors|Emissions|CO2|Agriculture|Har... Mt CO2/yr 2015 \n", + "411 CEDS+|9+ Sectors|Emissions|CO2|Agriculture|Har... Mt CO2/yr 2020 \n", + "412 CEDS+|9+ Sectors|Emissions|CO2|Agriculture|Har... Mt CO2/yr 2030 \n", + "413 CEDS+|9+ Sectors|Emissions|CO2|Agriculture|Har... Mt CO2/yr 2040 \n", + "414 CEDS+|9+ Sectors|Emissions|CO2|Agriculture|Har... Mt CO2/yr 2050 \n", + "\n", + " value gas sector \n", + "410 0.0 CO2 AGR \n", + "411 0.0 CO2 AGR \n", + "412 0.0 CO2 AGR \n", + "413 0.0 CO2 AGR \n", + "414 0.0 CO2 AGR " + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[\"gas\"] = df.variable.apply(lambda x: x.split(\"|\")[3])\n", + "df[\"sector\"] = df.variable.apply(lambda x: x.split(\"|\")[4]).replace(sector_mapping)\n", + "data = df[\n", + " (df.sector.isin(np.unique(proxy.sector))) & (df.gas.isin(np.unique(proxy.gas)))\n", + "]\n", + "data = data.rename(columns={\"region\": \"iso\"})\n", + "data.head()" + ] + }, + { + "cell_type": "markdown", + "id": "85bf112a", + "metadata": {}, + "source": [ + "# Perform Calculation" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "97b36793", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\gidden\\Miniconda3\\envs\\aneris\\lib\\site-packages\\dask\\array\\core.py:4830: PerformanceWarning: Increasing number of chunks by factor of 24\n", + " result = blockwise(\n", + "root - WARNING: Missing from x iso: ['Pitcairn', 'Northern Mariana Islands', 'Tuvalu', 'Mayotte', 'Jersey', 'Guernsey', 'Bonaire, Sint Eustatius and Saba', 'San Marino', 'Monaco', 'Norfolk Island', 'Saint Helena, Ascension and Tristan da Cunha', 'Svalbard and Jan Mayen', 'Andorra', 'Anguilla', 'Isle of Man', 'Nauru']\n", + "\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray (year: 10, gas: 1, sector: 7, lat: 280, lon: 720, month: 12)>\n",
+       "dask.array<truediv, shape=(10, 1, 7, 280, 720, 12), dtype=float64, chunksize=(1, 1, 1, 280, 720, 12), chunktype=numpy.ndarray>\n",
+       "Coordinates:\n",
+       "  * year     (year) int64 2015 2020 2030 2040 2050 2060 2070 2080 2090 2100\n",
+       "  * gas      (gas) object 'CO2'\n",
+       "  * sector   (sector) object 'AGR' 'ENE' 'IND' 'RCO' 'SLV' 'TRA' 'WST'\n",
+       "  * lat      (lat) float64 -55.75 -55.25 -54.75 -54.25 ... 82.75 83.25 83.75\n",
+       "  * lon      (lon) float64 -179.8 -179.2 -178.8 -178.2 ... 178.8 179.2 179.8\n",
+       "  * month    (month) int32 1 2 3 4 5 6 7 8 9 10 11 12
" + ], + "text/plain": [ + "\n", + "dask.array\n", + "Coordinates:\n", + " * year (year) int64 2015 2020 2030 2040 2050 2060 2070 2080 2090 2100\n", + " * gas (gas) object 'CO2'\n", + " * sector (sector) object 'AGR' 'ENE' 'IND' 'RCO' 'SLV' 'TRA' 'WST'\n", + " * lat (lat) float64 -55.75 -55.25 -54.75 -54.25 ... 82.75 83.25 83.75\n", + " * lon (lon) float64 -179.8 -179.2 -178.8 -178.2 ... 178.8 179.2 179.8\n", + " * month (month) int32 1 2 3 4 5 6 7 8 9 10 11 12" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "kg_per_mt = 1e9\n", + "s_per_yr = 365 * 24 * 60 * 60\n", + "\n", + "ds = grid(data, proxy, idxr, as_flux=True) * kg_per_mt / s_per_yr\n", + "ds" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "16b52425", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\gidden\\Miniconda3\\envs\\aneris\\lib\\site-packages\\dask\\core.py:119: RuntimeWarning: invalid value encountered in divide\n", + " return func(*(_execute_task(a, cache) for a in args))\n" + ] + } + ], + "source": [ + "da = ds.sel(year=2015, sector=\"ENE\").mean(dim=\"month\").compute()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "25d27ed7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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TZuiWbNmqrbtSs1vV11djb59++L48eP4y1/+gmuvvRZ79uzBc889h927d+O///2vGDCNHDkSH3zwAUaNGoXp06fDarVi+/btOHLkCABg2bJl+P3vf4+UlBTMnTsXwJUiilOnTqF3796ora3F3/72N7Rq1QpffvklJk+ejIMHD4rzCyJ9TdrtdlXLm81mFBUVYfDgwVi0aJGqgFntukmUimh+DVFtwYIFDADbsWOHOO27777zyDrv0KED69atG6urq5Msf9ddd7HMzExJMYYru93O6urq2G233cZ++9vfitMPHz7MALA2bdqw2tpaVWnt27cvA+DzM2LECPU/QL3jx4+z9PR01r17d8m+jBkzhtlsNtll2rVrxwoKCmS/81WUM2XKFDZ37lz21Vdfsf/85z9swoQJzGKxsJtvvlnxt/Tm7NmzzGazsaFDh0qmb968mQHwmsUvHKNRo0axbt26idNfeeUVBoD9+uuvfqdHq2MlFL2sWrVK1XY7dOjAMjIyvM4zb948BoAtWbJEcZ63336bAWB///vfVW3XnZrfrqioiJlMJrZ161bJ9H//+98MAFuxYgVjjLENGzYwAGzKlClet6lUlPPMM88wAOzbb7+VTH/00UcZx3Fs3759jLHIX5Pe1jVq1ChxPqEoZ+nSpYwxxm688UbWokULdunSJcaYclGOmnWT6EY5JgZx//334+mnn8Y//vEPvP322wCcLVCaNm2KoUOHAnBW6vzpp5/wyiuvAJC+ddxxxx348ssvsW/fPnTs2BEAMH/+fLz11lv48ccfUVNTI87boUMHj+3/5je/QVxcnKq0vvnmmzh//rzP+dLS0lStT3D27FnccccdYIxhyZIlHm9Pctn8ar7zZsaMGZK/77jjDrRq1QqTJ0/G559/jt/+9rd+rW/Lli2oqanBvffeK5nes2dP2VYHS5cuxZw5c7Br1y5JsUF8fLz4byG37N5778WoUaPQp08fNG/eXFV6QnWstMDq3/CVjt3KlSsxfvx4/P73v8djjz0W0DbU/HZffvklOnfujK5du0quqf79+4PjOKxbtw4DBw7EypUrAQDjx48PKC1fffUVrr76arGoUjBy5EjMmzcPX331lSRHLZLXZJs2bfDxxx97TG/atKniMi+++CL69OmDv//973j66ac1XbdebdiwAS+//DJKSkpQVlaGZcuWqc5VDNSJEyfw9NNPY+XKlbh06RLatWuHf/7zn8jLywvpdrVEgYlB2Gw2PPLII3j11VfFcvd//etfmDRpkpgV/MsvvwAAJk+ejMmTJ8uu5/Tp0wCA2bNn48knn8TYsWPxt7/9DWlpaTCbzfjrX/+KvXv3eiyXmZmpOq1XXXWV6mxjtc6dO4f8/HycOHECX331FVq3bi35PjU1FZcvX0Z1dTUSExMl3509e1bTi/LBBx/E5MmTsWXLFr8DkzNnzgCAbL0K92mffvop7r33XgwZMgR//vOfkZGRAYvFgnnz5uHdd98V57v55pvx2Wef4bXXXsPw4cNRU1ODTp06YcqUKR5Ff+60OlYtW7YEABw+fNjnuoT59+/fj4sXL6JBgway8wjFH9nZ2R7frV69Gvfccw/y8/OxePHigANPNb/dL7/8ggMHDigGAcI1derUKZjNZmRkZASUljNnzsgGp1lZWeL3riJ5TQp1o/zRu3dv3H333XjhhRfwxz/+UdN169XFixfRpUsXPPTQQ/jd734X8u2dO3cOffr0wS233IKVK1eiWbNmOHjwoOFaEVJgYiCPPvooXnjhBbz77ru4fPky7HY7xo4dK34vvO0UFhbinnvukV1H+/btAQAffPAB+vXrh3nz5km+V3qr8ufGf9ttt2H9+vU+5xsxYoSq/hzOnTuH22+/HYcPH8b//vc/sQKlK6Fuye7du9GjRw9xenl5OU6fPo3OnTurTr9agZR3C5V5hSDSVXl5ueTB9MEHHyA3NxdLliyR/P6uuVuCwYMHY/DgwaipqcGWLVtQVFSEYcOGoVWrVujVq5dierQ6Vrfccgvi4uLw2WefSc5JJfn5+VizZg2++OIL3HfffR7fM8awfPlyNGnSxCOoXL16Ne6++2707dsXn3zyCaxWq8/teePrt0tLS0NCQoIkGHQlXHdNmzaFw+FAeXm5X0GDIDU1FWVlZR7TT548KdmOIJLXZKCKiorQuXNnzJo1K2Tb0JOBAwdi4MCBit/X1tbi2WefxeLFi/Hrr7+ic+fOePHFFz3q+Kn14osvIjs7GwsWLBCnGbH/FwpMDCQzMxNDhgzB3LlzUVtbi0GDBolvqoAz6Gjbti127drl88LnOM6jX4Dvv/8emzdvln1D9YeW2cZCUHLo0CEUFxejW7dusvMNGDAA8fHxWLhwoSQwWbhwITiO0zT7dNGiRQDgtUKmkh49esBms2HJkiWS4HHLli04evSo5CbCcRysVqvkAVReXi7bKkdgs9nEjuNWr16NHTt2eA1MtDpWGRkZGD16NObNm4f33ntPtmXOwYMHcfHiRVx77bUYPXo0Xn75ZRQWFuLWW2/1qLj60ksv4aeffsILL7wgyalYs2YN7r77btx444347LPPNO3bQum3u+uuuzBr1iykpqYiNzdXcfmBAweiqKgI8+bNw/Tp071u59KlSx7Tb7vtNhQVFWH79u247rrrxOlCy7tbbrkl4H3TS5Fdhw4d8PDDD+P1119H7969Q7otI3jooYdw5MgRfPzxx8jKysKyZcswYMAA7N6922tlZiXLly9H//79MWTIEKxfvx7NmzfHuHHjMGbMmBCkPoQiWcGF+O/bb78VK4P997//9fj+q6++YjabjRUUFLAPP/yQrV+/ni1btozNmjWL/f73vxfne+655xjHcey5555j//vf/9jcuXNZRkYGa9OmDcvJyRHnEyravfzyy+HYPYnq6mp2/fXXM47j2N///ne2efNmyefAgQOS+WfMmME4jmN/+ctf2Lp169jLL7/MbDYbGzNmjMe6ly5dypYuXcpefPFFBoCNHz9enCbYsGED69+/P5s/fz5bs2YNW758OXv00UeZ2Wxmt956q0fl15ycHMlvp6SwsJABYI888ghbtWoVe+edd1h2djbLzMxkt9xyizjfu+++ywCwRx99lP3vf/9jCxcuZG3atGFt27ZlrpfuX//6V/bQQw+xDz74gK1bt4599tln7JZbbmFxcXHshx9+UPtzB+3SpUusf//+jOM4NmzYMLZ06VK2YcMG9umnn7JHH32UxcfHs88++0yc/+uvv2aNGjViLVq0YH//+9/ZunXr2PLly9kDDzzAALChQ4dKfuONGzeyhIQE1qpVK/bVV195nA+VlZXivMJ566syp5rf7sKFC6xbt26sRYsW7NVXX2XFxcVs9erV7O2332ZDhgxhW7ZsEdf3hz/8gXEcx/74xz+y5cuXs9WrV7MXXniBvfbaa+I8I0aMYDabjX388cfsu+++Y99//z1jjLGKigrWvHlzlpGRwd566y22evVq9vjjjzOO49i4ceM89i0S1yRjzgqqrVu39vj9hY/AvfKr4MSJEywxMZEBkK38qmbdRgSALVu2TPz7wIEDjOM4duLECcl8t912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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "xr.where(da > 0, da, np.nan).plot()" + ] + }, + { + "cell_type": "markdown", + "id": "0b2b9a40", + "metadata": {}, + "source": [ + "# Check against previous data" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "47fefd84", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.DataArray 'CO2-em-anthro' (time: 120, sector: 7, lat: 360, lon: 720)>\n",
+       "dask.array<getitem, shape=(120, 7, 360, 720), dtype=float32, chunksize=(12, 1, 360, 720), chunktype=numpy.ndarray>\n",
+       "Coordinates:\n",
+       "  * lon      (lon) float64 -179.8 -179.2 -178.8 -178.2 ... 178.8 179.2 179.8\n",
+       "  * lat      (lat) float64 -89.75 -89.25 -88.75 -88.25 ... 88.75 89.25 89.75\n",
+       "  * sector   (sector) <U3 'AGR' 'ENE' 'IND' 'RCO' 'SLV' 'TRA' 'WST'\n",
+       "  * time     (time) object 2015-01-16 00:00:00 ... 2100-12-16 00:00:00\n",
+       "Attributes:\n",
+       "    units:         kg m-2 s-1\n",
+       "    cell_methods:  time: mean\n",
+       "    long_name:     CO2-em-anthro
" + ], + "text/plain": [ + "\n", + "dask.array\n", + "Coordinates:\n", + " * lon (lon) float64 -179.8 -179.2 -178.8 -178.2 ... 178.8 179.2 179.8\n", + " * lat (lat) float64 -89.75 -89.25 -88.75 -88.25 ... 88.75 89.25 89.75\n", + " * sector (sector) " + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAHFCAYAAAAUpjivAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/P9b71AAAACXBIWXMAAA9hAAAPYQGoP6dpAADB90lEQVR4nOydd3gUVffHv3d2k00PPQGpKtKRXqVLExE7CqIIov5QEVHw5UWkSFFURMUGomBHRV5FAY1UFVCpFhBFQIoJNSQhdXfn/v7YzGZ2dmZ3Znc2u8mez/PMk+zMnTtn2p1zzzn3XMY55yAIgiAIgqikCOEWgCAIgiAIIpSQskMQBEEQRKWGlB2CIAiCICo1pOwQBEEQBFGpIWWHIAiCIIhKDSk7BEEQBEFUakjZIQiCIAiiUkPKDkEQBEEQlRpSdgiCIAiCqNSQskNosn//fsycORNHjx4NtyiGadiwIRhjfpfly5cDgNf6lJQUdOvWDR9++KHmMc6ePQubzQbGGHbu3FlOZ1a52LhxI8aMGYOmTZsiMTERl1xyCYYNG4Zdu3aplt+9ezeuvvpqJCUloUqVKrjxxhtx+PBhr3KLFi3CjTfeiEaNGoExht69e6vWt3z5cs1nIysry8xTrTT88ssvuPvuu9GoUSPExcUhKSkJ7dq1w4IFC3D+/HmPsna7Ha+99hq6du2K1NRUxMfHo1mzZvjPf/6Dc+fOeZR1Op1YuHAhBg0ahLp16yIhIcFd9sKFC+V4hkRlxBpuAYjIZf/+/Zg1axZ69+6Nhg0bhlscQ6xevRrFxcXu32+++SaWLVuG9evXIzU11b3+sssuc/9/880349FHHwXnHEeOHMG8efMwYsQIcM4xYsQIr2O8++67KCkpAQAsW7YMHTp0COEZVU5ee+01nDt3Dg8//DCaN2+OM2fO4Pnnn0eXLl3w9ddfo2/fvu6yf/zxB3r37o02bdrg448/RlFREZ588kn06NEDe/fuRc2aNd1lX3/9dSQmJqJv375Ys2aNXznefvttNG3a1GNd9erVzTvRSsLSpUsxfvx4NGnSBJMnT0bz5s1ht9uxc+dOvP7669i+fTtWr14NACgoKMA111yD77//Hvfeey+mT5+O+Ph4bN++Hc899xw++OADZGRkoEmTJgCAwsJCzJw5E7fffjvuuece1KhRA7t378acOXOwZs0a7Ny5E/Hx8eE8faIiwwlCg08++YQD4Js2bTK13vz8fFPr08OMGTM4AH7mzBnV7QD4Aw884LHu6NGjHADv2bOn6j4tW7bktWrV4h07duSpqam8oKDAdLnDRXndo1OnTnmty8vL42lpabxfv34e62+55RZeo0YNnpOT41539OhRHhMTw6dMmeJR1ul0uv9v0aIF79Wrl+rx3377bQ6A//zzz0GcRXSwbds2brFY+KBBg3hRUZHX9uLiYv7555+7f997770cAP/oo4+8yh48eJCnpqbyFi1acIfDwTnn3OFw8LNnz3qVldqhd99918SzIaINcmNVIM6cOYN7770X9erVg81mQ82aNdG9e3d8++23HuW+/fZb9OvXDykpKUhISED37t2xYcMGr/r++OMP3H777UhLS4PNZkP9+vVx5513ori4GMuXL8ctt9wCAOjTp4+X2wcA3nrrLVx55ZWIi4tDtWrVcMMNN+DAgQMexxg9ejSSkpLw66+/YsCAAUhOTka/fv3MvzghoEGDBqhZsyZOnTrlte3HH3/Eb7/9hlGjRmHcuHHIycnBqlWrAjoO5xyNGzfGwIEDvbZdvHgRqampeOCBB9zrcnNz8dhjj6FRo0aIjY3FJZdcgokTJyI/P99j31deeQU9e/ZErVq1kJiYiFatWmHBggWw2+0e5Xr37o2WLVti69at6NatGxISEjBmzJiAzsUotWrV8lqXlJSE5s2b4/jx4+51DocDX375JW666SakpKS41zdo0AB9+vRxWxMkBCG8Tdv333+Prl27Ii4uDpdccgmmT5+ON998E4wxD7fwypUrMWDAANSuXdvDxaO8l4cPH8Ztt92GOnXqwGazIS0tDf369cPevXvL7ZzmzZsHxhiWLFkCm83mtT02NhbXXXcdACArKwtvvfUWBg4ciOHDh3uVveKKK/D444/j999/x//+9z8AgMViUbWmderUCQA8ngeCMAopOxWIUaNG4X//+x+efPJJfPPNN3jzzTdx9dVXe/i+33vvPQwYMAApKSlYsWIFPv74Y1SrVg0DBw70UHj27duHjh07YseOHZg9ezbWrVuH+fPno7i4GCUlJRgyZAjmzZsHwPXR3L59O7Zv344hQ4YAAObPn4+xY8eiRYsW+Oyzz/Diiy/il19+QdeuXfHXX395yF1SUoLrrrsOffv2xeeff45Zs2ZpniPnHA6HQ9cSanJycnD+/HlcccUVXtuWLVsGABgzZgxuu+02JCQkuNcZhTGGhx56CBkZGV7X7p133kFubq5b2SkoKECvXr2wYsUKTJgwAevWrcPjjz+O5cuX47rrrgPn3L3v33//jREjRuDdd9/Fl19+ibFjx+LZZ5/Ffffd5yVDZmYm7rjjDowYMQJr167F+PHjNeUN9T3KycnB7t270aJFC49zKSwsROvWrb3Kt27dGocOHUJRUVFAxwOAa6+9FhaLBdWqVcONN96I3377LeC6fvnlF/Tv3x8FBQVYsWIFXn/9dezevRtz5871KvvXX3/hmmuucbtYJ06ciI8//hhDhw71KHfNNddg165dWLBgATIyMvDaa6+hbdu2fmNZzLpXTqcTGzduRPv27VGvXj2/12DTpk1wOBy4/vrrNctI2zIyMnzWtXHjRgDweB4IwjBhtSsRhkhKSuITJ07U3J6fn8+rVavGhw4d6rHe6XTyK6+8knfq1Mm9rm/fvrxKlSr89OnTmvVpubGys7N5fHw8v+aaazzWHzt2jNtsNj5ixAj3urvuuosD4G+99ZaeU+SbNm3iAHQtR44c0VUn5/rcWOPHj+d2u52XlJTwP//8k1933XU8OTmZ79y506Nsfn4+T0lJ4V26dPE4T8YYP3TokG6Z5OTm5vLk5GT+8MMPe6xv3rw579Onj/v3/PnzuSAIXm6XTz/9lAPga9euVa3f6XRyu93O33nnHW6xWPj58+fd23r16sUB8A0bNuiSVXL96FkCYeTIkdxqtXpc9x9++IED4B9++KFX+Xnz5nEA/N9//1Wtz5cba926dXzatGl8zZo1fMuWLXzx4sW8bt26PDExke/duzcg+W+55RaemJjo8aw5nU7evHlzn8+tKIrcbrfzLVu2cAB83759nHPOz549ywHwRYsWGZbFrHuVlZXFAfDbbrtN13GffvppDoCvX79es0xhYSEHwAcPHqxZ5sSJEzwtLY136NDBwzVJEEahAOUKRKdOnbB8+XJUr14dV199Ndq3b4+YmBj39m3btuH8+fO46667vHpqgwYNwoIFC5Cfnw/GGLZs2YKxY8d6BHXqZfv27SgsLMTo0aM91terVw99+/ZVdZnddNNNuupu3749fv75Z11l69Spo6ucXl599VW8+uqr7t8xMTFYvXo12rdv71Hu448/Rm5uroerZ8yYMVix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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "gdiff.plot(vmin=-1e-9, vmax=1e-9, cmap=\"RdBu_r\")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "4b4e073e", + "metadata": {}, + "outputs": [], + "source": [ + "# checks first year values across all sectors\n", + "def check_values(exp_raster, obs_raster, sum_dim=None):\n", + " exp = (\n", + " (exp_raster.isel(time=slice(0, 12)).mean(dim=\"time\")).sum(dim=sum_dim).compute()\n", + " )\n", + " obs = (\n", + " (obs_raster.sel(year=2015, gas=\"CO2\").mean(dim=\"month\")).sum(sum_dim).compute()\n", + " )\n", + " return exp, obs" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "90bac319", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\gidden\\Miniconda3\\envs\\aneris\\lib\\site-packages\\dask\\core.py:119: RuntimeWarning: invalid value encountered in divide\n", + " return func(*(_execute_task(a, cache) for a in args))\n" + ] + } + ], + "source": [ + "s_exp, s_obs_us = check_values(exp_raster, ds, sum_dim=[\"lat\", \"lon\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "98f1ee02", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\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", + "
yeargasrel_diff
sector
AGR2015CO2NaN
ENE2015CO2-0.047221
IND2015CO20.068426
RCO2015CO20.047668
SLV2015CO2-0.023627
TRA2015CO2-0.060756
WST2015CO20.109542
\n", + "
" + ], + "text/plain": [ + " year gas rel_diff\n", + "sector \n", + "AGR 2015 CO2 NaN\n", + "ENE 2015 CO2 -0.047221\n", + "IND 2015 CO2 0.068426\n", + "RCO 2015 CO2 0.047668\n", + "SLV 2015 CO2 -0.023627\n", + "TRA 2015 CO2 -0.060756\n", + "WST 2015 CO2 0.109542" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "(100 * (s_exp - s_obs_us) / s_exp).to_dataframe(name=\"rel_diff\") # units: %" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62a4e223", + "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 +} From 2bd9a286cefc846b358034ed41259a60dd1e1fb9 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Tue, 11 Apr 2023 16:11:43 +0200 Subject: [PATCH 07/77] add docstrings for grid --- src/aneris/grid.py | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index f8f2ba1..1efb9ff 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -36,11 +36,39 @@ def grid( extra_coords=["year", "gas", "sector"], as_flux=False, ): - # TODO: add docstrings - # Note that area normalization has been kept with `as_flux`, - # but other unit conversions need to happen outside this function: - # kg_per_mt = 1e9, s_per_yr = 365 * 24 * 60 * 60 - # Otherwise, operates as currently in `prototype_gridding.ipynb` + """ + Develops spatial grids for emissions data. + + Parameters + ---------- + df : pandas.DataFrame + downscaled emissions provided per country (iso) + proxy : xarray.DataArray + proxy data used to apply emissions to spatial grids + idx_raster : xarray.DataArray + a raster mapping data in `df` to spatial grids + value_col : str, optional + the column in `df` which is gridded + shape_col : str, optional + the column in `df` which aligns with `idx_raster` + extra_coords : Collection of str, optional + the additional columns in `df` which will become coordinates + in the returned DataArray + as_flux : bool, optional + if True, divide the result by the latitude-resolved cell areas + to estimate parameter as a flux rather than bulk magnitude + + Returns + ------- + xarray.DataArray: + gridded emissions from `df` + + Notes + ----- + 1. `df` must have columns including `extra_coords`, `value_col`, and `shape_col` + 2. `proxy` must have coodrinates including `extra_coords`, "lat", and "lon" + 3. `idx_rater` must have coodrinates including `shape_col`, "lat", and "lon" + """ df_dim_diff = set(extra_coords + [value_col, shape_col]).difference(set(df.columns)) if df_dim_diff: raise MissingColumns(f"df missing columns: {df_dim_diff}") From 32a0051e69fecd1b0fc64da89455dcf38141928e Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Wed, 12 Apr 2023 11:06:57 +0200 Subject: [PATCH 08/77] add docstring for check_coord_overalp --- src/aneris/grid.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 1efb9ff..c379607 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -8,6 +8,25 @@ def check_coord_overlap(x, y, coord, x_strict=False, y_strict=False, warn=False): + """ + Checks whether the coordinates or columns between two xarray.DataArrays. + + Parameters + ---------- + x : xarray.DataArray + y : xarray.DataArray + coord : str + x_strict : bool, optional + the check fails if the coordinates in `y` are not a subset of `x` + y_strict : bool, optional + the check fails if the coordinates in `x` are not a subset of `y` + warn : bool, optional + if the check fails, issue a warning rather than a `MissingCoordinateValue` error + + Raises + ------ + `MissingCoordinateValue` if check fails + """ # TODO: add docs and try to generalize iso coord logic x, y = set(np.unique(x[coord])), set(np.unique(y[coord])) msg = "" From c5cab38c58c777f0ea1c02d079ad40cb279b1a81 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Wed, 12 Apr 2023 11:13:03 +0200 Subject: [PATCH 09/77] update xlsxwriter save -> close --- src/aneris/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aneris/utils.py b/src/aneris/utils.py index 17054a7..0f86d12 100644 --- a/src/aneris/utils.py +++ b/src/aneris/utils.py @@ -121,4 +121,4 @@ def pd_write(df, f, *args, **kwargs): else: writer = pd.ExcelWriter(f) df.to_excel(writer, index=index, *args, **kwargs) - writer.save() + writer.close() From 338a277e689d871b66cef7ffa667f3cfe2e2b880 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Wed, 12 Apr 2023 11:30:32 +0200 Subject: [PATCH 10/77] add plots in notebook --- notebooks/grid.ipynb | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/notebooks/grid.ipynb b/notebooks/grid.ipynb index 60feb75..671a559 100644 --- a/notebooks/grid.ipynb +++ b/notebooks/grid.ipynb @@ -847,23 +847,23 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 35, "id": "25d27ed7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 10, + "execution_count": 35, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiYAAAHFCAYAAADG9jL3AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/P9b71AAAACXBIWXMAAA9hAAAPYQGoP6dpAACJ60lEQVR4nO3deXwTZf4H8M8kadKW0gIt9IBSCnIJCliUSwWPFlBZXHcRRRdQYEVAF5FVu7iCLFBPfqy6gMcKqKgsqyi6XN2VSwGFcoiIyF2O1nLZAoW2yTy/P9IZMslMMkkmyUzyffvKSzqZ45nM9Z3n5BhjDIQQQgghOmCKdAIIIYQQQgQUmBBCCCFENygwIYQQQohuUGBCCCGEEN2gwIQQQgghukGBCSGEEEJ0gwITQgghhOgGBSaEEEII0Q0KTAghhBCiGxSYEN1yOByYPXs2BgwYgBYtWiAxMREdO3bEM888g19//VV2mddffx0dOnSAzWZDbm4unn/+edTV1UnmOX78OCZOnIi+ffuiUaNG4DgOCxculF1fv379wHGcx2fAgAEa72104Hke77//Pm6//XakpaUhLi4OzZo1w1133YUvvvgCPM9L5j927BgmTJiANm3aID4+Ho0bN0a/fv2wePFiuHdK/fPPP2Py5MnIy8tDo0aN0KRJE/Tp0wf//ve/w7mLQZs7d67i+WYEStcEx3Fo1aqVON+6devE6Zs3b/ZYz8iRI5GUlBTQukl0s0Q6AYQouXTpEqZNm4b7778fo0ePRlpaGrZv344ZM2bgiy++wLZt25CQkCDOP3PmTPz1r3/FM888g4KCAmzduhXPPvssTpw4gbfeekuc78CBA1i8eDG6du2KO+64Ax999JHXdLRu3RqLFy+WTGvUqJGm+xoNLl++jLvvvhtr1qzBfffdh3nz5iEjIwOnTp3CqlWrMGTIECxZsgSDBw8GAHzzzTe46667kJSUhD//+c+49tprUVlZiX/961948MEH8cUXX+DDDz+EyeR8f1qzZg3+85//4A9/+AOuv/562O12LFmyBEOGDMHzzz+P5557LpK7r9rcuXORlpaGkSNHRjopAZO7JgDAZrPJzv/UU09h48aNIVk3iUKMED/Z7XZ2+fLlsGzn9OnTHtOXLl3KALD3339fnHb69GkWHx/P/vjHP0rmnTlzJuM4ju3Zs0ec5nA4xH9v3bqVAWALFiyQTUPfvn1Zp06dgtyT2PDoo48yAGzRokWy3//8889s165djDHGzp07x5o1a8ZycnJYeXm5x7wvvPACA8CKiorEaadOnWI8z3vMe+edd7LExMSwnJNa6NSpE+vbt6+m6wzXNcmY+mti7dq1DAAbMGAAA8CWL18u+X7EiBGsQYMGAa2bRDcqyjGAjRs3guM42Tf79957DxzHYevWreK0bdu24Te/+Q2aNGmC+Ph4dOvWDf/6178ky506dQrjxo3D1VdfjaSkJDRr1gy33nqrx1vNkSNHwHEcXnrpJcyYMQO5ubmw2WxYu3ZtaHbWhdlsRmpqqsf0G264AYCzGECwatUqXL58GQ899JBk3oceegiMMXz22WfiNOENPFIYY5g1axZycnIQHx+P7t27o7i4GP369UO/fv3E+S5fvownn3wSXbt2RUpKCpo0aYJevXrh888/91jn0qVL0aNHD6SkpCAxMRGtW7fGww8/HLZ9Ki8vxzvvvIP+/ftj+PDhsvO0bdsW1157LQDgnXfeQUVFBV544QWkp6d7zPvUU0+hQ4cOePnll8WiuLS0NHAc5zHvDTfcgOrqapw9ezagtKv57aqqqjB58mTk5ubCarWiefPmmDhxIi5evCiZj+d5vP766+jatSsSEhLQqFEj9OzZE8uXLwcAtGrVCnv27MH69etliyhKS0vx4IMPolmzZrDZbOjYsSNeffVVSRFYJK/JQIwcORJXX301CgsL4XA4Ip0cYgBUlGMAN910E7p164Z//OMfuP/++yXfvfHGG7j++utx/fXXAwDWrl2LAQMGoEePHpg/fz5SUlLw8ccfY+jQoaiurhazj4Wb+NSpU5GRkYELFy5g2bJl6NevH/73v/9JHpAA8Nprr6Fdu3Z45ZVXkJycjLZt2yqm1+FweNQPkGMymQIKEr766isAQKdOncRpP/zwAwDgmmuukcybmZmJtLQ08ftAHDx4EE2aNEFVVRVycnJw33334dlnn5UUI/ljypQpKCoqwh//+Efcc889OHbsGEaPHo26ujq0a9dOnK+mpgZnz57F5MmT0bx5c9TW1uK///0v7rnnHixYsEAMADZv3oyhQ4di6NChmDZtGuLj43H06FHxd/JGq2O1du1a1NXV4e677/b9AwAoLi6G2WzGoEGDZL/nOA6/+c1v8NJLL6GkpAQ9e/b0uu2mTZuiWbNmqrbtSs1vV11djb59++L48eP4y1/+gmuvvRZ79uzBc889h927d+O///2vGDCNHDkSH3zwAUaNGoXp06fDarVi+/btOHLkCABg2bJl+P3vf4+UlBTMnTsXwJUiilOnTqF3796ora3F3/72N7Rq1QpffvklJk+ejIMHD4rzCyJ9TdrtdlXLm81mFBUVYfDgwVi0aJGqgFntukmUimh+DVFtwYIFDADbsWOHOO27777zyDrv0KED69atG6urq5Msf9ddd7HMzExJMYYru93O6urq2G233cZ++9vfitMPHz7MALA2bdqw2tpaVWnt27cvA+DzM2LECPU/QL3jx4+z9PR01r17d8m+jBkzhtlsNtll2rVrxwoKCmS/81WUM2XKFDZ37lz21Vdfsf/85z9swoQJzGKxsJtvvlnxt/Tm7NmzzGazsaFDh0qmb968mQHwmsUvHKNRo0axbt26idNfeeUVBoD9+uuvfqdHq2MlFL2sWrVK1XY7dOjAMjIyvM4zb948BoAtWbJEcZ63336bAWB///vfVW3XnZrfrqioiJlMJrZ161bJ9H//+98MAFuxYgVjjLENGzYwAGzKlClet6lUlPPMM88wAOzbb7+VTH/00UcZx3Fs3759jLHIX5Pe1jVq1ChxPqEoZ+nSpYwxxm688UbWokULdunSJcaYclGOmnWT6EY5JgZx//334+mnn8Y//vEPvP322wCcLVCaNm2KoUOHAnBW6vzpp5/wyiuvAJC+ddxxxx348ssvsW/fPnTs2BEAMH/+fLz11lv48ccfUVNTI87boUMHj+3/5je/QVxcnKq0vvnmmzh//rzP+dLS0lStT3D27FnccccdYIxhyZIlHm9Pctn8ar7zZsaMGZK/77jjDrRq1QqTJ0/G559/jt/+9rd+rW/Lli2oqanBvffeK5nes2dP2VYHS5cuxZw5c7Br1y5JsUF8fLz4byG37N5778WoUaPQp08fNG/eXFV6QnWstMDq3/CVjt3KlSsxfvx4/P73v8djjz0W0DbU/HZffvklOnfujK5du0quqf79+4PjOKxbtw4DBw7EypUrAQDjx48PKC1fffUVrr76arGoUjBy5EjMmzcPX331lSRHLZLXZJs2bfDxxx97TG/atKniMi+++CL69OmDv//973j66ac1XbdebdiwAS+//DJKSkpQVlaGZcuWqc5VDNSJEyfw9NNPY+XKlbh06RLatWuHf/7zn8jLywvpdrVEgYlB2Gw2PPLII3j11VfFcvd//etfmDRpkpgV/MsvvwAAJk+ejMmTJ8uu5/Tp0wCA2bNn48knn8TYsWPxt7/9DWlpaTCbzfjrX/+KvXv3eiyXmZmpOq1XXXWV6mxjtc6dO4f8/HycOHECX331FVq3bi35PjU1FZcvX0Z1dTUSExMl3509e1bTi/LBBx/E5MmTsWXLFr8DkzNnzgCAbL0K92mffvop7r33XgwZMgR//vOfkZGRAYvFgnnz5uHdd98V57v55pvx2Wef4bXXXsPw4cNRU1ODTp06YcqUKR5Ff+60OlYtW7YEABw+fNjnuoT59+/fj4sXL6JBgway8wjFH9nZ2R7frV69Gvfccw/y8/OxePHigANPNb/dL7/8ggMHDigGAcI1derUKZjNZmRkZASUljNnzsgGp1lZWeL3riJ5TQp1o/zRu3dv3H333XjhhRfwxz/+UdN169XFixfRpUsXPPTQQ/jd734X8u2dO3cOffr0wS233IKVK1eiWbNmOHjwoOFaEVJgYiCPPvooXnjhBbz77ru4fPky7HY7xo4dK34vvO0UFhbinnvukV1H+/btAQAffPAB+vXrh3nz5km+V3qr8ufGf9ttt2H9+vU+5xsxYoSq/hzOnTuH22+/HYcPH8b//vc/sQKlK6Fuye7du9GjRw9xenl5OU6fPo3OnTurTr9agZR3C5V5hSDSVXl5ueTB9MEHHyA3NxdLliyR/P6uuVuCwYMHY/DgwaipqcGWLVtQVFSEYcOGoVWrVujVq5dierQ6Vrfccgvi4uLw2WefSc5JJfn5+VizZg2++OIL3HfffR7fM8awfPlyNGnSxCOoXL16Ne6++2707dsXn3zyCaxWq8/teePrt0tLS0NCQoIkGHQlXHdNmzaFw+FAeXm5X0GDIDU1FWVlZR7TT548KdmOIJLXZKCKiorQuXNnzJo1K2Tb0JOBAwdi4MCBit/X1tbi2WefxeLFi/Hrr7+ic+fOePHFFz3q+Kn14osvIjs7GwsWLBCnGbH/FwpMDCQzMxNDhgzB3LlzUVtbi0GDBolvqoAz6Gjbti127drl88LnOM6jX4Dvv/8emzdvln1D9YeW2cZCUHLo0CEUFxejW7dusvMNGDAA8fHxWLhwoSQwWbhwITiO0zT7dNGiRQDgtUKmkh49esBms2HJkiWS4HHLli04evSo5CbCcRysVqvkAVReXi7bKkdgs9nEjuNWr16NHTt2eA1MtDpWGRkZGD16NObNm4f33ntPtmXOwYMHcfHiRVx77bUYPXo0Xn75ZRQWFuLWW2/1qLj60ksv4aeffsILL7wgyalYs2YN7r77btx444347LPPNO3bQum3u+uuuzBr1iykpqYiNzdXcfmBAweiqKgI8+bNw/Tp071u59KlSx7Tb7vtNhQVFWH79u247rrrxOlCy7tbbrkl4H3TS5Fdhw4d8PDDD+P1119H7969Q7otI3jooYdw5MgRfPzxx8jKysKyZcswYMAA7N6922tlZiXLly9H//79MWTIEKxfvx7NmzfHuHHjMGbMmBCkPoQiWcGF+O/bb78VK4P997//9fj+q6++YjabjRUUFLAPP/yQrV+/ni1btozNmjWL/f73vxfne+655xjHcey5555j//vf/9jcuXNZRkYGa9OmDcvJyRHnEyravfzyy+HYPYnq6mp2/fXXM47j2N///ne2efNmyefAgQOS+WfMmME4jmN/+ctf2Lp169jLL7/MbDYbGzNmjMe6ly5dypYuXcpefPFFBoCNHz9enCbYsGED69+/P5s/fz5bs2YNW758OXv00UeZ2Wxmt956q0fl15ycHMlvp6SwsJABYI888ghbtWoVe+edd1h2djbLzMxkt9xyizjfu+++ywCwRx99lP3vf/9jCxcuZG3atGFt27ZlrpfuX//6V/bQQw+xDz74gK1bt4599tln7JZbbmFxcXHshx9+UPtzB+3SpUusf//+jOM4NmzYMLZ06VK2YcMG9umnn7JHH32UxcfHs88++0yc/+uvv2aNGjViLVq0YH//+9/ZunXr2PLly9kDDzzAALChQ4dKfuONGzeyhIQE1qpVK/bVV195nA+VlZXivMJ566syp5rf7sKFC6xbt26sRYsW7NVXX2XFxcVs9erV7O2332ZDhgxhW7ZsEdf3hz/8gXEcx/74xz+y5cuXs9WrV7MXXniBvfbaa+I8I0aMYDabjX388cfsu+++Y99//z1jjLGKigrWvHlzlpGRwd566y22evVq9vjjjzOO49i4ceM89i0S1yRjzgqqrVu39vj9hY/AvfKr4MSJEywxMZEBkK38qmbdRgSALVu2TPz7wIEDjOM4duLECcl8t912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\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiYAAAHFCAYAAADG9jL3AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/P9b71AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOydd3gU5fbHPzPbkhASSCghoSQBQieEXhRQDGnYRezitYHen1e92PXaRb32FgQVRSyIii0kIVeaSpEaadJ7CJ2E9OzM+/tjdie7yW46JIH5PM8+yc688867u1POnPec75GEEAIDAwMDAwMDg0aA3NADMDAwMDAwMDBwYhgmBgYGBgYGBo0GwzAxMDAwMDAwaDQYhomBgYGBgYFBo8EwTAwMDAwMDAwaDYZhYmBgYGBgYNBoMAwTAwMDAwMDg0aDYZgYGBgYGBgYNBoMw8TAwMDAwMCg0WAYJgaNFkVReOONN4iPj6d9+/b4+fnRo0cPHn30UU6dOuVxm3fffZfu3btjs9mIiIjg2WefpbS01K3NgQMHuP/++xk1ahQtWrRAkiQ+/fRTj/2NHj0aSZIqvOLj4+v5054bqKrK559/ziWXXEKrVq2wWCy0adOGcePG8fPPP6Oqqlv7/fv3889//pPOnTvj4+NDy5YtGT16NF988QXlRam3bdvGlClTGDBgAC1atCAoKIgRI0bw7bffns2PWGc++OADr8dbU8DbOSFJEuHh4Xq7xYsX68uXL19eoZ+JEyfi7+9fq74Nzm3MDT0AAwNvFBYW8swzz3D99ddzxx130KpVK9auXcsLL7zAzz//zOrVq/H19dXbv/jiizz11FM8+uijjB07llWrVvHkk09y8OBBpk+frrfbsWMHX3zxBf369SMxMZGvvvqq0nFERkbyxRdfuC1r0aJFvX7Wc4GioiKuuOIKFixYwHXXXUdycjIhISEcPXqUtLQ0xo8fz5w5c7j88ssB+OOPPxg3bhz+/v489NBD9O3bl5ycHL755htuuukmfv75Z7788ktkWXt+WrBgASkpKdx8880MGjQIu93OnDlzGD9+PM8++yz/+c9/GvLjV5sPPviAVq1aMXHixIYeSq3xdE4A2Gw2j+0ffvhhfvvttzPSt8E5iDAwqCF2u10UFRWdlf0cO3aswvK5c+cKQHz++ef6smPHjgkfHx9x1113ubV98cUXhSRJYtOmTfoyRVH0/1etWiUAMXPmTI9jGDVqlOjVq1cdP8n5weTJkwUgPvvsM4/rt23bJjIzM4UQQpw8eVK0adNGdOrUSWRnZ1do+/LLLwtATJ06VV929OhRoapqhbZJSUnCz8/vrByT9UGvXr3EqFGj6rXPs3VOClH9c2LRokUCEPHx8QIQP/30k9v6W2+9VTRr1qxWfRuc2xhTOU2A3377DUmSPD7Zz5o1C0mSWLVqlb5s9erVXHbZZQQFBeHj40NMTAzffPON23ZHjx7lnnvuoWfPnvj7+9OmTRsuvvjiCk81e/bsQZIkXn31VV544QUiIiKw2WwsWrTozHxYF0wmE8HBwRWWDx48GNCmAZykpaVRVFTEbbfd5tb2tttuQwjBDz/8oC9zPoE3FEIIXnrpJTp16oSPjw8DBw4kIyOD0aNHM3r0aL1dUVER//73v+nXrx+BgYEEBQUxbNgwfvzxxwp9zp07lyFDhhAYGIifnx+RkZH84x//OGufKTs7m48++oi4uDhuueUWj226du1K3759Afjoo484cuQIL7/8Mm3btq3Q9uGHH6Z79+7897//1afiWrVqhSRJFdoOHjyYgoICTpw4UauxV+e7y83NZcqUKURERGC1WgkLC+P+++8nPz/frZ2qqrz77rv069cPX19fWrRowdChQ/npp58ACA8PZ9OmTSxZssTjFMW+ffu46aabaNOmDTabjR49evD666+7TYE15DlZGyZOnEjPnj157LHHUBSloYdj0AQwpnKaABdeeCExMTG8//77XH/99W7r3nvvPQYNGsSgQYMAWLRoEfHx8QwZMoRp06YRGBjI119/zYQJEygoKNDdx86L+NNPP01ISAh5eXnMmzeP0aNH8+uvv7rdIAHeeecdoqKieO211wgICKBr165ex6soSoX4AE/IslwrI2HhwoUA9OrVS1+2ceNGAPr06ePWtl27drRq1UpfXxt27txJUFAQubm5dOrUieuuu44nn3zSbRqpJjzxxBNMnTqVu+66i6uuuor9+/dzxx13UFpaSlRUlN6uuLiYEydOMGXKFMLCwigpKeF///sfV111FTNnztQNgOXLlzNhwgQmTJjAM888g4+PD3v37tW/p8qor99q0aJFlJaWcsUVV1T9BQAZGRmYTCYuvfRSj+slSeKyyy7j1VdfZc2aNQwdOrTSfbdu3Zo2bdpUa9+uVOe7KygoYNSoURw4cIDHH3+cvn37smnTJv7zn/+wYcMG/ve//+kG08SJE5k9eza33347zz33HFarlbVr17Jnzx4A5s2bxzXXXENgYCAffPABUDZFcfToUYYPH05JSQnPP/884eHh/PLLL0yZMoWdO3fq7Z009Dlpt9urtb3JZGLq1KlcfvnlfPbZZ9UymKvbt8E5SoP6awyqzcyZMwUg1q1bpy/7888/K7jOu3fvLmJiYkRpaanb9uPGjRPt2rVzm8ZwxW63i9LSUjFmzBhx5ZVX6st3794tANG5c2dRUlJSrbGOGjVKAFW+br311up/AQ4OHDgg2rZtKwYOHOj2We68805hs9k8bhMVFSXGjh3rcV1VUzlPPPGE+OCDD8TChQtFSkqK+Oc//ynMZrMYOXKk1++yMk6cOCFsNpuYMGGC2/Lly5cLoFIXv/M3uv3220VMTIy+/LXXXhOAOHXqVI3HU1+/lXPqJS0trVr77d69uwgJCam0TXJysgDEnDlzvLaZMWOGAMTbb79drf2Wpzrf3dSpU4Usy2LVqlVuy7/99lsBiPnz5wshhFi6dKkAxBNPPFHpPr1N5Tz66KMCECtXrnRbPnnyZCFJkti6dasQouHPycr6uv322/V2zqmcuXPnCiGEuOCCC0T79u1FYWGhEML7VE51+jY4tzE8Jk2E66+/nkceeYT333+fGTNmAFoGSuvWrZkwYQKgBXX+/fffvPbaa4D7U0diYiK//PILW7dupUePHgBMmzaN6dOns3nzZoqLi/W23bt3r7D/yy67DIvFUq2xfvjhh5w+fbrKdq1atapWf05OnDhBYmIiQgjmzJlT4enJk5u/Ousq44UXXnB7n5iYSHh4OFOmTOHHH3/kyiuvrFF/K1asoLi4mGuvvdZt+dChQz1mHcydO5e33nqLzMxMt2kDHx8f/X+nt+zaa6/l9ttvZ8SIEYSFhVVrPGfqt6oPhOMJ39tvl5qayr333ss111zD//3f/9VqH9X57n755Rd69+5Nv3793M6puLg4JEli8eLFJCQkkJqaCsC9995bq7EsXLiQnj176lOVTiZOnEhycjILFy5086g15DnZuXNnvv766wrLW7du7XWbV155hREjRvD222/zyCOP1GvfjZWlS5fy3//+lzVr1nDo0CHmzZtXba9ibTh9+jRPPfUU8+bN48iRI8TExPD222/rx3lTwTBMmgg2m427776b119/XZ93/+abb3jwwQd1V/Dhw4cBmDJlClOmTPHYz7FjxwB44403+Pe//82kSZN4/vnnadWqFSaTiaeeeootW7ZU2K5du3bVHmuXLl2q7TauLidPniQ2NpaDBw+ycOFCIiMj3dYHBwdTVFREQUEBfn5+butOnDjBgAEDqr2vqrjpppuYMmUKK1asqLFhcvz4cQCPcRXll33//fdce+21jB8/noceeoiQkBDMZjPJycl88skneruRI0fyww8/8M4773DLLbdQXFxMr169eOKJJypM/ZWnvn6rjh07ArB79+4q+3K23759O/n5+TRr1sxjG+f0R4cOHSqsS09P56qrriI2NpYvvvii1oZndb67w4cPs2PHDq9GgPOcOnr0KCaTiZCQkFqN5fjx4x6N09DQUH29Kw15Tjpjo2rC8OHDueKKK3j55Ze566676rXvxkp+fj7R0dHcdtttXH311Wd8f3fccQcbN27k888/JzQ0lNmzZ3PJJZewefPmaj+sNAaMCbsmxOTJkyktLeWTTz5hxowZ2O12Jk2apK93Pu089thjrFq1yuOrX79+AMyePZvRo0eTnJxMUlISQ4YMYeDAgV6fqmpy4R8zZgwWi6XKV3WDM0+ePMkll1zC7t27ycjI0AMoXXHGlmzYsMFteXZ2NseOHaN3797VHn91qc18tzOY12lEupKdne32fvbs2URERDBnzhyuuOIKhg4dysCBA928W04uv/xyfv31V3Jycli8eDHt27fnhhtu8Kgf4Up9/VYXXXQRFovFLci4MmJjY1EUhZ9//tnjeiEEP/30E0FBQRWMyvT0dK644gpGjRrFd999h9VqrdY+vVHVd9eqVSv69Onj9Zx66qmnAO2JXlGUCr9jdQkODubQoUMVlmdlZenjcKUhz8naMnXqVE6fPs1LL710RvfTWEhISOCFF17gqquu8ri+pKSEhx9+mLCwMJo1a8aQIUNYvHhxrfZVWFjId999x6uvvsrIkSPp0qULzzzzDBERESQnJ9fhU5x9DI9JE6Jdu3aMHz+eDz74gJKSEi699FL9SRWgW7dudO3alczMzCpPfEmSKugC/PXXXyxfvtzjE2pNqE+3sdMo2bVrFxkZGcTExHhsFx8fj4+PD59++ilDhgzRl3/66adIklSv7tPPPvsMoNKATG8MGTIEm83GnDlz3C5WK1asYO/evW5PzJIkYbVa3W5A2dnZHrNynNhsNl04Lj09nXXr1jFs2DCv7evrtwoJCeGOO+4gOTmZWbNmeczM2blzJ/n5+fTt25c77riD//73vzz22GNcfPHFFQJXX331Vf7++29efvllN0/FggULuOKKK7jgggv44Ycf6lXbwtt3N27cOF566SWCg4OJiIjwun1CQgJTp04lOTmZ5557rtL9FBYWVlg+ZswYpk6dytq1a+nfv7++3Jl5d9FFF9X6szWWKbvu3bvzj3/8g3fffZfhw4ef0X01BW677Tb27NnD119/TWhoKPPmzSM+Pp4NGzZUGszsCbvdjqIobtO8AL6+vvz+++/1OewzjmGYNDH+9a9/6TfemTNnVlj/4YcfkpCQQFxcHBMnTiQsLIwTJ06wZcsW1q5dy9y5cwEYN24czz//PE8//TSjRo1i69atPPfcc0RERHiMiK8J3bp1q9P2TgoLC4mLi2PdunW89dZb2O12VqxYoa9v3bo1nTt3BiAoKIgnn3ySp556iqCgIF1g7ZlnnuGOO+6gZ8+ebn071UJ37doFaCnWThXKa665BtDStF988UWuvPJKIiMjKSoqIjU1lenTp3PxxRdXyChxGhXOKQhPBAUF8eCDDzJ16lRatmzJlVdeyYEDB3j22Wdp166dmxdm3LhxfP/999xzzz1cc8017N+/n+eff5527dqxfft2vd1//vMfDhw4wJgxY2jfvj2nTp3i7bffxmKxMGrUqEq/4/r6rUCbHty1axcTJ04kPT2dK6+8krZt23Ls2DEyMjKYOXMmX3/9NX379qVFixZ8//33jBs3jgEDBvDQQw8RHR1Nbm4uc+bM4YsvvmDChAk89NBDev+///47V1xxBSEhITz++OOsX7/ebf89e/YkICAA0H6DiIgIbr311kpVVqvz3d1///189913jBw5kgceeIC+ffuiqir79u1jwYIF/Pvf/2bIkCFceOGF3HzzzbzwwgscPnyYcePGYbPZWLduHX5+fnocTJ8+ffj666+ZM2cOkZGR+Pj40KdPHx544AFmzZpFUlISzz33HJ06dSIlJYUPPviAyZMnu8WX1JT6/J1BOzddz0VXqjLYn3nmGb744gsWLVrkcRqvLn03JXbu3MlXX33FgQMH9Om6KVOmkJaWxsyZM2vsVWrevDnDhg3j+eefp0ePHrRt25avvvqKlStX1tjIaXAaMvLWoHaEh4eLHj16eF2fmZkprr32WtGmTRthsVhESEiIuPjii8W0adP0NsXFxWLKlCkiLCxM+Pj4iP79+4sffvhB3HrrraJTp056O2cGwH//+98z+ZE84ty3t5enDIK3335bREVFCavVKjp27Ciefvppj5kLlfXrZPv27SIxMVGEhYUJm80mfHx8RJ8+fcSLL77oUcyqVatWYujQoVV+LlVVxQsvvCDat28vrFar6Nu3r/jll19EdHS0W0aUEFq2S3h4uLDZbKJHjx5ixowZ4umnn3Yb5y+//CISEhJEWFiYsFqtok2bNiIxMVH89ttvVY6lvrHb7eKzzz4TF198sQgKChJms1m0bt1aJCQkiC+//LJCJtO+ffvEvffeKyIjI4XVahWBgYFi5MiRYvbs2RXE1Jyf29tr0aJFetsNGzYIQDz66KOVjre6311eXp548sknRbdu3fRx9unTRzzwwANuAnGKoog333xT9O7dW283bNgw8fPPP+tt9uzZI8aOHSuaN28uALfzbe/eveKGG24QwcHBwmKxiG7duon//ve/bt9bQ56TQlSd4ePMCCyflePK448/LoAaZeW49t0UAcS8efP09998843+Hbi+zGazuPbaa4UQVV8DAXHvvffqfe7YsUOMHDlSAMJkMolBgwaJG2+8sdL7RWNEEqIaEVEGjYa//vqL6Oho3n//fe65556GHo6Bg82bN9OrVy9++eUXkpKSarz97t276d69O08//TSPP/74GRjh+cUHH3zAww8/zM6dOz0GGhsYnG0kSXLLypkzZw433ngjmzZtwmQyubX19/cnJCSE0tJSdu7cWWm/LVu2rHCM5+fnk5ubS7t27ZgwYQJ5eXmkpKTU6+c5kxhTOU2EnTt3snfvXh5//HHatWvXpOtsnIssWrSIYcOGVcsoyczM5KuvvmL48OEEBASwdetWXn31VQICArj99tvPwmjPfRYtWsR9991nGCUGjZaYmBgUReHIkSNceOGFHttYLBaP8g1V0axZM5o1a8bJkydJT0/n1VdfretwzyqGx6SJMHHiRD7//HN69OjBhx9+yIgRIxp6SAa1ZMeOHUyaNInMzExOnTpFYGAgo0eP5sUXX6z3WAADA4OGIy8vjx07dgCaIfLGG29w0UUXERQURMeOHbnpppv4448/eP3114mJieHYsWMsXLiQPn36kJiYWOP9paenI4SgW7du7Nixg4ceegibzcbvv/9ebc2bxoBhmBgYGBgYGJwBFi9e7DGbyhmUXVpaygsvvMCsWbM4ePAgwcHBDBs2jGeffbZCeY3q8M033/DYY49x4MABgoKCuPrqq3nxxRcJDAysj49z1jAMEwMDAwMDA4NGgyGwZmBgYGBgYNBoMAwTAwMDAwMDg0aDkZVTDlVVycrKonnz5rWuv2FgYGBgcO4jhOD06dOEhobWqkRFfaGqKrt37yYyMvKcuG8Zhkk5srKy6izJbmBgYGBw/rB//37at2/fYPv/9ttvmTBhAt9//32NC4s2Rozg13Lk5OTQokUL9u/fr8tbGzQ9Lg+sWKulPD/mzDoLIzEwMDhXyc3NpUOHDnraf0Ngt9vp1d2Ptq1MHD+p8tfmggqCbU0Nw2NSDqcbLCAgwDBMmjBmqeqcfeP3NTAwqA8acvpk5jthqCrM/zKMvhft5YsvvvBYRLMpYXhMypGbm0tgYCA5OTnGjasJECuPP2N9Z6hzz1jfBgYGTZ+Gvl8UFRUR1bk5Lz/ViuuuaM7nc3N55r/H2bojH6vVetbHU18YHhODRs2ZNDyqs2/DODEwMGisJL/agZYtZK69TKuMfsNVzXn1vZNMf709/3zsSAOPrvYYholBo6QhDRInhlFiABWPRedx4brcOFYMzjanT59m6jsn+ejNNsiyNpVkMkk890gw9z56hNvuy6dZs2YNPMra0WR0TOx2O08++SQRERH4+voSGRnJc889h6qqehshBM888wyhoaH4+voyevRoNm3a1ICjNjAwMDAwqH/efD6crpEWki5xNz6uSGhGxzAz77zUqYFGVneajMfklVdeYdq0aXz22Wf06tWL1atXc9tttxEYGMi//vUvAF599VXeeOMNPv30U6KionjhhReIjY1l69atNG/evIE/gUFlNAYPCRhPvucrzuPP9ff3dkx6a3s2j53yY/Dm1TE4Nzl+/DivTzvFD5+2qxB4K0kSLzzWigl3HWLyQ6do0aJFwwyyDjSZ4Ndx48bRtm1bPv74Y33Z1VdfjZ+fH59//jlCCEJDQ7n//vt55JFHACguLqZt27a88sor3H333dXaT0MHM52PNAajxLiQnx9UdaxlqHNrfTzW5RjyZOzUZLszMSaDqmmo+8VD9wbx1+ZiUr8K89omdvwBhvT34aW3T5y1cdUXTWYq54ILLuDXX39l27ZtAGRmZvL777/rpaF3795NdnY2Y8eO1bex2WyMGjWKZcuWNciYDSoSK493u5g2pFGSoc7VXwZNn+ocS1X93jU5Hl2Pn7oeQ7XpozpjbQxGv0H9kpWVxfufnOKFR4Mrbff8o8G889EpDh8+fJZGVn80mamcRx55hJycHLp3747JZEJRFF588UWuv/56ALKzswFo27at23Zt27Zl7969XvstLi6muLhYf5+bm3sGRm9gYGBgYFB3nn+8JwljmjEg2qfSdkMH+HLxhX68+ER33vno5FkaXf3QZAyTOXPmMHv2bL788kt69erF+vXruf/++wkNDeXWW2/V25WfbxNCVCp+M3XqVJ599tkzNm6DxofhITk3qcnv6qltdeJEajvlcqb7qmo/xjF/brBz505mfp3LmgUdq9X++UeCGZq4n38/tZdOnZpOMGyTiTHp0KEDjz76KPfee6++7IUXXmD27Nn8/fff7Nq1i86dO7N27VpiYmL0NpdffjktWrTgs88+89ivJ49Jhw4djBiTOuLNhezthnCmMS7MBucirsZNTaehDOrO2Y4xuemaAMxm+OStkGpvc/O92VitEjO/yjmDI6tfmkyMSUFBQYXqjSaTSU8XjoiIICQkhIyMDH19SUkJS5YsYfjw4V77tdlsuvy8IUNfM5zxIuXjRsD7ha/8NmfjqdG4CBucq7jGptQk3sWIPWl6bNiwge9S8nj635XHlpTnmYeC+GreabZs2VLjfS5dupRLL72U0NBQJEnihx9+qHKbJUuWMGDAAHx8fIiMjGTatGk13m+TMUwuvfRSXnzxRVJSUtizZw/z5s3jjTfe0CspSpLE/fffz0svvcS8efPYuHEjEydOxM/PjxtuuKGBR29gYGBgYFB7nnxoGHfcGECnDlXXAXOlc7iViRMCeOrhwTXeZ35+PtHR0bz33nvVar97924SExO58MILWbduHY8//jj33Xcf3333XY3222RiTN59912eeuop7rnnHo4cOUJoaCh33303//nPf/Q2Dz/8MIWFhdxzzz2cPHmSIUOGsGDBAkPDpB5xzlfX9xOX6zx4ffZteEsMzgfKx5FU91w6W3EuBnVj5cqV/PpbAdtXhNdq+yfuD6Lb8D2sWbOGAQMGVHu7hIQEEhIS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\n", "text/plain": [ "
" ] @@ -873,7 +873,7 @@ } ], "source": [ - "xr.where(da > 0, da, np.nan).plot()" + "xr.where(da > 0, da, np.nan).plot(vmax=1e-9)" ] }, { @@ -1552,6 +1552,38 @@ "exp_raster" ] }, + { + "cell_type": "code", + "execution_count": 34, + "id": "9ab3e473", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "da_exp = exp_raster.isel(time=slice(0, 12)).sel(sector=\"ENE\").mean(dim=\"time\").compute()\n", + "xr.where(da_exp > 0, da_exp, np.nan).plot(vmax=1e-9)" + ] + }, { "cell_type": "code", "execution_count": 13, From bca34164a66b20c2d6956ac50003825721c7cc35 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Fri, 3 Mar 2023 10:29:45 +0100 Subject: [PATCH 11/77] Add downscaling module --- pyproject.toml | 3 +- src/aneris/cmip6/driver.py | 5 +- src/aneris/downscaling/__init__.py | 1 + src/aneris/downscaling/core.py | 139 ++++++ src/aneris/downscaling/data.py | 41 ++ .../downscaling/intensity_convergence.py | 447 ++++++++++++++++++ src/aneris/downscaling/methods.py | 110 +++++ src/aneris/utils.py | 22 +- tests/test_utils.py | 27 +- 9 files changed, 749 insertions(+), 46 deletions(-) create mode 100644 src/aneris/downscaling/__init__.py create mode 100644 src/aneris/downscaling/core.py create mode 100644 src/aneris/downscaling/data.py create mode 100644 src/aneris/downscaling/intensity_convergence.py create mode 100644 src/aneris/downscaling/methods.py diff --git a/pyproject.toml b/pyproject.toml index c7d2275..d13400f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ dependencies = [ "openpyxl", "matplotlib", "pyomo>=5", - "pandas-indexing", + "pandas-indexing>=0.2.7", ] dynamic = ["version"] @@ -61,6 +61,7 @@ lint = [ [project.scripts] aneris = "aneris.cli:main" + [tool.setuptools_scm] fallback_version = "999" diff --git a/src/aneris/cmip6/driver.py b/src/aneris/cmip6/driver.py index 9f75e5a..44d5587 100644 --- a/src/aneris/cmip6/driver.py +++ b/src/aneris/cmip6/driver.py @@ -1,10 +1,13 @@ import numpy as np import pandas as pd +from pandas_indexing import isin + import aneris.cmip6.cmip6_utils as cmip6_utils import aneris.utils as utils from aneris.harmonize import Harmonizer, _log, _warn -from aneris.utils import isin, pd_read +from aneris.utils import pd_read + class _TrajectoryPreprocessor: diff --git a/src/aneris/downscaling/__init__.py b/src/aneris/downscaling/__init__.py new file mode 100644 index 0000000..e6eb75e --- /dev/null +++ b/src/aneris/downscaling/__init__.py @@ -0,0 +1 @@ +from aneris.downscaling.core import * diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py new file mode 100644 index 0000000..e585bf8 --- /dev/null +++ b/src/aneris/downscaling/core.py @@ -0,0 +1,139 @@ +from typing import Optional, Sequence, Callable +from functools import partial + +from pandas import DataFrame, Series, Index +from pandas_indexing import projectlevel, semijoin + +from ..methods import default_methods +from .data import DownscalingContext +from .methods import base_year_pattern, growth_rate, intensity_convergence + + +DEFAULT_INDEX = ("sector", "gas") + + +class Downscaler: + _methods = { + "ipat_2100_gdp": partial( + intensity_convergence, convergence_year=2100, proxy_name="gdp" + ), + "ipat_2150_pop": partial( + intensity_convergence, convergence_year=2150, proxy_name="pop" + ), + "base_year_pattern": base_year_pattern, + "growth_rate": growth_rate, + } + + def add_method(self, name, method): + self._methods = self._methods | {name: method} + + def __init__( + self, + model: DataFrame, + hist: DataFrame, + region_mapping: Series, + index: Sequence[str] = DEFAULT_INDEX, + return_type=DataFrame, + **additional_data: DataFrame, + ): + self.model = model + self.hist = hist + self.region_mapping = region_mapping + self.index = index + self.return_type = return_type + self.additional_data = additional_data + + self.region_level = self.region_mapping.name + self.country_level = self.region_mapping.index.name + + assert ( + hist.groupby(list(index) + [self.region_level]).count() <= 1 + ).all(), "More than one hist" + assert ( + projectlevel(model.index, list(index) + [self.region_level]) + .difference(projectlevel(hist.index, list(index) + [self.region_level])) + .empty + ), "History missing for some" + + # TODO Make configurable by re-using config just as in harmonizer + self.intensity_method = "ipat_2100_gdp" + self.linear_method = "base_year_pattern" + + def downscale(self, methods: Optional[Series] = None) -> DataFrame: + """Downscale aligned model data from historical data, and socio-economic scenario + + Notes + ----- + model.index contains at least the downscaling index levels, but also any other + levels. + + hist.index contains at least the downscaling index levels other index levels are + allowed, but only one value per downscaling index value. + + Parameters + ---------- + methods : Series Methods to apply + """ + + if methods is None: + methods = self.methods() + + # Check that data contains what is needed for all methods in use, ie. inspect partial keywords + + return self.return_type(downscaled) + + def methods(self, method_choice=None, overwrites=None): + if method_choice is not None: + method_choice = self.method_choice + + if method_choice is None: + method_choice = default_method_choice + + hist_agg = ( + semijoin(self.hist, self.context.regionmap_index) + .groupby(list(self.index) + [self.country_level], dropna=False) + .sum() + ) + methods = default_methods( + projectlevel(self.model, list(self.index) + [self.region_level]), + hist_agg, + method_choice=method_choice, + intensity_method=self.intensity_method, + linear_method=self.linear_method, + ) + + if isinstance(overwrites, str): + return Series(overwrites, methods.index) + elif isinstance(overwrites, dict): + overwrites = Series(overwrites).rename_axis("sector") + + return ( + semijoin(overwrites, methods.index, how="right") + .fillna(methods) + .rename("method") + ) + + @property + def context(self): + return DownscalingContext( + self.index, + self.region_mapping, + self.additional_data, + self.country_level, + self.region_level, + ) + + +def default_method_choice(traj, intensity_method, linear_method): + """Default downscaling decision tree""" + + # special cases + if traj.h == 0: + return linear_method + if traj.zero_m: + return linear_method + + if traj.get("sector", None) in ("Agriculture", "LULUCF"): + return linear_method + + return intensity_method diff --git a/src/aneris/downscaling/data.py b/src/aneris/downscaling/data.py new file mode 100644 index 0000000..403aeb1 --- /dev/null +++ b/src/aneris/downscaling/data.py @@ -0,0 +1,41 @@ +from collections.abc import Sequence +from dataclasses import dataclass, field +from typing import Union + +from pandas import DataFrame, MultiIndex, Series + + +@dataclass +class DownscalingContext: + """Context in which downscaling needs to happen + + Attributes + ---------- + index: sequence of str + index levels that differentiate trajectories + regionmap: Series + map from countries to regions + additional_data: dict, default {} + named `DataFrame`s or `Series` the methods need as proxies + country_level: str, default "country" + name of the fine index level + region_level: str, default "region" + name of the coarse index level + + Notes + ----- + Passed as context argument to each downscaling method + """ + + index: Sequence[str] + regionmap: Series + additional_data: dict[str, Union[Series, DataFrame]] = field(default_factory=dict) + country_level: str = "country" + region_level: str = "region" + + @property + def regionmap_index(self): + return MultiIndex.from_arrays( + [self.regionmap.index, self.regionmap.values], + names=[self.country_level, self.region_level], + ) diff --git a/src/aneris/downscaling/intensity_convergence.py b/src/aneris/downscaling/intensity_convergence.py new file mode 100644 index 0000000..196aba8 --- /dev/null +++ b/src/aneris/downscaling/intensity_convergence.py @@ -0,0 +1,447 @@ +import logging +from typing import Any, Optional, Union + +import numpy as np +from pandas import DataFrame, Series, concat +from pandas_indexing import isin, semijoin +from scipy.interpolate import interp1d +from scipy.optimize import root_scalar + +from ..utils import normalize +from .data import DownscalingContext + + +logger = logging.getLogger(__name__) + + +class ConvergenceError(RuntimeError): + pass + + +def make_affine_transform(x1, x2, y1=0.0, y2=1.0): + """Returns an affine transform that maps `x1` to `y1` and `x2` to `y2`""" + + def f(x): + return (y2 - y1) * (x - x1) / (x2 - x1) + y1 + + return f + + +def compute_intensity( + model: DataFrame, reference: DataFrame, convergence_year: int +) -> DataFrame: + intensity = model.idx.divide(reference, join="left") + + model_years = model.columns + if convergence_year > model_years[-1]: + x2 = model_years[-1] + x1 = x2 - 10 if x2 - 10 in model_years else model_years[-2] + + y1 = model[x1] + y2 = model[x2] + model_conv = (y2 * (y2 / y1) ** ((convergence_year - x2) / (x2 - x1))).where( + y2 > 0, y2 + (y2 - y1) * (convergence_year - x2) / (x2 - x1) + ) + + y1 = reference[x1] + y2 = reference[x2] + reference_conv = y2 * (y2 / y1) ** ((convergence_year - x2) / (x2 - x1)) + + intensity[convergence_year] = model_conv / reference_conv + else: + intensity = intensity.loc[:, :convergence_year] + + return intensity + + +def determine_scaling_parameter( + alpha: Series, + intensity_hist: Series, + intensity: Series, + reference: DataFrame, + intensity_projection_linear: DataFrame, + index: dict[str, Any], + context: DownscalingContext, +) -> float: + """Determine scaling parameter for negative exponential intensity model + + Gamma parameter for a single macro trajectory + + Parameters + ---------- + alpha : Series + Map from years to 0-1 range + intensity_hist : Series + Historic intensity of countries in base year + intensity : Series + Projected intensity of one worldregion/model + reference : DataFrame + Denominator of intensity + intensity_projection_linear : DataFrame + Per-country intensities previously determined by linear model + index : dict[str, Any] + Index levels of the full dataframe intensity + context : DownscalingContext + + Returns + ------- + gamma : float + """ + levels = list(context.index) + [context.region_level] + + negative_at_start = intensity.iloc[0] + if negative_at_start: + raise ConvergenceError("Trajectory is fully negative") + + selector_levels = isin(**{k: v for k, v in index.items() if k in levels}) + reference = reference.loc[selector_levels] + intensity_hist = intensity_hist.loc[selector_levels] + + intensity_projection_linear = intensity_projection_linear.loc[isin(**index)] + + # determine alpha_star, where projected emissions become negative + res = root_scalar( + interp1d(alpha, intensity), + method="brentq", + bracket=[0, 1], + ) + if not res.converged: + raise ConvergenceError( + "Could not find alpha_star for which emissions cross into zero" + ) + alpha_star = res.root + year_star = make_affine_transform(0, 1, *intensity.index[[0, -1]])(alpha_star) + + # reference at alpha_star + def at_alpha_star(df, alpha=alpha): + return df.apply( + ( + lambda s: interp1d(alpha, s, kind="slinear", fill_value="extrapolate")( + alpha_star + ) + ), + axis=1, + ) + + ref = at_alpha_star(reference, alpha=alpha[: len(reference.columns)]) + + if intensity_projection_linear is not None: + offset = (ref * at_alpha_star(intensity_projection_linear)).sum() + else: + offset = 0 + + # determine gamma scaling parameter with which the sum of the weights from + # the transformed model vanish at alpha_star + def sum_weight_at_alpha_star(gamma): + x0, x1 = intensity.iloc[[0, -1]] + f = make_affine_transform(x0, x1, gamma, 1.0) + inv_f = make_affine_transform(gamma, 1.0, x0, x1) + + return ( + ref * inv_f((f(x1) / f(intensity_hist)) ** alpha_star * f(intensity_hist)) + ).sum() + offset + + # Widen gamma_max until finding a sign flip in sum_weight_at_alpha_star + gamma_min = 1.5 + gamma_max = 10 * gamma_min + sum_weight_min = sum_weight_at_alpha_star(gamma_min) + while sum_weight_min * sum_weight_at_alpha_star(gamma_max) > 0: + if gamma_max >= 1e7: + raise ConvergenceError( + f"Exponential model does not converge to " + f"{intensity.iloc[-1]} at {intensity.index[-1]}, " + f"while guaranteeing zero emissions in {year_star}" + ) + gamma_max *= 10 + + res = root_scalar( + sum_weight_at_alpha_star, + method="brentq", + bracket=[gamma_max / 10, gamma_max], + ) + if not res.converged: + raise ConvergenceError( + "Could not determine scaling parameter gamma such that the weights" + "from the exponential model vanish exactly with intensity" + ) + + gamma = res.root + + logger.debug( + "Determined year(alpha_star) = %.2f, and gamma = %.2f", + year_star, + gamma, + ) + + return gamma + + +def negative_exponential_intensity_model( + alpha: Series, + intensity_hist: Series, + intensity: DataFrame, + reference: DataFrame, + intensity_projection_linear: DataFrame, + context: DownscalingContext, + allow_fallback_to_linear: bool = True, +) -> DataFrame: + """Create a per-country time-series of intensities w/ negative intensities + + Parameters + ---------- + alpha : Series + Map from years to 0-1 range + intensity_hist : Series + Historic intensity of countries in base year + intensity : DataFrame + Projected intensity of worldregion + reference : DataFrame + Denominator of intensity + intensity_projection_linear : DataFrame + _description_ + context : DownscalingContext + + Returns + ------- + DataFrame + _description_ + + Raises + ------ + ConvergenceError + if it can not determine all scaling parameters + """ + + gammas = np.empty(len(intensity)) + + for i, (index, intensity_traj) in enumerate(intensity.iterrows()): + + index = dict(zip(intensity.index.names, index)) + try: + gammas[i] = determine_scaling_parameter( + alpha, + intensity_hist, + intensity_traj, + reference, + intensity_projection_linear, + index, + context, + ) + except ConvergenceError: + if not allow_fallback_to_linear: + raise + gammas[i] = np.nan + + gammas = Series(gammas, intensity.index) + + f = make_affine_transform(intensity.iloc[:, 0], intensity.iloc[:, -1], gammas, 1.0) + inv_f = make_affine_transform( + gammas, 1.0, intensity.iloc[:, 0], intensity.iloc[:, -1] + ) + + intensity, intensity_hist = intensity.align(intensity_hist, join="left", axis=0) + + intensity_projection = DataFrame( + inv_f( + (f(intensity.values[:, -1]) / f(intensity_hist.values))[:, np.newaxis] + ** alpha.values + * f(intensity_hist.values)[:, np.newaxis] + ), + index=intensity_hist.index, + columns=intensity.columns, + ).where( + gammas.notna(), + intensity_growth_rate_model(intensity, intensity_hist), + ) + + return intensity_projection + + +def exponential_intensity_model( + alpha: Series, intensity_hist: Series, intensity: DataFrame +) -> DataFrame: + positive_intensity = intensity.iloc[:, -1] > 0 + if positive_intensity.all(): + f = inv_f = lambda x: x + else: + f = lambda x: np.where(positive_intensity, x, x + 1) + inv_f = lambda x: np.where(positive_intensity, x, x - 1) + + intensity_hist = semijoin(intensity_hist, intensity.index, how="right") + + intensity_projection = DataFrame( + inv_f( + (f(intensity.values[:, -1]) / f(intensity_hist.values))[:, np.newaxis] + ** alpha.values + * f(intensity_hist.values)[:, np.newaxis] + ), + index=intensity_hist.index, + columns=intensity.columns, + ) + + return intensity_projection + + +def linear_intensity_model( + alpha: Series, intensity_hist: Series, intensity: DataFrame +) -> DataFrame: + intensity_projection = DataFrame( + (1 - alpha).values * intensity_hist.values[:, np.newaxis] + + alpha.values * intensity.values[:, -1], + index=intensity.index, + columns=intensity.columns, + ) + + return intensity_projection + + +def intensity_growth_rate_model( + intensity: DataFrame, intensity_hist: Series +) -> DataFrame: + years_downscaling = intensity.columns + intensity_projection = DataFrame( + ( + 1 + + (intensity.iloc[:, -1] / intensity_hist - 1) + / (years_downscaling[-1] - years_downscaling[0]) + ).values[:, np.newaxis] + ** np.arange(0, len(years_downscaling)) + * intensity_hist.values[:, np.newaxis], + index=intensity_hist.index, + columns=years_downscaling.rename("year"), + ) + return intensity_projection + + +def intensity_convergence( + model: DataFrame, + hist: Union[Series, DataFrame], + context: DownscalingContext, + proxy_name: str = "gdp", + convergence_year: Optional[int] = 2100, + allow_fallback_to_linear: bool = True, +) -> DataFrame: + """Downscales emission data using emission intensity convergence + + Parameters + ---------- + model : DataFrame + model emissions for each world region and trajectory + historic : DataFrame or Series + historic emissions for each country and trajectory + context : DownscalingContext + settings for downscaling, like the regionmap, and + additional_data. + proxy_name : str, default "gdp" + name of the additional data used as a reference for intensity + (intensity = model/reference) + convergence_year : int, default 2100 + year of emission intensity convergence + + Returns + ------- + DataFrame + downscaled emissions for countries + + TODO + ---- + We are assembling a dictionary, with intermediate results as `diagnostics`. Would be + nice to give the user intuitive access. + + References + ---------- + Gidden, M. et al. Global emissions pathways under different socioeconomic + scenarios for use in CMIP6: a dataset of harmonized emissions trajectories + through the end of the century. Geoscientific Model Development Discussions 12, + 1443–1475 (2019). + """ + + if isinstance(hist, DataFrame): + hist = hist.iloc[:, -1] + + reference = semijoin(context.additional_data[proxy_name], context.regionmap_index) + reference_region = reference.groupby(context.region_level).sum() + hist = semijoin(hist, context.regionmap_index) + + intensity = compute_intensity(model, reference_region, convergence_year) + intensity_hist = hist / reference.iloc[:, 0] + + alpha = make_affine_transform(intensity.columns[0], convergence_year)( + intensity.columns + ) + intensity_countries, intensity_hist = intensity.align( + intensity_hist, join="left", axis=0 + ) + + # use a linear model for sub-regions with an intensity below the convergence intensity + low_intensity = intensity_hist <= intensity_countries.iloc[:, -1] + + if low_intensity.any(): + intensity_projection_linear = linear_intensity_model( + alpha, + intensity_hist.loc[low_intensity], + intensity_countries.loc[low_intensity], + ) + logger.debug( + "Linear model was chosen for some trajectories: %s", + ", ".join(intensity_hist.index[low_intensity]), + ) + else: + intensity_projection_linear = None + del intensity_countries + + negative_convergence = intensity.iloc[:, -1] < 0 + if negative_convergence.any(): + negative_convergence_i = negative_convergence.index[negative_convergence] + # sum does not work here. We need the individual per-country dimension + negative_intensity_projection = negative_exponential_intensity_model( + alpha, + intensity_hist, + intensity.loc[negative_convergence], + reference, + None + if intensity_projection_linear is None + else semijoin( + intensity_projection_linear, negative_convergence_i, how="right" + ), + context + ) + + else: + negative_intensity_projection = None + + if not negative_convergence.all(): + exponential_intensity_projection = exponential_intensity_model( + alpha, + intensity_hist.loc[~negative_convergence & ~low_intensity], + intensity.loc[~negative_convergence], + ) + else: + exponential_intensity_projection = None + + intensity_projection = concat( + filter( + None, + [ + exponential_intensity_projection, + negative_intensity_projection, + intensity_projection_linear, + ], + ), + sort=False, + ).reindex(index=intensity.index) + + intensity_projection = intensity_projection.loc[:, model.columns[-1]] + + if model.columns[-1] > intensity_projection.columns[-1]: + # Extend modelled intensity projection beyond year_convergence + intensity_projection = intensity_projection.reindex( + columns=model.columns, method="ffill" + ) + + weights = ( + (reference * intensity_projection) + .groupby(list(context.index) + [context.region_level]) + .transform(normalize) + ) + return model.multiply(weights, how="left") diff --git a/src/aneris/downscaling/methods.py b/src/aneris/downscaling/methods.py new file mode 100644 index 0000000..1943db4 --- /dev/null +++ b/src/aneris/downscaling/methods.py @@ -0,0 +1,110 @@ +import logging +from collections.abc import Sequence +from dataclasses import dataclass, field +from typing import Optional, Union + +from pandas import DataFrame, MultiIndex, Series +from pandas_indexing import semijoin + +from ..utils import normalize +from .data import DownscalingContext +from .intensity_convergence import intensity_convergence + + +logger = logging.getLogger(__name__) + + + +def base_year_pattern( + model: DataFrame, hist: Union[Series, DataFrame], context: DownscalingContext +) -> DataFrame: + """Downscales emission data using a base year pattern + + Parameters + ---------- + model : DataFrame + model emissions for each world region and trajectory + historic : DataFrame or Series + historic emissions for each country and trajectory + context : DownscalingContext + settings for downscaling, like the regionmap + + Returns + ------- + DataFrame: + downscaled emissions for countries + + Notes + ----- + 1. All trajectories in `model` exist in `hist` + a. `model` has the levels in `index` and "region" + b. `hist` has the levels in `index` and "country" + 2. region mapping has two indices the first one is fine, the second coarse + + See also + -------- + DownscalingContext + """ + + if isinstance(hist, DataFrame): + hist = hist.iloc[:, -1] + + weights = ( + semijoin(hist, context.regionmap_index) + .groupby(list(context.index) + [context.region_level]) + .transform(normalize) + ) + + return model.idx.multiply(weights, join="left") + + +def growth_rate( + model: DataFrame, + hist: Union[Series, DataFrame], + context: DownscalingContext, +) -> DataFrame: + """Downscales emission data using growth rates + + Assumes growth rates in all sub regions are the same as in the macro_region + + Parameters + ---------- + model : DataFrame + model emissions for each world region and trajectory + historic : DataFrame or Series + historic emissions for each country and trajectory + context : DownscalingContext + settings for downscaling, like the regionmap + + Returns + ------- + DataFrame: + downscaled emissions for countries + + Notes + ----- + 1. All trajectories in `model` exist in `hist` + a. `model` has the levels in `index` and "region" + b. `hist` has the levels in `index` and "country" + 2. region mapping has two indices the first one is fine, the second coarse + """ + + if isinstance(hist, DataFrame): + hist = hist.iloc[:, -1] + + cumulative_growth_rates = (model / model.shift(axis=1, fill_value=1)).cumprod( + axis=1 + ) + + weights = ( + cumulative_growth_rates.idx.multiply( + semijoin(hist, context.regionmap_index), + join="left", + ) + .groupby(list(context.index) + [context.region_level]) + .transform(normalize) + ) + + return model * weights + + diff --git a/src/aneris/utils.py b/src/aneris/utils.py index 17054a7..23570e2 100644 --- a/src/aneris/utils.py +++ b/src/aneris/utils.py @@ -42,24 +42,6 @@ def numcols(df): return [i for i in dtypes.index if dtypes.loc[i].name.startswith(("float", "int"))] -def isin(df=None, **filters): - """ - Constructs a MultiIndex selector. - - Usage - ----- - > df.loc[isin(region="World", gas=["CO2", "N2O"])] - or with explicit df to get boolean mask - > isin(df, region="World", gas=["CO2", "N2O"]) - """ - - def tester(df): - tests = (df.index.isin(np.atleast_1d(v), level=k) for k, v in filters.items()) - return reduce(and_, tests, next(tests)) - - return tester if df is None else tester(df) - - def isstr(x): """ Returns True if x is a string. @@ -122,3 +104,7 @@ def pd_write(df, f, *args, **kwargs): writer = pd.ExcelWriter(f) df.to_excel(writer, index=index, *args, **kwargs) writer.save() + + +def normalize(s): + return s / s.sum() \ No newline at end of file diff --git a/tests/test_utils.py b/tests/test_utils.py index 6af5a32..fc6f68c 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -22,29 +22,4 @@ def combine_rows_df(): "gas": ["BC"] * 5, } ).set_index(utils.df_idx) - return df - - -def test_isin(): - df = combine_rows_df() - exp = pd.DataFrame( - { - "sector": [ - "sector1", - "sector2", - "sector1", - ], - "region": ["a", "a", "b"], - "2010": [1.0, 4.0, 2.0], - "foo": [-1.0, -4.0, 2.0], - "unit": ["Mt"] * 3, - "gas": ["BC"] * 3, - } - ).set_index(utils.df_idx) - obs = exp.loc[ - utils.isin(sector=["sector1", "sector2"], region=["a", "b", "non-existent"]) - ] - pdt.assert_frame_equal(obs, exp) - - with pytest.raises(KeyError): - utils.isin(df, region="World", non_existing_level="foo") + return df \ No newline at end of file From 3f26663f7539574640900d8c5b6bf54b7801b499 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Mon, 3 Apr 2023 18:33:03 +0200 Subject: [PATCH 12/77] Improve harmonization bits with pandas_indexing --- src/aneris/cmip6/driver.py | 9 ++------- src/aneris/convenience.py | 5 ++--- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/aneris/cmip6/driver.py b/src/aneris/cmip6/driver.py index 44d5587..0f6a067 100644 --- a/src/aneris/cmip6/driver.py +++ b/src/aneris/cmip6/driver.py @@ -1,7 +1,6 @@ import numpy as np import pandas as pd - -from pandas_indexing import isin +from pandas_indexing import assignlevel, isin import aneris.cmip6.cmip6_utils as cmip6_utils import aneris.utils as utils @@ -9,7 +8,6 @@ from aneris.utils import pd_read - class _TrajectoryPreprocessor: def __init__(self, hist, model, overrides, regions, prefix, suffix): self.hist = hist @@ -279,10 +277,7 @@ def harmonize(self, scenario, diagnostic_config=None): ) # collect metadata - self._meta = self._meta.reset_index() - self._meta["model"] = self.model_name - self._meta["scenario"] = scenario - self._meta = self._meta.set_index(["model", "scenario"]) + self._meta = assignlevel(self._meta, model=self.model_name, scenario=scenario) self._postprocess_trajectories(scenario) # store results diff --git a/src/aneris/convenience.py b/src/aneris/convenience.py index 64825ce..5319c22 100644 --- a/src/aneris/convenience.py +++ b/src/aneris/convenience.py @@ -1,7 +1,7 @@ import pandas as pd import pyam from openscm_units import unit_registry -from pandas_indexing import isin, semijoin +from pandas_indexing import isin, semijoin, projectlevel from .errors import ( AmbiguousHarmonisationMethod, @@ -100,9 +100,8 @@ def _knead_overrides(overrides, scen, harm_idx): def _check_data(hist, scen, year): check = ["region", "variable"] - # @coroa - this may be a very slow way to do this check.. def downselect(df): - return df.filter(year=year)._data.reset_index().set_index(check).index.unique() + return projectlevel(df._data.index[isin(df._data, year=year)], check) s = downselect(scen) h = downselect(hist) From 8b421ab8b4654a4aa11b38787d13e3af5110215b Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Wed, 5 Apr 2023 17:07:16 +0200 Subject: [PATCH 13/77] Extend harmonization method selection to downscaling --- src/aneris/harmonize.py | 53 ++++++++++++++++++++--------------------- src/aneris/methods.py | 26 ++++++++++---------- 2 files changed, 38 insertions(+), 41 deletions(-) diff --git a/src/aneris/harmonize.py b/src/aneris/harmonize.py index 5e1e5dc..bb102e0 100644 --- a/src/aneris/harmonize.py +++ b/src/aneris/harmonize.py @@ -60,7 +60,7 @@ def downselect(df): ) -def _check_overrides(overrides, idx): +def _check_overrides(overrides, data_index): if overrides is None: return @@ -70,8 +70,16 @@ def _check_overrides(overrides, idx): if not overrides.name == "method": raise ValueError("Overrides name must be method") - if not overrides.index.name != idx: - raise ValueError(f"Overrides must be indexed by {idx}") + # Check whether there exists an override for at least one data variable + _, lidx, _ = overrides.index.join(data_index, how="right", return_indexers=True) + if lidx is None: + return + + if (lidx == -1).all(): + raise ValueError( + "overrides must have at least one index dimension " + f"aligned with methods: {data_index.names}" + ) class Harmonizer: @@ -155,11 +163,11 @@ def check_idx(df, label): ) self.method_choice = method_choice - # get default methods to use in decision tree - self.ratio_method = config.get("default_ratio_method") - self.offset_method = config.get("default_offset_method") - self.luc_method = config.get("default_luc_method") - self.luc_cov_threshold = config.get("luc_cov_threshold") + # set default methods to use in decision tree + self.ratio_method = config.get("default_ratio_method", "reduce_ratio_2080") + self.offset_method = config.get("default_offset_method", "reduce_offset_2080") + self.luc_method = config.get("default_luc_method", "reduce_offset_2150_cov") + self.luc_cov_threshold = config.get("luc_cov_threshold", 10) def metadata(self): """ @@ -216,13 +224,10 @@ def _default_methods(self, year): def _harmonize(self, method, idx, check_len, base_year): # get data - def downselect(df, idx, level="unit"): - return df.reset_index(level=level).loc[idx].set_index(level, append=True) - - model = downselect(self.data, idx) - hist = downselect(self.history, idx) - offsets = downselect(self.offsets, idx)["offset"] - ratios = downselect(self.ratios, idx)["ratio"] + model = semijoin(self.data, idx, how="right") + hist = semijoin(self.history, idx, how="right") + offsets = semijoin(self.offsets, idx, how="right") + ratios = semijoin(self.ratios, idx, how="right") # get delta delta = hist if method == "budget" else ratios if "ratio" in method else offsets @@ -255,16 +260,10 @@ def methods(self, year=None, overrides=None): """ # get method listing base_year = year if year is not None else self.base_year or "2015" - _check_overrides(overrides, self.harm_idx) + _check_overrides(overrides, self.data.index) methods = self._default_methods(year=base_year) if overrides is not None: - # overrides requires an index - if overrides.index.names == [None]: - raise ValueError( - "overrides must have at least on index dimension " - f"aligned with methods: {methods.index.names}" - ) # expand overrides index to match methods and align indicies overrides = semijoin(overrides, methods.index, how="right").reorder_levels( methods.index.names @@ -277,10 +276,11 @@ def methods(self, year=None, overrides=None): overrides.name = methods.name # overwrite defaults with overrides - final_methods = overrides.combine_first(methods).to_frame() - final_methods["default"] = methods - final_methods["override"] = overrides - methods = final_methods + methods = ( + overrides.combine_first(methods) + .to_frame() + .assign(default=methods, override=overrides) + ) return methods @@ -291,7 +291,6 @@ def harmonize(self, year=None, overrides=None): """ base_year = year if year is not None else self.base_year or "2015" _check_data(self.history, self.data, base_year, self.harm_idx) - _check_overrides(overrides, self.harm_idx) self.model = pd.Series( index=self.data.index, name=base_year, dtype=float diff --git a/src/aneris/methods.py b/src/aneris/methods.py index cb42994..5113b3f 100644 --- a/src/aneris/methods.py +++ b/src/aneris/methods.py @@ -439,7 +439,7 @@ def default_method_choice( def default_methods(hist, model, base_year, method_choice=None, **kwargs): """ - Determine default harmonization methods to use. + Determine default harmonization or downscaling methods to use. See http://mattgidden.com/aneris/theory.html#default-decision-tree for a graphical description of the decision tree. @@ -455,17 +455,24 @@ def default_methods(hist, model, base_year, method_choice=None, **kwargs): method_choice : function, optional codified decision tree, see `default_method_choice` function **kwargs : - Additional parameters passed on to the choice function: + Additional parameters passed on to the choice functions. - ratio_method : string, optional + Harmonization functions might depend on the following method names: + ratio_method : string method to use for ratio harmonization, default: reduce_ratio_2080 - offset_method : string, optional + offset_method : string method to use for offset harmonization, default: reduce_offset_2080 - luc_method : string, optional + luc_method : string method to use for high coefficient of variation, reduce_offset_2150_cov luc_cov_threshold : float cov threshold above which to use `luc_method` + Downscaling functions require the following choices: + intensity_method : string + method to use for intensity convergence, default ipat_gdp_2100 + luc_method : string + method to use for agriculture and luc emissions, default base_year_pattern + Returns ------- methods : pd.Series @@ -478,15 +485,6 @@ def default_methods(hist, model, base_year, method_choice=None, **kwargs): `default_method_choice` """ - if kwargs.get("ratio_method") is None: - kwargs["ratio_method"] = "reduce_ratio_2080" - if kwargs.get("offset_method") is None: - kwargs["offset_method"] = "reduce_offset_2080" - if kwargs.get("luc_method") is None: - kwargs["luc_method"] = "reduce_offset_2150_cov" - if kwargs.get("luc_cov_threshold") is None: - kwargs["luc_cov_threshold"] = 10 - y = str(base_year) try: h = hist[base_year] From 1b8e20e0a029231687b97cc39a4ce6c34dd96299 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Wed, 5 Apr 2023 17:08:47 +0200 Subject: [PATCH 14/77] Add method selection to downscaling --- src/aneris/downscaling/core.py | 151 +++++++++++++++++++++--------- src/aneris/downscaling/methods.py | 13 +++ src/aneris/errors.py | 5 + 3 files changed, 125 insertions(+), 44 deletions(-) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index e585bf8..bc68c08 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -1,12 +1,18 @@ -from typing import Optional, Sequence, Callable from functools import partial +from typing import Optional, Sequence -from pandas import DataFrame, Series, Index -from pandas_indexing import projectlevel, semijoin +from pandas import DataFrame, Series +from pandas_indexing import semijoin +from ..errors import MissingHistoricalError, MissingProxyError from ..methods import default_methods from .data import DownscalingContext -from .methods import base_year_pattern, growth_rate, intensity_convergence +from .methods import ( + base_year_pattern, + default_method_choice, + growth_rate, + intensity_convergence, +) DEFAULT_INDEX = ("sector", "gas") @@ -31,6 +37,7 @@ def __init__( self, model: DataFrame, hist: DataFrame, + year: int, region_mapping: Series, index: Sequence[str] = DEFAULT_INDEX, return_type=DataFrame, @@ -38,6 +45,7 @@ def __init__( ): self.model = model self.hist = hist + self.year = year self.region_mapping = region_mapping self.index = index self.return_type = return_type @@ -47,18 +55,84 @@ def __init__( self.country_level = self.region_mapping.index.name assert ( - hist.groupby(list(index) + [self.region_level]).count() <= 1 - ).all(), "More than one hist" - assert ( - projectlevel(model.index, list(index) + [self.region_level]) - .difference(projectlevel(hist.index, list(index) + [self.region_level])) - .empty - ), "History missing for some" + hist[year].groupby(list(index) + [self.country_level]).count() <= 1 + ).all(), "Ambiguous history" + + missing_hist = ( + model.index.join(self.context.regionmap_index, how="right") + .idx.project(list(index) + [self.country_level]) + .difference(hist.index.idx.project(list(index) + [self.country_level])) + ) + if not missing_hist.empty: + raise MissingHistoricalError( + "History missing for variables/countries:\n" + + missing_hist.to_frame().to_string(index=False), + missing_hist, + ) # TODO Make configurable by re-using config just as in harmonizer self.intensity_method = "ipat_2100_gdp" self.linear_method = "base_year_pattern" + + @property + def context(self): + return DownscalingContext( + self.index, + self.region_mapping, + self.additional_data, + self.country_level, + self.region_level, + ) + + def check_proxies(self, methods: Series) -> None: + """Checks proxies required for chosen `methods` + + Parameters + ---------- + methods : Series + Methods to be used for each trajectory + + Raises + ------ + MissingProxyError + if a required proxy is missing or incomplete + """ + # TODO: Check that data contains what is needed for all methods in use, ie. + # inspect partial keywords + for method in methods.unique(): + proxy_name = getattr(self._methods[method], "kwargs", {}).get("proxy_name") + if proxy_name is None: + continue + + proxy = self.additional_data.get(proxy_name) + if proxy is None: + raise MissingProxyError( + f"Downscaling method `{method}` requires the additional data" + f" `{proxy_name}`" + ) + + # TODO checking the columns/years might also be a good idea + trajectory_index = methods.index[methods == method] + + # trajectory index typically has the levels model, scenario, region, sector, + # gas, while proxy data is expected on country level (and probably no model, + # scenario dependency, but potentially) + proxy = semijoin(proxy, self.context.regionmap_index, how="right") + + common_levels = proxy.index.names.intersection(trajectory_index.names) + missing_proxy = ( + trajectory_index.idx.project(common_levels) + .difference(proxy.index.idx.project(common_levels)) + .unique() + ) + if not missing_proxy.empty: + raise MissingProxyError( + f"The proxy data `{proxy} is missing data:\n" + + missing_proxy.to_frame().to_string(index=False), + missing_proxy, + ) + def downscale(self, methods: Optional[Series] = None) -> DataFrame: """Downscale aligned model data from historical data, and socio-economic scenario @@ -78,7 +152,16 @@ def downscale(self, methods: Optional[Series] = None) -> DataFrame: if methods is None: methods = self.methods() - # Check that data contains what is needed for all methods in use, ie. inspect partial keywords + hist_ext = semijoin(self.hist, self.context.regionmap_index, how="right") + self.check_proxies(methods) + + downscaled = [] + method_groups = methods.index.groupby(methods) + for method, trajectory_index in method_groups.items(): + hist = semijoin(hist_ext, trajectory_index, how="right") + model = semijoin(self.model, trajectory_index, how="right") + + downscaled.append(self._methods[method](model, hist, self.context)) return self.return_type(downscaled) @@ -90,19 +173,24 @@ def methods(self, method_choice=None, overwrites=None): method_choice = default_method_choice hist_agg = ( - semijoin(self.hist, self.context.regionmap_index) - .groupby(list(self.index) + [self.country_level], dropna=False) + semijoin(self.hist, self.context.regionmap_index, how="right") + .groupby(list(self.index) + [self.region_level], dropna=False) .sum() ) - methods = default_methods( - projectlevel(self.model, list(self.index) + [self.region_level]), - hist_agg, + methods, meta = default_methods( + semijoin(hist_agg, self.model.index, how="right").reorder_levels( + self.model.index.names + ), + self.model, + self.year, method_choice=method_choice, intensity_method=self.intensity_method, - linear_method=self.linear_method, + luc_method=self.luc_method, ) - if isinstance(overwrites, str): + if overwrites is None: + return methods + elif isinstance(overwrites, str): return Series(overwrites, methods.index) elif isinstance(overwrites, dict): overwrites = Series(overwrites).rename_axis("sector") @@ -112,28 +200,3 @@ def methods(self, method_choice=None, overwrites=None): .fillna(methods) .rename("method") ) - - @property - def context(self): - return DownscalingContext( - self.index, - self.region_mapping, - self.additional_data, - self.country_level, - self.region_level, - ) - - -def default_method_choice(traj, intensity_method, linear_method): - """Default downscaling decision tree""" - - # special cases - if traj.h == 0: - return linear_method - if traj.zero_m: - return linear_method - - if traj.get("sector", None) in ("Agriculture", "LULUCF"): - return linear_method - - return intensity_method diff --git a/src/aneris/downscaling/methods.py b/src/aneris/downscaling/methods.py index 1943db4..6349024 100644 --- a/src/aneris/downscaling/methods.py +++ b/src/aneris/downscaling/methods.py @@ -108,3 +108,16 @@ def growth_rate( return model * weights +def default_method_choice(traj, intensity_method, luc_method): + """Default downscaling decision tree""" + + # special cases + if traj.h == 0: + return luc_method + if traj.zero_m: + return luc_method + + if traj.get("sector", None) in ("Agriculture", "LULUCF"): + return luc_method + + return intensity_method diff --git a/src/aneris/errors.py b/src/aneris/errors.py index 583a717..61b8df5 100644 --- a/src/aneris/errors.py +++ b/src/aneris/errors.py @@ -9,6 +9,11 @@ class MissingHistoricalError(ValueError): Error raised when historical data is missing. """ +class MissingProxyError(ValueError): + """ + Error raised when required proxy data is missing. + """ + class MissingScenarioError(ValueError): """ From 82452d365a6778ac2d63d298bbfd50f575206516 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Fri, 7 Apr 2023 18:57:16 +0200 Subject: [PATCH 15/77] Add proxy checking --- src/aneris/downscaling/core.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index bc68c08..32b1b40 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -98,10 +98,10 @@ def check_proxies(self, methods: Series) -> None: MissingProxyError if a required proxy is missing or incomplete """ - # TODO: Check that data contains what is needed for all methods in use, ie. - # inspect partial keywords for method in methods.unique(): - proxy_name = getattr(self._methods[method], "kwargs", {}).get("proxy_name") + proxy_name = getattr(self._methods[method], "keywords", {}).get( + "proxy_name" + ) if proxy_name is None: continue @@ -112,7 +112,6 @@ def check_proxies(self, methods: Series) -> None: f" `{proxy_name}`" ) - # TODO checking the columns/years might also be a good idea trajectory_index = methods.index[methods == method] # trajectory index typically has the levels model, scenario, region, sector, @@ -120,7 +119,9 @@ def check_proxies(self, methods: Series) -> None: # scenario dependency, but potentially) proxy = semijoin(proxy, self.context.regionmap_index, how="right") - common_levels = proxy.index.names.intersection(trajectory_index.names) + common_levels = [ + l for l in trajectory_index.names if l in proxy.index.names + ] missing_proxy = ( trajectory_index.idx.project(common_levels) .difference(proxy.index.idx.project(common_levels)) @@ -128,9 +129,18 @@ def check_proxies(self, methods: Series) -> None: ) if not missing_proxy.empty: raise MissingProxyError( - f"The proxy data `{proxy} is missing data:\n" - + missing_proxy.to_frame().to_string(index=False), - missing_proxy, + f"The proxy data `{proxy_name}` is missing data for the following trajectories:\n" + + missing_proxy.to_frame().to_string(index=False) + ) + + if not isinstance(proxy, DataFrame): + return + + missing_years = self.model.columns.difference(proxy.columns) + if not missing_years.empty: + raise MissingProxyError( + f"The proxy data `{proxy_name}` is missing model year(s): " + + ", ".join(missing_years.astype(str)) ) def downscale(self, methods: Optional[Series] = None) -> DataFrame: From fc5a8c18c064ff1c5b9281519ee1d4914c503df1 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Fri, 7 Apr 2023 18:58:14 +0200 Subject: [PATCH 16/77] Create downscaling context early --- src/aneris/downscaling/core.py | 40 +++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index 32b1b40..b5fff9a 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -46,13 +46,14 @@ def __init__( self.model = model self.hist = hist self.year = year - self.region_mapping = region_mapping - self.index = index self.return_type = return_type - self.additional_data = additional_data - - self.region_level = self.region_mapping.name - self.country_level = self.region_mapping.index.name + self.context = DownscalingContext( + index, + region_mapping, + additional_data, + country_level=region_mapping.index.name, + region_level=region_mapping.name, + ) assert ( hist[year].groupby(list(index) + [self.country_level]).count() <= 1 @@ -72,18 +73,27 @@ def __init__( # TODO Make configurable by re-using config just as in harmonizer self.intensity_method = "ipat_2100_gdp" - self.linear_method = "base_year_pattern" + self.luc_method = "base_year_pattern" + @property + def index(self): + return self.context.index @property - def context(self): - return DownscalingContext( - self.index, - self.region_mapping, - self.additional_data, - self.country_level, - self.region_level, - ) + def region_mapping(self): + return self.context.regionmap + + @property + def additional_data(self): + return self.context.additional_data + + @property + def country_level(self): + return self.context.country_level + + @property + def region_level(self): + return self.context.region_level def check_proxies(self, methods: Series) -> None: """Checks proxies required for chosen `methods` From 676309a1a37d5091686c82c5edc84409b3975937 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Fri, 7 Apr 2023 19:01:33 +0200 Subject: [PATCH 17/77] Fix downscaling methods --- src/aneris/downscaling/core.py | 11 +- .../downscaling/intensity_convergence.py | 142 ++++++++++-------- src/aneris/downscaling/methods.py | 21 ++- 3 files changed, 97 insertions(+), 77 deletions(-) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index b5fff9a..09a13b4 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -2,7 +2,7 @@ from typing import Optional, Sequence from pandas import DataFrame, Series -from pandas_indexing import semijoin +from pandas_indexing import concat, semijoin from ..errors import MissingHistoricalError, MissingProxyError from ..methods import default_methods @@ -60,15 +60,14 @@ def __init__( ).all(), "Ambiguous history" missing_hist = ( - model.index.join(self.context.regionmap_index, how="right") + model.index.join(self.context.regionmap_index, how="left") .idx.project(list(index) + [self.country_level]) .difference(hist.index.idx.project(list(index) + [self.country_level])) ) if not missing_hist.empty: raise MissingHistoricalError( "History missing for variables/countries:\n" - + missing_hist.to_frame().to_string(index=False), - missing_hist, + + missing_hist.to_frame().to_string(index=False) ) # TODO Make configurable by re-using config just as in harmonizer @@ -183,7 +182,7 @@ def downscale(self, methods: Optional[Series] = None) -> DataFrame: downscaled.append(self._methods[method](model, hist, self.context)) - return self.return_type(downscaled) + return self.return_type(concat(downscaled)) def methods(self, method_choice=None, overwrites=None): if method_choice is not None: @@ -217,6 +216,6 @@ def methods(self, method_choice=None, overwrites=None): return ( semijoin(overwrites, methods.index, how="right") - .fillna(methods) + .combine_first(methods) .rename("method") ) diff --git a/src/aneris/downscaling/intensity_convergence.py b/src/aneris/downscaling/intensity_convergence.py index 196aba8..a2ffc37 100644 --- a/src/aneris/downscaling/intensity_convergence.py +++ b/src/aneris/downscaling/intensity_convergence.py @@ -2,7 +2,7 @@ from typing import Any, Optional, Union import numpy as np -from pandas import DataFrame, Series, concat +from pandas import DataFrame, MultiIndex, Series, concat from pandas_indexing import isin, semijoin from scipy.interpolate import interp1d from scipy.optimize import root_scalar @@ -27,6 +27,12 @@ def f(x): return f +def make_affine_transform_pair(x1, x2, y1, y2): + f = make_affine_transform(x1, x2, y1, y2) + inv_f = make_affine_transform(y1, y2, x1, x2) + return f, inv_f + + def compute_intensity( model: DataFrame, reference: DataFrame, convergence_year: int ) -> DataFrame: @@ -87,17 +93,14 @@ def determine_scaling_parameter( ------- gamma : float """ - levels = list(context.index) + [context.region_level] - - negative_at_start = intensity.iloc[0] + negative_at_start = intensity.iloc[0] < 0 if negative_at_start: raise ConvergenceError("Trajectory is fully negative") - selector_levels = isin(**{k: v for k, v in index.items() if k in levels}) - reference = reference.loc[selector_levels] - intensity_hist = intensity_hist.loc[selector_levels] - - intensity_projection_linear = intensity_projection_linear.loc[isin(**index)] + selector = isin(**index, ignore_missing_levels=True) + reference = reference.loc[selector] + intensity_hist = intensity_hist.loc[selector] + intensity_projection_linear = intensity_projection_linear.loc[selector] # determine alpha_star, where projected emissions become negative res = root_scalar( @@ -125,7 +128,7 @@ def at_alpha_star(df, alpha=alpha): ref = at_alpha_star(reference, alpha=alpha[: len(reference.columns)]) - if intensity_projection_linear is not None: + if not intensity_projection_linear.empty: offset = (ref * at_alpha_star(intensity_projection_linear)).sum() else: offset = 0 @@ -134,8 +137,7 @@ def at_alpha_star(df, alpha=alpha): # the transformed model vanish at alpha_star def sum_weight_at_alpha_star(gamma): x0, x1 = intensity.iloc[[0, -1]] - f = make_affine_transform(x0, x1, gamma, 1.0) - inv_f = make_affine_transform(gamma, 1.0, x0, x1) + f, inv_f = make_affine_transform_pair(x0, x1, gamma, 1.0) return ( ref * inv_f((f(x1) / f(intensity_hist)) ** alpha_star * f(intensity_hist)) @@ -215,7 +217,6 @@ def negative_exponential_intensity_model( gammas = np.empty(len(intensity)) for i, (index, intensity_traj) in enumerate(intensity.iterrows()): - index = dict(zip(intensity.index.names, index)) try: gammas[i] = determine_scaling_parameter( @@ -234,27 +235,39 @@ def negative_exponential_intensity_model( gammas = Series(gammas, intensity.index) - f = make_affine_transform(intensity.iloc[:, 0], intensity.iloc[:, -1], gammas, 1.0) - inv_f = make_affine_transform( - gammas, 1.0, intensity.iloc[:, 0], intensity.iloc[:, -1] + intensity_conv, intensity_hist_conv = intensity.loc[gammas.notna()].align( + intensity_hist, join="left", axis=0, copy=False ) + gammas_conv = semijoin(gammas, intensity_conv.index, how="right") - intensity, intensity_hist = intensity.align(intensity_hist, join="left", axis=0) + def ts(s): + return np.asarray(s)[:, np.newaxis] + f, inv_f = make_affine_transform_pair( + ts(intensity_conv.iloc[:, 0]), + ts(intensity_conv.iloc[:, -1]), + ts(gammas_conv), + 1.0, + ) intensity_projection = DataFrame( inv_f( - (f(intensity.values[:, -1]) / f(intensity_hist.values))[:, np.newaxis] - ** alpha.values - * f(intensity_hist.values)[:, np.newaxis] + ( + (f(ts(intensity_conv.values[:, -1])) / f(ts(intensity_hist_conv))) + ** alpha.values + ) + * f(ts(intensity_hist_conv)) ), - index=intensity_hist.index, + index=intensity_hist_conv.index, columns=intensity.columns, - ).where( - gammas.notna(), - intensity_growth_rate_model(intensity, intensity_hist), ) - return intensity_projection + return concat( + [ + intensity_projection, + intensity_growth_rate_model(intensity.loc[gammas.isna()], intensity_hist), + ], + sort=False, + ) def exponential_intensity_model( @@ -264,19 +277,19 @@ def exponential_intensity_model( if positive_intensity.all(): f = inv_f = lambda x: x else: - f = lambda x: np.where(positive_intensity, x, x + 1) - inv_f = lambda x: np.where(positive_intensity, x, x - 1) + f = lambda x: x.where(positive_intensity, x + 1) + inv_f = lambda x: x.where(positive_intensity, x - 1) intensity_hist = semijoin(intensity_hist, intensity.index, how="right") - intensity_projection = DataFrame( - inv_f( - (f(intensity.values[:, -1]) / f(intensity_hist.values))[:, np.newaxis] + intensity_projection = inv_f( + DataFrame( + (f(intensity.iloc[:, -1]) / f(intensity_hist)).values[:, np.newaxis] ** alpha.values - * f(intensity_hist.values)[:, np.newaxis] + * f(intensity_hist).values[:, np.newaxis], + index=intensity_hist.index, + columns=intensity.columns, ), - index=intensity_hist.index, - columns=intensity.columns, ) return intensity_projection @@ -285,9 +298,12 @@ def exponential_intensity_model( def linear_intensity_model( alpha: Series, intensity_hist: Series, intensity: DataFrame ) -> DataFrame: + intensity, intensity_hist = intensity.align( + intensity_hist, join="left", copy=False, axis=0 + ) intensity_projection = DataFrame( (1 - alpha).values * intensity_hist.values[:, np.newaxis] - + alpha.values * intensity.values[:, -1], + + alpha.values * intensity.values[:, -1:], index=intensity.index, columns=intensity.columns, ) @@ -298,6 +314,10 @@ def linear_intensity_model( def intensity_growth_rate_model( intensity: DataFrame, intensity_hist: Series ) -> DataFrame: + intensity, intensity_hist = intensity.align( + intensity_hist, join="left", axis=0, copy=False + ) + years_downscaling = intensity.columns intensity_projection = DataFrame( ( @@ -359,7 +379,9 @@ def intensity_convergence( if isinstance(hist, DataFrame): hist = hist.iloc[:, -1] - reference = semijoin(context.additional_data[proxy_name], context.regionmap_index) + reference = semijoin(context.additional_data[proxy_name], context.regionmap_index)[ + model.columns + ] reference_region = reference.groupby(context.region_level).sum() hist = semijoin(hist, context.regionmap_index) @@ -372,6 +394,14 @@ def intensity_convergence( intensity_countries, intensity_hist = intensity.align( intensity_hist, join="left", axis=0 ) + intensity_idx = intensity_countries.index + + levels = list(model.index.names) + [context.country_level] + empty_intensity = DataFrame( + [], + index=MultiIndex.from_arrays([[] for _ in levels], names=levels), + columns=intensity.columns, + ) # use a linear model for sub-regions with an intensity below the convergence intensity low_intensity = intensity_hist <= intensity_countries.iloc[:, -1] @@ -383,11 +413,11 @@ def intensity_convergence( intensity_countries.loc[low_intensity], ) logger.debug( - "Linear model was chosen for some trajectories: %s", - ", ".join(intensity_hist.index[low_intensity]), + "Linear model was chosen for some trajectories:\n%s", + intensity_hist.index[low_intensity].to_frame().to_string(index=False), ) else: - intensity_projection_linear = None + intensity_projection_linear = empty_intensity del intensity_countries negative_convergence = intensity.iloc[:, -1] < 0 @@ -399,16 +429,12 @@ def intensity_convergence( intensity_hist, intensity.loc[negative_convergence], reference, - None - if intensity_projection_linear is None - else semijoin( - intensity_projection_linear, negative_convergence_i, how="right" - ), - context + semijoin(intensity_projection_linear, negative_convergence_i, how="inner"), + context, ) else: - negative_intensity_projection = None + negative_intensity_projection = empty_intensity if not negative_convergence.all(): exponential_intensity_projection = exponential_intensity_model( @@ -417,21 +443,19 @@ def intensity_convergence( intensity.loc[~negative_convergence], ) else: - exponential_intensity_projection = None + exponential_intensity_projection = empty_intensity intensity_projection = concat( - filter( - None, - [ - exponential_intensity_projection, - negative_intensity_projection, - intensity_projection_linear, - ], - ), + [ + exponential_intensity_projection, + negative_intensity_projection, + intensity_projection_linear, + ], sort=False, - ).reindex(index=intensity.index) + ).reindex(index=intensity_idx) - intensity_projection = intensity_projection.loc[:, model.columns[-1]] + # if convergence year is past model horizon, intensity_projection is longer + intensity_projection = intensity_projection.loc[:, : model.columns[-1]] if model.columns[-1] > intensity_projection.columns[-1]: # Extend modelled intensity projection beyond year_convergence @@ -440,8 +464,8 @@ def intensity_convergence( ) weights = ( - (reference * intensity_projection) - .groupby(list(context.index) + [context.region_level]) + intensity_projection.idx.multiply(reference, join="left") + .groupby(model.index.names, dropna=False) .transform(normalize) ) - return model.multiply(weights, how="left") + return model.idx.multiply(weights, join="left").where(model != 0, 0) diff --git a/src/aneris/downscaling/methods.py b/src/aneris/downscaling/methods.py index 6349024..6d2e327 100644 --- a/src/aneris/downscaling/methods.py +++ b/src/aneris/downscaling/methods.py @@ -1,20 +1,17 @@ import logging -from collections.abc import Sequence -from dataclasses import dataclass, field -from typing import Optional, Union +from typing import Union -from pandas import DataFrame, MultiIndex, Series +from pandas import DataFrame, Series from pandas_indexing import semijoin from ..utils import normalize from .data import DownscalingContext -from .intensity_convergence import intensity_convergence +from .intensity_convergence import intensity_convergence # noqa: F401 logger = logging.getLogger(__name__) - def base_year_pattern( model: DataFrame, hist: Union[Series, DataFrame], context: DownscalingContext ) -> DataFrame: @@ -50,12 +47,12 @@ def base_year_pattern( hist = hist.iloc[:, -1] weights = ( - semijoin(hist, context.regionmap_index) - .groupby(list(context.index) + [context.region_level]) + semijoin(hist, context.regionmap_index, how="right") + .groupby(list(context.index) + [context.region_level], dropna=False) .transform(normalize) ) - return model.idx.multiply(weights, join="left") + return model.idx.multiply(weights, join="left").where(model != 0, 0) def growth_rate( @@ -98,14 +95,14 @@ def growth_rate( weights = ( cumulative_growth_rates.idx.multiply( - semijoin(hist, context.regionmap_index), + semijoin(hist, context.regionmap_index, how="right"), join="left", ) - .groupby(list(context.index) + [context.region_level]) + .groupby(model.index.names, dropna=False) .transform(normalize) ) - return model * weights + return model.idx.multiply(weights, join="left").where(model != 0, 0) def default_method_choice(traj, intensity_method, luc_method): From 4813d93637b9646cfff9f4a0e7e52b03f11e82d8 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Fri, 7 Apr 2023 23:49:17 +0200 Subject: [PATCH 18/77] Make linter happy --- .coveragerc | 2 +- .readthedocs.yml | 2 +- README.rst | 2 +- ci/.coveragerc | 2 +- ci/py2/Dockerfile | 2 +- ci/py3/Dockerfile | 2 +- ci/travis-install-miniconda.sh | 1 - doc/.gh-config | 2 +- doc/source/_bib/index.bib | 2 +- doc/source/_static/logo.svg | 608 +++++++++--------- doc/source/_themes/LICENSE | 4 +- doc/source/_themes/README.rst | 1 - doc/source/_themes/kr/static/flasky.css_t | 2 +- doc/source/_themes/kr/static/small_flask.css | 2 +- doc/source/_themes/kr/theme.conf | 2 +- .../_themes/kr_small/static/flasky.css_t | 44 +- doc/source/api.rst | 2 +- doc/source/config.rst | 1 - doc/source/contribute.rst | 2 +- doc/source/design.rst | 16 +- doc/source/index.rst | 4 +- doc/source/install.rst | 10 +- doc/source/theory.rst | 12 +- src/aneris/convenience.py | 2 +- src/aneris/downscaling/__init__.py | 2 +- src/aneris/downscaling/core.py | 13 +- src/aneris/downscaling/data.py | 3 +- .../downscaling/intensity_convergence.py | 15 +- src/aneris/downscaling/methods.py | 10 +- src/aneris/errors.py | 1 + src/aneris/utils.py | 5 +- tests/test_utils.py | 4 +- 32 files changed, 394 insertions(+), 388 deletions(-) diff --git a/.coveragerc b/.coveragerc index 74b2976..06eaf74 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,2 +1,2 @@ [run] -omit = aneris/tutorial.py \ No newline at end of file +omit = aneris/tutorial.py diff --git a/.readthedocs.yml b/.readthedocs.yml index 030f904..fd23194 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -13,4 +13,4 @@ python: install: - method: pip path: . - extra_requirements: [docs] \ No newline at end of file + extra_requirements: [docs] diff --git a/README.rst b/README.rst index a504870..bde470f 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,7 @@ **To reproduce harmonization routines from [Gidden et al. (2019)](https://gmd.copernicus.org/articles/12/1443/2019/), use `v0.3.2` (or -earlier). Subsequent versions introduce backwards incompatibilities.** +earlier). Subsequent versions introduce backwards incompatibilities.** Documentation ------------- diff --git a/ci/.coveragerc b/ci/.coveragerc index 4c1f347..42ced13 100644 --- a/ci/.coveragerc +++ b/ci/.coveragerc @@ -1,3 +1,3 @@ [report] omit = - aneris/_version.py \ No newline at end of file + aneris/_version.py diff --git a/ci/py2/Dockerfile b/ci/py2/Dockerfile index 550ab5d..bdb8e55 100644 --- a/ci/py2/Dockerfile +++ b/ci/py2/Dockerfile @@ -2,4 +2,4 @@ FROM gidden/python2-viz COPY . /aneris WORKDIR / -RUN cd /aneris && python2 setup.py install +RUN cd /aneris && python2 setup.py install diff --git a/ci/py3/Dockerfile b/ci/py3/Dockerfile index 8ac6ff3..4d651a2 100644 --- a/ci/py3/Dockerfile +++ b/ci/py3/Dockerfile @@ -2,4 +2,4 @@ FROM gidden/python3-viz COPY . /aneris WORKDIR / -RUN cd /aneris && python3 setup.py install +RUN cd /aneris && python3 setup.py install diff --git a/ci/travis-install-miniconda.sh b/ci/travis-install-miniconda.sh index 0c39107..d14e5f8 100644 --- a/ci/travis-install-miniconda.sh +++ b/ci/travis-install-miniconda.sh @@ -19,4 +19,3 @@ fi # update conda conda update --yes conda - diff --git a/doc/.gh-config b/doc/.gh-config index 88598c8..e31e921 100644 --- a/doc/.gh-config +++ b/doc/.gh-config @@ -4,4 +4,4 @@ include: - _static - _modules - _templates - - _downloads \ No newline at end of file + - _downloads diff --git a/doc/source/_bib/index.bib b/doc/source/_bib/index.bib index 8c27696..f1cfc4d 100644 --- a/doc/source/_bib/index.bib +++ b/doc/source/_bib/index.bib @@ -7,4 +7,4 @@ @article{Gidden:2019:aneris volume = {105}, journal = {Environmental Modelling & Software}, doi = {10.1016/j.envsoft.2018.04.002} -} \ No newline at end of file +} diff --git a/doc/source/_static/logo.svg b/doc/source/_static/logo.svg index 2f0501f..8773c55 100644 --- a/doc/source/_static/logo.svg +++ b/doc/source/_static/logo.svg @@ -10,330 +10,330 @@ - - - - - - - diff --git a/doc/source/_themes/LICENSE b/doc/source/_themes/LICENSE index 81f4d30..718c53a 100644 --- a/doc/source/_themes/LICENSE +++ b/doc/source/_themes/LICENSE @@ -1,9 +1,9 @@ -Modifications: +Modifications: Copyright (c) 2010 Kenneth Reitz. -Original Project: +Original Project: Copyright (c) 2010 by Armin Ronacher. diff --git a/doc/source/_themes/README.rst b/doc/source/_themes/README.rst index e8179f9..8d15beb 100644 --- a/doc/source/_themes/README.rst +++ b/doc/source/_themes/README.rst @@ -22,4 +22,3 @@ The following themes exist: **kr_small** small one-page theme. Intended to be used by very small addon libraries. - diff --git a/doc/source/_themes/kr/static/flasky.css_t b/doc/source/_themes/kr/static/flasky.css_t index 5774310..ac43777 100644 --- a/doc/source/_themes/kr/static/flasky.css_t +++ b/doc/source/_themes/kr/static/flasky.css_t @@ -442,4 +442,4 @@ a:hover tt { .revsys-inline { display: none!important; -} \ No newline at end of file +} diff --git a/doc/source/_themes/kr/static/small_flask.css b/doc/source/_themes/kr/static/small_flask.css index 8d55e95..a0af646 100644 --- a/doc/source/_themes/kr/static/small_flask.css +++ b/doc/source/_themes/kr/static/small_flask.css @@ -87,4 +87,4 @@ div.body { .github { display: none; -} \ No newline at end of file +} diff --git a/doc/source/_themes/kr/theme.conf b/doc/source/_themes/kr/theme.conf index 307a1f0..07698f6 100644 --- a/doc/source/_themes/kr/theme.conf +++ b/doc/source/_themes/kr/theme.conf @@ -4,4 +4,4 @@ stylesheet = flasky.css pygments_style = flask_theme_support.FlaskyStyle [options] -touch_icon = +touch_icon = diff --git a/doc/source/_themes/kr_small/static/flasky.css_t b/doc/source/_themes/kr_small/static/flasky.css_t index fe2141c..71961a2 100644 --- a/doc/source/_themes/kr_small/static/flasky.css_t +++ b/doc/source/_themes/kr_small/static/flasky.css_t @@ -8,11 +8,11 @@ * :license: BSD, see LICENSE for details. * */ - + @import url("basic.css"); - + /* -- page layout ----------------------------------------------------------- */ - + body { font-family: 'Georgia', serif; font-size: 17px; @@ -35,7 +35,7 @@ div.bodywrapper { hr { border: 1px solid #B1B4B6; } - + div.body { background-color: #ffffff; color: #3E4349; @@ -46,7 +46,7 @@ img.floatingflask { padding: 0 0 10px 10px; float: right; } - + div.footer { text-align: right; color: #888; @@ -55,12 +55,12 @@ div.footer { width: 650px; margin: 0 auto 40px auto; } - + div.footer a { color: #888; text-decoration: underline; } - + div.related { line-height: 32px; color: #888; @@ -69,18 +69,18 @@ div.related { div.related ul { padding: 0 0 0 10px; } - + div.related a { color: #444; } - + /* -- body styles ----------------------------------------------------------- */ - + a { color: #004B6B; text-decoration: underline; } - + a:hover { color: #6D4100; text-decoration: underline; @@ -89,7 +89,7 @@ a:hover { div.body { padding-bottom: 40px; /* saved for footer */ } - + div.body h1, div.body h2, div.body h3, @@ -109,24 +109,24 @@ div.indexwrapper h1 { height: {{ theme_index_logo_height }}; } {% endif %} - + div.body h2 { font-size: 180%; } div.body h3 { font-size: 150%; } div.body h4 { font-size: 130%; } div.body h5 { font-size: 100%; } div.body h6 { font-size: 100%; } - + a.headerlink { color: white; padding: 0 4px; text-decoration: none; } - + a.headerlink:hover { color: #444; background: #eaeaea; } - + div.body p, div.body dd, div.body li { line-height: 1.4em; } @@ -164,25 +164,25 @@ div.note { background-color: #eee; border: 1px solid #ccc; } - + div.seealso { background-color: #ffc; border: 1px solid #ff6; } - + div.topic { background-color: #eee; } - + div.warning { background-color: #ffe4e4; border: 1px solid #f66; } - + p.admonition-title { display: inline; } - + p.admonition-title:after { content: ":"; } @@ -254,7 +254,7 @@ dl { dl dd { margin-left: 30px; } - + pre { padding: 0; margin: 15px -30px; diff --git a/doc/source/api.rst b/doc/source/api.rst index 8cab06e..ed7dd9d 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -32,7 +32,7 @@ Methods: :code:`aneris.methods` .. automodule:: aneris.methods :members: - + Tools/Utilities: :code:`aneris.utils` ------------------------------------- diff --git a/doc/source/config.rst b/doc/source/config.rst index 9928d3c..6a4d597 100644 --- a/doc/source/config.rst +++ b/doc/source/config.rst @@ -10,4 +10,3 @@ shown below. .. program-output:: python -c 'import aneris; print(aneris.RC_DEFAULTS)' .. _yaml: http://www.yaml.org/ - diff --git a/doc/source/contribute.rst b/doc/source/contribute.rst index e441dda..a0580f9 100644 --- a/doc/source/contribute.rst +++ b/doc/source/contribute.rst @@ -9,4 +9,4 @@ You can add your own using the tutorial below. .. todo:: Write an example tutorial - maybe harmonization that returns straight - trajectories? \ No newline at end of file + trajectories? diff --git a/doc/source/design.rst b/doc/source/design.rst index 84e2ebe..04e3e25 100644 --- a/doc/source/design.rst +++ b/doc/source/design.rst @@ -31,7 +31,7 @@ The `Harmonization` module takes as input examples) (optional) It then harmonizes the IAM data to historical data based either on default logic -or via user-provided logic. +or via user-provided logic. It provides as output @@ -50,13 +50,13 @@ The module is described in more detail in the following sections .. todo:: - Add documentaion for logic + Add documentation for logic Downscaling ~~~~~~~~~~~ The `Downscaling` module implements different downscaling routines to enhance -the spatial resolution of data. It reqiures +the spatial resolution of data. It reqiures 1. IAM model data at a given region and variable (sector and gas by default) resolution - in a standard workflow, this would be the output of the @@ -75,11 +75,11 @@ the spatial resolution of data. It reqiures It provides as output 1. IAM data at a given variable (sector and gas by default) resolution and at - the *higher spatial resolution* of the historical data used + the *higher spatial resolution* of the historical data used .. todo:: - Add documentaion for logic + Add documentation for logic Gridding ~~~~~~~~ @@ -87,7 +87,7 @@ Gridding The `Gridding` module generates spatial grids of emissions data compliant with CMIP/ESGF dataformats -It takes as input +It takes as input 1. IAM data at the *country-level* defined by emissions species and sector - normally an output of the `Downscaling` module @@ -101,7 +101,7 @@ It provides as output .. todo:: - Add documentaion for installing pattern files + Add documentation for installing pattern files Climate ~~~~~~~ @@ -115,4 +115,4 @@ Workflow .. todo:: - Write documentation once we have some example workflows \ No newline at end of file + Write documentation once we have some example workflows diff --git a/doc/source/index.rst b/doc/source/index.rst index d533e3b..138d73e 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -1,5 +1,5 @@ -aneris: Harmonization for Integrated Assessment Models +aneris: Harmonization for Integrated Assessment Models ====================================================== Release v\ |version|. @@ -34,7 +34,7 @@ Release v\ |version|. .. |doi| image:: https://zenodo.org/badge/DOI/10.5281/zenodo.802832.svg :target: https://doi.org/10.5281/zenodo.802832 - + The open-source Python package |aneris| :cite:`Gidden:2019:aneris` is a library and Command Line Interface (CLI) for harmonization of IAM results with historical data sources. Currently, emissions trajectories are supported. diff --git a/doc/source/install.rst b/doc/source/install.rst index d3af7a8..b7ba60f 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -3,8 +3,8 @@ Install ******* -Via Conda (installs depedencies for you) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Via Conda (installs dependencies for you) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: bash @@ -24,9 +24,9 @@ From Source pip install git+https://github.com/iiasa/aneris.git -Depedencies -~~~~~~~~~~~ +Dependencies +~~~~~~~~~~~~ -The depedencies for :code:`aneris` are: +The dependencies for :code:`aneris` are: .. program-output:: python -c 'import sys, os; sys.path.append("../.."); import setup; print("\n".join([r for r in setup.REQUIREMENTS]))' diff --git a/doc/source/theory.rst b/doc/source/theory.rst index 42853ca..b94e9df 100644 --- a/doc/source/theory.rst +++ b/doc/source/theory.rst @@ -11,7 +11,7 @@ All harmonization is based on the following equations. :math:`\beta`: the harmonization convergence parameter .. math:: - + \begin{equation}\label{eqs:factor} \beta(t, t_i, t_f) = \begin{cases} @@ -31,7 +31,7 @@ All harmonization is based on the following equations. :math:`m^{off}`: offset-based harmoniation .. math:: - + \begin{equation}\label{eqs:offset} m^{off}(t, m, h, t_i, t_f) = \beta(t, t_i, t_f) (h(t_i) - m(t_i)) + m(t) \end{equation} @@ -39,7 +39,7 @@ All harmonization is based on the following equations. :math:`m^{int}`: linear-interoplation-based harmoniation .. math:: - + \begin{equation}\label{eqs:interpolate} m^{int}(t, m, h, t_i, t_f) = \begin{cases} @@ -54,7 +54,7 @@ selection. Available names are listed below: .. list-table:: All Harmonization Methods Provided in :code:`aneris` :header-rows: 1 - + * - Method Name - Harmonization Family - Convergence Year @@ -73,13 +73,13 @@ selection. Available names are listed below: * - :code:`linear_inerpolate_` - interpolation - :math:`t_f = \texttt{}` - + Default Decision Tree ~~~~~~~~~~~~~~~~~~~~~ While any method can be used to harmonize a given trajectory, intelligent -defaults are made available to the user. These default methods are deteremined +defaults are made available to the user. These default methods are determined by use of a *decision tree*, which analyzes the historical trajectory, model trajectory, and relative difference between trajectories in the harmonization year. The decision tree as implemented is provided below: diff --git a/src/aneris/convenience.py b/src/aneris/convenience.py index 5319c22..18fa604 100644 --- a/src/aneris/convenience.py +++ b/src/aneris/convenience.py @@ -1,7 +1,7 @@ import pandas as pd import pyam from openscm_units import unit_registry -from pandas_indexing import isin, semijoin, projectlevel +from pandas_indexing import isin, projectlevel, semijoin from .errors import ( AmbiguousHarmonisationMethod, diff --git a/src/aneris/downscaling/__init__.py b/src/aneris/downscaling/__init__.py index e6eb75e..1f262c3 100644 --- a/src/aneris/downscaling/__init__.py +++ b/src/aneris/downscaling/__init__.py @@ -1 +1 @@ -from aneris.downscaling.core import * +from aneris.downscaling.core import Downscaler # noqa: F401 diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index 09a13b4..7a86c76 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -95,7 +95,8 @@ def region_level(self): return self.context.region_level def check_proxies(self, methods: Series) -> None: - """Checks proxies required for chosen `methods` + """ + Checks proxies required for chosen `methods` Parameters ---------- @@ -129,7 +130,7 @@ def check_proxies(self, methods: Series) -> None: proxy = semijoin(proxy, self.context.regionmap_index, how="right") common_levels = [ - l for l in trajectory_index.names if l in proxy.index.names + lvl for lvl in trajectory_index.names if lvl in proxy.index.names ] missing_proxy = ( trajectory_index.idx.project(common_levels) @@ -138,8 +139,8 @@ def check_proxies(self, methods: Series) -> None: ) if not missing_proxy.empty: raise MissingProxyError( - f"The proxy data `{proxy_name}` is missing data for the following trajectories:\n" - + missing_proxy.to_frame().to_string(index=False) + f"The proxy data `{proxy_name}` is missing for the following " + "trajectories:\n" + missing_proxy.to_frame().to_string(index=False) ) if not isinstance(proxy, DataFrame): @@ -153,7 +154,9 @@ def check_proxies(self, methods: Series) -> None: ) def downscale(self, methods: Optional[Series] = None) -> DataFrame: - """Downscale aligned model data from historical data, and socio-economic scenario + """ + Downscale aligned model data from historical data, and socio-economic + scenario. Notes ----- diff --git a/src/aneris/downscaling/data.py b/src/aneris/downscaling/data.py index 403aeb1..5b7f8ae 100644 --- a/src/aneris/downscaling/data.py +++ b/src/aneris/downscaling/data.py @@ -7,7 +7,8 @@ @dataclass class DownscalingContext: - """Context in which downscaling needs to happen + """ + Context in which downscaling needs to happen. Attributes ---------- diff --git a/src/aneris/downscaling/intensity_convergence.py b/src/aneris/downscaling/intensity_convergence.py index a2ffc37..0bd5e00 100644 --- a/src/aneris/downscaling/intensity_convergence.py +++ b/src/aneris/downscaling/intensity_convergence.py @@ -19,7 +19,9 @@ class ConvergenceError(RuntimeError): def make_affine_transform(x1, x2, y1=0.0, y2=1.0): - """Returns an affine transform that maps `x1` to `y1` and `x2` to `y2`""" + """ + Returns an affine transform that maps `x1` to `y1` and `x2` to `y2` + """ def f(x): return (y2 - y1) * (x - x1) / (x2 - x1) + y1 @@ -69,7 +71,8 @@ def determine_scaling_parameter( index: dict[str, Any], context: DownscalingContext, ) -> float: - """Determine scaling parameter for negative exponential intensity model + """ + Determine scaling parameter for negative exponential intensity model. Gamma parameter for a single macro trajectory @@ -187,7 +190,8 @@ def negative_exponential_intensity_model( context: DownscalingContext, allow_fallback_to_linear: bool = True, ) -> DataFrame: - """Create a per-country time-series of intensities w/ negative intensities + """ + Create a per-country time-series of intensities w/ negative intensities. Parameters ---------- @@ -341,7 +345,8 @@ def intensity_convergence( convergence_year: Optional[int] = 2100, allow_fallback_to_linear: bool = True, ) -> DataFrame: - """Downscales emission data using emission intensity convergence + """ + Downscales emission data using emission intensity convergence. Parameters ---------- @@ -403,7 +408,7 @@ def intensity_convergence( columns=intensity.columns, ) - # use a linear model for sub-regions with an intensity below the convergence intensity + # use a linear model for countries with an intensity below the convergence intensity low_intensity = intensity_hist <= intensity_countries.iloc[:, -1] if low_intensity.any(): diff --git a/src/aneris/downscaling/methods.py b/src/aneris/downscaling/methods.py index 6d2e327..c3bcb21 100644 --- a/src/aneris/downscaling/methods.py +++ b/src/aneris/downscaling/methods.py @@ -15,7 +15,8 @@ def base_year_pattern( model: DataFrame, hist: Union[Series, DataFrame], context: DownscalingContext ) -> DataFrame: - """Downscales emission data using a base year pattern + """ + Downscales emission data using a base year pattern. Parameters ---------- @@ -60,7 +61,8 @@ def growth_rate( hist: Union[Series, DataFrame], context: DownscalingContext, ) -> DataFrame: - """Downscales emission data using growth rates + """ + Downscales emission data using growth rates. Assumes growth rates in all sub regions are the same as in the macro_region @@ -106,7 +108,9 @@ def growth_rate( def default_method_choice(traj, intensity_method, luc_method): - """Default downscaling decision tree""" + """ + Default downscaling decision tree. + """ # special cases if traj.h == 0: diff --git a/src/aneris/errors.py b/src/aneris/errors.py index 61b8df5..17ee77c 100644 --- a/src/aneris/errors.py +++ b/src/aneris/errors.py @@ -9,6 +9,7 @@ class MissingHistoricalError(ValueError): Error raised when historical data is missing. """ + class MissingProxyError(ValueError): """ Error raised when required proxy data is missing. diff --git a/src/aneris/utils.py b/src/aneris/utils.py index 23570e2..c852917 100644 --- a/src/aneris/utils.py +++ b/src/aneris/utils.py @@ -1,9 +1,6 @@ import logging import os -from functools import reduce -from operator import and_ -import numpy as np import pandas as pd @@ -107,4 +104,4 @@ def pd_write(df, f, *args, **kwargs): def normalize(s): - return s / s.sum() \ No newline at end of file + return s / s.sum() diff --git a/tests/test_utils.py b/tests/test_utils.py index fc6f68c..03492ad 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,6 +1,4 @@ import pandas as pd -import pandas.testing as pdt -import pytest import aneris.utils as utils @@ -22,4 +20,4 @@ def combine_rows_df(): "gas": ["BC"] * 5, } ).set_index(utils.df_idx) - return df \ No newline at end of file + return df From 588c6b5de712ff8012ad610e62814f74d88eeffa Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Thu, 25 May 2023 18:57:41 +0200 Subject: [PATCH 19/77] Fix tox typo --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index b2c720f..2c78957 100644 --- a/tox.ini +++ b/tox.ini @@ -53,7 +53,7 @@ deps = ruff skip_install = true commands = - black --check --diff {posags:src tests} + black --check --diff {posargs:src tests} ruff --diff {posargs:src tests doc} # asserts package build integrity From f05c1e182c4c86df574efaeb4826312656499ed1 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Thu, 25 May 2023 18:58:10 +0200 Subject: [PATCH 20/77] Add simple_proxy downscaling method --- src/aneris/downscaling/core.py | 3 ++ src/aneris/downscaling/methods.py | 46 +++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index 7a86c76..95ff213 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -12,6 +12,7 @@ default_method_choice, growth_rate, intensity_convergence, + simple_proxy, ) @@ -28,6 +29,8 @@ class Downscaler: ), "base_year_pattern": base_year_pattern, "growth_rate": growth_rate, + "proxy_gdp": partial(simple_proxy, proxy_name="gdp"), + "proxy_pop": partial(simple_proxy, proxy_name="gdp"), } def add_method(self, name, method): diff --git a/src/aneris/downscaling/methods.py b/src/aneris/downscaling/methods.py index c3bcb21..63483ab 100644 --- a/src/aneris/downscaling/methods.py +++ b/src/aneris/downscaling/methods.py @@ -56,6 +56,48 @@ def base_year_pattern( return model.idx.multiply(weights, join="left").where(model != 0, 0) +def simple_proxy( + model: DataFrame, + _hist: Union[Series, DataFrame], + context: DownscalingContext, + proxy_name: str, +) -> DataFrame: + """ + Downscales emission data using the shares in a proxy scenario + + Parameters + ---------- + model : DataFrame + model emissions for each world region and trajectory + _hist : DataFrame or Series + historic emissions for each country and trajectory. + Unused for this method. + context : DownscalingContext + settings for downscaling, like the regionmap + proxy_name : str + name of the additional data to be used as proxy + + Returns + ------- + DataFrame: + downscaled emissions for countries + + See also + -------- + DownscalingContext + """ + + proxy_data = context.additional_data[proxy_name] + common_levels = [lvl for lvl in context.index if lvl in proxy_data.index.names] + weights = ( + semijoin(proxy_data, context.regionmap_index)[model.columns] + .groupby(common_levels + [context.region_level], dropna=False) + .transform(normalize) + ) + + return model.idx.multiply(weights, join="left").where(model != 0, 0) + + def growth_rate( model: DataFrame, hist: Union[Series, DataFrame], @@ -114,9 +156,9 @@ def default_method_choice(traj, intensity_method, luc_method): # special cases if traj.h == 0: - return luc_method + return "proxy_gdp" if traj.zero_m: - return luc_method + return "proxy_gdp" if traj.get("sector", None) in ("Agriculture", "LULUCF"): return luc_method From e55f1d23bd6a3eb3e030e9ae2ff58ef671203d50 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Fri, 26 May 2023 22:57:57 +0200 Subject: [PATCH 21/77] Revise how arguments to default_methods are handled --- src/aneris/downscaling/core.py | 16 +++++++++++----- src/aneris/downscaling/methods.py | 11 ++++++++--- src/aneris/harmonize.py | 22 +++++++++++++--------- src/aneris/methods.py | 6 +++++- tests/test_default_decision_tree.py | 8 +++++++- 5 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index 95ff213..9b93113 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -74,8 +74,9 @@ def __init__( ) # TODO Make configurable by re-using config just as in harmonizer - self.intensity_method = "ipat_2100_gdp" - self.luc_method = "base_year_pattern" + self.fallback_method = None + self.intensity_method = None + self.luc_method = None @property def index(self): @@ -197,6 +198,13 @@ def methods(self, method_choice=None, overwrites=None): if method_choice is None: method_choice = default_method_choice + kwargs = { + "method_choice": method_choice, + "fallback_method": self.fallback_method, + "intensity_method": self.intensity_method, + "luc_method": self.luc_method, + } + hist_agg = ( semijoin(self.hist, self.context.regionmap_index, how="right") .groupby(list(self.index) + [self.region_level], dropna=False) @@ -208,9 +216,7 @@ def methods(self, method_choice=None, overwrites=None): ), self.model, self.year, - method_choice=method_choice, - intensity_method=self.intensity_method, - luc_method=self.luc_method, + **{k: v for k, v in kwargs.items() if v is not None}, ) if overwrites is None: diff --git a/src/aneris/downscaling/methods.py b/src/aneris/downscaling/methods.py index 63483ab..ff0e8de 100644 --- a/src/aneris/downscaling/methods.py +++ b/src/aneris/downscaling/methods.py @@ -149,16 +149,21 @@ def growth_rate( return model.idx.multiply(weights, join="left").where(model != 0, 0) -def default_method_choice(traj, intensity_method, luc_method): +def default_method_choice( + traj, + fallback_method="proxy_gdp", + intensity_method="ipat_2100_gdp", + luc_method="base_year_pattern", +): """ Default downscaling decision tree. """ # special cases if traj.h == 0: - return "proxy_gdp" + return fallback_method if traj.zero_m: - return "proxy_gdp" + return fallback_method if traj.get("sector", None) in ("Agriculture", "LULUCF"): return luc_method diff --git a/src/aneris/harmonize.py b/src/aneris/harmonize.py index bb102e0..6ca489b 100644 --- a/src/aneris/harmonize.py +++ b/src/aneris/harmonize.py @@ -164,10 +164,10 @@ def check_idx(df, label): self.method_choice = method_choice # set default methods to use in decision tree - self.ratio_method = config.get("default_ratio_method", "reduce_ratio_2080") - self.offset_method = config.get("default_offset_method", "reduce_offset_2080") - self.luc_method = config.get("default_luc_method", "reduce_offset_2150_cov") - self.luc_cov_threshold = config.get("luc_cov_threshold", 10) + self.ratio_method = config.get("default_ratio_method") + self.offset_method = config.get("default_offset_method") + self.luc_method = config.get("default_luc_method") + self.luc_cov_threshold = config.get("luc_cov_threshold") def metadata(self): """ @@ -208,17 +208,21 @@ def metadata(self): def _default_methods(self, year): assert year is not None + + kwargs = { + "method_choice": self.method_choice, + "ratio_method": self.ratio_method, + "offset_method": self.offset_method, + "luc_method": self.luc_method, + "luc_cov_threshold": self.luc_cov_threshold, + } methods, diagnostics = default_methods( self.history.droplevel( list(set(self.history.index.names) - set(self.harm_idx)) ), self.data.droplevel(list(set(self.data.index.names) - set(self.harm_idx))), year, - method_choice=self.method_choice, - ratio_method=self.ratio_method, - offset_method=self.offset_method, - luc_method=self.luc_method, - luc_cov_threshold=self.luc_cov_threshold, + **{k: v for k, v in kwargs.items() if v is not None}, ) return methods diff --git a/src/aneris/methods.py b/src/aneris/methods.py index 5113b3f..2bea29e 100644 --- a/src/aneris/methods.py +++ b/src/aneris/methods.py @@ -390,7 +390,11 @@ def coeff_of_var(s): def default_method_choice( - row, ratio_method, offset_method, luc_method, luc_cov_threshold + row, + ratio_method="reduce_ratio_2080", + offset_method="reduce_offset_2080", + luc_method="reduce_offset_2150_cov", + luc_cov_threshold=10, ): """ Default decision tree as documented at. diff --git a/tests/test_default_decision_tree.py b/tests/test_default_decision_tree.py index 64b5d7b..9946c4d 100644 --- a/tests/test_default_decision_tree.py +++ b/tests/test_default_decision_tree.py @@ -127,7 +127,13 @@ def test_branch6(index1): def test_custom_method_choice(index1, index1_co2): - def method_choice(row, ratio_method, offset_method, luc_method, luc_cov_threshold): + def method_choice( + row, + ratio_method="reduce_ratio_2080", + offset_method=None, + luc_method=None, + luc_cov_threshold=None, + ): return "budget" if row.gas == "CO2" else ratio_method # CH4 From 73b16598f73cb3ceb0c61cb9cc02a7d93923247e Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Sat, 27 May 2023 00:33:17 +0200 Subject: [PATCH 22/77] Fix ExcelWriter usage --- src/aneris/cmip6/cmip6_utils.py | 5 ++--- src/aneris/utils.py | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/aneris/cmip6/cmip6_utils.py b/src/aneris/cmip6/cmip6_utils.py index 39ef36d..2c3d8e1 100644 --- a/src/aneris/cmip6/cmip6_utils.py +++ b/src/aneris/cmip6/cmip6_utils.py @@ -160,9 +160,8 @@ def pd_write(df, f, *args, **kwargs): if f.endswith("csv"): df.to_csv(f, index=index, *args, **kwargs) else: - writer = pd.ExcelWriter(f) - df.to_excel(writer, index=index, *args, **kwargs) - writer.save() + with pd.ExcelWriter(f) as writer: + df.to_excel(writer, index=index, *args, **kwargs) def recalculated_row_idx(df, prefix="", suffix=""): diff --git a/src/aneris/utils.py b/src/aneris/utils.py index c852917..2e2b1f7 100644 --- a/src/aneris/utils.py +++ b/src/aneris/utils.py @@ -98,9 +98,8 @@ def pd_write(df, f, *args, **kwargs): if f.endswith("csv"): df.to_csv(f, index=index, *args, **kwargs) else: - writer = pd.ExcelWriter(f) - df.to_excel(writer, index=index, *args, **kwargs) - writer.save() + with pd.ExcelWriter(f) as writer: + df.to_excel(writer, index=index, *args, **kwargs) def normalize(s): From 22f9cebea6fea6a1c5375bf08c91b2027245b2f3 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Sat, 27 May 2023 01:21:04 +0200 Subject: [PATCH 23/77] Fix pandas-indexing imports --- src/aneris/downscaling/core.py | 1 + src/aneris/downscaling/intensity_convergence.py | 1 + src/aneris/downscaling/methods.py | 1 + 3 files changed, 3 insertions(+) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index 9b93113..4a91dc8 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -1,6 +1,7 @@ from functools import partial from typing import Optional, Sequence +import pandas_indexing.accessors # noqa: F401 from pandas import DataFrame, Series from pandas_indexing import concat, semijoin diff --git a/src/aneris/downscaling/intensity_convergence.py b/src/aneris/downscaling/intensity_convergence.py index 0bd5e00..e8c7e31 100644 --- a/src/aneris/downscaling/intensity_convergence.py +++ b/src/aneris/downscaling/intensity_convergence.py @@ -2,6 +2,7 @@ from typing import Any, Optional, Union import numpy as np +import pandas_indexing.accessors # noqa: F401 from pandas import DataFrame, MultiIndex, Series, concat from pandas_indexing import isin, semijoin from scipy.interpolate import interp1d diff --git a/src/aneris/downscaling/methods.py b/src/aneris/downscaling/methods.py index ff0e8de..e49b0f4 100644 --- a/src/aneris/downscaling/methods.py +++ b/src/aneris/downscaling/methods.py @@ -1,6 +1,7 @@ import logging from typing import Union +import pandas_indexing.accessors # noqa: F401 from pandas import DataFrame, Series from pandas_indexing import semijoin From 23c007309f60b0be8f70dc77dc385e35d37f0d6f Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Wed, 31 May 2023 20:40:18 +0200 Subject: [PATCH 24/77] grid: Generalize check_coord_overlap --- src/aneris/grid.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index c379607..af25365 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -7,7 +7,13 @@ from aneris.errors import MissingColumns, MissingCoordinateValue, MissingDimension -def check_coord_overlap(x, y, coord, x_strict=False, y_strict=False, warn=False): +def country_name(country: str): + return pycountry.countries.get(alpha_3=country).name + + +def check_coord_overlap( + x, y, coord, x_strict=False, y_strict=False, warn=False, labels=None +): """ Checks whether the coordinates or columns between two xarray.DataArrays. @@ -22,24 +28,27 @@ def check_coord_overlap(x, y, coord, x_strict=False, y_strict=False, warn=False) the check fails if the coordinates in `x` are not a subset of `y` warn : bool, optional if the check fails, issue a warning rather than a `MissingCoordinateValue` error + labels : callable or dict + what to report for missing coordinates Raises ------ `MissingCoordinateValue` if check fails """ - # TODO: add docs and try to generalize iso coord logic + if labels is None: + labels = lambda x: x + if isinstance(labels, dict): + label_dict = labels + labels = lambda x: label_dict.get(x, x) + x, y = set(np.unique(x[coord])), set(np.unique(y[coord])) msg = "" if x_strict and x - y: missing = x - y - if coord == "iso": - missing = [pycountry.countries.get(alpha_3=c).name for c in missing] - msg += f"Missing from x {coord}: {missing}\n" + msg += f"Missing from x {coord}: {', '.join(str(labels(x)) for x in missing)}\n" if y_strict and y - x: missing = y - x - if coord == "iso": - missing = [pycountry.countries.get(alpha_3=c).name for c in missing] - msg += f"Missing from y {coord}: {missing}\n" + msg += f"Missing from y {coord}: {', '.join(str(labels(x)) for x in missing)}\n" if msg and not warn: raise MissingCoordinateValue(msg) elif msg and warn: From 9aff824a34d0fa9412f5da19e0c4c28c9fec4dca Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Wed, 31 May 2023 21:47:32 +0200 Subject: [PATCH 25/77] Add Gridder --- src/aneris/errors.py | 4 +- src/aneris/grid.py | 385 +++++++++++++++++++++++++++++-------------- src/aneris/utils.py | 6 + 3 files changed, 266 insertions(+), 129 deletions(-) diff --git a/src/aneris/errors.py b/src/aneris/errors.py index df76c44..60d47e6 100644 --- a/src/aneris/errors.py +++ b/src/aneris/errors.py @@ -28,9 +28,9 @@ class MissingHarmonisationYear(ValueError): """ -class MissingColumns(ValueError): +class MissingLevels(ValueError): """ - Error raised when a column of dataframe is expected but missing. + Error raised when an index level is expected but missing. """ diff --git a/src/aneris/grid.py b/src/aneris/grid.py index af25365..7723350 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -1,131 +1,262 @@ -import numpy as np +from contextlib import contextmanager +from itertools import repeat +from pathlib import Path +from typing import Optional, Sequence, Union + +import dask +import pandas as pd +import pandas_indexing.accessors # noqa: F401 import ptolemy as pt -import pycountry import xarray as xr +from dask.diagnostics.progress import ProgressBar +from pandas import DataFrame, MultiIndex, Series +from pandas_indexing import isin, semijoin +from xarray import DataArray + +from .errors import MissingCoordinateValue, MissingDimension, MissingLevels +from .utils import country_name, logger + + +DEFAULT_INDEX = ("sector", "gas", "year") + + +class Gridder: + def __init__( + self, + data: DataFrame, + idxraster: DataArray, + proxy_cfg: DataFrame, + index: Sequence[str] = DEFAULT_INDEX, + index_mappings: Optional[dict[str, dict[str, str]]] = None, + country_level: str = "country", + output_dir: Optional[Union[Path, str]] = None, + ): + """Prepare gridding data + + Parameters + ---------- + data : DataFrame or Series + Tabular data (should contain `country_level` and `index` levels) + If a DataFrame is given, it expects 'year's on the columns. + idxraster : DataArray + Rasterized country map (should sum to 1 over `country_level`) + proxy_cfg : DataFrame + Configuration of proxies with the columns: + "name", "path", "template", "as_flux", "separate_shares" + index : Sequence[str], optional + level names on which to align between tabular data and proxies, by default + DEFAULT_INDEX + index_mappings : Optional[dict[str, dict[str, str]]], optional + Mapping from proxy index coordinate to data values, by default None + country_level : str, optional + level or dimension name for countries, by default "country" + output_dir : str or Path, optional + directory in which to create gridded proxies + if omitted or None, files are created in the current working directory + """ + if isinstance(data, DataFrame): + data = data.rename_axis(columns="year").stack() + self.data = data + + self.idxraster = idxraster + + if isinstance(proxy_cfg, (list, tuple)): + proxy_cfg = DataFrame(dict(path=Series(proxy_cfg).map(Path))) + if isinstance(proxy_cfg, DataFrame): + proxy_cfg = proxy_cfg.copy(deep=False) + if "name" not in proxy_cfg.columns: + proxy_cfg["name"] = proxy_cfg["path"].map(lambda p: p.stem) + if "template" not in proxy_cfg.columns: + proxy_cfg["template"] = ( + "{gas}-em-" + proxy_cfg["name"] + "-{model}-{scenario}" + ) + if "as_flux" not in proxy_cfg.columns: + proxy_cfg["as_flux"] = True + if "separate_shares" not in proxy_cfg.columns: + proxy_cfg["separate_shares"] = False + self.proxy_cfg = proxy_cfg + + self.index = list(index) + self.index_mappings = index_mappings if index_mappings is not None else dict() + self.country_level = country_level + + self.output_dir = Path.cwd() if output_dir is None else Path(output_dir) + + def check(self) -> None: + """Check levels and dimensions of gridding data + + Raises + ------ + MissingLevels + If `data` is missing levels + MissingDimension + If `idxraster` or a proxy is missing dimensions + MissingCoordinateValue + If tabular and spatial data is misaligned + """ + # Check data + missing_levels = {self.country_level, *self.index}.difference( + self.data.index.names + ) + if missing_levels: + raise MissingLevels( + "Tabular `data` must have `country_level` and `index` levels, " + "but is missing: " + ", ".join(missing_levels) + ) + + # Check idxraster + idxr_missing_dims = {self.country_level, "lat", "lon"}.difference( + self.idxraster.dims + ) + if idxr_missing_dims: + raise MissingDimension( + "idx_raster missing dimensions: " + ", ".join(idxr_missing_dims) + ) + + # Check data and idxraster alignment + countries_data = set(self.data.idx.unique(self.country_level)) + countries_idx = set(self.idxraster.indexes[self.country_level]) + missing_from_idxraster = countries_data - countries_idx + if missing_from_idxraster: + raise MissingCoordinateValue( + f"`idxraster` missing countries ('{self.country_level}'): " + + ", ".join(country_name(x) for x in missing_from_idxraster) + ) + missing_from_data = countries_idx - countries_data + if missing_from_data: + logger().warning( + f"Tabular `data` missing countries ('{self.country_level}'): " + + ", ".join(country_name(x) for x in missing_from_data) + ) + + # Check proxies and alignment with data + data_index = self.data.idx.unique(self.index) + + def get_index(dim): + idx = proxy.indexes[dim] + mapping = self.index_mappings.get(dim) + if mapping is not None: + idx = idx.map(mapping) + return idx + + proxy_index = [] + for proxy_cfg in self.proxy_cfg.itertuples(): + with xr.open_dataset(proxy_cfg.path) as proxy: + proxy_missing_dims = {"lat", "lon", *self.index}.difference(proxy.dims) + if proxy_missing_dims: + raise MissingDimension( + f"Proxy {proxy_cfg.name} missing dimensions: " + + ", ".join(proxy_missing_dims) + ) + + index = MultiIndex.from_product([get_index(dim) for dim in self.index]) + missing_from_data = index.difference(data_index) + if not missing_from_data.empty: + raise MissingCoordinateValue( + f"Proxy '{proxy_cfg.name}' has values missing from `data`:\n" + + missing_from_data.to_frame().to_string(index=False) + ) + + proxy_index.append(index) + + proxy_index = pd.concat(proxy_index) + missing_from_proxy = data_index.difference(proxy_index) + if not missing_from_proxy.empty: + raise MissingCoordinateValue( + "None of the configured proxies provides:\n" + + missing_from_proxy.to_frame().to_string(index=False) + ) + + @contextmanager + def open_and_normalize_proxy(self, proxy_cfg): + with xr.open_dataarray( + proxy_cfg.path, chunks=dict(zip(self.index, repeat(1))) + ) as proxy: + for idx in self.index: + mapping = self.index_mappings.get(idx) + if mapping is not None: + proxy[idx] = proxy.indexes[idx].map(mapping) + + separate = self.idxraster * proxy + normalized = separate / separate.sum(["lat", "lon"]) + + if proxy_cfg.as_flux: + lat_areas_in_m2 = xr.DataArray.from_series( + pt.cell_area_from_file(proxy) + ) + normalized = normalized / lat_areas_in_m2 + + yield normalized + + def grid(self, skip_check: bool = False) -> None: + """ + Grid data onto configured proxies + + Parameters + ---------- + skip_check : bool, default False + If set, skips structural and alignment checks + """ + + if not skip_check: + self.check() + + iter_levels = self.data.index.names.difference( + self.index + [self.country_level] + ) + + for proxy_cfg in self.proxy_cfg.itertuples(): + logger().info("Collecting tasks for proxy %s", proxy_cfg.name) + + with self.open_and_normalize_proxy(proxy_cfg) as proxy: + write_tasks = [] + + proxy_index = MultiIndex.from_product( + [proxy.indexes[dim] for dim in self.index] + ) + tabular = semijoin(self.data, proxy_index, how="right") + + for iter_vals in tabular.idx.unique(iter_levels): + iter_ids = dict(zip(iter_levels, iter_vals)) + logger().info("Adding tasks for %s", iter_ids) + data = DataArray.from_series( + tabular.loc[isin(**iter_ids)].droplevel(iter_levels) + ) + gridded = (data * proxy).sum(self.country_level) + + write_tasks.append( + self.write_output(proxy_cfg, gridded, data.indexes, iter_ids) + ) + + with ProgressBar(): + dask.compute(write_tasks) + + def write_output(self, proxy_cfg, gridded: DataArray, indexes, iter_ids): + # TODO: need to add attr definitions and dimension bounds + ids = {dim: index[0] for dim, index in indexes.items() if len(index) == 1} + path = ( + self.output_dir + / proxy_cfg.template.format(name=proxy_cfg.name, **ids, **iter_ids) + ).with_suffix(".nc") + logger().info(f"Writing to {path}") + if not proxy_cfg.separate_shares: + return gridded.to_dataset(name=proxy_cfg.name).to_netcdf( + path, compute=False + ) + + if isinstance(proxy_cfg.separate_shares, str): + shares_stem = proxy_cfg.separate_shares.format(name=proxy_cfg.name, **ids) + else: + shares_stem = proxy_cfg.template.format( + name=f"{proxy_cfg.name}-shares", **ids + ) + shares_path = (self.output_dir / shares_stem).with_suffix(".nc") -from aneris import utils -from aneris.errors import MissingColumns, MissingCoordinateValue, MissingDimension - - -def country_name(country: str): - return pycountry.countries.get(alpha_3=country).name - - -def check_coord_overlap( - x, y, coord, x_strict=False, y_strict=False, warn=False, labels=None -): - """ - Checks whether the coordinates or columns between two xarray.DataArrays. - - Parameters - ---------- - x : xarray.DataArray - y : xarray.DataArray - coord : str - x_strict : bool, optional - the check fails if the coordinates in `y` are not a subset of `x` - y_strict : bool, optional - the check fails if the coordinates in `x` are not a subset of `y` - warn : bool, optional - if the check fails, issue a warning rather than a `MissingCoordinateValue` error - labels : callable or dict - what to report for missing coordinates - - Raises - ------ - `MissingCoordinateValue` if check fails - """ - if labels is None: - labels = lambda x: x - if isinstance(labels, dict): - label_dict = labels - labels = lambda x: label_dict.get(x, x) - - x, y = set(np.unique(x[coord])), set(np.unique(y[coord])) - msg = "" - if x_strict and x - y: - missing = x - y - msg += f"Missing from x {coord}: {', '.join(str(labels(x)) for x in missing)}\n" - if y_strict and y - x: - missing = y - x - msg += f"Missing from y {coord}: {', '.join(str(labels(x)) for x in missing)}\n" - if msg and not warn: - raise MissingCoordinateValue(msg) - elif msg and warn: - utils.logger().warning(msg) - - -def grid( - df, - proxy, - idx_raster, - value_col="value", - shape_col="iso", - extra_coords=["year", "gas", "sector"], - as_flux=False, -): - """ - Develops spatial grids for emissions data. - - Parameters - ---------- - df : pandas.DataFrame - downscaled emissions provided per country (iso) - proxy : xarray.DataArray - proxy data used to apply emissions to spatial grids - idx_raster : xarray.DataArray - a raster mapping data in `df` to spatial grids - value_col : str, optional - the column in `df` which is gridded - shape_col : str, optional - the column in `df` which aligns with `idx_raster` - extra_coords : Collection of str, optional - the additional columns in `df` which will become coordinates - in the returned DataArray - as_flux : bool, optional - if True, divide the result by the latitude-resolved cell areas - to estimate parameter as a flux rather than bulk magnitude - - Returns - ------- - xarray.DataArray: - gridded emissions from `df` - - Notes - ----- - 1. `df` must have columns including `extra_coords`, `value_col`, and `shape_col` - 2. `proxy` must have coodrinates including `extra_coords`, "lat", and "lon" - 3. `idx_rater` must have coodrinates including `shape_col`, "lat", and "lon" - """ - df_dim_diff = set(extra_coords + [value_col, shape_col]).difference(set(df.columns)) - if df_dim_diff: - raise MissingColumns(f"df missing columns: {df_dim_diff}") - proxy_dim_diff = set(extra_coords + ["lat", "lon"]).difference(set(proxy.dims)) - if proxy_dim_diff: - raise MissingDimension(f"proxy missing dimensions: {proxy_dim_diff}") - idxr_dim_diff = set([shape_col] + ["lat", "lon"]).difference(set(idx_raster.dims)) - if idxr_dim_diff: - raise MissingDimension(f"idx_raster missing dimensions: {idxr_dim_diff}") - - map_data = pt.df_to_weighted_raster( - df, - xr.where(idx_raster > 0, 1, np.nan), - col=value_col, - extra_coords=extra_coords, - ) - weighted_proxy = idx_raster * proxy - normalized_proxy = weighted_proxy / weighted_proxy.sum(dim=["lat", "lon"]) - - for coord in extra_coords: - check_coord_overlap( - normalized_proxy, map_data, coord, x_strict=True, y_strict=True + shares_dims = [dim for dim in self.index if dim not in ids] + total = gridded.sum(shares_dims) + shares = gridded / total + return total.to_dataset(name=proxy_cfg.name).to_netcdf( + path, compute=False + ), shares.to_dataset(name=f"{proxy_cfg.name}-shares").to_netcdf( + shares_path, compute=False ) - check_coord_overlap(normalized_proxy, map_data, shape_col, y_strict=True) - # warn here because sometimes we have more small countries than data - check_coord_overlap(normalized_proxy, map_data, shape_col, x_strict=True, warn=True) - - result = (map_data * normalized_proxy).sum(dim=shape_col)[value_col] - if as_flux: - lat_areas_in_m2 = xr.DataArray.from_series(pt.cell_area_from_file(proxy)) - result = result / lat_areas_in_m2 - return result diff --git a/src/aneris/utils.py b/src/aneris/utils.py index 2e2b1f7..3a3fd93 100644 --- a/src/aneris/utils.py +++ b/src/aneris/utils.py @@ -2,6 +2,7 @@ import os import pandas as pd +import pycountry _logger = None @@ -104,3 +105,8 @@ def pd_write(df, f, *args, **kwargs): def normalize(s): return s / s.sum() + + +def country_name(iso: str): + country_obj = pycountry.countries.get(alpha_3=iso) + return iso if country_obj is None else country_obj.name From 6567c37966d218d4de42e6359b1134365ec92af8 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Wed, 19 Jul 2023 21:16:11 +0200 Subject: [PATCH 26/77] Assume years as integers --- src/aneris/downscaling/core.py | 9 +++++--- src/aneris/harmonize.py | 41 +++++++++++++++++----------------- src/aneris/methods.py | 22 +++++++++--------- 3 files changed, 37 insertions(+), 35 deletions(-) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index 4a91dc8..a35b576 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -44,6 +44,7 @@ def __init__( year: int, region_mapping: Series, index: Sequence[str] = DEFAULT_INDEX, + method_choice: Optional[callable] = None, return_type=DataFrame, **additional_data: DataFrame, ): @@ -71,13 +72,14 @@ def __init__( if not missing_hist.empty: raise MissingHistoricalError( "History missing for variables/countries:\n" - + missing_hist.to_frame().to_string(index=False) + + missing_hist.to_frame().to_string(index=False, max_rows=100) ) # TODO Make configurable by re-using config just as in harmonizer self.fallback_method = None self.intensity_method = None self.luc_method = None + self.method_choice = None @property def index(self): @@ -145,7 +147,8 @@ def check_proxies(self, methods: Series) -> None: if not missing_proxy.empty: raise MissingProxyError( f"The proxy data `{proxy_name}` is missing for the following " - "trajectories:\n" + missing_proxy.to_frame().to_string(index=False) + "trajectories:\n" + + missing_proxy.to_frame().to_string(index=False, max_rows=100) ) if not isinstance(proxy, DataFrame): @@ -193,7 +196,7 @@ def downscale(self, methods: Optional[Series] = None) -> DataFrame: return self.return_type(concat(downscaled)) def methods(self, method_choice=None, overwrites=None): - if method_choice is not None: + if method_choice is None: method_choice = self.method_choice if method_choice is None: diff --git a/src/aneris/harmonize.py b/src/aneris/harmonize.py index 6ca489b..649c997 100644 --- a/src/aneris/harmonize.py +++ b/src/aneris/harmonize.py @@ -2,7 +2,7 @@ from itertools import chain import pandas as pd -from pandas_indexing import projectlevel, semijoin +from pandas_indexing import projectlevel, semijoin, uniquelevel from aneris import utils from aneris.errors import ( @@ -38,25 +38,21 @@ def _check_data(hist, scen, year, idx): if "unit" not in idx: idx += ["unit"] - # @coroa - this may be a very slow way to do this check.. - def downselect(df): - return df[year].reset_index().set_index(idx).index.unique() - - s = downselect(scen) - h = downselect(hist) + s = uniquelevel(scen, idx) + h = uniquelevel(hist, idx) if h.empty: raise MissingHarmonisationYear("No historical data in harmonization year") if not s.difference(h).empty: raise MissingHistoricalError( "Historical data does not match scenario data in harmonization " - f"year for\n {s.difference(h)}" + f"year for\n {s.difference(h).to_frame().to_string(index=False, max_rows=100)}" ) if not h.difference(s).empty: raise MissingScenarioError( "Scenario data does not match historical data in harmonization " - f"year for\n {h.difference(s)}" + f"year for\n {h.difference(s).to_frame().to_string(index=False, max_rows=100)}" ) @@ -169,10 +165,12 @@ def check_idx(df, label): self.luc_method = config.get("default_luc_method") self.luc_cov_threshold = config.get("luc_cov_threshold") - def metadata(self): + def metadata(self, year=None): """ Return pd.DataFrame of method choice metadata. """ + base_year = year if year is not None else self.base_year or 2015 + methods = self.methods_used if isinstance(methods, pd.Series): # only defaults used methods = methods.to_frame() @@ -186,10 +184,10 @@ def metadata(self): methods["override"], self.offsets, self.ratios, - self.history[self.base_year], + self.history[base_year], self.history.apply(coeff_of_var, axis=1), - self.data[self.base_year], - self.model[self.base_year], + self.data[base_year], + self.model[base_year], ], axis=1, ) @@ -246,11 +244,12 @@ def _harmonize(self, method, idx, check_len, base_year): # harmonize model = Harmonizer._methods[method](model, delta, harmonize_year=base_year) - y = str(base_year) if model.isnull().values.any(): msg = "{} method produced NaNs: {}, {}" where = model.isnull().any(axis=1) - raise ValueError(msg.format(method, model.loc[where, y], delta.loc[where])) + raise ValueError( + msg.format(method, model.loc[where, base_year], delta.loc[where]) + ) # construct the full df of history and future return model @@ -263,7 +262,7 @@ def methods(self, year=None, overrides=None): pd.DataFrame of overrides. """ # get method listing - base_year = year if year is not None else self.base_year or "2015" + base_year = year if year is not None else self.base_year or 2015 _check_overrides(overrides, self.data.index) methods = self._default_methods(year=base_year) @@ -293,12 +292,9 @@ def harmonize(self, year=None, overrides=None): Return pd.DataFrame of harmonized trajectories given pd.DataFrame overrides. """ - base_year = year if year is not None else self.base_year or "2015" + base_year = year if year is not None else self.base_year or 2015 _check_data(self.history, self.data, base_year, self.harm_idx) - self.model = pd.Series( - index=self.data.index, name=base_year, dtype=float - ).to_frame() self.offsets, self.ratios = harmonize_factors( self.data, self.history, base_year ) @@ -310,10 +306,13 @@ def harmonize(self, year=None, overrides=None): if isinstance(methods, pd.DataFrame): methods = methods["method"] # drop default and override info if (methods == "unicorn").any(): + self.model = pd.Series( + index=self.data.index, name=base_year, dtype=float + ).to_frame() msg = """Values found where model has positive and negative values and is zero in base year. Unsure how to proceed:\n{}\n{}""" cols = ["history", "unharmonized"] - df1 = self.metadata().loc[methods == "unicorn", cols] + df1 = self.metadata(year=base_year).loc[methods == "unicorn", cols] df2 = self.data.loc[methods == "unicorn"] raise ValueError(msg.format(df1.reset_index(), df2.reset_index())) diff --git a/src/aneris/methods.py b/src/aneris/methods.py index 2bea29e..c5f55e1 100644 --- a/src/aneris/methods.py +++ b/src/aneris/methods.py @@ -12,7 +12,7 @@ from aneris import utils -def harmonize_factors(df, hist, harmonize_year="2015"): +def harmonize_factors(df, hist, harmonize_year=2015): """ Calculate offset and ratio values between data and history. @@ -40,7 +40,7 @@ def harmonize_factors(df, hist, harmonize_year="2015"): return offset, ratios -def constant_offset(df, offset, harmonize_year="2015"): +def constant_offset(df, offset, harmonize_year=2015): """ Calculate constant offset harmonized trajectory. @@ -65,7 +65,7 @@ def constant_offset(df, offset, harmonize_year="2015"): return df -def constant_ratio(df, ratios, harmonize_year="2015"): +def constant_ratio(df, ratios, harmonize_year=2015): """ Calculate constant ratio harmonized trajectory. @@ -90,7 +90,7 @@ def constant_ratio(df, ratios, harmonize_year="2015"): return df -def linear_interpolate(df, offset, final_year="2050", harmonize_year="2015"): +def linear_interpolate(df, offset, final_year=2050, harmonize_year=2015): """ Calculate linearly interpolated convergence harmonized trajectory. @@ -122,7 +122,7 @@ def linear_interpolate(df, offset, final_year="2050", harmonize_year="2015"): return df -def reduce_offset(df, offset, final_year="2050", harmonize_year="2015"): +def reduce_offset(df, offset, final_year=2050, harmonize_year=2015): """ Calculate offset convergence harmonized trajectory. @@ -157,7 +157,7 @@ def reduce_offset(df, offset, final_year="2050", harmonize_year="2015"): return df -def reduce_ratio(df, ratios, final_year="2050", harmonize_year="2015"): +def reduce_ratio(df, ratios, final_year=2050, harmonize_year=2015): """ Calculate ratio convergence harmonized trajectory. @@ -197,7 +197,7 @@ def reduce_ratio(df, ratios, final_year="2050", harmonize_year="2015"): return df -def budget(df, df_hist, harmonize_year="2015"): +def budget(df, df_hist, harmonize_year=2015): r""" Calculate budget harmonized trajectory. @@ -253,8 +253,8 @@ def budget(df, df_hist, harmonize_year="2015"): harmonize_year = int(harmonize_year) - df = df.set_axis(df.columns.astype(int), axis="columns") - df_hist = df_hist.set_axis(df_hist.columns.astype(int), axis="columns") + # df = df.set_axis(df.columns.astype(int), axis="columns") + # df_hist = df_hist.set_axis(df_hist.columns.astype(int), axis="columns") data_years = df.columns hist_years = df_hist.columns @@ -344,13 +344,13 @@ def l2_norm(): df_harm = pd.DataFrame( harmonized, index=df.index, - columns=years.astype(str), + columns=years, ) return df_harm -def model_zero(df, offset, harmonize_year="2015"): +def model_zero(df, offset, harmonize_year=2015): """ Returns result of aneris.methods.constant_offset() """ From 2d6581cdc15baa3e872375f530d6f1ddc33e9f9b Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Wed, 19 Jul 2023 21:17:26 +0200 Subject: [PATCH 27/77] fix(intensity_convergence): Avoid creating duplicates --- src/aneris/downscaling/intensity_convergence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aneris/downscaling/intensity_convergence.py b/src/aneris/downscaling/intensity_convergence.py index e8c7e31..9d41612 100644 --- a/src/aneris/downscaling/intensity_convergence.py +++ b/src/aneris/downscaling/intensity_convergence.py @@ -432,7 +432,7 @@ def intensity_convergence( # sum does not work here. We need the individual per-country dimension negative_intensity_projection = negative_exponential_intensity_model( alpha, - intensity_hist, + intensity_hist.loc[~low_intensity], intensity.loc[negative_convergence], reference, semijoin(intensity_projection_linear, negative_convergence_i, how="inner"), From 90d7526f7475af65bab29d1ae0f5a87ca0f798ac Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Thu, 10 Aug 2023 17:41:33 +0200 Subject: [PATCH 28/77] Add semijoin call into where to help pandas --- src/aneris/downscaling/core.py | 8 ++++---- src/aneris/downscaling/intensity_convergence.py | 3 ++- src/aneris/downscaling/methods.py | 16 +++++++++++----- src/aneris/harmonize.py | 10 +++++----- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index a35b576..b28a33d 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -66,8 +66,8 @@ def __init__( missing_hist = ( model.index.join(self.context.regionmap_index, how="left") - .idx.project(list(index) + [self.country_level]) - .difference(hist.index.idx.project(list(index) + [self.country_level])) + .pix.project(list(index) + [self.country_level]) + .difference(hist.index.pix.project(list(index) + [self.country_level])) ) if not missing_hist.empty: raise MissingHistoricalError( @@ -140,8 +140,8 @@ def check_proxies(self, methods: Series) -> None: lvl for lvl in trajectory_index.names if lvl in proxy.index.names ] missing_proxy = ( - trajectory_index.idx.project(common_levels) - .difference(proxy.index.idx.project(common_levels)) + trajectory_index.pix.project(common_levels) + .difference(proxy.index.pix.project(common_levels)) .unique() ) if not missing_proxy.empty: diff --git a/src/aneris/downscaling/intensity_convergence.py b/src/aneris/downscaling/intensity_convergence.py index 9d41612..4bf0ef7 100644 --- a/src/aneris/downscaling/intensity_convergence.py +++ b/src/aneris/downscaling/intensity_convergence.py @@ -474,4 +474,5 @@ def intensity_convergence( .groupby(model.index.names, dropna=False) .transform(normalize) ) - return model.idx.multiply(weights, join="left").where(model != 0, 0) + res = model.pix.multiply(weights, join="left") + return res.where(semijoin(model != 0, res.index, how="right"), 0) diff --git a/src/aneris/downscaling/methods.py b/src/aneris/downscaling/methods.py index e49b0f4..045d36a 100644 --- a/src/aneris/downscaling/methods.py +++ b/src/aneris/downscaling/methods.py @@ -54,7 +54,9 @@ def base_year_pattern( .transform(normalize) ) - return model.idx.multiply(weights, join="left").where(model != 0, 0) + # the semijoin in where should not be necessary, but pandas fails without it + res = model.pix.multiply(weights, join="left") + return res.where(semijoin(model != 0, res.index, how="right"), 0) def simple_proxy( @@ -89,14 +91,16 @@ def simple_proxy( """ proxy_data = context.additional_data[proxy_name] - common_levels = [lvl for lvl in context.index if lvl in proxy_data.index.names] + common_levels = [lvl for lvl in model.index.names if lvl in proxy_data.index.names] weights = ( semijoin(proxy_data, context.regionmap_index)[model.columns] .groupby(common_levels + [context.region_level], dropna=False) .transform(normalize) ) - return model.idx.multiply(weights, join="left").where(model != 0, 0) + # the semijoin in where should not be necessary, but pandas fails without it + res = model.pix.multiply(weights, join="left") + return res.where(semijoin(model != 0, res.index, how="right"), 0) def growth_rate( @@ -139,7 +143,7 @@ def growth_rate( ) weights = ( - cumulative_growth_rates.idx.multiply( + cumulative_growth_rates.pix.multiply( semijoin(hist, context.regionmap_index, how="right"), join="left", ) @@ -147,7 +151,9 @@ def growth_rate( .transform(normalize) ) - return model.idx.multiply(weights, join="left").where(model != 0, 0) + # the semijoin in where should not be necessary, but pandas fails without it + res = model.pix.multiply(weights, join="left") + return res.where(semijoin(model != 0, res.index, how="right"), 0) def default_method_choice( diff --git a/src/aneris/harmonize.py b/src/aneris/harmonize.py index 649c997..04cc203 100644 --- a/src/aneris/harmonize.py +++ b/src/aneris/harmonize.py @@ -235,16 +235,16 @@ def _harmonize(self, method, idx, check_len, base_year): delta = hist if method == "budget" else ratios if "ratio" in method else offsets # checks - assert not model.isnull().values.any() - assert not hist.isnull().values.any() - assert not delta.isnull().values.any() + assert not model.isnull().any(axis=None) + assert not hist.isnull().any(axis=None) + assert not delta.isnull().any(axis=None) if check_len: assert (len(model) < len(self.data)) & (len(hist) < len(self.history)) # harmonize model = Harmonizer._methods[method](model, delta, harmonize_year=base_year) - if model.isnull().values.any(): + if model.isnull().any(axis=None): msg = "{} method produced NaNs: {}, {}" where = model.isnull().any(axis=1) raise ValueError( @@ -318,11 +318,11 @@ def harmonize(self, year=None, overrides=None): dfs = [] y = base_year + check_len = len(methods.unique()) > 1 for method in methods.unique(): _log(f"Harmonizing with {method}") # get subset indicies idx = methods[methods == method].index - check_len = len(methods.unique()) > 1 # harmonize df = self._harmonize(method, idx, check_len, base_year=base_year) if method not in ["model_zero", "hist_zero"]: From f79fcee0c881f1b4cb8a71b562a2a397e76f0c30 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Wed, 16 Aug 2023 14:54:42 +0200 Subject: [PATCH 29/77] fix(downscaling): Cope with zero model emissions in intensity convergence --- src/aneris/downscaling/intensity_convergence.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/aneris/downscaling/intensity_convergence.py b/src/aneris/downscaling/intensity_convergence.py index 4bf0ef7..fd9a51c 100644 --- a/src/aneris/downscaling/intensity_convergence.py +++ b/src/aneris/downscaling/intensity_convergence.py @@ -316,6 +316,7 @@ def linear_intensity_model( return intensity_projection +@np.errstate(invalid="ignore") def intensity_growth_rate_model( intensity: DataFrame, intensity_hist: Series ) -> DataFrame: @@ -334,7 +335,7 @@ def intensity_growth_rate_model( * intensity_hist.values[:, np.newaxis], index=intensity_hist.index, columns=years_downscaling.rename("year"), - ) + ).where(intensity_hist != 0, 0.) return intensity_projection From f0c27728045b95ddfdb1fac79dc3639e36bc3baf Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Fri, 11 Aug 2023 14:14:56 +0200 Subject: [PATCH 30/77] add global trajectories to gridding, allow missing data that is in proxies, and fix concat of multiindex --- src/aneris/grid.py | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 7723350..f7af2ce 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -1,10 +1,11 @@ +import warnings from contextlib import contextmanager +from functools import reduce from itertools import repeat from pathlib import Path from typing import Optional, Sequence, Union import dask -import pandas as pd import pandas_indexing.accessors # noqa: F401 import ptolemy as pt import xarray as xr @@ -31,7 +32,8 @@ def __init__( country_level: str = "country", output_dir: Optional[Union[Path, str]] = None, ): - """Prepare gridding data + """ + Prepare gridding data. Parameters ---------- @@ -82,8 +84,21 @@ def __init__( self.output_dir = Path.cwd() if output_dir is None else Path(output_dir) - def check(self) -> None: - """Check levels and dimensions of gridding data + def check( + self, strict_proxy_data: bool = False, global_label: str = "World" + ) -> None: + """ + Check levels and dimensions of gridding data. + + Parameters + ---------- + strict_proxy_data : bool, default True + If true, proxy data must align with tabular data. If false, proxy + data can have additional data than is provided in tabular data + (e.g., additional years) + global_label : str, default "World" + The regional label applied to global data which should not be + checked against country proxy data Raises ------ @@ -114,7 +129,9 @@ def check(self) -> None: ) # Check data and idxraster alignment - countries_data = set(self.data.idx.unique(self.country_level)) + countries_data = set(self.data.idx.unique(self.country_level)) - set( + [global_label] + ) countries_idx = set(self.idxraster.indexes[self.country_level]) missing_from_idxraster = countries_data - countries_idx if missing_from_idxraster: @@ -152,14 +169,21 @@ def get_index(dim): index = MultiIndex.from_product([get_index(dim) for dim in self.index]) missing_from_data = index.difference(data_index) if not missing_from_data.empty: - raise MissingCoordinateValue( + msg = ( f"Proxy '{proxy_cfg.name}' has values missing from `data`:\n" + missing_from_data.to_frame().to_string(index=False) ) + if strict_proxy_data: + raise MissingCoordinateValue(msg) + else: + warnings.warn(msg) proxy_index.append(index) - proxy_index = pd.concat(proxy_index) + def concat(objs): + return reduce(lambda x, y: x.append(y), objs) + + proxy_index = concat(proxy_index) missing_from_proxy = data_index.difference(proxy_index) if not missing_from_proxy.empty: raise MissingCoordinateValue( @@ -190,7 +214,7 @@ def open_and_normalize_proxy(self, proxy_cfg): def grid(self, skip_check: bool = False) -> None: """ - Grid data onto configured proxies + Grid data onto configured proxies. Parameters ---------- From 487e41b745323f09e283a0b869891cf0585ae7e3 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Fri, 11 Aug 2023 17:38:18 +0200 Subject: [PATCH 31/77] dropnas in tabular when proxy has more dims than data, add compression --- src/aneris/grid.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index f7af2ce..c7ef9fb 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -238,7 +238,9 @@ def grid(self, skip_check: bool = False) -> None: proxy_index = MultiIndex.from_product( [proxy.indexes[dim] for dim in self.index] ) - tabular = semijoin(self.data, proxy_index, how="right") + # dropna is required when data is allowed to have less dimension + # values than proxy (e.g., fewer years) + tabular = semijoin(self.data, proxy_index, how="right").dropna() for iter_vals in tabular.idx.unique(iter_levels): iter_ids = dict(zip(iter_levels, iter_vals)) @@ -255,17 +257,28 @@ def grid(self, skip_check: bool = False) -> None: with ProgressBar(): dask.compute(write_tasks) - def write_output(self, proxy_cfg, gridded: DataArray, indexes, iter_ids): + def write_output( + self, + proxy_cfg, + gridded: DataArray, + indexes, + iter_ids, + comp=dict(zlib=True, complevel=5), + ): # TODO: need to add attr definitions and dimension bounds + self.output_dir.mkdir(parents=True, exist_ok=True) ids = {dim: index[0] for dim, index in indexes.items() if len(index) == 1} - path = ( - self.output_dir - / proxy_cfg.template.format(name=proxy_cfg.name, **ids, **iter_ids) - ).with_suffix(".nc") + fname = ( + proxy_cfg.template.format(name=proxy_cfg.name, **ids, **iter_ids).replace( + " ", "__" + ) + + ".nc" + ) + path = self.output_dir / fname logger().info(f"Writing to {path}") if not proxy_cfg.separate_shares: return gridded.to_dataset(name=proxy_cfg.name).to_netcdf( - path, compute=False + path, compute=False, encoding={proxy_cfg.name: comp} ) if isinstance(proxy_cfg.separate_shares, str): @@ -280,7 +293,7 @@ def write_output(self, proxy_cfg, gridded: DataArray, indexes, iter_ids): total = gridded.sum(shares_dims) shares = gridded / total return total.to_dataset(name=proxy_cfg.name).to_netcdf( - path, compute=False + path, compute=False, encoding={proxy_cfg.name: comp} ), shares.to_dataset(name=f"{proxy_cfg.name}-shares").to_netcdf( - shares_path, compute=False + shares_path, compute=False, encoding={proxy_cfg.name: comp} ) From 50ef375b54ebfa729fa3b1a44271baf1adc6acd6 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Sat, 12 Aug 2023 09:17:42 +0200 Subject: [PATCH 32/77] add chunking option for proxy dimensions and provide explicit iter_levels --- src/aneris/grid.py | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index c7ef9fb..f2131cf 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -192,9 +192,9 @@ def concat(objs): ) @contextmanager - def open_and_normalize_proxy(self, proxy_cfg): + def open_and_normalize_proxy(self, proxy_cfg, chunk_proxy_dims): with xr.open_dataarray( - proxy_cfg.path, chunks=dict(zip(self.index, repeat(1))) + proxy_cfg.path, chunks=dict(zip(self.index + chunk_proxy_dims, repeat(1))) ) as proxy: for idx in self.index: mapping = self.index_mappings.get(idx) @@ -212,7 +212,16 @@ def open_and_normalize_proxy(self, proxy_cfg): yield normalized - def grid(self, skip_check: bool = False) -> None: + # TODO: iter_levels was added because some trajectories can have different + # downscaling methods applied? E.g., for burning emissions, proxy_gdp and + # ipat are both used, causing the gridding process to be called twice in + # `for iter_vals in tabular.idx.unique(iter_levels)` + def grid( + self, + skip_check: bool = False, + chunk_proxy_dims: Sequence[str] = [], + iter_levels: Sequence[str] = [], + ) -> None: """ Grid data onto configured proxies. @@ -220,19 +229,24 @@ def grid(self, skip_check: bool = False) -> None: ---------- skip_check : bool, default False If set, skips structural and alignment checks + chunk_proxy_dims : Sequence[str], default [] + Additional dimensions to chunk when opening proxy files + iter_levels : Sequence[str], default [] + Explicit levels over which to iterate (e.g., model and scenario) """ if not skip_check: self.check() - iter_levels = self.data.index.names.difference( + iter_levels = iter_levels or self.data.index.names.difference( self.index + [self.country_level] ) + print(iter_levels) for proxy_cfg in self.proxy_cfg.itertuples(): logger().info("Collecting tasks for proxy %s", proxy_cfg.name) - with self.open_and_normalize_proxy(proxy_cfg) as proxy: + with self.open_and_normalize_proxy(proxy_cfg, chunk_proxy_dims) as proxy: write_tasks = [] proxy_index = MultiIndex.from_product( @@ -281,13 +295,14 @@ def write_output( path, compute=False, encoding={proxy_cfg.name: comp} ) - if isinstance(proxy_cfg.separate_shares, str): - shares_stem = proxy_cfg.separate_shares.format(name=proxy_cfg.name, **ids) - else: - shares_stem = proxy_cfg.template.format( - name=f"{proxy_cfg.name}-shares", **ids - ) - shares_path = (self.output_dir / shares_stem).with_suffix(".nc") + shares_fname = ( + proxy_cfg.template.format( + name=f"{proxy_cfg.name}-shares", **ids, **iter_ids + ).replace(" ", "__") + + ".nc" + ) + shares_path = self.output_dir / shares_fname + logger().info(f"Writing to {shares_path}") shares_dims = [dim for dim in self.index if dim not in ids] total = gridded.sum(shares_dims) @@ -295,5 +310,5 @@ def write_output( return total.to_dataset(name=proxy_cfg.name).to_netcdf( path, compute=False, encoding={proxy_cfg.name: comp} ), shares.to_dataset(name=f"{proxy_cfg.name}-shares").to_netcdf( - shares_path, compute=False, encoding={proxy_cfg.name: comp} + shares_path, compute=False, encoding={f"{proxy_cfg.name}-shares": comp} ) From d2c563239f3e11a0638c03aacb000b68a43612ff Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Sat, 12 Aug 2023 09:18:38 +0200 Subject: [PATCH 33/77] rm print --- src/aneris/grid.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index f2131cf..d296254 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -241,7 +241,6 @@ def grid( iter_levels = iter_levels or self.data.index.names.difference( self.index + [self.country_level] ) - print(iter_levels) for proxy_cfg in self.proxy_cfg.itertuples(): logger().info("Collecting tasks for proxy %s", proxy_cfg.name) From 3b78655a7d383ae20865b73d86fec3e91d607d59 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Mon, 14 Aug 2023 12:32:17 +0200 Subject: [PATCH 34/77] add global_only cfg column for global sectors --- src/aneris/grid.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index d296254..2e24087 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -44,7 +44,7 @@ def __init__( Rasterized country map (should sum to 1 over `country_level`) proxy_cfg : DataFrame Configuration of proxies with the columns: - "name", "path", "template", "as_flux", "separate_shares" + "name", "path", "template", "as_flux", "global_only", "separate_shares" index : Sequence[str], optional level names on which to align between tabular data and proxies, by default DEFAULT_INDEX @@ -74,6 +74,8 @@ def __init__( ) if "as_flux" not in proxy_cfg.columns: proxy_cfg["as_flux"] = True + if "global_only" not in proxy_cfg.columns: + proxy_cfg["global_only"] = False if "separate_shares" not in proxy_cfg.columns: proxy_cfg["separate_shares"] = False self.proxy_cfg = proxy_cfg @@ -201,7 +203,7 @@ def open_and_normalize_proxy(self, proxy_cfg, chunk_proxy_dims): if mapping is not None: proxy[idx] = proxy.indexes[idx].map(mapping) - separate = self.idxraster * proxy + separate = proxy if proxy_cfg.global_only else self.idxraster * proxy normalized = separate / separate.sum(["lat", "lon"]) if proxy_cfg.as_flux: From 884693f27361bdf6570332d8a3ea215a02e885c1 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Mon, 14 Aug 2023 12:41:28 +0200 Subject: [PATCH 35/77] add comment about chunk_proxy_dims --- src/aneris/grid.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 2e24087..98cd6f2 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -218,6 +218,9 @@ def open_and_normalize_proxy(self, proxy_cfg, chunk_proxy_dims): # downscaling methods applied? E.g., for burning emissions, proxy_gdp and # ipat are both used, causing the gridding process to be called twice in # `for iter_vals in tabular.idx.unique(iter_levels)` + # + # TODO: chunk_proxy_dims can in principle be moved into Gridder.proxy_cfg, + # but requires supporting lists, so need to decide how to deal with that def grid( self, skip_check: bool = False, From 088d3ce6dadb65ba0ae5d74b7a853d01ee75ad1f Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Wed, 16 Aug 2023 15:35:22 +0200 Subject: [PATCH 36/77] allow for inspection of datasets to be generated with write arg, provide share dims as arg --- src/aneris/grid.py | 58 +++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 98cd6f2..052f3c2 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -203,7 +203,8 @@ def open_and_normalize_proxy(self, proxy_cfg, chunk_proxy_dims): if mapping is not None: proxy[idx] = proxy.indexes[idx].map(mapping) - separate = proxy if proxy_cfg.global_only else self.idxraster * proxy + # separate = proxy if proxy_cfg.global_only else self.idxraster * proxy # TODO: this maybe isn't needed anymore with 'World' included in idxraster + separate = self.idxraster * proxy normalized = separate / separate.sum(["lat", "lon"]) if proxy_cfg.as_flux: @@ -226,6 +227,8 @@ def grid( skip_check: bool = False, chunk_proxy_dims: Sequence[str] = [], iter_levels: Sequence[str] = [], + write: bool = True, # TODO: make docs + share_dims: Sequence[str] = ["sector"], # TODO: make docs ) -> None: """ Grid data onto configured proxies. @@ -247,6 +250,7 @@ def grid( self.index + [self.country_level] ) + ret = [] for proxy_cfg in self.proxy_cfg.itertuples(): logger().info("Collecting tasks for proxy %s", proxy_cfg.name) @@ -258,7 +262,7 @@ def grid( ) # dropna is required when data is allowed to have less dimension # values than proxy (e.g., fewer years) - tabular = semijoin(self.data, proxy_index, how="right").dropna() + tabular = semijoin(self.data, proxy_index, how="inner") for iter_vals in tabular.idx.unique(iter_levels): iter_ids = dict(zip(iter_levels, iter_vals)) @@ -269,18 +273,32 @@ def grid( gridded = (data * proxy).sum(self.country_level) write_tasks.append( - self.write_output(proxy_cfg, gridded, data.indexes, iter_ids) + self.compute_output( + proxy_cfg, + gridded, + data.indexes, + iter_ids, + write=write, + share_dims=share_dims, + ) ) - with ProgressBar(): - dask.compute(write_tasks) + if write: + with ProgressBar(): + dask.compute(write_tasks) + else: + ret.append(write_tasks) - def write_output( + return ret + + def compute_output( self, proxy_cfg, gridded: DataArray, indexes, iter_ids, + write=True, + share_dims=["sector"], comp=dict(zlib=True, complevel=5), ): # TODO: need to add attr definitions and dimension bounds @@ -295,9 +313,13 @@ def write_output( path = self.output_dir / fname logger().info(f"Writing to {path}") if not proxy_cfg.separate_shares: - return gridded.to_dataset(name=proxy_cfg.name).to_netcdf( - path, compute=False, encoding={proxy_cfg.name: comp} - ) + gridded = gridded.to_dataset(name=proxy_cfg.name) + if write: + return gridded.to_netcdf( + path, compute=False, encoding={proxy_cfg.name: comp} + ) + else: + return gridded shares_fname = ( proxy_cfg.template.format( @@ -308,11 +330,15 @@ def write_output( shares_path = self.output_dir / shares_fname logger().info(f"Writing to {shares_path}") - shares_dims = [dim for dim in self.index if dim not in ids] - total = gridded.sum(shares_dims) + total = gridded.sum(share_dims) shares = gridded / total - return total.to_dataset(name=proxy_cfg.name).to_netcdf( - path, compute=False, encoding={proxy_cfg.name: comp} - ), shares.to_dataset(name=f"{proxy_cfg.name}-shares").to_netcdf( - shares_path, compute=False, encoding={f"{proxy_cfg.name}-shares": comp} - ) + total = total.to_dataset(name=proxy_cfg.name) + shares = shares.to_dataset(name=f"{proxy_cfg.name}-shares") + if write: + return total.to_netcdf( + path, compute=False, encoding={proxy_cfg.name: comp} + ), shares.to_netcdf( + shares_path, compute=False, encoding={f"{proxy_cfg.name}-shares": comp} + ) + else: + return total, shares From b992c356ab8d047aa40309cf4c09878eebd984fb Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Wed, 16 Aug 2023 17:40:33 +0200 Subject: [PATCH 37/77] add a verification function to confirm global yearly sums --- src/aneris/grid.py | 56 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 052f3c2..235c301 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -81,6 +81,8 @@ def __init__( self.proxy_cfg = proxy_cfg self.index = list(index) + self.spatial_dims = ["lat", "lon", "level"] + self.mean_time_dims = ["month"] self.index_mappings = index_mappings if index_mappings is not None else dict() self.country_level = country_level @@ -203,9 +205,16 @@ def open_and_normalize_proxy(self, proxy_cfg, chunk_proxy_dims): if mapping is not None: proxy[idx] = proxy.indexes[idx].map(mapping) - # separate = proxy if proxy_cfg.global_only else self.idxraster * proxy # TODO: this maybe isn't needed anymore with 'World' included in idxraster + # TODO: this maybe isn't needed anymore with 'World' included in idxraster + # separate = proxy if proxy_cfg.global_only else self.idxraster * proxy separate = self.idxraster * proxy - normalized = separate / separate.sum(["lat", "lon"]) + # NB: this only preserves seasonality if years and months are + # separate dimensions in the proxy raster. If instead they are + # combined into a single 'time' dimension, seasonality is lost. + sum_spatial_dims = list(set(separate.dims).intersection(self.spatial_dims)) + normalized = separate / separate.mean(self.mean_time_dims).sum( + sum_spatial_dims + ) if proxy_cfg.as_flux: lat_areas_in_m2 = xr.DataArray.from_series( @@ -229,6 +238,7 @@ def grid( iter_levels: Sequence[str] = [], write: bool = True, # TODO: make docs share_dims: Sequence[str] = ["sector"], # TODO: make docs + verify_output: bool = False, # TODO: make docs ) -> None: """ Grid data onto configured proxies. @@ -249,7 +259,6 @@ def grid( iter_levels = iter_levels or self.data.index.names.difference( self.index + [self.country_level] ) - ret = [] for proxy_cfg in self.proxy_cfg.itertuples(): logger().info("Collecting tasks for proxy %s", proxy_cfg.name) @@ -272,6 +281,9 @@ def grid( ) gridded = (data * proxy).sum(self.country_level) + if verify_output: + write_tasks.append(self.verify_output(tabular, gridded)) + write_tasks.append( self.compute_output( proxy_cfg, @@ -291,6 +303,44 @@ def grid( return ret + def verify_output( + self, + tabular, + gridded, + ): + # TODO: this is complex and can be given to us by the user? + # the point of this function is to compute global totals across + # self.index (nominally sector, gas, year), and compare with + # the same values summed up in the original tabular data provided + # to confirm that gridded values comport with provided global totals + sum_spatial_dims = list(set(gridded.dims).intersection(self.spatial_dims)) + droplevel = list( + set(gridded.dims).difference( + set(self.index + self.spatial_dims + self.mean_time_dims) + ) + ) + grid_df = ( + (xr.DataArray(pt.cell_area_from_file(gridded)) * gridded) + .mean(dim=self.mean_time_dims) + .sum(dim=sum_spatial_dims) + .to_dataframe(name="emissions") + .unstack("year") + .droplevel(droplevel)["emissions"] + ) + tab_df = ( + semijoin(tabular, grid_df.index, how="inner") + .groupby(level=grid_df.index.names) + .sum()[grid_df.columns] + ) + rel_diff = (grid_df - tab_df).abs() / tab_df + lim = 1e-4 + if not (rel_diff < lim).all().all(): + logger().warning( + f"Yearly global totals not within {lim} relative values:\n" + f"{rel_diff}" + ) + return rel_diff + def compute_output( self, proxy_cfg, From cbd94c8fc2601a642f0bd7eca5dd00b53c7e8eee Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Thu, 17 Aug 2023 13:49:59 +0200 Subject: [PATCH 38/77] revert global_only changes, to be checked --- src/aneris/grid.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 235c301..79d3c35 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -206,8 +206,10 @@ def open_and_normalize_proxy(self, proxy_cfg, chunk_proxy_dims): proxy[idx] = proxy.indexes[idx].map(mapping) # TODO: this maybe isn't needed anymore with 'World' included in idxraster - # separate = proxy if proxy_cfg.global_only else self.idxraster * proxy - separate = self.idxraster * proxy + # but need to confirm 'World' is also in the proxy rasters + separate = proxy if proxy_cfg.global_only else self.idxraster * proxy + # separate = self.idxraster * proxy + # NB: this only preserves seasonality if years and months are # separate dimensions in the proxy raster. If instead they are # combined into a single 'time' dimension, seasonality is lost. @@ -308,6 +310,10 @@ def verify_output( tabular, gridded, ): + # TODO: figure out correct message here + # ids = {dim: index[0] for dim, index in indexes.items() if len(index) == 1} + # logger().info(f"Veryifying output for {ids}") + # TODO: this is complex and can be given to us by the user? # the point of this function is to compute global totals across # self.index (nominally sector, gas, year), and compare with From 8c265c7bb9df2463c46feb8450b171e36ca166b3 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Thu, 17 Aug 2023 13:50:40 +0200 Subject: [PATCH 39/77] change chunk_proxy_dims to a map instead of a list --- src/aneris/grid.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 79d3c35..244d343 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -3,7 +3,7 @@ from functools import reduce from itertools import repeat from pathlib import Path -from typing import Optional, Sequence, Union +from typing import Mapping, Optional, Sequence, Union import dask import pandas_indexing.accessors # noqa: F401 @@ -196,9 +196,10 @@ def concat(objs): ) @contextmanager - def open_and_normalize_proxy(self, proxy_cfg, chunk_proxy_dims): + def open_and_normalize_proxy(self, proxy_cfg, chunk_proxy_dims={}): with xr.open_dataarray( - proxy_cfg.path, chunks=dict(zip(self.index + chunk_proxy_dims, repeat(1))) + proxy_cfg.path, + chunks=dict(**zip(self.index, repeat(1)), **chunk_proxy_dims), ) as proxy: for idx in self.index: mapping = self.index_mappings.get(idx) @@ -236,7 +237,7 @@ def open_and_normalize_proxy(self, proxy_cfg, chunk_proxy_dims): def grid( self, skip_check: bool = False, - chunk_proxy_dims: Sequence[str] = [], + chunk_proxy_dims: Mapping[str, int] = {}, iter_levels: Sequence[str] = [], write: bool = True, # TODO: make docs share_dims: Sequence[str] = ["sector"], # TODO: make docs From 7b223db7bf1c45e08a086d965ec76462d47f4b22 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Thu, 17 Aug 2023 13:58:04 +0200 Subject: [PATCH 40/77] bugfix chunks --- src/aneris/grid.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 244d343..cfa9f70 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -199,7 +199,10 @@ def concat(objs): def open_and_normalize_proxy(self, proxy_cfg, chunk_proxy_dims={}): with xr.open_dataarray( proxy_cfg.path, - chunks=dict(**zip(self.index, repeat(1)), **chunk_proxy_dims), + chunks=dict( + **dict(zip(self.index, repeat(1))), + **chunk_proxy_dims + ), ) as proxy: for idx in self.index: mapping = self.index_mappings.get(idx) @@ -255,7 +258,6 @@ def grid( iter_levels : Sequence[str], default [] Explicit levels over which to iterate (e.g., model and scenario) """ - if not skip_check: self.check() From 04a33a37e9e2fe022992f37b36d37f5e9cbd9bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20H=C3=B6rsch?= Date: Thu, 17 Aug 2023 17:20:15 +0200 Subject: [PATCH 41/77] Convert output verification into a dask task (#63) --- src/aneris/grid.py | 62 +++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index cfa9f70..9b51042 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -21,6 +21,24 @@ DEFAULT_INDEX = ("sector", "gas", "year") +@dask.delayed +def verify_global_values(aggregated, tabular, proxy_name, index, reltol=1e-4): + grid_df = aggregated.to_series().pix.project(index).unstack("year") + tab_df = ( + semijoin(tabular, grid_df.index, how="inner")[grid_df.columns] + .groupby(grid_df.index.names) + .sum() + ) + + reldiff = abs(grid_df - tab_df) / tab_df + if (reldiff >= reltol).any(axis=None): + logger().warning( + f"Yearly global totals ({proxy_name}) not within {reltol} relative values:\n" + f"{reldiff}" + ) + return reldiff + + class Gridder: def __init__( self, @@ -199,10 +217,7 @@ def concat(objs): def open_and_normalize_proxy(self, proxy_cfg, chunk_proxy_dims={}): with xr.open_dataarray( proxy_cfg.path, - chunks=dict( - **dict(zip(self.index, repeat(1))), - **chunk_proxy_dims - ), + chunks=dict(zip(self.index, repeat(1))) | chunk_proxy_dims, ) as proxy: for idx in self.index: mapping = self.index_mappings.get(idx) @@ -287,7 +302,9 @@ def grid( gridded = (data * proxy).sum(self.country_level) if verify_output: - write_tasks.append(self.verify_output(tabular, gridded)) + write_tasks.append( + self.verify_output(proxy_cfg, tabular, gridded) + ) write_tasks.append( self.compute_output( @@ -310,6 +327,7 @@ def grid( def verify_output( self, + proxy_cfg, tabular, gridded, ): @@ -323,32 +341,14 @@ def verify_output( # the same values summed up in the original tabular data provided # to confirm that gridded values comport with provided global totals sum_spatial_dims = list(set(gridded.dims).intersection(self.spatial_dims)) - droplevel = list( - set(gridded.dims).difference( - set(self.index + self.spatial_dims + self.mean_time_dims) - ) - ) - grid_df = ( - (xr.DataArray(pt.cell_area_from_file(gridded)) * gridded) - .mean(dim=self.mean_time_dims) - .sum(dim=sum_spatial_dims) - .to_dataframe(name="emissions") - .unstack("year") - .droplevel(droplevel)["emissions"] - ) - tab_df = ( - semijoin(tabular, grid_df.index, how="inner") - .groupby(level=grid_df.index.names) - .sum()[grid_df.columns] - ) - rel_diff = (grid_df - tab_df).abs() / tab_df - lim = 1e-4 - if not (rel_diff < lim).all().all(): - logger().warning( - f"Yearly global totals not within {lim} relative values:\n" - f"{rel_diff}" - ) - return rel_diff + + if proxy_cfg.as_flux: + lat_areas_in_m2 = xr.DataArray.from_series(pt.cell_area_from_file(gridded)) + gridded = gridded * lat_areas_in_m2 + + aggregated = gridded.mean(dim=self.mean_time_dims).sum(dim=sum_spatial_dims) + + return verify_global_values(aggregated, tabular, proxy_cfg.name, self.index) def compute_output( self, From 3654362936b1a7ae14389841e8e9dd616e0db85b Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Sun, 28 May 2023 10:10:57 +0200 Subject: [PATCH 42/77] Fix CI/CD - Install pandoc - Add pip caching --- .github/workflows/ci.yml | 9 ++++- .gitignore | 77 +++++++++++++++++++++++++++++++++++----- tox.ini | 5 ++- 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index edb8f70..1144345 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: python-version: [3.8, 3.11] # to minimise complexity we only test a min and a max version include: # on all platforms and versions do everything - - tox-envs: [docs, lint, build, test] + - tox-envs: [lint, test, docs, build] runs-on: ${{ matrix.platform }} @@ -24,10 +24,17 @@ jobs: - name: Checkout uses: actions/checkout@v3 + # pandoc is required by nbsphinx for building the notebook-based docs + - name: Setup pandoc for building docs + uses: r-lib/actions/setup-pandoc@v2 + with: + pandoc-version: '2.19.2' + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + cache: 'pip' - name: Install tox run: | diff --git a/.gitignore b/.gitignore index 39ead74..dcc2071 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,72 @@ -#* -aneris/_version.py +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class -*# +# C extensions +*.so + +# editors +*.swp *~ -*.pyc -build -dist -*.egg-info + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +_version.py + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* .cache -.* +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Sphinx documentation +docs/_build/ +docs/html +docs/latex + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ -venv +# Editor settings +.spyderproject +.spyproject +.ropeproject +.vscode \ No newline at end of file diff --git a/tox.ini b/tox.ini index 2c78957..7293151 100644 --- a/tox.ini +++ b/tox.ini @@ -85,9 +85,8 @@ commands = [testenv:docs] package = editable extras = doc -# TODO: add docs back, currently fail saying can't find pandoc -# commands = -# sphinx-build {posargs:-E} -b html docs docs/html +commands = + sphinx-build {posargs:-E} -b html docs docs/html # safety checks [testenv:safety] From 2b98cd6cef07299bd42312e605be5207e2a0c238 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Fri, 18 Aug 2023 13:34:26 +0200 Subject: [PATCH 43/77] add pycountry to deps --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 2942a68..7defb4b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ dependencies = [ "matplotlib", "pyomo>=5", "pandas-indexing>=0.2.7", + "pycountry", ] dynamic = ["version"] From faa03b6853e813b58e3129c01a4835ce47a03313 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Fri, 18 Aug 2023 14:17:37 +0200 Subject: [PATCH 44/77] verify output now works as expected, allow skipping of write --- src/aneris/grid.py | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 9b51042..d9fba78 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -24,8 +24,9 @@ @dask.delayed def verify_global_values(aggregated, tabular, proxy_name, index, reltol=1e-4): grid_df = aggregated.to_series().pix.project(index).unstack("year") + tab_df = tabular.pix.project(index).unstack("year") tab_df = ( - semijoin(tabular, grid_df.index, how="inner")[grid_df.columns] + semijoin(tab_df, grid_df.index, how="inner")[grid_df.columns] .groupby(grid_df.index.names) .sum() ) @@ -33,9 +34,13 @@ def verify_global_values(aggregated, tabular, proxy_name, index, reltol=1e-4): reldiff = abs(grid_df - tab_df) / tab_df if (reldiff >= reltol).any(axis=None): logger().warning( - f"Yearly global totals ({proxy_name}) not within {reltol} relative values:\n" + f"Yearly global totals relative values between grids and global data for ({proxy_name}) not within {reltol}:\n" f"{reldiff}" ) + else: + logger().info( + f"Yearly global totals relative values between grids and global data for ({proxy_name}) within tolerance" + ) return reldiff @@ -305,23 +310,21 @@ def grid( write_tasks.append( self.verify_output(proxy_cfg, tabular, gridded) ) - - write_tasks.append( - self.compute_output( - proxy_cfg, - gridded, - data.indexes, - iter_ids, - write=write, - share_dims=share_dims, + if write: + write_tasks.append( + self.compute_output( + proxy_cfg, + gridded, + data.indexes, + iter_ids, + write=write, + share_dims=share_dims, + ) ) - ) - if write: - with ProgressBar(): - dask.compute(write_tasks) - else: - ret.append(write_tasks) + with ProgressBar(): + dask.compute(write_tasks) + ret.append(write_tasks) return ret From c27099eaaca20807eb66081961485db291540f81 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Fri, 18 Aug 2023 14:31:30 +0200 Subject: [PATCH 45/77] black file --- src/aneris/downscaling/intensity_convergence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aneris/downscaling/intensity_convergence.py b/src/aneris/downscaling/intensity_convergence.py index fd9a51c..c747023 100644 --- a/src/aneris/downscaling/intensity_convergence.py +++ b/src/aneris/downscaling/intensity_convergence.py @@ -335,7 +335,7 @@ def intensity_growth_rate_model( * intensity_hist.values[:, np.newaxis], index=intensity_hist.index, columns=years_downscaling.rename("year"), - ).where(intensity_hist != 0, 0.) + ).where(intensity_hist != 0, 0.0) return intensity_projection From 3d4c107c77e7b8076cfb225b9d38c141e6cfc220 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Fri, 18 Aug 2023 15:04:16 +0200 Subject: [PATCH 46/77] additional bugfix for downscaled data in verify_global_values --- src/aneris/grid.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index d9fba78..904151e 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -24,12 +24,8 @@ @dask.delayed def verify_global_values(aggregated, tabular, proxy_name, index, reltol=1e-4): grid_df = aggregated.to_series().pix.project(index).unstack("year") - tab_df = tabular.pix.project(index).unstack("year") - tab_df = ( - semijoin(tab_df, grid_df.index, how="inner")[grid_df.columns] - .groupby(grid_df.index.names) - .sum() - ) + tab_df = tabular.pix.project(index).groupby(level=index).sum().unstack("year") + tab_df = semijoin(tab_df, grid_df.index, how="inner")[grid_df.columns] reldiff = abs(grid_df - tab_df) / tab_df if (reldiff >= reltol).any(axis=None): From 9c69460bd4b1bd8784c6bc43af41302b81e5a3cd Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Fri, 18 Aug 2023 17:24:49 +0200 Subject: [PATCH 47/77] support multiple methods in verify_global_values --- src/aneris/grid.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 904151e..7b82711 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -23,8 +23,14 @@ @dask.delayed def verify_global_values(aggregated, tabular, proxy_name, index, reltol=1e-4): - grid_df = aggregated.to_series().pix.project(index).unstack("year") tab_df = tabular.pix.project(index).groupby(level=index).sum().unstack("year") + grid_df = ( + aggregated.to_series() + .pix.project(index) + .groupby(level=index) + .sum() + .unstack("year") + ) tab_df = semijoin(tab_df, grid_df.index, how="inner")[grid_df.columns] reldiff = abs(grid_df - tab_df) / tab_df From 17f3641de781d7bbc59da3fb7b620d40fc668fef Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Sat, 19 Aug 2023 16:07:32 +0200 Subject: [PATCH 48/77] make luc_sectors explicit and allow Gridder to be instatiated with them --- src/aneris/downscaling/core.py | 3 +++ src/aneris/downscaling/methods.py | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index b28a33d..4f33127 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -43,6 +43,7 @@ def __init__( hist: DataFrame, year: int, region_mapping: Series, + luc_sectors: Sequence[str] = [], index: Sequence[str] = DEFAULT_INDEX, method_choice: Optional[callable] = None, return_type=DataFrame, @@ -80,6 +81,7 @@ def __init__( self.intensity_method = None self.luc_method = None self.method_choice = None + self.luc_sectors = luc_sectors @property def index(self): @@ -207,6 +209,7 @@ def methods(self, method_choice=None, overwrites=None): "fallback_method": self.fallback_method, "intensity_method": self.intensity_method, "luc_method": self.luc_method, + "luc_sectors": self.luc_sectors, } hist_agg = ( diff --git a/src/aneris/downscaling/methods.py b/src/aneris/downscaling/methods.py index 045d36a..22d169f 100644 --- a/src/aneris/downscaling/methods.py +++ b/src/aneris/downscaling/methods.py @@ -66,7 +66,7 @@ def simple_proxy( proxy_name: str, ) -> DataFrame: """ - Downscales emission data using the shares in a proxy scenario + Downscales emission data using the shares in a proxy scenario. Parameters ---------- @@ -161,10 +161,12 @@ def default_method_choice( fallback_method="proxy_gdp", intensity_method="ipat_2100_gdp", luc_method="base_year_pattern", + luc_sectors=None, ): """ Default downscaling decision tree. """ + luc_sectors = luc_sectors or ("Agriculture", "LULUCF") # special cases if traj.h == 0: @@ -172,7 +174,7 @@ def default_method_choice( if traj.zero_m: return fallback_method - if traj.get("sector", None) in ("Agriculture", "LULUCF"): + if traj.get("sector", None) in luc_sectors: return luc_method return intensity_method From ab43e18f28a8e1a978eb9df3754ae01716ef5d9b Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Mon, 21 Aug 2023 10:24:14 +0200 Subject: [PATCH 49/77] grid: Fix verify_global_values for multiple scenarios --- src/aneris/grid.py | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 7b82711..159a114 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -23,15 +23,9 @@ @dask.delayed def verify_global_values(aggregated, tabular, proxy_name, index, reltol=1e-4): - tab_df = tabular.pix.project(index).groupby(level=index).sum().unstack("year") - grid_df = ( - aggregated.to_series() - .pix.project(index) - .groupby(level=index) - .sum() - .unstack("year") - ) - tab_df = semijoin(tab_df, grid_df.index, how="inner")[grid_df.columns] + tab_df = tabular.groupby(level=index).sum().unstack("year") + grid_df = aggregated.to_series().groupby(level=index).sum().unstack("year") + grid_df, tab_df = grid_df.align(tab_df, join="inner") reldiff = abs(grid_df - tab_df) / tab_df if (reldiff >= reltol).any(axis=None): @@ -303,14 +297,15 @@ def grid( for iter_vals in tabular.idx.unique(iter_levels): iter_ids = dict(zip(iter_levels, iter_vals)) logger().info("Adding tasks for %s", iter_ids) - data = DataArray.from_series( - tabular.loc[isin(**iter_ids)].droplevel(iter_levels) + single_tabular = tabular.loc[isin(**iter_ids)].droplevel( + iter_levels ) + data = DataArray.from_series(single_tabular) gridded = (data * proxy).sum(self.country_level) if verify_output: write_tasks.append( - self.verify_output(proxy_cfg, tabular, gridded) + self.verify_output(proxy_cfg, single_tabular, gridded) ) if write: write_tasks.append( @@ -325,17 +320,11 @@ def grid( ) with ProgressBar(): - dask.compute(write_tasks) - ret.append(write_tasks) + ret.append(dask.compute(write_tasks)) return ret - def verify_output( - self, - proxy_cfg, - tabular, - gridded, - ): + def verify_output(self, proxy_cfg, tabular, gridded): # TODO: figure out correct message here # ids = {dim: index[0] for dim, index in indexes.items() if len(index) == 1} # logger().info(f"Veryifying output for {ids}") From 4d3984757d51b7c6b917ef45565d7ef78f90da44 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Mon, 21 Aug 2023 16:22:59 +0200 Subject: [PATCH 50/77] fix(test_harmonize): Specify string-based harmonization year explicitly Harmonize interface was updated to work with string and non-string year columns, but defaults are to use ints and we need to use strings explicitly. --- tests/test_harmonize.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_harmonize.py b/tests/test_harmonize.py index d37153b..f7c64b6 100644 --- a/tests/test_harmonize.py +++ b/tests/test_harmonize.py @@ -60,7 +60,9 @@ def test_factors(): df = _df.copy() hist = _hist.copy() - obsoffset, obsratio = harmonize.harmonize_factors(df.copy(), hist.copy()) + obsoffset, obsratio = harmonize.harmonize_factors( + df.copy(), hist.copy(), harmonize_year="2015" + ) # im lazy; test initially written when these were of length 2 exp = np.array([0.01 - 3, -1.0]) npt.assert_array_almost_equal(exp, obsoffset[-2:]) @@ -89,7 +91,7 @@ def test_harmonize_constant_offset(): def test_no_model(): df = pd.DataFrame({"2015": [0]}) hist = pd.DataFrame({"2015": [1.5]}) - obsoffset, obsratio = harmonize.harmonize_factors(df.copy(), hist.copy()) + obsoffset, obsratio = harmonize.harmonize_factors(df.copy(), hist.copy(), harmonize_year="2015") exp = np.array([1.5]) npt.assert_array_almost_equal(exp, obsoffset) exp = np.array([0]) From a3f78a44e8aee2dee19890ee26368c682ef76724 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Mon, 21 Aug 2023 16:42:45 +0200 Subject: [PATCH 51/77] black test harmonize --- tests/test_harmonize.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_harmonize.py b/tests/test_harmonize.py index f7c64b6..44c6796 100644 --- a/tests/test_harmonize.py +++ b/tests/test_harmonize.py @@ -91,7 +91,9 @@ def test_harmonize_constant_offset(): def test_no_model(): df = pd.DataFrame({"2015": [0]}) hist = pd.DataFrame({"2015": [1.5]}) - obsoffset, obsratio = harmonize.harmonize_factors(df.copy(), hist.copy(), harmonize_year="2015") + obsoffset, obsratio = harmonize.harmonize_factors( + df.copy(), hist.copy(), harmonize_year="2015" + ) exp = np.array([1.5]) npt.assert_array_almost_equal(exp, obsoffset) exp = np.array([0]) From 1185c2d54a4ea7ea252505ca06e4dfcfef2774da Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Mon, 21 Aug 2023 17:19:59 +0200 Subject: [PATCH 52/77] Fix docs CI Typos in tox.ini and pyproject.toml --- doc/source/conf.py | 3 ++- pyproject.toml | 4 +--- tox.ini | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 78a27c7..9be3b20 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -43,6 +43,7 @@ "nbsphinx", "sphinxcontrib.bibtex", "sphinxcontrib.programoutput", + "sphinxcontrib.exceltable", ] # Add any paths that contain templates here, relative to this directory. @@ -304,4 +305,4 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {"https://docs.python.org/": None} -bibtex_bibfiles = "./_bib/index.bib" +bibtex_bibfiles = ["./_bib/index.bib"] diff --git a/pyproject.toml b/pyproject.toml index 7defb4b..c3d4f52 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,13 +45,11 @@ docs = [ "sphinx", "sphinxcontrib-bibtex", "sphinxcontrib-programoutput", + "sphinxcontrib-exceltable", "sphinx-gallery", "nbsphinx", "numpydoc", "nbformat", - "ipython", - "jupyter", - "jupyter_contrib_nbextensions", "pillow", ] lint = [ diff --git a/tox.ini b/tox.ini index 7293151..b3a7113 100644 --- a/tox.ini +++ b/tox.ini @@ -84,9 +84,9 @@ commands = # if this fails, most likely RTD build will fail [testenv:docs] package = editable -extras = doc +extras = docs commands = - sphinx-build {posargs:-E} -b html docs docs/html + sphinx-build {posargs:-E} -b html doc/source doc/build/html # safety checks [testenv:safety] From 8f434edc3471f72487fe0a463d3b92195d1bfeea Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Fri, 25 Aug 2023 21:32:33 +0200 Subject: [PATCH 53/77] update base_year_pattern to support multiple scenarios/models --- src/aneris/downscaling/methods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aneris/downscaling/methods.py b/src/aneris/downscaling/methods.py index 22d169f..96d8094 100644 --- a/src/aneris/downscaling/methods.py +++ b/src/aneris/downscaling/methods.py @@ -50,7 +50,7 @@ def base_year_pattern( weights = ( semijoin(hist, context.regionmap_index, how="right") - .groupby(list(context.index) + [context.region_level], dropna=False) + .groupby(model.index.names, dropna=False) .transform(normalize) ) From a2de0802744537824b3fe2509a2888833701a288 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Fri, 25 Aug 2023 21:49:14 +0200 Subject: [PATCH 54/77] enh(downscaler): Check downscaling results for correctness --- src/aneris/downscaling/core.py | 36 ++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index 4f33127..3409e40 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -7,6 +7,7 @@ from ..errors import MissingHistoricalError, MissingProxyError from ..methods import default_methods +from ..utils import logger from .data import DownscalingContext from .methods import ( base_year_pattern, @@ -31,7 +32,7 @@ class Downscaler: "base_year_pattern": base_year_pattern, "growth_rate": growth_rate, "proxy_gdp": partial(simple_proxy, proxy_name="gdp"), - "proxy_pop": partial(simple_proxy, proxy_name="gdp"), + "proxy_pop": partial(simple_proxy, proxy_name="pop"), } def add_method(self, name, method): @@ -80,7 +81,7 @@ def __init__( self.fallback_method = None self.intensity_method = None self.luc_method = None - self.method_choice = None + self.method_choice = method_choice self.luc_sectors = luc_sectors @property @@ -163,7 +164,9 @@ def check_proxies(self, methods: Series) -> None: + ", ".join(missing_years.astype(str)) ) - def downscale(self, methods: Optional[Series] = None) -> DataFrame: + def downscale( + self, methods: Optional[Series] = None, check_result: bool = True + ) -> DataFrame: """ Downscale aligned model data from historical data, and socio-economic scenario. @@ -179,6 +182,9 @@ def downscale(self, methods: Optional[Series] = None) -> DataFrame: Parameters ---------- methods : Series Methods to apply + + check_result : bool, default True + Check whether the downscaled trajectories sum up to the regional totals """ if methods is None: @@ -195,7 +201,29 @@ def downscale(self, methods: Optional[Series] = None) -> DataFrame: downscaled.append(self._methods[method](model, hist, self.context)) - return self.return_type(concat(downscaled)) + downscaled = concat(downscaled) + if check_result: + self.check_downscaled(downscaled) + + return self.return_type(downscaled) + + def check_downscaled(self, downscaled, rtol=1e-05, atol=1e-08): + downscaled = ( + downscaled.groupby(self.model.index.names, dropna=False) + .sum() + .rename_axis(columns="year") + .stack() + ) + model = self.model.rename_axis(columns="year").stack() + diff = downscaled - model + diff_exceeded = abs(diff) + rtol * abs(model) > atol + if diff_exceeded.any(): + logger().warning( + "Difference thresholds exceeded for a few trajectories:\n%s", + DataFrame(dict(model=model, downscaled=downscaled, diff=diff)) + .loc[diff_exceeded] + .to_string(), + ) def methods(self, method_choice=None, overwrites=None): if method_choice is None: From 34100b14e963ea9df91252ca8c5c4f8ed0cb5787 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Fri, 25 Aug 2023 21:49:29 +0200 Subject: [PATCH 55/77] Add pre-commit config --- .pre-commit-config.yaml | 61 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..9b26b19 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,61 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: check-merge-conflict + - id: end-of-file-fixer + #- id: fix-encoding-pragma # ruff does not thing this makes sense + - id: mixed-line-ending + - id: trailing-whitespace + - id: check-added-large-files + args: ["--maxkb=2000"] + +# # Convert relative imports to absolute imports +# - repo: https://github.com/MarcoGorelli/absolufy-imports +# rev: v0.3.1 +# hooks: +# - id: absolufy-imports + +# Find common spelling mistakes in comments and docstrings +- repo: https://github.com/codespell-project/codespell + rev: v2.2.2 + hooks: + - id: codespell + args: ['--ignore-regex="(\b[A-Z]+\b)"', '--ignore-words-list=fom'] # Ignore capital case words, e.g. country codes + types_or: [python, rst, markdown] + files: ^(scripts|doc)/ + +# Make docstrings PEP 257 compliant +- repo: https://github.com/PyCQA/docformatter + rev: v1.5.1 + hooks: + - id: docformatter + args: ["--in-place", "--make-summary-multi-line", "--pre-summary-newline"] + +- repo: https://github.com/keewis/blackdoc + rev: v0.3.8 + hooks: + - id: blackdoc + +# Formatting with "black" coding style +- repo: https://github.com/psf/black + rev: 23.1.0 + hooks: + # Format Python files + - id: black + # Format Jupyter Python notebooks + - id: black-jupyter + +# Linting with ruff +- repo: https://github.com/charliermarsh/ruff-pre-commit + # Ruff version. + rev: 'v0.0.245' + hooks: + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + +# # Check for FSFE REUSE compliance (licensing) +# - repo: https://github.com/fsfe/reuse-tool +# rev: v1.1.2 +# hooks: +# - id: reuse From 347fcbffb369a3570f996101d9fd731e77970c2a Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Wed, 30 Aug 2023 17:54:22 +0200 Subject: [PATCH 56/77] fix(downscaling): Make Downscaler use year-argument Downscaling methods assumed previously that the last historical year is the downscaling base year. Use provided year-argument instead. --- src/aneris/downscaling/core.py | 8 ++++++-- src/aneris/downscaling/data.py | 13 ++++++++----- src/aneris/downscaling/intensity_convergence.py | 3 ++- src/aneris/downscaling/methods.py | 8 ++++++-- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index 3409e40..5bd5295 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -52,10 +52,10 @@ def __init__( ): self.model = model self.hist = hist - self.year = year self.return_type = return_type self.context = DownscalingContext( index, + year, region_mapping, additional_data, country_level=region_mapping.index.name, @@ -63,7 +63,7 @@ def __init__( ) assert ( - hist[year].groupby(list(index) + [self.country_level]).count() <= 1 + hist[self.year].groupby(list(index) + [self.country_level]).count() <= 1 ).all(), "Ambiguous history" missing_hist = ( @@ -88,6 +88,10 @@ def __init__( def index(self): return self.context.index + @property + def year(self): + return self.context.year + @property def region_mapping(self): return self.context.regionmap diff --git a/src/aneris/downscaling/data.py b/src/aneris/downscaling/data.py index 5b7f8ae..c6c2766 100644 --- a/src/aneris/downscaling/data.py +++ b/src/aneris/downscaling/data.py @@ -12,15 +12,17 @@ class DownscalingContext: Attributes ---------- - index: sequence of str + index : sequence of str index levels that differentiate trajectories - regionmap: Series + year : int + base year for downscaling + regionmap : Series map from countries to regions - additional_data: dict, default {} + additional_data : dict, default {} named `DataFrame`s or `Series` the methods need as proxies - country_level: str, default "country" + country_level : str, default "country" name of the fine index level - region_level: str, default "region" + region_level : str, default "region" name of the coarse index level Notes @@ -29,6 +31,7 @@ class DownscalingContext: """ index: Sequence[str] + year: int regionmap: Series additional_data: dict[str, Union[Series, DataFrame]] = field(default_factory=dict) country_level: str = "country" diff --git a/src/aneris/downscaling/intensity_convergence.py b/src/aneris/downscaling/intensity_convergence.py index c747023..f7630e0 100644 --- a/src/aneris/downscaling/intensity_convergence.py +++ b/src/aneris/downscaling/intensity_convergence.py @@ -383,8 +383,9 @@ def intensity_convergence( 1443–1475 (2019). """ + model = model.loc[:, context.year :] if isinstance(hist, DataFrame): - hist = hist.iloc[:, -1] + hist = hist.loc[:, context.year] reference = semijoin(context.additional_data[proxy_name], context.regionmap_index)[ model.columns diff --git a/src/aneris/downscaling/methods.py b/src/aneris/downscaling/methods.py index 96d8094..7c65e4c 100644 --- a/src/aneris/downscaling/methods.py +++ b/src/aneris/downscaling/methods.py @@ -45,8 +45,9 @@ def base_year_pattern( DownscalingContext """ + model = model.loc[:, context.year :] if isinstance(hist, DataFrame): - hist = hist.iloc[:, -1] + hist = hist.loc[:, context.year] weights = ( semijoin(hist, context.regionmap_index, how="right") @@ -90,6 +91,8 @@ def simple_proxy( DownscalingContext """ + model = model.loc[:, context.year :] + proxy_data = context.additional_data[proxy_name] common_levels = [lvl for lvl in model.index.names if lvl in proxy_data.index.names] weights = ( @@ -135,8 +138,9 @@ def growth_rate( 2. region mapping has two indices the first one is fine, the second coarse """ + model = model.loc[:, context.year :] if isinstance(hist, DataFrame): - hist = hist.iloc[:, -1] + hist = hist.loc[:, context.year] cumulative_growth_rates = (model / model.shift(axis=1, fill_value=1)).cumprod( axis=1 From 023fa9063c8ba95814706014df2e7f6ea7a169eb Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Wed, 30 Aug 2023 18:01:17 +0200 Subject: [PATCH 57/77] Add additional check whether downscaled starts from history --- src/aneris/downscaling/core.py | 44 +++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index 5bd5295..d23c27f 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -212,22 +212,44 @@ def downscale( return self.return_type(downscaled) def check_downscaled(self, downscaled, rtol=1e-05, atol=1e-08): - downscaled = ( + def warn_if_differences(actual, should, message): + actual, should = actual.align(should, join="left") + diff = actual - should + diff_exceeded = abs(diff) > atol + rtol * abs(should) + if diff_exceeded.any(): + logger().warning( + "%s:\n%s", + message, + DataFrame(dict(actual=actual, should=should, diff=diff)) + .loc[diff_exceeded] + .to_string(), + ) + + downscaled_region = ( downscaled.groupby(self.model.index.names, dropna=False) .sum() .rename_axis(columns="year") .stack() ) - model = self.model.rename_axis(columns="year").stack() - diff = downscaled - model - diff_exceeded = abs(diff) + rtol * abs(model) > atol - if diff_exceeded.any(): - logger().warning( - "Difference thresholds exceeded for a few trajectories:\n%s", - DataFrame(dict(model=model, downscaled=downscaled, diff=diff)) - .loc[diff_exceeded] - .to_string(), - ) + model = self.model.loc[:, self.year:].rename_axis(columns="year").stack() + + warn_if_differences( + downscaled_region, + model, + "Downscaled trajectories do not sum up to regional totals", + ) + + hist = self.hist + if isinstance(hist, DataFrame): + hist = hist.loc[:, self.year] + hist = hist.pix.semijoin(downscaled.index, how="right") + downscaled_start = downscaled.loc[:, self.year] + + warn_if_differences( + downscaled_start, + hist, + "Downscaled trajectories do not start from history", + ) def methods(self, method_choice=None, overwrites=None): if method_choice is None: From 8600e13eed6afdcdfd36bbcaf7182dc9e44346cd Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Mon, 28 Aug 2023 15:44:22 +0200 Subject: [PATCH 58/77] add capability to skip executing a gridding operation if the output file already exists --- src/aneris/grid.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 159a114..a117036 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -246,6 +246,17 @@ def open_and_normalize_proxy(self, proxy_cfg, chunk_proxy_dims={}): yield normalized + def output_path(self, proxy_cfg, indexes, iter_ids): + self.output_dir.mkdir(parents=True, exist_ok=True) + ids = {dim: index[0] for dim, index in indexes.items() if len(index) == 1} + fname = ( + proxy_cfg.template.format(name=proxy_cfg.name, **ids, **iter_ids).replace( + " ", "__" + ) + + ".nc" + ) + return self.output_dir / fname + # TODO: iter_levels was added because some trajectories can have different # downscaling methods applied? E.g., for burning emissions, proxy_gdp and # ipat are both used, causing the gridding process to be called twice in @@ -261,6 +272,7 @@ def grid( write: bool = True, # TODO: make docs share_dims: Sequence[str] = ["sector"], # TODO: make docs verify_output: bool = False, # TODO: make docs + skip_exists: bool = False, # TODO: make docs ) -> None: """ Grid data onto configured proxies. @@ -296,11 +308,16 @@ def grid( for iter_vals in tabular.idx.unique(iter_levels): iter_ids = dict(zip(iter_levels, iter_vals)) - logger().info("Adding tasks for %s", iter_ids) single_tabular = tabular.loc[isin(**iter_ids)].droplevel( iter_levels ) data = DataArray.from_series(single_tabular) + + if skip_exists and self.output_path(proxy_cfg, data.indexes, iter_ids).exists(): + logger().info("File exists, skipping tasks for %s", iter_ids) + continue + + logger().info("Adding tasks for %s", iter_ids) gridded = (data * proxy).sum(self.country_level) if verify_output: @@ -355,15 +372,7 @@ def compute_output( comp=dict(zlib=True, complevel=5), ): # TODO: need to add attr definitions and dimension bounds - self.output_dir.mkdir(parents=True, exist_ok=True) - ids = {dim: index[0] for dim, index in indexes.items() if len(index) == 1} - fname = ( - proxy_cfg.template.format(name=proxy_cfg.name, **ids, **iter_ids).replace( - " ", "__" - ) - + ".nc" - ) - path = self.output_dir / fname + path = self.output_path(proxy_cfg, indexes, iter_ids) logger().info(f"Writing to {path}") if not proxy_cfg.separate_shares: gridded = gridded.to_dataset(name=proxy_cfg.name) From 0d4d8c934820a2877632c0de2642d1010042bcf4 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Tue, 3 Oct 2023 17:11:08 +0200 Subject: [PATCH 59/77] remove share separation logic --- src/aneris/grid.py | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index a117036..e7ed3f6 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -374,33 +374,11 @@ def compute_output( # TODO: need to add attr definitions and dimension bounds path = self.output_path(proxy_cfg, indexes, iter_ids) logger().info(f"Writing to {path}") - if not proxy_cfg.separate_shares: - gridded = gridded.to_dataset(name=proxy_cfg.name) - if write: - return gridded.to_netcdf( - path, compute=False, encoding={proxy_cfg.name: comp} - ) - else: - return gridded - - shares_fname = ( - proxy_cfg.template.format( - name=f"{proxy_cfg.name}-shares", **ids, **iter_ids - ).replace(" ", "__") - + ".nc" - ) - shares_path = self.output_dir / shares_fname - logger().info(f"Writing to {shares_path}") - total = gridded.sum(share_dims) - shares = gridded / total - total = total.to_dataset(name=proxy_cfg.name) - shares = shares.to_dataset(name=f"{proxy_cfg.name}-shares") + gridded = gridded.to_dataset(name=proxy_cfg.name) if write: - return total.to_netcdf( + return gridded.to_netcdf( path, compute=False, encoding={proxy_cfg.name: comp} - ), shares.to_netcdf( - shares_path, compute=False, encoding={f"{proxy_cfg.name}-shares": comp} ) else: - return total, shares + return gridded From 12619b02ca04526221b9294b00b27c42168ea609 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Wed, 4 Oct 2023 15:59:24 +0200 Subject: [PATCH 60/77] change complevel to 2 --- src/aneris/grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index e7ed3f6..673c091 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -369,7 +369,7 @@ def compute_output( iter_ids, write=True, share_dims=["sector"], - comp=dict(zlib=True, complevel=5), + comp=dict(zlib=True, complevel=2), ): # TODO: need to add attr definitions and dimension bounds path = self.output_path(proxy_cfg, indexes, iter_ids) From 238b2a43768185fe5dbcfdc2b4964630c44dcda9 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Wed, 4 Oct 2023 12:38:12 +0200 Subject: [PATCH 61/77] first cut at multiproxy --- src/aneris/grid.py | 91 ++++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 36 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 673c091..6a64415 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -95,8 +95,6 @@ def __init__( proxy_cfg["as_flux"] = True if "global_only" not in proxy_cfg.columns: proxy_cfg["global_only"] = False - if "separate_shares" not in proxy_cfg.columns: - proxy_cfg["separate_shares"] = False self.proxy_cfg = proxy_cfg self.index = list(index) @@ -185,7 +183,7 @@ def get_index(dim): proxy_missing_dims = {"lat", "lon", *self.index}.difference(proxy.dims) if proxy_missing_dims: raise MissingDimension( - f"Proxy {proxy_cfg.name} missing dimensions: " + f"Proxy {proxy_cfg.path.stem} missing dimensions: " + ", ".join(proxy_missing_dims) ) @@ -193,7 +191,7 @@ def get_index(dim): missing_from_data = index.difference(data_index) if not missing_from_data.empty: msg = ( - f"Proxy '{proxy_cfg.name}' has values missing from `data`:\n" + f"Proxy '{proxy_cfg.path.stem}' has values missing from `data`:\n" + missing_from_data.to_frame().to_string(index=False) ) if strict_proxy_data: @@ -214,31 +212,37 @@ def concat(objs): + missing_from_proxy.to_frame().to_string(index=False) ) - @contextmanager - def open_and_normalize_proxy(self, proxy_cfg, chunk_proxy_dims={}): - with xr.open_dataarray( - proxy_cfg.path, + + def _open_single_proxy(self, path, global_only=False, chunk_proxy_dims={}): + proxy = xr.open_dataarray( + path, chunks=dict(zip(self.index, repeat(1))) | chunk_proxy_dims, - ) as proxy: - for idx in self.index: - mapping = self.index_mappings.get(idx) - if mapping is not None: - proxy[idx] = proxy.indexes[idx].map(mapping) + ) + for idx in self.index: + mapping = self.index_mappings.get(idx) + if mapping is not None: + proxy[idx] = proxy.indexes[idx].map(mapping) - # TODO: this maybe isn't needed anymore with 'World' included in idxraster - # but need to confirm 'World' is also in the proxy rasters - separate = proxy if proxy_cfg.global_only else self.idxraster * proxy - # separate = self.idxraster * proxy + # TODO: this maybe isn't needed anymore with 'World' included in idxraster + # but need to confirm 'World' is also in the proxy rasters + separate = proxy if global_only else self.idxraster * proxy + return separate + + @contextmanager + def open_and_normalize_proxy(self, cfgs, concat_dim='sector', as_flux=True, chunk_proxy_dims={}): + try: + proxies = [self._open_single_proxy(cfg['path'], cfg['global_only'], chunk_proxy_dims) for cfg in cfgs] + proxy = xr.concat(proxies, dim=concat_dim) # NB: this only preserves seasonality if years and months are # separate dimensions in the proxy raster. If instead they are # combined into a single 'time' dimension, seasonality is lost. - sum_spatial_dims = list(set(separate.dims).intersection(self.spatial_dims)) - normalized = separate / separate.mean(self.mean_time_dims).sum( + sum_spatial_dims = list(set(proxy.dims).intersection(self.spatial_dims)) + normalized = proxy / proxy.mean(self.mean_time_dims).sum( sum_spatial_dims ) - if proxy_cfg.as_flux: + if as_flux: lat_areas_in_m2 = xr.DataArray.from_series( pt.cell_area_from_file(proxy) ) @@ -246,11 +250,15 @@ def open_and_normalize_proxy(self, proxy_cfg, chunk_proxy_dims={}): yield normalized - def output_path(self, proxy_cfg, indexes, iter_ids): + finally: + for p in proxies: + p.close() + + def output_path(self, name, template, indexes, iter_ids): self.output_dir.mkdir(parents=True, exist_ok=True) ids = {dim: index[0] for dim, index in indexes.items() if len(index) == 1} fname = ( - proxy_cfg.template.format(name=proxy_cfg.name, **ids, **iter_ids).replace( + template.format(name=name, **ids, **iter_ids).replace( " ", "__" ) + ".nc" @@ -293,10 +301,19 @@ def grid( self.index + [self.country_level] ) ret = [] - for proxy_cfg in self.proxy_cfg.itertuples(): - logger().info("Collecting tasks for proxy %s", proxy_cfg.name) - - with self.open_and_normalize_proxy(proxy_cfg, chunk_proxy_dims) as proxy: + for name, cfgs in self.proxy_cfg.groupby('name'): # MJG: needs to change to support multiple rows + logger().info("Collecting tasks for proxy %s", name) + def _get_unique_opt(cfgs, key): + assert cfgs[key].unique() == 1 + return cfgs[key][0] + opts = {key: _get_unique_opt(cfgs, key) for key in ['template', 'as_flux', 'concat_dim']} + + with self.open_and_normalize_proxy( + cfgs, + concat_dim=opts["concat_dim"], + as_flux=opts["as_flux"], + chunk_proxy_dims=chunk_proxy_dims, + ) as proxy: write_tasks = [] proxy_index = MultiIndex.from_product( @@ -313,7 +330,7 @@ def grid( ) data = DataArray.from_series(single_tabular) - if skip_exists and self.output_path(proxy_cfg, data.indexes, iter_ids).exists(): + if skip_exists and self.output_path(name, opts["template"], data.indexes, iter_ids).exists(): logger().info("File exists, skipping tasks for %s", iter_ids) continue @@ -322,12 +339,13 @@ def grid( if verify_output: write_tasks.append( - self.verify_output(proxy_cfg, single_tabular, gridded) + self.verify_output(name, single_tabular, gridded, as_flux=opts["as_flux"]) ) if write: write_tasks.append( self.compute_output( - proxy_cfg, + name, + opts["template"], gridded, data.indexes, iter_ids, @@ -341,7 +359,7 @@ def grid( return ret - def verify_output(self, proxy_cfg, tabular, gridded): + def verify_output(self, name, tabular, gridded, as_flux=True): # TODO: figure out correct message here # ids = {dim: index[0] for dim, index in indexes.items() if len(index) == 1} # logger().info(f"Veryifying output for {ids}") @@ -353,17 +371,18 @@ def verify_output(self, proxy_cfg, tabular, gridded): # to confirm that gridded values comport with provided global totals sum_spatial_dims = list(set(gridded.dims).intersection(self.spatial_dims)) - if proxy_cfg.as_flux: + if as_flux: lat_areas_in_m2 = xr.DataArray.from_series(pt.cell_area_from_file(gridded)) gridded = gridded * lat_areas_in_m2 aggregated = gridded.mean(dim=self.mean_time_dims).sum(dim=sum_spatial_dims) - return verify_global_values(aggregated, tabular, proxy_cfg.name, self.index) + return verify_global_values(aggregated, tabular, name, self.index) def compute_output( self, - proxy_cfg, + name, + template, gridded: DataArray, indexes, iter_ids, @@ -372,13 +391,13 @@ def compute_output( comp=dict(zlib=True, complevel=2), ): # TODO: need to add attr definitions and dimension bounds - path = self.output_path(proxy_cfg, indexes, iter_ids) + path = self.output_path(name, template, indexes, iter_ids) logger().info(f"Writing to {path}") - gridded = gridded.to_dataset(name=proxy_cfg.name) + gridded = gridded.to_dataset(name=name) if write: return gridded.to_netcdf( - path, compute=False, encoding={proxy_cfg.name: comp} + path, compute=False, encoding={name: comp} ) else: return gridded From 6479a9d8643b1a8531dac7239de58ad132e2cbad Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Wed, 4 Oct 2023 13:03:14 +0200 Subject: [PATCH 62/77] slight tweaks --- src/aneris/grid.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 6a64415..39dc193 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -214,24 +214,26 @@ def concat(objs): def _open_single_proxy(self, path, global_only=False, chunk_proxy_dims={}): - proxy = xr.open_dataarray( + opened = xr.open_dataarray( path, chunks=dict(zip(self.index, repeat(1))) | chunk_proxy_dims, ) for idx in self.index: mapping = self.index_mappings.get(idx) if mapping is not None: - proxy[idx] = proxy.indexes[idx].map(mapping) + opened[idx] = opened.indexes[idx].map(mapping) # TODO: this maybe isn't needed anymore with 'World' included in idxraster # but need to confirm 'World' is also in the proxy rasters - separate = proxy if global_only else self.idxraster * proxy - return separate + proxy = opened if global_only else self.idxraster * opened + return {'to_close': opened, 'proxy': proxy} @contextmanager def open_and_normalize_proxy(self, cfgs, concat_dim='sector', as_flux=True, chunk_proxy_dims={}): try: - proxies = [self._open_single_proxy(cfg['path'], cfg['global_only'], chunk_proxy_dims) for cfg in cfgs] + _proxies = [self._open_single_proxy(cfg['path'], cfg['global_only'], chunk_proxy_dims) for cfg in cfgs] + proxies = [_p['proxy'] for _p in proxies] + to_close = [_p['to_close'] for _p in _proxies] proxy = xr.concat(proxies, dim=concat_dim) # NB: this only preserves seasonality if years and months are @@ -251,8 +253,8 @@ def open_and_normalize_proxy(self, cfgs, concat_dim='sector', as_flux=True, chun yield normalized finally: - for p in proxies: - p.close() + for f in to_close: + f.close() def output_path(self, name, template, indexes, iter_ids): self.output_dir.mkdir(parents=True, exist_ok=True) From 5b3a50224ab1db321e7fdf870bbad7979a832181 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Wed, 4 Oct 2023 17:23:00 +0200 Subject: [PATCH 63/77] rearrange try except in open_and_normalize, bugfix for getting options from cfgs --- src/aneris/grid.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 39dc193..5fe0699 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -229,12 +229,16 @@ def _open_single_proxy(self, path, global_only=False, chunk_proxy_dims={}): return {'to_close': opened, 'proxy': proxy} @contextmanager - def open_and_normalize_proxy(self, cfgs, concat_dim='sector', as_flux=True, chunk_proxy_dims={}): - try: - _proxies = [self._open_single_proxy(cfg['path'], cfg['global_only'], chunk_proxy_dims) for cfg in cfgs] - proxies = [_p['proxy'] for _p in proxies] - to_close = [_p['to_close'] for _p in _proxies] - proxy = xr.concat(proxies, dim=concat_dim) + def open_and_normalize_proxy(self, cfgs, concat_dim='sector', as_flux=True, chunk_proxy_dims={}): + proxies = [] + to_close = [] + for _, cfg in cfgs.iterrows(): + _p = self._open_single_proxy(cfg['path'], cfg['global_only'], chunk_proxy_dims) + proxies.append(_p['proxy']) + to_close.append(_p['to_close']) + + try: + proxy = xr.concat(proxies, dim=concat_dim) if len(proxies) > 1 else proxies[0] # NB: this only preserves seasonality if years and months are # separate dimensions in the proxy raster. If instead they are @@ -249,7 +253,6 @@ def open_and_normalize_proxy(self, cfgs, concat_dim='sector', as_flux=True, chun pt.cell_area_from_file(proxy) ) normalized = normalized / lat_areas_in_m2 - yield normalized finally: @@ -306,8 +309,8 @@ def grid( for name, cfgs in self.proxy_cfg.groupby('name'): # MJG: needs to change to support multiple rows logger().info("Collecting tasks for proxy %s", name) def _get_unique_opt(cfgs, key): - assert cfgs[key].unique() == 1 - return cfgs[key][0] + assert len(cfgs[key].unique()) == 1, cfgs[key].unique() + return cfgs[key].values[0] opts = {key: _get_unique_opt(cfgs, key) for key in ['template', 'as_flux', 'concat_dim']} with self.open_and_normalize_proxy( @@ -381,6 +384,7 @@ def verify_output(self, name, tabular, gridded, as_flux=True): return verify_global_values(aggregated, tabular, name, self.index) + # MJG: add a callback function here that dresses the dataset in input4MIPS style def compute_output( self, name, From 9e9e9c5166478efce5175e30c8a48b541f0137f4 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Wed, 4 Oct 2023 23:32:36 +0200 Subject: [PATCH 64/77] add fillvalue --- src/aneris/grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 5fe0699..6d4e48c 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -394,7 +394,7 @@ def compute_output( iter_ids, write=True, share_dims=["sector"], - comp=dict(zlib=True, complevel=2), + comp=dict(zlib=True, complevel=2, _FillValue=1e20), ): # TODO: need to add attr definitions and dimension bounds path = self.output_path(name, template, indexes, iter_ids) From 7ab762dbd722b3db082d5bc75cc42126163737c5 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Wed, 4 Oct 2023 23:34:45 +0200 Subject: [PATCH 65/77] fixup pr --- src/aneris/grid.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 6d4e48c..109de46 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -306,10 +306,11 @@ def grid( self.index + [self.country_level] ) ret = [] - for name, cfgs in self.proxy_cfg.groupby('name'): # MJG: needs to change to support multiple rows + for name, cfgs in self.proxy_cfg.groupby('name'): logger().info("Collecting tasks for proxy %s", name) def _get_unique_opt(cfgs, key): - assert len(cfgs[key].unique()) == 1, cfgs[key].unique() + if len(cfgs[key].unique()) != 1: + raise ValueError(f'Non unique config keys {cfgs[key].unique()}') return cfgs[key].values[0] opts = {key: _get_unique_opt(cfgs, key) for key in ['template', 'as_flux', 'concat_dim']} From 894907245561febbc9aa15fe39d3d75fffcc812a Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Thu, 5 Oct 2023 10:35:37 +0200 Subject: [PATCH 66/77] aneris updates for dressing up gridded files --- src/aneris/grid.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 109de46..1fcb557 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -259,11 +259,13 @@ def open_and_normalize_proxy(self, cfgs, concat_dim='sector', as_flux=True, chun for f in to_close: f.close() - def output_path(self, name, template, indexes, iter_ids): + def output_path(self, name, template, indexes, iter_ids, template_kwargs): self.output_dir.mkdir(parents=True, exist_ok=True) ids = {dim: index[0] for dim, index in indexes.items() if len(index) == 1} fname = ( - template.format(name=name, **ids, **iter_ids).replace( + template.format( + name=name.replace('_', '-'), **ids, **iter_ids, **template_kwargs + ).replace( " ", "__" ) + ".nc" @@ -283,9 +285,11 @@ def grid( chunk_proxy_dims: Mapping[str, int] = {}, iter_levels: Sequence[str] = [], write: bool = True, # TODO: make docs - share_dims: Sequence[str] = ["sector"], # TODO: make docs verify_output: bool = False, # TODO: make docs skip_exists: bool = False, # TODO: make docs + template_kwargs={}, + dress_up_callback = None, # TODO: make docs + encoding_kwargs = {}, # TODO: make docs ) -> None: """ Grid data onto configured proxies. @@ -336,7 +340,7 @@ def _get_unique_opt(cfgs, key): ) data = DataArray.from_series(single_tabular) - if skip_exists and self.output_path(name, opts["template"], data.indexes, iter_ids).exists(): + if skip_exists and self.output_path(name, opts["template"], data.indexes, iter_ids, template_kwargs).exists(): logger().info("File exists, skipping tasks for %s", iter_ids) continue @@ -355,8 +359,10 @@ def _get_unique_opt(cfgs, key): gridded, data.indexes, iter_ids, + template_kwargs=template_kwargs, write=write, - share_dims=share_dims, + callback=dress_up_callback, + encoding_kwargs=encoding_kwargs, ) ) @@ -394,17 +400,21 @@ def compute_output( indexes, iter_ids, write=True, - share_dims=["sector"], - comp=dict(zlib=True, complevel=2, _FillValue=1e20), + callback=None, + template_kwargs={}, + encoding_kwargs={}, ): # TODO: need to add attr definitions and dimension bounds - path = self.output_path(name, template, indexes, iter_ids) + path = self.output_path(name, template, indexes, iter_ids, template_kwargs) logger().info(f"Writing to {path}") + ids = {dim: index[0] for dim, index in indexes.items() if len(index) == 1} gridded = gridded.to_dataset(name=name) + if callback: + gridded = callback(gridded, **ids, **iter_ids, **template_kwargs) if write: return gridded.to_netcdf( - path, compute=False, encoding={name: comp} + path, compute=False, encoding={name: encoding_kwargs, 'time': dict(calendar='noleap')}, ) else: return gridded From 3dd850a008ed52479faac09c72e1e331643017f5 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Thu, 5 Oct 2023 10:44:38 +0200 Subject: [PATCH 67/77] remove template kwargs --- src/aneris/grid.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 1fcb557..10982e5 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -259,12 +259,12 @@ def open_and_normalize_proxy(self, cfgs, concat_dim='sector', as_flux=True, chun for f in to_close: f.close() - def output_path(self, name, template, indexes, iter_ids, template_kwargs): + def output_path(self, name, template, indexes, iter_ids): self.output_dir.mkdir(parents=True, exist_ok=True) ids = {dim: index[0] for dim, index in indexes.items() if len(index) == 1} fname = ( template.format( - name=name.replace('_', '-'), **ids, **iter_ids, **template_kwargs + name=name.replace('_', '-'), **ids, **iter_ids, ).replace( " ", "__" ) @@ -287,7 +287,6 @@ def grid( write: bool = True, # TODO: make docs verify_output: bool = False, # TODO: make docs skip_exists: bool = False, # TODO: make docs - template_kwargs={}, dress_up_callback = None, # TODO: make docs encoding_kwargs = {}, # TODO: make docs ) -> None: @@ -340,7 +339,7 @@ def _get_unique_opt(cfgs, key): ) data = DataArray.from_series(single_tabular) - if skip_exists and self.output_path(name, opts["template"], data.indexes, iter_ids, template_kwargs).exists(): + if skip_exists and self.output_path(name, opts["template"], data.indexes, iter_ids).exists(): logger().info("File exists, skipping tasks for %s", iter_ids) continue @@ -359,7 +358,6 @@ def _get_unique_opt(cfgs, key): gridded, data.indexes, iter_ids, - template_kwargs=template_kwargs, write=write, callback=dress_up_callback, encoding_kwargs=encoding_kwargs, @@ -401,17 +399,16 @@ def compute_output( iter_ids, write=True, callback=None, - template_kwargs={}, encoding_kwargs={}, ): # TODO: need to add attr definitions and dimension bounds - path = self.output_path(name, template, indexes, iter_ids, template_kwargs) + path = self.output_path(name, template, indexes, iter_ids) logger().info(f"Writing to {path}") ids = {dim: index[0] for dim, index in indexes.items() if len(index) == 1} gridded = gridded.to_dataset(name=name) if callback: - gridded = callback(gridded, **ids, **iter_ids, **template_kwargs) + gridded = callback(gridded, **ids, **iter_ids) if write: return gridded.to_netcdf( path, compute=False, encoding={name: encoding_kwargs, 'time': dict(calendar='noleap')}, From 33da47aceba115817063fbf66b1430cea4e66df8 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Thu, 5 Oct 2023 11:10:09 +0200 Subject: [PATCH 68/77] blacked --- src/aneris/grid.py | 80 +++++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 10982e5..6ec13f2 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -190,9 +190,8 @@ def get_index(dim): index = MultiIndex.from_product([get_index(dim) for dim in self.index]) missing_from_data = index.difference(data_index) if not missing_from_data.empty: - msg = ( - f"Proxy '{proxy_cfg.path.stem}' has values missing from `data`:\n" - + missing_from_data.to_frame().to_string(index=False) + msg = f"Proxy '{proxy_cfg.path.stem}' has values missing from `data`:\n" + missing_from_data.to_frame().to_string( + index=False ) if strict_proxy_data: raise MissingCoordinateValue(msg) @@ -212,7 +211,6 @@ def concat(objs): + missing_from_proxy.to_frame().to_string(index=False) ) - def _open_single_proxy(self, path, global_only=False, chunk_proxy_dims={}): opened = xr.open_dataarray( path, @@ -226,27 +224,31 @@ def _open_single_proxy(self, path, global_only=False, chunk_proxy_dims={}): # TODO: this maybe isn't needed anymore with 'World' included in idxraster # but need to confirm 'World' is also in the proxy rasters proxy = opened if global_only else self.idxraster * opened - return {'to_close': opened, 'proxy': proxy} + return {"to_close": opened, "proxy": proxy} @contextmanager - def open_and_normalize_proxy(self, cfgs, concat_dim='sector', as_flux=True, chunk_proxy_dims={}): + def open_and_normalize_proxy( + self, cfgs, concat_dim="sector", as_flux=True, chunk_proxy_dims={} + ): proxies = [] to_close = [] for _, cfg in cfgs.iterrows(): - _p = self._open_single_proxy(cfg['path'], cfg['global_only'], chunk_proxy_dims) - proxies.append(_p['proxy']) - to_close.append(_p['to_close']) + _p = self._open_single_proxy( + cfg["path"], cfg["global_only"], chunk_proxy_dims + ) + proxies.append(_p["proxy"]) + to_close.append(_p["to_close"]) try: - proxy = xr.concat(proxies, dim=concat_dim) if len(proxies) > 1 else proxies[0] + proxy = ( + xr.concat(proxies, dim=concat_dim) if len(proxies) > 1 else proxies[0] + ) # NB: this only preserves seasonality if years and months are # separate dimensions in the proxy raster. If instead they are # combined into a single 'time' dimension, seasonality is lost. sum_spatial_dims = list(set(proxy.dims).intersection(self.spatial_dims)) - normalized = proxy / proxy.mean(self.mean_time_dims).sum( - sum_spatial_dims - ) + normalized = proxy / proxy.mean(self.mean_time_dims).sum(sum_spatial_dims) if as_flux: lat_areas_in_m2 = xr.DataArray.from_series( @@ -264,10 +266,10 @@ def output_path(self, name, template, indexes, iter_ids): ids = {dim: index[0] for dim, index in indexes.items() if len(index) == 1} fname = ( template.format( - name=name.replace('_', '-'), **ids, **iter_ids, - ).replace( - " ", "__" - ) + name=name.replace("_", "-"), + **ids, + **iter_ids, + ).replace(" ", "__") + ".nc" ) return self.output_dir / fname @@ -286,9 +288,9 @@ def grid( iter_levels: Sequence[str] = [], write: bool = True, # TODO: make docs verify_output: bool = False, # TODO: make docs - skip_exists: bool = False, # TODO: make docs - dress_up_callback = None, # TODO: make docs - encoding_kwargs = {}, # TODO: make docs + skip_exists: bool = False, # TODO: make docs + dress_up_callback=None, # TODO: make docs + encoding_kwargs={}, # TODO: make docs ) -> None: """ Grid data onto configured proxies. @@ -309,20 +311,25 @@ def grid( self.index + [self.country_level] ) ret = [] - for name, cfgs in self.proxy_cfg.groupby('name'): + for name, cfgs in self.proxy_cfg.groupby("name"): logger().info("Collecting tasks for proxy %s", name) + def _get_unique_opt(cfgs, key): if len(cfgs[key].unique()) != 1: - raise ValueError(f'Non unique config keys {cfgs[key].unique()}') + raise ValueError(f"Non unique config keys {cfgs[key].unique()}") return cfgs[key].values[0] - opts = {key: _get_unique_opt(cfgs, key) for key in ['template', 'as_flux', 'concat_dim']} - + + opts = { + key: _get_unique_opt(cfgs, key) + for key in ["template", "as_flux", "concat_dim"] + } + with self.open_and_normalize_proxy( - cfgs, - concat_dim=opts["concat_dim"], - as_flux=opts["as_flux"], + cfgs, + concat_dim=opts["concat_dim"], + as_flux=opts["as_flux"], chunk_proxy_dims=chunk_proxy_dims, - ) as proxy: + ) as proxy: write_tasks = [] proxy_index = MultiIndex.from_product( @@ -339,7 +346,12 @@ def _get_unique_opt(cfgs, key): ) data = DataArray.from_series(single_tabular) - if skip_exists and self.output_path(name, opts["template"], data.indexes, iter_ids).exists(): + if ( + skip_exists + and self.output_path( + name, opts["template"], data.indexes, iter_ids + ).exists() + ): logger().info("File exists, skipping tasks for %s", iter_ids) continue @@ -348,12 +360,14 @@ def _get_unique_opt(cfgs, key): if verify_output: write_tasks.append( - self.verify_output(name, single_tabular, gridded, as_flux=opts["as_flux"]) + self.verify_output( + name, single_tabular, gridded, as_flux=opts["as_flux"] + ) ) if write: write_tasks.append( self.compute_output( - name, + name, opts["template"], gridded, data.indexes, @@ -411,7 +425,9 @@ def compute_output( gridded = callback(gridded, **ids, **iter_ids) if write: return gridded.to_netcdf( - path, compute=False, encoding={name: encoding_kwargs, 'time': dict(calendar='noleap')}, + path, + compute=False, + encoding={name: encoding_kwargs, "time": dict(calendar="noleap")}, ) else: return gridded From aafde73c2f03c05b3125941161e90e262e06c624 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Thu, 5 Oct 2023 11:17:55 +0200 Subject: [PATCH 69/77] Update src/aneris/grid.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jonas Hörsch --- src/aneris/grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index 6ec13f2..d52cd19 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -427,7 +427,7 @@ def compute_output( return gridded.to_netcdf( path, compute=False, - encoding={name: encoding_kwargs, "time": dict(calendar="noleap")}, + encoding={name: encoding_kwargs}, ) else: return gridded From d262217efdea9ed40047ab376845000505723f60 Mon Sep 17 00:00:00 2001 From: Matthew Gidden Date: Thu, 5 Oct 2023 11:18:01 +0200 Subject: [PATCH 70/77] Update src/aneris/grid.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jonas Hörsch --- src/aneris/grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aneris/grid.py b/src/aneris/grid.py index d52cd19..c4ac5f2 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -316,7 +316,7 @@ def grid( def _get_unique_opt(cfgs, key): if len(cfgs[key].unique()) != 1: - raise ValueError(f"Non unique config keys {cfgs[key].unique()}") + raise ValueError(f"Non unique config keys for {name}: {cfgs[key].unique()}") return cfgs[key].values[0] opts = { From d851f668c439e9e1b3ddd7db84e849f0b712fb39 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Tue, 3 Oct 2023 18:15:13 +0200 Subject: [PATCH 71/77] Loosen downscaling check thresholds --- src/aneris/downscaling/core.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index d23c27f..314429a 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -211,7 +211,7 @@ def downscale( return self.return_type(downscaled) - def check_downscaled(self, downscaled, rtol=1e-05, atol=1e-08): + def check_downscaled(self, downscaled, rtol=1e-02, atol=1e-06): def warn_if_differences(actual, should, message): actual, should = actual.align(should, join="left") diff = actual - should @@ -231,7 +231,7 @@ def warn_if_differences(actual, should, message): .rename_axis(columns="year") .stack() ) - model = self.model.loc[:, self.year:].rename_axis(columns="year").stack() + model = self.model.loc[:, self.year :].rename_axis(columns="year").stack() warn_if_differences( downscaled_region, @@ -243,11 +243,18 @@ def warn_if_differences(actual, should, message): if isinstance(hist, DataFrame): hist = hist.loc[:, self.year] hist = hist.pix.semijoin(downscaled.index, how="right") + non_zero_region = ( + abs(hist) + .groupby(hist.index.names.difference(["region"])) + .max() + .loc[lambda s: s > 0] + .index + ) downscaled_start = downscaled.loc[:, self.year] warn_if_differences( - downscaled_start, - hist, + downscaled_start.pix.semijoin(non_zero_region, how="right"), + hist.pix.semijoin(non_zero_region, how="right"), "Downscaled trajectories do not start from history", ) From f86527c6a3bcc9f59b0e4090d96fad2814fd29c6 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Fri, 24 Nov 2023 11:34:49 +0100 Subject: [PATCH 72/77] Cope with empty methods better --- src/aneris/downscaling/intensity_convergence.py | 6 +++--- src/aneris/methods.py | 3 ++- src/aneris/utils.py | 4 ++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/aneris/downscaling/intensity_convergence.py b/src/aneris/downscaling/intensity_convergence.py index f7630e0..613bed0 100644 --- a/src/aneris/downscaling/intensity_convergence.py +++ b/src/aneris/downscaling/intensity_convergence.py @@ -8,7 +8,7 @@ from scipy.interpolate import interp1d from scipy.optimize import root_scalar -from ..utils import normalize +from ..utils import normalize, skipempty from .data import DownscalingContext @@ -454,11 +454,11 @@ def intensity_convergence( exponential_intensity_projection = empty_intensity intensity_projection = concat( - [ + skipempty( exponential_intensity_projection, negative_intensity_projection, intensity_projection_linear, - ], + ), sort=False, ).reindex(index=intensity_idx) diff --git a/src/aneris/methods.py b/src/aneris/methods.py index c5f55e1..7d14286 100644 --- a/src/aneris/methods.py +++ b/src/aneris/methods.py @@ -386,7 +386,8 @@ def coeff_of_var(s): coefficient of variation """ x = np.diff(s.values) - return np.abs(np.std(x) / np.mean(x)) + with np.errstate(invalid="ignore"): + return np.abs(np.std(x) / np.mean(x)) def default_method_choice( diff --git a/src/aneris/utils.py b/src/aneris/utils.py index 3a3fd93..2d5b109 100644 --- a/src/aneris/utils.py +++ b/src/aneris/utils.py @@ -110,3 +110,7 @@ def normalize(s): def country_name(iso: str): country_obj = pycountry.countries.get(alpha_3=iso) return iso if country_obj is None else country_obj.name + + +def skipempty(*dfs): + return [df for df in dfs if not df.empty] \ No newline at end of file From a2f1591cc9e52e96f9765608215e81bff7a9b6ea Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Thu, 22 Feb 2024 17:48:25 +0100 Subject: [PATCH 73/77] Blackify --- src/aneris/_io.py | 1 + src/aneris/cli.py | 1 + src/aneris/grid.py | 4 +++- src/aneris/utils.py | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/aneris/_io.py b/src/aneris/_io.py index 0134922..b3192db 100644 --- a/src/aneris/_io.py +++ b/src/aneris/_io.py @@ -3,6 +3,7 @@ The default configuration values are provided in aneris.RC_DEFAULTS. """ + import os from collections import abc diff --git a/src/aneris/cli.py b/src/aneris/cli.py index 13e964a..855b9ac 100644 --- a/src/aneris/cli.py +++ b/src/aneris/cli.py @@ -1,6 +1,7 @@ """ Harmonization CLI for aneris. """ + import argparse import os diff --git a/src/aneris/grid.py b/src/aneris/grid.py index c4ac5f2..83f5c0a 100644 --- a/src/aneris/grid.py +++ b/src/aneris/grid.py @@ -316,7 +316,9 @@ def grid( def _get_unique_opt(cfgs, key): if len(cfgs[key].unique()) != 1: - raise ValueError(f"Non unique config keys for {name}: {cfgs[key].unique()}") + raise ValueError( + f"Non unique config keys for {name}: {cfgs[key].unique()}" + ) return cfgs[key].values[0] opts = { diff --git a/src/aneris/utils.py b/src/aneris/utils.py index 2d5b109..d29ed24 100644 --- a/src/aneris/utils.py +++ b/src/aneris/utils.py @@ -113,4 +113,4 @@ def country_name(iso: str): def skipempty(*dfs): - return [df for df in dfs if not df.empty] \ No newline at end of file + return [df for df in dfs if not df.empty] From 1cec507343f55da51f3079b42d1d10a16076eeef Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Thu, 22 Feb 2024 17:52:40 +0100 Subject: [PATCH 74/77] Update pyproject.toml ruff settings --- pyproject.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c3d4f52..8cf8d6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,6 +87,8 @@ exclude = [ "doc", "_typed_ops.pyi", ] + +[tool.ruff.lint] # E402: module level import not at top of file # E501: line too long - let black worry about that # E731: do not assign a lambda expression, use a def @@ -109,11 +111,11 @@ select = [ "UP", ] -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] # F401: imported but unsued "__init__.py" = ["F401"] -[tool.ruff.isort] +[tool.ruff.lint.isort] lines-after-imports = 2 known-first-party = ["aneris"] From 89df851e266a4d046e536058ac63fd131451143d Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Tue, 14 May 2024 09:42:15 +0200 Subject: [PATCH 75/77] enh(downscaling): Switch downscaling regionmap to MultiIndex --- src/aneris/downscaling/core.py | 21 +++++++------- src/aneris/downscaling/data.py | 29 ++++++++++++++----- .../downscaling/intensity_convergence.py | 4 +-- src/aneris/downscaling/methods.py | 6 ++-- 4 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index 314429a..3e29345 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -1,8 +1,8 @@ from functools import partial -from typing import Optional, Sequence +from typing import Optional, Sequence, Union import pandas_indexing.accessors # noqa: F401 -from pandas import DataFrame, Series +from pandas import DataFrame, MultiIndex, Series from pandas_indexing import concat, semijoin from ..errors import MissingHistoricalError, MissingProxyError @@ -43,7 +43,7 @@ def __init__( model: DataFrame, hist: DataFrame, year: int, - region_mapping: Series, + region_mapping: Union[Series, MultiIndex], luc_sectors: Sequence[str] = [], index: Sequence[str] = DEFAULT_INDEX, method_choice: Optional[callable] = None, @@ -53,13 +53,12 @@ def __init__( self.model = model self.hist = hist self.return_type = return_type + regionmap = DownscalingContext.to_regionmap(region_mapping) self.context = DownscalingContext( index, year, - region_mapping, + regionmap, additional_data, - country_level=region_mapping.index.name, - region_level=region_mapping.name, ) assert ( @@ -67,7 +66,7 @@ def __init__( ).all(), "Ambiguous history" missing_hist = ( - model.index.join(self.context.regionmap_index, how="left") + model.index.join(self.context.regionmap, how="left") .pix.project(list(index) + [self.country_level]) .difference(hist.index.pix.project(list(index) + [self.country_level])) ) @@ -93,7 +92,7 @@ def year(self): return self.context.year @property - def region_mapping(self): + def region_mapping(self) -> MultiIndex: return self.context.regionmap @property @@ -141,7 +140,7 @@ def check_proxies(self, methods: Series) -> None: # trajectory index typically has the levels model, scenario, region, sector, # gas, while proxy data is expected on country level (and probably no model, # scenario dependency, but potentially) - proxy = semijoin(proxy, self.context.regionmap_index, how="right") + proxy = semijoin(proxy, self.context.regionmap, how="right") common_levels = [ lvl for lvl in trajectory_index.names if lvl in proxy.index.names @@ -194,7 +193,7 @@ def downscale( if methods is None: methods = self.methods() - hist_ext = semijoin(self.hist, self.context.regionmap_index, how="right") + hist_ext = semijoin(self.hist, self.context.regionmap, how="right") self.check_proxies(methods) downscaled = [] @@ -274,7 +273,7 @@ def methods(self, method_choice=None, overwrites=None): } hist_agg = ( - semijoin(self.hist, self.context.regionmap_index, how="right") + semijoin(self.hist, self.context.regionmap, how="right") .groupby(list(self.index) + [self.region_level], dropna=False) .sum() ) diff --git a/src/aneris/downscaling/data.py b/src/aneris/downscaling/data.py index c6c2766..d29eca7 100644 --- a/src/aneris/downscaling/data.py +++ b/src/aneris/downscaling/data.py @@ -16,10 +16,14 @@ class DownscalingContext: index levels that differentiate trajectories year : int base year for downscaling - regionmap : Series - map from countries to regions + regionmap : MultiIndex + map from fine to coarse level + (there can be overlapping coarse levels) additional_data : dict, default {} named `DataFrame`s or `Series` the methods need as proxies + + Derived attributes + ------------------- country_level : str, default "country" name of the fine index level region_level : str, default "region" @@ -32,14 +36,23 @@ class DownscalingContext: index: Sequence[str] year: int - regionmap: Series + regionmap: MultiIndex additional_data: dict[str, Union[Series, DataFrame]] = field(default_factory=dict) - country_level: str = "country" - region_level: str = "region" @property - def regionmap_index(self): + def country_level(self) -> str: + return self.regionmap.names[0] + + @property + def region_level(self) -> str: + return self.regionmap.names[1] + + @staticmethod + def to_regionmap(region_mapping: Union[Series, MultiIndex]): + if isinstance(region_mapping, MultiIndex): + return region_mapping + return MultiIndex.from_arrays( - [self.regionmap.index, self.regionmap.values], - names=[self.country_level, self.region_level], + [region_mapping.index, region_mapping.values], + names=[region_mapping.index.name, region_mapping.name], ) diff --git a/src/aneris/downscaling/intensity_convergence.py b/src/aneris/downscaling/intensity_convergence.py index 613bed0..8036efe 100644 --- a/src/aneris/downscaling/intensity_convergence.py +++ b/src/aneris/downscaling/intensity_convergence.py @@ -387,11 +387,11 @@ def intensity_convergence( if isinstance(hist, DataFrame): hist = hist.loc[:, context.year] - reference = semijoin(context.additional_data[proxy_name], context.regionmap_index)[ + reference = semijoin(context.additional_data[proxy_name], context.regionmap)[ model.columns ] reference_region = reference.groupby(context.region_level).sum() - hist = semijoin(hist, context.regionmap_index) + hist = semijoin(hist, context.regionmap) intensity = compute_intensity(model, reference_region, convergence_year) intensity_hist = hist / reference.iloc[:, 0] diff --git a/src/aneris/downscaling/methods.py b/src/aneris/downscaling/methods.py index 7c65e4c..be36b7a 100644 --- a/src/aneris/downscaling/methods.py +++ b/src/aneris/downscaling/methods.py @@ -50,7 +50,7 @@ def base_year_pattern( hist = hist.loc[:, context.year] weights = ( - semijoin(hist, context.regionmap_index, how="right") + semijoin(hist, context.regionmap, how="right") .groupby(model.index.names, dropna=False) .transform(normalize) ) @@ -96,7 +96,7 @@ def simple_proxy( proxy_data = context.additional_data[proxy_name] common_levels = [lvl for lvl in model.index.names if lvl in proxy_data.index.names] weights = ( - semijoin(proxy_data, context.regionmap_index)[model.columns] + semijoin(proxy_data, context.regionmap)[model.columns] .groupby(common_levels + [context.region_level], dropna=False) .transform(normalize) ) @@ -148,7 +148,7 @@ def growth_rate( weights = ( cumulative_growth_rates.pix.multiply( - semijoin(hist, context.regionmap_index, how="right"), + semijoin(hist, context.regionmap, how="right"), join="left", ) .groupby(model.index.names, dropna=False) From 08b95d96299faefc5df8d8331503a51e3399b633 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Fri, 23 Aug 2024 17:09:07 +0200 Subject: [PATCH 76/77] Make compatible with pyarrow-backed DataFrames --- src/aneris/_io.py | 2 +- src/aneris/cmip6/driver.py | 2 +- src/aneris/convenience.py | 10 +++++----- src/aneris/downscaling/data.py | 4 ++-- .../downscaling/intensity_convergence.py | 20 ++++++++++--------- src/aneris/methods.py | 2 +- tests/test_harmonize.py | 2 +- 7 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/aneris/_io.py b/src/aneris/_io.py index b3192db..6614996 100644 --- a/src/aneris/_io.py +++ b/src/aneris/_io.py @@ -90,7 +90,7 @@ def read_excel(f): # a single row of nans implies only configs provided, # if so, only return the empty df - if len(overrides) == 1 and overrides.isnull().values.all(): + if len(overrides) == 1 and overrides.isnull().all(axis=None): overrides = pd.DataFrame([], columns=iamc_idx + ["Unit"]) return model, overrides, config diff --git a/src/aneris/cmip6/driver.py b/src/aneris/cmip6/driver.py index 0f6a067..da801e3 100644 --- a/src/aneris/cmip6/driver.py +++ b/src/aneris/cmip6/driver.py @@ -421,7 +421,7 @@ def _harmonize_regions( model, mapping=mapping, rfrom="Native Region Code", rto="5_region" ) model = pd.concat([model, aggdf]) - assert not model.isnull().values.any() + assert not model.isnull().any(axis=None) # duplicates come in from World and World being translated duplicates = model.index.duplicated(keep="first") diff --git a/src/aneris/convenience.py b/src/aneris/convenience.py index 18fa604..6f851a2 100644 --- a/src/aneris/convenience.py +++ b/src/aneris/convenience.py @@ -26,7 +26,7 @@ def xform(x): units = xform(to).join(xform(fr), how="left", lsuffix="_to", rsuffix="_fr") # can get duplicates if multiple regions with same conversion units = units[~units.index.duplicated(keep="first")] - assert not units.isnull().values.any() + assert not units.isnull().any(axis=None) # downselect to non-comparable units = units[units.unit_to != units.unit_fr] # combine units that don't need changing with those that do @@ -61,7 +61,7 @@ def _knead_overrides(overrides, scen, harm_idx): # check if no index and single value - this should be the override for everything if overrides.index.names == [None] and len(overrides["method"]) == 1: _overrides = pd.Series( - overrides["method"].values[0], + overrides["method"].iloc[0], index=pd.Index(scen.region, name=harm_idx[-1]), # only need to match 1 dim name="method", ) @@ -78,12 +78,12 @@ def _knead_overrides(overrides, scen, harm_idx): _overrides = overrides # do checks - if _overrides.isnull().values.any(): - missing = _overrides[_overrides.isnull().any(axis=1)] + if isinstance(_overrides, pd.DataFrame) and _overrides.isnull().any(axis=None): + missing = _overrides.loc[_overrides.isnull().any(axis=1)] raise AmbiguousHarmonisationMethod( f"Overrides are missing for provided data:\n" f"{missing}" ) - if _overrides.index.to_frame().isnull().values.any(): + if _overrides.index.to_frame().isnull().any(axis=None): missing = _overrides[_overrides.index.to_frame().isnull().any(axis=1)] raise AmbiguousHarmonisationMethod( f"Defined overrides are missing data:\n" f"{missing}" diff --git a/src/aneris/downscaling/data.py b/src/aneris/downscaling/data.py index d29eca7..a4ff0f2 100644 --- a/src/aneris/downscaling/data.py +++ b/src/aneris/downscaling/data.py @@ -1,4 +1,4 @@ -from collections.abc import Sequence +from collections.abc import Mapping, Sequence from dataclasses import dataclass, field from typing import Union @@ -37,7 +37,7 @@ class DownscalingContext: index: Sequence[str] year: int regionmap: MultiIndex - additional_data: dict[str, Union[Series, DataFrame]] = field(default_factory=dict) + additional_data: Mapping[str, Union[Series, DataFrame]] = field(default_factory=dict) @property def country_level(self) -> str: diff --git a/src/aneris/downscaling/intensity_convergence.py b/src/aneris/downscaling/intensity_convergence.py index 8036efe..7bf6891 100644 --- a/src/aneris/downscaling/intensity_convergence.py +++ b/src/aneris/downscaling/intensity_convergence.py @@ -246,6 +246,8 @@ def negative_exponential_intensity_model( gammas_conv = semijoin(gammas, intensity_conv.index, how="right") def ts(s): + if isinstance(s, (DataFrame, Series)): + s = s.to_numpy() return np.asarray(s)[:, np.newaxis] f, inv_f = make_affine_transform_pair( @@ -257,8 +259,8 @@ def ts(s): intensity_projection = DataFrame( inv_f( ( - (f(ts(intensity_conv.values[:, -1])) / f(ts(intensity_hist_conv))) - ** alpha.values + (f(ts(intensity_conv.to_numpy()[:, -1])) / f(ts(intensity_hist_conv))) + ** alpha.to_numpy() ) * f(ts(intensity_hist_conv)) ), @@ -289,9 +291,9 @@ def exponential_intensity_model( intensity_projection = inv_f( DataFrame( - (f(intensity.iloc[:, -1]) / f(intensity_hist)).values[:, np.newaxis] - ** alpha.values - * f(intensity_hist).values[:, np.newaxis], + (f(intensity.iloc[:, -1]) / f(intensity_hist)).to_numpy()[:, np.newaxis] + ** alpha.to_numpy() + * f(intensity_hist).to_numpy()[:, np.newaxis], index=intensity_hist.index, columns=intensity.columns, ), @@ -307,8 +309,8 @@ def linear_intensity_model( intensity_hist, join="left", copy=False, axis=0 ) intensity_projection = DataFrame( - (1 - alpha).values * intensity_hist.values[:, np.newaxis] - + alpha.values * intensity.values[:, -1:], + (1 - alpha).to_numpy() * (intensity_hist).to_numpy()[:, np.newaxis] + + alpha.to_numpy() * intensity.to_numpy()[:, -1:], index=intensity.index, columns=intensity.columns, ) @@ -330,9 +332,9 @@ def intensity_growth_rate_model( 1 + (intensity.iloc[:, -1] / intensity_hist - 1) / (years_downscaling[-1] - years_downscaling[0]) - ).values[:, np.newaxis] + ).to_numpy()[:, np.newaxis] ** np.arange(0, len(years_downscaling)) - * intensity_hist.values[:, np.newaxis], + * intensity_hist.to_numpy()[:, np.newaxis], index=intensity_hist.index, columns=years_downscaling.rename("year"), ).where(intensity_hist != 0, 0.0) diff --git a/src/aneris/methods.py b/src/aneris/methods.py index 7d14286..ac58072 100644 --- a/src/aneris/methods.py +++ b/src/aneris/methods.py @@ -385,7 +385,7 @@ def coeff_of_var(s): c_v : float coefficient of variation """ - x = np.diff(s.values) + x = np.diff(s.to_numpy()) with np.errstate(invalid="ignore"): return np.abs(np.std(x) / np.mean(x)) diff --git a/tests/test_harmonize.py b/tests/test_harmonize.py index 44c6796..5dd1c0f 100644 --- a/tests/test_harmonize.py +++ b/tests/test_harmonize.py @@ -287,7 +287,7 @@ def test_harmonize_budget(): def _carbon_budget(emissions): # trapezoid rule dyears = np.diff(emissions.columns.astype(int)) - emissions = emissions.values + emissions = emissions.to_numpy() demissions = np.diff(emissions, axis=1) budget = (dyears * (emissions[:, :-1] + demissions / 2)).sum(axis=1) From 14729ae4a73bb16bd0898503c044225912621d38 Mon Sep 17 00:00:00 2001 From: Jonas Hoersch Date: Fri, 23 Aug 2024 17:10:14 +0200 Subject: [PATCH 77/77] Update pandas-indexing --- pyproject.toml | 2 +- src/aneris/downscaling/core.py | 1 - src/aneris/downscaling/intensity_convergence.py | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8cf8d6e..cfb79ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ dependencies = [ "openpyxl", "matplotlib", "pyomo>=5", - "pandas-indexing>=0.2.7", + "pandas-indexing>=0.4.0", "pycountry", ] dynamic = ["version"] diff --git a/src/aneris/downscaling/core.py b/src/aneris/downscaling/core.py index 3e29345..ff7c32a 100644 --- a/src/aneris/downscaling/core.py +++ b/src/aneris/downscaling/core.py @@ -1,7 +1,6 @@ from functools import partial from typing import Optional, Sequence, Union -import pandas_indexing.accessors # noqa: F401 from pandas import DataFrame, MultiIndex, Series from pandas_indexing import concat, semijoin diff --git a/src/aneris/downscaling/intensity_convergence.py b/src/aneris/downscaling/intensity_convergence.py index 7bf6891..2babd64 100644 --- a/src/aneris/downscaling/intensity_convergence.py +++ b/src/aneris/downscaling/intensity_convergence.py @@ -39,7 +39,7 @@ def make_affine_transform_pair(x1, x2, y1, y2): def compute_intensity( model: DataFrame, reference: DataFrame, convergence_year: int ) -> DataFrame: - intensity = model.idx.divide(reference, join="left") + intensity = model.pix.divide(reference, join="left") model_years = model.columns if convergence_year > model_years[-1]: @@ -474,7 +474,7 @@ def intensity_convergence( ) weights = ( - intensity_projection.idx.multiply(reference, join="left") + intensity_projection.pix.multiply(reference, join="left") .groupby(model.index.names, dropna=False) .transform(normalize) )