Example #1
0
def test_dwpt():
    input_p = 900
    correct_t = 11.52599445805832
    returned_t = interp.dwpt(prof, input_p)
    npt.assert_almost_equal(returned_t, correct_t)

    input_p = [900, 800, 600, 400]
    correct_t = np.asarray([11.52599445805832, 6.07174951,
                            -13.34348479, -35.7])
    returned_t = interp.dwpt(prof, input_p)
    npt.assert_almost_equal(returned_t, correct_t)
Example #2
0
def test_dwpt():
    input_p = 900
    correct_t = 11.52599445805832
    returned_t = interp.dwpt(prof, input_p)
    npt.assert_almost_equal(returned_t, correct_t)

    input_p = [900, 800, 600, 400]
    correct_t = np.asarray([11.52599445805832, 6.07174951,
                            -13.34348479, -35.7])
    returned_t = interp.dwpt(prof, input_p)
    npt.assert_almost_equal(returned_t, correct_t)
Example #3
0
def precip_water(lower, upper, prof):
    '''
    Calculates the precipitable water from a profile object within the
    specified layer. The default layer (lower=-1 & upper=-1) is defined to
    be surface to 400 hPa.

    Inputs
    ------
        lower       (float)             Lower pressure level
        upper       (float)             Upper pressure level
        prof        (profile object)    Profile Object

    Returns
    -------
        pwat        (float)             Precipitable Water (in)
    '''
    if lower == -1: lower = prof.gSndg[prof.sfc][prof.pind]
    if upper == -1: upper = 400.

    # Find lower and upper ind bounds for looping
    i = 0
    while prof.gSndg[i][prof.pind] > lower:
        i += 1
    lptr = i
    while prof.gSndg[i][prof.pind] > upper:
        i += 1
    uptr = i

    # Start with interpolated bottom level
    d1 = interp.dwpt(lower, prof)
    p1 = lower
    w1 = thermo.mixratio(p1, d1)

    # Loop through every level that has a dew point
    pwat = 0
    for i in range(lptr, uptr + 1):
        if QC(prof.gSndg[i][prof.tdind]):
            p2 = prof.gSndg[i][prof.pind]
            w2 = thermo.mixratio(p2, prof.gSndg[i][prof.tdind])
            pwat += ((w1 + w2) / 2.) * (p1 - p2)
            p1 = p2
            w1 = w2

    # Finish with interpolated top level
    d2 = interp.dwpt(upper, prof)
    p2 = upper
    w2 = thermo.mixratio(p2, d2)
    pwat += ((w1 + w2) / 2.) * (p1 - p2)

    return pwat * 0.00040173
Example #4
0
def precip_water(lower, upper, prof):
    '''
    Calculates the precipitable water from a profile object within the
    specified layer. The default layer (lower=-1 & upper=-1) is defined to
    be surface to 400 hPa.

    Inputs
    ------
        lower       (float)             Lower pressure level
        upper       (float)             Upper pressure level
        prof        (profile object)    Profile Object

    Returns
    -------
        pwat        (float)             Precipitable Water (in)
    '''
    if lower == -1: lower = prof.gSndg[prof.sfc][prof.pind]
    if upper == -1: upper = 400.

    # Find lower and upper ind bounds for looping
    i = 0
    while prof.gSndg[i][prof.pind] > lower: i+=1
    lptr = i
    while prof.gSndg[i][prof.pind] > upper: i+=1
    uptr = i

    # Start with interpolated bottom level
    d1 = interp.dwpt(lower, prof)
    p1 = lower
    w1 = thermo.mixratio(p1, d1)

    # Loop through every level that has a dew point
    pwat = 0
    for i in range(lptr, uptr+1):
        if QC(prof.gSndg[i][prof.tdind]):
            p2 = prof.gSndg[i][prof.pind]
            w2 = thermo.mixratio(p2, prof.gSndg[i][prof.tdind])
            pwat += ((w1 + w2) / 2.) * (p1 - p2)
            p1 = p2
            w1 = w2

    # Finish with interpolated top level
    d2 = interp.dwpt(upper, prof)
    p2 = upper
    w2 = thermo.mixratio(p2, d2)
    pwat += ((w1 + w2) / 2.) * (p1 - p2)

    return pwat * 0.00040173
Example #5
0
def haines_high(prof):
    '''
        Haines Index High Elevation calculation
        
        Calculates the Haines Index(Lower Atmosphere Severity Index)
        using the higher elevation parmeters, used above 3000ft or 914 m.
        
        Pressure levels 700 mb and 500 mb
        Dewpoint depression at 700 mb
        
        Lapse Rate Term
        ---------------
        1 : < 18C
        2 : 18C to 21C
        3 : > 21C
        
        Dewpoint Depression Term
        ------------------------
        1 : < 15C
        2 : 15C to 20C
        3 : > 20C
        
        Adapted from S-591 course
        Added by Nickolai Reimer (NWS Billings, MT)
        
        Parameters
        ----------
        prof : profile object
            Profile object

        Returns
        -------
        param : number
            the Haines Index high

    '''
    tp1  = interp.temp(prof, 700)
    tp2  = interp.temp(prof, 500)
    tdp1 = interp.dwpt(prof, 700)
    
    if utils.QC(tp1) and utils.QC(tp2) and utils.QC(tdp1):
        lapse_rate = tp1 - tp2
        dewpoint_depression = tp1 - tdp1
        
        if lapse_rate < 18:
            a = 1
        elif 18 <= lapse_rate and lapse_rate <= 21:
            a = 2
        else:
            a = 3
        
        if dewpoint_depression < 15:
            b = 1
        elif 15 <= dewpoint_depression and dewpoint_depression <= 20:
            b = 2
        else:
            b = 3
        return a + b
    else:
        return constants.MISSING
def insertLevels(prof, zeroHt, zeroPres, level):   
    
    prof.dwpc = np.insert(prof.dwpc,level,
                          [interp.dwpt(prof,zeroPres)])
    prof.vtmp = np.insert(prof.vtmp,level,
                          [interp.vtmp(prof,zeroPres)])
    prof.thetae = np.insert(prof.thetae,level,
                          [interp.thetae(prof,zeroPres)])
    #prof.wetbulb = np.insert(prof.wetbulb,level,
    #                      [interp.generic_interp_pres(np.log10(zeroPres), prof.logp[::-1], prof.wetbulb[::-1])])
    try:
        dir,mag = interp.vec(prof,zeroPres)
        prof.wdir = np.insert(prof.wdir,level,[dir])
        prof.wspd = np.insert(prof.wspd,level,[mag])
        prof.u, prof.v = utils.vec2comp(prof.wdir, prof.wspd)
    except:
        prof.wdir = np.insert(prof.wdir,level,[0])
        prof.wspd = np.insert(prof.wspd,level,[0])
        prof.u, prof.v = utils.vec2comp(prof.wdir, prof.wspd)        

    prof.hght = np.insert(prof.hght,level,[zeroHt])
    prof.pres = np.insert(prof.pres,level,[zeroPres])
    prof.logp = np.log10(prof.pres.copy())    
    
    return prof
def lift_parcels(prof):
    """Lift all the parcels within a given height interval and return the CAPEs, CINHs, and LFCs"""
    ## the height bottom, top, and interval
    zvals = np.arange(0, 5000, 100)
    pvals = interp.pres(prof, interp.to_msl(prof, zvals))

    tvals = interp.temp(prof, pvals)
    dvals = interp.dwpt(prof, pvals)
    hvals = interp.hght(prof, pvals)
    hvals = interp.to_agl(prof, hvals)

    ## empty lists for storing the result
    cape_arr = []
    cinh_arr = []
    lfc_arr = []

    ## lift each parcel in the vertical profile
    for p, t, td, h in zip(pvals, tvals, dvals, hvals):
        ## use SHARPpy to compute the parcel indices
        pcl = params.parcelx(prof, pres=p, tmpc=t, dwpc=td)

        ## store the parcel indices
        cape_arr.append(pcl.bplus)
        cinh_arr.append(pcl.bminus)
        lfc_arr.append(pcl.lfchght - h)

    ## return the data
    return np.ma.masked_invalid(cape_arr), np.ma.masked_invalid(
        cinh_arr), np.ma.masked_invalid(lfc_arr)
