Ejemplo n.º 1
0
def helicity(prof, lower, upper, stu=0, stv=0, dp=-1, exact=True):
    '''
    Calculates the relative helicity (m2/s2) of a layer from lower to upper.
    If storm-motion vector is supplied, storm-relative helicity, both
    positve and negative, is returned.

    Parameters
    ----------
    prof : profile object
        Profile Object
    lower : number
        Bottom level of layer (m, AGL)
    upper : number
        Top level of layer (m, AGL)
    stu : number (optional; default = 0)
        U-component of storm-motion
    stv : number (optional; default = 0)
        V-component of storm-motion
    dp : negative integer (optional; default -1)
        The pressure increment for the interpolated sounding
    exact : bool (optional; default = True)
        Switch to choose between using the exact data (slower) or using
        interpolated sounding at 'dp' pressure levels (faster)

    Returns
    -------
    phel+nhel : number
        Combined Helicity (m2/s2)
    phel : number
        Positive Helicity (m2/s2)
    nhel : number
        Negative Helicity (m2/s2)

    '''
    if lower != upper:
        lower = interp.to_msl(prof, lower)
        upper = interp.to_msl(prof, upper)
        plower = interp.pres(prof, lower)
        pupper = interp.pres(prof, upper)
        if exact:
            ind1 = np.where(plower >= prof.pres)[0].min()
            ind2 = np.where(pupper <= prof.pres)[0].max()
            u1, v1 = interp.components(prof, plower)
            u2, v2 = interp.components(prof, pupper)
            u = np.concatenate([[u1], prof.u[ind1:ind2 + 1].compressed(),
                                [u2]])
            v = np.concatenate([[v1], prof.v[ind1:ind2 + 1].compressed(),
                                [v2]])
        else:
            ps = np.arange(plower, pupper + dp, dp)
            u, v = interp.components(prof, ps)
        sru = utils.KTS2MS(u - stu)
        srv = utils.KTS2MS(v - stv)
        layers = (sru[1:] * srv[:-1]) - (sru[:-1] * srv[1:])
        phel = layers[layers > 0].sum()
        nhel = layers[layers < 0].sum()
    else:
        phel = nhel = 0

    return phel + nhel, phel, nhel
Ejemplo n.º 2
0
def wind_shear(prof, pbot=850, ptop=250):
    '''
    Calculates the shear between the wind at (pbot) and (ptop).

    Parameters
    ----------
    prof: profile object
        Profile object
    pbot : number (optional; default 850 hPa)
        Pressure of the bottom level (hPa)
    ptop : number (optional; default 250 hPa)
        Pressure of the top level (hPa)

    Returns
    -------
    shu : number
        U-component (kts)
    shv : number
        V-component (kts)

    '''
    if prof.wdir.count() == 0 or not utils.QC(ptop) or not utils.QC(pbot):
        return ma.masked, ma.masked

    ubot, vbot = interp.components(prof, pbot)
    utop, vtop = interp.components(prof, ptop)
    shu = utop - ubot
    shv = vtop - vbot
    return shu, shv
Ejemplo n.º 3
0
def wind_shear(prof, pbot=850, ptop=250):
    '''
    Calculates the shear between the wind at (pbot) and (ptop).

    Parameters
    ----------
    prof: profile object
        Profile object
    pbot : number (optional; default 850 hPa)
        Pressure of the bottom level (hPa)
    ptop : number (optional; default 250 hPa)
        Pressure of the top level (hPa)

    Returns
    -------
    shu : number
        U-component
    shv : number
        V-component

    '''
    ubot, vbot = interp.components(prof, pbot)
    utop, vtop = interp.components(prof, ptop)
    shu = utop - ubot
    shv = vtop - vbot
    return shu, shv
