Exemple #1
0
    def get_parcels(self):
        '''
        Function to generate various parcels and parcel
        traces.
        Returns nothing, but sets the following
        variables:

        self.mupcl : Most Unstable Parcel
        self.sfcpcl : Surface Based Parcel
        self.mlpcl : Mixed Layer Parcel
        self.fcstpcl : Forecast Surface Parcel
        self.ebottom : The bottom pressure level of
            the effective inflow layer
        self.etop : the top pressure level of
            the effective inflow layer
        self.ebotm : The bottom, meters (agl), of the
            effective inflow layer
        self.etopm : The top, meters (agl), of the
            effective inflow layer
    
        Parameters
        ----------
        None

        Returns
        -------
        None
        '''

        self.mupcl = params.parcelx( self, flag=3 )
        if self.mupcl.lplvals.pres == self.pres[self.sfc]:
            self.sfcpcl = self.mupcl
        else:
            self.sfcpcl = params.parcelx( self, flag=1 )
        self.fcstpcl = params.parcelx( self, flag=2 )
        self.mlpcl = params.parcelx( self, flag=4 )
        self.usrpcl = params.Parcel()

        ## get the effective inflow layer data
        self.ebottom, self.etop = params.effective_inflow_layer( self, mupcl=self.mupcl )

        ## if there was no effective inflow layer, set the values to masked
        if self.etop is ma.masked or self.ebottom is ma.masked:
            self.ebotm = ma.masked; self.etopm = ma.masked
            self.effpcl = self.sfcpcl # Default to surface parcel, as in params.DefineProfile().

        ## otherwise, interpolate the heights given to above ground level
        else:
            self.ebotm = interp.to_agl(self, interp.hght(self, self.ebottom))
            self.etopm = interp.to_agl(self, interp.hght(self, self.etop))
            # The below code was adapted from params.DefineProfile()
            # Lifting one additional parcel probably won't slow the program too much.
            # It's just one more lift compared to all the lifts in the params.effective_inflow_layer() call.
            mtha = params.mean_theta(self, self.ebottom, self.etop)
            mmr = params.mean_mixratio(self, self.ebottom, self.etop)
            effpres = (self.ebottom+self.etop)/2.
            efftmpc = thermo.theta(1000., mtha, effpres)
            effdwpc = thermo.temp_at_mixrat(mmr, effpres)
            self.effpcl = params.parcelx(self, flag=5, pres=effpres, tmpc=efftmpc, dwpc=effdwpc) #This is the effective parcel.
Exemple #2
0
    def get_parcels(self):
        '''
        Function to generate various parcels and parcel
        traces.
        Returns nothing, but sets the following
        variables:

        self.mupcl : Most Unstable Parcel
        self.sfcpcl : Surface Based Parcel
        self.mlpcl : Mixed Layer Parcel
        self.fcstpcl : Forecast Surface Parcel
        self.ebottom : The bottom pressure level of
            the effective inflow layer
        self.etop : the top pressure level of
            the effective inflow layer
        self.ebotm : The bottom, meters (agl), of the
            effective inflow layer
        self.etopm : The top, meters (agl), of the
            effective inflow layer
    
        Parameters
        ----------
        None

        Returns
        -------
        None
        '''

        self.mupcl = params.parcelx( self, flag=3 )
        if self.mupcl.lplvals.pres == self.pres[self.sfc]:
            self.sfcpcl = self.mupcl
        else:
            self.sfcpcl = params.parcelx( self, flag=1 )
        self.fcstpcl = params.parcelx( self, flag=2 )
        self.mlpcl = params.parcelx( self, flag=4 )
        self.usrpcl = params.Parcel()

        ## get the effective inflow layer data
        self.ebottom, self.etop = params.effective_inflow_layer( self, mupcl=self.mupcl )

        ## if there was no effective inflow layer, set the values to masked
        if self.etop is ma.masked or self.ebottom is ma.masked:
            self.ebotm = ma.masked; self.etopm = ma.masked
            self.effpcl = self.sfcpcl # Default to surface parcel, as in params.DefineProfile().

        ## otherwise, interpolate the heights given to above ground level
        else:
            self.ebotm = interp.to_agl(self, interp.hght(self, self.ebottom))
            self.etopm = interp.to_agl(self, interp.hght(self, self.etop))
            # The below code was adapted from params.DefineProfile()
            # Lifting one additional parcel probably won't slow the program too much.
            # It's just one more lift compared to all the lifts in the params.effective_inflow_layer() call.
            mtha = params.mean_theta(self, self.ebottom, self.etop)
            mmr = params.mean_mixratio(self, self.ebottom, self.etop)
            effpres = (self.ebottom+self.etop)/2.
            efftmpc = thermo.theta(1000., mtha, effpres)
            effdwpc = thermo.temp_at_mixrat(mmr, effpres)
            self.effpcl = params.parcelx(self, flag=5, pres=effpres, tmpc=efftmpc, dwpc=effdwpc) #This is the effective parcel.
