def is_rotated_proj_working(): import pyproj srs = ('+ellps=WGS84 +proj=ob_tran +o_proj=latlon ' '+to_meter=0.0174532925199433 +o_lon_p=0.0 +o_lat_p=80.5 ' '+lon_0=357.5 +no_defs') p1 = pyproj.Proj(srs) p2 = wgs84 return np.isclose(transform_proj(p1, p2, -20, -9), [-22.243473889042903, -0.06328365194179102], atol=1e-5).all()
def proj(lon, lat): return salem.transform_proj(salem.wgs84, gdir.grid.proj, lon, lat)
def define_nonrgi_glacier_region(gdir: NonRGIGlacierDirectory): """ Very first task: define the glacier's local grid. Defines the local projection (Transverse Mercator), centered on the glacier. The resolution of the local grid is dx. After defining the grid, the topography is transformed into the local projection. The default interpolation for the topography is `cubic`. Parameters ---------- gdir : :py:class:`oggm.NonRGIGlacierDirectory` where to write the data dx : float grid spacing """ xx, yy = gdir.extent_ll dx = gdir.case.dx # Make a local glacier map proj_params = dict(name='tmerc', lat_0=0., lon_0=gdir.cenlon, k=0.9996, x_0=0, y_0=0, datum='WGS84') proj4_str = "+proj={name} +lat_0={lat_0} +lon_0={lon_0} +k={k} " \ "+x_0={x_0} +y_0={y_0} +datum={datum}".format(**proj_params) # proj_in = pyproj.Proj("+init=EPSG:4326", preserve_units=True) proj_out = pyproj.Proj(proj4_str, preserve_units=True) merc_xx, merc_yy = salem.transform_proj(salem.wgs84, proj_out, xx, yy) # Corners, incl. a buffer of N pix ulx = np.min(merc_xx) lrx = np.max(merc_xx) uly = np.max(merc_yy) lry = np.min(merc_yy) # n pixels nx = np.int((lrx - ulx) / dx) ny = np.int((uly - lry) / dx) # Back to lon, lat for DEM download/preparation tmp_grid = salem.Grid(proj=proj_out, nxny=(nx, ny), x0y0=(ulx, uly), dxdy=(dx, -dx), pixel_ref='corner') minlon, maxlon, minlat, maxlat = tmp_grid.extent_in_crs(crs=salem.wgs84) dem_list, dem_source = get_topo_file((minlon, maxlon), (minlat, maxlat), rgi_region=None, rgi_subregion=None, source='DEM3') log.debug('(%s) DEM source: %s', gdir.name, dem_source) # A glacier area can cover more than one tile: if len(dem_list) == 1: dem_dss = [rasterio.open(dem_list[0])] # if one tile, just open it dem_data = rasterio.band(dem_dss[0], 1) if LooseVersion(rasterio.__version__) >= LooseVersion('1.0'): src_transform = dem_dss[0].transform else: src_transform = dem_dss[0].affine else: dem_dss = [rasterio.open(s) for s in dem_list] # list of rasters dem_data, src_transform = merge_tool(dem_dss) # merged rasters # Use Grid properties to create a transform (see rasterio cookbook) dst_transform = rasterio.transform.from_origin( ulx, uly, dx, dx # sign change (2nd dx) is done by rasterio.transform ) # Set up profile for writing output profile = dem_dss[0].profile profile.update({ 'crs': proj4_str, 'transform': dst_transform, 'width': nx, 'height': ny }) # Could be extended so that the cfg file takes all Resampling.* methods if cfg.PARAMS['topo_interp'] == 'bilinear': resampling = Resampling.bilinear elif cfg.PARAMS['topo_interp'] == 'cubic': resampling = Resampling.cubic else: raise ValueError('{} interpolation not understood'.format( cfg.PARAMS['topo_interp'])) dem_reproj = gdir.get_filepath('dem') with rasterio.open(dem_reproj, 'w', **profile) as dest: dst_array = np.empty((ny, nx), dtype=dem_dss[0].dtypes[0]) reproject( # Source parameters source=dem_data, src_crs=dem_dss[0].crs, src_transform=src_transform, # Destination parameters destination=dst_array, dst_transform=dst_transform, dst_crs=proj4_str, # Configuration resampling=resampling) # TODO: ugly if gdir.case.name == 'Borden Peninsula': print('Anti icepatch used') dst_array[32, 27] = gdir.case.ela_h - 5 dst_array[:2, -4:] = gdir.case.ela_h - 5 if gdir.case.name == 'Borden Peninsula HR': print('Anti icepatch HR used') dst_array[-21:-16, 32:38] = gdir.case.ela_h - 5 dst_array[-8:-2, 88:98] = gdir.case.ela_h - 5 dst_array[:-109, 120:] = gdir.case.ela_h - 5 dest.write(dst_array, 1) for dem_ds in dem_dss: dem_ds.close() # Glacier grid x0y0 = (ulx + dx / 2, uly - dx / 2) # To pixel center coordinates glacier_grid = salem.Grid(proj=proj_out, nxny=(nx, ny), dxdy=(dx, -dx), x0y0=x0y0) glacier_grid.to_json(gdir.get_filepath('glacier_grid')) # Write DEM source info source_txt = DEM_SOURCE_INFO.get(dem_source, dem_source) with open(gdir.get_filepath('dem_source'), 'w') as fw: fw.write(source_txt)
def _reproject_and_scale(gdir, do_error=False): """Reproject and scale itslive data, avoid code duplication for error""" reg = find_region(gdir) if reg is None: raise InvalidWorkflowError('There does not seem to be its_live data ' 'available for this glacier') vnx = 'vx' vny = 'vy' if do_error: vnx += '_err' vny += '_err' with utils.get_lock(): fx = utils.file_downloader(region_files[reg][vnx]) fy = utils.file_downloader(region_files[reg][vny]) # Open the files dsx = salem.GeoTiff(fx) dsy = salem.GeoTiff(fy) # subset them to our map grid_gla = gdir.grid.center_grid proj_vel = dsx.grid.proj x0, x1, y0, y1 = grid_gla.extent_in_crs(proj_vel) dsx.set_subset(corners=((x0, y0), (x1, y1)), crs=proj_vel, margin=4) dsy.set_subset(corners=((x0, y0), (x1, y1)), crs=proj_vel, margin=4) grid_vel = dsx.grid.center_grid # TODO: this should be taken care of by salem # https://github.com/fmaussion/salem/issues/171 with rasterio.Env(): with rasterio.open(fx) as src: nodata = getattr(src, 'nodata', -32767.0) # Error files are wrong if nodata == 0: nodata = -32767.0 # Get the coords at t0 xx0, yy0 = grid_vel.center_grid.xy_coordinates # Compute coords at t1 xx1 = dsx.get_vardata() yy1 = dsy.get_vardata() non_valid = (xx1 == nodata) | (yy1 == nodata) xx1[non_valid] = np.NaN yy1[non_valid] = np.NaN orig_vel = np.sqrt(xx1**2 + yy1**2) xx1 += xx0 yy1 += yy0 # Transform both to glacier proj xx0, yy0 = salem.transform_proj(proj_vel, grid_gla.proj, xx0, yy0) xx1, yy1 = salem.transform_proj(proj_vel, grid_gla.proj, xx1, yy1) # Correct no data after proj as well (inf) xx1[non_valid] = np.NaN yy1[non_valid] = np.NaN # Compute velocities from there vx = xx1 - xx0 vy = yy1 - yy0 # Scale back velocities - https://github.com/OGGM/oggm/issues/1014 new_vel = np.sqrt(vx**2 + vy**2) p_ok = new_vel > 1e-5 # avoid div by zero vx[p_ok] = vx[p_ok] * orig_vel[p_ok] / new_vel[p_ok] vy[p_ok] = vy[p_ok] * orig_vel[p_ok] / new_vel[p_ok] # And transform to local map vx = grid_gla.map_gridded_data(vx, grid=grid_vel, interp='linear') vy = grid_gla.map_gridded_data(vy, grid=grid_vel, interp='linear') # Write with utils.ncDataset(gdir.get_filepath('gridded_data'), 'a') as nc: vn = 'obs_icevel_x' if do_error: vn = vn.replace('obs', 'err') if vn in nc.variables: v = nc.variables[vn] else: v = nc.createVariable(vn, 'f4', ('y', 'x', ), zlib=True) v.units = 'm yr-1' ln = 'ITS LIVE velocity data in x map direction' if do_error: ln = 'Uncertainty of ' + ln v.long_name = ln v[:] = vx.filled(np.nan) vn = 'obs_icevel_y' if do_error: vn = vn.replace('obs', 'err') if vn in nc.variables: v = nc.variables[vn] else: v = nc.createVariable(vn, 'f4', ('y', 'x', ), zlib=True) v.units = 'm yr-1' ln = 'ITS LIVE velocity data in y map direction' if do_error: ln = 'Uncertainty of ' + ln v.long_name = ln v[:] = vy.filled(np.nan)
def proj(lon, lat): return salem.transform_proj(salem.wgs84, gdir.grid.proj, lon, lat)
def its_live_to_gdir(gdir, dsx, dsy, dex, dey, fx): """ Re-project its_live files to a given glacier directory. based on the function from oggm_shop: https://github.com/OGGM/oggm/blob/master/oggm/shop/its_live.py#L79 Variables are added to the gridded_data nc file. Re-projecting velocities from one map proj to another is done re-projecting the vector distances. In this process, absolute velocities might change as well because map projections do not always preserve distances -> we scale them back to the original velocities as per the ITS_LIVE documentation. Which states that velocities are given in ground units, i.e. absolute velocities. We use bi-linear interpolation to re-project the velocities to the local glacier map. Parameters ---------- gdir : :py:class:`oggm.GlacierDirectory` where to write the data dsx: :salem.Geotiff: velocity in the x direction for Greenland dsy: :salem.Geotiff: velocity in the y direction for Greenland dex: :salem.Geotiff: velocity error in the x direction Greenland dey: :salem.Geotiff: velocity error in the y direction Greenland fx: path directory to original velocity data (x direction) """ # subset its live data to our glacier map grid_gla = gdir.grid.center_grid proj_vel = dsx.grid.proj x0, x1, y0, y1 = grid_gla.extent_in_crs(proj_vel) # Same projection for all the itslive data dsx.set_subset(corners=((x0, y0), (x1, y1)), crs=proj_vel, margin=4) dsy.set_subset(corners=((x0, y0), (x1, y1)), crs=proj_vel, margin=4) dex.set_subset(corners=((x0, y0), (x1, y1)), crs=proj_vel, margin=4) dey.set_subset(corners=((x0, y0), (x1, y1)), crs=proj_vel, margin=4) grid_vel = dsx.grid.center_grid # TODO: this should be taken care of by salem # https://github.com/fmaussion/salem/issues/171 with rasterio.Env(): with rasterio.open(fx) as src: nodata = getattr(src, 'nodata', -32767.0) # Get the coords at t0 xx0, yy0 = grid_vel.center_grid.xy_coordinates # Compute coords at t1 xx1 = dsx.get_vardata() yy1 = dsy.get_vardata() ex1 = dex.get_vardata() ey1 = dey.get_vardata() non_valid = (xx1 == nodata) | (yy1 == nodata) non_valid_e = (ex1 == nodata) | (ey1 == nodata) xx1[non_valid] = np.NaN yy1[non_valid] = np.NaN ex1[non_valid_e] = np.NaN ey1[non_valid_e] = np.NaN orig_vel = np.sqrt(xx1**2 + yy1**2) orig_vel_e = np.sqrt(ex1**2 + ey1**2) xx1 += xx0 yy1 += yy0 ex1 += xx0 ey1 += yy0 # Transform both to glacier proj xx0, yy0 = salem.transform_proj(proj_vel, grid_gla.proj, xx0, yy0) xx1, yy1 = salem.transform_proj(proj_vel, grid_gla.proj, xx1, yy1) ex0, ey0 = salem.transform_proj(proj_vel, grid_gla.proj, xx0, yy0) ex1, ey1 = salem.transform_proj(proj_vel, grid_gla.proj, ex1, ey1) # Correct no data after proj as well (inf) xx1[non_valid] = np.NaN yy1[non_valid] = np.NaN ex1[non_valid_e] = np.NaN ey1[non_valid_e] = np.NaN # Compute velocities from there vx = xx1 - xx0 vy = yy1 - yy0 ex = ex1 - ex0 ey = ey1 - ey0 # Scale back velocities - https://github.com/OGGM/oggm/issues/1014 new_vel = np.sqrt(vx**2 + vy**2) new_vel_e = np.sqrt(ex**2 + ey**2) p_ok = new_vel > 1e-5 # avoid div by zero vx[p_ok] = vx[p_ok] * orig_vel[p_ok] / new_vel[p_ok] vy[p_ok] = vy[p_ok] * orig_vel[p_ok] / new_vel[p_ok] p_ok_e = new_vel_e > 1e-5 # avoid div by zero ex[p_ok_e] = ex[p_ok_e] * orig_vel_e[p_ok_e] / new_vel_e[p_ok_e] ey[p_ok_e] = ey[p_ok_e] * orig_vel_e[p_ok_e] / new_vel_e[p_ok_e] # And transform to local map vx = grid_gla.map_gridded_data(vx, grid=grid_vel, interp='linear') vy = grid_gla.map_gridded_data(vy, grid=grid_vel, interp='linear') ex = grid_gla.map_gridded_data(ex, grid=grid_vel, interp='linear') ey = grid_gla.map_gridded_data(ey, grid=grid_vel, interp='linear') # Write with utils.ncDataset(gdir.get_filepath('gridded_data'), 'a') as nc: vn = 'obs_icevel_x' if vn in nc.variables: v = nc.variables[vn] else: v = nc.createVariable(vn, 'f4', ( 'y', 'x', ), zlib=True) v.units = 'm yr-1' v.long_name = 'ITS LIVE velocity data in x map direction' v[:] = vx vn = 'obs_icevel_y' if vn in nc.variables: v = nc.variables[vn] else: v = nc.createVariable(vn, 'f4', ( 'y', 'x', ), zlib=True) v.units = 'm yr-1' v.long_name = 'ITS LIVE velocity data in y map direction' v[:] = vy vn = 'obs_icevel_x_error' if vn in nc.variables: v = nc.variables[vn] else: v = nc.createVariable(vn, 'f4', ( 'y', 'x', ), zlib=True) v.units = 'm yr-1' v.long_name = 'ITS LIVE error velocity data in x map direction' v[:] = ex vn = 'obs_icevel_y_error' if vn in nc.variables: v = nc.variables[vn] else: v = nc.createVariable(vn, 'f4', ( 'y', 'x', ), zlib=True) v.units = 'm yr-1' v.long_name = 'ITS LIVE error velocity data in y map direction' v[:] = ey
def velocity_to_gdir(gdir): """Reproject the its_live files to the given glacier directory. Variables are added to the gridded_data nc file. Reprojecting velocities from one map proj to another is done reprojecting the vector distances. In this process, absolute velocities might change as well because map projections do not always preserve distances -> we scale them back to the original velocities as per the ITS_LIVE documentation that states that velocities are given in ground units, i.e. absolute velocities. We use bilinear interpolation to reproject the velocities to the local glacier map. Parameters ---------- gdir : :py:class:`oggm.GlacierDirectory` where to write the data """ reg = find_region(gdir) if reg is None: raise InvalidWorkflowError('There does not seem to be its_live data ' 'available for this glacier') if not gdir.has_file('gridded_data'): raise InvalidWorkflowError('Please run `glacier_masks` before running ' 'this task') with utils.get_lock(): fx = utils.file_downloader(region_files[reg]['vx']) fy = utils.file_downloader(region_files[reg]['vy']) # Open the files dsx = salem.GeoTiff(fx) dsy = salem.GeoTiff(fy) # subset them to our map grid_gla = gdir.grid.center_grid proj_vel = dsx.grid.proj x0, x1, y0, y1 = grid_gla.extent_in_crs(proj_vel) dsx.set_subset(corners=((x0, y0), (x1, y1)), crs=proj_vel, margin=4) dsy.set_subset(corners=((x0, y0), (x1, y1)), crs=proj_vel, margin=4) grid_vel = dsx.grid.center_grid # TODO: this should be taken care of by salem # https://github.com/fmaussion/salem/issues/171 with rasterio.Env(): with rasterio.open(fx) as src: nodata = getattr(src, 'nodata', -32767.0) # Get the coords at t0 xx0, yy0 = grid_vel.center_grid.xy_coordinates # Compute coords at t1 xx1 = dsx.get_vardata() yy1 = dsy.get_vardata() non_valid = (xx1 == nodata) | (yy1 == nodata) xx1[non_valid] = np.NaN yy1[non_valid] = np.NaN orig_vel = np.sqrt(xx1**2 + yy1**2) xx1 += xx0 yy1 += yy0 # Transform both to glacier proj xx0, yy0 = salem.transform_proj(proj_vel, grid_gla.proj, xx0, yy0) xx1, yy1 = salem.transform_proj(proj_vel, grid_gla.proj, xx1, yy1) # Correct no data after proj as well (inf) xx1[non_valid] = np.NaN yy1[non_valid] = np.NaN # Compute velocities from there vx = xx1 - xx0 vy = yy1 - yy0 # Scale back velocities - https://github.com/OGGM/oggm/issues/1014 new_vel = np.sqrt(vx**2 + vy**2) p_ok = new_vel > 0.1 # avoid div by zero vx[p_ok] = vx[p_ok] * orig_vel[p_ok] / new_vel[p_ok] vy[p_ok] = vy[p_ok] * orig_vel[p_ok] / new_vel[p_ok] # And transform to local map vx = grid_gla.map_gridded_data(vx, grid=grid_vel, interp='linear') vy = grid_gla.map_gridded_data(vy, grid=grid_vel, interp='linear') # Write with utils.ncDataset(gdir.get_filepath('gridded_data'), 'a') as nc: vn = 'obs_icevel_x' if vn in nc.variables: v = nc.variables[vn] else: v = nc.createVariable(vn, 'f4', ( 'y', 'x', ), zlib=True) v.units = 'm yr-1' v.long_name = 'ITS LIVE velocity data in x map direction' v[:] = vx vn = 'obs_icevel_y' if vn in nc.variables: v = nc.variables[vn] else: v = nc.createVariable(vn, 'f4', ( 'y', 'x', ), zlib=True) v.units = 'm yr-1' v.long_name = 'ITS LIVE velocity data in xy map direction' v[:] = vy