Ejemplo n.º 4
0
def wind_shear(prof, pbot=850, ptop=250):
    '''
    Calculates the shear between the wind at (pbot) and (ptop).

    Parameters
    ----------
    prof: profile object
        Profile object
    pbot : number (optional; default 850 hPa)
        Pressure of the bottom level (hPa)
    ptop : number (optional; default 250 hPa)
        Pressure of the top level (hPa)

    Returns
    -------
    shu : number
        U-component
    shv : number
        V-component

    '''
    ubot, vbot = interp.components(prof, pbot)
    utop, vtop = interp.components(prof, ptop)
    shu = utop - ubot
    shv = vtop - vbot
    return shu, shv
Ejemplo n.º 5
0
def helicity(prof, lower, upper, stu=0, stv=0, dp=-1, exact=True):
    '''
    Calculates the relative helicity (m2/s2) of a layer from lower to upper.
    If storm-motion vector is supplied, storm-relative helicity, both
    positve and negative, is returned.

    Parameters
    ----------
    prof : profile object
        Profile Object
    lower : number
        Bottom level of layer (m, AGL)
    upper : number
        Top level of layer (m, AGL)
    stu : number (optional; default = 0)
        U-component of storm-motion
    stv : number (optional; default = 0)
        V-component of storm-motion
    dp : negative integer (optional; default -1)
        The pressure increment for the interpolated sounding
    exact : bool (optional; default = True)
        Switch to choose between using the exact data (slower) or using
        interpolated sounding at 'dp' pressure levels (faster)

    Returns
    -------
    phel+nhel : number
        Combined Helicity (m2/s2)
    phel : number
        Positive Helicity (m2/s2)
    nhel : number
        Negative Helicity (m2/s2)

    '''
    if lower != upper:
        lower = interp.to_msl(prof, lower)
        upper = interp.to_msl(prof, upper)
        plower = interp.pres(prof, lower)
        pupper = interp.pres(prof, upper)
        if np.isnan(plower) or np.isnan(pupper):
            return np.ma.masked, np.ma.masked, np.ma.masked
        if exact:
            ind1 = np.where(plower >= prof.pres)[0].min()
            ind2 = np.where(pupper <= prof.pres)[0].max()
            u1, v1 = interp.components(prof, plower)
            u2, v2 = interp.components(prof, pupper)
            u = np.concatenate([[u1], prof.u[ind1:ind2+1].compressed(), [u2]])
            v = np.concatenate([[v1], prof.v[ind1:ind2+1].compressed(), [v2]])
        else:
            ps = np.arange(plower, pupper+dp, dp)
            u, v = interp.components(prof, ps)
        sru = utils.KTS2MS(u - stu)
        srv = utils.KTS2MS(v - stv)
        layers = (sru[1:] * srv[:-1]) - (sru[:-1] * srv[1:])
        phel = layers[layers > 0].sum()
        nhel = layers[layers < 0].sum()
    else:
        phel = nhel = 0

    return phel+nhel, phel, nhel
Ejemplo n.º 6
0
def max_wind(lower, upper, prof):
    '''
    Finds the maximum wind speed of the layer given by lower and upper levels.
    In the event of the maximum wind speed occurring at multiple levels, the
    lowest level it occurs is returned.

    Inputs
    ------
        lower       (float)             Bottom level of layer (m, AGL)
        upper       (float)             Top level of layer (m, AGL)
        prof        (profile object)    Profile Object

    Returns
    -------
        p           (float)             Pressure level (hPa) of max wind speed
        maxu        (float)             Maximum U-component
        maxv        (float)             Maximum V-component
    '''
    if lower == -1: lower = prof.gSndg[prof.sfc][prof.pind]
    if upper == -1: upper = prof.gSndg[prof.gNumLevels - 1][prof.pind]

    # 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
    maxu, maxv = interp.components(lower, prof)
    maxspd = vector.comp2vec(maxu, maxv)[1]
    p = lower

    # Loop through all levels in layer
    for i in range(lptr, uptr + 1):
        if QC(prof.gSndg[i][prof.pind]) and QC(prof.gSndg[i][prof.uind]) and \
           QC(prof.gSndg[i][prof.vind]):
            spd = vector.comp2vec(prof.gSndg[i][prof.uind],
                                  prof.gSndg[i][prof.vind])[1]
            if spd > maxspd:
                maxspd = spd
                maxu = prof.gSndg[i][prof.uind]
                maxv = prof.gSndg[i][prof.vind]
                p = prof.gSndg[i][prof.pind]

    # Finish with interpolated top level
    tmpu, tmpv = interp.components(upper, prof)
    tmpspd = vector.comp2vec(tmpu, tmpv)[1]
    if tmpspd > maxspd:
        maxu = tmpu
        maxv = tmpv
        maxspd = tmpspd
        p = upper

    return p, maxu, maxv
