def setUp(self): """Instance the TestCase, create the test directory, OGGM initialisation and setting paths and parameters. Most input files, like the DEM, the climate file and the glacier outline, come from the oggm-sample-data repository and my hence be outdated. The test are performed on Hintereisferner (RGI60-11.00897), running with HISTALP climate data and the matching mass balance calibration parameters. """ # test directory self.testdir = os.path.join(get_test_dir(), 'tmp_vas') if not os.path.exists(self.testdir): os.makedirs(self.testdir) self.clean_dir() # load default parameter file and set working directory vascaling.initialize() cfg.PATHS['working_dir'] = self.testdir # set path to GIS files cfg.PARAMS['use_intersects'] = False cfg.PATHS['dem_file'] = get_demo_file('hef_srtm.tif') # set parameters for climate file and mass balance calibration cfg.PARAMS['baseline_climate'] = 'CUSTOM' cfg.PATHS['climate_file'] = get_demo_file('histalp_merged_hef.nc') cfg.PARAMS['run_mb_calibration'] = True # adjust parameters for HistAlp climate cfg.PARAMS['prcp_scaling_factor'] = 2.5 cfg.PARAMS['temp_melt'] = -0.5 cfg.PARAMS['temp_all_solid'] = 0. # coveralls.io has issues if multiprocessing is enabled cfg.PARAMS['use_multiprocessing'] = False
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')
"""Run prepro tasks and store glacier directories as archive.""" # build-ins import os import logging # external libraries import geopandas as gpd # local/oggm imports from oggm import cfg, utils, workflow import oggm_vas as vascaling if __name__ == '__main__': # Initialize OGGM and set up the default run parameters vascaling.initialize(logging_level='WORKFLOW') rgi_version = '62' cfg.PARAMS['border'] = 80 # CLUSTER paths wdir = os.environ.get('WORKDIR', '') cfg.PATHS['working_dir'] = wdir outdir = os.environ.get('OUTDIR', '') # define the baseline climate CRU cfg.PARAMS['baseline_climate'] = 'CRU' # set the mb hyper parameters accordingly cfg.PARAMS['prcp_scaling_factor'] = 3 cfg.PARAMS['temp_melt'] = 0 cfg.PARAMS['temp_all_solid'] = 4 cfg.PARAMS['prcp_default_gradient'] = 4e-4 cfg.PARAMS['run_mb_calibration'] = False
def mb_calibration(rgi_version, baseline): """Run the mass balance calibration for the VAS model. RGI version and baseline climate must be given. Parameters ---------- rgi_version : str Version (and subversion) of the RGI, e.g., '62' baseline : str 'HISTALP' or 'CRU', name of the baseline climate """ # initialize OGGM and set up the run parameters vascaling.initialize(logging_level='WORKFLOW') # LOCAL paths (where to write the OGGM run output) # dirname = 'VAS_ref_mb_{}_RGIV{}'.format(baseline, rgi_version) # wdir = utils.gettempdir(dirname, home=True, reset=True) # utils.mkdir(wdir, reset=True) # cfg.PATHS['working_dir'] = wdir # CLUSTER paths wdir = os.environ.get('WORKDIR', '') cfg.PATHS['working_dir'] = wdir # we are running the calibration ourselves cfg.PARAMS['run_mb_calibration'] = True # we are using which baseline data? cfg.PARAMS['baseline_climate'] = baseline # no need for intersects since this has an effect on the inversion only cfg.PARAMS['use_intersects'] = False # use multiprocessing? cfg.PARAMS['use_multiprocessing'] = True # set to True for operational runs cfg.PARAMS['continue_on_error'] = True # 10 is only for OGGM-VAS, OGGM needs 80 to run cfg.PARAMS['border'] = 80 if baseline == 'HISTALP': # OGGM HISTALP PARAMETERS from Matthias Dusch # see https://oggm.org/2018/08/10/histalp-parameters/ # cfg.PARAMS['prcp_scaling_factor'] = 1.75 # cfg.PARAMS['temp_melt'] = -1.75 # cfg.PARAMS['temp_all_solid'] = 0 # cfg.PARAMS['prcp_default_gradient'] = 0 # VAS HISTALP PARAMETERS from x-validation cfg.PARAMS['prcp_scaling_factor'] = 2.5 cfg.PARAMS['temp_melt'] = -0.5 cfg.PARAMS['temp_all_solid'] = 0 cfg.PARAMS['prcp_default_gradient'] = 0 elif baseline == 'CRU': # using the parameters from Marzeion et al. (2012) # cfg.PARAMS['prcp_scaling_factor'] = 2.5 # cfg.PARAMS['temp_melt'] = 1 # cfg.PARAMS['temp_all_solid'] = 3 # cfg.PARAMS['prcp_default_gradient'] = 3e-4 # using the parameters from Malles and Marzeion 2020 cfg.PARAMS['prcp_scaling_factor'] = 3 cfg.PARAMS['temp_melt'] = 0 cfg.PARAMS['temp_all_solid'] = 4 cfg.PARAMS['prcp_default_gradient'] = 4e-4 # the next step is to get all the reference glaciers, # i.e. glaciers with mass balance measurements. # get the reference glacier ids (they are different for each RGI version) df, _ = utils.get_wgms_files() rids = df['RGI{}0_ID'.format(rgi_version[0])] # we can't do Antarctica rids = [rid for rid in rids if not ('-19.' in rid)] # For HISTALP only RGI reg 11.01 (ALPS) if baseline == 'HISTALP': rids = [rid for rid in rids if '-11' in rid] # initialize the glacier regions base_url = "https://cluster.klima.uni-bremen.de/~oggm/gdirs/oggm_v1.4/" \ "L3-L5_files/CRU/elev_bands/qc3/pcp2.5/match_geod" # Go - get the pre-processed glacier directories gdirs = workflow.init_glacier_directories(rids, from_prepro_level=3, prepro_base_url=base_url, prepro_rgi_version=rgi_version) # Some glaciers in RGI Region 11 are not inside the HISTALP domain if baseline == 'HISTALP': gdirs = [gdir for gdir in gdirs if gdir.rgi_subregion == '11-01'] # get reference glaciers with mass balance measurements gdirs = utils.get_ref_mb_glaciers(gdirs) # make a new dataframe with those (this takes a while) print('For RGIV{} we have {} candidate reference ' 'glaciers.'.format(rgi_version, len(gdirs))) # run climate tasks vascaling.compute_ref_t_stars(gdirs) # execute_entity_task(vascaling.local_t_star, gdirs) # we store the associated params mb_calib = gdirs[0].read_pickle('climate_info')['mb_calib_params'] with open(os.path.join(wdir, 'mb_calib_params.json'), 'w') as fp: json.dump(mb_calib, fp)
""" # build-ins import os import logging # externals import numpy as np import geopandas as gpd # local/oggm modules from oggm import cfg, utils, workflow import oggm_vas as vascaling if __name__ == '__main__': # Initialize OGGM and set up the default run parameters vascaling.initialize(logging_level='DEBUG') rgi_version = '62' cfg.PARAMS['border'] = 80 # CLUSTER paths wdir = os.environ.get('WORKDIR', '') cfg.PATHS['working_dir'] = wdir outdir = os.environ.get('OUTDIR', '') # define the baseline climate CRU or HISTALP cfg.PARAMS['baseline_climate'] = 'CRU' # set the mb hyper parameters accordingly cfg.PARAMS['prcp_scaling_factor'] = 3 cfg.PARAMS['temp_melt'] = 0 cfg.PARAMS['temp_all_solid'] = 4 cfg.PARAMS['prcp_default_gradient'] = 4e-4
# import the needed OGGM modules from oggm import cfg, utils, workflow from oggm.core import gis, climate, flowline import oggm_vas as vascaling log.info('Starting run') # get all glaciers of RGI region 14 (HIGH MOUNTAIN ASIA) rgi_region = '14' rgi_version = '61' rgidf = gpd.read_file( utils.get_rgi_region_file(region=rgi_region, version=rgi_version)) # load default parameter file vascaling.initialize() # get path to directories on the CLUSTER - comment/uncomment as necessary OUTPUT_DIR = os.environ['OUTDIR'] WORKING_DIR = os.environ['WORKDIR'] # 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 # define the baseline cliamte CRU or HISTALP cfg.PARAMS['baseline_climate'] = 'CRU' # set the mb hyper parameters accordingly
def run_cmip(): # Initialize OGGM and set up the default run parameters vascaling.initialize(logging_level='WORKFLOW') rgi_version = '62' cfg.PARAMS['border'] = 80 # CLUSTER paths wdir = os.environ.get('WORKDIR', '') cfg.PATHS['working_dir'] = wdir outdir = os.environ.get('OUTDIR', '') # define the baseline climate CRU or HISTALP cfg.PARAMS['baseline_climate'] = 'CRU' # set the mb hyper parameters accordingly cfg.PARAMS['prcp_scaling_factor'] = 3 cfg.PARAMS['temp_melt'] = 0 cfg.PARAMS['temp_all_solid'] = 4 cfg.PARAMS['run_mb_calibration'] = False # set minimum ice thickness to include in glacier length computation # this reduces weird spikes in length records cfg.PARAMS['min_ice_thick_for_length'] = 0.1 # 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 # read RGI entry for the glaciers as DataFrame # containing the outline area as shapefile # RGI glaciers rgi_reg = os.environ.get('OGGM_RGI_REG', '') if rgi_reg not in ['{:02d}'.format(r) for r in range(1, 20)]: raise RuntimeError('Need an RGI Region') rgi_ids = gpd.read_file( utils.get_rgi_region_file(rgi_reg, version=rgi_version)) # get and set path to intersect shapefile intersects_db = utils.get_rgi_intersects_region_file(region=rgi_reg) cfg.set_intersects_db(intersects_db) # operational run, all glaciers should run cfg.PARAMS['continue_on_error'] = True # Module logger log = logging.getLogger(__name__) log.workflow('Starting run for RGI reg {}'.format(rgi_reg)) # Go - get the pre-processed glacier directories # base_url = 'https://cluster.klima.uni-bremen.de/~oggm/gdirs/oggm_v1.4/' \ # 'L3-L5_files/RGIV62_fleb_qc3_CRU_pcp2.5' prepro_dir = '/home/users/moberrauch/run_output/vas_prepro/' gdirs = workflow.init_glacier_directories(rgi_ids, from_tar=prepro_dir) # # run vascaling climate tasks # workflow.execute_entity_task(vascaling.local_t_star, gdirs) # # adjust mass balance residual with geodetic observations # vascaling.match_regional_geodetic_mb(gdirs=gdirs, rgi_reg=rgi_reg) # # prepare historic "spinup" # workflow.execute_entity_task(vascaling.run_from_climate_data, gdirs, # ys=2003, ye=2020, # output_filesuffix='_historical') # read gcm list gcms = pd.read_csv('/home/www/oggm/cmip6/all_gcm_list.csv', index_col=0) # iterate over all specified gcms for gcm in sys.argv[1:]: # iterate over all SSPs (Shared Socioeconomic Pathways) df1 = gcms.loc[gcms.gcm == gcm] for ssp in df1.ssp.unique(): df2 = df1.loc[df1.ssp == ssp] assert len(df2) == 2 # get temperature projections ft = df2.loc[df2['var'] == 'tas'].iloc[0] # get precipitation projections fp = df2.loc[df2['var'] == 'pr'].iloc[0].path rid = ft.fname.replace('_r1i1p1f1_tas.nc', '') ft = ft.path log.workflow('Starting run for {}'.format(rid)) workflow.execute_entity_task( gcm_climate.process_cmip_data, gdirs, filesuffix='_' + rid, # recognize the climate file for later fpath_temp=ft, # temperature projections fpath_precip=fp, # precip projections year_range=('1981', '2020')) workflow.execute_entity_task(vascaling.run_from_climate_data, gdirs, climate_filename='gcm_data', climate_input_filesuffix='_' + rid, init_model_filesuffix='_historical', output_filesuffix=rid, return_value=False) gcm_dir = os.path.join(outdir, 'RGI' + rgi_reg, gcm) utils.mkdir(gcm_dir) utils.compile_run_output(gdirs, input_filesuffix=rid, path=os.path.join(gcm_dir, rid + '.nc')) log.workflow('OGGM Done')
def mb_calibration(rgi_version, baseline): """ Run the mass balance calibration for the VAS model. RGI version and baseline cliamte must be given. :param rgi_version: int, RGI version :param baseline: str, baseline climate 'HISTALP' or 'CRU' """ # initialize OGGM and set up the run parameters vascaling.initialize(logging_level='WORKFLOW') # LOCAL paths (where to write the OGGM run output) # dirname = 'VAS_ref_mb_{}_RGIV{}'.format(baseline, rgi_version) # wdir = utils.gettempdir(dirname, home=True, reset=True) # utils.mkdir(wdir, reset=True) # cfg.PATHS['working_dir'] = wdir # CLUSTER paths wdir = os.environ.get('WORKDIR', '') cfg.PATHS['working_dir'] = wdir # we are running the calibration ourselves cfg.PARAMS['run_mb_calibration'] = True # we are using which baseline data? cfg.PARAMS['baseline_climate'] = baseline # no need for intersects since this has an effect on the inversion only cfg.PARAMS['use_intersects'] = False # use multiprocessing? cfg.PARAMS['use_multiprocessing'] = True # set to True for operational runs cfg.PARAMS['continue_on_error'] = True # 10 is only for OGGM-VAS, OGGM needs 80 to run cfg.PARAMS['border'] = 80 if baseline == 'HISTALP': # other params: see https://oggm.org/2018/08/10/histalp-parameters/ # cfg.PARAMS['prcp_scaling_factor'] = 1.75 # cfg.PARAMS['temp_melt'] = -1.75 cfg.PARAMS['prcp_scaling_factor'] = 2.5 cfg.PARAMS['temp_melt'] = -0.5 elif baseline == 'CRU': # using the parameters from Marzeion et al. (2012) # cfg.PARAMS['prcp_scaling_factor'] = 2.5 # cfg.PARAMS['temp_melt'] = 1 # cfg.PARAMS['temp_all_solid'] = 3 # using the parameters from Malles and Marzeion 2020 cfg.PARAMS['prcp_scaling_factor'] = 3 cfg.PARAMS['temp_melt'] = 0 cfg.PARAMS['temp_all_solid'] = 4 # cfg.PARAMS['prcp_gradient'] = 4 # the next step is to get all the reference glaciers, # i.e. glaciers with mass balance measurements. # get the reference glacier ids (they are different for each RGI version) df, _ = utils.get_wgms_files() rids = df['RGI{}0_ID'.format(rgi_version[0])] # we can't do Antarctica rids = [rid for rid in rids if not ('-19.' in rid)] # For HISTALP only RGI reg 11.01 (ALPS) if baseline == 'HISTALP': rids = [rid for rid in rids if '-11' in rid] # make a new dataframe with those (this takes a while) print('Reading the RGI shapefiles...') rgidf = utils.get_rgi_glacier_entities(rids, version=rgi_version) print('For RGIV{} we have {} candidate reference ' 'glaciers.'.format(rgi_version, len(rgidf))) # initialize the glacier regions base_url = 'https://cluster.klima.uni-bremen.de/~oggm/gdirs/oggm_v1.4/' \ 'L3-L5_files/RGIV62_fleb_qc3_CRU_pcp2.5' # Go - get the pre-processed glacier directories gdirs = workflow.init_glacier_directories(rids, from_prepro_level=3, prepro_base_url=base_url, prepro_rgi_version=rgi_version) # Some glaciers in RGI Region 11 are not inside the HISTALP domain if baseline == 'HISTALP': gdirs = [gdir for gdir in gdirs if gdir.rgi_subregion == '11-01'] # get reference glaciers with mass balance measurements gdirs = utils.get_ref_mb_glaciers(gdirs) # keep only these glaciers rgidf = rgidf.loc[rgidf.RGIId.isin([g.rgi_id for g in gdirs])] # save to file rgidf.to_file(os.path.join(wdir, 'mb_ref_glaciers.shp')) print('For RGIV{} and {} we have {} reference glaciers'.format( rgi_version, baseline, len(rgidf))) # sort for more efficient parallel computing rgidf = rgidf.sort_values('Area', ascending=False) # newly initialize glacier directories gdirs = workflow.init_glacier_directories(rgidf, reset=False, force=True) workflow.execute_entity_task(gis.define_glacier_region, gdirs) workflow.execute_entity_task(gis.glacier_masks, gdirs) # run climate tasks vascaling.compute_ref_t_stars(gdirs) execute_entity_task(vascaling.local_t_star, gdirs) # we store the associated params mb_calib = gdirs[0].read_pickle('climate_info')['mb_calib_params'] with open(os.path.join(wdir, 'mb_calib_params.json'), 'w') as fp: json.dump(mb_calib, fp)
def run_cmip(): """ """ # Initialize OGGM and set up the default run parameters vascaling.initialize(logging_level='DEBUG') rgi_version = '62' cfg.PARAMS['border'] = 80 # CLUSTER paths wdir = os.environ.get('WORKDIR', '') utils.mkdir(wdir) cfg.PATHS['working_dir'] = wdir outdir = os.environ.get('OUTDIR', '') utils.mkdir(outdir) # define the baseline climate CRU or HISTALP cfg.PARAMS['baseline_climate'] = 'CRU' # set the mb hyper parameters accordingly cfg.PARAMS['prcp_scaling_factor'] = 3 cfg.PARAMS['temp_melt'] = 0 cfg.PARAMS['temp_all_solid'] = 4 cfg.PARAMS['prcp_default_gradient'] = 4e-4 cfg.PARAMS['run_mb_calibration'] = False # set minimum ice thickness to include in glacier length computation # this reduces weird spikes in length records cfg.PARAMS['min_ice_thick_for_length'] = 0.1 # 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 # read RGI entry for the glaciers as DataFrame # containing the outline area as shapefile # RGI glaciers rgi_reg = os.environ.get('RGI_REG', '') if rgi_reg not in ['{:02d}'.format(r) for r in range(1, 20)]: raise RuntimeError('Need an RGI Region') rgi_ids = gpd.read_file( utils.get_rgi_region_file(rgi_reg, version=rgi_version)) # For greenland we omit connectivity level 2 if rgi_reg == '05': rgi_ids = rgi_ids.loc[rgi_ids['Connect'] != 2] # get and set path to intersect shapefile intersects_db = utils.get_rgi_intersects_region_file(region=rgi_reg) cfg.set_intersects_db(intersects_db) # operational run, all glaciers should run cfg.PARAMS['continue_on_error'] = True # Module logger log = logging.getLogger(__name__) log.workflow('Starting run for RGI reg {}'.format(rgi_reg)) # Go - get the pre-processed glacier directories base_url = 'https://cluster.klima.uni-bremen.de/' \ '~moberrauch/prepro_vas_paper/' gdirs = workflow.init_glacier_directories(rgi_ids, from_prepro_level=3, prepro_base_url=base_url, prepro_rgi_version=rgi_version) # read gcm list gcms = pd.read_csv('/home/www/oggm/cmip6/all_gcm_list.csv', index_col=0) # iterate over all specified GCMs for gcm in sys.argv[1:]: # iterate over all SSPs (Shared Socioeconomic Pathways) df1 = gcms.loc[gcms.gcm == gcm] for ssp in df1.ssp.unique(): df2 = df1.loc[df1.ssp == ssp] assert len(df2) == 2 # get temperature projections ft = df2.loc[df2['var'] == 'tas'].iloc[0] # get precipitation projections fp = df2.loc[df2['var'] == 'pr'].iloc[0].path rid = ft.fname.replace('_r1i1p1f1_tas.nc', '') ft = ft.path log.workflow('Starting run for {}'.format(rid)) workflow.execute_entity_task(gcm_climate.process_cmip_data, gdirs, # recognize the climate file for later filesuffix='_' + rid, # temperature projections fpath_temp=ft, # precip projections fpath_precip=fp, year_range=('1981', '2020')) workflow.execute_entity_task(vascaling.run_from_climate_data, gdirs, # use gcm_data, not climate_historical climate_filename='gcm_data', # use a different scenario climate_input_filesuffix='_' + rid, # this is important! Start from 2019 init_model_filesuffix='_historical', # recognize the run for later output_filesuffix=rid, return_value=False) gcm_dir = os.path.join(outdir, 'RGI' + rgi_reg, gcm) utils.mkdir(gcm_dir) utils.compile_run_output(gdirs, input_filesuffix=rid, path=os.path.join(gcm_dir, rid + '.nc')) log.workflow('OGGM Done')
def compute_scaling_params(rgi_ids, path=None): """ The routine computes scaling parameters by fitting a linear regression to the volume/area and volume/length scatter in log-log space, using the inversion volume, the RGI area and the longest centerline as "observations" Thereby, the following two cases apply: - compute only scaling constants, since scaling exponents have a physical basis and should not be changed - compute only scaling constants and scaling exponents Returns parameters in a 2-level dictionary. The upper level differentiates between the two cases, the lower level indicates the parameters. Parameters ---------- rgi_ids: array-like List of RGI IDs for which the equilibrium experiments are performed. Returns ------- Dictionary containing the computed parameters. """ log.info('Starting scaling parameter computation') # compute RGI region and version from RGI IDs # assuming all they are all the same rgi_region = (rgi_ids[0].split('-')[-1]).split('.')[0] rgi_version = (rgi_ids[0].split('-')[0])[-2:-1] # load default parameter file vascaling.initialize() # get environmental variables for working and output directories WORKING_DIR = os.environ["WORKDIR"] OUTPUT_DIR = os.environ["OUTDIR"] # create working directory utils.mkdir(WORKING_DIR) 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'] = 120 # 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 # set minimum ice thickness to include in glacier length computation # this reduces weird spikes in length records cfg.PARAMS['min_ice_thick_for_length'] = 0.1 # read RGI entry for the glaciers as DataFrame # containing the outline area as shapefile rgidf = utils.get_rgi_glacier_entities(rgi_ids) # get and set path to intersect shapefile intersects_db = utils.get_rgi_intersects_region_file(region=rgi_region) cfg.set_intersects_db(intersects_db) # 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 # sort by area for more efficient parallel computing rgidf = rgidf.sort_values('Area', ascending=False) cfg.PARAMS['use_multiprocessing'] = True # operational run, all glaciers should run cfg.PARAMS['continue_on_error'] = True # initialize the GlacierDirectory gdirs = workflow.init_glacier_directories(rgidf, reset=False, force=True) # run gis tasks workflow.gis_prepro_tasks(gdirs) # run climate tasks workflow.execute_entity_task(climate.process_climate_data, gdirs) # compute local t* and the corresponding mu* workflow.execute_entity_task(climate.local_t_star, gdirs) workflow.execute_entity_task(climate.mu_star_calibration, gdirs) # run inversion tasks workflow.inversion_tasks(gdirs) # finalize preprocessing workflow.execute_entity_task(flowline.init_present_time_glacier, gdirs) # create empty dictionary params = dict() # compute scaling constants for given (fixed) slope params['const_only'] = vascaling.get_scaling_constant(gdirs) # compute scaling constants and scaling exponent via linear regression params['const_expo'] = vascaling.get_scaling_constant_exponent(gdirs) # store to file if path: if not isinstance(path, str): # set default path and filename path = os.path.join(OUTPUT_DIR, 'scaling_params.json') json.dump(params, open(path, 'w')) return params
def sensitivity_run_vas(rgi_ids, use_random_mb=False, use_mean=False, path=True, temp_bias=0, tstar=None, use_default_tstar=True, use_bias_for_run=True, scaling_params=[(4.5507, 0.191, 2.2, 1.375)], time_scale_factors=[1], suffixes=['_default'], **kwargs): """ The routine runs all steps for the equilibrium experiments using the volume/area scaling model (cf. `equilibrium_run_vas`) but for only one given temperature bias. However, it is possible to supply a list of sensitivity parameters (the scaling constants, and time scale factor) to alter the model behavior. - OGGM preprocessing, including initialization, GIS tasks, climate tasks and massbalance tasks. - Run model for all glaciers with constant (or random) massbalance model over 3000 years (default value). - Process the model output dataset(s), i.e. normalization, average/sum, ... The final dataset containing all results is returned. Given a path is is also stored to file. Parameters ---------- rgi_ids: array-like List of RGI IDs for which the equilibrium experiments are performed. use_random_mb: bool, optional, default=True Choose between random massbalance model and constant massbalance model. use_mean: bool, optional, default=False Choose between the mean or summation over all glaciers path: bool or str, optional, default=True If a path is given (or True), the resulting dataset is stored to file. temp_bias: float, optional, default=0 Temperature bias (degC) for the mass balance model. sensitivity_params: multi-dimensional array-like, optional, default=[(4.5507, 0.191, 2.2, 1.375)] List containing the scaling constants and scaling exponents for length and area scaling as tuples, e.g., (c_l, c_a, q, gamma) suffixes: array-like, optional, default=['_default'] Descriptive suffixes corresponding to the given sensitivity params tstar: float, optional, default=None 'Equilibrium year' used for the mass balance calibration. use_default_tstar: bool, optional, default=True Flag deciding whether or not to compute mustar from given from reference table. Overridden by a given tstar. use_bias_for_run: bool, optional, default=True Flag deciding whether or not to use the mass balance residual. kwargs: Additional key word arguments for the `run_random_climate` or `run_constant_climate` routines of the vascaling module. Returns ------- Dataset containing yearly values of all glacier geometries. """ # assert correct output file suffixes for temp biases if len(scaling_params) * len(time_scale_factors) != len(suffixes): raise RuntimeError("Each given combination of scaling parameters and " "time scale factor must have its corresponding" "suffix.") # OGGM preprocessing # ------------------ # compute RGI region and version from RGI IDs # assuming all they are all the same rgi_region = (rgi_ids[0].split('-')[-1]).split('.')[0] rgi_version = (rgi_ids[0].split('-')[0])[-2:-1] # load default parameter file vascaling.initialize() # get environmental variables for working and output directories WORKING_DIR = os.environ["WORKDIR"] OUTPUT_DIR = os.environ["OUTDIR"] # create working directory utils.mkdir(WORKING_DIR) 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'] = 120 # we use HistAlp climate data cfg.PARAMS['baseline_climate'] = 'HISTALP' # set the mb hyper parameters accordingly cfg.PARAMS['prcp_scaling_factor'] = 2.5 cfg.PARAMS['temp_melt'] = -0.5 # 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'] = use_bias_for_run # set minimum ice thickness to include in glacier length computation # this reduces weird spikes in length records cfg.PARAMS['min_ice_thick_for_length'] = 0.1 # read RGI entry for the glaciers as DataFrame # containing the outline area as shapefile rgidf = utils.get_rgi_glacier_entities(rgi_ids) # get and set path to intersect shapefile intersects_db = utils.get_rgi_intersects_region_file(region=rgi_region) cfg.set_intersects_db(intersects_db) # sort by area for more efficient parallel computing rgidf = rgidf.sort_values('Area', ascending=False) cfg.PARAMS['use_multiprocessing'] = True # operational run, all glaciers should run cfg.PARAMS['continue_on_error'] = True # initialize the GlacierDirectory gdirs = workflow.init_glacier_directories(rgidf, reset=False, force=True) # define the local grid and glacier mask workflow.execute_entity_task(gis.define_glacier_region, gdirs) workflow.execute_entity_task(gis.glacier_masks, gdirs) # process the given climate file workflow.execute_entity_task(climate.process_climate_data, gdirs) # compute local t* and the corresponding mu* if tstar or use_default_tstar: # compute mustar from given tstar or reference table workflow.execute_entity_task(vascaling.local_t_star, gdirs, tstar=tstar, bias=0) else: # compute mustar from the reference table for the flowline model # RGI v6 and HISTALP baseline climate ref_df = pd.read_csv( utils.get_demo_file('oggm_ref_tstars_rgi6_histalp.csv')) workflow.execute_entity_task(vascaling.local_t_star, gdirs, ref_df=ref_df) # Run model with constant/random mass balance model # ------------------------------------------------- # use t* as center year, even if specified differently kwargs['y0'] = tstar # run for 3000 years if not specified otherwise kwargs.setdefault('nyears', 1000) # limit parameters to 3 decimal points scaling_params = recursive_round(scaling_params, 3) time_scale_factors = recursive_round(time_scale_factors, 3) # assure that scaling params are handled as tuples (pairs) scaling_params_list = np.zeros(len(scaling_params), dtype=object) scaling_params_list[:] = scaling_params # combine scaling constants, scaling exponents and time scale factor # into one iterable array sensitivity_params = np.array( np.meshgrid(scaling_params_list, time_scale_factors)).T sensitivity_params = (sensitivity_params.reshape( -1, sensitivity_params.shape[-1])) if use_random_mb: # set random seed to get reproducible results kwargs.setdefault('seed', 12) # run RandomMassBalance model centered around t* for each given # parameter set for suffix, params in zip(suffixes, sensitivity_params): cfg.PARAMS['vas_c_length_m'] = params[0][0] cfg.PARAMS['vas_c_area_m2'] = params[0][1] cfg.PARAMS['vas_q_length'] = params[0][2] cfg.PARAMS['vas_gamma_area'] = params[0][3] kwargs['time_scale_factor'] = params[1] workflow.execute_entity_task(vascaling.run_random_climate, gdirs, temperature_bias=temp_bias, output_filesuffix=suffix, **kwargs) else: # run ConstantMassBalance model centered around t* for each given # parameter set for suffix, params in zip(suffixes, sensitivity_params): cfg.PARAMS['vas_c_length_m'] = params[0][0] cfg.PARAMS['vas_c_area_m2'] = params[0][1] cfg.PARAMS['vas_q_length'] = params[0][2] cfg.PARAMS['vas_gamma_area'] = params[0][3] kwargs['time_scale_factor'] = params[1] workflow.execute_entity_task(vascaling.run_constant_climate, gdirs, temperature_bias=temp_bias, output_filesuffix=suffix, **kwargs) # Process output dataset(s) # ------------------------- # create empty container ds = list() # iterate over all scaling constants for i, params in enumerate(scaling_params): # create empty container ds_ = list() # iterate over all time scale factor for j, factor in enumerate(time_scale_factors): # compile the output for each run pos = j + len(time_scale_factors) * i ds__ = utils.compile_run_output(np.atleast_1d(gdirs), filesuffix=suffixes[pos], path=False) # add time scale factor as coordinate ds__.coords['time_scale_factor'] = factor # add to container ds_.append(ds__) # concatenate using time scale factor as concat dimension ds_ = xr.concat(ds_, dim='time_scale_factor') # add scaling constants as coordinate params_list = np.zeros(len([params]), dtype=object) params_list[:] = [params] ds_ = ds_.expand_dims(dim={'scaling_params': params_list}) # add to container ds.append(ds_) # concatenate using scaling constants as concat dimension ds = xr.concat(ds, dim='scaling_params') # add model type as coordinate ds.coords['model'] = 'vas' # add mb model type as coordinate ds.coords['mb_model'] = 'random' if use_random_mb else 'constant' # normalize glacier geometries (length/area/volume) with start value if use_mean: # compute average over all glaciers ds_normal = normalize_ds_with_start(ds).mean(dim='rgi_id') ds = ds.mean(dim='rgi_id') else: # compute sum over all glaciers ds_normal = normalize_ds_with_start(ds.sum(dim='rgi_id')) ds = ds.sum(dim='rgi_id') # add coordinate to distinguish between normalized and absolute values ds.coords['normalized'] = False ds_normal.coords['normalized'] = True # combine datasets ds = xr.concat([ds, ds_normal], 'normalized') # store datasets if path: if not isinstance(path, str): # set default path and filename mb = 'random' if use_random_mb else 'constant' path = os.path.join(OUTPUT_DIR, f'run_output_{mb}_vas.nc') # write to file log.info(f'Writing run output to {path}') pickle.dump(ds, open(path, mode='wb')) # return ds, ds_normal return ds
def mb_calibration(rgi_version, baseline): """ Run the mass balance calibration for the VAS model. RGI version and baseline cliamte must be given. :param rgi_version: int, RGI version :param baseline: str, baseline climate 'HISTALP' or 'CRU' """ # initialize OGGM and set up the run parameters vascaling.initialize(logging_level='WORKFLOW') # local paths (where to write the OGGM run output) # dirname = 'VAS_ref_mb_{}_RGIV{}'.format(baseline, rgi_version) # wdir = utils.gettempdir(dirname, home=True, reset=True) # utils.mkdir(wdir, reset=True) wdir = os.environ['WORKDIR'] cfg.PATHS['working_dir'] = wdir # we are running the calibration ourselves cfg.PARAMS['run_mb_calibration'] = True # we are using which baseline data? cfg.PARAMS['baseline_climate'] = baseline # no need for intersects since this has an effect on the inversion only cfg.PARAMS['use_intersects'] = False # use multiprocessing? cfg.PARAMS['use_multiprocessing'] = True # set to True for operational runs cfg.PARAMS['continue_on_error'] = True if baseline == 'HISTALP': # other params: see https://oggm.org/2018/08/10/histalp-parameters/ # cfg.PARAMS['prcp_scaling_factor'] = 1.75 # cfg.PARAMS['temp_melt'] = -1.75 cfg.PARAMS['prcp_scaling_factor'] = 2.5 cfg.PARAMS['temp_melt'] = -0.5 elif baseline == 'CRU': # using the parameters from Marzeion et al. (2012) cfg.PARAMS['prcp_scaling_factor'] = 2.5 cfg.PARAMS['temp_melt'] = 1 cfg.PARAMS['temp_all_solid'] = 3 # the next step is to get all the reference glaciers, # i.e. glaciers with mass balance measurements. # get the reference glacier ids (they are different for each RGI version) rgi_dir = utils.get_rgi_dir(version=rgi_version) df, _ = utils.get_wgms_files() rids = df['RGI{}0_ID'.format(rgi_version[0])] # we can't do Antarctica rids = [rid for rid in rids if not ('-19.' in rid)] # For HISTALP only RGI reg 11.01 (ALPS) if baseline == 'HISTALP' or True: rids = [rid for rid in rids if '-11' in rid] debug = False if debug: print("==================================\n" + "DEBUG MODE: only RGI60-11.00897\n" + "==================================") rids = [rid for rid in rids if '-11.00897' in rid] cfg.PARAMS['use_multiprocessing'] = False # make a new dataframe with those (this takes a while) print('Reading the RGI shapefiles...') rgidf = utils.get_rgi_glacier_entities(rids, version=rgi_version) print('For RGIV{} we have {} candidate reference ' 'glaciers.'.format(rgi_version, len(rgidf))) # initialize the glacier regions gdirs = workflow.init_glacier_directories(rgidf, reset=False, force=True) workflow.execute_entity_task(gis.define_glacier_region, gdirs) workflow.execute_entity_task(gis.glacier_masks, gdirs) # we need to know which period we have data for print('Process the climate data...') if baseline == 'CRU': execute_entity_task(tasks.process_cru_data, gdirs, print_log=False) elif baseline == 'HISTALP': # Some glaciers are not in Alps gdirs = [gdir for gdir in gdirs if gdir.rgi_subregion == '11-01'] # cfg.PARAMS['continue_on_error'] = True execute_entity_task(tasks.process_histalp_data, gdirs, print_log=False, y0=1850) # cfg.PARAMS['continue_on_error'] = False else: execute_entity_task(tasks.process_custom_climate_data, gdirs, print_log=False) # get reference glaciers with mass balance measurements gdirs = utils.get_ref_mb_glaciers(gdirs) # keep only these glaciers rgidf = rgidf.loc[rgidf.RGIId.isin([g.rgi_id for g in gdirs])] # save to file rgidf.to_file(os.path.join(wdir, 'mb_ref_glaciers.shp')) print('For RGIV{} and {} we have {} reference glaciers'.format(rgi_version, baseline, len(rgidf))) # sort for more efficient parallel computing rgidf = rgidf.sort_values('Area', ascending=False) # newly initialize glacier directories gdirs = workflow.init_glacier_directories(rgidf, reset=False, force=True) workflow.execute_entity_task(gis.define_glacier_region, gdirs) workflow.execute_entity_task(gis.glacier_masks, gdirs) # run climate tasks vascaling.compute_ref_t_stars(gdirs) execute_entity_task(vascaling.local_t_star, gdirs) # we store the associated params mb_calib = gdirs[0].read_pickle('climate_info')['mb_calib_params'] with open(os.path.join(wdir, 'mb_calib_params.json'), 'w') as fp: json.dump(mb_calib, fp)