def test_signchange(self): ts = pd.Series([-2., -1., 1., 2., 3], index=np.arange(5)) sc = utils.signchange(ts) assert_array_equal(sc, [0, 0, 1, 0, 0]) ts = pd.Series([-2., -1., 1., 2., 3][::-1], index=np.arange(5)) sc = utils.signchange(ts) assert_array_equal(sc, [0, 0, 0, 1, 0])
def t_star_from_refmb(gdir, mbdf): """Computes the t* for the glacier, given a series of MB measurements. Could be multiprocessed but its probably not necessary. Parameters ---------- gdirs: the list of oggm.GlacierDirectory objects where to write the data. mbdf: a pd.Series containing the observed MB data indexed by year Returns ------- A dict: {t_star:[], bias:[], bias_std:[], prcp_fac:float} """ # Only divide 0, we believe the original RGI entities to be the ref... years, temp_yr_ts, prcp_yr_ts = mb_yearly_climate_on_glacier(gdir, 1., div_id=0) # which years to look at selind = np.searchsorted(years, mbdf.index) temp_yr_ts = temp_yr_ts[selind] prcp_yr_ts = prcp_yr_ts[selind] temp_yr = np.mean(temp_yr_ts) prcp_yr = np.mean(prcp_yr_ts) # Average oberved mass-balance ref_mb = np.mean(mbdf) ref_mb_std = np.std(mbdf) # Average mass-balance per mu and fac mu_yr_clim_df = gdir.read_pickle('mu_candidates', div_id=0) odf = pd.DataFrame(index=mu_yr_clim_df.columns) out = dict() for prcp_fac in mu_yr_clim_df: mu_yr_clim = mu_yr_clim_df[prcp_fac] nmu = len(mu_yr_clim) mb_per_mu = prcp_yr * prcp_fac - mu_yr_clim * temp_yr mbts_per_mu = np.atleast_2d(prcp_yr_ts * prcp_fac).repeat(nmu, 0) - \ np.atleast_2d(mu_yr_clim).T * \ np.atleast_2d(temp_yr_ts).repeat(nmu, 0) std_per_mu = mb_per_mu*0 + np.std(mbts_per_mu, axis=1) # Diff to reference diff = (mb_per_mu - ref_mb).dropna() diff_std = (std_per_mu - ref_mb_std).dropna() signchange = utils.signchange(diff) # If sign changes save them # TODO: ideas to do this better: # - apply a smooth (take noise into account) # - take longer stable periods into account # these stuffs could be proven better (or not) with cross-val pchange = np.where(signchange == 1)[0] years = diff.index diff = diff.values diff_std = diff_std.values if len(pchange) > 0: t_stars = [] bias = [] std_bias = [] for p in pchange: # Check the side with the smallest bias ide = p-1 if np.abs(diff[p-1]) < np.abs(diff[p]) else p if years[ide] not in t_stars: t_stars.append(years[ide]) bias.append(diff[ide]) std_bias.append(diff_std[ide]) else: amin = np.argmin(np.abs(diff)) t_stars = [years[amin]] bias = [diff[amin]] std_bias = [diff_std[amin]] # (prcp_fac, t_stars, bias, std_bias) odf.loc[prcp_fac, 'avg_bias'] = np.mean(bias) odf.loc[prcp_fac, 'avg_std_bias'] = np.mean(std_bias) odf.loc[prcp_fac, 'n_tstar'] = len(std_bias) out[prcp_fac] = {'t_star': t_stars, 'bias': bias, 'std_bias': std_bias, 'prcp_fac': prcp_fac} # write gdir.write_pickle(odf, 'prcp_fac_optim') # we take the closest result and see later if it needs cleverer handling amin = np.argmin(np.abs(odf.avg_std_bias)) # this gives back an index! return out[amin]
def t_star_from_refmb(gdir, mbdf): """Computes the t* for the glacier, given a series of MB measurements. Could be multiprocessed but its probably not necessary. Parameters ---------- gdirs: the list of oggm.GlacierDirectory objects where to write the data. mbdf: a pd.Series containing the observed MB data indexed by year Returns: -------- (t_star, bias, prcp_fac): lists of t*, their associated bias and a prcp fac """ # Only divide 0, we believe the original RGI entities to be the ref... years, temp_yr_ts, prcp_yr_ts = mb_yearly_climate_on_glacier(gdir, 1., div_id=0) # which years to look at selind = np.searchsorted(years, mbdf.index) temp_yr_ts = temp_yr_ts[selind] prcp_yr_ts = prcp_yr_ts[selind] temp_yr = np.mean(temp_yr_ts) prcp_yr = np.mean(prcp_yr_ts) # Average oberved mass-balance ref_mb = np.mean(mbdf) ref_mb_std = np.std(mbdf) # Average mass-balance per mu and fac mu_yr_clim_df = gdir.read_pickle('mu_candidates', div_id=0) odf = pd.DataFrame(index=mu_yr_clim_df.columns) out = dict() for prcp_fac in mu_yr_clim_df: mu_yr_clim = mu_yr_clim_df[prcp_fac] nmu = len(mu_yr_clim) mb_per_mu = prcp_yr * prcp_fac - mu_yr_clim * temp_yr mbts_per_mu = np.atleast_2d(prcp_yr_ts * prcp_fac).repeat(nmu, 0) - \ np.atleast_2d(mu_yr_clim).T * \ np.atleast_2d(temp_yr_ts).repeat(nmu, 0) std_per_mu = mb_per_mu*0 + np.std(mbts_per_mu, axis=1) # Diff to reference diff = (mb_per_mu - ref_mb).dropna() diff_std = (std_per_mu - ref_mb_std).dropna() signchange = utils.signchange(diff) # If sign changes save them # TODO: ideas to do this better: # - apply a smooth (take noise into account) # - take longer stable periods into account # these stuffs could be proven better (or not) with cross-val pchange = np.where(signchange == 1)[0] years = diff.index diff = diff.values diff_std = diff_std.values if len(pchange) > 0: t_stars = [] bias = [] std_bias = [] for p in pchange: # Check the side with the smallest bias ide = p-1 if np.abs(diff[p-1]) < np.abs(diff[p]) else p if years[ide] not in t_stars: t_stars.append(years[ide]) bias.append(diff[ide]) std_bias.append(diff_std[ide]) else: amin = np.argmin(np.abs(diff)) t_stars = [years[amin]] bias = [diff[amin]] std_bias = [diff_std[amin]] # (prcp_fac, t_stars, bias, std_bias) odf.loc[prcp_fac, 'avg_bias'] = np.mean(bias) odf.loc[prcp_fac, 'avg_std_bias'] = np.mean(std_bias) odf.loc[prcp_fac, 'n_tstar'] = len(std_bias) out[prcp_fac] = t_stars, bias, prcp_fac # write gdir.write_pickle(odf, 'prcp_fac_optim') # we take the closest result and see later if it needs cleverer handling amin = np.argmin(np.abs(odf.avg_std_bias)) # this gives back an index! return out[amin]