def compute_region_ensembles():
    print('Computing region ensembles...')
    global gia, mask, settings
    mask['area'] = gentools.grid_area(mask['lat'],mask['lon'])
    pool = mp.Pool(settings['nproc'])
    out  = pool.map(compute_region_ens_indiv, range(settings['num_ens']))
    return
Exemple #2
0
def comp_GrIS_grd(grace_grd, mask, ens):
    global settings, glaciers, icesheets
    grd_ens = {}
    area = gentools.grid_area(mask['lat'],mask['lon'])
    rsl  = np.zeros([len(settings['time']),len(mask['lat']),len(mask['lon'])],dtype=np.float32)
    rad  = np.zeros([len(settings['time']),len(mask['lat']),len(mask['lon'])],dtype=np.float32)
    rsl[np.in1d(settings['time'],settings['time_grace']),:,:] = grace_grd['GrIS']['rsl'] * 1000
    rad[np.in1d(settings['time'],settings['time_grace']),:,:] = grace_grd['GrIS']['rad'] * 1000

    # Compute uniform grd fingerprints
    rsl_uniform = gentools.field_trend(settings['time_grace'],grace_grd['GrIS']['rsl'])
    scale_factor = ((rsl_uniform * (1 - mask['land']) * area).sum() / ((1 - mask['land']) * area).sum())
    rsl_uniform = rsl_uniform / scale_factor
    rad_uniform = gentools.field_trend(settings['time_grace'],grace_grd['GrIS']['rad']) / scale_factor

    GrIS_insitu_rsl =  icesheets['GrIS_ens'][ens,:][:,np.newaxis,np.newaxis] * rsl_uniform
    GrIS_insitu_rad =  icesheets['GrIS_ens'][ens,:][:,np.newaxis,np.newaxis] * rad_uniform
    ovl_time = (settings['time'] == 2003)
    insitu_time =   settings['time'] < 2003
    rsl[insitu_time,:,:] = GrIS_insitu_rsl[:-1,:,:] - GrIS_insitu_rsl[-1,:,:][np.newaxis,:,:] + rsl[ovl_time,:,:][np.newaxis,:,:]
    rad[insitu_time,:,:] = GrIS_insitu_rad[:-1,:,:] - GrIS_insitu_rad[-1,:,:][np.newaxis,:,:] + rad[ovl_time,:,:][np.newaxis,:,:]
    grd_ens['rsl'] = rsl - rsl[-19:,:,:].mean(axis=0)[np.newaxis,...]
    grd_ens['rad'] = rad - rad[-19:,:,:].mean(axis=0)[np.newaxis,...]
    area_ocn = ((area * (1 - mask['land']))[np.newaxis, ...])
    area_ocn_tot = area_ocn.sum()
    grd_ens['barystatic']   = (area_ocn*rsl).sum(axis=(1,2)) / area_ocn_tot
    area_ocn = ((area * np.isfinite(mask['basin']))[np.newaxis, ...])
    area_ocn_tot = area_ocn.sum()
    grd_ens['qglb'] = (area_ocn*rsl).sum(axis=(1,2)) / area_ocn_tot
    return(grd_ens)
Exemple #3
0
def comp_glac_grd(grace_grd, mask, ens):
    # Compute glacier contribution
    global settings, random_numbers, glacier_insitu
    grd_ens = {}
    area = gentools.grid_area(mask['lat'],mask['lon'])
    rsl  = np.zeros([len(settings['time']),len(mask['lat']),len(mask['lon'])],dtype=np.float32)
    rad  = np.zeros([len(settings['time']),len(mask['lat']),len(mask['lon'])],dtype=np.float32)

    rsl[np.in1d(settings['time'],settings['time_grace']),:,:] = grace_grd['glac']['rsl'] * 1000
    rad[np.in1d(settings['time'],settings['time_grace']),:,:] = grace_grd['glac']['rad'] * 1000

    glac_insitu_rsl = np.zeros([len(settings['time_insitu']),len(mask['lat']),len(mask['lon'])],dtype=np.float32)
    glac_insitu_rad = np.zeros([len(settings['time_insitu']),len(mask['lat']),len(mask['lon'])],dtype=np.float32)
    #
    for reg in range(17):
        glac_insitu_rsl+= glacier_insitu['fp_rsl'][reg,...]*glacier_insitu['ensemble'][ens,reg,:][:,np.newaxis,np.newaxis]
        glac_insitu_rad+= glacier_insitu['fp_rad'][reg,...]*glacier_insitu['ensemble'][ens,reg,:][:,np.newaxis,np.newaxis]

    ovl_time = (settings['time'] == 2003)
    insitu_time =   settings['time'] < 2003

    rsl[insitu_time,:,:] = glac_insitu_rsl[:-1,:,:] - glac_insitu_rsl[-1,:,:][np.newaxis,:,:] + rsl[ovl_time,:,:][np.newaxis,:,:]
    rad[insitu_time,:,:] = glac_insitu_rad[:-1,:,:] - glac_insitu_rad[-1,:,:][np.newaxis,:,:] + rad[ovl_time,:,:][np.newaxis,:,:]
    grd_ens['rsl'] = rsl - rsl[-19:,:,:].mean(axis=0)[np.newaxis,...]
    grd_ens['rad'] = rad - rad[-19:,:,:].mean(axis=0)[np.newaxis,...]
    area_ocn = ((area * (1 - mask['land']))[np.newaxis, ...])
    area_ocn_tot = area_ocn.sum()
    grd_ens['barystatic'] = (area_ocn*rsl).sum(axis=(1,2)) / area_ocn_tot
    area_ocn = ((area * np.isfinite(mask['basin']))[np.newaxis, ...])
    area_ocn_tot = area_ocn.sum()
    grd_ens['qglb'] = (area_ocn*rsl).sum(axis=(1,2)) / area_ocn_tot
    return(grd_ens)