def test_to_agl():
    input_z = 1000.
    correct_agl = 643.0
    returned_agl = interp.to_agl(prof, input_z)
    npt.assert_almost_equal(returned_agl, correct_agl)

    input_z = [1000., 3000., 6000.]
    correct_agl = [643., 2643., 5643.]
    returned_agl = interp.to_agl(prof, input_z)
    npt.assert_almost_equal(returned_agl, correct_agl)
Exemple #4
0
def test_to_agl():
    input_z = 1000.
    correct_agl = 643.0
    returned_agl = interp.to_agl(prof, input_z)
    npt.assert_almost_equal(returned_agl, correct_agl)

    input_z = [1000., 3000., 6000.]
    correct_agl = [643., 2643., 5643.]
    returned_agl = interp.to_agl(prof, input_z)
    npt.assert_almost_equal(returned_agl, correct_agl)
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)
Exemple #6
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
Exemple #7
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
Exemple #8
0
def add_hodo(ax,
             prof,
             lw=1,
             color='black',
             ls='solid',
             size=5,
             AGLs=[1, 2, 6, 10]):
    # Return 2D hodograph line and list of text AGL labels.

    # Draw hodo line
    u_prof = prof.u[prof.pres >= 100]
    v_prof = prof.v[prof.pres >= 100]
    hodo, = ax.plot(u_prof, v_prof, 'k-', lw=lw, color=color, ls=ls)

    # position AGL text labels
    bbox_props = dict(boxstyle="square",
                      fc="w",
                      ec="0.5",
                      linewidth=0.5,
                      alpha=0.7)
    AGL_labels = []
    AGL_labels.append(ax.text(-35, -55, 'km AGL', size=size, bbox=bbox_props))
    for a in AGLs:
        in_meters = a * 1000
        if in_meters <= np.max(interp.to_agl(prof, prof.hght)):
            junk = ax.text(0,
                           0,
                           str(a),
                           ha='center',
                           va='center',
                           size=size,
                           bbox=bbox_props,
                           color=color)
            ind = np.min(np.where(interp.to_agl(prof, prof.hght) > in_meters))
            junk.set_position((prof.u[ind], prof.v[ind]))
            junk.set_clip_on(True)
            AGL_labels.append(junk)
    return hodo, AGL_labels
Exemple #9
0
    def draw_ensemble_point(self, qp, prof):
        # Plot the profile index on the scatter plot
        if 'pbl_h' not in dir(
                prof
        ):  # Make sure a PBL top has been found in the profile object
            ppbl_top = params.pbl_top(prof)
            setattr(prof, 'pbl_h',
                    interp.to_agl(prof, interp.hght(prof, ppbl_top)))
        if 'sfcpcl' not in dir(
                prof
        ):  # Make sure a surface parcel has been lifted in the profile object
            setattr(prof, 'sfcpcl', params.parcelx(prof, flag=1))
        #x = self.x_to_xpix()
        #y = self.y_to_ypix()
        color = QtCore.Qt.red
        qp.setPen(QtGui.QPen(color))
        qp.setBrush(QtGui.QBrush(color))
        x = self.x_to_xpix(prof.pbl_h) - 50 / 2.
        y = self.y_to_ypix(prof.sfcpcl.bplus) - (self.fsize - 1) / 2
        qp.drawEllipse(x, y, 3, 3)

        return