Example #8
0
 def __mu(self, prof, **kwargs):
     ''' Create the most unstable parcel within defined level '''
     self.desc = 'Most Unstable Parcel in Lowest %.2f hPa' % self.presval
     diff = prof.gSndg[prof.sfc][prof.pind] - self.presval
     self.pres = unstable_level(prof, -1, diff)
     self.temp = interp.temp(self.pres, prof)
     self.dwpt = interp.dwpt(self.pres, prof)
     return
Example #9
0
 def __mu(self, prof, **kwargs):
     ''' Create the most unstable parcel within defined level '''
     self.desc = 'Most Unstable Parcel in Lowest %.2f hPa' % self.presval
     diff = prof.gSndg[prof.sfc][prof.pind] - self.presval
     self.pres = unstable_level(prof, -1, diff)
     self.temp = interp.temp(self.pres, prof)
     self.dwpt = interp.dwpt(self.pres, prof)
     return
Example #10
0
 def __user(self, prof, **kwargs):
     ''' Create a user-defined parcel '''
     self.desc = '%.2f hPa Parcel' % self.presval
     self.pres = self.presval
     if 'temp' in kwargs: self.temp = kwargs.get('temp')
     else: self.temp = interp.temp(self.pres, prof)
     if 'dwpt' in kwargs: self.dwpt = kwargs.get('dwpt')
     else: self.dwpt = interp.dwpt(self.pres, prof)
     return
Example #11
0
 def __user(self, prof, **kwargs):
     ''' Create a user-defined parcel '''
     self.desc = '%.2f hPa Parcel' % self.presval
     self.pres = self.presval
     if 'temp' in kwargs: self.temp = kwargs.get('temp')
     else: self.temp = interp.temp(self.pres, prof)
     if 'dwpt' in kwargs: self.dwpt = kwargs.get('dwpt')
     else: self.dwpt = interp.dwpt(self.pres, prof)
     return
Example #12
0
def k_index(prof):
    '''
    Calculates the K-Index from a profile object

    Inputs
    ------
        prof    (profile object)    Profile Object

    Returns
    -------
        kind    (float)             K-Index
    '''
    t8 = interp.temp(850., prof)
    t7 = interp.temp(700., prof)
    t5 = interp.temp(500., prof)
    td7 = interp.dwpt(700., prof)
    td8 = interp.dwpt(850., prof)
    if not QC(t8) or not QC(t7) or not QC(t5) or not QC(td8) or not QC(td7):
        return RMISSD
    else:
        return t8 - t5 + td8 - (t7 - td7)
Example #13
0
def k_index(prof):
    '''
    Calculates the K-Index from a profile object

    Inputs
    ------
        prof    (profile object)    Profile Object

    Returns
    -------
        kind    (float)             K-Index
    '''
    t8 = interp.temp(850., prof)
    t7 = interp.temp(700., prof)
    t5 = interp.temp(500., prof)
    td7 = interp.dwpt(700., prof)
    td8 = interp.dwpt(850., prof)
    if not QC(t8) or not QC(t7) or not QC(t5) or not QC(td8) or not QC(td7):
        return RMISSD
    else:
        return t8 - t5 + td8 - (t7 - td7)
Example #14
0
def c_totals(prof):
    '''
    Calculates the Cross Totals Index from data in profile object.

    Inputs
    ------
        prof        (profile object)    Profile Object

    Returns
    -------
        c_totals    (float)             Cross Totals
    '''
    t5 = interp.temp(500., prof)
    td8 = interp.dwpt(850., prof)
    return td8 - t5
Example #15
0
def c_totals(prof):
    '''
    Calculates the Cross Totals Index from data in profile object.

    Inputs
    ------
        prof        (profile object)    Profile Object

    Returns
    -------
        c_totals    (float)             Cross Totals
    '''
    t5 = interp.temp(500., prof)
    td8 = interp.dwpt(850., prof)
    return td8 - t5
Example #16
0
def haines_ma(prof):
    '''
        Haines Index, Middle Altitude

        The Haines Index (or Lower Atmospheric Severity Index) was developed in order to help forecast fire "blow up"
        potential.  It is a function of lower atmospheric stability and moisture content.  Three versions were
        developed, to be used depending on the altitude of the surface.  Values of 2 or 3 indicate very low "blow up"
        potential; a value of 4 indicates low potential; a value of 5 indicates moderate potential; and a value of
        6 indicates high potential.

        The middle altitude version was developed primarily for use when the surface level pressure is between 950
        and 850 mb.

        Parameters
        ----------
        prof - Profile object

        Returns
        -------
        haines_ma : number
            Haines Index, Middle Altitude (number)
    '''

    tmp850 = interp.temp(prof, 850)
    tmp700 = interp.temp(prof, 700)
    dpt850 = interp.dwpt(prof, 850)

    lr87 = tmp850 - tmp700
    tdd850 = tmp850 - dpt850

    if lr87 <= 5:
        stab_tm = 1
    elif 5 < lr87 and lr87 < 11:
        stab_tm = 2
    else:
        stab_tm = 3

    if tdd850 <= 5:
        mois_tm = 1
    elif 5 < tdd850 and tdd850 < 13:
        mois_tm = 2
    else:
        mois_tm = 3

    haines_ma = stab_tm + mois_tm

    return haines_ma
Example #17
0
def haines_ha(prof):
    '''
        Haines Index, High Altitude

        The Haines Index (or Lower Atmospheric Severity Index) was developed in order to help forecast fire "blow up"
        potential.  It is a function of lower atmospheric stability and moisture content.  Three versions were
        developed, to be used depending on the altitude of the surface.  Values of 2 or 3 indicate very low "blow up"
        potential; a value of 4 indicates low potential; a value of 5 indicates moderate potential; and a value of
        6 indicates high potential.

        The low altitude version was developed primarily for use when the surface level pressure is between 850 and
        700 mb.

        Parameters
        ----------
        prof - Profile object

        Returns
        -------
        haines_ha : number
            Haines Index, High Altitude (number)
    '''

    tmp700 = interp.temp(prof, 700)
    tmp500 = interp.temp(prof, 500)
    dpt700 = interp.dwpt(prof, 700)

    lr75 = tmp700 - tmp500
    tdd700 = tmp700 - dpt700

    if lr75 <= 17:
        stab_tm = 1
    elif 17 < lr75 and lr75 < 22:
        stab_tm = 2
    else:
        stab_tm = 3

    if tdd700 <= 14:
        mois_tm = 1
    elif 14 < tdd700 and tdd700 < 21:
        mois_tm = 2
    else:
        mois_tm = 3

    haines_ha = stab_tm + mois_tm

    return haines_ha
    def interp(self, dp=-25):
        """
        Interpolate the profile object to a specific pressure level spacing.
        """

        if self.isEnsemble():
            raise ValueError("Cannot interpolate the ensemble profiles.")

        prof = self._profs[self._highlight][self._prof_idx]

        # Save original, if one hasn't already been saved
        if self._prof_idx not in self._orig_profs:
            self._orig_profs[self._prof_idx] = prof

        cls = type(prof)
        # Copy the tmpc, dwpc, etc. profiles to be inteprolated
        keys = ['tmpc', 'dwpc', 'hght', 'wspd', 'wdir', 'omeg']

        prof_vars = {
            'pres': np.arange(prof.pres[prof.sfc], prof.pres[prof.top], dp)
        }
        prof_vars['tmpc'] = interp.temp(prof, prof_vars['pres'])
        prof_vars['dwpc'] = interp.dwpt(prof, prof_vars['pres'])
        prof_vars['hght'] = interp.hght(prof, prof_vars['pres'])
        if prof.omeg.all() is not np.ma.masked:
            prof_vars['omeg'] = interp.omeg(prof, prof_vars['pres'])
        else:
            prof_vars['omeg'] = np.ma.masked_array(prof_vars['pres'],
                                                   mask=np.ones(len(
                                                       prof_vars['pres']),
                                                                dtype=int))
        u, v = interp.components(prof, prof_vars['pres'])
        prof_vars['u'] = u
        prof_vars['v'] = v

        interp_prof = cls.copy(prof, **prof_vars)
        self._profs[self._highlight][self._prof_idx] = interp_prof

        # Save the original like in modify()
        if self._prof_idx not in self._interp_profs:
            self._interp_profs[self._prof_idx] = interp_prof

        # Update bookkeeping
        self._interp[self._prof_idx] = True