def proc_grid_basin(pname):
    print('   Processing grid ' + pname + '...')
    global settings, mask
    steric = {}
    file_handle = Dataset(settings['fn_' + pname])
    file_handle.set_auto_mask(False)
    time = file_handle.variables['t'][:]
    lon = file_handle.variables['x'][:]
    lat = file_handle.variables['y'][:]
    slm = file_handle.variables['slm'][:]
    time_acc = (time < settings['years_grid'][-1] + 1) & (
        time >= settings['years_grid'][0])
    time = time[time_acc]
    steric_monthly = file_handle.variables['h_totalsteric'][time_acc, :, :]
    halo_glb_monthly = file_handle.variables['ts_halosteric'][time_acc]
    file_handle.close()
    steric_monthly -= halo_glb_monthly[:, np.newaxis, np.newaxis]

    # To annual data
    steric['years'] = settings['years_grid']
    steric_annual = np.zeros([len(steric['years']), len(lat), len(lon)])
    for idx, yr in enumerate(steric['years']):
        acc_idx = (time >= yr) & (time < yr + 1)
        steric_annual[idx, :, :] = steric_monthly[acc_idx, :, :].mean(axis=0)

    area = gentools.grid_area(lat, lon)
    steric['basin'] = np.zeros(6, dtype=object)
    # Basin mean
    for basin in range(6):
        msk_lcl = (mask['basin'] == basin)
        msk_interp = np.rint(
            interp2d(mask['lon'],
                     mask['lat'],
                     msk_lcl,
                     kind='linear',
                     bounds_error=False,
                     fill_value=0)(lon, lat)) * slm
        steric['basin'][basin] = np.nansum(
            (area[np.newaxis, :, :] * msk_interp[np.newaxis, :, :] *
             steric_annual),
            axis=(1, 2)) / (area * msk_interp).sum()

    # Global steric
    msk_lcl = 1.0 * (np.isfinite(mask['basin']))
    msk_interp = np.rint(
        interp2d(mask['lon'],
                 mask['lat'],
                 msk_lcl,
                 kind='linear',
                 bounds_error=False,
                 fill_value=0)(lon, lat)) * slm
    steric['global'] = np.nansum(
        (area[np.newaxis, :, :] * msk_interp[np.newaxis, :, :] *
         steric_annual),
        axis=(1, 2)) / (area * msk_interp).sum()
    return (steric)
Exemple #5
0
def comp_tws_grd(grace_grd,mask, ens):
    global settings, tws, random_numbers
    grd_ens = {}
    area = gentools.grid_area(mask['lat'],mask['lon'])
    rsl  = np.zeros([len(settings['time']),len(mask['lat']),len(mask['lon'])],dtype=np.float32)
    rad  = np.zeros([len(settings['time']),len(mask['lat']),len(mask['lon'])],dtype=np.float32)

    rsl[np.in1d(settings['time'],settings['time_grace']),:,:] = grace_grd['tws']['rsl'] * 1000
    rad[np.in1d(settings['time'],settings['time_grace']),:,:] = grace_grd['tws']['rad'] * 1000

    # Compute natural, grd, and dam over Thompson mask
    tws_natural_rsl,tws_natural_rad = read_tws_natural(ens)
    tws_dams_rsl = random_numbers['tws_dam_scale'][ens] * tws['grd_dam_rsl']
    tws_dams_rad = random_numbers['tws_dam_scale'][ens] * tws['grd_dam_rad']
    if random_numbers['tws_wada_doll'][ens] == 0:
        tws_gwd_rsl  = random_numbers['tws_gwd_scale'][ens] * tws['grd_gwd_wada_rsl']
        tws_gwd_rad  = random_numbers['tws_gwd_scale'][ens] * tws['grd_gwd_wada_rad']
    else:
        tws_gwd_rsl  = random_numbers['tws_gwd_scale'][ens] * tws['grd_gwd_doll_rsl']
        tws_gwd_rad  = random_numbers['tws_gwd_scale'][ens] * tws['grd_gwd_doll_rad']

    # Combine three sources
    tws_insitu_rsl = tws_dams_rsl + tws_gwd_rsl + tws_natural_rsl
    tws_insitu_rad = tws_dams_rad + tws_gwd_rad + tws_natural_rad
    ovl_time = (settings['time'] == 2003)
    insitu_time =   settings['time'] < 2003
    rsl[insitu_time,:,:] = tws_insitu_rsl[:-1,:,:] - tws_insitu_rsl[-1,:,:][np.newaxis,:,:] + rsl[ovl_time,:,:][np.newaxis,:,:]
    rad[insitu_time,:,:] = tws_insitu_rad[:-1,:,:] - tws_insitu_rad[-1,:,:][np.newaxis,:,:] + rad[ovl_time,:,:][np.newaxis,:,:]
    grd_ens['rsl'] = rsl - rsl[-19:,:,:].mean(axis=0)[np.newaxis,...]
    grd_ens['rad'] = rad - rad[-19:,:,:].mean(axis=0)[np.newaxis,...]

    # Save barystatic terms, as well as individual terms
    area_ocn = ((area * (1 - mask['land']))[np.newaxis, ...])
    area_ocn_tot = area_ocn.sum()
    grd_ens['barystatic']         = (area_ocn*rsl).sum(axis=(1,2)) / area_ocn_tot
    grd_ens['barystatic_dam']     = np.hstack([(area_ocn*tws_dams_rsl).sum(axis=(1,2))    / area_ocn_tot, np.zeros(15,dtype=np.float32)*np.nan])
    grd_ens['barystatic_gwd']     = np.hstack([(area_ocn*tws_gwd_rsl).sum(axis=(1,2))/ area_ocn_tot, np.zeros(15,dtype=np.float32)*np.nan])
    grd_ens['barystatic_natural'] = np.hstack([(area_ocn*tws_natural_rsl).sum(axis=(1,2))   / area_ocn_tot, np.zeros(15,dtype=np.float32)*np.nan])

    # Save quasi-global estimate (i.e. Thompsons mask)
    area_ocn = ((area * np.isfinite(mask['basin']))[np.newaxis, ...])
    area_ocn_tot = area_ocn.sum()
    grd_ens['qglb']         = (area_ocn*rsl).sum(axis=(1,2)) / area_ocn_tot
    grd_ens['qglb_dam']     = np.hstack([(area_ocn*tws_dams_rsl).sum(axis=(1,2))    / area_ocn_tot, np.zeros(15,dtype=np.float32)*np.nan])
    grd_ens['qglb_gwd']     = np.hstack([(area_ocn*tws_gwd_rsl).sum(axis=(1,2))/ area_ocn_tot, np.zeros(15,dtype=np.float32)*np.nan])
    grd_ens['qglb_natural'] = np.hstack([(area_ocn*tws_natural_rsl).sum(axis=(1,2))   / area_ocn_tot, np.zeros(15,dtype=np.float32)*np.nan])

    # Same baseline
    grd_ens['barystatic_dam']     = grd_ens['barystatic_dam']     - grd_ens['barystatic_dam'][103]     + grd_ens['barystatic'][103]
    grd_ens['barystatic_gwd']     = grd_ens['barystatic_gwd']     - grd_ens['barystatic_gwd'][103]     + grd_ens['barystatic'][103]
    grd_ens['barystatic_natural'] = grd_ens['barystatic_natural'] - grd_ens['barystatic_natural'][103] + grd_ens['barystatic'][103]

    grd_ens['qglb_dam']     = grd_ens['qglb_dam']     - grd_ens['qglb_dam'][103]     + grd_ens['qglb'][103]
    grd_ens['qglb_gwd']     = grd_ens['qglb_gwd']     - grd_ens['qglb_gwd'][103]     + grd_ens['qglb'][103]
    grd_ens['qglb_natural'] = grd_ens['qglb_natural'] - grd_ens['qglb_natural'][103] + grd_ens['qglb'][103]
    return(grd_ens)