Ejemplo n.º 7
0
def max_wind(lower, upper, prof):
    '''
    Finds the maximum wind speed of the layer given by lower and upper levels.
    In the event of the maximum wind speed occurring at multiple levels, the
    lowest level it occurs is returned.

    Inputs
    ------
        lower       (float)             Bottom level of layer (m, AGL)
        upper       (float)             Top level of layer (m, AGL)
        prof        (profile object)    Profile Object

    Returns
    -------
        p           (float)             Pressure level (hPa) of max wind speed
        maxu        (float)             Maximum U-component
        maxv        (float)             Maximum V-component
    '''
    if lower == -1: lower = prof.gSndg[prof.sfc][prof.pind]
    if upper == -1: upper = prof.gSndg[prof.gNumLevels-1][prof.pind]

    # 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
    maxu, maxv = interp.components(lower, prof)
    maxspd = vector.comp2vec(maxu, maxv)[1]
    p = lower

    # Loop through all levels in layer
    for i in range(lptr, uptr+1):
        if QC(prof.gSndg[i][prof.pind]) and QC(prof.gSndg[i][prof.uind]) and \
           QC(prof.gSndg[i][prof.vind]):
            spd = vector.comp2vec(prof.gSndg[i][prof.uind],
                prof.gSndg[i][prof.vind])[1]
            if spd > maxspd:
                maxspd = spd
                maxu = prof.gSndg[i][prof.uind]
                maxv = prof.gSndg[i][prof.vind]
                p = prof.gSndg[i][prof.pind]

    # Finish with interpolated top level
    tmpu, tmpv = interp.components(upper, prof)
    tmpspd = vector.comp2vec(tmpu, tmpv)[1]
    if tmpspd > maxspd:
        maxu = tmpu
        maxv = tmpv
        maxspd = tmpspd
        p = upper

    return p, maxu, maxv
def test_components():
    input_p = 900
    correct_u, correct_v = -5.53976475, 20.6746835
    correct = [correct_u, correct_v]
    returned = interp.components(prof, input_p)
    npt.assert_almost_equal(returned, correct)

    input_p = [900, 800, 600, 400]
    correct_u = np.asarray([-5.53976475, 5.95267234, 23.10783339, 42.])
    correct_v = np.asarray([20.6746835, 15.54170573, -9.37502817, 0])
    correct = [correct_u, correct_v]
    returned = interp.components(prof, input_p)
    npt.assert_almost_equal(returned, correct)
Ejemplo n.º 9
0
def test_components():
    input_p = 900
    correct_u, correct_v = -5.53976475, 20.6746835
    correct = [correct_u, correct_v]
    returned = interp.components(prof, input_p)
    npt.assert_almost_equal(returned, correct)

    input_p = [900, 800, 600, 400]
    correct_u = np.asarray([-5.53976475, 5.95267234,
                            23.10783339, 42.])
    correct_v = np.asarray([20.6746835, 15.54170573,
                            -9.37502817, 0])
    correct = [correct_u, correct_v]
    returned = interp.components(prof, input_p)
    npt.assert_almost_equal(returned, correct)
