Ejemplo n.º 1
0
def interpolate_SRTM(lon_pts, lat_pts):

    # Open NetCDF data file and read cooordintes
    nc_data = nc4.Dataset("earth_relief_15s.nc", "r")
    lon_data = np.deg2rad(nc_data.variables['lon'][:])
    lat_data = np.deg2rad(nc_data.variables['lat'][:])

    # Setup interpolation boxes (for large bathymetry datasets)
    n = 15
    xbox = np.deg2rad(np.linspace(-180, 180, n))
    ybox = np.deg2rad(np.linspace(-90, 90, n))
    dx = xbox[1] - xbox[0]
    dy = ybox[1] - ybox[0]
    boxes = []
    for i in range(n - 1):
        for j in range(n - 1):
            boxes.append(
                np.asarray([xbox[i], xbox[i + 1], ybox[j], ybox[j + 1]]))

    # Initialize bathymetry
    bathymetry = np.zeros(np.shape(lon_pts))
    bathymetry.fill(np.nan)

    # Interpolate inside each box
    start = timeit.default_timer()
    for i, box in enumerate(boxes):
        print(i + 1, "/", len(boxes))

        # Get data inside box (plus a small overlap region)
        overlap = 0.1
        lon_idx, = np.where((lon_data >= box[0] - overlap * dx)
                            & (lon_data <= box[1] + overlap * dx))
        lat_idx, = np.where((lat_data >= box[2] - overlap * dy)
                            & (lat_data <= box[3] + overlap * dy))
        xdata = lon_data[lon_idx]
        ydata = lat_data[lat_idx]
        zdata = nc_data.variables['z'][lat_idx, lon_idx]

        # Get points inside box
        lon_idx, = np.where((lon_pts >= box[0]) & (lon_pts <= box[1]))
        lat_idx, = np.where((lat_pts >= box[2]) & (lat_pts <= box[3]))
        idx = np.intersect1d(lon_idx, lat_idx)
        xpts = lon_pts[idx]
        ypts = lat_pts[idx]

        bathymetry[idx] = interp_bilin(xdata, ydata, zdata, xpts, ypts)

    end = timeit.default_timer()
    print(end - start, " seconds")

    return bathymetry
Ejemplo n.º 2
0
def interpolate_ocean_mask(dsMesh, dsGeom, min_ocean_fraction):
    """
    Interpolate the ocean mask from the original BISICLES grid to the MPAS
    mesh.  This is handled separately from other fields because the ocean mask
    is needed to cull land cells from the MPAS mesh before interpolating the
    remaining fields.

    Parameters
    ----------
    dsMesh : xarray.Dataset
        An MPAS-Ocean mesh

    dsGeom : xarray.Dataset
        Ice-sheet topography produced by
        :py:func:`compass.ocean.tests.isomip_plus.geom.process_input_geometry()`

    min_ocean_fraction : float
        The minimum ocean fraction after interpolation, below which the cell
        is masked as land (which is not distinguished from grounded ice)

    Returns
    -------
    dsMask : xarray.Dataset
        A dataset containing ``regionCellMasks``, a field with the ocean mask
        that can be used to cull land cells from the mesh
    """
    x, y, xCell, yCell, oceanFraction = _get_geom_fields(dsGeom, dsMesh)

    dsMask = xarray.Dataset()

    valid = numpy.logical_and(numpy.logical_and(xCell >= x[0], xCell <= x[-1]),
                              numpy.logical_and(yCell >= y[0], yCell <= y[-1]))

    xCell = xCell[valid]
    yCell = yCell[valid]
    oceanFracObserved = numpy.zeros(dsMesh.sizes['nCells'])
    oceanFracObserved[valid] = interp_bilin(x, y, oceanFraction.values, xCell,
                                            yCell)

    mask = oceanFracObserved > min_ocean_fraction

    nCells = mask.shape[0]

    dsMask['regionCellMasks'] = (('nCells', 'nRegions'),
                                 mask.astype(int).reshape(nCells, 1))

    return dsMask
def inject_spherical_meshDensity(cellWidth, lon, lat, mesh_filename):
    """
    Add a ``meshDensity`` field into a spherical MPAS mesh.  The mesh density is
    defined as:

      meshDensity = (minCellWidth / cellWidth)**4

    Parameters
    ----------
    cellWidth : ndarray
        m x n array of cell width in km

    lon : ndarray
        longitude in degrees (length n and between -180 and 180)

    lat : ndarray
        longitude in degrees (length m and between -90 and 90)

    mesh_filename : str
        The mesh file to add ``meshDensity`` to
    """

    minCellWidth = cellWidth.min()
    meshDensityVsXY = (minCellWidth / cellWidth)**4
    print('  minimum cell width in grid definition: {0:.0f} km'.format(
        minCellWidth))
    print('  maximum cell width in grid definition: {0:.0f} km'.format(
        cellWidth.max()))

    print('Open unstructured MPAS mesh file...')
    ds = nc4.Dataset(mesh_filename, 'r+')
    meshDensity = ds.variables['meshDensity']
    lonCell = ds.variables['lonCell'][:]
    latCell = ds.variables['latCell'][:]

    lonCell = np.mod(np.rad2deg(lonCell) + 180., 360.) - 180.
    latCell = np.rad2deg(latCell)

    print('Interpolating and writing meshDensity...')
    mpasMeshDensity = interp_bilin(lon, lat, meshDensityVsXY, lonCell, latCell)

    meshDensity[:] = mpasMeshDensity

    ds.close()