Exemple #10
0
def init_phase(prof):
    '''
        Inital Precipitation Phase
        Adapted from SHARP code donated by Rich Thompson (SPC)

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

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

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

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

    '''
    # Needs to be tested

    plevel = 0
    phase = -1

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

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

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

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

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

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

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

    return plevel, phase, tmp, st
Exemple #11
0
def best_guess_precip(prof, init_phase, init_lvl, init_temp, tpos, tneg):
    '''
        Best Guess Precipitation type
        Adapted from SHARP code donated by Rich Thompson (SPC)

        Description:
        This algorithm utilizes the output from the init_phase() and posneg_temperature()
        functions to make a best guess at the preciptation type one would observe
        at the surface given a thermodynamic profile.

        Precipitation Types Supported:
        - None
        - Rain
        - Snow
        - Sleet and Snow
        - Sleet
        - Freezing Rain/Drizzle
        - Unknown

        Parameters
        ----------
        prof : Profile object
        init_phase : the initial phase of the precipitation (int) (see 2nd value returned from init_phase())
        init_lvl : the inital level of the precipitation source (mb) (see 1st value returned from init_phase())
        init_temp : the inital level of the precipitation source (C) (see 3rd value returned from init_phase())
        tpos : the positive area (> 0 C) in the temperature profile (J/kg)

        Returns
        -------
        precip_type : a string containing the best guess precipitation type
    '''
    # Needs to be tested

    precip_type = None

    # Case: No precip
    if init_phase < 0:
        precip_type = "None."

    # Case: Always too warm - Rain
    elif init_phase == 0 and tneg >= 0 and prof.tmpc[prof.get_sfc()] > 0:
        precip_type = "Rain."

    # Case: always too cold
    elif init_phase == 3 and tpos <= 0 and prof.tmpc[prof.get_sfc()] <= 0:
        precip_type = "Snow."

    # Case: ZR too warm at sfc - Rain
    elif init_phase == 1 and tpos <= 0 and prof.tmpc[prof.get_sfc()] > 0:
        precip_type = "Rain."

    # Case: non-snow init...always too cold - Initphase & sleet
    elif init_phase == 1 and tpos <= 0 and prof.tmpc[prof.get_sfc()] <= 0:
        #print interp.to_agl(prof, interp.hght(prof, init_lvl))
        if interp.to_agl(prof, interp.hght(prof, init_lvl)) >= 3000:
            if init_temp <= -4:
                precip_type = "Sleet and Snow."
            else:
                precip_type = "Sleet."
        else:
            precip_type = "Freezing Rain/Drizzle."

    # Case: Snow...but warm at sfc
    elif init_phase == 3 and tpos <= 0 and prof.tmpc[prof.get_sfc()] > 0:
        if prof.tmpc[prof.get_sfc()] > 4:
            precip_type = "Rain."
        else:
            precip_type = "Snow."

    # Case: Warm layer.
    elif tpos > 0:
        x1 = tpos
        y1 = -tneg
        y2 = (0.62 * x1) + 60.0
        if y1 > y2:
            precip_type = "Sleet."
        else:
            if prof.tmpc[prof.get_sfc()] <= 0:
                precip_type = "Freezing Rain."
            else:
                precip_type = "Rain."
    else:
        precip_type = "Unknown."

    return precip_type