Example #19
0
    def interp(self, dp=-25):
        """
        Interpolate the profile object to a specific pressure level spacing.
        """

        if self.isEnsemble():
            raise ValueError("Cannot interpolate the ensemble profiles.")

        prof = self._profs[self._highlight][self._prof_idx]

        # Save original, if one hasn't already been saved
        if self._prof_idx not in self._orig_profs:
            self._orig_profs[self._prof_idx] = prof

        cls = type(prof)
        # Copy the tmpc, dwpc, etc. profiles to be inteprolated
        keys = ['tmpc', 'dwpc', 'hght', 'wspd', 'wdir', 'omeg']
        
        prof_vars = {'pres': np.arange(prof.pres[prof.sfc], prof.pres[prof.top], dp)}
        prof_vars['tmpc'] = interp.temp(prof, prof_vars['pres'])
        prof_vars['dwpc'] = interp.dwpt(prof, prof_vars['pres'])
        prof_vars['hght'] = interp.hght(prof, prof_vars['pres'])
        if prof.omeg.all() is not np.ma.masked:
            prof_vars['omeg'] = interp.omeg(prof, prof_vars['pres'])
        else:
            prof_vars['omeg'] = np.ma.masked_array(prof_vars['pres'], mask=np.ones(len(prof_vars['pres']), dtype=int))
        u, v = interp.components(prof, prof_vars['pres'])
        prof_vars['u'] = u
        prof_vars['v'] = v

        interp_prof = cls.copy(prof, **prof_vars)
        self._profs[self._highlight][self._prof_idx] = interp_prof

         # Save the original like in modify()
        if self._prof_idx not in self._interp_profs:
            self._interp_profs[self._prof_idx] = interp_prof
       
        # Update bookkeeping
        self._interp[self._prof_idx] = True
Example #20
0
def unstable_level(prof, lower, upper):
    '''
    Finds the most unstable level between the lower and upper levels.

    Inputs
    ------
        prof        (profile object)    Profile Object
        lower       (float)             Bottom level (hPa) [-1=SFC]
        upper       (float)             Top level (hPa) [-1=SFC-100hPa]

    Returns
    -------
        Pressure Level of most unstable level   (float [hPa])
    '''
    if lower == -1: lower = prof.gSndg[prof.sfc][prof.pind]
    if upper == -1: upper = prof.gSndg[prof.sfc][prof.pind] - 400.

    # Make sure this is a valid layer
    while not QC(interp.dwpt(upper, prof)):
        upper += 50.
    if not QC(interp.temp(lower, prof)): lower = prof.gSndg[prof.sfc][0]

    # Find lowest observations in the layer
    i = 0
    while prof.gSndg[i][prof.pind] > lower:
        i += 1
    while not QC(prof.gSndg[i][prof.tind]):
        i += 1
    lptr = i
    if prof.gSndg[i][prof.pind] == lower: lptr += 1

    # Find highest observations in the layer
    i = prof.gNumLevels - 1
    while prof.gSndg[i][prof.pind] < upper:
        i -= 1
    uptr = i
    if prof.gSndg[i][prof.pind] == upper: uptr -= 1

    # Start with interpolated bottom layer
    p1 = lower
    t1 = interp.temp(p1, prof)
    td1 = interp.dwpt(p1, prof)
    p2, t2 = thermo.drylift(p1, t1, td1)
    tmax = thermo.wetlift(p2, t2, 1000.)
    pmax = p1

    # Calculate every level that reports a dew point
    for i in range(lptr, uptr + 1):
        if QC(prof.gSndg[i][prof.tdind]):
            p1 = prof.gSndg[i][prof.pind]
            t1 = prof.gSndg[i][prof.tind]
            td1 = prof.gSndg[i][prof.tdind]
            p2, t2 = thermo.drylift(p1, t1, td1)
            t1 = thermo.wetlift(p2, t2, 1000.)
            if t1 > tmax:
                tmax = t1
                pmax = p1

    # Finish with interpolated top layer
    p1 = upper
    t1 = interp.temp(p1, prof)
    td1 = interp.dwpt(p1, prof)
    p2, t2 = thermo.drylift(p1, t1, td1)
    t1 = thermo.wetlift(p2, t2, 1000.)
    if t1 > tmax:
        pmax = prof.gSndg[i][prof.pind]

    return pmax
Example #21
0
def haines_mid(prof):
    '''
        Haines Index Mid Elevation calculation
        
        Calculates the Haines Index(Lower Atmosphere Severity Index)
        using the middle elevation parmeters, used 
        between 1000 ft or 305 m and 3000 ft or 914 m.
        
        Pressure levels 850 mb and 700 mb
        Dewpoint depression at 850 mb
        
        Lapse Rate Term
        ---------------
        1 : < 6C
        2 : 6C to 10C
        3 : > 10C
        
        Dewpoint Depression Term
        ------------------------
        1 : < 6C
        2 : 6C to 12C
        3 : > 12C
        
        Adapted from S-591 course
        Added by Nickolai Reimer (NWS Billings, MT)
        
        Parameters
        ----------
        prof : profile object
            Profile object

        Returns
        -------
        param : number
            the Haines Index mid

    '''
    
    tp1  = interp.temp(prof, 850)
    tp2  = interp.temp(prof, 700)
    tdp1 = interp.dwpt(prof, 850)
    
    if utils.QC(tp1) and utils.QC(tp2) and utils.QC(tdp1):
        lapse_rate = tp1 - tp2
        dewpoint_depression = tp1 - tdp1
        
        if lapse_rate < 6:
            a = 1
        elif 6 <= lapse_rate and lapse_rate <= 10:
            a = 2
        else:
            a = 3
        
        if dewpoint_depression < 6:
            b = 1
        elif 6 <= dewpoint_depression and dewpoint_depression <= 12:
            b = 2
        else:
            b = 3
        return a + b
    else:
        return constants.MISSING
Example #22
0
def mean_mixratio(prof, lower=-1, upper=-1):
    '''
    Calculates the mean mixing ratio from a profile object within the
    specified layer.

    Inputs
    ------
        prof        (profile object)    Profile Object
        lower       (float)             Bottom level (hPa) [-1=SFC]
        upper       (float)             Top level (hPa) [-1=SFC-100hPa]

    Returns
    -------
        Mean Mixing Ratio   (float)
    '''
    if lower == -1: lower = prof.gSndg[prof.sfc][prof.pind]
    if upper == -1: upper = prof.gSndg[prof.sfc][prof.pind] - 100.

    if not QC(interp.temp(upper, prof)): mmw = RMISSD
    if not QC(interp.temp(lower, prof)): prof.gSndg[prof.sfc][prof.pind]

    # Find lowest observations in the layer
    i = 0
    while prof.gSndg[i][prof.pind] > lower:
        i += 1
    while not QC(prof.gSndg[i][prof.tdind]):
        i += 1
    lptr = i
    if prof.gSndg[i][prof.pind] == lower: lptr += 1

    # Find highest observations in the layer
    i = prof.gNumLevels - 1
    while prof.gSndg[i][prof.pind] < upper:
        i -= 1
    uptr = i
    if prof.gSndg[i][prof.pind] == upper: uptr -= 1

    totd = 0
    totp = 0

    # Start with interpolated bottom layer
    p1 = lower
    dp1 = interp.dwpt(p1, prof)
    num = 1

    # Calculate every level that reports a dew point
    for i in range(lptr, uptr + 1):
        if QC(prof.gSndg[i][prof.tdind]):
            dp2 = prof.gSndg[i][prof.tdind]
            p2 = prof.gSndg[i][prof.pind]
            dpbar = (dp1 + dp2) / 2.
            pbar = (p1 + p2) / 2.
            totd += dpbar
            totp += pbar
            dp1 = dp2
            p1 = p2
            num += 1

    # Finish with top layer
    dp2 = interp.dwpt(upper, prof)
    p2 = upper
    dbar = (dp1 + dp2) / 2.
    pbar = (p1 + p2) / 2.
    totd += dbar
    totp += pbar
    return thermo.mixratio(totp / num, totd / num)
