Пример #1
0
def theta_plots(pressure, temperature, mixing_ratio):
    """
    plots for vertical profiles of potential temperature, equivalent potential temperature, 
    and saturated equivalent potential temperature
    """
    p = pressure * units('mbar')
    T = temperature * units('degC')
    q = mixing_ratio * units('kilogram/kilogram')

    lev = find_nearest(p.magnitude, 100)
    Td = mpcalc.dewpoint(mpcalc.vapor_pressure(p, q))  # dewpoint
    theta = mpcalc.potential_temperature(p, T)
    theta_e = mpcalc.equivalent_potential_temperature(p, T, Td)
    theta_es = mpcalc.equivalent_potential_temperature(p, T, T)

    plt.figure(figsize=(7, 7))
    plt.plot(theta[:lev], p[:lev], '-ok')
    plt.plot(theta_e[:lev], p[:lev], '-ob')
    plt.plot(theta_es[:lev], p[:lev], '-or')
    plt.xlabel('Temperature [K]', fontsize=12)
    plt.ylabel('Pressure [hpa]', fontsize=12)
    plt.gca().invert_yaxis()
    plt.legend(['$\\theta$', '$\\theta_e$', '$\\theta_{es}$'], loc=1)
    plt.grid()
    return (plt)
Пример #2
0
def run_calcs(df, ctx):
    """Do our maths."""
    # Convert sea level pressure to station pressure
    df['pressure'] = mcalc.add_height_to_pressure(
        df['slp'].values * units('millibars'),
        ctx['nt'].sts[ctx['station']]['elevation'] * units('m')).to(
            units('millibar'))
    # Compute the mixing ratio
    df['mixingratio'] = mcalc.mixing_ratio_from_relative_humidity(
        df['relh'].values * units('percent'),
        df['tmpf'].values * units('degF'),
        df['pressure'].values * units('millibars'))
    # Compute the saturation mixing ratio
    df['saturation_mixingratio'] = mcalc.saturation_mixing_ratio(
        df['pressure'].values * units('millibars'),
        df['tmpf'].values * units('degF'))
    df['vapor_pressure'] = mcalc.vapor_pressure(
        df['pressure'].values * units('millibars'),
        df['mixingratio'].values * units('kg/kg')).to(units('kPa'))
    df['saturation_vapor_pressure'] = mcalc.vapor_pressure(
        df['pressure'].values * units('millibars'),
        df['saturation_mixingratio'].values * units('kg/kg')).to(units('kPa'))
    df['vpd'] = df['saturation_vapor_pressure'] - df['vapor_pressure']
    group = df.groupby('year')
    df = group.aggregate(np.average)

    df['dwpf'] = mcalc.dewpoint(df['vapor_pressure'].values * units('kPa')).to(
        units('degF')).m
    return df
Пример #3
0
def add_entropy(ax,
                pressure,
                temperature,
                mixing_ratio,
                ds=100,
                linewidth=1.0):
    "add entropy curves and rescale values to fit in by 0.5*entropy + ds"
    p = pressure * units('mbar')
    T = temperature * units('degC')
    q = mixing_ratio * units('kilogram/kilogram')
    qs = mpcalc.mixing_ratio(mpcalc.saturation_vapor_pressure(T), p)
    Td = mpcalc.dewpoint(mpcalc.vapor_pressure(p, q))  # dewpoint
    Tp = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC')  # parcel profile

    # specific entropy [joule/(kg*K)]
    # sd : specific entropy of dry air
    # sm1 : specific entropy of airborne mositure in state 1 (water vapor)
    # sm2 : specific entropy of airborne mositure in state 2 (saturated water vapor)

    sd = entropy(T, q * 0, p)
    sm1 = entropy(T, q, p)
    sm2 = entropy(T, qs, p)

    ax.plot(sd.magnitude * 0.5 + ds, p, '--k')
    ax.plot(sm1.magnitude * 0.5 + ds, p, '--b')
    ax.plot(sm2.magnitude * 0.5 + ds, p, '--r')
Пример #4
0
def run_calcs(df, ctx):
    """Do our maths."""
    # Convert sea level pressure to station pressure
    df["pressure"] = mcalc.add_height_to_pressure(
        df["slp"].values * units("millibars"),
        ctx["_nt"].sts[ctx["station"]]["elevation"] * units("m"),
    ).to(units("millibar"))
    # Compute the mixing ratio
    df["mixingratio"] = mcalc.mixing_ratio_from_relative_humidity(
        df["relh"].values * units("percent"),
        df["tmpf"].values * units("degF"),
        df["pressure"].values * units("millibars"),
    )
    # Compute the saturation mixing ratio
    df["saturation_mixingratio"] = mcalc.saturation_mixing_ratio(
        df["pressure"].values * units("millibars"),
        df["tmpf"].values * units("degF"),
    )
    df["vapor_pressure"] = mcalc.vapor_pressure(
        df["pressure"].values * units("millibars"),
        df["mixingratio"].values * units("kg/kg"),
    ).to(units("kPa"))
    df["saturation_vapor_pressure"] = mcalc.vapor_pressure(
        df["pressure"].values * units("millibars"),
        df["saturation_mixingratio"].values * units("kg/kg"),
    ).to(units("kPa"))
    df["vpd"] = df["saturation_vapor_pressure"] - df["vapor_pressure"]
    # remove any NaN rows
    df = df.dropna()
    group = df.groupby("year")
    df = group.aggregate(np.average)

    df["dwpf"] = (mcalc.dewpoint(df["vapor_pressure"].values *
                                 units("kPa")).to(units("degF")).m)
    return df
Пример #5
0
def plot(variables, prev_vars, pltenv):

    cont_int = 10
    cont_smooth = 0.5

    x = pltenv['x']
    y = pltenv['y']
    m = pltenv['map']

    bbox = dict(boxstyle="square", ec='None', fc=(1, 1, 1, 0.75))

    #var = (variables['T2'][0]-273.15) * 1.8 + 32
    var = variables['Q2'][0] * 1000.
    varp = variables['AFWA_MSLP'][0] * 0.01
    var = var * units('g/kg')
    vare = mcalc.vapor_pressure(varp * units.mbar, var)
    vartd = mcalc.dewpoint(vare)
    vartd = vartd.to('degF')
    var2 = ndimage.gaussian_filter(vartd, sigma=cont_smooth)
    levels = np.arange(-100, 150, cont_int)
    levels2 = np.arange(-40, 140, 1)

    P = m.contour(x, y, var2, levels=levels, colors='k')
    plt.clabel(P, inline=1, fontsize=10, fmt='%1.0f', inline_spacing=1)

    P = m.contour(x, y, var2, levels=[32], colors='r')
    plt.clabel(P, inline=1, fontsize=10, fmt='%1.0f', inline_spacing=1)

    m.contourf(x, y, vartd, cmap='gist_ncar', levels=levels2, extend='both')
Пример #6
0
def convert_H2O_MR_to_Td(H2O_MR, p):
    # input water vapour mass mixing ration in (mWV / mDA) kg/kg

    WVMR = H2O_MR * 1000  # convert to grams
    WVMR = WVMR * units('g/kg')
    e_1 = mpcalc.vapor_pressure(p_NUCAPS_orig, WVMR)
    T_d = mpcalc.dewpoint(e_1)
    return T_d
Пример #7
0
def test_dewpoint_weird_units():
    """Test dewpoint using non-standard units.

    Revealed from odd dimensionless units and ending up using numpy.ma math
    functions instead of numpy ones.
    """
    assert_almost_equal(dewpoint(15825.6 * units('g * mbar / kg')),
                        13.8564 * units.degC, 4)
Пример #8
0
def test_dewpoint_weird_units():
    """Test dewpoint using non-standard units.

    Revealed from odd dimensionless units and ending up using numpy.ma math
    functions instead of numpy ones.
    """
    assert_almost_equal(dewpoint(15825.6 * units('g * mbar / kg')),
                        13.8564 * units.degC, 4)