Exemple #12
0
def init_phase(prof):
    '''
        Inital Precipitation Phase
        Adapted from SHARP code donated by Rich Thompson (SPC)

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

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

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

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

    '''
    # Needs to be tested

    plevel = 0
    phase = -1

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

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

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

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

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

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

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

    return plevel, phase, tmp, st
Exemple #13
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
Exemple #14
0
''' Create the Sounding (Profile) Object '''
Exemple #15
0
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)
ebot_hght = interp.to_agl(prof, interp.hght(prof, eff_inflow[0]))
etop_hght = interp.to_agl(prof, interp.hght(prof, eff_inflow[1]))
effective_srh = winds.helicity(prof,
                               ebot_hght,
                               etop_hght,
                               stu=srwind[0],
                               stv=srwind[1])
ebwd = winds.wind_shear(prof, pbot=eff_inflow[0], ptop=eff_inflow[1])
ebwspd = utils.mag(ebwd[0], ebwd[1])
scp = params.scp(mupcl.bplus, effective_srh[0], ebwspd)
stp_cin = params.stp_cin(mlpcl.bplus, effective_srh[0], ebwspd, mlpcl.lclhght,
                         mlpcl.bminus)

indices = {'SBCAPE': [int(sfcpcl.bplus), 'J/kg'],\
           'SBCIN': [int(sfcpcl.bminus), 'J/kg'],\
           'SBLCL': [int(sfcpcl.lclhght), 'm AGL'],\
Exemple #16
0
    # annotate dewpoint in F at bottom of dewpoint profile
    dewpointF = skew.ax.text(prof.dwpc[0], prof.pres[0]+10, utils.INT2STR(thermo.ctof(prof.dwpc[0])), 
            verticalalignment='top', horizontalalignment='center', size=7, color=dwpt_trace.get_color())
    skew.plot(pcl.ptrace, pcl.ttrace, 'brown', linestyle="dashed" )        # parcel temperature trace 
    skew.ax.set_ylim(1050,100)
    skew.ax.set_xlim(-50,45)


    # Plot the effective inflow layer using purple horizontal lines
    eff_inflow = params.effective_inflow_layer(prof)
    inflow_bot = skew.ax.axhline(eff_inflow[0], color='purple',xmin=0.38, xmax=0.45)
    inflow_top = skew.ax.axhline(eff_inflow[1], color='purple',xmin=0.38, xmax=0.45)
    srwind = params.bunkers_storm_motion(prof)
    # annotate effective inflow layer SRH 
    if eff_inflow[0]:
        ebot_hght = interp.to_agl(prof, interp.hght(prof, eff_inflow[0]))
        etop_hght = interp.to_agl(prof, interp.hght(prof, eff_inflow[1]))
        effective_srh = winds.helicity(prof, ebot_hght, etop_hght, stu = srwind[0], stv = srwind[1])
        # Set position of label
        # x position is mean of horizontal line bounds
        # For some reason this makes a big white space on the left side and for all subsequent plots.
        inflow_SRH = skew.ax.text(
                np.mean(inflow_top.get_xdata()), eff_inflow[1],
                '%.0f' % effective_srh[0] + ' ' + '$\mathregular{m^{2}s^{-2}}$',
                verticalalignment='bottom', horizontalalignment='center', size=6, transform=inflow_bot.get_transform(), color=inflow_top.get_color()
                )

    # draw indices text string to the right of plot.
    indices_text = plt.text(1.08, 1.0, myskewt.indices(prof), verticalalignment='top', size=5.6, transform=plt.gca().transAxes)

    # globe with dot
Exemple #17
0
def append_wbz():
    #Load each ERA-Interim netcdf file, and append wbz

    start_lat = -44.525
    end_lat = -9.975
    start_lon = 111.975
    end_lon = 156.275
    domain = [start_lat, end_lat, start_lon, end_lon]
    model = "erai"
    region = "aus"
    dates = []
    for y in np.arange(1979, 2019):
        for m in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]:
            if (m != 12):
                dates.append([dt.datetime(y,m,1,0,0,0),\
                 dt.datetime(y,m+1,1,0,0,0)-dt.timedelta(hours = 6)])
            else:
                dates.append([dt.datetime(y,m,1,0,0,0),\
                 dt.datetime(y+1,1,1,0,0,0)-dt.timedelta(hours = 6)])
    for t in np.arange(0, len(dates)):
        print(str(dates[t][0]) + " - " + str(dates[t][1]))

        fname = "/g/data/eg3/ab4502/ExtremeWind/"+region+"/"+model+"/"+model+"_"+\
         dt.datetime.strftime(dates[t][0],"%Y%m%d")+"_"+\
         dt.datetime.strftime(dates[t][-1],"%Y%m%d")+".nc"

        ta,dp,hur,hgt,terrain,p,ps,wap,ua,va,uas,vas,tas,ta2d,cp,wg10,cape,lon,lat,date_list = \
         read_erai(domain,dates[t])

        dp = get_dp(ta, hur, dp_mask=False)

        agl_idx = (p <= ps)

        #Replace masked dp values
        dp = replace_dp(dp)
        try:
            prof = profile.create_profile(pres = np.insert(p[agl_idx],0,ps), \
             hght = np.insert(hgt[agl_idx],0,terrain), \
             tmpc = np.insert(ta[agl_idx],0,tas), \
             dwpc = np.insert(dp[agl_idx],0,ta2d), \
             u = np.insert(ua[agl_idx],0,uas), \
             v = np.insert(va[agl_idx],0,vas), \
             strictqc=False, omeg=np.insert(wap[agl_idx],0,wap[agl_idx][0]) )
        except:
            p = p[agl_idx]
            ua = ua[agl_idx]
            va = va[agl_idx]
            hgt = hgt[agl_idx]
            ta = ta[agl_idx]             \
               dp = dp[agl_idx]
            p[0] = ps
            ua[0] = uas
            va[0] = vas
            hgt[0] = terrain
            ta[0] = tas
            dp[0] = ta2d
            prof = profile.create_profile(pres = p, \
             hght = hgt, \
             tmpc = ta, \
             dwpc = dp, \
             u = ua, \
             v = va, \
             strictqc=False, omeg=wap[agl_idx])

        pwb0 = params.temp_lvl(prof, 0, wetbulb=True)
        hwb0 = interp.to_agl(prof, interp.hght(prof, pwb0))

        param_file = nc.Dataset(fname, "a")
        wbz_var = param_file.createVariable("wbz",float,\
        ("time","lat","lon"))
        wbz_var.units = "m"
        wbz_var.long_name = "wet_bulb_zero_height"
        wbz_var[:] = hwb0

        T1 = abs(
            thermo.wetlift(prof.pres[0], prof.tmpc[0], 600) -
            interp.temp(prof, 600))
        T2 = abs(
            thermo.wetlift(pwb0, interp.temp(prof, pwb0), sfc) - prof.tmpc[0])
        Vprime = utils.KTS2MS(13 * np.sqrt((T1 + T2) / 2) + (1 / 3 *
                                                             (Umean01)))

        Vprime_var = param_file.createVariable("Vprime",float,\
        ("time","lat","lon"))
        Vprime_var.units = "m/s"
        Vprime_var.long_name = "miller_1972_wind_speed"
        Vprime_var[:] = Vprime

        param_file.close()