Example #23
0
def parcelx(lower, upper, pres, temp, dwpt, prof, **kwargs):
    '''
    Lifts the specified parcel, calculated various levels and parameters from
    the profile object. B+/B- are calculated based on the specified layer.

    !! All calculations use the virtual temperature correction unless noted. !!

    Inputs
    ------
        lower       (float)                 Lower-bound lifting level (hPa)
        upper       (float)                 Upper-bound lifting level
        pres        (float)                 Pressure of parcel to lift (hPa)
        temp        (float)                 Temperature of parcel to lift (C)
        dwpt        (float)                 Dew Point of parcel to lift (C)
        prof        (profile object)        Profile Object

    Returns
    -------
        pcl         (parcel object)         Parcel Object
    '''
    pcl = Parcel(-1, -1, pres, temp, dwpt)
    if 'lplvals' in kwargs: pcl.lplvals = kwargs.get('lplvals')
    else:
        lplvals = DefineParcel(prof, 5, pres=pres, temp=temp, dwpt=dwpt)
        pcl.lplvals = lplvals

    if prof.gNumLevels < 1: return pcl

    lyre = -1
    cap_strength = RMISSD
    cap_strengthpres = RMISSD
    li_max = RMISSD
    li_maxpres = RMISSD
    totp = 0.
    totn = 0.
    tote = 0.
    cinh_old = 0.

    # See if default layer is specified
    if lower == -1:
        lower = prof.gSndg[prof.sfc][prof.pind]
        pcl.blayer = lower
    if upper == -1:
        upper = prof.gSndg[prof.gNumLevels-1][prof.pind]
        pcl.tlayer = upper

    # Make sure that this is a valid layer
    if lower > pres:
        lower = pres
        pcl.blayer = lower
    if not QC(interp.vtmp(lower, prof)) or \
       not QC(interp.vtmp(upper, prof)):
        return RMISSD

    # Begin with the Mixing Layer
    te1 = interp.vtmp(pres, prof)
    pe1 = lower
    h1 = interp.hght(pe1, prof)
    tp1 = thermo.virtemp(pres, temp, dwpt)
    # te1 = tp1

    # Lift parcel and return LCL pres (hPa) and LCL temp (c)
    pe2, tp2 = thermo.drylift(pres, temp, dwpt)
    blupper = pe2       # Define top of layer as LCL pres
    h2 = interp.hght(pe2, prof)
    te2 = interp.vtmp(pe2, prof)
    pcl.lclpres = pe2
    pcl.lclhght = interp.agl(h2, prof)

    # Calculate lifted parcel theta for use in iterative CINH loop below
    # RECALL: lifted parcel theta is CONSTANT from LPL to LCL
    theta_parcel = thermo.theta(pe2, tp2, 1000.)

    # Environmental theta and mixing ratio at LPL
    bltheta = thermo.theta(pres, interp.temp(pres, prof), 1000.)
    blmr = thermo.mixratio(pres, dwpt)

    # ACCUMULATED CINH IN MIXING LAYER BELOW THE LCL
    # This will be done in 10mb increments, and will use the virtual
    # temperature correction where possible
    pinc = -10
    a = int(lower)
    b = int(blupper)
    for pp in range(a, b, int(pinc)):
        pp1 = pp
        pp2 = pp + pinc
        if pp2 < blupper: pp2 = blupper
        dz = interp.hght(pp2, prof) - interp.hght(pp1, prof)

        # Calculate difference between Tv_parcel and Tv_environment at top
        # and bottom of 10mb layers. Make use of constant lifted parcel
        # theta and mixing ratio from LPL to LCL
        tv_env_bot = thermo.virtemp(pp1, thermo.theta(pp1,
            interp.temp(pp1, prof), 1000.), interp.dwpt(pp1, prof))
        tdef1 = (thermo.virtemp(pp1, theta_parcel,
            thermo.temp_at_mixrat(blmr, pp1)) - tv_env_bot) / \
            (thermo.ctok(tv_env_bot))

        tv_env_top = thermo.virtemp(pp2, thermo.theta(pp2,
            interp.temp(pp2, prof), 1000.), interp.dwpt(pp2, prof))
        tdef2 = (thermo.virtemp(pp2, theta_parcel,
            thermo.temp_at_mixrat(blmr, pp2)) - tv_env_top) / \
            (thermo.ctok(tv_env_bot))

        lyre = G * (tdef1 + tdef2) / 2. * dz
        if lyre < 0: totn += lyre

    # Move the bottom layer to the top of the boundary layer
    if lower > pe2:
        lower = pe2
        pcl.blayer = lower

    # Calculate height of various temperature levels
    p0c = temp_lvl(0., prof)
    pm10c = temp_lvl(-10., prof)
    pm20c = temp_lvl(-20., prof)
    pm30c = temp_lvl(-30., prof)
    hgt0c = interp.hght(p0c, prof)
    hgtm10c = interp.hght(pm10c, prof)
    hgtm20c = interp.hght(pm20c, prof)
    hgtm30c = interp.hght(pm30c, prof)
    pcl.p0c = p0c
    pcl.pm10c = pm10c
    pcl.pm20c = pm20c
    pcl.pm30c = pm30c
    pcl.hght0c = hgt0c
    pcl.hghtm10c = hgtm10c
    pcl.hghtm20c = hgtm20c
    pcl.hghtm30c = hgtm30c

    # Find lowest observation in layer
    i = 0
    while prof.gSndg[i][prof.pind] > lower:
        if i == prof.gNumLevels-1: break
        i += 1
    while not QC(prof.gSndg[i][prof.tdind]):
        if i == prof.gNumLevels-1: break
        i += 1
    lptr = i
    if prof.gSndg[i][prof.pind] == lower:
        if i != prof.gNumLevels-1: lptr += 1

    # Find highest observation in layer
    i = prof.gNumLevels-1
    while prof.gSndg[i][prof.pind] < upper:
        if i < lptr: break
        i -= 1
    uptr = i
    if prof.gSndg[i][prof.pind] == upper:
        if i > lptr: uptr -= 1

    # START WITH INTERPOLATED BOTTOM LAYER
    # Begin moist ascent from lifted parcel LCL (pe2, tp2)
    pe1 = lower
    h1 = interp.hght(pe1, prof)
    te1 = interp.vtmp(pe1, prof)
    tp1 = thermo.wetlift(pe2, tp2, pe1)
    lyre = 0
    lyrlast = 0
    for i in range(lptr, prof.gNumLevels):
        if not QC(prof.gSndg[i][prof.tind]): continue
        pe2 = prof.gSndg[i][prof.pind]
        h2 = prof.gSndg[i][prof.zind]
        te2 = interp.vtmp(pe2, prof)
        tp2 = thermo.wetlift(pe1, tp1, pe2)
        tdef1 = (thermo.virtemp(pe1, tp1, tp1) - te1) / thermo.ctok(te1)
        tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / thermo.ctok(te2)
        lyrlast = lyre
        lyre = G * (tdef1 + tdef2) / 2. * (h2 - h1)

        # Add layer energy to total positive if lyre > 0
        if lyre > 0: totp += lyre
        # Add layer energy to total negative if lyre < 0, only up to EL
        else:
            if pe2 > 500.: totn += lyre

        # Check for Max LI
        mli = thermo.virtemp(pe2, tp2, tp2) - te2
        if  mli > li_max:
            li_max = mli
            li_maxpres = pe2

        # Check for Max Cap Strength
        mcap = te2 - mli
        if mcap > cap_strength:
            cap_strength = mcap
            cap_strengthpres = pe2

        tote += lyre
        pelast = pe1
        pe1 = pe2
        h1 = h2
        te1 = te2
        tp1 = tp2

        # Is this the top of the specified layer
        if i >= uptr and not QC(pcl.bplus):
            pe3 = pe1
            h3 = h1
            te3 = te1
            tp3 = tp1
            lyrf = lyre
            if lyrf > 0:
                pcl.bplus = totp - lyrf
                pcl.bminus = totn
            else:
                pcl.bplus = totp
                if pe2 > 500.: pcl.bminus = totn + lyrf
                else: pcl.bminus = totn
            pe2 = upper
            h2 = interp.hght(pe2, prof)
            te2 = interp.vtmp(pe2, prof)
            tp2 = thermo.wetlift(pe3, tp3, pe2)
            tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / thermo.ctok(te3)
            tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / thermo.ctok(te2)
            lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
            if lyrf > 0: pcl.bplus += lyrf
            else:
                if pe2 > 500.: pcl.bminus += lyrf
            if pcl.bplus == 0: pcl.bminus = 0.

        # Is this the freezing level
        if te2 < 0. and not QC(pcl.bfzl):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.bfzl = totp - lyrf
            else: pcl.bfzl = totp
            if not QC(p0c) or p0c > pe3:
                pcl.bfzl = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgt0c - h3)
                if lyrf > 0: pcl.bfzl += lyrf

        # Is this the -10C level
        if te2 < -10. and not QC(pcl.wm10c):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.wm10c = totp - lyrf
            else: pcl.wm10c = totp
            if not QC(pm10c) or pm10c > pcl.lclpres:
                pcl.wm10c = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgtm10c - h3)
                if lyrf > 0: pcl.wm10c += lyrf

        # Is this the -20C level
        if te2 < -20. and not QC(pcl.wm20c):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.wm20c = totp - lyrf
            else: pcl.wm20c = totp
            if not QC(pm20c) or pm20c > pcl.lclpres:
                pcl.wm20c = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgtm20c - h3)
                if lyrf > 0: pcl.wm20c += lyrf

        # Is this the -30C level
        if te2 < -30. and not QC(pcl.wm30c):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.wm30c = totp - lyrf
            else: pcl.wm30c = totp
            if not QC(pm30c) or pm30c > pcl.lclpres:
                pcl.wm30c = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgtm30c - h3)
                if lyrf > 0: pcl.wm30c += lyrf

        # Is this the 3km level
        if pcl.lclhght < 3000.:
            h = interp.agl(interp.hght(pe2, prof), prof)
            if h >= 3000. and not QC(pcl.b3km):
                pe3 = pelast
                h3 = interp.hght(pe3, prof)
                te3 = interp.vtmp(pe3, prof)
                tp3 = thermo.wetlift(pe1, tp1, pe3)
                lyrf = lyre
                if lyrf > 0: pcl.b3km = totp - lyrf
                else: pcl.b3km = totp
                h2 = interp.msl(3000., prof)
                pe2 = interp.pres(h2, prof)
                if QC(pe2):
                    te2 = interp.vtmp(pe2, prof)
                    tp2 = thermo.wetlift(pe3, tp3, pe2)
                    tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                        thermo.ctok(te3)
                    tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                        thermo.ctok(te2)
                    lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
                    if lyrf > 0: pcl.b3km += lyrf
        else: pcl.b3km = 0.

        # Is this the 6km level
        if pcl.lclhght < 6000.:
            h = interp.agl(interp.hght(pe2, prof), prof)
            if h >= 6000. and not QC(pcl.b6km):
                pe3 = pelast
                h3 = interp.hght(pe3, prof)
                te3 = interp.vtmp(pe3, prof)
                tp3 = thermo.wetlift(pe1, tp1, pe3)
                lyrf = lyre
                if lyrf > 0: pcl.b6km = totp - lyrf
                else: pcl.b6km = totp
                h2 = interp.msl(6000., prof)
                pe2 = interp.pres(h2, prof)
                if QC(pe2):
                    te2 = interp.vtmp(pe2, prof)
                    tp2 = thermo.wetlift(pe3, tp3, pe2)
                    tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                        thermo.ctok(te3)
                    tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                        thermo.ctok(te2)
                    lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
                    if lyrf > 0: pcl.b6km += lyrf
        else: pcl.b6km = 0.

        # LFC Possibility
        if lyre >= 0. and lyrlast <= 0.:
            tp3 = tp1
            te3 = te1
            pe2 = pe1
            pe3 = pelast
            while interp.vtmp(pe3, prof) > thermo.virtemp(pe3,
                thermo.wetlift(pe2, tp3, pe3), thermo.wetlift(pe2, tp3, pe3)):
                    pe3 -= 5
            pcl.lfcpres = pe3
            pcl.lfchght = interp.agl(interp.hght(pe3, prof), prof)
            cinh_old = totn
            tote = 0.
            pcl.elpres = RMISSD
            li_max = RMISSD

            if cap_strength < 0.: cap_strength = 0.
            pcl.cap = cap_strength
            pcl.cappres = cap_strengthpres
            # Hack to force LFC to be at least at the LCL
            if pcl.lfcpres > pcl.lclpres:
                pcl.lfcpres = pcl.lclpres
                pcl.lfchght = pcl.lclhght

        # EL Possibility
        if lyre <= 0. and lyrlast >= 0.:
            tp3 = tp1
            te3 = te1
            pe2 = pe1
            pe3 = pelast
            while interp.vtmp(pe3, prof) < thermo.virtemp(pe3,
                thermo.wetlift(pe2, tp3, pe3), thermo.wetlift(pe2, tp3, pe3)):
                    pe3 -= 5
            pcl.elpres = pe3
            pcl.elhght = interp.agl(interp.hght(pe3, prof), prof)
            pcl.mplpres = RMISSD
            pcl.limax = -li_max
            pcl.limaxpress = li_maxpres

        # MPL Possibility
        if tote < 0. and not QC(pcl.mplpres) and QC(pcl.elpres):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            totx = tote - lyre
            pe2 = pelast
            while totx > 0:
                pe2 -= 1
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                h2 = interp.hght(pe2, prof)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
                totx += lyrf
                tp3 = tp2
                te3 = te2
                pe3 = pe2
            pcl.mplpres = pe2
            pcl.mplhght = interp.agl(interp.hght(pe2, prof), prof)

        # 500 hPa Lifted Index
        if prof.gSndg[i][prof.pind] <= 500. and pcl.li5 == RMISSD:
            a = interp.vtmp(500., prof)
            b = thermo.wetlift(pe1, tp1, 500.)
            pcl.li5 = a - thermo.virtemp(500, b, b)

        # 300 hPa Lifted Index
        if prof.gSndg[i][prof.pind] <= 300. and pcl.li3 == RMISSD:
            a = interp.vtmp(300., prof)
            b = thermo.wetlift(pe1, tp1, 300.)
            pcl.li3 = a - thermo.virtemp(300, b, b)

    # Calculate BRN if available
    pcl = bulk_rich(pcl, prof)

    pcl.bminus = cinh_old
    if pcl.bplus == 0: pcl.bminus = 0.
    return pcl
