#!/usr/bin/python -tt #======================================================================= # General Documentation """Single-function module. See function docstring for description. """ #----------------------------------------------------------------------- # Additional Documentation # # RCS Revision Code: # $Id: vapor_press.py,v 1.3 2004/04/06 20:07:50 jlin Exp $ # # Modification History: # - 20 Oct 2003: Original by Johnny Lin, Computation Institute, # University of Chicago. Email: air_jlin@yahoo.com. Passed # passably reasonable tests. # - 18 Nov 2003: Added capability to accomodate missing values. # Passed passably reasonable tests. # # Notes: # - Written for Python 2.2. # - Module docstrings can be tested using the doctest module. To # test, execute "python vapor_press.py". # - When I refer to a source code variable in source code comments, # and it is not clear from context I am talking about a source # code variable, I enclose the variable in pipes (e.g. |missing|). # - Non-"built-in" packages and modules required: atmqty # # Copyright (c) 2003-2004 by Johnny Lin. For licensing, distribution # conditions, contact information, and additional documentation see # the URL http://www.johnny-lin.com/py_pkgs/atmqty/doc/. #======================================================================= #---------------- Module General Import and Declarations --------------- #- Set module version number to package version number: import package_version __version__ = package_version.version del package_version #------------------- General Function: vapor_press -------------------- def vapor_press(variables, missing=1e+20): """Calculate vapor pressure over liquid water. Method Arguments: * variables: A dictionary of input state variables, where for each key:value pair the key labels what state variable it is and the value is the state variable. The value is a Numeric floating point array of any number of dimensions and size. All state variables must be arrays of the same shape and size. Argument |variables| can have any number of items. Key values may be any value, but the values that are understood by this function include: + 'esat': Saturation vapor pressure over water [hPa]. + 'p': Total pressure [hPa]. + 'q': Specific humidity [kg/kg]. + 'r': Mixing ratio [kg/kg]. + 'RH': Relative humidity (based on esat) [fraction]. * missing: If any array in |variables| has elements that are missing values, this is the missing value value. Floating point scalar. Default is 1e+20. Output: * Vapor pressure [hPa]. Numeric array of same dimensions and size as state variables in the argument. If there are any missing values in output, those values are set to the value in argument |missing| from the input. If there are missing values in the output due to math errors and |missing| is set to None, output will fill those missing values with the MA default value of 1e+20. Vapor pressure can be calculated from a variety of different combinations of state variables. In this function, the follow- ing combinations are supported: * Mixing ratio and total pressure, * Specific humidity and total pressure, * Relative humidity and saturation vapor pressure over water. The function will automatically apply the correct equation depending on what key values are available in the |variables| dictionary. An error is returned if none of the above combina- tions are present in |variables|. References: * Emanuel, K. A. (1994): Atmospheric Convection. New York, NY: Oxford University Press, 580 pp. * Wallace, J. M., and P. V. Hobbs (1977): Atmospheric Science: An Introductory Survey. San Diego, CA: Academic Press, ISBN 0-12-732950-1, 467 pp. Example without missing values: >>> from vapor_press import vapor_press >>> import Numeric as N >>> p = N.array([1026.8, 840.2, 640.3, 450.2]) >>> r = N.array([5.5e-3, 5.4e-3, 6.2e-3, 3.9e-3]) >>> e = vapor_press({'p':p, 'r':r}) >>> ['%.9g' % e[i] for i in range(len(e))] ['9.00051379', '7.23209979', '6.31989271', '2.80541885'] Example with missing values: >>> from vapor_press import vapor_press >>> import Numeric as N >>> p = N.array([1026.8, 840.2, 1e+20, 450.2]) >>> r = N.array([5.5e-3, 5.4e-3, 6.2e-3, 3.9e-3]) >>> e = vapor_press({'p':p, 'r':r}, missing=1e+20) >>> ['%.9g' % e[i] for i in range(len(e))] ['9.00051379', '7.23209979', '1e+20', '2.80541885'] """ #- Import statements: import atmqty import MA import Numeric as N from atmconst import AtmConst from is_numeric_float import is_numeric_float #- Atmospheric constants: const = AtmConst() #- Check input is of the correct type: for akey in variables.keys(): if is_numeric_float(variables[akey]) != 1: raise TypeError, "vapor_press: Arg not Numeric floating" #- Calculate. vapor pressure (vp) depending on what the inputs # are (change needed variables to MA, setting them to the input # value, adding a mask if there are missing values): # * Option 1: r, p specified (Wallace and Hobbs, eqn. 2.61): if (variables.has_key('r') == 1) and (variables.has_key('p') == 1): if missing == None: r = MA.masked_array(variables['r']) p = MA.masked_array(variables['p']) else: r = MA.masked_values(variables['r'], missing, copy=0) p = MA.masked_values(variables['p'], missing, copy=0) vp = r * p / (r + const.epsilon) # * Option 2: q, p specified (Emanuel eqn. 4.1.4): elif (variables.has_key('q') == 1) and (variables.has_key('p') == 1): if missing == None: q = MA.masked_array(variables['q']) p = MA.masked_array(variables['p']) else: q = MA.masked_values(variables['q'], missing, copy=0) p = MA.masked_values(variables['p'], missing, copy=0) vp = (q * p) / ( const.epsilon + (q*(1.0-const.epsilon)) ) # * Option 3: RH, esat specified (Emanuel eqn 4.1.5): elif (variables.has_key('RH') == 1) and (variables.has_key('esat') == 1): if missing == None: RH = MA.masked_array(variables['RH']) esat = MA.masked_array(variables['esat']) else: RH = MA.masked_values(variables['RH'], missing, copy=0) esat = MA.masked_values(variables['esat'], missing, copy=0) vp = RH * esat # * Option 4: Bad input keys, return an error: else: raise ValueError, "vapor_press: Bad input keys" #- Return vapor pressure: return MA.filled(vp, missing) #-------------------------- Main: Test Module ------------------------- #- Define additional examples for doctest to use: __test__ = { 'Additional Example 1': """ >>> from vapor_press import vapor_press >>> import Numeric as N >>> p = N.array([1026.8, 450.2]) >>> q = N.array([5.5e-3/(1.+5.5e-3), 3.9e-3/(1.+3.9e-3)]) >>> e = vapor_press({'p':p, 'q':q}) >>> ['%.9g' % e[i] for i in range(len(e))] ['9.00051379', '2.80541885'] >>> p = N.array([1e+20, 450.2]) >>> e = vapor_press({'p':p, 'q':q}, missing=1e+20) >>> ['%.9g' % e[i] for i in range(len(e))] ['1e+20', '2.80541885'] """, 'Additional Example 2': """ >>> from vapor_press import vapor_press >>> import Numeric as N >>> RH = N.array([0.8, 0.5, 0.3, 0.4]) >>> esat = N.array([20.0, 18.2, 3.5, 2.2]) >>> e = vapor_press({'RH':RH, 'esat':esat}) >>> ['%.9g' % e[i] for i in range(len(e))] ['16', '9.1', '1.05', '0.88'] >>> esat = N.array([20.0, 1e+20, 3.5, 2.2]) >>> e = vapor_press({'RH':RH, 'esat':esat}, missing=1e+20) >>> ['%.9g' % e[i] for i in range(len(e))] ['16', '1e+20', '1.05', '0.88'] """ } #- Execute doctest if module is run from command line: if __name__ == "__main__": """Test the module. Tests the examples in all the module documentation strings, plus __test__. The parent directory is added to sys.path for this module testing case. """ import doctest, sys, os sys.path.append(os.pardir) doctest.testmod(sys.modules[__name__]) # ===== end file =====