Esempio n. 1
0
    def setValidMask(self, inMask):
        """
        Set valid mask array for the grid

        Parameters
        ----------

           inMask
              flat numpy array of type numpy.int32 or a valid cdms2 variable with its mask set.
                 0 - invalid, 1 - valid data

            _: None

        Note:  This must be invoked before computing the weights, the mask is a property of the grid (not the data).
        """
        if self.weightsComputed:
            raise RegridError('Must set mask before computing weights')

        mask = numpy.array(inMask, dtype=numpy.int32)

        # extend src data if grid was made cyclic and or had a cut accounted
        # for
        newMask = self._extend(mask)
        c_intmask = newMask.ctypes.data_as(POINTER(c_int))
        status = self.lib.nccf_set_grid_validmask(self.src_gridid, c_intmask)
        catchError(status, sys._getframe().f_lineno)
        self.maskSet = True
Esempio n. 2
0
def makeCurvilinear(coords):
    """
    Turn a mixture of axes and curvilinear coordinates into
    full curvilinear coordinates

    Parameters
    ----------

       coords
          list of coordinates
       _: None

    Returns
    -------

       new list of coordinates and associated dimensions
    """
    rank = len(coords)

    count1DAxes = 0
    dims = []
    for i in range(rank):
        coord = coords[i]
        if len(coord.shape) == 1:
            # axis
            dims.append(len(coord))
            count1DAxes += 1
        elif len(coord.shape) == rank:
            # fully curvilinear
            dims.append(coord.shape[i])
        else:
            # assumption: all 1D axes preceed curvilinear
            # coordinates!!!
            dims.append(coord.shape[i - count1DAxes])

    for i in range(rank):
        nd = len(coords[i].shape)
        if nd == rank:
            # already in curvilinear form, keep as is
            pass
        elif nd == 1:
            # it's an axis
            coords[i] = getTensorProduct(coords[i][:], i, dims)
        elif rank == 3 and nd == 2 and i > 0:
            # assume leading coordinate is an axis
            o1 = numpy.ones((len(coords[0]), ), coords[i].dtype)
            coords[i] = numpy.ma.outer(o1, coords[i]).reshape(dims)
        else:
            raise RegridError(
                "ERROR in %s: funky mixture of axes and curvilinear coords %s"
                % (__FILE__, str([x.shape for x in coords])))
    return coords, dims
Esempio n. 3
0
    def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER):
        """
        Creator for structured ESMF Field
        @param esmfGrid instance of an ESMF
        @param name field name (must be unique)
        @param datatype data type, one of 'float64', 'float32', 'int64', or 'int32'
                        (or equivalent numpy dtype)
        @param staggerloc ESMF.StaggerLoc.CENTER
                          ESMF.StaggerLoc.CORNER
        """
        # field object
        self.field = None
        # the local processor rank
        self.pe = 0
        # the number of processors
        self.nprocs = 1
        # associated grid
        self.grid = esmfGrid
        # staggering
        self.staggerloc = staggerloc
        # communicator
        self.comm = None

        try:
            from mpi4py import MPI
            self.comm = MPI.COMM_WORLD
        except BaseException:
            pass

        etype = None
        sdatatype = str(datatype)  # in case user passes a numpy dtype
        if re.search('float64', sdatatype):
            etype = R8
        elif re.search('float32', sdatatype):
            etype = R4
        elif re.search('int64', sdatatype):
            etype = I8
        elif re.search('int32', sdatatype):
            etype = I4
        else:
            msg = 'esmf.EsmfStructField.__init__: ERROR invalid type %s' % datatype
            raise RegridError(msg)

        self.field = ESMF.Field(grid=esmfGrid.grid,
                                name=name,
                                typekind=etype,
                                staggerloc=staggerloc)
        vm = ESMF.ESMP_VMGetGlobal()
        self.pe, self.nprocs = ESMF.ESMP_VMGet(vm)
Esempio n. 4
0
    def __init__(self, esmfGrid, name, datatype, staggerloc=CENTER):
        """

        """
        # field object
        self.field = None
        # the local processor rank
        self.pe = 0
        # the number of processors
        self.nprocs = 1
        # associated grid
        self.grid = esmfGrid
        # staggering
        self.staggerloc = staggerloc
        # communicator
        self.comm = None

        try:
            from mpi4py import MPI
            self.comm = MPI.COMM_WORLD
        except BaseException:
            pass

        etype = None
        sdatatype = str(datatype)  # in case user passes a numpy dtype
        if re.search('float64', sdatatype):
            etype = R8
        elif re.search('float32', sdatatype):
            etype = R4
        elif re.search('int64', sdatatype):
            etype = I8
        elif re.search('int32', sdatatype):
            etype = I4
        else:
            msg = 'esmf.EsmfStructField.__init__: ERROR invalid type %s' % datatype
            raise RegridError(msg)

        self.field = ESMF.Field(grid=esmfGrid.grid,
                                name=name,
                                typekind=etype,
                                staggerloc=staggerloc)
        vm = ESMF.ESMP_VMGetGlobal()
        self.pe, self.nprocs = ESMF.ESMP_VMGet(vm)
