def minimize_dl(tbias, mb, fls, dl, len2003, gdir, optimization, runsuffix=''): # Mass balance mb.temp_bias = tbias model = FluxBasedModel(fls, mb_model=mb) try: model.run_until_equilibrium(ystep=10, max_ite=200) except FloatingPointError: if optimization is True: log.info('(%s) tbias of %.2f gave length: %.2f' % (gdir.rgi_id, tbias, model.length_m)) return len2003**2 else: raise RuntimeError('This should never happen...') except RuntimeError as err: if (optimization is True) and\ ('Glacier exceeds domain boundaries' in err.args[0]): log.info('(%s) tbias of %.2f exceeds domain boundaries' % (gdir.rgi_id, tbias)) return len2003**2 elif (optimization is True) and \ ('Did not find equilibrium' in err.args[0]): log.info('(%s) tbias of %.2f did exceed max iterations' % (gdir.rgi_id, tbias)) return len2003**2 elif 'CFL error' in err.args[0]: log.info('(%s) tbias of %.2f leads to CFL error' % (gdir.rgi_id, tbias)) print(err) return len2003**2 else: print(err) raise RuntimeError('This should never happen 2...') if optimization is True: if model.length_m < fls[-1].dx_meter: log.info('(%s) tbias of %.2f gave length: %.2f' % (gdir.rgi_id, tbias, model.length_m)) return len2003**2 dl_spinup = model.length_m - len2003 delta = (dl - dl_spinup)**2 print('%s: tbias: %.2f delta: %.4f' % (gdir.rgi_id, tbias, delta)) return delta else: filesuffix = '_spinup' + runsuffix run_path = gdir.get_filepath('model_run', filesuffix=filesuffix, delete=True) diag_path = gdir.get_filepath('model_diagnostics', filesuffix=filesuffix, delete=True) model2 = FluxBasedModel(fls, mb_model=mb) model2.run_until_and_store(model.yr, run_path=run_path, diag_path=diag_path)
def test_limiter(self, default_calving): _, ds1, df_diag1 = default_calving model = FluxBasedModel(bu_tidewater_bed(), mb_model=ScalarMassBalance(), is_tidewater=True, calving_use_limiter=False, flux_gate=0.06, do_kcalving=True, calving_k=0.2) _, ds2 = model.run_until_and_store(3000) df_diag2 = model.get_diagnostics() assert_allclose(model.volume_m3 + model.calving_m3_since_y0, model.flux_gate_m3_since_y0) assert_allclose(ds2.calving_m3[-1], model.calving_m3_since_y0) # Not exact same of course assert_allclose(ds1.volume_m3[-1], ds2.volume_m3[-1], rtol=0.06) assert_allclose(ds1.calving_m3[-1], ds2.calving_m3[-1], rtol=0.15) if do_plot: f, ax = plt.subplots(1, 1, figsize=(12, 5)) df_diag1[['surface_h']].plot(ax=ax, color=['C3']) df_diag2[['surface_h', 'bed_h']].plot(ax=ax, color=['C1', 'k']) plt.hlines(0, 0, 60000, color='C0', linestyles=':') plt.ylim(-350, 800) plt.ylabel('Altitude [m]') plt.show()
def test_run_until_and_store(self): fls = dummy_constant_bed() mb = LinearMassBalance(2600.) model = FluxBasedModel(fls, mb_model=mb) ds_f, ds_d = model.run_until_and_store(150) assert ds_d['length_m'][-1] > 1e3 df = model.get_diagnostics() assert (df['ice_velocity'].max() * cfg.SEC_IN_YEAR) > 10
def default_calving(): cfg.initialize() model = FluxBasedModel(bu_tidewater_bed(), mb_model=ScalarMassBalance(), is_tidewater=True, calving_use_limiter=True, flux_gate=0.06, do_kcalving=True, calving_k=0.2) _, ds = model.run_until_and_store(3000) df_diag = model.get_diagnostics() assert_allclose(model.volume_m3 + model.calving_m3_since_y0, model.flux_gate_m3_since_y0) assert_allclose(ds.calving_m3[-1], model.calving_m3_since_y0) return model, ds, df_diag
def test_water_level(self, default_calving): _, ds_1, _ = default_calving model = FluxBasedModel(bu_tidewater_bed(water_level=1000), mb_model=ScalarMassBalance(), is_tidewater=True, calving_use_limiter=True, flux_gate=0.06, do_kcalving=True, calving_water_level=1000, calving_k=0.2) _, ds_2 = model.run_until_and_store(3000) assert_allclose(model.volume_m3 + model.calving_m3_since_y0, model.flux_gate_m3_since_y0) assert_allclose(ds_1.calving_m3, ds_2.calving_m3) if do_plot: df_diag = model.get_diagnostics() f, ax = plt.subplots(1, 1, figsize=(12, 5)) df_diag[['surface_h', 'bed_h']].plot(ax=ax, color=['C3', 'k']) plt.hlines(1000, 0, 60000, color='C0', linestyles=':') plt.ylim(1000 - 350, 1000 + 800) plt.ylabel('Altitude [m]') plt.show() # Let the model decide the water level fls = bu_tidewater_bed(water_level=1000) thick = fls[0].thick thick[fls[0].bed_h > 1000] = 1 fls[0].thick = thick model = FluxBasedModel(fls, mb_model=ScalarMassBalance(), is_tidewater=True, calving_use_limiter=True, is_lake_terminating=True, flux_gate=0.06, do_kcalving=True, calving_k=0.2) assert_allclose(model.water_level, 1000, atol=1) with pytest.raises(InvalidParamsError): fls = bu_tidewater_bed(water_level=1000) FluxBasedModel(fls, mb_model=ScalarMassBalance(), is_tidewater=True, calving_use_limiter=True, is_lake_terminating=True)
def progress_to_year(self, year): """Progress the glacier to year n. Parameters ---------- year: int Year until which to progress the glacier. """ # Some checks on the year. if year < 0: raise ValueError("Year has to be above zero") elif year <= self.age: warnings.warn( "Year has to be above the current age of" + " the glacier. It is not possible to" + " de-age the glacier." + " Geometry will remain." ) # If all passes else: # Check if we have a current state already. state = self._state() # Initialise the model model = FluxBasedModel( state, mb_model=self.mass_balance, y0=self.age, glen_a=self.creep, fs=self.basal_sliding, ) # Run the model. Store the history. try: out = model.run_until_and_store(year, fl_diag_path=None) # If it fails, see above. except RuntimeError: print("Glacier grew out of its domain, stepping back five years") # Ohhh recursion self.progress_to_year(year - 5) return # Update attributes. self.history = out[0] self.state_history = out[1][0] self._current_state = model.fls[0] self._model_state = model self.age = model.yr
def plot_length(gdir, plot_dir, t0, te): reconstruction = gdir.read_pickle('reconstruction_output') experiment = gdir.read_pickle('synthetic_experiment') surface_t0 = pd.DataFrame() widths_t0 = pd.DataFrame() surface_t = pd.DataFrame() widths_t = pd.DataFrame() fls_t0 = pd.DataFrame() for rec in reconstruction: if rec[0] != None: # surface surface_t0 = surface_t0.append([rec[0].fls[-1].surface_h], ignore_index=True) surface_t = surface_t.append([rec[1].fls[-1].surface_h], ignore_index=True) widths_t0 = widths_t0.append([rec[0].fls[-1].widths], ignore_index=True) widths_t = widths_t.append([rec[1].fls[-1].widths], ignore_index=True) fls_t0 = fls_t0.append({ 'model': rec[0], 'length': rec[0].length_m }, ignore_index=True) past_climate = PastMassBalance(gdir) plt.figure(figsize=(25, 15)) for i in np.arange(0, 30, 1): fls = gdir.read_pickle('model_flowlines') try: fls[-1].surface_h = surface_t0.iloc[i].values past_model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) a, b = past_model.run_until_and_store(te) plt.plot(b.length_m.to_series().rolling(36, center=True).mean(), alpha=0.3, color='grey', label='') except: pass # mean plot fls = gdir.read_pickle('model_flowlines') fls[-1].surface_h = surface_t0.median(axis=0).values past_model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) a, b = past_model.run_until_and_store(te) plt.plot(b.length_m.to_series().rolling(36, center=True).mean(), linewidth=3, label='median') #objective plot # calculate objective diff_s = surface_t.subtract(experiment['y_t'].fls[-1].surface_h, axis=1)**2 diff_w = widths_t.subtract(experiment['y_t'].fls[-1].widths, axis=1)**2 objective = diff_s.sum(axis=1) + diff_w.sum(axis=1) min_id = objective.argmin(axis=0) fls = gdir.read_pickle('model_flowlines') fls[-1].surface_h = surface_t0.iloc[min_id].values past_model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) a, b = past_model.run_until_and_store(te) plt.plot(b.length_m.to_series().rolling(36, center=True).mean(), 'r', linewidth=3, label='best objective') # experiment plot fls = gdir.read_pickle('synthetic_experiment')['y_t0'].fls past_climate = PastMassBalance(gdir) past_model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) a, b = past_model.run_until_and_store(te) #plt.plot(b.length_m.to_series().rolling(36, center=True).mean(), 'k:', linewidth=3, # label='experiment') fls = gdir.read_pickle('model_flowlines') past_model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) plt.plot([2000], [past_model.length_m], 'o') if gdir.name != "": plt.title(gdir.rgi_id + ': ' + gdir.name, fontsize=25) else: plt.title(gdir.rgi_id, fontsize=25) plt.ylabel('Glacier Lenght Change (m) ', fontsize=25) plt.xlabel('Time', fontsize=25) plt.legend(loc='best', fontsize=25) plt.xlim((t0, te)) plt.tick_params(axis='both', which='major', labelsize=25) plt.savefig(os.path.join(plot_dir, 'lengths_RGI50-11-00687.pdf'), dpi=200) #try: df = gdir.get_ref_length_data() df = df.loc[1855:2000]['dL'] df = df - df.iloc[-1] + past_model.length_m plt.plot(df, 'k', linewidth=3, label='real observations') fls = gdir.read_pickle('model_flowlines') past_model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) a, b = past_model.run_until_and_store(te) plt.plot(b.length_m.to_series().rolling(36, center=True).mean(), linewidth=3, label='default initial state') plt.legend(loc='best', fontsize=25) plt.savefig(os.path.join(plot_dir, 'lengths_RGI50-11-00687_obs.pdf'), dpi=200) #except: # pass plt.show() return
plt.axvline(x=yr, color='k') best_id = result['objective_' + str(yr + 50)].idxmin() list = result['objective_' + str(yr + 50)].dropna().index if not best_id in list: list = list.append(pd.Index([best_id])) for i in list: fls = deepcopy(result[str(yr)].dropna().loc[i].fls) past_climate = PastMassBalance(gdir) model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=yr) if i == best_id: plt.plot(model.yr, model.length_m, 'ro') a, b = model.run_until_and_store(yr + 50) b.length_m.plot(color='red') plt.plot(model.yr, model.length_m, 'bo') else: a, b = model.run_until_and_store(yr + 50) b.length_m.plot(color='grey', alpha=0.3) if yr == 1850: a, b = model.run_until_and_store(2000) b.length_m.plot(linestyle=':', color='red') plt.xlim((1850, 2000)) plt.show() ''' plt.figure(1)
def plot_length_change(gdir, plot_dir, t0, te, synthetic_exp=True): plot_dir = os.path.join(plot_dir, 'length_change') if not os.path.exists(plot_dir): os.makedirs(plot_dir) reconstruction = gdir.read_pickle('reconstruction_output') surface_t0 = pd.DataFrame() for rec in reconstruction: if rec[0] != None: # surface surface_t0 = surface_t0.append([rec[0].fls[-1].surface_h], ignore_index=True) past_climate = PastMassBalance(gdir) fig = plt.figure(figsize=(25, 15)) ax = fig.add_subplot(111) for i in np.arange(0, 5, 1): #fls = gdir.read_pickle('model_flowlines') if reconstruction[i][0] != None: fls = copy.deepcopy(reconstruction[i][0].fls) past_model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) a, b = past_model.run_until_and_store(te) (b.length_m.rolling(time=36, center=True).mean() - b.length_m[-1]).plot(ax=ax, alpha=0.3, color='grey', label='') # median plot fls = copy.deepcopy(gdir.read_pickle('model_flowlines')) fls[-1].surface_h = surface_t0.median(axis=0).values past_model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) a, b = past_model.run_until_and_store(te) (b.length_m.rolling(time=36, center=True).mean() - b.length_m[-1]).plot( ax=ax, linewidth=3, label='median') #objective plot # calculate objective if synthetic_exp: experiment = gdir.read_pickle('synthetic_experiment') df, min_id = find_best_objective(gdir, experiment['y_t'].fls, 1865, 2000) else: df, min_id = find_best_objective(gdir, fls, 1865, 2000) fls = copy.deepcopy(df.loc[min_id, '1865'].fls) past_model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) a, b = past_model.run_until_and_store(te) (b.length_m.rolling(time=36, center=True).mean() - b.length_m[-1]).plot( ax=ax, color='red', linewidth=3, label='best objective') fls = gdir.read_pickle('model_flowlines') past_model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) if synthetic_exp: # experiment plot fls = copy.deepcopy( gdir.read_pickle('synthetic_experiment')['y_t0'].fls) past_climate = PastMassBalance(gdir) past_model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) a, b = past_model.run_until_and_store(te) (b.length_m.rolling(time=36, center=True).mean() - b.length_m[-1]).plot(ax=ax, color='k', linestyle=':', linewidth=3, label='experiment') else: try: df = gdir.get_ref_length_data() df = df.loc[1855:2000]['dL'] df = df - df.iloc[-1] df = df.reset_index().set_index('years') df = df.rename(columns={'dL': 'real observations'}) df.plot(ax=ax, use_index=True, color='k', linewidth=3, label='real observations') except: pass fls = gdir.read_pickle('model_flowlines') past_model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) fls = gdir.read_pickle('model_flowlines') past_model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) a, b = past_model.run_until_and_store(te) (b.length_m.rolling(time=36, center=True).mean() - b.length_m[-1]).plot( ax=ax, linewidth=3, label='default initial state') plt.legend(loc='best', fontsize=30) if gdir.name != "": ax.set_title(gdir.rgi_id + ': ' + gdir.name, fontsize=30) else: ax.set_title(gdir.rgi_id, fontsize=30) ax.set_xlabel('Time', fontsize=35) ax.legend(loc='best', fontsize=30) plt.xlim((t0, te)) plt.tick_params(axis='both', which='major', labelsize=35) ax.set_ylabel('Glacier Length Change (m) ', fontsize=35) plt.savefig(os.path.join(plot_dir, 'lengths_change_' + str(gdir.rgi_id) + '.png'), dpi=300) return
def progress_to_equilibrium(self, years=2500, t_rate=0.0001): """Progress the glacier to equilibrium. Parameters ---------- years : int, optional Specify the number of years during which we try to find an equilibrium state. t_rate : float, optional Specify how slow the glacier is allowed to change without reaching equilibrium. """ def stop_function(model, previous_state): """Function to stop the simulation when equilbrium is reached. Basically a re-shape of the criterium of run_until_equilibrium.""" # We don't stop unless stop = False # Ambigous rate, basically how fast is the glacier # changing every step. rate = t_rate # How many times to we try max_ite = years # If we have a previous step check it if previous_state is not None: # Here we save some stuff to diagnose the eq. state # If this is true, we update the state: if ( (previous_state["t_rate"] > rate) and (previous_state["ite"] <= max_ite) and (previous_state["was_close_zero"] < 5) ): # Increase iterations. previous_state["ite"] += 1 # Get the current volume v_af = model.volume_m3 # If volume before is close to zero, update counter. if np.isclose(previous_state["v_bef"], 0, atol=1): previous_state["was_close_zero"] += 1 previous_state["t_rate"] = 1 # If not close to zero, update how slow volume is updating. else: previous_state["t_rate"] = ( np.abs(v_af - previous_state["v_bef"]) / previous_state["v_bef"] ) previous_state["v_bef"] = v_af # If we go over the iteration limit. elif previous_state["ite"] > max_ite: # raise RuntimeError('Not able to find equilbrium') print(f"Not able to find equilibrium within {years} years") stop = True # Otherwise we stop. else: stop = True # If we don't have a previous state, define it. else: # Dictionary containing the stuff we need. previous_state = { "ite": 0, "was_close_zero": 0, "t_rate": 1, "v_bef": model.volume_m3, } return stop, previous_state # Do we have a future temperature changes assigned? if self.age < self.mass_balance._temp_bias_series.year.iloc[-1]: # If so, progress normally until finished. self.progress_to_year(self.mass_balance._temp_bias_series.year.iloc[-1]) # Then we can find the eq. state. # Initialise the model state = self._state() model = FluxBasedModel( state, mb_model=self.mass_balance, y0=self.age, glen_a=self.creep, fs=self.basal_sliding, ) # Run the model. try: # Run with a stopping criteria. out = model.run_until_and_store( years, fl_diag_path=None, stop_criterion=stop_function ) except RuntimeError: # We chose to print and return instead of raising since the # collection will then be able to continue. print( "Glacier grew out of its domain before reaching an equilibrium state." ) return # Update attributes. self.history = out[0] self.state_history = out[1][0] self._current_state = model.fls[0] self.age = model.yr self._model_state = model # Remember the eq. year self._eq_states[self.age] = self.mass_balance.ela_h
def progress_to_year(self, year): """Progress the surging glacier to specified year. This will progress the glacier in periods of surging and not surging, specified by the `normal_years` and `surging_years` attributes. Parameters ---------- year : int Which year to progress the surging glacier. """ # Check if the glacier has a masss balance model if not self.mass_balance: string = ( "To evolve the glacier it needs a mass balance." + "\nMake sure the ELA and mass balance gradient" + " are defined." ) raise NotImplementedError(string) # Some checks on the year. elif year < 0: raise ValueError("Year has to be above zero") elif year <= self.age: warnings.warn( "Year has to be above the current age of" + " the glacier. It is not possible to" + " de-age the glacier." + " Geometry will remain." ) # If all passes else: # How many years to have left to simulate years_left = year - self.age # While we have years to run we do the following... while years_left: # Check if we have a current state already. state = self._state() # If in a normal period if self._normal_period: # How many years should we run? # We either run for the normal period amount of # yeasrs. Or for the years left we have left. # or the normal years left from a previous run. years_to_run = np.min( [ years_left, self.normal_years, self._normal_years_left, ] ) # Cast to int years_to_run = int(years_to_run + self.age) # Update normal_years_left self._normal_years_left -= years_to_run - self.age # If we have no normal years left we change state. if self._normal_years_left == 0: # Re-set it self._normal_years_left = self.normal_years # Not normal anymore self._normal_period = not self._normal_period # Initialise the model, width the normal basal_slidng model = FluxBasedModel( state, mb_model=self.mass_balance, y0=self.age, glen_a=self.creep, fs=self.basal_sliding, ) # Run the model. Store the history. try: out = model.run_until_and_store(years_to_run, fl_diag_path=None) except RuntimeError: print("Glacier outgrew its domain and had to stop.") # We should break here. break # If we are not in normal state, we do a surging period. else: # How many years should we run? # Same as above but now we run for surging period amount # of years. years_to_run = np.min( [ years_left, self.surging_years, self._surging_years_left, ] ) # Cast to int years_to_run = int(years_to_run + self.age) # Update surging years left self._surging_years_left -= years_to_run - self.age # If there are no surging years left, we change state if self._surging_years_left == 0: # Re-set self._surging_years_left = self.surging_years # Not surging anymore self._normal_period = not self._normal_period # Initialise the model, with the surging basal_sliding model = FluxBasedModel( state, mb_model=self.mass_balance, y0=self.age, glen_a=self.creep, fs=self.basal_sliding_surge, ) # Run the model. Store the history. try: out = model.run_until_and_store(years_to_run, fl_diag_path=None) except RuntimeError: print("Glacier outgrew its domain and had to stop.") # We should break here. break # Update attributes. self.history = out[0] self.state_history = out[1][0] self._current_state = model.fls[0] self._model_state = model self.age = model.yr # Check where we are years_left = year - self.age
def evolve_glacier_and_create_measurements(gdir, used_mb_models, yr_start_run, yr_spinup, yr_end_run): """TODO """ fls_spinup = gdir.read_pickle('model_flowlines', filesuffix='_spinup') yr_rgi = gdir.rgi_date # now start actual experiment run for the creation of measurements if used_mb_models == 'constant': halfsize_spinup = (yr_start_run - yr_spinup) / 2 mb_spinup = MultipleFlowlineMassBalance( gdir, fls=fls_spinup, mb_model_class=ConstantMassBalance, filename='climate_historical', input_filesuffix='', y0=yr_spinup + halfsize_spinup, halfsize=halfsize_spinup) halfsize_run = (yr_end_run - yr_start_run) / 2 mb_run = MultipleFlowlineMassBalance( gdir, fls=fls_spinup, mb_model_class=ConstantMassBalance, filename='climate_historical', input_filesuffix='', y0=yr_start_run + halfsize_run, halfsize=halfsize_run) # save used massbalance models for combine mb_models_combine = { 'MB1': { 'type': 'constant', 'years': np.array([yr_spinup, yr_start_run]) }, 'MB2': { 'type': 'constant', 'years': np.array([yr_start_run, yr_end_run]) } } gdir.write_pickle(mb_models_combine, 'inversion_input', filesuffix='_combine_mb_models') else: raise NotImplementedError(f'{used_mb_models}') # do spinup period before first measurement model = FluxBasedModel(copy.deepcopy(fls_spinup), mb_spinup, y0=yr_spinup) model.run_until_and_store(yr_start_run, diag_path=gdir.get_filepath( 'model_diagnostics', filesuffix='_combine_spinup')) # get measurements for dhdt dh_volume = [None, None] dh_area = [None, None] dh_volume[0] = model.volume_m3 dh_area[0] = model.area_m2 # switch to mb_run and run to rgi_date and save measurements and flowline model = FluxBasedModel(copy.deepcopy(model.fls), mb_run, y0=yr_start_run) model.run_until(yr_rgi) gdir.write_pickle(model.fls, 'model_flowlines', filesuffix='_combine_true_init') rgi_date_area_km2 = model.area_km2 rgi_date_volume_km3 = model.volume_km3 rgi_date_us_myr = model.u_stag[0] * model._surf_vel_fac * SEC_IN_YEAR # now run to the end for dhdt model.run_until_and_store(yr_end_run, diag_path=gdir.get_filepath( 'model_diagnostics', filesuffix='_combine_end')) gdir.write_pickle(model.fls, 'model_flowlines', filesuffix='_combine_true_end') dh_volume[1] = model.volume_m3 dh_area[1] = model.area_m2 # calculate dh dh_m = (dh_volume[1] - dh_volume[0]) / \ ((dh_area[1] + dh_area[0]) / 2.) # save measurements in gdir all_measurements = { 'dh:m': { '2000-2019': dh_m }, 'area:km2': { str(yr_rgi): rgi_date_area_km2 }, 'volume:km3': { str(yr_rgi): rgi_date_volume_km3 }, 'us:myr-1': { str(yr_rgi): rgi_date_us_myr }, } gdir.write_pickle(all_measurements, 'inversion_input', filesuffix='_combine_measurements')