Esempio 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
Esempio n. 2
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
Esempio n. 3
0
def max_wind(prof, lower, upper, all=False):
    '''
    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 by default.

    Parameters
    ----------
    prof : profile object
        Profile Object
    lower : number
        Bottom level of layer (m, AGL)
    upper : number
        Top level of layer (m, AGL)
    all : Boolean
        Switch to change the output to sorted wind levels or maximum level.

    Returns
    -------
    p : number, numpy array
        Pressure level (hPa) of max wind speed
    maxu : number, numpy array
        Maximum Wind Speed U-component (kts)
    maxv : number, numpy array
        Maximum Wind Speed V-component (kts)

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

    lower = interp.to_msl(prof, lower)
    upper = interp.to_msl(prof, upper)
    plower = interp.pres(prof, lower)
    pupper = interp.pres(prof, upper)
    if np.ma.is_masked(plower) or np.ma.is_masked(pupper):
        warnings.warn(
            "winds.max_wind() was unable to interpolate between height and pressure correctly.  This may be due to a data integrity issue."
        )
        return ma.masked, ma.masked, ma.masked
    #print(lower, upper, plower, pupper, prof.pres)
    ind1 = np.where((plower > prof.pres)
                    | (np.isclose(plower, prof.pres)))[0][0]
    ind2 = np.where((pupper < prof.pres)
                    | (np.isclose(pupper, prof.pres)))[0][-1]

    if len(prof.wspd[ind1:ind2 + 1]) == 0 or ind1 == ind2:
        maxu, maxv = utils.vec2comp([prof.wdir[ind1]], [prof.wspd[ind1]])
        return maxu, maxv, prof.pres[ind1]

    arr = prof.wspd[ind1:ind2 + 1]
    inds = np.ma.argsort(arr)
    inds = inds[~arr[inds].mask][::-1]
    maxu, maxv = utils.vec2comp(prof.wdir[ind1:ind2 + 1][inds],
                                prof.wspd[ind1:ind2 + 1][inds])
    if all:
        return maxu, maxv, prof.pres[inds]
    else:
        return maxu[0], maxv[0], prof.pres[inds[0]]
Esempio n. 4
0
def non_parcel_bunkers_motion_experimental(prof):
    '''
        Compute the Bunkers Storm Motion for a Right Moving Supercell
        
        Parameters
        ----------
        prof : profile object
            Profile Object
        
        Returns
        -------
        rstu : number
            Right Storm Motion U-component (kts)
        rstv : number
            Right Storm Motion V-component (kts)
        lstu : number
            Left Storm Motion U-component (kts)
        lstv : number
            Left Storm Motion V-component (kts)
        
        '''
    if prof.wdir.count() == 0:
        return ma.masked, ma.masked, ma.masked, ma.masked

    d = utils.MS2KTS(7.5)  # Deviation value emperically derived as 7.5 m/s
    ## get the msl height of 500m, 5.5km, and 6.0km above the surface
    msl500m = interp.to_msl(prof, 500.)
    msl5500m = interp.to_msl(prof, 5500.)
    msl6000m = interp.to_msl(prof, 6000.)

    ## get the pressure of the surface, 500m, 5.5km, and 6.0km levels
    psfc = prof.pres[prof.sfc]
    p500m = interp.pres(prof, msl500m)
    p5500m = interp.pres(prof, msl5500m)
    p6000m = interp.pres(prof, msl6000m)

    ## sfc-500m Mean Wind
    mnu500m, mnv500m = mean_wind(prof, psfc, p500m)

    ## 5.5km-6.0km Mean Wind
    mnu5500m_6000m, mnv5500m_6000m = mean_wind(prof, p5500m, p6000m)

    # shear vector of the two mean winds
    shru = mnu5500m_6000m - mnu500m
    shrv = mnv5500m_6000m - mnv500m

    # SFC-6km Mean Wind
    mnu6, mnv6 = mean_wind(prof, psfc, p6000m)

    # Bunkers Right Motion
    tmp = d / utils.mag(shru, shrv)
    rstu = mnu6 + (tmp * shrv)
    rstv = mnv6 - (tmp * shru)
    lstu = mnu6 - (tmp * shrv)
    lstv = mnv6 + (tmp * shru)

    return rstu, rstv, lstu, lstv
Esempio n. 5
0
def test_to_msl():
    input_z = 1000.
    correct_agl = 1357.
    returned_agl = interp.to_msl(prof, input_z)
    npt.assert_almost_equal(returned_agl, correct_agl)

    input_z = [1000., 3000., 6000.]
    correct_agl = [1357., 3357., 6357]
    returned_agl = interp.to_msl(prof, input_z)
    npt.assert_almost_equal(returned_agl, correct_agl)
def test_wind_shear():
    agl1 = 0
    agl2 = 1000
    msl1 = interp.to_msl(prof, agl1)
    msl2 = interp.to_msl(prof, agl2)
    pbot = interp.pres(prof, msl1)
    ptop = interp.pres(prof, msl2)
    correct_u, correct_v = -2.625075135691132, 10.226725739920353
    returned = winds.wind_shear(prof, pbot, ptop)
    npt.assert_almost_equal(returned, [correct_u, correct_v])
Esempio n. 7
0
def test_to_msl():
    input_z = 1000.
    correct_agl = 1357.
    returned_agl = interp.to_msl(prof, input_z)
    npt.assert_almost_equal(returned_agl, correct_agl)

    input_z = [1000., 3000., 6000.]
    correct_agl = [1357., 3357., 6357]
    returned_agl = interp.to_msl(prof, input_z)
    npt.assert_almost_equal(returned_agl, correct_agl)
Esempio n. 8
0
def test_wind_shear():
    agl1 = 0
    agl2 = 1000
    msl1 = interp.to_msl(prof, agl1)
    msl2 = interp.to_msl(prof, agl2)
    pbot = interp.pres(prof, msl1)
    ptop = interp.pres(prof, msl2)
    correct_u, correct_v = -2.625075135691132, 10.226725739920353
    returned = winds.wind_shear(prof, pbot, ptop)
    npt.assert_almost_equal(returned, [correct_u, correct_v])
Esempio n. 9
0
def non_parcel_bunkers_motion_experimental(prof):
    '''
        Compute the Bunkers Storm Motion for a Right Moving Supercell
        
        Inputs
        ------
        prof : profile object
        Profile Object
        
        Returns
        -------
        rstu : number
        Right Storm Motion U-component
        rstv : number
        Right Storm Motion V-component
        lstu : number
        Left Storm Motion U-component
        lstv : number
        Left Storm Motion V-component
        
        '''
    d = utils.MS2KTS(7.5)     # Deviation value emperically derived as 7.5 m/s
    ## get the msl height of 500m, 5.5km, and 6.0km above the surface
    msl500m = interp.to_msl(prof, 500.)
    msl5500m = interp.to_msl(prof, 5500.)
    msl6000m = interp.to_msl(prof, 6000.)
    
    ## get the pressure of the surface, 500m, 5.5km, and 6.0km levels
    psfc = prof.pres[prof.sfc]
    p500m = interp.pres(prof, msl500m)
    p5500m = interp.pres(prof, msl5500m)
    p6000m = interp.pres(prof, msl6000m)
    
    ## sfc-500m Mean Wind
    mnu500m, mnv500m = mean_wind(prof, psfc, p500m)
    
    ## 5.5km-6.0km Mean Wind
    mnu5500m_6000m, mnv5500m_6000m = mean_wind(prof, p5500m, p6000m)
    
    # shear vector of the two mean winds
    shru = mnu5500m_6000m - mnu500m
    shrv = mnv5500m_6000m - mnv500m
    
    # SFC-6km Mean Wind
    mnu6, mnv6 = mean_wind(prof, psfc, p6000m)
    
    # Bunkers Right Motion
    tmp = d / utils.mag(shru, shrv)
    rstu = mnu6 + (tmp * shrv)
    rstv = mnv6 - (tmp * shru)
    lstu = mnu6 - (tmp * shrv)
    lstv = mnv6 + (tmp * shru)
    
    return rstu, rstv, lstu, lstv
Esempio n. 10
0
def max_wind(prof, lower, upper, all=False):
    '''
    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 by default.

    Parameters
    ----------
    prof : profile object
        Profile Object
    lower : number
        Bottom level of layer (m, AGL)
    upper : number
        Top level of layer (m, AGL)
    all : Boolean
        Switch to change the output to sorted wind levels or maximum level.

    Returns
    -------
    p : number, numpy array
        Pressure level (hPa) of max wind speed
    maxu : number, numpy array
        Maximum Wind Speed U-component
    maxv : number, numpy array
        Maximum Wind Speed V-component

    '''
    lower = interp.to_msl(prof, lower)
    upper = interp.to_msl(prof, upper)
    plower = interp.pres(prof, lower)
    pupper = interp.pres(prof, upper)

    ind1 = np.where((plower > prof.pres)
                    | (np.isclose(plower, prof.pres)))[0][0]
    ind2 = np.where((pupper < prof.pres)
                    | (np.isclose(pupper, prof.pres)))[0][-1]

    if len(prof.wspd[ind1:ind2 + 1]) == 0 or ind1 == ind2:
        maxu, maxv = utils.vec2comp([prof.wdir[ind1]], [prof.wspd[ind1]])
        return maxu, maxv, prof.pres[ind1]

    arr = prof.wspd[ind1:ind2 + 1]
    inds = np.ma.argsort(arr)
    inds = inds[~arr[inds].mask][::-1]
    maxu, maxv = utils.vec2comp(prof.wdir[ind1:ind2 + 1][inds],
                                prof.wspd[ind1:ind2 + 1][inds])
    if all:
        return maxu, maxv, prof.pres[inds]
    else:
        return maxu[0], maxv[0], prof.pres[inds[0]]
Esempio n. 11
0
    def get_fire(self):
        '''
        Function to generate different indices and information
        regarding any fire weather in the sounding.  This helps fill
        the data shown in the FIRE inset.
    
        Parameters
        ----------
        None

        Returns
        -------
        None
        '''
        self.fosberg = fire.fosberg(self)
        self.ppbl_top = params.pbl_top(self)
        self.sfc_rh = thermo.relh(self.pres[self.sfc], self.tmpc[self.sfc],
                                  self.dwpc[self.sfc])
        pres_sfc = self.pres[self.sfc]
        pres_1km = interp.pres(self, interp.to_msl(self, 1000.))
        pbl_h = interp.to_agl(self, interp.hght(self, self.ppbl_top))
        self.rh01km = params.mean_relh(self, pbot=pres_sfc, ptop=pres_1km)
        self.pblrh = params.mean_relh(self, pbot=pres_sfc, ptop=self.ppbl_top)
        self.meanwind01km = winds.mean_wind(self, pbot=pres_sfc, ptop=pres_1km)
        self.meanwindpbl = winds.mean_wind(self,
                                           pbot=pres_sfc,
                                           ptop=self.ppbl_top)
        self.pblmaxwind = winds.max_wind(self, lower=0, upper=pbl_h)
        #self.pblmaxwind = [np.ma.masked, np.ma.masked]
        mulplvals = params.DefineParcel(self, flag=3, pres=500)
        mupcl = params.cape(self, lplvals=mulplvals)
        self.bplus_fire = mupcl.bplus
Esempio n. 12
0
 def get_fire(self):
     '''
     Function to generate different indices and information
     regarding any fire weather in the sounding.  This helps fill
     the data shown in the FIRE inset.
 
     Parameters
     ----------
     None
     Returns
     -------
     None
     '''
     self.fosberg = fire.fosberg(self)
     self.ppbl_top = params.pbl_top(self)
     self.sfc_rh = thermo.relh(self.pres[self.sfc], self.tmpc[self.sfc], self.dwpc[self.sfc])
     pres_sfc = self.pres[self.sfc]
     pres_1km = interp.pres(self, interp.to_msl(self, 1000.))
     pbl_h = interp.to_agl(self, interp.hght(self, self.ppbl_top))
     self.rh01km = params.mean_relh(self, pbot=pres_sfc, ptop=pres_1km)
     self.pblrh = params.mean_relh(self, pbot=pres_sfc, ptop=self.ppbl_top)
     self.meanwind01km = winds.mean_wind(self, pbot=pres_sfc, ptop=pres_1km)
     self.meanwindpbl = winds.mean_wind(self, pbot=pres_sfc, ptop=self.ppbl_top)
     self.pblmaxwind = winds.max_wind(self, lower=0, upper=pbl_h)
     #self.pblmaxwind = [np.ma.masked, np.ma.masked]
     mulplvals = params.DefineParcel(self, flag=3, pres=500)
     mupcl = params.cape(self, lplvals=mulplvals)
     self.bplus_fire = mupcl.bplus
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)
Esempio n. 14
0
def max_wind(prof, lower, upper, all=False):
    '''
    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 by default.

    Parameters
    ----------
    prof : profile object
        Profile Object
    lower : number
        Bottom level of layer (m, AGL)
    upper : number
        Top level of layer (m, AGL)
    all : Boolean
        Switch to change the output to sorted wind levels or maximum level.

    Returns
    -------
    p : number, numpy array
        Pressure level (hPa) of max wind speed
    maxu : number, numpy array
        Maximum Wind Speed U-component
    maxv : number, numpy array
        Maximum Wind Speed V-component

    '''
    lower = interp.to_msl(prof, lower)
    upper = interp.to_msl(prof, upper)
    plower = interp.pres(prof, lower)
    pupper = interp.pres(prof, upper)

    ind1 = np.where((plower > prof.pres) | (np.isclose(plower, prof.pres)))[0][0]
    ind2 = np.where((pupper < prof.pres) | (np.isclose(pupper, prof.pres)))[0][-1]

    if len(prof.wspd[ind1:ind2+1]) == 0 or ind1 == ind2:
        maxu, maxv =  utils.vec2comp([prof.wdir[ind1]], [prof.wspd[ind1]])
        return maxu, maxv, prof.pres[ind1]

    arr = prof.wspd[ind1:ind2+1]
    inds = np.ma.argsort(arr)
    inds = inds[~arr[inds].mask][::-1]
    maxu, maxv =  utils.vec2comp(prof.wdir[ind1:ind2+1][inds], prof.wspd[ind1:ind2+1][inds])
    if all:
        return maxu, maxv, prof.pres[inds]
    else:
        return maxu[0], maxv[0], prof.pres[inds[0]]
Esempio n. 15
0
def max_wind(prof, lower, upper, all=False):
    '''
    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 by default.

    Parameters
    ----------
    prof : profile object
        Profile Object
    lower : number
        Bottom level of layer (m, AGL)
    upper : number
        Top level of layer (m, AGL)

    Returns
    -------
    p : number, numpy array
        Pressure level (hPa) of max wind speed
    maxu : number, numpy array
        Maximum Wind Speed U-component
    maxv : number, numpy array
        Maximum Wind Speed V-component

    '''
    lower = interp.to_msl(prof, lower)
    upper = interp.to_msl(prof, upper)
    plower = interp.pres(prof, lower)
    pupper = interp.pres(prof, upper)
    ind1 = np.where(plower > prof.pres)[0].min()
    ind2 = np.where(pupper < prof.pres)[0].max()
    inds = np.where(
        np.fabs(prof.wspd[ind1:ind2 + 1] -
                prof.wspd[ind1:ind2 + 1].max()) < TOL)[0]
    inds += ind1
    inds.sort()
    maxu, maxv = utils.vec2comp(prof.wdir[inds], prof.wspd[inds])
    if all:
        return maxu, maxv, prof.pres[inds]
    else:
        return maxu[0], maxv[0], prof.pres[inds[0]]
Esempio n. 16
0
def max_wind(prof, lower, upper, all=False):
    '''
    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 by default.

    Parameters
    ----------
    prof : profile object
        Profile Object
    lower : number
        Bottom level of layer (m, AGL)
    upper : number
        Top level of layer (m, AGL)

    Returns
    -------
    p : number, numpy array
        Pressure level (hPa) of max wind speed
    maxu : number, numpy array
        Maximum Wind Speed U-component
    maxv : number, numpy array
        Maximum Wind Speed V-component

    '''
    lower = interp.to_msl(prof, lower)
    upper = interp.to_msl(prof, upper)
    plower = interp.pres(prof, lower)
    pupper = interp.pres(prof, upper)
    ind1 = np.where(plower > prof.pres)[0].min()
    ind2 = np.where(pupper < prof.pres)[0].max()
    inds = np.where(np.fabs(prof.wspd[ind1:ind2+1] -
                    prof.wspd[ind1:ind2+1].max()) < TOL)[0]
    inds += ind1
    inds.sort()
    maxu, maxv =  utils.vec2comp(prof.wdir[inds], prof.wspd[inds])
    if all:
        return maxu, maxv, prof.pres[inds]
    else:
        return maxu[0], maxv[0], prof.pres[inds[0]]
Esempio n. 17
0
def non_parcel_bunkers_motion(prof):
    '''
    Compute the Bunkers Storm Motion for a Right Moving Supercell

    Inputs
    ------
    prof : profile object
        Profile Object

    Returns
    -------
    rstu : number
        Right Storm Motion U-component
    rstv : number
        Right Storm Motion V-component
    lstu : number
        Left Storm Motion U-component
    lstv : number
        Left Storm Motion V-component

    '''
    d = utils.MS2KTS(7.5)  # Deviation value emperically derived as 7.5 m/s
    msl6km = interp.to_msl(prof, 6000.)
    p6km = interp.pres(prof, msl6km)

    # SFC-6km Mean Wind
    mnu6, mnv6 = mean_wind_npw(prof, prof.pres[prof.sfc], p6km)
    # SFC-6km Shear Vector
    shru, shrv = wind_shear(prof, prof.pres[prof.sfc], p6km)

    # Bunkers Right Motion
    tmp = d / utils.mag(shru, shrv)

    # Cambios para el hemisferio sur JP JP
    if prof.latitude < 0:
        lstu = mnu6 + (tmp * shrv)
        lstv = mnv6 - (tmp * shru)
        rstu = mnu6 - (tmp * shrv)
        rstv = mnv6 + (tmp * shru)
    else:
        rstu = mnu6 + (tmp * shrv)
        rstv = mnv6 - (tmp * shru)
        lstu = mnu6 - (tmp * shrv)
        lstv = mnv6 + (tmp * shru)

    return rstu, rstv, lstu, lstv
Esempio n. 18
0
def corfidi_mcs_motion(prof):
    '''
    Calculated the Meso-beta Elements (Corfidi) Vectors

    Parameters
    ----------
    prof : profile object
        Profile Object

    Returns
    -------
    upu : number
        U-component of the upshear vector (kts)
    upv : number
        V-component of the upshear vector (kts)
    dnu : number
        U-component of the downshear vector (kts)
    dnv : number
        V-component of the downshear vector (kts)

    '''
    if prof.wdir.count() == 0:
        return ma.masked, ma.masked, ma.masked, ma.masked
    # Compute the tropospheric (850hPa-300hPa) mean wind
    if prof.pres[prof.sfc] < 850:
        mnu1, mnv1 = mean_wind_npw(prof, pbot=prof.pres[prof.sfc], ptop=300.)
    else:
        mnu1, mnv1 = mean_wind_npw(prof, pbot=850., ptop=300.)

    # Compute the low-level (SFC-1500m) mean wind
    p_1p5km = interp.pres(prof, interp.to_msl(prof, 1500.))
    mnu2, mnv2 = mean_wind_npw(prof, prof.pres[prof.sfc], p_1p5km)

    # Compute the upshear vector
    upu = mnu1 - mnu2
    upv = mnv1 - mnv2

    # Compute the downshear vector
    dnu = mnu1 + upu
    dnv = mnv1 + upv

    return upu, upv, dnu, dnv
Esempio n. 19
0
def corfidi_mcs_motion(prof):
    '''
    Calculated the Meso-beta Elements (Corfidi) Vectors

    Parameters
    ----------
    prof : profile object
        Profile Object

    Returns
    -------
    upu : number
        U-component of the upshear vector
    upv : number
        V-component of the upshear vector
    dnu : number
        U-component of the downshear vector
    dnv : number
        V-component of the downshear vector

    '''
    # Compute the tropospheric (850hPa-300hPa) mean wind
    if prof.pres[ prof.sfc ] < 850:
         mnu1, mnv1 = mean_wind_npw(prof, pbot=prof.pres[prof.sfc], ptop=300.)
    else:
        mnu1, mnv1 = mean_wind_npw(prof, pbot=850., ptop=300.)

    # Compute the low-level (SFC-1500m) mean wind
    p_1p5km = interp.pres(prof, interp.to_msl(prof, 1500.))
    mnu2, mnv2 = mean_wind_npw(prof, prof.pres[prof.sfc], p_1p5km)

    # Compute the upshear vector
    upu = mnu1 - mnu2
    upv = mnv1 - mnv2

    # Compute the downshear vector
    dnu = mnu1 + upu
    dnv = mnv1 + upv

    return upu, upv, dnu, dnv
Esempio n. 20
0
def non_parcel_bunkers_motion(prof):
    '''
    Compute the Bunkers Storm Motion for a Right Moving Supercell

    Parameters
    ----------
    prof : profile object
        Profile Object

    Returns
    -------
    rstu : number
        Right Storm Motion U-component (kts)
    rstv : number
        Right Storm Motion V-component (kts)
    lstu : number
        Left Storm Motion U-component (kts)
    lstv : number
        Left Storm Motion V-component (kts)

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

    d = utils.MS2KTS(7.5)  # Deviation value emperically derived as 7.5 m/s
    msl6km = interp.to_msl(prof, 6000.)
    p6km = interp.pres(prof, msl6km)
    # SFC-6km Mean Wind
    mnu6, mnv6 = mean_wind_npw(prof, prof.pres[prof.sfc], p6km)
    # SFC-6km Shear Vector
    shru, shrv = wind_shear(prof, prof.pres[prof.sfc], p6km)

    # Bunkers Right Motion
    tmp = d / utils.mag(shru, shrv)
    rstu = mnu6 + (tmp * shrv)
    rstv = mnv6 - (tmp * shru)
    lstu = mnu6 - (tmp * shrv)
    lstv = mnv6 + (tmp * shru)

    return rstu, rstv, lstu, lstv