Esempio n. 5
0
    def apply(self, src_data_in, dst_data, missingValue=None):
        """
        Apply interpolation
        @param src_data data on source grid
        @param dst_data data on destination grid
        @param missingValue value that should be set for points falling outside the src domain,
                            pass None if these should not be touched.
        """
        if not self.weightsComputed:
            raise RegridError('Weights must be set before applying the regrid')
        # extend src data if grid was made cyclic and or had a cut accounted
        # for
        src_data = self._extend(src_data_in)

        # Check
        if reduce(
                operator.iand,
            [src_data.shape[i] == self.src_dims[i]
             for i in range(self.rank)]) == False:  # noqa
            raise RegridError(
                ("ERROR in %s: supplied src_data have wrong shape " +
                 "%s != %s") % (__FILE__, str(
                     src_data.shape), str(tuple([d for d in self.src_dims]))))
        if reduce(
                operator.iand,
            [dst_data.shape[i] == self.dst_dims[i]
             for i in range(self.rank)]) == False:  # noqa
            raise RegridError(
                ("ERROR in %s: supplied dst_data have wrong shape " +
                 "%s != %s") % (__FILE__, str(
                     dst_data.shape), str(tuple([d for d in self.dst_dims]))))

        # Create temporary data objects
        src_dataid = c_int(-1)
        dst_dataid = c_int(-1)
        save = 0
        standard_name = ""
        units = ""
        time_dimname = ""

        status = self.lib.nccf_def_data(self.src_gridid, "src_data",
                                        standard_name, units, time_dimname,
                                        byref(src_dataid))
        catchError(status, sys._getframe().f_lineno)

        if src_data.dtype != dst_data.dtype:
            try:  # try recasting
                warnings.warn(
                    "mismatch in src and dst data types (%s vs %s) we recasted src to dst"
                    % (src_data.dtype, dst_data.dtype))
                src_data = src_data.astype(dst_data.dtype)
            except BaseException:
                try:
                    warnings.warn(
                        "mismatch in src and dst data types (%s vs %s) we recasted dst to src"
                        % (src_data.dtype, dst_data.dtype))
                    dst_data = dst_data.astype(src_data.dtype)
                except BaseException:
                    raise RegridError(
                        "ERROR in %s: mismatch in src and dst data types (%s vs %s)"
                        % (__FILE__, src_data.dtype, dst_data.dtype))

        # only float64 and float32 data types are supported for interpolation
        if src_data.dtype == numpy.float64:
            fill_value = c_double(libCFConfig.NC_FILL_DOUBLE)
            if missingValue is not None:
                fill_value = c_double(missingValue)
            ptr = src_data.ctypes.data_as(POINTER(c_double))
            status = self.lib.nccf_set_data_double(src_dataid, ptr, save,
                                                   fill_value)
            catchError(status, sys._getframe().f_lineno)
        elif src_data.dtype == numpy.float32:
            fill_value = c_float(libCFConfig.NC_FILL_FLOAT)
            if missingValue is not None:
                fill_value = c_float(missingValue)
            ptr = src_data.ctypes.data_as(POINTER(c_float))
            status = self.lib.nccf_set_data_float(src_dataid, ptr, save,
                                                  fill_value)
            catchError(status, sys._getframe().f_lineno)
        else:
            raise RegridError(
                "ERROR in %s: invalid src_data type %s (neither float nor double)"
                % (__FILE__, src_data.dtype))

        status = self.lib.nccf_def_data(self.dst_gridid, "dst_data",
                                        standard_name, units, time_dimname,
                                        byref(dst_dataid))
        catchError(status, sys._getframe().f_lineno)
        if dst_data.dtype == numpy.float64:
            fill_value = c_double(libCFConfig.NC_FILL_DOUBLE)
            if missingValue is not None:
                fill_value = c_double(missingValue)
                dst_data[:] = missingValue
            ptr = dst_data.ctypes.data_as(POINTER(c_double))
            status = self.lib.nccf_set_data_double(dst_dataid, ptr, save,
                                                   fill_value)
            catchError(status, sys._getframe().f_lineno)
        elif dst_data.dtype == numpy.float32:
            fill_value = c_float(libCFConfig.NC_FILL_FLOAT)
            if missingValue is not None:
                fill_value = c_float(missingValue)
                dst_data[:] = missingValue
            ptr = dst_data.ctypes.data_as(POINTER(c_float))
            status = self.lib.nccf_set_data_float(dst_dataid, ptr, save,
                                                  fill_value)
            catchError(status, sys._getframe().f_lineno)
        else:
            raise RegridError("ERROR in %s: invalid dst_data type = %s" %
                              (__FILE__, dst_data.dtype))

        # Now apply weights
        status = self.lib.nccf_apply_regrid(self.regridid, src_dataid,
                                            dst_dataid)
        catchError(status, sys._getframe().f_lineno)

        # Clean up
        status = self.lib.nccf_free_data(src_dataid)
        catchError(status, sys._getframe().f_lineno)
        status = self.lib.nccf_free_data(dst_dataid)
        catchError(status, sys._getframe().f_lineno)

        return dst_data
