diff --git a/.DS_Store b/.DS_Store index d98d740b..f36a9c94 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Farinotti_icethickness_process.ipynb b/Farinotti_icethickness_process.ipynb deleted file mode 100644 index 91da95e5..00000000 --- a/Farinotti_icethickness_process.ipynb +++ /dev/null @@ -1,378 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "# Built-in libraries\n", - "import os\n", - "import argparse\n", - "# External libraries\n", - "from osgeo import gdal\n", - "#import geopandas as gpd\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import pandas as pd\n", - "#import shapely\n", - "\n", - "from pygeotools.lib import iolib, warplib, geolib, timelib, malib\n", - "\n", - "import pygemfxns_modelsetup as modelsetup\n", - "\n", - "\n", - "#Function to generate a 3-panel plot for input arrays\n", - "def plot3panel(dem_list, clim=None, titles=None, cmap='inferno', label=None, overlay=None, fn=None):\n", - " fig, axa = plt.subplots(1,3, sharex=True, sharey=True, figsize=(10,5))\n", - " alpha = 1.0\n", - " for n, ax in enumerate(axa):\n", - " #Gray background\n", - " ax.set_facecolor('0.5')\n", - " #Force aspect ratio to match images\n", - " ax.set(aspect='equal')\n", - " #Turn off axes labels/ticks\n", - " ax.get_xaxis().set_visible(False)\n", - " ax.get_yaxis().set_visible(False)\n", - " if titles is not None:\n", - " ax.set_title(titles[n])\n", - " #Plot background shaded relief map\n", - " if overlay is not None:\n", - " alpha = 0.7\n", - " axa[n].imshow(overlay[n], cmap='gray', clim=(1,255))\n", - " #Plot each array\n", - " im_list = [axa[i].imshow(dem_list[i], clim=clim, cmap=cmap, alpha=alpha) for i in range(len(dem_list))]\n", - " fig.tight_layout()\n", - " fig.colorbar(im_list[0], ax=axa.ravel().tolist(), label=label, extend='both', shrink=0.5)\n", - " if fn is not None:\n", - " fig.savefig(fn, bbox_inches='tight', pad_inches=0, dpi=150)\n", - "\n", - "#Input DEM filenames\n", - "dem_ref_fn = None\n", - "# dem_ref_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/Alaska_albers_V3_mac/Alaska_albers_V3.tif'\n", - "thickness_fp_prefix = ('/Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/' +\n", - " 'composite_thickness_RGI60-all_regions/')\n", - "# dem_farinotti_fp = ('/Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/surface_DEMs_RGI60/' +\n", - "# 'surface_DEMs_RGI60-01/')\n", - "dem_farinotti_fp_prefix = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/surface_DEMs_RGI60/'\n", - "output_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/output/'\n", - "fig_fp = output_fp + 'figures/'\n", - "if os.path.exists(output_fp) == False:\n", - " os.makedirs(output_fp)\n", - "if os.path.exists(fig_fp) == False:\n", - " os.makedirs(fig_fp)\n", - "\n", - "rgi_regionsO1 = [15] # RGI Order 1 regions\n", - "binsize = 10 # elevation bin (must be an integer greater than 1)\n", - "dem_poorquality_switch = True # Switch to filter poor quality DEMs if another DEM is available\n", - "dem_poorquality_threshold = 200 # threshold used to identify problems with Farinotti DEM\n", - "option_plot_DEMsraw = True # Option to plot the raw DEMs\n", - "option_plot_DEMs = False # Option to plot the masked DEMs\n", - "debug = False" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "DELETE ME - SWITCH TO COMPLETE LIST\n", - "\n", - "\n", - "1 glaciers in region 15 are included in this model run: ['02228']\n", - "This study is focusing on 1 glaciers in region [15]\n", - "['/Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/surface_DEMs_RGI60/surface_DEMs_RGI60-15/surface_DEM_RGI60-15.02228.tif', '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/composite_thickness_RGI60-all_regions/RGI60-15/RGI60-15.02228_thickness.tif']\n", - "\n", - "Warping all inputs to the following:\n", - "Resolution: 25.0\n", - "Extent: [751262.5, 3110587.5, 755412.5, 3112962.5]\n", - "Projection: '+proj=utm +zone=45 +datum=WGS84 +units=m +no_defs '\n", - "Resampling alg: cubic\n", - "\n", - "1 of 2: /Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/surface_DEMs_RGI60/surface_DEMs_RGI60-15/surface_DEM_RGI60-15.02228.tif\n", - "2 of 2: /Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/composite_thickness_RGI60-all_regions/RGI60-15/RGI60-15.02228_thickness.tif\n", - "0 15.02228 520 1150\n" - ] - } - ], - "source": [ - "# ======\n", - "glacno_wpoor_DEM = []\n", - "for region in rgi_regionsO1:\n", - "\n", - " thickness_fp = thickness_fp_prefix + 'RGI60-' + str(region).zfill(2) + '/'\n", - " dem_farinotti_fp = dem_farinotti_fp_prefix + 'surface_DEMs_RGI60-' + str(region).zfill(2) + '/'\n", - "\n", - " glacno_list = []\n", - " for i in os.listdir(thickness_fp):\n", - " if i.endswith('_thickness.tif'):\n", - " glacno_list.append(i.split('-')[1].split('_')[0])\n", - " glacno_list = sorted(glacno_list)\n", - "\n", - " print('\\n\\nDELETE ME - SWITCH TO COMPLETE LIST\\n\\n')\n", - " glacno_list = ['15.02228']\n", - " # glacno_list = glacno_list[10000:10010]\n", - "\n", - " # Load RGI glacier data\n", - " main_glac_rgi = modelsetup.selectglaciersrgitable(glac_no=glacno_list)\n", - " # setup empty datasets\n", - " elev_bins_all = np.arange(binsize / 2, main_glac_rgi.Zmax.max() + binsize / 2, binsize).astype(int)\n", - " df_cns = ['RGIId']\n", - " for elev_bin in elev_bins_all:\n", - " df_cns.append(elev_bin)\n", - " main_glac_hyps = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns)\n", - " main_glac_thickness = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns)\n", - " main_glac_width = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns)\n", - " main_glac_length = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns)\n", - " main_glac_slope = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns)\n", - " main_glac_hyps['RGIId'] = main_glac_rgi.RGIId.values\n", - " main_glac_thickness['RGIId'] = main_glac_rgi.RGIId.values\n", - " main_glac_width['RGIId'] = main_glac_rgi.RGIId.values\n", - " main_glac_length['RGIId'] = main_glac_rgi.RGIId.values\n", - " main_glac_slope['RGIId'] = main_glac_rgi.RGIId.values\n", - " \n", - " # ===== PROCESS EACH GLACIER ======\n", - " for nglac, glacno in enumerate(glacno_list):\n", - " # print(nglac, glacno)\n", - " thickness_fn = thickness_fp + 'RGI60-' + glacno + '_thickness.tif'\n", - " dem_farinotti_fn = dem_farinotti_fp + 'surface_DEM_RGI60-' + glacno + '.tif'\n", - " \n", - " # Reproject, resample, warp rasters to common extent, grid size, etc.\n", - " # note: use thickness for the reference to avoid unrealistic extrapolations, e.g., negative thicknesses\n", - " # also using equal area increases areas significantly compared to RGI\n", - " raster_fn_list = [dem_farinotti_fn, thickness_fn]\n", - " if dem_ref_fn is not None:\n", - " raster_fn_list.append(dem_ref_fn)\n", - " \n", - " print(raster_fn_list)\n", - " \n", - " ds_list = warplib.memwarp_multi_fn(raster_fn_list, extent='intersection', res='min', t_srs=thickness_fn)\n", - "\n", - " # masked arrays using ice thickness estimates\n", - " if dem_ref_fn is not None:\n", - " dem_ref_raw, dem_far_raw, thickness = [iolib.ds_getma(i) for i in ds_list]\n", - " dem_ref = dem_ref_raw.copy()\n", - " dem_ref.mask = thickness.mask\n", - " else:\n", - " dem_far_raw, thickness = [iolib.ds_getma(i) for i in ds_list]\n", - " dem_far = dem_far_raw.copy()\n", - " dem_far.mask = thickness.mask\n", - " \n", - " # DEM selection for binning computations\n", - " # if exceeds threshold, then use the reference\n", - " if ((abs(main_glac_rgi.loc[nglac,'Zmin'] - dem_far.min()) > dem_poorquality_threshold or\n", - " abs(main_glac_rgi.loc[nglac,'Zmax'] - dem_far.max()) > dem_poorquality_threshold) \n", - " and dem_ref_fn is not None):\n", - " print(' Check Glacier ' + glacno + ': use Christian DEM instead of Farinotti')\n", - " print('\\n RGI Zmin/Zmax:', main_glac_rgi.loc[nglac,'Zmin'], '/', main_glac_rgi.loc[nglac,'Zmax'])\n", - " print(' Farinotti Zmin/Zmax:', np.round(dem_far.min(),0), '/', np.round(dem_far.max(),0))\n", - " print(' Christian Zmin/Zmax:', np.round(dem_ref.min(),0), '/', np.round(dem_ref.max(),0), '\\n')\n", - " glacno_wpoor_DEM.append(glacno)\n", - " dem = dem_ref\n", - " dem_raw = dem_ref_raw\n", - "\n", - " # ===== PLOT DEMS TO CHECK =====\n", - " if option_plot_DEMsraw:\n", - " dem_list_raw = [dem_ref_raw, dem_far_raw, thickness]\n", - " titles = ['DEM-Christian-raw', 'DEM-Farinotti-raw', 'Thickness']\n", - " clim = malib.calcperc(dem_list_raw[0], (2,98))\n", - " plot3panel(dem_list_raw, clim, titles, 'inferno', 'Elevation (m WGS84)', fn=fig_fp + glacno +\n", - " '_dem_raw.png')\n", - "\n", - " if option_plot_DEMs:\n", - " dem_list = [dem_ref, dem_far, thickness]\n", - " titles = ['DEM-Christian', 'DEM-Farinotti', 'Thickness']\n", - " clim = malib.calcperc(dem_list[0], (2,98))\n", - " plot3panel(dem_list, clim, titles, 'inferno', 'Elevation (m WGS84)', fn=fig_fp + glacno + '_dem.png')\n", - " # otherwise, use Farinotti\n", - " else:\n", - " dem = dem_far\n", - " dem_raw = dem_far_raw\n", - " \n", - " #Extract x and y pixel resolution (m) from geotransform\n", - " gt = ds_list[0].GetGeoTransform()\n", - " px_res = (gt[1], -gt[5])\n", - " #Calculate pixel area in m^2\n", - " px_area = px_res[0]*px_res[1]\n", - "\n", - " if debug:\n", - " print('\\nx_res [m]:', np.round(px_res[0],1), 'y_res[m]:', np.round(px_res[1],1),'\\n')\n", - "\n", - " # ===== USE SHAPEFILE OR SINGLE POLYGON TO CLIP =====\n", - " # shp_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/RGI/rgi60/01_rgi60_Alaska/01_rgi60_Alaska.shp'\n", - " # #Create binary mask from polygon shapefile to match our warped raster datasets\n", - " # shp_mask = geolib.shp2array(shp_fn, ds_list[0])\n", - " # #Now apply the mask to each array\n", - " # dem_list_shpclip = [np.ma.array(dem, mask=shp_mask) for dem in dem_list]\n", - " # plot3panel(dem_list_shpclip, clim, titles, 'inferno', 'Elevation (m WGS84)', fn=output_fp + 'dem_shpclp.png')\n", - " # rgi_alaska = gpd.read_file(shp_fn)\n", - " # print(rgi_alaska.head())\n", - " # rgi_alaska.plot();\n", - " # print(rgi_alaska.crs)\n", - " # # print('\\nGeometry_type:\\n',rgi_alaska[0:5].geom_type)\n", - " # # print('\\nArea (NOTE THESE ARE IN DEGREES!):\\n',rgi_alaska[0:5].geometry.area)\n", - " # # print('\\nBounds:\\n',rgi_alaska[0:5].geometry.bounds)\n", - " # rgi_alaska.plot(column='O2Region', categorical=True, legend=True, figsize=(14,6))\n", - " # rgiid = 'RGI60-' + glacno\n", - " # rgi_single = rgi_alaska[rgi_alaska['RGIId'] == rgiid]\n", - " # # export to\n", - " # rgi_single_fn = 'rgi_single.shp'\n", - " # rgi_single.to_file(rgi_single_fn)\n", - " # #Create binary mask from polygon shapefile to match our warped raster datasets\n", - " # rgi_single_mask = geolib.shp2array(rgi_single_fn, ds_list[0])\n", - " # #Now apply the mask to each array\n", - " # dem_list_shpclip = [np.ma.array(dem, mask=rgi_single_mask) for dem in dem_list]\n", - " # plot3panel(dem_list_shpclip, clim, titles, 'inferno', 'Elevation (m WGS84)', fn=output_fp + 'dem_single.png')\n", - " # =============================================================================================================\n", - "\n", - " if debug:\n", - " glacier_area_total = thickness.count() * px_res[0] * px_res[1] / 10**6\n", - " print(glacno, 'glacier area [km2]:', np.round(glacier_area_total,2),\n", - " 'vs RGI [km2]:', np.round(main_glac_rgi.loc[nglac,'Area'],2))\n", - "\n", - " # Remove negative elevation values\n", - " dem[dem < 0] = 0\n", - " dem.mask = thickness.mask\n", - "\n", - " elev_bin_min = binsize * (dem.min() / binsize).astype(int)\n", - " elev_bin_max = binsize * (dem.max() / binsize).astype(int) + binsize\n", - "\n", - " print(nglac, glacno, elev_bin_min, elev_bin_max)\n", - "\n", - " # if elev_bin_min < 0:\n", - " # print(nglac, glacno, elev_bin_min, elev_bin_max)\n", - " # debug_fp = input.output_sim_fp + 'debug/'\n", - " # # Create filepath if it does not exist\n", - " # if os.path.exists(debug_fp) == False:\n", - " # os.makedirs(debug_fp)\n", - " # debug_df = pd.DataFrame(np.zeros((1,1)), columns=['count'])\n", - " # debug_df.iloc[0,0] = 1\n", - " # debug_fn_loaded = str(glacno) + '_nglac' + str(nglac) + '_minlt0_.csv'\n", - " # debug_df.to_csv(debug_fp + debug_fn_loaded)\n", - "\n", - " elev_bin_edges = np.arange(elev_bin_min, elev_bin_max+binsize, binsize)\n", - " elev_bins = (elev_bin_edges[0:-1] + binsize/2).astype(int)\n", - " \n", - " # Hypsometry [km2]\n", - " # must used .compressed() in histogram to exclude masked values\n", - " hist, elev_bin_edges = np.histogram(dem.reshape(-1).compressed(), bins=elev_bin_edges)\n", - " bin_hyps = hist * px_res[0] * px_res[1] / 10**6\n", - " if debug:\n", - " print('Zmin/Zmax:', np.round(dem.min(),0), '/', np.round(dem.max(),0), '\\n')\n", - " print('elev_bin_edges:', elev_bin_edges)\n", - " print('hist:', hist)\n", - " print('total area:', hist.sum() * px_res[0] * px_res[1] / 10**6)\n", - "\n", - " # Mean thickness [m]\n", - " hist_thickness, elev_bin_edges = np.histogram(dem.reshape(-1).compressed(), bins=elev_bin_edges,\n", - " weights=thickness.reshape(-1).compressed())\n", - " bin_thickness = hist_thickness / hist\n", - "\n", - " # Mean Slope [deg]\n", - " # --> MAY WANT TO RESAMPLE TO SMOOTH DEM PRIOR TO ESTIMATING SLOPE\n", - " grad_x, grad_y = np.gradient(dem_raw, px_res[0], px_res[1])\n", - " slope = np.arctan(np.sqrt(grad_x ** 2 + grad_y ** 2))\n", - " slope_deg = np.rad2deg(slope)\n", - " slope_deg.mask = dem.mask\n", - " hist_slope, elev_bin_edges = np.histogram(dem.reshape(-1).compressed(), bins=elev_bin_edges,\n", - " weights=slope_deg.reshape(-1).compressed())\n", - " bin_slope = hist_slope / hist\n", - "\n", - " # Length [km] - based on the mean slope and bin elevation\n", - " bin_length = binsize / np.tan(np.deg2rad(bin_slope)) / 1000\n", - "\n", - " # Width [km] - based on length (inherently slope) and bin area\n", - " bin_width = bin_hyps / bin_length\n", - " \n", - " # Remove negative values\n", - " bin_hyps[bin_hyps < 0] = 0\n", - " bin_thickness[bin_thickness < 0] = 0\n", - " bin_width[bin_width < 0] = 0\n", - " bin_length[bin_length < 0] = 0\n", - " bin_slope[bin_slope < 0] = 0\n", - "\n", - " # Record properties\n", - " # Check if need to expand columns\n", - " missing_cns = sorted(list(set(elev_bins) - set(df_cns)))\n", - " if len(missing_cns) > 0:\n", - " for missing_cn in missing_cns:\n", - " main_glac_hyps[missing_cn] = 0\n", - " main_glac_thickness[missing_cn] = 0\n", - " main_glac_width[missing_cn] = 0\n", - " main_glac_length[missing_cn] = 0\n", - " main_glac_slope[missing_cn] = 0\n", - " # Record data\n", - " main_glac_hyps.loc[nglac, elev_bins] = bin_hyps\n", - " main_glac_thickness.loc[nglac, elev_bins] = bin_thickness\n", - " main_glac_width.loc[nglac, elev_bins] = bin_width\n", - " main_glac_length.loc[nglac, elev_bins] = bin_length\n", - " main_glac_slope.loc[nglac, elev_bins] = bin_slope\n", - "\n", - " # Remove NaN values\n", - " main_glac_hyps = main_glac_hyps.fillna(0)\n", - " main_glac_thickness = main_glac_thickness.fillna(0)\n", - " main_glac_width = main_glac_width.fillna(0)\n", - " main_glac_length = main_glac_length.fillna(0)\n", - " main_glac_slope = main_glac_slope.fillna(0)\n", - "# # Remove negative values\n", - "# main_glac_hyps[main_glac_hyps < 0] = 0\n", - "# main_glac_thickness[main_glac_thickness < 0] = 0\n", - "# main_glac_width[main_glac_width < 0] = 0\n", - "# main_glac_length[main_glac_length < 0] = 0\n", - "# main_glac_slope[main_glac_slope < 0] = 0\n", - " # Export results\n", - " main_glac_hyps.to_csv(output_fp + 'area_km2_' + \"{:02d}\".format(region) + '_Farinotti2019_' +\n", - " str(binsize) + 'm.csv', index=False)\n", - " main_glac_thickness.to_csv(output_fp + 'thickness_m_' + \"{:02d}\".format(region) + '_Farinotti2019_' +\n", - " str(binsize) + 'm.csv', index=False)\n", - " main_glac_width.to_csv(output_fp + 'width_km_' + \"{:02d}\".format(region) + '_Farinotti2019_' +\n", - " str(binsize) + 'm.csv', index=False)\n", - " main_glac_length.to_csv(output_fp + 'length_km_' + \"{:02d}\".format(region) + '_Farinotti2019_' +\n", - " str(binsize) + 'm.csv', index=False)\n", - " main_glac_slope.to_csv(output_fp + 'slope_deg_' + \"{:02d}\".format(region) + '_Farinotti2019_' +\n", - " str(binsize) + 'm.csv', index=False)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.7" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/Shean_mb_parallel_breakingdown.ipynb b/Shean_mb_parallel_breakingdown.ipynb deleted file mode 100644 index 1046de5a..00000000 --- a/Shean_mb_parallel_breakingdown.ipynb +++ /dev/null @@ -1,1520 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "#Function to generate a 3-panel plot for input arrays\n", - "def plot_array(dem, clim=None, titles=None, cmap='inferno', label=None, overlay=None, fn=None):\n", - " fig, ax = plt.subplots(1,1, sharex=True, sharey=True, figsize=(10,5))\n", - " alpha = 1.0\n", - " #Gray background\n", - " ax.set_facecolor('0.5')\n", - " #Force aspect ratio to match images\n", - " ax.set(aspect='equal')\n", - " #Turn off axes labels/ticks\n", - " ax.get_xaxis().set_visible(False)\n", - " ax.get_yaxis().set_visible(False)\n", - " if titles is not None:\n", - " ax.set_title(titles[0])\n", - " #Plot background shaded relief map\n", - " if overlay is not None:\n", - " alpha = 0.7\n", - " ax.imshow(overlay, cmap='gray', clim=(1,255))\n", - " #Plot each array\n", - " im_list = [ax.imshow(dem, clim=clim, cmap=cmap, alpha=alpha)]\n", - " fig.tight_layout()\n", - " fig.colorbar(im_list[0], label=label, extend='both', shrink=0.5)\n", - " if fn is not None:\n", - " fig.savefig(fn, bbox_inches='tight', pad_inches=0, dpi=150)\n", - "\n", - "#Function to generate a 3-panel plot for input arrays\n", - "def plot2panel(dem_list, clim=None, titles=None, cmap='inferno', label=None, overlay=None, fn=None):\n", - " fig, axa = plt.subplots(1,2, sharex=True, sharey=True, figsize=(10,5))\n", - " alpha = 1.0\n", - " for n, ax in enumerate(axa):\n", - " #Gray background\n", - " ax.set_facecolor('0.5')\n", - " #Force aspect ratio to match images\n", - " ax.set(aspect='equal')\n", - " #Turn off axes labels/ticks\n", - " ax.get_xaxis().set_visible(False)\n", - " ax.get_yaxis().set_visible(False)\n", - " if titles is not None:\n", - " ax.set_title(titles[n])\n", - " #Plot background shaded relief map\n", - " if overlay is not None:\n", - " alpha = 0.7\n", - " axa[n].imshow(overlay[n], cmap='gray', clim=(1,255))\n", - " #Plot each array\n", - " im_list = [axa[i].imshow(dem_list[i], clim=clim, cmap=cmap, alpha=alpha) for i in range(len(dem_list))]\n", - " fig.tight_layout()\n", - " fig.colorbar(im_list[0], ax=axa.ravel().tolist(), label=label, extend='both', shrink=0.5)\n", - " if fn is not None:\n", - " fig.savefig(fn, bbox_inches='tight', pad_inches=0, dpi=150)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Warping all inputs to the following:\n", - "Resolution: 30.0\n", - "Extent: [537155.67713055, 6545401.2408929, 695675.67713055, 6657601.2408929]\n", - "Projection: '+proj=utm +zone=7 +datum=WGS84 +units=m +no_defs '\n", - "Resampling alg: cubic\n", - "\n", - "1 of 2: /Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_03_PCRn/srtm_filled_ice__03_PCRn-utm07N-strips_crp2reg_03_PCRn.tif\n", - "nl: 3740 ns: 5284 res: 30.000\n", - "2 of 2: /Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_03_PCRn/dh_dt_on_ice__03_PCRn-utm07N-strips_crp2reg_03_PCRn.tif\n", - "\n", - "Static analysis does not work for quantifying uncertainty because clipped by RGI extents\n", - "\n", - "Opting to use UTM projections to avoid errors caused by projecting/resampling datasets\n", - "\n", - "Shp init crs: {'init': 'epsg:4326'}\n", - "Input glacier polygon count: 27108\n", - "Glacier polygon count after spatial filter: 1156\n", - "Min. Area filter glacier polygon count: 1156\n", - "Processing 1156 features\n", - "Loading /Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/Braun/output/Braun_PCR07N_glacfeat_list.p\n" - ] - } - ], - "source": [ - "#! /usr/bin/env python\n", - "\"\"\"\n", - "Compute dh/dt and mass balance for input DEMs and glacier polygons\n", - "\"\"\"\n", - "\n", - "\"\"\"\n", - "Todo:\n", - "GDAL_MAX_DATASET_POOL_SIZE - set to large number of open datasets in vrt\n", - "Better error estimates - use buffered dz/dt and semivariogram\n", - "Filling gaps using 1) dz/dt obs 2) setting to 0 around polygon margins\n", - "Curves for PRISM T an precip vs. mb\n", - "Move mb_plot_gpd funcitonality here, export polygons with mb numbers as geojson, spatialite, shp?\n", - "Add +/- std for each dh/dt polygon, some idea of spread\n", - "Create main function, pass args to mb_proc\n", - "Clean up mb_proc function, one return, globals\n", - "Better penetration correction\n", - "\"\"\"\n", - "\n", - "import sys\n", - "import os\n", - "import re\n", - "import subprocess\n", - "from datetime import datetime, timedelta\n", - "import time\n", - "import pickle\n", - "from collections import OrderedDict\n", - "\n", - "import geopandas as gpd\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import rasterio\n", - "from osgeo import gdal, ogr, osr\n", - "\n", - "from pygeotools.lib import malib, warplib, geolib, iolib, timelib\n", - "# from imview.lib import pltlib\n", - "\n", - "#Avoid printing out divide by 0 errors\n", - "np.seterr(all='ignore')\n", - "\n", - "\"\"\"\n", - "Class to store relevant feature attributes and derived values\n", - "Safe for multiprocessing\n", - "\"\"\"\n", - "class GlacFeat:\n", - " def __init__(self, feat, glacname_fieldname, glacnum_fieldname):\n", - "\n", - " self.glacname = feat.GetField(glacname_fieldname)\n", - " if self.glacname is None:\n", - " self.glacname = \"\"\n", - " else:\n", - " #RGI has some nonstandard characters\n", - " #self.glacname = self.glacname.decode('unicode_escape').encode('ascii','ignore')\n", - " #glacname = re.sub(r'[^\\x00-\\x7f]',r'', glacname)\n", - " self.glacname = re.sub(r'\\W+', '', self.glacname)\n", - " self.glacname = self.glacname.replace(\" \", \"\")\n", - " self.glacname = self.glacname.replace(\"_\", \"\")\n", - " self.glacname = self.glacname.replace(\"/\", \"\")\n", - "\n", - " self.glacnum = feat.GetField(glacnum_fieldname)\n", - " fn = feat.GetDefnRef().GetName()\n", - " #RGIId (String) = RGI50-01.00004\n", - " self.glacnum = '%0.5f' % float(self.glacnum.split('-')[-1])\n", - "\n", - " if self.glacname:\n", - " self.feat_fn = \"%s_%s\" % (self.glacnum, self.glacname)\n", - " else:\n", - " self.feat_fn = str(self.glacnum)\n", - "\n", - " self.glac_geom_orig = geolib.geom_dup(feat.GetGeometryRef())\n", - " self.glac_geom = geolib.geom_dup(self.glac_geom_orig)\n", - " #Hack to deal with fact that this is not preserved in geom when loaded from pickle on disk\n", - " self.glac_geom_srs_wkt = self.glac_geom.GetSpatialReference().ExportToWkt()\n", - "\n", - " #Attributes written by mb_calc\n", - " self.z1 = None\n", - " self.z1_hs = None\n", - " self.z1_stats = None\n", - " self.z1_ela = None\n", - " self.z2 = None\n", - " self.z2_hs = None\n", - " self.z2_stats = None\n", - " self.z2_ela = None\n", - " self.z2_aspect = None\n", - " self.z2_aspect_stats = None\n", - " self.z2_slope = None\n", - " self.z2_slope_stats = None\n", - " self.res = None\n", - " self.dhdt = None\n", - " self.mb = None\n", - " self.mb_mean = None\n", - " self.t1 = None\n", - " self.t2 = None\n", - " self.dt = None\n", - " self.t1_mean = None\n", - " self.t2_mean = None\n", - " self.dt_mean = None\n", - "\n", - " self.H = None\n", - " self.H_mean = np.nan\n", - " self.vx = None\n", - " self.vy = None\n", - " self.vm = None\n", - " self.vm_mean = np.nan\n", - " self.divQ = None\n", - " self.debris_class = None\n", - " self.debris_thick = None\n", - " self.debris_thick_mean = np.nan\n", - " self.perc_clean = np.nan\n", - " self.perc_debris = np.nan\n", - " self.perc_pond = np.nan\n", - "\n", - " def geom_srs_update(self, srs=None):\n", - " if self.glac_geom.GetSpatialReference() is None:\n", - " if srs is None:\n", - " srs = osr.SpatialReference()\n", - " srs.ImportFromWkt(self.glac_geom_srs_wkt)\n", - " self.glac_geom.AssignSpatialReference(srs)\n", - "\n", - " def geom_attributes(self, srs=None):\n", - " self.geom_srs_update()\n", - " if srs is not None:\n", - " #Should reproject here to equal area, before geom_attributes\n", - " #self.glac_geom.AssignSpatialReference(glac_shp_srs)\n", - " #self.glac_geom_local = geolib.geom2localortho(self.glac_geom)\n", - " geolib.geom_transform(self.glac_geom, srs)\n", - "\n", - " self.glac_geom_extent = geolib.geom_extent(self.glac_geom)\n", - " self.glac_area = self.glac_geom.GetArea()\n", - " self.glac_area_km2 = self.glac_area / 1E6\n", - " self.cx, self.cy = self.glac_geom.Centroid().GetPoint_2D()\n", - "\n", - "def srtm_corr(z):\n", - " #Should separate into different regions from Kaab et al (2012)\n", - " #Should separate into firn/snow, clean ice, and debris-covered ice\n", - "\n", - " #For now, use Kaab et al (2012) region-wide mean of 2.1 +/- 0.4\n", - " offset = 2.1\n", - " return z + offset\n", - "\n", - "def z_vs_dz(z,dz):\n", - " plt.scatter(z.compressed(), dz.compressed())\n", - "\n", - "#RGI uses 50 m bins\n", - "def hist_plot(gf, outdir, bin_width=50.0, dz_clim=(-2.0, 2.0)):\n", - " #print(\"Generating histograms\")\n", - " #Create bins for full range of input data and specified bin width\n", - "\n", - " #NOTE: these counts/areas are for valid pixels only\n", - " #Not necessarily a true representation of actual glacier hypsometry\n", - " #Need a void-filled DEM for this\n", - "\n", - " z_bin_edges, z_bin_centers = malib.get_bins(gf.z1, bin_width)\n", - " #Need to compress here, otherwise histogram uses masked values!\n", - " z1_bin_counts, z1_bin_edges = np.histogram(gf.z1.compressed(), bins=z_bin_edges)\n", - " z1_bin_areas = z1_bin_counts * gf.res[0] * gf.res[1] / 1E6\n", - " #RGI standard is integer thousandths of glaciers total area\n", - " #Should check to make sure sum of bin areas equals total area\n", - " #z1_bin_areas_perc = 100. * z1_bin_areas / np.sum(z1_bin_areas)\n", - " z1_bin_areas_perc = 100. * (z1_bin_areas / gf.glac_area_km2)\n", - "\n", - " #If we only have one elevation grid with dhdt\n", - " if gf.z2 is not None:\n", - " z2_bin_counts, z2_bin_edges = np.histogram(gf.z2.compressed(), bins=z_bin_edges)\n", - " z2_bin_areas = z2_bin_counts * gf.res[0] * gf.res[1] / 1E6\n", - " #z2_bin_areas_perc = 100. * z2_bin_areas / np.sum(z2_bin_areas)\n", - " z2_bin_areas_perc = 100. * (z1_bin_areas / gf.glac_area_km2)\n", - " else:\n", - " z2_bin_counts = z1_bin_counts\n", - " z2_bin_edges = z1_bin_edges\n", - " z2_bin_areas = z1_bin_areas\n", - " z2_bin_areas_perc = z1_bin_areas_perc\n", - "\n", - " #Create arrays to store output\n", - " if gf.dhdt is not None:\n", - " mb_bin_med = np.ma.masked_all_like(z1_bin_areas)\n", - " np.ma.set_fill_value(mb_bin_med, np.nan)\n", - " mb_bin_mad = np.ma.masked_all_like(mb_bin_med)\n", - " mb_bin_mean = np.ma.masked_all_like(mb_bin_med)\n", - " mb_bin_std = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_med = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_mad = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_mean = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_std = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_count = np.ma.masked_all_like(mb_bin_med)\n", - " if gf.vm is not None:\n", - " vm_bin_med = np.ma.masked_all_like(mb_bin_med)\n", - " vm_bin_mad = np.ma.masked_all_like(mb_bin_med)\n", - " if gf.H is not None:\n", - " H_bin_mean = np.ma.masked_all_like(mb_bin_med)\n", - " H_bin_std = np.ma.masked_all_like(mb_bin_med)\n", - " if gf.debris_class is not None:\n", - " perc_clean = np.ma.masked_all_like(mb_bin_med)\n", - " perc_debris = np.ma.masked_all_like(mb_bin_med)\n", - " perc_pond = np.ma.masked_all_like(mb_bin_med)\n", - " debris_thick_med = np.ma.masked_all_like(mb_bin_med)\n", - " debris_thick_mad = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_clean_bin_med = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_debris_bin_med = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_pond_bin_med = np.ma.masked_all_like(mb_bin_med)\n", - "\n", - " gf.dhdt_clean = np.ma.array(gf.dhdt, mask=~((gf.debris_class == 1).data))\n", - " gf.dhdt_debris = np.ma.array(gf.dhdt, mask=~((gf.debris_class == 2).data))\n", - " gf.dhdt_pond = np.ma.array(gf.dhdt, mask=~((gf.debris_class == 3).data))\n", - "\n", - " #Bin sample count must be greater than this value\n", - " min_bin_samp_count = 9\n", - "\n", - " #Loop through each bin and extract stats\n", - " idx = np.digitize(gf.z1, z_bin_edges)\n", - " for bin_n in range(z_bin_centers.size):\n", - " if gf.dhdt is not None:\n", - " mb_bin_samp = gf.mb_map[(idx == bin_n+1)]\n", - " if mb_bin_samp.count() > min_bin_samp_count:\n", - " mb_bin_med[bin_n] = malib.fast_median(mb_bin_samp)\n", - " mb_bin_mad[bin_n] = malib.mad(mb_bin_samp)\n", - " mb_bin_mean[bin_n] = mb_bin_samp.mean()\n", - " mb_bin_std[bin_n] = mb_bin_samp.std()\n", - " dhdt_bin_samp = gf.dhdt[(idx == bin_n+1)]\n", - " if dhdt_bin_samp.count() > min_bin_samp_count:\n", - " dhdt_bin_med[bin_n] = malib.fast_median(dhdt_bin_samp)\n", - " dhdt_bin_mad[bin_n] = malib.mad(dhdt_bin_samp)\n", - " dhdt_bin_mean[bin_n] = dhdt_bin_samp.mean()\n", - " dhdt_bin_std[bin_n] = dhdt_bin_samp.std()\n", - " dhdt_bin_count[bin_n] = dhdt_bin_samp.count()\n", - " if gf.debris_thick is not None:\n", - " debris_thick_bin_samp = gf.debris_thick[(idx == bin_n+1)]\n", - " if debris_thick_bin_samp.size > min_bin_samp_count:\n", - " debris_thick_med[bin_n] = malib.fast_median(debris_thick_bin_samp)\n", - " debris_thick_mad[bin_n] = malib.mad(debris_thick_bin_samp)\n", - " if gf.debris_class is not None:\n", - " debris_class_bin_samp = gf.debris_class[(idx == bin_n+1)]\n", - " dhdt_clean_bin_samp = gf.dhdt_clean[(idx == bin_n+1)]\n", - " dhdt_debris_bin_samp = gf.dhdt_debris[(idx == bin_n+1)]\n", - " dhdt_pond_bin_samp = gf.dhdt_pond[(idx == bin_n+1)]\n", - " if debris_class_bin_samp.count() > min_bin_samp_count:\n", - " perc_clean[bin_n] = 100. * (debris_class_bin_samp == 1).sum()/debris_class_bin_samp.count()\n", - " perc_debris[bin_n] = 100. * (debris_class_bin_samp == 2).sum()/debris_class_bin_samp.count()\n", - " perc_pond[bin_n] = 100. * (debris_class_bin_samp == 3).sum()/debris_class_bin_samp.count()\n", - " if dhdt_clean_bin_samp.count() > min_bin_samp_count:\n", - " dhdt_clean_bin_med[bin_n] = malib.fast_median(dhdt_clean_bin_samp)\n", - " if dhdt_debris_bin_samp.count() > min_bin_samp_count:\n", - " dhdt_debris_bin_med[bin_n] = malib.fast_median(dhdt_debris_bin_samp)\n", - " if dhdt_pond_bin_samp.count() > min_bin_samp_count:\n", - " dhdt_pond_bin_med[bin_n] = malib.fast_median(dhdt_pond_bin_samp)\n", - " if gf.vm is not None:\n", - " vm_bin_samp = gf.vm[(idx == bin_n+1)]\n", - " if vm_bin_samp.size > min_bin_samp_count:\n", - " vm_bin_med[bin_n] = malib.fast_median(vm_bin_samp)\n", - " vm_bin_mad[bin_n] = malib.mad(vm_bin_samp)\n", - " if gf.H is not None:\n", - " H_bin_samp = gf.H[(idx == bin_n+1)]\n", - " if H_bin_samp.size > min_bin_samp_count:\n", - " H_bin_mean[bin_n] = H_bin_samp.mean()\n", - " H_bin_std[bin_n] = H_bin_samp.std()\n", - "\n", - " dhdt_bin_areas = dhdt_bin_count * gf.res[0] * gf.res[1] / 1E6\n", - " #dhdt_bin_areas_perc = 100. * dhdt_bin_areas / np.sum(dhdt_bin_areas)\n", - " dhdt_bin_areas_perc = 100. * (dhdt_bin_areas / gf.glac_area_km2)\n", - "\n", - " outbins_header = 'bin_center_elev_m, z1_bin_count_valid, z1_bin_area_valid_km2, z1_bin_area_perc, z2_bin_count_valid, z2_bin_area_valid_km2, z2_bin_area_perc'\n", - " fmt = '%0.1f, %0.0f, %0.3f, %0.2f, %0.0f, %0.3f, %0.2f'\n", - " outbins = [z_bin_centers, z1_bin_counts, z1_bin_areas, z1_bin_areas_perc, z2_bin_counts, z2_bin_areas, z2_bin_areas_perc]\n", - " if gf.dhdt is not None:\n", - " outbins_header += ', dhdt_bin_count, dhdt_bin_area_valid_km2, dhdt_bin_area_perc, dhdt_bin_med_ma, dhdt_bin_mad_ma, dhdt_bin_mean_ma, dhdt_bin_std_ma, mb_bin_med_mwea, mb_bin_mad_mwea, mb_bin_mean_mwea, mb_bin_std_mwea'\n", - " fmt += ', %0.0f, %0.3f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f'\n", - " outbins.extend([dhdt_bin_count, dhdt_bin_areas, dhdt_bin_areas_perc, dhdt_bin_med, dhdt_bin_mad, dhdt_bin_mean, dhdt_bin_std, \\\n", - " mb_bin_med, mb_bin_mad, mb_bin_mean, mb_bin_std])\n", - " if gf.debris_thick is not None:\n", - " outbins_header += ', debris_thick_med_m, debris_thick_mad_m'\n", - " fmt += ', %0.2f, %0.2f'\n", - " debris_thick_med[debris_thick_med == -(np.inf)] = 0.00\n", - " debris_thick_mad[debris_thick_mad == -(np.inf)] = 0.00\n", - " outbins.extend([debris_thick_med, debris_thick_mad])\n", - " if gf.debris_class is not None:\n", - " outbins_header += ', perc_debris, perc_pond, perc_clean, dhdt_debris_med, dhdt_pond_med, dhdt_clean_med'\n", - " fmt += ', %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f'\n", - " outbins.extend([perc_debris, perc_pond, perc_clean, dhdt_debris_bin_med, dhdt_pond_bin_med, dhdt_clean_bin_med])\n", - " if gf.vm is not None:\n", - " outbins_header += ', vm_med, vm_mad'\n", - " fmt += ', %0.2f, %0.2f'\n", - " outbins.extend([vm_bin_med, vm_bin_mad])\n", - " if gf.H is not None:\n", - " outbins_header += ', H_mean, H_std'\n", - " fmt += ', %0.2f, %0.2f'\n", - " outbins.extend([H_bin_mean, H_bin_std])\n", - "\n", - " outbins = np.ma.array(outbins).T.astype('float32')\n", - " np.ma.set_fill_value(outbins, np.nan)\n", - " outbins = outbins.filled(np.nan)\n", - " outbins_fn = os.path.join(outdir, gf.feat_fn+'_mb_bins.csv')\n", - " np.savetxt(outbins_fn, outbins, fmt=fmt, delimiter=',', header=outbins_header)\n", - "\n", - " #Create plots of elevation bins\n", - " #print(\"Generating aed plot\")\n", - " #f,axa = plt.subplots(1,2, figsize=(6, 6))\n", - " nsubplots = 0\n", - " if gf.dhdt is not None:\n", - " nsubplots += 1\n", - " if gf.debris_thick is not None:\n", - " nsubplot += 1\n", - " if gf.vm is not None:\n", - " nsubplot += 1\n", - " f,axa = plt.subplots(1,nsubplots, figsize=(10, 7.5))\n", - " f.suptitle(gf.feat_fn)\n", - " fs = 9\n", - " nplot = -1\n", - " if gf.dhdt is not None:\n", - " nplot += 1\n", - " axa[nplot].plot(z1_bin_areas, z_bin_centers, label='%0.2f' % gf.t1_mean)\n", - " axa[nplot].axhline(gf.z1_ela, ls=':', c='C0')\n", - " if gf.z2 is not None:\n", - " axa[nplot].plot(z2_bin_areas, z_bin_centers, label='%0.2f' % gf.t2_mean)\n", - " axa[nplot].axhline(gf.z2_ela, ls=':', c='C1')\n", - " axa[nplot].legend(prop={'size':8}, loc='upper right')\n", - " axa[nplot].set_ylabel('Elevation (m WGS84)', fontsize=fs)\n", - " axa[nplot].set_xlabel('Area $\\mathregular{km^2}$', fontsize=fs)\n", - " axa[nplot].yaxis.set_ticks_position('both')\n", - " # pltlib.minorticks_on(axa[0])\n", - "\n", - " nplot += 1\n", - " axa[nplot].axvline(0, lw=1.0, c='k')\n", - " \"\"\"\n", - " #Plot flux divergence values for each bin\n", - " if gf.vm is not None and gf.H is not None:\n", - " divQ_bin_mean = np.gradient(H_bin_mean * vm_bin_med * v_col_f)\n", - " axa[1].plot(divQ_bin_mean, z_bin_centers, color='green')\n", - " \"\"\"\n", - " axa[nplot].plot(mb_bin_med, z_bin_centers, color='k')\n", - " axa[nplot].axvline(gf.mb_mean, lw=0.5, ls=':', c='k', label='%0.2f m w.e./yr' % gf.mb_mean)\n", - " axa[nplot].fill_betweenx(z_bin_centers, mb_bin_med-mb_bin_mad, mb_bin_med+mb_bin_mad, color='k', alpha=0.1)\n", - " axa[nplot].fill_betweenx(z_bin_centers, 0, mb_bin_med, where=(mb_bin_med<0), color='r', alpha=0.2)\n", - " axa[nplot].fill_betweenx(z_bin_centers, 0, mb_bin_med, where=(mb_bin_med>0), color='b', alpha=0.2)\n", - " #axa[nplot].set_xlabel('dh/dt (m/yr)')\n", - " axa[nplot].set_xlabel('Mass balance (m w.e./yr)', fontsize=fs)\n", - " axa[nplot].legend(prop={'size':8}, loc='upper right')\n", - " axa[nplot].yaxis.set_ticks_position('both')\n", - " # pltlib.minorticks_on(axa[1])\n", - " #Hide y-axis labels\n", - " axa[nplot].axes.yaxis.set_ticklabels([])\n", - " axa[nplot].set_xlim(*dz_clim)\n", - "\n", - " if gf.debris_thick is not None:\n", - " nplot += 1\n", - " axa[nplot].errorbar(debris_thick_med*100., z_bin_centers, xerr=debris_thick_mad*100, color='k', fmt='o', ms=3, label='Debris Thickness', alpha=0.6)\n", - " if gf.debris_class is not None:\n", - " axa[nplot].plot(perc_debris, z_bin_centers, color='sienna', label='Debris Coverage')\n", - " axa[nplot].plot(perc_pond, z_bin_centers, color='turquoise', label='Pond Coverage')\n", - " if gf.debris_thick is not None or gf.debris_class is not None:\n", - " axa[nplot].set_xlim(0, 100)\n", - " axa[nplot].yaxis.set_ticks_position('both')\n", - " # pltlib.minorticks_on(axa[2])\n", - " axa[nplot].axes.yaxis.set_ticklabels([])\n", - " axa[nplot].legend(prop={'size':8}, loc='upper right')\n", - " axa[nplot].set_xlabel('Debris thickness (cm), coverage (%)', fontsize=fs)\n", - "\n", - " if gf.vm is not None:\n", - " nplot += 1\n", - " ax4 = axa[nplot].twinx()\n", - " ax4.set_xlabel('Velocity (m/yr)', fontsize=fs)\n", - " ax4.plot(vm_bin_med, z_bin_centers, color='g', label='Vm (%0.2f m/yr)' % gf.vm_mean)\n", - " ax4.fill_betweenx(z_bin_centers, vm_bin_med-vm_bin_mad, vm_bin_med+vm_bin_mad, color='g', alpha=0.1)\n", - " #ax4.set_xlim(0, 50)\n", - " ax4.xaxis.tick_top()\n", - " ax4.xaxis.set_label_position(\"top\")\n", - " ax4.legend(prop={'size':8}, loc='upper right')\n", - "\n", - " if gf.H is not None:\n", - " axa[nplot].plot(H_bin_mean, z_bin_centers, color='b', label='H (%0.2f m)' % gf.H_mean)\n", - " axa[nplot].fill_betweenx(z_bin_centers, H_bin_mean-H_bin_std, H_bin_mean+H_bin_std, color='b', alpha=0.1)\n", - " axa[nplot].set_xlabel('Ice Thickness (m)', fontsize=fs)\n", - " axa[nplot].legend(prop={'size':8}, loc='lower right')\n", - " # pltlib.minorticks_on(axa[3])\n", - " #axa[nplot].set_xlim(0, 400)\n", - " axa[nplot].yaxis.tick_right()\n", - " axa[nplot].yaxis.set_ticks_position('both')\n", - " axa[nplot].yaxis.set_label_position(\"right\")\n", - "\n", - " plt.tight_layout()\n", - " #Make room for suptitle\n", - " plt.subplots_adjust(top=0.95, wspace=0.1)\n", - " #print(\"Saving aed plot\")\n", - " fig_fn = os.path.join(outdir, gf.feat_fn+'_mb_aed.png')\n", - " #plt.savefig(fig_fn, bbox_inches='tight', dpi=300)\n", - " plt.savefig(fig_fn, dpi=300)\n", - " plt.close(f)\n", - " return z_bin_edges\n", - "\n", - "def map_plot(gf, z_bin_edges, outdir, hs=True, dz_clim=(-2.0, 2.0)):\n", - " #print(\"Generating map plot\")\n", - " f,axa = plt.subplots(1,3, figsize=(10,7.5))\n", - " #f.suptitle(gf.feat_fn)\n", - " alpha = 1.0\n", - " if hs:\n", - " #z1_hs = geolib.gdaldem_wrapper(gf.out_z1_fn, product='hs', returnma=True, verbose=False)\n", - " #z2_hs = geolib.gdaldem_wrapper(gf.out_z2_fn, product='hs', returnma=True, verbose=False)\n", - " z1_hs = gf.z1_hs\n", - " z2_hs = gf.z2_hs\n", - " hs_clim = malib.calcperc(z2_hs, (2,98))\n", - " z1_hs_im = axa[0].imshow(z1_hs, cmap='gray', vmin=hs_clim[0], vmax=hs_clim[1])\n", - " z2_hs_im = axa[1].imshow(z2_hs, cmap='gray', vmin=hs_clim[0], vmax=hs_clim[1])\n", - " alpha = 0.5\n", - " z1_im = axa[0].imshow(gf.z1, cmap='cpt_rainbow', vmin=z_bin_edges[0], vmax=z_bin_edges[-1], alpha=alpha)\n", - " z2_im = axa[1].imshow(gf.z2, cmap='cpt_rainbow', vmin=z_bin_edges[0], vmax=z_bin_edges[-1], alpha=alpha)\n", - " axa[0].contour(gf.z1, [gf.z1_ela,], linewidths=0.5, linestyles=':', colors='w')\n", - " axa[1].contour(gf.z2, [gf.z2_ela,], linewidths=0.5, linestyles=':', colors='w')\n", - " #t1_title = int(np.round(gf.t1))\n", - " #t2_title = int(np.round(gf.t2))\n", - " t1_title = '%0.2f' % gf.t1_mean\n", - " t2_title = '%0.2f' % gf.t2_mean\n", - " #t1_title = gf.t1.strftime('%Y-%m-%d')\n", - " #t2_title = gf.t2.strftime('%Y-%m-%d')\n", - " axa[0].set_title(t1_title)\n", - " axa[1].set_title(t2_title)\n", - " axa[2].set_title('%s to %s (%0.2f yr)' % (t1_title, t2_title, gf.dt_mean))\n", - " dz_im = axa[2].imshow(gf.dhdt, cmap='RdBu', vmin=dz_clim[0], vmax=dz_clim[1])\n", - " for ax in axa:\n", - " # pltlib.hide_ticks(ax)\n", - " ax.set_facecolor('k')\n", - " # sb_loc = pltlib.best_scalebar_location(gf.z1)\n", - " # pltlib.add_scalebar(axa[0], gf.res[0], location=sb_loc)\n", - " # pltlib.add_cbar(axa[0], z1_im, label='Elevation (m WGS84)')\n", - " # pltlib.add_cbar(axa[1], z2_im, label='Elevation (m WGS84)')\n", - " # pltlib.add_cbar(axa[2], dz_im, label='dh/dt (m/yr)')\n", - " plt.tight_layout()\n", - " #Make room for suptitle\n", - " #plt.subplots_adjust(top=0.90)\n", - " #print(\"Saving map plot\")\n", - " fig_fn = os.path.join(outdir, gf.feat_fn+'_mb_map.png')\n", - " plt.savefig(fig_fn, dpi=300)\n", - " plt.close(f)\n", - "\n", - "def get_date_a(ds, date_shp_lyr, glac_geom_mask, datefield):\n", - " date_r_ds = iolib.mem_drv.CreateCopy('', ds)\n", - " #Shapefile order should be sorted by time, but might want to think about sorting here\n", - " #Can automatically search for datefield\n", - " gdal.RasterizeLayer(date_r_ds, [1], date_shp_lyr, options=[\"ATTRIBUTE=%s\" % datefield])\n", - " date_a = np.ma.array(iolib.ds_getma(date_r_ds), mask=glac_geom_mask)\n", - " #Note: NED dates are in integer years, assume source imagery was flown in late summer for mountains\n", - " if datefield == 'S_DATE_CLN':\n", - " date_a += 0.75\n", - " return date_a\n", - "\n", - "\"\"\"\n", - "#Consider storing setup variables in dictionary that can be passed to Process\n", - "setup = {}\n", - "setup['site'] = site\n", - "\"\"\"\n", - "\n", - "topdir='/Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/'\n", - "site = 'Braun_PCR07N'\n", - "# Braun options: ['Braun_PCR07N', 'Braun_PCR08N', 'Braun_PCR09N']\n", - "# site='StElias'\n", - "# site = 'Chugach'\n", - "# site = 'AR_W'\n", - "# site = 'AR_C'\n", - "# site = 'AR_E'\n", - "# site = 'Coast'\n", - "# site = 'Kenai'\n", - "# site = 'AK_Pen'\n", - "# Berthier options: ['StElias', 'Chugach', 'AR_W', 'AR_C', 'AR_E', 'Coast', 'Kenai', 'AK_Pen', 'HMA']\n", - "\n", - "#Filter glacier poly - let's stick with big glaciers for now\n", - "# min_glac_area = 0.0 #km^2\n", - "#min_glac_area = 0.1 #km^2\n", - "min_glac_area = 0 #km^2\n", - "# min_glac_area = 2. #km^2\n", - "#Only write out for larger glaciers\n", - "min_glac_area_writeout = 1.\n", - "#Minimum percentage of glacier poly covered by valid dz\n", - "min_valid_area_perc = 0.6 # DSHEAN WAS 0.85\n", - "#Process thickness, velocity, etc\n", - "extra_layers = False # DSHEAN WAS TRUE\n", - "#Write out DEMs and dz map\n", - "writeout = True\n", - "#Generate figures\n", - "mb_plot = True\n", - "#Run in parallel, set to False for serial loop\n", - "parallel = False\n", - "#Verbose for debugging\n", - "verbose = True\n", - "#Number of parallel processes\n", - "#Use all virtual cores\n", - "#nproc = iolib.cpu_count(logical=True) - 1\n", - "#Use all physical cores\n", - "# nproc = iolib.cpu_count(logical=False) - 1\n", - "nproc = 1\n", - "#Shortcut to use existing glacfeat_list.p if found\n", - "use_existing_glacfeat = True\n", - "\n", - "#Pad by this distance (meters) around glacier polygon for uncertainty estimates over surrounding surfaces\n", - "buff_dist = 1000\n", - "\n", - "#Bin width\n", - "bin_width = 50\n", - "\n", - "#Surface to column average velocity scaling\n", - "v_col_f = 0.8\n", - "\n", - "#This is recommendation by Huss et al (2013)\n", - "rho_is = 0.85\n", - "rho_sigma = 0.06\n", - "\n", - "#If breaking down into accumulation vs. ablation area\n", - "#rho_i = 0.91\n", - "#rho_s = 0.50\n", - "#rho_f = 0.60\n", - "\n", - "#Fountain\n", - "#Other sources Kaab et al (2012) use 0.1\n", - "area_sigma_perc = 0.09\n", - "\n", - "global z1_date\n", - "global z2_date\n", - "z1_date = None\n", - "z2_date = None\n", - "z1_srtm_penetration_corr = False\n", - "z2_srtm_penetration_corr = False\n", - "\n", - "\n", - "if site in ['Braun_PCR07N', 'Braun_PCR08N', 'Braun_PCR09N']:\n", - " #Output directory\n", - " outdir = topdir + 'Braun/output/'\n", - " outdir_fig = topdir + 'Braun/output/figures/'\n", - " outdir_csv = topdir + 'Braun/output/csv/'\n", - "\n", - " glac_shp_fn = topdir + '../RGI/rgi60/01_rgi60_Alaska/01_rgi60_Alaska.shp'\n", - " glacfeat_fn = outdir + site + '_glacfeat_list.p'\n", - "\n", - " # Filenames\n", - " z1_fn_dict = {'Braun_PCR07N': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_03_PCRn/srtm_filled_ice__03_PCRn-utm07N-strips_crp2reg_03_PCRn.tif',\n", - " 'Braun_PCR08N': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_03_PCRn/srtm_filled_ice__03_PCRn-utm08N-strips_crp2reg_03_PCRn.tif',\n", - " 'Braun_PCR09N': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_03_PCRn/srtm_filled_ice__03_PCRn-utm09N-strips_crp2reg_03_PCRn.tif'}\n", - " z1_date_dict = 2000.128\n", - " z2_fn_dict = None\n", - " z2_date_dict = 2012.0\n", - " dhdt_fn_dict = {'Braun_PCR07N': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_03_PCRn/dh_dt_on_ice__03_PCRn-utm07N-strips_crp2reg_03_PCRn.tif',\n", - " 'Braun_PCR08N': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_03_PCRn/dh_dt_on_ice__03_PCRn-utm08N-strips_crp2reg_03_PCRn.tif',\n", - " 'Braun_PCR09N': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_03_PCRn/dh_dt_on_ice__03_PCRn-utm09N-strips_crp2reg_03_PCRn.tif'}\n", - " \n", - " \n", - " z1_fn = z1_fn_dict[site]\n", - " z1_date = z1_date_dict\n", - " z1_sigma = 10\n", - " z1_srtm_penetration_corr = False\n", - "\n", - " if z2_fn_dict is None:\n", - " dhdt_fn = dhdt_fn_dict[site]\n", - "\n", - " # Hack - use z1 and dhdt to produce z2, so Shean processing scripts can be used for MB and binning calcs with Braun data\n", - " #Output projection\n", - " #'+proj=aea +lat_1=25 +lat_2=47 +lat_0=36 +lon_0=85 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs '\n", - " ds = gdal.Open(z1_fn)\n", - " prj = ds.GetProjection()\n", - " srs = osr.SpatialReference(wkt=prj)\n", - " aea_srs = srs\n", - " \n", - " #Warp everything to common res/extent/proj\n", - " ds_list = warplib.memwarp_multi_fn([z1_fn, dhdt_fn], \n", - " res='min', t_srs=aea_srs, verbose=verbose, r='cubic')\n", - " # DEM masks\n", - " ds_list_masked = [iolib.ds_getma(i) for i in ds_list]\n", - " z1 = np.ma.masked_less_equal(ds_list_masked[0], 0)\n", - " dhdt = ds_list_masked[1]\n", - " \n", - " # Create z2 from z1 and dhdt\n", - " z2 = z1 + dhdt * (z2_date_dict - z1_date_dict)\n", - " z2.mask = np.ma.mask_or(z1.mask, dhdt.mask)\n", - "\n", - " # Write out file\n", - " z2_fn = z1_fn.replace('srtm_filled_ice', 'z2_fromSTRM&dhdt')\n", - " iolib.writeGTiff(z2, z2_fn, src_ds=ds_list[0]) \n", - " \n", - " else:\n", - " z2_fn = z2_fn_dict[site]\n", - " z2_date = z2_date_dict\n", - " z2_sigma = 10\n", - " z2_srtm_penetration_corr = False\n", - " \n", - "\n", - " #Output projection\n", - " #'+proj=aea +lat_1=25 +lat_2=47 +lat_0=36 +lon_0=85 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs '\n", - " # print('\\n\\nSHOULD CHANGE TO EQUAL AREA PROJECTION!\\n\\n')\n", - " # aea_srs = geolib.hma_aea_srs\n", - " ds = gdal.Open(z1_fn)\n", - " prj = ds.GetProjection()\n", - " srs = osr.SpatialReference(wkt=prj)\n", - " aea_srs = srs\n", - "\n", - " #Surface velocity\n", - " # add surface velocities where possible?\n", - "\n", - " print('\\nStatic analysis does not work for quantifying uncertainty because clipped by RGI extents')\n", - " print('\\nOpting to use UTM projections to avoid errors caused by projecting/resampling datasets\\n')\n", - " \n", - "elif site in ['StElias', 'Chugach', 'AR_W', 'AR_C', 'AR_E', 'Coast', 'Kenai', 'AK_Pen']:\n", - " #Output directory\n", - " outdir = topdir + 'Berthier/output/'\n", - " outdir_fig = topdir + 'Berthier/output/figures/'\n", - " outdir_csv = topdir + 'Berthier/output/csv'\n", - "\n", - " glac_shp_fn = topdir + '../RGI/rgi60/01_rgi60_Alaska/01_rgi60_Alaska.shp'\n", - " glacfeat_fn = outdir + site + '_glacfeat_list.p'\n", - "\n", - " #ASTER+WV trend interp 2008\n", - " z1_fn_dict = {'StElias': topdir + 'Berthier/Alaska_1950_2006/1.StElias/StElias_Map_DEM.tif',\n", - " 'Chugach': topdir + 'Berthier/Alaska_1950_2006/2.Chugach/Chugach_Map_DEM.tif',\n", - " 'AR_W': topdir + 'Berthier/Alaska_1950_2006/3.AR_W/AR_W_Map_DEM.tif',\n", - " 'AR_C': topdir + 'Berthier/Alaska_1950_2006/4.AR_C/AR_C_Map_DEM.tif',\n", - " 'AR_E': topdir + 'Berthier/Alaska_1950_2006/5.AR_E/AR_E_Map_DEM.tif',\n", - " 'Coast': topdir + 'Berthier/Alaska_1950_2006/6.Coast/Coast_Map_DEM.tif',\n", - " 'Kenai': topdir + 'Berthier/Alaska_1950_2006/7.Kenai/Kenai_Map_DEM.tif',\n", - " 'AK_Pen': topdir + 'Berthier/Alaska_1950_2006/8.AK_Peninsula/AK_Peninsula_Map_DEM.tif',}\n", - " z1_date_dict = {'StElias': 1968.,\n", - " 'Chugach': 1954.,\n", - " 'AR_W': 1953.,\n", - " 'AR_C': 1953.,\n", - " 'AR_E': 1953.,\n", - " 'Coast': 1966.,\n", - " 'Kenai': 1950.,\n", - " 'AK_Pen': 1950.}\n", - " z2_fn_dict = {'StElias': topdir + 'Berthier/Alaska_1950_2006/1.StElias/StElias_Satellite_DEM.tif',\n", - " 'Chugach': topdir + 'Berthier/Alaska_1950_2006/2.Chugach/Chugach_Sat_DEM.tif',\n", - " 'AR_W': topdir + 'Berthier/Alaska_1950_2006/3.AR_W/AR_W_Sat_DEM.tif',\n", - " 'AR_C': topdir + 'Berthier/Alaska_1950_2006/4.AR_C/AR_C_Sat_DEM.tif',\n", - " 'AR_E': topdir + 'Berthier/Alaska_1950_2006/5.AR_E/AR_E_Sat_DEM.tif',\n", - " 'Coast': topdir + 'Berthier/Alaska_1950_2006/6.Coast/Coast_Sat_DEM.tif',\n", - " 'Kenai': topdir + 'Berthier/Alaska_1950_2006/7.Kenai/Kenai_Sat_DEM.tif',\n", - " 'AK_Pen': topdir + 'Berthier/Alaska_1950_2006/8.AK_Peninsula/AK_Peninsula_Sat_DEM.tif',}\n", - " z2_date_dict = {'StElias': 2006.75,\n", - " 'Chugach': 2006.75,\n", - " 'AR_W': 2004.75,\n", - " 'AR_C': 2004.75,\n", - " 'AR_E': 2004.75,\n", - " 'Coast': 2007.75,\n", - " 'Kenai': 2007.75,\n", - " 'AK_Pen': 2007.75}\n", - "\n", - " z1_fn = z1_fn_dict[site]\n", - " z1_date = z1_date_dict[site]\n", - " z1_sigma = 10\n", - " z1_srtm_penetration_corr = False\n", - "\n", - " #WV trend interp 2018\n", - " # z2_fn = topdir + 'Berthier/Alaska_1950_2006/1.StElias/StElias_Satellite_DEM.tif'\n", - " z2_fn = z2_fn_dict[site]\n", - " z2_date = z2_date_dict[site]\n", - " z2_sigma = 10\n", - " z2_srtm_penetration_corr = False\n", - "\n", - " #Output projection\n", - " #'+proj=aea +lat_1=25 +lat_2=47 +lat_0=36 +lon_0=85 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs '\n", - " # print('\\n\\nSHOULD CHANGE TO EQUAL AREA PROJECTION!\\n\\n')\n", - " # aea_srs = geolib.hma_aea_srs\n", - " ds = gdal.Open(z1_fn)\n", - " prj = ds.GetProjection()\n", - " srs = osr.SpatialReference(wkt=prj)\n", - " aea_srs = srs\n", - "\n", - " #Surface velocity\n", - " # add surface velocities where possible?\n", - "\n", - " print('\\nStatic analysis does not work for quantifying uncertainty because glacier exceeded RGI extents in 1950s')\n", - " print('\\nOpting to use UTM projections to avoid errors caused by projecting/resampling datasets\\n')\n", - "\n", - "elif site == 'hma':\n", - " glac_shp_fn = os.path.join(topdir,'data/rgi60/regions/rgi60_merge_HMA_aea.shp')\n", - " #glac_shp_fn = '/nobackupp8/deshean/hma/aster/dsm/aster_align_index_2000-2018_aea_stack/mb_test/rgi_ngozumpa.shp'\n", - " glacfeat_fn = os.path.splitext(glac_shp_fn)[0]+'_glacfeat_list.p'\n", - "\n", - " #ASTER+WV trend interp 2008\n", - " z1_fn = '/nobackupp8/deshean/hma/combined_aster_wv/dem_align_ASTER_WV_index_2000-2018_aea_stack/dem_align_ASTER_WV_index_2000-2018_aea_20000531_mos_retile.vrt'\n", - " z1_date = 2000.412\n", - " z1_sigma = 4.0\n", - " z1_srtm_penetration_corr = False\n", - "\n", - " #WV trend interp 2018\n", - " z2_fn = '/nobackupp8/deshean/hma/combined_aster_wv/dem_align_ASTER_WV_index_2000-2018_aea_stack/dem_align_ASTER_WV_index_2000-2018_aea_20180531_mos_retile.vrt'\n", - " z2_date = 2018.412\n", - " z2_sigma = 4.0\n", - " z2_srtm_penetration_corr = False\n", - "\n", - " #Output directory\n", - " outdir = os.path.join(os.path.split(z2_fn)[0], 'mb_combined_20190206')\n", - " outdir_fig = outdir\n", - " outdir_csv = outdir\n", - " #outdir = '/nobackup/deshean/hma/aster/dsm/aster_align_index_2000-2018_aea_stack/mb'\n", - "\n", - " #Output projection\n", - " #'+proj=aea +lat_1=25 +lat_2=47 +lat_0=36 +lon_0=85 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs '\n", - " aea_srs = geolib.hma_aea_srs\n", - "\n", - " #Surface velocity\n", - " #Note: had to force srs on Amaury's original products\n", - " #gdal_edit.py -a_srs '+proj=lcc +lat_1=28 +lat_2=32 +lat_0=90 +lon_0=85 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs' fn\n", - " #v_dir = '/nobackup/deshean/rpcdem/hma/velocity_jpl_amaury_2013-2015'\n", - " v_dir = '/nobackup/deshean/data/jpl_vel'\n", - " vx_fn = os.path.join(v_dir, 'HMA_G0240_0000_vx_masked.tif')\n", - " vy_fn = os.path.join(v_dir, 'HMA_G0240_0000_vy_masked.tif')\n", - "\n", - "else:\n", - " sys.exit(\"Must specify input site\")\n", - "\n", - "\n", - " \n", - "if not os.path.exists(outdir):\n", - " os.makedirs(outdir)\n", - "if not os.path.exists(outdir_fig):\n", - " os.makedirs(outdir_fig)\n", - "if not os.path.exists(outdir_csv):\n", - " os.makedirs(outdir_csv)\n", - "\n", - "ts = datetime.now().strftime('%Y%m%d_%H%M')\n", - "out_fn = '%s_mb_%s.csv' % (site, ts)\n", - "out_fn = os.path.join(outdir, out_fn)\n", - "\n", - "#List to hold output\n", - "out = []\n", - "\n", - "if 'rgi' in glac_shp_fn:\n", - " #Use RGI\n", - " glacname_fieldname = \"Name\"\n", - " #RGIId (String) = RGI50-01.00004\n", - " glacnum_fieldname = \"RGIId\"\n", - " glacnum_fmt = '%08.5f'\n", - "else:\n", - " sys.exit('Unrecognized glacier shp filename')\n", - "\n", - "#Set up output header\n", - "#out_header = '%s,x,y,z_med,z_min,z_max,z_p16,z_p84,z_slope,z_aspect,dhdt_ma,dhdt_ma_sigma,mb_mwea,mb_mwea_sigma,area_m2,mb_m3wea,mb_m3wea_sigma,t1,t2,dt,valid_area_perc' % glacnum_fieldname\n", - "out_header = '%s,x,y,z_med,z_min,z_max,z_slope,z_aspect,dhdt_ma,dhdt_ma_sigma,mb_mwea,mb_mwea_sigma,area_m2,mb_m3wea,mb_m3wea_sigma,t1,t2,dt,valid_area_perc' % glacnum_fieldname\n", - "if extra_layers:\n", - " out_header += ',H_m'\n", - " if site == 'hma':\n", - " out_header += ',debris_m,perc_debris,perc_pond,perc_clean'\n", - " out_header += ',vm_ma'\n", - "\n", - "nf = len(out_header.split(','))\n", - "out_fmt = [glacnum_fmt,] + ['%0.3f'] * (nf - 1)\n", - "\n", - "\n", - "# Shape layer processing\n", - "glac_shp_init = gpd.read_file(glac_shp_fn)\n", - "if verbose:\n", - " print('Shp init crs:', glac_shp_init.crs)\n", - "# ax = glac_shp_wgs84.plot()\n", - "# ax.set_title(\"WGS84 (lat/lon)\"\n", - "\n", - "# If projected shapefile already exists, then skip projection\n", - "glac_shp_proj_fn = (outdir + glac_shp_fn.split('/')[-1].replace('.shp','_crs' +\n", - " str(aea_srs.GetAttrValue(\"AUTHORITY\", 1)) + '.shp'))\n", - "if os.path.exists(glac_shp_proj_fn) == False:\n", - " glac_shp_proj = glac_shp_init.to_crs({'init': 'epsg:' + str(aea_srs.GetAttrValue(\"AUTHORITY\", 1))})\n", - " glac_shp_proj.to_file(glac_shp_proj_fn)\n", - "\n", - "glac_shp_ds = ogr.Open(glac_shp_proj_fn, 0)\n", - "glac_shp_lyr = glac_shp_ds.GetLayer()\n", - "#This should be contained in features\n", - "glac_shp_srs = glac_shp_lyr.GetSpatialRef()\n", - "feat_count = glac_shp_lyr.GetFeatureCount()\n", - "print(\"Input glacier polygon count: %i\" % feat_count)\n", - "\n", - "z1_ds = gdal.Open(z1_fn)\n", - "z2_ds = gdal.Open(z2_fn)\n", - "dz_int_geom = geolib.ds_geom_intersection([z1_ds, z2_ds], t_srs=glac_shp_srs)\n", - "\n", - "#Spatial filter\n", - "glac_shp_lyr.SetSpatialFilter(dz_int_geom)\n", - "feat_count = glac_shp_lyr.GetFeatureCount()\n", - "print(\"Glacier polygon count after spatial filter: %i\" % feat_count)\n", - "glac_shp_lyr.ResetReading()\n", - "\n", - "#Area filter\n", - "glac_shp_lyr.SetAttributeFilter(\"Area > %s\" % min_glac_area)\n", - "feat_count = glac_shp_lyr.GetFeatureCount()\n", - "print(\"Min. Area filter glacier polygon count: %i\" % feat_count)\n", - "glac_shp_lyr.ResetReading()\n", - "\n", - "print(\"Processing %i features\" % feat_count)\n", - "\n", - "#Set higher stripe count so we're not thrashing one disk\n", - "#cmd = ['lfs', 'setstripe', '-c', str(nproc), outdir]\n", - "#subprocess.call(cmd)\n", - "# iolib.setstripe(outdir, nproc) # REMOVED THIS BECAUSE IT WAS CAUSING subprocess error - likely for spc?\n", - "\n", - "#Create a list of glacfeat objects (contains geom) - safe for multiprocessing, while OGR layer is not\n", - "if os.path.exists(glacfeat_fn) and use_existing_glacfeat:\n", - " print(\"Loading %s\" % glacfeat_fn)\n", - " #This fails to load geometry srs\n", - " glacfeat_list = pickle.load(open(glacfeat_fn,\"rb\"))\n", - "else:\n", - " glacfeat_list = []\n", - " print(\"Generating %s\" % glacfeat_fn)\n", - " for n, feat in enumerate(glac_shp_lyr):\n", - " gf = GlacFeat(feat, glacname_fieldname, glacnum_fieldname)\n", - " print(\"%i of %i: %s\" % (n+1, feat_count, gf.feat_fn))\n", - " #Calculate area, extent, centroid\n", - " #NOTE: Input must be in projected coordinate system, ideally equal area\n", - " #Should check this and reproject\n", - " gf.geom_attributes(srs=aea_srs)\n", - " glacfeat_list.append(gf)\n", - " pickle.dump(glacfeat_list, open(glacfeat_fn,\"wb\"))\n", - "\n", - "glac_shp_lyr = None\n", - "glac_shp_ds = None" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# # ===== TESTING Z2 CREATION WORKS =====\n", - "# #Warp everything to common res/extent/proj\n", - "# ds_list = warplib.memwarp_multi_fn([z1_fn, dhdt_fn, z2_fn], \n", - "# res='min', t_srs=aea_srs, verbose=verbose, r='cubic')\n", - "# # DEM masks\n", - "# ds_list_masked = [iolib.ds_getma(i) for i in ds_list]\n", - "# z1 = np.ma.masked_less_equal(ds_list_masked[0], 0)\n", - "# dhdt = ds_list_masked[1]\n", - "# z2 = ds_list_masked[2]\n", - "\n", - "# titles = ['z1']\n", - "# clim = malib.calcperc(z1, (2,98))\n", - "# plot_array(z1, clim, titles, 'inferno', 'Elevation (m WGS84)', fn='z1.png')\n", - "\n", - "# titles = ['dhdt']\n", - "# clim = malib.calcperc(dhdt, (2,98))\n", - "# plot_array(dhdt, clim, titles, 'inferno', 'Elevation (m WGS84)', fn='z1.png')\n", - "\n", - "# titles = ['z2']\n", - "# clim = malib.calcperc(z2, (2,98))\n", - "# plot_array(z2, clim, titles, 'inferno', 'Elevation (m WGS84)', fn='z2.png')" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# For testing\n", - "# glacfeat_list_in = [glacfeat_list[240]]\n", - "glacfeat_list_in = glacfeat_list[0:2]\n", - "# glacfeat_list_in = glacfeat_list\n", - "\n", - "#This is a hack to limit processing for just a few glaciers\n", - "glac_dict = None\n", - "#Ngozumpa, Khumbu etc\n", - "#glac_dict = ['15.03474', '15.03733', '15.10070', '15.09991']\n", - "\n", - "if glac_dict:\n", - " glacfeat_list_in = []\n", - " for i in glacfeat_list:\n", - " if i.glacnum in glac_dict:\n", - " glacfeat_list_in.append(i)\n", - "\n", - "gf = glacfeat_list_in[0]" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1.12645_EastYakutatGlacier\n", - "output_fn: /Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/Braun/output/1.12645_EastYakutatGlacier_mb.csv\n" - ] - } - ], - "source": [ - "print(gf.feat_fn)\n", - "\n", - "out_csv_fn = os.path.join(outdir, gf.feat_fn+'_mb.csv')\n", - "if verbose:\n", - " print('output_fn:', out_csv_fn)\n", - "if not os.path.exists(out_csv_fn):\n", - " #This should already be handled by earlier attribute filter, but RGI area could be wrong\n", - " if gf.glac_area_km2 < min_glac_area:\n", - " if verbose:\n", - " print(\"Glacier area of %0.1f is below %0.1f km2 threshold\" % (gf.glac_area_km2, min_glac_area))\n", - "# return None\n", - "\n", - " fn_dict = OrderedDict()\n", - " #We at least want to warp the two input DEMs\n", - " fn_dict['z1'] = z1_fn\n", - " fn_dict['z2'] = z2_fn\n", - "\n", - " if extra_layers and (gf.glac_area_km2 > min_glac_area_writeout):\n", - " #Attempt to load Huss ice thickness grid\n", - " huss_dir = os.path.join(topdir, 'data/huss')\n", - " ice_thick_fn = os.path.join(huss_dir, 'RGI%02i_thick/thickness/thick_%05i.agr' % \\\n", - " tuple(map(int, gf.glacnum.split('.'))))\n", - " if os.path.exists(ice_thick_fn):\n", - " fn_dict['ice_thick'] = ice_thick_fn\n", - "\n", - " if site == 'hma':\n", - " #Add debris cover datasets\n", - " #Should tar these up, and extract only necessary file\n", - " #Downloaded from: http://mountainhydrology.org/data-nature-2017/\n", - " kra_nature_dir = '/nobackup/deshean/data/Kraaijenbrink_hma/regions/out'\n", - " #This assumes that numbers are identical between RGI50 and RGI60\n", - " debris_class_fn = os.path.join(kra_nature_dir, 'RGI50-%s/classification.tif' % gf.glacnum)\n", - " debris_thick_fn = os.path.join(kra_nature_dir, 'RGI50-%s/debris-thickness-50cm.tif' % gf.glacnum)\n", - " #ice_thick_fn = os.path.join(kra_nature_dir, 'RGI50-%s/ice-thickness.tif' % gf.glacnum)\n", - " if os.path.exists(debris_class_fn):\n", - " fn_dict['debris_class'] = debris_class_fn\n", - " if os.path.exists(debris_thick_fn):\n", - " fn_dict['debris_thick'] = debris_thick_fn\n", - " if os.path.exists(vx_fn):\n", - " fn_dict['vx'] = vx_fn\n", - " fn_dict['vy'] = vy_fn\n", - "\n", - " if z1_date is None:\n", - " #Rasterize source dates\n", - " #Note: need to clean this up, as glac_geom_mask is not defined\n", - " if os.path.splitext(z1_date_fn)[1] == 'shp':\n", - " z1_date = get_date_a(ds_dict['z1'], z1_date_shp_lyr, glac_geom_mask, z1_datefield)\n", - " gf.t1 = z1_date.mean()\n", - " else:\n", - " #Otherwise, clip the timestamp array\n", - " fn_dict['z1_date'] = z1_date_fn\n", - " else:\n", - " gf.t1 = z1_date\n", - "\n", - " if z2_date is None:\n", - " if os.path.splitext(z2_date_fn)[1] == 'shp':\n", - " z2_date = get_date_a(ds_dict['z2'], z2_date_shp_lyr, glac_geom_mask, z2_datefield)\n", - " gf.t1 = z2_date.mean()\n", - " else:\n", - " fn_dict['z2_date'] = z2_date_fn\n", - " else:\n", - " gf.t2 = z2_date\n", - "\n", - " #Expand extent to include buffered region around glacier polygon\n", - " warp_extent = geolib.pad_extent(gf.glac_geom_extent, width=buff_dist)\n", - " if verbose:\n", - " print(\"Expanding extent\")\n", - " print(gf.glac_geom_extent)\n", - " print(warp_extent)\n", - "\n", - " #Warp everything to common res/extent/proj\n", - " ds_list = warplib.memwarp_multi_fn(fn_dict.values(), res='min', \\\n", - " extent=warp_extent, t_srs=aea_srs, verbose=verbose, \\\n", - " r='cubic')\n", - "\n", - " ds_dict = dict(zip(fn_dict.keys(), ds_list))\n", - "\n", - " #Prepare mask for all glaciers within buffered area, not just the current glacier polygon\n", - " glac_shp_ds = ogr.Open(glac_shp_proj_fn, 0)\n", - " glac_shp_lyr = glac_shp_ds.GetLayer()\n", - " #Spatial filter\n", - " #glac_shp_lyr.SetSpatialFilter(geom)\n", - "\n", - " #Get global glacier mask\n", - " #Want this to be True over ALL glacier surfaces, not just the current polygon\n", - " glac_shp_lyr_mask = geolib.lyr2mask(glac_shp_lyr, ds_dict['z1'])\n", - "\n", - " #geom srs is not preserved when loaded from disk, attempt to reassign\n", - " gf.geom_srs_update()\n", - " #Create buffer around glacier polygon\n", - " glac_geom_buff = gf.glac_geom.Buffer(buff_dist)\n", - " #This is False over glacier polygon surface, True elsewhere - can be applied directly\n", - " glac_geom_buff_mask = geolib.geom2mask(glac_geom_buff, ds_dict['z1'])\n", - "\n", - " # DEM masks\n", - " ds_list_masked = [iolib.ds_getma(i) for i in ds_list]\n", - " dem1 = np.ma.masked_less_equal(ds_list_masked[0], 0)\n", - " dem2 = np.ma.masked_less_equal(ds_list_masked[1], 0)\n", - " dems_mask = np.ma.mask_or(dem1.mask, dem2.mask)\n", - " # dem1 = ds_list_masked[0]\n", - " # dem1 = np.ma.masked_less_equal(dem1, 0)\n", - " # dem2 = ds_list_masked[1]\n", - " # dem2 = np.ma.masked_less_equal(dem2, 0)\n", - " # dems_mask = np.ma.mask_or(dem1.mask, dem2.mask\n", - "\n", - " #Combine to identify ~1 km buffer around glacier polygon over static rock\n", - " static_buffer_mask = np.ma.mask_or(~glac_shp_lyr_mask, glac_geom_buff_mask)\n", - " static_shp_lyr_mask = np.ma.mask_or(static_buffer_mask, dems_mask)\n", - "\n", - "\n", - " if 'z1' in ds_dict:\n", - " #This is False over glacier polygon surface, True elsewhere - can be applied directly\n", - " glac_geom_mask = geolib.geom2mask(gf.glac_geom, ds_dict['z1'])\n", - " gf.z1 = np.ma.array(iolib.ds_getma(ds_dict['z1']))\n", - " #gf.z1 = np.ma.array(iolib.ds_getma(ds_dict['z1']), mask=glac_geom_mask)\n", - " print('\\n\\n# z1 pixels:', gf.z1.count(), '\\n')\n", - " if gf.z1.count() == 0:\n", - " if verbose:\n", - " print(\"No z1 pixels\")\n", - "# return None\n", - " else:\n", - " print(\"Unable to load z1 ds\")\n", - "# return None\n", - "\n", - " if 'z2' in ds_dict:\n", - " gf.z2 = iolib.ds_getma(ds_dict['z2'])\n", - " print('\\n\\n# z2 pixels:', gf.z2.count(), '\\n')\n", - " if gf.z2.count() == 0:\n", - " if verbose:\n", - " print(\"No z2 pixels\")\n", - "# return None\n", - " else:\n", - " print(\"Unable to load z2 ds\")\n", - "# return None\n", - "\n", - " #Apply SRTM penetration correction\n", - " #Do this only over glaciers, not static rock?\n", - " if z1_srtm_penetration_corr:\n", - " gf.z1 = srtm_corr(gf.z1)\n", - " if z2_srtm_penetration_corr:\n", - " gf.z2 = srtm_corr(gf.z2)\n", - " #gf.z2 = np.ma.array(gf.z2, mask=glac_geom_mask)\n", - " gf.dz = gf.z2 - gf.z1\n", - " if gf.dz.count() == 0:\n", - " if verbose:\n", - " print(\"No valid dz pixels\")\n", - "# return None\n", - "\n", - " #Should add better filtering here\n", - " #Elevation dependent abs. threshold filter?\n", - "\n", - " filter_outliers = False\n", - " #Remove clearly bogus pixels\n", - " if filter_outliers:\n", - " bad_perc = (0.1, 99.9)\n", - " #bad_perc = (1, 99)\n", - " rangelim = malib.calcperc(gf.dz, bad_perc)\n", - " gf.dz = np.ma.masked_outside(gf.dz, *rangelim)\n", - "\n", - " #Preserve full dz map\n", - " gf.dz_full = gf.dz\n", - "\n", - " #Compute stats for \"static\" surfaces (non-glacier)\n", - " gf.dz_static = np.ma.array(gf.dz, mask=static_shp_lyr_mask)\n", - " gf.dz_static_stats = malib.get_stats(gf.dz_static)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "ename": "AttributeError", - "evalue": "'GlacFeat' object has no attribute 'dz_full'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mtitles\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'DZ-Full (Satellite-Map)'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mdz_full2plot\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdz_full\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mdz_full2plot\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmask\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdems_mask\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mclim\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmalib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcalcperc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdz_full2plot\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m98\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mplot_array\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdz_full2plot\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mclim\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtitles\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'inferno'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'Elevation (m WGS84)'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfn\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'dem.png'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mAttributeError\u001b[0m: 'GlacFeat' object has no attribute 'dz_full'" - ] - } - ], - "source": [ - "titles = ['DZ-Full (Satellite-Map)']\n", - "dz_full2plot = gf.dz_full\n", - "dz_full2plot.mask = dems_mask\n", - "clim = malib.calcperc(dz_full2plot, (2,98))\n", - "plot_array(dz_full2plot, clim, titles, 'inferno', 'Elevation (m WGS84)', fn='dem.png')\n", - "\n", - "titles = ['DZ-Static (Satellite-Map)']\n", - "clim = malib.calcperc(gf.dz_static, (2,98))\n", - "plot_array(gf.dz_static, clim, titles, 'inferno', 'Elevation (m WGS84)', fn='dem.png')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Plot single glacier\n", - "rgiid = 'RGI60-' + gf.feat_fn.split('_')[0].split('.')[0].zfill(2) + '.' + gf.feat_fn.split('_')[0].split('.')[1]\n", - "glac_shp_proj = gpd.read_file(glac_shp_proj_fn)\n", - "glac_shp_single = glac_shp_proj[glac_shp_proj['RGIId'] == rgiid]\n", - "glac_shp_single = glac_shp_single.reset_index()\n", - "\n", - "# Plot over region of interest\n", - "ax = glac_shp_proj.plot()\n", - "xlim = (warp_extent[0], warp_extent[2])\n", - "ylim = (warp_extent[1], warp_extent[3])\n", - "ax.set_xlim(xlim)\n", - "ax.set_ylim(ylim)\n", - "ax.set_title(\"UTM (m)\")\n", - "\n", - "ax = glac_shp_single.plot()\n", - "xlim = (warp_extent[0], warp_extent[2])\n", - "ylim = (warp_extent[1], warp_extent[3])\n", - "ax.set_xlim(xlim)\n", - "ax.set_ylim(ylim)\n", - "ax.set_title(\"UTM (m)\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Now apply glacier mask AND mask NaN values\n", - "glac_geom_mask = np.ma.mask_or(glac_geom_mask, dems_mask)\n", - "nan_mask = np.ma.masked_invalid(gf.dz)\n", - "glac_geom_mask = np.ma.mask_or(glac_geom_mask, nan_mask.mask)\n", - "gf.z1 = np.ma.array(gf.z1, mask=glac_geom_mask)\n", - "gf.z2 = np.ma.array(gf.z2, mask=glac_geom_mask)\n", - "gf.dz = np.ma.array(gf.dz, mask=glac_geom_mask)\n", - "\n", - "gf.res = geolib.get_res(ds_dict['z1'])\n", - "\n", - "print('dz_count:', gf.dz.count())\n", - "# print(gf.dz.compressed()))\n", - "\n", - "#Compute area covered by valid pixels in m2\n", - "gf.valid_area = gf.dz.count() * gf.res[0] * gf.res[1]\n", - "#Compute percentage covered by total area of polygon\n", - "gf.valid_area_perc = 100. * (gf.valid_area / gf.glac_area)\n", - "if verbose:\n", - " print('valid area %:', gf.valid_area_perc)\n", - "\n", - "titles = ['DZ-GLACIER (Satellite-Map)']\n", - "clim = malib.calcperc(gf.dz, (2,98))\n", - "plot_array(gf.dz, clim, titles, 'inferno', 'Elevation (m WGS84)', fn='dem.png')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "if gf.valid_area_perc < (100. * min_valid_area_perc):\n", - " if verbose:\n", - " print(\"Not enough valid pixels. %0.1f%% percent of glacier polygon area\" % (gf.valid_area_perc))\n", - "# return None\n", - "\n", - "else:\n", - " #Filter dz - throw out abs differences >150 m\n", - "\n", - " #Compute dz, volume change, mass balance and stats\n", - " gf.z1_stats = malib.get_stats(gf.z1)\n", - " gf.z2_stats = malib.get_stats(gf.z2)\n", - "\n", - " #Should probably take mean of z1 and z2 here\n", - " #For cases where WV/GE is z2, maybe best to take\n", - " z2_elev_med = gf.z2_stats[5]\n", - " #z2_elev_min = gf.z2_stats[1]\n", - " #z2_elev_max = gf.z2_stats[2]\n", - " z2_elev_min, z2_elev_max = malib.calcperc(gf.z2, (0.1, 99.9))\n", - " #z2_elev_p16 = gf.z2_stats[11]\n", - " #z2_elev_p84 = gf.z2_stats[12]\n", - " \n", - " #Caluclate stats for aspect and slope using z2\n", - " #Requires GDAL 2.1+\n", - " gf.z2_aspect = np.ma.array(geolib.gdaldem_mem_ds(ds_dict['z2'], processing='aspect', returnma=True), mask=glac_geom_mask)\n", - " gf.z2_aspect_stats = malib.get_stats(gf.z2_aspect)\n", - " z2_aspect_med = gf.z2_aspect_stats[5]\n", - " gf.z2_slope = np.ma.array(geolib.gdaldem_mem_ds(ds_dict['z2'], processing='slope', returnma=True), mask=glac_geom_mask)\n", - " gf.z2_slope_stats = malib.get_stats(gf.z2_slope)\n", - " z2_slope_med = gf.z2_slope_stats[5]\n", - "\n", - " #Load timestamp array, if available\n", - " if 'z1_date' in ds_dict:\n", - " gf.t1 = iolib.ds_getma(ds_dict['z1_date'])\n", - " else:\n", - " if isinstance(gf.t1, datetime):\n", - " gf.t1 = float(timelib.dt2decyear(gf.t1))\n", - " #else, assume we've hardcoded decimal year\n", - " gf.t1_mean = np.mean(gf.t1)\n", - "\n", - " if 'z2_date' in ds_dict:\n", - " gf.t2 = iolib.ds_getma(ds_dict['z2_date'])\n", - " else:\n", - " if isinstance(gf.t2, datetime):\n", - " gf.t2 = float(timelib.dt2decyear(gf.t2))\n", - " #else, assume we've hardcoded decimal year\n", - " gf.t2_mean = np.mean(gf.t2)\n", - "\n", - " #These should be decimal years, either grids or constants\n", - " gf.dt = gf.t2 - gf.t1\n", - " gf.dt_mean = np.mean(gf.dt)\n", - " #if isinstance(gf.dt, timedelta):\n", - " # gf.dt = gf.dt.total_seconds()/timelib.spy\n", - " \n", - " #Calculate dh/dt, in m/yr\n", - " gf.dhdt = gf.dz/gf.dt\n", - " gf.dhdt_sum = gf.dhdt.sum()\n", - " gf.dhdt_stats = malib.get_stats_dict(gf.dhdt)\n", - " gf.dhdt_mean = gf.dhdt_stats['mean']\n", - " gf.dhdt_med = gf.dhdt_stats['med']\n", - " gf.dhdt_nmad = gf.dhdt_stats['nmad']\n", - " \n", - " gf.dhdt_static = gf.dz_static/gf.dt\n", - " gf.dhdt_static_stats = malib.get_stats_dict(gf.dhdt_static)\n", - " gf.dhdt_static_mean = gf.dhdt_static_stats['mean']\n", - " gf.dhdt_static_med = gf.dhdt_static_stats['med']\n", - " gf.dhdt_static_nmad = gf.dhdt_static_stats['nmad']\n", - " \n", - " print('STATIC ANALYSIS DOES NOT WORK FOR UNCERTAINTY HERE BECAUSE IN 1950s THE GLACIER EXCEEDED THE RGI EXTENTS')\n", - " \n", - " #Can estimate ELA values computed from hypsometry and typical AAR\n", - " #For now, assume ELA is mean\n", - " gf.z1_ela = None\n", - " gf.z1_ela = gf.z1_stats[3]\n", - " gf.z2_ela = gf.z2_stats[3]\n", - " #Note: in theory, the ELA should get higher with mass loss\n", - " #In practice, using mean and same polygon, ELA gets lower as glacier surface thins\n", - " if verbose:\n", - " print(\"ELA(t1): %0.1f\" % gf.z1_ela)\n", - " print(\"ELA(t2): %0.1f\" % gf.z2_ela)\n", - "\n", - " if gf.z1_ela > gf.z2_ela:\n", - " min_ela = gf.z2_ela\n", - " max_ela = gf.z1_ela\n", - " else:\n", - " min_ela = gf.z1_ela\n", - " max_ela = gf.z2_ela\n", - " \n", - " #Calculate uncertainty of total elevation change\n", - " #decorrelation length\n", - " L = 500\n", - " Acor = np.pi*L**2\n", - " if gf.glac_area > Acor:\n", - " #Correction factor for sample size area\n", - " Acorf = np.sqrt(Acor/(5*gf.glac_area))\n", - " else:\n", - " Acorf = 1.0\n", - "\n", - " #Std or NMAD of elevation change on stable ground, assuming we know a priori uncertainty for z1 and z2\n", - " #dz_sigma = np.sqrt(z1_sigma**2 + z2_sigma**2)\n", - " #dhdt_sigma = dz_sigma/gf.dt\n", - "\n", - " #This is NMAD of static pixels within buffer\n", - " dhdt_sigma = gf.dhdt_static_nmad\n", - " #Uncertainty of dh/dt\n", - " gf.dhdt_sigma = Acorf * (dhdt_sigma)\n", - "\n", - " #This is percentage of valid pixels, 0-1\n", - " #p = min(gf.valid_area_perc/100., 1.0)\n", - " #From Brun et al, multiply uncertainty for nodata by 5x\n", - " #p_factor = (p + 5*(1-p))\n", - " p_factor = 1.0\n", - "\n", - " #Calculate volume change (m3/a)\n", - " gf.dv = gf.dhdt_mean * gf.glac_area\n", - " #gf.dv = gf.dhdt_med * gf.glac_area\n", - " gf.dv_sum = gf.dhdt_sum*gf.res[0]*gf.res[1]\n", - " #print(gf.dv, gf.dv_sum, (gf.dv - gf.dv_sum))\n", - "\n", - " #Volume change uncertainty (m3/a)\n", - " gf.dv_sigma = np.sqrt((gf.dhdt_sigma*p_factor*gf.glac_area)**2 + (area_sigma_perc * gf.glac_area)**2)\n", - "\n", - " #Mass balance in mwe/a for each pixel\n", - " gf.mb_map = gf.dhdt * rho_is\n", - " gf.mb_map_sum = gf.mb_map.sum()\n", - " gf.mb_map_stats = malib.get_stats_dict(gf.mb_map)\n", - " gf.mb_map_sigma = np.ma.abs(gf.mb_map) * np.sqrt((rho_sigma/rho_is)**2 + (gf.dhdt_sigma/gf.dhdt)**2)\n", - " gf.mb_map_sigma_stats = malib.get_stats_dict(gf.mb_map_sigma)\n", - "\n", - " #This is estimate for polygon mb in mwea\n", - " gf.mb_mean = gf.mb_map_stats['mean']\n", - " #This is average mb uncertainty, does not include area uncertainty\n", - " gf.mb_mean_sigma = gf.mb_map_sigma_stats['mean']\n", - " gf.mb_med = gf.mb_map_stats['med']\n", - " gf.mb_med_sigma = gf.mb_map_sigma_stats['med']\n", - "\n", - " #Total mass balance for polygon in m3wea\n", - " #previously gf.mb_mean_totalarea\n", - " gf.mb_total = gf.dv * rho_is\n", - " gf.mb_total_sigma = np.sqrt((gf.dv_sigma*rho_is)**2 + (rho_sigma*gf.dv)**2)\n", - "\n", - " \"\"\"\n", - " # This attempted to assign different densities above and below ELA\n", - " if gf.z1_ela is None:\n", - " gf.mb = gf.dhdt * rho_is\n", - " else:\n", - " #Initiate with average density\n", - " gf.mb = gf.dhdt*(rho_is + rho_f)/2.\n", - " #Everything that is above ELA at t2 is elevation change over firn, use firn density\n", - " accum_mask = (gf.z2 > gf.z2_ela).filled(0).astype(bool)\n", - " gf.mb[accum_mask] = (gf.dhdt*rho_f)[accum_mask]\n", - " #Everything that is below ELA at t1 is elevation change over ice, use ice density\n", - " abl_mask = (gf.z1 <= gf.z1_ela).filled(0).astype(bool)\n", - " gf.mb[abl_mask] = (gf.dhdt*rho_is)[abl_mask]\n", - " #Everything in between, use average of ice and firn density\n", - " #mb[(z1 > z1_ela) || (z2 <= z2_ela)] = dhdt*(rhois + rho_f)/2.\n", - " #Linear ramp\n", - " #rho_f + z2*((rho_is - rho_f)/(z2_ela - z1_ela))\n", - " #mb = np.where(dhdt < ela, dhdt*rho_i, dhdt*rho_s)\n", - " \"\"\"\n", - "\n", - " #Old approach\n", - " #This is mb uncertainty map\n", - " #gf.mb_sigma = np.ma.abs(gf.mb) * np.sqrt((rho_sigma/rho_is)**2 + (gf.dhdt_sigma/gf.dhdt)**2)\n", - " #gf.mb_sigma_stats = malib.get_stats(gf.mb_sigma)\n", - " #This is average mb uncertainty\n", - " #gf.mb_mean_sigma = gf.mb_sigma_stats[3]\n", - "\n", - " #Now calculate mb for entire polygon\n", - " #gf.mb_mean_totalarea = gf.mb_mean * gf.glac_area\n", - " #Already have area uncertainty as percentage, just use directly\n", - " #gf.mb_mean_totalarea_sigma = np.ma.abs(gf.mb_mean_totalarea) * np.sqrt((gf.mb_mean_sigma/gf.mb_mean)**2 + area_sigma_perc**2)\n", - "\n", - " #z2_elev_med, z2_elev_min, z2_elev_max, z2_elev_p16, z2_elev_p84, \\\n", - " outlist = [gf.glacnum, gf.cx, gf.cy, \\\n", - " z2_elev_med, z2_elev_min, z2_elev_max, \\\n", - " z2_slope_med, z2_aspect_med, \\\n", - " gf.dhdt_mean, gf.dhdt_sigma, \\\n", - " gf.mb_mean, gf.mb_mean_sigma, \\\n", - " gf.glac_area, gf.mb_total, gf.mb_total_sigma, \\\n", - " gf.t1_mean, gf.t2_mean, gf.dt_mean, gf.valid_area_perc]\n", - "\n", - " if extra_layers and (gf.glac_area_km2 > min_glac_area_writeout):\n", - " if 'ice_thick' in ds_dict:\n", - " #Load ice thickness\n", - " gf.H = np.ma.array(iolib.ds_getma(ds_dict['ice_thick']), mask=glac_geom_mask)\n", - " gf.H_mean = gf.H.mean()\n", - " #These should be NaN or None\n", - " outlist.append(gf.H_mean)\n", - "\n", - " if 'debris_thick' in ds_dict:\n", - " gf.debris_thick = np.ma.array(iolib.ds_getma(ds_dict['debris_thick']), mask=glac_geom_mask)\n", - " gf.debris_thick_mean = gf.debris_thick.mean()\n", - " outlist.append(gf.debris_thick_mean)\n", - "\n", - " if 'debris_class' in ds_dict:\n", - " #Load up debris cover maps\n", - " #Classes are: 1 = clean ice, 2 = debris, 3 = pond\n", - " gf.debris_class = np.ma.array(iolib.ds_getma(ds_dict['debris_class']), mask=glac_geom_mask)\n", - "\n", - " #Compute debris/pond/clean percentages for entire polygon\n", - " if gf.debris_class.count() > 0:\n", - " gf.perc_clean = 100. * (gf.debris_class == 1).sum()/gf.debris_class.count()\n", - " gf.perc_debris = 100. * (gf.debris_class == 2).sum()/gf.debris_class.count()\n", - " gf.perc_pond = 100. * (gf.debris_class == 3).sum()/gf.debris_class.count()\n", - " outlist.extend([gf.perc_debris, gf.perc_pond, gf.perc_clean])\n", - "\n", - " if 'vx' in ds_dict and 'vy' in ds_dict:\n", - " #Load surface velocity maps\n", - " gf.vx = np.ma.array(iolib.ds_getma(ds_dict['vx']), mask=glac_geom_mask)\n", - " gf.vy = np.ma.array(iolib.ds_getma(ds_dict['vy']), mask=glac_geom_mask)\n", - " gf.vm = np.ma.sqrt(gf.vx**2 + gf.vy**2)\n", - " gf.vm_mean = gf.vm.mean()\n", - "\n", - " if gf.H is not None:\n", - " #Compute flux\n", - " gf.Q = gf.H * v_col_f * np.array([gf.vx, gf.vy])\n", - " #Note: np.gradient returns derivatives relative to axis number, so (y, x) in this case\n", - " #Want x-derivative of x component\n", - " gf.divQ = np.gradient(gf.Q[0])[1] + np.gradient(gf.Q[1])[0]\n", - "\n", - " #gf.divQ = gf.H*(np.gradient(v_col_f*gf.vx)[1] + np.gradient(v_col_f*gf.vy)[0]) \\\n", - " #+ v_col_f*gf.vx*(np.gradient(gf.H)[1]) + v_col_f*gf.vy*(np.gradient(gf.H)[0])\n", - "\n", - " #Should smooth divQ, better handling of data gaps\n", - " outlist.append(gf.vm_mean)\n", - "\n", - " if verbose:\n", - " print('Area [km2]:', gf.glac_area / 1e6)\n", - " print('Mean mb: %0.2f +/- %0.2f mwe/yr' % (gf.mb_mean, gf.mb_mean_sigma))\n", - " print('Sum/Area mb: %0.2f mwe/yr' % (gf.mb_total/gf.glac_area))\n", - " print('Mean mb * Area: %0.2f +/- %0.2f m3we/yr' % (gf.mb_total, gf.mb_total_sigma))\n", - "# print('Sum mb: %0.2f m3we/yr' % gf.mb_total)\n", - " print('-------------------------------')\n", - " \n", - " #Write out mb stats for entire polygon - in case processing is interupted\n", - " #out = np.array(outlist, dtype=float)\n", - " out = np.full(len(out_fmt), np.nan)\n", - " out[0:len(outlist)] = np.array(outlist, dtype=float)\n", - " #Note, need a 2D array here, add 0 axis\n", - "\n", - " print(out)\n", - "\n", - " np.savetxt(out_csv_fn, out[np.newaxis,:], fmt=out_fmt, delimiter=',', header=out_header, comments='')\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Do AED for all\n", - "#Compute mb using scaled AED vs. polygon\n", - "if mb_plot and (gf.glac_area_km2 > min_glac_area_writeout):\n", - " dz_clim = (-2.0, 2.0)\n", - " z_bin_edges = hist_plot(gf, outdir, bin_width=bin_width, dz_clim=dz_clim)\n", - " gf.z1_hs = geolib.gdaldem_mem_ds(ds_dict['z1'], processing='hillshade', returnma=True)\n", - " gf.z2_hs = geolib.gdaldem_mem_ds(ds_dict['z2'], processing='hillshade', returnma=True)\n", - " map_plot(gf, z_bin_edges, outdir, dz_clim=dz_clim)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.7" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/analyze_erainterim.py b/analyze_erainterim.py deleted file mode 100644 index 76903892..00000000 --- a/analyze_erainterim.py +++ /dev/null @@ -1,931 +0,0 @@ -""" Analyze MCMC output - chain length, etc. """ - -# Built-in libraries -import collections -import decimal -import glob -import os -import pickle -# External libraries -import cartopy -import matplotlib.pyplot as plt -from matplotlib.lines import Line2D -from matplotlib.ticker import MultipleLocator -import numpy as np -import pandas as pd -import pymc -from scipy import stats -from scipy.stats.kde import gaussian_kde -from scipy.stats import norm -from scipy.stats import truncnorm -from scipy.stats import uniform -#from scipy.stats import linregress -from scipy.stats import lognorm -from scipy.optimize import minimize -import xarray as xr -# Local libraries -import class_climate -import class_mbdata -import pygem_input as input -import pygemfxns_massbalance as massbalance -import pygemfxns_modelsetup as modelsetup -import pygemfxns_gcmbiasadj as gcmbiasadj -import run_calibration as calibration - -#%% -option_observation_vs_calibration = 0 -option_GRACE_2deg = 0 -option_trishuli = 0 - - -variables = ['massbal', 'precfactor', 'tempchange', 'ddfsnow'] -vn_title_dict = {'massbal':'Mass\nBalance', - 'precfactor':'Precipitation\nFactor', - 'tempchange':'Temperature\nBias', - 'ddfsnow':'Degree-Day \nFactor of Snow'} -vn_label_dict = {'massbal':'Mass Balance\n[mwea]', - 'precfactor':'Precipitation Factor\n[-]', - 'tempchange':'Temperature Bias\n[$^\circ$C]', - 'ddfsnow':'Degree Day Factor of Snow\n[mwe d$^{-1}$ $^\circ$C$^{-1}$]'} -vn_label_units_dict = {'massbal':'[mwea]', - 'precfactor':'[-]', - 'tempchange':'[$^\circ$C]', - 'ddfsnow':'[mwe d$^{-1}$ $^\circ$C$^{-1}$]'} - -# Export option -sim_netcdf_fp = input.output_filepath + 'simulations/spc_20190914/merged/ERA-Interim/' -#sim_netcdf_fp = input.output_filepath + 'simulations/ERA-Interim/ERA-Interim_1980_2017_nochg/' -#sim_netcdf_fp = input.output_filepath + 'simulations/ERA-Interim_2000_2017wy_nobiasadj/' - -figure_fp = sim_netcdf_fp + 'figures/' - -regions = [13, 14, 15] -degree_size = 0.1 - -cal_datasets = ['shean'] - -burn=0 - -colors = ['#387ea0', '#fcb200', '#d20048'] -linestyles = ['-', '--', ':'] - -east = 60 -west = 110 -south = 15 -north = 50 -xtick = 5 -ytick = 5 -xlabel = 'Longitude [$^\circ$]' -ylabel = 'Latitude [$^\circ$]' - - -#%% -# ===== FUNCTIONS ==== -def plot_hist(df, cn, bins, xlabel=None, ylabel=None, fig_fn='hist.png', fig_fp=figure_fp): - """ - Plot histogram for any bin size - """ - if os.path.exists(figure_fp) == False: - os.makedirs(figure_fp) - - data = df[cn].values - hist, bin_edges = np.histogram(data,bins) # make the histogram - fig,ax = plt.subplots() - # Plot the histogram heights against integers on the x axis - ax.bar(range(len(hist)),hist,width=1, edgecolor='k') - # Set the ticks to the middle of the bars - ax.set_xticks([0.5+i for i,j in enumerate(hist)]) - # Set the xticklabels to a string that tells us what the bin edges were - ax.set_xticklabels(['{} - {}'.format(bins[i],bins[i+1]) for i,j in enumerate(hist)], rotation=45, ha='right') - ax.set_xlabel(xlabel, fontsize=16) - ax.set_ylabel(ylabel, fontsize=16) - # Save figure - fig.set_size_inches(6,4) - fig.savefig(fig_fp + fig_fn, bbox_inches='tight', dpi=300) - - -def select_groups(grouping, main_glac_rgi_all): - """ - Select groups based on grouping - """ - if grouping == 'rgi_region': - groups = regions - group_cn = 'O1Region' - elif grouping == 'watershed': - groups = main_glac_rgi_all.watershed.unique().tolist() - group_cn = 'watershed' - elif grouping == 'kaab': - groups = main_glac_rgi_all.kaab.unique().tolist() - group_cn = 'kaab' - groups = [x for x in groups if str(x) != 'nan'] - elif grouping == 'degree': - groups = main_glac_rgi_all.deg_id.unique().tolist() - group_cn = 'deg_id' - elif grouping == 'mascon': - groups = main_glac_rgi_all.mascon_idx.unique().tolist() - groups = [int(x) for x in groups] - group_cn = 'mascon_idx' - else: - groups = ['all'] - group_cn = 'all_group' - try: - groups = sorted(groups, key=str.lower) - except: - groups = sorted(groups) - return groups, group_cn - - -def load_masschange_monthly(regions, ds_ending, netcdf_fp=sim_netcdf_fp, option_add_caldata=0): - """ Load monthly mass change data """ - count = 0 - for region in regions: - count += 1 - - # Load datasets - ds_fn = 'R' + str(region) + ds_ending - ds = xr.open_dataset(netcdf_fp + ds_fn) - - main_glac_rgi_region_ds = pd.DataFrame(ds.glacier_table.values, columns=ds.glac_attrs) - glac_wide_massbaltotal_region = ds.massbaltotal_glac_monthly.values[:,:,0] - glac_wide_area_annual_region = ds.area_glac_annual.values[:,:,0] - time_values = pd.Series(ds.massbaltotal_glac_monthly.coords['time'].values) - - # ===== GLACIER DATA ===== - main_glac_rgi_region = modelsetup.selectglaciersrgitable( - rgi_regionsO1=[region], rgi_regionsO2 = 'all', rgi_glac_number='all') - if (main_glac_rgi_region['glacno'] - main_glac_rgi_region_ds['glacno']).sum() == 0: - print('Region', str(region),': number of glaciers match') - # Glacier hypsometry - main_glac_hyps_region = modelsetup.import_Husstable( - main_glac_rgi_region, input.hyps_filepath,input.hyps_filedict, input.hyps_colsdrop) - # Ice thickness [m], average - main_glac_icethickness_region = modelsetup.import_Husstable( - main_glac_rgi_region, input.thickness_filepath, input.thickness_filedict, input.thickness_colsdrop) - main_glac_hyps_region[main_glac_icethickness_region == 0] = 0 - # ===== CALIBRATION DATA ===== - if option_add_caldata == 1: - dates_table_nospinup = modelsetup.datesmodelrun(startyear=input.startyear, endyear=input.endyear, - spinupyears=0) - cal_data_region = pd.DataFrame() - for dataset in cal_datasets: - cal_subset = class_mbdata.MBData(name=dataset) - cal_subset_data = cal_subset.retrieve_mb(main_glac_rgi_region, main_glac_hyps_region, dates_table_nospinup) - cal_data_region = cal_data_region.append(cal_subset_data, ignore_index=True) - cal_data_region = cal_data_region.sort_values(['glacno', 't1_idx']) - cal_data_region.reset_index(drop=True, inplace=True) - - # ===== APPEND DATASETS ===== - if count == 1: - main_glac_rgi = main_glac_rgi_region - main_glac_hyps = main_glac_hyps_region - main_glac_icethickness = main_glac_icethickness_region - glac_wide_massbaltotal = glac_wide_massbaltotal_region - glac_wide_area_annual = glac_wide_area_annual_region - - if option_add_caldata == 1: - cal_data = cal_data_region - - else: - main_glac_rgi = main_glac_rgi.append(main_glac_rgi_region) - - glac_wide_massbaltotal = np.concatenate([glac_wide_massbaltotal, glac_wide_massbaltotal_region]) - glac_wide_area_annual = np.concatenate([glac_wide_area_annual, glac_wide_area_annual_region]) - - if option_add_caldata == 1: - cal_data = cal_data.append(cal_data_region) - - # If more columns in region, then need to expand existing dataset - if main_glac_hyps_region.shape[1] > main_glac_hyps.shape[1]: - all_col = list(main_glac_hyps.columns.values) - reg_col = list(main_glac_hyps_region.columns.values) - new_cols = [item for item in reg_col if item not in all_col] - for new_col in new_cols: - main_glac_hyps[new_col] = 0 - main_glac_icethickness[new_col] = 0 - elif main_glac_hyps_region.shape[1] < main_glac_hyps.shape[1]: - all_col = list(main_glac_hyps.columns.values) - reg_col = list(main_glac_hyps_region.columns.values) - new_cols = [item for item in all_col if item not in reg_col] - for new_col in new_cols: - main_glac_hyps_region[new_col] = 0 - main_glac_icethickness_region[new_col] = 0 - main_glac_hyps = main_glac_hyps.append(main_glac_hyps_region) - main_glac_icethickness = main_glac_icethickness.append(main_glac_icethickness_region) - - # reset index - main_glac_rgi.reset_index(inplace=True, drop=True) - main_glac_hyps.reset_index(inplace=True, drop=True) - main_glac_icethickness.reset_index(inplace=True, drop=True) - if option_add_caldata == 1: - cal_data.reset_index(inplace=True, drop=True) - - # Volume [km**3] and mean elevation [m a.s.l.] - main_glac_rgi['Volume'], main_glac_rgi['Zmean'] = modelsetup.hypsometrystats(main_glac_hyps, main_glac_icethickness) - - - # ===== MASS CHANGE CALCULATIONS ===== - # Compute glacier volume change for every time step and use this to compute mass balance - glac_wide_area = np.repeat(glac_wide_area_annual[:,:-1], 12, axis=1) - - # Mass change [km3 mwe] - # mb [mwea] * (1 km / 1000 m) * area [km2] - glac_wide_masschange = glac_wide_massbaltotal / 1000 * glac_wide_area - - if option_add_caldata == 1: - return main_glac_rgi, glac_wide_masschange, glac_wide_area, time_values, cal_data - else: - return main_glac_rgi, glac_wide_masschange, glac_wide_area, time_values - - -# ===== PLOT OPTIONS ================================================================================================== -#%% -def observation_vs_calibration(regions, netcdf_fp): - """ - Compare mass balance observations with model calibration - - Parameters - ---------- - regions : list of strings - list of regions - Returns - ------- - .png files - saves histogram of differences between observations and calibration - .csv file - saves .csv file of comparison - """ -#%% -if option_observation_vs_calibration == 1: -# observation_vs_calibration(regions, sim_netcdf_fp) - - t1_idx = 0 - t2_idx = 216 -# t1_idx = 240 -# t2_idx = 455 - t1 = 2000 - t2 = 2018 - -# main_glac_rgi, glac_wide_masschange, glac_wide_area, time_values = ( -# load_masschange_monthly(regions, ds_ending='_ERA-Interim_c2_ba1_100sets_1980_2017.nc')) - main_glac_rgi, glac_wide_masschange, glac_wide_area, time_values = ( - load_masschange_monthly(regions, ds_ending='_ERA-Interim_c2_ba1_100sets_2000_2018.nc')) - - # Mean annual mass balance [mwea] - glac_wide_mb_mwea = glac_wide_masschange[:,t1_idx:t2_idx+1].sum(axis=1) / glac_wide_area[:,0] * 1000 / (t2 - t1) - - - #%% - # Total mass change [Gt/yr] - total_masschange = glac_wide_masschange[:,t1_idx:t2_idx+1].sum(axis=1).sum() / (t2 - t1) -# total_masschange_obs = (cal_data.mb_mwe.values / 1000 * glac_wide_area[:,0]).sum() / (t2 - t1) - - #%% -# main_glac_rgi['mb_mwea_era_mean'] = glac_wide_mb_mwea -# main_glac_rgi['mb_mwea_cal_mean'] = cal_data.mb_mwe.values / (t2 - t1) -# main_glac_rgi['mb_mwea_cal_std'] = cal_data.mb_mwe_err.values / (t2 - t1) - -# #%% Total mass change accounting for truncation -# # Maximum loss if entire glacier melted between 2000 and 2018 -# mb_max_loss = (-1 * (main_glac_hyps * main_glac_icethickness * input.density_ice / -# input.density_water).sum(axis=1).values / main_glac_hyps.sum(axis=1).values / (t2 - t1)) -# main_glac_rgi['mb_max_loss'] = mb_max_loss -# -# # Truncated normal - updated means to remove portions of observations that are below max mass loss! -# main_glac_rgi['mb_cal_dist_mean'] = np.nan -# main_glac_rgi['mb_cal_dist_med'] = np.nan -# main_glac_rgi['mb_cal_dist_std'] = np.nan -# main_glac_rgi['mb_cal_dist_95low'] = np.nan -# main_glac_rgi['mb_cal_dist_95high'] = np.nan -# for glac in range(main_glac_rgi.shape[0]): -# if glac%500 == 0: -# print(glac) -# cal_mu = main_glac_rgi.loc[glac, 'mb_mwea_cal_mean'] -# cal_sigma = main_glac_rgi.loc[glac, 'mb_mwea_cal_std'] -# cal_lowbnd = main_glac_rgi.loc[glac, 'mb_max_loss'] -# cal_rvs = stats.truncnorm.rvs((cal_lowbnd - cal_mu) / cal_sigma, np.inf, loc=cal_mu, scale=cal_sigma, -# size=int(1e5)) -# main_glac_rgi.loc[glac,'mb_cal_dist_mean'] = np.mean(cal_rvs) -# main_glac_rgi.loc[glac,'mb_cal_dist_med'] = np.median(cal_rvs) -# main_glac_rgi.loc[glac,'mb_cal_dist_std'] = np.std(cal_rvs) -# main_glac_rgi.loc[glac,'mb_cal_dist_95low'] = np.percentile(cal_rvs, 2.5) -# main_glac_rgi.loc[glac,'mb_cal_dist_95high'] = np.percentile(cal_rvs, 97.5) -# -# total_masschange_obs_adjdist = np.nansum((main_glac_rgi.mb_cal_dist_mean.values / 1000 * glac_wide_area[:,0])) -# -# -# #%% -# -# main_glac_rgi['dif_cal_era_mean'] = main_glac_rgi['mb_mwea_cal_mean'] - main_glac_rgi['mb_mwea_era_mean'] -# -# # remove nan values -# main_glac_rgi_dropnan = ( -# main_glac_rgi.drop(np.where(np.isnan(main_glac_rgi['mb_mwea_era_mean'].values) == True)[0].tolist(), -# axis=0)) -# main_glac_rgi_dropnan.reset_index(drop=True, inplace=True) -# -# # Degrees -# main_glac_rgi_dropnan['CenLon_round'] = np.floor(main_glac_rgi_dropnan.CenLon.values/degree_size) * degree_size -# main_glac_rgi_dropnan['CenLat_round'] = np.floor(main_glac_rgi_dropnan.CenLat.values/degree_size) * degree_size -# deg_groups = main_glac_rgi_dropnan.groupby(['CenLon_round', 'CenLat_round']).size().index.values.tolist() -# deg_dict = dict(zip(deg_groups, np.arange(0,len(deg_groups)))) -# main_glac_rgi_dropnan.reset_index(drop=True, inplace=True) -# cenlon_cenlat = [(main_glac_rgi_dropnan.loc[x,'CenLon_round'], main_glac_rgi_dropnan.loc[x,'CenLat_round']) -# for x in range(len(main_glac_rgi_dropnan))] -# main_glac_rgi_dropnan['CenLon_CenLat'] = cenlon_cenlat -# main_glac_rgi_dropnan['deg_id'] = main_glac_rgi_dropnan.CenLon_CenLat.map(deg_dict) -# -##%% -# # Histogram: Mass balance [mwea], Observation - ERA -# hist_cn = 'dif_cal_era_mean' -# low_bin = np.floor(main_glac_rgi_dropnan[hist_cn].min()) -# high_bin = np.ceil(main_glac_rgi_dropnan[hist_cn].max()) -# bins = [low_bin, -0.2, -0.1, -0.05, -0.02, 0.02, 0.05, 0.1, 0.2, high_bin] -# plot_hist(main_glac_rgi_dropnan, hist_cn, bins, xlabel='Mass balance [mwea]\n(Calibration - MCMC_mean)', -# ylabel='# Glaciers', fig_fn='MB_cal_vs_mcmc_hist.png', fig_fp=figure_fp) -# -# #%% -# -# # Map: Mass change, difference between calibration data and median data -# # Area [km2] * mb [mwe] * (1 km / 1000 m) * density_water [kg/m3] * (1 Gt/km3 / 1000 kg/m3) -# main_glac_rgi_dropnan['mb_cal_Gta'] = main_glac_rgi_dropnan['mb_mwea_cal_mean'] * main_glac_rgi_dropnan['Area'] / 1000 -# main_glac_rgi_dropnan['mb_cal_Gta_var'] = (main_glac_rgi_dropnan['mb_mwea_cal_std'] * main_glac_rgi_dropnan['Area'] / 1000)**2 -# main_glac_rgi_dropnan['mb_era_Gta'] = main_glac_rgi_dropnan['mb_mwea_era_mean'] * main_glac_rgi_dropnan['Area'] / 1000 -## main_glac_rgi_dropnan['mb_era_Gta_var'] = (main_glac_rgi_dropnan['mb_era_std'] * main_glac_rgi_dropnan['Area'] / 1000)**2 -## main_glac_rgi_dropnan['mb_era_Gta_med'] = main_glac_rgi_dropnan['mb_era_med'] * main_glac_rgi_dropnan['Area'] / 1000 -## print('All MB cal (mean +/- 1 std) [gt/yr]:', np.round(main_glac_rgi_dropnan['mb_cal_Gta'].sum(),3), -## '+/-', np.round(main_glac_rgi_dropnan['mb_cal_Gta_var'].sum()**0.5,3), -## '\nAll MB ERA (mean +/- 1 std) [gt/yr]:', np.round(main_glac_rgi_dropnan['mb_era_Gta'].sum(),3), -## '+/-', np.round(main_glac_rgi_dropnan['mb_era_Gta_var'].sum()**0.5,3), -## '\nAll MB ERA (med) [gt/yr]:', np.round(main_glac_rgi_dropnan['mb_era_Gta_med'].sum(),3)) -# -# print('All MB cal (mean +/- 1 std) [gt/yr]:', np.round(main_glac_rgi_dropnan['mb_cal_Gta'].sum(),3), -# '+/-', np.round(main_glac_rgi_dropnan['mb_cal_Gta_var'].sum()**0.5,3), -# '\nAll MB ERA (mean) [gt/yr]:', np.round(main_glac_rgi_dropnan['mb_era_Gta'].sum(),3), -# ) -# -# #%% -# -# def partition_sum_groups(grouping, vn, main_glac_rgi_dropnan): -# """Partition model parameters by each group -# -# Parameters -# ---------- -# grouping : str -# name of grouping to use -# vn : str -# variable name -# main_glac_rgi_dropnan : pd.DataFrame -# glacier table -# -# Output -# ------ -# groups : list -# list of group names -# ds_group : list of lists -# dataset containing the multimodel data for a given variable for all the GCMs -# """ -# # Groups -# groups, group_cn = select_groups(grouping, main_glac_rgi_dropnan) -# -# ds_group = [[] for group in groups] -# -# # Cycle through groups -# for ngroup, group in enumerate(groups): -# # Select subset of data -# main_glac_rgi = main_glac_rgi_dropnan.loc[main_glac_rgi_dropnan[group_cn] == group] -# vn_glac = main_glac_rgi_dropnan[vn].values[main_glac_rgi.index.values.tolist()] -# # Regional sum -# vn_reg = vn_glac.sum(axis=0) -# -# # Record data for each group -# ds_group[ngroup] = [group, vn_reg] -# -# return groups, ds_group -# -# grouping='degree' -# -# groups, ds_group_cal = partition_sum_groups(grouping, 'mb_cal_Gta', main_glac_rgi_dropnan) -# groups, ds_group_era = partition_sum_groups(grouping, 'mb_era_Gta', main_glac_rgi_dropnan) -# groups, ds_group_area = partition_sum_groups(grouping, 'Area', main_glac_rgi_dropnan) -# -## ds_group_dif = [[] for x in ds_group_cal ] -# -# # Group difference [Gt/yr] -# dif_cal_era_Gta = (np.array([x[1] for x in ds_group_cal]) - np.array([x[1] for x in ds_group_era])).tolist() -# ds_group_dif_cal_era_Gta = [[x[0],dif_cal_era_Gta[n]] for n, x in enumerate(ds_group_cal)] -# # Group difference [mwea] -# area = [x[1] for x in ds_group_area] -# ds_group_dif_cal_era_mwea = [[x[0], dif_cal_era_Gta[n] / area[n] * 1000] for n, x in enumerate(ds_group_cal)] -# -# east = 104 -# west = 67 -# south = 25 -# north = 48 -# -# labelsize = 13 -# -# norm = plt.Normalize(-0.1, 0.1) -# -# # Create the projection -# fig, ax = plt.subplots(1, 1, figsize=(10,5), subplot_kw={'projection':cartopy.crs.PlateCarree()}) -# # Add country borders for reference -# ax.add_feature(cartopy.feature.BORDERS, alpha=0.15, zorder=10) -# ax.add_feature(cartopy.feature.COASTLINE) -# # Set the extent -# ax.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) -# # Label title, x, and y axes -# ax.set_xticks(np.arange(east,west+1,xtick), cartopy.crs.PlateCarree()) -# ax.set_yticks(np.arange(south,north+1,ytick), cartopy.crs.PlateCarree()) -# ax.set_xlabel(xlabel, size=labelsize) -# ax.set_ylabel(ylabel, size=labelsize) -# -# cmap = 'RdYlBu_r' -# -# # Add colorbar -## sm = plt.cm.ScalarMappable(cmap=cmap) -# sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) -# sm._A = [] -# plt.colorbar(sm, ax=ax, fraction=0.03, pad=0.01) -# fig.text(1, 0.5, 'Mass balance [mwea]\n(Observation - MCMC)', va='center', rotation='vertical', size=labelsize) -# -# # Group by degree -# groups_deg = groups -# ds_vn_deg = ds_group_dif_cal_era_mwea -# -# z = [ds_vn_deg[ds_idx][1] for ds_idx in range(len(ds_vn_deg))] -# x = np.array([x[0] for x in deg_groups]) -# y = np.array([x[1] for x in deg_groups]) -# lons = np.arange(x.min(), x.max() + 2 * degree_size, degree_size) -# lats = np.arange(y.min(), y.max() + 2 * degree_size, degree_size) -# x_adj = np.arange(x.min(), x.max() + 1 * degree_size, degree_size) - x.min() -# y_adj = np.arange(y.min(), y.max() + 1 * degree_size, degree_size) - y.min() -# z_array = np.zeros((len(y_adj), len(x_adj))) -# z_array[z_array==0] = np.nan -# for i in range(len(z)): -# row_idx = int((y[i] - y.min()) / degree_size) -# col_idx = int((x[i] - x.min()) / degree_size) -# z_array[row_idx, col_idx] = z[i] -# ax.pcolormesh(lons, lats, z_array, cmap='RdYlBu_r', norm=norm, zorder=2, alpha=0.8) -# -# # Save figure -# fig.set_size_inches(6,4) -# fig_fn = 'MB_cal_minus_era_map_2000_2018_areachg.png' -# fig.savefig(figure_fp + fig_fn, bbox_inches='tight', dpi=300) -# -# main_glac_rgi_dropnan.to_csv(figure_fp + 'main_glac_rgi_HMA_2000_2018_areachg.csv') - - #%% - # Plot change in volume over time - # Index time period - time_values_year = np.array([x.to_pydatetime().year for x in time_values]) - ref_year = np.array([int(str(x)[0:4]) for x in main_glac_rgi['RefDate'].values]) - ref_month = np.array([int(str(x)[4:6]) for x in main_glac_rgi['RefDate'].values]) - ref_month[ref_month>12] = 6 - ref_day = np.array([int(str(x)[6:]) for x in main_glac_rgi['RefDate'].values]) - ref_day[ref_day>31] = 15 - ref_year_frac = ref_year + (ref_month + ref_day / (365/12)) / 12 - ref_year_avg = np.median(ref_year_frac) - ref_year_4idx = int(ref_year_avg) - ref_month_4idx = int((ref_year_avg%ref_year_4idx)*12) - start_idx = np.where(time_values_year == ref_year_4idx)[0][ref_month_4idx-1] - - # Initial mass [Gt] - region_initmass = main_glac_rgi.Volume.values.sum() - # Monthly mass change [km3 w.e. == Gt] - region_masschange = glac_wide_masschange.sum(axis=0) - region_mass = np.zeros((region_masschange.shape)) - region_mass[start_idx] = region_initmass - region_mass[start_idx+1:] = region_initmass + region_masschange[start_idx+1:].cumsum() - region_mass[:start_idx] = region_initmass + region_masschange[:start_idx][::-1].cumsum()[::-1] - - # Normalized regional mass - region_mass_norm = region_mass / region_initmass - - # ===== Plot ===== - fig, ax = plt.subplots(1, 1, squeeze=False, sharex=False, sharey=True, - figsize=(5,4), gridspec_kw = {'wspace':0, 'hspace':0}) - ax[0,0].plot(time_values, region_mass_norm, color='k', linewidth=1, label=None) - ax[0,0].set_ylabel('Normalized Mass [-]') - - print('ADD UNCERTAINTY TO PLOT!') - - # Save figure - fig.set_size_inches(6.5,4) - figure_fn = 'Normalized_Mass_1980-2017.png' - fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300) - - -#%% -if option_GRACE_2deg == 1: - grouping = 'degree' - -# main_glac_rgi, glac_wide_masschange, glac_wide_area, time_values = ( -# load_masschange_monthly(regions, ds_ending='_ERA-Interim_c2_ba1_100sets_1980_2017.nc')) - main_glac_rgi, glac_wide_masschange, glac_wide_area, time_values = ( - load_masschange_monthly(regions, ds_ending='_ERA-Interim_c2_ba1_100sets_2000_2018.nc')) - - # Add watersheds, regions, degrees, mascons, and all groups to main_glac_rgi_all - # Degrees - main_glac_rgi['CenLon_round'] = np.floor(main_glac_rgi.CenLon.values/degree_size) * degree_size - main_glac_rgi['CenLat_round'] = np.floor(main_glac_rgi.CenLat.values/degree_size) * degree_size - deg_groups = main_glac_rgi.groupby(['CenLon_round', 'CenLat_round']).size().index.values.tolist() - deg_dict = dict(zip(deg_groups, np.arange(0,len(deg_groups)))) - main_glac_rgi.reset_index(drop=True, inplace=True) - cenlon_cenlat = [(main_glac_rgi.loc[x,'CenLon_round'], main_glac_rgi.loc[x,'CenLat_round']) - for x in range(len(main_glac_rgi))] - main_glac_rgi['CenLon_CenLat'] = cenlon_cenlat - main_glac_rgi['deg_id'] = main_glac_rgi.CenLon_CenLat.map(deg_dict) - - # Groups - groups, group_cn = select_groups(grouping, main_glac_rgi) - - ds_group_masschange = {} - ds_group_area = {} - - # Cycle through groups - for ngroup, group in enumerate(groups): - if ngroup%50 == 0: - print(group) - # Select subset of data - main_glac_rgi_subset = main_glac_rgi.loc[main_glac_rgi[group_cn] == group] - masschange_glac = glac_wide_masschange[main_glac_rgi_subset.index.values.tolist(),:] - area_glac = glac_wide_area[main_glac_rgi_subset.index.values.tolist(),:] - # Regional sum - masschange_reg = masschange_glac.sum(axis=0) - area_reg = area_glac.sum(axis=0) - # Record data - ds_group_masschange[ngroup] = masschange_reg - ds_group_area[ngroup] = area_reg - - latitude = np.arange(main_glac_rgi.CenLat_round.min(), main_glac_rgi.CenLat_round.max() + degree_size, degree_size) - longitude = np.arange(main_glac_rgi.CenLon_round.min(), main_glac_rgi.CenLon_round.max() + degree_size, degree_size) - - masschange_3d = np.zeros((len(longitude), len(latitude), len(time_values))) - area_3d = np.zeros((len(longitude), len(latitude), len(time_values))) - -# #%% -# def round_degsize(x, degree_size=degree_size): -# """ Round scalar or array to nearest degree_size - avoids rounding errors with np.where """ -# ndigits = -1 * len(str(degree_size).split('.')[1]) -# if np.isscalar(x): -# return np.around(int(np.floor(x/degree_size)) * degree_size, ndigits) -# else: -# return np.array([np.around(int(np.floor(i/degree_size)) * degree_size, ndigits) for i in x]) -# -## longitude = round_degsize(longitude) -## latitude = round_degsize(latitude) - #%% - for ngroup, group in enumerate(groups): - lon_idx = np.where(np.isclose(longitude, deg_groups[ngroup][0]))[0][0] - lat_idx = np.where(np.isclose(latitude, deg_groups[ngroup][1]))[0][0] - masschange_3d[lon_idx, lat_idx, :] = ds_group_masschange[ngroup] - area_3d[lon_idx, lat_idx, :] = ds_group_area[ngroup] - #%% - - # Create empty datasets for each variable and merge them - # Coordinate values - output_variables = ['masschange_monthly', 'area_monthly'] - # Year type for attributes - if time_values[0].to_pydatetime().month == 10: - year_type = 'water year' - elif time_values[0].to_pydatetime().month == 1: - year_type = 'calendar year' - else: - year_type = 'custom year' - - # Variable coordinates dictionary - output_coords_dict = { - 'masschange_monthly': collections.OrderedDict( - [('longitude', longitude), ('latitude', latitude), ('time', time_values)]), - 'area_monthly': collections.OrderedDict( - [('longitude', longitude), ('latitude', latitude), ('time', time_values)]), - } - # Attributes dictionary - output_attrs_dict = { - 'longitude': { - 'long_name': 'longitude', - 'degree_size':degree_size}, - 'latitude': { - 'long_name': 'latitude', - 'degree_size':degree_size}, - 'time': { - 'long_name': 'date', - 'year_type':year_type}, - 'masschange_monthly': { - 'long_name': 'glacier mass change', - 'units': 'Gt', - 'temporal_resolution': 'monthly', - 'comment': ('mass change of all glaciers with center in grid (glaciers spanning multiple grids' + - 'are counted in grid where their center latitude/longitude is located)')}, - 'area_monthly': { - 'long_name': 'glacier area', - 'units': 'km**2', - 'temporal_resolution': 'monthly', - 'comment': ('area of all glaciers with center in grid (glaciers spanning multiple grids' + - 'are counted in grid where their center latitude/longitude is located')}, - } - # Add variables to empty dataset and merge together - count_vn = 0 - encoding = {} - for vn in output_variables: - count_vn += 1 - empty_holder = np.zeros([len(output_coords_dict[vn][i]) for i in list(output_coords_dict[vn].keys())]) - output_ds = xr.Dataset({vn: xr.DataArray(empty_holder, - dims=list(output_coords_dict[vn].keys()), - coords=output_coords_dict[vn])}) - # Merge datasets of stats into one output - if count_vn == 1: - output_ds_all = output_ds - else: - output_ds_all = xr.merge((output_ds_all, output_ds)) - # Add attributes - for vn in output_ds_all.variables: - try: - output_ds_all[vn].attrs = output_attrs_dict[vn] - except: - pass - # Encoding (specify _FillValue, offsets, etc.) - encoding[vn] = {'_FillValue': False} - - # Add values - output_ds_all.masschange_monthly[:,:,:] = masschange_3d - output_ds_all.area_monthly[:,:,:] = area_3d - - # Export netcdf -# netcdf_fn = 'ERA-Interim_1980_2017_masschange_p' + str(int(degree_size*100)) + 'deg.nc' - netcdf_fn = 'ERA-Interim_2000_2018_masschange_p' + str(int(degree_size*100)) + 'deg.nc' - output_ds_all.to_netcdf(sim_netcdf_fp + netcdf_fn, encoding=encoding) - # Close datasets - output_ds_all.close() - - print(np.round(output_ds_all.masschange_monthly[:,:,:].values.sum() / 18,2), 'Gt/yr') - -#%% -if option_trishuli == 1: - glac_no = input.glac_fromcsv(input.main_directory + '/../qgis_himat/trishuli_shp/trishuli_RGIIds.csv') - main_glac_rgi = modelsetup.selectglaciersrgitable(glac_no=glac_no) - -# ds_new = xr.open_dataset(input.output_sim_fp + 'ERA-Interim/Trishuli_ERA-Interim_c2_ba1_100sets_2000_2017.nc') -# ds_old13 = xr.open_dataset(input.output_sim_fp + 'ERA-Interim/ERA-Interim_1980_2017_nochg/' + -# 'R13_ERA-Interim_c2_ba1_100sets_1980_2017.nc') -# ds_old15 = xr.open_dataset(input.output_sim_fp + 'ERA-Interim/ERA-Interim_1980_2017_nochg/' + -# 'R15_ERA-Interim_c2_ba1_100sets_1980_2017.nc') -# time_old_idx_start = 12*20 -# time_new_idx_start = 0 -# years = np.arange(2000,2018) -# option_components = 1 - - ds_new = xr.open_dataset(input.output_sim_fp + 'IPSL-CM5A-LR/' + - 'Trishuli_IPSL-CM5A-LR_rcp85_c2_ba1_100sets_2000_2100.nc') - ds_old13 = xr.open_dataset(input.output_sim_fp + 'spc_subset/' + - 'R13_IPSL-CM5A-LR_rcp26_c2_ba1_100sets_2000_2100--subset.nc') - ds_old15 = xr.open_dataset(input.output_sim_fp + 'spc_subset/' + - 'R15_IPSL-CM5A-LR_rcp26_c2_ba1_100sets_2000_2100--subset.nc') - time_old_idx_start = 16*12 - time_new_idx_start = 16*12 - years = np.arange(2016,2101) - option_components = 0 - - # Concatenate datasets - ds_old = xr.concat([ds_old13, ds_old15], dim='glac') - - df_old = pd.DataFrame(ds_old.glacier_table.values, columns=ds_old.glac_attrs) - df_old.reset_index(inplace=True, drop=True) - df_old['rgino_str'] = [str(int(df_old.loc[x,'O1Region'])) + '.' + str(int(df_old.loc[x,'glacno'])).zfill(5) - for x in np.arange(df_old.shape[0])] - - # Find indices to select data from - df_old_idx = np.where(df_old.rgino_str.isin(main_glac_rgi.rgino_str.values))[0] - - runoff_old_monthly = ds_old.runoff_glac_monthly.values[df_old_idx,time_old_idx_start:,0] - offglac_runoff_old_monthly = ds_old.offglac_runoff_monthly.values[df_old_idx,time_old_idx_start:,0] - totalrunoff_old_monthly = (runoff_old_monthly + offglac_runoff_old_monthly) / 10**9 - totalrunoff_old = gcmbiasadj.annual_sum_2darray(totalrunoff_old_monthly) - totalrunoff_old_trishuli = totalrunoff_old.sum(axis=0) - - runoff_new_monthly = ds_new.runoff_glac_monthly.values[:,time_new_idx_start:,0] - offglac_runoff_new_monthly = ds_new.offglac_runoff_monthly.values[:,time_new_idx_start:,0] - totalrunoff_new_monthly = (runoff_new_monthly + offglac_runoff_new_monthly) / 10**9 - totalrunoff_new = gcmbiasadj.annual_sum_2darray(totalrunoff_new_monthly) - totalrunoff_new_trishuli = totalrunoff_new.sum(axis=0) - - dif_runoff = totalrunoff_new_trishuli.sum() - totalrunoff_old_trishuli.sum() - print('DIFFERENCE RUNOFF TOTAL:\n', np.round(dif_runoff,1), 'Gt', - np.round(dif_runoff / totalrunoff_old_trishuli.sum()*100,1), '%') - - - if option_components == 1: - area_annual = ds_old.area_glac_annual.values[df_old_idx,20:,0][:,:-1] - # Compare precipitation - prec_old_monthly = ds_old.prec_glac_monthly.values[df_old_idx,time_old_idx_start:,0] - acc_old_monthly = ds_old.acc_glac_monthly.values[df_old_idx,time_old_idx_start:,0] - totalprec_old_monthly = prec_old_monthly + acc_old_monthly - totalprec_old = gcmbiasadj.annual_sum_2darray(totalprec_old_monthly) - totalprec_old_Gt = totalprec_old / 1000 * area_annual - totalprec_old_trishuli = totalprec_old_Gt.sum(axis=0) - - - prec_new_monthly = ds_new.prec_glac_monthly.values[:,:,0] - acc_new_monthly = ds_new.acc_glac_monthly.values[:,:,0] - totalprec_new_monthly = prec_new_monthly + acc_new_monthly - totalprec_new = gcmbiasadj.annual_sum_2darray(totalprec_new_monthly) - totalprec_new_Gt = totalprec_new / 1000 * area_annual - totalprec_new_trishuli = totalprec_new_Gt.sum(axis=0) - - pf_dif = totalprec_new / totalprec_old - dif_totalprec = totalprec_new_trishuli.sum() - totalprec_old_trishuli.sum() - print('DIFFERENCE PRECIPITATION TOTAL:\n', np.round(dif_totalprec,1), 'Gt', - np.round(dif_totalprec / totalprec_old_trishuli.sum() * 100, 1), '%') - - # Compare melt - melt_old_monthly = ds_old.melt_glac_monthly.values[df_old_idx,time_old_idx_start:,0] - melt_old = gcmbiasadj.annual_sum_2darray(melt_old_monthly) - melt_old_Gt = melt_old / 1000 * area_annual - melt_old_trishuli = melt_old_Gt.sum(axis=0) - - melt_new_monthly = ds_new.melt_glac_monthly.values[:,:,0] - melt_new = gcmbiasadj.annual_sum_2darray(melt_new_monthly) - melt_new_Gt = melt_new / 1000 * area_annual - melt_new_trishuli = melt_new_Gt.sum(axis=0) - - dif_melt = melt_new_trishuli.sum() - melt_old_trishuli.sum() - print('DIFFERENCE Melt TOTAL:\n', np.round(dif_melt,1), 'Gt', - np.round(dif_melt / melt_old_trishuli.sum() * 100, 1), '%') - - # Compare refreeze - refreeze_old_monthly = ds_old.refreeze_glac_monthly.values[df_old_idx,time_old_idx_start:,0] - refreeze_old = gcmbiasadj.annual_sum_2darray(refreeze_old_monthly) - refreeze_old_Gt = refreeze_old / 1000 * area_annual - refreeze_old_trishuli = refreeze_old_Gt.sum(axis=0) - - refreeze_new_monthly = ds_new.refreeze_glac_monthly.values[:,:,0] - refreeze_new = gcmbiasadj.annual_sum_2darray(refreeze_new_monthly) - refreeze_new_Gt = refreeze_new / 1000 * area_annual - refreeze_new_trishuli = refreeze_new_Gt.sum(axis=0) - - dif_refreeze = refreeze_new_trishuli.sum() - refreeze_old_trishuli.sum() - print('DIFFERENCE refreeze TOTAL:\n', np.round(dif_refreeze,1), 'Gt', - np.round(dif_refreeze / refreeze_old_trishuli.sum() * 100, 1), '%') - - #%% - # Set up your plot (and/or subplots) - fig, ax = plt.subplots(1, 1, squeeze=False, sharex=False, sharey=False, gridspec_kw = {'wspace':0.4, 'hspace':0.15}) - ax[0,0].plot(years, totalrunoff_new_trishuli, color='k', linewidth=1, zorder=2, label='new') - ax[0,0].plot(years, totalrunoff_old_trishuli, color='b', linewidth=1, zorder=2, label='old') - -# ax[0,0].text(0.5, 0.99, '[insert text]', size=10, horizontalalignment='center', verticalalignment='top', -# transform=ax[0,0].transAxes) - - ax[0,0].set_ylabel('Glacier Runoff [Gt]', size=12) - ax[0,0].legend(loc=(0.05, 0.05), fontsize=10, labelspacing=0.25, handlelength=1, handletextpad=0.25, borderpad=0, - frameon=False) - - # Save figure - # figures can be saved in any format (.jpg, .png, .pdf, etc.) - fig.set_size_inches(4, 4) - figure_fp = os.getcwd() + '/../Output/' - if os.path.exists(figure_fp) == False: - os.makedirs(figure_fp) - figure_fn = 'Trishuli_runoff_comparison_2016_2100.png' - fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300) - -#if option_trishuli == 1: -# glac_no = input.glac_fromcsv(input.main_directory + '/../qgis_himat/trishuli_shp/trishuli_RGIIds.csv') -# main_glac_rgi = modelsetup.selectglaciersrgitable(glac_no=glac_no) -# -## ds_new = xr.open_dataset(input.output_sim_fp + 'ERA-Interim/Trishuli_ERA-Interim_c2_ba1_100sets_2000_2017.nc') -## ds_old13 = xr.open_dataset(input.output_sim_fp + 'ERA-Interim/ERA-Interim_1980_2017_nochg/' + -## 'R13_ERA-Interim_c2_ba1_100sets_1980_2017.nc') -## ds_old15 = xr.open_dataset(input.output_sim_fp + 'ERA-Interim/ERA-Interim_1980_2017_nochg/' + -## 'R15_ERA-Interim_c2_ba1_100sets_1980_2017.nc') -## time_old_idx_start = 12*20 -## time_new_idx_start = 0 -## years = np.arange(2000,2018) -## option_components = 1 -# -# ds_new = xr.open_dataset(input.output_sim_fp + 'IPSL-CM5A-LR/' + -# 'Trishuli_IPSL-CM5A-LR_rcp85_c2_ba1_100sets_2000_2100.nc') -# ds_old13 = xr.open_dataset(input.output_sim_fp + 'spc_subset/' + -# 'R13_IPSL-CM5A-LR_rcp26_c2_ba1_100sets_2000_2100--subset.nc') -# ds_old15 = xr.open_dataset(input.output_sim_fp + 'spc_subset/' + -# 'R15_IPSL-CM5A-LR_rcp26_c2_ba1_100sets_2000_2100--subset.nc') -# time_old_idx_start = 16*12 -# time_new_idx_start = 16*12 -# years = np.arange(2016,2101) -# option_components = 0 -# -# # Concatenate datasets -# ds_old = xr.concat([ds_old13, ds_old15], dim='glac') -# -# df_old = pd.DataFrame(ds_old.glacier_table.values, columns=ds_old.glac_attrs) -# df_old.reset_index(inplace=True, drop=True) -# df_old['rgino_str'] = [str(int(df_old.loc[x,'O1Region'])) + '.' + str(int(df_old.loc[x,'glacno'])).zfill(5) -# for x in np.arange(df_old.shape[0])] -# -# # Find indices to select data from -# df_old_idx = np.where(df_old.rgino_str.isin(main_glac_rgi.rgino_str.values))[0] -# -# runoff_old_monthly = ds_old.runoff_glac_monthly.values[df_old_idx,time_old_idx_start:,0] -# offglac_runoff_old_monthly = ds_old.offglac_runoff_monthly.values[df_old_idx,time_old_idx_start:,0] -# totalrunoff_old_monthly = (runoff_old_monthly + offglac_runoff_old_monthly) / 10**9 -# totalrunoff_old = gcmbiasadj.annual_sum_2darray(totalrunoff_old_monthly) -# totalrunoff_old_trishuli = totalrunoff_old.sum(axis=0) -# -# runoff_new_monthly = ds_new.runoff_glac_monthly.values[:,time_new_idx_start:,0] -# offglac_runoff_new_monthly = ds_new.offglac_runoff_monthly.values[:,time_new_idx_start:,0] -# totalrunoff_new_monthly = (runoff_new_monthly + offglac_runoff_new_monthly) / 10**9 -# totalrunoff_new = gcmbiasadj.annual_sum_2darray(totalrunoff_new_monthly) -# totalrunoff_new_trishuli = totalrunoff_new.sum(axis=0) -# -# dif_runoff = totalrunoff_new_trishuli.sum() - totalrunoff_old_trishuli.sum() -# print('DIFFERENCE RUNOFF TOTAL:\n', np.round(dif_runoff,1), 'Gt', -# np.round(dif_runoff / totalrunoff_old_trishuli.sum()*100,1), '%') -# -# -# if option_components == 1: -# area_annual = ds_old.area_glac_annual.values[df_old_idx,20:,0][:,:-1] -# # Compare precipitation -# prec_old_monthly = ds_old.prec_glac_monthly.values[df_old_idx,time_old_idx_start:,0] -# acc_old_monthly = ds_old.acc_glac_monthly.values[df_old_idx,time_old_idx_start:,0] -# totalprec_old_monthly = prec_old_monthly + acc_old_monthly -# totalprec_old = gcmbiasadj.annual_sum_2darray(totalprec_old_monthly) -# totalprec_old_Gt = totalprec_old / 1000 * area_annual -# totalprec_old_trishuli = totalprec_old_Gt.sum(axis=0) -# -# -# prec_new_monthly = ds_new.prec_glac_monthly.values[:,:,0] -# acc_new_monthly = ds_new.acc_glac_monthly.values[:,:,0] -# totalprec_new_monthly = prec_new_monthly + acc_new_monthly -# totalprec_new = gcmbiasadj.annual_sum_2darray(totalprec_new_monthly) -# totalprec_new_Gt = totalprec_new / 1000 * area_annual -# totalprec_new_trishuli = totalprec_new_Gt.sum(axis=0) -# -# pf_dif = totalprec_new / totalprec_old -# dif_totalprec = totalprec_new_trishuli.sum() - totalprec_old_trishuli.sum() -# print('DIFFERENCE PRECIPITATION TOTAL:\n', np.round(dif_totalprec,1), 'Gt', -# np.round(dif_totalprec / totalprec_old_trishuli.sum() * 100, 1), '%') -# -# # Compare melt -# melt_old_monthly = ds_old.melt_glac_monthly.values[df_old_idx,time_old_idx_start:,0] -# melt_old = gcmbiasadj.annual_sum_2darray(melt_old_monthly) -# melt_old_Gt = melt_old / 1000 * area_annual -# melt_old_trishuli = melt_old_Gt.sum(axis=0) -# -# melt_new_monthly = ds_new.melt_glac_monthly.values[:,:,0] -# melt_new = gcmbiasadj.annual_sum_2darray(melt_new_monthly) -# melt_new_Gt = melt_new / 1000 * area_annual -# melt_new_trishuli = melt_new_Gt.sum(axis=0) -# -# dif_melt = melt_new_trishuli.sum() - melt_old_trishuli.sum() -# print('DIFFERENCE Melt TOTAL:\n', np.round(dif_melt,1), 'Gt', -# np.round(dif_melt / melt_old_trishuli.sum() * 100, 1), '%') -# -# # Compare refreeze -# refreeze_old_monthly = ds_old.refreeze_glac_monthly.values[df_old_idx,time_old_idx_start:,0] -# refreeze_old = gcmbiasadj.annual_sum_2darray(refreeze_old_monthly) -# refreeze_old_Gt = refreeze_old / 1000 * area_annual -# refreeze_old_trishuli = refreeze_old_Gt.sum(axis=0) -# -# refreeze_new_monthly = ds_new.refreeze_glac_monthly.values[:,:,0] -# refreeze_new = gcmbiasadj.annual_sum_2darray(refreeze_new_monthly) -# refreeze_new_Gt = refreeze_new / 1000 * area_annual -# refreeze_new_trishuli = refreeze_new_Gt.sum(axis=0) -# -# dif_refreeze = refreeze_new_trishuli.sum() - refreeze_old_trishuli.sum() -# print('DIFFERENCE refreeze TOTAL:\n', np.round(dif_refreeze,1), 'Gt', -# np.round(dif_refreeze / refreeze_old_trishuli.sum() * 100, 1), '%') -# -# #%% -# # Set up your plot (and/or subplots) -# fig, ax = plt.subplots(1, 1, squeeze=False, sharex=False, sharey=False, gridspec_kw = {'wspace':0.4, 'hspace':0.15}) -# ax[0,0].plot(years, totalrunoff_new_trishuli, color='k', linewidth=1, zorder=2, label='new') -# ax[0,0].plot(years, totalrunoff_old_trishuli, color='b', linewidth=1, zorder=2, label='old') -# -## ax[0,0].text(0.5, 0.99, '[insert text]', size=10, horizontalalignment='center', verticalalignment='top', -## transform=ax[0,0].transAxes) -# -# ax[0,0].set_ylabel('Glacier Runoff [Gt]', size=12) -# ax[0,0].legend(loc=(0.05, 0.05), fontsize=10, labelspacing=0.25, handlelength=1, handletextpad=0.25, borderpad=0, -# frameon=False) -# -# # Save figure -# # figures can be saved in any format (.jpg, .png, .pdf, etc.) -# fig.set_size_inches(4, 4) -# figure_fp = os.getcwd() + '/../Output/' -# if os.path.exists(figure_fp) == False: -# os.makedirs(figure_fp) -# figure_fn = 'Trishuli_runoff_comparison_2016_2100.png' -# fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300) - - - - - - - - - - - - - \ No newline at end of file diff --git a/analyze_massredistribution.py b/analyze_massredistribution.py deleted file mode 100644 index e62772d2..00000000 --- a/analyze_massredistribution.py +++ /dev/null @@ -1,1374 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Created on Wed Jul 25 17:13:22 2018 - -@author: kitreatakataglushkoff -Kitrea's hand-written copied/adjusted version of the analyze_massredistribution.py, -which was last significantly edited Thursday July 18. - -UPDATE - Oct 9, 2018 - Kitrea double-checked code, added some comments. -last updated Wed Nov 14 - to clean out bad data in the new large dataset. -""" -import pandas as pd -import numpy as np -import os -import glob -import matplotlib.pyplot as plt -import copy - -import pygem_input as input -import pygemfxns_modelsetup as modelsetup - -# Tips, comments, and old portions of code no longer used have been moved to bottom of file - -#%% ===== REGION AND GLACIER FILEPATH OPTIONS ===== -# User defines regions of interest -rgi_regionO1 = [13, 14, 15] -#rgi_regionO1 = [15] -search_binnedcsv_fn = (input.main_directory + '/../DEMs/Shean_2018_1109/aster_2000-2018_20181109_bins/*_mb_bins.csv') - -#%% ===== PLOT OPTIONS ===== -# Option to save figures -option_savefigs = 1 -fig_fp = input.main_directory + '/../Output/figures/massredistribution/' - -# Plot histogram options -option_plot_histogram = 0 -histogram_parameters = ['Area', 'Zmed', 'Slope', 'PercDebris'] -#histogram_parameters = ['Area', 'Zmin', 'Zmax', 'Zmed', 'Slope', 'Aspect', 'Lmax', 'PercDebris'] - -# Plot dhdt of each glacier options -option_plot_eachglacier = 0 - -# Plot glaciers above and below a given parameter threshold (*MAIN FUNCTION TO RUN) -option_plot_multipleglaciers_single_thresholds = 0 -# run for specific parameter or all parameters -option_run_specific_pars = 0 - -# Plot glaciers above and below a given set of multiple thresholds -option_plot_multipleglaciers_multiplethresholds = 0 - -# Plot glacier characteristics to see if parameters are related -option_plot_compareparameters = 1 - -#option_plot_multipleglaciers_binned_parameter = 0 #glaciers within a characteristic's defined range -#option_plot_multipleglaciers_indiv_subdivisions = 0 #glaciers binned into 6 categories. (NOT USED) -#option_plots_threshold = 0 #scatter plots relating glacier stats - -# Columns to use for mass balance and dhdt (specify mean or median) -mb_cn = 'mb_bin_med_mwea' -dhdt_cn = 'dhdt_bin_med_ma' -dhdt_max = 2.5 -dhdt_min = -4 -# Threshold for tossing glaciers with too much missing data -perc_area_valid_threshold = 90 -# Switch to use merged data or not (0 = don't use, 1 = use merged data) -option_use_mergedata = 0 -# Remove glacier options (surging, all positive dhdt, etc.) -option_remove_surge_glac = 1 -option_remove_all_pos_dhdt = 1 -option_remove_dhdt_acc = 1 -acc_dhdt_threshold = 0.5 - -# Legend option (switch to show legend on multi-glacier figures or not) -option_show_legend = 0 -# Transparency value (between 0 & 1: 0 = no plot, 1 = full opaque) -glacier_plots_transparency = 0.3 - - - -#user-defined stored variables for ideal thresholds, for each region and parameter -Area_15_thresholds = list(range(5,40, 5)) -Area_13_thresholds = list(range(5, 120, 5)) -Area_13_thresholds.extend([150, 200, 250, 300, 350]) #if histogram has 2 separate ranges use .extend -Slope_15_thresholds = list(range(10,26,2)) -Slope_13_thresholds = list(range(5, 40, 2)) -PercDebris_13_thresholds = list(range(0,65,5)) -PercDebris_15_thresholds = list(range(0, 65, 5)) -Zmin_13_thresholds = list(range(2600,5800, 200)) -Zmin_15_thresholds = list(range(3500, 6500, 500)) -Zmed_13_thresholds = list(range(3800, 6600, 200)) -Zmed_15_thresholds = list(range(4750, 7000, 500)) -Aspect_13_thresholds = list(range(0, 450, 90)) -Aspect_15_thresholds = list(range(0, 450, 90)) -Zmax_15_thresholds = list(range(6000, 7600, 200)) -Zmax_13_thresholds = list(range(4000, 7600, 200)) -Lmax_15_thresholds = list(range(4000, 14000, 2000)) -Lmax_13_thresholds = list(range(4400, 40000, 2000)) -Lmax_13_thresholds.extend([56000, 58000, 6000]) -dhdt_13_thresholds = [1] - -Area_14_thresholds = list(range(5, 120, 5,)) -Area_14_thresholds.extend([150, 200, 250, 300, 350]) -Zmin_14_thresholds = list(range(2600, 5800, 200)) -Zmax_14_thresholds = list(range(5000, 7600, 200)) -Zmed_14_thresholds = list(range(3800,6400, 200)) -Slope_14_thresholds = list(range(10, 42, 2)) -Aspect_14_thresholds = list(range(0,450,90)) -Lmax_14_thresholds = list(range(4000, 45000,2000)) -PercDebris_14_thresholds = list(range(0, 65,5)) - -#For plotting one parameter at a time -#User defines parameter for multi-glacier and histogram runs -#set the threshold equal to one of the above, defined thresholds, depending on the current -#keep in mind for threshold, that the subplots are examining >= and < the threshold - -#If you have not yet evaluated the histograms to define the threshold ranges, -#then you must define the following variable - -#For plotting multiple parameters in one run -#Create dictionary. key = parameter found in main_glac_rgi, value = thresholds -all_13_pars = {'Area': Area_13_thresholds, 'Zmin': Zmin_13_thresholds , - 'Zmax':Zmax_13_thresholds, 'Zmed': Zmed_13_thresholds, - 'Slope': Slope_13_thresholds, 'Aspect': Aspect_13_thresholds, - 'Lmax': Lmax_13_thresholds, 'PercDebris': PercDebris_13_thresholds} - -all_14_pars = {'Area': Area_14_thresholds, 'Zmin': Zmin_14_thresholds , - 'Zmax':Zmax_14_thresholds, 'Zmed': Zmed_14_thresholds, - 'Slope': Slope_14_thresholds, 'Aspect': Aspect_14_thresholds, - 'Lmax': Lmax_14_thresholds, 'PercDebris': PercDebris_14_thresholds} - -all_15_pars = {'Area': Area_15_thresholds , 'Zmin': Zmin_15_thresholds , - 'Zmax':Zmax_15_thresholds, 'Zmed': Zmed_15_thresholds, - 'Slope': Slope_15_thresholds, 'Aspect': Aspect_15_thresholds, - 'Lmax': Lmax_15_thresholds, 'PercDebris': PercDebris_15_thresholds} - -#If only plotting one parameter in the run, define the parameter of interest -pars_dict = {'PercDebris': PercDebris_13_thresholds} - -if option_run_specific_pars == 1: - region_pars = pars_dict -else: - if rgi_regionO1[0] == 13: - region_pars = all_13_pars - elif rgi_regionO1[0] == 14: - region_pars = all_14_pars - elif rgi_regionO1[0] == 15: - region_pars = all_15_pars - else: - print("Please Check Region Specification") - - -#Binned CSV column name conversion dictionary -# change column names so they are easier to work with (remove spaces, etc.) -sheancoldict = {'# bin_center_elev_m': 'bin_center_elev_m', - ' z1_bin_count_valid': 'z1_bin_count_valid', - ' z1_bin_area_valid_km2': 'z1_bin_area_valid_km2', - ' z1_bin_area_perc': 'z1_bin_area_perc', - ' z2_bin_count_valid': 'z2_bin_count_valid', - ' z2_bin_area_valid_km2': 'z2_bin_area_valid_km2', - ' z2_bin_area_perc': 'z2_bin_area_perc', - ' dhdt_bin_count' : 'dhdt_bin_count', - ' dhdt_bin_area_valid_km2' : 'dhdt_bin_area_valid_km2', - ' dhdt_bin_area_perc' : 'dhdt_bin_area_perc', - ' dhdt_bin_med_ma': 'dhdt_bin_med_ma', - ' dhdt_bin_mad_ma': 'dhdt_bin_mad_ma', - ' dhdt_bin_mean_ma': 'dhdt_bin_mean_ma', - ' dhdt_bin_std_ma': 'dhdt_bin_std_ma', - ' mb_bin_med_mwea': 'mb_bin_med_mwea', - ' mb_bin_mad_mwea': 'mb_bin_mad_mwea', - ' mb_bin_mean_mwea': 'mb_bin_mean_mwea', - ' mb_bin_std_mwea': 'mb_bin_std_mwea', - ' debris_thick_med_m': 'debris_thick_med_m', - ' debris_thick_mad_m': 'debris_thick_mad_m', - ' perc_debris': 'perc_debris', - ' perc_pond': 'perc_pond', - ' perc_clean': 'perc_clean', - ' dhdt_debris_med' : 'dhdt_debris_med', - ' dhdt_pond_med' : 'dhdt_pond_med', - ' dhdt_clean_med' : 'dhdt_clean_med', - ' vm_med' : 'vm_med', - ' vm_mad' : 'vm_mad', - ' H_mean' : 'H_mean', - ' H_std' : 'H_std'} - -#%% Select Files -# Find files for analysis; create list of all binnedcsv filenames (fn) -binnedcsv_files_all = glob.glob(search_binnedcsv_fn) - -# Fill in dataframe of glacier names and RGI IDs, of ALL glaciers with binnedcsv, regardless of the region -df_glacnames_all = pd.DataFrame() #empty df -df_glacnames_all['reg_glacno'] = [x.split('/')[-1].split('_')[0] for x in binnedcsv_files_all] -df_glacnames_all['RGIId'] = 'RGI60-' + df_glacnames_all.reg_glacno -# turn region column values from object to float to int, to store just reg -df_glacnames_all['region'] = df_glacnames_all.reg_glacno.astype(float).astype(int) -# split glacno into list of reg and id, and store just the id part as an object -df_glacnames_all['glacno_str'] = (df_glacnames_all.reg_glacno.str.split('.').apply(lambda x: x[1])) -# store the same value as glacno_str, but as an int -df_glacnames_all['glacno'] = df_glacnames_all.glacno_str.astype(int) - -# Define df_glacnames containing ONLY the data for desired region(s) -df_glacnames = df_glacnames_all[df_glacnames_all.region.isin(rgi_regionO1) == True] -# make list of all binnedcsv file pathway names -binnedcsv_files = [binnedcsv_files_all[x] for x in df_glacnames.index.values] -# Sort glaciers by region and glacier number -binnedcsv_files = sorted(binnedcsv_files) -df_glacnames = df_glacnames.sort_values('reg_glacno') -df_glacnames.reset_index(drop=True, inplace=True) - -# Create dataframe with RGI attributes for each glacier -main_glac_rgi = pd.DataFrame() - -for n, region in enumerate(rgi_regionO1): - print('Region', region) - df_glacnames_reg = df_glacnames[df_glacnames.region == region] #temp df for one reg at a time - rgi_glac_number = df_glacnames_reg['glacno_str'].tolist() - #If statement to avoid errors associated with regions that have no glaciers - if len(rgi_glac_number) > 0: - #pullselect data from fxn outputs of pygemfxnsmodelsetup, and from - #pathways and vars defined in pygem input file - main_glac_rgi_reg= modelsetup.selectglaciersrgitable(rgi_regionsO1=[region], rgi_regionsO2='all', - rgi_glac_number=rgi_glac_number) - # concatenate regions - main_glac_rgi = main_glac_rgi.append(main_glac_rgi_reg, ignore_index=True) - -#%%MAIN DATASET -# ds is the main dataset for this analysis and is a list of lists (order of glaciers can be found in df_glacnames) -# Data for each glacier is held in a sublist -ds = [] -norm_list = [] -for n in range(len(binnedcsv_files)): - # Note: RuntimeWarning: invalid error encountered in greater than is due - # to nan and zero values being included in array. This error can be ignored. - # Process binned geodetic data - binnedcsv = pd.read_csv(binnedcsv_files[n]) - # Rename columns so they are easier to read - binnedcsv = binnedcsv.rename(columns=sheancoldict) - - # ===== Filter out bad values ========================================================== - # Replace strings of nan with nan and make all columns floats or ints - binnedcsv = binnedcsv.replace([' nan'], [np.nan]) - for col in binnedcsv.columns.values: - binnedcsv[col] = pd.to_numeric(binnedcsv[col]) - # Remove bad values of dhdt - binnedcsv.loc[binnedcsv[dhdt_cn] > dhdt_max, dhdt_cn] = np.nan - binnedcsv.loc[binnedcsv[dhdt_cn] < dhdt_min, dhdt_cn] = np.nan - # If dhdt is nan, remove row - null_bins = binnedcsv.loc[pd.isnull(binnedcsv[dhdt_cn])].index.values - binnedcsv = binnedcsv.drop(null_bins) - # Add percent area valid to main_glac_rgi - main_glac_rgi.loc[n, 'perc_areavalid'] = binnedcsv['z1_bin_area_perc'].sum() - # Debris thickness - binnedcsv['debris_thick_med_m'] = binnedcsv['debris_thick_med_m'].astype(float) - binnedcsv.loc[pd.isnull(binnedcsv['debris_thick_med_m']), 'debris_thick_med_m'] = 0 - binnedcsv.loc[binnedcsv['debris_thick_med_m'] < 0, 'debris_thick_med_m'] = 0 - binnedcsv.loc[binnedcsv['debris_thick_med_m'] > 5, 'debris_thick_med_m'] = 0 - binnedcsv.loc[binnedcsv['debris_thick_med_m'] == -0, 'debris_thick_med_m'] = 0 - #Percent Debris - binnedcsv.loc[binnedcsv['perc_debris'] > 100, 'perc_debris'] = 0 - binnedcsv.loc[binnedcsv['perc_debris'] <= 0, 'perc_debris'] = 0 - # Supraglacial ponds - binnedcsv.loc[binnedcsv['perc_pond'] > 100, 'perc_pond'] = 0 - binnedcsv.loc[binnedcsv['perc_pond'] <= 0, 'perc_pond'] = 0 - # Clean ice - binnedcsv.loc[binnedcsv['perc_clean'] > 100, 'perc_clean'] = 0 - binnedcsv.loc[binnedcsv['perc_clean'] <= 0, 'perc_clean'] = 0 - - # Find glacier-wide debris perc for each glacier, and add to main_glac_rgi - glacwide_debris = ((binnedcsv['z1_bin_area_valid_km2']*binnedcsv['perc_debris']).sum() - / binnedcsv['z1_bin_area_valid_km2'].sum()) - main_glac_rgi.loc[n, 'PercDebris'] = glacwide_debris - #sort out glaciers based on if they have all positive dh/dt, all negative, dh/dt, or both - #based on evaluating, for each glacier, the max from the list of dhdt and the min from the list. - if np.nanmin(binnedcsv[dhdt_cn].astype(float)) >= 0: - glacwide_dhdt_sign = 1 #glaciers with all positive dh/dt - elif np.nanmax(binnedcsv[dhdt_cn].astype(float)) <= 0: - glacwide_dhdt_sign = -1 #glaciers with all negative dh/dt - else: - glacwide_dhdt_sign = 0 #glaciers with both, + and - dh/dt - main_glac_rgi.loc[n, 'dhdt_sign'] = glacwide_dhdt_sign - - # ===== Normalized elevation vs. ice thickness change =============================== - # Normalized elevation - # (max elevation - bin elevation) / (max_elevation - min_elevation) - glac_elev = binnedcsv.bin_center_elev_m.values - binnedcsv['elev_norm'] = (glac_elev[-1] - glac_elev) / (glac_elev[-1] - glac_elev[0]) - # Normalized ice thickness change [ma] - # dhdt / dhdt_max - glac_dhdt = binnedcsv[dhdt_cn].values.astype(float) - # Shifted normalized ice thickness change such that everything is negative - binnedcsv['dhdt_norm_shifted'] = (glac_dhdt - np.nanmax(glac_dhdt)) / np.nanmin(glac_dhdt - np.nanmax(glac_dhdt)) - binnedcsv.loc[binnedcsv['dhdt_norm_shifted'] == -0, 'dhdt_norm_shifted'] = 0 - # Replace positive values to zero - glac_dhdt[glac_dhdt >= 0] = 0 - binnedcsv['dhdt_norm_huss'] = glac_dhdt / np.nanmin(glac_dhdt) - binnedcsv.loc[binnedcsv['dhdt_norm_huss'] == -0, 'dhdt_norm_huss'] = 0 - - # ===== ADD DATA TO MAIN DATASET ===================================================== - # ds is the main datset, n is index of each glacier - # Keep only glaciers with enough good data based on percentage area valid - if main_glac_rgi.loc[n, 'perc_areavalid'] > perc_area_valid_threshold: - ds.append([n, df_glacnames.loc[n, 'RGIId'], binnedcsv, main_glac_rgi.loc[n]]) - # ds.append([n, df_glacnames.loc[n, 'RGIId'], binnedcsv, main_glac_rgi.loc[n], main_glac_hyps.loc[n], - # main_glac_icethickness.loc[n], ds_merged_bins]) - -#%% Remove Unwanted Glaciers -# NOTE: TO USE MAIN_GLAC_RGI ATTRIBUTES, NEED TO ACCESS THEM VIA THE DATASET -# remove them from both ds and norm_list -remove_idx = [] - -# Indices to remove Surging glaciers (listed as 1 possible, 2 probable, or 3 observed in main_glac_rgi) -if option_remove_surge_glac == 1: - # Remove indices - remove_idx_surge = [i for i in range(len(ds)) if ((ds[i][3].Surging != 9) and (ds[i][3].Surging != 0))] - # Add unique values to list - for i in remove_idx_surge: - if i not in remove_idx: - remove_idx.append(i) - -# Indices to remove glaciers with all positive dh/dt values (listed as 1 in main_glac_rgi) -if option_remove_all_pos_dhdt == 1: - #add index of glaciers with all pos values to the Int64 Index list - remove_idx_allposdhdt = [i for i in range(len(ds)) if ds[i][3].dhdt_sign == 1] - for i in remove_idx_allposdhdt: - if i not in remove_idx: - remove_idx.append(i) - -# Indices to remove glaciers who have max surface lowering in accumulation area -if option_remove_dhdt_acc == 1: - remove_idx_acc = [] - for glac in range(len(ds)): - glac_elevnorm = ds[glac][2]['elev_norm'].values - glac_dhdt_norm = ds[glac][2]['dhdt_norm_huss'].values - acc_idx = np.where(glac_elevnorm < 0.5)[0] - if (glac_dhdt_norm[acc_idx] > acc_dhdt_threshold).any(): - remove_idx_acc.append(glac) - for i in remove_idx_acc: - if i not in remove_idx: - remove_idx.append(i) - -# ===== Remove glaciers ===== -all_glac_idx = range(len(ds)) -ds = [ds[i] for i in all_glac_idx if i not in remove_idx] - -# ===== Normalized elevation versus ice thickness change list ====== -# List of np.array where first column is elev_norm and second column is dhdt_norm -# Each item is a glacier -norm_list = [np.array([ds[i][2]['elev_norm'].values, ds[i][2]['dhdt_norm_huss'].values]).transpose() - for i in range(len(ds))] - - -#%% MEAN AND STANDARD DEVIATIONS OF CURVES (black lines to add onto plots) -def normalized_stats(norm_list): - # Merge norm_list to make array of all glaciers with same elevation normalization space - max_length = len(max(norm_list,key=len)) #len of glac w most norm values - norm_all = np.zeros((max_length, len(norm_list)+1)) #array: each col a glac, each row a norm dhdt val to be interpolated - # First column is normalized elevation, pulled from the glac with most norm vals - norm_all[:,0] = max(norm_list,key=len)[:,0] - - # Loop through each glacier's normalized array (where col1 is elev_norm and col2 is norm dhdt) - for n in range(len(norm_list)): -# print(main_glac_rgi.loc[n,'RGIId']) #NOT SURE IF THIS WILL SHOW THE CORRECT CORRESPONDING GLACIER - norm_single = norm_list[n] # get one glacier at a time - -# #Skip over glaciers that contain only NaN values for normalized dhdt -# #(I added this so that it could run, but I want to be sure it doesn't have weird implications.) -# if np.isnan(norm_single[:,1][0]) == True and np.isnan(norm_single[:,1][-1]) == True: -## print('The current glacier likely only contains NaNs, and is being skipped') -# continue -# #also skip over glaciers that contain almost all 0 values . - - # Fill in nan values for elev_norm of 0 and 1 with nearest neighbor - norm_single[0,1] = norm_single[np.where(~np.isnan(norm_single[:,1]))[0][0], 1] - norm_single[-1,1] = norm_single[np.where(~np.isnan(norm_single[:,1]))[0][-1], 1] - # Remove nan values. - norm_single = norm_single[np.where(~np.isnan(norm_single[:,1]))] #~ is the same as ! - elev_single = norm_single[:,0] #set name for first col of a given glac - dhdt_single = norm_single[:,1] #set name for the second col of a given glac - #loop through each dhdt value of the glacier, and add it and interpolate to add to the - #norm_all array. - for r in range(0, max_length): - if r == 0: - norm_all[r,n+1] = dhdt_single[0] #put the first value dhdt value into the norm_all. n+1 because the first col is taken by the elevnorms. - elif r == (max_length - 1): - norm_all[r,n+1] = dhdt_single[-1] #put the last value into the the last row for the glacier's 'stretched out'(interpolated) normalized curve. - else: - # Find value need to interpolate to - norm_elev_value = norm_all[r,0] #go through each row in the elev (col1) - # Find index of value above it from dhdt_norm, which is a different size - upper_idx = np.where(elev_single == elev_single[elev_single >= norm_elev_value].min())[0][0] - # Find index of value below it - lower_idx = np.where(elev_single == elev_single[elev_single < norm_elev_value].max())[0][0] - #get the two values, based on the indices. - upper_elev = elev_single[upper_idx] - upper_value = dhdt_single[upper_idx] - lower_elev = elev_single[lower_idx] - lower_value = dhdt_single[lower_idx] - #Linearly Interpolate between two values, and plug in interpolated value into norm_all - norm_all[r,n+1] = (lower_value + (norm_elev_value - lower_elev) / (upper_elev - lower_elev) * - (upper_value - lower_value)) - - # Compute mean and standard deviation - norm_all_stats = pd.DataFrame() - norm_all_stats['norm_elev'] = norm_all[:,0] - norm_all_stats['norm_dhdt_mean'] = np.nanmean(norm_all[:,1:], axis=1) - norm_all_stats['norm_dhdt_std'] = np.nanstd(norm_all[:,1:], axis=1) - norm_all_stats['norm_dhdt_68high'] = norm_all_stats['norm_dhdt_mean'] + norm_all_stats['norm_dhdt_std'] - norm_all_stats['norm_dhdt_68low'] = norm_all_stats['norm_dhdt_mean'] - norm_all_stats['norm_dhdt_std'] - norm_all_stats.loc[norm_all_stats['norm_dhdt_68high'] > 1, 'norm_dhdt_68high'] = 1 - norm_all_stats.loc[norm_all_stats['norm_dhdt_68low'] < 0, 'norm_dhdt_68low'] = 0 - return norm_all_stats - -norm_stats = normalized_stats(norm_list) - -#%% Plots comparing glacier parameters to see if any are related -if option_plot_compareparameters == 1: - parameter1 = 'Area' - parameter2 = 'Lmax' - A = np.array([ds[x][3][parameter1] for x in range(len(ds))]) - B = np.array([ds[x][3][parameter2] for x in range(len(ds))]) - - param_label_dict = {'Area': 'Area [km2]', - 'PercDebris': 'Debris cover[%]', - 'Slope':'Slope [deg]', - 'Lmax': 'Length [km]'} - # ===== PLOT ===== - fig_width = 4 - fig_height = 3 - fig, ax = plt.subplots(1, 1, squeeze=False, figsize=(fig_width,fig_height), - gridspec_kw = {'wspace':0.2, 'hspace':0.5}) - ax[0,0].scatter(A,B, color='k', s=1) - ax[0,0].set_xlabel(param_label_dict[parameter1], size=14) - ax[0,0].set_ylabel(param_label_dict[parameter2], size=14) - # Save figure - fig.savefig(fig_fp + ('scatter_' + parameter1 + '_' + parameter2 + '.png'), bbox_inches='tight', dpi=300) - - -#%% Plots for a histogram of parameter (distribution of values) -def plot_var_histogram(): - #plot histogram, where x-axis is the testing_var values, and y-axis is how many glaciers have that given x-axis value - for parameter in histogram_parameters: - parameter_values = np.array([ds[i][3][parameter] for i in range(len(ds))]) - plt.hist(parameter_values, 50) - plt.xlabel(parameter) - plt.ylabel('Number of glaciers') - plt.title(parameter + ' Distribution' ' Region' + str(rgi_regionO1)) - plt.minorticks_on() - - if option_savefigs == 1: - hist_fp = fig_fp + 'histograms/' - if not os.path.exists(hist_fp): - os.makedirs(hist_fp) - plt.savefig(hist_fp + parameter + '_histogram_reg_' + str(rgi_regionO1), bbox_inches='tight') - plt.show() - - parameter_lower_bound = int(parameter_values.min()) - parameter_upper_bound = np.ceil(parameter_values.max()) - print('Range of '+ parameter+ ': (' + str(parameter_lower_bound) + ', ' + str(parameter_upper_bound) + ')') - -if option_plot_histogram == 1: - plot_var_histogram() - - -#%% Plots for a single glacier -def plot_eachglacier(ds, option_merged_dataset=0): - # Set position of dataset to plot in list based on using merged or unmerged elev bin data - # [2 = 10m, 6 = merged] - if option_merged_dataset == 0: - ds_position = 2 - elif option_merged_dataset == 1: - ds_position = 6 - - individual_fp = fig_fp + 'individual_plots/' - if not os.path.exists(individual_fp): - os.makedirs(individual_fp) - - # Loop through glaciers and plot - for glac in range(len(ds)): - #pull values from binnedcsv into vars - glac_elevbins = ds[glac][ds_position]['bin_center_elev_m'] - glac_area_t1 = ds[glac][ds_position]['z1_bin_area_valid_km2'] - glac_area_t2 = ds[glac][ds_position]['z2_bin_area_valid_km2'] - glac_mb_mwea = ds[glac][ds_position][mb_cn] - glac_debristhick_cm = ds[glac][ds_position]['debris_thick_med_m'] * 100 - glac_debrisperc = ds[glac][ds_position]['perc_debris'] - glac_pondperc = ds[glac][ds_position]['perc_pond'] - glac_elevnorm = ds[glac][ds_position]['elev_norm'] - glac_dhdt_med = ds[glac][ds_position]['dhdt_bin_med_ma'] - glac_dhdt_norm_huss = ds[glac][ds_position]['dhdt_norm_huss'] - glac_dhdt_norm_shifted = ds[glac][ds_position]['dhdt_norm_shifted'] - glac_elevs = ds[glac][ds_position]['bin_center_elev_m'] - glacwide_mb_mwea = (glac_area_t1 * glac_mb_mwea).sum() / glac_area_t1.sum() - glac_name = ds[glac][1].split('-')[1] - - # dhdt (raw) vs. elevation (raw) - plt.figure(figsize = (20, 12)) - plt.plot(glac_elevs, glac_dhdt_med, label=glac_name) - plt.gca().invert_xaxis() - plt.xlabel('Elevation (m)') - plt.ylabel('Ice thickness Change [m/a]') - plt.title('Raw dh/dt\n') - plt.minorticks_on() - - # Plot Elevation bins vs. Area, Mass balance, and Debris thickness/pond coverage/ debris coverage - plt.figure(figsize=(10,6)) - plt.subplots_adjust(wspace=0.05, hspace=0.05) - plt.suptitle(ds[glac][1], y=0.94) - # Elevation vs. Area - plt.subplot(1,3,1) - plt.plot(glac_area_t1, glac_elevbins, label='t1') - plt.plot(glac_area_t2, glac_elevbins, label='t2') - plt.ylabel('Elevation [masl, WGS84]') - plt.xlabel('Glacier area [km2]') - plt.minorticks_on() - plt.legend() - # Elevation vs. Mass Balance - plt.subplot(1,3,2) - plt.plot(glac_mb_mwea, glac_elevbins, 'k-', label=str(round(glacwide_mb_mwea, 2)) + ' mwea') - # k refers to the color (k=black, b=blue, g=green, etc.) - # - refers to using a line (-- is a dashed line, o is circle points, etc.) - plt.ylabel('Elevation [masl, WGS84]') - plt.xlabel('Mass balance [mwea]') - plt.xlim(-3, 3) - plt.xticks(np.arange(-3, 3 + 1, 1)) - plt.axvline(x=0, color='k') - plt.fill_betweenx(glac_elevbins, glac_mb_mwea, 0, where=glac_mb_mwea<0, color='r', alpha=0.5) - plt.fill_betweenx(glac_elevbins, glac_mb_mwea, 0, where=glac_mb_mwea>0, color='b', alpha=0.5) - plt.legend(loc=1) - plt.minorticks_on() - plt.gca().axes.get_yaxis().set_visible(False) - # Elevation vs. Debris Area, Pond Area, Thickness - plt.subplot(1,3,3) - plt.plot(glac_debrisperc, glac_elevbins, label='Debris area') - plt.plot(glac_pondperc, glac_elevbins, label='Pond area') - plt.plot(glac_debristhick_cm, glac_elevbins, 'k-', label='Thickness') - plt.ylabel('Elevation [masl, WGS84]') - plt.xlabel('Debris thickness [cm], Area [%]') - plt.minorticks_on() - plt.legend() - plt.gca().axes.get_yaxis().set_visible(False) - if option_savefigs == 1: - plt.savefig(individual_fp + '/mb_fig' + ds[glac][1] + '_mb_aed.png', bbox_inches='tight') - plt.show() - - # Elevation change vs. Elevation - plt.figure(figsize=(10,3)) - plt.subplots_adjust(wspace=0.4, hspace=0.4) - # Normalized curves using range of dh/dt - plt.subplot(1,3,1) - plt.plot(glac_elevs, glac_dhdt_med, label=ds[glac][1]) - plt.gca().invert_xaxis() - plt.xlabel('Elevation [m]') - plt.ylabel('dh/dt [m/a]') - plt.title('dhdt vs elevation') - plt.minorticks_on() - plt.legend() - # Normalized curves using dhdt max (according to Huss) - plt.subplot(1,3,2) - plt.plot(glac_elevnorm, glac_dhdt_norm_huss, label=ds[glac][1]) - plt.xlabel('Normalized elev range') - plt.ylabel('Normalized dh/dt [ma]') - plt.title('huss normalization') - if glac_dhdt_med.min() < 0: - plt.gca().invert_yaxis() - plt.minorticks_on() - plt.legend() - # Normalized curves shifting all values to be negative - plt.subplot(1,3,3) - plt.plot(glac_elevnorm, glac_dhdt_norm_shifted, label=ds[glac][1]) - plt.ylim(1,0) - plt.xlabel('Normalized elev range') - plt.title('shifted normalization') - plt.minorticks_on() - plt.legend() - if option_savefigs == 1: - plt.savefig(individual_fp + 'Single_Plots' + ds[glac][1] + '_normcurves.png', bbox_inches='tight') - plt.show() - -if option_plot_eachglacier == 1: - plot_eachglacier(ds, option_merged_dataset=option_use_mergedata) - -#%% Plot multiple glaciers on the same plot -def plot_multipleglaciers_single_threshold(ds, option_merged_dataset=0, parameter='Area', threshold_n=0): - # Set position of dataset to plot in list based on using merged or unmerged data - # [2 = 10m, 6 = merged] - if option_merged_dataset == 0: - ds_position = 2 #refer to binnedcsv - elif option_merged_dataset == 1: - ds_position = 6 #refers to the ds of merged elev bin data - - #plot empty figure - plt.figure(figsize=(10,6)) - plt.subplots_adjust(wspace=0.4, hspace=0.6) - - #set counters to keep track of total number of glac > and < threshold - count_lt = 0 - count_gt = 0 - norm_list_gt = [] - norm_list_lt = [] - - # Parameter values -# parameter_values = np.array([ds[i][3][parameter] for i in range(len(ds))]) - - #loop through each glacier, in order of ascending parameter, accessing binnedcsv values - for glac in range(len(ds)): - glac_rgi = ds[glac][3] -# glac_elevbins = ds[glac][ds_position]['bin_center_elev_m'] -# glac_area_t1 = ds[glac][ds_position]['z1_bin_area_valid_km2'] -# glac_area_t2 = ds[glac][ds_position]['z2_bin_area_valid_km2'] -# glac_area_t1_perc = ds[glac][ds_position]['z1_bin_area_perc'] -# glac_bin_count_t1 = ds[glac][ds_position]['z1_bin_count_valid'] -# glac_mb_mwea = ds[glac][ds_position][mb_cn] -# glac_debristhick_cm = ds[glac][ds_position]['debris_thick_med_m'] * 100 -# glac_debrisperc = ds[glac][ds_position]['perc_debris'] -# glac_pondperc = ds[glac][ds_position]['perc_pond'] - glac_elevnorm = ds[glac][ds_position]['elev_norm'] - glac_dhdt_norm_huss = ds[glac][ds_position]['dhdt_norm_huss'] -# glac_dhdt_norm_shifted = ds[glac][ds_position]['dhdt_norm_shifted'] - glac_dhdt_med = ds[glac][ds_position]['dhdt_bin_med_ma'] -# glac_dhdt_mean = ds[glac][ds_position]['dhdt_bin_mean_ma'] -# glac_dhdt_std = ds[glac][ds_position]['dhdt_bin_std_ma'] - glac_elevs = ds[glac][ds_position]['bin_center_elev_m'] -# glacwide_mb_mwea = (glac_area_t1 * glac_mb_mwea).sum() / glac_area_t1.sum() - glac_name = ds[glac][1].split('-')[1] - - # Subset parameters based on column name and threshold - if glac_rgi[parameter] < threshold_n: - count_lt += 1 - # Make list of array containing elev_norm and dhdt_norm_huss - norm_list_lt.append(np.array([glac_elevnorm.values, - glac_dhdt_norm_huss.values]).transpose()) - - # dhdt (raw) vs. elevation (raw) - plt.subplot(2,2,1) - plt.plot(glac_elevs, glac_dhdt_med, label=glac_name) - if count_lt == 1: - plt.gca().invert_xaxis() - plt.xlabel('Elevation (m)') - plt.ylabel('dh/dt [m/a]') - plt.title('Raw dh/dt\n' + parameter + '<' + str(threshold_n)) - plt.minorticks_on() - - # Huss Norm dhdt vs. Norm Elev - plt.subplot(2,2,2) - plt.rcParams.update({'font.size': 12}) - plt.plot(glac_elevnorm, glac_dhdt_norm_huss, label=glac_name, alpha=glacier_plots_transparency) - plt.xlabel('Normalized Elevation Range') - plt.ylabel('Normalized dh/dt') - if count_lt == 1: - plt.gca().invert_yaxis() - plt.title('Huss Normalization (' + str(count_lt) + ' Glaciers)\n' + parameter + '<' + str(threshold_n)) - plt.minorticks_on() - - if option_show_legend == 1: - plt.legend(bbox_to_anchor=(1.2, 1), loc=2, borderaxespad=0.) - - # Subset parameters based on column name and threshold - elif glac_rgi[parameter] >= threshold_n: - count_gt += 1 - # Make list of array containing elev_norm and dhdt_norm_huss - norm_list_gt.append(np.array([glac_elevnorm.values, - glac_dhdt_norm_huss.values]).transpose()) - - # dhdt vs. elevation - plt.subplot(2,2,3) - plt.plot(glac_elevs, glac_dhdt_med, label=glac_name) - if count_gt == 1: - plt.gca().invert_xaxis() - plt.xlabel('Elevation (m)') - plt.ylabel('dh/dt [m/a]') - plt.title('Raw dh/dt\n' + parameter + '>' + str(threshold_n)) - plt.minorticks_on() - - # Normalized curves using dhdt max (according to Huss) - plt.subplot(2,2,4) - plt.plot(glac_elevnorm, glac_dhdt_norm_huss, label=glac_name, alpha=glacier_plots_transparency) - plt.xlabel('Normalized Elevation Range') - plt.ylabel('Normalized dh/dt') - if count_gt == 1: - plt.gca().invert_yaxis() - plt.title('Huss Normalization (' + str(count_gt) +' Glaciers)\n' + parameter + '>' + str(threshold_n)) - plt.minorticks_on() - - #display legend, if defined as such in "Input Data" section - if option_show_legend == 1: - plt.legend(bbox_to_anchor=(1.2, 1), loc=3, borderaxespad=0.) - - print(count_gt, 'Glaciers above threshold for', parameter) - print(count_lt, 'Glaciers below threshold for', parameter) - - # Put mean and plus/minus 1 standard deviation on normalized plots - norm_lt_stats = pd.DataFrame() - norm_gt_stats = pd.DataFrame() - - if count_lt > 1: - norm_lt_stats = normalized_stats(norm_list_lt) - # Less than threshold plots - plt.subplot(2,2,2) - plt.plot(norm_lt_stats.norm_elev, norm_lt_stats.norm_dhdt_mean, color='black', linewidth=2) - plt.plot(norm_lt_stats.norm_elev, norm_lt_stats.norm_dhdt_68high, '--', color='black', linewidth=1.5) - plt.plot(norm_lt_stats.norm_elev, norm_lt_stats.norm_dhdt_68low, '--', color='black', linewidth=1.5) - if count_gt > 1: - norm_gt_stats = normalized_stats(norm_list_gt) - # Greater than threshold plots - plt.subplot(2,2,4) - plt.plot(norm_gt_stats.norm_elev, norm_gt_stats.norm_dhdt_mean, color='black', linewidth=2) - plt.plot(norm_gt_stats.norm_elev, norm_gt_stats.norm_dhdt_68high, '--', color='black', linewidth=1.5) - plt.plot(norm_gt_stats.norm_elev, norm_gt_stats.norm_dhdt_68low, '--', color='black', linewidth=1.5) - - # Add title to subplot - plot_fn = 'R' + str(rgi_regionO1) +'_' + parameter + '_' + str(threshold_n) - plt.suptitle(plot_fn) - # Save and show figure - if option_savefigs == 1: - multiglacier_fp = fig_fp + 'multiple_glaciers/' - if not os.path.exists(multiglacier_fp): - os.makedirs(multiglacier_fp) - plt.savefig(multiglacier_fp + plot_fn + '_dhdt_elev_curves.png', bbox_inches='tight') - plt.show() - return norm_gt_stats, norm_lt_stats - -if option_plot_multipleglaciers_single_thresholds == 1: -# norm_gt_stats, norm_lt_stats = plot_multipleglaciers_single_threshold( -# ds, option_merged_dataset=0, parameter='Area', threshold_n=5) - #loop through each parameter, and its respective threshold list - for parameter, thresholds in (region_pars.items()): - #loop through each threshold within the list of thresholds of a prmtr - for threshold_n in thresholds: - #call the fxn - norm_gt_stats, norm_lt_stats = plot_multipleglaciers_single_threshold( - ds, parameter=parameter, threshold_n=threshold_n) - - -#%% Plot multiple glaciers on the same plot -def plot_multipleglaciers_multiplethresholds(ds, parameter='Area', thresholds_raw=[0]): - """ - Plot all glaciers for multiple thresholds - - Parameters - ---------- - ds : list of lists - main dataset containing elevation, dh/dt, glacier rgi table and other data for each glacier - parameter : str - parameter name (needs to match parameter name in glacier rgi table) - thresholds_raw : list of integers - threshold values; they are considered "raw" because the function automatically includes a greater than of the - last threshold, so [5, 10] will look at 3 thresholds: "< 5", "5 - 10", and "> 10" - - Returns - ------- - Two plots of the normalized elevation dh/dt curves. - 1. Normalized elevation vs normalized dh/dt with mean and standard deviation included with each threshold having - a separate subplot - 2. Mean normalized elevation vs. normalized dh/dt for each threshold on a single plot - """ - # Set position of dataset to plot in list based on using merged or unmerged data - ds_position = 2 #refer to binnedcsv - - # Sort list according to parameter - ds_sorted = copy.deepcopy(ds) - for i in ds_sorted: - i.append(i[3][parameter]) - ds_sorted.sort(key=lambda x: x[4]) - - # Add maximum threshold to threshold such that don't need a greater than statement - max_list = max(ds_sorted, key=lambda x: x[4]) - max_threshold = max_list[4] + 1 - thresholds=copy.deepcopy(thresholds_raw) - thresholds.append(max_threshold) - - # Count number of glaciers per threshold and record list of values for each threshold's plot - count_glac_per_threshold = [] - normlist_glac_per_threshold = [] - for n, threshold in enumerate(thresholds): - count_glac = 0 - normlist_glac = [] - - for glac in range(len(ds_sorted)): - glac_rgi = ds_sorted[glac][3] - glac_elevnorm = ds_sorted[glac][ds_position]['elev_norm'] - glac_dhdt_norm_huss = ds_sorted[glac][ds_position]['dhdt_norm_huss'] -# glac_dhdt_med = ds_sorted[glac][ds_position]['dhdt_bin_med_ma'] -# glac_elevs = ds_sorted[glac][ds_position]['bin_center_elev_m'] -# glac_name = ds_sorted[glac][1].split('-')[1] - - if n == 0: - if glac_rgi[parameter] < threshold: - count_glac += 1 - # Make list of array containing elev_norm and dhdt_norm_huss - normlist_glac.append(np.array([glac_elevnorm.values, - glac_dhdt_norm_huss.values]).transpose()) - else: - if thresholds[n-1] < glac_rgi[parameter] < threshold: - count_glac += 1 - # Make list of array containing elev_norm and dhdt_norm_huss - normlist_glac.append(np.array([glac_elevnorm.values, - glac_dhdt_norm_huss.values]).transpose()) - # Record glaciers per threshold - count_glac_per_threshold.append(count_glac) - normlist_glac_per_threshold.append(normlist_glac) - - # ===== PLOT ===== - # Plot the normalized curves - fig_width = 5 - fig, ax = plt.subplots(len(thresholds), 1, squeeze=False, figsize=(fig_width,int(3*len(thresholds))), - gridspec_kw = {'wspace':0.2, 'hspace':0.5}) - - normlist_stats_all = [] - for n, threshold in enumerate(thresholds): - - # Extract values to plot - normlist = normlist_glac_per_threshold[n] - - for glac in range(len(normlist)): - normlist_glac = normlist[glac] - - # Normalized elevation vs. normalized dh/dt - ax[n,0].plot(normlist_glac[:,0], normlist_glac[:,1], linewidth=1, alpha=glacier_plots_transparency, - label=None) - ax[n,0].set_ylim(max(normlist_glac[:,0]), min(normlist_glac[:,0])) - ax[n,0].set_xlim(0,1) - ax[n,0].set_ylabel('Normalized Elevation [-]', size=12) - ax[n,0].set_xlabel('Normalized dh/dt [-]', size=12) - ax[n,0].yaxis.set_major_locator(plt.MultipleLocator(0.2)) - ax[n,0].yaxis.set_minor_locator(plt.MultipleLocator(0.1)) - ax[n,0].xaxis.set_major_locator(plt.MultipleLocator(0.2)) - ax[n,0].xaxis.set_minor_locator(plt.MultipleLocator(0.1)) - - if threshold == thresholds[0]: - ax[n,0].set_title((parameter + '<' + str(threshold) + ' (' + str(len(normlist)) + ' Glaciers)'), - size=12) - elif threshold != thresholds[-1]: - ax[n,0].set_title((str(thresholds[n-1]) + '<' + parameter + '<' + str(threshold) + ' (' + - str(len(normlist)) + ' Glaciers)'), size=12) - else: - ax[n,0].set_title((parameter + '>' + str(thresholds[n-1]) + ' (' + str(len(normlist)) + ' Glaciers)'), - size=12) - - # Add statistics to plot - normlist_stats = normalized_stats(normlist) - ax[n,0].plot(normlist_stats.norm_elev, normlist_stats.norm_dhdt_mean, color='black', linewidth=2) - ax[n,0].plot(normlist_stats.norm_elev, normlist_stats.norm_dhdt_68high, '--', color='black', linewidth=1.5) - ax[n,0].plot(normlist_stats.norm_elev, normlist_stats.norm_dhdt_68low, '--', color='black', linewidth=1.5) - # Record stats to plot on separate graph - normlist_stats_all.append(normlist_stats) - - # Save figure - fig.set_size_inches(fig_width, int(len(thresholds)*3)) - threshold_str_list = [str(i) for i in thresholds] - threshold_str_list[-1] = 'max' - threshold_str = '-'.join(threshold_str_list) - fig.savefig(fig_fp + ('normcurves' + parameter + '_' + threshold_str + '.png'), bbox_inches='tight', dpi=300) - - # ===== PLOT ALL ON ONE ===== - fig_width_all = 4 - fig_height_all = 3 - fig, ax = plt.subplots(1, 1, squeeze=False, figsize=(fig_width_all,fig_height_all), - gridspec_kw = {'wspace':0.2, 'hspace':0.5}) - for n, normlist_stats in enumerate(normlist_stats_all): - # Threshold label - threshold = thresholds[n] - num_glac = count_glac_per_threshold[n] - if threshold == thresholds[0]: - threshold_label = '< ' + str(threshold) + ' (' + str(num_glac) + ')' - elif threshold != thresholds[-1]: - threshold_label = str(thresholds[n-1]) + '-' + str(threshold) + ' (' + str(num_glac) + ')' - else: - threshold_label = '> ' + str(thresholds[n-1]) + ' (' + str(num_glac) + ')' - - # Plot mean of each - ax[0,0].plot(normlist_stats.norm_elev, normlist_stats.norm_dhdt_mean, linewidth=2, label=threshold_label) - ax[0,0].set_ylim(max(normlist_glac[:,0]), min(normlist_glac[:,0])) - ax[0,0].set_xlim(0,1) - ax[0,0].set_ylabel('Normalized Elevation [-]', size=12) - ax[0,0].set_xlabel('Normalized dh/dt [-]', size=12) - ax[0,0].yaxis.set_major_locator(plt.MultipleLocator(0.2)) - ax[0,0].yaxis.set_minor_locator(plt.MultipleLocator(0.1)) - ax[0,0].xaxis.set_major_locator(plt.MultipleLocator(0.2)) - ax[0,0].xaxis.set_minor_locator(plt.MultipleLocator(0.1)) - ax[0,0].legend(loc='lower left') - - # Save figure - fig.savefig(fig_fp + ('normcurves' + parameter + '_' + threshold_str + '_MEANS.png'), bbox_inches='tight', dpi=300) - - -if option_plot_multipleglaciers_multiplethresholds == 1: - plot_multipleglaciers_multiplethresholds(ds, parameter='Area', thresholds_raw=[5,10]) - - - -#%% -##%%PLOT Multiple Glaciers, with threshold bins for the parameter -#def plot_multipleglaciers_binned_parameter(glacier_list, option_merged_dataset, parameter='Area', threshold_n=0): -# # Set position of dataset to plot in list based on using merged or unmerged data -# # [2 = 10m, 6 = merged] -# if option_merged_dataset == 0: -# ds_position = 2 #refer to binnedcsv -# elif option_merged_dataset == 1: -# ds_position = 6 #refers to the ds of merged elev bin data -# -# #plot empty figure -# plt.figure(figsize=(10,6)) -# plt.subplots_adjust(wspace=0.4, hspace=0.6) -# -# #set counters to keep track of total number of glac > and < threshold -# count_current = 0 -# norm_list_thresholdbin = [] -# -# #sort main_glac_rgi by parameter, in ascending order -# main_glac_rgi.sort_values(by=[parameter], inplace = True) -# prmtr_sorted_glacier_list = list(main_glac_rgi.index.values) #list of desired order to loop through ds -# #loop through each glacier, in order of ascending parameter, accessing binnedcsv values -# for glac in prmtr_sorted_glacier_list: -# glac_rgi = ds[glac][3] #accessing the glacier's main_glac_rgi row -# glac_elevbins = ds[glac][ds_position]['bin_center_elev_m'] -# glac_area_t1 = ds[glac][ds_position]['z1_bin_area_valid_km2'] -# glac_area_t2 = ds[glac][ds_position]['z2_bin_area_valid_km2'] -# glac_area_t1_perc = ds[glac][ds_position]['z1_bin_area_perc'] -# glac_bin_count_t1 = ds[glac][ds_position]['z1_bin_count_valid'] -# glac_mb_mwea = ds[glac][ds_position][mb_cn] -# glac_debristhick_cm = ds[glac][ds_position]['debris_thick_med_m'] * 100 -# glac_debrisperc = ds[glac][ds_position]['perc_debris'] -# glac_pondperc = ds[glac][ds_position]['perc_pond'] -# glac_elevnorm = ds[glac][ds_position]['elev_norm'] -# glac_dhdt_norm_huss = ds[glac][ds_position]['dhdt_norm_huss'] -## glac_dhdt_norm_range = ds[glac][ds_position]['dhdt_norm_range'] -# glac_dhdt_norm_shifted = ds[glac][ds_position]['dhdt_norm_shifted'] -# glac_dhdt_med = ds[glac][ds_position]['dhdt_bin_med_ma'] -# glac_dhdt_mean = ds[glac][ds_position]['dhdt_bin_mean_ma'] -# glac_dhdt_std = ds[glac][ds_position]['dhdt_bin_std_ma'] -# glac_elevs = ds[glac][ds_position]['bin_center_elev_m'] -# glacwide_mb_mwea = (glac_area_t1 * glac_mb_mwea).sum() / glac_area_t1.sum() -# t1 = 2000 -# t2 = 2015 -# glac_name = ds[glac][1].split('-')[1] -## -# -# # Subset parameters based on column name and threshold -# if glac_rgi[parameter] >= threshold_n and glac_rgi[parameter] < thresholds[next_threshold]: -# print(glac_name, ' is between ', threshold_n, ' and ', thresholds[next_threshold]) -# count_current += 1 -# # Make list of array containing elev_norm and dhdt_norm_huss -# norm_list_thresholdbin.append(np.array([glac_elevnorm.values, glac_dhdt_norm_huss.values]).transpose()) -# -# # dhdt (raw) vs. elevation (raw) -# plt.subplot(2,2,1) -# plt.plot(glac_elevs, glac_dhdt_med, label=glac_name) -# if count_current == 1: -# plt.gca().invert_xaxis() -# plt.xlabel('Elevation (m)') -# plt.ylabel('dh/dt [m/a]') -# plt.title('Raw dh/dt') -# plt.minorticks_on() -# -# # Huss Norm dhdt vs. Norm Elev -# plt.subplot(2,2,2) -# plt.plot(glac_elevnorm, glac_dhdt_norm_huss, label=glac_name, alpha=0.3) -# plt.xlabel('Normalized Elevation Range') -# plt.ylabel('Normalized dh/dt') -# if count_current == 1: -# plt.gca().invert_yaxis() -# plt.title('Huss Normalization') -# plt.minorticks_on() -# -# if option_show_legend == 1: -# plt.legend(bbox_to_anchor=(1.2, 1), loc=2, borderaxespad=0.) -# -# print(count_current, 'glaciers total' ) -# -# # Put mean and plus/minus 1 standard deviation on normalized plots -# norm_thresholdbin_stats = pd.DataFrame() -# if count_current > 1: -# norm_thresholdbin_stats = normalized_stats(norm_list_thresholdbin) -# # Less than threshold plots -# plt.subplot(2,2,2) -# plt.plot(norm_thresholdbin_stats.norm_elev, norm_thresholdbin_stats.dhdt_mean, color='black', linewidth=2) -# plt.plot(norm_thresholdbin_stats.norm_elev, norm_thresholdbin_stats.dhdt_68high, '--', color='black', linewidth=1.5) -# plt.plot(norm_thresholdbin_stats.norm_elev, norm_thresholdbin_stats.dhdt_68low, '--', color='black', linewidth=1.5) -# -# # Add title to subplot -# plot_fn = ('reg_' + str(rgi_regionO1) +'_' + parameter +'_(' + str(threshold_n) + -# ',' + str(thresholds[next_threshold]) + ')_' + str(bin_size)) -# plt.suptitle(plot_fn + '\n '+ str(count_current) + ' glaciers') -# # Save and show figure -# if option_savefigs == 1: -# plt.savefig(input.output_filepath + 'figures/Multi_Glac_Plots_Binned_Parameter/' + plot_fn + '_dhdt_elev_curves.png', bbox_inches='tight') -# plt.show() -# return norm_thresholdbin_stats -# -##%%PLOT Multiple Glaciers, divided into 6 bins, each with equal num of glaciers -## NOTE - This section is not used. Sorting in this way does NOT appear to be -## as effective of a way to bin or analyze the data for our purposes. -#def plot_multipleglaciers_equal_subdivisions(glacier_list, option_merged_dataset, parameter='Area', threshold_n=0): -# # Set position of dataset to plot in list based on using merged or unmerged data -# # [2 = 10m, 6 = merged] -# if option_merged_dataset == 0: -# ds_position = 2 #refer to binnedcsv -# elif option_merged_dataset == 1: -# ds_position = 6 #refers to the ds of merged elev bin data -# -# #plot empty figure -# plt.figure(figsize=(10,6)) -# plt.subplots_adjust(wspace=0.4, hspace=0.6) -# -# #set counters to keep track of total number of glac > and < threshold -# count_current = 0 -# norm_list_thresholdbin = [] -# -# #sort main_glac_rgi by parameter, in ascending order -# main_glac_rgi.sort_values(by=[parameter], inplace = True) -# prmtr_sorted_glacier_list = list(main_glac_rgi.index.values) #list of desired order to loop through ds -# #loop through each glacier, in order of ascending parameter, accessing binnedcsv values -# sample_size = len(main_glac_rgi//6) -# for glac in prmtr_sorted_glacier_list: -# glac_rgi = ds[glac][3] -# glac_elevbins = ds[glac][ds_position]['bin_center_elev_m'] -# glac_area_t1 = ds[glac][ds_position]['z1_bin_area_valid_km2'] -# glac_area_t2 = ds[glac][ds_position]['z2_bin_area_valid_km2'] -# glac_area_t1_perc = ds[glac][ds_position]['z1_bin_area_perc'] -# glac_bin_count_t1 = ds[glac][ds_position]['z1_bin_count_valid'] -# glac_mb_mwea = ds[glac][ds_position][mb_cn] -# glac_debristhick_cm = ds[glac][ds_position]['debris_thick_med_m'] * 100 -# glac_debrisperc = ds[glac][ds_position]['perc_debris'] -# glac_pondperc = ds[glac][ds_position]['perc_pond'] -# glac_elevnorm = ds[glac][ds_position]['elev_norm'] -# glac_dhdt_norm_huss = ds[glac][ds_position]['dhdt_norm_huss'] -## glac_dhdt_norm_range = ds[glac][ds_position]['dhdt_norm_range'] -# glac_dhdt_norm_shifted = ds[glac][ds_position]['dhdt_norm_shifted'] -# glac_dhdt_med = ds[glac][ds_position]['dhdt_bin_med_ma'] -# glac_dhdt_mean = ds[glac][ds_position]['dhdt_bin_mean_ma'] -# glac_dhdt_std = ds[glac][ds_position]['dhdt_bin_std_ma'] -# glac_elevs = ds[glac][ds_position]['bin_center_elev_m'] -# glacwide_mb_mwea = (glac_area_t1 * glac_mb_mwea).sum() / glac_area_t1.sum() -# t1 = 2000 -# t2 = 2015 -# glac_name = ds[glac][1].split('-')[1] -# glac_rgi[parameter].sort() -# -# # Subset parameters based on column name and threshold -# if glac_rgi[parameter] >= threshold_n and glac_rgi[parameter] < thresholds[next_threshold]: -# print(glac_name, ' is between ', threshold_n, ' and ', thresholds[next_threshold]) -# count_current += 1 -# # Make list of array containing elev_norm and dhdt_norm_huss -# norm_list_thresholdbin.append(np.array([glac_elevnorm.values, glac_dhdt_norm_huss.values]).transpose()) -# -# # dhdt (raw) vs. elevation (raw) -# plt.subplot(2,2,1) -# plt.plot(glac_elevs, glac_dhdt_med, label=glac_name) -# if count_current == 1: -# plt.gca().invert_xaxis() -# plt.xlabel('Elevation (m)') -# plt.ylabel('dh/dt [m/a]') -# plt.title('Raw dh/dt') -# plt.minorticks_on() -# -# # Huss Norm dhdt vs. Norm Elev -# plt.subplot(2,2,2) -# plt.plot(glac_elevnorm, glac_dhdt_norm_huss, label=glac_name, alpha=0.3) -# plt.xlabel('Normalized Elevation Range') -# plt.ylabel('Normalized dh/dt') -# if count_current == 1: -# plt.gca().invert_yaxis() -# plt.title('Huss Normalization') -# plt.minorticks_on() -# -# if option_show_legend == 1: -# plt.legend(bbox_to_anchor=(1.2, 1), loc=2, borderaxespad=0.) -# -# # Put mean and plus/minus 1 standard deviation on normalized plots -# norm_thresholdbin_stats = pd.DataFrame() -# if count_current > 1: -# norm_thresholdbin_stats = normalized_stats(norm_list_thresholdbin) -# # Less than threshold plots -# plt.subplot(2,2,2) -# plt.plot(norm_thresholdbin_stats.norm_elev, norm_thresholdbin_stats.dhdt_mean, color='black', linewidth=2) -# plt.plot(norm_thresholdbin_stats.norm_elev, norm_thresholdbin_stats.dhdt_68high, '--', color='black', linewidth=1.5) -# plt.plot(norm_thresholdbin_stats.norm_elev, norm_thresholdbin_stats.dhdt_68low, '--', color='black', linewidth=1.5) -# -# # Add title to subplot -# plot_fn = ('reg_' + str(rgi_regionO1) +'_' + parameter +'_(' + str(threshold_n) + -# ',' + str(thresholds[next_threshold]) + ')_' + str(bin_size)) -# plt.suptitle(plot_fn + '\n '+ str(count_current) + ' glaciers') -# # Save and show figure -# if option_savefigs == 1: -# plt.savefig(input.output_filepath + 'figures/Multi_Glac_Plots_Binned_Parameter/' + plot_fn + '_dhdt_elev_curves.png', bbox_inches='tight') -# plt.show() -# return norm_thresholdbin_stats - - -#%% Call Functions (based on user-defined options from section 1) -# Index of glaciers to loop through -#glacier_list = list(range(0,len(norm_list))) - - -#if option_plot_multipleglaciers_binned_parameter == 1: -# #loop through each threshold, and run the multipleglacier plot fxn -# for parameter, thresholds in (region_pars.items()): -# next_threshold = 1 -# for threshold_n in thresholds: -# norm_thresholdbin_stats = (plot_multipleglaciers_binned_parameter( -# glacier_list, option_merged_dataset=1,parameter=parameter, -# threshold_n=threshold_n)) -# if next_threshold < (len(thresholds) - 1): -# next_threshold += 1 -# -##if option_plot_multipleglaciers_equal_subdivisions == 1: -# -##%% PLOTS USED TO DETERMINE THRESHOLDS FOR DISCARDING POOR DATA -# #these plots inform the section '%Main Dataset', which removes poor data -## Normalized Elevation vs. Normalized Ice Thickness Change -#glacier_list = list(range(0,len(norm_list))) -#plt.figure(figsize=(10,6)) -#plt.subplots_adjust(wspace=0.4, hspace=0.6) -# -#if option_merged_dataset == 1: -# list_pos = 6 -#else: -# list_pos = 2 -# -#if option_plots_threshold == 1: -# for glac in glacier_list: -# glac_elevbins = ds[glac][list_pos]['bin_center_elev_m'] -# glac_area_t1 = ds[glac][list_pos]['z1_bin_area_valid_km2'] -# glac_area_t2 = ds[glac][list_pos]['z2_bin_area_valid_km2'] -# glac_area_t1_perc = ds[glac][list_pos]['z1_bin_area_perc'] -# glac_bin_count_t1 = ds[glac][list_pos]['z1_bin_count_valid'] -# glac_mb_mwea = ds[glac][list_pos][mb_cn] -# glac_debristhick_cm = ds[glac][list_pos]['debris_thick_med_m'] * 100 -# glac_debrisperc = ds[glac][list_pos]['perc_debris'] -# glac_pondperc = ds[glac][list_pos]['perc_pond'] -# glac_elevnorm = ds[glac][list_pos]['elev_norm'] -# glac_dhdt_norm_huss = ds[glac][list_pos]['dhdt_norm_huss'] -## glac_dhdt_norm_range = ds[glac][list_pos]['dhdt_norm_range'] -# glac_dhdt_norm_shifted = ds[glac][list_pos]['dhdt_norm_shifted'] -# glac_dhdt_med = ds[glac][list_pos]['dhdt_bin_med_ma'] -# glac_dhdt_mean = ds[glac][list_pos]['dhdt_bin_mean_ma'] -# glac_dhdt_std = ds[glac][list_pos]['dhdt_bin_std_ma'] -# glac_elevs = ds[glac][list_pos]['bin_center_elev_m'] -# glacwide_mb_mwea = (glac_area_t1 * glac_mb_mwea).sum() / glac_area_t1.sum() -# t1 = 2000 -# t2 = 2015 -# glac_name = ds[glac][1].split('-')[1] -# -# # ====== Relationship between valid area, mean dhdt and std dhdt ===== -# plt.subplot(2,3,1) -# plt.plot(glac_area_t1, glac_dhdt_mean, 'o', mfc='none') -# plt.xlim(0, 3) -# plt.xlabel('valid area t1 [km2]') -# plt.ylabel('mean dhdt [ma]') -# -# plt.subplot(2,3,2) -# plt.plot(glac_area_t1, glac_dhdt_std, 'o', mfc='none') -# plt.xlim(0,3) -# plt.xlabel('valid area t1 [km2]') -# plt.ylabel('std dhdt [ma]') -# -# plt.subplot(2,3,3) -# plt.plot(glac_area_t1, glac_area_t2, 'o', mfc='none') -# plt.xlabel('valid area t1 [km2]') -# plt.ylabel('valid area t2 [km2]') -# -# plt.subplot(2,3,4) -# plt.plot(glac_area_t1, glac_dhdt_med, 'o', mfc='none') -# plt.xlabel('valid area t1 [km2]') -# plt.ylabel('median dhdt [ma]') -# -# plt.subplot(2,3,5) -# plt.plot(glac_area_t1_perc, glac_dhdt_std, 'o', mfc='none') -# plt.xlim(0,3) -# plt.xlabel('perc total area') -# plt.ylabel('std dhdt [ma]') -# -# plt.subplot(2,3,6) -# plt.plot(glac_dhdt_mean, glac_dhdt_std, 'o', mfc='none') -# plt.xlim() -# plt.xlabel('mean dhdt [ma]') -# plt.ylabel('std dhdt [ma]') -# -# if option_show_legend == 1: -# plt.legend() -# plot_fn = 'discard_eval_' + glac_name -# -# if option_savefigs == 1: -# plt.savefig(input.output_filepath + 'figures/discard_threshold_plots/' + plot_fn + '.png', bbox_inches='tight') -# -# plt.show() - - - - - - -# =============================================== OLD CODE/TEXT ======================================================= -#%% TIPS -# - columns in a dataframe can be accessed using df['column_name'] or -# df.column_name -# - .iloc uses column 'positions' to index into a dataframe -# (ex. ds_all.iloc[0,0] = 13.00175) -# while .loc uses column 'names' to index into a dataframe -# (ex. ds_all.loc[0, 'reg_glacno'] = 13.00175) -# - When indexing into lists it is best to use list comprehension. -# List comprehension is essentially an efficient -# for loop for lists and is best read backwards. For example: -# A = [binnedcsv_files_all[x] for x in ds.index.values] -# means that for every value (x) in ds.index.values, select -# binnedcsv_files_all[x] and add it to the list. -# - lists also have the ability to store many objects of different forms. -# For example it can store individual values,strings, numpy arrays, -# pandas series/dataframes, etc. Therefore, depending on what you are -# trying to achieve, you may want to use a combination of different -# indexing methods (ex. list comprehension to access a pandas dataframe, -# followed by pandas indexing to access an element within the dataframe). -# - Accessing list of lists: first index is going to access which sublist -# you're looking at, while second index is -# going to access that element of the list. For example, -# ds[0] access the first glacier and ds[0][0] accesses the first element -# of the first glacier. in this manner, ds[1][0] accesses the first -# element of the second glacier(sublist), ds[1][1] accesses the second -# element of the second glacier (sublist), etc. - -#%% Runnings this File - Tips from Kitrea -# Before running, make sure that the directory paths are accurate for the user's -# computer folders (search_binnedcsv_fn = ....) and (df_glacnames_al[reg_glacno'] = ...) -# For each region or combination of regions, this is the suggested flow of how -# to logically run through the code: -# 1. User defines input region -# 2. run option_plot_histogram = 1 and option_plot_eachglacier = 1 -# (keep all run options turned off to 0) -# 3. based on the histograms, user defines logical range and step size for -# setting thresholds of each possible parameter -# define these as variables, within "input data" section. -# Remember, that the list excludes last value so put one extra step -# 4. Now, set option_plot_multipleglaciers_single_threshold = 1. -# Plug in which parameter you'd like to examine, -# by redefining 'parameter = ...' in the Input Data section. Or, run all -# parameters in one run with option_run_specific_pars = 0. -# If you would like to save your figures, make sure to define an output path. -# 5. Run! -# 6. Now all your png files are stored, and ready to access. -# Note- to change the size of the plots (in order to optimize for presentations, etc) -# change font size and plot size within the code itself. - -#%% OLD MERGED BINS CODE - removed because David Shean now merges the bins to 50 m - # ===== MERGED BINS ================================================================== - # NOTE: Bins are now 50 m (11/15/2018) -# #Merge the bins (continuing within for-loop) -# bin_start = (binnedcsv['bin_center_elev_m'].min() -# - binnedcsv['bin_center_elev_m'].min() / bin_size % 1 * bin_size) -# bin_end = (int(binnedcsv['bin_center_elev_m'].max() / bin_size) -# * bin_size + bin_size / 2) -# # do plus/minus bin_size from the center to get the values to merge, -# # determining the middle value of each elevation bin -# merged_bin_center_elev_m = (np.arange(bin_start + bin_size / 2, bin_end -# + bin_size / 2, bin_size)) -# -# merged_cols = binnedcsv.columns.values #new df with same columns as binnedcsv -# #df filled with nans, with as many rows as merged bins, and as many columns as -# # in merged_cols (aka all the binnedcsv columns) -# ds_merged_bins = (pd.DataFrame(np.full([merged_bin_center_elev_m.shape[0], -# len(merged_cols)], np.nan), -# columns=merged_cols)) -# ds_merged_bins['bin_center_elev_m'] = merged_bin_center_elev_m -# -# #loop through each merged elevation bin (note, this is all still within -# #the greater for-loop through binnedcsv files) -# for nbin in range(merged_bin_center_elev_m.shape[0]): -# bin_center_elev = merged_bin_center_elev_m[nbin] -# #find idx in binnedcsv with elev that will fit into the current -# #merge-bin-size interval. (binnedcsv.bin_center_elev_m refers to the -# # specific glacier's list of all 10m interval bins. bin_center_elev -# # refers to currently looped large merge-bin-size middle. so first -# bin_idx = binnedcsv.loc[((binnedcsv.bin_center_elev_m > bin_center_elev - bin_size/2) & -# (binnedcsv.bin_center_elev_m <= bin_center_elev + bin_size/2))].index.values -# #for each column, store values at the given indexes that fit into merged bin -# bin_counts = binnedcsv.loc[bin_idx, 'z1_bin_count_valid'].values #how many pixels present in that elevation bin -# bin_dhdt_med = binnedcsv.loc[bin_idx, 'dhdt_bin_med_ma'].astype(float).values -# bin_dhdt_mean = binnedcsv.loc[bin_idx, 'dhdt_bin_mean_ma'].astype(float).values -# bin_mb_med_mwea = binnedcsv.loc[bin_idx, 'mb_bin_med_mwea'].astype(float).values -# bin_mb_mean_mwea = binnedcsv.loc[bin_idx, 'mb_bin_mean_mwea'].astype(float).values -# bin_debris_med_m = binnedcsv.loc[bin_idx, 'debris_thick_med_m'].values -# bin_debris_perc = binnedcsv.loc[bin_idx, 'perc_debris'].values -# bin_pond_perc = binnedcsv.loc[bin_idx, 'perc_pond'].values -# bin_clean_perc = binnedcsv.loc[bin_idx, 'perc_clean'].astype(float).values -# # for z1 and z2 raw measures, sum all of the values within each merged -# # bin together, add to df -# ds_merged_bins.loc[nbin, 'z1_bin_count_valid'] = np.nansum(bin_counts) -# ds_merged_bins.loc[nbin, 'z1_bin_area_valid_km2'] = ( -# np.nansum(binnedcsv.loc[bin_idx, 'z1_bin_area_valid_km2'].values)) -# ds_merged_bins.loc[nbin, 'z1_bin_area_perc'] = ( -# np.nansum(binnedcsv.loc[bin_idx, 'z1_bin_area_perc'].values)) -# ds_merged_bins.loc[nbin, 'z2_bin_count_valid'] = ( -# np.nansum(binnedcsv.loc[bin_idx, 'z2_bin_count_valid'].values)) -# ds_merged_bins.loc[nbin, 'z2_bin_area_valid_km2'] = ( -# np.nansum(binnedcsv.loc[bin_idx, 'z2_bin_area_valid_km2'].values)) -# ds_merged_bins.loc[nbin, 'z2_bin_area_perc'] = ( -# np.nansum(binnedcsv.loc[bin_idx, 'z2_bin_area_perc'].values)) -# #as long as there are valid bins of data, find bin_count-weighted -# # average for all other measures, and store into df. This df contains all the -# #merged bin data. -# if np.nansum(bin_counts) > 0: -# ds_merged_bins.loc[nbin, 'dhdt_bin_med_ma'] = ( -# np.nansum(bin_counts * bin_dhdt_med) / np.nansum(bin_counts)) -# ds_merged_bins.loc[nbin, 'dhdt_bin_mean_ma'] = ( -# np.nansum(bin_counts * bin_dhdt_mean) / np.nansum(bin_counts)) -# ds_merged_bins.loc[nbin, 'mb_bin_med_mwea'] = ( -# np.nansum(bin_counts * bin_mb_med_mwea) / np.nansum(bin_counts)) -# ds_merged_bins.loc[nbin, 'mb_bin_mean_mwea'] = ( -# np.nansum(bin_counts * bin_mb_mean_mwea) / np.nansum(bin_counts)) -# ds_merged_bins.loc[nbin, 'debris_thick_med_m'] = ( -# np.nansum(bin_counts * bin_debris_med_m) / np.nansum(bin_counts)) -# ds_merged_bins.loc[nbin, 'perc_debris'] = ( -# np.nansum(bin_counts * bin_debris_perc) / np.nansum(bin_counts)) -# ds_merged_bins.loc[nbin, 'perc_pond'] = ( -# np.nansum(bin_counts * bin_pond_perc) / np.nansum(bin_counts)) -# ds_merged_bins.loc[nbin, 'perc_clean'] = ( -# np.nansum(bin_counts * bin_clean_perc) / np.nansum(bin_counts)) -# -# # Normalized elevation (MERGED) -# # (max elevation - bin elevation) / (max_elevation - min_elevation) -# ds_merged_bins['elev_norm'] = ((merged_bin_center_elev_m[-1] -# - merged_bin_center_elev_m) -# / (merged_bin_center_elev_m[-1] -# - merged_bin_center_elev_m[0])) -# # Normalized ice thickness change [ma] (MERGED) -# # dhdt / dhdt_max (note the max is found by using np.nanmin of a (-) val) -# merged_glac_dhdt = ds_merged_bins[dhdt_cn].values -# # Remove positive elevations and replace with zero (MERGED) -# merged_glac_dhdt[merged_glac_dhdt >= 0] = 0 -# ds_merged_bins['dhdt_norm_huss'] = merged_glac_dhdt / np.nanmin(merged_glac_dhdt) -## ds_merged_bins['dhdt_norm_range'] = merged_glac_dhdt / (np.nanmin(merged_glac_dhdt) - np.nanmax(merged_glac_dhdt)) -# # Shifted normalized ice thickness change such that everything is negative (MERGED) -# ds_merged_bins['dhdt_norm_shifted'] = ((merged_glac_dhdt -# - np.nanmax(merged_glac_dhdt)) -# / np.nanmin(merged_glac_dhdt - -# np.nanmax(merged_glac_dhdt))) -# -## if all(np.isnan(ds_merged_bins['dhdt_norm_huss'].values)) == False: -# #note: this is now done later in this section - -#%% Kitrea's try for removing bad values -#remove glaciers where the max dhdt is not in the accumulation zone. -#if the max surface lowering (where norm > 0.75) is within the accumulation zone -#(where norm_elev <0.5) then discard that glacier. -#for glac in range(len(ds)): -# glacname = ds[glac][1] -# print('evaluating', glacname, glac) -# high_dhdt_norm = (ds[glac][6]['dhdt_norm_huss'] > 0.75) -# high_dhdt_norm_idx = np.where((ds[glac][6]['dhdt_norm_huss'] > 0.75)) -# accumulation_elev_norm = (ds[glac][6]['elev_norm'] < 0.5) -# accumulation_elev_norm_idx = np.where(ds[1][6]['elev_norm'] < 0.5) -# for idx in high_dhdt_norm_idx: -# if idx in accumulation_elev_norm_idx[0]: -# print('high dhdt found in accumulation zone of ', glacname) -# removable_idx = removable_idx.union(main_glac_rgi[main_glac_rgi['RGIId'] == glacname].index) -# else: -# print('high accumulation found, but not in accumulation zone of ', glacname) - -##do the actual removal, based on the index you just created^ -#if (option_remove_outliers == 1 or option_remove_all_pos_dhdt == 1 or -# option_remove_surge_glac == 1): -# #Drop all indices corresponding to unwanted glaciers, and reset index. -# main_glac_rgi.drop(removable_idx, inplace = True) -# main_glac_rgi.reset_index(drop = True, inplace = True) -# #change Int64Index to a list of ints, in reverse order -# reversed_list_removable_idx = sorted(list(removable_idx), reverse = True) -# #looping through indices, delete them from ds and norm_list -# # note, no reset needed bcs index is automatically reset after removal for lists) -# for removing_idx_int in reversed_list_removable_idx: -# glac_name = ds[removing_idx_int][1] #pull glacname from ds -# print('Removing glacier ', glac_name) -# del ds[removing_idx_int] -# del norm_list[removing_idx_int] -# print(len(reversed_list_removable_idx), ' total glaciers removed from ' + -# 'main_glac_rgi, ds, and norm_list') diff --git a/analyze_mcmc.py b/analyze_mcmc.py index 361db0ac..c0e3fff0 100644 --- a/analyze_mcmc.py +++ b/analyze_mcmc.py @@ -37,13 +37,14 @@ # Paper figures option_observation_vs_calibration = 0 option_papermcmc_prior_vs_posterior = 0 -option_papermcmc_modelparameter_map_and_postvprior = 1 +option_papermcmc_modelparameter_map_and_postvprior = 0 option_metrics_histogram_all = 0 -option_metrics_vs_chainlength = 0 +option_metrics_vs_chainlength = 1 option_correlation_scatter = 0 option_regional_priors = 0 option_glacier_mb_vs_params = 0 +option_papermcmc_solutionspace = 0 option_papermcmc_hh2015_map = 0 # Others @@ -274,11 +275,6 @@ def load_glacierdata_byglacno(glac_no, option_loadhyps_climate=1, option_loadcal # Air temperature [degC], Precipitation [m], Elevation [masl], Lapse rate [K m-1] gcm_temp_region, gcm_dates = gcm.importGCMvarnearestneighbor_xarray( gcm.temp_fn, gcm.temp_vn, main_glac_rgi_region, dates_table_nospinup) - if input.option_ablation != 2 or input.ref_gcm_name not in ['ERA5']: - gcm_tempstd_region = np.zeros(gcm_temp_region.shape) - elif input.ref_gcm_name in ['ERA5']: - gcm_tempstd_region, gcm_dates = gcm.importGCMvarnearestneighbor_xarray( - gcm.tempstd_fn, gcm.tempstd_vn, main_glac_rgi_region, dates_table_nospinup) gcm_prec_region, gcm_dates = gcm.importGCMvarnearestneighbor_xarray( gcm.prec_fn, gcm.prec_vn, main_glac_rgi_region, dates_table_nospinup) gcm_elev_region = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn, main_glac_rgi_region) @@ -298,7 +294,6 @@ def load_glacierdata_byglacno(glac_no, option_loadhyps_climate=1, option_loadcal main_glac_icethickness = main_glac_icethickness_region main_glac_width = main_glac_width_region gcm_temp = gcm_temp_region - gcm_tempstd = gcm_tempstd_region gcm_prec = gcm_prec_region gcm_elev = gcm_elev_region gcm_lr = gcm_lr_region @@ -332,7 +327,6 @@ def load_glacierdata_byglacno(glac_no, option_loadhyps_climate=1, option_loadcal main_glac_width = main_glac_width.append(main_glac_width_region) gcm_temp = np.vstack([gcm_temp, gcm_temp_region]) - gcm_tempstd = np.vstack([gcm_tempstd, gcm_tempstd_region]) gcm_prec = np.vstack([gcm_prec, gcm_prec_region]) gcm_elev = np.concatenate([gcm_elev, gcm_elev_region]) gcm_lr = np.vstack([gcm_lr, gcm_lr_region]) @@ -354,7 +348,7 @@ def load_glacierdata_byglacno(glac_no, option_loadhyps_climate=1, option_loadcal return main_glac_rgi, cal_data else: return (main_glac_rgi, main_glac_hyps, main_glac_icethickness, main_glac_width, - gcm_temp, gcm_tempstd, gcm_prec, gcm_elev, gcm_lr, + gcm_temp, gcm_prec, gcm_elev, gcm_lr, cal_data, dates_table) @@ -692,9 +686,9 @@ def plot_hist(df, cn, bins, xlabel=None, ylabel=None, fig_fn='hist.png', fig_fp= def plot_mb_vs_parameters(tempchange_iters, precfactor_iters, ddfsnow_iters, modelparameters, glacier_rgi_table, - glacier_area_t0, icethickness_t0, width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, - glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, - observed_massbal, observed_error, tempchange_boundhigh, tempchange_boundlow, + glacier_area_t0, icethickness_t0, width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, observed_massbal, + observed_error, tempchange_boundhigh, tempchange_boundlow, tempchange_opt_init=None, mb_max_acc=None, mb_max_loss=None, option_areaconstant=0, option_plotsteps=1, fig_fp=input.output_filepath): """ @@ -729,10 +723,9 @@ def plot_mb_vs_parameters(tempchange_iters, precfactor_iters, ddfsnow_iters, mod glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( - massbalance.runmassbalance(modelparameters[0:8], glacier_rgi_table, glacier_area_t0, - icethickness_t0, width_t0, elev_bins, glacier_gcm_temp, - glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, - glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + massbalance.runmassbalance(modelparameters[0:8], glacier_rgi_table, glacier_area_t0, icethickness_t0, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, option_areaconstant=option_areaconstant)) # Compute glacier volume change for every time step and use this to compute mass balance @@ -806,8 +799,7 @@ def plot_mb_vs_parameters(tempchange_iters, precfactor_iters, ddfsnow_iters, mod else: ylim_lower = np.floor(mb_max_loss) ax.set_ylim(int(ylim_lower),np.ceil(mb_vs_parameters['massbal'].max())) - print('\nMANUALLY SET YLIM\n') - ax.set_ylim(-2,2) +# ax.set_ylim(-2,2) # Labels # ax.set_title('Mass balance versus Parameters ' + glacier_str) @@ -815,36 +807,22 @@ def plot_mb_vs_parameters(tempchange_iters, precfactor_iters, ddfsnow_iters, mod ax.set_ylabel('Mass Balance (m w.e. $\mathregular{a^{-1}}$)', fontsize=12) # Add legend - x_min = mb_vs_parameters.loc[:,'tempbias'].min() - y_min = mb_vs_parameters.loc[:,'massbal'].min() - leg_lines = [] leg_names = [] - for precfactor in precfactor_iters: + x_min = mb_vs_parameters.loc[:,'tempbias'].min() + y_min = mb_vs_parameters.loc[:,'massbal'].min() + for precfactor in reversed(precfactor_iters): line = Line2D([x_min,y_min],[x_min,y_min], linestyle=prec_linedict[precfactor], color='gray') leg_lines.append(line) - leg_names.append(str(precfactor)) - leg_pf = ax.legend(leg_lines, leg_names, loc='upper right', title='$\mathit{k_{p}}$', frameon=False, - labelspacing=0.25, bbox_to_anchor=(0.99, 0.99)) - leg_lines = [] - leg_names = [] + leg_names.append('$\mathregular{k_{p}}$ ' + str(precfactor)) + for ddfsnow in ddfsnow_iters: line = Line2D([x_min,y_min],[x_min,y_min], linestyle='-', color=ddfsnow_colordict[ddfsnow]) leg_lines.append(line) - leg_names.append(str(np.round(ddfsnow*10**3,1))) - leg_ddf = ax.legend(leg_lines, leg_names, loc='upper left', title='$\mathit{f_{snow}}$', frameon=False, - labelspacing=0.25, bbox_to_anchor=(0.63, 0.99)) - ax.add_artist(leg_pf) - -# for precfactor in reversed(precfactor_iters): -# line = Line2D([x_min,y_min],[x_min,y_min], linestyle=prec_linedict[precfactor], color='gray') -# leg_lines.append(line) -# leg_names.append('$\mathregular{k_{p}}$ ' + str(precfactor)) -# for ddfsnow in ddfsnow_iters: -# line = Line2D([x_min,y_min],[x_min,y_min], linestyle='-', color=ddfsnow_colordict[ddfsnow]) -# leg_lines.append(line) -# leg_names.append('$\mathregular{f_{snow}}$ ' + str(np.round(ddfsnow*10**3,1))) + leg_names.append('$\mathregular{f_{snow}}$ ' + str(np.round(ddfsnow*10**3,1))) + + ax.legend(leg_lines, leg_names, loc='upper right', frameon=False, labelspacing=0.25) fig.savefig(fig_fp + glacier_str + '_mb_vs_parameters_areachg.eps', bbox_inches='tight', dpi=300) #%% @@ -935,7 +913,7 @@ def plot_spatialmap_mbdif(vns, grouping, modelparams_all, xlabel, ylabel, figure cbar_ax = fig.add_axes([0.92, 0.5, 0.02, 0.35]) cbar = fig.colorbar(sm, cax=cbar_ax) cbar.set_ticks(list(np.arange(colorbar_dict['dif_masschange'][0], colorbar_dict['dif_masschange'][1] + 0.01, 0.1))) - fig.text(1.04, 0.67, '$\mathit{B_{mod}} - \mathit{B_{obs}}$ (m w.e. $\mathregular{a^{-1}}$)', va='center', + fig.text(1.04, 0.67, '$\mathregular{B_{mod} - B_{obs}}$ (m w.e. $\mathregular{a^{-1}}$)', va='center', rotation='vertical', size=12) # Add contour lines and/or rgi outlines if option_contour_lines == 1: @@ -1030,8 +1008,7 @@ def plot_spatialmap_mbdif(vns, grouping, modelparams_all, xlabel, ylabel, figure a.set_facecolor('none') ax2.set_xlim([0,200]) ax2.set_ylim([-3.8,2.5]) -# ax2.set_ylabel('z-score ($\\frac{B_{mod} - B_{obs}}{B_{std}}$)', size=12) - ax2.set_ylabel('z-score (-)', size=12) + ax2.set_ylabel('z-score ($\\frac{B_{mod} - B_{obs}}{B_{std}}$)', size=12) ax2.set_xlabel('Area ($\mathregular{km^{2}}$)', size=12) # Inset axis over main axis ax_inset = plt.axes([.37, 0.16, .51, .12]) @@ -1045,7 +1022,7 @@ def plot_spatialmap_mbdif(vns, grouping, modelparams_all, xlabel, ylabel, figure cbar_ax = fig.add_axes([0.92, 0.13, 0.02, 0.29]) cbar = fig.colorbar(sm, cax=cbar_ax) cbar.set_ticks(list(np.arange(colorbar_dict['massbal'][0], colorbar_dict['massbal'][1] + 0.01, 0.5))) - fig.text(1.04, 0.28, '$\mathit{B_{obs}}$ $\mathregular{(m w.e. a^{-1})}$', va='center', + fig.text(1.04, 0.28, '$\mathregular{B_{obs}}$ $\mathregular{(m w.e. a^{-1})}$', va='center', rotation='vertical', size=12) # cbar = plt.colorbar(sm, ax=ax2, fraction=0.04, pad=0.01) @@ -1225,7 +1202,7 @@ def observation_vs_calibration(regions, netcdf_fp, chainlength=chainlength, burn glac_no = sorted(glac_no) (main_glac_rgi, main_glac_hyps, main_glac_icethickness, main_glac_width, - gcm_temp, gcm_tempstd, gcm_prec, gcm_elev, gcm_lr, cal_data, dates_table) = load_glacierdata_byglacno(glac_no) + gcm_temp, gcm_prec, gcm_elev, gcm_lr, cal_data, dates_table) = load_glacierdata_byglacno(glac_no) posterior_cns = ['glacno', 'mb_mean', 'mb_std', 'pf_mean', 'pf_std', 'tc_mean', 'tc_std', 'ddfsnow_mean', 'ddfsnow_std'] @@ -1335,32 +1312,6 @@ def observation_vs_calibration(regions, netcdf_fp, chainlength=chainlength, burn '\nModeled MB [Gt/yr]:', np.round(mb_compare.mod_Gta.sum(),2), '(+/-', np.round(mb_compare.mod_Gta_std.sum(),2),')' ) - - #%% - mb_compare['abs_zscore'] = np.absolute(mb_compare['dif_zscore']) - mb_compare_gt1zscore = mb_compare.loc[mb_compare.abs_zscore > 1] - mb_compare_gt5km2 = mb_compare.loc[mb_compare.Area_km2 > 5] - mb_compare_gt5km2_gt1zscore = mb_compare_gt5km2.loc[mb_compare_gt5km2.abs_zscore > 1] - print('Glaciers > 5km2', mb_compare_gt5km2.shape[0], 'w zscore > 1', mb_compare_gt5km2_gt1zscore.shape[0]) - mb_compare_lt5km2 = mb_compare.loc[mb_compare.Area_km2 <= 5] - mb_compare_lt5km2_gt1zscore = mb_compare_lt5km2.loc[mb_compare_lt5km2.abs_zscore > 1] - print('Glaciers > 5km2', mb_compare_lt5km2.shape[0], 'w zscore > 1', mb_compare_lt5km2_gt1zscore.shape[0], - '(' + str(np.round(mb_compare_lt5km2_gt1zscore.shape[0] / mb_compare_lt5km2.shape[0] *100, 0)) + '%)',) - print('Number of glaciers with zscore > 1:', mb_compare_gt1zscore.shape[0], '(' + - str(np.round(mb_compare_gt1zscore.shape[0] / mb_compare.shape[0] *100, 0)) + '%)', '(' + - str(np.round(mb_compare_gt1zscore['Area_km2'].sum() / mb_compare['Area_km2'].sum() *100, 2)) + '% of area)') -# #%% -# # Calculate number of glaciers where observed mass balance < maximum mass loss -# glac_no = [x.split('-')[1] for x in mb_compare['RGIId'].values] -# (main_glac_rgi, main_glac_hyps, main_glac_icethickness, main_glac_width, -# gcm_temp, gcm_tempstd, gcm_prec, gcm_elev, gcm_lr, cal_data, dates_table) = load_glacierdata_byglacno(glac_no) -# #%% -# mb_max_loss = -1 * (main_glac_hyps * main_glac_icethickness).sum(1) / main_glac_hyps.sum(1) / 18 -# mb_compare['mb_max_loss'] = mb_max_loss -# mb_compare['cal_mwea'] = cal_data['mb_mwe'] / 18 -# mb_compare['mb_obs_vs_maxloss'] = mb_compare['cal_mwea'] - mb_compare['mb_max_loss'] -# mb_compare_lt_maxloss = mb_compare.loc[mb_compare['mb_obs_vs_maxloss'] < 0] -# #%% # ===== HISTOGRAM: mass balance difference ====== dif_bins = [-1.5, -1, -0.5, -0.2, -0.1, -0.05,-0.02, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 1.5] @@ -1509,8 +1460,7 @@ def __call__(self, value, clip=None): a.set_facecolor('none') ax.set_xlim([0,200]) ax.set_ylim([-3.99,2.5]) -# ax.set_ylabel('z-score ($\\frac{B_{mod} - B_{obs}}{B_{std}}$)', size=12) - ax.set_ylabel('z-score (-)', size=12) + ax.set_ylabel('z-score ($\\frac{B_{mod} - B_{obs}}{B_{std}}$)', size=12) ax.set_xlabel('Area ($\mathregular{km^{2}}$)', size=12) # Inset axis over main axis ax_inset = plt.axes([.35, .19, .48, .35]) @@ -1523,15 +1473,13 @@ def __call__(self, value, clip=None): sm._A = [] cbar = plt.colorbar(sm, ax=ax, fraction=0.04, pad=0.01) cbar.set_ticks(list(np.arange(colorbar_dict['massbal'][0], colorbar_dict['massbal'][1] + 0.01, 0.25))) - fig.text(1.01, 0.5, '$\mathit{B_{obs}}$ $\mathregular{(m w.e. a^{-1})}$', va='center', + fig.text(1.01, 0.5, '$\mathregular{B_{obs}}$ $\mathregular{(m w.e. a^{-1})}$', va='center', rotation='vertical', size=12) # Save figure fig.set_size_inches(6,4) fig_fn = 'dif_vs_area_wMB_scatterplot_zscore.png' fig.savefig(fig_fp + fig_fn, bbox_inches='tight', dpi=300) - return mb_compare - #%% if __name__ == '__main__': @@ -1792,7 +1740,7 @@ def __call__(self, value, clip=None): figwidth=6.5 figheight=8 fig, ax = plt.subplots(len(variables), len(metrics), squeeze=False, sharex=False, sharey=False, - figsize=(figwidth,figheight), gridspec_kw = {'wspace':0.6, 'hspace':0.2}) + figsize=(figwidth,figheight), gridspec_kw = {'wspace':0.4, 'hspace':0.25}) # Metric statistics df_cns = ['iters', 'mean', 'std', 'median', 'lowbnd', 'highbnd'] @@ -1852,38 +1800,19 @@ def __call__(self, value, clip=None): # niceties ax[nvar,nmetric].xaxis.set_major_locator(MultipleLocator(10)) ax[nvar,nmetric].xaxis.set_minor_locator(MultipleLocator(2)) - ax[nvar,nmetric].set_xlim(0,iterations[-1]/10**3) -# if nvar == 0: -# ax[nvar,nmetric].set_title(metric_title_dict[metric], fontsize=10) -# elif nvar == len(variables) - 1: -# ax[nvar,nmetric].set_xlabel('Steps ($10^3$)', fontsize=12) - if nvar == len(variables) - 1: + if nvar == 0: + ax[nvar,nmetric].set_title(metric_title_dict[metric], fontsize=10) + elif nvar == len(variables) - 1: ax[nvar,nmetric].set_xlabel('Steps ($10^3$)', fontsize=12) if metric == 'Gelman-Rubin': -# ax[nvar,nmetric].set_ylabel(vn_title_dict[vn], fontsize=12, labelpad=10) - if vn == 'massbal': - ax[nvar,nmetric].set_ylabel('$\hat{R}_{\mathit{B}}$', fontsize=12) - elif vn == 'precfactor': - ax[nvar,nmetric].set_ylabel('$\hat{R}_{k_{p}}$', fontsize=12) - elif vn == 'tempchange': - ax[nvar,nmetric].set_ylabel('$\hat{R}_{T_{bias}}$', fontsize=12) - elif vn == 'ddfsnow': - ax[nvar,nmetric].set_ylabel('$\hat{R}_{f_{snow}}$', fontsize=12) + ax[nvar,nmetric].set_ylabel(vn_title_dict[vn], fontsize=12, labelpad=10) ax[nvar,nmetric].set_ylim(1,1.12) ax[nvar,nmetric].axhline(y=1.1, color='k', linestyle='--', linewidth=2) ax[nvar,nmetric].yaxis.set_major_locator(MultipleLocator(0.05)) ax[nvar,nmetric].yaxis.set_minor_locator(MultipleLocator(0.01)) elif metric == 'MC Error': - if vn == 'massbal': - ax[nvar,nmetric].set_ylabel('MCE$_{\mathit{B}}$', fontsize=12, labelpad=2) - elif vn == 'precfactor': - ax[nvar,nmetric].set_ylabel('MCE$_{k_{p}}$', fontsize=12, labelpad=2) - elif vn == 'tempchange': - ax[nvar,nmetric].set_ylabel('MCE$_{T_{bias}}$', fontsize=12, labelpad=2) - elif vn == 'ddfsnow': - ax[nvar,nmetric].set_ylabel('MCE$_{f_{snow}}$', fontsize=12, labelpad=2) if option_mcerror_normalize == 1: ax[nvar,nmetric].axhline(y=0.1, color='k', linestyle='--', linewidth=2) ax[nvar,nmetric].set_ylim(0,0.12) @@ -1911,38 +1840,30 @@ def __call__(self, value, clip=None): ax[nvar,nmetric].yaxis.set_major_locator(MultipleLocator(0.05)) ax[nvar,nmetric].yaxis.set_minor_locator(MultipleLocator(0.01)) elif metric == 'Effective N': - if vn == 'massbal': - ax[nvar,nmetric].set_ylabel('n$_{\mathit{B}}$', fontsize=12, labelpad=0) - elif vn == 'precfactor': - ax[nvar,nmetric].set_ylabel('n$_{k_{p}}$', fontsize=12, labelpad=0) - elif vn == 'tempchange': - ax[nvar,nmetric].set_ylabel('n$_{T_{bias}}$', fontsize=12, labelpad=0) - elif vn == 'ddfsnow': - ax[nvar,nmetric].set_ylabel('n$_{f_{snow}}$', fontsize=12, labelpad=0) ax[nvar,nmetric].set_ylim(0,1200) ax[nvar,nmetric].axhline(y=100, color='k', linestyle='--', linewidth=2) ax[nvar,nmetric].yaxis.set_major_locator(MultipleLocator(500)) ax[nvar,nmetric].yaxis.set_minor_locator(MultipleLocator(100)) if option_subplot_labels == 1: - fig.text(0.135, 0.86, 'A', size=12) - fig.text(0.435, 0.86, 'B', size=12) - fig.text(0.725, 0.86, 'C', size=12) - fig.text(0.131, 0.66, 'D', size=12) - fig.text(0.435, 0.66, 'E', size=12) - fig.text(0.725, 0.66, 'F', size=12) - fig.text(0.135, 0.4625, 'G', size=12) - fig.text(0.435, 0.4625, 'H', size=12) - fig.text(0.725, 0.4625, 'I', size=12) - fig.text(0.135, 0.270, 'J', size=12) - fig.text(0.435, 0.270, 'K', size=12) - fig.text(0.725, 0.270, 'L', size=12) + fig.text(0.130, 0.86, 'A', size=12) + fig.text(0.415, 0.86, 'B', size=12) + fig.text(0.700, 0.86, 'C', size=12) + fig.text(0.130, 0.66, 'D', size=12) + fig.text(0.415, 0.66, 'E', size=12) + fig.text(0.700, 0.66, 'F', size=12) + fig.text(0.130, 0.4625, 'G', size=12) + fig.text(0.415, 0.4625, 'H', size=12) + fig.text(0.700, 0.4625, 'I', size=12) + fig.text(0.130, 0.265, 'J', size=12) + fig.text(0.415, 0.265, 'K', size=12) + fig.text(0.700, 0.265, 'L', size=12) # Save figure fig.set_size_inches(figwidth,figheight) if os.path.exists(fig_fp) == False: os.makedirs(fig_fp) - figure_fn = 'chainlength_vs_metrics' + iter_ending.replace('.pkl','') + '.eps' + figure_fn = 'chainlength_vs_metrics' + iter_ending.replace('.pkl','') + '.png' fig.savefig(fig_fp + figure_fn, bbox_inches='tight', dpi=300) @@ -2199,19 +2120,26 @@ def __call__(self, value, clip=None): netcdf_fp = mcmc_output_netcdf_fp_all burn = 1000 mb_compare_fn = 'main_glac_rgi_20190806_wcal_wposteriors_all_' + str(burn) + 'burn.csv' - mb_compare = observation_vs_calibration(regions, netcdf_fp, chainlength=chainlength, burn=burn, - netcdf_fn=mb_compare_fn) + observation_vs_calibration(regions, netcdf_fp, chainlength=chainlength, burn=burn, netcdf_fn=mb_compare_fn) #%% if option_papermcmc_prior_vs_posterior == 1: print('Prior vs posterior showing two example glaciers side-by-side!') glac_no = ['13.26360', '14.08487'] - netcdf_fp = input.output_filepath + 'cal_opt2_spc_20190815_3chain/cal_opt2_3chain_figure/' + netcdf_fp = mcmc_output_netcdf_fp_3chain + netcdf_fp = input.output_filepath + 'cal_opt2_3chain/' burn = 1000 iters=[2000,10000] figure_fn = 'prior_v_posteriors_2glac.eps' + # glac_no = ['15.10755', '15.12457'] + # burn = 1000 + # iters=[10000] + # netcdf_fp = mcmc_output_netcdf_fp_all + # figure_fn = 'prior_v_posteriors_2glac_poorglaciers.eps' + # # note: need to change position and lines of legend below + fig_fp = netcdf_fp + 'figures/' if os.path.exists(fig_fp) == False: os.makedirs(fig_fp) @@ -2222,7 +2150,6 @@ def __call__(self, value, clip=None): # Add regions main_glac_rgi['region'] = main_glac_rgi.RGIId.map(input.reg_dict) - #%% # PRIOR VS POSTERIOR PLOTS fig, ax = plt.subplots(4, 2, squeeze=False, figsize=(6.5, 7), gridspec_kw={'wspace':0.2, 'hspace':0.47}) @@ -2236,7 +2163,7 @@ def __call__(self, value, clip=None): # RGI information glacier_rgi_table = main_glac_rgi.loc[main_glac_rgi.index.values[n], :] # Calibration data - cal_idx = np.where(cal_data['glacno'] == glacier_str)[0] + cal_idx = np.where(cal_data['glacno'] == glacno)[0] glacier_cal_data = (cal_data.iloc[cal_idx,:]).copy() # Select observed mass balance, error, and time data t1 = glacier_cal_data.loc[cal_idx, 't1'].values[0] @@ -2336,7 +2263,7 @@ def __call__(self, value, clip=None): # ax[0,1].legend(title='Steps', loc='upper right', handlelength=1, handletextpad=0.05, borderpad=0.2) leg_lines = [] leg_labels = [] - chain_labels = ['Prior', '2,000', '10,000'] + chain_labels = ['Prior', '1000', '10000'] chain_colors = ['black', '#387ea0', '#fcb200'] # chain_labels = ['Prior', '10000'] # chain_colors = ['black', '#387ea0'] @@ -2348,9 +2275,9 @@ def __call__(self, value, clip=None): leg_lines.append(line) leg_labels.append(chain_labels[n_chain]) fig.legend(leg_lines, leg_labels, loc='upper right', -# bbox_to_anchor=(0.87,0.885), - bbox_to_anchor=(0.88,0.82), - handlelength=1, handletextpad=0.25, borderpad=0.2, labelspacing = 0.2, frameon=True) + bbox_to_anchor=(0.87,0.885), + # bbox_to_anchor=(0.87,0.815), + handlelength=1.5, handletextpad=0.25, borderpad=0.2, frameon=True) # # Legend (Note: hard code the spacing between the two legends) # leg_lines = [] @@ -2402,6 +2329,125 @@ def __call__(self, value, clip=None): # Save figure fig.savefig(fig_fp + figure_fn, bbox_inches='tight', pad_inches=0.02, dpi=300) + + + #%% + if option_papermcmc_solutionspace == 1: + + glac_no = ['13.05086'] + netcdf_fp = input.output_fp_cal + # netcdf_fp = mcmc_output_netcdf_fp_3chain + + # filelist = [] + # for region in regions: + # filelist.extend(glob.glob(netcdf_fp + str(region) + '*.nc')) + # + # glac_no = [] + # reg_no = [] + # for netcdf in filelist: + # glac_str = netcdf.split('/')[-1].split('.nc')[0] + # glac_no.append(glac_str) + # reg_no.append(glac_str.split('.')[0]) + # glac_no = sorted(glac_no) + + (main_glac_rgi, main_glac_hyps, main_glac_icethickness, main_glac_width, + gcm_temp, gcm_prec, gcm_elev, gcm_lr, cal_data, dates_table) = load_glacierdata_byglacno(glac_no) + + # Elevation bins + elev_bins = main_glac_hyps.columns.values.astype(int) + + for n, glac_str_wRGI in enumerate(main_glac_rgi['RGIId'].values): + # Glacier string + glacier_str = glac_str_wRGI.split('-')[1] + # Glacier number + glacno = int(glacier_str.split('.')[1]) + # RGI information + glacier_rgi_table = main_glac_rgi.loc[main_glac_rgi.index.values[n], :] + # Calibration data + cal_idx = np.where(cal_data['glacno'] == glacno)[0] + glacier_cal_data = (cal_data.iloc[cal_idx,:]).copy() + # Select observed mass balance, error, and time data + t1 = glacier_cal_data.loc[cal_idx, 't1'].values[0] + t2 = glacier_cal_data.loc[cal_idx, 't2'].values[0] + t1_idx = int(glacier_cal_data.loc[cal_idx,'t1_idx']) + t2_idx = int(glacier_cal_data.loc[cal_idx,'t2_idx']) + observed_massbal = (glacier_cal_data.loc[cal_idx,'mb_mwe'] / (t2 - t1)).values[0] + observed_error = (glacier_cal_data.loc[cal_idx,'mb_mwe_err'] / (t2 - t1)).values[0] + mb_obs_max = observed_massbal + 3 * observed_error + mb_obs_min = observed_massbal - 3 * observed_error + + # MCMC Analysis + ds = xr.open_dataset(netcdf_fp + glacier_str + '.nc') + df = pd.DataFrame(ds['mp_value'].values[:,:,0], columns=ds.mp.values) + print('MB (obs - mean_model):', np.round(observed_massbal - df.massbal.mean(),3)) + + # Priors + try: + priors = pd.Series(ds.priors, index=ds['dim_0']) + except: + priors = pd.Series(ds.priors, index=ds.prior_cns) + + precfactor_boundlow = priors['pf_bndlow'] + precfactor_boundhigh = priors['pf_bndhigh'] + precfactor_boundmu = priors['pf_mu'] + tempchange_boundlow = priors['tc_bndlow'] + tempchange_boundhigh = priors['tc_bndhigh'] + tempchange_mu = priors['tc_mu'] + tempchange_sigma = priors['tc_std'] + ddfsnow_boundhigh = priors['ddfsnow_bndhigh'] + ddfsnow_boundlow = priors['ddfsnow_bndlow'] + ddfsnow_mu = priors['ddfsnow_mu'] + ddfsnow_sigma = priors['ddfsnow_std'] + mb_max_loss = priors['mb_max_loss'] + mb_max_acc = priors['mb_max_acc'] + try: + tempchange_max_loss = priors['tc_max_loss'] + except: # typo in initial code - issue fixed 03/08/2019 + tempchange_max_loss = priors['tc_maxloss'] + tempchange_max_acc = priors['tc_max_acc'] + precfactor_opt_init = priors['pf_opt_init'] + tempchange_opt_init = priors['tc_opt_init'] + + print('\nParameters:\nPF_low:', np.round(precfactor_boundlow,2), 'PF_high:', + np.round(precfactor_boundhigh,2), '\nTC_low:', np.round(tempchange_boundlow,2), + 'TC_high:', np.round(tempchange_boundhigh,2), + '\nTC_mu:', np.round(tempchange_mu,2), 'TC_sigma:', np.round(tempchange_sigma,2)) + + + # Select subsets of data + glacier_gcm_elev = gcm_elev[n] + glacier_gcm_temp = gcm_temp[n,:] + glacier_gcm_lrgcm = gcm_lr[n,:] + glacier_gcm_lrglac = glacier_gcm_lrgcm.copy() + glacier_gcm_prec = gcm_prec[n,:] + glacier_area_t0 = main_glac_hyps.iloc[n,:].values.astype(float) + icethickness_t0 = main_glac_icethickness.iloc[n,:].values.astype(float) + width_t0 = main_glac_width.iloc[n,:].values.astype(float) + glac_idx_t0 = glacier_area_t0.nonzero()[0] + # Set model parameters + modelparameters = [input.lrgcm, input.lrglac, input.precfactor, input.precgrad, input.ddfsnow, input.ddfice, + input.tempsnow, input.tempchange] + + tc_iter_step = 0.1 + tc_iter_high = np.max([tempchange_max_loss, tempchange_boundhigh]) + tempchange_iters = np.arange(int(tempchange_max_acc), np.ceil(tc_iter_high)+tc_iter_step, tc_iter_step).tolist() + ddfsnow_iters = [0.0026, 0.0041, 0.0056] + precfactor_iters = [int(precfactor_boundlow*10)/10, int((precfactor_boundlow + precfactor_boundhigh)/2*10)/10, + int(precfactor_boundhigh*10)/10] + if 1 not in precfactor_iters: + precfactor_iters.append(int(1)) + precfactor_iters = sorted(precfactor_iters) + + fig_fp = netcdf_fp + 'figures/' + if os.path.exists(fig_fp) == False: + os.makedirs(fig_fp) + + plot_mb_vs_parameters(tempchange_iters, precfactor_iters, ddfsnow_iters, modelparameters, glacier_rgi_table, + glacier_area_t0, icethickness_t0, width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, observed_massbal, + observed_error, tempchange_boundhigh, tempchange_boundlow, tempchange_opt_init, + mb_max_acc, mb_max_loss, tempchange_max_acc, tempchange_max_loss, option_areaconstant=0, + option_plotsteps=1, fig_fp=fig_fp) #%% @@ -2750,15 +2796,12 @@ def __call__(self, value, clip=None): ax[nvar,nest].set_xlabel(vn_label_dict[vn], fontsize=10, labelpad=1) if nvar == 0: ax[nvar,nest].set_title('$\Delta$ ' + estimator, fontsize=12) - if nest == 0: - ax[nvar,nest].set_ylabel('Count (%)', fontsize=12) if nest == 1: -# ax[nvar,nest].set_yticks([]) - ax[nvar,nest].set_yticklabels([]) + ax[nvar,nest].set_yticks([]) print(' ', estimator, '% near 0:', np.round(hist[np.where(bins > 0)[0][0] - 1])) -# fig.text(0.04, 0.5, 'Count (%)', va='center', rotation='vertical', size=12) + fig.text(0.04, 0.5, 'Count (%)', va='center', rotation='vertical', size=12) fig.text(0.135, 0.86, 'A', size=12) fig.text(0.540, 0.86, 'B', size=12) fig.text(0.135, 0.655, 'C', size=12) @@ -2849,8 +2892,6 @@ def __call__(self, value, clip=None): reg_no.append(glac_str.split('.')[0]) glac_no = sorted(glac_no) - print(glac_no) - main_glac_rgi, cal_data = load_glacierdata_byglacno(glac_no, option_loadhyps_climate=0) posterior_cns = ['glacno', 'mb_mod_mwea', 'precfactor', 'tempbias', 'ddfsnow'] @@ -2961,7 +3002,6 @@ def __call__(self, value, clip=None): #%% # Map & Scatterplot of mass balance difference - print(figure_fp) plot_spatialmap_mbdif(vns, grouping, modelparams_all, xlabel, ylabel, figure_fp=figure_fp, fig_fn_prefix='HH2015_', option_group_regions=1) @@ -3522,7 +3562,7 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): #%% PLOT MCMC CHAINS if option_glacier_mcmc_plots == 1: # glac_no = str(input.rgi_regionsO1[0]) + '.' + input.rgi_glac_number[0] - glac_no = '15.03475' + glac_no = '13.45048' netcdf_fp = input.main_directory + '/../Output/cal_opt2_spc_20190806/' # glac_no = '15.03473' # netcdf_fp = input.output_fp_cal @@ -3537,13 +3577,12 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): rgi_glac_number = [glac_no.split('.')[1]] # Glacier RGI data - main_glac_rgi = modelsetup.selectglaciersrgitable(glac_no = [glac_no]) + main_glac_rgi = modelsetup.selectglaciersrgitable(rgi_regionsO1=region, rgi_regionsO2 = 'all', + rgi_glac_number=rgi_glac_number) # Add regions main_glac_rgi['region'] = main_glac_rgi.RGIId.map(input.reg_dict) # Glacier hypsometry [km**2], total area - print(main_glac_rgi) - print(region) - main_glac_hyps = modelsetup.import_Husstable(main_glac_rgi, input.hyps_filepath, + main_glac_hyps = modelsetup.import_Husstable(main_glac_rgi, region, input.hyps_filepath, input.hyps_filedict, input.hyps_colsdrop) # Ice thickness [m], average main_glac_icethickness = modelsetup.import_Husstable(main_glac_rgi, input.thickness_filepath, @@ -3555,8 +3594,7 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): # Elevation bins elev_bins = main_glac_hyps.columns.values.astype(int) # Select dates including future projections - dates_table = modelsetup.datesmodelrun(startyear=input.startyear, endyear=input.endyear, spinupyears=0, - option_wateryear=input.option_wateryear) + dates_table = modelsetup.datesmodelrun(startyear=input.startyear, endyear=input.endyear, spinupyears=0) # ===== LOAD CLIMATE DATA ===== gcm = class_climate.GCM(name=input.ref_gcm_name) @@ -3564,12 +3602,6 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): gcm_temp, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn, gcm.temp_vn, main_glac_rgi, dates_table) gcm_prec, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn, gcm.prec_vn, main_glac_rgi, dates_table) gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn, main_glac_rgi) - # Air temperature standard deviation [K] - if input.option_ablation != 2 or gcm.name not in ['ERA5']: - gcm_tempstd = np.zeros(gcm_temp.shape) - elif gcm.name in ['ERA5']: - gcm_tempstd, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.tempstd_fn, gcm.tempstd_vn, - main_glac_rgi, dates_table) # Lapse rate [K m-1] gcm_lr, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.lr_fn, gcm.lr_vn, main_glac_rgi, dates_table) @@ -3595,7 +3627,7 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): # RGI information glacier_rgi_table = main_glac_rgi.loc[main_glac_rgi.index.values[n], :] # Calibration data - cal_idx = np.where(cal_data['glacno'] == glacier_str)[0] + cal_idx = np.where(cal_data['glacno'] == glacno)[0] glacier_cal_data = (cal_data.iloc[cal_idx,:]).copy() # Select observed mass balance, error, and time data t1 = glacier_cal_data.loc[cal_idx, 't1'].values[0] @@ -3617,7 +3649,6 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): # Select subsets of data glacier_gcm_elev = gcm_elev[n] glacier_gcm_temp = gcm_temp[n,:] - glacier_gcm_tempstd = gcm_tempstd[n,:] glacier_gcm_lrgcm = gcm_lr[n,:] glacier_gcm_lrglac = glacier_gcm_lrgcm.copy() glacier_gcm_prec = gcm_prec[n,:] @@ -3631,9 +3662,9 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): tempchange_boundlow, tempchange_boundhigh, mb_max_loss = ( calibration.retrieve_priors(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, - width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, - glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, - glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2)) + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + t1_idx, t2_idx, t1, t2)) # Regional priors precfactor_gamma_alpha = input.precfactor_gamma_region_dict[glacier_rgi_table.loc['region']][0] @@ -3983,7 +4014,7 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): tempchange_boundlow, tempchange_boundhigh, mb_max_loss = ( calibration.retrieve_priors( modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, - width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, debug=False)) # Iterations to plot @@ -4032,8 +4063,8 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( massbalance.runmassbalance(modelparameters[0:8], glacier_rgi_table, glacier_area_t0, icethickness_t0, width_t0, elev_bins, glacier_gcm_temp, - glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, - glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, + glacier_gcm_lrglac, dates_table, option_areaconstant=option_areaconstant)) # Compute glacier volume change for every time step and use this to compute mass balance @@ -4108,14 +4139,14 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): #%% PLOT MASS BALANCE VS MODEL PARAMETERS if option_glacier_mb_vs_params == 1: - glac_no = ['13.26360'] + glac_no = ['15.10755'] # glac_no = [str(input.rgi_regionsO1[0]) + '.' + input.rgi_glac_number[0]] # netcdf_fp = input.output_fp_cal netcdf_fp = mcmc_output_netcdf_fp_all fig_fp = netcdf_fp + 'figures/' (main_glac_rgi, main_glac_hyps, main_glac_icethickness, main_glac_width, - gcm_temp, gcm_tempstd, gcm_prec, gcm_elev, gcm_lr, cal_data, dates_table) = load_glacierdata_byglacno(glac_no) + gcm_temp, gcm_prec, gcm_elev, gcm_lr, cal_data, dates_table) = load_glacierdata_byglacno(glac_no) main_glac_rgi['region'] = main_glac_rgi.RGIId.map(input.reg_dict) @@ -4131,7 +4162,7 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): # RGI information glacier_rgi_table = main_glac_rgi.loc[main_glac_rgi.index.values[n], :] # Calibration data - cal_idx = np.where(cal_data['glacno'] == glacier_str)[0] + cal_idx = np.where(cal_data['glacno'] == glacno)[0] glacier_cal_data = (cal_data.iloc[cal_idx,:]).copy() # Select observed mass balance, error, and time data t1 = glacier_cal_data.loc[cal_idx, 't1'].values[0] @@ -4151,7 +4182,6 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): # Select subsets of data glacier_gcm_elev = gcm_elev[n] glacier_gcm_temp = gcm_temp[n,:] - glacier_gcm_tempstd = gcm_tempstd[n,:] glacier_gcm_lrgcm = gcm_lr[n,:] glacier_gcm_lrglac = glacier_gcm_lrgcm.copy() glacier_gcm_prec = gcm_prec[n,:] @@ -4167,7 +4197,7 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): tempchange_boundlow, tempchange_boundhigh, mb_max_loss = ( calibration.retrieve_priors( modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, - width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, debug=True)) # Iterations to plot @@ -4181,8 +4211,8 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): tc_iter_step).tolist() # Set manually - print('\n\nTempchange iters set manually for figure generation\n\n') - tempchange_iters = np.arange(-6, 6+tc_iter_step, tc_iter_step).tolist() + # print('\n\nTempchange iters set manually for figure generation\n\n') + # tempchange_iters = np.arange(-6, 6+tc_iter_step, tc_iter_step).tolist() ddfsnow_iters = [0.0026, 0.0041, 0.0056] @@ -4191,10 +4221,9 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): # Plot plot_mb_vs_parameters(tempchange_iters, precfactor_iters, ddfsnow_iters, modelparameters, glacier_rgi_table, - glacier_area_t0, icethickness_t0, width_t0, elev_bins, glacier_gcm_temp, - glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, - glacier_gcm_lrglac, dates_table, observed_massbal, observed_error, - tempchange_boundhigh, tempchange_boundlow, + glacier_area_t0, icethickness_t0, width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, observed_massbal, + observed_error, tempchange_boundhigh, tempchange_boundlow, mb_max_loss=mb_max_loss, option_areaconstant=0, option_plotsteps=0, fig_fp=fig_fp) @@ -4234,7 +4263,7 @@ def partition_era_groups(grouping, vn, main_glac_rgi_all): glac_no = sorted(glac_no) (main_glac_rgi, main_glac_hyps, main_glac_icethickness, main_glac_width, - gcm_temp, gcm_tempstd, gcm_prec, gcm_elev, gcm_lr, cal_data, dates_table) = load_glacierdata_byglacno(glac_no) + gcm_temp, gcm_prec, gcm_elev, gcm_lr, cal_data, dates_table) = load_glacierdata_byglacno(glac_no) df_export = main_glac_rgi[['RGIId', 'O1Region', 'glacno', 'Zmin', 'Zmax', 'Zmed']].copy() df_export['precfactor'] = df_all['precfactor'].values @@ -4331,18 +4360,12 @@ def calc_correlation(df, vn1, vn2): #%% # Plot combinations combinations = ['mb/pf', 'mb/tc', 'mb/ddf', 'pf/tc', 'pf/ddf', 'tc/ddf'] -# combination_dict = {'mb/pf':'$\mathregular{B}$ / $\mathregular{k_{p}}$', -# 'mb/tc':'$\mathregular{B}$ / $\mathregular{T_{bias}}$', -# 'mb/ddf':'$\mathregular{B}$ / $\mathregular{f_{snow}}$', -# 'pf/tc':'$\mathregular{k_{p}}$ / $\mathregular{T_{bias}}$', -# 'pf/ddf':'$\mathregular{k_{p}}$ / $\mathregular{f_{snow}}$', -# 'tc/ddf':'$\mathregular{T_{bias}}$ / $\mathregular{f_{snow}}$'} - combination_dict = {'mb/pf':'R($\mathit{B}$,$\mathit{k_{p}}$)', - 'mb/tc':'R($\mathit{B}$,$\mathit{T_{bias}}$)', - 'mb/ddf':'R($\mathit{B}$,$\mathit{f_{snow}}$)', - 'pf/tc':'R($\mathit{k_{p}}$,$\mathit{T_{bias}}$)', - 'pf/ddf':'R($\mathit{k_{p}}$,$\mathit{f_{snow}}$)', - 'tc/ddf':'R($\mathit{T_{bias}}$,$\mathit{f_{snow}}$)'} + combination_dict = {'mb/pf':'$\mathregular{B}$ / $\mathregular{k_{p}}$', + 'mb/tc':'$\mathregular{B}$ / $\mathregular{T_{bias}}$', + 'mb/ddf':'$\mathregular{B}$ / $\mathregular{f_{snow}}$', + 'pf/tc':'$\mathregular{k_{p}}$ / $\mathregular{T_{bias}}$', + 'pf/ddf':'$\mathregular{k_{p}}$ / $\mathregular{f_{snow}}$', + 'tc/ddf':'$\mathregular{T_{bias}}$ / $\mathregular{f_{snow}}$'} bdict = {} bdict['mb/pf'] = np.arange(-0.2, 1.05, 0.05) - 0.025 @@ -4362,7 +4385,7 @@ def calc_correlation(df, vn1, vn2): nrows = 2 ncols = 3 - fig, ax = plt.subplots(nrows, ncols, squeeze=False, gridspec_kw={'wspace':0.3, 'hspace':0.45}) + fig, ax = plt.subplots(nrows, ncols, squeeze=False, gridspec_kw={'wspace':0.5, 'hspace':0.4}) nrow = 0 ncol = 0 for nvar, combination in enumerate(combinations): @@ -4374,14 +4397,12 @@ def calc_correlation(df, vn1, vn2): ax[nrow,ncol].bar(x=bins_centered, height=hist, width=(bins[1]-bins[0]), align='center', edgecolor='black', color='lightgrey', linewidth=0.2) ax[nrow,ncol].set_ylim(0,18) - ax[nrow,ncol].set_xticks(tdict[combination]) -# ax[nrow,ncol].set_xlabel(combination_dict[combination], size=12) - ax[nrow,ncol].text(0.5, -0.35, combination_dict[combination], size=12, horizontalalignment='center', + ax[nrow,ncol].set_xticks(tdict[combination]) + ax[nrow,ncol].text(0.5, 1.01, combination_dict[combination], size=12, horizontalalignment='center', verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) r_mean = df_all[combination].mean() - ax[nrow,ncol].axvline(r_mean, color='grey', linestyle='--') -# ax[nrow,ncol].text(0.98, 0.98, np.round(r_mean,2), size=12, horizontalalignment='right', -# verticalalignment='top', transform=ax[nrow,ncol].transAxes) + ax[nrow,ncol].text(0.98, 0.98, np.round(r_mean,2), size=12, horizontalalignment='right', + verticalalignment='top', transform=ax[nrow,ncol].transAxes) # Adjust row and column ncol += 1 @@ -4389,10 +4410,8 @@ def calc_correlation(df, vn1, vn2): nrow += 1 ncol = 0 - ax[0,0].set_ylabel('Count (%)', va='center', rotation='vertical', size=12) - ax[1,0].set_ylabel('Count (%)', va='center', rotation='vertical', size=12) -# fig.text(0.04, 0.5, 'Count (%)', va='center', rotation='vertical', size=12) -# fig.text(0.5,0, 'Correlation Coefficient (R)', size=12, horizontalalignment='center') + fig.text(0.04, 0.5, 'Count (%)', va='center', rotation='vertical', size=12) + fig.text(0.5,0, 'Correlation Coefficient (R)', size=12, horizontalalignment='center') if os.path.exists(fig_fp) == False: os.makedirs(fig_fp) diff --git a/analyze_simulation.py b/analyze_simulation.py index aedea75b..03e6e9c9 100644 --- a/analyze_simulation.py +++ b/analyze_simulation.py @@ -1,7 +1,6 @@ """ Analyze MCMC output - chain length, etc. """ # Built-in libraries -from collections import OrderedDict import datetime import glob import os @@ -10,16 +9,13 @@ import cartopy import matplotlib as mpl import matplotlib.pyplot as plt -from matplotlib.pyplot import MaxNLocator from matplotlib.lines import Line2D import matplotlib.patches as mpatches from matplotlib.ticker import MultipleLocator from matplotlib.ticker import EngFormatter -from matplotlib.ticker import StrMethodFormatter from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable import numpy as np import pandas as pd -from scipy.stats import linregress from scipy.ndimage import uniform_filter import scipy #from scipy import stats @@ -41,42 +37,36 @@ import run_calibration as calibration # Script options -option_plot_cmip5_normalizedchange = 0 # updated - 11/6/2019 (includes the runoff figure 5) -option_cmip5_heatmap_w_volchange = 0 # updated - 11/6/2019 +option_plot_cmip5_normalizedchange = 0 +option_cmip5_heatmap_w_volchange = 0 option_cmip5_mb_vs_climate = 0 option_map_gcm_changes = 0 option_region_map_nodata = 0 -option_peakwater_map = 0 # updated - 11/7/2019 -option_temp_and_prec_map = 0 # updated - 11/18/2019 -option_watersheds_colored = 0 # still good 11/6/2019 -option_runoff_monthlychange_and_components = 0 # updated - 11/20/2019 -runoff_erainterim_bywatershed = 0 # updated - better to export to table -option_excess_meltwater_diagram = 0 - -option_startdate = 0 +option_peakwater_map = 0 +option_watersheds_colored = 0 +option_runoff_components = 0 +option_runoff_monthlychange = 0 +runoff_erainterim_bywatershed = 0 option_plot_cmip5_normalizedchange_proposal = 0 option_runoff_components_proposal = 0 -option_glaciermip_table = 0 # updated - 11/12/2019 -option_zemp_compare = 0 # updated - 11/6/2019 -option_gardelle_compare = 0 # updated - 11/6/2019 -option_wgms_compare = 1 # updated - 11/6/2019 +option_glaciermip_table = 0 +option_zemp_compare = 0 +option_gardelle_compare = 0 +option_wgms_compare = 0 option_dehecq_compare = 0 -option_uncertainty_fig = 0 # updated - 11/12/2019 +option_uncertainty_fig = 0 option_nick_snowline = 0 -option_caldata_compare = 0 analyze_multimodel = 0 option_merge_multimodel_datasets = 0 -option_regional_hyps = 0 #%% ===== Input data ===== #netcdf_fp_cmip5 = input.output_sim_fp + 'spc_subset/' -#netcdf_fp_cmip5 = input.output_sim_fp + 'spc_multimodel/' -netcdf_fp_cmip5 = input.output_filepath + 'simulations/spc_20190914/merged/multimodel/' -netcdf_fp_era = input.output_filepath + 'simulations/spc_20190914/merged/ERA-Interim/' +netcdf_fp_cmip5 = input.output_sim_fp + 'spc_multimodel/' +netcdf_fp_era = input.output_sim_fp + '/ERA-Interim/ERA-Interim_1980_2017_wy_areachg_pre2000/' #%% @@ -89,19 +79,20 @@ #gcm_names = ['bcc-csm1-1', 'CESM1-CAM5', 'CCSM4', 'CSIRO-Mk3-6-0', 'GFDL-CM3', # 'GFDL-ESM2G', 'GFDL-ESM2M', 'GISS-E2-R', 'IPSL-CM5A-LR', 'IPSL-CM5A-MR', 'MIROC-ESM', # 'MIROC-ESM-CHEM', 'MIROC5', 'MRI-CGCM3', 'NorESM1-ME'] +#gcm_names = ['bcc-csm1-1', 'CanESM2', 'CESM1-CAM5'] rcps = ['rcp26', 'rcp45', 'rcp60', 'rcp85'] +#rcps = ['rcp26', 'rcp45', 'rcp85'] +#rcps = ['rcp26'] # Grouping #grouping = 'all' -grouping = 'rgi_region' -#grouping = 'watershed' +#grouping = 'rgi_region' +grouping = 'watershed' #grouping = 'kaab' #grouping = 'himap' #grouping = 'degree' - -#subgrouping = 'hexagon' -subgrouping = 'hexagon42' +subgrouping = 'hexagon' degree_size = 0.5 @@ -235,9 +226,6 @@ hex_dict_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/qgis_himat/rgi60_HMA_dict_hexbins.csv' hex_csv = pd.read_csv(hex_dict_fn) hex_dict = dict(zip(hex_csv.RGIId, hex_csv.hexid)) -hex42_dict_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/qgis_himat/rgi60_HMA_dict_hexbins_42km.csv' -hex42_csv = pd.read_csv(hex42_dict_fn) -hex42_dict = dict(zip(hex42_csv.RGIId, hex42_csv.hexid42)) # Shapefiles rgiO1_shp_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/RGI/rgi60/00_rgi60_regions/00_rgi60_O1Regions.shp' @@ -281,26 +269,6 @@ def pickle_data(fn, data): """ with open(fn, 'wb') as f: pickle.dump(data, f) - - -def plot_hist(df, cn, bins, xlabel=None, ylabel=None, fig_fn='hist.png', fig_fp=input.output_filepath): - """ - Plot histogram for any bin size - """ - data = df[cn].values - hist, bin_edges = np.histogram(data,bins) # make the histogram - fig,ax = plt.subplots() - # Plot the histogram heights against integers on the x axis - ax.bar(range(len(hist)),hist,width=1, edgecolor='k') - # Set the ticks to the middle of the bars - ax.set_xticks([0.5+i for i,j in enumerate(hist)]) - # Set the xticklabels to a string that tells us what the bin edges were - ax.set_xticklabels(['{} - {}'.format(bins[i],bins[i+1]) for i,j in enumerate(hist)], rotation=45, ha='right') - ax.set_xlabel(xlabel, fontsize=16) - ax.set_ylabel(ylabel, fontsize=16) - # Save figure - fig.set_size_inches(6,4) - fig.savefig(fig_fp + fig_fn, bbox_inches='tight', dpi=300) def peakwater(runoff, time_values, nyears): @@ -388,9 +356,6 @@ def select_groups(grouping, main_glac_rgi_all): elif grouping == 'hexagon': groups = main_glac_rgi_all.hexid.unique().tolist() group_cn = 'hexid' - elif grouping == 'hexagon42': - groups = main_glac_rgi_all.hexid42.unique().tolist() - group_cn = 'hexid42' else: groups = ['all'] group_cn = 'all_group' @@ -401,27 +366,51 @@ def select_groups(grouping, main_glac_rgi_all): return groups, group_cn -def load_glacier_data(glac_no=None, rgi_regionsO1=None, rgi_regionsO2='all', rgi_glac_number='all', +def load_glacier_data(rgi_regions, load_caldata=0, startyear=2000, endyear=2018, option_wateryear=3): -#def load_glacier_data(rgi_regions, -# load_caldata=0, startyear=2000, endyear=2018, option_wateryear=3): """ Load glacier data (main_glac_rgi, hyps, and ice thickness) """ - # Load glaciers - main_glac_rgi_all = modelsetup.selectglaciersrgitable( - rgi_regionsO1=rgi_regionsO1, rgi_regionsO2 =rgi_regionsO2, rgi_glac_number=rgi_glac_number, - glac_no=glac_no) - - # Glacier hypsometry [km**2], total area - main_glac_hyps_all = modelsetup.import_Husstable(main_glac_rgi_all, input.hyps_filepath, input.hyps_filedict, - input.hyps_colsdrop) - # Ice thickness [m], average - main_glac_icethickness_all = modelsetup.import_Husstable(main_glac_rgi_all, input.thickness_filepath, - input.thickness_filedict, input.thickness_colsdrop) - - # Additional processing - main_glac_hyps_all[main_glac_icethickness_all == 0] = 0 + for rgi_region in rgi_regions: + # Data on all glaciers + main_glac_rgi_region = modelsetup.selectglaciersrgitable(rgi_regionsO1=[rgi_region], rgi_regionsO2 = 'all', + rgi_glac_number='all') + # Glacier hypsometry [km**2] + main_glac_hyps_region = modelsetup.import_Husstable(main_glac_rgi_region, input.hyps_filepath, + input.hyps_filedict, input.hyps_colsdrop) + # Ice thickness [m], average + main_glac_icethickness_region= modelsetup.import_Husstable(main_glac_rgi_region, + input.thickness_filepath, input.thickness_filedict, + input.thickness_colsdrop) + if rgi_region == rgi_regions[0]: + main_glac_rgi_all = main_glac_rgi_region + main_glac_hyps_all = main_glac_hyps_region + main_glac_icethickness_all = main_glac_icethickness_region + else: + main_glac_rgi_all = pd.concat([main_glac_rgi_all, main_glac_rgi_region], sort=False) + main_glac_hyps_all = pd.concat([main_glac_hyps_all, main_glac_hyps_region], sort=False) + main_glac_icethickness_all = pd.concat([main_glac_icethickness_all, main_glac_icethickness_region], + sort=False) + + if load_caldata == 1: + cal_datasets = ['shean'] + dates_table = modelsetup.datesmodelrun(startyear=startyear, endyear=endyear, spinupyears=0, + option_wateryear=option_wateryear) + # Calibration data + cal_data = pd.DataFrame() + for dataset in cal_datasets: + cal_subset = class_mbdata.MBData(name=dataset) + cal_subset_data = cal_subset.retrieve_mb(main_glac_rgi_region, main_glac_hyps_region, dates_table) + cal_data = cal_data.append(cal_subset_data, ignore_index=True) + cal_data = cal_data.sort_values(['glacno', 't1_idx']) + cal_data.reset_index(drop=True, inplace=True) + + if rgi_region == rgi_regions[0]: + cal_data_all = cal_data + else: + cal_data_all = pd.concat([cal_data_all, cal_data], sort=False) + #%% + main_glac_hyps_all = main_glac_hyps_all.fillna(0) main_glac_icethickness_all = main_glac_icethickness_all.fillna(0) @@ -433,7 +422,6 @@ def load_glacier_data(glac_no=None, rgi_regionsO1=None, rgi_regionsO2='all', rgi main_glac_rgi_all['himap'] = main_glac_rgi_all.RGIId.map(himap_dict) # Hexbins main_glac_rgi_all['hexid'] = main_glac_rgi_all.RGIId.map(hex_dict) - main_glac_rgi_all['hexid42'] = main_glac_rgi_all.RGIId.map(hex42_dict) # Degrees main_glac_rgi_all['CenLon_round'] = np.floor(main_glac_rgi_all.CenLon.values/degree_size) * degree_size main_glac_rgi_all['CenLat_round'] = np.floor(main_glac_rgi_all.CenLat.values/degree_size) * degree_size @@ -458,20 +446,6 @@ def load_glacier_data(glac_no=None, rgi_regionsO1=None, rgi_regionsO2='all', rgi # All main_glac_rgi_all['all_group'] = 'all' - if load_caldata == 1: - cal_datasets = ['shean'] - startyear=2000 - dates_table = modelsetup.datesmodelrun(startyear=startyear, endyear=endyear, spinupyears=0, - option_wateryear=option_wateryear) - # Calibration data - cal_data_all = pd.DataFrame() - for dataset in cal_datasets: - cal_subset = class_mbdata.MBData(name=dataset) - cal_subset_data = cal_subset.retrieve_mb(main_glac_rgi_all, main_glac_hyps_all, dates_table) - cal_data_all = cal_data_all.append(cal_subset_data, ignore_index=True) - cal_data_all = cal_data_all.sort_values(['glacno', 't1_idx']) - cal_data_all.reset_index(drop=True, inplace=True) - if load_caldata == 0: return main_glac_rgi_all, main_glac_hyps_all, main_glac_icethickness_all else: @@ -560,8 +534,8 @@ def retrieve_gcm_data(gcm_name, rcp, main_glac_rgi, option_bias_adjustment=input if option_uncertainty_fig == 1: #%% - netcdf_fp_cmip5 = '/Volumes/LaCie/HMA_PyGEM/2019_0914/spc_subset/' - netcdf_fp_multi = input.output_filepath + 'simulations/spc_20190914/merged/multimodel/' + netcdf_fp_cmip5 = input.output_sim_fp + 'spc_subset/' + netcdf_fp_multi = input.output_sim_fp + 'spc_multimodel/' figure_fp = input.output_sim_fp + 'figures/' # gcm_names = ['bcc-csm1-1', 'CanESM2', 'CESM1-CAM5', 'CCSM4', 'CNRM-CM5', 'CSIRO-Mk3-6-0', 'FGOALS-g2', 'GFDL-CM3', # 'GFDL-ESM2G', 'GFDL-ESM2M', 'GISS-E2-R', 'HadGEM2-ES', 'IPSL-CM5A-LR', 'IPSL-CM5A-MR', 'MIROC-ESM', @@ -579,8 +553,11 @@ def retrieve_gcm_data(gcm_name, rcp, main_glac_rgi, option_bias_adjustment=input vn = 'volume_glac_annual' - # Load glaciers - main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(rgi_regionsO1=regions) + # Load glaciers +# main_glac_rgi, main_glac_hyps, main_glac_icethickness, cal_data = ( +# load_glacier_data(regions, load_caldata=1, startyear=2000, endyear=2018, option_wateryear=3)) + + main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(regions) cal_data = pd.read_csv(input.shean_fp + input.shean_fn) print('Check glacier indices are correct') @@ -591,15 +568,14 @@ def retrieve_gcm_data(gcm_name, rcp, main_glac_rgi, option_bias_adjustment=input #%% # SINGLE GCM DATA - region_single = int(rgiid_big.split('-')[1].split('.')[0]) + region_single = int(rgiid_small.split('-')[1].split('.')[0]) ds_single_all, ds_single_std_all = {}, {} for rcp in rcps: ds_single_all[rcp], ds_single_std_all[rcp] = {}, {} for ngcm, gcm_name in enumerate(gcm_names): # Load datasets - ds_fn = ('R' + str(region_single) + '--all--' + gcm_name + '_' + rcp + - '_c2_ba1_100sets_2000_2100--subset.nc') + ds_fn = ('R' + str(region_single) + '_' + gcm_name + '_' + rcp + '_c2_ba1_100sets_2000_2100--subset.nc') ds = xr.open_dataset(netcdf_fp_cmip5 + ds_fn) # Extract time variable @@ -628,9 +604,6 @@ def retrieve_gcm_data(gcm_name, rcp, main_glac_rgi, option_bias_adjustment=input # Load datasets ds_fn = 'R' + str(region) + '_multimodel_' + rcp + '_c2_ba1_100sets_2000_2100.nc' ds = xr.open_dataset(netcdf_fp_multi + ds_fn) - df = pd.DataFrame(ds.glacier_table.values, columns=ds.glac_attrs) - df['RGIId'] = ['RGI60-' + str(int(df.O1Region.values[x])) + '.' + - str(int(df.glacno.values[x])).zfill(5) for x in df.index.values] # Extract time variable time_values_annual = ds.coords['year_plus1'].values @@ -639,21 +612,12 @@ def retrieve_gcm_data(gcm_name, rcp, main_glac_rgi, option_bias_adjustment=input if region == regions[0]: ds_multi[rcp] = ds[vn].values[:,:,0] ds_multi_std[rcp] = ds[vn].values[:,:,1] - df_all = df else: ds_multi[rcp] = np.concatenate((ds_multi[rcp], ds[vn].values[:,:,0]), axis=0) ds_multi_std[rcp] = np.concatenate((ds_multi_std[rcp], ds[vn].values[:,:,1]), axis=0) - df_all = pd.concat([df_all, df], axis=0) ds.close() - # Remove RGIIds from main_glac_rgi that are not in the model runs - rgiid_df = list(df_all.RGIId.values) - rgiid_all = list(main_glac_rgi.RGIId.values) - rgi_idx = [rgiid_all.index(x) for x in rgiid_df] - main_glac_rgi = main_glac_rgi.loc[rgi_idx,:] - main_glac_rgi.reset_index(inplace=True, drop=True) - #%% multimodel_linewidth = 2 alpha=0.2 @@ -683,11 +647,10 @@ def retrieve_gcm_data(gcm_name, rcp, main_glac_rgi, option_bias_adjustment=input vol_low_norm[vol_low_norm < 0] = 0 # Plot ax[0,0].plot(time_values, vol_norm, color=rcp_colordict[rcp], linewidth=1, zorder=4) - if len(rcps) == 4 and rcp in ['rcp26', 'rcp85']: - ax[0,0].plot(time_values, vol_low_norm, color=rcp_colordict[rcp], linewidth=1, linestyle=':', zorder=4) - ax[0,0].plot(time_values, vol_high_norm, color=rcp_colordict[rcp], linewidth=1, linestyle=':', zorder=4) - ax[0,0].fill_between(time_values, vol_low_norm, vol_high_norm, - facecolor=rcp_colordict[rcp], alpha=0.2, zorder=3) + ax[0,0].plot(time_values, vol_low_norm, color=rcp_colordict[rcp], linewidth=1, linestyle=':', zorder=4) + ax[0,0].plot(time_values, vol_high_norm, color=rcp_colordict[rcp], linewidth=1, linestyle=':', zorder=4) + ax[0,0].fill_between(time_values, vol_low_norm, vol_high_norm, + facecolor=rcp_colordict[rcp], alpha=0.2, zorder=3) # Text ax[0,0].text(0.5, 0.99, rgiid_big + '\n(single GCM)', size=10, horizontalalignment='center', verticalalignment='top', transform=ax[0,0].transAxes) @@ -727,13 +690,12 @@ def retrieve_gcm_data(gcm_name, rcp, main_glac_rgi, option_bias_adjustment=input vol_multi_low_norm[vol_multi_low_norm < 0] = 0 # Plot ax[0,1].plot(time_values, vol_multi_norm, color=rcp_colordict[rcp], linewidth=1, zorder=4) - if len(rcps) == 4 and rcp in ['rcp26', 'rcp85']: - ax[0,1].plot(time_values, vol_multi_low_norm, color=rcp_colordict[rcp], linewidth=1, linestyle=':', zorder=4) - ax[0,1].plot(time_values, vol_multi_high_norm, color=rcp_colordict[rcp], linewidth=1, linestyle=':', zorder=4) - ax[0,1].fill_between(time_values, vol_multi_low_norm, vol_multi_high_norm, - facecolor=rcp_colordict[rcp], alpha=0.2, zorder=3) + ax[0,1].plot(time_values, vol_multi_low_norm, color=rcp_colordict[rcp], linewidth=1, linestyle=':', zorder=4) + ax[0,1].plot(time_values, vol_multi_high_norm, color=rcp_colordict[rcp], linewidth=1, linestyle=':', zorder=4) + ax[0,1].fill_between(time_values, vol_multi_low_norm, vol_multi_high_norm, + facecolor=rcp_colordict[rcp], alpha=0.2, zorder=3) # Text - ax[0,1].text(0.5, 0.99, rgiid_big + '\n(multi-GCM mean)', size=10, horizontalalignment='center', + ax[0,1].text(0.5, 0.99, rgiid_big + '\n(multi-model mean)', size=10, horizontalalignment='center', verticalalignment='top', transform=ax[0,1].transAxes) ax[0,1].text(0.05, 0.99, 'B', size=12, horizontalalignment='center', verticalalignment='top', transform=ax[0,1].transAxes, zorder=5) @@ -767,13 +729,12 @@ def retrieve_gcm_data(gcm_name, rcp, main_glac_rgi, option_bias_adjustment=input vol_multi_low_norm[vol_multi_low_norm < 0] = 0 # Plot ax[1,0].plot(time_values, vol_multi_norm, color=rcp_colordict[rcp], linewidth=1, zorder=4) - if len(rcps) == 4 and rcp in ['rcp26', 'rcp85']: - ax[1,0].plot(time_values, vol_multi_low_norm, color=rcp_colordict[rcp], linewidth=1, linestyle=':', zorder=4) - ax[1,0].plot(time_values, vol_multi_high_norm, color=rcp_colordict[rcp], linewidth=1, linestyle=':', zorder=4) - ax[1,0].fill_between(time_values, vol_multi_low_norm, vol_multi_high_norm, - facecolor=rcp_colordict[rcp], alpha=0.2, zorder=3) + ax[1,0].plot(time_values, vol_multi_low_norm, color=rcp_colordict[rcp], linewidth=1, linestyle=':', zorder=4) + ax[1,0].plot(time_values, vol_multi_high_norm, color=rcp_colordict[rcp], linewidth=1, linestyle=':', zorder=4) + ax[1,0].fill_between(time_values, vol_multi_low_norm, vol_multi_high_norm, + facecolor=rcp_colordict[rcp], alpha=0.2, zorder=3) # Text - ax[1,0].text(0.5, 0.99, rgiid_small + '\n(multi-GCM mean)', size=10, horizontalalignment='center', + ax[1,0].text(0.5, 0.99, rgiid_small + '\n(multi-model mean)', size=10, horizontalalignment='center', verticalalignment='top', transform=ax[1,0].transAxes) ax[1,0].text(0.05, 0.99, 'C', size=12, horizontalalignment='center', verticalalignment='top', transform=ax[1,0].transAxes, zorder=5) @@ -786,7 +747,7 @@ def retrieve_gcm_data(gcm_name, rcp, main_glac_rgi, option_bias_adjustment=input ax[1,0].set_xticklabels(['2015','2050','2100']) # Y-label ax[1,0].set_ylabel('Mass (-)', size=12) - ax[1,0].set_ylim(0,15) + ax[1,0].set_ylim(0,33) ax[1,0].yaxis.set_major_locator(plt.MultipleLocator(10)) ax[1,0].yaxis.set_minor_locator(plt.MultipleLocator(2)) # Tick parameters @@ -811,7 +772,7 @@ def retrieve_gcm_data(gcm_name, rcp, main_glac_rgi, option_bias_adjustment=input ax[1,1].text(0.05, 0.99, 'D', size=12, horizontalalignment='center', verticalalignment='top', transform=ax[1,1].transAxes, zorder=5) # Y-label - ax[1,1].set_ylabel('$\mathregular{\sigma_B (m w.e. {yr^{-1}}}$)', size=12) + ax[1,1].set_ylabel('$\mathregular{B_{sigma} (m w.e. {yr^{-1}}}$)', size=12) ax[1,1].yaxis.set_major_locator(plt.MultipleLocator(0.2)) ax[1,1].yaxis.set_minor_locator(plt.MultipleLocator(0.1)) # # Tick parameters @@ -848,7 +809,7 @@ def retrieve_gcm_data(gcm_name, rcp, main_glac_rgi, option_bias_adjustment=input fig.set_size_inches(6, 6) figure_fn = 'uncertainty_large_small_single_multi.png' fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300) - +# #%% @@ -909,304 +870,152 @@ def print_max(netcdf_fp, fn, ds_vns): # print_max(netcdf_fp, ds_fn, ds_vns) # ds = xr.open_dataset(netcdf_fp + ds_fn) + - -#%% -if option_runoff_monthlychange_and_components == 1: - # Note: RECOMPUTE RUNOFF FROM RUNOFF / NOT COMPONENTS TO AVOID AGGREGATING UNCERTAINTIES - rcps = ['rcp45'] - +if option_runoff_components == 1: figure_fp = input.output_sim_fp + 'figures/' - grouping = 'watershed' + startyear = 2015 + endyear = 2100 + + grouping = 'watershed' + peakwater_Nyears = 11 + + startyear=2000 + endyear=2100 ref_startyear = 2000 ref_endyear = 2015 - eoc_startyear = 2085 - eoc_endyear = 2100 - plt_startyear = 2015 plt_endyear = 2100 - - peakwater_startyear = 2015 - peakwater_endyear = 2100 multimodel_linewidth = 2 alpha=0.2 # Load glaciers - main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(rgi_regionsO1=regions) + main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(regions) # Groups groups, group_cn = select_groups(grouping, main_glac_rgi) - subgroups, subgroup_cn = select_groups(subgrouping, main_glac_rgi) - + if grouping == 'watershed': + groups.remove('Irrawaddy') + groups.remove('Yellow') + # Glacier and grouped annual specific mass balance and mass change - for nrcp, rcp in enumerate(rcps): + + for rcp in rcps: + print(rcp) + ds_vn = {} + ds_vn_std = {} + + ds_vns = ['volume_glac_annual', 'area_glac_annual', + 'prec_glac_monthly', 'acc_glac_monthly', 'refreeze_glac_monthly', 'melt_glac_monthly', + 'offglac_prec_monthly', 'offglac_refreeze_monthly', 'offglac_melt_monthly'] + ds_vns_needarea = ['prec_glac_monthly', 'acc_glac_monthly', 'refreeze_glac_monthly', 'melt_glac_monthly', + 'offglac_prec_monthly', 'offglac_refreeze_monthly', 'offglac_melt_monthly'] for region in regions: # Load datasets ds_fn = 'R' + str(region) + '_multimodel_' + rcp + '_c2_ba1_100sets_2000_2100.nc' ds = xr.open_dataset(netcdf_fp_cmip5 + ds_fn) - df = pd.DataFrame(ds.glacier_table.values, columns=ds.glac_attrs) - df['RGIId'] = ['RGI60-' + str(int(df.O1Region.values[x])) + '.' + - str(int(df.glacno.values[x])).zfill(5) for x in df.index.values] - + # Extract time variable time_values_annual = ds.coords['year_plus1'].values time_values_monthly = ds.coords['time'].values - time_values_df = pd.DatetimeIndex(time_values_monthly) - time_values_months = np.array([x.month for x in time_values_df]) - months = list(time_values_months[0:12]) - refyear_idx1 = np.where(time_values_annual == ref_startyear)[0][0] - refyear_idx2 = np.where(time_values_annual == ref_endyear)[0][0] + 1 - refmonth_idx1 = refyear_idx1 * 12 - refmonth_idx2 = refyear_idx2 * 12 - eocyear_idx1 = np.where(time_values_annual==eoc_startyear)[0][0] - eocyear_idx2 = np.where(time_values_annual==eoc_endyear)[0][0] + 1 - eocmonth_idx1 = eocyear_idx1 * 12 - eocmonth_idx2 = eocyear_idx2 * 12 - - # RUNOFF (Gt) - ds_runoff_reg = ((ds['runoff_glac_monthly'].values[:,:,0] + ds['offglac_runoff_monthly'].values[:,:,0]) - / 10**9) - ds_runoff_reg_std = ((ds['runoff_glac_monthly'].values[:,:,1] + ds['offglac_runoff_monthly'].values[:,:,1]) - / 10**9) - ds_runoff_onglac_reg = ds['runoff_glac_monthly'].values[:,:,0] / 10**9 - ds_runoff_offglac_reg = ds['offglac_runoff_monthly'].values[:,:,0] / 10**9 - - # RUNOFF COMPONENTS (UNITS: Gt) - ds_vol_reg = ds['volume_glac_annual'].values[:,:,0] - ds_area_reg = ds['area_glac_annual'].values[:,:,0][:,:-1].repeat(12,axis=1) - ds_prec_reg = ds['prec_glac_monthly'].values[:,:,0] * ds_area_reg * 10**6 / 10**9 - ds_melt_reg = ds['melt_glac_monthly'].values[:,:,0] * ds_area_reg * 10**6 / 10**9 - ds_refr_reg = ds['refreeze_glac_monthly'].values[:,:,0] * ds_area_reg * 10**6 / 10**9 - # Off-glacier - ds_area_off_reg = ds_area_reg[:,0][:,np.newaxis] - ds_area_reg - ds_area_off_reg[ds_area_off_reg < 0] = 0 - ds_prec_off_reg = ds['offglac_prec_monthly'].values[:,:,0] * ds_area_off_reg * 10**6 / 10**9 - ds_melt_off_reg = ds['offglac_melt_monthly'].values[:,:,0] * ds_area_off_reg * 10**6 / 10**9 - ds_refr_off_reg = ds['offglac_refreeze_monthly'].values[:,:,0] * ds_area_off_reg * 10**6 / 10**9 + for vn in ds_vns: + if region == regions[0]: + ds_vn[vn] = ds[vn].values[:,:,0] + ds_vn_std[vn] = ds[vn].values[:,:,1] + else: + ds_vn[vn] = np.concatenate((ds_vn[vn], ds[vn].values[:,:,0]), axis=0) + ds_vn_std[vn] = np.concatenate((ds_vn_std[vn], ds[vn].values[:,:,1]), axis=0) + + # Remove negative values in off glacier caused by glacier advance + if 'offglac' in vn: + ds_vn[vn][ds_vn[vn] < 0] = 0 ds.close() - if region == regions[0]: - df_all = df - ds_runoff = ds_runoff_reg - ds_runoff_std = ds_runoff_reg_std - ds_runoff_onglac = ds_runoff_onglac_reg - ds_runoff_offglac = ds_runoff_offglac_reg - ds_vol = ds_vol_reg - ds_prec = ds_prec_reg - ds_melt = ds_melt_reg - ds_refr = ds_refr_reg - ds_area = ds_area_reg - ds_prec_off = ds_prec_off_reg - ds_melt_off = ds_melt_off_reg - ds_refr_off = ds_refr_off_reg - ds_area_off = ds_area_off_reg + # Convert to annual + ds_vn_annual = {} + for vn in ds_vns: + if 'monthly' in vn: + ds_vn_annual[vn] = gcmbiasadj.annual_sum_2darray(ds_vn[vn]) else: - df_all = pd.concat([df_all, df], axis=0) - ds_runoff = np.concatenate((ds_runoff, ds_runoff_reg), axis=0) - ds_runoff_std = np.concatenate((ds_runoff_std, ds_runoff_reg_std), axis=0) - ds_runoff_onglac = np.concatenate((ds_runoff_onglac, ds_runoff_onglac_reg), axis=0) - ds_runoff_offglac = np.concatenate((ds_runoff_offglac, ds_runoff_offglac_reg), axis=0) - ds_vol = np.concatenate((ds_vol, ds_vol_reg), axis=0) - ds_area = np.concatenate((ds_area, ds_area_reg), axis=0) - ds_prec = np.concatenate((ds_prec, ds_prec_reg), axis=0) - ds_melt = np.concatenate((ds_melt, ds_melt_reg), axis=0) - ds_refr = np.concatenate((ds_refr, ds_refr_reg), axis=0) - ds_area_off = np.concatenate((ds_area_off, ds_area_off_reg), axis=0) - ds_prec_off = np.concatenate((ds_prec_off, ds_prec_off_reg), axis=0) - ds_melt_off = np.concatenate((ds_melt_off, ds_melt_off_reg), axis=0) - ds_refr_off = np.concatenate((ds_refr_off, ds_refr_off_reg), axis=0) - - - # RUNOFF FROM COMPONENTS AND RELATIVE FRACTION OF EACH COMPONENT - # note: this significantly differs from runoff values due to the propagation of errors associated with - # the averaging of each of the components and the area, which in part result from using the mean values - # since this is biased towards higher values (see Figure Uncertainty in Projections Paper) - ds_runoff2 = ds_prec + ds_melt - ds_refr + ds_prec_off + ds_melt_off - ds_refr_off - - # ANNUAL RUNOFF AND COMPONENTS - ds_runoff_annual = gcmbiasadj.annual_sum_2darray(ds_runoff) - ds_runoff_onglac_annual = gcmbiasadj.annual_sum_2darray(ds_runoff_onglac) - ds_runoff_offglac_annual = gcmbiasadj.annual_sum_2darray(ds_runoff_offglac) - ds_runoff2_annual = gcmbiasadj.annual_sum_2darray(ds_runoff2) - ds_prec_annual = gcmbiasadj.annual_sum_2darray(ds_prec) - ds_melt_annual = gcmbiasadj.annual_sum_2darray(ds_melt) - ds_refr_annual = gcmbiasadj.annual_sum_2darray(ds_refr) - ds_prec_off_annual = gcmbiasadj.annual_sum_2darray(ds_prec_off) - ds_melt_off_annual = gcmbiasadj.annual_sum_2darray(ds_melt_off) - ds_refr_off_annual = gcmbiasadj.annual_sum_2darray(ds_refr_off) - # excess glacier meltwater based on volume change - ds_melt_excess_annual = excess_meltwater_m3(ds_vol) / 1e9 - - # Remove RGIIds from main_glac_rgi that are not in the model runs - if nrcp == 0: - rgiid_df = list(df_all.RGIId.values) - rgiid_all = list(main_glac_rgi.RGIId.values) - rgi_idx = [rgiid_all.index(x) for x in rgiid_df] - main_glac_rgi = main_glac_rgi.loc[rgi_idx,:] - main_glac_rgi.reset_index(inplace=True, drop=True) - + ds_vn_annual[vn] = ds_vn[vn] + + # Excess glacier meltwater based on volume change + ds_vn_annual['excess_melt_annual'] = excess_meltwater_m3(ds_vn_annual['volume_glac_annual']) + ds_vns.append('excess_melt_annual') + #%% - # GROUP PROCESSING (RUNOFF AND UNCERTAINTY) - df_runoff_group_annual = pd.DataFrame(np.zeros((len(groups), len(time_values_annual[:-1]))), - columns=time_values_annual[:-1], index=groups) - df_runoff2_group_annual = pd.DataFrame(np.zeros((len(groups), len(time_values_annual[:-1]))), - columns=time_values_annual[:-1], index=groups) - df_runoff_onglac_group_annual = pd.DataFrame(np.zeros((len(groups), len(time_values_annual[:-1]))), - columns=time_values_annual[:-1], index=groups) - df_runoff_offglac_group_annual = pd.DataFrame(np.zeros((len(groups), len(time_values_annual[:-1]))), - columns=time_values_annual[:-1], index=groups) - df_runoff_group_ref_monthly = pd.DataFrame(np.zeros((len(groups),12)), columns=months, index=groups) - df_runoff_group_eoc_monthly = pd.DataFrame(np.zeros((len(groups),12)), columns=months, index=groups) - df_runoff_group_eoc_monthly_norm = pd.DataFrame(np.zeros((len(groups),12)), columns=months, index=groups) - df_runoff_group_eoc_monthly_norm_std = pd.DataFrame(np.zeros((len(groups),12)), columns=months, index=groups) + # Groups + count = 0 + group_vn_annual = {} for ngroup, group in enumerate(groups): # Select subset of data group_glac_indices = main_glac_rgi.loc[main_glac_rgi[group_cn] == group].index.values.tolist() - - # MONTHLY GROUP RUNOFF - runoff_group = ds_runoff[group_glac_indices,:].sum(axis=0) - - # Uncertainty associated with volume change based on subgroups - # sum standard deviations in each subgroup assuming that they are uncorrelated - # then use the root sum of squares using the uncertainty of each subgroup to get the - # uncertainty of the group - main_glac_rgi_subset = main_glac_rgi.loc[main_glac_rgi[group_cn] == group] - subgroups_subset = main_glac_rgi_subset[subgroup_cn].unique() - subgroup_std = np.zeros((len(subgroups_subset), ds_runoff.shape[1])) - for nsubgroup, subgroup in enumerate(subgroups_subset): - main_glac_rgi_subgroup = main_glac_rgi.loc[main_glac_rgi[subgroup_cn] == subgroup] - subgroup_indices = ( - main_glac_rgi.loc[main_glac_rgi[subgroup_cn] == subgroup].index.values.tolist()) - # subgroup uncertainty is sum of each glacier since assumed to be perfectly correlated - subgroup_std[nsubgroup,:] = ds_runoff_std[subgroup_indices,:].sum(axis=0) - runoff_group_std = (subgroup_std**2).sum(axis=0)**0.5 - - # ANNUAL GROUP RUNOFF - df_runoff_group_annual.loc[group,:] = ds_runoff_annual[group_glac_indices,:].sum(axis=0) - df_runoff2_group_annual.loc[group,:] = ds_runoff2_annual[group_glac_indices,:].sum(axis=0) - # Total (glacier and off-glacier) - df_runoff_onglac_group_annual.loc[group,:] = ds_runoff_onglac_annual[group_glac_indices,:].sum(axis=0) - df_runoff_offglac_group_annual.loc[group,:] = ds_runoff_offglac_annual[group_glac_indices,:].sum(axis=0) - - # REFERENCE AND END OF CENTURY MONTHLY RUNOFF - def monthly_mean(x, month_idx1, month_idx2): - x_subset = x[month_idx1:month_idx2] - monthly_mean = np.zeros((12)) - for nmonth in np.arange(0,12): - monthly_mean[nmonth] = x_subset[nmonth::12].mean() - return monthly_mean - - runoff_group_ref_monthly = monthly_mean(runoff_group, refmonth_idx1, refmonth_idx2) - runoff_group_ref_monthly_std = monthly_mean(runoff_group_std, refmonth_idx1, refmonth_idx2) - runoff_group_eoc_monthly = monthly_mean(runoff_group, eocmonth_idx1, eocmonth_idx2) - runoff_group_eoc_monthly_std = monthly_mean(runoff_group_std, eocmonth_idx1, eocmonth_idx2) - df_runoff_group_ref_monthly.loc[group,:] = runoff_group_ref_monthly - df_runoff_group_eoc_monthly.loc[group,:] = runoff_group_eoc_monthly - - # NORMALIZED CHANGE IN RUNOFF BY END OF CENTURY RELATIVE TO REFERENCE PERIOD - runoff_group_eoc_monthly_norm = ((runoff_group_eoc_monthly - runoff_group_ref_monthly) / - runoff_group_ref_monthly * 100) - runoff_group_eoc_monthly_norm_std = runoff_group_eoc_monthly_std / runoff_group_ref_monthly * 100 - df_runoff_group_eoc_monthly_norm.loc[group,:] = runoff_group_eoc_monthly_norm - df_runoff_group_eoc_monthly_norm_std.loc[group,:] = runoff_group_eoc_monthly_norm_std - - # ===== EXPORT RUNOFF CHANGES FOR MAY - OCTOBER ===== - output_df = df_runoff_group_eoc_monthly_norm.copy() - output_df_std = df_runoff_group_eoc_monthly_norm_std.copy() - # Replace nan and infinity with 0 - output_df.replace({np.nan:0, np.inf:0},inplace=True) - output_df_std.replace({np.nan:0, np.inf:0},inplace=True) - for nrow in output_df.index.values: - for ncol in output_df.columns.values: - xmean = output_df.loc[nrow,ncol] - xstd = output_df_std.loc[nrow,ncol] - if xmean >= 0: - output_df.loc[nrow,ncol] = ('+' + str(int(np.round(xmean,0))) + u'\u00B1' + - str(int(np.round(xstd,0))) + '%') + group_vn_annual[group] = {} + for vn in ds_vns: + if vn in ds_vns_needarea: + if 'offglac' in vn: + offglac_area_annual = (ds_vn_annual['area_glac_annual'][:,0][:,np.newaxis] - + ds_vn_annual['area_glac_annual']) + offglac_area_annual[offglac_area_annual < 0] = 0 + group_vn_annual[group][vn] = ( + (offglac_area_annual[group_glac_indices,:-1] * 10**6 * + ds_vn_annual[vn][group_glac_indices,:]).sum(axis=0)) + + else: + group_vn_annual[group][vn] = ( + (ds_vn_annual['area_glac_annual'][group_glac_indices,:-1] * 10**6 * + ds_vn_annual[vn][group_glac_indices,:]).sum(axis=0)) else: - output_df.loc[nrow,ncol] = (str(int(np.round(xmean,0))) + u'\u00B1' + - str(int(np.round(xstd,0))) + '%') - output_df.index = [title_dict[group] for group in groups] - - cns_ordered = [1,2,3,4,5,6,7,8,9,10,11,12] - - output_df = output_df[cns_ordered] - - output_fn = grouping + '_monthly_chg_' + rcp + '.csv' - output_df.to_csv(figure_fp + output_fn) + group_vn_annual[group][vn] = ds_vn_annual[vn][group_glac_indices,:].sum(axis=0) + + group_vn_annual[group]['runoff_glac_monthly'] = ( + group_vn_annual[group]['melt_glac_monthly'] + group_vn_annual[group]['prec_glac_monthly'] - + group_vn_annual[group]['refreeze_glac_monthly']) + group_vn_annual[group]['offglac_runoff_monthly'] = ( + group_vn_annual[group]['offglac_melt_monthly'] + group_vn_annual[group]['offglac_prec_monthly'] - + group_vn_annual[group]['offglac_refreeze_monthly']) + group_vn_annual[group]['total_runoff_monthly'] = ( + group_vn_annual[group]['offglac_runoff_monthly'] + group_vn_annual[group]['runoff_glac_monthly']) #%% - # ===== EXPORT PEAK WATER STATISTICS ===== # Peakwater - stats_cns = ['group', 'rcp', 'runoff_Gtyr_ref', 'peakwater_yr', 'peakwater_chg_perc', '2100_chg_perc'] - output_dfpw = pd.DataFrame(np.zeros((len(groups),len(stats_cns))), columns=stats_cns) - output_dfpw['group'] = groups - output_dfpw['rcp'] = rcp print('Peakwater by group for', rcp) nyears = 11 group_peakwater = {} - pw_idx1 = np.where(time_values_annual == peakwater_startyear)[0][0] - pw_idx2 = np.where(time_values_annual == peakwater_endyear)[0][0]+1 for ngroup, group in enumerate(groups): - group_peakwater[group] = peakwater(df_runoff_group_annual.loc[group,:].values[pw_idx1:pw_idx2], - time_values_annual[pw_idx1:pw_idx2], nyears) + group_peakwater[group] = peakwater(group_vn_annual[group]['total_runoff_monthly'], + time_values_annual[:-1], nyears) print(group, group_peakwater[group][0], '\n peakwater_chg[%]:', np.round(group_peakwater[group][1],0), '\n 2100 chg[%]:', np.round(group_peakwater[group][2],0)) - output_dfpw.loc[ngroup,'runoff_Gtyr_ref'] = ( - df_runoff_group_annual.loc[group,:].values[refyear_idx1:refyear_idx2].mean()) - output_dfpw.loc[ngroup,'peakwater_yr'] = group_peakwater[group][0] - output_dfpw.loc[ngroup,'peakwater_chg_perc'] = group_peakwater[group][1] - output_dfpw.loc[ngroup,'2100_chg_perc'] = group_peakwater[group][2] if grouping == 'watershed': # Add Aral Sea (Amu Darya + Syr Darya) for comparison with HH2019 group = 'Aral_Sea' - group_peakwater['Aral_Sea'] = peakwater(df_runoff_group_annual.loc['Amu_Darya',:].values[pw_idx1:pw_idx2] + - df_runoff_group_annual.loc['Syr_Darya',:].values[pw_idx1:pw_idx2], - time_values_annual[pw_idx1:pw_idx2], nyears) + group_peakwater['Aral_Sea'] = peakwater(group_vn_annual['Amu_Darya']['total_runoff_monthly'] + + group_vn_annual['Syr_Darya']['total_runoff_monthly'], + time_values_annual[:-1], nyears) print(group, group_peakwater[group][0], '\n peakwater_chg[%]:', np.round(group_peakwater[group][1],0), '\n 2100 chg[%]:', np.round(group_peakwater[group][2],0)) - output_dfpw2 = pd.DataFrame(np.zeros((1,len(stats_cns))), columns=stats_cns) - output_dfpw2.loc[0,'group'] = group - output_dfpw2.loc[0,'rcp'] = rcp - output_dfpw2.loc[0,'runoff_Gtyr_ref'] = ( - (df_runoff_group_annual.loc['Amu_Darya',:].values + - df_runoff_group_annual.loc['Syr_Darya',:].values)[refyear_idx1:refyear_idx2].mean()) - output_dfpw2.loc[0,'peakwater_yr'] = group_peakwater[group][0] - output_dfpw2.loc[0,'peakwater_chg_perc'] = group_peakwater[group][1] - output_dfpw2.loc[0,'2100_chg_perc'] = group_peakwater[group][2] - output_dfpw = pd.concat([output_dfpw, output_dfpw2], axis=0) - output_dfpw.reset_index(inplace=True, drop=True) - - output_dfpw.to_csv(figure_fp + grouping + '_peakwater_stats_' + rcp + '.csv', index=False) #%% - groups2plot = groups.copy() - if grouping == 'watershed': - groups2plot.remove('Irrawaddy') - groups2plot.remove('Yellow') - - t1_idx = np.where(time_values_annual == plt_startyear)[0][0] - t2_idx = np.where(time_values_annual == plt_endyear)[0][0] + 1 - multimodel_linewidth = 2 alpha=0.2 reg_legend = [] num_cols_max = 4 if len(groups) < num_cols_max: - num_cols = len(groups2plot) + num_cols = len(groups) else: num_cols = num_cols_max - num_rows = int(np.ceil(len(groups2plot)/num_cols)) + num_rows = int(np.ceil(len(groups)/num_cols)) fig, ax = plt.subplots(num_rows, num_cols, squeeze=False, sharex=False, sharey=True, gridspec_kw = {'wspace':0, 'hspace':0}) @@ -1215,63 +1024,42 @@ def monthly_mean(x, month_idx1, month_idx2): # Cycle through groups row_idx = 0 col_idx = 0 - - for ngroup, group in enumerate(groups2plot): + for ngroup, group in enumerate(groups): # Set subplot position if (ngroup % num_cols == 0) and (ngroup != 0): row_idx += 1 col_idx = 0 - # COMPONENTS OF ANNUAL RUNOFF ADJUSTED - group_glac_indices = main_glac_rgi.loc[main_glac_rgi[group_cn] == group].index.values.tolist() - group_annual_runoff2 = df_runoff2_group_annual.loc[group,:].values - group_annual_prec = ds_prec_annual[group_glac_indices,:].sum(axis=0) - group_annual_melt = ds_melt_annual[group_glac_indices,:].sum(axis=0) - group_annual_melt_excess = ds_melt_excess_annual[group_glac_indices,:].sum(axis=0) - group_annual_refr = ds_refr_annual[group_glac_indices,:].sum(axis=0) - group_annual_prec_off = ds_prec_off_annual[group_glac_indices,:].sum(axis=0) - group_annual_melt_off = ds_melt_off_annual[group_glac_indices,:].sum(axis=0) - group_annual_refr_off = ds_refr_off_annual[group_glac_indices,:].sum(axis=0) - - # Runoff datasets (not from components) - group_annual_runoff = df_runoff_group_annual.loc[group,:].values - - # Fraction of each component - group_annual_prec_frac = group_annual_prec / group_annual_runoff2 - group_annual_melt_frac = group_annual_melt / group_annual_runoff2 - group_annual_melt_excess_frac = group_annual_melt_excess / group_annual_runoff2 - group_annual_refr_frac = group_annual_refr / group_annual_runoff2 - group_annual_prec_off_frac = group_annual_prec_off / group_annual_runoff2 - group_annual_melt_off_frac = group_annual_melt_off / group_annual_runoff2 - group_annual_refr_off_frac = group_annual_refr_off / group_annual_runoff2 - - component_check = (group_annual_prec_frac + group_annual_melt_frac - group_annual_refr_frac + - group_annual_prec_off_frac + group_annual_melt_off_frac - - group_annual_refr_off_frac) - - # Each component adjusted - group_annual_prec_adj = group_annual_prec_frac * group_annual_runoff - group_annual_melt_adj = group_annual_melt_frac * group_annual_runoff - group_annual_melt_excess_adj = group_annual_melt_excess_frac * group_annual_runoff - group_annual_refr_adj = group_annual_refr_frac * group_annual_runoff - group_annual_prec_off_adj = group_annual_prec_off_frac * group_annual_runoff - group_annual_melt_off_adj = group_annual_melt_off_frac * group_annual_runoff - group_annual_refr_off_adj = group_annual_refr_off_frac * group_annual_runoff - - - # Normalize values for plot - runoff_total_normalizer = group_annual_runoff[refyear_idx1:refyear_idx2].mean() - - runoff_total_norm = group_annual_runoff / runoff_total_normalizer - runoff_glac_total_norm = df_runoff_onglac_group_annual.loc[group,:].values / runoff_total_normalizer - runoff_glac_prec_norm = group_annual_prec_adj / runoff_total_normalizer - runoff_glac_melt_norm = group_annual_melt_adj / runoff_total_normalizer - runoff_glac_excess_norm = group_annual_melt_excess_adj / runoff_total_normalizer - runoff_glac_refreeze_norm = group_annual_refr_adj / runoff_total_normalizer - runoff_offglac_prec_norm = group_annual_prec_off_adj / runoff_total_normalizer - runoff_offglac_melt_norm = group_annual_melt_off_adj / runoff_total_normalizer - runoff_offglac_refreeze_norm = group_annual_refr_off_adj / runoff_total_normalizer + # Time indices + t1_idx_ref = np.where(time_values_annual == ref_startyear)[0][0] + t2_idx_ref = np.where(time_values_annual == ref_endyear)[0][0] + 1 + + # Multi-model statistics + runoff_total = group_vn_annual[group]['total_runoff_monthly'] + runoff_glac_total = group_vn_annual[group]['runoff_glac_monthly'] + runoff_glac_melt = group_vn_annual[group]['melt_glac_monthly'] + runoff_glac_excess = group_vn_annual[group]['excess_melt_annual'] + runoff_glac_prec = group_vn_annual[group]['prec_glac_monthly'] + runoff_glac_refreeze = group_vn_annual[group]['refreeze_glac_monthly'] + runoff_offglac_melt = group_vn_annual[group]['offglac_melt_monthly'] + runoff_offglac_prec = group_vn_annual[group]['offglac_prec_monthly'] + runoff_offglac_refreeze = group_vn_annual[group]['offglac_refreeze_monthly'] + runoff_total_normalizer = runoff_total[t1_idx_ref:t2_idx_ref].mean() + + # Normalize values + runoff_total_norm = runoff_total / runoff_total_normalizer + runoff_glac_total_norm = runoff_glac_total / runoff_total_normalizer + runoff_glac_melt_norm = runoff_glac_melt / runoff_total_normalizer + runoff_glac_excess_norm = runoff_glac_excess / runoff_total_normalizer + runoff_glac_prec_norm = runoff_glac_prec / runoff_total_normalizer + runoff_glac_refreeze_norm = runoff_glac_refreeze / runoff_total_normalizer + runoff_offglac_prec_norm = runoff_offglac_prec / runoff_total_normalizer + runoff_offglac_melt_norm = runoff_offglac_melt / runoff_total_normalizer + runoff_offglac_refreeze_norm = runoff_offglac_refreeze / runoff_total_normalizer + t1_idx = np.where(time_values_annual == plt_startyear)[0][0] + t2_idx = np.where(time_values_annual == plt_endyear)[0][0] + 1 + # Plot # Total runoff (line) ax[row_idx, col_idx].plot(time_values_annual[t1_idx:t2_idx], runoff_total_norm[t1_idx:t2_idx], @@ -1281,41 +1069,37 @@ def monthly_mean(x, month_idx1, month_idx2): color='k', linewidth=1, linestyle='--', zorder=3) # Components - component_alpha = 0.5 - # Glacier melt on bottom (green fill) + # Glacier melt - excess on bottom (green fill) ax[row_idx, col_idx].fill_between( time_values_annual[t1_idx:t2_idx], 0, runoff_glac_melt_norm[t1_idx:t2_idx] - runoff_glac_excess_norm[t1_idx:t2_idx], -# facecolor='green', alpha=0.2, label='glac melt', zorder=3) - facecolor='maroon', alpha=component_alpha, label='glac melt', zorder=3) - # Excess glacier melt (green fill) + facecolor='green', alpha=0.2, label='glac melt', zorder=3) + # Excess glacier melt on bottom (green fill) ax[row_idx, col_idx].fill_between( time_values_annual[t1_idx:t2_idx], runoff_glac_melt_norm[t1_idx:t2_idx], runoff_glac_melt_norm[t1_idx:t2_idx] - runoff_glac_excess_norm[t1_idx:t2_idx], -# facecolor='darkgreen', alpha=0.4, label='glac excess', zorder=3) - facecolor='orangered', alpha=component_alpha, label='glac excess', zorder=3) + facecolor='darkgreen', alpha=0.4, label='glac excess', zorder=3) # Off-Glacier melt (blue fill) ax[row_idx, col_idx].fill_between( time_values_annual[t1_idx:t2_idx], runoff_glac_melt_norm[t1_idx:t2_idx], runoff_glac_melt_norm[t1_idx:t2_idx] + runoff_offglac_melt_norm[t1_idx:t2_idx], - facecolor='orange', alpha=component_alpha, label='offglac melt', zorder=3) + facecolor='blue', alpha=0.2, label='offglac melt', zorder=3) # Glacier refreeze (grey fill) ax[row_idx, col_idx].fill_between( time_values_annual[t1_idx:t2_idx], 0, runoff_glac_refreeze_norm[t1_idx:t2_idx], - facecolor='grey', alpha=component_alpha, label='glac refreeze', hatch='////', zorder=4) + facecolor='grey', alpha=0.2, label='glac refreeze', hatch='////', zorder=4) # Glacier precipitation (yellow fill) ax[row_idx, col_idx].fill_between( time_values_annual[t1_idx:t2_idx], runoff_glac_melt_norm[t1_idx:t2_idx] + runoff_offglac_melt_norm[t1_idx:t2_idx], (runoff_glac_melt_norm[t1_idx:t2_idx] + runoff_offglac_melt_norm[t1_idx:t2_idx] + runoff_glac_prec_norm[t1_idx:t2_idx]), -# facecolor='yellow', alpha=0.2, label='glacier prec', zorder=3) - facecolor='mediumblue', alpha=component_alpha, label='glacier prec', zorder=3) + facecolor='yellow', alpha=0.2, label='glacier prec', zorder=3) # Off-glacier precipitation (red fill) ax[row_idx, col_idx].fill_between( time_values_annual[t1_idx:t2_idx], @@ -1323,14 +1107,13 @@ def monthly_mean(x, month_idx1, month_idx2): runoff_glac_prec_norm[t1_idx:t2_idx]), (runoff_glac_melt_norm[t1_idx:t2_idx] + runoff_offglac_melt_norm[t1_idx:t2_idx] + runoff_glac_prec_norm[t1_idx:t2_idx] + runoff_offglac_prec_norm[t1_idx:t2_idx]), -# facecolor='red', alpha=0.2, label='offglac prec', zorder=3) - facecolor='lightseagreen', alpha=component_alpha, label='offglac prec', zorder=3) -# # Off-glacier refreeze (grey fill) -# ax[row_idx, col_idx].fill_between( -# time_values_annual[t1_idx:t2_idx], -# runoff_glac_melt_norm[t1_idx:t2_idx], -# runoff_glac_melt_norm[t1_idx:t2_idx] + runoff_offglac_refreeze_norm[t1_idx:t2_idx], -# facecolor='grey', alpha=0.2, label='offglac refreeze', hatch='....', zorder=4) + facecolor='red', alpha=0.2, label='offglac prec', zorder=3) + # Off-glacier refreeze (grey fill) + ax[row_idx, col_idx].fill_between( + time_values_annual[t1_idx:t2_idx], + runoff_glac_melt_norm[t1_idx:t2_idx], + runoff_glac_melt_norm[t1_idx:t2_idx] + runoff_offglac_refreeze_norm[t1_idx:t2_idx], + facecolor='grey', alpha=0.2, label='offglac refreeze', hatch='....', zorder=4) # Group labels if add_group_label == 1: @@ -1351,15 +1134,10 @@ def monthly_mean(x, month_idx1, month_idx2): ax[row_idx, col_idx].set_xticklabels(['','','']) # Y-label - if rcp in ['rcp85']: - ax[row_idx, col_idx].set_ylim(0,2.3) - ax[row_idx, col_idx].set_yticklabels(['','','0.5','1.0','1.5', '2.0']) - else: - ax[row_idx, col_idx].set_ylim(0,2) - ax[row_idx, col_idx].set_yticklabels(['','','0.5','1.0','1.5', '']) + ax[row_idx, col_idx].set_ylim(0,2) ax[row_idx, col_idx].yaxis.set_major_locator(plt.MultipleLocator(0.5)) ax[row_idx, col_idx].yaxis.set_minor_locator(plt.MultipleLocator(0.1)) - + ax[row_idx, col_idx].set_yticklabels(['','','0.5','1.0','1.5', '']) # Tick parameters ax[row_idx, col_idx].yaxis.set_ticks_position('both') @@ -1367,31 +1145,28 @@ def monthly_mean(x, month_idx1, month_idx2): ax[row_idx, col_idx].tick_params(axis='both', which='minor', labelsize=12, direction='inout') # Add value to subplot -# plot_str = '(' + str(int(np.round(runoff_total_normalizer,0))) + ' Gt $\mathregular{yr^{-1}}$)' -# plot_str = '(' + str(np.round(runoff_total_normalizer,1)) + ' Gt $\mathregular{yr^{-1}}$) - plot_str = str(np.round(runoff_total_normalizer,1)) - - ax[row_idx, col_idx].text(0.5, 0.9, plot_str, size=10, horizontalalignment='center', + group_runoff_Gta = runoff_total_normalizer * (1/1000)**3 + plot_str = '(' + str(int(np.round(group_runoff_Gta,0))) + ' Gt $\mathregular{a^{-1}}$)' + + ax[row_idx, col_idx].text(0.5, 0.92, plot_str, size=10, horizontalalignment='center', verticalalignment='top', transform=ax[row_idx, col_idx].transAxes, color='k', zorder=5) # Count column index to plot col_idx += 1 # Line legend - leg_alpha = component_alpha - leg_list = ['Fixed-gauge\nglacier runoff', 'Moving-gauge\nglacier runoff', + leg_alpha = 0.2 + leg_list = ['Total runoff', 'Glacier runoff', 'Off-glacier\nprecipitation', 'Glacier\nprecipitation', 'Off-glacier\nmelt', -# 'Off-glacier\nrefreeze', - 'Glacier melt\n(excess)', 'Glacier melt\n(equilibrium)', + 'Off-glacier\nrefreeze', 'Glacier melt\n(excess)', 'Glacier melt\n(equilibrium)', 'Glacier\nrefreeze'] - line_dict = {'Fixed-gauge\nglacier runoff':['black',1,'-',1,''], - 'Moving-gauge\nglacier runoff':['black',1,'--',1,''], - 'Glacier melt\n(equilibrium)':['maroon',5,'-',leg_alpha,''], - 'Glacier melt\n(excess)':['orangered',5,'-',0.4,''], - 'Glacier\nprecipitation':['mediumblue',5,'-',leg_alpha,''], + line_dict = {'Total runoff':['black',1,'-',1,''], 'Glacier runoff':['black',1,'--',1,''], + 'Glacier melt\n(equilibrium)':['green',5,'-',leg_alpha,''], + 'Glacier melt\n(excess)':['darkgreen',5,'-',0.4,''], + 'Glacier\nprecipitation':['yellow',5,'-',leg_alpha,''], 'Glacier\nrefreeze':['grey',5,'-',leg_alpha,'////'], - 'Off-glacier\nmelt':['orange',5,'-',leg_alpha,''], - 'Off-glacier\nprecipitation':['lightseagreen',5,'-',leg_alpha,''], + 'Off-glacier\nmelt':['blue',5,'-',leg_alpha,''], + 'Off-glacier\nprecipitation':['red',5,'-',leg_alpha,''], 'Off-glacier\nrefreeze':['grey',5,'-',leg_alpha,'....']} leg_lines = [] leg_labels = [] @@ -1405,7 +1180,7 @@ def monthly_mean(x, month_idx1, month_idx2): leg_lines.append(line) leg_labels.append(vn_label) fig.subplots_adjust(right=0.83) - fig.legend(leg_lines, leg_labels, loc=(0.83,0.30), fontsize=10, labelspacing=0.5, handlelength=1, ncol=1, + fig.legend(leg_lines, leg_labels, loc=(0.83,0.38), fontsize=10, labelspacing=0.5, handlelength=1, ncol=1, handletextpad=0.5, borderpad=0, frameon=False) # Label @@ -1420,144 +1195,270 @@ def monthly_mean(x, month_idx1, month_idx2): figure_fn = grouping + '_runoffcomponents_mulitmodel_' + rcp + '.png' fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300) + + +#%% + +if option_runoff_monthlychange == 1: + # Note: RECOMPUTE RUNOFF FROM COMPONENTS since using the mean glacier area * components does not equal the mean + # of the runoff computed from the simulations. Hence, need to compute from components to get proper alignment. + rcps = ['rcp85'] - #%% - # ====== PLOT OF NORMALIZED CHANGE AND COMPONENTS ===== - groups2plot = groups.copy() - if grouping == 'watershed': - groups2plot.remove('Irrawaddy') - groups2plot.remove('Yellow') - - multimodel_linewidth = 2 - alpha=0.5 + figure_fp = input.output_sim_fp + 'figures/' - reg_legend = [] - num_cols_max = 4 - if len(groups) < num_cols_max: - num_cols = len(groups2plot) - else: - num_cols = num_cols_max - num_rows = int(np.ceil(len(groups2plot)/num_cols)) - - fig, ax = plt.subplots(num_rows, num_cols, squeeze=False, sharex=False, sharey=True, - gridspec_kw = {'wspace':0, 'hspace':0}) - add_group_label = 1 - - # Cycle through groups - row_idx = 0 - col_idx = 0 - - def shift_list(l,n): - return l[n:] + l[:n] + grouping = 'watershed' + + ref_startyear = 2000 + ref_endyear = 2015 + + plt_startyear = 2085 + plt_endyear = 2100 + + multimodel_linewidth = 2 + alpha=0.2 + + # Load glaciers + main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(regions) + + # Groups + groups, group_cn = select_groups(grouping, main_glac_rgi) + if grouping == 'watershed': + groups.remove('Irrawaddy') + groups.remove('Yellow') + +#%% + # Glacier and grouped annual specific mass balance and mass change + for rcp in rcps: + print(rcp) + ds_vn = {} + ds_vn_std = {} - def norm_shift(values, norm_value, nshift): - return np.array(shift_list(list(values / norm_value), nshift)) - n_shift = 3 - months_plot = shift_list(months, n_shift) + ds_vns = ['area_glac_annual', 'prec_glac_monthly', 'acc_glac_monthly', 'refreeze_glac_monthly', + 'melt_glac_monthly', 'offglac_prec_monthly', 'offglac_refreeze_monthly', 'offglac_melt_monthly'] + ds_vns_needarea = ['prec_glac_monthly', 'acc_glac_monthly', 'refreeze_glac_monthly', 'melt_glac_monthly', + 'offglac_prec_monthly', 'offglac_refreeze_monthly', 'offglac_melt_monthly'] - for ngroup, group in enumerate(groups2plot): - # COMPONENTS OF END OF CENTURY MONTHLY RUNOF - group_glac_indices = main_glac_rgi.loc[main_glac_rgi[group_cn] == group].index.values.tolist() - group_runoff2 = ds_runoff2[group_glac_indices,:].sum(axis=0) - group_prec = ds_prec[group_glac_indices,:].sum(axis=0) - group_melt = ds_melt[group_glac_indices,:].sum(axis=0) - group_refr = ds_refr[group_glac_indices,:].sum(axis=0) - group_prec_off = ds_prec_off[group_glac_indices,:].sum(axis=0) - group_melt_off = ds_melt_off[group_glac_indices,:].sum(axis=0) - group_refr_off = ds_refr_off[group_glac_indices,:].sum(axis=0) - - group_eoc_monthly_runoff2 = monthly_mean(group_runoff2, eocmonth_idx1, eocmonth_idx2) - group_eoc_monthly_prec = monthly_mean(group_prec, eocmonth_idx1, eocmonth_idx2) - group_eoc_monthly_melt = monthly_mean(group_melt, eocmonth_idx1, eocmonth_idx2) - group_eoc_monthly_refr = monthly_mean(group_refr, eocmonth_idx1, eocmonth_idx2) - group_eoc_monthly_prec_off = monthly_mean(group_prec_off, eocmonth_idx1, eocmonth_idx2) - group_eoc_monthly_melt_off = monthly_mean(group_melt_off, eocmonth_idx1, eocmonth_idx2) - group_eoc_monthly_refr_off = monthly_mean(group_refr_off, eocmonth_idx1, eocmonth_idx2) - - group_runoff2_check = (group_eoc_monthly_prec + group_eoc_monthly_melt - group_eoc_monthly_refr + - group_eoc_monthly_prec_off + group_eoc_monthly_melt_off - group_eoc_monthly_refr_off) - - # Runoff datasets (not from components) - runoff_group_eoc_monthly = df_runoff_group_eoc_monthly.loc[group,:].values - runoff_group_ref_monthly = df_runoff_group_ref_monthly.loc[group,:].values - - runoff_dif = group_eoc_monthly_runoff2 - runoff_group_eoc_monthly - runoff_dif_norm = np.round(runoff_dif / runoff_group_eoc_monthly * 100,1) - - print('\n', group, '\n', runoff_dif_norm) - - # Fraction of each component - group_eoc_monthly_prec_frac = group_eoc_monthly_prec / group_eoc_monthly_runoff2 - group_eoc_monthly_melt_frac = group_eoc_monthly_melt / group_eoc_monthly_runoff2 - group_eoc_monthly_refr_frac = group_eoc_monthly_refr / group_eoc_monthly_runoff2 - group_eoc_monthly_prec_off_frac = group_eoc_monthly_prec_off / group_eoc_monthly_runoff2 - group_eoc_monthly_melt_off_frac = group_eoc_monthly_melt_off / group_eoc_monthly_runoff2 - group_eoc_monthly_refr_off_frac = group_eoc_monthly_refr_off / group_eoc_monthly_runoff2 - - component_check = (group_eoc_monthly_prec_frac + group_eoc_monthly_melt_frac - group_eoc_monthly_refr_frac + - group_eoc_monthly_prec_off_frac + group_eoc_monthly_melt_off_frac - - group_eoc_monthly_refr_off_frac) - - # Each component adjusted - group_eoc_monthly_prec_adj = group_eoc_monthly_prec_frac * runoff_group_eoc_monthly - group_eoc_monthly_melt_adj = group_eoc_monthly_melt_frac * runoff_group_eoc_monthly - group_eoc_monthly_refr_adj = group_eoc_monthly_refr_frac * runoff_group_eoc_monthly - group_eoc_monthly_prec_off_adj = group_eoc_monthly_prec_off_frac * runoff_group_eoc_monthly - group_eoc_monthly_melt_off_adj = group_eoc_monthly_melt_off_frac * runoff_group_eoc_monthly - group_eoc_monthly_refr_off_adj = group_eoc_monthly_refr_off_frac * runoff_group_eoc_monthly - - - # PLOT DETAILS - # Set subplot position - if (ngroup % num_cols == 0) and (ngroup != 0): - row_idx += 1 - col_idx = 0 - - # Normalize and shift values for plot - runoff_normalizer = runoff_group_ref_monthly.max() + for region in regions: - month_runoff_total_ref_plot = norm_shift(runoff_group_ref_monthly, runoff_normalizer, n_shift) - month_runoff_total_plot = norm_shift(runoff_group_eoc_monthly, runoff_normalizer, n_shift) - month_glac_prec_plot = norm_shift(group_eoc_monthly_prec_adj, runoff_normalizer, n_shift) - month_glac_melt_plot = norm_shift(group_eoc_monthly_melt_adj, runoff_normalizer, n_shift) - month_glac_refreeze_plot = norm_shift(group_eoc_monthly_refr_adj, runoff_normalizer, n_shift) - month_offglac_prec_plot = norm_shift(group_eoc_monthly_prec_off_adj, runoff_normalizer, n_shift) - month_offglac_melt_plot = norm_shift(group_eoc_monthly_melt_off_adj, runoff_normalizer, n_shift) - month_offglac_refreeze_plot = norm_shift(group_eoc_monthly_refr_off_adj, runoff_normalizer, n_shift) + # Load datasets + ds_fn = 'R' + str(region) + '_multimodel_' + rcp + '_c2_ba1_100sets_2000_2100.nc' + ds = xr.open_dataset(netcdf_fp_cmip5 + ds_fn) - ax[row_idx, col_idx].plot(months_plot, month_runoff_total_ref_plot, color='k', linewidth=1, linestyle='-', - zorder=4) - ax[row_idx, col_idx].plot(months_plot, month_runoff_total_plot, color='k', linewidth=1, linestyle='--', - zorder=4) + # Extract time variable + time_values_annual = ds.coords['year_plus1'].values + time_values_monthly = ds.coords['time'].values - # Components - # Glacier melt on bottom (green fill) - ax[row_idx, col_idx].fill_between(months_plot, 0, - month_glac_melt_plot, - facecolor='darkred', alpha=alpha, label='glac melt', zorder=3) - # Off-Glacier melt (blue fill) - ax[row_idx, col_idx].fill_between(months_plot, month_glac_melt_plot, - month_glac_melt_plot + month_offglac_melt_plot, - facecolor='orange', alpha=alpha, label='offglac melt', zorder=3) - # Glacier refreeze (grey fill) - ax[row_idx, col_idx].fill_between(months_plot, 0, month_glac_refreeze_plot, - facecolor='grey', alpha=alpha, label='glac refreeze', hatch='////', + for vn in ds_vns: + if region == regions[0]: + ds_vn[vn] = ds[vn].values[:,:,0] + ds_vn_std[vn] = ds[vn].values[:,:,1] + else: + ds_vn[vn] = np.concatenate((ds_vn[vn], ds[vn].values[:,:,0]), axis=0) + ds_vn_std[vn] = np.concatenate((ds_vn_std[vn], ds[vn].values[:,:,1]), axis=0) + + # Remove negative values in off glacier caused by glacier advance + if 'offglac' in vn: + ds_vn[vn][ds_vn[vn] < 0] = 0 + ds.close() + + ds_vn['area_glac_monthly'] = ds_vn['area_glac_annual'][:,:-1].repeat(12,axis=1) + ds_vns.append('area_glac_monthly') +# ds_vn['runoff_total_monthly'] = ds_vn['runoff_glac_monthly'] + ds_vn['offglac_runoff_monthly'] +# ds_vns.append('runoff_total_monthly') + + #%% + # Groups + count = 0 + group_vn = {} + for ngroup, group in enumerate(groups): + # Select subset of data + group_glac_indices = main_glac_rgi.loc[main_glac_rgi[group_cn] == group].index.values.tolist() + + group_vn[group] = {} + for vn in ds_vns: + if vn in ds_vns_needarea: + if 'offglac' in vn: + offglac_area = ds_vn['area_glac_monthly'][:,0][:,np.newaxis] - ds_vn['area_glac_monthly'] + offglac_area[offglac_area < 0] = 0 + group_vn[group][vn] = ((offglac_area[group_glac_indices,:] * 10**6 * + ds_vn[vn][group_glac_indices,:]).sum(axis=0)) + else: + group_vn[group][vn] = ((ds_vn['area_glac_monthly'][group_glac_indices,:] * 10**6 * + ds_vn[vn][group_glac_indices,:]).sum(axis=0)) + else: + group_vn[group][vn] = ds_vn[vn][group_glac_indices,:].sum(axis=0) + + group_vn[group]['runoff_glac_monthly'] = ( + group_vn[group]['melt_glac_monthly'] + group_vn[group]['prec_glac_monthly'] - + group_vn[group]['refreeze_glac_monthly']) + group_vn[group]['offglac_runoff_monthly'] = ( + group_vn[group]['offglac_melt_monthly'] + group_vn[group]['offglac_prec_monthly'] - + group_vn[group]['offglac_refreeze_monthly']) + group_vn[group]['total_runoff_monthly'] = ( + group_vn[group]['offglac_runoff_monthly'] + group_vn[group]['runoff_glac_monthly']) + + #%% + # Months + time_values_df = pd.DatetimeIndex(time_values_monthly) + time_values_months = np.array([x.month for x in time_values_df]) + + group_vns = ['total_runoff_monthly', 'runoff_glac_monthly', 'offglac_runoff_monthly', + 'melt_glac_monthly', 'prec_glac_monthly', 'refreeze_glac_monthly', + 'offglac_melt_monthly', 'offglac_prec_monthly', 'offglac_refreeze_monthly'] + + group_vn_months = {} + for ngroup, group in enumerate(groups): +# for ngroup, group in enumerate(['Amu_Darya']): + + months = list(time_values_months[0:12]) + month_values = [] + group_vn_months[group] = {} + for vn in group_vns: +# for vn in ['runoff_total_monthly', 'runoff_glac_monthly']: + group_vn_months[group][vn] = {} + var_all = group_vn[group][vn] + for n_month, month in enumerate(months): +# for n_month, month in enumerate([10]): + group_vn_months[group][vn][month] = var_all[n_month::12] +# var_month = var_all[n_month::12] +# var_month_runningmean = uniform_filter(var_month, size=nyears) +# group_vn_months[group][vn][month] = var_month_runningmean + + + def shift_list(l,n): + return l[n:] + l[:n] + + # Shift values for plots + def retrieve_monthly_values_ref(group_vn_months, group, vn, t1_idx, t2_idx, months): + month_values_ref = [] + for n_month, month in enumerate(months): + month_values_ref.append(group_vn_months[group][vn][month][t1_idx:t2_idx].mean()) + return month_values_ref.copy() + + def retrieve_monthly_values(group_vn_months, group, vn, t_idx, months): + A = [] + for n_month, month in enumerate(months): + B = group_vn_months[group][vn][month][t_idx] + A.append(B) + return A.copy() + + #%% + multimodel_linewidth = 2 + alpha=0.2 + + reg_legend = [] + num_cols_max = 4 + if len(groups) < num_cols_max: + num_cols = len(groups) + else: + num_cols = num_cols_max + num_rows = int(np.ceil(len(groups)/num_cols)) + + fig, ax = plt.subplots(num_rows, num_cols, squeeze=False, sharex=False, sharey=True, + gridspec_kw = {'wspace':0, 'hspace':0}) + add_group_label = 1 + + # Cycle through groups + row_idx = 0 + col_idx = 0 + + def norm_shift(values, norm_value, nshift): + return np.array(shift_list(list(values / norm_value), nshift)) + + for ngroup, group in enumerate(groups): +# for ngroup, group in enumerate(['Amu_Darya']): + # Set subplot position + if (ngroup % num_cols == 0) and (ngroup != 0): + row_idx += 1 + col_idx = 0 + + # Retrieve values + # Time indices + ref_idx1 = np.where(time_values_annual == ref_startyear)[0][0] + ref_idx2 = np.where(time_values_annual == ref_endyear)[0][0] + 1 + year_idx1 = np.where(time_values_annual==plt_startyear)[0][0] + year_idx2 = np.where(time_values_annual==plt_endyear)[0][0]+1 + months = list(time_values_months[0:12]) + + month_runoff_total_ref = [] + month_runoff_total = [] + month_runoff_glac = [] + month_runoff_offglac = [] + month_glac_prec = [] + month_glac_melt = [] + month_glac_refreeze = [] + month_offglac_prec = [] + month_offglac_melt = [] + month_offglac_refreeze = [] + for nmonth in range(0,12): + month_runoff_total_ref.append( + group_vn_months[group]['total_runoff_monthly'][months[nmonth]][ref_idx1:ref_idx2].mean()) + month_runoff_total.append( + group_vn_months[group]['total_runoff_monthly'][months[nmonth]][year_idx1:year_idx2].mean()) + month_runoff_glac.append( + group_vn_months[group]['runoff_glac_monthly'][months[nmonth]][year_idx1:year_idx2].mean()) + month_runoff_offglac.append( + group_vn_months[group]['offglac_runoff_monthly'][months[nmonth]][year_idx1:year_idx2].mean()) + month_glac_melt.append( + group_vn_months[group]['melt_glac_monthly'][months[nmonth]][year_idx1:year_idx2].mean()) + month_glac_prec.append( + group_vn_months[group]['prec_glac_monthly'][months[nmonth]][year_idx1:year_idx2].mean()) + month_glac_refreeze.append( + group_vn_months[group]['refreeze_glac_monthly'][months[nmonth]][year_idx1:year_idx2].mean()) + month_offglac_melt.append( + group_vn_months[group]['offglac_melt_monthly'][months[nmonth]][year_idx1:year_idx2].mean()) + month_offglac_prec.append( + group_vn_months[group]['offglac_prec_monthly'][months[nmonth]][year_idx1:year_idx2].mean()) + month_offglac_refreeze.append( + group_vn_months[group]['offglac_refreeze_monthly'][months[nmonth]][year_idx1:year_idx2].mean()) + + runoff_normalizer = np.max(month_runoff_total_ref) + + n_shift = 3 + months = shift_list(months, n_shift) + month_runoff_total_ref_plot = norm_shift(month_runoff_total_ref, runoff_normalizer, n_shift) + month_runoff_total_plot = norm_shift(month_runoff_total, runoff_normalizer, n_shift) + month_runoff_glac_plot = norm_shift(month_runoff_glac, runoff_normalizer, n_shift) + month_runoff_offglac_plot = norm_shift(month_runoff_offglac, runoff_normalizer, n_shift) + month_glac_prec_plot = norm_shift(month_glac_prec, runoff_normalizer, n_shift) + month_glac_melt_plot = norm_shift(month_glac_melt, runoff_normalizer, n_shift) + month_glac_refreeze_plot = norm_shift(month_glac_refreeze, runoff_normalizer, n_shift) + month_offglac_prec_plot = norm_shift(month_offglac_prec, runoff_normalizer, n_shift) + month_offglac_melt_plot = norm_shift(month_offglac_melt, runoff_normalizer, n_shift) + month_offglac_refreeze_plot = norm_shift(month_offglac_refreeze, runoff_normalizer, n_shift) + + ax[row_idx, col_idx].plot(months, month_runoff_total_ref_plot, color='k', linewidth=1, linestyle='-') + ax[row_idx, col_idx].plot(months, month_runoff_total_plot, color='k', linewidth=1, linestyle='--') + + # Components + # Glacier melt on bottom (green fill) + ax[row_idx, col_idx].fill_between(months, 0, + month_glac_melt_plot, + facecolor='green', alpha=0.2, label='glac melt', zorder=3) + # Off-Glacier melt (blue fill) + ax[row_idx, col_idx].fill_between(months, month_glac_melt_plot, + month_glac_melt_plot + month_offglac_melt_plot, + facecolor='blue', alpha=0.2, label='offglac melt', zorder=3) + # Glacier refreeze (grey fill) + ax[row_idx, col_idx].fill_between(months, 0, month_glac_refreeze_plot, + facecolor='grey', alpha=0.2, label='glac refreeze', hatch='////', zorder=4) # Glacier precipitation (yellow fill) - ax[row_idx, col_idx].fill_between(months_plot, month_glac_melt_plot + month_offglac_melt_plot, + ax[row_idx, col_idx].fill_between(months, month_glac_melt_plot + month_offglac_melt_plot, month_glac_melt_plot + month_offglac_melt_plot + month_glac_prec_plot, - facecolor='mediumblue', alpha=alpha, label='glacier prec', zorder=3) + facecolor='yellow', alpha=0.2, label='glacier prec', zorder=3) # Off-glacier precipitation (red fill) - ax[row_idx, col_idx].fill_between(months_plot, + ax[row_idx, col_idx].fill_between(months, month_glac_melt_plot + month_offglac_melt_plot + month_glac_prec_plot, (month_glac_melt_plot + month_offglac_melt_plot + month_glac_prec_plot + month_offglac_prec_plot), - facecolor='lightseagreen', alpha=alpha, label='offglac prec', zorder=3) -# # Off-glacier refreeze (grey fill) -# ax[row_idx, col_idx].fill_between(months, month_glac_melt_plot, -# month_glac_melt_plot + month_offglac_refreeze_plot, -# facecolor='grey', alpha=alpha, label='glac refreeze', hatch='....', -# zorder=4) + facecolor='red', alpha=0.2, label='offglac prec', zorder=3) + + # Off-glacier refreeze (grey fill) + ax[row_idx, col_idx].fill_between(months, month_glac_melt_plot, + month_glac_melt_plot + month_offglac_refreeze_plot, + facecolor='grey', alpha=0.2, label='glac refreeze', hatch='....', + zorder=4) # Group labels if add_group_label == 1: ax[row_idx, col_idx].text(0.5, 0.99, title_dict[group], size=12, horizontalalignment='center', @@ -1574,10 +1475,7 @@ def norm_shift(values, norm_value, nshift): ax[row_idx, col_idx].set_xticklabels(['','','','','','','','']) # Y-label - if rcp in ['rcp26', 'rcp45']: - ax[row_idx, col_idx].set_ylim(0,1.5) - else: - ax[row_idx, col_idx].set_ylim(0,1.8) + ax[row_idx, col_idx].set_ylim(0,1.5) ax[row_idx, col_idx].yaxis.set_major_locator(plt.MultipleLocator(0.5)) ax[row_idx, col_idx].yaxis.set_minor_locator(plt.MultipleLocator(0.1)) ax[row_idx, col_idx].set_yticklabels(['','','0.5','1.0','1.5', '']) @@ -1588,43 +1486,42 @@ def norm_shift(values, norm_value, nshift): ax[row_idx, col_idx].tick_params(axis='both', which='minor', labelsize=12, direction='inout') # Add value to subplot + maxchg = np.nanmin([(month_runoff_total[i] - month_runoff_total_ref[i]) / month_runoff_total_ref[i] * 100 + for i in range(0,12)]) month_chg = ([np.round((month_runoff_total_plot[i] - month_runoff_total_ref_plot[i]) / - month_runoff_total_ref_plot[i] * 100,0) for i in range(0,12)]) - month_chg_subset = month_chg[5:9] - maxchg_subset = np.nanmin(month_chg_subset) + month_runoff_total_ref_plot[i] * 100,0) + for i in range(0,12)]) +# print(group, month_runoff_total_plot[5:9]) +# print(group, month_runoff_total_ref_plot[5:9]) print(group, month_chg[5:9]) - month_dict = {5:'May', 6:'June', 7:'July', 8:'August', 9:'September'} - if maxchg_subset < 0: - txtcolor='k' - month_of_maxchg = np.where(maxchg_subset == month_chg)[0][0] + 1 - plot_str = '(' + str(int(np.round(maxchg_subset,0))) + '%, ' + month_dict[month_of_maxchg] + ')' +# i=5 +# print(month_runoff_total_plot[i], month_runoff_total_ref_plot[i]) +# print(month_runoff_total_plot[i] / month_runoff_total_ref_plot[i]) +# print((month_runoff_total_plot[i]-month_runoff_total_ref_plot[i]) / month_runoff_total_ref_plot[i]) + if maxchg < 0: + txtcolor='red' else: - txtcolor='k' - maxchg_subset = np.nanmax(month_chg_subset) - month_of_maxchg = np.where(maxchg_subset == month_chg)[0][0] + 1 - plot_str = '(+' + str(int(np.round(maxchg_subset,0))) + '%, ' + month_dict[month_of_maxchg] + ')' -# plot_str = '(' + str(int(np.round(maxchg,0))) + ' %)' + txtcolor='blue' + plot_str = '(' + str(int(np.round(maxchg,0))) + ' %)' - ax[row_idx, col_idx].text(0.5, 0.88, plot_str, size=8, horizontalalignment='center', + ax[row_idx, col_idx].text(0.5, 0.88, plot_str, size=12, horizontalalignment='center', verticalalignment='top', transform=ax[row_idx, col_idx].transAxes, color=txtcolor, zorder=5) # Count column index to plot col_idx += 1 # Line legend - leg_alpha = alpha - leg_list = ['Glacier runoff\n2000-2015', 'Glacier runoff\n2085-2100', + leg_alpha = 0.2 + leg_list = ['Total runoff', 'Glacier runoff', 'Off-glacier\nprecipitation', 'Glacier\nprecipitation', 'Off-glacier\nmelt', -# 'Off-glacier\nrefreeze', - 'Glacier melt', + 'Off-glacier\nrefreeze', 'Glacier melt', 'Glacier\nrefreeze'] - line_dict = {'Glacier runoff\n2000-2015':['black',1,'-',1,''], - 'Glacier runoff\n2085-2100':['black',1,'--',1,''], - 'Glacier melt':['darkred',5,'-',leg_alpha,''], - 'Glacier\nprecipitation':['mediumblue',5,'-',leg_alpha,''], + line_dict = {'Total runoff':['black',1,'-',1,''], 'Glacier runoff':['black',1,'--',1,''], + 'Glacier melt':['green',5,'-',leg_alpha,''], + 'Glacier\nprecipitation':['yellow',5,'-',leg_alpha,''], 'Glacier\nrefreeze':['grey',5,'-',leg_alpha,'////'], - 'Off-glacier\nmelt':['orange',5,'-',leg_alpha,''], - 'Off-glacier\nprecipitation':['lightseagreen',5,'-',leg_alpha,''], + 'Off-glacier\nmelt':['blue',5,'-',leg_alpha,''], + 'Off-glacier\nprecipitation':['red',5,'-',leg_alpha,''], 'Off-glacier\nrefreeze':['grey',5,'-',leg_alpha,'....']} leg_lines = [] leg_labels = [] @@ -1659,13 +1556,9 @@ def norm_shift(values, norm_value, nshift): #%% if option_peakwater_map == 1: - figure_fp = netcdf_fp_cmip5 + 'figures/' - if os.path.exists(figure_fp) == False: - os.mkdir(figure_fp) - - rcps = ['rcp26', 'rcp45', 'rcp85'] + figure_fp = input.output_sim_fp + 'figures/' - option_plot4paper_3rcps = 1 + rcps = ['rcp45'] startyear = 2015 endyear = 2100 @@ -1689,7 +1582,7 @@ def norm_shift(values, norm_value, nshift): # Load glaciers - main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(rgi_regionsO1=regions) + main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(regions) # Groups groups, group_cn = select_groups(grouping, main_glac_rgi) @@ -1710,9 +1603,6 @@ def norm_shift(values, norm_value, nshift): # Load datasets ds_fn = 'R' + str(region) + '_multimodel_' + rcp + '_c2_ba1_100sets_2000_2100.nc' ds = xr.open_dataset(netcdf_fp_cmip5 + ds_fn) - df = pd.DataFrame(ds.glacier_table.values, columns=ds.glac_attrs) - df['RGIId'] = ['RGI60-' + str(int(df.O1Region.values[x])) + '.' + - str(int(df.glacno.values[x])).zfill(5) for x in df.index.values] # Extract time variable time_values_annual = ds.coords['year_plus1'].values @@ -1735,23 +1625,13 @@ def norm_shift(values, norm_value, nshift): # Merge datasets if region == regions[0]: vn_glac_all = vn_glac_region - vn_glac_std_all = vn_glac_std_region - df_all = df + vn_glac_std_all = vn_glac_std_region else: vn_glac_all = np.concatenate((vn_glac_all, vn_glac_region), axis=0) vn_glac_std_all = np.concatenate((vn_glac_std_all, vn_glac_std_region), axis=0) - df_all = pd.concat([df_all, df], axis=0) ds.close() - # Remove RGIIds from main_glac_rgi that are not in the model runs - rgiid_df = list(df_all.RGIId.values) - rgiid_all = list(main_glac_rgi.RGIId.values) - rgi_idx = [rgiid_all.index(x) for x in rgiid_df] - main_glac_rgi = main_glac_rgi.loc[rgi_idx,:] - main_glac_rgi.reset_index(inplace=True, drop=True) - - for ngroup, group in enumerate(groups): # Select subset of data group_glac_indices = main_glac_rgi.loc[main_glac_rgi[group_cn] == group].index.values.tolist() @@ -1841,6 +1721,20 @@ def norm_shift(values, norm_value, nshift): group_shp = cartopy.io.shapereader.Reader(kaab_shp_fn) group_shp_attr = 'Name' +# title_location = {'Syr_Darya': [70.2, 43.1], +# 'Ili': [83.6, 45], +# 'Amu_Darya': [67, 35.5], +# 'Tarim': [83.0, 39.2], +# 'Inner_Tibetan_Plateau_extended': [100, 39], +# 'Indus': [70.7, 31.9], +# 'Inner_Tibetan_Plateau': [85, 32.4], +# 'Yangtze': [100.7, 31.6], +# 'Ganges': [81.3, 26.6], +# 'Brahmaputra': [92.0, 25.5], +# 'Irrawaddy': [96.2, 23.8], +# 'Salween': [92.9, 31.2], +# 'Mekong': [96, 31.8], +# 'Yellow': [106.0, 36]} title_location = {'Syr_Darya': [71, 42], 'Ili': [82, 44.5], 'Amu_Darya': [69, 36], @@ -1906,7 +1800,7 @@ def norm_shift(values, norm_value, nshift): if rec.attributes[group_shp_attr] in groups: group = rec.attributes[group_shp_attr] ax.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', edgecolor='Black', - linewidth=1, zorder=3) + linewidth=0.5, zorder=3) # ax.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor=group_colordict[group], # edgecolor='Black', linewidth=0.5, alpha=0.5, zorder=3) if group not in ['Yellow', 'Irrawaddy', 'Mekong']: @@ -1930,11 +1824,10 @@ def norm_shift(values, norm_value, nshift): cbar = plt.colorbar(sm, ax=ax, cax=cax, orientation='vertical') cax.xaxis.set_ticks_position('top') cax.xaxis.set_tick_params(pad=0) - cbar.ax.tick_params(labelsize=8) + cbar.ax.tick_params(labelsize=10) for n, label in enumerate(cax.xaxis.get_ticklabels()): if n%2 != 0: label.set_visible(False) -# fig.text(0.5, 0.89, 'Year', ha='center', va='center', size=10) # fig.text(0.5, 0.89, 'Peak water (year) - RCP ' + rcp[3:], ha='center', va='center', size=10) # Degree peakwater @@ -1966,1259 +1859,6 @@ def norm_shift(values, norm_value, nshift): fig.set_size_inches(3.5,6) figure_fn = 'peakwater_map_' + grouping + '_multimodel_' + rcp + '.png' fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300, transparent=True) - - - #%% - # ===== PLOT WITH CIRCLES SIZED ACCORDING TO AREA ===== - # Create the projection - fig, ax = plt.subplots(1, 1, subplot_kw={'projection':cartopy.crs.PlateCarree()}, - gridspec_kw = {'wspace':0, 'hspace':0}) - - # Add group and attribute of interest - if grouping == 'rgi_region': - group_shp = cartopy.io.shapereader.Reader(rgiO1_shp_fn) - group_shp_attr = 'RGI_CODE' - elif grouping == 'watershed': - group_shp = cartopy.io.shapereader.Reader(watershed_shp_fn) - group_shp_attr = 'watershed' - elif grouping == 'kaab': - group_shp = cartopy.io.shapereader.Reader(kaab_shp_fn) - group_shp_attr = 'Name' - - title_location = {'Syr_Darya': [70.5, 42.7], - 'Ili': [83, 45], - 'Amu_Darya': [68.2, 36], - 'Tarim': [82.5, 38.5], - 'Inner_Tibetan_Plateau_extended': [98.7, 39.75], - 'Indus': [72, 32], - 'Inner_Tibetan_Plateau': [86.2, 34.3], - 'Yangtze': [100.7, 31.5], - 'Ganges': [81.3, 26.6], - 'Brahmaputra': [91.9, 24.3], - 'Irrawaddy': [96.2, 23.8], - 'Salween': [92.6, 31.15], - 'Mekong': [96, 31.8], - 'Yellow': [106.0, 36]} - - # Set the extent - ax.set_extent([east, 66, 24, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax.set_xticks(np.arange(70,100+1,10), cartopy.crs.PlateCarree()) - ax.set_yticks(np.arange(30,45+1,5), cartopy.crs.PlateCarree()) - ax.xaxis.set_tick_params(pad=0, size=2, labelsize=6) - ax.yaxis.set_tick_params(pad=0, size=2, labelsize=6) - ax.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax.xaxis.get_ticklabels()[::2]: - label.set_visible(False) - - - for rec in group_shp.records(): - if rec.attributes[group_shp_attr] in groups: - group = rec.attributes[group_shp_attr] - ax.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', edgecolor='Black', - linewidth=0.5, zorder=3) - if group not in ['Yellow', 'Irrawaddy', 'Mekong']: - ax.text(title_location[rec.attributes[group_shp_attr]][0], - title_location[rec.attributes[group_shp_attr]][1], - title_dict[rec.attributes[group_shp_attr]], horizontalalignment='center', size=8, - zorder=4) - - colorbar_dict = {'volume_norm':[0,1], - 'runoff_glac_monthly':[2020,2080]} - cmap = mpl.cm.RdYlBu - norm = plt.Normalize(colorbar_dict[vn][0], colorbar_dict[vn][1]) - - # Add colorbar - cmap_alpha=1 - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm._A = [] - cax = plt.axes([0.92, 0.38, 0.015, 0.23]) - cbar = plt.colorbar(sm, ax=ax, cax=cax, orientation='vertical', alpha=cmap_alpha) - cax.xaxis.set_ticks_position('top') - cax.xaxis.set_tick_params(pad=0) - cbar.ax.tick_params(labelsize=6) - for n, label in enumerate(cax.xaxis.get_ticklabels()): - if n%2 != 0: - label.set_visible(False) - fig.text(0.965, 0.63, 'Year', ha='center', va='center', size=7) - - # Degree peakwater - x, y, z, s = [], [], [], [] - for group in groups_deg: - vn_multimodel_mean = ds_multimodel_deg[rcp][group] - peakwater_yr, peakwater_chg, runoff_chg = ( - peakwater(vn_multimodel_mean[time_idx_start:time_idx_end], - time_values_annual[time_idx_start:time_idx_end], peakwater_Nyears)) - x.append(deg_dict[group][0]) - y.append(deg_dict[group][1]) - z.append(peakwater_yr) - s.append(vn_multimodel_mean[0:16].mean()) - x = np.array(x) - y = np.array(y) - z = np.array(z) - s = np.array(s) / 1e9 # convert to Gt/yr - - # Size thresholds - s_sizes = [1, 3, 9, 20] - s_plot = np.array(s) - s_plot[s <= 0.01] = s_sizes[0] - s_plot[s > 0.01] = s_sizes[1] - s_plot[s > 0.1] = s_sizes[2] - s_plot[s > 1] = s_sizes[3] - marker_linecolor='k' - marker_linewidth=0.1 - a = ax.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, -# s=5, - s=s_plot, - marker='o', edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - - # Add legend - circ1 = ax.scatter([10],[0], s=s_sizes[0], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ2 = ax.scatter([0],[0], s=s_sizes[1], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ3 = ax.scatter([0],[0], s=s_sizes[2], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ4 = ax.scatter([0],[0], s=s_sizes[3], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - legend=ax.legend([circ1,circ2,circ3,circ4], ['0.001', '0.01', '0.1', '1'], - scatterpoints=1, -# scatteryoffsets=0.5, - ncol=5, loc='upper right', fontsize=6, - labelspacing=0.3, - columnspacing=0, - handletextpad=0, - handlelength=1, - borderpad=0.2, - framealpha=1, - title='Runoff (Gt yr$^{-1}$)', - borderaxespad=0.2, -# titlefontsize=5, -# title_fontsize=5 - ) - legend.get_title().set_fontsize('6') - legend.get_frame().set_linewidth(0.5) - - # Save figure - fig.set_size_inches(3.5,6) - figure_fn = 'peakwater_map_' + grouping + '_multimodel_' + rcp + '_circles_lowres.png' - fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=150, transparent=True) - - #%% - # ===== THREE RCPS TOGETHER WITH CIRCLES ===== - if option_plot4paper_3rcps == 1 and len(rcps) >= 3: - - title_location = {'Syr_Darya': [70.5, 42.7], - 'Ili': [83, 45], - 'Amu_Darya': [68.2, 36], - 'Tarim': [82.5, 38.5], - 'Inner_Tibetan_Plateau_extended': [98.7, 39.75], - 'Indus': [72, 32], - 'Inner_Tibetan_Plateau': [86.2, 34.3], - 'Yangtze': [100.7, 31.5], - 'Ganges': [81.3, 26.6], - 'Brahmaputra': [91.9, 24.3], - 'Irrawaddy': [96.2, 23.8], - 'Salween': [92.6, 31.15], - 'Mekong': [96, 31.8], - 'Yellow': [106.0, 36]} - - # Create the projection - fig = plt.figure() - - # Custom subplots - gs = mpl.gridspec.GridSpec(122, 1) - ax1 = plt.subplot(gs[0:40,0], projection=cartopy.crs.PlateCarree()) - ax2 = plt.subplot(gs[41:81,0], projection=cartopy.crs.PlateCarree()) - ax3 = plt.subplot(gs[82:122,0], projection=cartopy.crs.PlateCarree()) - - # ===== PLOT WITH CIRCLES SIZED ACCORDING TO AREA ===== - marker_linecolor='k' - marker_linewidth=0.1 - - for group in groups: - - # Add group and attribute of interest - if grouping == 'rgi_region': - group_shp = cartopy.io.shapereader.Reader(rgiO1_shp_fn) - group_shp_attr = 'RGI_CODE' - elif grouping == 'watershed': - group_shp = cartopy.io.shapereader.Reader(watershed_shp_fn) - group_shp_attr = 'watershed' - elif grouping == 'kaab': - group_shp = cartopy.io.shapereader.Reader(kaab_shp_fn) - group_shp_attr = 'Name' - - group_fontsize = 10 - for rec in group_shp.records(): - if rec.attributes[group_shp_attr] in groups: - group = rec.attributes[group_shp_attr] - ax1.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - ax2.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - ax3.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - if group not in ['Yellow', 'Irrawaddy', 'Mekong']: - ax1.text(title_location[rec.attributes[group_shp_attr]][0], - title_location[rec.attributes[group_shp_attr]][1], - title_dict[rec.attributes[group_shp_attr]], horizontalalignment='center', - size=group_fontsize, zorder=4) - ax2.text(title_location[rec.attributes[group_shp_attr]][0], - title_location[rec.attributes[group_shp_attr]][1], - title_dict[rec.attributes[group_shp_attr]], horizontalalignment='center', - size=group_fontsize, zorder=4) - ax3.text(title_location[rec.attributes[group_shp_attr]][0], - title_location[rec.attributes[group_shp_attr]][1], - title_dict[rec.attributes[group_shp_attr]], horizontalalignment='center', - size=group_fontsize, zorder=4) - - for nrcp, rcp in enumerate(['rcp26', 'rcp45', 'rcp85']): - for group in groups: - - vn_multimodel_mean = ds_multimodel[rcp][group] - peakwater_yr, peakwater_chg, runoff_chg = ( - peakwater(vn_multimodel_mean[time_idx_start:time_idx_end], - time_values_annual[time_idx_start:time_idx_end], peakwater_Nyears)) - - print(rcp, group, peakwater_yr, np.round(peakwater_chg,0), np.round(runoff_chg,0)) - - # ===== PLOT WITH CIRCLES SIZED ACCORDING TO AREA ===== - # Degree peakwater - x, y, z, s = [], [], [], [] - for group in groups_deg: - vn_multimodel_mean = ds_multimodel_deg[rcp][group] - peakwater_yr, peakwater_chg, runoff_chg = ( - peakwater(vn_multimodel_mean[time_idx_start:time_idx_end], - time_values_annual[time_idx_start:time_idx_end], peakwater_Nyears)) - x.append(deg_dict[group][0]) - y.append(deg_dict[group][1]) - z.append(peakwater_yr) - s.append(vn_multimodel_mean[0:16].mean()) - x = np.array(x) - y = np.array(y) - z = np.array(z) - s = np.array(s) / 1e9 # convert to Gt/yr - - # Size thresholds -# s_sizes = [1, 3, 9, 20] - s_sizes = [2, 6, 18, 40] - s_plot = np.array(s) - s_plot[s <= 0.01] = s_sizes[0] - s_plot[s > 0.01] = s_sizes[1] - s_plot[s > 0.1] = s_sizes[2] - s_plot[s > 1] = s_sizes[3] - - if nrcp == 0: - a = ax1.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - elif nrcp == 1: - a = ax2.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - elif nrcp == 2: - a = ax3.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - - west = 66 - north = 47 - south = 24 - axis_fontsize = 8 - # Set the extent - ax1.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax1.set_xticks(np.arange(70,east+1,10), cartopy.crs.PlateCarree()) - ax1.set_yticks(np.arange(30,north+1,5), cartopy.crs.PlateCarree()) - ax1.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax1.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax1.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax1.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax1.xaxis.get_ticklabels(): - label.set_visible(False) - # Set the extent - ax2.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax2.set_xticks(np.arange(70,100+1,10), cartopy.crs.PlateCarree()) - ax2.set_yticks(np.arange(30,45+1,5), cartopy.crs.PlateCarree()) - ax2.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax2.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax2.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax2.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax2.xaxis.get_ticklabels(): - label.set_visible(False) - # Set the extent - ax3.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax3.set_xticks(np.arange(70,100+1,10), cartopy.crs.PlateCarree()) - ax3.set_yticks(np.arange(30,45+1,5), cartopy.crs.PlateCarree()) - ax3.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax3.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax3.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax3.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax3.xaxis.get_ticklabels()[::2]: - label.set_visible(False) - - - # Add colorbar legend for peakwater - leg_fontsize = 10 - colorbar_dict = {'volume_norm':[0,1], - 'runoff_glac_monthly':[2020,2080]} - cmap = mpl.cm.RdYlBu - norm = plt.Normalize(colorbar_dict[vn][0], colorbar_dict[vn][1]) - cmap_alpha = 1 - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm._A = [] - cax = fig.add_axes([0.68, 0.5, 0.01, 0.35]) - cbar = fig.colorbar(sm, cax=cax, orientation='vertical', alpha=cmap_alpha) - cax.xaxis.set_ticks_position('top') - cax.xaxis.set_tick_params(pad=0) - cbar.ax.tick_params(labelsize=leg_fontsize) - for n, label in enumerate(cax.xaxis.get_ticklabels()): - if n%2 != 0: - label.set_visible(False) - fig.text(0.7, 0.87, 'Year', ha='center', va='center', size=leg_fontsize) - - # Add circle size legend - circ1 = ax1.scatter([0],[0], s=s_sizes[0], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ2 = ax1.scatter([0],[0], s=s_sizes[1], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ3 = ax1.scatter([0],[0], s=s_sizes[2], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ4 = ax1.scatter([0],[0], s=s_sizes[3], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - legend = fig.legend([circ1,circ2,circ3,circ4], ['0.001', '0.01', '0.1', '1'], - scatterpoints=1, - ncol=1, - loc='lower right', - bbox_to_anchor=(0.395,0.24), - fontsize=leg_fontsize, - labelspacing=0.3, - columnspacing=0, - handletextpad=0, - handlelength=1, - borderpad=0.2, - framealpha=0, -# title='Runoff\n(Gt yr$^{-1}$)', - borderaxespad=0.2, - ) -# legend.get_title().set_fontsize(str(leg_fontsize + 1)) - legend.get_frame().set_linewidth(0) - fig.text(0.7, 0.4425, 'Runoff', ha='center', va='center', size=leg_fontsize) - fig.text(0.7, 0.425, '(Gt yr$^{-1}$)', ha='center', va='center', size=leg_fontsize) - - fig.text(0.37, 0.865, 'A', ha='center', va='center', size=12, fontweight='bold') - fig.text(0.37, 0.61, 'B', ha='center', va='center', size=12, fontweight='bold') - fig.text(0.37, 0.356, 'C', ha='center', va='center', size=12, fontweight='bold') - - # Save figure - fig_height = 14 - fig_width = 10.5 - fig.set_size_inches(fig_height,fig_width) - figure_fn = 'peakwater_map_' + grouping + '_multimodel_3rcps_circles.png' - fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300, transparent=True) - #%% - -if option_temp_and_prec_map == 1: - netcdf_fp_cmip5 = '/Volumes/LaCie/HMA_PyGEM/2019_0914/spc_subset/' - figure_fp = netcdf_fp_cmip5 + 'figures/' - if os.path.exists(figure_fp) == False: - os.mkdir(figure_fp) - - rcps = ['rcp26', 'rcp45', 'rcp85'] - - option_plot4paper_3rcps = 1 - - startyear = 2015 - endyear = 2100 - - vn = 'temperature' - grouping = 'watershed' - -# east = 60 -# west = 110 -# south = 15 -# north = 50 - east = 104 - west = 64 - south = 26 - north = 47 - xtick = 5 - ytick = 5 - xlabel = 'Longitude ($\mathregular{^{\circ}}$)' - ylabel = 'Latitude ($\mathregular{^{\circ}}$)' - - startyear=2000 - endyear=2100 - - -# ref_startyear = 2000 -# ref_endyear = 2015 - -# plt_startyear = 2015 -# plt_endyear = 2100 - - # Load glaciers - main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(rgi_regionsO1=regions) - - # Select dates including future projections - dates_table = modelsetup.datesmodelrun(startyear=startyear, endyear=endyear, spinupyears=0, option_wateryear=1) - - # Groups - groups, group_cn = select_groups(grouping, main_glac_rgi) - groups_deg, group_cn_deg = select_groups('degree', main_glac_rgi) - deg_groups = main_glac_rgi.groupby(['CenLon_round', 'CenLat_round']).size().index.values.tolist() - deg_dict = dict(zip(np.arange(0,len(deg_groups)), deg_groups)) - - #%% - # Glacier and grouped annual runoff - ds_temp_multimodel_deg, ds_temp_multimodel_std_deg = {}, {} - ds_prec_multimodel_deg, ds_prec_multimodel_std_deg = {}, {} - ds_temp_multimodel_all, ds_prec_multimodel_all = {}, {} - for rcp in rcps: - - ds_temp_multimodel_deg[rcp], ds_temp_multimodel_std_deg[rcp] = {}, {} - ds_prec_multimodel_deg[rcp], ds_prec_multimodel_std_deg[rcp] = {}, {} - - for ngcm, gcm_name in enumerate(gcm_names): - print(rcp, gcm_name) - - group_glacidx = {} - vol_group_dict = {} - temp_group_dict = {} - prectotal_group_dict = {} - - # Extract data from netcdf - for region in regions: - try: - # Load datasets - ds_fn = ('R' + str(region) + '--all--' + gcm_name + '_' + rcp + - '_c2_ba1_100sets_2000_2100--subset.nc') - ds = xr.open_dataset(netcdf_fp_cmip5 + ds_fn) - df = pd.DataFrame(ds.glacier_table.values, columns=ds.glac_attrs) - df['RGIId'] = ['RGI60-' + str(int(df.O1Region.values[x])) + '.' + - str(int(df.glacno.values[x])).zfill(5) for x in df.index.values] - skip_gcm = 0 - except: - skip_gcm = 1 - print('Skip', gcm_name, rcp, region) - - if skip_gcm == 0: - # Extract time variable - time_values_annual = ds.coords['year_plus1'].values - time_values_monthly = ds.coords['time'].values - # Merge datasets - if region == regions[0]: - area_glac_all = ds['area_glac_annual'].values[:,:,0] - area_glac_std_all = ds['area_glac_annual'].values[:,:,1] - df_all = df - else: - area_glac_all = np.concatenate((area_glac_all, ds['area_glac_annual'].values[:,:,0]), axis=0) - area_glac_std_all = np.concatenate((area_glac_std_all, ds['area_glac_annual'].values[:,:,1]),axis=0) - df_all = pd.concat([df_all, df], axis=0) - ds.close() - - # Remove RGIIds from main_glac_rgi that are not in the model runs - if ngcm == 0: - rgiid_df = list(df_all.RGIId.values) - rgiid_all = list(main_glac_rgi.RGIId.values) - rgi_idx = [rgiid_all.index(x) for x in rgiid_df] - main_glac_rgi = main_glac_rgi.loc[rgi_idx,:] - main_glac_rgi.reset_index(inplace=True, drop=True) - - # Annual Temperature, Precipitation, and Accumulation - temp_glac_all, prectotal_glac_all, elev_glac_all = retrieve_gcm_data(gcm_name, rcp, main_glac_rgi) - temp_glac_all_annual = gcmbiasadj.annual_avg_2darray(temp_glac_all) - prectotal_glac_all_annual = gcmbiasadj.annual_sum_2darray(prectotal_glac_all) - - # Groups for single GCM - for ngroup, group in enumerate(groups_deg): - # Select subset of data - group_glac_indices = main_glac_rgi.loc[main_glac_rgi[group_cn_deg] == group].index.values.tolist() - group_glacidx[group] = group_glac_indices - - # Regional Volume, and Area-weighted Temperature and Precipitation (SINGLE GCM) - temp_group_all = ((temp_glac_all_annual[group_glac_indices,:] * - area_glac_all[group_glac_indices,:][:,0][:,np.newaxis]).sum(axis=0) / - area_glac_all[group_glac_indices,:][:,0].sum()) - prectotal_group_all = ((prectotal_glac_all_annual[group_glac_indices,:] * - area_glac_all[group_glac_indices,:][:,0][:,np.newaxis]).sum(axis=0) / - area_glac_all[group_glac_indices,:][:,0].sum()) - - # Expand dimensions for multi-model calculations - temp_group_all = np.expand_dims(temp_group_all, axis=1) - prectotal_group_all = np.expand_dims(prectotal_group_all, axis=1) - - temp_group_dict[group] = temp_group_all - prectotal_group_dict[group] = prectotal_group_all - - # Expand dimensions for multi-model calculation - temp_glac_all_annual = np.expand_dims(temp_glac_all_annual, axis=2) - prectotal_glac_all_annual = np.expand_dims(prectotal_glac_all_annual, axis=2) - - # ===== MULTI-MODEL ===== - if ngcm == 0: - temp_glac_all_annual_multimodel = temp_glac_all_annual - prectotal_glac_all_annual_multimodel = prectotal_glac_all_annual - - temp_group_dict_multimodel = temp_group_dict - prectotal_group_dict_multimodel = prectotal_group_dict - - else: - temp_glac_all_annual_multimodel = np.append(temp_glac_all_annual_multimodel, - temp_glac_all_annual, axis=2) - prectotal_glac_all_annual_multimodel = np.append(prectotal_glac_all_annual_multimodel, - prectotal_glac_all_annual, axis=2) - - for ngroup, group in enumerate(groups_deg): - temp_group_dict_multimodel[group] = np.append(temp_group_dict_multimodel[group], - temp_group_dict[group], axis=1) - prectotal_group_dict_multimodel[group] = np.append(prectotal_group_dict_multimodel[group], - prectotal_group_dict[group], axis=1) - - ds_temp_multimodel_all[rcp] = temp_glac_all_annual_multimodel - HMA_multimodel_gcm_temp = temp_glac_all_annual_multimodel.mean(axis=2).mean(axis=0) - HMA_multimodel_gcm_temp_increase = HMA_multimodel_gcm_temp[90:101].mean() - HMA_multimodel_gcm_temp[0:16].mean() - print('manually specifying range') - print(rcp, 'HMA temp increase', HMA_multimodel_gcm_temp_increase) - - ds_prec_multimodel_all[rcp] = prectotal_glac_all_annual_multimodel - HMA_multimodel_gcm_prec = prectotal_glac_all_annual_multimodel.mean(axis=2).mean(axis=0) - HMA_multimodel_gcm_prec_increase = HMA_multimodel_gcm_prec[85:101].mean() / HMA_multimodel_gcm_prec[0:16].mean() - print(rcp, 'HMA prec increase', HMA_multimodel_gcm_prec_increase) - - # Group multimodel mean for each RCP - for ngroup, group in enumerate(groups_deg): - ds_temp_multimodel_deg[rcp][group] = temp_group_dict_multimodel[group].mean(axis=1) - ds_prec_multimodel_deg[rcp][group] = prectotal_group_dict_multimodel[group].mean(axis=1) - - # Area for size plotting - area_init_group = {} - for ngroup, group in enumerate(groups_deg): - # Select subset of data - area_init_group[group] = area_glac_all[group_glacidx[group],0].sum() - - #%% - for rcp in rcps: - temp_glac_all_annual_multimodel = ds_temp_multimodel_all[rcp] - HMA_multimodel_gcm_temp = temp_glac_all_annual_multimodel.mean(axis=2).mean(axis=0) - HMA_multimodel_gcm_temp_increase = HMA_multimodel_gcm_temp[85:101].mean() - HMA_multimodel_gcm_temp[0:16].mean() - print(rcp, 'HMA temp increase', HMA_multimodel_gcm_temp_increase) - prectotal_glac_all_annual_multimodel = ds_prec_multimodel_all[rcp] - HMA_multimodel_gcm_prec = prectotal_glac_all_annual_multimodel.mean(axis=2).mean(axis=0) - HMA_multimodel_gcm_prec_increase = HMA_multimodel_gcm_prec[85:101].mean() / HMA_multimodel_gcm_prec[0:16].mean() - print(rcp, 'HMA prec increase', HMA_multimodel_gcm_prec_increase) - - time_idx_start = np.where(time_values_annual == startyear)[0][0] - time_idx_end = np.where(time_values_annual == endyear)[0][0] + 1 - - #%% - # ===== THREE RCPS TOGETHER WITH CIRCLES FOR TEMPERATURE ===== - if option_plot4paper_3rcps == 1 and len(rcps) >= 3: - - title_location = {'Syr_Darya': [70.5, 42.7], - 'Ili': [83, 45], - 'Amu_Darya': [68.2, 36], - 'Tarim': [82.5, 38.5], - 'Inner_Tibetan_Plateau_extended': [98.7, 39.75], - 'Indus': [72, 32], - 'Inner_Tibetan_Plateau': [86.2, 34.3], - 'Yangtze': [100.7, 31.5], - 'Ganges': [81.3, 26.6], - 'Brahmaputra': [91.9, 24.3], - 'Irrawaddy': [96.2, 23.8], - 'Salween': [92.6, 31.15], - 'Mekong': [96, 31.8], - 'Yellow': [106.0, 36]} - title_dict = {'Amu_Darya': 'Amu\nDarya', - 'Brahmaputra': 'Brahma-\nputra', - 'Ganges': 'Ganges', - 'Ili': 'Ili', - 'Indus': 'Indus', - 'Inner_Tibetan_Plateau': 'Inner TP', - 'Inner_Tibetan_Plateau_extended': 'Inner TP ext', - 'Irrawaddy': 'Irrawaddy', - 'Mekong': 'Mk', - 'Salween': 'Sw', - 'Syr_Darya': 'Syr\nDarya', - 'Tarim': 'Tarim', - 'Yangtze': 'Yz'} - group_colordict = {'Amu_Darya': 'mediumblue', - 'Brahmaputra': 'salmon', - 'Ganges': 'lightskyblue', - 'Ili': 'royalblue', - 'Indus': 'darkred', - 'Inner_Tibetan_Plateau': 'gold', - 'Inner_Tibetan_Plateau_extended': 'navy', - 'Irrawaddy': 'white', - 'Mekong': 'white', - 'Salween': 'plum', - 'Syr_Darya':'darkolivegreen', - 'Tarim': 'olive', - 'Yangtze': 'orange', - 'Yellow':'white'} - - # Create the projection - fig = plt.figure() - - # Custom subplots - gs = mpl.gridspec.GridSpec(122, 1) - ax1 = plt.subplot(gs[0:40,0], projection=cartopy.crs.PlateCarree()) - ax2 = plt.subplot(gs[41:81,0], projection=cartopy.crs.PlateCarree()) - ax3 = plt.subplot(gs[82:122,0], projection=cartopy.crs.PlateCarree()) - - # ===== PLOT WITH CIRCLES SIZED ACCORDING TO AREA ===== - marker_linecolor='k' - marker_linewidth=0.1 - - for group in groups: - - # Add group and attribute of interest - if grouping == 'rgi_region': - group_shp = cartopy.io.shapereader.Reader(rgiO1_shp_fn) - group_shp_attr = 'RGI_CODE' - elif grouping == 'watershed': - group_shp = cartopy.io.shapereader.Reader(watershed_shp_fn) - group_shp_attr = 'watershed' - elif grouping == 'kaab': - group_shp = cartopy.io.shapereader.Reader(kaab_shp_fn) - group_shp_attr = 'Name' - - group_fontsize = 10 - for rec in group_shp.records(): - if rec.attributes[group_shp_attr] in groups: - group = rec.attributes[group_shp_attr] - ax1.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - ax2.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - ax3.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - if group not in ['Yellow', 'Irrawaddy', 'Mekong']: - ax1.text(title_location[rec.attributes[group_shp_attr]][0], - title_location[rec.attributes[group_shp_attr]][1], - title_dict[rec.attributes[group_shp_attr]], horizontalalignment='center', - size=group_fontsize, zorder=4) - ax2.text(title_location[rec.attributes[group_shp_attr]][0], - title_location[rec.attributes[group_shp_attr]][1], - title_dict[rec.attributes[group_shp_attr]], horizontalalignment='center', - size=group_fontsize, zorder=4) - ax3.text(title_location[rec.attributes[group_shp_attr]][0], - title_location[rec.attributes[group_shp_attr]][1], - title_dict[rec.attributes[group_shp_attr]], horizontalalignment='center', - size=group_fontsize, zorder=4) - - for nrcp, rcp in enumerate(['rcp26', 'rcp45', 'rcp85']): - # Add colorbar legend for peakwater - leg_fontsize = 10 - cmap_alpha=1 - cmap = mpl.cm.RdYlBu_r - if rcp == 'rcp26': - norm = plt.Normalize(0.5, 1.5) - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm._A = [] - cax1 = fig.add_axes([0.68, 0.65, 0.01, 0.19]) - cbar1 = fig.colorbar(sm, cax=cax1, orientation='vertical', alpha=cmap_alpha) - cax1.xaxis.set_ticks_position('top') - cax1.xaxis.set_tick_params(pad=0) - cbar1.ax.tick_params(labelsize=leg_fontsize) - for n, label in enumerate(cax1.xaxis.get_ticklabels()): - if n%2 != 0: - label.set_visible(False) - fig.text(0.705, 0.865, '$\Delta$ Temperature\n($^\circ$C)', ha='center', va='center', size=leg_fontsize) - elif rcp == 'rcp45': - norm = plt.Normalize(2, 3) - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm._A = [] - cax1 = fig.add_axes([0.68, 0.41, 0.01, 0.19]) - cbar1 = fig.colorbar(sm, cax=cax1, orientation='vertical', alpha=cmap_alpha) - cax1.xaxis.set_ticks_position('top') - cax1.xaxis.set_tick_params(pad=0) - cbar1.ax.tick_params(labelsize=leg_fontsize) - for n, label in enumerate(cax1.xaxis.get_ticklabels()): - if n%2 != 0: - label.set_visible(False) - elif rcp == 'rcp85': - norm = plt.Normalize(5, 7) - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm._A = [] - cax1 = fig.add_axes([0.68, 0.15, 0.01, 0.19]) - cbar1 = fig.colorbar(sm, cax=cax1, orientation='vertical', alpha=cmap_alpha) - cax1.xaxis.set_ticks_position('top') - cax1.xaxis.set_tick_params(pad=0) - cbar1.ax.tick_params(labelsize=leg_fontsize) - for n, label in enumerate(cax1.xaxis.get_ticklabels()): - if n%2 != 0: - label.set_visible(False) - cmap_alpha = 1 - - # ===== PLOT WITH CIRCLES SIZED ACCORDING TO AREA ===== - # Degree peakwater - x, y, z, s = [], [], [], [] - for group in groups_deg: - vn_multimodel_mean = ds_temp_multimodel_deg[rcp][group] - vn_multimodel_mean_plot = ( - vn_multimodel_mean[-1] - vn_multimodel_mean[0:16].mean()) - x.append(deg_dict[group][0]) - y.append(deg_dict[group][1]) - z.append(vn_multimodel_mean_plot) - s.append(area_init_group[group]) - x = np.array(x) - y = np.array(y) - z = np.array(z) - s = np.array(s) - - # Size thresholds - s_sizes = [2, 6, 18, 40] - s_plot = np.array(s) - s_plot[s <= 10] = s_sizes[0] - s_plot[s > 10] = s_sizes[1] - s_plot[s > 100] = s_sizes[2] - s_plot[s > 1000] = s_sizes[3] - - if nrcp == 0: - a = ax1.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - elif nrcp == 1: - a = ax2.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - elif nrcp == 2: - a = ax3.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - - west = 66 - north = 47 - south = 24 - axis_fontsize = 8 - # Set the extent - ax1.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax1.set_xticks(np.arange(70,east+1,10), cartopy.crs.PlateCarree()) - ax1.set_yticks(np.arange(30,north+1,5), cartopy.crs.PlateCarree()) - ax1.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax1.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax1.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax1.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax1.xaxis.get_ticklabels(): - label.set_visible(False) - # Set the extent - ax2.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax2.set_xticks(np.arange(70,100+1,10), cartopy.crs.PlateCarree()) - ax2.set_yticks(np.arange(30,45+1,5), cartopy.crs.PlateCarree()) - ax2.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax2.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax2.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax2.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax2.xaxis.get_ticklabels(): - label.set_visible(False) - # Set the extent - ax3.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax3.set_xticks(np.arange(70,100+1,10), cartopy.crs.PlateCarree()) - ax3.set_yticks(np.arange(30,45+1,5), cartopy.crs.PlateCarree()) - ax3.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax3.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax3.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax3.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax3.xaxis.get_ticklabels()[::2]: - label.set_visible(False) - - # Add circle size legend - circ1 = ax1.scatter([0],[0], s=s_sizes[0], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ2 = ax1.scatter([0],[0], s=s_sizes[1], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ3 = ax1.scatter([0],[0], s=s_sizes[2], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ4 = ax1.scatter([0],[0], s=s_sizes[3], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - legend=ax1.legend([circ1,circ2,circ3,circ4], ['0.001', '0.01', '0.1', '1'], - scatterpoints=1, - # scatteryoffsets=0.5, - ncol=5, loc='upper right', fontsize=leg_fontsize, - labelspacing=0.3, - columnspacing=0, - handletextpad=0, - handlelength=1, - borderpad=0.2, - framealpha=1, - title='Initial area (km$^{2}$)', - borderaxespad=0.2, - ) - legend.get_title().set_fontsize(str(leg_fontsize)) - legend.get_frame().set_linewidth(0.5) - - fig.text(0.37, 0.865, 'A', ha='center', va='center', size=12, fontweight='bold') - fig.text(0.37, 0.61, 'B', ha='center', va='center', size=12, fontweight='bold') - fig.text(0.37, 0.356, 'C', ha='center', va='center', size=12, fontweight='bold') - - # Save figure - fig_height = 14 - fig_width = 10.5 - fig.set_size_inches(fig_height,fig_width) - figure_fn = 'temp_map_' + grouping + '_multimodel_3rcps_circles.png' - fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300, transparent=True) - #%% - # Create the projection - fig = plt.figure() - - # Custom subplots - gs = mpl.gridspec.GridSpec(122, 1) - ax1 = plt.subplot(gs[0:40,0], projection=cartopy.crs.PlateCarree()) - ax2 = plt.subplot(gs[41:81,0], projection=cartopy.crs.PlateCarree()) - ax3 = plt.subplot(gs[82:122,0], projection=cartopy.crs.PlateCarree()) - - # ===== PLOT WITH CIRCLES SIZED ACCORDING TO AREA ===== - marker_linecolor='k' - marker_linewidth=0.1 - - for group in groups: - - # Add group and attribute of interest - if grouping == 'rgi_region': - group_shp = cartopy.io.shapereader.Reader(rgiO1_shp_fn) - group_shp_attr = 'RGI_CODE' - elif grouping == 'watershed': - group_shp = cartopy.io.shapereader.Reader(watershed_shp_fn) - group_shp_attr = 'watershed' - elif grouping == 'kaab': - group_shp = cartopy.io.shapereader.Reader(kaab_shp_fn) - group_shp_attr = 'Name' - - group_fontsize = 10 - for rec in group_shp.records(): - if rec.attributes[group_shp_attr] in groups: - group = rec.attributes[group_shp_attr] - ax1.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - ax2.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - ax3.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - if group not in ['Yellow', 'Irrawaddy', 'Mekong']: - ax1.text(title_location[rec.attributes[group_shp_attr]][0], - title_location[rec.attributes[group_shp_attr]][1], - title_dict[rec.attributes[group_shp_attr]], horizontalalignment='center', - size=group_fontsize, zorder=4) - ax2.text(title_location[rec.attributes[group_shp_attr]][0], - title_location[rec.attributes[group_shp_attr]][1], - title_dict[rec.attributes[group_shp_attr]], horizontalalignment='center', - size=group_fontsize, zorder=4) - ax3.text(title_location[rec.attributes[group_shp_attr]][0], - title_location[rec.attributes[group_shp_attr]][1], - title_dict[rec.attributes[group_shp_attr]], horizontalalignment='center', - size=group_fontsize, zorder=4) - - # Add colorbar legend - leg_fontsize = 10 - cmap = mpl.cm.RdYlBu - norm = plt.Normalize(0.9, 1.1) - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm._A = [] - cax1 = fig.add_axes([0.68, 0.3, 0.01, 0.4]) - cbar1 = fig.colorbar(sm, cax=cax1, orientation='vertical', alpha=cmap_alpha) - cax1.xaxis.set_ticks_position('top') - cax1.xaxis.set_tick_params(pad=0) - cbar1.ax.tick_params(labelsize=leg_fontsize) - for n, label in enumerate(cax1.xaxis.get_ticklabels()): - if n%2 != 0: - label.set_visible(False) - fig.text(0.705, 0.73, '$\Delta$ Precipitation\n(-)', ha='center', va='center', size=leg_fontsize) - cmap_alpha = 1 - - for nrcp, rcp in enumerate(['rcp26', 'rcp45', 'rcp85']): - # ===== PLOT WITH CIRCLES SIZED ACCORDING TO AREA ===== - # Degree peakwater - x, y, z, s = [], [], [], [] - for group in groups_deg: - vn_multimodel_mean = ds_prec_multimodel_deg[rcp][group] - vn_multimodel_mean_plot = ( - vn_multimodel_mean[-1] / vn_multimodel_mean[0:16].mean()) - x.append(deg_dict[group][0]) - y.append(deg_dict[group][1]) - z.append(vn_multimodel_mean_plot) - s.append(area_init_group[group]) - x = np.array(x) - y = np.array(y) - z = np.array(z) - s = np.array(s) - - # Size thresholds - s_sizes = [2, 6, 18, 40] - s_plot = np.array(s) - s_plot[s <= 10] = s_sizes[0] - s_plot[s > 10] = s_sizes[1] - s_plot[s > 100] = s_sizes[2] - s_plot[s > 1000] = s_sizes[3] - - if nrcp == 0: - a = ax1.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - elif nrcp == 1: - a = ax2.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - elif nrcp == 2: - a = ax3.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - - west = 66 - north = 47 - south = 24 - axis_fontsize = 8 - # Set the extent - ax1.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax1.set_xticks(np.arange(70,east+1,10), cartopy.crs.PlateCarree()) - ax1.set_yticks(np.arange(30,north+1,5), cartopy.crs.PlateCarree()) - ax1.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax1.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax1.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax1.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax1.xaxis.get_ticklabels(): - label.set_visible(False) - # Set the extent - ax2.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax2.set_xticks(np.arange(70,100+1,10), cartopy.crs.PlateCarree()) - ax2.set_yticks(np.arange(30,45+1,5), cartopy.crs.PlateCarree()) - ax2.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax2.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax2.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax2.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax2.xaxis.get_ticklabels(): - label.set_visible(False) - # Set the extent - ax3.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax3.set_xticks(np.arange(70,100+1,10), cartopy.crs.PlateCarree()) - ax3.set_yticks(np.arange(30,45+1,5), cartopy.crs.PlateCarree()) - ax3.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax3.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax3.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax3.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax3.xaxis.get_ticklabels()[::2]: - label.set_visible(False) - - # Add circle size legend - circ1 = ax1.scatter([0],[0], s=s_sizes[0], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ2 = ax1.scatter([0],[0], s=s_sizes[1], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ3 = ax1.scatter([0],[0], s=s_sizes[2], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ4 = ax1.scatter([0],[0], s=s_sizes[3], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - legend=ax1.legend([circ1,circ2,circ3,circ4], ['0.001', '0.01', '0.1', '1'], - scatterpoints=1, - # scatteryoffsets=0.5, - ncol=5, loc='upper right', fontsize=leg_fontsize, - labelspacing=0.3, - columnspacing=0, - handletextpad=0, - handlelength=1, - borderpad=0.2, - framealpha=1, - title='Initial area (km$^{2}$)', - borderaxespad=0.2, - ) - legend.get_title().set_fontsize(str(leg_fontsize)) - legend.get_frame().set_linewidth(0.5) - - fig.text(0.37, 0.865, 'A', ha='center', va='center', size=12, fontweight='bold') - fig.text(0.37, 0.61, 'B', ha='center', va='center', size=12, fontweight='bold') - fig.text(0.37, 0.356, 'C', ha='center', va='center', size=12, fontweight='bold') - - # Save figure - fig_height = 14 - fig_width = 10.5 - fig.set_size_inches(fig_height,fig_width) - figure_fn = 'prec_map_' + grouping + '_multimodel_3rcps_circles.png' - fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300, transparent=True) - #%% - # ===== BOTH PRECIPITATION AND TEMPERATURE ==== - # Create the projection - fig = plt.figure() - - # Custom subplots - gs = mpl.gridspec.GridSpec(122, 101, wspace=0, hspace=0) - ax1 = plt.subplot(gs[0:40,0:46], projection=cartopy.crs.PlateCarree()) - ax2 = plt.subplot(gs[41:81,0:46], projection=cartopy.crs.PlateCarree()) - ax3 = plt.subplot(gs[82:122,0:46], projection=cartopy.crs.PlateCarree()) - ax4 = plt.subplot(gs[0:40,55:101], projection=cartopy.crs.PlateCarree()) - ax5 = plt.subplot(gs[41:81,55:101], projection=cartopy.crs.PlateCarree()) - ax6 = plt.subplot(gs[82:122,55:101], projection=cartopy.crs.PlateCarree()) - - # ===== PLOT WITH CIRCLES SIZED ACCORDING TO AREA ===== - marker_linecolor='k' - marker_linewidth=0.1 - leg_fontsize = 9 - - for group in groups: - - # Add group and attribute of interest - if grouping == 'rgi_region': - group_shp = cartopy.io.shapereader.Reader(rgiO1_shp_fn) - group_shp_attr = 'RGI_CODE' - elif grouping == 'watershed': - group_shp = cartopy.io.shapereader.Reader(watershed_shp_fn) - group_shp_attr = 'watershed' - elif grouping == 'kaab': - group_shp = cartopy.io.shapereader.Reader(kaab_shp_fn) - group_shp_attr = 'Name' - - group_fontsize = 10 - for rec in group_shp.records(): - if rec.attributes[group_shp_attr] in groups: - group = rec.attributes[group_shp_attr] - ax1.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - ax2.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - ax3.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - ax4.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - ax5.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - ax6.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='Black', linewidth=0.5, zorder=3) - - for nrcp, rcp in enumerate(['rcp26', 'rcp45', 'rcp85']): - # Add colorbar legend for peakwater - cmap_alpha=1 - cmap = mpl.cm.RdYlBu_r - if rcp == 'rcp26': - norm = plt.Normalize(0.5, 1.5) - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm._A = [] - cax1 = fig.add_axes([0.485, 0.64, 0.01, 0.18]) - cbar1 = fig.colorbar(sm, cax=cax1, orientation='vertical', alpha=cmap_alpha) - cax1.xaxis.set_ticks_position('top') - cax1.xaxis.set_tick_params(pad=0) - cbar1.ax.tick_params(labelsize=leg_fontsize) - for n, label in enumerate(cax1.xaxis.get_ticklabels()): - if n%2 != 0: - label.set_visible(False) - fig.text(0.51, 0.85, '$\Delta$ T\n($^\circ$C)', ha='center', va='center', size=leg_fontsize+1) - elif rcp == 'rcp45': - norm = plt.Normalize(2, 3) - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm._A = [] - cax1 = fig.add_axes([0.485, 0.41, 0.01, 0.18]) - cbar1 = fig.colorbar(sm, cax=cax1, orientation='vertical', alpha=cmap_alpha) - cax1.xaxis.set_ticks_position('top') - cax1.xaxis.set_tick_params(pad=0) - cbar1.ax.tick_params(labelsize=leg_fontsize) - for n, label in enumerate(cax1.xaxis.get_ticklabels()): - if n%2 != 0: - label.set_visible(False) - elif rcp == 'rcp85': - norm = plt.Normalize(5, 6) - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm._A = [] - cax1 = fig.add_axes([0.485, 0.16, 0.01, 0.18]) - cbar1 = fig.colorbar(sm, cax=cax1, orientation='vertical', alpha=cmap_alpha) - cax1.xaxis.set_ticks_position('top') - cax1.xaxis.set_tick_params(pad=0) - cbar1.ax.tick_params(labelsize=leg_fontsize) - for n, label in enumerate(cax1.xaxis.get_ticklabels()): - if n%2 != 0: - label.set_visible(False) - cmap_alpha = 1 - - # ===== PLOT WITH CIRCLES SIZED ACCORDING TO AREA ===== - # Degree TEMPERATURE - x, y, z, s = [], [], [], [] - for group in groups_deg: - vn_multimodel_mean = ds_temp_multimodel_deg[rcp][group] - vn_multimodel_mean_plot = ( - vn_multimodel_mean[90:101].mean() - vn_multimodel_mean[0:16].mean()) - x.append(deg_dict[group][0]) - y.append(deg_dict[group][1]) - z.append(vn_multimodel_mean_plot) - s.append(area_init_group[group]) - x = np.array(x) - y = np.array(y) - z = np.array(z) - s = np.array(s) - - # Size thresholds - s_sizes = [2, 4, 8, 16] - s_plot = np.array(s) - s_plot[s <= 10] = s_sizes[0] - s_plot[s > 10] = s_sizes[1] - s_plot[s > 100] = s_sizes[2] - s_plot[s > 1000] = s_sizes[3] - - if nrcp == 0: - a = ax1.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - elif nrcp == 1: - a = ax2.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - elif nrcp == 2: - a = ax3.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - - # PRECIPITATION - cmap = mpl.cm.RdYlBu - norm = plt.Normalize(0.9, 1.1) - x, y, z, s = [], [], [], [] - for group in groups_deg: - vn_multimodel_mean = ds_prec_multimodel_deg[rcp][group] - vn_multimodel_mean_plot = ( - vn_multimodel_mean[90:101].mean() / vn_multimodel_mean[0:16].mean()) - x.append(deg_dict[group][0]) - y.append(deg_dict[group][1]) - z.append(vn_multimodel_mean_plot) - s.append(area_init_group[group]) - x = np.array(x) - y = np.array(y) - z = np.array(z) - s = np.array(s) - - # Size thresholds - s_plot = np.array(s) - s_plot[s <= 10] = s_sizes[0] - s_plot[s > 10] = s_sizes[1] - s_plot[s > 100] = s_sizes[2] - s_plot[s > 1000] = s_sizes[3] - - if nrcp == 0: - a = ax4.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - elif nrcp == 1: - a = ax5.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - elif nrcp == 2: - a = ax6.scatter(x, y, c=z, cmap=cmap, norm=norm, zorder=3, s=s_plot, marker='o', - edgecolor=marker_linecolor, linewidth=marker_linewidth, alpha=cmap_alpha) - - west = 66 - north = 47 - south = 24 - axis_fontsize = 7 - # Set the extent - ax1.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax1.set_xticks(np.arange(70,east+1,10), cartopy.crs.PlateCarree()) - ax1.set_yticks(np.arange(30,north+1,5), cartopy.crs.PlateCarree()) - ax1.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax1.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax1.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax1.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax1.xaxis.get_ticklabels(): - label.set_visible(False) - # Set the extent - ax2.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax2.set_xticks(np.arange(70,100+1,10), cartopy.crs.PlateCarree()) - ax2.set_yticks(np.arange(30,45+1,5), cartopy.crs.PlateCarree()) - ax2.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax2.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax2.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax2.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax2.xaxis.get_ticklabels(): - label.set_visible(False) - # Set the extent - ax3.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax3.set_xticks(np.arange(70,100+1,10), cartopy.crs.PlateCarree()) - ax3.set_yticks(np.arange(30,45+1,5), cartopy.crs.PlateCarree()) - ax3.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax3.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax3.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax3.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) -# for label in ax3.xaxis.get_ticklabels()[::2]: -# label.set_visible(False) - - # Set the extent - ax4.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax4.set_xticks(np.arange(70,east+1,10), cartopy.crs.PlateCarree()) - ax4.set_yticks(np.arange(30,north+1,5), cartopy.crs.PlateCarree()) - ax4.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax4.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax4.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax4.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax4.xaxis.get_ticklabels(): - label.set_visible(False) - for label in ax4.yaxis.get_ticklabels(): - label.set_visible(False) - - # Set the extent - ax5.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax5.set_xticks(np.arange(70,east+1,10), cartopy.crs.PlateCarree()) - ax5.set_yticks(np.arange(30,north+1,5), cartopy.crs.PlateCarree()) - ax5.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax5.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax5.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax5.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax5.xaxis.get_ticklabels(): - label.set_visible(False) - for label in ax5.yaxis.get_ticklabels(): - label.set_visible(False) - - # Set the extent - ax6.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax6.set_xticks(np.arange(70,east+1,10), cartopy.crs.PlateCarree()) - ax6.set_yticks(np.arange(30,north+1,5), cartopy.crs.PlateCarree()) - ax6.xaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax6.yaxis.set_tick_params(pad=0, size=2, labelsize=axis_fontsize) - ax6.yaxis.set_major_formatter(EngFormatter(unit=u"°N")) - ax6.xaxis.set_major_formatter(EngFormatter(unit=u"°E")) - for label in ax6.yaxis.get_ticklabels(): - label.set_visible(False) - - # Add circle size legend - circ1 = ax1.scatter([0],[0], s=s_sizes[0], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ2 = ax1.scatter([0],[0], s=s_sizes[1], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ3 = ax1.scatter([0],[0], s=s_sizes[2], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ4 = ax1.scatter([0],[0], s=s_sizes[3], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - legend=fig.legend([circ1,circ2,circ3,circ4], ['1', '10', '100', '1000'], - scatterpoints=1, ncol=1, loc='lower right', bbox_to_anchor=(0.895,0.07), - fontsize=leg_fontsize, labelspacing=0.3, - columnspacing=0, handletextpad=0, handlelength=1, borderpad=0.2, framealpha=0, - title='Area\n(km$^{2}$)', borderaxespad=0.2) - legend.get_title().set_fontsize(str(leg_fontsize+1)) -# legend.get_frame().set_linewidth(0.5) - - - # Add colorbar legend - cmap = mpl.cm.RdYlBu - norm = plt.Normalize(0.9, 1.1) - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm._A = [] - cax4 = fig.add_axes([0.91, 0.32, 0.01, 0.49]) - cbar4 = fig.colorbar(sm, cax=cax4, orientation='vertical', alpha=cmap_alpha) - cax4.xaxis.set_ticks_position('top') - cax4.xaxis.set_tick_params(pad=0) - cbar4.ax.tick_params(labelsize=leg_fontsize) - for label in cax4.yaxis.get_ticklabels()[1::2]: - label.set_visible(False) - fig.text(0.94, 0.85, '$\Delta$ P\n(-)', ha='center', va='center', size=leg_fontsize+1) - cmap_alpha = 1 - - fig.text(0.14, 0.86, 'A', ha='center', va='center', size=12, fontweight='bold') - fig.text(0.14, 0.605, 'B', ha='center', va='center', size=12, fontweight='bold') - fig.text(0.14, 0.35, 'C', ha='center', va='center', size=12, fontweight='bold') - fig.text(0.565, 0.86, 'D', ha='center', va='center', size=12, fontweight='bold') - fig.text(0.565, 0.605, 'E', ha='center', va='center', size=12, fontweight='bold') - fig.text(0.565, 0.35, 'F', ha='center', va='center', size=12, fontweight='bold') - - # Save figure - fig_height = 7 - fig_width = 7.8 - fig.set_size_inches(fig_width,fig_height) - figure_fn = 'temp_prec_map_' + grouping + '_multimodel_3rcps_circles.png' - fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300, transparent=True) #%% if option_watersheds_colored == 1: @@ -3494,7 +2134,7 @@ def norm_shift(values, norm_value, nshift): alpha=0.2 # Load glaciers - main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(rgi_regionsO1=regions) + main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(regions) # Groups groups, group_cn = select_groups(grouping, main_glac_rgi) @@ -3523,10 +2163,6 @@ def norm_shift(values, norm_value, nshift): # Load datasets ds_fn = ('R' + str(region) + '_' + gcm_name + '_' + rcp + '_c2_ba1_100sets_2000_2100--subset.nc') ds = xr.open_dataset(netcdf_fp_cmip5 + ds_fn) - df = pd.DataFrame(ds.glacier_table.values, columns=ds.glac_attrs) - df['RGIId'] = ['RGI60-' + str(int(df.O1Region.values[x])) + '.' + - str(int(df.glacno.values[x])).zfill(5) for x in df.index.values] - # Extract time variable time_values_annual = ds.coords['year_plus1'].values time_values_monthly = ds.coords['time'].values @@ -3565,15 +2201,6 @@ def norm_shift(values, norm_value, nshift): temp_glac_all_annual = gcmbiasadj.annual_avg_2darray(temp_glac_all) prectotal_glac_all_annual = gcmbiasadj.annual_sum_2darray(prectotal_glac_all) - - # Remove RGIIds from main_glac_rgi that are not in the model runs - if ngcm == 0: - rgiid_df = list(df_all.RGIId.values) - rgiid_all = list(main_glac_rgi.RGIId.values) - rgi_idx = [rgiid_all.index(x) for x in rgiid_df] - main_glac_rgi = main_glac_rgi.loc[rgi_idx,:] - main_glac_rgi.reset_index(inplace=True, drop=True) - # Groups for ngroup, group in enumerate(groups): # Select subset of data @@ -3736,15 +2363,12 @@ def norm_shift(values, norm_value, nshift): if option_cmip5_heatmap_w_volchange == 1: - netcdf_fp_cmip5 = '/Volumes/LaCie/HMA_PyGEM/2019_0914/spc_subset/' - grouping = 'himap' + netcdf_fp_cmip5 = '/Volumes/LaCie/PyGEM_simulations/spc_subset/' vns_heatmap = ['massbaltotal_glac_monthly', 'temp_glac_monthly', 'prec_glac_monthly'] figure_fp = input.output_sim_fp + 'figures/' - if os.path.exists(figure_fp) == False: - os.makedirs(figure_fp) - rcps = ['rcp60'] + rcps = ['rcp85'] startyear=2000 endyear=2100 @@ -3763,8 +2387,7 @@ def norm_shift(values, norm_value, nshift): alpha=0.2 # Load glaciers - main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(rgi_regionsO1=regions) - + main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(regions) # Groups groups, group_cn = select_groups(grouping, main_glac_rgi) @@ -3778,83 +2401,60 @@ def norm_shift(values, norm_value, nshift): #%% # Glacier and grouped annual specific mass balance and mass change for rcp in rcps: - - if rcp == 'rcp60': - print('\nIF RCP6.0 MAKE SURE THAT ALL GCMS HAVE RCP60\n') for ngcm, gcm_name in enumerate(gcm_names): print(rcp, gcm_name) - group_glacidx = {} - vol_group_dict = {} - temp_group_dict = {} - prectotal_group_dict = {} - - # Extract data from netcdf - for region in regions: - - try: - # Load datasets - ds_fn = ('R' + str(region) + '--all--' + gcm_name + '_' + rcp + - '_c2_ba1_100sets_2000_2100--subset.nc') - ds = xr.open_dataset(netcdf_fp_cmip5 + ds_fn) - df = pd.DataFrame(ds.glacier_table.values, columns=ds.glac_attrs) - df['RGIId'] = ['RGI60-' + str(int(df.O1Region.values[x])) + '.' + - str(int(df.glacno.values[x])).zfill(5) for x in df.index.values] - skip_gcm = 0 - except: - skip_gcm = 1 - print('Skip', gcm_name, rcp, region) - - if skip_gcm == 0: - # Extract time variable - time_values_annual = ds.coords['year_plus1'].values - time_values_monthly = ds.coords['time'].values - - # Merge datasets - if region == regions[0]: - # Volume - vol_glac_all = ds['volume_glac_annual'].values[:,:,0] - vol_glac_std_all = ds['volume_glac_annual'].values[:,:,1] - # Area - area_glac_all = ds['area_glac_annual'].values[:,:,0] - area_glac_std_all = ds['area_glac_annual'].values[:,:,1] - # Mass balance - mb_glac_all = ds['massbaltotal_glac_monthly'].values[:,:,0] - mb_glac_std_all = ds['massbaltotal_glac_monthly'].values[:,:,1] - df_all = df - else: - # Volume - vol_glac_all = np.concatenate((vol_glac_all, ds['volume_glac_annual'].values[:,:,0]), axis=0) - vol_glac_std_all = np.concatenate((vol_glac_std_all, ds['volume_glac_annual'].values[:,:,1]),axis=0) - # Area - area_glac_all = np.concatenate((area_glac_all, ds['area_glac_annual'].values[:,:,0]), axis=0) - area_glac_std_all = np.concatenate((area_glac_std_all, ds['area_glac_annual'].values[:,:,1]),axis=0) - # Mass balance - mb_glac_all = np.concatenate((mb_glac_all, ds['massbaltotal_glac_monthly'].values[:,:,0]), axis=0) - mb_glac_std_all = np.concatenate((mb_glac_std_all, ds['massbaltotal_glac_monthly'].values[:,:,1]), - axis=0) - df_all = pd.concat([df_all, df], axis=0) - - ds.close() + # Climate data + temp_glac_all, prectotal_glac_all, elev_glac_all = retrieve_gcm_data(gcm_name, rcp, main_glac_rgi) + + group_glacidx = {} + vol_group_dict = {} + temp_group_dict = {} + prectotal_group_dict = {} + + # Extract data from netcdf + for region in regions: + + # Load datasets + ds_fn = ('R' + str(region) + '_' + gcm_name + '_' + rcp + '_c2_ba1_100sets_2000_2100--subset.nc') + ds = xr.open_dataset(netcdf_fp_cmip5 + ds_fn) + # Extract time variable + time_values_annual = ds.coords['year_plus1'].values + time_values_monthly = ds.coords['time'].values + # Merge datasets + if region == regions[0]: + # Volume + vol_glac_all = ds['volume_glac_annual'].values[:,:,0] + vol_glac_std_all = ds['volume_glac_annual'].values[:,:,1] + # Area + area_glac_all = ds['area_glac_annual'].values[:,:,0] + area_glac_std_all = ds['area_glac_annual'].values[:,:,1] + # Mass balance + mb_glac_all = ds['massbaltotal_glac_monthly'].values[:,:,0] + mb_glac_std_all = ds['massbaltotal_glac_monthly'].values[:,:,1] + else: + # Volume + vol_glac_all = np.concatenate((vol_glac_all, ds['volume_glac_annual'].values[:,:,0]), axis=0) + vol_glac_std_all = np.concatenate((vol_glac_std_all, ds['volume_glac_annual'].values[:,:,1]),axis=0) + # Area + area_glac_all = np.concatenate((area_glac_all, ds['area_glac_annual'].values[:,:,0]), axis=0) + area_glac_std_all = np.concatenate((area_glac_std_all, ds['area_glac_annual'].values[:,:,1]),axis=0) + # Mass balance + mb_glac_all = np.concatenate((mb_glac_all, ds['massbaltotal_glac_monthly'].values[:,:,0]), axis=0) + mb_glac_std_all = np.concatenate((mb_glac_std_all, ds['massbaltotal_glac_monthly'].values[:,:,1]), + axis=0) + + ds.close() - # Remove RGIIds from main_glac_rgi that are not in the model runs - if ngcm == 0: - rgiid_df = list(df_all.RGIId.values) - rgiid_all = list(main_glac_rgi.RGIId.values) - rgi_idx = [rgiid_all.index(x) for x in rgiid_df] - main_glac_rgi = main_glac_rgi.loc[rgi_idx,:] - main_glac_rgi.reset_index(inplace=True, drop=True) - # Annual Mass Balance mb_glac_all_annual = gcmbiasadj.annual_sum_2darray(mb_glac_all) # mask values where volume is zero mb_glac_all_annual[vol_glac_all[:,:-1] == 0] = np.nan # Annual Temperature, Precipitation, and Accumulation - temp_glac_all, prectotal_glac_all, elev_glac_all = retrieve_gcm_data(gcm_name, rcp, main_glac_rgi) temp_glac_all_annual = gcmbiasadj.annual_avg_2darray(temp_glac_all) prectotal_glac_all_annual = gcmbiasadj.annual_sum_2darray(prectotal_glac_all) @@ -3969,7 +2569,7 @@ def __call__(self, value, clip=None): for area_cutoff in area_cutoffs: # Plot the normalized volume change for each region, along with the mass balances fig, ax = plt.subplots(len(groups), len(vns_heatmap), squeeze=False, sharex=True, sharey=False, - gridspec_kw = {'wspace':0.3, 'hspace':0.15}) + gridspec_kw = {'wspace':0.3, 'hspace':0}) fig.subplots_adjust(top=0.94) for nvar, vn_heatmap in enumerate(vns_heatmap): @@ -3991,9 +2591,7 @@ def __call__(self, value, clip=None): if vn_heatmap == 'massbaltotal_glac_monthly': zmesh = mb_glac_all_annual_multimodel.mean(axis=2) var_line = (vol_group_dict_multimodel[group][:-1].mean(axis=1) / - vol_group_dict_multimodel[group][16].mean()) - if ngroup == 0: - print('\nhard coded 2015 start date\n') + vol_group_dict_multimodel[group][0].mean()) elif vn_heatmap == 'temp_glac_monthly': zmesh_raw = temp_glac_all_annual_multimodel.mean(axis=2) @@ -4020,30 +2618,20 @@ def __call__(self, value, clip=None): # plot ax[ngroup,nvar].pcolormesh(x, y, z, cmap=cmap, norm=norm, zorder=1) if nvar == 0: -# y_spacing = int((y.max()/2+20)/20)*20 -# ax[ngroup,nvar].yaxis.set_ticks(np.arange(0,y.max(),y_spacing)) - y_spacing = int(np.round((y.max() / 4)/10))*10 - y_spacing_minor = int(np.ceil(y.max()/2)) - ax[ngroup,nvar].yaxis.set_ticks(np.arange(int(y_spacing), y.max(), 2*y_spacing)) - ax[ngroup,nvar].yaxis.set_minor_locator(MultipleLocator(y_spacing_minor)) + y_spacing = int((y.max()/2+20)/20)*20 + ax[ngroup,nvar].yaxis.set_ticks(np.arange(0,y.max(),y_spacing)) else: - y_spacing = int(np.round((y.max() / 4)/10))*10 - y_spacing_minor = int(np.ceil(y.max()/2)) - ax[ngroup,nvar].yaxis.set_ticks(np.arange(int(y_spacing), y.max(), 2*y_spacing)) + y_spacing = int((y.max()/2+20)/20)*20 + ax[ngroup,nvar].yaxis.set_ticks(np.arange(0,y.max(),y_spacing)) ax[ngroup,nvar].yaxis.set_ticklabels([]) - ax[ngroup,nvar].yaxis.set_minor_locator(MultipleLocator(y_spacing_minor)) # LINE ax2_line_color ='black' - ax2_line_width = 1 + ax2_line_width = 0.5 ax2 = ax[ngroup,nvar].twinx() - if vn_heatmap in ['temp_glac_monthly', 'prec_glac_monthly']: - ax2.plot(time_values_annual[plt_idx_start:plt_idx_end], var_line[plt_idx_start:plt_idx_end], - color=ax2_line_color, linewidth=ax2_line_width, label=str(group), zorder=2) - else: - ax2.plot(time_values_annual[plt_idx_start:plt_idx_end], var_line[plt_idx_start:plt_idx_end], - color=ax2_line_color, linewidth=1.5, label=str(group), zorder=2) + ax2.plot(time_values_annual[plt_idx_start:plt_idx_end], var_line[plt_idx_start:plt_idx_end], + color=ax2_line_color, linewidth=ax2_line_width, label=str(group), zorder=2) # ax2.plot(time_values_annual[plt_idx_start:plt_idx_end], var_line[plt_idx_start:plt_idx_end], # color='gray', linewidth=1, label=str(group), zorder=2) ax2.tick_params(axis='y', colors=ax2_line_color) @@ -4051,54 +2639,66 @@ def __call__(self, value, clip=None): ax2.patch.set_visible(False) ax2.set_xlim([time_values_annual[plt_idx_start:plt_idx_end][0], time_values_annual[plt_idx_start:plt_idx_end][-1]]) - ax2.xaxis.set_ticks(np.arange(2020,2101,30)) - ax2.xaxis.set_minor_locator(MultipleLocator(10)) - if vn_heatmap == 'massbaltotal_glac_monthly': ax2.set_ylim([0,1]) ax2.yaxis.set_ticks(np.arange(0,1.05,0.5)) ax2.set_yticklabels(['', '0.5', '1']) - ax2.yaxis.set_minor_locator(MultipleLocator(0.25)) elif vn_heatmap == 'temp_glac_monthly': if rcp == 'rcp26': ax2.set_ylim([0, 2]) - ax2.yaxis.set_ticks([0.5,1.5]) - ax2.yaxis.set_minor_locator(MultipleLocator(0.5)) - elif rcp in ['rcp45', 'rcp60']: + ax2.yaxis.set_ticks([0,1,2]) + ax2.set_yticklabels(['0','1','']) + elif rcp == 'rcp45': +# ax2.set_ylim([0, 3]) + ax2.set_ylim([0, 3.75]) + ax2.yaxis.set_ticks([0,1,2,3]) + ax2.set_yticklabels(['','1','2','']) + ax2.set_yticklabels(['','1','','3']) + elif rcp == 'rcp60': ax2.set_ylim([0, 4]) - ax2.yaxis.set_ticks([1,3]) - ax2.yaxis.set_minor_locator(MultipleLocator(1)) + ax2.yaxis.set_ticks([0,1,2,3,4]) + ax2.set_yticklabels(['','1','','3','']) elif rcp == 'rcp85': ax2.set_ylim([0, 7]) - ax2.yaxis.set_ticks([2,5]) - ax2.yaxis.set_minor_locator(MultipleLocator(1)) + ax2.yaxis.set_ticks([0,2,4,6]) + ax2.set_yticklabels(['','2','','6']) elif vn_heatmap == 'prec_glac_monthly': - ax2.set_ylim([0.9, 1.3]) - ax2.yaxis.set_ticks([1,1.2]) - ax2.yaxis.set_minor_locator(MultipleLocator(0.1)) + if rcp == 'rcp26': + ax2.set_ylim([0.9, 1.15]) + ax2.yaxis.set_ticks([0.9,1,1.1]) + ax2.set_yticklabels(['','1','1.1']) + elif rcp == 'rcp45': + ax2.set_ylim([0.9, 1.25]) + ax2.yaxis.set_ticks([0.9,1,1.1,1.2]) + ax2.set_yticklabels(['','1','','1.2']) + elif rcp == 'rcp60': + ax2.set_ylim([0.9, 1.25]) + ax2.yaxis.set_ticks([0.9,1,1.1,1.2]) + ax2.set_yticklabels(['','1','','1.2']) + elif rcp == 'rcp85': + ax2.set_ylim([0.9, 1.3]) + ax2.yaxis.set_ticks([0.9,1,1.1,1.2]) + ax2.set_yticklabels(['','1','','1.2']) -# if nvar == 0: -# ax[ngroup,nvar].text(0.98,0.6, title_dict[group], horizontalalignment='right', -# transform=ax[ngroup,nvar].transAxes, size=10, zorder=3) - if nvar == 1: - ax[ngroup,nvar].text(0.5,0.6, title_dict[group], horizontalalignment='center', + if nvar == 0: + ax[ngroup,nvar].text(0.98,0.6, title_dict[group], horizontalalignment='right', transform=ax[ngroup,nvar].transAxes, size=10, zorder=3) -# # Line legend -# line = Line2D([0,1],[0,1], linestyle='-', color=ax2_line_color, linewidth=ax2_line_width) -# leg_line = [line] -# leg_label = [line_label_dict[vn_heatmap]] -# leg = fig.legend(leg_line, leg_label, loc='upper left', -# bbox_to_anchor=line_loc_dict[vn_heatmap], -# handlelength=1, handletextpad=0.5, borderpad=0, frameon=False) -# for text in leg.get_texts(): -# text.set_color(ax2_line_color) + # Line legend + line = Line2D([0,1],[0,1], linestyle='-', color=ax2_line_color, linewidth=ax2_line_width) + leg_line = [line] + leg_label = [line_label_dict[vn_heatmap]] + leg = fig.legend(leg_line, leg_label, loc='upper left', + bbox_to_anchor=line_loc_dict[vn_heatmap], + handlelength=1, handletextpad=0.5, borderpad=0, frameon=False) + for text in leg.get_texts(): + text.set_color(ax2_line_color) # Mass balance colorbar # fig.text(0.23, 1.02, 'Mass Balance\n(m w.e. yr$^{-1}$)', ha='center', va='center', size=12) - fig.text(0.23, 1.015, 'Mass Balance\n', ha='center', va='center', size=12) - fig.text(0.23, 1.005, '(m w.e. yr$^{-1}$)', ha='center', va='center', size=10) + fig.text(0.23, 1.02, 'Mass Balance\n', ha='center', va='center', size=12) + fig.text(0.23, 1.015, '(m w.e. yr$^{-1}$)', ha='center', va='center', size=10) cmap=cmap_dict['massbaltotal_glac_monthly'] # norm=norm_dict['massbaltotal_glac_monthly'] # norm = MidpointNormalize(midpoint=0, vmin=-2, vmax=1) @@ -4107,7 +2707,7 @@ def __call__(self, value, clip=None): vmax=norm_dict['massbaltotal_glac_monthly'][rcp][2]) sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) sm._A = [] - cax = plt.axes([0.125, 0.95, 0.215, 0.015]) + cax = plt.axes([0.125, 0.96, 0.215, 0.015]) plt.colorbar(sm, cax=cax, orientation='horizontal') cax.xaxis.set_ticks_position('top') for n, label in enumerate(cax.xaxis.get_ticklabels()): @@ -4116,8 +2716,8 @@ def __call__(self, value, clip=None): # Temperature colorbar # fig.text(0.51, 1.02, '$\Delta$ Temperature\n($^\circ$C)', ha='center', va='center', size=12) - fig.text(0.51, 1.025, '$\Delta$ Temperature', ha='center', va='center', size=12) - fig.text(0.51, 1.005, '($^\circ$C)', ha='center', va='center', size=10) + fig.text(0.51, 1.0325, '$\Delta$ Temperature', ha='center', va='center', size=12) + fig.text(0.51, 1.015, '($^\circ$C)', ha='center', va='center', size=10) cmap=cmap_dict['temp_glac_monthly'] # norm=norm_dict['temp_glac_monthly'] norm = MidpointNormalize(midpoint=norm_dict['temp_glac_monthly'][rcp][1], @@ -4125,7 +2725,7 @@ def __call__(self, value, clip=None): vmax=norm_dict['temp_glac_monthly'][rcp][2]) sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) sm._A = [] - cax = plt.axes([0.405, 0.95, 0.215, 0.015]) + cax = plt.axes([0.405, 0.96, 0.215, 0.015]) plt.colorbar(sm, cax=cax, orientation='horizontal') cax.xaxis.set_ticks_position('top') for n, label in enumerate(cax.xaxis.get_ticklabels()): @@ -4134,8 +2734,8 @@ def __call__(self, value, clip=None): # Precipitation colorbar # fig.text(0.79, 1.02, '$\Delta$ Precipitation\n(-)', ha='center', va='center', size=12) - fig.text(0.79, 1.025, '$\Delta$ Precipitation', ha='center', va='center', size=12) - fig.text(0.79, 1.005, '(-)', ha='center', va='center', size=10) + fig.text(0.79, 1.0325, '$\Delta$ Precipitation', ha='center', va='center', size=12) + fig.text(0.79, 1.015, '(-)', ha='center', va='center', size=10) cmap=cmap_dict['prec_glac_monthly'] # norm=norm_dict['prec_glac_monthly'] norm = MidpointNormalize(midpoint=norm_dict['prec_glac_monthly'][rcp][1], @@ -4143,7 +2743,7 @@ def __call__(self, value, clip=None): vmax=norm_dict['prec_glac_monthly'][rcp][2]) sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) sm._A = [] - cax = plt.axes([0.685, 0.95, 0.215, 0.015]) + cax = plt.axes([0.685, 0.96, 0.215, 0.015]) plt.colorbar(sm, cax=cax, orientation='horizontal', format='%.2f') cax.xaxis.set_ticks_position('top') for n, label in enumerate(cax.xaxis.get_ticklabels()): @@ -4151,7 +2751,7 @@ def __call__(self, value, clip=None): label.set_visible(False) # Label y-axis - fig.text(0.03, 0.5, 'Glacier Number', + fig.text(0.03, 0.5, 'Glacier Number (only glaciers greater than ' + str(area_cutoff) + 'km$^2$)', va='center', ha='center', rotation='vertical', size=12) # Save figure @@ -4300,7 +2900,7 @@ def __call__(self, value, clip=None): #%% TIME SERIES OF SUBPLOTS FOR EACH GROUP if option_plot_cmip5_normalizedchange == 1: - netcdf_fp_cmip5 = '/Volumes/LaCie/HMA_PyGEM/2019_0914/spc_subset/' + netcdf_fp_cmip5 = '/Volumes/LaCie/PyGEM_simulations/spc_subset/' vn = 'volume_glac_annual' # vn = 'runoff_glac_monthly' @@ -4315,41 +2915,21 @@ def __call__(self, value, clip=None): startyear = 2015 endyear = 2100 - figure_fp = netcdf_fp_cmip5 + 'figures/' - runoff_fn_pkl = figure_fp + 'watershed_runoff_annual_22gcms_4rcps-' + grouping + '.pkl' - vol_fn_pkl = figure_fp + 'regional_vol_annual_22gcms_4rcps-' + grouping + '.pkl' + figure_fp = input.output_sim_fp + 'figures/' + runoff_fn_pkl = figure_fp + 'watershed_runoff_annual_22gcms_4rcps.pkl' option_plot_individual_gcms = 0 - if os.path.exists(figure_fp) == False: - os.makedirs(figure_fp) - # Load glaciers - main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(rgi_regionsO1=regions) - + main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(regions) # Groups groups, group_cn = select_groups(grouping, main_glac_rgi) - - if grouping in ['rgi_region']: - groups.append('all') - #%% # Load data if vn == 'runoff_glac_monthly' and os.path.isfile(runoff_fn_pkl): with open(runoff_fn_pkl, 'rb') as f: ds_all = pickle.load(f) # Load single GCM to get time values needed for plot - ds_fn = ('R' + str(regions[0]) + '--all--' + gcm_names[0] + '_' + rcps[0] + - '_c2_ba1_100sets_2000_2100--subset.nc') - ds = xr.open_dataset(netcdf_fp_cmip5 + ds_fn) - # Extract time variable - time_values_annual = ds.coords['year_plus1'].values - time_values_monthly = ds.coords['time'].values - elif vn == 'volume_glac_annual' and os.path.isfile(vol_fn_pkl): - with open(vol_fn_pkl, 'rb') as f: - ds_all = pickle.load(f) - # Load single GCM to get time values needed for plot - ds_fn = ('R' + str(regions[0]) + '--all--' + gcm_names[0] + '_' + rcps[0] + - '_c2_ba1_100sets_2000_2100--subset.nc') + ds_fn = 'R' + str(regions[0]) + '_' + gcm_names[0] + '_' + rcps[0] + '_c2_ba1_100sets_2000_2100--subset.nc' ds = xr.open_dataset(netcdf_fp_cmip5 + ds_fn) # Extract time variable time_values_annual = ds.coords['year_plus1'].values @@ -4369,19 +2949,14 @@ def __call__(self, value, clip=None): print(rcp, gcm_name) # Merge all data, then select group data - for region in regions: - print(region) + for region in regions: # Load datasets - ds_fn = ('R' + str(region) + '--all--' + gcm_name + '_' + rcp + - '_c2_ba1_100sets_2000_2100--subset.nc') + ds_fn = ('R' + str(region) + '_' + gcm_name + '_' + rcp + '_c2_ba1_100sets_2000_2100--subset.nc') # Bypass GCMs that are missing a rcp scenario try: ds = xr.open_dataset(netcdf_fp_cmip5 + ds_fn) - df = pd.DataFrame(ds.glacier_table.values, columns=ds.glac_attrs) - df['RGIId'] = ['RGI60-' + str(int(df.O1Region.values[x])) + '.' + - str(int(df.glacno.values[x])).zfill(5) for x in df.index.values] skip_gcm = 0 except: skip_gcm = 1 @@ -4409,45 +2984,23 @@ def __call__(self, value, clip=None): # Merge datasets if region == regions[0]: vn_glac_all = vn_glac_region - vn_glac_std_all = vn_glac_std_region - df_all = df + vn_glac_std_all = vn_glac_std_region else: vn_glac_all = np.concatenate((vn_glac_all, vn_glac_region), axis=0) vn_glac_std_all = np.concatenate((vn_glac_std_all, vn_glac_std_region), axis=0) - df_all = pd.concat([df_all, df], axis=0) ds.close() - - - # Remove RGIIds from main_glac_rgi that are not in the model runs - if ngcm == 0: - rgiid_df = list(df_all.RGIId.values) - rgiid_all = list(main_glac_rgi.RGIId.values) - rgi_idx = [rgiid_all.index(x) for x in rgiid_df] - main_glac_rgi = main_glac_rgi.loc[rgi_idx,:] - main_glac_rgi.reset_index(inplace=True, drop=True) - - + if skip_gcm == 0: for ngroup, group in enumerate(groups): # Select subset of data - if group in ['all']: - group_glac_indices = ( - main_glac_rgi.loc[main_glac_rgi['all_group'] == group].index.values.tolist()) - else: - group_glac_indices = ( - main_glac_rgi.loc[main_glac_rgi[group_cn] == group].index.values.tolist()) + group_glac_indices = main_glac_rgi.loc[main_glac_rgi[group_cn] == group].index.values.tolist() vn_glac = vn_glac_all[group_glac_indices,:] subgroups, subgroup_cn = select_groups(subgrouping, main_glac_rgi) # Sum volume change for group - if group in ['all']: - group_glac_indices = ( - main_glac_rgi.loc[main_glac_rgi['all_group'] == group].index.values.tolist()) - else: - group_glac_indices = ( - main_glac_rgi.loc[main_glac_rgi[group_cn] == group].index.values.tolist()) + group_glac_indices = main_glac_rgi.loc[main_glac_rgi[group_cn] == group].index.values.tolist() vn_group = vn_glac_all[group_glac_indices,:].sum(axis=0) # area_group = area_glac_all[group_glac_indices,:].sum(axis=0) @@ -4472,8 +3025,6 @@ def __call__(self, value, clip=None): if vn == 'runoff_glac_monthly': pickle_data(runoff_fn_pkl, ds_all) - elif vn == 'volume_glac_annual': - pickle_data(vol_fn_pkl, ds_all) #%% # Select multimodel data @@ -4515,7 +3066,6 @@ def __call__(self, value, clip=None): groups = [x for _,x in sorted(zip(group_order,groups))] #%% - # ===== PLOT THE NORMALIZED CHANGE AS SUBPLOTS ===== multimodel_linewidth = 2 alpha=0.2 @@ -4530,10 +3080,6 @@ def __call__(self, value, clip=None): fig, ax = plt.subplots(num_rows, num_cols, squeeze=False, sharex=False, sharey=True, gridspec_kw = {'wspace':0, 'hspace':0}) - if vn == 'volume_glac_annual': - stats_cns = ['group', 'rcp', 'Gt_init', '% remaining', '% remaining_std', 'mb_gt_loss', 'mb_gt_loss_std'] - output_df = pd.DataFrame(np.zeros((len(groups)*4, len(stats_cns))), columns=stats_cns) - ncount = 0 # Cycle through groups row_idx = 0 col_idx = 0 @@ -4555,9 +3101,7 @@ def __call__(self, value, clip=None): # Normalize volume by initial volume if vn == 'volume_glac_annual': -# vn_normalizer = vn_multimodel_mean[0] - tnorm_idx = np.where(time_values_annual == 2006)[0][0] - vn_normalizer = vn_multimodel_mean[tnorm_idx] + vn_normalizer = vn_multimodel_mean[0] # Normalize runoff by mean runoff from 2000-2015 elif vn == 'runoff_glac_monthly': t1_idx = np.where(time_values_annual == 2000)[0][0] @@ -4574,17 +3118,16 @@ def __call__(self, value, clip=None): ax[row_idx, col_idx].plot( time_values_annual[t1_idx:t2_idx], vn_multimodel_mean_norm[t1_idx:t2_idx], color=rcp_colordict[rcp], linewidth=multimodel_linewidth, label=rcp, zorder=4) - if len(rcps) == 4 and rcp in ['rcp26', 'rcp85']: - ax[row_idx, col_idx].plot( - time_values_annual[t1_idx:t2_idx], vn_multimodel_stdlow_norm[t1_idx:t2_idx], - color=rcp_colordict[rcp], linewidth=0.25, linestyle='-', label=rcp, zorder=3) - ax[row_idx, col_idx].plot( - time_values_annual[t1_idx:t2_idx], vn_multimodel_stdhigh_norm[t1_idx:t2_idx], - color=rcp_colordict[rcp], linewidth=0.25, linestyle='-', label=rcp, zorder=3) - ax[row_idx, col_idx].fill_between( - time_values_annual[t1_idx:t2_idx], vn_multimodel_stdlow_norm[t1_idx:t2_idx], - vn_multimodel_stdhigh_norm[t1_idx:t2_idx], - facecolor=rcp_colordict[rcp], alpha=0.2, label=None, zorder=2) + ax[row_idx, col_idx].plot( + time_values_annual[t1_idx:t2_idx], vn_multimodel_stdlow_norm[t1_idx:t2_idx], + color=rcp_colordict[rcp], linewidth=0.25, linestyle='-', label=rcp, zorder=3) + ax[row_idx, col_idx].plot( + time_values_annual[t1_idx:t2_idx], vn_multimodel_stdhigh_norm[t1_idx:t2_idx], + color=rcp_colordict[rcp], linewidth=0.25, linestyle='-', label=rcp, zorder=3) + ax[row_idx, col_idx].fill_between( + time_values_annual[t1_idx:t2_idx], vn_multimodel_stdlow_norm[t1_idx:t2_idx], + vn_multimodel_stdhigh_norm[t1_idx:t2_idx], + facecolor=rcp_colordict[rcp], alpha=0.2, label=None, zorder=2) # Group labels if vn == 'volume_glac_annual': @@ -4634,12 +3177,11 @@ def __call__(self, value, clip=None): plot_str = '' if vn == 'volume_glac_annual' and rcp == rcps[-1]: volume_str = str(int(np.round(vn_multimodel_mean[0] * input.density_ice / input.density_water, 0))) - plot_str = volume_str + plot_str = '(' + volume_str + ' Gt)' if grouping == 'himap': - plot_str_loc = 0.05 + plot_str_loc = 0.83 else: plot_str_loc = 0.9 - elif vn == 'runoff_glac_monthly' and rcp == rcps[-1]: group_glac_indices = main_glac_rgi.loc[main_glac_rgi[group_cn] == group].index.values.tolist() group_volume_Gt = ((main_glac_hyps.values[group_glac_indices,:] * @@ -4650,13 +3192,13 @@ def __call__(self, value, clip=None): plot_str_loc = 0.90 if rcp == rcps[-1]: - if grouping in ['all', 'rgi_region', 'kaab']: - ax[row_idx, col_idx].text(0.5, 0.9, plot_str, size=10, horizontalalignment='center', + if grouping == 'all': + ax[row_idx, col_idx].text(0.5, 0.93, plot_str, size=10, horizontalalignment='center', verticalalignment='top', transform=ax[row_idx, col_idx].transAxes, color='k', zorder=5) else: - ax[row_idx, col_idx].text(0.05, plot_str_loc, plot_str, size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[row_idx, col_idx].transAxes, + ax[row_idx, col_idx].text(0.5, plot_str_loc, plot_str, size=10, horizontalalignment='center', + verticalalignment='top', transform=ax[row_idx, col_idx].transAxes, color='k', zorder=5) # Print relevant information @@ -4665,21 +3207,6 @@ def __call__(self, value, clip=None): np.round((1-vn_multimodel_mean_norm[-1]) * np.round(vn_multimodel_mean[0] * input.density_ice / input.density_water,0),0), '+/-', np.round(vn_multimodel_std[-1]*input.density_ice/input.density_water,0), 'Gt total loss') - - if vn == 'volume_glac_annual': - output_df.loc[ncount,:] = ( - [group, rcp, - vn_multimodel_mean[0] * input.density_ice / input.density_water, - vn_multimodel_mean_norm[-1]*100, - vn_multimodel_std_norm[-1]*100, - (1-vn_multimodel_mean_norm[-1]) * vn_multimodel_mean[tnorm_idx] * input.density_ice - / input.density_water, - vn_multimodel_std[-1]*input.density_ice/input.density_water]) - ncount += 1 - - if grouping == 'rgi_region': - print(' HH2015 comparison 2010-2100, vol loss [%]:', - np.round((vn_multimodel_mean[-1] - vn_multimodel_mean[10]) / vn_multimodel_mean[10] * 100,0)) # Count column index to plot @@ -4695,22 +3222,21 @@ def __call__(self, value, clip=None): # RCP Legend rcp_lines = [] - rcp_number_dict = {'rcp26':' (22 GCMs)','rcp45':' (22 GCMs)','rcp60':' (15 GCMs)','rcp85':' (22 GCMs)',} for rcp in rcps: line = Line2D([0,1],[0,1], color=rcp_colordict[rcp], linewidth=multimodel_linewidth) rcp_lines.append(line) - rcp_labels = ['RCP ' + rcp_dict[rcp] + rcp_number_dict[rcp] for rcp in rcps] -# line = Line2D([0,1],[0,1], color='grey', linewidth=multimodel_linewidth) -# rcp_lines.append(line) -# rcp_labels.append('multi-model\nmean') -# line = Line2D([0,1],[0,1], color='grey', linewidth=4*multimodel_linewidth, alpha=0.2) -# rcp_lines.append(line) -# rcp_labels.append('multi-model\nstandard deviation') -# line = Line2D([0,1],[0,1], color='none', linewidth=multimodel_linewidth) -# rcp_lines.append(line) -# rcp_labels.append('') - fig.legend(rcp_lines, rcp_labels, loc=(0.6, 0.075), fontsize=10, labelspacing=0.1, handlelength=1, - handletextpad=0.5, borderpad=0, frameon=False, ncol=1) + rcp_labels = ['RCP ' + rcp_dict[rcp] for rcp in rcps] + line = Line2D([0,1],[0,1], color='grey', linewidth=multimodel_linewidth) + rcp_lines.append(line) + rcp_labels.append('multi-model\nmean') + line = Line2D([0,1],[0,1], color='grey', linewidth=4*multimodel_linewidth, alpha=0.2) + rcp_lines.append(line) + rcp_labels.append('multi-model\nstandard deviation') + line = Line2D([0,1],[0,1], color='none', linewidth=multimodel_linewidth) + rcp_lines.append(line) + rcp_labels.append('') + fig.legend(rcp_lines, rcp_labels, loc=(0.575,0.065), fontsize=10, labelspacing=0.1, handlelength=1, + handletextpad=0.5, borderpad=0, frameon=False, ncol=2) else: # RCP Legend rcp_lines = [] @@ -4724,16 +3250,15 @@ def __call__(self, value, clip=None): legend_loc = 'lower left' ax[0,0].legend(rcp_lines, rcp_labels, loc=(0.05,0.01), fontsize=10, labelspacing=0, handlelength=1, handletextpad=0.25, borderpad=0, frameon=False, ncol=1) -# if grouping != 'all': -# # RCP Legend -# rcp_lines = [] -# line = Line2D([0,1],[0,1], color='grey', linewidth=multimodel_linewidth) -# rcp_lines.append(line) -# line = Line2D([0,1],[0,1], color='grey', linewidth=4*multimodel_linewidth, alpha=0.2) -# rcp_lines.append(line) -# rcp_labels = ['multi-model\nmean', 'multi-model\nstandard deviation'] -# ax[0,1].legend(rcp_lines, rcp_labels, loc=(0.05,0.01), fontsize=8, labelspacing=0.2, handlelength=1, -# handletextpad=0.6, borderpad=0, frameon=False, ncol=1) + # RCP Legend + rcp_lines = [] + line = Line2D([0,1],[0,1], color='grey', linewidth=multimodel_linewidth) + rcp_lines.append(line) + line = Line2D([0,1],[0,1], color='grey', linewidth=4*multimodel_linewidth, alpha=0.2) + rcp_lines.append(line) + rcp_labels = ['multi-model\nmean', 'multi-model\nstandard deviation'] + ax[0,1].legend(rcp_lines, rcp_labels, loc=(0.05,0.01), fontsize=8, labelspacing=0.2, handlelength=1, + handletextpad=0.6, borderpad=0, frameon=False, ncol=1) # Label if vn == 'runoff_glac_monthly': @@ -4759,228 +3284,207 @@ def __call__(self, value, clip=None): figure_fn = grouping + '_' + vn + '_multimodel_' + str(len(rcps)) + 'rcps.png' fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300, transparent=True) - - if vn == 'volume_glac_annual': - output_df.to_csv(figure_fp + grouping + '_' + vn + '_multimodel_' + str(len(rcps)) + 'rcps_stats.csv', - index=False) #%% - # ===== RUNOFF PLOT OF NORMALIZED CHANGE WITH SUBPLOTS AROUND A MAP ===== - if vn == 'runoff_glac_monthly': - # External subplots - multimodel_linewidth = 2 - alpha=0.2 - year_start_peakwater = 2015 - year_idx_start = np.where(time_values_annual == year_start_peakwater)[0][0] - - group_colordict = {'Amu_Darya': 'mediumblue', - 'Brahmaputra': 'salmon', - 'Ganges': 'lightskyblue', - 'Ili': 'royalblue', - 'Indus': 'darkred', - 'Inner_Tibetan_Plateau': 'gold', - 'Inner_Tibetan_Plateau_extended': 'navy', - 'Irrawaddy': 'white', - 'Mekong': 'white', - 'Salween': 'plum', - 'Syr_Darya':'darkolivegreen', - 'Tarim': 'olive', - 'Yangtze': 'orange', - 'Yellow':'white'} - group_rowcol_idx = {'Amu_Darya': [1,0], - 'Brahmaputra': [3,1], - 'Ganges': [3,0], - 'Ili': [0,2], - 'Indus': [2,0], - 'Inner_Tibetan_Plateau': [1,3], - 'Inner_Tibetan_Plateau_extended': [0,3], - 'Irrawaddy': [0,0], - 'Mekong': [0,0], - 'Salween': [3,2], - 'Syr_Darya':[0,0], - 'Tarim': [0,1], - 'Yangtze': [2,3], - 'Yellow':[0,0]} - - # Cycle through groups - if 'Mekong' in groups: - groups.remove('Mekong') - - fig, ax = plt.subplots(4, 4, squeeze=False, sharex=False, sharey=False, - gridspec_kw = {'wspace':0.25, 'hspace':0.25}) - - for ngroup, group in enumerate(groups): - # for ngroup, group in enumerate(['Amu_Darya']): - row_idx = group_rowcol_idx[group][0] - col_idx = group_rowcol_idx[group][1] - - for rcp in rcps: - - # ===== Plot ===== - # Multi-model statistics - vn_multimodel = ds_multimodel[rcp][group] - vn_multimodel_mean = vn_multimodel.mean(axis=0) - vn_multimodel_std = vn_multimodel.std(axis=0) - vn_multimodel_stdlow = vn_multimodel_mean - vn_multimodel_std - vn_multimodel_stdhigh = vn_multimodel_mean + vn_multimodel_std - - # Normalize volume by initial volume - if vn == 'volume_glac_annual': - vn_normalizer = vn_multimodel_mean[0] - # Normalize runoff by mean runoff from 2000-2015 - elif vn == 'runoff_glac_monthly': - t1_idx = np.where(time_values_annual == 2000)[0][0] - t2_idx = np.where(time_values_annual == 2015)[0][0] + 1 - vn_normalizer = vn_multimodel.mean(axis=0)[t1_idx:t2_idx].mean() - vn_multimodel_mean_norm = vn_multimodel_mean / vn_normalizer - vn_multimodel_std_norm = vn_multimodel_std / vn_normalizer - vn_multimodel_stdlow_norm = vn_multimodel_mean_norm - vn_multimodel_std_norm - vn_multimodel_stdhigh_norm = vn_multimodel_mean_norm + vn_multimodel_std_norm - - t1_idx = np.where(time_values_annual == startyear)[0][0] - t2_idx = np.where(time_values_annual == endyear)[0][0] + 1 - - ax[row_idx, col_idx].plot( - time_values_annual[t1_idx:t2_idx], vn_multimodel_mean_norm[t1_idx:t2_idx], - color=rcp_colordict[rcp], linewidth=multimodel_linewidth, label=rcp, zorder=4) - if len(rcps) == 4 and rcp in ['rcp26', 'rcp85']: - ax[row_idx, col_idx].plot( - time_values_annual[t1_idx:t2_idx], vn_multimodel_stdlow_norm[t1_idx:t2_idx], - color=rcp_colordict[rcp], linewidth=0.25, linestyle='-', label=rcp, zorder=3) - ax[row_idx, col_idx].plot( - time_values_annual[t1_idx:t2_idx], vn_multimodel_stdhigh_norm[t1_idx:t2_idx], - color=rcp_colordict[rcp], linewidth=0.25, linestyle='-', label=rcp, zorder=3) - ax[row_idx, col_idx].fill_between( - time_values_annual[t1_idx:t2_idx], vn_multimodel_stdlow_norm[t1_idx:t2_idx], - vn_multimodel_stdhigh_norm[t1_idx:t2_idx], - facecolor=rcp_colordict[rcp], alpha=0.2, label=None, zorder=2) - - # Peakwater stats on plots (lower left: peakwater and increase, lower right: change by end of century) - group_peakwater = peakwater(vn_multimodel_mean[year_idx_start:], - time_values_annual[year_idx_start:-1], nyears) - - # Add value to subplot - plot_str = '' - if vn == 'volume_glac_annual' and rcp == rcps[-1]: - volume_str = str(int(np.round(vn_multimodel_mean[0] * input.density_ice / input.density_water, 0))) - plot_str = '(' + volume_str + ' Gt)' - plot_str_loc = 0.83 - elif vn == 'runoff_glac_monthly' and rcp == rcps[-1]: - group_glac_indices = main_glac_rgi.loc[main_glac_rgi[group_cn] == group].index.values.tolist() - group_volume_Gt = ((main_glac_hyps.values[group_glac_indices,:] * - main_glac_icethickness.values[group_glac_indices,:] / 1000 * input.density_ice / - input.density_water).sum()) - group_runoff_Gta = ds_multimodel[rcp][group].mean(axis=0)[:15].mean() * (1/1000)**3 -# plot_str = str(int(np.round(group_runoff_Gta,0))) + ' Gt $\mathregular{yr^{-1}}$' - plot_str = str(np.round(group_runoff_Gta,1)) + ' Gt $\mathregular{yr^{-1}}$' - plot_str = str(np.round(group_runoff_Gta,1)) - plot_str_loc = 0.90 - - print(rcp, group, group_peakwater[0]) - ax[row_idx,col_idx].plot((group_peakwater[0], group_peakwater[0]), (0, 1+group_peakwater[1]/100), - color=rcp_colordict[rcp], linewidth=1, linestyle='--', zorder=5) - - # Group labels - group_labelsize = 10 - tick_labelsize = 9 - title_dict['Salween'] = 'Salween (Sw)' - title_dict['Yangtze'] = 'Yangtze (Yz)' - ax[row_idx, col_idx].text(0.5, 0.99, title_dict[group], size=group_labelsize, color='black', - horizontalalignment='center', verticalalignment='top', - transform=ax[row_idx, col_idx].transAxes, zorder=10) + # External subplots + multimodel_linewidth = 2 + alpha=0.2 - # X-label - ax[row_idx, col_idx].set_xlim(time_values_annual[t1_idx:t2_idx].min(), - time_values_annual[t1_idx:t2_idx].max()) - ax[row_idx, col_idx].xaxis.set_tick_params(pad=2, size=4, labelsize=tick_labelsize) - ax[row_idx, col_idx].xaxis.set_minor_locator(plt.MultipleLocator(10)) - ax[row_idx, col_idx].set_xticks([2020,2050,2080]) - - # Y-label + group_colordict = {'Amu_Darya': 'mediumblue', + 'Brahmaputra': 'salmon', + 'Ganges': 'lightskyblue', + 'Ili': 'royalblue', + 'Indus': 'darkred', + 'Inner_Tibetan_Plateau': 'gold', + 'Inner_Tibetan_Plateau_extended': 'navy', + 'Irrawaddy': 'white', + 'Mekong': 'white', + 'Salween': 'plum', + 'Syr_Darya':'darkolivegreen', + 'Tarim': 'olive', + 'Yangtze': 'orange', + 'Yellow':'white'} + group_rowcol_idx = {'Amu_Darya': [1,0], + 'Brahmaputra': [3,1], + 'Ganges': [3,0], + 'Ili': [0,2], + 'Indus': [2,0], + 'Inner_Tibetan_Plateau': [1,3], + 'Inner_Tibetan_Plateau_extended': [0,3], + 'Irrawaddy': [0,0], + 'Mekong': [0,0], + 'Salween': [3,2], + 'Syr_Darya':[0,0], + 'Tarim': [0,1], + 'Yangtze': [2,3], + 'Yellow':[0,0]} + + # Cycle through groups + if 'Mekong' in groups: + groups.remove('Mekong') + + fig, ax = plt.subplots(4, 4, squeeze=False, sharex=False, sharey=False, + gridspec_kw = {'wspace':0.25, 'hspace':0.25}) + + for ngroup, group in enumerate(groups): +# for ngroup, group in enumerate(['Amu_Darya']): + row_idx = group_rowcol_idx[group][0] + col_idx = group_rowcol_idx[group][1] + + for rcp in rcps: + + # ===== Plot ===== + # Multi-model statistics + vn_multimodel = ds_multimodel[rcp][group] + vn_multimodel_mean = vn_multimodel.mean(axis=0) + vn_multimodel_std = vn_multimodel.std(axis=0) + vn_multimodel_stdlow = vn_multimodel_mean - vn_multimodel_std + vn_multimodel_stdhigh = vn_multimodel_mean + vn_multimodel_std - if vn == 'runoff_glac_monthly': - ylabel_str = 'Runoff (-)' - ax[row_idx, col_idx].set_ylim(0,2.2) - ax[row_idx, col_idx].yaxis.set_minor_locator(plt.MultipleLocator(0.1)) - ax[row_idx, col_idx].set_yticks([0.5,1,1.5,2]) - ax[row_idx, col_idx].set_yticklabels(['0.5','1.0','1.5','2.0']) - ax[row_idx, col_idx].yaxis.set_tick_params(pad=0, size=4, labelsize=tick_labelsize) - elif vn == 'volume_glac_annual': - ylabel_str = 'Mass (-)' - ax[row_idx, col_idx].set_ylim(0, 1.15) - if option_plot_individual_gcms == 1: - ax[row_idx, col_idx].set_ylim(0,1.35) - ax[row_idx, col_idx].yaxis.set_major_locator(plt.MultipleLocator(0.5)) - ax[row_idx, col_idx].yaxis.set_minor_locator(plt.MultipleLocator(0.1)) - ax[row_idx, col_idx].set_yticklabels(['','','0.5','1.0',]) - ax[row_idx, col_idx].yaxis.set_ticks_position('both') - ax[row_idx, col_idx].tick_params(axis='both', which='major', labelsize=tick_labelsize, direction='inout') - ax[row_idx, col_idx].tick_params(axis='both', which='minor', labelsize=tick_labelsize, direction='inout') - - # Mean annual runoff - ax[row_idx, col_idx].text(0.99, 0.0, plot_str, size=9, horizontalalignment='right', - verticalalignment='bottom', transform=ax[row_idx, col_idx].transAxes, - color='k', zorder=6) - - # Label + # Normalize volume by initial volume + if vn == 'volume_glac_annual': + vn_normalizer = vn_multimodel_mean[0] + # Normalize runoff by mean runoff from 2000-2015 + elif vn == 'runoff_glac_monthly': + t1_idx = np.where(time_values_annual == 2000)[0][0] + t2_idx = np.where(time_values_annual == 2015)[0][0] + 1 + vn_normalizer = vn_multimodel.mean(axis=0)[t1_idx:t2_idx].mean() + vn_multimodel_mean_norm = vn_multimodel_mean / vn_normalizer + vn_multimodel_std_norm = vn_multimodel_std / vn_normalizer + vn_multimodel_stdlow_norm = vn_multimodel_mean_norm - vn_multimodel_std_norm + vn_multimodel_stdhigh_norm = vn_multimodel_mean_norm + vn_multimodel_std_norm + + t1_idx = np.where(time_values_annual == startyear)[0][0] + t2_idx = np.where(time_values_annual == endyear)[0][0] + 1 + + ax[row_idx, col_idx].plot( + time_values_annual[t1_idx:t2_idx], vn_multimodel_mean_norm[t1_idx:t2_idx], color=rcp_colordict[rcp], + linewidth=multimodel_linewidth, label=rcp, zorder=4) + ax[row_idx, col_idx].plot( + time_values_annual[t1_idx:t2_idx], vn_multimodel_stdlow_norm[t1_idx:t2_idx], + color=rcp_colordict[rcp], linewidth=0.25, linestyle='-', label=rcp, zorder=3) + ax[row_idx, col_idx].plot( + time_values_annual[t1_idx:t2_idx], vn_multimodel_stdhigh_norm[t1_idx:t2_idx], + color=rcp_colordict[rcp], linewidth=0.25, linestyle='-', label=rcp, zorder=3) + ax[row_idx, col_idx].fill_between( + time_values_annual[t1_idx:t2_idx], vn_multimodel_stdlow_norm[t1_idx:t2_idx], + vn_multimodel_stdhigh_norm[t1_idx:t2_idx], + facecolor=rcp_colordict[rcp], alpha=0.2, label=None, zorder=2) + + # Peakwater stats on plots (lower left: peakwater and increase, lower right: change by end of century) + group_peakwater = peakwater(vn_multimodel_mean, time_values_annual[:-1], nyears) + + # Add value to subplot + plot_str = '' + if vn == 'volume_glac_annual' and rcp == rcps[-1]: + volume_str = str(int(np.round(vn_multimodel_mean[0] * input.density_ice / input.density_water, 0))) + plot_str = '(' + volume_str + ' Gt)' + plot_str_loc = 0.83 + elif vn == 'runoff_glac_monthly' and rcp == rcps[-1]: + group_glac_indices = main_glac_rgi.loc[main_glac_rgi[group_cn] == group].index.values.tolist() + group_volume_Gt = ((main_glac_hyps.values[group_glac_indices,:] * + main_glac_icethickness.values[group_glac_indices,:] / 1000 * input.density_ice / + input.density_water).sum()) + group_runoff_Gta = ds_multimodel[rcp][group].mean(axis=0)[:15].mean() * (1/1000)**3 + plot_str = str(int(np.round(group_runoff_Gta,0))) + ' Gt $\mathregular{yr^{-1}}$' + plot_str_loc = 0.90 + +# print(rcp, group_peakwater[0]) + ax[row_idx,col_idx].plot((group_peakwater[0], group_peakwater[0]), (0, 1+group_peakwater[1]/100), + color=rcp_colordict[rcp], linewidth=1, linestyle='--', zorder=5) + + # Group labels + group_labelsize = 10 + tick_labelsize = 9 + title_dict['Salween'] = 'Salween (Sw)' + title_dict['Yangtze'] = 'Yangtze (Yz)' + ax[row_idx, col_idx].text(0.5, 0.99, title_dict[group], size=group_labelsize, color='black', + horizontalalignment='center', verticalalignment='top', + transform=ax[row_idx, col_idx].transAxes, zorder=10) + + # X-label + ax[row_idx, col_idx].set_xlim(time_values_annual[t1_idx:t2_idx].min(), + time_values_annual[t1_idx:t2_idx].max()) + ax[row_idx, col_idx].xaxis.set_tick_params(pad=2, size=4, labelsize=tick_labelsize) + ax[row_idx, col_idx].xaxis.set_minor_locator(plt.MultipleLocator(10)) + ax[row_idx, col_idx].set_xticks([2020,2050,2080]) + + # Y-label + if vn == 'runoff_glac_monthly': ylabel_str = 'Runoff (-)' + ax[row_idx, col_idx].set_ylim(0,2.2) + ax[row_idx, col_idx].yaxis.set_minor_locator(plt.MultipleLocator(0.1)) + ax[row_idx, col_idx].set_yticks([0.5,1,1.5,2]) + ax[row_idx, col_idx].set_yticklabels(['0.5','1.0','1.5','2.0']) + ax[row_idx, col_idx].yaxis.set_tick_params(pad=0, size=4, labelsize=tick_labelsize) elif vn == 'volume_glac_annual': ylabel_str = 'Mass (-)' - # Y-Label - if len(groups) == 1: - fig.text(-0.01, 0.5, ylabel_str, va='center', rotation='vertical', size=12) - else: - fig.text(0.06, 0.5, ylabel_str, va='center', rotation='vertical', size=12) + ax[row_idx, col_idx].set_ylim(0, 1.15) + if option_plot_individual_gcms == 1: + ax[row_idx, col_idx].set_ylim(0,1.35) + ax[row_idx, col_idx].yaxis.set_major_locator(plt.MultipleLocator(0.5)) + ax[row_idx, col_idx].yaxis.set_minor_locator(plt.MultipleLocator(0.1)) + ax[row_idx, col_idx].set_yticklabels(['','','0.5','1.0',]) + ax[row_idx, col_idx].yaxis.set_ticks_position('both') + ax[row_idx, col_idx].tick_params(axis='both', which='major', labelsize=tick_labelsize, direction='inout') + ax[row_idx, col_idx].tick_params(axis='both', which='minor', labelsize=tick_labelsize, direction='inout') - fig.delaxes(ax[1][1]) - fig.delaxes(ax[1][2]) - fig.delaxes(ax[2][1]) - fig.delaxes(ax[2][2]) - fig.delaxes(ax[3][3]) - - # RCP Legend - leg_size = 9 - rcp_lines = [] - for rcp in ['rcp26', 'rcp45', 'rcp60', 'rcp85']: - line = Line2D([0,1],[0,1], color=rcp_colordict[rcp], linewidth=multimodel_linewidth) - rcp_lines.append(line) - rcp_labels = ['RCP ' + rcp_dict[rcp] for rcp in ['rcp26','rcp45','rcp60', 'rcp85']] - fig.legend(rcp_lines, rcp_labels, loc=(0.79,0.125), fontsize=leg_size, labelspacing=0, handlelength=1.5, - handletextpad=0.5, borderpad=0, frameon=False, ncol=1) - -# leg_size = 9 -# rcp_lines = [] -# for rcp in ['rcp26', 'rcp45']: -# line = Line2D([0,1],[0,1], color=rcp_colordict[rcp], linewidth=multimodel_linewidth) -# rcp_lines.append(line) -# rcp_labels = ['RCP ' + rcp_dict[rcp] for rcp in ['rcp26','rcp45']] -# fig.legend(rcp_lines, rcp_labels, loc=(0.75,0.18), fontsize=leg_size, labelspacing=0, handlelength=0.5, -# handletextpad=0.5, borderpad=0, frameon=False, ncol=1) -# rcp_lines2 = [] -# for rcp in ['rcp60', 'rcp85']: -# line = Line2D([0,1],[0,1], color=rcp_colordict[rcp], linewidth=multimodel_linewidth) -# rcp_lines2.append(line) -# rcp_labels2 = ['RCP ' + rcp_dict[rcp] for rcp in ['rcp60', 'rcp85']] -# fig.legend(rcp_lines2, rcp_labels2, loc=(0.855,0.18), fontsize=leg_size, labelspacing=0, handlelength=0.5, -# handletextpad=0.5, borderpad=0, frameon=False, ncol=1) -# rcp_lines3 = [] -# line = Line2D([0,1],[0,1], color='grey', linewidth=3*multimodel_linewidth, alpha=0.2) -# rcp_lines3.append(line) -# rcp_labels3 = ['multi-model\nstandard deviation'] -# fig.legend(rcp_lines3, rcp_labels3, loc=(0.75,0.12), fontsize=leg_size, labelspacing=0, handlelength=0.5, -# handletextpad=0.5, borderpad=0, frameon=False, ncol=1) - rcp_lines4 = [] - line = Line2D([0,1],[0,1], color='grey', linewidth=0.75, linestyle='--') - rcp_lines4.append(line) - rcp_labels4 = ['Peak water'] - fig.legend(rcp_lines4, rcp_labels4, loc=(0.79,0.085), fontsize=leg_size, labelspacing=0, handlelength=1.5, - handletextpad=0.5, borderpad=0, frameon=False, ncol=1) + # Mean annual runoff + ax[row_idx, col_idx].text(0.99, 0.0, plot_str, size=9, horizontalalignment='right', + verticalalignment='bottom', transform=ax[row_idx, col_idx].transAxes, + color='k', zorder=6) - # Save figure - fig.set_size_inches(7.5, 5.25) - figure_fn = grouping + '-panels-' + vn + '_multimodel_' + str(len(rcps)) + 'rcps.png' - fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300, transparent=True) + # Label + if vn == 'runoff_glac_monthly': + ylabel_str = 'Runoff (-)' + elif vn == 'volume_glac_annual': + ylabel_str = 'Mass (-)' + # Y-Label + if len(groups) == 1: + fig.text(-0.01, 0.5, ylabel_str, va='center', rotation='vertical', size=12) + else: + fig.text(0.06, 0.5, ylabel_str, va='center', rotation='vertical', size=12) + + fig.delaxes(ax[1][1]) + fig.delaxes(ax[1][2]) + fig.delaxes(ax[2][1]) + fig.delaxes(ax[2][2]) + fig.delaxes(ax[3][3]) + + # RCP Legend + leg_size = 9 + rcp_lines = [] + for rcp in ['rcp26', 'rcp45']: + line = Line2D([0,1],[0,1], color=rcp_colordict[rcp], linewidth=multimodel_linewidth) + rcp_lines.append(line) + rcp_labels = ['RCP ' + rcp_dict[rcp] for rcp in ['rcp26','rcp45']] + fig.legend(rcp_lines, rcp_labels, loc=(0.75,0.18), fontsize=leg_size, labelspacing=0, handlelength=0.5, + handletextpad=0.5, borderpad=0, frameon=False, ncol=1) + rcp_lines2 = [] + for rcp in ['rcp60', 'rcp85']: + line = Line2D([0,1],[0,1], color=rcp_colordict[rcp], linewidth=multimodel_linewidth) + rcp_lines2.append(line) + rcp_labels2 = ['RCP ' + rcp_dict[rcp] for rcp in ['rcp60', 'rcp85']] + fig.legend(rcp_lines2, rcp_labels2, loc=(0.855,0.18), fontsize=leg_size, labelspacing=0, handlelength=0.5, + handletextpad=0.5, borderpad=0, frameon=False, ncol=1) + rcp_lines3 = [] + line = Line2D([0,1],[0,1], color='grey', linewidth=3*multimodel_linewidth, alpha=0.2) + rcp_lines3.append(line) + rcp_labels3 = ['multi-model\nstandard deviation'] + fig.legend(rcp_lines3, rcp_labels3, loc=(0.75,0.12), fontsize=leg_size, labelspacing=0, handlelength=0.5, + handletextpad=0.5, borderpad=0, frameon=False, ncol=1) + rcp_lines4 = [] + line = Line2D([0,1],[0,1], color='grey', linewidth=0.75, linestyle='--') + rcp_lines4.append(line) + rcp_labels4 = ['RCP\'s peak water'] + fig.legend(rcp_lines4, rcp_labels4, loc=(0.745,0.09), fontsize=leg_size, labelspacing=0, handlelength=1, + handletextpad=0.25, borderpad=0, frameon=False, ncol=1) + + # Save figure + fig.set_size_inches(7.5, 5.25) + figure_fn = grouping + '-panels-' + vn + '_multimodel_' + str(len(rcps)) + 'rcps.png' + fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300, transparent=True) #%% # Regional maps @@ -5063,38 +3567,30 @@ def __call__(self, value, clip=None): #%% if option_glaciermip_table == 1: - startyear = 2000 + startyear = 2015 endyear = 2100 vn = 'volume_glac_annual' # vn = 'area_glac_annual' - rcps = ['rcp26', 'rcp45', 'rcp60', 'rcp85'] - - grouping = 'rgi_region' - netcdf_fp_cmip5= '/Volumes/LaCie/HMA_PyGEM/2019_0914/spc_subset/' - - gcm_names = ['CanESM2', 'CCSM4', 'CNRM-CM5', 'CSIRO-Mk3-6-0', 'GFDL-CM3', 'GFDL-ESM2M', 'GISS-E2-R', 'IPSL-CM5A-LR', - 'MPI-ESM-LR', 'NorESM1-M'] - if vn == 'volume_glac_annual': output_prefix = 'Volume' elif vn == 'area_glac_annual': output_prefix = 'Area' - output_fp = input.output_sim_fp + 'GlacierMIP/' if os.path.exists(output_fp) == False: os.makedirs(output_fp) # Load glaciers - main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(rgi_regionsO1=regions) + main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(regions) # Groups groups, group_cn = select_groups(grouping, main_glac_rgi) -#%% + # Load mass balance data ds_all = {} for rcp in rcps: +# for rcp in ['rcp26']: ds_all[rcp] = {} for ngcm, gcm_name in enumerate(gcm_names): # for ngcm, gcm_name in enumerate(['CanESM2']): @@ -5105,69 +3601,48 @@ def __call__(self, value, clip=None): for region in regions: # Load datasets - ds_fn = ('R' + str(region) + '--all--' + gcm_name + '_' + rcp + '_c2_ba' + - str(input.option_bias_adjustment) + '_100sets_2000_2100--subset.nc') - + ds_fn = ('R' + str(region) + '_' + gcm_name + '_' + rcp + '_c2_ba' + str(input.option_bias_adjustment) + + '_100sets_2000_2100--subset.nc') + ds = xr.open_dataset(netcdf_fp_cmip5 + ds_fn) + + # Bypass GCMs that are missing a rcp scenario try: ds = xr.open_dataset(netcdf_fp_cmip5 + ds_fn) - skip_gcm = 0 except: - skip_gcm = 1 - print('Skip', gcm_name, rcp, region) - - # Bypass GCMs that are missing a rcp scenario - if skip_gcm == 0: - ds = xr.open_dataset(netcdf_fp_cmip5 + ds_fn) - df = pd.DataFrame(ds.glacier_table.values, columns=ds.glac_attrs.values) - df['RGIId'] = ['RGI60-' + str(int(df.O1Region.values[x])) + '.' + - str(int(df.glacno.values[x])).zfill(5) for x in df.index.values] - - # Extract time variable - time_values_annual = ds.coords['year_plus1'].values - time_values_monthly = ds.coords['time'].values - # Extract start/end indices for calendar year! - time_values_df = pd.DatetimeIndex(time_values_monthly) - time_values = np.array([x.year for x in time_values_df]) - time_idx_start = np.where(time_values == startyear)[0][0] - time_idx_end = np.where(time_values == endyear)[0][0] - year_idx_start = np.where(time_values_annual == startyear)[0][0] - year_idx_end = np.where(time_values_annual == endyear)[0][0] - - time_values_annual_subset = time_values_annual[year_idx_start:year_idx_end+1] - var_glac_region = ds[vn].values[:,year_idx_start:year_idx_end+1,0] - - print(rcp, gcm_name, region, var_glac_region[:,-1].sum() / var_glac_region[:,0].sum() * 100) - - # Merge datasets - if region == regions[0]: - var_glac_all = var_glac_region - df_all = df - else: - var_glac_all = np.concatenate((var_glac_all, var_glac_region), axis=0) - df_all = pd.concat([df_all, df], axis=0) - - ds.close() - - - if skip_gcm == 0: - # RGIIds of only glaciers in simulations - if ngcm == 0: - rgiid_df = list(df_all.RGIId.values) - rgiid_all = list(main_glac_rgi.RGIId.values) - rgi_idx = [rgiid_all.index(x) for x in rgiid_df] - main_glac_rgi = main_glac_rgi.loc[rgi_idx,:] - main_glac_rgi.reset_index(inplace=True, drop=True) + continue - ds_all[rcp][gcm_name] = {} - for ngroup, group in enumerate(groups): - # Sum volume change for group - group_glac_indices = main_glac_rgi.loc[main_glac_rgi[group_cn] == group].index.values.tolist() - varchg_group = var_glac_all[group_glac_indices,:].sum(axis=0) - - ds_all[rcp][gcm_name][group] = varchg_group + # Extract time variable + time_values_annual = ds.coords['year_plus1'].values + time_values_monthly = ds.coords['time'].values + # Extract start/end indices for calendar year! + time_values_df = pd.DatetimeIndex(time_values_monthly) + time_values = np.array([x.year for x in time_values_df]) + time_idx_start = np.where(time_values == startyear)[0][0] + time_idx_end = np.where(time_values == endyear)[0][0] + year_idx_start = np.where(time_values_annual == startyear)[0][0] + year_idx_end = np.where(time_values_annual == endyear)[0][0] - #%% + time_values_annual_subset = time_values_annual[year_idx_start:year_idx_end+1] + var_glac_region = ds[vn].values[:,year_idx_start:year_idx_end+1,0] + + # Merge datasets + if region == regions[0]: + var_glac_all = var_glac_region + else: + var_glac_all = np.concatenate((var_glac_all, var_glac_region), axis=0) + try: + ds.close() + except: + continue + + ds_all[rcp][gcm_name] = {} + for ngroup, group in enumerate(groups): + # Sum volume change for group + group_glac_indices = main_glac_rgi.loc[main_glac_rgi[group_cn] == group].index.values.tolist() + varchg_group = var_glac_all[group_glac_indices,:].sum(axis=0) + ds_all[rcp][gcm_name][group] = varchg_group + # Export csv files output_cns = time_values_annual_subset.tolist() output_rns = ['Alaska','Western Canada and U.S.','Arctic Canada North','Arctic Canada South','Greenland','Iceland', @@ -5177,46 +3652,38 @@ def __call__(self, value, clip=None): group_dict = {13:'Central Asia', 14:'South Asia West', 15:'South Asia East'} rcp_dict = {'rcp26':'RCP26', 'rcp45':'RCP45', 'rcp60':'RCP60', 'rcp85':'RCP85'} - for gcm_name in gcm_names: + for gcm in gcm_names: for rcp in rcps: - # Load datasets - ds_fn = ('R' + str(region) + '--all--' + gcm_name + '_' + rcp + '_c2_ba' + - str(input.option_bias_adjustment) + '_100sets_2000_2100--subset.nc') - if os.path.exists(netcdf_fp_cmip5 + ds_fn): - print(gcm_name, rcp, 'exists') - - output = pd.DataFrame(np.zeros((len(output_rns), len(output_cns))) + -9999, + print(gcm, rcp) + + output = pd.DataFrame(np.zeros((len(output_rns), len(output_cns))) + -9999, index=output_rns, columns=output_cns) - for group in groups: - # Convert volume to water equivalent - if vn == 'volume_glac_annual': - output_gcm_rcp_group = ds_all[rcp][gcm_name][group] * input.density_ice / input.density_water - elif vn == 'area_glac_annual': - output_gcm_rcp_group = ds_all[rcp][gcm_name][group] - - - output.loc[group_dict[group],:] = output_gcm_rcp_group - - # Export txt file - output_fn = output_prefix + '_PyGEM_' + gcm_name + '_' + rcp_dict[rcp] + '_r1i1p1.txt' - output.to_csv(output_fp + output_fn, sep=',', index=False) - - txt_header = 'David Rounce, drounce@alaska.edu' - if vn == 'volume_glac_annual': - txt_header += ', Volume [km3 we]' - elif vn == 'area_glac_annual': - txt_header += ', Area [km2]' - with open(output_fp + output_fn, 'r+') as f: - content = f.read() - f.seek(0, 0) - f.write(txt_header.rstrip('\r\n') + '\n' + content) + for group in groups: - else: - print(' ', gcm_name, rcp, 'does not exist') - - #%% + # Convert volume to water equivalent + if vn == 'volume_glac_annual': + output_gcm_rcp_group = ds_all[rcp][gcm_name][group] * input.density_ice / input.density_water + elif vn == 'area_glac_annual': + output_gcm_rcp_group = ds_all[rcp][gcm_name][group] + + + output.loc[group_dict[group],:] = output_gcm_rcp_group + + # Export txt file + output_fn = output_prefix + '_PyGEM_' + gcm + '_' + rcp_dict[rcp] + '_r1i1p1.txt' + output.to_csv(output_fp + output_fn, sep=',') + + txt_header = 'David Rounce, drounce@alaska.edu' + if vn == 'volume_glac_annual': + txt_header += ', Volume [km3 we]' + elif vn == 'area_glac_annual': + txt_header += ', Area [km2]' + with open(output_fp + output_fn, 'r+') as f: + content = f.read() + f.seek(0, 0) + f.write(txt_header.rstrip('\r\n') + '\n' + content) # # Export csv files # output_cns = ['year'] + gcm_names @@ -5275,7 +3742,7 @@ def __call__(self, value, clip=None): vn = 'massbaltotal_glac_monthly' grouping = 'rgi_region' - subgrouping = 'hexagon42' + subgrouping = 'hexagon' # subgrouping = 'degree' # degree_size = 1 @@ -5293,8 +3760,8 @@ def __call__(self, value, clip=None): os.makedirs(output_fp) # Load glaciers - main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(rgi_regionsO1=regions) - + main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(regions) + # Groups groups, group_cn = select_groups(grouping, main_glac_rgi) subgroups, subgroup_cn = select_groups(subgrouping, main_glac_rgi) @@ -5305,11 +3772,8 @@ def __call__(self, value, clip=None): for region in regions: # Load datasets - ds_fn = ('R' + str(region) + '--all--ERA-Interim_c2_ba1_100sets_1980_2017.nc') + ds_fn = ('R' + str(region) + '_ERA-Interim_c2_ba1_100sets_1980_2017.nc') ds = xr.open_dataset(netcdf_fp_era + ds_fn) - df = pd.DataFrame(ds.glacier_table.values, columns=ds.glac_attrs.values) - df['RGIId'] = ['RGI60-' + str(int(df.O1Region.values[x])) + '.' + - str(int(df.glacno.values[x])).zfill(5) for x in df.index.values] # Extract time variable time_values_annual = ds.coords['year_plus1'].values @@ -5342,23 +3806,14 @@ def __call__(self, value, clip=None): var_glac_all = volchg_monthly_glac_region var_glac_all_std = volchg_monthly_glac_region_std area_glac_all = area_glac_region - df_all = df else: var_glac_all = np.concatenate((var_glac_all, volchg_monthly_glac_region), axis=0) var_glac_all_std = np.concatenate((var_glac_all_std, volchg_monthly_glac_region_std), axis=0) area_glac_all = np.concatenate((area_glac_all, area_glac_region), axis=0) - df_all = pd.concat([df_all, df], axis=0) try: ds.close() except: continue - - # RGIIds of only glaciers in simulations - rgiid_df = list(df_all.RGIId.values) - rgiid_all = list(main_glac_rgi.RGIId.values) - rgi_idx = [rgiid_all.index(x) for x in rgiid_df] - main_glac_rgi = main_glac_rgi.loc[rgi_idx,:] - main_glac_rgi.reset_index(inplace=True, drop=True) ds_all = {} ds_all_std = {} @@ -5392,10 +3847,6 @@ def __call__(self, value, clip=None): ds_all[group] = mb_mwea_group ds_all_std[group] = mb_mwea_group_std - #%% - stats_cns = ['group', 'rmse', 'r', 'slope', 'intercept', 'p-value', 'mae', 'nse'] - group_stats = pd.DataFrame(np.zeros((len(groups), len(stats_cns))), columns=stats_cns) - group_stats['group'] = groups fig, ax = plt.subplots(len(groups), 1, squeeze=False, figsize=(10,8), gridspec_kw = {'wspace':0, 'hspace':0}) for ngroup, group in enumerate(groups): @@ -5407,61 +3858,37 @@ def __call__(self, value, clip=None): dif_group = zemp_group - mb_mwea_group # All glaciers - ax[ngroup,0].plot(years, zemp_group, color='k', label='Zemp et al. (2019)', zorder=2) + ax[ngroup,0].plot(years, zemp_group, color='k', label='Zemp (2019)') ax[ngroup,0].fill_between(years, zemp_group + zemp_group_std, zemp_group - zemp_group_std, facecolor='lightgrey', label=None, zorder=1) - ax[ngroup,0].plot(years, mb_mwea_group, color='b', label='Modeled', zorder=2) + ax[ngroup,0].plot(years, mb_mwea_group, color='b', label='ERA-Interim') ax[ngroup,0].fill_between(years, mb_mwea_group + mb_mwea_group_std, mb_mwea_group - mb_mwea_group_std, - facecolor='dodgerblue', label=None, zorder=1) + facecolor='lightblue', label=None, zorder=1) ax[ngroup,0].set_ylim(-1.1,0.75) ax[ngroup,0].set_xlim(1980,2016) - ax[ngroup,0].xaxis.set_minor_locator(MultipleLocator(5)) - ax[ngroup,0].tick_params(axis='x', direction='inout', which='both') if ngroup == 0: ax[ngroup,0].legend(loc=(0.02,0.02), ncol=1, fontsize=10, frameon=False, handlelength=1.5, handletextpad=0.25, columnspacing=1, borderpad=0, labelspacing=0) - if ngroup+1 < len(groups): + if ngroup + 1 == len(groups): + ax[ngroup,0].set_xlabel('Year', size=12) + else: ax[ngroup,0].xaxis.set_ticklabels([]) -# if ngroup + 1 == len(groups): -# ax[ngroup,0].set_xlabel('Year', size=12) -# else: -# ax[ngroup,0].xaxis.set_ticklabels([]) ax[ngroup,0].yaxis.set_ticks(np.arange(-1, 0.55, 0.5)) - - # Statistics for comparison - # Root-mean-square-deviation - rmse = (np.sum((mb_mwea_group - zemp_group)**2) / zemp_group.shape[0])**0.5 - print(group, 'RMSE:', np.round(rmse,2)) - # Correlation - slope, intercept, r_value, p_value, std_err = linregress(zemp_group, mb_mwea_group) - print(' r_value =', np.round(r_value,2), 'slope = ', np.round(slope,2), - 'intercept = ', np.round(intercept,2), 'p_value = ', np.round(p_value,4)) - # Mean absolute error - mae = np.mean(np.absolute(zemp_group - mb_mwea_group)) - print(' mean absolute error:', np.round(mae,2)) - # Nash-Sutcliffe model efficiency coefficient - nse = 1 - (np.sum((mb_mwea_group - zemp_group)**2) / np.sum((zemp_group - zemp_group.mean())**2)) - print(' NSE:', np.round(nse,2)) - # Record stats - group_stats.loc[ngroup, ['rmse', 'r', 'slope', 'intercept', 'p-value', 'mae', 'nse']] = ( - [rmse, r_value, slope, intercept, p_value, mae, nse]) # Add text - fig.text(-0.08, 0.5, 'Mass Balance (m w.e. $\mathregular{yr^{-1}}$)', va='center', rotation='vertical', size=12) + fig.text(-0.05, 0.5, 'Mass Balance (m w.e. $\mathregular{yr^{-1}}$)', va='center', rotation='vertical', size=12) fig.text(0.5, 0.845, 'Central Asia', horizontalalignment='center', zorder=4, color='black', fontsize=10) fig.text(0.5, 0.59, 'South Asia West', horizontalalignment='center', zorder=4, color='black', fontsize=10) fig.text(0.5, 0.34, 'South Asia East', horizontalalignment='center', zorder=4, color='black', fontsize=10) - fig.text(0.135, 0.84, 'A', zorder=4, color='black', fontsize=12, fontweight='bold') + fig.text(0.135, 0.845, 'A', zorder=4, color='black', fontsize=12, fontweight='bold') fig.text(0.135, 0.59, 'B', zorder=4, color='black', fontsize=12, fontweight='bold') - fig.text(0.135, 0.335, 'C', zorder=4, color='black', fontsize=12, fontweight='bold') + fig.text(0.135, 0.34, 'C', zorder=4, color='black', fontsize=12, fontweight='bold') # Save figure - fig.set_size_inches(3.25,3.75) + fig.set_size_inches(4,4) fig.savefig(output_fp + 'Zemp2019_vs_ERA-Interim_' + str(startyear) + '-' + str(endyear) + '_squeezed.eps', bbox_inches='tight', dpi=300) - # Export stats - group_stats.to_csv(output_fp + 'Zemp2019_vs_ERA-Interim_stats.csv', index=False) #%% @@ -5505,18 +3932,18 @@ def __call__(self, value, clip=None): os.makedirs(output_fp) # Load glaciers - main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(rgi_regionsO1=regions) + main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(regions) # Groups groups, group_cn = select_groups(grouping, main_glac_rgi) -#%% + # Load mass balance data ds_all = {} # Merge all data, then select group data for region in regions: # Load datasets - ds_fn = ('R' + str(region) + '--all--ERA-Interim_c2_ba1_100sets_1980_2017.nc') + ds_fn = ('R' + str(region) + '_ERA-Interim_c2_ba1_100sets_1980_2017.nc') ds = xr.open_dataset(netcdf_fp_era + ds_fn) # Extract time variable @@ -5570,11 +3997,6 @@ def __call__(self, value, clip=None): # np.round(ela_subset.mean(),0), '+/-', np.round(ela_subset.std(),0)) #%% - # Record all for stats - gardelle_all = [] - era_ela_all = [] - - # Plot fig, ax = plt.subplots(1, 1, squeeze=False, figsize=(10,8), gridspec_kw = {'wspace':0, 'hspace':0}) for ngroup, group in enumerate(sorted(group_data_dict.keys())): @@ -5582,8 +4004,6 @@ def __call__(self, value, clip=None): gardelle_std = group_data_dict[group][3] era_ela = ds_all[group][0] era_ela_std = ds_all[group][1] - gardelle_all.append(gardelle) - era_ela_all.append(era_ela) group_label = group if group == 'Yigong': @@ -5598,7 +4018,7 @@ def __call__(self, value, clip=None): ax[0,0].errorbar(gardelle, era_ela, xerr=gardelle_std, yerr=era_ela_std, capsize=1, linewidth=0.5, color='darkgrey', zorder=2) - ax[0,0].set_xlabel('Observed ELA (m a.s.l.)', size=12) + ax[0,0].set_xlabel('ELA (m a.s.l.) (Gardelle, 2013)', size=12) ax[0,0].set_ylabel('Modeled ELA (m a.s.l.)', size=12) ymin = 4000 ymax = 6500 @@ -5608,41 +4028,22 @@ def __call__(self, value, clip=None): ax[0,0].set_ylim(ymin,ymax) ax[0,0].plot([np.min([xmin,ymin]),np.max([xmax,ymax])], [np.min([xmin,ymin]),np.max([xmax,ymax])], color='k', linewidth=0.5, zorder=1) - ax[0,0].yaxis.set_ticks(np.arange(4500, 6500, 500)) + ax[0,0].yaxis.set_ticks(np.arange(4500, ymax+1, 500)) ax[0,0].xaxis.set_ticks(np.arange(4500, 6500, 500)) # Ensure proper order for legend handles, labels = ax[0,0].get_legend_handles_labels() labels, handles = zip(*sorted(zip(labels, handles), key=lambda t:t[0])) - ax[0,0].legend(handles, labels, loc=(0.02,0.51), ncol=1, fontsize=10, frameon=False, handlelength=1, - handletextpad=0.15, columnspacing=0.5, borderpad=0, labelspacing=0) + ax[0,0].legend(handles, labels, loc=(0.02,0.57), ncol=1, fontsize=10, frameon=False, handlelength=1.5, + handletextpad=0.25, columnspacing=1, borderpad=0, labelspacing=0) + # Add text fig.text(0.15, 0.85, 'D', va='center', size=12, fontweight='bold') + + # Save figure - fig.set_size_inches(3.45,3.45) + fig.set_size_inches(2.75,4) fig.savefig(output_fp + 'gardelle2013_compare_regional_ELA_RGIIds.eps', bbox_inches='tight', dpi=300) - - # Stats - gardelle_all = np.array(gardelle_all) - era_ela_all = np.array(era_ela_all) - stats_cns = ['group', 'rmse', 'r', 'slope', 'intercept', 'p-value', 'mae'] - group_stats = pd.DataFrame(np.zeros((1, len(stats_cns))), columns=stats_cns) - group_stats['group'] = 'all' - # Statistics for comparison - # Root-mean-square-deviation - rmse = (np.sum((gardelle_all - era_ela_all)**2) / gardelle_all.shape[0])**0.5 - print('RMSE:', np.round(rmse,2)) - # Correlation - slope, intercept, r_value, p_value, std_err = linregress(gardelle_all, era_ela_all) - print('r_value =', np.round(r_value,2), 'slope = ', np.round(slope,2), - 'intercept = ', np.round(intercept,2), 'p_value = ', np.round(p_value,6)) - # Mean absolute error - mae = np.mean(np.absolute(gardelle_all - era_ela_all)) - print('mean absolute error:', np.round(mae,2)) - # Record stats - group_stats.loc[0, ['rmse', 'r', 'slope', 'intercept', 'p-value', 'mae']] = ( - [rmse, r_value, slope, intercept, p_value, mae]) - group_stats.to_csv(output_fp + 'gardelle2013_stats.csv', index=False) #%% @@ -5662,14 +4063,14 @@ def __call__(self, value, clip=None): option_wateryear=wateryear) # Load glaciers - main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(rgi_regionsO1=regions) + main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(regions) # Modeled Mass Balance ds_all = {} for region in regions: # Load datasets - ds_fn = ('R' + str(region) + '--all--ERA-Interim_c2_ba1_100sets_1980_2017.nc') + ds_fn = ('R' + str(region) + '_ERA-Interim_c2_ba1_100sets_1980_2017.nc') ds = xr.open_dataset(netcdf_fp_era + ds_fn) # Extract time variable @@ -5710,213 +4111,148 @@ def __call__(self, value, clip=None): continue # Calibration data - cal_data = pd.DataFrame() - for dataset in cal_datasets: - cal_subset = class_mbdata.MBData(name=dataset) - cal_subset_data = cal_subset.retrieve_mb(main_glac_rgi, main_glac_hyps, dates_table) - cal_data = cal_data.append(cal_subset_data, ignore_index=True) - cal_data = cal_data.sort_values(['glacno', 't1_idx']) - cal_data.reset_index(drop=True, inplace=True) + for nreg, reg in enumerate(regions): + # Load glaciers + main_glac_rgi_reg, main_glac_hyps_reg, main_glac_icethickness_reg = load_glacier_data([reg]) + + cal_data = pd.DataFrame() + for dataset in cal_datasets: + cal_subset = class_mbdata.MBData(name=dataset) + cal_subset_data = cal_subset.retrieve_mb(main_glac_rgi_reg, main_glac_hyps_reg, dates_table) + cal_data = cal_data.append(cal_subset_data, ignore_index=True) + cal_data = cal_data.sort_values(['glacno', 't1_idx']) + cal_data.reset_index(drop=True, inplace=True) + + if nreg == 0: + cal_data_all = cal_data + else: + cal_data_all = pd.concat([cal_data_all, cal_data], sort=False) # Link glacier index number from main_glac_rgi to cal_data to facilitate grabbing the data glacnodict = dict(zip(main_glac_rgi['RGIId'], main_glac_rgi.index.values)) - cal_data['glac_idx'] = cal_data['RGIId'].map(glacnodict) + cal_data_all['glac_idx'] = cal_data_all['RGIId'].map(glacnodict) # Remove glaciers that don't have data over the entire glacier - cal_data['elev_dif'] = cal_data['z2'] - cal_data['z1'] + cal_data_all['elev_dif'] = cal_data_all['z2'] - cal_data_all['z1'] main_glac_rgi['elev_range'] = main_glac_rgi['Zmax'] - main_glac_rgi['Zmin'] # add elevation range to cal_data elevrange_dict = dict(zip(main_glac_rgi['RGIId'], main_glac_rgi['elev_range'])) - cal_data['elev_range'] = cal_data['RGIId'].map(elevrange_dict) + cal_data_all['elev_range'] = cal_data_all['RGIId'].map(elevrange_dict) # check difference (see if within 100 m of glacier) elev_margin_of_safety = 100 - cal_data['elev_check'] = cal_data['elev_dif'] - (cal_data['elev_range'] - elev_margin_of_safety) - cal_data = cal_data[cal_data['elev_check'] > 0] - cal_data.reset_index(drop=True, inplace=True) + cal_data_all['elev_check'] = cal_data_all['elev_dif'] - (cal_data_all['elev_range'] - elev_margin_of_safety) + cal_data_all = cal_data_all[cal_data_all['elev_check'] > 0] + cal_data_all.reset_index(drop=True, inplace=True) #%% - cal_data['mb_mwe_era'] = np.nan - cal_data['mb_mwea_era'] = np.nan - cal_data['mb_mwe_era_std'] = np.nan - for n in range(cal_data.shape[0]): - glac_idx = cal_data.loc[n,'glac_idx'] - t1_idx = int(cal_data.loc[n,'t1_idx']) - t2_idx = int(cal_data.loc[n,'t2_idx']) - t1 = cal_data.loc[n,'t1'] - t2 = cal_data.loc[n,'t2'] - cal_data.loc[n,'mb_mwe_era'] = var_glac_all[glac_idx, t1_idx:t2_idx].sum() - cal_data.loc[n,'mb_mwe_era_std'] = var_glac_all_std[glac_idx, t1_idx:t2_idx].sum() - cal_data.loc[n,'mb_mwe_era_std_rsos'] = ((var_glac_all_std[glac_idx, t1_idx:t2_idx]**2).sum())**0.5 - - cal_data['mb_mwea_era'] = cal_data['mb_mwe_era'] / (cal_data['t2'] - cal_data['t1']) - cal_data['mb_mwea_era_std'] = cal_data['mb_mwe_era_std'] / (cal_data['t2'] - cal_data['t1']) - cal_data['mb_mwea_era_std_rsos'] = cal_data['mb_mwe_era_std_rsos'] / (cal_data['t2']-cal_data['t1']) - cal_data['mb_mwea'] = cal_data['mb_mwe'] / (cal_data['t2'] - cal_data['t1']) - cal_data['year'] = (cal_data['t2'] + cal_data['t1']) / 2 - - #%% - # Determine whether data is seasonal or annual - cal_data['time_difference'] = cal_data['t2'] - cal_data['t1'] - cal_data['seasonal/annual'] = 'summer' - # Determine approximate center month of the seasonal/annual data - cal_data['season_month'] = (cal_data['year'] - cal_data['year'].astype(int)) * 365 / 30 - cal_data.loc[cal_data['season_month'] < 4.5, 'seasonal/annual'] = 'winter' - cal_data.loc[cal_data['season_month'] > 10.5, 'seasonal/annual'] = 'winter' - cal_data.loc[cal_data['time_difference'] > 0.75, 'seasonal/annual'] = 'annual' - - # Remove data that spans less than a year - #cal_data = cal_data[(cal_data['t2'] - cal_data['t1']) > 1] - #cal_data.reset_index(drop=True, inplace=True) - - # Drop nan values - cal_data.drop(index=np.where(np.isnan(cal_data.mb_mwe.values))[0], inplace=True) - cal_data.reset_index(drop=True, inplace=True) - - #%% - # Loop through conditions: - condition_dict = OrderedDict() - condition_dict['All']= cal_data.index.values - condition_dict['All (annual)'] = (cal_data['t2'] - cal_data['t1']) >= 0.75 - condition_dict['All (seasonal)'] = (cal_data['t2'] - cal_data['t1']) < 0.75 - condition_dict['Geodetic'] = cal_data['obs_type'] == 'mb_geo' - condition_dict['Glaciological'] = cal_data['obs_type'] == 'mb_glac' - condition_dict['Glaciological (annual)'] = ((cal_data['seasonal/annual'] == 'annual') & - (cal_data['obs_type'] == 'mb_glac')) - condition_dict['Glaciological (winter)'] = ((cal_data['seasonal/annual'] == 'winter') & - (cal_data['obs_type'] == 'mb_glac')) - condition_dict['Glaciological (summer)'] = ((cal_data['seasonal/annual'] == 'summer') & - (cal_data['obs_type'] == 'mb_glac')) -# condition_dict['Glaciological (> 1 yr)'] = ((cal_data['obs_type'] == 'mb_glac') & -# ((cal_data['t2'] - cal_data['t1']) >= 0.75)) -# condition_dict['Glaciological (< 1 yr)'] = ((cal_data['obs_type'] == 'mb_glac') & -# ((cal_data['t2'] - cal_data['t1']) < 0.75)) - - stats_cns = ['group', 'count', 'rmse', 'r', 'slope', 'intercept', 'p-value', 'mae'] - group_stats = pd.DataFrame(np.zeros((len(condition_dict.keys()), len(stats_cns))), columns=stats_cns) - group_stats['group'] = condition_dict.keys() - - for ncondition, cal_condition in enumerate(condition_dict.keys()): -# for ncondition, cal_condition in enumerate(['Glaciological (annual)']): - # Statistics for comparison - cal_data_subset = cal_data.loc[condition_dict[cal_condition],:].copy() - print('\n',cal_condition, cal_data_subset.shape[0]) - - # Root-mean-square-deviation - rmse = (np.sum((cal_data_subset.mb_mwea - cal_data_subset.mb_mwea_era)**2) / cal_data_subset.shape[0])**0.5 - print(' RMSE:', np.round(rmse,2)) - # Correlation - slope, intercept, r_value, p_value, std_err = linregress(cal_data_subset.mb_mwea, cal_data_subset.mb_mwea_era) - print(' r_value =', np.round(r_value,2), 'slope = ', np.round(slope,2), - 'intercept = ', np.round(intercept,2), 'p_value = ', np.round(p_value,6)) - # Mean absolute error - mae = np.mean(np.absolute(cal_data_subset.mb_mwea - cal_data_subset.mb_mwea_era)) - print(' mean absolute error:', np.round(mae,2)) - # Record stats - group_stats.loc[ncondition, ['count', 'rmse', 'r', 'slope', 'intercept', 'p-value', 'mae']] = ( - [cal_data_subset.shape[0], rmse, r_value, slope, intercept, p_value, mae]) - - - cal_data_subset['dif_mb_mwea'] = cal_data_subset['mb_mwea'] - cal_data_subset['mb_mwea_era'] - print(' Difference stats: \n Mean (+/-) std [mwea]:', - np.round(cal_data_subset['dif_mb_mwea'].mean(),2), '+/-', np.round(cal_data_subset['dif_mb_mwea'].std(),2), - 'count:', cal_data_subset.shape[0], - '\n Median (+/-) std [mwea]:', - np.round(cal_data_subset['dif_mb_mwea'].median(),2), '+/- XXX', -# np.round(cal_data_subset['dif_mb_mwea'].std(),2), - '\n Mean standard deviation (correlated):',np.round(cal_data_subset['mb_mwea_era_std'].mean(),2), - '\n Mean standard deviation (uncorrelated):',np.round(cal_data_subset['mb_mwea_era_std_rsos'].mean(),2)) - - group_stats.to_csv(output_fp + 'wgms_stats.csv', index=False) + cal_data_all['mb_mwe_era'] = np.nan + cal_data_all['mb_mwea_era'] = np.nan + cal_data_all['mb_mwe_era_std'] = np.nan + for n in range(cal_data_all.shape[0]): + glac_idx = cal_data_all.loc[n,'glac_idx'] + t1_idx = int(cal_data_all.loc[n,'t1_idx']) + t2_idx = int(cal_data_all.loc[n,'t2_idx']) + t1 = cal_data_all.loc[n,'t1'] + t2 = cal_data_all.loc[n,'t2'] + cal_data_all.loc[n,'mb_mwe_era'] = var_glac_all[glac_idx, t1_idx:t2_idx].sum() + cal_data_all.loc[n,'mb_mwe_era_std'] = var_glac_all_std[glac_idx, t1_idx:t2_idx].sum() + cal_data_all.loc[n,'mb_mwe_era_std_rsos'] = ((var_glac_all_std[glac_idx, t1_idx:t2_idx]**2).sum())**0.5 + + cal_data_all['mb_mwea_era'] = cal_data_all['mb_mwe_era'] / (cal_data_all['t2'] - cal_data_all['t1']) + cal_data_all['mb_mwea_era_std'] = cal_data_all['mb_mwe_era_std'] / (cal_data_all['t2'] - cal_data_all['t1']) + cal_data_all['mb_mwea_era_std_rsos'] = cal_data_all['mb_mwe_era_std_rsos'] / (cal_data_all['t2']-cal_data_all['t1']) + cal_data_all['mb_mwea'] = cal_data_all['mb_mwe'] / (cal_data_all['t2'] - cal_data_all['t1']) + cal_data_all['year'] = (cal_data_all['t2'] + cal_data_all['t1']) / 2 - #%% - - # ===== PLOT ===== - fig, ax = plt.subplots(1, 2, squeeze=False, figsize=(10,8), gridspec_kw = {'wspace':0.3, 'hspace':0}) + # Remove data that spans less than a year + #cal_data_all = cal_data_all[(cal_data_all['t2'] - cal_data_all['t1']) > 1] + #cal_data_all.reset_index(drop=True, inplace=True) + + # Print summary of errors + cal_data_all['dif_mb_mwea'] = cal_data_all['mb_mwea'] - cal_data_all['mb_mwea_era'] + cal_data_all['dif_mb_mwe'] = cal_data_all['mb_mwe'] - cal_data_all['mb_mwe_era'] + A = cal_data_all.copy() + print('All\n Mean (+/-) std [mwea]:', + np.round(A['dif_mb_mwea'].mean(),2), '+/-', np.round(A['dif_mb_mwea'].std(),2), 'count:', A.shape[0], + '\n Mean standard deviation (correlated):',np.round(A['mb_mwea_era_std'].mean(),2), + '\n Mean standard deviation (uncorrelated):',np.round(A['mb_mwea_era_std_rsos'].mean(),2)) + # More than 1 year + A = cal_data_all.copy() + A = A[(A['t2'] - A['t1']) >= 1] + print('All (> 1 yr)\n Mean (+/-) std [mwea]:', + np.round(A['dif_mb_mwea'].mean(),2), '+/-', np.round(A['dif_mb_mwea'].std(),2), 'count:', A.shape[0], + '\n Mean standard deviation (correlated):',np.round(A['mb_mwea_era_std'].mean(),2), + '\n Mean standard deviation (uncorrelated):',np.round(A['mb_mwea_era_std_rsos'].mean(),2)) + # Less than 1 year + A = cal_data_all.copy() + A = A[(A['t2'] - A['t1']) < 1] + print('All (< 1 yr)\n Mean (+/-) std [mwea]:', + np.round(A['dif_mb_mwea'].mean(),2), '+/-', np.round(A['dif_mb_mwea'].std(),2), 'count:', A.shape[0], + '\n Mean standard deviation (correlated):',np.round(A['mb_mwea_era_std'].mean(),2), + '\n Mean standard deviation (uncorrelated):',np.round(A['mb_mwea_era_std_rsos'].mean(),2)) + # Geodetic + A = cal_data_all.copy() + A = A[A['obs_type'] == 'mb_geo'] + print('Geodetic\n Mean (+/-) std [mwea]:', + np.round(A['dif_mb_mwea'].mean(),2), '+/-', np.round(A['dif_mb_mwea'].std(),2), 'count:', A.shape[0], + '\n Mean standard deviation (correlated):',np.round(A['mb_mwea_era_std'].mean(),2), + '\n Mean standard deviation (uncorrelated):',np.round(A['mb_mwea_era_std_rsos'].mean(),2)) + # Glaciological + A = cal_data_all.copy() + A = A[A['obs_type'] == 'mb_glac'] + print('Glaciological\n Mean (+/-) std [mwea]:', + np.round(A['dif_mb_mwea'].mean(),2), '+/-', np.round(A['dif_mb_mwea'].std(),2), 'count:', A.shape[0], + '\n Mean standard deviation (correlated):',np.round(A['mb_mwea_era_std'].mean(),2), + '\n Mean standard deviation (uncorrelated):',np.round(A['mb_mwea_era_std_rsos'].mean(),2)) + # Glaciological + A = cal_data_all.copy() + A = A[(A['obs_type'] == 'mb_glac') & ((A['t2'] - A['t1']) >= 1)] + print('Glaciological (> 1 yr)\n Mean (+/-) std [mwea]:', + np.round(A['dif_mb_mwea'].mean(),2), '+/-', np.round(A['dif_mb_mwea'].std(),2), 'count:', A.shape[0], + '\n Mean standard deviation (correlated):',np.round(A['mb_mwea_era_std'].mean(),2), + '\n Mean standard deviation (uncorrelated):',np.round(A['mb_mwea_era_std_rsos'].mean(),2)) + + fig, ax = plt.subplots(1, 2, squeeze=False, figsize=(10,8), gridspec_kw = {'wspace':0.27, 'hspace':0}) datatypes = ['mb_geo', 'mb_glac'] cmap = 'RdYlBu_r' norm = plt.Normalize(startyear, endyear) for nplot, datatype in enumerate(datatypes): -# for nplot, datatype in enumerate(['mb_geo']): - cal_data_plot = cal_data[cal_data['obs_type'] == datatype].copy() + cal_data_plot = cal_data_all[cal_data_all['obs_type'] == datatype] cal_data_plot.reset_index(drop=True, inplace=True) - cal_data_plot['circ_size'] = 4 - cal_data_plot.loc[cal_data_plot['area_km2'] > 1, 'circ_size'] = 10 - cal_data_plot.loc[cal_data_plot['area_km2'] > 5, 'circ_size'] = 30 - cal_data_plot.loc[cal_data_plot['area_km2'] > 10, 'circ_size'] = 60 -# cal_data_plot.loc[cal_data_plot['area_km2'] > 20, 'circ_size'] = 60 - if datatype == 'mb_geo': # All glaciers a = ax[0,nplot].scatter(cal_data_plot.mb_mwea.values, cal_data_plot.mb_mwea_era.values, -# c=cal_data_plot['year'].values, cmap=cmap, norm=norm, - color='k', - zorder=3, -# s=15, - s=cal_data_plot.circ_size.values, - marker='o') + c=cal_data_plot['year'].values, cmap=cmap, norm=norm, zorder=3, s=15, + marker='D') a.set_facecolor('none') -# ymin = -1.25 -# ymax = 0.6 -# xmin = -1.25 -# xmax = 0.6 - ymin = -2.5 - ymax = 2.5 - xmin = -2.5 - xmax = 2.5 + ymin = -1.25 + ymax = 0.6 + xmin = -1.25 + xmax = 0.6 ax[0,nplot].set_xlim(xmin,xmax) ax[0,nplot].set_ylim(ymin,ymax) ax[0,nplot].plot([np.min([xmin,ymin]),np.max([xmax,ymax])], [np.min([xmin,ymin]),np.max([xmax,ymax])], color='k', linewidth=0.25, zorder=1) -# ax[0,nplot].yaxis.set_ticks(np.arange(-1, ymax+0.1, 0.5)) -# ax[0,nplot].xaxis.set_ticks(np.arange(-1, xmax+0.11, 0.5)) -# ax[0,nplot].yaxis.set_ticks(np.arange(-1, ymax+0.1, 0.5)) -# ax[0,nplot].xaxis.set_ticks(np.arange(-1, xmax+0.11, 0.5)) + ax[0,nplot].yaxis.set_ticks(np.arange(-1, ymax+0.1, 0.5)) + ax[0,nplot].xaxis.set_ticks(np.arange(-1, xmax+0.11, 0.5)) ax[0,nplot].set_ylabel('$\mathregular{B_{mod}}$ (m w.e. $\mathregular{yr^{-1}}$)', labelpad=0, size=12) - ax[0,nplot].set_xlabel('$\mathregular{B_{geo}}$ (m w.e. $\mathregular{yr^{-1}}$)', labelpad=0, size=12) + ax[0,nplot].set_xlabel('$\mathregular{B_{geo}}$ (m w.e. $\mathregular{yr^{-1}}$)\n(WGMS, 2017)', labelpad=0, size=12) # Add text ax[0,nplot].text(0.05, 0.95, 'E', va='center', size=12, fontweight='bold', transform=ax[0,nplot].transAxes) - ax[0,nplot].text(0.7, 0.1, 'n=' + str(cal_data_plot.shape[0]) + '\n' + - str(cal_data_plot.glacno.unique().shape[0]) + ' glaciers', va='center', ha='center', - size=12, transform=ax[0,nplot].transAxes) - slope, intercept, r_value, p_value, std_err = linregress(cal_data_plot.mb_mwea.values, - cal_data_plot.mb_mwea_era.values) - print(datatype, 'r_value [mwea] =', r_value) + ax[0,nplot].text(0.7, 0.1, 'n=' + str(cal_data_plot.shape[0]) + '\nglaciers=' + + str(cal_data_plot.glacno.unique().shape[0]), va='center', ha='center', size=12, + transform=ax[0,nplot].transAxes) elif datatype == 'mb_glac': - glac_alpha = 1 # All glaciers -# a = ax[0,nplot].scatter(cal_data_plot.mb_mwe.values, cal_data_plot.mb_mwe_era.values, -# c=cal_data_plot['year'].values, cmap=cmap, norm=norm, -# zorder=3, s=15, marker='o') - # Annual - cal_data_plot_annual = cal_data_plot[cal_data_plot['seasonal/annual'] == 'annual'] - print('annual measurements:', len(cal_data_plot_annual)) - a = ax[0,nplot].scatter(cal_data_plot_annual.mb_mwe.values, cal_data_plot_annual.mb_mwe_era.values, - color='k', zorder=4, - s=cal_data_plot.circ_size.values, -# s=15, - marker='o', alpha=glac_alpha) + a = ax[0,nplot].scatter(cal_data_plot.mb_mwe.values, cal_data_plot.mb_mwe_era.values, + c=cal_data_plot['year'].values, cmap=cmap, norm=norm, zorder=3, s=15, + marker='o') a.set_facecolor('none') - cal_data_plot_summer = cal_data_plot[cal_data_plot['seasonal/annual'] == 'summer'] - print('summer measurements:', len(cal_data_plot_summer)) - b = ax[0,nplot].scatter(cal_data_plot_summer.mb_mwe.values, cal_data_plot_summer.mb_mwe_era.values, - color='red', zorder=3, -# s=15, - s=cal_data_plot.circ_size.values, - marker='o', alpha=glac_alpha) - b.set_facecolor('none') - cal_data_plot_winter = cal_data_plot[cal_data_plot['seasonal/annual'] == 'winter'] - print('winter measurements:', len(cal_data_plot_winter)) - b = ax[0,nplot].scatter(cal_data_plot_winter.mb_mwe.values, cal_data_plot_winter.mb_mwe_era.values, - color='blue', zorder=3, -# s=15, - s=cal_data_plot.circ_size.values, - marker='o', alpha=glac_alpha) - b.set_facecolor('none') ymin = -2.5 ymax = 2.5 xmin = -2.5 @@ -5930,93 +4266,27 @@ def __call__(self, value, clip=None): ax[0,nplot].set_ylabel('$\mathregular{B_{mod}}$ (m w.e.)', labelpad=0, size=12) - ax[0,nplot].set_xlabel('$\mathregular{B_{glac}}$ (m w.e.)', labelpad=2, size=12) + ax[0,nplot].set_xlabel('$\mathregular{B_{glac}}$ (m w.e.)\n(WGMS, 2017)', labelpad=2, size=12) # Add text ax[0,nplot].text(0.05, 0.95, 'F', va='center', size=12, fontweight='bold', transform=ax[0,nplot].transAxes) - ax[0,nplot].text(0.7, 0.1, 'n=' + str(cal_data_plot.shape[0]) + '\n' + - str(cal_data_plot.glacno.unique().shape[0]) + ' glaciers', va='center', ha='center', - size=12, transform=ax[0,nplot].transAxes) - # Correlation coefficient - slope, intercept, r_value, p_value, std_err = linregress(cal_data_plot.mb_mwe.values, - cal_data_plot.mb_mwe_era.values) - print(datatype, 'r_value [mwe] =', r_value) + ax[0,nplot].text(0.7, 0.1, 'n=' + str(cal_data_plot.shape[0]) + '\nglaciers=' + + str(cal_data_plot.glacno.unique().shape[0]), va='center', ha='center', size=12, + transform=ax[0,nplot].transAxes) # Add title #ax[0,nplot].set_title('Mass Balance (m w.e.)', size=12) - # Add colorbar for years -# sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) -# sm._A = [] -# fig.subplots_adjust(right=0.9) -# cbar_ax = fig.add_axes([0.92, 0.16, 0.02, 0.66]) -# cbar = fig.colorbar(sm, cax=cbar_ax) -# fig.text(0.93,0.845, 'Year', size=12) - - -# colorbar_dict = {'volume_norm':[0,1], -# 'runoff_glac_monthly':[2020,2080]} -# cmap = mpl.cm.RdYlBu -# norm = plt.Normalize(colorbar_dict[vn][0], colorbar_dict[vn][1]) -# -# # Add colorbar -# cmap_alpha=1 -# sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) -# sm._A = [] -# cax = plt.axes([0.92, 0.38, 0.015, 0.23]) -# cbar = plt.colorbar(sm, ax=ax, cax=cax, orientation='vertical', alpha=cmap_alpha) -# cax.xaxis.set_ticks_position('top') -# cax.xaxis.set_tick_params(pad=0) -# cbar.ax.tick_params(labelsize=6) -# for n, label in enumerate(cax.xaxis.get_ticklabels()): -# if n%2 != 0: -# label.set_visible(False) -# fig.text(0.965, 0.63, 'Year', ha='center', va='center', size=7) - - # SIZE LEGEND - s_sizes = [4,10,30,60] - marker_linecolor='grey' - marker_linewidth = 1 - circ1 = ax[0,nplot].scatter([0],[0], s=s_sizes[0], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ1.set_facecolor('none') - circ2 = ax[0,nplot].scatter([0],[0], s=s_sizes[1], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ2.set_facecolor('none') - circ3 = ax[0,nplot].scatter([0],[0], s=s_sizes[2], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ3.set_facecolor('none') - circ4 = ax[0,nplot].scatter([0],[0], s=s_sizes[3], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ4.set_facecolor('none') - leg_fontsize = 10 - legend=fig.legend([circ1,circ2,circ3,circ4], ['0.1', '1', '5', '10'], - scatterpoints=1, ncol=1, - loc='upper left', bbox_to_anchor=(0.865,0.63), - fontsize=leg_fontsize, labelspacing=0.3, columnspacing=0,handletextpad=0, handlelength=1, - borderpad=0.2, framealpha=0, borderaxespad=0.2, - ) - fig.text(0.94, 0.62, 'Area\n(km$^{2}$)', ha='center', va='center', size=leg_fontsize) - - # COLOR LEGEND - circ_c1 = ax[0,nplot].scatter([0],[0], s=s_sizes[2], marker='o', color='black', linewidth=marker_linewidth) - circ_c1.set_facecolor('none') - circ_c2 = ax[0,nplot].scatter([0],[0], s=s_sizes[2], marker='o', color='red', linewidth=marker_linewidth) - circ_c2.set_facecolor('none') - circ_c3 = ax[0,nplot].scatter([0],[0], s=s_sizes[2], marker='o', color='blue', linewidth=marker_linewidth) - circ_c3.set_facecolor('none') - legend_c=fig.legend([circ_c1,circ_c2,circ_c3], ['annual', 'summer', 'winter'], - scatterpoints=1, ncol=1, - loc='upper left', bbox_to_anchor=(0.74,0.93), - fontsize=leg_fontsize, labelspacing=0.3, columnspacing=0,handletextpad=0, handlelength=1, - borderpad=0.2, framealpha=1, borderaxespad=0.2, - ) - legend.get_frame().set_linewidth(0.5) -# fig.text(0.97, 0.45, 'Season', ha='center', va='center', size=leg_fontsize) + # Add colorbar + sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) + sm._A = [] + fig.subplots_adjust(right=0.9) + cbar_ax = fig.add_axes([0.92, 0.16, 0.03, 0.67]) + cbar = fig.colorbar(sm, cax=cbar_ax) # Save figure - fig.set_size_inches(6.75,3) - fig_fn = 'wgms2017_compare.png' - fig.savefig(output_fp + fig_fn, bbox_inches='tight', dpi=600) + fig.set_size_inches(6.75,4) + fig_fn = 'wgms2017_compare.eps' + fig.savefig(output_fp + fig_fn, bbox_inches='tight', dpi=300) #%% if option_dehecq_compare == 1: @@ -6267,25 +4537,26 @@ def __call__(self, value, clip=None): #%% if runoff_erainterim_bywatershed == 1: - startyear = 2001 - endyear = 2018 + startyear = 2000 + endyear = 2017 grouping = 'watershed' subgrouping = 'hexagon' netcdf_fp = netcdf_fp_era - regions = [13, 14, 15] + # Load glaciers + main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(regions) + # Groups + groups, group_cn = select_groups(grouping, main_glac_rgi) + subgroups, subgroup_cn = select_groups(subgrouping, main_glac_rgi) # Merge all data, then select group data for region in regions: # Load datasets - ds_fn = ('R' + str(region) + '--all--ERA-Interim_c2_ba1_100sets_2000_2018.nc') + ds_fn = ('R' + str(region) + '_ERA-Interim_c2_ba1_100sets_1980_2017.nc') ds = xr.open_dataset(netcdf_fp_era + ds_fn) - df = pd.DataFrame(ds.glacier_table.values, columns=ds.glac_attrs.values) - glacno_region = [str(int(df.loc[x,'O1Region'])) + '.' + str(int(df.loc[x,'glacno'])).zfill(5) - for x in df.index.values] # Extract time variable time_values_annual = ds.coords['year_plus1'].values @@ -6293,70 +4564,33 @@ def __call__(self, value, clip=None): # Extract start/end indices for calendar year! time_values_df = pd.DatetimeIndex(time_values_monthly) time_values_yr = np.array([x.year for x in time_values_df]) - if ds.time.year_type == 'water year': + if input.gcm_wateryear == 1: time_values_yr = np.array([x.year + 1 if x.month >= 10 else x.year for x in time_values_df]) - elif ds.time.year_type == 'custom year': - startmonth = int(input.startmonthday.split('-')[0]) - time_values_yr = np.array([x.year + 1 if x.month >= startmonth else x.year for x in time_values_df]) time_idx_start = np.where(time_values_yr == startyear)[0][0] time_idx_end = np.where(time_values_yr == endyear)[0][0] time_values_monthly_subset = time_values_monthly[time_idx_start:time_idx_end + 12] year_idx_start = np.where(time_values_annual == startyear)[0][0] year_idx_end = np.where(time_values_annual == endyear)[0][0] time_values_annual_subset = time_values_annual[year_idx_start:year_idx_end+1] + var_glac_region = ds['runoff_glac_monthly'].values[:,time_idx_start:time_idx_end + 12, 0] var_glac_region_std = ds['runoff_glac_monthly'].values[:,time_idx_start:time_idx_end + 12, 1] - - vol_glac_region = ds['volume_glac_annual'].values[:,year_idx_start:year_idx_end+1,0] - excess_meltwater_reg = excess_meltwater_m3(vol_glac_region) - - melt_glac_region_mwea = ds['melt_glac_monthly'].values[:,time_idx_start:time_idx_end + 12, 0] - rfrz_glac_region_mwea = ds['refreeze_glac_monthly'].values[:,time_idx_start:time_idx_end + 12, 0] - area_glac_region = ds['area_glac_annual'].values[:,year_idx_start:year_idx_end+1,0] - melt_glac_region_m3 = melt_glac_region_mwea * area_glac_region.repeat(12,axis=1) * 10**6 - rfrz_glac_region_m3 = rfrz_glac_region_mwea * area_glac_region.repeat(12,axis=1) * 10**6 - - option_include_offglac = 1 - if option_include_offglac == 1: - var_glac_region += ds['offglac_runoff_monthly'].values[:,time_idx_start:time_idx_end + 12, 0] - var_glac_region_std += ds['offglac_runoff_monthly'].values[:,time_idx_start:time_idx_end + 12, 1] # Merge datasets if region == regions[0]: - glacno = glacno_region var_glac_all = var_glac_region var_glac_all_std = var_glac_region_std - excess_meltwater_all = excess_meltwater_reg - melt_glac_all = melt_glac_region_m3 - rfrz_glac_all = rfrz_glac_region_m3 else: - glacno.extend(glacno_region) var_glac_all = np.concatenate((var_glac_all, var_glac_region), axis=0) var_glac_all_std = np.concatenate((var_glac_all_std, var_glac_region_std), axis=0) - excess_meltwater_all = np.concatenate((excess_meltwater_all, excess_meltwater_reg), axis=0) - melt_glac_all = np.concatenate((melt_glac_all, melt_glac_region_m3), axis=0) - rfrz_glac_all = np.concatenate((rfrz_glac_all, rfrz_glac_region_m3), axis=0) - + ds.close() - - - main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(glac_no = glacno) - - # Groups - groups, group_cn = select_groups(grouping, main_glac_rgi) - subgroups, subgroup_cn = select_groups(subgrouping, main_glac_rgi) - - output_cns = ['watershed', 'runoff_gta', 'runoff_interannual_std_gta', 'runoff_interannual_std_pc', 'std_corr_gta', - 'std_uncorr_gta', 'std_corr_perfect_gta', 'std_corr_perfect_pc', 'melt_gta', - 'melt_interannual_std_gta', 'excess_meltwater_gta', 'excess_meltwater_interannual_std_gta', - 'rfrz_gta', 'rfrz_interannual_std_gta'] - output_df = pd.DataFrame(np.zeros((len(groups),len(output_cns))), columns=output_cns) - output_df['watershed'] = groups +#%% ds_all = {} ds_all_std = {} - print('Mean annual runoff (+/-) 1 std [Gt/yr],', str(startyear), '-', str(endyear),'(water years) from ERA-Interim') + print('Mean annual runoff (+/-) 1 std [Gt/yr],', str(startyear), '-', str(endyear), '(water years) from ERA-Interim') for ngroup, group in enumerate(groups): # for ngroup, group in enumerate(['Yellow']): # Sum volume change for group @@ -6364,9 +4598,6 @@ def __call__(self, value, clip=None): var_group = var_glac_all[group_glac_indices,:].sum(axis=0) var_group_std_pc = var_glac_all_std[group_glac_indices,:].sum(axis=0) - excess_meltwater_group = excess_meltwater_all[group_glac_indices,:].sum(axis=0) - melt_group = melt_glac_all[group_glac_indices,:].sum(axis=0) - rfrz_group = rfrz_glac_all[group_glac_indices,:].sum(axis=0) # Uncertainty associated with volume change based on subgroups # sum standard deviations in each subgroup assuming that they are uncorrelated @@ -6382,14 +4613,8 @@ def __call__(self, value, clip=None): subgroup_std[nsubgroup,:] = var_glac_all_std[subgroup_indices,:].sum(axis=0) var_group_std = (subgroup_std**2).sum(axis=0)**0.5 - # Group's mean annual runoff - group_annual_excess_melt_Gta = excess_meltwater_group.sum() / excess_meltwater_group.shape[0] * (1/1000)**3 - group_annual_excess_melt_Gta_interannual_std = excess_meltwater_group.std() * (1/1000)**3 - group_annual_melt_Gta = melt_group.sum() / (melt_group.shape[0] / 12) * (1/1000)**3 - group_annual_melt_Gta_interannual_std = melt_group.reshape(-1,12).sum(1).std() * (1/1000)**3 - group_annual_rfrz_Gta = rfrz_group.sum() / (rfrz_group.shape[0] / 12) * (1/1000)**3 - group_annual_rfrz_Gta_interannual_std = rfrz_group.reshape(-1,12).sum(1).std() * (1/1000)**3 + # Group's mean annual runoff group_annual_runoff_Gta = var_group.sum() / (var_group.shape[0] / 12) * (1/1000)**3 group_annual_runoff_Gta_interannual_std = var_group.reshape(-1,12).sum(1).std() * (1/1000)**3 group_annual_runoff_Gta_pc = var_group_std_pc.sum() / (var_group_std_pc.shape[0] / 12) * (1/1000)**3 @@ -6401,31 +4626,10 @@ def __call__(self, value, clip=None): ds_all[group] = group_annual_runoff_Gta ds_all_std[group] = group_annual_runoff_Gta_std - output_df.loc[ngroup,'runoff_gta'] = group_annual_runoff_Gta - output_df.loc[ngroup,'runoff_interannual_std_gta'] = group_annual_runoff_Gta_interannual_std - output_df.loc[ngroup,'std_corr_gta'] = group_annual_runoff_Gta_std - output_df.loc[ngroup,'std_uncorr_gta'] = group_annual_runoff_Gta_std_rsos - output_df.loc[ngroup,'std_corr_perfect_gta'] = group_annual_runoff_Gta_pc - output_df.loc[ngroup,'melt_gta'] = group_annual_melt_Gta - output_df.loc[ngroup,'melt_interannual_std_gta'] = group_annual_melt_Gta_interannual_std - output_df.loc[ngroup,'excess_meltwater_gta'] = group_annual_excess_melt_Gta - output_df.loc[ngroup,'excess_meltwater_interannual_std_gta'] = group_annual_excess_melt_Gta_interannual_std - output_df.loc[ngroup,'rfrz_gta'] = group_annual_rfrz_Gta - output_df.loc[ngroup,'rfrz_interannual_std_gta'] = group_annual_rfrz_Gta_interannual_std - print(group, np.round(group_annual_runoff_Gta,3), '+/-', np.round(group_annual_runoff_Gta_std,3), '(', np.round(group_annual_runoff_Gta_std_rsos,3),'for uncorrelated)', '\n all perfectly correlated:', np.round(group_annual_runoff_Gta_pc,3), '\n interannual std:', np.round(group_annual_runoff_Gta_interannual_std,3)) - - output_df['runoff_interannual_std_pc'] = output_df['runoff_interannual_std_gta'] / output_df['runoff_gta'] * 100 - output_df['std_corr_perfect_pc'] = output_df['std_corr_gta'] / output_df['runoff_gta'] * 100 - - output_df.to_csv(input.output_sim_fp + 'watershed_eraint_' + str(time_values_annual[0]) + '-' + - str(time_values_annual[-1]) + '_runoff.csv', index=False) - -#%% - if option_merge_multimodel_datasets == 1: ds1 = xr.open_dataset(netcdf_fp_cmip5 + 'R14_multimodel_rcp45_c2_ba1_100sets_2000_2100.nc') @@ -7083,280 +5287,9 @@ def __call__(self, value, clip=None): figure_fn = 'runoff_multimodel_4rcps.png' fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300, transparent=True) - -#%% -if option_regional_hyps == 1: - rgi_regionsO1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] - rgi_regionsO2 = 'all' - rgi_glac_number = 'all' - - # Set up plot - ncols = 4 - nrows = int(np.ceil(len(rgi_regionsO1)/ncols)) - fig, ax = plt.subplots(nrows, ncols, squeeze=False, sharex=False, sharey=False, - gridspec_kw = {'wspace':0.4, 'hspace':0.4}) - nrow, ncol = 0,0 - - for nregion, region in enumerate(rgi_regionsO1): - main_glac_rgi = modelsetup.selectglaciersrgitable(rgi_regionsO1=[region], - rgi_regionsO2='all',rgi_glac_number='all') - main_glac_rgi.sort_values('Area', inplace=True, ascending=False) - main_glac_rgi.reset_index(inplace=True, drop=True) - main_glac_rgi['cum_area'] = main_glac_rgi.Area.cumsum() - main_glac_rgi['cum_area_%'] = main_glac_rgi.Area.cumsum() - main_glac_rgi['cum_area_%'] = main_glac_rgi.cum_area / main_glac_rgi.cum_area.values[-1] * 100 - - # Plot glacier number vs. cumulative area - ax[nrow,ncol].plot(main_glac_rgi.index.values, main_glac_rgi['cum_area_%'].values, - color='k', linewidth=1, zorder=2, label='plot1') - - ax[nrow,ncol].set_xscale('log') - if main_glac_rgi.shape[0] > 1000: - ax[nrow,ncol].set_xticks([10,100,1000,10000]) - else: - ax[nrow,ncol].set_xticks([10,100,1000]) - - ax[nrow,ncol].set_ylim(0,100) - ax[nrow,ncol].yaxis.set_major_locator(plt.MultipleLocator(20)) - ax[nrow,ncol].yaxis.set_minor_locator(plt.MultipleLocator(5)) - - # Tick parameters - ax[nrow,ncol].yaxis.set_ticks_position('both') - ax[nrow,ncol].tick_params(axis='both', which='major', labelsize=12, direction='inout') - ax[nrow,ncol].tick_params(axis='both', which='minor', labelsize=12, direction='inout') - ax[nrow,ncol].text(0.5,0.95, str(region) + '\n(' + str(main_glac_rgi.shape[0]) + ' glaciers)' + - '\n(' + str(int(main_glac_rgi.cum_area.values[-1])) + 'km2)', - horizontalalignment='center', verticalalignment='top', transform=ax[nrow,ncol].transAxes) - - # Adjust row and column - ncol += 1 - if ncol == ncols: - nrow += 1 - ncol = 0 - -# # Remove extra plots -# n_extras = len(regions)%ncols -# if n_extras > 0: -# for nextra in np.arange(0,n_extras): -# ax[nrow,ncol].axis('off') -# ncol += 1 - - # Example Legend - # Option 1: automatic based on labels -# ax[0,0].legend(loc=(0.05, 0.05), fontsize=10, labelspacing=0.25, handlelength=1, handletextpad=0.25, borderpad=0, -# frameon=False) - # Option 2: manually define legend - #leg_lines = [] - #labels = ['plot1', 'plot2'] - #label_colors = ['k', 'b'] - #for nlabel, label in enumerate(labels): - # line = Line2D([0,1],[0,1], color=label_colors[nlabel], linewidth=1) - # leg_lines.append(line) - #ax[0,0].legend(leg_lines, labels, loc=(0.05,0.05), fontsize=10, labelspacing=0.25, handlelength=1, - # handletextpad=0.25, borderpad=0, frameon=False) - - # X and Y labels - fig.text(0.5, 0.03, 'Glacier Number (by size)', size=12, horizontalalignment='center', verticalalignment='top') - fig.text(0.03, 0.5, 'Cumulative Area (%)', size=12, horizontalalignment='center', verticalalignment='top', - rotation='vertical') - - # Save figure - # figures can be saved in any format (.jpg, .png, .pdf, etc.) - fig.set_size_inches(8, 8) - figure_fp = os.getcwd() + '/../Output/' - if os.path.exists(figure_fp) == False: - os.makedirs(figure_fp) - figure_fn = 'rgi_regions_vs_cumarea.png' - fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300) - - -#%% -# Plot histogram of start dates -if option_startdate == 1: - regions = [13,14,15] - main_glac_rgi = modelsetup.selectglaciersrgitable(rgi_regionsO1=regions, rgi_regionsO2 = 'all', - rgi_glac_number='all') - main_glac_rgi['RefYear'] = [int(str(x)[0:4]) for x in main_glac_rgi.RefDate.values] - main_glac_rgi['RefMonth'] = [int(str(x)[4:6]) for x in main_glac_rgi.RefDate.values] - main_glac_rgi['RefDay'] = [int(str(x)[6:]) for x in main_glac_rgi.RefDate.values] - main_glac_rgi['RefMonth_dec'] = main_glac_rgi['RefMonth'] + main_glac_rgi['RefDay'] / 30 - 1 - main_glac_rgi['RefYear_dec'] = main_glac_rgi['RefYear'] + main_glac_rgi['RefMonth_dec'] / 12 - - print('Mean date:', main_glac_rgi.RefYear_dec.mean()) - - refyear_bins = np.arange(1998,2015) - data = main_glac_rgi['RefYear_dec'].values - hist, bin_edges = np.histogram(data,refyear_bins) # make the histogram - hist = hist/main_glac_rgi.shape[0] * 100 - fig,ax = plt.subplots() - # Plot the histogram heights against integers on the x axis - ax.bar(range(len(hist)),hist,width=1, edgecolor='k') - # Set the ticks to the middle of the bars - ax.set_xticks([0.5+i for i,j in enumerate(hist)]) - # Set the xticklabels to a string that tells us what the bin edges were - ax.set_xticklabels(['{}'.format(refyear_bins[i]) for i,j in enumerate(hist)], rotation=45, ha='right') -# ax.set_xlabel(xlabel, fontsize=16) - ax.set_ylabel('Count (%)', fontsize=12) - # Save figure - fig.set_size_inches(4,3) - fig.savefig(input.output_filepath + 'refyear_hist_HMA.png', bbox_inches='tight', dpi=300) - -#%% -if option_excess_meltwater_diagram == 1: - fig_fp = input.output_sim_fp + 'figures/' - - glacier_mass = np.array([10, 10.5, 9, 8.5, 9, 8, 7.5, 6.5, 7.5, 7, 8, 6, 5, 4.5]) - 4 - excess_meltwater_step_x = np.array([0,1,1,4,4,10,10,11,11,12,12,12]) + 1 - excess_meltwater_step_y = np.array([0,0,1,1,2,2,4,4,5,5,5.5,5.5]) - time = np.array(np.arange(0,len(glacier_mass))) - - - annual_mb = glacier_mass[1:] - glacier_mass[0:-1] - annual_mb_cumsum = np.zeros((len(glacier_mass))) - annual_mb_cumsum[1:] = np.cumsum(annual_mb) - excess_meltwater = np.array([0,1,0,0,1,0,0,0,0,0,2,1,0.5,0]) -# vol_km3 = np.reshape(vol,(-1,len(vol))) / input.density_ice * input.density_water / 1000**3 -# excess_meltwater = excess_meltwater_m3(vol_km3) - - # Create the projection - fig = plt.figure() - gs = mpl.gridspec.GridSpec(100, 1) - ax1 = plt.subplot(gs[0:56,0]) - ax2 = plt.subplot(gs[60:100,0]) -# gs = mpl.gridspec.GridSpec(100, 1) -# ax1 = plt.subplot(gs[0:60,0]) -# ax2 = plt.subplot(gs[71:100,0]) - -# # First subplot (glacier mass and cumulative excess meltwater) -# ax1.plot(time, glacier_mass, color='k', linewidth=1, zorder=2, label='Glacier mass') -## ax1.plot(time, annual_mb_cumsum, color='k', linewidth=1, zorder=2, label='cumulative MB', linestyle='..') -# ax1.set_xlim(0,len(glacier_mass)-1) -# ax1.set_ylim(0,7) -# ax1.set_ylabel('Glacier mass\n(Gt)') -# ax1.yaxis.set_minor_locator(plt.MultipleLocator(1)) -# ax1.yaxis.set_ticks_position('both') -# ax1.tick_params(axis='y', which='both', direction='inout') -# -# ax1b = ax1.twinx() -# ax1b.plot(excess_meltwater_step_x, excess_meltwater_step_y, color='b', linewidth=1, linestyle='--', -# label='Excess meltwater Cumsum') -# ax1b.set_ylim(-1,6) -# ax1b.invert_yaxis() -# ax1b.set_ylabel('Excess meltwater \n(cumulative, Gt)', color='b') -# ax1b.spines['right'].set_color('b') -# ax1b.tick_params(axis='y', colors='b') -# ax1b.yaxis.set_minor_locator(plt.MultipleLocator(1)) -# ax1b.tick_params(axis='y', which='both', direction='inout', color='b') - - # First subplot (glacier mass and cumulative excess meltwater) -# ax1.plot(time, glacier_mass, color='k', linewidth=1, zorder=2, label='Glacier mass') - ax1.plot(time, annual_mb_cumsum, color='k', linewidth=1, zorder=2, label='cumulative MB', linestyle='-') - ax1.set_xlim(0,len(glacier_mass)-1) - ax1.set_ylim(-6,1) - ax1.set_ylabel('Cumulative \nmass balance\n(Gt)') - ax1.yaxis.set_minor_locator(plt.MultipleLocator(1)) - ax1.yaxis.set_ticks_position('both') - ax1.tick_params(axis='y', which='both', direction='inout') - ax1.tick_params(labelbottom=False) - ax1.xaxis.set_minor_locator(plt.MultipleLocator(1)) - ax1.tick_params(axis='x', which='both', direction='inout') - ax1.grid(which='major', axis='both', color='grey', linewidth=0.5, alpha=1) - ax1.grid(which='minor', axis='both', color='grey', linewidth=0.25, alpha=0.5) - - - ax1b = ax1.twinx() - ax1b.plot(excess_meltwater_step_x, excess_meltwater_step_y, color='b', linewidth=2, linestyle='--', - label='Excess meltwater Cumsum') - ax1b.set_ylim(-1,6) - ax1b.invert_yaxis() - ax1b.set_ylabel('Cumulative \nexcess meltwater \n(Gt)', labelpad=12, color='b') - ax1b.spines['right'].set_color('b') - ax1b.tick_params(axis='y', colors='b') - ax1b.yaxis.set_minor_locator(plt.MultipleLocator(1)) - ax1b.tick_params(axis='y', which='both', direction='inout', color='b') - - - # Second subplot (annual mass balance and annual excess meltwater) - ax2.plot(time[1:], annual_mb, color='k', linewidth=1, zorder=2, label='annual mb') - ax2.set_xlim(0,len(glacier_mass)-1) - ax2.set_ylim(-2.5,2.5) - ax2.yaxis.set_major_locator(plt.MultipleLocator(2)) - ax2.yaxis.set_minor_locator(plt.MultipleLocator(1)) - ax2.set_ylabel('Annual \nmass balance \n(Gt)') - ax2.xaxis.set_minor_locator(plt.MultipleLocator(1)) - ax2.tick_params(axis='x', which='both', direction='inout') - ax2.grid(which='major', axis='both', color='grey', linewidth=0.5, alpha=1) - ax2.grid(which='minor', axis='both', color='grey', linewidth=0.25, alpha=0.5) - ax2.set_xlabel('Year') - - ax2b = ax2.twinx() - ax2b.plot(time[1:], excess_meltwater[:-1], color='b', linewidth=1, linestyle='--', label='Excess meltwater') - ax2b.set_ylim(-2.5,2.5) - ax2b.yaxis.set_major_locator(plt.MultipleLocator(2)) - ax2b.yaxis.set_minor_locator(plt.MultipleLocator(1)) - ax2b.set_ylabel('Annual \nexcess meltwater\n(Gt)', color='b') - ax2b.spines['right'].set_color('b') - ax2b.tick_params(axis='y', colors='b') - ax2b.tick_params(axis='y', which='both', direction='inout', color='b') - - # Save figure - fig.set_size_inches(3, 4) - if os.path.exists(fig_fp) == False: - os.makedirs(fig_fp) - figure_fn = 'excess_melwater_diagram.png' - fig.savefig(fig_fp + figure_fn, bbox_inches='tight', dpi=300) #%% EXTRA CODE -#rgi_glac_number_fn = '../SPC_PYGEM/PyGEM/R131415_rgi_glac_number_batch_0.pkl' -#with open(rgi_glac_number_fn, 'rb') as f: -# glac_no = pickle.load(f) -# -##rgi_glac_number_fn = '../SPC_PYGEM/PyGEM/R131415_rgi_glac_number_batch_0_check.pkl' -##with open(rgi_glac_number_fn, 'rb') as f: -## glac_no_check = pickle.load(f) -# -#import spc_split_glaciers -#glac_no_batches = spc_split_glaciers.split_list(glac_no, n=24, option_ordered=0) -# -# -#list_fns = ['R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--1.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--2.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--3.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--4.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--5.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--6.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--7.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--8.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--9.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--10.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--12.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--13.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--14.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--15.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--16.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--18.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--19.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--20.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--21.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--22.nc', -# 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--23.nc'] -####list_fns = ['R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--8.nc', -#### 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch0--10.nc'] -####list_fns = ['R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch7--14.nc', -#### 'R131415_CCSM4_rcp26_c2_ba1_100sets_2000_2100_batch7--16.nc'] -## -#netcdf_fp = input.main_directory + '/../SPC_PYGEM/' -#for i in list_fns: -# ds = xr.open_dataset(netcdf_fp + i) -# df = pd.DataFrame(ds.glacier_table.values, columns=ds.glac_attrs) -# print(str(int(df.loc[0,'O1Region'])) + '.' + str(int(df.loc[0,'glacno'])).zfill(5), -# str(int(df.loc[1,'O1Region'])) + '.' + str(int(df.loc[1,'glacno'])).zfill(5), -# str(int(df.loc[2,'O1Region'])) + '.' + str(int(df.loc[2,'glacno'])).zfill(5)) -## print(str(int(df.loc[df.shape[0]-1,'O1Region'])) + '.' + str(int(df.loc[df.shape[0]-1,'glacno']))) - - -#%% # Code for individual glacier changes mass balance vs. climate # # Multimodel means @@ -7392,310 +5325,4 @@ def __call__(self, value, clip=None): # # #%% # main_glac_rgi['vol_norm'] = vol_norm -# glac_idx = main_glac_rgi[(main_glac_rgi.Area > 1) & (main_glac_rgi.vol_norm < 2)].index.values - -#%% -if option_caldata_compare == 1: - netcdf_fp_era = input.output_sim_fp + 'ERA5/' - - regions = [1] - cal_datasets = ['braun'] - ds_fn = 'R1--all--ERA5_c4_ba1_1sets_1995_2017.nc' - - startyear=1995 - endyear=2017 - wateryear=1 - - output_fp = netcdf_fp_era + 'figures/' - if os.path.exists(output_fp) == False: - os.makedirs(output_fp) - - dates_table = modelsetup.datesmodelrun(startyear=startyear, endyear=endyear, spinupyears=0, - option_wateryear=wateryear) - - # Load glaciers - main_glac_rgi, main_glac_hyps, main_glac_icethickness = load_glacier_data(rgi_regionsO1=regions) - - # Modeled Mass Balance - # Load datasets - ds = xr.open_dataset(netcdf_fp_era + ds_fn) - df = pd.DataFrame(ds.glacier_table.values, columns=ds.glac_attrs) - df['RGIId'] = ['RGI60-' + str(int(df.O1Region.values[x])).zfill(2) + '.' + - str(int(df.glacno.values[x])).zfill(5) for x in df.index.values] - - # Extract time variable - time_values_annual = ds.coords['year_plus1'].values - time_values_monthly = ds.coords['time'].values - # Extract start/end indices for calendar year! - time_values_df = pd.DatetimeIndex(time_values_monthly) - time_values_yr = np.array([x.year for x in time_values_df]) - if input.gcm_wateryear == 1: - time_values_yr = np.array([x.year + 1 if x.month >= 10 else x.year for x in time_values_df]) - time_idx_start = np.where(time_values_yr == startyear)[0][0] - time_idx_end = np.where(time_values_yr == endyear)[0][0] - time_values_monthly_subset = time_values_monthly[time_idx_start:time_idx_end + 12] - year_idx_start = np.where(time_values_annual == startyear)[0][0] - year_idx_end = np.where(time_values_annual == endyear)[0][0] - time_values_annual_subset = time_values_annual[year_idx_start:year_idx_end+1] - - var_glac_region_raw = ds['massbaltotal_glac_monthly'].values[:,time_idx_start:time_idx_end + 12, 0] - var_glac_region_raw_std = ds['massbaltotal_glac_monthly'].values[:,time_idx_start:time_idx_end + 12, 1] - area_glac_region = np.repeat(ds['area_glac_annual'].values[:,year_idx_start:year_idx_end+1,0], 12, axis=1) - - # Area average - volchg_monthly_glac_region = var_glac_region_raw - volchg_monthly_glac_region_std = var_glac_region_raw_std - - # Merge datasets - var_glac_all = volchg_monthly_glac_region - var_glac_all_std = volchg_monthly_glac_region_std - area_glac_all = area_glac_region - df_all = df - - # Remove RGIIds from main_glac_rgi that are not in the model runs - rgiid_df = list(df_all.RGIId.values) - rgiid_all = list(main_glac_rgi.RGIId.values) - rgi_idx = [rgiid_all.index(x) for x in rgiid_df] - main_glac_rgi = main_glac_rgi.loc[rgi_idx,:] - main_glac_rgi.reset_index(inplace=True, drop=True) - - #%% - # Calibration data - cal_data = pd.DataFrame() - for dataset in cal_datasets: - cal_subset = class_mbdata.MBData(name=dataset) - cal_subset_data = cal_subset.retrieve_mb(main_glac_rgi, main_glac_hyps, dates_table) - cal_data = cal_data.append(cal_subset_data, ignore_index=True) - cal_data = cal_data.sort_values(['glacno', 't1_idx']) - cal_data.reset_index(drop=True, inplace=True) - - #%% - # Link glacier index number from main_glac_rgi to cal_data to facilitate grabbing the data - glacnodict = dict(zip(main_glac_rgi['RGIId'], main_glac_rgi.index.values)) - cal_data['glac_idx'] = cal_data['RGIId'].map(glacnodict) - - # Update main_glac_rgi and simulation datasets to be consistent with cal_data - cal_data_idx = list(cal_data.glac_idx.values) - main_glac_rgi = main_glac_rgi.loc[cal_data_idx,:] - main_glac_rgi.reset_index(inplace=True, drop=True) - var_glac_all = volchg_monthly_glac_region[cal_data_idx,:] - var_glac_all_std = volchg_monthly_glac_region_std[cal_data_idx,:] - area_glac_all = area_glac_region[cal_data_idx,:] - df_all = df_all.loc[cal_data_idx,:] - cal_data.reset_index(inplace=True, drop=True) - - #%% - cal_data['mb_mwe_era'] = np.nan - cal_data['mb_mwea_era'] = np.nan - cal_data['mb_mwe_era_std'] = np.nan - for nglac in list(cal_data.index.values): - glac_idx = nglac - t1_idx = int(cal_data.loc[nglac,'t1_idx']) - t2_idx = int(cal_data.loc[nglac,'t2_idx']) - t1 = cal_data.loc[nglac,'t1'] - t2 = cal_data.loc[nglac,'t2'] - cal_data.loc[nglac,'mb_mwe_era'] = var_glac_all[glac_idx, t1_idx:t2_idx].sum() -# cal_data.loc[nglac,'mb_mwe_era_std'] = var_glac_all_std[glac_idx, t1_idx:t2_idx].sum() -# cal_data.loc[nglac,'mb_mwe_era_std_rsos'] = ((var_glac_all_std[glac_idx, t1_idx:t2_idx]**2).sum())**0.5 - - cal_data['time_difference'] = cal_data['t2'] - cal_data['t1'] - cal_data['mb_mwea_era'] = cal_data['mb_mwe_era'] / (cal_data['t2'] - cal_data['t1']) -# cal_data['mb_mwea_era_std'] = cal_data['mb_mwe_era_std'] / (cal_data['t2'] - cal_data['t1']) -# cal_data['mb_mwea_era_std_rsos'] = cal_data['mb_mwe_era_std_rsos'] / (cal_data['t2']-cal_data['t1']) - cal_data['mb_mwea'] = cal_data['mb_mwe'] / (cal_data['t2'] - cal_data['t1']) - cal_data['mb_mwea_std'] = cal_data['mb_mwe_err'] / (cal_data['t2'] - cal_data['t1']) - cal_data['mb_mwea_dif'] = cal_data['mb_mwea_era'] - cal_data['mb_mwea'] - cal_data['zscore'] = (cal_data['mb_mwea_era'] - cal_data['mb_mwea']) / cal_data['mb_mwea_std'] - - #%% - # Loop through conditions: - condition_dict = OrderedDict() - condition_dict['All']= cal_data.index.values - condition_dict['All w data'] = cal_data['obs_type'] == 'mb_geo' - condition_dict['All extrapolated'] = cal_data['obs_type'] == 'mb_geo_extrapolated' - - stats_cns = ['group', 'count', 'rmse', 'r', 'slope', 'intercept', 'p-value', 'mae'] - group_stats = pd.DataFrame(np.zeros((len(condition_dict.keys()), len(stats_cns))), columns=stats_cns) - group_stats['group'] = condition_dict.keys() - - for ncondition, cal_condition in enumerate(condition_dict.keys()): -# for ncondition, cal_condition in enumerate(['Glaciological (annual)']): - # Statistics for comparison - cal_data_subset = cal_data.loc[condition_dict[cal_condition],:].copy() - print('\n',cal_condition, cal_data_subset.shape[0]) - - # Root-mean-square-deviation - rmse = (np.sum((cal_data_subset.mb_mwea - cal_data_subset.mb_mwea_era)**2) / cal_data_subset.shape[0])**0.5 - print(' RMSE:', np.round(rmse,2)) - # Correlation - slope, intercept, r_value, p_value, std_err = linregress(cal_data_subset.mb_mwea, cal_data_subset.mb_mwea_era) - print(' r_value =', np.round(r_value,2), 'slope = ', np.round(slope,2), - 'intercept = ', np.round(intercept,2), 'p_value = ', np.round(p_value,6)) - # Mean absolute error - mae = np.mean(np.absolute(cal_data_subset.mb_mwea - cal_data_subset.mb_mwea_era)) - print(' mean absolute error:', np.round(mae,2)) - # Record stats - group_stats.loc[ncondition, ['count', 'rmse', 'r', 'slope', 'intercept', 'p-value', 'mae']] = ( - [cal_data_subset.shape[0], rmse, r_value, slope, intercept, p_value, mae]) - - - cal_data_subset['dif_mb_mwea'] = cal_data_subset['mb_mwea'] - cal_data_subset['mb_mwea_era'] - print(' Difference stats: \n Mean (+/-) std [mwea]:', - np.round(cal_data_subset['dif_mb_mwea'].mean(),2), '+/-', np.round(cal_data_subset['dif_mb_mwea'].std(),2), - 'count:', cal_data_subset.shape[0], - '\n Median (+/-) std [mwea]:', - np.round(cal_data_subset['dif_mb_mwea'].median(),2), '+/- XXX', -# np.round(cal_data_subset['dif_mb_mwea'].std(),2), -# '\n Mean standard deviation (correlated):',np.round(cal_data_subset['mb_mwea_era_std'].mean(),2), -# '\n Mean standard deviation (uncorrelated):',np.round(cal_data_subset['mb_mwea_era_std_rsos'].mean(),2) - ) - - group_stats.to_csv(output_fp + 'cal_compare_stats.csv', index=False) - - #%% - # ===== PLOT ===== - fig, ax = plt.subplots(1, 2, squeeze=False, figsize=(10,8), gridspec_kw = {'wspace':0.3, 'hspace':0}) - - datatypes = ['mb_geo', 'mb_geo_extrapolated'] - cmap = 'RdYlBu_r' - norm = plt.Normalize(startyear, endyear) - - for nplot, datatype in enumerate(datatypes): -# for nplot, datatype in enumerate(['mb_geo']): - cal_data_plot = cal_data[cal_data['obs_type'] == datatype].copy() - cal_data_plot.reset_index(drop=True, inplace=True) - sizes = [0.01,1,5,50] - sizes_str = [str(x) for x in sizes] - s_sizes = [1,4,10,20] - cal_data_plot['circ_size'] = s_sizes[0] - cal_data_plot.loc[cal_data_plot['area_km2'] > sizes[1], 'circ_size'] = s_sizes[1] - cal_data_plot.loc[cal_data_plot['area_km2'] > sizes[2], 'circ_size'] = s_sizes[2] - cal_data_plot.loc[cal_data_plot['area_km2'] > sizes[3], 'circ_size'] = s_sizes[3] - - if datatype in ['mb_geo', 'mb_geo_extrapolated']: - # All glaciers - a = ax[0,nplot].scatter(cal_data_plot.mb_mwea.values, cal_data_plot.mb_mwea_era.values, - color='k', zorder=3, -# s=15, - s=cal_data_plot.circ_size.values, - marker='o', linewidth=0.25) - a.set_facecolor('none') - ymin = -5 - ymax = 3.5 - xmin = -5 - xmax = 3.5 - ax[0,nplot].set_xlim(xmin,xmax) - ax[0,nplot].set_ylim(ymin,ymax) - ax[0,nplot].plot([np.min([xmin,ymin]),np.max([xmax,ymax])], [np.min([xmin,ymin]),np.max([xmax,ymax])], - color='k', linewidth=0.25, zorder=1) - - ax[0,nplot].set_ylabel('$\mathregular{B_{mod}}$ (m w.e. $\mathregular{yr^{-1}}$)', labelpad=0, size=12) - ax[0,nplot].set_xlabel('$\mathregular{B_{geo}}$ (m w.e. $\mathregular{yr^{-1}}$)', labelpad=0, size=12) - # Add text - ax[0,nplot].text(0.05, 0.95, 'E', va='center', size=12, fontweight='bold', transform=ax[0,nplot].transAxes) - ax[0,nplot].text(0.7, 0.1, 'n=' + str(cal_data_plot.shape[0]) + '\n' + - str(cal_data_plot.glacno.unique().shape[0]) + ' glaciers', va='center', ha='center', - size=12, transform=ax[0,nplot].transAxes) - slope, intercept, r_value, p_value, std_err = linregress(cal_data_plot.mb_mwea.values, - cal_data_plot.mb_mwea_era.values) - print(datatype, 'r_value [mwea] =', r_value) - - # SIZE LEGEND - marker_linecolor='k' - marker_linewidth = 0.25 - circ1 = ax[0,nplot].scatter([0],[0], s=s_sizes[0], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ1.set_facecolor('none') - circ2 = ax[0,nplot].scatter([0],[0], s=s_sizes[1], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ2.set_facecolor('none') - circ3 = ax[0,nplot].scatter([0],[0], s=s_sizes[2], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ3.set_facecolor('none') - circ4 = ax[0,nplot].scatter([0],[0], s=s_sizes[3], marker='o', color='grey', - edgecolor=marker_linecolor, linewidth=marker_linewidth) - circ4.set_facecolor('none') - leg_fontsize = 10 - legend=fig.legend([circ1,circ2,circ3,circ4], sizes_str, - scatterpoints=1, ncol=1, - loc='upper left', bbox_to_anchor=(0.865,0.63), - fontsize=leg_fontsize, labelspacing=0.3, columnspacing=0,handletextpad=0, handlelength=1, - borderpad=0.2, framealpha=0, borderaxespad=0.2, - ) - fig.text(0.94, 0.62, 'Area\n(km$^{2}$)', ha='center', va='center', size=leg_fontsize) - - # Save figure - fig.set_size_inches(6.75,3) - fig_fn = 'cal_compare.png' - fig.savefig(output_fp + fig_fn, bbox_inches='tight', dpi=600) - - -#thickness_fn = 'thickness_m_01_Farinotti2019_10m.csv' -#hyps_fn = 'area_km2_01_Farinotti2019_10m.csv' -#width_fn = 'width_km_01_Farinotti2019_10m.csv' -#slope_fn = 'slope_deg_01_Farinotti2019_10m.csv' -#length_fn = 'length_km_01_Farinotti2019_10m.csv' -# -#thickness = pd.read_csv(input.hyps_filepath + thickness_fn) -#thickness_cns = list(thickness.columns) -#thickness_cns.remove('RGIId') -#thickness_values = thickness.loc[:,thickness_cns].values -#print('thickness < 0', np.where(thickness_values < 0)) -#thickness_values[thickness_values < 0] = 0 -# -#thickness_v2 = thickness.copy() -#thickness_v2.loc[:,thickness_cns] = thickness_values -#thickness_v2.to_csv(input.hyps_filepath + 'updated/' + thickness_fn, index=False) -# -#hyps = pd.read_csv(input.hyps_filepath + hyps_fn) -#hyps_values = hyps.loc[:,thickness_cns].values -#hyps_values[thickness_values == 0] = 0 -#print('hyps < 0', np.where(hyps_values < 0)) -# -#hyps_v2 = hyps.copy() -#hyps_v2.loc[:,thickness_cns] = hyps_values -#hyps_v2.to_csv(input.hyps_filepath + 'updated/' + hyps_fn, index=False) -# -# -#width = pd.read_csv(input.hyps_filepath + width_fn) -#width_values = width.loc[:,thickness_cns].values -#width_values[thickness_values == 0] = 0 -#print('width < 0', np.where(width_values < 0)) -# -#width_v2 = width.copy() -#width_v2.loc[:,thickness_cns] = width_values -#width_v2.to_csv(input.hyps_filepath + 'updated/' + width_fn, index=False) -# -#slope = pd.read_csv(input.hyps_filepath + slope_fn) -#slope_values = slope.loc[:,thickness_cns].values -#slope_values[thickness_values == 0] = 0 -#print('slope < 0', np.where(slope_values < 0)) -# -#slope_v2 = slope.copy() -#slope_v2.loc[:,thickness_cns] = slope_values -#slope_v2.to_csv(input.hyps_filepath + 'updated/' + slope_fn, index=False) -# -#length = pd.read_csv(input.hyps_filepath + length_fn) -#length_values = length.loc[:,thickness_cns].values -#length_values[thickness_values == 0] = 0 -#print('length < 0', np.where(length_values < 0)) -# -#length_v2 = length.copy() -#length_v2.loc[:,thickness_cns] = length_values -#length_v2.to_csv(input.hyps_filepath + 'updated/' + length_fn, index=False) - - - - - - - - - - - - - - - - \ No newline at end of file +# glac_idx = main_glac_rgi[(main_glac_rgi.Area > 1) & (main_glac_rgi.vol_norm < 2)].index.values \ No newline at end of file diff --git a/class_climate.py b/class_climate.py index 2b3a5f11..0e34d909 100644 --- a/class_climate.py +++ b/class_climate.py @@ -235,10 +235,11 @@ def importGCMvarnearestneighbor_xarray(self, filename, vn, main_glac_rgi, dates_ glac_variable_series = np.zeros((main_glac_rgi.shape[0],dates_table.shape[0])) # Determine the correct time indices if self.timestep == 'monthly': - start_idx = (np.where(pd.Series(data[self.time_vn]).apply(lambda x: x.strftime('%Y-%m')) == - dates_table['date'].apply(lambda x: x.strftime('%Y-%m'))[0]))[0][0] - end_idx = (np.where(pd.Series(data[self.time_vn]).apply(lambda x: x.strftime('%Y-%m')) == - dates_table['date'] + start_idx = (np.where(pd.Series(data[self.time_vn]) + .apply(lambda x: x.strftime('%Y-%m')) == dates_table['date'] + .apply(lambda x: x.strftime('%Y-%m'))[0]))[0][0] + end_idx = (np.where(pd.Series(data[self.time_vn]) + .apply(lambda x: x.strftime('%Y-%m')) == dates_table['date'] .apply(lambda x: x.strftime('%Y-%m'))[dates_table.shape[0] - 1]))[0][0] # np.where finds the index position where to values are equal # pd.Series(data.variables[gcm_time_varname]) creates a pandas series of the time variable associated with @@ -296,18 +297,15 @@ def importGCMvarnearestneighbor_xarray(self, filename, vn, main_glac_rgi, dates_ # Perform corrections to the data if necessary # Surface air temperature corrections - if vn in ['tas', 't2m', 'T2']: + if (vn == 'tas') or (vn == 't2m') or (vn == 'T2'): if 'units' in data[vn].attrs and data[vn].attrs['units'] == 'K': # Convert from K to deg C glac_variable_series = glac_variable_series - 273.15 else: print('Check units of air temperature from GCM is degrees C.') - elif vn in ['t2m_std']: - if 'units' in data[vn].attrs and data[vn].attrs['units'] not in ['C', 'K']: - print('Check units of air temperature standard deviation from GCM is degrees C or K') # Precipitation corrections # If the variable is precipitation - elif vn in ['pr', 'tp', 'TOTPRECIP']: + elif (vn == 'pr') or (vn == 'tp') or (vn == 'TOTPRECIP'): # If the variable has units and those units are meters (ERA Interim) if 'units' in data[vn].attrs and data[vn].attrs['units'] == 'm': pass @@ -333,24 +331,21 @@ def importGCMvarnearestneighbor_xarray(self, filename, vn, main_glac_rgi, dates_ #%% Testing if __name__ == '__main__': -## gcm = GCM(name='CanESM2', rcp_scenario='rcp85') +# gcm = GCM(name='CanESM2', rcp_scenario='rcp85') # gcm = GCM(name='ERA5') -## gcm = GCM(name='ERA-Interim') -# -# main_glac_rgi = modelsetup.selectglaciersrgitable(rgi_regionsO1=input.rgi_regionsO1, rgi_regionsO2 = 'all', -# rgi_glac_number=input.rgi_glac_number) -# dates_table = modelsetup.datesmodelrun(startyear=1980, endyear=2017, spinupyears=0, -# option_wateryear=input.gcm_wateryear) -# -# # Air temperature [degC], Precipitation [m], Elevation [masl], Lapse rate [K m-1] -# gcm_temp, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn, gcm.temp_vn, main_glac_rgi, dates_table) -# gcm_prec, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn, gcm.prec_vn, main_glac_rgi, dates_table) -# gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn, main_glac_rgi) -# if gcm.name == 'ERA-Interim' or gcm.name == 'ERA5': -# gcm_lr, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.lr_fn, gcm.lr_vn, main_glac_rgi, dates_table) -# if gcm.name == 'ERA5': -# gcm_tempstd, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.tempstd_fn, gcm.tempstd_vn, main_glac_rgi, -# dates_table) + gcm = GCM(name='ERA-Interim') + + main_glac_rgi = modelsetup.selectglaciersrgitable(rgi_regionsO1=input.rgi_regionsO1, rgi_regionsO2 = 'all', + rgi_glac_number=input.rgi_glac_number) + dates_table = modelsetup.datesmodelrun(startyear=1980, endyear=2017, spinupyears=0, + option_wateryear=input.gcm_wateryear) + + # Air temperature [degC], Precipitation [m], Elevation [masl], Lapse rate [K m-1] + gcm_temp, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn, gcm.temp_vn, main_glac_rgi, dates_table) + gcm_prec, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn, gcm.prec_vn, main_glac_rgi, dates_table) + gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn, main_glac_rgi) + if gcm.name == 'ERA-Interim' or gcm.name == 'ERA5': + gcm_lr, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.lr_fn, gcm.lr_vn, main_glac_rgi, dates_table) # else: # gcm_lr = np.tile(ref_lr_monthly_avg, int(gcm_temp.shape[1]/12)) # # COAWST data has two domains, so need to merge the two domains @@ -368,18 +363,4 @@ def importGCMvarnearestneighbor_xarray(self, filename, vn, main_glac_rgi, dates_ # ~(input.coawst_d02_lon_min <= glac_lon <= input.coawst_d02_lon_max)): # gcm_prec[glac,:] = gcm_prec_d01[glac,:] # gcm_temp[glac,:] = gcm_temp_d01[glac,:] -# gcm_elev[glac] = gcm_elev_d01[glac] - - #%% -# # Get range of dates -# rcp_scenario = 'rcp85' -# gcm_names = ['bcc-csm1-1', 'CanESM2', 'CESM1-CAM5', 'CCSM4', 'CNRM-CM5', 'CSIRO-Mk3-6-0', 'FGOALS-g2', 'GFDL-CM3', -# 'GFDL-ESM2G', 'GFDL-ESM2M', 'GISS-E2-R', 'HadGEM2-ES', 'IPSL-CM5A-LR', 'IPSL-CM5A-MR', 'MIROC-ESM', -# 'MIROC-ESM-CHEM', 'MIROC5', 'MPI-ESM-LR', 'MPI-ESM-MR', 'MRI-CGCM3', 'NorESM1-M', 'NorESM1-ME'] -# for gcm_name in gcm_names: -# print(gcm_name) -# ds = xr.open_dataset(input.cmip5_fp_var_prefix + rcp_scenario + input.cmip5_fp_var_ending + -# 'tas' + '_mon_' + gcm_name + '_' + rcp_scenario + '_r1i1p1_native.nc') -# -# print(' ', ds.time[0].values, -# '\n ', ds.time[-1].values) \ No newline at end of file +# gcm_elev[glac] = gcm_elev_d01[glac] \ No newline at end of file diff --git a/class_mbdata.py b/class_mbdata.py index f7f4b2a2..e9ee8b9c 100644 --- a/class_mbdata.py +++ b/class_mbdata.py @@ -4,7 +4,6 @@ import pandas as pd import numpy as np import calendar -import collections import datetime # Local libraries import pygem_input as input @@ -42,26 +41,6 @@ def __init__(self, self.t2_cn = input.shean_time2_cn self.area_cn = input.shean_area_cn - elif self.name == 'berthier': - self.ds_fp = input.berthier_fp - self.ds_fn = input.berthier_fn - self.rgi_glacno_cn = input.berthier_rgi_glacno_cn - self.mb_mwea_cn = input.berthier_mb_cn - self.mb_mwea_err_cn = input.berthier_mb_err_cn - self.t1_cn = input.berthier_time1_cn - self.t2_cn = input.berthier_time2_cn - self.area_cn = input.berthier_area_cn - - elif self.name == 'braun': - self.ds_fp = input.braun_fp - self.ds_fn = input.braun_fn - self.rgi_glacno_cn = input.braun_rgi_glacno_cn - self.mb_mwea_cn = input.braun_mb_cn - self.mb_mwea_err_cn = input.braun_mb_err_cn - self.t1_cn = input.braun_time1_cn - self.t2_cn = input.braun_time2_cn - self.area_cn = input.braun_area_cn - elif self.name == 'mcnabb': self.ds_fp = input.mcnabb_fp self.ds_fn = input.mcnabb_fn @@ -178,7 +157,7 @@ def retrieve_mb(self, main_glac_rgi, main_glac_hyps, dates_table): # DATASET SPECIFIC CALCULATIONS # ===== SHEAN GEODETIC DATA ===== - if self.name in ['shean', 'berthier', 'braun']: + if self.name == 'shean': ds['z1_idx'] = ( (main_glac_hyps.iloc[ds['glacno'].map(glacnodict)].values != 0).argmax(axis=1).astype(int)) ds['z2_idx'] = ( @@ -193,31 +172,26 @@ def retrieve_mb(self, main_glac_rgi, main_glac_hyps, dates_table): main_glac_hyps.iloc[glacnodict[ds.loc[x,'glacno']], ds.loc[x,'z1_idx']:ds.loc[x,'z2_idx']+1].sum()) # Time indices - ds['t1'] = ds[self.t1_cn].astype(np.float64) - ds['t2'] = ds[self.t2_cn].astype(np.float64) + ds['t1'] = ds[self.t1_cn] + ds['t2'] = ds[self.t2_cn] ds['t1_year'] = ds['t1'].astype(int) ds['t1_month'] = round(ds['t1'] % ds['t1_year'] * 12 + 1) - ds.loc[ds['t1_month'] == 13, 't1_year'] = ds.loc[ds['t1_month'] == 13, 't1_year'] + 1 - ds.loc[ds['t1_month'] == 13, 't1_month'] = 1 # add 1 to account for the fact that January starts with value of 1 ds['t2_year'] = ds['t2'].astype(int) ds['t2_month'] = round(ds['t2'] % ds['t2_year'] * 12) - ds.loc[ds['t2_month'] == 0, 't2_month'] = 1 # do not need to add one for t2 because we want the last full time step # Remove data with dates outside of calibration period year_decimal_min = dates_table.loc[0,'year'] + dates_table.loc[0,'month'] / 12 year_decimal_max = (dates_table.loc[dates_table.shape[0]-1,'year'] + (dates_table.loc[dates_table.shape[0]-1,'month'] + 1) / 12) ds = ds[ds['t1_year'] + ds['t1_month'] / 12 >= year_decimal_min] - ds = ds[ds['t2_year'] + ds['t2_month'] / 12 < year_decimal_max] + ds = ds[ds['t2_year'] + ds['t2_month'] / 12 <= year_decimal_max] ds.reset_index(drop=True, inplace=True) # Determine time indices (exclude spinup years, since massbal fxn discards spinup years) ds['t1_idx'] = np.nan ds['t2_idx'] = np.nan for x in range(ds.shape[0]): -# if x == 10539: -# print(x, ds.loc[x,'RGIId'], ds.loc[x,'t1'], ds.loc[x,'t1_month'], ds.loc[x,'t2_month']) ds.loc[x,'t1_idx'] = (dates_table[(ds.loc[x, 't1_year'] == dates_table['year']) & (ds.loc[x, 't1_month'] == dates_table['month'])].index.values[0]) ds.loc[x,'t2_idx'] = (dates_table[(ds.loc[x, 't2_year'] == dates_table['year']) & @@ -229,65 +203,12 @@ def retrieve_mb(self, main_glac_rgi, main_glac_hyps, dates_table): # # Total mass change [Gt] # ds['mb_gt'] = ds[self.mb_vol_cn] * (ds['t2'] - ds['t1']) * (1/1000)**3 * input.density_water / 1000 # ds['mb_gt_err'] = ds[self.mb_vol_err_cn] * (ds['t2'] - ds['t1']) * (1/1000)**3 * input.density_water / 1000 - if 'obs_type' not in list(ds.columns.values): - # Observation type - ds['obs_type'] = 'mb_geo' + # Observation type + ds['obs_type'] = 'mb_geo' # Add columns with nan for things not in list ds_addcols = [x for x in ds_output_cols if x not in ds.columns.values] for colname in ds_addcols: ds[colname] = np.nan - -# # ===== BERTHIER ===== -# if self.name == 'berthier': -# ds['z1_idx'] = ( -# (main_glac_hyps.iloc[ds['glacno'].map(glacnodict)].values != 0).argmax(axis=1).astype(int)) -# ds['z2_idx'] = ( -# (main_glac_hyps.iloc[ds['glacno'].map(glacnodict)].values.cumsum(1)).argmax(axis=1).astype(int)) -# # Lower and upper bin elevations [masl] -# ds['z1'] = elev_bins[ds['z1_idx'].values] - elev_bin_interval/2 -# ds['z2'] = elev_bins[ds['z2_idx'].values] + elev_bin_interval/2 -# # Area [km2] -# ds['area_km2'] = np.nan -# for x in range(ds.shape[0]): -# ds.loc[x,'area_km2'] = ( -# main_glac_hyps.iloc[glacnodict[ds.loc[x,'glacno']], -# ds.loc[x,'z1_idx']:ds.loc[x,'z2_idx']+1].sum()) -# # Time indices -# ds['t1'] = ds[self.t1_cn] -# ds['t2'] = ds[self.t2_cn] -# print(ds) -# ds['t1_year'] = ds['t1'].astype(int) -# ds['t1_month'] = round(ds['t1'] % ds['t1_year'] * 12 + 1) -# # add 1 to account for the fact that January starts with value of 1 -# ds['t2_year'] = ds['t2'].astype(int) -# ds['t2_month'] = round(ds['t2'] % ds['t2_year'] * 12) -# # do not need to add one for t2 because we want the last full time step -# # Remove data with dates outside of calibration period -# year_decimal_min = dates_table.loc[0,'year'] + dates_table.loc[0,'month'] / 12 -# year_decimal_max = (dates_table.loc[dates_table.shape[0]-1,'year'] + -# (dates_table.loc[dates_table.shape[0]-1,'month'] + 1) / 12) -# ds = ds[ds['t1_year'] + ds['t1_month'] / 12 >= year_decimal_min] -# ds = ds[ds['t2_year'] + ds['t2_month'] / 12 <= year_decimal_max] -# ds.reset_index(drop=True, inplace=True) -# # Determine time indices (exclude spinup years, since massbal fxn discards spinup years) -# ds['t1_idx'] = np.nan -# ds['t2_idx'] = np.nan -# for x in range(ds.shape[0]): -# ds.loc[x,'t1_idx'] = (dates_table[(ds.loc[x, 't1_year'] == dates_table['year']) & -# (ds.loc[x, 't1_month'] == dates_table['month'])].index.values[0]) -# ds.loc[x,'t2_idx'] = (dates_table[(ds.loc[x, 't2_year'] == dates_table['year']) & -# (ds.loc[x, 't2_month'] == dates_table['month'])].index.values[0]) -# ds['t1_idx'] = ds['t1_idx'].astype(int) -# # Specific mass balance [mwea] -# print(ds[self.mb_mwea_cn]) -# ds['mb_mwe'] = ds[self.mb_mwea_cn] * (ds['t2'] - ds['t1']) -# ds['mb_mwe_err'] = ds[self.mb_mwea_err_cn] * (ds['t2'] - ds['t1']) -# # Observation type -# ds['obs_type'] = 'mb_geo' -# # Add columns with nan for things not in list -# ds_addcols = [x for x in ds_output_cols if x not in ds.columns.values] -# for colname in ds_addcols: -# ds[colname] = np.nan # ===== BRUN GEODETIC DATA ===== elif self.name == 'brun': @@ -850,69 +771,18 @@ def retrieve_mb(self, main_glac_rgi, main_glac_hyps, dates_table): ds_output.reset_index(drop=True, inplace=True) return ds_output - -def select_best_mb(cal_data): - """ - Retrieve 'best' mass balance (observed > extrapolated) and longest time period - - Returns - ------- - cal_data_best : pandas dataframe - dataframe of 'best' mass balance observations and other relevant information for calibration - """ - cal_data['dt'] = cal_data['t2'] - cal_data['t1'] - rgiids = list(cal_data.RGIId.values) - rgiids_count = collections.Counter(rgiids) - rgiids_multiple = [] - rgiids_single_idx = [] - cal_data_rgiids_all = list(cal_data.RGIId.values) - for x in rgiids_count: - if rgiids_count[x] > 1: - rgiids_multiple.append(x) - else: - rgiids_single_idx.append(cal_data_rgiids_all.index(x)) - rgiids_multiple = sorted(rgiids_multiple) - rgiids_single_idx = sorted(rgiids_single_idx) - - # Select all data with single value - cal_data_best = cal_data.loc[rgiids_single_idx,:] - - # Append 'best' value for those with multiple observations - for rgiid in rgiids_multiple: - cal_data_multiple = cal_data[cal_data['RGIId'] == rgiid] - # Select observations over extrapolated values - if 'mb_geo' in list(cal_data_multiple.obs_type.values): - cal_data_multiple = cal_data_multiple[cal_data_multiple.obs_type == 'mb_geo'] - # Select longest time series - cal_data_append = cal_data_multiple[cal_data_multiple.dt == cal_data_multiple.dt.max()] - - cal_data_best = pd.concat([cal_data_best, cal_data_append], axis=0) - - cal_data_best = cal_data_best.sort_values(by=['RGIId']) - cal_data_best.reset_index(inplace=True, drop=True) - - return cal_data_best - #%% Testing if __name__ == '__main__': # Glacier selection - rgi_regionsO1 = [1] - rgi_glac_number = 'all' + rgi_regionsO1 = [1, 13, 15] + rgi_glac_number = input.rgi_glac_number glac_no = input.glac_no - startyear = 1950 + startyear = 1970 endyear = 2018 -# # Select glaciers -# for rgi_regionsO1 in [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]: -# main_glac_rgi = modelsetup.selectglaciersrgitable(rgi_regionsO1=[rgi_regionsO1], rgi_regionsO2 = 'all', -# rgi_glac_number='all') -# marine = main_glac_rgi[main_glac_rgi['TermType'] == 1] -# lake = main_glac_rgi[main_glac_rgi['TermType'] == 2] -# print('Region ' + str(rgi_regionsO1) + ':') -# print(' marine:', np.round(marine.Area.sum() / main_glac_rgi.Area.sum() * 100,0)) -# print(' lake:', np.round(lake.Area.sum() / main_glac_rgi.Area.sum() * 100,0)) + # Select glaciers main_glac_rgi = modelsetup.selectglaciersrgitable(rgi_regionsO1=rgi_regionsO1, rgi_regionsO2 = 'all', rgi_glac_number=rgi_glac_number, glac_no=input.glac_no) # Glacier hypsometry [km**2], total area @@ -924,121 +794,108 @@ def select_best_mb(cal_data): elev_bins = main_glac_hyps.columns.values.astype(int) elev_bin_interval = elev_bins[1] - elev_bins[0] +# # Testing +# mb1 = MBData(name='larsen') +## mb1 = MBData(name='mauer') +## mb1 = MBData(name='cogley') +# ds_output = mb1.retrieve_mb(main_glac_rgi, main_glac_hyps, dates_table) #%% # cal_datasets = ['shean'] -# cal_datasets = ['braun', 'mcnabb', 'larsen', 'berthier'] -# cal_datasets = ['braun', 'larsen', 'mcnabb'] - cal_datasets = ['braun'] + cal_datasets = ['larsen'] # cal_datasets = ['shean', 'mauer', 'wgms_d', 'wgms_ee', 'cogley', 'mcnabb', 'larsen'] # cal_datasets = ['group'] cal_data = pd.DataFrame() for dataset in cal_datasets: + print(dataset) cal_subset = MBData(name=dataset) cal_subset_data = cal_subset.retrieve_mb(main_glac_rgi, main_glac_hyps, dates_table) cal_data = cal_data.append(cal_subset_data, ignore_index=True) - - # Count unique glaciers and fraction of total area - glacno_unique = list(cal_subset_data.glacno.unique()) - main_glac_rgi_cal = modelsetup.selectglaciersrgitable(glac_no = glacno_unique) - print(dataset, '- glacier area covered: ', - np.round(main_glac_rgi_cal.Area.sum() / main_glac_rgi.Area.sum() * 100,1),'%') - cal_data = cal_data.sort_values(['glacno', 't1_idx']) cal_data.reset_index(drop=True, inplace=True) - # Count unique glaciers and fraction of total area - if len(cal_datasets) > 1: - glacno_unique = list(cal_data.glacno.unique()) - main_glac_rgi_cal = modelsetup.selectglaciersrgitable(glac_no = glacno_unique) - print('All datasets glacier area covered: ', - np.round(main_glac_rgi_cal.Area.sum() / main_glac_rgi.Area.sum() * 100,1),'%') - -# # Export 'best' dataset -# cal_data_best = select_best_mb(cal_data) -# cal_data_best = cal_data_best.drop(['group_name', 'sla_m', 'WGMS_ID'], axis=1) -# cal_data_best['mb_mwea'] = cal_data_best.mb_mwe / cal_data_best.dt -# cal_data_best['mb_mwea_sigma'] = cal_data_best.mb_mwe_err / cal_data_best.dt -# cal_data_best.to_csv(input.braun_fp + 'braun_AK_all_20190924_wlarsen_mcnabb_best.csv', index=False) - +# #%% +# # Count unique glaciers and fraction of total area +# rgiid_unique = list(cal_data.RGIId.unique()) +# rgiid_unique_idx = [] +# for rgiid in rgiid_unique: +# rgiid_unique_idx.append(np.where(main_glac_rgi.RGIId.values == rgiid)[0][0]) +# print('Glacier area covered: ', np.round(main_glac_rgi.loc[rgiid_unique_idx, 'Area'].sum() / +# main_glac_rgi['Area'].sum() * 100,1),'%') #%% PRE-PROCESS MCNABB DATA # # Remove glaciers that: # # (1) poor percent coverage -# # (2) uncertainty is too hig +# # (2) uncertainty is too high +# # Glacier selection +# rgi_regionsO1 = [1] +# rgi_glac_number = 'all' +# startyear = 1980 +# endyear = 2017 # # density_ice_brun = 850 # -# mcnabb_fn = 'McNabb_data_all_raw.csv' -# output_fn = 'McNabb_data_all_preprocessed.csv' +# mcnabb_fn = 'Alaska_dV_17jun.csv' # +# # Select glaciers +# main_glac_rgi = modelsetup.selectglaciersrgitable(rgi_regionsO1=rgi_regionsO1, rgi_regionsO2 = 'all', +# rgi_glac_number=rgi_glac_number) # # Load data # ds_raw = pd.read_csv(input.mcnabb_fp + mcnabb_fn) -# ds_raw['glacno_str'] = [x.split('-')[1] for x in ds_raw.RGIId.values] -# ds_raw['mb_mwea'] = ds_raw['smb'] * density_ice_brun / input.density_water -# ds_raw['mb_mwea_sigma'] = ds_raw['e_dh'] * density_ice_brun / input.density_water -# nraw = ds_raw.shape[0] # # # remove data with poor coverage -# ds = ds_raw[ds_raw['pct_data'] > 0.75].copy() -# ds.reset_index(drop=True, inplace=True) -# nraw_goodcoverage = ds.shape[0] -# print('Glaciers removed (poor coverage):', nraw - nraw_goodcoverage, 'points') +# ds1 = ds_raw[ds_raw['pct_data'] > 0.75].copy() +# ds1.reset_index(drop=True, inplace=True) # # # remove glaciers with too high uncertainty (> 1.96 stdev) -# uncertainty_median = ds.e_dh.median() -# ds['e_mad'] = np.absolute(ds['e_dh'] - uncertainty_median) -# uncertainty_mad = np.median(ds['e_mad']) +# uncertainty_median = ds1.e_dh.median() +# ds1['e_mad'] = np.absolute(ds1['e_dh'] - uncertainty_median) +# uncertainty_mad = np.median(ds1['e_mad']) # print('uncertainty median and mad [m/yr]:', np.round(uncertainty_median,2), np.round(uncertainty_mad,2)) -# ds = ds[ds['e_dh'] < uncertainty_median + 3*uncertainty_mad].copy() -# ds = ds.sort_values('RGIId') -# ds.reset_index(drop=True, inplace=True) -# print('Glaciers removed (too high uncertainty):', nraw_goodcoverage - ds.shape[0], 'points') +# ds2 = ds1[ds1['e_dh'] < uncertainty_median + 3*uncertainty_mad].copy() +# ds2.reset_index(drop=True, inplace=True) +# print('Glaciers removed (too high uncertainty):', ds1.shape[0] - ds2.shape[0], 'points') +# +# # Minimum and maximum mass balances +## print(ds2.loc[np.where(ds2.smb.values == ds2.smb.max())[0][0],'smb'], +## ds2.loc[np.where(ds2.smb.values == ds2.smb.max())[0][0],'e_dh']) +## print(ds2.loc[np.where(ds2.smb.values == ds2.smb.min())[0][0],'smb'], +## ds2.loc[np.where(ds2.smb.values == ds2.smb.min())[0][0],'e_dh']) # -# # Select glaciers -# glac_no = sorted(set(ds['glacno_str'].values)) -# main_glac_rgi = modelsetup.selectglaciersrgitable(glac_no=glac_no) +# ds2.sort_values('RGIId') +# ds2.reset_index(drop=True, inplace=True) # # # Count unique glaciers and fraction of total area -# print('Glacier area covered: ', np.round(main_glac_rgi['Area'].sum(),1),'km2') +# rgiid_unique = list(ds2.RGIId.unique()) +# rgiid_unique_idx = [] +# for rgiid in rgiid_unique: +# rgiid_unique_idx.append(np.where(main_glac_rgi.RGIId.values == rgiid)[0][0]) +# print('Glacier area covered: ', np.round(main_glac_rgi.loc[rgiid_unique_idx, 'Area'].sum() / +# main_glac_rgi['Area'].sum() * 100,1),'%') +# +# rgiid_values = list(ds2.RGIId.values) +# rgiid_idx = [] +# for rgiid in rgiid_values: +# rgiid_idx.append(np.where(main_glac_rgi.RGIId.values == rgiid)[0][0]) +# ds2['CenLat'] = main_glac_rgi.loc[rgiid_idx, 'CenLat'].values +# ds2['CenLon'] = main_glac_rgi.loc[rgiid_idx, 'CenLon'].values +# +# ds2['mb_mwea'] = ds2['smb'] * density_ice_brun / input.density_water +# ds2['mb_mwea_sigma'] = ds2['e_dh'] * density_ice_brun / input.density_water # -## # All values -## rgiid_values = list(ds.RGIId.values) -## rgiid_idx = [] -## for rgiid in rgiid_values: -## rgiid_idx.append(np.where(main_glac_rgi.RGIId.values == rgiid)[0][0]) -## ds['CenLat'] = main_glac_rgi.loc[rgiid_idx, 'CenLat'].values -## ds['CenLon'] = main_glac_rgi.loc[rgiid_idx, 'CenLon'].values -# -# -# # Only longest value -# ds_output = pd.DataFrame(np.zeros((len(glac_no), ds.shape[1])), columns=ds.columns) -# for nglac, glacno in enumerate(glac_no): -# ds_subset = ds.loc[np.where(ds.glacno_str.values == glacno)[0],:] -# ds_subset.reset_index(inplace=True) -# ds_output.loc[nglac,:] = ( -# ds_subset.loc[np.where(ds_subset['pct_data'].values == ds_subset['pct_data'].max())[0][0],:]) -# -# # Minimum and maximum mass balances -# print('Max MB:', np.round(ds_output.loc[np.where(ds_output.smb.values == ds_output.smb.max())[0][0],'smb'],2), -# '+/-', np.round(ds_output.loc[np.where(ds_output.smb.values == ds_output.smb.max())[0][0],'e_dh'],2)) -# print('Min MB:', np.round(ds_output.loc[np.where(ds_output.smb.values == ds_output.smb.min())[0][0],'smb'],2), -# '+/-', np.round(ds_output.loc[np.where(ds_output.smb.values == ds_output.smb.min())[0][0],'e_dh'],2)) -# # # Adjust date to YYYYMMDD format -# print('\nCHECK ALL YEARS AFTER IN 2000s\n') -# ds_output['y0'] = ['20' + str(x.split('/')[2]).zfill(2) for x in ds_output['date0'].values] -# ds_output['m0'] = [str(x.split('/')[0]).zfill(2) for x in ds_output['date0'].values] -# ds_output['d0'] = [str(x.split('/')[1]).zfill(2) for x in ds_output['date0'].values] -# ds_output['y1'] = ['20' + str(x.split('/')[2]).zfill(2) for x in ds_output['date1'].values] -# ds_output['m1'] = [str(x.split('/')[0]).zfill(2) for x in ds_output['date1'].values] -# ds_output['d1'] = [str(x.split('/')[1]).zfill(2) for x in ds_output['date1'].values] -# ds_output['date0'] = ds_output['y0'] + ds_output['m0'] + ds_output['d0'] -# ds_output['date1'] = ds_output['y1'] + ds_output['m1'] + ds_output['d1'] -# ds_output.drop(['y0', 'm0', 'd0', 'y1', 'm1', 'd1'], axis=1, inplace=True) +# ds2['y0'] = [str(x.split('-')[0]) for x in ds2['date0'].values] +# ds2['m0'] = [str(x.split('-')[1]) for x in ds2['date0'].values] +# ds2['d0'] = [str(x.split('-')[2]) for x in ds2['date0'].values] +# ds2['y1'] = [str(x.split('-')[0]) for x in ds2['date1'].values] +# ds2['m1'] = [str(x.split('-')[1]) for x in ds2['date1'].values] +# ds2['d1'] = [str(x.split('-')[2]) for x in ds2['date1'].values] +# ds2['date0'] = ds2['y0'] + ds2['m0'] + ds2['d0'] +# ds2['date1'] = ds2['y1'] + ds2['m1'] + ds2['d1'] +# ds2.drop(['y0', 'm0', 'd0', 'y1', 'm1', 'd1'], axis=1, inplace=True) # -# ds_output.to_csv(input.mcnabb_fp + output_fn) +# ds2.to_csv(input.mcnabb_fp + mcnabb_fn.replace('.csv','_preprocessed.csv')) #%% diff --git a/emergence_velocity.ipynb b/emergence_velocity.ipynb deleted file mode 100644 index 6dc18beb..00000000 --- a/emergence_velocity.ipynb +++ /dev/null @@ -1,2193 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "#Function to generate a 3-panel plot for input arrays\n", - "def plot_array(dem, clim=None, titles=None, cmap='inferno', label=None, overlay=None, fn=None):\n", - " fig, ax = plt.subplots(1,1, sharex=True, sharey=True, figsize=(10,5))\n", - " alpha = 1.0\n", - " #Gray background\n", - " ax.set_facecolor('0.5')\n", - " #Force aspect ratio to match images\n", - " ax.set(aspect='equal')\n", - " #Turn off axes labels/ticks\n", - " ax.get_xaxis().set_visible(False)\n", - " ax.get_yaxis().set_visible(False)\n", - " if titles is not None:\n", - " ax.set_title(titles[0])\n", - " #Plot background shaded relief map\n", - " if overlay is not None:\n", - " alpha = 0.7\n", - " ax.imshow(overlay, cmap='gray', clim=(1,255))\n", - " #Plot each array\n", - " im_list = [ax.imshow(dem, clim=clim, cmap=cmap, alpha=alpha)]\n", - " fig.tight_layout()\n", - " fig.colorbar(im_list[0], label=label, extend='both', shrink=0.5)\n", - " if fn is not None:\n", - " fig.savefig(fn, bbox_inches='tight', pad_inches=0, dpi=150)\n", - "\n", - "#Function to generate a 3-panel plot for input arrays\n", - "def plot2panel(dem_list, clim=None, titles=None, cmap='inferno', label=None, overlay=None, fn=None):\n", - " fig, axa = plt.subplots(1,2, sharex=True, sharey=True, figsize=(10,5))\n", - " alpha = 1.0\n", - " for n, ax in enumerate(axa):\n", - " #Gray background\n", - " ax.set_facecolor('0.5')\n", - " #Force aspect ratio to match images\n", - " ax.set(aspect='equal')\n", - " #Turn off axes labels/ticks\n", - " ax.get_xaxis().set_visible(False)\n", - " ax.get_yaxis().set_visible(False)\n", - " if titles is not None:\n", - " ax.set_title(titles[n])\n", - " #Plot background shaded relief map\n", - " if overlay is not None:\n", - " alpha = 0.7\n", - " axa[n].imshow(overlay[n], cmap='gray', clim=(1,255))\n", - " #Plot each array\n", - " im_list = [axa[i].imshow(dem_list[i], clim=clim, cmap=cmap, alpha=alpha) for i in range(len(dem_list))]\n", - " fig.tight_layout()\n", - " fig.colorbar(im_list[0], ax=axa.ravel().tolist(), label=label, extend='both', shrink=0.5)\n", - " if fn is not None:\n", - " fig.savefig(fn, bbox_inches='tight', pad_inches=0, dpi=150)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "#! /usr/bin/env python\n", - "\"\"\"\n", - "Compute emergence velocities for input DEMs, surface velocities and glacier polygons\n", - "\"\"\"\n", - "\n", - "import sys\n", - "import os\n", - "import re\n", - "import subprocess\n", - "from datetime import datetime, timedelta\n", - "import time\n", - "import pickle\n", - "from collections import OrderedDict\n", - "\n", - "import geopandas as gpd\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import rasterio\n", - "from osgeo import gdal, ogr, osr\n", - "\n", - "from pygeotools.lib import malib, warplib, geolib, iolib, timelib\n", - "# from imview.lib import pltlib\n", - "\n", - "#Avoid printing out divide by 0 errors\n", - "np.seterr(all='ignore')\n", - "\n", - "\"\"\"\n", - "Class to store relevant feature attributes and derived values\n", - "Safe for multiprocessing\n", - "\"\"\"\n", - "class GlacFeat:\n", - " def __init__(self, feat, glacname_fieldname, glacnum_fieldname):\n", - "\n", - " self.glacname = feat.GetField(glacname_fieldname)\n", - " if self.glacname is None:\n", - " self.glacname = \"\"\n", - " else:\n", - " #RGI has some nonstandard characters\n", - " #self.glacname = self.glacname.decode('unicode_escape').encode('ascii','ignore')\n", - " #glacname = re.sub(r'[^\\x00-\\x7f]',r'', glacname)\n", - " self.glacname = re.sub(r'\\W+', '', self.glacname)\n", - " self.glacname = self.glacname.replace(\" \", \"\")\n", - " self.glacname = self.glacname.replace(\"_\", \"\")\n", - " self.glacname = self.glacname.replace(\"/\", \"\")\n", - "\n", - " self.glacnum = feat.GetField(glacnum_fieldname)\n", - " fn = feat.GetDefnRef().GetName()\n", - " #RGIId (String) = RGI50-01.00004\n", - " self.glacnum = '%0.5f' % float(self.glacnum.split('-')[-1])\n", - "\n", - " if self.glacname:\n", - " self.feat_fn = \"%s_%s\" % (self.glacnum, self.glacname)\n", - " else:\n", - " self.feat_fn = str(self.glacnum)\n", - "\n", - " self.glac_geom_orig = geolib.geom_dup(feat.GetGeometryRef())\n", - " self.glac_geom = geolib.geom_dup(self.glac_geom_orig)\n", - " #Hack to deal with fact that this is not preserved in geom when loaded from pickle on disk\n", - " self.glac_geom_srs_wkt = self.glac_geom.GetSpatialReference().ExportToWkt()\n", - "\n", - " #Attributes written by mb_calc\n", - " self.z1 = None\n", - " self.z1_hs = None\n", - " self.z1_stats = None\n", - " self.z1_ela = None\n", - " self.z2 = None\n", - " self.z2_hs = None\n", - " self.z2_stats = None\n", - " self.z2_ela = None\n", - " self.z2_aspect = None\n", - " self.z2_aspect_stats = None\n", - " self.z2_slope = None\n", - " self.z2_slope_stats = None\n", - " self.res = None\n", - " self.dhdt = None\n", - " self.mb = None\n", - " self.mb_mean = None\n", - " self.t1 = None\n", - " self.t2 = None\n", - " self.dt = None\n", - " self.t1_mean = None\n", - " self.t2_mean = None\n", - " self.dt_mean = None\n", - "\n", - " self.H = None\n", - " self.H_mean = np.nan\n", - " self.vx = None\n", - " self.vy = None\n", - " self.vm = None\n", - " self.vm_mean = np.nan\n", - " self.divQ = None\n", - " self.debris_class = None\n", - " self.debris_thick = None\n", - " self.debris_thick_mean = np.nan\n", - " self.perc_clean = np.nan\n", - " self.perc_debris = np.nan\n", - " self.perc_pond = np.nan\n", - "\n", - " def geom_srs_update(self, srs=None):\n", - " if self.glac_geom.GetSpatialReference() is None:\n", - " if srs is None:\n", - " srs = osr.SpatialReference()\n", - " srs.ImportFromWkt(self.glac_geom_srs_wkt)\n", - " self.glac_geom.AssignSpatialReference(srs)\n", - "\n", - " def geom_attributes(self, srs=None):\n", - " self.geom_srs_update()\n", - " if srs is not None:\n", - " #Should reproject here to equal area, before geom_attributes\n", - " #self.glac_geom.AssignSpatialReference(glac_shp_srs)\n", - " #self.glac_geom_local = geolib.geom2localortho(self.glac_geom)\n", - " geolib.geom_transform(self.glac_geom, srs)\n", - "\n", - " self.glac_geom_extent = geolib.geom_extent(self.glac_geom)\n", - " self.glac_area = self.glac_geom.GetArea()\n", - " self.glac_area_km2 = self.glac_area / 1E6\n", - " self.cx, self.cy = self.glac_geom.Centroid().GetPoint_2D()\n", - "\n", - "#RGI uses 50 m bins\n", - "def hist_plot(gf, outdir, bin_width=50.0, dz_clim=(-2.0, 2.0)):\n", - " #print(\"Generating histograms\")\n", - " #Create bins for full range of input data and specified bin width\n", - "\n", - " #NOTE: these counts/areas are for valid pixels only\n", - " #Not necessarily a true representation of actual glacier hypsometry\n", - " #Need a void-filled DEM for this\n", - "\n", - " z_bin_edges, z_bin_centers = malib.get_bins(gf.z1, bin_width)\n", - " #Need to compress here, otherwise histogram uses masked values!\n", - " z1_bin_counts, z1_bin_edges = np.histogram(gf.z1.compressed(), bins=z_bin_edges)\n", - " z1_bin_areas = z1_bin_counts * gf.res[0] * gf.res[1] / 1E6\n", - " #RGI standard is integer thousandths of glaciers total area\n", - " #Should check to make sure sum of bin areas equals total area\n", - " #z1_bin_areas_perc = 100. * z1_bin_areas / np.sum(z1_bin_areas)\n", - " z1_bin_areas_perc = 100. * (z1_bin_areas / gf.glac_area_km2)\n", - "\n", - " #If we only have one elevation grid with dhdt\n", - " if gf.z2 is not None:\n", - " z2_bin_counts, z2_bin_edges = np.histogram(gf.z2.compressed(), bins=z_bin_edges)\n", - " z2_bin_areas = z2_bin_counts * gf.res[0] * gf.res[1] / 1E6\n", - " #z2_bin_areas_perc = 100. * z2_bin_areas / np.sum(z2_bin_areas)\n", - " z2_bin_areas_perc = 100. * (z1_bin_areas / gf.glac_area_km2)\n", - " else:\n", - " z2_bin_counts = z1_bin_counts\n", - " z2_bin_edges = z1_bin_edges\n", - " z2_bin_areas = z1_bin_areas\n", - " z2_bin_areas_perc = z1_bin_areas_perc\n", - "\n", - " #Create arrays to store output\n", - " slope_bin_med = np.ma.masked_all_like(z1_bin_areas)\n", - " slope_bin_mad = np.ma.masked_all_like(z1_bin_areas)\n", - " aspect_bin_med = np.ma.masked_all_like(z1_bin_areas)\n", - " aspect_bin_mad = np.ma.masked_all_like(z1_bin_areas)\n", - " if gf.dhdt is not None:\n", - " mb_bin_med = np.ma.masked_all_like(z1_bin_areas)\n", - " np.ma.set_fill_value(mb_bin_med, np.nan)\n", - " mb_bin_mad = np.ma.masked_all_like(mb_bin_med)\n", - " mb_bin_mean = np.ma.masked_all_like(mb_bin_med)\n", - " mb_bin_std = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_med = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_mad = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_mean = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_std = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_count = np.ma.masked_all_like(mb_bin_med)\n", - " if gf.vm is not None:\n", - " vm_bin_med = np.ma.masked_all_like(z1_bin_areas)\n", - " vm_bin_mad = np.ma.masked_all_like(z1_bin_areas)\n", - " if gf.H is not None:\n", - " H_bin_mean = np.ma.masked_all_like(z1_bin_areas)\n", - " H_bin_std = np.ma.masked_all_like(z1_bin_areas)\n", - "# emvel_bin_mean = np.ma.masked_all_like(z1_bin_areas)\n", - "# emvel_bin_std = np.ma.masked_all_like(z1_bin_areas)\n", - " if gf.debris_class is not None:\n", - "# perc_clean = np.ma.masked_all_like(z1_bin_areas)\n", - "# perc_debris = np.ma.masked_all_like(z1_bin_areas)\n", - "# perc_pond = np.ma.masked_all_like(z1_bin_areas)\n", - " debris_thick_med = np.ma.masked_all_like(z1_bin_areas)\n", - " debris_thick_mad = np.ma.masked_all_like(z1_bin_areas)\n", - "# dhdt_clean_bin_med = np.ma.masked_all_like(z1_bin_areas)\n", - "# dhdt_debris_bin_med = np.ma.masked_all_like(z1_bin_areas)\n", - "# dhdt_pond_bin_med = np.ma.masked_all_like(mz1_bin_areas)\n", - "\n", - "# gf.dhdt_clean = np.ma.array(gf.dhdt, mask=~((gf.debris_class == 1).data))\n", - "# gf.dhdt_debris = np.ma.array(gf.dhdt, mask=~((gf.debris_class == 2).data))\n", - "# gf.dhdt_pond = np.ma.array(gf.dhdt, mask=~((gf.debris_class == 3).data))\n", - "\n", - " #Bin sample count must be greater than this value\n", - " min_bin_samp_count = 9\n", - "\n", - " #Loop through each bin and extract stats\n", - " idx = np.digitize(gf.z1, z_bin_edges)\n", - " for bin_n in range(z_bin_centers.size):\n", - " if gf.dhdt is not None:\n", - " mb_bin_samp = gf.mb_map[(idx == bin_n+1)]\n", - " if mb_bin_samp.count() > min_bin_samp_count:\n", - " mb_bin_med[bin_n] = malib.fast_median(mb_bin_samp)\n", - " mb_bin_mad[bin_n] = malib.mad(mb_bin_samp)\n", - " mb_bin_mean[bin_n] = mb_bin_samp.mean()\n", - " mb_bin_std[bin_n] = mb_bin_samp.std()\n", - " dhdt_bin_samp = gf.dhdt[(idx == bin_n+1)]\n", - " if dhdt_bin_samp.count() > min_bin_samp_count:\n", - " dhdt_bin_med[bin_n] = malib.fast_median(dhdt_bin_samp)\n", - " dhdt_bin_mad[bin_n] = malib.mad(dhdt_bin_samp)\n", - " dhdt_bin_mean[bin_n] = dhdt_bin_samp.mean()\n", - " dhdt_bin_std[bin_n] = dhdt_bin_samp.std()\n", - " dhdt_bin_count[bin_n] = dhdt_bin_samp.count()\n", - " if gf.debris_thick is not None:\n", - " debris_thick_bin_samp = gf.debris_thick[(idx == bin_n+1)]\n", - " if debris_thick_bin_samp.size > min_bin_samp_count:\n", - " debris_thick_med[bin_n] = malib.fast_median(debris_thick_bin_samp)\n", - " debris_thick_mad[bin_n] = malib.mad(debris_thick_bin_samp)\n", - " if gf.debris_class is not None:\n", - " debris_class_bin_samp = gf.debris_class[(idx == bin_n+1)]\n", - " dhdt_clean_bin_samp = gf.dhdt_clean[(idx == bin_n+1)]\n", - " dhdt_debris_bin_samp = gf.dhdt_debris[(idx == bin_n+1)]\n", - " dhdt_pond_bin_samp = gf.dhdt_pond[(idx == bin_n+1)]\n", - " if debris_class_bin_samp.count() > min_bin_samp_count:\n", - " perc_clean[bin_n] = 100. * (debris_class_bin_samp == 1).sum()/debris_class_bin_samp.count()\n", - " perc_debris[bin_n] = 100. * (debris_class_bin_samp == 2).sum()/debris_class_bin_samp.count()\n", - " perc_pond[bin_n] = 100. * (debris_class_bin_samp == 3).sum()/debris_class_bin_samp.count()\n", - " if dhdt_clean_bin_samp.count() > min_bin_samp_count:\n", - " dhdt_clean_bin_med[bin_n] = malib.fast_median(dhdt_clean_bin_samp)\n", - " if dhdt_debris_bin_samp.count() > min_bin_samp_count:\n", - " dhdt_debris_bin_med[bin_n] = malib.fast_median(dhdt_debris_bin_samp)\n", - " if dhdt_pond_bin_samp.count() > min_bin_samp_count:\n", - " dhdt_pond_bin_med[bin_n] = malib.fast_median(dhdt_pond_bin_samp)\n", - " if gf.vm is not None:\n", - " vm_bin_samp = gf.vm[(idx == bin_n+1)]\n", - " if vm_bin_samp.size > min_bin_samp_count:\n", - " vm_bin_med[bin_n] = malib.fast_median(vm_bin_samp)\n", - " vm_bin_mad[bin_n] = malib.mad(vm_bin_samp)\n", - " if gf.H is not None:\n", - " H_bin_samp = gf.H[(idx == bin_n+1)]\n", - " if H_bin_samp.size > min_bin_samp_count:\n", - " H_bin_mean[bin_n] = H_bin_samp.mean()\n", - " H_bin_std[bin_n] = H_bin_samp.std()\n", - "# emvel_bin_samp = gf.emvel[(idx == bin_n+1)]\n", - "# if emvel_bin_samp.size > min_bin_samp_count:\n", - "# emvel_bin_mean[bin_n] = emvel_bin_samp.mean()\n", - "# emvel_bin_std[bin_n] = emvel_bin_samp.std()\n", - " slope_bin_samp = gf.z1_slope[(idx == bin_n+1)]\n", - " if slope_bin_samp.size > min_bin_samp_count:\n", - " slope_bin_med[bin_n] = malib.fast_median(slope_bin_samp)\n", - " slope_bin_mad[bin_n] = malib.mad(slope_bin_samp)\n", - " aspect_bin_samp = gf.z1_aspect[(idx == bin_n+1)]\n", - " if aspect_bin_samp.size > min_bin_samp_count:\n", - " aspect_bin_med[bin_n] = malib.fast_median(aspect_bin_samp)\n", - " aspect_bin_mad[bin_n] = malib.mad(aspect_bin_samp)\n", - "\n", - " if gf.dhdt is not None:\n", - " dhdt_bin_areas = dhdt_bin_count * gf.res[0] * gf.res[1] / 1E6\n", - " #dhdt_bin_areas_perc = 100. * dhdt_bin_areas / np.sum(dhdt_bin_areas)\n", - " dhdt_bin_areas_perc = 100. * (dhdt_bin_areas / gf.glac_area_km2)\n", - "\n", - " outbins_header = 'bin_center_elev_m, z1_bin_count_valid, z1_bin_area_valid_km2, z1_bin_area_perc, z2_bin_count_valid, z2_bin_area_valid_km2, z2_bin_area_perc, slope_bin_med, aspect_bin_med'\n", - " fmt = '%0.1f, %0.0f, %0.3f, %0.2f, %0.0f, %0.3f, %0.2f, %0.2f, %0.2f'\n", - " outbins = [z_bin_centers, z1_bin_counts, z1_bin_areas, z1_bin_areas_perc, z2_bin_counts, z2_bin_areas, z2_bin_areas_perc, slope_bin_med, aspect_bin_med]\n", - " if gf.dhdt is not None:\n", - " outbins_header += ', dhdt_bin_count, dhdt_bin_area_valid_km2, dhdt_bin_area_perc, dhdt_bin_med_ma, dhdt_bin_mad_ma, dhdt_bin_mean_ma, dhdt_bin_std_ma, mb_bin_med_mwea, mb_bin_mad_mwea, mb_bin_mean_mwea, mb_bin_std_mwea'\n", - " fmt += ', %0.0f, %0.3f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f'\n", - " outbins.extend([dhdt_bin_count, dhdt_bin_areas, dhdt_bin_areas_perc, dhdt_bin_med, dhdt_bin_mad, dhdt_bin_mean, dhdt_bin_std, \\\n", - " mb_bin_med, mb_bin_mad, mb_bin_mean, mb_bin_std])\n", - " if gf.debris_thick is not None:\n", - " outbins_header += ', debris_thick_med_m, debris_thick_mad_m'\n", - " fmt += ', %0.2f, %0.2f'\n", - " debris_thick_med[debris_thick_med == -(np.inf)] = 0.00\n", - " debris_thick_mad[debris_thick_mad == -(np.inf)] = 0.00\n", - " outbins.extend([debris_thick_med, debris_thick_mad])\n", - " if gf.debris_class is not None:\n", - " outbins_header += ', perc_debris, perc_pond, perc_clean, dhdt_debris_med, dhdt_pond_med, dhdt_clean_med'\n", - " fmt += ', %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f'\n", - " outbins.extend([perc_debris, perc_pond, perc_clean, dhdt_debris_bin_med, dhdt_pond_bin_med, dhdt_clean_bin_med])\n", - " if gf.vm is not None:\n", - " outbins_header += ', vm_med, vm_mad'\n", - " fmt += ', %0.2f, %0.2f'\n", - " outbins.extend([vm_bin_med, vm_bin_mad])\n", - " if gf.H is not None:\n", - " outbins_header += ', H_mean, H_std'\n", - " fmt += ', %0.2f, %0.2f'\n", - " outbins.extend([H_bin_mean, H_bin_std])\n", - "# outbins_header += ', H_mean, H_std, emvel_mean, emvel_std'\n", - "# fmt += ', %0.2f, %0.2f, %0.2f, %0.2f'\n", - "# outbins.extend([H_bin_mean, H_bin_std, emvel_bin_mean, emvel_bin_std])\n", - "\n", - " outbins = np.ma.array(outbins).T.astype('float32')\n", - " np.ma.set_fill_value(outbins, np.nan)\n", - " outbins = outbins.filled(np.nan)\n", - " outbins_fn = os.path.join(outdir, gf.feat_fn+'_mb_bins.csv')\n", - " np.savetxt(outbins_fn, outbins, fmt=fmt, delimiter=',', header=outbins_header)\n", - "\n", - " #Create plots of elevation bins\n", - " #print(\"Generating aed plot\")\n", - " #f,axa = plt.subplots(1,2, figsize=(6, 6))\n", - " nsubplots = 0\n", - " if gf.dhdt is not None:\n", - " nsubplots += 1\n", - " if gf.debris_thick is not None:\n", - " nsubplots += 1\n", - " if gf.vm is not None:\n", - " nsubplots += 1\n", - " if gf.H is not None:\n", - " nsubplots += 1\n", - " print(nsubplots)\n", - " f,axa = plt.subplots(1,nsubplots, squeeze=False, figsize=(10, 7.5))\n", - " f.suptitle(gf.feat_fn)\n", - " fs = 9\n", - " nplot = -1\n", - " if gf.dhdt is not None:\n", - " nplot += 1\n", - " axa[0,nplot].plot(z1_bin_areas, z_bin_centers, label='%0.2f' % gf.t1_mean)\n", - " axa[0,nplot].axhline(gf.z1_ela, ls=':', c='C0')\n", - " if gf.z2 is not None:\n", - " axa[0,nplot].plot(z2_bin_areas, z_bin_centers, label='%0.2f' % gf.t2_mean)\n", - " axa[0,nplot].axhline(gf.z2_ela, ls=':', c='C1')\n", - " axa[0,nplot].legend(prop={'size':8}, loc='upper right')\n", - " axa[0,nplot].set_ylabel('Elevation (m WGS84)', fontsize=fs)\n", - " axa[0,nplot].set_xlabel('Area $\\mathregular{km^2}$', fontsize=fs)\n", - " axa[0,nplot].yaxis.set_ticks_position('both')\n", - " # pltlib.minorticks_on(axa[0])\n", - "\n", - " nplot += 1\n", - " axa[0,nplot].axvline(0, lw=1.0, c='k')\n", - " \"\"\"\n", - " #Plot flux divergence values for each bin\n", - " if gf.vm is not None and gf.H is not None:\n", - " divQ_bin_mean = np.gradient(H_bin_mean * vm_bin_med * v_col_f)\n", - " axa[1].plot(divQ_bin_mean, z_bin_centers, color='green')\n", - " \"\"\"\n", - " axa[0,nplot].plot(mb_bin_med, z_bin_centers, color='k')\n", - " axa[0,nplot].axvline(gf.mb_mean, lw=0.5, ls=':', c='k', label='%0.2f m w.e./yr' % gf.mb_mean)\n", - " axa[0,nplot].fill_betweenx(z_bin_centers, mb_bin_med-mb_bin_mad, mb_bin_med+mb_bin_mad, color='k', alpha=0.1)\n", - " axa[0,nplot].fill_betweenx(z_bin_centers, 0, mb_bin_med, where=(mb_bin_med<0), color='r', alpha=0.2)\n", - " axa[0,nplot].fill_betweenx(z_bin_centers, 0, mb_bin_med, where=(mb_bin_med>0), color='b', alpha=0.2)\n", - " #axa[nplot].set_xlabel('dh/dt (m/yr)')\n", - " axa[0,nplot].set_xlabel('Mass balance (m w.e./yr)', fontsize=fs)\n", - " axa[0,nplot].legend(prop={'size':8}, loc='upper right')\n", - " axa[0,nplot].yaxis.set_ticks_position('both')\n", - " # pltlib.minorticks_on(axa[1])\n", - " #Hide y-axis labels\n", - " axa[0,nplot].axes.yaxis.set_ticklabels([])\n", - " axa[0,nplot].set_xlim(*dz_clim)\n", - "\n", - " if gf.debris_thick is not None:\n", - " nplot += 1\n", - " axa[0,nplot].errorbar(debris_thick_med*100., z_bin_centers, xerr=debris_thick_mad*100, color='k', fmt='o', ms=3, label='Debris Thickness', alpha=0.6)\n", - " if gf.debris_class is not None:\n", - " axa[0,nplot].plot(perc_debris, z_bin_centers, color='sienna', label='Debris Coverage')\n", - " axa[0,nplot].plot(perc_pond, z_bin_centers, color='turquoise', label='Pond Coverage')\n", - " if gf.debris_thick is not None or gf.debris_class is not None:\n", - " axa[0,nplot].set_xlim(0, 100)\n", - " axa[0,nplot].yaxis.set_ticks_position('both')\n", - " # pltlib.minorticks_on(axa[2])\n", - " axa[0,nplot].axes.yaxis.set_ticklabels([])\n", - " axa[0,nplot].legend(prop={'size':8}, loc='upper right')\n", - " axa[0,nplot].set_xlabel('Debris thickness (cm), coverage (%)', fontsize=fs)\n", - "\n", - " if gf.H is not None:\n", - " nplot += 1\n", - " axa[0,nplot].plot(H_bin_mean, z_bin_centers, color='b', label='H (%0.2f m)' % gf.H_mean)\n", - " axa[0,nplot].fill_betweenx(z_bin_centers, H_bin_mean-H_bin_std, H_bin_mean+H_bin_std, color='b', alpha=0.1)\n", - " axa[0,nplot].set_xlabel('Ice Thickness (m)', fontsize=fs)\n", - " axa[0,nplot].legend(prop={'size':8}, loc='lower right')\n", - " # pltlib.minorticks_on(axa[3])\n", - " #axa[nplot].set_xlim(0, 400)\n", - " axa[0,nplot].yaxis.tick_left()\n", - " axa[0,nplot].yaxis.set_ticks_position('both')\n", - " axa[0,nplot].yaxis.set_label_position(\"right\")\n", - " \n", - " if gf.vm is not None:\n", - " nplot += 1\n", - "# ax4 = axa[0,nplot].twinx()\n", - " axa[0,nplot].set_xlabel('Velocity (m/yr)', fontsize=fs)\n", - " axa[0,nplot].plot(vm_bin_med, z_bin_centers, color='g', label='Vm (%0.2f m/yr)' % gf.vm_mean)\n", - " axa[0,nplot].fill_betweenx(z_bin_centers, vm_bin_med-vm_bin_mad, vm_bin_med+vm_bin_mad, color='g', alpha=0.1)\n", - " #ax4.set_xlim(0, 50)\n", - " axa[0,nplot].xaxis.tick_bottom()\n", - " axa[0,nplot].xaxis.set_label_position(\"bottom\")\n", - " axa[0,nplot].legend(prop={'size':8}, loc='upper right')\n", - " \n", - " nplot += 1\n", - "# axa[0,nplot].set_xlabel('divQ (??)', fontsize=fs)\n", - "# axa[0,nplot].plot(vm_bin_med, z_bin_centers, color='g', label='Vm (%0.2f m/yr)' % gf.vm_mean)\n", - "# axa[0,nplot].fill_betweenx(z_bin_centers, vm_bin_med-vm_bin_mad, vm_bin_med+vm_bin_mad, color='g', alpha=0.1)\n", - "# #ax4.set_xlim(0, 50)\n", - "# axa[0,nplot].xaxis.tick_bottom()\n", - "# axa[0,nplot].xaxis.set_label_position(\"bottom\")\n", - "# axa[0,nplot].legend(prop={'size':8}, loc='upper right')\n", - "# gf.divQ\n", - " \n", - "# if gf.vm is not None:\n", - "# nplot += 1\n", - "# # ax4 = axa[0,nplot].twinx()\n", - "# axa[0,nplot].set_xlabel('Velocity (m/yr)', fontsize=fs)\n", - "# axa[0,nplot].plot(vm_bin_med, z_bin_centers, color='g', label='Vm (%0.2f m/yr)' % gf.vm_mean)\n", - "# axa[0,nplot].fill_betweenx(z_bin_centers, vm_bin_med-vm_bin_mad, vm_bin_med+vm_bin_mad, color='g', alpha=0.1)\n", - "# #ax4.set_xlim(0, 50)\n", - "# axa[0,nplot].xaxis.tick_bottom()\n", - "# axa[0,nplot].xaxis.set_label_position(\"bottom\")\n", - "# axa[0,nplot].legend(prop={'size':8}, loc='upper right')\n", - "\n", - " plt.tight_layout()\n", - " #Make room for suptitle\n", - " plt.subplots_adjust(top=0.95, wspace=0.1)\n", - " #print(\"Saving aed plot\")\n", - " fig_fn = os.path.join(outdir_fig, gf.feat_fn+'_mb_aed.png')\n", - " #plt.savefig(fig_fn, bbox_inches='tight', dpi=300)\n", - " plt.savefig(fig_fn, dpi=300)\n", - " plt.close(f)\n", - " return z_bin_edges" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "#INPUT\n", - "topdir='/Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/'\n", - "#Output directory\n", - "outdir = topdir + 'kennicott/'\n", - "outdir_fig = outdir + '/figures/'\n", - "outdir_csv = outdir + '/csv'\n", - "\n", - "#RGI inventory\n", - "glac_shp_fn = topdir + '../RGI/rgi60/01_rgi60_Alaska/01_rgi60_Alaska.shp'\n", - "# glac_shp_fn = '/Users/davidrounce/Documents/Dave_Rounce/Satellite_Images/Kennicott_glacier.shp'\n", - "glacfeat_fn = outdir + 'glacfeat_list.p'\n", - "#DEM\n", - "z1_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/Alaska_albers_V3_mac/Alaska_albers_V3.tif'\n", - "# Ice thickness\n", - "# huss_dir = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/composite_thickness_RGI60-all_regions/RGI60-01/'\n", - "# huss_fn = 'RGI60-01.15645_thickness.tif'\n", - "huss_dir = '/Users/davidrounce/Documents/Dave_Rounce/DebrisGlaciers_WG/Melt_Intercomparison/rounce_model/kennicott_data/'\n", - "huss_fn = 'thick_kennicott_HH2012.tif'\n", - "\n", - "\n", - "#Output projection\n", - "proj_fn = os.path.join(huss_dir, huss_fn) # THIS PROJECTION IS KEY!\n", - "ds = gdal.Open(proj_fn)\n", - "prj = ds.GetProjection()\n", - "srs = osr.SpatialReference(wkt=prj)\n", - "aea_srs = srs\n", - "\n", - "#Surface velocity\n", - "v_dir = '/Users/davidrounce/Documents/Dave_Rounce/Satellite_Images/ITS_Live'\n", - "vx_fn = os.path.join(v_dir, 'ALA_G0120_0000_vx.tif')\n", - "vy_fn = os.path.join(v_dir, 'ALA_G0120_0000_vy.tif')\n", - "\n", - "#Filter glacier poly - let's stick with big glaciers for now\n", - "min_glac_area = 0 #km^2\n", - "#Only write out for larger glaciers\n", - "min_glac_area_writeout = 1.\n", - "#Minimum percentage of glacier poly covered by valid dz\n", - "min_valid_area_perc = 0.6 # DSHEAN WAS 0.85\n", - "#Process thickness, velocity, etc\n", - "extra_layers = True\n", - "#Write out DEMs and dz map\n", - "writeout = True\n", - "#Generate figures\n", - "mb_plot = True\n", - "# #Run in parallel, set to False for serial loop\n", - "# parallel = False\n", - "#Verbose for debugging\n", - "verbose = True\n", - "# #Number of parallel processes\n", - "# #Use all virtual cores\n", - "# #nproc = iolib.cpu_count(logical=True) - 1\n", - "# #Use all physical cores\n", - "# # nproc = iolib.cpu_count(logical=False) - 1\n", - "# nproc = 1\n", - "#Shortcut to use existing glacfeat_list.p if found\n", - "use_existing_glacfeat = True\n", - "\n", - "#Pad by this distance (meters) around glacier polygon for uncertainty estimates over surrounding surfaces\n", - "buff_dist = 1000\n", - "\n", - "#Bin width\n", - "bin_width = 10\n", - "\n", - "#Surface to column average velocity scaling\n", - "v_col_f = 0.8\n", - "\n", - "#This is recommendation by Huss et al (2013)\n", - "rho_is = 0.85\n", - "rho_sigma = 0.06\n", - "\n", - "\n", - "if not os.path.exists(outdir):\n", - " os.makedirs(outdir)\n", - "if not os.path.exists(outdir_fig):\n", - " os.makedirs(outdir_fig)\n", - "if not os.path.exists(outdir_csv):\n", - " os.makedirs(outdir_csv)\n", - "\n", - "# ts = datetime.now().strftime('%Y%m%d_%H%M')" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Shp init crs: {'init': 'epsg:4326'}\n", - "Input glacier polygon count: 27108\n", - "Glacier polygon count after spatial filter: 27108\n", - "Min. Area filter glacier polygon count: 27108\n", - "Processing 27108 features\n", - "Loading /Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/kennicott/glacfeat_list.p\n" - ] - } - ], - "source": [ - "# Process RGI shapefile\n", - "if 'rgi' in glac_shp_fn or 'Kennicott' in glac_shp_fn:\n", - " #Use RGI\n", - " glacname_fieldname = \"Name\"\n", - " #RGIId (String) = RGI50-01.00004\n", - " glacnum_fieldname = \"RGIId\"\n", - " glacnum_fmt = '%08.5f'\n", - "else:\n", - " sys.exit('Unrecognized glacier shp filename')\n", - "\n", - "# Shape layer processing\n", - "glac_shp_init = gpd.read_file(glac_shp_fn)\n", - "if verbose:\n", - " print('Shp init crs:', glac_shp_init.crs)\n", - "\n", - "# If projected shapefile already exists, then skip projection\n", - "glac_shp_proj_fn = (outdir + glac_shp_fn.split('/')[-1].replace('.shp','_crs' +\n", - " str(aea_srs.GetAttrValue(\"AUTHORITY\", 1)) + '.shp'))\n", - "if os.path.exists(glac_shp_proj_fn) == False:\n", - " glac_shp_proj = glac_shp_init.to_crs({'init': 'epsg:' + str(aea_srs.GetAttrValue(\"AUTHORITY\", 1))})\n", - " glac_shp_proj.to_file(glac_shp_proj_fn)\n", - " \n", - "glac_shp_ds = ogr.Open(glac_shp_proj_fn, 0)\n", - "glac_shp_lyr = glac_shp_ds.GetLayer()\n", - "#This should be contained in features\n", - "glac_shp_srs = glac_shp_lyr.GetSpatialRef()\n", - "feat_count = glac_shp_lyr.GetFeatureCount()\n", - "print(\"Input glacier polygon count: %i\" % feat_count)\n", - "\n", - "z1_ds = gdal.Open(z1_fn)\n", - "z1_int_geom = geolib.ds_geom_intersection([z1_ds, z1_ds], t_srs=glac_shp_srs)\n", - "\n", - "#Spatial filter\n", - "glac_shp_lyr.SetSpatialFilter(z1_int_geom)\n", - "feat_count = glac_shp_lyr.GetFeatureCount()\n", - "print(\"Glacier polygon count after spatial filter: %i\" % feat_count)\n", - "glac_shp_lyr.ResetReading()\n", - "\n", - "#Area filter\n", - "glac_shp_lyr.SetAttributeFilter(\"Area > %s\" % min_glac_area)\n", - "feat_count = glac_shp_lyr.GetFeatureCount()\n", - "print(\"Min. Area filter glacier polygon count: %i\" % feat_count)\n", - "glac_shp_lyr.ResetReading()\n", - "print(\"Processing %i features\" % feat_count)\n", - "\n", - "#Create a list of glacfeat objects (contains geom) - safe for multiprocessing, while OGR layer is not\n", - "if os.path.exists(glacfeat_fn) and use_existing_glacfeat:\n", - " print(\"Loading %s\" % glacfeat_fn)\n", - " #This fails to load geometry srs\n", - " glacfeat_list = pickle.load(open(glacfeat_fn,\"rb\"))\n", - "else:\n", - " glacfeat_list = []\n", - " print(\"Generating %s\" % glacfeat_fn)\n", - " for n, feat in enumerate(glac_shp_lyr):\n", - " gf = GlacFeat(feat, glacname_fieldname, glacnum_fieldname)\n", - " print(\"%i of %i: %s\" % (n+1, feat_count, gf.feat_fn))\n", - " #Calculate area, extent, centroid\n", - " #NOTE: Input must be in projected coordinate system, ideally equal area\n", - " #Should check this and reproject\n", - " gf.geom_attributes(srs=aea_srs)\n", - " glacfeat_list.append(gf)\n", - " pickle.dump(glacfeat_list, open(glacfeat_fn,\"wb\"))\n", - "\n", - "glac_shp_lyr = None\n", - "glac_shp_ds = None" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1.15645_KennicottGlacier\n" - ] - } - ], - "source": [ - "glacfeat_list_in = glacfeat_list\n", - "\n", - "#This is a hack to limit processing for just a few glaciers\n", - "glac_dict = None\n", - "#Ngozumpa, Khumbu etc\n", - "glac_dict = ['1.15645']\n", - "\n", - "if glac_dict:\n", - " glacfeat_list_in = []\n", - " for i in glacfeat_list:\n", - " if i.glacnum in glac_dict:\n", - " glacfeat_list_in.append(i)\n", - "\n", - "gf = glacfeat_list_in[0]\n", - "print(gf.feat_fn)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "output_fn: /Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/kennicott/1.15645_KennicottGlacier_mb.csv\n", - "1.15645\n", - "/Users/davidrounce/Documents/Dave_Rounce/DebrisGlaciers_WG/Melt_Intercomparison/rounce_model/kennicott_data/thick_kennicott_HH2012.tif\n", - "Expanding extent\n", - "[373321.835701501, 6813195.9656392, 399722.971437693, 6848260.35757026]\n", - "[372321.835701501, 6812195.9656392, 400722.971437693, 6849260.35757026]\n", - "PROJCS[\"WGS 84 / UTM zone 7N\",\n", - " GEOGCS[\"WGS 84\",\n", - " DATUM[\"WGS_1984\",\n", - " SPHEROID[\"WGS 84\",6378137,298.257223563,\n", - " AUTHORITY[\"EPSG\",\"7030\"]],\n", - " AUTHORITY[\"EPSG\",\"6326\"]],\n", - " PRIMEM[\"Greenwich\",0,\n", - " AUTHORITY[\"EPSG\",\"8901\"]],\n", - " UNIT[\"degree\",0.0174532925199433,\n", - " AUTHORITY[\"EPSG\",\"9122\"]],\n", - " AUTHORITY[\"EPSG\",\"4326\"]],\n", - " PROJECTION[\"Transverse_Mercator\"],\n", - " PARAMETER[\"latitude_of_origin\",0],\n", - " PARAMETER[\"central_meridian\",-141],\n", - " PARAMETER[\"scale_factor\",0.9996],\n", - " PARAMETER[\"false_easting\",500000],\n", - " PARAMETER[\"false_northing\",0],\n", - " UNIT[\"metre\",1,\n", - " AUTHORITY[\"EPSG\",\"9001\"]],\n", - " AXIS[\"Easting\",EAST],\n", - " AXIS[\"Northing\",NORTH],\n", - " AUTHORITY[\"EPSG\",\"32607\"]]\n", - "\n", - "Warping all inputs to the following:\n", - "Resolution: 29.960128343948845\n", - "Extent: [372321.835701501, 6812195.9656392, 400722.971437693, 6849260.35757026]\n", - "Projection: '+proj=utm +zone=7 +datum=WGS84 +units=m +no_defs '\n", - "Resampling alg: cubic\n", - "\n", - "1 of 4: /Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/Alaska_albers_V3_mac/Alaska_albers_V3.tif\n", - "nl: 1237 ns: 948 res: 29.960\n", - "2 of 4: /Users/davidrounce/Documents/Dave_Rounce/DebrisGlaciers_WG/Melt_Intercomparison/rounce_model/kennicott_data/thick_kennicott_HH2012.tif\n", - "nl: 1237 ns: 948 res: 29.960\n", - "3 of 4: /Users/davidrounce/Documents/Dave_Rounce/Satellite_Images/ITS_Live/ALA_G0120_0000_vx.tif\n", - "nl: 1237 ns: 948 res: 29.960\n", - "4 of 4: /Users/davidrounce/Documents/Dave_Rounce/Satellite_Images/ITS_Live/ALA_G0120_0000_vy.tif\n", - "nl: 1237 ns: 948 res: 29.960\n", - "[ >, >, >, >]\n", - "odict_keys(['z1', 'ice_thick', 'vx', 'vy'])\n", - "list of datasets: 4 odict_values(['/Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/Alaska_albers_V3_mac/Alaska_albers_V3.tif', '/Users/davidrounce/Documents/Dave_Rounce/DebrisGlaciers_WG/Melt_Intercomparison/rounce_model/kennicott_data/thick_kennicott_HH2012.tif', '/Users/davidrounce/Documents/Dave_Rounce/Satellite_Images/ITS_Live/ALA_G0120_0000_vx.tif', '/Users/davidrounce/Documents/Dave_Rounce/Satellite_Images/ITS_Live/ALA_G0120_0000_vy.tif'])\n", - "\n", - "\n", - "# z1 pixels: 1172676 \n", - "\n" - ] - } - ], - "source": [ - "out_csv_fn = os.path.join(outdir, gf.feat_fn+'_mb.csv')\n", - "if verbose:\n", - " print('output_fn:', out_csv_fn)\n", - "if not os.path.exists(out_csv_fn):\n", - " #This should already be handled by earlier attribute filter, but RGI area could be wrong\n", - " if gf.glac_area_km2 < min_glac_area:\n", - " if verbose:\n", - " print(\"Glacier area of %0.1f is below %0.1f km2 threshold\" % (gf.glac_area_km2, min_glac_area))\n", - "\n", - " fn_dict = OrderedDict()\n", - " #We at least want to warp the two input DEMs\n", - " fn_dict['z1'] = z1_fn\n", - "\n", - " if extra_layers and (gf.glac_area_km2 > min_glac_area_writeout):\n", - " print(gf.glacnum)\n", - " #Attempt to load Huss ice thickness grid\n", - "# if int(gf.glacnum.split('.')[0]) < 10:\n", - "# ice_thick_fn = os.path.join(huss_dir, 'RGI60-0' + gf.glacnum + '_thickness.tif')\n", - "# else:\n", - "# ice_thick_fn = os.path.join(huss_dir, 'RGI60-' + gf.glacnum + '_thickness.tif')\n", - " ice_thick_fn = os.path.join(huss_dir, huss_fn)\n", - " if os.path.exists(ice_thick_fn):\n", - " fn_dict['ice_thick'] = ice_thick_fn\n", - " \n", - " print(fn_dict['ice_thick'])\n", - "\n", - " if os.path.exists(vx_fn):\n", - " fn_dict['vx'] = vx_fn\n", - " fn_dict['vy'] = vy_fn\n", - "\n", - " #Expand extent to include buffered region around glacier polygon\n", - " warp_extent = geolib.pad_extent(gf.glac_geom_extent, width=buff_dist)\n", - " if verbose:\n", - " print(\"Expanding extent\")\n", - " print(gf.glac_geom_extent)\n", - " print(warp_extent)\n", - " print(aea_srs)\n", - "\n", - " #Warp everything to common res/extent/proj\n", - " ds_list = warplib.memwarp_multi_fn(fn_dict.values(), res='min', \\\n", - " extent=warp_extent, t_srs=aea_srs, verbose=verbose, \\\n", - " r='cubic')\n", - "\n", - " ds_dict = dict(zip(fn_dict.keys(), ds_list))\n", - " \n", - " print(ds_list)\n", - " print(fn_dict.keys())\n", - " \n", - " #Prepare mask for all glaciers within buffered area, not just the current glacier polygon\n", - " glac_shp_ds = ogr.Open(glac_shp_proj_fn, 0)\n", - " glac_shp_lyr = glac_shp_ds.GetLayer()\n", - " #Spatial filter\n", - "# glac_shp_lyr.SetSpatialFilter(geom)\n", - "\n", - " #Get global glacier mask\n", - " #Want this to be True over ALL glacier surfaces, not just the current polygon\n", - " glac_shp_lyr_mask = geolib.lyr2mask(glac_shp_lyr, ds_dict['ice_thick'])\n", - " \n", - " #geom srs is not preserved when loaded from disk, attempt to reassign\n", - "# gf.geom_srs_update()\n", - " #Create buffer around glacier polygon\n", - " glac_geom_buff = gf.glac_geom.Buffer(buff_dist)\n", - " #This is False over glacier polygon surface, True elsewhere - can be applied directly\n", - " glac_geom_buff_mask = geolib.geom2mask(glac_geom_buff, ds_dict['ice_thick'])\n", - " \n", - " # ds masks\n", - " ds_list_masked = [iolib.ds_getma(i) for i in ds_list]\n", - " dem1 = np.ma.masked_less_equal(ds_list_masked[0], 0)\n", - " dems_mask = dem1.mask\n", - " if verbose:\n", - " print('list of datasets:', len(ds_list_masked), fn_dict.values())\n", - " \n", - " #Combine to identify ~1 km buffer around glacier polygon over static rock\n", - " static_buffer_mask = np.ma.mask_or(~glac_shp_lyr_mask, glac_geom_buff_mask)\n", - " static_shp_lyr_mask = np.ma.mask_or(static_buffer_mask, dems_mask)\n", - "\n", - " if 'z1' in ds_dict:\n", - " #This is False over glacier polygon surface, True elsewhere - can be applied directly\n", - " glac_geom_mask = geolib.geom2mask(gf.glac_geom, ds_dict['z1'])\n", - " gf.z1 = np.ma.array(iolib.ds_getma(ds_dict['z1']))\n", - " #gf.z1 = np.ma.array(iolib.ds_getma(ds_dict['z1']), mask=glac_geom_mask)\n", - " print('\\n\\n# z1 pixels:', gf.z1.count(), '\\n')\n", - " if gf.z1.count() == 0:\n", - " if verbose:\n", - " print(\"No z1 pixels\")\n", - "# return None\n", - " else:\n", - " print(\"Unable to load z1 ds\")\n", - "# return None" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAV4AAAFgCAYAAADzWxHHAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOy9y49kW5bm9Vt77/Mwc48Ij/vIrKzs7FaqKUEJSqjFhAGPFlPElAkThHrEiBkDpJaQesSEGVPUEgMGiL+hJCTUEkIgNVLRlOiiOqsqK/PeuPFwd7Pz2HsvBmvvfY55RGZXZN2692amLSnkHm5mx44dO+c7a3/rW98SVeUa17jGNa7xzYX7tnfgGte4xjV+2+IKvNe4xjWu8Q3HFXivcY1rXOMbjivwXuMa17jGNxxX4L3GNa5xjW84rsB7jWtc4xrfcFyB9xrXuMY1vuG4Au9vaYjIfyIiDx/4pyLyD0XkPxaR/1VETiLyh9/2/l7jGr9JIdcGimvUEJF/APwj4O8B/zrwCfCvAf+Bqv79b3HXrnGN36gI3/YOXOO7ESLy94D/FviPVPWnwE/L3//Bt7pj17jGb2BcqYZrICJ3wP8E/CNV/cNveXeucY3f+LgC7295iIgA/xj4v4D/5lvenWtc47cirlTDNf5L4N8A/i29Ev7XuMY3Elfg/S0OEfn7wH8F/Huq+uZb3p1rXOO3Jq7A+1saIvID4H8E/gtV/T8+8LgHOuwccSIyAklV1292T69xjd+8uMrJfktDRP4h8F8Djx94+H8A/gnw3z/5+z9W1f/0b3jXrnGN3/i4Au81rnGNa3zDcVU1XOMa17jGNxxX4L3GNa5xjW84rsB7jWtc4xrfcFyB9xrXuMY1vuH4KDnZZ58M+rd/d0ByBs2gCjnbP7T8X0HEXpAV1B4iC6oCWQCxpwOotO1r/f29ep/sflcQEBQtf2+/6257ThFREEV8RvoMwwDOgTh7CxHQshUtO1o/T/1s6OXn+OD+7XbTC3gHPqChA/EgrnwEKcctlydrecyh5Sc5lU3l8p6pbHt3jyzbkLp/bf93P1PaPkf9LnaH8EOHlQx56dAsqLrylUrZ7Pbd6P6F5f+yOygium2/Pl9371d+b6+R7XUX54DY32T3Xe6/4194/jz5/SLqYUJsmwpZXdkN3fbhAy8XbF/2n1HVtrN95u0zSTlXtw2UI7ffRvvX3mQLBzjZvnvZ7Ze4di4DaP1dvD0nZzt39sVzEXABFQ8i/Iuf3PPq1fkXHKhr/E3GRwHv3/7RM/6X//nfwT++QpYJiStyekCmsz1hXeB0huDtQj8tsCo6Cbo68tyhayAvAU0ezQLqyNFtF1MuJ1I5ofchLtvJ6xTxqV0EAGnuyDGg0SMh4XxCfMYNK+E4EX68wOefsf7uj9HQo6G3bRagc9MDEleIC246Q1yRh3tIEU4TLAmSQsFNcQU/c9kBBzIIPD+gL16S7z4lvvwh6fZzGD8HFyBHSGeIU3lNgO4ZEm5xfsT5kZwmcprQ+QuIE7Lu1F7OQ05InCFH3Hoq/1+2Y5STfS/TI+SMLDOyzDBPdjEuK8RkF7QrF3TO6OuV+MUt86sXzA9H8upJMaAqxPIzpw3898CWkr/4nlz5XryP7bmqcvE8VcH7jHOpfc+hX8nJE0JkXTucy/TDgu9XQr8iPsHu/MjJodmRoi83dscy93if2vtkFfKT99Us5WM7fEjlRiMsS99AdH/+hbB9jtBFum7F+YxIJmc7j32IuC7ZfoqCyzif7XP2q52rkhGnuM6254YVd5jte+uyAXIAqVflTQfjAF2/HdwQ0H4gffYD+95CZ+dzdySPz8F51AUkzu0fGlE/QBjIwwsYXiLhln//3/3vuMa3Ex/XQJEWA93psV3Q8nAP5wK8OcMSL16icbtIxVs2KaGglXNoBHElNarPATSLAWwF13LSWiZr2xCX0ewQl3FdNPBdwwbMIePH2U5u58i3z8mHO9TtLsTyq8QFdR5xnhx63MNb9PaZ3VScg2UxwFqiJR2pZC8VfAeB4wA3t+h4QPsR7Y9w/AHd+Dv04YUdIt2OT8ozTgLeDe1v2d8Q0yNRIyr3aH1+vRpdbACcnf1N1kckJ9QPSJoNiPsRt0y276GD0BkA+7qdXQZ9PoFbiY8jqWS8AM5ncnIXQFS/j/r3lELZnJKzvAe6FXzqNi+y2qfvUUB1XUvWLYILER8iYZzJySM+2vOzs23Ltj+ky21mFZwoqby/OCWn8roC1M6tpGwnQQiJnOUCuJ2z806ztH2v+5+zLyCLrRBIDXR9FxGf0d3Nqp6/tmElrwF3mA10gyI9tmICGAPc3EDf28opBPLzT5BlIt59r50DANod7Vyrf3MBPXyKrg/l3J7RMIAfkfFzfHdH173AuR2gX+MbjY8CXllm/Fc/sy94mQ2U5gnuZzthHJYVnktzU969uIJmSEi9CLNePKVe1HaROAPbYJmFOEW6WE7e3AC6nsi6eqSLaMlupDzHHWbcJxnGQ3sf7W/sM0DLIPPwDFlPljHkBLcY+I4gIRhgrVtmSVYDYo9l+McRDkf0eEu+vSPdfEoeXiBubKAL4GQ75M6/f/idBPrwApGADp8R5y/R6YvdMwIq8QKAYceChAG6iKQZDT0+J2DagLYfdm9WltjnU1vNahYDJqdozog4UnaI2vdbs8ANjDPOOXLJGnP7QkPJCF3LIvevBbshx7UjZyGEaJlrOzaZECKqsmWIPoEovtxwVQWNHuczcenIQFcyThElx8AavWW1yMX7Z7V9TtET+rVkzor3NID2IbX3rVlzTo6UfNuWCwnxWig0C8tutWS3u3MGStJQ6CSfbYU2JLuvuvKvDxA8erxpGa72I+o8enyGW86WwMSFPJZzeQHibDfg/kiWAN2tHWc/2vsdfoDzI+ICqolrfHvx8S3DhQOVZS6/q4FuKCfeqrQk7UnpzjJUaSee4nEkVPLuOTt6oSzLZFgNsP2WLdi+yAa8fUIXv10ATnFDRJ4BtyUTDZ2dvMOLbemfYwNhdR5JM245o6EjjwdkKVya83YzAIjRPnfwbcmuz16g44F8e0ceb8jjc+T4A7rhs48+xACdv7GPmCZSN0FeIU2232CUhw8Ik4EtbDcTQHNClke7SJ2HHR2xz3YlRuh7cFNZRah9JypkPJrAiaK7Jbi9Vd7435zx9T6WHVpALecOEcX7TOjWixtxzg7nbLkg5USpXO6e0nDlBuu6hPhCC1TqIDukiyWLtX12Llkm6pR+WFgw+qCC6AammSHM7b1UpX0m53LZNztnnSiULNiy/nKcXKGzfCZF/96NZfsQivOJNHeIx0A5GFUmfTSwDRQOVuy8Ohy38y5GYCrZrDdKrG56ekRzIvcJqedx9Ih7tJtxdwtEGF7iQwHiHElMF6uva3yz8dHAK6dHy/weTuhjRg4Cx95OmKwQFysqOCBiWZLPIII6EJJlvk7RnOwkga1IUk/emh13ERmSbafnUoeRy/tkkJzRLpelvwGyHIHbEW5ujWY4Prdsd3hp7yEBTROaKlWSkCmR+wMuJ+gPBbRWZJlR5wx8YzlhczbQHQ/k53foeEMeb8mHl+jx+3TDZw1Af9Xw4dY43zxBONiNQlbLeHNEGS3rruG2r1S7G5bjJ7jTV/jzzgOnXsDLZCsYcegCfpwJB+Of0zSQk8f3sRwrtcyXjYdvmatsy29Rq9J1Xb6gFPZRwa1yurCBbioZqmWlsj3my3kDiIuo8+R12xcD6GgZO0YDuBAJlRLJlc++3HdxSorhIiv3PrX3duVvwWdElHUNeLettowOy3RD5TmMAnMhQ0koNDpSdO3GhgrS1az3KUiX/VwX5IRRDc4X7j5aES10kJNREIXTd9BqF249kcMA66NRVSXzTfEBNCJ+RGMsRYprfBvxq5nkLCv6WsmnAe5tOS8vSmYYBPqSCcaERIVQlAFTqSa7DCEVjlTs4knOQLecyDhFvCKjGn+6Lwa53QW9KxBJLCd/LiXx4GEYG+eax1u0u0HcSDd8hmq0jHJ9Y9lBnMiALI9ob+CkobOTPnTIMqH9YNm+c5ZB9wOEnjzekA53aH+DDi+Q/iXejb/S4d2HdwM53JJzQHNE2We90TJhANdtWTyAC4izZWXuvyA/myxjBuP61ge6n/0/Rhe9fgtRQAU/rGjyyHHauNlKBUZ734QBUvsKGmcqRAnGrxaKoWas7XkqeFeyzpJJb48nQogN9GpIOS+cT6jsVjRAml2hBna8NOALv5pVijhAjSJwtYZQALv8v9IauWS+sqMOGk+tgi/Zbv1sTz+j7bAV0lwXUbWbVS0Gu7p6C0+W+hmzJAI7f3O2wu4C0vdoqQNIXA1wbcfsnAw95GzZb1jI/cFoB2ZkeYTwSD5EoxzCYTsPfqE85xp/0/HxwBsCxER6dyCdyxX5BvybBXcz4V5kOHirxsZoxbZYFAG9bidczVwzSMxoki1T9QWAe6AT47ycK0v7AvAl22zFonqiVpKxPKa3z9DjrWUDw3P8899jHL7fPs5aONcsAfUTWkBNc2qZBrXwFnorwh2fkfvRTnjnC33x3CrGYTTQDbcXRbNfNZwEnB8tc3EAOzB3wJPim4SAK4Ab/A1OAnn4PinPxPWNZfka4ef/O+70rtAmkOdSJOsi2SmShXCYyDEgq14UlDz5go/fF+M6WaGzAlldlrcCqCjr2m3crc+k5DcaoIAaBTB9oab20QpUEfAJ14kBbCmq1gJbLWrVbeZk+1CzVS1ADOALTQFWYKsqBdVLhY2qNNAVv/G/TW3h3s8gXRcv1ThdRPrYzvGLFZyTLamoskYPLIutNCrgFqpBlqnx/FJWMYDRS0AenpVtJWR9sHM7R1t5SkCvwPutxccBr4hlgLBpPQGyEB8OuDUQeMANWoCyVtBL9luzG9VNDeBAnVpmXC+yoBvv1Xvouw1kQ9hlvm4Dx5yBnl11B719boWJ0BnvOrzgZge6sHGpqtEAyY9omKxKHGdTPXTHJjszGUbYlBEuoP0RHe5AAtI9Q4o07OsK7wbURzTHdqGKsww4Z8teRIL9cwHvxgvQN/AOdP6GlGeW5csiSSvauLQpSjQ7nItodLjOCluREVd516RbAVOy6Y9L1OKYiBJC3NQFBZBqUSoMi0n/GpWQLwDS9rku44tC5aIOkMEJeZVyAyjZZdxoC9VKESwFOD2SXFMoVLCvgOpDKvI0aRlslYs9jbovey53n8Fq8hA2jriCbgPmLNDljTqrhengNynmbiXXovwuy4yWYrG256VWgKvnqqTZztVaA4gT+EJX+YB8SKx8jW8kPhp4CQH6gL+xC17XQM6BvJo2V3zCfXKy59fstHfbCQV2AsUE0QC2yrOItXiGnYy9h9sjDGMDWQNev51wdXvQKvy2DU8+3pLHGzT0xJd/h+7lH3zwY3X+hs7fkDWyLK9IGo1yCINlCX68LMYV8LX3KY+HAyIB390RvqZst32UonRY4tv2N+9GEhPe3ba/SdmnX/be3g3k+IALg3GF4mzVUegf53IDMB8Wo4LSVrTJybHO/ZYB5mzLadmKZCk7A9KqZCha2laMS6a9zSot+91LtvZRXw8F3GQDfldULFKVCKtv+l7n06Z8WG3/LDks4Kt78LXP4Jte11k2mk3OVjXC9nk2RY0Ure4+C9ZCZ+x15rVegc+NRmuZbj3PK+iGsInE600tBKPSwKitGNuKT3K2FVd/YP38XyG8+pPLlVpnwKvdbTmHV6Ol5FdjGa/x9cTHHf1SZaXvcS8n3LNHa45IQvzqGZqFcHeC5zdWlQXTv+b3l2Bo3uiCnGGaDYzr+/TBALfvybfPIXTbUgveq+ADG/A6Tz4+Jx3uyMdP4PgDDjd/90LK9cGPJ4Guu4Mjxvvm2PhUcaMJ0TVuPGo9iQuf6sMtQ//pRx3Sj4lQsnMngayx/b9Kg0T8v/Qz2vMKnVJXJYMgU0aj2rVeOEhdA4rDDba0VZ9g7reiWMaWrTkXDta40OAu+cu9KgAwCVmlEpoyQjZlwY5eqBmwhIx00ZQMzopoJF+yZG/nkDhb2nshLZ3RHKVAmJMzFcL6fgaLU5zEnVIjtUKflhvGU9BtvO5O/YAKfpxbc5ApcfIl6AbrpGzSsdqdBtYoMY6tMcLAcwNZO3jRALdwvTrebJQDbIoHl8jHFwa6NXGAoozpEHcF3m8zPuroqzg0BMtsXhiwSs7IEgncWzHsRzfop9+zOzO2LGIp+sI9cMK2dMpp08k6B11vS6miYczH561D52J/Ql9ohtSWV5UCSC9+iN7+6BcCbsozWWN7rGaJIh7nR3z4Ww3gahNDXdqLBHIrUFiIC7+QXsgaWVfLViuloWkCCYT+7kLn+8viQgO8/0wfmb2E4TNiGNDejrFx5xEZoxXZorfK+7AWaVJGY+FMhwVcwKVCIyRPLumb+K1g2jLGkmU6aA0NsHGvcQl0/dr0sVAlW0Un63OTkolT8BFd683QAMxUDGJKAoqWO2y8LWA6ZGjA6bvYuOdcKBBxGe8zqW6/3DCk0mr7DLZk9AAuRFzI5L1ywd500+zWTBdsldcoBtnUOesC40j63g8hJ9zDW2RZ2spRi5TM1AwZ+sHOd+cgJ/qf/lF7rF0rOSJV3QBINspKw+016/0W4yMzXo/2o12sKW53YcA9m6AT07MWwXfuR2tfrRrSXUZqYFkrzAkZj8h0anRC5Wa1Pxhd0B0bVyVxLidcgPXRWtPr487bXf5JlrvEtw0wc57Iyxuk6BrZgWulC8SHpnP0biRrRPxW6MppQh9/snG+h8/tZH4Sp8f/1xog0oRbHiFai6jLiXx8yTp+Ruxffi3Ss79q9OEF6/Biu5iDNz1pLIWwYNItjR6iR6PHHxby3JFyh68FOLnMHpv+toCu+AwJfMikGDbKYAesteGhG2dcKcg1rbCz1m/XL41mKAcPF7TQDq5w01KUDsG45JAgC142AI9L17LatIadKmHLxtMaGqiq2mpO/OZ5obr5Uuw7K8UnfGn0qIU3XQPq1Dong9U1RNTwriva91YwFng4o59+3trWW9dkWRU2m4ac0PGIxIh7eGPfY++bTn3Lfu26kymRx+d2feQELqLx4a99Hl3jV4+Py3h9Tz4+x4efw7pb+pzm0vpbOdxUilnPjOAvGem+VXefqTadYvF/0H7cmh36A3mwk0ZyNODSiBQPmdoqm48vi1xmJNz8uC351/TI8u6PNn4WkPURl+PljcCFdkNIQCzvp8Pd9truFumeoY8/wT98gZvv2zbSs69YD1+Qd6qJ0+lP0dNPCW/+P/OCKJ8PrEKtj6+IL07km4lVI93N3/1VvsNfGJatpw9TEN0zy4r6wYqXwwJZkSFb1usU6TJalAWaPLWhBa1cruDDVqCqy3M7phuAqhqv6nSTYb23rzE0PrUpxrrUJFmmGlBbspM3EPf1ZpEhglYZV3LgTTZm7cSeblhall71yTUqCKe4Fc18iGUFlIhLt5ORpUuZXMilKJe2dngomf/u/44t6w2ygap9We1p/s2rtmK8KLLVzLcf0Ke1jqLnJdiqrwFwKQTbtYP9zY/I11j8vcbHx8e1DLuOdLgj9ANyPsHpjL5aSW+OyLDiblbk8R76gXTzGfnme8j81iroQDXwaJlrjsj0rm2/mr7sDWzUD1tVNid7Dta1hQukm8/R7gYOn+PCLSLhgmdd7v8Y9/gzZDnhzm8aPSHVxyBny+J3hbl2k3AedX/e/paHZ2gYcOsj3Zd/Vrr3tm6iFGdSGDlVGuLdH+MfvyB8+We4h3fmiVALJ4ej8XhxJc3viHeRubv7a3PElUKJhaPW2dqNZficYfydRqn44TNyfzBdctdDPyMuwdl4SKCMuUy4vJDPvanXxDrTfBcJciYvvRnqzL0tgvxmpiOiGweMuwCrWtBqP2vWuaMYLsJlA90+QbRWYVSK9rvypyBJAZOE5dIYAaUQl2uLcbpo2JBdJi3iLgxyWpda43Z3oFtBtba2h2w3ji4aR15vQkGbFrlF1gK+BYCXFfqAvHtL/ux7dr5USVlVB+Xc1AwSI9qXLrYdAD+l49AIbti4XmjAe9U0fHvxkaoGV0Brts61V4n4+taWosNqd/TTGZ7ZyUD3DO2eWWdYnCCM4A/2pfvRONPxNSylq2oZ2lLcONsEGnHTu9bOK0WjqIdyMh2/jz/8gK67u6jmr+nRQPfNP8fN9/h3XxoAxNVO1l1hT/thyyycR05lGRa61ikky0weD+h4gzvd49682jrYQrDmMeesTz5H3OPPCW//wp775c/NSGiphQ/rfpNhRPoB5zxu+IoY/gRx4a/M+daYl1dWDEyltVhjc0Cr7mYaJ6Y8EfrPGPpPGYfvc7r5nPzwGrl9ZsdmniCkC6MjOYDLq/G8xVkOaC2veVlJU83OjPvVLEYtgBXgkCLBMqDFWQtvnHvLrEkXTRhA80qQSlvUTkafrdFgVQPg7CwDJsIacMNKnrsClpfeDq6z7Wn0Bpq7Jg+zLC2ZuWzGPlWtUNdqIooflp2yQcu5X7S9fqMg5LBYY1AUNJRGtj34Po2S9VqHmkeIW/F57yTXD+1crg08QOtko6wgFTbqzYWyqiuSRwm0pcU1vvH4OKpBE+H1n8M0wTkS39yQzkMRkIvpcqNpamU5wXpfeNgHW7Z3t0i4xRcbRADt71gf/sTANyejJuDD1ET9Pa5maHN8+QubFZbzn+G/+mPc+Q3u9A738M70jyXLrNVh1gXx4WIp1wAVrEW4ZBwurmi1WaxFj5qVLDPudI8c35kk8+1f4L/6mbVYPz7CFE0y5yhcpak9XAgG7OsjxIlYbkJ/VfBd0yPx9BNk+rKJ6NsKo1pIqhVUMhCj3biG/lPk7veJ0brwvPPIuzcFfL2Bb87QVwBIZuaybgU3gjZesxbfEjR5V1oD4s0dzDjfTcudk2W5vhTBfIi2nH9iyajZtMTSxYv22mqCo8khXUJ01wXXuNfC/e4bOUTR6jjGzpOhNEDoGqz45RMirsnPIBW6ZVfs88k60aoUbmd+08Lnxu+qK7rjvZIBNtVP8FY72ScHe9CtXG/OjWrYq3u27ZVrJfRNx2vXn3lOqkYzy7nOQfjW4qOA153f4H8yw2kive5Y396iyeHHBU3O9JJRrXf8/KZ1VUlcwHny3e9zGH94sc01PRpnG+d2p64WjZWj2kejCkrh4ENFqcc3/yf+qz/GP77Cv/kSmU52s0jRgLRaPFYtsVajn6KlrI/Vi6MUP+R4sGW5K3TBakJ0YixNJQk3PeDefYl79xXy+pXJ5KZoGVo7kNpuUIQTMh5wy5m8PqLzF1TYf9oIsY+mOX74E9z5Ff7+Zy3bser3YjeonKzLLi7I/A4dnhPXB2J3Szj+iOFv/Yc83v0zwp//E0IItsSdJhjYevlvHHI+2zFYrBtR5/J5OvBMJqFKHi/WcqylGaKCHX4zNK/ZpKsSq2y8a1My1AaFopOtznatsFV2S5Mz6uCwXEjQRDJ0EaJDc2i+CXnpcJ1lr3n15JLH5qJi0LX4Dq8ej4Gvq+oFB+Jql2Am3J4bpQBbC3Lbh0pDVJph0MKdQ5F40BzuwM67cq5dFNVC2JKEei7CVugutFltnmDP78IGusOdNU9g0sjwDRVyr/Hh+DiqYV1hcjBHdD6WdlFr18xzb3f6Z6WSGlfc9FCWOj25O15sKmtkOv0p8vr/LgYfg0lfKpXQH1phgGAUhKSSXZVtqh/fA92UZ+T0M/zjK9zDGwPdagiSs/0+WSGJtWQiEUDRNSO+FGaayxmIJLuAziscOjgetm3VjESzVZlrdv36FTycza2tiDokQO3W236a05s7vcMNz0hhgOHz5iCVdp1p3g04CaQ8s65vrBHi/AqZ3+GmRzMoWuamFqlGKn56LJ6uPem44M6vUedJ05dML/+Am9t/lcfv3QPgQ9eM4LcvKyPj2ORMxIjc39sxXEzz6+YFN3do8tZ8UgzA09K1vKqCkRPd2SyWZogqRYOmOKjAXGVjTf9aluxuWFGfEa/W/RiSyeD6bJSI2ywlwYp1tiMZMG63gm716RVKAa/aOlZXMqB2oHXPT7vW9+IpQqUrLi+Zts9gLfN7fM7ZmljGwW7g9VyqQBtC6xS1a2IoevZggDs9Nn43jzeXPtPN9rR4NPiDqXg02orzKiX7VuNX8GrwMCju2UQ498TTaJ1IxbfBLQuyLEixVmwVVkDf/BGP7o+tqLac7GedAHF+jTu9s2y3ZLXqaIUBiTPh3ZcATTFBeL8yO09/iZveFRnbrnJdz/il8mY1UymPR7to8tIZLwfkJWxKDWfTLGRay/iWrZqMs0484Ut818PjA9xP6MPWVm3eqxiARHaGKHm7SDRa9bmsFKpWuErdsrNW5Li+IU9fGL0wv8Of3ppi4uGdZUtp8+WUYG3W6jz0g12sGB+Y4kICppcQbn5M/B7k4V/gz29se0V5ctERCCZ1qtlYzvD6NfI2bf4FUjsrtGSzRSUwrE0hEbxpdz/kYOa72FQGdYpIM5GJtftNzLUubMZKMpg9I9VTwcXSXLHZV9prN29doDVd2CHTZppep5i8Nz1iV+gT0VaMlP3YK9j43Iy1B9cbrx0kGHtrNNq3wWOgWae6tHb4eqxzQpadJr4ofzRsLma5tLi3pKW7xQ+fNXrv6zBvusZfLz6+c+3mFvI90kVcH+Fky6x4HknTgBsWwotH3HRG611YCrGPaXClyrpyQtYTbnosGdu6a7w443IiPjPQlVS1u65U428+KADXPBlw5bQVxmA7ed1qS/8a2f49BQAtXUtpqmL6TJ573Lzg3YQ8Cxs3t+++m2Zzb3uwVtUq0lecXZhOrdBS/SpC2AAOrAiSJhJvLOPf6S2zMz8GXV4j51e4yUDXMvuzKUpO5/eXr8E3oJSut+JMCOaqNjwjzV/i+jvCzY/Jhx+wPv7E1ChFvufme7vAvQn2w/3PkfFg0sI3X+DOJ9zNA+4UyUs9Hlo8fWZc8hvIeTNHx2XzR6jL/FpAqxxvUQ+I36kDctwyTF+40rQZ4siQcLEU16p5ejXziQ7xlJbeWM7LJ4Wueg4Uz9xKUVS1gqvUQna771631cteLlY3OTubMAFGZ9XTLHjziK6F3doVCmwNIFsAACAASURBVHbujoetc61GfU5djVQPkuNz8vDc/hZnc8grCqJ6jTg/fnTR9hp/c/HxwBtsCScBpIv4YSXNlimmtSM+HAnRCkSNYgjDRWVVKZpc50Ej+WgtvhWkWyOECyYVA/NNKCdXlca48fP3d3HfkVOAV51Z8xEdhAUTfO58IbBsRbEi0N5xC4As5BygnO9yn/Bu3Y5eLfrEZBfUOaOrbx1WmgXBpiAQtLyXIgdaAaU2mrjTV2Q/olWdANuMNop2eX3EP35hfPLpfpOqTXMpimGfLxbJUjVtB8uCy3aIixUz0xnNt0gIHPofwvhDlvjWLDPPP0VPPzNT9fne6IqbT+Hm0zZuRpYZmWZCfCSfelvmF6mX6828Jp5G41ALgNm8va1dWDzvScgqNZHXYFxrfaCYKOns0MXjBnPc0tW0vubjnMzlbAFUUNxm6mRfOK4C4v7vu8cvRk0NVTpWjZ4EXTxyKDI2t31ddkO100wOecsP6ogrJ9BXS9GwaXbb+eYQ59FlNh8HuMyIxwPVslRDZ81D/dEAuz82hz12rcJX0P1uxUdTDdbpFKAT3M1iUs+5x5170jS06rY6Z8uf/sbAs0jJ2nbSGfUT1My1mM1I96wBpxZ+k3hGw2jPr+HCe4W6Gvn4krSe8IWaaObXQPMMLryuPV72KfrC7zq7sKJrQIyac1U697as7RPS1YuqZjlWlNOlFGpaM0HeNKdZzQthAXptmZPEiH94bc8Pry669NpSv1Izalx4pRca6D7OsEuQ2n4F4zSbG1kD+rVkVRM8aSgI/obz6c/wr/4I//DaViBT5d8H8x++fWkZ82c/wOeMHO/x7x5wu/2QGwFV/HQi3/egYkNPozcZmmxNGZo3IEalLfM1OtR7tKseEuUcW0o7c7EUbTe66LduNmjcrLho712+z6YdJrX3raOmauznpFW+uHbRSUimqiCjAfYiAXFsDp5d7VCTjeoqShkdj1Ykg+17dh6Ni23uSbenOrfpzp0nVz+SqtGt/iJ+BNc1FdG+Pf4a3378au5kXV+WkCviJ9y84rqIPyx2cgZvF2d3RA+f4g4/wJfmhtpum5Nd7KrR7Ay9mczsh0KmPKMaSfHBJkX4yab0FqpiTY/vFdd8uGUd7siHk2WQ0+MOuLLdNJ6GK5yhyygGvvtJyM2dq8yC0+zQcwd5tayy1w2A41Ztbxd+3py5rI3WwbDCSZEhwjwhthvbBORowLufJFyBUospu6sTnpcFHmd0uvxMUBsKAFbrUKser7AtbYt3RJWyBX/Dur7FffXP8A+v8V/+FLl/a+Ded0jX48bR2lWr1tkOPrx4jhxLNdE5MzoKAZkm/P0DLMmAOQtBxTSuayDPXTvmODUQldyGllY9b4sozf9Al9BA1z5Pyaaza25hFwb7ThHZOZG1w1EKaYVasD/qZu3Y7Zf9ZX/qz6rBDexWQrKtrGr0wb4HH6xLk1os3jhbAIkdGldLAnY+vNa1VnS7/Ug+voT+ztJtf6AZ44cDUmoC1RAn5flrdc27xq8eHw282g9IP1tl3zmkWyz7G074LMhR4dknRviPz/HHH10Yj9u7viDlmZQnNEd+mYdsff6aHlnnL20JjrXwLm/+Kd2n//blpv0N6fADcuOR/+JSE3k42s8ysl2ymgOfFKoB46z3oLufFJtXj8x2IXix7NX8hbeKuy6Xr9HsLGurFfxhxUVvPfz3EcGUF5JtcCRltVALXLJMBXwvs1KZTpbtngrollZf21HshhKxSv2+SwpK4dOKjJIjOr9G13vW+EAePiOdfkKY7y2zfvsa3p23Qab+DOMZF6NxkOtiSpE5GtiMPdzcoLfPzJrz+Nx4/NMDMp2s6zFGmxgSE5xn5HFFHvvGrcuwlEaHOjHaFAtEQQ5pk29ZO50djy5e0Bd5B8Ya3YXKQYuhjXP1/5d62P22mp9u65RT66BrJ+sTcN1zvnUSCtixH4ftXATkwXTf8e57Fx2bxvPeXEoEy023GUEd7oxWWB9Kllvev1iUhv4O78bmqfHUW+Ma31585NpD2rgbKTZ8pn1drMIMcBzR443pCv1oNosfCO8G84YtxNi/bBnU+RuiKyN6SuVf1um95zmxCQy5e0YeJ/L8zpbJcWkTdpvciglcQlB01ytf6YW8Glf5VKOZ12A8ZXlciFY8E92WvXmTpFXT+LrETWejMTQL3p2BWKwVze5PpkckrAa8U/E2jvF9m8B1MU3tWdvym2TqDPG2L9Lm0FVAtoxXdiZFspwQNzcePseHtqpwpwcD1aStEElUSDPV4J4lkt8IunRWhDosyIvFnOt64+vj3fdx4w3+4Q3SD8jDPcRHWJLdHLqMv52tILkGECWXG5yUqRD7xgTpbLSPiJpmd1cos5UJjUu2ydbl+ygtvdYNV1QOBeDrd2+Z7BPQLb+3DLjuR9X4hvreRcFgJ+P2sxrhgK0Y9+C72IDVFHrUDyAJekj9YTOYAnIF36rX7W9snlqcNj63FGD38Qv9Oq7xrcXHda45Z6Y1UGaQzZZNHjYw0OMN+fknv1Du9TQ+5mRwbrT3TpONZO8/LAIP4Zbc35HXe9LN5zj/zoYALmfb7xDs4u8erVPLTbb/s12Eae6Mr9atyNZG3UTfqu7m4lVaT3NqxTlKp1YuxaRy8MixcMe5M/AuwO3ibG25+RHJGf+0w66ONYpxa7yoQHqO6NldLnuhuXUZIGck6DaGaVmtY8950+0uZ1OKdEdyaTWV9aGNEa8AcVE8mgTJk/HZsyN+9Yx4Gq2FdpwJeo/jrXXm5Yzc3hn4xNW6+V6/Qe8zOjvyeSgttmsZbFo41dq267Rxqk1FUIC4FtTss5bMrigPJCSzuAT8Yd6KfrqbdL2/qe7ohf3QVdyu0Lazd9xLyTQb+Eo9PrVJYj/KxxWevds1R5QViDvdG/XgfBvZrn5bAdbCc94ZOmkY7E2reVOdQt1qJJEsxu1eQfe7FR/t1ZDHG1sOh37LfPcG5FXeMj4HCaQ8fW28UooPsD7gTq9x8z2H3//PPvg87wa765cxPnl8Th193cT8S2mrrd1rkWa8klebqNHMXpyyd4+qy2HNzjKpZNOrpExvyEswn9r9UrcAcpr7JtbXXbeWXdAJyUW/WV9Yp3WUluOLidw1A2WXtZX3aTeM2jRAttbfzpWKe7RM691rCB2uH8jHZ7jzG9LyeHlAm18AsJifgi4eZiA50uPIen9sEx9yNDAMPODGe+uSrrrUZYZXX7VhqelxbCsCPy9Gw1SO+LDCsnG01syim3zsycww6XZDJLMYoBezGiWbwiJX7tdRW4mrKkXxNvLo6SDKi2Oh20m089dtsb+ikm7dkGBA63fnxE4+Vn9KTrjFIcu0AbCzSdzqQ6EbdsZRBWx1eb2N9ZF4IbW88rrfvfho4NXuaHfdaj7+dNzO8My8P4cXplD4miLlGV1e485fEV7/uS2Bf0k4b3SDakQlFAPoZNXimkm+fUf+Mltr6RqI94fSEOI3k+/Sq98KLyUTilOPH2cyAcmC62NbGutqxZ4KEDWrsm0aOKXoL7XDori84FiR0vGGl7bE10jL9GqHVOMly6wwEk3BUX1qDbilNB/QlsuAZb1z6YwbxkZruGUi3b7cgKEPxt9OVoTU6JtcLp0H4mkkLV07PikL8mAKlq57h8SE7Fy49LUS3xwbj15vUDGO8DjiH1f87RnrTit3mgJ4urpGn1x0GII91220izvM73G3wDblt4C4Rn/R9XZ5IuX3Xl+pHHu8KBg6abPrWpOE3zdTuEtJ2FP9bk5AtykcYCt+gl1vzJYFFw8O7U3zTQ5thLv4EcrsvVQ04Kl0PV7juxMfRzWIt+yxetnmePmEqtcd7qB71mwav46Yp7+E9QF//zNkOpGef/JLLT768ALNkVinR6yPuNqs8e41fPEl+jaSH0fy3JOKHC5OPXHpCrhVP1m9mKRbR8qkaWhV9zYAskw0yNG1SQYAFF/YvGsmSGvlfysdUbLUc1kqD2nLpgrQiGhz5dLVXwAtbCDf+MtUtK0xW1ut6qY3Pp2NfpgVXkYDYedwu1VM8w3Yha6ePPdmjD71LI+HzbzcJ0y6Zjcsfz/Z5wkZ8VZxTw92c9O4aWtrxxjqWB/sBujHGX8zGWdcu8OKhE8nabaTOHASNwqgyxtIu51Fo8rG15ZjI06RYbVjX1ULdWLwE25/30a+z3w1F/VIBd86vHI/NbgewyfDWomxXIWlDbhmunWi9e5nA9/C8VYzJO1Kk08BXedHcpqaaf+1qPbdi4/PeAcDNICLde8TLa4r+sGv4067xLdofNgsDscj3b/5n7fhjx8Sh+fiwOTCLTlHNAzk4ZlpZV+/hsdIfjeQ55713ZF4HlmnnnUaiMXH1Rc3rf3FmqPiQkRzxi0dLohddDuONa+hOGftJGVATr7N8aqxFjDWLHRZ8LtKvstLa0vVKr1yBVwb0O4bEQqI+bTRDdnoDAOhAuRRYZ5tXl5tOogTMgJemrSN0G28sphkyrLdQDr3dsxO4wUXXqcO52TDJ+O74wU/araNPRpdG5AKoGkDX02eHDfKJ6wT/vbcCri6sFEPbkc9PGnLlZvCB68ZXSodZoBsLeLuYjqwVC1wnRnXrRffa51q0SidUGfUQWsV7nZgXadLxLRlt08sHrdJ3FVGtuKmx93onnTxeA2tPG+1e4RGL+Q0oXkiA+Phw1r3a3y78VHAKy7A8PL9TBdaNbXqcX+Zs9bHRMozcf4S8lrajU1e8/jzP2ytx6sLyO2POR7/zrY7ElBJ+DKOJ8+vLyZGaOF0K+gujyPzNJKiZ107Qojk6qwF20wul1HtUI342onl88UImrR0mxytqCIaOLUs2n7mFMhF5+t8tizaZVy/4pPHH4tHbi3u1QIR0Bo9amZWC2q77Bsp/rOixkmv9vnzuS+dZK4BopyjWT/2Z5urF4IVH3MGLUv45IynXjorQka/gdHuc9XIS28qgoSZnkffALXeNOr+12OkZQaaukx+PBDPI+FxxB+W1vTgb6ayr0DcGdHUttwxwE0pvoawSfHevoP7DB0I6YK+EZ+RbmnKFMDUKsWk54LfbScaG+juY8/t1rlosgPc9vrdFInqa5KTeZ3sOF7gotgmOV6Y4gDWcFSuiTD+DuJCUzRc47sVH53xug/MFRMpoPsBPe5fN9b1zVYoKCdVHm/oXv3z8rcCJA9f8PjsJ4QXv8/Qf1psE780adTpp4TXf0r46qe4d2/aBaHJkWNgnXpSNEtAVSFnxzwPzavV+1zGlys5WAYasrAWE20pvgM2pka25b9uINtAWN02m4z6ERzreXdRiRLGmdrK6g/zxs3udKrbBnbV+N3fNZeCmxapmpYR6KWrrhmYY/SGP8y4uOCPC7ji+XCOjV/W6K3RYe6I08B6Hkwmp4LDbg7Nc8EZ0OeoSO6Mkulye84+qlduKwhW68gdVZPXQFjmJu/SNRj4dhE5GIDqIrCUG6WuMBawTdGUHOV7l4OgZ0WeOZgzuqgV6io25sKrrw5h8xBukzn20fS60AZX9mHLdsHkY+U7qP+sSBaan0ibINGPm0Jor98FG2UUdtdWTpbtpgK4GpH+JdVzlwwxP9jKz389lN81vp74uIwX1zLI9redVOXrJvBTnknrGzupljclY8240lory4yOm92kOk/sbu1OnyP5/FPc489wj18S3vzcQHeeTJdaxsfUwk6qWWnNRHWbopBzGYpYxpG7XcHFh4jrEjl5MxzbjSwHLrO5Hb/bHlch106rIqtyLjUvWunizpylbrNU5i9AtuiHn/oOJOyGMF+OhKkZZwO7YlSOqDnMdSusmXxvBazKKae5Jy0dcenIeWdDqAZStfAXFwPbwmabOXrpCGtUS2lIqCPU2yQIZ6PlK8WTk0OTEKcB369ogvX+SJo7ws2Edye0tCH7T07kdwMuzMjDyWgV2PyDARlsH4kKg0O6QkmkyhELrGqFttIU0yRiteAJF/z7Zv0YLgB2e9Mdr0tRNMRongxxRXZOfgJlpE++aKqon0Bi0VxXOeXehKqsOO2cqN15H1ihXuNbjY8DXvHfvNnG/PrCc1aWM+7dG5MlOQenB6sQ11ltD3/Ouj6ARtzyiL//Gf7dKxvV8/o1+mpFZ4+u5YQu87ecKPEJcO1BmB0opwIUqkLKDh8zoQxSrMbZe/DNpfq+z4DbYyrG8aqQKEC+M21tS+txbnKoVqmvNMaTLq2LUMd67m357lP7+XSJ3yiVkGER6DP6II2SqO28y9tb4tIZnVKX6KWJIJcpvvi0AWUXEe+2bdfdepr17iZP7G9OdfxOPY46bTcQmQbSNBDm3lYkIePOO149qjV2RE+utqW9TbPAKdwr8qm7NBKq6osQtikju5ln+GDZa3GhK1/iVkR7GnsQfgrGT4dW5oRbpgsr1aqxljqdpUy1blNG/AhVPeQ2jteHW8vgi6Lh6tXw3Yrv9DeRNdqJFWfzKshpk5FF8zig782AHMw83XkbOwQ29md6tBlqr1+jb1fyY086mWQnl6zKlRE0PQvLDDlLyYBLoajghTWAbeDb64JLjlSW1t24lCX29hn2k3YvP9tWEFO1AZEiSlw6mzUmasvmhyN+GuhfCOLOWxFr7zObfKMlnmbButMT5wJa1X6xSaWys2nC2hHyZFzulMizGdzn6qWwBtbZhls274ndiJ4qk8trIJSiVZXj5dUmQUjtJvvAcdIspQnl8rNUnrwqRuwzmKQsLR1yyhu/fhrxxwl3XmBR0v3BtNmLzWNDdDPT8Rm/RLi7MU+JfYRgA0mdNzew0Nl5VORfzWA/RpunV4tmS3Gtc93l9tpJVLrV8tJc8zTUDNdtXWmha/yuTREpNpG1OaI/Gs8rEfIK4WBmUm60m2AduOog5auW97sW32ngdWL8VTVLr0YiEq3zyrqwTtAv5u4VI77/yvwBxhub6vDuDXL/Fn27omdHKlIl2ADIh4QOC9Ajq7Ks3ZbtZsE5R95lrBVsUim+hTIixk89vS/dbDvlgoiCZFSfFkMujcBzLZJFA5sYA2np6A4zfurxx2mTXe1ogkoZbF1ytXC3FfjyXm6WDLhEXFvOa5n6EE8j7jDbjWzuTPJVNMlx6j/Az+pF5qsqONnUCUpZVdQCz76z7gkHzq4IuS9K1ue79p55413rZ9rdAMyU/7Y9FyzTdX2VnBWVQp+K/Cugt8/Jx9vikXGGIt8C410lrsWGsdy8jrdmVPTwDsbRsuPzyXwqshaZWLm8Utyy5V3GK8ts3rrFpL6aHwGtNVicI4+3FzMHq/VjUzSk4kFdMl/N0dQbhef1Ybxmu9+x+E5/G94N4EI50TaTEJlfb3PRcjGoicl0qMOIi6uZsbTBlKv56jyOW1dayXokJPywgMus08Ay95a57eiElqzs6AZFWGKHk0xf9J+5AEWdngBs5jul1bVyurrjlLfMrgK8K9Xo0jq7ZOI0EOauOHXlVkir2e6Fi9q+ALfjgquu2B73l/vpbHqDLB25FPqeSuFy+nB13CRd0o4bgPfpvedpFqTTCwlYvTlUnXMF3KdcuLgdfZM3S8dG6xQKJa/BaNm5M267qhJkawO2g2rTLRhs+V+tLtfPfw//8IUVqnIy8/c6lqqCX3mszhKU6WSdhlUFAgbE7eCVE6jKyfp+cyPbDrDVLIq3RQP5Cv5F0VD9NLRMltheH2G9RzsQN5Lz9LWqi67x9cZ3GniBpmRw62mb+XXxOICWltoVhgWpQy1PZ+PtljJ63pWJBrplgXnu29L3glusz9HLbC6pIyZ/8fc1BVJyBrxZGI+TFeNC3DTAJSOtnG7LQFtm7cnZFBVrtKm/oY5QT4516pE3z+hfPJrDVgXoPbXwBHCBi6aN2hRSlQg5YoU8n5HqiyBKPI10rbPLX/LKu6jDJ52zm0Qq04dzOT55DXiXTQ/tsnX71Y462JQMT5pL0rqBknOmljAjo8sGiJatZ2tYEC1TInZ/bwM0d37DTbsbsPOj70m3d6y/8we4mx+hz3+PHB/w3Z11PqYJXe/NBWw3mLWConMOGY8GnLfPLQuWJ7xulbONY5l/Vwz6czZ+d6dq0NCRx/fVQyY1i+COZgXZHrBsd99AcZ048d2O7zTwZo1GNczvbOTMuy+3JVuIm2vWlojAkpHzAwTQCWQ0oJaATaNdA66MkzE/BU+KgVSAyvtE8IkYnzo8lc4sUbzL9hp1oFtxSkTpusi6dC3jcyFebCMuHSntZFI7CiNn19QVKQVSrUoXzllcGad+OTf0SRPFlvnWKb8ts95lxNtyXiBSst/cPCbqvDnNYhTDU33uroEj5cIhl5sKmKrB+Wy0Q/LEpWS3aSUcJgP1ndIjrYFYVhu50BV1+z5EVKS9b1U/CIXa2Ld010x7f8PDAP5iPHyXbXzTM7OuTC9+l/7uD7Ylef8ZWc0vWt2IhlvkGMh5Ip9/WrYdSTdzoyfc6Z3t83iw+XY1SSi0g4auTI9wrSFCm+2js1FM440ZFvnhcm5a8WjAeXSf6QZrzfbFBfAKuL8e8Z0G3pRnW05JQNaTncihsyXdOVNHqdQpvkSxJe95s2WUuYDX3LXlputXUpFTxbUjxsA8DaQi3Hcu0/cL81xsJJ+qFGolv4BuwrHEQO8j6UnWnKOZ7axrxzwNLLts7r3tZk9Krt0EWENr5hjTtnQdwSbm7iYlbBtxFxxpy+J3QNskbNAAG2oS5xoVIyG3oh0UvjRZ0XH/elf0zLXo1vws1kCKRmn0/QIhomUVYI0niTR35OSZz8a7uz0dUI9h9sbv1qLgLuoND2iZ9D4rrvstZUy8OZzRrBt1PKDHZ+TDpxem+inPOAk2RYnYBkUGf9eGfGiayGXZL91jG0ypteU67uiEnMzEvH9SxKuFxP5gxuYFdKl0Qnvt0aYF1y614rm7l48Ff3Plcn9N4jv9LXk3gD9YBXc92RKtgK+EAK4o+3fdR7qEbQLEai5hdZpBXYaantQywXXtiGtHSp41dsTocS5bFrWrotfITzM/taJPzJ45djw1qszJsSw9y9yzRgPSlB1OLkGkURnZEbNvz4nZMwLRJ9zc412mGxZgQby8BzK6k6ddqALq6KLs3pORSdEet5uAy8aBP2F1tm1tUjRx2W5EO8rjovBVKJ213HCCLgbqPpUW6tAMdrbvPW+vLdtWqctyCu3gwGejjyqHC4XvzpvrWxnKWi0lq48DncDtEQq3S/fsPclVNeqvoBvXN/hwyzB8n5geyRJIGmF+Ay6Qji9w0wN5vNl0t8VIaqMU/IWZuSsm97br22BYDTaXsM0qrFFsHyvomlxsvPrt/prFd/qbcjthOGBLurBCWE3+kzMsNuJbHwugaOEMi/yp+gkA23K08KZpsZbXGD3TPBCTZ0m1GSQzhLWBH+wkYCqtkKYKSQUQVueNLoj20yXjNzVvxbr6+iV/QJJVgKbSDfvH6u/dsBBLA4PziTAuVhhbQ+NK01M+tkq9srMOvT1IOkVUwCcDODX9bQXDOukXaKPS6+tzdvZaIMWAD9EMhmTjv60dGnS1DDcuna0qfGade5bT2ApyYKyRuNwyX7c7NmDgm3GEfjVFyn4czy5Eso2iOszmqTDUbBgD3U9fkD/5DD0+I774IeLH90A3pwkRc/lyfqTvP7NuyDTRdXfNACr5L6Bk0KlQBE1vm2ZTSbApFfa+C7lkwBr6Jh+rto/KsDVHuAD+gOvv0BwJ/V3T6F4B99cvfuVv7Jua3yRuJPc3ps1dzqZqqL3vOUMxqdGgMMnW1roD3Vg8cPdV9wqOlukG5tgRk2WaSW25/ygjQ1jpQyRl1wpqKTsyQspykQGvKRCT5/F0JGfP0M/0/VK60XKTn9Wo26s/VYXdLF0AnCrz2hm3vCb8eRsYGkIBsl0xSQsVsC8I1kw3p0vVg+0EJj3KzqjyMkWiLuvTWm5Uq0fVQD0l3wqJm0PX1um3LxiK5LI/jmUaqGOVAJa5bzeJ/YRhTR4tmfhT6sE2vGXmQBuKKX7ztJCiGZYu2ziqTqyrbBxgGMnP78i3d6Rnn6PDC/rxdy7eIsUHk2VpxHd39OEF8/KqSbVSGcQqEpCbH6HLa7SbkPUBreOUnDU6iB+aKqcaS8kuy5WcyqTgG6MX/MiFH0oBXal0R3935XF/zePjbCE1saZHUnywu+3TsdRfc2SN+HBLlEu+q0UzF7GLT6GBbl4DcdoAdy3a3Lh2rGu4oBUq4C4pENMGvNVb9kJGVpQN7e9s4KtJeDgf8WX5PS09x/HMOCx4n4ml1dS7TIxbFr0H3X23nKr5rzhRptWka668VkTp+4VhlMaZ1kz+aXNGBd8LRcATflnLSiEBaekbFVIBu/oHq7oGpiIZ0W07ojVLLdpZl8oNIJeMPxBjYCnceS4A6pySc75oxa5G8dS243qDUG9KByh8dlFJlPesE4LbeJ6+GNvUOXDjYRtN1Y+lYBWI6xtcMe4HyOUct30xwEvrGyu2lU37cNseyy6QlzfGw64Prb23UgaAaZqXk7X8Fu8EdR4dBpumspsmYedTbYIIiNuGVuY0ka4ysV/r+EjgjazTX4KE9zwb/iZCNZlXQ+G8NPSIqyfjTudZk4NiP5jmjngeScWeMUZfMlwrXsXkWdZAzJ5lNnOcmD1L8qzZk3ZKg+QNiAF8uaj3gLsHr1UdD/PYOEqHktUaIZxTurAa9bAD8adqgbZ93UBZUFLuymMOJ5lxmBt4dsPyQV1wfY99dxlc0hft7648tzw/6q7ponyG3Ljh0JQHtRjpnJYbRWZd+gbOsAFs/azrk/bmnBXnLvctrqEB8V4ZAlsRrfK71ZSHwt+LK9luSNboNQSb7Jsi8nhvGebz4gK2PiLnV+Q4MXVftIkOAFqyzLi+YTn/GcTzts/xjBzsOhAXcIzQ35n0rHSRteMLlunG6jTnobb8PtHkSv/SJgNLgK40QdTPXaRi1WP3OjX41zc+EngzdRz7g768wQAAIABJREFUNxExPtiJ50d0gHQwP16ZTmXkUIZoraeazMSlerxWedJ+iV2lWyl5YvbE6pGgjrWoCZZkwFtjzY5JAk6UziXLQNH3KAGAlIXT2tH7xJo9vYtkhCUGOp849NJkZnLBXfLB7dk2i81M289A56PJtHag7fe+sh/QJO+9EJ5muqqCI7fHL5b9u5vDfht165u5UPWoCAWMXQPc/efcb8s44J2JkDq74ewaSiCSxPTBnrxJyerNQ4p3cfFfqLPwxGdzE8tYHYBywx57mCbEvcOFrjVCaHcs/GvYFAQ5oumMSrAW4JqBlqieCN6N5gJWZwKCvaZ99gKe/oB2t+j6AAONdqC7tbE9WBbddUYjPOVuU57J5fpzEkiaLh67gvCvT3wcgmq2O3kX2hLrbzzi2U74etJXqqEK0lVtDti5awbbe7C4XCYXrjM7vGQiW4HLOyU2T4bLTDSrjXLf60sdl6qEShVMyfG49pY1OsecMl6UIUS8y4TdVANfeN9UGxpKpmvvaUBbueRKfyzJc9vDee1tfyrP+cSw/YNUAjugdbn5DT8FQHFPP5srdMAlEOfdT6nZeVVnJLm4ueTCkfsnCoq9HOwpUOcMflcntP3aSeiKtrnxuvVYFNlYy4zrQXVCHRxqXY2Ttf3mr9DxiIa+NS9oZ3yrdjdbW+6T0PNPWeIDofDDZot6i+b4QeCtnDFlJJV9/nDR9PDLJGEifnfDmy8ey7U9+Aq+vxbxkamrtrv0N/EFp2idQtauuWvZdA763nrji29qXrapCGnuLttds2ddbXmcUrho522fbN9NipIQ03AWgIgqVvC5AF7jXysAxeyYsyMVYHmnPaNPHIJlvm46cDNMF5RF20c1gN1TGEmFNfsCwgXYytDNrEJMvjV05Oxw5JbtPqUTts8pH8w07Xjkctx9A8TmS7HLoPf73SiZsr0uxAtgveSsL7P6i8z1SexB2+gWGrfbsvsPzEOrE4kJxu1qtAwUnyzbdc78ccE6zKYJvX1mI45CIB+LcX6pK0iaUEb8898jv/6nlgnDlq3mSMxr42XFjzhnVIGU4QB7w5r6twqu1cNCNZl8TRNrnun8DUt821p+s0bLeNPUfK8r3VBjf03Wv2eNF/rka3w34uNsITWBPxCGz74VCcveuakaiLTJAE/3tfB+Bh6XF+geAESKYfcTUNiDblZpzmSV11QK91qBp2TTSYWYHWstzu064GqWfOzn9/hdVVBsG2vVGJdsOENRUlh0LnOORm30ITLkGVeaP3gfi375Md0Vy54C8Pv7eAmoe8lYfc2yFrnYDjibuqLcLOrj+79Xr+OnFEwNf6Fg2HS6l25sZpbT/rL3yYXimVAUMff3zaxc4mo38a7HtXOsR/qj8bPOirw5p6Idt7DWYVMvaJGPqUbC4a6BYMpzWx3+MunXmmdEAuv6hnT6CWv/sg0dqB10FcCFQIzbsNcKxO1jaizTvUeuXrzfzfhIqsFGinwTUpYlvm1aSIDqtp/7Aw4zQrdxKtYKamY3K2sZvNgcu8pFvW+GqMUxeP8Cr9muo3UiF49sYdk1PvgnNMOanakqyvPMf1sIAmntGiADBJdwosyxY4rGH1fQTtkR1fFYJmKkHfjvby83Kvgus8TAPA8Eny6yx2pc8/QzqjpS2tQEYBaXRiXUv1f37w/HBr72POcuW6ydU7JsKoWt8GfPlyegvM+s2/4/0S/bho1/rtpiKWOOdA0FYxOaAxoSEsUkIUGLTaNsvgnzhH4xIzdiLeenMt5o7JGczZkt9Gh3hP6ITDPLq/8NF2f+f/beNdSadUsPesZ436qac631fXvvPvt094mdiHYrxA4k4oX+J4iXKEhiwMsfI8RLCDH6w1+JEhtjhICXHyJCgpAoqDSCIiGNIhpMICa0F7xGOnZ3ujt90n32Pvvb31przqp6L8MfY4y33pprft8+61z23n38XlistWrWrFlVs+qp8T7jGc+g9XE7D+OtJegeNBKOygvn9ArDQXudfVbnB49MmSKqgat3kVAVhTaMJQN1Zi0JXvOnrYswiRn/hw1kHYgDH9558X4JxzNb/wDxc1AzAMaHUQQNLyBQnsxlOa2HFauJNR0qaCmgnK2gQPYdfrHdvKUwqnSeCJ5YMz5V1wUgW6Tbig+EkC6AGnCKYZN/FSGwwWQGEBmgElABxDwgrApIqQY89haUtr1UGUsJSm/YPvRATyXgEApWK/jYFVwY4F6a8PQKg01nux1DMXrCuVXA9LUGyNfUF5usrDQQr5VsW9QA3Zd7YrFa9M5crWXZ0+jYv7MQt24cw7QiTKkVwkjdypthUXA8zuoH/PIRjAQ+FMgM4FRB4wLEpdFT8tq+61k7/ZKBII2j2j6WBYIboGbw6Zt27m2dvOr3Zc5l8Eq14QWkZqTy+C1N8Xf0QJ4xHX4YRAHL8qvg8L42rhQ16aHhhfp3jF9RQKW5Jbtr3XPQXu3mAFydZ5byjgf+EoznAW+tWM6/jJvbH/0e7c7bh3BUaNwVUARgEvAL7Qg7ffUV6hoRDyvO33wJnIBVRtv9LYkFbLykj1I1QZY9+ux+HIRz7QBK+mh4nxwj2hJxuWzAdTDFgwiwlLjxwpVb4qlYBJ3qnmcOJAhmj3jOEQxBthLjXAKGqn3V+ik8gFY0ckkdEMnOn6JenA89Z9cVCf263gLIAbpfv9YtgdbTGr5tb6O+U0zYeQihIMas/eyitkBia09Uc9xXJLrNZIrgIaMsA8b3H1BsRk6hahv3SqAxtyIREQKScudSBVRmYJrV6PzOFCjujVsLqBaU26+C59egsqAeXoLm19bBOUDyGRJV8VCfUVXW87nL+jHi8D5yegXiiLo+AC5Tk4zHV/8ryNzIQtSIOK8f6cPDjdKLArL3XAM0qu4bXwrk6r68G9/78UyqoUDmb2CdPvye14fHeAeRrDrevhOFefJKHEDHG3Uqu6mglxXhKxny8QzcVwxRS3XjmDCuA9bTAfF8wKevX4JJGo96ye2qgsCBbwNgB8Da6Wu3CPVCkQAA4pGvRlVJgFBUlTDnCBHV/WYh1Q8LgavzuXvA1b9VbVEKYWDBycB0DAVrjljXEeOQEKNHNvtI9zJifQqee/8GH5dRaJWnEbRHsiHsQb5/ADjX3pdOq2KhNr+LTd3Amz7YaAUOFWHIkKqNQfvS451cDtaCngTrqztw1OIKYgFOB22h5A8QmDG6n4YKyAq1Fc0JvJ5RXujD3qvO8tf+Lq2mfP2zCJ/+NYT7v67HywEy3ui1mu5R+PDGJpOlLo2DrR0HSxSQymMrlHAVBMU7yPwNTTLHO0i04goyikE02pUyA64BhnK/tWjpc60zxvFDiGgXiyoZuxYg78bnOp6XXKsVfP4Yqf7vSFZh41ncXh7jmdvvpI488AQMNtXCvdpD5qX1o5LDjWomfb6cE2g+g2JEOD5C7hNGADwl8MMRtTBijjgeZtDiiQ+2Lgkm1zK6waPbPuLNnf1jMZCtIJQGxLobl5eygzALkJz/rVvCzEE3XXRx6LflnwVzwCwFOJLvGz95Xw+6PU3wpuTVXjqnJjuXJj763Qp6N7Neb3uNjvAZBZOoAoP1ty9TSkL71Dn4+mCumA4LwpCaHWaeFXBrMnBnKKVS1LuBQ93ZRsJ8gdVMyB5IJUCybJ68F4MYKlX0tjvro1IOHEB5xfjz/30zwyHv8wdApheah8iz6nI9GXaFbnDznUpmO1kzap03wKSItHwEyQ8AW9HE+L6WDBu1IAzI+oma9GCTpUnNEOybXDodkc1zImB6Ikd7Nz7f8WwdLy2vwXlBvTGD6OkDCHVP3HJG/Ogvg06vcf6b/h7cvvzxb3vnAk8Ypg+RJCvPmxfl0/is9nocAHN3opx07romYBHl8FLcdL1mVB5jwSRrxz0yzpmRi0a4uTJWi3Qd+LJFryJQLUMHugDeCLr9KJVQCFgq42QcbbGEmdMLDNcDb9vVBwG03NQ3Rlv0yZBWWbdFjJvKAG1b1ws0fDuX6/WCgGsysL4a7ZKOuJSOtfOYt2i4iGt6GSJPQT5Y8syPqxZWA54uYiYRLRVmVY/sikRyAGK5WpaiHsRBFRCxABAIW0n1RCpVhCbYOJ30+rIf4dBAl3KySNf8MzhoxMsDKDxVFHiSK/ABa/4IxBEx3CLVTxV8i3K2CsauW8+o6yvdn3S/bYwHgAe95yzQ0ZU6/+fSJafdU8NkaQDeEQ1f4Hg2xxtffwSJA0pZIMOtToPNqg6SwZ/+IsKrXwUATP/vf4fH33SP26/8xLe9g0O4RR3eR5asFT8Aalm26KgW0Ko+qO0HgKwRZRmbUY7fmMxFOwZQte4JFZErYqiYi2p9awceDkAFBoJmA+yUQ9uNzzp1UErinBnBhPCtNNeAPcm2bR8CtEo61w37uGYg41N6VS88pRkuARLYaIaNGrD3cdd+qPtdjH/NnSlOvz2RTTXinheqdwZ6bUY1ACfawH7bz627Ri0MWSOySdUAdK2AtK28a5e96k6EALOT9E4aHFbjdglSrcKsMgjq10sRaqQzHSAxakVbHFuj1adfamlm53JUs3J0hUUclErI5RFjfA9MsSXd4vB+S74R6yyxdjaUHtUCAMc71PxgSbyk4Oqgak01pSt13l0PULCVnBGmDyE1I9cHpTPketT/bnzvx7N5AFpnIK+I7iMa/yrqeNBqnzAhPH6M1oV1XTD+8v+M+gN/53fMBRMf1Hm/ZuuDZT6npuslb8PdNxOkqnyfWB+0vJcu9VFWLl3xA7akGdBxrK2qbIsW5ErYsOMcu6l9gRinyxis8AFwSmPjdoEd7dgGd2EvAxi5amsdqk3ZoAnEp0ky3wcfvTmPvsZb5N60sZ0hjRWK7Nd/uj0AV30sXAPtgNwDsMvMAGwgXdUfIozJ9unCWc1ODAVpiTKgq17rlRJCW/NN0XJnitriXqUmVnBxZCAG7XsG43Xzld5pPjpP3XoE4ie/iHL7FTVHD4cmRwx8eFLS66Dbos+adyY4Pog3o/O6vgIfvqodMMJRQdjBliN2jmY1aUTM2PlG6GHMGwf2bnwh49tCQ8oJ/PAx8KgRaJgOerHGiHr3nl6QcbBo9Gwi8u9OEk7CARQXtd5juyniCDkcrUNF0AqhsTPANjorxqw1/1GNarJ5KCx5QBYF3dVkXz2vC2i06zpdYB9tXot2L3lXwNUPABODCxAsGvTijB7oC/bafwAN/AIJBq4YuIIITQbXihNMAuYJtMvE2H4/N08FvihE0eVKW/SStf49DcBBTyiLdq6unCcmtNY9RGX3PjLTneYwZprs3reXuqo1Ymq0Q+WgrZ2EQJUBLs3BrBmwW8diCWqmszvR46j90A63LdrdWrLrw3437DqPH/+iBhw5odSCmh5QDx8CByCMm5PYpZTLtbuAgq/zuh7ditwjLd+wlfO+11o8dhvKQDGAtdlnO+HxqIGL0xj+ee8i3i9sPA8NSwH/2te1k+psoHdzANIKihGCqBcmB9SbF6jjEfmDvxG334Ke8W0mHzotyvqUTw9NViYcUK31NuIAGSdVOpxm0Ko3VTzqRZaD3oDxsDST71oZp3VCqYRI6qnQKx6caijSqxl0n95kavPGpJUfp5B6tkCj3jFUqJk6rOgCu/dwF+Fa3RUYWsBRhDRSzxGPywHjkDGYqqEH30ve9U3Jtz6g8+NX/pV2oNzMhirvottLYG/JSKcbsEW+RajRBQ6o0fwsLqsNvT0ToLRDM2/vTpTOHnhXxcihKpcbtfvwBtalFdigMLAGoEI7k9xppwjvECEctEuEfnjrJCHjUXne+REyHsG1tviRl3vrHPEKNR5R4l27tn3m54Y3nvgijub1u4Fu84doy7JGuxT19dq1CHH3M47QJnoX4EubnaWU2SiLd6qGL2o8D3hTgfzKK838RgCBrIOvk1GhNezLH/wmyM3XMNz8yLewWfX4rTalGsItqmSk9KkmA5aP9GlOUZ3KgM2f10Zr/R4j8PIOhAcEzKBQEU4r+NPbpv/01jhk0/0xFhTJOFhXiFQZi+wpBr+pnPO9RjEAG0/q6/WXtlMViwOdNhLDXBhrJZTa8mZtNHaBFHQvPzdVRigBgSLWFDEO+qmqg61Iad+NwjncPjl2LXmm+0vwnmoighDqVdD1dS/BVyyB1o9+plDEdMe2r04DhVAxjEl9i5cR8/nQijHcAxhA62KxydUE0RKoHHNTOiAHCGsnZaoMMm/iMjPCpAU3cJXDMDaqAQB4tko1A13UArl5AdSqSgePim0oLzwoUJKre54aShEFlUruTnzeItc8b8sK1Fg9HMxa8qBdhR9+CTK9b++ZdR10n+Xgi6H7iAe8G1/8eD7Hy9imZkw6tQ8RMk6oN3fI7/0w6s0HkMOHgD/FP2OIZJTTL6HYRbU6f5UewOdvIuRFZTQmXpebH0INB1B6AJ8AXs+g0z349SulP+YVWCpQoWqGZUCeJ6R5RM3agNEN0seQUaIWMAxc4QWhvWRsRzG89Tj2AJZli1gvE2ZzJQxCyFWwVJWTAQB3yEqWaPNtiJBm4ts2N9cyAK1X2+YQ1pmitwh2i3J7wLqMhvsIuT1Euvc5+Pq6l+9pCgvZHMkq9v3U+n1gK6PW8m6tVvNedZveWGN+ZkEIGSWHZnDv5cmlROSgRReoBB4KQsytwML5/pq1yEaGrOd0qqpogFJplBMkr0ofWMRL6wJhRh27LiCvfg20Gpc1ThYUjPB2PdxFu5cjxDvtdNHJvlDO2kberwGrigMHUHrU4CY9gu5/xSRvD6rdtY4Xm3mPbcA1wR7lAhtFcSUZ9258PuPZXg1SDXwBqxo7QG5uUd7/KsrdByjv/UbAnZqsvvxyXNIK6Zv/C+Knv6wfYQ3/hAN4uQfPj8azacQRHj7B+rUAmd7fNQGknBoFIp8I6nk00B1RlgFpHpHmqTW3TCniPB+QLcrtXcZc2pVMytUOv/v7cpJ2qb3tE3EXp1AjaNHtm3tBA9iKrdx4d84sAo+8Lx9u+/MEYDcuuudnL/W2l+B7nQdWwN8fx0Yj9FSGb8+LIBw0PdK9bPRZhBG7z2TzY1jOR5znCa3TBQlCOwalUapV/BXrk8dckItgiNQ+d8K86X6FQaFoGbL1wtufRACfvALXCoxqESl3L1UjbuoFygnDX/8FWEtm5WeM50VOIGbw/Kg+D1Vnayfz7Z3Gr2zHSREctPMFAFUtZAVdNd8xo3YPXGyZALvXeX2ERAVnPxq5pBkG0we7xC3d6z36jmr4wsbzH3n+XR0HbaXy8j3UmzttozJot9YwfbjZ1114O6z5U+T1VWvWt97/LIaPf069UbvSTOTVIo+sCgmgTQHjJ7+I9JVoT3l1ktpJyQqhPByRT4eWzSZWYPXmli7kTyVYk0v9fyDByFX9HAQAbXpdoqdT/Use9zKy7cclpFUBSsvy4yr4Ov/rn+8A5u5nA7Yocl5HRC6YxrX5IOyn/n2C7CkXfVlCrcewvealvC63K3XzvNCI1kNz3f+2rHKz1GRLJrqc7tLFjKii5IBlHbCsY+NuibQsIISCUoJ18tDoPRn/G8Nmh9mopLCXoKEEVBIU71X3AE3eFQafE+i2gNIrIBDoThO2Mk5Ns7uTldUKsHY1BrSYR8YJtJ5B6YT46hdQh19DffEbkIcXiBfRbzXTmxacWDUa5debQqGpFgyI86IzSY7qEwE0gPbrbQNgAHwATl8HDl+F1E7dkO5B9Uob6XfjcxnPpxpGAB/cALd3KD/wVZSXH6Lefoh6p25MqAklvdJot2QUemjTKakZsnwDNH1V9YTpI/DrX9x0knkFe2Qxn0GnR41iAWAYNaEWB9A6I37yV1FvP+wuTDPNSRWSB5R5wvL6tpnlOLdbDGjZkjh+4xM6UCABk1LY1FhWaXrarcCBrnK4bxLpXFtOF8t34Cv7ThcsglQJAxFWssjRkmnq+6DlyD9w+4jDuO50uAB2vG4PyH2035kq7qJod3QjyGZfmaMZtW9RbR/JNroB1HJerTCjO+/A5ufAXLEsE5ZlQhXrmlwZkYt+fo4owgh5O/NFuFXHtf2NuUW9cVA1i2R7sCwjhjGhpIgwZJR1QFwG8JAR0xk0JXW8SycgF9B77wHMSim4RwizVrhF8w/xZXEAckI4vW72pXz+2B7KGQEdf0wRw/AeUvrUTk5uVIGXKHvDzD6noX3iLiJiYNfbrXUyTg9bEQWwJezKjKehwLvxeY1nu5NhUiNpORwhh1vU6QXq7Q8hHL+myYKz9q3yoorLyQxNX91FwZSXTq5TQTnrlG1dFHTXtCFajKD5rNGS8W+Aa4szkDNkBVAYNWn7nzTrBZtzxDJPWC1Dztxl27liCBVDKch1AkE1stH6kKVKeG3T1Wuge0knXP5/OZw7viyW6N/P9HQZaOOds6j64tHMcgILwAUkjDVHRC6IEQgho9ZOj4unXOw1SVgfifbRbU9dVKiqYvsysfuMnhJx8BUh5Vzh0jHZJdb6YoxkQJpLwCIDYihtX2MozVhId7gC2I6jVEYxq0z9zD21IEKIhSFlKx6pKUKEFYBfPqqj2bEA66oacZ9VmbUkQrfMR7Zkcy1A1Sq3aqqFtHyE4WbT73r0G+Md8umX1KCnFqBmUDo1BzTK6w6QK7+h+SugXLBFv6r8iWZXaYUXHBsYyzvg/cLG84EXAJJmcdUz4SUwvEA5f10zq8nSUxzUIDo9aO26lVEOZqKubvu5yXbQayT7iznbspOCMMUAmg7AOIJPD6iHo7Zxmc9ALpCzdaMw0F3mqTW5XJNOX+c0Iltjy+w8oRAe04iRq1Zm2aGqqXkAEZD7rhb4FiLct1AUT9a9+N+BtgfhzQ1N94UBhBJwD+A25k1m1irR3ECmPi1AaJ+zN4F3LbB0ybHeQnPjc9FeB7R1UqA9gL7xWLtEW7Bk2mFaEIeMnNTmsoo2JS3CDdzXElpicckRRNgVkDiv7JI0TbpdL5jxfc/JKr+q+j140o1CQbidQbkA57M2y3T1TqrWemrdZlohqgbYgdmDgloURDmgnr+OORxwmH4I8+v/G4hHcNRWQVhftQg2nF/t3NBkuAEv9/DSZZ4fkF/84P6kmuSM8gIZbxoNp9KzrPsXjsrvWmKanoRF78bnNb4Njle6CLWAT58Aj9/QJ/FwA6oF4f4bWlb84odU0wsA8QDhuDN81j2YUG9egk+vNXKtZZvOATalK4o4KQFIwGkBYgCdTwiTyWfOJ+AxQZYJZZ7Up1W0SKJY+/acY8v8zzlirRFzjruuEW5ek4RMc7t57QJPk2fXaAIA6PW+rlSou2n80/f3Q7p1fBTje5N1BUYFigQUIa2EI8FE2cCsPqEZnuh5LyrMLlsR9es76Hpb+56eCCymzVXOdeCCQBWpboY4WiiyB+NAFTFm3N6cMB0WfWCkuKNCinUHuSzQ8O2KQJtKyAaubrizlgisGvUr31t2UXU7105p5IAAoKaA/HAET0lPcnWgxQa07bosAAoQ7Z7ovlNyj144AD+gPPw8Hl//rHY3dpogTuC8aLJsea0m7BxQhhv1/5W8U1JQXsHptAUtFI1esN+mgkDrmHGRbPPjpr3U8N34/MazVQ2IwUpzA/h0D379Tc34uuB8nKxh4O321C8zBAAfv4bAE9LyCmX5CIe7H8Ocz5A4oU4vMeSfM6ohb+Bba4d2NuPKAsSs3QDGWfdpTZCTlYamCDIwENF2Mw6++zLZzYEsy2bFKPa72TNCo9Zg7dp7Xe/l6MHSgab9/gywvXx/H+n64rls3g4rgGOsGMS6Y5SAgQOWPGDM2vssxoxrJcSXhQ892EndJ6muRa9FuPGzPQi3fecK1NAaerZkmp3DMRTEUHA8LK2HmgP0/rPRnOM84ZgqY3RTdd8/o4z8fegi32rRMIBmm+lj5/1QGSJVjz9W9e11PihbQOAXY+1+++s2O+OH15CcrZpzAK+MykFpNf9ccz3rfSC8Sk7ioNWYdndeVsw5oHsRkUot7Tq1dSUqZUZrRh0B4AAMBt4mV7vqP/FufC7j2xPyMYNOD6BX31SzDkCnMgDw/g+gvPwK6vEDTbiVGZS0DHKafggANNqdv4Hw8sdxePmbMfNfAfB1lJcfmkRmUTpjXnVa1wGv/hDkTJAFoCmr5R9b5HKeWlVS9vY5JSDl2Lg/1eZuSaE+m18NhN2djKFKh+UK+FzSAG8a15QOn8UD9+v4vS/YIl5PAFbR59Ds1V8cEZK+8b3jI6i19dmOcddQswNZ4CnQOpfrD6L+/T0PLaKRb0tAdnzwpZkPW1JTuV01YF/mLXnkSc8i3Ogg/V6U0/UHasXW/RnQaDuyAnrg2v5ux2GzHo98+yFVW0gBAA9ZfXtf2BXgdNcYLTso27IYoFGxLbt/AM5nUHytxTy1Qj74Cnh8hfLyrGXItaCOxw103WzHIukGrHndF2f0qp84tsjWlyOOqLdfBT9+A6hO4WWdHB0PKieraeOS340vbDxfx3ufQfkeGM/AnCGLABmgGwC3E3CzqI4xjqjeITgvEI6Yz39NvUWXbyC895vVaT/eIUwfotSEmheE1x/phbWudjF3ckMDXhFS8M0MmU2jGAvAm89qLVqz34oJrNCg150C2Gl4RbZuvoDN5klz+QML1nI51X0KjrrNN56+JyqGzzjdTWZ2bRBpDwHnnkfWfV9LwNiZBfVtffpx2YljJwtr58BUCnVTNvi69WI7uk/a0qhUbwyqPeZcL00dBcJcdv4LOUfl3tPQEmv+vTWf5GpWmFAT+AKdGQmhuZw5OAf3fOh478HVE6FsihazoORQEMaE4b0HxA8fVb3zcN70fLP5OvRP21zMH4SshRABc9mKiwDQx98ATQfNQzCrn4nTAYD+5tL4YcpJtcSXw0AZwAbIPqsEQLMpGCha2yID61o04V3mlvjm+TXeuZN9ceOZXg2Eej9of7PBXKMeNTnBNYOwgF4s4Fcf2RP1LzezLkJHAAAgAElEQVQeimtBpV9C4QiUGeX0SwBF5HhU8t/s7drFCABJFHS7+lspDGRSv1UxaiEHYB6VkyPrLuzOXUF/JCnlkGtA6jLxgSoqGCz7zguXpt/AllDrcXCziHzzaduBcrf88i3X0lFyZbk6mQGra4AZMHZvU12AkG2qDzyVkF0uu9Tius9vpS0h12t6/T2eIFtzwEgFRLSbQYhoRd3l5wBAMptHp0RSjsg5Ys2DPSRp9xDLlTWRBtLoWghkJvYDF5AIAnf769y1qTra9RCtSi5oYi/EgnhYwKFi+vAV4g8+gt4bFFS9cgXQSDdBK3B7XDw7/4st+1mh13UMOnNbE+h8AmJUUDVXPdvBbdrv1XK9K1o/eM/LEsyW0u+z86uN9osWCXv0Wzodb3zXd+2LHM8CXqmM8voGYAFPK3hKkGUwXjUgYAE9PoBiBK2zJszsApI4op4/Ue0tAMyvmyTGK3FoPSk/fPcSfD4B7CYhaBSD74fLgCRbl9kUkR8PanRC2jImxAzmgnFYVdWQY4vaXGdKpPeTP/tdy3sJuuUKsF6TfV0bO973LQB9DWT75dT9n0QduTwAi90bnUfN1kkickGfJNsDYx/Bdn/b9nSGoJHnvoxYI0+CNN+GOUeV5XGBSLByYWnRcuiNzY3mSKYqSDkipQFzGrVzsul1nWLw6LQ1JBWLtAVmbBQwWpeJvoQ5Z9VshyAYhow4aLPMOK0YjwvGFydQKIh3Z4T3T9p5eIwKuilpKyBGq9hUH98u09obclRAVlGtO2AXTWmRLwAgZ9Wn372EjAczVDeQbZRDp/ThywRYgnSqiUY3+PvNs2S7GFTZwOsjsD6aeU/cVX2+G5//eB7wFsb66R3ClLSp4Lmo4UzeQDCOj6D4AOKAkDN6iViIA8pLlZv1yTcAkDC1FisAILcvtGrt45Mm1BrFAAVgA1/JQfehBNQUUM+hNUakUBEH1bHGmDENSeVJdfOe9YQOdxHuZnyu0/gtClSA88j3WwHdy9HztZ9FO7ztdS87dp7TNbOqO2aEyjinEaUyjuPaCh+YBOiaagJoHSw8AuaOlmic7RuSbEOopgxhjJyV5vAZtKkOHEADtqnt1gg0aPJLCHMaQSRYS8RcBoigcbyXLYsKANRg29HMUiFLjolrgANGUzQASm0cjjOG44zD+w8Yv/IpECp4yqD3ABxcG1ub1wcymiG5z77kEnCh/1O0h6NaSmgFzk4LaBdNrVsJ8jrD2wzx/LgllC25TDkr0LbPcbqhB+iq/wNAnQHvzlIriBlSC6QsqNNL0Hp6F+1+CcazgLdWxvJwgyGtGF48ar18ik2YXuYJ4XwGzQsoPAIn0/SKXUzDiJCTeud2iQJtXqmJBL8QNYEQ1bjEBayAgq5TDJUb8Pv/kgNy8mZ/KiHSrhOabJli0kirhoZqDMHIBVkI4Iq1hKtmOIFtP4SADkB9vInbfVOhxLfK9V4bAlj7d/3fW88vlREsAnxYCbeDcp7ROM0+Gmz7h73Ua6MF0JJcl5EuQwwkA5YccZ9GfHg8afTZUTn+mY1P7egcl/b5tl23K4Km3S1tX+yBwrVZYm77v7mglUqIrJH6EErzlJjGhGFawTFjvDshvngEDVlLhD+YNrXOvGjuwiJdMIBs0yLAZl0X1yMAjGL8L/aR8GHYHPyY9DOiXZ8tKClbks3L3oH2t1tROli7P4Rw3bTFQCs+AqBR7+HWqAbbdnrUAKcGK3B6Jyf7osbzqYZ1QC2qewzTVuvNoaAuA8r9EXz7CKyfmtK/+6Qptg6utVaQlVeyTa+EeWteef9aiyZ8iudhqO+LR9reWaBS26+8DlYivLWDiaHg9nhGXLeN9Fl6L5JYSkAgsSiLsYJxKoRg9xd14PukKo/24OuAdgm6fAW023Hhsws5PRJW8IU1ygRiB5BFCCMXBB6AFbgZV4wxvxF8/X+xKbxP33ceDDAJXvOXsGaf2IA12oNL133qTNYD79rpqv1z16odmJeq+mSvTpvtYRigXK/uwLataklFABhF+dwqhIEq7m5PCEH1zWHICEed2tNQQUdLgjHrhXa/aPWjfoHbTKuYt3HZEo/+v6shAOj17nfV3aSac98WoFWfN7eod++b0XpSUFxni3ZL+471wLYW8y1SrlUBNnZFHR79Gs1AbZ2N/1WgX1oZ8nf26H83vpPx7XWgcDlP0j5mFNVkHDZdL58oyUWHrNFCFL3Ih6pqhWHUKdN80tLgedb/vf5dKvDpCfJAkOQXloDC1jrGh4NusUaI7rVbC2NdR5Qc0JvDxJhxixlTTK1qq1StkjrGiHMetPNvZQQzX0m76AootGl536RkeJNROrr3PDmv2ACV3rLMRxHV9UZiFBaoFXcFcoSYjGqsBYXZwFQTYalEFCgQ5hKa30J/DKlu0afu89Pj0ahXE5QvxwVFGGvBLjp21QLZZwTSz1yyAsSSo81APMLVv4sQZnsIolXiaZm0Y1g2851ofdY8Ol/tmI7Dimlc1d3MTNdrCSjnETxkvbbuCwhnyL2A3mPUR4acB9Q1ageTY9JrGPbwr8Y1sV2LbWcAWUkj3xmgKECaYQJmBcvpAHn5Psr7H6LcqlOZ+/2S03KXaoa86Y5pXXavk9MSFkEL6wOEAMjopjrQu9x4ZM4JlH/Vcir7lkDvxuc3visMu5jvKQ8ZkgPSp+rFEOZVmwgOWc1GDlZJc6z2xS9acZbzJkA3QbqcgPL6iGrJO2IBTwlkUTaFstEcfqN7xLuMSGkwJ7LYiii8dNint9FMZDyqcq6XMeCcD206O3RT2zcJcC4NzN3g5m3JtEsOVy6WXwNfH04ZVgIeMmEKDv6MSBWpMiJrA8+BTSubB9xOM5gqmDo6wORZHrH3VWrOz7Z1nS+FtE7Bm6/DttNOSaTuobdSaBGwR6ezfT/JJGMu58uiXg9a9luhjmdGPVxocJWC0IfOYJ0rgj1kNEhQB7GcIwZvHBoKaDKN76dAXQZQKqiPB6TXN+pmtxTwGq2Czb+ki89nlfTxbVJAXpWWkAzlfRmmghDVvFtLeD6/Aq+zuvKtS6MI9OTVTenQl8/7366vLBnNo9UAF14t55rgnNR8qlbQrMlrPj3odsq+mOTd+PzGs4H3SSUTq4KAx6RTOKscA2A3cwUtA8CCyA/g90ubHgkHe9JXBd21qC7YZGN1GVAWjWQBgEtAKFtkzaEAA0E4IM8TSor6PuOAAbTKpcuiAAFhyQNW6z4MAKloCfF9GjGX0JpfAibUh0Zumsy64Em7U9K0vZDmtwC8GWh376G3TwAvG25qFZvKyxIRggiyAEE2EFuLupY5JeDFBQLCGDPWHFuFWe2iVf2cbTvkJbp6cE094cD7ajngg8MMEQvyjMLR41L6xiNcjbLJ6Ay0Ig1vu0T2sGMolz34+afNVlL3074T6ENzDBmHIRmtoh4VOYdWNgzA5IYbJyuPjHqaUNeIuo6omRvAcooIJWjbIPL31badVsj2etqi49j1i4v9zmrAwafX+n6jGbbXeKMSfBmwzQK79XYlzL2vLjEIM+iQIBYhEyxaTuv+fstvCiPeje/1eBbwEgnitLayTnLNbCgIUwIPuV2UNUWgEmoZAfIL9QY0PKjk7GDlizECp7M9gQ10F02Sgc0xyumDFFHOI4a7s75mNEPvOuVmMJf7TSQoXQGEu18pMEWslthZS9g4RBvBpqkMjeoGlla00Ot4P4tu+FYYtZ3fw5XX/Le/JtDivkCEKNKAUo10GDMUG1JlHGtWvW0suBmXZmoTuCLnsHHexvXupWZoSUXAyqfNcawYUB5Cbkkxbx7qPLeem9Ci6iqEuahPhoPtbpJt53uzltyGSui2syP2OcHlgT5zIdl32+CK4aCtfmjIoANcELGd48yoObZZFmTzc+Zx1VJi10aTgMctapQ1gKIV7STWrhaucBij8rtWbo9aVE52ugewlQHvwNaj217p4Os4ePbLPIFXBXh8BPUyNmZN8s0ZKBaRf0kpXiK6BXAS+SxrqV+/45nuZNKqwThUlWxxBbtBSCxAMGvHEhpNAHC7eOl1RnxvBd1/ul1cdjH43SVrbDpdHrLSBZUgNWgLl3tCuFnMfSu29UYSJBZInYAxIa+D8bubY1Yv/gfU8WrrnrBFsd6cES6tskhrYE1oEW3XePAolTTy7DtKAHtVw5vMdXDl/2tR9JvUEWtVqZuwKRwqUCUgMWOtjKNxviVYYQVVTF4EI50pjfATj4m+mKQYBVAqKb1CaNVtA9cWybpEzQswCgilaELTtb1uTJTqvudGdBN3oBW2XKq3+tEn7HpPYNXvbtdrjEqH0dC1xwmqhuHDqnkKoHUjBoCStOCBuELqpBRFrBjee0BdlAv2akkigqwR8NzGANMgBuAwQe5eQA5qC1kPt2r0z9xohi1xZvvXgy5g94t0/6uFZHfwttyigLAZ48gioIkgj8ZPxTdkd7/gQUTvv/fezSf/6U/9AeCz88y/bsczS4YtyhsyOOjF6ByuVEJ5PICGrO5gy9C6+W5dIBSs5XEGxfMOcMU0kz4tkxwAizq0NNYqqyyJRgb8INUqhjEBY0I4LJjuTlgfj8rxLiOyKRwCV5zOR9PhKgABeJKw8xs9dDc8k6h8C2j848juGLY3znGKwceb2v9cG2/zf3ibyU4V7eMWLMhaQYgsmMw8naBJwqkGHGNGtKqxYPwv7BgF2tiydOeEIVibZlYpJAEhQIFWS4w36Rj8nGEvBwPUTW1EwVo1gTmX8CSaLV3HCgdfnxQTCZJQa9/Ya5j1PFh0C5cS1u6nwLtcqAEOIGcFojqPTY/Og9IS3tEYQEseS41gqSinAySrmY4PYlEarJefBQIOoyaUvbAhryDX7dpQaWXduNedSVTdADeX7imMJuZWu95uuf/4uc+sx+oJwfQZnNYXNP7wT/6uTx4fF/yb/8Z/iX/4H/xj9P0a9T6/AwUJwpgs2pVW516WYWutYqBbvfuDazKNL5Mzg45ZS4LnPfdKqBpBzGOjEigU5fpSVElbZdA8IgLmKmXTQqoqTRwyBiEE1/OSYJUR47hiTSNyDg0IVJtbUUmTdGxge2mi4jd3BRBJvRua1Ij27lxvUzS8aVyLii8LNN6kB3buOFdgKc5Jb4HRwMC5BIw2fY+VsZhl4s24L03dIv4tgdaiVz9GIfPrVYcyj1c9OQZ4lNspYDoqIQjvjIjWwq2qDf6wu6AaducB+hBhKCijW+/yNg0W9caoBTXEVemCIJAVqI8DyumgNqKLyhAlhw2TOgN5zzVUIeA8AsKgUsADgWLR6JcFUhg0FFXxVGzguS5NXUDrufG7Mk7mNMYg77hybTin1ZdR1v2PJJVYAha8tJ13jqibnX7JBhG9/1t/62/CX/hL/zp+3+/9D/GH/tXfqRT+9+F4thF6mBLizdy0kOWsAAnLHKNS410dcKvrOmeNTLXs+ARkdRMD1xYtCAskBa1Ia1QFGsDX1awdzwdICRp9m9UfBYCiRsLxdsb6StUVyZNnacA4rAiBd9PrIZjsSrglfNYSMJfYnLEqAJc1Rd68ZslQj0m51n5cRqjXItjL6PYSgN8Etv3wl4so5QAQIgnGQFiNw1QahVuCyvf90LeOMWnYUvWyCFyx1C0iveRgnYIQUDPtcqB1eVjf7t4BuFjCz2V6TJ2mmkgTtvYxXizRgNUKRFpULNqyXbej68RQMMSMcUg4HGeMVjgRhqxdh4+qrZUzozyociY9HlugIMYLc9Drua+m0Ug46LVsFZxSCbDWQYAl74wu4JhAWIA1g6SCY0S9e0/VDJ2ErLUV6uRjT6Jdt0h1JqIXJbjkzWm6ypvix74nGjIIvKkyvmSx5B/+yd/1yde+9j7GMeIP/iu/A//s7/kT37dR7/OSa1wxvnxAfP8RFAvyN1+gzBPW+xsACsp84XfqSgMAAAvy+aBRQZc8uzbyg94IxUqCAWhJcN06JGiBRLDoq4CCThP9xgrHFTVHDECbMtKtYD4fgMOMGErzM/BRhfAwHyEyIVUBrCMFW5TXzL9JMDGAFu0Bj5mxVs2wF0W4t3K7Dqpvi2z79/WqiEvfXg+EpLoygoAiOEYDNYZWGgJg+9oHK3bwaNOlZGRAKEK7B48DqMpZBXDrR9uPxab5YyhtfbLfxUB3rayzoov93yrRFGjFzmkpAUPXZJNNyyswvtmjeKqN3XEeP4TafBlCzAhTQriZVZI4CuRek7VlntoD3n/rbIsRgCcmXrWwtog3gHNlj5SwtRIKFYMolcBrBsYMwgk0jKCD3i8SI1B50+euKzAdNrrhkmKwJ3szjsqmMMrKU7uiSAo3vhrAlgy0e45iUS5a3mDE8wWMPtoFgB/7sR/Gj/7oD37fRr3PrFzbuNp6HpHub7Dc324X4sk8YQ8WUVTV1DodAGzR53p/04C6f92neut50gtIGOsytrYuWyeBioJoEdWAMAKwaJfvFusamxHGpFPHqr2+iAXDmJDWAesyIVmnilIiaiVQN3WNpDCjpjFiySMAlTHEgtWirzEUPKQBxSqYilCrLN2dP/t9zez86vm++L9cAel+e57kmwtwCKp0SFVVGLUq75grYQaDSQEtpBHHmDCE2pnkoIv+bdbi+2TnwnnXBsRAA2n3BmbafICTmHxMXI9rzURJyfF+O6jUBBSCTRrX7Dt356RPhpqHb44404TDtGD0aNhmRtr0MoCyUlpsOQl0QOVyNmCjyfTv0JZxqEjnO00yWzQtj8f23jhqwowXLdYINzNCXIGbWfW0hxu0bit9A81a1YuaWb9Yl3zljstdaedbIpWBYmXzBrpa3GSFIzD6gTVAQQ5fOqqhj3Z9fD9Hvc9Orp0/fk+fmlR12jZklPXQChVaOfGQrWqMUPL+CQxYFJQjDi8f9AkuhJIiyjognQ8NbAEgp0FNrrtoOsQCiE77SCooRYQptQtKVi0pzvOItIwoSWmL1o+MK6Jl9VOKqKS6H+855tnxiIpC1oPNliWb/t6Fgkhiml/aFA5XolGN6t6eVLschKeuaNcoicv3CICl6L4UAVAJ0aiQSlo4kqpK54I9UACYlSRbx2JVG6yVd+FGMyFv01UFYI9I1yva51IJq5kNtVb19omhGRva5hqgi80yusrBRk1I2z6gJvDu43ATMqpoM8w1jRjTivVk7aEqoyzqquf0QTiuyKcDUBhUGRQExbjRFilWvaY9EBAhzI9q6JPP1lreaAbt+EEoOWgroVgQDosmiscMPs6g41mB178z8+lFrcDhoNFu0+l20xmjGRx0JZu+2Om9bvaoih+GJGr3K/n2vmQcw2W068Oj3j//5/6fvx/Af/PF7N33ZjzPJKeoSQ4ADMeleTW4SL3kiJwGzOcDjjdnEEuz/QPQqsTIMuq1EtbHI+JhVVvHdcB6Oqg94PnQ6W+DrR/gHQtafyzj+aQy5F55rIE0waGOZapocNCtJej/oh0qHNy127BoO5px1RbiVDGXzTO2gsA2bb+hirUGnHLUtjvQyDKKVkoxEfwh/aZk25uM1IGNWrjm5Uu4Drr+Hv97KVpcwKG3uhTbX61uGy2aRFMZRDzmaGW3tm/2ezD/AwffzWSeTBa2cbaaB6LWu06LPKjT2aL5X2wFF/3BODeJzZ3ME5/YFBSbXSSAylgoIIruZ84ByzKplKys+r2nCISqWvFlQF3MTzrobEb8WhNqUXC7XuxaXuapBRouUeRFbSfTOig9soyIY8I4rpigVBcfF/DjDBxUxy7jBBkPey3ubMk1pxhW8/QdCEiikatTC0Dbf0mxzez0nG5JNlRSLTF/uQC3G//IP/ZP/MQu2vXx+//AP4A/9Sf/3D+N/18DrzDm8wGlMqYUMd6eN1Bz0F3Mp8HlQD7V4woBYRiSPp319kE9BeR5RE56wZasHQi8xJe5bJVMtWvnDb2xg037vKMuvvkSqIRwXHaFFdcGs0qnLu0OCVoBxVD+c7V+bakyKgWMVLU4oWzZ74EFVYBkMq5BCCEYQFbZ+T1c3ZcuyXbJ5+LK34Q90F6uVwU4e2IN1gxThcmt4CIZYM454tai/2yRsPeiCyRbdAuXwm0RqK+3VNpZaHo0mqpSA+XKd+Hf5GW5tQNxi6xFcccfAAItCHHwbTpj8kaWWwTuVYxehCOVQGMBhQogAY8HcFTQVZqpoJbBksObKmBdRzVfMg/h7NtreuW604iXEhDSoNuwarfweABPCTydQS/cg/rTrYLTR/Zeb/7hPouDHUMPqkorSOYNbFkB2n1MVJNsUfzoUfyXijYdXr48oF5pR/TixQQAw5MXfp2PZ8vJUhrAoaKkAcvDdkGXHLCsA9ZVp2AnoOlEYywQURE7oC1e+iEyIic1wvYIYuuXtpWQOtXAFpUAEXBFAxNk1SkhhYLJVBDxsDa/Xo/ORAi1hiedd6tFxW6SHkMBWWhZqALYfAUaKNlvQMGilA149NFCKBZwvEmXC6gUbHdOrqxz7XX/+9ptxFB6gQCEqMbpTl+UDjQrCI8Wzbl2tlc/+HC+1wHPed0s6luc7Fzq+dA9ctqhRc9XdvY2Fjzm0CiaHoj70mBXUrjUrB2/P5jtu1lKxDkNCFwxDrmVjEtVXa6cB9DdolP1WJpcEVJQamxGS+uqQYRUbg0z/Rrtrx89T6H9XSuDuaLmiJAK8jKqMf+YEG5ncJmBdYXc3AG9Ix+g0a+Z3vQ8r5y1Gk5WLSKqa2wOfSKsGmQ3Djb82qo6gy0MkCxW+nzlgvkCh0iBSL66/PtxPBt4Q+giTqsoy9Y9IKUBuQYwVZA1FQQAKsoxDV4pZVIXL47oo9yUhicNErXTAFnjxtrdSD6tMs5LxTIaAQhrUmNK4HkEx9xsIn3s/Rvs5pINXFzGFKhqpBtyu7lbJMh1S8wY6ERSB7O+s4Wu72C0pxj60UNdD7rXmLk3lRf37yuieZm1AgezIFDA1eqxYhGuH/Pi57ZLMDW3MZ/W+xRbaAe6HtUWqO26d2kGtmIKp4a88KGVXmML4lrxyhXVRwM3W29XqbY7j101XtGZk/otVI1mH1TJkI06K8tgPK5SUTVHFCu86c9F9l5wZfP/cJrKH7rMFaVociulAXHIiMke/jmoHMw8dWFNLuVwNEObvDWOhSkbFkG9H7puL3GTaOYuKXihzHBOXLtnqNxTLIG80/h+CUaVjFKXp8vrl0d58d0cz/ZqYC7K9VpX2FoYtQasacScRr0YGUh5u3mDVQ4NhwXL+dBcwwC09uMeYXh/LiZtKwPoTUQQpBzBLAAykAajLXirajJZj49wd0a4Vc4szGNbvhn97Nu9M1cT5KveNQalOUqbNm8Xqx+Xy4mkslW4KY85ccVSGRBgsjJjIa3AKxfAeDmucb3XgPUSmC4tKv1MzEWr12okDKJua4EIiTUZFrhisGMsdhz6t05b/Xvk7kGlD6CNYugj2wGy43YJWs6cBYgg7Hx0QVgLt/MQjYd0f4yB96bnrZS724+ALTp3jwZ/eJfC1mU5NL25Jtki1k9eIJ2nzfPD20kJa5FNpZa/ANDor5zDln+oJilDvaDCuvPZKSPUxL8L+pkhcQDlpIUU6wo8PgKP2nZIzgH1fIN8OmiBR4raT/BmQbq/2cs3ZeN+m89GJYQho6YACqQ6+SxfOlWDSEatT4tH6hUwvhxEdADwPwCYoJj2n4vIv0ZEPwngnwPwDVv1D4nIn7H3/EEA/ww0NvoXReS/tuV/B4A/CeAI4M8A+Je+F4qK5wEvPNkVNxVDVS/bedVeWT58yj6G3C6C5XzAcj4ipYiUN6VCDMUir9giip7LBTYhPlZgiAS50AsTyZZZPqgHKwBNtn3wGvjkZdMMEwtmy3RvlVoVzAxWUhZelSXUTW+FMVoUf8qDAoBF4E43FBIMpFFfIOnmyhvlUC4Sad9qgYR+B33y6un7vR2QLxd791oUwo8BqEwYBao5Jp1JIKincuAKrozUQHyL9nwG4JFsK5cG2voE5bkvC6wEmkzrS3xzdetIpTtCF7ky0Crf4A9HenqiLikW39fYyoPt4d1Fg86J5nnEejq2golSAtI67N7ndEIuAaVrU1RraPeDrudWmvs8RLBggDwgIPuCpAI5te4SqFX9S14/QB4r6v2A9MmLplRIp8lmcnoc0RLHb+VqLSioTs3RppsPw9Np/Rc6atIuyBdDvgXgBbAA+HtF5IGIBgB/noh+2l77d0Xk3+pXJqK/DcA/CeDHAfwGAP8tEf2torzGfwDgnwfwP0KB97cD+Gl8l8ezK9eU6zILv64r7GmZkKyeP5W4gRUJHk43KtM6iUXHsU3p5zSqRaEQ5nW0G1Cjh17W5TX8fWluTxUoj1x2EUA2X1WKBTSoprekiJK2gorLwVw1yVI3LhPQNjK+L1UIk0myINxKW6upG2DlxAPrn57tV6mZRpuVrke7bzjtOzcy4ELt8AbuWKAJP389Vf3syE53bPKvuei+38SC2SI05bDRpqzOszptsFRGrko39MOplN1+0abT9UiYSY9tstlDH9lWOw5XNKhqZNOHXJ46f32gimNM2nEjZEzjimHUAgqphGwzn+Y34g/H6jMh3nh6m/E46HpCbTtORiQz0+n9LvoZVPMEtgd8d925Ly7lrNrdV4+o32TU5YD8+hY1Raz3N6glgH32lSJqVgVQiAXkBRskTQ/fijtgCcOqbmxa8vzlinR9aK+8b4/jtYj0wf4d7Odtd9fvAPCficgC4OeJ6K8A+LuJ6BcAvBSRvwAARPQfAfid+MKBF2gcbCkRyzqolWLebBUJDpaEXNR8e+CCtUSMIbdWLx7ZAjrdzEX7oKmBNW86Wi4bP2hcb6aAUKvyal2E4RcfACyvXrTtt6TePCLNk2qEywbssCkjkSYgat0iboaCpUc2gSoC1Rb5kkV9PsXzKbmQWicyNMINpOY6/fBE19vGk4gOb7+itomuNADuk1XJiqFS1XZGzrFGFvWf6K79vlS3X1bst3XsyGwAACAASURBVBh/XLoHQLN9bH6+RoVUBbhgR6BYR8alKxXh33PkDahcZxxIEK2CjUis1bs0rfAhFAys38shZgxWNgygdSOJsWB9hEWgRUvflxHr6dCMlAAYX2sdTCqjNAUDNdprd85FDZeO49IqIcmM2EMo+tM5o9EtqWlOrcAyK6+7JgXd84T0+kYrQs3oCZWQqnXkJq3Y1ECEzH/Crs+idJvq6U3FIFZVJ+pfrX7C0h6mX5YhdYWUpx0xLAr+m4noZ7rFf1xE/ni/HhEFAP8TgB8D8O+LyF8kon8IwL9ARL8bwM8A+JdF5BMAfwM0ovXxy7Ys2d+Xy7/r41nAm3PAq4cXrYNDLgExFKQSsZb9ptweEADGUHAEtXYvpaohtmai2ZZZlECMEcW8YreLw31dGQKEzWXKATqEjGHU1t3z61vl67hLvISKssZmkCNCJifTi9J7dJEVUvSJJa+uApzbFQDa12stmo1XqZm0ggItviAk2YPnZVeKN+l3L8dlpPdEIXHlPZfb1iIOwVw2xYFvd2CVmJUIHOzhpf4L+yjUQXVTRmAXqXrnjd2+iVIvauXhoa6Yt8O2XrH/U3V/34obA1TA7SJ1+8XAmKHAHK2t/BQzbsYFY8iIMbdkbMlR+V/WvoHx7qz2jtMKqYT1U6+OrI1S2KlrKj9xsWuev3b8uQSMQ0YpjBi0o/F0WDDenBEPK+LNDD4m9eZ1Xwb3YDgnSB6RXt+o9ty4XFRNFG+eJd7CiMFBk2tEG5VBspfBobo/h9JJABoN96UC35qBfMUgqCwA8HMi8o+/7e1GE/w2InofwH9BRL8FShv8Eeht80cA/NsAfg+u32JvuvW+6/wu8EzgLTXgo4cXuE8jboeEkTNGEM5paLpKT0BpFKDaV9eIehFCqWqC3Q/v37U1TXTKYcu4Awrim8mLlg9PhwXjtGI4LMjziJLVJYpEWvY5Dgm1hl1kKqIqDV+HST0gPOLx9dy1LHBFsW4NAGN1EyBQAwcW9XXI9qP7avzilXPaf9OXdEIPtjvwvkiu6fnDkyn/tSGiyTYRwkwKuBp5k3UjZxAqBtbz0xLkzifbg+NaDzZ/nSEtuu93yUFaRBBZE2eCDcjVWF1nLZE8CSg4xgyGtO/ey5n9mjjGhNtpaZ01plF7rfVevCFmk3RlxMOiHg1mWxqGjOmw4Hw6toKfUtkkY9xUHHruO/mgJ39lKyYBsNFsZkUZYtG8QzRNei4b6OYMzKvaJgipzeTqfPQ+UUYsLSp3CafO5lgZBNaEtHPWPuK4RcFxTJvV5WdfLp/boJpAVzheKt8Sx9uGiLwioj8L4Lf33C4R/QkAf9r+/WUAv7F7248A+BVb/iNXln/Xx/OAVwiv1gk3IbcbUURBVJsQihlp6/JsF+xr00M64Lq3rUdKLh8ajA+rQkhVMHDR6SRXm7Jul0oIOpUbhoRhSBhvzqglYJkPOz0l4Im3ZJKiABLlwXZcGG39vXIR1DpYNtyi4a5XW6nczL6LHXfkqkAL7PwepHIzfAE2WZmDpjua9WB7CcCXf/voqQSfrmfZ0wyX6/u6D1nBLbHuSxb1d1gLwGDty4ZNUbC1GlKKQTnePY/r0eglpXLNCKiIPqRGaNSqtR1ihjfAyBUDV9wOCYeQMYaMm3Ftidg5je0BfDfNuDmcEbhimpaWZPVBpiUfDguGmxlStQIzW7EPx9xUNv4deyeTXmXT2t53j0Ff1ryK/WFcGcmAnYfS9MI0ZNAwgw4nYBwVdB+1kq6cp+5k1sY5O5DmVSWaTfVD0oqRiAnM+QnoSgnIMyGMmuOgWDdFw5cJeWt6W8T71kFEXwWQDHSPAP4+AH+MiL4mIl+31f5RAP+H/f1fAfhPiOjfgSbX/hYAf0lEChHdE9FPAPiLAH43gH/vOzuw6+PZHO9AFcchIXqLH9ms/s6WVHOurvGy0Hr6viKqv2Cdp0PH117qeFvG26IaIuXPHEDDmFDPm4kJAJQSweanKqKFFcGkXw60mqAQELFpea0luRdm2Fx4TqMmWazzrkdd/bTaM/FM0k6sFlIYEEMBqAch77HmwHZJJfRSsdYWvpui+9/NYKbb7hMD9ov/s31wZEKpmhqOREgiGDue9hI0K4Cl7ikGXd7d8Hg6XFpm5oQYTHNBpA+pG9brYOKKaMDL0Afv7bTgOJiXbRTcTttNqp2ERctzD4vyqTGjJNXmViFwzIij2jimedwM8iuDaGxKhhgKUlbDJH9wuwUlYHkEmDE/aKOgIM3tLtqU3ouJyjogB90nXkbwOYEeFuDO3stobdOIalNv9HRXK/LxfIIl23brmTqlr17T92uJPXHdaAbb6y/LIKmgK8k1+tYKKL4G4E8Zz8sAfkpE/jQR/cdE9Nug39IvAPi9ACAi/ycR/RSA/wua1fj9smXxfh82OdlP43uQWAOeCbxMwCFmSy5poqznOL2yySOj1plXCGezAmTatJg+jSdA+Sbj47gly7bPFmgUO4SCccg4HhaEkJViOM4qj6krTq/vlJ9rPJf+XuYJw6DTLK+Ac+8GtgSF1ApmLQgZSNRWkAuWpYtEdudDY9kQgLnEpuutpP4SjA1o3cvBiwicK/0sE51dMUS7Ofcg6hIyB18yaHib+tA/18FXWKVTmlwjAIwDK/3jkjSXkSkts0Xrvq3oD0uiLkJ+Sp30CcWDJfW83c/BuNuBK25jwhhKe8gzVzU0J1G/Xev/d2meFMaEYVqB27Ma8psqAFxRVzU7X9dxN21XNcOmt3WOtwGenzcApVMS67EbwBXS4qFexibUNO9EAjYHPTqfQHcAxgGIFZTVsrLOI0JJ8F5vJQfArFH7pFnvUyGyJfy8qMkTau5REoWQTgeNvr+Mng01g/LT6JbKZxdQiMj/BuBvv7L8n3rLe/4ogD96ZfnPAPgtn/mh3+F4ZsQr7SZQdcLm9rWLZrHdpMDGgV1WKbo20zlMzRq7lEi5YGZpxRTHYcXd8YTbmxM4KM2gXqultQKKMSOt45aFNi+GWieLcDPGcVU+LMcGkoAmLgA0mdEwJOQcG/Cq1EygyTfNnkdTbAy54jENSODWx20u3DwagtfPw2RlpBTfc6Z7Drg9oPbxyzVFw+U6/XfQ9MDwIEtaNRpXaoUPsdf/99yhUUYOrtkAGRefodzupj3ut1cECKL7NYZinhJbm/b+c10rG62jRIjZGnVG7U5iM5ghB4SYMUyrcqvWIaWmiDyPWObpCehqs8+OP+3+9sSrA3B/DvtrvDiFxVvREKAzsGImUjVtnr0YrSXQMoM+AEJcQfdKR4AFxTu4WDLNZ3AcNNcgnV64eGsto0R6eVteB00usnHNQ9Zo+Mvk11AzcAV4vWPH99t4nh+vUJONjZKtCku5ztW+6NRFRZdDdaCbK5Uv6y/k0J7i2zYCVdyMK96/u8ftzQnjtCIOCfGwNpc0HlfkeYS7Uvl7nbOTHLGmAYdJv8jpOG/TS7Py6+kPT8og64UfubQLeooJU0yIoWDJWiatCaIt4u/5azHuM7AowFVVOzAE0XiCXDcqYnfOOqClt5w3X7f/3c65DY+I/XefmNPzbNn5VlmllU5Btm1VaKTbWrL327lCbzQe2o/Ffmd4OTOBBBiBxuePXBFJlQqRi3L9Bn7FpvLOn8/LiGWZ2nc3FI1+xxwRKyPcLBrtAhr91q7qrGyUQi5bNaXLxpJJw1ofN7s2W4RrD4HLa93prV15vUWfMPmi7uyI5sc7DsALaAPMVuAxYZ0nJKNF7Ftq5lH9w4NZew9eTsyzHZ8UxjIfEM+rNe7kRqV8GQaVDLoCst9KxPvrcTzTnUyTY6EKHmVoRQSv04ClPp2SXQ5fJjbdvlwndNFOYEEMSml8cPOIm+MZt7cnHG9OOH5wr2WTh9VcyBjlPJobU8fLtRtkP41U3wgzxiZPhoS2P712NYSCaUwIXHGeD4gxY7Dp7rJO4KI3cS68e+Co7Eyj2mj3mxjgCOnDZ4EilUALKi6n5n3y7DLSBZ6CqMvF9Jj3r/cjy55rVgHdNopsbxpYo/WBBHNhrFeA1ReluhVFANiBsvO71L1vKYRAWxGCboPNp8FatrNot2CL5tj+JxbkZJRBB4zVSnSVYnAbSN1+PCwI84i0DptKoUum9eXjgGq5s81egKfX9DXHPN9WYFXLhAAQa/GNth7K4NFayzNr14l5AU4rEEl7wD0eUOYJZY04P960fdQIWuxhEdv++76EUFFtltiPUvTBsqwDDrcnnF3j/mWKeKWCrriT7QyEvo/Gs1UNZ3vynkrATSgoQvho2bu2RZIn3ylLb56tBbmexXYh/BgKDqFgDKrjHbjgZlzx4vYR07Ro8uTlI+LNjHinYuvl45co1nm4pNi0m5LjTo/pg0gwLxPikHG4LeChmCC94NKvVIz/Pd6cEGLBbVLjlJID5mXC43zAmiOydTAO1TTFHiUBJssyrYIB8E2oSEKgwjiDkMrFLOAiguyTaUW2klpgA1F9batUa2XD3fH06/rnNJMdcdDuqAQor5wqYYyC21h1n4t6NPRnK9c90NrX3D6niIJ43e2vFXRgc43T5drSR/2C0SRdrt0GgJKDenu4wY8Bs2tvSw5NLgZSc5xwk3Go2hXFzc63B6U+pi5lcruqST8uofY9w15rKgPojMuj3k11M2O8PSPezuC7RU/G44N1Da5AEcg9UE8T0sPRKJGDWqVaMhhdMNEHFr6fXrxRCpp+uV+3lIDHTxV0ieXLFfHW8oaIN11Z+9f/eF7EC8LrNCByxWMOWI3DbNNqUqGNt/sGNn0ugN10zS9cr0o6WBKlrwwLJi+LUbWQ482MeNAOAjVF5Icj5k/V6CTn2KZQMWbMy2HP1blblT04lnlCjBnjzYwQt2mbt62vRXu5iRDCoNHKcATW0xGvvvk+Tuejgm5V6sWVF5NFP4G0MwUBiraVFZRInnRjCNTDnZ1r2dMMb1IvAAqYZPraS68G/V722/XffWJPVSVQblGAgUg1vg0kles8BDWA12XbfrbqtYtj8Ah491n2+zZatVy7vsyVDJuqJdWAGCpWK4DQc6Hf1bKOLRmrDmQKzClHnE834FAxkai5eSgI0wpJUWVV6wiq1eSDYUvS5c0vpL9+/P9+RuPXs6seYlBftiqkrmQHvbam2zOGmxnDixPCyxNohMpClhMkAxShUtyHCWUZUXNEOk84Pd5YmbIWSXjLe4+q97aU9l17b0F7QPlsz6m0eT7AO3R8mTx5qV6nGpDfAS9EgIfMmFidqWbhFoERbZlWn1Ze6w+myRp1w/Iyz9thxTEmxFCRizZbHLioo1koYC4YxqQRw90Z4bjg/2PvXWNtW7LzoG9U1Zxz7b3Pud1u+YHBQSYJ/EAKECGiyBYSGMQvIAgpVkACR6DIPwgChIhbyQ+QLBFHcTCgIARWZAWIiHlYIJKAyEMIBUeOsJPglowUkwABQ/rh7j7n7L3mnFU1Bj/GGFU1117nse/t+O5Grtbts/Z6zDXXfIwa9Y3v+8b5l77VTE5OrSOAD/eTKDW2gNuoOKSV+22fkdbSqEdxUvigNcUk6bLLoHQ12DKWpeO5gFKJoqngKqmYoi2Z0elwRAAs6K6VmnLM34cL5zKgwwiJrgdV/ZTaPI6vH7Yhj89FL2kOwRiafMWh7lI9W4cHHmAOgodBgSfoAbdyh0YYvbgW6bgPc9DVwGwwRj8Gvbjqq4DK2g2EhVpQfDjftMe9K4ZK1UUC1o2QpgXTSQ3xw8Io9ydwCVhuV3BJWB9OiFb9d8GE/p4eXJlDV0wCjTJHDqvJIK7h0HDdGI07PGVE8wmhqajybLXjviXINiHcbKhvblC3WSEzJs12L9g5PrF4MB0LgO1aoOMFFEiaTN/5z6dJBSYszyfjRVVmx+X41YwXvWj0UOnRTT4qm0YO7lgQ8qLG1GCFglMqeDHvuJ1VeeQLWPd2uDmtSFNR8UOs5qavleKya4sg52O645nfSGWwcfTCmHcKjlm9Urd1wXLqbk1EaqrDOSFACydON6Oo74mWmY8XvIsHvB15sPe5p4DLb6u9N0AfJwtImYEEQRk6E4chgL1PlRbIOsMIjGVKjQZGQ5Ach783jt+JzjTwTFZ5172bsIjCSasci2ujac/ltSEOm0CDcLLMbTRBYqi7iWK8hu/a45ZtErCV6YCtRnDDs8fAo10k1FuXX6fDc/PtGcKE80NoOH8IVSl1dr2M57c3Au0qNcddWdTjtsnXA2Oe9gY3HGwhobQz2ZP66m4T6tkM13NCtWLaiEMDjkX7xNIz8cK9kMy2KmntkMaEQ7rJfz8vzyfjhTBwBePFr2K8MBcrarzUVuVFz3odbhixQ+8mO4UedBczNFliwWdu7vHi9kG/w/CyaSogYsynDcvNitNH98p/DKJ9plhvKO8IUKq6npXmkBZbRuQ3il90AV2l1paMsaqcMmnFPBrZXj+gbcKFA2JSDX4uCec8d6XShZACtvx1HHDxm7JGMAJOYCTpnrUI+q+7BgdfvltEytKFGB5Y/TFgWS0GetOw6B/fP/5dpQddf84z7CoKiTj1S9ChjhRc8guc38FvV2wUbf/a9RD9eEnbb32t1wFUtagTnJ9DQCfk6hV5M8MReIDRC5oZWBZdzfhKZntz24Kwq7uU+sWPskRAfRdKVbbKZYDS/bTJ1qEOs2AU0fZWDo+5wKeNJKAkqK8nM12P4G2C1IC6zdgeTtiHFdwoXx8bBLDBW8UwYN/HQnKcfMRNhWILwq/LqR/DZzKI69Xs9lcz3osxGqh0sjgOYKVKad3STzB7sA1sMtCKyaS/wZycZr/xlh3zvGO+WzHdnRGWjPTiATRV8JsbAMC+zS3oevcLr0Lnmg59vuKAJVYQUIE3640Z5ejFuZg8cb47A+RNNC3AOYd02THXgGXecTPt+p2sIhLPep3qRCTNpHsJfCh4FQrYjJ/l/GWdsfR4bWycWJvVyJb5+YoqYoQKnNXwWKIrb+HYPn5e398fZ1bMVywLXQKwBw3aNLz3mmDDJ+VLSlwVhTmBgEDOc7ZAEGsrtnpWWyXgbEb7Td7N4WJ1pQFmThmnZUOM1WxAkwa2okG7OiyVO257wG8xyIMtWHVaWb+W3AaVmbRHn+PSecKUCu6WHXHOLWGQGiFbaHxxzql5RrAVbrmk5p87siXcSrWvLuhgk9omfun1Fc1yO01SQL13oPTnn8Xgeh3Prc/MN/gbNJ4ceH1pedmOxelhBA2yi6mRJlsqti+0G8r/S6Hifjsh14QUKm5vzri5PSOliuXFGdPLe0yffYP42RV0AupXpm7mHCumqWCzzhW7QQ5uxONFL8CCR3B3JjX8YRAetgW1dgkxkfXGmnMzzfYWMDFVczhLmKbcsvTNGBS6ZLbAF6pyU4O2Drovk6n8CIkElUQxTIs11ApUmlZO6BkvsUqR93bT+ZkYz8GxePU2bu1lpuzb61Q0P16C+wIEUhKYBk4t8kwkuI2Mc1Ej9TFIHzBou0YOzAuWhm2TQTO9O3HH/QEzEUc3xXEHPIekIgXwhcScIFhmLdKsZyskXXRbaAUqLzo519s6oYjBZdm+1zaM4tQtsRY6VteYSAt0W5mUjZMKYmTkfdKWUzn13zgVhJcrKFWkFw8KL+zoirTBmpKNJUPE2Mr0qJB2OWH4c91Pw7n10eiORxjluQXeqxhveZ6Bl4i+C2qm/vdD/R7OUC+IPw7gvxWRd2IkTw6846kaObst+NpyNBqW6x6pE3E78VPQgDtiYoBeEOu2NNVYPG1YvuOrCJ9j4HYBvr4BNaA+KA7m3YVTKtiLdoAdg60XwfzmcRWSMruUe7uZv3A0xVHJEyYL7GVdmn9vLVFhhrsHnO4edMkqhG2fcTvtmGNErvr9gXTSqWZgcp8VQGieFIYBJwIAGdz5OnYeIIBllM7xnYL+wQNXNwZdzivDUw4BV4/BMfiOGe4lZ1jQM2ZAg+/Xd2CNwClqX7WNCaeosNFd0u4R+3CJXft+sQzSv3tkQWibd4OgbNlfmfCaZ/PmVcxyLUmPLQS3NoHuzkYw3D+QNI71vs/Ke10BmfWGdtaLB11v4zMGoMoB2ZbvatYUzU+6v6+ws1jYYA7/rQQOBKqCh21BePUSHwEo24xkwp142hDuVoSbHWBCmHfgQVWVnDubIkata+Q8QYIyNbzI5/DH6IjmSk8fY1G5MqFIaBMHAJSWIjyTwXIdz313/PpUBhH9BNSn948B+H0AvgjgBODvgHas+D1E9HkR+R/fto2PDzUMWYwvJyN1K78mhjC6WAyCmSpiENyY8msMvIEYKda29BchhMSgparGdM/gszo41U1NTlYzsHatOtmyTw+Ozvh+wwQSSFV+aHRaDqRlUXtOmFLCXFXaWfYJ21nxNjd/j+YVsNydIVKbbHlOBUkqltQv/L0mFE7t+7UNkHnDAgMMYcwB6ctx9bMAgnHIJgNvHQ+dgrq3+Xkg6tfsGGTf5fvgQ6GC67dgFjc8CspWsP8VBuZIFiwFUyCsQ1IpkBZYr2HRGoAJLy3oJpuQvBvGTtI6OWcOrbOEJd+tdOjnOAqbXFYx1ofzTcsM53lHzhPmWaXltajyyylWjnV6hwn2rNeyRrHg2wIcVIY+Ftu8iakzK6oErPvcCrC3N2fckJrl1G1COM8aeIOyaEYMuJSE88NNu2adrubNAtgy8tbIc6hb8DAJ6LHu7+lS/mdaXGOzyrwc5Vl2zPgDIvKFK89/AcBPEdEM4G991wY+FtTgxTMvsAUAN4lxGxmnwS93CYw51AOzIZh5yxQrXt7eN/kj0CWYKdWWIfB5QjyZn+8+GcdWLfe8M7GICRgCI4pS0vyCdLMe9ZYlDWDk9C/1gCjUW3MDWvmueWr94fw7gKKE9hIbCX9vlpehwRwipNmvXeSJusBXSFBDb44J0QAWQmc3VNtXtViVVtViASQYLZgIdQhwTtvyxx5kI3V2g4+D8Y4FwTLcsd7bz4t1WQS1CooomBSJECrwctJGnlNQO8kRf3ZOcQwyQBm2TQEeiuAuEeZA2CiAM6lBzoBxZ4Nl1INBEEQn6bUknFIBWjCnJh4oJTbYwSlUp2XDJISSU+sm0XunhSa08RpB5YDVONrKSfcgq6eCSJrWhkENdhDzEi41IEXG2VY6TglLy27881tE7/IbBPG0gb/+Auv5Btu6YNtn5JIM8uBWGPMkoZlRCR3gg3E0SXcLvhqsPcTX4bPPYRC/jU72/KCGa0GXiL5dRL5or+8AfvFd2/hYGa9ycbtyB1A11osp4y4V5eAOM7WPsWfZOc/4iN7gxd0bq/7WVvQ43axYXjwgzDvCYgc+ADRX0KZmOPOyY2/mNdqyx71aiwe5IYt0UUewtusi6otbRRtc1iHTKduMfZ9bU07HgJfZesPd3+qNsHdP2DHo1pZ1a26mrmX63WLZb0WnTRGpaXwUpZll6X3NsoHqFVpsc4Kc9nPTCOsuYc5UGMfbimf9nHToQo+Z/Z6L91URrMz4ykZYAuGjWbncFJTFEgOwlceijAZxWMZeLViqao1aN4xAgocaMEl3VdsRUAhtxTDHiioBk/lm+Mg1YUkZqzFckvXH099DluHGJi4YqYce4C6LVWfDVMcCF/vKxOhnjut7cIuBwZwaEwNQ6huR4LyecLOdUddF7RuZEG82hY6sj9p6PuHVmxetiLhXXTFNQX/3GHCzwWqX7Zl8sqx8zHIbBj5MSu9yr/sVH/WbJ+Mlos9dPgXgzxPRbwRAIvLL79vGx8J4U9C2LCMZ5SYVnOyCV1xXD2I2ZVeAy2kZU9SiyeuHO81GpozlhcpyASAuO+LthvTZe9CtpkmyA3w/g3PCdLuhrAumWbmSnq0Gi0B7Tai2LPPA79xaFtIf4TLMoEtVH1wDzlk7Eazb0m8qI9qfH27695kRey4JOcRGwAfQCjSBdDKgqJhvCsMS1Y/pwC8mC65kDTO92Faq46FdagsACFYI4uv4LfW3tef7Pj5WzAEAkXaCADpTwg10dtamlMkytt02XC8jNbpwYrS77P8KvrozIgWdDGvAHASl6HGZg6BU7VKhRP/UhCleJAV0BZUltGzQJ0+HsFgIlAUhTE3ksFsx1jnjjuuONQJnLNAQ4Mfs0cdae+dfYk1GFrv2PYgvSV3uXr96iX2fcXP7gGmdla0zFZTzCQ9vbpFLwlYm+y8p1ZADdluR5SGR2WtEviisjQF4r64u1GOR7Fz7PVDlsnPcpzyYrwfZ+v7A+4727p8D8JMAvhvqx/v91nMNn7C9+5cB/B8Xz/0tAH4Oelv92vft8xPbuwOnqNSoUWkUgyuPxJpVclOfOfWm2nKsEeYtk8h5wknUKWx6eQ9KjLjsCLebChm+bsY3ZnjC5guR5ozltLXOEGTZ4170BmNQa0PUuijYYzG2gGe+Mi7JrImnwxhAv6BL7cGVrHrdgrD9fiYNXGTb9c97f0HPPKbArUNHa2N+EQbdzczFDBgoZiGaS1iFZc9WrR5uJ9/aNemwDP8Gk5p1L4LHWa8HXzKj9FfZs08ynjasku4qRv+cf4+07fi2Mwu+sklbBiMpZKHbsqaXDFQL+o73jpaHu0EMDZEhafAAibSW9d0EJxyy2ylWa9aaWtHM8d0swbqFOPTSsV1tb6QJRR6pXEC77hCAYN1D9zJBzrZtJtwMQoZqrJh9n83tLrSgWyQ0/P+hppbRelutaquBQHqBOZzwiOkANHFPe88zghoUG7kye3+YgOJt7d3/SQB/WkR+hIg+D+DzAH7oG9De/XdBu1z8ayLy8wBARH9VRP62D/25TzRC10z3MtudTKHFcbhIPSMMRY2YQzcy1w4SvRoNAGWfcEqMdLsCzt18fYP6cFIMLQjCVIziFVHMfcqLa41wTtxuHC+OjJVfscIfmMEWIP0mZCFs+4RtW7BbJuMUMWZCrbr8VM7xsVDRJhMj0gfqHMrJMi/m1CYnx3zdr1f9CQCIW2Pq86fAECKczwAAIABJREFUWJkQmRBj16Jlk/bGAJSqH5yCLt8vMV0f14pr+vwQrIkeYbxt+WrFtmCPXxdGIrKiqlX8pQsi3LRnVMb5EBFkALVW1C3gvlAL4nMAagJu7bdqsZawuk0jVCm219iC3BzVPpLQVW/ZOqLohEkAXEQQWqfre7OUrKINWBtmCoV/Kklj5Iw8AIWpBrhjNLCJFZX1vE+hgrcb20e9F0JghJW1I0Vk5POCPU+myCNLJHQfNpv8Nw5NBameyWQThbncjdfQlXNdaahhiPfNu349fCqD5S0Z7/sD7zvau/8WAP+APf+HAfwPAH4In7C9u4j8KBH9UQA/RkR/DcC/jkt+53vGkztQ3Eb1S3Xsq3BQjI/EZuEIIvVjiAY51NADlPMck5lYJ1P3pDlDSkB+dQtYmx6pEfnNTbugw9BLq+4J27qgGqxQrGiiVK5e0MsXrlLuA4CglLI0wBEiam6ylaktEx1r9WKMEuYDsjW9TKm2wp4I6aTBAWxB0Vd/AYI5FIgkFAnKQ4UqjbxzhUIx+v7FVhEbK5PACRMMxUmn5myj50Wg12giFSb4VWCxvI2eBfsEOWDwfmzHc44jbfBIIRRsFow3osa48Mzbs90q1tRyyHZHMUkWQS36myYihEm5wUXMUpO8UOctgdRQ6VwmrKYODJAW7LSOwBaA9Xxn62rNErCa2MYnXA+6D6aKG8dECmUARtECGsPFr0vPPMeOKxKrXlf70jogBwhySLh/uEUIgqVskMoKfZSEPMAD2bq7AGg97FgI2wHnJTOpQrs2I8Em9z6p6/nSybxDb0+MFH+jB/N1WEED78dt7/4d3nNNRP4fIvp2e/snbu8uIv8XgN9KRP8YgD8JzxM+cDwRatCOr87PZQBi2dxsaiNnLew1IpZJmxQuWzOtSbEimiIpBMY074hT1pn//sY8dalRbPbz0h37g2DxjNhs7dbNu01Ya+5WnQ6HgNrmTce27OYpYu3kAzfsz2+AYNmFU3oAu6n84mWtxo/FFc94SQgVmqF49dkLa0ssDUdkAME+M9mEoCwRnWS2fYJAcXVvEOk+v3pO+ogB2KplmvAMSItnoanMzOvWnh+zXUAD4Zj1Aj0g8/DY//Z/mTX7DdLb0BQxo3do0B1zlzGIV8MJ1BUNNpHb77MVShrMdDTrC/iqZaun8dqrVhALumcR0gpVo1/BXmJjvhQOLehWIeyWTASSw2/Odi1VIbjKzvHShqWSN2vV1yMJUA2L5ojER+P0kifU0pkW/pls11qDo7xAZgG3sGe93TvFOzcHHOEGh7FEyJqhWhcUGa+eT3mwqLfo5dDZ++O2d3/buPbD31byeOf8JCL/DRH9KQC/7l3vuxxP77k2XORaBELrFhCJ4W16HHLYa0IsrGY3HA4dAFwokeasN8erO5Q8NbXRcvegbVtybHDD9uYG081mP1qhBsdinQ60V+8IcWw/5IPJKvH2ty9H130+YHgtuwsMiYP0crigL2noo+GLF6g07VWHLZf/VgmIoSDUiBXQGzlWDcLQm+++cZQ7/FBxLPhcFtwE0jDb/p5j0AWO2ecYBH2oIk0Or19mvO14DtsqIof3edAft/+4VqFjDoRTJNwmrSWcIltdQamKk4spatI2Sxywjn3SYNenBBBpb8Bxee2Tcq5B5bPeuJQDAjSw3hdVmXndwlV2mrFTqxM4c8UxVj/OweofeiwIkQNClK6mNKhhmndQVDMmkaD9AEm5yTEwbihjrVFxW/t9mQP2GkxuHVBYOz1n1kkrW+y6bIQqNlkDLrYhZDwvqEH4ulbiqfqJsb07gL/unYaJ6DuhQgfgE7Z3N57ubwPwSyLyp6AdjL+HiH4Bmo2/12DiyawG99D14V1gHbt0fM0ver/Yz+sJtzdnwHi+RIIXL99gvtVusfv9Cdt6QjHVWC2KgUUzrSkcjZLlSy3NcJkDck2tQOKy3E4efyyPDNDldGrLMzYNu/aRmyKrWsw/wzg0Phy9WIVcAHIMUpAjpuYdKcAMQtf+T7YU9vY0OmkAb/KEKtT8avuyvTuCiT2/s6B6kmeYa+9zpoFvvMeuBd0xq/V/iQgR14tt1+6HpqhDz5rr8N63BdzxvBApo8H/0+tNGj/8XFLDO1+XaEFHm6lGe/2jecciLmigQ3NHD5iRGLvEds7JoLLNskkS5Vfv6MXZkTqWDSftxS09J0sgzJFxgkra2b5zR8QcioptTF0HqMBD2/AQPrp5wNcf7qzzRcBEDDGqoasGPaCvVc+pB12/Fsbr3H81iy4SIw08ccGjNkGf6mC5bsF36ZN6ZbytvTu0jfsPAPgR+/e/to980vbuPwGNnbdE9APQftE/BeAfAvCb7LveOZ4MNUTy4tBxeM+xaK5S3hHAebuVA9ZtwcsXb5rD13SzgmvEdn+LfZsNs+0Z8TzvCkHk1LTsVaiJGM7rCXtVl7CtJKxWYHOKTzYCvWcrzegEmu2yaMEkkOBsuF80qS8N2CdR53kCaNVrD1qTFfQcdvUqcx2Wo2QQBcXO9Y0Ec+CSduOzEN5Y1q8KYcd9NTjsgyzUe6NNKnPTQpa9Fkwz5qi4B0XPSPt5u57xHs670csOgXfk/rbrw56/zLgvAvdlRuxjZUFkYGfCxIoXi2jfsEgRO4eGdxYOOBcNlHtQ7wgiwhLEirkqxmiTpOHw7vlcxQpYw/Ycq9XlvRakRlm1r0S7FwLZ+e8/WQBkiYc7a07dZW1J2kaKAqsIx2hsAHBaNqxZueF7SYj7CTN0wsn7jABgtYkB0NZJHpecOy143A1kfOy0QwzPPYuhxYvH48Nmh7e1d/9zAP4zIvrnAfyfAH4rAHwD2rv/BhH5u4goAfi/AfzNFrT/EwB/6UN2+Ml0suRwwrCc8eHeqQdCt2d9rujKE043K+KcsT+YUmddejttU7IRCd68foElT+3mEWvct9cZe55wXk/Y8oS9xFbh3mrUJZldzF6MON7s1Ej5DMX/smFoJFrM8ruttZOpXTbafxy3IBtiNfWUMSmoZ8Ye5D3zZg7NGlGxP8HZCnr3JWG3fVG4gtTLFoIghNlaxAdSEYWwYrsRhMqaNFSRVtirpihLg1DiMshe/j0eK/eA9ey3XuDCAt23/tnRbrKr4kas+W3ZchE1zHkoKgZhOQI5pyitmWq1DHBtwSfgFNVQ5m7K7Vh3GEAAEtyEHRsmrKUzX+6tSLdzQGbCufZrZmMYftpBwEsoMhM1yCdXwsk425mo2XxOQRu2umHPw5s7uNF65YDzesI8FdzM5qr2cKfCCU6YiHGXCqpMkKqqvn3IdPX49eA7jrY6Er0OPPDqc88o8jJBymOIVT5AuPaO9u5fgWah1z7zSdq7B4Mb7qBFtc8A+GUoj3h61wd9PA1qMPyJyKuk+pwagDPcL0H37BiAAbQAtpvBTSn6OJfUzMyDqX8ak2EXTPPegq667yufthVMxGACy3LHm8j3IVFHztu2SewGCa0AJ1YUa7JT8SCcDiqmMSQ0m0L7DIXe1cC/1JVxEUC1zFuRh/5drpYi9OUtgNa9IhtrIVoWXJ3KFfT5nfW/rToWbaZFMrAY0DOeyyKaZ/nXAuMlxextw4NwbNmhHP4dlXWXjIsqgrUyTjEiVmMRGGQyh4As3a4RAM5VXw/SjXpeJl3ac9RVRSBCNOtRFsJu7IYpMqrotewFNXcQq4KmqGtClOFHewD29062hNBzoZNDDhp0l8C4TRkfnc5q9h+LypL32Rp3VjysNwZlBdzdPGDblrZa8kzaJ+JqQXetfRVOw369bWXO9lve5svxqQ8BrjbffJ77+4cA/K/QBebvAfCfE9FfAfCbAfzRD9nAk6EGsuXxaMMHoGXBrlBzUYH/66OUhG1bMC97o2Z50FUcN7YAvu+zYrCxNCWXtzzZHQsWk04ydeK5VW+14KQV6il0qlZjIVBAFpXqVi+oQP+71L4rNnjsKAugqaHEoYSLgNz6xklvRXSUbVIjyHtl3NkRhyBngToSWrCNJLiJGnQVHjN+ZrDr1bCP3sH4GHDlLQH4clxivJ69erZ7jZqmfeB6RqyV9mNmPEIUgp5N3xfNdrfaKWVfpYBTa8vkcuOe5eVCqAHIE+Gru0nJp+MKTIQa4+XQusle31pQ023n4VQH0sJUDG4x2l+fbH51vJ6gx1/bWxXcTBmnSSEGF+bEwChFVZJrnlXVGNXo5+vnO5zzhPs847Vh/W6fydDJda2K7QNaCL02Ifpz7hDnp/haf7xPe0glSAmPn39+Vg0QkR8jop+0x79kfN9/GMCPi8if/5BtPFlAMZLUgY6dumrIsV1vjzNmwH3HrWPs2OhwKID5cp1rUE0KgJO1AAI0SxytJK/FDKdwNQyvqBIqDNm6F94c2wMzJEAz3ovLUrxY5JBE0H5wwLH9CtAzYP/3tGxWDOxLSwEBgc2URT+bAiPaxMFeGfd9A7Rflz1WvizsseBrezTaGey3ATNp5tbNa46+DIBh0gCmEJCZD9j2+5aiOhXpUsKpaY01YcG2vedijAEbONLeHiojsz5O5s4WK8EnFs3q9XOnCNwXDc5TIHx1TwgEfG1fsNaEzy6rGSLlNtH5Cumc1WoyDsHZl/D6Pd1m01keQTQA77X7DHsA/mgi+HynrIxu5H7eZ+whwdvzzLG013Yz5sksOOfPoHDAfZ5xXxJe5dS4upkJr7OKJtYqbf+USWSrnAMi3bvFFAu+o2T7WQ0JnTY6Pv1EVsOvxCCiWwBfGtgL3wFlSTCAb3zgVT4lN5qKYqLj69wq/NFsHlXRZUGaCcu84+7FPeKcUTb1TA1BgDpkgDZYCKthvIAG35gqTmHVrKFMfQKAksu94KE4oGYefu5Kky33QtBaI6IpgmLsP6bJjL0oxxEI2t8LhAO3dxxEAm+A6LDFZpm7rwR6ltw/n2xJymKKLAloogo79iydrvRgF+kUBPclwn0RCMCclBmw2lJ8J10BEDrW6sck2oRS8PbM95J/605mns3GIZsdg++1UYVx2Q8uEKHaHVZFUIXxAGChiDn4KqYXwu6LBpBE6j59ih0WKAK8LqExDqrcYKsJH81rk6+TiS2qBNwbS6IVR0UD6assLVP04Ob7C3ig7zS+YKuOBc7OUCz+oUzt/LrpDkFwa30GO7dYu6asXqOoEfcl4r4Ey3KpFdMyj+wEQZaeTDimLtL9NS4phM9yVALcsW0czzDjBfDfQX0e/jIR/XoAfw7AHwHwjxLRbxKRz79vA0+DGkjwYlmbexLQuwRMqWCOBVPqRyoEwZR0UmAh3N1uymY46QXnRTV1FzPpb1Viu3MtAb3ovQX37d0DKDHSWltG7aR6/55qFCMnt/tgUsBOl256MT/UaPaVbEt9C9bieF+woMYICOa9WhEpoAwy0gav+Hf5l8pg2kJd8Td6qqbIbSLLHDEJK3UuKH7Z27v0cYLe4K5OWoL6R5yi4GTf8dpu3GhrTlWD9eWpww0ecMdsd6SYjb+J0bPT9hMvnutFtJ71Cqzw5teSBV9VuInBPnyAJc5SjFYVsEgYJkP0rVggSvHx0tmx2/uSUPgWNymrP7QFQYYWX9fag3skzWZ3lgMDZMwp/f8j/DoSzEQHdeurrIHzFCa8nKbmrjab8m6KDJEdbuS0loTVAu9u+/S6BA28YmyJAWLY2QRMdt78sXOvNSD7ZGEcY+Bwjp/TGP1Sji88y/39FhH5y/b4BwD8pyLyL1rB7WehnhDvHE/m8d6d1NBmy70VSYoVd8uKZd5xOikv1+34mAkhKE57ul1xenkPIsHD114qHWyfzR1KhRBrSdhZ+6V5hvB6O7UlWkra7r1ywJQKwuaG6xUTJS1cwQsJF7jXcOMK6cUYLXNMFnzX5vlwifOGtjF3sIpBeapNNCLK6wVwwLadYubBNsUKasUTvat8lcBEiImBkppBjn+nY32nWEEmrmAOeJn0hk6kAoI5MO5LQiDBErUhpS+LtYnmiEO7sfcg+MCwtLa/r9G/9KhQgw0um2pqZq1BOJr4Y6KIbMydIz2Ne9Y8hNAMRhVBrgxUYAnRpMl9teAti8Zi3d4MhZQmVmJtJjvJvEXOJWGtoa0Y1kq4L7o68KyxwumEgymU0cycF0vQYOheGW8KYWJlWVQJ2HnCKQpSjfjcvB/c1ZhDo5r5xLIx4b4EvM6hFczGLLeynR/uq4SRQ922Pfylh6i7ztEFt/vTHlID5ErGK8+KbNzGeOi+D8DvBwAR2YmucG2vjCdnvPO0Y5k3nNcT1jwjhYqb04plzpiXDctpRTrt4BqRz1qdnecd083WbPC2r73U5VVNyDW1jsBrSTiXqQU2QOGJAyl8eBxMdqz6fcZNKhpASkQiwX4IAvrvWPWNTMik/xYO+PJ6QiTBbSqYw/GMVyFURMuIGSIJSazNOwEsQYtzlm16y3EATTas2K1NIIYP1xAQqhm5UPdeTZGRwG1JHKEetIsZrcRJxQKeqc8WVE4WYHwFoMW4bh0ZTS7cAos8Lo6pAORK9v6+6+Mi6I6yZA/AxSCFoxjjcQgYoYg65N9ZWLNoEcxBzYJeJDr4Vew1gIMCIaeo557IlvOiarJE2uUiQCGo1Whar7JgrXKYnMKQVTorJBj2/FCk0fUADG2QqBVzYzT5NHTl5L0GARjGrB8aJ+ts0MfOSl9rlLCBfDtOhg77+N+JwqPzelAePjfYQeg6xvsBAopPYfwvRPSjUA7vrwfw3wOAyZU/aDw5402pWoDVqlctEdOcW8CdbrZmcJNmlUEisL72mTeAENavfqTFt1gQKAFQeKGYMcjO8bBsJwq9AGHdg10dx+g0Lu8pNQVpZuJ5OG/jKdRMQnMkxeKier8CWK1dj/tR9P0wxgOoyX5HW0hdamrxrSLYDduDruPfzm4AOu0uBLYGlwEk3Hi/Os/o57z/GAfGLIREjM0Ke7MF8o1DU71lE2lohtjhEzfSyUCj63gwThdww+W4hBn0F/cC21jcUWbDY18IgvcOu8jK3pGDVTAiggVeIAphrYwpqOCh2uqASYuJzGQFSGsrVAPEMN7dzsfrErFXld0+VMLrrPhxZu6UOz3xXQQyBLHMwEOteswsC64Di6SKkjoDxBrAcmMFLSYRjsTgQLiZCohgtLaANbIxcggpdP+YQN0EaWSOFOFDgXI8X98M4+0Z77MMvL8DwL8E4LsB/CMi8mDP/50AfvRDNvAx6GSMac6IU9YZKghiqphuV4RYMb18QLxbUe9PyG9uEBIjnjbQVBDvVpRXd4ipIs4ZKVYs8w6W0PwW3GnfA97Y5SJbDzUvtk3muzuFenAhc9x3vOYEPWvQ79FMJLNGpsa+sPc7SZ9oKEQNx8I9YD3JY8tQvB+XV8pHLvNYjPPHHoxDrKqfZ6eNqVwUh+zVsmmSVuAr2bjPolm7F3bYoBr3xyXRNjr+2/QYXGRE4w0LpyI9LpZdBt8xeI5ZrwwZ2Pi39277EEJT24b9L0DNjx64YKEIRsBEbkxjvhWsHiJeYFNc+vhdaw3N3eu+EL62SytWXU44TteqAybOIk3A0MUmflxHHLp3a4nGCpqishp2s62MgXGK2QQdCXOs+MxE2GoAcFQr+nGLwykpwg0r1+NtmO7FeXN8Pzkm/N6j/ys4hLQzx+XTzzDwisgZKkO+fP6nAfz0h2zjaYE3GF0sVMx3Z237QoK4ZKQXDwAJ4t0KuqmgqYCmgjAXhBcb6KTbiHzGbGbmn/3cV/Hm1UsQCVYzPRkt9hpVDUZarxHnkpp5SbJlfUDHZJO95pDEZcAdWxFVERTuGTNDuZetnY9lzcCg06dujENk4pEWUI4XSfMBRs9sD9JjAOBuN9l8IxB6T7jgwVFaVX7sKHs37Y0S55+PgfG1fcZdqnhdEuagASkkzcruW791FSWMcENFz/JGuGAMtu794OeFRQy/DY+C7Ij7RgqoFiQaOwCEgmOmfG2EQegs7dv93GjRyYUMSzSfZdFs1lcyPrSppl4Ta6WGnfYGotKKfHoeu+fEcWLWvYjUpxs917DfC3ML0+vKVyVLyu0am1NBNlXkjReioY5rGys9rgqwRGPjWLa71n78g2X5vRAoDdK5pPcpS+SxK92nPYRVmfro+WdYXCOi3wLgu0Tk37O/fwbAt9nLv0tE/ov3beNJgVdEO7i6ZePps2+QblfEmw3xxVlbZ3PQ9X0ShJsdFBikEh4AQLjLSNtZ7R+FcFPUnSnes3qQcs94lWLTl/OA+7PKoZV1NMvAOVYs1Kv6D3WkFdlBG35PZc16uQXqXlAT59Ja8A0A4lgUsUJXp/E4Wf/xMQMcN6XWm20cAVqUG7Njr7ynluVy4wFrthMRxHpxGeSh3RCUJ6zkfcHL1GlFp6g355uimOZ9IeODMpyQ6FmTL2OvBV8elrj62+mQPgU6Gp8LlLWgv0ODr/deO2K9fAiwPhTnrZbtetYryFIxIyidK0rL8P2cF4uUThdXYURovNgHC7qFtTiWmRX7Hs8feqZ4b7TNzwQVAm92TEQEYdDqeibsXhr+ksITCpndb6eDGEcLqxFLLMgcu7E/dIUzB7Lzod4cGzqdrx+//j3tuYtVzc6sjJZHR/nTHSLhLRnvMyTyageK3zb8vQD4+6AS4p8A8I0NvMwaeIEeUBTDFfCewKYmC5bpCpuheS6aKd7toBMQPzq3GS6vM/j1C9vmY/lmbkHTvg9HOS3gjmmCk6gB9Wy93+5DBKByUv/EmI0o3iaPlqEedIMHTdLArp9/rMYbR3u9BRZvrqm0obHxoI8KQq1+PG3/LgQoroDzjhqNElXFMjf1m8iWUWfR6vxNUs/hRMASGYGAOQJf291zmJBqwMZiktzjvjXMd1CrTXTsSuzb8TFmvQ4r1CtM+DGrVNz3cdD1EuX4mgffAg0kup/qfzHyajc2yW1VnDSRYv9uJdkcvkSDbh4yXTX7OYo/zqbm+Yw5MLAIlhAai2ZOhFPs6sIY+nykmCzhziCG8zZhChWL0S9HGbvuW2xNZV0u7tdy46UPx/RSuVYx1EjQs94Iahn9cxrCJpi6fP7Kc89gzCLy14a//6z5QnyFiO4+ZANPCryVI758/xIfVZX93q0LtvWEu8++QojclgphKg2GCFNBWDRTCG8q4oszwssdYckIi3rxRguURGp5d+msLwLjKXYjZ6DjaJG0Q4OISntPkZGFsFfd1thzrKm9qDeG9FvLoYTL0eGGy+ePDTy9pZEHR5elVhyZGaNTmh5XutgmTHxBSFQ7A+JCYOKfc77yuUYrDCqdqogGlmVQCN5GxloJd4lxXxxnBiYQchVMITR6mRvX6LGjlmFlOQZNbxt5eTOPeO+14TADcMR/39q6qGW7He/NUkEMPABgBMzBDITaJG6TrPj51316nfW1KqqCu2RZjBPJuDcTktEDNdPNoiuKJRBuokICL5NDUboyGFcyiynW1pLwhmdrIMCt2wSA1vECsPPleD0dFWo+sVUcA2lAh8g06XcRCPWVhnTJ+LMY/Lbi2rPMeL9l/ENEfufw57fhA8aTAm+RgFfbgrUk3KSMb7WLeDHubi2ptUWJqQBBkOaMdNpR1lmLcOuCOXwVkhPAhNpasvRltUMJY9AFLnmfrkqjQTkUcZeUXnVflIC+sxcb+r9jYeIgDrCbNRhW7EUt7ZpsmTSkqY8mM39PJg3lFnB7o83x2vaAC6B1KBhHb0mOxtY4GPpAnxeDYArHBlsciniiQpDJmCGZNMDcRjZHr4Bz0YktQHFdVYJ5pncMmUrG5xZoD0GXCPkduk6HJy4lrRGEDEayf3W7PbBe/qv/E7BJMAIIxR5HKG6Z2fDU0D2JwbZ6uUIt3Cuw8VCUGpft0rt2+LPfSi+GYywtg0zUFZFzECyR1Z5S7G/jiL+YdgDAVpKtUmJbpQBo94532pgDIwVg4oCvMQHo6jqWHlQB4DNxxtfrbr9jOHfGHpnQ4aJrq49Pe4hcx3Of09wwjJ8hot8hIj8+PklEP4i/EZJhtS2csFvLdrwB7m7OEAnYtxn7tqBWlbkma+Q3TRnxfMK2LkipYN5mUKxAENR1Bmd1GnOvVK0eO87av/vaSVEPYL0Ii3ijx4AaBQ+D0UnwmxD2b7DKumV2HatU6GGJFadYVeVkvMspVOXWjq3FB9gh19g8G3zSGN+nPsC9aHhsy2KB1Z+DQRXUA/D4GXWoSijVqEdV9fwezKcgZhJEbULxySYz4XUJWAeasstvFVZw20XBxp2zCtHla8TxPKiwgA7L3jF7ZdGiWza6k1PMxIJ3aVlbfQQntONnwTcZO7qAD4F0k6oqMtvnyMCrTJiDelfMQUUeIloPCNQ7I+8GsYwFp0ShBeHL+94nkmr7f+n2FTwAR27duGfjmYsQXu1aZd5Zg+4qx64WUwg4Q1s/zbGicDCzfYEU9weWAyyi2zsG08vVh0MPrmx7bkM4NM/tcXhX73cNIvo1AP4jAH8TdN75D0Xk3yGifwNK/fqSvfV3i8ifsM98kvbu/wqA/4qI/mloS3cA+HuhWO8/8SG/94mB1ziu0F5RAYIvff2z6kPrPcuMo5pCxbJsrQV6LgnzlNXEfJ8w3ajvAlmhTpfRhrmO3/kB+yXoWYAWjPxitMx4eC9Bl5Yx2U0CDUqnyDgFxm0q+MyyYQ6lCSJSqHDjn+omN6Idix1SGJf9uk+dleGtuvtv6sY+BLXUHOEHhUAsM6SB0+v47dBTLktvBe5L24YD2/5NoWPU5xqaqctNBBCBG6NiCQajbO4NNscD7ZjvFALOtbZg3B3LemAdl8IefIFefIuAiSN6cPUxZroA8IIWFGE8wFVvnqXq67sQhM0UvgTUAPgPIGjnYpBOWqPrmEIGXTU3ijxGR7XRTQ1QIcdCPSiM3X0D9Hgnz14DY+OAzLNltNzgIS/2ZXbBhGO8c1txefuhETPOFmgdqnkjG4JKS4ZJYzxG0c5VeBSUn8MQfpuA4oMw3gLgXxWRnyOilwB+loj+pL3+E5HXAAAgAElEQVT2YyJy4NZ+0vbuIvJFaKuf77NtAMAfF5E/80E/Fk9lNcAvloiJBFuMeG3VWS/2uOduCIytdBNzX0bdnDd89PI17ogRX5wBwFpvWyEE5j8LXb6hFaYej7FFtVN7tqqBtHiRxV+jnvlGGtrLRMFdqvhoyjjFituUcYpZ1UUDtlrsd40FMoIcMtzRf0FPUPf49Wx0dHUDjNFgWUvzIkDPUP3YulfFaApUmQ6TlMMGwMB/JjXZuUsVr3JqYooFoqouuByVcF/0e9kYHn4cxwnfKVVlyPra91tGO2K03WSmF9HGAp4HAs94CyqSMaY9A/bgugQV1+yDc4pnfRmMSS2MHrES/F9v1+PXS1sFSJc8e0bu2742tKnnkSFzOaqo2VEhAVlbeiJBrRGI3WPDZdy+T7sxeiLhQKVk23f/zorjJOfH6bJA6cfO3+MTHV1MJJ/2ELme8X5I4LVOwt5N+LX1PrvaHdjGJ2rvTkT/NoD/CcBPPyXYjuOJdDITHIAgQRqn1oPQnGrvxltSCyiOd55ixl6SmucsO8JWsZ1PqHZhahGgX5DO16xQhoFzJFmcsynKjLCoXCwQe6br22Hoxe3Bewr6/BQ06N7GirtUcJsyFjP7mVPpxu12QYwWmCyESwOPEQ7wrJYsQDZWg3RcDgBA0nDaMQsOIiDhA3YLdD6x048iWClapEcrwjjPDpuYpFpPRMIc2YpQ2kwSAN7k2CAZ/w9QqCZpdejQxFKDde08V6BBCoxewDmuXHoWpvmXBsvaMNsedAuqFYg861XDnG+NC4AZX+FyyEQVehBsErAgoogb/zhur+bwS3R8nZpp/PqBxZuR7eCf2KXiFNJB7QeoepBLN1DSCV6zX4TeFt5hiEgEhhrjNBolW6LDGqTdF6KI0iA3MzEQSMO6E46By4OuHqvj79QA/YxCL+NdPN73tnf3QUTfDe1G8TMAvhfA7ySifxbA/wzNir+KT97e/RehDS5/v5kO/TQsEAP4SyLvB9GfLBn2mZoZiLUXkIiAkDtJXBkGAZt1hggA9hjxGVqx7jNeff0jCAeUrOY45zw3Cz3AgpOlvB5svdAWW9D0m4jwxZX6e6RTmdxIW2/2I248t0aShHNJmELFrfkobHlC5mjbG+GDY+Ak6qY5l0GXxdoVeQblcAKoMSI0gB8xbA22emxzSYjz3l3NKh1w5t1MtWf7HXHAju9SMbgBeF0mM4MXvEydmuZ4r2eAnlUp/QxITNhYMBFhHw7eZLzcKkrWrxAsREgI8PZVBYJkgbip5Pw6GgKBF83GghkbJul28BkFVWacQsCviS+wseCX6xllCC5n7IiygLh3kCgG3RRRpgOg/r07q8+C78Ulq8Iz80v1l9h3RROL+O+K5D30zMimmo8w6XdliThFxsvQHfW6TJzwUMMB53f/3Z014O4GAW0VuK8V2bL+Q9FwKEaOx7Yfz9GM/nkhvSyh9Z47PK/Pvbe9OwAQ0QsA/yWAf1lEXhHRvw/gh6Gn7YcB/AEA/xyuL1bkHc8fnxD5gwD+oH3nd0ID/PdAsd9vB/DR+/b1iVCDZ7wAgsouAwliTW2mvjV6jEt/s3RbRO2aO+FmSrhhPdDn9YRtn7GXqJJX0puBCKqPb05QAqG+w5NlbHvV2zORqpT8cjoYtmCknlngJjSMzfHZU43YSmr0Hg+oI/UrkGNufsNZJjcEXTe2qRZ0+3tgngZksqOLgGwsDu3irKuIKgG7kem7Fafmjer/IAArnQ2wSQDagPNmKhABXu1mVmRFntlkyv/v+WTHry+7/Ti5zJhImul6JG1dlIcAPIdg5u2ClQtmiodbutgNH2BOYwAmKOB6LXj43wXcgnB73oLgxp0KdRkwdwvgWQSBFdvdLQiOXZtZYM5tHpgcqjnWGAIIdzHiddUs+2iHKRdFRW1HVFiLegFQjjsIyfeTBBMxQkC7P9ysJ5Ji1Rpoe3FYndO0LVIWwRvObUVweYyOWS4uXpO3vvZpD+WkXymuXXnu2iCiCRp0/4iI/JRuU/768PqPA/hj9ucnau9u2yMAvwEacL8X6tPwiwD+4w/Z3ycH3sY4YI0b0WYpV5t9bVeDFm/450yBsWimLmcZtSgLoHDUlur2egCUeEmWwVLPqhfnB9t2HPecgmYyup8Dhki9Esy2ZPNCSKdTaXAc29J7R4wRpwXGPMGPQ8dcAReBdOkz7JiNHgpxCOTH9+i2igQkcINq1jwhRT5mxdDVBRGACBRjkwQqzScCAM51QhEVXEzQavkSKlbzCSASzJFwR9wktpl1pfBQgCCEKK5oCwP1qhd4+tHQ5be+3s9BBR/CQ4Ya3ly+z0cBY8GEDbkF5Y/ohEgKDXyJHx59xseO4mkpEiltSwUSdu4NUnGjILZ9OO5jQEQvtO1M+Nw04ZdzvlpE3JmRasA9CDcJYOqwWIQb5OgKRLtS6GSJAFRrS3+TKrjEwVQJ7b/dgu7GjFV6tgvwALV0/+O3jaPK7XkFX2U1XCmuXevDdjEsCP4hAL8gIv/W8Px3Gv4LKDTwBXv8idq7W+HuIwB/EQpZ/Jsi8gsf+luBp0INgtZaGiBk56SG3nK6iC7932S9oJK13kbwQAnMsYBZ273nPLWKvG4VdmFaoLPikHhwJPWjZSGs7utgN1UiL5SMwfWYoXiIyAIQEyjAcLZjsNXP2oUwYrkjTQxqGgTgAEn4a4JeFGT7rLMhfAXQCnVktzIJFtJVQyRuhvBcOgfYB0EnitGdLIWK2TrZlhpwxoTFYArnIpeqDUEBWFt05fwylPWw1oC9Ahx7q50J1PqM6fJXxRYrV1RRnNnNzB0LTiBsKFcZC/lKawEPHMmO3hhMzlLwEhFv+Pi5kUHRGA7QbH0yH4xbhOab66l9EZ8k/Xs6u6Ltj107Z66tE8LBYc0m9Y2VKhcDQJZde8Kh0m2llgW7LlYTuviYAqtKMvkqzFgMBGzSO0fXK8HyEkq49txlkO2TxvMZb1OuXXvuyvheAP8MgJ8nor9oz/1uAP8UEf090Kn4fwfwgwDwDWjv/lcA/N3QgP0VAF8moi+JyJc/ZGeBj8FqKOKPYYEkIgVp+Gvm7oswBdKJnQJiqEik7kyFI9ZtwcO+tLbplTvc70s0kcGkxlupAy3j9Y6rLo91SKEv6XumDHTxhN6EenH70nM2RoOLFmTAaUeoYey8waSQwhTqkB3rRDCqj/xzxSrdMfTg5LxlXdLrMqJIwC1xY3U4dMPt2NNhf1w9F0iQTNQBAJUCTrE0PBlA4/76OEXBjSkHdXsTAMZEhDkCD4XwIikv2qXbVYAMldl6V4lNKhaKg1GOGMzQC2TvysaAa3ile/ESNmRknnGiiIcrrPoRWqqoyCA8MOE2pBZkdcXWP7OxrzBcnCGYW9npaOp+5p4Pd9c15fy6peZDATgOqyzRdlQoQA0ESqpKC3beql0TY7FtIsHYSNOz835cdD8TRq6xYdJXMtq3B93nFHbxDgHF+zNeEfmzuI7P/ol3fOZjt3cXkR8EACL6CNpZ+HsA/AtE9G0AviAiP/C+fX4y1CDwSrHegBsuLwzqGScLKlEr6symTWchvDrf4pyntpxmq9RHEhQSQGxJDrRg62qyibzzg32ndGzSJwBfBQcMbAHqvq3+WyIp2V0NTAJi0GxvrxGZ4yGL9e3HICDxDNwzXg2Y7qzm7A7P88pg/uNdLgDgZHSxMNyAvr+VqWXBERp8CXII8hrjCEL6vVSBKVRT1DFupow5FlTRBoqKXev33EZuK4hAmondpIpZyLr4BuO5aub+UIyAL91QfVxReLZLoCYHJhAiojJWGv7oXgv1kShiZCvw8JmIgC9WhRiuNXasF1inQgfOG4bVIPSEVOnXrMIMchG00IKvD/9Ox4A9451IRQ+aoVKjLArUQWyG+gLjYvspMLgq4LKLefkSHYKv20FqzUM7TmzIAxPkelBiPKaa+f4/x6ALKJ2sXhFLVPmgjPfTGhtUrX62x98FmJHHe8aTWQ1AZw44d7bIY1W+F6FEBDfRMzwNSKsFAA8gKlAA7qZsqjhzBDsUtQTebHMKjGyeBCyjI9VjVY7fRL5P/p8v5QA1yb4fgmEMYkIJOpz4BoeIX/R6eWcOLehefjeAHoxbltPfMxFBzHPXPXPnWNuEBFin4bFV0HAeMkfNiA2ucUreHF39JkAI4GoNSAMBHNT4xwptMTDORU12XHihnXUYicgaa5JNVO7rS831jBEwtoP1JfHoxQDgIvv14OpL/A4rXMvWHMtsv729p0MEhWozNgKAgoosjN0pjgLcpWNvNAA4Yx+yRjZucb9u/Or2icYZMno+CHOgZknpwbfvtxsxwSiTaM0szzVaNm6QlP3cjV12rtd0c07z30yipu/vhB4ec3qfY8D1wfLNY5JDRD8GzXL/dijO+9MA/gMAPyAiX/uQbXyswAt0s2cPwEAPZCkMz4W+rFLa1tRUV4BmZ0sQBGJQKvCW7H6zOAfVOalzrFitGwVDMefdikHV+LujLwMwUtA6qyHZTdCzd2rL9XNODSo4Vrg75xaAYctqQC7DDTQuj7R4qNnudmFO7r7C3s49kvavm2OHLnyM5jt6/MksBgnZUNFo7W4cM9b3hZY5O8a714jEESfL3l/nCQ81Yq/dN+Bg6yjdUMY9AgRKMUtEbYYZzXKqcPPZLaiYkNqNPyEhoxwKQz48cDgGfIMF97QC8jhbO9KmdNXAPjGJhvg3ol4HWhjsMABgKx7DlDWPrG0JH0A4TtrqcXBpDhTsPROpA5pe092dzDPY2fjU2ZpvZtEJ7dKu1NvLu12lcncFuxXVAghJ3l3pF4N4DsdmwNmvucB92kOY3kUne27jr0K7Cv+FARt+0ng6j5d7o79LzKxasCvDFSuiM/gcldd7zqnp1KfA4Eh4uWx4saxdiivAL2+nhl+q2opxigVrTXiTJzyU2AjnwDEg+D51+W0fp6j83cluCocvnPJ1n+eDyowHNsYYdMlYECLdEAf2s9tnLBAQPPt/rMBzqahuH1is55q3NfJj6EW9atm1thoaOMIgM1Ybb7ijb4QH7TlWnAzyuc+6MppIsNtx9CWu76+3iXd2yBw0wFZWnFQ7NAQQEXbDfUEBLIxsy+KMgoSIMBTO+n52tZtnl4UqkkRscHPwY9DgR0cSPegCyJQxyYSNMr7OhBeyAND9vY3OxOGBhdG3f80MCFAv4SIVTjubYBS7IeDOVli7S9z45l5oEyHtMgKXLmvS0Lwy2vWkVLIiKiEeTXx8fyoqImJT/L1LxTYG2mOh8/lkwIIAvgIrXHvu0x4i8u9+0m08OfC690GkjqMC/RTyGHwBlMF0+b4knA1iyEKt2i7GJsj22hwrbmNpWefUjGoYD+Y7u7MyKVrnVYcaLKtRcxcxOESXg8my3SUornsyRdFiTSJ3jloMwZDpwJRDXnmGBh+nnrkBeTUs1rNSMpzag93GPYgWIcv/qLWcT0Fao0oACKayctWbj7X2U3YZepTGV1u9ulpVX/vZHeGKyZpkiqBNbFVimyA227hTy2Dn/CaS8Ur9Oc36BeoONlk3BMDVab6vjzPVjNokwyM7oVBt0EESHOCDcXigPWS6tv2I1LaTUfFKVrV05GgwlvVmAwyDPgZgQK8bFYHoX+414RQ0//0ONajnhzQPEIXKfOKKmKNe84kEZzv2e7XrgQRJqNUeqgVdF2m4ys/Tq2sZ7SX88jYv4+c43urH+wF0sm/G8bGLawQNsG6uMr7HsV/AFDdMuC9R3cMEmKMuvYCAaJLc/HBrBZ4JIor3Ah3T9Mp+NTw02gp3Z8JWe9sW/X5p++l7lYgsI+nyzTkybq0duvNuW9sf2G8YskWHA2JQ/NTFHtF6v/FwkbgZudgk4wFX94vafkEIyUxs1A+4/2bnBHtmOxbtmtYfmk1lIbWBjEdj7THoFpvIElQgotsMZg6u7BRHxcsQBPxca8FHz+8pEnYWkHgxkBAj6XlgRpbuC+Ay4B0FaQgCl4Yul3aQwDGLVdn4+wPHmNW5QUxGQQUjyaITumgHi4pjoB0fd1ijwwy6zb5PaagZAGrSFEgFOqdIWIyu5xCUQkRWZGVS+Am2yqjelLTDdhszijwWkwCPC4pv6+Dxtuef03jUEsvGtef+/zCenPGOjfwIR6hhHF7sDqQtVlYe2A5Q1sBN0mzz1bY0lZXjlkTAKRUEgQVFdUObTHU1jjJkvYBPDpYNuR8sdX+G2QKdsyW83VAwzjDs+WrBx7PXsemkU7jczIRFjcuz3YJaOBl7tsGKdRosixB2KONjhlwEZOM8X1DTxhvXLR/TAGWEWFEkYOfU2oxPoZrB/CjoUJaBq9x8MnuZGK+8iwg57c4LpbDfDsxJIZu1apC5z8fsO1AAsYBYmQ4eNBTv7Zju24o9SSIKVVQUAAmzTNhoA8j2bThOGlTioVuIZsA909towyQT3OtMj/8R2pgQUeDB1ZkU5tGBI1MA0GKfQHnjWyVk0knJrSijZdTEhCWoiGIKjCLa3XitWuQTGDe69lrEaNjvrYXeNtrvfUdw1VXV88x0fYh8U2G8bRDRt0BVcC2WisjPvf0TOp4ceF3Pv9ZesPLlvnNTgb5Ur6JZwFjU2izgiAXVtabWrseXxrl6JVov9N2MdNaqcIBnk0Dn77qRiz/nxt7RaWS2BPTOwswAD2wGxew82+wdhsdSxhQYNyk3E3RAf7/7rdYasBl0Uji0qvWoUOvLxY5NO8Ti2w8kCCIoIWC1YDgGXW3xQ61luWfJOwfUPNn29fPRYAU3++liC33e/y4cMJtZ+kRKb1KWRT+XD3Yu5yC4jYpD3sReFNLfDVT7/CRj9qm+u3IlQDgjoQcQxy71s3TxGbUH0uzes+IksQWYJPEIP9jjs+wqJSZ3MtNMu1hoDfY/tr8jjhm6B19/NrNKuxWj9XPc6Wq+4plEOb331lJe2zcptdFx372qz65S1XTlplCOcqMvhSiX422vXYNqAsKlx9OnOhxuvPb8cx1E9MMAfjuA/w194S8Avu99n32ycg3oWWu5mIjHv/0SIOm4rxbfFH9d0IUNHhQ8+G5mw5jzdAiktWozTO2gEKxho6l6RPX7TA4NWPsaOIZpLlW2vFuCQgbqwKUZcUwV3fuUO1ZrYyLG3bTjlAqSMQ9yTSjWwJKM7uZLSSfRexsjXy04DBKonwBvnLkk9QEeMdlA0gKuoBfqAPXLUI4zYSc5THw6iZR2jH25WzggBcZCVbmogbGakGUJjDWoeHkSwpw0W9utkOkY5m3i5vGbhfBQAtZKWCIAqCn5RIRMAUEcPiAAEZnMo6HBJf56bNmZGE5bLQ8NCKgo0DKeFZUss/VttQBvWaBjv5NMOIczkiTjDXfKW4HCDWopebygFUAiBJswfF/1ccTJ8O1Aei077KDH2ymLvXC7GovBr0uHFDwhgD23cgWLntMs2v1jRmqFRh963B5DEJfY9/hve134WperT228NeN9xoEXwPcD+HUisj/1gx+bTubj0hHMRyO5D4HGs2XnPDqVaucAsqKRY5kevCZb8geS1o/NPQU2L64NOLOYJaBuS/8usAp81T3TfmvkcnlIAKZh3wWPKWGzdQRIhud2b15qLmZVgrUOdx6yBs2tdGtIsX0ZTa9Eut2kj2rwRxGFAbIdr/EYeJCNcGoftZWBi09mENaaDNMdfTOsX5xBDg67+IXuwhKVEruU2cyLnM9MJjU203SBBp9KSq9i0gLbhIDzQPq/zMAOcmIhFOqFLgYjU8ZJTqhk8uMhw3VhRnBYwIMujrzeSWZk2jHJZIG2y5Ydaw6gxhTo14KY7Fm30y0rqRUWT1G7Xbgz2Rh822+8CHKt/ZBRIIn6NeGtlrKor0W2fPwyox0pdFePKfUJbXzdP/OcYto3Kcb7BQCfBfDFp37wSYHXbzQlz+PA7QQuA8qIsXb6mQdhJ4hvtpSKJOBInfcqvcGfu4e5U/+5anBbraim2cOQ7Q0kdwawDHhbIIACgTzlNFy3u3ONnSD0N9ykgrspYw5FcdqBPlY86BqDIBpjIJIg1qjLzGDCCZskspBZVAqcLROH9MPtATOrY1uT+wo1rq22ENJsHVa8WWvQwp/dWKdYcS4JqxtxAxB73rHyrSaMEKLzp5UXrM9NEISoAfgUuAWW7g2shcqThCaqyAJEUZ7v7tfHkJEmUcUaUw8oTiFLEpHJu4XpWGltjxnccODLLNcfQ/p7AA3Ss9yhUMUuBZMd+AUTMsogzqjD9zwGRdwVLEChrGRwm1PJdEXSPZ8BK5LahJ8NpkgWpCMBCLpa1OxZOxcLqwxb83Fpk8G1IHuZ2ep+DkyGi2Pjq4HnNN4WeJ85xvt7AfwFIvoCYC2oAYjIP/6+Dz4p8AYS3CXBQ1Vj6UB+UUnDKsfVWjScqljlNhEQo1OqFN/qxSf94GaZXjUPBoCaFaW2RunGLZqZdsWa+6e2x7ZtN+n2myFR51aeojSGgzMXtPGmZoS3seJu0q4UVUJT3PnxcFN0MlpY7zwsmOwCr7G3FC824TBpgcpHmzRImly5cDezYfQVgjTYwoKcmaokUupTIj2eqwV+VQdyozh5w07/Pjb0sgo1tolPpnNTHfZCXuumwN5GXgPuKUjjJc+BUI3jO1FEFsZGuQcAx3JFM7JCKtzNxAc81+GGiAR17VW4waliI7jizwHK411kOQQjzxAB4IyMCsaChNB+oZ+L96/B3a/Xz6fDDFOQQ/GZqPtHF58orb4wBS2cVdEAvkGP22RybNLWhAhgnFHfGlQvH1/j8F7CL89uDPDZ4elnNkFcjD8M4PcB+Hk8Zne+czyxA4WyEwD1Mq3FaVe98tpVQRrApqBBxogBjVeb4EorxzdtyW3ftbMWI9x7IQBGd1IWQ2H1KHVcuVPIrDgGLbYJgJcpHpbx7o+q2JoccFzHdQnAKVYtdEGQWb16XVmnZjrShBRl4CC6Is2D5VpDyyo9IwIcd/WbCUjErXwzDu9z54KGMhQiijFARLSYpW5pAgyFvUiK0c6DZ68fD5UbR1PuiTZZtMfJ4J2x47LDQLtNCjoJBuQ2UaKZERFpcMlCKocestSAnvH288ItmHrA9cAqYCyy4ExnhUWuFOgCQvuOSabOQBhu3ohooVaFEtmmndF0pm+P4BJn3T/BggkTApYQDR/Xc+fn1M319dgCixmfp8Ag2w//yTtrQe4EwQrdVhJdnSUhvEhaSF65okhFFoVGfGXwrgB6tQ3Qcwy4NryofjkqnnXg/fLHFVM8nU7GvuTvy3NX1riAoS2xLIsKrTqLnpkRcArqQ+rFo5NJWk8cmpzSIYlAMMNt17Lrvhy+G0elkUBvlsy6Hyf7/tFQR/81JzJyDwHgNhXMQbnDUqlzdVvGqfQxXdpX8MUF4jP1SCkbPVYdC5yYBijBoAJi7FWLd9EUfrl5MXRBit/s3tYoSGeBeFasDmdd3OHSVfVKVi6y+8OG4M5vXRq9kCCZim6vEQ8mdz0XnQx2Vvx6MxXWQ0GTziq/1ZbWILgXggfHJCMNrB87FUD0xx5AdsqHYBKEANIA7ZnwLW6xScar8BoVBZPMWEy1BqAF2IyMiIBiOO+MBLZl/egZcWlEk1FwS6dBOKFSYUHvXXeXuLneaWFXGu5/a77T52JiFWqOk53DC2WVaB1DDEaz4D9ktdfGIxn1lQnqOY5vUqjhZ4no90L9fUeo4RtLJ/MbfmwYOLIONMOQVrkHeqCbDQO7Td2j9BRZq/e2pHfuLNnrOxNyIWvbjpahCrydirIZnGTevhCwqnCXf3qxC+iBvxUz0It/s6nYIim/V9kBlikOEt02GABiC8jqGEbNWyIAj3ppORbumK/ziKsQtpLUU9dMzrXLBCNxwCwEICFL1IKiuOF2z2T2avLs4aSJ0Z1Og/1jlQARhRwisQpQXaSCwXMiMO7L3I7hbp4Tq7mXebCpApyrHset9t5gvTVOaBeFTnAGvRhfV4tmQ5UUMPXZahBBGDwedGoow6nw6e0VPYDB2LC268EDbzSurn8vCTXKmLMuLoOtB7wKNc9J1q33xmoXVbz422sYVbTjsScZe9UahlBf3XmvwiLepURhOPc+WcUK0wMA/7aM9TIIe3Mpf+2bIfh+kuLaO9q7fw7ATwL4bqgf7/dbzzV8wvbuPn6j/fubh+cE32g6mWNWTq7Hxd/H/rIa/Co0M9kZeDEE3TlIM42JBFSLiu7cJGKYYRAlm0tnJbgrv8uEd6lWTDt2ByjCuAnxoKdXi0CC3+EMQoRPBLWxATYOSCTNiF3btBwvYXJ8VDrFq0qHIryFdxc+6E1VbMLyY+WdJ0SUgRA5NHXcZJ0j5qAuWx3zijiX7pHrRuZiRUdfjTiGezcseQurFwQCUAY2iX42mj2mdbyoRxm1Fgm1yOdy12LnpvpkyPobV2bsrEv1KhrYfIl8ZCJowD1gk61g1LHKIIRoGe4R3+3BJmNHoYJKSr264xf9+6QHe/3MCHN4htpd0BJCe+zMBxWDJAuqx3vDj7mq15y7roIdtZAU/QZyE3xPKLyRqBXg7Bw67eyqAfpbMt/H/nz9uI4FtucmHdYO5lcC74d5NbytvftvB/CnReRHiOjzAD4P4Ic+aXv3ts8i/+DTfmUfT5oKyXBRV9do5inNvq6b0/jyqAeXbPSv1eTDX9oSXuXYMGMW9Txw3utDDc3fQF/Xm3urKt7YzCovizS7vN6JAO1vom7Zl/8/9t42VNuu2+v6jTmP43xZ1/3c7q2yRSjxLYIwDT+kpJHlFwNDo3yLcmtSQRQGQb58MRJqJ2mIRqGhKWWoH2KLiCCCWiSKL/QCfcudCBtf9/Pc17XWeZ7Hccw5+jDGmHMe51rXfV/ree69n2U0b657rXW+Hq9jjvkf//H/O3UnAt2c+kQQ2gVBBxtFqi3zdA+5mloBcPF25/ugu6rh09fyXPuh1MC/8aaPfQYdQTsFTIN1yB3z1mZYDX8AACAASURBVKhgoXZ1zDaF2PHvkpMRHKMAF5l+Ai7b5NjyKJ6DU/TCPkibotpTye5IYbjuU0l8a82skd3TA1C+u5pak4FWbt6yO2Ztke1O6h1pw+UYwfElUZwqlfslNcAqRqdcWRCy/7OAc2ida/uAE1oRQREbfw8cWIegPJHJRIHQP0MGiuTw8VX7ZFU16I+9iNQLb3DIdj3GMQwNjTiObdLybx050J86qicSr33fj8UIjZP7f59Q50RVfziW96r6Hgh791+GFcDwn7/cf2/27qr6NzCvtH/ajSs/V9W/6FnuHx7e04aI/Osi8tEDKCI/Q0R+4Zdt8ytZDUacZ0vNw8r4mkqRrpdQNOy11ZfYvnwqLk+YfJZXIVWYZyvqhDFk7NHFs6qxHfhWXZ/UP/tJ15aNjCL0EYDDersYrdEPjP28FmGV3gV2yCZgktnr3kZBKVgPoTIVkALx+iHDrdqbHW6DcWFY0AdlzI5Ll2M85o3ztDLlym2bWL1wttbcstF1wI2jMWVV10aufRWS6XZJFZoi3EjqVzVXhDJk0yKmDZzEFLgWTSw+SVxKyCuyw4KjzVUc9zbnEdfsVbwNokelwsbMgVV6JprU4IakyQPykSIWJDaJ3rLaXpfVGyykMuuBqpWZAzeujiVPzvUdcGGMSWHCOBG89saRCWFm2ompd1t6x5trJUt2BoJfn5WWkcSVGBDZLK7zrFZcOzjWm6Xrd4SzcFFvO1a7v0gTtcITt74iILGxx7xfynbbPvt4a5lujI9CDa9UJ7uzd/9J4bmmqj8sIt/nL/tO7d1/AkYj+6vAXwX+LnACfibwzwF/D8uuPzpezeMNb7NYVuVkflxL7W4RRisb6VxOIau9gyy6dQ551I4VLp5BRkYYhTz7XT1ztmz3qn3JOAqu3Gupxhh5lbbcl1ZgO0RQjtfSu796i273R9uGi0RVOOWtPRZZbzxn9+TzolhsU9Pkxdp5A2Y4uNLYLRTZvHPP9HH3nllrmGgi7s7c97XrZmhrAonH6pC9NUEijO8bjSuxvwGX2DG3c19rX0k0tkaNQmucD7qPmlqRbHah/t7V9rwddlwSR1YcuG/SPdRgDInKqgtnfWBhae95SSw9/PdGp4u4fh5cPWPsCYsOtjjro+D5KApVXOgmoIe1On3LbTByjqPnhbaMc7NByyjqHxO0OU+Ulq/XXeZrn7an4H3Z+DJZze/mCFjufvhjP11E/srw8O9T1d93/9oX7N0/9nUvPaFf8vj+AcOPfy+G5f4C4GdjLhT/F/BvqOrf/NgXx3glncyJ9V6cOmfHosT4h7e6n3Or70mC5om2BENB4N1U+N7D1nQO/v7t2Cxnbo3VYO9d/QZ/v20U1JevhuNFxjJ+L8BnaXZVMjcipAtUh3SfSSSaIWdU+cN9d052eYbwemSwDDAE/popV85siGel6pnuVq2dtioNkhnVp2KUardOwBfmtlEc4jAsNLatOoUskvLoHKxDkK9OcwhaVyvo0JskZqkGuwitGTUmzjD+jHPdzn8EGz/IIdo9+xtVgCSsJVY7fWkr1KYfa+epB9z74LvJRtLUaGWbbMiQ/UTGC5btxucVb0ee9cD9cnrk8UIXZAcrvK0UZnKvEVDadvUAHWwZW+F90BA+l3acIrGYk91gnW5mrdSbn+s5Vw6xwiuJVaQd45gww8l5nDx2DREtI6+719zvd4x79be3Mj6G8boe7/+tqr/yy97/kr078LfDadhhhOgw+47t3R0P/jP+79XjdRivdH7mIQdhvF94vkGAF9b8X2Q+RZ0fm5QfNxe+77Twbl4pKnyxzlzd4dacbq1IsVbDdZ825VvrZgFXC0/cGHmXJnTyvGgyuk7ECKcK8cJHuAzHz9kZCWDL88j2bL+kaUnU9nnG0z1PK6dcWmeYbZcfF7qYkKIt4xSMnxwc2/frgffrgcd15sN65IvlyOM6s9XEedoIdkbYycSwSSE+PwJiuH4YNvtUsrkf7Ip0NKpTsCRiX0e2xOS/z75sFun7Fsd4TsHdxfWPo602da6sRIioLVO7XwpXqS1bBS+++ejFt7Qrsj3JByadeNDPbJs4NMZu/xzdMSrG1uCYxGcmNkz/tqKO6A61huHaUoIyCVs1TnlOtG62eI1dN/HTJs3sFLPgQD8V05iu2DW/qrZEZh1MDj6lmPaxx5/LZb6dodon+/t/XzU+Zu+O0by+33//fuAHh8d/tYgcReSn0e3dfxh4LyI/3z/z1w7v+VrHq3m8c1JOVGbvsHlsdC+7sjbvHgO7SEWNr2FBN3HKcJ60NUNcton368S1msjKtdisf3UdhmuxRolvbivFizQ90x0cKNjbdJ+Ymc04rGWERyeHhqDJIVlh7cEZDaHSFcW3qwvgRHYbQSlamFFh8065aBm2Y1S5lOy6BfZZsUTvbgK90yloZ6PcoyZB1LrDFi96ZYcKAERNbOiQ1Ohqw1J/FGu5FoEMuQp5UHybphDP8TCUKjWEeNQobFtNQ5jxideLfsdkwSF7ZhZFoVO2LPmL1ZbidY01D3zQbs1udLCNo578eetOm9QCb3/uOTd1HBGo43pIKhw5tW639rphEmkuF4xOxh2/faK3J5skT6clrli7cfbJKtyqETu3tyLU1LHdeC4YDuG7tvi5CH51rBxCZH6k4sW2Vukm9ve8508dY/B9S/0UH4caPuntH7N3/wHgj4nIbwD+JvArAL4Ge/fveLw68D75Tb7VvY2NYIH4ijp31EYsy5SODSf/fa2Jq7tJLEW4bNKYDLdisMTjVrnWStHKhdUEQ2SvQWqfbxBNRTkzc065Z1zJgu4pKVOCY1IO2eCFs2eo35gXjtPm2gjwuM4Ne41gGwI+4zLBGARd2rIrk9mEtA53SMAM0AWDeju0OhQTk4W0YBvwhgarwc0+Z1GKa71GUebekimLab3ioWNO1pFWVXgqk9HVpDquK41Hbe/VdjNE22v14tBShUPSIaAYh3iWLhVZVAwyKr1oNWlmkY5XJhXT2gXwQpm91jJZs+/xoHoHUYBlw0c9WXBjcvrf1D472BHQKWqrbM237J6q9dR58O269i3j4LdLYzn49TVJn3jUmTmj8tiUOrwWdDFgJxgVlj+3MtQzYsUI7j7hk6X/bDCN3AVe7cfP9mGP63ZM+KuzyR+rUceEZnz8ExwovsTeHeAXf+Q937a9+9cxXhV4w8bEupWsyj0yDsLyxYKtQwwS0pB3+K/iWa5plIba2AcX1S6qPG7KUylc1LLcmyz9opHOSwzcsKK848BBMoeUOOa+DD44ZeedyxmeJwu4x1R5N60t6F63yVtwpQXQEt5Y7MXcs5iAzyrdul1boArmQC+YxLEZx6Z2HA8OTWztpuzZcxTrEtYEEaP4zToafNqb+9L/lHuRU337Nl/iiigPftPmpEwY1BL2QyvsOofC+SOptcKuKs1B+qn0bD20eYM6JyLUGpl+l3zc2LikC8FAeInuNQbO6E6DTimL4DProX029CD80oigO37XiPfC/bLcPmdh48yBLB3ACElI6EG6sUqkQzTx+q0xX6Ko2lknHSaKbkvl5iaXmxQ2GbZPPxJ0Xxhxz4xFuJ7Dv40Rbij3o7wxLHocInIE/hXgp7IXQv9Pvuq9r+5cs+zP2AaRlS5VuQ5rgk2rKefTPdBgDyhXYHVd3dUzv6XCU9F24b0vKyuVC7ddh1P7DDHZlAjA7zhwShNzwxZ7m/Ja3YgQdRF2p6+4vXnR9Mzostxzev17exXbltVrsB5K1zyYU2VOiTQUoYCGd0dAXqsFqqUmjrm0pT7tuwLKENe66II3Fujt37X0NuRxmOmiNpEeYz/YPr27w6LN1t00h4O+Vly7d3WvMqNAWTA3a3jlsiVfWiuhNRgNALMINxx+GuJgnMtJJ6OKOY1s1N2N19n2GfwwYr/xeIxY/TzJB876sAsycb3EtTLitonEzRsuIiuulBago9gWGW94r0ULe5xLm5i66H/7/OH3pY6wlWV0xn6wv5fSi7CrB90bK6NAkO/As+Pwkg/bOMbga/v2dkJvYLzPH3872/jC+EHgWxil7PYVr92NV4vkRP9/rZFB2XOCLbkCM4slUnIGwlmiMt8LC1dvkrgWaayFa6ncnCoWF11fivbRRbHt4sokZudVHlJqmW4asg8l2netgJalq2xtmnZdW3N8T2Cuw3fHBWI3nd3u1xImil3lK7LREDC3bRHWWukNJ3Yr3aplILHkBMP/Rq2HcQQMUel4+FL7jQ9OyBfl3VSsBXvAFQ+pcp42m3SqLUwRP181N15lqJuF23NHbGkuywE3FA/wpgLXb5i11jbhtOLa0AQRWrlRVIssLqhjEMUiy/LCEkg9040st+P99l+mu0n062R0hE4u2lN6wH0hS37gyOzt52bp44VXV3CqYmJAOURzpF97cRim5rhi91C0l+P3gmrneSvKTatr8RZWWVu2e7+v43gp+MYxjccnnZn9GLylkPYVdLK3Ov4RVf0l384bX53xPhN0jg/ywHZIibWYrpQOi5uq+zdGd9VWO1VsqboLuiuFm9z2yym1b70nxc/0TNeYFtJugFjyCUGVAkm6q9qHClpRgWqesyZ5GJ1HY7CN743mBSGFbq6ai8P9jSEE5Uvb5wRXOTLaK6n9bRtlF2M4PZjJZOcYB583nisVPEkjiWHaoRnRmArgMpjF8h8vpNnJ7DzkYHJMYkLygUUm7YI7MQL7rd48Qe3B3wqZ4p1upsN7Sz27jeyreJC0gphBSiuLNVeIaSWkF5aim2wc9NCyOQDzmegc3rFd1p435+ERxriXVHxJrzYmnVkSZeCpd1fhfRcb2HU1e1Ftqam5b1fPklN13Q6VXWZcVVnYuMnNm0cqm68SAr+9n5JH3Pt+JDWR9wMT0VLylkKa8g9l4P1fReSfVNX/47VvfLVWA9BEayB4nwJYtpV8WVZcXNoucuVDEb6hUUgL0Rhc1cqKaY+b6S5cWCh3M/2zjVC/2DVzZOYsE+EGcEzCeXKqW+ss2+Nux6Sc3WE48KVoV45leQTi5rJBvxCqWpEOf+yp9C6xRGo30uzNEONlbhzQSpbESYXHLVl2Wi1zjGAqWBFz8YB2SOpFOzt+IV8Z2yPi/NrUl7rHoMulSt6mpjEc7AhVQdyqXgQu68RTmRxSSm2fGgSTukzQqtYCHsdtKb1x5JSDySEmy1mEUpSLNzYI0Z2WfeI8sLJQPeiCc3lJJE3cxDrd4rVxHO1npcrWst97PHPWic/FGBJ/nw/oXQPCmCmGlsTst8bkXIdEp8fNvmoRX121z2mrv35tHLJvZ5WG50cCUxSKr1CiVmIt+EZnW8X4y3Yvbc+29z74jlBEZPqKdfOZnOXkE4fpl3xJg8GP+YiV4fPH3842vjB+IfDrRORvYFCDLVpVf/ZXvfGVnWvKMRlXN4pAQc43+cH+2o3KTRZu2MX8AeX9OnFInReZxDzTDGJQPpSND9x4TI/Nawv6TB43a++i90yXxCElTjlxTMK7Gc5Zecg9MFpDgtHHQqkrMr2l5G6i6UFvc33ZOPHtJte+m6tao0IUXs3yxn5Xd/Bda2g99GNjRUezQr8WEwF6v6Y2UVyHjNFcJgzage4yEdoQcwqheW1SnZFNTx50D7lwTIV5KKRVFRZvzMi1erOIORqHLnKhQxon73i7Oo59TJVbNQ2H613QncVWFO8mIQX2XPYYv53BQ8NTG5YrtbESei+kZbFxzoHWNtw+T0f8MtgH9vxVrnymR66sVKkssvdws/PrS3gJSyFjyAjCQTJzSsxik3pOUDU3AXTjt3dNEGWvW1FUuFa7FnrLOO18VS+Mmg6JsXisc27b47ovjHvmQjxW28/a8PSMNAjIkqS3E9SUlzm79yvsNzb+xW/3ja/TasC6zQ5ZeOeCN09bF2OxYpsQYjXRcXQTOOsD/6DcOKxnkkgrxq0VnkrlWgvf0gvfTD/SupbsO8fqclxA9txRbSY/pYlTShySSSIKITyinIZlvznBmqX8KVsg2gbRm3jN5svmaECIMbITwGfpQYWqqCDJHCFCJnLV3pYcRodRuU5EYdK+55QhHJFj2L54oM3GsJicQlYcahglGC2bEo7ZXhP+ayHYvpTMskmrrieMV71pagabTX8il4ZbH3MxXu8AfYBpDqxqx/1AZPfGcriUfZZv51PuAutAd/ICW4jdxLj/O4LuiAfHuMoTQOtmi2topfJBnnaBNnDg+0YO00Ewju9MYk42oR9SD7xC90uLRqLgT08SK6IObYU+csBqYZ2VoH3e5g0TNy3cWFlk8a3sxcdxjJn6KBgf+7UNk1nVCgO+PYnwhhLej2a8bxlqUNX/R0R+DvDP+kP/s6r+b5/y3lcF3pyU7zstzVLmccvMYk4Hjy6OKqsLpQxYFNgy6MbK+21mksn0FlS51sJVN/5e+gfc0hX1Nk0NRRud2/cXWUGtNHDUI0dmjl5QsyzW+KOn3DvSQnksMrdJ1INvYcqVy+p+BOK2ObnwYcsNHth5yjnsAJ0gXzS4oHYhX4s0PYpoq73WPX4nWGW8GnjJLMKSjAcbbhLQOwWT2BphrgwZi23X42ZdfbcQKHKc9+DKa2Dc4MfNDC8jZEY7cHasN/DuznJwXFC6lkbFVgohaziLknJhFgv4sWK4ehdWBJpboQkm2efU9nNsCd6pk/kkKy2QTA12elZEGqhl951wmYl3enLDyOrYpl2X98v1HeQQaKrYs9mz3WM2Xm5wcCPwjrWEU+6t6ABPW3f8WIoV5Rrbx1czO2yfTrsbKWMhn/kpbb/lDpq4sRp8ojCnxPZRidnvzgiO/EuPv9UhIr8R+LeAaFH+70Xk96nq7/mq974q8M5S+Z7DjVvNXLbJM6OpcXvN6sSWM5NmZp1ZZGFlAbmSmXjUFVYLVn+fD3wh32RNN7vI1Hy3spgTrJCoA6MhM/NOP2tBNyCG7LP3nOCYlXdTbULrttxPjSqVU+WUN07RuZWdnwtUF6EJxsVaO3VuzHTj18hMzbHMAR46tQtw6UcLiIavubIZTptDeCrVAnAKqld38hCkFW+AtviO5e3Fo3sZOgYPqfOQbzVxWw6N8wuGP0YX1exQxNWFeOZUze5IQk/YwtPjNjeJy9nfl53+FsU2ARbHh2PEhDMGFctATTc369Qy4DF4ToxSkVODBux42/ujQ23WgzkQv5ABWwdbbqulCL7jd+nd1tlVY/plwT8PDH1KvRFnRO6DR31MtrKISS8LMFWetmCUmJDOpnDR2gwz+7f78fJGkEUW1LxOuB/3UNw4oY1BWalc0oW5TjzQRe3fUuwdOy/H8Ymda9+t8RuAn6eqjwAi8p8DfxH4egOviDJls6E5OAfUbrLcMkORqPomFjKTThSx4sDF3QEe/cb5kL7FohdQqEPffBdDKSQxl6ysM2d94KQnDkycZGKW1ERwTlk847WstqjwYe1ea8dkfNssymEwrYy24FD+ioC76iA4o51nCT3wjnNxzyR7YUsZlbv67T2JUEgU152o1dqdb57R1iGI3rNB4nNn6Z2DFoiFUxKm1Futz+6gEdKUxnSIsGKwy2HAuaNr7p2Yied167bwN8fAj6mSUuW62kokFMzGgl9yPuu6j4G+rTYpF+lYrHFKD9zkSpWe6UVABtPYzUMAzkyssthy2o93QBI2OXUq2Y/It3ZZYssilWdBuFJd56Hr7hZVlmpc5q1CTVFMtkloSt08dZYeeCs0x+zZxdCtk03YijUYXWo1JpCah9/qNj+B79p15lTMUSRoCK73+gsjPBePnxx6KXT9lL1twXd3VOfK34+3DDVgV94oYlf4RLLIq1uGt5JYqnlvRdEqYQpWt8IuOzOM7NCymyuP3OTKpBM3ubDo07PPD1eCLDOJxKxHZg5MOu3gheMLOsQJw0u3mnsWJu4AQOCn4nj01Cx3NtdDuA3eYeZ40ZfL4yU6shzse3vXXql2Y0WxK56L4Luqc21VQBLVg28cr6Se5WIB2NYA3QMMnNDf6GHC7LY6ky+Lrwgg5JS4JmMdnKfaoJcs6pl/YZLKZZtbpr/UxDdvp+bzdvEJaqmpWZBvJbOUQTiIfs4D748JKPzyRtfn8F7bZLPt9nMezRS2X0OAxQJqpmOzETDBYIloHW481zsbofjMCLrdjWJrXXMBQ8QxBpiG6+xaLHgWPw6fTepB2AqZp9RF9WMEJr6KtViXbBP6Ummrm8dS2NQKaiuVR7myxKTywvgYzPAs4Eb7tQsKra5BnBSypDcUdntX5bPH33bg/YPAXxKR/8n//uWYWM9Xjlc3UGyaXBA7NxfbTQ37Kgpr4RlNZd+FZLYsm96e0WESmSwzE8dG+g55v1lna5IgMUtCpL8zMtKnIsw66EGkzjIImUcLyCb+HZ1ZqxeaNpdxDIgBeuFE6bzbkf4TspVAs7yptQfaEMne7pTa+j7bETIav914M5M1WFCdmmc6WttwU40i3lUzM4lL6UvSxQWMro4PH3NoVJSGdSesqHZzgZ/VO/kunv2GaE9g2xGco/hWMZaFWdInjrl64XDP+W4wiNImkfuutbg+8gutu5Mvuac6NU5rdmpUvKZq3b2nUq0hRPdZYYwRU77PgMdM8P62X4p68dKw+8mvgRMGFUVJ7+CrwagtWDdjn8ijDiBiYkgAK5WFjZWlCbyPY5ww6jDBBCf6PqOPImRMcolE1swMLwAX390Rxcf78ZahBlX9XSLy5zBamQC/XlX/+qe895UNFMJlm7iVzLV0+/XV8b0o+Khqo4ztZmAtFFcWu5eti0z3Qb+x01LNTJz1wJGJCm5gGYR18Y40Zas0/itp37E2OwtgSpWHvBE2PmFvE7SvCMBxrgOfPDiDIHDXpk1Re/BdqzEaCHcMDajBAi5YhlPVOvkim41hOLFlt6G+No5Q0BoDcYxMZUV40APvi7JqZnbhoVM2TvOlJI5JETFxnc3hgYOzFa6hz1ATB6eKXUtyMSTL2kw5LvUuLA1NBjtQBkXYJBdcb/Xs0JxKMqLCQnHxm1u7RiadCMfgKLjdZ3XBZFhdsyOuLcNCn5p+wehQPEbO0ekiHk+aWlCK4Gv28Jkk0yBtuRfDAYNzrHGoIb32/8lgnOj2y0mZVdmqsjo2f0jiRUebcBXlwq1pV4xjxHhfYjcAL7dTi4EWVaCosertDjQ8/C3FtMI/PFCDiHzuQus/HjPR/KHhuR+vqv/gqz7j1Z1rS9CvVHxZH15SBjWsNShT/bRaH5vxGsZRBwkMwx0NNxw7mh44cRTD25RB90ECf/OAj333KQfuBqdceZdNT+AhFx5Cm6DasnwT5YYFjrD/CZ6lOH43i1Gm4jUxEma/HfY9Ny+obSJk7YyG5vDgGfCUM2utbE69ivZTJYwU4339+MWx7FnO3qxwZTV8UpWjztRiDstFE5VkgTNZZvzj/Hhdq7SlcWDAY5eciRd1d+R43eNmWHpVuBTZwQmhhwF98goI5pCMIYAzHG53xZ9VloaxHr1YFkG00aIikyM1eOHg4jjt+eG4jEdJqVSJJol+2UfAGjvg+jkW5pQ4pc7FFu0JxnwX/4JbHf8MZhpZHr3AGYLnc0rm4qGVm9x2zRJ7D4znY2Q72Poo7f7ux8EMOrupqK2sPm6e+2M/QjTofrzFwAv8EeCXYhoN40GM+vpP/6oPeDXGK67IBXYhXl3Kbqt2ky2uQ7D5pRAFglV70I1CWmS5tvA0mAG1v896ZGbiKJmTSzxaVr0/EcEAiEetccC84b4xuc6u45kiytVddadUyVF8wvDhUdg7GheOuXJMFqCDvhpL9TOhM2HB6FasCy9XsYCu5t8WeHB24aCcU4MfTlggXhQO7n5Q6YE3BFqa3jGFomZtPmZ8hY2rXClaeOCEqpJVuK0bS82sVfi+kzC5ZsZ4Hu04ehOEY5hrC8YxuaSmPXEtdi7WamKmsQK4FliTBaZLMbfhq9s0zSlkKROl2gRx4bKTOAwsN/bpJlfywFQYV0kzB1btOOhRTyQSN67tc0YmRFx50f0WdLWDHthkGzLoSorimni3WjJh94hTkwfcwwBBWYAYJksVCrhJqAdfZzMstU9IALdqwv4Bo1SplDs/tfuxw29lJevcAm7WmXKn6hawyyqrQxN766jv9gixp2ePf8J7ReQPYIHw76jqz/LH/mOM6vV3/WW/VVX/lD/3HVm7q+ov9Z8/7ZN38G682voHbOmUa5/5t2qFh5trLaxaCMnmTTau8kjRlfqRGTyRmeTIUc886GfMOlljhGSOyShjD5M0knociS8WE5oJ0rpV8G17rEpqr7NMzYqBgjUEhNuEcVQDL6VxL8OcsDkvJOXkF3vQfzYvlBXP/kvtDRXHjHNabbl5zKGI1VXbVmcaLCKcyY1baZ2BhosevSU1HD0ALrWwaGFhaxbkCdOeXWXlqsmEUCqmmVFg00S6pbacm0R4mKxLTuiqWcaIyDseblELPJHVFu2i8psajxjsuS/W6kIyVqW/1EJBTZNgWPdXKmc9c5GnFmAaE0H6hK0EvHDbvbfSRXVijEF2XHqP1f7V3zd+VjAmwjQzafdXM364GbTWIfAGtBY0srDE6i3qyrXk3fW1qfC4WtB92ixJeaobF1YucmnB/6Wg+xKlTCktwK7SjTBbJjyuivSGiLkuG0voLfWtWWKyvRBlPxHj/e+A34u5Ao/jv1TV/2J84OuydvfP+rOq+ou/6rGXxuv0eBGuJZs4i1f83cPPZ3LDqzZfNoeUY9GVwooOBZDRHVkw9sLn9ccxM3Fm5iCZc86cUscpY4kbxZvJl4DBdw2+5a0KudgN87RlE27BIIWcerEjmA/V900E0jC5zE6ryg45TClu4MhwujOstYOGs7BBDWtVDmmvWDUnx4Ohvdbery0Qxw0N0dppE5tIFGYSm048lUxByRgf2JaQG4ushlV6QFZVtpKZZSZU5CxwinN37btCJS45QyW87qDDCB82vF/fpQAAIABJREFUY2ucmvKatT1HBnetFgiKq2sBDUKpaJuQAVY3vexmQL2VN/R6DX7YyN5Ik5kaj9c+s+4CqlJIenwRB+2BaGtMmTHwgwX6xEz01Y1o68NkARa8cOsXS9QWskM3o2ZyWPuEs0Qcq1VNgezGxk3WVgQr0vH9kb0wBt3YTzE/EMTJby/vq9VWkq90Dnpg0tyYJG9lfCcOFKr6F9xd+FNGs3YH/oaIhLX7D+HW7gAi8ocxlsKzwCsiJ+AB+Iki8r30BffnWDD/yvFKIXThsmWTcqzCpXibcLHZ2yr3lRWzCVQqN7lQtF9MIgYrVAciAm44cvKfMw9p4pStN/48Cd+YrRttFrMxv3rQt8xzyKI8213FgtnjlnjIlawD51VpXVrhmxaOAbZ99nwE3dk7kMQfC5nIaCdeXNbSrOuH7fBJ6Zi7B5eR63vmpD5JnDItYwYr4Ix6rnOCd07PWCs8bcJWlVM6cK2Vp7JREI46u5KXqVpFF9eqG8KJosqlVM45EWyraHyBXii8+jmNfYhxwfbrWmsrnm0OLz35OV7YODCxUbjJ2rrSooAWWOriBbKQhIR9R1awHu47sOJMrnJrNQETkll9X+3xHQMgVip3xaexEy7zPFDHI3H+5mTXYMBPTZnOr5volpxS5bJNPG6Zpdh1aKuBHkUmiaw6uSRln3xim14Kuh8b93jwM2qZlvbYJoX8Stv0H+1htYQXHv/O8JB/T0R+LfBXgP9QVX+E79zaHeDfAf4DLMj+VXoQ+gL4rz5lw17tQPF+M8zq/erC5Vu3KFFo+OQiK+/TF5btDoFXte78ogAO8kCqqQVdE7wRzll4mMYWYKWW1AJgNjJny3QVE+/JjqOlzWlLybYtboyw6LkXHU+u9jWnzjnN/p7eyRVc38RSwkn45eNlho/dCeKYrFB3cKuerQpTtSLVIdmZT2KZ5SmrL+07fcsMPcTPmrAUKKtwTpmkphObVNhCsNuVrZCJVTeeauaoySetLp8ZGW+p8C1PcZdaG+e4OKk/CpyrGsciYwwF0xXobJUnh5gik00kFll4knWH5U7eBGHL39SEkSzAWpCIDrYIIuFeEUE3Auwm9ookubszEDS1lczMTS5OqZpbESvgiuZl1mCJsShqx8doeRZ056QcRGFLzNmaKQ7ZOiMv22SmrVvi/WbGrY2368exqjKLICotWx0hkFEgyP7uGe79uH9u/H3ExauYtGTWibF4+ybGxzBee+yT7N3vxn8N/Hb7ZH478DuBf5OXGxz0Sx5/YZv0dwO/W0T+/U9pD35pvJrVEO3Bi+O6a6XpLmxaPdM1DsOiTzv62EsqS3EDARyZOKbEuynxbgq3WnVTSss4L37dSfzzNbthbf3YRYdR8dkgoIMIYkWNpbBW8RvW3jfSygOziwxZ/X3B9Q06VaVL/UVzRdDZ7HO62eHskpRgGfAZ2K5m2Ryvtxvb9zNpv/EHilz09p+yMKcMmwXCrGIVa5SihSoe6MQlD9U60apEld15ympiRU+1EM0aNy1MKmx+TM4y8aSrhzQrngacNGaPwK5QFo8t+sQsJ1cgs0JqdKcd9MCjLC3LUw+6Rz2xydY+TzCZSJUoIq2sQ9AfnYUjKI9smcKGSG6832ADjDiz/TSO7ST9/E3SlcaKF3GDURN83ehUe3KR/7gm8Gss4KVgNMw1sSIc1BqNQldorx/Rxz6olt1rXmqsiDZ8a40uzjCqd4TE7/4ofCnG+5X27vdDVf92/C4ivx/4k/7nd2ztPnzH7xGRnwX8E+BLdnv8Hmt+Nl7dQGHL6k4ds1bK6kHXxJvDH0q9UHAfdFVrw3izzG7L/cApTRySQQsP2cRGIsM45Wr0JqW1AceFHAWOOdGs2wtObTMXx1YYu9YEDXfruFL2xorAdOPz46YCGn/5WlILutCzovhpEMUeqw3njZZ1N1w1cZ6UuvUlf8AR43tPSRvEEQ0cWeAw2SQImaUqR03camXRAhy56I0im3cMmg6tVqWKM0VEuJQ+cb7nul+iOnWtsHHVM5XaxOmDoH9xDm3gkxEQK7WvdtSKqKteUSpn+ZxFFj6vD/60BdrZWQZgkMniwXiVG0JuvFuI5bT1swmJoiuTHNu1NvJ2Y3vsc1dU9tzYmG9NarRLl+bUz8OqsBVBsXNwdofqQ+qFtaUmvrlMjWoZ12fQ0Myd26iI16IcU2apVvQqsk9SnrcFP3eYeOn3+6xYSCTJRLF7cwz9LbUMf90NFCLyk92uHeBfBv5P//1PAH9ERH4XBhWEtXsRkfci8vOBv4RZu39pNisivw34RVjg/VOYTOT/wvMi37PxqsAb+N/FM93FM92CetfV5gTthSd5z1KfdkudGIpdkVlmhMRn+jk/IT1wSomH7AWmZEH3s8kws8gkxiwysl6wwhtAkecnS0R5KtYPL4XBldfZDE50j4Aesn5BgAfTMrjn8hosYSyE+KzIZmLbxsw3/g5922jYmD0gLwMGswvYYhNP7P8kQTLrDrZRhd8Cz67OuiA36tVjeuRczxawFGYS1UW3r55RXuSys+UBK8hUqTzKY3vsxpVZDo5R7oNBlVsLuIa9hrmkZV9FV1ZuZJlZZeGoJyadW0Dtco/TLvDEt3Sd3UdGkZskmY1bgycmz6bHQC3Mu6V5YaPqzfV+Yx/2OgZ2fLWdv3lYAVXgwYuuRYVvrdn1kX0CrXZN7q6D5Dh6rXyoKxduPMmHdswDm+8Txd7m6n7spVP391sU1drf3j5c2jrmbYzvRCRHRP5HLAD+RBH5W8BvA36RiPxT2Gn6IQyX/bqt3f9V4OcAf11Vf72I/CTgv/3qLX41q4GW7W4a1DGzXi9UNiqrrFzkiZt+eBZ07/82vu47vlffccqJb8yJdzO8m5Sz68mGsWIsQ8Lp1niwQhAl7uX5Ynm3VltWT2Kyi6Nl+W5bJJaX9sYoqEVQjgp3CFfPKJKiUOdFutongmAwZBkq4c6kmF0lrbpdUKni+ro0kr0kbbS1mBRKcYcPx4GFcJhwopoEKyHxBEzFxHjQCYQWfC9cmgvERG4dZOF2kAnM0w7ubaAnxXMhqRgL9dXJ/zGSZKr2zCvLTNWCkBBJZJmZ9Qh0ninQAvGY7c16IMvcMrnNA0fVwiwTq66maOc/Y9xrHYxZYzTzRDdlZNQBVUyaTcpSOzf83VT9HHb0NdG1mL/woNuukwFmGIXtN4fnLrXwhTzyJB+4ymNjH+ydgDPyLPPdjxH/jgAdLJDejm34+syBo544DHKrb2F8tLj2Ce9V1V/zwsMf1Uz4Gq3dL6paRWQTkc+Bv8MnNE/At8HjXapxTLtho3VhLWzdqkRWSh2YDNxL7xm74SAPPNTPeMgTD5Nwzl5YSupi5V1wxKg7ZpezFOGY+vI+Lu4IviMlayS2m6iUtSOkth32Mzi8QTOb7vDgEAE37VpA+s0UNu6REUUm3LYljWUS48lWeiPGeGRGjDkmgcNg0T6lUFrzmz7BORltzIxDbW/nas4J9nEbyRkPZq9Dp1ENmGIE1Gduzp41Wma78bEl7pipJRJZrAi26Y1Vr2Rm/47crocQqNnkSh3+C7nHsQmi0n3HMjaZVCpJ7PMi6O6hkn0mGJPFiH0ay6a6fOTIfdWm9HZIVug9T7VN0NpWOeLntMNWwfqYpE+gYCyWD5vyVApPLNzk2jPyITvt2xuUupdD0CgmH8d/1iNnfbD3qB0DO++dH509rL+VocN9PI437kDxV0Tke4Dfj7EbPgB/+VPe+GpWw+KdSMZFjGbgwuqUoZWFi35B6OtCYLCdS9g61Zj5XB84JtkFz2sVchLYEiVZu+pDLqySnNKTeCqJXA0zC+nFKHBFwIvLSh3zNZuWPWOhBctBzGR0bQAotZtQbt6EEUE6+LwWkDtOOy5Jo7BWMb859eLa2TWBH3J1sRmMDlZ7Ia+5QYhyyPbvG1Ph/ZYbx/c82YSUS7RSB8c2oQ45VL/hZocNCvsMdhxj8AzObFCxWpBw5kCRFfGAZXs424Sgc8uEJzm260FILTstzjcevxe6EE6MaIYozneddOKk73iUbzXowjJiD7KR5fm2gRVxNwwCGROBcd9f4v4WtSB6KSZo/vlcOE/bAEvYRAp2vvNkOxSslTwFGwYum3iBugMZptTHs236mN3P6Cn30uNgXX0PeqY2MMWoZKFJEUplbymmfSzjfeMiOf+u//rfiMifxnjA//unvPeVrIbnQTc4u6vP3k98waa3Iej2JWf8nNI0KJDZsksQHjfaclswUZegvcxhR+4NHLmqa9fi37Pf1vu5PKrPMzTPMfCMJHVYYwy8YNui8R5n+CRMByI8tAIKEN0H/EoPnOCdakmZ6Vxi/L0hNFS0C7FYR5Rl7JMAsQoQm3yC3hmi78ctcU2e+YgJ2hgVzDLfohXE8N4sFnDvb/aRAha46pj9jsEpimEAN7GijrWjdhHzo579fCRubtVu58uW0RFkG1YsvQMttkHp9LSAG0bWxCRHFn0iM7diLcAqheZoMgTowJ/vW9dXub0YfK3TUFrr7zElPp/Xdn0UV3XLrpFcqmER5kZh9YVtM80MK0obY+TmsFynge0dMZJDWOP5eSnoMrwGQlPYimcb4gXJjsWbwcBb0+P9UeHx/qgOEflB4I8CP6iqP/Sa975ej9er3xUwlSyrcl/kiUUuHw26MUzY3G6QpIkbGyednIgPeMV4q5a9SbXgswYeqnsvtJH8n++jLbZ0n1Jv862AqDQGwylr03MIGb8RtxMx7dtZlJRoE0E0UkCneY1D/DNCrQtCs0HoFu/e7aYdroBOKoxMvPrz7ybbzsiwopJ+csw4Ap7R44JnnEy7t4Lq7B9+IGlqwvTRPWbbnTjqYUfLCj3lka7V4AD/ztDCzUw76/aDzsxkNipX2TMWIpuOABMi6BZ4agvUGz3jjb/jd7u+SqOMtax3+Fl0bautyLrt2oBo5Clq7Jsj58YnNo3c3M4JwBerd4Alc2PZNLkaW+eF1xSCTspTydYe7oXprVoWfTOD+d22xr4f9Wxt9sM5ifGxoBtj1iP96Nv6Y0NZdaOQ2aR4S/TbaqBQ7cJS43jpsTc0fhfwq4D/TET+MhaE/6SqXr/8bd8GjzcYDFFMq1QWWYxPqdcdk8GW/88vnuQIk3E4I9D179nUMsAT2oMVXc2/aCdbB6WMu8+4D4RtH9RI7G2pqMb/rdjPUWvWthVUenNIhiH40wJnQB3x3ZHt3G9XfHb1m9RalqV9F7Knkqmao29k/MVvcBHlKLSGkM0pcqO0nohbMSnmehy25h7Zj3pilaVhupF1nvVMxgpvlo3aZ44E/3jv2A0WQXzS7NrJJnKUEDatHHRiUWO+tHbyIRDnYCPohDrZ/34YPBLdXBtJcoMP7HwW62rTuQW0SAAKKxPHAUvtj4+fD4ZkW0NOx+97wVZ4KplTmThlQ52PTet5j/tGkiB+HZjF+8CYuMtgo9sz6HGBX8dzXzWOeuLsq4xZMhVFVEmYnRZqe5MYlTO++yOK1/fjDSe8qOqfB/68iGTgX8BEef4A1jr8peP1gVdt4bZ5vrvK2nDdEDfvr98H3SSmcRqz+lFPnJk558wx75kJgakeB/+qTQ0j3VSaEWTBUtcxuBlcAL2sZqMFUzVcIIpvqwq1eNNoTah3sEUQzljmKR70No3ee8vUltoDMdi2Z7+3W/V7gBaCP5y160vEiCJf2xeHQEInYvX3POTaxH6OTrfLycRo8M94N5nuq8k3ClKEqSZb5upKOP5e5WknOH/ERefF7Ins8Yl7u5ijHiiOH8bNfHQW7CyJb0wTJz8x16JcSuGmE6tWLrpwlQhyG9OANQf8MHPYZYUBF8wcHWN+uQlg1dsOazLohVbpvx8zJ6J9vUplYWHW2QSGvMB2GIq5MSm+X2eyhO6uWf6EuPx1nXncJi4ltRZ3+9ePYKUaG8T5xy+zgIaC21Anid/Hxx70GzzoA+84IJgGMgiSpAkWZRK9a+3thF4dRKDG8ZYxXgAROQP/Epb5/lzgD33K+14NNVQc80LZpHCTK4tcqFp2sEK3UNlXvWdOzHJkrgfOeuBdnpkTnLM0xavJM0boPNZJOi4bI4tyyBZe46aIABzQggz0szS833BeWBFmx3GJzNYz39iG9a61GGj26KHJu93dlONIvg1g0EfIRI4tywnrUovXCzizYp/9Aq2brhcELRuuKpRkAfCQrOV6qcLTJnzw9uknoFYl3JsrSihWHfXQrJUypkWrmrhpdUYCrVEmttl0hY30dEyZU0pu2mlddd/wWPe4CacysVTlcSvOH9446omLW7LfNwyEAllo7gZMEDBDIu/b0e8negb7oKGoFiuxCLbRsmyfYWyHKtb5t+rEWg0Gm6s0gflrSmwC1+uZd1Ng0s5oUDMMeL8l12kQnrYuOrQ6vnuTa4NcIrttbi0aGss9wEIPuPdBV0ic9IEzB7IkTsnct831ot874ek2WjG9hWH3wwuB9w3nvCLyR4GfB/xpTKPhz+moBPYl45V0soAYTPYxOouKrlT14ocWZFgePdtYjO5i/fZ5UPjHhbntdQcvIk3u2goRwKyddlLTZQidBOsGEtc60Jb1dgjA5BgN1/Wlm+O8EbAj4CkhnCNkl4+sACrNm22rFnSjwNb3b2h+GB4bi2xjRXxTn2T8wZhoHvLwvRjM0mQHU6c0henoQQJXN1xxKYlbjW/v7dX1bhuAxus8c+CzNDGn5EwMK16ePKO14mraaTgUtWN2TImHnHg3m+6EqbB5pT9Zxri6sFLRxKWmZnoZ+ri2XRYcJ8yXD7DuNTX64U0/ONwwIx48g6Y2wlmr3jjIA1VvOyU8y5LtPYHx5gjIFGaOdFJbYPHGtV6r29VXgTUby8S1GSBWWnZdhmnq0ybNdfpalPfbxur4eODP9xhuBNnWwXZXJ7nPfO27DZs/SuaQTGDqmFxLmMRS1c56rXY1CM8sur6bI4Sl7scbz3j/IPCvDQ0Ynzy+jYy3X5AhT1dYjRf5Fd+fZbbimlp29eDWKpO4xqlfB8doxfTgO9K7snRH26Uknug+YJWeFZq/mC/PvRqtHpRP7igRK61Drg2jK9WgjM1xVNwSR4ege/U+/Ai60RoaOB7gMpLdffY+8KZhWzvdrDMmouC3uB9acvwwpcpxOBbhIxd2RuvglFw0sl1rellq931b/TxaoSUzk010PptAUchH2rBfNi8yrmpNG4t7ywHN6Tm0DQ4+iYqfi1sVrneV60AZZw5c5Kk5QARjYdZjYxqMconBThh1HcZq/30gi8LZuAobW9mDZpal48JGwppZtZigfI2uRyGXkP8U0qQNOjqlumfHDNfDUpX3W+VJN25+9KNV+WM1kfv9GP8eg3ESq5lc5QqcLeCKOU6Ht9vsBQTFnEqSvC2MVx3Wefb4G3LJeGH8BeC3iMhPUdV/W0T+MeAfV9U/+VVvfDWdLEIt0PICy3if+4RF9gu9PTiq4glT949hco7CcRAfh07nqirMLrk3pdqC1qrSNHQP3v0VHmvvpg1V4YlsamXYDaHephuNEkIvdt080MaNA7jte24WLvEvlo73EMMs6sHcb8L0/OKJQkwCqu9vUN0i6OZUOfgxELGmksB6ASYxHa9rMZH3xbcxhHweN6PoPa52Oz8V7zT0ifPARDTizky2NHU/sOi8i/0Kus9ShBMGCym2hFbUb/Re7FyqtO7DKSmPW88Yzd0jMWlqurtJ066YtpNJlH0zzsaNmePueCbJrGrtyZG9Fgw7jawySXZN6Nzw4UbTkr7Er/7ZmxQuuiLVmChZJpbSr8uHSRvO71sBVGpy9owfCyUE5LsesVnT3xgpbZ2RYVl5Yt/uG/s5Nn/EOOrZIRXr5jtP0V7u5626Mpq4b6EE5/ttjNB2vh8vPfaGxh/EGif+Gf/7bwF/nC7I89Hx6owXbDk4ygDG2GUVL2S/hqdlZj00IeaQcpyG4HUtybV9O70riQXZCJQAx1TRLO3ij8LUKVfeOcn96h1nD55Fxnuj2BVSj6FURnxO1uYicHXGwJObPy4uEBRuDGCZXXSVHTKOcZqlelilBwUtsEAVX/5Be9wEdCqn7A0PuZqIihfY4jqsCEud3DUi9X3w/Xgqhute3BkkpDsD24uCGGSSa8NmEXeOpsED82BsmTxzmgQeJuVpi0YNaU0royHoVk1DQ4FDhs9QphTHO3EsFigKE0WmVmyy42laCk1j17vSknfjxfOZmcKKaNoFqghkEXDtXJf+twJkCuZ4LWI4KwLr0AGXVFiZSIjpDpdETiZMlFxKbJTuPDVIJTms0oWbbL+EKtogutjW+wBs3Wrl2f70z9lzfq1gPZPF7gW7/vy92vnh4udK3hqrQXXH9ojxxgPvz1DVXyUivwZAVS/yifjN6zrXxAoiRr6urV/+fok3Zrr2u2UUQtrZsayqHPxG7S4IkJMgVSiNjmVSiluoTYFjub2leHXoIGCD4yBcEq8JPu3YHBGUn61KEz5vpPUIylVM1NqD7s1lMSPwZgGVHnwPgwTlIRcm5wSHpm92jHZx3BbCoLNDDMdsxbLFObtLyTyuEXy6RnDs01PJXDYzIr0Uw1IjI7dlsa1WkoiR+STYsoblTsPSc1M40M9LFjtPsa+z2OSWyHucfQCOYxLdqnDMyjlXThkODoNci3CtyS1oekEtfoZGrbQJujr90PSbo+kgstiXagqh5RB8WKUyydHwYUls7gM4YsDNLcUz7iTJ09YTudrkdC2Yli7Rkt5hk/eSOSZrrrm5owfQ7OAVZWUhHAnV9zqC6Esyqi9lvvad9vzEkYMeODNzSrkd/zh3S41GI7l7/9sZlb3rdoy3XFwDFmc12NEV+Rlw5+j7kfFqqOHm3k73bZ33GFocL6U+U0hSv7HCNnsMukks+51EuRDtubTABR03tPdWci7ubAGncBKGxmktQ1ZYtWvzBk4c3GBRKCLtucDuthoavIOluXZbnMDyjo7pBtQxsjEic598UijDtkUwPnrgPeWNtSaWknkqE5s7O6t2kR8Ro/YfHec9pcqF1CCGEDOyooVlutnhnTmlhq1HQWMSq3hP0jNWgxbgsxneTVHE0fZ6KFxL5hZYrZ/HCNBT6tS+EPcp1c6bOBMiOMJm0b7QaGMuXh6j+gQeY9VbYwHc08riWjTqVEzA+yKWKaRdHd8++TdeGpSR1YOzGCviqgtJhakKqSQkm+D+5sfYgpy4XnR6xoIxF+rQNFme3TvjTzC4YSzCRlac2DOGjvLZgI1XrtVe88VitYGHSTwRsMAf90/Il76VofTmpP3jbzrw/jaM0fCPisj/APwC4Nd9yhtfGXhr6/eO4sDeRy2jWkgyU/1Cj6qskFoWEUT5LLbsKRWufnyzwCZwzMJWeuZUxGCBybPaaC0GC2YR2OZUne+bm+zivZxjKYIGnWxohkgEb3af7d5qYlNa4A7qWogzhmZrTk71Qls23gotQwEwJgLLNrV1zVW1BeRaE4/b3LbhFlBCFcDw6VwTKdntGxNMNJpUX94Gpgi0DPfgdK85WdZmk0+sBJ4HC7KxF7Ion00G1USmXtW0hNl6e/So/GbnKmyUehHKtsfPtzfTTK6g1s6RriQxla1x4k4kFr3tik9jRlhxOMFhBJQGU0ShDcEZOBWRubURv6SP0FZ2ZC4szJo4qLEEpoBmUJ8UDfeeJRol/FrBJCBvNXo9vQ3aIZTRAuslbnJkxfF8Z8ukpjLXugm1GuuCyOQFmQyiO+fekJT0DWa8LzCx3jLUoKp/RkT+GvDzscP5G1X1733Ke1+v1cDSdE7vBZcD19UItIFVhTZrmPqpdUPNEnbhnslKLHttBgyJx7hEInsqVZAEMnRSRdFsrYmnktk8WG41Gh76ZZZEG/XsWqJ7zIR0jNnlbgK7jLdngWPnXARfIaAG09ZNDjPk8PtKRgmzIl1u2et52jjkgqqY5Xyq3MrU6GwxlpJobheO00YzhWXGnagfI7Z1GqCEYB+cc7cpf6RT4hSXwVQ7HlGYieMYnFWAh6k4oyQ5tUxIquSW8UaDhzY2yNgwMokwqXnF3cRobVcpTeaxXTMDfart25ARj0v0GBHMQg+4v6aY/dSAqY4O2BGcRez6fZL3ZJlY9cxn9RtcdYMCx2qdgHHMVrFzc3Y36ahFXItyK3ALI1g3CVj1isg+W78PuiNVbq+l4dcxvZMv2oAFcTqguJog6EZjnHxjrg1+eksZrynPvRB4X3jsfnzE3v3HYy28PxXT4/2V7rnGd2rvLiI/9+6hEFz/Kc5w+Gtftc2vDryhKNWrzl3gw15z5zbBnuoTffxzu1mVBZqyV0ALIE13NvbcMmQj7E/DEmTMbrNogw8Cu40GhwjmXSDHeujBgsHRl8bRORa0MctexMXf+7JxtD0/RQVfOsxQasLd2X2CyY0dUZyadcq9iUIV1tp1GDY1AZadLxxG0JdqOV9xzug9b3TzKrHQJ7PQlDhn3N1DW8v00gpAMcn1Yplte+KUzdpm9kx7KZlD9t+roEWCItpcQ0ZJxDEjzmI8UkGYMU+4yHBXh8kKW2vxteBrR6Cpm31J8wTQMVQP3BFwIyhnmVn0yYKs7t8f+G/COHGLmJYxFapWqs4tJGQRHnxlsPiErq6aV6qZgy5aeOLW2Aw94+5FwdGZZdyvPknseciR6U46MTPxIDOnlDj4RTcG1q1aN+VahZNnvm+rgUJfDLKfEnh52d79NwN/VlV/QER+s//9m74me/ff+SXbolj78JeOb4vHywuMhvj7vmOtarUbJgKccxctaPRPSKpske1WC0KnbEGvuMbswXG0nC3AdTggeTBzCo9i8EAV1qgq063L7yd6Ze8qMC6Lg86m9CX8tVgFNks8Ls2td03iVW47DktNTA4lbDWxlMRS0w5H7vq8iVkrs9jrDfqoZogo2qhuSXB+L6RKL1YVwxiDX2vZDw1WCNWzYw5ZSzhnbWyOyEQqE8WvAAAgAElEQVRbES0F3uvW8Q67xLGCztCYBci1cY4/n0vjYF9LbiuHa+lQwyzCJIn1bok5ZrdjscnayHv2q5gGb2ZCtbbs9j77DchhvEYjANs+ZApWeGvfRWFTk7S0iwJUCpoqVT+z9uk62zGWxCK2QqmtuYTherQvX6QL47Rrz00EGhziwVe1NhgiHq8yPO/vSU7JOzNzSInP59w6QEcR9uDzbhWKF4BlOI/f7WGazM9hliJfHXg/Yu/+y4Bf5L//IeDPAb+Jr8HeXVX/+U/YpS8drwy8wULcj6qF4hnLGHCzTFS9kaRzLpMa7aWKctuJhQiiSvGCW5Ho6grsVJo7sc38Fs1vTvW6Obc2stUIurehT34UsoGuCTF5QN9UmdT0IJrsozdKRGfNzYXgL6Vw9CXdPETy6pSuWQVc1Gd2PPey5Ya/rQgH7zKLALVh2HLKvSU5YZOCJlv7b1WarGW0Hi9eUAuKG9jkE4FzFmkUt9Gl45QrZ8fLL5srpdEDbzR2WHHMoA22zBZc41wo1TLhm08qOSkP2aUba+LDlj3gJh6dfmYTnbTuuGjlnnRiFQsko91NQA9VS2ucmDiycePIZ2zc2oQfBbNxRCC2NpF5B1OsmKJekqk9PnFk4cmv+OrwSKFiYvKmO32i6gMHTHuiFOWUcsvojw5iX8s+uC2ysOrVYAQxkfhoGQ7Wxb0rdwRadCwczoQGWdfKsPvl3eQ6JtrpjlEwvVUxw5tvi0j6ozeC4fz88U/KeF8aPyk811T1h0Xk+/zx79jeXUT+I1X9Hf77r1DVPz4895+q6m/9qo171eGPC2TEbxuEIC8vXKzQVncNBhXlg3bWRVw+gmF+s2RUhC3aHh12uB9PJbXlazQ1xLJ8awUmGkQAPTABLRvs24q3EXdPtlas0k4fC8ujmdC7te8sjimX1N97LYkrPXCFr9qczBhRVVmjy2kQVx+ZDLE9SVzFqUr7PGtFNQw6YIEswmHq+5QdsoEeTEN8aE7K98yFLLnhtBEc45BPEr30dhWUYoWbaGo5TxvvCM0K27bHbeKL1SAgEzaCpwGDniIT930Jpox9w97u5oHPWb3ZYNMbBzk3Lu5Fv7VrGb6/CiNj3Fw4Z4/3QpKpwQyqJuxufAjLgqOjrb3HD4zZ1B9Y2Zh1AoW1VI6SUbJfL8afvrlLS/LPUCpbvbXPHUfzqhuCb1U7Lu2e00p1s85JJ8N3xf6tLtx+mJR3k9c9PAGJhadNoDxjXnw3RxV9MeP1x74de/ePjZd2Wr/k8ZfGrwZ+h//+W7CmiRi/BPh6Ay8IBzG90lVXCiY7GcWzsMweg/D4e9wET/LU2BHnem5qWEfprgriXVSzdKp3pyUpoQ5mr1WuxdkJYvq7TbKRMWjqjleZW9Zln5vwKnyy3vxxRMAoqq37S10yMAJWEOmr4rbx0pTL4jPDEmatBqusA+3s5F8Zrb+t6Ddg1qq9ELZV28ebQzFbZafyFtSwsRHC2Ad9v7Ioc7asNqzui/aptTdIaHs92E1bpYuvTKmCFw9vNfHFOnHZUsPWSx0MSX37DQ8V4j/LeBcKjt8OjQwj9rvqjVmOHOSB1aVPhcRBjq7l4EpjQ7HqIA/tGgw3ik1vzHLu7siDM8b43giCkxydwmbebKuL+MCJosW0iRWkQFXjSq8+Sd8wFb+i607F774JomW0cqcvPLi57DvWjpw5khhWEG1FYwJKS7V8OK4XxYu0vJ1hIqHPZUC9S/bV9u7A3w6nYRH5yZgfGnw99u7ykd9f+vvF8cqMN9iXtWUZS3169jrLcF9Wyq9SuXElM/GuvuOBI7MkV7dKjdsLHjySeJC0DCky38Wr+PZ90oLrlEzHNy6syFK3ah1cRZU5CYeUOOUoivnB8Cp8dB6pf2Yoj61VPYuprGysmpnbc10KEiwbj+w2AnEEXLBAb3CK+ccZ791uhbWmFuhQ4eqZcnG4Y3PMehQWyQ7JTIJlZBLYrnXSBS57rQOVy38estnZLI7FVjqdLmh0jQaGTXStGcUpc2BZ8Yi3x9kXLOiKWOPIrYZUZYgKSWsfPuqpUaOumKuxaT0bb7do8Hz3zTuwzxKDmbC79iL79QA+ybHhwradqT12LzIVy/1Vr0xy5Ma1JRVFNmYOVHyWUatTZLE23dUEJrnJ1bPdK59PP5mn+iN2iod9GFeRdu08F8jJ4lCDJlZZOerciqj9mNp1f0qKehAuac8/fzv5LqjUps08jpce+8TxJ4DvB37Af/7g8Ph3au+uH/n9pb9fHK9GepImVFLLB6Z0ZClry3ZjRPCF/QxdMB7luT40YZa5NVKEhiitEBQtqobDhp26tcNG0BmhAMVoSkaDsgYAsypSlmrbeMCCahyhcC4+JqvC36o0da8IOEEnM9qZUV82tSB9zntM8eKBp1SbKCKDDB1fgwyMmaES3zF4vA2BLnDeaG2ObY59HT3mTjmghjhW5oAxBb0tKWyGN4uwc9uwfe9OCkWFWlPTLoZeBQ+mglkQ+XPDtquG8LcxUMCEj+x8KrkKS81WWRfaa2zJHPzc6FSrrHpr+Ose3spM2nVss8xeuM29W82vy/rCMrZdq54hj4W5CNo7njrGQNi4kWViccnJ8Jwz63Tj+6IHZqxwuGEuLVEdmdLJ6GRBD9N9wXDvNtx1GXbdbJI56okwEyhYUtC1TXpgjWu7EpzsgOTeTs77cvXo0xooPmLv/gPAHxOR3wD8TeBXAHxN9u4/R0S+wA7x2X/H/z595QbzbWS8lo2YHqhowmT3spEFMWghgnAU2Hr7cGXjZq8haOTKKVvwDceEEFsRogW3B0fDNh1rLbj4jQVX+36r7Pfn7YK8Bi4rCcVcercqrJ4lHKbK5HzTWCKv3ho80rOeytYclYv7jdm+2s/LHZc2Lv57S/kIvhltTRTR5pzE8F/obhyqvUC46X6ZGBKMh2QaE9YmbYH23VQJwZ8kcDwUvrXmNslE0D3kwlIymyj4tpoEJVA71GCrkOoOG9ZlZ9h0RQc3iqDWnSdTgqsYxUxEKetEclhNcFlQzVjYmjhqsu4urVSxZXm4FY8aurE9IY4TRafC2mhahb2v3Dhe4tBGx9uOz6tG/bIGIC8mxzYIwIaKNUb0tnllVmsOWcXkU1e5tYAb+hBtYvDCYWzjvVX9/T5EJnzUmdm1JCLgjkXkotJU+gKmCt71x1xavhsjRI3ux0uP3Y+P2LsD/OKPvP47sndX1Zd7uF8xvvbaZmS69xnwmPVmnZk5MDMZcKEgCW9v7AWvWDIlAkPtKLiv6LiWLk3YgrXY46u6QEytXNU6fjIRVEK9qbfJhpJTMAUi4F6LNsjCloyLz8/qy/Ie6OPij+0MytlSLIsf8dXZJ5MpdYghu5CPSVR2qCIgliCCtKzTOZlzdhEULHDP0p2Qj0lbF10Uz8Daq0dnjKC9qfQiXymZlGw/I0hnD7rv5sWaPqSy1Ux06WUP3jmZH9z3nG4UTXxzObQOQhE4T67NIcKEu1eoWQZddaakbUcnA1pgHWEFsBt30SfCvTroYuJaC59aHY8AvnFrsEOMCMQR0KPQFQG4SuUL+SZndTzZ7wFz9e2iOEv9QA7NCM9qYx9fUh4bh2oBMbikuNHsTNfbiOti9WJz0C7PuZBTpdTEpdjzbyjufkng/bahhjc9Xg81DBfEmHkoVmXdvfYOY+sXbvJOm6jG7r9jtGu3rFcajmqf2wOd2cFXVLURxx8dyw1Frov7fJ2YCSm8YCtUjEa2VuEmfYk/2sUX/461Pi+IGBshuLV9GyOjCDHx+NIq9qZxn+NpGYpVpl4mrgNgs0Gj1Gnn4QbjwATHrXlk/KwGY2CBdlPhmAuP24RgQkPv5sX32TLbgwsGbW4wug1SmSbiU1ogB1wlDbLYY4dsVkQH1544z4Yfz6mSVdAs5KMCmcfNXB1OaWJWJcuBBGjVYRlvN+XMqTVCBPSQZW5/R5Y4ajzEGNtynz03sgbEMt6JY/uOJJmVq71OuaM12s/iAVilchELGCKpu2dI7U0Z3lIfRWlp6mkDcwHnLet6Jzg1qpdFC1OhumHsrUJ2BszsfHKR6k0zxkOeU+X9Nr2xjLe+GGQ/Zu/0D/v49hoo6Bls73N/+aLu/EPTcCguAr1JIXqzBVtK3wrNVdSq64ZHZS8Ijdq3VQ1GWDwgBgnfKFZeAPMi2Ebl6DejYZri22afmQBNtixbivC4pUY/CyNLgKsWVnfdMFdddQEa2+5VrT20idJ4p100L0QhLQJmaDuE2tfkfN7GaNC+DeCYrJjaFwRc0R03jkkBW9qLdAbCmOvNnvU85EIW5d28stbM4k0cxuwohAFogqYBPItyzIU5FYomnra5BWfLkBPZ2Q2neeXoVDNzkA3Gh/2M4t0hWaNMTNKhH/FhsY6s5PBBNDVU7a3Adj73Qjmh1TBzYuU6LOW3XWPGSzq4UUCLwHaQB0KtzFgSPTBEQ4Plq0M27rzbmxTzeBNLVqK93mCLvRZw/D0WA7uqXw+6MVp3nWzc5EbWzKKFqQqTZG7FPeIqbCLt2jZt6NpWNm8L460vBtn/P/D6uGdKvniwBowXenbX8CtZHe8trGp0F1KyBooBy7T3dtZBqXt7kKKG3W5aWTHt1KzCooUNs9AOLYW+vcZOCOpNdqx1tG2PzHWrBjMUL8zdWPkgj9bK6k66k/fEAy3ofrEF/cgsWMhmsX7yVt1TUs6TYbBHVzI7DjdEULqgcy2jiWFs1hhlLr/hnWJlza4lbA0SYReUXTwIlRbgp2RBeqnZO/3sQJ9ramyFU7awcvKAu9bMtUwtUAflLUY8fhDlkEyr4mmbWUpmqYknl9d8v2VXozOI6VilQTGPm3KUzFGPjo3ObZkeJZiAHGKpb0aV99dqZvNGDKB1oo3dYIW6w1qD7zthRbtwMYaBcdAmxDpkv7k3b6hz3l3BL6lpCu8palETgexGlzuKmWe2o8RqiFBZMDc94ugEjWs8ZJFs4pT4tHYtneaV6zbxbtrellaDlmfwEfTj9P+18e0JoWtik8hANr9ADdcdIYfk4tJF4zHjMBbphb/qUUvRdiMKJjodGVfVuHEsk4wbPTRmg7Iz+cW2+d+rU1HOXgSbJHF0da5Gt0o9MwQLZiFmvfp3PZbCRTdWNm5ybVl/8I2BRlW7lMKCFVo+42jNDEkafh1B1zzV4DyVpt0bLhJh1T62dFoQNJ2GoM+ZippbBXlW+j2Hjdug83vyzDamy9ACluE7b86/DZgiGiM+m1cOuZBQJi/QdL2JyMQ6PDO527GIcivZhGIcslicm7y4tvFaRxEkmGfD8q+ueXtIiWOZuemB60c80yLw5SHjHYtgQto1SFQtjUoWf9t5zDu8tuhKlcKspx7UYddIEfBEvG9js+43Vz9rjQ50nYjQDY77pejKMX8Pa734tpcXM9wY6vhvZMrh1G1uLonZvdZk4OiuCgevW9xq4vD/svf+S3LkSNKYB4DMrG5y7u6TTI+g99XT6Gn0ADKTzL7bHbKr8gci9IdHAMjs6tkl93bJGxFjY+yursrKykIGAh4e7jXj5tTB9FNlvBX6BOO1v6O49t9xfLNIToxeVS7o5nx1eG7t2Gb7W6cCrfLAzW5IEhkeA2uBQE0bRptFAI1KL1+9txuJQZfk9KPRkg7HvUKxCQAmkCPsEKsfL/5nZhCts01WD4JqSldY7Nhl8MoCHXZ3VRwpOc5neFjFhgMvmHFzA8jXIi3TvWXgU9FmuMnXsYilCAUz10Tw7rIovlWwUjfuAqLB4V5zUw5bUuQ6aEF384BYHWtl0YUZagT7JjLkLc5z3JwJDgVRNS2y8FGMiEyK5JAHz+0wgboRpFp3+GDQp47EnLopaXUKVAJZAcESkIHqFbBDMBci0PJaMsMdGQEjtezqzBu/Bzc2CmeKikNXIAEzXhvTgfO4Z6XEYd1+3o9T0tJakBuEYf21a/1yule2+uVUMxiDb7t3LgW3yLwPTwSSCXarOCxB0Qts4/3HNnjqmryUHbdsp8Lqjx6855/weL/dR/K/xfhmOtkYeK6CJGHH8uxngBf30Aeq7D5pNuw2I6m0o1TPIAOjXQbsuJo1e/GABnYczRVj9a3KIRXFqTzZ69ykkLG4AwUWCL2xDG3lj8JWCICz0+0MVUSX0yEV5oH/MMPhGe+KnUEfhDLEs7qgxi1ZPbCQ2vOw5FoNaLrA1N8FrApyMdzCZVn79Qlh8YS+kPCmOiCNe0yseLMuxHNz7WIxQgwhYBPvLR6xu7V9AlQbXj0aOQYkYn7NamVW7+i/f/fEjHNS5JRQANxg+K3QRidu/vCzC1bJYYZj2H4DzHZtCKpqR6NhjQW1K4MhAvS1GWEcBkXVHXN6PT0+6jowUPPRK1sigvmha8twMXJzHXvOUlDtaBoM1Y72WJZyOp8rd3f8PILUJFY59w9Mml3oHij+vQj6vLbLvz8R0gBAP8zy/4zjO8wuz5M6OaeXcEBkA2MhYBCxju4fPNh6bAfesKLa5BxhZnQZgh0sjKkZJksIC5Aw24xN2+44WsXRyPfxc3hMmk9fMWaoKaWGe11HdnYPKWUMpudMPzReUzvnt1qxG/OqCvVWWopfJ0l4OwRSeinj4QEmdAyCZ6kWurcMZFMCZm+gyGJIqWf9ARcgCnUeEANaCNx504zHPp1MGQ28+XaHANZBKP5RBf8+8Ri7Ce77hCWTPBVmozeEgtvEBQddO2KtgkMNc7bW9fbJpC0QRYCUqN3xm1S2VFuX3Jwc591dsznmW5aptQe3wpgHqmdshlW/YEovCIeJu/3lXFzzzDey3tAgiWx1fO5qX3h868enXCSpa43xgF5szg4ltKwcTDqI057dYcZM74QhD9l1/BsQBoSQ32wzJpeF7J1rIXRPquTi1zugq6/7xLrGz6TV4EJbzx7/M47v5vE2IrdXmp/xJD9iOhy6Yk8rvqYvgAIbdsxD8E0Q7KgUyDCe5u75D9+bghp0BmAGHmpW1Cadm+JVvIYtyd1uCDg3JGxKKGDcnvXPIU5R7yInOzZUzHgzw4HwFVDc0x0v+uLCPo59Si8w3h1H3cBCIQNPQlUG/dWtw6fLNjCu7uTnON5ICWjUrbA9gjADPobi166EXqahQ2135bBQdst+3FFtTOBZUjmwpAqknl0rCnYXw2k6GIkc6PtR2iIg0tulo8EjpC43DS3ljvu+pIyHn2+x0tTC8lBo48fsAS5afkPxK8aOR2tOeCaq3q6xdeGcDp8xMx2LbpFiBOQxnge7CDtTIrJi1joOxPIXDIaRchmvCWeK87nFAtSZF/11xrZ7rydE7aIkcsRLMrzk2ubUprl9/z/L4HfzHs8dmSR/pvEPNVBcLbIN+wli4N/qu0lUbcUGkt2/JmC2GbsUFGOLaPTqAySl73Zwa+/BLR7nOXASRp8/gJMaf2RNSWhffsup6dPKEBB5XsGh7Rq2NSXsZkiO0/Hmythlw1/xBXRc3k7ntsgNDo3yZsid3rM6qyC0FtgZ54vE0bnL9PSy5m4c2/voSIttf7T9zrliEsWUKh5HQbXUfNsCuwWYXb7V5KI50hTTdlcJmwsLZOqLglgPYbMJVqV7xpQU6kW86ChM4guHGXISpwYKHpoRMoVqxItz6gBOJ/2TI1sNeMkZb1rwpc0jPbEIMD4OZYEqeSYafxueH9AAhrn5LJsK3DaCc/WuuCiczekVEjizO1ckAJDsim0d840AHJlukkTsGD3w9nPpgVSQ3zUgxah2tJs26hcZqReph/Wai4CdxOgDWiL09BMFXqvPA++Tx/4M47sCr3mWC6BVjGsjoZ8nc0yicWUXcIJueAMEMJe4S8N/nTmQ2iR9RrAmjls8y8ys8HrvPID2WDRrAD0Yhg7ElIij5mTw0g4LXl5yV0vYa8KLLbjJZ9ztr/iC/8SUqDPcAq694D/0f+CGGZMk9zdjIA0XC8CLThGEQDx5pPaEaDWvL/+vXqmm6CChhWjdFQmPN9K92JMv2DTh7uyDt5qw1oQlK74e2d+ny18e6mI1oRfsWsTZTUWBhOyWRSLU3CW9zfAf04EsGf9zy0jiimn+VSWhISQpTv1f1LMk51o7VfD33fC1urmmT9HiymO9Yed9sSk81EaNAxiz5MiCe1abcaUviWSo7SdNXAZYZspL+oxwLiZljkp9wfWNMWbV/T6ppyw8MN4rE4jv+b4ZKR5vxxRgwozFFhRkFHED08RCbmhNVxefV8ttUQ946WeyM2PgfX9//8J4wS1N9co+f/d/LxfnamHyTCyH/e47Nry1x2d59UzVsw3f1o9DPDBnm1A8y80gxlVaQUewoLSiWPEgODIaQkymeMamAFTDEr03L4jQp0w8K50w4+GQQ2RDL/g3fLLPuNkNLx50l5QY1IUwRiicxVY6ggzFy8moSP5+ow2SCLFTcdpYVUFKQB6w3yy0eg8r+PB2+3oUp8VRbY2CQQnhihvFLPKjmWEf2jPgQ9nWGwodMgReWiQpJhNM4DlG52DAJZHRT4mcaPPPa8Zmk1uWxs0Ox+NoStmdmz1ZwWf8G2VEHdMdGx4CnIqusIq9wQp1CKKdhROQQ59P4xxLF85wC+pQrPoFL+nfQZ8z7uJynIelYb72xCRGtcO70MYE5Gxhf/17BOCx+UKGe6k3M3GmF1+9N40mo6CVsXvtUXPD3cc5/jMMGoa+z/KfPfZnGP+wVsMz0vOzbVQLvqOti6vui2e1d/sLxl778MUC0NpHo5sJACabMdnkryAKC8QWn75ucSaxFc6p/1yNDQnVAETBS8NjDa5oRmZDEbY5L3bDLp/xFf8TCRmLfMYn/YxXo67wv+epZbp0tQCOytsx4IsDPciETvCqhiUJ5qGrbnMpSeLSlLNcvCkiiTVWgYLMg+pwSHB4w5ljrQlhTf+2M/DfK5qpKL3jGCgpVt5vys35tg930zBz3FByu7aPmlFV8FtRPJRWOL+7I0Y1YD/i++ZnrUre8++7DruQ3lGYBVgkYbd0KrAB6NoI6K2+44LebNAdp622o/jOJOx0QiuhZ8qDM7YX3K7BN37ejIkCC7nZd2qAOZOhUdIGjLjacQqe8XiWM/OHi8Ilifmgc8uGoBu7OfLIuXiSi90X8exYvlnMGfy3gBp+ZbwAel2+j+Tbs/aMwTMqcC3gfHOM0nZJypA9dCvvGS+09rYOPeThdANiyMiYURiWo2ABFtBuKbUAGzSbPHiPZd8WwwDzKv46KJtFNvpQxWq10ZvC1p4FFm4hCzJukjF7phsOBAyuDJoTxP3anGnhgWgP12CleaYa8PWIohzP+5aBWQVvSPjk7r7QBPMgWyW15oix8y0w7Ph31LwIOl14ccGr4SFGNCVgMjSvtMVpIsUisJMbvNVeqJnEIFlBI8uERwU2O2OP6jNpN0P1zkPaz/M7o/18ws2ov0ttD1ceC78/64Wyq/ll/N40Dexoi7uZIg01hywTKromQhTJ+B61Zcjx+25vrrWRme0ihNG7HkRkvZ1qllDtLO9Inu9z6iVJiu93kb393uE9L+vuOLBql3xcUkL2uQQAb4fg7cinOdAgn59kcAH8BTX8zdFYDU8ujCA/JQmOk5jPY089M4h8ghEiV42CmYqiuOxgFOCKZc9zGXSzr/xR1FoSg2zoMYyOE1fLn8BdAxJgwDY/T46grsW4KmcBntHZmfZV3RyNHUVdMS3OddWKyTuPzEhjm5yk670jyEK44FDXwM3MV2I7WZL6zR/Pp/7Dumc2YKhg989tSlw5br5d+1Y/WpPFMcJPBc0wtF1bX4BXpfZE9YJdwCU5cSFZMrUlJj8pBnTPhHc+Z3VIwcz50loatc0AzMjYrGASdh9G1nrgaLsh8mMvbIeBZxvc22aV7joI8TcbcFgIhuDYs2Aeky27m7LkN8srZnk54bFjdnwdIy93hA3eQQxD8nIdzJS7Mwd1fhlJkyV8wtTma0A7sZDmIfD+fENhT2o4z67jn2F8l0hOTPCrTkM35gue5RVy2FsP+pRecJPfULBgtvnU3ZNRWqZ7czGaaAqoqNDQKPAJX3y7tQzW1kmAOZPQP6ceXEI6svuT9fPrljTWBHkANLEdioJ7cXH47JtsOKyiojRd4OrtzfH68MPKIngoBYKOIQ0sSE1daoEgZxalmlCQAIAA2b3mnJXw9UgoyfC5AMgRQAhNzEm96GLuAJFwPwQYGBW85oa3GplQP6dPJZGX61DEo3Yh8zuSG2V2M9FHlRNjIQsgiV12VYEloQXVWybivpth826/igrYbeCxmrNWAql0DHvgwQaeGzSyUWxlfCyGIKGkGymQHmiBXljruKsHyYsyWIxd32Cpc4wjeTgbVVafC93RIji4/gHfjWfQQs+4mSkf+oBKhaYKTUxIKl5xsxtmy9iNLedb5Xemw/UUSFtcf6r4awQ/nj/+5xvfXFwb+bsjXvWsABDY7nmld/sVXYH8GwC/GRy7jay3WHjCRpZLN4MKxWFsoJjdoQAAZg+6t9xbJovH/dBl4Ht1XPOPRrUuLWmIZo39pNWgdqC6d9z4ut0UOjRe7KBFe6ixjQI+PCfCHUclLl0t4eHsgjmxyPVAV2ibRPDXPXuFWvBJ2NjQOpK8+PWws7/ap8IcXCqzVxwMvlUDcvDPawYRwVQN/+/K91udjfWpuFSlefu1AFvtb/LlCEgnrscZ5mi25+C53VIClIaoq2z4K762xTd42jSW3AZsd2ANoGLCrQVbvbAHiizY9a0t+G2+pYK1rj3IO6xwHVkmHPpoz4lBCtsbVNgmPOO1nVOnrkVR7TjdF6NzcG8VPgeYputwyX5DG8VAmckVXwD57PTFztxRA74c1nZt8R0I0CC3n2nwu3mW8f5Uy8N/2fjmjDeoM71xt/fTjyvzGHyB7sE2bsV2eyALTQOTJCy6NHbChIRZMqaUWvZoICQgEOw4MCOj+M3CdmJjRTdLs8HZPKhEMKh2XunV6Os8PhYZZhVgAgf88RIAACAASURBVKCS6V5hEzbvwR+FV/qxHJ3z7XOMzSdURXKc2LDJ3gJMseyBuMDMml8XGyOCqUDct2ZxYRyyC8wEt6zegixN9vE6Zn8OimJKYcyZ8PXgezHLF5gCqxlUFb+bYUqJuwZzc04NDQsAYDNGLBKbFybXHc1OPra5MQTOolAvXHobeHY64SoP+pnhTCsc9Ww5j5wiZgk5cQ5crdGDV1vtQPFsNMt0CmQBJ/CYvcWX53pubhgTiciQd71Dbcchq8+dc/DuFLAdpl58cw3hZtvers37FuFroZrH0qYtMUpE7nZgtYKk4loXnJMprLW8XtDO7eeJaf8PW4afLQYKdKPKP8345uLaSVLP9kEx6RnsMLZo9uA7ZhYVh0v8sUlisQkzMiZJeMkZcwoXX/bvQwG6+xbfOgFTigLeWbtgrKJfM68YWaQVuoCg4fD/mAZJKNyzy/7uRgmbcfX9QLQOH170AIBV1hZEwl25WMFkE15xQxputewdSAy6qVHdqhlbqZXFrsCPu3Mvi23F2Q5N4rGQbzvnikMTShKkI1MfAqTK/ecmJ/wbSFhVcdfqcIgzGLwjDejwjQqDeDAY1Nkg+8EAfai5XkW/qSKzVt9VdHW5DOCGKgdWuSOaY047Jsdod3trNYPd7idaWOv8smgndhqaVRxDZjtSzKqtDU6IzDan6bSwBnQWRS5+/8xqqx0oidn1dZCJETKPCsWO7EyLcS6du9H0gyy4wjAzkNtEk0jszXwzWeL9YfClDJiQ32W4iYjTzzL+Ty7PhvNJGTzw/h8/4qT+meO7imst2/Wg2/RKLwUBtf3p9u2kMYqECTNmm7HYzMzHK7O3JJhzdxCGUiRG0fuTouATq3pxzzZp5+B+ac4sSDhr+iL1Ylg8H4isV1q2HXCCotuzTPKCggWTzV7ik/acHQe+pN9bxnbIgWLFM1wG3QUTJiQsadCzGN4bAO7V8PVQ3HJqW3tycIGX3DNZYqo01AyMN7uWLotlBhMuVNX5wIcZXgTQidSzSanOZhYtsIY3O2AVyF7F3514vyUyRW65Ox9vQR9T4uS3xCCsDd81330IegGSC0BxjoqY4BWfIQ4v7LJiMwazit11FCafW9kXyeoL5qh3u7eim16CWszLkm7tucxCa4Mcqq0tQ25OEcNxrroChoqtfvEstMui9iw6GBIfNUf8MZYZQTd+jglesTPrlwkrCImsWDG5F9uCiWmRWeP5hjLczxJ36fAbpeHx2jAQm+n/9WPO7J83vgvjDSqPDDqjH7+mDl06fCxoXyE2EyPo8HyO4MXlFO+HQCWcgBOSoukgRNYWFjvVmwAaV7YVFhgMBD3IxrtGBlaEwciaewQzy91F2yNjXfULqu14Tf+jYdMLJhRJWN2l4p7uLWvLmFzMZMaLveAGBupJEm6JilJxE8S5vdXa8LpJohhmmJP4dp/XqGrILWbca6aIjfflh+PvPmzhDBRNOdzmaDfgNQN7AlINZgefv1vCXgV3OzC7YloORw0j/hw838DNQzh+V/VFwNp1frjKWW4LheBVWAyazLBaxYzClm/7hHviLmGSG+76Fz//MYCOXFk9BUYz6rsmCew1o6Iv+hG4gXNADc2A6HJryYN/jM546L6CKea2DNgslLDWAGm0LwDvMd0R/33KiJBeH1E7KOruhrYV3jkngOINC9hUBKN6H6y4lgO/s1sGlnwuLP/4oQXA0DTfst3//Uee1T9rfB/G65jYyY7kI/rL5bHkdiaBhe3uUjzinSEFecWgQk8XDi0Uz0h5XqzYRlcU0LPdVuTSziQgfODPA5XETChscwxawA23RYjx9M9+yrCgWA24Y8OX9MWLQXRRmMCgO9uEVyxYJL8LtPF5eE1YoOMCkJAlu9KZ07mcwrVWoBZxDicJ8TfjYrSBffpvR3eKyO7Llt1HjULoANCZCeMlL0IvtDc98Je64bNjqUtKuIFSnpvaCTfkdTasplBfaYskqGrbPYTRqMUi66+b0BXlKlitf8Er7gIs8hmrffHvdUd3cHi/owLQkoKuQsapfgSbAT1wR2COzJjSjgN+quGV1jvl0GYOWtvvicPeWBHn+2J0Lb5SyD4a8Te234fQei8uJgCbvZHehk++49rI9MFEprFjvLcMvBbglg1nr+ofO95nvX/ebBf4B1gNATPoqWHieYU2HrsKPPfjhl9Wf11o2ZIW5l02cSM7JSaI4E1AW2jbDu2KXMFOiN+TCB6uRpMltSBNbDZhAdV5V6tYkBHqZmEseG4vpQ5FVN8BUGPYt8gk1lNHgjdARoZgdcdjgWCR3IuHTTWNwZ7UfGlc4OqB+KjS2o53A0Sl6fTOiXQzcwWw3Sln5C4bsnXnCS5S3sVk/f/+HTCIL5LxZjt+1w2z3/A8D5e+RGp86V37Fdod+a5mLaBOvohMjl/DrwM/twDOCOCyVVgbcMggOhr7nOli45GlRhPEWEuIADsWxc6wwbmgdcJyAYReLp/b5UdH1xXgnHxcfwbwLgDHuAbhcfytZObk/WbUuU5ImDG3jk62sHdt6NaO/vQdf+QYs94/b7YLfEfGGypkEXRjpQf+eAI9G9ES3C1MouXVuYZR7ElRuGGGGzzE3ZkMQX9K5jSpCJbWAxb8+Zxwgg0sHAXFa/eCyQFBbBYjQEbwDbpb3LS0iFkgRrYC848Du9B6uwwtzk4AQvXjMxATxuCNLwiDHoq9OzprClM+ViQha4imE5p5OwQovE5bZUCkI0UEYrIVNqA99pLDVLO7Qpj1671kftN7DYEcIFvCF9yhmJBM8ObJfvCMk7ENOBaJgIxW7G3JMXjRRwpWNyhdXEdjSYLJF6GHChbj+1Q5UFCwgQU04tUZpu48MUAAsZMadyJXJk3stALPbX+XThe7NkEEtJBlAdCx335PnBX5ePz3hbFnCcqzrFecsaD6TBJRobZCbW7nUdV59YlKgJMtCP5z9xLk//caRebwZPt5Rs96K/7M2S7wnVBDjOtKL0OmwF754zSJw/4nhiBhssXLKgUvNnuxKbVVeRSWibEPaZl58C3g18WeddJoxqnP7Xttjx2oKMi4u2WQglCFWkWGoJLO3wMGevNILDqRfdFac8IhFbts7XlFunoZdYMNkxXMri9cQRPMRmz3/w2GDQeKl52qLwC7VWQTLP4ZD6fLpSqOXQN/3Xl9HyFUk0nzWmvnNfPakx+8ewNEvN7QW4rDTl4BYoSW8VUeOEzxYnPrFAzsdtd+xQ/jjX9IhZpi8muYkfBF9xaY/QI5bY1t1Qpgr4J12AqH3fru3YJTevEslEFxzG6fUbTYjdgxXW6g3jc7jKwGHq/juNUVzoqbU16lHIGPi2RN3GaksqXSgus1i+0c+XoJ7AlmBw73aRPx3YAsSPAGDoGTMguyJWwmroaZW43gurv5eYYWQA7A/rTZLvCtgdescR7HbhygU2wAn+xDc8V1RIjJmKCiSJqacHkQ64PeNHnHVIjJRBYb1foYh/MVV9X2uAyshMMURwNLmA/csbYuuHj/4kWYHRWb7HgxBs9DBjzwMmEPObDFLiAyYVQ3BXV9VlFMNregugs74aL7bkYh/pkSdselV9+sx8IwoSAMNUOc5VFjoYnv4Sw5CQ+woZAG9B7+cH3YKrPcaJcerzG/dr5wwYRqFW/yhmoVL1gwWaKlEuTEXe7XWbHLgQMVi81N0D5aZbR9P4bDUsO5YyEaMVW+glACO9JitzVBGly1Owxw5dMqzjDK1DLe0/NOhpO9iHZ1zObP6ZSIcM6NRNnz/P+jLPh8rmfLrKvATvysdiChPMUMwpVlB2VRQ7P3UMMDcpIe/ZmGcdX7uVLxf8L4Roz3bEj3fNKcyefnSnPPirlKT11/QRgpphC6kd6p9ai9jTcCwqbn971+UwFBxN+SCJLjmbszFCLoVhxQSdixY3J7l3C4WCU1/7bxcwHAbndMQogkycjTzdjsDQ98AfAZu2woKM0pYzzpjNLcN4rw5thB6EGFi8Ns0Zu/IxnZEPz8CRIQg7flVmObdNC6Fm8kefhddsvS2khDHOcwYPeoXDWu39nVOXsIfMHCarlwUViMdKXoIjxAy55mMImEXRQHHrwOxgbvYrktOuYLCpTNLEtK1HiwwqYAAdtim63OhCorwgjRUJ1xUXxenoWbIgh3zHZqrJwoWI24sLWiG3/Ow07uzGToTReht3CSbhz0IuL3jzDgj4prraDWxiWQy/tGj3EcUjFZQTVtJq6TW0z9hHH3/zfjm6GGj2Tq+LePK7Pj5FjSZ9zkM0Y+YwS3JOJ5DgPH77V7nwXEEAF1dVgAYGA13zIrqA0VI4JG9syRduDqTRu9LbUFTnMjQSiSJcIHMhbVvELuxp0qC3bbAOCk05skYwebJ+J06vB+oUnRnTK86o9EIyMTvKU3JHz25oLeOr2aYq8GA90d4Hb0qMR+Vw1+MvHbyHbN2O0WBTWDtaAcIj5j+zDQO/J8SWzc0GifLpZxdw2NUas5glmxgru8YYdCXeym+lY4gYR/wjwTFiGP+5YyalWX+0wgk5q7JBNFlsXhnsODVrAcOu2qZa5xLh5sr1lqlgXVu+LGICzIp2IdbGzCOQuYj8E9KGGhiHbNfAFA9TgF6mfBN6hsqXGJx2P7gqN0P5nTp3fYM3dZCRWKO3Zm/MrvcPW59mv8mPHtgffDlfn9qnvlR07ppZHWBRmzzbjZKxabMaPgVaZTh82hcBnFThlTRHuwtsIBzyumI1rm2EVBvIDUtrhCDQjjOe7ORIigUaRrQKxDwD3i5kY+4YqGikP4L3v7GHxDvSyLQypIxI1takEno6CAN0c1RUZy/JedcuILwiaK2aYWoKsRYT6M/IhdFbsZlpSaytiuhirROk2pxiWRgxsMBMDlGc1w7S6LBgf+rr6g8Xow01Ws8sAuvbX36hJyUnMbRPR39MYZKs9lrCDkc68VRUIz1lCsYJftdFzKQRZSy3RDSsWD5wJAkaWcYAO+5pz5ct7UU9b47m84JxtnHm8/ny4MNTUsmMfQU/C9Fp9PwujSHTI6931sTuIV5d8PAKVz6Z8cO67/KgdudnNOL5uJEgQfp0m/xj97fBedbAyyfPzc1nltf4yh3macpHhQmkHqS8GM3Krbt8zus0cFHs7/5Oud3+rBwGDYUT1bZQ5QIM0CHoBLJfrPkiDebkx9MYaSYsTJdmxY5e5aFL4tPdmGv++M2vGAWFemUtRWgKsIIj4lCSETRnujyWYUy40R0Y7t77PJhooDD3nDv+m/IzvCucZWGIJNtVHJHkpd1hc39VQAps78ACDegReUr75zcEdff15k3kDnOwukYbbM9bS1+F6DItADroqedxD+tyrnoLxLogSoAfAiK7+jipvdcMjRFr5RGU4kIaUyFNGYJR62sggWhbIBi7pmxFFs8y+5zd2gjsVzzs0bI57dMdhnheVRsP09pnymnCWZUJ033JOcgJVYbIUL5fgSjCzzO0y74+v8bh54YLKJxEcLZsevjPdHjW8KvMG3HLdRz3yS/tYwUxxYcYC0lw0Hctty9qDeaWDaAoHBcHggZV5ovhFl6aU7v1XyGCUhD3ddFvGuJkIaxTKOhiFSN+KA28jYDpPzohLb1Khsmymq9ELj6Dob16pgIYkf1BqOhoqrt1zgznHDRHkqo+CQCjHBwwtujeJmMxQJ1YuHFYcXvLgrmCS1xWqWaKYYdhEIHLdf33F0TeIzih7namBghYTuRmlZL2lgG0LIvKA4Bs7nHqBz72wzVmwenJmZTVZQfVHdvUCZfIFLlk/SkEnKqZgbgXDk3MaIwlxJPSh3H7apNU29C5Af5IcfFb7inMak5KOgO/6cUrREr+jl4/fYsakHX/9asgvvQByLFsVu22mh32UHDIgr9yvs/rjxzRnvtVgGvIcZnmW9/N25k94Btskdb0hI+De31cmYzPhs6QpdUXBi0GWwLUh+i3XaV9uGtWzXjS7l3Gs0IQNWAUxYAWTL2OVoousQNIuX3R7tM1DM5yx+PupUnK8V1bSSBMmfhZwJM4oVD/gVdYQyggGB3pQRbhc7NjfxjIBZscuO2QqZCKDQzI4D2ajuxucFAGKYAHytoaV8HrEUETVmthnmPgm9GSLef/LW3gMFq2yAsUA52wxFhwYWu7UCagaD0SEHKg7c5SsXYOHW/GFfsKbXtgPhe3MuBT9a7ayFHMWnWATj2pe0ePHr3FTBjDidutOCQjbqRfvM47V60n05vv9TDd0rxHC9Hy6YbmsiUs/isXjwjW9AcUpQ5QzjNV0JuMK9xHG42EchV6FukjldltJf4185/mEHinE8w8neBeqRvmm1BZkdwaV1KpL1dmDEYwhaOKlWAKu2zBZJzwqmQhSjoiMN4Nac5+R6EU5FCmI/hD5u8aTN3jC6x16D7a53bqVzfod9x45gtBuPALQ513cs2AGEOiL4Nnx4gDqyh6ED6qwCbQ0KfP2BVVYsNlG4HYJkqXGC79ZhjKNl2tKz53dZbfCX42/SgnO/JqSJPdwhJLvl6KKLny2fP/nZK2j1s8uBV/uMu7zhq/ylYeJv9j+RMZ12GcG/3e1xCjaR3UaAS6mg26try2SLB9Mz0+GsNNbmrJ3n7DOb9S6eo43N8GyMiYna8a6DLaVy4uzG9eyX99yaPI6AM+L15vP8wApxmltQNiFw6yS0tvzrd/1r/GvHdwXejzDcPxqBfcUIhTMVhVg6mVWG3mvY78SNHlq2ZB/UtqVlW0ZquGECPdB27xTjpEsth4l23esnSCYtCypWcEjGbK/Y8ObwyECl8+0f5KyKBfRqNHnKHoQtYZV7y0ACwjiJfXvHW+gLjJQ8AB5MEzb3HfuavuCwo3X9rfLAXd6QlYW7F5v7AgVt14/Xn1BBsugHGwMsnPnRO9DOm3XxY7IDL/SRM4AXh1AE0nzwqilmZytUb2RZ3XFksoIizJDv8hWbvTU1MgbL2lwmRi80XmcyD4LKF/53IRYevmZX7YURu+3v0/HUsRU4AiyfF7+fG4nalQkdBpzhKQDDzqePZwJTMae6MM+4u3zWls9jHLb6fojQlsiESW4IPk+o4s02YUI+zYVf418/voNO9j6ze7aV+qPXM7CUxuONQAkw0JLe5I0A4A3OzLjb/sR7RYY4PhaTPaNgscn712UIKhThqKjvgnkMntOCQ1ZMdsMuD1TterxRRc5NGP1cQY/nhflhBfE1k9wKTQAzW0N3XNjtgYwJuz2YLQupVwWFGB2YMcM/wSqPU/AO+luxgq+eUQesccWU49+xa67BM2AQzhJOv8SCM8gaCclMwGEOL9jcMGES6l0EVHSA5pVLIs1NlIH9YQcSDC/20s5nwoKaduxu2bPLA4euDQYAOk83D8EsgiIkrOQH9wZUhI8e0LPdMaDGEHS6WQTdoI0JMg4lPlytPg+aw/wb58E4rkI5Y8t9/Kttp8V04dpm3GCM9txb/xaHRSW0n0dZ0x3AJnu7l36Nf/34bqjhWjC4Bt8r8wGISaJIQkXdloHgwIodYgLV7FluBASOwzO0UZAmRmS+EVgSGJDFUhMjNw8l/RVOa7riqqIDqNFtZCbckNPkkpDRr7+0YDBSlYIyN2Jvp+sQgdh/3u0BHSCFA8Q8RyxzlUe7ech2oKRmxY4qOyZbGgf5Lm8ukkKecNgTqb9fdnwWYAAcdxsxslPy+F0SoYZEMKbSVewg1Jj5VriCmuspq1PUbuK29gakwKhNm1h8BICbvQIAHnhDOAq3Yma6ociCsJyqSO84t3RmOE/pMfhW+wMstn03vWusDh5s8bfYxl+P8e64HyQjHwXrP26m6Hjz9Zwbu8FcuyKOderI7v+tsr6DuH6Nf/34L4UanlWCrwF43PIZXN/WBZzF9VvVcmsBJoFG8OCmsR0nnByiCaJYacpMMSoODxaUGwwOam3HqAjFsSj4RDYZmWh4eI2LjHq7Jid8acF3zMrG6xTSfQdoVRO4b/x9xHPj+TOW9p6R1bdqvcMRB7TpQWwy9O6DWb6CgSiw5Tj/wL8DM3ayWdNeiFGEcANALYUJZERQSFsw+7W++wVVFx1ahGH8NVO1jF15rtUrzH5NMfCzGSgCm15wA6I5A0uz9mkLtezOqMnNDy2uTzXqOOx676wbT+yeidP8LVGnZ8Llz9rhr9DC9e/PgvOz7rVnbcTj39pxRw6xKapuaLZCPqeiqMamkQPWKH2p1zJ+jR8yvivwjlntxzSb95MTYNBKwuCy2wMiCQcSILyBqk3YkFEsYfKA4Q2+76r+O0jlAoBj4GGmS7Dna/vvke3x2Edr5e0M1S6Gw+fsLdMCvDsKBVU3hJ9X04i1A5J4XaI1dTRnjK0gg+zestrD1vZZAp7o57i3zDj+Hsc6bMUin3FgbVXr9jkvyCwXIKfRXaCGSZKLZV8x3eG6uV7xkuj0QaNL6ksclR13tD+i/CTAzHjObNjIiQ7KyeDdcxnVKgom3GxGgbgexILVFqyy4qsk34X0bDVjwmZvDvdQO4P1gOoMh3PDw7NxUgJzZsKojfCMqdDai8eAOSzKV9ralf3z7Bzev88HuC96AL7ed2YHKNpeWpFNkLyOQNeLaPAZm3d+jR83vlMW8jnO+7fGNQMw0caVrWDGOsl8chyejapfqzywg9moesDV04T3zjAZqsJCsjnfuzsYj1ju+89HWlrYyjxjNcSgDU1vUeVz4ubvQvFn5aydGal1c8RnO4OmfHbaTg9iMS2zzkiWcMMnZJwz2ygSAmh6EKGpQK1WBsrAeJdBIzdEimhWGYLpdPsQAT6VLjVYTChKDzIfxg44cZW5JM6JEIMYs14oMMkNanT/GEWNxATZC3CU2DnadllE8Rv+V/yn/N9+LTs8QDpYd2pQPVqDRT+nnvmO2/JrdtsC4EkYZ0IQ9K71jStz4e8VOj+PM6zw4bOc1QBTQIJuRi2VtgOLAjYAc451GW75XxDvjxvf1UAR46Os9uPXpxaYKoatnlO5ouhU0XmfIbO4O8F+7IKqbt8S7787nprR23sRmJ/1Kd0gg8u/UZyCBF+3IoFNB6m9jtBDlukUlIFQq6ro7ghjAafrBUSYjhv20AdKuqGq+4jhaAR8kYQJk59Dxo4HJrm16xMjmjJO73XaCkfxLLUOuPB6CydaNcOckvtxER7ordiD9oXrJQPA5yLY1ZqlT2g6TJ4VT4kKc/XJWheOImxqoahR4qSgC4mhiRbxOz/aHHjDX9s1jDbd8TsYg2Bck2hsuD6WZR4eqy2zbY8NGecz+tg1ofgo+D4bkW0/K7Q9E1Nv7zcGTWdS9NfWhvcCnYFRZGFyg9kXol+Ush81vrmBAnjeMPERr/ejYtuJHuSC1sxIMzZ/7liUCuEZOD0reJ/P1NF2t9qmgIsL4ERLZivA9SpvFNP4vB6Eazvv2rIHnktwRQ+GsiHAqh2e3WUP0FFBH4J0CNb4IgQAu7650PbAypCp/RzFyAxuFUPrYrK5FdUCSlhwA0VsuCuYjVzlyHZuQp+30Z3Z1z4k9Gw3CTBDsFVzmIHnvXhSeMts675lgVpqwTuKb0tm0A095SmBYj4wb//unYl7XL+2N0Hbo5AKpSwSutRmxoRsvcuQAdiv6zAn2Ak28nsHFkx0Gyp3Ui0otwz4LKLevrexS+5ZYW14LMRwTroLl6aLoIpdAZ5nnW0fy0j2pCbkKpMUJDsXB1MTHfpVYPuR47tZDcA5470G2bEYNT63TWQXJxmx1CsVZlzVEzKydeuXGOPvIU4TTQcmChPXrvXAFJxfoFOrgskaW3NCGdXhhvruc2QpOGzlTZUSMDASkhQEtxRgYePQFWO1PLaS4WpgUCRM3m11tOupqMxOhwBM+xull5vNWGzBYkvj5IbU4gum1nYbDA6Ftl2LeLYZHYJZHDbwLLUIhdPV4E7P1rLgIrQYom/a4FpRBeaQQknSxOxH92GAr6+unczvlue0e0lw5BoHLBQL4iGHF9F2BKUv4b2dT5JywW9TC5TXYlWbP7a1pobx+2ZQL62AdR1/VBA748H5hB+/L6wdGNuDnx035isXggEj9terHajmGK+Rjselq9vJN8WNX1jDDxv/UOAdx7MgC/SunVPzhClvWjvjZPCunQh4MRqcIAy0obQfGfF4w4UCf4ZbwEiYKaaWGXJ04ZLxvKOjTC+fwU4W3121Kra0zyy7+Vn3E3YY5PySlobVirMZzDpLId5rkhtu9ulUDDkcr8sNkslYoiHBy2aTZIgxiIWWRYzNKiawkHbLDLTNZgk9Q42gSqlcBl3xx6dkLWgjsVgmmRza7PDClBhs10oFtHWwC+IxqCscSnPRlRjNMdfvonOfjw4X2dF3Ti3oTqcmCPGdUkvrL2MMhFq7bkOTaxwCdjzvqir2RwW08X1GaOE8GjnvKbc3Pt9p5ygJlLF+bzt0gC7EVXfyjsEdo0hucN2v8ePGP4TxPoMPrsNwxtViMPh2nVNyJANz7N1fLFowMBwutxf4bW14Wz1lD71bqCvxnt57OM/IdKPwJkjYbYNJard5HLe/B0tTmhaoMsvIMtxQwiPvbs8Sr2ldcWlqGT+QT+ccm+sYBUvbbseisTRb7wMLZizocpEJwC0VBlUkfGniXLQziqaI3hHIwHvLEXDNoRJ6tGUBUgZm9JgVIvUCNNF1AMhGZ+I58/EIvIeF2wV5vrvyGwhY4m5sfQ70Wz3AHC4U1L5vh06C3REBdxS5iZ/DesnQbdhbPQH9wzwLcIBCbUUassSrdm685plppZl+DCs8CbrPuLz9+c+fex4KPHFbPvTRZCPHW1dBnd5fnWs/bnw7q+Fdy+L7DPcKPZx+DwGPEzG9F578IO1x2rN0AZMx2CdBK0gFTBGlo9iej1oHUeE/Z779/cdGDNgElbXJPcZnI22pb2cVR4Mc4tpED31kwqO0YL+OsSj0GzrOPbLeaJBQFEzG4DsbVQ8qFJt077KbL1pFBLdMitimVCeDARsqSpqmHAAAIABJREFUFhSIo8+jDob4/7dsuGV1eICWQTWxgxBAw30DQliS0clYBZNKWyATzF2He3Ht8ClyOLbb/O/MWROoOKQ2QfwKcrPXoBnKjs3u2PHw6v3+Lijx2qtfhx40Qzs3WosDlkDbdeX2s78C8OclXJpfPgia4+9joL0W487wwTNc92go97P6yXuufIUM56huyZXT3GonFTyHZFzkixetf+G8P258f+fakAGOsnxADzAjrgbpsEMEsLihx755AC0ARxvu+HtkxjxWL05licLThEmWhuvGlkoHR1oArelik+3p1uvKGyUp/UkBURKqsjEiAmk8HtKRravN+rl3OhicuXBreHXoOYScX5z/5JoTL6GP4Lq1SaQF3GjlTcLbmh5mqQW4GFMYZqrhMMGmwGKAmiAJA2oqwGzA2yEecKOZAnjJiiWRZrZKQpFOgqoGrO4Ft1ZCFeKwxO7Qwt0NmGIXxWC7ujSn2wgNfnXV+9zUjpbJkbuqXfDGKpIkTOm1QVWxeE9pcdjnA480TwjOrIIhcFqf86O4zTURuW77P2Y1aPv3FLyHjjQe94AMrdFnfvAoHdlHTrMX8xzS8/dQYb0i5v6vjPfHje/g8Y4BI49/APC+YDCKg8SWmq3DvfofrZlZSmMMROvnyJGNEaInxOEGhwFkp2ORp3oNpvF73ByreNutdOxt3BomzyyBsyTkOJIU6KDHC+kFtiv3NqfpJIATN2Vk5dds99phRMbChFkyu7+GrDWYBCUxfz2U3FhGj3NmFYyG7MFyV2axj8qs9ZZpCz9nww2K/5gAEUM1wRQ+dSZYVVDdpRig99tbZZDelb8f1vU3dqeLMcNVfE1fW9Fzkw2rsD8xNIsBNxJ1lbhqewuokbUS9phOBUh2cJHJoBFQHUWmdKJnpZdgG99ZHGPMSsfvsmrH7EeYI7Lnd8H3A8oYEBnyJbNtcymC+nH6nfdQsDPUP0b8LZ92lkxuSN8cs94q+6/A+wPHNwZeeScwApyLBteiw/gv0FWaWBTZhoxhg6W5TUS1vWmqxvHHgokaIAORHeB2FCHrJ9pu0pGWdnaU6FmsDBkI0Lu+WtEPF5x3gAjGyjn/1vHceG5qme6ZvdFZtS7yPWDSAtrjJJNe3UdIOAIpDdcaZCQsmYaVB9CYCiKCAv4brw3+bAIQxpdr5WObBv1LMYm1bFeaFoBgr4JN+X9VFt9G9gKt41lQC/bDQyvGIh+Aptu7yYYDqy/CK3Z364hM97ro8Rq60kRaTrj4SAHLTq2KnUfQrXSQgjzht4jvmEaiPUjq8Hh6F1yvEMMpARlw3Wf0x/Hf/iFS/9d6QG5Nl5IAi4Ic/wbP0NOT2zqy3io7xD7Kwn+Nf9X45uJaOK9GAAHgEo4DjnYJysx8p7ZtO09wtG1b8Cmv/Mr2/kMgj0AZxPkpvWDVUYZvyCrtzIN9RhMTx1MjMMctlCQ7zkthH6UNZVtkxhsusLU43tnvq7THW6D1YDGyMwS5YdER/DMyskU7K+2PFjBjZUsu4YVX1w9XIbMAyuLYjI7TRpYzOS83miHUABNSv2L7kkUwZUNJiiUpshh2TXgYM10zwVp7wK3megxeUDPQoLS648Xu7IUVO+5yR4ihV9sbFklmSUWy3AJmSEOOAZTfS8FNfmvsjsDo1Sq/y7iukjz7racC3AkuS4VYfct6+9wYub+E1c5z8tT99gEG/BHz4cqq4YMebE9FNs+yT9lwqOJxlpA9ND/t1jO/JiKpXedf48eNb8t4RXyrlk7BiyKLHWs7Y7YDX3bIDiPzFaGI+XVce+f9h7ZFFGQcuCO6jFSPhm0B5+YDnhO3ozvubcUPzQQeOnRrvZUX0eYbmXHXVXjfMt2z/YBMIuhmmUhk9yZdcnOnUxbes+vONw6IoVjGjOLOw7zjixDXnZPgtYhzaqMLrJ/VDga/aWjhjaXpMPJpgW4Nf349cKigpv7AW804NGFXx4eNmSwDrmfOkemqYVfm5+GBd8eGiopVVoojyb03wgQ9DKE+1htsALQuxfCMzjJhkc9Y7AUTZjSxI+9ui+x5tGKKwuhYYwhaY8zFjtsO2/kIgg0iGzrdBu5tzKkxS45v+PzYFRf+IAhegi+fG/dC8MLFM+Hq1LIDJglxa4+SmGo7DgVUDkzygitL6df4141vzHg5gYsXF3LQwVwMxk5Zwj5kn/FYHMeDUlOdylAvnIz43LvOnZZVHAPzobauINNRyGZCybcW4FiIITMisicGwrMRYdzUOx4tM302zpXm0GQoDXseIZA4TjRqJMmYbGkBYrIXUInLO8vsFdGFRrw6hMVZRLylhNlFashGICYbDAOAZqFrJRY7JdK7RkRPjY89HApQb5iYhIyE7PDwboKbCdQEhya8VQbew4Pv7tluAvC1ajt2dUv43YNoZLmHHNixUfJxgBFOdEAPXgEhBGc7FsMiCxZ7oUaFvTa1NQBYZcUdb8TKnbsrSCcYKh5vBV7pj3PejVks3Xw5zxl8Ded25OcB9tm4LNgf8X/fwRFnveD+WEKPnR2Eih1kX8wO7yykVXzstn5hvD9ufGPgTa34E73gdWAVjBlKlqUFuvh+o7X27FnFtlpCFJ34PuK7I/TQ2iMdvujb/QNmUQVOUFuxHTtyWpDT3AKwmbbi3Fi461S1ipF7HMTzyMTU6BunPrljgYhzATo9LbbDAFqWmzEhGbFbuJJaOEiMlLYXmxGi5IvQrjMkG5N3mk2DZsItG5ak2BNZDJtKxJf291vuN5o5WPjbZB5I4RKOQQlzTi9YVNs0NSz4UMGqpJz1QhphhdaNJoJqijs2rO6WvLrU4y49Gw2MOyruERRGKciKHZMsyDahoCBbcVeRgk92azS5kE3aseGww3ceVHAzKFS4CKqNi2Vqv7/vEPPGCyjC2bcXvAaY6l0QHrDX08/jcy6wxJBVt4dQT0I21wDcgi8A2DFAFIqqd6gXeUUSUionreJnheJf4183vpnV0IsYDEYto/QtNICGy42OAea6tsPOtdFd2rEbTODBShLELbpjKxjjCkNQEk9h5upRdkBtI7f88rre2669kcNGN9ipZVnk6o4E+M6MiCIgoI6pXXnGpVHcskyYbMGEGQbFbBQqKShs//WvQr2an5HxKqXpKRTXQYiflyTI3vgQ4uK7CW7JkCfFVsk6OLzwlT2Yfp6q47M8x8MEt2wefBhnpmTYVFDEUJJBhMF50/5lVRPsyoyZ722nLJeYLb3VHvKGw80qQ6Mjrum4+4i5NNnSIJdw5shGXeFodHlxKGZCwWsqOMywuYdfPGeyTwCAVabGjEiSW9AJFbk2ny7dbe9agJXBLdp1MRRQOwMCp6Jc/Py3xHKuY+yO7HN2gCmwYwzqY1s0s9u5B91gCPl8HW2lfo0fM74x482Y5aVlZWIXfQbX2SUMMZ2243U4RgRS2re8vCtytUA9BG5Yt2KJMWYAScrphjn0DjGF2oajAlP+5K/hTVCtb2+zvDiNLfy22DU30pcC0xYkqG+NP9pWdoYC/598azzZ3GhSS6hueefZIsxuY8OY0e1yJmGQVZOT5U609ubELFSE/NrfsuIhCVITNmE0mYTNEVMyFEOjghkYuKdEyljcyrcE3DI/36Mm7CZ4VBbUFMHpZQDfKgO3wgVvcGD3hoi7vBHLdfH2GCO7ZJHPlAK13kEYGW0wGyab8IKl4ZKf09RCh4hgVwIXABtlknAnEeJHbBpYsdl9gKm0QQ5Ax/OjKGuihB18rjY+7chscbbAsy7OawH52Tjhu++eE0H1/WOnn035rBMmPN4nz8/v1/hx45tZDYvjkYCLbUiYrPeeeXJp62ni5QEHjkA6pRc/bhom/BBsfVgrJERRpFPMRn4kn+vvlxwS8cy36tQqvdfWzOpC0gzIQV3z94aezh2I91fvEmJx5f21Sh1esAk3e8ViMwoSbkPQmSShiDi7QC7HgH8WKoAVCbiGf1kc212SISfDLTG43nL1TLk0bdwpGV6zYkqKR+3XVk3wUEFOLu3owVfEsCoD7VtNMEPLeiM7Th70RR3TtUAZ2e4bGsqxUGeniI1c8NloUbTYrT1WLLcAW5Bw+DSdkPCaChSEWT6VhGrAX/ajwQxU3krIVtriViyjCLUtRDJW+wJIFE17MsDvvNcExjmSXJzI9Ohzb1Q6k/69jzq516D3LAiev/QRbohl8AkkET/3FzZoggL7gEif71EgLrIgNEx+jR83vksIfXLdgATisVEw2YXdZGNRKrLgyCzEt/Hvvvi/A+d/1i4JXDG2fp45LagKwA6orTCtKB7sxxvgyj9mMA+s15sbJOPQWFgSDu2ZTAT0E3bdmiMoPj2yE15SDzzXgHu4Lq04x9YgrcGhuJ7CnOAwAPBaFJ+yYvaAm8UwJUUVQxbDo2aImD9fcWiCiGESeCGO2W/y5ggRdq6R42t41IRVGfQPJZ4b+gt5YAZMibgvr71gFLnJKNhtxSwLFrshxIgyCl68OBauxgZDBs1Pb1KgFmHEuxNFMLv1EDvheomIdvYCCK83gR5Hz63j7yYvePju5dqSGzWGoCGO0BK/19LZNeN8M3QYYpyvT5kJl+Br/T3OgmHPX//0McdIKGzf52Zja3h2D8EvqOEnGN+B8Z63gVPYgwv8ZmLLLsDfN3tDHmAIwLvAxuzYV+DrTQD0bPc6RgfYZ6O1SerWMC7VjY0FLRvumXJgjfE4DScz1FYvHqcWhIM7PHY8xRgz9ZGfq+68cEsFc2IACWeHVZXOC7CT/c7Isa1mWCuhgRCgmZLhJSteS8VLrh4wDXOuqKKYs+BTOSB+Nz9qBpJi1YRqZCY8lFzcJEBNzKDNnIpmCbu3/ybpzRGbdonHTVlU4zWntOOKHZtszTEkvufgJ2fXnqB4e8HsxbERanmRgtecEbq9arQYmpLgJVOs/VGt+bYlCApocJ4NmFEwI2NJGZNl3N17LSQRd6zdHBKKwzm+kfm2jrfxO5bAbN1CvhWTFRg5tm0Setbrha93nN13AVRhw8+n41xHC9bPMxazHYbkqPBZaa3fZ79YDT9qfJdWw0micLDRmW2mu611QvuCFxxyNF6loqKKK0c16hcA9KIdgI4HCnpxzSdMZCVRkQbOVekWdIdAGpOu6qOxELJ3yokkHOqC2gNkEUF0V9KT0hBIx2JKL7QpxLPnyPonY5b34roKgdG+1YrdtFX/FS63bgmzZCRvAQ6t3Bg63Cvx+JwUt9y3vfej4HD615wUc+a1XJLi6+HfTaP2cWzOUkDpmXC8VxTQogOtGnB36lgwGSoMq9WG7ba5YkRYIec26N/cUVictZH9TEIQfXKe8pwILz0qcejgJN8Pw8O5wgrz11PmO2yNlpSxpOTPyUi2QDomQBcLoepdutQk2hzAQNmKayYZcEhD7e4/R7ErDu/F38Gp+NQS3ObZfmEovA+43YBA2u8CGYJuvMZAaVXx++YYOudS22lEgfMX3vDjxncFXhf18xU1cN5eTW5uCIjtNp1jY/u5yR27PVrG0RoTbDiOdL8xZsOdGRFncR2jwPVZxGTs4KGwChJv0yxLy2AjoEaABfqW8rAVeYAe3m1FjXlUSQtCACeDmgMvtmBBYfblgZdFKAWtdRQ7XPQcCdUzX27he5fZnMi1pSoYAyl/ZsDeNYpgGWaCKSnuNeNeM5ZcUVxvoer7G07ALPY/N/4tWoiL47gBd4zFtN0MmyrebMeBilBMC0y3oJy0JibHcz/ZDRkJN19gonWZGDGbQ15yxmtmC7SBGHdoP2xq2JTZLnNNwjVmFRkZi2QskvCSswu3Z4gKsgpWEyy24JADky/+KgMjoDED1g4/BddXUneUQILITDTAorWlB9ZuvfMMjz3/3ndtf1zwGrPbE5XsyfPEmyrUaXXNpBO1SWb+ynh/3Pi+wBveZ+hC1REQm4XO8O/sN5+iQEXdiv2lSf21rc9g0gdDU/ca++pjXFuTY4gkZGEmm1D6DaVkLRBf5vbvqHekcvbgYnHkOceR6ljaMGEzbhe7yHk3tYybtljBgglZUts2mxmKUBP3DfSUO6RitgkVigWZBS4wKIWFzuRQQHB2X4piTgo1waoJW6U/3FYTpmRQ59/ynGTAgK1RwxjcDeYSjqNw+a7AY+hwA7rozVut2KxidQYD54Kh4qDsJhKKO2QcUrFjQwLNSxengL3kjCV3nJgwhiG4xHMmXY4Zdj+HYHMchkax4+MJs7NBbinh5q3UMMB8sQP6Li3of+QRw+NQRaicAWduepsn4+KcgKrqRa1nRTA9hbdnIjrvAq4p/ri5QS//vv+7IUF8QTArSLKgKmEz+1Vc++HjmwPv6E2WLLk5ZP97FDGuwTcegwEJbO0tVlq2PGreVuy96mx7w9zGBoUo1kXwHTFfGQj4oQOQ09xokKobFDsEiu34ncHaHSHa8dH1FVqvvrELCABUO6G+t0Dzps3pvG19w4rJMhsiqgc8jLb1XQBcQdnE3QSqilS9OCSst98y2QmfSsWUGHgjy90qGycUgrcajRDmQSp5Fxs1F/LlxhN0vQUGNP6/qeLwduTG1bWAFQ7cvTkiJBy79xvrAOIFr6DR8btKmD0wxoISqmhsRzaHGYAlE9suwu46mmLyOEUEVcKWCFgkYUrJJTJ5ze7V8FYVq1Zs4DlXePfc0EQQ33Focxz68Oty1uqNLsmgnCVMLsj06ME2mAk2BMhoQz7xcT/GbkfO7vuf25PxPIKeehShunGHJ0tjDn0rr/jX+K8d3xh4Y0PVzSKBfrONI7LhcA+4cnWTA/+TLVRMkn4Mdhc5fUuYAXdyeO2428DB7MfO3vW2O+babxxuEQtSAqrewd77jXxkU0z5U8OHQ1gFwOn3YDHE5+hFvIPZhHTLIQNt6TMKMWlULJhwgCpdEbTiWKztp7b9Xty3rCSnbrXiGYOnmuDrUbC7YM1DE7Yqp9t6Tq30g2qARgYMoCRDjYVAzv9X45ZVwYwutHQrDNXYBhxebgJyZqsLCE2WUIytIwkJBwQHaqOJReZ/r4pNBa9Z8MkTyFuOTJ9Bd07R3CE4jH8rCVBODajDFOLXK/QrqgKrBiRCWOeOFbvs2MVblgcthyJLg7zULdLJMy9UeINiFMupQ00gyQQkRdUIquMdQzwWURNo0NeluOZZ7sfY7UfZ7UeZcWS9hBwicD8zMvg1/vXjm2UhI4BWKOrAXRwbKa7jGXcxsmBSrUp7TMGilknFbmsXq/FAO7YmBx+42sHuM++ki6A7qoYFrSZhgiFDpQugKFaExF6S5V02cJW3vEoAcpJXwAOsYMdhKzbcUeWgpbbM5Kr6fXL3ANCdMBQFNwcZuJ3fFZhT17vNQhoZgBZsdxXsrhb2qPzd/LmT9FvYPIP9lBVJCFX8ZS8AGFRJBev4bgKbI6oAqxmOoYBWXWFBIHixGasHrwm3VtwKnFUBrFqhzWqITdm7+uKdgLcK7Ear+FtmwJ2EC8OSFFMS/HVjJguXvZwKaXbJIZvQIv5EthcergG8qaJGU4fs1PcdFrxZXtscjUAcCnRjMTf4vQYak7KJ5jhpIohMznQYg1ptpTF4IGTS8L6IxqAb8+qazRq4fP69AZPBmm4WNMK0VgP5BTX86PFdPN5veTzGNfi27NYGE0x3GiA3+NxOyjeJ5orOQgDvRT/+2VttVA0bC24AkGT2yQiITTAX6QHYyTZ+prGAFv8+M7cU30qy2l2bMEsV8p6pV+B0JtehDdv52QOYwgCjhxqzTGBJHQdVeLCFB14XIlfrnWhqnfGgxts56Gev5UAWw6oJ05F9CwrkZCg1QY3beiTKSR4GHMEpNqBAAKdt0ViTFLDi+fokhEZuiZn7YbSGjwDdvOEG7nLMitW1yYsAOYcGMDmy2c+z+AukvVA8RDFoJwHuR8epDzMcMOxe2K2g7VORBcX56KFoBgkVtEHTwAuvXNgZjBWHL6DJmQPoTRNtvl8zUTIODDQhPf9lzHRjr/IsMn5nljoU+zov+VfG+yPHt+vxXjDbK+zwfESQfR94T8HYeKzwRFulAtfgC0IPwf8NmUoG3nMWyuN3kXIR5xu7/ZBE8IV7uwXjAUBOL41bHOfYdV3PrrbMD8+OE2rcyookPOwLVCgOM16vUQaShUdatCeQw0unCLhuLt9pq4yK1YDqbb+HhSYymih5NkMQlbIAc1Z8KgdeyuGtx4pjSp4pcxF5EzCfS6SWvR0AisAOz4jNvEioWDBhJysaL4MrRvHzLkJb+K32jjYuKH1GZBEIyNhoEIKxoSMPBcBrCCsOhdy86BhEqymxCLdqx6I3q3hgwy57g75UFC/2islmZr4CHHY0uCFkKkmfmwY6Yy+Mte/7ncLYM4x2HB58PdBGELZ3cMJHEMK3MBHimCwinrQn/uY9+2v8M8c3Bd7rKv73BN0x2EZBLl4LnKdm4MJhuZNtgojzddELcE3MXMZAm/smzWrDeUP4OuxeQjjEamgBA8ABaULju2N17FIaVccieNNn7dEeSzI13DeGjCaZknC3v5x81WZ5heHAK37DZPMfXscRdwUEj11aMSz8zDaXaQwjylAby85aSADmXPl/OmBgcHvUjCyGr0dBdj2H2rq84IHTr7B7u2dI20AvkvE5F++oC6nKXjQDBDdNSBrfkrggOo8/4srxWXelz5tmivHMieLqeXjeItHsEdcbFxEfshgO0C7+EBbVCgomnQdhogUrZtzlDSEFudkbs1+3G4rvOQJjktISU3Xls7HN99xY8WyEH7R+EEb/K2lehHjCu42PdHjk1/gx45sDb9CCIuhW9MaGp6vohfEw+qAFJQ3o5PpsVKNKoKDMAWakrP5TeSw0WoMB0TLSeH9B4/xG59uVHpQTVcLEoiMpYIQK2IGqd2J2omQ8XNpB28dz6UG+R7Agusngrm+NemSimOW1nWc4J0QHV1fsJXe3SASy6BRjW+9Du4R1K8M0loe38kIg1tkLt1zxmg/M6cChmfmbMBuak+J3Y5Dbahc6D1FzHmPc+tJcRo2bbwF5tp8co1Uj1/ih5N4uSbh4Vr7mNRen1EljNsT58zqGuPqAb7dAx4Lha7EWeKsJfj+E8II6ng0W1VZXcSjG1m3qQkytnZjzkG+8O7XPnN9rUBRZnEbYLYNGVoOgMIRaSJaO44+y1jpcU7v8/NH43oCsoDGm0zp/FdZ++PiHoIYIviNu9FERLShoMcZMuB8/wu+ZdB/YXHYaEMXM2f/vL0SI2YQ9zOkWMAzSlIM3nMEdY5PzGw8IJgR3w8xVAhQIdwnACfO2Q2Ty58X1OLoEXzgKS4cgmlAJliYRudgNkxW8YEb27Wf2gpGBVCo1w2uhOM0KccYBRwTWuG0je5ySOedX8R8TIYaSFfdjQrXUOL6bwwxhWqkIzd1gRQg2DUoavJOO1vERdHkevt0Xw1zc602ZiQKxIAiWRD5zSnQmnhLwqQR1rT83uuR4bDZ+xGcLtsOSlMLsXjiM1ypIgwMosmNGV+aChAUFWVJrza4epY9W9OKcLdIth864KFtxW3OOY71dwyGy3b8nSNrl539WxYvvQ3utFSlH5vtfmVn/Gt8yvlskJ1oPxwLUR9J4wDkAj+PZFjsykPi7ghlT9qzlGAJwbAfNw3OzbwGlGavDDdRhjUJcP6do9wVoC0N5yUK6mWcKFE0plAW0wwN0iJw7N9M6BjylbucO9MaKwIspAJ7YYm0TZhSyRPyckiXslnCYuwlDkCoXvqYA5lv66G4LY8spAa/ZsGTF56L493nDaz5wKwe2mvF1nzzI8hpHAKYOg7QGimiUADqz4j+IHeBelZzg4bs7tzK7CI/T4eYsdBg2ZryhQZET8dqXzBCQa19UAjIJrWFBh03mFAJAyXWBpWlIkA3i1whgoEXGi7AsuLjeQ7Qe72YACqDA3VttFeSJNw+4obOtfV649OiI9SJ9f1LKGfOPvPhvHNl87haEoP+v8ePGN2e85997swSeFN2yB+hxfIQL95ZNAJK8yNSPnwxg2Jxwx536qtiwCRoGvNkbkvN2R3NJoGfEIYbSWBHx/hLOvw4DpBc2WtijY8NYhhf0glvgxjEOXTHnzzjbH/EGPWxFlgmr3AEAqzyaJGJGaYvOhIJsgqpBI+pdWhG4IhSw0CR4ycCnYvhUKl6K4rdy4FM5MKWKtRbcj4JN2VpcTSBCQZy3mnBYdw1OnvkFn7bIucB3KDPX+GqZnbI2f3jmnFMPIgkM3kAvAra/+c9zYrAGSC0TeFAufJNbNtyPEH3hOeyDGHu0Eu8Oj8x+fgrDTVLTvSC0wc+1KxkTqwqmcEoxaoyozAA+Y5eVWbBUHENrOdAFlghpxRxOwDvI4WcYQXkkHznYGr/GjxnfpU4W/75rpHiWvV4z3AuzYcySA/MMD61W+fVcMcZn+0R6kChejMF9x9YgB7WKDW9UQZO9YcIh85icJ0zuZocdclq8tdj5mml2H7fdCe6EF4gzsw0zRlDVUqJf3KErcghnA5TLlNjW71jxBQd6EF7spSm+8dpSkWuxCVBmo0W6CX2wHuYkLUAung2WROHzKSloh8SsdvegnnzrDjgW6h5qgQ/vQMNqQ4XstfBva6WNfHGaGT8P/Ps6B9V6yoKlZbHAOWOvBrwmw5wUCcCbtzz/b8uG6n5vmyZMYi3wvtWEvcIXC4roMFPvYu4C4DVlTN5YEe3XxWGTKQFQUt8AQiPqwTfkPOODVdsbJevAChhhJfXC7M9frDo3TujfbEv+Nf6Z47u0GmL8YSX+7/jbldcb2d450MYGfdjWQrl91BessmLCjHAcuMtbC7ppoHiRdtZpZeP2H4ibqTdJJEwulDKh+Vk57hujN2hQDJ0iKgE5hBddOdHPQiqy2g6VSr4vMlQUi5HCNmFmAUTgLbITJiRsxgaSdg09mN0y8OK6Bmw4YNBVE+yWUCuv3iQGFYO6Ri+pZKlBD4Hzxsjc6zsOa15YEhee6XZEkQkHtpwq5xqgAAAgAElEQVTA4B7wQ3SaRREtmBih8ZvcPGRxCOHfpgNJDLdcsWtqIU2Exb91sCEKfWA9BX/HxXNmN5sX8ELjIT5jdOcl/yxICVUNatQBVlEsuKFYwSbbaX6Y1NbRxnPz3dJPG8v6eTblPvtpT/ZPP7494228U1855f1K/6xwBuD0uiik8flnTLf/LJ4Vj2xacigrSIqH8TWLzXiTNyygceTmW3kZzuXAimAcXYsmYr0QZgM1KEmBpheY3pl9CyDe3aa6OUUn4Vx8U+/f3xHddPEJeo8/uZWklREv3yU0gBWTzL7FZTfcioQJGYsVzJKb1sGnwm6t3ybFp6LMdL2d+PejoHibMZsRDGvN0KHrbVN5d/9F1vpaGNT+l9kaLLErxWsU5A+bZ64BQwkAcfw1jhUuxDl5t1mK3zs+HULtt1wxiXng5mLw9Sgt2FbXEN49Qx+DbvGCnBrwmunETJeOHnDjfzZrkKamFngy9R6qsSXEjI4WLOwWzJixyYYVX2BJAX2cBJXe27r/TGPIeP37/ZXx/rjxzfbuXeqR2+grL3cc7wRy8D4THm1e/vb7C0rL+AzJChaU1pn0Yi/03RJgx9os1KNIIpZaS66JNswOQIMFzD9XtI3GGVcpgLnmqtHLLSWyL8YMOn5vDRtxLYQ2QEUWjA4d0RgSVLtk9AdLl/8WTK7nm/6/9r6uuZEkR9KByCQpVff1mZ3d8/3/n3XPa7s70yWJzIwI4B4ciEiqpmdXe7ZVqm5ibLr0SSXzA4FwONyHF1uJAYslRG+qCVwwAKDdJMZuWT3eIoERs3UOOajj5jTF1Kj+JJIqE1hAF+rYO0KAnEdPNbOEL6KaHdc+m2ExbBuDfmkHn7AEq1AfyZf28rQnurYF1ahB0Z2qaxnmhAscuVBwSu5SiOMKcAcrZPPNHXgLR+Rj2rGQmDQghkSAFQXFFT2u1xJqd3m7kkfOBf5+iOKzJbT5fBGKq3cFySO+f3xYq+EIDxwbV38ELeg/+Pnj1xMnPsIL+k8ScW4lS7S7HACcOgnPUPw7XnHyExxfsPopGBCKLhVFfqEylXP4ITmaAIbjRB6TiA7xnB4sBsh4NL+pdO+djO8TcZ4jvrcQSD/gw0vg1Jl0BVRuK2EZtI5xXFa6Z6UuwSKZgATXngsTp9QAJqpFHbeoQBPPXdVxVmBRIqbdHc0EO+Sb6lGEsMFJbVDPFmUSS0YFgCHmk+yDogYRwe9Vg4XAhLuI4NZn0k2WwqnYcNG4tgVvobaWppx674kDx8SfE9NdVPC8sMLNuHUMDLjHYtJDR7iG68e8JznOXEMEKL+mKBAXVGlY3FChSIft0ZT1vMafsdrNOEyuieLzLRB/nfhYxeuz8WWHB+GPbrV/WPEeYAULzFE9b3C5+1kAo0LNr1AJIWrRaDZJ1I0nVbz1NUZll0ELIvGd1ekmt9EsSfoZ/846lM+G9Qva1GdAxzQwpNrTcXmY6mexoMS48HtNh+TxJp84zR55Hkn0z6Yjh0boSLxGZ17BBLabU9cnbHkcEokNOEc10w24QNAgyCmpGqyFZEhcyuzApyWQeUIAjufCKjSbccPZWNgwW4XXf0IGGBNwi0TSjNe/FGdlHRoUz4vjl4Vi7gpaE2noSKT4D8DEX00GnzehgcFhVt7I5zKx6GsXvNbkJXtUvIYt+L1MrgFXvbvn2oGVcJeYXWAa05XxHBRZ0cPiiKyGzxiOLBh4D/+xQ/Yjvk98uOItkUiKT4zIIHeJ+O4PxA1KVPO+Kjb38C0wrCghuhJ8VUwuJrvfMzFbdGeS/FWiK93dwUHQgt3pibCANKGrXpGi7ApFFR30szHNFrjvP7opBQWGCnjnUIAbHI0uBBFH/ExlAbm+8z2nApaIktEQi8PZF6y+Dq2G4/nK99zdsPFFUCBorngGvdysscnmTtw0hw2qUfnrf6wOiwYbu/mO6oI1KGUnNVQTnHU2nlJwPStSFeAlXjchBFry5LV8d90FUHX8uvSgohHauHVha1SAL4sNy3mesyT6T55xBhccQiB8fYerQCMJPy8+joMqbfduFdUMm9sQQ6esJe++Jv1bhs7hOgDB2xW6aTds2PwFW39Bs2vgvKEA9mn5sQ9o4TPFhzHeRB/bYeSRYteDhQvgWyyXk0PlLvn2QFI70vqmsNaLJJtVWUILiwjSfTfVrRKby1hFUYLc3+DYULGF/OKKKYqy+AIXQ/XbHdNgtvGiUtcF1ulaIT61UrPqpZHhAXY5aPeuusZrFiBGm1WCmO/GylcKNtwCXig4J+Y7Eu+MN99hiMXFBbdOz7bdfAwELD492r5Wx1kFz1F0NyfM0E3QJUaEgzUgofO7mY7fL1FpnpSMiC9Lx60rdsyhihzRfa+LDABflo7nuEtKQBXmhB4A0sR+Wxs2U3xZGhZxNBdcgAPEwGS6qHPHhTTdnAJAvA+Iad/6Ac+Na7UZE+7mHQ4fCfcumUq7G/hJnP04OLHJDVd5xdX+jlv/O1q/ods1hJaCdvgpObzAqHgjHhXvj40PD1Bwao2SgLPiTcPBdxXtu41XWA4ijQ0RyaVSM4pJEsDiGgImGDKDx6aNHgwgy0jAgfV5jKUCuFlDheDsJyjO1GTVHRd/pmCKnDmp5FSkSrYBMWs22sxb4LWGLgtkyP/Z2MBN3uiUrRTcS1cKktNbiBtjjqhm4naQyZCVf87VAdz+krvMqvjF5rk5juJeoOjRaE+ftJeWVTPw60qlMRGgCuUl04V4DWgh35PK5Pz2TH4W4juYSXm3w3CFA2U03BxPIUOpcPzNdFa3cTynUM9ZgsXA8+f4ZeljAi3hhfx4MxmYcTIzkq2QSZdavKx066HSPd6XnB5UtMBoq+zY5MbJQdmxxI4koaBNrtj9Dbf+O1q/QURxWn7j+7YrjVTtCscUTP88od98/GA1/Lj4LwxQAFnpHkhX3MaGs8L8WRkuBdm4SF2mMhoSPuCLDItKVSGALyPBtDvekwTON7e/6sCqOaQQE0nRrrqiokkfGKqDI7su4RbheXR2qHrjL4nCAxukX1tFtvcyPFwL+PGEHO5HqksMUiAw3JQUr9hyIcGCfkgSFW1YAzlsWOzQHihEx1FCQMbHopR6B82AlzaVw45J8mYSEpETUiB3lpQtJkyMxJz4bVbXJo5FZ9JbMds1ZBIoTqZQJYO6qEFGo4zHeesFDuDt4KSR9Lc1kvIJTLi0Q+LC22zqSySX18H3e+uOW7dQKPO5cwJ7AmesUfN63GMA5BQ7tn1QETsWFF/R5BafN1S/kiKoJ5zKL1jkjBbGmKlY9/nifjuSouiP5tqPi49VvCIooqC5taB69n4JFyxZ8cWFdjgWYCTWHv9TLBBPMWwBwpiSszQ+Uh4n0hq6a1TbRHUTbjhGER6TBNZp7jhrweKKGrgbK19BRcOmFMYuTnR5j+rTpN/dj9OtmNWupx0QHECHOAb1zGXKTo7fjwZf8y0sfNaYENORoMdUlORFWQbIcHRLyHNiYqjxMxe/oHtHcbo+vPQGBW3RybUCLNTMFsHYbe6xlT8pK9o1cNwvodf76ziv/P4QT1c26jIRXgI2aHH4+YgnTnvtBbde6IRsihYTaD24ul9bwXOxUck2k4EJexzXSW0wMlKbIbm8mXS32OHXg1YDj598GXptzARcnWPCzQ1nLLgGzq+ueFVKQ1L5buPAQWh6NLtBUPC8/i9onMxqb0Mf5LOmsiNlc96ff8weesR/b3wY4007l+QCNCfOWAL/nN9j0y0vOOECHbAEYYGEDXgLd6eV5HApGPW1RMKkHTr/CEW3PfbqOQ2l8fRfRIaMn6OgdG7Fb1H5qiue8UvM5afpUEcJ80K+OwMU6JZTSws8Gmz5DiErjo4F/ywox0fRHor3lMExpvawYhOEhI6O6ja1IpIz3dHgMitzd+LCL86ke8GKOdei0yU4BhgEMqhYlHDM7TzTxq9rxRLjxjaun+NrW9Es2Slc4G7g+HApk1MrQmuiYoLulJ1cQeiB1azgUgyXws9rWM7v4RmXiycAXIqhuUYi5/EkxHCEFlLUh0JBghVyl4DrqHoRqmTZNFNUo5O1hkjOyU+AAJu/YAeTavNtaG88Lf9zvG73ih5i+p85OHqvsWOzUI37rMvEnz8+lHhJmucN29yxYm6li4TtzKGqyI9z6xyaYdHgQGi6YjTTVEgLa2nPA0GDh93M3Cru3gmzKjkP6TJbwvmAAuDUhqUjA/CbLPjamHCf/AzFBQ2GW7gSLL4A8oyGDYqCDS8wv6eDvV9W4EnTsjFMAQBm7SC6w/gjV1c+BCurK1cm1IP2L5165zHkQEVGlZ2VWHB+ASUu7IY15CUVk/OKJugxWLAqk00Ru9PDlahGixrcyaDI6y+SnFwOZxQXnMscD2Zi4yfVKbKp4mziBYZ7KTbgi70r3mJs2Z2/cwtMelVn4i6Z/imO435QgA6YySUW8cF6AFAk3CiAFZMmp4LpXAxgF4EaK244oP4rNtmgQougDS9j5LwE/6ajovoV1d44oZjw0JCK/Exx3MLZSL6P+HHxYaghxbmL8+ETz9l8PhrNnVUpfyNSlbAyBm/00MSP6hajwZT6rmdlm25zg3jqXpHtIPHazQ1mM8lng4ndsolLFiX/GLH9NluAwFENFauvWH3FJhuA28B8F5xjSO0t3kuCKgXAtIBJlTKz4HKGMDor0UMSdQwM+H1MA1GaZBasY0ET0QHVKHTYpOtIhpPuNFTM4kFbgKHKRTUzRo/1I+3iT1F5LmpYDlNj/PuzUsxHdeKwPPa96xjFBnhf/LJ0JnAQ602WQr5WDnl8bQW7pXFlshMIHZwLk+PFdWhAEOJgVX1WwlUnnZb0x6k43ihMvnkOLiXwaAmLIKMvW+Ljqy9o0VBbQdz3JM93XOs0xew+JUmn6WXcg58q+/4BpPCZDvEvFh+nk0VFuYIW2plcgXw4JQjsHSLCLWZ81wcmzHCkGq6w8orkCic391nKaJBkFbyKflNZA8R0r71jVcVFdbyxHg9pEeCiHEIgDigQF3Ss2IgkD3lGE1K9+qCALTBZgKANzROSNi8FEP6ciKLoGSrLf6qqSB3hef44xFFAYZ85eDIr3Zxq49ennsUCHYyIVQpWkaHMlUktdXBPymGDNRgHCqCZ4toWaNC6Us/hUozQQY70Ln18D4qxt6nBNljDkr1Hwk29hqx4PRqfW4iYH7HaRfnvtRNbpoGl4KUJvgRXN50pBKnBG7zhSKy8T3zcixJJN6v83YA3my7EV+thM5pUs3mNuROKeylgIY7d0nvPvMGsRdX73mH48wRLmntK2QPi/XHxYVbDqeQ2kNbfB7PYqIDYVc7tKdkGrFTNHDb8tiYVTXN7DIU7HxgYBm83IQ0ff4dJOiEGIOEKxs1smC4Cs9JLRa0VMraXN2tMVi7Dplyh2OTKh0w5MqxCXLWH8A2OrywKjUEKDcyXTbZyn6gjzCuKnN/xhgHmsW+dkpODrOAocXJ+c8Bi2AWBY8VcIHnuMtleono8CqfnVjuv4WaCzQrO6neTY8keyKbXGipi5FeTx+cOnBY/XAMddvMqwN4nBs9tPq9zJtxjxXrrrMpvzq1QDnXc+hTGOYq1FxHSEAXYdd4jT4XTbAkvCKZuA4dLOqobXrChow/2SI2GZvLSj95ruStpdkOzLZLuBjpUh3X6o5R8xH8QH4Qa5mz+SdlQeR+3jqHrytFOVkoCAZS0p807Umv3OFYMJA6McHYtwCG5ArhPvmHdUg5Jdhwr+FCy0ouqGHMLmiOvJ6HdtoPcZDjGRFmXhhVPo0hwN5is4V/lQSsjVcDRUPRpygYOVbIQ3TnooGrAD+5BZRswRioDrEO7F5hwQsILqd+Q1S2AoeNAHP7+3BynyrqzMVYE+HudcpCZUKkI5oMfy9emKluLz0+FKmhLbP8XpXpZD0Gb1Pe9dQQt7V6bd+s8xmlsyYU47YG6O95iOCR52qvmz2HUbrdwMM6Jt9SqIAwx74fj+3dwkciFf48KNycbN7kN/Y5sgN7861gQuzPxVrui9le4M/Ey6VZ89qR7N+7+uQ/1Tx0fbq6dDon3UnxUTTkf32KSiZhsfp8d8yUn0AKeyMo3k2/ygGnRUwZ7IPHdhCLMk186H8wjrpdV3nvVs+P3MzyOYbIt2P5LTdzEaE37kHmkOtkrjls3bkE73BWGhiJnzBp8qp+9J8LdC8Gv4wE/ymbm65sYSvCQCwoKBGctMPcBsdDdl8lORYZh5daBDVyMVp2mlCWq0UUF18avv1QyC7LSfQrGwtZJ7zIouvhgTqzquKiNKpcTZOERFwV/cn0TK94tm3Uc602boVywv/ZKtosscLByzuS8KpOzw4e3Wsv7K/7PRt283sl6yX/NETCX4apXbLihysakilv8XoO4DhU7QgtU96r9FeY73Leocg0/TSYLvYZH/Lj4MMabFe+5UG7wVFgdvbbE0whHiJGHeSp8SMw5AMEGWQIHguQAZySpfTbfooMd1VA28gyAukMi8Tpmwn2fdBPfzAowq+BF6LaQP9vRUaUOK3CN6rOAko4qKwT7oXPtQfViZIPlPb1sNMqgSNNNHtesbFWWkXQT2xUUYoy4T9DJaV5EcdY5srIqhmtvWqFXASQwVKpy5USXjAR8M7IBSjScWshE5uRbkfx9ivHcOvDbOqGBo3jNNx5oltzaeX3GdQHx5mpMoJei0VwjEXHzjmo8J2kLZMDdytk8+gTuqM4eAGmGihIFwHHwhmSHvCc9AAW7S7p5HVsMROSOJe1yum0cQgiN5s+fdKNBHYyG49cf8WPiw1DDpXgwD5h0s5roPrmhGV9WiQYIMb2seBbRYDlwk53uxRxFYOVJ0cWJ/QJsAsGJX+btkwyKBoQaVvYMfCTc5kF/k/tuM9+HAgZUL6DyKoXHq0xh8pM8oeKGRc/ovkHs2Ln2gB4WkKcMiB8cLg6QQWpCGGjE+V4U3dC/wXiBaYmUDbYFyg68pANFVnoULxdM3dvbAWIm79WHOtjcuPN5zAbYbik245Gk+Pt7J4bKKbFJzxIofDF0m9clf594Kl+gRlUKANWMMEjngrBZD9YMf66D04svXfGMBSbJ02V1n9XtIoKbcZxaQfpcOSzyCuBqHYvoWNTXsVj7aKQlU6HaNWAuGyPf5m26NkRjzb0ih2g+fxx3ftylPehkPzY+BjWI46kQU7sErncLzVR+H0Ml68sio8MM8IFmXaCAzSkfTpUdmRHskTdYdNsFOUDRY8UmN/UeSCAunBWtBMaLmNUPIOBgesgKOTFCsirSRp6vx4qzYeOYbyRHgaLoU2B7rwAkql6NseGJ8abr7FGb9+i9Vg5fP0IM/Pc+AS9OetPRBDQhHmA2zJKO1Y2C3xZ4Zo3tvMh85aw+9z7FbgzAW/PAX1kp3TrFxR2O2plQzRXnMseS965TmBw5lTi1b7MyXeP8VDd0M6xSsDnHd6sZXITaCmi4yQ2LK85eogrm7xkAqMKCCgYgRszJBllCbKkasfsKw+5TgezkBWctaPChqldkHdNn1d/Q+tFdgjQx8x1UpeuAN/wcSTfjHaMBj3r3R8aHEu8iwG9r4K7RTOnOJJbusSq0hjkppfpy27lqbktpkkhOpmOVMpKvR9U3GQ8IzLfH94TNKRwmqgLz9fFaHnivxPbTUJGNLYcJq8UeFLU+0NkOE8ervKALH7iaW0tMt2DSxU5wPMPbNlgLbJRNPyv1ZThT3DXKDtACMBNtUspK7AMcHcUnncyE290l1MssElk2wgbckecuqtu3fqBGRTLMQZNVBCVK1GrA3knd6w5YJOrETlctg37VPJqlmFBFPsbVp3ZDkePXDTt66EvIqGj59YYl9htwvreKjl12mD8x2ToTaEcPX7SwfwrBIRNHQx0ypLfEd2MHdZUNDsPqKwQXqAvOUuB+Gc3dGtztIitu+B3dN7R+xUCmw/B0Yro/S3j8lyPuDxrZj48PYryOL0sbXfCvtlD0WvNBl8GwOmskQHg0Q7IiloHXARiqUcGOHF/Pj8k2KIfPNQQpswp2dFD1bPM+kdB48Go07SoaCgpOvmANdkCD44Z90Iiy2t39ihSwcTekZ1qRFZfyG2fzYTD9gm4vmJVPiqEXLHrGopfB5x1DEkcKWSZhlJF4U8EMABcAR7jdMiE36ZDUqnVgi1O2R/KtPildKYcIzOnA5/AhKyJYdBpQmhBvvbX5exYNrOqCiym+9jYanDmq/bVykSVLhVEEeDNWzpvxHdVIgRsqCOoYdqkHxsYaQy2B78c1ucqGxUs0Xy20Pmj8mbKfVRo2uUWKPUFdsUk90MH4/fxb1ZfBGxdQvY7niPZLAoUsir2/UEnOtpB/PFbAP2+9mMyGR/y4+DCPt8gULVnV8YtY+G5RZ6A7Z/9PhS63VwjcZtLNenYZW1GZFLKoLHK0OBUUsgGmQSR6LzcJzER9ZALsaKjSonmy4+yXwIRXSFTSCS9sqUAlcyKp+TbggGywdVSIKrpXFH2C3XW1I5HqgiLn2TATJlbz9HGbgxPHibCEGyxoZgULTAwtfo8ShWwC7sgpqgW128AwuxvKYTtf0XAOQZ2z0gDypGzAnZQLpEGwGqDBREiTyTdQ/3fFgn+vFRWGs3AbvxmbSnytoOs5Bxj+dUNMk7FC3rzHiAoXjhbn/XjdNqnDf48Erzauyym0KDhdCBQvQ8d5l4pNbqjY455ZhrD5Td6whxZzlW3cUzw3bUwEvskbNrlFU3WaVyYnu2N68/1c8MIx+IwyfqZq/c8ZH0q8Fo6vT0vDc+nQtaK6oJniVHSoRxWhh9dr15hui6oq8uVF88H957ue4WrhtHPPhJsqZlkVAXOCawXQYKjS8CYvA9cTaDAVBGkPz59faDQJw1Xe4qSco9rtqF7RcBuQgcrCpCsruuxQObPZchiqUFnu4AUAAz9MElM2OEymvdEfNddMOMQBQZhiEjvuQfMHgFP4thkci5dhX5OchzUaUclkyEr3pWUFjCGmk48lN9Yt/g2houREh7rXewH032uwFHoOLAQUENcrF7omDRU7VpxQQe3b/Jz3RVof3XCK4ZQUDerecZOKPXQq+G+H+nncCznCvDt3J7lWixR8ld+x+IKzX2Bi2HDDLldUv6E5IYnudeopH87IzxvHYkVJKXvED4sPJd4kzuS6+bQ0PAG4tiXUrCiq3Uzxb/sKcnXvDRS1CPZokycjIceEpxLWtP4xsKGmPoXWUyxn8YJNNm5h9YazX8LzlQ9pQxt47epn7FlFOmVlACCdCOjke0F1BSSmlaQS5/MNZq8QKBblw50cX5El6GUUSE+owYIylpKR6UqRwe8z0XpAFBo6EPn9NFSkVRFNZ9Jq3CNBtdh6eziAKHT4iK1YsIJ28GtwfE9KpsO1zcmvSww5JAc7r69CSK9Dj0m5QgF0NxQpIbmYnOHJkVhV8NaIEZ9jaKahQ13QhbuPrDzf5OuoRGlMumONrf8uVwgUV3kbO5nVT8RzI3HXqILfO56cfMVNEAMQb0M3A86k3qSM3zXYSLrV3tC9ofsWtLHJYviZ4QVG7sry35/9/fy88eHE68FOqKbhUgucSscJRCFvfYGLjwo3k24R0JzR5uhoCT4uu+nJ3z3ADVG5WHx+lJjMkMMj96J/p6U7DF0qqlNprGBBk4biCzroSpFODlk1J3c3E8JJntGiIVPtim7J4dzfKY3ZrB4O/N3uG8zJ2xXoP7zHR+UbFZnJ/fuZ9DMm1HQjBhp2CR0BkPq2yXQrnu7EC85SBsTgDrw2v6P9OXw0Pd1nMj7COVV2ILBT+tgtQ6UuR3GBsFKXsHRXUs40JuGIqbISZzVLOU4gsXUyQtR17DwEHF7Qg2moQMcOxWRi56MmlTiX76rTPMdVbqBrMJt52V7Nf7u3GI7g9aYe84afu9rNeOC6nyU+nHg3E5S2QKPJlol4FUNRBzqT8lkdm0xtgIAEIUrvr5w00/BMS6bBkdObD6pHcsnqjgl5GkMCGFXTK/4GQx+z9atf0FGxyBkVlF3MLWqRJTbB6b/VDu/VaP8eugouhm5XdL8hRQndawjnOAQLVM6g0HmNYYEVCsN7q3eAlRgXphymQMAhFGI5Jmtiy+FuG81FVr8Uy8mmYH5f3bDiTEHJwNLf+kwcKRVJOprjrDqoZsmVpTbyPCeEZQqe5YRzDClocGubC9ARQu+8qS5Fgt9Nit/ZFwAN3QurdQG2MSHWRwJtIK5u3iOBBt7rV5zkCTd5HWO9qQyWXna5uFapIaeZO6RC54jD4MrRZy+vt3uPa1cj4TZOpn1KK5//SgzPjQM09ogfER9LvIdEZyDEkFJ/XQ0lOJYaxohbNt1sjp9Ol1gAEFhUvd0d6cXW4VigE68UBC5I6UVIbC0HJsltqsOQIiYZCTXA+VAvch5JumANzDQJZW0kwnydoaMgipyjM7/eYWSpO2G+oZsC+kQ2A3pU/JOONo5r/G6OkZTRfOu41+Q1pw4sgu5fhgdcRcGKk5+wyTW0HPjeNqmczDI+ajQL5eCKj1fmpNdmrG/bQaUrG5MVO578+Rv+cHOODCsoUNNlTg9mrbyo4ATiwaoLYHz0N2zE212BaFjmOT8umvyLE/O++QuSTz2bk0e95JnAE0umlVJqL6SwfCqMzRHglHbMqTTzLRbVP0PSZUt2xDcTbI/43vFhVgNn3R23nv5ik50gveB5aegBQTwXViKLCa49higcsCzmLDi9kXSJ9R5R5GiCuR6sedgMyYRafB2JM5Mmj4fJbvOXwUbISiof1qyu8ucNfSTtHBlNTq1Zqk+1kXSnWSDFzEWmCOY4X0HdyYSgsnIyynuol83kqvF5avlOjdshnhnn3MZxOzqu8gqH4U2+4ov/Nhw1OhZUNKw+JSR5tI4cVNk8yW187T2EEWs0r2pg6Ge5wNyx+8KhhsCOh1aFAq3J0F1YRbAEe8JcozImT7f7EwAMCliRlTg6+jACPRnK+kkAAAUHSURBVAoHpT5xXpv3ovInOWP1MyEQP+HiF9yCPlYPi2eer56La1S2za6B5eaARIX7jj9XJKf6OEjxwHh/VHww8fJC5Tx+fjwUspTOAl+Whr0XPC8d2oEX58RYDynB1FIwkOsrIliAMYV0NyARSYHW6mtssBdsoNV2xctgDDREIyy2jEDihPGgBTNhumasdxUuNVb7XTXkQQPzSAqOeki4ySguEKxDj9fdhjXP+0j7GABj6wswmQy2RKhiTSYERhXMq2CjiltwHtVfwYqKPc6bBoa6Y5Pkyk7hnYIFm9yw+mnANwCZJNzKNyZe3wgL+GGX4QvOmJTA5kDr3OncumEzKotRtEfG7uapFKhxoiwX0VxUOyoUBQ2TcneEAe6+5rx2RVascsHqZ5xxwdkvOPsKDcAqYaTjdUhOdQ/hevMKM0JP1F74M8o6HmGFNBb4M2DWP298WKsBAF5bGdJ/JeQBV6X4zTXoZqfSQQNDxSKOXRxFBatjuA0opj17BYAY382R4IlEZkMtBXZkNE9e8Lc7vK/ZDf2dYLmgQEW/aXi9f6Az4Y4HfnS0DWY7zI8kevbwqbt7DueJqCx1Dk3cjwtTElKkjAQ8nIlxP2CRFXAm4fyTfqwGRbHj7a6C3w8LS/eKkzxPrzblsZ/9CQJlkg6KmoZrRpV9KHUldLPijBUnrDjhyU9YsQyu8G6Gk4ZWsnOA4+YdJRI5DTE1RMgFzQWnZG7YE656xckJCbHK72i2DcwVeJc2YqcABLcay6h0OWjBpLl4QZEFJ3ma51eBaty9ZLOUsAKn0/6cSfd9yB98/IjvGR+GGmpUu7ulSAoVZ1n1MMnWsPQu4jirAUtI8tWCKtnxDlEWm3KBGnJ+FtuibLSxqz893IDZTKMty0pNBXRoWVDtGg9vDi0Y+qF6XHRKNiZDNZNusxS1RjycFgk4ByXyGCYh/Zh0R/ddplBO90nKT8w3IwVZ7qoyMLmkV9089kxBydE9SlLyZ3a8je25w7D72x2c0lFRsWEVsj8y6WY0tKHUZei4yC8QFJwisW2o2FDx7Bds3rFA8GbASQpUBJtxLOUNFYs/x991nAvvl4tS5mdLvMmAV33F6mdAotEmNmCF7g3wNhaGtEZySd8zVvYNDau8F4tfsOKMig0JqJgz6SaskNeA1+TPnnQZcrh3H/Fj4sPNtVtX7J3MBAen15oJrlBclEmXAjVkPOQlVlAwe/WDRYyQnWAhWnNkOHh8/J4WNCth4OwXKHZQweCMKhuTXChmVbsy6drE60Q0lLHOd9hfNlm67RNWCPdYH7YuhBZSCkZkxVHMJq3dU4chxdABjUq2jL8FpFzlFEa/P9f3nx+r44xMzMdFJCvkiiuSP+w2K2QN4Z+xQ8CGs/zC1wtGRX6cQyeXGExI7VoAqJ7V8xlnrFhRsFnHjo6vMQn2bGecQf2M1zbPHECY4uQFwBktkq3BsApZKBJ86gKg2nXQEvPYYG/oUrHhBYuccZJn7LJiAZunYzxYtrH7mDBP6i7cL2R/jZgiTH+NZeZzhkxjyv/ED4v8C4D/+993OI94xCO+Y/wfd//fP/og/orxocT7iEc84hGP+P+PB9DziEc84hHfOR6J9xGPeMQjvnM8Eu8jHvGIR3zneCTeRzziEY/4zvFIvI94xCMe8Z3jkXgf8YhHPOI7xyPxPuIRj3jEd45H4n3EIx7xiO8cj8T7iEc84hHfOf4ficBZS56NUzwAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "titles = ['Z1']\n", - "z1_full2plot = gf.z1\n", - "z1_full2plot.mask = dems_mask\n", - "clim = malib.calcperc(z1_full2plot, (2,98))\n", - "plot_array(z1_full2plot, clim, titles, 'inferno', 'Elevation (m WGS84)', fn='dem.png')" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "RGI60-01.15645\n" - ] - }, - { - "data": { - "text/plain": [ - "Text(0.5, 1, 'UTM (m)')" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Plot single glacier\n", - "rgiid = 'RGI60-' + gf.feat_fn.split('_')[0].split('.')[0].zfill(2) + '.' + gf.feat_fn.split('_')[0].split('.')[1]\n", - "glac_shp_proj = gpd.read_file(glac_shp_proj_fn)\n", - "glac_shp_single = glac_shp_proj[glac_shp_proj['RGIId'] == rgiid]\n", - "glac_shp_single = glac_shp_single.reset_index()\n", - "\n", - "print(rgiid)\n", - "\n", - "# Plot over region of interest\n", - "ax = glac_shp_proj.plot()\n", - "xlim = (warp_extent[0], warp_extent[2])\n", - "ylim = (warp_extent[1], warp_extent[3])\n", - "ax.set_xlim(xlim)\n", - "ax.set_ylim(ylim)\n", - "ax.set_title(\"UTM (m)\")\n", - "\n", - "ax = glac_shp_single.plot()\n", - "xlim = (warp_extent[0], warp_extent[2])\n", - "ylim = (warp_extent[1], warp_extent[3])\n", - "ax.set_xlim(xlim)\n", - "ax.set_ylim(ylim)\n", - "ax.set_title(\"UTM (m)\")" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "HACK TO BYPASS VALID AREA\n", - "\n", - "\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "#Now apply glacier mask AND mask NaN values\n", - "glac_geom_mask = np.ma.mask_or(glac_geom_mask, dems_mask)\n", - "# nan_mask = np.ma.masked_invalid(gf.dz)\n", - "# glac_geom_mask = np.ma.mask_or(glac_geom_mask, nan_mask.mask)\n", - "gf.z1 = np.ma.array(gf.z1, mask=glac_geom_mask)\n", - "# gf.z2 = np.ma.array(gf.z2, mask=glac_geom_mask)\n", - "# gf.dz = np.ma.array(gf.dz, mask=glac_geom_mask)\n", - "\n", - "gf.res = geolib.get_res(ds_dict['z1'])\n", - "\n", - "print('\\n\\nHACK TO BYPASS VALID AREA\\n\\n')\n", - "gf.valid_area_perc = 100\n", - "\n", - "# print('dz_count:', gf.dz.count())\n", - "# print(gf.dz.compressed()))\n", - "\n", - "# #Compute area covered by valid pixels in m2\n", - "# gf.valid_area = gf.dz.count() * gf.res[0] * gf.res[1]\n", - "# #Compute percentage covered by total area of polygon\n", - "# gf.valid_area_perc = 100. * (gf.valid_area / gf.glac_area)\n", - "# if verbose:\n", - "# print('valid area %:', gf.valid_area_perc)\n", - "\n", - "# titles = ['Z1']\n", - "# z1_full2plot = gf.z1\n", - "# z1_full2plot.mask = dems_mask\n", - "# clim = malib.calcperc(z1_full2plot, (2,98))\n", - "# plot_array(z1_full2plot, clim, titles, 'inferno', 'Elevation (m WGS84)', fn='dem.png')\n", - "\n", - "titles = ['Z1 (again)']\n", - "clim = malib.calcperc(gf.z1, (2,98))\n", - "plot_array(gf.z1, clim, titles, 'inferno', 'Elevation (m WGS84)', fn='dem.png')" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ELA(t1): 1862.8\n", - "['1.15645', 387904.10807713855, 6836288.341308625, 1825.5572509765625, 415.84836010742185, 4326.4982832031255, 13.094484329223633, 163.20254516601562, 292387143.2191999, 100]\n", - "['1.15645', 387904.10807713855, 6836288.341308625, 1825.5572509765625, 415.84836010742185, 4326.4982832031255, 13.094484329223633, 163.20254516601562, 292387143.2191999, 100, 165.9513434462557]\n", - "69.52308565990822\n", - "['1.15645', 387904.10807713855, 6836288.341308625, 1825.5572509765625, 415.84836010742185, 4326.4982832031255, 13.094484329223633, 163.20254516601562, 292387143.2191999, 100, 165.9513434462557, 69.52308565990822]\n", - "Area [km2]: 292.3871432191999\n", - "-------------------------------\n", - "[1.15645000e+00 3.87904108e+05 6.83628834e+06 1.82555725e+03\n", - " 4.15848360e+02 4.32649828e+03 1.30944843e+01 1.63202545e+02\n", - " 2.92387143e+08 1.00000000e+02 1.65951343e+02 6.95230857e+01]\n" - ] - } - ], - "source": [ - "if gf.valid_area_perc < (100. * min_valid_area_perc):\n", - " if verbose:\n", - " print(\"Not enough valid pixels. %0.1f%% percent of glacier polygon area\" % (gf.valid_area_perc))\n", - "# return None\n", - "\n", - "else:\n", - " #Filter dz - throw out abs differences >150 m\n", - "\n", - " #Compute dz, volume change, mass balance and stats\n", - " gf.z1_stats = malib.get_stats(gf.z1)\n", - " z1_elev_med = gf.z1_stats[5]\n", - " z1_elev_min, z1_elev_max = malib.calcperc(gf.z1, (0.1, 99.9))\n", - " \n", - " #Caluclate stats for aspect and slope using z2\n", - " #Requires GDAL 2.1+\n", - " gf.z1_aspect = np.ma.array(geolib.gdaldem_mem_ds(ds_dict['z1'], processing='aspect', returnma=True), mask=glac_geom_mask)\n", - " gf.z1_aspect_stats = malib.get_stats(gf.z1_aspect)\n", - " z1_aspect_med = gf.z1_aspect_stats[5]\n", - " gf.z1_slope = np.ma.array(geolib.gdaldem_mem_ds(ds_dict['z1'], processing='slope', returnma=True), mask=glac_geom_mask)\n", - " gf.z1_slope_stats = malib.get_stats(gf.z1_slope)\n", - " z1_slope_med = gf.z1_slope_stats[5]\n", - "\n", - "# #Load timestamp array, if available\n", - "# if 'z1_date' in ds_dict:\n", - "# gf.t1 = iolib.ds_getma(ds_dict['z1_date'])\n", - "# else:\n", - "# if isinstance(gf.t1, datetime):\n", - "# gf.t1 = float(timelib.dt2decyear(gf.t1))\n", - "# #else, assume we've hardcoded decimal year\n", - "# gf.t1_mean = np.mean(gf.t1)\n", - "\n", - "# if 'z2_date' in ds_dict:\n", - "# gf.t2 = iolib.ds_getma(ds_dict['z2_date'])\n", - "# else:\n", - "# if isinstance(gf.t2, datetime):\n", - "# gf.t2 = float(timelib.dt2decyear(gf.t2))\n", - "# #else, assume we've hardcoded decimal year\n", - "# gf.t2_mean = np.mean(gf.t2)\n", - "\n", - "\n", - " #Can estimate ELA values computed from hypsometry and typical AAR\n", - " #For now, assume ELA is mean\n", - " gf.z1_ela = None\n", - " gf.z1_ela = gf.z1_stats[3]\n", - "# gf.z2_ela = gf.z2_stats[3]\n", - " #Note: in theory, the ELA should get higher with mass loss\n", - " #In practice, using mean and same polygon, ELA gets lower as glacier surface thins\n", - " if verbose:\n", - " print(\"ELA(t1): %0.1f\" % gf.z1_ela)\n", - "# print(\"ELA(t2): %0.1f\" % gf.z2_ela)\n", - "\n", - " \"\"\"\n", - " # This attempted to assign different densities above and below ELA\n", - " if gf.z1_ela is None:\n", - " gf.mb = gf.dhdt * rho_is\n", - " else:\n", - " #Initiate with average density\n", - " gf.mb = gf.dhdt*(rho_is + rho_f)/2.\n", - " #Everything that is above ELA at t2 is elevation change over firn, use firn density\n", - " accum_mask = (gf.z2 > gf.z2_ela).filled(0).astype(bool)\n", - " gf.mb[accum_mask] = (gf.dhdt*rho_f)[accum_mask]\n", - " #Everything that is below ELA at t1 is elevation change over ice, use ice density\n", - " abl_mask = (gf.z1 <= gf.z1_ela).filled(0).astype(bool)\n", - " gf.mb[abl_mask] = (gf.dhdt*rho_is)[abl_mask]\n", - " #Everything in between, use average of ice and firn density\n", - " #mb[(z1 > z1_ela) || (z2 <= z2_ela)] = dhdt*(rhois + rho_f)/2.\n", - " #Linear ramp\n", - " #rho_f + z2*((rho_is - rho_f)/(z2_ela - z1_ela))\n", - " #mb = np.where(dhdt < ela, dhdt*rho_i, dhdt*rho_s)\n", - " \"\"\"\n", - "\n", - " #Old approach\n", - " #This is mb uncertainty map\n", - " #gf.mb_sigma = np.ma.abs(gf.mb) * np.sqrt((rho_sigma/rho_is)**2 + (gf.dhdt_sigma/gf.dhdt)**2)\n", - " #gf.mb_sigma_stats = malib.get_stats(gf.mb_sigma)\n", - " #This is average mb uncertainty\n", - " #gf.mb_mean_sigma = gf.mb_sigma_stats[3]\n", - "\n", - " #Now calculate mb for entire polygon\n", - " #gf.mb_mean_totalarea = gf.mb_mean * gf.glac_area\n", - " #Already have area uncertainty as percentage, just use directly\n", - " #gf.mb_mean_totalarea_sigma = np.ma.abs(gf.mb_mean_totalarea) * np.sqrt((gf.mb_mean_sigma/gf.mb_mean)**2 + area_sigma_perc**2)\n", - "\n", - " #z2_elev_med, z2_elev_min, z2_elev_max, z2_elev_p16, z2_elev_p84, \\\n", - " outlist = [gf.glacnum, gf.cx, gf.cy, \\\n", - " z1_elev_med, z1_elev_min, z1_elev_max, \\\n", - " z1_slope_med, z1_aspect_med, \\\n", - "# gf.dhdt_mean, gf.dhdt_sigma, \\\n", - "# gf.mb_mean, gf.mb_mean_sigma, \\\n", - " gf.glac_area, \n", - "# gf.mb_total, gf.mb_total_sigma, \\\n", - "# gf.t1_mean, gf.t2_mean, gf.dt_mean, \n", - " gf.valid_area_perc]\n", - " print(outlist)\n", - "\n", - " if extra_layers and (gf.glac_area_km2 > min_glac_area_writeout):\n", - " if 'ice_thick' in ds_dict:\n", - " #Load ice thickness\n", - " gf.H = np.ma.array(iolib.ds_getma(ds_dict['ice_thick']), mask=glac_geom_mask)\n", - " gf.H_mean = gf.H.mean()\n", - " #These should be NaN or None\n", - " outlist.append(gf.H_mean)\n", - " print(outlist)\n", - "\n", - "# if 'debris_thick' in ds_dict:\n", - "# gf.debris_thick = np.ma.array(iolib.ds_getma(ds_dict['debris_thick']), mask=glac_geom_mask)\n", - "# gf.debris_thick_mean = gf.debris_thick.mean()\n", - "# outlist.append(gf.debris_thick_mean)\n", - "\n", - "# if 'debris_class' in ds_dict:\n", - "# #Load up debris cover maps\n", - "# #Classes are: 1 = clean ice, 2 = debris, 3 = pond\n", - "# gf.debris_class = np.ma.array(iolib.ds_getma(ds_dict['debris_class']), mask=glac_geom_mask)\n", - "\n", - "# #Compute debris/pond/clean percentages for entire polygon\n", - "# if gf.debris_class.count() > 0:\n", - "# gf.perc_clean = 100. * (gf.debris_class == 1).sum()/gf.debris_class.count()\n", - "# gf.perc_debris = 100. * (gf.debris_class == 2).sum()/gf.debris_class.count()\n", - "# gf.perc_pond = 100. * (gf.debris_class == 3).sum()/gf.debris_class.count()\n", - "# outlist.extend([gf.perc_debris, gf.perc_pond, gf.perc_clean])\n", - "\n", - " if 'vx' in ds_dict and 'vy' in ds_dict:\n", - " #Load surface velocity maps\n", - " gf.vx = np.ma.array(iolib.ds_getma(ds_dict['vx']), mask=glac_geom_mask)\n", - " gf.vy = np.ma.array(iolib.ds_getma(ds_dict['vy']), mask=glac_geom_mask)\n", - " gf.vm = np.ma.sqrt(gf.vx**2 + gf.vy**2)\n", - " gf.vm_mean = gf.vm.mean()\n", - " \n", - " print(gf.vm_mean)\n", - "\n", - " if gf.H is not None:\n", - " #Compute flux\n", - " gf.Q = gf.H * v_col_f * np.array([gf.vx, gf.vy])\n", - " #Note: np.gradient returns derivatives relative to axis number, so (y, x) in this case\n", - " #Want x-derivative of x component\n", - " gf.divQ = np.gradient(gf.Q[0])[1] + np.gradient(gf.Q[1])[0]\n", - "\n", - "# gf.divQ = gf.H*(np.gradient(v_col_f*gf.vx)[1] + np.gradient(v_col_f*gf.vy)[0]) \\\n", - "# + v_col_f*gf.vx*(np.gradient(gf.H)[1]) + v_col_f*gf.vy*(np.gradient(gf.H)[0])\n", - "\n", - " #Should smooth divQ, better handling of data gaps\n", - " \n", - " \n", - " outlist.append(gf.vm_mean)\n", - " print(outlist)\n", - "\n", - " if verbose:\n", - " print('Area [km2]:', gf.glac_area / 1e6)\n", - "# print('Mean mb: %0.2f +/- %0.2f mwe/yr' % (gf.mb_mean, gf.mb_mean_sigma))\n", - "# print('Sum/Area mb: %0.2f mwe/yr' % (gf.mb_total/gf.glac_area))\n", - "# print('Mean mb * Area: %0.2f +/- %0.2f m3we/yr' % (gf.mb_total, gf.mb_total_sigma))\n", - "# # print('Sum mb: %0.2f m3we/yr' % gf.mb_total)\n", - " print('-------------------------------')\n", - " \n", - " #Set up output header\n", - " \n", - " out_header = '%s,x,y,z_med,z_min,z_max,area_m2,valid_area_perc,slope_med,aspect_med' % glacnum_fieldname\n", - " if extra_layers:\n", - " out_header += ',H_m'\n", - " out_header += ',vm_ma'\n", - "\n", - " nf = len(out_header.split(','))\n", - " out_fmt = [glacnum_fmt,] + ['%0.3f'] * (nf - 1)\n", - " \n", - " #Write out mb stats for entire polygon - in case processing is interupted\n", - " #out = np.array(outlist, dtype=float)\n", - " out = np.full(len(out_fmt), np.nan)\n", - " out[0:len(outlist)] = np.array(outlist, dtype=float)\n", - " #Note, need a 2D array here, add 0 axis\n", - "\n", - " print(out)\n", - "\n", - " np.savetxt(out_csv_fn, out[np.newaxis,:], fmt=out_fmt, delimiter=',', header=out_header, comments='')\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "plot?\n", - "2\n" - ] - } - ], - "source": [ - "#Do AED for all\n", - "#Compute mb using scaled AED vs. polygon\n", - "#Check for valid pixel count vs. feature area, fill if appropriate\n", - "\n", - "if mb_plot and (gf.glac_area_km2 > min_glac_area_writeout):\n", - " print('plot?')\n", - "# dz_clim = (-2.0, 2.0)\n", - "# if site == 'hma':\n", - "# dz_clim = (-3.0, 3.0)\n", - " z_bin_edges = hist_plot(gf, outdir, bin_width=bin_width)\n", - "# gf.z1_hs = geolib.gdaldem_mem_ds(ds_dict['z1'], processing='hillshade', returnma=True)\n", - "# gf.z2_hs = geolib.gdaldem_mem_ds(ds_dict['z2'], processing='hillshade', returnma=True)\n", - "# map_plot(gf, z_bin_edges, outdir, dz_clim=dz_clim)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "titles = ['Flux']\n", - "divQ_full2plot = gf.divQ\n", - "divQ_full2plot.mask = dems_mask\n", - "clim = malib.calcperc(divQ_full2plot, (2,98))\n", - "plot_array(divQ_full2plot, clim, titles, 'inferno', 'divQ', fn='divQ.png')" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAVgAAAFgCAYAAAD+RWGAAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOy9eZBl2V3f+fmdc+7+ltwrKytrr17V6kVtqYX2HYQtcBCAwWNjs88w4Rl7bDMTnoiZscd2THhM4DDjiTAyDmMGDDGWgcGYAAsQRgghIbQhtUpd3V17ZVXl+ta7nXPmj/squ6pVLamlLvXC/URUVOZ795137n0vv/d3fue3iPeelpaWlpYXHvViT6ClpaXllUorsC0tLS13iFZgW1paWu4QrcC2tLS03CFagW1paWm5Q7QC29LS0nKHaAX2zwAiclZE3vUcz71ZRE5/FWP8dRH58As/u5aWVy6twL6IfDnh+zrG/Dci8g+/2uO997/vvb/nhZxDS0tLQyuwLS0tLXeIVmBfQojID4vI4yIyFJHPi8hrZo+vicgHROS6iDwtIv/dc7z+R4D/CvhxERmJyK/d9PTDIvIZEdkTkV8SkXj2mreJyMWbxjgsIv9h9l5bIvJ/Pcd7/Z8i8mER6d9wH4jIPxWRndkc33vTsX0R+RkRuSIil0TkH4qInj13SkR+bzavTRH5pdnjIiI/KSLXZs99RkQe+DovcUvLN5RWYF8iiMh3Af8b8H1AD/g2YEtEFPBrwKeBQ8A7gb8pIt/87DG89z8N/DzwT7z3He/9+256+ruBbwGOAw8Cf/02c9DAfwTOAcdm7/eLzzpGicj7Z2O8x3u/N3vqMeA0sAT8E+BnRERmz/0sUAOngEeA9wA/NHvufwd+C5gH1oGfmj3+HuAtwN3AHPCXgK3bXLqWlpcsrcC+dPghGmH8uG84470/B7wWWPbe/wPvfem9fwp4P/A9z3P8f+69v+y936YR7Idvc8zrgDXg73rvx9773Ht/88ZWAPw7YAF4n/d+ctNz57z37/feWxpBPQgcEJEDwHuBvzkb8xrwkzfNvwKOAmvPer8K6AL3AuK9f9x7f+V5nnNLy4uKebEn0LLPYeDJ2zx+FFgTkd2bHtPA7z/P8Tdu+nlCI6S3m8M57339HGOcAh4CXue9L59rfO/9ZGa8dmjEOACuPGPQooALs59/nMaK/ZiI7AA/4b3/197735m5J/4FcEREfhn4O977wVd1ti0tLwFaC/alwwXg5HM8/rT3fu6mf13v/bc+xzhfT3m0CzRi9lw33seB7wd+Q0S+2siDC0ABLN00/573/lUA3vsN7/0Pe+/XgB8F/m8ROTV77p977x8FXkXjKvi7X/uptbR842kF9qXDvwL+jog8OtvgOSUiR4GPAQMR+R9FJBERLSIPiMhrn2Ocq8CJr3EOHwOuAP+HiGQiEovIG28+wHv/74C/B3xQRG53Q+BZx1+h8bH+hIj0Zj7ckyLyVmh8zyKyPjt8h+YGYUXktSLymIgEwBjIAfs1nldLy4tCK7AvEbz3/y/wj4BfAIbArwALM5/m+2h8pk8DmzRi3H+OoX4GuF9EdkXkV57nHG681yngPHCRZnPp2cf9LPAPgN8RkWNfxdDfB4TA52lE9N/T+Gih8TH/kYiMgP8P+O+990/TbPS9f3b8OZoNrn/6fM6npeXFRtqC2y0tLS13htaCbWlpablDtALb0tLScodoBbalpaXlDtEKbEtLS8sd4nklGohIuyPW0vIKwnsvX/molq+VryGTS7/ws2hpaXkRaMOK7zSti6ClpaXlDtEKbEtLS8sdohXYlpaWljtEK7AtLS0td4hWYFtaWlruEK3AtrS0tNwhWoFtaWlpuUO0AvsiY/QiIvH+/y0tLa8c/kwK7EL6EIFZBl7sJBbB2j3AUdstvM9f5Pm0tLS8kDyverBNquzLNZNLiMNDKDGkZpEeKygU2/4iud2jsmOq+vo3fE4iAd6XiIR4XxGaA5T1xld+6VczusStaLd8GWybKnuHecU3PRQJ6cd3AxCqFE2AlgBLRUmNwmAkomJMY9F+5RtOEh6hrPewbm9fxOaSByjsAOdrrCswOqG2U2q7/ZxjKkkJTB8RRT9Yx+Mo3QSjYybF2a/rvNc7b2PidpjUW+Tlxa9rrJaWlq+NV7zAel9SuhFGIqyv0BKgMUQ+weHQYohNl1j3GaiI2k5xvsS54S3jiIQY3SfUPcbFU9wQzRsW4qi8RBIs4XyAViGT4gJfKddbqRARRW2nXC0/yoHs9XgcRbVDs1J4frniSXgEgCPBI+SMcd5S2/HzGqOlpeWF4xUvsIKhtjnGRACNwPqAwIdEPsKJp6KkkIwwTG+y+m4VWKP7WJczdTnPWKSN26EoN6jtDkO7Qxodo6yH3E4cb7gBwGP0ItaNsW66L9KD6jJKApwb3/b1t0dzIHst97lXMaJgW20xkSHWV0Sqgw2WGNodAJTq0o0Oszf9/PO+ji0tLc+fV7zAemrK+iq1HdKNjzbWKzE93yHAUPgKBGpqBIXz9rZL6kBneO8QUeAd3fgofyF+O3MhPD2q+aw8wVb1FJUdU9utW15r9CKryas5aA8TEbASRHzcnab0E4b1BoJmUl7CupKHg7fzR+oa/lkW9K0Ixzrv4a3hKS7mJXtuyraMsNQEhBj/zMc6pw9QZaeopOBq/nkqNyGLTjIunnyhLnFLS8tz8IoX2AaF9wWpmue4PQpAqgyV91S+RnnZDyjwuNuOoCWgtlsk4RGqepPj8hCxhsx45kLNYnGAqdljt/5SYQx0xil7knu7MYuRo3KCDO9lUNc8bRbZZYNAJRR2wGn5FO+Mv5c/4eNYX7E7/dNbxurGd5HoeR6SE5yb5hTUABiviQjBg51Zv25WvleJomRKGixRuhHWF3wtLoiWlpbnxyteYG8I0v+w8ghvOnSRD18yXJgYcgvWw7g2DGvLyMVsKcVYtm47zjA/A8C0PE83votFOvQDT2ocmdGYXKNE43z5Ja89FjzK3WnMw/NTOkGF9UJqUgalwe2tEUjIntrEqMaNcd0PeXf4TRzO4AO7h9ly5xAUB9RJltwCCxJRe48WhfKKDoZUGWKtsB4q56i8J1ZNFN6OTZjqCUZF5HaXotqkFdeWljvPK0ZgX51+F0/Uf0hRbuCpyaKTGBXxEN/EWxdCHlu9hPPC/fM7dIMue5XBekGLZ1BprkwM82WI8gqVGXamZ7Bu76Z3eCYSINI9nPMMa0GkEbWUiNJN8G56y7yWskc5zgr390syU1M7RagsK1GFdSELQcCk7OGUI5cIS41xmsVIiJXjvZ0TPDk6QuUdSyagFwq5hetFjfOeWAx9Y5gLFYmGyoH1szmZ5vewiInqI2zQYcRV8PWzrt5XFz3R0tLy/HjZC6xSXebjUwQ+IDPLVPUQ6/ZYCI6ybg9zKovpBRU705TCGkqnWImn9ALDxGq6psJ6xVyQcGlqCCcHOFQvMo4e5HCUcKGYMpARF/zj+8v1UXWVUlvGtcd6wd7sVRCzL2BvSn6Av7IOIo24KjwOxU4ZMawM41rQAhGGzGWgmG24FWxMPaVTTGoIREi1IdTCsPKMa0fuagLRpFrTNYrMQKg8sQbvoZ6FN4qCtVToViGdcoV7zPt46KDnfz33fpRKcW40m3jrMmhpeaF5WQus0fP0oiOscoJV1eV0PUCpEKWWmXfLLOkE6+D8JMD6PtVMdI5lEzphiakNqWmW7N0gYN4qnFcckgBPwKCEe7MUSNETwxPRlHHxJHl5kaezM4T5PcwHAV2jiEXTV6vs0bgS3ph8P3/73gmjMmQ+nlI5jXWCs0LhFFulZrcSptbhAI0m8jEGg6DYqKZsVYpANIEIzkFR2tny3xGIJtOafqCIbsr9WAgtK3FJ6RTDyhBrx7hWLEbCISdYL1zLFd+a/RAfth+isI3PONQZfXOIa/kXXrBEh5aWP+u8bAV2MX2ESb3Fkhwh8CFPc42i3sXOdt8rKYm1IpktkzdyQ+WahfBcELIQT9CBw3qF84IAtRMi5ekEHusby/FgUnO8O+SdVrNbvo0f+2Kz+z6y1yjlFM4HGAWp1pT77gHh0X7KoLQc6e0CMMgTSq/JraZywrBqrNGRrbE4LJbQB0CAzHbcbjaMvffU3uOBRGkyo0m1YNQzi/tUe45kU04sbOK9sDHsocST1wbrFZVTjGvDNQkYRYZj+cNc1meoXUGoUqyviE2fsr7Oc1mzSjI60Tp5vdcKcUvLV+BlKbDd+C4AFsMTRC4m8AaLQauIQGdYV1KQk9uZbSgwqaGwUHu4lgfMhSlZUDKuQiqnGNaa3IJIs8T2XugEnl5YsdodcGh1g8Vjlznz8z/Gv9j8FQKVUvqa0jnGtVB5z5Jf47r6ArXNsR7uXrzOQn+Py5tL7BQx22XIsNKMa0XlILeOwlumFIzVmNCHpD4hIkAjKBG0CCKCAvTs98wo0tkn53zjQdUC81FNrGvmOkO6vSHJ9YLrwz6V04xLjYhHiUcEtII532FPzVOqZ/zGHb3CRF+jnsXOfgmiENHMR8cYqBBoNv5aWlq+lJeVwMpsus47al9gfcVYRgiKWmoWw5MUfoT1FVMGbNgxcdFlPmwswsp79irHkyNF7jokurH9tHimVpE7oXaQWyFQMKcdpdVMqxBba85+9m4WI8urzTvYli2UF2rvyW0zTuQj0mAJCQ9wfz+nm45xTpiUIXtVwGYeMKyFYQXDyjNxlgk5YzVmyDZjv8XbzVux3mNnNSJuiGsjthCqZm7Wg3WNUCqBWHsOJlNOLF0j6zZ+Va0t29OEa3nCuFaNsIpnagXnweGJfQYCDkfpJ+RuB60Sajvgdlasc0P2pp9nD00vPsWwePoOf+otLS9fXnICqyTD+TEiMVGwRD9YJ5CYQX0FgFB3OO7uZ04S/pTPUUlBRUngQ7qyQCo9JjLAUrGjtknKkL1K0zWG2nuGtmLXOq4Whlg1PkznG8vQ3iSW/UARKkWiFWWtqaoA5xSZcZwMewSlRqMxIsRaiLxQupQFfYzX6pNM6prL20uIeGqn6QcV01ozqg3Ww9RaCm+ppGIiQyZ2h8H0i/wKn2ctezPH3SkCFFqaUKtIFKjG8vX74ts4FGINp7oT7j94kU5nzPVry9ROsztJGdcBu5VmUKrZ9YONqbBdWipqQh9iqSlkisfhfEVlhwhyS1zBn+/81xzLNOfHlt+rf5dBfppJtQn+9nHDLS0tL4rAarLoGB5LqDpEqtPk37sRWgLu8Q+zqwYMZafJpaeg8jmx7je1BAjweJ6UC/sjupm3suu6CEIkMXtqi4Ip19U2iUvIqwSLY0pBLZZh80Ku5gEAfUnQCJV3NJ7OkCxQpEYxrQOKMiRNphztDrk0XWCyl2C9p2s03UBINPTCgIXyJEYJ1wvD5VGXXlgAYJQjM5bUaLaKxqVgb7IQSzfCz5IGSiZsqm0iH5P4iIQAJwrnPV6aCAElzb6/AhLtWYxztHIMBj2uDvuMq5BpbcitJreK3aqx4nUNw8qxZ0sKqfavnfVV4wn2FUoMNc+Ecp3I3staosmMZyXWvLd6Jx81h7lafoHQdL/uwjQtLa9UvmECGwVrFNUVwFLU23TCQ0Sqg6YROK0CBMUFdY7K5xR2RKhSSjdBiUaJQaQJdDqvvkjtCyJ55vWF5EQ+JCPEeEXlS6YyZiJDpnrCwBsCGp+hw2GpqaRg5LawvqKvVum5eWpVo7yCeo64iBA0Tw67dMKSI8FVDs9tcWqacD1PKZ0nM8Jc6JkLLCKwU2q2i2bZ7rzgvKDE471Q+RvL/WYDTftm+9/jyKst4nCdvLzIXnEeHQVkMo/x86hmDY8VjfVCqNTMuhREmmyy0mqu7iwwKiN2ipjdMmRYa6a1YlAJ48pTzSzfoa2pqJnKBDUrCWypKOyAotpBRM3qJjRJE4lPCRSsJRWRMnyhEmKfEeu5/dA1wXC0806267MM8tPfkO9US8tLnTsusEoyknAVLYbV6H5KP2XidtASoLiR/dRYcjUFpZ00f+j1Dt4XaNUlCRZQ0gipkYjKTZjW2+y5km9Nv5fPyBkETS4hkQ/239v6CksjYLUEVBSNuPoKgGG9wTB/AtCQQK5GjOrrxLqHklPE1QJKNIEKUFuLACx39+gFFZkBZZv9futgXGsS01iDqYFYO3phQScsmdYB49qQW0XlIdYQa8We89RSY31FJ1zbF6aqvs6Wr7HxCYwy4LrEBHSNJtG31kgPZr9WTjEoY0ZlyKS+4auGiRWKmaHsPJTOYb1jKgW5jLmS/ylahcwFh5vrdUtyBaTRMaDZSBvWmr1KMaxrKsrGRTDjSOdt3OWOcqx7ivfnZ/hqYmpFYo5kb+JV/iTX3YQ/zn9pX9RbWl4J3FGBNXqeLDyIzKykobveFLxW8xiJiHyC8gqHo5ApzlsqN2Vanm82tERhdMIwf4LQrALgfHHLBsx/HP0r5tNXMSdrFJIzQGG8RmPwOCwVtS+o7IRApdQup3JT8mrjpj9my+70cyThYableWy4ziXjmHd/jsxqJjVcKwyf31ngZG0orGYhdGyVCgEqL0xKyFxznpnxxKqxKqd1QF4bxrVhUDUW61zoya1CV4qJDCnciMEsFfcGtd1hWu+CWaNPyvEs4njHkuqKYa0oraL2kBnHalLQCwtK24w/HxVkQcm1acqoTrm5c8PUWa7LLlOZcLV8JuZVScC0uLXITWCW6ZpVAh9yZeqYWs1W4Ri6EhSzkK4NBMPDchdLaeMj/ovdH+H37UfZnnx23+3xbA533sF97hQHw4Cl2DM37TKR9/GF/INfIvItLS9X7qjA9qNjhJJS+GZX23mLoBBRRD6h43sYrymkQKGwVES6wwTT/GF6KKsmXOi5Yi49NduTzyCpIlF9AGJSIh+TyRw7/jKTeouy3vuSGq/PHulGuFFeXqIXrOG8R0mzpAfYKQxP0iNSDhGYDx2h8pRO8F4ItcN5aXb4PQyqEIdQWo3zEIgnVKDE0w00aWEo/ZSd6eN8qcUnZGaRvpvbF9fVuECLpxcIlVPE2nIgHbGQjcmSCc4ppkWM80IaFcxNJwyqg1wYBwxrS+EdOzLmCmfYHn+Gm9NjrS+atK+bdra0ioilAx726prKaQrncDgiYubNYcpwzPd0v53jHctSlLNbGs6NDY+OX8uHzJXbfm5pdIxT9gSnegFLkSPWjlgrcrvCqewv8wn/OBdHH/oyn1VLy8uDOyawcbhOV61wdvSbzCUP4HF4b/E4tARUUmB9jUL2LdyagtrlaN3dr5Pq/FdTMNqzPf0cShJWkgdw4uj4Hh3fYyDXKasdnJ981XNPwsOsu1MYmnCmyjVuACvCtFaM0eRW6AdN1pSjiZsFZq4AITOOxNRkQUWsa5R4AhXu1z8ASLRmc+c4ZTJha/LJLzmnYbUB+p5ZjQFhXBu0eLpBRWYqelHBSnfAoSMX6azs4GpFvtelnMRUVYCIYzkqiFRI5T0Dn7Ojr7M7PsOzaw8U1SZKEuxNS3QlZhZhkLPnNLik8QcDkY/puA5vyu7hLStj7l/eYFJGnN2bRwsMKsP7zHfwa5P/QC86hPdu36JdCe5hSYcciC0LYY31wrhWzIeKqfW8S70KHb+KX5l85DbXpaXl5cMdE9h+sM7U7wGC9QWCorDDZqPKW9AgSpP4FGg2nhyWQX7mtvGVN2+63A7vS6wvuTr5FPek72EiIzquy0l/H9vqCbSkKAkoqsu3fb1WfVaSB+ixxOujdS7njZ+2dI7SaSovhHjqmRiMaqF0Bi0wF1YY5Uh1TT9s5mjEcaA7IItyvBc2Rz2MSsmtJtaWpRj2ypAr0x5nZu/1bGo3ZSO8xMa0SzdohK0XlhzuPrOEDoKKzsoO0domvgiwecRop8fuXp/NUY9BFZCYJknBe8/UD9A6xdW33ri8zwmDFablM2M7XzOor1DpnKnu07WHm3hcNB2fcDxJeOuBMa9ZP0evN+T65iLWC9ulpnSeiXW8I/p2cldzVyfm/ZNPciB7Pff7Y5zswuuWr3NocRPnFFd2Fjg/alYHtRc284ij4/tIOv3Wmm152XJHBDY0qyg0RiLi8NBsI2n2hnq+6VXlCzDgxaJ9Y9FOqi2M7jEuN24R0158D6UbU9sp1o3xPkckJAnXSM0iISm5HzAozlPbHZ4s/pA0WOKLz6ql+lysZW9mya8x5zpEoplYz5E0IDUwrJrl/qS+ERWgyG2TLFBaz1Zh6AWG5dhyX3/II8eeZHHtGpuXVhmNU5TyRGFO3xqK2gDhfuiW9cLBJOKd9i184Ja5NmLaDdfQBIytJdHCoXTMUjZibWmTogwoy5CiDBlcXiYrAibbfa5fW2IwyRjmMeeGfS5Motk5eFIiEulBdJwtV/Ka6NtYMx2MCL88+jmyYJnKDvezuPLyIhIeIa/3OBS8AyON/ZqIYSEwvG6x4M+tn2N5ZRPRFrW1gAOu5cJvVx/i+/pvZ2PqcZXniVFOaFbpsshiZHhVf8i9x87SW9rBWcXi4jZH9npM85idSYd7F0u+49VbmKBm7uBR1n7aEukei+ooW+7cbbsyrGVvZrN44sum8GrVb328Ld8w7ojAGh3Pel8FLIWn2JGI0g6o6uvUdqfZwDLdZvOJAjvbSQ9VBwy3xFUGZhmPI1QZocoY5E291jhYZdXctx961ZUFTBxxbfwJyvoqepbG+ZUQDCk9Mh8TiUZoduaPZJZDad7k7ucBu6Wa+VWbGFTrGwttp3JczWG3DHhw3rJ69zmi1S2KUcLG1iJ7ecJC2liLnbAgDUuSoKSoAora8OjCgMNpwtsO/BD/0/nfZTk4BcB2fZZAkiZ8ylk8htwatHIoZUmTGq0cm3tzXLm8SmevS17E7I4zBnmC9ULuFMNKGNWOgc95Un2O7fEX6MXHOZg+wrxLWIkVc6HnDdV3cVaeQkl0y9W5x7yRyAckBOhZVlmgFIuxcKq/w4G1DUxYcf3SKteGPbaKkN3SMcjP8AsS8Wr/Giocl/RlltRdbLpzLEbH9m8yk90u2tRoU9Of3yPfiChqw/rSNdYf/TzB+hifw6e/+TH+ygdPcm/UYyM/zAflqVs65gqGzeIJuuFB6mDhtgJs9DwL8V1cn3ym7bbb8g3hBRdYwRCodP935y2x7gFN+FFgltGzwtLOW7w43MwdaFSEx5GER8ira/t/BKHqEEozZh0VvD34Fqz3jFxFQUUlTdhQquZZyh5mUFxq5vIV3AoA3fgkPddHoZj6mpyStO6yHFXcvbCJdYqdacqVSca5ccS1XJjWjbhOXJONNZIpO7nhMztzvKPSSGbZ2Vrg/N48wypAi2NtfofF/i5BUGHCClsbjgFhWKLDikvn1/ln+i18aiflytRxXpa5Lhts1+f4qDtDfu3tvNV2WOsMmOYxWjnyIqKoA7YmGQedJo2nLPb2UOLZGPUYVppR0xGHeZUwqbdwfsywuMBceggljaU8rISeChjaazdZf5r1zpsxVjOvEiKl0AKZUcyF8IblPR6854vM33eWycUVijJiUoUshBWHs4S/Fv4wvzz5XS6qDRyOy/mnKesNlrJH6RqHiOfa9SU66YQ0mxClU4pJxPa4y7CMcE6h+1N8CXJkgWN/b8CHHvp1BhcOcPHcYf7G4Nv4xaeX+KW9n8e6Ef3k3n3/fm4HAGTRSSblBbrRcY6phzlAn0xpLsX3MC8JvzX56a/z297S8uV5wQXWmHkEhfVV07+KWTyqbyyWcCa2RkVNG+1Zl1eAkIRq9lg3WGVUXwMgkkZglVesqxMAZLop4ze0wjYlU5kw8TvMsYoPHZWb4MzSl/hcb3Q4uBELuyjrTJnivGcqEzb9eZ6yjkN7b2I57mG0wyhHPyyJ82aTamIde7ZiSslEJozUHterMww2H+IHry4yvLrIk1cPMqwCKj/z1eqarDPGRCVRZ0J25Cr6mOCvF2z/yV0kcc7R3h6lUyiJseMuUR1wzX2RaXmeP+Tf8pj9MdKoaKIF8hjnm+tbuSY8qz+3x2SUUdQB09qgBA6mnnUBLYp3B++h9nBpEtAxno28SZJwvtlw8/aZSAZBmLo9Io4zF2hS04jxocSxnuU8evwMS4+cRvUtZrNkeeU6kyKiX8RYL3xiO+ZuHqXwJZYaP4uSKO2I3UqxnSeE2uK8oqoNnVqztTPPtAow0tw8Nj9+LyYq6V7dIHhsC/cDb6ZrCx4Y7fDQ7hne+/R5XvePv5+f3Hh6vxXQeS5zrfgYIChRnEzfzTdFx3AejMBi5HlzmrBdaoz8KP9p/C9fwG9/S8utvOACG5s5jIowEhH4CCWqEVGJMHoeJQolAYFKMERoDKnvEviQ0AeUUpHLHE/lH6G22xg9R21WCIhQs+kaaZbpqVZU3oCHEVtsTU+zq85T1ldZyl6DUTHWFftNCI1e5C55Lc575nzKiIKxNMv3HXWdsd9he/JZ3pD8VZTA5WmKEY8Wj/NCoDxzIYxrwVrHQA0Yss1udYFJcZbTxVk+8Mc/TKiahIPKC6m2TZbV7gJKPPOLO0RzQ/QRD0lKvW3YudYkMQS6JtEWLdAxisKF3CNv5LyZZ3d6hp0CtscZi3hKa1DisU6wTpiWITvbC2wPu4zKkEhbDiZ5E4trNVo8gXJUTjEXOnIrzIdNvG6oPcc6CrXzTJKGxzMva6QEREpmm3me1aRkJZki4vFOARad5pio5PDaZQZ7PUqr+cIgZlGlTFyIAqLg3fxJ/QsM8jN8fvAWjmURiakJlGV3kuK2FymsYVBGOC+c31nCOcWh9UuotMD11mD1MZyrcYMnKE++k9h8gO949ONc/vAbmFphMbI8ON/nn53+QT7lP8yr5Q28ppsyPzvf3DZ1GzpBRawtG0lMUCxT1ddf6D+DlhbgDgjsMH8C4rvIzDxWKix1s6EFhKaJUzUSEdD4aSOfzHLuQ1IJsT7iiuSAQyQi0F0KN5pV+48IVMjUJhhpKvx3jWau7HDW7WFn/5Q0HWBvWKnQZA1pFTEvGRNfclZf5OzoNwnMMt8UfBt/7D7JtNwAMfRVSGYav0UnqOgGjZsh1jGKaBaKFTL2KRM1JK+e6eP1t578OR5I3sfr0hWOZJYsrdHi2J6m1FZR1QFlESJnHCnOXiIAACAASURBVGFccP7sEXanGUo8e3nMF4cp58eOiXVNHK4XHBbnx3y0uMgDOwd4QDy9ZMowT5jWAVlQMSxi9ooE78E6RaAskVIMqoCtognvykwTc7oYVeyUhuu5xntIjONwWvHf6jfzjy7cujFYecuoNswpoWMcmakZVwEXrq4S/0lOd3WTwZVldnf7BKZGa0uoLbH2VN5hcRRYtvXW7HMIeFKd5/L0JJ0gJLeanSJir9IY8U20hvLkVrOYjlCBRUU1Ls5w0yuo4WWiJz+BXTgAJiCbH3BXd8puGTAflVyZZNyVxfTzt7MSa1Zii/NNNbKO8RxMSrR4rhQBT4xz0mCZvVZgW+4Qd2STa5g/QRmMmQuPYKmo3IRQdSjdiEClhNK4AQIfEfuUxIcEs6kIQuYyOuEhhsWFJkHA15QyItI9DnGsabPtPbVrip10dUDoO/vv7/wY6ysClZCFB8jrCOumLIYnucwmHd+h63oc63wzl/NP81+mPzN7pXAge4wtN6W0HRajggPZiLlkjHWKJWtQO4sM64zMGJbLBTbLPhfc72H0IrXdItBznPefY2ncJzMRc6EhUo6J1WzmMZ/eWmJcN0v7xDQdZgPlqZxwLddcnDh26pKBTKgoccoxyhuf8unxr/JrV36QQC1w1A6xTsiCktIadsuI0moSU7NXhoxqzU5p2C1nEQkB9MSzno1YSCYMi5gv7PVnx2gI4UiWczB7I1fGfwBYdtlgkUVKFxDrxg2RW01RBcQ65eLlNdLtea7sLDKtAxbTEXOdIYGuOZRUfHpHuKgvsGYPsWOb4jze59QUXJmC9wmOpsfYtAajmnke7xSsd4bkVcjVS6sobZk/dBrTmUflI+TCRcyFi5BGeL/KfJQj4vdjjI91LIuRwuOZ1orCNckiy3HNwXTMThFzeaKZMiZV81TRsVd8wRrBkETrLAenWLOHuKwvcW70n1/sab3iuXOJBmYOS4VCE6gU5ysS3aTIhpIQ+4zIx3R9SjqrM1B7R4UjwJCoPgP/dCOWs7AaH64T6QAPFM5RuaZeau4s69xN3OlyNf8cVX2d3Zuyo5RkRMEiE7dDLgOsarogGG9Yie9lp8oYF0+ykr2Wwo04I59lZfgY81GGFo9RljioCLSlFxYsRxFdI6zGsFJpJvb7Oa1Oc3n8+yTBAnfxGuaDgNrDZh6wWxq2Co0S+Lm9j5CoPofsEeZVQqyEYNb9dWItubNMKdlUV9gqn8L5+pbi139U/wbzV7+dN7gexzpj4qCaFXi5YQWGfHFg2C4tgfKsxEKqfbPRFZUcnd8iSyesAivdAV/cWubKJGGr1GwVCd/ZfZifGv8BIHRkiUIqrPdEyhNrx1YRsFVoMlOzUIaMipjIVNROYZ2i0xkTmJqLgzmOZl0+OrzA5frTHI9ej0kjRBTzbplJ7Xli6Get0x0LQcC9meee/og33PM4C+sbTLb6XLl8kMvn1kk+sUt44DxqNKC+FOErg1keUU4jAuWYC4v9rg2hclRxE/FwvQgpCj0rSu6Z1gFbRche6VFIs5q6aVP2BgvpQyzIOhpDITmFH81uPC8ftOqThau8PXgHE2uZ+IrMBZRYVuxBLt/mvFteWO6YwM7pNSw1zlsi3UGh0D5AoYhcTDKr3J9JQNc0GzIT6yhd09fFUhEG85QVOD+hG5/iQXkTqRgsnsrZJgdsthOe+JDUd1mO7uWKHd4ShuP8mGk5ZkqTYbYXJCjRhJIgKPpmjdpNuTb+2P5rPhhucenqm3hnNcepKmA5nhLpmrw2syIqilh7OsZxNI24lM8xlzyA8xUHTYcjmSJUnr1KcX7s+H3bZCV9U/LX0FZjEArX3AA8txZwUQihT26JSb1BUV3m09FTzO2eomtiVrJZixwnDCrFlSlslzWBCKe6wmpSMqw0hVXUTjGtQhKX0+kNWT1xgROTmNOn7+J3L65zaaKp9xO8PFO/R5dmU7IXOsa1ZrNoGjGOqoBuPGV+rmmJc37jIMv9XRbWN9i9skwvLHjjslC5d/G5yYBLnGV7+jj4mmPJfdzdE35tdwNLzaJf4NFOwDvWL3H4wAYL6xskR6+SPXCF+NMjrjx5hGqYEl+9DFsT3LTPeGMRfW2e4c4cRll68ZQ0LMirkL2Z62RaG0aVZlg1vtfdSlO5mIlVOJqC44GP0BJwc2fd0KxyiLtZdD0C0UxdE11SprfLuHvp0Y3vYtGc4JBd456sEdGwEmLbfM/8rKawQn+5YVpeAO6YwJZ+ipEILYrAR0TETWEXcSQ+ISYkEo0SwQiEumnIB4quitiyh7hWfhwArXokep7S1WQEWO+o8YAHDwYhwhD7lC0uspw+yHb+5P7m1s3k5aX9n/vBOtBU20rMwi0bYtPyPOez0/zR9sMICaXVzEcFudU4oHSyv7zXAqWU7E7/FKW6HO5rSvdMpavSNVEN705/BAEOpwGBapIYPH6/2PekhgqhLzHr+jhr4UE+PP3XX3IO50a/zR+nHdhcRatFRlXARm7YKYVJ7egbzXoGB+KaXlBRWkXpPPNRQRoWpNmE7tIO0cKAaG7I0sYyh7aXeGqYUThPEh4hUAlb+WmmwQ4r6i0MyoDaC1enHo9nt9IM84TV+Cr5NN5PFXZWMxp0ScOSle6A+SgnvLiEHR1mN2w2A4dqyNVpny9Of4dudJhTaq3xDwcVVRWwdeEg2aDD4uufIDtxmbmdHiYuoduIvWzU7F1fYDTuoHXNYjZieWkLEc9olDEpQ66WGWfHMZtFU03MA4NSUWrFdinsVhUWixOHcxaRYD+kTylDKSUBmrnAEFpFZWsS1WcxfeQlLbLd+C7ukteS2pieCigs9EOwTihdU/0tEKHGzuoet9xJ7pjAXs+/wMHkIfxNrfs0BuUdTQqCIhJFoBRaNWIU6yb3f6+uucpTzQT1At7XGKL9L0RTbd8hyKxotUYhZD5mVU4wlhHEJ5naBcbF5WfVM/DkZVM1Ki8vEphlrJ2wmr6GME65PhnvW7+b40/wdKfPZHuNR8o+y1GIiGdaC/UsqiAAIg09Nwc0LVV+afgRHvSPMh8E9IKmrcwpeRSHZz0OOZJZlqMKD+yWholV7JaKYNZv60ZxmRUiHpS/xGcnH7ilKlUnPs7p4nf43GSHJ6c/QCSejm5uOIkWlmNhLrQY5dgqQnInrMYVR+e2OHrqadKDW6ioRHcKUJ6ltassXzlEqDOenOY8oN+Kx/Ougz3ev/2HaIRP7zUbhhNfEhOwMY24MOzT3ThAEFQo5RhNUq6fO0RtNQpPHJYcWdzk4XGHa3mfPxmeRas+56pPcHr8qwBUbgmnINWOSREBPeKiRMTTu9IhuLtg7uRFzNwIrw5S3/ca/Kc+y5XNZa4M+9x38CJrBzcYjzLKKiAvIq5NMy5PIzaminHtCVRTgGdYC9sl7JaOqa9x4vHYptj5TfHS/WAd483+ja90DodnwR0ADhBlnf0ym5fHH+Gl0O58LnmAb4newrliTEciFsNm/sDMlQaJbjp3+BqcddRtacg7zh0TWOuGlLMCK1oMlVcgNMWsASMKLYIRQWZ9VEMlON3UMD3hX80k3CIvL2H0Anv1ZdZUE+sYiKLyDoNgbvTp4kbr6wjnHQpFaFK6epWUHjv+MluTT6JU95aqWlV9HaW6TZA6ASvpwxzwRykk5/T4V7kw+h1U5118cgSH8i69QBEoCNUzFmqoYJkeTY8By9bkk/wun0KmmvdmP8jBOGB72hy8VzkGleJA7FnLRhwGaqfIa8NwtqzdKgxXc0VpBYUiDtduaSw4yp9G6yYi45w+y7xbJq9TuiokM82yb1gppnWIFs9caHloZYMH3/kRglfNrBYH9A9AWZJd3eLo0jUeHHWZ1Akbhabwlg9uDagp+K3p+4EmAqAXn+KovJqdIuTxvQ6j6jBHuwOMclTWMC5irFeUVmOtIolzHlm9TDdY5mNnm1TWGzc4ENbNA2RaM6g8O3lCGhUEpsLWmsG5g8xF5wkPD/ATQa5exYQR470Om+MOsa6x1lAWIduD5nqEuqYXlhS2Q+1uNIpsRGbiPKVr/L6RaLyP2UXfssGVRsf2o16c9wxry9TXWCxzvkNHGQ74Pht+h77v0s+WeHz8y1/HX8rXRmCWyYID/P311/NbVwwdrVhNhFh3GFSObiBkpknzBpgPPbkVRnXTc+6GgdJyZ7ljAqtVtt8GJges1DjviCTGeT/bdGjcA0aarqiRbqxYJYY8j1gO72ZLminGukdJtd/S5YblGolGI1g8ua8JMASuiyWjFovyQoBhmSXq5AE29CU28s+SBssM83M4P8a5IVfGf0AvvocT6jX0fEpEnyz5y3y6+HXOjX6bYfogpb2XVdtnITTEkcysbo+WZpMmNMs3ZUJ5PDX/afwvOcWfJ5GUgRcCl3Jpokl1RGZqjs5tkwQlaTKlqg3bwx7nB3PkLmOrgIqSvLp2y7X11PuujO3qHD09TyYBC6FmPhR6gaNrmhY1q8mE+w9d4ORbPoG87QSTU2/GbJ9BTQaoyQCUJjj0OCsHrvHguAMc4NI0ZGMacmGqSWWegQT047u5j0f5nvWAv3/p4/zt9YfIrWZaG3aLmKVkwnw6YneaMSpDKqeprMHUhmPHz3LfI5/lu78z49f/xtv4jk/9Ir34Hn7q5GNs5nGTCuxhXAfsTVOUNNbw9u4crtIsPvwEasnhhzXujy5w/dzDjKsQLY7rgz7jPAaaWhGjOmYrj8ktFLMUwQAhVI0FV1ghsB4jgqs9oQ9nnSQuAZ682qJrVtHe4Gk8sxU1lVTEdFiMDNZ7irxHJJq/urLC/3J+/rm78N4RNMvRvRx3p/jItZADcSOm86Gd9XBTJLr5bjoPtYNINa3ojQj9UFiq+riXgOX9SueOCWxtdyhdHyMRohXKa6wYrDe42VJfSbN0EWmsQS3ghf07a+AjOmYFh0UTUJAz9AERARUWRxMnyixjTBCiGy1omsqzRKppXhgoYa+qqdwBVKyIfcZ8dhhLxWbZFLt+b/TOpleWh5Gt+Wz1n1lK7uPq+KPs5WdJ03nmbIfcarQIi2FNaiyjWjMXBizWJ7lym0IjZ8a/jtGLPBZ+28wqclyaaoxK6Uc5vXRMFBUo5eglE/pFQqxSuoFipZrntEqo7bNz54V+ch+x6tFzHU50A149l3O4M2QxGxEHJVFYknXGrNz/FPouTdVbJOjfRwWE+aeQyRgZ7lFvptja0ImnPLB0jRNlyHaecnaccn/+ML2FB/nRN/whB9/1/2Bf8wj/ze4ervdZ9IWn2PvNJXavLpJ2xvRPXMZVhiufO9kkInhh9Z6niU9s4l73CDaM+Qs/8VHqt/8so7/1P4P8NqI82+cP8sT5o2hxVE6zPe5QWoNRFi6sky7tki1cxY810wsrXLq+wsRqvDdUY0WcJ2hxbBXx/gpgWAuVa7rzKoHMCN3AsxA19SSu55AozbybpwjvZRwcwPmaSDok9Ih82LRwBxICIh+wlgYcydws1jhir7b88Zbiu3vfy3+pPv8Nq/q1mD7IA/4+FiJDZhoLPdbNea4lNaluumvo2WdQuKaBpa+F0jUdNVJt2k2ubwB3tOD2pLhAEh5CSYBSGkdETb3f7M958L4R1+ZfEw8KYHEYDHMcaI6d9dGayrSxZKVEeUVB0yZG0ZTRC0ShaVwPXaPphc8sg5w35FVKZNeICIhEU3vHml7nZNzZ91EBHNUh3fF38uvTf08WnSSvNjFEzc6zEjLjyUwTVD+qNdbDsl/nynNci9pu8bQ6w93ubowX9krPeTSxnkOLozMTlbLWjKsArZri3H0TcI+8g7P2U4yLJ/fHU6qDloA+y8yrmOOdijcefYq1oxcJOxPwgrOasDciODCAMsBsnKNIfhvtLGqwjdQVTHJU1zF/4iJKO8Znj7KQjVnqDOlHffaKmDfc8zirPzbGv+mnMbMVhQJ4FOb+IvR/48fh8ibugfvIT72Zo1/8EOrpxodePPZ2Ch1h9jZQ+ZjpA+9GNj5I+h0JMhrgenOs7/7/7L1psGVZdtf328OZ7rnju2/KfDlWZlV21tRVrVZ3tVqNhGiQkUAgjATCBBgwAQ4F/sDgMA4IQzgCwp+sCMDGwaDAKGjCHYAGS0IzkrrV6knVNVdl5fQyX2a+8b47nnnv7Q/75quq7kItBFX+UisiIzJf3nfuOefus+7aa/2HO2x+7RrNPMEZha0Vo51NHuyvsyhj8uMuwe2M6rhDOW9hrUdEzGrNuApItSGQltJKsuWk/KG+xcPP0zroBt794bj0tjoShTItAnOOqfBsOukkgdOkhEghPCVbamIleKpf86H+CIdgGPX5/EHApG6YNI7L7hKqrdme/+J/3kPzTeJU+kkesY+xFgcMI//MFOatzX43qEmUvx/g9YljBUI4ZnWIFFBZX8la9+5uEx/Ef7l4jz25DLXxAyaHRUjfh81lTmZjtBUoobygtYOWgFBbZkr6IZiLUWgSF9JgKURB5CIWckEuMpzwifrtmFqJx5UGQtANvdsrwKLxLYieDYAAKQThkgLqXEiq/TYrkI6LacnHz2xz9Tu+RPBch+zncv7xj/8JvnSoQcIwEsTKLIWivRVM1jg6rsV6+rF3wL3eHvcXv85WcgFhBUIIjkrBgzwgkgO6QU1uFPUySYwrRW58lX+aIbV+nGtvS7DWZpRmzr68xRW1RawMWhmsUTijcE6g4wrdzRCpgDDAxQku7mKjPi5soWZ7cMag93eIZhPWz79KkBRsX7/IrEiQwrHWWtBZGVNc+lZ48Eu4ZEg6+Og7riv76PfR+tkfRR7uodbuoj7xP2GfayiybcTRK0Rvfhlx5x4oQevGG9iz5zHdFUSrDVJRnnqUYPU2YVNj+muo6RFbX3iR5tc+wv5oiHOCxf1VjvfWmM1TplVMaSWlFeRG0g9rEt1g6gDJWzsi8C2nyvoBYKwsK6F3hRiWikMnEEISq5ihjbDOV7wlFsWSJRgKaut91pRwbK14HLESljuLDcxCMW8MCMnTXKZOS+4vfv13/cQINH9q8JcY14YXuUbkElquTce1uKO2OW3O0BKBN86Ub+0Evcg7SyQOHJUhi0ayaDyFuB0YVkJDJBWjJfkkkMnv+jw/iN9ZvOemh405wroKYyusrlEq8B5c1ORWIoQgsl5jNVGQKsdK5DgsQ6ZNQEJESwTUzhA6TYCkdCUVGRUZ1jUcmOs8IT+FxSJgyZ0XJ4nbOpZcekGqFUr4n9fW//zh0CqUjlg5ttI5V3/Pl2n+2l9HxZu0mr/Np792k5a6wKjSaOGWdE5JsTx3KSBA0mWNQ5GiVedddUm/nP8YT7X+OIEJ6JJwex4yrkJSHZ6cq1n2zSrj2xUWR9t26MZXmBZvoNWAJFhlXtzC0fBTvMyF2Q9z+WCddneGs4IgrtBrx6jNGgY9XH+F8vyzyMFTBEEf03mU8IwfDNnHG8SyMh2c+R+Z/pMxjCHUDUI4gqTEJUPk7D6U42+4JllOcAtH/mKA/I0v4q7+HO7SZZKDXRAS81qGCCV2ESOiGqV3MFc/giwWyPEucrSP7Q8x/XXU9BA5HWOspK4DyjpgtL+KdYKD8YB5FfFgkVIYSW4klYHSSuKlg+9BqTiuBOPKV3CVhXHtt82FkRRG09i3kBrAyRetZ4KBcYraOgLp18i0thyUjkGo2RmteiueKqYXWi4gmTceDjWpLZfNY1RpxuHiq/9Jz0kaXaKnT5PZY+4WBYGQnHPnsVgUCoPhkrlIKBRaCLLGcVT63jL44gFgVmvM0rYo1RYhJONasSzkSbSlj0QKSWsR/yed4wfxnx7vi223tTNqV6KV/0DNsk1Q44kFWeNxBLESRNLjS2trUChioQmEQKAI8L3PZ6J1fqa4jnE1WX1I3RzyRvwlLotvoc1DKUQojDt5kGLl/xLKt/pVi0YsJ82ghWcrBdJvpYSyCKlRMqJZP825S7fZn/bYmXcpjFqqavnkumgEpXEoIRnYFb49/pPsyUP2ghsnttZvheOV/Gd4pPWdzJmxZzXdrENPxEjhe8YPxWxOtrn4QV1PbzHlDUC+Q8RcoBlXYJwkCBqcEwjhkEkF7QS7fgobp/7eZ3cx3EUmp2CpDSHFW8sge+4HOfvGP0Z87hlmszbD4Yh484hKaOzKFWjyd/mADWIY4a5JFrtDylGX5Noeql0gOxXOxMjAIpPSC8RUHvIl5lPcTT/AU2cWiNUCOR7BwRE2S6kbTW0VB5M+jVXcm3WZ1AH3sre0fi2C/SI4Sbi7uWBce0ZcLBWFbZi6gj1TsVWs0gkidvPAv65atqqWx5JAKKUftPLQhdcjCaau4M6iQzpaIVZ9KuOTdC+0tAOBc1BawfY84oXqXe7R20KguZj+fs7Z07wqX/J9X5fStT164kP0dUCsBI6AWW2xy3PrBt4p4qAqEULQdoq2doSK5RqUJ4y78x2PlDkqYnYy/9zpZTtBArFc4sg/iPc03pcEC97Sxbmly6toyGWOsgrtBLXzQPhF44kGs6VGy0AkSCH8AhPiRPD5bl4wKl4BvPB2kjxGIBPGHNM4Q16ntIQ+GXD5LZR/jAahZC22KAECybT2iVdJb7WdaktjJbsvPMaZz/xt7Lkt1IMHJGtdzq/vIQTcn3c8vtRI8sZXypGCDRWwSUgg4Sl9hsKc4Tfko98A47FuwY3sl07wtp34UapmwVb4YU41m3RkSEcr2lqgpSA3glaTsskVTFp/3RZUEIen2StqOpFXtZLKUM4T2qGheupTNBvPEtz7ItH288jtW9h9g7y6zuJbfxCVnCKONt52OI18pM0Z+TWqvT7xUzPc1lni7lWUjMgWN/j6cKsfxp5/g7RzQFo+oH7JMX7zLACt4QTVKtGbBeKxNagqmEwJXvgiZlsyu3kRGTR0uIt0Fo6mmP2IeppS1wGTMqbKUkZVyIM8ZL/w1dtKJBiEfly6m0se5JLCOB4UJRMyrHAY2zCWR+RuQtYcUcyf4nJnkzemjklT0pKaeGmDPqorcmoSE7AhIsJlko0UCALSRp1Ui0o4SivQwrESNTTOk2QqI8kTzaPVR3gz4V1Fv/vJk1wQTxHZAAtcsldPdDhioWgvP/d2AL0AaieprceHx8qxXwgOK0EgBMPIsR4bYmUZVXpppun1Fk53j2msIg0qekFFbSV3sxZHpZ8XVPYbTu2DeA/ifUuwoHBYapcTiBh46MUFtbVUQrCoPeOkdo5YSULpK4NZs9QUwDsJzCnpxpeJZZdAxBhXk9sJR2xj1Vl27Ots8RgtkyCNICagxsO7Ut1C4IHt01q+bRji/1hgVge8fvsC9U8EJK2cIGlhqoBWe8HjnRtsjgbcOVpjL/NV4aLx27LGwTCqaKxECce0DthqbfIvxKe/YfjxMLmm0aVlNSqooseoaFAiYhAKTrcM3cBQGMlRqRhXgk9UT/FveHuC9W64nxM/z5f2/gAXtu7RGY5prY6RV9dpNp5Fjt4geOUrFF9NabJ1VFSjRhnxa//QH2FVYq4+RdPbRJuS/KN/EHVlF10syNcu4dpneLiZlLpNbRYEKj05g1brPIur30PcvkxdjzHfdcjav/+H5F/tABAOJ9BrYfpD1P4DzH1BddAjP+qTz1soaVHXGoIHGdasAJAfd7k/GfAga2Gc4F6meX1qmNiKngyJlUbgRcDXYt9KOSgEK0HIrC7Y5hVqm4GFafEGANerA/63B09x2V7ldJhwLoWV0MtD3pzH3F4oRi5DVILTcUSivUTjlW6DEp4JFyvDcRnRWAGSk+T6kI4cCMelsEteXyVIEw4XX0XKDt+X/ml+6OKUf3enRycQ3M/9mg5EiHHupEo1zrcatJScbRmU8K7FpZWk2lDZgOPK92BDBak21EuRm7Wo5mJ3TCcuTrSCrRNEukFZyVYrp7KSB7m3ov+gfn3v431MsAYpNNa9hb3zeFaLQVJbSyjfzoX30ThOGDXGOUIp6bmEDXGJSlQkroWhYa98EWtnTPBVw4gX6SdPoERAbo45rZ9gygGd8lkutn1VUBgPW3nYLrBOEUhJNzDs5ync3yIOalphSbuVsba1S/exu6zVis3rZzneH2KtpCgj2mlGd+WYpD8jO+6yd/8Utw7XGJcx31te4cfduw8/FuVtWks1J01EQkg/UKzFlovtjCc37tMYxbXDDa5NU7Za8O9m6Te47WblbbSAptaosCa5sI/tXiHc/nXU577E7LUz1FlMmObIsEIGDcWdNWTQEKkj1EtfQ54/R715Adc+A6sfRQU9sOU7kmkYDt/10027T5AtbhC3ziOjDYo/8nfQT/00we3Xsd2LsHcf+aVXaMYt6mmP2f11TKMIggahDHUW0xQRzgqaKuD1a49yb9HmoNTkjeDNmeUVcQOjvL7Fx6onCaVkrWU40ypYi3MKo7mXtXii6vD37++8Q+dVqyFJsEIgYhoMLSU4l5Zc6R+TBBVPljHPHw35VwcLrpkv8+H404wrvy56YcWl/ohFFXFj2uP6LPJf0tqha0UoHVo45g4GkUVJyWS8inQSmSq+Q3+Uv/rhW4yzFs8M2tyca9yyiPDsRb87i5Xvvb8FW3Qo6UikQxnoaIOJBaH0VWhhBNdmviWWKMdqBK2wopvOMUbTNIpI1570YSXdsORS22Fdm1hK9PQDosF7He9jgvU6sFL4brzF0giDcALlJBKfRMFvuTNjmTReE/Wh2Z4UgkAKVmVAXa0zFnNC54dmz0R/mFrUCCTb7iUqM2da3MK5EkfD9fI2nfhRXlAvo0ZPsRFrssZRLKkui9r3gNPAW247J8gbj6l9OOwJ2xlqWEPkGCQ3SPdG1IsE1yi637KN+cizmPYZVnfeZOVLX2D1hUeZTTso+Qg354+zK37rXWzIDVl5mwvt7yZ0IWfiiCf6Dc8OD7mwscvW1ZuUk5QwaAjVJs+Pevzh9p/hJXubm4uffceR/vX9nO9/xhCvHyNXwOgA9WtfYvryFnvMMQAAIABJREFUBYpZStKfEnQWhBtenSyKalSv9hqBeY2YTgjkXfThPWx3hfrKDxAEvXe8hxQaY0sQ71w6xY3PkNx8ifLSs7D1e3zb4eqfh6vQvPlj6C/f5N7nn6WpNf31I4QyTI8GrJ95QPvsHs4oylGXYpoyPlxhZ9rntWnMovHU1utuj5HZZla8yan0k5xuSU4lhpWw9mpaScZqb8yFrEUclfzI/gor0SVSBnyIc4RSctAUVKZhU6e0Az/UGrTmrA5HVGVIZRRPHp/itcW/47j8NMvuwQnk6c6sy6/thSxMw9mW5nRi6AS+RVBZRSCgHzS0lGQ/CrDFgIHtMggFn7n2CIF0XJtaYuVYizSJZrn19zOAh3CqvBEI4QXbFY7KSAor6AIX2wukcNRWsrNocVQp+oFhNa4YRn5XZK1klic4J1DSEkhDIz27DmAtqomVOkEhfBDvXby/CVbG7xio1FQY0eCcw7qQ0Eqs83212lkmLj9hY0UERE4TW0knkGyEEe1GE2u/za+XFa51jj6fAAUvqi8SyTaKgFF9i0W1SyHH/GaYcXnxFBJPRS29lDc9GaKlprKCwijazi/0fnvG2tYuKqpxc4EYtpBrLeJLBXF5CGFI8cwfhfVvwZkCG3UJW2+w0X6Z9rUtzhyt0tPtd0mub8X24lf5M4O/wNODmqdXD7h46h4rZ/awjaQuQ7rdKU/omlAZxtWQlxacVL4PY1fd48z/MAE2cdagtq+zuH6KvTun6Q18UhXS4YxAKOeT67AFUQw9ie2vgFTIe9vIe3ep4jb5xrMI3abVOn/yPsXhF0jXv/Pk39nuL5Jcex6sReZj6slrsO77ukW5hx7vIXuWwel9VFSTfFtG9VuK7dvnkfc3iLoLorUxKqyRyrI7GvLKpO0daR0c1hW5ypgVb3Kh/d18Z3SZT61PaOma4yW54P6sh1aGqtHcnw74X89e5sXjiNz4Y6Ra0A9bLBrHMBKsxYZ4Se81jWIy8+2MfihIwnMn7YELacHF/ohWWDKMCz6yoimt5GwroxtW9KKCw7zFvG4RKosUjlBa2gGsWM2ikRxX/hz6oaATSLqBYBhZAvmWU4ZcbtgtAucEibacSzOUcOzlCd3Asp5kpEGFECCFYxh7NEOsGi6u7xKFNcZIyiqiMYrKaFphyaC1QOQpx0VCZjxDbS2q0O8Ucfsg3oN4XxPsKHuBbnwFFMSkhISUomAh5gSEFKZDREBLBFjnF1xNRSkLFJqO7aCMJJJeRGUQarSEwvgqxzrPWMHAyGVMiut0ovMkasBa+BgutOglymDsJsvkWvCgfoV+cJZL9gpDqzFWLBe+JVR+Kh92MuKrI9hYI//wp4nWP0Uxv44M+wihSZaDory4B7bxE3IjcU4QBTXffKbgXyGEY5S36IxWTtAA80VK02i6nRn9OMO44TdUrwB9O0QcfJn66kfQ+3fJv9ji9eefJAprrJFLEL+mvL/qbbaDhqCaIDYs5vwlygsfR5YT4ru3cAclwc6bNCuXEWH/5D0Wx18huvcSxewB8aUfAsCpmPrCh6jPfhLKY7ANi6PfRNRzkpd+GfIMkoD2J/Zxa+tkH/kztIJ/zfqrh2zfP42+3rBaBUhlyGcp9+dd7mWCRfMWEH4n/wob6XN8KrzMHzt/wJWtHYyRjKY9Hkx7ZEaTVRGRrllLZ6y3p2y1elybdnmQv7XMYyVO3Cr8mkwxVvLm8ZBb84TtRc1V9e0clY6n+iXPbNyn15kRBDVPtzKeBo8x1g3Hkx6jRZt5HbBoFFo65o2Hg3UCR24Exkk/tde+BZBqsXQnfqv/3wscZ1ol3bBiXgdMpGYzKTjXO6aowyUZx3K2PyIMGqT0mGfnBFJatG6Ik2Kpauar1CSsiFxNYxT78y478w6doEYLh5GWykrfR/4g3tN4XxMsgBQBtc3J5JQWbdq2w1geM2NEoRa0XAdruyeT1UY01MLbe3vsDASNJA00LQ0St4R1OQrrcbCZa7gnb9GJfNXVYchgOTzJRMZUHlMIg0BRuYyi3uVBdYc07XPOnae0glmjyJrgxL3VWQGDHsXVb8O1z1LXY3S8SfR1PUml2xipEU2NzQOaIkRJyx86M+ezk//4fXGu4gvlHeqjs+wsejzIWqyO1hjGGWlUoqRlZ3+D25MBz8/f/UCH4j4PPnuJ9b8+hde3ufH8d3K46DBkTl0H1EWImLRpqgAd1oS9OTYPUJMCdbhHGL4IUkKvjyj24e4O+vQbNNGA4uZnMb2ziHKCqAqia89jH/kBvyPx8kyQLXlsQiMX+2AbzOopRDZD2l3sqbOUT/4x0vQSi+ca1n7t37Kzu8l01qE1ykj6U6yVzGsPT8psgxKSOTlXo+/iQ3qNyx3PnpvNU9JWRhoXXNA107xFHFY4J+i0Fmxs7bI56eCuP0ptu34IaQWlZal7IJkpxX7e4ua0x+vTkP3CMnEFm7LD2RZsJBmddEG3PyVIihOGXLVIaKqALE+oZ4pJrcmMoKgEofS16MPkuRZ7vY1O4JErXnBFMKtZ4rR9a+B8Z8LpwTFZGbEo/UixMYqdmYcFArQXbTpxQaRrRFRSVSHdzgwpLYt5ynTeRgpH2Xj8MEDeBLw56fPmLOCJnmA19lb0B2XwDfOOD+K/fLzvCbYwY0KZclTdgBB+f/w086bPz5Y/Q6IGCKkIRIh2ilKU1FTUrkQKhaGhFCUTq+jVKaH0fVOBdziYuxKFIqMgFAnV0p4mICREY7HUomJUbyOFZE1dZlTfOpGqe1KeozQwrgQtLXEOomX/tZh0SHMv6CGEPgHmf304u6y6rEUkNTqu6LQWyKM1zre/EU3w9tizN9gp1jmVRCjht42duODc1j2mky439ze5NU/Ixf67/v5+/jKrjzvUiwsWr5/iztGqNz2sQoo8RukGt6SStjZG6HaGKwNcUUMYgZQ0nXVsmBCEEeLuXYJ9b/USXnuB/FsHOB356vzOIdXNz6IufB96skOwcwM92qNZPU3T28LGXWS1oHz0D0D2gCj+Gk6HMLlOHW8SX/91ZlNv8xMEvsIu5y2s8QgMKaDBMWJKITM+Hp0jXoLpR3lCYyVJlqKVIQ4qikYzrWICaeimc6QyxElBLy7YKGMyo8gbibaSaS0pGzgWmsJIDkvFfmE5rmsve6kV7cCbREppidoZQZrTFCHFpIM1kiApaSU5naggWm7xKytYNL4O0J60SKq9sWSqLaX1AvGpdoTSD1gFgmHUsN6ZEkeFd+ZNFhR1SGMUhVHcmEek2nFcrbIaV3xo5ZB2uqCuA6oqJGl53K11viqelzHzKiRZDrjmzUN3Z0FjJfNGMa4UzQdQrfc83v8EW+3wULbkfn2fH8tfPLGEMUFFL9wkdTELUTCRR9SuoHGll24REoVmDhzXEYkOTmQDAymZ22w5PGsQKHJzTKg9yqCkJhc5e/bGCad/Id/OtBIcNiUBEi1C1mKBko5WWKKU4Xh/SOflfcKtlym653C6zbuFVDFNuo7ZPIu6f4hOvHvAud4xf/fcFv/tN0IjT2KgzvJkGvNoJ+fR/ojTqwdsPX6daOOY+jc+TNloTiUVr2T/5l1/39gJ//uP/iX+xl/7pyQX9xC/7lg0AUkdkhcxaWdOmBbopAAraOYtXK1R3RzX7lJd/L0k6SXqekKZ/ibx9W14+SZh5zZsrEPnIrgG2+0j8gdEr34Zbr4EO7tgQfSm6KpEFosTYgNNie2do7zwHEQDhNDUe58j+sIb7Nz8dt8rrEIODlaZZCkHWZtrs4TCGDIKMjHnbvU8XdvjyVaPRSMZVxGhMhjrBzdKWkqjmVQhWlrSaY/6ZkCwRID0woqw0QRCM2tgXgvmtWBcCaRQzGrLzDQUeAB2qgWbcclmd0ySZuSTNtUixjlJVYZYK1FhTdNoFlVEKC1n0ppBo7g999KL6RIVUBi/DddL3Gy6FGHxuFlBOzBsxD5ZR3FJlNUI4Rgm/pnotRZcXvj+8H6WclxGHGUp7ThnXiQsypggS8nKiNoqBi3vIaekJdI1LSs5XSS0dcAgKpnWAXu5J6Z80IN97+N9TbBJeI68uoOSPdrRFpP81ZPkCt4O5Wb9gKPkKpPsNbTqkwSrABhXo3RAQIQRDYc2ICi7OKfQEnqB5F55DS18j1W5gKy8TVbe5sHSDiQKTlPW90/e76EurEAjRMSBPGLP3uA77acYV5JE10jh0MoQxV6cWs6nyOkdTDUGFcPbQfpAoFJc7yrlOUimI+Jqm24e84i0KGn5aPKn+Ur+Y+96f/p2hdXIstHK2BiM6K+OCIdTRGJQuuFulvKZe8U3aNq+Pf7uzk/wV//yP2Dvv/knlI1mvLTw3lKWzsoEFZcUkw51HuGcIB1MSQaCpjuE2h+zye6iqgxOr8KdQ9yxw14Z0kovAeAO/xmmDMBZiivPoc4c4nRI0zuDsA2iKaEpCQ5uocb7mHyMu/RHCIIeRX6P4OgWrtJEYeWJBEZRW8VLowEHpebW3HJkc3KZcyP7JQBG4RGLpusHkFZ6SxhgXIVUS7pyaf2uY784xVYrJ5QWLXyZ5l0oJNNaMakF49qSGYMADI6pK8hERuQiAgnrSYZzgumkS7c3JQwbdFxS7K5xfNxnPk8ZzbqMy5hYGdZiX0Uumj6VFSciRsbBUekJNJtxw6nEDzrvZi1OJRUrUUGoDFobpDIEgU+wrTSjszIm7GRUsxZVlnBx3mJnf4OiDtif9jgqWpzrHZNXIfMqItINa6tHtLpzTBVweDAkL2LaQU07qMkbzWEZECrYTBzB9IMewXsd72uCDVUbHT9KbXNOyyuU4fRt4ssPwzHJXwMcjTlmZh5uy0O0iOipNRoaxvKYxhoWeZtYeo3OUfYCWg2ItO+39pMnl1RVv5DenlzfHlKmGDvhgXmdafEGP87LfPbin8I4b+QXhhVJewFWwGxKtP0iNk5ohudYBB3S7hPvvE7dIxw+x+JqQWJ/hba9i7OCzmjA96yd4yt33vU0eK69wlYrY7Mzod2doYKGxZ0NynmLm3fOUVvBV4t/+9uiEapml1/4+H/Auce4l3nOfkvXdLtThDY0eUw+S7FW0h0e0/7QXdzZs9gwgXpOkd8j6T2J7D9Dde4P4G78OOH1l2hWTqOBLNsmqSsQjvKJj5Oc+77l+05I9TshXVn4c+jjO2ANzexNGlMg0rNU5z9F8vE9Oi/OyLYD9vMWoyrg1YlmWhsemDmH6oDtxa/inP9CGdpVTwRxUBnJotHMas1RpamXW93KCrIGlJAcV21SbUmV/8/CSg4KxV7umBvDzNRMReZ947DkMiNnyiqnCaXvXfr+taDfn2CNpFok7Oxu8uaxF6DxTsGBdwd2glQ3JMpLvwvxlqaEAPqB4YmVI/rJgmnRYlqHRNKyms7ppXOaRjE7WGVRxpxaPaC3NkJFFcW4g1SGzul90lpTlhFfuH2J3SKiGzScA1phSRoVdNIF/VMHJKcOcbXGOcG9e6fQwjKpQ+Z1gBaOy50M4wT/kU7TB/FfMN5XJteavMj1xU8D8HTyfTywfQrenmAFUXDqXROhcxXT4g2qcMEl/XEWcs5UjCldQeJapC4+sc5+KH6chOe+6Vn1kscJZMIoe/2E8QNwZ9HmSv8YJS3OeTRAOe4g3yzRzV1UmoJU2LgLX5dgH0aw8iz1mR3CqiTNd+nuD3mknfG97b/MT8//8Tte+8MbP8y3rCy4NDji7Jl7rD51HdkuGb/wCNdvPMJX9zf4lT3x2ybXh/ETd9YYRt5gZxgaIt1gGkV+3KUsfOXaHR7TvbqNvNDGxi3E0oBRqregdKHuwZU/S578pFfeAlx5APMMddoi9rcpzuzhXIMbv0YDtDY//dZnFvXQ+zuI2QSZTVGjA2y3jwv9EKd7+gBehDdnMYvGawjsmwUWy1712gnbbRBfpu38zmTRwH6hGNeKwnjMdCB94hWw3JbDbi4IpCLV3lF20UBuHHNjGZuSkRwzxmeYzB6Dg7we8aD5TX747J/l+VGbbtjisTLCLhWqDucdXhv3uTnXBBJyA4va0Q68a3A3sBxXimltSZRXa2ucF5S3CGZlxOmVQ98CKGLqpROvEI7ZIuXBrI/EsVoH1GWI0IbpUR+pLHGWIJTxpJagZkv4HvGijChkyNbwgPWzD0g2RojAYBYxzgqK2us2RNIyWV5HYyXWedujD+K9jfctwWrV51b+OUDQiS/zk/n/e2KDIpanEQbrhCrF2G9UiO/GV1jRF9jJv8LrzS/yVPw9TMWYQiwoxIIXFp97h5MsgLEVIJCyzUbyNKWbU9uMWXEdrVZIghUm+asIEeOWNiEAz7R+iHuZJtUdlsAvsjyhdZzTnbXo1fcJPhHjnvmLtN7Gcvr6CHWPPBng4gQ12CfpLBhEBU/1UwLx3/Oavc8bi5+gFV3gD57Zp59kbAwP6W7toc4aaLUJr+fMipgb84Bfa376m97nQK9xc1GS6iXDR/vEWdcBx0cDyipkMBgTr0yRj7Rxg1VoavTIIwDEyrPfcEyx8XH0jf+DpvgR4qbm4SRH3rhOdOtveypcXkOvRXP+ZWycYtIhuvQtB3d3ihq9ih0LRLKPXGuBlASDhtUkozBdprW/z9vyDRLRJc/vcDr9FJftY8QotPSyg6b2iU0JryTVCzwf/yHVdNFIJrWEBua1ozAemlUaPLHEGnJKRjzguLz9ropnf+XGTzGILqKJ+MHqaa7N2igBR6XiuITDyjwEtBBJP7jKjSA3ikUNuTE0zitWCQS1gLsLxVoUY4wmiQtOdSc8mPa4N+tR1AG1VShhUcLjgI+mPdKooG70CZ41DCtqo1lvzUmjgsosnxvVMBiOiFam2DLAzhOqSZv5rM2kSJjU4bL/2wCawihGlcZ8MOR6z+N9SrAKrRKKagetBgTSe2WB14ldDS+zZc4RoLmtvFDzw9aAVkOG8aOsu7OUruBq9F28lH2Wl8uf55nwD3JP3iISbQLVpx1uMKvun1Akq2YXKTuk4SZH5Q2qZpcz7e+kk24SiIjCzem1t6hchnE1tc0IVZs5U27M+8ybhDdnMWuRIdGGC+0ZlxtFmJSYK8+S/DbJFWAxfQWdHyOyBa7xGNf1zpQnqoiOTnhObPLXb/wLAHb+5I9gGk1/84BwbQJawXSBqQcArIS/s35Z3RzwK80/pebP87F+zHpc0ApLpov2SbUUxSVBf44bbGH6q8jpCDk6IMjmlMnn4Mz3vuOYbu+LNL9+THHoiPozqskWQlrKWUpThicQpvSZPdTdm8i9OboS8PhpXCtFrkXY3Rqbh4jSwaxGhIbqaI1e4n3bJrXlZa6zv/gqYNBqyLPiCeJALrVP33K6cHjgvhSemvr44Jh2WJLVITvzDqoI0UL6CrNxJ4kkM4b74pADcYfKzN81uWo1oG4OODATnKv4kcXnuJx+D0+rcwTCUVifpFtS0VuSBmLlK+j8bTY1E1NRWU0sPTGmsoKb85gzxyucW91npTshCUte2t3i1rRPJ6jZ6kzQynBrvMJhEdMNajZaC/ImIFYN7bCkaDTxstfaWRkzP+6hdUNrOEEGDbbW2FqTT9vUjX+8J1VIrAyDsKQbVOwWCeNKnkgYfhDvXbxPCdbQGD8ECLW3kQlFi35wlpqCTXOGoUxonGNg15gtm0PD1rN8yD3DzGU4LBbLVB4vh2X3eM1+gbZco3IZVbPLqNkl0GvL9/Tthqo5pDKLk4fpoa3HqfSTOCyF81VWYaYn6IJ5eIYNtc71xZS5nHBQX+cPx99DYXo8cf4WnSe2kef+l9/2imuzQKgYpzz8CQvJypStUw+Iw4rTsw4bgxH2V3+B/MN/hK3vfpHmfgu1miESARNHvZtia00vyUm0pWrefbD1bvHF+qe42vwgAGUTcJS1CWVDOypZzFK605R4OkZqjczmMJsh8oz4pV9l0b9M2r5ycqxo+0VG26e4e+scxkoC3SClw1pBrzvFGknUXeBmDlHPKW6uUk3b9Nbu4c5fhE4Hdkc005Ry3EEoQ9SfkR31eGHvFPcyy6HJuFP8Gg8dWiPtyQ0t7THOD0MKr98aKc+/XwlrhumcVlTiZh2GUbHUdQ0orMJYKKyjtj7LTjhklF87aYMEeu0dmgWB6tCY8dtcZh336pc4YzdpcCRC01GalUgyCL004MPIjTwxGdQIamcojcE4zSDU5EawPetSW0U/zoiDmnZQMapCqjLi8rAiKyNuzVvcXShiFXC6CImVZ4eFqsWi0fSDmtXemKSVIZVBaYMMa+ppC1NEnlRiPSMskIbVuKClGlbTOYeLNhJYibzIzQfx3sb71iKwtmAjfY55c0CbIYELKZkTEBMR0DhHICVt02JDXmIqbvKt4mMoKRBGcCCPmHFEbXMcFil8H0+iCJbIAeBtD4ujaka0wrMniVOrIcZMcDTsZl4QOQk3CWSLQCYnD1tR7fB5fnRphud7xD8jfoHz5e9n7Z9/Etn/4W96vYFKCdJL8MglstaAxP48SbwPwqKjin42JukscHGLtP8M+e/7o+jjHQyg93fgzi44gWk0Qji+Y2uH5vbR7/h+N80xhfGg+rLRTKuQWClCbQjjEt0qoAR57w7MClwGrpYIlZO0P0vxsb9IHG2w2P8PtK7dRIcX0NqQZRH5sq/XTTIGm4dEKxOaLKbcGWKKkOyo5z2+dkC1vOi27Dp4AMUs9ZjXacqt7fN8+SjhVXuHTM3eYZ29FlxGL0ss5/x2/KFvWyB9XxNg3nim0jpTtDL04gKtLJGKMS7GOsWsFjgE/VDwyfgJNuJH+Z/vfpVIPE4oEg7q6zhnyau7JHqAdc3b5gCKqplwO9zhnDnDSqBJg4dOGFBbz8xyS7H0WWMonCESy96vq5nbhthIskZyPw+Z1JqObtMNK8ZVyHGpGUYePz2tYgojmdceVxtJRaq953FtveXLcanp7J6mKCPSJPeIA6CctpmPu0RxibF+bqCVpRtWtMPS03iVIZSWWMoPPGXfh3j/EqxbcJC9xGrrCdquSymWwhQYxmJK4Po4Cy0Rkrs2H06+H+scw1ATy5g3zR4H+Ssn8CSthmgZ0WednAwpvl5hSpGEm3T1JlpGzIptNpOnMK5mbvaZl3dxrngHlx981XyUPU83vuIr3OXPZ8Wb/L27f+t3de2tzU+TPQvxG58nabZRSYVQhuDRCvexfwTgp/HLmVy+89PERz+Jaue0hhPCWw2/dbB14mjwOwmHf2DbYUVeBxyVEf2g5kyvJO3NkGkBGbiJxUxjhLLYIkTGFepon+Br/zflyilaN71gePvifc4JRzFLkbohTErS87uoJ1PYHVM+f5b9m2c5OF5hUcZ04hwhHd39A4LBFJkIqkmbxaxNUYYUZcS/v32eX8lvcmvxCziaExgfgKEmN4Z4SSZRy6QaSO+QOogscmkDI3EMOlO6/Sn9C/cAuP/yo7xw+xEEXWKl6GjH4/0pz5y7xY3d0/y5/idPxLn35Sn21QO2q7toEXE5+AQ3xZeX52IYJJdZM+ucT2Iuti2xMkxrhRLuRJVtWnvng2ObMxcLNlmhozR1Y9kXx9i6Rz9MyBuvc3Ev0ygREUiPie0GgmtHaxyVETdmLB2LYSNpONvKmNYhN+cxo1KwEsGbsw6hMlyMC+I0Iz/qMx93WSxaRHGJNYrRrMu88sWHxFEZfWJrflxp7Acorfc83leYlnUL2gxJXMREHp0IUs7lBGU1HdciQNIm8d5aSuJwbCaC31N8hAfR47zEbzLJXyNQKZFs88C+ybT09ttaDU96vV6lapuO3mRTPspH4m9jZgpKUZKoLv30LIGL0GgqUeEwPKceY9IYiuQjvCi+wrTcgeX3/Nn27/3PunY5eIrq7DFy/SzoEKsixCM/8K5VRHLme7FbzyNnN5GjipWVY6L9U/yh5Pfxr36HCRbgW1YqppVnhVVGYgNQwtJUAWaWgC0QgUAEBiEtMqpBOi/aMjpAA67VRgwzVJTR6W3TlcDpFczp85jWBdRrX6W+1ybqz1hTltm8TWMUo0VK97iHlAY16pKsTJmNehRlyP3RkBeOVvn5wwV3qi8Rh6cp6t2T5AqwW7zEY+ElMmPRUhEJWIkcgXC0A8MTg2PSsOTerEc/ydh85C6dT08pnvkuRFNy4af/PcXPRIyrCEe0rHwNWjfeZj00tJSkdpJR2eWwbGPbloFdo+NaRKqLb2oJhpzhtG7TDbz+alsb+kHDMC5oByXbsx6vTWO284pddZ/alTQ09JseNQ0PuI6Vj6BEwkbSUBjJcaW4nzdLDzHBfqFR4w6FcRTGEivFWuTYTAqSoKGyis2kphMohmHNZmvBueEh3d6UMkuYTLokcUm7vfTAc14H4biIT3QwYlVjnCSSvg3zQQ/2vY/3ncl1c/GzTFrP0nObaGFpXEnupiDBWUvLJQRoJF6I2zo/5FiPBZKYVv3tyPRT/Fz2o+TVHQSaXvIhKjunaiaot7ULwHGYv8bl6CqJVASuhSFhbhMM9kRBaxhqTiWOTmDJG19d9OtvYxLWHIkZp0WfZ/qKw7/w91n9Z3/zd3XdcbQBj/zA7/j18lN/i6b9DwiLrxHerHhkcMT/9ZUrfKalT6rTbxZ/4/aP8/fOfT+h8rYjpVHMyoSjvTUvZacNyXBMfOYI0QNMiZsLKBz21BmKRz4BrqH1ws/DeIEYxtDrU527QrP1HADBL/4q9XSDaP2Y6OKYwf11pvdbnqChDSpsmI+7ZNM22aLF/dGQ/Tzlfq75Yv4vAcfT4XeTBznX8l8+IZ40zTH74ZiWSTAuIVJ+TbQDQy9oGLQWnFrfJ9gzRLpmcdgn/NKcOPoNaBrynaHn6ocVFniQR7w26eFuXWK/SFACBpEX0g5lgBSSjxUfYmQqpBCMs4dWP441O6Re4hS08L5Xm0nBejrjwtY9Vg9WGURrFKbH0aLHq/lPcd9V9JMnWdR7NGbGTN3nT6z+1+RGMqsln5n+FFf0J0lcSICmrSIiYNFGAAAgAElEQVQGMQxCwXGlMM6RGcHteQspvDh9IPwXTCAt7bAiDCpMoxmNBmwfD+lGJa2wpJvOvUCR8utkv4g4LkP6YU1l36JvSfFBCftex/ueYAGOsucZiZjv7/w5/kPzGwDk+CRrraXtUjQBkfRT2o72cJtEC7QMOK4ano3/OC/Xv0zV7FGaKZHqkpnbgB9gHZbXqJsDlEx4IHc5oy8SKm83EhhJ7SxtpdmIJVstw+mk9C6xSqOlItWGxioys8KikShhOXywzur7eJ/0s3+FKvwnrBy8yuoTN1Gff5G9/+4ip/75/jsYcP+xqJsDDkpNS9slH75B4iirkIPddbrdGcnKFDEQ0Iq9fsJmG9fuYrpD1OwBspxBnmHHAjmMadbP0Jz6KGn7Covjr4CEepEgJzVmbmhqzbTwbqVFGTI+GLI3WkEKR6AaplXMrXmLe5n3hNLKoyQMDVqlJ9flaLjjXmGgzmLMGhdVj1B5nd7SSu6MPZnEWMmsSCh3znB0tEL/+ph80WI865KVEZvtKY+EJfMy5it7m3z5qE9uvNPqMGqorFxKDPqB2qiGnbch8LvxFQIk67EnNNxeBF5fQIWkizby/mnWByMeUwYtLFuTNf7OdoVWA7SMsLbCuYK6Kfj7938S5yxVs0sveZy+a7EWRoRScKFtudTOyI3i9WnMUQn7heO49KQFJbyzre/HhjDtsahDQumTaGE0e+MWjROsRQWrrYz13jHnjWK/2GC38KSMh+lVCXeC7/0g3rv4/yXBgrdM+bfT/9PLFwI1GVYZhFREJiIiINWSR9oN59sLpnXA9jxhUgsaq6jrNh8LvocX9efJmxF55XtvjTnmweLzgMfX1mbMobmJDh+hE7C09VYYp2gpwUrk6ARLrKiVhNJytZfx6OoeSll2x31ePR6SGQ9xap7/B+hn/8r7dp/CJ/4i9Q94UoJ86i8zuP3nufiZ/+qEsPHN4pWJ5VJbcT6tOd2eEQU1o0UHJSxhUCOCBmqL2/P2KuJsSLN6GlEViDpDZlM4mGLzGBnHVKefBulFt0U4oLrXZ/vNi0jpaBrF3qxH1gR0w4JAN8zmKQ9mnuFVW8mtecqtmeIns/8HUKzFj5PYiKfjAYfOtwgeDpgm+avMxDZ/88oPsrOwdANDqhtayrBoNPcnfdphiVkSQbJqwM5oFSWsH3TpmlOrBwzP7lLOWoyLFq/fHXJcWYxTQERlJPNGsF84xrU34ryWeSlIIUK+RXyKTwxD2kHDfqExDgZhQz+svOHivMOkSKiMoh2WfNeZHT688ieZlBF7RcRW63H+9Mv/EiV7aJkQqTajZpeiGaMCL2Uol462tfv/2HvvKEuu+87vc++tXC92np7QkweDDCIQzEGkqJVEpZW5ola0LGm1VNyz9h6HDWdXx1rZ3rX32EerVTxWtuTVsURFUqQoLSVGgAABEHEwqWemc/frF+tVvtd/1JsGRhiAwJoAARrf/6anq29Vvarfu/d3f7/PV+CqkpP1lKFfwWkq54IKvp1ryEoYoBjkPquxiycNbTfDFoZhbrEWWwxyi6iwJ8jNEkdpSmMhjaHhlIxyxbCQr9O0XgF9zQLsVVWbNgLHmqfQKY4dEEkPqSVSuCz4CYv1PnMT24s8cvGUoIWFKgT7uZGxNWQnv0j+rHIsmGz0mIJBcgY7fA/aQM2GGtUucDGxyM5KSakEmZbU7LwKDpOecCHAUyW5FgyjkOzUe1/xm2bf8iPEy39AsfwHeL7FT+xb5B+fe3HH9soUCFDC0E88+onHuLRoOSmNcUCy00R5KUIahFWiAHSJcTxkFqPOnyE5N13lZ/s97K0nKcMtklaM/9BHWH36MF9aO1i1XgqDEoa6nZNpi8GoRjQBYvdzm1GuWB0rLsUJS+49nCs+iiN8CkrW4pzd8SO49uI1569NxJ+uuNwzY5jzEmb8MTU3oR/7GATtICLOHZLcJsqdPWq/o0pqjqTXb+J6KWeXD/NQp835KEFQtbmeGxrMJEM5MAmxSHk0+SOMyVCySds/zpLncqo5pG5nhFaNbmbhKY0jS2xZAWd24iolUnErNIuNLodUyQ2TOtQr33Mb/9d99/LlnuKppEcrXGQ9f5zc6KrTy1TWNN3UYdqtnAkO1XLGhU1aKvq5TVZW9tvdTDIqqqCca4UB2qli2i0r+puqaoR7mU3Unaq6vQq11/HWtAvqVsly5LxuyvUK6GseYCsZskkNa2IGICCXGZcSm6cG4d6Lm2lJqSsKUCgqD63pvE2NGp4Vcjb/q+cdYSMpaNmKBb8yiGs5mriQjEuxtyOcaIk2Nsu6yZVRY2/ccaGo2wVTrR4m68Kz6P6vmKSF9zd/TPpUgx/+nt/nH//rF3fYA8XHOZx+J4u+ZJg7exsew9whyR2Guy2ENNhhjDvbAyFRo1415MVz6DWNKRVCJeA4lPV5dOMQYrxJ/td9nrh4F0mp9r6c4sIiLRWuKrFlnVyrya65QycV7KQageA4BwiCD7Bj1thQa3wpeQS4Hi9C0XIUdStjPhxx7MAVykJBZ4Y0t5md6ZDEHhe3FtiZpCYqWlVF2hrnNpe60zyy2+L/2P4kLesgvgnps82o3KY0KQ17ke3xlxDCxZgE117klP02Zk2DRd/QclICJ+O4KrgyaqAnTshq4to6Xx8ghWGYeBSlJMkdpv0+SpWYCc/iXYeWaTn7YavFUwn41t3ISRvt1ZpeT2nmg4h9jR6um2JbBdE4YJy5OKqgE9VYHjbZTBw6qQQJwxy2EkEntZCi2pIVVPbdg1Sxm0mSiQ2eKysTxIaTEab26/H1FdCrJMBWyottYulj2z4dfYlEjnA6p9iI60w5BiVhPDEqdCQ0HYHBBVySMuCQ90G+LL7MTvwkgTNHWgypO/vI9ZgHeIAb0tuQwiO0qtIfgO2kWoLVbRtbgiMVubZJy8qGxleCW9spN89sUZYK5xd+mfiD78E//F2v6L0ReYTpGoarczz42M3MhBfYiR78isel+Rpnkj7TcZNpN6PlpESFjTGC3XGI323hhWPc1hDh54CP3FrHXO4xvliRwpz2EOuUZnzv3yWceyfaFBTrXyLZbbAdh2RaMiokQliTJa8hLixWRnX6ucUgV6zHgpU4ZUzGQA7RaGbNNOfKK88plXu2QvcwR2oa3yoYZS7DYY16fUTNH2Orqh7XcTJCJwWq8VpOZa2jhGY39bg08vmt7gWGyVmGnN3724vh26p7ZEY0/RtwZMAxfZoL8gwNHbLgOSihyUqFqyWOVdJ0MjItqdsZvpVX+VGpSTKHKHeQwhA4GUnqsjloMs4d5sbBXltrzRLMiBo7puLdOkpQs6DllDTsnFP7V9h3w3mc2T6qmaOHiny3zmh9lvbOFGZNAA1saVMaCC3JMBdMTGpJSkOhBQaFElXO1kx87hxVpRqyUjHr5q83GrwCelUFWIA4u4xBk+Y74MGj8iFWk0VOZwdo2RINRIVG2ZLAgoZdpe1tIdjMUupimm00o+QihoJEhdSsWRQ2fTFkM1XUCousrFoFu1lBVyd8Kf4L3uW8H1sIEq25JNap6Tq5yGk5s9w5r+kP6zzxl2/iRj5J9KNHCVu3v2L3xRrsYHKJsgta/pjfuWmJb7z/KwdYgAfi36YQH8RTbQ4GitIIPFXSdCvYteOnlKlNsVvDdqvZa3xxnuHGDPbVpgRSVPM0MDE+DGcIDtxP201YHXuMiqrao26Vk515TS+z2UqqDqao0KzJbSSSlfIxhslZvnLBmeBG+WZGuSAqLLqJRz+q4XsJgR9jqRJdSjw/wbNzfKtgI3Goa4mjSuLcYpTbrMWSrfza0QL3MIkZUOgETzWpyzl2i2Well/GF01ScjJdlTj1MpdxaVG3M6xJfhegNJK8VKQji07isxp7E68rzXZUYyWqVchEVTEGeplNXFZ4RBcbC0FoVct6JQyeKihLiRUmqKM21KeR65vYDLE6LeLERQk9YQpUOW1PGgIlSbWgaZdsJharY4OTCdqT9mpfVUF3XAi6afXKJ6V8fQb7CuhVF2CBve6pflzRqTNvRCpiluIlbCEpjcaRLnVb0LCv5lIFtlDUTINDwZvZLZYZJGeI0mWkkLSsg2xxhYHoMl3MsVFYWChiUrQwnLLfxl/nH2O/fQsDsc1WdP/e+bjm+7hldwbfKogLi+zjb+euhZ+l/P5fQEn3utfw1VY+vYS38CjqXFWW9NHlF5+mmApu46ni08S9O7l5uJ/9gWDRL5gPJIOohr2ygG3ntOY7SDcj3W7RXVlgOKwR+HHFjS07eOG/Izl1Nzpoo9IB6gaP4wtrLI/qjCdOCQ07x1MFoZ2TlHWSUtDP4Fyxy7quiGVTwW3MhHfiifpe6/L1dDT8Jk44dTxV0aCU1KwOWixM7xDUxjCC3V4LP0mYbnU5CVyOlthObWzpM8htnhrYnI8S6tbCNTPlcbrMeMIJHlxn7KF/I2R3UvZrREVAw9a40seSBlcaPFVtuAlhGGQOq7FDpgWetNgch2ynDuuxxYJXENoVKvCpgUUnLUhNiUTiyWdeP1saak5Ga6qL9DLoZ9Adk1yYIh8GDDstktSl7lWtL50koJ9VKR8lDI56JvCujhXbiUYJSaAmrskFbCaanSLhRBCQlGavrfd1vXx6VQbYv61BcoYBZ5jzP8QZcZZD5gTDwsbL1QSCIvAVhEqRFwFosJRFo7aP3XyZUXqFYXJ1aSgIwu9gQMaQDlPso6RgLIY07EWGdK4JrgBr8hKP9m5hf5CTlJLxxiL7P3ELM/f8Jpz+L1+RIKvDOZidwV/o4F48yKEw4WDt3VwZPX/euZJikK5QlB3OZCt0wjtZHBznbWaGlhMQ5xbbUZ2jsxvMeGvkvRrDjRn6/QbGSNLUpdyZIo9d6uMOwYWPIeY9zHTFfNh/6gJ3DJo8uj1PqiWhnbOv3q8AM5nLrFelCFaogqvnHMATDaRQFSbweSX4Z4fm2YxLHGk4EI44ubiCH47Z9+bHkL6m+8WjbHRmGPQC9k9vI6jYBE/0PbpZwCCHtbigwHCruZUv+iOifPOadurnUz9+gqe8nDK/m2RQp+1YgMRV0HYMC16Vy1fC0MstlIAFr8BT5eTL3uCrqiki15Lt1GY7LRnpAmuSKdXGEBUQKAitgmPz64RzXYpBwHhljqRXYzwKMUaQZQ6em9JoDJGqZGVtkcu9NsPCJisVniqxhEEjqnKzTFfVB1owyg3rWcKG3GLDPM1nO9VsXgj1Yh+/1/WfqddEgL2qL8a/RegeY2TtIywdSEEJhaeqWaynBHVjI8qQtgnJKAmtJgNrPw1mmNczPCUfZcsso4TN9vhhTnkfoiN6dIsrpEWPUl/LW236N3KHuAlbwk5is5EIQsvijvV9zPzBZ9Hf8WvoGz9EFq8gd8+gFt9RcVS/yrLqJ0iP3YG7+XFmL26xb2uBpz8bE9z2lRoPSoryGYbBTvQgfq3Jo4MaBp/Q8ljwCmbD4R5DYHNzjry0yEuFk9m4Tk6eW+S5jbRLPLYQzRwT1gnv2uTOxmcxn3wrD24t7DFOo9RjN3MYF1Up0lWniaKMUY5NQ7eJef5a3tA9ygOdkHct9Ci1oOWPmVtapX76Cuau05jxiODSLtOrfa7szPHU2gF6qcda7LCTVPn6XIM2hkBUVtW38kY+o3/vmnFsa5YF7xaG5Rb9+Cl89wA3ybcR4vCkfBw0dHXCOLEIpMWcZ+2VVWkgVAVNW2GMhZogAXMtmfMTlHQptGQzdhlkkkTnSCCQFr5S1G1B3Yamozna7DE1t0Me+UQ7LZIoIM8ctBZIWTVtTC9s0zp1CYzAcTJYhu2oziBzJghCh24qiQpNoks2EkOiCwbE9GSX5fgz1zybz2Y/vK6XR6+pAAsQpecZ2Uu0aOAZi0Fe5ZcKA7YUNGxFaMkJhQmaqUNfT+EJCwQs6VMkIgEDqTfic9kfXhOAAKSsM+Wf5A5zJ3Ouzf7AMC4EO6lhmJecK3OmLy0x+1CHpYNfRI+HBLvbkGfoK4/BW/7ZV/26XWeaaO5W9IllZoJLvO8fhWSzp/mrN83yrs//8Uv6W1dGf0Ut/E6eGEwx77j0M5u2M0tWWLRrIwZxgJkUoStZ5RtdN6163Itq99p4AenSrVhzazjyIRqfG9NJLTzpIIcNNhKf5VEFJwltaKXzbFFRsjIz5vHxXyHF9XGPUoT85Oz7uLXVZy4cUmjFXHuX8NAmom0hzp6hXLUR0qM11aMzaPJIZ5ozA5vdVGMwNJTEVlWuMdUaWwgalouOryWStd0jSCQzcomDwWlc43JT0GDBN9yY30kvM+ykxcSsUFG3oe2UNOyiatt1MmpOBqM6halyxeNCYUuLuJAMiwoMXhooTVVBsT+wOBBUM87cCKacgoZXWdSkowAhKivuslBobVEUCs9PCOd2UYcMZjunLCyySRlYlNtsJA6DXNJJKyzjwCSMxIiR6tMrrjCMztLwTiGFTcIKoXuMIt98iU/h63qpes0FWIDN5AnuCW5gUFQzNyGgbk040KIKtM7E1dNXCnAmcGTJjKyT6hrbRcKCPEHuLTFgi0KnTMmDxAyYN4do6IBjdZv9QYktDFuJwlMV2MPTin+z/lHesXg7tU8fp3H5CiUg3Zz0H7ybF6bE/ucrrJ2CN/63QPXBWcDbPgsHGoMXzGVeT09GH+Fk/UfZyXOGheTLvZC6XdlejzKX0ggCO0cWFp6dETaHBO0BZWYzPrtAGF5ETc0jRz30RokQmoNBZTCYThxc572Cml3SSW3ag6pjK0qfMZ28njuDlHW+p/khFryc2TCiXRtSCyMWbz+DOunA9oj43Ax55GMHKeNRwEq/xfmhzco4JzEldWVTGoMUAiUqZHpqNBv5c3GPmR4TqDYSSSEKDoopbmnlvP3gMpZVstFr8fmtObaSyrHVU4aklERC4agSYwS+ndN0MrYSj2ji2HrVmrs0hnGhybRmRMpxt8Ht7QRflWwkLtkkCK/227jrGVJqbKsgrEWE9RHjUUiauiirINlt0PvjfezszHC5M8PjvRbdrKKFxUW1ihsVmr5O6MgdJJJ+sUpWVvdZCMUoW6fp38gbxVt5oLi+eebXWkKIEBgbY17zWeLXZIDNig0eKi9yr3uES0nMz919md96/NRevknDHqrPYBBCUE54oNOeqCjzkQtl1W65jwUUEq0NCdMA2ELu0Yam3YxUu2wmVc7qnLiCEJKdqMaTT53k8DDEsgqENLT6V2D63lfsXuRlxMN//wozv/TSj/2T6Ld5k/vdJAZybVXke6VJCotMS6zJ7HWj38KyCg7UxkSdFnluk0c+Lb6AiQzJ+gyBH3Pb/HrVDhsHWLKBpOqb72WNF3U+Qni8wf12FjxYqg+Zb+0yt7hJY2kde98IVEVc619ZIE1c/DDm6ZWDfLnXYD0uGZqUlJy8LIhKC09a5EZTGk0gLR6K/+A5Y2qTU5JTINlljV3W+W7nBo6cOk/jxkssnd3P0Uv7eWrlICtRjVxLdrOq7TSbMFeJISkVw1zRzyS9XBDlhs0spcAwEBGJGNOkxQ1NTdtJWR0HdFJFpgW5UTzdr5budTfFkiXH6yOUU1CWFlJqRoM6l1f3c7E3xUrk088V5QSXCFV51qjURGVOPmHqnh//BcbkiEl6JtdjTrnv5C5vgRnP8OjOqy9+CSFazWbQ/d3f+0m4Slp6Des1GWChgsZcmEyA3vw3h/hv5k+iEVyIMgwGWygcKfGkpKYEuaw+q2FeYeAAmtJBiSqXlmvN2BRsqjUUNrtGci7OeVN+kree7vCZrYM8kK1wJvojBBaHau/kz9fa3NIKSXKb0E3ZGtX59jN/9ZKgLv9fZauQ5l3L/Hd/+mP829Wff0nHaj3kUfM5DsqbKU21K11MGgayUrETV5CRXm4D0GgMicc+aeYSj33k/QV2GJN0G0zt22bm0DpZ5LN8/jB1u2oljfMqZ3lbrc55eefz1u4K4fBttR/AkQLfMoR2RrvdI5jpYk2P4NAcSImJJd1ui+XteUaZw8PdBueGhn6ZMxAjBrKLbVwkEt8EBMZHY3CMou4uPQf3OEpXMOi9TVBLtVHyJL3NaeonrlC/a5XaiVXmL17i4mM3sDNscL7XZjny6OeK3LhEReVqqw2MclhPcoYmZV1tUJBSmpzMjFk3T/EbN82zsjPHsLDpZhauNBQGhoXkqX6Tpl1wtNGjKCxUoSoamTKMY59LvSkujgJsYTgYZLScjFRLuqnD2JdsJorNWNIyDvOmRs3/ThIxZsguP3/yID/w1GO8t7nAyXpViSB3XtLj8oroX/7Ud3WjKOV/+td/yDe/79+I1/os9jUbYJ+tOLvMz1z5BZZq7yGQdXztYxuLmnbxpMRTAoeqFrOXlXhKYkw1s021JjElMRmX5Vm2oi9dk/y/zKfIH/+HbOcJO+IynnOAGec4TT3Nalwwym3G5QxTTk5pBMWBo9iv9A1YmOJnfvqX+bc/+NIPTcshSlZs0P6kR32fMLhS00ldttPq/w6FNnlmY1lFtaudO/Q3Z6hP9VBWtVQ2hULn1bfXMHcwpmKf5lowyA2zHGKH5wZYKULe6H03jqyg2EoYRpnDaFijZWnErAtaY5a3GDx5hN6oTlpYbCQ+nVTQzTMuqUuMdIc471Kz5oiKDk1rkULMYBmLVcY0rf1EcgNjir30hDbRJLgKpAhouIcwRnBxfT/ic4b9dz+OcHOCI5ssDmoUF5ZwBk1adklpICoUu6kgKav67GFZsMEu6+IcRZFgSY9x0aEoI4qyy88+8I38rz/0e5z9/W+jMFUdQ64FUSEmgVrSdnyiSfWAskocN6PTbVMaQcueOBRYOdoIRGlRtwumXY2nHDxpYUlBYBnuoU2mpzgYzDLICn7pxG20vXUW2h26wwbW5VdX7BJCtG677RCfv/9/5Ec//H/yz/7Fd2he47PYr4sAe1WXRp/EUtPMejfgihqxbqHzOq5yCC1BVMCoLBiVzxxztbNoTZ9hMD53TXAVWByovZ21PEIiOW3uwFICpSUKwVgXPFUu84crj/Ie99vYLEf8zJstLr94Z5evisrFJc78+5v4Rws38bMb/+ElHZvma+ROxiA3BFZVy6qES2iVXBjZXI5KZj1VBcvUZWa+KnFKoqCyK3Fz7PqY4ZU5RoM66zuzrA6aRIW1V5dZaEFSGqSR1z2H48G7eVsrxFNVfakrDVHusLIzR/3SEHfxcYSlKDZrpFGAP2lPXR2HrMcFHTHk0uiTe3/var1rWvTIvMM0xBzW5FGvuweRQmEJ95pyvDf6H+JNrTr//Fs/zkOPDBlnDo8vH6HbbdFsDAhqY7qdNsPEp5M6DHKFJQ2phl5miMuSsS7oiTFdscUgufwc406AX9z6D3z4i9/A6thlJxV7EPHQMkhRMQk6qcf5zX3M1QeE/hg9qLPcnSEqLDw1aeRQJXFelWgJUUG7A6WZ80paTs6cP2Y6iAiclIWFTdzaGOXkWF6GtAsWe3XCx9LnnN/XUv/yp76ru29fC8ex+Kf//Nv5Bz/4K6/5WezXVYAFKMoOnfQ8LfcQQ7ZYFbCWHeLvhvsRSJRwWM8SBqKawaQioeTqZpmLkiFF2UXJJjP+aQ6UB1m0Q4rJZ2wJQWEMgyKnKwb0ylXSfI0/y38RITx8Z4GfWLif//3jD2Df9mOvyDXn7f2ceMt/4qdvfppf+blD14CrX9TxZOxmBZ6ySUrDViJxpGIjKXiEx7gruYVe5lYdVO0BVhgTJi7ZMMDyE5zpPs5ug8HqIpf7bXqZg5pwS/ta0s8FvSLlyfQT1x3/ZnWAea/geKPPuLDxrALfygHo7bZwHjlKI76CDKB9/ArTN51Hpw75x9/B/7bRIzZ9DtTeicJiOz+3F2CLskM3LgiDNiNTAd7TcoBB46nK86vhneJd9ru5Z1pzstHlzJOnaHhVG243DjjfmSMctEgKi53EZ3XsshpLepkm1VUZ1Dl5kYyYU9xAKhIyxlgqvG6ABfjJzy7xrhmDoGr7Lg0cCgumnJxBbpMbweVRnUHm4qmCfu6wMvawJ/AhJaoUim/nKKkZT2phbak5EKa03ISZcMhUq0djuke4UFXJZN06RgukXVA7torXGr+k5+Tl1LNnrwDHjy9w7Njca34W+3UXYAFKHRMVnb3d6rHToTD7OVwrqCUKiceF4iwZY3zRZFhusSRu4Wj4Dj6W/BFK+tSdfRzUx5m3AhZ8QTeD9SSrOskwXFRXiE3/WWBmsFWLBes0vcyw/C8sTvzJK3O97tK3Ie59gOyjgl84/i5+6vIGy6OPv+jjz0V/zttnfoSLUUrDsvmifowFfZAz+j5Kk6LcWwGqltR9HdRCDhq8nqAcBJQjnzK3yMvKPwwg05L1ccB2arGTGLZFDymsPdhMJcW7/B/AU4Ij9QE3H7lAmrgUpcJzq9nVYFjnyoUlDgLtt15EvGmOsjWL89B9HHl8hZX7HgCqeuVCp88xhix1n63sadKiu2c3BJBQdQsOkjPM1N6DI0uS0mJj2KDtxQRuyqLdY5j6E8sdj43EYVjIygK81OzoiF3ZYTs/R5Jts24+S+AexhLuXjfi9fSZ+FcZ73wvd4Rt4qLiEVgTattG4tLLJKFlGJdVDXFUSqKiaov1lMaWGikMvpUTOilu5jDKXRwtabkJ+5pd9i2u47eHFIlDOXaRTo6wSkZb0wRFn6AxBufV8/o/e/Z6VV8Ps9hXzx3+KqrUfaL0mSL272u+n8NhwiCvLvcvi/v2NlukCGl4RxjIHg+abaacI2yMH2QkJK66FSkg06CEQApBZHKGYoxvApajq0FMsFT7Bt5knWRYaEJLoPX1l8Mvh6SwiE/cRXD0z7h9/2X+q+gUPzV6KX+h5M/jLzMjFvlC+nmSfIM182kAjoZ/h1mvYkAUhYVwCvAc9NJRAKwHnmTr8zdxfnmJrVEdieFIo4/AcLbfZpBXHN3jag7cd7NqzjAnj/BW/xBnosi/mYUAACAASURBVDFvnHa4uTXk1L5VZo+uIOwCndpkwwDl5kwXWwx22uhSkTw5hRufw17cwfQ1/X6T9wb/kL8Y//JeW/X1JjsvNKOXss5GUtK0LUrjE1oOSWlRz1waXlxZ7GhZEcMmrrGFNuRmUh+Mh6/aZLKPLiM81WSQfuUVxJfi32Va/DCBUjQneefKj0sRFYYFX05yvJJMQ6FB2yCE3INlx4WNEppx7tBNXZpOxnQ4YnZ2h8ahDZx9PcpegCklWa+Gzi2SsYcbjkELKF6cM8bLrb89e72qq7PYz3z6zHuB6y9/XuX6ugywz5bnHMCRsB5XtbC9XPAmcTeyfg9Xij6FKHGNQ64LenKXfrmKMQlKuAzFGHIYlw6BktSVxbjIMGg6VIDvwD3M2633EUo1oXQpXAWfvnCCuQ//NI0f9Mhu+158b//Lep3OoW/B3PU0JzoP8wE756n+j/F/9158VUE3v8RG8fA1szzXXuRe5wiHwwJXara2Z2heWCQoNlHRkyAE44vzLF8+yOV+m1RLptxkQraCGS9hWChatuDm9oD3vPVBhjttPvXYFE8NDHdOSeb9LnO1IZ6fYNXGWPOjyuJcUtmXpwb1REY6DEl2G5hSoVZToMnC/jW+/+gibx/9COux4tPDLSIxYrs896zW6OdX07+RtjpIv8xYjlyGhYWvLOzIYcop8a0Gkmrzb1TIvXrTcamRCNoioG0CGqZO1zvA2ehjWMJ9VmpAcdWG/LkybNBlv56iMJOgCdTtqp57XMAwl8QTKnaqDYNc0HIkLcfFUSVZqehlDlFR5WHbbornZBUYfuwhd8MJarIkHdTobU/vja4TB/JXTYrg/f/F37v3mtnrVf34T34jv/Hrn/5+Xg+wr05N2UfYSQyBJahZmhnXEFrVTvd00WYjLsgxjE3OyFiM8x1sa5ZZ+zhOaZOSU+iSkbZwhUJjWBcXSMsBtwcf5ITdpuUIpl2DEppcV8u9can46/vvZv+ZHkeP/wb2h12su//Jy3adSrpEN70fv/gI81trfN/mPs4/8SG+GP/Wizq+coR4Jhi49iK7/zTmV34n53izh8CwPWowdWWBInFQTk7UabG6vo/1QRNPFRxp97FVQV5alBOk3+lmwcHWLnd84JPoe++g8cjDHLxUgWoWa1Uw3xw2mKoPULUYcXiOYvEwamcdRkMYjlBeRtlpkmuXIrOxnJxgX4fW8RXeNKyhzp5iynGBOT45Sl5UcBXCw5iSbnmFUNQweYPVvMTFpq5sPKlwVfWc+ErsUQsq+3DBlFN1+LWdAvCw5QLnRx8mKSFz7+ZLyRYdscF69PnnbWVumwaJKeikkuXIoW5r9MT+e5AbtrOUmBwbq6rnLgTDwkEJZ2LtrUh1xXnd51f4xCy3GA1rxGO/qkBwMmw/ZTyosdNrUWpJEEaEbGNewVXWV5DdaHho/dwvo3rdBV75wpyvlr6uA6zAImPMapagRx5tR+3VwEL1IKdGMzIpsahmXafdd7NAm0AoLFuQaU2iNbkpyY3GxuKIvpFQOATCmjBkK0xfzS7JSomShsO1IfsafUot2d2cwfuPFymmfhfv2AdftusNGzcR3dClftOv8iap+V+s2/nBx99zzQ778+vah/ujb7iHT/2ZxY1THRandnDdFCEMQWNEmVt01udY78ywGdVxVcG+Rp+FuS3cICYehQyHNUotCd2EIycuAKAef4TkbJvQTWhnLpYs2YzqPD2ocaAVVi98NMJ68IvET8ySDVsoJ6RIHGy/cl3QpUQqjbQLdG4RNofceeQc6zuz7AtChpcPsVocQwnrBS3OjUkYJGcQwqMbTLMjVkn1CCVsAtrM5gv4uUtTOpRW1cUnRNWZVbckxxsld89us9DaZRQHxLnD8aZF6KR044Cl3RmeHsxy0T/CffFvXvccHtSf4k75TsZlyUpkIYQkKsqq0oWUVbnMqNzClgGuqOFRIymnyYYBW0nF3m04glm3qr6wZck4c0l7VTxqhiMs5VF2JWVp0RsHZNpiqtck2JjGlC8pj/SyypgSY577RWTM860AXhv6ug6whgKFzZbcRmZzRIVFw1a4UjAuTfUwT4KrQeObgDla7PdtGnbVDRaXiqgQ5LrqaQeYUS6hVTmMikmZjRAQqKqtNrAKArvaBXetHKVKBmuz1H/uMdIf+23cE9/3sl2zrB9BHGrh7+4SuCk/OH2cf/WiAuy1qnkxgZE4Vs7U3A7hTA9nuo+OXaKNabLcJi0sPKug5qRMt7rMnlxGhQnBVhuu7MMYSS0ckY4CxmcXUH5GstPEUiWuVVBoRTqxeAm8GB07yNUxgyeWWH76KHlpEfpjZhe2aBzcZLw5RR57FKrEGfkgDVKV1FoDDjk5enU/vpqmaS2yET/8oq7TmIS16NPX/Kwnm/j+25Fa4kiPml3NYEtdcYenXcPhcMxCa5fZuR2mCkWv16Q3qrNvZptav/IlS8o6T6fPn+d8h/UebCnJtaZflKyZHi1TY0zKSa/BF7tXz0vQ8E5SqpxS5WR6miKrU1MWVqFI7WpmrY1ATTbAYJIzF4ZBVCPOHca5Q1TYXNhaQBtBkf1t94ivnbQpKPVzy8a0fm0Dab6uAyzAZvQFnNq72ZQ7dI2DndrYWJRoFJIAh2nh4ylJUmpajmLBrzB0IPcKwQE0VYPClCuZ86rfSUqBMTDIFU1bMuWm2LLyR8oKCyyQUlNqyWBjhvavPgL/88sXYH1vP7rRxJq5xFSzT90umQvveQ6C8YXk2ovkpUWrNqTWGFKb7+BMD5D1DGGXqN0G48THtSr77GZ9yPzxy9jfMofIUrwvbBAOarQWtrG8jKRXx5SKcuwS9etYVsFCa5eisMhLSWjlBH5Mttugf2E/588f5XKvTWkkvpVjjKBIHdbWF9BGEvpjbDfDbQ2xvAynNsaUikHi08/MCy7Lr6fQPbZXcdLyb6YXP8amPk+mDnKT3aTlGIa5wLeh5VTMhf31PvOLlf/beBSgtcRWJa6XEmQxoZ0TWpojdovHi8XrWOHAPt+im2mUknzDQsZvXnH5dPJbGJPxQPzs3zQkRX9vRj4d3IHFaXxTx5rs6UWFRT/1CJyMwIur1m1hKEsLS1buDqlWjAuL8aRRI89fPa+/MQVaJ8/5ub5O0H0t6dVzh19GDcoNUJDjEokuBk1cdjmgbuaA2se0K2g5hq3EYpgbOqnAkZUxYlUELpBltdGQG8O4qOhatrzahQPkULcsjjV7+HbGMPXoxQHz9T6Wk+M4GUVus3P+IAd+70cRH/iFl+16i5lFbOcSs0urfEPqALfxUyv9F1wyP1ue1eJvVg/wzcefxvFSMJJsp0W5apNFPtnYqzZTMLSbAxZvPIf1vcdQt/wIAOXUL9JSDyHvmCM7fCtTj3yW8kJOdGGR7u4Ujp1RbwyJxwGDOGA6HGGMYP3cEruDJuuDJqvjgNwIwKeberzdzfiJ++d4U7PBW+Z6eG5Ks1T4UwN0rrh85QAfuTzDg8UyB2pvfxGcXHCsBe6xv5matDnY+Ca2E812kfCol9OPn0B7Oco7ji1hyjWEluZ0s8+N+6+w/4Yq7THcmGGnO4UlS+pBhFePKEtFUlh0M8VuntJyDrF5nQD7+9Ffc5o7kUh+fmXA4/Hzw1eumnn+zOEP84WdCmITWIK2W1l6ZxPguRQGpTRFYZHkDqWWe3Y1gZXTzxzWYmdyb19F5aU6x5TPDbDm9QD76ldaDihkGykkm6MvANXuf03XsO3Kb95QBdOoLCkSScOWtJzqEXRVVaZVaklXazpZQaYV2kAyScxfZIPvWrK54cgF8tTh4vp+4gkXddBvUK+P0FoSj31W/p/TTL3rM4Szb31ZrjdfuIXyfYt4965x49mHOPDJZe546FZ+6MtHuRB97CsefwN3cVOrx2AcMp3ZpP2KD1ZklZdXmrgIoYlzh3k3xbulT3ryO/d2IvKj70V8YBH/0LfhAeXWJbL7dtlZXWAwDoAAx8nQk5XB+rBFWlRHrw2bnBvW+MIO3NCQbMQCsPiJ88t4Vg+rfzeeagLHCFcztBGcPniJz60e5G+SC1yIPoZrL9Lyb2aUrT5vsT+AocRC0LQUg8xgS8Gbp3y+xXkn8E66maKTMnGRNdzQ7POWNzzE1FvOweIc+f0RyYUD9OOAUebgWQXaVACYc8Maj/dzOmLIQX2cHfkkpb6Wf5vrmHV7g5KcjeTR657jXf73cdpv8rH0C/y92r1AwXv2FWRlVTrXcnJCq8BTBUoastJiZ9igKCVR7uCokiivzk0JQ6qrmtpOWtl6v1pkjH49B/taVZKtsJl3sVSdqeA2jplbsZAs2iHGQCeFhl0hDj1ZeUs1bJh2S5JSMsgFngLpCkalpFemjPOcmBQXm2V5jvXos0yFf4c4CpDS4Fo5O+OAYe6Qa8UikOc2WWGjVIn/1KfgZQqw4VWa1wHgJvBP/Ar3/vFf8pkTSyxef7/lGn0p/xiXR9+OowqGgzpOkBAu7GBKVZX9CMP27jRay8rhVQo8d37v+CA8BuGxvX+LcUQe+Wx32/Ti6p4UpcK2CjajOjuJxyhzaHsx6YRdYAv4ue0/JM3XWKq9h7utb2LacrlU9uikNf50pYWn4DPjNc489Bja3Lc33tXleMM9RC/OQEhCZwEpbAbJM+3QebHNirtBkc1TkzYtWxFamiknZ1xWsKBDoabtFDTtnMVGj/Yd52BuCrZ36F84ztr2HHFhM8hcuqlHrhWdxON3tjfJReWasTn+Itcr15qyl5gqp8lFTt+aepbTQqXbgw9yT71J29H89607aTljZvyqNtcYgaMKPDvHm+T7paj2CDaHTcpJW3KUO2wlHmZiqz7MKwvv0Cr3mkJeDTI6w5Txc39+nVnta0n/vwiwUEE96s5J7hb3MO9ZNJyK7dnLBOMJR1YJmHYltoQT9QxPlWwmDrupQk/+f8pRlKnDWBccspp8IvsY43iZqeA2fu3Jo9zeTtgfjsi1pJe5DHKLpFRIYUgmgOTAixG9XbQpkOLl/wicm36YYvzvmN33BL90/w/w4ad+7QV/vyi6nB+5tJyQ9qhGIxkQb7cJ5ncRQUIIOFdydqMQL0gw+xZfcLGZHbmV2vGPEz59jO2oTid12Uk8hDB0UptCC4ZFxVe1pGYjlvxl/olJoFSUFDxQfoJATJOUfR7eWUbKOrP+TZTkz+HKKtkkzddwVMhMcBOz5iA2DqlIWAxO8WT0EZRs4lhNdvQlEhURmDpL2T4uRzZZ6dF0CqbdatY37aaEdo4QhuTSHJ7eBsuQxh7jrDIi9FRBVNhcGtbxVMmT0UeoeyeoqTmuXwsrCEwdF5sKEa4RwqPuLnFS3M1QDjksW8y4msNhzFKjx1R9yDD2kcLg2RlJ7lDzx9TCCD+Msf2EMreYiwLyzGa7O8XZziwrY4dcV9DvpARfweFahNrW1zmvr5F0AcV1gmn5eorgNaGWfzOLHOdYzeJQWJGvci3QRiIm4UFSuSNIAb1cIXLF5UjRzTSOFDTs6vdCpdDG8NH4I3hWk8XwbRzUR+ikhoe7HpfHLo40E0JS1aUz5TroiWXyTr/F4GNN/If/a+ybDPG97ydYfN/Lev3piW/A/8ITfOPNX8Y5t7CX07ueDAX39Ubc3hYUWrG9NUuz2UcqTTIM6XebbPRbVbtma0B28Ga8FxjbOfKdlO/a5ujKk+iHBWtRyPLYYXUM22lBw7KYci0yXUcJaDqGuloAD4bJWXKTUJQRu9kKV/OGWg/JTUwopxFca5sjpYNtHUAbzU36VmwhiUyORjMWI4TwKHWfOOuTipCeeYymfyM9uYmTvIG7pnJCO2eU2xRG4E42iVwn48rjx5kfBvjzuwC0gxGOXbnBnt2ZZ5Db+BPIzTA5S+7Ezzm/az4XqvOaspYI1DRNZvG0Q9PMURpDNuki66cemir9MNfsMj29izECN4yxnJwis7H9FK81onl0lbxfw76cszlsIAi5EhmGRYErJW+aNZyc28BeyV/aQ/QySugccZ3Zqng9wL425Msm2mi6meGWVkFoFQxyG1daSKFIS0FhKuuZYaqJigq4fS7tc46H+fuNd9DNDLmGTGtyo7nNfi8hDk3pIGQF9x7kVcqhnORntTE0bItDWuFbOblWXBy0WPv0W7Gk5uBfdLntLZ/EvPnjlAv7KRszuKe+/6t+/WHrdszxaez7cv7jLe/k18+1+aPh82+0deQuS01BLw5o1wfoUrJ1ZR9rO7OsR3WSUnFyaofw4BZZ0H7BsZPxJbzdTaygstuuzAKhl5X8ZfK72KrO6eIddNIW2sAnso8SZxu49gxQVYI8o2eWtd34DGN75prgZak2S+49ABzU+5h3HXINUZ5XdvAixphnXuSrs9+rrba3H7yTaS/BliVbsYctq/HiwmZ1d5qamzI+43MgcXCcjGM3nEMIw87qAu1RTKElM35E07+RfvzECzAJDNtmGVfcgGscarpJjSY1E2IjSU1JXmquRB65dunlFqFVMu2mzLd2qc93kHa511qsS8lwqwLIe/UIIQzx2CcpLJJS0CsytuhxiGkOhWNmZl5lMFidvz6DfS1rPfocY/80tSTkZBKw4FUW01NuykxhsTL2iAqJqwTdTLOV5wxExKp4mt74MR7njcw6btVpM/mbDeFNnA+qDZLdPCNUNpd1h8D4rKrLjE2XbPcuTtQdPFUFgriw6JSSQgu2Eo/al27iUHQBf995nJtXiZdWX5bW2vG9H2Bu+ee5OfL5fgPtKz/Or3eujzd8OvoT/tXDP8SHljSNQZPASRlnLptRja3EY8rJaNWGqLkUdEmadbDt5nNSHmnWwX3sDzAPrRFvH0SpEk+V7KaCL4szaD0k1UMGTo9zhaYvO8TpCobiusFJySbaxIDEd6614gYoyi67ZoWWWCSjJCkN47Iko6AQVV00VIH4mPd2OqzscSl85xCdVLIV+0y7CY6qcp1T/phmELEb1dmOathxQLAVM39oDeXk6LwqeVJS41s5923PsiALjFd+xcqNeZqMSFHPehWHJBSirEhvSYtM+7hS4SmNEoYsc0iHIcH8LlaQEA8D0iggTVwGwzr5+gKlkawPmlyOQtZjQ4cRqzxNlzbflB5nbX2BNDv/lR6ZV0zCaMR1NrnE65tcrxUZ+vETXAxr/O7OPt7qH+ANUwkHwhFzwYhA1bgyDhjmNoUxdGSX1fKJvRckR+9ZyIzLgoySpnC4ZHbYZJlRsonWBXm885zlYOHfySC3UcInKiob643EYjsxE/7nDdyyuY+ml3D4vjWOvv/l4RaE7bso7rqJQ/mXCB8YkZZ3YMyP8xu71w+yF9VFPrV5ml62yP6g6ltPSotSV40XrVYfmgEyGaC3vkCWjRFlStE8QDj3zurah2dxeh2S7RbJMMR2qlzmelyyOvrM3lgXoo/R8E5xmNs5VHsnvXLtWQCXZySERd05co0Lwd9WNz5D7o6JVJdeWd3LkeqjjL1HGfvW4HuY8yS3tWf4udVDXMjuI85W+etojUDtA6BuFbS9hJNHLjJ9+iJbjx/jyQtHiQub7rCBuGJoTXURSuMHMVa/JC5sOqliyczjSIcoPMrF6C8wlPxtm/Dd8Zc5W1ugoVuUFKQiYSQGlCInMl3ScsC6cLlczhGMT6OERWjZdKI65bkjTHdahPUR/W6LURQySj1Wh03iwmKQ21yKbLYSw1oW87T+/GTMR3DUEf6H+w/SL15+u/kXLV0giufOVkX5eqPBa0pb0f0s+R/CVfDgrkdhBHOeTWjntJychm3hSgkGRs/qdHFQZFqTas0luVoBRaJrX3Alm+yvvZXMjNmK7ucN/vcyI2ocCGyUyCYoOsV6LOhlJefMJk9Ff8KfjAqYAJgK/Rsv6/Vbd/8TCuvfM80jvE0r2t4JvvXA9/KfNtusjjWf1w9Smpy6nONIeZArZcK59ZxjXoMDAbiyYpK2nJzhoM78coprfRaEhDgGz8UOzxC9oYZwZxH5iHJqFmf2KWamBxS9kANX/l/23jzarqu+8/zsfeZzh3ffPOpplmzL84TBBswQhphAqAAhExAIkDhrdXWlm1Cpla7qXl3pJJ3qrKzKCklIhYRVqRQBAgUkYbADxsZ4xpZlWfOs957ecN+707ln3rv/OFeyZD3ZsiyDqOirddfVO/eec/e5w+/89m9/f9/vGp5m9qwLUSvaw9PswbEmGHeuYbC0logOCV26WZ2yOUInW6CbLlBzNxCbq9eStS70CAzPQYpiNX0+2U2UHMcyh/mFvvcx4mr6rIxjXYcJPcSiPc5vT76TubBgEnTzwgkjSC1MJ0GnJmM3FBfbxkqhJZukFmHXp39iAafS5cTiMAc7Po2kMNhcxyCdvA/PfxcrYoHl9NDzsnJNI5+hJMr42ue43kWctxDIMxTAUmcjyr4SgE5qsXN5EKUHceem8MwMU2gWo0IkHaCRmgSZJMggzDVt0UXwXI/4vz54D1eYr6WdXULZocpglQBLdjnA/tjhsfC/8rahX+PepS6mKDNj24x5RcE/11AyJYNxP641SDfuAjm75S6m8g04WBwK//kU1cc0+inbk2gUlvTYkG9kUS5zR/XXqNmSqgU1O6edGSxGBvOhZl+yQks22R/84xnjen/tbu591Vd5wx89Szq6EW06qNpGDGfoDBrUy0Wy5Sexs4QRYyfXypzFhWFMQ/H0co3B4BbaqaaZZizRYdmoc7jzTZ7KJnh79i4AJnzJhCc4vDCK+/3rmAh3Y450yZsW5DHGSAs/+TzInphIs4l2cuSmQYxmk2sXn2Hrjjdy5Bzji9NZMmcLQkgkBrb2ca0Km/KNLBoNFs1jmDh41gBpvsx6/028zt1APc75dnoPQXwYyGmEO9nq3ci15QrPLBaBeI1zM61UMegUzIV6LBiyLH7Ou42qFXNlX5NG4hDnBlFPxHrf/o14R9YwPLKIaeZUKh28ckASOcShV3RMJVbv+yPItT7VCFCxbGQ8ABpWVjljQ1gM6xoKuF2+ln8Kz3SvrHlX48t+xj3NpB/jmRmNxOZA26GVghQOpihYMCXTxDcKK/AgE4S5JlYKR9tY0qMRFtrFUpgsiONk4tIJsCLPEKsE08sZ7I8p/u9jf8o/3PRe7p0tk2uYC61TVKNBR+BIj6uMu/hS92HqwXYWo900jGNnaYtm+QqN8Dky++ah2xhPxxl0BeNeYe9hCU2kCl3PhSThyehLZyy0ANzu/TLvmGqzec1R9AOHccb2FdG+v0w+uZbutvfg+2svyrlrnRGvvQnb9hj2H6d27DjVZzYh2YQlaxzvmgy7Fs8Gs6fswON0lv+R/ilDpZu4tXMznuGitKBvYYTR8CBmKUGEOdmyR37EQRyLkH6MMZiSHiuTdfrwKovgO+SZyV+9+yEm/9u5x3jydWve1RjCoiJG2CN3I5AIJO38BO1oHxV3Mx8YWsvhTtEMMmCtPdX2KoTF9vzb/M1rJvmLrxTZ8qHgHraVf4WlSOIYULU0Y65myE2Y8LpsmzqKUpJWUOZ4o58Toc+hxgCuUQip9JU6WGaG60VUhlZIjjvUj40hDUWt3GbQSdnbsgEIMk2mNQaCUHTPqUu7LDpUdYl746+c9ViQzvOBodezrdamaieFc4Eo7GVco9Aq7mSaXMGJsAjslgTQBJkiVjmxSPBEH43TjrsY7ybXlxDHVCvEKmpaQl1CVLILwL/YAAvwV/uGeftkwEzXJVOCVBcULUtqpBAc7OQMMkXidmhFe8jy+hn7C2EjsJDSxbMGKBsjNBLNgCPwjCKwVqzeNDgDWxock3PPC66Cn/A/StU0WYpSgsAnXuhn6dFJotDFL3UZueogNl8kvu5DOPYgLxel8lYobyUfejXh6Ba87fcykh1iS+iyErs8Xvf5gTp4KsidjqXgCb4hdlNXP4Mjy1wLZIGHo1qIbePYc3PotiJvuBj9KWrLJsxkP+GJQdxQI9IIrQRHj00Bq3cvnY6TWdfJd77ibi6m/7IPz55ms7iFHSsSS2oSpdDiuR+k1glRcpzNXzmO3SsnaDK+m32Ha/LXsNb1GPM0E16M0oJ2ahN0fTZs20tpYYCZZo0DHQffsJnyY4a8gFa3dOr4fVpgWhlHZidObauYGVXLoZ0pmnnCbrmdRHUIs+WzPwdnI2U5iFaqECSSZ/4cpSjxk957GHZzLKEIU5NWWui/Vi1FxSxEhqK8yFhbaeF9FuYapTX5SZsjbTDKNC3nBEF88LSFwUsneAmVnyODvXSoZBeCf9EB9u9bn0KKu3nXmjZ7W2XSvPiy5rrIDEwhQEN+1uqmgWdPMmpfiaNdJBJHu1SVj2kW8oWOhIqV0dfLOtqpiQaultPsP+04m0pvo2aajHmChcjiB8fW0ehUuOfoGr6x1OHOgQruI7fyvy59nepdv0+8YRv51B1Ft9TLhCEd/LE3E1hl/NlPI7cXrZRzaZfD4bktZ5QOeDq/j49X3shyt0S33kcpnSMbm0atuwrrxCGMKIQoJB8Yw7gavIU5AOJDNb7y8Kv51T2fuaAxn1zYylUT25jEOU0qtGoZjMVTHF9F6Pr0Wm0r2sMu34XoRkqmT59lYkvFYmyza2GcgYEV0sRmPvSJ8iLLtY2cgUobx45pByWi2EE2KyglmWtXWUkcol6Xm2PAUt5lUS5S7+44w0gTisDqGGUqchhfV1C9f4Iz9Vnf5P0C0yWJLVPamUWmJKqXBPiGwu6xCjIlaWcS15CEuaCdCtppz3FBGnjKYVEsYQiTMxfaDC4VCLV6iYDscoD9scYXmp+inX2cq6qCdlYUCYqOF40pBOsZwzFcZvwq9e6TAFTcDZSNEUqqTFWXqQgHUwgqlkHZEgzYiqqVY8viBxDmBocDk0aieUI/R9sZKd3E67x1PT8mzXwkOBGV2df2+Z1jBUf1sZnC1qTxpQ/w4b27ueL1j2LdcZjghvdQqm67OG+CykAI8lyyEDk8FP7Zi+4SJkf51pzPxsxZvQAAIABJREFUO6ZypJVDfxm16Z1FrbgX+5Ndn8Ha9zS0OqRxleYP1rM0O8pnj16c2t+UuJJNbplS76JmSc2w28e/GvsVfnfu2y8ovL3c3c6DPM0Vpbs50LGY9DIyLdjbKlE9uBHfTliMrULoxc7ItWClU6bPF0X3llS0Qp8otci1ZDmxOBYYp7qlGrJ5Tt2HfmsNQ2ocMzdQKEIZ0qaOet6FfNgxGXJ6Lrs99okhioYYW2okEPXofrkqxIlcqTFsgWtIWommmyssJK72Czubi/LOvwLIFWKVYPrjnsFeMpLmP0p8M/hLHm0U03ali14hpYuFA1dKHG2jT5tOdaJDnAgeYY79rHdL+IZByTQYcgutUM9UPS8vSZCZPf8keDapM9t94tRxfNFPM9GUTY0rNY1E873wKP/pxJm1OKXa/Oni5/jvu7aytHMDYv4EonOcJDtTPOSlIsmaxEkdGRbTV9eLuLq/gWNNvMieBe5PdzDX9TDMDF3pO2shTm24C1od8hMGWksWZ8b448evpy7Pni6/NAhGSrey1RxhxNVM+jmuodG6uFDtbJjYsnz2XuL5/Waa74aHOREqFmOzsIXJJLubfRxu1liMDOqxJlVFbtmOXaLULoJr5DHXrnKwVWMhcsl1UQvdF0TsjJc5ofZRcjZScs6eadwkrqSsPfqE15POzPBEH0JIXHsKKMSIBIIwl0S9W5BJwqz4ySogVoJESRQC29BULIVrgNVr5DClwJYSV5qUtMu02sJU+c4zzv+SgVag8lVuL17GEEK4QohHhRDbhRA7hRD/V2/7gBDiHiHEvt59/2n7/JYQYr8QYo8Q4hVro/wXn8FC0Rr6/fgLHJTX89Pla3uLXYJ6rOjmRbY1JKZZZvupWh4UWdBxfTMDpk2/LeizNEJoEnVyucygkxksxSY7wybHxe5TikpC2Egt0WhcQzDuJYy4gq8demxV6lGW1/m75l7esH8T1UcX8Ya/T+iPYteuP/WcoLOnqK+eJ9LoBLKxH3vmWZDgeiGWzM9bH2E2eADFldRefZh07Dbs5z1uWTWy627GTB9lZecQjx3ZgCGKJoYLhWNNsM28E0MZ5LIQ5JkudemkFu3UZG/b4kScYIgzXUYEJlOl1wCwnB45tRDWYpH5dAQ38iiZgiSHhcjEMywWopwR16Bqp5Stor1aa4FnJcSZhUgc2qnZ4zTDoajDXvE0zfgoVWeKklnUy09fwQf4Xv4w13ITjpB0NCwzy1LniTNGO2ZeSZAVugyLkUmmINNQMqGbF2wBrydM02/HDPldhNB0Eoe9zSrzoUmiBFnPsNPBJBTJGQ0Nl1wNdpVs9Twz2Bh4o9a6I4SwgO8JIb4O/Cvgn7XWvyeE+LfAvwU+KYS4Cng/sA2YAO4VQmzRr4B01+UMtgel2swGD/Cp+T9hKdL8/MYZDuRL5GgWjDmOJE8ghHtW8HtGPE47L6Z2CkiU4FhgcDQwSZXg2YbF95YD9uhHWO5ux7OnGSndyhb/7axVk9hSkOrCsvnGsVn+YP076POuwjbHzhrjkc69fGz3Csd3bUQ9uoC7555Tj4XRDNaR+1/SORtWDbIY2WmRHvFpLPeTK8m7/Hec9zE+efAvYXQQ88RR4n1/Q9A5s3NJRAH5ok19fpg9zTJ/vnRuzdPzRSZy7F6gyLWgaseM+l0qVkaSwx65j4XgiTP2ce0J1ufruVVewfsrb+PK0rsBiFWHGWOW2ShmMVI0U0UjyVmKC86z7F0rMyU50S1xuDFAPaiQ5ZKaEzLixqzEcDjqclDuYTncSZbXWe5uZ677GDkpUd44YyyJ6hCREqqcWKTUGGOodBOuPcW68lu53fsQA2qQSClmwpQngxV2h20W45SFSLEYQScT2FIx4MSsH6izbfM+brzpSbaOH2djpc2gk1M2wTMFlhAYQuJpm8F8hKHSTYDAkN7L/iwuGlRe1Fuff8tfXDhdFzjpf2P1bhp4F3CSWP5Z4Kd7/38X8Dmtday1PgTsB269mKdzEpcz2FXwnexxbl68nme6n3lRZfzl7jMcK00zkU/z1ErOoG3yg2SWfdF96CV1hgbo+2t300hzcq3xDYOqI+m3oWrlGFKR5QY3jc7x2/kdPFo3SZRmf77Azu5zQelY59v82ZO/zl1LI9xp/CNx7bOo0hDW4kFka7loTT1PpoHrjBIMbYN9j5M2y4SRy4nQZ8QVZ2TqL4yc6H6NWV7Brj+I0VmBG57LolW5H8POWGzW2N3SKH1hNTXfWcda8wam9DCWENhGISu5EkuOdSoYQnM4cDkeJcyE36dY5BKAZqp8J8vpYa6quEUNU8BbqxMs6Buod5/E9B3qokqc+RgYhbaVUjiYdDOLA22PPivHMxVVoBm7lK0Yz0qxjRzHAIViPngE31mLJX2a4bNoHTEfPMLzp+KpCvFNm5aOyMmwsBnV6xg11yGVxBcWDVqsKEksUg6xnVa0n1vd95NmNhoLU0jKpsmK6SAbheB3tVVhsdGPITU1OyPVAt+U1GyJJYu402/n3DY6xX/eeSvfDP72gj6LVwQqX70GW1iLbxBCPH7a5k9rrT99xvOEMIAngE3An2itHxFCjGqt5wC01nNCiJHe0yeB0wUujve2XXRcDrCrYCF4lE8cPF+LlZy9wdfYGwAICM6ua60pv5FcpywnGQO2ScUSlEyomApTakbcmJKZkitJ1e9y8+gJBp0BgsxkS3eUnc9zV/7jE3/C+vJHufqpLVQXduGM1ZF9Ofm12xDypX2kpfJWkon1OGOPUy51GXQiTOFxu/UOHjHuPavXfzWM/VGFIx+q4KtFxJXPTc2jzn5E3yTWthGmvzfH6xZHeZX6GT558NMvcLTVYQqHQdWPbciebivEOSwn0FlxyTQcDCIeye9B6wTT6KfPWXeqdn6rfBOHg4xB20QKqMcZm/Q1hM4Ky90dmCWHFeni6hIKhYmJq33s2OgFJ4NxL2a81CbJDUxDYchCpnBDOWPY9Xm9/jXaqeDeznGanGzzPfv7ECXH2WPvo18NE4oukQjwqWBgkpFxT/Bp1pTfSKqLKf2o2EhoLNMRAWiQeSFCrrqSTubidx0OtMsM2CmmVMS5gdKCiqmomIqylTLuB5TtmEwZtGOXW4cU9wWXDougEPlYpWShFcBBrfX7Xmj33vT+eiFEDfiyEOLqF3j6auqar0hB+nKAvQiQotRTZTrzM/KddQxaG7iWLQW1xpSUTEG/rRl1C0UvpQWOLERFlkOfdlwsxFSshJoTkeoKt3u/zIPhmRquv7H/L3hk8W7+/Wt24B2aZOLmZ9FuibR7nDTdBUZxHMMbf9EuMPOqX0Z1W6yvPIJ1b0LJWst1AyW++SmLf/7ffoa3P/7C0/ogPsCvf+5uPvtbf4WGU8IvSBNz5Da61XVMPPrHXHFsGkvmmEcGz+IUnxuCQf96tukbGbYcHKNwnnAMKJuaZio4FKTsk0foyhXC8Ci+sw7P6KfefRpQhPYaWnKOTeomVFxGA5lW5Ciuka/jcGkvkWqxEP0AQ1aQwsIySrhGlUF9E5aEiqUYdEPKbohp5JRLXZQS+HaMbeQsRx7N1AJs3jMwwe8EZ1PFTkeomvQzTECDVEccD+475Q1mm2McD76PFA5XuW/hSP4kSbZIx23i5z6WkAWFEAhzkEJgCUlTmPiGwuqxV07el62UihNRKxXKYa2uTy0oY8rV4syPCCqHbJXZ4kts59VaN4QQ9wFvA+aFEOO97HUcWOg97Tiw5rTdpoBXxAHycoB9WTAY9K/FEWW2qC0o4IRc4Fi6HSEk18nXMyJ8albRNZTpovvGNxX9dkLJSglSiyg3yHpasUFm9PySCnRSg9sHLI407zyL+P93zU/xqn0f5dd/9bPIMYHqNHD23QMqR9se2nbRpk0wesMLUrqkMAm3vg2/UWfilp1M3fkkXDFJeN37+YlHt/G/TIzxn0+sLgjz3Fj+nL+oD+F0GkizjBTmqQU3u9xHKhW2kXGgMcAt9jt4KDw/zYVB/3pGxDoMLXoW6cV7005h2IUJTzETCo4E30EIh6HSTdygb8KVEqNyG7vULEv6KM34MAveLFY+jYeFJQz68OjomHG9nq7s4PhlaowSioBjnW8TYDDR/xom/WIhbbBUlPmSzKIT+HhuhG0nGEKRaUEnNYhywYkQ7ip/lAey72Ab5VNqXaej3n2S1O0yblzBvm7h+nty4S3JFvGdNXTjw+zofuGM/UrY+IbENwuXjYqpKZmaspUz7BQXZYBuZhVtu0qSKMlK6ONZCRPjJyiXOsy0+riU4qtQ56JpvXgNVggxDKS94OoBbwZ+H/gq8EHg93r3J+k5XwX+VgjxhxSLXJuB83cFfQm4HGBfBixzgFR1CdQiJXsbviEZZQ1XySmGXVlY0BgarQuBlFQJLFl0eCnAkjkVS7OcOEiK/DdRgm4uWYgkQaZpJDkrKkLJ4kr+/Gz2N/b/BemnPsbdz6zD/eJ/KDZmGmwDPTqKqtZQzgFid+wFa7PCcMlGpjBusQi3vYHSyJ2UgG73CB+/4WmuPfwhfmXXX597f2Hw4Hfu4E3r/gfJ6FcxNrz31GNhNIORFSR8BWzxyjx0tjvIGdhUuosxNUqHEDQ06ZLHGkcYDFgmRs9wcsjJ+MD6Lt961mHUu5abxTXYhqRsCmKliXVEMzpMljcwcWjJNl1tUtY+Q4ZHRZRItaaZe5SpkIqUvcHX+MnSx/m5dSG7mpr15S5XDM0zPFQnS03y3MB2ElqtKsvtCs3YJchMFuOCTRDmmm6esVZeS0xE0zx6lh0MgCV95tWBsxwZIMcQFlJWUKp9autgPkKGJtcn9y8u2CVTUTaLOj7QmxXlmEbxd8lKKDkRY2PzVEaWiY5MkGt5KVkeQv6yMthx4LO9OqwEPq+1/gchxEPA54UQH6GQU3ovgNZ6pxDi88CzQAb8+ivBIIDLAfZlIc0WT/1wElMx6Rk96xnBhJfR3yOot9IiK82VwJAaU2pMofHMlFxLssgj6WWtnqlwDU0rlRzr5hzTS6fcRoVwOWqcLRjyyYOf5q+H383Tf6gI9w+RRw6GG+NOzWKM1xFZSmz7MPbmc56LX9pIMH4VRrkfGT1HR/f9taz7Ixf7N3fx/yUf45OH/37V6b3WCU/Wh7jmwW2MZN9Ab3mCbGId6eB6vPu/RHtxFCk0FTNlUzXnDeGv8J3wv6w+FmcdY2oUicDRFityhYaYxxFlcp2yPtlESVjkysQ3TGq2xW9O/BIbyyGLsSbMitJBKxUMxIMc7hkfLqb7GbY2gYBYRzj5CH2mTTfPaImAjmjhaZ+h0k2kWvPkcpk+u7Bcz5RB3/AyViVAWhlCatSOzSy2+lAITKHxjaLFOlWKDjFt2SIjJl2lTRY41biy2vlfIW6j5bU4ofadkm08KvcwrbZSVhaGkPTbikEn65keFo0tuZI4ZsZ4tcHo6AKWGyOkJum6mE7C8swox+bHaCQ24lLiwSq1ejDNXzzuaa2fBm5YZXsdeNM59vkd4Hde6jBfKi4H2JeJk2pag7aJ01szUBoyLZC9OliiJCoXCKmpWDkls+gainKLXAm6mUGQFxlFxSq+ULmGjkrPsHLWOmKb3syMeOSsrGdX8GX+8g8/zF03PEG7VaFaK4Kkky8jk4OY1UECf+cLlgqMvivJDRcRN0myJrbZVxxj8y8y/dqPsm12in8T/Sy/fvtDrPv82cHh8/Mt1u+4llu6LiPHj6DSo3jTjxMvVQGoldvkPWL8jUmF75wji+3GhzlRmmcTUzzLU7TimTMYDUbZYipfw7P5Xj4/833Qik9MfozlxGLSD+mkFqa0yLTBZrvGk5GL1hGuUSWnmIZ2RcyisGllDh3Z5kjyBLkKqbkbKIshYpWznFi4RsFkjFOL1lI/pczA8mLS0MEwc/q8gDC1ioYSINeaWCu6ostCuodcJbxQLXY1XCNfx3XlCgcCFyQExjxZXidTMT4uFdNgxNUMOxmDTnxKyN2QCt9KGe1rML5mhtJYHSEUcaNCt1VmZaVGMygz26nSSM1LylUWfY5FrstiL/+ykeUtysZ15BqqliLvfWnjXBIrSZ+VMuJG1GOHdmZgCI0jFVFucLxTJtWFbN5ceDLASpYiwXycsU8+Jzi9tvxmhvMx2irBsQYJk+dPK+FX93yGT3TuxpWaN685zgYl6AO8viWEyrH8qRc8F9cZhXMsiCXv+2neYH6Zqx+9kpmZcZ76iTdw/T3fOeM5T3U/zzdmfhXH2MD48iB95TaDrTLeQAshNINDy/TVmpgzkxzp+Ksu3p3EofB7vGP0F/nXk+v4hWczlk8LsMc632HC+6XTatKCrzRmuNWZIlESVyoG7AxHaqLcRAqHXEcYwqJfDbMnfYAN9qvoyCZZjzVQscdpRIdZCfcjPYOYUbR2KVs5FSshyU0OHltDaSHCNHKaPdGXlcjjeFBmOTGxhKZmS9qpQawjBEbPuFFQdbe8oEj4yfPYWnon02aZOAdXGkgtKdvjlI1reF/lKtqZwDNg0Emp9txk26lNqgUDdoxvx1SrxcW1dXSMPDNotyocWxphvluildi0UoNWKi+l/LWXlayWwV4OsP/CkTPbfYLIv4KapRjzIlIlWUlsHKkomSkDXhfPLH6ImZI0EptuLqnHhUV1K4XZMMU3DJZieCY/dla3U78aZpNTpZ0pwnB12TuAP5j5FDd6P891A2X6V2r4A008xySrjOD1MtILgTP5VrI3zTLqPURlzxKHdmzlyze8n/muz937voBSbSxzgANhyI6VGqkyuKG2wsCr94ME1ZSY5ZC86xAGPls7FapWCX/mY9zTPZu2pXTIoY7i7w6NcZXu43tsP/WYZ6/hsfjLpz1b02KJQ+EgqXJZV5aMuCklM8cUJkoVHlmJ6vJ0+EVMo8qCPowv+jG1yTSjbBeLjLhXcSJ8isXgB4z6axGiQq4FsTIgdlAIDrVqRdknsYpOKS1IlMA3FNOlkFRJRlyXa9U0v3v8PgQmhlHBNfqY0Bs56vssd59htaz2ytJPU1UVcq3pZOAbkmsZZ6saQwpQCNaXs57ouaaR9jRolUABWgsMqdAnBNVWlSixSTKTMLVZCn1aiU0jNQl7fnOXFJRavRxwOcBehlJtDqs6f3jNUeLYIcsNVjoVDKmwjByBJswsBp2Yma5HW0naqWQlETQSRTPLmBVL7Gp/mZ/vv5sDnec6skxjkOvtt3NHXx/1GA7q+Rcci2NNUMbjrV9eYu+vWKAkJDlW/SjdkSMXrCkrhYnyajBWw8vmWRPZSKmwlkb4Txvez3+cfZRRsYGrSx6+kTLsd6iN1Mmv3QamjXFoD27fMmQwYSjixEYujnLHcI17VlHe1jrhgfz7DERTDHLm4lyYzPD8ALUU72XUnqad2cx1DZS2cKRGA6/3PkhdtNgV30vNu5Jcx5TlII726Mgm30+fohsfYbJ8B5u8O6mqPsZlmSjXzHQNJD6GeK5TL8ol3awwyDQE1Kyibm5KxZAXULJSToQe/2b8g3yleYSq6iPWMV3RYZh1xE7nFGPgOQhqqoqFyXKaYAjJgGUx7gt8A9qZIFWFuEuuC32ETAmE0JRMxZgb9wJ/YQPTTWwcM0OIIpL6ZorWJ92TDcguIQ4s9DLYVYJpfqldCV4aLgfYi4Qd3S/yH+7/Nf7P1/6AgVqLUrOL5SRYVkYUurRjj1wLbEMRKwPdU+xaSVNOyDr7ovsBg/uSHacJywhusH+SaatCO4VWqphTq08xhbD58OBH2R10eTD+ImNXDvHV668hSyzyBQtjxw6cqEtwzbsuWIUr719PNr2IqfdSyY4zbWUM1Zd461v2cve26zjw20vcs2+Icb/LhumjlNfMY+wJwXfRg8OotX2IJMIN9jNa7yPLTOLcZG35zRzp3HvW6y13t7PCTg6cpY1wdqaTZovsUP/EYWcNt0SvoZ0ZVC1JqmDCdfCTAVa861hK9nOd8Ua83CJFERITmR3CdIHjnfu43v85yjjYUmKIQqRnb6uor56kRZk95S6zV2uPlGAxNpmPqvRZJWp2ryYq4FX2OhbilI62SHXOYblrleAKIGmJDhMMMkudRXGM9ckV+EaFthR0Uk3as/G2JJgCTKGZKmVM+l2umTqC48YcnpkkSG0MqbHNjFzJ3vcDDKEK7jWQaoG4lEqw6mRPwdnbf5xxOcBeNBRX2u2HN7B5tNA+rZo5ZrmLkZpoLWinFu3UIMwl7UwQ55oOcaEFKiSgmA0eOHXEt/gfpc8yGXSK7OVI3iBRnbNeeWvpXby7f5I/q3/3lKhIEDf55NOv5uvX5gSHx7HqAU7jIF72RfLXbsKQL93wziytJ1nvkZf7sUaPU9pSx9i2DTH1m5jApn/3/yB/T2FZKeOveQY5YoDtgmkSr70G1TeNubQbu7KX8sQSQ6HLiVaNV5tbOMLZAbZ4VzNYxW10NVhmhUb4DPfwDHd4H8YQRWusIwXDjomZOPxs+V3MxxmOlKRKURMOa8QNPOZZxLrDilxkQm8kyHM0ElsKLFlwcD0D+myF07PybmeSdipYjosAeDQJaMgWVxnj9NkCwXOKbErZ7BK7V+XEFsjZ2f174tJdxCKk3t3DstjHiryDWIQ42mOzmGQhUrhSULIEVUuwrtzmlit2MfqRFbKxadZ872u0d6whalaojC+RxxaNuWFmTozRDD2M9LnP3RSXUHZYrAyfvf1yBnsZJzEbxXxnvp/FyKNqJ4y2Ogw1W1hmiiEU/U58qvYaZJp2ltEVXVoscYV9JwvOMeaDhzGNft7hv5/bh3O6ucLv8RlPRH1s7x5nqHQTS8ETbCrdxagaoSYcvlVvnKHYBPB4+Df8v/90N1dWu9yxeTdjgDcyQ3LoS8TeANobxO275ryDrWMPIg2X1CxjbCxKDafLhRi3/zs2vfPDRIcHkEOSbNsNZJURjKAO0kS2Z7FOHC6e6yTYbsxopcmdoxU+1zj79V4qTjcU1BRaqH2WJNWaKNdUVY0vdb/FlHE1N5jjLMWaJdWmikdZ1pjtPkDT6OdIfi/b/J9hOK1RM20qlsCW4JvFjz3VglQJwkwQZNBJNc0spy6X2Rt8jV3ANf576dMVLCQJORaSue5DL3oOz/dp2xt8DSFctI5pl17DgBrDyE3W5P0MOZKJaoO+qQXykXXkG38Stemd9DmjnF5trwBTf/Vh2k9OsXhkknanRJTalGcvIa1Vxepki0vHNuyCcDnAXiSYRj+LosFsd4R9bYNBu8LGSpkJb4A+O8E1sqL91TaJcokUBmXT4nA3IVRNdoTf56QwyS/WrmLQzhjzIjwzJcpNmonNhGexWb+dNXqMPeUKo/kIGzyfR+Pj7AnP9nOCYtErvLvE09+6g6HQRTcznJ2PgGGiagMkk0cR47eft6miZZSw/NI5Hxcf/QzOA/8RJQfIt7wbnXUw5r+EtetJSDIIM5JjVZKVCjo3yJRBqiQTpdeekb2/XJSERSOPSZSFIQRdlSGFxDcGmVP72NO8lxudd/F08nWyvMHJGUjW48ymIqGjY0raIsg0wjzpdFHMq6NcEKvCWHApTanT4Vj23ELcju4X2Fp6FzkZLRaJ8uaLCgedCycthuaCB5kDBv0byNUGtqpRloIKiwenmPz6U1hZSu5XYesHzzpG972fpBz9Pu5QA+nHCKko7b+UAqxAZ2fXLM5z8nLJ4nKAvUjI8zZ74vsIvJtps4Cd+nxnOecN1o2MuC59lmJtOaRmJz2NSIeSKfiTDSZveXQvUvhMl+5gOp8iyaFk5thGjiE1SVJYznQzyMiIdEaqIx6KPs+SfDN7gtWD60mU/w+TP9gwzZo1x5H7xvCzeURZI20bI6iTtvahhgbPWwf2xRBtvg0RtfCcUWJhIudnyPaBLCnIDJKVCmnoEEcOYWKTKMkGtZlZLl6AfUbswpDFKvvafB2eMLG0yXz3YcBASp9ZeeRUQH0+jmc72Gjcgiur1GxB1dJUzELYW2noSgknSwhCsiTmiNKFM44xmz9LN1k4Q1HtYmC5u4NN3jW0M8H2+gBhapHENpP1/TijK0SWj3taJx2AaB1GTNWwzAZ60xpUuYr4k+3neIUfATSgVikK68slgsugqBVmeWFxfTo+x8OMl25nQI/x2niMLdWEkpkx5KTESvLVIxOs99/E4e793GJsxLIgUoK5sKDUjLkxQWYyG5p0MoVE8mD4VxiyD6WDM4KrFCVe5b7nrD7/XDX5xMHPk6qf5Y3Th9kQOVSuO4IIOlgHdmId3kM+9jjhhjso9d/8st8Lf+zNxEnR7eXYg+hOF526SC8CCXZ/m6Beo9MpobWg305Y75V4OHkpIjAvjNnggVMGiQ13M4++cYRrv7m392iOUm0a2bFz7h8li2ypDDPsCia9jLKVM+F1qXkhYWqxHHkcCTxybdBODW5QV3Bc33fGMV6Y83rh0GTUZZ2FqIQlTVJdJVYbqDdrhcLXN0JGJ36foZv2IkZt1NoNeI06+mgDMVkmuvUDhaeb9ZFXZHwXAp0LdHa2PPXlDPYyXhRzwYOs2FO0ulu4aWAtC5GNKTWd1GAx0pR0mWu9d7KcptRMi2YCICkpgSWKFWEpYCHrcij+HiDY5N3J4eSxHpEdXHuKq407mbZLq/b556rJbx36b3yg+SE+GLtcC/iTi6Qtlyx08ad2Y5s2vMQAG9QfRoZ1vKm7zth+UvcgaDyFt2Yaq7IMeRk91yFtlkgTC0MqTCPHNTK2VHPekb6PZ9Xxl+V4cDpOBrh2tI8r/3EfUpxZ2nghKUatYxwDanZBg6qYGWU7Zry/Tq4k44lNtTHAzkaNldjgUPjDnW4fDO9nynkfkxT26fXYwWrVGPC6CDRHDq9lZXGQ/sFlymN1pJ1gVm2ya179nGHmJUUjkOh8lQB7mUVwGeeDKDnOseQ4//7Y7VyhruSqarGwZAgYoUZXJxinfeEzBXEuOBGZ5FpQjyHr0beEcCipM4OJzqmIAAAgAElEQVTFVcbrGJEl7kkfPOcYlA746/qfETz7cT6YOEwdWKJcCvDLAf5UMb1N8wDLOHeN9fmQwQLujvsJ4awgGyzch3PkCbKBUURtCOP+R+nuHycJPCqDDbxKgGWlzLT6UBqmS5LNxhru0T/HU93/ft5jOF+cLapybvR5V+Aagn47ZVNfg/G+FYaHl3BKIc2lfoTQTFQbHGpX6WSSx/J7XvygFxFKtRmwbIYcxaQfUbVSSlaCKXPKfiEg3On6tIMSlfoA/YPLDN64l3xg83MHuZQCbC5W5+ZezmAv46VgLniQjd5W5kJFyZRULHAMm25mkapC51SjCXNBogAKr/tWmqPRWGaFOA05LveT9EREqu5WWrLJM/G3z8OFIOcLzU8h99/NT61xmSi3mBqZp6/jYUYBUXsf1mk+Xy8Gb/qdxOEKyjtbqUt2lzEaxZQ/r41i9kny2CYNXSoTC/jlEKfcZXp5EIXgij6FbeRcWXXZ2P9TvO3x7YTJubvWXkncJm9nyldcWWuwbf1BBqbnsPo6SC/BOJBxaM9GWpFPrARBnhOl5+P+cHEx4sqeFkFOxY4p2TG1UoBf6uJ6IX2ZSZaZlGotTDdBOApn/3cJNmRYJ3ZAO/6hj/lc0IhTjRBnPnAJXQQuAJcD7I8AK6LJQp4wmY4yYttU7YLTqCnsp3Nd0ALzU/qxAq0NFhOBFCb93pUMMsmCfhTLHKYV7aHFnhd93dPxd81PEalf4x2TJsuhT7NV5WrvQWz/YYK0A07/eTckiI0/jZFHZ21XfdOkE3XMpVlkFEKskFaGU+7iTtURozbWxnluHGyy8dAEWWwjpKaxXOPY0jD/++hd/OXyMxeVXXC+aKuEOyeW2TB9lNrEAt7aBfSNG9G2Q8XcRXV2lH1LI+RacG1N8o0g+aGP8YvBw3yifBOd1KJmx3hWgm0lOG6MP9jE3zSHKAl0rMmXfFTbxmjUcQ4+iPzBTrLo+TaVPzroXKJXyWBfGRHBHx4uB9gfAXZ2/75wQfDvZCn1GUlrVAyTMU9SsxWW1D3Lj5yqnZLkBnOWjehUuELeRao083FCXvop5vLdq2qNng++0v5THjv2Wj5z1Qj76yP0P7aNteOPYaydIx8YJZgOz2vRyzb7CLMOSmenmAhpHoBVIe+bwGjVkYsnwBL4a0+QBy5iQz9qYAiRxFh9bYY27Cc74pKsVFC5pL/rs6ka8BGu5l614bwFui8Wrqv6bN34OLX1MxilCLG2QjK+GZHH2EO7yHPJQuSRa/j6yoW9/y8Xy+Fe5sLbWONDqiSuEzOx6cgpOUUk6I3rIYnJjobkoU0pSRBZSr7ko9UP/6JwTmixeg32cqPBZVwIlA7OIJWvLb8ZP6hwazbBiKeZ8hMGnRhLKsLMJMgMJn2DVBXtmbm2kekYNzhrmBev4/7oc2jyU5zJ88Vs8ABa/wz722XcIxswv5EytOkozqbjCJUTZBF4wy9oBx4e/hL2zG6ijbdCdfNzvmAqQ9klsqEpTAolZGl2ESsBNGOE66FdD2Ga4LvISoQR2riVgL5Om9GwUH96/WCJj1Q+xMd2f+El1VEvFFJWuLZWlC+SZhm1VMNpNzEnZ0iHN6CWIOj6RLlEacFGY4gdr/iozoZWIRVTESvBoB8wue4Y/vo5skaZYHYIq9HCrC9Ap0vWGUflEkgQUUjn6Ch5/oq4pFwQzp3B/ngH2Mu23ZcIjnTuZU7tY3fYZmcjp5WaRLlBkFq0U4tuLk+TQgTXEPSZJitpRkDCm7xfuGBOy9sf/3uuqLY41K7w3Z3XcPgH2wh3DWIc2IV78CFkYz/qecc++bfSGe7T96MfPIpz4FFo7UM3dqGSBqhiZV0bDtp2C8V600CURHG/uICcOQbtQl5PWAqjFOHWOlRrLYYrTSZLHTZVusyFLu+vfRApKxf6Fp83pv3XkCpJa6mf9sIA80cnaM+MIDtNRBaTLVdY6ZaxDUXFzLlt6Eez1O3YY+xrC7SGgUqL0tQCcghUapIlFtJLwDAhVZjlHrXkxDJiZoZWvZ8sv4QEX7RA58aqtx9nXM5gLyE0wmd4hGcYLd3Gh/vWc6BdQeuCSbASF+IwhizuU6WJlaKrMzxsVnSXyfIdzHafOMNm5Hzx3qf/lgH/Om7gVmw5TTMosy15mtIt+3CiLknShcnX4Tqj5ComDo9jWDWsR/6UlX8YIu74jA0/g+1X0NJAuTOo0hBamqAzRBKBlNANwbfJtl6DeXQ/1JtgG1ApI0ohhorQqYlbCaiFTYLYJcpMqlbGuGfz7vyXOJCtvCIsg5O4XmygZIbEkUNuGjQ7Fbqhh/ovJ/D6d9BdnsIQRVCVAr514keTZUXJcZbNDNeAqQ1HMd4yDa0VrJkVKoCs6eI9r7g4YyukbZ/urlFUatJo9J0SgrkUoJVAr9JosOrC148RLgfYSxDzwcN8fF/MjdzCoG0QZDmp1nRVRo4iIWPRWEAKCQIOBt8ANELYaH3hdbXl7nb2lge5Z+5KgqNVfkPmXGHswF06hnPsGJQfQFs2MuziTE6j3RKisYw3aFDu0byM2UJ7ULseqraC8quIrDcmpdCxRkz2k256K8n0rTgHv4dxaC+YJlRLiLyDDBKscojX6eLbMWU7QSGQQMm0GIsHOKA2v0JEfgNDFLqqSWrRN7iCEJqZhVGe3H0FUWYy2dcgygoBn9dMHuMTh773Cozj/GBJyaATIq1iRpEPjGBcFWEsLUOtDHkGzYi84yKNnDTwaNdrdCIPdQm5cmktV81W9WU92Mt4JVDvPsk9PMmouI0Kg0yoMVIytqvvnpMg/3KC60kc63ybz6UHucN4Cw/PrkFrwZr5GVQu8WttkAooUdm2F268kmx6E264A10QdWGlUUz/4wgjCpHl3pReKdT4FHqNhXZLON4UeFNEG03k4DRGUMeaPQSdLsLMkXaC5cX09zfIcgM38pFobCMnUR4b5c08xcUPsHd4H2RzFXwjQ2uBWw2wvZhmq8pCp4JCsNCuIoRmPjL5rccmLmjGcDFQcTfzkU0NupmFSk3k8iKqWgPXRU9Pov0SstVAtTukjTIqN2jXaxydneBYq3ZJWcZoJXo14udtX2XbjxMuB9hLHPPBw8wD+3+Ir9mND/Mt/pK+hY+T6zVcHfkMV5usHWrgjS6DVAgbxLFDyE5MvmCRtWqYlRBZjhGuKoRdOiEijsBx0a5HXh0kr4yiTQe99BAiizGDRZTlo9wy2nYQpgEyL2qxuonWxQ/PbOVYRoYRVPAMh2vcAZ7qXtzzFsLl5prHulKIY2akqUUW2RhmjpSadmpTcyLaqY3Wgnos2CN3X9xBvAS8yXozB1o5rqF4+LEbud19iNL1B4q6xeQk2dAUslxDbG8Q1mt0W2UajRpxZmFJhSUvIQ6UOtci1+UM9jL+p0TRkGCIu1mJR3lPbRnDTpFejFaS7q5ROvOD5JmBNBRS5lTWLGAqgcyfy6RFu4vOI4SzjLW4gLF2PSKJEUlMPjSOiAJEN0BVa2jTQlQqyGAZYRQkeDu0MVb6yHKDNDfpcyKGHJdWKnnk9W/lVd/95rlO4CXjCv/t2D07FtfMMM0cw07xx+tM5ZJu7JAryf7lIQ51PDIFQ3qCuYs2gpeG+ayLovB6e3hhmHV7NrBxoo6spIist8Bo2hhez+gx8IkSm6rbZay/jnnw0gmwWq9eb/0x13q5HGAv44XxucanuCX+JdJnr+KXnQT2rcMvBSSJTbtdJstMLCvFcyPErMLrb2HFRWoppCKu99Fd7sMpdymvn8Vo7yWdKyP9GGNsgXzrlQgpEUmM7HbQfgkxmCDoIOIcw0lptSocb/bTShyGvC4TpQClBX++cxOjpSbzwcMX5VzrzDAfTrC5AkoLXCfCdBPMyZBq5Qjb/Ij5g9PMtftopCWaqWJ3ct9Fee0LwVa/TNmM6GYGIRDFDuQSHRgIpVBOFSEDxKCBNIpgKoWiv69JudZCXkKC21pJ1Co1WKUuswgu439yPBb+Vx6fcbm3/h4eDn6CpY/8LtJQLC/3E6Y2JaE5UR8iih1K7TLDG44jrAwhFJ3Ffk6cGMVxYqasDDdeITwxSBrbGPsyaupZ1ObNyE4L6nVEkhXiyyULQ6Uki4JO6KO1IFGS5chjutrAEIoor3EouJp5Lk6ALTPI1r6MspVSdiIMIy9qgy2BMBSGH1MdWME+Ps1yDEtZfMFNHhcDWtNzIs5YV+4wMrIIQoPU0Pz/2XvzGNmyvM7vc5a7R0RGrm+vV2t3U9U03UD3sDRDw4ChjT2NZYPBCIHUI7BBHjNCMoxHYmTLWMiWRvKMQKOxBhjZzAAG28BgDzvMdNPs3XRRXV3Vtbw98+Ua213PPef4jxsvq7rqVVfVq1cv8jHxebrKfDcyIu85yvjF7/6W729MsPcCcjbGj1t03LC6eUA4blDa4q3C+pMT3/TutRoNTs413gn399UvuWd4X/Fn5f/BRwafoJxm7GyfojQhRRMxKVN2Z32eu3mG/YM1bB0glUUlDSo0COEpyoRq1ENIT7g67eKBu+u016POuI5H+LHBXE4xV1P8gQFN9xrS0QtrHl4ZsRpVHJYpWdAwDA1fuR7ynvQ/f8vrO5t9Db/1Tfu8f2uXh1b3EcLTNCEmT2gPe7i8aysV8iWvbywWk9zqEHzRSksgHYOgYS0pUKF5qXe/apCTI8T4CJcHXZWBEzinmM0y8ukbF/S5F3jfebCvPJYGdsm/V/z67J/y0C/9OX987SJFE/G50SpPH2zy1GiFp0crPLl7hr3LZ5FJDdKRrk5I4gqPwLYabyUqauitjhluHSCzBsoCWgsOvNGU2xu4WdSpPTlBoFoGScn7vuTTfPBv/CmDqGa36FFYRagc7083EOKt9dX/40fP05qAdz74IpsbB/TTnCBou6GRRYwtYlwdsL+9xX6ZECt4T7R1l3b1zSNlj8NGYb0gCVqG2QxvFWaS4RsNxiOODqBtkZlBxTUysOjAYK1m72jtZDUauJdqYT/vOEGVDnfCMkSw5I74gWf/OVqt8p/2vpPWd4I0ANNWce7GOYYvHhzXxg5WJmT9GUq3TK+cRsc10SAnXJ0i18Ctb+EuDtE3LhG4fcxsPulLgtCWJK6whSQaTkk+BB88/Tt84v/7OrbLhEw53jFw/G+b/wV/5+mfveP17FcJT165yOPnrpKkJVlWUFcRh7sb7G6fYmU4RgrPtMgorCJWMGoWF8P80ugjVFYQK0sWNPSyLu5d7a/g6oAk2UX0LYQBIhEEa1NSoxGiS+JVe5snqg7WeYm7TePD7c7dT9zfV79kobT2iPVY8OvVr2Kcp2g924XgufEq1TSjzWMAdNQQhg1Ij2001bjPdGeDdpZA67HDTVw6wJ6+gHh4A51W1HtDqD16c8bKaleuhZdw84Bqf0huQgLh2Yxr1qOGP9zLeEf2H9/xWqZGE0iHaTXj8YDptEdZxVzaPcVnts/z7KWH2N3dpGzC4zfNFbO4EMGaSOlpT6QskTYo1SKUxdQhtglwtQatulbZNATt0VlFdnqfwcYRaVwiOUFJLi9uGyK4XeLrfmLpwS55S/zUzZ8E4NfEb/C9w28mb7upqze2T5PPMuqmu3UPA0N/MO0EVIqE0eGQMC2J4wnBjRfxcYrZuoAYDNH9q0yvb6GvlwTrU+oqopcWlIcD9n/9HJ96/lFCZbnYnxAqy6wJOZ8mfGl7gVH2AXbzP3lTa9jKPkCqLY+duU6cVOzubRBHNb2soF/HTJqYG7M+jVU4LzBeUFnYVYsq0FIEUhIph5x7pAA4QTTIiTdGqI0WkpWuVdY0iKBGpl2JXZCVrK6OCNQJKtNy8vaNBreb03UfsTSwS+4Kef08P3nzJ/nBUz/Iv7kh2Iy2CEedCPdaUrDRn5C6vBMh0S29wZRokHcG4MoOItGo3go+TlFfukp2eEh+Y4O0lSS9nLqKONjZxLSaM4MxF85fp5ilTGc92vEqmbZEMuC0f4hd3pyBfYd7N8ZJWqvwXhCFBq0sSVqwYSWVCbkx67NTZEjAONFNmmUx3pWSPVIliaTFOIlpNVI5gqQmyEpUr4RBgu8NwFlEWXSNIcYipMM7cRwqOCm8VifX7c7dT9zfV7/kxPGTN3+ST7jf44GVI47qiIMq5vp0wM3xkMl4wPRoSDnLugRSEVP9ZUb+1GncvsPFGe3qOcz5R4kf3MdZRZsnpKsTWqt4Zvs80yIjDhsG524yWB+RxN1o8762PNS3fPTcm1fbuqRe4KDWXNo7xc7eJs4Jsl5OENcM147YHIzZTHJS1Q3tWQsNj/U9N6rFTGU9k76PaWuxHiQeKR1h1KAig9AOEVnIeri0644j6O4iXB5iJhnVuE9ZJCcqgXSr0eB2x/3M0sAuuetMq8/xdZ/4XZ4cJbyYR1zKE/aKrEsQlQmj0QqjwyGH25vsPvMgR9dOQyvmKlyd10UrSFYnxGcOQHjSpGQYFwSqZXNrj2BQECQVYdiglSULDMPAEknHt/b/qzd1vaUb8/7NA86uHDGtugTbYOuga5pIatKkZD2bEciubdM4yR/sN29gPM/bw/X8DwEIpUdJj5IOFRh0UhEMckQKtJ2CmWhbqCt8BTaPMXlCPu5zNF6hsSfnBtZ7iXXq1ccJqtW9E+7vq19yYnE+57dmVxg3grzttGzzOqaoI8omoigT2lbT1CFVGePKCFnleB0RvPA03gqc0bg6wFuF0pZHL17m0SeeYfjg9a7cK2jRoSENa/pBQ6wsV4uIwr652OIPn/oAw6QgCAzWCbTulKnC4YwgrRDC0TrF1ITkreagCai5t1NkX04SnuV0rEm1pRfUZFGF9wKhHTJtINKgdWdcWwOtxdddOEMGLVJ2sVt3ciIEuLnmxCuPN1IHK4S4IIT4PSHE00KIp4QQ/838/JoQ4reEEJ+bf1192XP+vhDiOSHEM0KIb3q71nVyPsKW/LXj2fzXaMQ38RXmEbaiiM0kx3uBdRLrJN4LVlbHhGmJTGrkleewvVU4GFPf2KSaZJTjHlI5th5/gfDhKcQhfq+mPczQWUnSK0inJWluiJtb7aBv7rYyVo66Dbh2sEFtNUo60jMHne7CwQpNEzIuE6atZmI0o0bypPu3b8eWvSG+RH4ta2E3VijUFqVspwehLOiXrKaXEsKoK8bSHhm2hIMZvTogn2UnqEhrHoO98zKtFvhh7/1fCCH6wJ8LIX4L+F7gd7z3PyGE+FHgR4EfEUI8DnwH8ARwFvhtIcQ7vL/7E8CWHuySt5VLs9/gux/ZZafS7Fcp4zKhsZpyrkgV93N6D9xErnZ/29FffpzmUp9q1EPPu8BWHr5O+O4GNtdhdRWxqhHadh7u3MNR0iGEx3vB1DU8nH34DV/jU6OQzx6uc3m6cjzJui1iisun2XnhAofTAZMmprES67t44ZfLv3XX9+qNoYjQtF5Q2e6DSivbGVfp4WXiUz5Ocb0hrKwcJ7RkZIiGU9a29on0yZmJ7ZFdLextjtd9rvfb3vu/mH8/BZ4GzgEfAW4Nc/sXwLfOv/8I8PPe+9p7/yKdWN0H7vKSgKWBXXIP+P5n9nnHoOTFWcrl6QrTOqJoQsoqBunQWwWspFCWNJ8KaI76hFlJkFak6+OuKyzr4dOsS9qsDJCRoS1jXNsVzyvhCKVjPWp5opfyPvUQG9mXvaHrW488xguGYc1mNmV1/QicYP/KGZ669gBXxqvMTEAgPYHwTFvB2Sh6m3ft9jyRfiuPZDFrkaUftCjpiKK6k1QM2s+7J/VhPD8iROoRQQteoCJDujohjE7O0MNbVQSvChF0ZVoPCyH+7GXH973W6wghHgTeB/wxcMp7vw2dEQZutd6dA66+7GnX5ufuOssQwZK3nWuz3+eXr7yDBzNFZSUToxmGhpWkREiPPYxQQYmvPW0xpJ6lpBtHzG6u09YhbRWSmV3U2j5s9rrSLu2xdYBtFVFcs9qbzT1YKGwPj+Jv+6/gZ4vPfsFBiVL2OWoE7xoYLq4ecnpzj3hlincCqRyDqKYquiYEJTy9wDJqFP/n+Kfu4Q7eQvA/vjPg2bFhPWo435tyanhIkpWoubEUt1wmN3dlne2+DwSqV2Nn4BqNUA4hTo7WqpuHjl7J/NwL3vtvf73XEEL0gF8Gfsh7PxGvHSq63QNvS0R66cEuuSd8wv0eG5FnYgQHjWJqNE2rqUY9Dv7qEcrPbGIPu86vpoiZ3VynylOOjoZcefYRtv/8i6heWIeq04m14wRTh8dyiVmas9afcG4w5lxSsRl51iPPNyTf9QWv68uibyXTEKuWqgkpi4RyNEAGLdnKlIundjiVzUjmt9N5243wWQTne1/Lx26uMQwN53tTNvtjhsMxOmqQoUFmVecyadWN4IFjXVh0l+TybVf6lu8PT1SXlPddDPZ2xxtBCBHQGdef897/X/PTN4UQZ+aPnwF25+evARde9vTzwNsyYndpYJfcE6bV5/ilo6tk2lNZgRQghGd0uMqVq+e58lePUe2s463k8HCV2WhAOpjhvWCUZ9zc3aTYW8VeAw4myLBFKofWLUpb+qtjNk/vcm7rJuf7E7ZiQyw9Z+KAfvwYQsSvuiaB5pGoTyg9eRuwW/Q4nA7Ipz2K3TWaIkYIh/eC3ATkrWK71HyWK/d+AwFNRKY9sbLH1Q5dg0GFzipE4qAfQ5J04uVN1c1DCyOIu3ZZbzSmiKmLBHvSDOxtjjdSBys6V/WfA0977//Ryx76VeB75t9/D/ArLzv/HUKISAjxEPAYvMnulDfIMkSw5J7xueI3+Nd8C18anuWBFOo24Gg6YFImFHXE6uERtlXdqJbA4J0gDAytUxwVGYOdTaSyDMLLuDoAQKruNjeIX5JGHBwWrEc9Kis5kwq+svo68tjw8fJnPu96Hss+TKZFp0HgJK2TjMqULK/oNwHWKnYP1zkoUyYmwHowDipm93zvAPpuwDBsMU5StgGzMqVX5SROdrf8IeA82LabGlHNhc9nk2O1MugkF52TJ6oN9ZYH+0re4Nywrwa+G3hSCPGp+bn/DvgJ4BeFEB8FrgDf1v0u/5QQ4heBz9BVIPzg21FBAEsDu+Qe4n3DmH0uVUMesxGzJsQ6QWFClHTs7W4AdDWneUYU10RxzSAuuDld6ZJiAA7UsCDcL2mKGGsVOmrQSdXFdL2kdhLjBX1tebQf8HOTz5/8KtAoNI3rCvb7gSHRhsYq5FzzVeuWptU0rqvjBZga8CwmdnnVP8314m8yWDEYp47lBp2VtEWMqgqEaqAxICVCBwhnOznIxhzfrwplkdLdPhK5IF4nBvsF8d5/jNdezW3LPbz3Pw78+Ju4xDtiaWCX3FNu5P+OjfQsxsVUVmO9ZDRXqHK7pwmVRQnHWpbTmoAkLVDzAX1KWYT0iGjutfYLgmmKK2Nso2lmKcWkR9WEHNUhEs9q2DIILN+vP8QvjS5ywzxJ1Wyznn0Jmeu0BQLpWYkqsqAhCgxxVKG0pcpTGquJlWUQGCobUlnPdv7xhezdV8ivxjiB9YJhVBJpQ2sCmiIhrItOWFsahPZQ1Ygg7BJcrcVPHb68JWKtTlwL6msZ2PtdrnBpYJfccyzt8Rs8Vi2B6G73yzYgCxqsl1QmwFpJXUVo3ZKGDVUdMdlfJXi+JD6/h4rrbpRM1ZVMNU3Izb1NtvM+DlACAunoK0thJV8ZPsxzbpNBGoOHQAoS3Tl23gsGScG589cJki6RVuQp0zrCOEmiW/I24WP2LxaxZd31uBYp9HG80iNwc1FqZzSuDJFRCxFdUquuOgPbGHypaEc9bBHRlBGmCU+WkX2NeOuJusY7YGlgl9xznHDMWsGkCUl1l+UOpONcf0wa1uznfeo2oCgTEi+omy6EsJ/3iaOa6OZ6Z1CMJh/3mc56BHXEaNbnyb1TjBrN2ChaB9aHbMUNfW05FWuk6BPOnSIlIFZgPTgEg/6M3pl98JLZzhqjWZ+xCWmdpBcYTiUNRzuXFrZvIzHD+hjrBY3TGKuOY6nOyi4uLT3E3QcWsy4G63OHNxG2DmiriLpIKMrkjcY37wnOi9vqDtiTFMe4A5YGdsk955niN/n63veyVweUdkDrYThPUAEIPHWrMVYTOokUnnGZoIRDK4tQlvKojwzs8XPqOuKoyNirA24UirOpZRhYxkZRWEUkHYPQoWT3JjZOMAgca2HLetQ1GGT9GUI7bBFg286ARXOBF+u7W/NFCbwAPKzW2Iq7cEWiDUnQEATdB5QzupsX5kSX6GoMtB5fe9w4xJYR3iraJqCpIxqjT56BPWEhAiHEP+EL1Md67//u673G0sAuued4X7NTepRQzFpJph1nlaV1qpvd5SWNVYyKFIEnCg1KegI5T84AYVYR9guCqMF7wWTaR0mH84JzqeVbHn6eIDB8/NIjXCkiNqOWRDkS5QjmSaytuGIrzVnLpmxs7tPbOgDAFDFtq4kDQ6gsWjqO6oj/defFhe0ZwPvWPGeSitW4pB+XpElJGNco3aIiA9Ljao2cmnlFAfha4qpwLpojjz+QiiZ6Qwmke8VbSXK9jfzZy77/74F/+GZfYGlgl9xzPC3XzIy47rMWCbYix6lsRqjaY+911HRx1WFaoFRLGtaMyhTTamwToFcnIBwqrgmiBnOkCZUl05Z3rx7yxNf/EUfPPIB98dF5B5YhVZbVuDyuFoh0y9bwiMHKhOED2+iswjUaU0YcHKxxfTyksopQOvbqgNwfLXTfruSKU7HEeUHVhBRl0s06C1tUaI6HM6pZRbA5OTayCI9QFqG6ml5r5YmLbd76YH0li5Qr9N7f0jFACPFDL///G2VpYJcshFLUzNqMlbArp8pNSD8uiUJDEhjGJuSwiUjyHpUJ8F4ghWdWpgSTFj33XIXwjI6GXB2tUTtFqroKBDNJAZDC865BzhefvUoUNsRJRVNHjCadx7u6foQKDWaa4UxnvK9cucC18SrbRcaZNJ97z55RdWmhe/a/jwe91CAAACAASURBVH6Zrzv9jRxWCftlylmnWKkmhGGDyRPsXPwmWZ10soRZBU4gtIU6wDYBpowwrZ7v3UKX83m8prj2yZFUvKMrWRrYJQth6HsctDWnXIL1gptFSi+sSaKKYVJwVCVcLxJS1Qlgdzlz33m5c9WsfNxNL9gZrXGjTPFeUFjJswebTP/gq9kvUiJl+YpHn+H04y9gy5BmlmJ218mSkjiuujZTZammGUGruH7pAS6P1hk1IdYLNrMZw96UR7a2+bEri+3db9odtosEOQ+z9oNOVxdAFenxGBghu0MW8bHKlvcSZzRNE+KcwiEQJ8h6vWaI4D4X3F4a2CUL4VP+Y7xXfJDGdVn8wipGZUIa1kTaEKuWWHUShI1VRKpF3pLcmydznFO4eTeSFp5It4RScb1IOKojhPC8Z2OX/toY30rwnYBLkpYI0XUzCekI0orZ0Qq7N7e4crBBZdXx7C01j/n+2B8+Tmv/YFHbNUdwtQg4FbckuruuSZF1jwjfyRbKW+3DKbJqUUGLDCzOzAW3pUNKi5YnZ+Ah3KoieLUHe7tz9wohxJSXPNdUCDG59RDgvfeD13uNpYFdshBC1SPyisp6pqbzUi7NegCcHx4R6Zbz2YxEGzyCcR3Pn2fR2tIbTAmjmnyWMWtCkvmE1CwwTFtFplsu9CdsDY/QocEZjUprZGCJ10fsPfsgN26eojecIJVjOu1x6WCTZt4dVVlFID2HRcaV0SqxWvz9tBAR+7VnMxbzDwBJ3QaM8x6h7uLXwVyUxjqJ1hYpLTLo9GKt0QjZVWJI4TEnKMn1WjHYN6IH+3bhvX/zA95ewdLALlkIrauZUBG3KfuVQgqJdYK9KuGUnSCFZyWuaFqFdfJ4HtZhmZJFFVK39HsFpgmQwmO9INNdtcHZeab94tYOZx67RPbEDm4qkSsOuxuBcmw81gm2VHl3az2a9SmNZtoGpHNjfT6bMWkifm9nwG+bP1rYXt0iDc8RSsGokWTaUlnNuIq7ZoqoQivbNR/knQpV563e8vq7qQe3Jso2Vi/UO3wl3t9ed+AklZLdCUsDu2QhjMqneGT1b1JZj/GevBVYCeZlI2X28u72dzUucQh6Yddh1TqFkJ5obUJwMEQJz7TVrMclZwZjNlYPqeuoM65fvAOnN7o2fNPgrlnaWUIwKNh8xyXqwxVUXNNPSgZVwk6VsJWUvOfcFcoq5nevXmRiPJd/+AWy/2Fx+wVQt4dMjSeU3TSDUipcE5HNO92Ud1QmwLmIoom6VlqnEMITaYPWLcYEjMqMT+9vMj05Aw2+QIhgARdzF1ka2CULIQrO8L7Vlo/vKUIpCCVkupsY4OdvtmkbHHuvK3FFGtbEQUNlQsppRluHjMcDTvXHDJOCC2e2ibMCbxWbD10j2hzBxhA3XAPnkNvX8CZidnOdHt0AQBXXeKsIg06w+p0rRzzxyPNsPHqF7ace5Zm/eoS9pmL4Py3+rRLpNfZMTaxiZqaLEwugH5jjWWelCajn02KFAOsEsW67+LRqGVcJh1XCZycBE7e/0PW8nC7JdRsP9gQpft0Ji/+rWfLvJbW5QTGfpzUMYRjaz/NijOsMSDP/v/OCm9MB/ahG4slnGdZJJkXGsDfliff+BW0Rs/38A7x48zRfVF3i1KCA6QyRZp0mahgCEPUK2jLG56JrHc0TJnmPQdwJqJg6ZHLtFE9fvciz5YxPlG+6/PFt4ZR+BxsqJNXQ+s67U9Ih53mYxmoKEzI1IWa+b5VVxMqSKkuoLAdVzHYZEis4STVQ7rXqYO9zyeqlgV2yEJRcYbtUWG/JW9iMPJXrbn1vGY2JCegFXV0swKSJOKxjTqfdCJjD6QDnJBub+8SPHpA/dZpr+1t85miNUFvirGBj8xlEbwpVCXsTbL1BsnWEazTl3iptHZLPMqRwRNoRBi0HR6vcPNhg0kT8afOvF7lNn8cHgodYjwSx8sTKk2hHqiyRbrFOdAbWaiYmYNoqylZSWWi9YBh2MexPHnpm1rAjDxa8ms/ntWKwJ60h4s2yNLBLFsIT8TfzyemU0zrDerhaaIyDvBUUc3GXwkrWI0eoOu92NaqYmpBQWcKwYZjltK0i6pX4CkyeEKiXAovJygyxIrFP14yePcXBzrvQ2rJ2ehepHHWeUsxSlLL00oKyiinqiLyO+cv9DX5pu6K1J8MQKbnCTl3zRSsvDV/MdEusWpToWoQrq6msIm8lR7XksBFMjOO59oALcpXCtvxe+TPAySrRgpNZpnU3WBrYJQvhin+KLxNfyflU8kBmuFYEjBrPegSTJmYjyenrTgegNAGjJiJWFok/jtWtrx8wm/aoZwnx3qAbn6IsqbacXdsne8d17I2QFz/2Pi7dPA2Akp66CYijmrbVmFbjnKJtFUXTTbu9PF3h6UnAZ/nYF1rCPUXKkPcOY04nxbFXd+u2HziuEbZOUlnJ2AimxrNvGq6Jz/Lp2V8u7NrfCF2Z1tLALlly1xj7ksf6sBrV82GCEi06Axrolo24wnrBQZWwW0U81J+hpOegSlE7Z3n0whWck+ztbpKuj1FxzbA35d1OsnV+G7GqMTd6XN07xbPjVbwXhNIxa0J6YUMa1scCMXkdY6xkv0p5fhbzy/nvMS4/s+gtOuaja9/Oe1e74Ytu3jashCPS3ejuW11QHqidYGY8k7alpOGwONnGFeaTbv4almnd3xHkJfct4/Kz/JP3H3C1CNgpYwLpWQ09g8CStwF5HZFqw1EdMTEBtRM0VuG8YBhVOC/Y3dvAtAGbW3vEpw+RQXtc4mXqED9umd3YIDfhvE62ZRA2JNqwnffYnfUpm5DaBMyakMMq5blJxqUZTKvLi96iY9LoQf7e3/gkF/pjlOimOyTaMIhqelFFEjRE+iXlLw8U1qGEICJY9OW/ITy3H3roTk4e7o5YerBLFoKn5Tv+wvANsWC3CkgU9LSnsJLMKhqrqVp9bBhv9dlnQUMaNGwNj+gNpgAI5civbrF/9Sw3DteZzZW46ivrXLt8gdwEWCcYhjXDpKRpFUp4tHREgaFoIq7nPQ4bzbMTwZ/a53E+X+T2HJNGD/L3tj7MdPYcZ9b3mW2fw9GVXsVzw9pJEIbdWB3h6WlHP5AYB+8fSD52ddGreH1ey4NdhgiWLLlDDtvLXC8fIVWSiQFiSesFkVRM515nrCyrUU2sujpOJT2tU4zzHkJ4pHTs7W7SWE1rFcYpTvW7lvHp9gZXR2s0VrGVVITKkgQNkoDAONbSnH6a085LmQ7qiE+3N7iU/8ZiN+ZlPC4/yD/46L/ETDL2L50j0i2tkwSqnTcP2ONaUYE/FghfDQV5CzvV/WGg3GvEYN1yosGSJXfOuUTzQGb5zEgyMZ7aCnpaHddvrkU1G0nnTQbzYvm8jtmerHBjPCRUlqkJCaRjI8l5cPMmWVYQpRWmDhnGJTtFhnSSdG6UlHRkbcCoTI9FUgZhQ6wSbrhnFrwjL6HVKj/woObmXz3KYOMI70R3/U51YuBBi5QWIcRL0yDmHmwZSBonGAT3xz2287fv2lp2ci1ZcocEMmUt8jzSzwlkytNjTaJhPWoJpMN6gcRTtgGlCUiDhmFasLEy4vTaAQeTFUZlelxZYL1kdXVEkNS0TUCYlTxweptZE6GEI74VasCTaMNhmdJMB6xEnXe7FloeEl/CpzgZyS0hNFtpjtYth9ubOKdI5kMh47AhmIcHrJMo4eaJL08oHUp4GivYtfeHB+i8oF2GCJYsuXtUdsyTI8tGlDBq1HFCw/ku++qA7TIlbwOMk6x6SWFCHo1qkv6MC1nBcNpj52idcRVjnWA8WmEoRySDGVJZVjYPeZxu4uxk1mNaJQTKEgWGpDVMm4hrswGjJuSgURiaBe7I5/MtyX/Gw6eeJEwr2lbTGoijGikdgW6pm5CyjrFOzj1xhxYOR7d/QsBedYIEB74Ants3FSwbDZYsuUOG+gI3/Ig/O1gHwHqHR9A4QTEPERRW4nzQjeGWAbGy3DhaxVrJoD9FzoVMlAxxXnAwWSGOK+J+jlAOqRxRXFOUCZ6uvOlWSZMSXbzSe0HrJKH0fMvqKZ4qFrUjL/F1yd9hGErWTu2Tnd5HxzWjnU2kdMRRffxznf5AONci6EIFEuZdcR51ksYWfAH8MkSwZMndZWp32JBn2WtqlJBIBJUVXC00WnpipaisQAmB91C2mtZJvM9onGZYJRir2S0yJN3t8WGZofY3ieLOCDV5N8DQOUllAo7KlEi1hLor0G+dPK61DKTngaxa2H68HIvn2x68yeDiNjJuMNMMITxxVKODFmclUdhQ1RGlCRjX8fGkh8JKKisAz6EtF72UN4RlGSJYsuSuMq2eY9y7yMBmCO8J5iO1pwa2y4BUeWat4IGsOg4ZtE6iZVcL6pwkNyEz03m2ge080pdPTFVhS3UUMytTRlXKYR1jveBMmtNYxU7ZCXkXVlK0kv/3eryIrfg8Hux9E4+nMY+efRqZ3vqgSGiNRspucKHSFmOCrnrCSQ7qqPPyhaeyklh5+oFgy6asJI+fqKaJ2+GXZVpLltxtPNfLP+cd0cOkqpMtVAIa52mcwDhBP+h67tfjglGd4D2sJSW9qGJ9ZcSDUcPR0ZCiiQiUpWxCsqjzQnVco5OKXhFTNyEHeY+DOqSy8rjDZrfWGNcl02btSZhTpXjMXeS//rJPc/59TyMzg5tEXRdaXOOsoq4ilOo+YELV0gsbVqOastUYJ+kHFi08zismjSCVq4wXvKrXw/vueNX5e38pd5WlgV2yUJRMuMmYx9U6gRQkCmatp7KgReeReS+obEDe6q66wAl6ScH5d38OlVbIJx9DjYY0RtNYzXpUEyUVOivxvhtRXdUR1gsi2b329TIibyWHtWAYegIJeQWf8i8sdD9+7IHv49sff4pHv/GPkCsOHIjIkKxOcEZRzDLMXENBSYeSjkgbNuIucFzMp/EqoaisJAskj5vH2ebjC13X6+HoJBhfyTIGu2TJW8DYKZEOj40rQCA6Ae5B4NmMWhJtqFpNYxUzE5CqljQpQXpsEWNbxZWDDRyC0mh6UcZaHeKakPJwwN7eBkUToaXjYn/K5Wmfz01DjhpPpiGQMDWCvdpwvfmLhe7H93z5n3HmS55BbgA1uLGiHfW6keKtxpjgeBxMaxWlCbtGCd3iENS2kzBMlaWykkErOR+HcAISd1+I5USDJUveBr4h/k4K39JYz+kEMu2YNBLjBf3AkeiWxip6YUOsW/bLhFETsXe0xhmepxn3yIuUYVIQBw17swHbkxX6hzn9UwfYRpPXMXtFj8YqaicxTtA4iFVn1J2HmeluR61bXJLrndlH6A0/i1opwTh8IWgOVmiO+jRlF1eW0lM34XE1hGn1cWvwrUmxXSWBPw6DjI0j1Kdp2p0Frez1cdzemC61CJYsedMI0ugiW8E7ObIlAxFTO38s8KElKDzGCXariG0fcT6tyHTXgFC0+qX6SOk4/+glLoaG8mjA7LPv5KhKmJUpxcEKs0mf6bxG1jjJxATs1ZpEQaw8HiitoHae9ww1v3VjurBdOe+32Lk2ZvV9z+Er8EZii4i2CcjHfYT0BGFDFDbkVQJ0raRp2Bzvx7jWHM3DIbmVNA4iKU60cQXgtWKwSwO7ZMmbxZPqdaSXDETMUAc0znFQd96lnMde87Yr0cpbgSDmQloRq5ZKKHZnfQ6eP08QtAwe2CF+9JD44IDguUfIW90V3ytHGNf0oppQW5pWIcuMqVF4JIHsRoYf1J7DpuUzzWJTQXtM5qGPzri6OsBZhW26MjOtWoLA0O/Pjltjb3myTatpncJ4ychoylayVwsmjefQnPxmA8udx2CFED8N/EfArvf+3fNza8AvAA8Cl4Bv994fzR/7+8BH57/273rv3zbxiaVc4ZKFoAjIfI+Hs5APnyt4z6rAeshfZgsCCafilrNJSz+wxKolCVpWwobdMuUTTz/B9o3TxA8eYt/zHsRcF1XP45Oj/TVmkz5ZVLGazjg1GLMS1aTKkajOQz6oYbtquCr2eN7+2cL2Q6B5d7ROkpWYmwPsKMUcDSgOVyiLlDipyFamRL2CJC2IowYlHXHYfQUoTUBuAo5qyeVccKO0jFvLFXFzYet6o9xqNLjd8Qb4WeCbX3HuR4Hf8d4/BvzO/P8IIR4HvgN4Yv6cnxJCqLu0jFex9GCXLIRY9IhdzCDwXByMGYY13q8yMoJAdoIlK4FlEBgmJiDRLRtpgfOCQFr6YU0aNPR7+byv1iL7lrX+hLyJaKzmc9vnUMKRzsfLWCuReGLlmLaKUSMorWNKxUyMUWJxb4fHsg/zSM/jncCMM5xVNHlCPu1hraQ3nBANZrRljHMK5wR1E9K0AdMqoWo1RdvN4hqEjpuV4ml/mYiYZ/JfWdi63ihvRezFe/9vhRAPvuL0R4APzb//F8DvAz8yP//z3vsaeFEI8RzwAeATd3Ldr8fSwC5ZCIGPsFi2S3j2aA0tHbXrxlALuq6qTHfubDd9VjOuYtKgoTQBj53a5tH3fxqVNLASI6sSNMRRpxd76xZaSUfrFEXdCb44BMZ3HWO3JrN+cLjCL0xeZNbcWNh+fGPvAf72I5+jf+oAU8SYOqQuEpwThGFDkFZ4q3BW4ufyhK1VVCagajV128VeGyf5mYPnuDz77YWt5U54zSRX9+VhIcTLby/+mff+n73OS57y3m8DeO+3hRBb8/PngD962c9dm597W1ga2CULwYgaJzyBEIwaTesFgQTjoHUwahSp0sTKdhNH588LlCOhmzIbXhghViNoHWIygixCB4bWKTYHY6KwxrSaG4frXD5a6xJkVhNJxzC0jBrNQVvzB6M/YVpfxbvFtZV+xcaUc+ev46yibQJsEyCkYzCcoKOGoF9giwhn1XFCSwqPsZpQWXITslsH/P6u4XJ5fxlXuDVV9tXn5+de8N5/+136VbdrDXvbUmlLA7vkniNEyKY9zVROaf0aWnpWdcvEaGLVdXDlrWRsutCY8YLVeZwxDhoam7A7XuXiZ87Re+91fAHuco6rA2azDGMlzgm0bjGt5qhKeH7WIxCe9aghUhZM96d/VV1hNPurhe0FgBQZ7z5zndmkT1UmxwY0SQvCrCLISqSyOOW6Eizl0PPZXM53GrGDUOB8n481/89C13KnvJYH+xbqYG8KIc7MvdczwO78/DXgwst+7jzwtt26LA3sknuO9w0viCfJxDo3qppTZUgVdvnWQHicEKTKk7dyXlHQ3erXTlGZkNIEWCcZbW+SXtzh6KmH8U7Q1iG741U8nXEFqOoI4yV2LoFYWEXeKp6faloHO/Xie/ST8DR/eOVB3rV6wKSJmTUhp3tTHn/0OXRSoXslYv4BI5UlXRsTpiXGBOR1TOsUN4seT4/FiRkz/mZ5rRjsW6iD/VXge4CfmH/9lZed/5dCiH8EnAUeA/7kjn/L67A0sEsWwmHxlxyiOJ9c4MmxZD3UbMaCRHli5QmVo20lsXRsxjVKeKwX7BYZ3gsi3ZIOZrg6oClioqxERw3WSQ6qBH20zoWNXfpZDvtgnGDUKg5qxU4F/848TeGOqM3i4q63+KGt/4CitYzrmCuzPpfykA9qg9QtQa9ERp1GrU4rhLL4eQKsMQGjKuGwjvnIBz/G9/300YJXcud4D9a9+vztzr0SIcS/oktobQghrgH/kM6w/qIQ4qPAFeDbut/jnxJC/CLwGaAFftB7b+/KIm7D0sAuWSCWT9rf4V36a0jtkLwVxKp7swnRdXUNQ8O5/oRRmZC3AZauRlYJR5BW6I2KbHVCtDZGRobHpj2OPvdOyjZgVqQMerN5g4Fk1HQx3qeaPQqOOCg+uegNAOBTR57vuFiRaMMwbHhEeNaSotN4rSJE0KKyCpk0cNin3OtRTjPCwLCaFCjh+a6f+3q8/4VFL+WOcbwUZ385b8SB9d5/52s89Lde4+d/HPjxN3hpb4mlgV2yUKrmGqsq+7xztRNo6UmVI5Cum8PVBqxENdYJJk3EzETsXT5H/6tuMviqq929ZKjZnF4jffFhrsz6APNbaEkgOpGX55sRz7YfPxGeK3Tx6P/wrCHRBiHgQr9rdujHJbYJUHGNjAwisogQZG5om24U9/rpPeKkYndvg3/w3oLf/MOTrpn12njvsbdp21pqESxZ8ha5Lm9y3cEXNxfQQtDTnlkrO22AMsb5dSqr6AVNNxlWt4yakMm0h7vhkGcVtBZaS7Ay4+zKEZ8dr3B52icuUmrXTat13rOndqjLk2FcAQbxo5xJc5wXFCYgVJJQWVYGE4YXtwk2J6C7ALIrJWaSIpUl6eeEWRebNU3Ih373/tZN7ZJctzGw97lg4bKTa8nCeTb/Nb487BK7HgjnfTWNlUxbyUEd4oHJXNQkmIua7M/6HD75CPaKwO4o/NSBdKwMJmxGDXu15qAO2K0CpIDobevXuXN+5PTXMKpjgnkSS+BZy6asbBwRbo4QsUdo8LXEjpPj59kmoJpkFJMeWX/Gdn6y5QhfD+e7VtlXHve7B7s0sEtOBE/We5TWMjV+Pu4EjO+SU8YLVsOaftAghSfWLX1tcF5QzjLsLKHeWaPd6wGwfnaXQVhjXDeGJNOOvnYEQlD6k3Ub/cf7EgeEqqUf1ZxbO+DM2R2ifo43Gl+J7iiDLqE36dEUCU0dUpcx2zun+Z9/92sWvYy3jMfj/e2P+5lliGDJieCp6t8wTb+KR5oHCGTI1nxyi32ZTmgadNn02nbC20p6TBPSjHs0eYJ3gnA4Q2jLIKrpB46+7kIKuz4iUhCSLmqJt+W/fOcuuQkZpgVx2NDLctK1MfHpQ1AObyS+VTQHK1SjHtU0oypjmibEzueJ/eOdf7roZbxlujKt28Vg728Du/Rgl5wInJuyZtd5WnyWvbolb+dGVXn62pIFBuu7P9fchAA0VlGUCaaMiPo5MmiRcYNOKlaSnM2o6WJ7riv3SjW8w71jUUt8FSvJ49wsegTSoaUlS3OSrETFNWqjRvYN3knaSUo16pGPBkwnfQ5HQ/bGQ/bHQ/I6phOFur9x3tPe5rjfDezSg11yYnjafoyQHk54Ro1HCkGsHJluu4mqumUQFySBoTQBvagm0AalLfG5fXACEbfIoCUKGxLdcrWIyLRDCU/j4Dn1/KKXecyHow8xNg0X+mOE8OigReq201eY1yzZSUo96lNMelRlzCTvMSpSRnXCYR3xr67e3wboFg5/24TWMsm1ZMldomyuIJA8vhJgXDdd9qiRFFZ1pVaqRStLFlWE2rLanxAELU0ZIRODOm0QgUNox3B1NNcxEEyMYmYUlYX95rlFL/OYnbpmPaoZJAVpUhLFNfEgRw9nAPhc0Yx71LOUtgkwraZsQnbLjOemPZ6ZxHys/OkFr+Lu4OmM7CsPvzSwS5bcPcbVsxzU3cBDgNpCJB3raQ7ApEwpmohkHo8VwmGqCF8rSCOEBmc0WluyuaqW9TA2EgGcDp9Y0Mpezfc+1PLQ6gFRVKOU6zq3+jlCebwDVwfHugTOSZomZNZETJqQK7ni56d/uuAV3D0cHuvdbY6lgV2y5K7hfcP3P34JITrB7VTDelQx7E3Jm4idWZ+6DRDCY0zAZNpnMh7QjnpQzVtKewW9rQMe2NhlM2oJpUcLjxTwmLu44BV2hPo0H3r3pzm9uUegW5wTBHGDDFsIPSISuDrEFDG2CWiakLyOaWxXa/bhcwccVicn3PFWcTja2xz2tv1d9w9LA7vkxPFdn6qPZzEp0Q3x08oyTAocgmkdEQcNSlnqNmBvPOTohfO43c7bU72acHXKqXM7PLZyxDCw9AJPomA91GxlH1jg6jo2osd4+oWHcVZSNyFVHWOqsOvaCsHnnmp/hWLSwzqJUhatLKtxyXpU8dvb6/etsMvt6GKw7rbH/czSwC45cezUn+H5ZoJ1XaH59SJDCE8vKUi1YWxCRnmPcd5jUibUbcBkNCC/dAY7DvBGIrQlGsy4sLFHpjtN2Vh5Iin4xvD9i14iXyae4JMHG2zvb1I3IUI4XKtxjcZNJbNnznP9+YsUeRd/1bolDhrisCFvA/7v2acWvYS7isPRCvuqw4qlgV2y5K7iffdmM95jHBw1mud2zjLOeyjhmZiAF8arXBqvYr0kmcda9y6fw5Uh3klEYJFBy9r6EWeyHC07la6txFNZz6PZtyx0jUqILvFmQpK4IolrhHC004z6+ho7L1zg6v4mO4frHI2G7B6uM5pXEBw2ATv5Hy/0+u82XTrrdmmu+9vALsu0lpw4pNTMxITarjLB47xCsMbFrCSUFusEB3VIP2hZj0vObd0kW5myc/0ss6unWHnXZZAeIT0qMISyZS3s9GGl8IybmLOz0yyynuCLhzAIWgLVXZdSLd5L6nGGVI4gMITaUrWaajro1MFMyKgJeXEW4Dn5k2LfDE54WvHqet7bnbufWHqwS04cVXON/2R4kUCCQJC3cNQoWi/YzHIe6OUMghYtHYk2pIMZUb8g0IZ8NMC3CpxAJXVnZKVnKyl5fG2fi/0Jw9CzqkP+23M/sJD1DZN3MzbyuEPNOYkxAU0dYsoIU4dI5Yi0obaacR0zaSIOm5DrZcD14v42OrfDYmlv88/e500USwO75ETyv1z/KXbqmlnraJ2naGHchEg8m+mMi/0xp5PiOKsulSVJS5SyNAcD7CxBBC06NISqZSPJObV6SBo0PJjVPLEi2K8F70+++56v7Wv11/D8zJK3kqMyRQiPcxLbKloTMDsaMJtlTKqESRMxMSGlVRgnKFrBVXey9BTuBl44rGhve9zPLA3skhPL75c/zblUEqtOiFsIT9l2WqhJYNjoTYkDw9HeOqPtTUajFWbTTvBFqC5256xEK4uU3TyrlTTnfG/KmaRhK/ac0z2UXLmn6xKAcY7CCoxTtK3Ge4FzkqqMKcqEw+mAaRMxNQFToylaxcQo8hb+qv7Ne3q994IuAvvqf8tGgyVLkYbW7QAAIABJREFU3jY8vzz7c86kXbPA1CiOqoS9osdBkVGbrhD/aDrgc5cf5MWDTSazHuXBEG+7RFfYK9hYGREoi2k1QWBYiUtOJwWnY8NjA8EHom+9p6v6pP8cgZSMGsG1PGNnPCQvE/aO1ri+t8XBZIWjMmXchDROklvJyChGjeSocVj718+DdVgs5rbH/czSwC450dzM/4inx900gryVXC8SpiYgbwOKuehLaUJaK1HSUzQRk4Mh3klk3/z/7Z35j6XZWd8/Z3mXe2/dWnu6e5aefQY8yAsmYIidACKCkLAkBARkE4qEICF/AFL+hvxIJEhEkBKhLIogQXISBZwgxwsBgw3YZhbP1tN713bX933P8uSH81Z1G/d4ejxdVV3t85FeddfMvVXnHKm+/dznPM/3YfD4ddY29lkZLNA6MqgbhmXLStmyUbUMjPBYOeLc6LuPbU/PxqeotKKLsN1ari1WmDUDFl3FXjPk+nzM1JXMvaWNt6bszj3U+nQba78dby+wOUWQyRwpr4abPLkSmDjF5aVlt03ic2W+wl4zYNZV1IVjrVqyOZ6gTWT21lnclVVUFSmHS0IwOFdgbGA0XDCuGzaqhpENnB8o/uVTz7E2eOEYdqPQKM5UmvUSKhPpombp06Tcoq+S2OtKpl6z9JomKBY+1QRPfXjgKggg1cEG/Nc8MV9yZTJHy58t/jNXloZSg+2nyzbBMHEFN5rB4UXX2fVd1jf22LpwhcHmhOnFczSvn8HWHT4YJssh29ub+P71s65kv7O4CJ+4usoPV9+HNRtHuhdrNhlbw5lKeHTgGZpIGzW7zYDW36qatCrlHoMouqhoA+x0gT9TLx/p+k4K6SX2Ts9pJgts5lTw6ekOc5/GyRgl6eZdkidsFMX6aM7q2gStBF066meuE4Nmfn0TUzkeefgqg6Jjd7HCjb0N9pcDumgoTcQo2KqEzUrxI8OfOdJ9hDhnbDWViUy95srS8tai7C+zSqZdRRBNqSO1lsOxKU0QFsGz7y8d6fpOiiiBIO4Oz+mO1rPAZk4FX3a/Txdh4hRN1BgljGxgXDhq6wkh3cBvb2+x9+bDqIFi47mLALT7I1YfucH589fYWpkwrNrDFMHjw4ZHBp5aC1tlZKvSfGD400e2j3H1BFMfCaLY7TSvzoQbjWLuDUEUIuBismgMAj7emle1URQ8q77jyNZ2kiQnAvc1j5zyS67cyZU5FbTuMp9pX+fC8mHOVKl6YFR2aEAjiCj2J6ssXUm8cQb7ied56KMvMrg5ZXZjE9eWrJ7doRo0NPMh89kIoyOV9RgdeWkyYuLSJNuR1CjskeQ6P6K/l5HVrJcdhTbsdyldsd1ZalMyLhxNMHQhxT5Wg4nJWWzu79zt9CAQJd4xWg1yuvebI9jMqeFCfJgPb5TUJlL2U1gj0ATL0pV0weJD6u+/fuUc/maNGbbs766xd3OTdjpEQnKmAjAqUujA0Ph+6kGqUX3faIV/vPkLR7KHz/EHGAVj67kwXPLkSuRsfSvfGkXRxdTlZVTyxTUqeRdE4CV/uqfHvj0RkXDH5zSTI9jMqUErxfOrS96a12xVkUJFumjYbmoKHRj0k2bTa4XFxXPUZ3dZLAfsLUeUZcdobYqRQBTFvK1x0VBZz/m6Ze41TdBMnPDZ7jW0GhFlfk/30IY0rSACXhSbZcBLinSMStYmqr/giv0T+oGA0+Bo3c17up77hZSD/doINp5ygc0RbObU8HuLf82/e0NxtdEsvWURLFNXMHGWr0xWeWO6xm47oAuWYb2kmY5QJnDmzDaboylKp1SCMoHCpl9mHzVGRVbLlkcGHYUGF+EZucBDw/ff8z0M7DpDC3NvubasWARNoVM+uTaBSkcqHSl0qpZwEbqYLrmWdIic7pzk2yFEorivfU55SVoW2Myp4qJ5k0knNEGz35UsQrrwavqP1Rqh9ZbtyRrBG2JbsHb+Jg8/dpkYNLs3tljORhgTWB/N2BjOqa3HaKEygdoIhU7G3I/H5/i5rV+6p+v/oHyYFSt9fatm7jUhKmoTWCkctfGMrKfu0xgi6ZJLgBElSpl7up77BZFwZ4E95f+gZIHNnCrenP9fbjrHnjPsO8My6MOP0UYJD43mDArHfjvg2rWztHtjBg/fZPzwTdq24rXr57l+8wz7k1WAQxPrUdGxWTWsF4H1UnG2VnxgtMrQwi+e/SUG5ePvee1aj5lIg1awCBqlYGAiQxsYFx1D66ispzaeUqdJuEZDZWBgFDNa1ur7Z+z4vSQJrP+a57TnYLPAZk4VIg0/dSEwdYqbraYLmmUfCSolPHn+Mo+duQ7Axb1Nrr/xKG5vBbs6Z/PsTRTC67tbtL1pTIwaHwxGRUoTGNjIyAprReShWmgDbLfCjw1+hLp87D2tfVSeZ1XV7LSKqUsdWis2MjABa1JFw6joGBYdI+sY28DIRqyCSiseL8bMugezDlYQROIdn9NMFtjMqeNzOwOaAAsPU6/Y6wwhwsyl4YDrm7usVUsmXcWV7TPsvfkwZqVluDGhtCkiWulHZXd9BUJEEaJmvXCcqVJVQamF2qRb/H0fOFd+63ta9wvqe9gsCoQUcVtFaigwnto4hmVLXXbU1lPoSG0CAxOpTYpkC6XwYfcenOD9x9unCHIONpM5Vv7NjV9l5oS9LtKEg84uuLSwvH79HMvFkNXBAoCFK7ly9Rw3//BbWGyvMSxbxmVLVXZIX0ngo0ZEYXRkYD1bVcfIBoYmMrTCyCpGxvBIePQ9mcJM9BQXUwdapYW10jMuHCtlhzWR0nh036VWmkBpAoUWCp3eUxqFekALf4SIiL/jc5rJAps5dQjC1AcqrXh+7Hhy1LFaRJwoXpmss7e3RogaqyNRFDdmq7zx5uM0ywEPbewwKlv2p2MWy0GaWKsjhfGY2wbsHZRIHUSxtVFsmgEfMx/+hvOxV+LLLEJgGVIZllW3SrIq6yisR/VNE0qlP29npwsMq/tj7Pi9JyL4Ozx3l4NVSv1NpdSLSqlXlFK/fMSLvWuywGZOIYHrcc5qqdiqOv7qhdfZLD1GwdIb9uYrjAZLHl9LH6cbb7kxG7NcDDj79EWefeINlq7k8v4GRkXG9ZKyL9taesvc28NOqiYohHTRNDSaIMJPrvzoN7Tq/eVf0EigDeBE4Xsv6SDpZ4koBEWkHyUjqYV26VML7WZp8HH5Hs7tPkbi2z/vgEqlFb8C/DDwAvCzSqnjsEZ7R7LAZk4ll/RrfGm24OKiZmc+pu5LrJykKQHnLlzm8UfThdAbszE7zYDrextIMKw/dZnCBN6ajZm2NVanKCldcvlU9K+Foo8uFbBawEO1YmQ1O13g74z/KdZsvas1F/YMu2qC76flLkOq5106y7ytWHQVyy55285dycQVdCGJ7aDPDJyv7gvduOfIe4tgvwt4RUReFZEO+A/Ajx/pgu+SBzOhk3ngubr4Q35w40O8OoUg5xmaeBgtXFuMuPLmo6yuTdhpBrw8LahN4OZ8hS/+yfvZWttLrbVR0wSLCxYXDBFFbT2lCcRgCKTIsdLCwArrWhgYjVaGG63nu8sfRxA+tfy3d7VmrS0GixdB9y2wLmrmvsB0ctiF1gZ72C5rtVAaRRNTNPRUeII3juZIT5IbqVX2TmbiEeAhpdQf3fYff01Efu22rx8FLt729VvAR+79Mt89WWAzpxKRjveteV6fW16ZKs7WltoIc695cX+FuXuWh+olc2+5MPSH3gVXp6tcna4ysI4nxlNWy4alK1m6gkIHpLdA3OssPqaP66aPZEcmEqJiZFOZlRNDI57nRz/KS/PfeYcVGx4rPshKHCAi+JgqCbSSVO96W/7XRXOYQ9ZKUyih1uCMwqgH8kPnx1MrhQC3i6zQC+zPi8jXm7J+J2W+L4Z5ZYHNnFp++bVf46ODn2OsS4yybFWpkwvglWnF1abkwrDhW9YmzPrxMrX1aXKAiTzx0GXKsmN7b4PWW7pgabzFKKE2kSWaKLfyaLcuvmCz0tS+YOI0ZTzH06NfYGg0/3X2m4S/NPW1Lh9jo3iCrbjFii4YWUOhU5PBQZlWaQKlDYS+dVerlKIodSSKxupk/qLvqCWnGxEJKY0agds71ZLgisSvJ66QItYLt339GHD53q7yGyMLbOYUI3ym+U98rP4ZdjoFGEZWMS6ENiguLRQPVYbz4wkuGN6arBNRrJYNSgmjlTnjrT3qQUO49Chv7m3QRcO4cKyXLRNXEmKF1YJVgo+KIIrKpF98qxSVtuz3NodtFP7W8GfZD44XxjWfnt1kV9/gmfAUPgprpmS9MGxWcKYKrBWegfUMCk9t/WEuuLYeFw1t1EDyiV0GRRPSXfuDSbSAvxXFHkavz93Fm/8QeE4p9RRwCfgZ4O8f0ULfFVlgM6eaKHO+pD/Pw/FppN1EY1kvoTZCFxVTbxiULWdXZvhoeHV/HYDNwYLt7U2UjixmIyAJW/Qqtawaz1rVUOoVpt7ShOQdYJSgURgrCAqtYKXQaJU8A5YBxkFzvYk8bTaBTYa1wijFwMCKFVbLyFqRLtSG1lEbl6wTTUArwQeNVfEwNREE2gATF1mzFmu28GH7pI78SPjaKPauo1dExCul/jnwP/s3/7qIfPFIF3yXZIHNnHq2F1/k/fW3MxHHFjblLG1kZBXrhUdEsbq1x7m24vX9dXbbilHRMW0GhGtnD4v7B9ahFNQm/QlwZrBANwNESiZOIf3Fk48KRUoXjIvkfgUctsBOXPoGtUlm2UZBoYSRFUYm9kINSqWnsL4fg3MrBZAmHKhkKq6S0F71c/rI7gHk9ij2rqNXAETk48DHj2hh3zBZYDOnHpGGl80rNDLlGb6bIAovivODlq2qYWc+ZmN/zPkLl/kIcPHmQwTRh51cw7KlLjoq6whR0/YTXrUSKqtY+oKpS1MUIsnhymphs0qXXqVJ+dIIjGxy46r6xG3ZpxSLvtus0sncZaVwlCagkTRHrG8siFHjYqpoEFG9F2xfXRAjAwq0qk7imI+cW1Fs4G6j1/udLLCZB4K3Zv+HDw1/lhutJ2I5W2seGaTi/f2m5vVLj/IkcPaRawzqhreunwNgczzBmkBRJFu8EAxd72mwdCUxGFaKFkg3/lNnGfV+BkHUYXVCFzVtVKlcTClKrdBKKHWKVMu+jKzQkZXCMbKub4UNd4hcNXNXsOhLxyIpgh0ajVEFP1n/BL+5+6+O6WSPm2hBeZC7jl7vZ7LAZh4YvrD8LS4O3sdfc9/NuNBcb/rKARPoguHm9iZl2bG6tcfZruTyzhn25ysMyxZrA1oHtE7pgqJw+GiYtxVLn0q4Hh7OOdd/bPeiD826I6l6IYjuR9gYumAOI8+yN24xuq8asMncperTAgcYHXFAiKqv0dV0QRF7Y5iBSTngJ0fAg+n5giR/wgemVCILbOaBQaRhv32dp89+DwdlkItgWC07umDZX47QV8+xtjqhqlrOre+wbGomy2HKwdYNztvDgvfSOsZ1g4umTw8oVooO3Yti4y1dMKnrS4fkaaADS18wdyUu6jRWHKhNqhYodG/iYjxlXzmQUgGaEDVB9GFtrIuKRd/JJcDIgg6KS4vkLRvj9AROOfNuyAKbeaDwYRerYWQjA5s+vt9salb7FEDR1hRLx8pozng8o+tKRBTOW6y3xJiSpkpFrPVsVC1KCfO2pgvp/1kdsCYwqhp8MPhgkmmMSXWsinRhtqoDc5e+vzWRUnsKE7E6UFrPsGop+jlibVux141wITUY1CawVgTaoFN5Vj+62yjY6yKlXaPpssDe7yiRu6+rU0rJVxcCZzL3Jx8Y/jR/Y22Lx0eOkU31pg+Ppmyt7lMWLkWNsR+NbcKtQYNRo3UkBEPTpsskYyLeG5auxAdDVThK4ykKh9bx0OowimK+HDJtBr3loO8n3R78nIhREWsCg6JjOFgepibatuLK7hbX5itUOhlw77cV223FvjNMnGa3hamPNCHyOb7Atfln3+MpBeTO/amZe0SOYDMPJJfVK3xqr8LLmBfWAudGM7ZW95kth+zvDFgfLhhWLXXVMFqZo02kbSqCNxgbiL0oFoVHqYj3liq0xHirVdWaQFl2FKXDmDSptiodddnhvcFHQxRFafzh6w9aYsuyoyw7gD7n6ymNx0fNbluxWnaUOrBauBS9RsXCKPYdFFrznH+Ba7xXgc0cNVlgMw8kN+efoxwNeXL5fr51VVFZR9NWXNzfYOYKfDScU5HhYEkIBucKmmUNQNeVaB2pqpZ60KC04LqCGDXBG0Iwh5GuLTxFmdIP0Rts4RgCzlmiKKy+VVJ1EK0epBO0iUjsrQmjoguWRd/UoF3BauFQfdvuwEY20XjR7HWR3/ihP+fZ3z72Y828S7LAZh5YGpngRJh7w6QZpPbTPo/aBcO0HWBngbIrMDoe5lJDsMSoqAcN9XhO8DaVUgVNsJrFbHTrIqzqsFVHdIbgK7o25VwHwyXGeiRqlosBMWqMSVUKxnhs6YjBgIbgDW1XohHODhZMuoplSK2ylY6ICQz7yPlMpXFR8/2/u3Ji55q5e7LAZh5Y9ppXeaX+Vs7OzlCaNUbW949jWKSP54uuYt7WVDZFoQeTBDbWJgxW5ujCo7SgTUD6CDYGw87ORsrBWs9wa5/QFugiYOYDXFtirKesW6K3xKiJIQ1lLKsOYwOmdLhlhfcWLAzqljU/B1Kt7HYzIIhKLbQ61du2USXrRKN4JjzFv/iWf8IvvvjrJ3a+mXcmC2zmgSXGKa/FP+bC4gdYL0seHcC4cBgd+1KoyKKr2G9rauMZlh3DskUrIUZFUXdEZ3FtiW9LfB/Juq7EWs/m5i5rj1/FjBrCvD4c9VL07bmhK9AmUtUtMWi0idiqw1iPNikXa4LDtyUSFYO6Sd1lrqQJhkJHgiRhPrQ11MJmJZx3Fb9z6UFtmX1wyAKbeaCZNi/zcV7jUvwpfv6xIS9NxgxNZKPsKHTExdQc0AWTbv29RSvBeUs3TznZtqlxXYFzBc5bnCvY3Nxl/Ykr2DNT4rw8/Hm2dCgdkX6QolKC0pF4UMpVt5jSgSiUDfimJPT5Xa1TTnitq5i78vAfgSYkC8VKC12vqUOrmDhhbfAC+8svncDJZu6GLLCZBx7B84Xlf+FX3/q7PKbWOVsXnK0tlRZKI4xtQKxntxmwqeDMSmqf9S5FoKP1CcFZJGi8K5hOxkhUSDDEaY30FQdKCdhwGMECaBNACbGPfu2wQZnUaisHOV9n0U2FsYHgDWujGaVNYt8FC02qwY1yy3BbASNreKH7Tj5DFtj7lSywmW8KRDr+dPEfuTH6KD/Eh7iyTJMJtqpIoTSlTuNjWm9pfUEdW5wrqG1DMWgZbO0nQXWGarSknQ9Y7qwSvU6iaSN22BxWBUgwKXdbdigtSFQoLajCow68DPoI2RSeqm5TJ1dfpaBVpOqbEAbWHXZ4zb2hNpGHas1aAd+xWfO5i+fp/NUTO9vM2/NAzp/IZN6ORdyli8LlpuPFacvVpWYRNEPrWa8axn131mwxpFnW6ZmM6KZDojPQX4KVw4bQpfhERENU6Mph+gdAmYAuPWhBl0lYdZkuzQ4QUWgTKYdNyg3riDGpU8yavuOr7Niol71/bKDWwshGVsvInjP8o/W/dyJnmXlncgSb+aZif/klfkcc0+ZlSnueN5bfzne6pxjbipFNBi++n4mllBx2e5m+mkC8OWxCsHVH6Ir0jQcdxcoMdMq5qsITFjWxs0hfGqYLj/SXW+iYxLcnBo0pHRWgTaRZ1nS9RSIkIS50sjmceUOIaYTM2AZWx8DNgykAmfuJHMFmvumYNi8D0PmrXPMvcaVr+fKk4M35CpO2Yr+pmXUV+8sRi+UA7wq6xYDQFgRvDnOnANFZOOg21YKuPGoUMGtLdOVSdKsFXTmUDYcpBCBFw97QLSvavsnh9uhW63j4c5LRd7I8rLRg+gkKySA88m3Dnzj6g8u8a3IEm/mmZt5+hVdXLrCcX6ANq+x062xVnqEJnKmXFMYzaEtiHLOcDyiqDmvDVwlhaEt06SBoYmvRpUOPI5YZcV6iioCygbgsoY+IlRaE1GTg25LgLaFLLblwqx73UMhJNbGpLjaNVel6sZ64gi1ZP9Zzy9wdWWAz3/S8Nfsky+EHuOo2uL79LGerkgsjYWA9q8EyXYwOzVtWxzNi2aFt6saS2PvDLmv0tPcciAv0wKFMxKw2qIMqLt0hnYGoUKXHFJ56fUYMBuv611tP15UUhUsNCtGkKbMIhUniehADT52mNoJWUDyY47xPPVlgMxkC24vPI8MPsCePsmw8y1AxMENG1mF1YFgm28IDG0OiQmK6oErdXSXapo/5sUuNA7pyFKtz9LADK6iiz796lf6uoXrkJqrwdLtjYtC4ZUVReIK3OG9pu+Sb0HhLF23vTRBwsaQJIKh+tHg2xbofyQKbyfScU0+zwYCL6ga7XlNPzlGbMaOiY1B2h2NlkqhatA8UwxnKmsO62NAV+K5Am4CtUzuu9QZV+Fu5WiVJcHVEFZFibUa7s8psdw3vUiOD7+0SF11FEE0XLftthRdFGwxNUMw9zLzQBnhTXTupY8t8HbLAZjIACF+e/xZvVs+glabQQ1zXMZo+zma5ShCN1f3YF5/aaUNXgBLsoCE6S2gqXFMSvcUMPdFZYlsQTQBnic6iTUAVvp8om3xpY1scVia0bcV0kcaIHzQadMGwdJY2appgmHvDbqdogjDxnhtMWehsvn0/kgU2k7mNefuVw79P7WW24iaKFT4YNXNXMio6zjU1VdVSlY4YNNXK4vBSSkJqkXVtSrya0qVKAy3EtkC0xZCGUouz+EWNOIutO6q6wTvLbDFk3ta4aFj6gsZb5r5g7i0hKmbOsNcJglBrzUvuMywWr5/IeWW+PllgM5m3wYd93qovcnmpeWvxDM+vrrNRBp5uBjy2ukddOJZNxZq3VMNlShF4kyoB2jK1yQKVs+jCH9a6KmdRURGaKjUwBJPcukTjXKqrTYINPug+JWDoQppc6/oChkIpvuuhyIvX389L7esndEqZr0cW2EzmbRDpuDj7BAAX1Wf4C/463z94mvMDw6IrKUzAuYLpdAXves/YqFPtK2ALR+ginRKMN8lBS1LqQAOhK/ryrAJlAs5ZfDAIqTIhHpjF9E5aEVgGTRMUQdI029fnlk51J3dIma9LFthM5i6IMue1+f8iqO/jwvJZ1ss0XXahK2wzYLDsKIwnRE1VdhT2VpfWQepAF2magS58aqPtS72UktTAEHVqke2HKuqDibV97evQRLqoWHiDUQoXhRsNPBke42r5GE331gmeUOZOZIHNZN4FCsPlhWG9GBKiotARayJLVzAsO4xOpVgiGhF3+L4oikKS6BaA0hFdOiwNMQwh2uRBYP1hB5fRQv+Ww0i21EJthPVSsdcHriNTMFRbWWDvQ3J1ciZzlwgeT8vMC3Ov2W5r9l3JpCuZuYppW9O4knlbM29qmrbCOUvXlvguVQrEoPFdgUSN7ku3JGq6Lhl6h963wPQiqxQYLWjSL6tRwtBGRhYKDS4KXYx8Bx850bPJ3JkcwWYyd4nC8mx4hlbDxYXloUpztoZOCXNXMLSWkXV911dgXCWxPJgea2wadBgP/AVCcuc6QCTlXvVtbbipPTaNBTcqCe1BS0GhFE4irQRu6B3AAOEYTiJzt2SBzWTuFqXZUwuUUzTRAgarLbWJFFowUWOjoQsGoyODwh2KJiTfgY6S2iZD7uhuOW0ZHfExXWoZ44Hqq3606cfG6ANfGYSIoosRh6eQEmvW8WH7GA8k807kFEEmc5eIdEzUHlMa5sFxaRF4c2642Vq6vlGgC4YupsmvIWp8TAIagiGEA/9YhXiDX9S4ZUXwvTm3SW241gTK/sIsSKqrNUoodcTqJOZWQ22g1JoCSykFg2LzxM4mc2dyBJvJvAteW/we8+GHeTI+Ty2WZRCmTqEwlMZSKCGIohTFznKACISoqYsOrSPeWVgMkuWhCYTulufrAQc+tLpPH1gTIUBpArUogqRpDF00DI2mi4aFwIo5y5SXT+JYMm9DFthM5l0g0nF98XmerJ9nZFK5VBTwESbOMDARq6CLmrkvMJ0QReGCwZiID4Za2sO6WRGFLVKpQPCGGNPIGN+7aNUmjY0RsVRAMAofNZ1OTlqlVhilQEDlD6T3HVlgM5l3iUjDy+oLDN13UpsKq5NfaxM0TdDUJjIwERMMoa2Sl4BPk2PrsqNtK6IorAkM6uaW52s0hKDxwWB1QJVCDczbmi6mPG0R02WXUUJtIloZKq0xURNwX3/hmWMnC2wm8w2ws/gCfzIILJoP861qjCk5jGSbYOiMprORsQ2HXVi6FbpgqAtHYUKKXr29NYFWR4yJ6JBKtKxKFQGF8dRR4aIhklIEQRQKKPugtaJgnXNkT637iyywmcw3yN7yz3ltNGSt+RBOLBulSh/be0F1UbEIGqNMEsX+4gvSRZdT6QKssB5jAmXhUCr01QJy2FwwKFKZV+zSZZeiz9OKptBQasWKtryq9k/oJDJvR07aZDLvgevz/8dn4+8TBbZboQmKSktKESihCZqJM0ydpQmGJliaUNB6i4+GLvT+A6L7IYc6pQ9s6uo6QKs00cCqSGkClZZUGtbfj0XgW+JzlPb8yRxE5o5kgc1k3iOT5kU+3vwer7Uz9jqYe0UbNG1vzDL3hnnQTJxlEdJ0giYU+HCrlKvpO7liVBTWUxYdZeEwJhAkvS5Kajgo+qfU8bAu1ihFoTQfLX7kZA8j81XkFEEmcw+YNC/y5ugMoXkKH1dZKxVWw6IPQofWMDBCoQtGfWSqFL37lkLrQF21aC3EfpihMRFc6uZSfdrAqGT+UpnAzBsKJRQazpiUbrjSCFqNiDI/kXPIfDVZYDOZe8SV+adphzNM90EelREKxdR7GgmsmYLN0lBpy1pp2KiWGB1p+imyo76a4EBcre2dauHjAAAIZklEQVQvuHoxDr0FYhRFFww6pI+fXhQDA5VJF2z70mDNmM5ngb0fyCmCTOaeIews/pQ9vc9N1zH1nn1pWNAyC54mCFOfBHLhSkJMs7aCaDp3q5qgqlts4YgxXYxpncZ1+2gQSeVaXdQsgj5MEbQBBDhrhrmj6z4iC2wmc08RLvovsKdm7EtDqxwVBZU2LEJkp4VLy5J9V7JwBSEqXN9me1BhEEMS1YNLLucKWp9ytupgbuLtJjHAMghjK5ytDUO9caw7zrw9OUWQydxjFu3rXBudx6iCDTkL1EQRolIEEZZesd+lmV3rZRqgeGBPCNA0afz3wYQE5y2tL3C9r0E8iHR18oddsYrVQnGm9ihlME1x/JvO3JEssJnMEXBt/lkK+xBFXUEELyMGoaDSJV40LiaXrS4YSmNoXIkxkRg1u7MxIoph2QLgoyFEdZgm6IIhRI0ThVYwtMnG0MXUgPBjo2/j17tXsgH3fUBOEWQyR4TzN3hj9r/ZVddZqpYJS6LQ168mU5guGoJojI60XcGlnS2uTFfZbwcsuoqlK3HBoFS66HJR0wSbxJUU8boIU6/Y7zQTBy9PHQ+Vz5/w7jOQI9hM5ogJXJ5/kutmg6frjwFr/dDC5P06so7aODpvuTFf4dJihO0Nu4Noeg2l9RYXdYpe5attXVLkmlIHimTInXrJMidNjmAzmWPAh13e8n9GFyOFhiDJO3buC64vR3zx5lm+Mh2z9IZSR4Jo/G2XX7GfYxBRSWj7KoImKLp4IKrp+2ql+B7zwsltNnNIjmAzmWPEiaARnCh2Osv1pqCJijYoVqywVvaVA73ZtopJiJfO4voUQRc1bVR9lxjMvTCyyTZx7oU2Bj7VfuKEd5qBLLCZzLGyEMfUF3gxaAVNSC5cB/Ws1W3zuELUKJID1yJYZq4gyIGQauZeMelSMqALqTNs6gMNjnV7IZtv3wdkgc1kjgmrKl7TrzCav4+1whIkienIakb9b6LqL78OCKJZ+oL9rmTmdT+3CyZO0/TzDTUpMnYB9mPDXDVcb//imHeXuRNZYDOZY2LSvAg1XDRnWHQbWBSFSlMRxoViYCNVP3cr9CVckJyylBIqLb2JDMw9GAVnBymi3e2EK13DNX2dPblM6y6f7GYzQBbYTOZYmTZf4VINhf4QI6lRonCxHytz4EPQz+SaxhKt0v/TJKG1Wph6jQLWCmGjikyd5uWp52X9Ja4vPo9Ic5JbzNxGFthM5hgRPJPmJfZXLlCG81SkVEEXoYuKNuo+z5psDpuoMApqHdHQT5cVlFUYDdutYbtNJi/LuJvF9T4jC2wmc+wI03iDszzMyBSMrGaQsgHcbAqUgkpH2qjZblOp1mapiEATFCIpym2DYreDnS7QKkehhie3pcwdyQKbyRwz4/o5NtVjjKSkUIpCp0aBhU8NCEMrGKUYmghVimznXjH1Kd86tFAooQkw9/HwskypXNZ+v5EFNpM5ZjbtEwzjyuHXUVKDgJDKtVxU+KjYLD21idxoLdutZuaFykAQRW2SKCsUTiKOji7MTm5TmTuSBTaTOUYUlkIqRlJTa4vp/QcPRNbHJLQuagY2TSyYOM1OF9JkWqUBOYx6BUGj0Gisrk9ya5k7kAU2kzlGzo8+wnrcYKhKKq2pDBQ6Ra5RwAtMneCiIFjOVJEoqc51ET0ilrE1dKGvfY1CRCikoNIr77yAzLGSkzaZzDHx02v/jHPyOGf0iKE22D56NQpKfaubKwosQuDSInJpofmNvf/BJ/3vckPv4OSWjUsbIIgQRbhhrvITKx86mY1l3pYssJnMMfAPNn6JPwhfYYsV1gtDbTSFhoFRVOZWi2wUsAqsUmz7lt9efJp5+xUW3SVmah8v8VZNrAIvwj4LWpnxK9d+5UT3mPlacoogkzlixvVzfMq9wuPhMcY25V1HNkWutUlpASeK/Q66eFARoJioOXN/AwCjR6zIGo5IGwUv0MXIVFp2zDY35p8/yS1m3oYssJnMEXPOPM9KXKVSqdi1i0JlFLVJaYHWp4utoYURySHrStcx0xOcnwJgzYBKaiplmIdARJhJyyXzJteaLyLSneAOM29HThFkMkfMK/OPY8XgJaYcqsDCH9SxwswJLsJWJZyrI4Lwqn6ZnXgRpVIMVOgBAykJEtmTJRfVVbb1NleXf4bro9zM/UeOYDOZI0f4o+W/Z1Q9w0fVD7BZGoxKl1RA36ElzH2Kas9Uiqt7f0yUef9+xQfUx2hxzNSCPb3NjnsDoyw+bJ/UpjJ3QRbYTOYYKO15njF/hY3CYhQsvTD1gdpoFIouRt6cK/Z9x6fcf/sqcV0bvI9L5jJaNDO22W/fym5Zp4QssJnMEaOwnKtf4MPVGUqdIlcnwkXZ4cm4RRsD+9LQKsdfhE/+pY/8Qq1X2fGvM23fyGYup4wssJnMESMI75fnKDSsWMFqRWk0/735A74cpqxWj+NkQYzxjqO2r80/ewKrztwLlIi886sOXqyUgDnC5WQyDyZajfjB4T8kilBpTRDh4/NfPeFVBURuG5+QuefkCDaTOQaizPkCf85+uMRi8fpJLydzTOQyrUzmmPje4oO4MH/nF2YeGLLAZjLHxEvtHs9WHzvpZWSOkSywmcwx8Yp8ji/Pf4tnR3/7pJeSOSbyJVcm801LvuQ6anIEm8lkMkdEFthMJpM5IrLAZjKZzBGRBTaTyWSOiCywmUwmc0Rkgc1kMpkjIgtsJpPJHBFZYDOZTOaIeLdmLzchvHEkK8lkMsfNEye9gAedd9XJlclkMpm7J6cIMplM5ojIApvJZDJHRBbYTCaTOSKywGYymcwRkQU2k8lkjogssJlMJnNEZIHNZDKZIyILbCaTyRwRWWAzmUzmiPj/CZhcyaSw1HcAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "titles = ['Vx']\n", - "var_full2plot = gf.vx\n", - "var_full2plot.mask = dems_mask\n", - "clim = malib.calcperc(var_full2plot, (2,98))\n", - "plot_array(var_full2plot, clim, titles, 'inferno', 'vx', fn='vx.png')\n", - "\n", - "titles = ['Vy']\n", - "var_full2plot = gf.vy\n", - "var_full2plot.mask = dems_mask\n", - "clim = malib.calcperc(var_full2plot, (2,98))\n", - "plot_array(var_full2plot, clim, titles, 'inferno', 'vy', fn='vy.png')\n", - "\n", - "titles = ['Ice thickness']\n", - "var_full2plot = gf.H\n", - "var_full2plot.mask = dems_mask\n", - "clim = malib.calcperc(var_full2plot, (2,98))\n", - "plot_array(var_full2plot, clim, titles, 'inferno', 'H', fn='ice_thickness.png')" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "56.06334222158319\n", - "Mass is conserved? True\n", - "-1.3789596557617188\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "def emergence_pixels(vel_x_raw, vel_y_raw, icethickness_raw, xres, yres, \n", - " vel_min=0, max_velocity=600, vel_depth_avg_factor=0.8, option_border=1,\n", - " positive_is_east=True, positive_is_north=True, constant_icethickness=False):\n", - " \"\"\" Compute the emergence velocity using an ice flux approach\n", - " \"\"\"\n", - " # Modify vel_y by multiplying velocity by -1 such that matrix operations agree with flow direction\n", - " # Specifically, a negative y velocity means the pixel is flowing south.\n", - " # However, if you were to subtract that value from the rows, it would head north in the matrix.\n", - " # This is due to the fact that the number of rows start at 0 at the top.\n", - " # Therefore, multipylying by -1 aligns the matrix operations with the flow direction\n", - " if positive_is_north:\n", - " vel_y = -1*vel_y_raw * vel_depth_avg_factor\n", - " else:\n", - " vel_y = vel_y_raw * vel_depth_avg_factor\n", - " if positive_is_east:\n", - " vel_x = vel_x_raw * vel_depth_avg_factor\n", - " else:\n", - " vel_x = -1*vel_x_raw * vel_depth_avg_factor\n", - " vel_total = (vel_y**2 + vel_x**2)**0.5\n", - " # Ice thickness\n", - " icethickness = icethickness_raw.copy()\n", - " if constant_icethickness:\n", - " icethickness[:,:] = 1\n", - " print(icethickness.mean())\n", - " # Compute the initial volume\n", - " volume_initial = icethickness * (xres * yres)\n", - " pix_maxres = xres\n", - " if yres > pix_maxres:\n", - " pix_maxres = yres\n", - " # Quality control options:\n", - " # Apply a border based on the max specified velocity to prevent errors associated with pixels going out of bounds\n", - " if option_border == 1:\n", - " border = int(max_velocity / pix_maxres)\n", - " for r in range(vel_x.shape[0]):\n", - " for c in range(vel_x.shape[1]):\n", - " if (r < border) | (r >= vel_x.shape[0] - border) | (c < border) | (c >= vel_x.shape[1] - border):\n", - " vel_x[r,c] = 0\n", - " vel_y[r,c] = 0\n", - " # Minimum/maximum velocity bounds\n", - " vel_x[vel_total < vel_min] = 0\n", - " vel_y[vel_total < vel_min] = 0\n", - " vel_x[vel_total > max_velocity] = 0\n", - " vel_y[vel_total > max_velocity] = 0\n", - "# # Remove clusters of high velocity on stagnant portions of glaciers due to feature tracking of ice cliffs and ponds\n", - "# if option_stagnantbands == 1:\n", - "# vel_x[bands <= stagnant_band] = 0\n", - "# vel_y[bands <= stagnant_band] = 0 \n", - " # Compute displacement in units of pixels\n", - " vel_x_pix = vel_x / xres\n", - " vel_y_pix = vel_y / yres\n", - " # Compute the displacement and fraction of pixels moved for all columns (x-axis)\n", - " # col_x1 is the number of columns to the closest pixel receiving ice [ex. 2.6 returns 2, -2.6 returns -2]\n", - " # int() automatically rounds towards zero\n", - " col_x1 = vel_x_pix.astype(int)\n", - " # col_x2 is the number of columns to the further pixel receiving ice [ex. 2.6 returns 3, -2.6 returns -3]\n", - " # np.sign() returns a value of 1 or -1, so it's adding 1 pixel away from zero\n", - " col_x2 = (vel_x_pix + np.sign(vel_x_pix)).astype(int)\n", - " # rem_x2 is the fraction of the pixel that remains in the further pixel (col_x2) [ex. 2.6 returns 0.6, -2.6 returns 0.6]\n", - " # np.sign() returns a value of 1 or -1, so multiplying by that ensures you have a positive value\n", - " # then when you take the remainder using \"% 1\", you obtain the desired fraction\n", - " rem_x2 = np.multiply(np.sign(vel_x_pix), vel_x_pix) % 1\n", - " # rem_x1 is the fraction of the pixel that remains in the closer pixel (col_x1) [ex. 2.6 returns 0.4, -2.6 returns 0.4]\n", - " rem_x1 = 1 - rem_x2\n", - " # Repeat the displacement and fraction computations for all rows (y-axis)\n", - " row_y1 = vel_y_pix.astype(int)\n", - " row_y2 = (vel_y_pix + np.sign(vel_y_pix)).astype(int)\n", - " rem_y2 = np.multiply(np.sign(vel_y_pix), vel_y_pix) % 1\n", - " rem_y1 = 1 - rem_y2\n", - " # Compute the mass flux for each pixel\n", - " volume_final = np.zeros(volume_initial.shape)\n", - " for r in range(vel_x.shape[0]):\n", - " for c in range(vel_x.shape[1]):\n", - " volume_final[r+row_y1[r,c], c+col_x1[r,c]] = (\n", - " volume_final[r+row_y1[r,c], c+col_x1[r,c]] + rem_y1[r,c]*rem_x1[r,c]*volume_initial[r,c]\n", - " )\n", - " volume_final[r+row_y2[r,c], c+col_x1[r,c]] = (\n", - " volume_final[r+row_y2[r,c], c+col_x1[r,c]] + rem_y2[r,c]*rem_x1[r,c]*volume_initial[r,c]\n", - " )\n", - " volume_final[r+row_y1[r,c], c+col_x2[r,c]] = (\n", - " volume_final[r+row_y1[r,c], c+col_x2[r,c]] + rem_y1[r,c]*rem_x2[r,c]*volume_initial[r,c]\n", - " )\n", - " volume_final[r+row_y2[r,c], c+col_x2[r,c]] = (\n", - " volume_final[r+row_y2[r,c], c+col_x2[r,c]] + rem_y2[r,c]*rem_x2[r,c]*volume_initial[r,c]\n", - " )\n", - " # Check that mass is conserved (threshold = 0.1 m x pixel_size**2)\n", - " print('Mass is conserved?', (volume_final.sum() - volume_initial.sum()) < 0.1 * (xres * yres))\n", - " print(volume_final.sum() - volume_initial.sum())\n", - " # Final ice thickness\n", - " icethickness_final = volume_final / (xres * yres)\n", - " # Emergence velocity\n", - " emergence_velocity = icethickness_final - icethickness\n", - " return emergence_velocity\n", - "\n", - "# Emergence computation\n", - "gf.emvel = emergence_pixels(gf.vx, gf.vy, gf.H, gf.res[0], gf.res[1], positive_is_east=False, \n", - " positive_is_north=False, constant_icethickness=False)\n", - "\n", - "titles = ['Emergence Velocity']\n", - "var_full2plot = gf.emvel\n", - "var_full2plot.mask = dems_mask\n", - "clim = malib.calcperc(var_full2plot, (2,98))\n", - "plot_array(var_full2plot, clim, titles, 'inferno', 'emvel', fn='emergence_velocity.png')" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2\n" - ] - } - ], - "source": [ - "#RGI uses 50 m bins\n", - "def hist_plot_wemvel(gf, outdir, bin_width=50.0, dz_clim=(-2.0, 2.0)):\n", - " #print(\"Generating histograms\")\n", - " #Create bins for full range of input data and specified bin width\n", - "\n", - " #NOTE: these counts/areas are for valid pixels only\n", - " #Not necessarily a true representation of actual glacier hypsometry\n", - " #Need a void-filled DEM for this\n", - "\n", - " z_bin_edges, z_bin_centers = malib.get_bins(gf.z1, bin_width)\n", - " #Need to compress here, otherwise histogram uses masked values!\n", - " z1_bin_counts, z1_bin_edges = np.histogram(gf.z1.compressed(), bins=z_bin_edges)\n", - " z1_bin_areas = z1_bin_counts * gf.res[0] * gf.res[1] / 1E6\n", - " #RGI standard is integer thousandths of glaciers total area\n", - " #Should check to make sure sum of bin areas equals total area\n", - " #z1_bin_areas_perc = 100. * z1_bin_areas / np.sum(z1_bin_areas)\n", - " z1_bin_areas_perc = 100. * (z1_bin_areas / gf.glac_area_km2)\n", - "\n", - " #If we only have one elevation grid with dhdt\n", - " if gf.z2 is not None:\n", - " z2_bin_counts, z2_bin_edges = np.histogram(gf.z2.compressed(), bins=z_bin_edges)\n", - " z2_bin_areas = z2_bin_counts * gf.res[0] * gf.res[1] / 1E6\n", - " #z2_bin_areas_perc = 100. * z2_bin_areas / np.sum(z2_bin_areas)\n", - " z2_bin_areas_perc = 100. * (z1_bin_areas / gf.glac_area_km2)\n", - " else:\n", - " z2_bin_counts = z1_bin_counts\n", - " z2_bin_edges = z1_bin_edges\n", - " z2_bin_areas = z1_bin_areas\n", - " z2_bin_areas_perc = z1_bin_areas_perc\n", - "\n", - " #Create arrays to store output\n", - " slope_bin_med = np.ma.masked_all_like(z1_bin_areas)\n", - " slope_bin_mad = np.ma.masked_all_like(z1_bin_areas)\n", - " aspect_bin_med = np.ma.masked_all_like(z1_bin_areas)\n", - " aspect_bin_mad = np.ma.masked_all_like(z1_bin_areas)\n", - " if gf.dhdt is not None:\n", - " mb_bin_med = np.ma.masked_all_like(z1_bin_areas)\n", - " np.ma.set_fill_value(mb_bin_med, np.nan)\n", - " mb_bin_mad = np.ma.masked_all_like(mb_bin_med)\n", - " mb_bin_mean = np.ma.masked_all_like(mb_bin_med)\n", - " mb_bin_std = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_med = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_mad = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_mean = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_std = np.ma.masked_all_like(mb_bin_med)\n", - " dhdt_bin_count = np.ma.masked_all_like(mb_bin_med)\n", - " if gf.vm is not None:\n", - " vm_bin_med = np.ma.masked_all_like(z1_bin_areas)\n", - " vm_bin_mad = np.ma.masked_all_like(z1_bin_areas)\n", - " if gf.H is not None:\n", - " H_bin_mean = np.ma.masked_all_like(z1_bin_areas)\n", - " H_bin_std = np.ma.masked_all_like(z1_bin_areas)\n", - " emvel_bin_mean = np.ma.masked_all_like(z1_bin_areas)\n", - " emvel_bin_std = np.ma.masked_all_like(z1_bin_areas)\n", - " if gf.debris_class is not None:\n", - "# perc_clean = np.ma.masked_all_like(z1_bin_areas)\n", - "# perc_debris = np.ma.masked_all_like(z1_bin_areas)\n", - "# perc_pond = np.ma.masked_all_like(z1_bin_areas)\n", - " debris_thick_med = np.ma.masked_all_like(z1_bin_areas)\n", - " debris_thick_mad = np.ma.masked_all_like(z1_bin_areas)\n", - "# dhdt_clean_bin_med = np.ma.masked_all_like(z1_bin_areas)\n", - "# dhdt_debris_bin_med = np.ma.masked_all_like(z1_bin_areas)\n", - "# dhdt_pond_bin_med = np.ma.masked_all_like(mz1_bin_areas)\n", - "\n", - "# gf.dhdt_clean = np.ma.array(gf.dhdt, mask=~((gf.debris_class == 1).data))\n", - "# gf.dhdt_debris = np.ma.array(gf.dhdt, mask=~((gf.debris_class == 2).data))\n", - "# gf.dhdt_pond = np.ma.array(gf.dhdt, mask=~((gf.debris_class == 3).data))\n", - "\n", - " #Bin sample count must be greater than this value\n", - " min_bin_samp_count = 9\n", - "\n", - " #Loop through each bin and extract stats\n", - " idx = np.digitize(gf.z1, z_bin_edges)\n", - " for bin_n in range(z_bin_centers.size):\n", - " if gf.dhdt is not None:\n", - " mb_bin_samp = gf.mb_map[(idx == bin_n+1)]\n", - " if mb_bin_samp.count() > min_bin_samp_count:\n", - " mb_bin_med[bin_n] = malib.fast_median(mb_bin_samp)\n", - " mb_bin_mad[bin_n] = malib.mad(mb_bin_samp)\n", - " mb_bin_mean[bin_n] = mb_bin_samp.mean()\n", - " mb_bin_std[bin_n] = mb_bin_samp.std()\n", - " dhdt_bin_samp = gf.dhdt[(idx == bin_n+1)]\n", - " if dhdt_bin_samp.count() > min_bin_samp_count:\n", - " dhdt_bin_med[bin_n] = malib.fast_median(dhdt_bin_samp)\n", - " dhdt_bin_mad[bin_n] = malib.mad(dhdt_bin_samp)\n", - " dhdt_bin_mean[bin_n] = dhdt_bin_samp.mean()\n", - " dhdt_bin_std[bin_n] = dhdt_bin_samp.std()\n", - " dhdt_bin_count[bin_n] = dhdt_bin_samp.count()\n", - " if gf.debris_thick is not None:\n", - " debris_thick_bin_samp = gf.debris_thick[(idx == bin_n+1)]\n", - " if debris_thick_bin_samp.size > min_bin_samp_count:\n", - " debris_thick_med[bin_n] = malib.fast_median(debris_thick_bin_samp)\n", - " debris_thick_mad[bin_n] = malib.mad(debris_thick_bin_samp)\n", - " if gf.debris_class is not None:\n", - " debris_class_bin_samp = gf.debris_class[(idx == bin_n+1)]\n", - " dhdt_clean_bin_samp = gf.dhdt_clean[(idx == bin_n+1)]\n", - " dhdt_debris_bin_samp = gf.dhdt_debris[(idx == bin_n+1)]\n", - " dhdt_pond_bin_samp = gf.dhdt_pond[(idx == bin_n+1)]\n", - " if debris_class_bin_samp.count() > min_bin_samp_count:\n", - " perc_clean[bin_n] = 100. * (debris_class_bin_samp == 1).sum()/debris_class_bin_samp.count()\n", - " perc_debris[bin_n] = 100. * (debris_class_bin_samp == 2).sum()/debris_class_bin_samp.count()\n", - " perc_pond[bin_n] = 100. * (debris_class_bin_samp == 3).sum()/debris_class_bin_samp.count()\n", - " if dhdt_clean_bin_samp.count() > min_bin_samp_count:\n", - " dhdt_clean_bin_med[bin_n] = malib.fast_median(dhdt_clean_bin_samp)\n", - " if dhdt_debris_bin_samp.count() > min_bin_samp_count:\n", - " dhdt_debris_bin_med[bin_n] = malib.fast_median(dhdt_debris_bin_samp)\n", - " if dhdt_pond_bin_samp.count() > min_bin_samp_count:\n", - " dhdt_pond_bin_med[bin_n] = malib.fast_median(dhdt_pond_bin_samp)\n", - " if gf.vm is not None:\n", - " vm_bin_samp = gf.vm[(idx == bin_n+1)]\n", - " if vm_bin_samp.size > min_bin_samp_count:\n", - " vm_bin_med[bin_n] = malib.fast_median(vm_bin_samp)\n", - " vm_bin_mad[bin_n] = malib.mad(vm_bin_samp)\n", - " if gf.H is not None:\n", - " H_bin_samp = gf.H[(idx == bin_n+1)]\n", - " if H_bin_samp.size > min_bin_samp_count:\n", - " H_bin_mean[bin_n] = H_bin_samp.mean()\n", - " H_bin_std[bin_n] = H_bin_samp.std()\n", - " emvel_bin_samp = gf.emvel[(idx == bin_n+1)]\n", - " if emvel_bin_samp.size > min_bin_samp_count:\n", - " emvel_bin_mean[bin_n] = emvel_bin_samp.mean()\n", - " emvel_bin_std[bin_n] = emvel_bin_samp.std()\n", - " slope_bin_samp = gf.z1_slope[(idx == bin_n+1)]\n", - " if slope_bin_samp.size > min_bin_samp_count:\n", - " slope_bin_med[bin_n] = malib.fast_median(slope_bin_samp)\n", - " slope_bin_mad[bin_n] = malib.mad(slope_bin_samp)\n", - " aspect_bin_samp = gf.z1_aspect[(idx == bin_n+1)]\n", - " if aspect_bin_samp.size > min_bin_samp_count:\n", - " aspect_bin_med[bin_n] = malib.fast_median(aspect_bin_samp)\n", - " aspect_bin_mad[bin_n] = malib.mad(aspect_bin_samp)\n", - "\n", - " if gf.dhdt is not None:\n", - " dhdt_bin_areas = dhdt_bin_count * gf.res[0] * gf.res[1] / 1E6\n", - " #dhdt_bin_areas_perc = 100. * dhdt_bin_areas / np.sum(dhdt_bin_areas)\n", - " dhdt_bin_areas_perc = 100. * (dhdt_bin_areas / gf.glac_area_km2)\n", - "\n", - " outbins_header = 'bin_center_elev_m,z1_bin_count_valid,z1_bin_area_valid_km2,z1_bin_area_perc,z2_bin_count_valid,z2_bin_area_valid_km2,z2_bin_area_perc,slope_bin_med,aspect_bin_med'\n", - " fmt = '%0.1f,%0.0f,%0.3f,%0.2f,%0.0f,%0.3f,%0.2f,%0.2f,%0.2f'\n", - " outbins = [z_bin_centers, z1_bin_counts, z1_bin_areas, z1_bin_areas_perc, z2_bin_counts, z2_bin_areas, z2_bin_areas_perc, slope_bin_med, aspect_bin_med]\n", - " if gf.dhdt is not None:\n", - " outbins_header += ',dhdt_bin_count,dhdt_bin_area_valid_km2,dhdt_bin_area_perc,dhdt_bin_med_ma,dhdt_bin_mad_ma,dhdt_bin_mean_ma,dhdt_bin_std_ma,mb_bin_med_mwea,mb_bin_mad_mwea,mb_bin_mean_mwea,mb_bin_std_mwea'\n", - " fmt += ', %0.0f,%0.3f,%0.2f,%0.2f,%0.2f,%0.2f,%0.2f,%0.2f,%0.2f,%0.2f,%0.2f'\n", - " outbins.extend([dhdt_bin_count, dhdt_bin_areas, dhdt_bin_areas_perc, dhdt_bin_med, dhdt_bin_mad, dhdt_bin_mean, dhdt_bin_std, \\\n", - " mb_bin_med, mb_bin_mad, mb_bin_mean, mb_bin_std])\n", - " if gf.debris_thick is not None:\n", - " outbins_header += ',debris_thick_med_m,debris_thick_mad_m'\n", - " fmt += ',%0.2f,%0.2f'\n", - " debris_thick_med[debris_thick_med == -(np.inf)] = 0.00\n", - " debris_thick_mad[debris_thick_mad == -(np.inf)] = 0.00\n", - " outbins.extend([debris_thick_med, debris_thick_mad])\n", - " if gf.debris_class is not None:\n", - " outbins_header += ',perc_debris,perc_pond,perc_clean,dhdt_debris_med,dhdt_pond_med,dhdt_clean_med'\n", - " fmt += ',%0.2f,%0.2f,%0.2f,%0.2f,%0.2f,%0.2f'\n", - " outbins.extend([perc_debris, perc_pond, perc_clean, dhdt_debris_bin_med, dhdt_pond_bin_med, dhdt_clean_bin_med])\n", - " if gf.vm is not None:\n", - " outbins_header += ',vm_med,vm_mad'\n", - " fmt += ',%0.2f,%0.2f'\n", - " outbins.extend([vm_bin_med, vm_bin_mad])\n", - " if gf.H is not None:\n", - "# outbins_header += ', H_mean, H_std'\n", - "# fmt += ', %0.2f, %0.2f'\n", - "# outbins.extend([H_bin_mean, H_bin_std])\n", - " outbins_header += ',H_mean,H_std,emvel_mean,emvel_std'\n", - " fmt += ',%0.2f,%0.2f,%0.2f,%0.2f'\n", - " outbins.extend([H_bin_mean, H_bin_std, emvel_bin_mean, emvel_bin_std])\n", - "\n", - " outbins = np.ma.array(outbins).T.astype('float32')\n", - " np.ma.set_fill_value(outbins, np.nan)\n", - " outbins = outbins.filled(np.nan)\n", - " outbins_fn = os.path.join(outdir, gf.feat_fn+'_mb_bins_wemvel.csv')\n", - " np.savetxt(outbins_fn, outbins, fmt=fmt, delimiter=',', header=outbins_header)\n", - "\n", - " #Create plots of elevation bins\n", - " #print(\"Generating aed plot\")\n", - " #f,axa = plt.subplots(1,2, figsize=(6, 6))\n", - " nsubplots = 0\n", - " if gf.dhdt is not None:\n", - " nsubplots += 1\n", - " if gf.debris_thick is not None:\n", - " nsubplots += 1\n", - " if gf.vm is not None:\n", - " nsubplots += 1\n", - " if gf.H is not None:\n", - " nsubplots += 1\n", - " print(nsubplots)\n", - " f,axa = plt.subplots(1,nsubplots, squeeze=False, figsize=(10, 7.5))\n", - " f.suptitle(gf.feat_fn)\n", - " fs = 9\n", - " nplot = -1\n", - " if gf.dhdt is not None:\n", - " nplot += 1\n", - " axa[0,nplot].plot(z1_bin_areas, z_bin_centers, label='%0.2f' % gf.t1_mean)\n", - " axa[0,nplot].axhline(gf.z1_ela, ls=':', c='C0')\n", - " if gf.z2 is not None:\n", - " axa[0,nplot].plot(z2_bin_areas, z_bin_centers, label='%0.2f' % gf.t2_mean)\n", - " axa[0,nplot].axhline(gf.z2_ela, ls=':', c='C1')\n", - " axa[0,nplot].legend(prop={'size':8}, loc='upper right')\n", - " axa[0,nplot].set_ylabel('Elevation (m WGS84)', fontsize=fs)\n", - " axa[0,nplot].set_xlabel('Area $\\mathregular{km^2}$', fontsize=fs)\n", - " axa[0,nplot].yaxis.set_ticks_position('both')\n", - " # pltlib.minorticks_on(axa[0])\n", - "\n", - " nplot += 1\n", - " axa[0,nplot].axvline(0, lw=1.0, c='k')\n", - " \"\"\"\n", - " #Plot flux divergence values for each bin\n", - " if gf.vm is not None and gf.H is not None:\n", - " divQ_bin_mean = np.gradient(H_bin_mean * vm_bin_med * v_col_f)\n", - " axa[1].plot(divQ_bin_mean, z_bin_centers, color='green')\n", - " \"\"\"\n", - " axa[0,nplot].plot(mb_bin_med, z_bin_centers, color='k')\n", - " axa[0,nplot].axvline(gf.mb_mean, lw=0.5, ls=':', c='k', label='%0.2f m w.e./yr' % gf.mb_mean)\n", - " axa[0,nplot].fill_betweenx(z_bin_centers, mb_bin_med-mb_bin_mad, mb_bin_med+mb_bin_mad, color='k', alpha=0.1)\n", - " axa[0,nplot].fill_betweenx(z_bin_centers, 0, mb_bin_med, where=(mb_bin_med<0), color='r', alpha=0.2)\n", - " axa[0,nplot].fill_betweenx(z_bin_centers, 0, mb_bin_med, where=(mb_bin_med>0), color='b', alpha=0.2)\n", - " #axa[nplot].set_xlabel('dh/dt (m/yr)')\n", - " axa[0,nplot].set_xlabel('Mass balance (m w.e./yr)', fontsize=fs)\n", - " axa[0,nplot].legend(prop={'size':8}, loc='upper right')\n", - " axa[0,nplot].yaxis.set_ticks_position('both')\n", - " # pltlib.minorticks_on(axa[1])\n", - " #Hide y-axis labels\n", - " axa[0,nplot].axes.yaxis.set_ticklabels([])\n", - " axa[0,nplot].set_xlim(*dz_clim)\n", - "\n", - " if gf.debris_thick is not None:\n", - " nplot += 1\n", - " axa[0,nplot].errorbar(debris_thick_med*100., z_bin_centers, xerr=debris_thick_mad*100, color='k', fmt='o', ms=3, label='Debris Thickness', alpha=0.6)\n", - " if gf.debris_class is not None:\n", - " axa[0,nplot].plot(perc_debris, z_bin_centers, color='sienna', label='Debris Coverage')\n", - " axa[0,nplot].plot(perc_pond, z_bin_centers, color='turquoise', label='Pond Coverage')\n", - " if gf.debris_thick is not None or gf.debris_class is not None:\n", - " axa[0,nplot].set_xlim(0, 100)\n", - " axa[0,nplot].yaxis.set_ticks_position('both')\n", - " # pltlib.minorticks_on(axa[2])\n", - " axa[0,nplot].axes.yaxis.set_ticklabels([])\n", - " axa[0,nplot].legend(prop={'size':8}, loc='upper right')\n", - " axa[0,nplot].set_xlabel('Debris thickness (cm), coverage (%)', fontsize=fs)\n", - "\n", - " if gf.H is not None:\n", - " nplot += 1\n", - " axa[0,nplot].plot(H_bin_mean, z_bin_centers, color='b', label='H (%0.2f m)' % gf.H_mean)\n", - " axa[0,nplot].fill_betweenx(z_bin_centers, H_bin_mean-H_bin_std, H_bin_mean+H_bin_std, color='b', alpha=0.1)\n", - " axa[0,nplot].set_xlabel('Ice Thickness (m)', fontsize=fs)\n", - " axa[0,nplot].legend(prop={'size':8}, loc='lower right')\n", - " # pltlib.minorticks_on(axa[3])\n", - " #axa[nplot].set_xlim(0, 400)\n", - " axa[0,nplot].yaxis.tick_left()\n", - " axa[0,nplot].yaxis.set_ticks_position('both')\n", - " axa[0,nplot].yaxis.set_label_position(\"right\")\n", - " \n", - " if gf.vm is not None:\n", - " nplot += 1\n", - "# ax4 = axa[0,nplot].twinx()\n", - " axa[0,nplot].set_xlabel('Velocity (m/yr)', fontsize=fs)\n", - " axa[0,nplot].plot(vm_bin_med, z_bin_centers, color='g', label='Vm (%0.2f m/yr)' % gf.vm_mean)\n", - " axa[0,nplot].fill_betweenx(z_bin_centers, vm_bin_med-vm_bin_mad, vm_bin_med+vm_bin_mad, color='g', alpha=0.1)\n", - " #ax4.set_xlim(0, 50)\n", - " axa[0,nplot].xaxis.tick_bottom()\n", - " axa[0,nplot].xaxis.set_label_position(\"bottom\")\n", - " axa[0,nplot].legend(prop={'size':8}, loc='upper right')\n", - " \n", - " nplot += 1\n", - "# axa[0,nplot].set_xlabel('divQ (??)', fontsize=fs)\n", - "# axa[0,nplot].plot(vm_bin_med, z_bin_centers, color='g', label='Vm (%0.2f m/yr)' % gf.vm_mean)\n", - "# axa[0,nplot].fill_betweenx(z_bin_centers, vm_bin_med-vm_bin_mad, vm_bin_med+vm_bin_mad, color='g', alpha=0.1)\n", - "# #ax4.set_xlim(0, 50)\n", - "# axa[0,nplot].xaxis.tick_bottom()\n", - "# axa[0,nplot].xaxis.set_label_position(\"bottom\")\n", - "# axa[0,nplot].legend(prop={'size':8}, loc='upper right')\n", - "# gf.divQ\n", - " \n", - "# if gf.vm is not None:\n", - "# nplot += 1\n", - "# # ax4 = axa[0,nplot].twinx()\n", - "# axa[0,nplot].set_xlabel('Velocity (m/yr)', fontsize=fs)\n", - "# axa[0,nplot].plot(vm_bin_med, z_bin_centers, color='g', label='Vm (%0.2f m/yr)' % gf.vm_mean)\n", - "# axa[0,nplot].fill_betweenx(z_bin_centers, vm_bin_med-vm_bin_mad, vm_bin_med+vm_bin_mad, color='g', alpha=0.1)\n", - "# #ax4.set_xlim(0, 50)\n", - "# axa[0,nplot].xaxis.tick_bottom()\n", - "# axa[0,nplot].xaxis.set_label_position(\"bottom\")\n", - "# axa[0,nplot].legend(prop={'size':8}, loc='upper right')\n", - "\n", - " plt.tight_layout()\n", - " #Make room for suptitle\n", - " plt.subplots_adjust(top=0.95, wspace=0.1)\n", - " #print(\"Saving aed plot\")\n", - " fig_fn = os.path.join(outdir_fig, gf.feat_fn+'_mb_aed.png')\n", - " #plt.savefig(fig_fn, bbox_inches='tight', dpi=300)\n", - " plt.savefig(fig_fn, dpi=300)\n", - " plt.close(f)\n", - " return z_bin_edges\n", - "\n", - "z_bin_edges = hist_plot_wemvel(gf, outdir, bin_width=5)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "gf.vtot = (gf.vx**2 + gf.vy**2)**0.5\n", - "\n", - "titles = ['Velocity (m/yr)']\n", - "var_full2plot = gf.vtot\n", - "var_full2plot.mask = dems_mask\n", - "clim = malib.calcperc(var_full2plot, (2,98))\n", - "plot_array(var_full2plot, clim, titles, 'inferno', 'Velocity (m/yr)', fn='velocity.png')" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# # ===== TESTING Z2 CREATION WORKS =====\n", - "# #Warp everything to common res/extent/proj\n", - "# ds_list = warplib.memwarp_multi_fn([z1_fn, dhdt_fn, z2_fn], \n", - "# res='min', t_srs=aea_srs, verbose=verbose, r='cubic')\n", - "# # DEM masks\n", - "# ds_list_masked = [iolib.ds_getma(i) for i in ds_list]\n", - "# z1 = np.ma.masked_less_equal(ds_list_masked[0], 0)\n", - "# dhdt = ds_list_masked[1]\n", - "# z2 = ds_list_masked[2]\n", - "\n", - "# titles = ['z1']\n", - "# clim = malib.calcperc(z1, (2,98))\n", - "# plot_array(z1, clim, titles, 'inferno', 'Elevation (m WGS84)', fn='z1.png')\n", - "\n", - "# titles = ['dhdt']\n", - "# clim = malib.calcperc(dhdt, (2,98))\n", - "# plot_array(dhdt, clim, titles, 'inferno', 'Elevation (m WGS84)', fn='z1.png')\n", - "\n", - "# titles = ['z2']\n", - "# clim = malib.calcperc(z2, (2,98))\n", - "# plot_array(z2, clim, titles, 'inferno', 'Elevation (m WGS84)', fn='z2.png')" - ] - }, - { - "cell_type": "code", - "execution_count": 81, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Shp init crs: {'init': 'epsg:4326'}\n", - "Input glacier polygon count: 1\n", - "Expanding extent\n", - "[373321.835701501, 6813195.9656392, 399722.971437693, 6848260.35757026]\n", - "[372321.835701501, 6812195.9656392, 400722.971437693, 6849260.35757026]\n", - "PROJCS[\"WGS 84 / UTM zone 7N\",\n", - " GEOGCS[\"WGS 84\",\n", - " DATUM[\"WGS_1984\",\n", - " SPHEROID[\"WGS 84\",6378137,298.257223563,\n", - " AUTHORITY[\"EPSG\",\"7030\"]],\n", - " AUTHORITY[\"EPSG\",\"6326\"]],\n", - " PRIMEM[\"Greenwich\",0,\n", - " AUTHORITY[\"EPSG\",\"8901\"]],\n", - " UNIT[\"degree\",0.0174532925199433,\n", - " AUTHORITY[\"EPSG\",\"9122\"]],\n", - " AUTHORITY[\"EPSG\",\"4326\"]],\n", - " PROJECTION[\"Transverse_Mercator\"],\n", - " PARAMETER[\"latitude_of_origin\",0],\n", - " PARAMETER[\"central_meridian\",-141],\n", - " PARAMETER[\"scale_factor\",0.9996],\n", - " PARAMETER[\"false_easting\",500000],\n", - " PARAMETER[\"false_northing\",0],\n", - " UNIT[\"metre\",1,\n", - " AUTHORITY[\"EPSG\",\"9001\"]],\n", - " AXIS[\"Easting\",EAST],\n", - " AXIS[\"Northing\",NORTH],\n", - " AUTHORITY[\"EPSG\",\"32607\"]]\n", - "\n", - "Warping all inputs to the following:\n", - "Resolution: 35.83196016248294\n", - "Extent: [372321.835701501, 6812195.9656392, 400722.971437693, 6849260.35757026]\n", - "Projection: '+proj=utm +zone=7 +datum=WGS84 +units=m +no_defs '\n", - "Resampling alg: cubic\n", - "\n", - "1 of 2: /Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/Alaska_albers_V3_mac/Alaska_albers_V3.tif\n", - "nl: 1034 ns: 793 res: 35.832\n", - "2 of 2: /Users/davidrounce/Documents/Dave_Rounce/Satellite_Images/Kennicott/Kennicott_tsurfC_20130802.tif\n", - "nl: 1034 ns: 793 res: 35.832\n", - "[ >, >]\n", - "odict_keys(['z1', 'ts'])\n", - "list of datasets: 2 odict_values(['/Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/Alaska_albers_V3_mac/Alaska_albers_V3.tif', '/Users/davidrounce/Documents/Dave_Rounce/Satellite_Images/Kennicott/Kennicott_tsurfC_20130802.tif'])\n", - "\n", - "\n", - "# z1 pixels: 819962 \n", - "\n" - ] - } - ], - "source": [ - "#====== BIN DEBRIS THICKNESS FROM THERMAL METHOD ======\n", - "debris_fullfn = '/Users/davidrounce/Documents/Dave_Rounce/Satellite_Images/Kennicott/Kennicott_debristhickness_20130802.tif'\n", - "ts_fullfn = '/Users/davidrounce/Documents/Dave_Rounce/Satellite_Images/Kennicott/Kennicott_tsurfC_20130802.tif'\n", - "\n", - "#INPUT\n", - "topdir='/Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/'\n", - "#Output directory\n", - "outdir = topdir + 'kennicott/'\n", - "outdir_fig = outdir + '/figures/'\n", - "outdir_csv = outdir + '/csv'\n", - "\n", - "#RGI inventory\n", - "glac_shp_fn = '/Users/davidrounce/Documents/Dave_Rounce/Satellite_Images/Kennicott_glacier.shp'\n", - "glacfeat_fn = outdir + 'glacfeat_list.p'\n", - "#DEM\n", - "z1_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/Alaska_albers_V3_mac/Alaska_albers_V3.tif'\n", - "# Ice thickness\n", - "huss_dir = '/Users/davidrounce/Documents/Dave_Rounce/DebrisGlaciers_WG/Melt_Intercomparison/rounce_model/kennicott_data/'\n", - "huss_fn = 'thick_kennicott_HH2012.tif'\n", - "\n", - "#Output projection\n", - "proj_fn = os.path.join(huss_dir, huss_fn) # THIS PROJECTION IS KEY!\n", - "ds = gdal.Open(proj_fn)\n", - "prj = ds.GetProjection()\n", - "srs = osr.SpatialReference(wkt=prj)\n", - "aea_srs = srs\n", - "\n", - "# Process RGI shapefile\n", - "if 'rgi' in glac_shp_fn or 'Kennicott' in glac_shp_fn:\n", - " #Use RGI\n", - " glacname_fieldname = \"Name\"\n", - " #RGIId (String) = RGI50-01.00004\n", - " glacnum_fieldname = \"RGIId\"\n", - " glacnum_fmt = '%08.5f'\n", - "else:\n", - " sys.exit('Unrecognized glacier shp filename')\n", - "\n", - "# Shape layer processing\n", - "glac_shp_init = gpd.read_file(glac_shp_fn)\n", - "if verbose:\n", - " print('Shp init crs:', glac_shp_init.crs)\n", - "\n", - "# If projected shapefile already exists, then skip projection\n", - "glac_shp_proj_fn = (outdir + glac_shp_fn.split('/')[-1].replace('.shp','_crs' +\n", - " str(aea_srs.GetAttrValue(\"AUTHORITY\", 1)) + '.shp'))\n", - "if os.path.exists(glac_shp_proj_fn) == False:\n", - " glac_shp_proj = glac_shp_init.to_crs({'init': 'epsg:' + str(aea_srs.GetAttrValue(\"AUTHORITY\", 1))})\n", - " glac_shp_proj.to_file(glac_shp_proj_fn)\n", - " \n", - "glac_shp_ds = ogr.Open(glac_shp_proj_fn, 0)\n", - "glac_shp_lyr = glac_shp_ds.GetLayer()\n", - "#This should be contained in features\n", - "glac_shp_srs = glac_shp_lyr.GetSpatialRef()\n", - "feat_count = glac_shp_lyr.GetFeatureCount()\n", - "print(\"Input glacier polygon count: %i\" % feat_count)\n", - "\n", - "z1_ds = gdal.Open(z1_fn)\n", - "z1_int_geom = geolib.ds_geom_intersection([z1_ds, z1_ds], t_srs=glac_shp_srs)\n", - "\n", - "fn_dict = OrderedDict()\n", - "#We at least want to warp the two input DEMs\n", - "fn_dict['z1'] = z1_fn\n", - "# fn_dict['debris_thick'] = debris_fullfn\n", - "fn_dict['ts'] = ts_fullfn\n", - "\n", - "#Expand extent to include buffered region around glacier polygon\n", - "warp_extent = geolib.pad_extent(gf.glac_geom_extent, width=buff_dist)\n", - "if verbose:\n", - " print(\"Expanding extent\")\n", - " print(gf.glac_geom_extent)\n", - " print(warp_extent)\n", - " print(aea_srs)\n", - "\n", - "\n", - " #Warp everything to common res/extent/proj\n", - " ds_list = warplib.memwarp_multi_fn(fn_dict.values(), res='min', \\\n", - " extent=warp_extent, t_srs=aea_srs, verbose=verbose, \\\n", - " r='cubic')\n", - "\n", - " ds_dict = dict(zip(fn_dict.keys(), ds_list))\n", - " \n", - " print(ds_list)\n", - " print(fn_dict.keys())\n", - " \n", - " #Prepare mask for all glaciers within buffered area, not just the current glacier polygon\n", - " glac_shp_ds = ogr.Open(glac_shp_proj_fn, 0)\n", - " glac_shp_lyr = glac_shp_ds.GetLayer()\n", - " #Spatial filter\n", - "# glac_shp_lyr.SetSpatialFilter(geom)\n", - "\n", - " #Get global glacier mask\n", - " #Want this to be True over ALL glacier surfaces, not just the current polygon\n", - " glac_shp_lyr_mask = geolib.lyr2mask(glac_shp_lyr, ds_dict['z1'])\n", - " \n", - " #geom srs is not preserved when loaded from disk, attempt to reassign\n", - "# gf.geom_srs_update()\n", - " #Create buffer around glacier polygon\n", - " glac_geom_buff = gf.glac_geom.Buffer(buff_dist)\n", - " #This is False over glacier polygon surface, True elsewhere - can be applied directly\n", - " glac_geom_buff_mask = geolib.geom2mask(glac_geom_buff, ds_dict['z1'])\n", - " \n", - " # ds masks\n", - " ds_list_masked = [iolib.ds_getma(i) for i in ds_list]\n", - " dem1 = np.ma.masked_less_equal(ds_list_masked[0], 0)\n", - " dems_mask = dem1.mask\n", - " if verbose:\n", - " print('list of datasets:', len(ds_list_masked), fn_dict.values())\n", - " \n", - " #Combine to identify ~1 km buffer around glacier polygon over static rock\n", - " static_buffer_mask = np.ma.mask_or(~glac_shp_lyr_mask, glac_geom_buff_mask)\n", - " static_shp_lyr_mask = np.ma.mask_or(static_buffer_mask, dems_mask)\n", - "\n", - " if 'z1' in ds_dict:\n", - " #This is False over glacier polygon surface, True elsewhere - can be applied directly\n", - " glac_geom_mask = geolib.geom2mask(gf.glac_geom, ds_dict['z1'])\n", - " gf.z1 = np.ma.array(iolib.ds_getma(ds_dict['z1']))\n", - "# gf.debris_thick = np.ma.array(iolib.ds_getma(ds_dict['debris_thick']), mask=glac_geom_mask)\n", - " gf.ts = np.ma.array(iolib.ds_getma(ds_dict['ts']), mask=glac_geom_mask)\n", - " print('\\n\\n# z1 pixels:', gf.z1.count(), '\\n')\n", - " if gf.z1.count() == 0:\n", - " if verbose:\n", - " print(\"No z1 pixels\")\n", - "# return None\n", - " else:\n", - " print(\"Unable to load z1 ds\")\n", - "# return None" - ] - }, - { - "cell_type": "code", - "execution_count": 82, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "#Now apply glacier mask AND mask NaN values\n", - "glac_geom_mask = np.ma.mask_or(glac_geom_mask, dems_mask)\n", - "gf.ts = np.ma.array(gf.ts, mask=glac_geom_mask)\n", - "# gf.debris_thick = np.ma.masked_less_equal(gf.debris, 0)\n", - "# gf.debris_thick[gf.debris_thick>1] = 1\n", - "\n", - "gf.res = geolib.get_res(ds_dict['z1'])\n", - "\n", - "titles = ['Surface temperature (degC)']\n", - "clim = malib.calcperc(gf.ts, (2,98))\n", - "plot_array(gf.ts, clim, titles, 'inferno', 'Surface temperature (degC)', fn='../ts.png')" - ] - }, - { - "cell_type": "code", - "execution_count": 89, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "31.291631240292492" - ] - }, - "execution_count": 89, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gf.ts.max()" - ] - }, - { - "cell_type": "code", - "execution_count": 107, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "#Now apply glacier mask AND mask NaN values\n", - "# glac_geom_mask = np.ma.mask_or(glac_geom_mask, dems_mask)\n", - "# gf.debris_thick = np.ma.array(iolib.ds_getma(ds_dict['ts']), mask=glac_geom_mask)\n", - "k = 0.13\n", - "Tsmax_offset = 6\n", - "Tsmax = gf.ts.max() + Tsmax_offset\n", - "gf.debris_thick = gf.ts * 0.13 / (Tsmax - gf.ts)\n", - "# gf.debris_thick = np.ma.array(gf.debris_thick, mask=glac_geom_mask)\n", - "# gf.debris_thick = np.ma.masked_less_equal(gf.debris, 0)\n", - "# gf.debris_thick[gf.debris_thick>1] = 1\n", - "\n", - "gf.res = geolib.get_res(ds_dict['z1'])\n", - "\n", - "titles = ['Debris thickness (m)']\n", - "clim = malib.calcperc(gf.debris_thick, (2,98))\n", - "plot_array(gf.debris_thick, clim, titles, 'inferno', 'Debris thickness (m)', fn='../debris_thickness.png')" - ] - }, - { - "cell_type": "code", - "execution_count": 109, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "31.291631240292492" - ] - }, - "execution_count": 109, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gf.ts.max()" - ] - }, - { - "cell_type": "code", - "execution_count": 108, - "metadata": {}, - "outputs": [], - "source": [ - "#RGI uses 50 m bins\n", - "def hist_plot_wdebris(gf, outdir, bin_width=50.0):\n", - "\n", - " z_bin_edges, z_bin_centers = malib.get_bins(gf.z1, bin_width)\n", - " #Need to compress here, otherwise histogram uses masked values!\n", - " z1_bin_counts, z1_bin_edges = np.histogram(gf.z1.compressed(), bins=z_bin_edges)\n", - " z1_bin_areas = z1_bin_counts * gf.res[0] * gf.res[1] / 1E6\n", - " #RGI standard is integer thousandths of glaciers total area\n", - " #Should check to make sure sum of bin areas equals total area\n", - " z1_bin_areas_perc = 100. * (z1_bin_areas / gf.glac_area_km2)\n", - "\n", - " #Create arrays to store output\n", - " if gf.debris_thick is not None:\n", - " debris_thick_med = np.ma.masked_all_like(z1_bin_areas)\n", - " debris_thick_mad = np.ma.masked_all_like(z1_bin_areas)\n", - " else:\n", - " print('NO DEBRIS THICKNESS!')\n", - "\n", - " #Bin sample count must be greater than this value\n", - " min_bin_samp_count = 9\n", - "\n", - " #Loop through each bin and extract stats\n", - " idx = np.digitize(gf.z1, z_bin_edges)\n", - " for bin_n in range(z_bin_centers.size):\n", - " if gf.debris_thick is not None:\n", - " debris_thick_bin_samp = gf.debris_thick[(idx == bin_n+1)]\n", - " if debris_thick_bin_samp.size > min_bin_samp_count:\n", - " debris_thick_med[bin_n] = malib.fast_median(debris_thick_bin_samp)\n", - " debris_thick_mad[bin_n] = malib.mad(debris_thick_bin_samp)\n", - "\n", - " outbins_header = 'bin_center_elev_m,z1_bin_count_valid,z1_bin_area_valid_km2,z1_bin_area_perc'\n", - " fmt = '%0.1f,%0.0f,%0.3f,%0.2f'\n", - " outbins = [z_bin_centers, z1_bin_counts, z1_bin_areas, z1_bin_areas_perc]\n", - " if gf.debris_thick is not None:\n", - " outbins_header += ',debris_thick_med_m,debris_thick_mad_m'\n", - " fmt += ',%0.2f,%0.2f'\n", - " debris_thick_med[debris_thick_med == -(np.inf)] = 0.00\n", - " debris_thick_mad[debris_thick_mad == -(np.inf)] = 0.00\n", - " outbins.extend([debris_thick_med, debris_thick_mad])\n", - "\n", - " outbins = np.ma.array(outbins).T.astype('float32')\n", - " np.ma.set_fill_value(outbins, np.nan)\n", - " outbins = outbins.filled(np.nan)\n", - " outbins_fn = os.path.join(outdir, gf.feat_fn+'_mb_bins_wdebris.csv')\n", - " np.savetxt(outbins_fn, outbins, fmt=fmt, delimiter=',', header=outbins_header)\n", - " return z_bin_edges\n", - "\n", - "z_bin_edges = hist_plot_wdebris(gf, outdir, bin_width=5)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.7" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/example_plots.py b/example_plots.py deleted file mode 100644 index a30cf6e3..00000000 --- a/example_plots.py +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Created on Thu Jun 20 07:58:00 2019 - -@author: davidrounce -""" - -import os -import cartopy -import matplotlib.pyplot as plt -from matplotlib.lines import Line2D -import numpy as np -import pandas as pd - -#pd.read_csv('') - -#%% X-Y PLOT -#ds = pd.read_csv(...) - -# X,Y values -x_values = [0,1,2,3] -y_values = [2,-1,1,5] -y2_values = [3, 2, 3, 0] - -# Set up your plot (and/or subplots) -fig, ax = plt.subplots(1, 1, squeeze=False, sharex=False, sharey=False, gridspec_kw = {'wspace':0.4, 'hspace':0.15}) - -# Plot -# zorder controls the order of the plots (higher zorder plots on top) -# label used to automatically generate legends (legends can be done manually for more control) -ax[0,0].plot(x_values, y_values, color='k', linewidth=1, zorder=2, label='plot1') -ax[0,0].plot(x_values, y2_values, color='b', linewidth=1, zorder=2, label='plot2') - -# Fill between -# fill between is useful for putting colors between plots (e.g., error bounds) -#ax[0,0].fill_between(x_values, y_values, y2_values, facecolor='k', alpha=0.2, zorder=1) - -# Text -# text can be used to manually add labels or to comment on plot -# transform=ax.transAxes means the x and y are between 0-1 -ax[0,0].text(0.5, 0.99, '[insert text]', size=10, horizontalalignment='center', verticalalignment='top', - transform=ax[0,0].transAxes) - -# X-label -ax[0,0].set_xlabel('X LABEL', size=12) -#ax[0,0].set_xlim(time_values_annual[t1_idx:t2_idx].min(), time_values_annual[t1_idx:t2_idx].max()) -#ax[0,0].xaxis.set_tick_params(labelsize=12) -#ax[0,0].xaxis.set_major_locator(plt.MultipleLocator(50)) -#ax[0,0].xaxis.set_minor_locator(plt.MultipleLocator(10)) -#ax[0,0].set_xticklabels(['2015','2050','2100']) - -# Y-label -ax[0,0].set_ylabel('Y LABEL', size=12) -#ax[0,0].set_ylim(0,1.1) -#ax[0,0].yaxis.set_major_locator(plt.MultipleLocator(0.2)) -#ax[0,0].yaxis.set_minor_locator(plt.MultipleLocator(0.05)) - -# Tick parameters -# controls the plotting of the ticks -#ax[0,0].yaxis.set_ticks_position('both') -#ax[0,0].tick_params(axis='both', which='major', labelsize=12, direction='inout') -#ax[0,0].tick_params(axis='both', which='minor', labelsize=12, direction='inout') - -# Example Legend -# Option 1: automatic based on labels -ax[0,0].legend(loc=(0.05, 0.05), fontsize=10, labelspacing=0.25, handlelength=1, handletextpad=0.25, borderpad=0, - frameon=False) -# Option 2: manually define legend -#leg_lines = [] -#labels = ['plot1', 'plot2'] -#label_colors = ['k', 'b'] -#for nlabel, label in enumerate(labels): -# line = Line2D([0,1],[0,1], color=label_colors[nlabel], linewidth=1) -# leg_lines.append(line) -#ax[0,0].legend(leg_lines, labels, loc=(0.05,0.05), fontsize=10, labelspacing=0.25, handlelength=1, -# handletextpad=0.25, borderpad=0, frameon=False) - -# Save figure -# figures can be saved in any format (.jpg, .png, .pdf, etc.) -fig.set_size_inches(4, 4) -figure_fp = os.getcwd() + '/../Output/' -if os.path.exists(figure_fp) == False: - os.makedirs(figure_fp) -figure_fn = 'example_plot_xy.png' -fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300) - - -#%% MAP PLOT -xtick = 5 -ytick = 5 -xlabel = 'Longitude [$^\circ$]' -ylabel = 'Latitude [$^\circ$]' -labelsize = 12 -west = -180 -east = 180 -south = -90 -north = 90 - -rgiO1_shp_fn = os.getcwd() + '/../RGI/rgi60/00_rgi60_regions/00_rgi60_O1Regions.shp' - - -# Time, Latitude, Longitude -lons = [7.5,86.8,43.2,85.6,6.9,-69.9,10.6,-70.0,170] -lats = [46.0,28.0,42.8,28.2,45.8,-33.6,46.5,-30.1,-43] -values = [2665,5471,3050,4076,2030,3459,2623,4570,900] -#sizes = [100, 50, 20] - -#var_change = temp_change - - -# Create the projection -fig, ax = plt.subplots(1, 1, figsize=(10,5), subplot_kw={'projection':cartopy.crs.PlateCarree()}) -# Add country borders for reference -ax.add_feature(cartopy.feature.BORDERS, alpha=0.3, zorder=1) -ax.add_feature(cartopy.feature.COASTLINE) - -# Set the extent -ax.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) -# Label title, x, and y axes -ax.set_xticks(np.arange(east,west+1,xtick), cartopy.crs.PlateCarree()) -ax.set_yticks(np.arange(south,north+1,ytick), cartopy.crs.PlateCarree()) -ax.set_xlabel(xlabel, size=labelsize) -ax.set_ylabel(ylabel, size=labelsize) - -# Add regions -# facecolor='none' just plots the lines -#group_shp = cartopy.io.shapereader.Reader(rgiO1_shp_fn) -#group_feature = cartopy.feature.ShapelyFeature(group_shp.geometries(), cartopy.crs.PlateCarree(), -# edgecolor='black', facecolor='grey', alpha=0.2, linewidth=1) -#ax.add_feature(group_feature,zorder=2) - -# Add colorbar -cmap = 'RdYlBu_r' -norm = plt.Normalize(int(np.min(values)), np.ceil(np.max(values))) -var_label = 'Elevation [m a.s.l.]' -sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) -sm._A = [] -plt.colorbar(sm, ax=ax, fraction=0.024, pad=0.01) -fig.text(1, 0.5, var_label, va='center', ha='center', rotation='vertical', size=labelsize) - -ax.scatter(lons, lats, c=values, s=50, cmap=cmap, norm=norm, edgecolors='k', linewidth=0.5, alpha=0.9, zorder=3) - -#ax.pcolormesh(lons, lats, var_change, cmap=cmap, norm=norm, zorder=2, alpha=0.8) - -# Title -#ax.set_title('[INSERT TITLE]') - -# Save figure -fig.set_size_inches(6,4) -figure_fp = os.getcwd() + '/../Output/' -if os.path.exists(figure_fp) == False: - os.makedirs(figure_fp) -fig_fn = 'example_plot_map.png' -fig.savefig(figure_fp + fig_fn, bbox_inches='tight', dpi=300) \ No newline at end of file diff --git a/farinotti.yml b/farinotti.yml deleted file mode 100644 index 96c6a553..00000000 --- a/farinotti.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: farinotti_preprocess -channels: -- conda-forge -dependencies: -- python -- gdal -- pandas -- numpy -- scipy -- xarray -- matplotlib -- spyder diff --git a/loop_merge.py b/loop_merge.py deleted file mode 100644 index 22efb7e9..00000000 --- a/loop_merge.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Created on Wed Dec 5 08:21:18 2018 -@author: davidrounce -""" -import os -from subprocess import call -import spc_split_glaciers as split_glaciers - -# regions = [13, 14] -# gcm_names = ['CCSM4'] -# rcps = ['rcp26'] -regions = [13, 14, 15] -gcm_names = ['CCSM4'] -rcps = ['rcp45', 'rcp60', 'rcp85'] -#output_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/simulations/spc_20190914/' -output_fp = '/Volumes/LaCie/HMA_PyGEM/2019_0914/merged/' -nchunks = 10 - - -for gcm in gcm_names: - for rcp in rcps: - - ds_fp = output_fp + gcm + '/' + rcp + '/' - - for region in regions: - - if region == 15: - nchunks = 10 - if region == 14: - nchunks = 15 - elif region == 13: - nchunks = 25 - - - # Glacier numbers - glac_no = [] - for i in os.listdir(ds_fp): - if i.endswith('.nc') and i.startswith(str(region)): - glac_no.append(i.split('_')[0]) - if len(glac_no) == 1: - ds_ending = i.replace(i.split('_')[0],'') - glac_no = sorted(glac_no) - - # Glacier number lists to pass for parallel processing - glac_no_lsts = split_glaciers.split_list(glac_no, n=nchunks) - - - for nchunk, chunk in enumerate(glac_no_lsts): - print(nchunk, chunk[0], chunk[-1]) - chunk_start = glac_no.index(chunk[0]) - chunk_end = glac_no.index(chunk[-1]) - - # Append arguments to call list - call_list = ["python", "merge_ds.py"] - call_list.append('-region=' + str(region)) - call_list.append("-gcm_name={}".format(gcm)) - call_list.append("-rcp={}".format(rcp)) - call_list.append('-chunk_no=' + str(nchunk)) - call_list.append('-chunk_start=' + str(chunk_start)) - call_list.append('-chunk_end=' + str(chunk_end)) - - # Run script - call(call_list) - - # ADD IN LOOP TO THEN MERGE THE LISTS IN THEIR ENTIRETY INTO A SINGLE DS! - # DO THIS WITH A SEPARATE CALL... diff --git a/loop_subset.py b/loop_subset.py deleted file mode 100644 index bf686625..00000000 --- a/loop_subset.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Created on Fri Sep 20 2019 -@author: davidrounce -""" -from subprocess import call - -regions = [13, 14, 15] -#gcm_names = ['CSIRO-Mk3-6-0', 'GFDL-ESM2G', 'IPSL-CM5A-MR', 'MIROC-ESM', 'MIROC-ESM-CHEM', 'NorESM1-ME'] -gcm_names = ['FGOALS-g2', 'HadGEM2-ES', 'MPI-ESM-LR', 'MPI-ESM-MR'] -rcps = ['rcp26', 'rcp45', 'rcp85'] -#rcps = ['rcp26', 'rcp45', 'rcp60', 'rcp85'] -#output_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/simulations/spc_20190914/' -netcdf_fp = '/Volumes/LaCie/HMA_PyGEM/2019_0914/spc_zipped/' - -for gcm in gcm_names: - - ds_fp = netcdf_fp + gcm + '/' - - for rcp in rcps: - for region in regions: - - # Append arguments to call list - call_list = ["python", "run_postprocessing.py"] - call_list.append("-gcm_name={}".format(gcm)) - call_list.append("-rcp={}".format(rcp)) - call_list.append('-region=' + str(region)) - call_list.append('-output_sim_fp={}'.format(ds_fp)) - call_list.append('-extract_subset=1') - call_list.append('-unzip_files=1') - -# print(call_list) - - # Run script - call(call_list) - - # ADD IN LOOP TO THEN MERGE THE LISTS IN THEIR ENTIRETY INTO A SINGLE DS! - # DO THIS WITH A SEPARATE CALL... \ No newline at end of file diff --git a/merge_ds_spc.py b/merge_ds_spc.py index 7e816119..78e85d6b 100644 --- a/merge_ds_spc.py +++ b/merge_ds_spc.py @@ -117,6 +117,7 @@ def main(list_packed_vars): nchunks = args.num_simultaneous_processes output_fp = '../Output/simulations/' +# output_fp = '../Output/simulations/spc_20190914/' ds_fp = output_fp + gcm_name + '/' ds_all_fp = output_fp + 'merged/' + gcm_name + '/' @@ -131,23 +132,15 @@ def main(list_packed_vars): # gcm_files = sorted(gcm_files) gcm_files = [] - if args.rcp is not None: - rcps = [args.rcp] - ds_fp += args.rcp + '/' - for i in os.listdir(ds_fp): - if i.endswith('.nc'): - full_fn = ds_fp + i - gcm_files.append(full_fn) - else: - for i in os.listdir(ds_fp): - if i.endswith('.nc'): - full_fn = ds_fp + i - gcm_files.append(full_fn) - elif os.path.isdir(ds_fp + i): - for j in os.listdir(ds_fp + i): - if j.endswith('.nc'): - full_fn = ds_fp + i + '/' + j - gcm_files.append(full_fn) + for i in os.listdir(ds_fp): + if i.endswith('.nc'): + full_fn = ds_fp + i + gcm_files.append(full_fn) + elif os.path.isdir(ds_fp + i): + for j in os.listdir(ds_fp + i): + if j.endswith('.nc'): + full_fn = ds_fp + i + '/' + j + gcm_files.append(full_fn) gcm_files = sorted(gcm_files) rcps = [] @@ -166,14 +159,14 @@ def main(list_packed_vars): regions = sorted(regions) rcps = sorted(rcps) - if args.rcp is not None: - rcps = [args.rcp] - if len(rcps) == 0: rcps.append(gcm_name) # regions = ['14', '15'] # rcps = ['rcp26', 'rcp45', 'rcp60', 'rcp85'] + + if args.rcp is not None: + rcps = [args.rcp] for rcp in rcps: for region in regions: @@ -186,8 +179,6 @@ def main(list_packed_vars): glac_fullfn_region.append(i) glac_fullfn_region = sorted(glac_fullfn_region) - print(rcp, region, len(glac_fullfn_region), 'glaciers') - # Split into lists for parallel processing glac_fullfn_lsts = split_glaciers.split_list(glac_fullfn_region, n=nchunks) @@ -211,8 +202,8 @@ def main(list_packed_vars): # MERGE CHUNKS chunk_fns = [] for i in os.listdir(ds_all_fp): - if i.startswith('R' + region) and i.endswith('.nc') and rcp in i and gcm_name in i and 'chunk' in i: - print(i) + print(i) + if i.startswith('R' + region) and rcp in i and gcm_name in i: chunk_fns.append(i) chunk_fns = sorted(chunk_fns) for nchunk, chunk_fn in enumerate(chunk_fns): diff --git a/pygem_input.py b/pygem_input.py index 7e915080..816b7ab7 100644 --- a/pygem_input.py +++ b/pygem_input.py @@ -118,26 +118,26 @@ def glac_fromcsv(csv_fullfn, cn='RGIId'): output_filepath = main_directory + '/../Output/' # ===== GLACIER SELECTION ===== -rgi_regionsO1 = [13, 14, 15] # 1st order region number (RGI V6.0) +rgi_regionsO1 = [13,14,15] # 1st order region number (RGI V6.0) rgi_regionsO2 = 'all' # 2nd order region number (RGI V6.0) # RGI glacier number (RGI V6.0) # Two options: (1) use glacier numbers for a given region (or 'all'), must have glac_no set to None # (2) glac_no is not None, e.g., ['1.00001', 13.0001'], overrides rgi_glac_number rgi_glac_number = 'all' -#rgi_glac_number = ['00013'] -#rgi_glac_number = glac_num_fromrange(1,5) +#rgi_glac_number = glac_num_fromrange(1,48) +#rgi_glac_number = glac_num_fromrange(1100,1200) #rgi_glac_number = get_same_glaciers(output_filepath + 'cal_opt1/reg1/') #rgi_glac_number = get_shean_glacier_nos(rgi_regionsO1[0], 1, option_random=1) -#glac_no = None +glac_no = None #glac_no = glac_fromcsv(main_directory + '/../qgis_himat/trishuli_and_naltar_RGIIds.csv') -glac_no = ['15.03473'] +#glac_no = ['13.26960', '15.00002', '14.01243'] if glac_no is not None: rgi_regionsO1 = sorted(list(set([int(x.split('.')[0]) for x in glac_no]))) # ===== CLIMATE DATA ===== # Reference period runs -#ref_gcm_name = 'ERA-Interim' # reference climate dataset -ref_gcm_name = 'ERA5' # reference climate dataset +ref_gcm_name = 'ERA-Interim' # reference climate dataset +#ref_gcm_name = 'ERA5' # reference climate dataset #startyear = 1980 # first year of model run (reference dataset) #endyear = 2018 # last year of model run (reference dataset) @@ -146,25 +146,23 @@ def glac_fromcsv(csv_fullfn, cn='RGIId'): endyear = 2018 # last year of model run (reference dataset) option_wateryear = 3 # 1: water year, 2: calendar year, 3: custom defined -constantarea_years = 0 # number of years to not let the area or volume change -if constantarea_years > 0: - print('\nConstant area years > 0\n') spinupyears = 0 # spin up years +constantarea_years = 0 # number of years to not let the area or volume change # Simulation runs (separate so calibration and simulations can be run at same time; also needed for bias adjustments) -gcm_startyear = 1995 # first year of model run (simulation dataset) -gcm_endyear = 2017 # last year of model run (simulation dataset) #gcm_startyear = 2000 # first year of model run (simulation dataset) -#gcm_endyear = 2100 # last year of model run (simulation dataset) +#gcm_endyear = 2018 # last year of model run (simulation dataset) +gcm_startyear = 2000 # first year of model run (simulation dataset) +gcm_endyear = 2100 # last year of model run (simulation dataset) gcm_spinupyears = 0 # spin up years for simulation gcm_wateryear = 1 # water year for simmulation # Hindcast option (flips array so 1960-2000 would run 2000-1960 ensuring that glacier area at 2000 is correct) hindcast = 0 # 1: run hindcast simulation, 0: do not if hindcast == 1: - constantarea_years = 0 # number of years to not let the area or volume change - gcm_startyear = 1980 # first year of model run (simulation dataset) - gcm_endyear = 2000 # last year of model run (simulation dataset) + constantarea_years = 18 # number of years to not let the area or volume change + gcm_startyear = 1960 # first year of model run (simulation dataset) + gcm_endyear = 2017 # last year of model run (simulation dataset) # Synthetic options (synthetic refers to created climate data, e.g., repeat 1995-2015 for the next 100 years) option_synthetic_sim = 0 # 1: run synthetic simulation, 0: do not @@ -177,8 +175,8 @@ def glac_fromcsv(csv_fullfn, cn='RGIId'): #%% SIMULATION OPTIONS # MCMC options -sim_iters = 100 # number of simulations (needed for cal_opt 2) -sim_burn = 200 # number of burn-in (needed for cal_opt 2) +sim_iters = 100 # number of simulations (needed for cal_opt 2) +sim_burn = 200 # number of burn-in (needed for cal_opt 2) # Simulation output filepath output_sim_fp = output_filepath + 'simulations/' @@ -189,24 +187,25 @@ def glac_fromcsv(csv_fullfn, cn='RGIId'): #%% ===== CALIBRATION OPTIONS ===== # Calibration option (1 = minimization, 2 = MCMC, 3=HH2015, 4=modified HH2015) -option_calibration = 4 +option_calibration = 2 # Calibration datasets ('shean', 'larsen', 'mcnabb', 'wgms_d', 'wgms_ee', 'group') cal_datasets = ['shean'] -#cal_datasets = ['shean'] # Calibration output filepath output_fp_cal = output_filepath + 'cal_opt' + str(option_calibration) + '/' # OPTION 1: Minimization -# Model parameter bounds for each calibration round +# Model parameter bounds for each calibration roun +#precfactor_bnds_list_init = [(0.9, 1.125), (0.8,1.25), (0.5,2), (0.33,3)] +#precgrad_bnds_list_init = [(0.0001,0.0001), (0.0001,0.0001), (0.0001,0.0001), (0.0001,0.0001)] +#ddfsnow_bnds_list_init = [(0.0036, 0.0046), (0.0036, 0.0046), (0.0026, 0.0056), (0.00185, 0.00635)] +#tempchange_bnds_list_init = [(-1,1), (-2,2), (-5,5), (-10,10)] precfactor_bnds_list_init = [(0.8, 2.0), (0.8,2), (0.8,2), (0.2,5)] precgrad_bnds_list_init = [(0.0001,0.0001), (0.0001,0.0001), (0.0001,0.0001), (0.0001,0.0001)] ddfsnow_bnds_list_init = [(0.003, 0.003), (0.00175, 0.0045), (0.00175, 0.0045), (0.00175, 0.0045)] tempchange_bnds_list_init = [(0,0), (0,0), (-2.5,2.5), (-10,10)] # Minimization details method_opt = 'SLSQP' # SciPy optimization scheme ('SLSQP' or 'L-BFGS-B') -params2opt = ['tempbias', 'precfactor'] ftol_opt = 1e-3 # tolerance for SciPy optimization scheme -eps_opt = 0.01 # epsilon (adjust variables for jacobian) for SciPy optimization scheme (1e-6 works) massbal_uncertainty_mwea = 0.1 # mass balance uncertainty [mwea] for glaciers lacking uncertainty data zscore_tolerance_all = 1 # tolerance if multiple calibration points (shortcut that could be improved) zscore_tolerance_single = 0.1 # tolerance if only a single calibration point (want this to be more exact) @@ -215,49 +214,81 @@ def glac_fromcsv(csv_fullfn, cn='RGIId'): # OPTION 2: MCMC # Chain options -if option_calibration == 2: - n_chains = 1 # number of chains (min 1, max 3) - mcmc_sample_no = 10000 # number of steps (10000 was found to be sufficient in HMA) - mcmc_burn_no = 0 # number of steps to burn-in (0 records all steps in chain) - mcmc_step = None # step option (None or 'am') - thin_interval = 1 # thin interval if need to reduce file size (best to leave at 1 if space allows) - # Precipitation factor distribution options - precfactor_disttype = 'gamma' # distribution type ('gamma', 'lognormal', 'uniform') - precfactor_gamma_region_dict_fullfn = main_directory + '/../Output/precfactor_gamma_region_dict.csv' - precfactor_gamma_region_df = pd.read_csv(precfactor_gamma_region_dict_fullfn) - precfactor_gamma_region_dict = dict(zip( - precfactor_gamma_region_df.Region.values, - [[precfactor_gamma_region_df.loc[x,'alpha'], precfactor_gamma_region_df.loc[x,'beta']] - for x in precfactor_gamma_region_df.index.values])) - precfactor_gamma_alpha = 3.0 - precfactor_gamma_beta = 0.84 - precfactor_lognorm_mu = 0 - precfactor_lognorm_tau = 4 - precfactor_mu = 0 - precfactor_sigma = 1.5 - precfactor_boundlow = 0.5 - precfactor_boundhigh = 1.5 - precfactor_start = 1 - # Temperature bias distribution options - tempchange_disttype = 'normal' # distribution type ('normal', 'truncnormal', 'uniform') - tempchange_norm_region_dict_fullfn = main_directory + '/../Output/tempchange_norm_region_dict.csv' - tempchange_norm_region_df = pd.read_csv(tempchange_norm_region_dict_fullfn) - tempchange_norm_region_dict = dict(zip( - tempchange_norm_region_df.Region.values, - [[tempchange_norm_region_df.loc[x,'mu'], tempchange_norm_region_df.loc[x,'sigma']] - for x in tempchange_norm_region_df.index.values])) - tempchange_mu = 0.91 - tempchange_sigma = 1.4 - tempchange_boundlow = -10 - tempchange_boundhigh = 10 - tempchange_start = tempchange_mu - # Degree-day factor of snow distribution options - ddfsnow_disttype = 'truncnormal' # distribution type ('truncnormal', 'uniform') - ddfsnow_mu = 0.0041 - ddfsnow_sigma = 0.0015 - ddfsnow_boundlow = 0 - ddfsnow_boundhigh = np.inf - ddfsnow_start=ddfsnow_mu +n_chains = 1 # number of chains (min 1, max 3) +mcmc_sample_no = 10000 # number of steps (10000 was found to be sufficient in HMA) +mcmc_burn_no = 0 # number of steps to burn-in (0 records all steps in chain) +mcmc_step = None # step option (None or 'am') +thin_interval = 1 # thin interval if need to reduce file size (best to leave at 1 if space allows) +# Precipitation factor distribution options +precfactor_disttype = 'gamma' # distribution type ('gamma', 'lognormal', 'uniform') +precfactor_gamma_region_dict = {'Altun Shan': [8.52, 2.54], + 'Central Himalaya': [2.52, 1.38], + 'Central Tien Shan': [1.81, 1.37], + 'Dzhungarsky Alatau': [2.85, 1.49], + 'Eastern Himalaya': [3.03, 1.65], + 'Eastern Hindu Kush': [2.86, 1.87], + 'Eastern Kunlun Shan': [2.55, 1.45], + 'Eastern Pamir': [1.21, 1.48], + 'Eastern Tibetan Mountains': [3.92, 2.14], + 'Eastern Tien Shan': [1.86, 1.24], + 'Gangdise Mountains': [3.66, 1.73], + 'Hengduan Shan': [4.88, 1.95], + 'Karakoram': [1.29, 1.47], + 'Northern/Western Tien Shan': [2.61, 1.48], + 'Nyainqentanglha': [6.48, 2.33], + 'Pamir Alay': [3.3, 1.88], + 'Qilian Shan': [2.74, 1.36], + 'Tanggula Shan': [9.03, 2.92], + 'Tibetan Interior Mountains': [2.41, 1.35], + 'Western Himalaya': [2.15, 1.53], + 'Western Kunlun Shan': [1.21, 1.64], + 'Western Pamir': [1.85, 1.44]} +precfactor_gamma_alpha = 3.0 +precfactor_gamma_beta = 0.84 +precfactor_lognorm_mu = 0 +precfactor_lognorm_tau = 4 +precfactor_mu = 0 +precfactor_sigma = 1.5 +precfactor_boundlow = 0.5 +precfactor_boundhigh = 1.5 +precfactor_start = 1 +# Temperature bias distribution options +tempchange_disttype = 'normal' # distribution type ('normal', 'truncnormal', 'uniform') +tempchange_norm_region_dict = {'Altun Shan': [-0.60, 1.09], + 'Central Himalaya': [0.13, 0.9], + 'Central Tien Shan': [0.4, 0.85], + 'Dzhungarsky Alatau': [0.1, 0.51], + 'Eastern Himalaya': [-0.01, 0.87], + 'Eastern Hindu Kush': [0.08, 1.19], + 'Eastern Kunlun Shan': [0.13, 0.58], + 'Eastern Pamir': [0.93, 1.06], + 'Eastern Tibetan Mountains': [0.06, 0.45], + 'Eastern Tien Shan': [0.45, 1.58], + 'Gangdise Mountains': [-0.06, 0.41], + 'Hengduan Shan': [-0.28, 0.68], + 'Karakoram': [1.39, 1.54], + 'Northern/Western Tien Shan': [0.09, 0.66], + 'Nyainqentanglha': [-0.41, 0.83], + 'Pamir Alay': [-0.03, 0.72], + 'Qilian Shan': [0.22, 0.83], + 'Tanggula Shan': [-0.13, 0.33], + 'Tibetan Interior Mountains': [0.15, 0.75], + 'Western Himalaya': [0.11, 0.79], + 'Western Kunlun Shan': [2.27, 1.79], + 'Western Pamir': [0.54, 1.2]} +tempchange_mu = 0.91 +tempchange_sigma = 1.4 +tempchange_boundlow = -10 +tempchange_boundhigh = 10 +tempchange_start = tempchange_mu +tempchange_step = 0.1 +# Degree-day factor of snow distribution options +ddfsnow_disttype = 'truncnormal' # distribution type ('truncnormal', 'uniform') +ddfsnow_mu = 0.0041 +ddfsnow_sigma = 0.0015 +ddfsnow_boundlow = 0 +ddfsnow_boundhigh = np.inf +ddfsnow_start=ddfsnow_mu #%% MODEL PARAMETERS option_import_modelparams = 1 # 0: input values, 1: calibrated model parameters from netcdf files @@ -266,29 +297,79 @@ def glac_fromcsv(csv_fullfn, cn='RGIId'): ddfsnow = 0.0041 # degree-day factor of snow [m w.e. d-1 degC-1] ddfsnow_iceratio = 0.7 # Ratio degree-day factor snow snow to ice ddfice = ddfsnow / ddfsnow_iceratio # degree-day factor of ice [m w.e. d-1 degC-1] -tempchange = 0 # temperature bias [deg C] +tempchange = 1000 # temperature bias [deg C] lrgcm = -0.0065 # lapse rate from gcm to glacier [K m-1] lrglac = -0.0065 # lapse rate on glacier for bins [K m-1] tempsnow = 1.0 # temperature threshold for snow [deg C] (HH2015 used 1.5 degC +/- 1 degC) frontalablation_k = 2 # frontal ablation rate [yr-1] af = 0.7 # Bulk flow parameter for frontal ablation (m^-0.5) # Calving width dictionary to override RGI elevation bins, which can be highly inaccurate at the calving front -width_calving_dict_fullfn = main_directory + '/../Calving_data/calvingfront_widths.csv' -width_calving_df = pd.read_csv(width_calving_dict_fullfn) -width_calving_dict = dict(zip(width_calving_df.RGIId, width_calving_df.front_width_m)) -# Calving option (1=values from HH2015, 2=calibrate glaciers independently and use transfer fxns for others) +width_calving_dict = {'RGI60-01.01390':5730, + 'RGI60-01.03622':1860, + 'RGI60-01.10689':4690, + 'RGI60-01.13638':940, + 'RGI60-01.14443':6010, + 'RGI60-01.14683':2240, + 'RGI60-01.14878':1570, + 'RGI60-01.17807':2130, + 'RGI60-01.17840':980, + 'RGI60-01.17843':1030, + 'RGI60-01.17876':1390, + 'RGI60-01.20470':1200, + 'RGI60-01.20783':760, + 'RGI60-01.20841':420, + 'RGI60-01.20891':2050, + 'RGI60-01.21001':1580, + 'RGI60-01.23642':2820, + 'RGI60-01.26736':3560} +# Calving option +# option 1 - use values from HH2015 +# option 2 - calibrate each glacier independently, use transfer functions for uncalibrated glaciers option_frontalablation_k = 1 # Calving parameter dictionary (according to Supplementary Table 3 in HH2015) -frontalablation_k0dict_fullfn = main_directory + '/../Calving_data/frontalablation_k0_dict.csv' -frontalablation_k0dict_df = pd.read_csv(frontalablation_k0dict_fullfn) -frontalablation_k0dict = dict(zip(frontalablation_k0dict_df.O1Region, frontalablation_k0dict_df.k0)) +frontalablation_k0dict = { + 1: 3.4, + 2: 0, + 3: 0.2, + 4: 0.2, + 5: 0.5, + 6: 0.3, + 7: 0.5, + 8: 0, + 9: 0.2, + 10: 0, + 11: 0, + 12: 0, + 13: 0, + 14: 0, + 15: 0, + 16: 0, + 17: 6, + 18: 0, + 19: 1} # Model parameter column names and filepaths modelparams_colnames = ['lrgcm', 'lrglac', 'precfactor', 'precgrad', 'ddfsnow', 'ddfice', 'tempsnow', 'tempchange'] # Model parameter filepath -modelparams_fp = output_filepath + 'cal_opt' + str(option_calibration) + '/' -#modelparams_fp = output_filepath + 'cal_opt2_spc_20190806/' +#modelparams_fp = output_filepath + 'cal_opt' + str(option_calibration) + '/' +modelparams_fp = output_filepath + 'cal_opt2_spc_20190806/' +#if option_calibration == 1: +# modelparams_fp_dict = { +# 1: output_filepath + 'cal_opt1/reg1/', +# 3: output_filepath + 'cal_opt1/', +# 4: output_filepath + 'cal_opt1/', +# 6: output_filepath + 'cal_opt1/reg6/', +# 13: output_filepath + 'cal_opt1/reg13/', +# 14: output_filepath + 'cal_opt1/reg14/', +# 15: output_filepath + 'cal_opt1/reg15/'} +#elif option_calibration == 2: +# modelparams_fp_dict = { +# 13: output_filepath + 'cal_opt2_spc_20190806/', +# 14: output_filepath + 'cal_opt2_spc_20190806/', +# 15: output_filepath + 'cal_opt2_spc_20190806/'} + + #%% CLIMATE DATA # ERA-INTERIM (Reference data) # Variable names @@ -357,7 +438,7 @@ def glac_fromcsv(csv_fullfn, cn='RGIId'): #%% GLACIER DATA (RGI, ICE THICKNESS, ETC.) # ===== RGI DATA ===== # Filepath for RGI files -rgi_fp = main_directory + '/../RGI/rgi60/00_rgi60_attribs/' +rgi_filepath = main_directory + '/../RGI/rgi60/00_rgi60_attribs/' # Column names rgi_lat_colname = 'CenLat' rgi_lon_colname = 'CenLon' @@ -367,94 +448,82 @@ def glac_fromcsv(csv_fullfn, cn='RGIId'): rgi_glacno_float_colname = 'RGIId_float' # Column names from table to drop rgi_cols_drop = ['GLIMSId','BgnDate','EndDate','Status','Connect','Linkages','Name'] +# Dictionary of hypsometry filenames +rgi_dict = { + 1: '01_rgi60_Alaska.csv', + 3: '03_rgi60_ArcticCanadaNorth.csv', + 4: '04_rgi60_ArcticCanadaSouth.csv', + 6: '06_rgi60_Iceland.csv', + 7: '07_rgi60_Svalbard.csv', + 8: '08_rgi60_Scandinavia.csv', + 9: '09_rgi60_RussianArctic.csv', + 13: '13_rgi60_CentralAsia.csv', + 14: '14_rgi60_SouthAsiaWest.csv', + 15: '15_rgi60_SouthAsiaEast.csv', + 16: '16_rgi60_LowLatitudes.csv', + 17: '17_rgi60_SouthernAndes.csv'} # ===== ADDITIONAL DATA (hypsometry, ice thickness, width) ===== +# Option to shift all elevation bins by 20 m +# (required for Matthias' ice thickness and area since they are 20 m off, see email from May 24 2018) +option_shift_elevbins_20m = 1 +# Elevation band height [m] +binsize = 10 # Filepath for the hypsometry files -binsize = 10 # Elevation bin height [m] -hyps_data = 'Huss' # Hypsometry dataset (options: 'Huss' from GlacierMIP or 'Farinotti' from Farinotti etal 2019) -#hyps_data = 'Farinotti' # Hypsometry dataset (options: 'Huss' from GlacierMIP or 'Farinotti' from Farinotti etal 2019) - -if hyps_data == 'Farinotti': - option_shift_elevbins_20m = 0 # option to shift bins by 20 m (needed since off by 20 m, seem email 5/24/2018) - # Dictionary of hypsometry filenames - hyps_filepath = main_directory + '/../IceThickness_Farinotti/output/' - hyps_filedict = {1: 'area_km2_01_Farinotti2019_10m.csv', - 13: 'area_km2_13_Farinotti2019_10m.csv', - 14: 'area_km2_14_Farinotti2019_10m.csv', - 15: 'area_km2_15_Farinotti2019_10m.csv'} - hyps_colsdrop = ['RGIId'] - # Thickness data - thickness_filepath = main_directory + '/../IceThickness_Farinotti/output/' - thickness_filedict = {1: 'thickness_m_01_Farinotti2019_10m.csv', - 13: 'thickness_m_13_Farinotti2019_10m.csv', - 14: 'thickness_m_14_Farinotti2019_10m.csv', - 15: 'thickness_m_15_Farinotti2019_10m.csv'} - thickness_colsdrop = ['RGIId'] - # Width data - width_filepath = main_directory + '/../IceThickness_Farinotti/output/' - width_filedict = {1: 'width_km_01_Farinotti2019_10m.csv', - 13: 'width_km_13_Farinotti2019_10m.csv', - 14: 'width_km_14_Farinotti2019_10m.csv', - 15: 'width_km_15_Farinotti2019_10m.csv'} - width_colsdrop = ['RGIId'] - -elif hyps_data == 'Huss': - option_shift_elevbins_20m = 1 # option to shift bins by 20 m (needed since off by 20 m, seem email 5/24/2018) - # Dictionary of hypsometry filenames - # (Files from Matthias Huss should be manually pre-processed to be 'RGI-ID', 'Cont_range', and bins starting at 5) - hyps_filepath = main_directory + '/../IceThickness_Huss/bands_10m_DRR/' - hyps_filedict = { - 1: 'area_01_Huss_Alaska_10m.csv', - 3: 'area_RGI03_10.csv', - 4: 'area_RGI04_10.csv', - 6: 'area_RGI06_10.csv', - 7: 'area_RGI07_10.csv', - 8: 'area_RGI08_10.csv', - 9: 'area_RGI09_10.csv', - 13: 'area_13_Huss_CentralAsia_10m.csv', - 14: 'area_14_Huss_SouthAsiaWest_10m.csv', - 15: 'area_15_Huss_SouthAsiaEast_10m.csv', - 16: 'area_16_Huss_LowLatitudes_10m.csv', - 17: 'area_17_Huss_SouthernAndes_10m.csv'} - hyps_colsdrop = ['RGI-ID','Cont_range'] - # Thickness data - thickness_filepath = main_directory + '/../IceThickness_Huss/bands_10m_DRR/' - thickness_filedict = { - 1: 'thickness_01_Huss_Alaska_10m.csv', - 3: 'thickness_RGI03_10.csv', - 4: 'thickness_RGI04_10.csv', - 6: 'thickness_RGI06_10.csv', - 7: 'thickness_RGI07_10.csv', - 8: 'thickness_RGI08_10.csv', - 9: 'thickness_RGI09_10.csv', - 13: 'thickness_13_Huss_CentralAsia_10m.csv', - 14: 'thickness_14_Huss_SouthAsiaWest_10m.csv', - 15: 'thickness_15_Huss_SouthAsiaEast_10m.csv', - 16: 'thickness_16_Huss_LowLatitudes_10m.csv', - 17: 'thickness_17_Huss_SouthernAndes_10m.csv'} - thickness_colsdrop = ['RGI-ID','Cont_range'] - # Width data - width_filepath = main_directory + '/../IceThickness_Huss/bands_10m_DRR/' - width_filedict = { - 1: 'width_01_Huss_Alaska_10m.csv', - 3: 'width_RGI03_10.csv', - 4: 'width_RGI04_10.csv', - 6: 'width_RGI06_10.csv', - 7: 'width_RGI07_10.csv', - 8: 'width_RGI08_10.csv', - 9: 'width_RGI09_10.csv', - 13: 'width_13_Huss_CentralAsia_10m.csv', - 14: 'width_14_Huss_SouthAsiaWest_10m.csv', - 15: 'width_15_Huss_SouthAsiaEast_10m.csv', - 16: 'width_16_Huss_LowLatitudes_10m.csv', - 17: 'width_17_Huss_SouthernAndes_10m.csv'} - width_colsdrop = ['RGI-ID','Cont_range'] - -# Debris datasets -debris_fp = main_directory + '/../IceThickness_Farinotti/output/' -debris_filedict = {15: 'meltfactor_15_10m.csv'} -debris_colsdrop = ['RGIId'] - +hyps_filepath = main_directory + '/../IceThickness_Huss/bands_10m_DRR/' +# Dictionary of hypsometry filenames +# (Files from Matthias Huss should be manually pre-processed to be 'RGI-ID', 'Cont_range', and bins starting at 5) +hyps_filedict = { + 1: 'area_01_Huss_Alaska_10m.csv', + 3: 'area_RGI03_10.csv', + 4: 'area_RGI04_10.csv', + 6: 'area_RGI06_10.csv', + 7: 'area_RGI07_10.csv', + 8: 'area_RGI08_10.csv', + 9: 'area_RGI09_10.csv', + 13: 'area_13_Huss_CentralAsia_10m.csv', + 14: 'area_14_Huss_SouthAsiaWest_10m.csv', + 15: 'area_15_Huss_SouthAsiaEast_10m.csv', + 16: 'area_16_Huss_LowLatitudes_10m.csv', + 17: 'area_17_Huss_SouthernAndes_10m.csv'} +# Extra columns in hypsometry data that will be dropped +hyps_colsdrop = ['RGI-ID','Cont_range'] +# Filepath for the ice thickness files +thickness_filepath = main_directory + '/../IceThickness_Huss/bands_10m_DRR/' +# Dictionary of thickness filenames +thickness_filedict = { + 1: 'thickness_01_Huss_Alaska_10m.csv', + 3: 'thickness_RGI03_10.csv', + 4: 'thickness_RGI04_10.csv', + 6: 'thickness_RGI06_10.csv', + 7: 'thickness_RGI07_10.csv', + 8: 'thickness_RGI08_10.csv', + 9: 'thickness_RGI09_10.csv', + 13: 'thickness_13_Huss_CentralAsia_10m.csv', + 14: 'thickness_14_Huss_SouthAsiaWest_10m.csv', + 15: 'thickness_15_Huss_SouthAsiaEast_10m.csv', + 16: 'thickness_16_Huss_LowLatitudes_10m.csv', + 17: 'thickness_17_Huss_SouthernAndes_10m.csv'} +# Extra columns in ice thickness data that will be dropped +thickness_colsdrop = ['RGI-ID','Cont_range'] +# Filepath for the width files +width_filepath = main_directory + '/../IceThickness_Huss/bands_10m_DRR/' +# Dictionary of thickness filenames +width_filedict = { + 1: 'width_01_Huss_Alaska_10m.csv', + 3: 'width_RGI03_10.csv', + 4: 'width_RGI04_10.csv', + 6: 'width_RGI06_10.csv', + 7: 'width_RGI07_10.csv', + 8: 'width_RGI08_10.csv', + 9: 'width_RGI09_10.csv', + 13: 'width_13_Huss_CentralAsia_10m.csv', + 14: 'width_14_Huss_SouthAsiaWest_10m.csv', + 15: 'width_15_Huss_SouthAsiaEast_10m.csv', + 16: 'width_16_Huss_LowLatitudes_10m.csv', + 17: 'width_17_Huss_SouthernAndes_10m.csv'} +# Extra columns in ice thickness data that will be dropped +width_colsdrop = ['RGI-ID','Cont_range'] #%% MODEL TIME FRAME DATA # Models require complete data for each year such that refreezing, scaling, etc. can be calculated @@ -501,29 +570,6 @@ def glac_fromcsv(csv_fullfn, cn='RGIId'): shean_time2_cn = 't2' shean_area_cn = 'area_m2' -# ===== BERTHIER GEODETIC ===== -berthier_fp = main_directory + '/../DEMs/Berthier/output/' -#berthier_fn = 'AK_all_20190913_wextrapolations_1980cheat.csv' -berthier_fn = 'AK_all_20190913.csv' -berthier_rgi_glacno_cn = 'RGIId' -berthier_mb_cn = 'mb_mwea' -berthier_mb_err_cn = 'mb_mwea_sigma' -berthier_time1_cn = 't1' -berthier_time2_cn = 't2' -berthier_area_cn = 'area_km2' - -# ===== BRAUN GEODETIC ===== -braun_fp = main_directory + '/../DEMs/Braun/output/' -braun_fn = 'braun_AK_all_20190924_wlarsen_mcnabb_best.csv' -#braun_fn = 'braun_AK_all_20190924_wextrapolations.csv' -#braun_fn = 'braun_AK_all_20190924.csv' -braun_rgi_glacno_cn = 'RGIId' -braun_mb_cn = 'mb_mwea' -braun_mb_err_cn = 'mb_mwea_sigma' -braun_time1_cn = 't1' -braun_time2_cn = 't2' -braun_area_cn = 'area_km2' - # ===== BRUN GEODETIC ===== brun_fp = main_directory + '/../DEMs/' brun_fn = 'Brun_Nature2017_MB_glacier-wide.csv' @@ -630,8 +676,6 @@ def glac_fromcsv(csv_fullfn, cn='RGIId'): reg_dict_fn = main_directory + '/../qgis_himat/rgi60_HMA_dict_bolch.csv' reg_csv = pd.read_csv(reg_dict_fn) reg_dict = dict(zip(reg_csv.RGIId, reg_csv[reg_vn])) -else: - reg_dict = {} #%% MASS BALANCE MODEL OPTIONS # Initial surface type options @@ -660,17 +704,18 @@ def glac_fromcsv(csv_fullfn, cn='RGIId'): option_accumulation = 2 # 1: single threshold, 2: threshold +/- 1 deg using linear interpolation # Ablation model options -option_ablation = 2 # 1: monthly temp, 2: superimposed daily temps enabling melt near 0 (HH2015) +option_ablation = 1 # 1: monthly temp, 2: superimposed daily temps enabling melt near 0 (HH2015) option_ddf_firn = 1 # 0: ddf_firn = ddf_snow; 1: ddf_firn = mean of ddf_snow and ddf_ice ddfdebris = ddfice # add options for handling debris-covered glaciers # Refreezing model options -option_refreezing = 1 # 1: heat conduction (HH2015), 2: annual air temp (Woodward etal 1997) +option_refreezing = 2 # 1: heat conduction (HH2015), 2: annual air temp (Woodward etal 1997) if option_refreezing == 1: - rf_layers = 5 # number of layers for refreezing model (8 is sufficient - Matthias) -# rf_layers_max = 8 # number of layers to include for refreeze calculation + rf_layers = 8 # number of layers for refreezing model (8 is sufficient - Matthias) + rf_layers_max = 8 # number of layers to include for refreeze calculation rf_dz = 10/rf_layers # layer thickness (m) - rf_dsc = 3 # number of time steps for numerical stability (3 is sufficient - Matthias) +# rf_dz = 1 # layer thickness (m) + rf_dsc = 3 # number of time steps for numerical stability (3 is sufficient - Matthias) rf_meltcrit = 0.002 # critical amount of melt [m w.e.] for initializing refreezing module pp = 0.3 # additional refreeze water to account for water refreezing at bare-ice surface rf_dens_top = 300 # snow density at surface (kg m-3) @@ -729,7 +774,7 @@ def glac_fromcsv(csv_fullfn, cn='RGIId'): #%% DEBUGGING OPTIONS debug_refreeze = False -debug_mb = True +debug_mb = False # Pass variable to shell script diff --git a/pygemfxns_massbalance.py b/pygemfxns_massbalance.py index 664d90a2..c44445dc 100644 --- a/pygemfxns_massbalance.py +++ b/pygemfxns_massbalance.py @@ -7,10 +7,9 @@ import pygem_input as input #========= FUNCTIONS (alphabetical order) =================================== -def runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, width_initial, - elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, - glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, option_areaconstant=0, - constantarea_years=input.constantarea_years, frontalablation_k=None, +def runmassbalance(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, width_t0, elev_bins, + glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, + glacier_gcm_lrglac, dates_table, option_areaconstant=0, frontalablation_k=None, debug=False, debug_refreeze=False): """ Runs the mass balance and mass redistribution allowing the glacier to evolve. @@ -142,10 +141,8 @@ def runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, ice snowpack_remaining = np.zeros(nbins) dayspermonth = dates_table['daysinmonth'].values surfacetype_ddf = np.zeros(nbins) - glac_idx_initial = glacier_area_initial.nonzero()[0] - glacier_area_t0 = glacier_area_initial.copy() - icethickness_t0 = icethickness_initial.copy() - width_t0 = width_initial.copy() + glac_idx_initial = glacier_area_t0.nonzero()[0] + glac_area_initial = glacier_area_t0.copy() if input.option_refreezing == 1: # Refreezing layers density, volumetric heat capacity, and thermal conductivity rf_dens_expb = (input.rf_dens_bot / input.rf_dens_top)**(1/(input.rf_layers-1)) @@ -165,7 +162,6 @@ def runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, ice # Adjust sea level to account for disagreement between ice thickness estimates and glaciers classified by RGI as # marine-terminating. Modify the sea level, so sea level is consistent with lowest elevation bin that has ice. if glacier_rgi_table.loc['TermType'] == 1: -# print('glac_idx_initial:', glac_idx_initial) sea_level = elev_bins[glac_idx_initial[0]] - (elev_bins[1] - elev_bins[0]) / 2 # glac_idx_initial is used with advancing glaciers to ensure no bands are added in a discontinuous section @@ -190,15 +186,15 @@ def runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, ice # Check ice still exists: if icethickness_t0.max() > 0: - if debug: - print(year, 'max ice thickness [m]:', icethickness_t0.max()) +# if debug: +# print(year, 'max ice thickness [m]:', icethickness_t0.max()) # Glacier indices glac_idx_t0 = glacier_area_t0.nonzero()[0] # Off-glacier area and indices if option_areaconstant == 0: - offglac_bin_area_annual[:,year] = glacier_area_initial - glacier_area_t0 + offglac_bin_area_annual[:,year] = glac_area_initial - glacier_area_t0 offglac_idx = np.where(offglac_bin_area_annual[:,year] > 0)[0] @@ -314,12 +310,6 @@ def runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, ice # DDF based on surface type [m w.e. degC-1 day-1] for surfacetype_idx in surfacetype_ddf_dict: surfacetype_ddf[surfacetype == surfacetype_idx] = surfacetype_ddf_dict[surfacetype_idx] - if input.option_surfacetype_debris == 1: - print('\n\nLOAD THE MELTFACTOR DATASET over areas that are not firn\n\n') - - if year == 0 and month == 0: - print('\nDELETE ME\n surfacetype_ddf[glac_idx]:', surfacetype_ddf[glac_idx_t0]) - bin_meltglac[glac_idx_t0,step] = surfacetype_ddf[glac_idx_t0] * melt_energy_available[glac_idx_t0] # TOTAL MELT (snow + glacier) # off-glacier need to include melt of refreeze because there are no glacier dynamics, @@ -708,16 +698,12 @@ def runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, ice surfacetype, firnline_idx = surfacetypebinsannual(surfacetype, glac_bin_massbalclim_annual, year) # MASS REDISTRIBUTION - # Mass redistribution ignored for calibration and spinup years (glacier properties constant) - if (option_areaconstant == 1) or (year < input.spinupyears) or (year < constantarea_years): + # Mass redistribution ignored for calibration and spinup years (glacier properties constant) + if (option_areaconstant == 1) or (year < input.spinupyears) or (year < input.constantarea_years): glacier_area_t1 = glacier_area_t0 icethickness_t1 = icethickness_t0 - width_t1 = width_t0 + width_t1 = width_t0 else: - - if debug: - print('area is changing') - # First, remove volume lost to frontal ablation # changes to _t0 not _t1, since t1 will be done in the mass redistribution if glac_bin_frontalablation[:,step].max() > 0: @@ -758,8 +744,7 @@ def runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, ice glacier_area_t1, icethickness_t1, width_t1 = ( massredistributionHuss(glacier_area_t0, icethickness_t0, width_t0, glac_bin_massbalclim_annual, year, glac_idx_initial, - glacier_area_initial, - debug=False)) + glac_area_initial)) # update surface type for bins that have retreated surfacetype[glacier_area_t1 == 0] = 0 # update surface type for bins that have advanced @@ -774,9 +759,9 @@ def runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, ice # Record glacier properties (area [km**2], thickness [m], width [km]) # if first year, record initial glacier properties (area [km**2], ice thickness [m ice], width [km]) if year == 0: - glac_bin_area_annual[:,year] = glacier_area_initial - glac_bin_icethickness_annual[:,year] = icethickness_initial - glac_bin_width_annual[:,year] = width_initial + glac_bin_area_annual[:,year] = glacier_area_t0 + glac_bin_icethickness_annual[:,year] = icethickness_t0 + glac_bin_width_annual[:,year] = width_t0 # record the next year's properties as well # 'year + 1' used so the glacier properties are consistent with mass balance computations glac_bin_icethickness_annual[:,year + 1] = icethickness_t1 @@ -903,10 +888,20 @@ def calc_glacwide(bin_var, area_bin, area_wide): """Calculate glacier wide sum of a variable""" var_wide = np.zeros(bin_var.shape[1]) var_wide_mkm2 = (bin_var * area_bin).sum(axis=0) - var_wide[var_wide_mkm2 > 0] = var_wide_mkm2[var_wide_mkm2 > 0] / area_wide[var_wide_mkm2 > 0] + var_wide[var_wide_mkm2 > 0] = var_wide_mkm2[var_wide_mkm2 > 0] / area_wide[var_wide_mkm2 > 0] + +# print('melt_wide_mkm2.sum() 2:', var_wide_mkm2.sum()) + + +# glac_wide_melt = calc_glacwide(bin_melt, glac_bin_area, glac_wide_area) +# glac_wide_melt_mkm2 = (glac_bin_melt * glac_bin_area).sum(axis=0) +# glac_wide_melt2 = np.zeros(glac_wide_melt.shape) +# glac_wide_melt2[glac_wide_melt_mkm2 > 0] = (glac_wide_melt_mkm2[glac_wide_melt_mkm2 > 0] / +# glac_wide_area[glac_wide_melt_mkm2 > 0]) + + return var_wide - def calc_runoff(prec_wide, melt_wide, refreeze_wide, area_wide): """ Calculate runoff from precipitation, melt, and refreeze [units: m3] @@ -916,7 +911,7 @@ def calc_runoff(prec_wide, melt_wide, refreeze_wide, area_wide): def massredistributionHuss(glacier_area_t0, icethickness_t0, width_t0, glac_bin_massbalclim_annual, year, - glac_idx_initial, glacier_area_initial, debug=False): + glac_idx_initial, glac_area_initial, debug=False): """ Mass redistribution according to empirical equations from Huss and Hock (2015) accounting for retreat/advance. glac_idx_initial is required to ensure that the glacier does not advance to area where glacier did not exist before @@ -936,7 +931,7 @@ def massredistributionHuss(glacier_area_t0, icethickness_t0, width_t0, glac_bin_ Count of the year of model run (first year is 0) glac_idx_initial : np.ndarray Initial glacier indices - glacier_area_initial : np.ndarray + glac_area_initial : np.ndarray Initial glacier array used to determine average terminus area in event that glacier is only one bin debug : Boolean option to turn on print statements for development or debugging of code (default False) @@ -956,9 +951,6 @@ def massredistributionHuss(glacier_area_t0, icethickness_t0, width_t0, glac_bin_ # Annual glacier-wide volume change [km**3] glacier_volumechange = ((glac_bin_massbalclim_annual[:, year] / 1000 * input.density_water / input.density_ice * glacier_area_t0).sum()) - if debug: - print('\nDebugging Mass Redistribution Huss function\n') - print('glacier volume change:', glacier_volumechange) # units: [m w.e.] * (1 km / 1000 m) * (1000 kg / (1 m water * m**2) * (1 m ice * m**2 / 900 kg) * [km**2] # = km**3 ice # If volume loss is less than the glacier volume, then redistribute mass loss/gains across the glacier; @@ -979,11 +971,7 @@ def massredistributionHuss(glacier_area_t0, icethickness_t0, width_t0, glac_bin_ # Option 1: apply mass redistribution using Huss' empirical geometry change equations icethickness_t1, glacier_area_t1, width_t1, icethickness_change, glacier_volumechange_remaining = ( massredistributioncurveHuss(icethickness_t0, glacier_area_t0, width_t0, glac_idx_t0, - glacier_volumechange, glac_bin_massbalclim_annual[:, year], - debug=False)) - if debug: - print(icethickness_t0.max(), icethickness_t1.max(), glacier_area_t0.max(), glacier_area_t1.max()) - + glacier_volumechange, glac_bin_massbalclim_annual[:, year])) # Glacier retreat # if glacier retreats (ice thickness < 0), then ice thickness is set to zero, and some volume change will need # to be redistributed across the rest of the glacier @@ -1007,9 +995,7 @@ def massredistributionHuss(glacier_area_t0, icethickness_t0, width_t0, glac_bin_ glacier_volumechange_remaining_retreated, massbal_clim_retreat)) # Glacier advances # if glacier advances (ice thickness change exceeds threshold), then redistribute mass gain in new bins - while (icethickness_change > input.icethickness_advancethreshold).any() == True: - if debug: - print('advancing glacier') + while (icethickness_change > input.icethickness_advancethreshold).any() == True: # Record glacier area and ice thickness before advance corrections applied glacier_area_t1_raw = glacier_area_t1.copy() icethickness_t1_raw = icethickness_t1.copy() @@ -1069,7 +1055,7 @@ def massredistributionHuss(glacier_area_t0, icethickness_t0, width_t0, glac_bin_ if glac_idx_terminus_initial.shape[0] <= 1: glac_idx_terminus_initial = glac_idx_initial.copy() terminus_area_avg = ( - glacier_area_initial[glac_idx_terminus_initial[1]: + glac_area_initial[glac_idx_terminus_initial[1]: glac_idx_terminus_initial[glac_idx_terminus_initial.shape[0]-1]+1].mean()) # Check if the last bin's area is below the terminus' average and fill it up if it is if (glacier_area_t1[glac_idx_terminus[0]] < terminus_area_avg) and (icethickness_t0[glac_idx_terminus[0]] < @@ -1148,7 +1134,7 @@ def massredistributionHuss(glacier_area_t0, icethickness_t0, width_t0, glac_bin_ def massredistributioncurveHuss(icethickness_t0, glacier_area_t0, width_t0, glac_idx_t0, glacier_volumechange, - massbalclim_annual, debug=False): + massbalclim_annual): """ Apply the mass redistribution curves from Huss and Hock (2015). This is paired with massredistributionHuss, which takes into consideration retreat and advance. @@ -1186,8 +1172,6 @@ def massredistributioncurveHuss(icethickness_t0, glacier_area_t0, width_t0, glac glacier_volumechange_remaining : float Glacier volume change remaining, which could occur if there is less ice in a bin than melt, i.e., retreat """ - if debug: - print('\nDebugging mass redistribution curve Huss\n') # Apply Huss redistribution if there are at least 3 elevation bands; otherwise, use the mass balance # reset variables icethickness_t1 = np.zeros(glacier_area_t0.shape) @@ -1219,8 +1203,6 @@ def massredistributioncurveHuss(icethickness_t0, glacier_area_t0, width_t0, glac icethicknesschange_norm[icethicknesschange_norm < 0] = 0 # Huss' ice thickness scaling factor, fs_huss [m ice] fs_huss = glacier_volumechange / (glacier_area_t0 * icethicknesschange_norm).sum() * 1000 - if debug: - print('fs_huss:', fs_huss) # units: km**3 / (km**2 * [-]) * (1000 m / 1 km) = m ice # Volume change [km**3 ice] bin_volumechange = icethicknesschange_norm * fs_huss / 1000 * glacier_area_t0 @@ -1234,21 +1216,6 @@ def massredistributioncurveHuss(icethickness_t0, glacier_area_t0, width_t0, glac icethickness_t1[glac_idx_t0] = ((icethickness_t0[glac_idx_t0] / 1000)**1.5 + (icethickness_t0[glac_idx_t0] / 1000)**0.5 * bin_volumechange[glac_idx_t0] / glacier_area_t0[glac_idx_t0]) - -# print('ice thickness:', icethickness_t0[81], -# 'bin_volumechange:', bin_volumechange[81], -# 'glacier_area:', glacier_area_t0[81], -# 'thickness_change:', bin_volumechange[81] / glacier_area_t0[81]) -# print('test:', (icethickness_t0[81] / 1000)**3/2) -# print(((icethickness_t0[81] / 1000)**1.5 + -# (icethickness_t0[81] / 1000)**0.5 * bin_volumechange[81] / -# glacier_area_t0[81])) -# -# print(np.where(np.isnan(icethickness_t1))) -# print(bin_volumechange[glac_idx_t0].max()) - if debug: - print('icethickness_max:', icethickness_t1.max()) - icethickness_t1[icethickness_t1 < 0] = 0 icethickness_t1[glac_idx_t0] = icethickness_t1[glac_idx_t0]**(2/3) * 1000 # Glacier area for parabola [km**2] diff --git a/pygemfxns_modelsetup.py b/pygemfxns_modelsetup.py index 4f92d25e..fefe062d 100644 --- a/pygemfxns_modelsetup.py +++ b/pygemfxns_modelsetup.py @@ -10,11 +10,11 @@ import pygem_input as input -def datesmodelrun(startyear=input.startyear, endyear=input.endyear, spinupyears=input.spinupyears, +def datesmodelrun(startyear=input.startyear, endyear=input.endyear, spinupyears=input.spinupyears, option_wateryear=input.option_wateryear): """ Create table of year, month, day, water year, season and number of days in the month. - + Parameters ---------- startyear : int @@ -23,7 +23,7 @@ def datesmodelrun(startyear=input.startyear, endyear=input.endyear, spinupyears= ending year spinupyears : int number of spinup years - + Returns ------- dates_table : pd.DataFrame @@ -56,7 +56,7 @@ def datesmodelrun(startyear=input.startyear, endyear=input.endyear, spinupyears= # Generate dates_table using date_range function if input.timestep == 'monthly': # Automatically generate dates from start date to end data using a monthly frequency (MS), which generates - # monthly data using the 1st of each month + # monthly data using the 1st of each month dates_table = pd.DataFrame({'date' : pd.date_range(startdate, enddate, freq='MS')}) # Select attributes of DateTimeIndex (dt.year, dt.month, and dt.daysinmonth) dates_table['year'] = dates_table['date'].dt.year @@ -116,12 +116,12 @@ def datesmodelrun(startyear=input.startyear, endyear=input.endyear, spinupyears= def daysinmonth(year, month): """ Return days in month based on the month and year - + Parameters ---------- year : str month : str - + Returns ------- integer of the days in the month @@ -131,21 +131,21 @@ def daysinmonth(year, month): 1:31, 2:29, 3:31, 4:30, 5:31, 6:30, 7:31, 8:31, 9:30, 10:31, 11:30, 12:31} else: daysinmonth_dict = { - 1:31, 2:28, 3:31, 4:30, 5:31, 6:30, 7:31, 8:31, 9:30, 10:31, 11:30, 12:31} + 1:31, 2:28, 3:31, 4:30, 5:31, 6:30, 7:31, 8:31, 9:30, 10:31, 11:30, 12:31} return daysinmonth_dict[month] def hypsometrystats(hyps_table, thickness_table): """Calculate the volume and mean associated with the hypsometry data. - - Output is a series of the glacier volume [km**3] and mean elevation values [m a.s.l.]. + + Output is a series of the glacier volume [km**3] and mean elevation values [m a.s.l.]. """ # Glacier volume [km**3] glac_volume = (hyps_table * thickness_table/1000).sum(axis=1).values # Mean glacier elevation glac_hyps_mean = np.zeros(glac_volume.shape) - glac_hyps_mean[glac_volume > 0] = ((hyps_table[glac_volume > 0].values * - hyps_table[glac_volume > 0].columns.values.astype(int)).sum(axis=1) / + glac_hyps_mean[glac_volume > 0] = ((hyps_table[glac_volume > 0].values * + hyps_table[glac_volume > 0].columns.values.astype(int)).sum(axis=1) / hyps_table[glac_volume > 0].values.sum(axis=1)) # Median computations # main_glac_hyps_cumsum = np.cumsum(hyps_table, axis=1) @@ -162,10 +162,10 @@ def hypsometrystats(hyps_table, thickness_table): def import_Husstable(rgi_table, filepath, filedict, drop_col_names, indexname=input.indexname): """Use the dictionary specified by the user to extract the desired variable. The files must be in the proper units (ice thickness [m], area [km2], width [km]) and should be pre-processed. - + Output is a Pandas DataFrame of the variable for all the glaciers in the model run (rows = GlacNo, columns = elevation bins). - + Line Profiling: Loading in the table takes the most time (~2.3 s) """ #%% @@ -178,23 +178,23 @@ def import_Husstable(rgi_table, filepath, filedict, drop_col_names, indexname=in region = int(i.split('.')[0]) glac_no_only = i.split('.')[1] glac_no_byregion[int(region)].append(glac_no_only) - + # Load data for each region for count, region in enumerate(rgi_regionsO1): # Select regional data for indexing - glac_no = sorted(glac_no_byregion[region]) - rgi_table_region = rgi_table.iloc[np.where(rgi_table.O1Region.values == region)[0]] - + glac_no = sorted(glac_no_byregion[region]) + rgi_table_region = rgi_table.iloc[np.where(rgi_table.O1Region.values == region)[0]] + # Load table ds = pd.read_csv(filepath + filedict[region]) - + # Select glaciers based on 01Index value from main_glac_rgi table - # as long as Huss tables have all rows associated with rgi attribute table, + # as long as Huss tables have all rows associated with rgi attribute table, # then this shortcut works and saves time glac_table = ds.iloc[rgi_table_region['O1Index'].values] # glac_table = pd.DataFrame() # if input.rgi_regionsO2 == 'all' and input.rgi_glac_number == 'all': - # glac_table = ds + # glac_table = ds # elif input.rgi_regionsO2 != 'all' and input.rgi_glac_number == 'all': # glac_table = ds.iloc[rgi_table['O1Index'].values] # elif input.rgi_regionsO2 == 'all' and input.rgi_glac_number != 'all': @@ -222,7 +222,7 @@ def import_Husstable(rgi_table, filepath, filedict, drop_col_names, indexname=in for new_col in new_cols: glac_table[new_col] = 0 glac_table_all = glac_table_all.append(glac_table) - + # Clean up table and re-index (make copy to avoid SettingWithCopyWarning) glac_table_copy = glac_table_all.copy() glac_table_copy.reset_index(drop=True, inplace=True) @@ -237,16 +237,16 @@ def import_Husstable(rgi_table, filepath, filedict, drop_col_names, indexname=in glac_table_copy = glac_table_copy.iloc[:,2:] glac_table_copy.columns = colnames return glac_table_copy - + #%% - + # ds = pd.read_csv(filepath + filedict[rgi_regionsO1[0]]) # # Select glaciers based on 01Index value from main_glac_rgi table # # as long as Huss tables have all rows associated with rgi attribute table, then this shortcut works and saves time # glac_table = ds.iloc[rgi_table['O1Index'].values] ## glac_table = pd.DataFrame() ## if input.rgi_regionsO2 == 'all' and input.rgi_glac_number == 'all': -## glac_table = ds +## glac_table = ds ## elif input.rgi_regionsO2 != 'all' and input.rgi_glac_number == 'all': ## glac_table = ds.iloc[rgi_table['O1Index'].values] ## elif input.rgi_regionsO2 == 'all' and input.rgi_glac_number != 'all': @@ -283,8 +283,8 @@ def selectcalibrationdata(main_glac_rgi): rgi_region = int(main_glac_rgi.loc[main_glac_rgi.index.values[0],'RGIId'].split('-')[1].split('.')[0]) ds = pd.read_csv(input.cal_mb_filepath + input.cal_mb_filedict[rgi_region]) main_glac_calmassbal = np.zeros((main_glac_rgi.shape[0],4)) - ds[input.rgi_O1Id_colname] = ((ds[input.cal_rgi_colname] % 1) * 10**5).round(0).astype(int) - ds_subset = ds[[input.rgi_O1Id_colname, input.massbal_colname, input.massbal_uncertainty_colname, + ds[input.rgi_O1Id_colname] = ((ds[input.cal_rgi_colname] % 1) * 10**5).round(0).astype(int) + ds_subset = ds[[input.rgi_O1Id_colname, input.massbal_colname, input.massbal_uncertainty_colname, input.massbal_time1, input.massbal_time2]].values rgi_O1Id = main_glac_rgi[input.rgi_O1Id_colname].values for glac in range(rgi_O1Id.shape[0]): @@ -300,25 +300,26 @@ def selectcalibrationdata(main_glac_rgi): # If there is no mass balance data available for the glacier, then set as NaN main_glac_calmassbal[glac,:] = np.empty(4) main_glac_calmassbal[glac,:] = np.nan - main_glac_calmassbal = pd.DataFrame(main_glac_calmassbal, - columns=[input.massbal_colname, input.massbal_uncertainty_colname, + main_glac_calmassbal = pd.DataFrame(main_glac_calmassbal, + columns=[input.massbal_colname, input.massbal_uncertainty_colname, input.massbal_time1, input.massbal_time2]) return main_glac_calmassbal def selectglaciersrgitable(glac_no=None, - rgi_regionsO1=None, - rgi_regionsO2=None, + rgi_regionsO1=None, + rgi_regionsO2=None, rgi_glac_number=None, - rgi_fp=input.rgi_fp, + rgi_filepath=input.rgi_filepath, + rgi_dict=input.rgi_dict, rgi_cols_drop=input.rgi_cols_drop, rgi_O1Id_colname=input.rgi_O1Id_colname, rgi_glacno_float_colname=input.rgi_glacno_float_colname, indexname=input.indexname): """ - Select all glaciers to be used in the model run according to the regions and glacier numbers defined by the RGI + Select all glaciers to be used in the model run according to the regions and glacier numbers defined by the RGI glacier inventory. This function returns the rgi table associated with all of these glaciers. - + glac_no : list of strings list of strings of RGI glacier numbers (e.g., ['1.00001', '13.00001']) rgi_regionsO1 : list of integers @@ -327,10 +328,10 @@ def selectglaciersrgitable(glac_no=None, list of integers of RGI order 2 regions or simply 'all' for all the order 2 regions rgi_glac_number : list of strings list of RGI glacier numbers without the region (e.g., ['00001', '00002']) - + Output: Pandas DataFrame of the glacier statistics for each glacier in the model run (rows = GlacNo, columns = glacier statistics) - """ + """ if glac_no is not None: glac_no_byregion = {} rgi_regionsO1 = [int(i.split('.')[0]) for i in glac_no] @@ -341,28 +342,22 @@ def selectglaciersrgitable(glac_no=None, region = i.split('.')[0] glac_no_only = i.split('.')[1] glac_no_byregion[int(region)].append(glac_no_only) - + for region in rgi_regionsO1: glac_no_byregion[region] = sorted(glac_no_byregion[region]) - + # Create an empty dataframe rgi_regionsO1 = sorted(rgi_regionsO1) glacier_table = pd.DataFrame() for region in rgi_regionsO1: - + if glac_no is not None: rgi_glac_number = glac_no_byregion[region] - -# if len(rgi_glac_number) < 50: - - for i in os.listdir(rgi_fp): - if i.startswith(str(region).zfill(2)) and i.endswith('.csv'): - rgi_fn = i + try: - csv_regionO1 = pd.read_csv(rgi_fp + rgi_fn) + csv_regionO1 = pd.read_csv(rgi_filepath + rgi_dict[region]) except: - csv_regionO1 = pd.read_csv(rgi_fp + rgi_fn, encoding='latin1') - + csv_regionO1 = pd.read_csv(rgi_filepath + rgi_dict[region], encoding='latin1') # Populate glacer_table with the glaciers of interest if rgi_regionsO2 == 'all' and rgi_glac_number == 'all': print("All glaciers within region(s) %s are included in this model run." % (region)) @@ -371,56 +366,49 @@ def selectglaciersrgitable(glac_no=None, else: glacier_table = pd.concat([glacier_table, csv_regionO1], axis=0) elif rgi_regionsO2 != 'all' and rgi_glac_number == 'all': - print("All glaciers within subregion(s) %s in region %s are included in this model run." % + print("All glaciers within subregion(s) %s in region %s are included in this model run." % (rgi_regionsO2, region)) for regionO2 in rgi_regionsO2: if glacier_table.empty: glacier_table = csv_regionO1.loc[csv_regionO1['O2Region'] == regionO2] else: - glacier_table = (pd.concat([glacier_table, csv_regionO1.loc[csv_regionO1['O2Region'] == + glacier_table = (pd.concat([glacier_table, csv_regionO1.loc[csv_regionO1['O2Region'] == regionO2]], axis=0)) else: - if len(rgi_glac_number) < 20: - print("%s glaciers in region %s are included in this model run: %s" % (len(rgi_glac_number), region, - rgi_glac_number)) - else: - print("%s glaciers in region %s are included in this model run: %s and more" % - (len(rgi_glac_number), region, rgi_glac_number[0:50])) - - rgiid_subset = ['RGI60-' + str(region).zfill(2) + '.' + x for x in rgi_glac_number] - rgiid_all = list(csv_regionO1.RGIId.values) - rgi_idx = [rgiid_all.index(x) for x in rgiid_subset] - if glacier_table.empty: - glacier_table = csv_regionO1.loc[rgi_idx] - else: - glacier_table = (pd.concat([glacier_table, csv_regionO1.loc[rgi_idx]], - axis=0)) - + print("%s glaciers in region %s are included in this model run: %s" % (len(rgi_glac_number), region, + rgi_glac_number)) + for x_glac in rgi_glac_number: + glac_id = 'RGI60-' + str(region).zfill(2) + '.' + x_glac + if glacier_table.empty: + glacier_table = csv_regionO1.loc[csv_regionO1['RGIId'] == glac_id] + else: + glacier_table = (pd.concat([glacier_table, csv_regionO1.loc[csv_regionO1['RGIId'] == glac_id]], + axis=0)) glacier_table = glacier_table.copy() # reset the index so that it is in sequential order (0, 1, 2, etc.) glacier_table.reset_index(inplace=True) # change old index to 'O1Index' to be easier to recall what it is glacier_table.rename(columns={'index': 'O1Index'}, inplace=True) - # Record the reference date + # Record the reference date glacier_table['RefDate'] = glacier_table['BgnDate'] # if there is an end date, then roughly average the year enddate_idx = glacier_table.loc[(glacier_table['EndDate'] > 0), 'EndDate'].index.values glacier_table.loc[enddate_idx,'RefDate'] = ( - np.mean((glacier_table.loc[enddate_idx,['BgnDate', 'EndDate']].values / 10**4).astype(int), - axis=1).astype(int) * 10**4 + 9999) + np.mean((glacier_table.loc[enddate_idx,['BgnDate', 'EndDate']].values / 10**4).astype(int), + axis=1).astype(int) * 10**4 + 9999) # drop columns of data that is not being used glacier_table.drop(rgi_cols_drop, axis=1, inplace=True) # add column with the O1 glacier numbers glacier_table[rgi_O1Id_colname] = ( glacier_table['RGIId'].str.split('.').apply(pd.Series).loc[:,1].astype(int)) glacier_table['rgino_str'] = [x.split('-')[1] for x in glacier_table.RGIId.values] - glacier_table[rgi_glacno_float_colname] = (np.array([np.str.split(glacier_table['RGIId'][x],'-')[1] + glacier_table[rgi_glacno_float_colname] = (np.array([np.str.split(glacier_table['RGIId'][x],'-')[1] for x in range(glacier_table.shape[0])]).astype(float)) # set index name glacier_table.index.name = indexname - + print("This study is focusing on %s glaciers in region %s" % (glacier_table.shape[0], rgi_regionsO1)) - + return glacier_table # OPTION 2: CUSTOMIZE REGIONS USING A SHAPEFILE that specifies the @@ -436,4 +424,4 @@ def selectglaciersrgitable(glac_no=None, # regions. # Development Note: if create another method for selecting glaciers, # make sure that update way to select glacier - # hypsometry as well. + # hypsometry as well. \ No newline at end of file diff --git a/pygemfxns_output.py b/pygemfxns_output.py deleted file mode 100644 index fd6a9207..00000000 --- a/pygemfxns_output.py +++ /dev/null @@ -1,777 +0,0 @@ -""" Functions that pertain to creating and writing output for the model results.""" - -# External Libraries -import numpy as np -import netCDF4 as nc -from time import strftime -import matplotlib.pyplot as plt -# Local Libraries -import pygem_input as input - - -def netcdfcreate(filename, main_glac_rgi, main_glac_hyps, dates_table, output_filepath=input.output_filepath, nsims=1): - """ - Create a netcdf file to store the desired output - - Parameters - ---------- - filename : str - netcdf filename that is being created - main_glac_rgi : pandas dataframe - dataframe containing relevant rgi glacier information - main_glac_hyps : numpy array - glacier hypsometry of every glacier included in model run - dates_table : pandas dataframe - table of the dates, months, days in month, etc. - output_filepath : str - output filepath of where to store netcdf file - nsims : int - number of simulations included - - Returns - ------- - creates a netcdf file with the proper structure to be fill in by the model results - """ - # Annual columns - annual_columns = np.unique(dates_table['wateryear'].values)[0:int(dates_table.shape[0]/12)] - # Netcdf file path and name - fullfilename = output_filepath + filename - # Create netcdf file ('w' will overwrite existing files, 'r+' will open existing file to write) - netcdf_output = nc.Dataset(fullfilename, 'w', format='NETCDF4') - # ===== Global attributes ===== - netcdf_output.description = 'Results from glacier evolution model' - netcdf_output.history = 'Created ' + str(strftime("%Y-%m-%d %H:%M:%S")) - netcdf_output.source = 'Python Glacier Evolution Model' - # ===== Dimensions ===== - glac_idx = netcdf_output.createDimension('glac_idx', None) - if input.timestep == 'monthly': - time = netcdf_output.createDimension('time', dates_table.shape[0] - input.spinupyears * 12) - year = netcdf_output.createDimension('year', annual_columns.shape[0] - input.spinupyears) - year_plus1 = netcdf_output.createDimension('year_plus1', annual_columns.shape[0] - input.spinupyears + 1) - glac_table = netcdf_output.createDimension('glac_table', main_glac_rgi.shape[1]) - elevbin = netcdf_output.createDimension('elevbin', main_glac_hyps.shape[1]) - sim = netcdf_output.createDimension('sim', nsims) - # Variables associated with dimensions - sims = netcdf_output.createVariable('sim', np.int32, ('sim',)) - sims.long_name = 'simulation number' - sims[:] = range(0, nsims) - glaciers = netcdf_output.createVariable('glac_idx', np.int32, ('glac_idx',)) - glaciers.long_name = "glacier index" - glaciers.standard_name = input.indexname - glaciers.comment = "Glacier index value that refers to the glacier table" - glaciers[:] = main_glac_rgi.index.values - times = netcdf_output.createVariable('time', np.float64, ('time',)) - times.long_name = "date" - times.units = "days since 1900-01-01 00:00:00" - times.calendar = "gregorian" - if input.timestep == 'monthly': - times[:] = (nc.date2num(dates_table.loc[input.spinupyears*12:dates_table.shape[0]+1,'date'].tolist(), - units = times.units, calendar = times.calendar)) - years = netcdf_output.createVariable('year', np.int32, ('year',)) - years.long_name = "year" - if input.option_wateryear == 1: - years.units = 'water year' - elif input.option_wateryear == 2: - years.units = 'calendar year' - elif input.option_wateryear == 3: - years.units = 'custom year' - years[:] = annual_columns[input.spinupyears:annual_columns.shape[0]] - # years_plus1 adds an additional year such that the change in glacier dimensions (area, etc.) is recorded - years_plus1 = netcdf_output.createVariable('year_plus1', np.int32, ('year_plus1',)) - years_plus1.long_name = "year with additional year to record glacier dimension changes" - if input.option_wateryear == 1: - years_plus1.units = 'water year' - elif input.option_wateryear == 2: - years_plus1.units = 'calendar year' - elif input.option_wateryear == 3: - years_plus1.units = 'custom year' - years_plus1[:] = np.concatenate((annual_columns[input.spinupyears:annual_columns.shape[0]], - np.array([annual_columns[annual_columns.shape[0]-1]+1]))) - glacier_table_header = netcdf_output.createVariable('glacier_table_header',str,('glac_table',)) - glacier_table_header.long_name = "glacier table header" - glacier_table_header[:] = main_glac_rgi.columns.values - glacier_table_header.comment = "Column names of RGI table and any added columns. See 'glac_table' for values." - glacier_table = netcdf_output.createVariable('glacier_table',np.float64,('glac_idx','glac_table',)) - glacier_table.long_name = "glacier table values" - glacier_table[:] = main_glac_rgi.values - glacier_table.comment = "Values of RGI table and any added columns. See 'glac_table_header' for column names" - elevbins = netcdf_output.createVariable('elevbin', np.int32, ('elevbin',)) - elevbins.long_name = "center of elevation bin" - elevbins.units = "m a.s.l." - elevbins[:] = main_glac_hyps.columns.values - - # ===== Output Variables ===== - if input.output_package == 1: - # Package 1 "Raw Package" output [units: m w.e. unless otherwise specified]: - # monthly variables for each bin (temp, prec, acc, refreeze, snowpack, melt, frontalablation, massbal_clim) - # annual variables for each bin (area, icethickness, width, surfacetype) - temp_bin_monthly = netcdf_output.createVariable('temp_bin_monthly', np.float64, ('glac_idx', 'elevbin', 'time')) - temp_bin_monthly.long_name = "air temperature" - temp_bin_monthly.units = "degC" - prec_bin_monthly = netcdf_output.createVariable('prec_bin_monthly', np.float64, ('glac_idx', 'elevbin', 'time')) - prec_bin_monthly.long_name = "liquid precipitation" - prec_bin_monthly.units = "m" - acc_bin_monthly = netcdf_output.createVariable('acc_bin_monthly', np.float64, ('glac_idx', 'elevbin', 'time')) - acc_bin_monthly.long_name = "accumulation" - acc_bin_monthly.units = "m w.e." - refreeze_bin_monthly = netcdf_output.createVariable('refreeze_bin_monthly', np.float64, - ('glac_idx', 'elevbin', 'time')) - refreeze_bin_monthly.long_name = "refreezing" - refreeze_bin_monthly.units = "m w.e." - snowpack_bin_monthly = netcdf_output.createVariable('snowpack_bin_monthly', np.float64, - ('glac_idx', 'elevbin', 'time')) - snowpack_bin_monthly.long_name = "snowpack on the glacier surface" - snowpack_bin_monthly.units = "m w.e." - snowpack_bin_monthly.comment = ("snowpack represents the snow depth when units are m w.e.") - melt_bin_monthly = netcdf_output.createVariable('melt_bin_monthly', np.float64, ('glac_idx', 'elevbin', 'time')) - melt_bin_monthly.long_name = 'surface melt' - melt_bin_monthly.units = "m w.e." - melt_bin_monthly.comment = ("surface melt is the sum of melt from snow, refreeze, and the underlying glacier") - frontalablation_bin_monthly = netcdf_output.createVariable('frontalablation_bin_monthly', np.float64, - ('glac_idx', 'elevbin', 'time')) - frontalablation_bin_monthly.long_name = "frontal ablation" - frontalablation_bin_monthly.units = "m w.e." - frontalablation_bin_monthly.comment = ("mass losses from calving, subaerial frontal melting, sublimation above " - + "the waterline and subaqueous frontal melting below the waterline") - massbalclim_bin_monthly = netcdf_output.createVariable('massbalclim_bin_monthly', np.float64, - ('glac_idx', 'elevbin', 'time')) - massbalclim_bin_monthly.long_name = "climatic mass balance" - massbalclim_bin_monthly.units = "m w.e." - massbalclim_bin_monthly.comment = ("climatic mass balance is the sum of the surface mass balance and the " - + "internal mass balance and accounts for the climatic mass loss over the " - + "area of the entire bin") - area_bin_annual = netcdf_output.createVariable('area_bin_annual', np.float64, - ('glac_idx', 'elevbin', 'year_plus1')) - area_bin_annual.long_name = "glacier area" - area_bin_annual.unit = "km**2" - area_bin_annual.comment = "the area that was used for the duration of the year" - icethickness_bin_annual = netcdf_output.createVariable('icethickness_bin_annual', np.float64, - ('glac_idx', 'elevbin', 'year_plus1')) - icethickness_bin_annual.long_name = "ice thickness" - icethickness_bin_annual.unit = "m ice" - icethickness_bin_annual.comment = "the ice thickness that was used for the duration of the year" - width_bin_annual = netcdf_output.createVariable('width_bin_annual', np.float64, - ('glac_idx', 'elevbin', 'year_plus1')) - width_bin_annual.long_name = "glacier width" - width_bin_annual.unit = "km" - width_bin_annual.comment = "the width that was used for the duration of the year" - surfacetype_bin_annual = netcdf_output.createVariable('surfacetype_bin_annual', np.float64, - ('glac_idx', 'elevbin', 'year')) - surfacetype_bin_annual.long_name = "surface type" - surfacetype_bin_annual.comment = "surface types: 0 = off-glacier, 1 = ice, 2 = snow, 3 = firn, 4 = debris" - elif input.output_package == 2: - # Package 2 "Glaciologist Package" output [units: m w.e. unless otherwise specified]: - # monthly glacier-wide variables (prec, acc, refreeze, melt, frontalablation, massbal_total, runoff, snowline) - # annual glacier-wide variables (area, volume, ELA) - temp_glac_monthly = netcdf_output.createVariable('temp_glac_monthly', np.float64, ('glac_idx', 'time', 'sim')) - temp_glac_monthly.long_name = "glacier-wide mean air temperature" - temp_glac_monthly.units = "deg C" - temp_glac_monthly.comment = ("each elevation bin is weighted equally to compute the mean temperature, and bins " - + "where the glacier no longer exists due to retreat have been removed") - prec_glac_monthly = netcdf_output.createVariable('prec_glac_monthly', np.float64, ('glac_idx', 'time', 'sim')) - prec_glac_monthly.long_name = "glacier-wide precipitation (liquid)" - prec_glac_monthly.units = "m" - acc_glac_monthly = netcdf_output.createVariable('acc_glac_monthly', np.float64, ('glac_idx', 'time', 'sim')) - acc_glac_monthly.long_name = "glacier-wide accumulation" - acc_glac_monthly.units = "m w.e." - refreeze_glac_monthly = netcdf_output.createVariable('refreeze_glac_monthly', np.float64, - ('glac_idx', 'time', 'sim')) - refreeze_glac_monthly.long_name = "glacier-wide refreeze" - refreeze_glac_monthly.units = "m w.e." - melt_glac_monthly = netcdf_output.createVariable('melt_glac_monthly', np.float64, ('glac_idx', 'time', 'sim')) - melt_glac_monthly.long_name = "glacier-wide melt" - melt_glac_monthly.units = "m w.e." - frontalablation_glac_monthly = netcdf_output.createVariable('frontalablation_glac_monthly', np.float64, - ('glac_idx', 'time', 'sim')) - frontalablation_glac_monthly.long_name = "glacier-wide frontal ablation" - frontalablation_glac_monthly.units = "m w.e." - frontalablation_glac_monthly.comment = ("mass losses from calving, subaerial frontal melting, sublimation above" - + " the waterline and subaqueous frontal melting below the waterline") - massbaltotal_glac_monthly = netcdf_output.createVariable('massbaltotal_glac_monthly', np.float64, - ('glac_idx', 'time', 'sim')) - massbaltotal_glac_monthly.long_name = "glacier-wide total mass balance" - massbaltotal_glac_monthly.units = "m w.e." - massbaltotal_glac_monthly.comment = ("total mass balance is the sum of the climatic mass balance and frontal " - + "ablation.") - runoff_glac_monthly = netcdf_output.createVariable('runoff_glac_monthly', np.float64, - ('glac_idx', 'time', 'sim')) - runoff_glac_monthly.long_name = "glacier runoff" - runoff_glac_monthly.units = "m**3" - runoff_glac_monthly.comment = "runoff from the glacier terminus, which moves over time" - snowline_glac_monthly = netcdf_output.createVariable('snowline_glac_monthly', np.float64, - ('glac_idx', 'time', 'sim')) - snowline_glac_monthly.long_name = "transient snowline" - snowline_glac_monthly.units = "m a.s.l." - snowline_glac_monthly.comment = "transient snowline is the line separating the snow from ice/firn" - area_glac_annual = netcdf_output.createVariable('area_glac_annual', np.float64, - ('glac_idx', 'year_plus1', 'sim')) - if input.option_wateryear == 1: - area_glac_annual.long_name = "glacier area by hydrological year" - elif input.option_wateryear == 2: - area_glac_annual.long_name = "glacier area by calendar year" - elif input.option_wateryear == 3: - area_glac_annual.long_name = "glacier area by custom year" - else: - area_glac_annual.long_name = "glacier area" - area_glac_annual.units = "km**2" - area_glac_annual.comment = "the area that was used for the duration of the defined start/end of year" - volume_glac_annual = netcdf_output.createVariable('volume_glac_annual', np.float64, - ('glac_idx', 'year_plus1', 'sim')) - if input.option_wateryear == 1: - volume_glac_annual.long_name = "glacier volume by hydrological year" - elif input.option_wateryear == 2: - volume_glac_annual.long_name = "glacier volume by calendar year" - elif input.option_wateryear == 3: - volume_glac_annual.long_name = "glacier volume by custom year" - else: - volume_glac_annual.long_name = "glacier volume" - volume_glac_annual.units = "km**3 ice" - volume_glac_annual.comment = "the volume based on area and ice thickness used for that year" - ELA_glac_annual = netcdf_output.createVariable('ELA_glac_annual', np.float64, ('glac_idx', 'year', 'sim')) - ELA_glac_annual.long_name = "annual equilibrium line altitude" - ELA_glac_annual.units = "m a.s.l." - ELA_glac_annual.comment = "equilibrium line altitude is the elevation where the climatic mass balance is zero" - netcdf_output.close() - - -def netcdfwrite(netcdf_fn, glac, modelparameters, glacier_rgi_table, elev_bins, glac_bin_temp, glac_bin_prec, - glac_bin_acc, glac_bin_refreeze, glac_bin_snowpack, glac_bin_melt, glac_bin_frontalablation, - glac_bin_massbalclim, glac_bin_massbalclim_annual, glac_bin_area_annual, glac_bin_icethickness_annual, - glac_bin_width_annual, glac_bin_surfacetype_annual, output_filepath=input.output_filepath, sim=0): - """ - Write to the netcdf file that has already been generated to store the desired output - - Parameters - ---------- - netcdf_fn : str - netcdf filename that is being filled in - glac : int - glacier index number used to determine where to write model results - glacier_rgi_table : pandas series - series containing relevant rgi glacier information - elev_bins : numpy array - elevation bins - glac_bin_temp : numpy array - temperature for each elevation bin for each timestep - glac_bin_prec : numpy array - precipitation (liquid) for each elevation bin for each timestep - glac_bin_acc : numpy array - accumulation (solid precipitation) for each elevation bin for each timestep - glac_bin_refreeze : numpy array - refreeze for each elevation bin for each timestep - glac_bin_snowpack : numpy array - snowpack for each elevation bin for each timestep - glac_bin_melt : numpy array - glacier melt for each elevation bin for each timestep - glac_bin_frontalablation : numpy array - frontal ablation for each elevation bin for each timestep - glac_bin_massbalclim : numpy array - climatic mass balance for each elevation bin for each timestep - glac_bin_massbalclim_annual : numpy array - annual climatic mass balance for each elevation bin for each timestep - glac_bin_area_annual : numpy array - annual glacier area for each elevation bin for each timestep - glac_bin_icethickness_annual: numpy array - annual ice thickness for each elevation bin for each timestep - glac_bin_width_annual : numpy array - annual glacier width for each elevation bin for each timestep - glac_bin_surfacetype_annual : numpy array - annual surface type for each elevation bin for each timestep - output_filepath : str - output filepath of where to store netcdf file - sim : int - simulation index used to write model results - - - Returns - ------- - netcdf file with model results filled in - """ - # Open netcdf file to write to existing file ('r+') - netcdf_output = nc.Dataset(output_filepath + netcdf_fn, 'r+') - # Record the variables for each glacier (remove data associated with spinup years) - if input.output_package == 1: - # Package 1 "Raw Package" output [units: m w.e. unless otherwise specified]: - # monthly variables for each bin (temp, prec, acc, refreeze, snowpack, melt, frontalablation, massbal_clim) - # annual variables for each bin (area, icethickness, surfacetype) - # Write variables to netcdf - netcdf_output.variables['temp_bin_monthly'][glac,:,:] = glac_bin_temp - netcdf_output.variables['prec_bin_monthly'][glac,:,:] = glac_bin_prec - netcdf_output.variables['acc_bin_monthly'][glac,:,:] = glac_bin_acc - netcdf_output.variables['refreeze_bin_monthly'][glac,:,:] = glac_bin_refreeze - netcdf_output.variables['snowpack_bin_monthly'][glac,:,:] = glac_bin_snowpack - netcdf_output.variables['melt_bin_monthly'][glac,:,:] = glac_bin_melt - netcdf_output.variables['frontalablation_bin_monthly'][glac,:,:] = glac_bin_frontalablation - netcdf_output.variables['massbalclim_bin_monthly'][glac,:,:] = glac_bin_massbalclim - netcdf_output.variables['area_bin_annual'][glac,:,:] = glac_bin_area_annual - netcdf_output.variables['icethickness_bin_annual'][glac,:,:] = glac_bin_icethickness_annual - netcdf_output.variables['width_bin_annual'][glac,:,:] = glac_bin_width_annual - netcdf_output.variables['surfacetype_bin_annual'][glac,:,:] = glac_bin_surfacetype_annual - elif input.output_package == 2: - # Package 2 "Glaciologist Package" output [units: m w.e. unless otherwise specified]: - # monthly glacier-wide variables (prec, acc, refreeze, melt, frontalablation, massbal_total, runoff, snowline) - # annual glacier-wide variables (area, volume, ELA) - # Preset desired output (needed to avoid dividing by zero) - glac_wide_temp = np.zeros(glac_bin_temp.shape[1]) - glac_wide_prec = np.zeros(glac_bin_temp.shape[1]) - glac_wide_acc = np.zeros(glac_bin_temp.shape[1]) - glac_wide_refreeze = np.zeros(glac_bin_temp.shape[1]) - glac_wide_melt = np.zeros(glac_bin_temp.shape[1]) - glac_wide_frontalablation = np.zeros(glac_bin_temp.shape[1]) - # Compute desired output - glac_bin_area = glac_bin_area_annual[:,0:glac_bin_area_annual.shape[1]-1].repeat(12,axis=1) - glac_wide_area = glac_bin_area.sum(axis=0) - glac_wide_temp_sum = glac_bin_temp.sum(axis=0) - glac_bin_temp_nonzero = np.zeros(glac_bin_temp.shape) - glac_bin_temp_nonzero[glac_bin_temp != 0] = 1 - glac_wide_temp_bincount = glac_bin_temp_nonzero.sum(axis=0) - glac_wide_temp[glac_wide_temp_bincount > 0] = (glac_wide_temp_sum[glac_wide_temp_bincount > 0] / - glac_wide_temp_bincount[glac_wide_temp_bincount > 0]) - glac_wide_prec_mkm2 = (glac_bin_prec * glac_bin_area).sum(axis=0) - glac_wide_prec[glac_wide_prec_mkm2 > 0] = (glac_wide_prec_mkm2[glac_wide_prec_mkm2 > 0] / - glac_wide_area[glac_wide_prec_mkm2 > 0]) - glac_wide_acc_mkm2 = (glac_bin_acc * glac_bin_area).sum(axis=0) - glac_wide_acc[glac_wide_acc_mkm2 > 0] = (glac_wide_acc_mkm2[glac_wide_acc_mkm2 > 0] / - glac_wide_area[glac_wide_acc_mkm2 > 0]) - glac_wide_refreeze_mkm2 = (glac_bin_refreeze * glac_bin_area).sum(axis=0) - glac_wide_refreeze[glac_wide_refreeze_mkm2 > 0] = (glac_wide_refreeze_mkm2[glac_wide_refreeze_mkm2 > 0] / - glac_wide_area[glac_wide_refreeze_mkm2 > 0]) - glac_wide_melt_mkm2 = (glac_bin_melt * glac_bin_area).sum(axis=0) - glac_wide_melt[glac_wide_melt_mkm2 > 0] = (glac_wide_melt_mkm2[glac_wide_melt_mkm2 > 0] / - glac_wide_area[glac_wide_melt_mkm2 > 0]) - glac_wide_frontalablation_mkm2 = (glac_bin_frontalablation * glac_bin_area).sum(axis=0) - glac_wide_frontalablation[glac_wide_frontalablation_mkm2 > 0] = ( - glac_wide_frontalablation_mkm2[glac_wide_frontalablation_mkm2 > 0] / - glac_wide_area[glac_wide_frontalablation_mkm2 > 0]) - glac_wide_massbalclim = glac_wide_acc + glac_wide_refreeze - glac_wide_melt - glac_wide_massbaltotal = glac_wide_massbalclim - glac_wide_frontalablation - glac_wide_runoff = (glac_wide_prec + glac_wide_melt - glac_wide_refreeze) * glac_wide_area * (1000)**2 - # units: (m + m w.e. - m w.e.) * km**2 * (1000 m / 1 km)**2 = m**3 - glac_wide_snowline = (glac_bin_snowpack > 0).argmax(axis=0) - glac_wide_snowline[glac_wide_snowline > 0] = (elev_bins[glac_wide_snowline[glac_wide_snowline > 0]] - - input.binsize/2) - glac_wide_area_annual = glac_bin_area_annual.sum(axis=0) - glac_wide_volume_annual = (glac_bin_area_annual * glac_bin_icethickness_annual / 1000).sum(axis=0) - glac_wide_ELA_annual = (glac_bin_massbalclim_annual > 0).argmax(axis=0) - glac_wide_ELA_annual[glac_wide_ELA_annual > 0] = (elev_bins[glac_wide_ELA_annual[glac_wide_ELA_annual > 0]] - - input.binsize/2) - # Write variables to netcdf - netcdf_output.variables['temp_glac_monthly'][glac,:,sim] = glac_wide_temp - netcdf_output.variables['prec_glac_monthly'][glac,:,sim] = glac_wide_prec - netcdf_output.variables['acc_glac_monthly'][glac,:,sim] = glac_wide_acc - netcdf_output.variables['refreeze_glac_monthly'][glac,:,sim] = glac_wide_refreeze - netcdf_output.variables['melt_glac_monthly'][glac,:,sim] = glac_wide_melt - netcdf_output.variables['frontalablation_glac_monthly'][glac,:,sim] = glac_wide_frontalablation - netcdf_output.variables['massbaltotal_glac_monthly'][glac,:,sim] = glac_wide_massbaltotal - netcdf_output.variables['runoff_glac_monthly'][glac,:,sim] = glac_wide_runoff - netcdf_output.variables['snowline_glac_monthly'][glac,:,sim] = glac_wide_snowline - netcdf_output.variables['area_glac_annual'][glac,:,sim] = glac_wide_area_annual - netcdf_output.variables['volume_glac_annual'][glac,:,sim] = glac_wide_volume_annual - netcdf_output.variables['ELA_glac_annual'][glac,:,sim] = glac_wide_ELA_annual - # Close the netcdf file - netcdf_output.close() - - -#def netcdfcreate_calgridsearch(regionO1_number, main_glac_hyps, dates_table, modelparameters): -# # Annual columns -# annual_columns = np.unique(dates_table['wateryear'].values) -# # Netcdf file path and name -# filename = input.calibrationnetcdf_filenameprefix + str(regionO1_number) + '_' + str(strftime("%Y%m%d")) + '.nc' -# fullfilename = input.output_filepath + filename -# # Create netcdf file ('w' will overwrite existing files, 'r+' will open existing file to write) -# netcdf_output = nc.Dataset(fullfilename, 'w', format='NETCDF4') -# # Global attributes -# netcdf_output.description = 'Results from glacier evolution model' -# netcdf_output.history = 'Created ' + str(strftime("%Y-%m-%d %H:%M:%S")) -# netcdf_output.source = 'Python Glacier Evolution Model' -# # Dimensions -# glac_idx = netcdf_output.createDimension('glac_idx', None) -# elevbin = netcdf_output.createDimension('elevbin', main_glac_hyps.shape[1]) -# if input.timestep == 'monthly': -# time = netcdf_output.createDimension('time', dates_table.shape[0] - input.spinupyears * 12) -# year = netcdf_output.createDimension('year', annual_columns.shape[0] - input.spinupyears) -# year_plus1 = netcdf_output.createDimension('year_plus1', annual_columns.shape[0] - input.spinupyears + 1) -# gridround = netcdf_output.createDimension('gridround', modelparameters.shape[0]) -# gridparam = netcdf_output.createDimension('gridparam', modelparameters.shape[1]) -# glacierinfo = netcdf_output.createDimension('glacierinfo', 3) -# # Variables associated with dimensions -# glaciers = netcdf_output.createVariable('glac_idx', np.int32, ('glac_idx',)) -# glaciers.long_name = "glacier number associated with model run" -# glaciers.standard_name = "GlacNo" -# glaciers.comment = ("The glacier number is defined for each model run. The user should look at the main_glac_rgi" -# + " table to determine the RGIID or other information regarding this particular glacier.") -# elevbins = netcdf_output.createVariable('elevbin', np.int32, ('elevbin',)) -# elevbins.standard_name = "center of elevation bin" -# elevbins.units = "m a.s.l." -# elevbins[:] = main_glac_hyps.columns.values -# times = netcdf_output.createVariable('time', np.float64, ('time',)) -# times.standard_name = "date" -# times.units = "days since 1900-01-01 00:00:00" -# times.calendar = "gregorian" -# if input.timestep == 'monthly': -# times[:] = (nc.date2num(dates_table.loc[input.spinupyears*12:dates_table.shape[0]+1,'date'].astype(datetime), -# units = times.units, calendar = times.calendar)) -# years = netcdf_output.createVariable('year', np.int32, ('year',)) -# years.standard_name = "year" -# if input.option_wateryear == 1: -# years.units = 'water year' -# elif input.option_wateryear == 0: -# years.units = 'calendar year' -# years[:] = annual_columns[input.spinupyears:annual_columns.shape[0]] -# # years_plus1 adds an additional year such that the change in glacier dimensions (area, etc.) is recorded -# years_plus1 = netcdf_output.createVariable('year_plus1', np.int32, ('year_plus1',)) -# years_plus1.standard_name = "year with additional year to record glacier dimension changes" -# if input.option_wateryear == 1: -# years_plus1.units = 'water year' -# elif input.option_wateryear == 0: -# years_plus1.units = 'calendar year' -# years_plus1[:] = np.concatenate((annual_columns[input.spinupyears:annual_columns.shape[0]], -# np.array([annual_columns[annual_columns.shape[0]-1]+1]))) -# gridrounds = netcdf_output.createVariable('gridround', np.int32, ('gridround',)) -# gridrounds.long_name = "number associated with the calibration grid search" -# glacierinfoheader = netcdf_output.createVariable('glacierinfoheader', str, ('glacierinfo',)) -# glacierinfoheader.standard_name = "information about each glacier from main_glac_rgi" -# glacierinfoheader[:] = np.array(['RGIID','lat','lon']) -# glacierinfo = netcdf_output.createVariable('glacierinfo',str,('glac_idx','glacierinfo',)) -# # Variables associated with the output -# # monthly glacier-wide variables (massbal_total, runoff, snowline, snowpack) -# # annual glacier-wide variables (area, volume, ELA) -# grid_modelparameters = netcdf_output.createVariable('grid_modelparameters', np.float64, ('gridround', 'gridparam')) -# grid_modelparameters.standard_name = ("grid model parameters [lrglac, lrgcm, precfactor, precgrad, ddfsnow, ddfice," -# + " tempsnow, tempchange]") -# grid_modelparameters[:] = modelparameters -# massbaltotal_glac_monthly = netcdf_output.createVariable('massbaltotal_glac_monthly', np.float64, -# ('glac_idx', 'gridround', 'time')) -# massbaltotal_glac_monthly.standard_name = "glacier-wide total mass balance" -# massbaltotal_glac_monthly.units = "m w.e." -# massbaltotal_glac_monthly.comment = ("total mass balance is the sum of the climatic mass balance and frontal " -# + "ablation.") -# runoff_glac_monthly = netcdf_output.createVariable('runoff_glac_monthly', np.float64, -# ('glac_idx', 'gridround', 'time')) -# runoff_glac_monthly.standard_name = "glacier runoff" -# runoff_glac_monthly.units = "m**3" -# runoff_glac_monthly.comment = "runoff from the glacier terminus, which moves over time" -# snowline_glac_monthly = netcdf_output.createVariable('snowline_glac_monthly', np.float64, -# ('glac_idx', 'gridround', 'time')) -# snowline_glac_monthly.standard_name = "transient snowline" -# snowline_glac_monthly.units = "m a.s.l." -# snowline_glac_monthly.comment = "transient snowline is the line separating the snow from ice/firn" -# snowpack_glac_monthly = netcdf_output.createVariable('snowpack_glac_monthly', np.float64, -# ('glac_idx', 'gridround', 'time')) -# snowpack_glac_monthly.standard_name = "snowpack volume" -# snowpack_glac_monthly.units = "km**3 w.e." -# snowpack_glac_monthly.comment = "m w.e. multiplied by the area converted to km**3" -# area_glac_annual = netcdf_output.createVariable('area_glac_annual', np.float64, -# ('glac_idx', 'gridround', 'year_plus1')) -# area_glac_annual.standard_name = "glacier area" -# area_glac_annual.units = "km**2" -# area_glac_annual.comment = "the area that was used for the duration of the year" -# volume_glac_annual = netcdf_output.createVariable('volume_glac_annual', np.float64, -# ('glac_idx', 'gridround', 'year_plus1')) -# volume_glac_annual.standard_name = "glacier volume" -# volume_glac_annual.units = "km**3 ice" -# volume_glac_annual.comment = "the volume based on area and ice thickness used for that year" -# ELA_glac_annual = netcdf_output.createVariable('ELA_glac_annual', np.float64, ('glac_idx', 'gridround', 'year')) -# ELA_glac_annual.standard_name = "annual equilibrium line altitude" -# ELA_glac_annual.units = "m a.s.l." -# ELA_glac_annual.comment = "equilibrium line altitude is the elevation where the climatic mass balance is zero" -# netcdf_output.close() -# return fullfilename -# -# -#def netcdfwrite_calgridsearch(fullfilename, glac, glacier_rgi_table, output_glac_wide_massbaltotal, -# output_glac_wide_runoff, output_glac_wide_snowline, output_glac_wide_snowpack, -# output_glac_wide_area_annual, output_glac_wide_volume_annual, -# output_glac_wide_ELA_annual): -# # Open netcdf file to write to existing file ('r+') -# netcdf_output = nc.Dataset(fullfilename, 'r+') -# # Write variables to netcdf -# netcdf_output.variables['glacierinfo'][glac,:] = np.array([glacier_rgi_table.loc['RGIId'], -# glacier_rgi_table.loc[input.lat_colname], glacier_rgi_table.loc[input.lon_colname]]) -# netcdf_output.variables['massbaltotal_glac_monthly'][glac,:,:] = output_glac_wide_massbaltotal -# netcdf_output.variables['runoff_glac_monthly'][glac,:,:] = output_glac_wide_runoff -# netcdf_output.variables['snowline_glac_monthly'][glac,:,:] = output_glac_wide_snowline -# netcdf_output.variables['snowpack_glac_monthly'][glac,:,:] = output_glac_wide_snowpack -# netcdf_output.variables['area_glac_annual'][glac,:,:] = output_glac_wide_area_annual -# netcdf_output.variables['volume_glac_annual'][glac,:,:] = output_glac_wide_volume_annual -# netcdf_output.variables['ELA_glac_annual'][glac,:,:] = output_glac_wide_ELA_annual -# netcdf_output.close() - - - -#%%===== PLOT FUNCTIONS ============================================================================================= -def plot_latlonvar(lons, lats, variable, rangelow, rangehigh, title, xlabel, ylabel, colormap, east, west, south, north, - xtick, ytick): - """ - Plot a variable according to its latitude and longitude - """ - # Create the projection - ax = plt.axes(projection=cartopy.crs.PlateCarree()) - # Add country borders for reference - ax.add_feature(cartopy.feature.BORDERS) - # Set the extent - ax.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - plt.title(title) - ax.set_xticks(np.arange(east,west+1,xtick), cartopy.crs.PlateCarree()) - ax.set_yticks(np.arange(south,north+1,ytick), cartopy.crs.PlateCarree()) - plt.xlabel(xlabel) - plt.ylabel(ylabel) - # Plot the data - plt.scatter(lons, lats, c=variable, cmap=colormap) - # plotting x, y, size [s=__], color bar [c=__] - plt.clim(rangelow,rangehigh) - # set the range of the color bar - plt.colorbar(fraction=0.02, pad=0.04) - # fraction resizes the colorbar, pad is the space between the plot and colorbar - plt.show() - - -def plot_caloutput(data): - """ - Plot maps and histograms of the calibration parameters to visualize results - """ - # Set extent - east = int(round(data['CenLon'].min())) - 1 - west = int(round(data['CenLon'].max())) + 1 - south = int(round(data['CenLat'].min())) - 1 - north = int(round(data['CenLat'].max())) + 1 - xtick = 1 - ytick = 1 - # Select relevant data - lats = data['CenLat'][:] - lons = data['CenLon'][:] - precfactor = data['precfactor'][:] - tempchange = data['tempchange'][:] - ddfsnow = data['ddfsnow'][:] - calround = data['calround'][:] - massbal = data['MB_geodetic_mwea'] - # Plot regional maps - plot_latlonvar(lons, lats, massbal, 'Geodetic mass balance [mwea]', 'longitude [deg]', 'latitude [deg]', east, west, - south, north, xtick, ytick) - plot_latlonvar(lons, lats, precfactor, 'precipitation factor', 'longitude [deg]', 'latitude [deg]', east, west, - south, north, xtick, ytick) - plot_latlonvar(lons, lats, tempchange, 'Temperature bias [degC]', 'longitude [deg]', 'latitude [deg]', east, west, - south, north, xtick, ytick) - plot_latlonvar(lons, lats, ddfsnow, 'DDF_snow [m w.e. d-1 degC-1]', 'longitude [deg]', 'latitude [deg]', east, west, - south, north, xtick, ytick) - plot_latlonvar(lons, lats, calround, 'Calibration round', 'longitude [deg]', 'latitude [deg]', east, west, - south, north, xtick, ytick) - # Plot histograms - data.hist(column='MB_difference_mwea', bins=50) - plt.title('Mass Balance Difference [mwea]') - data.hist(column='precfactor', bins=50) - plt.title('Precipitation factor [-]') - data.hist(column='tempchange', bins=50) - plt.title('Temperature bias [degC]') - data.hist(column='ddfsnow', bins=50) - plt.title('DDFsnow [mwe d-1 degC-1]') - plt.xticks(rotation=60) - data.hist(column='calround', bins = [0.5, 1.5, 2.5, 3.5]) - plt.title('Calibration round') - plt.xticks([1, 2, 3]) - - -#%% -if __name__ == '__main__': - gcm_list_fn = input.main_directory + '/../Climate_data/cmip5/gcm_rcp26_filenames.txt' - rcp_scenario = 'rcp26' - output_filepath = input.main_directory + '/../Output/' - output_prefix = 'PyGEM_R15_' - with open(gcm_list_fn, 'r') as gcm_fn: - gcm_list = gcm_fn.read().splitlines() - gcm_reg_annual_volume = np.zeros((len(gcm_list),101)) -# for n_gcm in range(len(gcm_list)): -## for n_gcm in [0]: -# gcm = gcm_list[n_gcm] -# print(n_gcm, gcm) -# gcm_fn = glob.glob(output_filepath + output_prefix + gcm + '_' + rcp_scenario + '_2000_2100' + '*.nc')[0] -# output = nc.Dataset(gcm_fn) -# glac_annual_volume = output['volume_glac_annual'][:][:,:-1] -# reg_annual_volume = glac_annual_volume.sum(axis=0) -# annual_columns = output['year'][:] -# gcm_reg_annual_volume[n_gcm,:] = reg_annual_volume -# print(reg_annual_volume[100]) -# output.close() - - gcm_fn = output_filepath + 'PyGEM_R15_MPI-ESM-LR_rcp26_2000_2100_20180428.nc' -# gcm_fn = output_filepath + 'PyGEM_R15_NorESM1-ME_rcp26_2000_2100_20180428.nc' - output = nc.Dataset(gcm_fn) - glac_annual_volume = output['volume_glac_annual'][:][:,:-1] - reg_annual_volume = glac_annual_volume.sum(axis=0) - annual_columns = output['year'][:] - # Label title, x, and y axes - # plt.title(title) - # plt.xlabel(xlabel) - # plt.ylabel(ylabel) - # Plot the data - plt.scatter(annual_columns, reg_annual_volume) - # plotting x, y, size [s=__], color bar [c=__] - # plt.clim(rangelow,rangehigh) - # set the range of the color bar - # plt.colorbar(fraction=0.02, pad=0.04) - # fraction resizes the colorbar, pad is the space between the plot and colorbar -# plt.show() - -#%%===== PLOTTING =========================================================================================== -#netcdf_output15 = nc.Dataset(input.main_directory + -# '/../Output/PyGEM_output_rgiregion15_ERAInterim_calSheanMB_nearest_20180306.nc', 'r+') -#netcdf_output15 = nc.Dataset(input.main_directory + -# '/../Output/PyGEM_output_rgiregion15_ERAInterim_calSheanMB_transferAvg_20180306.nc', 'r+') -#netcdf_output14 = nc.Dataset(input.main_directory + -# '/../Output/PyGEM_output_rgiregion14_ERAInterim_calSheanMB_nearest_20180313.nc', 'r+') -#netcdf_output14 = nc.Dataset(input.main_directory + -# '/../Output/PyGEM_output_rgiregion14_ERAInterim_calSheanMB_transferAvg_20180313.nc', 'r+') -# -## Select relevant data -#glacier_data15 = pd.DataFrame(netcdf_output15['glacierparameter'][:]) -#glacier_data15.columns = netcdf_output15['glacierparameters'][:] -#lats15 = glacier_data15['lat'].values.astype(float) -#lons15 = glacier_data15['lon'].values.astype(float) -#massbal_total15 = netcdf_output15['massbaltotal_glac_monthly'][:] -#massbal_total_mwea15 = massbal_total15.sum(axis=1)/(massbal_total15.shape[1]/12) -#volume_glac_annual15 = netcdf_output15['volume_glac_annual'][:] -#volume_reg_annual15 = volume_glac_annual15.sum(axis=0) -#volume_reg_annualnorm15 = volume_reg_annual15 / volume_reg_annual15[0] -#runoff_glac_monthly15 = netcdf_output15['runoff_glac_monthly'][:] -#runoff_reg_monthly15 = runoff_glac_monthly15.mean(axis=0) -#acc_glac_monthly15 = netcdf_output15['acc_glac_monthly'][:] -#acc_reg_monthly15 = acc_glac_monthly15.mean(axis=0) -#acc_reg_annual15 = np.sum(acc_reg_monthly15.reshape(-1,12), axis=1) -#refreeze_glac_monthly15 = netcdf_output15['refreeze_glac_monthly'][:] -#refreeze_reg_monthly15 = refreeze_glac_monthly15.mean(axis=0) -#refreeze_reg_annual15 = np.sum(refreeze_reg_monthly15.reshape(-1,12), axis=1) -#melt_glac_monthly15 = netcdf_output15['melt_glac_monthly'][:] -#melt_reg_monthly15 = melt_glac_monthly15.mean(axis=0) -#melt_reg_annual15 = np.sum(melt_reg_monthly15.reshape(-1,12), axis=1) -#massbaltotal_glac_monthly15 = netcdf_output15['massbaltotal_glac_monthly'][:] -#massbaltotal_reg_monthly15 = massbaltotal_glac_monthly15.mean(axis=0) -#massbaltotal_reg_annual15 = np.sum(massbaltotal_reg_monthly15.reshape(-1,12), axis=1) -#glacier_data14 = pd.DataFrame(netcdf_output14['glacierparameter'][:]) -#glacier_data14.columns = netcdf_output14['glacierparameters'][:] -#lats14 = glacier_data14['lat'].values.astype(float) -#lons14 = glacier_data14['lon'].values.astype(float) -#massbal_total14 = netcdf_output14['massbaltotal_glac_monthly'][:] -#massbal_total_mwea14 = massbal_total14.sum(axis=1)/(massbal_total14.shape[1]/12) -#volume_glac_annual14 = netcdf_output14['volume_glac_annual'][:] -#volume_reg_annual14 = volume_glac_annual14.sum(axis=0) -#volume_reg_annualnorm14 = volume_reg_annual14 / volume_reg_annual14[0] -#runoff_glac_monthly14 = netcdf_output14['runoff_glac_monthly'][:] -#runoff_reg_monthly14 = runoff_glac_monthly14.mean(axis=0) -#acc_glac_monthly14 = netcdf_output14['acc_glac_monthly'][:] -#acc_reg_monthly14 = acc_glac_monthly14.mean(axis=0) -#acc_reg_annual14 = np.sum(acc_reg_monthly14.reshape(-1,12), axis=1) -#refreeze_glac_monthly14 = netcdf_output14['refreeze_glac_monthly'][:] -#refreeze_reg_monthly14 = refreeze_glac_monthly14.mean(axis=0) -#refreeze_reg_annual14 = np.sum(refreeze_reg_monthly14.reshape(-1,12), axis=1) -#melt_glac_monthly14 = netcdf_output14['melt_glac_monthly'][:] -#melt_reg_monthly14 = melt_glac_monthly14.mean(axis=0) -#melt_reg_annual14 = np.sum(melt_reg_monthly14.reshape(-1,12), axis=1) -#massbaltotal_glac_monthly14 = netcdf_output14['massbaltotal_glac_monthly'][:] -#massbaltotal_reg_monthly14 = massbaltotal_glac_monthly14.mean(axis=0) -#massbaltotal_reg_annual14 = np.sum(massbaltotal_reg_monthly14.reshape(-1,12), axis=1) -#years = np.arange(2000, 2016 + 1) -#month = np.arange(2000, 2016, 1/12) -#plt.plot(years,volume_reg_annualnorm15, label='Region 15') -#plt.plot(years,volume_reg_annualnorm14, label='Region 14') -#plt.ylabel('Volume normalized [-]', size=15) -#plt.legend() -#plt.show() -#plt.plot(month,runoff_reg_monthly15, label='Region 15') -#plt.ylabel('Runoff [m3 / month]', size=15) -#plt.legend() -#plt.show() -##plt.plot(month, massbaltotal_reg_monthly, label='massbal_total') -##plt.plot(month, acc_reg_monthly, label='accumulation') -##plt.plot(month, refreeze_reg_monthly, label='refreeze') -##plt.plot(month, -1*melt_reg_monthly, label='melt') -##plt.ylabel('monthly regional mean [m.w.e.] / month') -##plt.legend() -##plt.show() -#plt.plot(years[0:16], massbaltotal_reg_annual15, label='massbal_total') -#plt.plot(years[0:16], acc_reg_annual15, label='accumulation') -#plt.plot(years[0:16], refreeze_reg_annual15, label='refreeze') -#plt.plot(years[0:16], -1*melt_reg_annual15, label='melt') -#plt.ylabel('Region 15 annual mean [m.w.e.]', size=15) -#plt.legend() -#plt.show() -# -#lons = np.concatenate((lons14, lons15), axis=0) -#lats = np.concatenate((lats14, lats15), axis=0) -#massbal_total_mwea = np.concatenate((massbal_total_mwea14, massbal_total_mwea15), axis=0) -# -## Set extent -#east = int(round(lons.min())) - 1 -#west = int(round(lons.max())) + 1 -#south = int(round(lats.min())) - 1 -#north = int(round(lats.max())) + 1 -#xtick = 1 -#ytick = 1 -## Plot regional maps -#plot_latlonvar(lons, lats, massbal_total_mwea, -1.5, 0.5, 'Modeled mass balance [mwea]', 'longitude [deg]', -# 'latitude [deg]', 'jet_r', east, west, south, north, xtick, ytick) - -#%% ====== PLOTTING FOR CALIBRATION FUNCTION ====================================================================== -### Plot histograms and regional variations -#data13 = pd.read_csv(input.main_directory + '/../Output/calibration_R13_20180318_Opt01solutionspaceexpanding.csv') -#data13 = data13.dropna() -##data14 = pd.read_csv(input.main_directory + '/../Output/calibration_R14_20180313_Opt01solutionspaceexpanding.csv') -##data14 = data14.dropna() -##data15 = pd.read_csv(input.main_directory + '/../Output/calibration_R15_20180306_Opt01solutionspaceexpanding.csv') -##data15 = data15.dropna() -#data = data13 -# -## Concatenate the data -##frames = [data13, data14, data15] -##data = pd.concat(frames) -# -### Fill in values with average -### Subset all values that have data -##data_subset = data.dropna() -##data_subset_params = data_subset[['lrgcm','lrglac','precfactor','precgrad','ddfsnow','ddfice','tempsnow','tempchange']] -##data_subset_paramsavg = data_subset_params.mean() -##paramsfilled = data[['lrgcm','lrglac','precfactor','precgrad','ddfsnow','ddfice','tempsnow','tempchange']] -##paramsfilled = paramsfilled.fillna(data_subset_paramsavg) -# -## Set extent -#east = int(round(data['CenLon'].min())) - 1 -#west = int(round(data['CenLon'].max())) + 1 -#south = int(round(data['CenLat'].min())) - 1 -#north = int(round(data['CenLat'].max())) + 1 -#xtick = 1 -#ytick = 1 -## Select relevant data -#lats = data['CenLat'][:] -#lons = data['CenLon'][:] -#precfactor = data['precfactor'][:] -#tempchange = data['tempchange'][:] -#ddfsnow = data['ddfsnow'][:] -#calround = data['calround'][:] -#massbal = data['MB_geodetic_mwea'] -## Plot regional maps -#plot_latlonvar(lons, lats, massbal, -1.5, 0.5, 'Geodetic mass balance [mwea]', 'longitude [deg]', 'latitude [deg]', -# 'jet_r', east, west, south, north, xtick, ytick) -#plot_latlonvar(lons, lats, precfactor, 0.8, 1.3, 'Precipitation factor [-]', 'longitude [deg]', 'latitude [deg]', -# 'jet_r', east, west, south, north, xtick, ytick) -#plot_latlonvar(lons, lats, tempchange, -4, 2, 'Temperature bias [degC]', 'longitude [deg]', 'latitude [deg]', -# 'jet', east, west, south, north, xtick, ytick) -#plot_latlonvar(lons, lats, ddfsnow, 0.003, 0.005, 'DDF_snow [m w.e. d-1 degC-1]', 'longitude [deg]', 'latitude [deg]', -# 'jet', east, west, south, north, xtick, ytick) -#plot_latlonvar(lons, lats, calround, 1, 3, 'Calibration round', 'longitude [deg]', 'latitude [deg]', -# 'jet_r', east, west, south, north, xtick, ytick) -## Plot histograms -#data.hist(column='MB_difference_mwea', bins=50) -#plt.title('Mass Balance Difference [mwea]') -#data.hist(column='precfactor', bins=50) -#plt.title('Precipitation factor [-]') -#data.hist(column='tempchange', bins=50) -#plt.title('Temperature bias [degC]') -#data.hist(column='ddfsnow', bins=50) -#plt.title('DDFsnow [mwe d-1 degC-1]') -#plt.xticks(rotation=60) -#data.hist(column='calround', bins = [0.5, 1.5, 2.5, 3.5]) -#plt.title('Calibration round') -#plt.xticks([1, 2, 3]) -# -### run plot function -##output.plot_caloutput(data) diff --git a/pygemfxns_plotting.py b/pygemfxns_plotting.py deleted file mode 100644 index 994a1885..00000000 --- a/pygemfxns_plotting.py +++ /dev/null @@ -1,2647 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Mon Oct 16 09:04:46 2017 - -@author: David Rounce - -pygemfxns_plotting.py produces figures of simulation results -""" - -# Built-in Libraries -import os -import collections -# External Libraries -import numpy as np -import pandas as pd -#import netCDF4 as nc -import matplotlib as mpl -import matplotlib.pyplot as plt -from matplotlib.lines import Line2D -from matplotlib.ticker import MaxNLocator -import matplotlib.patches as mpatches -import scipy -from scipy import stats -from scipy.ndimage import uniform_filter -import cartopy -#import geopandas -import xarray as xr -from osgeo import gdal, ogr, osr -import pickle -# Local Libraries -import pygem_input as input -import pygemfxns_modelsetup as modelsetup -import pygemfxns_massbalance as massbalance -import pygemfxns_gcmbiasadj as gcmbiasadj -import class_mbdata -import class_climate -#import run_simulation - - -# Script options -option_plot_cmip5_normalizedchange = 1 -option_plot_cmip5_runoffcomponents = 0 -option_plot_cmip5_map = 0 -option_output_tables = 0 -option_subset_GRACE = 0 -option_plot_modelparam = 0 -option_plot_era_normalizedchange = 1 -option_compare_GCMwCal = 0 -option_plot_mcmc_errors = 0 -option_plot_maxloss_issues = 0 - -option_plot_individual_glaciers = 0 -option_plot_degrees = 0 -option_plot_pies = 0 -option_plot_individual_gcms = 0 - - -#%% ===== Input data ===== -netcdf_fp_cmip5 = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/simulations/spc/' -netcdf_fp_era = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/simulations/ERA-Interim/ERA-Interim_1980_2017_nochg' -#mcmc_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/cal_opt2_allglac_1ch_tn_20190108/' -#mcmc_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/cal_opt2_spc_20190222_adjp10/' -mcmc_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/cal_opt2_spc_20190308_adjp12/cal_opt2/' -figure_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/figures/cmip5/' -csv_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/csv/cmip5/' -cal_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/cal_opt2_spc_20190308_adjp12/cal_opt2/' - -# Regions -rgi_regions = [13, 14, 15] -#rgi_regions = [13] - -# Shapefiles -rgiO1_shp_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/RGI/rgi60/00_rgi60_regions/00_rgi60_O1Regions.shp' -watershed_shp_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/qgis_himat/HMA_basins_20181018_4plot.shp' -kaab_shp_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/qgis_himat/kaab2015_regions.shp' -srtm_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/qgis_himat/SRTM_HMA.tif' -srtm_contour_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/qgis_himat/SRTM_HMA_countours_2km_gt3000m_smooth.shp' -rgi_glac_shp_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/qgis_himat/rgi60_HMA.shp' -#kaab_dict_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/qgis_himat/rgi60_HMA_w_watersheds_kaab.csv' -#kaab_csv = pd.read_csv(kaab_dict_fn) -#kaab_dict = dict(zip(kaab_csv.RGIId, kaab_csv.kaab)) -# GCMs and RCP scenarios -#gcm_names = ['CanESM2', 'CCSM4', 'CNRM-CM5', 'CSIRO-Mk3-6-0', 'GFDL-CM3', 'GFDL-ESM2M', 'GISS-E2-R', 'IPSL-CM5A-LR', -# 'IPSL-CM5A-MR', 'MIROC5', 'MRI-CGCM3', 'NorESM1-M'] -gcm_names = ['CanESM2'] -#gcm_names = ['CanESM2', 'CCSM4', 'CNRM-CM5', 'CSIRO-Mk3-6-0', 'GFDL-CM3', 'GFDL-ESM2M', 'GISS-E2-R', 'IPSL-CM5A-LR', -# 'MPI-ESM-LR', 'NorESM1-M'] -rcps = ['rcp26', 'rcp45', 'rcp85'] -#rcps = ['rcp26'] - -# Grouping -grouping = 'all' -#grouping = 'rgi_region' -#grouping = 'watershed' -#grouping = 'kaab' - -# Variable name -vn = 'mass_change' -#vn = 'volume_norm' -#vn = 'peakwater' - -# Group dictionaries -watershed_dict_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/qgis_himat/rgi60_HMA_dict_watershed.csv' -watershed_csv = pd.read_csv(watershed_dict_fn) -watershed_dict = dict(zip(watershed_csv.RGIId, watershed_csv.watershed)) -kaab_dict_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/qgis_himat/rgi60_HMA_dict_kaab.csv' -kaab_csv = pd.read_csv(kaab_dict_fn) -kaab_dict = dict(zip(kaab_csv.RGIId, kaab_csv.kaab_name)) - -# GRACE mascons -mascon_fp = input.main_directory + '/../GRACE/GSFC.glb.200301_201607_v02.4/' -mascon_fn = 'mascon.txt' -mascon_cns = ['CenLat', 'CenLon', 'LatWidth', 'LonWidth', 'Area_arcdeg', 'Area_km2', 'location', 'basin', - 'elevation_flag'] -mascon_df = pd.read_csv(mascon_fp + mascon_fn, header=None, names=mascon_cns, skiprows=14, - delim_whitespace=True) -mascon_df = mascon_df.sort_values(by=['CenLat', 'CenLon']) -mascon_df.reset_index(drop=True, inplace=True) - -degree_size = 0.25 -peakwater_Nyears = 10 - -# Plot label dictionaries -title_dict = {'Amu_Darya': 'Amu Darya', - 'Brahmaputra': 'Brahmaputra', - 'Ganges': 'Ganges', - 'Ili': 'Ili', - 'Indus': 'Indus', - 'Inner_Tibetan_Plateau': 'Inner TP', - 'Inner_Tibetan_Plateau_extended': 'Inner TP ext', - 'Irrawaddy': 'Irrawaddy', - 'Mekong': 'Mekong', - 'Salween': 'Salween', - 'Syr_Darya': 'Syr Darya', - 'Tarim': 'Tarim', - 'Yangtze': 'Yangtze', - 'inner_TP': 'Inner TP', - 'Karakoram': 'Karakoram', - 'Yigong': 'Yigong', - 'Yellow': 'Yellow', - 'Bhutan': 'Bhutan', - 'Everest': 'Everest', - 'West Nepal': 'West Nepal', - 'Spiti Lahaul': 'Spiti Lahaul', - 'tien_shan': 'Tien Shan', - 'Pamir': 'Pamir', - 'pamir_alai': 'Pamir Alai', - 'Kunlun': 'Kunlun', - 'Hindu Kush': 'Hindu Kush', - 13: 'Central Asia', - 14: 'South Asia West', - 15: 'South Asia East', - 'all': 'HMA' - } -title_location = {'Syr_Darya': [68, 46.1], - 'Ili': [83.6, 45.5], - 'Amu_Darya': [64.6, 36.9], - 'Tarim': [83.0, 39.2], - 'Inner_Tibetan_Plateau_extended': [100, 40], - 'Indus': [70.7, 31.9], - 'Inner_Tibetan_Plateau': [85, 32.4], - 'Yangtze': [106.0, 29.8], - 'Ganges': [81.3, 26.6], - 'Brahmaputra': [92.0, 26], - 'Irrawaddy': [96.2, 23.8], - 'Salween': [98.5, 20.8], - 'Mekong': [103.8, 17.5], - 'Yellow': [106.0, 36], - 13: [83,39], - 14: [70.8, 30], - 15: [81,26.8], - 'inner_TP': [89, 33.5], - 'Karakoram': [68.7, 33.5], - 'Yigong': [97.5, 26.2], - 'Bhutan': [92.1, 26], - 'Everest': [85, 26.3], - 'West Nepal': [76.5, 28], - 'Spiti Lahaul': [72, 31.9], - 'tien_shan': [80, 42], - 'Pamir': [67.3, 36.5], - 'pamir_alai': [65.2, 40.2], - 'Kunlun': [79, 37.5], - 'Hindu Kush': [65.3, 35] - } -vn_dict = {'volume_glac_annual': 'Normalized Volume [-]', - 'volume_norm': 'Normalized Volume Remaining [-]', - 'runoff_glac_annual': 'Normalized Runoff [-]', - 'peakwater': 'Peak Water [yr]', - 'temp_glac_annual': 'Temperature [$^\circ$C]', - 'prec_glac_annual': 'Precipitation [m]', - 'precfactor': 'Precipitation Factor [-]', - 'tempchange': 'Temperature bias [$^\circ$C]', - 'ddfsnow': 'DDFsnow [mm w.e. d$^{-1}$ $^\circ$C$^{-1}$]'} -rcp_dict = {'rcp26': '2.6', - 'rcp45': '4.5', - 'rcp60': '6.0', - 'rcp85': '8.5'} - -# Colors list -colors_rgb = [(0.00, 0.57, 0.57), (0.71, 0.43, 1.00), (0.86, 0.82, 0.00), (0.00, 0.29, 0.29), (0.00, 0.43, 0.86), - (0.57, 0.29, 0.00), (1.00, 0.43, 0.71), (0.43, 0.71, 1.00), (0.14, 1.00, 0.14), (1.00, 0.71, 0.47), - (0.29, 0.00, 0.57), (0.57, 0.00, 0.00), (0.71, 0.47, 1.00), (1.00, 1.00, 0.47)] -gcm_colordict = dict(zip(gcm_names, colors_rgb[0:len(gcm_names)])) -rcp_colordict = {'rcp26':'b', 'rcp45':'k', 'rcp60':'m', 'rcp85':'r'} -rcp_styledict = {'rcp26':':', 'rcp45':'--', 'rcp85':'-.'} - -east = 60 -west = 110 -south = 15 -north = 50 -xtick = 5 -ytick = 5 -xlabel = 'Longitude [$^\circ$]' -ylabel = 'Latitude [$^\circ$]' - - -#%% FUNCTIONS -def select_groups(grouping, main_glac_rgi_all): - """ - Select groups based on grouping - """ - if grouping == 'rgi_region': - groups = main_glac_rgi_all.O1Region.unique().tolist() - group_cn = 'O1Region' - elif grouping == 'watershed': - groups = main_glac_rgi_all.watershed.unique().tolist() - group_cn = 'watershed' - elif grouping == 'kaab': - groups = main_glac_rgi_all.kaab.unique().tolist() - group_cn = 'kaab' - groups = [x for x in groups if str(x) != 'nan'] - elif grouping == 'degree': - groups = main_glac_rgi_all.deg_id.unique().tolist() - group_cn = 'deg_id' - elif grouping == 'mascon': - groups = main_glac_rgi_all.mascon_idx.unique().tolist() - groups = [int(x) for x in groups] - group_cn = 'mascon_idx' - else: - groups = ['all'] - group_cn = 'all_group' - try: - groups = sorted(groups, key=str.lower) - except: - groups = sorted(groups) - return groups, group_cn - -def partition_multimodel_groups(gcm_names, grouping, vn, main_glac_rgi_all, rcp=None): - """Partition multimodel data by each group for all GCMs for a given variable - - Parameters - ---------- - gcm_names : list - list of GCM names - grouping : str - name of grouping to use - vn : str - variable name - main_glac_rgi_all : pd.DataFrame - glacier table - rcp : str - rcp name - - Output - ------ - time_values : np.array - time values that accompany the multimodel data - ds_group : list of lists - dataset containing the multimodel data for a given variable for all the GCMs - ds_glac : np.array - dataset containing the variable of interest for each gcm and glacier - """ - # Groups - groups, group_cn = select_groups(grouping, main_glac_rgi_all) - - # variable name - if vn == 'volume_norm' or vn == 'mass_change': - vn_adj = 'volume_glac_annual' - elif vn == 'peakwater': - vn_adj = 'runoff_glac_annual' - else: - vn_adj = vn - - ds_group = [[] for group in groups] - for ngcm, gcm_name in enumerate(gcm_names): - for region in rgi_regions: - - # Load datasets - if gcm_name == 'ERA-Interim': - netcdf_fp = netcdf_fp_era - ds_fn = 'R' + str(region) + '_ERA-Interim_c2_ba1_100sets_1980_2017.nc' - else: - netcdf_fp = netcdf_fp_cmip5 + vn_adj + '/' - ds_fn = ('R' + str(region) + '_' + gcm_name + '_' + rcp + '_c2_ba' + str(input.option_bias_adjustment) + - '_100sets_2000_2100--' + vn_adj + '.nc') - - # Bypass GCMs that are missing a rcp scenario - try: - ds = xr.open_dataset(netcdf_fp + ds_fn) - except: - continue - # Extract time variable - if 'annual' in vn_adj: - try: - time_values = ds[vn_adj].coords['year_plus1'].values - except: - time_values = ds[vn_adj].coords['year'].values - elif 'monthly' in vn_adj: - time_values = ds[vn_adj].coords['time'].values - - # Merge datasets - if region == rgi_regions[0]: - vn_glac_all = ds[vn_adj].values[:,:,0] - vn_glac_std_all = ds[vn_adj].values[:,:,1] - else: - vn_glac_all = np.concatenate((vn_glac_all, ds[vn_adj].values[:,:,0]), axis=0) - vn_glac_std_all = np.concatenate((vn_glac_std_all, ds[vn_adj].values[:,:,1]), axis=0) - - try: - ds.close() - except: - continue - - if ngcm == 0: - ds_glac = vn_glac_all[np.newaxis,:,:] - else: - ds_glac = np.concatenate((ds_glac, vn_glac_all[np.newaxis,:,:]), axis=0) - # Cycle through groups - for ngroup, group in enumerate(groups): - # Select subset of data - main_glac_rgi = main_glac_rgi_all.loc[main_glac_rgi_all[group_cn] == group] - vn_glac = vn_glac_all[main_glac_rgi.index.values.tolist(),:] -# vn_glac_std = vn_glac_std_all[main_glac_rgi.index.values.tolist(),:] -# vn_glac_var = vn_glac_std **2 - # Regional sum - vn_reg = vn_glac.sum(axis=0) - # Record data for multi-model stats - if ngcm == 0: - ds_group[ngroup] = [group, vn_reg] - else: - ds_group[ngroup][1] = np.vstack((ds_group[ngroup][1], vn_reg)) - - return groups, time_values, ds_group, ds_glac - -def partition_era_groups(grouping, vn, main_glac_rgi_all): - """Partition multimodel data by each group for all GCMs for a given variable - - Parameters - ---------- - grouping : str - name of grouping to use - vn : str - variable name - main_glac_rgi_all : pd.DataFrame - glacier table - - Output - ------ - time_values : np.array - time values that accompany the multimodel data - ds_group : list of lists - dataset containing the multimodel data for a given variable for all the GCMs - ds_glac : np.array - dataset containing the variable of interest for each gcm and glacier - """ - # Groups - groups, group_cn = select_groups(grouping, main_glac_rgi_all) - - # variable name - if vn == 'volume_norm' or vn == 'mass_change': - vn_adj = 'volume_glac_annual' - elif vn == 'peakwater': - vn_adj = 'runoff_glac_annual' - else: - vn_adj = vn - - ds_group = [[] for group in groups] - for region in rgi_regions: - # Load datasets - ds_fn = 'R' + str(region) + '_ERA-Interim_c2_ba1_100sets_1980_2017.nc' - ds = xr.open_dataset(netcdf_fp_era + ds_fn) - # Extract time variable - if 'annual' in vn_adj: - try: - time_values = ds[vn_adj].coords['year_plus1'].values - except: - time_values = ds[vn_adj].coords['year'].values - elif 'monthly' in vn_adj: - time_values = ds[vn_adj].coords['time'].values - - # Merge datasets - if region == rgi_regions[0]: - vn_glac_all = ds[vn_adj].values[:,:,0] - vn_glac_std_all = ds[vn_adj].values[:,:,1] - else: - vn_glac_all = np.concatenate((vn_glac_all, ds[vn_adj].values[:,:,0]), axis=0) - vn_glac_std_all = np.concatenate((vn_glac_std_all, ds[vn_adj].values[:,:,1]), axis=0) - - # Close dataset - ds.close() - - ds_glac = [vn_glac_all, vn_glac_std_all] - - # Cycle through groups - for ngroup, group in enumerate(groups): - # Select subset of data - main_glac_rgi = main_glac_rgi_all.loc[main_glac_rgi_all[group_cn] == group] - vn_glac = vn_glac_all[main_glac_rgi.index.values.tolist(),:] - vn_glac_std = vn_glac_std_all[main_glac_rgi.index.values.tolist(),:] - vn_glac_var = vn_glac_std **2 - - # Regional mean, standard deviation, and variance - # mean: E(X+Y) = E(X) + E(Y) - # var: Var(X+Y) = Var(X) + Var(Y) + 2*Cov(X,Y) - # assuming X and Y are indepdent, then Cov(X,Y)=0, so Var(X+Y) = Var(X) + Var(Y) - # std: std(X+Y) = (Var(X+Y))**0.5 - # Regional sum - vn_reg = vn_glac.sum(axis=0) - vn_reg_var = vn_glac_var.sum(axis=0) -# vn_reg_std = vn_glac_var**0.5 - - # Record data for multi-model stats - ds_group[ngroup] = [group, vn_reg, vn_reg_var] - - return groups, time_values, ds_group, ds_glac - - -def partition_modelparams_groups(grouping, vn, main_glac_rgi_all): - """Partition model parameters by each group - - Parameters - ---------- - grouping : str - name of grouping to use - vn : str - variable name - main_glac_rgi_all : pd.DataFrame - glacier table - - Output - ------ - groups : list - list of group names - ds_group : list of lists - dataset containing the multimodel data for a given variable for all the GCMs - """ - # Groups - groups, group_cn = select_groups(grouping, main_glac_rgi_all) - - ds_group = [[] for group in groups] - - # Cycle through groups - for ngroup, group in enumerate(groups): - # Select subset of data - main_glac_rgi = main_glac_rgi_all.loc[main_glac_rgi_all[group_cn] == group] - vn_glac = main_glac_rgi_all[vn].values[main_glac_rgi.index.values.tolist()] - # Regional sum - vn_reg = vn_glac.mean(axis=0) - - # Record data for each group - ds_group[ngroup] = [group, vn_reg] - - return groups, ds_group - - -def vn_multimodel_mean_processed(vn, ds, idx, time_values, every_glacier=0): - """ - Calculate multi-model mean for a given variable of interest - - Parameters - ---------- - vn : str - variable/parameter name - ds : list - dataset containing groups - group_idx : int - group index - time_values : np.array - array of years - every_glacier : int - switch to work with groups or work with concatenated dataframe - - Output - ------ - - """ - # Multi-model mean - if every_glacier == 0: - vn_multimodel_mean = ds[idx][1].mean(axis=0) - else: - vn_multimodel_mean = ds[:,idx,:].mean(axis=0) - - # Normalized volume based on initial volume - if vn == 'volume_norm': - if vn_multimodel_mean[0] > 0: - output_multimodel_mean = vn_multimodel_mean / vn_multimodel_mean[0] - else: - output_multimodel_mean = np.zeros(vn_multimodel_mean.shape) - # Peak water based on 10-yr running average - elif vn == 'peakwater': - vn_runningmean = uniform_filter(vn_multimodel_mean, peakwater_Nyears) - output_multimodel_mean = time_values[np.where(vn_runningmean == vn_runningmean.max())[-1][0]] - return output_multimodel_mean - - -def peakwater(runoff, time_values, nyears): - """Compute peak water based on the running mean of N years - - Parameters - ---------- - runoff : np.array - one-dimensional array of runoff for each timestep - time_values : np.array - time associated with each timestep - nyears : int - number of years to compute running mean used to smooth peakwater variations - - Output - ------ - peakwater_yr : int - peakwater year - peakwater_chg : float - percent change of peak water compared to first timestep (running means used) - runoff_chg : float - percent change in runoff at the last timestep compared to the first timestep (running means used) - """ - runningmean = uniform_filter(runoff, size=(nyears)) - peakwater_idx = np.where(runningmean == runningmean.max())[-1][0] - peakwater_yr = time_values[peakwater_idx] - peakwater_chg = (runningmean[peakwater_idx] - runningmean[0]) / runningmean[0] * 100 - runoff_chg = (runningmean[-1] - runningmean[0]) / runningmean[0] * 100 - return peakwater_yr, peakwater_chg, runoff_chg - - -def size_thresholds(variable, cutoffs, sizes): - """Loop through size thresholds for a given variable to plot - - Parameters - ---------- - variable : np.array - data associated with glacier characteristic - cutoffs : list - values used as minimums for thresholds - (ex. 100 would give you greater than 100) - sizes : list - size values for the plot - - Output - ------ - output : np.array - plot size for each glacier - """ - output = np.zeros(variable.shape) - for i, cutoff in enumerate(cutoffs): - output[(variable>cutoff) & (output==0)] = sizes[i] - output[output==0] = 2 - return output - - -def select_region_climatedata(gcm_name, rcp, main_glac_rgi): - """ - Get the regional temperature and precipitation for a given dataset. - - Extracts all nearest neighbor temperature and precipitation data for a given set of glaciers. The mean temperature - and precipitation of the group of glaciers is returned. If two glaciers have the same temp/prec data, that data - is only used once in the mean calculations. Additionally, one would not expect for different GCMs to be similar - because they all have different resolutions, so this mean calculations will have different numbers of pixels. - - Parameters - ---------- - gcm_name : str - GCM name - rcp : str - rcp scenario (ex. rcp26) - main_glac_rgi : pd.DataFrame - glacier dataset used to select the nearest neighbor climate data - """ - # Date tables - print('select_region_climatedata fxn dates supplied manually') - dates_table_ref = modelsetup.datesmodelrun(startyear=2000, endyear=2100, spinupyears=0, - option_wateryear=1) - dates_table = modelsetup.datesmodelrun(startyear=2000, endyear=2100, spinupyears=0, - option_wateryear=1) - # Load gcm lat/lons - gcm = class_climate.GCM(name=gcm_name, rcp_scenario=rcp) - # Select lat/lon from GCM - ds_elev = xr.open_dataset(gcm.fx_fp + gcm.elev_fn) - gcm_lat_values_all = ds_elev.lat.values - gcm_lon_values_all = ds_elev.lon.values - ds_elev.close() - # Lat/lon dictionary to convert - gcm_lat_dict = dict(zip(range(gcm_lat_values_all.shape[0]), list(gcm_lat_values_all))) - gcm_lon_dict = dict(zip(range(gcm_lon_values_all.shape[0]), list(gcm_lon_values_all))) - - # Find nearest neighbors for glaciers that have pixles - latlon_nearidx = pd.DataFrame(np.zeros((main_glac_rgi.shape[0],2)), columns=['CenLat','CenLon']) - latlon_nearidx.iloc[:,0] = (np.abs(main_glac_rgi.CenLat.values[:,np.newaxis] - gcm_lat_values_all).argmin(axis=1)) - latlon_nearidx.iloc[:,1] = (np.abs(main_glac_rgi.CenLon.values[:,np.newaxis] - gcm_lon_values_all).argmin(axis=1)) - latlon_nearidx = latlon_nearidx.drop_duplicates().sort_values(['CenLat', 'CenLon']) - latlon_nearidx.reset_index(drop=True, inplace=True) - latlon_reg = latlon_nearidx.copy() - latlon_reg.CenLat.replace(gcm_lat_dict, inplace=True) - latlon_reg.CenLon.replace(gcm_lon_dict, inplace=True) - # ===== LOAD CLIMATE DATA ===== - # Reference climate data - ref_gcm = class_climate.GCM(name=input.ref_gcm_name) - # Air temperature [degC], Precipitation [m], Elevation [masl], Lapse rate [K m-1] - ref_temp, ref_dates = ref_gcm.importGCMvarnearestneighbor_xarray(ref_gcm.temp_fn, ref_gcm.temp_vn, latlon_reg, - dates_table_ref) - ref_prec, ref_dates = ref_gcm.importGCMvarnearestneighbor_xarray(ref_gcm.prec_fn, ref_gcm.prec_vn, latlon_reg, - dates_table_ref) -# ref_elev = ref_gcm.importGCMfxnearestneighbor_xarray(ref_gcm.elev_fn, ref_gcm.elev_vn, latlon_reg) - # GCM climate data - gcm_temp_all, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn, gcm.temp_vn, latlon_reg, dates_table) - gcm_prec_all, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn, gcm.prec_vn, latlon_reg, dates_table) -# gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn, latlon_reg) - # GCM subset to agree with reference time period to calculate bias corrections - gcm_subset_idx_start = np.where(dates_table.date.values == dates_table_ref.date.values[0])[0][0] - gcm_subset_idx_end = np.where(dates_table.date.values == dates_table_ref.date.values[-1])[0][0] - gcm_temp = gcm_temp_all[:,gcm_subset_idx_start:gcm_subset_idx_end+1] - gcm_prec = gcm_prec_all[:,gcm_subset_idx_start:gcm_subset_idx_end+1] - - ## ===== BIAS ADJUSTMENTS ===== - # OPTION 2: Adjust temp and prec according to Huss and Hock (2015) accounts for means and interannual variability - if input.option_bias_adjustment == 2: - # TEMPERATURE BIAS CORRECTIONS - # Mean monthly temperature - ref_temp_monthly_avg = (ref_temp.reshape(-1,12).transpose() - .reshape(-1,int(ref_temp.shape[1]/12)).mean(1).reshape(12,-1).transpose()) - gcm_temp_monthly_avg = (gcm_temp.reshape(-1,12).transpose() - .reshape(-1,int(gcm_temp.shape[1]/12)).mean(1).reshape(12,-1).transpose()) - # Monthly bias adjustment - gcm_temp_monthly_adj = ref_temp_monthly_avg - gcm_temp_monthly_avg - # Monthly temperature bias adjusted according to monthly average - t_mt = gcm_temp_all + np.tile(gcm_temp_monthly_adj, int(gcm_temp_all.shape[1]/12)) - # Mean monthly temperature bias adjusted according to monthly average - t_m25avg = np.tile(gcm_temp_monthly_avg + gcm_temp_monthly_adj, int(gcm_temp_all.shape[1]/12)) - # Calculate monthly standard deviation of temperature - ref_temp_monthly_std = (ref_temp.reshape(-1,12).transpose() - .reshape(-1,int(ref_temp.shape[1]/12)).std(1).reshape(12,-1).transpose()) - gcm_temp_monthly_std = (gcm_temp.reshape(-1,12).transpose() - .reshape(-1,int(gcm_temp.shape[1]/12)).std(1).reshape(12,-1).transpose()) - variability_monthly_std = ref_temp_monthly_std / gcm_temp_monthly_std - # Bias adjusted temperature accounting for monthly mean and variability - gcm_temp_bias_adj = t_m25avg + (t_mt - t_m25avg) * np.tile(variability_monthly_std, int(gcm_temp_all.shape[1]/12)) - - # PRECIPITATION BIAS CORRECTIONS - # Calculate monthly mean precipitation - ref_prec_monthly_avg = (ref_prec.reshape(-1,12).transpose() - .reshape(-1,int(ref_temp.shape[1]/12)).mean(1).reshape(12,-1).transpose()) - gcm_prec_monthly_avg = (gcm_prec.reshape(-1,12).transpose() - .reshape(-1,int(gcm_temp.shape[1]/12)).mean(1).reshape(12,-1).transpose()) - bias_adj_prec = ref_prec_monthly_avg / gcm_prec_monthly_avg - # Bias adjusted precipitation accounting for differences in monthly mean - gcm_prec_bias_adj = gcm_prec_all * np.tile(bias_adj_prec, int(gcm_temp_all.shape[1]/12)) - - # Regional means - reg_mean_temp_biasadj = gcm_temp_bias_adj.mean(axis=0) - reg_mean_prec_biasadj = gcm_prec_bias_adj.mean(axis=0) - - return reg_mean_temp_biasadj, reg_mean_prec_biasadj - - -#%% LOAD ALL GLACIERS -# Load all glaciers -for rgi_region in rgi_regions: - # Data on all glaciers - main_glac_rgi_region = modelsetup.selectglaciersrgitable(rgi_regionsO1=[rgi_region], rgi_regionsO2 = 'all', - rgi_glac_number='all') - # Glacier hypsometry [km**2] - main_glac_hyps_region = modelsetup.import_Husstable(main_glac_rgi_region, input.hyps_filepath, - input.hyps_filedict, input.hyps_colsdrop) - # Ice thickness [m], average - main_glac_icethickness_region= modelsetup.import_Husstable(main_glac_rgi_region, - input.thickness_filepath, input.thickness_filedict, - input.thickness_colsdrop) - - if rgi_region == rgi_regions[0]: - main_glac_rgi_all = main_glac_rgi_region - main_glac_hyps_all = main_glac_hyps_region - main_glac_icethickness_all = main_glac_icethickness_region - else: - main_glac_rgi_all = pd.concat([main_glac_rgi_all, main_glac_rgi_region], sort=False) - main_glac_hyps_all = pd.concat([main_glac_hyps_all, main_glac_hyps_region], sort=False) - main_glac_icethickness_all = pd.concat([main_glac_icethickness_all, main_glac_icethickness_region], sort=False) - -# Add watersheds, regions, degrees, mascons, and all groups to main_glac_rgi_all -# Watersheds -main_glac_rgi_all['watershed'] = main_glac_rgi_all.RGIId.map(watershed_dict) -# Regions -main_glac_rgi_all['kaab'] = main_glac_rgi_all.RGIId.map(kaab_dict) -# Degrees -main_glac_rgi_all['CenLon_round'] = np.floor(main_glac_rgi_all.CenLon.values/degree_size) * degree_size -main_glac_rgi_all['CenLat_round'] = np.floor(main_glac_rgi_all.CenLat.values/degree_size) * degree_size -deg_groups = main_glac_rgi_all.groupby(['CenLon_round', 'CenLat_round']).size().index.values.tolist() -deg_dict = dict(zip(deg_groups, np.arange(0,len(deg_groups)))) -main_glac_rgi_all.reset_index(drop=True, inplace=True) -cenlon_cenlat = [(main_glac_rgi_all.loc[x,'CenLon_round'], main_glac_rgi_all.loc[x,'CenLat_round']) - for x in range(len(main_glac_rgi_all))] -main_glac_rgi_all['CenLon_CenLat'] = cenlon_cenlat -main_glac_rgi_all['deg_id'] = main_glac_rgi_all.CenLon_CenLat.map(deg_dict) -# Mascons -if grouping == 'mascon' or option_subset_GRACE == 1: - main_glac_rgi_all['mascon_idx'] = np.nan - for glac in range(main_glac_rgi_all.shape[0]): - latlon_dist = (((mascon_df.CenLat.values - main_glac_rgi_all.CenLat.values[glac])**2 + - (mascon_df.CenLon.values - main_glac_rgi_all.CenLon.values[glac])**2)**0.5) - main_glac_rgi_all.loc[glac,'mascon_idx'] = [x[0] for x in np.where(latlon_dist == latlon_dist.min())][0] - mascon_groups = main_glac_rgi_all.mascon_idx.unique().tolist() - mascon_groups = [int(x) for x in mascon_groups] - mascon_groups = sorted(mascon_groups) - mascon_latlondict = dict(zip(mascon_groups, mascon_df[['CenLat', 'CenLon']].values[mascon_groups].tolist())) - -# All -main_glac_rgi_all['all_group'] = 'all' - - - -#%% TIME SERIES OF SUBPLOTS FOR EACH GROUP -if option_plot_cmip5_normalizedchange == 1: -# vns = ['volume_glac_annual', 'runoff_glac_annual'] - vns = ['volume_glac_annual'] -# vns = ['runoff_glac_annual'] -# vns = ['temp_glac_annual'] -# vns = ['prec_glac_annual'] - # NOTE: Temperatures and precipitation will not line up exactly because each region is covered by a different - # number of pixels, and hence the mean of those pixels is not going to be equal. - - multimodel_linewidth = 2 - alpha=0.2 - - # Determine grouping - if grouping == 'rgi_region': - groups = rgi_regions - group_cn = 'O1Region' - elif grouping == 'watershed': - groups = main_glac_rgi_all.watershed.unique().tolist() - group_cn = 'watershed' - elif grouping == 'kaab': - groups = main_glac_rgi_all.kaab.unique().tolist() - group_cn = 'kaab' - groups = [x for x in groups if str(x) != 'nan'] - elif grouping == 'degree': - groups = main_glac_rgi_all.deg_id.unique().tolist() - group_cn = 'deg_id' - elif grouping == 'all': - groups = ['all'] - group_cn = 'all_group' - try: - groups = sorted(groups, key=str.lower) - except: - groups = groups - - if grouping == 'watershed': - groups.remove('Irrawaddy') - groups.remove('Yellow') -# # Adjust groups if desired -# remove_groups = ['Amu_Darya', 'Brahmaputra', 'Ili', 'Inner_Tibetan_Plateau', 'Inner_Tibetan_Plateau_extended', -# 'Mekong', 'Salween', 'Syr_Darya', 'Tarim'] -# for x in remove_groups: -# print('removed group ', x) -# groups.remove(x) - - reg_legend = [] - num_cols_max = 4 - if len(groups) < num_cols_max: - num_cols = len(groups) - else: - num_cols = num_cols_max - num_rows = int(np.ceil(len(groups)/num_cols)) - - for vn in vns: - fig, ax = plt.subplots(num_rows, num_cols, squeeze=False, sharex=False, sharey=True, - figsize=(5*num_rows,4*num_cols), gridspec_kw = {'wspace':0, 'hspace':0}) - add_group_label = 1 - - for rcp in rcps: -# for rcp in ['rcp85']: - ds_multimodels = [[] for group in groups] - if vn == 'volume_glac_annual': - masschg_multimodels = [[] for group in groups] - - for ngcm, gcm_name in enumerate(gcm_names): -# for ngcm, gcm_name in enumerate(['CSIRO-Mk3-6-0']): -# print(ngcm, gcm_name) - - # Merge all data, then select group data - for region in rgi_regions: - # Load datasets - if gcm_name == 'ERA-Interim': - netcdf_fp = netcdf_fp_era - ds_fn = 'R' + str(region) + '--ERA-Interim_c2_ba0_200sets_2000_2017_stats.nc' - else: - netcdf_fp = netcdf_fp_cmip5 + gcm_name + '/' - ds_fn = ('R' + str(region) + '_' + gcm_name + '_' + rcp + '_c2_ba1_100sets_2000_2100.nc') - # Bypass GCMs that are missing a rcp scenario - try: - ds = xr.open_dataset(netcdf_fp + ds_fn) - except: - continue - # Extract time variable - if 'annual' in vn: - try: - time_values = ds[vn].coords['year_plus1'].values - except: - time_values = ds[vn].coords['year'].values - # Merge datasets - if region == rgi_regions[0]: - vn_glac_all = ds[vn].values[:,:,0] - vn_glac_std_all = ds[vn].values[:,:,1] - else: - vn_glac_all = np.concatenate((vn_glac_all, ds[vn].values[:,:,0]), axis=0) - vn_glac_std_all = np.concatenate((vn_glac_std_all, ds[vn].values[:,:,1]), axis=0) - - try: - ds.close() - except: - continue - - - # Cycle through groups - row_idx = 0 - col_idx = 0 - for ngroup, group in enumerate(groups): -# for ngroup, group in enumerate([groups[1]]): - # Set subplot position - if (ngroup % num_cols == 0) and (ngroup != 0): - row_idx += 1 - col_idx = 0 - - # Select subset of data - main_glac_rgi = main_glac_rgi_all.loc[main_glac_rgi_all[group_cn] == group] - vn_glac = vn_glac_all[main_glac_rgi.index.values.tolist(),:] - vn_glac_std = vn_glac_std_all[main_glac_rgi.index.values.tolist(),:] - vn_glac_var = vn_glac_std **2 - - # Plot data - if vn == 'volume_glac_annual': - # Regional mean, standard deviation, and variance - # mean: E(X+Y) = E(X) + E(Y) - # var: Var(X+Y) = Var(X) + Var(Y) + 2*Cov(X,Y) - # assuming X and Y are indepdent, then Cov(X,Y)=0, so Var(X+Y) = Var(X) + Var(Y) - # std: std(X+Y) = (Var(X+Y))**0.5 - vn_reg = vn_glac.sum(axis=0) - vn_reg_var = vn_glac_var.sum(axis=0) - vn_reg_std = vn_reg_var**0.5 - vn_reg_stdhigh = vn_reg + vn_reg_std - vn_reg_stdlow = vn_reg - vn_reg_std - # Regional normalized volume - vn_reg_norm = vn_reg / vn_reg[0] - vn_reg_norm_stdhigh = vn_reg_stdhigh / vn_reg[0] - vn_reg_norm_stdlow = vn_reg_stdlow / vn_reg[0] - vn_reg_plot = vn_reg_norm.copy() - vn_reg_plot_stdlow = vn_reg_norm_stdlow.copy() - vn_reg_plot_stdhigh = vn_reg_norm_stdhigh.copy() - - # Mass change for text on plot - # Gt = km3 ice * density_ice / 1000 - # divide by 1000 because density of ice is 900 kg/m3 or 0.900 Gt/km3 - vn_reg_masschange = (vn_reg[-1] - vn_reg[0]) * input.density_ice / 1000 - - elif ('prec' in vn) or ('temp' in vn): - # Regional mean function (monthly data) - reg_mean_temp_biasadj, reg_mean_prec_biasadj = ( - select_region_climatedata(gcm_name, rcp, main_glac_rgi)) - # Annual region mean - if 'prec' in vn: - reg_var_mean_annual = reg_mean_prec_biasadj.reshape(-1,12).sum(axis=1) - elif 'temp' in vn: - reg_var_mean_annual = reg_mean_temp_biasadj.reshape(-1,12).mean(axis=1) - # Plot data - vn_reg_plot = reg_var_mean_annual.copy() - elif vn == 'runoff_glac_annual': - # Regional mean, standard deviation, and variance - # mean: E(X+Y) = E(X) + E(Y) - # var: Var(X+Y) = Var(X) + Var(Y) + 2*Cov(X,Y) - # assuming X and Y are indepdent, then Cov(X,Y)=0, so Var(X+Y) = Var(X) + Var(Y) - # std: std(X+Y) = (Var(X+Y))**0.5 - vn_reg = vn_glac.sum(axis=0) - vn_reg_var = vn_glac_var.sum(axis=0) - vn_reg_std = vn_reg_var**0.5 - vn_reg_stdhigh = vn_reg + vn_reg_std - vn_reg_stdlow = vn_reg - vn_reg_std - # Runoff from 2000 - 2017 - t1_idx = np.where(time_values == 2000)[0][0] - t2_idx = np.where(time_values == 2017)[0][0] - vn_reg_2000_2017_mean = vn_reg[t1_idx:t2_idx+1].sum() / (t2_idx - t1_idx + 1) - # Regional normalized volume - vn_reg_norm = vn_reg / vn_reg_2000_2017_mean - vn_reg_norm_stdhigh = vn_reg_stdhigh / vn_reg_2000_2017_mean - vn_reg_norm_stdlow = vn_reg_stdlow / vn_reg_2000_2017_mean - vn_reg_plot = vn_reg_norm.copy() - vn_reg_plot_stdlow = vn_reg_norm_stdlow.copy() - vn_reg_plot_stdhigh = vn_reg_norm_stdhigh.copy() - - # ===== Plot ===== - if option_plot_individual_gcms == 1: - ax[row_idx, col_idx].plot(time_values, vn_reg_plot, color=rcp_colordict[rcp], linewidth=1, - alpha=alpha, label=None) - # # Volume change uncertainty - # if vn == 'volume_glac_annual': - # ax[row_idx, col_idx].fill_between( - # time_values, vn_reg_plot_stdlow, vn_reg_plot_stdhigh, - # facecolor=gcm_colordict[gcm_name], alpha=0.15, label=None) - - # Group labels -# ax[row_idx, col_idx].set_title(title_dict[group], size=14) - if add_group_label == 1: - ax[row_idx, col_idx].text(0.5, 0.99, title_dict[group], size=14, horizontalalignment='center', - verticalalignment='top', transform=ax[row_idx, col_idx].transAxes) - - # Tick parameters - ax[row_idx, col_idx].tick_params(axis='both', which='major', labelsize=25, direction='inout') - ax[row_idx, col_idx].tick_params(axis='both', which='minor', labelsize=15, direction='inout') - # X-label - ax[row_idx, col_idx].set_xlim(time_values.min(), time_values.max()) - ax[row_idx, col_idx].xaxis.set_tick_params(labelsize=14) - ax[row_idx, col_idx].xaxis.set_major_locator(plt.MultipleLocator(50)) - ax[row_idx, col_idx].xaxis.set_minor_locator(plt.MultipleLocator(10)) - if col_idx == 0 and row_idx == num_rows-1: - ax[row_idx, col_idx].set_xticklabels(['','2000','2050','2100']) - elif row_idx == num_rows-1: - ax[row_idx, col_idx].set_xticklabels(['','','2050','2100']) - else: - ax[row_idx, col_idx].set_xticklabels(['','','','']) - # labels are the first one, 2000, 2050, 2100, and 2101 - # Y-label - ax[row_idx, col_idx].yaxis.set_tick_params(labelsize=14) -# ax[row_idx, col_idx].yaxis.set_major_locator(MaxNLocator(prune='both')) - if vn == 'volume_glac_annual': - if option_plot_individual_gcms == 1: - ax[row_idx, col_idx].set_ylim(0,1.35) - ax[row_idx, col_idx].yaxis.set_major_locator(plt.MultipleLocator(0.2)) - ax[row_idx, col_idx].yaxis.set_minor_locator(plt.MultipleLocator(0.1)) - elif vn == 'runoff_glac_annual': - ax[row_idx, col_idx].set_ylim(0,2) - ax[row_idx, col_idx].yaxis.set_major_locator(plt.MultipleLocator(0.5)) - ax[row_idx, col_idx].yaxis.set_minor_locator(plt.MultipleLocator(0.1)) - ax[row_idx, col_idx].set_yticklabels(['','','0.5','1.0','1.5', '']) - elif vn == 'temp_glac_annual': - ax[row_idx, col_idx].yaxis.set_major_locator(plt.MultipleLocator()) - ax[row_idx, col_idx].yaxis.set_minor_locator(plt.MultipleLocator()) - elif vn == 'prec_glac_annual': - ax[row_idx, col_idx].yaxis.set_major_locator(plt.MultipleLocator()) - ax[row_idx, col_idx].yaxis.set_minor_locator(plt.MultipleLocator()) - - # Count column index to plot - col_idx += 1 - - # Record data for multi-model stats - if ngcm == 0: - ds_multimodels[ngroup] = [group, vn_reg_plot] - else: - ds_multimodels[ngroup][1] = np.vstack((ds_multimodels[ngroup][1], vn_reg_plot)) - - if vn == 'volume_glac_annual': - if ngcm == 0: - # print(group, rcp, gcm_name, vn_reg_masschange) - masschg_multimodels[ngroup] = [group, vn_reg_masschange] - else: - # print(group, rcp, gcm_name, vn_reg_masschange) - masschg_multimodels[ngroup][1] = np.vstack((masschg_multimodels[ngroup][1], - vn_reg_masschange)) - - - # Only add group label once - add_group_label = 0 - - if vn == 'temp_glac_annual' or vn == 'prec_glac_annual': - skip_fill = 1 - else: - skip_fill = 0 - -# # Multi-model mean -# row_idx = 0 -# col_idx = 0 -# for ngroup, group in enumerate(groups): -# if (ngroup % num_cols == 0) and (ngroup != 0): -# row_idx += 1 -# col_idx = 0 -# # Multi-model statistics -# vn_multimodel_mean = ds_multimodels[ngroup][1].mean(axis=0) -# vn_multimodel_std = ds_multimodels[ngroup][1].std(axis=0) -# vn_multimodel_stdlow = vn_multimodel_mean - vn_multimodel_std -# vn_multimodel_stdhigh = vn_multimodel_mean + vn_multimodel_std -# ax[row_idx, col_idx].plot(time_values, vn_multimodel_mean, color=rcp_colordict[rcp], -# linewidth=multimodel_linewidth, label=rcp) -# if skip_fill == 0: -# ax[row_idx, col_idx].fill_between(time_values, vn_multimodel_stdlow, vn_multimodel_stdhigh, -# facecolor=rcp_colordict[rcp], alpha=0.2, label=None) -# -# # Add mass change to plot -# if vn == 'volume_glac_annual': -# masschg_multimodel_mean = masschg_multimodels[ngroup][1].mean(axis=0)[0] -# -# print(group, rcp, np.round(masschg_multimodel_mean,0),'Gt', -# np.round((vn_multimodel_mean[-1] - 1)*100,0), '%') -# -# if vn == 'volume_glac_annual' and rcp == rcps[-1]: -# masschange_str = '(' + str(masschg_multimodel_mean).split('.')[0] + ' Gt)' -# if grouping == 'all': -# ax[row_idx, col_idx].text(0.5, 0.93, masschange_str, size=12, horizontalalignment='center', -# verticalalignment='top', transform=ax[row_idx, col_idx].transAxes, -# color=rcp_colordict[rcp]) -# else: -# ax[row_idx, col_idx].text(0.5, 0.88, masschange_str, size=12, horizontalalignment='center', -# verticalalignment='top', transform=ax[row_idx, col_idx].transAxes, -# color=rcp_colordict[rcp]) -# # Adjust subplot column index -# col_idx += 1 - - # RCP Legend - rcp_lines = [] - for rcp in rcps: - line = Line2D([0,1],[0,1], color=rcp_colordict[rcp], linewidth=multimodel_linewidth) - rcp_lines.append(line) - rcp_labels = [rcp_dict[rcp] for rcp in rcps] - if vn == 'temp_glac_annual' or vn == 'prec_glac_annual': - legend_loc = 'upper left' - else: - legend_loc = 'lower left' - ax[0,0].legend(rcp_lines, rcp_labels, loc=legend_loc, fontsize=12, labelspacing=0, handlelength=1, - handletextpad=0.5, borderpad=0, frameon=False, title='RCP') - -# # GCM Legend -# gcm_lines = [] -# for gcm_name in gcm_names: -# line = Line2D([0,1],[0,1], linestyle='-', color=gcm_colordict[gcm_name]) -# gcm_lines.append(line) -# gcm_legend = gcm_names.copy() -# fig.legend(gcm_lines, gcm_legend, loc='center right', title='GCMs', bbox_to_anchor=(1.06,0.5), -# handlelength=0, handletextpad=0, borderpad=0, frameon=False) - - # Y-Label - if len(groups) == 1: - fig.text(-0.01, 0.5, vn_dict[vn], va='center', rotation='vertical', size=14) - else: - fig.text(0.03, 0.5, vn_dict[vn], va='center', rotation='vertical', size=16) -# fig.text(0.03, 0.5, 'Normalized\nVolume [-]', va='center', ha='center', rotation='vertical', size=16) -# fig.text(0.03, 0.5, 'Normalized\nGlacier Runoff [-]', va='center', ha='center', rotation='vertical', size=16) - - # Save figure - if len(groups) == 1: - fig.set_size_inches(4, 4) - else: - fig.set_size_inches(7, num_rows*2) - if option_plot_individual_gcms == 1: - figure_fn = grouping + '_' + vn + '_wgcms_' + str(len(gcm_names)) + 'gcms_' + str(len(rcps)) + 'rcps.png' - else: - figure_fn = grouping + '_' + vn + '_' + str(len(gcm_names)) + 'gcms_' + str(len(rcps)) + 'rcps.png' - - - fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300) - - -#%% RUNOFF COMPONENTS FOR EACH GROUP -if option_plot_cmip5_runoffcomponents == 1: - vns = ['prec_glac_annual', 'melt_glac_annual', 'melt_glac_summer', 'refreeze_glac_annual'] - multimodel_linewidth = 1 - - # Load all glaciers - for rgi_region in rgi_regions: - # Data on all glaciers - main_glac_rgi_region = modelsetup.selectglaciersrgitable(rgi_regionsO1=[rgi_region], rgi_regionsO2 = 'all', - rgi_glac_number='all') - if rgi_region == rgi_regions[0]: - main_glac_rgi_all = main_glac_rgi_region - else: - main_glac_rgi_all = pd.concat([main_glac_rgi_all, main_glac_rgi_region]) - - # Add watersheds to main_glac_rgi_all - main_glac_rgi_all['watershed'] = main_glac_rgi_all.RGIId.map(watershed_dict) - - # Determine grouping - if grouping == 'rgi_region': - groups = rgi_regions - group_cn = 'O1Region' - elif grouping == 'watershed': - groups = main_glac_rgi_all.watershed.unique().tolist() - groups.remove('Irrawaddy') - group_cn = 'watershed' - groups = sorted(groups, key=str.lower) - - #%% - reg_legend = [] - num_cols_max = 4 - if len(groups) < num_cols_max: - num_cols = len(groups) - else: - num_cols = num_cols_max - num_rows = int(np.ceil(len(groups)/num_cols)) - - fig, ax = plt.subplots(num_rows, num_cols, squeeze=False, sharex=False, sharey=True, - figsize=(4*num_rows,3*num_cols), gridspec_kw = {'wspace':0, 'hspace':0}) - add_group_label = 1 - - for rcp in rcps: -# for rcp in ['rcp85']: - ds_prec = [[] for group in groups] - ds_melt = [[] for group in groups] - ds_melt_summer = [[] for group in groups] - ds_refreeze = [[] for group in groups] - - for ngcm, gcm_name in enumerate(gcm_names): - - for vn in vns: - - # Merge all data, then select group data - for region in rgi_regions: - # Load datasets - if gcm_name == 'ERA-Interim': - netcdf_fp = netcdf_fp_era - ds_fn = 'R' + str(region) + '--ERA-Interim_c2_ba0_200sets_2000_2017_stats.nc' - else: - netcdf_fp = netcdf_fp_cmip5 + vn + '/' - ds_fn = ('R' + str(region) + '_' + gcm_name + '_' + rcp + '_c2_ba2_100sets_2000_2100--' - + vn + '.nc') - # Bypass GCMs that are missing a rcp scenario - try: - ds = xr.open_dataset(netcdf_fp + ds_fn) - except: - continue - # Extract time variable - if 'annual' in vn: - try: - time_values = ds[vn].coords['year_plus1'].values - except: - time_values = ds[vn].coords['year'].values - # Merge datasets - if region == rgi_regions[0]: - vn_glac_all = ds[vn].values[:,:,0] - vn_glac_std_all = ds[vn].values[:,:,1] - else: - vn_glac_all = np.concatenate((vn_glac_all, ds[vn].values[:,:,0]), axis=0) - vn_glac_std_all = np.concatenate((vn_glac_std_all, ds[vn].values[:,:,1]), axis=0) - - try: - ds.close() - except: - continue - - # Cycle through groups - for ngroup, group in enumerate(groups): - - # Select subset of data - main_glac_rgi = main_glac_rgi_all.loc[main_glac_rgi_all[group_cn] == group] - vn_glac = vn_glac_all[main_glac_rgi.index.values.tolist(),:] - vn_glac_std = vn_glac_std_all[main_glac_rgi.index.values.tolist(),:] - vn_glac_var = vn_glac_std **2 - - # Regional mean - vn_reg = vn_glac.sum(axis=0) - - # Record data for multi-model stats - if vn == 'prec_glac_annual': - if ngcm == 0: - ds_prec[ngroup] = [group, vn_reg] - else: - ds_prec[ngroup][1] = np.vstack((ds_prec[ngroup][1], vn_reg)) - elif vn == 'melt_glac_annual': - if ngcm == 0: - ds_melt[ngroup] = [group, vn_reg] - else: - ds_melt[ngroup][1] = np.vstack((ds_melt[ngroup][1], vn_reg)) - elif vn == 'melt_glac_summer': - if ngcm == 0: - ds_melt_summer[ngroup] = [group, vn_reg] - else: - ds_melt_summer[ngroup][1] = np.vstack((ds_melt_summer[ngroup][1], vn_reg)) - elif vn == 'refreeze_glac_annual': - if ngcm == 0: - ds_refreeze[ngroup] = [group, vn_reg] - else: - ds_refreeze[ngroup][1] = np.vstack((ds_refreeze[ngroup][1], vn_reg)) - - # Multi-model mean - row_idx = 0 - col_idx = 0 - for ngroup, group in enumerate(groups): - if (ngroup % num_cols == 0) and (ngroup != 0): - row_idx += 1 - col_idx = 0 - # Multi-model statistics - prec_multimodel_mean = ds_prec[ngroup][1].mean(axis=0) - melt_multimodel_mean = ds_melt[ngroup][1].mean(axis=0) - melt_summer_multimodel_mean = ds_melt_summer[ngroup][1].mean(axis=0) - refreeze_multimodel_mean = ds_refreeze[ngroup][1].mean(axis=0) - # Runoff and components (melt adjusted = melt - refreeze) - runoff_multimodel_mean = prec_multimodel_mean + melt_multimodel_mean - refreeze_multimodel_mean - meltadj_multimodel_mean = melt_multimodel_mean - refreeze_multimodel_mean - meltadj_multimodel_mean_frac = meltadj_multimodel_mean / runoff_multimodel_mean - prec_multimodel_mean_frac = prec_multimodel_mean / runoff_multimodel_mean - melt_summer_mean_frac = (melt_summer_multimodel_mean - refreeze_multimodel_mean) / runoff_multimodel_mean - - - # ===== Plot ===== - # Precipitation - ax[row_idx, col_idx].plot(time_values, prec_multimodel_mean_frac, color=rcp_colordict[rcp], - linewidth=multimodel_linewidth, label=rcp) - if rcp == 'rcp45': - ax[row_idx, col_idx].fill_between(time_values, 0, prec_multimodel_mean_frac, - facecolor='b', alpha=0.2, label=None) - # Melt - melt_summer_mean_frac2plot = prec_multimodel_mean_frac + melt_summer_mean_frac - ax[row_idx, col_idx].plot(time_values, melt_summer_mean_frac2plot, color=rcp_colordict[rcp], - linewidth=multimodel_linewidth, label=rcp) - if rcp == 'rcp45': - ax[row_idx, col_idx].fill_between(time_values, prec_multimodel_mean_frac, melt_summer_mean_frac2plot, - facecolor='y', alpha=0.2, label=None) - - # Group labels - if add_group_label == 1: - ax[row_idx, col_idx].text(0.5, 0.99, title_dict[group], size=14, horizontalalignment='center', - verticalalignment='top', transform=ax[row_idx, col_idx].transAxes) - # Tick parameters - ax[row_idx, col_idx].tick_params(axis='both', which='major', labelsize=25, direction='inout') - ax[row_idx, col_idx].tick_params(axis='both', which='minor', labelsize=15, direction='inout') - # X-label - ax[row_idx, col_idx].set_xlim(time_values.min(), time_values.max()) - ax[row_idx, col_idx].xaxis.set_tick_params(labelsize=14) - ax[row_idx, col_idx].xaxis.set_major_locator(plt.MultipleLocator(50)) - ax[row_idx, col_idx].xaxis.set_minor_locator(plt.MultipleLocator(10)) - if col_idx == 0 and row_idx == num_rows-1: - ax[row_idx, col_idx].set_xticklabels(['','2000','2050','2100']) - elif row_idx == num_rows-1: - ax[row_idx, col_idx].set_xticklabels(['','','2050','2100']) - else: - ax[row_idx, col_idx].set_xticklabels(['','','','']) - # labels are the first one, 2000, 2050, 2100, and 2101 - # Y-label - ax[row_idx, col_idx].yaxis.set_tick_params(labelsize=14) - ax[row_idx, col_idx].set_ylim(0,1) - ax[row_idx, col_idx].yaxis.set_major_locator(plt.MultipleLocator(0.5)) - ax[row_idx, col_idx].yaxis.set_minor_locator(plt.MultipleLocator(0.1)) - ax[row_idx, col_idx].set_yticklabels(['','','0.5','1.0','1.5', '']) - - # Adjust subplot column index - col_idx += 1 - - # Only add group label once - add_group_label = 0 - - # RCP Legend - rcp_lines = [] - for rcp in rcps: - line = Line2D([0,1],[0,1], color=rcp_colordict[rcp], linewidth=multimodel_linewidth) - rcp_lines.append(line) - rcp_labels = [rcp_dict[rcp] for rcp in rcps] - ax[0,0].legend(rcp_lines, rcp_labels, loc='center left', bbox_to_anchor=(0, 0.7), fontsize=12, - labelspacing=0, handlelength=1, handletextpad=0.5, borderpad=0, frameon=False) - - # GCM Legend - gcm_lines = [] - for gcm_name in gcm_names: - line = Line2D([0,1],[0,1], linestyle='-', color=gcm_colordict[gcm_name]) - gcm_lines.append(line) - gcm_legend = gcm_names.copy() - fig.legend(gcm_lines, gcm_legend, loc='center right', title='GCMs', bbox_to_anchor=(1.06,0.5), - handlelength=0, handletextpad=0, borderpad=0, frameon=False) - - # Y-Label - fig.text(0.03, 0.5, 'Normalized Runoff Components [-]', va='center', rotation='vertical', size=16) - - # Save figure - fig.set_size_inches(7, num_rows*2) - figure_fn = grouping + '_runoffcomponents_' + str(len(gcm_names)) + 'gcms_' + str(len(rcps)) + 'rcps.png' - fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300) - - -#%% MAP OF VARIABLE OVERLAID BY DEGREES OR GLACIER DATA -if option_plot_cmip5_map == 1: - - for rcp in rcps: -# for rcp in ['rcp45']: - # Merge all data and partition into groups - groups, time_values, ds_vn, ds_glac = partition_multimodel_groups(gcm_names, grouping, vn, main_glac_rgi_all, - rcp=rcp) -#%% - # Create the projection - fig, ax = plt.subplots(1, 1, figsize=(10,5), subplot_kw={'projection':cartopy.crs.PlateCarree()}) - # Add country borders for reference - if grouping == 'rgi_region': - ax.add_feature(cartopy.feature.BORDERS, alpha=0.15) - ax.add_feature(cartopy.feature.COASTLINE) - # Set the extent - ax.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax.set_xticks(np.arange(east,west+1,xtick), cartopy.crs.PlateCarree()) - ax.set_yticks(np.arange(south,north+1,ytick), cartopy.crs.PlateCarree()) - ax.set_xlabel(xlabel, size=12) - ax.set_ylabel(ylabel, size=12) - - # Add group and attribute of interest - if grouping == 'rgi_region': - group_shp = cartopy.io.shapereader.Reader(rgiO1_shp_fn) - group_shp_attr = 'RGI_CODE' - elif grouping == 'watershed': - group_shp = cartopy.io.shapereader.Reader(watershed_shp_fn) - group_shp_attr = 'watershed' - elif grouping == 'kaab': - group_shp = cartopy.io.shapereader.Reader(kaab_shp_fn) - group_shp_attr = 'Name' - - colorbar_dict = {'volume_norm':[0,1], - 'peakwater':[2000,2100]} - cmap = mpl.cm.RdYlBu - norm = plt.Normalize(colorbar_dict[vn][0], colorbar_dict[vn][1]) - - # Add attribute of interest to the shapefile - for rec in group_shp.records(): - if rec.attributes[group_shp_attr] in groups: - # Group index - ds_idx = groups.index(rec.attributes[group_shp_attr]) - vn_multimodel_mean = vn_multimodel_mean_processed(vn, ds_vn, ds_idx, time_values) - - # Value to plot - if vn == 'volume_norm': - rec.attributes['value'] = vn_multimodel_mean[-1] - elif vn == 'peakwater': - rec.attributes['value'] = vn_multimodel_mean - - print(rec.attributes[group_shp_attr], rec.attributes['value']) - - - # Add polygon to plot - ax.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), - facecolor=cmap(norm(rec.attributes['value'])), - edgecolor='None', zorder=1) - # plot polygon outlines on top of everything with their labels - ax.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='grey', linewidth=0.75, zorder=3) - ax.text(title_location[rec.attributes[group_shp_attr]][0], - title_location[rec.attributes[group_shp_attr]][1], - title_dict[rec.attributes[group_shp_attr]], horizontalalignment='center', size=12, zorder=4) - if rec.attributes[group_shp_attr] == 'Karakoram': - ax.plot([72.2, 76.2], [34.3, 35.8], color='black', linewidth=0.75) - elif rec.attributes[group_shp_attr] == 'Pamir': - ax.plot([69.2, 73], [37.3, 38.3], color='black', linewidth=0.75) - - - # Add colorbar - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm._A = [] - plt.colorbar(sm, ax=ax, fraction=0.03, pad=0.02) - fig.text(0.95, 0.5, vn_dict[vn], va='center', rotation='vertical', size=14) - - if option_plot_individual_glaciers == 1: - # Plot individual glaciers - area_cutoffs = [100, 10, 1, 0.1] - area_cutoffs_size = [1000, 100, 10, 2] - area_sizes = size_thresholds(main_glac_rgi_all.Area.values, area_cutoffs, area_cutoffs_size) - # Multi-model mean of all glaciers - output_multimodel_mean_all_list = [] - for glac in range(len(main_glac_rgi_all)): - output_multimodel_mean = vn_multimodel_mean_processed(vn, ds_glac, glac, time_values, every_glacier=1) - output_multimodel_mean_all_list.append(output_multimodel_mean) - output_multimodel_mean_all = np.array(output_multimodel_mean_all_list) - - # Value to plot - if vn == 'volume_norm': - output_multimodel_mean_all_plot = output_multimodel_mean_all[:,-1] - elif vn == 'peakwater': - output_multimodel_mean_all_plot = output_multimodel_mean_all - - glac_lons = main_glac_rgi_all.CenLon.values - glac_lats = main_glac_rgi_all.CenLat.values - sc = ax.scatter(glac_lons, glac_lats, c=output_multimodel_mean_all_plot, cmap=cmap, norm=norm, - s=area_sizes, - edgecolor='grey', linewidth=0.25, transform=cartopy.crs.PlateCarree(), zorder=2) - - # Add legend for glacier sizes - legend_glac = [] - legend_glac_labels = [] - legend_glac_markersize = [20, 10, 5, 2] - for i_area, area_cutoff_size in enumerate(area_cutoffs_size): - legend_glac.append(Line2D([0], [0], linestyle='None', marker='o', color='grey', - label=(str(area_cutoffs[i_area]) + 'km$^2$'), - markerfacecolor='grey', markersize=legend_glac_markersize[i_area])) - plt.legend(handles=legend_glac, loc='lower left', fontsize=12) - - elif option_plot_degrees == 1: - # Group by degree - groups_deg, time_values, ds_vn_deg, ds_glac = ( - partition_multimodel_groups(gcm_names, 'degree', vn, main_glac_rgi_all, rcp=rcp)) - # Get values for each group - for group_idx in range(len(ds_vn_deg)): - vn_multimodel_mean_deg = vn_multimodel_mean_processed(vn, ds_vn_deg, group_idx, time_values) - # Value to plot - if vn == 'volume_norm': - ds_vn_deg[group_idx].append(vn_multimodel_mean_deg[-1]) - elif vn == 'peakwater': - ds_vn_deg[group_idx].append(vn_multimodel_mean_deg) - z = [ds_vn_deg[ds_idx][2] for ds_idx in range(len(ds_vn_deg))] - x = np.array([x[0] for x in deg_groups]) - y = np.array([x[1] for x in deg_groups]) - lons = np.arange(x.min(), x.max() + 2 * degree_size, degree_size) - lats = np.arange(y.min(), y.max() + 2 * degree_size, degree_size) - x_adj = np.arange(x.min(), x.max() + 1 * degree_size, degree_size) - x.min() - y_adj = np.arange(y.min(), y.max() + 1 * degree_size, degree_size) - y.min() - z_array = np.zeros((len(y_adj), len(x_adj))) - z_array[z_array==0] = np.nan - for i in range(len(z)): - row_idx = int((y[i] - y.min()) / degree_size) - col_idx = int((x[i] - x.min()) / degree_size) - z_array[row_idx, col_idx] = z[i] - ax.pcolormesh(lons, lats, z_array, cmap='RdYlBu', norm=norm, zorder=2) - -# elif option_plot_pies == 1: -# -# #%% -## pie_volumes = [] -# pie_years = [2040, 2070, 2100] -# pie_years_idx = [np.where(time_values == pie_year)[0][0] for pie_year in pie_years] -# pie_volumes = [vn_multimodel_mean[idx] for idx in pie_years_idx] -# pie_radii = [1.3,1,0.7] -# -# # Make data: I have 3 groups and 3 subgroups -## group_names=['2040', '2070', '2100'] -## group_size=[12,11,30] -# group_size = [1] -# subgroup_names=['A.1', 'A.2', 'A.3', 'B.1', 'B.2', 'C.1', 'C.2', 'C.3', 'C.4', 'C.5'] -# subgroup_size=[4,3,5,6,5,10,5,5,4,6] -# -# # Create colors -# a, b, c=[plt.cm.Blues, plt.cm.Reds, plt.cm.Greens] -# -# # First Ring (outside) -# fig, ax = plt.subplots() -# ax.axis('equal') -# for i, pie_year in enumerate(pie_years): -# i_volume = [pie_volumes[i], 1-pie_volumes[i]] -# mypie, _ = ax.pie(i_volume, radius=pie_radii[i], labels=[str(pie_year), ''], colors=['grey','None'], -# startangle=90, textprops={'fontsize': 14}) -# plt.setp( mypie, width=0.3, edgecolor='white') -# -# # show it -# plt.show() -# -# #%% - - - # Add time period and RCP - if 'volume' in vn: - additional_text = 'RCP ' + rcp_dict[rcp] + ': ' + str(time_values.max()-1) - else: - additional_text = 'RCP ' + rcp_dict[rcp] + ': ' + str(time_values.max()) - ax.text(0.98*west, 0.95*north, additional_text, horizontalalignment='right', fontsize=14) - - # Save figure - fig.set_size_inches(10,6) - if option_plot_individual_glaciers == 1: - figure_fn = grouping + '_wglac_' + vn + '_' + str(len(gcm_names)) + 'gcms_' + rcp + '.png' - elif option_plot_degrees == 1: - figure_fn = grouping + '_wdeg_' + vn + '_' + str(len(gcm_names)) + 'gcms_' + rcp + '.png' - else: - figure_fn = grouping + '_' + vn + '_' + str(len(gcm_names)) + 'gcms_' + rcp + '.png' - fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300) - - -#%% Output tables of mass change and peakwater -if option_output_tables == 1: - -# vns = ['mass_change', 'peakwater'] -# vns = ['peakwater'] - vns = ['mass_change'] - - -# groupings = ['all', 'rgi_region', 'watershed', 'kaab'] -# groupings = ['all'] -# groupings = ['rgi_region'] -# groupings = ['watershed'] - groupings = ['kaab'] - - # Create filepath if it does not exist - if os.path.exists(csv_fp) == False: - os.makedirs(csv_fp) - - for grouping in groupings: - - # Select groups - groups, group_cn = select_groups(grouping, main_glac_rgi_all) - - for vn in vns: - if vn == 'mass_change': - masschg_table_fn = ('MassChg_' + grouping + '_' + str(len(gcm_names)) + '_gcms_' + str(len(rcps)) + - '_rcps.csv') - table_cns = [] - for rcp in rcps: - table_cns.append(rcp + '_MassChg_Gt') - table_cns.append(rcp + '_MassChg_std_Gt') - table_cns.append(rcp + '_VolChg_%') - table_cns.append(rcp + '_VolChg_std_%') - output_table = pd.DataFrame(np.zeros((len(groups), len(table_cns))), index=groups, columns=table_cns) - - #%% - # Load volume_glac_annual - ds_vn_rcps = {} - for rcp in rcps: - groups, time_values, ds_vn, ds_glac = ( - partition_multimodel_groups(gcm_names, grouping, vn, main_glac_rgi_all, rcp=rcp)) - ds_vn_rcps[rcp] = ds_vn - #%% - - # Load area_glac_annual - ds_area_rcps = {} - area_vn = 'area_glac_annual' - for rcp in rcps: - groups, time_values, ds_area, ds_area_glac = ( - partition_multimodel_groups(gcm_names, grouping, area_vn, main_glac_rgi_all, rcp=rcp)) - ds_area_rcps[rcp] = ds_area - - for rcp in rcps: - for ngroup, group in enumerate(groups): - print(rcp, group) - ds_vn_multimodel = ds_vn_rcps[rcp][ngroup][1].mean(axis=0) - ds_vn_multimodel_std = ds_vn_rcps[rcp][ngroup][1].std(axis=0) - - ds_area_multimodel = ds_area_rcps[rcp][ngroup][1].mean(axis=0) - - # Mass change [Gt] - # Gt = km3 ice * density_ice / 1000 - # divide by 1000 because density of ice is 900 kg/m3 or 0.900 Gt/km3 - vn_reg_masschange = (ds_vn_multimodel - ds_vn_multimodel[0]) * input.density_ice / 1000 - vn_reg_masschange_std = ds_vn_multimodel_std * input.density_ice / 1000 - output_table.loc[group, rcp + '_MassChg_Gt'] = np.round(vn_reg_masschange[-1],1) - output_table.loc[group, rcp + '_MassChg_std_Gt'] = np.round(vn_reg_masschange_std[-1],1) - - # Volume change [%] - vn_reg_volchg = (ds_vn_multimodel - ds_vn_multimodel[0]) / ds_vn_multimodel[0] * 100 - vn_reg_volchg_std = ds_vn_multimodel_std / ds_vn_multimodel[0] * 100 - output_table.loc[group, rcp + '_VolChg_%'] = np.round(vn_reg_volchg[-1],1) - output_table.loc[group, rcp + '_VolChg_std_%'] = np.round(vn_reg_volchg_std[-1],1) - - - - - - # Mass change rate [Gt/yr] - runningmean_years = 10 - vn_reg_mass = ds_vn_multimodel * input.density_ice / 1000 - vn_reg_masschgrate = vn_reg_mass[1:] - vn_reg_mass[0:-1] - vn_reg_masschgrate_runningmean = uniform_filter(vn_reg_masschgrate, (runningmean_years)) -# print('Mass change rate [Gt/yr] 2015:', np.round(vn_reg_masschgrate_runningmean[idx_2015],1), -# '\nMass change rate [Gt/yr] 2100:', np.round(vn_reg_masschgrate_runningmean[-1],1)) - vn_reg_masschgrate_mwe = ( - vn_reg_masschgrate * 10**9 * 1000 / 1000 / 10**6 / ds_area_multimodel[0]) - vn_reg_masschgrate_mwe_runningmean = uniform_filter(vn_reg_masschgrate_mwe, runningmean_years) - - idx_2015 = np.where(time_values == 2015)[0][0] - if group in ['Karakoram', 'Kunlun']: - print('Vol change [%] 2015:', np.round(vn_reg_volchg[idx_2015],1), - '\nVol change [%] 2100:', np.round(vn_reg_volchg[-1],1)) - print('Mass balance [mwea] 2000-2015:', np.round(vn_reg_masschgrate_mwe[idx_2015],2), - '\nMass balance [mwea] 2000-2100:', np.round(vn_reg_masschgrate_mwe[-1],2)) - - # Export table - output_table.to_csv(csv_fp + masschg_table_fn) - - - if vn == 'peakwater': - peakwater_table_fn = ('PeakWater_' + grouping + '_' + str(len(gcm_names)) + '_gcms_' + str(len(rcps)) + - '_rcps.csv') - runoff_cns = [] - for rcp in rcps: - runoff_cns.append(rcp + '_PeakWater_Yr') - runoff_cns.append(rcp + '_PeakWater_std_Yr') - runoff_cns.append(rcp + '_PeakWaterChg_%') - runoff_cns.append(rcp + '_PeakWaterChg_std_%') - runoff_cns.append(rcp + '_RunoffChg_%') - runoff_cns.append(rcp + '_RunoffChg_std_%') - runoff_table = pd.DataFrame(np.zeros((len(groups), len(runoff_cns))), index=groups, columns=runoff_cns) - - ds_vn_rcps = {} - for rcp in rcps: - groups, time_values, ds_vn, ds_glac = ( - partition_multimodel_groups(gcm_names, grouping, vn, main_glac_rgi_all, rcp=rcp)) - ds_vn_rcps[rcp] = ds_vn - - for rcp in rcps: - for ngroup, group in enumerate(groups): - runoff = ds_vn_rcps[rcp][ngroup][1] - - # Compute peak water of each one - nyears = 10 - - peakwater_yr_gcms = np.zeros((runoff.shape[0])) - peakwater_chg_gcms = np.zeros((runoff.shape[0])) - runoff_chg_gcms = np.zeros((runoff.shape[0])) - for n in range(runoff.shape[0]): - peakwater_yr_gcms[n], peakwater_chg_gcms[n], runoff_chg_gcms[n] = ( - peakwater(runoff[n,:], time_values, nyears)) - - # Peakwater Year - runoff_table.loc[group, rcp + '_PeakWater_Yr'] = np.round(np.mean(peakwater_yr_gcms),1) - runoff_table.loc[group, rcp + '_PeakWater_std_Yr'] = np.round(np.std(peakwater_yr_gcms),1) - - # Peakwater Change [%] - runoff_table.loc[group, rcp + '_PeakWaterChg_%'] = np.round(np.mean(peakwater_chg_gcms),1) - runoff_table.loc[group, rcp + '_PeakWaterChg_std_%'] = np.round(np.std(peakwater_chg_gcms),1) - - # Runoff Change [%] end of simulation - runoff_table.loc[group, rcp + '_RunoffChg_%'] = np.round(np.mean(runoff_chg_gcms),1) - runoff_table.loc[group, rcp + '_RunoffChg_std_%'] = np.round(np.std(runoff_chg_gcms),1) - - # Export table - runoff_table.to_csv(csv_fp + peakwater_table_fn) - -#%% -if option_subset_GRACE == 1: - - vns = ['mass_change'] - grouping = 'mascon' - gcm_names = ['ERA-Interim'] - timestep = 'monthly' - - output_fn = '../mascon_' + timestep + '_GlacierMassGt_ERA-Interim.txt' - - - # Load volume, mass balance and area to extract monthly glacier mass [Gt] - groups, time_values_annual, ds_vol, ds_vol_glac = ( - partition_multimodel_groups(gcm_names, grouping, 'volume_glac_annual', main_glac_rgi_all)) - groups, time_values_monthly, ds_mb, ds_mb_glac = ( - partition_multimodel_groups(gcm_names, grouping, 'massbaltotal_glac_monthly', main_glac_rgi_all)) - groups, time_values_annual, ds_area, ds_area_glac = ( - partition_multimodel_groups(gcm_names, grouping, 'area_glac_annual', main_glac_rgi_all)) - - # Monthly glacier area - ds_area_glac_monthly = np.repeat(ds_area_glac[:,:,:-1], 12, axis=2) - # Monthly glacier mass change - # Area [km2] * mb [mwe] * (1 km / 1000 m) * density_water [kg/m3] * (1 Gt/km3 / 1000 kg/m3) - ds_masschange_glac_monthly = ds_area_glac_monthly * ds_mb_glac / 1000 * input.density_water / 1000 - # Monthly glacier mass - ds_mass_glac_initial = ds_vol_glac[:,:,0][:,:,np.newaxis] * input.density_ice / 1000 - ds_masschange_glac_monthly_cumsum = np.cumsum(ds_masschange_glac_monthly, axis=2) - ds_mass_glac_monthly = np.repeat(ds_mass_glac_initial, len(time_values_monthly), axis=2) - ds_mass_glac_monthly[:,:,1:] = ds_mass_glac_monthly[:,:,1:] + ds_masschange_glac_monthly_cumsum[:,:,:-1] - - # Check to see difference in deriving mass from mass balance or volume - # If you run 100 simulations, mass change is slightly different if it's computed using the MB and area or using - # the volume. This is not a problem when only run a single simulation nor is it a proble with the calculation - # of volume in the first year. This suggests that it has something to do with differences in the means and how - # outliers might propagate through. - ds_mass_glac_annual_fromMB = ds_mass_glac_monthly[:,:,::12] - ds_mass_glac_annual_fromVol = ds_vol_glac * input.density_ice / 1000 - - # Group monthly mass - ds_mass_mascon_monthly = [[] for group in groups] - ngcm = 0 - for ngroup, group in enumerate(groups): - # Select subset of data - main_glac_rgi = main_glac_rgi_all.loc[main_glac_rgi_all['mascon_idx'] == group] - mascon_mass_glac = ds_mass_glac_monthly[0,main_glac_rgi.index.values.tolist(),:] - # Regional sum - mascon_mass = mascon_mass_glac.sum(axis=0) - # Record data for multi-model stats - if ngcm == 0: - ds_mass_mascon_monthly[ngroup] = [group, mascon_mass] - else: - ds_mass_mascon_monthly[ngroup][1] = np.vstack((ds_mass_mascon_monthly[ngroup][1], mascon_mass)) - - # Convert monthly timestep to Year-Month - if timestep == 'monthly': - time_values_df = pd.DatetimeIndex(time_values_monthly) - time_values = [str(x.year) + '-' + str(x.month) for x in time_values_df] - elif timestep == 'annual': - time_values = time_values_annual[:-1] - - # Output column names - mascon_output_cns = ['mascon_idx', 'CenLat', 'CenLon'] - for x in time_values: - mascon_output_cns.append(x) - # Mascon index - mascon_output_array = np.reshape(np.array(groups),(-1,1)) - # Mascon center lat/lon - mascon_latlon = np.array([mascon_latlondict[x] for x in groups]) - mascon_output_array = np.hstack([mascon_output_array, mascon_latlon]) - # Mascon glacier mass [Gt] - mascon_values_list = [ds_mass_mascon_monthly[x][1] for x in range(len(groups))] - mascon_values_monthly = np.vstack(mascon_values_list) - if timestep == 'annual': - mascon_values = mascon_values_monthly[:,::12] - elif timestep == 'monthly': - mascon_values = mascon_values_monthly - mascon_output_array = np.hstack([mascon_output_array, mascon_values]) - - # Output dataframe - mascon_output_df = pd.DataFrame(mascon_output_array, columns=mascon_output_cns) - mascon_output_df.to_csv(mascon_fp + output_fn, sep=' ', index=False) - - if timestep == 'annual': - headerline=('Annual glacier mass [Gt] for each mascon where at least 1 HMA glacier exists\n' + - 'Glacier mass change modeled using the Python Glacier Evolution Model (PyGEM)\n' + - 'forced by ERA-Interim climate data\n' - 'Glaciers aggregated according to nearest center latitude and longitude\n' + - 'Years refer to water years (e.g., 2000 is October 1999 - September 2000)\n' + - 'Glacier mass refers to mass at the start of the year (e.g., mass_change_2000 = mass_2001 - ' - 'mass_2000\n' + - 'Mascons provided by Bryant Loomis (NASA GSFC mascons)\n' + - 'Contact: drounce@alaska.edu\n' + - 'Column 1: Mascon index used to aggregate glaciers\n' + - 'Column 2: Mascon latitude center [deg]\n' + - 'Column 3: Mascon longitude center [deg]\n' + - 'Columns 4+: Water year\n' + - 'END OF COMMENTS (first row is header of column names)\n') - elif timestep == 'monthly': - headerline=('Monthly glacier mass [Gt] for each mascon where at least 1 HMA glacier exists\n' + - 'Glacier mass change modeled using the Python Glacier Evolution Model (PyGEM)\n' + - 'forced by ERA-Interim climate data\n' - 'Glaciers aggregated according to nearest center latitude and longitude\n' + - 'Glacier mass refers to mass at the start of the month (e.g., mass_change_Sept = mass_Oct - ' - 'mass_Sept)\n' + - 'Mascons provided by Bryant Loomis (NASA GSFC mascons)\n' + - 'Contact: drounce@alaska.edu\n' + - 'Column 1: Mascon index used to aggregate glaciers\n' + - 'Column 2: Mascon latitude center [deg]\n' + - 'Column 3: Mascon longitude center [deg]\n' + - 'Columns 4+: Year-Month\n' + - 'END OF COMMENTS (first row is header of column names)\n') - - with open(mascon_fp + output_fn, 'r+') as f: - content=f.read() - f.seek(0,0) - f.write(headerline.rstrip('\r\n') + '\n' + content) - - - - -#%% -## COUNT HOW MANY BIAS ADJUSTMENTS HAVE RIDICULOUS VALUES -#biasadj_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/biasadj/' -#gcm_names = ['CanESM2', 'CCSM4', 'CNRM-CM5', 'CSIRO-Mk3-6-0', 'GFDL-CM3', 'GFDL-ESM2M', 'GISS-E2-R', 'IPSL-CM5A-LR', -# 'IPSL-CM5A-MR', 'MIROC5', 'MPI-ESM-LR', 'MRI-CGCM3', 'NorESM1-M'] -#maxvalue = 1000 -#for gcm in gcm_names: -# for rcp in rcps: -# for region in [13, 14, 15]: -# biasadj_fn = 'R' + str(region) + '_' + gcm + '_' + rcp + '_biasadj_opt2_2000_2017_wy1.csv' -# -# ds = pd.read_csv(biasadj_fp + biasadj_fn, index_col=0) -# cns = list(ds.columns.values) -# prec_cns = [] -# for cn in cns: -# if 'precadj' in cn: -# prec_cns.append(cn) -# ds_prec = ds[prec_cns] -# ds_prec_maxcol = ds_prec.max(axis=1) -# ds_prec_large = ds_prec_maxcol.loc[ds_prec_maxcol > maxvalue] -# -# if ds_prec_large.shape[0] > 0: -# print(gcm, rcp, region, ds_prec_large.shape[0]) - -#%% PLOT CALIBRATION MODEL PARAMETERS -if option_plot_modelparam == 1: - - vns = ['ddfsnow', 'tempchange', 'precfactor'] -# vns = ['precfactor'] - option_addbackground_group = 0 - modelparams_fn = 'modelparams_all_mean_20181018.csv' - - east = 104 - west = 67 - south = 25 - north = 48 - - labelsize = 13 - - colorbar_dict = {'volume_norm':[0,1], - 'peakwater':[2000,2100], - 'precfactor':[0.8,1.2], - 'tempchange':[-2,2], - 'ddfsnow':[3.6,4.6]} - - # Load mean of all model parameters - if os.path.isfile(cal_fp + modelparams_fn) == False: - modelparams_all = pd.DataFrame(np.zeros((main_glac_rgi_all.shape[0], len(input.modelparams_colnames))), - columns=input.modelparams_colnames) - for glac in range(main_glac_rgi_all.shape[0]): - - glac_rgiid_full = main_glac_rgi_all.loc[main_glac_rgi_all.index.values[glac],'RGIId'] - if glac%200 == 0: - print(glac_rgiid_full) - - glacno = str(glac_rgiid_full.split('-')[1]) - regionO1 = int(glacno.split('.')[0]) - - ds_mp = xr.open_dataset(cal_fp + 'reg' + str(regionO1) + '/' + glacno + '.nc') - cn_subset = input.modelparams_colnames - modelparams_all.iloc[glac,:] = (pd.DataFrame(ds_mp['mp_value'].sel(chain=0).values,columns=ds_mp.mp.values) - [input.modelparams_colnames].mean().values) - modelparams_all.to_csv(cal_fp + modelparams_fn, index=False) - ds_mp.close() - else: - modelparams_all = pd.read_csv(cal_fp + modelparams_fn) - - # Convert ddfsnow from [m w.e. to mm w.e.] - modelparams_all['ddfsnow'] = modelparams_all['ddfsnow'] * 1000 - modelparams_all['ddfice'] = modelparams_all['ddfice'] * 1000 - - # Add model parameters to main_glac_rgi_all - main_glac_rgi_all[input.modelparams_colnames] = modelparams_all - - for vn in vns: - - # Group data - groups, ds_group = partition_modelparams_groups(grouping, vn, main_glac_rgi_all) - - # Create the projection - fig, ax = plt.subplots(1, 1, figsize=(10,5), subplot_kw={'projection':cartopy.crs.PlateCarree()}) - # Add country borders for reference - ax.add_feature(cartopy.feature.BORDERS, alpha=0.15, zorder=10) - ax.add_feature(cartopy.feature.COASTLINE) - # Set the extent - ax.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax.set_xticks(np.arange(east,west+1,xtick), cartopy.crs.PlateCarree()) - ax.set_yticks(np.arange(south,north+1,ytick), cartopy.crs.PlateCarree()) - ax.set_xlabel(xlabel, size=labelsize) - ax.set_ylabel(ylabel, size=labelsize) - -# # Add background DEM -# gtif = gdal.Open(srtm_fn) -# arr = gtif.ReadAsArray() #Values -# trans = gtif.GetGeoTransform() #Defining bounds -# extent = (trans[0], trans[0] + gtif.RasterXSize*trans[1], -# trans[3] + gtif.RasterYSize*trans[5], trans[3]) -# norm_srtm = plt.Normalize(3000,6000) -# srtm = ax.imshow(arr[:,:],extent=extent,transform=cartopy.crs.PlateCarree(), norm=norm_srtm, origin='upper', -# cmap='Greys') -# -# plt.colorbar(srtm, ax=ax, fraction=0.03, pad=0.02) - -# # Add contour lines - srtm_contour_fn - srtm_contour_shp = cartopy.io.shapereader.Reader(srtm_contour_fn) - srtm_contour_feature = cartopy.feature.ShapelyFeature(srtm_contour_shp.geometries(), cartopy.crs.PlateCarree(), - edgecolor='black', facecolor='none', linewidth=0.15) - ax.add_feature(srtm_contour_feature, zorder=9) - - - - # Add group and attribute of interest - if grouping == 'rgi_region': - group_shp = cartopy.io.shapereader.Reader(rgiO1_shp_fn) - group_shp_attr = 'RGI_CODE' - elif grouping == 'watershed': - group_shp = cartopy.io.shapereader.Reader(watershed_shp_fn) - group_shp_attr = 'watershed' - elif grouping == 'kaab': - group_shp = cartopy.io.shapereader.Reader(kaab_shp_fn) - group_shp_attr = 'kaab_name' - - -# cmap = mpl.cm.RdYlBu - cmap = 'RdYlBu' - if vn == 'tempchange': - cmap = 'RdYlBu_r' -# cmap = mpl.cm.RdYlBu_r - norm = plt.Normalize(colorbar_dict[vn][0], colorbar_dict[vn][1]) - - # Add attribute of interest to the shapefile - if option_addbackground_group == 1: - for rec in group_shp.records(): - if rec.attributes[group_shp_attr] in groups: - # Group index - ds_idx = groups.index(rec.attributes[group_shp_attr]) - # Value to plot - rec.attributes['value'] = ds_group[ds_idx][1] - - # Add polygon to plot - ax.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), - facecolor=cmap(norm(rec.attributes['value'])), - edgecolor='None', zorder=1) - # plot polygon outlines on top of everything with their labels - ax.add_geometries(rec.geometry, cartopy.crs.PlateCarree(), facecolor='None', - edgecolor='grey', linewidth=0.75, zorder=3) - ax.text(title_location[rec.attributes[group_shp_attr]][0], - title_location[rec.attributes[group_shp_attr]][1], - title_dict[rec.attributes[group_shp_attr]], horizontalalignment='center', size=12, zorder=4) - if rec.attributes[group_shp_attr] == 'Karakoram': - ax.plot([72.2, 76.2], [34.3, 35.8], color='black', linewidth=0.75) - elif rec.attributes[group_shp_attr] == 'Pamir': - ax.plot([69.2, 73], [37.3, 38.3], color='black', linewidth=0.75) - - - # Add colorbar - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm._A = [] - plt.colorbar(sm, ax=ax, fraction=0.03, pad=0.01) - fig.text(0.98, 0.5, vn_dict[vn], va='center', rotation='vertical', size=labelsize) - - if option_plot_individual_glaciers == 1: - # Plot individual glaciers - area_cutoffs = [100, 10, 1, 0.1] - area_cutoffs_size = [1000, 100, 10, 2] - area_sizes = size_thresholds(main_glac_rgi_all.Area.values, area_cutoffs, area_cutoffs_size) - - modelparam_value = main_glac_rgi_all[vn].values - glac_lons = main_glac_rgi_all.CenLon.values - glac_lats = main_glac_rgi_all.CenLat.values - sc = ax.scatter(glac_lons, glac_lats, c=modelparam_value, cmap=cmap, norm=norm, s=area_sizes, - edgecolor='grey', linewidth=0.25, transform=cartopy.crs.PlateCarree(), zorder=2) - - # Add legend for glacier sizes - legend_glac = [] - legend_glac_labels = [] - legend_glac_markersize = [20, 10, 5, 2] - for i_area, area_cutoff_size in enumerate(area_cutoffs_size): - legend_glac.append(Line2D([0], [0], linestyle='None', marker='o', color='grey', - label=(str(area_cutoffs[i_area]) + 'km$^2$'), - markerfacecolor='grey', markersize=legend_glac_markersize[i_area])) - plt.legend(handles=legend_glac, loc='lower left', fontsize=12) - - elif option_plot_degrees == 1: - # Group by degree - groups_deg, ds_vn_deg = partition_modelparams_groups('degree', vn, main_glac_rgi_all) - - z = [ds_vn_deg[ds_idx][1] for ds_idx in range(len(ds_vn_deg))] - x = np.array([x[0] for x in deg_groups]) - y = np.array([x[1] for x in deg_groups]) - lons = np.arange(x.min(), x.max() + 2 * degree_size, degree_size) - lats = np.arange(y.min(), y.max() + 2 * degree_size, degree_size) - x_adj = np.arange(x.min(), x.max() + 1 * degree_size, degree_size) - x.min() - y_adj = np.arange(y.min(), y.max() + 1 * degree_size, degree_size) - y.min() - z_array = np.zeros((len(y_adj), len(x_adj))) - z_array[z_array==0] = np.nan - for i in range(len(z)): - row_idx = int((y[i] - y.min()) / degree_size) - col_idx = int((x[i] - x.min()) / degree_size) - z_array[row_idx, col_idx] = z[i] - if vn == 'tempchange': - ax.pcolormesh(lons, lats, z_array, cmap='RdYlBu_r', norm=norm, zorder=2, alpha=0.8) - else: - ax.pcolormesh(lons, lats, z_array, cmap='RdYlBu', norm=norm, zorder=2, alpha=0.8) - - - # Save figure - fig.set_size_inches(6,4) - if option_plot_individual_glaciers == 1: - fig_fn = 'mp_' + vn + '_wglac.png' - elif option_plot_degrees == 1: - if degree_size < 1: - degsize_name = 'pt' + str(int(degree_size * 100)) - else: - degsize_name = str(degree_size) - fig_fn = 'mp_' + vn + '_' + degsize_name + 'deg.png' - else: - fig_fn = 'mp_' + vn + '_' + grouping + '.png' - fig.savefig(figure_fp + '../cal/' + fig_fn, bbox_inches='tight', dpi=300) - -#%% ERA-INTERIM NORMALIZED CHANGE 2000-2018 -if option_plot_era_normalizedchange == 1: - - vns = ['volume_glac_annual'] - grouping = 'all' - glac_float = 13.26360 - labelsize = 13 - - for vn in vns: - groups, time_values, ds_group, ds_glac = partition_era_groups(grouping, vn, main_glac_rgi_all) - - if vn == 'volume_glac_annual': - group_idx = 0 - vn_norm = ds_group[group_idx][1] / ds_group[group_idx][1][0] - vn_norm_upper = (ds_group[group_idx][1] + ds_group[group_idx][2]) / ds_group[group_idx][1][0] - vn_norm_lower = (ds_group[group_idx][1] - ds_group[group_idx][2]) / ds_group[group_idx][1][0] - - glac_idx = np.where(main_glac_rgi_all['RGIId_float'].values == glac_float)[0][0] - vn_glac_norm = ds_glac[0][glac_idx,:] / ds_glac[0][glac_idx,0] - vn_glac_norm_upper = (ds_glac[0][glac_idx,:] + ds_glac[1][glac_idx,:]) / ds_glac[0][glac_idx,0] - vn_glac_norm_lower = (ds_glac[0][glac_idx,:] - ds_glac[1][glac_idx,:]) / ds_glac[0][glac_idx,0] - - fig, ax = plt.subplots(1, 1, squeeze=False, figsize=(10,8), gridspec_kw = {'wspace':0, 'hspace':0}) - # All glaciers - ax[0,0].plot(time_values, vn_norm, color='k', linewidth=1, label='HMA') - ax[0,0].fill_between(time_values, vn_norm_lower, vn_norm_upper, facecolor='k', alpha=0.15, label=r'$\pm$1 std') - - # Individual glacier - ax[0,0].plot(time_values, vn_glac_norm, color='b', linewidth=1, label=glac_float) - ax[0,0].fill_between(time_values, vn_glac_norm_lower, vn_glac_norm_upper, facecolor='b', alpha=0.15, label=None) - - # Tick parameters - ax[0,0].tick_params(axis='both', which='major', labelsize=labelsize, direction='inout') - ax[0,0].tick_params(axis='both', which='minor', labelsize=labelsize, direction='inout') - # X-label - ax[0,0].set_xlim(time_values.min(), time_values.max()) - ax[0,0].xaxis.set_tick_params(labelsize=labelsize) - ax[0,0].xaxis.set_major_locator(plt.MultipleLocator(5)) - ax[0,0].xaxis.set_minor_locator(plt.MultipleLocator(1)) - # Y-label - ax[0,0].set_ylabel('Normalized volume [-]', fontsize=labelsize+1) - ax[0,0].yaxis.set_tick_params(labelsize=labelsize) - ax[0,0].yaxis.set_major_locator(plt.MultipleLocator(0.1)) - ax[0,0].yaxis.set_minor_locator(plt.MultipleLocator(0.02)) - - # Legend - ax[0,0].legend(loc='lower left', fontsize=labelsize-2) - - # Save figure - fig.set_size_inches(5,3) - glac_float_str = str(glac_float).replace('.','-') - figure_fn = 'HMA_volchange_wglac' + glac_float_str + '.png' - - fig.savefig(cal_fp + '../' + figure_fn, bbox_inches='tight', dpi=300) - -#%% COMPARE GCM MASS BALANCE 2000-2018 TO CALIBRATION DATA -if option_compare_GCMwCal == 1: - - change_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/simulations/spc_vars_20180109_changeArea/' - constant_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/simulations/spc_vars_20180109_constantArea/' - change_fp_era = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/simulations/spc_vars_era_chgArea/' - constant_fp_era = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/simulations/spc_vars_era_conArea_100sims/' - - gcm_names = ['CanESM2', 'CCSM4', 'CNRM-CM5', 'CSIRO-Mk3-6-0', 'GFDL-CM3', 'GFDL-ESM2M', 'GISS-E2-R', - 'IPSL-CM5A-LR', 'NorESM1-M'] - rcps = ['rcp26'] - region = 13 - - netcdf_fp = netcdf_fp_cmip5 - - # Glacier hypsometry [km**2], total area - main_glac_hyps_raw = modelsetup.import_Husstable(main_glac_rgi_all, input.hyps_filepath, - input.hyps_filedict, input.hyps_colsdrop) - dates_table_nospinup = modelsetup.datesmodelrun(startyear=input.startyear, endyear=input.endyear, - spinupyears=0) - cal_data = pd.DataFrame() - for dataset in input.cal_datasets: - cal_subset = class_mbdata.MBData(name=dataset) - cal_subset_data = cal_subset.retrieve_mb(main_glac_rgi_all, main_glac_hyps_raw, dates_table_nospinup) - cal_data = cal_data.append(cal_subset_data, ignore_index=True) - cal_data = cal_data.sort_values(['glacno', 't1_idx']) - cal_data.reset_index(drop=True, inplace=True) -#%% - def retrieve_mb_mwea_all(netcdf_fp, gcm, rcp=None): - vn_area = 'area_glac_annual' - if gcm == 'ERA-Interim': - try: - ds_area_fn = 'R' + str(region) + '_' + gcm + '_c2_ba1_1sets_2000_2018--' + vn_area + '.nc' - ds_area = xr.open_dataset(netcdf_fp + vn_area + '/' + ds_area_fn) - except: - ds_area_fn = 'R' + str(region) + '_' + gcm + '_c2_ba1_100sets_2000_2018--' + vn_area + '.nc' - ds_area = xr.open_dataset(netcdf_fp + vn_area + '/' + ds_area_fn) - else: - ds_area_fn = 'R' + str(region) + '_' + gcm + '_' + rcp + '_c2_ba1_1sets_2000_2018--' + vn_area + '.nc' - ds_area = xr.open_dataset(netcdf_fp + vn_area + '/' + ds_area_fn) - - vn_mb = 'massbaltotal_glac_monthly' - if gcm == 'ERA-Interim': - try: - ds_mb_fn = 'R' + str(region) + '_' + gcm + '_c2_ba1_1sets_2000_2018--' + vn_mb + '.nc' - ds_mb = xr.open_dataset(netcdf_fp + vn_mb + '/' + ds_mb_fn) - except: - ds_mb_fn = 'R' + str(region) + '_' + gcm + '_c2_ba1_100sets_2000_2018--' + vn_mb + '.nc' - ds_mb = xr.open_dataset(netcdf_fp + vn_mb + '/' + ds_mb_fn) - else: - ds_mb_fn = 'R' + str(region) + '_' + gcm + '_' + rcp + '_c2_ba1_1sets_2000_2018--' + vn_mb + '.nc' - ds_mb = xr.open_dataset(netcdf_fp + vn_mb + '/' + ds_mb_fn) - - print(ds_mb_fn) - - # Convert to mass balance - mb_monthly_all = ds_mb[vn_mb].values[:,:,0] - area_all = ds_area[vn_area].values[:,:,0] -# time_values = ds_mb.year_plus1.values -# time_values_mb = time_values[:-1] - mb_annual_all = gcmbiasadj.annual_sum_2darray(mb_monthly_all) - mb_2000_2018_mwea_all = (mb_annual_all * area_all[:,:-1]).sum(axis=1) / area_all[:,0] / 18 - - # Close datasets - ds_area.close() - ds_mb.close() - - return mb_2000_2018_mwea_all - - #%% - gcm_names = ['CanESM2'] - for gcm in gcm_names: - for rcp in rcps: - - mb_2000_2018_mwea_all_constantArea = retrieve_mb_mwea_all(constant_fp, gcm, rcp) - mb_2000_2018_mwea_all_changeArea = retrieve_mb_mwea_all(change_fp, gcm, rcp) - - mb_2000_2018_mwea_all_cal = cal_data.mb_mwe.values / 18 - -# mb_compare = pd.DataFrame(np.stack((mb_2000_2018_mwea_all_cal, mb_2000_2018_mwea_all_constantArea, -# mb_2000_2018_mwea_all_changeArea), axis=1), -# columns=['cal_mb_mwea', 'constA_mb_mwea', 'chgA_mb_mwea']) -# mb_compare['Const-Chg'] = mb_compare.constA_mb_mwea - mb_compare.chgA_mb_mwea -# mb_compare['cal-const'] = mb_compare.cal_mb_mwea - mb_compare.constA_mb_mwea -# print(gcm, rcp, '\nCal-Const median:', np.round(np.nanmedian(mb_compare['cal-const']),2), -# '\nCal-Const mean:', np.round(np.nanmean(mb_compare['cal-const']),2), -# '\nCal-Const std:', np.round(np.nanstd(mb_compare['cal-const']),2), -# '\nCal-Const min:', np.round(np.nanmin(mb_compare['cal-const']),2), -# '\nCal-Const max:', np.round(np.nanmax(mb_compare['cal-const']),2), -# '\nDif due to Area Change (median, std):', np.round(np.nanmedian(mb_compare['Const-Chg']),2), -# np.round(np.nanstd(mb_compare['Const-Chg']),2)) - - for gcm in ['ERA-Interim']: - mb_2000_2018_mwea_all_constantArea_era = retrieve_mb_mwea_all(constant_fp_era, gcm) - mb_2000_2018_mwea_all_changeArea_era = retrieve_mb_mwea_all(change_fp_era, gcm) - - mb_compare = pd.DataFrame(np.stack((mb_2000_2018_mwea_all_cal, mb_2000_2018_mwea_all_constantArea_era, - mb_2000_2018_mwea_all_changeArea_era, mb_2000_2018_mwea_all_constantArea, - mb_2000_2018_mwea_all_changeArea), axis=1), - columns=['cal_mb_mwea', 'constA_mb_mwea_era', 'chgA_mb_mwea_era', 'constA_mb_mwea', - 'chgA_mb_mwea']) - - mb_compare['era-gcm'] = mb_compare['constA_mb_mwea_era'] - mb_compare['constA_mb_mwea'] -# mb_compare['cal-const'] = mb_compare.cal_mb_mwea_era - mb_compare.constA_mb_mwea_era - print(gcm, rcp, '\nERA - GCM median:', np.round(np.nanmedian(mb_compare['era-gcm']),2), - '\nera-gcm mean:', np.round(np.nanmean(mb_compare['era-gcm']),2), - '\nera-gcm std:', np.round(np.nanstd(mb_compare['era-gcm']),2), - '\nera-gcm min:', np.round(np.nanmin(mb_compare['era-gcm']),2), - '\nera-gcm max:', np.round(np.nanmax(mb_compare['era-gcm']),2)) - - -#%% -if option_plot_mcmc_errors == 1: - print('plot mcmc errors for all of HMA:\n1. Spatial distribution - do certain regions perform poorly' + - '\n2. How many chains are actually "good" and how many are bad?') - print(mcmc_fp) - - - # Load cal data - ds_cal = pd.read_csv(input.shean_fp + input.shean_fn) - # Glacier number and index for comparison - ds_cal['O1region'] = ds_cal['RGIId'].astype(int) - ds_cal['glacno'] = ((ds_cal['RGIId'] % 1) * 10**5).round(0).astype(int) - ds_cal['RGIId_full'] = ('RGI60-' + ds_cal['O1region'].map(str) + '.' + - (ds_cal['glacno'] / 10**5).apply(lambda x: '%.5f' % x).astype(str).str.split('.').str[1]) - - # Add calibration data to main_glac_rgi_all - rand_idx = np.random.randint(0,main_glac_rgi_all.shape[0]) - if (main_glac_rgi_all.shape[0] == ds_cal.shape[0] and - (ds_cal.loc[rand_idx,'RGIId_full'] == main_glac_rgi_all.loc[rand_idx, 'RGIId'])): - main_glac_rgi_all['mb_cal_mwea'] = ds_cal['mb_mwea'] - main_glac_rgi_all['mb_cal_sigma'] = ds_cal['mb_mwea_sigma'] - else: - main_glac_rgi_all['mb_cal_mwea'] = np.nan - for glac in range(main_glac_rgi_all.shape[0]): - cal_idx = np.where(ds_cal['RGIId_full'] == main_glac_rgi_all.loc[glac, 'RGIId'])[0][0] - main_glac_rgi_all.loc[glac,'mb_cal_mwea'] = ds_cal.loc[cal_idx,'mb_mwea'] - main_glac_rgi_all.loc[glac,'mb_cal_sigma'] = ds_cal.loc[cal_idx,'mb_mwea_sigma'] - - - #%% - # Load ERA-Interim modeled mass balance to data -# if (main_glac_rgi_all.shape[0] == ds_cal.shape[0] and -# (ds_cal.loc[rand_idx,'RGIId_full'] == main_glac_rgi_all.loc[rand_idx, 'RGIId'])): -# df_mean_all = pd.read_csv(shean_fp + 'mcmc_mean_all.csv', index_col=0) -# df_median_all = pd.read_csv(shean_fp + 'mcmc_median_all.csv', index_col=0) -# else: - - burn_no = 200 - thin_interval = 1 - print('\nBURN NUMBER:', burn_no,'\n') - #%% - # Load data for each glacier - mcmc_cns = ['RGIId', 'massbal', 'precfactor', 'tempchange', 'ddfsnow', 'ddfice', 'lrgcm', 'lrglac', 'precgrad', - 'tempsnow'] - df_cns = ['massbal', 'precfactor', 'tempchange', 'ddfsnow', 'ddfice', 'lrgcm', 'lrglac', 'precgrad', 'tempsnow'] - df_mean_all = pd.DataFrame(np.zeros((main_glac_rgi_all.shape[0], len(mcmc_cns))), columns=mcmc_cns) - df_median_all = pd.DataFrame(np.zeros((main_glac_rgi_all.shape[0], len(mcmc_cns))), columns=mcmc_cns) - df_std_all = pd.DataFrame(np.zeros((main_glac_rgi_all.shape[0], len(mcmc_cns))), columns=mcmc_cns) - df_min_all = pd.DataFrame(np.zeros((main_glac_rgi_all.shape[0], len(mcmc_cns))), columns=mcmc_cns) - df_max_all = pd.DataFrame(np.zeros((main_glac_rgi_all.shape[0], len(mcmc_cns))), columns=mcmc_cns) - for n, glac_str_wRGI in enumerate(main_glac_rgi_all['RGIId'].values): - if n%500 == 0: - print(n, glac_str_wRGI) - # Glacier string - glacier_str = glac_str_wRGI.split('-')[1] - ds = xr.open_dataset(mcmc_fp + glacier_str + '.nc') - df = pd.DataFrame(ds['mp_value'].values[burn_no::thin_interval,:,0], columns=ds.mp.values) - df = df[df_cns] - df_mean_all.loc[n,df_cns] = df.mean() - df_mean_all.loc[n,'RGIId'] = glac_str_wRGI - df_median_all.loc[n,:] = df.median() - df_median_all.loc[n,'RGIId'] = glac_str_wRGI - df_std_all.loc[n,:] = df.std() - df_std_all.loc[n,'RGIId'] = glac_str_wRGI - df_min_all.loc[n,:] = df.min() - df_min_all.loc[n,'RGIId'] = glac_str_wRGI - df_max_all.loc[n,:] = df.max() - df_max_all.loc[n,'RGIId'] = glac_str_wRGI - - ds.close() - - - #%% - # Maximum loss if entire glacier melted between 2000 and 2018 - mb_max_loss = (-1 * (main_glac_hyps_all * main_glac_icethickness_all * input.density_ice / - input.density_water).sum(axis=1).values / main_glac_hyps_all.sum(axis=1).values / (2018 - 2000)) - main_glac_rgi_all['mb_max_loss'] = mb_max_loss - -# # Truncated normal - updated means to remove portions of observations that are below max mass loss! -# main_glac_rgi_all['mb_cal_dist_mean'] = np.nan -# main_glac_rgi_all['mb_cal_dist_med'] = np.nan -# main_glac_rgi_all['mb_cal_dist_std'] = np.nan -# main_glac_rgi_all['mb_cal_dist_95low'] = np.nan -# main_glac_rgi_all['mb_cal_dist_95high'] = np.nan -# for glac in range(main_glac_rgi_all.shape[0]): -# cal_mu = main_glac_rgi_all.loc[glac, 'mb_cal_mwea'] -# cal_sigma = main_glac_rgi_all.loc[glac, 'mb_cal_sigma'] -# cal_lowbnd = main_glac_rgi_all.loc[glac, 'mb_max_loss'] -# cal_rvs = stats.truncnorm.rvs((cal_lowbnd - cal_mu) / cal_sigma, np.inf, loc=cal_mu, scale=cal_sigma, -# size=int(1e5)) -# main_glac_rgi_all.loc[glac,'mb_cal_dist_mean'] = np.mean(cal_rvs) -# main_glac_rgi_all.loc[glac,'mb_cal_dist_med'] = np.median(cal_rvs) -# main_glac_rgi_all.loc[glac,'mb_cal_dist_std'] = np.std(cal_rvs) -# main_glac_rgi_all.loc[glac,'mb_cal_dist_95low'] = np.percentile(cal_rvs, 2.5) -# main_glac_rgi_all.loc[glac,'mb_cal_dist_95high'] = np.percentile(cal_rvs, 97.5) - - # Add to main_glac_rgi - if (main_glac_rgi_all.shape[0] == df_mean_all.shape[0] and - (df_mean_all.loc[rand_idx,'RGIId'] == main_glac_rgi_all.loc[rand_idx, 'RGIId'])): - main_glac_rgi_all['mb_era_mean'] = df_mean_all['massbal'] - main_glac_rgi_all['mb_era_med'] = df_median_all['massbal'] - main_glac_rgi_all['mb_era_std'] = df_std_all['massbal'] - main_glac_rgi_all['mb_era_min'] = df_min_all['massbal'] - main_glac_rgi_all['mb_era_max'] = df_max_all['massbal'] - - -# main_glac_rgi_all['dif_mean_med'] = main_glac_rgi_all['mb_era_mean'] - main_glac_rgi_all['mb_era_med'] - main_glac_rgi_all['dif_cal_era_mean'] = main_glac_rgi_all['mb_cal_mwea'] - main_glac_rgi_all['mb_era_mean'] - main_glac_rgi_all['dif_cal_era_med'] = main_glac_rgi_all['mb_cal_mwea'] - main_glac_rgi_all['mb_era_med'] - - # remove nan values - main_glac_rgi_all = ( - main_glac_rgi_all.drop(np.where(np.isnan(main_glac_rgi_all['mb_era_mean'].values) == True)[0].tolist(), - axis=0)) - main_glac_rgi_all.reset_index(drop=True, inplace=True) - - - def plot_hist(df, cn, bins, xlabel=None, ylabel=None, fig_fn='hist.png', fig_fp=figure_fp): - """ - Plot histogram for any bin size - """ - data = df[cn].values - hist, bin_edges = np.histogram(data,bins) # make the histogram - fig,ax = plt.subplots() - # Plot the histogram heights against integers on the x axis - ax.bar(range(len(hist)),hist,width=1, edgecolor='k') - # Set the ticks to the middle of the bars - ax.set_xticks([0.5+i for i,j in enumerate(hist)]) - # Set the xticklabels to a string that tells us what the bin edges were - ax.set_xticklabels(['{} - {}'.format(bins[i],bins[i+1]) for i,j in enumerate(hist)], rotation=45, ha='right') - ax.set_xlabel(xlabel, fontsize=16) - ax.set_ylabel(ylabel, fontsize=16) - # Save figure - fig.set_size_inches(6,4) - fig.savefig(fig_fp + fig_fn, bbox_inches='tight', dpi=300) - - # Histogram: Mass balance [mwea], Observation - ERA - hist_cn = 'dif_cal_era_mean' - low_bin = np.floor(main_glac_rgi_all[hist_cn].min()) - high_bin = np.ceil(main_glac_rgi_all[hist_cn].max()) - bins = [low_bin, -0.2, -0.1, -0.05, -0.02, 0.02, 0.05, 0.1, 0.2, high_bin] - plot_hist(main_glac_rgi_all, hist_cn, bins, xlabel='Mass balance [mwea]\n(Calibration - MCMC_mean)', - ylabel='# Glaciers', fig_fn='MB_cal_vs_mcmc_hist.png', fig_fp=figure_fp + '../cal/') - - - # Histogram: Mass balance [mwea], MCMC mean - median - hist_cn = 'dif_cal_era_med' - low_bin = np.floor(main_glac_rgi_all[hist_cn].min()) - high_bin = np.ceil(main_glac_rgi_all[hist_cn].max() + 1) - bins = [low_bin, -0.2, -0.1, -0.05, -0.02, 0.02, 0.05, 0.1, 0.2, high_bin] - plot_hist(main_glac_rgi_all, hist_cn, bins, xlabel='MCMC Mass balance [mwea]\n(Calibration - MCMC_median)', - ylabel='# Glaciers', fig_fn='MB_mean_vs_med_mcmc_hist.png', fig_fp=figure_fp + '../cal/') - - # Histogram: Glacier Area [km2] - hist_cn = 'Area' - low_bin = np.floor(main_glac_rgi_all[hist_cn].min()) - high_bin = np.ceil(main_glac_rgi_all[hist_cn].max() + 1) - bins = [0, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 25, 50, 100, high_bin] - plot_hist(main_glac_rgi_all, hist_cn, bins, xlabel='Glacier Area [km2]', - ylabel='# Glaciers', fig_fn='Glacier_Area.png', fig_fp=figure_fp + '../cal/') - - # Map: Mass change, difference between calibration data and median data - # Area [km2] * mb [mwe] * (1 km / 1000 m) * density_water [kg/m3] * (1 Gt/km3 / 1000 kg/m3) - main_glac_rgi_all['mb_cal_Gta'] = main_glac_rgi_all['mb_cal_mwea'] * main_glac_rgi_all['Area'] / 1000 - main_glac_rgi_all['mb_cal_Gta_var'] = (main_glac_rgi_all['mb_cal_sigma'] * main_glac_rgi_all['Area'] / 1000)**2 - main_glac_rgi_all['mb_era_Gta'] = main_glac_rgi_all['mb_era_mean'] * main_glac_rgi_all['Area'] / 1000 - main_glac_rgi_all['mb_era_Gta_var'] = (main_glac_rgi_all['mb_era_std'] * main_glac_rgi_all['Area'] / 1000)**2 - main_glac_rgi_all['mb_era_Gta_med'] = main_glac_rgi_all['mb_era_med'] * main_glac_rgi_all['Area'] / 1000 - print('All MB cal (mean +/- 1 std) [gt/yr]:', np.round(main_glac_rgi_all['mb_cal_Gta'].sum(),3), - '+/-', np.round(main_glac_rgi_all['mb_cal_Gta_var'].sum()**0.5,3), - '\nAll MB ERA (mean +/- 1 std) [gt/yr]:', np.round(main_glac_rgi_all['mb_era_Gta'].sum(),3), - '+/-', np.round(main_glac_rgi_all['mb_era_Gta_var'].sum()**0.5,3), - '\nAll MB ERA (med) [gt/yr]:', np.round(main_glac_rgi_all['mb_era_Gta_med'].sum(),3)) - - def partition_sum_groups(grouping, vn, main_glac_rgi_all): - """Partition model parameters by each group - - Parameters - ---------- - grouping : str - name of grouping to use - vn : str - variable name - main_glac_rgi_all : pd.DataFrame - glacier table - - Output - ------ - groups : list - list of group names - ds_group : list of lists - dataset containing the multimodel data for a given variable for all the GCMs - """ - # Groups - groups, group_cn = select_groups(grouping, main_glac_rgi_all) - - ds_group = [[] for group in groups] - - # Cycle through groups - for ngroup, group in enumerate(groups): - # Select subset of data - main_glac_rgi = main_glac_rgi_all.loc[main_glac_rgi_all[group_cn] == group] - vn_glac = main_glac_rgi_all[vn].values[main_glac_rgi.index.values.tolist()] - # Regional sum - vn_reg = vn_glac.sum(axis=0) - - # Record data for each group - ds_group[ngroup] = [group, vn_reg] - - return groups, ds_group - - grouping='degree' - - groups, ds_group_cal = partition_sum_groups(grouping, 'mb_cal_Gta', main_glac_rgi_all) - groups, ds_group_era = partition_sum_groups(grouping, 'mb_era_Gta', main_glac_rgi_all) - groups, ds_group_area = partition_sum_groups(grouping, 'Area', main_glac_rgi_all) - -# ds_group_dif = [[] for x in ds_group_cal ] - - # Group difference [Gt/yr] - dif_cal_era_Gta = (np.array([x[1] for x in ds_group_cal]) - np.array([x[1] for x in ds_group_era])).tolist() - ds_group_dif_cal_era_Gta = [[x[0],dif_cal_era_Gta[n]] for n, x in enumerate(ds_group_cal)] - # Group difference [mwea] - area = [x[1] for x in ds_group_area] - ds_group_dif_cal_era_mwea = [[x[0], dif_cal_era_Gta[n] / area[n] * 1000] for n, x in enumerate(ds_group_cal)] - - fig_fn = 'MB_cal_vs_mcmc_map.png' - - east = 104 - west = 67 - south = 25 - north = 48 - - labelsize = 13 - - norm = plt.Normalize(-0.1, 0.1) - - # Create the projection - fig, ax = plt.subplots(1, 1, figsize=(10,5), subplot_kw={'projection':cartopy.crs.PlateCarree()}) - # Add country borders for reference - ax.add_feature(cartopy.feature.BORDERS, alpha=0.15, zorder=10) - ax.add_feature(cartopy.feature.COASTLINE) - # Set the extent - ax.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax.set_xticks(np.arange(east,west+1,xtick), cartopy.crs.PlateCarree()) - ax.set_yticks(np.arange(south,north+1,ytick), cartopy.crs.PlateCarree()) - ax.set_xlabel(xlabel, size=labelsize) - ax.set_ylabel(ylabel, size=labelsize) - - cmap = 'RdYlBu_r' - - # Add colorbar -# sm = plt.cm.ScalarMappable(cmap=cmap) - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm._A = [] - plt.colorbar(sm, ax=ax, fraction=0.03, pad=0.01) - fig.text(1, 0.5, 'Mass balance [mwea]\n(Observation - MCMC)', va='center', rotation='vertical', size=labelsize) - - # Group by degree - groups_deg = groups - ds_vn_deg = ds_group_dif_cal_era_mwea - - z = [ds_vn_deg[ds_idx][1] for ds_idx in range(len(ds_vn_deg))] - x = np.array([x[0] for x in deg_groups]) - y = np.array([x[1] for x in deg_groups]) - lons = np.arange(x.min(), x.max() + 2 * degree_size, degree_size) - lats = np.arange(y.min(), y.max() + 2 * degree_size, degree_size) - x_adj = np.arange(x.min(), x.max() + 1 * degree_size, degree_size) - x.min() - y_adj = np.arange(y.min(), y.max() + 1 * degree_size, degree_size) - y.min() - z_array = np.zeros((len(y_adj), len(x_adj))) - z_array[z_array==0] = np.nan - for i in range(len(z)): - row_idx = int((y[i] - y.min()) / degree_size) - col_idx = int((x[i] - x.min()) / degree_size) - z_array[row_idx, col_idx] = z[i] - ax.pcolormesh(lons, lats, z_array, cmap='RdYlBu_r', norm=norm, zorder=2, alpha=0.8) - - # Save figure - fig.set_size_inches(6,4) - fig.savefig(figure_fp + '../cal/' + fig_fn, bbox_inches='tight', dpi=300) - - main_glac_rgi_all.to_csv(input.output_filepath + 'main_glac_rgi_HMA_20190308_adjp12_100iters.csv') - - -#%% -if option_plot_maxloss_issues == 1: - -# # Load cal data -# shean_fp = input.main_directory + '/../DEMs/Shean_2018_1109/' -# shean_fn = 'hma_mb_20181108_0454_all_filled.csv' - #%% -# shean_fp = input.main_directory + '/../DEMs/Shean_2019_0213/' - #shean_fn = 'hma_mb_20190215_0815_std+mean.csv' -# shean_fn = 'hma_mb_20190215_0815_std+mean_all_filled.csv' - - ds_cal = pd.read_csv(input.shean_fp + input.shean_fn) - # Glacier number and index for comparison - ds_cal['O1region'] = ds_cal['RGIId'].astype(int) - ds_cal['glacno'] = ((ds_cal['RGIId'] % 1) * 10**5).round(0).astype(int) - ds_cal['RGIId_full'] = ('RGI60-' + ds_cal['O1region'].map(str) + '.' + - (ds_cal['glacno'] / 10**5).apply(lambda x: '%.5f' % x).astype(str).str.split('.').str[1]) - #%% - - # Add calibration data to main_glac_rgi_all - main_glac_rgi_all['mb_cal_mwea'] = np.nan - for glac in range(main_glac_rgi_all.shape[0]): -# for glac in [6718]: -# print(main_glac_rgi_all.loc[glac,'RGIId']) - cal_idx = np.where(ds_cal['RGIId_full'] == main_glac_rgi_all.loc[glac, 'RGIId'])[0][0] - main_glac_rgi_all.loc[glac,'mb_cal_mwea'] = ds_cal.loc[cal_idx,'mb_mwea'] - main_glac_rgi_all.loc[glac,'mb_cal_sigma'] = ds_cal.loc[cal_idx,'mb_mwea_sigma'] -# print(main_glac_rgi_all.loc[glac,'mb_cal_mwea']) - #%% - - - # Maximum loss if entire glacier melted between 2000 and 2018 - mb_max_loss = (-1 * (main_glac_hyps_all * main_glac_icethickness_all * input.density_ice / - input.density_water).sum(axis=1).values / main_glac_hyps_all.sum(axis=1).values / (2018 - 2000)) - main_glac_rgi_all['mb_max_loss'] = mb_max_loss - - # Z-score of where max loss falls on mb_cal - main_glac_rgi_all['max_loss_Z'] = ((main_glac_rgi_all['mb_max_loss'] - main_glac_rgi_all['mb_cal_mwea']) / - main_glac_rgi_all['mb_cal_sigma']) - - # Truncated normal - updated means to remove portions of observations that are below max mass loss! - main_glac_rgi_all['mb_cal_dist_mean'] = np.nan - main_glac_rgi_all['mb_cal_dist_med'] = np.nan - main_glac_rgi_all['mb_cal_dist_std'] = np.nan - for glac in range(main_glac_rgi_all.shape[0]): - cal_mu = main_glac_rgi_all.loc[glac, 'mb_cal_mwea'] - cal_sigma = main_glac_rgi_all.loc[glac, 'mb_cal_sigma'] - cal_lowbnd = main_glac_rgi_all.loc[glac, 'mb_max_loss'] - cal_rvs = stats.truncnorm.rvs((cal_lowbnd - cal_mu) / cal_sigma, np.inf, loc=cal_mu, scale=cal_sigma, - size=int(1e5)) - main_glac_rgi_all.loc[glac,'mb_cal_dist_mean'] = np.mean(cal_rvs) - main_glac_rgi_all.loc[glac,'mb_cal_dist_med'] = np.median(cal_rvs) - main_glac_rgi_all.loc[glac,'mb_cal_dist_std'] = np.std(cal_rvs) - - # remove nan values - main_glac_rgi_all = ( - main_glac_rgi_all.drop(np.where(np.isnan(main_glac_rgi_all['max_loss_Z'].values) == True)[0].tolist(), - axis=0)) - main_glac_rgi_all.reset_index(drop=True, inplace=True) - - #%% - - def plot_hist(df, cn, bins, xlabel=None, ylabel=None, fig_fn='hist.png', fig_fp=figure_fp): - """ - Plot histogram for any bin size - """ - data = df[cn].values - hist, bin_edges = np.histogram(data,bins) # make the histogram - fig,ax = plt.subplots() - # Plot the histogram heights against integers on the x axis - ax.bar(range(len(hist)),hist,width=1, edgecolor='k') - # Set the ticks to the middle of the bars - ax.set_xticks([0.5+i for i,j in enumerate(hist)]) - # Set the xticklabels to a string that tells us what the bin edges were - ax.set_xticklabels(['{} - {}'.format(bins[i],bins[i+1]) for i,j in enumerate(hist)], rotation=45, ha='right') - ax.set_xlabel(xlabel, fontsize=16) - ax.set_ylabel(ylabel, fontsize=16) - ax.set_ylim(0,10000) - # Save figure - fig.set_size_inches(6,4) - fig.savefig(fig_fp + fig_fn, bbox_inches='tight', dpi=300) - - # Histogram: Mass balance [mwea], Observation - ERA - hist_cn = 'max_loss_Z' - low_bin = np.floor(main_glac_rgi_all[hist_cn].min()) - high_bin = np.ceil(main_glac_rgi_all[hist_cn].max()) - bins = [low_bin, -2, -1.5, -1, -0.5, 0, 0.5, 1, 2, high_bin] - plot_hist(main_glac_rgi_all, hist_cn, bins, xlabel='Max Loss Z-score \n[(Max_Loss - Obs_MB) / Obs_sigma]', - ylabel='# Glaciers', fig_fn='maxloss_zscore_hist.png', fig_fp=figure_fp + '../cal/') - - - -#%% - # Map: Mass change, difference between calibration data and median data - def partition_sum_groups(grouping, vn, main_glac_rgi_all): - """Partition model parameters by each group - - Parameters - ---------- - grouping : str - name of grouping to use - vn : str - variable name - main_glac_rgi_all : pd.DataFrame - glacier table - - Output - ------ - groups : list - list of group names - ds_group : list of lists - dataset containing the multimodel data for a given variable for all the GCMs - """ - # Groups - groups, group_cn = select_groups(grouping, main_glac_rgi_all) - - ds_group = [[] for group in groups] - - # Cycle through groups - for ngroup, group in enumerate(groups): - # Select subset of data - main_glac_rgi = main_glac_rgi_all.loc[main_glac_rgi_all[group_cn] == group] - vn_glac = main_glac_rgi_all[vn].values[main_glac_rgi.index.values.tolist()] - # Regional sum - vn_reg = vn_glac.sum(axis=0) - - # Record data for each group - ds_group[ngroup] = [group, vn_reg] - - return groups, ds_group - - grouping='degree' - - main_glac_rgi_all['count'] = 1 - main_glac_rgi_all['count_gtNeg2'] = 0 - main_glac_rgi_all['count_gtNeg1'] = 0 - main_glac_rgi_all['count_gt0'] = 0 - main_glac_rgi_all.loc[main_glac_rgi_all['max_loss_Z'] > -2, 'count_gtNeg2'] = 1 - main_glac_rgi_all.loc[main_glac_rgi_all['max_loss_Z'] > -1, 'count_gtNeg1'] = 1 - main_glac_rgi_all.loc[main_glac_rgi_all['max_loss_Z'] > 0, 'count_gt0'] = 1 - groups, ds_group_zscore = partition_sum_groups(grouping, 'count_gt0', main_glac_rgi_all) - groups, ds_group_count = partition_sum_groups(grouping, 'count', main_glac_rgi_all) - - ds_group_zscore_perc = [[x[0], ds_group_zscore[n][1] / ds_group_count[n][1] * 100] - for n, x in enumerate(ds_group_zscore)] - - fig_fn = 'max_loss_zscore_map.png' - - east = 104 - west = 67 - south = 25 - north = 48 - - labelsize = 13 - - norm = plt.Normalize(0, 10) -# norm = plt.Normalize(0, 100) - - # Create the projection - fig, ax = plt.subplots(1, 1, figsize=(10,5), subplot_kw={'projection':cartopy.crs.PlateCarree()}) - # Add country borders for reference - ax.add_feature(cartopy.feature.BORDERS, alpha=0.15, zorder=10) - ax.add_feature(cartopy.feature.COASTLINE) - # Set the extent - ax.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - ax.set_xticks(np.arange(east,west+1,xtick), cartopy.crs.PlateCarree()) - ax.set_yticks(np.arange(south,north+1,ytick), cartopy.crs.PlateCarree()) - ax.set_xlabel(xlabel, size=labelsize) - ax.set_ylabel(ylabel, size=labelsize) - - cmap = 'RdYlBu_r' - - # Add colorbar -# sm = plt.cm.ScalarMappable(cmap=cmap) - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm._A = [] - plt.colorbar(sm, ax=ax, fraction=0.03, pad=0.01) - fig.text(1, 0.5, 'Count', va='center', rotation='vertical', size=labelsize) - - # Group by degree - groups_deg = groups - ds_vn_deg = ds_group_zscore -# ds_vn_deg = ds_group_zscore_perc - - z = [ds_vn_deg[ds_idx][1] for ds_idx in range(len(ds_vn_deg))] - x = np.array([x[0] for x in deg_groups]) - y = np.array([x[1] for x in deg_groups]) - lons = np.arange(x.min(), x.max() + 2 * degree_size, degree_size) - lats = np.arange(y.min(), y.max() + 2 * degree_size, degree_size) - x_adj = np.arange(x.min(), x.max() + 1 * degree_size, degree_size) - x.min() - y_adj = np.arange(y.min(), y.max() + 1 * degree_size, degree_size) - y.min() - z_array = np.zeros((len(y_adj), len(x_adj))) - z_array[z_array==0] = np.nan - for i in range(len(z)): - row_idx = int((y[i] - y.min()) / degree_size) - col_idx = int((x[i] - x.min()) / degree_size) - z_array[row_idx, col_idx] = z[i] - ax.pcolormesh(lons, lats, z_array, cmap='RdYlBu_r', norm=norm, zorder=2, alpha=0.8) - - # Save figure - fig.set_size_inches(6,4) - fig.savefig(figure_fp + '../cal/' + fig_fn, bbox_inches='tight', dpi=300) - -#%% -#main_glac_rgi_all['cal_norm'] = (main_glac_rgi_all.mb_cal_mwea - main_glac_rgi_all.mb_max_loss) / main_glac_rgi_all.mb_cal_sigma -#A = main_glac_rgi_all.copy() -#A.plot.scatter('Area', 'dif_cal_era_mean') - -#%% - -# Compute mass change from 2000 - 2018 - -## variable name -#vn = 'volume_glac_annual' -#rgi_regions = [13, 14, 15] -# -#for region in rgi_regions: -# # Load datasets -# ds_fn = 'R' + str(region) + '_ERA-Interim_c2_ba1_100sets_1980_2017.nc' -# ds = xr.open_dataset(netcdf_fp_era + ds_fn) -# # Extract time variable -# if 'annual' in vn: -# try: -# time_values = ds[vn].coords['year_plus1'].values -# except: -# time_values = ds[vn].coords['year'].values -# elif 'monthly' in vn: -# time_values = ds[vn].coords['time'].values -# -# # Merge datasets -# if region == rgi_regions[0]: -# vn_glac_all = ds[vn].values[:,:,0] -# vn_glac_std_all = ds[vn].values[:,:,1] -# else: -# vn_glac_all = np.concatenate((vn_glac_all, ds[vn].values[:,:,0]), axis=0) -# vn_glac_std_all = np.concatenate((vn_glac_std_all, ds[vn].values[:,:,1]), axis=0) -# -# # Close dataset -# ds.close() -# -## Mass change for text on plot -## Gt = km3 ice * density_ice / 1000 -## divide by 1000 because density of ice is 900 kg/m3 or 0.900 Gt/km3 -#vn_reg_masschange = (vn_reg[-1] - vn_reg[0]) * input.density_ice / 1000 -# -#A = (vn_glac_all[:,20].sum() - vn_glac_all[:,-1].sum()) * input.density_ice / 1000 / 18 diff --git a/pygemfxns_postprocessing.py b/pygemfxns_postprocessing.py deleted file mode 100644 index d5592798..00000000 --- a/pygemfxns_postprocessing.py +++ /dev/null @@ -1,1076 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Mon Oct 16 09:04:46 2017 - -@author: David Rounce - -pygemfxns_output_postprocessing.py is a mix of post-processing for things like plots, relationships between variables, -and any other comparisons between output or input data. -""" - -# Built-in Libraries -import os -import collections -# External Libraries -import numpy as np -import pandas as pd -import netCDF4 as nc -import matplotlib.pyplot as plt -from matplotlib.lines import Line2D -import scipy -import cartopy -import xarray as xr -# Local Libraries -import pygem_input as input -import pygemfxns_modelsetup as modelsetup -import pygemfxns_massbalance as massbalance -import class_mbdata -import run_simulation - -# Script options -option_plot_futuresim = 0 -option_mb_shean_analysis = 0 -option_mb_shean_regional = 0 -option_geodeticMB_loadcompare = 0 -option_check_biasadj = 0 -option_parameter_relationships = 0 -option_MCMC_ensembles = 0 -option_calcompare_w_geomb = 0 -option_add_metadata2netcdf = 0 -option_var_mon2annual = 0 - - -#%% SUBSET RESULTS INTO EACH VARIABLE NAME SO EASIER TO TRANSFER -if option_var_mon2annual == 1: - netcdf_fp_prefix = input.output_filepath + 'simulations/spc/20181108_vars/' - vns = ['acc_glac_monthly', 'melt_glac_monthly', 'refreeze_glac_monthly', 'frontalablation_glac_monthly', - 'massbaltotal_glac_monthly', 'temp_glac_monthly', 'prec_glac_monthly', 'runoff_glac_monthly'] -# vns = ['runoff_glac_monthly'] - - def coords_attrs_dict(ds, vn): - """ - Retrieve dictionaries containing coordinates, attributes, and encoding for the dataset and variable name - - Parameters - ---------- - ds : xr.Dataset - dataset of a variable of interest - vn : str - variable name - - Returns - ------- - output_coords_dict : dictionary - coordiantes for the modified variable - output_attrs_dict: dictionary - attributes to add to the modified variable - encoding : dictionary - encoding used with exporting xarray dataset to netcdf - """ - # Variable coordinates dictionary - output_coords_dict = { - 'temp_glac_annual': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'prec_glac_annual': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'runoff_glac_annual': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'acc_glac_annual': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'acc_glac_summer': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'acc_glac_winter': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'melt_glac_annual': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'melt_glac_summer': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'melt_glac_winter': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'refreeze_glac_annual': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'refreeze_glac_summer': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'refreeze_glac_winter': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'frontalablation_glac_annual': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'frontalablation_glac_summer': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'frontalablation_glac_winter': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'massbaltotal_glac_annual': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'massbaltotal_glac_summer': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]), - 'massbaltotal_glac_winter': collections.OrderedDict( - [('glac', ds.glac.values), ('year', ds.year.values), ('stats', ds.stats.values)]) - } - # Attributes dictionary - output_attrs_dict = { - 'temp_glac_annual': { - 'long_name': 'glacier-wide mean air temperature', - 'units': 'degC', - 'temporal_resolution': 'annual', - 'comment': ( - 'annual mean has each month weight equally, each elevation bin is weighted equally' - ' to compute the mean temperature, and bins where the glacier no longer exists due to ' - 'retreat have been removed')}, - 'prec_glac_annual': { - 'long_name': 'glacier-wide precipitation (liquid)', - 'units': 'm', - 'temporal_resolution': 'annual', - 'comment': 'only the liquid precipitation, solid precipitation excluded'}, - 'acc_glac_annual': { - 'long_name': 'glacier-wide accumulation', - 'units': 'm w.e.', - 'temporal_resolution': 'annual', - 'comment': 'only the solid precipitation'}, - 'acc_glac_summer': { - 'long_name': 'glacier-wide accumulation', - 'units': 'm w.e.', - 'temporal_resolution': 'annual summer', - 'comment': 'only the solid precipitation'}, - 'acc_glac_winter': { - 'long_name': 'glacier-wide accumulation', - 'units': 'm w.e.', - 'temporal_resolution': 'annual winter', - 'comment': 'only the solid precipitation'}, - 'melt_glac_annual': { - 'long_name': 'glacier-wide melt', - 'units': 'm w.e.', - 'temporal_resolution': 'annual'}, - 'melt_glac_summer': { - 'long_name': 'glacier-wide melt', - 'units': 'm w.e.', - 'temporal_resolution': 'annual summer'}, - 'melt_glac_winter': { - 'long_name': 'glacier-wide melt', - 'units': 'm w.e.', - 'temporal_resolution': 'annual winter'}, - 'refreeze_glac_annual': { - 'long_name': 'glacier-wide refreeze', - 'units': 'm w.e.', - 'temporal_resolution': 'annual'}, - 'refreeze_glac_summer': { - 'long_name': 'glacier-wide refreeze', - 'units': 'm w.e.', - 'temporal_resolution': 'annual summer'}, - 'refreeze_glac_winter': { - 'long_name': 'glacier-wide refreeze', - 'units': 'm w.e.', - 'temporal_resolution': 'annual winter'}, - 'frontalablation_glac_annual': { - 'long_name': 'glacier-wide frontal ablation', - 'units': 'm w.e.', - 'temporal_resolution': 'annual', - 'comment': ( - 'mass losses from calving, subaerial frontal melting, sublimation above the ' - 'waterline and subaqueous frontal melting below the waterline')}, - 'frontalablation_glac_summer': { - 'long_name': 'glacier-wide frontal ablation', - 'units': 'm w.e.', - 'temporal_resolution': 'annual summer', - 'comment': ( - 'mass losses from calving, subaerial frontal melting, sublimation above the ' - 'waterline and subaqueous frontal melting below the waterline')}, - 'frontalablation_glac_winter': { - 'long_name': 'glacier-wide frontal ablation', - 'units': 'm w.e.', - 'temporal_resolution': 'annual winter', - 'comment': ( - 'mass losses from calving, subaerial frontal melting, sublimation above the ' - 'waterline and subaqueous frontal melting below the waterline')}, - 'massbaltotal_glac_annual': { - 'long_name': 'glacier-wide total mass balance', - 'units': 'm w.e.', - 'temporal_resolution': 'annual', - 'comment': 'total mass balance is the sum of the climatic mass balance and frontal ablation'}, - 'massbaltotal_glac_summer': { - 'long_name': 'glacier-wide total mass balance', - 'units': 'm w.e.', - 'temporal_resolution': 'annual summer', - 'comment': 'total mass balance is the sum of the climatic mass balance and frontal ablation'}, - 'massbaltotal_glac_winter': { - 'long_name': 'glacier-wide total mass balance', - 'units': 'm w.e.', - 'temporal_resolution': 'annual winter', - 'comment': 'total mass balance is the sum of the climatic mass balance and frontal ablation'}, - 'runoff_glac_annual': { - 'long_name': 'glacier-wide runoff', - 'units': 'm**3', - 'temporal_resolution': 'annual', - 'comment': 'runoff from the glacier terminus, which moves over time'}, - } - - encoding = {} - noencoding_vn = ['stats', 'glac_attrs'] - # Encoding (specify _FillValue, offsets, etc.) - if vn not in noencoding_vn: - encoding[vn] = {'_FillValue': False} - return output_coords_dict, output_attrs_dict, encoding - - for vn in vns: - netcdf_fp = netcdf_fp_prefix + vn + '/' - for i in os.listdir(netcdf_fp): - if i.endswith('.nc'): - print(i) - - # Open dataset and extract annual values - ds = xr.open_dataset(netcdf_fp + i) - ds_mean = ds[vn].values[:,:,0] - ds_std = ds[vn].values[:,:,1] - ds_var = ds_std**2 - - # Compute annual/seasonal mean/sum and standard deviation for the variable of interest - if vn is 'temp_glac_monthly': - output_list = ['annual'] - vn_annual = 'temp_glac_annual' - # Mean annual temperature, standard deviation, and variance - ds_mean_annual = ds_mean.reshape(-1,12).mean(axis=1).reshape(-1,int(ds_mean.shape[1]/12)) - ds_var_annual = ds_var.reshape(-1,12).mean(axis=1).reshape(-1,int(ds_std.shape[1]/12)) - ds_std_annual = ds_var_annual**0.5 - ds_values_annual = np.concatenate((ds_mean_annual[:,:,np.newaxis], ds_std_annual[:,:,np.newaxis]), - axis=2) - elif vn in ['prec_glac_monthly', 'runoff_glac_monthly']: - output_list = ['annual'] - vn_annual = 'prec_glac_annual' - # Total annual precipitation, standard deviation, and variance - ds_sum_annual = ds_mean.reshape(-1,12).sum(axis=1).reshape(-1,int(ds_mean.shape[1]/12)) - ds_var_annual = ds_var.reshape(-1,12).sum(axis=1).reshape(-1,int(ds_std.shape[1]/12)) - ds_std_annual = ds_var_annual**0.5 - ds_values_annual = np.concatenate((ds_sum_annual[:,:,np.newaxis], ds_std_annual[:,:,np.newaxis]), - axis=2) - elif vn in ['acc_glac_monthly', 'melt_glac_monthly', 'refreeze_glac_monthly', - 'frontalablation_glac_monthly', 'massbaltotal_glac_monthly']: - output_list = ['annual', 'summer', 'winter'] - # Annual total, standard deviation, and variance - ds_sum_annual = ds_mean.reshape(-1,12).sum(axis=1).reshape(-1,int(ds_mean.shape[1]/12)) - ds_var_annual = ds_var.reshape(-1,12).sum(axis=1).reshape(-1,int(ds_std.shape[1]/12)) - ds_std_annual = ds_var_annual**0.5 - ds_values_annual = np.concatenate((ds_sum_annual[:,:,np.newaxis], ds_std_annual[:,:,np.newaxis]), - axis=2) - # Seasonal total, standard deviation, and variance - if ds.time.year_type == 'water year': - option_wateryear = 1 - elif ds.time.year_type == 'calendar year': - option_wateryear = 2 - else: - option_wateryear = 3 - dates_table = modelsetup.datesmodelrun(startyear=ds.year.values[0], endyear=ds.year.values[-1], - spinupyears=0, option_wateryear=option_wateryear) - # For seasonal calculations copy monthly values and remove the other season's values - ds_mean_summer = ds_mean.copy() - ds_var_summer = ds_var.copy() - ds_mean_summer[:,dates_table.season.values == 'winter'] = 0 - ds_sum_summer = ds_mean_summer.reshape(-1,12).sum(axis=1).reshape(-1, int(ds_mean.shape[1]/12)) - ds_var_summer = ds_var_summer.reshape(-1,12).sum(axis=1).reshape(-1,int(ds_std.shape[1]/12)) - ds_std_summer = ds_var_summer**0.5 - ds_values_summer = np.concatenate((ds_sum_summer[:,:,np.newaxis], ds_std_summer[:,:,np.newaxis]), - axis=2) - ds_mean_winter = ds_mean.copy() - ds_var_winter = ds_var.copy() - ds_mean_winter[:,dates_table.season.values == 'summer'] = 0 - ds_sum_winter = ds_mean_winter.reshape(-1,12).sum(axis=1).reshape(-1, int(ds_mean.shape[1]/12)) - ds_var_winter = ds_var_winter.reshape(-1,12).sum(axis=1).reshape(-1,int(ds_std.shape[1]/12)) - ds_std_winter = ds_var_winter**0.5 - ds_values_winter = np.concatenate((ds_sum_winter[:,:,np.newaxis], ds_std_winter[:,:,np.newaxis]), - axis=2) - # Create modified dataset - for temporal_res in output_list: - vn_new = vn.split('_')[0] + '_glac_' + temporal_res - output_fp = netcdf_fp_prefix + vn_new + '/' - output_fn = i.split('.nc')[0][:-7] + temporal_res + '.nc' - output_coords_dict, output_attrs_dict, encoding = coords_attrs_dict(ds, vn_new) - if temporal_res is 'annual': - ds_new = xr.Dataset({vn_new: (list(output_coords_dict[vn_new].keys()), ds_values_annual)}, - coords=output_coords_dict[vn_new]) - elif temporal_res is 'summer': - ds_new = xr.Dataset({vn_new: (list(output_coords_dict[vn_new].keys()), ds_values_summer)}, - coords=output_coords_dict[vn_new]) - elif temporal_res is 'winter': - ds_new = xr.Dataset({vn_new: (list(output_coords_dict[vn_new].keys()), ds_values_winter)}, - coords=output_coords_dict[vn_new]) - ds_new[vn_new].attrs = output_attrs_dict[vn_new] - # Merge new dataset into the old to retain glacier table and other attributes - output_ds = xr.merge((ds, ds_new)) - output_ds = output_ds.drop(vn) - # Export netcdf - if not os.path.exists(output_fp): - os.makedirs(output_fp) - output_ds.to_netcdf(output_fp + output_fn, encoding=encoding) - - # Remove file - os.remove(netcdf_fp + i) - - - -#%%===== PLOT FUNCTIONS ============================================================================================= -def plot_latlonvar(lons, lats, variable, rangelow, rangehigh, title, xlabel, ylabel, colormap, east, west, south, north, - xtick=1, - ytick=1, - marker_size=2, - option_savefig=0, - fig_fn='Samplefig_fn.png', - output_filepath = input.main_directory + '/../Output/'): - """ - Plot a variable according to its latitude and longitude - """ - # Create the projection - ax = plt.axes(projection=cartopy.crs.PlateCarree()) - # Add country borders for reference - ax.add_feature(cartopy.feature.BORDERS) - # Set the extent - ax.set_extent([east, west, south, north], cartopy.crs.PlateCarree()) - # Label title, x, and y axes - plt.title(title) - ax.set_xticks(np.arange(east,west+1,xtick), cartopy.crs.PlateCarree()) - ax.set_yticks(np.arange(south,north+1,ytick), cartopy.crs.PlateCarree()) - plt.xlabel(xlabel) - plt.ylabel(ylabel) - # Plot the data - plt.scatter(lons, lats, s=marker_size, c=variable, cmap='RdBu', marker='o', edgecolor='black', linewidths=0.25) - # plotting x, y, size [s=__], color bar [c=__] - plt.clim(rangelow,rangehigh) - # set the range of the color bar - plt.colorbar(fraction=0.02, pad=0.04) - # fraction resizes the colorbar, pad is the space between the plot and colorbar - if option_savefig == 1: - plt.savefig(output_filepath + fig_fn) - plt.show() - - -def plot_caloutput(data): - """ - Plot maps and histograms of the calibration parameters to visualize results - """ - # Set extent - east = int(round(data['CenLon'].min())) - 1 - west = int(round(data['CenLon'].max())) + 1 - south = int(round(data['CenLat'].min())) - 1 - north = int(round(data['CenLat'].max())) + 1 - xtick = 1 - ytick = 1 - # Select relevant data - lats = data['CenLat'][:] - lons = data['CenLon'][:] - precfactor = data['precfactor'][:] - tempchange = data['tempchange'][:] - ddfsnow = data['ddfsnow'][:] - calround = data['calround'][:] - massbal = data['MB_geodetic_mwea'] - # Plot regional maps - plot_latlonvar(lons, lats, massbal, 'Geodetic mass balance [mwea]', 'longitude [deg]', 'latitude [deg]', east, west, - south, north, xtick, ytick) - plot_latlonvar(lons, lats, precfactor, 'precipitation factor', 'longitude [deg]', 'latitude [deg]', east, west, - south, north, xtick, ytick) - plot_latlonvar(lons, lats, tempchange, 'Temperature bias [degC]', 'longitude [deg]', 'latitude [deg]', east, west, - south, north, xtick, ytick) - plot_latlonvar(lons, lats, ddfsnow, 'DDF_snow [m w.e. d-1 degC-1]', 'longitude [deg]', 'latitude [deg]', east, west, - south, north, xtick, ytick) - plot_latlonvar(lons, lats, calround, 'Calibration round', 'longitude [deg]', 'latitude [deg]', east, west, - south, north, xtick, ytick) - # Plot histograms - data.hist(column='MB_difference_mwea', bins=50) - plt.title('Mass Balance Difference [mwea]') - data.hist(column='precfactor', bins=50) - plt.title('Precipitation factor [-]') - data.hist(column='tempchange', bins=50) - plt.title('Temperature bias [degC]') - data.hist(column='ddfsnow', bins=50) - plt.title('DDFsnow [mwe d-1 degC-1]') - plt.xticks(rotation=60) - data.hist(column='calround', bins = [0.5, 1.5, 2.5, 3.5]) - plt.title('Calibration round') - plt.xticks([1, 2, 3]) - - -#%% ===== PARAMETER RELATIONSHIPS ====== -if option_parameter_relationships == 1: - # Load csv - ds = pd.read_csv(input.main_directory + '/../Output/20180710_cal_modelparams_opt1_R15_ERA-Interim_1995_2015.csv', - index_col=0) - property_cn = 'Zmed' - - # Relationship between model parameters and glacier properties - plt.figure(figsize=(6,10)) - plt.subplots_adjust(wspace=0.05, hspace=0.05) - plt.suptitle('Model parameters vs. ' + property_cn, y=0.94) - # Temperature change - slope, intercept, r_value, p_value, std_err = scipy.stats.linregress(ds[property_cn], ds['tempchange']) - xplot = np.arange(4000,6500) - line = slope*xplot+intercept - plt.subplot(4,1,1) - plt.plot(ds[property_cn], ds['tempchange'], 'o', mfc='none', mec='black') - plt.plot(xplot, line) - plt.xlabel(property_cn + ' [masl]', size=10) - plt.ylabel('tempchange \n[degC]', size=12) - equation = 'tempchange = ' + str(round(slope,7)) + ' * ' + property_cn + ' + ' + str(round(intercept,5)) - plt.text(0.15, 0.85, equation, fontsize=12, transform=plt.gcf().transFigure, - bbox=dict(facecolor='white', edgecolor='none', alpha=0.85)) - print(equation, ' , R2 =', round(r_value**2,2)) - # Precipitation factor - slope, intercept, r_value, p_value, std_err = scipy.stats.linregress(ds[property_cn], ds['precfactor']) - xplot = np.arange(4000,6500) - line = slope*xplot+intercept - plt.subplot(4,1,2) - plt.plot(ds[property_cn], ds['precfactor'], 'o', mfc='none', mec='black') - plt.plot(xplot, line) - plt.xlabel(property_cn + ' [masl]', size=12) - plt.ylabel('precfactor \n[-]', size=12) - equation = 'precfactor = ' + str(round(slope,7)) + ' * ' + property_cn + ' + ' + str(round(intercept,5)) - plt.text(0.15, 0.65, equation, fontsize=12, transform=plt.gcf().transFigure, - bbox=dict(facecolor='white', edgecolor='none', alpha=0.85)) - print(equation, ' , R2 =', round(r_value**2,2)) - # Degree day factor of snow - slope, intercept, r_value, p_value, std_err = scipy.stats.linregress(ds[property_cn], ds['ddfsnow']) - xplot = np.arange(4000,6500) - line = slope*xplot+intercept - plt.subplot(4,1,3) - plt.plot(ds[property_cn], ds['ddfsnow'], 'o', mfc='none', mec='black') - plt.plot(xplot, line) - plt.xlabel(property_cn + ' [masl]', size=12) - plt.ylabel('ddfsnow \n[mwe d-1 degC-1]', size=12) -# plt.legend() - equation = 'ddfsnow = ' + str(round(slope,12)) + ' * ' + property_cn + ' + ' + str(round(intercept,5)) - plt.text(0.15, 0.45, equation, fontsize=12, transform=plt.gcf().transFigure, - bbox=dict(facecolor='white', edgecolor='none', alpha=0.85)) - print(equation, ' , R2 =', round(r_value**2,2)) - # Precipitation gradient - slope, intercept, r_value, p_value, std_err = scipy.stats.linregress(ds[property_cn], ds['precgrad']) - xplot = np.arange(4000,6500) - line = slope*xplot+intercept - plt.subplot(4,1,4) - plt.plot(ds[property_cn], ds['precgrad'], 'o', mfc='none', mec='black') - plt.plot(xplot, line) - plt.xlabel(property_cn + ' [masl]', size=12) - plt.ylabel('precgrad \n[% m-1]', size=12) -# plt.legend() - equation = 'precgrad = ' + str(round(slope,12)) + ' * ' + property_cn + ' + ' + str(round(intercept,5)) - plt.text(0.15, 0.25, equation, fontsize=12, transform=plt.gcf().transFigure, - bbox=dict(facecolor='white', edgecolor='none', alpha=0.85)) - print(equation, ' , R2 =', round(r_value**2,2)) - # Plot and save figure - if option_savefigs == 1: - plt.savefig(input.output_filepath + 'figures/' + 'modelparameters_vs_' + property_cn + '.png', - bbox_inches='tight') - plt.show() - -#%% ===== PLOTTING: Future simulations ===== -if option_plot_futuresim == 1: - output_fp = input.output_filepath + 'R15_sims_20180530/' - gcm_list = ['MPI-ESM-LR', 'GFDL-CM3', 'CanESM2', 'GISS-E2-R'] -# gcm_list = ['NorESM1-M'] -# gcm_list = ['MPI-ESM-LR'] - rcp_scenario = 'rcp26' - rgi_regionO1 = [15] - output_all = [] - gcm = gcm_list[0] - for gcm in gcm_list: -# for rcp_scenario in ['rcp26', 'rcp85']: - print(gcm) - output_fn = 'PyGEM_R' + str(rgi_regionO1[0]) + '_' + gcm + '_' + rcp_scenario + '_biasadj_opt1_1995_2100.nc' - output = nc.Dataset(output_fp + output_fn) - - # Select relevant data - main_glac_rgi = pd.DataFrame(output['glacier_table'][:], columns=output['glacier_table_header'][:]) - main_glac_rgi['RGIId'] = 'RGI60-' + main_glac_rgi['RGIId_float'].astype(str) - lats = main_glac_rgi['CenLat'] - lons = main_glac_rgi['CenLon'] - months = nc.num2date(output['time'][:], units=output['time'].units, calendar=output['time'].calendar).tolist() - years = output['year'][:] - years_plus1 = output['year_plus1'][:] - massbal_total = output['massbaltotal_glac_monthly'][:] - massbal_total_mwea = massbal_total.sum(axis=1)/(massbal_total.shape[1]/12) - volume_glac_annual = output['volume_glac_annual'][:] - volume_glac_annual[volume_glac_annual[:,0] == 0] = np.nan - volume_glac_annualnorm = volume_glac_annual / volume_glac_annual[:,0][:,np.newaxis] * 100 - volchange_glac_perc_15yrs = (volume_glac_annual[:,16] - volume_glac_annual[:,0]) / volume_glac_annual[:,0] * 100 - volchange_glac_perc_15yrs[np.isnan(volchange_glac_perc_15yrs)==True] = 0 - volume_reg_annual = output['volume_glac_annual'][:].sum(axis=0) - volume_reg_annualnorm = volume_reg_annual / volume_reg_annual[0] * 100 - slr_reg_annual_mm = ((volume_reg_annual[0] - volume_reg_annual) * input.density_ice / input.density_water / - input.area_ocean * 10**6) - runoff_glac_monthly = output['runoff_glac_monthly'][:] - runoff_reg_monthly = runoff_glac_monthly.mean(axis=0) - acc_glac_monthly = output['acc_glac_monthly'][:] - acc_reg_monthly = acc_glac_monthly.mean(axis=0) - acc_reg_annual = np.sum(acc_reg_monthly.reshape(-1,12), axis=1) - refreeze_glac_monthly = output['refreeze_glac_monthly'][:] - refreeze_reg_monthly = refreeze_glac_monthly.mean(axis=0) - refreeze_reg_annual = np.sum(refreeze_reg_monthly.reshape(-1,12), axis=1) - melt_glac_monthly = output['melt_glac_monthly'][:] - melt_reg_monthly = melt_glac_monthly.mean(axis=0) - melt_reg_annual = np.sum(melt_reg_monthly.reshape(-1,12), axis=1) - massbaltotal_glac_monthly = output['massbaltotal_glac_monthly'][:] - massbaltotal_reg_monthly = massbaltotal_glac_monthly.mean(axis=0) - massbaltotal_reg_annual = np.sum(massbaltotal_reg_monthly.reshape(-1,12), axis=1) - - # PLOT OF ALL GCMS - # use subplots to plot all the GCMs on the same figure - # Plot: Regional volume change [%] - plt.subplot(2,1,1) - plt.plot(years_plus1, volume_reg_annualnorm, label=gcm) - plt.title('Region ' + str(rgi_regionO1[0])) - plt.ylabel('Volume [%]') - plt.xlim(2000,2101) - plt.legend() - - # Plot: Regional sea-level rise [mm] - plt.subplot(2,1,2) - plt.plot(years_plus1, slr_reg_annual_mm, label=gcm) - plt.ylabel('Sea-level rise [mm]') - plt.xlim(2000,2101) - plt.show() - - - # PLOTS FOR LAST GCM - # Plot: Regional mass balance [mwe] - plt.plot(years, massbaltotal_reg_annual, label='massbal_total') - plt.plot(years, acc_reg_annual, label='accumulation') - plt.plot(years, refreeze_reg_annual, label='refreeze') - plt.plot(years, -1*melt_reg_annual, label='melt') - plt.ylabel('Region 15 annual mean [m.w.e.]') - plt.title(gcm) - plt.legend() - plt.show() - - # Plot: Regional map of volume change by glacier - volume_change_glac_perc = output['volume_glac_annual'][:][:,0] - volume_change_glac_perc[volume_change_glac_perc > 0] = ( - (volume_glac_annual[volume_change_glac_perc > 0,-1] - - volume_glac_annual[volume_change_glac_perc > 0, 0]) - / volume_glac_annual[volume_change_glac_perc > 0, 0] * 100) - # Set extent - east = int(round(lons.min())) - 1 - west = int(round(lons.max())) + 1 - south = int(round(lats.min())) - 1 - north = int(round(lats.max())) + 1 - xtick = 1 - ytick = 1 - # Plot regional maps - plot_latlonvar(lons, lats, volume_change_glac_perc, -100, 100, gcm + ' Volume [%]', - 'longitude [deg]', 'latitude [deg]', 'jet_r', east, west, south, north, xtick, ytick, - marker_size=20) - - -#%% ===== MASS BALANCE ANALYSIS ===== -if option_mb_shean_analysis == 1: - # Set parameters within this little batch script - option_nearestneighbor_export = 0 - - # Load csv - ds = pd.read_csv(input.main_directory + '/../Output/calibration_R15_20180403_Opt02solutionspaceexpanding.csv', - index_col='GlacNo') - # Select data of interest - data_all = ds[['RGIId', 'Area', 'CenLon', 'CenLat', 'mb_mwea', 'mb_mwea_sigma', 'lrgcm', 'lrglac', 'precfactor', - 'precgrad', 'ddfsnow', 'ddfice', 'tempsnow', 'tempchange']].copy() - # Drop nan data to retain only glaciers with calibrated parameters - data = data_all.dropna() - - # Compute statistics - mb_mean = data['mb_mwea'].mean() - mb_std = data['mb_mwea'].std() - mb_95 = [mb_mean - 1.96 * mb_std, mb_mean + 1.96 * mb_std] - # Remove data outside of 95% confidence bounds - data_95 = data[(data['mb_mwea'] >= mb_95[0]) & (data['mb_mwea'] <= mb_95[1])] - mb_1std = [mb_mean - 1 * mb_std, mb_mean + 1 * mb_std] - # Remove data outside of 95% confidence bounds - data_1std = data[(data['mb_mwea'] >= mb_1std[0]) & (data['mb_mwea'] <= mb_1std[1])] - - # Plot Glacier Area vs. MB - plt.scatter(data['Area'], data['mb_mwea'], facecolors='none', edgecolors='black', label='Region 15') - plt.ylabel('MB 2000-2015 [mwea]', size=12) - plt.xlabel('Glacier area [km2]', size=12) - plt.legend() - plt.show() - # Only 95% confidence - plt.scatter(data_95['Area'], data_95['mb_mwea'], facecolors='none', edgecolors='black', label='Region 15') - plt.ylabel('MB 2000-2015 [mwea]', size=12) - plt.xlabel('Glacier area [km2]', size=12) - plt.ylim(-3,1.5) - plt.legend() - plt.show() - # Only 1 std - plt.scatter(data_1std['Area'], data_1std['mb_mwea'], facecolors='none', edgecolors='black', label='Region 15') - plt.ylabel('MB 2000-2015 [mwea]', size=12) - plt.xlabel('Glacier area [km2]', size=12) - plt.ylim(-3,1.5) - plt.legend() - plt.show() - - # Bar plot - bins = np.array([0.1, 0.25, 0.5, 1, 2.5, 5, 10, 20, 200]) - hist, bin_edges = np.histogram(data.Area,bins) # make the histogram - fig, ax = plt.subplots() - # Plot the histogram heights against integers on the x axis - ax.bar(range(len(hist)),hist,width=1) - # Set the tickets to the middle of the bars - ax.set_xticks([i for i,j in enumerate(hist)]) - # Set the xticklabels to a string taht tells us what the bin edges were - ax.set_xticklabels(['{} - {}'.format(bins[i],bins[i+1]) for i,j in enumerate(hist)], rotation=45) - plt.show() - - # Compute max/min for the various bins - mb = data_1std['mb_mwea'] - area = data_1std['Area'] - mb_envelope = np.zeros((bins.shape[0]-1,3)) - for n in range(bins.shape[0] - 1): - mb_envelope[n,0] = bins[n+1] - mb_subset = mb[(area > bins[n]) & (area <= bins[n+1])] - mb_envelope[n,1] = mb_subset.min() - mb_envelope[n,2] = mb_subset.max() - - - # zoomed in - plt.scatter(data['Area'], data['mb_mwea'], facecolors='none', edgecolors='black', label='Region 15') - plt.ylabel('MB 2000-2015 [mwea]', size=12) - plt.xlabel('Glacier area [km2]', size=12) - plt.xlim(0.1,2) - plt.legend() - plt.show() - - # Plot Glacier Area vs. MB - plt.scatter(data['mb_mwea'], data['Area'], facecolors='none', edgecolors='black', label='Region 15') - plt.ylabel('Glacier area [km2]', size=12) - plt.xlabel('MB 2000-2015 [mwea]', size=12) - plt.legend() - plt.show() - # Plot Glacier Area vs. MB - plt.scatter(data_95['mb_mwea'], data_95['Area'], facecolors='none', edgecolors='black', label='Region 15') - plt.ylabel('Glacier area [km2]', size=12) - plt.xlabel('MB 2000-2015 [mwea]', size=12) - plt.xlim(-3,1.75) - plt.legend() - plt.show() - - # Histogram of MB data - plt.hist(data['mb_mwea'], bins=50) - plt.show() - - - main_glac_rgi = modelsetup.selectglaciersrgitable(rgi_glac_number='all') - # Select calibration data from geodetic mass balance from David Shean - main_glac_calmassbal = modelsetup.selectcalibrationdata(main_glac_rgi) - # Concatenate massbal data to the main glacier - main_glac_rgi = pd.concat([main_glac_rgi, main_glac_calmassbal], axis=1) - # Drop those with nan values - main_glac_calmassbal = main_glac_calmassbal.dropna() - main_glac_rgi = main_glac_rgi.dropna() - - main_glac_rgi[['lrgcm', 'lrglac', 'precfactor', 'precgrad', 'ddfsnow', 'ddfice', 'tempsnow', 'tempchange']] = ( - data[['lrgcm', 'lrglac', 'precfactor', 'precgrad', 'ddfsnow', 'ddfice', 'tempsnow', 'tempchange']]) - # Mass balance versus various parameters - # Median elevation - plt.scatter(main_glac_rgi['mb_mwea'], main_glac_rgi['Zmed'], facecolors='none', edgecolors='black', - label='Region 15') - plt.ylabel('Median Elevation [masl]', size=12) - plt.xlabel('MB 2000-2015 [mwea]', size=12) - plt.legend() - plt.show() - # Elevation range - main_glac_rgi['elev_range'] = main_glac_rgi['Zmax'] - main_glac_rgi['Zmin'] - plt.scatter(main_glac_rgi['mb_mwea'], main_glac_rgi['elev_range'], facecolors='none', edgecolors='black', - label='Region 15') - plt.ylabel('Elevation range [m]', size=12) - plt.xlabel('MB 2000-2015 [mwea]', size=12) - plt.legend() - plt.show() - plt.scatter(main_glac_rgi['Area'], main_glac_rgi['elev_range'], facecolors='none', edgecolors='black', - label='Region 15') - plt.ylabel('Elevation range [m]', size=12) - plt.xlabel('Area [km2]', size=12) - plt.legend() - plt.show() - # Length - plt.scatter(main_glac_rgi['mb_mwea'], main_glac_rgi['Lmax'], facecolors='none', edgecolors='black', - label='Region 15') - plt.ylabel('Length [m]', size=12) - plt.xlabel('MB 2000-2015 [mwea]', size=12) - plt.legend() - plt.show() - # Slope - plt.scatter(main_glac_rgi['mb_mwea'], main_glac_rgi['Slope'], facecolors='none', edgecolors='black', - label='Region 15') - plt.ylabel('Slope [deg]', size=12) - plt.xlabel('MB 2000-2015 [mwea]', size=12) - plt.legend() - plt.show() - # Aspect - plt.scatter(main_glac_rgi['mb_mwea'], main_glac_rgi['Aspect'], facecolors='none', edgecolors='black', - label='Region 15') - plt.ylabel('Aspect [deg]', size=12) - plt.xlabel('MB 2000-2015 [mwea]', size=12) - plt.legend() - plt.show() - plt.scatter(main_glac_rgi['Aspect'], main_glac_rgi['precfactor'], facecolors='none', edgecolors='black', - label='Region 15') - plt.ylabel('precfactor [-]', size=12) - plt.xlabel('Aspect [deg]', size=12) - plt.legend() - plt.show() - # tempchange - # Line of best fit - slope, intercept, r_value, p_value, std_err = scipy.stats.linregress(main_glac_rgi['mb_mwea'], - main_glac_rgi['tempchange']) - xplot = np.arange(-3,1.5) - line = slope*xplot+intercept - plt.plot(main_glac_rgi['mb_mwea'], main_glac_rgi['tempchange'], 'o', mfc='none', mec='black') - plt.plot(xplot, line) - plt.ylabel('tempchange [deg]', size=12) - plt.xlabel('MB 2000-2015 [mwea]', size=12) - plt.legend() - plt.show() - # precfactor - # Line of best fit - slope, intercept, r_value, p_value, std_err = scipy.stats.linregress(main_glac_rgi['mb_mwea'], - main_glac_rgi['precfactor']) - xplot = np.arange(-3,1.5) - line = slope*xplot+intercept - plt.plot(main_glac_rgi['mb_mwea'], main_glac_rgi['precfactor'], 'o', mfc='none', mec='black') - plt.plot(xplot, line) - plt.ylabel('precfactor [-]', size=12) - plt.xlabel('MB 2000-2015 [mwea]', size=12) - plt.legend() - plt.show() - - -#%% ===== ALL GEODETIC MB DATA LOAD & COMPARE (Shean, Brun, Mauer) ===== -if option_geodeticMB_loadcompare == 1: - -# rgi_regionsO1 = [15] - rgi_regionsO1 = ['13, 14, 15'] # 13, 14, 15 - load data from csv - rgi_glac_number = 'all' - - if rgi_regionsO1[0] == '13, 14, 15': - # Note: this file was created by manually copying the main_glac_rgi for regions 13, 14, 15 into a csv - main_glac_rgi = pd.read_csv(input.main_directory + - '/../DEMs/geodetic_glacwide_Shean_Maurer_Brun_HMA_20180807.csv') - else: - # Mass balance column name - massbal_colname = 'mb_mwea' - # Mass balance uncertainty column name - massbal_uncertainty_colname = 'mb_mwea_sigma' - # Mass balance date 1 column name - massbal_t1 = 't1' - # Mass balance date 1 column name - massbal_t2 = 't2' - # Mass balance tolerance [m w.e.a] - massbal_tolerance = 0.1 - # Calibration optimization tolerance - - main_glac_rgi = modelsetup.selectglaciersrgitable(rgi_regionsO1=rgi_regionsO1, rgi_regionsO2='all', - rgi_glac_number=rgi_glac_number) - # SHEAN DATA - # Load all data - ds_all_shean = pd.read_csv(input.main_directory + '/../DEMs/Shean_2018_0806/hma_mb_20180803_1229.csv') - ds_all_shean['RegO1'] = ds_all_shean[input.shean_rgi_glacno_cn].values.astype(int) - ds_all_shean['glacno'] = ((ds_all_shean[input.shean_rgi_glacno_cn] % 1) * 10**5).round(0).astype(int) - ds_all_shean['RGIId'] = ('RGI60-' + ds_all_shean['RegO1'].astype(str) + '.' + - (ds_all_shean['glacno'] / 10**5).apply(lambda x: '%.5f' % x).str.split('.').str[1]) - # Select glaciers included in main_glac_rgi - ds_shean = (ds_all_shean.iloc[np.where(ds_all_shean['RGIId'].isin(main_glac_rgi['RGIId']) == True)[0],:]).copy() - ds_shean.sort_values(['glacno'], inplace=True) - ds_shean.reset_index(drop=True, inplace=True) - ds_shean['O1Index'] = np.where(main_glac_rgi['RGIId'].isin(ds_shean['RGIId']))[0] - # Select data for main_glac_rgi - main_glac_calmassbal_shean = np.zeros((main_glac_rgi.shape[0],4)) - ds_subset_shean = ds_shean[[input.rgi_O1Id_colname, massbal_colname, massbal_uncertainty_colname, massbal_t1, - massbal_t2]].values - rgi_O1Id = main_glac_rgi[input.rgi_O1Id_colname].values - for glac in range(rgi_O1Id.shape[0]): - try: - # Grab the mass balance based on the RGIId Order 1 glacier number - main_glac_calmassbal_shean[glac,:] = ( - ds_subset_shean[np.where(np.in1d(ds_subset_shean[:,0],rgi_O1Id[glac])==True)[0][0],1:]) - # np.in1d searches if there is a match in the first array with the second array provided and returns an - # array with same length as first array and True/False values. np.where then used to identify the - # index where there is a match, which is then used to select the massbalance value - # Use of numpy arrays for indexing and this matching approach is much faster than looping through; - # however, need the for loop because np.in1d does not order the values that match; hence, need to do - # it 1 at a time - except: - # If there is no mass balance data available for the glacier, then set as NaN - main_glac_calmassbal_shean[glac,:] = np.empty(4) - main_glac_calmassbal_shean[glac,:] = np.nan - main_glac_calmassbal_shean = pd.DataFrame(main_glac_calmassbal_shean, - columns=[massbal_colname, massbal_uncertainty_colname, massbal_t1, - massbal_t2]) - main_glac_rgi['Shean_MB_mwea'] = main_glac_calmassbal_shean[input.massbal_colname] - main_glac_rgi['Shean_MB_mwea_sigma'] = main_glac_calmassbal_shean[input.massbal_uncertainty_colname] - main_glac_rgi['Shean_MB_year1'] = main_glac_calmassbal_shean[massbal_t1] - main_glac_rgi['Shean_MB_year2'] = main_glac_calmassbal_shean[massbal_t2] - - # ===== BRUN DATA ===== - # Load all data - cal_rgi_colname = 'GLA_ID' - ds_all_raw_brun = pd.read_csv(input.brun_fp + input.brun_fn) - ds_all_brun = ds_all_raw_brun[ds_all_raw_brun['Measured GLA area [percent]'] >= 60].copy() - ds_all_brun[massbal_t1] = 2000 - ds_all_brun[massbal_t2] = 2016 - ds_all_brun.rename(columns={input.brun_mb_cn:massbal_colname}, inplace=True) - ds_all_brun.rename(columns={input.brun_mb_err_cn:massbal_uncertainty_colname}, inplace=True) - # Subset glaciers based on region - ds_all_brun['RegO1'] = ds_all_brun[input.brun_rgi_glacno_cn].values.astype(int) - ds_all_brun['glacno'] = ((ds_all_brun[input.brun_rgi_glacno_cn] % 1) * 10**5).round(0).astype(int) - ds_all_brun['RGIId'] = ('RGI60-' + ds_all_brun['RegO1'].astype(str) + '.' + - (ds_all_brun['glacno'] / 10**5).apply(lambda x: '%.5f' % x).str.split('.').str[1]) - # Select glaciers included in main_glac_rgi - ds_brun = (ds_all_brun.iloc[np.where(ds_all_brun['RGIId'].isin(main_glac_rgi['RGIId']) == True)[0],:]).copy() - ds_brun.sort_values(['glacno'], inplace=True) - ds_brun.reset_index(drop=True, inplace=True) - ds_brun['O1Index'] = np.where(main_glac_rgi['RGIId'].isin(ds_brun['RGIId']))[0] - # Select data for main_glac_rgi - main_glac_calmassbal_brun = np.zeros((main_glac_rgi.shape[0], 6)) - ds_subset_brun = ds_brun[[input.rgi_O1Id_colname, massbal_colname, massbal_uncertainty_colname, massbal_t1, - massbal_t2, 'Tot_GLA_area [km2]', 'Measured GLA area [percent]']].values - for glac in range(rgi_O1Id.shape[0]): - try: - # Grab the mass balance based on the RGIId Order 1 glacier number - main_glac_calmassbal_brun[glac,:] = ( - ds_subset_brun[np.where(np.in1d(ds_subset_brun[:,0],rgi_O1Id[glac])==True)[0][0],1:]) - except: - # If there is no mass balance data available for the glacier, then set as NaN - main_glac_calmassbal_brun[glac,:] = np.empty(main_glac_calmassbal_brun.shape[1]) - main_glac_calmassbal_brun[glac,:] = np.nan - main_glac_calmassbal_brun = pd.DataFrame(main_glac_calmassbal_brun, - columns=[massbal_colname, massbal_uncertainty_colname, massbal_t1, - massbal_t2, 'Tot_GLA_area [km2]', - 'Measured GLA area [percent]']) - main_glac_rgi['Brun_MB_mwea'] = main_glac_calmassbal_brun[massbal_colname] - main_glac_rgi['Brun_MB_err_mwea'] = main_glac_calmassbal_brun[massbal_uncertainty_colname] - main_glac_rgi['Brun_Tot_GLA_area[km2]'] = main_glac_calmassbal_brun['Tot_GLA_area [km2]'] - main_glac_rgi['Brun_GLA_area_measured[%]'] = main_glac_calmassbal_brun['Measured GLA area [percent]'] - ds_brun['GLA_ID'] = ds_brun['GLA_ID'].astype(str) - - - # ===== MAUER DATA ===== - # Load all data - cal_rgi_colname = 'id' - ds_all_raw_mauer = pd.read_csv(input.mauer_fp + input.mauer_fn) - ds_all_mauer = ds_all_raw_mauer[ds_all_raw_mauer['percentCov'] >= 60].copy() - ds_all_mauer.rename(columns={input.mauer_mb_cn:massbal_colname}, inplace=True) - ds_all_mauer.rename(columns={input.mauer_mb_err_cn:massbal_uncertainty_colname}, inplace=True) - ds_all_mauer.rename(columns={input.mauer_time1_cn:massbal_t1}, inplace=True) - ds_all_mauer.rename(columns={input.mauer_time2_cn:massbal_t2}, inplace=True) - # Subset glaciers based on region - ds_all_mauer['RegO1'] = ds_all_mauer[input.mauer_rgi_glacno_cn].values.astype(int) - ds_all_mauer['glacno'] = ((ds_all_mauer[input.mauer_rgi_glacno_cn] % 1) * 10**5).round(0).astype(int) - ds_all_mauer['RGIId'] = ('RGI60-' + ds_all_mauer['RegO1'].astype(str) + '.' + - (ds_all_mauer['glacno'] / 10**5).apply(lambda x: '%.5f' % x).str.split('.').str[1]) - # Select glaciers included in main_glac_rgi - ds_mauer = (ds_all_mauer.iloc[np.where(ds_all_mauer['RGIId'].isin(main_glac_rgi['RGIId']) == True)[0],:]).copy() - ds_mauer.sort_values(['glacno'], inplace=True) - ds_mauer.reset_index(drop=True, inplace=True) - ds_mauer['O1Index'] = np.where(main_glac_rgi['RGIId'].isin(ds_mauer['RGIId']))[0] - - main_glac_calmassbal_mauer = np.zeros((main_glac_rgi.shape[0], 5)) - ds_subset_mauer = ds_mauer[[input.rgi_O1Id_colname, massbal_colname, massbal_uncertainty_colname, massbal_t1, - massbal_t2, 'percentCov']].values - - for glac in range(rgi_O1Id.shape[0]): - try: - # Grab the mass balance based on the RGIId Order 1 glacier number - main_glac_calmassbal_mauer[glac,:] = ( - ds_subset_mauer[np.where(np.in1d(ds_subset_mauer[:,0],rgi_O1Id[glac])==True)[0][0],1:]) - except: - # If there is no mass balance data available for the glacier, then set as NaN - main_glac_calmassbal_mauer[glac,:] = np.empty(main_glac_calmassbal_mauer.shape[1]) - main_glac_calmassbal_mauer[glac,:] = np.nan - main_glac_calmassbal_mauer = pd.DataFrame(main_glac_calmassbal_mauer, - columns=[massbal_colname, massbal_uncertainty_colname, massbal_t1, - massbal_t2, 'percentCov']) - main_glac_rgi['Mauer_MB_mwea'] = main_glac_calmassbal_mauer[massbal_colname] - main_glac_rgi['Mauer_MB_mwea_sigma'] = main_glac_calmassbal_mauer[massbal_uncertainty_colname] - main_glac_rgi['Mauer_MB_year1'] = main_glac_calmassbal_mauer[massbal_t1] - main_glac_rgi['Mauer_MB_year2'] = main_glac_calmassbal_mauer[massbal_t2] - main_glac_rgi['Mauer_GLA_area_measured[%]'] = main_glac_calmassbal_mauer['percentCov'] - ds_mauer['id'] = ds_mauer['id'].astype(str) - - # Differences - main_glac_rgi['Dif_Shean-Mauer[mwea]'] = main_glac_rgi['Shean_MB_mwea'] - main_glac_rgi['Mauer_MB_mwea'] - main_glac_rgi['Dif_Shean-Brun[mwea]'] = main_glac_rgi['Shean_MB_mwea'] - main_glac_rgi['Brun_MB_mwea'] - main_glac_rgi['Dif_Mauer-Brun[mwea]'] = main_glac_rgi['Mauer_MB_mwea'] - main_glac_rgi['Brun_MB_mwea'] - - # Statistics - print('Glacier area [total]:', round(main_glac_rgi.Area.sum(),1),'km2') - print('Glacier count [total]:',main_glac_rgi.shape[0],'\n') - print('Glacier area [Shean]:', - round(main_glac_rgi[np.isfinite(main_glac_rgi['Shean_MB_mwea'])].Area.sum(),1), - 'km2 (', - round(main_glac_rgi[np.isfinite(main_glac_rgi['Shean_MB_mwea'])].Area.sum()/main_glac_rgi.Area.sum()*100,1), - '%)') - print('Glacier area [Brun]:', - round(main_glac_rgi[np.isfinite(main_glac_rgi['Brun_MB_mwea'])].Area.sum(),1), - 'km2 (', - round(main_glac_rgi[np.isfinite(main_glac_rgi['Brun_MB_mwea'])].Area.sum()/main_glac_rgi.Area.sum()*100,1), - '%)') - print('Glacier area [Mauer]:', - round(main_glac_rgi[np.isfinite(main_glac_rgi['Mauer_MB_mwea'])].Area.sum(),1), - 'km2 (', - round(main_glac_rgi[np.isfinite(main_glac_rgi['Mauer_MB_mwea'])].Area.sum()/main_glac_rgi.Area.sum()*100,1), - '%)','\n') - print('Glacier count [Shean]:',main_glac_rgi['Shean_MB_mwea'].dropna().shape[0], - '(', round(main_glac_rgi['Shean_MB_mwea'].dropna().shape[0]/main_glac_rgi.shape[0]*100,1),'% )') - print('Glacier count [Brun]:',main_glac_rgi['Brun_MB_mwea'].dropna().shape[0], - '(', round(main_glac_rgi['Brun_MB_mwea'].dropna().shape[0]/main_glac_rgi.shape[0]*100,1),'% )') - print('Glacier count [Mauer]:',main_glac_rgi['Mauer_MB_mwea'].dropna().shape[0], - '(', round(main_glac_rgi['Mauer_MB_mwea'].dropna().shape[0]/main_glac_rgi.shape[0]*100,1),'% )','\n') - print('Comparison:') - print('# same glaciers (Shean/Mauer):',main_glac_rgi['Dif_Shean-Mauer[mwea]'].copy().dropna().shape[0]) - print('# same glaciers (Shean/Brun)',main_glac_rgi['Dif_Shean-Brun[mwea]'].copy().dropna().shape[0]) - print('# same glaciers (Mauer/Brun)',main_glac_rgi['Dif_Mauer-Brun[mwea]'].copy().dropna().shape[0], '\n') - print('Mean difference (Shean/Mauer):', main_glac_rgi['Dif_Shean-Mauer[mwea]'].mean()) - print('Std difference (Shean/Mauer)):', main_glac_rgi['Dif_Shean-Mauer[mwea]'].std()) - print('Min difference (Shean/Mauer):', main_glac_rgi['Dif_Shean-Mauer[mwea]'].min()) - print('Max difference (Shean/Mauer):', main_glac_rgi['Dif_Shean-Mauer[mwea]'].max(), '\n') - print('Mean difference (Shean/Brun):', main_glac_rgi['Dif_Shean-Brun[mwea]'].mean()) - print('Std difference (Shean/Brun):', main_glac_rgi['Dif_Shean-Brun[mwea]'].std()) - print('Min difference (Shean/Brun):', main_glac_rgi['Dif_Shean-Brun[mwea]'].min()) - print('Max difference (Shean/Brun):', main_glac_rgi['Dif_Shean-Brun[mwea]'].max(), '\n') - print('Mean difference (Mauer/Brun):', main_glac_rgi['Dif_Mauer-Brun[mwea]'].mean()) - print('Std difference (Mauer/Brun):', main_glac_rgi['Dif_Mauer-Brun[mwea]'].std()) - print('Min difference (Mauer/Brun):', main_glac_rgi['Dif_Mauer-Brun[mwea]'].min()) - print('Max difference (Mauer/Brun):', main_glac_rgi['Dif_Mauer-Brun[mwea]'].max()) - # Plot histograms of the differences -# plt.hist(main_glac_rgi['Dif_Shean-Mauer[mwea]'].copy().dropna().values, label='Reg '+str(rgi_regionsO1[0])) -# plt.xlabel('MB Shean - Mauer [mwea]', size=12) -# plt.legend() -# plt.show() -# plt.hist(main_glac_rgi['Dif_Shean-Brun[mwea]'].copy().dropna().values, label='Reg '+str(rgi_regionsO1[0])) -# plt.xlabel('MB Shean - Brun [mwea]', size=12) -# plt.legend() -# plt.show() -# plt.hist(main_glac_rgi['Dif_Mauer-Brun[mwea]'].copy().dropna().values, label='Reg '+str(rgi_regionsO1[0])) -# plt.xlabel('MB Mauer - Brun [mwea]', size=12) -# plt.legend() -# plt.show() - # Plot differences vs. percent area - # Fairly consistent; only two 'outliers' - # Shean - Brun - compare_shean_brun = ( - main_glac_rgi[['RGIId', 'Area', 'Dif_Shean-Brun[mwea]','Brun_GLA_area_measured[%]']].copy().dropna()) - compare_shean_mauer = ( - main_glac_rgi[['RGIId', 'Area', 'Dif_Shean-Mauer[mwea]','Mauer_GLA_area_measured[%]']].copy().dropna()) - compare_mauer_brun = ( - main_glac_rgi[['RGIId', 'Area', 'Dif_Mauer-Brun[mwea]','Mauer_GLA_area_measured[%]', - 'Brun_GLA_area_measured[%]']].copy().dropna()) -# plt.scatter(compare_shean_brun['Brun_GLA_area_measured[%]'].values, -# compare_shean_brun['Dif_Shean-Brun[mwea]'].values, facecolors='none', edgecolors='black', -# label='Reg '+str(rgi_regionsO1[0])) -# plt.xlabel('Brun % Glacier area measured', size=12) -# plt.ylabel('MB Shean - Brun [mwea]', size=12) -# plt.legend() -# plt.show() - plt.scatter(compare_shean_brun['Area'].values, compare_shean_brun['Dif_Shean-Brun[mwea]'].values, facecolors='none', - edgecolors='black', label='Reg '+str(rgi_regionsO1[0])) - plt.xlabel('Glacier area [km2]', size=12) - plt.ylabel('MB Shean - Brun [mwea]', size=12) - plt.legend() - plt.show() - # Shean - Mauer -# plt.scatter(compare_shean_mauer['Mauer_GLA_area_measured[%]'].values, -# compare_shean_mauer['Dif_Shean-Mauer[mwea]'].values, facecolors='none', edgecolors='black', -# label='Reg '+str(rgi_regionsO1[0])) -# plt.xlabel('Mauer % Glacier area measured', size=12) -# plt.ylabel('MB Shean - Mauer [mwea]', size=12) -# plt.legend() -# plt.show() - plt.scatter(compare_shean_mauer['Area'].values, compare_shean_mauer['Dif_Shean-Mauer[mwea]'].values, - facecolors='none', edgecolors='black', label='Reg '+str(rgi_regionsO1[0])) - plt.xlabel('Glacier area [km2]', size=12) - plt.ylabel('MB Shean - Mauer [mwea]', size=12) - plt.legend() - plt.show() - # Mauer - Brun - plt.scatter(compare_mauer_brun['Area'].values, compare_mauer_brun['Dif_Mauer-Brun[mwea]'].values, - facecolors='none', edgecolors='black', label='Reg '+str(rgi_regionsO1[0])) - plt.xlabel('Glacier area [km2]', size=12) - plt.ylabel('MB Mauer - Brun [mwea]', size=12) - plt.legend() - plt.show() - - # Record statistics concerning number and area covered per region - main_glac_summary_colnames = ['reg count', 'count', '% reg count', 'reg area', 'area', '% total area'] - main_glac_summary_idxnames = ['shean', 'mauer', 'brun', 'all'] - main_glac_summary = pd.DataFrame(np.zeros((len(main_glac_summary_idxnames),len(main_glac_summary_colnames))), - index = main_glac_summary_idxnames, columns=main_glac_summary_colnames) - main_glac_summary['reg count'] = main_glac_rgi.shape[0] - main_glac_summary['reg area'] = main_glac_rgi['Area'].sum() - main_glac_summary.loc['shean', 'count'] = main_glac_rgi['Shean_MB_mwea'].dropna().shape[0] - main_glac_summary.loc['shean','area'] = ( - main_glac_rgi['Area'].where(pd.isnull(main_glac_rgi['Shean_MB_mwea']) == False).dropna().sum()) - main_glac_summary.loc['mauer', 'count'] = main_glac_rgi['Mauer_MB_mwea'].dropna().shape[0] - main_glac_summary.loc['mauer','area'] = ( - main_glac_rgi['Area'].where(pd.isnull(main_glac_rgi['Mauer_MB_mwea']) == False).dropna().sum()) - main_glac_summary.loc['brun', 'count'] = main_glac_rgi['Brun_MB_mwea'].dropna().shape[0] - main_glac_summary.loc['brun','area'] = ( - main_glac_rgi['Area'].where(pd.isnull(main_glac_rgi['Brun_MB_mwea']) == False).dropna().sum()) - main_glac_summary.loc['all', 'count'] = ( - main_glac_rgi['Area'][((pd.isnull(main_glac_rgi['Shean_MB_mwea']) == False) | - (pd.isnull(main_glac_rgi['Mauer_MB_mwea']) == False) | - (pd.isnull(main_glac_rgi['Brun_MB_mwea']) == False))].shape[0]) - main_glac_summary.loc['all', 'area'] = ( - main_glac_rgi['Area'][((pd.isnull(main_glac_rgi['Shean_MB_mwea']) == False) | - (pd.isnull(main_glac_rgi['Mauer_MB_mwea']) == False) | - (pd.isnull(main_glac_rgi['Brun_MB_mwea']) == False))].sum()) - main_glac_summary['% reg count'] = main_glac_summary['count'] / main_glac_summary['reg count'] * 100 - main_glac_summary['% total area'] = main_glac_summary['area'] / main_glac_summary['reg area'] * 100 - -# # Percent coverage if exclude glaciers < 1 km2 -# A = main_glac_rgi[np.isfinite(main_glac_rgi['Shean_MB_mwea'])] -# print(round(A[A['Area'] > 1].Area.sum() / main_glac_rgi.Area.sum() * 100,1)) - - -#%% ====== PLOTTING FOR CALIBRATION FUNCTION ====================================================================== -if option_calcompare_w_geomb == 1: - # Plot histograms and regional variations - rgi_regionsO1 = [15] - csv_path = '../DEMs/Shean_2018_0806/hma_mb_20180803_1229_all_filled.csv' - modelparams_fp_dict = { - 13: input.output_filepath + 'cal_opt2_20181018/reg13/', - 14: input.output_filepath + 'cal_opt2_20181018/reg14/', - 15: input.output_filepath + 'cal_opt2_20181018/reg15/'} - sims_fp_dict = { - 13: input.output_filepath + 'simulations/ERA-Interim_2000_2018_nobiasadj/reg13/stats/', - 14: input.output_filepath + 'simulations/ERA-Interim_2000_2018_nobiasadj/reg14/stats/', - 15: input.output_filepath + 'simulations/ERA-Interim_2000_2018_nobiasadj/reg15/stats/'} - - cal_data_all = pd.read_csv(csv_path) - - main_glac_rgi = modelsetup.selectglaciersrgitable(rgi_regionsO1=rgi_regionsO1, rgi_regionsO2 = 'all', - rgi_glac_number='all') - - cal_data_all['RegO1'] = cal_data_all['RGIId'].values.astype(int) - # Select data for specific region - cal_data_reg = cal_data_all[cal_data_all['RegO1']==rgi_regionsO1[0]].copy() - cal_data_reg.reset_index(drop=True, inplace=True) - # Glacier number and index for comparison - cal_data_reg['glacno'] = ((cal_data_reg['RGIId'] % 1) * 10**5).round(0).astype(int) - cal_data_reg['RGIId'] = ('RGI60-' + str(rgi_regionsO1[0]) + '.' + - (cal_data_reg['glacno'] / 10**5).apply(lambda x: '%.5f' % x).astype(str).str.split('.').str[1]) - # Select glaciers with mass balance data - cal_data = (cal_data_reg.iloc[np.where(cal_data_reg['glacno'].isin(main_glac_rgi['glacno']) == True)[0],:]).copy() - cal_data.reset_index(drop=True, inplace=True) - - # Compare observations, calibration, and simulations - cal_data['calibrated_mb'] = np.nan - for glac in range(main_glac_rgi.shape[0]): - glac_str = main_glac_rgi.loc[glac,'RGIId'].split('-')[1] - # Add calibrated mass balance - netcdf_fn_cal = glac_str + '.nc' - ds_cal = xr.open_dataset(modelparams_fp_dict[rgi_regionsO1[0]] + netcdf_fn_cal) - df_cal = pd.DataFrame(ds_cal['mp_value'].sel(chain=0).values, columns=ds_cal.mp.values) - cal_mb = df_cal.massbal.values.mean() - cal_data.loc[glac,'cal_mb'] = cal_mb - # Add simulated mass balance (will be more off because has mass loss/area changes feedback) - netcdf_fn_sim = 'ERA-Interim_c2_ba0_200sets_2000_2018--' + glac_str + '_stats.nc' - ds_sim = xr.open_dataset(sims_fp_dict[rgi_regionsO1[0]] + netcdf_fn_sim) - df_sim = pd.DataFrame(ds_cal['mp_value'].sel(chain=0).values, columns=ds_cal.mp.values) - sim_mb = df_cal.massbal.values.mean() - cal_data.loc[glac,'sim_mb'] = sim_mb - - cal_data['cal_mb_dif'] = cal_data.cal_mb - cal_data.mb_mwea - cal_data['sim_mb_dif'] = cal_data.sim_mb - cal_data.mb_mwea - cal_data.hist(column='cal_mb_dif', bins=50) - cal_data.hist(column='sim_mb_dif', bins=50) \ No newline at end of file diff --git a/run_calibration.py b/run_calibration.py index 1d36e67c..fd785441 100644 --- a/run_calibration.py +++ b/run_calibration.py @@ -9,7 +9,6 @@ import time import inspect # External libraries -from datetime import datetime import pandas as pd import numpy as np import xarray as xr @@ -63,6 +62,8 @@ def getparser(): help='number of simultaneous processes (cores) to use') parser.add_argument('-option_parallels', action='store', type=int, default=1, help='Switch to use or not use parallels (1 - use parallels, 0 - do not)') +# parser.add_argument('-spc_region', action='store', type=int, default=None, +# help='rgi region number for supercomputer') parser.add_argument('-rgi_glac_number_fn', action='store', type=str, default=None, help='Filename containing list of rgi_glac_number, helpful for running batches on spc') parser.add_argument('-progress_bar', action='store', type=int, default=0, @@ -74,83 +75,9 @@ def getparser(): return parser -def mb_mwea_calc(modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, width_initial, - elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, - glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, - option_areaconstant=1, return_tc_mustmelt=0, return_volremaining=0): - """ - Run the mass balance and calculate the mass balance [mwea] - - Parameters - ---------- - option_areaconstant : int - Switch to keep area constant (1) or not (0) - - Returns - ------- - mb_mwea : float - mass balance [m w.e. a-1] - """ - # Number of constant years - startyear_doy = (pd.to_datetime(pd.DataFrame({'year':[dates_table.loc[0,'date'].year], - 'month':[dates_table.loc[0,'date'].month], - 'day':[dates_table.loc[0,'date'].day]})) - .dt.strftime("%j").astype(float).values[0]) - startyear_daysinyear = ( - (pd.to_datetime(pd.DataFrame({'year':[dates_table.loc[0,'date'].year], 'month':[12], 'day':[31]})) - - pd.to_datetime(pd.DataFrame({'year':[dates_table.loc[0,'date'].year], 'month':[1], 'day':[1]}))) - .dt.days + 1).values[0] - startyear_decimal = dates_table.loc[0,'date'].year + startyear_doy / startyear_daysinyear - constantarea_years = int(t1 - startyear_decimal) - - # Mass balance calculations - (glac_bin_temp, glac_bin_prec, glac_bin_acc, glac_bin_refreeze, glac_bin_snowpack, glac_bin_melt, - glac_bin_frontalablation, glac_bin_massbalclim, glac_bin_massbalclim_annual, glac_bin_area_annual, - glac_bin_icethickness_annual, glac_bin_width_annual, glac_bin_surfacetype_annual, - glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, - glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, - offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( - massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, - width_initial, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, - glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, - option_areaconstant=option_areaconstant, constantarea_years=constantarea_years, - debug=False)) - # Option to return must melt condition - if return_tc_mustmelt == 1: - # Climatic mass balance of lowermost bin must be negative at some point - glac_bin_area_annual_mask = glac_bin_area_annual.copy() - glac_bin_area_annual_mask[glac_bin_area_annual_mask>0] = 1 - lowestbin_idx = np.argmax(glac_bin_area_annual_mask > 0, axis=0) - lowestbin_mbclim_annual = ( - glac_bin_massbalclim_annual[list(lowestbin_idx)[:-1], np.arange(0,lowestbin_idx.shape[0]-1)]) - nyears_negmbclim = np.sum([1 if x < 0 else 0 for x in lowestbin_mbclim_annual]) - return nyears_negmbclim - elif return_volremaining == 1: - # Ensure volume by end of century is zero - # Compute glacier volume change for every time step and use this to compute mass balance - glac_wide_area = glac_wide_area_annual[:-1].repeat(12) - # Mass change [km3 mwe] - # mb [mwea] * (1 km / 1000 m) * area [km2] - glac_wide_masschange = glac_wide_massbaltotal / 1000 * glac_wide_area - # Mean annual mass balance [mwea] - mb_mwea = glac_wide_masschange[t1_idx:t2_idx+1].sum() / glac_wide_area[0] * 1000 / (t2 - t1) - t2_yearidx = int(np.ceil(t2 - startyear_decimal)) - return mb_mwea, glac_wide_volume_annual[t2_yearidx] - # Return mass balance - else: - # Compute glacier volume change for every time step and use this to compute mass balance - glac_wide_area = glac_wide_area_annual[:-1].repeat(12) - # Mass change [km3 mwe] - # mb [mwea] * (1 km / 1000 m) * area [km2] - glac_wide_masschange = glac_wide_massbaltotal / 1000 * glac_wide_area - # Mean annual mass balance [mwea] - mb_mwea = glac_wide_masschange[t1_idx:t2_idx+1].sum() / glac_wide_area[0] * 1000 / (t2 - t1) - return mb_mwea - - -def retrieve_priors(modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, width_initial, - elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, - glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, debug=False): +def retrieve_priors(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, width_t0, elev_bins, + glacier_gcm_temp, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, + glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, debug=False): """ Calculate parameters for prior distributions for the MCMC analysis @@ -160,7 +87,7 @@ def retrieve_priors(modelparameters, glacier_rgi_table, glacier_area_initial, ic glacier model parameters glacier_rgi_table : pd.DataFrame table of RGI information for a particular glacier - glacier_area_initial, icethickness_initial, width_initial, elev_bins : np.arrays + glacier_area_t0, icethickness_t0, width_t0, elev_bins : np.arrays relevant glacier properties data glacier_gcm_temp, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac : np.arrays relevant glacier climate data @@ -182,12 +109,57 @@ def retrieve_priors(modelparameters, glacier_rgi_table, glacier_area_initial, ic tempchange_max_loss, tempchange_max_acc, mb_max_loss, mb_max_acc : floats temperature change and mass balance associated with maximum accumulation and maximum loss """ + def mb_mwea_calc(modelparameters, option_areaconstant=1, return_tc_mustmelt=0): + """ + Run the mass balance and calculate the mass balance [mwea] + + Parameters + ---------- + option_areaconstant : int + Switch to keep area constant (1) or not (0) + + Returns + ------- + mb_mwea : float + mass balance [m w.e. a-1] + """ + # Mass balance calculations + (glac_bin_temp, glac_bin_prec, glac_bin_acc, glac_bin_refreeze, glac_bin_snowpack, glac_bin_melt, + glac_bin_frontalablation, glac_bin_massbalclim, glac_bin_massbalclim_annual, glac_bin_area_annual, + glac_bin_icethickness_annual, glac_bin_width_annual, glac_bin_surfacetype_annual, + glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, + glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, + offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( + massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + option_areaconstant=option_areaconstant)) + # Option to return must melt condition + if return_tc_mustmelt == 1: + # Climatic mass balance of lowermost bin must be negative at some point + glac_idx = np.where(glac_bin_area_annual > 0)[0][0] + lower_massbalclim_annual = glac_bin_massbalclim_annual[glac_idx,:].tolist() + # Number of years with negative climatic mass balance + nyears_negmbclim = np.sum([1 if x < 0 else 0 for x in lower_massbalclim_annual]) + return nyears_negmbclim + + # Return mass balance + else: + # Compute glacier volume change for every time step and use this to compute mass balance + glac_wide_area = glac_wide_area_annual[:-1].repeat(12) + # Mass change [km3 mwe] + # mb [mwea] * (1 km / 1000 m) * area [km2] + glac_wide_masschange = glac_wide_massbaltotal / 1000 * glac_wide_area + # Mean annual mass balance [mwea] + mb_mwea = glac_wide_masschange[t1_idx:t2_idx+1].sum() / glac_wide_area[0] * 1000 / (t2 - t1) + return mb_mwea + # ----- TEMPBIAS: max accumulation ----- # Lower temperature bound based on max positive mass balance adjusted to avoid edge effects # Temperature at the lowest bin # T_bin = T_gcm + lr_gcm * (z_ref - z_gcm) + lr_glac * (z_bin - z_ref) + tempchange - lowest_bin = np.where(glacier_area_initial > 0)[0][0] + lowest_bin = np.where(glacier_area_t0 > 0)[0][0] tempchange_max_acc = (-1 * (glacier_gcm_temp + glacier_gcm_lrgcm * (elev_bins[lowest_bin] - glacier_gcm_elev)).max()) @@ -196,46 +168,30 @@ def retrieve_priors(modelparameters, glacier_rgi_table, glacier_area_initial, ic # ----- TEMPBIAS: UPPER BOUND ----- # MAXIMUM LOSS - AREA EVOLVING - # note: the mb_mwea_calc function ensures the area is constant until t1 such that the glacier is not completely - # lost before t1; otherwise, this will fail at high TC values - mb_max_loss = (-1 * (glacier_area_initial * icethickness_initial).sum() / glacier_area_initial.sum() * + mb_max_loss = (-1 * (glacier_area_t0 * icethickness_t0).sum() / glacier_area_t0.sum() * input.density_ice / input.density_water / (t2 - t1)) if debug: print('mb_max_loss:', np.round(mb_max_loss,2), 'precfactor:', np.round(modelparameters[2],2)) # Looping forward and backward to ensure optimization does not get stuck - modelparameters[7] = tempchange_max_acc - mb_mwea_1, vol_remaining = mb_mwea_calc( - modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, width_initial, elev_bins, - glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, - glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, - option_areaconstant=0, return_volremaining=1) - + modelparameters[7] = tempchange_max_acc + mb_mwea_1 = mb_mwea_calc(modelparameters, option_areaconstant=0) # use absolute value because with area evolving the maximum value is a limit - while vol_remaining > 0: - modelparameters[7] = modelparameters[7] + 1 - mb_mwea_1, vol_remaining = mb_mwea_calc( - modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, width_initial, - elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, - glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, - option_areaconstant=0, return_volremaining=1) + while mb_mwea_1 - mb_max_loss > 0: + modelparameters[7] = modelparameters[7] + 1 + mb_mwea_1 = mb_mwea_calc(modelparameters, option_areaconstant=0) if debug: - print('mb_mwea_1:', np.round(mb_mwea_1,2), 'TC:', np.round(modelparameters[7],2), - 'mb_max_loss:', np.round(mb_max_loss,2), 'vol_left:', np.round(vol_remaining,4)) + print('mb_mwea_1:', np.round(mb_mwea_1,2), 'TC:', np.round(modelparameters[7],2)) + # Looping backward for tempchange at max loss - while vol_remaining == 0: - modelparameters[7] = modelparameters[7] - 0.05 - mb_mwea_1, vol_remaining = mb_mwea_calc( - modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, width_initial, - elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, - glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, - option_areaconstant=0, return_volremaining=1) + while mb_mwea_1 - mb_max_loss < 0.01: + modelparameters[7] = modelparameters[7] - input.tempchange_step + mb_mwea_1 = mb_mwea_calc(modelparameters, option_areaconstant=0) if debug: - print('vol_left:', np.round(vol_remaining,4), 'mb_mwea_1:', np.round(mb_mwea_1,2), - 'TC:', np.round(modelparameters[7],2)) + print('mb_mwea_1:', np.round(mb_mwea_1,2), 'TC:', np.round(modelparameters[7],2)) tempchange_max_loss = modelparameters[7] tempchange_boundhigh = tempchange_max_loss @@ -248,40 +204,15 @@ def retrieve_priors(modelparameters, glacier_rgi_table, glacier_area_initial, ic # temperature biases still have 0 for nyears_negmbclim. Hence, the need to loop beyond the first instance, and # then go back and check that you're using the good cases from there onward. This ensures starting point is good modelparameters[7] = tempchange_max_acc - nyears_negmbclim = mb_mwea_calc( - modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, width_initial, - elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, - glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, - option_areaconstant=0, return_tc_mustmelt=1) - + nyears_negmbclim = mb_mwea_calc(modelparameters, option_areaconstant=0, return_tc_mustmelt=1) nyears_negmbclim_list = [nyears_negmbclim] tc_negmbclim_list = [modelparameters[7]] - tc_smallstep_switch = False while nyears_negmbclim < 10 and modelparameters[7] < tempchange_max_loss: - # Switch from large to small step sizes to speed up calculations - if tc_smallstep_switch == False: - tc_stepsize = 1 - else: - tc_stepsize = 0.05 - - modelparameters_old = modelparameters[7] - modelparameters[7] += tc_stepsize - nyears_negmbclim = mb_mwea_calc( - modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, width_initial, - elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, - glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, - option_areaconstant=0, return_tc_mustmelt=1) - - # Record if using big step and no there is no melt or if using small step and there is melt - if nyears_negmbclim == 0 or (nyears_negmbclim > 0 and tc_smallstep_switch == True): - nyears_negmbclim_list.append(nyears_negmbclim) - tc_negmbclim_list.append(modelparameters[7]) - - # First time nyears_negmbclim is > 0, flip the switch to use smalll step and restart with last tempchange - if nyears_negmbclim > 0 and tc_smallstep_switch == False: - tc_smallstep_switch = True - modelparameters[7] = modelparameters_old - nyears_negmbclim = 0 + modelparameters[7] += 0.05 +# modelparameters[7] += input.tempchange_step + nyears_negmbclim = mb_mwea_calc(modelparameters, option_areaconstant=0, return_tc_mustmelt=1) + nyears_negmbclim_list.append(nyears_negmbclim) + tc_negmbclim_list.append(modelparameters[7]) if debug: print('TC:', np.round(modelparameters[7],2), 'nyears_negmbclim:', nyears_negmbclim) @@ -313,11 +244,10 @@ def main(list_packed_vars): main_glac_icethickness = list_packed_vars[4] main_glac_width = list_packed_vars[5] gcm_temp = list_packed_vars[6] - gcm_tempstd = list_packed_vars[7] - gcm_prec = list_packed_vars[8] - gcm_elev = list_packed_vars[9] - gcm_lr = list_packed_vars[10] - cal_data = list_packed_vars[11] + gcm_prec = list_packed_vars[7] + gcm_elev = list_packed_vars[8] + gcm_lr = list_packed_vars[9] + cal_data = list_packed_vars[10] time_start = time.time() parser = getparser() @@ -328,6 +258,13 @@ def main(list_packed_vars): else: debug = False + # RGI region + print('\n\nDELETE ME!\n\n') + if args.spc_region is not None: + rgi_regionsO1 = [int(args.spc_region)] + else: + rgi_regionsO1 = input.rgi_regionsO1 + # ===== CALIBRATION ===== # Option 2: use MCMC method to determine posterior probability distributions of the three parameters tempchange, # ddfsnow and precfactor. Then create an ensemble of parameter sets evenly sampled from these @@ -512,10 +449,9 @@ def massbal(tempchange=tempchange, precfactor=precfactor, ddfsnow=ddfsnow): glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( - massbalance.runmassbalance(modelparameters_copy, glacier_rgi_table, glacier_area_initial, - icethickness_initial, width_initial, elev_bins, glacier_gcm_temp, - glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, - glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + massbalance.runmassbalance(modelparameters_copy, glacier_rgi_table, glacier_area_t0, + icethickness_t0, width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, option_areaconstant=0)) # Compute glacier volume change for every time step and use this to compute mass balance glac_wide_area = glac_wide_area_annual[:-1].repeat(12) @@ -559,10 +495,9 @@ def must_melt(tempchange=tempchange, precfactor=precfactor, ddfsnow=ddfsnow): glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( - massbalance.runmassbalance(modelparameters_copy, glacier_rgi_table, glacier_area_initial, - icethickness_initial, width_initial, elev_bins, glacier_gcm_temp, - glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, - glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + massbalance.runmassbalance(modelparameters_copy, glacier_rgi_table, glacier_area_t0, + icethickness_t0, width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, option_areaconstant=0)) # Climatic mass balance of lowermost bin must be negative at some point glac_idx = np.where(glac_bin_area_annual > 0)[0][0] @@ -574,6 +509,16 @@ def must_melt(tempchange=tempchange, precfactor=precfactor, ddfsnow=ddfsnow): else: return -np.inf + # Alternative ensuring that melt occurs +# # Total melt [km3] +# glac_bin_area = glac_bin_area_annual[:,:-1].repeat(12, axis=1) +# total_melt = (glac_bin_melt * glac_bin_area).sum() +# if total_melt == 0: +# return -np.inf +# else: +# return 0 + + # ===== OBSERVED DATA ===== # Observed data defines the observed likelihood of mass balances (based on geodetic observations) obs_massbal = pymc.Normal('obs_massbal', mu=massbal, tau=(1/(observed_error**2)), @@ -581,6 +526,8 @@ def must_melt(tempchange=tempchange, precfactor=precfactor, ddfsnow=ddfsnow): # Set model if use_potentials == 1: +# model = pymc.MCMC([{'precfactor':precfactor, 'tempchange':tempchange, 'ddfsnow':ddfsnow, +# 'massbal':massbal, 'obs_massbal':obs_massbal}, mb_max]) model = pymc.MCMC([{'precfactor':precfactor, 'tempchange':tempchange, 'ddfsnow':ddfsnow, 'massbal':massbal, 'obs_massbal':obs_massbal}, mb_max, must_melt]) else: @@ -627,14 +574,13 @@ def must_melt(tempchange=tempchange, precfactor=precfactor, ddfsnow=ddfsnow): glacier_gcm_elev = gcm_elev[glac] glacier_gcm_prec = gcm_prec[glac,:] glacier_gcm_temp = gcm_temp[glac,:] - glacier_gcm_tempstd = gcm_tempstd[glac,:] glacier_gcm_lrgcm = gcm_lr[glac,:] glacier_gcm_lrglac = glacier_gcm_lrgcm.copy() - glacier_area_initial = main_glac_hyps.iloc[glac,:].values.astype(float) - icethickness_initial = main_glac_icethickness.iloc[glac,:].values.astype(float) - width_initial = main_glac_width.iloc[glac,:].values.astype(float) + glacier_area_t0 = main_glac_hyps.iloc[glac,:].values.astype(float) + icethickness_t0 = main_glac_icethickness.iloc[glac,:].values.astype(float) + width_t0 = main_glac_width.iloc[glac,:].values.astype(float) glacier_cal_data = ((cal_data.iloc[np.where( - glacier_rgi_table['rgino_str'] == cal_data['glacno'])[0],:]).copy()) + glacier_rgi_table[input.rgi_O1Id_colname] == cal_data['glacno'])[0],:]).copy()) glacier_str = '{0:0.5f}'.format(glacier_rgi_table['RGIId_float']) # Select observed mass balance, error, and time data @@ -652,7 +598,7 @@ def must_melt(tempchange=tempchange, precfactor=precfactor, ddfsnow=ddfsnow): print('observed_massbal:', np.round(observed_massbal,2), 'observed_error:',np.round(observed_error,2)) # ===== RUN MARKOV CHAIN MONTE CARLO METHOD ==================== - if icethickness_initial.max() > 0: + if icethickness_t0.max() > 0: # Regional priors precfactor_gamma_alpha = input.precfactor_gamma_region_dict[glacier_rgi_table.loc['region']][0] @@ -691,10 +637,10 @@ def must_melt(tempchange=tempchange, precfactor=precfactor, ddfsnow=ddfsnow): modelparameters[5] = ddfsnow_start / input.ddfsnow_iceratio tempchange_boundlow, tempchange_boundhigh, mb_max_loss = ( - retrieve_priors(modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, - width_initial, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, - glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, - dates_table, t1_idx, t2_idx, t1, t2, debug=False)) + retrieve_priors(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + t1_idx, t2_idx, t1, t2, debug=False)) if debug: print('\nTC_low:', np.round(tempchange_boundlow,2), @@ -803,10 +749,10 @@ def objective(modelparameters_subset): glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( - massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, - icethickness_initial, width_initial, elev_bins, glacier_gcm_temp, - glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, - glacier_gcm_lrglac, dates_table, option_areaconstant=1)) + massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + option_areaconstant=1)) # Use a subset of model parameters to reduce number of constraints required modelparameters[2] = modelparameters_subset[0] modelparameters[3] = modelparameters_subset[1] @@ -820,10 +766,10 @@ def objective(modelparameters_subset): glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( - massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, - icethickness_initial, width_initial, elev_bins, glacier_gcm_temp, - glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, - glacier_gcm_lrglac, dates_table, option_areaconstant=1)) + massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + option_areaconstant=1)) # Compute glacier volume change for every time step and use this to compute mass balance glac_wide_area = glac_wide_area_annual[:-1].repeat(12) # Mass change [km3 mwe] @@ -900,8 +846,8 @@ def run_objective(modelparameters_init, observed_massbal, precfactor_bnds=(0.33, glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( - massbalance.runmassbalance(modelparams, glacier_rgi_table, glacier_area_initial, icethickness_initial, - width_initial, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, + massbalance.runmassbalance(modelparams, glacier_rgi_table, glacier_area_t0, icethickness_t0, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, option_areaconstant=1)) # Compute glacier volume change for every time step and use this to compute mass balance @@ -993,14 +939,13 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, mb_mwea, observed_m glacier_gcm_elev = gcm_elev[glac] glacier_gcm_prec = gcm_prec[glac,:] glacier_gcm_temp = gcm_temp[glac,:] - glacier_gcm_tempstd = gcm_tempstd[glac,:] glacier_gcm_lrgcm = gcm_lr[glac,:] glacier_gcm_lrglac = glacier_gcm_lrgcm.copy() - glacier_area_initial = main_glac_hyps.iloc[glac,:].values.astype(float) - icethickness_initial = main_glac_icethickness.iloc[glac,:].values.astype(float) - width_initial = main_glac_width.iloc[glac,:].values.astype(float) + glacier_area_t0 = main_glac_hyps.iloc[glac,:].values.astype(float) + icethickness_t0 = main_glac_icethickness.iloc[glac,:].values.astype(float) + width_t0 = main_glac_width.iloc[glac,:].values.astype(float) glacier_cal_data = ((cal_data.iloc[np.where( - glacier_rgi_table['rgino_str'] == cal_data['glacno'])[0],:]).copy()) + glacier_rgi_table[input.rgi_O1Id_colname] == cal_data['glacno'])[0],:]).copy()) glacier_str = '{0:0.5f}'.format(glacier_rgi_table['RGIId_float']) # Select observed mass balance, error, and time data @@ -1054,7 +999,7 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, mb_mwea, observed_m # Lower temperature bound based on no positive temperatures # Temperature at the lowest bin # T_bin = T_gcm + lr_gcm * (z_ref - z_gcm) + lr_glac * (z_bin - z_ref) + tempchange - lowest_bin = np.where(glacier_area_initial > 0)[0][0] + lowest_bin = np.where(glacier_area_t0 > 0)[0][0] tempchange_max_acc = (-1 * (glacier_gcm_temp + glacier_gcm_lrgcm * (elev_bins[lowest_bin] - glacier_gcm_elev)).max()) tempchange_bndlow = tempchange_max_acc @@ -1113,185 +1058,146 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, mb_mwea, observed_m # - precipitaiton factor, then temperature bias (no ddfsnow) # - ranges different elif input.option_calibration == 4: - - if input.params2opt.sort() == ['tempbias', 'precfactor'].sort(): - def objective(modelparameters_subset): - """ - Objective function for mass balance data. - - Parameters - ---------- - modelparameters_subset : np.float64 - List of model parameters to calibrate - [precipitation factor, precipitation gradient, degree-day factor of snow, temperature bias] - - Returns - ------- - mb_dif_mwea - Returns the difference in modeled vs observed mass balance [mwea] - """ - # Use a subset of model parameters to reduce number of constraints required - modelparameters[2] = modelparameters_subset[0] - modelparameters[7] = modelparameters_subset[1] - # Mass balance calculation - mb_mwea = mb_mwea_calc( - modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, width_initial, - elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, - glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, option_areaconstant=0) - print('model params:', modelparameters[2], modelparameters[7], - '\n mb_mwea:', mb_mwea) - # Difference [mwea] - mb_dif_mwea_abs = abs(observed_massbal - mb_mwea) - return mb_dif_mwea_abs - - def run_objective(modelparameters_init, observed_massbal, precfactor_bnds=(0.33,3), tempchange_bnds=(-10,10), - run_opt=True, eps_opt=input.eps_opt, ftol_opt=input.ftol_opt): - """ - Run the optimization for the single glacier objective function. - - Parameters - ---------- - modelparams_init : list - List of model parameters to calibrate - [precipitation factor, precipitation gradient, degree day factor of snow, temperature change] - glacier_cal_data : pd.DataFrame - Table containing calibration data for a single glacier - precfactor_bnds : tuple - Lower and upper bounds for precipitation factor (default is (0.33, 3)) - tempchange_bnds : tuple - Lower and upper bounds for temperature bias (default is (0.33, 3)) - ddfsnow_bnds : tuple - Lower and upper bounds for degree day factor of snow (default is (0.0026, 0.0056)) - precgrad_bnds : tuple - Lower and upper bounds for precipitation gradient (default is constant (0.0001,0.0001)) - run_opt : boolean - Boolean statement allowing one to bypass the optimization and run through with initial parameters - (default is True - run the optimization) - - Returns - ------- - modelparameters_opt : optimize.optimize.OptimizeResult - Returns result of scipy optimization, which includes optimized parameters and other information - glacier_cal_compare : pd.DataFrame - Table recapping calibration results: observation, model, calibration round, etc. - """ - # Bounds - modelparameters_bnds = (precfactor_bnds, tempchange_bnds) - # Run the optimization - # 'L-BFGS-B' - much slower - # 'SLSQP' did not work for some geodetic measurements using the sum_abs_zscore. One work around was to - # divide the sum_abs_zscore by 1000, which made it work in all cases. However, methods were switched - # to 'L-BFGS-B', which may be slower, but is still effective. - # note: switch enables running through with given parameters - if run_opt: - modelparameters_opt = minimize(objective, modelparameters_init, method=input.method_opt, - bounds=modelparameters_bnds, - options={'ftol':ftol_opt, 'eps':eps_opt}) - # Record the optimized parameters - modelparameters_subset = modelparameters_opt.x - else: - modelparameters_subset = modelparameters_init.copy() - modelparams = ( - [modelparameters[0], modelparameters[1], modelparameters_subset[0], modelparameters[3], - modelparameters[4], modelparameters[4] / ddfsnow_iceratio, modelparameters[6], - modelparameters_subset[1]]) - # Re-run the optimized parameters in order to see the mass balance - mb_mwea = mb_mwea_calc( - modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, width_initial, - elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, - glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, option_areaconstant=0) - return modelparams, mb_mwea - else: - def objective(modelparameters_subset): - """ - Objective function for mass balance data. - - Parameters - ---------- - modelparameters_subset : np.float64 - List of model parameters to calibrate - [precipitation factor, precipitation gradient, degree-day factor of snow, temperature bias] - - Returns - ------- - mb_dif_mwea - Returns the difference in modeled vs observed mass balance [mwea] - """ - # Use a subset of model parameters to reduce number of constraints required - modelparameters[2] = modelparameters_subset[0] - modelparameters[3] = modelparameters_subset[1] - modelparameters[4] = modelparameters_subset[2] - modelparameters[5] = modelparameters[4] / ddfsnow_iceratio - modelparameters[7] = modelparameters_subset[3] - # Mass balance calculation - mb_mwea = mb_mwea_calc( - modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, width_initial, - elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, - glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, option_areaconstant=0) - print('model params:', modelparameters[2], modelparameters[7], - '\n mb_mwea:', mb_mwea) - # Difference [mwea] - mb_dif_mwea_abs = abs(observed_massbal - mb_mwea) - return mb_dif_mwea_abs - - def run_objective(modelparameters_init, observed_massbal, precfactor_bnds=(0.33,3), tempchange_bnds=(-10,10), - ddfsnow_bnds=(0.0026,0.0056), precgrad_bnds=(0.0001,0.0001), run_opt=True, - eps_opt=input.eps_opt): - """ - Run the optimization for the single glacier objective function. - - Parameters - ---------- - modelparams_init : list - List of model parameters to calibrate - [precipitation factor, precipitation gradient, degree day factor of snow, temperature change] - glacier_cal_data : pd.DataFrame - Table containing calibration data for a single glacier - precfactor_bnds : tuple - Lower and upper bounds for precipitation factor (default is (0.33, 3)) - tempchange_bnds : tuple - Lower and upper bounds for temperature bias (default is (0.33, 3)) - ddfsnow_bnds : tuple - Lower and upper bounds for degree day factor of snow (default is (0.0026, 0.0056)) - precgrad_bnds : tuple - Lower and upper bounds for precipitation gradient (default is constant (0.0001,0.0001)) - run_opt : boolean - Boolean statement allowing one to bypass the optimization and run through with initial parameters - (default is True - run the optimization) - - Returns - ------- - modelparameters_opt : optimize.optimize.OptimizeResult - Returns result of scipy optimization, which includes optimized parameters and other information - glacier_cal_compare : pd.DataFrame - Table recapping calibration results: observation, model, calibration round, etc. - """ - # Bounds - modelparameters_bnds = (precfactor_bnds, precgrad_bnds, ddfsnow_bnds, tempchange_bnds) - # Run the optimization - # 'L-BFGS-B' - much slower - # 'SLSQP' did not work for some geodetic measurements using the sum_abs_zscore. One work around was to - # divide the sum_abs_zscore by 1000, which made it work in all cases. However, methods were switched - # to 'L-BFGS-B', which may be slower, but is still effective. - # note: switch enables running through with given parameters - if run_opt: - modelparameters_opt = minimize(objective, modelparameters_init, method=input.method_opt, - bounds=modelparameters_bnds, - options={'ftol':input.ftol_opt, 'eps':eps_opt}) - # Record the optimized parameters - modelparameters_subset = modelparameters_opt.x - else: - modelparameters_subset = modelparameters_init.copy() - modelparams = ( - [modelparameters[0], modelparameters[1], modelparameters_subset[0], modelparameters_subset[1], - modelparameters_subset[2], modelparameters_subset[2] / ddfsnow_iceratio, modelparameters[6], - modelparameters_subset[3]]) - # Re-run the optimized parameters in order to see the mass balance - mb_mwea = mb_mwea_calc( - modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, width_initial, - elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, - glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, option_areaconstant=0) - return modelparams, mb_mwea + #%% + def mb_mwea_calc(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, width_t0, elev_bins, + glacier_gcm_temp, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, + glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, option_areaconstant=0): + """ + Run the mass balance and calculate the mass balance [mwea] + + Parameters + ---------- + option_areaconstant : int + Switch to keep area constant (1) or not (0) + + Returns + ------- + mb_mwea : float + mass balance [m w.e. a-1] + """ + # Mass balance calculations + (glac_bin_temp, glac_bin_prec, glac_bin_acc, glac_bin_refreeze, glac_bin_snowpack, glac_bin_melt, + glac_bin_frontalablation, glac_bin_massbalclim, glac_bin_massbalclim_annual, glac_bin_area_annual, + glac_bin_icethickness_annual, glac_bin_width_annual, glac_bin_surfacetype_annual, + glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, + glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, + offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( + massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + option_areaconstant=option_areaconstant)) + # Compute glacier volume change for every time step and use this to compute mass balance + glac_wide_area = glac_wide_area_annual[:-1].repeat(12) + # Mass change [km3 mwe] + # mb [mwea] * (1 km / 1000 m) * area [km2] + glac_wide_masschange = glac_wide_massbaltotal / 1000 * glac_wide_area + # Mean annual mass balance [mwea] + mb_mwea = glac_wide_masschange[t1_idx:t2_idx+1].sum() / glac_wide_area[0] * 1000 / (t2 - t1) + return mb_mwea + + def objective(modelparameters_subset): + """ + Objective function for mass balance data. + + Parameters + ---------- + modelparameters_subset : np.float64 + List of model parameters to calibrate + [precipitation factor, precipitation gradient, degree-day factor of snow, temperature bias] + + Returns + ------- + mb_dif_mwea + Returns the difference in modeled vs observed mass balance [mwea] + """ + # Use a subset of model parameters to reduce number of constraints required + modelparameters[2] = modelparameters_subset[0] + modelparameters[3] = modelparameters_subset[1] + modelparameters[4] = modelparameters_subset[2] + modelparameters[5] = modelparameters[4] / ddfsnow_iceratio + modelparameters[7] = modelparameters_subset[3] + # Mass balance calculations + mb_mwea = mb_mwea_calc(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, width_t0, + elev_bins, glacier_gcm_temp, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, + glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, option_areaconstant=0) + # Difference [mwea] + mb_dif_mwea_abs = abs(observed_massbal - mb_mwea) + return mb_dif_mwea_abs + + + def run_objective(modelparameters_init, observed_massbal, precfactor_bnds=(0.33,3), tempchange_bnds=(-10,10), + ddfsnow_bnds=(0.0026,0.0056), precgrad_bnds=(0.0001,0.0001), run_opt=True): + """ + Run the optimization for the single glacier objective function. + + Parameters + ---------- + modelparams_init : list + List of model parameters to calibrate + [precipitation factor, precipitation gradient, degree day factor of snow, temperature change] + glacier_cal_data : pd.DataFrame + Table containing calibration data for a single glacier + precfactor_bnds : tuple + Lower and upper bounds for precipitation factor (default is (0.33, 3)) + tempchange_bnds : tuple + Lower and upper bounds for temperature bias (default is (0.33, 3)) + ddfsnow_bnds : tuple + Lower and upper bounds for degree day factor of snow (default is (0.0026, 0.0056)) + precgrad_bnds : tuple + Lower and upper bounds for precipitation gradient (default is constant (0.0001,0.0001)) + run_opt : boolean + Boolean statement allowing one to bypass the optimization and run through with initial parameters + (default is True - run the optimization) + + Returns + ------- + modelparameters_opt : optimize.optimize.OptimizeResult + Returns result of scipy optimization, which includes optimized parameters and other information + glacier_cal_compare : pd.DataFrame + Table recapping calibration results: observation, model, calibration round, etc. + """ + # Bounds + modelparameters_bnds = (precfactor_bnds, precgrad_bnds, ddfsnow_bnds, tempchange_bnds) + # Run the optimization + # 'L-BFGS-B' - much slower + # 'SLSQP' did not work for some geodetic measurements using the sum_abs_zscore. One work around was to + # divide the sum_abs_zscore by 1000, which made it work in all cases. However, methods were switched + # to 'L-BFGS-B', which may be slower, but is still effective. + # note: switch enables running through with given parameters + if run_opt: + modelparameters_opt = minimize(objective, modelparameters_init, method=input.method_opt, + bounds=modelparameters_bnds, options={'ftol':input.ftol_opt}) + # Record the optimized parameters + modelparameters_subset = modelparameters_opt.x + else: + modelparameters_subset = modelparameters_init.copy() + modelparams = ( + [modelparameters[0], modelparameters[1], modelparameters_subset[0], modelparameters_subset[1], + modelparameters_subset[2], modelparameters_subset[2] / ddfsnow_iceratio, modelparameters[6], + modelparameters_subset[3]]) + # Re-run the optimized parameters in order to see the mass balance + # Mass balance calculations + (glac_bin_temp, glac_bin_prec, glac_bin_acc, glac_bin_refreeze, glac_bin_snowpack, glac_bin_melt, + glac_bin_frontalablation, glac_bin_massbalclim, glac_bin_massbalclim_annual, glac_bin_area_annual, + glac_bin_icethickness_annual, glac_bin_width_annual, glac_bin_surfacetype_annual, + glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, + glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, + offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( + massbalance.runmassbalance(modelparams, glacier_rgi_table, glacier_area_t0, icethickness_t0, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + option_areaconstant=0)) + # Compute glacier volume change for every time step and use this to compute mass balance + glac_wide_area = glac_wide_area_annual[:-1].repeat(12) + # Mass change [km3 mwe] + # mb [mwea] * (1 km / 1000 m) * area [km2] + glac_wide_masschange = glac_wide_massbaltotal[t1_idx:t2_idx+1] / 1000 * glac_wide_area[t1_idx:t2_idx+1] + # Mean annual mass balance [mwea] + mb_mwea = (glac_wide_masschange.sum() / glac_wide_area[0] * 1000 / + (glac_wide_masschange.shape[0] / 12)) + + return modelparams, mb_mwea + def write_netcdf_modelparams(output_fullfn, modelparameters, mb_mwea, observed_massbal): """ @@ -1358,14 +1264,13 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, mb_mwea, observed_m glacier_gcm_elev = gcm_elev[glac] glacier_gcm_prec = gcm_prec[glac,:] glacier_gcm_temp = gcm_temp[glac,:] - glacier_gcm_tempstd = gcm_tempstd[glac,:] glacier_gcm_lrgcm = gcm_lr[glac,:] glacier_gcm_lrglac = glacier_gcm_lrgcm.copy() - glacier_area_initial = main_glac_hyps.iloc[glac,:].values.astype(float) - icethickness_initial = main_glac_icethickness.iloc[glac,:].values.astype(float) - width_initial = main_glac_width.iloc[glac,:].values.astype(float) + glacier_area_t0 = main_glac_hyps.iloc[glac,:].values.astype(float) + icethickness_t0 = main_glac_icethickness.iloc[glac,:].values.astype(float) + width_t0 = main_glac_width.iloc[glac,:].values.astype(float) glacier_cal_data = ((cal_data.iloc[np.where( - glacier_rgi_table['rgino_str'] == cal_data['glacno'])[0],:]).copy()) + glacier_rgi_table[input.rgi_O1Id_colname] == cal_data['glacno'])[0],:]).copy()) glacier_str = '{0:0.5f}'.format(glacier_rgi_table['RGIId_float']) # Select observed mass balance, error, and time data @@ -1377,21 +1282,18 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, mb_mwea, observed_m t2_idx = int(glacier_cal_data.loc[cal_idx,'t2_idx']) # Observed mass balance [mwea] observed_massbal = glacier_cal_data.loc[cal_idx,'mb_mwe'] / (t2 - t1) -# observed_massbal_err = glacier_cal_data.loc[cal_idx,'mb_mwe_err'] / (t2 - t1) if debug: print('obs_mwea:', np.round(observed_massbal,2)) - if icethickness_initial.max() > 0: + if icethickness_t0.max() > 0: # Temperature bias bounds and maximum mass loss tempchange_boundlow, tempchange_boundhigh, mb_max_loss = ( - retrieve_priors(modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, - width_initial, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, - glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, - dates_table, t1_idx, t2_idx, t1, t2, - debug=True - )) + retrieve_priors(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + t1_idx, t2_idx, t1, t2)) if debug: print('\nTC_low:', np.round(tempchange_boundlow,2), 'TC_high:', np.round(tempchange_boundhigh,2), 'mb_max_loss:', np.round(mb_max_loss,2)) @@ -1418,11 +1320,13 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, mb_mwea, observed_m tc_bndhigh_opt = tempchange_init # Constrain bounds of precipitation factor and temperature bias - mb_mwea = mb_mwea_calc( - modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, - width_initial, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, - glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, - t2, option_areaconstant=0) + mb_mwea = mb_mwea_calc(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, width_t0, + elev_bins, glacier_gcm_temp, glacier_gcm_prec, glacier_gcm_elev, + glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, + option_areaconstant=0) + + if glacier_str == '14.00006': + debug=True if debug: print('\nTC:', np.round(modelparameters[7],2), 'PF:', np.round(modelparameters[2],2), @@ -1444,11 +1348,11 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, mb_mwea, observed_m print(modelparameters[2], precfactor_boundlow, precfactor_boundhigh) while mb_mwea > observed_massbal and test_count < 50: - mb_mwea = mb_mwea_calc( - modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, - width_initial, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, - glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, - t1, t2, option_areaconstant=0) + + mb_mwea = mb_mwea_calc(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, width_t0, + elev_bins, glacier_gcm_temp, glacier_gcm_prec, glacier_gcm_elev, + glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, + option_areaconstant=0) if debug: print('\nTC:', np.round(modelparameters[7],2), 'PF:', np.round(modelparameters[2],2), @@ -1460,6 +1364,8 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, mb_mwea, observed_m modelparameters[7] += tc_step test_count += 1 + +# pf_init = 0.76 pf_init = np.mean([precfactor_boundlow, precfactor_boundhigh]) else: @@ -1472,11 +1378,11 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, mb_mwea, observed_m modelparameters[2] = precfactor_boundhigh while mb_mwea < observed_massbal and test_count < 20: - mb_mwea = mb_mwea_calc( - modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial, - width_initial, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec, - glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, - t2_idx, t1, t2, option_areaconstant=0) + + mb_mwea = mb_mwea_calc(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, width_t0, + elev_bins, glacier_gcm_temp, glacier_gcm_prec, glacier_gcm_elev, + glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, t2_idx, t1, t2, + option_areaconstant=0) if debug: print('\nTC:', np.round(modelparameters[7],2), 'PF:', np.round(modelparameters[2],2), @@ -1491,95 +1397,58 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, mb_mwea, observed_m pf_init = np.mean([precfactor_boundlow, precfactor_boundhigh]) # ===== RUN OPTIMIZATION WITH CONSTRAINED BOUNDS ===== - if input.params2opt.sort() == ['tempbias', 'precfactor'].sort(): - # Temperature change bounds - tempchange_bnds = (tc_bndlow_opt, tc_bndhigh_opt) - precfactor_bnds = (precfactor_boundlow, precfactor_boundhigh) - tc_init = np.mean([tc_bndlow_opt, tc_bndhigh_opt]) - pf_init = pf_init - - modelparameters_subset = [pf_init, tc_init] - modelparams, mb_mwea = run_objective(modelparameters_subset, observed_massbal, - precfactor_bnds=precfactor_bnds, - tempchange_bnds=tempchange_bnds) - pf_opt = modelparams[2] - tc_opt = modelparams[7] - if debug: - print('\nmb_mwea:', np.round(mb_mwea,2), 'obs_mb:', np.round(observed_massbal,2), - '\nPF:', np.round(pf_opt,2), 'TC:', np.round(tc_opt,2)) - - # Epsilon (the amount the variable change to calculate the jacobian) can be too small, which causes - # the minimization to believe it has reached a local minima and stop. Therefore, adjust epsilon - # to ensure this is not the case. - eps_opt_new = input.eps_opt - ftol_opt_new = input.ftol_opt - nround = 0 - while np.absolute(mb_mwea - observed_massbal) > 0.1 and eps_opt_new <= 0.1: - nround += 1 - if debug: - print('DIDNT WORK SO TRYING NEW INITIAL CONDITIONS') - print(' old eps_opt:', eps_opt_new) - - eps_opt_new = eps_opt_new * 10 - if debug: - print(' new eps_opt:', eps_opt_new) - - modelparameters_subset = [pf_init, tc_init] - modelparams, mb_mwea = run_objective(modelparameters_subset, observed_massbal, - precfactor_bnds=precfactor_bnds, - tempchange_bnds=tempchange_bnds, - eps_opt=eps_opt_new, ftol_opt=ftol_opt_new) - pf_opt = modelparams[2] - tc_opt = modelparams[7] - if debug: - print('\nmb_mwea:', np.round(mb_mwea,2), 'obs_mb:', np.round(observed_massbal,2), - '\nPF:', np.round(pf_opt,2), 'TC:', np.round(tc_opt,2)) - else: - # Temperature change bounds - tempchange_bnds = (tc_bndlow_opt, tc_bndhigh_opt) - precfactor_bnds = (precfactor_boundlow, precfactor_boundhigh) - ddfsnow_bnds = (ddfsnow_init, ddfsnow_init) - tc_init = np.mean([tc_bndlow_opt, tc_bndhigh_opt]) - pf_init = pf_init - - modelparameters_subset = [pf_init, modelparameters[3], modelparameters[4], tc_init] - modelparams, mb_mwea = run_objective(modelparameters_subset, observed_massbal, - precfactor_bnds=precfactor_bnds, - tempchange_bnds=tempchange_bnds, - ddfsnow_bnds=ddfsnow_bnds) - pf_opt = modelparams[2] - tc_opt = modelparams[7] - if debug: - print('\nmb_mwea:', np.round(mb_mwea,2), 'obs_mb:', np.round(observed_massbal,2), - '\nPF:', np.round(pf_opt,2), 'TC:', np.round(tc_opt,2)) - - # Epsilon (the amount the variable change to calculate the jacobian) can be too small, which causes - # the minimization to believe it has reached a local minima and stop. Therefore, adjust epsilon - # to ensure this is not the case. - eps_opt_new = input.eps_opt - nround = 0 - while np.absolute(mb_mwea - observed_massbal) > 0.3 and eps_opt_new <= 0.1: - nround += 1 - if debug: - print('DIDNT WORK SO TRYING NEW INITIAL CONDITIONS') - print(' old eps_opt:', eps_opt_new) - - eps_opt_new = eps_opt_new * 10 - if debug: - print(' new eps_opt:', eps_opt_new) - - modelparameters_subset = [pf_init, modelparameters[3], modelparameters[4], tc_init] - modelparams, mb_mwea = run_objective(modelparameters_subset, observed_massbal, - precfactor_bnds=precfactor_bnds, - tempchange_bnds=tempchange_bnds, - ddfsnow_bnds=ddfsnow_bnds, - eps_opt = eps_opt_new) - pf_opt = modelparams[2] - tc_opt = modelparams[7] - if debug: - print('\nmb_mwea:', np.round(mb_mwea,2), 'obs_mb:', np.round(observed_massbal,2), - '\nPF:', np.round(pf_opt,2), 'TC:', np.round(tc_opt,2)) + # Temperature change bounds + tempchange_bnds = (tc_bndlow_opt, tc_bndhigh_opt) + precfactor_bnds = (precfactor_boundlow, precfactor_boundhigh) + ddfsnow_bnds = (ddfsnow_init, ddfsnow_init) + tc_init = np.mean([tc_bndlow_opt, tc_bndhigh_opt]) + pf_init = pf_init + + modelparameters_subset = [pf_init, modelparameters[3], modelparameters[4], tc_init] + + modelparams, mb_mwea = run_objective(modelparameters_subset, observed_massbal, + precfactor_bnds=precfactor_bnds, + tempchange_bnds=tempchange_bnds, + ddfsnow_bnds=ddfsnow_bnds) + + pf_opt = modelparams[2] + tc_opt = modelparams[7] + + if debug: + print('\nmb_mwea:', np.round(mb_mwea,2), 'obs_mb:', np.round(observed_massbal,2), + '\nPF:', np.round(pf_opt,2), 'TC:', np.round(tc_opt,2)) + +# # ===== ITERATIVELY ADJUST PRECIPITATION FACTOR AND TEMPERATURE BIAS TOGETHER ===== +# cal_rounds = 10 +# tempchange_step = 0.5 +# round_count = 0 +# precfactor_bnds = (precfactor_boundlow, precfactor_boundhigh) +# ddfsnow_bnds = (ddfsnow_init, ddfsnow_init) +# tempchange_bndhigh_opt = tempchange_init +# tempchange_bndlow_opt = tempchange_init +# while (round_count < cal_rounds and abs(mb_mwea - observed_massbal) > 0.01 and +# tempchange_bndhigh_opt <= tempchange_boundhigh and +# tempchange_bndlow_opt >= tempchange_boundlow): +# + +# # Update optimized parameters +# precfactor_opt = modelparams[2] +# tempchange_opt = modelparams[7] +# modelparameters[2] = precfactor_opt +# +# # Update bounds and initial guess for temperature bias +# if mb_mwea > observed_massbal: +# tempchange_bndhigh_opt += tempchange_step +# modelparameters[7] = tempchange_opt + tempchange_step / 2 +# else: +# tempchange_bndlow_opt -= tempchange_step +# modelparameters[7] = tempchange_opt - tempchange_step / 2 +# +# # Increase round +# round_count += 1 + + #%% modelparameters[2] = pf_opt modelparameters[7] = tc_opt @@ -1587,6 +1456,7 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, mb_mwea, observed_m mb_mwea = 0 + # EXPORT TO NETCDF netcdf_output_fp = (input.output_fp_cal) if not os.path.exists(netcdf_output_fp): @@ -1594,11 +1464,12 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, mb_mwea, observed_m write_netcdf_modelparams(netcdf_output_fp + glacier_str + '.nc', modelparameters, mb_mwea, observed_massbal) if debug: - print('model parameters:', tc_opt, pf_opt) - ds = xr.open_dataset(input.output_fp_cal + glacier_str + '.nc') + print('model parameters:', pf_opt, tc_opt) + ds = xr.open_dataset(input.output_fp_cal + '14.00006.nc') df = pd.DataFrame(ds['mp_value'].sel(chain=0).values, columns=ds.mp.values) - print('ds PF:', np.round(df['precfactor'].values[0],2), - 'ds TC:', np.round(df['tempchange'].values[0],2)) + print('ds TC:', df['tempchange'].values, 'ds PF:', df['precfactor'].values) + + # ============================================================== @@ -1636,10 +1507,10 @@ def objective(modelparameters_subset): glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( - massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, - icethickness_initial, width_initial, elev_bins, glacier_gcm_temp, - glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, - glacier_gcm_lrglac, dates_table, option_areaconstant=1, + massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + option_areaconstant=1, debug=False )) # Loop through all measurements @@ -1742,10 +1613,10 @@ def run_objective(modelparameters_init, glacier_cal_data, precfactor_bnds=(0.33, glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( - massbalance.runmassbalance(modelparams, glacier_rgi_table, glacier_area_initial, icethickness_initial, - width_initial, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, - glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, - dates_table, option_areaconstant=1)) + massbalance.runmassbalance(modelparams, glacier_rgi_table, glacier_area_t0, icethickness_t0, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + option_areaconstant=1)) # Loop through all measurements for x in range(glacier_cal_data.shape[0]): cal_idx = glacier_cal_data.index.values[x] @@ -1833,12 +1704,11 @@ def objective_group(modelparameters_subset): glacier_gcm_elev = gcm_elev[glac] glacier_gcm_prec = gcm_prec[glac,:] glacier_gcm_temp = gcm_temp[glac,:] - glacier_gcm_tempstd = gcm_tempstd[glac,:] glacier_gcm_lrgcm = gcm_lr[glac,:] glacier_gcm_lrglac = glacier_gcm_lrgcm.copy() - glacier_area_initial = main_glac_hyps.iloc[glac,:].values.astype(float) - icethickness_initial = main_glac_icethickness.iloc[glac,:].values.astype(float) - width_initial = main_glac_width.iloc[glac,:].values.astype(float) + glacier_area_t0 = main_glac_hyps.iloc[glac,:].values.astype(float) + icethickness_t0 = main_glac_icethickness.iloc[glac,:].values.astype(float) + width_t0 = main_glac_width.iloc[glac,:].values.astype(float) # Mass balance calculations (glac_bin_temp, glac_bin_prec, glac_bin_acc, glac_bin_refreeze, glac_bin_snowpack, glac_bin_melt, glac_bin_frontalablation, glac_bin_massbalclim, glac_bin_massbalclim_annual, glac_bin_area_annual, @@ -1846,10 +1716,9 @@ def objective_group(modelparameters_subset): glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( - massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, - icethickness_initial, width_initial, elev_bins, glacier_gcm_temp, - glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, - glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, option_areaconstant=1)) # Mass balance comparisons # Modeled mass balance [mwe] @@ -1955,12 +1824,11 @@ def run_objective_group(modelparameters_init, precfactor_bnds=(0.33,3), tempchan glacier_gcm_elev = gcm_elev[glac] glacier_gcm_prec = gcm_prec[glac,:] glacier_gcm_temp = gcm_temp[glac,:] - glacier_gcm_tempstd = gcm_tempstd[glac,:] glacier_gcm_lrgcm = gcm_lr[glac,:] glacier_gcm_lrglac = glacier_gcm_lrgcm.copy() - glacier_area_initial = main_glac_hyps.iloc[glac,:].values.astype(float) - icethickness_initial = main_glac_icethickness.iloc[glac,:].values.astype(float) - width_initial = main_glac_width.iloc[glac,:].values.astype(float) + glacier_area_t0 = main_glac_hyps.iloc[glac,:].values.astype(float) + icethickness_t0 = main_glac_icethickness.iloc[glac,:].values.astype(float) + width_t0 = main_glac_width.iloc[glac,:].values.astype(float) # Mass balance calculations (glac_bin_temp, glac_bin_prec, glac_bin_acc, glac_bin_refreeze, glac_bin_snowpack, glac_bin_melt, glac_bin_frontalablation, glac_bin_massbalclim, glac_bin_massbalclim_annual, glac_bin_area_annual, @@ -1968,10 +1836,9 @@ def run_objective_group(modelparameters_init, precfactor_bnds=(0.33,3), tempchan glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( - massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, - icethickness_initial, width_initial, elev_bins, glacier_gcm_temp, - glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, - glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, option_areaconstant=1)) # Mass balance comparisons # Modeled mass balance [mwe] @@ -2118,7 +1985,7 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, glacier_cal_compare # Loop through glaciers that have unique cal_data cal_individual_glacno = np.unique(cal_data.loc[cal_data['glacno'].notnull(), 'glacno']) for n in range(cal_individual_glacno.shape[0]): - glac = np.where(main_glac_rgi['rgino_str'].isin([cal_individual_glacno[n]]) == True)[0][0] + glac = np.where(main_glac_rgi[input.rgi_O1Id_colname].isin([cal_individual_glacno[n]]) == True)[0][0] if debug: print(count, ':', main_glac_rgi.loc[main_glac_rgi.index.values[glac], 'RGIId']) elif glac%100 == 0: @@ -2131,14 +1998,13 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, glacier_cal_compare glacier_gcm_elev = gcm_elev[glac] glacier_gcm_prec = gcm_prec[glac,:] glacier_gcm_temp = gcm_temp[glac,:] - glacier_gcm_tempstd = gcm_tempstd[glac,:] glacier_gcm_lrgcm = gcm_lr[glac,:] glacier_gcm_lrglac = glacier_gcm_lrgcm.copy() - glacier_area_initial = main_glac_hyps.iloc[glac,:].values.astype(float) - icethickness_initial = main_glac_icethickness.iloc[glac,:].values.astype(float) - width_initial = main_glac_width.iloc[glac,:].values.astype(float) + glacier_area_t0 = main_glac_hyps.iloc[glac,:].values.astype(float) + icethickness_t0 = main_glac_icethickness.iloc[glac,:].values.astype(float) + width_t0 = main_glac_width.iloc[glac,:].values.astype(float) glacier_cal_data = ((cal_data.iloc[np.where( - glacier_rgi_table['rgino_str'] == cal_data['glacno'])[0],:]).copy()) + glacier_rgi_table[input.rgi_O1Id_colname] == cal_data['glacno'])[0],:]).copy()) cal_idx = glacier_cal_data.index.values glacier_str = '{0:0.5f}'.format(glacier_rgi_table['RGIId_float']) # Comparison dataframe @@ -2277,10 +2143,10 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, glacier_cal_compare glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( - massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, - icethickness_initial, width_initial, elev_bins, glacier_gcm_temp, - glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, - glacier_gcm_lrglac, dates_table, option_areaconstant=1, debug=False)) + massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, + width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + option_areaconstant=1, debug=False)) # Calibration round glacier_cal_compare['calround'] = calround # Model vs. observations @@ -2474,7 +2340,7 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, glacier_cal_compare if not os.path.exists(input.output_fp_cal + 'temp/'): os.makedirs(input.output_fp_cal + 'temp/') regions_str = 'R' - for region in input.rgi_regionsO1: + for region in rgi_regionsO1: regions_str += str(region) output_modelparams_fn = ( regions_str + '_modelparams_opt' + str(input.option_calibration) + '_' + gcm_name @@ -2504,6 +2370,21 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, glacier_cal_compare if input.option_calibration == 2: print('Chains:', input.n_chains, 'Iterations:', input.mcmc_sample_no) + +# # RGI region +# if args.spc_region is not None: +# rgi_regionsO1 = [int(args.spc_region)] +# else: +# rgi_regionsO1 = input.rgi_regionsO1 +# +# # RGI glacier number +# if args.rgi_glac_number_fn is not None: +# with open(args.rgi_glac_number_fn, 'rb') as f: +# rgi_glac_number = pickle.load(f) +# elif args.rgi_glac_number is not None: +# rgi_glac_number = [args.rgi_glac_number] +# else: +# rgi_glac_number = input.rgi_glac_number # RGI glacier number if args.rgi_glac_number_fn is not None: @@ -2519,9 +2400,8 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, glacier_cal_compare regions_str += str(region) # Select all glaciers in a region - main_glac_rgi_all = modelsetup.selectglaciersrgitable( - rgi_regionsO1=rgi_regionsO1, rgi_regionsO2 =input.rgi_regionsO2, rgi_glac_number=input.rgi_glac_number, - glac_no=glac_no) + main_glac_rgi_all = modelsetup.selectglaciersrgitable(rgi_regionsO1=rgi_regionsO1, rgi_regionsO2='all', + rgi_glac_number=rgi_glac_number) # Add regions main_glac_rgi_all['region'] = main_glac_rgi_all.RGIId.map(input.reg_dict) @@ -2556,7 +2436,6 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, glacier_cal_compare # Ice thickness [m], average main_glac_icethickness_all = modelsetup.import_Husstable(main_glac_rgi_all, input.thickness_filepath, input.thickness_filedict, input.thickness_colsdrop) - main_glac_icethickness_all[main_glac_icethickness_all < 0] = 0 main_glac_hyps_all[main_glac_icethickness_all == 0] = 0 # Width [km], average main_glac_width_all = modelsetup.import_Husstable(main_glac_rgi_all, input.width_filepath, @@ -2602,7 +2481,7 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, glacier_cal_compare # Drop glaciers that do not have any calibration data (individual or group) main_glac_rgi = ((main_glac_rgi_all.iloc[np.unique( np.append(main_glac_rgi_all[main_glac_rgi_all['group_name'].notnull() == True].index.values, - np.where(main_glac_rgi_all['rgino_str'].isin(cal_data['glacno']) == True)[0])), :]) + np.where(main_glac_rgi_all[input.rgi_O1Id_colname].isin(cal_data['glacno']) == True)[0])), :]) .copy()) # select glacier data main_glac_hyps = main_glac_hyps_all.iloc[main_glac_rgi.index.values] @@ -2616,18 +2495,12 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, glacier_cal_compare # ===== LOAD CLIMATE DATA ===== gcm = class_climate.GCM(name=gcm_name) - # Air temperature [degC], Air temperature Std [K], Precipitation [m], Elevation [masl], Lapse rate [K m-1] + # Air temperature [degC], Precipitation [m], Elevation [masl], Lapse rate [K m-1] gcm_temp, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn, gcm.temp_vn, main_glac_rgi, dates_table) gcm_prec, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn, gcm.prec_vn, main_glac_rgi, dates_table) gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn, main_glac_rgi) - # Air temperature standard deviation [K] - if input.option_ablation != 2 or gcm_name not in ['ERA5']: - gcm_tempstd = np.zeros(gcm_temp.shape) - elif gcm_name in ['ERA5']: - gcm_tempstd, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.tempstd_fn, gcm.tempstd_vn, - main_glac_rgi, dates_table) # Lapse rate [K m-1] - if gcm_name in ['ERA-Interim', 'ERA5']: + if gcm_name == 'ERA-Interim': gcm_lr, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.lr_fn, gcm.lr_vn, main_glac_rgi, dates_table) else: # Mean monthly lapse rate @@ -2660,7 +2533,6 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, glacier_cal_compare main_glac_icethickness_chunk = main_glac_icethickness.loc[chunk:chunk+chunk_size-1].copy() main_glac_width_chunk = main_glac_width.loc[chunk:chunk+chunk_size-1].copy() gcm_temp_chunk = gcm_temp[chunk:chunk+chunk_size] - gcm_tempstd_chunk = gcm_tempstd[chunk:chunk+chunk_size] gcm_prec_chunk = gcm_prec[chunk:chunk+chunk_size] gcm_elev_chunk = gcm_elev[chunk:chunk+chunk_size] gcm_lr_chunk = gcm_lr[chunk:chunk+chunk_size] @@ -2673,7 +2545,6 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, glacier_cal_compare main_glac_icethickness_chunk, main_glac_width_chunk, gcm_temp_chunk, - gcm_tempstd_chunk, gcm_prec_chunk, gcm_elev_chunk, gcm_lr_chunk, @@ -2768,6 +2639,7 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, glacier_cal_compare # # Place local variables in variable explorer # if (args.option_parallels == 0): # main_vars_list = list(main_vars.keys()) +## gcm_name = main_vars['gcm_name'] # main_glac_rgi = main_vars['main_glac_rgi'] # main_glac_hyps = main_vars['main_glac_hyps'] # main_glac_icethickness = main_vars['main_glac_icethickness'] @@ -2781,12 +2653,12 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, glacier_cal_compare # gcm_elev = main_vars['gcm_elev'] # gcm_lr = main_vars['gcm_lr'] # modelparameters = main_vars['modelparameters'] -# glacier_area_initial = main_vars['glacier_area_initial'] +# glacier_area_t0 = main_vars['glacier_area_t0'] # glacier_cal_data = main_vars['glacier_cal_data'] # cal_idx = main_vars['cal_idx'] # modelparameters = main_vars['modelparameters'] -# icethickness_initial = main_vars['icethickness_initial'] -# width_initial = main_vars['width_initial'] +# icethickness_t0 = main_vars['icethickness_t0'] +# width_t0 = main_vars['width_t0'] # # if input.option_calibration == 2 and input.new_setup == 1: # observed_massbal=main_vars['observed_massbal'] @@ -2820,9 +2692,16 @@ def write_netcdf_modelparams(output_fullfn, modelparameters, glacier_cal_compare # main_glac_output = main_vars['main_glac_output'] # main_glac_modelparamsopt_pd = main_vars['main_glac_modelparamsopt_pd'] # main_glacwide_mbclim_mwe = main_vars['main_glacwide_mbclim_mwe'] +# # glac_wide_massbaltotal = main_vars['glac_wide_massbaltotal'] +# # glac_wide_area_annual = main_vars['glac_wide_area_annual'] +# # glac_wide_volume_annual = main_vars['glac_wide_volume_annual'] +# # glacier_rgi_table = main_vars['glacier_rgi_table'] +# # main_glac_modelparamsopt = main_vars['main_glac_modelparamsopt'] +# # main_glac_massbal_compare = main_vars['main_glac_massbal_compare'] +# # main_glac_output = main_vars['main_glac_output'] # if set(['group']).issubset(input.cal_datasets): # group_dict_keyslist = main_vars['group_dict_keyslist'] # group_dict_keyslist_names = main_vars['group_dict_keyslist_names'] # cal_data_idx_groups = main_vars['cal_data_idx_groups'] # cal_data = main_vars['cal_data'] -# cal_individual_glacno = main_vars['cal_individual_glacno'] \ No newline at end of file +# cal_individual_glacno = main_vars['cal_individual_glacno'] diff --git a/run_postprocessing.py b/run_postprocessing.py index 4582120c..9a6bc5e6 100644 --- a/run_postprocessing.py +++ b/run_postprocessing.py @@ -7,20 +7,15 @@ import zipfile # External libraries import numpy as np -import pandas as pd import xarray as xr # Local libraries import pygem_input as input import pygemfxns_modelsetup as modelsetup import pygemfxns_gcmbiasadj as gcmbiasadj -import run_simulation as simulation #%run run_postprocessing.py -gcm_name='ERA-Interim' -merge_batches=1 -option_multimodel = 1 -option_merge_era = 0 - #%% Functions def getparser(): """ @@ -47,8 +42,6 @@ def getparser(): help='GCM name used for model run') parser.add_argument('-rcp', action='store', type=str, default=None, help='rcp scenario used for model run (ex. rcp26)') - parser.add_argument('-region', action='store', type=int, default=None, - help='RGI region number (order 1)') parser.add_argument('-output_sim_fp', action='store', type=str, default=input.output_sim_fp, help='output simulation filepath where results are being stored by GCM') parser.add_argument('-option_remove_merged_files', action='store', type=int, default=0, @@ -59,8 +52,6 @@ def getparser(): help='Switch to merge batches or not (1-merge)') parser.add_argument('-extract_subset', action='store', type=int, default=0, help='Switch to extract a subset of variables or not (1-yes)') - parser.add_argument('-unzip_files', action='store', type=int, default=0, - help='Switch to unzip files or not (1-yes)') parser.add_argument('-subset_byvar', action='store', type=int, default=0, help='Switch to subset by each variables or not') parser.add_argument('-vars_mon2annualseasonal', action='store', type=int, default=0, @@ -69,193 +60,128 @@ def getparser(): help='Boolean for debugging to turn it on or off (default 0 is off)') return parser - -#%% ===== MERGE HINDCAST AND PRESENT SIMULATION ===== -if option_merge_era == 1: - print('MERGING ERA...') - regions = ['13','14','15'] - ds_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/Output/simulations/spc_20190914/merged/ERA-Interim/' - - print('ASSUMES THERE IS ONE YEAR OF OVERLAP') - - for region in regions: - ds_fn1 = 'R' + region + '--all--ERA-Interim_c2_ba1_100sets_1980_2000.nc' - ds_fn2 = 'R' + region + '--all--ERA-Interim_c2_ba1_100sets_2000_2017.nc' - ds_merged_fn = 'R' + region + '--all--ERA-Interim_c2_ba1_100sets_1980_2017.nc' - ds1_raw = xr.open_dataset(ds_fp + ds_fn1) - ds2_raw = xr.open_dataset(ds_fp + ds_fn2) - - time_idx = list(np.arange(12,ds2_raw.time.shape[0])) - year_idx = list(np.arange(1,ds2_raw.year.shape[0])) - year_plus1_idx = list(np.arange(1,ds2_raw.year_plus1.shape[0])) - year_plus1_idx_4ds1 = list(np.arange(0,ds1_raw.year_plus1.shape[0]-1)) - - ds1 = ds1_raw.isel(year_plus1=year_plus1_idx_4ds1) - ds2 = ds2_raw.isel(time=time_idx, year=year_idx, year_plus1=year_plus1_idx) - - time_vns = ['temp_glac_monthly', 'prec_glac_monthly', 'acc_glac_monthly', 'refreeze_glac_monthly', - 'melt_glac_monthly', 'frontalablation_glac_monthly', 'massbaltotal_glac_monthly', 'runoff_glac_monthly', - 'snowline_glac_monthly', 'offglac_prec_monthly', 'offglac_refreeze_monthly', 'offglac_melt_monthly', - 'offglac_snowpack_monthly', 'offglac_runoff_monthly'] - year_plus1_vns = ['area_glac_annual', 'volume_glac_annual'] - year_vns = ['ELA_glac_annual'] - - ds1_time = ds1[time_vns] - ds2_time = ds2[time_vns] - ds3_time = xr.concat((ds1_time, ds2_time), 'time') - - ds1_year = ds1[year_vns] - ds2_year = ds2[year_vns] - ds3_year = xr.concat((ds1_year,ds2_year), 'year') - - ds1_year_plus1 = ds1[year_plus1_vns] - ds2_year_plus1 = ds2[year_plus1_vns] - ds3_year_plus1 = xr.concat((ds1_year_plus1,ds2_year_plus1), 'year_plus1') - - ds3_years = ds3_year.merge(ds3_year_plus1) - ds3 = ds3_years.merge(ds3_time) - ds3['glacier_table'] = ds1_raw['glacier_table'] - - # Export merged dataset - # Encoding - # add variables to empty dataset and merge together - encoding = {} - noencoding_vn = ['stats', 'glac_attrs'] - if input.output_package == 2: - for encoding_vn in input.output_variables_package2: - # Encoding (specify _FillValue, offsets, etc.) - if encoding_vn not in noencoding_vn: - encoding[encoding_vn] = {'_FillValue': False} - ds3.to_netcdf(ds_fp + ds_merged_fn, encoding=encoding) -#%% ====================== MULTI-MODEL SCRIPT! =================== -if option_multimodel == 1: - print('MULTIMODEL CALCULATIONS') - gcm_names = ['bcc-csm1-1', 'CanESM2', 'CESM1-CAM5', 'CCSM4', 'CNRM-CM5', 'CSIRO-Mk3-6-0', 'FGOALS-g2', 'GFDL-CM3', - 'GFDL-ESM2G', 'GFDL-ESM2M', 'GISS-E2-R', 'HadGEM2-ES', 'IPSL-CM5A-LR', 'IPSL-CM5A-MR', 'MIROC-ESM', - 'MIROC-ESM-CHEM', 'MIROC5', 'MPI-ESM-LR', 'MPI-ESM-MR', 'MRI-CGCM3', 'NorESM1-M', 'NorESM1-ME'] - #gcm_names = ['bcc-csm1-1'] - #rcps = ['rcp26', 'rcp45', 'rcp60', 'rcp85'] - #regions = [13,14,15] - rcps = ['rcp85'] - regions = [15] - zip_fp = '/Volumes/LaCie/HMA_PyGEM/2019_0914/spc_zipped/' - multimodel_fp = zip_fp + '../multimodel/' - - ds_vns = ['temp_glac_monthly', 'prec_glac_monthly', 'acc_glac_monthly', 'refreeze_glac_monthly', 'melt_glac_monthly', - 'frontalablation_glac_monthly', 'massbaltotal_glac_monthly', 'runoff_glac_monthly', 'snowline_glac_monthly', - 'area_glac_annual', 'volume_glac_annual', 'ELA_glac_annual', 'offglac_prec_monthly', - 'offglac_refreeze_monthly', 'offglac_melt_monthly', 'offglac_snowpack_monthly', 'offglac_runoff_monthly'] - - for batman in [0]: - def sum_multimodel(fn, vn, ds_var_multimodel_sum, count): - """ Sum multimodel to avoid creating excessively large np.arrays that crash memory """ - # Open dataset and use first dataset as multimodel dataset to retain attributes - ds = xr.open_dataset(multimodel_fp + fn) - print(fn, np.round(ds[vn][1,1,0].values,3)) - - # Select values of variable - ds_var = ds[vn][:,:,0].values - # Concatenate into numpy array - if ds_var_multimodel_sum is None: - ds_var_multimodel_sum = ds_var - else: - ds_var_multimodel_sum += ds_var - - ds.close() - - # Record count to divide by to get mean in the end - count += 1 - - return ds_var_multimodel_sum, count - - def sum_multimodel_variance(fn, vn, ds_var_multimodel_stdsum, ds_var_multimodel_mean): - """ Sum multimodel variance to avoid creating excessively large np.arrays that crash memory """ - # Open dataset and use first dataset as multimodel dataset to retain attributes - ds = xr.open_dataset(multimodel_fp + fn) - print(fn, 'std calc') - - # Select values of variable - ds_var = ds[vn][:,:,0].values - - ds_var_stdsum = (ds_var - ds_var_multimodel_mean)**2 - - # Concatenate into numpy array - if ds_var_multimodel_stdsum is None: - ds_var_multimodel_stdsum = ds_var_stdsum - else: - ds_var_multimodel_stdsum += ds_var_stdsum - - ds.close() - - return ds_var_multimodel_stdsum - - for region in regions: - for rcp in rcps: - - for gcm_name in gcm_names: - gcm_fp = zip_fp + gcm_name + '/' - for i in os.listdir(gcm_fp): - if str(region) in i and rcp in i and os.path.exists(multimodel_fp + i.replace('.zip','')) == False: - print('Extracting ' + i) - with zipfile.ZipFile(gcm_fp + i, 'r') as zipObj: - # Extract all the contents of zip file in current directory - zipObj.extractall(multimodel_fp) - - - list_fns = [] - for i in os.listdir(multimodel_fp): - if str(region) in i and rcp in i: - list_fns.append(i) - - print(len(list_fns), list_fns) - - # Use existing dataset to setup multimodel netcdf structure - ds_multimodel = xr.open_dataset(multimodel_fp + list_fns[0]) - - for vn in ds_vns: - print(vn) - - ds_var_multimodel_sum = None - ds_var_multimodel_stdsum = None - count = 0 - - # Multimodel mean - # sum data from each array to reduce memory requirements - for i in list_fns: - ds_var_multimodel_sum, count = sum_multimodel(i, vn, ds_var_multimodel_sum, count) - # compute mean - ds_var_multimodel_mean = ds_var_multimodel_sum / count - - print('Mean:', np.round(ds_var_multimodel_mean[1,1],3)) - - # Multimodel standard deviation - # sum squared difference - for i in list_fns: - ds_var_multimodel_stdsum = sum_multimodel_variance(i, vn, ds_var_multimodel_stdsum, - ds_var_multimodel_mean) - # compute standard deviation - ds_var_multimodel_std = (ds_var_multimodel_stdsum / count)**0.5 - - print('Std:', np.round(ds_var_multimodel_std[1,1],3)) - - ds_multimodel[vn][:,:,:] = ( - np.concatenate((ds_var_multimodel_mean[:,:,np.newaxis], ds_var_multimodel_std[:,:,np.newaxis]), - axis=2)) - - # Export merged dataset - # Encoding - # add variables to empty dataset and merge together - encoding = {} - noencoding_vn = ['stats', 'glac_attrs'] - if input.output_package == 2: - for encoding_vn in input.output_variables_package2: - # Encoding (specify _FillValue, offsets, etc.) - if encoding_vn not in noencoding_vn: - encoding[encoding_vn] = {'_FillValue': False} - - ds_multimodel_fn = 'R' + str(region) + '_multimodel_' + rcp + '_c2_ba1_100sets_2000_2100.nc' - ds_multimodel.to_netcdf(multimodel_fp + ds_multimodel_fn, encoding=encoding) +#gcm_names = ['bcc-csm1-1', 'CanESM2', 'CESM1-CAM5', 'CCSM4', 'CNRM-CM5', 'CSIRO-Mk3-6-0', 'FGOALS-g2', 'GFDL-CM3', +# 'GFDL-ESM2G', 'GFDL-ESM2M', 'GISS-E2-R', 'HadGEM2-ES', 'IPSL-CM5A-LR', 'IPSL-CM5A-MR', 'MIROC-ESM', +# 'MIROC-ESM-CHEM', 'MIROC5', 'MPI-ESM-LR', 'MPI-ESM-MR', 'MRI-CGCM3', 'NorESM1-M', 'NorESM1-ME'] +##gcm_names = ['bcc-csm1-1'] +#rcps = ['rcp26', 'rcp45', 'rcp60', 'rcp85'] +#regions = [13,14,15] +#zip_fp = '/Volumes/LaCie/PyGEM_simulations/2019_0317/spc_zipped/' +#multimodel_fp = zip_fp + '../multimodel/' +# +#ds_vns = ['temp_glac_monthly', 'prec_glac_monthly', 'acc_glac_monthly', 'refreeze_glac_monthly', 'melt_glac_monthly', +# 'frontalablation_glac_monthly', 'massbaltotal_glac_monthly', 'runoff_glac_monthly', 'snowline_glac_monthly', +# 'area_glac_annual', 'volume_glac_annual', 'ELA_glac_annual', 'offglac_prec_monthly', +# 'offglac_refreeze_monthly', 'offglac_melt_monthly', 'offglac_snowpack_monthly', 'offglac_runoff_monthly'] +#ds_vns = ['temp_glac_monthly'] + +#for batman in [0]: +# def sum_multimodel(fn, vn, ds_var_multimodel_sum, count): +# """ Sum multimodel to avoid creating excessively large np.arrays that crash memory """ +# # Open dataset and use first dataset as multimodel dataset to retain attributes +# ds = xr.open_dataset(multimodel_fp + fn) +# print(fn, np.round(ds[vn][1,1,0].values,3)) +# +# # Select values of variable +# ds_var = ds[vn][:,:,0].values +# # Concatenate into numpy array +# if ds_var_multimodel_sum is None: +# ds_var_multimodel_sum = ds_var +# else: +# ds_var_multimodel_sum += ds_var +# +# ds.close() +# +# # Record count to divide by to get mean in the end +# count += 1 +# +# return ds_var_multimodel_sum, count +# +# def sum_multimodel_variance(fn, vn, ds_var_multimodel_stdsum, ds_var_multimodel_mean): +# """ Sum multimodel variance to avoid creating excessively large np.arrays that crash memory """ +# # Open dataset and use first dataset as multimodel dataset to retain attributes +# ds = xr.open_dataset(multimodel_fp + fn) +# print(fn, 'std calc') +# +# # Select values of variable +# ds_var = ds[vn][:,:,0].values +# +# ds_var_stdsum = (ds_var - ds_var_multimodel_mean)**2 +# +# # Concatenate into numpy array +# if ds_var_multimodel_stdsum is None: +# ds_var_multimodel_stdsum = ds_var_stdsum +# else: +# ds_var_multimodel_stdsum += ds_var_stdsum +# +# ds.close() +# +# return ds_var_multimodel_stdsum +# +# for region in regions: +# for rcp in rcps: +# +# for gcm_name in gcm_names: +# gcm_fp = zip_fp + gcm_name + '/' +# for i in os.listdir(gcm_fp): +# if str(region) in i and rcp in i: +# with zipfile.ZipFile(gcm_fp + i, 'r') as zipObj: +# # Extract all the contents of zip file in current directory +# zipObj.extractall(multimodel_fp) +# +# #%% +# list_fns = [] +# for i in os.listdir(multimodel_fp): +# if str(region) in i and rcp in i: +# list_fns.append(i) +# +# # Use existing dataset to setup multimodel netcdf structure +# ds_multimodel = xr.open_dataset(multimodel_fp + list_fns[0]) +# +# for vn in ds_vns: +# print(vn) +# +# ds_var_multimodel_sum = None +# ds_var_multimodel_stdsum = None +# count = 0 +# +# # Multimodel mean +# # sum data from each array to reduce memory requirements +# for i in list_fns: +# ds_var_multimodel_sum, count = sum_multimodel(i, vn, ds_var_multimodel_sum, count) +# # compute mean +# ds_var_multimodel_mean = ds_var_multimodel_sum / count +# +# print('Mean:', np.round(ds_var_multimodel_mean[1,1],3)) +# +# # Multimodel standard deviation +# # sum squared difference +# for i in list_fns: +# ds_var_multimodel_stdsum = sum_multimodel_variance(i, vn, ds_var_multimodel_stdsum, +# ds_var_multimodel_mean) +# # compute standard deviation +# ds_var_multimodel_std = (ds_var_multimodel_stdsum / count)**0.5 +# +# print('Std:', np.round(ds_var_multimodel_std[1,1],3)) +# +# ds_multimodel[vn][:,:,:] = ( +# np.concatenate((ds_var_multimodel_mean[:,:,np.newaxis], ds_var_multimodel_std[:,:,np.newaxis]), +# axis=2)) +# +# # Export merged dataset +# # Encoding +# # add variables to empty dataset and merge together +# encoding = {} +# noencoding_vn = ['stats', 'glac_attrs'] +# if input.output_package == 2: +# for encoding_vn in input.output_variables_package2: +# # Encoding (specify _FillValue, offsets, etc.) +# if encoding_vn not in noencoding_vn: +# encoding[encoding_vn] = {'_FillValue': False} +# +# ds_multimodel_fn = 'R' + str(region) + '_multimodel_' + rcp + '_c2_ba1_100sets_2000_2100.nc' +# ds_multimodel.to_netcdf(input.output_sim_fp + ds_multimodel_fn, encoding=encoding) #%% @@ -377,21 +303,11 @@ def merge_batches(gcm_name, output_sim_fp=input.output_sim_fp, rcp=None, os.remove(netcdf_fp + i) -#def extract_subset(gcm_name, netcdf_fp=input.output_sim_fp): -def extract_subset(gcm_name, rcp_scenario=None, region_no=None, netcdf_fp=input.output_sim_fp, unzip_files=0): -##gcm_names = ['CanESM2', 'CESM1-CAM5', 'CNRM-CM5', 'CSIRO-Mk3-6-0', 'FGOALS-g2', -## 'GFDL-ESM2G', 'HadGEM2-ES', 'IPSL-CM5A-MR', 'MIROC-ESM', -## 'MIROC-ESM-CHEM', 'MPI-ESM-LR', 'MPI-ESM-MR', 'NorESM1-ME'] -#gcm_names = ['CanESM2'] -#zip_fp = '/Volumes/LaCie/HMA_PyGEM/2019_0914/spc_zipped/' -##netcdf_fp = input.output_sim_fp -#rcp_scenario= None -#region_no=None -#unzip_files = 1 +def extract_subset(gcm_name, netcdf_fp=input.output_sim_fp): +#gcm_names = ['NorESM1-ME'] +#netcdf_fp = multimodel_fp +#netcdf_fp = input.output_sim_fp #for gcm_name in gcm_names: -# -# netcdf_fp = zip_fp + gcm_name + '/' -# print(netcdf_fp) vns_all = input.output_variables_package2 @@ -401,144 +317,57 @@ def extract_subset(gcm_name, rcp_scenario=None, region_no=None, netcdf_fp=input. # List of variable names to drop from merged file drop_vns = [item for item in vns_all if item not in vns_subset] - if rcp_scenario is None: - rcp_checkstr = 'rcp' - else: - rcp_checkstr = rcp_scenario - - if region_no is None: - region_checkstr = 'R' - else: - region_checkstr = 'R' + str(region_no) - - # Unzip files - if unzip_files == 1: - for i in os.listdir(netcdf_fp): - # Unzip file if it doesn't exist yet - if ((i.endswith('.nc.zip')) and (os.path.isfile((netcdf_fp + i).replace('.zip','')) == False) - and (rcp_checkstr in i) and (region_checkstr in i)): - with zipfile.ZipFile(netcdf_fp + i, 'r') as zip_ref: - zip_ref.extractall(netcdf_fp) - -# # Loop through files to extract filenames -# regions = [] -# rcps = [] -# for i in os.listdir(netcdf_fp): -# if i.endswith('.nc') and gcm_name in i: -# i_region = int(i.split('_')[0][1:]) -# i_rcp = i.split('_')[2] -# -# if i_region not in regions: -# regions.append(i_region) -# if i_rcp not in rcps: -# rcps.append(i_rcp) -# regions = sorted(regions) -# rcps = sorted(rcps) - - # Determine RCPs - if rcp_scenario is not None: - rcps = [rcp_scenario] - else: - rcps = [] - for i in os.listdir(netcdf_fp): - if i.endswith('.nc') and gcm_name in i: -# i_rcp = i.split('_')[2] - i_rcp = 'rcp' + i.split('rcp')[1].split('_')[0] - if i_rcp not in rcps: - rcps.append(i_rcp) - rcps = sorted(rcps) - - # Determine Regions - if region_no is not None: - regions = [region_no] - else: - regions = [] - for i in os.listdir(netcdf_fp): - if i.endswith('.nc') and gcm_name in i: -# i_region = int(i.split('_')[0][1:]) - i_region = i.split('R')[1][0:2] - if i_region not in regions: - regions.append(i_region) - regions = sorted(regions) - - - ds_fns = [] + regions = [] + rcps = [] for i in os.listdir(netcdf_fp): - if (i.endswith('.nc')) and (rcp_checkstr in i) and (region_checkstr in i): - ds_fns.append(i) + if i.endswith('.nc') and gcm_name in i: + i_region = int(i.split('_')[0][1:]) + i_rcp = i.split('_')[2] + + if i_region not in regions: + regions.append(i_region) + if i_rcp not in rcps: + rcps.append(i_rcp) + regions = sorted(regions) + rcps = sorted(rcps) - - # Extract subsets - for ds_fn in ds_fns: - # Encoding - encoding = {} - noencoding_vn = ['stats', 'glac_attrs'] - # Encoding (specify _FillValue, offsets, etc.) - for vn in vns_subset: - if vn not in noencoding_vn: - encoding[vn] = {'_FillValue': False} - - # Open datasets and combine - ds = xr.open_dataset(netcdf_fp + ds_fn) - # Drop variables - ds = ds.drop(drop_vns) - ds_new_fn = ds_fn.replace('.nc', '--subset.nc') - # Export to netcdf - subset_fp = netcdf_fp + '../spc_subset/' - # Add filepath if it doesn't exist - if not os.path.exists(subset_fp): - os.makedirs(subset_fp) - ds.to_netcdf(subset_fp + ds_new_fn, encoding=encoding) - ds.close() + for reg in regions: + for rcp in rcps: + check_str = 'R' + str(reg) + '_' + gcm_name + '_' + rcp + output_list = [] - vol_glac_all = ds.volume_glac_annual.values[:,:,0] - vol_remain_perc = vol_glac_all[:,vol_glac_all.shape[1]-1].sum() / vol_glac_all[:,0].sum() * 100 - reg = ds_fn.split('--')[0] - rcp = ds_fn.split('_')[1] - print(gcm_name, 'Region', reg, rcp, 'Vol remain [%]:', np.round(vol_remain_perc,1)) - - # Remove file - os.remove(netcdf_fp + ds_fn) - -# # Extract subsets -# for reg in regions: -# for rcp in rcps: -# check_str = 'R' + str(reg) + '_' + gcm_name + '_' + rcp -# output_list = [] -# -# for i in os.listdir(netcdf_fp): -# if i.startswith(check_str): -# ds_fn = i -# output_list.append(i) -# -# # Encoding -# encoding = {} -# noencoding_vn = ['stats', 'glac_attrs'] -# # Encoding (specify _FillValue, offsets, etc.) -# for vn in vns_subset: -# if vn not in noencoding_vn: -# encoding[vn] = {'_FillValue': False} -# -# # Open datasets and combine -# ds = xr.open_dataset(netcdf_fp + ds_fn) -# # Drop variables -# ds = ds.drop(drop_vns) -# ds_new_fn = ds_fn.split('.nc')[0] + '--subset.nc' -# # Export to netcdf -# subset_fp = netcdf_fp + '../spc_subset/' -# print(subset_fp) -# # Add filepath if it doesn't exist -# if not os.path.exists(subset_fp): -# os.makedirs(subset_fp) -# ds.to_netcdf(subset_fp + ds_new_fn, encoding=encoding) -# ds.close() -# -# vol_glac_all = ds.volume_glac_annual.values[:,:,0] -# vol_remain_perc = vol_glac_all[:,vol_glac_all.shape[1]-1].sum() / vol_glac_all[:,0].sum() * 100 -# print(gcm_name, 'Region', reg, rcp, 'Vol remain [%]:', np.round(vol_remain_perc,1)) -# -## # Remove file -## os.remove(netcdf_fp + i) + for i in os.listdir(netcdf_fp): + if i.startswith(check_str): + ds_fn = i + output_list.append(i) + + # Encoding + encoding = {} + noencoding_vn = ['stats', 'glac_attrs'] + # Encoding (specify _FillValue, offsets, etc.) + for vn in vns_subset: + if vn not in noencoding_vn: + encoding[vn] = {'_FillValue': False} + + # Open datasets and combine + ds = xr.open_dataset(netcdf_fp + ds_fn) + # Drop variables + ds = ds.drop(drop_vns) + ds_new_fn = ds_fn.split('.nc')[0] + '--subset.nc' + # Export to netcdf + subset_fp = netcdf_fp + '/spc_subset/' + # Add filepath if it doesn't exist + if not os.path.exists(subset_fp): + os.makedirs(subset_fp) + ds.to_netcdf(subset_fp + ds_new_fn, encoding=encoding) + ds.close() + + vol_glac_all = ds.volume_glac_annual.values[:,:,0] + vol_remain_perc = vol_glac_all[:,vol_glac_all.shape[1]-1].sum() / vol_glac_all[:,0].sum() * 100 + print(gcm_name, 'Region', reg, rcp, 'Vol remain [%]:', np.round(vol_remain_perc,1)) + +# # Remove file +# os.remove(netcdf_fp + i) def subset_byvar(gcm_name): @@ -897,49 +726,10 @@ def vars_mon2annualseasonal(gcm_name): option_remove_batch_files=args.option_remove_batch_files) if args.extract_subset == 1: - extract_subset(args.gcm_name, rcp_scenario=args.rcp, region_no=args.region, netcdf_fp=args.output_sim_fp, - unzip_files=args.unzip_files) + extract_subset(args.gcm_name) if args.subset_byvar == 1: subset_byvar(args.gcm_name) if args.vars_mon2annualseasonal == 1: - vars_mon2annualseasonal(args.gcm_name) - -##%% RE-ORDER OUTPUT BY GLACIER NUMBER -#for region in regions: -# for rcp in rcps: -# -# output_fp = '../Output/simulations/spc_20190914/merged/' -# ds_fn = 'R' + str(region) + '--all--IPSL-CM5A-LR_' + rcp + '_c2_ba1_100sets_2000_2100.nc' -# #ds_fn = 'R15--all--IPSL-CM5A-LR_rcp60_c2_ba1_100sets_2000_2100.nc' -# ds = xr.open_dataset(output_fp + ds_fn) -# df = pd.DataFrame(ds.glacier_table.values, columns=ds.glac_attrs.values) -# -# glacno = df.glacno.values.astype(int) -# ds.glac.values = glacno -# ds2 = ds.sortby('glac') -# df2 = pd.DataFrame(ds2.glacier_table.values, columns=ds2.glac_attrs.values) -# -## glacno_str = [str(region) + '.' + str(x).zfill(5) for x in glacno] -## main_glac_rgi = modelsetup.selectglaciersrgitable(glac_no = glacno_str) -# -## A = ds2.area_glac_annual.values[:,:,0] -## B = A[:,0] - main_glac_rgi['Area'].values -# -# ds2_fn = ds_fn.replace('.nc', '-ordered.nc') -# # Encoding -# # Add variables to empty dataset and merge together -# encoding = {} -# noencoding_vn = ['stats', 'glac_attrs'] -# for vn in input.output_variables_package2: -# # Encoding (specify _FillValue, offsets, etc.) -# if vn not in noencoding_vn: -# encoding[vn] = {'_FillValue': False} -# # Export to netcdf -# ds2.to_netcdf(output_fp + ds2_fn, encoding=encoding) -# # Close dataset -# ds.close() -# ds2.close() -# -# os.remove(output_fp + ds_fn) \ No newline at end of file + vars_mon2annualseasonal(args.gcm_name) \ No newline at end of file diff --git a/run_preprocessing.py b/run_preprocessing.py index d8bb33cf..f9c83216 100644 --- a/run_preprocessing.py +++ b/run_preprocessing.py @@ -835,12 +835,6 @@ def coawst_merge_netcdf(vn, coawst_fp, coawst_fn_prefix): gcm_temp, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn, gcm.temp_vn, main_glac_rgi, dates_table) gcm_prec, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn, gcm.prec_vn, main_glac_rgi, dates_table) gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn, main_glac_rgi) - # Air temperature standard deviation - if input.option_ablation != 2: - gcm_tempstd = np.zeros(gcm_temp.shape) - elif input.ref_gcm_name in ['ERA5']: - gcm_tempstd, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.tempstd_fn, gcm.tempstd_vn, - main_glac_rgi, dates_table) # Lapse rate [K m-1] gcm_lr, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.lr_fn, gcm.lr_vn, main_glac_rgi, dates_table) #%% @@ -858,7 +852,6 @@ def coawst_merge_netcdf(vn, coawst_fp, coawst_fn_prefix): # Select subsets of data glacier_gcm_elev = gcm_elev[n] glacier_gcm_temp = gcm_temp[n,:] - glacier_gcm_tempstd = gcm_tempstd[n,:] glacier_gcm_lrgcm = gcm_lr[n,:] glacier_gcm_lrglac = glacier_gcm_lrgcm.copy() glacier_gcm_prec = gcm_prec[n,:] @@ -878,9 +871,9 @@ def coawst_merge_netcdf(vn, coawst_fp, coawst_fn_prefix): glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_t0, - icethickness_t0, width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, - glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, - dates_table, option_areaconstant=0, frontalablation_k=None, + icethickness_t0, width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_prec, + glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + option_areaconstant=0, frontalablation_k=None, debug=True)) print('Add objective function and code ') diff --git a/run_preprocessing_berthier.py b/run_preprocessing_berthier.py deleted file mode 100644 index 5db7a526..00000000 --- a/run_preprocessing_berthier.py +++ /dev/null @@ -1,1688 +0,0 @@ -""" -pygemfxns_preprocessing.py is a list of the model functions that are used to preprocess the data into the proper format. - -""" - -# Built-in libraries -import os -import argparse -# External libraries -import matplotlib.pyplot as plt -from matplotlib.lines import Line2D -from matplotlib.ticker import MultipleLocator -import numpy as np -import pandas as pd -from scipy.optimize import curve_fit - -import pygemfxns_modelsetup as modelsetup -#import pygem_input as input - -print('\ndhdt analysis performed separately using shean_mb_parallel.py\n') - -# ===== INPUT DATA ===== -hyps_fn = ('/Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/output/' + - 'area_km2_01_Farinotti2019_10m.csv') -icethickness_fn = ('/Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/output/' + - 'thickness_m_01_Farinotti2019_10m.csv') - -#dataset_name = 'berthier' -dataset_name = 'braun' - -if dataset_name == 'berthier': - dems_output_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/Berthier/output/' - mb_summary_fn_list = ['AK_Pen_mb_20190912_2256.csv', 'AR_C_mb_20190913_0735.csv', 'AR_E_mb_20190913_0735.csv', - 'AR_W_mb_20190913_0835.csv', 'Chugach_mb_20190913_0744.csv', 'Coast_mb_20190912_2308.csv', - 'Kenai_mb_20190912_2301.csv', 'StElias_mb_20190913_0836.csv'] - mb_summary_fn = 'AK_all_20190913.csv' - mb_mwea_all_fn = 'AK_all_20190913_wextrapolations.csv' - reg_t1_dict = {2: 1953., 3: 1950., 4: 1952., 5: 1968., 6: 1966, 9999: 1957.8} - reg_t2_dict = {2: 2004.75, 3: 2007.75, 4: 2007.75, 5: 2006.75, 6: 2007.75, 9999: 2006.75} - obs_type = 'mb_geo' -elif dataset_name == 'braun': - dems_output_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/Braun/output/' - mb_summary_fn_list = ['Braun_mb_20190924_all.csv'] - mb_summary_fn = 'braun_AK_all_20190924.csv' - mb_mwea_all_fn = 'braun_AK_all_20190924_wextrapolations.csv' - reg_t1_dict = {1: 2000.128, 2: 2000.128, 3: 2000.128, 4: 2000.128, 5: 2000.128, 6: 2000.128, 9999: 2000.128} - reg_t2_dict = {1: 2012., 2: 2012., 3: 2012., 4: 2012., 5: 2012., 6: 2012., 9999: 2012.} - obs_type = 'mb_geo' - -binned_fp = dems_output_fp + 'csv/' -fig_fp = dems_output_fp + 'figures/all/' - -if os.path.exists(fig_fp) == False: - os.makedirs(fig_fp) - -valid_perc_threshold = 90 -min_area_km2 = 3 -mb_cn = 'mb_bin_med_mwea' -mb_max = 2.5 -mb_min = -5 -option_normelev = 'huss' # Terminus = 1, Top = 0 -#option_normelev = 'larsen' # Terminus = 0, Top = 1 - -#Binned CSV column name conversion dictionary -# change column names so they are easier to work with (remove spaces, etc.) -sheancoldict = {'# bin_center_elev_m': 'bin_center_elev_m', - ' z1_bin_count_valid': 'z1_bin_count_valid', - ' z1_bin_area_valid_km2': 'z1_bin_area_valid_km2', - ' z1_bin_area_perc': 'z1_bin_area_perc', - ' z2_bin_count_valid': 'z2_bin_count_valid', - ' z2_bin_area_valid_km2': 'z2_bin_area_valid_km2', - ' z2_bin_area_perc': 'z2_bin_area_perc', - ' dhdt_bin_count' : 'dhdt_bin_count', - ' dhdt_bin_area_valid_km2' : 'dhdt_bin_area_valid_km2', - ' dhdt_bin_area_perc' : 'dhdt_bin_area_perc', - ' dhdt_bin_med_ma': 'dhdt_bin_med_ma', - ' dhdt_bin_mad_ma': 'dhdt_bin_mad_ma', - ' dhdt_bin_mean_ma': 'dhdt_bin_mean_ma', - ' dhdt_bin_std_ma': 'dhdt_bin_std_ma', - ' mb_bin_med_mwea': 'mb_bin_med_mwea', - ' mb_bin_mad_mwea': 'mb_bin_mad_mwea', - ' mb_bin_mean_mwea': 'mb_bin_mean_mwea', - ' mb_bin_std_mwea': 'mb_bin_std_mwea', - ' debris_thick_med_m': 'debris_thick_med_m', - ' debris_thick_mad_m': 'debris_thick_mad_m', - ' perc_debris': 'perc_debris', - ' perc_pond': 'perc_pond', - ' perc_clean': 'perc_clean', - ' dhdt_debris_med' : 'dhdt_debris_med', - ' dhdt_pond_med' : 'dhdt_pond_med', - ' dhdt_clean_med' : 'dhdt_clean_med', - ' vm_med' : 'vm_med', - ' vm_mad' : 'vm_mad', - ' H_mean' : 'H_mean', - ' H_std' : 'H_std'} - -def norm_stats(norm_list, option_normelev=option_normelev, option_norm_limits=False): - """ - Statistics associated with normalized elevation data - - Parameters - ---------- - norm_list : list of np.array - each item is a np.array (col 1: normalized elevation, col 2: mb, dhdt, normalized mb, or normalized dhdt) - option_norm_limits : boolean - option to place limits on the normalized dh/dt of 0 and 1 - - Returns - ------- - norm_all_stats : pd.DataFrame - statistics associated with the normalized values - """ - # Merge norm_list to make array of all glaciers with same elevation normalization space -# max_length = len(max(norm_list,key=len)) #len of glac w most norm values -# norm_all = np.zeros((max_length, len(norm_list)+1)) #array: each col a glac, each row a norm dhdt val to be interpolated -# # First column is normalized elevation, pulled from the glac with most norm vals -# norm_all[:,0] = max(norm_list,key=len)[:,0] - - # Interpolate to common normalized elevation for all glaciers - norm_elev = np.arange(0,1.01,0.01) - norm_all = np.zeros((len(norm_elev), len(norm_list)+1)) #array: each col a glac, each row norm dhdt val interpolated - norm_all[:,0] = norm_elev - - # Loop through each glacier's normalized array (where col1 is elev_norm and col2 is mb or dhdt) - for n, norm_single in enumerate(norm_list): - - if option_normelev == 'huss': - norm_single = norm_single[::-1] - - # Fill in nan values for elev_norm of 0 and 1 with nearest neighbor - nonan_idx = np.where(~np.isnan(norm_single[:,1]))[0] - norm_single[0,1] = norm_single[nonan_idx[0], 1] - norm_single[-1,1] = norm_single[nonan_idx[-1], 1] - # Remove nan values. - norm_single = norm_single[nonan_idx] - elev_single = norm_single[:,0] #set name for first col of a given glac - dhdt_single = norm_single[:,1] #set name for the second col of a given glac - #loop through each dhdt value of the glacier, and add it and interpolate to add to the norm_all array. - for r in range(0, norm_all.shape[0]): - if r == 0: - # put first value dhdt value into the norm_all. n+1 because the first col is taken by the elevnorms - norm_all[r,n+1] = dhdt_single[0] - elif r == (norm_all.shape[0] - 1): - #put last value into the the last row for the glacier's 'stretched out'(interpolated) normalized curve - norm_all[r,n+1] = dhdt_single[-1] - else: - # Find value need to interpolate to - norm_elev_value = norm_all[r,0] #go through each row in the elev (col1) - # Find index of value above it from dhdt_norm, which is a different size - upper_idx = np.where(elev_single == elev_single[elev_single >= norm_elev_value].min())[0][0] - # Find index of value below it - lower_idx = np.where(elev_single == elev_single[elev_single < norm_elev_value].max())[0][0] - #get the two values, based on the indices. - upper_elev = elev_single[upper_idx] - upper_value = dhdt_single[upper_idx] - lower_elev = elev_single[lower_idx] - lower_value = dhdt_single[lower_idx] - #Linearly Interpolate between two values, and plug in interpolated value into norm_all - norm_all[r,n+1] = (lower_value + (norm_elev_value - lower_elev) / (upper_elev - lower_elev) * - (upper_value - lower_value)) - - # Compute mean and standard deviation - norm_all_stats = pd.DataFrame() - norm_all_stats['norm_elev'] = norm_all[:,0] - norm_all_stats['norm_dhdt_med'] = np.nanmedian(norm_all[:,1:], axis=1) - norm_all_stats['norm_dhdt_nmad'] = (1.483 * - np.median(np.absolute((norm_all[:,1:] - norm_all_stats['norm_dhdt_med'][:,np.newaxis])), axis=1)) - norm_all_stats['norm_dhdt_mean'] = np.nanmean(norm_all[:,1:], axis=1) - norm_all_stats['norm_dhdt_std'] = np.nanstd(norm_all[:,1:], axis=1) - norm_all_stats['norm_dhdt_68high'] = norm_all_stats['norm_dhdt_mean'] + norm_all_stats['norm_dhdt_std'] - norm_all_stats['norm_dhdt_68low'] = norm_all_stats['norm_dhdt_mean'] - norm_all_stats['norm_dhdt_std'] - if option_norm_limits: - norm_all_stats.loc[norm_all_stats['norm_dhdt_68high'] > 1, 'norm_dhdt_68high'] = 1 - norm_all_stats.loc[norm_all_stats['norm_dhdt_68low'] < 0, 'norm_dhdt_68low'] = 0 - return norm_all_stats - - -# ===== START PROCESSING ===== -# Load mass balance summary data -if os.path.exists(dems_output_fp + mb_summary_fn): - mb_summary = pd.read_csv(dems_output_fp + mb_summary_fn) -else: - # Merge files - for n_fn, fn in enumerate(mb_summary_fn_list): - mb_summary_subset = pd.read_csv(dems_output_fp + fn) - mb_summary_subset['region'] = fn.split('_mb')[0] - if n_fn == 0: - mb_summary = mb_summary_subset - else: - mb_summary = mb_summary.append(mb_summary_subset) - # Sort and add glacier number - mb_summary = mb_summary.sort_values('RGIId') - mb_summary.reset_index(inplace=True, drop=True) - mb_summary['glacno'] = [str(int(x)).zfill(2) + '.' + str(int(np.round(x%1*10**5))).zfill(5) - for x in mb_summary['RGIId']] - # Export dataset - mb_summary.to_csv(dems_output_fp + mb_summary_fn, index=False) - -# ===== PROCESS DATA ===== -print('Glaciers total:', mb_summary.shape[0]) -if ~(type(mb_summary.loc[0,'glacno']) == str): - mb_summary['glacno'] = [str(int(x)).zfill(2) + '.' + str(int(np.round(x%1*10**5))).zfill(5) - for x in mb_summary['RGIId']] -mb_summary = mb_summary.loc[mb_summary['valid_area_perc'] >= valid_perc_threshold] -mb_summary.reset_index(inplace=True, drop=True) -mb_summary = mb_summary.loc[mb_summary['area_m2'] / 1e6 >= min_area_km2] -mb_summary.reset_index(inplace=True, drop=True) -print('Glaciers total after % threshold:', mb_summary.shape[0]) - -glacno_list = list(mb_summary.glacno.values) -main_glac_rgi = modelsetup.selectglaciersrgitable(glac_no=glacno_list) - -# ===== BINNED DATA ===== -binned_list = [] -for glacno in glacno_list: - csv_str = str(int(glacno.split('.')[0])) + '.' + glacno.split('.')[1] - - for i in os.listdir(binned_fp): - if i.startswith(csv_str) and i.endswith('_mb_bins.csv'): - binned_ds = pd.read_csv(binned_fp + i, na_values=' nan') - - # Rename columns so they are easier to read - binned_ds = binned_ds.rename(columns=sheancoldict) - # Remove bad values of dhdt - binned_ds.loc[binned_ds[mb_cn] > mb_max, mb_cn] = np.nan - binned_ds.loc[binned_ds[mb_cn] < mb_min, mb_cn] = np.nan - # If dhdt is nan, remove row - null_bins = binned_ds.loc[pd.isnull(binned_ds[mb_cn])].index.values - binned_ds = binned_ds.drop(null_bins) - - # ===== BINNED DATA NORMALIZATIONS ===== - elev_cn = binned_ds.columns[0] - glac_elev = binned_ds[elev_cn].values - glac_mb = binned_ds[mb_cn].values.astype(float) - # Larsen normalization (terminus = 0, top = 1) - if option_normelev == 'larsen': - binned_ds['elev_norm'] = (glac_elev - glac_elev[0]) / (glac_elev[-1] - glac_elev[0]) - # Huss normalization (terminus = 1, top = 0) - elif option_normelev == 'huss': - binned_ds['elev_norm'] = (glac_elev[-1] - glac_elev) / (glac_elev[-1] - glac_elev[0]) - - # Normalized ice thickness change [ma] - # dhdt / dhdt_max - # Shifted normalized ice thickness change such that everything is negative - binned_ds['mb_norm_shifted'] = (glac_mb - np.nanmax(glac_mb)) / np.nanmin(glac_mb - np.nanmax(glac_mb)) - binned_ds.loc[binned_ds['mb_norm_shifted'] == -0, 'mb_norm_shifted'] = 0 - # Replace positive values to zero - glac_mb[glac_mb >= 0] = 0 - binned_ds['mb_norm_huss'] = glac_mb / np.nanmin(glac_mb) - binned_ds.loc[binned_ds['mb_norm_huss'] == -0, 'mb_norm_huss'] = 0 - - # Append to list - binned_list.append(binned_ds) - - -#%% ===== ELEVATION VS MASS BALANCE PLOTS====== -# List of np.array where first column is elev_norm and second column is mass balance -elev_mb_list = [np.array([i[elev_cn].values, i[mb_cn].values]).transpose() for i in binned_list] -normelev_mb_list = [np.array([i['elev_norm'].values, i[mb_cn].values]).transpose() for i in binned_list] -normelev_mb_stats = norm_stats(normelev_mb_list) - -# Estimate a curve -def curve_func(x, a, b, c, d): - return (x + a)**d + b * (x + a) + c -p0 = [1,1,1,1] -coeffs, matcov = curve_fit(curve_func, normelev_mb_stats['norm_elev'].values, - normelev_mb_stats['norm_dhdt_med'].values, p0, maxfev=10000) -curve_x = np.arange(0,1.01,0.01) -curve_y = curve_func(curve_x, coeffs[0], coeffs[1], coeffs[2], coeffs[3]) - -# Plot -figwidth, figheight = 6.5, 8 -fig, ax = plt.subplots(2, 1, squeeze=False, sharex=False, sharey=False, - figsize=(figwidth,figheight), gridspec_kw = {'wspace':0.4, 'hspace':0.25}) -max_elev = 0 -for n, i in enumerate(elev_mb_list): - glac_elev = i[:,0] - glac_mb = i[:,1] - glac_elev_norm = normelev_mb_list[n][:,0] - - if glac_elev.max() > max_elev: - max_elev = glac_elev.max() - max_elev = np.ceil(max_elev/500)*500 - - # Elevation vs MB - ax[0,0].plot(glac_elev, glac_mb, linewidth=0.5, alpha=0.5) - - # Norm Elevation vs MB - # note: zorder overrides alpha, only alpha if same zorder - ax[1,0].plot(glac_elev_norm, glac_mb, linewidth=0.5, alpha=0.2, zorder=1) - ax[1,0].plot(normelev_mb_stats['norm_elev'], normelev_mb_stats['norm_dhdt_med'], - color='k', linewidth=1, alpha=1, zorder=2) - - ax[1,0].fill_between(normelev_mb_stats['norm_elev'], normelev_mb_stats['norm_dhdt_med'], - normelev_mb_stats['norm_dhdt_med'] + normelev_mb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=1) - ax[1,0].fill_between(normelev_mb_stats['norm_elev'], normelev_mb_stats['norm_dhdt_med'], - normelev_mb_stats['norm_dhdt_med'] - normelev_mb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=1) - ax[1,0].plot(curve_x, curve_y, - color='k', linewidth=1, alpha=1, linestyle='--', zorder=2) - -# niceties - Elevation vs MB -ax[0,0].set_xlabel('Elevation (m a.s.l.)', fontsize=12) -ax[0,0].xaxis.set_major_locator(MultipleLocator(500)) -ax[0,0].xaxis.set_minor_locator(MultipleLocator(100)) -ax[0,0].set_xlim(0, max_elev) -ax[0,0].set_ylabel('Mass Balance (m w.e. $\mathregular{yr{-1}}$)', fontsize=12, labelpad=10) -ax[0,0].axhline(y=0, color='k', linestyle='-', linewidth=0.5) -ax[0,0].yaxis.set_major_locator(MultipleLocator(0.5)) -ax[0,0].yaxis.set_minor_locator(MultipleLocator(0.1)) - -# niceties - Norm Elevation vs MB -ax[1,0].set_xlabel('Normalized Elevation (-)', fontsize=12) -ax[1,0].xaxis.set_major_locator(MultipleLocator(0.25)) -ax[1,0].xaxis.set_minor_locator(MultipleLocator(0.05)) -ax[1,0].set_xlim(0,1) -ax[1,0].set_ylabel('Mass Balance (m w.e. $\mathregular{yr{-1}}$)', fontsize=12, labelpad=10) -#ax[1,0].axhline(y=0, color='k', linestyle='--', linewidth=0.5) -ax[1,0].yaxis.set_major_locator(MultipleLocator(0.5)) -ax[1,0].yaxis.set_minor_locator(MultipleLocator(0.1)) -ax[1,0].set_ylim(-3,1.5) - -# Save figure -fig.set_size_inches(figwidth,figheight) -figure_fn = 'elev_mb_all_gt' + str(valid_perc_threshold) + 'pct_gt' + str(min_area_km2) + 'km2.png' -fig.savefig(fig_fp + figure_fn, bbox_inches='tight', dpi=300) - -#%% ===== REGIONAL ELEVATION VS MASS BALANCE PLOTS====== -subregions = 'O2Regions' -if subregions == 'Berthier': - regions = sorted(set(mb_summary.region.values)) - subregion_dict = {} - for region in regions: - subregion_dict[region] = region -elif subregions == 'O2Regions': - regions = sorted(set(main_glac_rgi.O2Region.values)) - subregion_dict = {2:'Alaska Range', 3:'Alaska Pena', 4:'W Chugach Mtns', 5:'St Elias Mtns', 6:'N Coast Ranges', - 9999:'All Alaska'} -reg_normelev_mb_dict = {} -regions.append(9999) - -ncols = 2 -nrows = int(np.ceil(len(regions)/ncols)) - -figwidth, figheight = 6.5, 8 -fig, ax = plt.subplots(nrows, ncols, squeeze=False, sharex=False, sharey=False, - figsize=(figwidth,figheight), gridspec_kw = {'wspace':0.25, 'hspace':0.4}) -ncol = 0 -nrow = 0 -for region in regions: - if subregions == 'Berthier': - reg_idx = list(np.where(mb_summary['region'] == region)[0]) - elif subregions =='O2Regions': - reg_idx = list(np.where(main_glac_rgi['O2Region'] == region)[0]) - if region == 9999: - reg_idx = main_glac_rgi.index.values - - - print(subregion_dict[region], 'glacier area mean/median:', np.round(main_glac_rgi.loc[reg_idx, 'Area'].mean(),1), - np.round(main_glac_rgi.loc[reg_idx, 'Area'].median(),1), np.round(main_glac_rgi.loc[reg_idx, 'Area'].std(),1)) - - reg_binned_list = [binned_list[i] for i in reg_idx] - - reg_elev_mb_list = [np.array([i[elev_cn].values, i[mb_cn].values]).transpose() for i in reg_binned_list] - reg_normelev_mb_list = [np.array([i['elev_norm'].values, i[mb_cn].values]).transpose() for i in reg_binned_list] - reg_normelev_mb_stats = norm_stats(reg_normelev_mb_list) - reg_normelev_mb_dict[region] = dict(zip((reg_normelev_mb_stats['norm_elev'].values * 100).astype(int), - reg_normelev_mb_stats['norm_dhdt_med'].values)) - - if region == 9999: - normelev_all = reg_normelev_mb_stats['norm_elev'] - dhdt_all = reg_normelev_mb_stats['norm_dhdt_med'] - - for n, i in enumerate(reg_elev_mb_list): - glac_elev = i[:,0] - glac_mb = i[:,1] - glac_elev_norm = reg_normelev_mb_list[n][:,0] - - # Norm Elevation vs MB - # note: zorder overrides alpha, only alpha if same zorder - ax[nrow,ncol].plot(glac_elev_norm, glac_mb, linewidth=0.5, alpha=0.2, zorder=1) - - # Regional curve - ax[nrow,ncol].plot(reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - color='k', linewidth=1, alpha=1, zorder=2) - ax[nrow,ncol].fill_between(reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - reg_normelev_mb_stats['norm_dhdt_med'] + reg_normelev_mb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=1) - ax[nrow,ncol].fill_between(reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - reg_normelev_mb_stats['norm_dhdt_med'] - reg_normelev_mb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=1) - - # niceties - Norm Elevation vs MB - ax[nrow,ncol].xaxis.set_major_locator(MultipleLocator(0.25)) - ax[nrow,ncol].xaxis.set_minor_locator(MultipleLocator(0.05)) - ax[nrow,ncol].set_xlim(0,1) - ax[nrow,ncol].yaxis.set_major_locator(MultipleLocator(1)) - ax[nrow,ncol].yaxis.set_minor_locator(MultipleLocator(0.25)) - ax[nrow,ncol].set_ylim(-3,1.5) - # Title - region_nglac = len(reg_normelev_mb_list) - ax[nrow,ncol].text(0.5, 1.01, subregion_dict[region] + ' (' + str(region_nglac) + ' glaciers)', size=10, - horizontalalignment='center', verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - - # Adjust row and column - ncol += 1 - if ncol == ncols: - nrow += 1 - ncol = 0 - -# Add All Alaska empirical curve to each glacier -ncol = 0 -nrow = 0 -for region in regions: - if region != 9999: - ax[nrow,ncol].plot(normelev_all, dhdt_all, color='y', linewidth=1, alpha=1, linestyle='--', zorder=4) - # Adjust row and column - ncol += 1 - if ncol == ncols: - nrow += 1 - ncol = 0 - -# Y-label -fig.text(0.04, 0.5, 'Mass Balance (m w.e. $\mathregular{yr^{-1}}$)', va='center', ha='center', - rotation='vertical', size=12) -fig.text(0.5, 0.08, 'Normalized Elevation', va='center', ha='center', size=12) - -# Save figure -fig.set_size_inches(figwidth,figheight) -figure_fn = 'elev_mb_regional_gt' + str(valid_perc_threshold) + 'pct_gt' + str(min_area_km2) + 'km2.png' -fig.savefig(fig_fp + figure_fn, bbox_inches='tight', dpi=300) - - -#%% ==== SIZE: ELEVATION VS MASS BALANCE PLOTS====== -if min_area_km2 < 5: - group_names = ['Area < 5 km$^{2}$', '5 km$^{2}$ < Area <= 20 km$^{2}$', 'Area > 20 km$^{2}$', 'All Alaska'] - group_thresholds = [(0,5), (5, 20), (20, np.inf)] -else: - group_names = ['5 km$^{2}$ < Area <= 20 km$^{2}$', 'Area > 20 km$^{2}$', 'All Alaska'] - group_thresholds = [(5, 20), (20, np.inf)] - -group_idx = [] -for group_threshold in group_thresholds: - group_idx.append(list(main_glac_rgi[(main_glac_rgi.Area > group_threshold[0]) & - (main_glac_rgi.Area <= group_threshold[1])].index.values)) -group_idx.append(list(main_glac_rgi.index.values)) - -group_ncols = 2 -group_nrows = int(np.ceil(len(group_names)/group_ncols)) -figwidth, figheight = 6.5, 8 -fig, ax = plt.subplots(group_nrows, group_ncols, squeeze=False, sharex=False, sharey=False, - figsize=(figwidth,figheight), gridspec_kw = {'wspace':0.25, 'hspace':0.4}) -ncol = 0 -nrow = 0 -for ngroup, group_name in enumerate(group_names): - reg_idx = group_idx[ngroup] - - reg_binned_list = [binned_list[i] for i in reg_idx] - - reg_elev_mb_list = [np.array([i[elev_cn].values, i[mb_cn].values]).transpose() for i in reg_binned_list] - reg_normelev_mb_list = [np.array([i['elev_norm'].values, i[mb_cn].values]).transpose() for i in reg_binned_list] - reg_normelev_mb_stats = norm_stats(reg_normelev_mb_list) - reg_normelev_mb_dict[region] = dict(zip((reg_normelev_mb_stats['norm_elev'].values * 100).astype(int), - reg_normelev_mb_stats['norm_dhdt_med'].values)) - if group_name in ['All Alaska']: - normelev_all = reg_normelev_mb_stats['norm_elev'] - dhdt_all = reg_normelev_mb_stats['norm_dhdt_med'] - - for n, i in enumerate(reg_elev_mb_list): - glac_elev = i[:,0] - glac_mb = i[:,1] - glac_elev_norm = reg_normelev_mb_list[n][:,0] - - # Norm Elevation vs MB - # note: zorder overrides alpha, only alpha if same zorder - ax[nrow,ncol].plot(glac_elev_norm, glac_mb, linewidth=0.5, alpha=0.2, zorder=1) - - # Regional curve - ax[nrow,ncol].plot(reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - color='k', linewidth=1, alpha=1, zorder=2) - ax[nrow,ncol].fill_between(reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - reg_normelev_mb_stats['norm_dhdt_med'] + reg_normelev_mb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=1) - ax[nrow,ncol].fill_between(reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - reg_normelev_mb_stats['norm_dhdt_med'] - reg_normelev_mb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=1) - - # niceties - Norm Elevation vs MB - ax[nrow,ncol].xaxis.set_major_locator(MultipleLocator(0.25)) - ax[nrow,ncol].xaxis.set_minor_locator(MultipleLocator(0.05)) - ax[nrow,ncol].set_xlim(0,1) - ax[nrow,ncol].yaxis.set_major_locator(MultipleLocator(1)) - ax[nrow,ncol].yaxis.set_minor_locator(MultipleLocator(0.25)) - ax[nrow,ncol].set_ylim(-5,1.5) - # Title - region_nglac = len(reg_normelev_mb_list) - ax[nrow,ncol].text(0.5, 1.01, group_name + ' (' + str(region_nglac) + ' glaciers)', size=10, - horizontalalignment='center', verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - - # Adjust row and column - ncol += 1 - if ncol == group_ncols: - nrow += 1 - ncol = 0 - -# Add All Alaska curve to each glacier -ncol = 0 -nrow = 0 -for group_name in group_names: - if group_name not in ['All Alaska']: - # Fitted curve - ax[nrow,ncol].plot(normelev_all, dhdt_all, color='y', linewidth=1, alpha=1, linestyle='--', zorder=4) - # Adjust row and column - ncol += 1 - if ncol == group_ncols: - nrow += 1 - ncol = 0 - -# Y-label -fig.text(0.04, 0.5, 'Mass Balance (m w.e. $\mathregular{yr^{-1}}$)', va='center', ha='center', - rotation='vertical', size=12) -fig.text(0.5, 0.08, 'Normalized Elevation', va='center', ha='center', size=12) - -# Save figure -fig.set_size_inches(figwidth,figheight) -figure_fn = 'elev_mb_SIZE_gt' + str(valid_perc_threshold) + 'pct_gt' + str(min_area_km2) + 'km2.png' -fig.savefig(fig_fp + figure_fn, bbox_inches='tight', dpi=300) - - -#%% ==== TERIMNUS TYPE: ELEVATION VS MASS BALANCE PLOTS====== -group_names = ['Land', 'Tidewater', 'Lake', 'All Alaska'] -group_idx = [] -for group_value in [0,1,2]: - group_idx.append(list(main_glac_rgi[main_glac_rgi.TermType == group_value].index.values)) -group_idx.append(list(main_glac_rgi.index.values)) - -group_ncols = 2 -group_nrows = int(np.ceil(len(group_names)/group_ncols)) - -figwidth, figheight = 6.5, 8 -fig, ax = plt.subplots(group_nrows, group_ncols, squeeze=False, sharex=False, sharey=False, - figsize=(figwidth,figheight), gridspec_kw = {'wspace':0.25, 'hspace':0.4}) -ncol = 0 -nrow = 0 -for ngroup, group_name in enumerate(group_names): - reg_idx = group_idx[ngroup] - - reg_binned_list = [binned_list[i] for i in reg_idx] - - reg_elev_mb_list = [np.array([i[elev_cn].values, i[mb_cn].values]).transpose() for i in reg_binned_list] - reg_normelev_mb_list = [np.array([i['elev_norm'].values, i[mb_cn].values]).transpose() for i in reg_binned_list] - reg_normelev_mb_stats = norm_stats(reg_normelev_mb_list) - reg_normelev_mb_dict[region] = dict(zip((reg_normelev_mb_stats['norm_elev'].values * 100).astype(int), - reg_normelev_mb_stats['norm_dhdt_med'].values)) - if group_name in ['All Alaska']: - normelev_all = reg_normelev_mb_stats['norm_elev'] - dhdt_all = reg_normelev_mb_stats['norm_dhdt_med'] - - for n, i in enumerate(reg_elev_mb_list): - glac_elev = i[:,0] - glac_mb = i[:,1] - glac_elev_norm = reg_normelev_mb_list[n][:,0] - - # Norm Elevation vs MB - # note: zorder overrides alpha, only alpha if same zorder - ax[nrow,ncol].plot(glac_elev_norm, glac_mb, linewidth=0.5, alpha=0.2, zorder=1) - - # Regional curve - ax[nrow,ncol].plot(reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - color='k', linewidth=1, alpha=1, zorder=2) - ax[nrow,ncol].fill_between(reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - reg_normelev_mb_stats['norm_dhdt_med'] + reg_normelev_mb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=1) - ax[nrow,ncol].fill_between(reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - reg_normelev_mb_stats['norm_dhdt_med'] - reg_normelev_mb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=1) - - # niceties - Norm Elevation vs MB - ax[nrow,ncol].xaxis.set_major_locator(MultipleLocator(0.25)) - ax[nrow,ncol].xaxis.set_minor_locator(MultipleLocator(0.05)) - ax[nrow,ncol].set_xlim(0,1) - ax[nrow,ncol].yaxis.set_major_locator(MultipleLocator(1)) - ax[nrow,ncol].yaxis.set_minor_locator(MultipleLocator(0.25)) - ax[nrow,ncol].set_ylim(-5,1.5) - # Title - region_nglac = len(reg_normelev_mb_list) - ax[nrow,ncol].text(0.5, 1.01, group_name + ' (' + str(region_nglac) + ' glaciers)', size=10, - horizontalalignment='center', verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - - # Adjust row and column - ncol += 1 - if ncol == group_ncols: - nrow += 1 - ncol = 0 - -# Add All Alaska empirical curve to each glacier -ncol = 0 -nrow = 0 -for ngroup, group_name in enumerate(group_names): - if group_name not in ['All Alaska']: - ax[nrow,ncol].plot(normelev_all, dhdt_all, color='y', linewidth=1, alpha=1, linestyle='--', zorder=4) - # Adjust row and column - ncol += 1 - if ncol == group_ncols: - nrow += 1 - ncol = 0 - -# Y-label -fig.text(0.04, 0.5, 'Mass Balance (m w.e. $\mathregular{yr^{-1}}$)', va='center', ha='center', - rotation='vertical', size=12) -fig.text(0.5, 0.08, 'Normalized Elevation', va='center', ha='center', size=12) - -# Save figure -fig.set_size_inches(figwidth,figheight) -figure_fn = 'elev_mb_TERMTYPE_gt' + str(valid_perc_threshold) + 'pct_gt' + str(min_area_km2) + 'km2.png' -fig.savefig(fig_fp + figure_fn, bbox_inches='tight', dpi=300) - -#%% ==== TERMINUS TYPE & SIZE: ELEVATION VS MASS BALANCE PLOTS====== -group_names = ['Tidewater', 'Lake', 'Land (A < 5 km$^{2}$)', 'Land (5 < A < 20 km$^{2}$)', - 'Land (A > 20 km$^{2}$)', 'All Alaska'] -group_idx = [] -for group_name in group_names: - if group_name == 'Tidewater': - group_idx.append(list(main_glac_rgi[main_glac_rgi.TermType == 1].index.values)) - elif group_name == 'Lake': - group_idx.append(list(main_glac_rgi[main_glac_rgi.TermType == 2].index.values)) - elif group_name == 'Land (A < 5 km$^{2}$)': - group_idx.append(list(main_glac_rgi[(main_glac_rgi.TermType == 0) & (main_glac_rgi.Area <= 5)].index.values)) - elif group_name == 'Land (5 < A < 20 km$^{2}$)': - group_idx.append(list(main_glac_rgi[(main_glac_rgi.TermType == 0) & (main_glac_rgi.Area > 5) & - (main_glac_rgi.Area <= 20)].index.values)) - elif group_name == 'Land (A > 20 km$^{2}$)': - group_idx.append(list(main_glac_rgi[(main_glac_rgi.TermType == 0) & (main_glac_rgi.Area > 20)].index.values)) - elif group_name == 'All Alaska': - group_idx.append(list(main_glac_rgi.index.values)) - -group_ncols = 2 -group_nrows = int(np.ceil(len(group_names)/group_ncols)) -figwidth, figheight = 6.5, 8 -fig, ax = plt.subplots(group_nrows, group_ncols, squeeze=False, sharex=False, sharey=False, - figsize=(figwidth,figheight), gridspec_kw = {'wspace':0.25, 'hspace':0.4}) -ncol = 0 -nrow = 0 -for ngroup, group_name in enumerate(group_names): - reg_idx = group_idx[ngroup] - - reg_binned_list = [binned_list[i] for i in reg_idx] - - reg_elev_mb_list = [np.array([i[elev_cn].values, i[mb_cn].values]).transpose() for i in reg_binned_list] - reg_normelev_mb_list = [np.array([i['elev_norm'].values, i[mb_cn].values]).transpose() for i in reg_binned_list] - reg_normelev_mb_stats = norm_stats(reg_normelev_mb_list) - reg_normelev_mb_dict[region] = dict(zip((reg_normelev_mb_stats['norm_elev'].values * 100).astype(int), - reg_normelev_mb_stats['norm_dhdt_med'].values)) - if group_name in ['All Alaska']: - normelev_all = reg_normelev_mb_stats['norm_elev'] - dhdt_all = reg_normelev_mb_stats['norm_dhdt_med'] - - for n, i in enumerate(reg_elev_mb_list): - glac_elev = i[:,0] - glac_mb = i[:,1] - glac_elev_norm = reg_normelev_mb_list[n][:,0] - - # Norm Elevation vs MB - # note: zorder overrides alpha, only alpha if same zorder - ax[nrow,ncol].plot(glac_elev_norm, glac_mb, linewidth=0.5, alpha=0.2, zorder=1) - - # Regional curve - ax[nrow,ncol].plot(reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - color='k', linewidth=1, alpha=1, zorder=2) - ax[nrow,ncol].fill_between(reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - reg_normelev_mb_stats['norm_dhdt_med'] + reg_normelev_mb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=1) - ax[nrow,ncol].fill_between(reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - reg_normelev_mb_stats['norm_dhdt_med'] - reg_normelev_mb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=1) - - # niceties - Norm Elevation vs MB - ax[nrow,ncol].xaxis.set_major_locator(MultipleLocator(0.25)) - ax[nrow,ncol].xaxis.set_minor_locator(MultipleLocator(0.05)) - ax[nrow,ncol].set_xlim(0,1) - ax[nrow,ncol].yaxis.set_major_locator(MultipleLocator(1)) - ax[nrow,ncol].yaxis.set_minor_locator(MultipleLocator(0.25)) - ax[nrow,ncol].set_ylim(-5,1.5) - # Title - region_nglac = len(reg_normelev_mb_list) - ax[nrow,ncol].text(0.5, 1.01, group_name + ' (' + str(region_nglac) + ' glaciers)', size=10, - horizontalalignment='center', verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - - # Adjust row and column - ncol += 1 - if ncol == group_ncols: - nrow += 1 - ncol = 0 - -# Add All Alaska curve to each glacier -ncol = 0 -nrow = 0 -for group_name in group_names: - if group_name not in ['All Alaska']: - # Fitted curve - ax[nrow,ncol].plot(normelev_all, dhdt_all, color='y', linewidth=1, alpha=1, linestyle='--', zorder=4) - # Adjust row and column - ncol += 1 - if ncol == group_ncols: - nrow += 1 - ncol = 0 - -# Y-label -fig.text(0.04, 0.5, 'Mass Balance (m w.e. $\mathregular{yr^{-1}}$)', va='center', ha='center', - rotation='vertical', size=12) -fig.text(0.5, 0.08, 'Normalized Elevation', va='center', ha='center', size=12) - -# Save figure -fig.set_size_inches(figwidth,figheight) -figure_fn = 'elev_mb_TERMTYPE-SIZE_gt' + str(valid_perc_threshold) + 'pct_gt' + str(min_area_km2) + 'km2.png' -fig.savefig(fig_fp + figure_fn, bbox_inches='tight', dpi=300) - -#%% ==== TERIMNUS TYPE - LARSEN: ELEVATION VS MASS BALANCE PLOTS====== -group_names = ['Land', 'Lake', 'Tidewater'] -group_idx = [] -for group_value in [0,2,1]: - group_idx.append(list(main_glac_rgi[main_glac_rgi.TermType == group_value].index.values)) - -figwidth, figheight = 3, 6.5 -fig, ax = plt.subplots(3, 1, squeeze=False, sharex=False, sharey=False, - figsize=(figwidth,figheight), gridspec_kw = {'wspace':0.25, 'hspace':0.2}) -ncol = 0 -nrow = 0 -for ngroup, group_name in enumerate(group_names): - reg_idx = group_idx[ngroup] - - reg_binned_list = [binned_list[i] for i in reg_idx] - - reg_elev_mb_list = [np.array([i[elev_cn].values, i[mb_cn].values]).transpose() for i in reg_binned_list] - reg_normelev_mb_list = [np.array([i['elev_norm'].values, i[mb_cn].values]).transpose() for i in reg_binned_list] - reg_normelev_mb_stats = norm_stats(reg_normelev_mb_list) - reg_normelev_mb_dict[region] = dict(zip((reg_normelev_mb_stats['norm_elev'].values * 100).astype(int), - reg_normelev_mb_stats['norm_dhdt_med'].values)) - - for n, i in enumerate(reg_elev_mb_list): - glac_elev = i[:,0] - glac_mb = i[:,1] - glac_elev_norm = reg_normelev_mb_list[n][:,0] - - # Norm Elevation vs MB - # note: zorder overrides alpha, only alpha if same zorder - ax[nrow,ncol].plot(1 - glac_elev_norm, glac_mb, linewidth=0.5, alpha=0.2, zorder=1) - - # Regional curve - ax[nrow,ncol].plot(1 - reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - color='k', linewidth=1, alpha=1, zorder=2) - ax[nrow,ncol].fill_between(1 - reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - reg_normelev_mb_stats['norm_dhdt_med'] + reg_normelev_mb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=1) - ax[nrow,ncol].fill_between(1 - reg_normelev_mb_stats['norm_elev'], reg_normelev_mb_stats['norm_dhdt_med'], - reg_normelev_mb_stats['norm_dhdt_med'] - reg_normelev_mb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=1) - - # niceties - Norm Elevation vs MB - ax[nrow,ncol].xaxis.set_major_locator(MultipleLocator(0.2)) - ax[nrow,ncol].xaxis.set_minor_locator(MultipleLocator(0.1)) - ax[nrow,ncol].set_xlim(0,1) - ax[nrow,ncol].tick_params(labelsize=10) - if group_name in ['Land', 'Lake']: - ax[nrow,ncol].set_ylim(-6,1) - ax[nrow,ncol].yaxis.set_major_locator(MultipleLocator(1)) - ax[nrow,ncol].yaxis.set_minor_locator(MultipleLocator(0.5)) - elif group_name == 'Tidewater': - ax[nrow,ncol].set_ylim(-10,12) - ax[nrow,ncol].yaxis.set_major_locator(MultipleLocator(5)) - ax[nrow,ncol].yaxis.set_minor_locator(MultipleLocator(1)) - # Title - region_nglac = len(reg_normelev_mb_list) - ax[nrow,ncol].text(0.5, 0.05, group_name + ' (' + str(region_nglac) + ' glaciers)', size=12, - horizontalalignment='center', verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - - # Adjust row - nrow += 1 - -# Y-label -fig.text(-0.02, 0.5, 'Mass Balance (m w.e. $\mathregular{yr^{-1}}$)', va='center', ha='center', - rotation='vertical', size=12) -fig.text(0.5, 0.07, 'Normalized Elevation', va='center', ha='center', size=12) - -# Save figure -fig.set_size_inches(figwidth,figheight) -figure_fn = 'elev_mb_TERMTYPE-Larsen_gt' + str(valid_perc_threshold) + 'pct_gt' + str(min_area_km2) + 'km2.png' -fig.savefig(fig_fp + figure_fn, bbox_inches='tight', dpi=300) - -#%% ===== REGIONAL: NORMALIZED ELEVATION VS NORMALIZED MASS BALANCE PLOT====== -subregions = 'O2Regions' -if subregions == 'Berthier': - regions = sorted(set(mb_summary.region.values)) - subregion_dict = {} - for region in regions: - subregion_dict[region] = region -elif subregions == 'O2Regions': - regions = sorted(set(main_glac_rgi.O2Region.values)) - subregion_dict = {2:'Alaska Range', 3:'Alaska Pena', 4:'W Chugach Mtns', 5:'St Elias Mtns', 6:'N Coast Ranges', - 9999:'All Alaska'} -reg_normelev_mb_dict = {} -regions.append(9999) - -ncols = 2 -nrows = int(np.ceil(len(regions)/ncols)) -figwidth, figheight = 6.5, 8 -fig, ax = plt.subplots(nrows, ncols, squeeze=False, sharex=False, sharey=False, - figsize=(figwidth,figheight), gridspec_kw = {'wspace':0.25, 'hspace':0.4}) -ncol = 0 -nrow = 0 -for region in regions: - if subregions == 'Berthier': - reg_idx = list(np.where(mb_summary['region'] == region)[0]) - elif subregions =='O2Regions': - reg_idx = list(np.where(main_glac_rgi['O2Region'] == region)[0]) - if region == 9999: - reg_idx = main_glac_rgi.index.values - - reg_binned_list = [binned_list[i] for i in reg_idx] - - mb_norm_cn = 'mb_norm_huss' - - # If mb_norm_huss, then remove glaciers with all positive values - if mb_norm_cn == 'mb_norm_huss': - reg_idx_allnan = [] - for n, reg_binned_data in enumerate(reg_binned_list): - if np.isnan(reg_binned_data[mb_norm_cn]).any() == True: - reg_idx_allnan.append(n) - for n in sorted(reg_idx_allnan, reverse=True): - del reg_binned_list[n] - - reg_normelev_normmb_list = [np.array([i['elev_norm'].values, i[mb_norm_cn].values]).transpose() - for i in reg_binned_list] - reg_normelev_normmb_stats = norm_stats(reg_normelev_normmb_list) - - # Estimate a curve - # Two steps: (1) estimate d to nearest integer and avoid nan issues, (2) force d to be an integer and optimize - # bounds ensure - x = reg_normelev_normmb_stats['norm_elev'].values - y = reg_normelev_normmb_stats['norm_dhdt_med'].values - def curve_func_raw(x, a, b, c, d): - y = (x + a)**d + b * (x + a) + c - # avoid errors with np.arrays where negative number to power returns NaN - replace with 0 - y = np.nan_to_num(y) - return y - def curve_func(x, a, b, c, d): - # force d to be an integer - d = int(np.round(d,0)) - y = (x + a)**d + b * (x + a) + c - return y - p0 = [-0.02,0.12,0,3] - bnd_low = [-np.inf, -np.inf, -np.inf, 0] - bnd_high = [np.inf, np.inf, np.inf, np.inf] - coeffs, matcov = curve_fit(curve_func_raw, x, y, p0, bounds=(bnd_low, bnd_high), maxfev=10000) - # specify integer for d - p0[3] = int(np.round(coeffs[3],0)) - coeffs, matcov = curve_fit(curve_func, x, y, p0, bounds=(bnd_low, bnd_high), maxfev=10000) - # Round coefficients - coeffs[0] = np.round(coeffs[0],2) - coeffs[1] = np.round(coeffs[1],2) - coeffs[2] = np.round(coeffs[2],2) - - glac_elev_norm = np.arange(0,1.01,0.01) - curve_y = curve_func(glac_elev_norm, coeffs[0], coeffs[1], coeffs[2], coeffs[3]) - if region == 9999: - curve_y_all = curve_y.copy() - - # Plot regional curves - ax[nrow,ncol].plot(reg_normelev_normmb_stats['norm_elev'], reg_normelev_normmb_stats['norm_dhdt_med'], - color='k', linewidth=2, alpha=0.5, zorder=4) - ax[nrow,ncol].fill_between(reg_normelev_normmb_stats['norm_elev'], reg_normelev_normmb_stats['norm_dhdt_med'], - reg_normelev_normmb_stats['norm_dhdt_med'] + reg_normelev_normmb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=2) - ax[nrow,ncol].fill_between(reg_normelev_normmb_stats['norm_elev'], reg_normelev_normmb_stats['norm_dhdt_med'], - reg_normelev_normmb_stats['norm_dhdt_med'] - reg_normelev_normmb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=2) - # Fitted curve - if region != 9999: - color_curve = 'k' - else: - color_curve = 'y' - ax[nrow,ncol].plot(glac_elev_norm, curve_y, color=color_curve, linewidth=1, alpha=1, linestyle='--', zorder=5) - # Huss curve - huss_y_lrg = (glac_elev_norm - 0.02)**6 + 0.12 * (glac_elev_norm - 0.02) - huss_y_med = (glac_elev_norm - 0.05)**4 + 0.19 * (glac_elev_norm - 0.05) + 0.01 - huss_y_sml = (glac_elev_norm - 0.30)**2 + 0.60 * (glac_elev_norm - 0.30) + 0.09 - ax[nrow,ncol].plot(glac_elev_norm, huss_y_lrg, linewidth=1, color='red', linestyle='-.', alpha=1, zorder=3) - ax[nrow,ncol].plot(glac_elev_norm, huss_y_med, linewidth=1, color='green', linestyle='-.', alpha=1, zorder=3) - ax[nrow,ncol].plot(glac_elev_norm, huss_y_sml, linewidth=1, color='blue', linestyle='-.', alpha=1, zorder=3) - - - # Individual curves - for n, i in enumerate(reg_normelev_normmb_list): - glac_elev_norm_single = reg_normelev_normmb_list[n][:,0] - glac_mb_norm_single = reg_normelev_normmb_list[n][:,1] - # note: zorder overrides alpha, only alpha if same zorder - ax[nrow,ncol].plot(glac_elev_norm_single, glac_mb_norm_single, linewidth=0.25, alpha=0.2, zorder=1) - - # Niceties - ax[nrow,ncol].xaxis.set_major_locator(MultipleLocator(0.25)) - ax[nrow,ncol].xaxis.set_minor_locator(MultipleLocator(0.05)) - ax[nrow,ncol].set_xlim(0,1) - ax[nrow,ncol].yaxis.set_major_locator(MultipleLocator(1)) - ax[nrow,ncol].yaxis.set_minor_locator(MultipleLocator(0.25)) - ax[nrow,ncol].set_ylim(1.05,-0.05) - # Title - region_nglac = len(reg_normelev_normmb_list) - ax[nrow,ncol].text(0.5, 1.01, subregion_dict[region] + ' (' + str(region_nglac) + ' glaciers)', size=10, - horizontalalignment='center', verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - # Equation - signs = ['+', '+', '+'] - for nsign, coeff in enumerate(coeffs[0:3]): - if coeff < 0: - signs[nsign] = '-' - eqn_txt = 'dh=(x+a)$^{d}$+b(x+a)+c' - ax[nrow,ncol].text(0.05, 0.45, 'a=' + '{:.2f}'.format(coeffs[0]), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.35, 'b=' + '{:.2f}'.format(coeffs[1]), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.25, 'c=' + '{:.2f}'.format(coeffs[2]), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.15, 'd=' + str(int(coeffs[3])), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.05, eqn_txt, size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - - # Adjust row and column - ncol += 1 - if ncol == ncols: - nrow += 1 - ncol = 0 - -# Add All Alaska curve to each glacier -ncol = 0 -nrow = 0 -for region in regions: - if region != 9999: - # Fitted curve - ax[nrow,ncol].plot(glac_elev_norm, curve_y_all, color='y', linewidth=1, alpha=1, linestyle='--', zorder=4) - # Adjust row and column - ncol += 1 - if ncol == ncols: - nrow += 1 - ncol = 0 - -# Legend -leg_labels = ['Median', 'Curve', 'Curve-all', 'H-small', 'H-medium', 'H-large'] -#leg_labels = ['Median', 'Curve_fit', 'Huss-small', 'Huss-medium', 'Huss-large'] -#leg_linestyles = ['-', '--', '--', '--', '--'] -leg_linestyles = ['-', '--', '--', '-.', '-.', '-.'] -leg_colors = ['dimgray', 'k', 'y', 'b', 'g', 'r'] -leg_lines = [] -for nline, label in enumerate(leg_labels): -# line = Line2D([0,1],[0,1], color='white') -# leg_lines.append(line) -# leg_labels.append('') - line = Line2D([0,0],[0,0], color=leg_colors[nline], linestyle=leg_linestyles[nline], linewidth=1.5) - leg_lines.append(line) -fig.legend(leg_lines, leg_labels, loc='lower center', - bbox_to_anchor=(0.5,0.01), handlelength=1.5, handletextpad=0.25, borderpad=0.2, frameon=True, - ncol=len(leg_labels), columnspacing=0.75) - -# Y-label -fig.text(0.04, 0.5, 'Normalized Mass Balance', va='center', ha='center', - rotation='vertical', size=12) -fig.text(0.5, 0.08, 'Normalized Elevation', va='center', ha='center', size=12) - -# Save figure -fig.set_size_inches(figwidth,figheight) -figure_fn = 'normelev_normmb_regional_gt' + str(valid_perc_threshold) + 'pct_gt' + str(min_area_km2) + 'km2.png' -fig.savefig(fig_fp + figure_fn, bbox_inches='tight', dpi=300) - -#%% ===== GLACIER SIZE: NORMALIZED ELEVATION VS NORMALIZED MASS BALANCE PLOT====== -if min_area_km2 < 5: - group_names = ['Area < 5 km$^{2}$', '5 km$^{2}$ < Area <= 20 km$^{2}$', 'Area > 20 km$^{2}$', 'All Alaska'] - group_thresholds = [(0,5), (5, 20), (20, np.inf)] -else: - group_names = ['5 km$^{2}$ < Area <= 20 km$^{2}$', 'Area > 20 km$^{2}$', 'All Alaska'] - group_thresholds = [(5, 20), (20, np.inf)] - -group_idx = [] -for group_threshold in group_thresholds: - group_idx.append(list(main_glac_rgi[(main_glac_rgi.Area > group_threshold[0]) & - (main_glac_rgi.Area <= group_threshold[1])].index.values)) -group_idx.append(list(main_glac_rgi.index.values)) - -group_ncols = 2 -group_nrows = int(np.ceil(len(group_names)/group_ncols)) -figwidth, figheight = 6.5, 8 -fig, ax = plt.subplots(group_nrows, group_ncols, squeeze=False, sharex=False, sharey=False, - figsize=(figwidth,figheight), gridspec_kw = {'wspace':0.25, 'hspace':0.4}) -ncol = 0 -nrow = 0 -for ngroup, group_name in enumerate(group_names): - print(group_name) - reg_idx = group_idx[ngroup] - - reg_binned_list = [binned_list[i] for i in reg_idx] - - mb_norm_cn = 'mb_norm_huss' - - # If mb_norm_huss, then remove glaciers with all positive values - if mb_norm_cn == 'mb_norm_huss': - reg_idx_allnan = [] - for n, reg_binned_data in enumerate(reg_binned_list): - if np.isnan(reg_binned_data[mb_norm_cn]).any() == True: - reg_idx_allnan.append(n) - for n in sorted(reg_idx_allnan, reverse=True): - del reg_binned_list[n] - - reg_normelev_normmb_list = [np.array([i['elev_norm'].values, i[mb_norm_cn].values]).transpose() - for i in reg_binned_list] - reg_normelev_normmb_stats = norm_stats(reg_normelev_normmb_list) - - # Estimate a curve - # Two steps: (1) estimate d to nearest integer and avoid nan issues, (2) force d to be an integer and optimize - # bounds ensure - x = reg_normelev_normmb_stats['norm_elev'].values - y = reg_normelev_normmb_stats['norm_dhdt_med'].values - def curve_func_raw(x, a, b, c, d): - y = (x + a)**d + b * (x + a) + c - # avoid errors with np.arrays where negative number to power returns NaN - replace with 0 - y = np.nan_to_num(y) - return y - def curve_func(x, a, b, c, d): - # force d to be an integer - d = int(np.round(d,0)) - y = (x + a)**d + b * (x + a) + c - return y - p0 = [-0.02,0.12,0,3] - bnd_low = [-np.inf, -np.inf, -np.inf, 0] - bnd_high = [np.inf, np.inf, np.inf, np.inf] - coeffs, matcov = curve_fit(curve_func_raw, x, y, p0, bounds=(bnd_low, bnd_high), maxfev=10000) - # specify integer for d - coeffs, matcov = curve_fit(curve_func, x, y, p0, bounds=(bnd_low, bnd_high), maxfev=10000) - # Round coefficients - coeffs[0] = np.round(coeffs[0],2) - coeffs[1] = np.round(coeffs[1],2) - coeffs[2] = np.round(coeffs[2],2) - - glac_elev_norm = np.arange(0,1.01,0.01) - curve_y = curve_func(glac_elev_norm, coeffs[0], coeffs[1], coeffs[2], coeffs[3]) - if group_name in ['All Alaska']: - curve_y_all = curve_y.copy() - - # Plot regional curves - ax[nrow,ncol].plot(reg_normelev_normmb_stats['norm_elev'], reg_normelev_normmb_stats['norm_dhdt_med'], - color='k', linewidth=2, alpha=0.5, zorder=4) - ax[nrow,ncol].fill_between(reg_normelev_normmb_stats['norm_elev'], reg_normelev_normmb_stats['norm_dhdt_med'], - reg_normelev_normmb_stats['norm_dhdt_med'] + reg_normelev_normmb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=2) - ax[nrow,ncol].fill_between(reg_normelev_normmb_stats['norm_elev'], reg_normelev_normmb_stats['norm_dhdt_med'], - reg_normelev_normmb_stats['norm_dhdt_med'] - reg_normelev_normmb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=2) - # Fitted curve - if group_name not in ['All Alaska']: - color_curve = 'k' - else: - color_curve = 'y' - ax[nrow,ncol].plot(glac_elev_norm, curve_y, color=color_curve, linewidth=1, alpha=1, linestyle='--', zorder=5) - # Huss curve - huss_y_lrg = (glac_elev_norm - 0.02)**6 + 0.12 * (glac_elev_norm - 0.02) - huss_y_med = (glac_elev_norm - 0.05)**4 + 0.19 * (glac_elev_norm - 0.05) + 0.01 - huss_y_sml = (glac_elev_norm - 0.30)**2 + 0.60 * (glac_elev_norm - 0.30) + 0.09 - ax[nrow,ncol].plot(glac_elev_norm, huss_y_lrg, linewidth=1, color='red', linestyle='-.', alpha=1, zorder=3) - ax[nrow,ncol].plot(glac_elev_norm, huss_y_med, linewidth=1, color='green', linestyle='-.', alpha=1, zorder=3) - ax[nrow,ncol].plot(glac_elev_norm, huss_y_sml, linewidth=1, color='blue', linestyle='-.', alpha=1, zorder=3) - - # Individual curves - for n, i in enumerate(reg_normelev_normmb_list): - glac_elev_norm_single = reg_normelev_normmb_list[n][:,0] - glac_mb_norm_single = reg_normelev_normmb_list[n][:,1] - # note: zorder overrides alpha, only alpha if same zorder - ax[nrow,ncol].plot(glac_elev_norm_single, glac_mb_norm_single, linewidth=0.25, alpha=0.2, zorder=1) - - # Niceties - ax[nrow,ncol].xaxis.set_major_locator(MultipleLocator(0.25)) - ax[nrow,ncol].xaxis.set_minor_locator(MultipleLocator(0.05)) - ax[nrow,ncol].set_xlim(0,1) - ax[nrow,ncol].yaxis.set_major_locator(MultipleLocator(1)) - ax[nrow,ncol].yaxis.set_minor_locator(MultipleLocator(0.25)) - ax[nrow,ncol].set_ylim(1.05,-0.05) - # Title - region_nglac = len(reg_normelev_normmb_list) - ax[nrow,ncol].text(0.5, 1.01, group_name + ' (' + str(region_nglac) + ' glaciers)', size=10, - horizontalalignment='center', verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - # Equation - signs = ['+', '+', '+'] - for nsign, coeff in enumerate(coeffs[0:3]): - if coeff < 0: - signs[nsign] = '-' - eqn_txt = 'dh=(x+a)$^{d}$+b(x+a)+c' - ax[nrow,ncol].text(0.05, 0.45, 'a=' + '{:.2f}'.format(coeffs[0]), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.35, 'b=' + '{:.2f}'.format(coeffs[1]), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.25, 'c=' + '{:.2f}'.format(coeffs[2]), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.15, 'd=' + str(int(coeffs[3])), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.05, eqn_txt, size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - - # Adjust row and column - ncol += 1 - if ncol == group_ncols: - nrow += 1 - ncol = 0 - -# Add All Alaska curve to each glacier -ncol = 0 -nrow = 0 -for group_name in group_names: - if group_name not in ['All Alaska']: - # Fitted curve - ax[nrow,ncol].plot(glac_elev_norm, curve_y_all, color='y', linewidth=1, alpha=1, linestyle='--', zorder=4) - # Adjust row and column - ncol += 1 - if ncol == group_ncols: - nrow += 1 - ncol = 0 - -# Legend -leg_labels = ['Median', 'Curve', 'Curve-all', 'H-small', 'H-medium', 'H-large'] -#leg_labels = ['Median', 'Curve_fit', 'Huss-small', 'Huss-medium', 'Huss-large'] -#leg_linestyles = ['-', '--', '--', '--', '--'] -leg_linestyles = ['-', '--', '--', '-.', '-.', '-.'] -leg_colors = ['dimgray', 'k', 'y', 'b', 'g', 'r'] -leg_lines = [] -for nline, label in enumerate(leg_labels): -# line = Line2D([0,1],[0,1], color='white') -# leg_lines.append(line) -# leg_labels.append('') - line = Line2D([0,0],[0,0], color=leg_colors[nline], linestyle=leg_linestyles[nline], linewidth=1.5) - leg_lines.append(line) -fig.legend(leg_lines, leg_labels, loc='lower center', - bbox_to_anchor=(0.5,0.01), handlelength=1.5, handletextpad=0.25, borderpad=0.2, frameon=True, - ncol=len(leg_labels), columnspacing=0.75) - -# Y-label -fig.text(0.04, 0.5, 'Normalized Mass Balance', va='center', ha='center', - rotation='vertical', size=12) -fig.text(0.5, 0.08, 'Normalized Elevation', va='center', ha='center', size=12) - -# Save figure -fig.set_size_inches(figwidth,figheight) -figure_fn = 'normelev_normmb_SIZE_gt' + str(valid_perc_threshold) + 'pct_gt' + str(min_area_km2) + 'km2.png' -fig.savefig(fig_fp + figure_fn, bbox_inches='tight', dpi=300) - -#%% ===== TERMINUS TYPE: NORMALIZED ELEVATION VS NORMALIZED MASS BALANCE PLOT====== -group_names = ['Land', 'Lake', 'Tidewater', 'All Alaska'] -group_idx = [] -for group_value in [0,2,1]: - group_idx.append(list(main_glac_rgi[main_glac_rgi.TermType == group_value].index.values)) -group_idx.append(main_glac_rgi.index.values) - -group_ncols = 2 -group_nrows = int(np.ceil(len(group_names)/group_ncols)) - -figwidth, figheight = 6.5, 8 -fig, ax = plt.subplots(group_nrows, group_ncols, squeeze=False, sharex=False, sharey=False, - figsize=(figwidth,figheight), gridspec_kw = {'wspace':0.25, 'hspace':0.4}) -ncol = 0 -nrow = 0 -for ngroup, group_name in enumerate(group_names): - reg_idx = group_idx[ngroup] - - reg_binned_list = [binned_list[i] for i in reg_idx] - - mb_norm_cn = 'mb_norm_huss' - - # If mb_norm_huss, then remove glaciers with all positive values - if mb_norm_cn == 'mb_norm_huss': - reg_idx_allnan = [] - for n, reg_binned_data in enumerate(reg_binned_list): - if np.isnan(reg_binned_data[mb_norm_cn]).any() == True: - reg_idx_allnan.append(n) - for n in sorted(reg_idx_allnan, reverse=True): - del reg_binned_list[n] - - reg_normelev_normmb_list = [np.array([i['elev_norm'].values, i[mb_norm_cn].values]).transpose() - for i in reg_binned_list] - reg_normelev_normmb_stats = norm_stats(reg_normelev_normmb_list) - - # Estimate a curve - # Two steps: (1) estimate d to nearest integer and avoid nan issues, (2) force d to be an integer and optimize - # bounds ensure - x = reg_normelev_normmb_stats['norm_elev'].values - y = reg_normelev_normmb_stats['norm_dhdt_med'].values - def curve_func_raw(x, a, b, c, d): - y = (x + a)**d + b * (x + a) + c - # avoid errors with np.arrays where negative number to power returns NaN - replace with 0 - y = np.nan_to_num(y) - return y - def curve_func(x, a, b, c, d): - # force d to be an integer - d = int(np.round(d,0)) - y = (x + a)**d + b * (x + a) + c - return y - p0 = [-0.02,0.12,0,3] - bnd_low = [-np.inf, -np.inf, -np.inf, 0] - bnd_high = [np.inf, np.inf, np.inf, np.inf] - coeffs, matcov = curve_fit(curve_func_raw, x, y, p0, bounds=(bnd_low, bnd_high), maxfev=10000) - # specify integer for d - p0[3] = int(np.round(coeffs[3],0)) - coeffs, matcov = curve_fit(curve_func, x, y, p0, bounds=(bnd_low, bnd_high), maxfev=10000) - # Round coefficients - coeffs[0] = np.round(coeffs[0],2) - coeffs[1] = np.round(coeffs[1],2) - coeffs[2] = np.round(coeffs[2],2) - - glac_elev_norm = np.arange(0,1.01,0.01) - curve_y = curve_func(glac_elev_norm, coeffs[0], coeffs[1], coeffs[2], coeffs[3]) - if group_name in ['All Alaska']: - curve_y_all = curve_y.copy() - - # Plot regional curves - ax[nrow,ncol].plot(reg_normelev_normmb_stats['norm_elev'], reg_normelev_normmb_stats['norm_dhdt_med'], - color='k', linewidth=2, alpha=0.5, zorder=4) - ax[nrow,ncol].fill_between(reg_normelev_normmb_stats['norm_elev'], reg_normelev_normmb_stats['norm_dhdt_med'], - reg_normelev_normmb_stats['norm_dhdt_med'] + reg_normelev_normmb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=2) - ax[nrow,ncol].fill_between(reg_normelev_normmb_stats['norm_elev'], reg_normelev_normmb_stats['norm_dhdt_med'], - reg_normelev_normmb_stats['norm_dhdt_med'] - reg_normelev_normmb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=2) - # Fitted curve - if group_name not in ['All Alaska']: - color_curve = 'k' - else: - color_curve = 'y' - ax[nrow,ncol].plot(glac_elev_norm, curve_y, color=color_curve, linewidth=1, alpha=1, linestyle='--', zorder=5) - # Huss curve - huss_y_lrg = (glac_elev_norm - 0.02)**6 + 0.12 * (glac_elev_norm - 0.02) - huss_y_med = (glac_elev_norm - 0.05)**4 + 0.19 * (glac_elev_norm - 0.05) + 0.01 - huss_y_sml = (glac_elev_norm - 0.30)**2 + 0.60 * (glac_elev_norm - 0.30) + 0.09 - ax[nrow,ncol].plot(glac_elev_norm, huss_y_lrg, linewidth=1, color='red', linestyle='-.', alpha=1, zorder=3) - ax[nrow,ncol].plot(glac_elev_norm, huss_y_med, linewidth=1, color='green', linestyle='-.', alpha=1, zorder=3) - ax[nrow,ncol].plot(glac_elev_norm, huss_y_sml, linewidth=1, color='blue', linestyle='-.', alpha=1, zorder=3) - - - # Individual curves - for n, i in enumerate(reg_normelev_normmb_list): - glac_elev_norm_single = reg_normelev_normmb_list[n][:,0] - glac_mb_norm_single = reg_normelev_normmb_list[n][:,1] - # note: zorder overrides alpha, only alpha if same zorder - ax[nrow,ncol].plot(glac_elev_norm_single, glac_mb_norm_single, linewidth=0.25, alpha=0.2, zorder=1) - - # Niceties - ax[nrow,ncol].xaxis.set_major_locator(MultipleLocator(0.25)) - ax[nrow,ncol].xaxis.set_minor_locator(MultipleLocator(0.05)) - ax[nrow,ncol].set_xlim(0,1) - ax[nrow,ncol].yaxis.set_major_locator(MultipleLocator(1)) - ax[nrow,ncol].yaxis.set_minor_locator(MultipleLocator(0.25)) - ax[nrow,ncol].set_ylim(1.05,-0.05) - # Title - region_nglac = len(reg_normelev_normmb_list) - ax[nrow,ncol].text(0.5, 1.01, group_name + ' (' + str(region_nglac) + ' glaciers)', size=10, - horizontalalignment='center', verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - # Equation - signs = ['+', '+', '+'] - for nsign, coeff in enumerate(coeffs[0:3]): - if coeff < 0: - signs[nsign] = '-' - eqn_txt = 'dh=(x+a)$^{d}$+b(x+a)+c' - ax[nrow,ncol].text(0.05, 0.45, 'a=' + '{:.2f}'.format(coeffs[0]), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.35, 'b=' + '{:.2f}'.format(coeffs[1]), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.25, 'c=' + '{:.2f}'.format(coeffs[2]), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.15, 'd=' + str(int(coeffs[3])), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.05, eqn_txt, size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - - # Adjust row and column - ncol += 1 - if ncol == group_ncols: - nrow += 1 - ncol = 0 - -# Add All Alaska curve to each glacier -ncol = 0 -nrow = 0 -for group_name in group_names: - if group_name not in ['All Alaska']: - # Fitted curve - ax[nrow,ncol].plot(glac_elev_norm, curve_y_all, color='y', linewidth=1, alpha=1, linestyle='--', zorder=4) - # Adjust row and column - ncol += 1 - if ncol == group_ncols: - nrow += 1 - ncol = 0 - -# Legend -leg_labels = ['Median', 'Curve', 'Curve-all', 'H-small', 'H-medium', 'H-large'] -#leg_labels = ['Median', 'Curve_fit', 'Huss-small', 'Huss-medium', 'Huss-large'] -#leg_linestyles = ['-', '--', '--', '--', '--'] -leg_linestyles = ['-', '--', '--', '-.', '-.', '-.'] -leg_colors = ['dimgray', 'k', 'y', 'b', 'g', 'r'] -leg_lines = [] -for nline, label in enumerate(leg_labels): -# line = Line2D([0,1],[0,1], color='white') -# leg_lines.append(line) -# leg_labels.append('') - line = Line2D([0,0],[0,0], color=leg_colors[nline], linestyle=leg_linestyles[nline], linewidth=1.5) - leg_lines.append(line) -fig.legend(leg_lines, leg_labels, loc='lower center', - bbox_to_anchor=(0.5,0.01), handlelength=1.5, handletextpad=0.25, borderpad=0.2, frameon=True, - ncol=len(leg_labels), columnspacing=0.75) - -# Y-label -fig.text(0.04, 0.5, 'Normalized Mass Balance', va='center', ha='center', - rotation='vertical', size=12) -fig.text(0.5, 0.08, 'Normalized Elevation', va='center', ha='center', size=12) - -# Save figure -fig.set_size_inches(figwidth,figheight) -figure_fn = 'normelev_normmb_TERMTYPE_gt' + str(valid_perc_threshold) + 'pct_gt' + str(min_area_km2) + 'km2.png' -fig.savefig(fig_fp + figure_fn, bbox_inches='tight', dpi=300) - -#%% ===== TERMTYPE AND SIZE: NORMALIZED ELEVATION VS NORMALIZED MASS BALANCE PLOT====== -group_names = ['Tidewater', 'Lake', 'Land (A < 5 km$^{2}$)', 'Land (5 < A < 20 km$^{2}$)', - 'Land (A > 20 km$^{2}$)', 'All Alaska'] -group_idx = [] -for group_name in group_names: - if group_name == 'Tidewater': - group_idx.append(list(main_glac_rgi[main_glac_rgi.TermType == 1].index.values)) - elif group_name == 'Lake': - group_idx.append(list(main_glac_rgi[main_glac_rgi.TermType == 2].index.values)) - elif group_name == 'Land (A < 5 km$^{2}$)': - group_idx.append(list(main_glac_rgi[(main_glac_rgi.TermType == 0) & (main_glac_rgi.Area <= 5)].index.values)) - elif group_name == 'Land (5 < A < 20 km$^{2}$)': - group_idx.append(list(main_glac_rgi[(main_glac_rgi.TermType == 0) & (main_glac_rgi.Area > 5) & - (main_glac_rgi.Area <= 20)].index.values)) - elif group_name == 'Land (A > 20 km$^{2}$)': - group_idx.append(list(main_glac_rgi[(main_glac_rgi.TermType == 0) & (main_glac_rgi.Area > 20)].index.values)) - elif group_name == 'All Alaska': - group_idx.append(list(main_glac_rgi.index.values)) - -group_ncols = 2 -group_nrows = int(np.ceil(len(group_names)/group_ncols)) -figwidth, figheight = 6.5, 8 -fig, ax = plt.subplots(group_nrows, group_ncols, squeeze=False, sharex=False, sharey=False, - figsize=(figwidth,figheight), gridspec_kw = {'wspace':0.25, 'hspace':0.4}) -ncol = 0 -nrow = 0 -for ngroup, group_name in enumerate(group_names): - reg_idx = group_idx[ngroup] - - reg_binned_list = [binned_list[i] for i in reg_idx] - - mb_norm_cn = 'mb_norm_huss' - - # If mb_norm_huss, then remove glaciers with all positive values - if mb_norm_cn == 'mb_norm_huss': - reg_idx_allnan = [] - for n, reg_binned_data in enumerate(reg_binned_list): - if np.isnan(reg_binned_data[mb_norm_cn]).any() == True: - reg_idx_allnan.append(n) - for n in sorted(reg_idx_allnan, reverse=True): - del reg_binned_list[n] - - reg_normelev_normmb_list = [np.array([i['elev_norm'].values, i[mb_norm_cn].values]).transpose() - for i in reg_binned_list] - reg_normelev_normmb_stats = norm_stats(reg_normelev_normmb_list) - - # Estimate a curve - # Two steps: (1) estimate d to nearest integer and avoid nan issues, (2) force d to be an integer and optimize - # bounds ensure - x = reg_normelev_normmb_stats['norm_elev'].values - y = reg_normelev_normmb_stats['norm_dhdt_med'].values - def curve_func_raw(x, a, b, c, d): - y = (x + a)**d + b * (x + a) + c - # avoid errors with np.arrays where negative number to power returns NaN - replace with 0 - y = np.nan_to_num(y) - return y - def curve_func(x, a, b, c, d): - # force d to be an integer - d = int(np.round(d,0)) - y = (x + a)**d + b * (x + a) + c - return y - p0 = [-0.02,0.12,0,3] - bnd_low = [-np.inf, -np.inf, -np.inf, 0] - bnd_high = [np.inf, np.inf, np.inf, np.inf] - coeffs, matcov = curve_fit(curve_func_raw, x, y, p0, bounds=(bnd_low, bnd_high), maxfev=10000) - # specify integer for d - p0[3] = int(np.round(coeffs[3],0)) - coeffs, matcov = curve_fit(curve_func, x, y, p0, bounds=(bnd_low, bnd_high), maxfev=10000) - # Round coefficients - coeffs[0] = np.round(coeffs[0],2) - coeffs[1] = np.round(coeffs[1],2) - coeffs[2] = np.round(coeffs[2],2) - - glac_elev_norm = np.arange(0,1.01,0.01) - curve_y = curve_func(glac_elev_norm, coeffs[0], coeffs[1], coeffs[2], coeffs[3]) - if group_name in ['All Alaska']: - curve_y_all = curve_y.copy() - - # Plot regional curves - ax[nrow,ncol].plot(reg_normelev_normmb_stats['norm_elev'], reg_normelev_normmb_stats['norm_dhdt_med'], - color='k', linewidth=2, alpha=0.5, zorder=4) - ax[nrow,ncol].fill_between(reg_normelev_normmb_stats['norm_elev'], reg_normelev_normmb_stats['norm_dhdt_med'], - reg_normelev_normmb_stats['norm_dhdt_med'] + reg_normelev_normmb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=2) - ax[nrow,ncol].fill_between(reg_normelev_normmb_stats['norm_elev'], reg_normelev_normmb_stats['norm_dhdt_med'], - reg_normelev_normmb_stats['norm_dhdt_med'] - reg_normelev_normmb_stats['norm_dhdt_nmad'], - color='dimgray', alpha=0.5, zorder=2) - # Fitted curve - if group_name not in ['All Alaska']: - color_curve = 'k' - else: - color_curve = 'y' - ax[nrow,ncol].plot(glac_elev_norm, curve_y, color=color_curve, linewidth=1, alpha=1, linestyle='--', zorder=5) - # Huss curve - huss_y_lrg = (glac_elev_norm - 0.02)**6 + 0.12 * (glac_elev_norm - 0.02) - huss_y_med = (glac_elev_norm - 0.05)**4 + 0.19 * (glac_elev_norm - 0.05) + 0.01 - huss_y_sml = (glac_elev_norm - 0.30)**2 + 0.60 * (glac_elev_norm - 0.30) + 0.09 - ax[nrow,ncol].plot(glac_elev_norm, huss_y_lrg, linewidth=1, color='red', linestyle='-.', alpha=1, zorder=3) - ax[nrow,ncol].plot(glac_elev_norm, huss_y_med, linewidth=1, color='green', linestyle='-.', alpha=1, zorder=3) - ax[nrow,ncol].plot(glac_elev_norm, huss_y_sml, linewidth=1, color='blue', linestyle='-.', alpha=1, zorder=3) - - - # Individual curves - for n, i in enumerate(reg_normelev_normmb_list): - glac_elev_norm_single = reg_normelev_normmb_list[n][:,0] - glac_mb_norm_single = reg_normelev_normmb_list[n][:,1] - # note: zorder overrides alpha, only alpha if same zorder - ax[nrow,ncol].plot(glac_elev_norm_single, glac_mb_norm_single, linewidth=0.25, alpha=0.2, zorder=1) - - # Niceties - ax[nrow,ncol].xaxis.set_major_locator(MultipleLocator(0.25)) - ax[nrow,ncol].xaxis.set_minor_locator(MultipleLocator(0.05)) - ax[nrow,ncol].set_xlim(0,1) - ax[nrow,ncol].yaxis.set_major_locator(MultipleLocator(1)) - ax[nrow,ncol].yaxis.set_minor_locator(MultipleLocator(0.25)) - ax[nrow,ncol].set_ylim(1.05,-0.05) - # Title - region_nglac = len(reg_normelev_normmb_list) - ax[nrow,ncol].text(0.5, 1.01, group_name + ' (' + str(region_nglac) + ' glaciers)', size=10, - horizontalalignment='center', verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - # Equation - signs = ['+', '+', '+'] - for nsign, coeff in enumerate(coeffs[0:3]): - if coeff < 0: - signs[nsign] = '-' - eqn_txt = 'dh=(x+a)$^{d}$+b(x+a)+c' - ax[nrow,ncol].text(0.05, 0.45, 'a=' + '{:.2f}'.format(coeffs[0]), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.35, 'b=' + '{:.2f}'.format(coeffs[1]), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.25, 'c=' + '{:.2f}'.format(coeffs[2]), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.15, 'd=' + str(int(coeffs[3])), size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - ax[nrow,ncol].text(0.05, 0.05, eqn_txt, size=10, horizontalalignment='left', - verticalalignment='bottom', transform=ax[nrow,ncol].transAxes) - - # Adjust row and column - ncol += 1 - if ncol == group_ncols: - nrow += 1 - ncol = 0 - -# Add All Alaska curve to each glacier -ncol = 0 -nrow = 0 -for group_name in group_names: - if group_name not in ['All Alaska']: - # Fitted curve - ax[nrow,ncol].plot(glac_elev_norm, curve_y_all, color='y', linewidth=1, alpha=1, linestyle='--', zorder=4) - # Adjust row and column - ncol += 1 - if ncol == group_ncols: - nrow += 1 - ncol = 0 - -# Legend -leg_labels = ['Median', 'Curve', 'Curve-all', 'H-small', 'H-medium', 'H-large'] -leg_linestyles = ['-', '--', '--', '-.', '-.', '-.'] -leg_colors = ['dimgray', 'k', 'y', 'b', 'g', 'r'] -leg_lines = [] -for nline, label in enumerate(leg_labels): -# line = Line2D([0,1],[0,1], color='white') -# leg_lines.append(line) -# leg_labels.append('') - line = Line2D([0,0],[0,0], color=leg_colors[nline], linestyle=leg_linestyles[nline], linewidth=1.5) - leg_lines.append(line) -fig.legend(leg_lines, leg_labels, loc='lower center', - bbox_to_anchor=(0.5,0.01), handlelength=1.5, handletextpad=0.25, borderpad=0.2, frameon=True, - ncol=len(leg_labels), columnspacing=0.75) - -# Y-label -fig.text(0.04, 0.5, 'Normalized Mass Balance', va='center', ha='center', - rotation='vertical', size=12) -fig.text(0.5, 0.08, 'Normalized Elevation', va='center', ha='center', size=12) - -# Save figure -fig.set_size_inches(figwidth,figheight) -figure_fn = 'normelev_normmb_TERMTYPE-SIZE_gt' + str(valid_perc_threshold) + 'pct_gt' + str(min_area_km2) + 'km2.png' -fig.savefig(fig_fp + figure_fn, bbox_inches='tight', dpi=300) - -#%% ===== EXTRAPOLATE MASS BALANCE CURVES TO EVERY GLACIER ===== -main_glac_rgi_all = modelsetup.selectglaciersrgitable(rgi_regionsO1=[1], rgi_regionsO2='all', rgi_glac_number='all') -# Load hypsometry data -glac_hyps_all_df = pd.read_csv(hyps_fn) -glac_hyps_all = glac_hyps_all_df.iloc[:,1:].values -glac_icethickness_all_df = pd.read_csv(icethickness_fn) -glac_icethickness_all = glac_icethickness_all_df.iloc[:,1:].values - -glac_elevnorm_all = np.zeros(glac_hyps_all.shape) -glac_hyps_all_mask = glac_hyps_all.copy() -glac_hyps_all_mask[glac_hyps_all_mask > 0] = 1 -elev_bins = np.array(glac_hyps_all_df.columns[1:].astype(int)) -elev_bin_dict = dict(zip(np.arange(0,len(elev_bins)), elev_bins)) -glac_min = np.array([elev_bin_dict[i] for i in list(glac_hyps_all_mask.argmax(axis=1))]) -glac_max = np.array([elev_bin_dict[i] - for i in list(glac_hyps_all.shape[1] - 1 - glac_hyps_all_mask[:,::-1].argmax(axis=1))]) - -# Normalized elevation (consistent with hypsometry) -glac_elev_all = glac_hyps_all_mask * elev_bins[np.newaxis,:] -if option_normelev == 'larsen': - glac_elevnorm_all = ((glac_elev_all - glac_min[:,np.newaxis]) * glac_hyps_all_mask / - (glac_max - glac_min)[:,np.newaxis]) -elif option_normelev == 'huss': - glac_elevnorm_all = ((glac_max[:,np.newaxis] - glac_elev_all) * glac_hyps_all_mask / - (glac_max - glac_min)[:,np.newaxis]) -glac_elevnorm_all[glac_elevnorm_all==0] = 0 -# Fill in glaciers with single bin -for singlebin_row in list(np.where(glac_max - glac_min == 0)[0]): - singlebin_col = glac_hyps_all_mask.argmax(axis=1)[np.where(glac_max - glac_min == 0)[0]] - glac_elevnorm_all[singlebin_row,singlebin_col] = 0.5 - -## Glacier regions used for indexing -#glac_region = (np.zeros(glac_hyps_all.shape[0]) + 9999).astype(int) -#for region in regions: -# region_idx = np.where(main_glac_rgi_all.O2Region == region)[0] -# glac_region[region_idx] = region - -# Use regional norm elevation vs mb curves to extrapolate to all glaciers -glac_mb_all = np.zeros(glac_hyps_all.shape) -glac_mb_all_pstd = np.zeros(glac_hyps_all.shape) -glac_mb_all_mstd = np.zeros(glac_hyps_all.shape) - -# Group dictionary -group_names = ['Tidewater', 'Lake', 'Land_A<5', 'Land_520'] -extrap_id_dict = {0:'Tidewater', 1:'Lake', 2:'Land_A<5', 3:'Land_520'} -extrap_ids = np.arange(0,len(group_names)) -group_idx = [] -main_glac_rgi_all['extrap_id'] = 0 -for group_name in group_names: - if group_name == 'Tidewater': - group_idx.append(list(main_glac_rgi[main_glac_rgi.TermType == 1].index.values)) - main_glac_rgi_all.loc[main_glac_rgi_all[main_glac_rgi_all.TermType == 1].index.values, 'extrap_id'] = 0 - elif group_name == 'Lake': - group_idx.append(list(main_glac_rgi[main_glac_rgi.TermType == 2].index.values)) - main_glac_rgi_all.loc[main_glac_rgi_all[main_glac_rgi_all.TermType == 2].index.values, 'extrap_id'] = 1 - elif group_name == 'Land_A<5': - group_idx.append(list(main_glac_rgi[(main_glac_rgi.TermType == 0) & (main_glac_rgi.Area <= 5)].index.values)) - main_glac_rgi_all.loc[main_glac_rgi_all[(main_glac_rgi_all.TermType == 0) & - (main_glac_rgi_all.Area <= 5)].index.values, 'extrap_id'] = 2 - elif group_name == 'Land_5 5) & - (main_glac_rgi.Area <= 20)].index.values)) - main_glac_rgi_all.loc[main_glac_rgi_all[(main_glac_rgi_all.TermType == 0) & (main_glac_rgi_all.Area > 5) & - (main_glac_rgi_all.Area <= 20)].index.values, 'extrap_id'] = 3 - elif group_name == 'Land_A>20': - group_idx.append(list(main_glac_rgi[(main_glac_rgi.TermType == 0) & (main_glac_rgi.Area > 20)].index.values)) - main_glac_rgi_all.loc[main_glac_rgi_all[(main_glac_rgi_all.TermType == 0) & - (main_glac_rgi_all.Area > 20)].index.values, 'extrap_id'] = 4 -reg_normelev_mb_dict = {} -reg_normelev_mb_dict_pstd = {} -reg_normelev_mb_dict_mstd = {} -for ngroup, group_name in enumerate(group_names): - reg_idx = group_idx[ngroup] - - reg_binned_list = [binned_list[i] for i in reg_idx] - - reg_elev_mb_list = [np.array([i[elev_cn].values, i[mb_cn].values]).transpose() for i in reg_binned_list] - reg_normelev_mb_list = [np.array([i['elev_norm'].values, i[mb_cn].values]).transpose() for i in reg_binned_list] - reg_normelev_mb_stats = norm_stats(reg_normelev_mb_list) - reg_normelev_mb_dict[ngroup] = dict(zip((reg_normelev_mb_stats['norm_elev'].values * 100).astype(int), - reg_normelev_mb_stats['norm_dhdt_med'].values)) - reg_normelev_mb_dict_pstd[ngroup] = dict(zip((reg_normelev_mb_stats['norm_elev'].values * 100).astype(int), - reg_normelev_mb_stats['norm_dhdt_68high'].values)) - reg_normelev_mb_dict_mstd[ngroup] = dict(zip((reg_normelev_mb_stats['norm_elev'].values * 100).astype(int), - reg_normelev_mb_stats['norm_dhdt_68low'].values)) - -for extrap_id in extrap_ids: - extrap_idx = main_glac_rgi_all[main_glac_rgi_all.extrap_id == extrap_id].index.values - print(extrap_id, group_names[extrap_id] + ': ' + str(len(extrap_idx)) + ' glaciers') - - # Partition for each region - glac_region_mask = np.zeros(glac_hyps_all.shape) - glac_region_mask[extrap_idx,:] = 1 - - # Convert normalized elevation to integers to work with dictionary and mask for specific region - glac_elevnorm_pc = (glac_elevnorm_all * 100).astype(int) - - # Apply region mb vs norm elevation dictionary - # median curve - glac_mb_reg = np.zeros(glac_elevnorm_pc.shape) - for k, v in reg_normelev_mb_dict[extrap_id].items(): - glac_mb_reg[glac_elevnorm_pc == k] = v - # plus 1 std - glac_mb_reg_pstd = np.zeros(glac_elevnorm_pc.shape) - for k, v in reg_normelev_mb_dict_pstd[extrap_id].items(): - glac_mb_reg_pstd[glac_elevnorm_pc == k] = v - # minus 1 std - glac_mb_reg_mstd = np.zeros(glac_elevnorm_pc.shape) - for k, v in reg_normelev_mb_dict_mstd[extrap_id].items(): - glac_mb_reg_mstd[glac_elevnorm_pc == k] = v - - # Mass balance cannot exceed max mass loss based on ice thickness - glac_t1_all = main_glac_rgi_all.O2Region.map(reg_t1_dict).values - glac_t2_all = main_glac_rgi_all.O2Region.map(reg_t2_dict).values - glac_mbmaxloss_all = -1 * glac_icethickness_all / (glac_t2_all - glac_t1_all)[:,np.newaxis] - glac_mb_reg[glac_mb_reg < glac_mbmaxloss_all] = glac_mbmaxloss_all[glac_mb_reg < glac_mbmaxloss_all] - glac_mb_reg_pstd[glac_mb_reg_pstd < glac_mbmaxloss_all] = glac_mbmaxloss_all[glac_mb_reg_pstd < glac_mbmaxloss_all] - glac_mb_reg_mstd[glac_mb_reg_mstd < glac_mbmaxloss_all] = glac_mbmaxloss_all[glac_mb_reg_mstd < glac_mbmaxloss_all] - - # mask values for areas without glacier hypsometry - glac_mb_reg_masked = glac_mb_reg * glac_hyps_all_mask * glac_region_mask - glac_mb_reg_pstd_masked = glac_mb_reg_pstd * glac_hyps_all_mask * glac_region_mask - glac_mb_reg_mstd_masked = glac_mb_reg_mstd * glac_hyps_all_mask * glac_region_mask - - glac_mb_all[glac_mb_reg_masked != 0] = glac_mb_reg_masked[glac_mb_reg_masked != 0] - glac_mb_all_pstd[glac_mb_reg_masked != 0] = glac_mb_reg_pstd_masked[glac_mb_reg_masked != 0] - glac_mb_all_mstd[glac_mb_reg_masked != 0] = glac_mb_reg_mstd_masked[glac_mb_reg_masked != 0] - -# Glacier-wide mass balance -glac_wide_mb = (glac_mb_all * glac_hyps_all).sum(axis=1) / glac_hyps_all.sum(axis=1) -glac_wide_mb_pstd = (glac_mb_all_pstd * glac_hyps_all).sum(axis=1) / glac_hyps_all.sum(axis=1) -glac_wide_mb_mstd = (glac_mb_all_mstd * glac_hyps_all).sum(axis=1) / glac_hyps_all.sum(axis=1) -main_glac_rgi_all['mb_mwea_extrap'] = glac_wide_mb -main_glac_rgi_all['mb_mwea_extrap_pstd'] = glac_wide_mb_pstd -main_glac_rgi_all['mb_mwea_extrap_mstd'] = glac_wide_mb_mstd -main_glac_rgi_all['mb_mwea_extrap_sigma'] = ( - (np.absolute(main_glac_rgi_all.mb_mwea_extrap_pstd - main_glac_rgi_all.mb_mwea_extrap).values + - np.absolute(main_glac_rgi_all.mb_mwea_extrap_pstd - main_glac_rgi_all.mb_mwea_extrap).values) / 2) - -# Uncertainty based on extrapolation method -# alternative: use the upper and lower bounds of regional curves for uncertainty -rgi_all_idx = [] -for rgiid in main_glac_rgi.RGIId.values: - rgi_all_idx.append(np.where(main_glac_rgi_all.RGIId.values == rgiid)[0][0]) - -mb_summary['mb_mwea_extrap'] = main_glac_rgi_all.loc[rgi_all_idx,'mb_mwea_extrap'].values -mb_summary['dif_mb'] = mb_summary.mb_mwea - mb_summary.mb_mwea_extrap -print('Potential bias from extrapolation [mean +/- std (median)]:\n ', np.round(mb_summary.dif_mb.mean(),2), '+/-', - np.round(mb_summary.dif_mb.std(),2), '(' + str(np.round(mb_summary.dif_mb.median(),2)) + ')') - -mb_summary['abs_dif_mb'] = np.absolute(mb_summary.mb_mwea - mb_summary.mb_mwea_extrap) -print('Uncertainty from obs [mean +/- std (median)]:\n ', np.round(mb_summary.abs_dif_mb.mean(),2), '+/-', - np.round(mb_summary.abs_dif_mb.std(),2), '(' + str(np.round(mb_summary.abs_dif_mb.median(),2)) + ')') -mb_summary['mb_mwea_sigma'] = mb_summary.abs_dif_mb.mean() - -print('Uncertainty from extrap_curves [mean +/- std (median)]:\n ', - np.round(main_glac_rgi_all['mb_mwea_extrap_sigma'].mean(),2), '+/-', - np.round(main_glac_rgi_all['mb_mwea_extrap_sigma'].std(),2), '(' + - str(np.round(main_glac_rgi_all['mb_mwea_extrap_sigma'].median(),2)) + ')') - -# ===== EXPORT DATA AND EXTRAPOLATED VALUES ===== -glac_wide_mb_export = pd.DataFrame(np.zeros((main_glac_rgi_all.shape[0],8)), - columns=['RGIId', 'region_id', 'region', 'area_km2', 'mb_mwea', 'mb_mwea_sigma', - 't1', 't2']) -glac_wide_mb_export['RGIId'] = main_glac_rgi_all.RGIId -glac_wide_mb_export['extrap_id'] = main_glac_rgi_all.extrap_id -glac_wide_mb_export['extrap_type'] = glac_wide_mb_export.extrap_id.map(extrap_id_dict) -glac_wide_mb_export['area_km2'] = main_glac_rgi_all.Area -glac_wide_mb_export['mb_mwea'] = main_glac_rgi_all.mb_mwea_extrap -glac_wide_mb_export['mb_mwea_sigma'] = main_glac_rgi_all.mb_mwea_extrap_sigma -glac_wide_mb_export['t1'] = main_glac_rgi_all.O2Region.map(reg_t1_dict).values -glac_wide_mb_export['t2'] = main_glac_rgi_all.O2Region.map(reg_t2_dict).values -glac_wide_mb_export['obs_type'] = obs_type + '_extrapolated' -# overwrite extrapolated values with observations -glac_wide_mb_export.loc[rgi_all_idx,'mb_mwea'] = mb_summary.mb_mwea.values -glac_wide_mb_export.loc[rgi_all_idx,'t1'] = mb_summary.t1.values -glac_wide_mb_export.loc[rgi_all_idx,'t2'] = mb_summary.t2.values -glac_wide_mb_export.loc[rgi_all_idx,'obs_type'] = obs_type -print('\nUncertainty from extrapolated curves used for all due to issues with static analysis\n') -glac_wide_mb_export.to_csv(dems_output_fp + mb_mwea_all_fn, index=False) - -massloss_all_gta = (glac_wide_mb_export.area_km2 * glac_wide_mb_export.mb_mwea / 1000).sum() -print('Region mass loss [mean]:', str(np.round(massloss_all_gta,1)) + ' Gt/yr') - -print('\n\n Need to aggregate uncertainty (Shean-hex method?)\n\n') diff --git a/run_preprocessing_farinotti.py b/run_preprocessing_farinotti.py deleted file mode 100644 index 8d737b57..00000000 --- a/run_preprocessing_farinotti.py +++ /dev/null @@ -1,305 +0,0 @@ -""" -pygemfxns_preprocessing.py is a list of the model functions that are used to preprocess the data into the proper format. - -""" -print('PROCESS FILE USING RASTERENV ENVIRONMENT') - -# Built-in libraries -import os -import argparse -# External libraries -from osgeo import gdal -#import geopandas as gpd -import matplotlib.pyplot as plt -import numpy as np -import pandas as pd -#import shapely - -from pygeotools.lib import iolib, warplib, geolib, timelib, malib - -import pygemfxns_modelsetup as modelsetup - - -#Function to generate a 3-panel plot for input arrays -def plot3panel(dem_list, clim=None, titles=None, cmap='inferno', label=None, overlay=None, fn=None): - fig, axa = plt.subplots(1,3, sharex=True, sharey=True, figsize=(10,5)) - alpha = 1.0 - for n, ax in enumerate(axa): - #Gray background - ax.set_facecolor('0.5') - #Force aspect ratio to match images - ax.set(aspect='equal') - #Turn off axes labels/ticks - ax.get_xaxis().set_visible(False) - ax.get_yaxis().set_visible(False) - if titles is not None: - ax.set_title(titles[n]) - #Plot background shaded relief map - if overlay is not None: - alpha = 0.7 - axa[n].imshow(overlay[n], cmap='gray', clim=(1,255)) - #Plot each array - im_list = [axa[i].imshow(dem_list[i], clim=clim, cmap=cmap, alpha=alpha) for i in range(len(dem_list))] - fig.tight_layout() - fig.colorbar(im_list[0], ax=axa.ravel().tolist(), label=label, extend='both', shrink=0.5) - if fn is not None: - fig.savefig(fn, bbox_inches='tight', pad_inches=0, dpi=150) - -#Input DEM filenames -dem_ref_fn = None -# dem_ref_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/Alaska_albers_V3_mac/Alaska_albers_V3.tif' -thickness_fp_prefix = ('/Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/' + - 'composite_thickness_RGI60-all_regions/') -# dem_farinotti_fp = ('/Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/surface_DEMs_RGI60/' + -# 'surface_DEMs_RGI60-01/') -dem_farinotti_fp_prefix = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/surface_DEMs_RGI60/' -output_fp = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/IceThickness_Farinotti/output/' -fig_fp = output_fp + 'figures/' -if os.path.exists(output_fp) == False: - os.makedirs(output_fp) -if os.path.exists(fig_fp) == False: - os.makedirs(fig_fp) - -rgi_regionsO1 = [14] # RGI Order 1 regions -binsize = 10 # elevation bin (must be an integer greater than 1) -dem_poorquality_switch = True # Switch to filter poor quality DEMs if another DEM is available -dem_poorquality_threshold = 200 # threshold used to identify problems with Farinotti DEM -option_plot_DEMsraw = True # Option to plot the raw DEMs -option_plot_DEMs = False # Option to plot the masked DEMs -debug = False - -# ====== -glacno_wpoor_DEM = [] -for region in rgi_regionsO1: - - thickness_fp = thickness_fp_prefix + 'RGI60-' + str(region).zfill(2) + '/' - dem_farinotti_fp = dem_farinotti_fp_prefix + 'surface_DEMs_RGI60-' + str(region).zfill(2) + '/' - - glacno_list = [] - for i in os.listdir(thickness_fp): - if i.endswith('_thickness.tif'): - glacno_list.append(i.split('-')[1].split('_')[0]) - glacno_list = sorted(glacno_list) - -# print('\n\nDELETE ME - SWITCH TO COMPLETE LIST\n\n') -# glacno_list = ['15.02228'] - # glacno_list = glacno_list[10000:10010] - - # Load RGI glacier data - main_glac_rgi = modelsetup.selectglaciersrgitable(glac_no=glacno_list) - # setup empty datasets - elev_bins_all = np.arange(binsize / 2, main_glac_rgi.Zmax.max() + binsize / 2, binsize).astype(int) - df_cns = ['RGIId'] - for elev_bin in elev_bins_all: - df_cns.append(elev_bin) - main_glac_hyps = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns) - main_glac_thickness = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns) - main_glac_width = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns) - main_glac_length = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns) - main_glac_slope = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns) - main_glac_hyps['RGIId'] = main_glac_rgi.RGIId.values - main_glac_thickness['RGIId'] = main_glac_rgi.RGIId.values - main_glac_width['RGIId'] = main_glac_rgi.RGIId.values - main_glac_length['RGIId'] = main_glac_rgi.RGIId.values - main_glac_slope['RGIId'] = main_glac_rgi.RGIId.values - - # ===== PROCESS EACH GLACIER ====== - for nglac, glacno in enumerate(glacno_list): - # print(nglac, glacno) - thickness_fn = thickness_fp + 'RGI60-' + glacno + '_thickness.tif' - dem_farinotti_fn = dem_farinotti_fp + 'surface_DEM_RGI60-' + glacno + '.tif' - - # Reproject, resample, warp rasters to common extent, grid size, etc. - # note: use thickness for the reference to avoid unrealistic extrapolations, e.g., negative thicknesses - # also using equal area increases areas significantly compared to RGI - raster_fn_list = [dem_farinotti_fn, thickness_fn] - if dem_ref_fn is not None: - raster_fn_list.append(dem_ref_fn) - - print(raster_fn_list) - - ds_list = warplib.memwarp_multi_fn(raster_fn_list, extent='intersection', res='min', t_srs=thickness_fn) - - # masked arrays using ice thickness estimates - if dem_ref_fn is not None: - dem_ref_raw, dem_far_raw, thickness = [iolib.ds_getma(i) for i in ds_list] - dem_ref = dem_ref_raw.copy() - dem_ref.mask = thickness.mask - else: - dem_far_raw, thickness = [iolib.ds_getma(i) for i in ds_list] - dem_far = dem_far_raw.copy() - dem_far.mask = thickness.mask - - # DEM selection for binning computations - # if exceeds threshold, then use the reference - if ((abs(main_glac_rgi.loc[nglac,'Zmin'] - dem_far.min()) > dem_poorquality_threshold or - abs(main_glac_rgi.loc[nglac,'Zmax'] - dem_far.max()) > dem_poorquality_threshold) - and dem_ref_fn is not None): - print(' Check Glacier ' + glacno + ': use Christian DEM instead of Farinotti') - print('\n RGI Zmin/Zmax:', main_glac_rgi.loc[nglac,'Zmin'], '/', main_glac_rgi.loc[nglac,'Zmax']) - print(' Farinotti Zmin/Zmax:', np.round(dem_far.min(),0), '/', np.round(dem_far.max(),0)) - print(' Christian Zmin/Zmax:', np.round(dem_ref.min(),0), '/', np.round(dem_ref.max(),0), '\n') - glacno_wpoor_DEM.append(glacno) - dem = dem_ref - dem_raw = dem_ref_raw - - # ===== PLOT DEMS TO CHECK ===== - if option_plot_DEMsraw: - dem_list_raw = [dem_ref_raw, dem_far_raw, thickness] - titles = ['DEM-Christian-raw', 'DEM-Farinotti-raw', 'Thickness'] - clim = malib.calcperc(dem_list_raw[0], (2,98)) - plot3panel(dem_list_raw, clim, titles, 'inferno', 'Elevation (m WGS84)', fn=fig_fp + glacno + - '_dem_raw.png') - - if option_plot_DEMs: - dem_list = [dem_ref, dem_far, thickness] - titles = ['DEM-Christian', 'DEM-Farinotti', 'Thickness'] - clim = malib.calcperc(dem_list[0], (2,98)) - plot3panel(dem_list, clim, titles, 'inferno', 'Elevation (m WGS84)', fn=fig_fp + glacno + '_dem.png') - # otherwise, use Farinotti - else: - dem = dem_far - dem_raw = dem_far_raw - - #Extract x and y pixel resolution (m) from geotransform - gt = ds_list[0].GetGeoTransform() - px_res = (gt[1], -gt[5]) - #Calculate pixel area in m^2 - px_area = px_res[0]*px_res[1] - - if debug: - print('\nx_res [m]:', np.round(px_res[0],1), 'y_res[m]:', np.round(px_res[1],1),'\n') - - # ===== USE SHAPEFILE OR SINGLE POLYGON TO CLIP ===== - # shp_fn = '/Users/davidrounce/Documents/Dave_Rounce/HiMAT/RGI/rgi60/01_rgi60_Alaska/01_rgi60_Alaska.shp' - # #Create binary mask from polygon shapefile to match our warped raster datasets - # shp_mask = geolib.shp2array(shp_fn, ds_list[0]) - # #Now apply the mask to each array - # dem_list_shpclip = [np.ma.array(dem, mask=shp_mask) for dem in dem_list] - # plot3panel(dem_list_shpclip, clim, titles, 'inferno', 'Elevation (m WGS84)', fn=output_fp + 'dem_shpclp.png') - # rgi_alaska = gpd.read_file(shp_fn) - # print(rgi_alaska.head()) - # rgi_alaska.plot(); - # print(rgi_alaska.crs) - # # print('\nGeometry_type:\n',rgi_alaska[0:5].geom_type) - # # print('\nArea (NOTE THESE ARE IN DEGREES!):\n',rgi_alaska[0:5].geometry.area) - # # print('\nBounds:\n',rgi_alaska[0:5].geometry.bounds) - # rgi_alaska.plot(column='O2Region', categorical=True, legend=True, figsize=(14,6)) - # rgiid = 'RGI60-' + glacno - # rgi_single = rgi_alaska[rgi_alaska['RGIId'] == rgiid] - # # export to - # rgi_single_fn = 'rgi_single.shp' - # rgi_single.to_file(rgi_single_fn) - # #Create binary mask from polygon shapefile to match our warped raster datasets - # rgi_single_mask = geolib.shp2array(rgi_single_fn, ds_list[0]) - # #Now apply the mask to each array - # dem_list_shpclip = [np.ma.array(dem, mask=rgi_single_mask) for dem in dem_list] - # plot3panel(dem_list_shpclip, clim, titles, 'inferno', 'Elevation (m WGS84)', fn=output_fp + 'dem_single.png') - # ============================================================================================================= - - if debug: - glacier_area_total = thickness.count() * px_res[0] * px_res[1] / 10**6 - print(glacno, 'glacier area [km2]:', np.round(glacier_area_total,2), - 'vs RGI [km2]:', np.round(main_glac_rgi.loc[nglac,'Area'],2)) - - # Remove negative elevation values - dem[dem < 0] = 0 - dem.mask = thickness.mask - - elev_bin_min = binsize * (dem.min() / binsize).astype(int) - elev_bin_max = binsize * (dem.max() / binsize).astype(int) + binsize - - print(nglac, glacno, elev_bin_min, elev_bin_max) - - # if elev_bin_min < 0: - # print(nglac, glacno, elev_bin_min, elev_bin_max) - # debug_fp = input.output_sim_fp + 'debug/' - # # Create filepath if it does not exist - # if os.path.exists(debug_fp) == False: - # os.makedirs(debug_fp) - # debug_df = pd.DataFrame(np.zeros((1,1)), columns=['count']) - # debug_df.iloc[0,0] = 1 - # debug_fn_loaded = str(glacno) + '_nglac' + str(nglac) + '_minlt0_.csv' - # debug_df.to_csv(debug_fp + debug_fn_loaded) - - elev_bin_edges = np.arange(elev_bin_min, elev_bin_max+binsize, binsize) - elev_bins = (elev_bin_edges[0:-1] + binsize/2).astype(int) - - # Hypsometry [km2] - # must used .compressed() in histogram to exclude masked values - hist, elev_bin_edges = np.histogram(dem.reshape(-1).compressed(), bins=elev_bin_edges) - bin_hyps = hist * px_res[0] * px_res[1] / 10**6 - if debug: - print('Zmin/Zmax:', np.round(dem.min(),0), '/', np.round(dem.max(),0), '\n') - print('elev_bin_edges:', elev_bin_edges) - print('hist:', hist) - print('total area:', hist.sum() * px_res[0] * px_res[1] / 10**6) - - # Mean thickness [m] - hist_thickness, elev_bin_edges = np.histogram(dem.reshape(-1).compressed(), bins=elev_bin_edges, - weights=thickness.reshape(-1).compressed()) - bin_thickness = hist_thickness / hist - - # Mean Slope [deg] - # --> MAY WANT TO RESAMPLE TO SMOOTH DEM PRIOR TO ESTIMATING SLOPE - grad_x, grad_y = np.gradient(dem_raw, px_res[0], px_res[1]) - slope = np.arctan(np.sqrt(grad_x ** 2 + grad_y ** 2)) - slope_deg = np.rad2deg(slope) - slope_deg.mask = dem.mask - hist_slope, elev_bin_edges = np.histogram(dem.reshape(-1).compressed(), bins=elev_bin_edges, - weights=slope_deg.reshape(-1).compressed()) - bin_slope = hist_slope / hist - - # Length [km] - based on the mean slope and bin elevation - bin_length = binsize / np.tan(np.deg2rad(bin_slope)) / 1000 - - # Width [km] - based on length (inherently slope) and bin area - bin_width = bin_hyps / bin_length - - # Remove negative values - bin_hyps[bin_hyps < 0] = 0 - bin_thickness[bin_thickness < 0] = 0 - bin_width[bin_width < 0] = 0 - bin_length[bin_length < 0] = 0 - bin_slope[bin_slope < 0] = 0 - - # Record properties - # Check if need to expand columns - missing_cns = sorted(list(set(elev_bins) - set(df_cns))) - if len(missing_cns) > 0: - for missing_cn in missing_cns: - main_glac_hyps[missing_cn] = 0 - main_glac_thickness[missing_cn] = 0 - main_glac_width[missing_cn] = 0 - main_glac_length[missing_cn] = 0 - main_glac_slope[missing_cn] = 0 - # Record data - main_glac_hyps.loc[nglac, elev_bins] = bin_hyps - main_glac_thickness.loc[nglac, elev_bins] = bin_thickness - main_glac_width.loc[nglac, elev_bins] = bin_width - main_glac_length.loc[nglac, elev_bins] = bin_length - main_glac_slope.loc[nglac, elev_bins] = bin_slope - - # Remove NaN values - main_glac_hyps = main_glac_hyps.fillna(0) - main_glac_thickness = main_glac_thickness.fillna(0) - main_glac_width = main_glac_width.fillna(0) - main_glac_length = main_glac_length.fillna(0) - main_glac_slope = main_glac_slope.fillna(0) -# # Remove negative values -# main_glac_hyps[main_glac_hyps < 0] = 0 -# main_glac_thickness[main_glac_thickness < 0] = 0 -# main_glac_width[main_glac_width < 0] = 0 -# main_glac_length[main_glac_length < 0] = 0 -# main_glac_slope[main_glac_slope < 0] = 0 - # Export results - main_glac_hyps.to_csv(output_fp + 'area_km2_' + "{:02d}".format(region) + '_Farinotti2019_' + - str(binsize) + 'm.csv', index=False) - main_glac_thickness.to_csv(output_fp + 'thickness_m_' + "{:02d}".format(region) + '_Farinotti2019_' + - str(binsize) + 'm.csv', index=False) - main_glac_width.to_csv(output_fp + 'width_km_' + "{:02d}".format(region) + '_Farinotti2019_' + - str(binsize) + 'm.csv', index=False) - main_glac_length.to_csv(output_fp + 'length_km_' + "{:02d}".format(region) + '_Farinotti2019_' + - str(binsize) + 'm.csv', index=False) - main_glac_slope.to_csv(output_fp + 'slope_deg_' + "{:02d}".format(region) + '_Farinotti2019_' + - str(binsize) + 'm.csv', index=False) diff --git a/run_preprocessing_larsen.py b/run_preprocessing_larsen.py deleted file mode 100644 index bd405694..00000000 --- a/run_preprocessing_larsen.py +++ /dev/null @@ -1,509 +0,0 @@ -""" -pygemfxns_preprocessing.py is a list of the model functions that are used to preprocess the data into the proper format. - -""" - -# Built-in libraries -import os -import gdal -import argparse -# External libraries -import pandas as pd -import numpy as np -import matplotlib.pyplot as plt -#from scipy import interpolate -from scipy import ndimage -# Local libraries -import pygem_input as input -import pygemfxns_modelsetup as modelsetup - - - -#%% TO-DO LIST: -# - clean up create lapse rate input data (put it all in input.py) - -#%% -def getparser(): - """ - Use argparse to add arguments from the command line - - Parameters - ---------- - option_farinotti2019_input : int - Switch for processing lapse rates (default = 0 (no)) - debug : int - Switch for turning debug printing on or off (default = 0 (off)) - - Returns - ------- - Object containing arguments and their respective values. - """ - parser = argparse.ArgumentParser(description="select pre-processing options") - # add arguments - parser.add_argument('-option_farinotti2019_input', action='store', type=int, default=0, - help='option to produce Farinotti 2019 input products (1=yes, 0=no)') - parser.add_argument('-debug', action='store', type=int, default=0, - help='Boolean for debugging to turn it on or off (default 0 is off)') - return parser - - -def import_raster(raster_fn): - """Open raster and obtain the values in its first band as an array - Output: array of raster values - """ - # open raster dataset - raster_ds = gdal.Open(raster_fn) - # extract band information and get values - raster_band = raster_ds.GetRasterBand(1) - raster_values = raster_band.ReadAsArray() - # extra cell size - gt = raster_ds.GetGeoTransform() - pixel_x, pixel_y = gt[1], -gt[5] - return raster_values, pixel_x, pixel_y - - -def filldem(dem, threshold=500, windowsize=5, burn_windowsize=3, glac_mask=None, option_onlyglaciers=1): - """ Fill DEM based on a given threshold below median values - - Parameters - ---------- - dem : np.array - raw DEM to be filled - threshold : np.float - threshold compared to median value of surrounding pixels to check if pixel is good or not - windowsize : int - size of focal window to compute median statistics for fill values - burn_windowsize : int - size of focal window use to burn in pixels surrounding nan to check if they have issues as well - glac_mask : np.array - glacier mask (same size as dem) - option_onlyglaciers : int - switch to only fill glacier values and only fill those values with good glacier pixels; otherwise, fill will be - done using median value from both glacier and non-glacier pixels - """ - if glac_mask is None or option_onlyglaciers == 0: - glac_mask = np.ones(dem.shape) - - dem_init = dem.copy() - # Burn in nan values to surrounding pixels - if burn_windowsize > windowsize: - burn_windowsize = windowsize - dem_nanplus = ndimage.filters.generic_filter(dem, np.min, size=burn_windowsize) - - # Mask of nan values to check against threshold - dem_nanplus_mask = np.ones(dem.shape) - dem_nanplus_mask[np.where(np.isnan(dem_nanplus))] = 0 - # Threshold based on median from surrounding pixels to identify bad pixels - dem_median = ndimage.filters.generic_filter(dem, np.nanmedian, size=windowsize) - # Threshold to remove pixels (burn-in nan values for pixels surrounding existing nans with poor values) - dem_threshold = dem_median - threshold - dem_threshold[np.isnan(dem_threshold)] = -threshold - - # Burn in values that don't pass threshold - dem[np.isnan(dem)] = -9999 - dem_test = dem - dem_threshold - dem[dem_test < 0] = np.nan - dem[glac_mask == 0] = np.nan - - # Fill remaining values with median of good values - dem_median = ndimage.filters.generic_filter(dem, np.nanmedian, size=windowsize) - dem_filled = dem.copy() - dem_filled[np.isnan(dem)] = dem_median[np.isnan(dem)] - dem_filled[glac_mask == 0] = dem_init[glac_mask == 0] - - # Replace nan values with -9999 for filled DEM - dem_filled[np.isnan(dem_filled)] = -9999 - - return dem_filled - - -def extract_hyps(main_glac_rgi, binsize): - #%% - """ Extract hypsometry and other features if desired based on main_glac_rgi and bin size - - Limitations - ----------- - Currently skips any pixels that have bad DEM values, defined as a pixel < minimum glacier elevation - """ - rgi_regionsO1 = [main_glac_rgi.loc[0,'O1Region']] - - # Filepath - dem_fp = (input.main_directory + '/../IceThickness_Farinotti/surface_DEMs_RGI60/surface_DEMs_RGI60-' + - "{:02d}".format(rgi_regionsO1[0]) + '/') - thickness_fp = (input.main_directory + '/../IceThickness_Farinotti/composite_thickness_RGI60-all_regions/' + - 'RGI60-' + "{:02d}".format(rgi_regionsO1[0]) + '/') - - elev_bins_all = np.arange(binsize / 2, main_glac_rgi.Zmax.max() + binsize / 2, binsize).astype(int) - df_cns = ['RGIId'] - for elev_bin in elev_bins_all: - df_cns.append(elev_bin) - main_glac_hyps = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns) - main_glac_thickness = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns) - main_glac_width = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns) - main_glac_length = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns) - main_glac_slope = pd.DataFrame(np.zeros((main_glac_rgi.shape[0], len(df_cns))), columns=df_cns) - main_glac_hyps['RGIId'] = main_glac_rgi['RGIId'] - main_glac_thickness['RGIId'] = main_glac_rgi['RGIId'] - main_glac_width['RGIId'] = main_glac_rgi['RGIId'] - main_glac_length['RGIId'] = main_glac_rgi['RGIId'] - main_glac_slope['RGIId'] = main_glac_rgi['RGIId'] - - # Loop through glaciers to derive various attributes - rgiid_list = list(main_glac_rgi['RGIId'].values) - for n_rgiid, rgiid in enumerate(rgiid_list): - - # Load filenames - thickness_fn = rgiid + '_thickness.tif' - dem_fn = 'surface_DEM_' + rgiid + '.tif' - - # Import tifs - thickness, thickness_pixel_x, thickness_pixel_y = import_raster(thickness_fp + thickness_fn) - dem_raw, dem_pixel_x, dem_pixel_y = import_raster(dem_fp + dem_fn) - -# if n_rgiid % 500 == 0: -# glacier_area_total = len(np.where(thickness > 0)[0]) * dem_pixel_x * dem_pixel_y / 10**6 -# print('glacier area [km2]:', np.round(glacier_area_total,2), -# 'vs RGI [km2]:', np.round(main_glac_rgi.loc[n_rgiid,'Area'],2)) - - # Glacier mask - glac_mask = np.zeros(thickness.shape) - glac_mask[thickness > 0] = 1 - - # Test for large discrepancies between RGI60, DEM, or data gaps - glac_pix_total = np.sum(glac_mask) - - # DEM - dem_masked = dem_raw.copy() - dem_masked[dem_masked < 0] = np.nan - dem_masked[(glac_mask == 0)] = np.nan - dem_masked = np.ma.masked_invalid(dem_masked) - - glac_pix_ltZmin = len(np.where(dem_masked < main_glac_rgi.loc[n_rgiid,'Zmin'])[0]) / glac_pix_total * 100 - glac_pix_gtZmax = len(np.where(dem_masked > main_glac_rgi.loc[n_rgiid,'Zmax'])[0]) / glac_pix_total * 100 - - if np.max([glac_pix_ltZmin, glac_pix_gtZmax]) > 10: - print('\n',rgiid, 'poor agreement with RGI60:\n pixels < Zmin [%]:', np.round(glac_pix_ltZmin,1), - '\n pixels > Zmin [%]:', np.round(glac_pix_gtZmax,1)) - skip_processing = 1 - else: - skip_processing = 0 - - if skip_processing == 0: - # Remove bad pixels: negative values and glacier pixels below minimum elevation - dem_raw[dem_raw < 0] = -9999 - dem_raw[(glac_mask == 1) & (dem_raw < main_glac_rgi.loc[n_rgiid,'Zmin'])] = -9999 - - - # Fill bad pixels: option_onlyglaciers controls if filling done using only glaciers or surrounding terrain - nan_glacpixels = np.where((dem_raw < 0) & (glac_mask ==1)) - if len(nan_glacpixels[0]) > 0: - nan_glacpixels_init = np.where((dem_raw < 0) & (glac_mask ==1)) - windowsize = 5 - while len(nan_glacpixels[0]) > 0 and windowsize < 26: - - nanpixels_prefill = len(nan_glacpixels[0]) - - dem_filled = filldem(dem_raw, glac_mask=glac_mask, windowsize=windowsize, option_onlyglaciers=1) - nan_glacpixels = np.where((dem_filled < 0) & (glac_mask ==1)) - - print(n_rgiid, rgiid, 'WindowSize:', windowsize, '# NaN pixels:', nanpixels_prefill, - 'Post-fill:', len(nan_glacpixels[0])) - - windowsize += 4 - -# for n in list(np.arange(0,len(nan_glacpixels_init[0]))): -# if dem_filled[nan_glacpixels_init[0][n], nan_glacpixels_init[1][n]] < 0: -# print(nan_glacpixels_init[0][n], nan_glacpixels_init[1][n], dem_filled[nan_glacpixels_init[0][n]]) - else: - dem_filled = dem_raw - - # DEM into bins - dem = np.zeros(thickness.shape) - dem_rounded = np.zeros(thickness.shape) - dem[glac_mask == 1] = dem_filled[glac_mask == 1] - dem_rounded[glac_mask == 1] = binsize * (dem[glac_mask == 1] / binsize).astype(int) + binsize / 2 - dem_rounded = dem_rounded.astype(int) - - # Unique bins exluding zero - elev_bins = list(np.unique(dem_rounded)) - elev_bins.remove(0) - - for elev_bin in elev_bins: - # for elev_bin in elev_bins[0:10]: - - if debug: - print('\nElevation bin:', elev_bin) - - bin_mask = np.where(dem_rounded == elev_bin) - - # Area [km2] - bin total - bin_hyps = len(bin_mask[0]) * dem_pixel_x * dem_pixel_y / 10**6 - - # Thickness [m] - bin mean - bin_thickness = thickness[bin_mask[0], bin_mask[1]].mean() - - # Slope [deg] - bin mean - grad_x, grad_y = np.gradient(dem_filled, dem_pixel_x, dem_pixel_y) - slope = np.arctan(np.sqrt(grad_x ** 2 + grad_y ** 2)) - slope_deg = np.rad2deg(slope) - bin_slope = np.mean(slope_deg[bin_mask]) - - # Length [km] - based on the mean slope and bin elevation - bin_length = binsize / np.tan(np.deg2rad(bin_slope)) / 1000 - - # Width [km] - based on length (inherently slope) and bin area - bin_width = bin_hyps / bin_length - - # Record properties - # print(n_rgiid, elev_bin, bin_hyps) - main_glac_hyps.loc[n_rgiid, elev_bin] = bin_hyps - main_glac_thickness.loc[n_rgiid, elev_bin] = bin_thickness - main_glac_width.loc[n_rgiid, elev_bin] = bin_width - main_glac_length.loc[n_rgiid, elev_bin] = bin_length - main_glac_slope.loc[n_rgiid, elev_bin] = bin_slope - - if main_glac_hyps.shape[1] > len(df_cns): - print(n_rgiid, rgiid, main_glac_hyps.shape[1]) - - #%% - return main_glac_hyps, main_glac_thickness, main_glac_width, main_glac_width, main_glac_slope - - -parser = getparser() -args = parser.parse_args() - -if args.debug == 1: - debug = True -else: - debug = False - -#%% -# Load Larsen dataset -larsen_summary = pd.read_csv(input.larsen_fp + input.larsen_fn) -larsen_summary = larsen_summary.sort_values('RGIId') -larsen_summary.reset_index(drop=True, inplace=True) -glacno = sorted([x.split('-')[1].split('.')[1] for x in larsen_summary.RGIId.values]) - -# Add directory names to Larsen dataset -glac_names = list(larsen_summary.name.values) -glac_names_nospace = [x.replace(' ','') for x in glac_names] -glac_names_nospace[glac_names_nospace.index('TlikakilaN.Fork')] = 'TlikakilaNorthFork' -glac_names_nospace[glac_names_nospace.index('TlikakilaFork')] = 'TlikakilaGlacierFork' -glac_names_nospace[glac_names_nospace.index('Melbern')] = 'GrandPacificMelbern' -larsen_summary['name_nospace'] = glac_names_nospace -larsen_summary['startyear_str'] = [str(x)[:4] for x in larsen_summary.date0.values] -larsen_summary['endyear_str'] = [str(x)[:4] for x in larsen_summary.date1.values] - -# Replace Mendenhall with '2000F', '2012F' -# Lemon Creek with '1993F', '2012F' -# Taku '1993F', '2012F' -# Nizina is not there -# Yanert is not available for the given time periods - others are - -# Load RGI attributes -rgi_regionsO1 = [1] -main_glac_rgi = modelsetup.selectglaciersrgitable(rgi_regionsO1=rgi_regionsO1, rgi_regionsO2='all', - rgi_glac_number=glacno) -main_glac_hyps_10m = modelsetup.import_Husstable(main_glac_rgi, input.hyps_filepath, - input.hyps_filedict, input.hyps_colsdrop) -binsize_rgi = int(main_glac_hyps_10m.columns[1]) - int(main_glac_hyps_10m.columns[0]) - -#%% -# Quick quality control check on Huss product -huss_area_ones = main_glac_hyps_10m.copy().values -huss_area_ones[huss_area_ones>0] = 1 -huss_area_ones_idxmax = np.argmax(huss_area_ones, axis=1) -main_glac_rgi['huss_min_elev'] = [int(main_glac_hyps_10m.columns.values[x]) for x in list(huss_area_ones_idxmax)] -main_glac_rgi['dif_min_elev'] = main_glac_rgi.Zmin - main_glac_rgi.huss_min_elev - -#rgi_bin_min = int(np.round(hyps_30m_cns[rgi_hyps_idx[0]])) -# rgi_bin_max = int(np.round(hyps_30m_cns[rgi_hyps_idx[-1]])) - - -#%% - -# Load RGI attributes -rgi_regionsO1 = [1] -main_glac_rgi_all = modelsetup.selectglaciersrgitable(rgi_regionsO1=rgi_regionsO1, rgi_regionsO2='all', - rgi_glac_number='all') -main_glac_hyps_all = modelsetup.import_Husstable(main_glac_rgi_all, input.hyps_filepath, - input.hyps_filedict, input.hyps_colsdrop) -# Quick quality control check on Huss product -huss_area_ones_all = main_glac_hyps_all.values.copy() -huss_area_ones_all[huss_area_ones_all>0] = 1 -huss_area_ones_all_idxmax = np.argmax(huss_area_ones_all, axis=1) -main_glac_rgi_all['huss_min_elev'] = [int(main_glac_hyps_all.columns.values[x]) for x in list(huss_area_ones_all_idxmax)] -main_glac_rgi_all['dif_min_elev'] = main_glac_rgi_all.Zmin - main_glac_rgi_all.huss_min_elev -dif_min_elev = main_glac_rgi_all['dif_min_elev'] -#main_glac_rgi_all.loc[main_glac_rgi_all.dif_min_elev < -500, 'dif_min_elev'] = -500 -#main_glac_rgi_all.loc[main_glac_rgi_all.dif_min_elev > 200, 'dif_min_elev'] = 200 -main_glac_rgi_all.dif_min_elev.plot.hist(bins=50, ylim=(0,100)) -#%% - - - -binsize = 30 # elevation bin must be an integer greater than 1 - -# Glacier hypsometry [km**2], total area -# NEED TO FIX BROKEN FUNCTION FOR PROCESSING FARINOTTI ET AL. (2019) DATA -#main_glac_hyps, main_glac_thickness, main_glac_width, main_glac_width, main_glac_slope = ( -# extract_hyps(main_glac_rgi, binsize)) - -add_cols = 3 - (main_glac_hyps_10m.shape[1] % 3) -for ncol in np.arange(0,add_cols): - colname = str(int(main_glac_hyps_10m.columns[-1]) + binsize_rgi) - main_glac_hyps_10m[colname] = 0 - -hyps_10m = main_glac_hyps_10m.values -hyps_30m = hyps_10m.reshape(-1,3).sum(1).reshape(hyps_10m.shape[0], int(hyps_10m.shape[1]/3)) -hyps_30m_cns = list(main_glac_hyps_10m.columns.values[1::3].astype(int)) -main_glac_hyps_30m = pd.DataFrame(hyps_30m, columns=hyps_30m_cns) - - -#%% -data_header = ['E', 'DZ', 'DZ25', 'DZ75', 'AAD', 'MassChange', 'MassBal', 'NumData'] -larsen_summary['mb_mwea_v2'] = np.nan -larsen_summary['mb_gta_v2'] = np.nan -larsen_summary['area_rgi'] = np.nan -larsen_summary['min_elev'] = np.nan -larsen_summary['min_elev_huss'] = main_glac_rgi.huss_min_elev.values - -for nglac, glac_name in enumerate(list(larsen_summary.name.values)): - - print(nglac) - larsen_glac_fp = input.main_directory + '/../DEMs/larsen/data/' - larsen_glac_fn = (larsen_summary.loc[nglac,'name_nospace'] + '.' + larsen_summary.loc[nglac,'startyear_str'] + '.' + - larsen_summary.loc[nglac,'endyear_str'] + '.output.txt') - -# larsen_glac_fn = 'Taku.2007.2014.output.txt' - - if os.path.isfile(larsen_glac_fp + larsen_glac_fn): - data = np.genfromtxt(larsen_glac_fp + larsen_glac_fn, skip_header=3) - df = pd.DataFrame(data, columns=data_header) - # Shift bins by 15 so elevations based on center of bin and not bottom of bin - df['E'] = df.E + 15 - - if larsen_summary.loc[nglac,'term_type'] == 'Tidewater': - print(nglac, larsen_summary.loc[nglac,'term_type'], df.loc[0,'E']) - - # Check if all bins accounted for - rgi_hyps_raw = np.array(main_glac_hyps_30m.loc[nglac,:].values) - rgi_hyps_idx = np.where(rgi_hyps_raw > 0)[0] - - rgi_bin_min = int(np.round(hyps_30m_cns[rgi_hyps_idx[0]])) - rgi_bin_max = int(np.round(hyps_30m_cns[rgi_hyps_idx[-1]])) - - - # ===== EXTEND TERMINUS (if needed) ===== - larsen_bin_min = int(np.round(df.loc[0,'E'])) - larsen_summary.loc[nglac,'min_elev'] = larsen_bin_min - if rgi_bin_min > larsen_bin_min: - print(glac_name, 'Larsen terminus is lower by ' + str(int(rgi_bin_min - larsen_bin_min)) + ' m') - rgi_bin_min = larsen_bin_min - - elif rgi_bin_min < larsen_bin_min: - n_bins2add = int((larsen_bin_min - rgi_bin_min) / binsize) - df_2append = pd.DataFrame(np.full((n_bins2add,len(df.columns)),np.nan), columns=df.columns) - df_2append['E'] = np.arange(rgi_bin_min, larsen_bin_min, binsize) - df_2append['DZ'] = df.loc[0,'DZ'] - df = df_2append.append(df) - df.reset_index(inplace=True, drop=True) - print('rgi bin is lower') - - # ===== EXPAND ACCUMULATION AREA (if needed) ===== - larsen_bin_max = int(np.round(df.loc[df.shape[0]-1,'E'])) - if rgi_bin_max < larsen_bin_max: - print(glac_name, 'Larsen peak is higher by ' + str(int(larsen_bin_max - rgi_bin_max)) + ' m') - rgi_bin_max = larsen_bin_max - - - elif rgi_bin_max > larsen_bin_max: - # Append more bins - n_bins2add = int((rgi_bin_max - larsen_bin_max) / binsize) - df_2append = pd.DataFrame(np.full((n_bins2add,len(df.columns)),np.nan), columns=df.columns) - df_2append['E'] = np.arange(larsen_bin_max + 15, larsen_bin_max + n_bins2add * binsize, binsize) - df = df.append(df_2append) - df.reset_index(inplace=True, drop=True) - - # Set accumulation at top bin to zero - df.loc[df.shape[0]-1,'DZ'] = 0 - # Linearly interpolate other values - df['DZ'] = df.DZ.interpolate(method='linear') - - df['E_norm'] = (df.E - df.E.min()) / (df.E.max() - df.E.min()) - - df['hyps_km2'] = main_glac_hyps_30m.loc[nglac, rgi_bin_min:rgi_bin_max].values - -# #%% -# A = main_glac_hyps_30m.loc[nglac, rgi_bin_min:rgi_bin_max].values -# B = hyps_30m_cns[rgi_hyps_idx[0]:rgi_hyps_idx[-1]+1] -# #%% - - df['mb_mwea'] = df.DZ * 850/1000 - df['mb_gta'] = df.mb_mwea / 1000 * df.hyps_km2 - - glac_mb_gta = df.mb_gta.sum() - glac_mb_mwea = glac_mb_gta / df.hyps_km2.sum() * 1000 -# print('Mass loss [Gt yr-1]:', np.round(glac_mb_gta,3)) - print('Mass loss [mwe yr-1]:', np.round(glac_mb_mwea,2)) - - larsen_summary.loc[nglac, 'mb_mwea_v2'] = glac_mb_mwea - larsen_summary.loc[nglac, 'mb_gta_v2'] = glac_mb_gta - larsen_summary.loc[nglac, 'area_rgi'] = df.hyps_km2.sum() - - # Elevation Change vs. Normalized Elevation - fig, ax = plt.subplots(1, 1, squeeze=False, sharex=False, sharey=False, - gridspec_kw = {'wspace':0.4, 'hspace':0.15}) - ax[0,0].plot(df.E_norm.values, df.DZ.values, color='k', linewidth=1, zorder=2, label='Baird') - - ax[0,0].set_xlabel('Normalized Elevation', size=12) - ax[0,0].set_ylabel('Elevation Change (m yr-1)', size=12) - - ax[0,0].set_xlim(0,1) - - # Save figure - # figures can be saved in any format (.jpg, .png, .pdf, etc.) - fig.set_size_inches(6, 4) - figure_fp = larsen_glac_fp + '/figures/' - if os.path.exists(figure_fp) == False: - os.makedirs(figure_fp) - figure_fn = larsen_glac_fn.replace('output.txt','_elevchg.png') - fig.savefig(figure_fp + figure_fn, bbox_inches='tight', dpi=300) - plt.close(fig) - - else: - print(glac_name, 'filename not correct or not available') - -#%% -larsen_summary['dif_min_elev'] = larsen_summary.min_elev - larsen_summary.min_elev_huss -larsen_summary['dif_mwea'] = larsen_summary.mb_mwea - larsen_summary.mb_mwea_v2 - -A = larsen_summary.dif_min_elev.values -B = np.where(np.array([0 if np.isnan(x) else x for x in A]) < -100)[0] - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/run_select_nnbr.py b/run_select_nnbr.py deleted file mode 100644 index 2ebd27a0..00000000 --- a/run_select_nnbr.py +++ /dev/null @@ -1,283 +0,0 @@ -""" -run_select_nnbr.py selects the best parameter set for the uncalibrated glaciers based on the nearest neighbors. -Specifically, the script iterates through the nearest neighbors until the modeled mass balance using the reference -climate dataset is within +/- 1 stdev from the mb_mwea statistics from the neighbors. -""" - -import pandas as pd -import numpy as np -import time -from time import strftime -from sklearn.neighbors import NearestNeighbors - -import pygem_input as input -import pygemfxns_modelsetup as modelsetup -#import pygemfxns_climate as climate -import pygemfxns_massbalance as massbalance -#import pygemfxns_output as output -import class_climate - -#%% INPUT -rgi_regionsO1 = [15] -rgi_glac_number = 'all' - -startyear = 2000 -endyear = 2015 -spinupyears = 5 -# Calibrated model parameters full filename (needs to include 'all' glaciers in a region) -cal_modelparams_fullfn = input.main_directory + '/../Output/20180710_cal_modelparams_opt1_R15_ERA-Interim_1995_2015.csv' -# Number of nearest neighbors -n_nbrs = 20 -# Option to remove marine-terminating glaciers -option_cal_remove_marine_glaciers = 1 - -# Reference climate data -gcm_name = 'ERA-Interim' -option_gcm_downscale = 2 -option_lapserate_fromgcm = 1 - -option_export = 1 - -time_start = time.time() - -#%% ===== LOAD GLACIER DATA ===== -# RGI glacier attributes -main_glac_rgi = modelsetup.selectglaciersrgitable(rgi_regionsO1=rgi_regionsO1, - rgi_regionsO2='all', - rgi_glac_number='all') -# Glacier hypsometry [km**2], total area -main_glac_hyps = modelsetup.import_Husstable(main_glac_rgi, input.hyps_filepath, - input.hyps_filedict, input.hyps_colsdrop) -elev_bins = main_glac_hyps.columns.values.astype(int) -# Ice thickness [m], average -main_glac_icethickness = modelsetup.import_Husstable(main_glac_rgi, input.thickness_filepath, - input.thickness_filedict, input.thickness_colsdrop) -main_glac_hyps[main_glac_icethickness == 0] = 0 -# Width [km], average -main_glac_width = modelsetup.import_Husstable(main_glac_rgi, input.width_filepath, - input.width_filedict, input.width_colsdrop) -# Add volume [km**3] and mean elevation [m a.s.l.] to the main glaciers table -main_glac_rgi['Volume'], main_glac_rgi['Zmean'] = modelsetup.hypsometrystats(main_glac_hyps, main_glac_icethickness) -# Model time frame -dates_table = modelsetup.datesmodelrun(startyear, endyear, spinupyears) -# Quality control - if ice thickness = 0, glacier area = 0 (problem identified by glacier RGIV6-15.00016 03/06/2018) -main_glac_hyps[main_glac_icethickness == 0] = 0 - -#%% ===== LOAD CLIMATE DATA ===== -gcm = class_climate.GCM(name=gcm_name) -if option_gcm_downscale == 1: - # Air Temperature [degC] and GCM dates - gcm_temp, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn, gcm.temp_vn, main_glac_rgi, dates_table) - # Precipitation [m] and GCM dates - gcm_prec, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn, gcm.prec_vn, main_glac_rgi, dates_table) - # Elevation [m a.s.l] associated with air temperature and precipitation data - gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn, main_glac_rgi) - # Air temperature standard deviation - if input.option_ablation != 2: - gcm_tempstd = np.zeros(gcm_temp.shape) - elif gcm_name in ['ERA5']: - gcm_tempstd, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.tempstd_fn, gcm.tempstd_vn, - main_glac_rgi, dates_table) - # Lapse rates [degC m-1] - if option_lapserate_fromgcm == 1: - gcm_lr, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.lr_fn, gcm.lr_vn, main_glac_rgi, dates_table) - # Add GCM time series to the dates_table - dates_table['date_gcm'] = gcm_dates - -elif option_gcm_downscale == 2: - # 32 seconds for Region 15 - # Import air temperature, precipitation, and elevation from pre-processed csv files for a given region - # this simply saves time from re-running the fxns above - gcm_temp_all = np.genfromtxt(gcm.var_fp + input.gcmtemp_filedict[input.rgi_regionsO1[0]], delimiter=',') - gcm_prec_all = np.genfromtxt(gcm.var_fp + input.gcmprec_filedict[input.rgi_regionsO1[0]], delimiter=',') - gcm_elev_all = np.genfromtxt(gcm.fx_fp + input.gcmelev_filedict[input.rgi_regionsO1[0]], delimiter=',') - # Lapse rates [degC m-1] - gcm_lr_all = np.genfromtxt(gcm.var_fp + input.gcmlapserate_filedict[input.rgi_regionsO1[0]], - delimiter=',') - # Select the climate data for the glaciers included in the study - gcm_temp = gcm_temp_all[main_glac_rgi['O1Index'].values] - gcm_prec = gcm_prec_all[main_glac_rgi['O1Index'].values] - gcm_elev = gcm_elev_all[main_glac_rgi['O1Index'].values] - gcm_lr = gcm_lr_all[main_glac_rgi['O1Index'].values] - -print('Loading time:', time.time()-time_start, 's') - -#%% ===== NEAREST NEIGHBOR SELECTION ===== -# The selection of nearest neighbors looks at the closest 20 pixels and looks at the - -# Load calibrated parameters -ds_cal = pd.read_csv(cal_modelparams_fullfn, index_col=0) -ds_cal['newidx'] = ds_cal['O1Index'] -ds_cal.set_index('newidx', inplace=True, drop=True) - -# Dictionary cal index and 'GlacNo' -cal_dict = dict(zip(np.arange(0,ds_cal.shape[0]), ds_cal.index.values)) -# Dataframe of all glaciers with model parameters from nearest neighbors -main_glac_modelparamsopt_pd = pd.DataFrame(np.full([main_glac_rgi.shape[0], len(input.modelparams_colnames)], np.nan), - columns=input.modelparams_colnames) -main_glac_modelparamsopt_pd.index = main_glac_rgi.index.values -ds_cal_all = pd.concat([main_glac_rgi.copy(), main_glac_modelparamsopt_pd], axis=1) -ds_cal_all['mbclim_mwe'] = np.nan -# Fill in the values of the already calibrated glaciers -ds_cal_all = ds_cal_all.combine_first(ds_cal) -# Add columns describing nearest neighbors -ds_cal_all['nbr_idx'] = np.nan -ds_cal_all['nbr_idx_count'] = np.nan -ds_cal_all['nbr_mb_mean'] = np.nan -ds_cal_all['nbr_mb_std'] = np.nan -ds_cal_all['z_score'] = np.nan -nbr_idx_cols = [] -for n in range(n_nbrs): - nbr_col_name = 'nearidx_' + str(n+1) - ds_cal_all[nbr_col_name] = np.nan - nbr_idx_cols.append(nbr_col_name) - -# AVOID MARINE-TERMINATING GLACIERS UNTIL FRONTAL ABLATION IS INCLUDED, i.e., climatic mass balance is separated -# Remove marine-terminating glaciers from calibration dataset such that they are not included in neighbor calculations -if option_cal_remove_marine_glaciers == 1: - ds_cal = ds_cal[ds_cal.TermType != 1] - -# Loop through each glacier and select the n_nbrs closest glaciers -for glac in range(main_glac_rgi.shape[0]): - # Select nnbrs only for uncalibrated glaciers - if ds_cal_all.loc[glac, input.modelparams_colnames].isnull().values.any() == True: - # Print every 100th glacier -# if glac%500 == 0: -# print(main_glac_rgi.loc[glac,'RGIId']) - print(main_glac_rgi.loc[glac,'RGIId']) - # Select the lon/lat of the glacier - glac_lonlat = np.zeros((1,2)) - glac_lonlat[:] = ds_cal_all.loc[glac,['CenLon','CenLat']].values - # Append the lon/lat - glac_lonlat_wcal = np.append(glac_lonlat, ds_cal.loc[:,['CenLon','CenLat']].values, axis=0) - # Calculate nearest neighbors (set neighbors + 1 to account for itself) - nbrs = NearestNeighbors(n_neighbors=n_nbrs+1, algorithm='brute').fit(glac_lonlat_wcal) - distances_raw, indices_raw = nbrs.kneighbors(glac_lonlat_wcal) - # Select glacier (row 0) and remove itself (col 0), so left with indices for nearest neighbors - indices_raw2 = indices_raw[0,:][indices_raw[0,:] > 0] - 1 - indices = np.array([cal_dict[n] for n in indices_raw2]) - # Add indices to columns - ds_cal_all.loc[glac, nbr_idx_cols] = indices - - # Nearest neighbors: mass balance envelope - nbrs_data = np.zeros((len(nbr_idx_cols),4)) - # Col 0 - index count - # Col 1 - index value - # Col 2 - MB - # Col 3 - MB modeled using neighbor's parameter - nbrs_data[:,0] = np.arange(1,len(nbr_idx_cols)+1) - nbrs_data[:,1] = ds_cal_all.loc[glac, nbr_idx_cols].values.astype(int) - nbrs_data[:,2] = ds_cal_all.loc[nbrs_data[:,1], input.mbclim_cn] - mb_nbrs_mean = nbrs_data[:,2].mean() - mb_nbrs_std = nbrs_data[:,2].std() - mb_envelope_lower = mb_nbrs_mean - mb_nbrs_std - mb_envelope_upper = mb_nbrs_mean + mb_nbrs_std - - # Set nbr_idx_count to -1, since adds 1 at the start - nbr_idx_count = -1 - # Loop through nearest neighbors until find set of model parameters that returns MB in MB envelope - # Break loop used to exit loop if unable to find parameter set that satisfies criteria - break_while_loop = False - while break_while_loop == False: - # Nearest neighbor index - nbr_idx_count = nbr_idx_count + 1 - # Check if cycled through all neighbors; if so, then choose neighbor with MB closest to the envelope - if nbr_idx_count == len(nbr_idx_cols): - break_while_loop = True - mb_abs = np.zeros((nbrs_data.shape[0],2)) - mb_abs[:,0] = abs(nbrs_data[:,3] - mb_envelope_lower) - mb_abs[:,1] = abs(nbrs_data[:,3] - mb_envelope_upper) - nbr_idx_count = np.where(mb_abs == mb_abs.min())[0][0] - # Nearest neighbor index value - nbr_idx = nbrs_data[nbr_idx_count,1] - # Model parameters - apply transfer function adjustments - modelparameters = ds_cal_all.loc[nbr_idx, input.modelparams_colnames] - modelparameters['tempchange'] = ( - modelparameters['tempchange'] + input.tempchange_lobf_slope * - (main_glac_rgi.loc[glac, input.tempchange_lobf_property_cn] - - ds_cal_all.loc[nbr_idx, input.tempchange_lobf_property_cn])) - modelparameters['precfactor'] = ( - modelparameters['precfactor'] + input.precfactor_lobf_slope * - (main_glac_rgi.loc[glac, input.precfactor_lobf_property_cn] - - ds_cal_all.loc[nbr_idx, input.precfactor_lobf_property_cn])) - modelparameters['ddfsnow'] = ( - modelparameters['ddfsnow'] + input.ddfsnow_lobf_slope * - (main_glac_rgi.loc[glac, input.ddfsnow_lobf_property_cn] - - ds_cal_all.loc[nbr_idx, input.ddfsnow_lobf_property_cn])) - modelparameters['ddfice'] = modelparameters['ddfsnow'] / input.ddfsnow_iceratio - modelparameters['precgrad'] = ( - modelparameters['precgrad'] + input.precgrad_lobf_slope * - (main_glac_rgi.loc[glac, input.precgrad_lobf_property_cn] - - ds_cal_all.loc[nbr_idx, input.precgrad_lobf_property_cn])) - # Select subsets of data - glacier_rgi_table = main_glac_rgi.loc[glac, :] - glacier_gcm_elev = gcm_elev[glac] - glacier_gcm_prec = gcm_prec[glac,:] - glacier_gcm_temp = gcm_temp[glac,:] - glacier_gcm_tempstd = gcm_tempstd[glac,:] - glacier_gcm_lrgcm = gcm_lr[glac,:] - glacier_gcm_lrglac = glacier_gcm_lrgcm.copy() - glacier_area_t0 = main_glac_hyps.iloc[glac,:].values.astype(float) - icethickness_t0 = main_glac_icethickness.iloc[glac,:].values.astype(float) - width_t0 = main_glac_width.iloc[glac,:].values.astype(float) - # Avoid error where there is no glacier/ice thickness - give it parameters to avoid issues in simulation - if glacier_area_t0.max() == 0: - break_while_loop = True - nbr_idx = nbrs_data[0,1] - mbclim_mwe = np.nan - # As long as there is ice present, then select parameters from nearest neighbors - else: - # MASS BALANCE - # Run the mass balance function (spinup years have been removed from output) - (glac_bin_temp, glac_bin_prec, glac_bin_acc, glac_bin_refreeze, glac_bin_snowpack, glac_bin_melt, - glac_bin_frontalablation, glac_bin_massbalclim, glac_bin_massbalclim_annual, glac_bin_area_annual, - glac_bin_icethickness_annual, glac_bin_width_annual, glac_bin_surfacetype_annual, - glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, - glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, - offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( - massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_t0, icethickness_t0, - width_t0, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, - glacier_gcm_prec, glacier_gcm_elev, glacier_gcm_lrgcm, - glacier_gcm_lrglac, dates_table, - option_areaconstant=1)) - # Glacier-wide climatic mass balance [m w.e.] based on initial area - mbclim_mwe = ( - (glac_bin_massbalclim * glac_bin_area_annual[:, 0][:,np.newaxis]).sum() / - glac_bin_area_annual[:, 0].sum()) - nbrs_data[nbr_idx_count,3] = mbclim_mwe - - # Prior to breaking loop print RGIId and z score - if break_while_loop == True: - # Compute z score and print out value - z_score = (mbclim_mwe - mb_nbrs_mean) / mb_nbrs_std - if abs(z_score) > 1.96: - print(glacier_rgi_table.RGIId, 'z_score:', mbclim_mwe, np.round(z_score,2)) - - # If mass balance falls within envelope, then end while loop - if (mbclim_mwe <= mb_envelope_upper) and (mbclim_mwe >= mb_envelope_lower): - break_while_loop = True - - # Record results - if break_while_loop == True: - z_score = (mbclim_mwe - mb_nbrs_mean) / mb_nbrs_std - ds_cal_all.loc[glac, input.mbclim_cn] = mbclim_mwe - ds_cal_all.loc[glac, 'nbr_idx'] = nbr_idx - ds_cal_all.loc[glac, 'nbr_idx_count'] = nbr_idx_count + 1 - ds_cal_all.loc[glac, 'nbr_mb_mean'] = mb_nbrs_mean - ds_cal_all.loc[glac, 'nbr_mb_std'] = mb_nbrs_std - ds_cal_all.loc[glac, 'z_score'] = z_score - ds_cal_all.loc[glac, 'lrgcm'] = ds_cal_all.loc[nbr_idx, 'lrgcm'] - ds_cal_all.loc[glac, 'lrglac'] = ds_cal_all.loc[nbr_idx, 'lrglac'] - ds_cal_all.loc[glac, 'precfactor'] = modelparameters['precfactor'] - ds_cal_all.loc[glac, 'precgrad'] = ds_cal_all.loc[nbr_idx, 'precgrad'] - ds_cal_all.loc[glac, 'ddfsnow'] = modelparameters['ddfsnow'] - ds_cal_all.loc[glac, 'ddfice'] = modelparameters['ddfice'] - ds_cal_all.loc[glac, 'tempsnow'] = ds_cal_all.loc[nbr_idx, 'tempsnow'] - ds_cal_all.loc[glac, 'tempchange'] = modelparameters['tempchange'] - - -if option_export == 1: - output_fullfn = cal_modelparams_fullfn.replace('.csv', '_wnnbrs_' + str(strftime("%Y%m%d")) + '.csv') - ds_cal_all.to_csv(output_fullfn, sep=',') - -print('Processing time:', time.time()-time_start, 's') \ No newline at end of file diff --git a/run_simulation.py b/run_simulation.py index 8b37a399..98d87374 100644 --- a/run_simulation.py +++ b/run_simulation.py @@ -33,7 +33,7 @@ def getparser(): """ Use argparse to add arguments from the command line - + Parameters ---------- gcm_list_fn (optional) : str @@ -52,13 +52,11 @@ def getparser(): batch number used to differentiate output on supercomputer option_ordered : int option to keep glaciers ordered or to grab every n value for the batch - (the latter helps make sure run times on each core are similar as it removes any timing differences caused by + (the latter helps make sure run times on each core are similar as it removes any timing differences caused by regional variations) debug (optional) : int Switch for turning debug printing on or off (default = 0 (off)) - debug_spc (optional) : int - Switch for turning debug printing of spc on or off (default = 0 (off)) - + Returns ------- Object containing arguments and their respective values. @@ -83,49 +81,48 @@ def getparser(): help='switch to keep lists ordered or not') parser.add_argument('-debug', action='store', type=int, default=0, help='Boolean for debugging to turn it on or off (default 0 is off') - parser.add_argument('-debug_spc', action='store', type=int, default=0, - help='Boolean for debugging to turn it on or off (default 0 is off') return parser -def calc_stats_array(data, stats_cns=input.sim_stat_cns): - """ - Calculate stats for a given variable - - Parameters - ---------- - vn : str - variable name - ds : xarray dataset - dataset of output with all ensemble simulations - - Returns - ------- - stats : np.array - Statistics related to a given variable - """ - if 'mean' in stats_cns: - stats = data.mean(axis=1)[:,np.newaxis] - if 'std' in stats_cns: - stats = np.append(stats, data.std(axis=1)[:,np.newaxis], axis=1) - if '2.5%' in stats_cns: - stats = np.append(stats, np.percentile(data, 2.5, axis=1)[:,np.newaxis], axis=1) - if '25%' in stats_cns: - stats = np.append(stats, np.percentile(data, 25, axis=1)[:,np.newaxis], axis=1) - if 'median' in stats_cns: - stats = np.append(stats, np.median(data, axis=1)[:,np.newaxis], axis=1) - if '75%' in stats_cns: - stats = np.append(stats, np.percentile(data, 75, axis=1)[:,np.newaxis], axis=1) - if '97.5%' in stats_cns: - stats = np.append(stats, np.percentile(data, 97.5, axis=1)[:,np.newaxis], axis=1) - return stats - - -def create_xrdataset(main_glac_rgi, dates_table, sim_iters=input.sim_iters, stat_cns=input.sim_stat_cns, +def calc_stats(vn, ds, stats_cns=input.sim_stat_cns, glac=0): + """ + Calculate stats for a given variable + + Parameters + ---------- + vn : str + variable name + ds : xarray dataset + dataset of output with all ensemble simulations + + Returns + ------- + stats : np.array + Statistics related to a given variable + """ + data = ds[vn].values[glac,:,:] + if 'mean' in stats_cns: + stats = data.mean(axis=1)[:,np.newaxis] + if 'std' in stats_cns: + stats = np.append(stats, data.std(axis=1)[:,np.newaxis], axis=1) + if '2.5%' in stats_cns: + stats = np.append(stats, np.percentile(data, 2.5, axis=1)[:,np.newaxis], axis=1) + if '25%' in stats_cns: + stats = np.append(stats, np.percentile(data, 25, axis=1)[:,np.newaxis], axis=1) + if 'median' in stats_cns: + stats = np.append(stats, np.median(data, axis=1)[:,np.newaxis], axis=1) + if '75%' in stats_cns: + stats = np.append(stats, np.percentile(data, 75, axis=1)[:,np.newaxis], axis=1) + if '97.5%' in stats_cns: + stats = np.append(stats, np.percentile(data, 97.5, axis=1)[:,np.newaxis], axis=1) + return stats + + +def create_xrdataset(main_glac_rgi, dates_table, sim_iters=input.sim_iters, stat_cns=input.sim_stat_cns, record_stats=0, option_wateryear=input.gcm_wateryear): """ Create empty xarray dataset that will be used to record simulation runs. - + Parameters ---------- main_glac_rgi : pandas dataframe @@ -138,14 +135,14 @@ def create_xrdataset(main_glac_rgi, dates_table, sim_iters=input.sim_iters, stat list of strings containing statistics that will be used on simulations record_stats : int Switch to change from recording simulations to statistics - + Returns ------- output_ds_all : xarray Dataset empty xarray dataset that contains variables and attributes to be filled in by simulation runs encoding : dictionary encoding used with exporting xarray dataset to netcdf - """ + """ if input.output_package == 2: # Create empty datasets for each variable and merge them # Coordinate values @@ -154,7 +151,7 @@ def create_xrdataset(main_glac_rgi, dates_table, sim_iters=input.sim_iters, stat annual_columns = np.unique(dates_table['wateryear'].values)[0:int(dates_table.shape[0]/12)] time_values = dates_table.loc[input.spinupyears*12:dates_table.shape[0]+1,'date'].tolist() year_values = annual_columns[input.spinupyears:annual_columns.shape[0]] - year_plus1_values = np.concatenate((annual_columns[input.spinupyears:annual_columns.shape[0]], + year_plus1_values = np.concatenate((annual_columns[input.spinupyears:annual_columns.shape[0]], np.array([annual_columns[annual_columns.shape[0]-1]+1]))) # Year type for attributes if option_wateryear == 1: @@ -163,7 +160,7 @@ def create_xrdataset(main_glac_rgi, dates_table, sim_iters=input.sim_iters, stat year_type = 'calendar year' else: year_type = 'custom year' - + # Switch to record simulations or statistics if record_stats == 0: record_name = 'sim' @@ -171,7 +168,7 @@ def create_xrdataset(main_glac_rgi, dates_table, sim_iters=input.sim_iters, stat elif record_stats == 1: record_name = 'stats' record_name_values = input.sim_stat_cns - + # Variable coordinates dictionary output_coords_dict = { 'prec_glac_monthly': collections.OrderedDict( @@ -185,11 +182,11 @@ def create_xrdataset(main_glac_rgi, dates_table, sim_iters=input.sim_iters, stat 'melt_glac_monthly': collections.OrderedDict( [('glac', glac_values), ('time', time_values), (record_name, record_name_values)]), 'frontalablation_glac_monthly': collections.OrderedDict( - [('glac', glac_values), ('time', time_values), (record_name, record_name_values)]), + [('glac', glac_values), ('time', time_values), (record_name, record_name_values)]), 'massbaltotal_glac_monthly': collections.OrderedDict( [('glac', glac_values), ('time', time_values), (record_name, record_name_values)]), 'runoff_glac_monthly': collections.OrderedDict( - [('glac', glac_values), ('time', time_values), (record_name, record_name_values)]), + [('glac', glac_values), ('time', time_values), (record_name, record_name_values)]), 'snowline_glac_monthly': collections.OrderedDict( [('glac', glac_values), ('time', time_values), (record_name, record_name_values)]), 'area_glac_annual': collections.OrderedDict( @@ -207,7 +204,7 @@ def create_xrdataset(main_glac_rgi, dates_table, sim_iters=input.sim_iters, stat 'offglac_snowpack_monthly': collections.OrderedDict( [('glac', glac_values), ('time', time_values), (record_name, record_name_values)]), 'offglac_runoff_monthly': collections.OrderedDict( - [('glac', glac_values), ('time', time_values), (record_name, record_name_values)]), + [('glac', glac_values), ('time', time_values), (record_name, record_name_values)]), } # Attributes dictionary output_attrs_dict = { @@ -225,7 +222,7 @@ def create_xrdataset(main_glac_rgi, dates_table, sim_iters=input.sim_iters, stat 'long_name': 'years plus one additional year', 'year_type': year_type, 'comment': ('additional year allows one to record glacier dimension changes at end of ' - 'model run')}, + 'model run')}, 'sim': { 'long_name': 'simulation number', 'comment': 'simulation numbers only needed for MCMC methods'}, @@ -290,14 +287,14 @@ def create_xrdataset(main_glac_rgi, dates_table, sim_iters=input.sim_iters, stat 'long_name': 'glacier volume', 'units': 'km**3 ice', 'temporal_resolution': 'annual', - 'comment': 'volume based on area and ice thickness used for that year'}, + 'comment': 'volume based on area and ice thickness used for that year'}, 'ELA_glac_annual': { 'long_name': 'annual equilibrium line altitude', 'units': 'm a.s.l.', 'temporal_resolution': 'annual', 'comment': ( 'equilibrium line altitude is the elevation where the climatic mass balance is ' - 'zero')}, + 'zero')}, 'offglac_prec_monthly': { 'long_name': 'off-glacier-wide precipitation (liquid)', 'units': 'm', @@ -323,7 +320,7 @@ def create_xrdataset(main_glac_rgi, dates_table, sim_iters=input.sim_iters, stat 'temporal_resolution': 'monthly', 'comment': 'snow remaining accounting for new accumulation, melt, and refreeze'}, } - + # Add variables to empty dataset and merge together count_vn = 0 encoding = {} @@ -359,12 +356,12 @@ def create_xrdataset(main_glac_rgi, dates_table, sim_iters=input.sim_iters, stat return output_ds_all, encoding -def convert_glacwide_results(elev_bins, glac_bin_temp, glac_bin_prec, glac_bin_acc, glac_bin_refreeze, - glac_bin_snowpack, glac_bin_melt, glac_bin_frontalablation, glac_bin_massbalclim_annual, +def convert_glacwide_results(elev_bins, glac_bin_temp, glac_bin_prec, glac_bin_acc, glac_bin_refreeze, + glac_bin_snowpack, glac_bin_melt, glac_bin_frontalablation, glac_bin_massbalclim_annual, glac_bin_area_annual, glac_bin_icethickness_annual): """ Convert raw runmassbalance function output to glacier-wide results for output package 2 - + Parameters ---------- elev_bins : numpy array @@ -384,12 +381,12 @@ def convert_glacwide_results(elev_bins, glac_bin_temp, glac_bin_prec, glac_bin_a glac_bin_frontalablation : numpy array frontal ablation for each elevation bin for each timestep glac_bin_massbalclim_annual : numpy array - annual climatic mass balance for each elevation bin for each timestep + annual climatic mass balance for each elevation bin for each timestep glac_bin_area_annual : numpy array annual glacier area for each elevation bin for each timestep glac_bin_icethickness_annual: numpy array annual ice thickness for each elevation bin for each timestep - + Returns ------- glac_wide_temp : np.array @@ -431,35 +428,35 @@ def convert_glacwide_results(elev_bins, glac_bin_temp, glac_bin_prec, glac_bin_a glac_bin_temp_nonzero = np.zeros(glac_bin_temp.shape) glac_bin_temp_nonzero[glac_bin_temp != 0] = 1 glac_wide_temp_bincount = glac_bin_temp_nonzero.sum(axis=0) - glac_wide_temp[glac_wide_temp_bincount > 0] = (glac_wide_temp_sum[glac_wide_temp_bincount > 0] / + glac_wide_temp[glac_wide_temp_bincount > 0] = (glac_wide_temp_sum[glac_wide_temp_bincount > 0] / glac_wide_temp_bincount[glac_wide_temp_bincount > 0]) glac_wide_prec_mkm2 = (glac_bin_prec * glac_bin_area).sum(axis=0) - glac_wide_prec[glac_wide_prec_mkm2 > 0] = (glac_wide_prec_mkm2[glac_wide_prec_mkm2 > 0] / + glac_wide_prec[glac_wide_prec_mkm2 > 0] = (glac_wide_prec_mkm2[glac_wide_prec_mkm2 > 0] / glac_wide_area[glac_wide_prec_mkm2 > 0]) glac_wide_acc_mkm2 = (glac_bin_acc * glac_bin_area).sum(axis=0) - glac_wide_acc[glac_wide_acc_mkm2 > 0] = (glac_wide_acc_mkm2[glac_wide_acc_mkm2 > 0] / + glac_wide_acc[glac_wide_acc_mkm2 > 0] = (glac_wide_acc_mkm2[glac_wide_acc_mkm2 > 0] / glac_wide_area[glac_wide_acc_mkm2 > 0]) glac_wide_refreeze_mkm2 = (glac_bin_refreeze * glac_bin_area).sum(axis=0) - glac_wide_refreeze[glac_wide_refreeze_mkm2 > 0] = (glac_wide_refreeze_mkm2[glac_wide_refreeze_mkm2 > 0] / + glac_wide_refreeze[glac_wide_refreeze_mkm2 > 0] = (glac_wide_refreeze_mkm2[glac_wide_refreeze_mkm2 > 0] / glac_wide_area[glac_wide_refreeze_mkm2 > 0]) glac_wide_melt_mkm2 = (glac_bin_melt * glac_bin_area).sum(axis=0) - glac_wide_melt[glac_wide_melt_mkm2 > 0] = (glac_wide_melt_mkm2[glac_wide_melt_mkm2 > 0] / + glac_wide_melt[glac_wide_melt_mkm2 > 0] = (glac_wide_melt_mkm2[glac_wide_melt_mkm2 > 0] / glac_wide_area[glac_wide_melt_mkm2 > 0]) glac_wide_frontalablation_mkm2 = (glac_bin_frontalablation * glac_bin_area).sum(axis=0) glac_wide_frontalablation[glac_wide_frontalablation_mkm2 > 0] = ( - glac_wide_frontalablation_mkm2[glac_wide_frontalablation_mkm2 > 0] / + glac_wide_frontalablation_mkm2[glac_wide_frontalablation_mkm2 > 0] / glac_wide_area[glac_wide_frontalablation_mkm2 > 0]) glac_wide_massbalclim = glac_wide_acc + glac_wide_refreeze - glac_wide_melt glac_wide_massbaltotal = glac_wide_massbalclim - glac_wide_frontalablation glac_wide_runoff = (glac_wide_prec + glac_wide_melt - glac_wide_refreeze) * glac_wide_area * (1000)**2 # units: (m + m w.e. - m w.e.) * km**2 * (1000 m / 1 km)**2 = m**3 glac_wide_snowline = (glac_bin_snowpack > 0).argmax(axis=0) - glac_wide_snowline[glac_wide_snowline > 0] = (elev_bins[glac_wide_snowline[glac_wide_snowline > 0]] - + glac_wide_snowline[glac_wide_snowline > 0] = (elev_bins[glac_wide_snowline[glac_wide_snowline > 0]] - input.binsize/2) glac_wide_area_annual = glac_bin_area_annual.sum(axis=0) glac_wide_volume_annual = (glac_bin_area_annual * glac_bin_icethickness_annual / 1000).sum(axis=0) glac_wide_ELA_annual = (glac_bin_massbalclim_annual > 0).argmax(axis=0) - glac_wide_ELA_annual[glac_wide_ELA_annual > 0] = (elev_bins[glac_wide_ELA_annual[glac_wide_ELA_annual > 0]] - + glac_wide_ELA_annual[glac_wide_ELA_annual > 0] = (elev_bins[glac_wide_ELA_annual[glac_wide_ELA_annual > 0]] - input.binsize/2) # ELA and snowline can't be below minimum elevation glac_zmin_annual = elev_bins[(glac_bin_area_annual > 0).argmax(axis=0)][:-1] - input.binsize/2 @@ -467,46 +464,46 @@ def convert_glacwide_results(elev_bins, glac_bin_temp, glac_bin_prec, glac_bin_a glac_zmin_annual[glac_wide_ELA_annual < glac_zmin_annual]) glac_zmin = elev_bins[(glac_bin_area > 0).argmax(axis=0)] - input.binsize/2 glac_wide_snowline[glac_wide_snowline < glac_zmin] = glac_zmin[glac_wide_snowline < glac_zmin] - + # print('DELETE ME - TESTING') # # Compute glacier volume change for every time step and use this to compute mass balance # # this will work for any indexing # glac_wide_area = glac_wide_area_annual[:-1].repeat(12) -# +# ## print('glac_wide_area_annual:', glac_wide_area_annual) -# +# # # Mass change [km3 mwe] # # mb [mwea] * (1 km / 1000 m) * area [km2] # glac_wide_masschange = glac_wide_massbaltotal / 1000 * glac_wide_area -# +# # print('glac_wide_melt:', glac_wide_melt) ## print('glac_wide_massbaltotal:', glac_wide_massbaltotal) ## print('glac_wide_masschange:', glac_wide_masschange) ## print('glac_wide_masschange.shape[0] / 12:', glac_wide_masschange.shape[0] / 12) -# +# # # Mean annual mass balance [mwea] -# mb_mwea = (glac_wide_masschange.sum() / glac_wide_area[0] * 1000 / +# mb_mwea = (glac_wide_masschange.sum() / glac_wide_area[0] * 1000 / # (glac_wide_masschange.shape[0] / 12)) # print(' mb_model [mwea]:', mb_mwea.round(3)) - - return (glac_wide_temp, glac_wide_prec, glac_wide_acc, glac_wide_refreeze, glac_wide_melt, - glac_wide_frontalablation, glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, + + return (glac_wide_temp, glac_wide_prec, glac_wide_acc, glac_wide_refreeze, glac_wide_melt, + glac_wide_frontalablation, glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual) def main(list_packed_vars): """ Model simulation - + Parameters ---------- list_packed_vars : list list of packed variables that enable the use of parallels - + Returns ------- netcdf files of the simulation output (specific output is dependent on the output option) - """ + """ # Unpack variables count = list_packed_vars[0] glac_no = list_packed_vars[1] @@ -515,60 +512,46 @@ def main(list_packed_vars): parser = getparser() args = parser.parse_args() - + if (gcm_name != input.ref_gcm_name) and (args.rcp is None): rcp_scenario = os.path.basename(args.gcm_list_fn).split('_')[1] elif args.rcp is not None: rcp_scenario = args.rcp + else: + rcp_scenario = '' if debug: if 'rcp_scenario' in locals(): print(rcp_scenario) - - if args.debug_spc == 1: - debug_spc = True - else: - debug_spc = False - + # ===== LOAD GLACIER DATA ===== +# main_glac_rgi = main_glac_rgi_all.iloc[chunk:chunk + chunk_size, :].copy() main_glac_rgi = modelsetup.selectglaciersrgitable(glac_no=glac_no) # Glacier hypsometry [km**2], total area - main_glac_hyps = modelsetup.import_Husstable(main_glac_rgi, input.hyps_filepath, input.hyps_filedict, + main_glac_hyps = modelsetup.import_Husstable(main_glac_rgi, input.hyps_filepath, input.hyps_filedict, input.hyps_colsdrop) # Ice thickness [m], average main_glac_icethickness = modelsetup.import_Husstable(main_glac_rgi, input.thickness_filepath, input.thickness_filedict, input.thickness_colsdrop) - main_glac_icethickness[main_glac_icethickness < 0] = 0 main_glac_hyps[main_glac_icethickness == 0] = 0 # Width [km], average - main_glac_width = modelsetup.import_Husstable(main_glac_rgi, input.width_filepath, input.width_filedict, + main_glac_width = modelsetup.import_Husstable(main_glac_rgi, input.width_filepath, input.width_filedict, input.width_colsdrop) elev_bins = main_glac_hyps.columns.values.astype(int) # Volume [km**3] and mean elevation [m a.s.l.] main_glac_rgi['Volume'], main_glac_rgi['Zmean'] = modelsetup.hypsometrystats(main_glac_hyps, main_glac_icethickness) - if input.option_surfacetype_debris == 1: - main_glac_debrisfactor = modelsetup.import_Husstable(main_glac_rgi, input.debris_fp, input.debris_filedict, - input.debris_colsdrop) - else: - print('\n\nDELETE ME - CHECK THAT THIS IS SAME FORMAT AS MAIN_GLAC_HYPS AND OTHERS\n\n') - main_glac_debrisfactor = np.zeros(main_glac_hyps.shape) + 1 - main_glac_debrisfactor[main_glac_hyps == 0] = 0 - -# print(main_glac_hyps.index.values) - # Select dates including future projections - dates_table = modelsetup.datesmodelrun(startyear=input.gcm_startyear, endyear=input.gcm_endyear, + dates_table = modelsetup.datesmodelrun(startyear=input.gcm_startyear, endyear=input.gcm_endyear, spinupyears=input.gcm_spinupyears, option_wateryear=input.gcm_wateryear) - - + # ================= if debug: # Select dates including future projections # - nospinup dates_table needed to get the proper time indices - dates_table_nospinup = modelsetup.datesmodelrun(startyear=input.gcm_startyear, endyear=input.gcm_endyear, + dates_table_nospinup = modelsetup.datesmodelrun(startyear=input.gcm_startyear, endyear=input.gcm_endyear, spinupyears=0, option_wateryear=input.gcm_wateryear) - + # ===== LOAD CALIBRATION DATA ===== cal_data = pd.DataFrame() for dataset in input.cal_datasets: @@ -578,14 +561,14 @@ def main(list_packed_vars): cal_data = cal_data.sort_values(['glacno', 't1_idx']) cal_data.reset_index(drop=True, inplace=True) # ================= - - + + # Synthetic simulation dates if input.option_synthetic_sim == 1: dates_table_synthetic = modelsetup.datesmodelrun( - startyear=input.synthetic_startyear, endyear=input.synthetic_endyear, + startyear=input.synthetic_startyear, endyear=input.synthetic_endyear, option_wateryear=input.gcm_wateryear, spinupyears=0) - + # ===== LOAD CLIMATE DATA ===== if gcm_name in ['ERA5', 'ERA-Interim', 'COAWST']: gcm = class_climate.GCM(name=gcm_name) @@ -606,90 +589,90 @@ def main(list_packed_vars): ref_endyear = input.endyear else: ref_endyear = input.gcm_endyear - dates_table_ref = modelsetup.datesmodelrun(startyear=ref_startyear, endyear=ref_endyear, - spinupyears=input.spinupyears, + dates_table_ref = modelsetup.datesmodelrun(startyear=ref_startyear, endyear=ref_endyear, + spinupyears=input.spinupyears, option_wateryear=input.option_wateryear) -# if debug: -# print(ref_startyear, ref_endyear) - + if debug: + print(ref_startyear, ref_endyear) + # ===== Regular Climate Data (not synthetic simulation) ===== - if input.option_synthetic_sim == 0: + if input.option_synthetic_sim == 0: # Air temperature [degC] - gcm_temp, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn, gcm.temp_vn, main_glac_rgi, + gcm_temp, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn, gcm.temp_vn, main_glac_rgi, dates_table) if input.option_ablation != 2: gcm_tempstd = np.zeros(gcm_temp.shape) elif input.option_ablation == 2 and gcm_name in ['ERA5']: - gcm_tempstd, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.tempstd_fn, gcm.tempstd_vn, + gcm_tempstd, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.tempstd_fn, gcm.tempstd_vn, main_glac_rgi, dates_table) elif input.option_ablation == 2 and input.ref_gcm_name in ['ERA5']: # Compute temp std based on reference climate data - ref_tempstd, ref_dates = ref_gcm.importGCMvarnearestneighbor_xarray(ref_gcm.tempstd_fn, ref_gcm.tempstd_vn, + ref_tempstd, ref_dates = ref_gcm.importGCMvarnearestneighbor_xarray(ref_gcm.tempstd_fn, ref_gcm.tempstd_vn, main_glac_rgi, dates_table_ref) # Monthly average from reference climate data gcm_tempstd = gcmbiasadj.monthly_avg_array_rolled(ref_tempstd, dates_table_ref, dates_table) else: gcm_tempstd = np.zeros(gcm_temp.shape) - + # Precipitation [m] - gcm_prec, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn, gcm.prec_vn, main_glac_rgi, + gcm_prec, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn, gcm.prec_vn, main_glac_rgi, dates_table) # Elevation [m asl] - gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn, main_glac_rgi) + gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn, main_glac_rgi) # Lapse rate if gcm_name in ['ERA-Interim', 'ERA5']: gcm_lr, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.lr_fn, gcm.lr_vn, main_glac_rgi, dates_table) else: # Compute lapse rates based on reference climate data - ref_lr, ref_dates = ref_gcm.importGCMvarnearestneighbor_xarray(ref_gcm.lr_fn, ref_gcm.lr_vn, main_glac_rgi, + ref_lr, ref_dates = ref_gcm.importGCMvarnearestneighbor_xarray(ref_gcm.lr_fn, ref_gcm.lr_vn, main_glac_rgi, dates_table_ref) # Monthly average from reference climate data gcm_lr = gcmbiasadj.monthly_avg_array_rolled(ref_lr, dates_table_ref, dates_table) - + # COAWST data has two domains, so need to merge the two domains if gcm_name == 'COAWST': gcm_temp_d01, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn_d01, gcm.temp_vn, main_glac_rgi, dates_table) - gcm_prec_d01, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn_d01, gcm.prec_vn, + gcm_prec_d01, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn_d01, gcm.prec_vn, main_glac_rgi, dates_table) gcm_elev_d01 = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn_d01, gcm.elev_vn, main_glac_rgi) # Check if glacier outside of high-res (d02) domain for glac in range(main_glac_rgi.shape[0]): glac_lat = main_glac_rgi.loc[glac,input.rgi_lat_colname] glac_lon = main_glac_rgi.loc[glac,input.rgi_lon_colname] - if (~(input.coawst_d02_lat_min <= glac_lat <= input.coawst_d02_lat_max) or + if (~(input.coawst_d02_lat_min <= glac_lat <= input.coawst_d02_lat_max) or ~(input.coawst_d02_lon_min <= glac_lon <= input.coawst_d02_lon_max)): gcm_prec[glac,:] = gcm_prec_d01[glac,:] gcm_temp[glac,:] = gcm_temp_d01[glac,:] gcm_elev[glac] = gcm_elev_d01[glac] - + # ===== Synthetic Simulation ===== elif input.option_synthetic_sim == 1: # Air temperature [degC] - gcm_temp_tile, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn, gcm.temp_vn, main_glac_rgi, + gcm_temp_tile, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn, gcm.temp_vn, main_glac_rgi, dates_table_synthetic) # Precipitation [m] - gcm_prec_tile, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn, gcm.prec_vn, main_glac_rgi, + gcm_prec_tile, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn, gcm.prec_vn, main_glac_rgi, dates_table_synthetic) # Elevation [m asl] - gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn, main_glac_rgi) + gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn, main_glac_rgi) # Lapse rate - gcm_lr_tile, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.lr_fn, gcm.lr_vn, main_glac_rgi, + gcm_lr_tile, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.lr_fn, gcm.lr_vn, main_glac_rgi, dates_table_synthetic) - # Future simulation based on synthetic (replicated) data; add spinup years; dataset restarts after spinupyears + # Future simulation based on synthetic (replicated) data; add spinup years; dataset restarts after spinupyears datelength = dates_table.shape[0] - input.gcm_spinupyears * 12 n_tiles = int(np.ceil(datelength / dates_table_synthetic.shape[0])) - gcm_temp = np.append(gcm_temp_tile[:,:input.gcm_spinupyears*12], + gcm_temp = np.append(gcm_temp_tile[:,:input.gcm_spinupyears*12], np.tile(gcm_temp_tile,(1,n_tiles))[:,:datelength], axis=1) - gcm_prec = np.append(gcm_prec_tile[:,:input.gcm_spinupyears*12], + gcm_prec = np.append(gcm_prec_tile[:,:input.gcm_spinupyears*12], np.tile(gcm_prec_tile,(1,n_tiles))[:,:datelength], axis=1) - gcm_lr = np.append(gcm_lr_tile[:,:input.gcm_spinupyears*12], np.tile(gcm_lr_tile,(1,n_tiles))[:,:datelength], + gcm_lr = np.append(gcm_lr_tile[:,:input.gcm_spinupyears*12], np.tile(gcm_lr_tile,(1,n_tiles))[:,:datelength], axis=1) # Temperature and precipitation sensitivity adjustments gcm_temp = gcm_temp + input.synthetic_temp_adjust gcm_prec = gcm_prec * input.synthetic_prec_factor - - + + # ===== BIAS CORRECTIONS ===== # No adjustments if input.option_bias_adjustment == 0 or gcm_name == input.ref_gcm_name: @@ -699,30 +682,30 @@ def main(list_packed_vars): # Bias correct based on reference climate data else: # Air temperature [degC], Precipitation [m], Elevation [masl], Lapse rate [K m-1] - ref_temp, ref_dates = ref_gcm.importGCMvarnearestneighbor_xarray(ref_gcm.temp_fn, ref_gcm.temp_vn, + ref_temp, ref_dates = ref_gcm.importGCMvarnearestneighbor_xarray(ref_gcm.temp_fn, ref_gcm.temp_vn, main_glac_rgi, dates_table_ref) - ref_prec, ref_dates = ref_gcm.importGCMvarnearestneighbor_xarray(ref_gcm.prec_fn, ref_gcm.prec_vn, + ref_prec, ref_dates = ref_gcm.importGCMvarnearestneighbor_xarray(ref_gcm.prec_fn, ref_gcm.prec_vn, main_glac_rgi, dates_table_ref) ref_elev = ref_gcm.importGCMfxnearestneighbor_xarray(ref_gcm.elev_fn, ref_gcm.elev_vn, main_glac_rgi) - + # OPTION 1: Adjust temp using Huss and Hock (2015), prec similar but addresses for variance and outliers if input.option_bias_adjustment == 1: # Temperature bias correction - gcm_temp_adj, gcm_elev_adj = gcmbiasadj.temp_biasadj_HH2015(ref_temp, ref_elev, gcm_temp, + gcm_temp_adj, gcm_elev_adj = gcmbiasadj.temp_biasadj_HH2015(ref_temp, ref_elev, gcm_temp, dates_table_ref, dates_table) # Precipitation bias correction - gcm_prec_adj, gcm_elev_adj = gcmbiasadj.prec_biasadj_opt1(ref_prec, ref_elev, gcm_prec, + gcm_prec_adj, gcm_elev_adj = gcmbiasadj.prec_biasadj_opt1(ref_prec, ref_elev, gcm_prec, dates_table_ref, dates_table) - + # OPTION 2: Adjust temp and prec using Huss and Hock (2015) elif input.option_bias_adjustment == 2: # Temperature bias correction - gcm_temp_adj, gcm_elev_adj = gcmbiasadj.temp_biasadj_HH2015(ref_temp, ref_elev, gcm_temp, + gcm_temp_adj, gcm_elev_adj = gcmbiasadj.temp_biasadj_HH2015(ref_temp, ref_elev, gcm_temp, dates_table_ref, dates_table) # Precipitation bias correction - gcm_prec_adj, gcm_elev_adj = gcmbiasadj.prec_biasadj_HH2015(ref_prec, ref_elev, gcm_prec, + gcm_prec_adj, gcm_elev_adj = gcmbiasadj.prec_biasadj_HH2015(ref_prec, ref_elev, gcm_prec, dates_table_ref, dates_table) - + # Checks on precipitation data if gcm_prec_adj.max() > 10: print('precipitation bias too high, needs to be modified') @@ -730,18 +713,7 @@ def main(list_packed_vars): elif gcm_prec_adj.min() < 0: print('Negative precipitation value') print(np.where(gcm_prec_adj < 0)) - - if debug_spc: - debug_fp = input.output_sim_fp + 'debug/' - # Create filepath if it does not exist - if os.path.exists(debug_fp) == False: - os.makedirs(debug_fp) - debug_df = pd.DataFrame(np.zeros((1,1)), columns=['count']) - debug_df.iloc[0,0] = count - debug_fn_loaded = ('biasadj_loaded_batch' + '_' + gcm_name + '_' + rcp_scenario + '_' + - str(args.batch_number) + '--' + str(count) + '.csv') - debug_df.to_csv(debug_fp + debug_fn_loaded) - + # ===== RUN MASS BALANCE ===== # Number of simulations if input.option_calibration == 2: @@ -749,12 +721,59 @@ def main(list_packed_vars): else: sim_iters = 1 # # Create datasets to store simulations -# output_ds_all, encoding = create_xrdataset(main_glac_rgi, dates_table, sim_iters=sim_iters, +# output_ds_all, encoding = create_xrdataset(main_glac_rgi, dates_table, sim_iters=sim_iters, # option_wateryear=input.gcm_wateryear) -# output_ds_all_stats, encoding = create_xrdataset(main_glac_rgi, dates_table, record_stats=1, +# output_ds_all_stats, encoding = create_xrdataset(main_glac_rgi, dates_table, record_stats=1, # option_wateryear=input.gcm_wateryear) - + +# def write_netcdf_output(output_fullfn, modelparameters, mb_mwea, observed_massbal): +# """ +# Export glacier model parameters and modeled observations to netcdf file. +# +# Parameters +# ---------- +# output_fullfn : str +# Full filename (path included) of the netcdf to be exported +# modelparams : list +# model parameters +# mb_mwea : float +# modeled mass balance for given parameters +# +# Returns +# ------- +# None +# Exports file to netcdf +# """ +# # Select data from model to be stored in netcdf +# df = pd.DataFrame(index=[0]) +# df['lrgcm'] = np.full(df.shape[0], input.lrgcm) +# df['lrglac'] = np.full(df.shape[0], input.lrglac) +# df['precfactor'] = modelparameters[2] +# df['precgrad'] = np.full(df.shape[0], input.precgrad) +# df['ddfsnow'] = modelparameters[4] +# df['ddfice'] = df['ddfsnow'] / ddfsnow_iceratio +# df['tempsnow'] = np.full(df.shape[0], input.tempsnow) +# df['tempchange'] = modelparameters[7] +# df['mb_mwea'] = mb_mwea +# df['obs_mwea'] = observed_massbal +# df['dif_mwea'] = mb_mwea - observed_massbal +# df_export = df.values[:, :, np.newaxis] +# # Set up dataset and export to netcdf +# ds = xr.Dataset({'mp_value': (('iter', 'mp', 'chain'), df_export)}, +# coords={'iter': df.index.values, +# 'mp': df.columns.values, +# 'chain': [0]}) +# ds.to_netcdf(output_fullfn) +# ds.close() + + annual_columns = np.unique(dates_table['wateryear'].values)[0:int(dates_table.shape[0]/12)] + time_values = dates_table.loc[input.spinupyears*12:dates_table.shape[0]+1,'date'].tolist() + year_values = annual_columns[input.spinupyears:annual_columns.shape[0]] + year_plus1_values = np.concatenate((annual_columns[input.spinupyears:annual_columns.shape[0]], + np.array([annual_columns[annual_columns.shape[0]-1]+1]))) + for glac in range(main_glac_rgi.shape[0]): + if glac == 0 or glac == main_glac_rgi.shape[0]: print(gcm_name,':', main_glac_rgi.loc[main_glac_rgi.index.values[glac],'RGIId']) # Select subsets of data @@ -765,23 +784,12 @@ def main(list_packed_vars): glacier_gcm_tempstd = gcm_tempstd[glac,:] glacier_gcm_lrgcm = gcm_lr[glac,:] glacier_gcm_lrglac = glacier_gcm_lrgcm.copy() - glacier_area_initial = main_glac_hyps.iloc[glac,:].values.astype(float) - icethickness_initial = main_glac_icethickness.iloc[glac,:].values.astype(float) - width_initial = main_glac_width.iloc[glac,:].values.astype(float) - glacier_debrisfactor = main_glac_debrisfactor.iloc[glac,:].values.astype(float) + glacier_area_t0 = main_glac_hyps.iloc[glac,:].values.astype(float) + icethickness_t0 = main_glac_icethickness.iloc[glac,:].values.astype(float) + width_t0 = main_glac_width.iloc[glac,:].values.astype(float) glacier_str = '{0:0.5f}'.format(glacier_rgi_table['RGIId_float']) - - print('DELETE ME!', glacier_debrisfactor[470:480]) - - if debug_spc: - debug_rgiid_fn = glacier_str + '_' + gcm_name + '_' + rcp_scenario + '.csv' - debug_df.to_csv(debug_fp + debug_rgiid_fn) - # Empty datasets to record output - annual_columns = np.unique(dates_table['wateryear'].values)[0:int(dates_table.shape[0]/12)] - year_values = annual_columns[input.spinupyears:annual_columns.shape[0]] - year_plus1_values = np.concatenate((annual_columns[input.spinupyears:annual_columns.shape[0]], - np.array([annual_columns[annual_columns.shape[0]-1]+1]))) + # TESTING: Record output to xarray dataset output_temp_glac_monthly = np.zeros((dates_table.shape[0], sim_iters)) output_prec_glac_monthly = np.zeros((dates_table.shape[0], sim_iters)) output_acc_glac_monthly = np.zeros((dates_table.shape[0], sim_iters)) @@ -791,41 +799,43 @@ def main(list_packed_vars): output_massbaltotal_glac_monthly = np.zeros((dates_table.shape[0], sim_iters)) output_runoff_glac_monthly = np.zeros((dates_table.shape[0], sim_iters)) output_snowline_glac_monthly = np.zeros((dates_table.shape[0], sim_iters)) + output_area_glac_annual = np.zeros((year_plus1_values.shape[0], sim_iters)) output_volume_glac_annual = np.zeros((year_plus1_values.shape[0], sim_iters)) output_ELA_glac_annual = np.zeros((year_values.shape[0], sim_iters)) + output_offglac_prec_monthly = np.zeros((dates_table.shape[0], sim_iters)) output_offglac_refreeze_monthly = np.zeros((dates_table.shape[0], sim_iters)) output_offglac_melt_monthly = np.zeros((dates_table.shape[0], sim_iters)) output_offglac_snowpack_monthly = np.zeros((dates_table.shape[0], sim_iters)) output_offglac_runoff_monthly = np.zeros((dates_table.shape[0], sim_iters)) - - if icethickness_initial.max() > 0: - + + if icethickness_t0.max() > 0: + if input.hindcast == 1: glacier_gcm_prec = glacier_gcm_prec[::-1] glacier_gcm_temp = glacier_gcm_temp[::-1] glacier_gcm_lrgcm = glacier_gcm_lrgcm[::-1] glacier_gcm_lrglac = glacier_gcm_lrglac[::-1] - + # get glacier number if glacier_rgi_table.O1Region >= 10: glacier_RGIId = main_glac_rgi.iloc[glac]['RGIId'][6:] else: glacier_RGIId = main_glac_rgi.iloc[glac]['RGIId'][7:] - + if input.option_import_modelparams == 1: ds_mp = xr.open_dataset(input.modelparams_fp + glacier_RGIId + '.nc') cn_subset = input.modelparams_colnames - modelparameters_all = (pd.DataFrame(ds_mp['mp_value'].sel(chain=0).values, + modelparameters_all = (pd.DataFrame(ds_mp['mp_value'].sel(chain=0).values, columns=ds_mp.mp.values)[cn_subset]) else: modelparameters_all = ( - pd.DataFrame(np.asarray([input.lrgcm, input.lrglac, input.precfactor, input.precgrad, + pd.DataFrame(np.asarray([input.lrgcm, input.lrglac, input.precfactor, input.precgrad, input.ddfsnow, input.ddfice, input.tempsnow, input.tempchange]) .reshape(1,-1), columns=input.modelparams_colnames)) - + # Set the number of iterations and determine every kth iteration to use for the ensemble if input.option_calibration == 2 and modelparameters_all.shape[0] > 1: sim_iters = input.sim_iters @@ -837,35 +847,38 @@ def main(list_packed_vars): mp_idx_all = np.arange(mp_idx_start, modelparameters_all.shape[0], mp_spacing) else: sim_iters = 1 - + # Loop through model parameters for n_iter in range(sim_iters): - + if sim_iters == 1: - modelparameters = modelparameters_all.mean() + modelparameters = modelparameters_all.mean() else: mp_idx = mp_idx_all[n_iter] modelparameters = modelparameters_all.iloc[mp_idx,:] - + if debug: - print(glacier_RGIId, ('PF: ' + str(np.round(modelparameters[2],2)) + ' ddfsnow: ' + + print(glacier_RGIId, ('PF: ' + str(np.round(modelparameters[2],2)) + ' ddfsnow: ' + str(np.round(modelparameters[4],4)) + ' tbias: ' + str(np.round(modelparameters[7],2)))) - + debug_mb = True + else: + debug_mb = False + # run mass balance calculation (glac_bin_temp, glac_bin_prec, glac_bin_acc, glac_bin_refreeze, glac_bin_snowpack, glac_bin_melt, glac_bin_frontalablation, glac_bin_massbalclim, glac_bin_massbalclim_annual, glac_bin_area_annual, glac_bin_icethickness_annual, glac_bin_width_annual, glac_bin_surfacetype_annual, glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack, - glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, + glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = ( - massbalance.runmassbalance(modelparameters[0:8], glacier_rgi_table, glacier_area_initial, - icethickness_initial, width_initial, elev_bins, glacier_gcm_temp, - glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, - glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, + massbalance.runmassbalance(modelparameters[0:8], glacier_rgi_table, glacier_area_t0, + icethickness_t0, width_t0, elev_bins, glacier_gcm_temp, + glacier_gcm_tempstd, glacier_gcm_prec, glacier_gcm_elev, + glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, option_areaconstant=0, debug=input.debug_mb, debug_refreeze=input.debug_refreeze)) - - if input.hindcast == 1: + + if input.hindcast == 1: glac_bin_temp = glac_bin_temp[:,::-1] glac_bin_prec = glac_bin_prec[:,::-1] glac_bin_acc = glac_bin_acc[:,::-1] @@ -891,18 +904,18 @@ def main(list_packed_vars): offglac_wide_melt = offglac_wide_melt[::-1] offglac_wide_snowpack = offglac_wide_snowpack[::-1] offglac_wide_runoff = offglac_wide_runoff[::-1] - - - # RECORD PARAMETERS TO DATASET + + + # RECORD PARAMETERS TO DATASET if input.output_package == 2: - (glac_wide_temp, glac_wide_prec, glac_wide_acc, glac_wide_refreeze, glac_wide_melt, - glac_wide_frontalablation, glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, + (glac_wide_temp, glac_wide_prec, glac_wide_acc, glac_wide_refreeze, glac_wide_melt, + glac_wide_frontalablation, glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual) = ( - convert_glacwide_results(elev_bins, glac_bin_temp, glac_bin_prec, glac_bin_acc, - glac_bin_refreeze, glac_bin_snowpack, glac_bin_melt, - glac_bin_frontalablation, glac_bin_massbalclim_annual, + convert_glacwide_results(elev_bins, glac_bin_temp, glac_bin_prec, glac_bin_acc, + glac_bin_refreeze, glac_bin_snowpack, glac_bin_melt, + glac_bin_frontalablation, glac_bin_massbalclim_annual, glac_bin_area_annual, glac_bin_icethickness_annual)) - + if debug: # Compute glacier volume change for every time step and use this to compute mass balance # this will work for any indexing @@ -911,13 +924,10 @@ def main(list_packed_vars): # mb [mwea] * (1 km / 1000 m) * area [km2] glac_wide_masschange = glac_wide_massbaltotal / 1000 * glac_wide_area # Mean annual mass balance [mwea] - # note: used annual shape - 1 because area and volume have "n+1 years" t0 account for initial - # and final - mb_mwea = (glac_wide_masschange.sum() / glac_wide_area[0] * 1000 / - (glac_wide_area_annual.shape[0]-1)) + mb_mwea = (glac_wide_masschange.sum() / glac_wide_area[0] * 1000 / + (glac_wide_masschange.shape[0] / 12)) print(' mb_model [mwea]:', mb_mwea.round(3)) - - # Record output to xarray dataset + output_temp_glac_monthly[:, n_iter] = glac_wide_temp output_prec_glac_monthly[:, n_iter] = glac_wide_prec output_acc_glac_monthly[:, n_iter] = glac_wide_acc @@ -935,80 +945,176 @@ def main(list_packed_vars): output_offglac_melt_monthly[:, n_iter] = offglac_wide_melt output_offglac_snowpack_monthly[:, n_iter] = offglac_wide_snowpack output_offglac_runoff_monthly[:, n_iter] = offglac_wide_runoff - - if debug: - print(' years:', glac_wide_volume_annual.shape[0]-1) - print(' vol start/end:', np.round(glac_wide_volume_annual[0],2), '/', - np.round(glac_wide_volume_annual[-1],2)) - print(' area start/end:', np.round(glac_wide_area_annual[0],2), '/', - np.round(glac_wide_area_annual[-1],2)) - print(' volume:', glac_wide_volume_annual) - # print('glac runoff max:', np.round(glac_wide_runoff.max(),0), + + # if debug: + # print('glac runoff max:', np.round(glac_wide_runoff.max(),0), # 'glac prec max:', np.round(glac_wide_prec.max(),2), # 'glac refr max:', np.round(glac_wide_refreeze.max(),2), # 'offglac ref max:', np.round(offglac_wide_refreeze.max(),2)) - - # ===== Export Results ===== + + + def calc_stats_array(data, stats_cns=input.sim_stat_cns): + """ + Calculate stats for a given variable + + Parameters + ---------- + vn : str + variable name + ds : xarray dataset + dataset of output with all ensemble simulations + + Returns + ------- + stats : np.array + Statistics related to a given variable + """ + if 'mean' in stats_cns: + stats = data.mean(axis=1)[:,np.newaxis] + if 'std' in stats_cns: + stats = np.append(stats, data.std(axis=1)[:,np.newaxis], axis=1) + if '2.5%' in stats_cns: + stats = np.append(stats, np.percentile(data, 2.5, axis=1)[:,np.newaxis], axis=1) + if '25%' in stats_cns: + stats = np.append(stats, np.percentile(data, 25, axis=1)[:,np.newaxis], axis=1) + if 'median' in stats_cns: + stats = np.append(stats, np.median(data, axis=1)[:,np.newaxis], axis=1) + if '75%' in stats_cns: + stats = np.append(stats, np.percentile(data, 75, axis=1)[:,np.newaxis], axis=1) + if '97.5%' in stats_cns: + stats = np.append(stats, np.percentile(data, 97.5, axis=1)[:,np.newaxis], axis=1) + return stats + + + + output_temp_glac_monthly_stats = calc_stats_array(output_temp_glac_monthly) + + output_prec_glac_monthly_stats = calc_stats_array(output_prec_glac_monthly) + output_acc_glac_monthly_stats = calc_stats_array(output_acc_glac_monthly) + output_refreeze_glac_monthly = calc_stats_array(output_refreeze_glac_monthly) + output_melt_glac_monthly = calc_stats_array(output_melt_glac_monthly) + output_frontalablation_glac_monthly = calc_stats_array(output_frontalablation_glac_monthly) + output_massbaltotal_glac_monthly = calc_stats_array(output_massbaltotal_glac_monthly) + output_runoff_glac_monthly = calc_stats_array(output_runoff_glac_monthly) + output_snowline_glac_monthly = calc_stats_array(output_snowline_glac_monthly) + output_area_glac_annual = calc_stats_array(output_area_glac_annual) + output_volume_glac_annual = calc_stats_array(output_volume_glac_annual) + output_ELA_glac_annual = calc_stats_array(output_ELA_glac_annual) + output_offglac_prec_monthly = calc_stats_array(output_offglac_prec_monthly) + output_offglac_refreeze_monthly = calc_stats_array(output_offglac_refreeze_monthly) + output_offglac_melt_monthly = calc_stats_array(output_offglac_melt_monthly) + output_offglac_snowpack_monthly = calc_stats_array(output_offglac_snowpack_monthly) + output_offglac_runoff_monthly = calc_stats_array(output_offglac_runoff_monthly) + rgi_table_ds = pd.DataFrame(np.zeros((1,glacier_rgi_table.shape[0])), columns=glacier_rgi_table.index) rgi_table_ds.iloc[0,:] = glacier_rgi_table.values - output_ds_all_stats, encoding = create_xrdataset(rgi_table_ds, dates_table, record_stats=1, + output_ds_all_stats, encoding = create_xrdataset(rgi_table_ds, dates_table, record_stats=1, option_wateryear=input.gcm_wateryear) - output_ds_all_stats['temp_glac_monthly'].values[0,:,:] = calc_stats_array(output_temp_glac_monthly) - output_ds_all_stats['prec_glac_monthly'].values[0,:,:] = calc_stats_array(output_prec_glac_monthly) - output_ds_all_stats['acc_glac_monthly'].values[0,:,:] = calc_stats_array(output_acc_glac_monthly) - output_ds_all_stats['refreeze_glac_monthly'].values[0,:,:] = calc_stats_array(output_refreeze_glac_monthly) - output_ds_all_stats['melt_glac_monthly'].values[0,:,:] = calc_stats_array(output_melt_glac_monthly) - output_ds_all_stats['frontalablation_glac_monthly'].values[0,:,:] = ( - calc_stats_array(output_frontalablation_glac_monthly)) - output_ds_all_stats['massbaltotal_glac_monthly'].values[0,:,:] = ( - calc_stats_array(output_massbaltotal_glac_monthly)) - output_ds_all_stats['runoff_glac_monthly'].values[0,:,:] = calc_stats_array(output_runoff_glac_monthly) - output_ds_all_stats['snowline_glac_monthly'].values[0,:,:] = calc_stats_array(output_snowline_glac_monthly) - output_ds_all_stats['area_glac_annual'].values[0,:,:] = calc_stats_array(output_area_glac_annual) - output_ds_all_stats['volume_glac_annual'].values[0,:,:] = calc_stats_array(output_volume_glac_annual) - output_ds_all_stats['ELA_glac_annual'].values[0,:,:] = calc_stats_array(output_ELA_glac_annual) - output_ds_all_stats['offglac_prec_monthly'].values[0,:,:] = calc_stats_array(output_offglac_prec_monthly) - output_ds_all_stats['offglac_melt_monthly'].values[0,:,:] = calc_stats_array(output_offglac_melt_monthly) - output_ds_all_stats['offglac_refreeze_monthly'].values[0,:,:] = ( - calc_stats_array(output_offglac_refreeze_monthly)) - output_ds_all_stats['offglac_snowpack_monthly'].values[0,:,:] = ( - calc_stats_array(output_offglac_snowpack_monthly)) - output_ds_all_stats['offglac_runoff_monthly'].values[0,:,:] = ( - calc_stats_array(output_offglac_runoff_monthly)) + output_ds_all_stats['prec_glac_monthly'].values[0,:,:] = output_prec_glac_monthly_stats + output_ds_all_stats['temp_glac_monthly'].values[0,:,:] = output_temp_glac_monthly_stats + output_ds_all_stats['acc_glac_monthly'].values[0,:,:] = output_acc_glac_monthly_stats + output_ds_all_stats['refreeze_glac_monthly'].values[0,:,:] = output_refreeze_glac_monthly + output_ds_all_stats['melt_glac_monthly'].values[0,:,:] = output_melt_glac_monthly + output_ds_all_stats['frontalablation_glac_monthly'].values[0,:,:] = output_frontalablation_glac_monthly + output_ds_all_stats['massbaltotal_glac_monthly'].values[0,:,:] = output_massbaltotal_glac_monthly + output_ds_all_stats['runoff_glac_monthly'].values[0,:,:] = output_runoff_glac_monthly + output_ds_all_stats['snowline_glac_monthly'].values[0,:,:] = output_snowline_glac_monthly + output_ds_all_stats['area_glac_annual'].values[0,:,:] = output_area_glac_annual + output_ds_all_stats['volume_glac_annual'].values[0,:,:] = output_volume_glac_annual + output_ds_all_stats['ELA_glac_annual'].values[0,:,:] = output_ELA_glac_annual + output_ds_all_stats['offglac_prec_monthly'].values[0,:,:] = output_offglac_prec_monthly + output_ds_all_stats['offglac_refreeze_monthly'].values[0,:,:] = output_offglac_refreeze_monthly + output_ds_all_stats['offglac_snowpack_monthly'].values[0,:,:] = output_offglac_snowpack_monthly + output_ds_all_stats['offglac_runoff_monthly'].values[0,:,:] = output_offglac_runoff_monthly + # Export statistics to netcdf if input.output_package == 2: output_sim_fp = input.output_sim_fp + gcm_name + '/' - if gcm_name not in ['ERA-Interim', 'ERA5', 'COAWST']: - output_sim_fp += rcp_scenario + '/' # Create filepath if it does not exist if os.path.exists(output_sim_fp) == False: os.makedirs(output_sim_fp) # Netcdf filename if gcm_name in ['ERA-Interim', 'ERA5', 'COAWST']: # Filename - netcdf_fn = (glacier_str + '_' + gcm_name + '_c' + str(input.option_calibration) + '_ba' + - str(input.option_bias_adjustment) + '_' + str(sim_iters) + 'sets' + '_' + + netcdf_fn = (glacier_str + '_' + gcm_name + '_c' + str(input.option_calibration) + '_ba' + + str(input.option_bias_adjustment) + '_' + str(sim_iters) + 'sets' + '_' + str(input.gcm_startyear) + '_' + str(input.gcm_endyear) + '.nc') else: - netcdf_fn = (glacier_str + '_' + gcm_name + '_' + rcp_scenario + '_c' + - str(input.option_calibration) + '_ba' + str(input.option_bias_adjustment) + '_' + + netcdf_fn = (glacier_str + '_' + gcm_name + '_' + rcp_scenario + '_c' + + str(input.option_calibration) + '_ba' + str(input.option_bias_adjustment) + '_' + str(sim_iters) + 'sets' + '_' + str(input.gcm_startyear) + '_' + str(input.gcm_endyear) + '.nc') if input.option_synthetic_sim==1: - netcdf_fn = (netcdf_fn.split('--')[0] + '_T' + str(input.synthetic_temp_adjust) + '_P' + + netcdf_fn = (netcdf_fn.split('--')[0] + '_T' + str(input.synthetic_temp_adjust) + '_P' + str(input.synthetic_prec_factor) + '--' + netcdf_fn.split('--')[1]) # Export netcdf output_ds_all_stats.to_netcdf(output_sim_fp + netcdf_fn, encoding=encoding) - + # Close datasets output_ds_all_stats.close() - - - if debug_spc: - os.remove(debug_fp + debug_rgiid_fn) - - # Global variables for Spyder development + + #%% + # testing +# ds = xr.open_dataset(input.main_directory + '/../Output/simulations/CCSM4/13.00001_CCSM4_rcp26_c2_ba1_100sets_2000_2100.nc') + + #%% + # Calculate statistics of simulations + # List of variables +# ds_vns = [] +# for vn in output_ds_all.variables: +# ds_vns.append(vn) +# for vn in ds_vns: +# if vn in input.output_variables_package2: +# stats = calc_stats(vn, output_ds_all, glac=glac) +# output_ds_all_stats[vn].values[glac,:,:] = stats + +# # EXPORT TO NETCDF +# netcdf_output_fp = (input.output_fp_cal) +# if not os.path.exists(netcdf_output_fp): +# os.makedirs(netcdf_output_fp) +# write_netcdf_output(netcdf_output_fp + glacier_str + '.nc', modelparameters, mb_mwea, observed_massbal) + + # if debug: + # mb_mwea_all = ((output_ds_all_stats.massbaltotal_glac_monthly.values[glac,:,0]).sum(axis=0) / + # (dates_table.shape[0] / 12)) + # print('mb_model [mwea] mean:', round(mb_mwea_all,4)) + # # Calibration + # cal_idx = np.where(cal_data.glacno == main_glac_rgi.glacno)[0][0] + # mb_cal_mwea = cal_data.loc[cal_idx,'mb_mwe'] / (cal_data.loc[cal_idx,'t2'] - cal_data.loc[cal_idx,'t1']) + # print('mb_cal [mwea]:', round(mb_cal_mwea,4)) + +# # Export statistics to netcdf +# if input.output_package == 2: +# output_sim_fp = input.output_sim_fp + gcm_name + '/' +# # Create filepath if it does not exist +# if os.path.exists(output_sim_fp) == False: +# os.makedirs(output_sim_fp) +# # Netcdf filename +# if gcm_name in ['ERA-Interim', 'ERA5', 'COAWST']: +# # Filename +# netcdf_fn = (regions_str + '_' + gcm_name + '_c' + str(input.option_calibration) + '_ba' + +# str(input.option_bias_adjustment) + '_' + str(sim_iters) + 'sets' + '_' + +# str(input.gcm_startyear) + '_' + str(input.gcm_endyear) + '--' + str(count) + '.nc') +# else: +# netcdf_fn = (regions_str + '_' + gcm_name + '_' + rcp_scenario + '_c' + +# str(input.option_calibration) + '_ba' + str(input.option_bias_adjustment) + '_' + +# str(sim_iters) + 'sets' + '_' + str(input.gcm_startyear) + '_' + str(input.gcm_endyear) + +# '--' + str(count) + '.nc') +# if input.option_synthetic_sim==1: +# netcdf_fn = (netcdf_fn.split('--')[0] + '_T' + str(input.synthetic_temp_adjust) + '_P' + +# str(input.synthetic_prec_factor) + '--' + netcdf_fn.split('--')[1]) +# if args.batch_number is not None: +# netcdf_fn_split = netcdf_fn.split('--') +# netcdf_fn = netcdf_fn_split[0] + '_batch' + str(args.batch_number) + '--' + netcdf_fn_split[1] +# # Export netcdf +# output_ds_all_stats.to_netcdf(output_sim_fp + netcdf_fn, encoding=encoding) +# +# # Close datasets +# output_ds_all_stats.close() +# output_ds_all.close() + + #%% Export variables as global to view in variable explorer if args.option_parallels == 0: global main_vars main_vars = inspect.currentframe().f_locals @@ -1018,7 +1124,7 @@ def main(list_packed_vars): time_start = time.time() parser = getparser() args = parser.parse_args() - + if args.debug == 1: debug = True else: @@ -1032,24 +1138,30 @@ def main(list_packed_vars): glac_no = input.glac_no else: main_glac_rgi_all = modelsetup.selectglaciersrgitable( - rgi_regionsO1=input.rgi_regionsO1, rgi_regionsO2 =input.rgi_regionsO2, + rgi_regionsO1=input.rgi_regionsO1, rgi_regionsO2 =input.rgi_regionsO2, rgi_glac_number=input.rgi_glac_number) glac_no = list(main_glac_rgi_all['rgino_str'].values) - + # Regions regions_str = 'R' for region in sorted(set([x.split('.')[0] for x in glac_no])): regions_str += str(region) - + # Number of cores for parallel processing if args.option_parallels != 0: num_cores = int(np.min([len(glac_no), args.num_simultaneous_processes])) else: num_cores = 1 - + # Glacier number lists to pass for parallel processing glac_no_lsts = split_glaciers.split_list(glac_no, n=num_cores, option_ordered=args.option_ordered) - + +# print('DELETE ME!') + BATMAN_fp = input.output_sim_fp + 'Batman/' +# # Create filepath if it does not exist +# if os.path.exists(BATMAN_fp) == False: +# os.makedirs(BATMAN_fp) + # Read GCM names from argument parser gcm_name = args.gcm_list_fn if args.gcm_name is not None: @@ -1094,17 +1206,17 @@ def main(list_packed_vars): # sim_iters = input.sim_iters # else: # sim_iters = 1 -# +# # if gcm_name in ['ERA-Interim', 'ERA5', 'COAWST']: -# check_str = (regions_str + '_' + gcm_name + '_c' + str(input.option_calibration) + '_ba' + -# str(input.option_bias_adjustment) + '_' + str(sim_iters) + 'sets' + '_' + +# check_str = (regions_str + '_' + gcm_name + '_c' + str(input.option_calibration) + '_ba' + +# str(input.option_bias_adjustment) + '_' + str(sim_iters) + 'sets' + '_' + # str(input.gcm_startyear) + '_' + str(input.gcm_endyear) + '--') # else: -# check_str = (regions_str + '_' + gcm_name + '_' + rcp_scenario + '_c' + str(input.option_calibration) + -# '_ba' + str(input.option_bias_adjustment) + '_' + str(sim_iters) + 'sets' + '_' + +# check_str = (regions_str + '_' + gcm_name + '_' + rcp_scenario + '_c' + str(input.option_calibration) + +# '_ba' + str(input.option_bias_adjustment) + '_' + str(sim_iters) + 'sets' + '_' + # str(input.gcm_startyear) + '_' + str(input.gcm_endyear) + '--') # if input.option_synthetic_sim==1: -# check_str = (check_str.split('--')[0] + '_T' + str(input.synthetic_temp_adjust) + '_P' + +# check_str = (check_str.split('--')[0] + '_T' + str(input.synthetic_temp_adjust) + '_P' + # str(input.synthetic_prec_factor) + '--') # if args.batch_number is not None: # check_str = check_str.split('--')[0] + '_batch' + str(args.batch_number) + '--' @@ -1117,9 +1229,9 @@ def main(list_packed_vars): # count_ds = 0 # for i in output_list: # count_ds += 1 -# +# # print(count_ds, 'output_list file:', i) -# +# # ds = xr.open_dataset(output_sim_fp + i) # # Merge datasets of stats into one output # if count_ds == 1: @@ -1129,7 +1241,7 @@ def main(list_packed_vars): # ds_all = xr.concat([ds_all, ds], 'glac') # # Close dataset (NOTE: closing dataset here causes error on supercomputer) ## ds.close() -# +# # # Filename # ds_all_fn = i.split('--')[0] + '.nc' # # Encoding @@ -1154,14 +1266,279 @@ def main(list_packed_vars): # os.remove(output_sim_fp + i) print('Total processing time:', time.time()-time_start, 's') - + # print('memory:', resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 10**6, 'GB') + +#%% TRYING TO USE THE CALIBRATION INPUT TO SEE IF THAT'S BETTER! +#if __name__ == '__main__': +# time_start = time.time() +# parser = getparser() +# args = parser.parse_args() +# +# if args.debug == 1: +# debug = True +# else: +# debug = False +# +# BATMAN_fp = input.output_sim_fp + 'Batman/' +# +# # RGI glacier number +# if args.rgi_glac_number_fn is not None: +# with open(args.rgi_glac_number_fn, 'rb') as f: +# glac_no = pickle.load(f) +# elif input.glac_no is not None: +# glac_no = input.glac_no +# else: +# main_glac_rgi_all = modelsetup.selectglaciersrgitable( +# rgi_regionsO1=input.rgi_regionsO1, rgi_regionsO2 =input.rgi_regionsO2, +# rgi_glac_number=input.rgi_glac_number) +# glac_no = list(main_glac_rgi_all['rgino_str'].values) +# +# # Regions +# regions_str = 'R' +# for region in sorted(set([x.split('.')[0] for x in glac_no])): +# regions_str += str(region) +# +# # Select all glaciers in a region +# main_glac_rgi_all = modelsetup.selectglaciersrgitable(glac_no=glac_no) +# # Add regions +# main_glac_rgi_all['region'] = main_glac_rgi_all.RGIId.map(input.reg_dict) +# +# # Define chunk size for parallel processing +# if args.option_parallels != 0: +# num_cores = int(np.min([main_glac_rgi_all.shape[0], args.num_simultaneous_processes])) +# chunk_size = int(np.ceil(main_glac_rgi_all.shape[0] / num_cores)) +# else: +# # if not running in parallel, chunk size is all glaciers +# chunk_size = main_glac_rgi_all.shape[0] +# +# # ===== LOAD GLACIER DATA ===== +# # Glacier hypsometry [km**2], total area +# main_glac_hyps_all = modelsetup.import_Husstable(main_glac_rgi_all, input.hyps_filepath, +# input.hyps_filedict, input.hyps_colsdrop) +# +# # Ice thickness [m], average +# main_glac_icethickness_all = modelsetup.import_Husstable(main_glac_rgi_all, input.thickness_filepath, +# input.thickness_filedict, input.thickness_colsdrop) +# main_glac_hyps_all[main_glac_icethickness_all == 0] = 0 +# # Width [km], average +# main_glac_width_all = modelsetup.import_Husstable(main_glac_rgi_all, input.width_filepath, +# input.width_filedict, input.width_colsdrop) +# elev_bins = main_glac_hyps_all.columns.values.astype(int) +# # Add volume [km**3] and mean elevation [m a.s.l.] +# main_glac_rgi_all['Volume'], main_glac_rgi_all['Zmean'] = ( +# modelsetup.hypsometrystats(main_glac_hyps_all, main_glac_icethickness_all)) +# # Select dates including future projections +# # - nospinup dates_table needed to get the proper time indices +# dates_table_nospinup = modelsetup.datesmodelrun(startyear=input.startyear, endyear=input.endyear, +# spinupyears=0) +# dates_table = modelsetup.datesmodelrun(startyear=input.startyear, endyear=input.endyear, +# spinupyears=input.spinupyears) +# +# # ===== LOAD CALIBRATION DATA ===== +# cal_data = pd.DataFrame() +# for dataset in input.cal_datasets: +# cal_subset = class_mbdata.MBData(name=dataset) +# cal_subset_data = cal_subset.retrieve_mb(main_glac_rgi_all, main_glac_hyps_all, dates_table_nospinup) +# cal_data = cal_data.append(cal_subset_data, ignore_index=True) +# cal_data = cal_data.sort_values(['glacno', 't1_idx']) +# cal_data.reset_index(drop=True, inplace=True) +# +# # If group data is included, then add group dictionary and add group name to main_glac_rgi +# if set(['group']).issubset(input.cal_datasets) == True: +# # Group dictionary +# group_dict_raw = pd.read_csv(input.mb_group_fp + input.mb_group_dict_fn) +# # Remove groups that have no data +# group_names_wdata = np.unique(cal_data[np.isnan(cal_data.glacno)].group_name.values).tolist() +# group_dict_raw_wdata = group_dict_raw.loc[group_dict_raw.group_name.isin(group_names_wdata)] +# # Create dictionary to map group names to main_glac_rgi +# group_dict = dict(zip(group_dict_raw_wdata['RGIId'], group_dict_raw_wdata['group_name'])) +# group_names_unique = list(set(group_dict.values())) +# group_dict_keyslist = [[] for x in group_names_unique] +# for n, group in enumerate(group_names_unique): +# group_dict_keyslist[n] = [group, [k for k, v in group_dict.items() if v == group]] +# # Add group name to main_glac_rgi +# main_glac_rgi_all['group_name'] = main_glac_rgi_all['RGIId'].map(group_dict) +# else: +# main_glac_rgi_all['group_name'] = np.nan +# +# # Drop glaciers that do not have any calibration data (individual or group) +# main_glac_rgi = ((main_glac_rgi_all.iloc[np.unique( +# np.append(main_glac_rgi_all[main_glac_rgi_all['group_name'].notnull() == True].index.values, +# np.where(main_glac_rgi_all['rgino_str'].isin(cal_data['glacno']) == True)[0])), :]) +# .copy()) +# # select glacier data +# main_glac_hyps = main_glac_hyps_all.iloc[main_glac_rgi.index.values] +# main_glac_icethickness = main_glac_icethickness_all.iloc[main_glac_rgi.index.values] +# main_glac_width = main_glac_width_all.iloc[main_glac_rgi.index.values] +# # Reset index +# main_glac_rgi.reset_index(drop=True, inplace=True) +# main_glac_hyps.reset_index(drop=True, inplace=True) +# main_glac_icethickness.reset_index(drop=True, inplace=True) +# main_glac_width.reset_index(drop=True, inplace=True) +# +# # ===== LOAD CLIMATE DATA ===== +# gcm = class_climate.GCM(name=gcm_name) +# # Air temperature [degC], Air temperature Std [K], Precipitation [m], Elevation [masl], Lapse rate [K m-1] +# gcm_temp, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn, gcm.temp_vn, main_glac_rgi, dates_table) +# gcm_prec, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn, gcm.prec_vn, main_glac_rgi, dates_table) +# gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn, main_glac_rgi) +# # Air temperature standard deviation [K] +# if input.option_ablation != 2 or gcm_name not in ['ERA5']: +# gcm_tempstd = np.zeros(gcm_temp.shape) +# elif gcm_name in ['ERA5']: +# gcm_tempstd, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.tempstd_fn, gcm.tempstd_vn, +# main_glac_rgi, dates_table) +# # Lapse rate [K m-1] +# if gcm_name in ['ERA-Interim', 'ERA5']: +# gcm_lr, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.lr_fn, gcm.lr_vn, main_glac_rgi, dates_table) +# else: +# # Mean monthly lapse rate +# ref_lr_monthly_avg = np.genfromtxt(gcm.lr_fp + gcm.lr_fn, delimiter=',') +# gcm_lr = np.tile(ref_lr_monthly_avg, int(gcm_temp.shape[1]/12)) +# # COAWST data has two domains, so need to merge the two domains +# if gcm_name == 'COAWST': +# gcm_temp_d01, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn_d01, gcm.temp_vn, main_glac_rgi, +# dates_table) +# gcm_prec_d01, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn_d01, gcm.prec_vn, main_glac_rgi, +# dates_table) +# gcm_elev_d01 = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn_d01, gcm.elev_vn, main_glac_rgi) +# # Check if glacier outside of high-res (d02) domain +# for glac in range(main_glac_rgi.shape[0]): +# glac_lat = main_glac_rgi.loc[glac,input.rgi_lat_colname] +# glac_lon = main_glac_rgi.loc[glac,input.rgi_lon_colname] +# if (~(input.coawst_d02_lat_min <= glac_lat <= input.coawst_d02_lat_max) or +# ~(input.coawst_d02_lon_min <= glac_lon <= input.coawst_d02_lon_max)): +# gcm_prec[glac,:] = gcm_prec_d01[glac,:] +# gcm_temp[glac,:] = gcm_temp_d01[glac,:] +# gcm_elev[glac] = gcm_elev_d01[glac] +# +# +# +# +# +# # Number of cores for parallel processing +# if args.option_parallels != 0: +# num_cores = int(np.min([len(glac_no), args.num_simultaneous_processes])) +# else: +# num_cores = 1 +# +# # Glacier number lists to pass for parallel processing +# glac_no_lsts = split_glaciers.split_list(glac_no, n=num_cores, option_ordered=args.option_ordered) +# +# # Read GCM names from argument parser +# gcm_name = args.gcm_list_fn +# if args.gcm_name is not None: +# gcm_list = [args.gcm_name] +# rcp_scenario = args.rcp +# elif args.gcm_list_fn == input.ref_gcm_name: +# gcm_list = [input.ref_gcm_name] +# rcp_scenario = args.rcp +# else: +# with open(args.gcm_list_fn, 'r') as gcm_fn: +# gcm_list = gcm_fn.read().splitlines() +# rcp_scenario = os.path.basename(args.gcm_list_fn).split('_')[1] +# print('Found %d gcms to process'%(len(gcm_list))) +# +# # Loop through all GCMs +# for gcm_name in gcm_list: +# if args.rcp is None: +# print('Processing:', gcm_name) +# else: +# print('Processing:', gcm_name, rcp_scenario) +# # Pack variables for multiprocessing +# list_packed_vars = [] +# for count, glac_no_lst in enumerate(glac_no_lsts): +# list_packed_vars.append([count, glac_no_lst, regions_str, gcm_name]) +# +# # Parallel processing +# if args.option_parallels != 0: +# print('Processing in parallel with ' + str(args.num_simultaneous_processes) + ' cores...') +# with multiprocessing.Pool(args.num_simultaneous_processes) as p: +# p.map(main,list_packed_vars) +# # If not in parallel, then only should be one loop +# else: +# # Loop through the chunks and export bias adjustments +# for n in range(len(list_packed_vars)): +# main(list_packed_vars[n]) +# +# # Merge netcdf files together into one +# # Filenames to merge +# output_list_sorted = [] +# output_sim_fp = input.output_sim_fp + gcm_name + '/' +# if input.option_calibration == 2: +# sim_iters = input.sim_iters +# else: +# sim_iters = 1 +# +# if gcm_name in ['ERA-Interim', 'ERA5', 'COAWST']: +# check_str = (regions_str + '_' + gcm_name + '_c' + str(input.option_calibration) + '_ba' + +# str(input.option_bias_adjustment) + '_' + str(sim_iters) + 'sets' + '_' + +# str(input.gcm_startyear) + '_' + str(input.gcm_endyear) + '--') +# else: +# check_str = (regions_str + '_' + gcm_name + '_' + rcp_scenario + '_c' + str(input.option_calibration) + +# '_ba' + str(input.option_bias_adjustment) + '_' + str(sim_iters) + 'sets' + '_' + +# str(input.gcm_startyear) + '_' + str(input.gcm_endyear) + '--') +# if input.option_synthetic_sim==1: +# check_str = (check_str.split('--')[0] + '_T' + str(input.synthetic_temp_adjust) + '_P' + +# str(input.synthetic_prec_factor) + '--') +# if args.batch_number is not None: +# check_str = check_str.split('--')[0] + '_batch' + str(args.batch_number) + '--' +# for i in os.listdir(output_sim_fp): +# if i.startswith(check_str): +# output_list_sorted.append([int(i.split('--')[1].split('.')[0]), i]) +# output_list_sorted = sorted(output_list_sorted) +# output_list = [i[1] for i in output_list_sorted] +# # Open datasets and combine +# count_ds = 0 +# for i in output_list: +# count_ds += 1 +# +# print(count_ds, 'output_list file:', i) +# +# ds = xr.open_dataset(output_sim_fp + i) +# # Merge datasets of stats into one output +# if count_ds == 1: +# ds_all = ds +# else: +## ds_all = xr.merge((ds_all, ds)) +# ds_all = xr.concat([ds_all, ds], 'glac') +# # Close dataset (NOTE: closing dataset here causes error on supercomputer) +## ds.close() +# +# # Filename +# ds_all_fn = i.split('--')[0] + '.nc' +# # Encoding +# # Add variables to empty dataset and merge together +# encoding = {} +# noencoding_vn = ['stats', 'glac_attrs'] +# if input.output_package == 2: +# for vn in input.output_variables_package2: +# # Encoding (specify _FillValue, offsets, etc.) +# if vn not in noencoding_vn: +# encoding[vn] = {'_FillValue': False} +# # Export to netcdf +# if input.output_package == 2: +# ds_all.to_netcdf(output_sim_fp + ds_all_fn, encoding=encoding) +# else: +# ds_all.to_netcdf(output_sim_fp + ds_all_fn) +# # Close dataset +# ds.close() +# ds_all.close() +# # Remove files in output_list +# for i in output_list: +# os.remove(output_sim_fp + i) +# +# print('Total processing time:', time.time()-time_start, 's') +# +## print('memory:', resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 10**6, 'GB') #%% ===== PLOTTING AND PROCESSING FOR MODEL DEVELOPMENT ===== # Place local variables in variable explorer if args.option_parallels == 0: main_vars_list = list(main_vars.keys()) gcm_name = main_vars['gcm_name'] +# rcp_scenario = main_vars['rcp_scenario'] main_glac_rgi = main_vars['main_glac_rgi'] main_glac_hyps = main_vars['main_glac_hyps'] main_glac_icethickness = main_vars['main_glac_icethickness'] @@ -1180,8 +1557,10 @@ def main(list_packed_vars): gcm_temp_adj = main_vars['gcm_temp_adj'] gcm_prec_adj = main_vars['gcm_prec_adj'] gcm_elev_adj = main_vars['gcm_elev_adj'] +# if input.option_bias_adjustment != 0: +# main_glac_biasadj = main_vars['main_glac_biasadj'] gcm_temp_lrglac = main_vars['gcm_lr'] - output_ds_all_stats = main_vars['output_ds_all_stats'] +# output_ds_all = main_vars['output_ds_all'] modelparameters = main_vars['modelparameters'] glacier_rgi_table = main_vars['glacier_rgi_table'] glacier_gcm_temp = main_vars['glacier_gcm_temp'] @@ -1190,9 +1569,9 @@ def main(list_packed_vars): glacier_gcm_elev = main_vars['glacier_gcm_elev'] glacier_gcm_lrgcm = main_vars['glacier_gcm_lrgcm'] glacier_gcm_lrglac = glacier_gcm_lrgcm - glacier_area_initial = main_vars['glacier_area_initial'] - icethickness_initial = main_vars['icethickness_initial'] - width_initial = main_vars['width_initial'] + glacier_area_t0 = main_vars['glacier_area_t0'] + icethickness_t0 = main_vars['icethickness_t0'] + width_t0 = main_vars['width_t0'] elev_bins = main_vars['elev_bins'] glac_bin_frontalablation = main_vars['glac_bin_frontalablation'] glac_bin_area_annual = main_vars['glac_bin_area_annual'] @@ -1210,5 +1589,67 @@ def main(list_packed_vars): glac_wide_runoff = main_vars['glac_wide_runoff'] glac_wide_prec = main_vars['glac_wide_prec'] glac_wide_refreeze = main_vars['glac_wide_refreeze'] + + modelparameters_all = main_vars['modelparameters_all'] - sim_iters = main_vars['sim_iters'] \ No newline at end of file + sim_iters = main_vars['sim_iters'] +# cal_data = main_vars['cal_data'] +# if input.option_calibration == 2: +# mp_idx = main_vars['mp_idx'] +# mp_idx_all = main_vars['mp_idx_all'] +# netcdf_fn = main_vars['netcdf_fn'] + +##%% +## ds = xr.open_dataset(input.output_sim_fp + 'CanESM2/R13_CanESM2_rcp26_c2_ba1_100sets_2000_2100.nc') +## vol_annual = ds.volume_glac_annual.values[0,:,0] +## mb_monthly = ds.massbaltotal_glac_monthly.values[0,:,0] +## area_annual = ds.area_glac_annual.values[0,:,0] +## +## # ===== MASS CHANGE CALCULATIONS ===== +## # Compute glacier volume change for every time step and use this to compute mass balance +### glac_wide_area = np.repeat(area_annual[:,:-1], 12, axis=1) +## glac_wide_area = np.repeat(area_annual[:-1], 12) +## +## # Mass change [km3 mwe] +## # mb [mwea] * (1 km / 1000 m) * area [km2] +## glac_wide_masschange = mb_monthly / 1000 * glac_wide_area +## +## print('Average mass balance:', np.round(glac_wide_masschange.sum() / 101, 2), 'Gt/yr') +## +## print('Average mass balance:', np.round(mb_monthly.sum() / 101, 2), 'mwea') +## +## A = mb_monthly[0:18*12] +## print(A.sum() / 18) +## +## print('Vol change[%]:', vol_annual[-1] / vol_annual[0] * 100) +## ds.close() +# +## #%% +## # ===== MASS CHANGE CALCULATIONS: ISSUE WITH USING AVERAGE MB AND AREA TO COMPUTE VOLUME CHANGE ====== +## # Mean volume change from each volume simulation +## A = output_ds_all.volume_glac_annual.values[0,:,:] +## A_volchg = A[-1,:] - A[0,:] +## A_volchg_mean = np.mean(A_volchg) +## +## # Mean volume change from each mass balance and area simulation +## B = output_ds_all.massbaltotal_glac_monthly.values[0,:,:] +## B_area = (output_ds_all.area_glac_annual.values[0,:-1,:]).repeat(12,axis=0) +## B_volchg_monthly = B / 1000 * B_area / 0.9 +## B_volchg = np.sum(B_volchg_monthly, axis=0) +## B_volchg_mean = np.mean(B_volchg) +## +## print('Volume change from each simulation of volume agree with each simulation of mass balance and area:', +## 'from volume:', np.round(A_volchg_mean,9), 'from MB/area:', np.round(B_volchg_mean,9), +## 'difference:', np.round(A_volchg_mean - B_volchg_mean,9)) +## +## # Mean volume change based on the mean mass balance and mean area (these are what we output because files would be +## # too large to output every simulation) +## B_mean = B.mean(axis=1) +## B_mean_area = B_area.mean(axis=1) +## B_mean_volchg_monthly = B_mean / 1000 * B_mean_area / 0.9 +## B_mean_volchg = np.sum(B_mean_volchg_monthly) +## +## print('\nVolume change from each simulation of volume is different than using mean mass balance and area', +## 'from volume', np.round(A_volchg_mean,9), 'from mean MB/area:', np.round(B_mean_volchg,9), +## 'difference:', np.round(A_volchg_mean - B_mean_volchg,9)) +# diff --git a/shean_mb_parallel.py b/shean_mb_parallel.py deleted file mode 100644 index eb988a93..00000000 --- a/shean_mb_parallel.py +++ /dev/null @@ -1,1446 +0,0 @@ -#! /usr/bin/env python -""" -Compute dh/dt and mass balance for input DEMs and glacier polygons -Author: David Shean -Reference: https://github.com/dshean/gmbtools/tree/master/gmbtools -Modified by: David Rounce -""" - -""" -Todo: -GDAL_MAX_DATASET_POOL_SIZE - set to large number of open datasets in vrt -Better error estimates - use buffered dz/dt and semivariogram -Filling gaps using 1) dz/dt obs 2) setting to 0 around polygon margins -Curves for PRISM T an precip vs. mb -Move mb_plot_gpd funcitonality here, export polygons with mb numbers as geojson, spatialite, shp? -Add +/- std for each dh/dt polygon, some idea of spread -Create main function, pass args to mb_proc -Clean up mb_proc function, one return, globals -Better penetration correction -""" - -import sys -import os -import re -import subprocess -from datetime import datetime, timedelta -import time -import pickle -from collections import OrderedDict - -import geopandas as gpd -import matplotlib.pyplot as plt -import numpy as np -import rasterio -from osgeo import gdal, ogr, osr - -from pygeotools.lib import malib, warplib, geolib, iolib, timelib -# from imview.lib import pltlib - -#Avoid printing out divide by 0 errors -np.seterr(all='ignore') - -""" -Class to store relevant feature attributes and derived values -Safe for multiprocessing -""" -class GlacFeat: - def __init__(self, feat, glacname_fieldname, glacnum_fieldname): - - self.glacname = feat.GetField(glacname_fieldname) - if self.glacname is None: - self.glacname = "" - else: - #RGI has some nonstandard characters - #self.glacname = self.glacname.decode('unicode_escape').encode('ascii','ignore') - #glacname = re.sub(r'[^\x00-\x7f]',r'', glacname) - self.glacname = re.sub(r'\W+', '', self.glacname) - self.glacname = self.glacname.replace(" ", "") - self.glacname = self.glacname.replace("_", "") - self.glacname = self.glacname.replace("/", "") - - self.glacnum = feat.GetField(glacnum_fieldname) - fn = feat.GetDefnRef().GetName() - #RGIId (String) = RGI50-01.00004 - self.glacnum = '%0.5f' % float(self.glacnum.split('-')[-1]) - - if self.glacname: - self.feat_fn = "%s_%s" % (self.glacnum, self.glacname) - else: - self.feat_fn = str(self.glacnum) - - self.glac_geom_orig = geolib.geom_dup(feat.GetGeometryRef()) - self.glac_geom = geolib.geom_dup(self.glac_geom_orig) - #Hack to deal with fact that this is not preserved in geom when loaded from pickle on disk - self.glac_geom_srs_wkt = self.glac_geom.GetSpatialReference().ExportToWkt() - - #Attributes written by mb_calc - self.z1 = None - self.z1_hs = None - self.z1_stats = None - self.z1_ela = None - self.z2 = None - self.z2_hs = None - self.z2_stats = None - self.z2_ela = None - self.z2_aspect = None - self.z2_aspect_stats = None - self.z2_slope = None - self.z2_slope_stats = None - self.res = None - self.dhdt = None - self.mb = None - self.mb_mean = None - self.t1 = None - self.t2 = None - self.dt = None - self.t1_mean = None - self.t2_mean = None - self.dt_mean = None - - self.H = None - self.H_mean = np.nan - self.vx = None - self.vy = None - self.vm = None - self.vm_mean = np.nan - self.divQ = None - self.debris_class = None - self.debris_thick = None - self.debris_thick_mean = np.nan - self.perc_clean = np.nan - self.perc_debris = np.nan - self.perc_pond = np.nan - - def geom_srs_update(self, srs=None): - if self.glac_geom.GetSpatialReference() is None: - if srs is None: - srs = osr.SpatialReference() - srs.ImportFromWkt(self.glac_geom_srs_wkt) - self.glac_geom.AssignSpatialReference(srs) - - def geom_attributes(self, srs=None): - self.geom_srs_update() - if srs is not None: - #Should reproject here to equal area, before geom_attributes - #self.glac_geom.AssignSpatialReference(glac_shp_srs) - #self.glac_geom_local = geolib.geom2localortho(self.glac_geom) - geolib.geom_transform(self.glac_geom, srs) - - self.glac_geom_extent = geolib.geom_extent(self.glac_geom) - self.glac_area = self.glac_geom.GetArea() - self.glac_area_km2 = self.glac_area / 1E6 - self.cx, self.cy = self.glac_geom.Centroid().GetPoint_2D() - -def srtm_corr(z): - #Should separate into different regions from Kaab et al (2012) - #Should separate into firn/snow, clean ice, and debris-covered ice - - #For now, use Kaab et al (2012) region-wide mean of 2.1 +/- 0.4 - offset = 2.1 - return z + offset - -def z_vs_dz(z,dz): - plt.scatter(z.compressed(), dz.compressed()) - -#RGI uses 50 m bins -def hist_plot(gf, outdir, bin_width=50.0, dz_clim=(-2.0, 2.0)): - #print("Generating histograms") - #Create bins for full range of input data and specified bin width - - #NOTE: these counts/areas are for valid pixels only - #Not necessarily a true representation of actual glacier hypsometry - #Need a void-filled DEM for this - - z_bin_edges, z_bin_centers = malib.get_bins(gf.z1, bin_width) - #Need to compress here, otherwise histogram uses masked values! - z1_bin_counts, z1_bin_edges = np.histogram(gf.z1.compressed(), bins=z_bin_edges) - z1_bin_areas = z1_bin_counts * gf.res[0] * gf.res[1] / 1E6 - #RGI standard is integer thousandths of glaciers total area - #Should check to make sure sum of bin areas equals total area - #z1_bin_areas_perc = 100. * z1_bin_areas / np.sum(z1_bin_areas) - z1_bin_areas_perc = 100. * (z1_bin_areas / gf.glac_area_km2) - - #If we only have one elevation grid with dhdt - if gf.z2 is not None: - z2_bin_counts, z2_bin_edges = np.histogram(gf.z2.compressed(), bins=z_bin_edges) - z2_bin_areas = z2_bin_counts * gf.res[0] * gf.res[1] / 1E6 - #z2_bin_areas_perc = 100. * z2_bin_areas / np.sum(z2_bin_areas) - z2_bin_areas_perc = 100. * (z1_bin_areas / gf.glac_area_km2) - else: - z2_bin_counts = z1_bin_counts - z2_bin_edges = z1_bin_edges - z2_bin_areas = z1_bin_areas - z2_bin_areas_perc = z1_bin_areas_perc - - #Create arrays to store output - mb_bin_med = np.ma.masked_all_like(z1_bin_areas) - np.ma.set_fill_value(mb_bin_med, np.nan) - mb_bin_mad = np.ma.masked_all_like(mb_bin_med) - mb_bin_mean = np.ma.masked_all_like(mb_bin_med) - mb_bin_std = np.ma.masked_all_like(mb_bin_med) - dhdt_bin_med = np.ma.masked_all_like(mb_bin_med) - dhdt_bin_mad = np.ma.masked_all_like(mb_bin_med) - dhdt_bin_mean = np.ma.masked_all_like(mb_bin_med) - dhdt_bin_std = np.ma.masked_all_like(mb_bin_med) - dhdt_bin_count = np.ma.masked_all_like(mb_bin_med) - if gf.vm is not None: - vm_bin_med = np.ma.masked_all_like(mb_bin_med) - vm_bin_mad = np.ma.masked_all_like(mb_bin_med) - if gf.H is not None: - H_bin_mean = np.ma.masked_all_like(mb_bin_med) - H_bin_std = np.ma.masked_all_like(mb_bin_med) - if gf.debris_class is not None: - perc_clean = np.ma.masked_all_like(mb_bin_med) - perc_debris = np.ma.masked_all_like(mb_bin_med) - perc_pond = np.ma.masked_all_like(mb_bin_med) - debris_thick_med = np.ma.masked_all_like(mb_bin_med) - debris_thick_mad = np.ma.masked_all_like(mb_bin_med) - dhdt_clean_bin_med = np.ma.masked_all_like(mb_bin_med) - dhdt_debris_bin_med = np.ma.masked_all_like(mb_bin_med) - dhdt_pond_bin_med = np.ma.masked_all_like(mb_bin_med) - - gf.dhdt_clean = np.ma.array(gf.dhdt, mask=~((gf.debris_class == 1).data)) - gf.dhdt_debris = np.ma.array(gf.dhdt, mask=~((gf.debris_class == 2).data)) - gf.dhdt_pond = np.ma.array(gf.dhdt, mask=~((gf.debris_class == 3).data)) - - #Bin sample count must be greater than this value - min_bin_samp_count = 9 - - #Loop through each bin and extract stats - idx = np.digitize(gf.z1, z_bin_edges) - for bin_n in range(z_bin_centers.size): - mb_bin_samp = gf.mb_map[(idx == bin_n+1)] - if mb_bin_samp.count() > min_bin_samp_count: - mb_bin_med[bin_n] = malib.fast_median(mb_bin_samp) - mb_bin_mad[bin_n] = malib.mad(mb_bin_samp) - mb_bin_mean[bin_n] = mb_bin_samp.mean() - mb_bin_std[bin_n] = mb_bin_samp.std() - dhdt_bin_samp = gf.dhdt[(idx == bin_n+1)] - if dhdt_bin_samp.count() > min_bin_samp_count: - dhdt_bin_med[bin_n] = malib.fast_median(dhdt_bin_samp) - dhdt_bin_mad[bin_n] = malib.mad(dhdt_bin_samp) - dhdt_bin_mean[bin_n] = dhdt_bin_samp.mean() - dhdt_bin_std[bin_n] = dhdt_bin_samp.std() - dhdt_bin_count[bin_n] = dhdt_bin_samp.count() - if gf.debris_thick is not None: - debris_thick_bin_samp = gf.debris_thick[(idx == bin_n+1)] - if debris_thick_bin_samp.size > min_bin_samp_count: - debris_thick_med[bin_n] = malib.fast_median(debris_thick_bin_samp) - debris_thick_mad[bin_n] = malib.mad(debris_thick_bin_samp) - if gf.debris_class is not None: - debris_class_bin_samp = gf.debris_class[(idx == bin_n+1)] - dhdt_clean_bin_samp = gf.dhdt_clean[(idx == bin_n+1)] - dhdt_debris_bin_samp = gf.dhdt_debris[(idx == bin_n+1)] - dhdt_pond_bin_samp = gf.dhdt_pond[(idx == bin_n+1)] - if debris_class_bin_samp.count() > min_bin_samp_count: - perc_clean[bin_n] = 100. * (debris_class_bin_samp == 1).sum()/debris_class_bin_samp.count() - perc_debris[bin_n] = 100. * (debris_class_bin_samp == 2).sum()/debris_class_bin_samp.count() - perc_pond[bin_n] = 100. * (debris_class_bin_samp == 3).sum()/debris_class_bin_samp.count() - if dhdt_clean_bin_samp.count() > min_bin_samp_count: - dhdt_clean_bin_med[bin_n] = malib.fast_median(dhdt_clean_bin_samp) - if dhdt_debris_bin_samp.count() > min_bin_samp_count: - dhdt_debris_bin_med[bin_n] = malib.fast_median(dhdt_debris_bin_samp) - if dhdt_pond_bin_samp.count() > min_bin_samp_count: - dhdt_pond_bin_med[bin_n] = malib.fast_median(dhdt_pond_bin_samp) - if gf.vm is not None: - vm_bin_samp = gf.vm[(idx == bin_n+1)] - if vm_bin_samp.size > min_bin_samp_count: - vm_bin_med[bin_n] = malib.fast_median(vm_bin_samp) - vm_bin_mad[bin_n] = malib.mad(vm_bin_samp) - if gf.H is not None: - H_bin_samp = gf.H[(idx == bin_n+1)] - if H_bin_samp.size > min_bin_samp_count: - H_bin_mean[bin_n] = H_bin_samp.mean() - H_bin_std[bin_n] = H_bin_samp.std() - - dhdt_bin_areas = dhdt_bin_count * gf.res[0] * gf.res[1] / 1E6 - #dhdt_bin_areas_perc = 100. * dhdt_bin_areas / np.sum(dhdt_bin_areas) - dhdt_bin_areas_perc = 100. * (dhdt_bin_areas / gf.glac_area_km2) - - outbins_header = 'bin_center_elev_m, z1_bin_count_valid, z1_bin_area_valid_km2, z1_bin_area_perc, z2_bin_count_valid, z2_bin_area_valid_km2, z2_bin_area_perc, dhdt_bin_count, dhdt_bin_area_valid_km2, dhdt_bin_area_perc, dhdt_bin_med_ma, dhdt_bin_mad_ma, dhdt_bin_mean_ma, dhdt_bin_std_ma, mb_bin_med_mwea, mb_bin_mad_mwea, mb_bin_mean_mwea, mb_bin_std_mwea' - fmt = '%0.1f, %0.0f, %0.3f, %0.2f, %0.0f, %0.3f, %0.2f, %0.0f, %0.3f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f' - outbins = [z_bin_centers, z1_bin_counts, z1_bin_areas, z1_bin_areas_perc, z2_bin_counts, z2_bin_areas, z2_bin_areas_perc, \ - dhdt_bin_count, dhdt_bin_areas, dhdt_bin_areas_perc, dhdt_bin_med, dhdt_bin_mad, dhdt_bin_mean, dhdt_bin_std, \ - mb_bin_med, mb_bin_mad, mb_bin_mean, mb_bin_std] - - if gf.debris_thick is not None: - outbins_header += ', debris_thick_med_m, debris_thick_mad_m' - fmt += ', %0.2f, %0.2f' - debris_thick_med[debris_thick_med == -(np.inf)] = 0.00 - debris_thick_mad[debris_thick_mad == -(np.inf)] = 0.00 - outbins.extend([debris_thick_med, debris_thick_mad]) - if gf.debris_class is not None: - outbins_header += ', perc_debris, perc_pond, perc_clean, dhdt_debris_med, dhdt_pond_med, dhdt_clean_med' - fmt += ', %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f' - outbins.extend([perc_debris, perc_pond, perc_clean, dhdt_debris_bin_med, dhdt_pond_bin_med, dhdt_clean_bin_med]) - if gf.vm is not None: - outbins_header += ', vm_med, vm_mad' - fmt += ', %0.2f, %0.2f' - outbins.extend([vm_bin_med, vm_bin_mad]) - if gf.H is not None: - outbins_header += ', H_mean, H_std' - fmt += ', %0.2f, %0.2f' - outbins.extend([H_bin_mean, H_bin_std]) - - outbins = np.ma.array(outbins).T.astype('float32') - np.ma.set_fill_value(outbins, np.nan) - outbins = outbins.filled(np.nan) - outbins_fn = os.path.join(outdir_csv, gf.feat_fn+'_mb_bins.csv') - np.savetxt(outbins_fn, outbins, fmt=fmt, delimiter=',', header=outbins_header) - - #Create plots of elevation bins - #print("Generating aed plot") - #f,axa = plt.subplots(1,2, figsize=(6, 6)) - n_subplots = 2 - if gf.debris_thick is not None or gf.debris_class is not None: - n_subplots += 1 - if gf.H is not None: - n_subplots += 1 - - f,axa = plt.subplots(1,n_subplots, figsize=(10, 7.5)) - f.suptitle(gf.feat_fn) - fs = 9 - - axa[0].plot(z1_bin_areas, z_bin_centers, label='%0.2f' % gf.t1_mean) - axa[0].axhline(gf.z1_ela, ls=':', c='C0') - if gf.z2 is not None: - axa[0].plot(z2_bin_areas, z_bin_centers, label='%0.2f' % gf.t2_mean) - axa[0].axhline(gf.z2_ela, ls=':', c='C1') - axa[0].legend(prop={'size':8}, loc='upper right') - axa[0].set_ylabel('Elevation (m WGS84)', fontsize=fs) - axa[0].set_xlabel('Area $\mathregular{km^2}$', fontsize=fs) - axa[0].yaxis.set_ticks_position('both') - # pltlib.minorticks_on(axa[0]) - - axa[1].axvline(0, lw=1.0, c='k') - """ - #Plot flux divergence values for each bin - if gf.vm is not None and gf.H is not None: - divQ_bin_mean = np.gradient(H_bin_mean * vm_bin_med * v_col_f) - axa[1].plot(divQ_bin_mean, z_bin_centers, color='green') - """ - axa[1].plot(mb_bin_med, z_bin_centers, color='k') - axa[1].axvline(gf.mb_mean, lw=0.5, ls=':', c='k', label='%0.2f m w.e./yr' % gf.mb_mean) - axa[1].fill_betweenx(z_bin_centers, mb_bin_med-mb_bin_mad, mb_bin_med+mb_bin_mad, color='k', alpha=0.1) - axa[1].fill_betweenx(z_bin_centers, 0, mb_bin_med, where=(mb_bin_med<0), color='r', alpha=0.2) - axa[1].fill_betweenx(z_bin_centers, 0, mb_bin_med, where=(mb_bin_med>0), color='b', alpha=0.2) - #axa[1].set_xlabel('dh/dt (m/yr)') - axa[1].set_xlabel('Mass balance (m w.e./yr)', fontsize=fs) - axa[1].legend(prop={'size':8}, loc='upper right') - axa[1].yaxis.set_ticks_position('both') - # pltlib.minorticks_on(axa[1]) - #Hide y-axis labels - axa[1].axes.yaxis.set_ticklabels([]) - axa[1].set_xlim(*dz_clim) - - if gf.debris_thick is not None: - axa[2].errorbar(debris_thick_med*100., z_bin_centers, xerr=debris_thick_mad*100, color='k', fmt='o', ms=3, label='Debris Thickness', alpha=0.6) - if gf.debris_class is not None: - axa[2].plot(perc_debris, z_bin_centers, color='sienna', label='Debris Coverage') - axa[2].plot(perc_pond, z_bin_centers, color='turquoise', label='Pond Coverage') - if gf.debris_thick is not None or gf.debris_class is not None: - axa[2].set_xlim(0, 100) - axa[2].yaxis.set_ticks_position('both') - # pltlib.minorticks_on(axa[2]) - axa[2].axes.yaxis.set_ticklabels([]) - axa[2].legend(prop={'size':8}, loc='upper right') - axa[2].set_xlabel('Debris thickness (cm), coverage (%)', fontsize=fs) - - if gf.vm is not None: - ax4 = axa[3].twinx() - ax4.set_xlabel('Velocity (m/yr)', fontsize=fs) - ax4.plot(vm_bin_med, z_bin_centers, color='g', label='Vm (%0.2f m/yr)' % gf.vm_mean) - ax4.fill_betweenx(z_bin_centers, vm_bin_med-vm_bin_mad, vm_bin_med+vm_bin_mad, color='g', alpha=0.1) - #ax4.set_xlim(0, 50) - ax4.xaxis.tick_top() - ax4.xaxis.set_label_position("top") - ax4.legend(prop={'size':8}, loc='upper right') - - if gf.H is not None: - axa[3].plot(H_bin_mean, z_bin_centers, color='b', label='H (%0.2f m)' % gf.H_mean) - axa[3].fill_betweenx(z_bin_centers, H_bin_mean-H_bin_std, H_bin_mean+H_bin_std, color='b', alpha=0.1) - axa[3].set_xlabel('Ice Thickness (m)', fontsize=fs) - axa[3].legend(prop={'size':8}, loc='lower right') - # pltlib.minorticks_on(axa[3]) - #axa[3].set_xlim(0, 400) - axa[3].yaxis.tick_right() - axa[3].yaxis.set_ticks_position('both') - axa[3].yaxis.set_label_position("right") - - plt.tight_layout() - #Make room for suptitle - plt.subplots_adjust(top=0.95, wspace=0.1) - #print("Saving aed plot") - fig_fn = os.path.join(outdir_fig, gf.feat_fn+'_mb_aed.png') - #plt.savefig(fig_fn, bbox_inches='tight', dpi=300) - plt.savefig(fig_fn, dpi=300) - plt.close(f) - return z_bin_edges - -def map_plot(gf, z_bin_edges, outdir, hs=True, dz_clim=(-2.0, 2.0)): - #print("Generating map plot") - f,axa = plt.subplots(1,3, figsize=(10,7.5)) - # f.subplots_adjust(left=0.02, bottom=0.06, right=0.95, top=0.94, wspace=0.05) - #f.suptitle(gf.feat_fn) - alpha = 1.0 - cmap_elev = 'gist_rainbow' - if hs: - #z1_hs = geolib.gdaldem_wrapper(gf.out_z1_fn, product='hs', returnma=True, verbose=False) - #z2_hs = geolib.gdaldem_wrapper(gf.out_z2_fn, product='hs', returnma=True, verbose=False) - z1_hs = gf.z1_hs - z2_hs = gf.z2_hs - hs_clim = malib.calcperc(z2_hs, (2,98)) - z1_hs_im = axa[0].imshow(z1_hs, cmap='gray', vmin=hs_clim[0], vmax=hs_clim[1]) - z2_hs_im = axa[1].imshow(z2_hs, cmap='gray', vmin=hs_clim[0], vmax=hs_clim[1]) - alpha = 0.5 - z1_im = axa[0].imshow(gf.z1, cmap=cmap_elev, vmin=z_bin_edges[0], vmax=z_bin_edges[-1], alpha=alpha) - z2_im = axa[1].imshow(gf.z2, cmap=cmap_elev, vmin=z_bin_edges[0], vmax=z_bin_edges[-1], alpha=alpha) - axa[0].contour(gf.z1, [gf.z1_ela,], linewidths=0.5, linestyles=':', colors='w') - axa[1].contour(gf.z2, [gf.z2_ela,], linewidths=0.5, linestyles=':', colors='w') - #t1_title = int(np.round(gf.t1)) - #t2_title = int(np.round(gf.t2)) - t1_title = str(np.round(gf.t1_mean,1)) + ' DEM (masl)' - t2_title = str(np.round(gf.t1_mean,1)) + ' DEM (masl)' - #t1_title = gf.t1.strftime('%Y-%m-%d') - #t2_title = gf.t2.strftime('%Y-%m-%d') - axa[0].set_title(t1_title) - axa[1].set_title(t2_title) - axa[2].set_title('dh/dt (mwea)') - dz_im = axa[2].imshow(gf.dhdt, cmap='RdBu', vmin=dz_clim[0], vmax=dz_clim[1]) - for ax in axa: - # pltlib.hide_ticks(ax) - ax.set_facecolor('k') - # Add colorbar - from mpl_toolkits.axes_grid1 import make_axes_locatable - # dhdt - divider = make_axes_locatable(axa[0]) - cax = divider.append_axes('right', size='5%', pad=0.05) - f.colorbar(z1_im, cax=cax, orientation='vertical') - # elevations - divider = make_axes_locatable(axa[2]) - cax = divider.append_axes('right', size='5%', pad=0.05) - f.colorbar(dz_im, cax=cax, orientation='vertical') - - # Add scalebar - # pltlib.add_scalebar(axa[0], gf.res[0], location=sb_loc) - # pltlib.add_cbar(axa[0], z1_im, label='Elevation (m WGS84)') - # pltlib.add_cbar(axa[1], z2_im, label='Elevation (m WGS84)') - # pltlib.add_cbar(axa[2], dz_im, label='dh/dt (m/yr)') - plt.tight_layout() - #Make room for suptitle - #plt.subplots_adjust(top=0.90) - #print("Saving map plot") - fig_fn = os.path.join(outdir_fig, gf.feat_fn+'_mb_map.png') - plt.savefig(fig_fn, dpi=300) - plt.close(f) - -def get_date_a(ds, date_shp_lyr, glac_geom_mask, datefield): - date_r_ds = iolib.mem_drv.CreateCopy('', ds) - #Shapefile order should be sorted by time, but might want to think about sorting here - #Can automatically search for datefield - gdal.RasterizeLayer(date_r_ds, [1], date_shp_lyr, options=["ATTRIBUTE=%s" % datefield]) - date_a = np.ma.array(iolib.ds_getma(date_r_ds), mask=glac_geom_mask) - #Note: NED dates are in integer years, assume source imagery was flown in late summer for mountains - if datefield == 'S_DATE_CLN': - date_a += 0.75 - return date_a - -""" -#Consider storing setup variables in dictionary that can be passed to Process -setup = {} -setup['site'] = site -""" - -topdir='/Users/davidrounce/Documents/Dave_Rounce/HiMAT/DEMs/' -#site = 'Braun_PCR07N' # COMPLETED -#site = 'Braun_PCR08N' # COMPLETED -#site = 'Braun_PCR09N' # COMPLETED -#site = 'Braun_AwA-1' # COMPLETED -#site = 'Braun_AwA-2' # COMPLETED -#site = 'Braun_AwA-3' # COMPLETED -#site = 'Braun_AwA-4' # COMPLETED -site = 'Braun_AwA-5' # COMPLETED -#site='StElias' -#site = 'Chugach' # COMPLETED -#site = 'AR_W' # COMPLETED -#site = 'AR_C' # COMPLETED -#site = 'AR_E' # COMPLETED -#site = 'Coast' # COMPLETED -#site = 'Kenai' # COMPLETED -#site = 'AK_Pen' # COMPLETED -# options: ['StElias', 'Chugach', 'AR_W', 'AR_C', 'AR_E', 'Coast', 'Kenai', 'AK_Pen', 'HMA'] -#Braun options: ['Braun_PCR07N', 'Braun_PCR08N', 'Braun_PCR09N', 'Braun_AwA-1', 'Braun_AwA-2', 'Braun_AwA-3', -# 'Braun_AwA-4', 'Braun_AwA-1'] - -print(site) - - -#Filter glacier poly - let's stick with big glaciers for no -min_glac_area = 0.0 #km^2 -#min_glac_area = 0.1 #km^2 -#min_glac_area = 1. #km^2 -# min_glac_area = 2. #km^2 -#Only write out for larger glaciers -min_glac_area_writeout = 1. -#Minimum percentage of glacier poly covered by valid dz -min_valid_area_perc = 0.6 # DSHEAN WAS 0.85 -#Process thickness, velocity, etc -extra_layers = False # DSHEAN WAS TRUE -#Write out DEMs and dz map -writeout = True -#Generate figures -mb_plot = True -#Run in parallel, set to False for serial loop -parallel = False -#Verbose for debugging -verbose = False -#Number of parallel processes -#Use all virtual cores -#nproc = iolib.cpu_count(logical=True) - 1 -#Use all physical cores -# nproc = iolib.cpu_count(logical=False) - 1 -nproc = 1 -#Shortcut to use existing glacfeat_list.p if found -use_existing_glacfeat = True - -#Pad by this distance (meters) around glacier polygon for uncertainty estimates over surrounding surfaces -buff_dist = 1000 - -#Bin width -bin_width = 50 - -#Surface to column average velocity scaling -v_col_f = 0.8 - -#This is recommendation by Huss et al (2013) -rho_is = 0.85 -rho_sigma = 0.06 - -#If breaking down into accumulation vs. ablation area -#rho_i = 0.91 -#rho_s = 0.50 -#rho_f = 0.60 - -#Fountain -#Other sources Kaab et al (2012) use 0.1 -area_sigma_perc = 0.09 - -global z1_date -global z2_date -z1_date = None -z2_date = None -z1_srtm_penetration_corr = False -z2_srtm_penetration_corr = False - - -if 'Braun' in site: - #Output directory - outdir = topdir + 'Braun/output/' - outdir_fig = topdir + 'Braun/output/figures/' - outdir_csv = topdir + 'Braun/output/csv/' - - glac_shp_fn = topdir + '../RGI/rgi60/01_rgi60_Alaska/01_rgi60_Alaska.shp' - glacfeat_fn = outdir + site + '_glacfeat_list.p' - - # Filenames - z1_fn_dict = {'Braun_PCR07N': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_03_PCRn/' + - 'srtm_filled_ice__03_PCRn-utm07N-strips_crp2reg_03_PCRn.tif', - 'Braun_PCR08N': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_03_PCRn/' + - 'srtm_filled_ice__03_PCRn-utm08N-strips_crp2reg_03_PCRn.tif', - 'Braun_PCR09N': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_03_PCRn/' + - 'srtm_filled_ice__03_PCRn-utm09N-strips_crp2reg_03_PCRn.tif', - 'Braun_AwA-1': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_04_AwA/' + - 'srtm_filled_ice__04_AwA-1-strips_crp2reg_04_AwA.tif', - 'Braun_AwA-2': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_04_AwA/' + - 'srtm_filled_ice__04_AwA-2-strips_crp2reg_04_AwA.tif', - 'Braun_AwA-3': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_04_AwA/' + - 'srtm_filled_ice__04_AwA-3-strips_crp2reg_04_AwA.tif', - 'Braun_AwA-4': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_04_AwA/' + - 'srtm_filled_ice__04_AwA-4-strips_crp2reg_04_AwA.tif', - 'Braun_AwA-5': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_04_AwA/' + - 'srtm_filled_ice__04_AwA-5-strips_crp2reg_04_AwA.tif', - } - z1_date_dict = 2000.128 - z2_fn_dict = None - z2_date_dict = 2012.0 - dhdt_fn_dict = {'Braun_PCR07N': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_03_PCRn/' + - 'dh_dt_on_ice__03_PCRn-utm07N-strips_crp2reg_03_PCRn.tif', - 'Braun_PCR08N': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_03_PCRn/' + - 'dh_dt_on_ice__03_PCRn-utm08N-strips_crp2reg_03_PCRn.tif', - 'Braun_PCR09N': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_03_PCRn/' + - 'dh_dt_on_ice__03_PCRn-utm09N-strips_crp2reg_03_PCRn.tif', - 'Braun_AwA-1': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_04_AwA/' + - 'dh_dt_on_ice__04_AwA-1-strips_crp2reg_04_AwA.tif', - 'Braun_AwA-2': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_04_AwA/' + - 'dh_dt_on_ice__04_AwA-2-strips_crp2reg_04_AwA.tif', - 'Braun_AwA-3': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_04_AwA/' + - 'dh_dt_on_ice__04_AwA-3-strips_crp2reg_04_AwA.tif', - 'Braun_AwA-4': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_04_AwA/' + - 'dh_dt_on_ice__04_AwA-4-strips_crp2reg_04_AwA.tif', - 'Braun_AwA-5': topdir + 'Braun/TDX-SRTM_prelim/NorthAmerica_dhdt/region_04_AwA/' + - 'dh_dt_on_ice__04_AwA-5-strips_crp2reg_04_AwA.tif',} - - - z1_fn = z1_fn_dict[site] - z1_date = z1_date_dict - z1_sigma = 10 - z1_srtm_penetration_corr = False - - if z2_fn_dict is None: - dhdt_fn = dhdt_fn_dict[site] - - # Hack - use z1 and dhdt to produce z2, so Shean processing scripts can be used for MB and binning calcs with Braun data - #Output projection - #'+proj=aea +lat_1=25 +lat_2=47 +lat_0=36 +lon_0=85 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ' - ds = gdal.Open(z1_fn) - prj = ds.GetProjection() - srs = osr.SpatialReference(wkt=prj) - aea_srs = srs - - #Warp everything to common res/extent/proj - ds_list = warplib.memwarp_multi_fn([z1_fn, dhdt_fn], - res='min', t_srs=aea_srs, verbose=verbose, r='cubic') - # DEM masks - ds_list_masked = [iolib.ds_getma(i) for i in ds_list] - z1 = np.ma.masked_less_equal(ds_list_masked[0], 0) - dhdt = ds_list_masked[1] - - # Create z2 from z1 and dhdt - z2 = z1 + dhdt * (z2_date_dict - z1_date_dict) - z2.mask = np.ma.mask_or(z1.mask, dhdt.mask) - - # Write out file - z2_fn = z1_fn.replace('srtm_filled_ice', 'z2_fromSTRM&dhdt') - iolib.writeGTiff(z2, z2_fn, src_ds=ds_list[0]) - - else: - z2_fn = z2_fn_dict[site] - z2_date = z2_date_dict - z2_sigma = 10 - z2_srtm_penetration_corr = False - - - #Output projection - #'+proj=aea +lat_1=25 +lat_2=47 +lat_0=36 +lon_0=85 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ' - # print('\n\nSHOULD CHANGE TO EQUAL AREA PROJECTION!\n\n') - # aea_srs = geolib.hma_aea_srs - ds = gdal.Open(z1_fn) - prj = ds.GetProjection() - srs = osr.SpatialReference(wkt=prj) - aea_srs = srs - - #Surface velocity - # add surface velocities where possible? - - print('\nStatic analysis does not work for quantifying uncertainty because clipped by RGI extents') - print('\nOpting to use UTM projections to avoid errors caused by projecting/resampling datasets\n') - -elif site in ['StElias', 'Chugach', 'AR_W', 'AR_C', 'AR_E', 'Coast', 'Kenai', 'AK_Pen']: - #Output directory - outdir = topdir + 'Berthier/output/' - outdir_fig = topdir + 'Berthier/output/figures/' - outdir_csv = topdir + 'Berthier/output/csv' - - glac_shp_fn = topdir + '../RGI/rgi60/01_rgi60_Alaska/01_rgi60_Alaska.shp' - glacfeat_fn = outdir + site + '_glacfeat_list.p' - - #ASTER+WV trend interp 2008 - z1_fn_dict = {'StElias': topdir + 'Berthier/Alaska_1950_2006/1.StElias/StElias_Map_DEM.tif', - 'Chugach': topdir + 'Berthier/Alaska_1950_2006/2.Chugach/Chugach_Map_DEM.tif', - 'AR_W': topdir + 'Berthier/Alaska_1950_2006/3.AR_W/AR_W_Map_DEM.tif', - 'AR_C': topdir + 'Berthier/Alaska_1950_2006/4.AR_C/AR_C_Map_DEM.tif', - 'AR_E': topdir + 'Berthier/Alaska_1950_2006/5.AR_E/AR_E_Map_DEM.tif', - 'Coast': topdir + 'Berthier/Alaska_1950_2006/6.Coast/Coast_Map_DEM.tif', - 'Kenai': topdir + 'Berthier/Alaska_1950_2006/7.Kenai/Kenai_Map_DEM.tif', - 'AK_Pen': topdir + 'Berthier/Alaska_1950_2006/8.AK_Peninsula/AK_Peninsula_Map_DEM.tif',} - z1_date_dict = {'StElias': 1968., - 'Chugach': 1954., - 'AR_W': 1953., - 'AR_C': 1953., - 'AR_E': 1953., - 'Coast': 1966., - 'Kenai': 1950., - 'AK_Pen': 1950.} - z2_fn_dict = {'StElias': topdir + 'Berthier/Alaska_1950_2006/1.StElias/StElias_Satellite_DEM.tif', - 'Chugach': topdir + 'Berthier/Alaska_1950_2006/2.Chugach/Chugach_Sat_DEM.tif', - 'AR_W': topdir + 'Berthier/Alaska_1950_2006/3.AR_W/AR_W_Sat_DEM.tif', - 'AR_C': topdir + 'Berthier/Alaska_1950_2006/4.AR_C/AR_C_Sat_DEM.tif', - 'AR_E': topdir + 'Berthier/Alaska_1950_2006/5.AR_E/AR_E_Sat_DEM.tif', - 'Coast': topdir + 'Berthier/Alaska_1950_2006/6.Coast/Coast_Sat_DEM.tif', - 'Kenai': topdir + 'Berthier/Alaska_1950_2006/7.Kenai/Kenai_Sat_DEM.tif', - 'AK_Pen': topdir + 'Berthier/Alaska_1950_2006/8.AK_Peninsula/AK_Peninsula_Sat_DEM.tif',} - z2_date_dict = {'StElias': 2006.75, - 'Chugach': 2006.75, - 'AR_W': 2004.75, - 'AR_C': 2004.75, - 'AR_E': 2004.75, - 'Coast': 2007.75, - 'Kenai': 2007.75, - 'AK_Pen': 2007.75} - - - # z1_fn = topdir + 'Berthier/Alaska_1950_2006/1.StElias/StElias_Map_DEM.tif' - z1_fn = z1_fn_dict[site] - z1_date = z1_date_dict[site] - z1_sigma = 10 - z1_srtm_penetration_corr = False - - #WV trend interp 2018 - # z2_fn = topdir + 'Berthier/Alaska_1950_2006/1.StElias/StElias_Satellite_DEM.tif' - z2_fn = z2_fn_dict[site] - z2_date = z2_date_dict[site] - z2_sigma = 10 - z2_srtm_penetration_corr = False - - #Output projection - #'+proj=aea +lat_1=25 +lat_2=47 +lat_0=36 +lon_0=85 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ' - # print('\n\nSHOULD CHANGE TO EQUAL AREA PROJECTION!\n\n') - # aea_srs = geolib.hma_aea_srs - ds = gdal.Open(z1_fn) - prj = ds.GetProjection() - srs = osr.SpatialReference(wkt=prj) - aea_srs = srs - - #Surface velocity - # add surface velocities where possible? - - print('\nStatic analysis does not work for quantifying uncertainty because glacier exceeded RGI extents in 1950s') - print('\nOpting to use UTM projections to avoid errors caused by projecting/resampling datasets\n') - -elif site == 'hma': - glac_shp_fn = os.path.join(topdir,'data/rgi60/regions/rgi60_merge_HMA_aea.shp') - #glac_shp_fn = '/nobackupp8/deshean/hma/aster/dsm/aster_align_index_2000-2018_aea_stack/mb_test/rgi_ngozumpa.shp' - glacfeat_fn = os.path.splitext(glac_shp_fn)[0]+'_glacfeat_list.p' - - #ASTER+WV trend interp 2008 - z1_fn = '/nobackupp8/deshean/hma/combined_aster_wv/dem_align_ASTER_WV_index_2000-2018_aea_stack/dem_align_ASTER_WV_index_2000-2018_aea_20000531_mos_retile.vrt' - z1_date = 2000.412 - z1_sigma = 4.0 - z1_srtm_penetration_corr = False - - #WV trend interp 2018 - z2_fn = '/nobackupp8/deshean/hma/combined_aster_wv/dem_align_ASTER_WV_index_2000-2018_aea_stack/dem_align_ASTER_WV_index_2000-2018_aea_20180531_mos_retile.vrt' - z2_date = 2018.412 - z2_sigma = 4.0 - z2_srtm_penetration_corr = False - - #Output directory - outdir = os.path.join(os.path.split(z2_fn)[0], 'mb_combined_20190206') - outdir_fig = outdir - outdir_csv = outdir - #outdir = '/nobackup/deshean/hma/aster/dsm/aster_align_index_2000-2018_aea_stack/mb' - - #Output projection - #'+proj=aea +lat_1=25 +lat_2=47 +lat_0=36 +lon_0=85 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ' - aea_srs = geolib.hma_aea_srs - - #Surface velocity - #Note: had to force srs on Amaury's original products - #gdal_edit.py -a_srs '+proj=lcc +lat_1=28 +lat_2=32 +lat_0=90 +lon_0=85 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs' fn - #v_dir = '/nobackup/deshean/rpcdem/hma/velocity_jpl_amaury_2013-2015' - v_dir = '/nobackup/deshean/data/jpl_vel' - vx_fn = os.path.join(v_dir, 'HMA_G0240_0000_vx_masked.tif') - vy_fn = os.path.join(v_dir, 'HMA_G0240_0000_vy_masked.tif') - -else: - sys.exit("Must specify input site") - -if not os.path.exists(outdir): - os.makedirs(outdir) -if not os.path.exists(outdir_fig): - os.makedirs(outdir_fig) -if not os.path.exists(outdir_csv): - os.makedirs(outdir_csv) - -ts = datetime.now().strftime('%Y%m%d_%H%M') -out_fn = '%s_mb_%s.csv' % (site, ts) -out_fn = os.path.join(outdir, out_fn) - -#List to hold output -out = [] - -if 'rgi' in glac_shp_fn: - #Use RGI - glacname_fieldname = "Name" - #RGIId (String) = RGI50-01.00004 - glacnum_fieldname = "RGIId" - glacnum_fmt = '%08.5f' -else: - sys.exit('Unrecognized glacier shp filename') - -#Set up output header -#out_header = '%s,x,y,z_med,z_min,z_max,z_p16,z_p84,z_slope,z_aspect,dhdt_ma,dhdt_ma_sigma,mb_mwea,mb_mwea_sigma,area_m2,mb_m3wea,mb_m3wea_sigma,t1,t2,dt,valid_area_perc' % glacnum_fieldname -out_header = '%s,x,y,z_med,z_min,z_max,z_slope,z_aspect,dhdt_ma,dhdt_ma_sigma,mb_mwea,mb_mwea_sigma,area_m2,mb_m3wea,mb_m3wea_sigma,t1,t2,dt,valid_area_perc' % glacnum_fieldname -if extra_layers: - out_header += ',H_m' - if site == 'hma': - out_header += ',debris_m,perc_debris,perc_pond,perc_clean' - out_header += ',vm_ma' - -nf = len(out_header.split(',')) -out_fmt = [glacnum_fmt,] + ['%0.3f'] * (nf - 1) - - -# Shape layer processing -glac_shp_init = gpd.read_file(glac_shp_fn) -if verbose: - print('Shp init crs:', glac_shp_init.crs) -# ax = glac_shp_wgs84.plot() -# ax.set_title("WGS84 (lat/lon)" - -# If projected shapefile already exists, then skip projection -glac_shp_proj_fn = (outdir + glac_shp_fn.split('/')[-1].replace('.shp','_crs' + - str(aea_srs.GetAttrValue("AUTHORITY", 1)) + '.shp')) -if os.path.exists(glac_shp_proj_fn) == False: - glac_shp_proj = glac_shp_init.to_crs({'init': 'epsg:' + str(aea_srs.GetAttrValue("AUTHORITY", 1))}) - glac_shp_proj.to_file(glac_shp_proj_fn) - -glac_shp_ds = ogr.Open(glac_shp_proj_fn, 0) -glac_shp_lyr = glac_shp_ds.GetLayer() -#This should be contained in features -glac_shp_srs = glac_shp_lyr.GetSpatialRef() -feat_count = glac_shp_lyr.GetFeatureCount() -print("Input glacier polygon count: %i" % feat_count) - -z1_ds = gdal.Open(z1_fn) -z2_ds = gdal.Open(z2_fn) -dz_int_geom = geolib.ds_geom_intersection([z1_ds, z2_ds], t_srs=glac_shp_srs) - -#Spatial filter -glac_shp_lyr.SetSpatialFilter(dz_int_geom) -feat_count = glac_shp_lyr.GetFeatureCount() -print("Glacier polygon count after spatial filter: %i" % feat_count) -glac_shp_lyr.ResetReading() - -#Area filter -glac_shp_lyr.SetAttributeFilter("Area > %s" % min_glac_area) -feat_count = glac_shp_lyr.GetFeatureCount() -print("Min. Area filter glacier polygon count: %i" % feat_count) -glac_shp_lyr.ResetReading() - -print("Processing %i features" % feat_count) - -#Set higher stripe count so we're not thrashing one disk -#cmd = ['lfs', 'setstripe', '-c', str(nproc), outdir] -#subprocess.call(cmd) -# iolib.setstripe(outdir, nproc) # REMOVED THIS BECAUSE IT WAS CAUSING subprocess error - likely for spc? - -#Create a list of glacfeat objects (contains geom) - safe for multiprocessing, while OGR layer is not -if os.path.exists(glacfeat_fn) and use_existing_glacfeat: - print("Loading %s" % glacfeat_fn) - #This fails to load geometry srs - glacfeat_list = pickle.load(open(glacfeat_fn,"rb")) -else: - glacfeat_list = [] - print("Generating %s" % glacfeat_fn) - for n, feat in enumerate(glac_shp_lyr): - gf = GlacFeat(feat, glacname_fieldname, glacnum_fieldname) - print("%i of %i: %s" % (n+1, feat_count, gf.feat_fn)) - #Calculate area, extent, centroid - #NOTE: Input must be in projected coordinate system, ideally equal area - #Should check this and reproject - gf.geom_attributes(srs=aea_srs) - glacfeat_list.append(gf) - pickle.dump(glacfeat_list, open(glacfeat_fn,"wb")) - -glac_shp_lyr = None -glac_shp_ds = None - -def mb_calc(gf, z1_date=z1_date, z2_date=z2_date, verbose=verbose): - #print("\n%i of %i: %s\n" % (n+1, len(glacfeat_list), gf.feat_fn)) - print(gf.feat_fn) - - out_csv_fn = os.path.join(outdir_csv, gf.feat_fn+'_mb.csv') - if verbose: - print('output_fn:', out_csv_fn) - if not os.path.exists(out_csv_fn): - #This should already be handled by earlier attribute filter, but RGI area could be wrong - if gf.glac_area_km2 < min_glac_area: - if verbose: - print("Glacier area of %0.1f is below %0.1f km2 threshold" % (gf.glac_area_km2, min_glac_area)) - return None - - fn_dict = OrderedDict() - #We at least want to warp the two input DEMs - fn_dict['z1'] = z1_fn - fn_dict['z2'] = z2_fn - - if extra_layers and (gf.glac_area_km2 > min_glac_area_writeout): - #Attempt to load Huss ice thickness grid - huss_dir = os.path.join(topdir, 'data/huss') - ice_thick_fn = os.path.join(huss_dir, 'RGI%02i_thick/thickness/thick_%05i.agr' % \ - tuple(map(int, gf.glacnum.split('.')))) - if os.path.exists(ice_thick_fn): - fn_dict['ice_thick'] = ice_thick_fn - - if site == 'hma': - #Add debris cover datasets - #Should tar these up, and extract only necessary file - #Downloaded from: http://mountainhydrology.org/data-nature-2017/ - kra_nature_dir = '/nobackup/deshean/data/Kraaijenbrink_hma/regions/out' - #This assumes that numbers are identical between RGI50 and RGI60 - debris_class_fn = os.path.join(kra_nature_dir, 'RGI50-%s/classification.tif' % gf.glacnum) - debris_thick_fn = os.path.join(kra_nature_dir, 'RGI50-%s/debris-thickness-50cm.tif' % gf.glacnum) - #ice_thick_fn = os.path.join(kra_nature_dir, 'RGI50-%s/ice-thickness.tif' % gf.glacnum) - if os.path.exists(debris_class_fn): - fn_dict['debris_class'] = debris_class_fn - if os.path.exists(debris_thick_fn): - fn_dict['debris_thick'] = debris_thick_fn - if os.path.exists(vx_fn): - fn_dict['vx'] = vx_fn - fn_dict['vy'] = vy_fn - - if z1_date is None: - #Rasterize source dates - #Note: need to clean this up, as glac_geom_mask is not defined - if os.path.splitext(z1_date_fn)[1] == 'shp': - z1_date = get_date_a(ds_dict['z1'], z1_date_shp_lyr, glac_geom_mask, z1_datefield) - gf.t1 = z1_date.mean() - else: - #Otherwise, clip the timestamp array - fn_dict['z1_date'] = z1_date_fn - else: - gf.t1 = z1_date - - if z2_date is None: - if os.path.splitext(z2_date_fn)[1] == 'shp': - z2_date = get_date_a(ds_dict['z2'], z2_date_shp_lyr, glac_geom_mask, z2_datefield) - gf.t1 = z2_date.mean() - else: - fn_dict['z2_date'] = z2_date_fn - else: - gf.t2 = z2_date - - #Expand extent to include buffered region around glacier polygon - warp_extent = geolib.pad_extent(gf.glac_geom_extent, width=buff_dist) - if verbose: - print("Expanding extent") - print(gf.glac_geom_extent) - print(warp_extent) - - #Warp everything to common res/extent/proj - ds_list = warplib.memwarp_multi_fn(fn_dict.values(), res='min', \ - extent=warp_extent, t_srs=aea_srs, verbose=verbose, \ - r='cubic') - - ds_dict = dict(zip(fn_dict.keys(), ds_list)) - - #Prepare mask for all glaciers within buffered area, not just the current glacier polygon - glac_shp_ds = ogr.Open(glac_shp_proj_fn, 0) - glac_shp_lyr = glac_shp_ds.GetLayer() - #Spatial filter - #glac_shp_lyr.SetSpatialFilter(geom) - - #Get global glacier mask - #Want this to be True over ALL glacier surfaces, not just the current polygon - glac_shp_lyr_mask = geolib.lyr2mask(glac_shp_lyr, ds_dict['z1']) - - #geom srs is not preserved when loaded from disk, attempt to reassign - gf.geom_srs_update() - #Create buffer around glacier polygon - glac_geom_buff = gf.glac_geom.Buffer(buff_dist) - #This is False over glacier polygon surface, True elsewhere - can be applied directly - glac_geom_buff_mask = geolib.geom2mask(glac_geom_buff, ds_dict['z1']) - - # DEM masks - ds_list_masked = [iolib.ds_getma(i) for i in ds_list] - dem1 = np.ma.masked_less_equal(ds_list_masked[0], 0) - dem2 = np.ma.masked_less_equal(ds_list_masked[1], 0) - dems_mask = np.ma.mask_or(dem1.mask, dem2.mask) - # dem1 = ds_list_masked[0] - # dem1 = np.ma.masked_less_equal(dem1, 0) - # dem2 = ds_list_masked[1] - # dem2 = np.ma.masked_less_equal(dem2, 0) - # dems_mask = np.ma.mask_or(dem1.mask, dem2.mask - - #Combine to identify ~1 km buffer around glacier polygon over static rock - static_buffer_mask = np.ma.mask_or(~glac_shp_lyr_mask, glac_geom_buff_mask) - static_shp_lyr_mask = np.ma.mask_or(static_buffer_mask, dems_mask) - - - if 'z1' in ds_dict: - #This is False over glacier polygon surface, True elsewhere - can be applied directly - glac_geom_mask = geolib.geom2mask(gf.glac_geom, ds_dict['z1']) - gf.z1 = np.ma.array(iolib.ds_getma(ds_dict['z1'])) - #gf.z1 = np.ma.array(iolib.ds_getma(ds_dict['z1']), mask=glac_geom_mask) - if gf.z1.count() == 0: - if verbose: - print("No z1 pixels") - return None - else: - print("Unable to load z1 ds") - return None - - if 'z2' in ds_dict: - gf.z2 = iolib.ds_getma(ds_dict['z2']) - if gf.z2.count() == 0: - if verbose: - print("No z2 pixels") - return None - else: - print("Unable to load z2 ds") - return None - - #Apply SRTM penetration correction - #Do this only over glaciers, not static rock? - if z1_srtm_penetration_corr: - gf.z1 = srtm_corr(gf.z1) - if z2_srtm_penetration_corr: - gf.z2 = srtm_corr(gf.z2) - #gf.z2 = np.ma.array(gf.z2, mask=glac_geom_mask) - gf.dz = gf.z2 - gf.z1 - if gf.dz.count() == 0: - if verbose: - print("No valid dz pixels") - return None - - #Should add better filtering here - #Elevation dependent abs. threshold filter? - - filter_outliers = False - #Remove clearly bogus pixels - if filter_outliers: - bad_perc = (0.1, 99.9) - #bad_perc = (1, 99) - rangelim = malib.calcperc(gf.dz, bad_perc) - gf.dz = np.ma.masked_outside(gf.dz, *rangelim) - - #Preserve full dz map - gf.dz_full = gf.dz - - #Compute stats for "static" surfaces (non-glacier) - gf.dz_static = np.ma.array(gf.dz, mask=static_shp_lyr_mask) - gf.dz_static_stats = malib.get_stats(gf.dz_static) - - #Should isolate slopes similar to glacier surface slopes - - #Now apply glacier mask (and account for gaps in DEMs) - glac_geom_mask = np.ma.mask_or(glac_geom_mask, dems_mask) - nan_mask = np.ma.masked_invalid(gf.dz) - glac_geom_mask = np.ma.mask_or(glac_geom_mask, nan_mask.mask) - gf.z1 = np.ma.array(gf.z1, mask=glac_geom_mask) - gf.z2 = np.ma.array(gf.z2, mask=glac_geom_mask) - gf.dz = np.ma.array(gf.dz, mask=glac_geom_mask) - - gf.res = geolib.get_res(ds_dict['z1']) - #Compute area covered by valid pixels in m2 - gf.valid_area = gf.dz.count() * gf.res[0] * gf.res[1] - #Compute percentage covered by total area of polygon - gf.valid_area_perc = 100. * (gf.valid_area / gf.glac_area) - if verbose: - print('valid area %:', np.round(gf.valid_area_perc,1)) - if gf.valid_area_perc < (100. * min_valid_area_perc): - if verbose: - print("Not enough valid pixels. %0.1f%% percent of glacier polygon area" % (gf.valid_area_perc)) - return None - - else: - #Filter dz - throw out abs differences >150 m - - #Compute dz, volume change, mass balance and stats - gf.z1_stats = malib.get_stats(gf.z1) - gf.z2_stats = malib.get_stats(gf.z2) - - #Should probably take mean of z1 and z2 here - #For cases where WV/GE is z2, maybe best to take - z2_elev_med = gf.z2_stats[5] - #z2_elev_min = gf.z2_stats[1] - #z2_elev_max = gf.z2_stats[2] - z2_elev_min, z2_elev_max = malib.calcperc(gf.z2, (0.1, 99.9)) - #z2_elev_p16 = gf.z2_stats[11] - #z2_elev_p84 = gf.z2_stats[12] - - #Caluclate stats for aspect and slope using z2 - #Requires GDAL 2.1+ - gf.z2_aspect = np.ma.array(geolib.gdaldem_mem_ds(ds_dict['z2'], processing='aspect', returnma=True), mask=glac_geom_mask) - gf.z2_aspect_stats = malib.get_stats(gf.z2_aspect) - z2_aspect_med = gf.z2_aspect_stats[5] - gf.z2_slope = np.ma.array(geolib.gdaldem_mem_ds(ds_dict['z2'], processing='slope', returnma=True), mask=glac_geom_mask) - gf.z2_slope_stats = malib.get_stats(gf.z2_slope) - z2_slope_med = gf.z2_slope_stats[5] - - #Load timestamp array, if available - if 'z1_date' in ds_dict: - gf.t1 = iolib.ds_getma(ds_dict['z1_date']) - else: - if isinstance(gf.t1, datetime): - gf.t1 = float(timelib.dt2decyear(gf.t1)) - #else, assume we've hardcoded decimal year - gf.t1_mean = np.mean(gf.t1) - - if 'z2_date' in ds_dict: - gf.t2 = iolib.ds_getma(ds_dict['z2_date']) - else: - if isinstance(gf.t2, datetime): - gf.t2 = float(timelib.dt2decyear(gf.t2)) - #else, assume we've hardcoded decimal year - gf.t2_mean = np.mean(gf.t2) - - #These should be decimal years, either grids or constants - gf.dt = gf.t2 - gf.t1 - gf.dt_mean = np.mean(gf.dt) - #if isinstance(gf.dt, timedelta): - # gf.dt = gf.dt.total_seconds()/timelib.spy - - #Calculate dh/dt, in m/yr - gf.dhdt = gf.dz/gf.dt - gf.dhdt_sum = gf.dhdt.sum() - gf.dhdt_stats = malib.get_stats_dict(gf.dhdt) - gf.dhdt_mean = gf.dhdt_stats['mean'] - gf.dhdt_med = gf.dhdt_stats['med'] - gf.dhdt_nmad = gf.dhdt_stats['nmad'] - - gf.dhdt_static = gf.dz_static/gf.dt - gf.dhdt_static_stats = malib.get_stats_dict(gf.dhdt_static) - gf.dhdt_static_mean = gf.dhdt_static_stats['mean'] - gf.dhdt_static_med = gf.dhdt_static_stats['med'] - gf.dhdt_static_nmad = gf.dhdt_static_stats['nmad'] - - #Can estimate ELA values computed from hypsometry and typical AAR - #For now, assume ELA is mean - gf.z1_ela = None - gf.z1_ela = gf.z1_stats[3] - gf.z2_ela = gf.z2_stats[3] - #Note: in theory, the ELA should get higher with mass loss - #In practice, using mean and same polygon, ELA gets lower as glacier surface thins - if verbose: - print("ELA(t1): %0.1f" % gf.z1_ela) - print("ELA(t2): %0.1f" % gf.z2_ela) - - if gf.z1_ela > gf.z2_ela: - min_ela = gf.z2_ela - max_ela = gf.z1_ela - else: - min_ela = gf.z1_ela - max_ela = gf.z2_ela - - #Calculate uncertainty of total elevation change - #decorrelation length - L = 500 - Acor = np.pi*L**2 - if gf.glac_area > Acor: - #Correction factor for sample size area - Acorf = np.sqrt(Acor/(5*gf.glac_area)) - else: - Acorf = 1.0 - - #Std or NMAD of elevation change on stable ground, assuming we know a priori uncertainty for z1 and z2 - #dz_sigma = np.sqrt(z1_sigma**2 + z2_sigma**2) - #dhdt_sigma = dz_sigma/gf.dt - - #This is NMAD of static pixels within buffer - dhdt_sigma = gf.dhdt_static_nmad - #Uncertainty of dh/dt - gf.dhdt_sigma = Acorf * (dhdt_sigma) - - #This is percentage of valid pixels, 0-1 - #p = min(gf.valid_area_perc/100., 1.0) - #From Brun et al, multiply uncertainty for nodata by 5x - #p_factor = (p + 5*(1-p)) - p_factor = 1.0 - - #Calculate volume change (m3/a) - gf.dv = gf.dhdt_mean * gf.glac_area - #gf.dv = gf.dhdt_med * gf.glac_area - gf.dv_sum = gf.dhdt_sum*gf.res[0]*gf.res[1] - #print(gf.dv, gf.dv_sum, (gf.dv - gf.dv_sum)) - - #Volume change uncertainty (m3/a) - gf.dv_sigma = np.sqrt((gf.dhdt_sigma*p_factor*gf.glac_area)**2 + (area_sigma_perc * gf.glac_area)**2) - - #Mass balance in mwe/a for each pixel - gf.mb_map = gf.dhdt * rho_is - gf.mb_map_sum = gf.mb_map.sum() - gf.mb_map_stats = malib.get_stats_dict(gf.mb_map) - gf.mb_map_sigma = np.ma.abs(gf.mb_map) * np.sqrt((rho_sigma/rho_is)**2 + (gf.dhdt_sigma/gf.dhdt)**2) - gf.mb_map_sigma_stats = malib.get_stats_dict(gf.mb_map_sigma) - - #This is estimate for polygon mb in mwea - gf.mb_mean = gf.mb_map_stats['mean'] - #This is average mb uncertainty, does not include area uncertainty - gf.mb_mean_sigma = gf.mb_map_sigma_stats['mean'] - gf.mb_med = gf.mb_map_stats['med'] - gf.mb_med_sigma = gf.mb_map_sigma_stats['med'] - - #Total mass balance for polygon in m3wea - #previously gf.mb_mean_totalarea - gf.mb_total = gf.dv * rho_is - gf.mb_total_sigma = np.sqrt((gf.dv_sigma*rho_is)**2 + (rho_sigma*gf.dv)**2) - - """ - # This attempted to assign different densities above and below ELA - if gf.z1_ela is None: - gf.mb = gf.dhdt * rho_is - else: - #Initiate with average density - gf.mb = gf.dhdt*(rho_is + rho_f)/2. - #Everything that is above ELA at t2 is elevation change over firn, use firn density - accum_mask = (gf.z2 > gf.z2_ela).filled(0).astype(bool) - gf.mb[accum_mask] = (gf.dhdt*rho_f)[accum_mask] - #Everything that is below ELA at t1 is elevation change over ice, use ice density - abl_mask = (gf.z1 <= gf.z1_ela).filled(0).astype(bool) - gf.mb[abl_mask] = (gf.dhdt*rho_is)[abl_mask] - #Everything in between, use average of ice and firn density - #mb[(z1 > z1_ela) || (z2 <= z2_ela)] = dhdt*(rhois + rho_f)/2. - #Linear ramp - #rho_f + z2*((rho_is - rho_f)/(z2_ela - z1_ela)) - #mb = np.where(dhdt < ela, dhdt*rho_i, dhdt*rho_s) - """ - - #Old approach - #This is mb uncertainty map - #gf.mb_sigma = np.ma.abs(gf.mb) * np.sqrt((rho_sigma/rho_is)**2 + (gf.dhdt_sigma/gf.dhdt)**2) - #gf.mb_sigma_stats = malib.get_stats(gf.mb_sigma) - #This is average mb uncertainty - #gf.mb_mean_sigma = gf.mb_sigma_stats[3] - - #Now calculate mb for entire polygon - #gf.mb_mean_totalarea = gf.mb_mean * gf.glac_area - #Already have area uncertainty as percentage, just use directly - #gf.mb_mean_totalarea_sigma = np.ma.abs(gf.mb_mean_totalarea) * np.sqrt((gf.mb_mean_sigma/gf.mb_mean)**2 + area_sigma_perc**2) - - #z2_elev_med, z2_elev_min, z2_elev_max, z2_elev_p16, z2_elev_p84, \ - outlist = [gf.glacnum, gf.cx, gf.cy, \ - z2_elev_med, z2_elev_min, z2_elev_max, \ - z2_slope_med, z2_aspect_med, \ - gf.dhdt_mean, gf.dhdt_sigma, \ - gf.mb_mean, gf.mb_mean_sigma, \ - gf.glac_area, gf.mb_total, gf.mb_total_sigma, \ - gf.t1_mean, gf.t2_mean, gf.dt_mean, gf.valid_area_perc] - - if extra_layers and (gf.glac_area_km2 > min_glac_area_writeout): - if 'ice_thick' in ds_dict: - #Load ice thickness - gf.H = np.ma.array(iolib.ds_getma(ds_dict['ice_thick']), mask=glac_geom_mask) - gf.H_mean = gf.H.mean() - #These should be NaN or None - outlist.append(gf.H_mean) - - if 'debris_thick' in ds_dict: - gf.debris_thick = np.ma.array(iolib.ds_getma(ds_dict['debris_thick']), mask=glac_geom_mask) - gf.debris_thick_mean = gf.debris_thick.mean() - outlist.append(gf.debris_thick_mean) - - if 'debris_class' in ds_dict: - #Load up debris cover maps - #Classes are: 1 = clean ice, 2 = debris, 3 = pond - gf.debris_class = np.ma.array(iolib.ds_getma(ds_dict['debris_class']), mask=glac_geom_mask) - - #Compute debris/pond/clean percentages for entire polygon - if gf.debris_class.count() > 0: - gf.perc_clean = 100. * (gf.debris_class == 1).sum()/gf.debris_class.count() - gf.perc_debris = 100. * (gf.debris_class == 2).sum()/gf.debris_class.count() - gf.perc_pond = 100. * (gf.debris_class == 3).sum()/gf.debris_class.count() - outlist.extend([gf.perc_debris, gf.perc_pond, gf.perc_clean]) - - if 'vx' in ds_dict and 'vy' in ds_dict: - #Load surface velocity maps - gf.vx = np.ma.array(iolib.ds_getma(ds_dict['vx']), mask=glac_geom_mask) - gf.vy = np.ma.array(iolib.ds_getma(ds_dict['vy']), mask=glac_geom_mask) - gf.vm = np.ma.sqrt(gf.vx**2 + gf.vy**2) - gf.vm_mean = gf.vm.mean() - - if gf.H is not None: - #Compute flux - gf.Q = gf.H * v_col_f * np.array([gf.vx, gf.vy]) - #Note: np.gradient returns derivatives relative to axis number, so (y, x) in this case - #Want x-derivative of x component - gf.divQ = np.gradient(gf.Q[0])[1] + np.gradient(gf.Q[1])[0] - - #gf.divQ = gf.H*(np.gradient(v_col_f*gf.vx)[1] + np.gradient(v_col_f*gf.vy)[0]) \ - #+ v_col_f*gf.vx*(np.gradient(gf.H)[1]) + v_col_f*gf.vy*(np.gradient(gf.H)[0]) - - #Should smooth divQ, better handling of data gaps - outlist.append(gf.vm_mean) - - if verbose: - print('Area [km2]:', gf.glac_area / 1e6) - print('Mean mb: %0.2f +/- %0.2f mwe/yr' % (gf.mb_mean, gf.mb_mean_sigma)) - print('Sum/Area mb: %0.2f mwe/yr' % (gf.mb_total/gf.glac_area)) - print('Mean mb * Area: %0.2f +/- %0.2f m3we/yr' % (gf.mb_total, gf.mb_total_sigma)) - # print('Sum mb: %0.2f m3we/yr' % gf.mb_total) - print('-------------------------------') - - #Write out mb stats for entire polygon - in case processing is interupted - #out = np.array(outlist, dtype=float) - out = np.full(len(out_fmt), np.nan) - out[0:len(outlist)] = np.array(outlist, dtype=float) - #Note, need a 2D array here, add 0 axis - np.savetxt(out_csv_fn, out[np.newaxis,:], fmt=out_fmt, delimiter=',', header=out_header, comments='') - - # if writeout and (gf.glac_area_km2 > min_glac_area_writeout): - # out_dz_fn = os.path.join(outdir, gf.feat_fn+'_dz.tif') - # iolib.writeGTiff(gf.dz, out_dz_fn, ds_dict['z1']) - # - # out_dz_static_fn = os.path.join(outdir, gf.feat_fn+'_dz_static.tif') - # iolib.writeGTiff(gf.dz_static, out_dz_static_fn, ds_dict['z1']) - # - # if isinstance(gf.dt, np.ndarray): - # out_dt_fn = os.path.join(outdir, gf.feat_fn+'_dt.tif') - # iolib.writeGTiff(gf.dt, out_dt_fn, ds_dict['z1']) - # - # out_z1_fn = os.path.join(outdir, gf.feat_fn+'_z1.tif') - # iolib.writeGTiff(gf.z1, out_z1_fn, ds_dict['z1']) - # - # out_z2_fn = os.path.join(outdir, gf.feat_fn+'_z2.tif') - # iolib.writeGTiff(gf.z2, out_z2_fn, ds_dict['z1']) - # - # temp_fn = os.path.join(outdir, gf.feat_fn+'_z2_aspect.tif') - # iolib.writeGTiff(gf.z2_aspect, temp_fn, ds_dict['z1']) - # - # temp_fn = os.path.join(outdir, gf.feat_fn+'_z2_slope.tif') - # iolib.writeGTiff(gf.z2_slope, temp_fn, ds_dict['z1']) - # - # #Need to fix this - write out constant date arrays regardless of source - # #out_z1_date_fn = os.path.join(outdir, gf.feat_fn+'_ned_date.tif') - # #iolib.writeGTiff(z1_date, out_z1_date_fn, ds_dict['z1']) - # - # if extra_layers: - # if gf.ppt_annual is not None: - # temp_fn = os.path.join(outdir, gf.feat_fn+'_ppt_annual.tif') - # iolib.writeGTiff(gf.ppt_annual, temp_fn, ds_dict['z1']) - # if gf.tmean_annual is not None: - # temp_fn = os.path.join(outdir, gf.feat_fn+'_tmean_annual.tif') - # iolib.writeGTiff(gf.tmean_annual, temp_fn, ds_dict['z1']) - # if gf.ppt_summer is not None: - # temp_fn = os.path.join(outdir, gf.feat_fn+'_ppt_summer.tif') - # iolib.writeGTiff(gf.ppt_summer, temp_fn, ds_dict['z1']) - # if gf.tmean_summer is not None: - # temp_fn = os.path.join(outdir, gf.feat_fn+'_tmean_summer.tif') - # iolib.writeGTiff(gf.tmean_summer, temp_fn, ds_dict['z1']) - # if gf.ppt_winter is not None: - # temp_fn = os.path.join(outdir, gf.feat_fn+'_ppt_winter.tif') - # iolib.writeGTiff(gf.ppt_winter, temp_fn, ds_dict['z1']) - # if gf.tmean_winter is not None: - # temp_fn = os.path.join(outdir, gf.feat_fn+'_tmean_winter.tif') - # iolib.writeGTiff(gf.tmean_winter, temp_fn, ds_dict['z1']) - # - # if gf.debris_thick is not None: - # temp_fn = os.path.join(outdir, gf.feat_fn+'_debris_thick.tif') - # iolib.writeGTiff(gf.debris_thick, temp_fn, ds_dict['z1']) - # if gf.debris_class is not None: - # temp_fn = os.path.join(outdir, gf.feat_fn+'_debris_class.tif') - # iolib.writeGTiff(gf.debris_class, temp_fn, ds_dict['z1']) - # - # if gf.H is not None: - # temp_fn = os.path.join(outdir, gf.feat_fn+'_H.tif') - # iolib.writeGTiff(gf.H, temp_fn, ds_dict['z1']) - # if gf.vm is not None: - # temp_fn = os.path.join(outdir, gf.feat_fn+'_vx.tif') - # iolib.writeGTiff(gf.vx, temp_fn, ds_dict['z1']) - # temp_fn = os.path.join(outdir, gf.feat_fn+'_vy.tif') - # iolib.writeGTiff(gf.vy, temp_fn, ds_dict['z1']) - # temp_fn = os.path.join(outdir, gf.feat_fn+'_vm.tif') - # iolib.writeGTiff(gf.vm, temp_fn, ds_dict['z1']) - # if gf.divQ is not None: - # temp_fn = os.path.join(outdir, gf.feat_fn+'_divQ.tif') - # iolib.writeGTiff(gf.divQ, temp_fn, ds_dict['z1']) - - #Do AED for all - #Compute mb using scaled AED vs. polygon - #Check for valid pixel count vs. feature area, fill if appropriate - - if mb_plot and (gf.glac_area_km2 > min_glac_area_writeout): - dz_clim = (-2.0, 2.0) - if site == 'hma': - dz_clim = (-3.0, 3.0) - z_bin_edges = hist_plot(gf, outdir, bin_width=bin_width, dz_clim=dz_clim) - gf.z1_hs = geolib.gdaldem_mem_ds(ds_dict['z1'], processing='hillshade', returnma=True) - gf.z2_hs = geolib.gdaldem_mem_ds(ds_dict['z2'], processing='hillshade', returnma=True) - map_plot(gf, z_bin_edges, outdir, dz_clim=dz_clim) - - #Write out the populated glacfeat objects (contain raster grids, stats, etc) - #Should compress with gzip module - #glacfeat_fn_out = os.path.join(outdir, gf.feat_fn+'_gf.p') - #pickle.dump(glacfeat_list_out, open(glacfeat_fn_out,"wb")) - - else: - #Shortcut to load existing output if run was interrupted - outlist = np.loadtxt(out_csv_fn, delimiter=',', skiprows=1).tolist() - - gf = None - #return outlist, gf - return outlist - -# For testing -# glacfeat_list_in = [glacfeat_list[240]] -# glacfeat_list_in = glacfeat_list[0:2] -glacfeat_list_in = glacfeat_list - -#This is a hack to limit processing for just a few glaciers -glac_dict = None -#Ngozumpa, Khumbu etc -#glac_dict = ['15.03474', '15.03733', '15.10070', '15.09991'] - -if glac_dict: - glacfeat_list_in = [] - for i in glacfeat_list: - if i.glacnum in glac_dict: - glacfeat_list_in.append(i) - -#List to store output glacfeat objects -#This can consume huge amounts of memory -#Should save individually -#glacfeat_list_out = [] - -if parallel: - print("Running in parallel with %i processes" % nproc) - from multiprocessing import Pool - # By default, use all cores - 1 - p = Pool(nproc) - - """ - # Simple mapping - # No progress bar - #out = p.map(mb_calc, glacfeat_list_in) - """ - - """ - # Using imap_unordered - apparently slower than map_async - results = p.imap_unordered(mb_calc, glacfeat_list_in, 1) - p.close() - import time - while True: - ndone = results._index - if ndone == len(glacfeat_list_in): break - print('%i of %i done' % (ndone, len(glacfeat_list_in))) - time.sleep(1) - #sys.stderr.write('%i of %i done' % (i, len(glacfeat_list))) - out = [j for j in results] - """ - - # Using map_async - results = p.map_async(mb_calc, glacfeat_list_in, 1) - p.close() - import time - while True: - if results.ready(): break - ndone = len(glacfeat_list_in) - results._number_left - print('%i of %i done' % (ndone, len(glacfeat_list_in))) - time.sleep(2) - out = results.get() -else: - print("Running serially") - for n, gf in enumerate(glacfeat_list_in): - print('%i of %i: %s' % (n+1, len(glacfeat_list_in), gf.feat_fn)) - out.append(mb_calc(gf)) - -mb_list = [] -for i in out: - if i is not None: - mb_list.append(i) - #mb_list.append(i[0]) - #glacfeat_list_out.append(i[1]) - -# import ipdb; ipdb.set_trace() -out = np.array(mb_list, dtype=float) - -#Sort by area -if len(out) > 0: - out = out[out[:,3].argsort()[::-1]] - - #Can also just load up all individual mb.csv files and compile, rather than trying to - - print("Saving output csv: %s" % out_fn) - np.savetxt(out_fn, out, fmt=out_fmt, delimiter=',', header=out_header, comments='') diff --git a/spc_postprocess_output.sh b/spc_postprocess_output.sh index 5e17393c..839d73a6 100644 --- a/spc_postprocess_output.sh +++ b/spc_postprocess_output.sh @@ -1,5 +1,5 @@ #!/bin/sh -#SBATCH --partition=t1small +#SBATCH --partition=debug #SBATCH --ntasks=24 #SBATCH --tasks-per-node=24 @@ -22,7 +22,15 @@ GCM_NAMES_LST="$(< $GCM_NAMES_FP$GCM_NAMES_FN)" module load lang/Anaconda3/2.5.0 source activate pygem_hpc +for GCM_NAME in $GCM_NAMES_LST; do + GCM_NAME_NOSPACE="$(echo -e "${GCM_NAME}" | tr -d '[:space:]')" + echo -e "\n$GCM_NAME" + # run the file on a separate node (& tells the command to move to the next loop for any empty nodes) + srun -N 1 -n 1 python run_postprocessing.py -gcm_name="$GCM_NAME_NOSPACE" -merge_batches=$MERGE_SWITCH +done +wait +echo -e "\nMerge finished" for GCM_NAME in $GCM_NAMES_LST; do GCM_NAME_NOSPACE="$(echo -e "${GCM_NAME}" | tr -d '[:space:]')" diff --git a/spc_run_calibration.sh b/spc_run_calibration.sh index b6cfa36f..cff32b77 100644 --- a/spc_run_calibration.sh +++ b/spc_run_calibration.sh @@ -11,7 +11,7 @@ REGNO="15" ADD_CAL_SWITCH=1 # split glaciers into batches for different nodes -python spc_split_glaciers.py -n_batches=$SLURM_JOB_NUM_NODES -add_cal=$ADD_CAL_SWITCH +python spc_split_glaciers.py -n_batches=$SLURM_JOB_NUM_NODES -spc_region=$REGNO -add_cal=$ADD_CAL_SWITCH # list rgi_glac_number batch filenames CHECK_STR="Cal_R${REGNO}_rgi_glac_number_batch" @@ -25,7 +25,7 @@ echo partition: $SLURM_JOB_PARTITION echo num_nodes: $SLURM_JOB_NUM_NODES nodes: $SLURM_JOB_NODELIST echo num_tasks: $SLURM_NTASKS tasks_node: $SLURM_NTASKS_PER_NODE -for i in $rgi_fns +for i in $rgi_fns do # print the filename echo $i @@ -33,4 +33,4 @@ do srun -N 1 -n 1 python run_calibration.py -num_simultaneous_processes=$SLURM_NTASKS_PER_NODE -rgi_glac_number_fn=$i & done # wait tells the loop to not move on until all the srun commands are completed -wait +wait \ No newline at end of file diff --git a/spc_run_retrieve_priors.sh b/spc_run_retrieve_priors.sh new file mode 100644 index 00000000..109c9675 --- /dev/null +++ b/spc_run_retrieve_priors.sh @@ -0,0 +1,36 @@ +#!/bin/sh +#SBATCH --partition=t1standard +#SBATCH --ntasks=576 +#SBATCH --tasks-per-node=24 + +# activate environment +module load lang/Anaconda3/2.5.0 +source activate pygem_hpc + +REGNO="15" +ADD_CAL_SWITCH=1 + +# split glaciers into batches for different nodes +python spc_split_glaciers.py -n_batches=$SLURM_JOB_NUM_NODES -spc_region=$REGNO -add_cal=$ADD_CAL_SWITCH + +# list rgi_glac_number batch filenames +CHECK_STR="Cal_R${REGNO}_rgi_glac_number_batch" +rgi_fns=$(find $CHECK_STR*) +echo rgi_glac_number filenames:$rgi_fns +# create list +list_rgi_fns=($rgi_fns) +echo first_batch:${list_rgi_fns[0]} + +echo partition: $SLURM_JOB_PARTITION +echo num_nodes: $SLURM_JOB_NUM_NODES nodes: $SLURM_JOB_NODELIST +echo num_tasks: $SLURM_NTASKS tasks_node: $SLURM_NTASKS_PER_NODE + +for i in $rgi_fns +do + # print the filename + echo $i + # run the file on a separate node (& tells the command to move to the next loop for any empty nodes) + srun -N 1 -n 1 python add_priors.py -num_simultaneous_processes=$SLURM_NTASKS_PER_NODE -rgi_glac_number_fn=$i & +done +# wait tells the loop to not move on until all the srun commands are completed +wait \ No newline at end of file diff --git a/spc_run_simulation.sh b/spc_run_simulation.sh index 53edf020..82f3ac2f 100644 --- a/spc_run_simulation.sh +++ b/spc_run_simulation.sh @@ -1,39 +1,32 @@ #!/bin/sh #SBATCH --partition=t1standard -#SBATCH --ntasks=576 +#SBATCH --ntasks=192 #SBATCH --tasks-per-node=24 -echo partition: $SLURM_JOB_PARTITION -echo num_nodes: $SLURM_JOB_NUM_NODES nodes: $SLURM_JOB_NODELIST -echo num_tasks: $SLURM_NTASKS tasks_node: $SLURM_NTASKS_PER_NODE - -REGNO="131415" -MERGE_SWITCH=0 -ORDERED_SWITCH=1 - # activate environment module load lang/Anaconda3/2.5.0 source activate pygem_hpc -# region -#REGNO=$(python pygem_input.py) -echo -e "Region: $REGNO\n" -# region batch string -rgi_batch_str="R${REGNO}_rgi_glac_number_batch" +REGNO="131415" # delete previous rgi_glac_number batch filenames -find -name '${rgi_batch_str}_*' -exec rm {} \; +find -name 'rgi_glac_number_batch_*' -exec rm {} \; # split glaciers into batches for different nodes -python spc_split_glaciers.py -n_batches=$SLURM_JOB_NUM_NODES -option_ordered=$ORDERED_SWITCH +python spc_split_glaciers.py -n_batches=$SLURM_JOB_NUM_NODES # list rgi_glac_number batch filenames -rgi_fns=$(find ${rgi_batch_str}*) +CHECK_STR="R${REGNO}_rgi_glac_number_batch" +rgi_fns=$(find $CHECK_STR*) echo rgi_glac_number filenames:$rgi_fns + # create list list_rgi_fns=($rgi_fns) echo first_batch:${list_rgi_fns[0]} +echo partition: $SLURM_JOB_PARTITION +echo num_nodes: $SLURM_JOB_NUM_NODES nodes: $SLURM_JOB_NODELIST +echo num_tasks: $SLURM_NTASKS tasks_node: $SLURM_NTASKS_PER_NODE for i in $rgi_fns do @@ -49,16 +42,3 @@ do done # wait tells the loop to not move on until all the srun commands are completed wait - -GCM_NAME_NOSPACE="ERA-Interim" - -set batman_list = 1 -# Merge simulation files -for batman in batman_list; do - # run the file on a separate node (& tells the command to move to the next loop for any empty nodes) - srun -N 1 -n 1 python merge_ds_spc.py -gcm_name="$GCM_NAME_NOSPACE" -num_simultaneous_processes=$SLURM_NTASKS_PER_NODE & - #srun -N 1 -n 1 python run_postprocessing.py -gcm_name="$GCM_NAME_NOSPACE" -rcp="$RCP" -merge_batches=$MERGE_SWITCH -done -wait - -echo -e "\nScript finished" diff --git a/spc_run_simulation_gcm.sh b/spc_run_simulation_gcm.sh index 07413c6b..d99c1a89 100644 --- a/spc_run_simulation_gcm.sh +++ b/spc_run_simulation_gcm.sh @@ -1,6 +1,6 @@ #!/bin/sh #SBATCH --partition=t1standard -#SBATCH --ntasks=240 +#SBATCH --ntasks=192 #SBATCH --tasks-per-node=24 echo partition: $SLURM_JOB_PARTITION @@ -10,11 +10,11 @@ echo num_tasks: $SLURM_NTASKS tasks_node: $SLURM_NTASKS_PER_NODE # region REGNO="131415" MERGE_SWITCH=0 -ORDERED_SWITCH=0 +ORDERED_SWITCH=1 # gcm list GCM_NAMES_FP="../Climate_data/cmip5/" -GCM_NAMES_FN="gcm_rcp26_filenames_important.txt" +GCM_NAMES_FN="gcm_rcp60_filenames_important.txt" # determine gcm names and rcp scenario GCM_NAMES_LST="$(< $GCM_NAMES_FP$GCM_NAMES_FN)" RCP="$(cut -d'_' -f2 <<<"$GCM_NAMES_FN")" @@ -64,6 +64,7 @@ for GCM_NAME in $GCM_NAMES_LST; do set batman_list = 1 # Merge simulation files for batman in batman_list; do + # run the file on a separate node (& tells the command to move to the next loop for any empty nodes) # run the file on a separate node (& tells the command to move to the next loop for any empty nodes) srun -N 1 -n 1 python merge_ds_spc.py -gcm_name="$GCM_NAME_NOSPACE" -rcp="$RCP" -num_simultaneous_processes=$SLURM_NTASKS_PER_NODE & #srun -N 1 -n 1 python run_postprocessing.py -gcm_name="$GCM_NAME_NOSPACE" -rcp="$RCP" -merge_batches=$MERGE_SWITCH diff --git a/spc_split_glaciers.py b/spc_split_glaciers.py index b27f7683..0c258a73 100644 --- a/spc_split_glaciers.py +++ b/spc_split_glaciers.py @@ -135,7 +135,6 @@ def split_list(lst, n=1, option_ordered=1): glac_no=input.glac_no) glacno_str = [x.split('-')[1] for x in main_glac_rgi_all.RGIId.values] - #%% # Check if need to update old batch files or not # (different number of glaciers or batches) if count_glac != len(glacno_str) or args.n_batches != len(batch_list):