Пример #9
0
def add_curves(ax,
               pressure,
               temperature,
               mixing_ratio,
               altitude,
               linewidth=1.0,
               LH_Tdepend=False):
    """
    overlaying new curves of multiple soundings from profiles
    """
    p = pressure * units('mbar')
    T = temperature * units('degC')
    q = mixing_ratio * units('kilogram/kilogram')
    qs = mpcalc.mixing_ratio(mpcalc.saturation_vapor_pressure(T), p)
    Td = mpcalc.dewpoint(mpcalc.vapor_pressure(p, q))  # dewpoint
    Tp = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC')  # parcel profile

    # Altitude based on the hydrostatic eq.
    if len(altitude) == len(pressure):  # (1) altitudes for whole levels
        altitude = altitude * units('meter')
    elif len(altitude
             ) == 1:  # (2) known altitude where the soundings was launched
        z_surf = altitude.copy() * units('meter')
        # given altitude
        altitude = np.zeros((np.size(T))) * units('meter')
        for i in range(np.size(T)):
            altitude[i] = mpcalc.thickness_hydrostatic(
                p[:i + 1], T[:i + 1]) + z_surf  # Hypsometric Eq. for height
    else:
        print(
            '***NOTE***: the altitude at the surface is assumed 0 meter, and altitudes are derived based on the hypsometric equation'
        )
        altitude = np.zeros(
            (np.size(T))) * units('meter')  # surface is 0 meter
        for i in range(np.size(T)):
            altitude[i] = mpcalc.thickness_hydrostatic(
                p[:i + 1], T[:i + 1])  # Hypsometric Eq. for height

    # specific energies
    if LH_Tdepend == False:
        mse = mpcalc.moist_static_energy(altitude, T, q)
        mse_s = mpcalc.moist_static_energy(altitude, T, qs)
        dse = mpcalc.dry_static_energy(altitude, T)
    else:
        # A short course in cloud physics, Roger and Yau (1989)
        Lvt = (2500.8 - 2.36 * T.magnitude +
               0.0016 * T.magnitude**2 - 0.00006 * T.magnitude**3) * units(
                   'joule/gram')  # latent heat of evaporation
        #Lf = 2834.1 - 0.29*T - 0.004*T**2                  # latent heat of fusion

        mse = Cp_d * T + g * altitude + Lvt * q
        mse_s = Cp_d * T + g * altitude + Lvt * qs
        dse = mpcalc.dry_static_energy(altitude, T)

    ax.plot(dse, p, '--k', linewidth=linewidth)
    ax.plot(mse, p, '--b', linewidth=linewidth)
    ax.plot(mse_s, p, '--r', linewidth=linewidth)
Пример #10
0
def down_cape(p_start=None):

    if p_start not in ls.lev:
        raise ValueError(
            "Please provide pressure of one level of large-scale dataset to start calculating DCAPE from."
        )

    # find index of p_start
    start_level = int((abs(ls.lev - p_start)).argmin())

    # get temperature and humidity from large-scale state
    temp = ls.T.sel(lev=slice(None, 990)).metpy.unit_array
    mix = ls.r.sel(lev=slice(None, 990)).metpy.unit_array.to('kg/kg')
    p_vector = ls.lev.sel(lev=slice(None, 990)).metpy.unit_array

    # get dew-point temperature
    vap_pres = mpcalc.vapor_pressure(p_vector, mix)
    dew_temp = mpcalc.dewpoint(vap_pres)

    # pressure levels to integrate over
    p_down = ls.lev.sel(lev=slice(p_start, 990))

    # find NaNs
    l_valid = ls.T[:, start_level].notnull().values

    d_cape = xr.full_like(ls.cape, np.nan)
    x = p_down.values
    temp = temp[l_valid, :]
    dew_temp = dew_temp[l_valid, :]
    # loop over all non-NaN times in large-scale state
    for i, this_time in enumerate(ls.T[l_valid].time):
        print(i)
        # bug: p_start has to be multiplied with units when given as argument, not beforehand
        wb_temp = mpcalc.wet_bulb_temperature(p_start * units['hPa'],
                                              temp[i, start_level],
                                              dew_temp[i, start_level])

        # create placeholder for moist adiabat temperature
        moist_adiabat = temp[i, start_level:].to('degC')

        moist_adiabat_below = mpcalc.moist_lapse(p_vector[start_level + 1:],
                                                 wb_temp,
                                                 p_start * units['hPa'])
        moist_adiabat[0] = wb_temp
        moist_adiabat[1:] = moist_adiabat_below

        env_temp = temp[i, start_level:]
        temp_diff = moist_adiabat - env_temp

        y = temp_diff.magnitude
        d_cape.loc[this_time] = (mpconsts.Rd *
                                 (np.trapz(y, np.log(x)) * units.degK)).to(
                                     units('J/kg'))

    d_cape.attrs['long_name'] = 'Downward CAPE'
    return xr.merge([ls, xr.Dataset({'d_cape': d_cape})])