Esempio n. 6
0
def catchError(status, lineno):
    if status != 0:
        raise RegridError("ERROR in %s: status = %d at line %d" %
                          (__FILE__, status, lineno))
Esempio n. 7
0
    def __init__(self,
                 src_grid,
                 dst_grid,
                 src_bounds=None,
                 mkCyclic=False,
                 handleCut=False,
                 verbose=False):
        """
        Constructor

        @param src_grid source grid, a list of [x, y, ...] coordinates
                        or a cdms2.grid.Transient
        @param dst_grid destination grid, a list of [x, y, ...] coordinates
        @param src_bounds list of cell bounding coordinates (to be used when
                          handling a cut in coordinates)
        @param mkCyclic Add a column to the right side of the grid to complete
               a cyclic grid
        @param handleCut Add a row to the top of grid to handle a cut for
               grids such as the tri-polar grid
        @param verbose print diagnostic messages
        @note the grid coordinates can either be axes (rectilinear grid) or
              n-dimensional for curvilinear grids. Rectilinear grids will
              be converted to curvilinear grids.
        """
        self.regridid = c_int(-1)
        self.src_gridid = c_int(-1)
        self.dst_gridid = c_int(-1)
        self.rank = 0
        self.src_dims = []
        self.dst_dims = []
        self.src_coords = []
        self.dst_coords = []
        self.lib = None
        self.extendedGrid = False
        self.handleCut = False
        self.dst_Index = []
        self.verbose = verbose
        self.weightsComputed = False
        self.maskSet = False

        # Open the shaped library
        dynLibFound = False
        for sosuffix in '.dylib', '.dll', '.DLL', '.so', '.a':
            if os.path.exists(LIBCFDIR + sosuffix):
                dynLibFound = True
        CFfile = self.find('pylibcf.*', __path__[0])
        if os.path.exists(CFfile):
            try:
                self.lib = CDLL(CFfile)
            except BaseException:
                pass