Exemple #6
0
def read_mask():
    global settings, mask
    mask = {}
    mask_raw = np.load(settings['fn_mask'], allow_pickle=True).all()
    mask['lon'] = mp_filled_float(mask_raw['lon'])
    mask['lat'] = mp_filled_float(mask_raw['lat'])
    mask['basin'] = mp_filled_float(mask_raw['basin'])
    mask['area'] = mp_filled_float(gentools.grid_area(mask['lat'],
                                                      mask['lon']))
    return
def prep_GWD(GRACE,settings):
    # ------------------------------------------------------------------
    # Groundwater depletion
    #  Use estimates from Wada et al., 2010, 2014, which cover 1900-2010
    #  Merge the 2 data sets
    #  Sum depletion rate to get total depletion
    #  Wada 2016: not all depleted water ends up in ocean. We apply a
    #  correction factor of 0.6 to account for this effect.
    # ------------------------------------------------------------------
    wada_2016_scale = 0.6 # Scale factor (Wada 2016)

    area = gentools.grid_area(GRACE['lat'], GRACE['lon'])
    time_tot = np.arange(1900,2004)
    depletion = np.zeros([len(time_tot),len(GRACE['lat']),len(GRACE['lon'])])
    # Old Wada 2010 data
    time_past = np.arange(1900,1960)
    for idx,yr in enumerate(time_past):
        data_raw = np.loadtxt(settings['dir_gwd_20c'] + 'gwd0' + str(yr) + '.asc', skiprows=6)
        data_raw[data_raw == -9999] = 0
        data_raw = np.flipud(data_raw)
        data_raw = np.hstack([data_raw[:, 360:], data_raw[:, 0:360]])
        depletion[idx, :, :] = data_raw
    # Present (Wada 2014)
    file_handle = Dataset(settings['fn_gwd_wada'], 'r')
    file_handle.set_auto_mask(False)
    depletion_pd_monthly = file_handle.variables["anrg"][:]
    depletion_pd_monthly[depletion_pd_monthly < 0] = 0
    file_handle.close()
    time_pd_m = gentools.monthly_time(1960, 2010)
    time_present = np.arange(1960, 2004)
    # To normal grid
    depletion_rate_monthly = np.fliplr(depletion_pd_monthly)
    depletion_rate_monthly = np.dstack([depletion_rate_monthly[:, :, 360:], depletion_rate_monthly[:, :, 0:360]])
    for idx,yr in enumerate(time_present):
        idx_m = (time_pd_m>yr) & (time_pd_m<yr+1)
        depletion[idx+60, :, :] = np.sum(depletion_rate_monthly[idx_m, :, :], axis=0)
    depletion = depletion/ area  * -1e9
    depletion = np.cumsum(depletion, axis=0)* wada_2016_scale

    # Test global
    depletion_global = np.nansum(depletion * area, axis=(1, 2))
    depletion_mscn = np.zeros(depletion.shape)
    # Into mascons
    for k in range(len(GRACE['mscn_coords'])):
        lat_acc = np.where((GRACE['lat'] >= GRACE['mscn_coords'][k, 0]) & (GRACE['lat'] < GRACE['mscn_coords'][k, 1]))[0]
        lon_acc = np.where((GRACE['lon'] >= GRACE['mscn_coords'][k, 2]) & (GRACE['lon'] < GRACE['mscn_coords'][k, 3]))[0]
        lsm_acc = GRACE['land'][lat_acc[0]:lat_acc[-1] + 1, lon_acc[0]:lon_acc[-1] + 1]
        dp_mean = np.mean(depletion[:,lat_acc[0]:lat_acc[-1] + 1, lon_acc[0]:lon_acc[-1] + 1]*lsm_acc[np.newaxis,:,:],axis=(1,2))
        depletion_mscn[:,lat_acc[0]:lat_acc[-1] + 1, lon_acc[0]:lon_acc[-1] + 1] = dp_mean[:,np.newaxis,np.newaxis]
    depletion_mscn = depletion_mscn * GRACE['land'][np.newaxis,:,:]
    depletion_global_mscn = np.nansum(depletion_mscn * area, axis=(1, 2))
    depletion_mscn = depletion_mscn * (depletion_global/depletion_global_mscn)[:,np.newaxis,np.newaxis]
    return(depletion_mscn)
def read_gia_ens(ens):
    global mask, settings
    gia = {}
    file_handle = Dataset(settings['fn_gia_rsl'], 'r')
    file_handle.set_auto_mask(False)
    gia['lat'] =  file_handle.variables['y'][:]
    gia['lon'] =  file_handle.variables['x'][:]
    if settings['test_run_ICE6G_D']:
        gia['rsl'] =  file_handle.variables['RSL'][:]
    else:
        gia['rsl'] =  file_handle.variables['rsl'][ens,:,:]
    file_handle.close()
    # Basin-mean estimate
    area = gentools.grid_area(gia['lat'],gia['lon'])
    gia['basin_mean'] = np.zeros(6)
    for basin in range(6):
        # Basin-mean GIA
        mask_lcl = (mask['basin']==basin)
        gia['basin_mean'][basin] = np.sum(gia['rsl']*mask_lcl*area)/np.sum(mask_lcl*area)
    return(gia)
Exemple #9
0
def compute_global_ensembles(basin_ensembles,settings):
    # Compute weights of each basin
    # Take into account that not all basins are complete
    basin_mask = read_basin_mask(settings)
    area = gentools.grid_area(basin_mask['lat'],basin_mask['lon'])
    slm = np.isfinite(basin_mask['num'])
    total_area = np.sum(area*slm)
    basin_weight = np.zeros(len(basin_ensembles))
    for basin in range(len(basin_ensembles)): basin_weight[basin] = np.sum(area*(basin_mask['num']==basin)) / total_area
    reg_acc = np.zeros([len(basin_ensembles),len(settings['years'])],dtype=bool)
    for basin in range(len(basin_ensembles)):  reg_acc[basin,:] = np.isfinite(basin_ensembles[basin]['tg_no_corrections'][0, :])
    weight_idx = reg_acc * basin_weight[:,np.newaxis]
    weight_idx = weight_idx / weight_idx.sum(axis=0)
    global_ensembles = {}
    for method in basin_ensembles[0].keys():
        global_ensembles[method] = np.zeros([settings['num_ens'],len(settings['years'])])
        for basin in range(len(basin_ensembles)):
            basin_lcl = basin_ensembles[basin][method].copy()
            basin_lcl[np.isnan(basin_lcl)] = 0
            global_ensembles[method] = global_ensembles[method] + weight_idx[basin,:] * basin_lcl
    return(global_ensembles)
