def mixr(t,p): """mx = mixr(t,p) Computes the saturation mixing ratio given ambient temperature(s) (t) and pressure(s) (p). Inputs: t = dry bulb temperature(s) (deg C or K) (vector of length N) p = pressure(s) (hPa) (vector of length N) Outputs: mixr = saturation mixing ratio for the given temperature and pressure RLT, 010607 """ es = esat(t) mx = 621.97*(es/(p-es)) return mx
def mixr(t, p): """mx = mixr(t,p) Computes the saturation mixing ratio given ambient temperature(s) (t) and pressure(s) (p). Inputs: t = dry bulb temperature(s) (deg C or K) (vector of length N) p = pressure(s) (hPa) (vector of length N) Outputs: mixr = saturation mixing ratio for the given temperature and pressure RLT, 010607 """ es = esat(t) mx = 621.97 * (es / (p - es)) return mx
def LCLfind(Td, T, p): """ LCLfind(Td, T, p) Finds the temperature and pressure at the lifting condensation level (LCL) of an air parcel. Parameters - - - - - - Td : float Dewpoint temperature (K). T : float Temperature (K). p : float Pressure (Pa) Returns - - - - Tlcl : float Temperature at the LCL (K). plcl : float Pressure at the LCL (Pa). Raises - - - - NameError If the air is saturated at a given Td and T (ie. Td >= T) Examples - - - - - >>> [Tlcl, plcl] = LCLfind(280., 300., 8.e4) >>> print [Tlcl, plcl] [275.76250387361404, 59518.928699453245] >>> LCLfind(300., 280., 8.e4) Traceback (most recent call last): ... NameError: parcel is saturated at this pressure References - - - - - - Emanuel 4.6.24 p. 130 and 4.6.22 p. 129 """ c = constants() hit = Td >= T if hit is True: raise NameError('parcel is saturated at this pressure') e = esat(Td) ehPa = e * 0.01 #Bolton's formula requires hPa. # This is is an empircal fit from for LCL temp from Bolton, 1980 MWR. Tlcl = (2840. / (3.5 * np.log(T) - np.log(ehPa) - 4.805)) + 55. r = c.eps * e / (p - e) #disp(sprintf('r=%0.5g',r')) cp = c.cpd + r * c.cpv logplcl = np.log(p) + cp / (c.Rd * (1 + r / c.eps)) * \ np.log(Tlcl / T) plcl = np.exp(logplcl) #disp(sprintf('plcl=%0.5g',plcl)) return Tlcl, plcl
def wsat(Temp, press): """ wsat(Temp, press) Calculates the saturation vapor mixing ratio of an air parcel. Parameters - - - - - - Temp : float or array_like Temperature in Kelvin. press : float or array_like Pressure in Pa. Returns - - - - theWs : float or array_like Saturation water vapor mixing ratio in (kg/kg). Raises - - - - IOError If both 'Temp' and 'press' are array_like. Examples - - - - - >>> wsat(300, 8e4) 0.028751159650442507 >>> wsat([300,310], 8e4) [0.028751159650442507, 0.052579529573838296] >>> wsat(300, [8e4, 7e4]) [0.028751159650442507, 0.033076887758679716] >>> wsat([300, 310], [8e4, 7e4]) Traceback (most recent call last): ... IOError: Can't have two vector inputs. """ c = constants() es = esat(Temp) # We need to test for all possible cases of (Temp,press) # combinations (ie. (vector,vector), (vector,scalar), # (scalar,vector), or (scalar,scalar). try: len(es) except: esIsVect = False else: esIsVect = True try: len(press) except: pressIsVect = False else: pressIsVect = True if esIsVect and pressIsVect: raise IOError, "Can't have two vector inputs." elif esIsVect: theWs = c.eps * es / (press - es) #theWs = [(c.eps * i/ (press - i)) for i in es] # Limit ws values so rootfinder doesn't blow up. #theWs = list(replaceelem(theWs,0,0.060)) elif pressIsVect: theWs = c.eps * es / (press - es) #theWs = [(c.eps * es/ (i - es)) for i in press] # Limit ws values so rootfinder doesn't blow up. #theWs = list(replaceelem(theWs,0,0.060)) else: # Neither 'es' nor 'press' in a vector. theWs = (c.eps * es / (press - es)) # Limit ws value so rootfinder doesn't blow up. if theWs > 0.060: theWs = 0.060 elif theWs < 0: theWs = 0 # Set minimum and maximum acceptable values for theWs. try: len(theWs) except: if theWs > 0.060: theWs = 0.060 elif theWs < 0: theWs = 0 else: theWs[theWs < 0] = 0 theWs[theWs > 0.060] = 0.060 # theWs = list(replaceelem(theWs, 0, 0.060)) return theWs
def LCLfind(Td, T, p): """ LCLfind(Td, T, p) Finds the temperature and pressure at the lifting condensation level (LCL) of an air parcel. Parameters - - - - - - Td : float Dewpoint temperature (K). T : float Temperature (K). p : float Pressure (Pa) Returns - - - - Tlcl : float Temperature at the LCL (K). plcl : float Pressure at the LCL (Pa). Raises - - - - NameError If the air is saturated at a given Td and T (ie. Td >= T) Examples - - - - - >>> [Tlcl, plcl] = LCLfind(280., 300., 8.e4) >>> print [Tlcl, plcl] [275.76250387361404, 59518.928699453245] >>> LCLfind(300., 280., 8.e4) Traceback (most recent call last): ... NameError: parcel is saturated at this pressure References - - - - - - Emanuel 4.6.24 p. 130 and 4.6.22 p. 129 """ c = constants(); hit = Td >= T; if hit is True: raise NameError('parcel is saturated at this pressure'); e = esat(Td); ehPa = e * 0.01; #Bolton's formula requires hPa. # This is is an empircal fit from for LCL temp from Bolton, 1980 MWR. Tlcl = (2840. / (3.5 * np.log(T) - np.log(ehPa) - 4.805)) + 55.; r = c.eps * e / (p - e); #disp(sprintf('r=%0.5g',r')) cp = c.cpd + r * c.cpv; logplcl = np.log(p) + cp / (c.Rd * (1 + r / c.eps)) * \ np.log(Tlcl / T); plcl = np.exp(logplcl); #disp(sprintf('plcl=%0.5g',plcl)) return Tlcl, plcl
def wsat(Temp, press): """ wsat(Temp, press) Calculates the saturation vapor mixing ratio of an air parcel. Parameters - - - - - - Temp : float or array_like Temperature in Kelvin. press : float or array_like Pressure in Pa. Returns - - - - theWs : float or array_like Saturation water vapor mixing ratio in (kg/kg). Raises - - - - IOError If both 'Temp' and 'press' are array_like. Examples - - - - - >>> wsat(300, 8e4) 0.028751159650442507 >>> wsat([300,310], 8e4) [0.028751159650442507, 0.052579529573838296] >>> wsat(300, [8e4, 7e4]) [0.028751159650442507, 0.033076887758679716] >>> wsat([300, 310], [8e4, 7e4]) Traceback (most recent call last): ... IOError: Can't have two vector inputs. """ c = constants(); es = esat(Temp); # We need to test for all possible cases of (Temp,press) # combinations (ie. (vector,vector), (vector,scalar), # (scalar,vector), or (scalar,scalar). try: len(es) except: esIsVect = False else: esIsVect = True try: len(press) except: pressIsVect = False else: pressIsVect = True if esIsVect and pressIsVect: raise IOError, "Can't have two vector inputs." elif esIsVect: theWs = c.eps*es/(press - es) #theWs = [(c.eps * i/ (press - i)) for i in es] # Limit ws values so rootfinder doesn't blow up. #theWs = list(replaceelem(theWs,0,0.060)) elif pressIsVect: theWs = c.eps*es/(press - es) #theWs = [(c.eps * es/ (i - es)) for i in press] # Limit ws values so rootfinder doesn't blow up. #theWs = list(replaceelem(theWs,0,0.060)) else: # Neither 'es' nor 'press' in a vector. theWs = (c.eps * es/ (press - es)) # Limit ws value so rootfinder doesn't blow up. if theWs > 0.060: theWs = 0.060 elif theWs < 0: theWs = 0 # Set minimum and maximum acceptable values for theWs. try: len(theWs) except: if theWs > 0.060: theWs = 0.060 elif theWs < 0: theWs = 0 else: theWs[theWs < 0] = 0 theWs[theWs > 0.060] = 0.060 # theWs = list(replaceelem(theWs, 0, 0.060)) return theWs
def humidity(x, t=288.15, p=101325, in_type='specific humidity', out_type='water vapor', nounits=False, method='Murphy_Koop'): """ Convert Humidity data into other humidity data humidity: - partial pressure of water vapor in Pa (not hPa nor mbar) - specific humidity in kg/kg (not g/kg) - mixing ratio in kg/kg (not g/kg) - relative humidity in percent - dew point temperature in K (not degree Celsius) - virtual temperature in K (not degree Celsius) """ in_unit = None out_unit = None ispandas = False inputs = ['water vapor', 'specific humidity', 'relative humidity', 'virtual temperature', 'ppmv'] outputs = ['water vapor', 'specific humidity', 'relative humidity', 'mixing ratio', 'ppmv', 'virtual temperature', 'dewpoint'] if in_type not in inputs: print "Unkown: %s" % in_type print inputs if out_type not in outputs: print "Unkown: %s" % out_type print outputs # retain time information if isinstance(x, pd.DataFrame) | isinstance(x, pd.Series): # convert to numpy time = x.index if isinstance(x, pd.DataFrame): columns = x.columns x = np.ma.asarray(x) ispandas = True if isinstance(p, pd.DataFrame) | isinstance(p, pd.Series): p = np.ma.asarray(p) # Vectorize funktion or not? x = np.ma.asarray(x) c = 0.622 # Constant (Mv / Md) if in_type in ('partial pressure', 'partial pressure of water vapor', 'water vapor'): e = x in_unit = 'Pa' elif in_type == 'specific humidity': q = x e = (q * p) / (c + (1 - c) * q) in_unit = 'kg/kg + Pa (p)' elif in_type == 'mixing ratio': r = x e = (r * p) / (r + c) in_unit = '1 + Pa (p)' elif in_type == 'relative humidity': RH = x es = esat(t, method=method, info=False) e = (RH / 100.) * es in_unit = '% + K (t)' elif in_type == 'virtual temperature': Tv = x e = p * (1 - t / Tv) / (1 - c) in_unit = 'K + K (t)' elif in_type == 'ppmv': x = (x / 1e6) e = x * p / (1 + x) in_unit = 'ppmv + Pa (p)' else: print "[INPUT] Unknown Conversion" return if out_type in ('partial pressure', 'partial pressure of water vapor', 'water vapor'): out = e out_unit = 'Pa' elif out_type == 'specific humidity': Pd = p - e out = (e * c) / (e * c + Pd) out_unit = '+ Pa (p) = kg/kg ' elif out_type == 'mixing ratio': Pd = p - e out = (e / Pd) * c out_unit = '+ Pa (p) = 1 ' elif out_type == 'ppmv': Pd = p - e out = (e / Pd) * 1e6 out_unit = '+ Pa (p) = ppmv' elif out_type == 'relative humidity': es = esat(t, method=method) out = 100. * e / es out_unit = '+ K (t) = %' elif out_type == 'virtual temperature': out = t / (1 - (e / p) * (1 - c)) out_unit = '+K (t) + Pa (p) = K' elif out_type == 'dew point': out = dewpoint(e, method=method) out_unit = 'K' else: print "[OUTPUT] Unknown Conversion" return if ispandas: if len(out.shape) > 1: out = pd.DataFrame(out, index=time, columns=columns) else: out = pd.Series(out, index=time) if nounits: return out else: print "Conversion: %s => %s" % (in_unit, out_unit) print in_type, ' => ', out_type return out