From 4c50b799fbf52678940fbdd5e47aabfd26cce408 Mon Sep 17 00:00:00 2001 From: Ian Bolliger Date: Wed, 3 Apr 2024 04:09:11 +0000 Subject: [PATCH] update to SLIIDERS v1.2 --- HISTORY.rst | 5 +- .../models/create-surge-lookup-tables.ipynb | 136 ++++----- notebooks/models/fit-movefactor.ipynb | 210 ++++++------- .../models/run-pyCIAM-slrquantiles.ipynb | 30 +- notebooks/post-processing/zenodo-upload.ipynb | 278 +++++++++++------- notebooks/shared.py | 119 ++++---- pyCIAM/io.py | 28 +- pyCIAM/run.py | 66 +++-- pyCIAM/surge/__init__.py | 3 +- pyCIAM/surge/_calc.py | 8 +- pyCIAM/surge/damage_funcs.py | 7 +- pyCIAM/surge/lookup.py | 8 +- pyCIAM/utils.py | 22 +- 13 files changed, 501 insertions(+), 419 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 23d138e..4d32d89 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,11 +1,12 @@ History ======= -v1.2 (unreleased) -------------------- +v1.2.0 +------ * Point `data-acquisition.ipynb` to updated Zenodo deposit that fixes the dtype of `subsets` variable in `diaz2016_inputs_raw.zarr.zip` to be bool rather than int8 * Variable name bugfix in `data-acquisition.ipynb` * Add netcdf versions of SLIIDERS and the pyCIAM results to `upload-zenodo.ipynb` +* Update results in Zenodo record to use SLIIDERS v1.2 v1.1.2 ------ diff --git a/notebooks/models/create-surge-lookup-tables.ipynb b/notebooks/models/create-surge-lookup-tables.ipynb index 6d250e4..6568d90 100644 --- a/notebooks/models/create-surge-lookup-tables.ipynb +++ b/notebooks/models/create-surge-lookup-tables.ipynb @@ -30,8 +30,23 @@ { "cell_type": "code", "execution_count": 1, + "id": "6b183aa3-366a-4f5f-bb95-5ef4bf48d438", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": 2, "id": "cd4b2928-65a0-4733-9c71-fbefa85590be", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "import sys\n", @@ -41,16 +56,26 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "id": "afd03880-8e46-4d81-867d-bfb6505ea788", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/srv/conda/envs/notebook/lib/python3.9/site-packages/dask_gateway/client.py:21: FutureWarning: format_bytes is deprecated and will be removed in a future release. Please use dask.utils.format_bytes instead.\n", - " from distributed.utils import LoopRunner, format_bytes\n" + "/srv/conda/envs/notebook/lib/python3.10/site-packages/google/cloud/storage/transfer_manager.py:30: UserWarning: The module `transfer_manager` is a preview feature. Functionality and API may change. This warning will be removed in a future release.\n", + " warnings.warn(\n", + "/home/jovyan/git-repos/pyCIAM-public/notebooks/models/../shared.py:3: UserWarning: Shapely 2.0 is installed, but because PyGEOS is also installed, GeoPandas will still use PyGEOS by default for now. To force to use and test Shapely 2.0, you have to set the environment variable USE_PYGEOS=0. You can do this before starting the Python process, or in your code before importing geopandas:\n", + "\n", + "import os\n", + "os.environ['USE_PYGEOS'] = '0'\n", + "import geopandas\n", + "\n", + "In a future release, GeoPandas will switch to using Shapely by default. If you are using PyGEOS directly (calling PyGEOS functions on geometries from GeoPandas), this will then stop working and you are encouraged to migrate from PyGEOS to Shapely 2.0 (https://shapely.readthedocs.io/en/latest/migration_pygeos.html).\n", + " import geopandas as gpd\n" ] } ], @@ -75,7 +100,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "47979c48-7fff-49b4-b445-ea6bf746fa37", "metadata": { "tags": [ @@ -86,8 +111,8 @@ "source": [ "# When running on larger/scalable dask cluster, may wish to specify number of workers\n", "# Default is LocalCluster which will use the number of CPUs available on local machine\n", - "# N_WORKERS_MIN = 7\n", - "# N_WORKERS_MAX = 700\n", + "N_WORKERS_MIN = 7\n", + "N_WORKERS_MAX = 700\n", "SEG_CHUNKSIZE = 5\n", "\n", "PARAMS = pd.read_json(PATH_PARAMS)[\"values\"]" @@ -95,9 +120,11 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "id": "6104bced", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "DMF_I = getattr(damage_funcs, PARAMS.dmf + \"_i\")\n", @@ -106,70 +133,31 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "id": "dbb04b4a-14b8-4403-ad33-88bfe71bd8fc", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [ { "data": { - "text/html": [ - "
\n", - "
\n", - "
\n", - "

Client

\n", - "

Client-f992a2c6-c6d1-11ed-862e-665816eadc72

\n", - " \n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n", - "
Connection method: Cluster objectCluster type: dask_gateway.GatewayCluster
\n", - " Dashboard: /services/dask-gateway/clusters/daskhub-dev.e0f56d1ca0ae4a42b9352ad6b7204454/status\n", - "
\n", - "\n", - " \n", - "
\n", - "

Cluster Info

\n", - "
\n", - "

GatewayCluster

\n", - " \n", - "
\n", - "\n", - "
\n", - " \n", - "\n", - "
\n", - "
" - ], + "application/vnd.jupyter.widget-view+json": { + "model_id": "fcadb94377b4430d9c2964ac9c808c2a", + "version_major": 2, + "version_minor": 0 + }, "text/plain": [ - "" + "VBox(children=(HTML(value='

GatewayCluster

'), HBox(children=(HTML(value='\\n
\\n
<xarray.Dataset>\n",
        "Dimensions:   ()\n",
        "Data variables:\n",
-       "    K_2019    float64 6.5\n",
-       "    pop_2019  float64 9.5
" + " K_2019 float64 6.2\n", + " pop_2019 float64 8.9" ], "text/plain": [ "\n", "Dimensions: ()\n", "Data variables:\n", - " K_2019 float64 6.5\n", - " pop_2019 float64 9.5" + " K_2019 float64 6.2\n", + " pop_2019 float64 8.9" ] }, - "execution_count": 12, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } @@ -740,30 +746,30 @@ }, { "cell_type": "code", - "execution_count": 13, - "id": "61fa9dc4-bbeb-4710-bc84-65bdf6cd6a4c", - "metadata": {}, + "execution_count": 29, + "id": "29d533e9-8571-4a2f-9adc-b7a2d03af6d7", + "metadata": { + "tags": [] + }, "outputs": [ { "data": { "text/plain": [ - "(0.0, 45675703.08690297)" + "(0.0, 48382814.95746777)" ] }, - "execution_count": 13, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ - "
" + "
" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -778,9 +784,11 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 31, "id": "17c41589-b943-42a8-9522-67e24f3ddf47", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "for v in mvmt.variables:\n", @@ -791,9 +799,11 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 32, "id": "f9812bce-b427-4941-820d-700ed1262d1a", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [ { "data": { @@ -801,13 +811,13 @@ "(None, None)" ] }, - "execution_count": 15, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "client.cluster.close(), client.close()" + "cluster.close(), client.close()" ] }, { @@ -1692,7 +1702,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.12.2" }, "widgets": { "application/vnd.jupyter.widget-state+json": { diff --git a/notebooks/models/run-pyCIAM-slrquantiles.ipynb b/notebooks/models/run-pyCIAM-slrquantiles.ipynb index b76556d..aa3ae75 100644 --- a/notebooks/models/run-pyCIAM-slrquantiles.ipynb +++ b/notebooks/models/run-pyCIAM-slrquantiles.ipynb @@ -11,7 +11,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { "tags": [] }, @@ -24,12 +24,13 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": { "tags": [] }, "outputs": [], "source": [ + "from pyCIAM.run import execute_pyciam\n", "from shared import (\n", " AUTHOR,\n", " CONTACT,\n", @@ -47,14 +48,12 @@ " QUANTILES,\n", " STORAGE_OPTIONS,\n", " start_dask_cluster,\n", - ")\n", - "\n", - "from pyCIAM.run import execute_pyciam" + ")" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "tags": [ "parameters" @@ -68,10 +67,9 @@ "\n", "# When running on larger/scalable dask cluster, may wish to specify number of workers\n", "# Default is LocalCluster which will use the number of CPUs available on local machine\n", - "N_WORKERS = None\n", - "# N_WORKERS = 400\n", + "N_WORKERS = 100\n", "\n", - "SEG_CHUNKSIZE = 3\n", + "SEG_CHUNKSIZE = 2\n", "\n", "SEG_ADM_SUBSET = None\n", "\n", @@ -80,7 +78,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": { "tags": [] }, @@ -102,15 +100,14 @@ }, "outputs": [], "source": [ - "client = start_dask_cluster(\n", - " n_workers=N_WORKERS,\n", - ")\n", - "client" + "client, cluster = start_dask_cluster()\n", + "cluster.scale(N_WORKERS)\n", + "cluster" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": { "tags": [] }, @@ -126,6 +123,7 @@ " output_path=PATH_OUTPUTS,\n", " seg_var_subset=SEG_ADM_SUBSET,\n", " surge_input_paths=PATHS_SURGE_LOOKUP,\n", + " pyciam_seg_chunksize=SEG_CHUNKSIZE,\n", " tmp_output_path=TMPPATH,\n", " quantiles=QUANTILES,\n", " dask_client_func=lambda: client,\n", @@ -156,7 +154,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.0" + "version": "3.12.2" }, "widgets": { "application/vnd.jupyter.widget-state+json": { diff --git a/notebooks/post-processing/zenodo-upload.ipynb b/notebooks/post-processing/zenodo-upload.ipynb index 8394580..3804624 100644 --- a/notebooks/post-processing/zenodo-upload.ipynb +++ b/notebooks/post-processing/zenodo-upload.ipynb @@ -35,7 +35,7 @@ "outputs": [], "source": [ "import json\n", - "from os import environ\n", + "import re\n", "from pathlib import Path\n", "from shutil import make_archive\n", "from tempfile import TemporaryDirectory\n", @@ -43,29 +43,62 @@ "import dask.config\n", "import requests\n", "import shared\n", - "import xarray as xr\n", + "from cloudpathlib import AnyPath\n", "from sliiders import settings as sset\n", - "from sliiders.io import open_zarr\n", "from zarr import ZipStore" ] }, { "cell_type": "code", "execution_count": 4, - "id": "f804bd08-6edb-43f6-8bbd-7a2b98281c29", + "id": "fc342d12-c698-4f64-aaea-fcbfa027431f", "metadata": {}, "outputs": [], "source": [ - "PATH_SLIIDERS_NC = sset.PATH_SLIIDERS.parent / (sset.PATH_SLIIDERS.stem + \".nc\")\n", - "PATH_OUTPUTS_NC = shared.PATH_OUTPUTS.parent / (shared.PATH_OUTPUTS.stem + \".nc\")\n", + "PATT_OUTPUTS_NC = shared.PATH_OUTPUTS.parent / (shared.PATH_OUTPUTS.stem + \"_{case}.nc\")\n", + "PATH_SLIIDERS_NC = sset.PATH_SLIIDERS.parent / (sset.PATH_SLIIDERS.stem + \".nc\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "a125e75e-2122-4bd1-a994-37f1dbaea124", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Processing noAdaptation\n", + "Processing protect10\n", + "Processing protect100\n", + "Processing protect1000\n", + "Processing protect10000\n", + "Processing retreat1\n", + "Processing retreat10\n", + "Processing retreat100\n", + "Processing retreat1000\n", + "Processing retreat10000\n", + "Processing optimalfixed\n" + ] + } + ], + "source": [ + "ds = shared.open_zarr(shared.PATH_OUTPUTS)\n", + "fpaths = []\n", + "for case in ds.case.values:\n", + " print(f\"Processing {case}\")\n", + " fpath = AnyPath(str(PATT_OUTPUTS_NC).format(case=case))\n", + " fpaths.append(fpath)\n", + " if not fpath.exists():\n", + " shared.save_dataset(ds.sel(case=case).load(), fpath)\n", "\n", - "shared.save_dataset(shared.open_zarr(sset.PATH_SLIIDERS).load(), PATH_SLIIDERS_NC)\n", - "shared.save_dataset(shared.open_zarr(sset.PATH_OUTPUTS).load(), PATH_OUTPUTS_NC)" + "shared.save_dataset(shared.open_zarr(sset.PATH_SLIIDERS).load(), PATH_SLIIDERS_NC)" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "id": "d37ca26f-091d-4cb6-be02-385464e0b687", "metadata": { "tags": [] @@ -74,10 +107,10 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 4, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -96,7 +129,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 7, "id": "55a3e849-a554-49fa-882c-846acf76f3b8", "metadata": { "tags": [ @@ -108,16 +141,20 @@ "ACCESS_TOKEN = \"Q5z5IQ1m5Z9l1QS7ZYeV78IS5bqPmhzcFVo0KSNLoh2p39HRMPgFoJsCyQt5\"\n", "VERSION = \"1.2.0\"\n", "TITLES = {\n", - " \"SLIIDERS\": \"SLIIDERS: Sea Level Impacts Input Dataset by Elevation, Region, and Scenario\",\n", - " # \"pyCIAM\": \"Estimates of Global Coastal Losses Under Multiple Sea Level Rise Scenarios\",\n", + " # \"SLIIDERS\": (\n", + " # \"SLIIDERS: Sea Level Impacts Input Dataset by Elevation, Region, and Scenario\"\n", + " # ),\n", + " \"pyCIAM\": (\n", + " \"Estimates of Global Coastal Losses Under Multiple Sea Level Rise Scenarios\"\n", + " ),\n", "}\n", - "PYCIAM_CODE_PATH = Path(\"pyCIAM-1.1.2.zip\")\n", - "SLIIDERS_CODE_PATH = Path(\"/tmp/sliiders-1.2.zip\")" + "PYCIAM_CODE_PATH = Path(\"pyCIAM.zip\")\n", + "SLIIDERS_CODE_PATH = Path(\"/tmp/sliiders.zip\")" ] }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 8, "id": "8725b84c-8a7f-4d88-96ec-849e963ef8ce", "metadata": {}, "outputs": [], @@ -127,7 +164,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 9, "id": "956c40ee-e3e8-4257-bd0d-2c938546604d", "metadata": {}, "outputs": [], @@ -162,7 +199,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 10, "id": "b5fcb2b8-3fb4-4789-bae0-18f7a66b7c51", "metadata": {}, "outputs": [], @@ -170,22 +207,25 @@ "# Metadata\n", "AUTHORS = [\n", " {\n", - " \"affiliation\": \"Energy & Resources Group, University of California, Berkeley; Global Policy Lab, Goldman School of Public Policy, University of California, Berkeley\",\n", + " \"affiliation\": \"United Nations Development Programme\",\n", " \"name\": \"Depsky, Nicholas\",\n", " \"orcid\": \"0000-0002-9441-9042\",\n", " },\n", " {\n", - " \"affiliation\": \"BlackRock; Global Policy Lab, Goldman School of Public Policy, University of California, Berkeley\",\n", + " \"affiliation\": (\n", + " \"Reask; Global Policy Lab, Goldman School of Public Policy, University of \"\n", + " \"California, Berkeley\"\n", + " ),\n", " \"name\": \"Bolliger, Ian\",\n", " \"orcid\": \"0000-0001-8055-297X\",\n", " },\n", " {\n", - " \"affiliation\": \"Global Policy Lab, Goldman School of Public Policy, University of California, Berkeley\",\n", + " \"affiliation\": \"Recidiviz\",\n", " \"name\": \"Allen, Daniel\",\n", " \"orcid\": \"0000-0001-5366-5178\",\n", " },\n", " {\n", - " \"affiliation\": \"Energy Policy Institute, University of Chicago\",\n", + " \"affiliation\": \"Columbia University\",\n", " \"name\": \"Choi, Jun Ho\",\n", " \"orcid\": \"0000-0003-0749-9222\",\n", " },\n", @@ -195,12 +235,15 @@ " \"orcid\": \"0000-0002-2414-045X\",\n", " },\n", " {\n", - " \"affiliation\": \"National Bureau of Economic Research; Energy Policy Institute, University of Chicago\",\n", + " \"affiliation\": (\n", + " \"National Bureau of Economic Research; Energy Policy Institute, University \"\n", + " \"of Chicago\"\n", + " ),\n", " \"name\": \"Greenstone, Michael\",\n", " \"orcid\": \"0000-0002-2364-2810\",\n", " },\n", " {\n", - " \"affiliation\": \"The Rhodium Group\",\n", + " \"affiliation\": \"BlackRock\",\n", " \"name\": \"Hamidi, Ali\",\n", " \"orcid\": \"0000-0001-6235-0303\",\n", " },\n", @@ -210,12 +253,18 @@ " \"orcid\": \"0000-0002-0514-7058\",\n", " },\n", " {\n", - " \"affiliation\": \"Global Policy Lab, Goldman School of Public Policy, University of California, Berkeley; National Bureau of Economic Research\",\n", + " \"affiliation\": (\n", + " \"Global Policy Lab, Goldman School of Public Policy, University of \"\n", + " \"California, Berkeley; National Bureau of Economic Research\"\n", + " ),\n", " \"name\": \"Hsiang, Solomon\",\n", " \"orcid\": \"0000-0002-2074-0829\",\n", " },\n", " {\n", - " \"affiliation\": \"Department of Earth & Planetary Sciences and Rutgers Institute of Earth, Ocean and Atmospheric Sciences, Rutgers University\",\n", + " \"affiliation\": (\n", + " \"Department of Earth & Planetary Sciences and Rutgers Institute of Earth, \"\n", + " \"Ocean and Atmospheric Sciences, Rutgers University\"\n", + " ),\n", " \"name\": \"Kopp, Robert E.\",\n", " \"orcid\": \"0000-0003-4016-9428\",\n", " },\n", @@ -232,7 +281,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 11, "id": "55188020-c02f-4fa6-bf4c-cf1cd87e1754", "metadata": {}, "outputs": [], @@ -247,16 +296,17 @@ " sset.PATH_SEG_PTS_MANUAL,\n", " ],\n", " },\n", + " # uncomment Diaz inputs if a re-upload is necessary\n", " \"pyCIAM\": {\n", " \"products\": [\n", " shared.PATH_OUTPUTS,\n", - " PATH_OUTPUTS_NC,\n", - " shared.PATH_DIAZ_RES,\n", + " # shared.PATH_DIAZ_RES,\n", " shared.PATH_MOVEFACTOR_DATA,\n", + " *fpaths,\n", " ],\n", " \"inputs\": [\n", - " shared.PATH_DIAZ_INPUTS_RAW,\n", - " shared.PATH_SLR_AR5_QUANTILES,\n", + " # shared.PATH_DIAZ_INPUTS_RAW,\n", + " # shared.PATH_SLR_AR5_QUANTILES,\n", " shared.PATH_SLIIDERS_INCOME_INTERMEDIATE_FILE,\n", " shared.PATHS_SURGE_LOOKUP[\"seg\"],\n", " shared.PATHS_SURGE_LOOKUP[\"seg_adm\"],\n", @@ -282,26 +332,37 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 12, "id": "50c10e4c-b3eb-4714-8d32-486ac878d041", "metadata": {}, "outputs": [], "source": [ "def create_draft_deposit(name, update_dict={}, overwrite=False):\n", " dep = EXISTING_DEPOSITS[name]\n", - " # create new deposit\n", - " deposition_id = dep[\"id\"]\n", - " if \"latest_draft\" not in dep[\"links\"]:\n", - " url = f\"{Z_URL}/{deposition_id}/actions/newversion\"\n", - " r = requests.post(url, params=PARAMS)\n", - " if r.status_code not in [200, 201]:\n", - " raise ValueError(f\"{r.status_code}: {r.text}\")\n", + "\n", + " # create new deposit if needed\n", + " r = requests.post(dep[\"links\"][\"newversion\"], params=PARAMS)\n", + " # case 1: this is already a new unpublished version\n", + " if (\n", + " r.status_code == 404\n", + " and r.json()[\"message\"] == \"The persistent identifier is not registered.\"\n", + " ):\n", + " pass\n", + " # case 2: this is a successful new version request and we need to grab the new\n", + " # version deposition\n", + " elif r.status_code in [200, 201]:\n", + " # returned value would be original deposit version in case of new version\n", + " # created\n", " dep = r.json()\n", + " # case 3: some other error\n", + " else:\n", + " raise ValueError(f\"{r.status_code}: {r.text}\")\n", + "\n", + " dep = requests.get(dep[\"links\"][\"latest_draft\"], params=PARAMS).json()\n", "\n", " if overwrite:\n", " new_id = dep[\"links\"][\"latest_draft\"].split(\"/\")[-1]\n", " files = requests.get(dep[\"links\"][\"files\"], params=PARAMS).json()\n", - " print(files)\n", " if len(files):\n", " for f in files:\n", " file_url = f\"{Z_URL}/{new_id}/files/{f['id']}\"\n", @@ -324,31 +385,22 @@ "\n", "\n", "def create_all_new_deposits(titles=TITLES, overwrite=False):\n", - " deps = {}\n", - " ids = {}\n", - " for t in titles.keys():\n", - " dep = create_draft_deposit(t, overwrite=overwrite)\n", - " ids[t] = int(dep[\"links\"][\"latest_draft\"].split(\"/\")[-1])\n", - " all_deps = requests.get(\n", - " Z_URL,\n", - " params={\"access_token\": ACCESS_TOKEN},\n", - " ).json()\n", - " for t in titles.keys():\n", - " dep = [d for d in all_deps if d[\"id\"] == ids[t]]\n", - " assert len(dep) == 1\n", - " deps[t] = dep[0]\n", - " return deps\n", + " return {t: create_draft_deposit(t, overwrite=overwrite) for t in titles.keys()}\n", + "\n", + "\n", + "def _get_zenodo_name(fname):\n", + " # drop a datestamp if it exists\n", + " zenodo_name = re.sub(r\"_\\d{8}\", \"\", fname.name)\n", + " # drop version from name\n", + " return \"-\".join([i for i in zenodo_name.split(\"-\") if shared.RES_VERS not in i])\n", "\n", "\n", - "def upload_file(deposit_link_dict, fname, root, zenodo_name=None, overwrite=False):\n", + "def upload_file(\n", + " deposit_link_dict, fname, zenodo_name=None, overwrite=False, existing_files={}\n", + "):\n", " if zenodo_name is None:\n", - " zenodo_name = fname.name\n", - " zenodo_name = root + zenodo_name\n", + " zenodo_name = _get_zenodo_name(fname)\n", "\n", - " existing_files = {\n", - " f[\"filename\"]: f\n", - " for f in requests.get(deposit_link_dict[\"files\"], params=PARAMS).json()\n", - " }\n", " if zenodo_name in existing_files:\n", " if not overwrite:\n", " print(\"...Skipping b/c already uploaded\")\n", @@ -362,27 +414,36 @@ " data=fp,\n", " )\n", "\n", - " if r.status_code != 200:\n", + " if r.status_code not in [200, 201]:\n", " raise ValueError(f\"{r.status_code}: {r.text}\")\n", " return r.json()\n", "\n", "\n", - "def upload_file_list(deposit, flist, root, overwrite=False):\n", + "def upload_file_list(deposit, flist, overwrite=False):\n", " out = []\n", - " existing_files = {\n", - " f[\"filename\"]: f\n", - " for f in requests.get(deposit[\"links\"][\"files\"], params=PARAMS).json()\n", - " }\n", + " existing_file_request = requests.get(deposit[\"links\"][\"files\"], params=PARAMS)\n", + " if existing_file_request.status_code == 404:\n", + " existing_files = {}\n", + " else:\n", + " existing_files = {f[\"filename\"]: f for f in existing_file_request.json()}\n", " for f in flist:\n", " print(f\"Uploading: {str(f)}\")\n", + " zenodo_name = _get_zenodo_name(f)\n", " if (\n", - " (root + f.name) in existing_files\n", - " or (root + f.name + \".zip\") in existing_files\n", + " zenodo_name in existing_files or (zenodo_name + \".zip\") in existing_files\n", " ) and not overwrite:\n", " print(\"...Skipping b/c already uploaded\")\n", " continue\n", " if f.is_file():\n", - " out.append(upload_file(deposit[\"links\"], f, root, overwrite=overwrite))\n", + " out.append(\n", + " upload_file(\n", + " deposit[\"links\"],\n", + " f,\n", + " overwrite=overwrite,\n", + " zenodo_name=zenodo_name,\n", + " existing_files=existing_files,\n", + " )\n", + " )\n", " elif f.is_dir():\n", " with TemporaryDirectory() as d:\n", " tmp_file = Path(d) / (f.name + \".zip\")\n", @@ -406,7 +467,7 @@ " upload_file(\n", " deposit[\"links\"],\n", " tmp_file,\n", - " root,\n", + " zenodo_name=zenodo_name,\n", " overwrite=overwrite,\n", " )\n", " )\n", @@ -417,7 +478,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 13, "id": "868b1d78-5eb4-4fa6-bcfc-0dbd8c88d39b", "metadata": {}, "outputs": [], @@ -425,17 +486,9 @@ "draft_deps = create_all_new_deposits(overwrite=False)" ] }, - { - "cell_type": "markdown", - "id": "558e67ba-77cb-4355-9dfb-d11533f1a344", - "metadata": {}, - "source": [ - "Note that it seems to take some time for the \"bucket\" link to show up, which is needed to use Zenodo's \"new\" file API, which allows for uploads larger than 100MB. So if bucket is not appearing, you may need to wait a while (<1 day) to be able to run the file uploads below." - ] - }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 14, "id": "ff8703bb-c630-418e-9f2f-c62b116ee7e8", "metadata": {}, "outputs": [ @@ -443,39 +496,48 @@ "name": "stdout", "output_type": "stream", "text": [ - "SLIIDERS\n" - ] - }, - { - "ename": "TypeError", - "evalue": "string indices must be integers, not 'str'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[44], line 6\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28mprint\u001b[39m(name)\n\u001b[1;32m 4\u001b[0m this_dep \u001b[38;5;241m=\u001b[39m draft_deps[name]\n\u001b[0;32m----> 6\u001b[0m uploads[name] \u001b[38;5;241m=\u001b[39m \u001b[43mupload_file_list\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 7\u001b[0m \u001b[43m \u001b[49m\u001b[43mthis_dep\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mkind\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43minputs\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43minputs/\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moverwrite\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\n\u001b[1;32m 8\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 9\u001b[0m uploads[name] \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m upload_file_list(\n\u001b[1;32m 10\u001b[0m this_dep, kind[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mproducts\u001b[39m\u001b[38;5;124m\"\u001b[39m], \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mproducts/\u001b[39m\u001b[38;5;124m\"\u001b[39m, overwrite\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m\n\u001b[1;32m 11\u001b[0m )\n\u001b[1;32m 12\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msource\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01min\u001b[39;00m kind\u001b[38;5;241m.\u001b[39mkeys():\n", - "Cell \u001b[0;32mIn[40], line 83\u001b[0m, in \u001b[0;36mupload_file_list\u001b[0;34m(deposit, flist, root, overwrite)\u001b[0m\n\u001b[1;32m 81\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mupload_file_list\u001b[39m(deposit, flist, root, overwrite\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m):\n\u001b[1;32m 82\u001b[0m out \u001b[38;5;241m=\u001b[39m []\n\u001b[0;32m---> 83\u001b[0m existing_files \u001b[38;5;241m=\u001b[39m \u001b[43m{\u001b[49m\n\u001b[1;32m 84\u001b[0m \u001b[43m \u001b[49m\u001b[43mf\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mfilename\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mf\u001b[49m\n\u001b[1;32m 85\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mf\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mrequests\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdeposit\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mlinks\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mfiles\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparams\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mPARAMS\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mjson\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 86\u001b[0m \u001b[43m \u001b[49m\u001b[43m}\u001b[49m\n\u001b[1;32m 87\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m f \u001b[38;5;129;01min\u001b[39;00m flist:\n\u001b[1;32m 88\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUploading: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mstr\u001b[39m(f)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", - "Cell \u001b[0;32mIn[40], line 84\u001b[0m, in \u001b[0;36m\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 81\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mupload_file_list\u001b[39m(deposit, flist, root, overwrite\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m):\n\u001b[1;32m 82\u001b[0m out \u001b[38;5;241m=\u001b[39m []\n\u001b[1;32m 83\u001b[0m existing_files \u001b[38;5;241m=\u001b[39m {\n\u001b[0;32m---> 84\u001b[0m \u001b[43mf\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mfilename\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m: f\n\u001b[1;32m 85\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m f \u001b[38;5;129;01min\u001b[39;00m requests\u001b[38;5;241m.\u001b[39mget(deposit[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlinks\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfiles\u001b[39m\u001b[38;5;124m\"\u001b[39m], params\u001b[38;5;241m=\u001b[39mPARAMS)\u001b[38;5;241m.\u001b[39mjson()\n\u001b[1;32m 86\u001b[0m }\n\u001b[1;32m 87\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m f \u001b[38;5;129;01min\u001b[39;00m flist:\n\u001b[1;32m 88\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUploading: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mstr\u001b[39m(f)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", - "\u001b[0;31mTypeError\u001b[0m: string indices must be integers, not 'str'" + "pyCIAM\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/sliiders/int/exposure/ypk/finalized/ypk_2000_2100_20240222.zarr\n", + "...Skipping b/c already uploaded\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/ciam_paper/data/int/surge-lookup-v1.2-seg.zarr\n", + "...Skipping b/c already uploaded\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/ciam_paper/data/int/surge-lookup-v1.2-seg_adm.zarr\n", + "...Skipping b/c already uploaded\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/ciam_paper/results-v1.2/pyCIAM_outputs.zarr\n", + "...Skipping b/c already uploaded\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/ciam_paper/results-v1.2/suboptimal_capital_by_movefactor.zarr\n", + "...Skipping b/c already uploaded\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/ciam_paper/results-v1.2/pyCIAM_outputs_noAdaptation.nc\n", + "...Skipping b/c already uploaded\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/ciam_paper/results-v1.2/pyCIAM_outputs_protect10.nc\n", + "...Skipping b/c already uploaded\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/ciam_paper/results-v1.2/pyCIAM_outputs_protect100.nc\n", + "...Skipping b/c already uploaded\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/ciam_paper/results-v1.2/pyCIAM_outputs_protect1000.nc\n", + "...Skipping b/c already uploaded\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/ciam_paper/results-v1.2/pyCIAM_outputs_protect10000.nc\n", + "...Skipping b/c already uploaded\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/ciam_paper/results-v1.2/pyCIAM_outputs_retreat1.nc\n", + "...Skipping b/c already uploaded\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/ciam_paper/results-v1.2/pyCIAM_outputs_retreat10.nc\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/ciam_paper/results-v1.2/pyCIAM_outputs_retreat100.nc\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/ciam_paper/results-v1.2/pyCIAM_outputs_retreat1000.nc\n", + "Uploading: gs://rhg-data/impactlab-rhg/coastal/ciam_paper/results-v1.2/pyCIAM_outputs_optimalfixed.nc\n", + "Uploading: pyCIAM.zip\n" ] } ], "source": [ "uploads = {}\n", - "for name, kind in ORIGINAL_PATHS.items():\n", + "for name in TITLES:\n", " print(name)\n", + " kind = ORIGINAL_PATHS[name]\n", " this_dep = draft_deps[name]\n", "\n", - " uploads[name] = upload_file_list(\n", - " this_dep, kind[\"inputs\"], \"inputs/\", overwrite=False\n", - " )\n", - " uploads[name] += upload_file_list(\n", - " this_dep, kind[\"products\"], \"products/\", overwrite=False\n", - " )\n", - " if \"source\" in kind.keys():\n", - " uploads[name] += upload_file_list(\n", - " this_dep, kind[\"source\"], \"source/\", overwrite=False\n", - " )" + " uploads[name] = []\n", + " for filetype in [\"inputs\", \"products\", \"source\"]:\n", + " if filetype in kind:\n", + " uploads[name] += upload_file_list(this_dep, kind[filetype], overwrite=False)" ] } ], @@ -495,7 +557,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.8" + "version": "3.12.2" }, "widgets": { "application/vnd.jupyter.widget-state+json": { diff --git a/notebooks/shared.py b/notebooks/shared.py index 0825bb2..2d575fc 100644 --- a/notebooks/shared.py +++ b/notebooks/shared.py @@ -1,20 +1,20 @@ +import os from pathlib import Path +from zipfile import ZipFile import geopandas as gpd import xarray as xr -from distributed import Client -from distributed.diagnostics.plugin import UploadDirectory - +from dask_gateway import GatewayCluster from pyCIAM import __file__ DIR_SCRATCH = Path("/tmp/ciam-scratch") SLIIDERS_VERS = "v1.2" -RES_VERS = "v1.1" +RES_VERS = "v1.2" # Cloud Storage tools (will work with local storage as well but may need to be specifiec # for cloud buckets -STORAGE_OPTIONS = {} +STORAGE_OPTIONS = None def _to_fuse(path): @@ -25,9 +25,10 @@ def _to_fuse(path): QUANTILES = [0.17, 0.5, 0.83] # Output dataset attrs -HISTORY = """version 1.1: Version associated with Depsky et al. 2023""" +HISTORY = """version 1.1: Version associated with Depsky et al. 2023. +version 1.2: Updated to use SLIIDERS v1.2 as input.""" AUTHOR = "Ian Bolliger" -CONTACT = "ian.bolliger@blackrock.com" +CONTACT = "ian@reask.earth" # AR5 SLR projections info LOCALIZESL_COREFILES = { @@ -54,9 +55,9 @@ def _to_fuse(path): ################## # NECESSARY FOR EXAMPLE -PATH_PARAMS = Path.home() / "git-repos/pyciam/params.json" +PATH_PARAMS = Path.home() / "git-repos/pyCIAM/params.json" -PATH_PARAMS_DIAZ = Path.home() / "git-repos/pyciam/params_diaz.json" +PATH_PARAMS_DIAZ = Path.home() / "git-repos/pyCIAM/params_diaz.json" ################## # SOCIOECON INPUTS @@ -67,8 +68,9 @@ def _to_fuse(path): # NECESSARY FOR EXAMPLE PATH_SLIIDERS = DIR_RAW / f"sliiders-{SLIIDERS_VERS}.zarr" -# NECESSARY FOR EXAMPLE -PATH_SLIIDERS_SEG = DIR_INT / f"sliiders-{SLIIDERS_VERS}-seg.zarr" +PATH_SLIIDERS_SEG = PATH_SLIIDERS.parent / ( + PATH_SLIIDERS.stem + "-seg" + PATH_SLIIDERS.suffix +) # Diaz PATH_DIAZ_INPUTS_RAW = DIR_RAW / "diaz2016_inputs_raw.zarr" @@ -132,7 +134,7 @@ def _to_fuse(path): # FILES FOR PLOTTING RESULTS ############################ PATH_MOVEFACTOR_DATA = DIR_RES / "suboptimal_capital_by_movefactor.zarr" -PATH_SLIIDERS_INCOME_INTERMEDIATE_FILE = DIR_RAW / "ypk_2000_2100_20221122.zarr" +PATH_SLIIDERS_INCOME_INTERMEDIATE_FILE = DIR_RAW / "ypk_2000_2100_20240222.zarr" DIR_FIGS = Path("/home/jovyan/ciam-figures") DIR_SHP = DIR_RAW / "shapefiles" @@ -155,48 +157,48 @@ def _to_fuse(path): p.mkdir(exist_ok=True, parents=True) -def upload_pyciam(client, restart_client=True): - """Upload a local package to Dask Workers. After calling this function, the package - contained at ``pkg_dir`` will be available on all workers in your Dask cluster, - including those that are instantiated afterward. This package will take priority - over any existing packages of the same name. This is a useful tool for working with - remote dask clusters (e.g. via Dask Gateway) but is not needed for local clusters. - If you wish to use this, you should call this function from within - `start_dask_cluster`. - - Parameters - ---------- - client : :py:class:`distributed.Client` - The client object associated with your Dask cluster's scheduler. - pkg_dir : str or Path-like - Path to the package you wish to zip and upload - **kwargs - Passed directly to :py:class:`distributed.diagnostics.plugin.UploadDirectory` - """ - client.register_worker_plugin( - UploadDirectory( - Path(__file__).parents[1], - update_path=True, - restart=restart_client, - skip_words=( - ".git", - ".github", - ".pytest_cache", - "tests", - "docs", - "deploy", - "notebooks", - ".ipynb_checkpoints", - "__pycache__", - ".coverage", - "dockerignore", - ".gitignore", - ".gitlab-ci.yml", - ".gitmodules", - "pyclaw.log", - ), - ) - ) +def _zipdir( + path, + zip_filename, + skip_files=( + ".git", + ".github", + ".pytest_cache", + "tests", + "docs", + "deploy", + "notebooks", + ".ipynb_checkpoints", + "__pycache__", + ".coverage", + "dockerignore", + ".gitignore", + ".gitlab-ci.yml", + ".gitmodules", + "pyclaw.log", + "run_tests.sh", + ), +): + + with ZipFile(zip_filename, "w") as ziph: + for root, dirs, files in os.walk(path): + for file in files: + if any([f in file.split("/") for f in skip_files]): + continue + # Create a relative path for files to preserve the directory structure + # within the ZIP archive. This relative path is based on the directory + # being zipped, so files are stored in the same structure. + relative_path = os.path.relpath( + os.path.join(root, file), os.path.join(path, "..") + ) + ziph.write(os.path.join(root, file), arcname=relative_path) + + +def upload_pyciam(client): + package_dir = Path(__file__).parent + zip_filename = "/tmp/pyCIAM.zip" # Output ZIP file name + _zipdir(package_dir, zip_filename) + client.upload_file(zip_filename) def save(obj, path, *args, **kwargs): @@ -241,7 +243,8 @@ def read_shapefile(path, **kwargs): return gpd.read_file(_path, **kwargs) -def start_dask_cluster(**kwargs): - client = Client(**kwargs) - print(client.dashboard_link) - return client +def start_dask_cluster(profile="micro", **kwargs): + cluster = GatewayCluster(profile=profile, **kwargs) + client = cluster.get_client() + upload_pyciam(client) + return client, cluster diff --git a/pyCIAM/io.py b/pyCIAM/io.py index f0c9dc8..64a951e 100644 --- a/pyCIAM/io.py +++ b/pyCIAM/io.py @@ -2,19 +2,17 @@ outputs used in running pyCIAM. Functions - prep_sliiders - load_ciam_inputs - load_diaz_inputs +--------- +* prep_sliiders +* load_ciam_inputs +* load_diaz_inputs """ -from collections.abc import Iterable - import dask.array as da import numpy as np import pandas as pd import pint_xarray # noqa: F401 import xarray as xr - from pyCIAM.utils import spherical_nearest_neighbor as snn from .utils import _s2d @@ -297,11 +295,11 @@ def _load_lslr_for_ciam( def create_template_dataarray(dims, coords, chunks, dtype="float32", name=None): """A utility function helpful for creatting an empty, dask-backed - :py:class:`xarray.DataArray` with specific dimensions, coordinates, dtype, name, - and chunk structure. This is useful for "probabilistic" mode of pyCIAM, in which - you will run the model on a large ensemble of SLR trajectory realizations. In this - case, we save an empty Zarr store and then parallelize the model runs across - regions, with each processor writing to a region within the template store. + :py:class:`xarray.DataArray` with specific dimensions, coordinates, dtype, name, and + chunk structure. This is useful for "probabilistic" mode of pyCIAM, in which you + will run the model on a large ensemble of SLR trajectory realizations. In this case, + we save an empty Zarr store and then parallelize the model runs across regions, with + each processor writing to a region within the template store. Parameters ---------- @@ -336,10 +334,10 @@ def create_template_dataarray(dims, coords, chunks, dtype="float32", name=None): def create_template_dataset(var_dims, coords, chunks, dtypes): """A utility function helpful for creatting an empty, dask-backed :py:class:`xarray.Dataset` with specific variables, dimensions, coordinates, dtypes, - and chunk structure. This is useful for "probabilistic" mode of pyCIAM, in which - you will run the model on a large ensemble of SLR trajectory realizations. In this - case, we save an empty Zarr store and then parallelize the model runs across - regions, with each processor writing to a region within the template store. + and chunk structure. This is useful for "probabilistic" mode of pyCIAM, in which you + will run the model on a large ensemble of SLR trajectory realizations. In this case, + we save an empty Zarr store and then parallelize the model runs across regions, with + each processor writing to a region within the template store. Parameters ---------- diff --git a/pyCIAM/run.py b/pyCIAM/run.py index c5a0905..6e1378d 100644 --- a/pyCIAM/run.py +++ b/pyCIAM/run.py @@ -2,9 +2,10 @@ options are calculated. Functions - calc_costs - select_optimal_case - execute_pyciam +--------- +* calc_costs +* select_optimal_case +* execute_pyciam """ from collections import OrderedDict @@ -15,8 +16,6 @@ import xarray as xr from cloudpathlib import AnyPath, CloudPath from distributed import Client, wait -from rhg_compute_tools.xarray import dataarray_from_delayed - from pyCIAM.constants import CASE_DICT, CASES, COSTTYPES, PLIST, RLIST, SOLVCASES from pyCIAM.io import ( check_finished_zarr_workflow, @@ -39,6 +38,7 @@ collapse_econ_inputs_to_seg, subset_econ_inputs, ) +from rhg_compute_tools.xarray import dataarray_from_delayed def calc_costs( @@ -83,9 +83,9 @@ def calc_costs( elev_chunksize : int, default 1 Number of elevation slices to process simultaneously. Higher numbers improve efficiency through vectorization but result in a larger memory footprint. - ddf_i, dmf_i : func, default :py:func:`.damage_funcs.ddf_i`, :py:func:`.damage_funcs.dmf_i` - Damage functions relating physical capital loss and monetized mortality arising - from a certain depth of inundation. + ddf_i, dmf_i : func, default :py:func:`.damage_funcs.ddf_i`, + :py:func:`.damage_funcs.dmf_i`. Damage functions relating physical capital loss + and monetized mortality arising from a certain depth of inundation. diaz_protect_height : bool, default False If True, reduce the 1-in-10-year extreme sea level by 50% as in Diaz 2016. This hack should not be necessary when using the ESL heights from CoDEC (as in @@ -280,9 +280,9 @@ def calc_costs( surge_noadapt["stormCapital"] = surge_noadapt.stormCapital * inputs.K.sum( "elev" ) - surge_noadapt[ - "stormPopulation" - ] = surge_noadapt.stormPopulation * inputs.pop.sum("elev") + surge_noadapt["stormPopulation"] = ( + surge_noadapt.stormPopulation * inputs.pop.sum("elev") + ) else: if surge_lookup is None: rh_years = RH_heights.sel(at=at).drop("at") @@ -402,9 +402,9 @@ def calc_costs( surge_noadapt["stormCapital"] = surge_noadapt.stormCapital * inputs.K.sum( "elev" ) - surge_noadapt[ - "stormPopulation" - ] = surge_noadapt.stormPopulation * inputs.pop.sum("elev") + surge_noadapt["stormPopulation"] = ( + surge_noadapt.stormPopulation * inputs.pop.sum("elev") + ) surge = surge.stack(tmp=["adapttype", "return_period"]) surge = ( @@ -880,6 +880,7 @@ def execute_pyciam( surge_input_paths=None, output_path=None, tmp_output_path=AnyPath("pyciam_tmp_results.zarr"), + remove_tmpfile=True, overwrite=False, mc_dim="quantile", seg_var="seg_adm", @@ -895,7 +896,7 @@ def execute_pyciam( diaz_inputs=False, diaz_config=False, dask_client_func=Client, - storage_options={}, + storage_options=None, **model_kwargs ): """Execute the full pyCIAM model. The following inputs are assumed: @@ -957,6 +958,10 @@ def execute_pyciam( tmp_output_path : Path-like, default Path("pyciam_tmp_results.zarr") Path to temporary output zarr store that is written to and read from within this function. Ignored if `output_path` is not None. + remove_tmpfile : bool, default True + If True, remove the intermediate zarr store created before collapsing to + `adm_var` and rechunking. Setting to False can be useful for debugging if you + want to examine seg-adm level results. ovewrwrite : bool, default False If True, overwrite all intermediate output files mc_dim : str, default "quantile" @@ -1052,6 +1057,9 @@ def execute_pyciam( surge_input_paths = {k: AnyPath(v) for k, v in surge_input_paths.items()} slr_input_paths = [AnyPath(f) if f is not None else None for f in slr_input_paths] + if seg_var == "seg": + adm_var = "seg" + # read parameters params = pd.read_json(params_path)["values"] @@ -1095,7 +1103,6 @@ def execute_pyciam( if seg_var == "seg": econ_input_path_seg = econ_input_path else: - assert tmp_output_path is not None if overwrite or not econ_input_path_seg.is_dir(): collapse_econ_inputs_to_seg( econ_input_path, @@ -1382,13 +1389,15 @@ def execute_pyciam( .chunk({"year": 10}) .persist() ) - out["costs"] = ( - out.costs.groupby(ciam_in[adm_var]).sum().chunk({adm_var: this_chunksize}) - ).persist() - out["optimal_case"] = ( - out.optimal_case.load().groupby(ciam_in.seg).first(skipna=False).chunk() - ).persist() - out = out.drop(seg_var).unify_chunks() + if adm_var != seg_var: + out["costs"] = ( + out.costs.groupby(ciam_in[adm_var]).sum().chunk({adm_var: this_chunksize}) + ).persist() + out["optimal_case"] = ( + out.optimal_case.load().groupby(ciam_in.seg).first(skipna=False).chunk() + ).persist() + out = out.drop(seg_var) + out = out.unify_chunks() for v in out.data_vars: out[v].encoding.clear() @@ -1411,10 +1420,11 @@ def execute_pyciam( ) client.cluster.close() client.close() - if isinstance(tmp_output_path, CloudPath): - tmp_output_path.rmtree() - else: - rmtree(tmp_output_path) + if remove_tmpfile: + if isinstance(tmp_output_path, CloudPath): + tmp_output_path.rmtree() + else: + rmtree(tmp_output_path) def get_refA( @@ -1595,7 +1605,7 @@ def optimize_case( ) as ds: all_segs = ds.seg.load() - this_seg_adms = all_segs.seg_adm.isel({seg_var: all_segs.seg == seg}).values + this_seg_adms = all_segs[seg_var].isel({seg_var: all_segs.seg == seg}).values save_to_zarr_region( select_optimal_case( diff --git a/pyCIAM/surge/__init__.py b/pyCIAM/surge/__init__.py index a4af155..224fded 100644 --- a/pyCIAM/surge/__init__.py +++ b/pyCIAM/surge/__init__.py @@ -1 +1,2 @@ -"""This module contains functions related to calculating losses from extreme sea levels.""" +"""This module contains functions related to calculating losses from extreme sea +levels.""" diff --git a/pyCIAM/surge/_calc.py b/pyCIAM/surge/_calc.py index e3dc42f..5ddefa0 100644 --- a/pyCIAM/surge/_calc.py +++ b/pyCIAM/surge/_calc.py @@ -1,5 +1,5 @@ -"""This private module contains functions related to specific calculations within -pyCIAM that are called by the ``run`` module.""" +"""This private module contains functions related to specific calculations within pyCIAM +that are called by the ``run`` module.""" import numpy as np import xarray as xr @@ -12,8 +12,8 @@ def _get_surge_heights_probs( min_surge_ht, max_surge_ht, gumbel_params, n_surge_heights=100 ): """Create an array of ``n_surge_heights`` surge heights and associated probabilities - to apply in CIAM in order to sample an appropriate range of plausible surge heights. - """ + to apply in CIAM in order to sample an appropriate range of plausible surge + heights.""" # get gumbel params loc = gumbel_params.sel(params="loc", drop=True) diff --git a/pyCIAM/surge/damage_funcs.py b/pyCIAM/surge/damage_funcs.py index 95b675b..f4b45fe 100644 --- a/pyCIAM/surge/damage_funcs.py +++ b/pyCIAM/surge/damage_funcs.py @@ -2,8 +2,8 @@ relate storm surge depth to mortality and physical capital loss. As of April 7, 2022, the only functions available are those included in Diaz 2016. These define the "resilience-unadjusted" fractional damages. That is, for a region with resiliendce -factor (:math:`\rho`) of 1, what fraction of the exposed population and/or physical capital -will be lost conditional on a storm surge depth. +factor (:math:`\rho`) of 1, what fraction of the exposed population and/or physical +capital will be lost conditional on a storm surge depth. At the moment, functions must have an analytical integral and are actually defined by their integral, as can be seen with the suffix ``_i``. @@ -51,7 +51,8 @@ def diaz_ddf_i(depth_st, depth_end): def diaz_dmf_i(depth_st, depth_end, floodmortality=0.01): """Integral of mortality damage function as used in Diaz 2016, assuming unit - resilience (:math:`\rho`). It is just a constant fraction conditional on a unit of exposure being inundated. Note that kwargs are not optional and will raise an error + resilience (:math:`\rho`). It is just a constant fraction conditional on a unit of + exposure being inundated. Note that kwargs are not optional and will raise an error if not specified when called. Parameters diff --git a/pyCIAM/surge/lookup.py b/pyCIAM/surge/lookup.py index a6424c3..7e9d08d 100644 --- a/pyCIAM/surge/lookup.py +++ b/pyCIAM/surge/lookup.py @@ -17,7 +17,6 @@ create_surge_lookup """ - import dask.array as da import numpy as np import pandas as pd @@ -63,12 +62,15 @@ def _get_lslr_rhdiff_range( storage_options={}, ): """Get the range of lslr and rhdiff that we need to model to cover the full range - across scenario/mcs. The minimum LSLR value we'll need to model for the purposes of + across scenario/mcs. + + The minimum LSLR value we'll need to model for the purposes of assessing storm damage is the minimum across sites of: the site-level maximum of "0 minus the s10000 surge height" and "the minimum projected LSLR for all of the scenario/mcs we use in our binned LSL dataset". The maximum LSLR value is the maximum experienced at any site in any year for all of the sceanrio/mcs we use in - the binned LSL dataset.""" + the binned LSL dataset. + """ if isinstance(slr_0_years, int): slr_0_years = [slr_0_years] * len(slr_stores) diff --git a/pyCIAM/utils.py b/pyCIAM/utils.py index 8efde61..5430db3 100644 --- a/pyCIAM/utils.py +++ b/pyCIAM/utils.py @@ -1,4 +1,4 @@ -"""This private module contains miscellaneous functions to support pyCIAM""" +"""This private module contains miscellaneous functions to support pyCIAM.""" import shutil from pathlib import Path @@ -7,9 +7,8 @@ import pandas as pd import xarray as xr from cloudpathlib import CloudPath -from sklearn.neighbors import BallTree - from pyCIAM.constants import CASE_DICT +from sklearn.neighbors import BallTree def _s2d(ds): @@ -281,13 +280,18 @@ def weighted_avg(varname, wts_in): def subset_econ_inputs(ds, seg_var, seg_var_subset): if seg_var_subset is None: return ds - if seg_var == "seg": - return ds.sel(seg=ds.seg.str.contains(seg_var_subset)) - necessary_segs = np.unique( - ds.seg.sel({seg_var: ds[seg_var].str.contains(seg_var_subset)}) - ) - return ds.sel({seg_var: ds.seg.isin(necessary_segs)}) + if isinstance(seg_var_subset, str): + if seg_var == "seg": + subsetter = ds.seg.str.contains(seg_var_subset) + else: + subsetter = ds.seg.isin( + np.unique( + ds.seg.sel({seg_var: ds[seg_var].str.contains(seg_var_subset)}) + ) + ) + + return ds.sel({seg_var: subsetter}) def copy(path_src, path_trg):