Source code for cdms2.gengrid

# Automatically adapted for numpy.oldnumeric Aug 01, 2007 by
# Further modified to be pure new numpy June 24th 2008

"""CDMS Generic Grids"""

import numpy
# import PropertiedClasses
from . import bindex
from .error import CDMSError
from .grid import LongitudeType, LatitudeType, CoordTypeToLoc
from .hgrid import AbstractHorizontalGrid
from .axis import allclose

MethodNotImplemented = "Method not yet implemented"


[docs]class AbstractGenericGrid(AbstractHorizontalGrid): def __init__(self, latAxis, lonAxis, id=None, maskvar=None, tempmask=None, node=None): """Create a generic grid. """ if latAxis.shape != lonAxis.shape: raise CDMSError( 'Latitude and longitude axes must have the same shape.') AbstractHorizontalGrid.__init__( self, latAxis, lonAxis, id, maskvar, tempmask, node) self._index_ = None
[docs] def clone(self, copyData=1): newlat = self._lataxis_.clone(copyData) newlon = self._lonaxis_.clone(copyData) return TransientGenericGrid(newlat, newlon, id=self.id)
# def __repr__(self): # return "<GenericGrid, id: %s, shape: %s>"%(self.id, `self.shape`) # __str__ = __repr__
[docs] def getMesh(self, transpose=None): """Generate a mesh array for the meshfill graphics method. Parameters ---------- 'transpose' : is for compatibility with other grid types, is ignored. """ from . import MV2 as MV if self._mesh_ is None: LAT = 0 LON = 1 latbounds, lonbounds = self.getBounds() if latbounds is None or lonbounds is None: raise CDMSError( 'No boundary data is available for grid %s' % self.id) nvert = latbounds.shape[-1] mesh = numpy.zeros((self.size(), 2, nvert), latbounds.dtype.char) mesh[:, LAT, :] = MV.filled(latbounds) mesh[:, LON, :] = MV.filled(lonbounds) self._mesh_ = mesh return self._mesh_
def _getShape(self): return self._lataxis_.shape # Get the n-th index axis. naxis is 0 or 1.
[docs] def getAxis(self, naxis): return self._lataxis_.getAxis(naxis)
# Don't try to generate bounds for generic grids
[docs] def genBounds(self): return (None, None)
[docs] def getMask(self): """Get the mask array, if any, otherwise None is returned.""" if self._maskVar_ is None: return None else: return self._maskVar_[:]
[docs] def size(self): return self._lataxis_.size()
[docs] def writeScrip(self, cufile, gridTitle=None): """Write a grid to a SCRIP file. Parameters ---------- cufile : is a Cdunif file, NOT a CDMS file. gridtitle : is a string identifying the grid. """ lat = numpy.ma.filled(self._lataxis_) lon = numpy.ma.filled(self._lonaxis_) blat, blon = self.getBounds() ngrid, ncorners = blat.shape mask = self.getMask() if mask is None: mask = numpy.ones((ngrid,), numpy.int32) else: mask[:] = 1 - mask mask = mask.astype(numpy.int32) # Write the file if gridTitle is None: gridTitle = self.id cufile.title = gridTitle cufile.createDimension("grid_size", ngrid) cufile.createDimension("grid_corners", ncorners) cufile.createDimension("grid_rank", 1) griddims = cufile.createVariable( "grid_dims", numpy.int, ("grid_rank",)) gridcenterlat = cufile.createVariable( "grid_center_lat", numpy.float, ("grid_size",)) gridcenterlat.units = "degrees" gridcenterlon = cufile.createVariable( "grid_center_lon", numpy.float, ("grid_size",)) gridcenterlon.units = "degrees" gridimask = cufile.createVariable( "grid_imask", numpy.int, ("grid_size",)) gridimask.units = "unitless" gridcornerlat = cufile.createVariable( "grid_corner_lat", numpy.float, ("grid_size", "grid_corners")) gridcornerlat.units = "degrees" gridcornerlon = cufile.createVariable( "grid_corner_lon", numpy.float, ("grid_size", "grid_corners")) gridcornerlon.units = "degrees" griddims[:] = numpy.array([ngrid], numpy.int32) gridcenterlat[:] = lat gridcenterlon[:] = lon gridimask[:] = mask gridcornerlat[:] = numpy.ma.filled(blat) gridcornerlon[:] = numpy.ma.filled(blon)
[docs] def writeToFile(self, file): latvar = self._lataxis_.writeToFile(file) lonvar = self._lonaxis_.writeToFile(file) if self._maskVar_ is not None: maskid = "mask_" + self.id file.write(self._maskVar_, id=maskid) latvar.maskid = maskid lonvar.maskid = maskid return (latvar, lonvar)
[docs] def subSlice(self, *specs, **keys): """Get a transient subgrid based on an argument list <specs> of slices.""" newlat = self._lataxis_.subSlice(*specs, **keys) newlon = self._lonaxis_.subSlice(*specs, **keys) if self._maskVar_ is None: newmask = None else: newmask = self._maskVar_.subSlice(*specs, **keys) result = TransientGenericGrid(newlat, newlon, maskvar=newmask) return result
[docs] def getGridSlices(self, domainlist, newaxislist, slicelist): """Determine which slices in slicelist correspond to the lat/lon elements of the grid. Parameters --------- domainlist : is a list of axes of a variable. newaxislist : is a list of result axes after the slicelist is applied to domainlist. slicelist : is a list of slices. All lists are of equal length. Return value : is (newslicelist, gridaxislist) where newslicelist : is the elements of slicelist that correspond to the grid, in the preferred order of the grid. gridaxislist : is the elements of newaxislist that correspond to the grid, in the preferred order of the grid. """ iaxis = self._lataxis_.getAxis(0) k = 0 i = -1 for d in domainlist: if d is iaxis: inewaxis = newaxislist[k] islice = slicelist[k] i = k k += 1 if i == -1: raise RuntimeError( 'Grid lat/lon domains do not match variable domain') return ((islice, ), (inewaxis, ))
[docs] def getIndex(self): """Get the grid index""" if self._index_ is None: latlin = numpy.ma.filled(self._lataxis_) lonlin = numpy.ma.filled(self._lonaxis_) self._index_ = bindex.bindexHorizontalGrid(latlin, lonlin) return self._index_
[docs] def intersect(self, spec): """Intersect with the region specification. Parameters ---------- 'spec' : region specification of the form defined in the grid module. Returns ------- (mask, indexspecs) where'mask' is the mask of the result grid AFTER self and region spec are interested. 'indexspecs' is a dictionary of index specifications suitable for slicing a variable with the given grid. """ ncell = self.shape index = self.getIndex() latspec = spec[CoordTypeToLoc[LatitudeType]] lonspec = spec[CoordTypeToLoc[LongitudeType]] latlin = numpy.ma.filled(self._lataxis_) lonlin = numpy.ma.filled(self._lonaxis_) lonlin = numpy.ma.where( numpy.ma.greater_equal( lonlin, 360.0), lonlin - 360.0, lonlin) points = bindex.intersectHorizontalGrid( latspec, lonspec, latlin, lonlin, index) if len(points) == 0: raise CDMSError( 'No data in the specified region, longitude=%s, latitude=%s' % (repr(lonspec), repr(latspec))) fullmask = numpy.ones(ncell) numpy.put(fullmask, points, 0) imin, imax = (min(points), max(points) + 1) submask = fullmask[imin:imax] cellid = self.getAxis(0).id indexspecs = {cellid: slice(imin, imax)} return submask, indexspecs
[docs] def getAxisList(self): return [self._lataxis_.getAxis(0), ]
[docs] def isClose(self, g): """ Is Close Returns ------- 1 iff g is a grid of the same type and shape. Notes ----- A real element-by-element comparison would be too expensive here.""" if g is None: return 0 elif self.shape != g.shape: return 0 elif not isinstance(g, AbstractGenericGrid): return 0 else: return 1
[docs] def checkAxes(self, axes): """ Check Axes Returns ------- 1 iff every element of self.getAxisList() is in the list 'axes'.""" for item in self.getAxisList(): if item not in axes: result = 0 break else: result = 1 return result
[docs] def reconcile(self, axes): """ Reconcile Returns ------- a grid that is consistent with the axes, or None. Notes ----- For curvilinear grids this means that the grid-related axes are contained in the 'axes' list. """ result = self selfaxes = self.getAxisList() missing = [] for i in range(1): if selfaxes[i] not in axes: missing.append(i) result = None # Some of the grid axes are not in the 'axes' list if result is None: result = self.clone() for i in missing: for item in axes: if (len(selfaxes[i]) == len(item)) and \ allclose(selfaxes[i], item): result._lataxis_.setAxis(i, item) result._lonaxis_.setAxis(i, item) break else: result = None break return result
[docs] def flatAxes(self): """ Flat Axes Returns ------- (flatlat, flatlon) where flatlat is a 1D NumPy array Notes ----- having the same length as the number of cells in the grid, similarly for flatlon.""" if self._flataxes_ is None: from . import MV2 as MV alat = MV.filled(self.getLatitude()) alon = MV.filled(self.getLongitude()) self._flataxes_ = (alat, alon) return self._flataxes_
[docs] def toGenericGrid(self, gridid=None): if gridid is None: gridid = self.id result = self.clone() result.id = gridid return result
shape = property(_getShape, None)
# PropertiedClasses.set_property (AbstractGenericGrid, 'shape', # AbstractGenericGrid._getShape, nowrite=1, # nodelete=1)
[docs]class DatasetGenericGrid(AbstractGenericGrid): def __init__(self, latAxis, lonAxis, id, parent=None, maskvar=None, tempmask=None, node=None): """Create a file curvilinear grid. """ AbstractGenericGrid.__init__( self, latAxis, lonAxis, id, maskvar, tempmask, node) self.parent = parent def __repr__(self): return "<DatasetGenericGrid, id: %s, shape: %s>" % ( self.id, repr(self.shape))
[docs]class FileGenericGrid(AbstractGenericGrid): def __init__(self, latAxis, lonAxis, id, parent=None, maskvar=None, tempmask=None, node=None): """Create a file curvilinear grid. """ AbstractGenericGrid.__init__( self, latAxis, lonAxis, id, maskvar, tempmask, node) self.parent = parent def __repr__(self): return "<FileGenericGrid, id: %s, shape: %s>" % ( self.id, repr(self.shape))
[docs]class TransientGenericGrid(AbstractGenericGrid): grid_count = 0 def __init__(self, latAxis, lonAxis, id=None, maskvar=None, tempmask=None): """Create a file curvilinear grid. """ if id is None: TransientGenericGrid.grid_count += 1 id = 'grid_' + str(TransientGenericGrid.grid_count) AbstractGenericGrid.__init__( self, latAxis, lonAxis, id, maskvar, tempmask) def __repr__(self): return "<TransientGenericGrid, id: %s, shape: %s>" % ( self.id, repr(self.shape))
[docs] def toGenericGrid(self, gridid=None): if gridid is None: result = self else: result = self.clone() result.id = gridid return result
[docs]def readScripGenericGrid(fileobj, dims, whichType, whichGrid): """Read a 'native' SCRIP grid file, returning a transient generic grid. Parameters ---------- fileobj : is an open CDMS dataset or file object. dims : is the grid shape. whichType : is the type of file, either "grid" or "mapping" Notes ----- if whichType is "mapping", whichGrid is the choice of grid, either "source" or "destination" """ from .auxcoord import TransientAuxAxis1D from .coord import TransientVirtualAxis convention = 'SCRIP' if 'S' in list(fileobj.variables.keys()): convention = 'NCAR' if whichType == "grid": gridCornerLatName = 'grid_corner_lat' gridCornerLonName = 'grid_corner_lon' gridMaskName = 'grid_imask' gridCenterLatName = 'grid_center_lat' gridCenterLonName = 'grid_center_lon' titleName = 'title' elif whichGrid == "destination": gridCornerLatName = 'yv_b' gridCornerLonName = 'xv_b' gridMaskName = 'mask_b' gridCenterLatName = 'yc_b' gridCenterLonName = 'xc_b' titleName = 'dest_grid' else: gridCornerLatName = 'yv_a' gridCornerLonName = 'xv_a' gridMaskName = 'mask_a' gridCenterLatName = 'yc_a' gridCenterLonName = 'xc_a' titleName = 'source_grid' else: if whichType == "grid": gridCornerLatName = 'grid_corner_lat' gridCornerLonName = 'grid_corner_lon' gridMaskName = 'grid_imask' gridCenterLatName = 'grid_center_lat' gridCenterLonName = 'grid_center_lon' titleName = 'title' elif whichGrid == "destination": gridCornerLatName = 'dst_grid_corner_lat' gridCornerLonName = 'dst_grid_corner_lon' gridMaskName = 'dst_grid_imask' gridCenterLatName = 'dst_grid_center_lat' gridCenterLonName = 'dst_grid_center_lon' titleName = 'dest_grid' else: gridCornerLatName = 'src_grid_corner_lat' gridCornerLonName = 'src_grid_corner_lon' gridMaskName = 'src_grid_imask' gridCenterLatName = 'src_grid_center_lat' gridCenterLonName = 'src_grid_center_lon' titleName = 'source_grid' vardict = fileobj.variables cornerLat = fileobj(gridCornerLatName) cornerLon = fileobj(gridCornerLonName) ncorners = cornerLat.shape[-1] if convention == 'NCAR': ni = cornerLat.shape[0] else: ni = dims[0] boundsshape = (ni, ncorners) if hasattr(cornerLat, 'units') and cornerLat.units[0:6].lower() == 'radian': cornerLat = (cornerLat * (180.0 / numpy.pi)).reshape(boundsshape) cornerLon = (cornerLon * (180.0 / numpy.pi)).reshape(boundsshape) iaxis = TransientVirtualAxis("i", ni) if gridMaskName in vardict: # SCRIP convention: 0 for invalid data # numpy.ma convention: 1 for invalid data mask = 1 - fileobj(gridMaskName) else: mask = None if gridCenterLatName in vardict: centerLat = fileobj(gridCenterLatName) if hasattr(centerLat, "units") and centerLat.units.lower() == 'radians': centerLat *= (180.0 / numpy.pi) else: centerLat = cornerLat[:, :, 0] if gridCenterLonName in vardict: centerLon = fileobj(gridCenterLonName) if hasattr(centerLon, "units") and centerLon.units.lower() == 'radians': centerLon *= (180.0 / numpy.pi) else: centerLon = cornerLon[:, :, 0] if hasattr(fileobj, titleName): gridid = getattr(fileobj, titleName) gridid = gridid.strip().replace(' ', '_') else: gridid = "<None>" lataxis = TransientAuxAxis1D(centerLat, axes=(iaxis,), bounds=cornerLat, attributes={'units': 'degrees_north'}, id="latitude") lonaxis = TransientAuxAxis1D(centerLon, axes=(iaxis,), bounds=cornerLon, attributes={'units': 'degrees_east'}, id="longitude") grid = TransientGenericGrid(lataxis, lonaxis, id=gridid, tempmask=mask) return grid