def run_model(param, gdir, y_t, random_climate2, t0, te): ''' :param param: temp bias, is changed by optimization :param gdir: oggm.GlacierDirectory :param y_t: oggm.Flowline for the observed state (2000) :param random_climate2: oggm.massbalance.RandomMassBalance :return: 2 oggm.flowline.FluxBasedModels (glacier candidate and predicted glacier model) ''' # run estimated glacier with random climate 2 until equilibrium # (glacier candidate) # estimated flowline = observed flowline estimated_fls = deepcopy(y_t) climate = deepcopy(random_climate2) # change temp_bias climate.temp_bias = param random_model = FluxBasedModel(estimated_fls, mb_model=climate, y0=t0) random_model.run_until_equilibrium() # run glacier candidate with past climate until 2000 candidate_fls = deepcopy(y_t) for i in range(len(y_t)): candidate_fls[i].surface_h = random_model.fls[i].surface_h past_climate = PastMassBalance(gdir) past_model = FluxBasedModel(candidate_fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) past_model.run_until(te) return [random_model, past_model]
def _run_parallel_experiment(gdir): # read flowlines from pre-processing fls = gdir.read_pickle('model_flowlines') try: # construct searched glacier # TODO: y0 in random mass balance? random_climate1 = RandomMassBalance(gdir, y0=1850, bias=0, seed=[1]) random_climate1.temp_bias = -0.75 commit_model = FluxBasedModel(fls, mb_model=random_climate1, glen_a=cfg.A, y0=1850) commit_model.run_until_equilibrium() y_t0 = deepcopy(commit_model) # try different seed of mass balance, if equilibrium could not be found except: # construct searched glacier random_climate1 = RandomMassBalance(gdir, y0=1850, bias=0,seed=[1]) commit_model = FluxBasedModel(fls, mb_model=random_climate1, glen_a=cfg.A, y0=1850) commit_model.run_until_equilibrium() y_t0 = deepcopy(commit_model) # construct observed glacier past_climate = PastMassBalance(gdir) commit_model2 = FluxBasedModel(commit_model.fls, mb_model=past_climate, glen_a=cfg.A, y0=1850) commit_model2.run_until(2000) y_t = deepcopy(commit_model2) # save output in gdir_dir experiment = {'y_t0': y_t0, 'y_t': y_t, 'climate': random_climate1} gdir.write_pickle(experiment, 'synthetic_experiment')
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 _run_parallel_experiment(gdir, t0, te): ''' :param gdir: :param t0: :param te: :return: ''' # read flowlines from pre-processing fls = gdir.read_pickle('model_flowlines') try: # construct searched glacier random_climate1 = RandomMassBalance(gdir, y0=t0, halfsize=14) #set temp bias negative to force a glacier retreat later random_climate1.temp_bias = -0.75 commit_model = FluxBasedModel(fls, mb_model=random_climate1, glen_a=cfg.A, y0=t0) commit_model.run_until_equilibrium() y_t0 = deepcopy(commit_model) # try different seed of mass balance, if equilibrium could not be found except: # construct searched glacier random_climate1 = RandomMassBalance(gdir, y0=t0, halfsize=14) commit_model = FluxBasedModel(fls, mb_model=random_climate1, glen_a=cfg.A, y0=t0) commit_model.run_until_equilibrium() y_t0 = deepcopy(commit_model) # construct observed glacier past_climate = PastMassBalance(gdir) commit_model2 = FluxBasedModel(commit_model.fls, mb_model=past_climate, glen_a=cfg.A, y0=t0) commit_model2.run_until(te) y_t = deepcopy(commit_model2) # save output in gdir_dir experiment = {'y_t0': y_t0, 'y_t': y_t, 'climate': random_climate1} gdir.write_pickle(experiment, 'synthetic_experiment')
def run_model(param,gdir,fls): fls1 = copy.deepcopy(fls) climate = random_climate2 climate.temp_bias = param model = FluxBasedModel(fls1, mb_model=climate, y0=1890) model.run_until_equilibrium() # fls2= copy.deepcopy(fls) fls2 = model.fls real_model = FluxBasedModel(fls2, mb_model=past_climate, glen_a=cfg.A, y0=1850) real_model.run_until(2000) return [model,real_model]
def spinup_run(t_bias): # with t_bias the glacier state after spinup is changed between iterations mb_spinup.temp_bias = t_bias # run the spinup model_spinup = FluxBasedModel(copy.deepcopy(fls_spinup), mb_spinup, y0=0) model_spinup.run_until_equilibrium(max_ite=1000) # Now conduct the actual model run to the rgi date model_historical = FluxBasedModel(model_spinup.fls, mb_historical, y0=yr_spinup) model_historical.run_until(yr_rgi) cost = (model_historical.length_m - length_m_ref) / length_m_ref * 100 return cost
def run_model(param, gdir, fls, random_climate2): fls1 = copy.deepcopy(fls) climate = random_climate2 climate.temp_bias = param model = FluxBasedModel(fls1, mb_model=climate, y0=1890) model.run_until_equilibrium() fls2 = copy.deepcopy(fls) #fls2 = model.fls for i in range(len(fls)): fls2[i].surface_h = model.fls[i].surface_h real_model = FluxBasedModel(fls2, mb_model=past_climate, glen_a=cfg.A, y0=1850) real_model.run_until(2000) return [model, real_model]
def test_constant_bed(self): map_dx = 100. yrs = np.arange(1, 400, 5) lens = [] volume = [] areas = [] surface_h = [] # Flowline case fls = dummy_constant_bed(hmax=3000., hmin=1000., nx=200, map_dx=map_dx, widths=1.) mb = LinearMassBalance(2600.) flmodel = FluxBasedModel(fls, mb_model=mb, y0=0.) length = yrs * 0. vol = yrs * 0. area = yrs * 0 for i, y in enumerate(yrs): flmodel.run_until(y) length[i] = fls[-1].length_m vol[i] = fls[-1].volume_km3 area[i] = fls[-1].area_km2 lens.append(length) volume.append(vol) areas.append(area) surface_h.append(fls[-1].surface_h.copy()) # Make a 2D bed out of the 1D bed_2d = np.repeat(fls[-1].bed_h, 3).reshape((fls[-1].nx, 3)) sdmodel = Upstream2D(bed_2d, dx=map_dx, mb_model=mb, y0=0., ice_thick_filter=None) length = yrs * 0. vol = yrs * 0. area = yrs * 0 for i, y in enumerate(yrs): sdmodel.run_until(y) surf_1d = sdmodel.ice_thick[:, 1] length[i] = np.sum(surf_1d > 0) * sdmodel.dx vol[i] = sdmodel.volume_km3 / 3 area[i] = sdmodel.area_km2 / 3 lens.append(length) volume.append(vol) areas.append(area) surface_h.append(sdmodel.surface_h[:, 1]) if do_plot: plt.figure() plt.plot(yrs, lens[0], 'r') plt.plot(yrs, lens[1], 'b') plt.title('Compare Length') plt.xlabel('years') plt.ylabel('[m]') plt.legend(['Flowline', '2D'], loc=2) plt.figure() plt.plot(yrs, volume[0], 'r') plt.plot(yrs, volume[1], 'b') plt.title('Compare Volume') plt.xlabel('years') plt.ylabel('[km^3]') plt.legend(['Flowline', '2D'], loc=2) plt.figure() plt.plot(fls[-1].bed_h, 'k') plt.plot(surface_h[0], 'r') plt.plot(surface_h[1], 'b') plt.title('Compare Shape') plt.xlabel('[m]') plt.ylabel('Elevation [m]') plt.legend(['Bed', 'Flowline', '2D'], loc=2) plt.show() np.testing.assert_almost_equal(lens[0][-1], lens[1][-1]) np.testing.assert_allclose(volume[0][-1], volume[1][-1], atol=3e-3) self.assertTrue(utils.rmsd(lens[0], lens[1]) < 50.) self.assertTrue(utils.rmsd(volume[0], volume[1]) < 2e-3) self.assertTrue(utils.rmsd(areas[0], areas[1]) < 2e-3) self.assertTrue(utils.rmsd(surface_h[0], surface_h[1]) < 1.0) # Equilibrium sdmodel.run_until_equilibrium() flmodel.run_until_equilibrium() assert_allclose(sdmodel.volume_km3 / 3, flmodel.volume_km3, atol=2e-3) assert_allclose(sdmodel.area_km2 / 3, flmodel.area_km2, atol=2e-3) # Store run_ds = sdmodel.run_until_and_store(sdmodel.yr + 50) ts = run_ds['ice_thickness'].mean(dim=['y', 'x']) assert_allclose(ts, ts.values[0], atol=1) # Other direction bed_2d = np.repeat(fls[-1].bed_h, 3).reshape((fls[-1].nx, 3)).T sdmodel = Upstream2D(bed_2d, dx=map_dx, mb_model=mb, y0=0., ice_thick_filter=None) length = yrs * 0. vol = yrs * 0. area = yrs * 0 for i, y in enumerate(yrs): sdmodel.run_until(y) surf_1d = sdmodel.ice_thick[1, :] length[i] = np.sum(surf_1d > 0) * sdmodel.dx vol[i] = sdmodel.volume_km3 / 3 area[i] = sdmodel.area_km2 / 3 lens.append(length) volume.append(vol) areas.append(area) surface_h.append(sdmodel.surface_h[:, 1]) np.testing.assert_almost_equal(lens[0][-1], lens[1][-1]) np.testing.assert_allclose(volume[0][-1], volume[1][-1], atol=3e-3) self.assertTrue(utils.rmsd(lens[0], lens[1]) < 50.) self.assertTrue(utils.rmsd(volume[0], volume[1]) < 2e-3) self.assertTrue(utils.rmsd(areas[0], areas[1]) < 2e-3) self.assertTrue(utils.rmsd(surface_h[0], surface_h[1]) < 1.0) # Equilibrium sdmodel.run_until_equilibrium() assert_allclose(sdmodel.volume_km3 / 3, flmodel.volume_km3, atol=2e-3) assert_allclose(sdmodel.area_km2 / 3, flmodel.area_km2, atol=2e-3)
def linear_mb_equilibrium(bed, surface, accw, elaw, nz, mb_grad, nx, map_dx, idx=None, advance=None, retreat=None, plot=True): """Runs the OGGM FluxBasedModel with a linear mass balance gradient until the glacier reaches equilibrium. Parameters ---------- bed : ndarray the glacier bed surface : ndarray the initial glacier surface accw : int the width of the glacier at the top of the accumulation area elaw : int the width of the glacier at the equilibrium line altitude nz : float fraction of vertical grid points occupied by accumulation area mb_grad : int, float the mass balance altitude gradient in mm w.e. m^-1 yr^-1 nx : int number of grid points map_dx : int grid point spacing idx : int, optional number of vertical grid points to shift ELA down/upglacier advance : bool, optional move the ELA downglacier by idx grid points to simulate a glacier advance retreat : bool, optional move the ELA upglacier by idx grid points to simulate a glacier retreat plot : bool, optional show a pseudo-3d plot of the glacier (default: True) Returns ------- model : oggm.core.flowline.FluxBasedModel OGGM model class of the glacier in equilibrium """ # accumulation area occupies a fraction NZ of the total glacier extent acc_width = np.linspace(accw, elaw, int(nx * nz)) # ablation area occupies a fraction 1 - NZ of the total glacier extent abl_width = np.tile(elaw, nx - len(acc_width)) # glacier widths profile widths = np.hstack([acc_width, abl_width]) # model widths mwidths = np.zeros(nx) + widths / map_dx # define the glacier bed init_flowline = RectangularBedFlowline(surface_h=surface, bed_h=bed, widths=mwidths, map_dx=map_dx) # equilibrium line altitude # in case of an advance scenario, move the ELA downglacier by a number of # vertical grid points idx if advance and idx: ela = bed[np.where(widths == elaw)[0][idx]] # in case of a retreat scenario, move the ELA upglacier by a number of # vertical grid points idx elif retreat and idx: ela = bed[np.where(widths == acc_width[-idx])[0][0]] # in case of no scenario, the ela is the height where the width of the ela # is first reached else: ela = bed[np.where(widths == elaw)[0][0]] # linear mass balance model mb_model = LinearMassBalance(ela, grad=mb_grad) # flowline model model = FluxBasedModel(init_flowline, mb_model=mb_model, y0=0., min_dt=0, cfl_number=0.01) # run until the glacier reaches an equilibrium model.run_until_equilibrium() # show a pseudo-3d plot of the glacier geometry if plot: dis = distance_along_glacier(nx, map_dx) plot_glacier_3d(dis, bed, widths, nx) return model
def response_time_vol(model, perturbed_mb): """Calculation of the volume response time after Oerlemans (1997). Parameters ---------- model : oggm.core.flowline.FluxBasedModel OGGM model class of the glacier in equilibrium perturbed_mb : oggm.core.massbalance.LinearMassBalance Perturbed mass balance model Returns ------- response_time : numpy.float64 the response time of the glacier pert_model : oggm.core.flowline.FluxBasedModel OGGM model class of the glacier in equilibrium adapted to the new ELA """ # to be sure that the model state is in equilibrium (maybe not necessary) count = 0 while True: try: model.run_until_equilibrium(rate=0.006) break except RuntimeError: count += 1 # if equilibrium not reached yet, add 1000 years. Then try again. model.run_until(models[0].yr + 1000) if count == 6: raise RuntimeError('Because the gradient is be very small, ' 'the equilibrium will be reached only ' 'after many years. Run this cell ' 'again, then it should work.') # set up new model, whith outlines of first model, but new mb_model pert_model = FluxBasedModel(model.fls[-1], mb_model=perturbed_mb, y0=0.) # run it until in reaches equilibrium state count = 0 while True: try: pert_model.run_until_equilibrium(rate=0.006) break except RuntimeError: count += 1 # if equilibrium not reached yet, add 1000 years. Then try again. pert_model.run_until(models[0].yr + 1000) if count == 6: raise RuntimeError('Because the gradient is be very small, ' 'the equilibrium will be reached only ' 'after many years. Run this cell ' 'again, then it should work.') # save outline of model in equilibrium state eq_pert_model = pert_model.fls[-1].surface_h # recalculate the perturbed model to be able to save intermediate steps yrs = np.arange(0, pert_model.yr, 5) nsteps = len(yrs) length_w = np.zeros(nsteps) vol_w = np.zeros(nsteps) year = np.zeros(nsteps) recalc_pert_model = FluxBasedModel(model.fls[-1], mb_model=perturbed_mb, y0=0.) for i, yer in enumerate(yrs): recalc_pert_model.run_until(yer) year[i] = recalc_pert_model.yr length_w[i] = recalc_pert_model.length_m vol_w[i] = recalc_pert_model.volume_km3 # to get response time: calculate volume difference between model and pert. # model in eq. state vol_dif = recalc_pert_model.volume_km3 vol_dif -= (recalc_pert_model.volume_km3 - model.volume_km3) / np.e # search for the appropriate time by determining the year with the closest # volume to vol_dif: # difference between volumes of different time steps and vol_dif all_dif_vol = abs(vol_w - vol_dif).tolist() # find index of smallest difference between index = all_dif_vol.index(min(all_dif_vol)) response_time = year[index] return response_time, pert_model
# Figure f = 0.7 f, axs = plt.subplots(2, 2, figsize=(10 * f, 7 * f), sharey=True, sharex=True) axs = np.asarray(axs).flatten() tx, ty = .98, .97 letkm = dict(color='black', ha='right', va='top', fontsize=12, bbox=dict(facecolor='white', edgecolor='black')) fls = dummy_constant_bed(map_dx=gdir.grid.dx) mb = LinearMassBalance(2600.) model = FluxBasedModel(fls, mb_model=mb, y0=0.) model.run_until_equilibrium() fls = [] for fl in model.fls: pg = np.where(fl.thick > 0) line = shpg.LineString([fl.line.coords[int(p)] for p in pg[0]]) flo = Centerline(line, dx=fl.dx, surface_h=fl.surface_h[pg]) flo.widths = fl.widths[pg] flo.is_rectangular = np.ones(flo.nx).astype(np.bool) fls.append(flo) gdir.write_pickle(fls, 'inversion_flowlines') tasks.apparent_mb_from_linear_mb(gdir) tasks.prepare_for_inversion(gdir) v, _ = mass_conservation_inversion(gdir) np.testing.assert_allclose(v, model.volume_m3, rtol=0.05) inv = gdir.read_pickle('inversion_output')[-1]
def find_initial_state(gdir): global past_climate,random_climate2 global y_2000 global x global ax1,ax2,ax3 fls = gdir.read_pickle('model_flowlines') past_climate = PastMassBalance(gdir) random_climate1 = RandomMassBalance(gdir,y0=1865,halfsize=14) #construct searched glacier commit_model = FluxBasedModel(fls, mb_model=random_climate1, glen_a=cfg.A, y0=1850) commit_model.run_until_equilibrium() y_1880 = copy.deepcopy(commit_model) #construct observed glacier commit_model2 = FluxBasedModel(commit_model.fls, mb_model=past_climate, glen_a=cfg.A, y0=1880) commit_model2.run_until(2000) y_2000 = copy.deepcopy(commit_model2) results = pd.DataFrame(columns=['1880','2000','length_1880']) for i in range(4): random_climate2 = RandomMassBalance(gdir, y0=1875, halfsize=14) res = minimize(objfunc, [0], args=(gdir, y_2000.fls), method='COBYLA', tol=1e-04, options={'maxiter': 100, 'rhobeg': 1}) #try: result_model_1880, result_model_2000 = run_model(res.x, gdir, y_2000.fls) results = results.append({'1880':result_model_1880,'2000':result_model_2000,'length_1880':result_model_1880.length_m,'length_2000':result_model_2000.length_m}, ignore_index=True) #except: # pass # create plots for i in range(len(fls)): plt.figure(i,figsize=(20,10)) #add subplot in the corner fig, ax1 = plt.subplots(figsize=(20, 10)) ax2 = fig.add_axes([0.55, 0.66, 0.3, 0.2]) ax1.set_title(gdir.rgi_id+' flowline '+str(i)) box = ax1.get_position() ax1.set_position([box.x0, box.y0, box.width * 0.95, box.height]) x = np.arange(y_2000.fls[i].nx) * y_2000.fls[i].dx * y_2000.fls[i].map_dx for j in range(len(results)): ax1.plot(x, results.get_value(j, '1880').fls[i].surface_h, alpha=0.8, ) ax2.plot(x, results.get_value(j, '2000').fls[i].surface_h, alpha=0.8, ) ax1.plot(x,y_1880.fls[i].surface_h,'k:') ax2.plot(x, y_2000.fls[i].surface_h, 'k') ax1.plot(x, y_1880.fls[i].bed_h, 'k') ax2.plot(x, y_2000.fls[i].bed_h, 'k') plot_dir = os.path.join(cfg.PATHS['working_dir'], 'plots') plt.savefig(os.path.join(plot_dir, gdir.rgi_id +'_fls'+str(i)+ '.png')) #plt.show() results.to_csv(os.path.join(plot_dir,str(gdir.rgi_id)+'.csv')) '''
def test_constant_bed(self): map_dx = 100. yrs = np.arange(1, 400, 5) lens = [] volume = [] areas = [] surface_h = [] # Flowline case fls = dummy_constant_bed(hmax=3000., hmin=1000., nx=200, map_dx=map_dx, widths=1.) mb = LinearMassBalance(2600.) flmodel = FluxBasedModel(fls, mb_model=mb, y0=0.) length = yrs * 0. vol = yrs * 0. area = yrs * 0 for i, y in enumerate(yrs): flmodel.run_until(y) length[i] = fls[-1].length_m vol[i] = fls[-1].volume_km3 area[i] = fls[-1].area_km2 lens.append(length) volume.append(vol) areas.append(area) surface_h.append(fls[-1].surface_h.copy()) # Make a 2D bed out of the 1D bed_2d = np.repeat(fls[-1].bed_h, 3).reshape((fls[-1].nx, 3)) sdmodel = Upstream2D(bed_2d, dx=map_dx, mb_model=mb, y0=0., ice_thick_filter=None) length = yrs * 0. vol = yrs * 0. area = yrs * 0 for i, y in enumerate(yrs): sdmodel.run_until(y) surf_1d = sdmodel.ice_thick[:, 1] length[i] = np.sum(surf_1d > 0) * sdmodel.dx vol[i] = sdmodel.volume_km3 / 3 area[i] = sdmodel.area_km2 / 3 lens.append(length) volume.append(vol) areas.append(area) surface_h.append(sdmodel.surface_h[:, 1]) if do_plot: plt.figure() plt.plot(yrs, lens[0], 'r') plt.plot(yrs, lens[1], 'b') plt.title('Compare Length') plt.xlabel('years') plt.ylabel('[m]') plt.legend(['Flowline', '2D'], loc=2) plt.figure() plt.plot(yrs, volume[0], 'r') plt.plot(yrs, volume[1], 'b') plt.title('Compare Volume') plt.xlabel('years') plt.ylabel('[km^3]') plt.legend(['Flowline', '2D'], loc=2) plt.figure() plt.plot(fls[-1].bed_h, 'k') plt.plot(surface_h[0], 'r') plt.plot(surface_h[1], 'b') plt.title('Compare Shape') plt.xlabel('[m]') plt.ylabel('Elevation [m]') plt.legend(['Bed', 'Flowline', '2D'], loc=2) plt.show() np.testing.assert_almost_equal(lens[0][-1], lens[1][-1]) np.testing.assert_allclose(volume[0][-1], volume[1][-1], atol=3e-3) self.assertTrue(utils.rmsd(lens[0], lens[1]) < 50.) self.assertTrue(utils.rmsd(volume[0], volume[1]) < 2e-3) self.assertTrue(utils.rmsd(areas[0], areas[1]) < 2e-3) self.assertTrue(utils.rmsd(surface_h[0], surface_h[1]) < 1.0) # Equilibrium sdmodel.run_until_equilibrium() flmodel.run_until_equilibrium() assert_allclose(sdmodel.volume_km3 / 3, flmodel.volume_km3, atol=2e-3) assert_allclose(sdmodel.area_km2 / 3, flmodel.area_km2, atol=2e-3) # Store run_ds = sdmodel.run_until_and_store(sdmodel.yr+50) ts = run_ds['ice_thickness'].mean(dim=['y', 'x']) assert_allclose(ts, ts.values[0], atol=1) # Other direction bed_2d = np.repeat(fls[-1].bed_h, 3).reshape((fls[-1].nx, 3)).T sdmodel = Upstream2D(bed_2d, dx=map_dx, mb_model=mb, y0=0., ice_thick_filter=None) length = yrs * 0. vol = yrs * 0. area = yrs * 0 for i, y in enumerate(yrs): sdmodel.run_until(y) surf_1d = sdmodel.ice_thick[1, :] length[i] = np.sum(surf_1d > 0) * sdmodel.dx vol[i] = sdmodel.volume_km3 / 3 area[i] = sdmodel.area_km2 / 3 lens.append(length) volume.append(vol) areas.append(area) surface_h.append(sdmodel.surface_h[:, 1]) np.testing.assert_almost_equal(lens[0][-1], lens[1][-1]) np.testing.assert_allclose(volume[0][-1], volume[1][-1], atol=3e-3) self.assertTrue(utils.rmsd(lens[0], lens[1]) < 50.) self.assertTrue(utils.rmsd(volume[0], volume[1]) < 2e-3) self.assertTrue(utils.rmsd(areas[0], areas[1]) < 2e-3) self.assertTrue(utils.rmsd(surface_h[0], surface_h[1]) < 1.0) # Equilibrium sdmodel.run_until_equilibrium() assert_allclose(sdmodel.volume_km3 / 3, flmodel.volume_km3, atol=2e-3) assert_allclose(sdmodel.area_km2 / 3, flmodel.area_km2, atol=2e-3)
def find_initial_state(gdir): global past_climate, random_climate2 global y_2000 global x global ax1, ax2, ax3 fls = gdir.read_pickle('model_flowlines') past_climate = PastMassBalance(gdir) random_climate1 = RandomMassBalance(gdir, y0=1865, halfsize=14) #construct searched glacier commit_model = FluxBasedModel(fls, mb_model=random_climate1, glen_a=cfg.A, y0=1850) commit_model.run_until_equilibrium() y_1880 = copy.deepcopy(commit_model) #construct observed glacier commit_model2 = FluxBasedModel(commit_model.fls, mb_model=past_climate, glen_a=cfg.A, y0=1880) commit_model2.run_until(2000) y_2000 = copy.deepcopy(commit_model2) results = pd.DataFrame(columns=['1880', '2000', 'length_1880']) pool = mp.Pool() result_list = pool.map(partial(run_parallel, gdir=gdir, y_2000=y_2000), range(300)) pool.close() pool.join() result_list = [x for x in result_list if x != [None, None]] # create plots for i in range(len(result_list[0][0].fls)): plt.figure(i, figsize=(20, 10)) #add subplot in the corner fig, ax1 = plt.subplots(figsize=(20, 10)) ax2 = fig.add_axes([0.55, 0.66, 0.3, 0.2]) ax1.set_title(gdir.rgi_id + ' flowline ' + str(i)) box = ax1.get_position() ax1.set_position([box.x0, box.y0, box.width * 0.95, box.height]) x = np.arange( y_2000.fls[i].nx) * y_2000.fls[i].dx * y_2000.fls[i].map_dx for j in range(len(result_list)): if result_list[j][0] != None: ax1.plot( x, result_list[j][0].fls[i].surface_h, alpha=0.8, ) ax2.plot( x, result_list[j][1].fls[i].surface_h, alpha=0.8, ) ax1.plot(x, y_1880.fls[i].surface_h, 'k:') ax2.plot(x, y_2000.fls[i].surface_h, 'k') ax1.plot(x, y_1880.fls[i].bed_h, 'k') ax2.plot(x, y_2000.fls[i].bed_h, 'k') plot_dir = os.path.join(cfg.PATHS['working_dir'], 'plots', 'Ben_idea_parallel_without_length') if not os.path.exists(plot_dir): os.makedirs(plot_dir) plt.savefig( os.path.join(plot_dir, gdir.rgi_id + '_fls' + str(i) + '.png')) pickle.dump(result_list, open(os.path.join(plot_dir, gdir.rgi_id + '.pkl'), 'wb')) solution = [y_1880, y_2000] pickle.dump( solution, open(os.path.join(plot_dir, gdir.rgi_id + '_solution.pkl'), 'wb'))
def _find_inital_glacier(final_model, firstguess_mb, y0, y1, rtol=0.01, atol=10, max_ite=100, init_bias=0., equi_rate=0.0005, ref_area=None): """ Iterative search for a plausible starting time glacier""" # Objective if ref_area is None: ref_area = final_model.area_m2 log.info( 'iterative_initial_glacier_search ' 'in year %d. Ref area to catch: %.3f km2. ' 'Tolerance: %.2f %%', np.int64(y0), ref_area * 1e-6, rtol * 100) # are we trying to grow or to shrink the glacier? prev_model = copy.deepcopy(final_model) prev_fls = copy.deepcopy(prev_model.fls) prev_model.reset_y0(y0) prev_model.run_until(y1) prev_area = prev_model.area_m2 # Just in case we already hit the correct starting state if np.allclose(prev_area, ref_area, atol=atol, rtol=rtol): model = copy.deepcopy(final_model) model.reset_y0(y0) log.info( 'iterative_initial_glacier_search: inital ' 'starting glacier converges ' 'to itself with a final dif of %.2f %%', utils.rel_err(ref_area, prev_area) * 100) return 0, None, model if prev_area < ref_area: sign_mb = -1. log.info( 'iterative_initial_glacier_search, ite: %d. ' 'Glacier would be too ' 'small of %.2f %%. Continue', 0, utils.rel_err(ref_area, prev_area) * 100) else: log.info( 'iterative_initial_glacier_search, ite: %d. ' 'Glacier would be too ' 'big of %.2f %%. Continue', 0, utils.rel_err(ref_area, prev_area) * 100) sign_mb = 1. # Log prefix logtxt = 'iterative_initial_glacier_search' # Loop until 100 iterations c = 0 bias_step = 0.1 mb_bias = init_bias - bias_step reduce_step = 0.01 mb = copy.deepcopy(firstguess_mb) mb.temp_bias = sign_mb * mb_bias grow_model = FluxBasedModel(copy.deepcopy(final_model.fls), mb_model=mb, fs=final_model.fs, glen_a=final_model.glen_a, min_dt=final_model.min_dt, max_dt=final_model.max_dt) while True and (c < max_ite): c += 1 # Grow mb_bias += bias_step mb.temp_bias = sign_mb * mb_bias log.info(logtxt + ', ite: %d. New bias: %.2f', c, sign_mb * mb_bias) grow_model.reset_flowlines(copy.deepcopy(prev_fls)) grow_model.reset_y0(0.) grow_model.run_until_equilibrium(rate=equi_rate) log.info( logtxt + ', ite: %d. Grew to equilibrium for %d years, ' 'new area: %.3f km2', c, grow_model.yr, grow_model.area_km2) # Shrink new_fls = copy.deepcopy(grow_model.fls) new_model = copy.deepcopy(final_model) new_model.reset_flowlines(copy.deepcopy(new_fls)) new_model.reset_y0(y0) new_model.run_until(y1) new_area = new_model.area_m2 # Maybe we done? if np.allclose(new_area, ref_area, atol=atol, rtol=rtol): new_model.reset_flowlines(new_fls) new_model.reset_y0(y0) log.info( logtxt + ', ite: %d. Converged with a ' 'final dif of %.2f %%', c, utils.rel_err(ref_area, new_area) * 100) return c, mb_bias, new_model # See if we did a step to far or if we have to continue growing do_cont_1 = (sign_mb < 0.) and (new_area < ref_area) do_cont_2 = (sign_mb > 0.) and (new_area > ref_area) if do_cont_1 or do_cont_2: # Reset the previous state and continue prev_fls = new_fls log.info(logtxt + ', ite: %d. Dif of %.2f %%. ' 'Continue', c, utils.rel_err(ref_area, new_area) * 100) continue # Ok. We went too far. Reduce the bias step but keep previous state mb_bias -= bias_step bias_step /= reduce_step log.info(logtxt + ', ite: %d. Went too far.', c) if bias_step < 0.1: break raise RuntimeError('Did not converge after {} iterations'.format(c))
def create_spinup_glacier(gdir, rgi_id_to_name, yr_start_run, yr_end_run, yr_spinup, used_mb_models): """TODO """ # now creat spinup glacier with consensus flowline starting from ice free, # try to match length at rgi_date for 'realistic' experiment setting fl_consensus = gdir.read_pickle('model_flowlines', filesuffix='_consensus')[0] length_m_ref = fl_consensus.length_m fls_spinup = copy.deepcopy([fl_consensus]) fls_spinup[0].thick = np.zeros(len(fls_spinup[0].thick)) halfsize = (yr_start_run - yr_spinup) / 2 yr_rgi = gdir.rgi_date mb_spinup = MultipleFlowlineMassBalance(gdir, fls=fls_spinup, mb_model_class=ConstantMassBalance, filename='climate_historical', input_filesuffix='', y0=yr_spinup + halfsize, halfsize=halfsize) mb_historical = MultipleFlowlineMassBalance(gdir, fls=fls_spinup, mb_model_class=PastMassBalance, filename='climate_historical', input_filesuffix='') def spinup_run(t_bias): # with t_bias the glacier state after spinup is changed between iterations mb_spinup.temp_bias = t_bias # run the spinup model_spinup = FluxBasedModel(copy.deepcopy(fls_spinup), mb_spinup, y0=0) model_spinup.run_until_equilibrium(max_ite=1000) # Now conduct the actual model run to the rgi date model_historical = FluxBasedModel(model_spinup.fls, mb_historical, y0=yr_spinup) model_historical.run_until(yr_rgi) cost = (model_historical.length_m - length_m_ref) / length_m_ref * 100 return cost glacier_name = rgi_id_to_name[gdir.rgi_id] if experiment_glaciers[glacier_name]['t_bias_spinup_limits'] is None: print( 'returned spinup_run function for searching for the t_bias_limits!' ) return gdir, spinup_run else: t_bias_spinup_limits = \ experiment_glaciers[glacier_name]['t_bias_spinup_limits'] if experiment_glaciers[glacier_name]['t_bias_spinup'] is None: # search for it by giving back t_bias_spinup = brentq(spinup_run, t_bias_spinup_limits[0], t_bias_spinup_limits[1], maxiter=20, disp=False) else: t_bias_spinup = experiment_glaciers[glacier_name]['t_bias_spinup'] print( f'{gdir.name} spinup tbias: {t_bias_spinup} with L mismatch at rgi_date:' f' {spinup_run(t_bias_spinup)} m') mb_spinup.temp_bias = t_bias_spinup model_spinup = FluxBasedModel(copy.deepcopy(fls_spinup), mb_spinup, y0=0) model_spinup.run_until_equilibrium(max_ite=1000) gdir.write_pickle(model_spinup.fls, 'model_flowlines', filesuffix='_spinup')
def find_initial_state(gdir): global past_climate global y_1900, y_1850 global y_start global x global ax1, ax2, ax3 fls = gdir.read_pickle('model_flowlines') past_climate = PastMassBalance(gdir) random_climate = RandomMassBalance(gdir) commit_model = FluxBasedModel(fls, mb_model=random_climate, glen_a=cfg.A, y0=1850) commit_model.run_until_equilibrium() y_1850 = copy.deepcopy(commit_model) commit_model = FluxBasedModel(commit_model.fls, mb_model=past_climate, glen_a=cfg.A, y0=1850) commit_model.run_until(2000) y_1900 = copy.deepcopy(commit_model) x = np.arange( y_1900.fls[-1].nx) * y_1900.fls[-1].dx * y_1900.fls[-1].map_dx plt.figure(figsize=(20, 10)) fig, ax1 = plt.subplots() ax2 = fig.add_axes([0.55, 0.66, 0.3, 0.2]) ax1.set_title(gdir.rgi_id) box = ax1.get_position() ax1.set_position([box.x0, box.y0, box.width * 0.95, box.height]) # Put a legend to the right of the current axis #plt.setp(ax1.get_xticklabels(), visible=False) #plt.plot(x, y_1850.fls[-1].surface_h, 'k:', label='solution') #plt.plot(x, y_1850.fls[-1].bed_h, 'k', label='bed') #plt.legend(loc='best') #ax2 = plt.subplot(412, sharex=ax1) #plt.setp(ax2.get_xticklabels(), visible=False) ''' ax3 = plt.subplot(413,sharex=ax1) ax3.plot(x, np.zeros(len(x)), 'k--') ax4 = plt.subplot(414, sharex=ax1) ax4.plot(x, np.zeros(len(x)), 'k--') ''' growing_model = FluxBasedModel(fls, mb_model=past_climate, glen_a=cfg.A, y0=1850) y_start = copy.deepcopy(growing_model) colors = [ pylab.cm.Blues(np.linspace(0.3, 1, 2)), pylab.cm.Reds(np.linspace(0.3, 1, 2)), pylab.cm.Greens(np.linspace(0.3, 1, 2)) ] #for i in [0,0.2,0.4,0.6,0.8,1,5,10,15,20,25,30,35,40,45,50]: j = 0 for i in [1]: k = 0 col = colors[j] j = j + 1 for t in [20, 40, 60, 80, 100, 120, 140, 150]: res = minimize(objfunc, [0], args=( gdir, y_1900.fls, t, i, ), method='COBYLA', tol=1e-04, options={ 'maxiter': 500, 'rhobeg': 2 }) try: result_model_1850, result_model_1900 = run_model( res.x, gdir, y_1900.fls, t, i) f = np.sum(abs(result_model_1900.fls[-1].surface_h-y_1900.fls[-1].surface_h) ** 2) + \ np.sum(abs(y_1900.fls[-1].widths - result_model_1900.fls[-1].widths) ** 2) dif_s = result_model_1900.fls[-1].surface_h - y_1900.fls[ -1].surface_h dif_w = result_model_1900.fls[-1].widths - y_1900.fls[-1].widths #if np.max(dif_s)<40 and np.max(dif_w)<15: ax1.plot(x, result_model_1850.fls[-1].surface_h, alpha=0.8, color=col[k], label='t=' + str(t)) ax2.plot(x, result_model_1900.fls[-1].surface_h, alpha=0.8, color=col[k]) except: pass k = k + 1 ax1.plot(x, y_1850.fls[-1].surface_h, 'k:') #, label='surface elevation (not known)') ax1.plot(x, y_1850.fls[-1].bed_h, 'k') #, label='bed topography') ax2.plot(x, y_1900.fls[-1].surface_h, 'k', label='surface elevation (observed)') ax2.plot(x, y_1900.fls[-1].bed_h, 'k', label='bed') #ax3.plot(x,np.zeros(len(x)),'k:') ax1.annotate('t = 1850', xy=(0.1, 0.95), xycoords='axes fraction', fontsize=13) ax2.annotate('t = 2000', xy=(0.1, 0.9), xycoords='axes fraction', fontsize=9) ax1.set_xlabel('Distance along the Flowline (m)') ax1.set_ylabel('Altitude (m)') ax2.set_xlabel('Distance along the Flowline (m)') ax2.set_ylabel('Altitude (m)') ax1.legend(loc='center left', bbox_to_anchor=(1, 0.5)) ax2.legend(loc='best') plot_dir = os.path.join(cfg.PATHS['working_dir'], 'plots') if not os.path.exists(plot_dir): os.makedirs(plot_dir) plt.savefig(os.path.join(plot_dir, gdir.rgi_id + '.png')) plt.show()