Esempio n. 21
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
Esempio n. 22
0
def non_parcel_bunkers_motion(prof):
    '''
    Compute the Bunkers Storm Motion for a Right Moving Supercell

    Inputs
    ------
    prof : profile object
        Profile Object

    Returns
    -------
    rstu : number
        Right Storm Motion U-component
    rstv : number
        Right Storm Motion V-component
    lstu : number
        Left Storm Motion U-component
    lstv : number
        Left Storm Motion V-component

    '''
    d = utils.MS2KTS(7.5)     # Deviation value emperically derived as 7.5 m/s
    msl6km = interp.to_msl(prof, 6000.)
    p6km = interp.pres(prof, msl6km)

    # SFC-6km Mean Wind
    mnu6, mnv6 = mean_wind_npw(prof, prof.pres[prof.sfc], p6km)

    # SFC-6km Shear Vector
    shru6, shrv6 = wind_shear(prof, prof.pres[prof.sfc], p6km)

    # Bunkers Right Motion
    tmp = d / utils.comp2vec(shru6, shrv6)[1]
    rstu = mnu6 + (tmp * shrv6)
    rstv = mnv6 - (tmp * shru6)
    lstu = mnu6 - (tmp * shrv6)
    lstv = mnv6 + (tmp * shru6)

    return rstu, rstv, lstu, lstv
