def ferret_result_limits(efid): """ Abstract axis limits for the shapefile_readxyz PyEF """ maxpts = pyferret.get_arg_one_val(efid, pyferret.ARG2) maxpts = int(maxpts) if maxpts == -1: shapefile_name = pyferret.get_arg_one_val(efid, pyferret.ARG1) sf = shapefile.Reader(shapefile_name) maxpts = 0 for shp in sf.shapes(): maxpts += len(shp.points) + 1 elif maxpts < 1: raise ValueError("MAXPTS must be a positive integer or -1") return ( (1, maxpts), (1, 3), None, None, None, None, )
def ferret_result_limits(efid): ''' Provides the bounds of the E abstract axis. The maximum number of EOFs is the number of locations. ''' maxeofs = pyferret.get_arg_one_val(efid, pyferret.ARG3) if maxeofs > 0.95: maxeofs = int(maxeofs + 0.1) else: maxeofs = 1 for axis in (pyferret.X_AXIS, pyferret.Y_AXIS, pyferret.Z_AXIS): axis_info = pyferret.get_axis_info(efid, pyferret.ARG1, axis) if axis_info: npts = axis_info.get("size", -1) if npts > 0: maxeofs *= npts result_limits = [None] * pyferret.MAX_FERRET_NDIM result_limits[pyferret.E_AXIS] = (1, maxeofs + 1) return result_limits
def ferret_compute(efid, result, result_bdf, inputs, input_bdfs): ''' Performs the regridding for the curv2rect function. Arguments: result - numpy array for rectilinear data values to be assigned result_bdf - numpy array of the missing-data value for result inputs - numpy arrays (CurvData, CurvCenterLons, CurvCenterLats, CurvCornerLons, CurvCornerLats. TemplateRectVar, Method) input_bdfs - numpy arrays of missing-data values for the corresponding inputs array ''' # Get the regridding method to use methodstr = pyferret.get_arg_one_val(efid, pyferret.ARG7).upper() if methodstr == "BILINEAR": method = ESMP.ESMP_REGRIDMETHOD_BILINEAR elif methodstr == "PATCH": method = ESMP.ESMP_REGRIDMETHOD_PATCH elif methodstr == "CONSERVE": method = ESMP.ESMP_REGRIDMETHOD_CONSERVE else: raise ValueError("Unknown method %s" % methodstr) # Get the template data and missing value template_data = inputs[pyferret.ARG6] template_undef = input_bdfs[pyferret.ARG6] # Get the rectilinear center longitudes and latitudes rect_center_lons = pyferret.get_axis_coordinates(efid, pyferret.ARG6, pyferret.X_AXIS) rect_center_lats = pyferret.get_axis_coordinates(efid, pyferret.ARG6, pyferret.Y_AXIS) # Get the rectilinear corner longitudes lo, hi = pyferret.get_axis_box_limits(efid, pyferret.ARG6, pyferret.X_AXIS) if not numpy.allclose(lo[1:], hi[:-1]): raise ValueError("Unexpected ARG6 X_AXIS box limit values " \ "returned from pyferret.get_axis_box_limits") rect_corner_lons = numpy.empty((lo.shape[0] + 1), dtype=numpy.float64) rect_corner_lons[0] = lo[0] rect_corner_lons[1:] = hi # Get the rectilinear corner latitudes lo, hi = pyferret.get_axis_box_limits(efid, pyferret.ARG6, pyferret.Y_AXIS) if not numpy.allclose(lo[1:], hi[:-1]): raise ValueError("Unexpected ARG6 Y_AXIS box limit values " \ "returned from pyferret.get_axis_box_limits") rect_corner_lats = numpy.empty((lo.shape[0] + 1), dtype=numpy.float64) rect_corner_lats[0] = lo[0] rect_corner_lats[1:] = hi # Get the curvilinear data curv_data = inputs[pyferret.ARG1] curv_centers_shape = (curv_data.shape[0], curv_data.shape[1]) if (curv_data.shape[2:] != template_data.shape[2:]): raise ValueError("Curvilinear data and template variable " \ "must have same Z, T, E, and F axes") curv_undef = input_bdfs[pyferret.ARG1] # Get the curvilinear centers arrays lons = inputs[pyferret.ARG2].squeeze() lats = inputs[pyferret.ARG3].squeeze() if (lons.shape == curv_centers_shape) and (lats.shape == curv_centers_shape): curv_center_lons = lons curv_center_lats = lats elif (lons.shape == ()) and (lats.shape == ()): curv_center_lons = None curv_center_lats = None else: raise ValueError("Curvilinear center points must have " \ "appropriate shape or be singletons") # Get the curvilinear corners arrays lons = inputs[pyferret.ARG4].squeeze() lats = inputs[pyferret.ARG5].squeeze() corners_shape = (curv_data.shape[0] + 1, curv_data.shape[1] + 1) corners_shape_3d = (curv_data.shape[0], curv_data.shape[1], 4) if (lons.shape == corners_shape) and (lats.shape == corners_shape): curv_corner_lons = lons curv_corner_lats = lats elif (lons.shape == corners_shape_3d) and (lats.shape == corners_shape_3d): curv_corner_lons, curv_corner_lats = regrid.quadCornersFrom3D( lons, lats) elif method == ESMP.ESMP_REGRIDMETHOD_CONSERVE: raise ValueError("CONSERVE method requires " \ "curvilinear grid corner coordinates") elif (lons.shape == ()) and (lats.shape == ()): curv_corner_lons = None curv_corner_lats = None else: raise ValueError("Curvilinear corner points must have " \ "appropriate shape or be singletons") # If curvilinear center point coordinates not given, # generate them from the curvilinear corner points if curv_center_lons is None: if not curv_corner_lons is None: curv_center_lons, curv_center_lats = \ regrid.quadCentroids(curv_corner_lons, curv_corner_lats) else: raise ValueError("Valid center or corner curvilinear " \ "grid coordinates must be given") # Make sure ESMP is, or has been, initialized regrid.ESMPControl().startCheckESMP() # Create the regridder used repeatedly in this function regridder = regrid.CurvRectRegridder() last_curv_center_ignore = None last_rect_center_ignore = None # Increment the depth index last # most likely to change the undefined (e.g., land) mask for d_idx in range(curv_data.shape[2]): # Arrays are probably in Fortran order, so increment last indices last for f_idx in range(curv_data.shape[5]): for e_idx in range(curv_data.shape[4]): for t_idx in range(curv_data.shape[3]): # Determine curvilinear center points to ignore from undefined data curv_center_ignore = ( numpy.abs(curv_data[:, :, d_idx, t_idx, e_idx, f_idx] - curv_undef) < 1.0E-7) # If mask has changed, need to recreate the curvilinear grid if (last_curv_center_ignore is None) or \ numpy.any(curv_center_ignore != last_curv_center_ignore): regridder.createCurvGrid(curv_center_lons, curv_center_lats, curv_center_ignore, curv_corner_lons, curv_corner_lats, None) last_curv_center_ignore = curv_center_ignore # Determine rectilinear center points to ignore from undefined data rect_center_ignore = (numpy.abs( template_data[:, :, d_idx, t_idx, e_idx, f_idx] - template_undef) < 1.0E-7) # If mask has changed, need to recreate the rectilinear grid if (last_rect_center_ignore is None) or \ numpy.any(rect_center_ignore != last_rect_center_ignore): regridder.createRectGrid(rect_center_lons, rect_center_lats, rect_center_ignore, rect_corner_lons, rect_corner_lats, None) last_rect_center_ignore = rect_center_ignore # Assign the curvilinear data regridder.assignCurvField(curv_data[:, :, d_idx, t_idx, e_idx, f_idx]) # Allocate space for the rectilinear data from the regridding regridder.assignRectField(None) # Regrid and assign the rectilinear data to the results array regrid_data = regridder.regridCurvToRect( result_bdf, method) result[:, :, d_idx, t_idx, e_idx, f_idx] = regrid_data return
def ferret_compute(efid, result, result_bdf, inputs, input_bdfs): ''' Performs the regridding for the curv3srect function. Arguments: result - rectilinear data values to be assigned result_bdf - missing-data value for result inputs - (CurvData, CurvLons, CurvLats, CurvBaths, CurvZetas, TemplateRectVar, Method) input_bdfs - missing-data values for the corresponding inputs array ''' # Get the regridding method to use methodstr = pyferret.get_arg_one_val(efid, pyferret.ARG7).upper() if methodstr == "BILINEAR": method = ESMP.ESMP_REGRIDMETHOD_BILINEAR elif methodstr == "PATCH": method = ESMP.ESMP_REGRIDMETHOD_PATCH else: raise ValueError("Unknown method %s (CONSERVE not supported)" % methodstr) # Get the template data and missing value template_data = inputs[pyferret.ARG6] template_undef = input_bdfs[pyferret.ARG6] # Get the rectilinear center longitudes, latitudes, and depths rect_center_lons = pyferret.get_axis_coordinates(efid, pyferret.ARG6, pyferret.X_AXIS) rect_center_lats = pyferret.get_axis_coordinates(efid, pyferret.ARG6, pyferret.Y_AXIS) rect_center_depths = pyferret.get_axis_coordinates(efid, pyferret.ARG6, pyferret.Z_AXIS) # Get the rectilinear corner longitudes lo, hi = pyferret.get_axis_box_limits(efid, pyferret.ARG6, pyferret.X_AXIS) if not numpy.allclose(lo[1:], hi[:-1]): raise ValueError("Unexpected ARG6 X_AXIS box limit values " \ "returned from pyferret.get_axis_box_limits") rect_corner_lons = numpy.empty((lo.shape[0] + 1), dtype=numpy.float64) rect_corner_lons[0] = lo[0] rect_corner_lons[1:] = hi # Get the rectilinear corner latitudes lo, hi = pyferret.get_axis_box_limits(efid, pyferret.ARG6, pyferret.Y_AXIS) if not numpy.allclose(lo[1:], hi[:-1]): raise ValueError("Unexpected ARG6 Y_AXIS box limit values " \ "returned from pyferret.get_axis_box_limits") rect_corner_lats = numpy.empty((lo.shape[0] + 1), dtype=numpy.float64) rect_corner_lats[0] = lo[0] rect_corner_lats[1:] = hi # Get the rectilinear corner depths lo, hi = pyferret.get_axis_box_limits(efid, pyferret.ARG6, pyferret.Z_AXIS) if not numpy.allclose(lo[1:], hi[:-1]): raise ValueError("Unexpected ARG6 Z_AXIS box limit values " \ "returned from pyferret.get_axis_box_limits") rect_corner_depths = numpy.empty((lo.shape[0] + 1), dtype=numpy.float64) rect_corner_depths[0] = lo[0] rect_corner_depths[1:] = hi # Get the curvilinear data curv_data = inputs[pyferret.ARG1] if curv_data.shape[3:] != template_data.shape[3:]: raise ValueError("Curvilinear data and template variable " \ "must have same T, E, and F axes") curv_undef = input_bdfs[pyferret.ARG1] # Get the curvilinear centers arrays - squeeze removes the singleton axes curv_center_lons = inputs[pyferret.ARG2].squeeze() curv_center_lats = inputs[pyferret.ARG3].squeeze() curv_center_baths = inputs[pyferret.ARG4].squeeze() curv_centers_shape = curv_data.shape[:2] if (curv_center_lons.shape != curv_centers_shape) or \ (curv_center_lats.shape != curv_centers_shape) or \ (curv_center_baths.shape != curv_centers_shape): raise ValueError("Curvilinear data, longitude, latitudes, and " \ "and bathymetry must have same X and Y axes") # Squeeze should remove a singleton Z axis in zetas curv_center_zetas = inputs[pyferret.ARG5].squeeze() # If only one time step, squeeze would have also removed it. # So if no time axis, put one in. if len(curv_center_zetas.shape) == 2: curv_center_zetas = curv_center_zetas[:, :, numpy.newaxis] # Allow zeta to be omitted by giving a single-point array if curv_center_zetas.shape == (): curv_center_zetas = None elif curv_center_zetas.shape != (curv_data.shape[0], curv_data.shape[1], curv_data.shape[3]): raise ValueError("Curvilinear data and zetas " \ "must have same X, Y, and T axes") # Get the sigma values from the Z axis of curv_data curv_center_sigmas = pyferret.get_axis_coordinates(efid, pyferret.ARG1, pyferret.Z_AXIS) curv_centers_shape = curv_data.shape[:3] # Expand the sigmas to 3D (adding X and Y axes) to simplify # calculation of curvilinear depths curv_center_sigmas = numpy.repeat(curv_center_sigmas, curv_centers_shape[0] * \ curv_centers_shape[1]) \ .reshape(curv_centers_shape, order='F') # Expand the curvilinear longitude, latitude, and bathymetry # arrays to 3D (adding Z axis) curv_center_lons = numpy.tile(curv_center_lons.flatten('F'), curv_centers_shape[2]) \ .reshape(curv_centers_shape, order='F') curv_center_lats = numpy.tile(curv_center_lats.flatten('F'), curv_centers_shape[2]) \ .reshape(curv_centers_shape, order='F') curv_center_baths = numpy.tile(curv_center_baths.flatten('F'), curv_centers_shape[2]) \ .reshape(curv_centers_shape, order='F') # Make sure ESMP is, or has been, initialized regrid.ESMPControl().startCheckESMP() # Create the regridder used repeatedly in this function regridder3d = regrid.CurvRect3DRegridder() last_rect_center_ignore = None if curv_center_zetas == None: # Create the curvilinear depths array curv_center_depths = curv_center_sigmas * curv_center_baths last_curv_center_ignore = None # Increment the time index last since zeta is time dependent for t_idx in range(curv_data.shape[3]): if curv_center_zetas != None: # Expand the zetas for this time step to 3D - adding Z axis zetas = numpy.tile(curv_center_zetas[:,:,t_idx].flatten('F'), curv_centers_shape[2]) \ .reshape(curv_centers_shape, order='F') # Create the curvilinear depths array curv_center_depths = curv_center_sigmas * (curv_center_baths + \ zetas) - zetas # Different curvilinear depths, so need to recreate the curvilinear grid last_curv_center_ignore = None # Arrays are probably in Fortran order, so increment last indices last for f_idx in range(curv_data.shape[5]): for e_idx in range(curv_data.shape[4]): # Determine curvilinear center points to ignore from undefined data curv_center_ignore = ( numpy.abs(curv_data[:, :, :, t_idx, e_idx, f_idx] - curv_undef) < 1.0E-7) # If mask has changed, need to recreate the curvilinear grid if (last_curv_center_ignore is None) or \ numpy.any(curv_center_ignore != last_curv_center_ignore): regridder3d.createCurvGrid(curv_center_lons, curv_center_lats, curv_center_depths, curv_center_ignore, True, None, None, None, None) last_curv_center_ignore = curv_center_ignore # Determine rectilinear center points to ignore from undefined data rect_center_ignore = ( numpy.abs(template_data[:, :, :, t_idx, e_idx, f_idx] - template_undef) < 1.0E-7) # If mask has changed, need to recreate the rectilinear grid if (last_rect_center_ignore is None) or \ numpy.any(rect_center_ignore != last_rect_center_ignore): regridder3d.createRectGrid( rect_center_lons, rect_center_lats, rect_center_depths, rect_center_ignore, True, rect_corner_lons, rect_corner_lats, rect_corner_depths, None) last_rect_center_ignore = rect_center_ignore # Assign the curvilinear data regridder3d.assignCurvField(curv_data[:, :, :, t_idx, e_idx, f_idx]) # Allocate space for the rectilinear data from the regridding regridder3d.assignRectField(None) # Regrid and assign the rectilinear data to the results array regrid_data = regridder3d.regridCurvToRect(result_bdf, method) result[:, :, :, t_idx, e_idx, f_idx] = regrid_data return