Пример #11
0
def entropy_plots(pressure,
                  temperature,
                  mixing_ratio,
                  altitude,
                  h0_std=2000,
                  ensemble_size=20,
                  ent_rate=np.arange(0, 2, 0.05),
                  entrain=False):
    """
    plotting the summarized entropy diagram with annotations and thermodynamic parameters
    """
    p = pressure * units('mbar')
    T = temperature * units('degC')
    q = mixing_ratio * units('kilogram/kilogram')
    qs = mpcalc.mixing_ratio(mpcalc.saturation_vapor_pressure(T), p)
    Td = mpcalc.dewpoint(mpcalc.vapor_pressure(p, q))  # dewpoint
    Tp = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC')  # parcel profile

    # Altitude based on the hydrostatic eq.
    if len(altitude) == len(pressure):  # (1) altitudes for whole levels
        altitude = altitude * units('meter')
    elif len(altitude
             ) == 1:  # (2) known altitude where the soundings was launched
        z_surf = altitude.copy() * units('meter')
        # given altitude
        altitude = np.zeros((np.size(T))) * units('meter')
        for i in range(np.size(T)):
            altitude[i] = mpcalc.thickness_hydrostatic(
                p[:i + 1], T[:i + 1]) + z_surf  # Hypsometric Eq. for height
    else:
        print(
            '***NOTE***: the altitude at the surface is assumed 0 meter, and altitudes are derived based on the hypsometric equation'
        )
        altitude = np.zeros(
            (np.size(T))) * units('meter')  # surface is 0 meter
        for i in range(np.size(T)):
            altitude[i] = mpcalc.thickness_hydrostatic(
                p[:i + 1], T[:i + 1])  # Hypsometric Eq. for height

    # specific entropy [joule/(kg*K)]
    # sd : specific entropy of dry air
    # sm1 : specific entropy of airborne mositure in state 1 (water vapor)
    # sm2 : specific entropy of airborne mositure in state 2 (saturated water vapor)

    sd = entropy(T.magnitude, q.magnitude * 1e-6, p.magnitude)
    sm1 = entropy(T.magnitude, q.magnitude, p.magnitude)
    sm2 = entropy(T.magnitude, qs.magnitude, p.magnitude)
    ###############################

    # Water vapor calculations
    p_PWtop = min(p)
    #p_PWtop = max(200*units.mbar, min(p) + 1*units.mbar) # integrating until 200mb
    cwv = mpcalc.precipitable_water(Td, p,
                                    top=p_PWtop)  # column water vapor [mm]
    cwvs = mpcalc.precipitable_water(
        T, p, top=p_PWtop)  # saturated column water vapor [mm]
    crh = (cwv / cwvs) * 100.  # column relative humidity [%]

    #================================================
    # plotting MSE vertical profiles
    fig = plt.figure(figsize=[12, 8])
    ax = fig.add_axes([0.1, 0.1, 0.6, 0.8])
    ax.plot(sd, p, '-k', linewidth=2)
    ax.plot(sm1, p, '-b', linewidth=2)
    ax.plot(sm2, p, '-r', linewidth=2)

    # mse based on different percentages of relative humidity
    qr = np.zeros((9, np.size(qs))) * units('kilogram/kilogram')
    sm1_r = qr  # container
    for i in range(9):
        qr[i, :] = qs * 0.1 * (i + 1)
        sm1_r[i, :] = entropy(T.magnitude, qr[i, :].magnitude, p.magnitude)

    for i in range(9):
        ax.plot(sm1_r[i, :], p[:], '-', color='grey', linewidth=0.7)
        ax.text(sm1_r[i, 3].magnitude - 2, p[3].magnitude, str((i + 1) * 10))

    # drawing LCL and LFC levels
    [lcl_pressure, lcl_temperature] = mpcalc.lcl(p[0], T[0], Td[0])
    lcl_idx = np.argmin(np.abs(p.magnitude - lcl_pressure.magnitude))

    [lfc_pressure, lfc_temperature] = mpcalc.lfc(p, T, Td)
    lfc_idx = np.argmin(np.abs(p.magnitude - lfc_pressure.magnitude))

    # conserved mse of air parcel arising from 1000 hpa
    sm1_p = np.squeeze(np.ones((1, np.size(T))) * sm1[0])

    # illustration of CAPE
    el_pressure, el_temperature = mpcalc.el(p, T, Td)  # equilibrium level
    el_idx = np.argmin(np.abs(p.magnitude - el_pressure.magnitude))
    ELps = [el_pressure.magnitude
            ]  # Initialize an array of EL pressures for detrainment profile

    [CAPE, CIN] = mpcalc.cape_cin(p[:el_idx], T[:el_idx], Td[:el_idx],
                                  Tp[:el_idx])

    plt.plot(sm1_p, p, color='green', linewidth=2)
    #ax.fill_betweenx(p[lcl_idx:el_idx+1],sm1_p[lcl_idx:el_idx+1],sm2[lcl_idx:el_idx+1],interpolate=True
    #                ,color='green',alpha='0.3')

    ax.fill_betweenx(p, sd, sm1, color='deepskyblue', alpha='0.5')
    ax.set_xlabel('Specific entropies: sd, sm, sm_sat [J K$^{-1}$ kg$^{-1}$]',
                  fontsize=14)
    ax.set_ylabel('Pressure [hPa]', fontsize=14)
    ax.set_xticks([0, 50, 100, 150, 200, 250, 300, 350])
    ax.set_xlim([0, 440])
    ax.set_ylim(1030, 120)

    if entrain is True:
        # Depict Entraining parcels
        # Parcel mass solves dM/dz = eps*M, solution is M = exp(eps*Z)
        # M=1 at ground without loss of generality

        # Distribution of surface parcel h offsets
        h0offsets = np.sort(np.random.normal(
            0, h0_std, ensemble_size)) * units('joule/kilogram')
        # Distribution of entrainment rates
        entrainment_rates = ent_rate / (units('km'))

        for h0offset in h0offsets:

            h4ent = sm1.copy()
            h4ent[0] += h0offset

            for eps in entrainment_rates:

                M = np.exp(eps * (altitude - altitude[0])).to('dimensionless')
                # dM is the mass contribution at each level, with 1 at the origin level.
                M[0] = 0
                dM = np.gradient(M)
                # parcel mass is a sum of all the dM's at each level
                # conserved linearly-mixed variables like h are weighted averages
                if eps.magnitude == 0.0:
                    hent = np.ones(len(h4ent)) * h4ent[0]  # no mixing
                else:
                    hent = np.cumsum(dM * h4ent) / np.cumsum(dM)
                # Boolean for positive buoyancy, and its topmost altitude (index) where curve is clippes
                posboy = (hent > sm2)
                posboy[0] = True  # so there is always a detrainment level

                # defining the first EL by posboy as the detrainment layer, swiching from positive buoyancy to
                # negative buoyancy (0 to 1) and skipping the surface
                ELindex_ent = 0
                for idx in range(len(posboy) - 1):
                    if posboy[idx + 1] == 0 and posboy[idx] == 1 and idx > 0:
                        ELindex_ent = idx
                        break

                # Plot the curve
                plt.plot(hent[0:ELindex_ent + 2],
                         p[0:ELindex_ent + 2],
                         linewidth=0.6,
                         color='g')
                #plt.plot( hent[0:], p[0:], linewidth=0.6, color='g')
                # Keep a list for a histogram plot (detrainment profile)
                if p[ELindex_ent].magnitude < lfc_pressure.magnitude:  # buoyant parcels only
                    ELps.append(p[ELindex_ent].magnitude)

        # Plot a crude histogram of parcel detrainment levels
        NBINS = 20
        pbins = np.linspace(1000, 150,
                            num=NBINS)  # pbins for detrainment levels
        hist = np.zeros((len(pbins) - 1))
        for x in ELps:
            for i in range(len(pbins) - 1):
                if (x < pbins[i]) & (x >= pbins[i + 1]):
                    hist[i] += 1
                    break

        det_per = hist / sum(hist) * 100
        # percentages of detrainment ensumbles at levels

        ax2 = fig.add_axes([0.705, 0.1, 0.1, 0.8], facecolor=None)
        ax2.barh(pbins[1:],
                 det_per,
                 color='lightgrey',
                 edgecolor='k',
                 height=15 * (20 / NBINS))
        ax2.set_xlim([0, 100])
        ax2.set_xticks([0, 20, 40, 60, 80, 100])
        ax2.set_ylim([1030, 120])
        ax2.set_xlabel('Detrainment [%]')
        ax2.grid()
        ax2.set_zorder(2)

        ax.plot([400, 400], [1100, 0])
        ax.annotate('Detrainment', xy=(362, 320), color='dimgrey')
        ax.annotate('ensemble: ' + str(ensemble_size * len(entrainment_rates)),
                    xy=(364, 340),
                    color='dimgrey')
        ax.annotate('Detrainment', xy=(362, 380), color='dimgrey')
        ax.annotate(' scale: 0 - 2 km', xy=(365, 400), color='dimgrey')

        # Overplots on the mess: undilute parcel and CAPE, etc.
        ax.plot((1, 1) * sm1[0], (1, 0) * (p[0]), color='g', linewidth=2)

        # Replot the sounding on top of all that mess
        ax.plot(sm2, p, color='r', linewidth=1.5)
        ax.plot(sm1, p, color='b', linewidth=1.5)

        # label LCL and LCF
        ax.plot((sm2[lcl_idx] + (-2000, 2000) * units('joule/kilogram')),
                lcl_pressure + (0, 0) * units('mbar'),
                color='orange',
                linewidth=3)
        ax.plot((sm2[lfc_idx] + (-2000, 2000) * units('joule/kilogram')),
                lfc_pressure + (0, 0) * units('mbar'),
                color='magenta',
                linewidth=3)

    # Plot a crude histogram of parcel detrainment levels
    # Text parts
    ax.text(30, pressure[3], 'RH (%)', fontsize=11, color='k')
    ax.text(20,
            200,
            'CAPE = ' + str(np.around(CAPE.magnitude, decimals=2)) + ' [J/kg]',
            fontsize=12,
            color='green')
    ax.text(20,
            250,
            'CIN = ' + str(np.around(CIN.magnitude, decimals=2)) + ' [J/kg]',
            fontsize=12,
            color='green')
    ax.text(20,
            300,
            'LCL = ' + str(np.around(lcl_pressure.magnitude, decimals=2)) +
            ' [hpa]',
            fontsize=12,
            color='darkorange')
    ax.text(20,
            350,
            'LFC = ' + str(np.around(lfc_pressure.magnitude, decimals=2)) +
            ' [hpa]',
            fontsize=12,
            color='magenta')
    ax.text(20,
            400,
            'CWV = ' + str(np.around(cwv.magnitude, decimals=2)) + ' [mm]',
            fontsize=12,
            color='deepskyblue')
    ax.text(20,
            450,
            'CRH = ' + str(np.around(crh.magnitude, decimals=2)) + ' [%]',
            fontsize=12,
            color='blue')
    ax.legend(['DEnt', 'MEnt', 'SMEnt'], fontsize=12, loc=1)

    ax.set_zorder(3)

    return (ax)
