def make(lon, lat, dx, keep_ll=False): if lon.ndim == 1: grid_lons, grid_lats = np.meshgrid(lon, lat) else: grid_lons = lon grid_lats = lat if not keep_ll: # Transform lon, lats to the mercator projection proj = pyproj.Proj('+proj=merc +lat_0=0. +lon_0=0.') x, y = pyproj.transform(salem.wgs84, proj, grid_lons, grid_lats) else: proj = salem.wgs84 x, y = grid_lons, grid_lats # take the min and max xmax, xmin = np.max(x), np.min(x) ymax, ymin = np.max(y), np.min(y) # Count the number of pixels nx, r = divmod(xmax - xmin, dx) ny, r = divmod(ymax - ymin, dx) # Here one could add + 1 to be sure that the last pixel is always included grid = salem.Grid(nxny=(nx, ny), dxdy=(dx, dx), ll_corner=(xmin, ymin), proj=proj) return grid
=============== Shape to raster =============== Compute a land/sea mask from a shapefile. This example illustrates the two different methods available to compute a raster mask from shapefile polygons. """ import salem import matplotlib.pyplot as plt # make a local grid from which we will compute the mask # we make it coarse so that we see the grid points grid = salem.Grid(proj=salem.wgs84, x0y0=(-18, 3), nxny=(25, 15), dxdy=(1, 1)) # read the ocean shapefile (data from http://www.naturalearthdata.com) oceans = salem.read_shapefile(salem.get_demo_file('ne_50m_ocean.shp'), cached=True) # read the lake shapefile (data from http://www.naturalearthdata.com) lakes = salem.read_shapefile(salem.get_demo_file('ne_50m_lakes.shp'), cached=True) # The default is to keep only the pixels which center is within the polygon: mask_default = grid.region_of_interest(shape=oceans) mask_default = grid.region_of_interest(shape=lakes, roi=mask_default) # But we can also compute a mask from all touched pixels mask_all_touched = grid.region_of_interest(shape=oceans, all_touched=True)
def blob(): trmm_folder = "/users/global/cornkle/data/OBS/TRMM/trmm_swaths_WA/" box = [-20, 0, 20, 25] # make grid # define projection proj = pyproj.Proj('+proj=merc +lat_0=0. +lon_0=0.') # get lower left x,y fr 10W, 4N x, y = pyproj.transform(salem.wgs84, proj, [box[0], box[2]], [box[1], box[3]]) dx = 12000 # 5km grid nx, r = divmod(x[1] - x[0], dx) ny, r = divmod(y[1] - y[0], dx) # make salem grid grid = salem.Grid(nxny=(nx, ny), dxdy=(12000, 12000), ll_corner=(x[0], y[0]), proj=proj) xi, yi = grid.ij_coordinates lon, lat = grid.ll_coordinates t = trmm.ReadWA(trmm_folder, yrange=YRANGE, area=[box[0], box[1], box[2], box[3]]) print('readTRMM') cnt = 0 # cycle through TRMM dates - only dates tat have a certain number of pixels in llbox are considered for _y, _m, _d, _h, _mi in zip(t.dates.y, t.dates.m, t.dates.d, t.dates.h, t.dates.mi): if (_m!=6) & (_m!=7): continue # dummy = np.empty((ny,nx))*-100#np.NAN td = t.get_ddata(_y, _m, _d, _h, _mi, cut=[box[1], box[3]]) date = dt.datetime(_y, _m, _d, _h, _mi) print(date) # ensure minimum trmm rainfall in area if len(np.where(td['p'].values > 0)[0]) < 10: # at least 100 pixel with rainfall print('Kickout: TRMM min pixel = 100') continue # Transform lons, lats to grid xt, yt = grid.transform(td['lon'].values.flatten(), td['lat'].values.flatten(), crs=salem.wgs84) # Convert for griddata input tpoints = np.array((yt, xt)).T inter = np.array((np.ravel(yi), np.ravel(xi))).T # Interpolate using delaunay triangularization dummyt = griddata(tpoints, td['p'].values.flatten(), inter, method='linear') outt = dummyt.reshape((grid.ny, grid.nx)) for nb in range(5): boole = np.isnan(outt) outt[boole] = -1000 grad = np.gradient(outt) outt[boole] = np.nan outt[abs(grad[1]) > 300] = np.nan outt[abs(grad[0]) > 300] = np.nan if np.nanmin(outt) < 0: continue print('Makes no sense!') # # add MSG # # define the "0 lag" frist # msg_folder = '/users/global/cornkle/data/OBS/meteosat_SA15' # m = msg.ReadMsg(msg_folder) # arr = np.array([15, 30, 45, 60, 0]) # dm = arr - _mi # ind = (np.abs(dm)).argmin() # # dt0 = dm[ind] # ndate = date + dt.timedelta(minutes=int(dt0)) # # m.set_date(ndate.year, ndate.month, ndate.day, ndate.hour, ndate.minute) # # if not m.dpath: # print('Date missing') # #continue # out = np.empty_like(outt) # out.fill(np.nan) # # else: # ml0 = m.get_data(llbox=box) # # xm, ym = grid.transform(ml0['lon'].values.flatten(), ml0['lat'].values.flatten(), crs=salem.wgs84) # mpoints = np.array((ym, xm)).T # out = griddata(mpoints, ml0['t'].values.flatten(), inter, method='linear') # out = out.reshape((grid.ny, grid.nx)) da = xr.Dataset({'p': (['x', 'y'], outt) # 't': (['x', 'y'], out) }, coords={'lon': (['x', 'y'], lon), 'lat': (['x', 'y'], lat), 'time': date}) da.close() savefile = '/users/global/cornkle/VERA/' + date.strftime('%Y-%m-%d_%H:%M:%S') + '.nc' try: os.remove(savefile) except OSError: pass da.to_netcdf(path=savefile, mode='w') print('Saved ' + savefile) cnt = cnt + 1 print('Saved ' + str(cnt) + ' TRMM swaths as netcdf.')
def define_glacier_region(gdir, entity=None): """ Very first task: define the glacier's local grid. Defines the local projection (Transverse Mercator), centered on the glacier. There is some options to set the resolution of the local grid. It can be adapted depending on the size of the glacier with:: dx (m) = d1 * AREA (km) + d2 ; clipped to dmax or be set to a fixed value. See ``params.cfg`` for setting these options. Default values of the adapted mode lead to a resolution of 50 m for Hintereisferner, which is approx. 8 km2 large. After defining the grid, the topography and the outlines of the glacier are transformed into the local projection. The default interpolation for the topography is `cubic`. Parameters ---------- gdir : :py:class:`oggm.GlacierDirectory` where to write the data entity : geopandas GeoSeries the glacier geometry to process """ # choose a spatial resolution with respect to the glacier area dxmethod = cfg.PARAMS['grid_dx_method'] area = gdir.rgi_area_km2 if dxmethod == 'linear': dx = np.rint(cfg.PARAMS['d1'] * area + cfg.PARAMS['d2']) elif dxmethod == 'square': dx = np.rint(cfg.PARAMS['d1'] * np.sqrt(area) + cfg.PARAMS['d2']) elif dxmethod == 'fixed': dx = np.rint(cfg.PARAMS['fixed_dx']) else: raise ValueError('grid_dx_method not supported: {}'.format(dxmethod)) # Additional trick for varying dx if dxmethod in ['linear', 'square']: dx = np.clip(dx, cfg.PARAMS['d2'], cfg.PARAMS['dmax']) log.debug('%s: area %.2f km, dx=%.1f', gdir.rgi_id, area, 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) project = partial(pyproj.transform, proj_in, proj_out) # transform geometry to map geometry = shapely.ops.transform(project, entity['geometry']) geometry = _check_geometry(geometry) xx, yy = geometry.exterior.xy # Corners, incl. a buffer of N pix ulx = np.min(xx) - cfg.PARAMS['border'] * dx lrx = np.max(xx) + cfg.PARAMS['border'] * dx uly = np.max(yy) + cfg.PARAMS['border'] * dx lry = np.min(yy) - cfg.PARAMS['border'] * dx # 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) # save transformed geometry to disk entity = entity.copy() entity['geometry'] = geometry # Avoid fiona bug: https://github.com/Toblerity/Fiona/issues/365 for k, s in entity.iteritems(): if type(s) in [np.int32, np.int64]: entity[k] = int(s) towrite = gpd.GeoDataFrame(entity).T towrite.crs = proj4_str # Delete the source before writing if 'DEM_SOURCE' in towrite: del towrite['DEM_SOURCE'] towrite.to_file(gdir.get_filepath('outlines')) # Also transform the intersects if necessary gdf = cfg.PARAMS['intersects_gdf'] gdf = gdf.loc[(gdf.RGIId_1 == gdir.rgi_id) | (gdf.RGIId_2 == gdir.rgi_id)] if len(gdf) > 0: gdf = salem.transform_geopandas(gdf, to_crs=proj_out) if hasattr(gdf.crs, 'srs'): # salem uses pyproj gdf.crs = gdf.crs.srs gdf.to_file(gdir.get_filepath('intersects')) # Open DEM source = entity.DEM_SOURCE if hasattr(entity, 'DEM_SOURCE') else None dem_list, dem_source = get_topo_file((minlon, maxlon), (minlat, maxlat), rgi_region=gdir.rgi_region, source=source) log.debug('%s: DEM source: %s', gdir.rgi_id, 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) src_transform = dem_dss[0].transform 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) 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')) gdir.write_pickle(dem_source, 'dem_source') # Looks in the database if the glacier has divides. gdf = cfg.PARAMS['divides_gdf'] if gdir.rgi_id in gdf.index.values: divdf = [g for g in gdf.loc[gdir.rgi_id].geometry] # Reproject the shape def proj(lon, lat): return salem.transform_proj(salem.wgs84, gdir.grid.proj, lon, lat) divdf = [shapely.ops.transform(proj, g) for g in divdf] # Keep only the ones large enough log.debug('%s: divide candidates: %d', gdir.rgi_id, len(divdf)) divdf = [g for g in divdf if (g.area >= (25 * dx**2))] log.debug('%s: number of divides: %d', gdir.rgi_id, len(divdf)) # Write the directories and the files for i, g in enumerate(divdf): _dir = os.path.join(gdir.dir, 'divide_{0:0=2d}'.format(i + 1)) if not os.path.exists(_dir): os.makedirs(_dir) # File entity['geometry'] = g towrite = gpd.GeoDataFrame(entity).T towrite.crs = proj4_str towrite.to_file(os.path.join(_dir, cfg.BASENAMES['outlines'])) else: # Make a single directory and link the files log.debug('%s: number of divides: %d', gdir.rgi_id, 1) _dir = os.path.join(gdir.dir, 'divide_01') if not os.path.exists(_dir): os.makedirs(_dir) linkname = os.path.join(_dir, cfg.BASENAMES['outlines']) sourcename = gdir.get_filepath('outlines') for ending in ['.cpg', '.dbf', '.shp', '.shx', '.prj']: _s = sourcename.replace('.shp', ending) _l = linkname.replace('.shp', ending) if os.path.exists(_s): try: # we are on UNIX os.link(_s, _l) except AttributeError: # we are on windows copyfile(_s, _l)
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 define_glacier_region(gdir, entity=None): """ Very first task: define the glacier's grid. Defines the local glacier projection (Transverse Mercator), chooses a resolution for the grid, and transforms the DEM as well as the RGI shape into it. Parameters ---------- gdir : oggm.GlacierDirectory entity : geopandas entity the glacier geometry to process """ # choose a spatial resolution with respect to the glacier area dxmethod = cfg.PARAMS['grid_dx_method'] area = gdir.rgi_area_km2 if dxmethod == 'linear': dx = np.rint(cfg.PARAMS['d1'] * area + cfg.PARAMS['d2']) elif dxmethod == 'square': dx = np.rint(cfg.PARAMS['d1'] * np.sqrt(area) + cfg.PARAMS['d2']) else: raise ValueError('grid_dx_method not supported: {}'.format(dxmethod)) dx = np.clip(dx, cfg.PARAMS['d2'], cfg.PARAMS['dmax']) log.debug('%s: area %.2f km, dx=%.1f', gdir.rgi_id, area, 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) project = partial(pyproj.transform, proj_in, proj_out) geometry = shapely.ops.transform(project, entity['geometry']) geometry = _check_geometry(geometry) xx, yy = geometry.exterior.xy # Corners, incl. a buffer of N pix ulx = np.min(xx) - cfg.PARAMS['border'] * dx lrx = np.max(xx) + cfg.PARAMS['border'] * dx uly = np.max(yy) + cfg.PARAMS['border'] * dx lry = np.min(yy) - cfg.PARAMS['border'] * dx # 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), ul_corner=(ulx, uly), dxdy=(dx, -dx), pixel_ref='corner') minlon, maxlon, minlat, maxlat = tmp_grid.extent_in_crs(crs=salem.wgs84) # save transformed geometry to disk entity['geometry'] = geometry towrite = gpd.GeoDataFrame(entity).T towrite.crs = proj4_str towrite.to_file(gdir.get_filepath('outlines')) # Open DEM dem_file, dem_source = get_topo_file((minlon, maxlon), (minlat, maxlat), region=gdir.rgi_region) log.debug('%s: DEM source: %s', gdir.rgi_id, dem_source) dem = gdal.Open(dem_file) geo_t = dem.GetGeoTransform() # Input proj dem_proj = dem.GetProjection() if dem_proj == '': # Assume defaults wgs84 = osr.SpatialReference() wgs84.ImportFromEPSG(4326) dem_proj = wgs84.ExportToWkt() # Dest proj gproj = osr.SpatialReference() gproj.SetProjCS('Local transverse Mercator') gproj.SetWellKnownGeogCS("WGS84") gproj.SetTM(np.float(0), gdir.cenlon, np.float(0.9996), np.float(0), np.float(0)) # Create an in-memory raster mem_drv = gdal.GetDriverByName('MEM') # GDALDataset Create (char *pszName, int nXSize, int nYSize, # int nBands, GDALDataType eType) dest = mem_drv.Create('', nx, ny, 1, gdal.GDT_Float32) # Calculate the new geotransform new_geo = (ulx, dx, geo_t[2], uly, geo_t[4], -dx) # Set the geotransform dest.SetGeoTransform(new_geo) dest.SetProjection(gproj.ExportToWkt()) # Perform the projection/resampling if cfg.PARAMS['topo_interp'] == 'bilinear': interp = gdal.GRA_Bilinear elif cfg.PARAMS['topo_interp'] == 'cubic': interp = gdal.GRA_Cubic else: raise ValueError('{} interpolation not understood'.format( cfg.PARAMS['topo_interp'])) res = gdal.ReprojectImage(dem, dest, dem_proj, gproj.ExportToWkt(), interp) # Let's save it as a GeoTIFF. driver = gdal.GetDriverByName("GTiff") tmp = driver.CreateCopy(gdir.get_filepath('dem'), dest, 0) tmp = None # without this, GDAL is getting crazy in python3 dest = None # the memfree above is necessary, this one is to be sure... # Glacier grid ul_corner = (ulx + dx / 2, uly - dx / 2) # To pixel center coordinates glacier_grid = salem.Grid(proj=proj_out, nxny=(nx, ny), dxdy=(dx, -dx), ul_corner=ul_corner) gdir.write_pickle(glacier_grid, 'glacier_grid') gdir.write_pickle(dem_source, 'dem_source') # Looks in the database if the glacier has divides. gdf = cfg.PARAMS['divides_gdf'] if gdir.rgi_id in gdf.index.values: divdf = [g for g in gdf.loc[gdir.rgi_id].geometry] log.debug('%s: number of divides: %d', gdir.rgi_id, len(divdf)) # Reproject the shape def proj(lon, lat): return salem.transform_proj(salem.wgs84, gdir.grid.proj, lon, lat) divdf = [shapely.ops.transform(proj, g) for g in divdf] # Write the directories and the files for i, g in enumerate(divdf): _dir = os.path.join(gdir.dir, 'divide_{0:0=2d}'.format(i + 1)) if not os.path.exists(_dir): os.makedirs(_dir) # File entity['geometry'] = g towrite = gpd.GeoDataFrame(entity).T towrite.crs = proj4_str towrite.to_file(os.path.join(_dir, cfg.BASENAMES['outlines'])) else: # Make a single directory and link the files log.debug('%s: number of divides: %d', gdir.rgi_id, 1) _dir = os.path.join(gdir.dir, 'divide_01') if not os.path.exists(_dir): os.makedirs(_dir) linkname = os.path.join(_dir, cfg.BASENAMES['outlines']) sourcename = gdir.get_filepath('outlines') # TODO: temporary suboptimal solution try: # we are on UNIX os.link(sourcename, linkname) except AttributeError: # we are on windows copyfile(sourcename, linkname)
def define_glacier_region(gdir, entity=None): """Very first task: define the glacier's local grid. Defines the local projection (Transverse Mercator), centered on the glacier. There is some options to set the resolution of the local grid. It can be adapted depending on the size of the glacier with:: dx (m) = d1 * AREA (km) + d2 ; clipped to dmax or be set to a fixed value. See ``params.cfg`` for setting these options. Default values of the adapted mode lead to a resolution of 50 m for Hintereisferner, which is approx. 8 km2 large. After defining the grid, the topography and the outlines of the glacier are transformed into the local projection. The default interpolation for the topography is `cubic`. Parameters ---------- gdir : :py:class:`oggm.GlacierDirectory` where to write the data entity : geopandas.GeoSeries the glacier geometry to process """ # 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) project = partial(pyproj.transform, proj_in, proj_out) # transform geometry to map geometry = shapely.ops.transform(project, entity['geometry']) geometry = multi_to_poly(geometry, gdir=gdir) xx, yy = geometry.exterior.xy # Save transformed geometry to disk entity = entity.copy() entity['geometry'] = geometry # Avoid fiona bug: https://github.com/Toblerity/Fiona/issues/365 for k, s in entity.iteritems(): if type(s) in [np.int32, np.int64]: entity[k] = int(s) towrite = gpd.GeoDataFrame(entity).T towrite.crs = proj4_str # Delete the source before writing if 'DEM_SOURCE' in towrite: del towrite['DEM_SOURCE'] # Define glacier area to use area = entity['Area'] # Do we want to use the RGI area or ours? if not cfg.PARAMS['use_rgi_area']: area = geometry.area * 1e-6 entity['Area'] = area towrite['Area'] = area # Write shapefile gdir.write_shapefile(towrite, 'outlines') # Also transform the intersects if necessary gdf = cfg.PARAMS['intersects_gdf'] if len(gdf) > 0: gdf = gdf.loc[((gdf.RGIId_1 == gdir.rgi_id) | (gdf.RGIId_2 == gdir.rgi_id))] if len(gdf) > 0: gdf = salem.transform_geopandas(gdf, to_crs=proj_out) if hasattr(gdf.crs, 'srs'): # salem uses pyproj gdf.crs = gdf.crs.srs gdir.write_shapefile(gdf, 'intersects') else: # Sanity check if cfg.PARAMS['use_intersects']: raise InvalidParamsError('You seem to have forgotten to set the ' 'intersects file for this run. OGGM ' 'works better with such a file. If you ' 'know what your are doing, set ' "cfg.PARAMS['use_intersects'] = False to " "suppress this error.") # 6. choose a spatial resolution with respect to the glacier area dxmethod = cfg.PARAMS['grid_dx_method'] if dxmethod == 'linear': dx = np.rint(cfg.PARAMS['d1'] * area + cfg.PARAMS['d2']) elif dxmethod == 'square': dx = np.rint(cfg.PARAMS['d1'] * np.sqrt(area) + cfg.PARAMS['d2']) elif dxmethod == 'fixed': dx = np.rint(cfg.PARAMS['fixed_dx']) else: raise InvalidParamsError( 'grid_dx_method not supported: {}'.format(dxmethod)) # Additional trick for varying dx if dxmethod in ['linear', 'square']: dx = np.clip(dx, cfg.PARAMS['d2'], cfg.PARAMS['dmax']) log.debug('(%s) area %.2f km, dx=%.1f', gdir.rgi_id, area, dx) # Safety check border = cfg.PARAMS['border'] if border > 1000: raise InvalidParamsError("You have set a cfg.PARAMS['border'] value " "of {}. ".format(cfg.PARAMS['border']) + 'This a very large value, which is ' 'currently not supported in OGGM.') # For tidewater glaciers we force border to 10 if gdir.is_tidewater and cfg.PARAMS['clip_tidewater_border']: border = 10 # Corners, incl. a buffer of N pix ulx = np.min(xx) - border * dx lrx = np.max(xx) + border * dx uly = np.max(yy) + border * dx lry = np.min(yy) - border * dx # 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) # Open DEM source = entity.DEM_SOURCE if hasattr(entity, 'DEM_SOURCE') else None dem_list, dem_source = get_topo_file((minlon, maxlon), (minlat, maxlat), rgi_region=gdir.rgi_region, rgi_subregion=gdir.rgi_subregion, source=source) log.debug('(%s) DEM source: %s', gdir.rgi_id, dem_source) log.debug('(%s) N DEM Files: %s', gdir.rgi_id, len(dem_list)) # 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 InvalidParamsError('{} interpolation not understood'.format( cfg.PARAMS['topo_interp'])) dem_reproj = gdir.get_filepath('dem') profile.pop('blockxsize', None) profile.pop('blockysize', None) profile.pop('compress', None) nodata = dem_dss[0].meta.get('nodata', None) if source == 'TANDEM' and nodata is None: # badly tagged geotiffs, let's do it ourselves nodata = -32767 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, src_nodata=nodata, # Destination parameters destination=dst_array, dst_transform=dst_transform, dst_crs=proj4_str, dst_nodata=nodata, # Configuration resampling=resampling) 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 gdir.add_to_diagnostics('dem_source', dem_source) source_txt = DEM_SOURCE_INFO.get(dem_source, dem_source) with open(gdir.get_filepath('dem_source'), 'w') as fw: fw.write(source_txt) fw.write('\n\n') fw.write('# Data files\n\n') for fname in dem_list: fw.write('{}\n'.format(os.path.basename(fname)))
import cartopy.crs as ccrs import cartopy import salem import matplotlib.pyplot as plt from salem import wgs84 grid = salem.Grid(nxny=(360, 180), dxdy=(1, 1), x0y0=(0.0, 0.0), proj=wgs84) print('1') ccrs.PlateCarree() central_lon, central_lat = -10, 45 extent = [-40, 20, 30, 60] ax = plt.axes(projection=ccrs.Orthographic(central_lon, central_lat)) ax.set_extent(extent) ax.gridlines() ax.coastlines(resolution='50m') print('2') import xarray as xr ds = xr.open_dataset( r'..\..\storage\C3S-LC-L4-LCCS-Map-300m-P1Y-2018-v2.1.1.nc') print('3') sst = ds['lccs_class'].isel(time=0) sst = sst.salem.subset(corners=((-40., 20.), (30., 60.)), crs=salem.wgs84) sst = sst.salem.subset(shape=shapes, margin=2)
dlon_km = haversine(lon1, np.min([lat1, lat2]), lon2, np.min([lat1, lat2])) nx_guess = int(dlon_km * 1000.0 / dx) dlat_km = haversine(lon1, lat1, lon1, lat2) ny_guess = int(dlat_km * 1000.0 / dy) nx = 1.7 * nx_guess ny = 1.7 * ny_guess lonc = 0.5 * (lon1 + lon2) print ' estimated nx and ny as {:n} and {:n}'.format(nx, ny) # create the correct projection x0 = -4e5 y0 = -5e5 pwrf = '+proj=lcc +lat_1={:2.5f} +lat_2={:2.5f} ' \ '+lat_0={:2.5f} +lon_0={:2.5f} ' \ '+x_0={:f} +y_0={:f}'.format(lat1,lat2,lat0,lonc,0,0) grid = salem.Grid(nxny=(nx, ny), x0y0=(x0, y0), dxdy=(dx, dy), proj=pwrf) lon1d = np.min(grid.ll_coordinates[0]) lon2d = np.max(grid.ll_coordinates[0]) lat1d = np.min(grid.ll_coordinates[1]) lat2d = np.max(grid.ll_coordinates[1]) # output an overview of the topography sm = salem.Map(grid) if preview: print ' * approximate boundaries (WESN):{:3.0f},{:3.0f},{:3.0f},{:3.0f}'.format( lon1d, lon2d, lat1d, lat2d) if plots: sm.visualize() print ' creating preview file...' plt.savefig('./{:s}_preview.pdf'.format(name))