#!/usr/bin/python -tt #======================================================================= # General Documentation """Define State class for model Field objects. The State class is a collection of Field class objects at the same instance in time or time "tendency" (actually the time differential multiplied by one time step, i.e. the amount to add to a current variable in order to obtain the variable one timestep later). """ #----------------------------------------------------------------------- # Additional Documentation # # RCS Revision Code: # $Id: state.py,v 1.1.1.1 2005/01/13 00:15:42 jlin Exp $ # # Modification History: # - 12 Jan 2005: Original by Johnny Lin, Computation Institute, # University of Chicago. Passed passably reasonable tests. # # Notes: # - Written for Python 2.2. # - See import statements throughout module for dependencies. # # Copyright (c) 2004-2005 by Johnny Lin. For licensing, distribution # conditions, contact information, and additional documentation see # the URL http://geosci.uchicago.edu/csc/modelutil/doc/. #======================================================================= #---------------- Module General Import and Declarations --------------- #- Set module version to package version: import package_version __version__ = package_version.version __author__ = package_version.author __date__ = package_version.date __credits__ = package_version.credits del package_version #- If you're importing this module in testing mode, or you're running # pydoc on this module via the command line, import user-specific # settings to make sure any non-standard libraries are found: import os, sys if (__name__ == "__main__") or \ ("pydoc" in os.path.basename(sys.argv[0])): import user del os, sys #- Import Numeric/numarray as appropriate (see gemath.num_settings # module for details as to what gets imported): from gemath.num_settings import * #- Import other packages: import copy import field #- Create module variable _typeField which holds the type of Field # class objects: _typeField = type( field.Field(0) ) #------------------------- State Class: Header ------------------------ class State(object): """Collection of Field objects at one time. The State class is a container that is a collection of Field class objects at the same instance in time or time "tendency" (actually the time differential multiplied by one time step, i.e. the amount to add to a current variable in order to obtain the variable one timestep later). The State keys for mapping the Field objects are the id attributes in the Field objects; the keys in a State object are unique. Public Instance Attributes: * id: This identifier contains information about whether the con- stituent Fields are full variables (i.e. not a "tendency") or "tendencies" and the relative time the State is at. The follow- ing values are possible: "tm1": Full variable at time equals 0 minus one timestep. "t0": Full variable at time equals 0. "tp1": Full variable at time equals 0 plus one timestep. "tend1": Value to add to a "t0" State object to obtain a "tp1" State object. Taken to be at the same time as id "t0". The number after "m" or "p" can be values other than "1", and denote the number of timesteps added to or subtracted from time 0. String. Default is None. * long_name: Description of the object, containing information about the collection of Field objects. Default is None. * time: Time of the State. Floating or integer. In units of attribute time_units. Default is None. * time_units: Units of the attribute time. String. Default is None. All the instance attributes can be set directly or via keywords passed in the instantiation parameter list. See the __init__ function docstring for details. Example: >>> from field import Field >>> data1 = [1.1, 3.0, -4.8, 2.9, 2.1] >>> data2 = [31.1, 0.4, 4.0, -4.9, 9.1] >>> data3 = [3.1, 2.4, 4.9, 8.1, -9.2] >>> f1 = Field(data1, id='u', units='m/s', axis=['Latitude']) >>> f2 = Field(data2, id='v', units='m/s', axis=['Latitude']) >>> f3 = Field(data3, id='w', units='m/s', axis=['Latitude']) >>> s = State(f1, f2, f3, long_name='winds', id='t0') >>> print s.id t0 >>> print s.long_name winds >>> print s.time None >>> print s.keys() ['u', 'w', 'v'] >>> print type(s['u']) >>> print s['v'].id v >>> ['%.6g' % s['v'][i] for i in range(len(s['v']))] ['31.1', '0.4', '4', '-4.9', '9.1'] """ #----------------- State Class: Initialization Method ----------------- def __init__(self, *args, **kwds): """Initialize class object. Positional Arguments: * All arguments of this initialization function are assumed to be Field objects which are put into the container's data structure, private attribute _data. If any of the arguments have the same id attribute, only the last Field object in the argument list with that id will be stored; the rest will be ignored. Keyword Arguments: * All keywords are attributes of the instance. Any other key- words in the calling line are ignored. See the class doc- string for details. The private variable _data is the data structure that holds all the Fields. The keys to _data (accessible via the public method keys) are the Field.id attributes and the values of _data (accessible via the public function values) are Field objects. """ self._ok_init_kwds = ('id', 'long_name', 'time', 'time_units') self._data = {} #- Note: _data is just a dictionary. for an_arg in args: self._data[an_arg.id] = an_arg for akey in self._ok_init_kwds: if kwds.has_key(akey): self.__dict__[akey] = kwds[akey] else: self.__dict__[akey] = None #------------------- State Class: Container Methods ------------------- def __contains__(self, item): return self._data.has_key(item) def __delitem__(self, key): del self._data[key] def __getitem__(self, key): return self._data[key] def __iter__(self): """Returns an iterkeys equivalent iterator over State data.""" return self._data.iterkeys() def __len__(self): return len(self._data) def __setitem__(self, key, value): self._data[key] = value #-------------------- State Class: Mapping Methods -------------------- def clear(self): """Clears all Field objects in the State object.""" self._data.clear() def has_key(self, key): """Returns True if Field object of id key is in State object.""" return self._data.has_key(key) def items(self): """Returns copy of list of all Field items in State object. The copy is a shallow copy (I think) and thus references to other objects are not copied recursively. """ return self._data.items() def keys(self): """Returns copy of list of all Field object ids in State object. The copy is a shallow copy (I think) and thus references to other objects are not copied recursively. """ return self._data.keys() def values(self): """Returns copy of list of all Field objects in State object. The copy is a shallow copy (I think) and thus references to other objects are not copied recursively. """ return self._data.values() #---------------------- State Class: add Method ----------------------- def add(self, *args): """Add/overwrite Field objects given in args to State object. Field objects specified in arguments are added by reference, not by copy. Positional Arguments: * All arguments are Field objects and are added to the State object self in the order they are given in the argument list. The list of arguments should have unique id attributes; an exception is thrown if this is not true. If self already has a Field object with the same id as an object in args, the object in args replaces the object in self. """ #- Check list of arguments does not contain Fields with dupli- # cate ids: list_ids = [anarg.id for anarg in args] for anid in list_ids: if list_ids.count(anid) != 1: raise ValueError, "Field list has duplicate ids" #- Add Field objects: for aField in args: if not isinstance(aField, field.Field): raise TypeError, "Adding a non-Field object" else: self[aField.id] = aField #----------------- State Class: Various Copy Methods ------------------ def copy(self): """Returns deepcopy of State object.""" return copy.deepcopy(self) def copymeta(self): """Returns deepcopy of State object metadata. The entire State object is copied, except for the Field data held in the State container. Thus, the returned State object contains no Field object data, just State metadata. """ tmp = State() for akey in self.__dict__.keys(): if akey != '_data': tmp.__dict__[akey] = copy.deepcopy(self.__dict__[akey]) else: pass return tmp #----------------- State Class: is_conformable Method ----------------- def is_conformable(self, ignore=None, include=None): """Returns True if all Field objects are conformable. Method examines the shape of each Field object in the State object and returns True if all Field objects are conformable. The Field objects are conformable if their data arrays all have the same shape. Scalars and one-element array Field objects are assumed to be conformable to any sized array. Field objects that are axes (i.e. extra_meta.isaxis is True) are not compared. Note: Part of the conformability test uses the Numeric/ numarray function allclose on array shapes. If the allclose test returns False or throws an exception for any reason (not just ValueError, which occurs for different shapes), this method returns False. Keyword Input Parameters: * ignore: A list of Field ids of Field objects in the State object to ignore in making the conformability test (if the id does not exist in the State object, there's nothing to ignore and the check continues on). These Field objects are not modified in any way in the State object. Default is None. * include: A list of Field objects to include as being a part of the State object for the purposes of making the conformability test. These Field objects are assumed to not be a part of the State object, nor are they added into the State object. The include objects can have ids that are the same as Field objects in the State object. In those cases, this method uses the include objects instead of the same-named objects in State. Default is None. Examples: >>> data1 = N.array([1.1, 3.0, -4.8, 2.9, 2.1]) >>> data2 = N.array([[31.1, 0.4], [4.0, -4.9]]) >>> data3 = N.array([[-1.1, 3.4], [9.0, -8.2]]) >>> f1 = field.Field(data1, id='Ts', units='K') >>> f2 = field.Field(data2, id='u', units='m/s') >>> f3 = field.Field(data3, id='v', units='m/s') >>> s = State(f1, f2, id='t0') >>> print s.is_conformable() False >>> f1 = field.Field(1.1, id='Ts', units='K') >>> s.add(f1) >>> print s.is_conformable() True >>> print s.is_conformable(include=[f3]) True >>> f1 = field.Field(data1, id='Ts', units='K') >>> s.add(f1, f3) >>> print s.is_conformable(ignore=['Ts']) True """ prev_shape = None #- Shape of last non-size1 aField object #- Create list of all Field objects ids to examine # (list_all_Field_key), taking into account keywords # ignore and include: list_all_Field_key = self.keys() if type(ignore) == type(None): pass else: if type(ignore) != type([]): raise TypeError, "Not a list" for akey in ignore: try: idx = list_all_Field_key.index(akey) tmp = list_all_Field_key.pop(idx) del tmp except ValueError: pass if type(include) == type(None): include_key = [] else: if type(include) != type([]): raise TypeError, "Not a list" include_key = [aField.id for aField in include] list_all_Field_key = list_all_Field_key + include_key #- Loop through all Field objects to examine (if is an axis, skip # and go to the next Field object): for aFieldkey in list_all_Field_key: if aFieldkey in include_key: for aninclude in include: if aFieldkey == aninclude.id: aField = aninclude break else: aField = self[aFieldkey] if hasattr(aField.extra_meta, 'isaxis'): if aField.extra_meta.isaxis: continue if not aField.is_size1(): #- Test if is scalar/1-element if prev_shape != None: try: if N.allclose( prev_shape \ , N.array(field.shape(aField)) ): pass else: return False except: return False else: prev_shape = N.array(field.shape(aField)) #- Default is to return True: return True #------------------- State Class: max_shape Method -------------------- def max_shape(self): """Returns shape of array needed to hold all non-axis Fields. Method examines the shape of each Field object in the State object (for which extra_meta.isaxis != True) and creates a tuple that has the number of dimensions of the largest Field object data array. Each dimension in this returned shape tuple is the maximum size of all non-axis Field objects for that dimension. If every Field object in the State object is has extra_meta.isaxis == True, an empty tuple is returned. Example: >>> data1 = N.array([1.1, 3.0, -4.8, 2.9, 2.1]) >>> data2 = N.array([[31.1, 0.4], [4.0, -4.9]]) >>> f1 = field.Field(data1, id='Ts', units='K') >>> f2 = field.Field(data2, id='v', units='m/s') >>> s = State(f1, f2, id='t0') >>> print s.max_shape() (5, 2) """ tmp_max_shape = [] #- Initialize output tuple as list for akey in self.keys(): if hasattr(self[akey].extra_meta, 'isaxis') and \ self[akey].extra_meta.isaxis: pass else: ashape = field.shape(self[akey]) if len(ashape) > len(tmp_max_shape): #- Add dimensions for i in range(len(ashape)-len(tmp_max_shape)): tmp_max_shape.append(0) for i in range(len(ashape)): #- Set to max. dimen. tmp_max_shape[i] = max([tmp_max_shape[i], ashape[i]]) return tuple(tmp_max_shape) #-------------- State Class: meta_ok_to_interface Method -------------- def meta_ok_to_interface(self, IMobj, check_long_name=False): """Returns True if metadata passes checks for interfaces. Tests whether the Field objects metadata in the State object passes consistency checks in accordance with the description given in InterfaceMeta object IMobj. If all the Field objects pass, this method returns True. See the docstring for the Field class for details as to what the consistency checks entail. Positional Input Argument: * IMobj: InterfaceMeta object that defines the accepted metadata that you wish to check this State variable's Field variable's metadata against. For details see: http://geosci.uchicago.edu/csc/modelutil/doc/imeta.html Keyword Input Arguments: * check_long_name: If set to True, the method not only checks units but also long_name. Default is False. """ for aobjkey in self.keys(): aobj = self[aobjkey] if not aobj.meta_ok_to_interface( IMobj \ , check_long_name=check_long_name ): return False return True #----------------- State Class: Various Subset Methods ---------------- def copysubset(self, keylist): """Returns copy of a subset of the State object. Returns a new State object that consists of only those Field variables that have a key given in keylist. All contents of the new State object (including Field data) are deep copies of the elements of the original State object. Positional input argument: * keylist: A list or tuple of keys (or a single scalar key) that specify the Field objects to include in the returned State object. The values of these keys are equivalent to the id attribute of the Field objects. If any of the Field keys in keylist do not exist in self, a KeyError exception is thrown. """ if (type(keylist) != type([])) and (type(keylist) != type(())): thekeys = [keylist] else: thekeys = keylist tmp = self.copymeta() for akey in thekeys: tmp.add(copy.deepcopy( self[akey] )) return tmp def subset(self, keylist): """Reference a subset of the State object. Returns a new State object that consists of only those Field variables that have a key given in keylist. Though the State object is new, the Field objects it holds are references (not copies) to the corresponding Field objects held in the origin- al State object container. Other attributes in the returned State object are a deep copy of the elements in the original State object. Positional input argument: * keylist: A list or tuple of keys (or a single scalar key) that specify the Field objects to include in the returned State object. The values of these keys are equivalent to the id attribute of the Field objects. If any of the Field keys in keylist do not exist in self, a KeyError exception is thrown. """ if (type(keylist) != type([])) and (type(keylist) != type(())): thekeys = [keylist] else: thekeys = keylist tmp = self.copymeta() for akey in thekeys: tmp.add(self[akey]) return tmp #------------------ State Class: More Public Methods ------------------ def refdata(self): """Returns reference to data of State object. This returns a reference to the private attribute _data, which is a dictionary. """ return self._data def setdata(self, data): """Reference State private _data attribute to data. This makes a reference of data to the private attribute _data, which is a dictionary. Thus, argument data must be a diction- ary. """ self._data = data def wrap(self): """Connect the MPI parallel subdomains of all Field variables. Runs through all Field variables in the State variable and ex- ecutes the wrap method for each Field. """ for aField in self.values(): aField.wrap() #-------------------------- Main: Test Module ------------------------- __test__ = { 'Additional Example 1': """ #- Initialize a State object: >>> from field import Field >>> data1 = [1.1, 3.0, -4.8, 2.9, 2.1] >>> data2 = [31.1, 0.4, 4.0, -4.9, 9.1] >>> data3 = [3.1, 2.4, 4.9, 8.1, -9.2] >>> f1 = Field(data1, id='u', units='m/s', axis=['Latitude']) >>> f2 = Field(data2, id='v', units='m/s', axis=['Latitude']) >>> f3 = Field(data3, id='w', units='m/s', axis=['Latitude']) >>> s = State(f1, f2, f3, id='t0') >>> print s.long_name None >>> print s.time None >>> print s.time_units None >>> print s.id t0 #- Test container methods: >>> print 'u' in s True >>> print 'q' in s False >>> print s.keys() ['u', 'w', 'v'] >>> del s['w'] >>> print s.keys() ['u', 'v'] >>> del s['q'] Traceback (most recent call last): ... KeyError: 'q' >>> print type(s['u']) >>> print s['u'].id u >>> [a for a in s] ['u', 'v'] >>> len(s) 2 >>> s['w'] = f3 >>> print s.keys() ['u', 'w', 'v'] >>> ['%.6g' % s['w'][i] for i in range(len(s['w']))] ['3.1', '2.4', '4.9', '8.1', '-9.2'] >>> fnew = f2.copy() >>> fnew.id = 'w' >>> s['w'] = fnew >>> ['%.6g' % s['w'][i] for i in range(len(s['w']))] ['31.1', '0.4', '4', '-4.9', '9.1'] >>> s['w'] = f3 #- Test mapping methods: >>> print s.keys() ['u', 'w', 'v'] >>> s.clear() >>> print s.keys() [] >>> print s._data {} >>> st = State(f1, f2, f3, id='t0') >>> print st.has_key('q') False >>> print st.has_key('v') True >>> items = st.items() >>> print items[0][0] u >>> print type(items[0][1]) >>> print st.keys() ['u', 'w', 'v'] >>> print type(st.values()[1]) #- Test various copy methods: >>> data1 = N.array([1.1, 3.0, -4.8, 2.9, 2.1]) >>> data2 = N.array([31.1, 0.4, 4.0, -4.9, 9.1]) >>> data3 = N.array([3.1, 2.4, 4.9, 8.1, -9.2]) / 2.0 >>> f1 = Field(data1, id='u', units='m/s', axis=['Latitude']) >>> f2 = Field(data2, id='v', units='m/s', axis=['Latitude']) >>> f3 = Field(data3, id='w', units='m/s', axis=['Latitude']) >>> s = State(f1, f2, f3, id='t0') >>> scopy = s.copy() >>> ['%.6g' % s['w'][i] for i in range(len(s['w']))] ['1.55', '1.2', '2.45', '4.05', '-4.6'] >>> ['%.6g' % scopy['w'][i] for i in range(len(scopy['w']))] ['1.55', '1.2', '2.45', '4.05', '-4.6'] >>> print scopy.id == s.id True >>> print scopy.id is s.id True >>> s.id = 'new' >>> print scopy.id == s.id False >>> print scopy.id is s.id False >>> sref = s >>> print sref.id == s.id True >>> print sref.id is s.id True >>> sref.id = 'newer' >>> print sref.id == s.id True >>> print sref.id is s.id True >>> del sref, s >>> scm = scopy.copymeta() >>> print scm.__dict__['_data'] {} >>> print len(scopy.__dict__['_data']) 3 >>> print scm.time_units == scopy.time_units True >>> print scm.id == scopy.id True >>> print scm.id is scopy.id True >>> scm.id = 'newest' >>> print scm.id == scopy.id False #- Test various subset methods: >>> data1 = N.array([1.1, 3.0, -4.8, 2.9, 2.1]) >>> data2 = N.array([31.1, 0.4, 4.0, -4.9, 9.1]) >>> data3 = N.array([3.1, 2.4, 4.9, 8.1, -9.2]) / 2.0 >>> f1 = Field(data1, id='u', units='m/s', axis=['Latitude']) >>> f2 = Field(data2, id='v', units='m/s', axis=['Latitude']) >>> f3 = Field(data3, id='w', units='m/s', axis=['Latitude']) >>> s = State(f1, f2, f3, id='t0') >>> snew = s.subset(['u', 'v']) >>> print s.keys() ['u', 'w', 'v'] >>> print snew.keys() ['u', 'v'] >>> print s.id == snew.id True >>> ['%.6g' % snew['v'][i] for i in range(len(snew['v']))] ['31.1', '0.4', '4', '-4.9', '9.1'] >>> f2[1] = -22.3 >>> ['%.6g' % s['v'][i] for i in range(len(s['v']))] ['31.1', '-22.3', '4', '-4.9', '9.1'] >>> ['%.6g' % snew['v'][i] for i in range(len(snew['v']))] ['31.1', '-22.3', '4', '-4.9', '9.1'] >>> s['v'][2] = 88.9 >>> ['%.6g' % s['v'][i] for i in range(len(s['v']))] ['31.1', '-22.3', '88.9', '-4.9', '9.1'] >>> ['%.6g' % snew['v'][i] for i in range(len(snew['v']))] ['31.1', '-22.3', '88.9', '-4.9', '9.1'] >>> snew = s.subset(('u', 'v')) >>> print s.keys() ['u', 'w', 'v'] >>> print snew.keys() ['u', 'v'] >>> print s.id == snew.id True >>> data1 = N.array([1.1, 3.0, -4.8, 2.9, 2.1]) >>> data2 = N.array([31.1, -22.3, 4.0, -4.9, 9.1]) >>> data3 = N.array([3.1, 2.4, 4.9, 8.1, -9.2]) / 2.0 >>> f1 = Field(data1, id='u', units='m/s', axis=['Latitude']) >>> f2 = Field(data2, id='v', units='m/s', axis=['Latitude']) >>> f3 = Field(data3, id='w', units='m/s', axis=['Latitude']) >>> s = State(f1, f2, f3, id='t0') >>> snew = s.copysubset(['u', 'v']) >>> print s.keys() ['u', 'w', 'v'] >>> print snew.keys() ['u', 'v'] >>> print s.id == snew.id True >>> f2[1] = 982.1 >>> ['%.6g' % s['v'][i] for i in range(len(s['v']))] ['31.1', '982.1', '4', '-4.9', '9.1'] >>> ['%.6g' % snew['v'][i] for i in range(len(snew['v']))] ['31.1', '-22.3', '4', '-4.9', '9.1'] >>> s['v'][4] = 333.5 >>> ['%.6g' % s['v'][i] for i in range(len(s['v']))] ['31.1', '982.1', '4', '-4.9', '333.5'] >>> ['%.6g' % snew['v'][i] for i in range(len(snew['v']))] ['31.1', '-22.3', '4', '-4.9', '9.1'] >>> snew = s.copysubset(('u', 'v')) >>> print s.keys() ['u', 'w', 'v'] >>> print snew.keys() ['u', 'v'] >>> print s.id == snew.id True #- More tests of is_conformable method: >>> data1 = N.array([1.1, 3.0, -4.8, 2.9, 2.1]) >>> data2 = N.array([-4.9]) >>> f1 = field.Field(data1, id='Ts', units='K') >>> f2 = field.Field(data2, id='v', units='m/s') >>> s = State(f1, f2, id='t0') >>> print s.is_conformable() True >>> data1 = N.array([1.1, 3.0, -4.8, 2.9, 2.1]) >>> data2 = N.array([-4.9]) >>> data3 = N.array([1.1, 9.0, -1.8, 9.9, 2.1]) >>> f1 = field.Field(data1, id='Ts', units='K') >>> f2 = field.Field(data2, id='v', units='m/s') >>> f3 = field.Field(data3, id='u', units='m/s') >>> s = State(f1, f2, f3, id='t0') >>> print s.is_conformable() True >>> data1 = N.reshape(N.array([1.1, 3.0, -4.8, 2.9, 1.2, 2.1]), (2,3)) >>> data2 = N.array([-4.9]) >>> data3 = N.reshape(N.array([9.2, 1.1, 9.0, -1.8, 9.9, 2.1]), (2,3)) >>> f1 = field.Field(data1, id='Ts', units='K') >>> f2 = field.Field(data2, id='v', units='m/s') >>> f3 = field.Field(data3, id='u', units='m/s') >>> s = State(f1, f2, f3, id='t0') >>> print s.is_conformable() True >>> data1 = N.reshape(N.array([1.1, 3.0, -4.8, 2.9, 1.2, 2.1]), (2,3)) >>> data2 = -4.9 >>> data3 = N.reshape(N.array([9.2, 1.1, 9.0, -1.8, 9.9, 2.1]), (2,3)) >>> f1 = field.Field(data1, id='Ts', units='K') >>> f2 = field.Field(data2, id='v', units='m/s') >>> f3 = field.Field(data3, id='u', units='m/s') >>> s = State(f1, f2, f3, id='t0') >>> print s.is_conformable() True >>> data1 = N.reshape(N.array([1.1, 3.0, -4.8, 2.9, 1.2, 2.1]), (2,3)) >>> data2 = -4.9 >>> data3 = N.array([9.2, 1.1, 9.0, -1.8, 9.9, 2.1]) >>> f1 = field.Field(data1, id='Ts', units='K') >>> f2 = field.Field(data2, id='v', units='m/s') >>> f3 = field.Field(data3, id='u', units='m/s') >>> s = State(f1, f2, f3, id='t0') >>> print s.is_conformable() False >>> data1 = N.reshape(N.array([1.1, 3.0, -4.8, 2.9, 1.2, 2.1]), (2,3)) >>> data2 = -4.9 >>> data3 = N.array([9.2, 1.1, 9.0, -1.8, 9.9, 2.1]) >>> f1 = field.Field(data1, id='Ts', units='K') >>> f2 = field.Field(data2, id='v', units='m/s') >>> f3 = field.Field(data3, id='u', units='m/s', isaxis=True) >>> s = State(f1, f2, f3, id='t0') >>> print s.is_conformable() True >>> data1 = N.reshape(N.array([1.1, 3.0, -4.8, 2.9, 1.2, 2.1]), (2,3)) >>> data2 = -4.9 >>> data3 = N.array([9.2, 1.1, 9.0, -1.8, 9.9, 2.1]) >>> f1 = field.Field(data1, id='Ts', units='K') >>> f2 = field.Field(data2, id='v', units='m/s', isaxis=True) >>> f3 = field.Field(data3, id='u', units='m/s') >>> s = State(f1, f2, f3, id='t0') >>> print s.is_conformable() False >>> data1 = N.array([1.1, 3.0, -4.8, 2.9, 1.2, 2.1]) >>> data2 = N.array([-4.9]) >>> data3 = N.reshape(N.array([9.2, 1.1, 9.0, -1.8, 9.9, 2.1]), (2,3)) >>> f1 = field.Field(data1, id='Ts', units='K') >>> f2 = field.Field(data2, id='v', units='m/s') >>> f3 = field.Field(data3, id='u', units='m/s') >>> s = State(f1, f2, f3, id='t0') >>> print s.is_conformable() False >>> print s.is_conformable(ignore=['u']) True >>> print s.is_conformable(ignore='ua') Traceback (most recent call last): ... TypeError: Not a list >>> print s.is_conformable(ignore=['ua']) False >>> print s.is_conformable(ignore=['ua', 'u']) True >>> data4 = N.reshape(N.array([-2.2, 0.1, 9.0, 7.2, 7.2, 1.1]), (2,3)) >>> f4 = field.Field(data3, id='w', units='m/s') >>> print s.is_conformable(ignore=['ua', 'u'], include=f4) Traceback (most recent call last): ... TypeError: Not a list >>> print s.is_conformable(ignore=['ua', 'u'], include=[f4]) False >>> print s.is_conformable(ignore=['', 'u'], include=[f4]) False >>> print s.is_conformable(ignore=['Ts'], include=[f4]) True >>> print s.is_conformable(ignore=['', 'Ts'], include=[f4]) True >>> print s.keys() ['u', 'Ts', 'v'] >>> data1 = N.array([1.1, 3.0, -4.8, 2.9, 1.2, 2.1]) >>> data2 = N.array([-4.9]) >>> data3 = N.reshape(N.array([9.2, 1.1, 9.0, -1.8, 9.9, 2.1]), (2,3)) >>> f1 = field.Field(data1, id='Ts', units='K') >>> f2 = field.Field(data2, id='v', units='m/s') >>> f3 = field.Field(data3, id='u', units='m/s') >>> f4 = field.Field(data1*0.2, id='u', units='m/s') >>> s = State(f1, f2, f3, id='t0') >>> print s.is_conformable() False >>> print s.is_conformable(include=[f4]) True >>> f5 = field.Field(80.2, id='u', units='m/s') >>> print s.is_conformable(include=[f5]) True #- More tests max_shape method: >>> data1 = N.array([1.1, 3.0, -4.8, 2.9, 2.1]) >>> data2 = N.array([[31.1, 0.4], [4.0, -4.9]]) >>> f1 = field.Field(data1, id='Ts', units='K') >>> f2 = field.Field(data2, id='v', units='m/s') >>> s = State(f1, f2, id='t0') >>> print s.max_shape() (5, 2) >>> data1 = N.array([1.1, 3.0, -4.8, 2.9, 2.1]) >>> data2 = N.array([[31.1, 0.4], [4.0, -4.9]]) >>> f1 = field.Field(data1, id='lat', units='degrees_north', isaxis=True) >>> f2 = field.Field(data2, id='v', units='m/s') >>> s = State(f1, f2, id='t0') >>> print s.max_shape() (2, 2) >>> data1 = N.array([1.1, 3.0, -4.8, 2.9, 2.1]) >>> data2 = N.array([21.1, 23.0, -124.8, 2.9, 62.1]) >>> f1 = field.Field(data1, id='lat', units='degrees_north', isaxis=True) >>> f2 = field.Field(data2, id='lon', units='degrees_east', isaxis=True) >>> s = State(f1, f2, id='t0') >>> print s.max_shape() () """} if __name__ == "__main__": """Test the module documentation strings and __test__. """ import doctest, sys, os sys.path.append(os.pardir) doctest.testmod(sys.modules[__name__]) # ===== end file =====