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
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()
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