Example #24
0
def parcelx(lower, upper, pres, temp, dwpt, prof, **kwargs):
    '''
    Lifts the specified parcel, calculated various levels and parameters from
    the profile object. B+/B- are calculated based on the specified layer.

    !! All calculations use the virtual temperature correction unless noted. !!

    Inputs
    ------
        lower       (float)                 Lower-bound lifting level (hPa)
        upper       (float)                 Upper-bound lifting level
        pres        (float)                 Pressure of parcel to lift (hPa)
        temp        (float)                 Temperature of parcel to lift (C)
        dwpt        (float)                 Dew Point of parcel to lift (C)
        prof        (profile object)        Profile Object

    Returns
    -------
        pcl         (parcel object)         Parcel Object
    '''
    pcl = Parcel(-1, -1, pres, temp, dwpt)
    if 'lplvals' in kwargs: pcl.lplvals = kwargs.get('lplvals')
    else:
        lplvals = DefineParcel(prof, 5, pres=pres, temp=temp, dwpt=dwpt)
        pcl.lplvals = lplvals

    if prof.gNumLevels < 1: return pcl

    lyre = -1
    cap_strength = RMISSD
    cap_strengthpres = RMISSD
    li_max = RMISSD
    li_maxpres = RMISSD
    totp = 0.
    totn = 0.
    tote = 0.
    cinh_old = 0.

    # See if default layer is specified
    if lower == -1:
        lower = prof.gSndg[prof.sfc][prof.pind]
        pcl.blayer = lower
    if upper == -1:
        upper = prof.gSndg[prof.gNumLevels - 1][prof.pind]
        pcl.tlayer = upper

    # Make sure that this is a valid layer
    if lower > pres:
        lower = pres
        pcl.blayer = lower
    if not QC(interp.vtmp(lower, prof)) or \
       not QC(interp.vtmp(upper, prof)):
        return RMISSD

    # Begin with the Mixing Layer
    te1 = interp.vtmp(pres, prof)
    pe1 = lower
    h1 = interp.hght(pe1, prof)
    tp1 = thermo.virtemp(pres, temp, dwpt)
    # te1 = tp1

    # Lift parcel and return LCL pres (hPa) and LCL temp (c)
    pe2, tp2 = thermo.drylift(pres, temp, dwpt)
    blupper = pe2  # Define top of layer as LCL pres
    h2 = interp.hght(pe2, prof)
    te2 = interp.vtmp(pe2, prof)
    pcl.lclpres = pe2
    pcl.lclhght = interp.agl(h2, prof)

    # Calculate lifted parcel theta for use in iterative CINH loop below
    # RECALL: lifted parcel theta is CONSTANT from LPL to LCL
    theta_parcel = thermo.theta(pe2, tp2, 1000.)

    # Environmental theta and mixing ratio at LPL
    bltheta = thermo.theta(pres, interp.temp(pres, prof), 1000.)
    blmr = thermo.mixratio(pres, dwpt)

    # ACCUMULATED CINH IN MIXING LAYER BELOW THE LCL
    # This will be done in 10mb increments, and will use the virtual
    # temperature correction where possible
    pinc = -10
    a = int(lower)
    b = int(blupper)
    for pp in range(a, b, int(pinc)):
        pp1 = pp
        pp2 = pp + pinc
        if pp2 < blupper: pp2 = blupper
        dz = interp.hght(pp2, prof) - interp.hght(pp1, prof)

        # Calculate difference between Tv_parcel and Tv_environment at top
        # and bottom of 10mb layers. Make use of constant lifted parcel
        # theta and mixing ratio from LPL to LCL
        tv_env_bot = thermo.virtemp(
            pp1, thermo.theta(pp1, interp.temp(pp1, prof), 1000.),
            interp.dwpt(pp1, prof))
        tdef1 = (thermo.virtemp(pp1, theta_parcel,
            thermo.temp_at_mixrat(blmr, pp1)) - tv_env_bot) / \
            (thermo.ctok(tv_env_bot))

        tv_env_top = thermo.virtemp(
            pp2, thermo.theta(pp2, interp.temp(pp2, prof), 1000.),
            interp.dwpt(pp2, prof))
        tdef2 = (thermo.virtemp(pp2, theta_parcel,
            thermo.temp_at_mixrat(blmr, pp2)) - tv_env_top) / \
            (thermo.ctok(tv_env_bot))

        lyre = G * (tdef1 + tdef2) / 2. * dz
        if lyre < 0: totn += lyre

    # Move the bottom layer to the top of the boundary layer
    if lower > pe2:
        lower = pe2
        pcl.blayer = lower

    # Calculate height of various temperature levels
    p0c = temp_lvl(0., prof)
    pm10c = temp_lvl(-10., prof)
    pm20c = temp_lvl(-20., prof)
    pm30c = temp_lvl(-30., prof)
    hgt0c = interp.hght(p0c, prof)
    hgtm10c = interp.hght(pm10c, prof)
    hgtm20c = interp.hght(pm20c, prof)
    hgtm30c = interp.hght(pm30c, prof)
    pcl.p0c = p0c
    pcl.pm10c = pm10c
    pcl.pm20c = pm20c
    pcl.pm30c = pm30c
    pcl.hght0c = hgt0c
    pcl.hghtm10c = hgtm10c
    pcl.hghtm20c = hgtm20c
    pcl.hghtm30c = hgtm30c

    # Find lowest observation in layer
    i = 0
    while prof.gSndg[i][prof.pind] > lower:
        if i == prof.gNumLevels - 1: break
        i += 1
    while not QC(prof.gSndg[i][prof.tdind]):
        if i == prof.gNumLevels - 1: break
        i += 1
    lptr = i
    if prof.gSndg[i][prof.pind] == lower:
        if i != prof.gNumLevels - 1: lptr += 1

    # Find highest observation in layer
    i = prof.gNumLevels - 1
    while prof.gSndg[i][prof.pind] < upper:
        if i < lptr: break
        i -= 1
    uptr = i
    if prof.gSndg[i][prof.pind] == upper:
        if i > lptr: uptr -= 1

    # START WITH INTERPOLATED BOTTOM LAYER
    # Begin moist ascent from lifted parcel LCL (pe2, tp2)
    pe1 = lower
    h1 = interp.hght(pe1, prof)
    te1 = interp.vtmp(pe1, prof)
    tp1 = thermo.wetlift(pe2, tp2, pe1)
    lyre = 0
    lyrlast = 0
    for i in range(lptr, prof.gNumLevels):
        if not QC(prof.gSndg[i][prof.tind]): continue
        pe2 = prof.gSndg[i][prof.pind]
        h2 = prof.gSndg[i][prof.zind]
        te2 = interp.vtmp(pe2, prof)
        tp2 = thermo.wetlift(pe1, tp1, pe2)
        tdef1 = (thermo.virtemp(pe1, tp1, tp1) - te1) / thermo.ctok(te1)
        tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / thermo.ctok(te2)
        lyrlast = lyre
        lyre = G * (tdef1 + tdef2) / 2. * (h2 - h1)

        # Add layer energy to total positive if lyre > 0
        if lyre > 0:
            totp += lyre
            # Add layer energy to total negative if lyre < 0, only up to EL
        else:
            if pe2 > 500.: totn += lyre

        # Check for Max LI
        mli = thermo.virtemp(pe2, tp2, tp2) - te2
        if mli > li_max:
            li_max = mli
            li_maxpres = pe2

        # Check for Max Cap Strength
        mcap = te2 - mli
        if mcap > cap_strength:
            cap_strength = mcap
            cap_strengthpres = pe2

        tote += lyre
        pelast = pe1
        pe1 = pe2
        h1 = h2
        te1 = te2
        tp1 = tp2

        # Is this the top of the specified layer
        if i >= uptr and not QC(pcl.bplus):
            pe3 = pe1
            h3 = h1
            te3 = te1
            tp3 = tp1
            lyrf = lyre
            if lyrf > 0:
                pcl.bplus = totp - lyrf
                pcl.bminus = totn
            else:
                pcl.bplus = totp
                if pe2 > 500.: pcl.bminus = totn + lyrf
                else: pcl.bminus = totn
            pe2 = upper
            h2 = interp.hght(pe2, prof)
            te2 = interp.vtmp(pe2, prof)
            tp2 = thermo.wetlift(pe3, tp3, pe2)
            tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / thermo.ctok(te3)
            tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / thermo.ctok(te2)
            lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
            if lyrf > 0: pcl.bplus += lyrf
            else:
                if pe2 > 500.: pcl.bminus += lyrf
            if pcl.bplus == 0: pcl.bminus = 0.

        # Is this the freezing level
        if te2 < 0. and not QC(pcl.bfzl):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.bfzl = totp - lyrf
            else: pcl.bfzl = totp
            if not QC(p0c) or p0c > pe3:
                pcl.bfzl = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgt0c - h3)
                if lyrf > 0: pcl.bfzl += lyrf

        # Is this the -10C level
        if te2 < -10. and not QC(pcl.wm10c):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.wm10c = totp - lyrf
            else: pcl.wm10c = totp
            if not QC(pm10c) or pm10c > pcl.lclpres:
                pcl.wm10c = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgtm10c - h3)
                if lyrf > 0: pcl.wm10c += lyrf

        # Is this the -20C level
        if te2 < -20. and not QC(pcl.wm20c):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.wm20c = totp - lyrf
            else: pcl.wm20c = totp
            if not QC(pm20c) or pm20c > pcl.lclpres:
                pcl.wm20c = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgtm20c - h3)
                if lyrf > 0: pcl.wm20c += lyrf

        # Is this the -30C level
        if te2 < -30. and not QC(pcl.wm30c):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            lyrf = lyre
            if lyrf > 0.: pcl.wm30c = totp - lyrf
            else: pcl.wm30c = totp
            if not QC(pm30c) or pm30c > pcl.lclpres:
                pcl.wm30c = 0
            elif QC(pe2):
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (hgtm30c - h3)
                if lyrf > 0: pcl.wm30c += lyrf

        # Is this the 3km level
        if pcl.lclhght < 3000.:
            h = interp.agl(interp.hght(pe2, prof), prof)
            if h >= 3000. and not QC(pcl.b3km):
                pe3 = pelast
                h3 = interp.hght(pe3, prof)
                te3 = interp.vtmp(pe3, prof)
                tp3 = thermo.wetlift(pe1, tp1, pe3)
                lyrf = lyre
                if lyrf > 0: pcl.b3km = totp - lyrf
                else: pcl.b3km = totp
                h2 = interp.msl(3000., prof)
                pe2 = interp.pres(h2, prof)
                if QC(pe2):
                    te2 = interp.vtmp(pe2, prof)
                    tp2 = thermo.wetlift(pe3, tp3, pe2)
                    tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                        thermo.ctok(te3)
                    tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                        thermo.ctok(te2)
                    lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
                    if lyrf > 0: pcl.b3km += lyrf
        else: pcl.b3km = 0.

        # Is this the 6km level
        if pcl.lclhght < 6000.:
            h = interp.agl(interp.hght(pe2, prof), prof)
            if h >= 6000. and not QC(pcl.b6km):
                pe3 = pelast
                h3 = interp.hght(pe3, prof)
                te3 = interp.vtmp(pe3, prof)
                tp3 = thermo.wetlift(pe1, tp1, pe3)
                lyrf = lyre
                if lyrf > 0: pcl.b6km = totp - lyrf
                else: pcl.b6km = totp
                h2 = interp.msl(6000., prof)
                pe2 = interp.pres(h2, prof)
                if QC(pe2):
                    te2 = interp.vtmp(pe2, prof)
                    tp2 = thermo.wetlift(pe3, tp3, pe2)
                    tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                        thermo.ctok(te3)
                    tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                        thermo.ctok(te2)
                    lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
                    if lyrf > 0: pcl.b6km += lyrf
        else: pcl.b6km = 0.

        # LFC Possibility
        if lyre >= 0. and lyrlast <= 0.:
            tp3 = tp1
            te3 = te1
            pe2 = pe1
            pe3 = pelast
            while interp.vtmp(pe3, prof) > thermo.virtemp(
                    pe3, thermo.wetlift(pe2, tp3, pe3),
                    thermo.wetlift(pe2, tp3, pe3)):
                pe3 -= 5
            pcl.lfcpres = pe3
            pcl.lfchght = interp.agl(interp.hght(pe3, prof), prof)
            cinh_old = totn
            tote = 0.
            pcl.elpres = RMISSD
            li_max = RMISSD

            if cap_strength < 0.: cap_strength = 0.
            pcl.cap = cap_strength
            pcl.cappres = cap_strengthpres
            # Hack to force LFC to be at least at the LCL
            if pcl.lfcpres > pcl.lclpres:
                pcl.lfcpres = pcl.lclpres
                pcl.lfchght = pcl.lclhght

        # EL Possibility
        if lyre <= 0. and lyrlast >= 0.:
            tp3 = tp1
            te3 = te1
            pe2 = pe1
            pe3 = pelast
            while interp.vtmp(pe3, prof) < thermo.virtemp(
                    pe3, thermo.wetlift(pe2, tp3, pe3),
                    thermo.wetlift(pe2, tp3, pe3)):
                pe3 -= 5
            pcl.elpres = pe3
            pcl.elhght = interp.agl(interp.hght(pe3, prof), prof)
            pcl.mplpres = RMISSD
            pcl.limax = -li_max
            pcl.limaxpress = li_maxpres

        # MPL Possibility
        if tote < 0. and not QC(pcl.mplpres) and QC(pcl.elpres):
            pe3 = pelast
            h3 = interp.hght(pe3, prof)
            te3 = interp.vtmp(pe3, prof)
            tp3 = thermo.wetlift(pe1, tp1, pe3)
            totx = tote - lyre
            pe2 = pelast
            while totx > 0:
                pe2 -= 1
                te2 = interp.vtmp(pe2, prof)
                tp2 = thermo.wetlift(pe3, tp3, pe2)
                h2 = interp.hght(pe2, prof)
                tdef3 = (thermo.virtemp(pe3, tp3, tp3) - te3) / \
                    thermo.ctok(te3)
                tdef2 = (thermo.virtemp(pe2, tp2, tp2) - te2) / \
                    thermo.ctok(te2)
                lyrf = G * (tdef3 + tdef2) / 2. * (h2 - h3)
                totx += lyrf
                tp3 = tp2
                te3 = te2
                pe3 = pe2
            pcl.mplpres = pe2
            pcl.mplhght = interp.agl(interp.hght(pe2, prof), prof)

        # 500 hPa Lifted Index
        if prof.gSndg[i][prof.pind] <= 500. and pcl.li5 == RMISSD:
            a = interp.vtmp(500., prof)
            b = thermo.wetlift(pe1, tp1, 500.)
            pcl.li5 = a - thermo.virtemp(500, b, b)

        # 300 hPa Lifted Index
        if prof.gSndg[i][prof.pind] <= 300. and pcl.li3 == RMISSD:
            a = interp.vtmp(300., prof)
            b = thermo.wetlift(pe1, tp1, 300.)
            pcl.li3 = a - thermo.virtemp(300, b, b)

    # Calculate BRN if available
    pcl = bulk_rich(pcl, prof)

    pcl.bminus = cinh_old
    if pcl.bplus == 0: pcl.bminus = 0.
    return pcl
