示例#1
0
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
示例#2
0
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
示例#3
0
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