Esempio n. 23
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
Esempio n. 24
0
def plot_sounding(file, imgName):
    try:
        prof, time, location = decode(file)
    except Exception as e:
        print(
            "\n Oops! Couldn't decode the sounding data. No plot produced!\n")
        print(e)
        # return None

    # Open up the text file with the data in columns (e.g. the sample OAX file distributed with SHARPpy)
    locInfo = location.split('_')
    title = locInfo[0] + ' ' + locInfo[1] + ' ' + locInfo[
        2] + '   ' + time.strftime('%Y%m%d/%H%M') + '   (Observed)'

    # Set up the figure in matplotlib.
    fig = plt.figure(figsize=(14, 7.25))
    gs = gridspec.GridSpec(4, 6, width_ratios=[1, 5, 1, 0.5, 3, 3])
    ax = plt.subplot(gs[0:3, 0:2], projection='skewx')
    plt.title(title, fontsize=14, loc='left', color='w')
    ax.set_facecolor('k')
    ax.spines['left'].set_color('w')
    ax.spines['right'].set_color('w')
    ax.spines['bottom'].set_color('w')
    ax.spines['top'].set_color('w')

    #     xticks = ax.xaxis.get_major_ticks() #mute a tick label outside plot
    #     xticks[-4].label1.set_visible(False)

    ax.tick_params(axis='both', colors='w', grid_color='silver')
    ax.ticklabel_format(style='plain')

    # ax.xaxis.label.set_color('w')
    # ax.yaxis.label.set_color('w')
    ax.grid(True)
    plt.grid(True)

    # Ask user for default limits or custom limits
    pt_plot, t_lower, t_upper = ask_limits(prof.pres[~prof.dwpc.mask],
                                           prof.dwpc[~prof.dwpc.mask])

    # Bounds of the pressure axis
    pb_plot = 1050
    dp_plot = 10
    plevs_plot = np.arange(pb_plot, pt_plot - 1, -dp_plot)

    # Plot the background variables
    # presvals = np.arange(1000, 0, -10)

    #draw mixing ratio lines
    draw_mixing_ratio_lines(ax)

    ax.semilogy(prof.tmpc[~prof.tmpc.mask],
                prof.pres[~prof.tmpc.mask],
                'r',
                lw=2)
    ax.semilogy(prof.dwpc[~prof.dwpc.mask],
                prof.pres[~prof.dwpc.mask],
                'lime',
                lw=2)
    ax.semilogy(prof.vtmp[~prof.dwpc.mask],
                prof.pres[~prof.dwpc.mask],
                'r--',
                lw=1)
    ax.semilogy(prof.wetbulb[~prof.dwpc.mask],
                prof.pres[~prof.dwpc.mask],
                'cyan',
                '-',
                lw=1)

    #write sfc temp and dewpoint in F
    sfcT = prof.tmpc[~prof.tmpc.mask][0]
    sfcTd = prof.dwpc[~prof.dwpc.mask][0]
    sfcW = prof.wetbulb[~prof.dwpc.mask][0]
    sfcP = prof.pres[~prof.tmpc.mask][0]
    ax.annotate(str(int(sfcW * (9 / 5) + 32)), (sfcW, sfcP),
                xytext=(-6, -9),
                textcoords='offset points',
                color='cyan',
                weight='black',
                size=8,
                path_effects=[pe.withStroke(linewidth=2, foreground="black")])
    ax.annotate(str(int(sfcT * (9 / 5) + 32)), (sfcT, sfcP),
                xytext=(-2, -9),
                textcoords='offset points',
                color='r',
                weight='black',
                size=8,
                path_effects=[pe.withStroke(linewidth=2, foreground="black")])
    ax.annotate(str(int(sfcTd * (9 / 5) + 32)), (sfcTd, sfcP),
                xytext=(-12, -9),
                textcoords='offset points',
                color='lime',
                weight='black',
                size=8,
                path_effects=[pe.withStroke(linewidth=2, foreground="black")])

    #plot significant levels
    plot_sig_levels(ax, prof)

    # Plot the parcel trace, but this may fail.  If it does so, inform the user.
    try:
        ax.semilogy(prof.mupcl.ttrace, prof.mupcl.ptrace, 'w--')
    except:
        print("Couldn't plot parcel traces...")

    # Highlight the 0 C and -20 C isotherms.
    l = ax.axvline(0, color='b', ls='--')
    l = ax.axvline(-20, color='b', ls='--')

    #plot dry adiabats
    skew.draw_dry_adiabats(ax, color='silver')

    #draw heights
    skew.draw_heights(ax, prof)

    # Disables the log-formatting that comes with semilogy
    ax.yaxis.set_major_formatter(ScalarFormatter())
    pmin = prof.pres[~prof.dwpc.mask][-1]
    if pmin > 700.:
        ax.set_yticks(np.arange(100, 1000, 50))
    else:
        ax.set_yticks(np.linspace(100, 1000, 10))
    ax.set_ylim(pb_plot, pt_plot)

    # Plot the hodograph data.
    # inset_axes = draw_hodo_inset(ax, prof)
    hodoAx = plt.subplot(gs[0:3, 3:])
    hodoAx.set_facecolor('k')
    hodoAx.axis('off')
    hodoAx = draw_hodo_inset(hodoAx, prof)

    # plotHodo(inset_axes, prof.hght, prof.u, prof.v, color='r')
    plotHodo(hodoAx, prof.hght, prof.u, prof.v, color='r')

    #plot bunkers motion unless the most unstable EL does not exist
    srwind = params.bunkers_storm_motion(prof)
    if isinstance(prof.mupcl.elpres, np.float64):
        hodoAx.text(srwind[0], srwind[1], 'RM', color='w', fontsize=8)
        hodoAx.text(srwind[2], srwind[3], 'LM', color='w', fontsize=8)
    else:
        print("couldn't plot Bunkers vectors")

    # inset_axes.text(srwind[0], srwind[1], 'RM', color='r', fontsize=8)
    # inset_axes.text(srwind[2], srwind[3], 'LM', color='b', fontsize=8)

    #mask out barbs above the top of the plot
    below_pmin = np.where(prof.pres >= pt_plot)[0]

    # Draw the wind barbs axis and everything that comes with it.
    if pmin > 700.:
        ax.xaxis.set_major_locator(MultipleLocator(5))
    else:
        ax.xaxis.set_major_locator(MultipleLocator(10))
    ax.set_xlim(t_lower, t_upper)

    ax2 = plt.subplot(gs[0:3, 2])
    ax3 = plt.subplot(gs[3, 0:3])
    plot_wind_axes(ax2, pb_plot, pt_plot, plevs_plot)

    #setting the stride for how many wind barbs plot
    # st = 15

    # plot_wind_barbs(ax2, prof.pres[below_pmin][~prof.pres.mask[below_pmin]][::st],
    #                 prof.u[below_pmin][~prof.u.mask[below_pmin]][::st],
    #                 prof.v[below_pmin][~prof.v.mask[below_pmin]][::st],
    #                 pt_plot)
    plot_wind_barbs(ax2, prof.pres[below_pmin][~prof.pres.mask[below_pmin]],
                    prof.u[below_pmin][~prof.u.mask[below_pmin]],
                    prof.v[below_pmin][~prof.v.mask[below_pmin]], pt_plot)

    gs.update(left=0.05, bottom=0.05, top=0.95, right=1, wspace=0.025)

    # Calculate indices to be shown.  More indices can be calculated here using the tutorial and reading the params module.
    p1km = interp.pres(prof, interp.to_msl(prof, 1000.))
    p6km = interp.pres(prof, interp.to_msl(prof, 6000.))
    sfc = prof.pres[prof.sfc]
    sfc_1km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p1km)
    sfc_6km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p6km)
    srh3km = winds.helicity(prof, 0, 3000., stu=srwind[0], stv=srwind[1])
    srh1km = winds.helicity(prof, 0, 1000., stu=srwind[0], stv=srwind[1])
    scp = params.scp(prof.mupcl.bplus, prof.right_esrh[0], prof.ebwspd)
    stp_cin = params.stp_cin(prof.mlpcl.bplus, prof.right_esrh[0], prof.ebwspd,
                             prof.mlpcl.lclhght, prof.mlpcl.bminus)
    stp_fixed = params.stp_fixed(
        prof.sfcpcl.bplus, prof.sfcpcl.lclhght, srh1km[0],
        utils.comp2vec(prof.sfc_6km_shear[0], prof.sfc_6km_shear[1])[1])
    ship = params.ship(prof)

    # A routine to perform the correct formatting when writing the indices out to the figure.
    def fmt(value, fmt='int'):
        if fmt == 'int':
            try:
                val = int(value)
            except:
                val = str("M")
        else:
            try:
                val = round(value, 1)
            except:
                val = "M"
        return val

    # Setting a dictionary that is a collection of all of the indices we'll be showing on the figure.
    # the dictionary includes the index name, the actual value, and the units.
    indices = {'SBCAPE': [fmt(prof.sfcpcl.bplus), 'J/kg'],\
               'SBCIN': [fmt(prof.sfcpcl.bminus), 'J/kg'],\
               'SBLCL': [fmt(prof.sfcpcl.lclhght), 'm AGL'],\
               'SBLFC': [fmt(prof.sfcpcl.lfchght), 'm AGL'],\
               'SBEL': [fmt(prof.sfcpcl.elhght), 'm AGL'],\
               'SBLI': [fmt(prof.sfcpcl.li5), 'C'],\
               'MLCAPE': [fmt(prof.mlpcl.bplus), 'J/kg'],\
               'MLCIN': [fmt(prof.mlpcl.bminus), 'J/kg'],\
               'MLLCL': [fmt(prof.mlpcl.lclhght), 'm AGL'],\
               'MLLFC': [fmt(prof.mlpcl.lfchght), 'm AGL'],\
               'MLEL': [fmt(prof.mlpcl.elhght), 'm AGL'],\
               'MLLI': [fmt(prof.mlpcl.li5), 'C'],\
               'MUCAPE': [fmt(prof.mupcl.bplus), 'J/kg'],\
               'MUCIN': [fmt(prof.mupcl.bminus), 'J/kg'],\
               'MULCL': [fmt(prof.mupcl.lclhght), 'm AGL'],\
               'MULFC': [fmt(prof.mupcl.lfchght), 'm AGL'],\
               'MUEL': [fmt(prof.mupcl.elhght), 'm AGL'],\
               'MULI': [fmt(prof.mupcl.li5), 'C'],\
               '0-1 km SRH': [fmt(srh1km[0]), 'm2/s2'],\
               '0-1 km Shear': [fmt(utils.comp2vec(sfc_1km_shear[0], sfc_1km_shear[1])[1]), 'kts'],\
               '0-3 km SRH': [fmt(srh3km[0]), 'm2/s2'],\
               '0-6 km Shear': [fmt(utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1]), 'kts'],\
               'Eff. SRH': [fmt(prof.right_esrh[0]), 'm2/s2'],\
               'EBWD': [fmt(prof.ebwspd), 'kts'],\
               'PWV': [round(prof.pwat, 2), 'inch'],\
               'K-index': [fmt(params.k_index(prof)), ''],\
               'STP(fix)': [fmt(stp_fixed, 'flt'), ''],\
               'SHIP': [fmt(ship, 'flt'), ''],\
               'SCP': [fmt(scp, 'flt'), ''],\
               'STP(cin)': [fmt(stp_cin, 'flt'), '']}

    # List the indices within the indices dictionary on the side of the plot.
    trans = transforms.blended_transform_factory(ax.transAxes, ax.transData)

    # Write out all of the indices to the figure.
    #print("##############")
    #print("   INDICES    ")
    #print("##############")
    string = ''
    keys = np.sort(list(indices.keys()))
    x = 0
    counter = 0
    for key in keys:
        string = string + key + ': ' + str(
            indices[key][0]) + ' ' + indices[key][1] + '\n'
        #    print((key + ": " + str(indices[key][0]) + ' ' + indices[key][1]))
        if counter < 7:
            counter += 1
            continue
        else:
            counter = 0
            ax3.text(x,
                     1,
                     string,
                     verticalalignment='top',
                     transform=ax3.transAxes,
                     fontsize=11,
                     color='w')
            string = ''
            x += 0.3
    ax3.text(x,
             1,
             string,
             verticalalignment='top',
             transform=ax3.transAxes,
             fontsize=11,
             color='w')
    ax3.set_axis_off()

    # Show SARS matches (edited for Keith Sherburn)
    #try:
    #    supercell_matches = prof.supercell_matches
    #    hail_matches = prof.matches
    #except:
    #    supercell_matches = prof.right_supercell_matches
    #    hail_matches = prof.right_matches

    #print()
    #print("#############")
    #print(" SARS OUTPUT ")
    #print("#############")
    #for mtype, matches in zip(['Supercell', 'Hail'], [supercell_matches, hail_matches]):
    #    print(mtype)
    #    print('-----------')
    #    if len(matches[0]) == 0:
    #        print("NO QUALITY MATCHES")
    #    for i in range(len(matches[0])):
    #        print(matches[0][i] + ' ' + matches[1][i])
    #    print("Total Loose Matches:", matches[2])
    #    print("# of Loose Matches that met Criteria:", matches[3])
    #    print("SVR Probability:", matches[4])
    #    print()

    #plot logos
    im = plt.imread('logo.png')
    #left, bottom, width, height = [0.25, 0.6, 0.2, 0.2]
    #left, bottom, width, height = [0.1, 0.175, 0.4, 0.4] #bottom left
    left, bottom, width, height = [0.035, 0.65, 0.4, 0.4]
    # ax4 = fig.add_axes([left, bottom, width, height])
    ax4 = plt.subplot(gs[3, 4])
    implot = ax4.imshow(im, alpha=0.99)
    ax4.axis('off')
    ax4.set_facecolor('k')

    im2 = plt.imread('essc_logo.png')
    ax5 = plt.subplot(gs[3, 5])
    implot = ax5.imshow(im2, alpha=0.99)
    ax5.axis('off')
    ax5.set_facecolor('k')

    #plot SHARPpy acknowledgement
    # plt.text(1, 1, 'Plotted with SHARPpy', horizontalalignment='right',
    #             verticalalignment='top', transform=ax.transAxes, color='w')
    hodoAx.annotate(
        'Plotted with SHARPpy - https://sharppy.github.io/SHARPpy/',
        (0.7, 0.96),
        xycoords='figure fraction',
        va='center',
        color='w')

    #filename for the plot
    # plotName = os.path.splitext(file)[0] + '.png'

    # Finalize the image formatting and alignments, and save the image to the file.
    #gs.tight_layout(fig)
    plt.style.use('dark_background')
    fn = time.strftime(
        '%Y%m%d.%H%M') + '_' + locInfo[0] + '_' + locInfo[1] + '.png'
    fn = fn.replace('/', '')
    print('SHARPpy quick-look image output at: ' + imgName)
    #plt.savefig(fn, bbox_inches='tight', dpi=180)
    plt.savefig(imgName, dpi=180)