def prep_GWD_Doll(GRACE, depletion_mscn, settings):
    # ---------------------------------------------
    # Ground water depletion from Doll et al (2014)
    # - Transform from monthly to annual
    # - 0-360
    # - Mask out Greenland
    # ---------------------------------------------
    file_handle = Dataset(settings['fn_gwd_doll_irr'], 'r')
    file_handle.set_auto_mask(False)
    time = 1960+file_handle.variables['time'][:]/12 + 1/24
    lat = file_handle.variables['lat'][:]
    lon = file_handle.variables['lon'][:]
    tws_irr = file_handle.variables['TWS_mm'][:]
    tws_irr[tws_irr < -9998] = np.nan
    file_handle.close()

    tws_nouse = Dataset(settings['fn_gwd_doll_nouse'], 'r').variables['TWS_mm'][:]._get_data()
    tws_nouse[tws_nouse < -9998] = np.nan

    # To 0-360
    tws_irr   = np.dstack([tws_irr[:,:,360:],tws_irr[:,:,:360]])
    tws_nouse = np.dstack([tws_nouse[:,:,360:],tws_nouse[:,:,:360]])

    # Depletion in irrigated minus natural
    tws = tws_irr - tws_nouse

    area = gentools.grid_area(GRACE['lat'], GRACE['lon'])

    mask = np.load(settings['fn_mask'],allow_pickle=True).all()
    mask_tws = (mask['land']) & (~mask['AIS']) & (~mask['GrIS'])

    # To annual
    tws[:,~mask_tws] = 0
    tws[np.isnan(tws)] = 0
    time_ann_doll = np.arange(1960,2004,1)
    tws_ann_doll = np.zeros([len(time_ann_doll),len(lat),len(lon)])
    for idx, t in enumerate(time_ann_doll):
        acc_t = (np.floor(time).astype(int)==t)
        tws_ann_doll[idx,:,:] = tws[acc_t,:,:].mean(axis=0)

    # To mascon
    tws_ann_doll_global = np.nansum(tws_ann_doll * area, axis=(1, 2))
    tws_ann_doll_mscn = np.zeros(tws_ann_doll.shape)
    # Into mascons
    for k in range(len(GRACE['mscn_coords'])):
        lat_acc = np.where((GRACE['lat'] >= GRACE['mscn_coords'][k, 0]) & (GRACE['lat'] < GRACE['mscn_coords'][k, 1]))[0]
        lon_acc = np.where((GRACE['lon'] >= GRACE['mscn_coords'][k, 2]) & (GRACE['lon'] < GRACE['mscn_coords'][k, 3]))[0]
        lsm_acc = GRACE['land'][lat_acc[0]:lat_acc[-1] + 1, lon_acc[0]:lon_acc[-1] + 1]
        dp_mean = np.mean(tws_ann_doll[:,lat_acc[0]:lat_acc[-1] + 1, lon_acc[0]:lon_acc[-1] + 1]*lsm_acc[np.newaxis,:,:],axis=(1,2))
        tws_ann_doll_mscn[:,lat_acc[0]:lat_acc[-1] + 1, lon_acc[0]:lon_acc[-1] + 1] = dp_mean[:,np.newaxis,np.newaxis]
    tws_ann_doll_mscn = tws_ann_doll_mscn * GRACE['land'][np.newaxis,:,:]
    tws_ann_doll_global_mscn = np.nansum(tws_ann_doll_mscn * area, axis=(1, 2))
    tws_ann_doll_mscn *= (tws_ann_doll_global/tws_ann_doll_global_mscn)[:,np.newaxis,np.newaxis]

    depletion_doll_mscn = np.zeros(depletion_mscn.shape)
    depletion_doll_mscn[:61,...] = depletion_mscn[:61,...]
    depletion_doll_mscn[60:,...] = tws_ann_doll_mscn - tws_ann_doll_mscn[0,...][np.newaxis,...] + depletion_doll_mscn[60,...][np.newaxis,...]
    # tst = np.nansum(tws_annual * area, axis=(1, 2))
    # tst2 = np.nansum(depletion_mscn * area, axis=(1, 2))
    # tst3 = np.nansum(depletion_doll_mscn * area, axis=(1, 2))
    return(depletion_doll_mscn)