Ejemplo n.º 10
0
def mean_wind_npw(prof, pbot=850., ptop=250., dp=-1, stu=0, stv=0):
    '''
    Calculates a non-pressure-weighted mean wind through a layer. The default
    layer is 850 to 200 hPa.

    Parameters
    ----------
    prof: profile object
        Profile object
    pbot : number (optional; default 850 hPa)
        Pressure of the bottom level (hPa)
    ptop : number (optional; default 250 hPa)
        Pressure of the top level (hPa)
    dp : negative integer (optional; default -1)
        The pressure increment for the interpolated sounding
    stu : number (optional; default 0)
        U-component of storm-motion vector
    stv : number (optional; default 0)
        V-component of storm-motion vector

    Returns
    -------
    mnu : number
        U-component
    mnv : number
        V-component

    '''
    if dp > 0: dp = -dp
    ps = np.arange(pbot, ptop+dp, dp)
    u, v = interp.components(prof, ps)
    # u -= stu; v -= stv
    return u.mean()-stu, v.mean()-stv
Ejemplo n.º 11
0
def mean_wind_npw(prof, pbot=850., ptop=250., dp=-1, stu=0, stv=0):
    '''
    Calculates a non-pressure-weighted mean wind through a layer. The default
    layer is 850 to 200 hPa.

    Parameters
    ----------
    prof: profile object
        Profile object
    pbot : number (optional; default 850 hPa)
        Pressure of the bottom level (hPa)
    ptop : number (optional; default 250 hPa)
        Pressure of the top level (hPa)
    dp : negative integer (optional; default -1)
        The pressure increment for the interpolated sounding
    stu : number (optional; default 0)
        U-component of storm-motion vector
    stv : number (optional; default 0)
        V-component of storm-motion vector

    Returns
    -------
    mnu : number
        U-component
    mnv : number
        V-component

    '''
    if dp > 0: dp = -dp
    ps = np.arange(pbot, ptop + dp, dp)
    u, v = interp.components(prof, ps)
    # u -= stu; v -= stv
    return u.mean() - stu, v.mean() - stv
Ejemplo n.º 12
0
def mean_wind_npw(pbot, ptop, prof, psteps=20, stu=0, stv=0):
    '''
    Calculates a pressure-weighted mean wind through a layer. The default
    layer is 850 to 200 hPa.

    Inputs
    ------
        pbot    (float)             Pressure of the bottom level (hPa)
        ptop    (float)             Pressure of the top level (hPa)
        prof    (profile object)    Profile Object
        psteps  (int; optional)     Number of steps to loop through (int)
        stu     (float; optional)   U-component of storm-motion vector
        stv     (float; optional)   V-component of storm-motion vector

    Returns
    -------
        mnu      (float)            U-component
        mnv      (float)            V-component
    '''
    if pbot == -1: lower = 850.
    if ptop == -1: upper = 200.
    pinc = int((pbot - ptop) / psteps)
    if pinc < 1:
        u1, v1 = interp.components(pbot, prof)
        u2, v2 = interp.components(ptop, prof)
        u1 = (u1 - stu) * pbot
        v1 = (v1 - stv) * pbot
        u2 = (u2 - stu) * ptop
        v2 = (v2 - stv) * ptop
        usum = u1 + u2
        vsum = v1 + v2
        wgt = 2
    else:
        wgt = 0
        usum = 0
        vsum = 0
        for p in range(int(pbot), int(ptop), -pinc):
            utmp, vtmp = interp.components(p, prof)
            usum += (utmp - stu)
            vsum += (vtmp - stv)
            wgt += 1

    return float(usum / wgt), float(vsum / wgt)