Esempio n. 25
0
spd_std = spd_std * units.knot
direc = direc * units.deg
direc_std = direc_std * units.deg

# Convert wind speed and direction to components
u, v = get_wind_components(spd, direc)
u_std, v_std = get_wind_components(spd_std, direc_std)

#PARCEL CALCULATIONS with sharppy
sfcpcl = params.parcelx(prof, flag=1)  # Surface Parcel
fcstpcl = params.parcelx(prof, flag=2)  # Forecast Parcel
mupcl = params.parcelx(prof, flag=3)  # Most-Unstable Parcel
mlpcl = params.parcelx(prof, flag=4)  # 100 mb Mean Layer Parcel

sfc = prof.pres[prof.sfc]
p3km = interp.pres(prof, interp.to_msl(prof, 3000.))
p6km = interp.pres(prof, interp.to_msl(prof, 6000.))
p1km = interp.pres(prof, interp.to_msl(prof, 1000.))
mean_3km = winds.mean_wind(prof, pbot=sfc, ptop=p3km)
sfc_6km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p6km)
sfc_3km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p3km)
sfc_1km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p1km)
srwind = params.bunkers_storm_motion(prof)
srh3km = winds.helicity(prof, 0, 3000., stu=srwind[0], stv=srwind[1])
srh1km = winds.helicity(prof, 0, 1000., stu=srwind[0], stv=srwind[1])

stp_fixed = params.stp_fixed(
    sfcpcl.bplus, sfcpcl.lclhght, srh1km[0],
    utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1])
ship = params.ship(prof)
eff_inflow = params.effective_inflow_layer(prof)
Esempio n. 26
0
    bunkerR, = hodo_ax.plot([], [],
                            color='r',
                            alpha=0.7,
                            linestyle="None",
                            marker="o",
                            markersize=5,
                            mew=0,
                            label="right mover")
    # Explanation for red and blue dots. Put only 1 point in the legend entry.
    bunkerleg = hodo_ax.legend(handles=[bunkerL, bunkerR],
                               fontsize=5,
                               frameon=False,
                               numpoints=1)

    # show Bunker left/right movers if 0-6km shear magnitude >= 20kts
    p6km = interp.pres(prof, interp.to_msl(prof, 6000.))
    sfc_6km_shear = winds.wind_shear(prof, pbot=prof.pres[prof.sfc], ptop=p6km)
    if utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1] >= 20.:
        bunkerR.set_visible(True)
        bunkerL.set_visible(True)
        bunkerleg.set_visible(True)
        bunkerR.set_data(srwind[0],
                         srwind[1])  # Update Bunker's Storm motion right mover
        bunkerL.set_data(srwind[2],
                         srwind[3])  # Update Bunker's Storm motion left mover
    else:
        bunkerR.set_visible(False)
        bunkerL.set_visible(False)
        bunkerleg.set_visible(False)

    if debug:
