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
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
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)
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)
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
def catchError(status, lineno): if status != 0: raise RegridError("ERROR in %s: status = %d at line %d" % (__FILE__, status, lineno))
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)
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)
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)