Example #25
0
def init_phase(prof):
    '''
        Inital Precipitation Phase
        Adapted from SHARP code donated by Rich Thompson (SPC)

        This function determines the initial phase of any precipitation source in the profile.
        It does this either by finding a source of precipitation by searching for the highest 50 mb 
        layer that has a relative humidity greater than 80 percent at the top and the bottom
        of the layer.  This layer may be found either in the lowest 5 km of the profile, and if
        an OMEG profile is specified in the profile object, it will search for the layers with
        upward motion.

        The precipitation type is determined by using a.) the interpolated temperature in the middle
        of the precipitation source layer and b.) set temperature thresholds to determine the 
        precipitation type.  The type may be "Rain", "Freezing Rain", "ZR/S Mix", or "Snow".

        Parameters
        ----------
        prof : Profile object (omega profile optional)

        Returns
        -------
        plevel : the pressure level of the precipitation source (mb)
        phase : the phase type of the precipitation (int)
                phase == 0 for "Rain"
                phase == 1 for "Freezing Rain" or "ZR/S Mix"
                phase == 3 for "Snow"
        tmp : the temperature at the level that is the precipitation source
        st : a string naming the precipitation type

    '''
    # Needs to be tested

    plevel = 0
    phase = -1

    # First, determine whether Upward VVELS are available.  If they are,  
    # use them to determine level where precipitation will develop.
    avail = np.ma.where(prof.omeg < .1)[0]

    hght_agl = interp.to_agl(prof, prof.hght)
    if len(avail) < 5:
        # No VVELS...must look for saturated level 
        # Find the highest near-saturated 50mb layer below 5km agl
        below_5km_idx = np.ma.where((hght_agl < 5000.) &\
                                    (hght_agl >= 0))[0]

    else:
        # Use the VV to find the source of precip.
        below_5km_idx = np.ma.where((hght_agl < 5000.) &\
                                    (hght_agl >= 0) &\
                                    (prof.omeg <= 0))[0]

    # Compute the RH at the top and bottom of 50 mb layers
    rh = thermo.relh(prof.pres, prof.tmpc, prof.dwpc)[below_5km_idx]
    sats = np.ma.where(rh > 80)[0]
    new_pres = prof.pres[below_5km_idx][sats] + 50.
    new_temp = interp.temp(prof, new_pres)
    new_dwpt = interp.dwpt(prof, new_pres)
    rh_plus50 = thermo.relh(new_pres, new_temp, new_dwpt)
    # Find layers where the RH is >80% at the top and bottom
    layers_idx = np.ma.where(rh_plus50 > 80)[0]

    if len(layers_idx) == 0:
        # Found no precipitation source layers
        st = "N/A"
        return prof.missing, phase, prof.missing, st

    # Find the highest layer up via the largest index
    top_most_layer = np.ma.max(layers_idx)
    plevel = new_pres[top_most_layer] - 25.

    # Determine the initial precip type based on the temp in the layer
    tmp = interp.temp(prof, plevel)
    if tmp > 0:
        phase = 0
        st = "Rain"
    elif tmp <= 0 and tmp > -5:
        phase = 1
        st = "Freezing Rain"
    elif tmp <=-5 and tmp > -9:
        phase = 1
        st = "ZR/S Mix"
    elif tmp <= -9:
        phase = 3
        st = "Snow"
    else:
        st = "N/A"

    return plevel, phase, tmp, st