#        for sosuffix in '.dylib', '.dll', '.DLL', '.so', '.a':
#            if os.path.exists(LIBCFDIR + sosuffix):
#                dynLibFound = True
#                try:
#                    self.lib = CDLL(LIBCFDIR + sosuffix)
#                    break
#                except:
#                    pass
        if self.lib is None:
            if not dynLibFound:
                raise RegridError(
                    "ERROR in %s: could not find shared library %s.{so,dylib,dll,DLL}"
                    % (__FILE__, LIBCFDIR))
            raise RegridError(
                "ERROR in %s: could not open shared library %s.{so,dylib,dll,DLL}"
                % (__FILE__, LIBCFDIR))

        # Number of space dimensions
        self.rank = len(src_grid)

        if len(dst_grid) != self.rank:
            raise RegridError("ERROR in %s: len(dst_grid) = %d != %d" %
                              (__FILE__, len(dst_grid), self.rank))

        if self.rank <= 0:
            raise RegridError(
                "ERROR in %s: must have at least one dimension, rank = %d" %
                (__FILE__, self.rank))

        # Convert src_grid/dst_grid to curvilinear grid, if need be
        if self.rank > 1:
            src_grid, src_dims = makeCurvilinear(src_grid)
            dst_grid, dst_dims = makeCurvilinear(dst_grid)

        # Make sure coordinates wrap around if mkCyclic is True
        if mkCyclic:
            src_gridNew, src_dimsNew = makeCoordsCyclic(src_grid, src_dims)
            if self.verbose:
                aa, bb = str(src_dims), str(src_dimsNew)
                print(
                    ('...  src_dims = %s, after making cyclic src_dimsNew = %s'
                     % (aa, bb)))
                for i in range(self.rank):
                    print(('...... src_gridNew[%d].shape = %s' %
                           (i, str(src_gridNew[i].shape))))
            # flag indicating that the grid was extended
            if reduce(lambda x, y: x + y,
                      [src_dimsNew[i] - src_dims[i]
                       for i in range(self.rank)]) > 0:
                self.extendedGrid = True
            # reset
            src_grid = src_gridNew
            src_dims = src_dimsNew

        # Handle a cut in the coordinate system. Run after mkCyclic.
        # e.g. a tri-polar grid
        if handleCut and src_bounds is not None:
            # Test for the presence of a cut.
            isCut = checkForCoordCut(src_grid, src_dims)
            if isCut:
                # No cut
                src_gridNew, src_dimsNew, dst_Index = handleCoordsCut(
                    src_grid, src_dims, src_bounds)
                if dst_Index is not None:
                    self.handleCut = True
                    self.extendedGrid = self.extendedGrid
                else:
                    self.handleCut = False
                    self.extendedGrid = self.extendedGrid
                if self.verbose:
                    aa, bb = str(src_dims), str(src_dimsNew)
                    print((
                        '...  src_dims = %s, after making cyclic src_dimsNew = %s'
                        % (aa, bb)))
                src_grid = src_gridNew
                src_dims = src_dimsNew
                self.dst_Index = dst_Index

        self.src_dims = (c_int * self.rank)()
        self.dst_dims = (c_int * self.rank)()

        # Build coordinate objects
        src_dimnames = (c_wchar_p * self.rank)()
        dst_dimnames = (c_wchar_p * self.rank)()
        for i in range(self.rank):
            src_dimnames[i] = 'src_n%d' % i
            dst_dimnames[i] = 'dst_n%d' % i
            self.src_dims[i] = src_dims[i]
            self.dst_dims[i] = dst_dims[i]
        self.src_coordids = (c_int * self.rank)()
        self.dst_coordids = (c_int * self.rank)()
        save = 0
        standard_name = ""
        units = ""
        coordid = c_int(-1)
        for i in range(self.rank):
            data = numpy.array(src_grid[i], numpy.float64)
            self.src_coords.append(data)
            dataPtr = data.ctypes.data_as(C_DOUBLE_P)
            name = "src_coord%d" % i
            # assume [lev,] lat, lon ordering
            if i == self.rank - 2:
                standard_name = 'latitude'
                units = 'degrees_north'
            elif i == self.rank - 1:
                standard_name = 'longitude'
                units = 'degrees_east'
            status = self.lib.nccf_def_coord(self.rank, self.src_dims,
                                             src_dimnames, dataPtr, save, name,
                                             standard_name, units,
                                             byref(coordid))
            catchError(status, sys._getframe().f_lineno)
            self.src_coordids[i] = coordid

            data = numpy.array(dst_grid[i], numpy.float64)
            self.dst_coords.append(data)
            dataPtr = data.ctypes.data_as(C_DOUBLE_P)
            name = "dst_coord%d" % i
            status = self.lib.nccf_def_coord(self.rank, self.dst_dims,
                                             dst_dimnames, dataPtr, save, name,
                                             standard_name, units,
                                             byref(coordid))
            catchError(status, sys._getframe().f_lineno)
            self.dst_coordids[i] = coordid

        # Build grid objects
        status = self.lib.nccf_def_grid(self.src_coordids, "src_grid",
                                        byref(self.src_gridid))
        catchError(status, sys._getframe().f_lineno)

        status = self.lib.nccf_def_grid(self.dst_coordids, "dst_grid",
                                        byref(self.dst_gridid))
        catchError(status, sys._getframe().f_lineno)

        # Create regrid object
        status = self.lib.nccf_def_regrid(self.src_gridid, self.dst_gridid,
                                          byref(self.regridid))
        catchError(status, sys._getframe().f_lineno)