Пример #12
0
def main():
    img_dir = Path("hail_plots/soundings/")

    if not img_dir.exists():
        img_dir.mkdir(parents=True)

    data_dir = Path("/HOME/huziy/skynet3_rech1/hail/soundings_from_erai/")

    # dates = [datetime(1991, 9, 7), datetime(1991, 9, 7, 6), datetime(1991, 9, 7, 12), datetime(1991, 9, 7, 18),
    #          datetime(1991, 9, 8, 0), datetime(1991, 9, 8, 18)]
    #
    # dates.extend([datetime(1991, 9, 6, 0), datetime(1991, 9, 6, 6), datetime(1991, 9, 6, 12), datetime(1991, 9, 6, 18)])
    #
    # dates = [datetime(1990, 7, 7), datetime(2010, 7, 12), datetime(1991, 9, 8, 0)]

    dates_s = """
- 07/09/1991 12:00
- 07/09/1991 18:00
- 08/09/1991 00:00
- 08/09/1991 06:00
- 08/09/1991 12:00
- 13/09/1991 12:00
- 13/09/1991 18:00
- 14/09/1991 00:00
- 14/09/1991 06:00
- 14/09/1991 12:00
    """

    dates = [
        datetime.strptime(line.strip()[1:].strip(), "%d/%m/%Y %H:%M")
        for line in dates_s.split("\n") if line.strip() != ""
    ]

    def __date_parser(s):
        return pd.datetime.strptime(s, '%Y-%m-%d %H:%M:%S')

    tt = pd.read_csv(data_dir.joinpath("TT.csv"),
                     index_col=0,
                     parse_dates=['Time'])
    uu = pd.read_csv(data_dir.joinpath("UU.csv"),
                     index_col=0,
                     parse_dates=['Time'])
    vv = pd.read_csv(data_dir.joinpath("VV.csv"),
                     index_col=0,
                     parse_dates=['Time'])
    hu = pd.read_csv(data_dir.joinpath("HU.csv"),
                     index_col=0,
                     parse_dates=['Time'])

    print(tt.head())
    print([c for c in tt])
    print(list(tt.columns.values))

    temp_perturbation_degc = 0

    for the_date in dates:

        p = np.array([float(c) for c in tt])

        fig = plt.figure(figsize=(9, 9))
        skew = SkewT(fig)

        skew.ax.set_ylim(1000, 100)
        skew.ax.set_xlim(-40, 60)

        tsel = tt.select(lambda d: d == the_date)
        usel = uu.select(lambda d: d == the_date)
        vsel = vv.select(lambda d: d == the_date)
        husel = hu.select(lambda d: d == the_date)

        tvals = tsel.values.mean(axis=0)
        uvals = usel.values.mean(axis=0) * mul_mpers_per_knot
        vvals = vsel.values.mean(axis=0) * mul_mpers_per_knot
        huvals = husel.values.mean(axis=0) * units("g/kg")

        # ignore the lowest level
        all_vars = [p, tvals, uvals, vvals, huvals]

        for i in range(len(all_vars)):
            all_vars[i] = all_vars[i][:-5]

        p, tvals, uvals, vvals, huvals = all_vars

        assert len(p) == len(huvals)

        tdvals = calc.dewpoint(
            calc.vapor_pressure(p * units.mbar, huvals).to(units.mbar))

        print(tvals, tdvals)
        # Calculate full parcel profile and add to plot as black line
        parcel_profile = calc.parcel_profile(
            p[::-1] * units.mbar,
            (tvals[-1] + temp_perturbation_degc) * units.degC,
            tdvals[-1]).to('degC')
        parcel_profile = parcel_profile[::-1]
        skew.plot(p, parcel_profile, 'k', linewidth=2)

        # Example of coloring area between profiles
        greater = tvals * units.degC >= parcel_profile
        skew.ax.fill_betweenx(p,
                              tvals,
                              parcel_profile,
                              where=greater,
                              facecolor='blue',
                              alpha=0.4)
        skew.ax.fill_betweenx(p,
                              tvals,
                              parcel_profile,
                              where=~greater,
                              facecolor='red',
                              alpha=0.4)

        skew.plot(p, tvals, "r")
        skew.plot(p, tdvals, "g")

        skew.plot_barbs(p, uvals, vvals)

        # Plot a zero degree isotherm
        l = skew.ax.axvline(0, color='c', linestyle='--', linewidth=2)

        # Add the relevant special lines
        skew.plot_dry_adiabats()
        skew.plot_moist_adiabats()
        skew.plot_mixing_lines()

        plt.title("{} (dT={})".format(the_date, temp_perturbation_degc))

        img_path = "{}_dT={}.png".format(the_date.strftime("%Y%m%d_%H%M%S"),
                                         temp_perturbation_degc)
        img_path = img_dir.joinpath(img_path)
        fig.savefig(str(img_path), bbox_inches="tight")

        plt.close(fig)
Пример #13
0
from metpy.vis import meteogram
from metpy.constants import C2F
from metpy.calc import dewpoint, windchill
from metpy.cbook import rec_append_fields

fields = ('stid', 'time', 'relh', 'tair', 'wspd', 'wmax', 'wdir', 'pres',
          'srad', 'rain')

data = read_mesonet_data('data/20080117nrmn.mts', fields, lookup_stids=False)

#Add a reasonable time range if we're doing current data
end = get_last_time(data)
times = (end - datetime.timedelta(hours=24), end)

#Calculate dewpoint in F from relative humidity and temperature
dewpt = C2F(dewpoint(data['TAIR'], data['RELH'] / 100.))
data = rec_append_fields(data, ('dewpoint', ), (dewpt, ))

#Convert temperature and dewpoint to Farenheit
mod_units = mesonet_units.copy()
mod_units['TAIR'] = 'F'
mod_units['dewpoint'] = 'F'
data['TAIR'] = C2F(data['TAIR'])

#Convert wind speeds to MPH
data['WSPD'] *= sconsts.hour / sconsts.mile
data['WMAX'] *= sconsts.hour / sconsts.mile
mod_units['WSPD'] = 'MPH'
mod_units['WMAX'] = 'MPH'

#Convert rainfall to inches
Пример #14
0
def main():
    img_dir = Path("hail_plots/soundings/")

    if not img_dir.exists():
        img_dir.mkdir(parents=True)


    data_dir = Path("/HOME/huziy/skynet3_rech1/hail/soundings_from_erai/")

    # dates = [datetime(1991, 9, 7), datetime(1991, 9, 7, 6), datetime(1991, 9, 7, 12), datetime(1991, 9, 7, 18),
    #          datetime(1991, 9, 8, 0), datetime(1991, 9, 8, 18)]
    #
    # dates.extend([datetime(1991, 9, 6, 0), datetime(1991, 9, 6, 6), datetime(1991, 9, 6, 12), datetime(1991, 9, 6, 18)])
    #
    # dates = [datetime(1990, 7, 7), datetime(2010, 7, 12), datetime(1991, 9, 8, 0)]



    dates_s = """
- 07/09/1991 12:00
- 07/09/1991 18:00
- 08/09/1991 00:00
- 08/09/1991 06:00
- 08/09/1991 12:00
- 13/09/1991 12:00
- 13/09/1991 18:00
- 14/09/1991 00:00
- 14/09/1991 06:00
- 14/09/1991 12:00
    """

    dates = [datetime.strptime(line.strip()[1:].strip(), "%d/%m/%Y %H:%M") for line in dates_s.split("\n") if line.strip() != ""]




    def __date_parser(s):
        return pd.datetime.strptime(s, '%Y-%m-%d %H:%M:%S')


    tt = pd.read_csv(data_dir.joinpath("TT.csv"), index_col=0, parse_dates=['Time'])
    uu = pd.read_csv(data_dir.joinpath("UU.csv"), index_col=0, parse_dates=['Time'])
    vv = pd.read_csv(data_dir.joinpath("VV.csv"), index_col=0, parse_dates=['Time'])
    hu = pd.read_csv(data_dir.joinpath("HU.csv"), index_col=0, parse_dates=['Time'])


    print(tt.head())
    print([c for c in tt])
    print(list(tt.columns.values))




    temp_perturbation_degc = 0

    for the_date in dates:

        p = np.array([float(c) for c in tt])

        fig = plt.figure(figsize=(9, 9))
        skew = SkewT(fig)

        skew.ax.set_ylim(1000, 100)
        skew.ax.set_xlim(-40, 60)


        tsel = tt.select(lambda d: d == the_date)
        usel = uu.select(lambda d: d == the_date)
        vsel = vv.select(lambda d: d == the_date)
        husel = hu.select(lambda d: d == the_date)


        tvals = tsel.values.mean(axis=0)
        uvals = usel.values.mean(axis=0) * mul_mpers_per_knot
        vvals = vsel.values.mean(axis=0) * mul_mpers_per_knot
        huvals = husel.values.mean(axis=0) * units("g/kg")


        # ignore the lowest level
        all_vars = [p, tvals, uvals, vvals, huvals]

        for i in range(len(all_vars)):
            all_vars[i] = all_vars[i][:-5]

        p, tvals, uvals, vvals, huvals = all_vars


        assert len(p) == len(huvals)

        tdvals = calc.dewpoint(calc.vapor_pressure(p * units.mbar, huvals).to(units.mbar))


        print(tvals, tdvals)
        # Calculate full parcel profile and add to plot as black line
        parcel_profile = calc.parcel_profile(p[::-1] * units.mbar, (tvals[-1] + temp_perturbation_degc) * units.degC, tdvals[-1]).to('degC')
        parcel_profile = parcel_profile[::-1]
        skew.plot(p, parcel_profile, 'k', linewidth=2)



        # Example of coloring area between profiles
        greater = tvals * units.degC >= parcel_profile
        skew.ax.fill_betweenx(p, tvals, parcel_profile, where=greater, facecolor='blue', alpha=0.4)
        skew.ax.fill_betweenx(p, tvals, parcel_profile, where=~greater, facecolor='red', alpha=0.4)



        skew.plot(p, tvals, "r")
        skew.plot(p, tdvals, "g")

        skew.plot_barbs(p, uvals, vvals)

        # Plot a zero degree isotherm
        l = skew.ax.axvline(0, color='c', linestyle='--', linewidth=2)


        # Add the relevant special lines
        skew.plot_dry_adiabats()
        skew.plot_moist_adiabats()
        skew.plot_mixing_lines()

        plt.title("{} (dT={})".format(the_date, temp_perturbation_degc))

        img_path = "{}_dT={}.png".format(the_date.strftime("%Y%m%d_%H%M%S"), temp_perturbation_degc)
        img_path = img_dir.joinpath(img_path)
        fig.savefig(str(img_path), bbox_inches="tight")

        plt.close(fig)