Esempio n. 27
0
def do_sharppy(spc_file):
    """
    Based on the tutorial which can be found here: http://nbviewer.ipython.org/github/sharppy/SHARPpy/blob/master/tutorials/SHARPpy_basics.ipynb
    SHARPpy can be found here: https://github.com/sharppy/SHARPpy
    Credit goes to:
    Patrick Marsh (SPC)
    Kelton Halbert (OU School of Meteorology)
    Greg Blumberg (OU/CIMMS)
    Tim Supinie (OU School of Meteorology)
    
    """
    import sharppy
    import sharppy.sharptab.profile as profile
    import sharppy.sharptab.interp as interp
    import sharppy.sharptab.winds as winds
    import sharppy.sharptab.utils as utils
    import sharppy.sharptab.params as params
    import sharppy.sharptab.thermo as thermo
    import matplotlib.pyplot as plt
    from StringIO import StringIO
    from matplotlib.axes import Axes
    import matplotlib.transforms as transforms
    import matplotlib.axis as maxis
    import matplotlib.spines as mspines
    import matplotlib.path as mpath
    from matplotlib.projections import register_projection
    
    spc_file = open('skewt_data', 'r').read()


    def parseSPC(spc_file):
        ## read in the file
        data = np.array([l.strip() for l in spc_file.split('\n')])

        ## necessary index points
        title_idx = np.where( data == '%TITLE%')[0][0]
        start_idx = np.where( data == '%RAW%' )[0] + 1
        finish_idx = np.where( data == '%END%')[0]
    
        ## create the plot title
        data_header = data[title_idx + 1].split()
        location = data_header[0]+' '+data_header[1]
        time = data_header[2]
        title = location+' '+time
        ## put it all together for StringIO
        full_data = '\n'.join(data[start_idx : finish_idx][:])
        sound_data = StringIO( full_data )
    
        ## read the data into arrays
        p, h, T, Td, wdir, wspd = np.genfromtxt( sound_data, delimiter=',', comments="%", unpack=True )
    
        return p, h, T, Td, wdir, wspd, title
        
    pres, hght, tmpc, dwpc, wdir, wspd, title = parseSPC(spc_file)
    prof = profile.create_profile(profile='default', pres=pres, hght=hght, tmpc=tmpc, \
    dwpc=dwpc, wspd=wspd, wdir=wdir, missing=-9999, strictQC=True)
    
    sfcpcl = params.parcelx( prof, flag=1 ) # Surface Parcel
    fcstpcl = params.parcelx( prof, flag=2 ) # Forecast Parcel
    mupcl = params.parcelx( prof, flag=3 ) # Most-Unstable Parcel
    mlpcl = params.parcelx( prof, flag=4 ) # 100 mb Mean Layer Parcel
         
    msl_hght = prof.hght[prof.sfc] # Grab the surface height value
    print "SURFACE HEIGHT (m MSL):",msl_hght
    agl_hght = interp.to_agl(prof, msl_hght) # Converts to AGL
    print "SURFACE HEIGHT (m AGL):", agl_hght
    msl_hght = interp.to_msl(prof, agl_hght) # Converts to MSL
    print "SURFACE HEIGHT (m MSL):",msl_hght
    print "Most-Unstable CAPE:", mupcl.bplus # J/kg
    print "Most-Unstable CIN:", mupcl.bminus # J/kg
    print "Most-Unstable LCL:", mupcl.lclhght # meters AGL
    print "Most-Unstable LFC:", mupcl.lfchght # meters AGL
    print "Most-Unstable EL:", mupcl.elhght # meters AGL
    print "Most-Unstable LI:", mupcl.li5 # C
    
    class SkewXTick(maxis.XTick):
        def draw(self, renderer):
            if not self.get_visible(): return
            renderer.open_group(self.__name__)
    
            lower_interval = self.axes.xaxis.lower_interval
            upper_interval = self.axes.xaxis.upper_interval
    
            if self.gridOn and transforms.interval_contains(
                    self.axes.xaxis.get_view_interval(), self.get_loc()):
                self.gridline.draw(renderer)
    
            if transforms.interval_contains(lower_interval, self.get_loc()):
                if self.tick1On:
                    self.tick1line.draw(renderer)
                if self.label1On:
                    self.label1.draw(renderer)
    
            if transforms.interval_contains(upper_interval, self.get_loc()):
                if self.tick2On:
                    self.tick2line.draw(renderer)
                if self.label2On:
                    self.label2.draw(renderer)
    
            renderer.close_group(self.__name__)
    
    
    # This class exists to provide two separate sets of intervals to the tick,
    # as well as create instances of the custom tick
    class SkewXAxis(maxis.XAxis):
        def __init__(self, *args, **kwargs):
            maxis.XAxis.__init__(self, *args, **kwargs)
            self.upper_interval = 0.0, 1.0
    
        def _get_tick(self, major):
            return SkewXTick(self.axes, 0, '', major=major)
    
        @property
        def lower_interval(self):
            return self.axes.viewLim.intervalx
    
        def get_view_interval(self):
            return self.upper_interval[0], self.axes.viewLim.intervalx[1]
    
    
    # This class exists to calculate the separate data range of the
    # upper X-axis and draw the spine there. It also provides this range
    # to the X-axis artist for ticking and gridlines
    class SkewSpine(mspines.Spine):
        def _adjust_location(self):
            trans = self.axes.transDataToAxes.inverted()
            if self.spine_type == 'top':
                yloc = 1.0
            else:
                yloc = 0.0
            left = trans.transform_point((0.0, yloc))[0]
            right = trans.transform_point((1.0, yloc))[0]
    
            pts  = self._path.vertices
            pts[0, 0] = left
            pts[1, 0] = right
            self.axis.upper_interval = (left, right)
    
    
    # This class handles registration of the skew-xaxes as a projection as well
    # as setting up the appropriate transformations. It also overrides standard
    # spines and axes instances as appropriate.
    class SkewXAxes(Axes):
        # The projection must specify a name.  This will be used be the
        # user to select the projection, i.e. ``subplot(111,
        # projection='skewx')``.
        name = 'skewx'
    
        def _init_axis(self):
            #Taken from Axes and modified to use our modified X-axis
            self.xaxis = SkewXAxis(self)
            self.spines['top'].register_axis(self.xaxis)
            self.spines['bottom'].register_axis(self.xaxis)
            self.yaxis = maxis.YAxis(self)
            self.spines['left'].register_axis(self.yaxis)
            self.spines['right'].register_axis(self.yaxis)
    
        def _gen_axes_spines(self):
            spines = {'top':SkewSpine.linear_spine(self, 'top'),
                      'bottom':mspines.Spine.linear_spine(self, 'bottom'),
                      'left':mspines.Spine.linear_spine(self, 'left'),
                      'right':mspines.Spine.linear_spine(self, 'right')}
            return spines
    
        def _set_lim_and_transforms(self):
            """
            This is called once when the plot is created to set up all the
            transforms for the data, text and grids.
            """
            rot = 30
    
            #Get the standard transform setup from the Axes base class
            Axes._set_lim_and_transforms(self)
    
            # Need to put the skew in the middle, after the scale and limits,
            # but before the transAxes. This way, the skew is done in Axes
            # coordinates thus performing the transform around the proper origin
            # We keep the pre-transAxes transform around for other users, like the
            # spines for finding bounds
            self.transDataToAxes = self.transScale + (self.transLimits +
                    transforms.Affine2D().skew_deg(rot, 0))
    
            # Create the full transform from Data to Pixels
            self.transData = self.transDataToAxes + self.transAxes
    
            # Blended transforms like this need to have the skewing applied using
            # both axes, in axes coords like before.
            self._xaxis_transform = (transforms.blended_transform_factory(
                        self.transScale + self.transLimits,
                        transforms.IdentityTransform()) +
                    transforms.Affine2D().skew_deg(rot, 0)) + self.transAxes
    
    # Now register the projection with matplotlib so the user can select
    # it.
    register_projection(SkewXAxes)
    
    pcl = mupcl
    # Create a new figure. The dimensions here give a good aspect ratio
    fig = plt.figure(figsize=(6.5875, 6.2125))
    ax = fig.add_subplot(111, projection='skewx')
    ax.grid(True)
    
    pmax = 1000
    pmin = 10
    dp = -10
    presvals = np.arange(int(pmax), int(pmin)+dp, dp)
    
    # plot the moist-adiabats
    for t in np.arange(-10,45,5):
        tw = []
        for p in presvals:
            tw.append(thermo.wetlift(1000., t, p))
        ax.semilogy(tw, presvals, 'k-', alpha=.2)
    
    def thetas(theta, presvals):
        return ((theta + thermo.ZEROCNK) / (np.power((1000. / presvals),thermo.ROCP))) - thermo.ZEROCNK
    
    # plot the dry adiabats
    for t in np.arange(-50,110,10):
        ax.semilogy(thetas(t, presvals), presvals, 'r-', alpha=.2)
    
    plt.title(title, fontsize=14, loc='left')
    # Plot the data using normal plotting functions, in this case using
    # log scaling in Y, as dicatated by the typical meteorological plot
    ax.semilogy(prof.tmpc, prof.pres, 'r', lw=2)
    ax.semilogy(prof.dwpc, prof.pres, 'g', lw=2)
    ax.semilogy(pcl.ttrace, pcl.ptrace, 'k-.', lw=2)
    
    # An example of a slanted line at constant X
    l = ax.axvline(0, color='b', linestyle='--')
    l = ax.axvline(-20, color='b', linestyle='--')
    
    # Disables the log-formatting that comes with semilogy
    ax.yaxis.set_major_formatter(plt.ScalarFormatter())
    ax.set_yticks(np.linspace(100,1000,10))
    ax.set_ylim(1050,100)
    
    ax.xaxis.set_major_locator(plt.MultipleLocator(10))
    ax.set_xlim(-50,50)
    plt.show()
    
    ##PLOTS SKEWT OK ABOVE HERE ##
    """
Esempio n. 28
0
def do_sharppy(spc_file):
    """
    Based on the tutorial which can be found here: http://nbviewer.ipython.org/github/sharppy/SHARPpy/blob/master/tutorials/SHARPpy_basics.ipynb
    SHARPpy can be found here: https://github.com/sharppy/SHARPpy
    Credit goes to:
    Patrick Marsh (SPC)
    Kelton Halbert (OU School of Meteorology)
    Greg Blumberg (OU/CIMMS)
    Tim Supinie (OU School of Meteorology)
    
    """
    import sharppy
    import sharppy.sharptab.profile as profile
    import sharppy.sharptab.interp as interp
    import sharppy.sharptab.winds as winds
    import sharppy.sharptab.utils as utils
    import sharppy.sharptab.params as params
    import sharppy.sharptab.thermo as thermo
    import matplotlib.pyplot as plt
    from StringIO import StringIO
    from matplotlib.axes import Axes
    import matplotlib.transforms as transforms
    import matplotlib.axis as maxis
    import matplotlib.spines as mspines
    import matplotlib.path as mpath
    from matplotlib.projections import register_projection

    spc_file = open('skewt_data', 'r').read()

    def parseSPC(spc_file):
        ## read in the file
        data = np.array([l.strip() for l in spc_file.split('\n')])

        ## necessary index points
        title_idx = np.where(data == '%TITLE%')[0][0]
        start_idx = np.where(data == '%RAW%')[0] + 1
        finish_idx = np.where(data == '%END%')[0]

        ## create the plot title
        data_header = data[title_idx + 1].split()
        location = data_header[0] + ' ' + data_header[1]
        time = data_header[2]
        title = location + ' ' + time
        ## put it all together for StringIO
        full_data = '\n'.join(data[start_idx:finish_idx][:])
        sound_data = StringIO(full_data)

        ## read the data into arrays
        p, h, T, Td, wdir, wspd = np.genfromtxt(sound_data,
                                                delimiter=',',
                                                comments="%",
                                                unpack=True)

        return p, h, T, Td, wdir, wspd, title

    pres, hght, tmpc, dwpc, wdir, wspd, title = parseSPC(spc_file)
    prof = profile.create_profile(profile='default', pres=pres, hght=hght, tmpc=tmpc, \
    dwpc=dwpc, wspd=wspd, wdir=wdir, missing=-9999, strictQC=True)

    sfcpcl = params.parcelx(prof, flag=1)  # Surface Parcel
    fcstpcl = params.parcelx(prof, flag=2)  # Forecast Parcel
    mupcl = params.parcelx(prof, flag=3)  # Most-Unstable Parcel
    mlpcl = params.parcelx(prof, flag=4)  # 100 mb Mean Layer Parcel

    msl_hght = prof.hght[prof.sfc]  # Grab the surface height value
    print "SURFACE HEIGHT (m MSL):", msl_hght
    agl_hght = interp.to_agl(prof, msl_hght)  # Converts to AGL
    print "SURFACE HEIGHT (m AGL):", agl_hght
    msl_hght = interp.to_msl(prof, agl_hght)  # Converts to MSL
    print "SURFACE HEIGHT (m MSL):", msl_hght
    print "Most-Unstable CAPE:", mupcl.bplus  # J/kg
    print "Most-Unstable CIN:", mupcl.bminus  # J/kg
    print "Most-Unstable LCL:", mupcl.lclhght  # meters AGL
    print "Most-Unstable LFC:", mupcl.lfchght  # meters AGL
    print "Most-Unstable EL:", mupcl.elhght  # meters AGL
    print "Most-Unstable LI:", mupcl.li5  # C

    class SkewXTick(maxis.XTick):
        def draw(self, renderer):
            if not self.get_visible(): return
            renderer.open_group(self.__name__)

            lower_interval = self.axes.xaxis.lower_interval
            upper_interval = self.axes.xaxis.upper_interval

            if self.gridOn and transforms.interval_contains(
                    self.axes.xaxis.get_view_interval(), self.get_loc()):
                self.gridline.draw(renderer)

            if transforms.interval_contains(lower_interval, self.get_loc()):
                if self.tick1On:
                    self.tick1line.draw(renderer)
                if self.label1On:
                    self.label1.draw(renderer)

            if transforms.interval_contains(upper_interval, self.get_loc()):
                if self.tick2On:
                    self.tick2line.draw(renderer)
                if self.label2On:
                    self.label2.draw(renderer)

            renderer.close_group(self.__name__)

    # This class exists to provide two separate sets of intervals to the tick,
    # as well as create instances of the custom tick
    class SkewXAxis(maxis.XAxis):
        def __init__(self, *args, **kwargs):
            maxis.XAxis.__init__(self, *args, **kwargs)
            self.upper_interval = 0.0, 1.0

        def _get_tick(self, major):
            return SkewXTick(self.axes, 0, '', major=major)

        @property
        def lower_interval(self):
            return self.axes.viewLim.intervalx

        def get_view_interval(self):
            return self.upper_interval[0], self.axes.viewLim.intervalx[1]

    # This class exists to calculate the separate data range of the
    # upper X-axis and draw the spine there. It also provides this range
    # to the X-axis artist for ticking and gridlines
    class SkewSpine(mspines.Spine):
        def _adjust_location(self):
            trans = self.axes.transDataToAxes.inverted()
            if self.spine_type == 'top':
                yloc = 1.0
            else:
                yloc = 0.0
            left = trans.transform_point((0.0, yloc))[0]
            right = trans.transform_point((1.0, yloc))[0]

            pts = self._path.vertices
            pts[0, 0] = left
            pts[1, 0] = right
            self.axis.upper_interval = (left, right)

    # This class handles registration of the skew-xaxes as a projection as well
    # as setting up the appropriate transformations. It also overrides standard
    # spines and axes instances as appropriate.
    class SkewXAxes(Axes):
        # The projection must specify a name.  This will be used be the
        # user to select the projection, i.e. ``subplot(111,
        # projection='skewx')``.
        name = 'skewx'

        def _init_axis(self):
            #Taken from Axes and modified to use our modified X-axis
            self.xaxis = SkewXAxis(self)
            self.spines['top'].register_axis(self.xaxis)
            self.spines['bottom'].register_axis(self.xaxis)
            self.yaxis = maxis.YAxis(self)
            self.spines['left'].register_axis(self.yaxis)
            self.spines['right'].register_axis(self.yaxis)

        def _gen_axes_spines(self):
            spines = {
                'top': SkewSpine.linear_spine(self, 'top'),
                'bottom': mspines.Spine.linear_spine(self, 'bottom'),
                'left': mspines.Spine.linear_spine(self, 'left'),
                'right': mspines.Spine.linear_spine(self, 'right')
            }
            return spines

        def _set_lim_and_transforms(self):
            """
            This is called once when the plot is created to set up all the
            transforms for the data, text and grids.
            """
            rot = 30

            #Get the standard transform setup from the Axes base class
            Axes._set_lim_and_transforms(self)

            # Need to put the skew in the middle, after the scale and limits,
            # but before the transAxes. This way, the skew is done in Axes
            # coordinates thus performing the transform around the proper origin
            # We keep the pre-transAxes transform around for other users, like the
            # spines for finding bounds
            self.transDataToAxes = self.transScale + (
                self.transLimits + transforms.Affine2D().skew_deg(rot, 0))

            # Create the full transform from Data to Pixels
            self.transData = self.transDataToAxes + self.transAxes

            # Blended transforms like this need to have the skewing applied using
            # both axes, in axes coords like before.
            self._xaxis_transform = (
                transforms.blended_transform_factory(
                    self.transScale + self.transLimits,
                    transforms.IdentityTransform()) +
                transforms.Affine2D().skew_deg(rot, 0)) + self.transAxes

    # Now register the projection with matplotlib so the user can select
    # it.
    register_projection(SkewXAxes)

    pcl = mupcl
    # Create a new figure. The dimensions here give a good aspect ratio
    fig = plt.figure(figsize=(6.5875, 6.2125))
    ax = fig.add_subplot(111, projection='skewx')
    ax.grid(True)

    pmax = 1000
    pmin = 10
    dp = -10
    presvals = np.arange(int(pmax), int(pmin) + dp, dp)

    # plot the moist-adiabats
    for t in np.arange(-10, 45, 5):
        tw = []
        for p in presvals:
            tw.append(thermo.wetlift(1000., t, p))
        ax.semilogy(tw, presvals, 'k-', alpha=.2)

    def thetas(theta, presvals):
        return ((theta + thermo.ZEROCNK) / (np.power(
            (1000. / presvals), thermo.ROCP))) - thermo.ZEROCNK

    # plot the dry adiabats
    for t in np.arange(-50, 110, 10):
        ax.semilogy(thetas(t, presvals), presvals, 'r-', alpha=.2)

    plt.title(title, fontsize=14, loc='left')
    # Plot the data using normal plotting functions, in this case using
    # log scaling in Y, as dicatated by the typical meteorological plot
    ax.semilogy(prof.tmpc, prof.pres, 'r', lw=2)
    ax.semilogy(prof.dwpc, prof.pres, 'g', lw=2)
    ax.semilogy(pcl.ttrace, pcl.ptrace, 'k-.', lw=2)

    # An example of a slanted line at constant X
    l = ax.axvline(0, color='b', linestyle='--')
    l = ax.axvline(-20, color='b', linestyle='--')

    # Disables the log-formatting that comes with semilogy
    ax.yaxis.set_major_formatter(plt.ScalarFormatter())
    ax.set_yticks(np.linspace(100, 1000, 10))
    ax.set_ylim(1050, 100)

    ax.xaxis.set_major_locator(plt.MultipleLocator(10))
    ax.set_xlim(-50, 50)
    plt.show()

    ##PLOTS SKEWT OK ABOVE HERE ##
    """