Ejemplo n.º 13
0
def mean_wind_npw(pbot, ptop, prof, psteps=20, stu=0, stv=0):
    '''
    Calculates a pressure-weighted mean wind through a layer. The default
    layer is 850 to 200 hPa.

    Inputs
    ------
        pbot    (float)             Pressure of the bottom level (hPa)
        ptop    (float)             Pressure of the top level (hPa)
        prof    (profile object)    Profile Object
        psteps  (int; optional)     Number of steps to loop through (int)
        stu     (float; optional)   U-component of storm-motion vector
        stv     (float; optional)   V-component of storm-motion vector

    Returns
    -------
        mnu      (float)            U-component
        mnv      (float)            V-component
    '''
    if pbot == -1: lower = 850.
    if ptop == -1: upper = 200.
    pinc = int((pbot - ptop) / psteps)
    if pinc < 1:
        u1, v1 = interp.components(pbot, prof)
        u2, v2 = interp.components(ptop, prof)
        u1 = (u1 - stu) * pbot
        v1 = (v1 - stv) * pbot
        u2 = (u2 - stu) * ptop
        v2 = (v2 - stv) * ptop
        usum = u1 + u2
        vsum = v1 + v2
        wgt = 2
    else:
        wgt = 0
        usum = 0
        vsum = 0
        for p in range(int(pbot), int(ptop), -pinc):
            utmp, vtmp = interp.components(p, prof)
            usum += (utmp - stu)
            vsum += (vtmp - stv)
            wgt += 1

    return float(usum / wgt), float(vsum / wgt)
Ejemplo n.º 14
0
def wind_shear(pbot, ptop, prof):
    '''
    Calculates the shear between the wind at (pbot) and (ptop).

    Inputs
    ------
        pbot    (float)             Pressure of the bottom level (hPa)
        ptop    (float)             Pressure of the top level (hPa)
        prof    (profile object)    Profile Object

    Returns
    -------
        shu      (float)            U-component
        shv      (float)            V-component
    '''
    ubot, vbot = interp.components(pbot, prof)
    utop, vtop = interp.components(ptop, prof)
    shu = utop - ubot
    shv = vtop - vbot
    return shu, shv
Ejemplo n.º 15
0
def wind_shear(pbot, ptop, prof):
    '''
    Calculates the shear between the wind at (pbot) and (ptop).

    Inputs
    ------
        pbot    (float)             Pressure of the bottom level (hPa)
        ptop    (float)             Pressure of the top level (hPa)
        prof    (profile object)    Profile Object

    Returns
    -------
        shu      (float)            U-component
        shv      (float)            V-component
    '''
    ubot, vbot = interp.components(pbot, prof)
    utop, vtop = interp.components(ptop, prof)
    shu = utop - ubot
    shv = vtop - vbot
    return shu, shv
Ejemplo n.º 16
0
def critical_angle(prof, stu=0, stv=0):
    '''
    Calculates the critical angle (degrees) as specified by Esterheld and Giuliano (2008).
    If the critical angle is 90 degrees, this indicates that the lowest 500 meters of 
    the storm is experiencing pure streamwise vorticity.

    Parameters
    ----------
    prof : profile object
        Profile Object
    stu : number (optional; default = 0)
        U-component of storm-motion (kts)
    stv : number (optional; default = 0)
        V-component of storm-motion (kts)

    Returns
    -------
    angle : number
        Critical Angle (degrees)

    '''
    if prof.wdir.count() == 0:
        return ma.masked

    if not utils.QC(stu) or not utils.QC(stv):
        return ma.masked

    pres_500m = interp.pres(prof, interp.to_msl(prof, 500))
    u500, v500 = interp.components(prof, pres_500m)
    sfc_u, sfc_v = interp.components(prof, prof.pres[prof.sfc])

    vec1_u, vec1_v = u500 - sfc_u, v500 - sfc_v
    vec2_u, vec2_v = stu - sfc_u, stv - sfc_v
    vec_1_mag = np.sqrt(np.power(vec1_u, 2) + np.power(vec1_v, 2))
    vec_2_mag = np.sqrt(np.power(vec2_u, 2) + np.power(vec2_v, 2))

    dot = vec1_u * vec2_u + vec1_v * vec2_v
    angle = np.degrees(np.arccos(dot / (vec_1_mag * vec_2_mag)))

    return angle