Пример #15
0
mixing = 10 * units('g/kg')
print(mixing)

###########################################
# Now throw that value with units into the function to calculate
# the corresponding vapor pressure, given a surface pressure of 1000 mb
e = mcalc.vapor_pressure(1000. * units.mbar, mixing)
print(e)

###########################################
# Take the odd units and force them to millibars
print(e.to(units.mbar))

###########################################
# Take the raw vapor pressure and throw into the dewpoint function
td = mcalc.dewpoint(e)
print(td)

###########################################
# Which can of course be converted to Fahrenheit
print(td.to('degF'))

###########################################
# Now do the same thing for 850 mb, approximately the pressure of Denver
e = mcalc.vapor_pressure(850. * units.mbar, mixing)
print(e.to(units.mbar))

###########################################
# And print the corresponding dewpoint
td = mcalc.dewpoint(e)
print(td, td.to('degF'))
Пример #16
0
def plotter(fdict):
    """ Go """
    pgconn = get_dbconn('asos')
    ctx = get_autoplot_context(fdict, get_description())
    station = ctx['zstation']
    network = ctx['network']
    month = ctx['month']

    nt = NetworkTable(network)

    if month == 'all':
        months = range(1, 13)
    elif month == 'fall':
        months = [9, 10, 11]
    elif month == 'winter':
        months = [12, 1, 2]
    elif month == 'spring':
        months = [3, 4, 5]
    elif month == 'summer':
        months = [6, 7, 8]
    else:
        ts = datetime.datetime.strptime("2000-"+month+"-01", '%Y-%b-%d')
        # make sure it is length two for the trick below in SQL
        months = [ts.month, 999]

    df = read_sql("""
        SELECT tmpf::int as tmpf, dwpf,
        coalesce(mslp, alti * 33.8639, 1013.25) as slp
        from alldata where station = %s
        and drct is not null and dwpf is not null and dwpf <= tmpf
        and sknt > 3 and drct::int %% 10 = 0
        and extract(month from valid) in %s
        and report_type = 2
    """, pgconn, params=(station, tuple(months)))
    # Convert sea level pressure to station pressure
    df['pressure'] = mcalc.add_height_to_pressure(
        df['slp'].values * units('millibars'),
        nt.sts[station]['elevation'] * units('m')
    ).to(units('millibar'))
    # compute RH
    df['relh'] = mcalc.relative_humidity_from_dewpoint(
        df['tmpf'].values * units('degF'),
        df['dwpf'].values * units('degF')
    )
    # compute mixing ratio
    df['mixingratio'] = mcalc.mixing_ratio_from_relative_humidity(
        df['relh'].values,
        df['tmpf'].values * units('degF'),
        df['pressure'].values * units('millibars')
    )
    # compute pressure
    df['vapor_pressure'] = mcalc.vapor_pressure(
        df['pressure'].values * units('millibars'),
        df['mixingratio'].values * units('kg/kg')
    ).to(units('kPa'))

    means = df.groupby('tmpf').mean().copy()
    # compute dewpoint now
    means['dwpf'] = mcalc.dewpoint(
        means['vapor_pressure'].values * units('kPa')
    ).to(units('degF')).m
    means.reset_index(inplace=True)
    # compute RH again
    means['relh'] = mcalc.relative_humidity_from_dewpoint(
        means['tmpf'].values * units('degF'),
        means['dwpf'].values * units('degF')
    ) * 100.

    (fig, ax) = plt.subplots(1, 1, figsize=(8, 6))
    ax.bar(
        means['tmpf'].values - 0.5, means['dwpf'].values - 0.5,
        ec='green', fc='green', width=1
    )
    ax.grid(True, zorder=11)
    ax.set_title(("%s [%s]\nAverage Dew Point by Air Temperature (month=%s) "
                  "(%s-%s)\n"
                  "(must have 3+ hourly observations at the given temperature)"
                  ) % (nt.sts[station]['name'], station, month.upper(),
                       nt.sts[station]['archive_begin'].year,
                       datetime.datetime.now().year), size=10)

    ax.plot([0, 140], [0, 140], color='b')
    ax.set_ylabel("Dew Point [F]")
    y2 = ax.twinx()
    y2.plot(means['tmpf'].values, means['relh'].values, color='k')
    y2.set_ylabel("Relative Humidity [%] (black line)")
    y2.set_yticks([0, 5, 10, 25, 50, 75, 90, 95, 100])
    y2.set_ylim(0, 100)
    ax.set_ylim(0, means['tmpf'].max() + 2)
    ax.set_xlim(0, means['tmpf'].max() + 2)
    ax.set_xlabel(r"Air Temperature $^\circ$F")

    return fig, means[['tmpf', 'dwpf', 'relh']]