Esempio n. 29
0
    # Update the hodograph on the Skew-T.
    # Draw the hodograph on the Skew-T.
    hodo_ax = myskewt.draw_hodo()
    hodo, AGL = myskewt.add_hodo(hodo_ax, prof)

    # Plot Bunker's Storm motion left mover as a blue dot
    bunkerL, = hodo_ax.plot([], [], color='b', alpha=0.7, linestyle="None", marker="o", markersize=5, mew=0, label="left mover")
    # Plot Bunker's Storm motion right mover as a red dot
    # The comma after bunkerR de-lists it.
    bunkerR, = hodo_ax.plot([], [], color='r', alpha=0.7, linestyle="None", marker="o", markersize=5, mew=0, label="right mover")
    # Explanation for red and blue dots. Put only 1 point in the legend entry.
    bunkerleg = hodo_ax.legend(handles=[bunkerL,bunkerR], fontsize=5, frameon=False, numpoints=1)

    # show Bunker left/right movers if 0-6km shear magnitude >= 20kts
    p6km = interp.pres(prof, interp.to_msl(prof, 6000.))
    sfc_6km_shear = winds.wind_shear(prof, pbot=prof.pres[prof.sfc], ptop=p6km)
    if utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1] >= 20.:
        bunkerR.set_visible(True)
        bunkerL.set_visible(True)
        bunkerleg.set_visible(True)
        bunkerR.set_data(srwind[0], srwind[1]) # Update Bunker's Storm motion right mover
        bunkerL.set_data(srwind[2], srwind[3]) # Update Bunker's Storm motion left mover
    else:
        bunkerR.set_visible(False)
        bunkerL.set_visible(False)
        bunkerleg.set_visible(False)

    # Recreate stack of wind barbs
    s = []
    bot=2000.