Ejemplo n.º 17
0
def critical_angle(prof, stu=0, stv=0):
    '''
    Calculates the critical angle (degrees) as specified by Esterheld and Giuliano (2008).
    If the critical angle is 90 degrees, this indicates that the lowest 500 meters of 
    the storm is experiencing pure streamwise vorticity.

    Parameters
    ----------
    prof : profile object
        Profile Object
    stu : number (optional; default = 0)
        U-component of storm-motion
    stv : number (optional; default = 0)
        V-component of storm-motion

    Returns
    -------
    angle : number
        Critical Angle (degrees)
    '''
    if not utils.QC(stu) or not utils.QC(stv):
        return ma.masked

    pres_500m = interp.pres(prof, interp.to_msl(prof, 500))
    u500, v500 = interp.components(prof, pres_500m)
    sfc_u, sfc_v = interp.components(prof, prof.pres[prof.sfc])

    vec1_u, vec1_v = u500 - sfc_u, v500 - sfc_v    
    vec2_u, vec2_v = stu - sfc_u, stv - sfc_v
    vec_1_mag = np.sqrt(np.power(vec1_u, 2) + np.power(vec1_v, 2))
    vec_2_mag = np.sqrt(np.power(vec2_u, 2) + np.power(vec2_v, 2))

    dot = vec1_u * vec2_u + vec1_v * vec2_v
    angle = np.degrees(np.arccos(dot / (vec_1_mag * vec_2_mag)))

    return angle
    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
Ejemplo n.º 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
Ejemplo n.º 20
0
def mean_wind(prof, pbot=850, ptop=250, dp=-1, stu=0, stv=0):
    '''
    Calculates a pressure-weighted mean wind through a layer. The default
    layer is 850 to 200 hPa.

    Parameters
    ----------
    prof: profile object
        Profile object
    pbot : number (optional; default 850 hPa)
        Pressure of the bottom level (hPa)
    ptop : number (optional; default 250 hPa)
        Pressure of the top level (hPa)
    dp : negative integer (optional; default -1)
        The pressure increment for the interpolated sounding
    stu : number (optional; default 0)
        U-component of storm-motion vector (kts)
    stv : number (optional; default 0)
        V-component of storm-motion vector (kts)

    Returns
    -------
    mnu : number
        U-component (kts)
    mnv : number
        V-component (kts)

    '''
    if dp > 0: dp = -dp
    if not utils.QC(pbot) or not utils.QC(ptop):
        return ma.masked, ma.masked
    if prof.wdir.count() == 0:
        return ma.masked, ma.masked

    ps = np.arange(pbot, ptop + dp, dp)
    u, v = interp.components(prof, ps)
    # u -= stu; v -= stv
    return ma.average(u, weights=ps) - stu, ma.average(v, weights=ps) - stv