def prep_dams(GRACE,settings):
    # --------------------------------------------------------------------------------------------
    # Prepare dam water storage data
    # 1. Read dam lists from the GRanD list and the data from Ben Chao
    # 2. Remove duplicates as good as it gets
    # 3. Fill global grid with dam retention data and seepage estimates based on Chao et al., 2008
    # --------------------------------------------------------------------------------------------
    print('   Reading spreadsheets...')
    chao_list_raw = pd.read_excel(settings['fn_chao_list'], header=None).values  # Read Chao list
    chao_loc_raw  = pd.read_excel(settings['fn_chao_loc'], header=None).values   # Read Chao locs
    lehner_raw    = pd.read_excel(settings['fn_lehner'], header=None).values     # Read Lehner locs

    # name lat lon year cap loc_avail
    dam_list_grand = np.zeros([len(lehner_raw), 6], dtype=object)
    print('   Processing GRanD list...')
    lehner_raw[:, 2][lehner_raw[:, 2]<0] = lehner_raw[:, 2][lehner_raw[:, 2]<0] + 360
    for i in range(len(lehner_raw)):
        dam_list_grand[i, 0] = lehner_raw[i, 1].split('(')[0].lower().replace(" ", "")
        dam_list_grand[i, 1] = lehner_raw[i, 3]
        dam_list_grand[i, 2] = lehner_raw[i, 2]
        dam_list_grand[i, 3] = lehner_raw[i, 7]
        dam_list_grand[i, 4] = lehner_raw[i, 6] * 1000
        dam_list_grand[i, 5] = True
    dam_list_grand = dam_list_grand[dam_list_grand[:, 4] > 0, :]

    print('   Processing Ben Chaos location list...')
    # --------------------------------------------------------------
    # GRanD list and Benjamin Chao's location list have overlap
    # Challenge: find dams that are in Chao's list, but not in GRanD
    # These dams have a known lat/lon location
    # --------------------------------------------------------------
    dam_list_chao_loc = []
    chao_loc_raw[:, 6][chao_loc_raw[:, 6]<0] = chao_loc_raw[:, 6][chao_loc_raw[:, 6]<0] + 360
    for i in range(len(chao_loc_raw)):
        dam_list_lcl = np.zeros(6, dtype=object)
        dam_list_lcl[0] = chao_loc_raw[i, 2].split('(')[0].lower().replace(" ", "")
        diff_score = np.zeros(len(dam_list_grand))
        for lcl in range(len(diff_score)):
            diff_score[lcl] = Levenshtein.ratio(dam_list_lcl[0], dam_list_grand[lcl, 0])
            vol_ratio = chao_loc_raw[i, 3] / (dam_list_grand[lcl, 4])
            if (vol_ratio < 0.5) | (vol_ratio > 2): diff_score[lcl] = -1                     # If capacity is vastly different, probably different dam
            if np.abs(chao_loc_raw[i, 4] - dam_list_grand[lcl, 3]) > 2: diff_score[lcl] = -1 # If year of construction is vastly different, probably different dam
        if np.max(diff_score) < 0.9:
            dam_list_lcl[1] = chao_loc_raw[i, 5]
            dam_list_lcl[2] = chao_loc_raw[i, 6]
            dam_list_lcl[3] = chao_loc_raw[i, 4]
            dam_list_lcl[4] = chao_loc_raw[i, 3]
            dam_list_lcl[5] = True
            dam_list_chao_loc.append(dam_list_lcl)
    dam_list_chao_loc = np.array(dam_list_chao_loc)
    dam_list_loc = np.vstack([dam_list_grand, dam_list_chao_loc])

    # --------------------------------------------------------------
    # GRanD list and Benjamin Chao's location list have overlap
    # Challenge: find dams that are in Chao's list, but not in GRanD
    # These dams don't have a known lat/lon location
    # --------------------------------------------------------------
    print('   Processing Ben Chaos full list...')
    dam_list_chao_full = []
    for i in range(len(chao_list_raw)):
        if chao_list_raw[i, 3] > 1000:
            dam_list_lcl = np.zeros(6, dtype=object)
            dam_list_lcl[0] = chao_list_raw[i, 2].split('(')[0].lower().replace(" ", "")
            diff_score = np.zeros(len(dam_list_loc))
            for lcl in range(len(dam_list_loc)):
                diff_score[lcl] = Levenshtein.ratio(dam_list_lcl[0], dam_list_loc[lcl, 0])
            if np.max(diff_score) < 0.7:
                dam_list_lcl[3] = chao_list_raw[i, 4]
                dam_list_lcl[4] = chao_list_raw[i, 3]
                dam_list_lcl[5] = False
                dam_list_chao_full.append(dam_list_lcl)
    dam_list_chao_full = np.array(dam_list_chao_full)
    dam_list = np.vstack([dam_list_grand, dam_list_chao_loc,dam_list_chao_full])

    # From 1000 m3 to kg
    dam_list[:, 4] = dam_list[:, 4] * 1e6
    dam_years      = np.arange(1800, 2004, 1)

    # Index for dams with known locations
    nlocs = np.sum(dam_list[:, 5])
    dam_load_list = np.zeros([nlocs, len(dam_years)])
    no_seepage = ['manicouagan', 'jenpeg', 'smallwoodreservoir', 'missifallscontrol', 'earfalls', 'whitesandrapids', 'pipmuacan', 'keenleyside', 'sanhezha', 'tainionkoski', 'irkutsk', 'verkhnetulomskaya', 'ondakumskaya', 'verkhnesvirskaya', 'structure308']

    # Total volumes
    print('   Computing storage and seepage...')
    total_volume  = np.zeros(len(dam_years)) # Total water in dam assuming 85% full
    total_scaled  = np.zeros(len(dam_years)) # Total water in dam assuming 85% full
    total_seepage = np.zeros(len(dam_years)) # Total TWS due to seepage after dam construction
    total_storage = np.zeros(len(dam_years)) # Total TWS due to water in dam and seepage
    for i in range(len(dam_list)):
        local_volume  = np.zeros(len(dam_years))
        local_seepage = np.zeros(len(dam_years))
        if (dam_list[i, 3] > 1799) & (dam_list[i, 3] < 2004):
            startindex = int(dam_list[i, 3] - 1800)
        else:
            startindex = 0
        local_volume[startindex:] = dam_list[i, 4] * 0.85
        seepage_growth = np.minimum(np.cumsum(1 / np.sqrt(dam_years[startindex + 1:] - (dam_years[startindex]))), 20)
        local_seepage[startindex + 1:] = dam_list[i, 4] * 0.05 * seepage_growth
        total_scaled = total_scaled + local_volume
        total_seepage = total_seepage + local_seepage
        if dam_list[i, 0] in no_seepage:
            local_storage = local_volume
        else:
            local_storage = local_seepage + local_volume
        total_storage = total_storage + local_storage
        total_volume = total_volume + local_volume/0.85
        # If location known, add as new entry, otherwise spread over all other locations
        if i < nlocs:
            dam_load_list[i, :] = local_storage
        else:
            dam_load_list = dam_load_list + (local_storage / nlocs)[np.newaxis, :]

    # List with dam indices
    print('   Adding all dams to grid...')
    area = gentools.grid_area(GRACE['lat'],GRACE['lon'])
    dam_load = np.zeros([len(dam_years),len(GRACE['lat']),len(GRACE['lon'])])
    for i in range(nlocs):
        idx_lat = np.argmin(np.abs(GRACE['lat'] - dam_list[i, 1]))
        idx_lon = np.argmin(np.abs(GRACE['lon'] - dam_list[i, 2]))
        dam_load[:, idx_lat, idx_lon] = dam_load[:, idx_lat, idx_lon] + dam_load_list[i, :] / area[idx_lat, idx_lon]

    # Only 1900-2004
    acc_idx = np.in1d(dam_years, settings['time'])
    dam_load = dam_load[acc_idx, :, :]
    total_scaled = total_scaled[acc_idx]
    total_seepage = total_seepage[acc_idx]
    total_storage = total_storage[acc_idx]
    total_volume = total_volume[acc_idx]

    # smooth_trend_s = np.zeros(len(settings['time']))*np.nan
    #
    # flen=30
    # fhalf = int(flen/2)
    # for idx,yr in enumerate(settings['time']):
    #     if (idx>(fhalf-1)) & (idx<len(settings['time'])-fhalf-1):
    #         amat = np.ones([flen,2])
    #         amat[:,1] = settings['time'][idx-fhalf:idx+fhalf]
    #         smooth_trend_s[idx] = np.linalg.lstsq(amat,total_storage[idx-fhalf:idx+fhalf],rcond=None)[0][1]


    # To mascon
    print('   Grid to mascon...')
    dam_load_mscn = np.zeros(dam_load.shape)
    # Into mascons
    for k in range(len(GRACE['mscn_coords'])):
        lat_acc = np.where((GRACE['lat'] >= GRACE['mscn_coords'][k, 0]) & (GRACE['lat'] < GRACE['mscn_coords'][k, 1]))[0]
        lon_acc = np.where((GRACE['lon'] >= GRACE['mscn_coords'][k, 2]) & (GRACE['lon'] < GRACE['mscn_coords'][k, 3]))[0]
        lsm_acc = GRACE['land'][lat_acc[0]:lat_acc[-1] + 1, lon_acc[0]:lon_acc[-1] + 1]
        dp_mean = np.mean(dam_load[:,lat_acc[0]:lat_acc[-1] + 1, lon_acc[0]:lon_acc[-1] + 1]*lsm_acc[np.newaxis,:,:],axis=(1,2))
        dam_load_mscn[:,lat_acc[0]:lat_acc[-1] + 1, lon_acc[0]:lon_acc[-1] + 1] = dp_mean[:,np.newaxis,np.newaxis]
    dam_load_mscn = dam_load_mscn * GRACE['land'][np.newaxis,:,:]
    dam_load_global_mscn = np.nansum(dam_load_mscn * area, axis=(1, 2))
    dam_load_mscn = dam_load_mscn * (total_storage/dam_load_global_mscn)[:,np.newaxis,np.newaxis]
    return(dam_load_mscn)