Esempio n. 30
0
''' Create the Sounding (Profile) Object '''
Esempio n. 31
0
 def get_kinematics(self):
     '''
     Function to generate the numerous kinematic quantities
     used for display and calculations. It requires that the
     parcel calculations have already been called for the lcl
     to el shear and mean wind vectors, as well as indices
     that require an effective inflow layer.
     Parameters
     ----------
     None
     Returns
     -------
     None
     '''
     sfc = self.pres[self.sfc]
     heights = np.array([1000., 3000., 4000., 5000., 6000., 8000., 9000.])
     p1km, p3km, p4km, p5km, p6km, p8km, p9km = interp.pres(self, interp.to_msl(self, heights))
     ## 1km and 6km winds
     self.wind1km = interp.vec(self, p1km)
     self.wind6km = interp.vec(self, p6km)
     ## calcluate wind shear
     self.sfc_1km_shear = winds.wind_shear(self, pbot=sfc, ptop=p1km)
     self.sfc_3km_shear = winds.wind_shear(self, pbot=sfc, ptop=p3km)
     self.sfc_6km_shear = winds.wind_shear(self, pbot=sfc, ptop=p6km)
     self.sfc_8km_shear = winds.wind_shear(self, pbot=sfc, ptop=p8km)
     self.sfc_9km_shear = winds.wind_shear(self, pbot=sfc, ptop=p9km)
     self.lcl_el_shear = winds.wind_shear(self, pbot=self.mupcl.lclpres, ptop=self.mupcl.elpres)
     ## calculate mean wind
     self.mean_1km = utils.comp2vec(*winds.mean_wind(self, pbot=sfc, ptop=p1km))
     self.mean_3km = utils.comp2vec(*winds.mean_wind(self, pbot=sfc, ptop=p3km))
     self.mean_6km = utils.comp2vec(*winds.mean_wind(self, pbot=sfc, ptop=p6km))
     self.mean_8km = utils.comp2vec(*winds.mean_wind(self, pbot=sfc, ptop=p8km))
     self.mean_lcl_el = utils.comp2vec(*winds.mean_wind(self, pbot=self.mupcl.lclpres, ptop=self.mupcl.elpres))
     ## parameters that depend on the presence of an effective inflow layer
     if self.etop is ma.masked or self.ebottom is ma.masked:
         self.etopm = ma.masked; self.ebotm = ma.masked
         self.srwind = winds.non_parcel_bunkers_motion( self )
         self.eff_shear = [MISSING, MISSING]
         self.ebwd = [MISSING, MISSING, MISSING]
         self.ebwspd = MISSING
         self.mean_eff = [MISSING, MISSING, MISSING]
         self.mean_ebw = [MISSING, MISSING, MISSING]
         self.srw_eff = [MISSING, MISSING, MISSING]
         self.srw_ebw = [MISSING, MISSING, MISSING]
         self.right_esrh = [ma.masked, ma.masked, ma.masked]
         self.left_esrh = [ma.masked, ma.masked, ma.masked]
         self.critical_angle = ma.masked
     else:
         self.srwind = params.bunkers_storm_motion(self, mupcl=self.mupcl, pbot=self.ebottom)
         depth = ( self.mupcl.elhght - self.ebotm ) / 2
         elh = interp.pres(self, interp.to_msl(self, self.ebotm + depth))
         ## calculate mean wind
         self.mean_eff = winds.mean_wind(self, self.ebottom, self.etop )
         self.mean_ebw = winds.mean_wind(self, pbot=self.ebottom, ptop=elh )
         ## calculate wind shear of the effective layer
         self.eff_shear = winds.wind_shear(self, pbot=self.ebottom, ptop=self.etop)
         self.ebwd = winds.wind_shear(self, pbot=self.ebottom, ptop=elh)
         self.ebwspd = utils.mag( self.ebwd[0], self.ebwd[1] )
         ## calculate the mean sr wind
         self.srw_eff = winds.sr_wind(self, pbot=self.ebottom, ptop=self.etop, stu=self.srwind[0], stv=self.srwind[1] )
         self.srw_ebw = winds.sr_wind(self, pbot=self.ebottom, ptop=elh, stu=self.srwind[0], stv=self.srwind[1] )
         self.right_esrh = winds.helicity(self, self.ebotm, self.etopm, stu=self.srwind[0], stv=self.srwind[1])
         self.left_esrh = winds.helicity(self, self.ebotm, self.etopm, stu=self.srwind[2], stv=self.srwind[3])
         self.critical_angle = winds.critical_angle(self, stu=self.srwind[0], stv=self.srwind[1])
     ## calculate mean srw
     self.srw_1km = utils.comp2vec(*winds.sr_wind(self, pbot=sfc, ptop=p1km, stu=self.srwind[0], stv=self.srwind[1] ))
     self.srw_3km = utils.comp2vec(*winds.sr_wind(self, pbot=sfc, ptop=p3km, stu=self.srwind[0], stv=self.srwind[1] ))
     self.srw_6km = utils.comp2vec(*winds.sr_wind(self, pbot=sfc, ptop=p6km, stu=self.srwind[0], stv=self.srwind[1] ))
     self.srw_8km = utils.comp2vec(*winds.sr_wind(self, pbot=sfc, ptop=p8km, stu=self.srwind[0], stv=self.srwind[1] ))
     self.srw_4_5km = utils.comp2vec(*winds.sr_wind(self, pbot=p4km, ptop=p5km, stu=self.srwind[0], stv=self.srwind[1] ))
     self.srw_lcl_el = utils.comp2vec(*winds.sr_wind(self, pbot=self.mupcl.lclpres, ptop=self.mupcl.elpres, stu=self.srwind[0], stv=self.srwind[1] ))
     # This is for the red, blue, and purple bars that appear on the SR Winds vs. Height plot
     self.srw_0_2km = winds.sr_wind(self, pbot=sfc, ptop=interp.pres(self, interp.to_msl(self, 2000.)), stu=self.srwind[0], stv=self.srwind[1])
     self.srw_4_6km = winds.sr_wind(self, pbot=interp.pres(self, interp.to_msl(self, 4000.)), ptop=p6km, stu=self.srwind[0], stv=self.srwind[1])
     self.srw_9_11km = winds.sr_wind(self, pbot=interp.pres(self, interp.to_msl(self, 9000.)), ptop=interp.pres(self, interp.to_msl(self, 11000.)), stu=self.srwind[0], stv=self.srwind[1])
     
     ## calculate upshear and downshear
     self.upshear_downshear = winds.mbe_vectors(self)
     self.srh1km = winds.helicity(self, 0, 1000., stu=self.srwind[0], stv=self.srwind[1])
     self.srh3km = winds.helicity(self, 0, 3000., stu=self.srwind[0], stv=self.srwind[1])
Esempio n. 32
0
def indices(prof, debug=False):

    # return a formatted-string list of stability and kinematic indices

    sfcpcl = params.parcelx(prof, flag=1)
    mupcl = params.parcelx(prof, flag=3)  # most unstable
    mlpcl = params.parcelx(prof, flag=4)  # 100 mb mean layer parcel

    pcl = mupcl
    sfc = prof.pres[prof.sfc]
    p3km = interp.pres(prof, interp.to_msl(prof, 3000.))
    p6km = interp.pres(prof, interp.to_msl(prof, 6000.))
    p1km = interp.pres(prof, interp.to_msl(prof, 1000.))
    mean_3km = winds.mean_wind(prof, pbot=sfc, ptop=p3km)
    sfc_6km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p6km)
    sfc_3km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p3km)
    sfc_1km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p1km)
    #print "0-3 km Pressure-Weighted Mean Wind (kt):", utils.comp2vec(mean_3km[0], mean_3km[1])[1]
    #print "0-6 km Shear (kt):", utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1]
    srwind = params.bunkers_storm_motion(prof)
    srh3km = winds.helicity(prof, 0, 3000., stu=srwind[0], stv=srwind[1])
    srh1km = winds.helicity(prof, 0, 1000., stu=srwind[0], stv=srwind[1])
    #print "0-3 km Storm Relative Helicity [m2/s2]:",srh3km[0]

    #### Calculating variables based off of the effective inflow layer:

    # The effective inflow layer concept is used to obtain the layer of buoyant parcels that feed a storm's inflow.
    # Here are a few examples of how to compute variables that require the effective inflow layer in order to calculate them:

    stp_fixed = params.stp_fixed(
        sfcpcl.bplus, sfcpcl.lclhght, srh1km[0],
        utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1])
    ship = params.ship(prof)

    # If you get an error about not converting masked constant to python int
    # use the round() function instead of int() - Ahijevych May 11 2016
    # 2nd element of list is the # of decimal places
    indices = {
        'SBCAPE': [sfcpcl.bplus, 0, 'J $\mathregular{kg^{-1}}$'],
        'SBCIN': [sfcpcl.bminus, 0, 'J $\mathregular{kg^{-1}}$'],
        'SBLCL': [sfcpcl.lclhght, 0, 'm AGL'],
        'SBLFC': [sfcpcl.lfchght, 0, 'm AGL'],
        'SBEL': [sfcpcl.elhght, 0, 'm AGL'],
        'SBLI': [sfcpcl.li5, 0, 'C'],
        'MLCAPE': [mlpcl.bplus, 0, 'J $\mathregular{kg^{-1}}$'],
        'MLCIN': [mlpcl.bminus, 0, 'J $\mathregular{kg^{-1}}$'],
        'MLLCL': [mlpcl.lclhght, 0, 'm AGL'],
        'MLLFC': [mlpcl.lfchght, 0, 'm AGL'],
        'MLEL': [mlpcl.elhght, 0, 'm AGL'],
        'MLLI': [mlpcl.li5, 0, 'C'],
        'MUCAPE': [mupcl.bplus, 0, 'J $\mathregular{kg^{-1}}$'],
        'MUCIN': [mupcl.bminus, 0, 'J $\mathregular{kg^{-1}}$'],
        'MULCL': [mupcl.lclhght, 0, 'm AGL'],
        'MULFC': [mupcl.lfchght, 0, 'm AGL'],
        'MUEL': [mupcl.elhght, 0, 'm AGL'],
        'MULI': [mupcl.li5, 0, 'C'],
        '0-1 km SRH': [srh1km[0], 0, '$\mathregular{m^{2}s^{-2}}$'],
        '0-1 km Shear':
        [utils.comp2vec(sfc_1km_shear[0], sfc_1km_shear[1])[1], 0, 'kt'],
        '0-3 km SRH': [srh3km[0], 0, '$\mathregular{m^{2}s^{-2}}$'],
        '0-6 km Shear':
        [utils.comp2vec(sfc_6km_shear[0], sfc_6km_shear[1])[1], 0, 'kt'],
        'PWV': [params.precip_water(prof), 2, 'inch'],
        'K-index': [params.k_index(prof), 0, ''],
        'STP(fix)': [stp_fixed, 1, ''],
        'SHIP': [ship, 1, '']
    }

    eff_inflow = params.effective_inflow_layer(prof)
    if any(eff_inflow):
        ebot_hght = interp.to_agl(prof, interp.hght(prof, eff_inflow[0]))
        etop_hght = interp.to_agl(prof, interp.hght(prof, eff_inflow[1]))
        #print "Effective Inflow Layer Bottom Height (m AGL):", ebot_hght
        #print "Effective Inflow Layer Top Height (m AGL):", etop_hght
        effective_srh = winds.helicity(prof,
                                       ebot_hght,
                                       etop_hght,
                                       stu=srwind[0],
                                       stv=srwind[1])
        indices['Eff. SRH'] = [
            effective_srh[0], 0, '$\mathregular{m^{2}s^{-2}}$'
        ]
        #print "Effective Inflow Layer SRH (m2/s2):", effective_srh[0]
        ebwd = winds.wind_shear(prof, pbot=eff_inflow[0], ptop=eff_inflow[1])
        ebwspd = utils.mag(*ebwd)
        indices['EBWD'] = [ebwspd, 0, 'kt']
        #print "Effective Bulk Wind Difference:", ebwspd
        scp = params.scp(mupcl.bplus, effective_srh[0], ebwspd)
        indices['SCP'] = [scp, 1, '']
        stp_cin = params.stp_cin(mlpcl.bplus, effective_srh[0], ebwspd,
                                 mlpcl.lclhght, mlpcl.bminus)
        indices['STP(cin)'] = [stp_cin, 1, '']
        #print "Supercell Composite Parameter:", scp
        #print "Significant Tornado Parameter (w/CIN):", stp_cin
        #print "Significant Tornado Parameter (fixed):", stp_fixed

    # Update the indices within the indices dictionary on the side of the plot.
    string = ''
    for index, value in sorted(indices.items()):
        if np.ma.is_masked(value[0]):
            if debug:
                print("skipping masked value for index=", index)
            continue
        if debug:
            print("index=", index)
            print("value=", value)
        format = '%.' + str(value[1]) + 'f'
        string += index + ": " + format % value[0] + " " + value[2] + '\n'

    return string