Ejemplo n.º 21
0
def helicity(lower, upper, prof, stu=0, stv=0):
    '''
    Calculates the relative helicity (m2/s2) of a layer from lower to upper.
    If storm-motion vector is supplied, storm-relative helicity, both
    positve and negative, is returned.

    Inputs
    ------
        lower       (float)             Bottom level of layer (m, AGL)
        upper       (float)             Top level of layer (m, AGL)
        prof        (profile object)    Profile Object
        stu         (float; optional)   U-component of storm-motion
        stv         (float; optional)   V-component of storm-motion

    Returns
    -------
        phel+nhel   (float)             Combined Helicity (m2/s2)
        phel        (float)             Positive Helicity (m2/s2)
        nhel        (float)             Negative Helicity (m2/s2)
    '''
    lower = interp.msl(lower, prof)
    upper = interp.msl(upper, prof)
    plower = interp.pres(lower, prof)
    pupper = interp.pres(upper, prof)
    phel = 0
    nhel = 0

    # Find lower and upper ind bounds for looping
    i = 0
    while interp.msl(prof.gSndg[i][prof.zind], prof) < lower: i+=1
    lptr = i
    if interp.msl(prof.gSndg[i][prof.zind], prof) == lower: lptr+=1
    while interp.msl(prof.gSndg[i][prof.zind], prof) <= upper: i+=1
    uptr = i
    if interp.msl(prof.gSndg[i][prof.zind], prof) == upper: uptr-=1


    # Integrate from interpolated bottom level to iptr level
    sru1, srv1 = interp.components(plower, prof)
    sru1 = KTS2MS(sru1 - stu)
    srv1 = KTS2MS(srv1 - stv)

    # Loop through levels
    for i in range(lptr, uptr+1):
        if QC(prof.gSndg[i][prof.uind]) and QC(prof.gSndg[i][prof.vind]):
            sru2, srv2 = interp.components(prof.gSndg[i][prof.pind], prof)
            sru2 = KTS2MS(sru2 - stu)
            srv2 = KTS2MS(srv2 - stv)
            lyrh = (sru2 * srv1) - (sru1 * srv2)
            if lyrh > 0: phel += lyrh
            else: nhel += lyrh
            sru1 = sru2
            srv1 = srv2

    # Integrate from tptr level to interpolated top level
    sru2, srv2 = interp.components(pupper, prof)
    sru2 = KTS2MS(sru2 - stu)
    srv2 = KTS2MS(srv2 - stv)

    lyrh = (sru2 * srv1) - (sru1 * srv2)
    if lyrh > 0: phel += lyrh
    else: nhel += lyrh
    return phel+nhel, phel, nhel
Ejemplo n.º 22
0
def total_shear(prof, pbot=850, ptop=250, dp=-1, exact=True):
    '''
    Calculates the total shear (also known as the hodograph length) between
    the wind at (pbot) and (ptop).

    Parameters
    ----------
    prof: profile object
        Profile object
    pbot : number (optional; default 850 hPa)
        Pressure of the bottom level (hPa)
    ptop : number (optional; default 250 hPa)
        Pressure of the top level (hPa)
    dp : negative integer (optional; default -1)
        The pressure increment for the interpolated sounding
    exact : bool (optional; default = True)
        Switch to choose between using the exact data (slower) or using
        interpolated sounding at 'dp' pressure levels (faster)

    Returns
    -------
    tot_pos_shr : number
        Total positive shear
    tot_neg_shr : number
        Total negative shear
    tot_net_shr : number
        Total net shear (subtracting negative shear from positive shear)
    tot_abs_shr : number
        Total absolute shear (adding positive and negative shear together)
    '''
    if np.isnan(pbot) or np.isnan(ptop) or \
        type(pbot) == type(ma.masked) or type(ptop) == type(ma.masked):
        print np.ma.masked, np.ma.masked, np.ma.masked, np.ma.masked
    if exact:
        ind1 = np.where(pbot > prof.pres)[0].min()
        ind2 = np.where(ptop < prof.pres)[0].max()
        u1, v1 = interp.components(prof, pbot)
        u2, v2 = interp.components(prof, ptop)
        u = np.concatenate([[u1], prof.u[ind1:ind2+1].compressed(), [u2]])
        v = np.concatenate([[v1], prof.v[ind1:ind2+1].compressed(), [v2]])
    else:
        ps = np.arange(pbot, ptop+dp, dp)
        u, v = interp.components(prof, ps)
    shu = u[1:] - u[:-1]
    shv = v[1:] - v[:-1]
    shr = ( ( np.power(shu, 2) + np.power(shv, 2) ) ** 0.5 )
    wdr, wsp = utils.comp2vec(u,v)
    t_wdr = wdr[1:]
    mod = 180 - wdr[:-1]
    t_wdr = t_wdr + mod

    idx1 = ma.where(t_wdr < 0)[0]
    idx2 = ma.where(t_wdr >= 360)[0]
    t_wdr[idx1] = t_wdr[idx1] + 360
    t_wdr[idx2] = t_wdr[idx2] - 360
    d_wdr = t_wdr - 180
    d_wsp = wsp[1:] - wsp[:-1]
    idxdp = ma.where(d_wdr > 0)[0]
    idxdn = ma.where(d_wdr < 0)[0]
    idxsp = ma.where(np.logical_and(d_wdr == 0, d_wsp > 0) == True)[0]
    idxsn = ma.where(np.logical_and(d_wdr == 0, d_wsp < 0) == True)[0]
    if not utils.QC(idxdp):
        pos_dir_shr = ma.masked
    else:
        pos_dir_shr = shr[idxdp].sum()
    if not utils.QC(idxdn):
        neg_dir_shr = ma.masked
    else:
        neg_dir_shr = shr[idxdn].sum()
    if not utils.QC(idxsp):
        pos_spd_shr = ma.masked
    else:
        pos_spd_shr = shr[idxsp].sum()
    if not utils.QC(idxsn):
        neg_spd_shr = ma.masked
    else:
        neg_spd_shr = shr[idxsn].sum()
    tot_pos_shr = pos_dir_shr + pos_spd_shr
    tot_neg_shr = neg_dir_shr + neg_spd_shr
    tot_net_shr = tot_pos_shr - tot_neg_shr
    tot_abs_shr = tot_pos_shr + tot_neg_shr

    return tot_pos_shr, tot_neg_shr, tot_net_shr, tot_abs_shr