def read_glacier_mask(grace_mask, settings):
    print('   Processing glacier masks...')
    glacier_mask = {}
    glacier_mask['lat'] = grace_mask['lat']
    glacier_mask['lon'] = grace_mask['lon']
    area = gentools.grid_area(grace_mask['lat'], grace_mask['lon'])
    # Read RGI masks and areas and remove the Greenland and Antarctic Periphery

    glacier_mask['num_grace'] = np.array(
        [1, 3, 4, 6, 7, 9,
         17])  # Glacier regions where mascons are dominated by GIS
    glacier_mask['num_insitu'] = np.array([
        2, 8, 10, 11, 12, 13, 14, 15, 16, 18
    ])  # Regions where GIS contribution is determined from Zemp et al (2019)
    glacier_mask['num'] = np.sort(
        np.hstack([glacier_mask['num_grace'], glacier_mask['num_insitu']]))

    # Read and remove the Greenland and Antarctic Periphery
    rgi_mask = Dataset(settings['fn_rgi_mask'],
                       'r').variables['mask'][:]._get_data().astype(bool)
    rgi_area = Dataset(settings['fn_rgi_mask'],
                       'r').variables['total_area'][:]._get_data() * 1e6  # m^2
    rgi_mask = np.delete(rgi_mask, 4, axis=0)[:-1, :, :]
    rgi_area = np.delete(rgi_area, 4, axis=0)[:-1, :, :]

    # Compute mascons that contain glaciers and determine load scale:
    # Multiply scale by mass loss in GT to get local load in kg/m^2
    rgi_scale_mscn = np.zeros(
        [rgi_mask.shape[0],
         len(grace_mask['lat']),
         len(grace_mask['lon'])])
    for reg in range(rgi_mask.shape[0]):
        print('      RGI region ' + str(glacier_mask['num'][reg]) + '...')
        scale_lcl = np.zeros([len(grace_mask['lat']), len(grace_mask['lon'])])
        glac_area_rgi_region = rgi_area[reg, :, :].sum()
        for k in range(len(grace_mask['mscn_coords'])):
            lat_acc = np.where(
                (grace_mask['lat'] >= grace_mask['mscn_coords'][k, 0])
                & (grace_mask['lat'] < grace_mask['mscn_coords'][k, 1]))[0]
            lon_acc = np.where(
                (grace_mask['lon'] >= grace_mask['mscn_coords'][k, 2])
                & (grace_mask['lon'] < grace_mask['mscn_coords'][k, 3]))[0]
            glac_area_in_mscn = rgi_area[reg, lat_acc[0]:lat_acc[-1] + 1,
                                         lon_acc[0]:lon_acc[-1] + 1].sum()
            area_mscn = np.maximum(
                1,
                (area[lat_acc[0]:lat_acc[-1] + 1, lon_acc[0]:lon_acc[-1] + 1] *
                 grace_mask['mask_land'][lat_acc[0]:lat_acc[-1] + 1,
                                         lon_acc[0]:lon_acc[-1] + 1]).sum())
            scale_lcl[lat_acc[0]:lat_acc[-1] + 1, lon_acc[0]:lon_acc[-1] +
                      1] = (glac_area_in_mscn /
                            glac_area_rgi_region) * (1 / area_mscn)
        rgi_scale_mscn[reg, :, :] = scale_lcl * grace_mask['mask_no_is'] * 1e12
        rgi_scale_mscn[reg, :, :] = rgi_scale_mscn[reg, :, :] * 1e12 / (
            rgi_scale_mscn[reg, :, :] * area).sum()
    glacier_mask['scale'] = rgi_scale_mscn
    glacier_mask['mask_all'] = (rgi_scale_mscn.sum(axis=0) > 0)
    glacier_mask['mask_grace'] = (rgi_scale_mscn[
        np.in1d(glacier_mask['num'], glacier_mask['num_grace']), :, :].sum(
            axis=0) > 0)
    glacier_mask['mask_insitu'] = (rgi_scale_mscn[
        np.in1d(glacier_mask['num'], glacier_mask['num_insitu']), :, :].sum(
            axis=0) > 0)
    return (glacier_mask)
def compute_basin_estimate(regions_for_selection, settings):
    print('Computing basin estimates:')
    # --------------------------------------------
    # Read GIA and GRD and compute basin estimates
    # --------------------------------------------
    basin_mask = read_basin_mask(settings)

    # Sample locations
    regions_for_selection['grd_sample_points'] = np.zeros(
        [len(regions_for_selection['id']), 2], dtype=int)
    lat = np.arange(-89.75, 90.25, 0.5)
    lon = np.arange(0.25, 360.25, 0.5)
    regions_for_selection['grd_sample_points'][:, 0] = np.argmin(
        np.abs(regions_for_selection['coords'][:, 0][np.newaxis, :] -
               lat[:, np.newaxis]),
        axis=0)
    regions_for_selection['grd_sample_points'][:, 1] = np.argmin(
        np.abs(regions_for_selection['coords'][:, 1][np.newaxis, :] -
               lon[:, np.newaxis]),
        axis=0)

    # Sample GIA at region locations
    GIA = read_GIA_rsl(settings)

    regions_for_selection['rsl_gia_mean'] = np.zeros(
        len(regions_for_selection['id']))
    regions_for_selection['rsl_gia_dev'] = np.zeros(
        len(regions_for_selection['id']))  # Deviation of region from basin
    for region in range(len(regions_for_selection['id'])):
        regions_for_selection['rsl_gia_mean'][region] = (
            GIA['probability'] *
            GIA['rsl'][:, regions_for_selection['grd_sample_points'][region,
                                                                     0],
                       regions_for_selection['grd_sample_points'][region,
                                                                  1]]).sum()
    GIA_basin = np.zeros(len(basin_mask['basins']))  # Basin-mean GIA
    area = gentools.grid_area(GIA['lat'], GIA['lon'])
    for basin in range(len(basin_mask['basins'])):
        GIA_basin[basin] = (GIA['probability'] * (
            ((area * (basin_mask['num'] == basin))[np.newaxis, :, :] *
             GIA['rsl']).sum(axis=(1, 2)) /
            (area * (basin_mask['num'] == basin)).sum())).sum()
    for region in range(len(regions_for_selection['id'])):
        regions_for_selection['rsl_gia_dev'][region] = regions_for_selection[
            'rsl_gia_mean'][region] - GIA_basin[
                regions_for_selection['basin_num'][region]]

    # Sample GRD at region locations
    regions_for_selection['rsl_grd_mean'] = np.zeros(
        [len(regions_for_selection['id']),
         len(settings['years'])])
    regions_for_selection['rsl_grd_dev'] = np.zeros(
        [len(regions_for_selection['id']),
         len(settings['years'])])  # Deviation of region from basin
    grd_region_ens = np.zeros([
        settings['num_ens'],
        len(regions_for_selection['id']),
        len(settings['years'])
    ])
    grd_basin_ens = np.zeros([
        settings['num_ens'],
        len(basin_mask['basins']),
        len(settings['years'])
    ])
    for ens in range(settings['num_ens']):
        print('   Ensemble ' + str(ens))
        GRD_rsl_ens = read_GRD_rsl_ens(ens, settings)
        for region in range(len(regions_for_selection['id'])):
            grd_region_ens[
                ens, region, :] = GRD_rsl_ens[:, regions_for_selection[
                    'grd_sample_points'][
                        region,
                        0], regions_for_selection['grd_sample_points'][region,
                                                                       1]]
        for basin in range(len(basin_mask['basins'])):
            grd_basin_ens[ens, basin, :] = (
                (area *
                 (basin_mask['num'] == basin))[np.newaxis, :, :] * GRD_rsl_ens
            ).sum(axis=(1, 2)) / (area * (basin_mask['num'] == basin)).sum()
    grd_basin = (GIA['probability'][:, np.newaxis, np.newaxis] *
                 grd_basin_ens).sum(axis=0)
    grd_region = (GIA['probability'][:, np.newaxis, np.newaxis] *
                  grd_region_ens).sum(axis=0)
    for region in range(len(regions_for_selection['id'])):
        regions_for_selection['rsl_grd_mean'][region, :] = grd_region[
            region, :]
        regions_for_selection['rsl_grd_dev'][region] = grd_region[
            region, :] - grd_basin[
                regions_for_selection['basin_num'][region], :]
    return (regions_for_selection)
