def set_grid_type(var, gtype): """Set an attribute so that var is identified as being on the specified Arakawa grid type. If var is a :mod:`cdms2` variable or grid, it sets the :attr:`_vacumm_arakawa_grid_type` attribute, else it sets the :attr:`arakawa_grid_type` attribute. :Params: - **var**: A :mod:`cdms2` variable or grid, a :class:`~vacumm.data.misc.dataset.Dataset` instance. - **gtype**: None or one of the :attr:`grid_type` letters. """ if gtype is not None: gtype = str(gtype).upper() if cdms2.isVariable(var) or cdms2.isGrid(var): vv = [var] if cdms2.isVariable(var): grid = var.getGrid() if grid is not None: vv.append(grid) for v in vv: _set_clean_atts_(v, _cdms2_atts, gtype) else: _set_clean_atts_(var, _other_atts, gtype) return gtype
def __init__(self, u, v, rsphere=6.3712e6): """Initialize a VectorWind instance. **Arguments:** *u*, *v* Zonal and meridional components of the vector wind respectively. Both components should be `cdms2` variables. The components must have the same shape and contain no missing values. **Example:** Initialize a `VectorWind` instance with zonal and meridional components of the vector wind:: from windspharm.cdms import VectorWind w = VectorWind(u, v) """ # Ensure the input are cdms2 variables. if not (cdms2.isVariable(u) and cdms2.isVariable(v)): raise TypeError("u and v must be cdms2 variables") # Check that both u and v have dimensions in the same order and that # there are latitude and longitude dimensions present. uorder = u.getOrder() vorder = v.getOrder() if uorder != vorder: raise ValueError("u and v must have the same dimension order") for order in (uorder, vorder): if "x" not in order or "y" not in order: raise ValueError("a latitude-longitude grid is required") self.order = uorder # Assess how to re-order the inputs to be compatible with the # computation API. apiorder = "yx" + "".join([a for a in order if a not in "xy"]) # Order the dimensions correctly. u = u.reorder(apiorder) v = v.reorder(apiorder) # Do a region selection on the inputs to ensure the latitude dimension # is north-to-south. u = u(latitude=(90, -90)) v = v(latitude=(90, -90)) # Determine the grid type, lon = u.getLongitude() lat = u.getLatitude() if lon is None or lat is None: raise ValueError("a latitude-longitude grid is required") gridtype = self._gridtype(lat) # Store the shape and axes when data is in the API order. self.ishape = u.shape self.axes = u.getAxisList() # Re-shape to 3-dimensional (compatible with API) u = u.reshape(u.shape[:2] + (np.prod(u.shape[2:]),)) v = v.reshape(v.shape[:2] + (np.prod(v.shape[2:]),)) # Instantiate a VectorWind object to do the computations. self.api = standard.VectorWind(u, v, gridtype=gridtype, rsphere=rsphere)
def __init__(self, u, v): """Initialize a VectorWind instance. **Arguments:** *u*, *v* Zonal and meridional components of the vector wind respectively. Both components should be `cdms2` variables. The components must have the same shape and contain no missing values. **Example:** Initialize a `VectorWind` instance with zonal and meridional components of the vector wind:: from windspharm.cdms import VectorWind w = VectorWind(u, v) """ # Ensure the input are cdms2 variables. if not (cdms2.isVariable(u) and cdms2.isVariable(v)): raise TypeError('u and v must be cdms2 variables') # Check that both u and v have dimensions in the same order and that # there are latitude and longitude dimensions present. uorder = u.getOrder() vorder = v.getOrder() if uorder != vorder: raise ValueError('u and v must have the same dimension order') for order in (uorder, vorder): if 'x' not in order or 'y' not in order: raise ValueError('a latitude-longitude grid is required') self.order = uorder # Assess how to re-order the inputs to be compatible with the # computation API. apiorder = 'yx' + ''.join([a for a in order if a not in 'xy']) # Order the dimensions correctly. u = u.reorder(apiorder) v = v.reorder(apiorder) # Do a region selection on the inputs to ensure the latitude dimension # is north-to-south. u = u(latitude=(90, -90)) v = v(latitude=(90, -90)) # Determine the grid type, lon = u.getLongitude() lat = u.getLatitude() if lon is None or lat is None: raise ValueError('a latitude-longitude grid is required') gridtype = self._gridtype(lat) # Store the shape and axes when data is in the API order. self.ishape = u.shape self.axes = u.getAxisList() # Re-shape to 3-dimensional (compatible with API) u = u.reshape(u.shape[:2] + (np.prod(u.shape[2:]),)) v = v.reshape(v.shape[:2] + (np.prod(v.shape[2:]),)) # Instantiate a VectorWind object to do the computations. self.api = standard.VectorWind(u, v, gridtype=gridtype)
def _val2z_(var, dep, varref, axis, monosign): """Compute depth for a given reference data value""" # Inits with Z axis first var = var.asma() if cdms2.isVariable(var) else N.ma.asarray(var) var = var.copy() dep = dep.asma() if cdms2.isVariable(dep) else N.ma.asarray(dep) dep = N.ma.masked_where(var.mask, dep, copy=False) varref = varref.asma() if cdms2.isVariable(varref) else N.ma.asarray( varref) if var.ndim - 1 == 0: var = var.reshape(-1, 1) dep = dep.reshape(-1, 1) varref = varref.reshape(1) axis = 0 rvar = N.rollaxis(var, axis) if axis else var rdep = N.rollaxis(dep, axis) if axis else dep rdepref = rdep[0].copy() rvar = rvar.copy() nz = rvar.shape[0] # nb of elements along the first axis (z in general) maskland = N.ma.getmaskarray(rvar)[-1] # Monotonic rvar *= monosign varref *= monosign dvar = N.ma.diff(rvar, axis=0) # Find z index dvarref = rvar - varref iiz0 = N.arange(nz - 1, dtype='i') iiz0 = N.ma.resize(iiz0, rvar.shape[rvar.ndim - 1:0:-1] + (nz - 1, )).T iiz0 = N.ma.masked_where(N.ma.diff(N.sign(dvarref), axis=0) < 2, iiz0, copy=0) iz0 = iiz0.max(axis=0) del iiz0 maskdz = iz0.mask iz0 = iz0.filled(0.) # Interpolation dvar0 = N_choose(iz0, dvar) dvar0[maskdz] = 1. w1 = -N_choose(iz0, dvarref) / dvar0 w1.set_fill_value(0.) rdep.set_fill_value(0.) rdepref = N_choose(iz0 + 1, rdep) * w1 rdepref += N_choose(iz0, rdep) * (1 - w1) # Masking rdepref[maskland] = N.ma.masked rdepref = N.ma.where(~maskland & maskdz, rdep.min(axis=0), rdepref) return rdepref
def _val2z_(var, dep, varref, axis, monosign): """Compute depth for a given reference data value""" # Inits with Z axis first var = var.asma() if cdms2.isVariable(var) else N.ma.asarray(var) var = var.copy() dep = dep.asma() if cdms2.isVariable(dep) else N.ma.asarray(dep) dep = N.ma.masked_where(var.mask, dep, copy=False) varref = varref.asma() if cdms2.isVariable(varref) else N.ma.asarray(varref) if var.ndim-1==0: var = var.reshape(-1,1) dep = dep.reshape(-1,1) varref = varref.reshape(1) axis = 0 rvar = N.rollaxis(var, axis) if axis else var rdep = N.rollaxis(dep, axis) if axis else dep rdepref = rdep[0].copy() rvar = rvar.copy() nz = rvar.shape[0] # nb of elements along the first axis (z in general) maskland = N.ma.getmaskarray(rvar)[-1] # Monotonic rvar *= monosign varref *= monosign dvar = N.ma.diff(rvar, axis=0) # Find z index dvarref = rvar-varref iiz0 = N.arange(nz-1, dtype='i') iiz0 = N.ma.resize(iiz0, rvar.shape[rvar.ndim-1:0:-1]+(nz-1, )).T iiz0 = N.ma.masked_where(N.ma.diff(N.sign(dvarref), axis=0)<2, iiz0, copy=0) iz0 = iiz0.max(axis=0) del iiz0 maskdz = iz0.mask iz0 = iz0.filled(0.) # Interpolation dvar0 = N_choose(iz0, dvar) dvar0[maskdz] = 1. w1 = -N_choose(iz0, dvarref)/dvar0 w1.set_fill_value(0.) rdep.set_fill_value(0.) rdepref = N_choose(iz0+1, rdep)*w1 rdepref += N_choose(iz0, rdep)*(1-w1) # Masking rdepref[maskland] = N.ma.masked rdepref = N.ma.where(~maskland&maskdz, rdep.min(axis=0), rdepref) return rdepref
def coriolis_parameter(lat, gravity=default_gravity, fromvar=False, format_axes=False): """Get the coriolis parameters computed at each latitude :Params: - **lat**: Latitude or a variable with latitude coordinates. - **gravity**, optional: Gravity. - **fromvar**, optional: If True, lat is supposed to be a MV2 array with latitude coordinates. """ # Latitude if fromvar: if not cdms2.isVariable(lat): raise VACUMMError('lat must a MV2 array because fromvar is True') latv = lat * 0 lat = lat.getLatitude() if lat is None: raise VACUMMError( 'lat must a MV2 array with a latitude axis because fromvar is True' ) if cdms2.isVariable(lat): lat = lat.asma() # 2D axes if lat.shape != latv.shape: if len(lat.shape) == 2: latv[:] = N.ma.resize(lat, latv.shape) else: yaxis = latv.getOrder().index('y') new_shape = len(latv.shape) * [1] new_shape[yaxis] = latv.shape[yaxis] tile_shape = list(latv.shape) tile_shape[yaxis] = 1 latv[:] = N.tile(lat[:].reshape(new_shape), tile_shape) else: latv = lat if not N.ndim(lat) else lat[:] # Compute f0 = 2 * N.ma.sin(N.pi * latv / 180.) # f0 *= 2*N.pi/(24.*3600.) f0 *= 2 * N.pi / (86164.) # 86164 = sidereal day.... # Format if N.isscalar(f0): return f0 f0 = MV2.asarray(f0) if not fromvar and isaxis(lat) and f0.ndim == 1: f0.setAxis(0, lat) return format_var(f0, 'corio', format_axes=format_axes)
def get_grid_type(var): """Guess the Arakawa grid type It search for the following attributes: :attr:`arakawa_grid_type`, :attr:`grid_type` and :attr:`_vacumm_arakawa_grid_type`. :Params: - **var**: A :mod:`cdms2` variable or grid, an :class:`ArakawaGrid` instance or a :class:`~vacumm.data.misc.dataset.Dataset` instance. If var is a :mod:`cdms2` variable, it also check its grid if defined. :Return: An Arakawa grid upper-base letter, like 'C' """ vv = [var] if cdms2.isVariable(var): grid = var.getGrid() if grid is not None: vv.append(grid) for v in vv: for att in _cdms2_atts + _other_atts: if hasattr(v, att): gt = getattr(a, att) if gt is None: return return str(gt).upper()
def generateLandSeaMask(target, source=None, threshold_1=.2, threshold_2=.3, regridTool='regrid2'): """ Generates a best guess mask on any rectilinear grid, using the method described in PCMDI's report #58 see: http://www-pcmdi.llnl.gov/publications/ab58.html Input: target: either a MV2 object with a grid, or a cdms2 grid (rectilinear grid only) source: A fractional (0 to 1.) land sea mask, where 1 means all land threshold_1 (optional): criteria 1 for detecting cells with possible increment see report for detail difference threshold threshold_2 (optional): criteria 2 for detecting cells with possible increment see report for detail water/land content threshold regridTool: which cdms2 regridder tool to use, default is regrid2 Output: landsea maks on target grid """ cdat_info.pingPCMDIdb("cdat", "cdutil.generateLandSeaMask") if cdms2.isVariable(target): target = target.getGrid() if target is None: raise Exception, "Error target data passed do not have a grid" if not isinstance(target, cdms2.grid.TransientRectGrid): raise Exception, "Error: target grid must be rectilinear" if source is None: source = cdms2.open( os.path.join(sys.prefix, 'share', 'cdutil', 'navy_land.nc'))('sftlf') try: navy_frac_t = source.regrid(target, regridTool='regrid2') except Exception, err: raise "error, cannot regrid source data to target, got error message: %s" % err
def generateLandSeaMask(target,source=None,threshold_1 = .2, threshold_2 = .3,regridTool='regrid2'): """ Generates a best guess mask on any rectilinear grid, using the method described in PCMDI's report #58 see: http://www-pcmdi.llnl.gov/publications/ab58.html Input: target: either a MV2 object with a grid, or a cdms2 grid (rectilinear grid only) source: A fractional (0 to 1.) land sea mask, where 1 means all land threshold_1 (optional): criteria 1 for detecting cells with possible increment see report for detail difference threshold threshold_2 (optional): criteria 2 for detecting cells with possible increment see report for detail water/land content threshold regridTool: which cdms2 regridder tool to use, default is regrid2 Output: landsea maks on target grid """ cdat_info.pingPCMDIdb("cdat","cdutil.generateLandSeaMask") if cdms2.isVariable(target): target = target.getGrid() if target is None: raise Exception,"Error target data passed do not have a grid" if not isinstance(target,cdms2.grid.TransientRectGrid): raise Exception, "Error: target grid must be rectilinear" if source is None: source = cdms2.open(os.path.join(sys.prefix,'share','cdutil','navy_land.nc'))('sftlf') try: navy_frac_t = source.regrid(target,regridTool='regrid2') except Exception,err: raise "error, cannot regrid source data to target, got error message: %s" % err
def create_axis(values, atype='-', **atts): """Quickly create a :mod:`cdms2` axis :Params: - **values**: Numerical values. - **atype**, optional: axis type within 'x','y','z','t','-' [default: '-'] - Other keywords are passed as attributes to the axis. :Example: >>> lon = create_axis(N.arange(-10., 0, 2), 'x') >>> lon = create_axis((-10., 0, 2), 't', id='temps', units='seconds since 2000') >>> """ from vacumm.misc import cp_atts if N.isscalar(values): values = [values] if isinstance(values, tuple) and len(values) < 4: values = N.arange(*values, **{'dtype': 'd'}) if cdms2.isVariable(values): for item in values.attributes.items(): atts.setdefault(*item) values = values.asma() if not isaxis(values): axis = cdms2.createAxis(values) else: axis = values for att, val in atts.items(): setattr(axis, att, val) axis.axis = atype.upper() check_axis(axis) if axis.axis == '-': del axis.axis return axis
def split_varname(varname): """Split a variable name in three parts (physical, depth, others) The separator is the underscore sign. Examples -------- >>> print split_varname('temp_surf_std_dev') ('temp', 'surf', 'std_dev') >>> print split_varname('temp_variance') ('temp', None, 'variance') >>> print split_varname('temp') ('temp', None, 'None') """ if cdms2.isVariable(varname): varname = varname.id svname = varname.split('_') physical = svname[0] depth = others = None if len(svname)>1: if svname[1] in ['surf', 'bottom']: depth = svname[1] svname = svname[2:] if depth=='3d': depth = None else: svname = svname[1:] if svname: others = '_'.join(svname) return physical, depth, others
def __call__(self, input): import numpy.ma from cdms2 import isVariable from cdms2.tvariable import TransientVariable # If input is a variable, make it a TV if isVariable(input) and not isinstance(input, TransientVariable): input = input.subSlice() isvar = isinstance(input, TransientVariable) if isvar: domain = tuple(input.getAxisList()) if self.inputGrid is not None: ingrid = self.inputGrid else: ingrid = input.getGrid() if ingrid is None: raise RegridError, "Input variable must have an associated grid." rank = len(ingrid.shape) gridsize = ingrid.size() outgridshape = self.outputGrid.shape # Check that the grid matches the last dimension(s) of input if input.shape[-rank:] != ingrid.shape: raise RegridError, 'Last dimensions of input array must match grid shape: %s'%`ingrid.shape` #this expects contiguous arrays if input.iscontiguous() is False: input = input.ascontiguous() else: rank = 1 # If not a TV, last dimension is the 'cell' dimension gridsize = input.shape[-1] outgridshape = (reduce(lambda x,y: x*y, self.outputGrid.shape, 1),) # If input is an numpy.ma, make it Numeric if numpy.ma.isMaskedArray(input): input = input.filled() restoreShape = input.shape[:-rank] restoreLen = reduce(lambda x,y: x*y, restoreShape, 1) oldshape = input.shape newshape = (restoreLen, gridsize) input.shape = newshape # Regrid output = self.regrid(input) # Reshape output and restore input shape input.shape = oldshape outshape = restoreShape + outgridshape output.shape = outshape # If the input was a variable, so is the output if isvar: outdomain = domain[:-rank]+(self.outputGrid,) output = TransientVariable(output, axes=outdomain) return output
def recursive_transform_att(data, att, func, *args, **kwargs): """Strip ids of a recursive lists of arrays""" if not isinstance(data, list): if cdms2.isVariable(data) and hasattr(data, att): setattr(data, att, func(getattr(data, att), *args, **kwargs)) return data return [recursive_transform_att(dat, att, func, *args, **kwargs) for dat in data]
def get_grid_type(var): """Guess the Arakawa grid type It search for the following attributes: :attr:`arakawa_grid_type`, :attr:`grid_type` and :attr:`_vacumm_arakawa_grid_type`. :Params: - **var**: A :mod:`cdms2` variable or grid, an :class:`ArakawaGrid` instance or a :class:`~vacumm.data.misc.dataset.Dataset` instance. If var is a :mod:`cdms2` variable, it also check its grid if defined. :Return: An Arakawa grid upper-base letter, like 'C' """ vv = [var] if cdms2.isVariable(var): grid = var.getGrid() if grid is not None: vv.append(grid) for v in vv: for att in _cdms2_atts+_other_atts: if hasattr(v, att): gt = getattr(a, att) if gt is None: return return str(gt).upper()
def return_defined_data_list(): tv = __main__.__dict__ trash_str = gui_defined_variables.trash_str data_list = [] for x in tv.keys(): # if ( ( isinstance( tv[x] , numpy.ndarray) ) or ( cdms2.isVariable( tv[x] ) ) or # ( MV2.isMA( tv[x] ) ) ): if ( cdms2.isVariable( tv[x] ) ): str_var = x + ' (' for i in range(len(tv[x].shape)): s ="%d" % tv[x].shape[i] str_var = str_var + s + ', ' if len (tv[x]) > 0: str_var = str_var[0:len(str_var)-2] str_var = str_var + ')' a = string.split( str_var, ' ')[0] if a[-len(trash_str):] != trash_str: if str_var[-2:] == '()': str_var = str_var + (' = %.17g' % tv[ x ]) data_list.append( str_var ) data_list.sort() return data_list
def create_axis(values, atype='-', **atts): """Quickly create a :mod:`cdms2` axis :Params: - **values**: Numerical values. - **atype**, optional: axis type within 'x','y','z','t','-' [default: '-'] - Other keywords are passed as attributes to the axis. :Example: >>> lon = create_axis(N.arange(-10., 0, 2), 'x') >>> lon = create_axis((-10., 0, 2), 't', id='temps', units='seconds since 2000') >>> """ from vacumm.misc import cp_atts if isinstance(values, tuple) and len(values) < 4: values = N.arange(*values, **{'dtype':'d'}) if cdms2.isVariable(values): for item in values.attributes.items(): atts.setdefault(*item) values = values.asma() if not isaxis(values): axis = cdms2.createAxis(values) else: axis = values for att,val in atts.items(): setattr(axis, att, val) axis.axis = atype.upper() check_axis(axis) if axis.axis == '-': del axis.axis return axis
def return_defined_data_list(): tv = __main__.__dict__ trash_str = gui_defined_variables.trash_str data_list = [] for x in tv.keys(): # if ( ( isinstance( tv[x] , numpy.ndarray) ) or ( cdms2.isVariable( tv[x] ) ) or # ( MV2.isMA( tv[x] ) ) ): if (cdms2.isVariable(tv[x])): str_var = x + ' (' for i in range(len(tv[x].shape)): s = "%d" % tv[x].shape[i] str_var = str_var + s + ', ' if len(tv[x]) > 0: str_var = str_var[0:len(str_var) - 2] str_var = str_var + ')' a = string.split(str_var, ' ')[0] if a[-len(trash_str):] != trash_str: if str_var[-2:] == '()': str_var = str_var + (' = %.17g' % tv[x]) data_list.append(str_var) data_list.sort() return data_list
def kinetic_energy(sshuv, gravity=default_gravity, format_axes=None, dxy=None): """Compute kinetic energy in m2.s-2 either from SSH or velocity on C-grid .. todo:: Rewrite it using :mod:`vacumm.data.misc.arakawa` and defining a limited number of algorithms for different staggering configurations. :Params: - **sshuv**: SSH or (U,V). - If SSH, geostrophic velocity is computed at U and V points using :func:`barotropic_geostrophic_velocity`. - If (U,V), velocities are supposed to be at V and U points. - **dxy**, optional: Horizontal resolutions (see :func:`barotropic_geostrophic_velocity`). :Return: KE at T points. """ # Init and get velocities if cdms2.isVariable(sshuv): # from SSH ke = sshuv*MV2.masked u, v = barotropic_geostrophic_velocity(sshuv, dxy=dxy, gravity=gravity, format_axes=format_axes) if format_axes is None: format_axes = False else: # from (U,V) u, v = sshuv ke = u*MV2.masked if format_axes is None: format_axes = True gridt = shiftgrid(u.getGrid(), jshift=1) set_grid(ke, gridt) # Sum contributions uf = u.filled(0.) vf = v.filled(0.) ke[..., 1:, :] = uf[..., 1:, :]**2 ke[..., 1:, :] += uf[..., :-1, :]**2 ke[..., 1:] += vf[..., :-1]**2 ke[..., 1:] += vf[..., :-1]**2 # Weight and mask count = N.zeros(ke.shape, 'i') gu = 1-N.ma.getmaskarray(u).astype('i') gv = 1-N.ma.getmaskarray(v).astype('i') count[1:] = gu[:-1] count[1:] += gu[1:] count[:, 1:] += gv[:, :-1] count[:, 1:] += gv[:, 1:] del gu, gv mask = count==0 count[mask] = 1 ke[:] /= count ke[:] = MV2.masked_where(mask, ke, copy=0) del mask, count # Format if format_axes: format_grid(gridt, 't') return format_var(ke, "ke", format_axes=False)
def coriolis_parameter(lat, gravity=default_gravity, fromvar=False, format_axes=False): """Get the coriolis parameters computed at each latitude :Params: - **lat**: Latitude or a variable with latitude coordinates. - **gravity**, optional: Gravity. - **fromvar**, optional: If True, lat is supposed to be a MV2 array with latitude coordinates. """ # Latitude if fromvar: if not cdms2.isVariable(lat): raise VACUMMError('lat must a MV2 array because fromvar is True') latv = lat*0 lat = lat.getLatitude() if lat is None: raise VACUMMError('lat must a MV2 array with a latitude axis because fromvar is True') if cdms2.isVariable(lat): lat=lat.asma() # 2D axes if lat.shape!=latv.shape: if len(lat.shape)==2: latv[:] = N.ma.resize(lat, latv.shape) else: yaxis = latv.getOrder().index('y') new_shape = len(latv.shape)*[1] new_shape[yaxis] = latv.shape[yaxis] tile_shape = list(latv.shape) tile_shape[yaxis] = 1 latv[:] = N.tile(lat[:].reshape(new_shape), tile_shape) else: latv = lat if N.isscalar(lat) else lat[:] # Compute f0 = 2*N.ma.sin(N.pi*latv/180.) # f0 *= 2*N.pi/(24.*3600.) f0 *= 2*N.pi/(86164.) # 86164 = sidereal day.... # Format if N.isscalar(f0): return f0 f0 = MV2.asarray(f0) if not fromvar and isaxis(lat) and f0.ndim==1: f0.setAxis(0, lat) return format_var(f0, 'corio', format_axes=format_axes)
def format_grid(grid, pt, **kwargs): """Format a grid and its axes""" if cdms2.isVariable(grid): grid = grid.getGrid() if grid is None: return gs = GRID_SPECS[pt] lon = grid.getLongitude() lat = grid.getLatitude() format_axis(lon, gs['lon'], **kwargs) format_axis(lat, gs['lat'], **kwargs)
def format_grid(grid, pt, **kwargs): """Format a grid and its axes""" if cdms2.isVariable(grid): grid = grid.getGrid() if grid is None: return gs = GRID_SPECS[pt] lon = grid.getLongitude() lat = grid.getLatitude() format_axis(lon, gs['lon']) format_axis(lat, gs['lat'])
def _get_from_name_(self, name, selector=None, lons=None, lats=None, times=None): """Load axis or variable from its generic name .. note:: Tests against generic names are case insensitives. They are search for in :attr:`names`. :Return: None is not found, else a MV2 array """ # Inits ncname = self._get_ncname_(name) if ncname is None: return selector = as_selector(selector) # Axis var = ncread_axis(self.f, ncname, mode=None) if var is not None: # Selector atype = axis_type(var, genname=True)[:3] for sname, sel in list(split_selector(selector)[1].items()): if sname==var.id or (atype is not None and atype==sname[:3]): if not isinstance(sel, slice): ijk = var.mapIntervalExt(sel) else: ijk = sel.indices(len(var)) var = var.subaxis(*ijk) return var # Variable Variables = list(self.f.variables.keys()) variables = list(map(string.lower, Variables)) if ncname.lower() in variables: ncname = Variables[variables.index(ncname.lower())] not_scalar = self.f[ncname].shape args = [ncname] if selector and not_scalar: args.append(selector) kwargs = {'mode':None} var = ncread_var(self.f, *args, **kwargs) if var is None: return if not_scalar and hasattr(self.f[ncname], '_FillValue') and cdms2.isVariable(var): var[:] = MV2.masked_values(var, self.f[ncname]._FillValue, copy=0) # Transect if not_scalar and lons is not None and lats is not None: var = grid2xy(var, xo=lons, yo=lons, to=times, outaxis=False) return var # Attribute Attributes = list(self.f.attributes.keys()) attributes = list(map(string.lower, Attributes)) if ncname.lower() in attributes: ncname = Attributes[attributes.index(ncname.lower())] return self.f.attributes.get(ncname, None)
def asma(*args): """Return pure numpy or numpy.ma arrays""" if not args: return # single = len(args)==1 out = [] for arg in args: if cdms2.isVariable(arg): arg = arg.asma() out.append(arg) if len(args)==1: return out[0] return out
def xycompress(valid, vari, **atts): """Keep valid spatial points Parameters ---------- valid: 1D or 2D bool array 2D array for data on structured grid vari: array The variable to compress """ # Slice for extra dimensions pslice = (slice(None), ) * (vari.ndim - valid.ndim) if cdms2.isVariable(vari): nv = valid.sum() if valid.ndim==2: # Init assert valid.ndim == 2, 'Valid must be a 2D array' varo = vari[pslice + (0, slice(0, nv))].clone() ax = create_axis((nv, ), id='point', long_name='Spatial points') varo.setAxis(-1, ax) varo.setGrid(None) # Fill varo[:] = vari.asma()[pslice + (valid, )] else: # Init ax = vari.getAxis(-1) varo = vari[pslice + (slice(0, nv), )].clone() # Fill varo.getAxis(-1)[:] = N.compress(valid, ax[:]) varo[:] = N.ma.compress(valid, vari.asma(), axis=-1) # Attributes set_atts(varo, **atts) else: # numpy or ma varo = vari[pslice + (valid, )] return varo
def _valmin2z_(var, dep, varmax, axis, monosign): """Compute depth at which data value at lower than a reference value""" # Inits with Z axis first var = var.asma() if cdms2.isVariable(var) else N.ma.asarray(var) var = var.copy() dep = dep.asma() if cdms2.isVariable(dep) else N.ma.asarray(dep) if var.ndim-1==0: var = var.reshape(-1,1) dep = dep.reshape(-1,1) axis = 0 rvar = N.rollaxis(var, axis) if axis else var rdep = N.rollaxis(dep, axis) if axis else dep rvar = rvar.copy() nz = rvar.shape[0] maskland = N.ma.getmaskarray(rvar)[-1] # Monotonic (greater at surface) rvar *= monosign # Find z index iiz = N.arange(nz, dtype='i') iiz = N.ma.resize(iiz, rvar.shape[rvar.ndim-1:0:-1]+(nz, )).T iiz = N.ma.masked_where(rvar>varmax, iiz, copy=0) iz0 = iiz.max(axis=0) del iiz maskz = iz0.mask iz0 = iz0.filled(0.) # Values rdepref = N_choose(iz0, rdep) # Masking rdepref[maskland] = N.ma.masked rdepref = N.ma.where(~maskland&maskz, rdep.min(axis=0), rdepref) return rdepref
def _valmin2z_(var, dep, varmax, axis, monosign): """Compute depth at which data value at lower than a reference value""" # Inits with Z axis first var = var.asma() if cdms2.isVariable(var) else N.ma.asarray(var) var = var.copy() dep = dep.asma() if cdms2.isVariable(dep) else N.ma.asarray(dep) if var.ndim - 1 == 0: var = var.reshape(-1, 1) dep = dep.reshape(-1, 1) axis = 0 rvar = N.rollaxis(var, axis) if axis else var rdep = N.rollaxis(dep, axis) if axis else dep rvar = rvar.copy() nz = rvar.shape[0] maskland = N.ma.getmaskarray(rvar)[-1] # Monotonic (greater at surface) rvar *= monosign # Find z index iiz = N.arange(nz, dtype='i') iiz = N.ma.resize(iiz, rvar.shape[rvar.ndim - 1:0:-1] + (nz, )).T iiz = N.ma.masked_where(rvar > varmax, iiz, copy=0) iz0 = iiz.max(axis=0) del iiz maskz = iz0.mask iz0 = iz0.filled(0.) # Values rdepref = N_choose(iz0, rdep) # Masking rdepref[maskland] = N.ma.masked rdepref = N.ma.where(~maskland & maskz, rdep.min(axis=0), rdepref) return rdepref
def set(Array,Indices,Values,axis=0): """ Arrayrrayindexing set Array[Indices] with Values, indices are taken along dimension given with axis Usage: Array=set(Array,Indices,Values,axis=0) # i.e. Array[Indices]=Values Indices accepts negative value ,e.g: -1 is last element """ ## if numpy.rank(Indices)==0: ## Array[Indices]=Values ## First some checks #isma=numpy.ma.isMA(Array) if Indices.dtype not in [numpy.int,numpy.int32,numpy.int16]: raise "Error indices array must be made of integers (try: Indices=Indices.astype('l') first)" if cdms2.isVariable(Array) : xatt=Array.attributes id=Array.id if len(Array.shape)!=len(Indices.shape): crap,Indices,crap,axis,ax=statistics.__checker(Array,Indices,None,axis,smally=1) Array,Values,crap,axis,ax=statistics.__checker(Array,Values,None,axis,smally=1) if Indices.shape!=Array.shape[1:]: raise "Error uncompatible shapes: "+str(Array.shape)+" and "+str(Indices.shape) else: Array,Indices,Values,axis,ax=statistics.__checker(Array,Indices,Values,axis) if Indices.shape!=Array.shape: raise "Error uncompatible shapes: "+str(Array.shape)+" and "+str(Indices.shape) m=numpy.ma.getmask(Array) mv=numpy.ma.getmask(Values) if numpy.rank(Indices)>0: Indices=Indices.raw_data() # Something happened with masking of y by x mask Values=Values.raw_data() genutil.array_indexing_emulate.set(Array.raw_data(),Indices.astype('i'),Values) if m is not numpy.ma.nomask: if mv is not numpy.ma.nomask: genutil.array_indexing_emulate.set(m,Indices,mv) elif mv is not numpy.ma.nomask: m=numpy.zeros(mv.shape,mv.typcode()) genutil.array_indexing_emulate.set(m,Indices,mv) if not numpy.ma.allequal(m,0): Array=numpy.ma.masked_where(m,Array,copy=0) if not ax is None: Array=cdms2.createVariable(C,axes=ax,id=id,copy=0) for at in xatt.keys(): setattr(C,at,xatt[at]) return Array
def check_variables(vv, searchmode='ns', format=True): """Check that all variables are of MV2.array type and are well known of the :mod:`vacumm.data.cf` module Variable are first checked on the first part of their id, before a "_". If the prefix is not known, their are checked is their are known with the :func:`vacumm.data.cf.match_known_var`. In this latter case, the id of the variable is changed in case of success if format is True. Return ------ list The corresponding list of generic names """ al = ArgList(vv) gennames = [] for var in al.get(): # It is MV2.array? if not cdms2.isVariable(var): raise SONATError('Variable is not of MV2.array type') # Is the name generic? vns = var.id.split('_') varname = vns[0] suffix = '_'.join(vns[1:]) if varname in GENERIC_VAR_NAMES: gennames.append(var.id) continue # Do its properties match a known variable? genname = match_known_var(var, searchmode=searchmode) if not genname: raise SONATError('Unkown variable') if format: format_var(var, genname, format_axes=False, force=1 if suffix else 2) # Suffix if suffix: if format: var.id = var.id + '_' + suffix genname = genname + '_' + suffix gennames.append(genname) return al.put(gennames)
def get(Array,Indices,axis=0): """ Arrayrrayindexing returns Array[Indices], indices are taken along dimension given with axis Usage: C=get(Array,Indices,axis=0) # i.e. C=Array[Indices] Indices accepts negative value ,e.g: -1 is last element """ ## First some checks isma=numpy.ma.isMA(Array) if isinstance(Indices,int): return Array[Indices] if Indices.dtype not in [numpy.int,numpy.int32,numpy.int16]: raise "Error indices array must be made of integers (try: Indices=Indices.astype('l') first)" if cdms2.isVariable(Array) : xatt=Array.attributes id=Array.id if len(Array.shape)!=len(Indices.shape): Array,Indices,weights,axis,ax=statistics.__checker(Array,Indices,None,axis,smally=1) if isinstance(Indices,int): return Array[Indices] if Indices.shape!=Array.shape[1:]: raise "Error uncompatible shapes: "+str(Array.shape)+" and "+str(Indices.shape) else: Array,Indices,weights,axis,ax=statistics.__checker(Array,Indices,None,axis) if Indices.shape!=Array.shape: raise "Error uncompatible shapes: "+str(Array.shape)+" and "+str(Indices.shape) m=Array.mask if not isinstance(Indices,int): Indices=Indices.data.astype('i') # Sometihng happened with masking of y by x mask print Array.data.dtype.char,Indices.dtype.char C=genutil.array_indexing.extract(Array.data,Indices) if m is not numpy.ma.nomask: M=genutil.array_indexing.extract(m.astype('i'),Indices) C=numpy.ma.masked_where(M,C,copy=0) elif isma: C=numpy.ma.array(C,copy=0,mask=None) if not ax is None: C=cdms2.createVariable(C,axes=ax,id=id,copy=0) for at in xatt.keys(): setattr(C,at,xatt[at]) return C
def scale(self, data, copy=False, mean=None, norm=None, mode=None): """Remove mean and normalize unpacked data""" if mode=='mean': if norm is None: norm = False if mean is None: mean = True elif mode=='norm': if norm is None: norm = True if mean is None: mean = False if copy: data = data.clone() if cdms2.isVariable(data) else data.copy() if mean is not False: data[:] -= self.mean if mean is True or mean is None else mean if norm is not False: data[:] /= self._norm if norm is True or norm is None else norm return data
def get_order(var): """Enhanced version of getOrder() method that handles 2D axes :Params: - **var**: axis or cdms variable. :Output: string containing letters x, y, z, t or - :Example: >>> get_order(var) "-yx" """ # Already an order if isinstance(var, basestring): return var.lower() # Axis if isaxis(var): order = get_axis_type(var) if len(var.shape) == 2 and order in 'xy': return 'yx' return order # Variable if not cdms2.isVariable(var): return '-' * len(var.shape) order = var.getOrder() if getattr(var, '_nogridorder', False) or \ '-' not in order[-2:]: return order if var.getGrid() is not None and \ 'z' not in order[-2:] and 't' not in order[-2:]: if order[-1] == '-' and 'x' not in order: # lon = var.getLongitude() # if len(lon.shape)==2: order = order[:-1] + 'x' if order[-2] == '-' and 'y' not in order: # lat = var.getLatitude() # if len(lat.shape)==2: order = order[:-2] + 'y' + order[-1] return order
def norm_atan(var, stretch=1.): """Normalize using arctan (arctan(strecth*var/std(var)) - *stretch*: If stretch close to 1, saturates values [default: 1] Return: Value in [-1,1] """ if cdms2.isVariable(var): var_norm = var.clone() var_norm.id += '_norm' mm = MV elif MA.isMA(var): var_norm = var.copy() mm = MA else: var_norm = N.array(var) mm = N std = var.std() var_norm[:] = mm.arctan(stretch * var / var.std()) * 2. / N.pi return var_norm
def norm_atan(var,stretch=1.): """Normalize using arctan (arctan(strecth*var/std(var)) - *stretch*: If stretch close to 1, saturates values [default: 1] Return: Value in [-1,1] """ if cdms2.isVariable(var): var_norm = var.clone() var_norm.id += '_norm' mm = MV elif MA.isMA(var): var_norm = var.copy() mm = MA else: var_norm = N.array(var) mm = N std = var.std() var_norm[:] = mm.arctan(stretch*var/var.std())*2./N.pi return var_norm
def get_order(var): """Enhanced version of getOrder() method that handles 2D axes :Params: - **var**: axis or cdms variable. :Output: string containing letters x, y, z, t or - :Example: >>> get_order(var) "-yx" """ # Already an order if isinstance(var, basestring): return var.lower() # Axis if isaxis(var): order = get_axis_type(var) if len(var.shape)==2 and order in 'xy': return 'yx' return order # Variable if not cdms2.isVariable(var): return '-'*len(var.shape) order = var.getOrder() if getattr(var, '_nogridorder', False) or \ '-' not in order[-2:]: return order if var.getGrid() is not None and \ 'z' not in order[-2:] and 't' not in order[-2:]: if order[-1]=='-' and 'x' not in order: # lon = var.getLongitude() # if len(lon.shape)==2: order= order[:-1]+'x' if order[-2]=='-' and 'y' not in order: # lat = var.getLatitude() # if len(lat.shape)==2: order = order[:-2]+'y'+order[-1] return order
def trimData2D(self,data): if data is None: return None try: g=data.getGrid() gaxes=list(g.getAxisList()) daxes=list(data.getAxisList()) if daxes[len(daxes)-len(gaxes):] == gaxes: # Ok it is gridded and the grid axes are last return self.cleanupData(data(*(slice(0,1),)*(len(daxes)-len(gaxes)),squeeze=1)) else: # Ok just return the last two dims return self.cleanupData(data(*(slice(0,1),)*(len(daxes)-2),squeeze=1)) except Exception,err: # ok no grid info daxes=list(data.getAxisList()) if cdms2.isVariable(data): return self.cleanupData( data(*(slice(0,1),)*(len(daxes)-2))) else: #numpy arrays are not callable op = () for i in range(numpy.rank(data)-2): op.append(slice(0,1)) return self.cleanupData(data[op])
def _get_anomaly_(var, ref='mean', mean=None): # Basic checks assert var.ndim == 1, 'Input variable must be 1D' assert cdms2.isVariable(var) and var.getTime( ) is not None, 'Input variable must have a proper time axis' # Get reference if ref is None: ref = 'mean' nt = len(var) if isinstance(ref, int): var_ref = running_average(var, ref) elif ref in ['demerliac', 'godin']: var_ref = eval(ref)(var, get_tide=False) elif ref == 'mean': if mean is None: var_ref = float(var.mean()) else: var_ref = mean else: var_ref = ref if not isinstance(var_ref, (float, int)) and nt != len(var_ref): ntref = len(var_ref) ct = var_ref.getAxis(0).subAxis(0, ntref, ntref - 1).asComponentTime() var = var((ct[0], ct[-1], 'cc')) nt = ntref if var.getMissing() is None: var.setMissing(1.e20) # Departure vara = var - var_ref # Deal with mask if vara.mask is not MV2.nomask: vara = compress(vara) if not isinstance(var_ref, (float, int)): var_ref = compress(MV2.masked_where(vara.mask, var_ref, copy=0)) return vara, var_ref
def _get_anomaly_(var,ref='mean',mean=None): # Basic checks assert var.ndim==1, 'Input variable must be 1D' assert cdms2.isVariable(var) and var.getTime() is not None, 'Input variable must have a proper time axis' # Get reference if ref is None: ref = 'mean' nt = len(var) if isinstance(ref,int): var_ref = running_average(var,ref) elif ref in ['demerliac','godin']: var_ref = eval(ref)(var,get_tide=False) elif ref == 'mean': if mean is None: var_ref = float(var.mean()) else: var_ref = mean else: var_ref = ref if not isinstance(var_ref, (float, int)) and nt != len(var_ref): ntref = len(var_ref) ct = var_ref.getAxis(0).subAxis(0,ntref,ntref-1).asComponentTime() var = var((ct[0],ct[-1],'cc')) nt = ntref if var.getMissing() is None: var.setMissing(1.e20) # Departure vara = var - var_ref # Deal with mask if vara.mask is not MV2.nomask: vara = compress(vara) if not isinstance(var_ref, (float, int)): var_ref = compress(MV2.masked_where(vara.mask, var_ref, copy=0)) return vara, var_ref
def projectField(self, fields, neofs=None, eofscaling=0, weighted=True): """Project a set of fields onto the EOFs. Given a set of fields, projects them onto the EOFs to generate a corresponding set of pseudo-PCs. **Argument:** *fields* A list/tuple containing one or more `cdms2` variables, each with two or more dimensions, containing the data to be projected onto the EOFs. Each field must have the same spatial dimensions (including missing values in the same places) as the corresponding data set in the `MultivariateEof` input *datasets*. The fields may have different length time dimensions to the `MultivariateEof` inputs *datasets* or no time dimension at all, but this must be consistent for all fields. **Optional arguments:** *neofs* Number of EOFs to project onto. Defaults to all EOFs. If the number of EOFs requested is more than the number that are available, then the field will be projected onto all available EOFs. *eofscaling* Set the scaling of the EOFs that are projected onto. The following values are accepted: * *0* : Un-scaled EOFs (default). * *1* : EOFs are divided by the square-root of their eigenvalue. * *2* : EOFs are multiplied by the square-root of their eigenvalue. *weighted* If *True* then each field in *fields* is weighted using the same weights used for the EOF analysis prior to projection. If *False* then no weighting is applied. Defaults to *True* (weighting is applied). Generally only the default setting should be used. **Returns:** *pseudo_pcs* A `cdms2` variable containing the ordered pseudo-PCs. **Examples:** Project a data set onto all EOFs:: pseudo_pcs = solver.projectField([field1, field2]) Project a data set onto the four leading EOFs:: pseudo_pcs = solver.projectField([field1, field2], neofs=4) """ for field in fields: if not cdms2.isVariable(field): raise TypeError("the input data set must be a cdms2 variable") if len(fields) != self._ndata: raise ValueError( "number of fields is incorrect, expecting {:d} " "but got {:d}".format(self._ndata, len(fields)) ) for field in fields: order = field.getOrder() if "t" in order: if order[0] != "t": raise ValueError("time must be the first dimension, " "consider using the reorder() method") pcs = self._solver.projectField( [f.asma() for f in fields], neofs=neofs, eofscaling=eofscaling, weighted=weighted ) # Create an axis list, its contents depend on whether or not a time # axis was present in the input field. if pcs.ndim == 2: # Time dimension present: pcsax = cdms2.createAxis(range(pcs.shape[1]), id="pc") pcsax.long_name = "pc_number" axlist = [fields[0].getAxis(0), pcsax] else: # A PC axis and a leading time axis. pcsax = cdms2.createAxis(range(pcs.shape[0]), id="pc") pcsax.long_name = "pc_number" axlist = [pcsax] # Apply meta data to the projected PCs. pcs = cdms2.createVariable(pcs, id="pseudo_pcs", axes=axlist) pcs.long_name = "psuedo_pcs" return pcs
def grid(axis_ids,latitude=None,longitude=None,latitude_vertices=None,longitude_vertices=None,nvertices=None): """ Creates a cmor grid Usage: grid_id = grid(axis_ids,latitude,longitude,latitude_vertices=None,longitude_vertices=None) Where: axis_ids : array contianing the axes ids for this grid. latitude/longitude: the values for longitude/latitude arrays (unless it is a time varying grid) latitude_vertices/longitude_vertices: coordinates of vertices for each latitude/latitude (unless it is a time varying grid) """ if numpy.ma.isMA(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif has_cdms2 and cdms2.isVariable(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif has_cdms2 and cdms2.isVariable(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif isinstance(axis_ids,(list,tuple)): axis_ids = numpy.ascontiguousarray(axis_ids) elif not isinstance(axis_ids, numpy.ndarray): raise Exception, "Error could not convert axis_ids list to a numpy array" if numpy.ndim(axis_ids)>1: raise Exception, "error axes list/array must be 1D" if latitude is not None: latitude = _to_numpy(latitude, 'latitude') if numpy.ndim(latitude)!=len(axis_ids): raise Exception, "latitude's rank does not match number of axes passed via axis_ids" type = latitude.dtype.char nvert = 0 if not type in ['d','f','i','l']: raise Exception, "latitude array must be of type 'd','f','l' or 'i'" longitude = _to_numpy(longitude, 'longitude') if numpy.ndim(longitude)!=len(axis_ids): raise Exception, "longitude's rank does not match number of axes passed via axis_ids" ## print 'longitude type:',longitude.dtype.char if longitude.dtype.char!=type: longitude = longitude.astype(type) elif longitude is not None: raise Exception, "latitude and longitude must be BOTH an array or None" else: type='f' if nvertices is None : nvert=0 else: nvert = nvertices if latitude_vertices is not None: latitude_vertices = _to_numpy(latitude_vertices, 'latitude_vertices') if numpy.ndim(latitude_vertices)!=len(axis_ids)+1: raise Exception, "latitude_vertices's rank does not match number of axes passed via axis_ids +1 (for vertices)" ## print 'latitude_vert type:',latitude_vertices.dtype.char if latitude_vertices.dtype.char!=type: latitude_vertices = latitude_vertices.astype(type) nvert = latitude_vertices.shape[-1] if nvertices is not None: if nvert!=nvertices: raise Exception,"you passed nvertices as: %i, but from your latitude_vertices it seems to be: %i" % (nvertices,nvert) if longitude_vertices is not None: longitude_vertices = _to_numpy(longitude_vertices, 'longitude_vertices') if numpy.ndim(longitude_vertices)!=len(axis_ids)+1: raise Exception, "longitude_vertices's rank does not match number of axes passed via axis_ids +1 (for vertices)" ## print 'longitude_vert type:',longitude_vertices.dtype.char if longitude_vertices.dtype.char!=type: longitude_vertices = longitude_vertices.astype(type) nvert2 = longitude_vertices.shape[-1] if latitude_vertices is None: nvert = nvert2 elif nvert!=nvert2: raise Exception, "error in shape longitude_vertices and latitude_vertices seem to have different # of vertices: %i vs %i, %s" % (nvert,nvert2, str(longitude_vertices.shape )) if nvertices is not None: if nvert!=nvertices: raise Exception,"you passed nvertices as: %i, but from your longitude_vertices it seems to be: %i" % (nvertices,nvert) ## if area is not None: ## if not isinstance(area,numpy.ndarray): ## try: ## area = numpy.ascontiguousarray(area.filled()) ## except: ## raise Exception, "Error could not convert area to a numpy array" ## if numpy.rank(area)!=len(axis_ids): ## raise Exception, "area's rank does not match number of axes passed via axis_ids" ## if area.dtype.char!=type: ## area = area.astype(type) n = len(axis_ids) axis_ids=axis_ids.astype('i'); return _cmor.grid(n,axis_ids,type,latitude,longitude,nvert,latitude_vertices,longitude_vertices)
def write(var_id,data,ntimes_passed=None,file_suffix="",time_vals=None,time_bnds=None,store_with=None): """ write data to a cmor variable Usage: ierr = write(var_id,data,ntimes_passed=None,file_suffix="",time_vals=None,time_bnds=None,store_with=None """ if not isinstance(var_id,(int,numpy.int,numpy.int32)): raise Exception, "error var_id must be an integer" var_id = int(var_id) if not isinstance(file_suffix,str): raise Exception, "Error file_suffix must be a string" if store_with is not None: if not isinstance(store_with,(int,numpy.int,numpy.int32)): raise Exception, "error store_with must be an integer" store_with = int(store_with) if numpy.ma.isMA(data): data = numpy.ascontiguousarray(data.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(data): data = numpy.ascontiguousarray(data.filled()) elif has_cdms2 and cdms2.isVariable(data): if time_vals is None: time_vals = data.getTime() data = numpy.ascontiguousarray(data.filled()) elif isinstance(data,(list,tuple)): data = numpy.ascontiguousarray(data) elif not isinstance(data, numpy.ndarray): raise Exception, "Error could not convert data to a numpy array" if time_vals is None: pass elif numpy.ma.isMA(time_vals): time_vals = numpy.ascontiguousarray(time_vals.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(time_vals): time_vals = numpy.ascontiguousarray(time_vals.filled()) elif has_cdms2 and isinstance(time_vals,cdms2.axis.TransientAxis): if time_bnds is None: time_bnds = time_vals.getBounds() time_vals = numpy.ascontiguousarray(time_vals[:]) elif has_cdms2 and cdms2.isVariable(time_vals): time_vals = numpy.ascontiguousarray(time_vals.filled()) elif isinstance(time_vals,(list,tuple)): time_vals = numpy.ascontiguousarray(time_vals) elif not isinstance(time_vals, numpy.ndarray): try: time_vals = numpy.ascontiguousarray(time_vals) except: raise Exception, "Error could not convert time_vals to a numpy array" if time_vals is not None: type = time_vals.dtype.char if not type in ['f','d','i','l']: raise Exception, "Error time_vals type must one of: 'f','d','i','l', please convert first" time_vals=time_vals.astype("d") if ntimes_passed is None: if time_vals is None: ntimes_passed = 0 else: ntimes_passed = len(time_vals) if not isinstance(ntimes_passed,(int,numpy.int,numpy.int32)): raise Exception, "error ntimes_passed must be an integer" ntimes_passed = int(ntimes_passed) #At that ponit we check that shapes matches! goodshape = _cmor.get_original_shape(var_id,1) osh = data.shape ogoodshape=list(goodshape) sh=list(osh) j=0 while sh.count(1)>0: sh.remove(1) while goodshape.count(1)>0: goodshape.remove(1) for i in range(len(goodshape)): if goodshape[i]!=0: if sh[j]!=goodshape[i]: if goodshape[i]!=1: raise Exception,"Error: your data shape (%s) does not match the expected variable shape (%s)\nCheck your variable dimensions before caling cmor_write" % (str(osh),str(ogoodshape)) j+=1 elif ntimes_passed!=1: j+=1 data = numpy.ascontiguousarray(numpy.ravel(data)) if time_bnds is not None: if numpy.ma.isMA(time_bnds): time_bnds = numpy.ascontiguousarray(time_bnds.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(time_bnds): time_bnds = numpy.ascontiguousarray(time_bnds.filled()) elif has_cdms2 and cdms2.isVariable(time_bnds): if time_vals is None: time_vals = time_bnds.getTime() time_bnds = numpy.ascontiguousarray(time_bnds.filled()) elif isinstance(time_bnds,(list,tuple)): time_bnds = numpy.ascontiguousarray(time_bnds) elif not isinstance(time_bnds, numpy.ndarray): raise Exception, "Error could not convert time_bnds to a numpy array" if numpy.ndim(time_bnds)>2: raise Exception, "bounds rank cannot be greater than 2" elif numpy.ndim(time_bnds)==2: if time_bnds.shape[1]!=2: raise Exception, "error time_bnds' 2nd dimension must be of length 2" bnds =[] if time_bnds.shape[0] > 1: _check_time_bounds_contiguous(time_bnds) bnds = _flatten_time_bounds(time_bnds) else: bnds = time_bnds.ravel() time_bnds=numpy.array(bnds) else: # ok it is a rank 1! if numpy.ndim(time_vals)==0: ltv=1 else: ltv=len(time_vals) if len(time_bnds)!=ltv+1: raise Exception,"error time_bnds if 1D must be 1 elt greater than time_vals, you have %i vs %i" % (len(time_bnds),ltv) bnds=[] for i in range(ltv): bnds.append([time_bnds[i],time_bnds[i+1]]) bnds=numpy.array(bnds) bnds = _flatten_time_bounds(bnds) time_bnds=numpy.array(bnds) if time_bnds is not None: type = time_bnds.dtype.char if not type in ['f','d','i','l']: raise Exception, "Error time_bnds type must one of: 'f','d','i','l', please convert first" time_bnds=time_bnds.astype("d") type = data.dtype.char if not type in ['f','d','i','l']: raise Exception, "Error data type must one of: 'f','d','i','l', please convert first" return _cmor.write(var_id,data,type,ntimes_passed,time_vals,time_bnds,store_with)
def __call__(self, input, gradLat, gradLon, gradLatlon): """gradLat = df/di gradLon = df/dj gradLatlon = d(df)/(di)(dj) """ import numpy.ma from cdms2 import isVariable from cdms2.tvariable import TransientVariable if (gradLat.shape != input.shape or gradLon.shape != input.shape or gradLatlon.shape != input.shape): raise RegridError, "All input arrays must have shape %s"%`input.shape` if (type(gradLat) is not type(input) or type(gradLon) is not type(input) or type(gradLatlon) is not type(input)): raise RegridError, "All input arrays must have type %s"%`type(input)` # If input is a variable, make it a TV if isVariable(input) and not isinstance(input, TransientVariable): input = input.subSlice() gradLat = gradLat.subSlice() gradLon = gradLon.subSlice() gradLatlon = gradLatlon.subSlice() isvar = isinstance(input, TransientVariable) if isvar: domain = tuple(input.getAxisList()) if self.inputGrid is not None: ingrid = self.inputGrid else: ingrid = input.getGrid() if ingrid is None: raise RegridError, "Input variable must have an associated grid." rank = len(ingrid.shape) gridsize = ingrid.size() outgridshape = self.outputGrid.shape # Check that the grid matches the last dimension(s) of input if input.shape[-rank:] != ingrid.shape: raise RegridError, 'Last dimensions of input array must match grid shape: %s'%`ingrid.shape` else: rank = 1 # If not a TV, last dimension is the 'cell' dimension gridsize = input.shape[-1] outgridshape = (reduce(lambda x,y: x*y, self.outputGrid.shape, 1),) # If input is an numpy.ma, make it Numeric if numpy.ma.isMaskedArray(input): input = input.filled() gradLat = gradLat.filled() gradLon = gradLon.filled() gradLatlon = gradLatlon.filled() restoreShape = input.shape[:-rank] restoreLen = reduce(lambda x,y: x*y, restoreShape, 1) oldshape = input.shape newshape = (restoreLen, gridsize) input.shape = newshape gradLat.shape = newshape gradLon.shape = newshape gradLatlon.shape = newshape # Regrid output = _scrip.bicubic_regrid(self.outputGrid.size(), input, self.remapMatrix, self.sourceAddress, self.destAddress, gradLat, gradLon, gradLatlon) # Reshape output and restore input shape input.shape = oldshape gradLat.shape = oldshape gradLon.shape = oldshape gradLatlon.shape = oldshape outshape = restoreShape + outgridshape output.shape = outshape # If the input was a variable, so is the output if isvar: outdomain = domain[:-rank]+(self.outputGrid,) output = TransientVariable(output, axes=outdomain) return output
def testTV(self): f = self.getDataFile("test.xml") x = self.test_arr v = f.variables['v'] vp = x[1, 1:, 4:12, 8:25] vp2 = vp[1, 1:-1, 1:] tv = v.subRegion((366., 731., 'ccn'), (-42., 42., 'ccn'), (90., 270.)) tvv = v[0:2, 0:10, 30:40] # Make sure we retrieve a scalar xx = tv[1, 7, 15] self.assertFalse(isinstance(xx, numpy.ndarray)) # Variable get: axis, grid, latitude, level, longitude, missing, order, # time, len, typecode vaxis0 = v.getAxis(0) axis0 = tv.getAxis(0) self.assertFalse(not numpy.ma.allequal(axis0[:], vaxis0[1:])) taxis = tv.getTime() taxisarray = taxis[:] vaxisarray = vaxis0[1:] self.assertFalse(not numpy.ma.allequal(taxisarray, vaxisarray)) vaxis1 = v.getAxis(1) lataxis = tv.getLatitude() self.assertFalse(not numpy.ma.allequal(lataxis[:], vaxis1[4:12])) vaxis2 = v.getAxis(2) lonaxis = tv.getLongitude() # # default is 'ccn' -- now it 8:25 # self.assertFalse(not numpy.ma.allequal(lonaxis[:], vaxis2[8:25])) tv = v.subRegion((366., 731., 'ccn'), (-42., 42., 'ccn'), (90., 270.)) missing_value = v.getMissing() self.assertEqual(missing_value, -99.9) tmv = tv.fill_value # TODO: Did the default value of fill_value/missing change? This is failing. #self.assertEqual(tmv, -99.9) grid = tv.getGrid() self.assertFalse(grid is None) order = tv.getOrder() self.assertEqual(order, 'tyx') self.assertEqual(len(tv), 2) # get TV domain domain = tv.getDomain() self.assertEqual(len(domain), 3) # getRegion of a TV tv2 = tv.getRegion(731., (-30., 30., 'ccn'), (101.25, 270.0)) self.assertFalse(not numpy.ma.allequal(tv2, vp2)) # Axis get: bounds, calendar, value, isXXX, len, subaxis, typecode axis1 = tv.getAxis(1) axis2 = tv.getAxis(2) bounds = axis1.getBounds() self.assertFalse(bounds is None) self.assertEqual(axis0.getCalendar(), cdtime.MixedCalendar) val = axis1.getValue() self.assertFalse(not numpy.ma.allequal(axis1.getValue(), axis1[:])) self.assertFalse(not axis0.isTime()) self.assertFalse(not axis1.isLatitude()) self.assertFalse(not axis2.isLongitude()) self.assertTrue(axis2.isCircular()) self.assertEqual(len(axis2), 17) saxis = axis2.subAxis(1, -1) self.assertFalse(not numpy.ma.allequal(saxis[:], axis2[1:-1])) self.assertEqual(axis1.typecode(), numpy.sctype2char(numpy.float)) self.assertEqual(axis2.shape, (17, )) # Axis set: bounds, calendar savebounds = copy.copy(bounds) bounds[0, 0] = -90.0 axis1.setBounds(bounds) nbounds = axis1.getBounds() self.assertFalse(not numpy.ma.allequal(bounds, nbounds)) axis0.setCalendar(cdtime.NoLeapCalendar) self.assertEqual(axis0.getCalendar(), cdtime.NoLeapCalendar) gaussaxis = cdms2.createGaussianAxis(32) try: testaxis = cdms2.createGaussianAxis(31) except BaseException: markError('Gaussian axis with odd number of latitudes') # Grid get: axis, bounds, latitude, longitude, mask, order, type, # weights, subgrid, subgridRegion a1 = grid.getAxis(1) self.assertFalse(not numpy.ma.allequal(a1[:], axis2[:])) bounds[0, 0] = savebounds[0, 0] axis1.setBounds(bounds) latbounds, lonbounds = grid.getBounds() self.assertFalse(not numpy.ma.allequal(latbounds, savebounds)) glat = grid.getLatitude() glon = grid.getLongitude() mask = grid.getMask() order = grid.getOrder() self.assertEqual(order, 'yx') gtype = grid.getType() weights = grid.getWeights() subg = grid.subGrid((1, 7), (1, 15)) subg2 = grid.subGridRegion((-30., 30., 'ccn'), (101.25, 247.5, 'ccn')) self.assertFalse(not numpy.ma.allequal(subg.getLongitude()[:], subg2.getLongitude()[:])) self.assertEqual(grid.shape, (8, 17)) # Grid set: bounds, mask, type latbounds[0, 0] = -90.0 grid.setBounds(latbounds, lonbounds) nlatb, nlonb = grid.getBounds() self.assertFalse(not numpy.ma.allequal(latbounds, nlatb)) grid.setType('uniform') self.assertEqual(grid.getType(), 'uniform') yy = numpy.ma.reshape(numpy.ma.arange(272.0), tv.shape) tv.assignValue(yy) self.assertFalse(not numpy.ma.allequal(tv, yy)) tv3 = tv[0:-1] self.assertEqual(tv3.shape, (1, 8, 17)) # Create a transient variable from scratch oldlat = tv.getLatitude() oldBounds = oldlat.getBounds() newlat = cdms2.createAxis(numpy.ma.array(oldlat[:]), numpy.ma.array(oldBounds)) b = newlat.getBounds() b[0, 0] = -48. newlat.setBounds(b) tv4 = cdms2.createVariable(tv[:], copy=1, fill_value=255.) tv4[0, 1:4] = 20.0 self.assertEqual(tv[:, ::-1, :].shape, tv.shape) # Test asVariable www = cdms2.asVariable(tv4) self.assertFalse(www is not tv4) www = cdms2.asVariable(v, 0) self.assertFalse(www is not v) www = cdms2.asVariable([1., 2., 3.]) self.assertFalse(not cdms2.isVariable(www)) # Check that createAxis allows an axis as an argument lon = f.axes['longitude'] newlon = cdms2.createAxis(lon) self.assertFalse(newlon.typecode() == 'O') # Test take of axis without bounds newlat.setBounds(None) samp = cdms2.axis.take(newlat, (2, 4, 6))
def __call__(self, input, gradLat, gradLon, gradLatlon): """gradLat = df/di gradLon = df/dj gradLatlon = d(df)/(di)(dj) """ import numpy.ma from cdms2 import isVariable from cdms2.tvariable import TransientVariable if (gradLat.shape != input.shape or gradLon.shape != input.shape or gradLatlon.shape != input.shape): raise RegridError("All input arrays must have shape %s" % repr(input.shape)) if (not isinstance(gradLat, type(input)) or not isinstance(gradLon, type(input)) or not isinstance(gradLatlon, type(input))): raise RegridError("All input arrays must have type %s" % repr(type(input))) # If input is a variable, make it a TV if isVariable(input) and not isinstance(input, TransientVariable): input = input.subSlice() gradLat = gradLat.subSlice() gradLon = gradLon.subSlice() gradLatlon = gradLatlon.subSlice() isvar = isinstance(input, TransientVariable) if isvar: domain = tuple(input.getAxisList()) if self.inputGrid is not None: ingrid = self.inputGrid else: ingrid = input.getGrid() if ingrid is None: raise RegridError( "Input variable must have an associated grid.") rank = len(ingrid.shape) gridsize = ingrid.size() outgridshape = self.outputGrid.shape # Check that the grid matches the last dimension(s) of input if input.shape[-rank:] != ingrid.shape: raise RegridError( 'Last dimensions of input array must match grid shape: %s' % repr(ingrid.shape)) else: rank = 1 # If not a TV, last dimension is the 'cell' dimension gridsize = input.shape[-1] outgridshape = (reduce(lambda x, y: x * y, self.outputGrid.shape, 1), ) # If input is an numpy.ma, make it Numeric if numpy.ma.isMaskedArray(input): input = input.filled() gradLat = gradLat.filled() gradLon = gradLon.filled() gradLatlon = gradLatlon.filled() restoreShape = input.shape[:-rank] restoreLen = reduce(lambda x, y: x * y, restoreShape, 1) oldshape = input.shape newshape = (restoreLen, gridsize) input.shape = newshape gradLat.shape = newshape gradLon.shape = newshape gradLatlon.shape = newshape # Regrid output = _scrip.bicubic_regrid(self.outputGrid.size(), input, self.remapMatrix, self.sourceAddress, self.destAddress, gradLat, gradLon, gradLatlon) # Reshape output and restore input shape input.shape = oldshape gradLat.shape = oldshape gradLon.shape = oldshape gradLatlon.shape = oldshape outshape = restoreShape + outgridshape output.shape = outshape # If the input was a variable, so is the output if isvar: outdomain = domain[:-rank] + (self.outputGrid, ) output = TransientVariable(output, axes=outdomain) return output
def write(var_id, data, ntimes_passed=None, file_suffix="", time_vals=None, time_bnds=None, store_with=None): """ write data to a cmor variable Usage: ierr = write(var_id,data,ntimes_passed=None,file_suffix="",time_vals=None,time_bnds=None,store_with=None """ if not isinstance(var_id, (int, numpy.int, numpy.int32)): raise Exception, "error var_id must be an integer" var_id = int(var_id) if not isinstance(file_suffix, str): raise Exception, "Error file_suffix must be a string" if store_with is not None: if not isinstance(store_with, (int, numpy.int, numpy.int32)): raise Exception, "error store_with must be an integer" store_with = int(store_with) if numpy.ma.isMA(data): data = numpy.ascontiguousarray(data.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(data): data = numpy.ascontiguousarray(data.filled()) elif has_cdms2 and cdms2.isVariable(data): if time_vals is None: time_vals = data.getTime() data = numpy.ascontiguousarray(data.filled()) elif isinstance(data, (list, tuple)): data = numpy.ascontiguousarray(data) elif not isinstance(data, numpy.ndarray): raise Exception, "Error could not convert data to a numpy array" if time_vals is None: pass elif numpy.ma.isMA(time_vals): time_vals = numpy.ascontiguousarray(time_vals.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(time_vals): time_vals = numpy.ascontiguousarray(time_vals.filled()) elif has_cdms2 and isinstance(time_vals, cdms2.axis.TransientAxis): if time_bnds is None: time_bnds = time_vals.getBounds() time_vals = numpy.ascontiguousarray(time_vals[:]) elif has_cdms2 and cdms2.isVariable(time_vals): time_vals = numpy.ascontiguousarray(time_vals.filled()) elif isinstance(time_vals, (list, tuple)): time_vals = numpy.ascontiguousarray(time_vals) elif not isinstance(time_vals, numpy.ndarray): try: time_vals = numpy.ascontiguousarray(time_vals) except: raise Exception, "Error could not convert time_vals to a numpy array" if time_vals is not None: type = time_vals.dtype.char if not type in ['f', 'd', 'i', 'l']: raise Exception, "Error time_vals type must one of: 'f','d','i','l', please convert first" time_vals = time_vals.astype("d") if ntimes_passed is None: if time_vals is None: ntimes_passed = 0 else: ntimes_passed = len(time_vals) if not isinstance(ntimes_passed, (int, numpy.int, numpy.int32)): raise Exception, "error ntimes_passed must be an integer" ntimes_passed = int(ntimes_passed) #At that ponit we check that shapes matches! goodshape = _cmor.get_original_shape(var_id, 1) osh = data.shape ogoodshape = list(goodshape) sh = list(osh) j = 0 while sh.count(1) > 0: sh.remove(1) while goodshape.count(1) > 0: goodshape.remove(1) for i in range(len(goodshape)): if goodshape[i] != 0: if sh[j] != goodshape[i]: if goodshape[i] != 1: raise Exception, "error your data shape (%s) does not match the expect variable shape (%s)" % ( str(osh), str(ogoodshape)) j += 1 elif ntimes_passed != 1: j += 1 data = numpy.ascontiguousarray(numpy.ravel(data)) if time_bnds is not None: if numpy.ma.isMA(time_bnds): time_bnds = numpy.ascontiguousarray(time_bnds.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(time_bnds): time_bnds = numpy.ascontiguousarray(time_bnds.filled()) elif has_cdms2 and cdms2.isVariable(time_bnds): if time_vals is None: time_vals = time_bnds.getTime() time_bnds = numpy.ascontiguousarray(time_bnds.filled()) elif isinstance(time_bnds, (list, tuple)): time_bnds = numpy.ascontiguousarray(time_bnds) elif not isinstance(time_bnds, numpy.ndarray): raise Exception, "Error could not convert time_bnds to a numpy array" if numpy.ndim(time_bnds) > 2: raise Exception, "bounds rank cannot be greater than 2" elif numpy.ndim(time_bnds) == 2: if time_bnds.shape[1] != 2: raise Exception, "error time_bnds' 2nd dimension must be of length 2" bnds = [] if time_bnds.shape[0] > 1: _check_time_bounds_contiguous(time_bnds) bnds = _flatten_time_bounds(time_bnds) else: bnds = time_bnds.ravel() time_bnds = numpy.array(bnds) else: # ok it is a rank 1! if numpy.ndim(time_vals) == 0: ltv = 1 else: ltv = len(time_vals) if len(time_bnds) != ltv + 1: raise Exception, "error time_bnds if 1D must be 1 elt greater than time_vals, you have %i vs %i" % ( len(time_bnds), ltv) bnds = [] for i in range(ltv): bnds.append([time_bnds[i], time_bnds[i + 1]]) bnds = numpy.array(bnds) bnds = _flatten_time_bounds(bnds) time_bnds = numpy.array(bnds) if time_bnds is not None: type = time_bnds.dtype.char if not type in ['f', 'd', 'i', 'l']: raise Exception, "Error time_bnds type must one of: 'f','d','i','l', please convert first" time_bnds = time_bnds.astype("d") type = data.dtype.char if not type in ['f', 'd', 'i', 'l']: raise Exception, "Error data type must one of: 'f','d','i','l', please convert first" return _cmor.write(var_id, data, type, ntimes_passed, time_vals, time_bnds, store_with)
def zfactor(zaxis_id, zfactor_name, units="", axis_ids=None, type=None, zfactor_values=None, zfactor_bounds=None): if not isinstance(zaxis_id, (int, numpy.int, numpy.int32)): raise Exception, "error zaxis_id must be a number" zaxis_id = int(zaxis_id) if not isinstance(zfactor_name, str): raise Exception, "Error you must pass a string for the variable zfactor_name" if not isinstance(units, str): raise Exception, "Error you must pass a string for the variable units" if numpy.ma.isMA(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif has_cdms2 and cdms2.isVariable(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif has_cdms2 and cdms2.isVariable(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif isinstance(axis_ids, (list, tuple)): axis_ids = numpy.ascontiguousarray(axis_ids) elif axis_ids is None: pass elif isinstance(axis_ids, (int, numpy.int, numpy.int32)): axis_ids = numpy.array([ axis_ids, ]) elif not isinstance(axis_ids, numpy.ndarray): raise Exception, "Error could not convert axis_ids list to a numpy array" if numpy.ndim(axis_ids) > 1: raise Exception, "error axis_ids list/array must be 1D" if axis_ids is None: ndims = 0 axis_ids = numpy.array(1) else: ndims = len(axis_ids) ## if ndims>1 and zfactor_values is not None: ## raise Exception, "Error you can only pass zfactor_values for zfactor with rank <=1" ## if ndims>1 and zfactor_bounds is not None: ## raise Exception, "Error you can only pass zfactor_bounds for zfactor with rank <=1" if zfactor_values is not None: if isinstance( zfactor_values, (float, int, numpy.float, numpy.float32, numpy.int, numpy.int32)): zfactor_values = numpy.array((zfactor_values, )) elif numpy.ma.isMA(zfactor_values): zfactor_values = numpy.ascontiguousarray(zfactor_values.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(zfactor_values): zfactor_values = numpy.ascontiguousarray(zfactor_values.filled()) elif has_cdms2 and cdms2.isVariable(zfactor_values): zfactor_values = numpy.ascontiguousarray(zfactor_values.filled()) elif isinstance(zfactor_values, (list, tuple)): zfactor_values = numpy.ascontiguousarray(zfactor_values) elif not isinstance(zfactor_values, numpy.ndarray): raise Exception, "Error could not convert zfactor_values to a numpy array" if type is None: try: type = zfactor_values.dtype.char except: if isinstance(zfactor_values, (float, numpy.float, numpy.float32)): type = 'f' elif isinstance(zfactor_values, (int, numpy.int, numpy.int32)): type = 'd' else: raise Exception, "Error unknown type for zfactor_values: %s" % repr( zfactor_values) elif type is None: type = 'd' if not isinstance(type, str): raise Exception, "error tpye must a a string" type = type.lower() if type == 's': type = 'c' if not type in ["c", "d", "f", "l", "i"]: raise Exception, 'error unknown type: "%s", must be one of: "c","d","f","l","i"' if zfactor_bounds is not None: if numpy.ma.isMA(zfactor_bounds): zfactor_bounds = numpy.ascontiguousarray(zfactor_bounds.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(zfactor_bounds): zfactor_bounds = numpy.ascontiguousarray(zfactor_bounds.filled()) elif has_cdms2 and cdms2.isVariable(zfactor_bounds): zfactor_bounds = numpy.ascontiguousarray(zfactor_bounds.filled()) elif isinstance(zfactor_bounds, (list, tuple)): zfactor_bounds = numpy.ascontiguousarray(zfactor_bounds) elif not isinstance(zfactor_bounds, numpy.ndarray): raise Exception, "Error could not convert zfactor_bounds to a numpy array" if numpy.ndim(zfactor_bounds) > 2: raise Exception, "error zfactor_bounds must be rank 2 at most" elif numpy.ndim(zfactor_bounds) == 2: if zfactor_bounds.shape[1] != 2: raise Exception, "error zfactor_bounds' 2nd dimension must be of length 2" bnds = [] b = zfactor_bounds[0] for i in range(zfactor_bounds.shape[0]): b = zfactor_bounds[i] bnds.append(b[0]) if (i < zfactor_bounds.shape[0] - 1) and ( b[1] != zfactor_bounds[i + 1][0]): raise Exception, "error zfactor_bounds have gaps between them" bnds.append(zfactor_bounds[-1][1]) zfactor_bounds = numpy.array(bnds) axis_ids = axis_ids.astype('i') ## print "sending",zaxis_id,zfactor_name,units,ndims,axis_ids,type,zfactor_values,zfactor_bounds return _cmor.zfactor(zaxis_id, zfactor_name, units, ndims, axis_ids, type, zfactor_values, zfactor_bounds)
def dataset(experiment_id,institution,source,calendar,outpath='.',realization=1,contact="",history="",comment="",references="",leap_year=0,leap_month=0,month_lengths=None,model_id="",forcing="",initialization_method=None,physics_version=None,institute_id="",parent_experiment_id="",branch_time=None,parent_experiment_rip=""): """ Initialize a cmor dataset Usage: dataset(experiment_id,institution,source,outpath='.',calendar=None,realization=None,contact=None,history="",comment="",references="",leap_year=None,leap_month=None,month_lengths=None,model_id="",forcing="",initialization_method=None,physics_version=None,institute_id="",parent_experiment_id="",branch_time=None,parent_experiment_rip="") """ if isinstance(calendar,int): if has_cdtime: # put this in a try loop in case cdtime is not available on the system if calendar == cdtime.Calendar360: calendar = "360_day" elif calendar == cdtime.ClimCalendar: calendar = "clim" elif calendar == cdtime.DefaultCalendar: calendar = "standard" elif calendar == cdtime.GregorianCalendar: calendar = "proleptic_gregorian" elif calendar == cdtime.JulianCalendar: calendar = "julian" elif calendar == cdtime.MixedCalendar: calendar= "standard" elif calendar == cdtime.NoLeapCalendar: calendar = "noleap" elif calendar == cdtime.StandardCalendar: calendar = "proleptic_gregorian" elif calendar == cdtime.ClimLeapCalendar: calendar = "climleap" elif calendar is None: calendar ="none" for st in [outpath,experiment_id,institution,source,contact,history,comment,references,model_id,forcing,institute_id,parent_experiment_id,parent_experiment_rip]: if not isinstance(st,str): for o in dir(): if locals()[o] is st: raise Exception, "Error argument %s must be a string" % o calendar = calendar.lower() for i in [realization,leap_year,leap_month]: if not isinstance(i,int): for o in dir(): if locals()[o] is i: raise Exception, "Error argument %s must be an integer" % o if isinstance(month_lengths,(list,tuple)): month_lengths = numpy.array(month_lengths) elif has_cdms2 and cdms2.isVariable(month_lengths): month_lengths = month_lengths.filled() elif isinstance(month_lengths,(numpy.ma.core.MaskedArray)): month_lengths = month_lengths.filled() elif has_oldma and isinstance(month_lengths,numpy.oldnumeric.ma.MaskedArray): month_lengths = month_lengths.filled() if isinstance(month_lengths,numpy.ndarray): if not numpy.rank(month_lengths)==1: raise Exception, "Error month_lengths must be 1D" if len(month_lengths)!=12: raise Exception, "Error month_lengths must have 12 elements exactly" months_lengths = numpy.ascontiguousarray(month_lengths) elif month_lengths is not None: raise Exception, "Error month_lengths must be a 12 elts array or list" if initialization_method is not None: if not isinstance(initialization_method,int): raise Exception, "initialization_method must be an int" else: initialization_method=0 if physics_version is not None: if not isinstance(physics_version,int): raise Exception, "physics_version must be an int" else: physics_version=0 if branch_time is not None: if not isinstance(branch_time,(float,int,numpy.float,numpy.float32,numpy.int,numpy.int32)): raise Exception,"branch_time must be a float" else: branch_time=float(branch_time) return _cmor.dataset(outpath,experiment_id,institution,source,calendar,realization,contact,history,comment,references,leap_year,leap_month,month_lengths,model_id,forcing,initialization_method,physics_version,institute_id,parent_experiment_id,branch_time,parent_experiment_rip)
def __init__(self, *datasets, **kwargs): """Create a MultipleEof object. The EOF solution is computed at initialization time. Method calls are used to retrieve computed quantities. **Arguments:** *\*datasets* One or more :py:mod:`cdms2` variables containing the data to be analyzed. Time must be the first dimension of each variable. Missing values are allowed provided that they are constant with time (e.g., values of an oceanographic field over land). **Optional arguments:** *weights* Sets the weighting method. The following values are accepted: * *"area"* : Square-root of grid cell area normalized by total area. Requires a latitude-longitude grid to be present in the corresponding :py:mod:`cdms2` variable in *\*datasets*. This is a fairly standard weighting strategy. If you are unsure which method to use and you have gridded data then this should be your first choice. * *"coslat"* : Square-root of cosine of latitude (*"cos_lat"* is also accepted). Requires a latitude dimension to be present in the corresponding :py:mod:`cmds2` variable in *\*datasets*. * *"none"* : Equal weights for all grid points (default). * *None* : Same as *"none"*. A sequence of values may be passed to use different weighting for each data set. Arrays of weights may also be supplied instead of specifying a weighting method. *center* If *True*, the mean along the first axis of the input data sets (the time-mean) will be removed prior to analysis. If *False*, the mean along the first axis will not be removed. Defaults to *True* (mean is removed). Generally this option should be set to *True* as the covariance interpretation relies on input data being anomalies with a time-mean of 0. A valid reson for turning this off would be if you have already generated an anomaly data set. Setting to *True* has the useful side-effect of propagating missing values along the time-dimension, ensuring the solver will work even if missing values occur at different locations at different times. *ddof* 'Delta degrees of freedom'. The divisor used to normalize the covariance matrix is *N - ddof* where *N* is the number of samples. Defaults to *1*. **Examples:** EOF analysis with area-weighting using two input fields: >>> from eof2 import Eof >>> eofobj = Eof(field_a, field_b, weights="area") """ # Handle keyword arguments manually. keywords = {"weights": "none", "center": True, "ddof":1} for kwarg in kwargs: if kwarg not in keywords.keys(): raise EofError("invalid argument: %s." % kwarg) weights = kwargs.get("weights", keywords["weights"]) center = kwargs.get("center", keywords["center"]) ddof = kwargs.get("ddof", keywords["ddof"]) # Record the number of datasets. self._numdsets = len(datasets) # Ensure the weights are specified one per dataset. if weights in ("none", None, "area", "cos_lat", "coslat"): weights = [weights] * self._numdsets elif len(weights) != self._numdsets: raise EofError("number of weights and data sets differs") # Record dimension information, missing values and compute weights. self._multitimeaxes = list() self._multichannels = list() self._multimissing = list() passweights = list() for dataset, weight in zip(datasets, weights): if not cdms2.isVariable(dataset): raise EofError("the input data set must be a cdms2 variable") # Ensure a time dimension exists. timeaxis = dataset.getTime() if timeaxis is None: raise EofError("time axis not found") self._multitimeaxes.append(timeaxis) # Ensure the time dimension is the first dimension. order = dataset.getOrder() if order[0] != "t": raise EofError("time must be the first dimension") # Record the other dimensions. channels = dataset.getAxisList() channels.remove(timeaxis) if len(channels) < 1: raise EofError("one or more spatial dimensions are required") self._multichannels.append(channels) # Record the missing values. self._multimissing.append(dataset.getMissing()) # Compute weights as required. if weight in ("none", None): passweights.append(None) else: try: wtarray = weights_array(dataset, scheme=weight.lower()) passweights.append(wtarray) except AttributeError: # Weight specification is not a string. Assume it is an array # of weights. passweights.append(weight) except EofToolError, err: # Another error occured, raise it as an EOF error. raise EofError(err)
oldBounds = oldlat.getBounds() newlat = cdms2.createAxis(numpy.ma.array(oldlat[:]),numpy.ma.array(oldBounds)) b = newlat.getBounds() b[0,0]=-48. newlat.setBounds(b) tv4 = cdms2.createVariable(tv[:],copy=1,fill_value=255.) tv4[0,1:4]=20.0 if tv[:,::-1,:].shape != tv.shape: markError("Reversing axis direction") # Test asVariable www = cdms2.asVariable(tv4) if www is not tv4: markError("asVariable failed, transient case.") www = cdms2.asVariable (v, 0) if www is not v: markError("asVariable failed, transient case.") www = cdms2.asVariable([1.,2.,3.]) if not cdms2.isVariable(www): markError("as/is test failed.") # Check that createAxis allows an axis as an argument lon = f.axes['longitude'] newlon = cdms2.createAxis(lon) if newlon.typecode()=='O': markError("createAxis failed: allow axis arg") # Test take of axis without bounds newlat.setBounds(None) samp = cdms2.axis.take(newlat,(2,4,6)) f.close() reportError()
def __init__(self, dataset, weights=None, center=True, ddof=1): """Create an Eof object. The EOF solution is computed at initialization time. Method calls are used to retrieve computed quantities. **Argument:** *dataset* A `cdms2` variable containing the data to be analysed. Time must be the first dimension. Missing values are allowed provided that they are constant with time (e.g., values of an oceanographic field over land). **Optional arguments:** *weights* Sets the weighting method. The following pre-defined weighting methods are available: * *'area'* : Square-root of grid cell area normalized by total grid area. Requires a latitude-longitude grid to be present in the `cdms2` variable *dataset*. This is a fairly standard weighting strategy. If you are unsure which method to use and you have gridded data then this should be your first choice. * *'coslat'* : Square-root of cosine of latitude. Requires a latitude dimension to be present in the `cdms2` variable *dataset*. * *None* : Equal weights for all grid points (*'none'* is also accepted). Alternatively an array of weights whose shape is compatible with the `cdms2` variable *dataset* may be supplied instead of specifying a weighting method. *center* If *True*, the mean along the first axis of *dataset* (the time-mean) will be removed prior to analysis. If *False*, the mean along the first axis will not be removed. Defaults to *True* (mean is removed). The covariance interpretation relies on the input data being anomalies with a time-mean of 0. Therefore this option should usually be set to *True*. Setting this option to *True* has the useful side effect of propagating missing values along the time dimension, ensuring that a solution can be found even if missing values occur in different locations at different times. *ddof* 'Delta degrees of freedom'. The divisor used to normalize the covariance matrix is *N - ddof* where *N* is the number of samples. Defaults to *1*. **Returns:** *solver* An `Eof` instance. **Examples:** EOF analysis with grid-cell-area weighting for the input field:: from eofs.cdms import Eof solver = Eof(dataset, weights='area') """ # Check that dataset is recognised by cdms2 as a variable. if not cdms2.isVariable(dataset): raise TypeError('the input data must be a cdms2 variable') # Store the time axis as an instance variable. self._timeax = dataset.getTime() # Verify that a time axis was found, getTime returns None when a # time axis is not found. if self._timeax is None: raise ValueError('time axis not found') # Check the dimension order of the input, time must be the first # dimension. order = dataset.getOrder() if order[0] != 't': raise ValueError('time must be the first dimension, ' 'consider using the reorder() method') # Verify the presence of at least one spatial dimension. The # instance variable channels will also be used as a partial axis # list when constructing meta-data. It contains the spatial # dimensions. self._channels = dataset.getAxisList() self._channels.remove(self._timeax) if len(self._channels) < 1: raise ValueError('one or more spatial dimensions are required') # Store the missing value attribute of the data set in an # instance variable so that it is recoverable later. self._missing_value = dataset.getMissing() # Generate an appropriate set of weights for the input dataset. There # are several weighting schemes. The 'area' weighting scheme requires # a latitude-longitude grid to be present, the 'cos_lat' scheme only # requires a latitude dimension. if weights in ('none', None): # No weights requested, set the weight array to None. wtarray = None else: try: # Generate a weights array of the appropriate kind, with a # shape compatible with the data set. scheme = weights.lower() wtarray = weights_array(dataset, scheme=scheme) except AttributeError: # Weights is not a string, assume it is an array. wtarray = weights except ValueError, err: # Weights is not recognized, raise an error. raise ValueError(err)
def __init__(self, datasets, weights=None, center=True, ddof=1): """Create a MultivariateEof object. The EOF solution is computed at initialization time. Method calls are used to retrieve computed quantities. **Arguments:** *datasets* A list/tuple containing one or more `cdms2` variables, each two or more dimensions, containing the data to be analysed. Time must be the first dimension of each variable. Missing values are allowed provided that they are constant with time in each field (e.g., values of an oceanographic field over land). **Optional arguments:** *weights* Sets the weighting method. One method can be chosen to apply to all variables in *datasets* or a sequence of options can be given to specify a different weighting method for each variable in *datasets*. The following pre-defined weighting methods are available: * *'area'* : Square-root of grid cell area normalized by total grid area. Requires a latitude-longitude grid to be present in the corresponding `cdms2` variable. This is a fairly standard weighting strategy. If you are unsure which method to use and you have gridded data then this should be your first choice. * *'coslat'* : Square-root of cosine of latitude. Requires a latitude dimension to be present in the corresponding `cdms2` variable. * *None* : Equal weights for all grid points (*'none'* is also accepted). Alternatively a sequence of arrays of weights whose shapes are compatible with the corresponding `cdms2` variables in *datasets* may be supplied instead of specifying a weighting method. *center* If *True*, the mean along the first axis of each variable in *datasets* (the time-mean) will be removed prior to analysis. If *False*, the mean along the first axis will not be removed. Defaults to *True* (mean is removed). The covariance interpretation relies on the input data being anomalies with a time-mean of 0. Therefore this option should usually be set to *True*. Setting this option to *True* has the useful side effect of propagating missing values along the time dimension, ensuring that a solution can be found even if missing values occur in different locations at different times. *ddof* 'Delta degrees of freedom'. The divisor used to normalize the covariance matrix is *N - ddof* where *N* is the number of samples. Defaults to *1*. **Returns:** *solver* An `MultivariateEof` instance. **Examples:** EOF analysis with grid-cell-area weighting using two input fields:: from eofs.multivariate.cdms import MultivariateEof solver = MultivariateEof([var1, var2], weights='area') """ # Record the number of datasets. self._ndata = len(datasets) # Ensure the weights are specified one per dataset. if weights in ("none", None, "area", "coslat"): weights = [weights] * self._ndata elif len(weights) != self._ndata: raise ValueError( "number of weights is incorrect, " "expecting {:d} but got {:d}".format(self._ndata, len(weights)) ) # Record dimension information, missing values and compute weights. self._multitimeaxes = list() self._multichannels = list() self._multimissing = list() passweights = list() for dataset, weight in zip(datasets, weights): if not cdms2.isVariable(dataset): raise TypeError("the input data set must be a cdms2 variable") # Ensure a time dimension exists. timeaxis = dataset.getTime() if timeaxis is None: raise ValueError("time axis not found") self._multitimeaxes.append(timeaxis) # Ensure the time dimension is the first dimension. order = dataset.getOrder() if order[0] != "t": raise ValueError("time must be the first dimension, " "consider using the reorder() method") # Record the other dimensions. channels = dataset.getAxisList() channels.remove(timeaxis) if len(channels) < 1: raise ValueError("one or more spatial dimensions are required") self._multichannels.append(channels) # Record the missing values. self._multimissing.append(dataset.getMissing()) # Compute weights as required. if weight in ("none", None): passweights.append(None) else: try: wtarray = weights_array(dataset, scheme=weight.lower()) passweights.append(wtarray) except AttributeError: # Weight specification is not a string. Assume it is an # array of weights. passweights.append(weight) # any other error will be raised # Define a time axis as the time axis of the first dataset. self._timeax = self._multitimeaxes[0] # Create a MultipleEofSolver to do the computations. self._solver = standard.MultivariateEof( [d.asma() for d in datasets], weights=passweights, center=center, ddof=ddof ) #: Number of EOFs in the solution. self.neofs = self._solver.neofs # Names of the input variables. self._dataset_names = map(lambda v: cdms2_name(v).replace(" ", "_"), datasets) self._dataset_ids = [dataset.id for dataset in datasets]
def grid(axis_ids, latitude=None, longitude=None, latitude_vertices=None, longitude_vertices=None, nvertices=None): """ Creates a cmor grid Usage: grid_id = grid(axis_ids,latitude,longitude,latitude_vertices=None,longitude_vertices=None) Where: axis_ids : array contianing the axes ids for this grid. latitude/longitude: the values for longitude/latitude arrays (unless it is a time varying grid) latitude_vertices/longitude_vertices: coordinates of vertices for each latitude/latitude (unless it is a time varying grid) """ if numpy.ma.isMA(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif has_cdms2 and cdms2.isVariable(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif has_cdms2 and cdms2.isVariable(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif isinstance(axis_ids, (list, tuple)): axis_ids = numpy.ascontiguousarray(axis_ids) elif not isinstance(axis_ids, numpy.ndarray): raise Exception, "Error could not convert axis_ids list to a numpy array" if numpy.ndim(axis_ids) > 1: raise Exception, "error axes list/array must be 1D" if latitude is not None: latitude = _to_numpy(latitude, 'latitude') if numpy.ndim(latitude) != len(axis_ids): raise Exception, "latitude's rank does not match number of axes passed via axis_ids" type = latitude.dtype.char nvert = 0 if not type in ['d', 'f', 'i', 'l']: raise Exception, "latitude array must be of type 'd','f','l' or 'i'" longitude = _to_numpy(longitude, 'longitude') if numpy.ndim(longitude) != len(axis_ids): raise Exception, "longitude's rank does not match number of axes passed via axis_ids" ## print 'longitude type:',longitude.dtype.char if longitude.dtype.char != type: longitude = longitude.astype(type) elif longitude is not None: raise Exception, "latitude and longitude must be BOTH an array or None" else: type = 'f' if nvertices is None: nvert = 0 else: nvert = nvertices if latitude_vertices is not None: latitude_vertices = _to_numpy(latitude_vertices, 'latitude_vertices') if numpy.ndim(latitude_vertices) != len(axis_ids) + 1: raise Exception, "latitude_vertices's rank does not match number of axes passed via axis_ids +1 (for vertices)" ## print 'latitude_vert type:',latitude_vertices.dtype.char if latitude_vertices.dtype.char != type: latitude_vertices = latitude_vertices.astype(type) nvert = latitude_vertices.shape[-1] if nvertices is not None: if nvert != nvertices: raise Exception, "you passed nvertices as: %i, but from your latitude_vertices it seems to be: %i" % ( nvertices, nvert) if longitude_vertices is not None: longitude_vertices = _to_numpy(longitude_vertices, 'longitude_vertices') if numpy.ndim(longitude_vertices) != len(axis_ids) + 1: raise Exception, "longitude_vertices's rank does not match number of axes passed via axis_ids +1 (for vertices)" ## print 'longitude_vert type:',longitude_vertices.dtype.char if longitude_vertices.dtype.char != type: longitude_vertices = longitude_vertices.astype(type) nvert2 = longitude_vertices.shape[-1] if latitude_vertices is None: nvert = nvert2 elif nvert != nvert2: raise Exception, "error in shape longitude_vertices and latitude_vertices seem to have different # of vertices: %i vs %i, %s" % ( nvert, nvert2, str(longitude_vertices.shape)) if nvertices is not None: if nvert != nvertices: raise Exception, "you passed nvertices as: %i, but from your longitude_vertices it seems to be: %i" % ( nvertices, nvert) ## if area is not None: ## if not isinstance(area,numpy.ndarray): ## try: ## area = numpy.ascontiguousarray(area.filled()) ## except: ## raise Exception, "Error could not convert area to a numpy array" ## if numpy.rank(area)!=len(axis_ids): ## raise Exception, "area's rank does not match number of axes passed via axis_ids" ## if area.dtype.char!=type: ## area = area.astype(type) n = len(axis_ids) axis_ids = axis_ids.astype('i') return _cmor.grid(n, axis_ids, type, latitude, longitude, nvert, latitude_vertices, longitude_vertices)
def axis(table_entry,units=None,length=None,coord_vals=None,cell_bounds=None,interval=None): """ Creates an cmor_axis Usage: axis_id = axis(table_entry,units=None,length=None,coord_vals=None,cell_bounds=None,interval=None) Where: table_entry: table_entry in the cmor table units: the axis units length: the number of coord_vals to actuall y use, or simply the number of coord_vals in case in index_only axes coord_vals: cmds2 axis or numpy/MV2 array (1D) cell_bounds: numpy or MV2 array, if coord_vals is a cdms2 axis then will try to obtain bounds from it interval: a string used for time axes only (???) """ if not isinstance(table_entry,str): raise Exception, "You need to pass a table_entry to match in the cmor table" if coord_vals is None: if cell_bounds is not None: raise Exception, "you passed cell_bounds but no coords" else: if has_cdms2 and isinstance(coord_vals,cdms2.axis.TransientAxis): if units is None: if hasattr(coord_vals,"units"): units = coord_vals.units if cell_bounds is None: cell_bounds = coord_vals.getBounds() if interval is None and hasattr(coord_vals,"interval"): interval = coord_vals.interval coord_vals = numpy.ascontiguousarray(coord_vals[:]) elif isinstance(coord_vals,(list,tuple)): coord_vals = numpy.ascontiguousarray(coord_vals) elif has_cdms2 and cdms2.isVariable(coord_vals): if units is None: if hasattr(coord_vals,"units"): units = coord_vals.units if interval is None and hasattr(coord_vals,"interval"): interval = coord_vals.interval coord_vals = numpy.ascontiguousarray(coord_vals.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(coord_vals): coord_vals = numpy.ascontiguousarray(coord_vals.filled()) elif numpy.ma.isMA(coord_vals): coord_vals = numpy.ascontiguousarray(coord_vals.filled()) if not isinstance(coord_vals,numpy.ndarray): raise Exception, "Error coord_vals must be an array or cdms2 axis or list/tuple" if numpy.ndim(coord_vals)>1: raise Exception, "Error, you must pass a 1D array!" if numpy.ma.isMA(cell_bounds): cell_bounds = numpy.ascontiguousarray(cell_bounds.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(cell_bounds): cell_bounds = numpy.ascontiguousarray(cell_bounds.filled()) elif has_cdms2 and cdms2.isVariable(cell_bounds): cell_bounds = numpy.ascontiguousarray(cell_bounds.filled()) elif has_cdms2 and cdms2.isVariable(cell_bounds): cell_bounds = numpy.ascontiguousarray(cell_bounds.filled()) elif isinstance(cell_bounds,(list,tuple)): cell_bounds = numpy.ascontiguousarray(cell_bounds) if cell_bounds is not None: if numpy.ndim(cell_bounds)>2: raise Exception, "Error cell_bounds rank must be at most 2" if numpy.ndim(cell_bounds)==2: if cell_bounds.shape[0]!=coord_vals.shape[0]: raise Exception, "Error, coord_vals and cell_bounds do not have the same length" if cell_bounds.shape[1]!=2: raise Exception, "Error, cell_bounds' second dimension must be of length 2" cbnds = 2 cell_bounds = numpy.ascontiguousarray(numpy.ravel(cell_bounds)) else: cbnds = 1 if len(cell_bounds)!=len(coord_vals)+1: raise Exception, "error cell_bounds are %i long and axes coord_vals are %i long this is not consistent" % (len(cell_bounds),len(coord_vals)) else: cbnds = 0 if coord_vals is not None: l = len(coord_vals) type = coord_vals.dtype.char[0] if not type in ['i','l','f','d','S']: raise Exception, "error allowed data type are: i,l,f,d or S" if type == 'S': type = 'c' cbnds = 0 for s in coord_vals: #print 'testing:',s,len(s) if len(s)>cbnds: cbnds = len(s) #cbnds+=1 else: l = 0 type = 'd' if cell_bounds is not None: if type !=cell_bounds.dtype.char: cell_bounds = cell_bounds.astype(type) if units is None: if coord_vals is not None: raise Exception, "Error you need to provide the units your coord_vals are in" else: units = "1" if interval is None: interval = "" if length is not None: l = int(length) return _cmor.axis(table_entry,units,l,coord_vals,type,cell_bounds,cbnds,interval)
def __init__(self, dataset, weights="none", center=True, ddof=1): """Create an Eof object. **Argument:** *dataset* A :py:mod:`cdms2` variable containing the data to be analyzed. Time must be the first dimension. Missing values are allowed provided that they are constant with time (e.g., values of an oceanographic field over land). **Optional arguments:** *weights* Sets the weighting method. The following values are accepted: * *"area"* : Square-root of grid cell area normalized by total area. Requires a latitude-longitude grid to be present in the input :py:mod:`cdms2` variable *dataset*. This is a fairly standard weighting strategy. If you are unsure which method to use and you have gridded data then this should be your first choice. * *"coslat"* : Square-root of cosine of latitude (*"cos_lat"* is also accepted). Requires a latitude dimension to be present in the input :py:mod:`cdms2` variable *dataset*. * *"none"* : Equal weights for all grid points (default). * *None* : Same as *"none"*. An array of weights may also be supplied instead of specifying a weighting method. *center* If *True*, the mean along the first axis of the input data set (the time-mean) will be removed prior to analysis. If *False*, the mean along the first axis will not be removed. Defaults to *True* (mean is removed). Generally this option should be set to *True* as the covariance interpretation relies on input data being anomalies with a time-mean of 0. A valid reson for turning this off would be if you have already generated an anomaly data set. Setting to *True* has the useful side-effect of propagating missing values along the time-dimension, ensuring the solver will work even if missing values occur at different locations at different times. *ddof* 'Delta degrees of freedom'. The divisor used to normalize the covariance matrix is *N - ddof* where *N* is the number of samples. Defaults to *1*. **Examples:** EOF analysis with area-weighting for the input field: >>> from eof2 import Eof >>> eofobj = Eof(field, weights="area") """ # Check that dataset is recognised by cdms2 as a variable. if not cdms2.isVariable(dataset): raise EofError("the input data must be a cdms2 variable") # Store the time axis as an instance variable. self._timeax = dataset.getTime() # Verify that a time axis was found, getTime returns None when a # time axis is not found. if self._timeax is None: raise EofError("time axis not found") # Check the dimension order of the input, time must be the first # dimension. order = dataset.getOrder() if order[0] != "t": raise EofError("time must be the first dimension") # Verify the presence of at least one spatial dimension. The # instance variable channels will also be used as a partial axis # list when constructing meta-data. It contains the spatial # dimensions. self._channels = dataset.getAxisList() self._channels.remove(self._timeax) if len(self._channels) < 1: raise EofError("one or more spatial dimensions are required") # Store the missing value attribute of the data set in an # instance variable so that it is recoverable later. self._missing_value = dataset.getMissing() # Generate an appropriate set of weights for the input dataset. There # are several weighting schemes. The "area" weighting scheme requires # a latitude-longitude grid to be present, the "cos_lat" scheme only # requires a latitude dimension. if weights in ("none", None): # No weights requested, set the weight array to None. wtarray = None else: try: # Generate a weights array of the appropriate kind, with a # shape compatible with the data set. scheme = weights.lower() wtarray = weights_array(dataset, scheme=scheme) except AttributeError: # Weights is not a string, assume it is an array. wtarray = weights except EofToolError, err: # Weights is not recognized, raise an error. raise EofError(err)
def variable(table_entry,units,axis_ids,type='f',missing_value=None,tolerance = 1.e-4,positive=None,original_name=None,history=None,comment=None): if not isinstance(table_entry,str): raise Exception, "Error you must pass a string for the variable table_entry" if not isinstance(units,str): raise Exception, "Error you must pass a string for the variable units" if original_name is not None: if not isinstance(original_name,str): raise Exception, "Error you must pass a string for the variable original_name" else: original_name = "" if history is not None: if not isinstance(history,str): raise Exception, "Error you must pass a string for the variable history" else: history = "" if comment is not None: if not isinstance(comment,str): raise Exception, "Error you must pass a string for the variable comment" else: comment = "" if numpy.ma.isMA(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif has_cdms2 and cdms2.isVariable(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif isinstance(axis_ids,(list,tuple)): axis_ids = numpy.ascontiguousarray(axis_ids) elif not isinstance(axis_ids, numpy.ndarray): raise Exception, "Error could not convert axis_ids list to a numpy array" if numpy.ndim(axis_ids)>1: raise Exception, "error axis_ids list/array must be 1D" if not isinstance(type,str): raise Exception, "error tpye must a a string" type = type.lower() if type == 's': type ='c' if not type in ["c","d","f","l","i"]: raise Exception, 'error unknown type: "%s", must be one of: "c","d","f","l","i"' ndims = len(axis_ids) if positive is None: positive = "" else: positive = str(positive) if history is None: history = "" else: history = str(history) if comment is None: comment = "" else: comment = str(comment) if not isinstance(tolerance,(float,int,numpy.float,numpy.float32,numpy.int,numpy.int32)): raise Exception, "error tolerance must be a number" tolerance = float(tolerance) if missing_value is not None: if not isinstance(missing_value,(float,int,numpy.float,numpy.float32,numpy.int,numpy.int32)): raise Exception, "error missing_value must be a number, you passed: %s" % repr(missing_value) missing_value = float(missing_value) axis_ids=axis_ids.astype('i') return _cmor.variable(table_entry,units,ndims,axis_ids,type,missing_value,tolerance,positive,original_name,history,comment)
def __call__(self, input): import numpy.ma from cdms2 import isVariable from cdms2.tvariable import TransientVariable # If input is a variable, make it a TV if isVariable(input) and not isinstance(input, TransientVariable): input = input.subSlice() isvar = isinstance(input, TransientVariable) if isvar: domain = tuple(input.getAxisList()) if self.inputGrid is not None: ingrid = self.inputGrid else: ingrid = input.getGrid() if ingrid is None: raise RegridError( "Input variable must have an associated grid.") rank = len(ingrid.shape) gridsize = ingrid.size() outgridshape = self.outputGrid.shape # Check that the grid matches the last dimension(s) of input if input.shape[-rank:] != ingrid.shape: raise RegridError( 'Last dimensions of input array must match grid shape: %s' % repr(ingrid.shape)) # this expects contiguous arrays if input.iscontiguous() is False: input = input.ascontiguous() else: rank = 1 # If not a TV, last dimension is the 'cell' dimension gridsize = input.shape[-1] outgridshape = (reduce(lambda x, y: x * y, self.outputGrid.shape, 1), ) # If input is an numpy.ma, make it Numeric if numpy.ma.isMaskedArray(input): input = input.filled() restoreShape = input.shape[:-rank] restoreLen = reduce(lambda x, y: x * y, restoreShape, 1) oldshape = input.shape newshape = (restoreLen, gridsize) input.shape = newshape # Regrid output = self.regrid(input) # Reshape output and restore input shape input.shape = oldshape outshape = restoreShape + outgridshape output.shape = outshape # If the input was a variable, so is the output if isvar: outdomain = domain[:-rank] + (self.outputGrid, ) output = TransientVariable(output, axes=outdomain) return output
def zfactor(zaxis_id,zfactor_name,units="",axis_ids=None,type=None,zfactor_values=None,zfactor_bounds=None): if not isinstance(zaxis_id,(int,numpy.int,numpy.int32)): raise Exception, "error zaxis_id must be a number" zaxis_id = int(zaxis_id) if not isinstance(zfactor_name,str): raise Exception, "Error you must pass a string for the variable zfactor_name" if not isinstance(units,str): raise Exception, "Error you must pass a string for the variable units" if numpy.ma.isMA(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif has_cdms2 and cdms2.isVariable(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif has_cdms2 and cdms2.isVariable(axis_ids): axis_ids = numpy.ascontiguousarray(axis_ids.filled()) elif isinstance(axis_ids,(list,tuple)): axis_ids = numpy.ascontiguousarray(axis_ids) elif axis_ids is None: pass elif isinstance(axis_ids,(int,numpy.int,numpy.int32)): axis_ids = numpy.array([axis_ids,]) elif not isinstance(axis_ids, numpy.ndarray): raise Exception, "Error could not convert axis_ids list to a numpy array" if numpy.ndim(axis_ids)>1: raise Exception, "error axis_ids list/array must be 1D" if axis_ids is None: ndims = 0 axis_ids = numpy.array(1) else: ndims = len(axis_ids) ## if ndims>1 and zfactor_values is not None: ## raise Exception, "Error you can only pass zfactor_values for zfactor with rank <=1" ## if ndims>1 and zfactor_bounds is not None: ## raise Exception, "Error you can only pass zfactor_bounds for zfactor with rank <=1" if zfactor_values is not None: if isinstance(zfactor_values,(float,int,numpy.float,numpy.float32,numpy.int,numpy.int32)): zfactor_values = numpy.array((zfactor_values,)) elif numpy.ma.isMA(zfactor_values): zfactor_values = numpy.ascontiguousarray(zfactor_values.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(zfactor_values): zfactor_values = numpy.ascontiguousarray(zfactor_values.filled()) elif has_cdms2 and cdms2.isVariable(zfactor_values): zfactor_values = numpy.ascontiguousarray(zfactor_values.filled()) elif isinstance(zfactor_values,(list,tuple)): zfactor_values = numpy.ascontiguousarray(zfactor_values) elif not isinstance(zfactor_values, numpy.ndarray): raise Exception, "Error could not convert zfactor_values to a numpy array" if type is None: try: type = zfactor_values.dtype.char except: if isinstance(zfactor_values,(float,numpy.float,numpy.float32)): type = 'f' elif isinstance(zfactor_values,(int,numpy.int,numpy.int32)): type = 'd' else: raise Exception, "Error unknown type for zfactor_values: %s" % repr(zfactor_values) elif type is None: type='d' if not isinstance(type,str): raise Exception, "error tpye must a a string" type = type.lower() if type == 's': type ='c' if not type in ["c","d","f","l","i"]: raise Exception, 'error unknown type: "%s", must be one of: "c","d","f","l","i"' if zfactor_bounds is not None: if numpy.ma.isMA(zfactor_bounds): zfactor_bounds = numpy.ascontiguousarray(zfactor_bounds.filled()) elif has_oldma and numpy.oldnumeric.ma.isMA(zfactor_bounds): zfactor_bounds = numpy.ascontiguousarray(zfactor_bounds.filled()) elif has_cdms2 and cdms2.isVariable(zfactor_bounds): zfactor_bounds = numpy.ascontiguousarray(zfactor_bounds.filled()) elif isinstance(zfactor_bounds,(list,tuple)): zfactor_bounds = numpy.ascontiguousarray(zfactor_bounds) elif not isinstance(zfactor_bounds, numpy.ndarray): raise Exception, "Error could not convert zfactor_bounds to a numpy array" if numpy.ndim(zfactor_bounds)>2: raise Exception, "error zfactor_bounds must be rank 2 at most" elif numpy.ndim(zfactor_bounds)==2: if zfactor_bounds.shape[1]!=2: raise Exception, "error zfactor_bounds' 2nd dimension must be of length 2" bnds =[] b = zfactor_bounds[0] for i in range(zfactor_bounds.shape[0]): b = zfactor_bounds[i] bnds.append(b[0]) if (i<zfactor_bounds.shape[0]-1) and (b[1]!=zfactor_bounds[i+1][0]): raise Exception, "error zfactor_bounds have gaps between them" bnds.append(zfactor_bounds[-1][1]) zfactor_bounds=numpy.array(bnds) axis_ids = axis_ids.astype('i') ## print "sending",zaxis_id,zfactor_name,units,ndims,axis_ids,type,zfactor_values,zfactor_bounds return _cmor.zfactor(zaxis_id,zfactor_name,units,ndims,axis_ids,type,zfactor_values,zfactor_bounds)
def putMetadata(meta, tv, **args): import cdms2 as cdms if cdms.isVariable(meta): meta = getMetadata(meta, **args) return cdms.createVariable(tv, axes=meta[0], attributes=meta[1])
def projectField(self, field, neofs=None, eofscaling=0, weighted=True): """Project a field onto the EOFs. Given a data set, projects it onto the EOFs to generate a corresponding set of pseudo-PCs. **Argument:** *field* A `cdms2` variable containing the field to project onto the EOFs. It must have the same corresponding spatial dimensions (including missing values in the same places) as the `Eof` input *dataset*. It may have a different length time dimension to the `Eof` input *dataset* or no time dimension at all. If a time dimension exists it must be the first dimension. **Optional arguments:** *neofs* Number of EOFs to project onto. Defaults to all EOFs. If the number of EOFs requested is more than the number that are available, then the field will be projected onto all available EOFs. *eofscaling* Set the scaling of the EOFs that are projected onto. The following values are accepted: * *0* : Un-scaled EOFs (default). * *1* : EOFs are divided by the square-root of their eigenvalue. * *2* : EOFs are multiplied by the square-root of their eigenvalue. *weighted* If *True* then the field is weighted using the same weights used for the EOF analysis prior to projection. If *False* then no weighting is applied. Defaults to *True* (weighting is applied). Generally only the default setting should be used. **Returns:** *pseudo_pcs* A `cdms2` variable containing the pseudo-PCs. The PCs are numbered from 0 to *neofs* - 1. **Examples:** Project a field onto all EOFs:: pseudo_pcs = solver.projectField(field) Project fields onto the three leading EOFs:: pseudo_pcs = solver.projectField(field, neofs=3) """ # Check that field is recognised by cdms2 as a variable. if not cdms2.isVariable(field): raise TypeError('the input field must be a cdms2 variable') dataset_name = cdms2_name(field).replace(' ', '_') # Compute the projected PCs. pcs = self._solver.projectField(field.asma(), neofs=neofs, eofscaling=eofscaling, weighted=weighted) # Construct the required axes. if pcs.ndim == 2: # 2D PCs require a time axis and a PC axis. pcsax = cdms2.createAxis(range(pcs.shape[1]), id='pc') pcsax.long_name = 'pc_number' timeax = field.getAxis(0) # time is assumed to be first anyway axlist = [timeax, pcsax] else: # 1D PCs require only a PC axis. pcsax = cdms2.createAxis(range(pcs.shape[0]), id='pc') pcsax.long_name = 'pc_number' axlist = [pcsax] # Apply meta data to the projected PCs. pcs = cdms2.createVariable(pcs, id='pseudo_pcs', axes=axlist) pcs.long_name = '{:s}_pseudo_pcs'.format(dataset_name) return pcs