Ejemplo n.º 23
0
''' Create the Sounding (Profile) Object '''
Ejemplo n.º 24
0
def helicity(lower, upper, prof, stu=0, stv=0):
    '''
    Calculates the relative helicity (m2/s2) of a layer from lower to upper.
    If storm-motion vector is supplied, storm-relative helicity, both
    positve and negative, is returned.

    Inputs
    ------
        lower       (float)             Bottom level of layer (m, AGL)
        upper       (float)             Top level of layer (m, AGL)
        prof        (profile object)    Profile Object
        stu         (float; optional)   U-component of storm-motion
        stv         (float; optional)   V-component of storm-motion

    Returns
    -------
        phel+nhel   (float)             Combined Helicity (m2/s2)
        phel        (float)             Positive Helicity (m2/s2)
        nhel        (float)             Negative Helicity (m2/s2)
    '''
    lower = interp.msl(lower, prof)
    upper = interp.msl(upper, prof)
    plower = interp.pres(lower, prof)
    pupper = interp.pres(upper, prof)
    phel = 0
    nhel = 0

    # Find lower and upper ind bounds for looping
    i = 0
    while interp.msl(prof.gSndg[i][prof.zind], prof) < lower:
        i += 1
    lptr = i
    if interp.msl(prof.gSndg[i][prof.zind], prof) == lower: lptr += 1
    while interp.msl(prof.gSndg[i][prof.zind], prof) <= upper:
        i += 1
    uptr = i
    if interp.msl(prof.gSndg[i][prof.zind], prof) == upper: uptr -= 1

    # Integrate from interpolated bottom level to iptr level
    sru1, srv1 = interp.components(plower, prof)
    sru1 = KTS2MS(sru1 - stu)
    srv1 = KTS2MS(srv1 - stv)

    # Loop through levels
    for i in range(lptr, uptr + 1):
        if QC(prof.gSndg[i][prof.uind]) and QC(prof.gSndg[i][prof.vind]):
            sru2, srv2 = interp.components(prof.gSndg[i][prof.pind], prof)
            sru2 = KTS2MS(sru2 - stu)
            srv2 = KTS2MS(srv2 - stv)
            lyrh = (sru2 * srv1) - (sru1 * srv2)
            if lyrh > 0: phel += lyrh
            else: nhel += lyrh
            sru1 = sru2
            srv1 = srv2

    # Integrate from tptr level to interpolated top level
    sru2, srv2 = interp.components(pupper, prof)
    sru2 = KTS2MS(sru2 - stu)
    srv2 = KTS2MS(srv2 - stv)

    lyrh = (sru2 * srv1) - (sru1 * srv2)
    if lyrh > 0: phel += lyrh
    else: nhel += lyrh
    return phel + nhel, phel, nhel