Exemple #14
0
def compute_indiv_tws(settings):
    indiv_tws = {}

    # Natural: Read Humphrey average
    fn = settings[
        'dir_data'] + 'Hydrology/Humphrey/01_monthly_grids_ensemble_means_allmodels/GRACE_REC_v03_JPL_GSWP3_monthly_ensemble_mean.nc'
    file_handle = Dataset(fn, 'r')
    file_handle.set_auto_mask(False)
    lat = file_handle.variables['lat'][:]
    lon = file_handle.variables['lon'][:]
    time = file_handle.variables['time'][:] / 365.25 + 1901
    load = file_handle.variables['rec_ensemble_mean'][:]
    file_handle.close()
    mask = np.load(settings['fn_mask'], allow_pickle=True).all()

    load = np.dstack([load[:, :, 360:], load[:, :, :360]])
    load[load < -32e4] = 0

    bary_annual = np.zeros(len(settings['years'])) * np.nan

    area = gentools.grid_area(lat, lon)
    for idx, year in enumerate(settings['years']):
        acc_idx = np.floor(time).astype(int) == year
        if acc_idx.sum() > 0:
            bary_annual[idx] = np.nansum(area * mask['tws'] *
                                         load[acc_idx, :, :].mean(axis=0))
    indiv_tws['Humphrey'] = bary_annual / -362e12

    # GWD Wada/Doll
    wada_2016_scale = 0.6  # Scale factor (Wada 2016)
    wada_depletion = np.zeros(len(settings['years'])) * np.nan
    # Old Wada 2010 data
    time_past = np.arange(1900, 1960)
    for idx, yr in enumerate(time_past):
        data_raw = np.loadtxt(settings['dir_gwd_20c'] + 'gwd0' + str(yr) +
                              '.asc',
                              skiprows=6)
        data_raw[data_raw == -9999] = 0
        data_raw = np.flipud(data_raw)
        data_raw = np.hstack([data_raw[:, 360:], data_raw[:, 0:360]])
        wada_depletion[idx] = data_raw.sum() * 1e9
    # Present (Wada 2014)
    file_handle = Dataset(settings['fn_gwd_wada'], 'r')
    file_handle.set_auto_mask(False)
    depletion_pd_monthly = file_handle.variables["anrg"][:]
    depletion_pd_monthly[depletion_pd_monthly < 0] = 0
    file_handle.close()
    time_pd_m = gentools.monthly_time(1960, 2010)
    time_present = np.arange(1960, 2011)
    # To normal grid
    depletion_rate_monthly = np.fliplr(depletion_pd_monthly)
    depletion_rate_monthly = np.dstack([
        depletion_rate_monthly[:, :, 360:], depletion_rate_monthly[:, :, 0:360]
    ])
    for idx, yr in enumerate(time_present):
        idx_m = (time_pd_m > yr) & (time_pd_m < yr + 1)
        wada_depletion[idx + 60] = (np.sum(depletion_rate_monthly[idx_m, :, :],
                                           axis=0)).sum() * 1e9
    indiv_tws['Wada'] = wada_2016_scale * np.cumsum(wada_depletion) / 362e12

    ### DOLL
    file_handle = Dataset(settings['fn_gwd_doll_irr'], 'r')
    file_handle.set_auto_mask(False)
    time = 1960 + file_handle.variables['time'][:] / 12 + 1 / 24
    tws_irr = file_handle.variables['TWS_mm'][:]
    tws_irr[tws_irr < -9998] = np.nan
    file_handle.close()

    tws_nouse = Dataset(settings['fn_gwd_doll_nouse'],
                        'r').variables['TWS_mm'][:]._get_data()
    tws_nouse[tws_nouse < -9998] = np.nan

    # To 0-360
    tws_irr = np.dstack([tws_irr[:, :, 360:], tws_irr[:, :, :360]])
    tws_nouse = np.dstack([tws_nouse[:, :, 360:], tws_nouse[:, :, :360]])

    # Depletion in irrigated minus natural
    tws_doll = tws_irr - tws_nouse

    mask = np.load(settings['fn_mask'], allow_pickle=True).all()
    mask_tws = (mask['land']) & (~mask['AIS']) & (~mask['GrIS'])

    doll_depletion = np.zeros(len(settings['years'])) * np.nan

    # To annual
    tws_doll[:, ~mask_tws] = 0
    tws_doll[np.isnan(tws_doll)] = 0
    time_ann_doll = np.arange(1960, 2010, 1)
    for idx, t in enumerate(time_ann_doll):
        acc_t = (np.floor(time).astype(int) == t)
        doll_depletion[idx +
                       60] = (area *
                              (tws_doll[acc_t, :, :].mean(axis=0))).sum()
    indiv_tws['Doll'] = doll_depletion / -362e12

    #################### Dams
    print('   Reading spreadsheets...')
    chao_list_raw = pd.read_excel(settings['fn_chao_list'],
                                  header=None).values  # Read Chao list
    chao_loc_raw = pd.read_excel(settings['fn_chao_loc'],
                                 header=None).values  # Read Chao locs
    lehner_raw = pd.read_excel(settings['fn_lehner'],
                               header=None).values  # Read Lehner locs

    # name lat lon year cap loc_avail
    dam_list_grand = np.zeros([len(lehner_raw), 6], dtype=object)
    print('   Processing GRanD list...')
    lehner_raw[:, 2][
        lehner_raw[:, 2] < 0] = lehner_raw[:, 2][lehner_raw[:, 2] < 0] + 360
    for i in range(len(lehner_raw)):
        dam_list_grand[i, 0] = lehner_raw[i, 1].split('(')[0].lower().replace(
            " ", "")
        dam_list_grand[i, 1] = lehner_raw[i, 3]
        dam_list_grand[i, 2] = lehner_raw[i, 2]
        dam_list_grand[i, 3] = lehner_raw[i, 7]
        dam_list_grand[i, 4] = lehner_raw[i, 6] * 1000
        dam_list_grand[i, 5] = True
    dam_list_grand = dam_list_grand[dam_list_grand[:, 4] > 0, :]

    print('   Processing Ben Chaos location list...')
    # --------------------------------------------------------------
    # GRanD list and Benjamin Chao's location list have overlap
    # Challenge: find dams that are in Chao's list, but not in GRanD
    # These dams have a known lat/lon location
    # --------------------------------------------------------------
    dam_list_chao_loc = []
    chao_loc_raw[:, 6][chao_loc_raw[:, 6] <
                       0] = chao_loc_raw[:, 6][chao_loc_raw[:, 6] < 0] + 360
    for i in range(len(chao_loc_raw)):
        dam_list_lcl = np.zeros(6, dtype=object)
        dam_list_lcl[0] = chao_loc_raw[i, 2].split('(')[0].lower().replace(
            " ", "")
        diff_score = np.zeros(len(dam_list_grand))
        for lcl in range(len(diff_score)):
            diff_score[lcl] = Levenshtein.ratio(dam_list_lcl[0],
                                                dam_list_grand[lcl, 0])
            vol_ratio = chao_loc_raw[i, 3] / (dam_list_grand[lcl, 4])
            if (vol_ratio < 0.5) | (vol_ratio > 2):
                diff_score[
                    lcl] = -1  # If capacity is vastly different, probably different dam
            if np.abs(chao_loc_raw[i, 4] - dam_list_grand[lcl, 3]) > 2:
                diff_score[
                    lcl] = -1  # If year of construction is vastly different, probably different dam
        if np.max(diff_score) < 0.9:
            dam_list_lcl[1] = chao_loc_raw[i, 5]
            dam_list_lcl[2] = chao_loc_raw[i, 6]
            dam_list_lcl[3] = chao_loc_raw[i, 4]
            dam_list_lcl[4] = chao_loc_raw[i, 3]
            dam_list_lcl[5] = True
            dam_list_chao_loc.append(dam_list_lcl)
    dam_list_chao_loc = np.array(dam_list_chao_loc)
    dam_list_loc = np.vstack([dam_list_grand, dam_list_chao_loc])

    # --------------------------------------------------------------
    # GRanD list and Benjamin Chao's location list have overlap
    # Challenge: find dams that are in Chao's list, but not in GRanD
    # These dams don't have a known lat/lon location
    # --------------------------------------------------------------
    print('   Processing Ben Chaos full list...')
    dam_list_chao_full = []
    for i in range(len(chao_list_raw)):
        if chao_list_raw[i, 3] > 1000:
            dam_list_lcl = np.zeros(6, dtype=object)
            dam_list_lcl[0] = chao_list_raw[i,
                                            2].split('(')[0].lower().replace(
                                                " ", "")
            diff_score = np.zeros(len(dam_list_loc))
            for lcl in range(len(dam_list_loc)):
                diff_score[lcl] = Levenshtein.ratio(dam_list_lcl[0],
                                                    dam_list_loc[lcl, 0])
            if np.max(diff_score) < 0.7:
                dam_list_lcl[3] = chao_list_raw[i, 4]
                dam_list_lcl[4] = chao_list_raw[i, 3]
                dam_list_lcl[5] = False
                dam_list_chao_full.append(dam_list_lcl)
    dam_list_chao_full = np.array(dam_list_chao_full)
    dam_list = np.vstack(
        [dam_list_grand, dam_list_chao_loc, dam_list_chao_full])

    # From 1000 m3 to kg
    dam_list[:, 4] = dam_list[:, 4] * 1e6
    dam_years = np.arange(1800, 2019, 1)

    # Index for dams with known locations
    nlocs = np.sum(dam_list[:, 5])
    dam_load_list = np.zeros([nlocs, len(dam_years)])
    no_seepage = [
        'manicouagan', 'jenpeg', 'smallwoodreservoir', 'missifallscontrol',
        'earfalls', 'whitesandrapids', 'pipmuacan', 'keenleyside', 'sanhezha',
        'tainionkoski', 'irkutsk', 'verkhnetulomskaya', 'ondakumskaya',
        'verkhnesvirskaya', 'structure308'
    ]

    # Total volumes
    print('   Computing storage and seepage...')
    total_volume = np.zeros(
        len(dam_years))  # Total water in dam assuming 85% full
    total_scaled = np.zeros(
        len(dam_years))  # Total water in dam assuming 85% full
    total_seepage = np.zeros(
        len(dam_years))  # Total TWS due to seepage after dam construction
    total_storage = np.zeros(
        len(dam_years))  # Total TWS due to water in dam and seepage
    for i in range(len(dam_list)):
        local_volume = np.zeros(len(dam_years))
        local_seepage = np.zeros(len(dam_years))
        if (dam_list[i, 3] > 1799) & (dam_list[i, 3] < 2004):
            startindex = int(dam_list[i, 3] - 1800)
        else:
            startindex = 0
        local_volume[startindex:] = dam_list[i, 4] * 0.85
        seepage_growth = np.minimum(
            np.cumsum(1 / np.sqrt(dam_years[startindex + 1:] -
                                  (dam_years[startindex]))), 20)
        local_seepage[startindex + 1:] = dam_list[i, 4] * 0.05 * seepage_growth
        total_scaled = total_scaled + local_volume
        total_seepage = total_seepage + local_seepage
        if dam_list[i, 0] in no_seepage:
            local_storage = local_volume
        else:
            local_storage = local_seepage + local_volume
        total_storage = total_storage + local_storage
        total_volume = total_volume + local_volume / 0.85

    indiv_tws['Chao'] = -total_storage[100:] / 362e12
    for model in indiv_tws:
        indiv_tws[model] -= indiv_tws[model][103:108].mean()

    full_ens = np.zeros([settings['num_ens'], len(settings['years'])])
    for ens in range(settings['num_ens']):
        full_ens[ens, :] = Dataset(
            settings['dir_data'] + 'Budget_20c/grd/grd_tws_' + str(ens) +
            '.nc', 'r').variables['barystatic'][:]._get_data()
    ts_full = ensemble_ts(full_ens, settings)
    indiv_tws['GRACE'] = np.zeros(len(settings['years'])) * np.nan
    indiv_tws['GRACE'][103:] = ts_full[103:, 1]
    indiv_tws['full'] = ts_full
    return (indiv_tws)