Exemple #18
0
def best_guess_precip(prof, init_phase, init_lvl, init_temp, tpos, tneg):
    '''
        Best Guess Precipitation type
        Adapted from SHARP code donated by Rich Thompson (SPC)

        Description:
        This algorithm utilizes the output from the init_phase() and posneg_temperature()
        functions to make a best guess at the preciptation type one would observe
        at the surface given a thermodynamic profile.

        Precipitation Types Supported:
        - None
        - Rain
        - Snow
        - Sleet and Snow
        - Sleet
        - Freezing Rain/Drizzle
        - Unknown

        Parameters
        ----------
        prof : Profile object
        init_phase : the initial phase of the precipitation (int) (see 2nd value returned from init_phase())
        init_lvl : the inital level of the precipitation source (mb) (see 1st value returned from init_phase())
        init_temp : the inital level of the precipitation source (C) (see 3rd value returned from init_phase())
        tpos : the positive area (> 0 C) in the temperature profile (J/kg)

        Returns
        -------
        precip_type : a string containing the best guess precipitation type
    '''
    # Needs to be tested

    precip_type = None

    # Case: No precip
    if init_phase < 0:
        precip_type = "None."

    # Case: Always too warm - Rain
    elif init_phase == 0 and tneg >=0 and prof.tmpc[prof.get_sfc()] > 0:
        precip_type = "Rain."

    # Case: always too cold
    elif init_phase == 3 and tpos <= 0 and prof.tmpc[prof.get_sfc()] <= 0:
        precip_type = "Snow."

    # Case: ZR too warm at sfc - Rain
    elif init_phase == 1 and tpos <= 0 and prof.tmpc[prof.get_sfc()] > 0:
        precip_type = "Rain."

    # Case: non-snow init...always too cold - Initphase & sleet
    elif init_phase == 1 and tpos <= 0 and prof.tmpc[prof.get_sfc()] <= 0:
        #print interp.to_agl(prof, interp.hght(prof, init_lvl))
        if interp.to_agl(prof, interp.hght(prof, init_lvl)) >= 3000:
            if init_temp <= -4:
                precip_type = "Sleet and Snow."
            else:
                precip_type = "Sleet."
        else:
            precip_type = "Freezing Rain/Drizzle."

    # Case: Snow...but warm at sfc
    elif init_phase == 3 and tpos <= 0 and prof.tmpc[prof.get_sfc()] > 0:
        if prof.tmpc[prof.get_sfc()] > 4:
            precip_type = "Rain."
        else:
            precip_type = "Snow."
   
    # Case: Warm layer.
    elif tpos > 0:
        x1 = tpos
        y1 = -tneg
        y2 = (0.62 * x1) + 60.0
        if y1 > y2:
            precip_type = "Sleet."
        else:
            if prof.tmpc[prof.get_sfc()] <= 0:
                precip_type = "Freezing Rain."
            else:
                precip_type = "Rain."
    else:
        precip_type = "Unknown."

    return precip_type
