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
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, resbdf, inputs, inpbdfs): """ Create the shapefile named in inputs[0] using the values array given in inputs[1]. The bounding box limits of the X and Y axes of inputs[1] are used to create the quadrilaterals. The values in inputs[1] are used as the values associated with each shape using the field name given in inputs[2]. Either a common name or a WKT description of the map projection for the coordinated should be given in inputs[3]. If blank, WGS 84 is used. If successful, fills result (which might as well be a 1x1x1x1 array) with zeros. If a problem occurs, an error will be raised. """ shapefile_name = inputs[0] values = inputs[1] missing_value = inpbdfs[1] field_name = inputs[2].strip() if not field_name: field_name = "VALUE" map_projection = inputs[3] # Verify the shapes are as expected if (values.shape[3] != 1) or (values.shape[4] != 1) or (values.shape[5] != 1): raise ValueError("The T, E, and F axes of VALUE must be undefined or singleton axes") # Get the X axis box limits for the quadrilateral coordinates x_box_limits = pyferret.get_axis_box_limits(efid, pyferret.ARG2, pyferret.X_AXIS) if x_box_limits == None: raise ValueError("Unable to determine the X axis box limits") lowerxs = x_box_limits[0] upperxs = x_box_limits[1] # Get the Y axis box limits for the quadrilateral coordinates y_box_limits = pyferret.get_axis_box_limits(efid, pyferret.ARG2, pyferret.Y_AXIS) if y_box_limits == None: raise ValueError("Unable to determine the y axis box limits") lowerys = y_box_limits[0] upperys = y_box_limits[1] # Get the elevation/depth coordinates, or None if they do not exist z_coords = pyferret.get_axis_coordinates(efid, pyferret.ARG2, pyferret.Z_AXIS) # Create polygons with a single field value if z_coords == None: sfwriter = shapefile.Writer(shapefile.POLYGON) else: sfwriter = shapefile.Writer(shapefile.POLYGONZ) sfwriter.field(field_name, "N", 20, 7) # Write out the shapes and the records shape_written = False if z_coords == None: for j in range(len(lowerys)): for i in range(len(lowerxs)): if values[i, j, 0, 0, 0, 0] != missing_value: pyferret.fershp.addquadxyvalues(sfwriter, ( lowerxs[i], lowerys[j] ), ( lowerxs[i], upperys[j] ), ( upperxs[i], upperys[j] ), ( upperxs[i], lowerys[j] ), None, [ float(values[i, j, 0, 0, 0, 0]) ]) shape_written = True else: for k in range(len(z_coords)): for j in range(len(lowerys)): for i in range(len(lowerxs)): if values[i, j, k, 0, 0, 0] != missing_value: pyferret.fershp.addquadxyvalues(sfwriter, ( lowerxs[i], lowerys[j] ), ( lowerxs[i], upperys[j] ), ( upperxs[i], upperys[j] ), ( upperxs[i], lowerys[j] ), z_coords[k], [ float(values[i, j, k, 0, 0, 0]) ]) shape_written = True if not shape_written: raise ValueError("All values are missing values") sfwriter.save(shapefile_name) # Create the .prj file from the map projection common name or the WKT description pyferret.fershp.createprjfile(map_projection, shapefile_name) result[:, :, :, :, :, :] = 0