Example #26
0
def mean_mixratio(prof, lower=-1, upper=-1):
    '''
    Calculates the mean mixing ratio from a profile object within the
    specified layer.

    Inputs
    ------
        prof        (profile object)    Profile Object
        lower       (float)             Bottom level (hPa) [-1=SFC]
        upper       (float)             Top level (hPa) [-1=SFC-100hPa]

    Returns
    -------
        Mean Mixing Ratio   (float)
    '''
    if lower == -1: lower = prof.gSndg[prof.sfc][prof.pind]
    if upper == -1: upper = prof.gSndg[prof.sfc][prof.pind] - 100.

    if not QC(interp.temp(upper, prof)): mmw = RMISSD
    if not QC(interp.temp(lower, prof)): prof.gSndg[prof.sfc][prof.pind]

    # Find lowest observations in the layer
    i = 0
    while prof.gSndg[i][prof.pind] > lower: i+=1
    while not QC(prof.gSndg[i][prof.tdind]): i+=1
    lptr = i
    if prof.gSndg[i][prof.pind] == lower: lptr+=1

    # Find highest observations in the layer
    i = prof.gNumLevels - 1
    while prof.gSndg[i][prof.pind] < upper: i-=1
    uptr = i
    if prof.gSndg[i][prof.pind] == upper: uptr-=1

    totd = 0
    totp = 0

    # Start with interpolated bottom layer
    p1 = lower
    dp1 = interp.dwpt(p1, prof)
    num = 1

    # Calculate every level that reports a dew point
    for i in range(lptr, uptr+1):
        if QC(prof.gSndg[i][prof.tdind]):
            dp2 = prof.gSndg[i][prof.tdind]
            p2 = prof.gSndg[i][prof.pind]
            dpbar = (dp1 + dp2) / 2.
            pbar = (p1 + p2) / 2.
            totd += dpbar
            totp += pbar
            dp1 = dp2
            p1 = p2
            num += 1

    # Finish with top layer
    dp2 = interp.dwpt(upper, prof)
    p2 = upper
    dbar = (dp1 + dp2) / 2.
    pbar = (p1 + p2) / 2.
    totd += dbar
    totp += pbar
    return thermo.mixratio(totp/num, totd/num)