def process_site(file):
    try:
        ## switch out the reading function for the anticipated data type
        data = read_wyoming_file(file)
        #data = read_sounding_file(file)

        ## depending on the data reader used, different block of code is requires
        #"""
        p = data[:, 0]
        Z = data[:, 1]
        T = data[:, 2]
        Td = data[:, 3]
        U = np.zeros(T.shape)
        V = np.zeros(T.shape)
        """
        
        p = data[:, 0]
        T = data[:, 1]
        Td = data[:, 2]
        Z = data[:, 5]
        U = np.zeros(T.shape)
        V = np.zeros(T.shape)
        """
        ## comment out this triple quote if using the above block

        dz = None
        p_og = None
        z_og = None

        p[p == 9999.0] = np.nan
        T[T == 999.0] = np.nan
        Td[Td == 999.0] = np.nan
        Z[Z == 9999.0] = np.nan

        p = np.ma.masked_invalid(p)
        T = np.ma.masked_invalid(T)
        Td = np.ma.masked_invalid(Td)
        Z = np.ma.masked_invalid(Z)

    except:
        ## read in Kevins beautiful data
        data = read_kevins_file(file)
        Z = data[:, 0]
        p = data[:, 1]
        T = data[:, 2]
        U = np.zeros(T.shape)
        V = np.zeros(T.shape)
        Td = data[:, 3]

        dz = data[:, 4][::10]
        p_og = data[:, 5][::10]
        z_og = data[:, 6][::10]

        p = np.ma.masked_invalid(p)
        T = np.ma.masked_invalid(T)
        Td = np.ma.masked_invalid(Td)
        Z = np.ma.masked_invalid(Z)
    print file

    ## create profile object for processing
    prof = profile.create_profile(profile='default',
                                  pres=p,
                                  hght=Z,
                                  tmpc=T,
                                  dwpc=Td,
                                  u=U,
                                  v=V,
                                  strictQC=False)

    if dz is not None:
        pvals = interp.pres(prof, interp.to_msl(prof, np.arange(0, 5000, 100)))
        dz = interp.generic_interp_pres(np.log10(pvals),
                                        np.log10(p_og)[::-1], dz[::-1])
    print dz
    ## return the lifted parcel indices and the bore dz
    return lift_parcels(prof), dz
Esempio n. 34
0
    def get_kinematics(self):
        '''
        Function to generate the numerous kinematic quantities
        used for display and calculations. It requires that the
        parcel calculations have already been called for the lcl
        to el shear and mean wind vectors, as well as indices
        that require an effective inflow layer.

        Parameters
        ----------
        None

        Returns
        -------
        None
        '''
        sfc = self.pres[self.sfc]
        heights = np.array([1000., 3000., 4000., 5000., 6000., 8000., 9000.])
        p1km, p3km, p4km, p5km, p6km, p8km, p9km = interp.pres(
            self, interp.to_msl(self, heights))
        ## 1km and 6km winds
        self.wind1km = interp.vec(self, p1km)
        self.wind6km = interp.vec(self, p6km)
        ## calcluate wind shear
        self.sfc_1km_shear = winds.wind_shear(self, pbot=sfc, ptop=p1km)
        self.sfc_3km_shear = winds.wind_shear(self, pbot=sfc, ptop=p3km)
        self.sfc_6km_shear = winds.wind_shear(self, pbot=sfc, ptop=p6km)
        self.sfc_8km_shear = winds.wind_shear(self, pbot=sfc, ptop=p8km)
        self.sfc_9km_shear = winds.wind_shear(self, pbot=sfc, ptop=p9km)
        self.lcl_el_shear = winds.wind_shear(self,
                                             pbot=self.mupcl.lclpres,
                                             ptop=self.mupcl.elpres)
        ## calculate mean wind
        self.mean_1km = utils.comp2vec(
            *winds.mean_wind(self, pbot=sfc, ptop=p1km))
        self.mean_3km = utils.comp2vec(
            *winds.mean_wind(self, pbot=sfc, ptop=p3km))
        self.mean_6km = utils.comp2vec(
            *winds.mean_wind(self, pbot=sfc, ptop=p6km))
        self.mean_8km = utils.comp2vec(
            *winds.mean_wind(self, pbot=sfc, ptop=p8km))
        self.mean_lcl_el = utils.comp2vec(*winds.mean_wind(
            self, pbot=self.mupcl.lclpres, ptop=self.mupcl.elpres))
        ## parameters that depend on the presence of an effective inflow layer
        if self.etop is ma.masked or self.ebottom is ma.masked:
            self.etopm = ma.masked
            self.ebotm = ma.masked
            self.srwind = winds.non_parcel_bunkers_motion(self)
            self.eff_shear = [MISSING, MISSING]
            self.ebwd = [MISSING, MISSING, MISSING]
            self.ebwspd = MISSING
            self.mean_eff = [MISSING, MISSING, MISSING]
            self.mean_ebw = [MISSING, MISSING, MISSING]
            self.srw_eff = [MISSING, MISSING, MISSING]
            self.srw_ebw = [MISSING, MISSING, MISSING]
            self.right_esrh = [ma.masked, ma.masked, ma.masked]
            self.left_esrh = [ma.masked, ma.masked, ma.masked]
            self.critical_angle = ma.masked
        else:
            self.srwind = params.bunkers_storm_motion(self,
                                                      mupcl=self.mupcl,
                                                      pbot=self.ebottom)
            depth = (self.mupcl.elhght - self.ebotm) / 2
            elh = interp.pres(self, interp.to_msl(self, self.ebotm + depth))
            ## calculate mean wind
            self.mean_eff = winds.mean_wind(self, self.ebottom, self.etop)
            self.mean_ebw = winds.mean_wind(self, pbot=self.ebottom, ptop=elh)
            ## calculate wind shear of the effective layer
            self.eff_shear = winds.wind_shear(self,
                                              pbot=self.ebottom,
                                              ptop=self.etop)
            self.ebwd = winds.wind_shear(self, pbot=self.ebottom, ptop=elh)
            self.ebwspd = utils.mag(self.ebwd[0], self.ebwd[1])
            ## calculate the mean sr wind
            self.srw_eff = winds.sr_wind(self,
                                         pbot=self.ebottom,
                                         ptop=self.etop,
                                         stu=self.srwind[0],
                                         stv=self.srwind[1])
            self.srw_ebw = winds.sr_wind(self,
                                         pbot=self.ebottom,
                                         ptop=elh,
                                         stu=self.srwind[0],
                                         stv=self.srwind[1])
            self.right_esrh = winds.helicity(self,
                                             self.ebotm,
                                             self.etopm,
                                             stu=self.srwind[0],
                                             stv=self.srwind[1])
            self.left_esrh = winds.helicity(self,
                                            self.ebotm,
                                            self.etopm,
                                            stu=self.srwind[2],
                                            stv=self.srwind[3])
            self.critical_angle = winds.critical_angle(self,
                                                       stu=self.srwind[0],
                                                       stv=self.srwind[1])
        ## calculate mean srw
        self.srw_1km = utils.comp2vec(*winds.sr_wind(
            self, pbot=sfc, ptop=p1km, stu=self.srwind[0], stv=self.srwind[1]))
        self.srw_3km = utils.comp2vec(*winds.sr_wind(
            self, pbot=sfc, ptop=p3km, stu=self.srwind[0], stv=self.srwind[1]))
        self.srw_6km = utils.comp2vec(*winds.sr_wind(
            self, pbot=sfc, ptop=p6km, stu=self.srwind[0], stv=self.srwind[1]))
        self.srw_8km = utils.comp2vec(*winds.sr_wind(
            self, pbot=sfc, ptop=p8km, stu=self.srwind[0], stv=self.srwind[1]))
        self.srw_4_5km = utils.comp2vec(*winds.sr_wind(
            self, pbot=p4km, ptop=p5km, stu=self.srwind[0],
            stv=self.srwind[1]))
        self.srw_lcl_el = utils.comp2vec(
            *winds.sr_wind(self,
                           pbot=self.mupcl.lclpres,
                           ptop=self.mupcl.elpres,
                           stu=self.srwind[0],
                           stv=self.srwind[1]))
        # This is for the red, blue, and purple bars that appear on the SR Winds vs. Height plot
        self.srw_0_2km = winds.sr_wind(self,
                                       pbot=sfc,
                                       ptop=interp.pres(
                                           self, interp.to_msl(self, 2000.)),
                                       stu=self.srwind[0],
                                       stv=self.srwind[1])
        self.srw_4_6km = winds.sr_wind(self,
                                       pbot=interp.pres(
                                           self, interp.to_msl(self, 4000.)),
                                       ptop=p6km,
                                       stu=self.srwind[0],
                                       stv=self.srwind[1])
        self.srw_9_11km = winds.sr_wind(
            self,
            pbot=interp.pres(self, interp.to_msl(self, 9000.)),
            ptop=interp.pres(self, interp.to_msl(self, 11000.)),
            stu=self.srwind[0],
            stv=self.srwind[1])

        ## calculate upshear and downshear
        self.upshear_downshear = winds.mbe_vectors(self)
        self.srh1km = winds.helicity(self,
                                     0,
                                     1000.,
                                     stu=self.srwind[0],
                                     stv=self.srwind[1])
        self.srh3km = winds.helicity(self,
                                     0,
                                     3000.,
                                     stu=self.srwind[0],
                                     stv=self.srwind[1])
    ax3 = plt.subplot(gs[3, 0:3])
    skew.plot_wind_axes(ax2)
    #skew.plot_wind_barbs(ax2, prof.pres, prof.u, prof.v)  # all the wind barbs (usually too many to see pattern)

    # Reduce the number of data points to use for the wind barbs
    p_less, u_less, v_less = pressure_interval(prof.pres, prof.u, prof.v, 0,
                                               1050, 25)
    skew.plot_wind_barbs(ax2, p_less, u_less, v_less)

    srwind = params.bunkers_storm_motion(prof)
    gs.update(left=0.05, bottom=0.05, top=0.95, right=1, wspace=0.025)

    #########################

    # Calculate indices to be shown.
    p1km = interp.pres(prof, interp.to_msl(prof, 1000.))
    p3km = interp.pres(prof, interp.to_msl(prof, 3000.))
    p6km = interp.pres(prof, interp.to_msl(prof, 6000.))
    p8km = interp.pres(prof, interp.to_msl(prof, 8000.))
    p9km = interp.pres(prof, interp.to_msl(prof, 9000.))
    sfc = prof.pres[prof.sfc]
    sfc_1km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p1km)
    sfc_3km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p3km)
    sfc_6km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p6km)
    sfc_8km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p8km)
    sfc_9km_shear = winds.wind_shear(prof, pbot=sfc, ptop=p9km)
    srh3km = winds.helicity(prof, 0, 3000., stu=srwind[0], stv=srwind[1])
    srh1km = winds.helicity(prof, 0, 1000., stu=srwind[0], stv=srwind[1])
    scp = params.scp(prof.mupcl.bplus, prof.right_esrh[0], prof.ebwspd)
    stp_cin = params.stp_cin(prof.mlpcl.bplus, prof.right_esrh[0], prof.ebwspd,
                             prof.mlpcl.lclhght, prof.mlpcl.bminus)