Пример #17
0
def plotter(fdict):
    """ Go """
    pgconn = get_dbconn('asos')
    ctx = get_autoplot_context(fdict, get_description())

    station = ctx['zstation']
    network = ctx['network']
    month = ctx['month']

    nt = NetworkTable(network)

    if month == 'all':
        months = range(1, 13)
    elif month == 'fall':
        months = [9, 10, 11]
    elif month == 'winter':
        months = [12, 1, 2]
    elif month == 'spring':
        months = [3, 4, 5]
    elif month == 'summer':
        months = [6, 7, 8]
    else:
        ts = datetime.datetime.strptime("2000-" + month + "-01", '%Y-%b-%d')
        # make sure it is length two for the trick below in SQL
        months = [ts.month, 999]

    df = read_sql("""
        SELECT drct::int as t, dwpf, tmpf, relh,
        coalesce(mslp, alti * 33.8639, 1013.25) as slp
        from alldata where station = %s
        and drct is not null and dwpf is not null and dwpf <= tmpf
        and sknt > 3 and drct::int %% 10 = 0
        and extract(month from valid) in %s
        and report_type = 2
    """,
                  pgconn,
                  params=(station, tuple(months)))
    # Convert sea level pressure to station pressure
    df['pressure'] = mcalc.add_height_to_pressure(
        df['slp'].values * units('millibars'),
        nt.sts[station]['elevation'] * units('m')).to(units('millibar'))
    # compute mixing ratio
    df['mixingratio'] = mcalc.mixing_ratio_from_relative_humidity(
        df['relh'].values * units('percent'),
        df['tmpf'].values * units('degF'),
        df['pressure'].values * units('millibars'))
    # compute pressure
    df['vapor_pressure'] = mcalc.vapor_pressure(
        df['pressure'].values * units('millibars'),
        df['mixingratio'].values * units('kg/kg')).to(units('kPa'))

    means = df.groupby('t').mean().copy()
    # compute dewpoint now
    means['dwpf'] = mcalc.dewpoint(means['vapor_pressure'].values *
                                   units('kPa')).to(units('degF')).m

    (fig, ax) = plt.subplots(1, 1)
    ax.bar(means.index.values,
           means['dwpf'].values,
           ec='green',
           fc='green',
           width=10,
           align='center')
    ax.grid(True, zorder=11)
    ax.set_title(("%s [%s]\nAverage Dew Point by Wind Direction (month=%s) "
                  "(%s-%s)\n"
                  "(must have 3+ hourly obs > 3 knots at given direction)") %
                 (nt.sts[station]['name'], station, month.upper(),
                  max([1973, nt.sts[station]['archive_begin'].year
                       ]), datetime.datetime.now().year),
                 size=10)

    ax.set_ylabel("Dew Point [F]")
    ax.set_ylim(means['dwpf'].min() - 5, means['dwpf'].max() + 5)
    ax.set_xlim(-5, 365)
    ax.set_xticks([0, 45, 90, 135, 180, 225, 270, 315, 360])
    ax.set_xticklabels(['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'N'])
    ax.set_xlabel("Wind Direction")

    return fig, means['dwpf']
Пример #18
0
def plotter(fdict):
    """ Go """
    pgconn = get_dbconn("asos")
    ctx = get_autoplot_context(fdict, get_description())

    station = ctx["zstation"]
    month = ctx["month"]

    if month == "all":
        months = range(1, 13)
    elif month == "fall":
        months = [9, 10, 11]
    elif month == "winter":
        months = [12, 1, 2]
    elif month == "spring":
        months = [3, 4, 5]
    elif month == "summer":
        months = [6, 7, 8]
    else:
        ts = datetime.datetime.strptime("2000-" + month + "-01", "%Y-%b-%d")
        # make sure it is length two for the trick below in SQL
        months = [ts.month, 999]

    df = read_sql(
        """
        SELECT drct::int as t, dwpf, tmpf, relh,
        coalesce(mslp, alti * 33.8639, 1013.25) as slp
        from alldata where station = %s
        and drct is not null and dwpf is not null and dwpf <= tmpf
        and sknt > 3 and drct::int %% 10 = 0
        and extract(month from valid) in %s
        and report_type = 2
    """,
        pgconn,
        params=(station, tuple(months)),
    )
    if df.empty:
        raise NoDataFound("No Data Found.")
    # Convert sea level pressure to station pressure
    df["pressure"] = mcalc.add_height_to_pressure(
        df["slp"].values * units("millibars"),
        ctx["_nt"].sts[station]["elevation"] * units("m"),
    ).to(units("millibar"))
    # compute mixing ratio
    df["mixingratio"] = mcalc.mixing_ratio_from_relative_humidity(
        df["relh"].values * units("percent"),
        df["tmpf"].values * units("degF"),
        df["pressure"].values * units("millibars"),
    )
    # compute pressure
    df["vapor_pressure"] = mcalc.vapor_pressure(
        df["pressure"].values * units("millibars"),
        df["mixingratio"].values * units("kg/kg"),
    ).to(units("kPa"))

    means = df.groupby("t").mean().copy()
    # compute dewpoint now
    means["dwpf"] = (mcalc.dewpoint(means["vapor_pressure"].values *
                                    units("kPa")).to(units("degF")).m)

    (fig, ax) = plt.subplots(1, 1)
    ax.bar(
        means.index.values,
        means["dwpf"].values,
        ec="green",
        fc="green",
        width=10,
        align="center",
    )
    ax.grid(True, zorder=11)
    ab = ctx["_nt"].sts[station]["archive_begin"]
    if ab is None:
        raise NoDataFound("Unknown station metadata.")
    ax.set_title(
        ("%s [%s]\nAverage Dew Point by Wind Direction (month=%s) "
         "(%s-%s)\n"
         "(must have 3+ hourly obs > 3 knots at given direction)") % (
             ctx["_nt"].sts[station]["name"],
             station,
             month.upper(),
             max([1973, ab.year]),
             datetime.datetime.now().year,
         ),
        size=10,
    )

    ax.set_ylabel("Dew Point [F]")
    ax.set_ylim(means["dwpf"].min() - 5, means["dwpf"].max() + 5)
    ax.set_xlim(-5, 365)
    ax.set_xticks([0, 45, 90, 135, 180, 225, 270, 315, 360])
    ax.set_xticklabels(["N", "NE", "E", "SE", "S", "SW", "W", "NW", "N"])
    ax.set_xlabel("Wind Direction")

    return fig, means["dwpf"]
Пример #19
0
def dewpoint_from_relative_humidity(temperature, relative_humidity):
    """Similar to `metpy.calc.dewpoint_from_relative_humidity`, but without
    a check for values greater than 120%"""
    return mpcalc.dewpoint(relative_humidity *
                           mpcalc.saturation_vapor_pressure(temperature))
Пример #20
0
def msed_plots(pressure,
               temperature,
               mixing_ratio,
               h0_std=2000,
               ensemble_size=20,
               ent_rate=np.arange(0, 2, 0.05),
               entrain=False):
    """
    plotting the summarized static energy diagram with annotations and thermodynamic parameters
    """
    p = pressure * units('mbar')
    T = temperature * units('degC')
    q = mixing_ratio * units('kilogram/kilogram')
    qs = mpcalc.mixing_ratio(mpcalc.saturation_vapor_pressure(T), p)
    Td = mpcalc.dewpoint(mpcalc.vapor_pressure(p, q))  # dewpoint
    Tp = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC')  # parcel profile

    # Altitude based on the hydrostatic eq.
    altitude = np.zeros((np.size(T))) * units('meter')  # surface is 0 meter
    for i in range(np.size(T)):
        altitude[i] = mpcalc.thickness_hydrostatic(
            p[:i + 1], T[:i + 1])  # Hypsometric Eq. for height

    # Static energy calculations
    mse = mpcalc.moist_static_energy(altitude, T, q)
    mse_s = mpcalc.moist_static_energy(altitude, T, qs)
    dse = mpcalc.dry_static_energy(altitude, T)

    # Water vapor calculations
    p_PWtop = max(200 * units.mbar,
                  min(p) + 1 * units.mbar)  # integrating until 200mb
    cwv = mpcalc.precipitable_water(Td, p,
                                    top=p_PWtop)  # column water vapor [mm]
    cwvs = mpcalc.precipitable_water(
        T, p, top=p_PWtop)  # saturated column water vapor [mm]
    crh = (cwv / cwvs) * 100.  # column relative humidity [%]

    #================================================
    # plotting MSE vertical profiles
    fig = plt.figure(figsize=[12, 8])
    ax = fig.add_axes([0.1, 0.1, 0.6, 0.8])
    ax.plot(dse, p, '-k', linewidth=2)
    ax.plot(mse, p, '-b', linewidth=2)
    ax.plot(mse_s, p, '-r', linewidth=2)

    # mse based on different percentages of relative humidity
    qr = np.zeros((9, np.size(qs))) * units('kilogram/kilogram')
    mse_r = qr * units('joule/kilogram')  # container
    for i in range(9):
        qr[i, :] = qs * 0.1 * (i + 1)
        mse_r[i, :] = mpcalc.moist_static_energy(altitude, T, qr[i, :])

    for i in range(9):
        ax.plot(mse_r[i, :], p[:], '-', color='grey', linewidth=0.7)
        ax.text(mse_r[i, 3].magnitude / 1000 - 1, p[3].magnitude,
                str((i + 1) * 10))

    # drawing LCL and LFC levels
    [lcl_pressure, lcl_temperature] = mpcalc.lcl(p[0], T[0], Td[0])
    lcl_idx = np.argmin(np.abs(p.magnitude - lcl_pressure.magnitude))

    [lfc_pressure, lfc_temperature] = mpcalc.lfc(p, T, Td)
    lfc_idx = np.argmin(np.abs(p.magnitude - lfc_pressure.magnitude))

    # conserved mse of air parcel arising from 1000 hpa
    mse_p = np.squeeze(np.ones((1, np.size(T))) * mse[0].magnitude)

    # illustration of CAPE
    el_pressure, el_temperature = mpcalc.el(p, T, Td)  # equilibrium level
    el_idx = np.argmin(np.abs(p.magnitude - el_pressure.magnitude))
    ELps = [el_pressure.magnitude
            ]  # Initialize an array of EL pressures for detrainment profile

    [CAPE, CIN] = mpcalc.cape_cin(p[:el_idx], T[:el_idx], Td[:el_idx],
                                  Tp[:el_idx])

    plt.plot(mse_p, p, color='green', linewidth=2)
    ax.fill_betweenx(p[lcl_idx:el_idx + 1],
                     mse_p[lcl_idx:el_idx + 1],
                     mse_s[lcl_idx:el_idx + 1],
                     interpolate=True,
                     color='green',
                     alpha='0.3')

    ax.fill_betweenx(p, dse, mse, color='deepskyblue', alpha='0.5')
    ax.set_xlabel('Specific static energies: s, h, hs [kJ kg$^{-1}$]',
                  fontsize=14)
    ax.set_ylabel('Pressure [hpa]', fontsize=14)
    ax.set_xticks([280, 300, 320, 340, 360, 380])
    ax.set_xlim([280, 390])
    ax.set_ylim(1030, 120)

    if entrain is True:
        # Depict Entraining parcels
        # Parcel mass solves dM/dz = eps*M, solution is M = exp(eps*Z)
        # M=1 at ground without loss of generality

        # Distribution of surface parcel h offsets
        H0STDEV = h0_std  # J/kg
        h0offsets = np.sort(np.random.normal(
            0, H0STDEV, ensemble_size)) * units('joule/kilogram')
        # Distribution of entrainment rates
        entrainment_rates = ent_rate / (units('km'))

        for h0offset in h0offsets:

            h4ent = mse.copy()
            h4ent[0] += h0offset

            for eps in entrainment_rates:

                M = np.exp(eps * (altitude - altitude[0])).to('dimensionless')
                # dM is the mass contribution at each level, with 1 at the origin level.
                M[0] = 0
                dM = np.gradient(M)

                # parcel mass is a  sum of all the dM's at each level
                # conserved linearly-mixed variables like h are weighted averages
                hent = np.cumsum(dM * h4ent) / np.cumsum(dM)

                # Boolean for positive buoyancy, and its topmost altitude (index) where curve is clippes
                posboy = (hent > mse_s)
                posboy[0] = True  # so there is always a detrainment level

                ELindex_ent = np.max(np.where(posboy))
                # Plot the curve
                plt.plot(hent[0:ELindex_ent + 2],
                         p[0:ELindex_ent + 2],
                         linewidth=0.25,
                         color='g')
                # Keep a list for a histogram plot (detrainment profile)
                if p[ELindex_ent].magnitude < lfc_pressure.magnitude:  # buoyant parcels only
                    ELps.append(p[ELindex_ent].magnitude)

        # Plot a crude histogram of parcel detrainment levels
        NBINS = 20
        pbins = np.linspace(1000, 150,
                            num=NBINS)  # pbins for detrainment levels
        hist = np.zeros((len(pbins) - 1))
        for x in ELps:
            for i in range(len(pbins) - 1):
                if (x < pbins[i]) & (x >= pbins[i + 1]):
                    hist[i] += 1
                    break

        det_per = hist / sum(hist) * 100
        # percentages of detrainment ensumbles at levels

        ax2 = fig.add_axes([0.705, 0.1, 0.1, 0.8], facecolor=None)
        ax2.barh(pbins[1:],
                 det_per,
                 color='lightgrey',
                 edgecolor='k',
                 height=15 * (20 / NBINS))
        ax2.set_xlim([0, max(det_per)])
        ax2.set_ylim([1030, 120])
        ax2.set_xlabel('Detrainment [%]')
        ax2.grid()
        ax2.set_zorder(2)

        ax.plot([400, 400], [1100, 0])
        ax.annotate('Detrainment', xy=(362, 320), color='dimgrey')
        ax.annotate('ensemble: ' + str(ensemble_size * len(entrainment_rates)),
                    xy=(364, 340),
                    color='dimgrey')
        ax.annotate('Detrainment', xy=(362, 380), color='dimgrey')
        ax.annotate(' scale: 0 - 2 km', xy=(365, 400), color='dimgrey')

        # Overplots on the mess: undilute parcel and CAPE, etc.
        ax.plot((1, 1) * mse[0], (1, 0) * (p[0]), color='g', linewidth=2)

        # Replot the sounding on top of all that mess
        ax.plot(mse_s, p, color='r', linewidth=1.5)
        ax.plot(mse, p, color='b', linewidth=1.5)

        # label LCL and LCF
        ax.plot((mse_s[lcl_idx] + (-2000, 2000) * units('joule/kilogram')),
                lcl_pressure + (0, 0) * units('mbar'),
                color='orange',
                linewidth=3)
        ax.plot((mse_s[lfc_idx] + (-2000, 2000) * units('joule/kilogram')),
                lfc_pressure + (0, 0) * units('mbar'),
                color='magenta',
                linewidth=3)

    ### Internal waves (100m adiabatic displacements, assumed adiabatic: conserves s, sv, h).
    #dZ = 100 *mpunits.units.meter
    dp = 1000 * units.pascal

    # depict displacements at sounding levels nearest these target levels
    targetlevels = [900, 800, 700, 600, 500, 400, 300, 200] * units.hPa
    for ilev in targetlevels:
        idx = np.argmin(np.abs(p - ilev))

        # dp: hydrostatic
        rho = (p[idx]) / Rd / (T[idx])
        dZ = -dp / rho / g

        # dT: Dry lapse rate dT/dz_dry is -g/Cp
        dT = (-g / Cp_d * dZ).to('kelvin')
        Tdisp = T[idx].to('kelvin') + dT

        # dhsat
        dqs = mpcalc.mixing_ratio(mpcalc.saturation_vapor_pressure(Tdisp),
                                  p[idx] + dp) - qs[idx]
        dhs = g * dZ + Cp_d * dT + Lv * dqs

        # Whiskers on the data plots
        ax.plot((mse_s[idx] + dhs * (-1, 1)),
                p[idx] + dp * (-1, 1),
                linewidth=3,
                color='r')
        ax.plot((dse[idx] * (1, 1)),
                p[idx] + dp * (-1, 1),
                linewidth=3,
                color='k')
        ax.plot((mse[idx] * (1, 1)),
                p[idx] + dp * (-1, 1),
                linewidth=3,
                color='b')

        # annotation to explain it
        if ilev == 400 * ilev.units:
            ax.plot(360 * mse_s.units + dhs * (-1, 1) / 1000,
                    440 * units('mbar') + dp * (-1, 1),
                    linewidth=3,
                    color='r')
            ax.annotate('+/- 10mb', xy=(362, 440), fontsize=8)
            ax.annotate(' adiabatic displacement', xy=(362, 460), fontsize=8)

    # Plot a crude histogram of parcel detrainment levels
    # Text parts
    ax.text(290, pressure[3], 'RH (%)', fontsize=11, color='k')
    ax.text(285,
            200,
            'CAPE = ' + str(np.around(CAPE.magnitude, decimals=2)) + ' [J/kg]',
            fontsize=12,
            color='green')
    ax.text(285,
            250,
            'CIN = ' + str(np.around(CIN.magnitude, decimals=2)) + ' [J/kg]',
            fontsize=12,
            color='green')
    ax.text(285,
            300,
            'LCL = ' + str(np.around(lcl_pressure.magnitude, decimals=2)) +
            ' [hpa]',
            fontsize=12,
            color='darkorange')
    ax.text(285,
            350,
            'LFC = ' + str(np.around(lfc_pressure.magnitude, decimals=2)) +
            ' [hpa]',
            fontsize=12,
            color='magenta')
    ax.text(285,
            400,
            'CWV = ' + str(np.around(cwv.magnitude, decimals=2)) + ' [mm]',
            fontsize=12,
            color='deepskyblue')
    ax.text(285,
            450,
            'CRH = ' + str(np.around(crh.magnitude, decimals=2)) + ' [%]',
            fontsize=12,
            color='blue')
    ax.legend(['DSE', 'MSE', 'SMSE'], fontsize=12, loc=1)

    ax.set_zorder(3)

    return (ax)
Пример #21
0
def plotter(fdict):
    """ Go """
    pgconn = get_dbconn("asos")
    ctx = get_autoplot_context(fdict, get_description())
    station = ctx["zstation"]
    month = ctx["month"]

    if month == "all":
        months = range(1, 13)
    elif month == "fall":
        months = [9, 10, 11]
    elif month == "winter":
        months = [12, 1, 2]
    elif month == "spring":
        months = [3, 4, 5]
    elif month == "summer":
        months = [6, 7, 8]
    else:
        ts = datetime.datetime.strptime("2000-" + month + "-01", "%Y-%b-%d")
        # make sure it is length two for the trick below in SQL
        months = [ts.month, 999]

    df = read_sql(
        """
        SELECT tmpf::int as tmpf, dwpf, relh,
        coalesce(mslp, alti * 33.8639, 1013.25) as slp
        from alldata where station = %s
        and drct is not null and dwpf is not null and dwpf <= tmpf
        and sknt > 3 and drct::int %% 10 = 0
        and extract(month from valid) in %s
        and report_type = 2
    """,
        pgconn,
        params=(station, tuple(months)),
    )
    if df.empty:
        raise NoDataFound("No Data Found.")
    # Convert sea level pressure to station pressure
    df["pressure"] = mcalc.add_height_to_pressure(
        df["slp"].values * units("millibars"),
        ctx["_nt"].sts[station]["elevation"] * units("m"),
    ).to(units("millibar"))
    # compute mixing ratio
    df["mixingratio"] = mcalc.mixing_ratio_from_relative_humidity(
        df["relh"].values * units("percent"),
        df["tmpf"].values * units("degF"),
        df["pressure"].values * units("millibars"),
    )
    # compute pressure
    df["vapor_pressure"] = mcalc.vapor_pressure(
        df["pressure"].values * units("millibars"),
        df["mixingratio"].values * units("kg/kg"),
    ).to(units("kPa"))

    means = df.groupby("tmpf").mean().copy()
    # compute dewpoint now
    means["dwpf"] = (
        mcalc.dewpoint(means["vapor_pressure"].values * units("kPa"))
        .to(units("degF"))
        .m
    )
    means.reset_index(inplace=True)
    # compute RH again
    means["relh"] = (
        mcalc.relative_humidity_from_dewpoint(
            means["tmpf"].values * units("degF"),
            means["dwpf"].values * units("degF"),
        )
        * 100.0
    )

    (fig, ax) = plt.subplots(1, 1, figsize=(8, 6))
    ax.bar(
        means["tmpf"].values - 0.5,
        means["dwpf"].values - 0.5,
        ec="green",
        fc="green",
        width=1,
    )
    ax.grid(True, zorder=11)
    ab = ctx["_nt"].sts[station]["archive_begin"]
    if ab is None:
        raise NoDataFound("Unknown station metadata.")
    ax.set_title(
        (
            "%s [%s]\nAverage Dew Point by Air Temperature (month=%s) "
            "(%s-%s)\n"
            "(must have 3+ hourly observations at the given temperature)"
        )
        % (
            ctx["_nt"].sts[station]["name"],
            station,
            month.upper(),
            ab.year,
            datetime.datetime.now().year,
        ),
        size=10,
    )

    ax.plot([0, 140], [0, 140], color="b")
    ax.set_ylabel("Dew Point [F]")
    y2 = ax.twinx()
    y2.plot(means["tmpf"].values, means["relh"].values, color="k")
    y2.set_ylabel("Relative Humidity [%] (black line)")
    y2.set_yticks([0, 5, 10, 25, 50, 75, 90, 95, 100])
    y2.set_ylim(0, 100)
    ax.set_ylim(0, means["tmpf"].max() + 2)
    ax.set_xlim(0, means["tmpf"].max() + 2)
    ax.set_xlabel(r"Air Temperature $^\circ$F")

    return fig, means[["tmpf", "dwpf", "relh"]]
Пример #22
0
def test_dewpoint():
    """Test dewpoint calculation."""
    assert_almost_equal(dewpoint(6.112 * units.mbar), 0. * units.degC, 2)
Пример #23
0
def test_dewpoint():
    """Test dewpoint calculation."""
    assert_almost_equal(dewpoint(6.112 * units.mbar), 0. * units.degC, 2)
T_NUCAPS = NUCAPS_data.Temperature.values - 273.15
T_NUCAPS = pd.DataFrame({
    'temperature_degC':
    np.reshape(T_NUCAPS, (T_NUCAPS.shape[0] * T_NUCAPS.shape[1]))
})
T_NUCAPS_1 = (NUCAPS_data.Temperature.values - 273.15) * units.degC

H2O_MR = np.reshape(NUCAPS_data['H2O_MR'].values,
                    (T_NUCAPS.shape[0] * T_NUCAPS.shape[1])) * units('g/kg')
H2O_MR_1 = NUCAPS_data['H2O_MR'].values
H2O_MR = pd.DataFrame({'mixing_ratio': H2O_MR})

p_NUCAPS_2 = NUCAPS_data.Pressure.values * units.hPa
WVMR = (H2O_MR_1 * 1000) * units('g/kg')
e_1 = mpcalc.vapor_pressure(p_NUCAPS_2, WVMR)
T_d = mpcalc.dewpoint(e_1)
T_d_NUCAPS = pd.DataFrame({
    'dew_point_degC':
    np.reshape(T_d, (T_NUCAPS.shape[0] * T_NUCAPS.shape[1]))
})

datetime_NUCAPS = NUCAPS_data.datetime.values
datetime_NUCAPS = pd.DataFrame(
    {'time_YMDHMS_1': (np.repeat(datetime_NUCAPS, 100))})

# round datime to next RS time (0000 or 1200)
datetime_NUCAPS_round = pd.DataFrame(
    datetime_NUCAPS.time_YMDHMS_1.dt.ceil('60 min').values,
    columns=['time_YMDHMS'])
datetime_NUCAPS_round.time_YMDHMS[
    datetime_NUCAPS_round.time_YMDHMS.dt.hour ==
Пример #25
0
print('Time length: ', len(time))

# From dimension to variable.
press = np.zeros_like(temp)
for cnt in range(temp.shape[0]):
    press[cnt, :] = lev

pressure = press * units.hPa
temperature = temp * units.K
mixing_ratio = wvmr * units('kg/kg')

# get dew point
relative_humidity = mpcalc.relative_humidity_from_mixing_ratio(
    mixing_ratio, temperature, pressure)
e = mpcalc.vapor_pressure(pressure, mixing_ratio)
dew_point = mpcalc.dewpoint(e)


def get_cape(inargs, return_parcel_profile=False):
    pres_prof, temp_prof, dp_prof = inargs
    try:
        prof = mpcalc.parcel_profile(pres_prof, temp_prof[0], dp_prof[0])
        cape, cin = mpcalc.cape_cin(pres_prof, temp_prof, dp_prof, prof)
    except Exception:
        cape, cin, prof = np.NaN, np.NaN, np.NaN
        print('Problem during CAPE-calculation. Likely NaN-related.')
    if return_parcel_profile:
        return cape, cin, prof
    else:
        return cape, cin
Пример #26
0
mixing = 10 * units('g/kg')
print(mixing)

###########################################
# Now throw that value with units into the function to calculate
# the corresponding vapor pressure, given a surface pressure of 1000 mb
e = mpcalc.vapor_pressure(1000. * units.mbar, mixing)
print(e)

###########################################
# Take the odd units and force them to millibars
print(e.to(units.mbar))

###########################################
# Take the raw vapor pressure and throw into the dewpoint function
td = mpcalc.dewpoint(e)
print(td)

###########################################
# Which can of course be converted to Fahrenheit
print(td.to('degF'))

###########################################
# Now do the same thing for 850 mb, approximately the pressure of Denver
e = mpcalc.vapor_pressure(850. * units.mbar, mixing)
print(e.to(units.mbar))

###########################################
# And print the corresponding dewpoint
td = mpcalc.dewpoint(e)
print(td, td.to('degF'))
Пример #27
0
from metpy.vis import meteogram
from metpy.constants import C2F
from metpy.calc import dewpoint, windchill
from metpy.cbook import rec_append_fields

fields = ('stid', 'time', 'relh', 'tair', 'wspd', 'wmax', 'wdir', 'pres',
    'srad', 'rain')

data = read_mesonet_data('data/20080117nrmn.mts', fields, lookup_stids=False)

#Add a reasonable time range if we're doing current data
end = get_last_time(data)
times = (end - datetime.timedelta(hours=24), end)

#Calculate dewpoint in F from relative humidity and temperature
dewpt = C2F(dewpoint(data['TAIR'], data['RELH']/100.))
data = rec_append_fields(data, ('dewpoint',), (dewpt,))

#Convert temperature and dewpoint to Farenheit
mod_units = mesonet_units.copy()
mod_units['TAIR'] = 'F'
mod_units['dewpoint'] = 'F'
data['TAIR'] = C2F(data['TAIR'])

#Convert wind speeds to MPH
data['WSPD'] *= sconsts.hour / sconsts.mile
data['WMAX'] *= sconsts.hour / sconsts.mile
mod_units['WSPD'] = 'MPH'
mod_units['WMAX'] = 'MPH'

#Convert rainfall to inches
Пример #28
0
mixing = 10 * units('g/kg')
print(mixing)

###########################################
# Now throw that value with units into the function to calculate
# the corresponding vapor pressure, given a surface pressure of 1000 mb
e = mpcalc.vapor_pressure(1000. * units.mbar, mixing)
print(e)

###########################################
# Take the odd units and force them to millibars
print(e.to(units.mbar))

###########################################
# Take the raw vapor pressure and throw into the dewpoint function
td = mpcalc.dewpoint(e)
print(td)

###########################################
# Which can of course be converted to Fahrenheit
print(td.to('degF'))

###########################################
# Now do the same thing for 850 mb, approximately the pressure of Denver
e = mpcalc.vapor_pressure(850. * units.mbar, mixing)
print(e.to(units.mbar))

###########################################
# And print the corresponding dewpoint
td = mpcalc.dewpoint(e)
print(td, td.to('degF'))