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
Exemplo n.º 2
0
===============
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)
Exemplo n.º 3
0
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.')
Exemplo n.º 4
0
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)
Exemplo n.º 5
0
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)
Exemplo n.º 6
0
Arquivo: gis.py Projeto: Enaith/oggm
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)
Exemplo n.º 7
0
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)))
Exemplo n.º 8
0
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)
Exemplo n.º 9
0
    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))