def test_min_max_elevation(self): """Test the helper method which computes the minimal and maximal glacier surface elevation in meters asl, from the given DEM and glacier outline. """ # read the Hintereisferner DEM hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] # initialize the GlacierDirectory gdir = oggm.GlacierDirectory(entity, base_dir=self.testdir) # define the local grid and glacier mask gis.define_glacier_region(gdir, entity=entity) gis.glacier_masks(gdir) # set targets from RGI min_target = 2430.0 max_target = 3674.0 # get values from method min_hgt, max_hgt = vascaling.get_min_max_elevation(gdir) # test with one percentage relative tolerance np.testing.assert_allclose(min_hgt, min_target, rtol=1e-2) np.testing.assert_allclose(max_hgt, max_target, rtol=1e-2)
def init_columbia(reset=False): from oggm.core import gis, climate, centerlines import geopandas as gpd # test directory testdir = os.path.join(get_test_dir(), 'tmp_columbia') if not os.path.exists(testdir): os.makedirs(testdir) reset = True # Init cfg.initialize() cfg.PATHS['working_dir'] = testdir cfg.PARAMS['use_intersects'] = False cfg.PATHS['dem_file'] = get_demo_file('dem_Columbia.tif') cfg.PARAMS['border'] = 10 entity = gpd.read_file(get_demo_file('01_rgi60_Columbia.shp')).iloc[0] gdir = oggm.GlacierDirectory(entity, reset=reset) if gdir.has_file('climate_historical'): return gdir gis.define_glacier_region(gdir) gis.glacier_masks(gdir) centerlines.compute_centerlines(gdir) centerlines.initialize_flowlines(gdir) centerlines.compute_downstream_line(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir) centerlines.catchment_width_correction(gdir) tasks.process_dummy_cru_file(gdir, seed=0) return gdir
def init_columbia_eb(dir_name, reset=False): from oggm.core import gis, centerlines import geopandas as gpd # test directory testdir = os.path.join(get_test_dir(), dir_name) mkdir(testdir, reset=reset) # Init cfg.initialize() cfg.PATHS['working_dir'] = testdir cfg.PARAMS['use_intersects'] = False cfg.PATHS['dem_file'] = get_demo_file('dem_Columbia.tif') cfg.PARAMS['border'] = 10 entity = gpd.read_file(get_demo_file('01_rgi60_Columbia.shp')).iloc[0] gdir = oggm.GlacierDirectory(entity) if gdir.has_file('climate_historical'): return gdir gis.define_glacier_region(gdir) gis.simple_glacier_masks(gdir) centerlines.elevation_band_flowline(gdir) centerlines.fixed_dx_elevation_band_flowline(gdir) centerlines.compute_downstream_line(gdir) tasks.process_dummy_cru_file(gdir, seed=0) return gdir
def test_run_random_climate(self): """ Test the run_random_climate task for a climate based on the equilibrium period centred around t*. Additionally a positive and a negative temperature bias are tested. Returns ------- """ # let's not use the mass balance bias since we want to reproduce # results from mass balance calibration cfg.PARAMS['use_bias_for_run'] = False # read the Hintereisferner DEM hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] # initialize the GlacierDirectory gdir = oggm.GlacierDirectory(entity, base_dir=self.testdir) # define the local grid and glacier mask gis.define_glacier_region(gdir, entity=entity) gis.glacier_masks(gdir) # process the given climate file climate.process_custom_climate_data(gdir) # compute mass balance parameters ref_df = cfg.PARAMS['vas_ref_tstars_rgi5_histalp'] vascaling.local_t_star(gdir, ref_df=ref_df) # define some parameters for the random climate model nyears = 300 seed = 1 temp_bias = 0.5 # read the equilibirum year used for the mass balance calibration t_star = gdir.read_json('vascaling_mustar')['t_star'] # run model with random climate _ = vascaling.run_random_climate(gdir, nyears=nyears, y0=t_star, seed=seed) # run model with positive temperature bias _ = vascaling.run_random_climate(gdir, nyears=nyears, y0=t_star, seed=seed, temperature_bias=temp_bias, output_filesuffix='_bias_p') # run model with negative temperature bias _ = vascaling.run_random_climate(gdir, nyears=nyears, y0=t_star, seed=seed, temperature_bias=-temp_bias, output_filesuffix='_bias_n') # compile run outputs ds = utils.compile_run_output([gdir], input_filesuffix='') ds_p = utils.compile_run_output([gdir], input_filesuffix='_bias_p') ds_n = utils.compile_run_output([gdir], input_filesuffix='_bias_n') # the glacier should not change much under a random climate # based on the equilibirum period centered around t* assert abs(1 - ds.volume.mean() / ds.volume[0]) < 0.015 # higher temperatures should result in a smaller glacier assert ds.volume.mean() > ds_p.volume.mean() # lower temperatures should result in a larger glacier assert ds.volume.mean() < ds_n.volume.mean()
def test_run_constant_climate(self): """ Test the run_constant_climate task for a climate based on the equilibrium period centred around t*. Additionally a positive and a negative temperature bias are tested. """ # let's not use the mass balance bias since we want to reproduce # results from mass balance calibration cfg.PARAMS['use_bias_for_run'] = False # read the Hintereisferner DEM hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] # initialize the GlacierDirectory gdir = oggm.GlacierDirectory(entity, base_dir=self.testdir) # define the local grid and glacier mask gis.define_glacier_region(gdir, entity=entity) gis.glacier_masks(gdir) # process the given climate file climate.process_custom_climate_data(gdir) # compute mass balance parameters ref_df = cfg.PARAMS['vas_ref_tstars_rgi5_histalp'] vascaling.local_t_star(gdir, ref_df=ref_df) # define some parameters for the constant climate model nyears = 500 temp_bias = 0.5 _ = vascaling.run_constant_climate(gdir, nyears=nyears, output_filesuffix='') _ = vascaling.run_constant_climate(gdir, nyears=nyears, temperature_bias=+temp_bias, output_filesuffix='_bias_p') _ = vascaling.run_constant_climate(gdir, nyears=nyears, temperature_bias=-temp_bias, output_filesuffix='_bias_n') # compile run outputs ds = utils.compile_run_output([gdir], input_filesuffix='') ds_p = utils.compile_run_output([gdir], input_filesuffix='_bias_p') ds_n = utils.compile_run_output([gdir], input_filesuffix='_bias_n') # the glacier should not change under a constant climate # based on the equilibirum period centered around t* assert abs(1 - ds.volume.mean() / ds.volume[0]) < 1e-7 # higher temperatures should result in a smaller glacier assert ds.volume.mean() > ds_p.volume.mean() # lower temperatures should result in a larger glacier assert ds.volume.mean() < ds_n.volume.mean() # compute volume change from one year to the next dV_p = (ds_p.volume[1:].values - ds_p.volume[:-1].values).flatten() dV_n = (ds_n.volume[1:].values - ds_n.volume[:-1].values).flatten() # compute relative volume change, with respect to the final volume rate_p = abs(dV_p / float(ds_p.volume.values[-1])) rate_n = abs(dV_n / float(ds_n.volume.values[-1])) # the glacier should be in a new equilibirum for last 300 years assert max(rate_p[-300:]) < 0.001 assert max(rate_n[-300:]) < 0.001
def test_run(self): entity = gpd.read_file(self.rgi_file).iloc[0] gdir = oggm.GlacierDirectory(entity, base_dir=self.testdir) gis.define_glacier_region(gdir) gis.glacier_masks(gdir) centerlines.compute_centerlines(gdir) centerlines.initialize_flowlines(gdir) centerlines.compute_downstream_line(gdir) centerlines.compute_downstream_bedshape(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir) centerlines.catchment_width_correction(gdir) # Climate tasks -- only data IO and tstar interpolation! tasks.process_dummy_cru_file(gdir, seed=0) tasks.local_t_star(gdir) tasks.mu_star_calibration(gdir) # Inversion tasks tasks.find_inversion_calving(gdir) # Final preparation for the run tasks.init_present_time_glacier(gdir) # check that calving happens in the real context as well tasks.run_constant_climate(gdir, bias=0, nyears=200, temperature_bias=-0.5) with xr.open_dataset(gdir.get_filepath('model_diagnostics')) as ds: assert ds.calving_m3[-1] > 10
def _set_up_VAS_model(self): """Avoiding a chunk of code duplicate. Set's up a running volume/area scaling model, including all needed prepo tasks. """ # read the Hintereisferner DEM hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] # initialize the GlacierDirectory gdir = oggm.GlacierDirectory(entity, base_dir=self.testdir) # define the local grid and glacier mask gis.define_glacier_region(gdir, entity=entity) gis.glacier_masks(gdir) # process the given climate file climate.process_custom_climate_data(gdir) # run center line preprocessing tasks centerlines.compute_centerlines(gdir) centerlines.initialize_flowlines(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir) centerlines.catchment_width_correction(gdir) # read reference glacier mass balance data mbdf = gdir.get_ref_mb_data() # compute the reference t* for the glacier # given the reference of mass balance measurements res = climate.t_star_from_refmb(gdir, mbdf=mbdf['ANNUAL_BALANCE']) t_star, bias = res['t_star'], res['bias'] # -------------------- # MASS BALANCE TASKS # -------------------- # compute local t* and the corresponding mu* vascaling.local_t_star(gdir, tstar=t_star, bias=bias) # instance the mass balance models mbmod = vascaling.VAScalingMassBalance(gdir) # ---------------- # DYNAMICAL PART # ---------------- # get reference area a0 = gdir.rgi_area_m2 # get reference year y0 = gdir.read_pickle('climate_info')['baseline_hydro_yr_0'] # get min and max glacier surface elevation h0, h1 = vascaling.get_min_max_elevation(gdir) model = vascaling.VAScalingModel(year_0=y0, area_m2_0=a0, min_hgt=h0, max_hgt=h1, mb_model=mbmod) return gdir, model
def test_to_tiff(self): from oggm import tasks from oggm.workflow import execute_entity_task from oggm import GlacierDirectory hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] gdir = GlacierDirectory(entity, base_dir=self.testdir) gdir.rgi_id = gdir.rgi_id.replace('50-', '60-') gis.define_glacier_region(gdir, entity=entity) gdirs = [gdir] # Preprocessing tasks task_list = [ tasks.glacier_masks, tasks.compute_centerlines, tasks.initialize_flowlines, tasks.catchment_area, tasks.catchment_intersections, tasks.catchment_width_geom, tasks.catchment_width_correction, ] for task in task_list: execute_entity_task(task, gdirs) # Climate tasks -- only data IO and tstar interpolation! execute_entity_task(tasks.process_cru_data, gdirs) tasks.distribute_t_stars(gdirs) execute_entity_task(tasks.apparent_mb, gdirs) # Inversion tasks execute_entity_task(tasks.prepare_for_inversion, gdirs) execute_entity_task(tasks.volume_inversion, gdirs, glen_a=cfg.A * 3, fs=0) execute_entity_task(tasks.distribute_thickness_per_altitude, gdirs) g2task.oggm_to_g2ti(gdir) ft = os.path.join(cfg.PATHS['working_dir'], 'final', 'RGI60-{}'.format(gdir.rgi_region)) ft = os.path.join(ft, 'thickness_{}.tif'.format(gdir.rgi_id)) ds = xr.open_rasterio(ft) tpl_f = os.path.join(g2ti.geometry_dir, gdir.rgi_id[:8], gdir.rgi_id, 'mask.tif') da = xr.open_rasterio(tpl_f) np.testing.assert_allclose(ds.sum(), (da * ds).sum(), rtol=0.05) if do_plot: import matplotlib.pyplot as plt ds.plot() plt.figure() da.plot() plt.show()
def test_coxe(): testdir = os.path.join(get_test_dir(), 'tmp_coxe') utils.mkdir(testdir, reset=True) # Init cfg.initialize() cfg.PARAMS['use_intersects'] = False cfg.PATHS['dem_file'] = get_demo_file('dem_RGI50-01.10299.tif') cfg.PARAMS['border'] = 40 cfg.PARAMS['clip_tidewater_border'] = False cfg.PARAMS['use_multiple_flowlines'] = False cfg.PARAMS['use_kcalving_for_inversion'] = True cfg.PARAMS['use_kcalving_for_run'] = True cfg.PARAMS['trapezoid_lambdas'] = 1 hef_file = get_demo_file('rgi_RGI50-01.10299.shp') entity = gpd.read_file(hef_file).iloc[0] gdir = oggm.GlacierDirectory(entity, base_dir=testdir, reset=True) gis.define_glacier_region(gdir) gis.glacier_masks(gdir) centerlines.compute_centerlines(gdir) centerlines.initialize_flowlines(gdir) centerlines.compute_downstream_line(gdir) centerlines.compute_downstream_bedshape(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir) centerlines.catchment_width_correction(gdir) climate.apparent_mb_from_linear_mb(gdir) inversion.prepare_for_inversion(gdir) inversion.mass_conservation_inversion(gdir) inversion.filter_inversion_output(gdir) flowline.init_present_time_glacier(gdir) fls = gdir.read_pickle('model_flowlines') p = gdir.read_pickle('linear_mb_params') mb_mod = massbalance.LinearMassBalance(ela_h=p['ela_h'], grad=p['grad']) mb_mod.temp_bias = -0.3 model = flowline.FluxBasedModel(fls, mb_model=mb_mod, y0=0, inplace=True, is_tidewater=True) # run model.run_until(200) assert model.calving_m3_since_y0 > 0 fig, ax = plt.subplots() graphics.plot_modeloutput_map(gdir, ax=ax, model=model) fig.tight_layout() shutil.rmtree(testdir) return fig
def test_local_t_star(self): # set parameters for climate file and mass balance calibration cfg.PARAMS['baseline_climate'] = 'CUSTOM' cfg.PARAMS['baseline_y0'] = 1850 cfg.PATHS['climate_file'] = get_demo_file('histalp_merged_hef.nc') cfg.PARAMS['run_mb_calibration'] = False # read the Hintereisferner hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] # initialize the GlacierDirectory gdir = oggm.GlacierDirectory(entity, base_dir=self.testdir) # define the local grid and the glacier mask gis.define_glacier_region(gdir, entity=entity) gis.glacier_masks(gdir) # run centerline prepro tasks centerlines.compute_centerlines(gdir) centerlines.initialize_flowlines(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir) centerlines.catchment_width_correction(gdir) # process the given climate file climate.process_custom_climate_data(gdir) # compute the reference t* for the glacier # given the reference of mass balance measurements res = vascaling.t_star_from_refmb(gdir) t_star, bias = res['t_star'], res['bias'] # compute local t* and the corresponding mu* vascaling.local_t_star(gdir, tstar=t_star, bias=bias) # read calibration results vas_mustar_refmb = gdir.read_json('vascaling_mustar') # get reference t* list ref_df = cfg.PARAMS['vas_ref_tstars_rgi5_histalp'] # compute local t* and the corresponding mu* vascaling.local_t_star(gdir, ref_df=ref_df) # read calibration results vas_mustar_refdf = gdir.read_json('vascaling_mustar') # compute local t* and the corresponding mu* vascaling.local_t_star(gdir) # read calibration results vas_mustar = gdir.read_json('vascaling_mustar') # compare with each other assert vas_mustar_refdf == vas_mustar # TODO: this test is failing currently # np.testing.assert_allclose(vas_mustar_refmb['bias'], # vas_mustar_refdf['bias'], atol=1) vas_mustar_refdf.pop('bias') vas_mustar_refmb.pop('bias') # end of workaround assert vas_mustar_refdf == vas_mustar_refmb
def test_set_width(self): entity = gpd.read_file(self.rgi_file).iloc[0] gdir = oggm.GlacierDirectory(entity, base_dir=self.testdir) gis.define_glacier_region(gdir) gis.glacier_masks(gdir) centerlines.compute_centerlines(gdir) centerlines.initialize_flowlines(gdir) centerlines.compute_downstream_line(gdir) centerlines.compute_downstream_bedshape(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir) centerlines.catchment_width_correction(gdir) # Test that area and area-altitude elev is fine with utils.ncDataset(gdir.get_filepath('gridded_data')) as nc: mask = nc.variables['glacier_mask'][:] topo = nc.variables['topo_smoothed'][:] rhgt = topo[np.where(mask)][:] fls = gdir.read_pickle('inversion_flowlines') hgt, widths = gdir.get_inversion_flowline_hw() bs = 100 bins = np.arange(utils.nicenumber(np.min(hgt), bs, lower=True), utils.nicenumber(np.max(hgt), bs) + 1, bs) h1, b = np.histogram(hgt, weights=widths, density=True, bins=bins) h2, b = np.histogram(rhgt, density=True, bins=bins) h1 = h1 / np.sum(h1) h2 = h2 / np.sum(h2) assert utils.rmsd(h1, h2) < 0.02 # less than 2% error new_area = np.sum(widths * fls[-1].dx * gdir.grid.dx) np.testing.assert_allclose(new_area, gdir.rgi_area_m2) centerlines.terminus_width_correction(gdir, new_width=714) fls = gdir.read_pickle('inversion_flowlines') hgt, widths = gdir.get_inversion_flowline_hw() # Check that the width is ok np.testing.assert_allclose(fls[-1].widths[-1] * gdir.grid.dx, 714) # Check for area distrib bins = np.arange(utils.nicenumber(np.min(hgt), bs, lower=True), utils.nicenumber(np.max(hgt), bs) + 1, bs) h1, b = np.histogram(hgt, weights=widths, density=True, bins=bins) h2, b = np.histogram(rhgt, density=True, bins=bins) h1 = h1 / np.sum(h1) h2 = h2 / np.sum(h2) assert utils.rmsd(h1, h2) < 0.02 # less than 2% error new_area = np.sum(widths * fls[-1].dx * gdir.grid.dx) np.testing.assert_allclose(new_area, gdir.rgi_area_m2)
def test_set_width(self): entity = gpd.read_file(self.rgi_file).iloc[0] gdir = oggm.GlacierDirectory(entity, base_dir=self.testdir) gis.define_glacier_region(gdir, entity=entity) gis.glacier_masks(gdir) centerlines.compute_centerlines(gdir) centerlines.initialize_flowlines(gdir) centerlines.compute_downstream_line(gdir) centerlines.compute_downstream_bedshape(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir) centerlines.catchment_width_correction(gdir) # Test that area and area-altitude elev is fine with utils.ncDataset(gdir.get_filepath('gridded_data')) as nc: mask = nc.variables['glacier_mask'][:] topo = nc.variables['topo_smoothed'][:] rhgt = topo[np.where(mask)][:] fls = gdir.read_pickle('inversion_flowlines') hgt, widths = gdir.get_inversion_flowline_hw() bs = 100 bins = np.arange(utils.nicenumber(np.min(hgt), bs, lower=True), utils.nicenumber(np.max(hgt), bs) + 1, bs) h1, b = np.histogram(hgt, weights=widths, density=True, bins=bins) h2, b = np.histogram(rhgt, density=True, bins=bins) h1 = h1 / np.sum(h1) h2 = h2 / np.sum(h2) assert utils.rmsd(h1, h2) < 0.02 # less than 2% error new_area = np.sum(widths * fls[-1].dx * gdir.grid.dx) np.testing.assert_allclose(new_area, gdir.rgi_area_m2) centerlines.terminus_width_correction(gdir, new_width=714) fls = gdir.read_pickle('inversion_flowlines') hgt, widths = gdir.get_inversion_flowline_hw() # Check that the width is ok np.testing.assert_allclose(fls[-1].widths[-1] * gdir.grid.dx, 714) # Check for area distrib bins = np.arange(utils.nicenumber(np.min(hgt), bs, lower=True), utils.nicenumber(np.max(hgt), bs) + 1, bs) h1, b = np.histogram(hgt, weights=widths, density=True, bins=bins) h2, b = np.histogram(rhgt, density=True, bins=bins) h1 = h1 / np.sum(h1) h2 = h2 / np.sum(h2) assert utils.rmsd(h1, h2) < 0.02 # less than 2% error new_area = np.sum(widths * fls[-1].dx * gdir.grid.dx) np.testing.assert_allclose(new_area, gdir.rgi_area_m2)
def test_run_until_equilibrium(self): """""" # let's not use the mass balance bias since we want to reproduce # results from mass balance calibration cfg.PARAMS['use_bias_for_run'] = False # read the Hintereisferner DEM hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] # initialize the GlacierDirectory gdir = oggm.GlacierDirectory(entity, base_dir=self.testdir) # define the local grid and glacier mask gis.define_glacier_region(gdir, entity=entity) gis.glacier_masks(gdir) # process the given climate file climate.process_custom_climate_data(gdir) # compute mass balance parameters ref_df = cfg.PARAMS['vas_ref_tstars_rgi5_histalp'] vascaling.local_t_star(gdir, ref_df=ref_df) # instance a constant mass balance model, centred around t* mb_model = vascaling.ConstantVASMassBalance(gdir) # add a positive temperature bias mb_model.temp_bias = 0.5 # create a VAS model: start with year 0 since we are using a constant # massbalance model, other values are read from RGI min_hgt, max_hgt = vascaling.get_min_max_elevation(gdir) model = vascaling.VAScalingModel(year_0=0, area_m2_0=gdir.rgi_area_m2, min_hgt=min_hgt, max_hgt=max_hgt, mb_model=mb_model) # run glacier with new mass balance model model.run_until_equilibrium(rate=1e-4) # equilibrium should be reached after a couple of 100 years assert model.year <= 300 # new equilibrium glacier should be smaller (positive temperature bias) assert model.volume_m3 < model.volume_m3_0 # run glacier for another 100 years and check volume again v_eq = model.volume_m3 model.run_until(model.year + 100) assert abs(1 - (model.volume_m3 / v_eq)) < 0.01
def _setup_mb_test(self): """Avoiding a chunk of code duplicate. Performs needed prepo tasks and returns the oggm.GlacierDirectory. """ # read the Hintereisferner DEM hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] # initialize the GlacierDirectory gdir = oggm.GlacierDirectory(entity, base_dir=self.testdir) # define the local grid and the glacier mask gis.define_glacier_region(gdir, entity=entity) gis.glacier_masks(gdir) # process the given climate file climate.process_custom_climate_data(gdir) # run centerline prepro tasks centerlines.compute_centerlines(gdir) centerlines.initialize_flowlines(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir) centerlines.catchment_width_correction(gdir) # read reference glacier mass balance data mbdf = gdir.get_ref_mb_data() # compute the reference t* for the glacier # given the reference of mass balance measurements res = vascaling.t_star_from_refmb(gdir, mbdf=mbdf['ANNUAL_BALANCE']) t_star, bias = res['t_star'], res['bias'] # compute local t* and the corresponding mu* vascaling.local_t_star(gdir, tstar=t_star, bias=bias) # run OGGM mu* calibration climate.local_t_star(gdir, tstar=t_star, bias=bias) climate.mu_star_calibration(gdir) # pass the GlacierDirectory return gdir
def seek_start_area(rgi_id, name, show=False, path='', ref=np.NaN, adjust_term_elev=False, legend=True, instant_geometry_change=False): """ Set up an VAS model from scratch and run/test the start area seeking tasks. The result is a plot showing the modeled glacier area evolution for different start values. The plots can be displayed and/or stored to file. Parameters ---------- rgi_id: string RGI ID denoting the glacier on which to perform the tasks name: string Name og glacier, since it is not always given (or correct) in RGI show: bool, optional, default=False Flag deciding whether or not to show the created plots. path: string, optional, default='' Path under which the modeled area plot should be stored. ref: float, optional, default=np.NaN Historic (1851) reference area with which a reference model run is performed. """ # Initialization and load default parameter file vascaling.initialize() # compute RGI region and version from RGI IDs # assuming they all are all the same rgi_region = (rgi_id.split('-')[-1]).split('.')[0] rgi_version = (rgi_id.split('-')[0])[-2:-1] # specify working directory and output directory working_dir = os.path.abspath('../working_directories/start_area/') # output_dir = os.path.abspath('./vas_run_output') output_dir = os.path.abspath('../data/vas_run_output') # create working directory utils.mkdir(working_dir, reset=False) utils.mkdir(output_dir) # set path to working directory cfg.PATHS['working_dir'] = working_dir # set RGI version and region cfg.PARAMS['rgi_version'] = rgi_version # define how many grid points to use around the glacier, # if you expect the glacier to grow large use a larger border cfg.PARAMS['border'] = 20 # we use HistAlp climate data cfg.PARAMS['baseline_climate'] = 'HISTALP' # set the mb hyper parameters accordingly cfg.PARAMS['prcp_scaling_factor'] = 1.75 cfg.PARAMS['temp_melt'] = -1.75 cfg.PARAMS['run_mb_calibration'] = False # the bias is defined to be zero during the calibration process, # which is why we don't use it here to reproduce the results cfg.PARAMS['use_bias_for_run'] = True # get/downlaod the rgi entity including the outline shapefile rgi_df = utils.get_rgi_glacier_entities([rgi_id]) # set name, if not delivered with RGI if rgi_df.loc[int(rgi_id[-5:]) - 1, 'Name'] is None: rgi_df.loc[int(rgi_id[-5:]) - 1, 'Name'] = name # get and set path to intersect shapefile intersects_db = utils.get_rgi_intersects_region_file(region=rgi_region) cfg.set_intersects_db(intersects_db) # initialize the GlacierDirectory gdir = workflow.init_glacier_directories(rgi_df)[0] # # DEM and GIS tasks # # get the path to the DEM file (will download if necessary) # dem = utils.get_topo_file(gdir.cenlon, gdir.cenlat) # print('DEM source: {}, path to DEM file: {}'.format(dem[1], dem[0][0])) # # set path in config file # cfg.PATHS['dem_file'] = dem[0][0] # cfg.PARAMS['border'] = 10 # cfg.PARAMS['use_intersects'] = False # run GIS tasks gis.define_glacier_region(gdir) gis.glacier_masks(gdir) # process climate data climate.process_climate_data(gdir) # compute local t* and the corresponding mu* vascaling.local_t_star(gdir) # create mass balance model mb_mod = vascaling.VAScalingMassBalance(gdir) # look at specific mass balance over climate data period min_hgt, max_hgt = vascaling.get_min_max_elevation(gdir) y0 = 1851 y1 = 2014 # run scalar minimization minimize_res = vascaling.find_start_area( gdir, adjust_term_elev=adjust_term_elev, instant_geometry_change=instant_geometry_change) # print(minimize_res) # stop script if minimization was not successful if minimize_res.status and False: sys.exit(minimize_res.status) # instance glacier with today's values model_ref = vascaling.VAScalingModel(year_0=gdir.rgi_date, area_m2_0=gdir.rgi_area_m2, min_hgt=min_hgt, max_hgt=max_hgt, mb_model=mb_mod) # instance guessed starting areas num = 9 area_guess = np.linspace(1e6, np.floor(gdir.rgi_area_m2 * 2), num, endpoint=True) # create empty containers area_list = list() volume_list = list() spec_mb_list = list() # iterate over all starting areas for area_ in area_guess: # instance iteration model model_guess = vascaling.VAScalingModel(year_0=gdir.rgi_date, area_m2_0=gdir.rgi_area_m2, min_hgt=min_hgt, max_hgt=max_hgt, mb_model=mb_mod) # set new starting values model_guess.create_start_glacier(area_, y0, adjust_term_elev=adjust_term_elev) # run model and save years and area best_guess_ds = model_guess.run_until_and_store( year_end=model_ref.year, instant_geometry_change=instant_geometry_change) # create series and store in container area_list.append(best_guess_ds.area_m2.to_dataframe()['area_m2']) volume_list.append(best_guess_ds.volume_m3.to_dataframe()['volume_m3']) spec_mb_list.append(best_guess_ds.spec_mb.to_dataframe()['spec_mb']) # create DataFrame area_df = pd.DataFrame( area_list, index=['{:.2f}'.format(a / 1e6) for a in area_guess]) area_df.index.name = 'Start Area [km$^2$]' volume_df = pd.DataFrame( volume_list, index=['{:.2f}'.format(a / 1e6) for a in area_guess]) volume_df.index.name = 'Start Area [km$^2$]' # set up model with resulted starting area model = vascaling.VAScalingModel(year_0=model_ref.year_0, area_m2_0=model_ref.area_m2_0, min_hgt=model_ref.min_hgt_0, max_hgt=model_ref.max_hgt, mb_model=model_ref.mb_model) model.create_start_glacier(minimize_res.x, y0, adjust_term_elev=adjust_term_elev) # run model with best guess initial area best_guess_ds = model.run_until_and_store( year_end=model_ref.year, instant_geometry_change=instant_geometry_change) # run model with historic reference area if ref: model.reset() model.create_start_glacier(ref * 1e6, y0, adjust_term_elev=adjust_term_elev) ref_ds = model.run_until_and_store( year_end=model_ref.year, instant_geometry_change=instant_geometry_change) # create figure and add axes fig = plt.figure(figsize=[5, 5]) ax = fig.add_axes([0.125, 0.075, 0.85, 0.9]) # plot model output ax = (area_df / 1e6).T.plot(legend=False, colormap='Spectral', ax=ax) # plot best guess ax.plot( best_guess_ds.time, best_guess_ds.area_m2 / 1e6, color='k', ls='--', lw=1.2, label= f'{best_guess_ds.area_m2.isel(time=0).values/1e6:.2f} km$^2$ (best result)' ) # plot reference if ref: ax.plot( ref_ds.time, ref_ds.area_m2 / 1e6, color='k', ls='-.', lw=1.2, label= f'{ref_ds.area_m2.isel(time=0).values/1e6:.2f} km$^2$ (1850 ref.)') # plot 2003 reference line ax.axhline( model_ref.area_m2_0 / 1e6, c='k', ls=':', label=f'{model_ref.area_m2_0/1e6:.2f} km$^2$ ({gdir.rgi_date} obs.)') # add legend if legend: handels, labels = ax.get_legend_handles_labels() labels[:-3] = [r'{} km$^2$'.format(l) for l in labels[:-3]] leg = ax.legend(handels, labels, loc='upper right', ncol=2) # leg.set_title('Start area $A_0$', prop={'size': 12}) # replot best guess estimate and reference (in case it lies below another # guess) ax.plot(best_guess_ds.time, best_guess_ds.area_m2 / 1e6, color='k', ls='--', lw=1.2) if ref: ax.plot(ref_ds.time, ref_ds.area_m2 / 1e6, color='k', ls='-.', lw=1.2) # labels, title ax.set_xlim([best_guess_ds.time.values[0], best_guess_ds.time.values[-1]]) ax.set_xlabel('') ax.set_ylabel('Glacier area [km$^2$]') # save figure to file if path: fig.savefig(path) # show plot if show: plt.show() plt.clf() # plot and store volume evolution (volume_df / 1e9).T.plot(legend=False, colormap='viridis') plt.gcf().savefig(path[:-4] + '_volume.pdf')
def init_hef(reset=False, border=40): # test directory testdir = os.path.join(get_test_dir(), 'tmp_border{}'.format(border)) if not os.path.exists(testdir): os.makedirs(testdir) reset = True # Init cfg.initialize() cfg.set_intersects_db(get_demo_file('rgi_intersect_oetztal.shp')) cfg.PATHS['dem_file'] = get_demo_file('hef_srtm.tif') cfg.PATHS['climate_file'] = get_demo_file('histalp_merged_hef.nc') cfg.PARAMS['baseline_climate'] = '' cfg.PATHS['working_dir'] = testdir cfg.PARAMS['border'] = border hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] gdir = oggm.GlacierDirectory(entity, reset=reset) if not gdir.has_file('inversion_params'): reset = True gdir = oggm.GlacierDirectory(entity, reset=reset) if not reset: return gdir gis.define_glacier_region(gdir, entity=entity) execute_entity_task(gis.glacier_masks, [gdir]) execute_entity_task(centerlines.compute_centerlines, [gdir]) centerlines.initialize_flowlines(gdir) centerlines.compute_downstream_line(gdir) centerlines.compute_downstream_bedshape(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir) centerlines.catchment_width_correction(gdir) climate.process_custom_climate_data(gdir) mbdf = gdir.get_ref_mb_data()['ANNUAL_BALANCE'] res = climate.t_star_from_refmb(gdir, mbdf=mbdf) climate.local_t_star(gdir, tstar=res['t_star'], bias=res['bias']) climate.mu_star_calibration(gdir) inversion.prepare_for_inversion(gdir, add_debug_var=True) ref_v = 0.573 * 1e9 glen_n = cfg.PARAMS['glen_n'] def to_optimize(x): # For backwards compat _fd = 1.9e-24 * x[0] glen_a = (glen_n+2) * _fd / 2. fs = 5.7e-20 * x[1] v, _ = inversion.mass_conservation_inversion(gdir, fs=fs, glen_a=glen_a) return (v - ref_v)**2 out = optimization.minimize(to_optimize, [1, 1], bounds=((0.01, 10), (0.01, 10)), tol=1e-4)['x'] _fd = 1.9e-24 * out[0] glen_a = (glen_n+2) * _fd / 2. fs = 5.7e-20 * out[1] v, _ = inversion.mass_conservation_inversion(gdir, fs=fs, glen_a=glen_a, write=True) d = dict(fs=fs, glen_a=glen_a) d['factor_glen_a'] = out[0] d['factor_fs'] = out[1] gdir.write_pickle(d, 'inversion_params') # filter inversion.filter_inversion_output(gdir) inversion.distribute_thickness_interp(gdir, varname_suffix='_interp') inversion.distribute_thickness_per_altitude(gdir, varname_suffix='_alt') flowline.init_present_time_glacier(gdir) return gdir
def init_hef(reset=False, border=40, invert_with_sliding=True, invert_with_rectangular=True): # test directory testdir = os.path.join(get_test_dir(), 'tmp_border{}'.format(border)) if not invert_with_sliding: testdir += '_withoutslide' if not invert_with_rectangular: testdir += '_withoutrectangular' if not os.path.exists(testdir): os.makedirs(testdir) reset = True # Init cfg.initialize() cfg.set_intersects_db(get_demo_file('rgi_intersect_oetztal.shp')) cfg.PATHS['dem_file'] = get_demo_file('hef_srtm.tif') cfg.PATHS['climate_file'] = get_demo_file('histalp_merged_hef.nc') cfg.PARAMS['border'] = border cfg.PARAMS['use_optimized_inversion_params'] = True hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] gdir = oggm.GlacierDirectory(entity, base_dir=testdir, reset=reset) if not gdir.has_file('inversion_params'): reset = True gdir = oggm.GlacierDirectory(entity, base_dir=testdir, reset=reset) if not reset: return gdir gis.define_glacier_region(gdir, entity=entity) execute_entity_task(gis.glacier_masks, [gdir]) execute_entity_task(centerlines.compute_centerlines, [gdir]) centerlines.initialize_flowlines(gdir) centerlines.compute_downstream_line(gdir) centerlines.compute_downstream_bedshape(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir) centerlines.catchment_width_correction(gdir) climate.process_custom_climate_data(gdir) climate.mu_candidates(gdir) mbdf = gdir.get_ref_mb_data()['ANNUAL_BALANCE'] res = climate.t_star_from_refmb(gdir, mbdf) climate.local_mustar(gdir, tstar=res['t_star'][-1], bias=res['bias'][-1], prcp_fac=res['prcp_fac']) climate.apparent_mb(gdir) inversion.prepare_for_inversion( gdir, add_debug_var=True, invert_with_rectangular=invert_with_rectangular) ref_v = 0.573 * 1e9 if invert_with_sliding: def to_optimize(x): # For backwards compat _fd = 1.9e-24 * x[0] glen_a = (cfg.N + 2) * _fd / 2. fs = 5.7e-20 * x[1] v, _ = inversion.mass_conservation_inversion(gdir, fs=fs, glen_a=glen_a) return (v - ref_v)**2 out = optimization.minimize(to_optimize, [1, 1], bounds=((0.01, 10), (0.01, 10)), tol=1e-4)['x'] _fd = 1.9e-24 * out[0] glen_a = (cfg.N + 2) * _fd / 2. fs = 5.7e-20 * out[1] v, _ = inversion.mass_conservation_inversion(gdir, fs=fs, glen_a=glen_a, write=True) else: def to_optimize(x): glen_a = cfg.A * x[0] v, _ = inversion.mass_conservation_inversion(gdir, fs=0., glen_a=glen_a) return (v - ref_v)**2 out = optimization.minimize(to_optimize, [1], bounds=((0.01, 10), ), tol=1e-4)['x'] glen_a = cfg.A * out[0] fs = 0. v, _ = inversion.mass_conservation_inversion(gdir, fs=fs, glen_a=glen_a, write=True) d = dict(fs=fs, glen_a=glen_a) d['factor_glen_a'] = out[0] try: d['factor_fs'] = out[1] except IndexError: d['factor_fs'] = 0. gdir.write_pickle(d, 'inversion_params') # filter inversion.filter_inversion_output(gdir) inversion.distribute_thickness_interp(gdir, varname_suffix='_interp') inversion.distribute_thickness_per_altitude(gdir, varname_suffix='_alt') flowline.init_present_time_glacier(gdir) return gdir
def test_terminus_temp(self): """Testing the subroutine which computes the terminus temperature from the given climate file and glacier DEM. Pretty straight forward and somewhat useless, but nice finger exercise. """ # read the Hintereisferner DEM hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] # initialize the GlacierDirectory gdir = oggm.GlacierDirectory(entity, base_dir=self.testdir) # define the local grid gis.define_glacier_region(gdir, entity=entity) # process the given climate file climate.process_custom_climate_data(gdir) # read the following variable from the center pixel (46.83N 10.75E) # of the Hintereisferner HistAlp climate file for the # entire time period from October 1801 until September 2003 # - surface height in m asl. # - total precipitation amount in kg/m2 # - 2m air temperature in °C with utils.ncDataset(get_demo_file('histalp_merged_hef.nc')) as nc_r: ref_h = nc_r.variables['hgt'][1, 1] ref_t = nc_r.variables['temp'][:, 1, 1] # define a temperature anomaly temp_anomaly = 0 # specify temperature gradient temp_grad = -0.0065 # the terminus temperature must equal the input temperature # if terminus elevation equals reference elevation temp_terminus =\ vascaling._compute_temp_terminus(ref_t, temp_grad, ref_hgt=ref_h, terminus_hgt=ref_h, temp_anomaly=temp_anomaly) np.testing.assert_allclose(temp_terminus, ref_t + temp_anomaly) # the terminus temperature must equal the input terperature # if the gradient is zero for term_h in np.array([-100, 0, 100]) + ref_h: temp_terminus =\ vascaling._compute_temp_terminus(ref_t, temp_grad=0, ref_hgt=ref_h, terminus_hgt=term_h, temp_anomaly=temp_anomaly) np.testing.assert_allclose(temp_terminus, ref_t + temp_anomaly) # now test the routine with actual elevation differences # and a non zero temperature gradient for h_diff in np.array([-100, 0, 100]): term_h = ref_h + h_diff temp_diff = temp_grad * h_diff temp_terminus =\ vascaling._compute_temp_terminus(ref_t, temp_grad, ref_hgt=ref_h, terminus_hgt=term_h, temp_anomaly=temp_anomaly) np.testing.assert_allclose(temp_terminus, ref_t + temp_anomaly + temp_diff)
cfg.PATHS['dem_file'] = get_demo_file('hef_srtm.tif') cfg.PATHS['climate_file'] = get_demo_file('histalp_merged_hef.nc') cfg.PARAMS['border'] = 10 cfg.PARAMS['run_mb_calibration'] = True cfg.PARAMS['baseline_climate'] = '' cfg.PARAMS['use_multiprocessing'] = True # read the Hintereisferner DEM hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] from oggm.core import gis # initialize the GlacierDirectory gdir = oggm.GlacierDirectory(entity, base_dir=testdir) # define the local grid and glacier mask gis.define_glacier_region(gdir, entity=entity) gis.glacier_masks(gdir) from oggm.core import climate # process the given climate file climate.process_custom_climate_data(gdir) from oggm.core import centerlines # run center line preprocessing tasks centerlines.compute_centerlines(gdir) centerlines.initialize_flowlines(gdir) centerlines.compute_downstream_line(gdir) centerlines.compute_downstream_bedshape(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir)
def test_run_until_and_store(self): """Test the volume/area scaling model against the oggm.FluxBasedModel. Both models run the Hintereisferner over the entire HistAlp climate period, initialized with the 2003 RGI outline without spin up. The following two parameters for length, area and volume are tested: - correlation coefficient - relative RMSE, i.e. RMSE/mean(OGGM). Whereby the results from the VAS model are offset with the average differences to the OGGM results. """ # read the Hintereisferner DEM hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] # initialize the GlacierDirectory gdir = oggm.GlacierDirectory(entity, base_dir=self.testdir) # define the local grid and glacier mask gis.define_glacier_region(gdir, entity=entity) gis.glacier_masks(gdir) # process the given climate file climate.process_custom_climate_data(gdir) # run center line preprocessing tasks centerlines.compute_centerlines(gdir) centerlines.initialize_flowlines(gdir) centerlines.compute_downstream_line(gdir) centerlines.compute_downstream_bedshape(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir) centerlines.catchment_width_correction(gdir) # read reference glacier mass balance data mbdf = gdir.get_ref_mb_data() # compute the reference t* for the glacier # given the reference of mass balance measurements res = climate.t_star_from_refmb(gdir, mbdf=mbdf['ANNUAL_BALANCE']) t_star, bias = res['t_star'], res['bias'] # -------------------- # SCALING MODEL # -------------------- # compute local t* and the corresponding mu* vascaling.local_t_star(gdir, tstar=t_star, bias=bias) # instance the mass balance models vas_mbmod = vascaling.VAScalingMassBalance(gdir) # get reference area a0 = gdir.rgi_area_m2 # get reference year y0 = gdir.read_json('climate_info')['baseline_hydro_yr_0'] # get min and max glacier surface elevation h0, h1 = vascaling.get_min_max_elevation(gdir) vas_model = vascaling.VAScalingModel(year_0=y0, area_m2_0=a0, min_hgt=h0, max_hgt=h1, mb_model=vas_mbmod) # let model run over entire HistAlp climate period vas_ds = vas_model.run_until_and_store(2003) # ------ # OGGM # ------ # compute local t* and the corresponding mu* climate.local_t_star(gdir, tstar=t_star, bias=bias) climate.mu_star_calibration(gdir) # instance the mass balance models mb_mod = massbalance.PastMassBalance(gdir) # perform ice thickness inversion inversion.prepare_for_inversion(gdir) inversion.mass_conservation_inversion(gdir) inversion.filter_inversion_output(gdir) # initialize present time glacier flowline.init_present_time_glacier(gdir) # instance flowline model fls = gdir.read_pickle('model_flowlines') y0 = gdir.read_json('climate_info')['baseline_hydro_yr_0'] fl_mod = flowline.FluxBasedModel(flowlines=fls, mb_model=mb_mod, y0=y0) # run model and store output as xarray data set _, oggm_ds = fl_mod.run_until_and_store(2003) # temporal indices must be equal assert (vas_ds.time == oggm_ds.time).all() # specify which parameters to compare and their respective correlation # coefficients and rmsd values params = ['length_m', 'area_m2', 'volume_m3'] corr_coeffs = np.array([0.96, 0.90, 0.93]) rmsds = np.array([0.43e3, 0.14e6, 0.03e9]) # compare given parameters for param, cc, rmsd in zip(params, corr_coeffs, rmsds): # correlation coefficient assert corrcoef(oggm_ds[param].values, vas_ds[param].values) >= cc # root mean squared deviation rmsd_an = rmsd_bc(oggm_ds[param].values, vas_ds[param].values) assert rmsd_an <= rmsd
def test_solid_prcp(self): """Tests the subroutine which computes solid precipitation amount from given total precipitation and temperature. """ # read the Hintereisferner DEM hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] # initialize the GlacierDirectory gdir = oggm.GlacierDirectory(entity, base_dir=self.testdir) # define the local grid gis.define_glacier_region(gdir, entity=entity) # process the given climate file climate.process_custom_climate_data(gdir) # read the following variable from the center pixel (46.83N 10.75E) # of the Hintereisferner HistAlp climate file for the # entire time period from October 1801 until September 2003 # - surface height in m asl. # - total precipitation amount in kg/m2 # - 2m air temperature in °C with utils.ncDataset(get_demo_file('histalp_merged_hef.nc')) as nc_r: ref_h = nc_r.variables['hgt'][1, 1] ref_p = nc_r.variables['prcp'][:, 1, 1] ref_t = nc_r.variables['temp'][:, 1, 1] # define needed parameters prcp_factor = 1 temp_all_solid = 0 temp_grad = -0.0065 # define elevation levels ref_hgt = ref_h min_hgt = ref_h - 100 max_hgt = ref_h + 100 # if the terminus temperature is below the threshold for # solid precipitation all fallen precipitation must be solid temp_terminus = ref_t * 0 + temp_all_solid solid_prcp = vascaling._compute_solid_prcp(ref_p, prcp_factor, ref_hgt, min_hgt, max_hgt, temp_terminus, temp_all_solid, temp_grad, prcp_grad=0, prcp_anomaly=0) np.testing.assert_allclose(solid_prcp, ref_p) # if the temperature at the maximal elevation is above the threshold # for solid precipitation all fallen precipitation must be liquid temp_terminus = ref_t + 100 solid_prcp = vascaling._compute_solid_prcp(ref_p, prcp_factor, ref_hgt, min_hgt, max_hgt, temp_terminus, temp_all_solid, temp_grad, prcp_grad=0, prcp_anomaly=0) np.testing.assert_allclose(solid_prcp, 0) # test extreme case if max_hgt equals min_hgt test_p = ref_p * (ref_t <= temp_all_solid).astype(int) solid_prcp = vascaling._compute_solid_prcp(ref_p, prcp_factor, ref_hgt, ref_hgt, ref_hgt, ref_t, temp_all_solid, temp_grad, prcp_grad=0, prcp_anomaly=0) np.testing.assert_allclose(solid_prcp, test_p)
def init_hef(reset=False, border=40, logging_level='INFO'): from oggm.core import gis, inversion, climate, centerlines, flowline import geopandas as gpd # test directory testdir = os.path.join(get_test_dir(), 'tmp_border{}'.format(border)) if not os.path.exists(testdir): os.makedirs(testdir) reset = True # Init cfg.initialize(logging_level=logging_level) cfg.set_intersects_db(get_demo_file('rgi_intersect_oetztal.shp')) cfg.PATHS['dem_file'] = get_demo_file('hef_srtm.tif') cfg.PATHS['climate_file'] = get_demo_file('histalp_merged_hef.nc') cfg.PARAMS['baseline_climate'] = '' cfg.PATHS['working_dir'] = testdir cfg.PARAMS['border'] = border hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] gdir = oggm.GlacierDirectory(entity, reset=reset) if not gdir.has_file('inversion_params'): reset = True gdir = oggm.GlacierDirectory(entity, reset=reset) if not reset: return gdir gis.define_glacier_region(gdir) execute_entity_task(gis.glacier_masks, [gdir]) execute_entity_task(centerlines.compute_centerlines, [gdir]) centerlines.initialize_flowlines(gdir) centerlines.compute_downstream_line(gdir) centerlines.compute_downstream_bedshape(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir) centerlines.catchment_width_correction(gdir) climate.process_custom_climate_data(gdir) mbdf = gdir.get_ref_mb_data()['ANNUAL_BALANCE'] res = climate.t_star_from_refmb(gdir, mbdf=mbdf) climate.local_t_star(gdir, tstar=res['t_star'], bias=res['bias']) climate.mu_star_calibration(gdir) inversion.prepare_for_inversion(gdir, add_debug_var=True) ref_v = 0.573 * 1e9 glen_n = cfg.PARAMS['glen_n'] def to_optimize(x): # For backwards compat _fd = 1.9e-24 * x[0] glen_a = (glen_n + 2) * _fd / 2. fs = 5.7e-20 * x[1] v, _ = inversion.mass_conservation_inversion(gdir, fs=fs, glen_a=glen_a) return (v - ref_v)**2 out = optimization.minimize(to_optimize, [1, 1], bounds=((0.01, 10), (0.01, 10)), tol=1e-4)['x'] _fd = 1.9e-24 * out[0] glen_a = (glen_n + 2) * _fd / 2. fs = 5.7e-20 * out[1] v, _ = inversion.mass_conservation_inversion(gdir, fs=fs, glen_a=glen_a, write=True) d = dict(fs=fs, glen_a=glen_a) d['factor_glen_a'] = out[0] d['factor_fs'] = out[1] gdir.write_pickle(d, 'inversion_params') # filter inversion.filter_inversion_output(gdir) inversion.distribute_thickness_interp(gdir, varname_suffix='_interp') inversion.distribute_thickness_per_altitude(gdir, varname_suffix='_alt') flowline.init_present_time_glacier(gdir) return gdir
def compare(rgi_id, glacier_name): """ :param rgi_id: :param glacier_name: :return: """ # --------------------- # PREPROCESSING TASKS # --------------------- # create test directory wdir = os.path.join(os.path.abspath('.'), 'comparison_wdir') if not os.path.exists(wdir): os.makedirs(wdir) shutil.rmtree(wdir) os.makedirs(wdir) # load default parameter file cfg.initialize() # RGI entity # get/downlaod the rgi entity including the outline shapefile rgi_df = utils.get_rgi_glacier_entities([rgi_id]) # set name, since not delivered with RGI if rgi_df.loc[int(rgi_id[-5:])-1, 'Name'] is None: rgi_df.loc[int(rgi_id[-5:])-1, 'Name'] = glacier_name # select single entry rgi_entity = rgi_df.iloc[0] # GlacierDirectory # specify the working directory and define the glacier directory cfg.PATHS['working_dir'] = wdir gdir = oggm.GlacierDirectory(rgi_entity) # DEM and GIS tasks # get the path to the DEM file (will download if necessary) dem = utils.get_topo_file(gdir.cenlon, gdir.cenlat) # set path in config file cfg.PATHS['dem_file'] = dem[0][0] cfg.PARAMS['border'] = 10 cfg.PARAMS['use_intersects'] = False # run GIS tasks gis.define_glacier_region(gdir, entity=rgi_entity) gis.glacier_masks(gdir) # Climate data # using HistAlp cfg.PARAMS['baseline_climate'] = 'HISTALP' # climate records before 1850 are hardly reliable, which is not so drastic for # qualitative experiments (could be driven with random climate anyway) # cfg.PARAMS['baseline_y0'] = 1850 # change hyper parameters for HistAlp cfg.PARAMS['prcp_scaling_factor'] = 1.75 cfg.PARAMS['temp_melt'] = -1.75 # run climate task climate.process_histalp_data(gdir) # run center line preprocessing tasks centerlines.compute_centerlines(gdir) centerlines.initialize_flowlines(gdir) centerlines.compute_downstream_line(gdir) centerlines.compute_downstream_bedshape(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir) centerlines.catchment_width_correction(gdir) # -------------------- # SCALING MODEL # -------------------- # compute local t* and the corresponding mu* vascaling.local_t_star(gdir) # instance the mass balance models vas_mb_mod = vascaling.VAScalingMassBalance(gdir) # get reference area a0 = gdir.rgi_area_m2 # get reference year y0 = gdir.read_pickle('climate_info')['baseline_hydro_yr_0'] y1 = gdir.read_pickle('climate_info')['baseline_hydro_yr_1'] # get min and max glacier surface elevation h0, h1 = vascaling.get_min_max_elevation(gdir) # instance VAS model vas_model = vascaling.VAScalingModel(year_0=y0, area_m2_0=a0, min_hgt=h0, max_hgt=h1, mb_model=vas_mb_mod) # run model over all HistAlp climate period vas_df = vas_model.run_and_store(y1, reset=True) # get relevant parameters years_vas = vas_df.index.values length_m_vas = vas_df.length_m.values area_m2_vas = vas_df.area_m2.values volume_m3_vas = vas_df.volume_m3.values # ------ # OGGM # ------ # compute local t* and the corresponding mu* climate.local_t_star(gdir) climate.mu_star_calibration(gdir) # instance the mass balance models mb_mod = massbalance.PastMassBalance(gdir) # run inversion tasks inversion.prepare_for_inversion(gdir) inversion.mass_conservation_inversion(gdir) inversion.filter_inversion_output(gdir) # initialize present time glacier flowline.init_present_time_glacier(gdir) # instance flowline model fls = gdir.read_pickle('model_flowlines') y0 = gdir.read_pickle('climate_info')['baseline_hydro_yr_0'] y1 = gdir.read_pickle('climate_info')['baseline_hydro_yr_1'] fl_mod = flowline.FluxBasedModel(flowlines=fls, mb_model=mb_mod, y0=y0) # run model and store output as xarray data set _, oggm_ds = fl_mod.run_until_and_store(y1) years_oggm = oggm_ds.hydro_year.values # annual index must be equal np.testing.assert_array_equal(years_oggm, years_vas) length_m_oggm = oggm_ds.length_m.values area_m2_oggm = oggm_ds.area_m2.values volume_m3_oggm = oggm_ds.volume_m3.values # define column names for DataFrame names = ['length_vas', 'length_oggm', 'area_vas', 'area_oggm', 'volume_vas', 'volume_oggm'] # combine glacier geometries into DataFrame df = pd.DataFrame(np.array([length_m_vas, length_m_oggm, area_m2_vas, area_m2_oggm, volume_m3_vas, volume_m3_oggm]).T, index=years_vas, columns=names) # save to file store = True if store: # define path and file names folder = '/Users/oberrauch/work/master/data/' df.to_csv(folder+'run_comparison.csv') def plot_both(vas_df, oggm_df, ref=None, correct_bias=False, title='', ylabel='', file_path='', exp=0): """ Plot geometric parameters of both models. If a `file_path` is given, the figure will be saved. :param vas_df: (pandas.Series) geometric glacier parameter of the VAS model :param oggm_df: (pandas.Series) geometric glacier parameter of the OGGM :param ref: (pandas.Series) measured glacier parameter, optional :param title: (string) figure title, optional :param ylabel: (string) label for y-axis, optional :param file_path: (string) where to store the figure, optional :param exp: (int) exponent for labels in scientific notation, optional """ beamer = True if beamer: mpl.rc('axes', titlesize=18) mpl.rc('axes', labelsize=14) mpl.rc('xtick', labelsize=14) mpl.rc('ytick', labelsize=14) mpl.rc('legend', fontsize=10) # create figure and first axes fig = plt.figure(figsize=[6, 4]) ax = fig.add_axes([0.15, 0.1, 0.8, 0.8]) # define colors c1 = 'C0' c2 = 'C1' c3 = 'C3' # plot vas and OGGM parameters ax.plot(oggm_df.index, oggm_df.values, c=c2, label='OGGM') ax.plot(vas_df.index, vas_df.values, c=c1, label='VAS') if ref: # plot reference parameter if given ax.plot(ref.index, ref.values, c=c3, label='measurements') if correct_bias: # plot bias corrected vas df_ = pd.DataFrame([oggm_df, vas_df]).T bias = vas_df.values - df_.mean().diff().iloc[1] ax.plot(vas_df.index, bias, c=c1, ls='--', label='VAS, bias corrected') # add RMSD as text ax.text(0.05, 0.05, 'RMSD: {:.1e}'.format(utils.rmsd(oggm_df, bias)), transform=plt.gca().transAxes) # add correlation coefficient as text ax.text(0.05, 0.11, 'Corr. Coef.: {:.2f}'.format( utils.corrcoef(oggm_df, vas_df)), transform=plt.gca().transAxes) # add title, labels, legend ax.set_title(title) ax.set_ylabel(ylabel) ax.legend() import matplotlib.ticker class OOMFormatter(matplotlib.ticker.ScalarFormatter): def __init__(self, order=0, fformat="%1.1f", offset=False, mathText=False): self.oom = order self.fformat = fformat matplotlib.ticker.ScalarFormatter.__init__(self, useOffset=offset, useMathText=mathText) def _set_orderOfMagnitude(self, nothing): self.orderOfMagnitude = self.oom def _set_format(self, vmin, vmax): self.format = self.fformat if self._useMathText: self.format = '$%s$' % matplotlib.ticker._mathdefault(self.format) # use scientific notation with fixed exponent according ax.yaxis.set_major_formatter(OOMFormatter(exp, "%1.2f")) # store to file if file_path: plt.savefig(file_path, bbox_inches='tight', format=file_path.split('.')[-1]) # specify plot directory folder = '/Users/oberrauch/work/master/plots/' # plot length plot_both(df.length_vas, df.length_oggm, correct_bias=True, title='Glacier length - {}'.format(glacier_name), ylabel=r'Length [m]', file_path=os.path.join(folder, '{}_length.pdf'.format(rgi_id)), exp=3) # plot area plot_both(df.area_vas, df.area_oggm, correct_bias=True, title='Surface area - {}'.format(glacier_name), ylabel=r'Area [m$^2$]', file_path=os.path.join(folder, '{}_area.pdf'.format(rgi_id)), exp=6) # plot volume plot_both(df.volume_vas, df.volume_oggm, correct_bias=True, title='Glacier volume - {}'.format(glacier_name), ylabel=r'Volume [m$^3$]', file_path=os.path.join(folder, '{}_volume.pdf'.format(rgi_id)), exp=9)
def test_yearly_mb_temp_prcp(self): """Test the routine which returns the yearly mass balance relevant climate parameters, i.e. positive melting temperature and solid precipitation. The testing target is the output of the corresponding OGGM routine `get_yearly_mb_climate_on_glacier(gdir)`. """ # read the Hintereisferner DEM hef_file = get_demo_file('Hintereisferner_RGI5.shp') entity = gpd.read_file(hef_file).iloc[0] # initialize the GlacierDirectory gdir = oggm.GlacierDirectory(entity, base_dir=self.testdir) # define the local grid and glacier mask gis.define_glacier_region(gdir, entity=entity) gis.glacier_masks(gdir) # run centerline prepro tasks centerlines.compute_centerlines(gdir) centerlines.initialize_flowlines(gdir) centerlines.catchment_area(gdir) centerlines.catchment_intersections(gdir) centerlines.catchment_width_geom(gdir) centerlines.catchment_width_correction(gdir) # process the given climate file climate.process_custom_climate_data(gdir) # get yearly sums of terminus temperature and solid precipitation years, temp, prcp = vascaling.get_yearly_mb_temp_prcp(gdir) # use the OGGM methode to get the mass balance # relevant climate parameters years_oggm, temp_oggm, prcp_oggm = \ climate.mb_yearly_climate_on_glacier(gdir) # the energy input at the glacier terminus must be greater than (or # equal to) the glacier wide average, since the air temperature drops # with elevation, i.e. the mean deviation must be positive, using the # OGGM data as reference assert md(temp_oggm, temp) >= 0 # consequentially, the average mass input must be less than (or equal # to) the mass input integrated over the whole glacier surface, i.e. # the mean deviation must be negative, using the OGGM data as reference # TODO: does it actually?! And if so, why?! @ASK assert md(prcp_oggm, prcp) <= 0 # correlation must be higher than set threshold assert corrcoef(temp, temp_oggm) >= 0.94 assert corrcoef(prcp, prcp_oggm) >= 0.98 # get terminus temperature using the OGGM routine fpath = gdir.get_filepath('gridded_data') with ncDataset(fpath) as nc: mask = nc.variables['glacier_mask'][:] topo = nc.variables['topo'][:] heights = np.array([np.min(topo[np.where(mask == 1)])]) years_height, temp_height, _ = \ climate.mb_yearly_climate_on_height(gdir, heights, flatten=False) temp_height = temp_height[0] # both time series must be equal np.testing.assert_array_equal(temp, temp_height) # get solid precipitation averaged over the glacier # (not weighted with widths) fls = gdir.read_pickle('inversion_flowlines') heights = np.array([]) for fl in fls: heights = np.append(heights, fl.surface_h) years_height, _, prcp_height = \ climate.mb_yearly_climate_on_height(gdir, heights, flatten=True) # correlation must be higher than set threshold assert corrcoef(prcp, prcp_height) >= 0.99 # TODO: assert absolute values (or differences) of precipitation @ASK # test exception handling of out of bounds time/year range with self.assertRaises(climate.MassBalanceCalibrationError): # start year out of bounds year_range = [1500, 1980] _, _, _ = vascaling.get_yearly_mb_temp_prcp(gdir, year_range=year_range) with self.assertRaises(climate.MassBalanceCalibrationError): # end year oud of bounds year_range = [1980, 3000] _, _, _ = vascaling.get_yearly_mb_temp_prcp(gdir, year_range=year_range) with self.assertRaises(ValueError): # get not N full years t0 = datetime.datetime(1980, 1, 1) t1 = datetime.datetime(1980, 3, 1) time_range = [t0, t1] _, _, _ = vascaling.get_yearly_mb_temp_prcp(gdir, time_range=time_range) # TODO: assert gradient in climate file?! pass