Exemple #19
0
                              linestyle="dashed")  # parcel temperature trace

    # Plot the effective inflow layer using purple horizontal lines
    eff_inflow = params.effective_inflow_layer(prof)
    inflow_bot = skew.ax.axhline(eff_inflow[0],
                                 color='purple',
                                 xmin=0.38,
                                 xmax=0.45)
    inflow_top = skew.ax.axhline(eff_inflow[1],
                                 color='purple',
                                 xmin=0.38,
                                 xmax=0.45)
    srwind = params.bunkers_storm_motion(prof)
    # annotate effective inflow layer SRH
    if eff_inflow[0]:
        ebot_hght = interp.to_agl(prof, interp.hght(prof, eff_inflow[0]))
        etop_hght = interp.to_agl(prof, interp.hght(prof, eff_inflow[1]))
        effective_srh = winds.helicity(prof,
                                       ebot_hght,
                                       etop_hght,
                                       stu=srwind[0],
                                       stv=srwind[1])
        # Set position of label
        # x position is mean of horizontal line bounds
        # For some reason this makes a big white space on the left side and for all subsequent plots.
        inflow_SRH = skew.ax.text(np.mean(inflow_top.get_xdata()),
                                  eff_inflow[1],
                                  '%.0f' % effective_srh[0] + ' ' +
                                  '$\mathregular{m^{2}s^{-2}}$',
                                  verticalalignment='bottom',
                                  horizontalalignment='center',
Exemple #20
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 ##
    """
Exemple #21
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 ##
    """