Esempio n. 8
0
    def __init__(self,
                 shape,
                 coordSys=ESMF.CoordSys.SPH_DEG,
                 periodicity=0,
                 staggerloc=ESMF.StaggerLoc.CENTER,
                 hasBounds=False):
        """
        Constructor
        @param shape  Tuple of cell sizes along each axis
        @param coordSys    coordinate system
                           ESMF.CoordSys.CART              Cartesian
                           ESMF.CoordSys.SPH_DEG (default) Degrees
                           ESMF.CoordSys.SPH_RAD           Radians
        @param periodicity Does the grid have a periodic coordinate
                           0 No periodicity
                           1 Periodic in x (1st) axis
                           2 Periodic in x, y axes
        @param staggerloc ESMF stagger location. ESMF.StaggerLoc.XXXX
                          The stagger constants are listed at the top
        @param hasBounds If the grid has bounds, Run AddCoords for the bounds
        """
        # ESMF grid object
        self.grid = None
        # number of cells in [z,] y, x on all processors
        self.shape = shape
        # number of dimensions
        self.ndims = len(self.shape)
        # whether or not cell areas were set
        self.cellAreasSet = False
        # whether or not nodal coords were set
        self.nodesSet = False
        # whether or not cell centered coordinates were set
        self.centersSet = False

        maxIndex = numpy.array(shape, dtype=numpy.int32)

        # assume last 2 dimensions are Y,X
        self.centersSet = False
        periodic_dim = self.ndims - 1
        pole_dim = self.ndims - 2
        if periodicity == 0:
            self.grid = ESMF.Grid(max_index=maxIndex,
                                  num_peri_dims=0,
                                  staggerloc=[staggerloc],
                                  coord_sys=coordSys)
        elif periodicity == 1:
            self.grid = ESMF.Grid(max_index=maxIndex,
                                  num_peri_dims=1,
                                  periodic_dim=periodic_dim,
                                  pole_dim=pole_dim,
                                  staggerloc=[staggerloc],
                                  coord_sys=coordSys)
        else:
            msg = """
esmf.EsmfStructGrid.__init__: ERROR periodic dimensions %d > 1 not permitted.
            """ % periodicity
            raise RegridError(msg)

        # Grid add coordinates call must go here for parallel runs
        # This occur before the fields are created, making the fields
        # parallel aware.
        if ((staggerloc == CENTER) and (not self.centersSet)):
            self.centersSet = True
        elif (staggerloc == CORNER) and (not self.nodesSet):
            self.nodesSet = True

        if hasBounds is not None:
            if self.ndims == 2:
                self.grid.add_coords([CORNER], coord_dim=None, from_file=False)
            if self.ndims == 3:
                self.grid.add_coords([VCORNER],
                                     coord_dim=None,
                                     from_file=False)
Esempio n. 9
0
    def __init__(self,
                 shape,
                 coordSys=ESMF.CoordSys.SPH_DEG,
                 periodicity=0,
                 staggerloc=ESMF.StaggerLoc.CENTER,
                 hasBounds=False):
        """

        """
        # ESMF grid object
        self.grid = None
        # number of cells in [z,] y, x on all processors
        self.shape = shape[::-1]
        # number of dimensions
        self.ndims = len(self.shape)
        # whether or not cell areas were set
        self.cellAreasSet = False
        # whether or not nodal coords were set
        self.nodesSet = False
        # whether or not cell centered coordinates were set
        self.centersSet = False

        # assume last 2 dimensions are Y,X
        # For esmf reverse to X, Y
        maxIndex = numpy.array(shape[::-1], dtype=numpy.int32)

        self.centersSet = False
        periodic_dim = 0
        pole_dim = 1
        if periodicity == 0:
            self.grid = ESMF.Grid(max_index=maxIndex,
                                  num_peri_dims=0,
                                  staggerloc=[staggerloc],
                                  coord_sys=coordSys)
        elif periodicity == 1:
            self.grid = ESMF.Grid(max_index=maxIndex,
                                  num_peri_dims=1,
                                  periodic_dim=periodic_dim,
                                  pole_dim=pole_dim,
                                  staggerloc=[staggerloc],
                                  coord_sys=coordSys)
        else:
            msg = """
esmf.EsmfStructGrid.__init__: ERROR periodic dimensions %d > 1 not permitted.
            """ % periodicity
            raise RegridError(msg)

        # Grid add coordinates call must go here for parallel runs
        # This occur before the fields are created, making the fields
        # parallel aware.
        if ((staggerloc == CENTER) and (not self.centersSet)):
            self.centersSet = True
        elif (staggerloc == CORNER) and (not self.nodesSet):
            self.nodesSet = True

        if hasBounds is not None:
            if self.ndims == 2:
                self.grid.add_coords([CORNER], coord_dim=None, from_file=False)
            if self.ndims == 3:
                self.grid.add_coords([VCORNER],
                                     coord_dim=None,
                                     from_file=False)