def test_wetbulb(): input_p = 950 input_t = 5 input_td = -10 correct_t = -0.04811002960985089 returned_t = thermo.wetbulb(input_p, input_t, input_td) npt.assert_almost_equal(returned_t, correct_t) input_p = 1013 input_t = 5 input_td = -10 correct_t = 0.22705033380623352 returned_t = thermo.wetbulb(input_p, input_t, input_td) npt.assert_almost_equal(returned_t, correct_t)
def dewpoint_to_wet_bulb_temperature(dewpoints_kelvins, temperatures_kelvins, total_pressures_pascals): """Converts one or more dewpoints to wet-bulb temperatures. :param dewpoints_kelvins: numpy array of dewpoints (K). :param temperatures_kelvins: equivalent-size numpy array of air temperatures (K). :param total_pressures_pascals: equivalent-size numpy array of total air pressures (K). :return: wet_bulb_temperatures_kelvins: equivalent-size numpy array of wet- bulb temperatures (K). """ error_checking.assert_is_real_numpy_array(dewpoints_kelvins) error_checking.assert_is_real_numpy_array(temperatures_kelvins) error_checking.assert_is_real_numpy_array(total_pressures_pascals) orig_dimensions = numpy.array(dewpoints_kelvins.shape, dtype=int) error_checking.assert_is_numpy_array(temperatures_kelvins, exact_dimensions=orig_dimensions) error_checking.assert_is_numpy_array(total_pressures_pascals, exact_dimensions=orig_dimensions) dewpoints_1d_celsius = -ZERO_CELSIUS_IN_KELVINS + numpy.ravel( dewpoints_kelvins) temperatures_1d_celsius = -ZERO_CELSIUS_IN_KELVINS + numpy.ravel( temperatures_kelvins) total_pressures_1d_millibars = PASCALS_TO_MILLIBARS * numpy.ravel( total_pressures_pascals) nan_flags = numpy.logical_or(numpy.isnan(dewpoints_1d_celsius), numpy.isnan(temperatures_1d_celsius)) nan_flags = numpy.logical_or(nan_flags, numpy.isnan(total_pressures_1d_millibars)) num_points = len(dewpoints_1d_celsius) wet_bulb_temperatures_1d_celsius = numpy.full(num_points, numpy.nan) for i in range(num_points): if nan_flags[i]: continue wet_bulb_temperatures_1d_celsius[i] = thermo.wetbulb( p=total_pressures_1d_millibars[i], t=temperatures_1d_celsius[i], td=dewpoints_1d_celsius[i]) return ZERO_CELSIUS_IN_KELVINS + numpy.reshape( wet_bulb_temperatures_1d_celsius, tuple(orig_dimensions.tolist()))
def get_wetbulb_profile(self): ''' Function to calculate the wetbulb profile. Parameters ---------- None Returns ------- Array of wet bulb profile ''' wetbulb = ma.empty(self.pres.shape[0]) for i in range(len(self.v)): wetbulb[i] = thermo.wetbulb( self.pres[i], self.tmpc[i], self.dwpc[i] ) wetbulb[wetbulb == self.missing] = ma.masked wetbulb.set_fill_value(self.missing) return wetbulb
def posneg_wetbulb(prof, start=-1): ''' Positive/Negative Wetbulb profile Adapted from SHARP code donated by Rich Thompson (SPC) Description: This routine calculates the positive (above 0 C) and negative (below 0 C) areas of the wet bulb profile starting from a specified pressure (start). If the specified pressure is not given, this routine calls init_phase() to obtain the pressure level the precipitation expected to fall begins at. This is an routine considers the wet-bulb profile instead of the temperature profile in case the profile beneath the profile beneath the falling precipitation becomes saturated. Parameters ---------- prof : Profile object start : the pressure level the precpitation originates from (found by calling init_phase()) Returns ------- pos : the positive area (> 0 C) of the wet-bulb profile in J/kg neg : the negative area (< 0 C) of the wet-bulb profile in J/kg top : the top of the precipitation layer pressure in mb bot : the bottom of the precipitation layer pressure in mb ''' # Needs to be tested # If there is no sounding, don't compute anything if utils.QC(interp.temp(prof, 500)) == False and utils.QC( interp.temp(prof, 850)) == False: return np.masked, np.masked, np.masked, np.masked # Find lowest obs in layer lower = prof.pres[prof.get_sfc()] lptr = prof.get_sfc() # Find the highest obs in the layer if start == -1: lvl, phase, st = init_phase(prof) if lvl > 0: upper = lvl else: upper = 500. else: upper = start # Find the level where the pressure is just greater than the upper pressure idxs = np.where(prof.pres > upper)[0] if len(idxs) == 0: uptr = 0 else: uptr = idxs[-1] # Start with the upper layer pe1 = upper h1 = interp.hght(prof, pe1) te1 = thermo.wetbulb(pe1, interp.temp(prof, pe1), interp.dwpt(prof, pe1)) tp1 = 0 warmlayer = coldlayer = lyre = totp = totn = tote = ptop = pbot = lyrlast = 0 for i in np.arange(uptr, lptr - 1, -1): pe2 = prof.pres[i] h2 = prof.hght[i] te2 = thermo.wetbulb(pe2, interp.temp(prof, pe2), interp.dwpt(prof, pe2)) tp2 = 0 tdef1 = (0 - te1) / thermo.ctok(te1) tdef2 = (0 - te2) / thermo.ctok(te2) lyrlast = lyre lyre = 9.8 * (tdef1 + tdef2) / 2.0 * (h2 - h1) # Has a warm layer been found yet? if te2 > 0: if warmlayer == 0: warmlayer = 1 ptop = pe2 # Has a cold layer been found yet? if te2 < 0: if warmlayer == 1 and coldlayer == 0: coldlayer = 1 pbot = pe2 if warmlayer > 0: if lyre > 0: totp += lyre else: totn += lyre tote += lyre pelast = pe1 pe1 = pe2 h1 = h2 te1 = te2 tp1 = tp2 if warmlayer == 1 and coldlayer == 1: pos = totp neg = totn top = ptop bot = pbot else: neg = 0 pos = 0 bot = 0 top = 0 return pos, neg, top, bot
''' Create the Sounding (Profile) Object '''
def posneg_wetbulb(prof, start=-1): ''' Positive/Negative Wetbulb profile Adapted from SHARP code donated by Rich Thompson (SPC) Description: This routine calculates the positive (above 0 C) and negative (below 0 C) areas of the wet bulb profile starting from a specified pressure (start). If the specified pressure is not given, this routine calls init_phase() to obtain the pressure level the precipitation expected to fall begins at. This is an routine considers the wet-bulb profile instead of the temperature profile in case the profile beneath the profile beneath the falling precipitation becomes saturated. Parameters ---------- prof : Profile object start : the pressure level the precpitation originates from (found by calling init_phase()) Returns ------- pos : the positive area (> 0 C) of the wet-bulb profile in J/kg neg : the negative area (< 0 C) of the wet-bulb profile in J/kg top : the top of the precipitation layer pressure in mb bot : the bottom of the precipitation layer pressure in mb ''' # Needs to be tested # If there is no sounding, don't compute anything if utils.QC(interp.temp(prof, 500)) == False and utils.QC(interp.temp(prof, 850)) == False: return np.ma.masked, np.ma.masked, np.ma.masked, np.ma.masked # Find lowest obs in layer lower = prof.pres[prof.get_sfc()] lptr = prof.get_sfc() # Find the highest obs in the layer if start == -1: lvl, phase, st = init_phase(prof) if lvl > 0: upper = lvl else: upper = 500. else: upper = start # Find the level where the pressure is just greater than the upper pressure idxs = np.where(prof.pres > upper)[0] if len(idxs) == 0: uptr = 0 else: uptr = idxs[-1] # Start with the upper layer pe1 = upper; h1 = interp.hght(prof, pe1); te1 = thermo.wetbulb(pe1, interp.temp(prof, pe1), interp.dwpt(prof, pe1)) tp1 = 0 warmlayer = coldlayer = lyre = totp = totn = tote = ptop = pbot = lyrlast = 0 for i in np.arange(uptr, lptr-1, -1): pe2 = prof.pres[i] h2 = prof.hght[i] te2 = thermo.wetbulb(pe2, interp.temp(prof, pe2), interp.dwpt(prof, pe2)) tp2 = 0 tdef1 = (0 - te1) / thermo.ctok(te1); tdef2 = (0 - te2) / thermo.ctok(te2); lyrlast = lyre; lyre = 9.8 * (tdef1 + tdef2) / 2.0 * (h2 - h1); # Has a warm layer been found yet? if te2 > 0: if warmlayer == 0: warmlayer = 1 ptop = pe2 # Has a cold layer been found yet? if te2 < 0: if warmlayer == 1 and coldlayer == 0: coldlayer = 1 pbot = pe2 if warmlayer > 0: if lyre > 0: totp += lyre else: totn += lyre tote += lyre pelast = pe1 pe1 = pe2 h1 = h2 te1 = te2 tp1 = tp2 if warmlayer == 1 and coldlayer == 1: pos = totp neg = totn top = ptop bot = pbot else: neg = 0 pos = 0 bot = 0 top = 0 return pos, neg, top, bot