def inject_planar_meshDensity(cellWidth, x, y, mesh_filename):
    """
    Add a ``meshDensity`` field into a planar MPAS mesh.  The mesh density is
    defined as:

      meshDensity = (minCellWidth / cellWidth)**4

    Parameters
    ----------
    cellWidth : ndarray
        m x n array of cell width in km

    x, y : ndarray
        Planar coordinates in meters

    mesh_filename : str
        The mesh file to add ``meshDensity`` to
    """
    minCellWidth = cellWidth.min()
    meshDensityVsXY = (minCellWidth / cellWidth)**4
    print('  minimum cell width in grid definition: {0:.0f} km'.format(
        minCellWidth))
    print('  maximum cell width in grid definition: {0:.0f} km'.format(
        cellWidth.max()))

    print('Open unstructured MPAS mesh file...')
    ds = nc4.Dataset(mesh_filename, 'r+')
    meshDensity = ds.variables['meshDensity']
    xCell = ds.variables['xCell'][:]
    yCell = ds.variables['xCell'][:]

    print('Interpolating and writing meshDensity...')
    mpasMeshDensity = interp_bilin(x, y, meshDensityVsXY, xCell, yCell)

    meshDensity[:] = mpasMeshDensity

    ds.close()
Ejemplo n.º 5
0
def interpolate_geom(dsMesh, dsGeom, min_ocean_fraction):
    """
    Interpolate the ice geometry from the original BISICLES grid to the MPAS
    mesh.

    Parameters
    ----------
    dsMesh : xarray.Dataset
        An MPAS-Ocean mesh

    dsGeom : xarray.Dataset
        Ice-sheet topography produced by
        :py:func:`compass.ocean.tests.isomip_plus.geom.process_input_geometry()`

    min_ocean_fraction : float
        The minimum ocean fraction after interpolation, below which the cell
        is masked as land (which is not distinguished from grounded ice)

    Returns
    -------
    dsOut : xarray.Dataset
        A dataset containing :

        * ``bottomDepthObserved`` -- the bedrock elevation (positive up)

        * ``ssh`` -- the sea surface height

        * ``oceanFracObserved`` -- the fraction of the mesh cell that is ocean

        * ``landIceFraction`` -- the fraction of the mesh cell that is covered
          by an ice shelf

        * ``smoothedDraftMask`` -- a smoothed version of the floating mask that
          may be useful for determining where to alter the vertical coordinate
          to accommodate ice-shelf cavities
    """
    x, y, xCell, yCell, oceanFraction = _get_geom_fields(dsGeom, dsMesh)

    dsOut = xarray.Dataset(dsMesh)
    dsOut.attrs = dsMesh.attrs

    dsGeom['oceanFraction'] = oceanFraction

    # mash the topography to the ocean region before interpolation
    for var in [
            'Z_bed', 'Z_ice_draft', 'floatingIceFraction', 'smoothedDraftMask'
    ]:
        dsGeom[var] = dsGeom[var] * dsGeom['oceanFraction']

    fields = {
        'bottomDepthObserved': 'Z_bed',
        'ssh': 'Z_ice_draft',
        'oceanFracObserved': 'oceanFraction',
        'landIceFraction': 'floatingIceFraction',
        'smoothedDraftMask': 'smoothedDraftMask'
    }

    valid = numpy.logical_and(numpy.logical_and(xCell >= x[0], xCell <= x[-1]),
                              numpy.logical_and(yCell >= y[0], yCell <= y[-1]))

    if not numpy.all(valid):
        raise ValueError('Something went wrong with culling.  There are still '
                         'out-of-range cells in the culled mesh.')

    for outfield, infield in fields.items():
        field = interp_bilin(x, y, dsGeom[infield].values, xCell, yCell)
        dsOut[outfield] = (('nCells', ), field)

    oceanFracObserved = dsOut['oceanFracObserved']
    if not numpy.all(oceanFracObserved > min_ocean_fraction):
        raise ValueError('Something went wrong with culling.  There are still '
                         'non-ocean cells in the culled mesh.')

    for field in [
            'bottomDepthObserved', 'ssh', 'landIceFraction',
            'smoothedDraftMask'
    ]:
        dsOut[field] = dsOut[field] / oceanFracObserved

    return dsOut