Example #27
0
def unstable_level(prof, lower, upper):
    '''
    Finds the most unstable level between the lower and upper levels.

    Inputs
    ------
        prof        (profile object)    Profile Object
        lower       (float)             Bottom level (hPa) [-1=SFC]
        upper       (float)             Top level (hPa) [-1=SFC-100hPa]

    Returns
    -------
        Pressure Level of most unstable level   (float [hPa])
    '''
    if lower == -1: lower = prof.gSndg[prof.sfc][prof.pind]
    if upper == -1: upper = prof.gSndg[prof.sfc][prof.pind] - 400.

    # Make sure this is a valid layer
    while not QC(interp.dwpt(upper, prof)): upper += 50.
    if not QC(interp.temp(lower, prof)): lower = prof.gSndg[prof.sfc][0]

    # Find lowest observations in the layer
    i = 0
    while prof.gSndg[i][prof.pind] > lower: i+=1
    while not QC(prof.gSndg[i][prof.tind]): i+=1
    lptr = i
    if prof.gSndg[i][prof.pind] == lower: lptr+=1

    # Find highest observations in the layer
    i = prof.gNumLevels - 1
    while prof.gSndg[i][prof.pind] < upper: i-=1
    uptr = i
    if prof.gSndg[i][prof.pind] == upper: uptr-=1

    # Start with interpolated bottom layer
    p1 = lower
    t1 = interp.temp(p1, prof)
    td1 = interp.dwpt(p1, prof)
    p2, t2 = thermo.drylift(p1, t1, td1)
    tmax = thermo.wetlift(p2, t2, 1000.)
    pmax = p1

    # Calculate every level that reports a dew point
    for i in range(lptr, uptr+1):
        if QC(prof.gSndg[i][prof.tdind]):
            p1 = prof.gSndg[i][prof.pind]
            t1 = prof.gSndg[i][prof.tind]
            td1 = prof.gSndg[i][prof.tdind]
            p2, t2 = thermo.drylift(p1, t1, td1)
            t1 = thermo.wetlift(p2, t2, 1000.)
            if t1 > tmax:
                tmax = t1
                pmax = p1

    # Finish with interpolated top layer
    p1 = upper
    t1 = interp.temp(p1, prof)
    td1 = interp.dwpt(p1, prof)
    p2, t2 = thermo.drylift(p1, t1, td1)
    t1 = thermo.wetlift(p2, t2, 1000.)
    if t1 > tmax:
        pmax = prof.gSndg[i][prof.pind]

    return pmax
Example #28
0
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
Example #29
0
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
Example #30
0
def init_phase(prof):
    '''
        Inital Precipitation Phase
        Adapted from SHARP code donated by Rich Thompson (SPC)

        This function determines the initial phase of any precipitation source in the profile.
        It does this either by finding a source of precipitation by searching for the highest 50 mb 
        layer that has a relative humidity greater than 80 percent at the top and the bottom
        of the layer.  This layer may be found either in the lowest 5 km of the profile, and if
        an OMEG profile is specified in the profile object, it will search for the layers with
        upward motion.

        The precipitation type is determined by using a.) the interpolated temperature in the middle
        of the precipitation source layer and b.) set temperature thresholds to determine the 
        precipitation type.  The type may be "Rain", "Freezing Rain", "ZR/S Mix", or "Snow".

        Parameters
        ----------
        prof : Profile object (omega profile optional)

        Returns
        -------
        plevel : the pressure level of the precipitation source (mb)
        phase : the phase type of the precipitation (int)
                phase == 0 for "Rain"
                phase == 1 for "Freezing Rain" or "ZR/S Mix"
                phase == 3 for "Snow"
        tmp : the temperature at the level that is the precipitation source
        st : a string naming the precipitation type

    '''
    # Needs to be tested

    plevel = 0
    phase = -1

    # First, determine whether Upward VVELS are available.  If they are,
    # use them to determine level where precipitation will develop.
    avail = np.ma.where(prof.omeg < .1)[0]

    hght_agl = interp.to_agl(prof, prof.hght)
    if len(avail) < 5:
        # No VVELS...must look for saturated level
        # Find the highest near-saturated 50mb layer below 5km agl
        below_5km_idx = np.ma.where((hght_agl < 5000.) &\
                                    (hght_agl >= 0))[0]

    else:
        # Use the VV to find the source of precip.
        below_5km_idx = np.ma.where((hght_agl < 5000.) &\
                                    (hght_agl >= 0) &\
                                    (prof.omeg <= 0))[0]

    # Compute the RH at the top and bottom of 50 mb layers
    rh = thermo.relh(prof.pres, prof.tmpc, prof.dwpc)[below_5km_idx]
    sats = np.ma.where(rh > 80)[0]
    new_pres = prof.pres[below_5km_idx][sats] + 50.
    new_temp = interp.temp(prof, new_pres)
    new_dwpt = interp.dwpt(prof, new_pres)
    rh_plus50 = thermo.relh(new_pres, new_temp, new_dwpt)
    # Find layers where the RH is >80% at the top and bottom
    layers_idx = np.ma.where(rh_plus50 > 80)[0]

    if len(layers_idx) == 0:
        # Found no precipitation source layers
        st = "N/A"
        return prof.missing, phase, prof.missing, st

    # Find the highest layer up via the largest index
    top_most_layer = np.ma.max(layers_idx)
    plevel = new_pres[top_most_layer] - 25.

    # Determine the initial precip type based on the temp in the layer
    tmp = interp.temp(prof, plevel)
    if tmp > 0:
        phase = 0
        st = "Rain"
    elif tmp <= 0 and tmp > -5:
        phase = 1
        st = "Freezing Rain"
    elif tmp <= -5 and tmp > -9:
        phase = 1
        st = "ZR/S Mix"
    elif tmp <= -9:
        phase = 3
        st = "Snow"
    else:
        st = "N/A"

    return plevel, phase, tmp, st
Example #31
0
def haines_low(prof):
    '''
        Haines Index Low Elevation calculation
        
        Calculates the Haines Index(Lower Atmosphere Severity Index)
        using the lower elevation parmeters, used below 1000ft or 305 m.
        
        Pressure levels 950 mb and 850 mb
        Dewpoint depression at 850 mb
        
        Lapse Rate Term
        ---------------
        1 : < 4C
        2 : 4C to 7C
        3 : > 7C
        
        Dewpoint Depression Term
        ------------------------
        1 : < 6C
        2 : 6C to 9C
        3 : > 9C
        
        Adapted from S-591 course 
        Added by Nickolai Reimer (NWS Billings, MT)
        
        Parameters
        ----------
        prof : profile object
            Profile object

        Returns
        -------
        param : number
            the Haines Index low

    '''
    
    tp1  = interp.temp(prof, 950)
    tp2  = interp.temp(prof, 850)
    tdp2 = interp.dwpt(prof, 850)
    
    if utils.QC(tp1) and utils.QC(tp2) and utils.QC(tdp2):
        lapse_rate = tp1 - tp2
        dewpoint_depression = tp2 - tdp2
        
        if lapse_rate < 4:
            a = 1
        elif 4 <= lapse_rate and lapse_rate <= 7:
            a = 2
        else:
            a = 3
        
        if dewpoint_depression < 6:
            b = 1
        elif 6 <= dewpoint_depression and dewpoint_depression <= 9:
            b = 2
        else:
            b = 3
        return a + b
    else:
        return constants.MISSING