Esempio n. 1
0
def test_parcel_profile_saturated():
    """Test parcel_profile works when LCL in levels (issue #232)."""
    levels = np.array([1000., 700., 500.]) * units.mbar
    true_prof = np.array([296.95, 284.381, 271.123]) * units.kelvin

    prof = parcel_profile(levels, 23.8 * units.degC, 23.8 * units.degC)
    assert_array_almost_equal(prof, true_prof, 2)
Esempio n. 2
0
    def calculate_basic_thermo(self):

        #Enclose in try, except because not every sounding will have a converging parcel path or CAPE.
        try:

            #Precipitable Water
            self.pw = mc.precipitable_water(self.sounding["pres"],
                                            self.sounding["dewp"])

            #Lifting condensation level
            self.lcl_pres, self.lcl_temp = mc.lcl(self.sounding["pres"][0],
                                                  self.sounding["temp"][0],
                                                  self.sounding["dewp"][0])

            #Surface-based CAPE and CIN
            self.parcel_path = mc.parcel_profile(self.sounding["pres"],
                                                 self.sounding["temp"][0],
                                                 self.sounding["dewp"][0])
            self.sfc_cape, self.sfc_cin = mc.cape_cin(self.sounding["pres"],
                                                      self.sounding["temp"],
                                                      self.sounding["dewp"],
                                                      self.parcel_path)

        #Do this when parcel path fails to converge
        except Exception as e:
            print("WARNING: No LCL, CAPE, or PW stats because:\n{}.".format(e))
            self.parcel_path = numpy.nan
            self.pw = numpy.nan
            self.lcl_pres = numpy.nan
            self.lcl_temp = numpy.nan
            self.sfc_cape = numpy.nan
            self.sfc_cin = numpy.nan

        #Returning
        return
Esempio n. 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')
Esempio n. 4
0
def test_parcel_profile_saturated():
    """Test parcel_profile works when LCL in levels (issue #232)."""
    levels = np.array([1000., 700., 500.]) * units.mbar
    true_prof = np.array([296.95, 284.381, 271.123]) * units.kelvin

    prof = parcel_profile(levels, 23.8 * units.degC, 23.8 * units.degC)
    assert_array_almost_equal(prof, true_prof, 2)
Esempio n. 5
0
    def _plot_profile(self, skew):

        profiles = self.atmo_profiles  # dictionary
        pres = profiles.get('pres').get('data')
        temp = profiles.get('temp').get('data')
        sphum = profiles.get('sphum').get('data')

        dewpt = mpcalc.dewpoint_from_specific_humidity(sphum, temp,
                                                       pres).to('degF')

        # Pressure vs temperature
        skew.plot(pres, temp, 'r', linewidth=1.5)

        # Pressure vs dew point temperature
        skew.plot(pres, dewpt, 'blue', linewidth=1.5)

        # Compute parcel profile and plot it
        parcel_profile = mpcalc.parcel_profile(pres, temp[0],
                                               dewpt[0]).to('degC')
        skew.plot(
            pres,
            parcel_profile,
            'orange',
            linestyle='dashed',
            linewidth=1.2,
        )
Esempio n. 6
0
def test_parcel_profile():
    """Test parcel profile calculation."""
    levels = np.array([1000., 900., 800., 700., 600., 500., 400.]) * units.mbar
    true_prof = np.array([303.15, 294.16, 288.026, 283.073, 277.058, 269.402,
                          258.966]) * units.kelvin

    prof = parcel_profile(levels, 30. * units.degC, 20. * units.degC)
    assert_array_almost_equal(prof, true_prof, 2)
Esempio n. 7
0
def test_parcel_profile():
    """Test parcel profile calculation."""
    levels = np.array([1000., 900., 800., 700., 600., 500., 400.]) * units.mbar
    true_prof = np.array([303.15, 294.16, 288.026, 283.073, 277.058, 269.402,
                          258.966]) * units.kelvin

    prof = parcel_profile(levels, 30. * units.degC, 20. * units.degC)
    assert_array_almost_equal(prof, true_prof, 2)
Esempio n. 8
0
def plot_sounding(date, station):
    p, T, Td, u, v, windspeed = get_sounding_data(date, station)

    lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0])
    lfc_pressure, lfc_temperature = mpcalc.lfc(p, T, Td)
    parcel_path = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC')

    # Create a new figure. The dimensions here give a good aspect ratio
    fig = plt.figure(figsize=(8, 8))
    skew = SkewT(fig)

    # Plot the data
    temperature_line, = skew.plot(p, T, color='tab:red')
    dewpoint_line, = skew.plot(p, Td, color='blue')
    cursor = mplcursors.cursor([temperature_line, dewpoint_line])

    # Plot thermodynamic parameters and parcel path
    skew.plot(p, parcel_path, color='black')

    if lcl_pressure:
        skew.ax.axhline(lcl_pressure, color='black')

    if lfc_pressure:
        skew.ax.axhline(lfc_pressure, color='0.7')

    # Add the relevant special lines
    skew.ax.axvline(0, color='c', linestyle='--', linewidth=2)
    skew.plot_dry_adiabats()
    skew.plot_moist_adiabats()
    skew.plot_mixing_lines()

    # Shade areas representing CAPE and CIN
    skew.shade_cin(p, T, parcel_path)
    skew.shade_cape(p, T, parcel_path)

    # Add wind barbs
    skew.plot_barbs(p, u, v)

    # Add an axes to the plot
    ax_hod = inset_axes(skew.ax, '30%', '30%', loc=1, borderpad=3)

    # Plot the hodograph
    h = Hodograph(ax_hod, component_range=100.)

    # Grid the hodograph
    h.add_grid(increment=20)

    # Plot the data on the hodograph
    mask = (p >= 100 * units.mbar)
    h.plot_colormapped(u[mask], v[mask],
                       windspeed[mask])  # Plot a line colored by wind speed

    # Set some sensible axis limits
    skew.ax.set_ylim(1000, 100)
    skew.ax.set_xlim(-40, 60)

    return fig, skew
Esempio n. 9
0
def test_cape_cin_no_lfc():
    """Test that CAPE is zero with no LFC."""
    p = np.array([959., 779.2, 751.3, 724.3, 700., 269.]) * units.mbar
    temperature = np.array([22.2, 24.6, 22., 20.4, 18., -10.]) * units.celsius
    dewpoint = np.array([19., -11.2, -10.8, -10.4, -10., -53.2]) * units.celsius
    parcel_prof = parcel_profile(p, temperature[0], dewpoint[0]).to('degC')
    cape, cin = cape_cin(p, temperature, dewpoint, parcel_prof)
    assert_almost_equal(cape, 0.0 * units('joule / kilogram'), 6)
    assert_almost_equal(cin, 0.0 * units('joule / kilogram'), 6)
Esempio n. 10
0
def test_cape_cin_no_el():
    """Test that CAPE works with no EL."""
    p = np.array([959., 779.2, 751.3, 724.3]) * units.mbar
    temperature = np.array([22.2, 14.6, 12., 9.4]) * units.celsius
    dewpoint = np.array([19., -11.2, -10.8, -10.4]) * units.celsius
    parcel_prof = parcel_profile(p, temperature[0], dewpoint[0]).to('degC')
    cape, cin = cape_cin(p, temperature, dewpoint, parcel_prof)
    assert_almost_equal(cape, 0.08750805 * units('joule / kilogram'), 6)
    assert_almost_equal(cin, -89.8073512 * units('joule / kilogram'), 6)
Esempio n. 11
0
def test_cape_cin():
    """Test the basic CAPE and CIN calculation."""
    p = np.array([959., 779.2, 751.3, 724.3, 700., 269.]) * units.mbar
    temperature = np.array([22.2, 14.6, 12., 9.4, 7., -38.]) * units.celsius
    dewpoint = np.array([19., -11.2, -10.8, -10.4, -10., -53.2]) * units.celsius
    parcel_prof = parcel_profile(p, temperature[0], dewpoint[0])
    cape, cin = cape_cin(p, temperature, dewpoint, parcel_prof)
    assert_almost_equal(cape, 58.0368212 * units('joule / kilogram'), 6)
    assert_almost_equal(cin, -89.8073512 * units('joule / kilogram'), 6)
Esempio n. 12
0
def test_cape_cin_no_el():
    """Tests that CAPE works with no EL."""
    p = np.array([959., 779.2, 751.3, 724.3]) * units.mbar
    temperature = np.array([22.2, 14.6, 12., 9.4]) * units.celsius
    dewpoint = np.array([19., -11.2, -10.8, -10.4]) * units.celsius
    parcel_prof = parcel_profile(p, temperature[0], dewpoint[0]).to('degC')
    cape, cin = cape_cin(p, temperature, dewpoint, parcel_prof)
    assert_almost_equal(cape, 0.08750805 * units('joule / kilogram'), 6)
    assert_almost_equal(cin, -89.8073512 * units('joule / kilogram'), 6)
Esempio n. 13
0
def test_cape_cin():
    """Tests the basic CAPE and CIN calculation."""
    p = np.array([959., 779.2, 751.3, 724.3, 700., 269.]) * units.mbar
    temperature = np.array([22.2, 14.6, 12., 9.4, 7., -38.]) * units.celsius
    dewpoint = np.array([19., -11.2, -10.8, -10.4, -10., -53.2]) * units.celsius
    parcel_prof = parcel_profile(p, temperature[0], dewpoint[0])
    cape, cin = cape_cin(p, temperature, dewpoint, parcel_prof)
    assert_almost_equal(cape, 58.0368212 * units('joule / kilogram'), 6)
    assert_almost_equal(cin, -89.8073512 * units('joule / kilogram'), 6)
Esempio n. 14
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)
Esempio n. 15
0
def test_cape_cin_custom_profile():
    """Test the CAPE and CIN calculation with a custom profile passed to LFC and EL."""
    p = np.array([959., 779.2, 751.3, 724.3, 700., 269.]) * units.mbar
    temperature = np.array([22.2, 14.6, 12., 9.4, 7., -38.]) * units.celsius
    dewpoint = np.array([19., -11.2, -10.8, -10.4, -10., -53.2]) * units.celsius
    parcel_prof = parcel_profile(p, temperature[0], dewpoint[0]) + 5 * units.delta_degC
    cape, cin = cape_cin(p, temperature, dewpoint, parcel_prof)
    assert_almost_equal(cape, 1443.505086499895 * units('joule / kilogram'), 6)
    assert_almost_equal(cin, 0.0 * units('joule / kilogram'), 6)
Esempio n. 16
0
def test_cape_cin_no_lfc():
    """Tests that CAPE is zero with no LFC."""
    p = np.array([959., 779.2, 751.3, 724.3, 700., 269.]) * units.mbar
    temperature = np.array([22.2, 24.6, 22., 20.4, 18., -10.]) * units.celsius
    dewpoint = np.array([19., -11.2, -10.8, -10.4, -10., -53.2]) * units.celsius
    parcel_prof = parcel_profile(p, temperature[0], dewpoint[0]).to('degC')
    cape, cin = cape_cin(p, temperature, dewpoint, parcel_prof)
    assert_almost_equal(cape, 0.0 * units('joule / kilogram'), 6)
    assert_almost_equal(cin, 0.0 * units('joule / kilogram'), 6)
Esempio n. 17
0
def plot_sounding(date, station):
    p, T, Td, u, v, windspeed = get_sounding_data(date, station)

    lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0])
    lfc_pressure, lfc_temperature = mpcalc.lfc(p, T, Td)
    parcel_path = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC')

    # Create a new figure. The dimensions here give a good aspect ratio
    fig = plt.figure(figsize=(8, 8))
    skew = SkewT(fig)

    # Plot the data
    temperature_line, = skew.plot(p, T, color='tab:red')
    dewpoint_line, = skew.plot(p, Td, color='blue')
    cursor = mplcursors.cursor([temperature_line, dewpoint_line])

    # Plot thermodynamic parameters and parcel path
    skew.plot(p, parcel_path, color='black')

    if lcl_pressure:
        skew.ax.axhline(lcl_pressure, color='black')

    if lfc_pressure:
        skew.ax.axhline(lfc_pressure, color='0.7')

    # Add the relevant special lines
    skew.ax.axvline(0, color='c', linestyle='--', linewidth=2)
    skew.plot_dry_adiabats()
    skew.plot_moist_adiabats()
    skew.plot_mixing_lines()

    # Shade areas representing CAPE and CIN
    skew.shade_cin(p, T, parcel_path)
    skew.shade_cape(p, T, parcel_path)

    # Add wind barbs
    skew.plot_barbs(p, u, v)

    # Add an axes to the plot
    ax_hod = inset_axes(skew.ax, '30%', '30%', loc=1, borderpad=3)

    # Plot the hodograph
    h = Hodograph(ax_hod, component_range=100.)

    # Grid the hodograph
    h.add_grid(increment=20)

    # Plot the data on the hodograph
    mask = (p >= 100 * units.mbar)
    h.plot_colormapped(u[mask], v[mask], windspeed[mask])  # Plot a line colored by wind speed

    # Set some sensible axis limits
    skew.ax.set_ylim(1000, 100)
    skew.ax.set_xlim(-40, 60)

    return fig, skew
Esempio n. 18
0
def test_el_ml():
    """Test equilibrium layer calculation for a mixed parcel."""
    levels = np.array([959., 779.2, 751.3, 724.3, 700., 400., 269.]) * units.mbar
    temperatures = np.array([22.2, 14.6, 12., 9.4, 7., -25., -35.]) * units.celsius
    dewpoints = np.array([19., -11.2, -10.8, -10.4, -10., -35., -53.2]) * units.celsius
    __, t_mixed, td_mixed = mixed_parcel(levels, temperatures, dewpoints)
    mixed_parcel_prof = parcel_profile(levels, t_mixed, td_mixed)
    el_pressure, el_temperature = el(levels, temperatures, dewpoints, mixed_parcel_prof)
    assert_almost_equal(el_pressure, 355.834 * units.mbar, 3)
    assert_almost_equal(el_temperature, -28.371 * units.degC, 3)
Esempio n. 19
0
def test_lfc_ml():
    """Test Mixed-Layer LFC calculation."""
    levels = np.array([959., 779.2, 751.3, 724.3, 700., 269.]) * units.mbar
    temperatures = np.array([22.2, 14.6, 12., 9.4, 7., -49.]) * units.celsius
    dewpoints = np.array([19., -11.2, -10.8, -10.4, -10., -53.2]) * units.celsius
    __, t_mixed, td_mixed = mixed_parcel(levels, temperatures, dewpoints)
    mixed_parcel_prof = parcel_profile(levels, t_mixed, td_mixed)
    lfc_pressure, lfc_temp = lfc(levels, temperatures, dewpoints, mixed_parcel_prof)
    assert_almost_equal(lfc_pressure, 631.794 * units.mbar, 2)
    assert_almost_equal(lfc_temp, -1.862 * units.degC, 2)
Esempio n. 20
0
def plot_skewt_icon(sounding, parcel=None, base=1000, top=100, skew=45):
    model_time = np.datetime_as_string(sounding.metadata.model_time, unit='m')
    valid_time = np.datetime_as_string(sounding.metadata.valid_time, unit='m')

    top_idx = find_closest_model_level(sounding.p * units.Pa, top * units("hPa"))

    fig = plt.figure(figsize=(11, 11), constrained_layout=True)
    skew = SkewT(fig, rotation=skew)

    skew.plot(sounding.p * units.Pa, sounding.T * units.K, 'r')
    skew.plot(sounding.p * units.Pa, sounding.Td, 'b')
    skew.plot_barbs(sounding.p[:top_idx] * units.Pa, sounding.U[:top_idx] * units.mps,
                    sounding.V[:top_idx] * units.mps, plot_units=units.knot, alpha=0.6, xloc=1.13, x_clip_radius=0.3)

    if parcel == "surface-based":
        prof = mpcalc.parcel_profile(sounding.p * units.Pa, sounding.T[0] * units.K, sounding.Td[0]).to('degC')
        skew.plot(sounding.p * units.Pa, prof, 'y', linewidth=2)

    # Add the relevant special lines
    skew.plot_dry_adiabats()
    skew.plot_moist_adiabats()
    skew.plot_mixing_lines()
    skew.plot(sounding.p * units.Pa, np.zeros(len(sounding.p)) * units.degC, "#03d3fc", linewidth=1)
    skew.ax.set_ylim(base, top)

    plt.title(f"Model run: {model_time}Z", loc='left')
    plt.title(f"Valid time: {valid_time}Z", fontweight='bold', loc='right')
    plt.xlabel("Temperature [°C]")
    plt.ylabel("Pressure [hPa]")

    fig.suptitle(f"ICON-EU Model for {sounding.latitude_pretty}, {sounding.longitude_pretty}", fontsize=14)

    ax1 = plt.gca()
    ax2 = ax1.twinx()  # instantiate a second axes that shares the same x-axis

    color = '#333333'
    ax2.set_ylabel('Geometric Altitude [kft]', color=color)  # we already handled the x-label with ax1
    ax2_data = (sounding.p * units.Pa).to('hPa')
    ax2.plot(np.zeros(len(ax2_data)), ax2_data, color=color, alpha=0.0)
    ax2.tick_params(axis='y', labelcolor=color)
    ax2.set_yscale('log')
    ax2.set_ylim((base, top))
    ticks = np.linspace(base, top, num=10)

    ideal_ticks = np.geomspace(base, top, 20)
    real_tick_idxs = [find_closest_model_level(sounding.p * units.Pa, p_level * units("hPa")) for p_level in
                      ideal_ticks]
    ticks = (sounding.p * units.Pa).to("hPa")[real_tick_idxs]
    full_levels = [full_level_height(sounding.HHL, idx) for idx in real_tick_idxs]
    tick_labels = np.around((full_levels * units.m).m_as("kft"), decimals=1)
    ax2.set_yticks(ticks)
    ax2.set_yticklabels(tick_labels)
    ax2.minorticks_off()

    return fig
Esempio n. 21
0
def test_parcel_profile_below_lcl():
    """Test parcel profile calculation when pressures do not reach LCL (#827)."""
    pressure = np.array([981, 949.2, 925., 913.9, 903, 879.4, 878, 864, 855,
                         850, 846.3, 838, 820, 814.5, 799, 794]) * units.hPa
    truth = np.array([276.35, 273.76110242, 271.74910213, 270.81364639,
                      269.88711359, 267.85332225, 267.73145436, 266.5050728,
                      265.70916946, 265.264412, 264.93408677, 264.18931638,
                      262.55585912, 262.0516423, 260.61745662,
                      260.15057861]) * units.kelvin
    profile = parcel_profile(pressure, 3.2 * units.degC, -10.8 * units.degC)
    assert_almost_equal(profile, truth, 6)
Esempio n. 22
0
def make_skewt():
    # Get the data
    date = request.args.get('date')
    time = request.args.get('time')
    region = request.args.get('region')
    station = request.args.get('station')
    date = datetime.strptime(date, '%Y%m%d')
    date = datetime(date.year, date.month, date.day, int(time))
    df = get_sounding_data(date, region, station)
    p = df['pressure'].values * units(df.units['pressure'])
    T = df['temperature'].values * units(df.units['temperature'])
    Td = df['dewpoint'].values * units(df.units['dewpoint'])
    u = df['u_wind'].values * units(df.units['u_wind'])
    v = df['v_wind'].values * units(df.units['v_wind'])

    # Make the Skew-T
    fig = plt.figure(figsize=(9, 9))
    add_metpy_logo(fig, 115, 100)
    skew = SkewT(fig, rotation=45)

    # Plot the data using normal plotting functions, in this case using
    # log scaling in Y, as dictated by the typical meteorological plot
    skew.plot(p, T, 'tab:red')
    skew.plot(p, Td, 'tab:green')
    skew.plot_barbs(p, u, v)
    skew.ax.set_ylim(1000, 100)
    skew.ax.set_xlim(-40, 60)

    # Calculate LCL height and plot as black dot
    lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0])
    skew.plot(lcl_pressure, lcl_temperature, 'ko', markerfacecolor='black')

    # Calculate full parcel profile and add to plot as black line
    prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC')
    skew.plot(p, prof, 'k', linewidth=2)

    # Shade areas of CAPE and CIN
    skew.shade_cin(p, T, prof)
    skew.shade_cape(p, T, prof)

    # An example of a slanted line at constant T -- in this case the 0
    # isotherm
    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()

    canvas = FigureCanvas(fig)
    img = BytesIO()
    fig.savefig(img)
    img.seek(0)
    return send_file(img, mimetype='image/png')
def calcMLCAPE(levels, temperature, dewpoint, depth=100.0 * units.hPa):
    _, T_parc, Td_par = mixed_parcel(
        levels,
        temperature,
        dewpoint,
        depth=depth,
        interpolate=False,
    )
    profile = parcel_profile(levels, T_parc, Td_parc)
    cape, cin = cape_cin(levels, temperature, dewpoint, profile)
    return cape
Esempio n. 24
0
def thermo_plots(pressure, temperature, mixing_ratio):
    """"
    plots for vertical profiles of temperature, dewpoint, mixing ratio and relative humidity.
    
    Parameters
    ----------
    pressure : array-like
            Atmospheric pressure profile (surface to TOA)
    temperature: array-like
            Atmospheric temperature profile (surface to TOA)
    dewpoint: array-like
            Atmospheric dewpoint profile (surface to TOA)    
    Returns
    -------
    """
    p = pressure * units('mbar')
    q = mixing_ratio * units('kilogram/kilogram')
    T = temperature * units('degC')

    Td = mpcalc.dewpoint_from_specific_humidity(q, T, p)  # dewpoint
    Tp = mpcalc.parcel_profile(p, T[0], Td[0])  # parcel

    plt.figure(figsize=(12, 5))

    lev = find_nearest(p.magnitude, 100)
    plt.subplot(1, 3, 1)
    plt.plot(T[:lev], p[:lev], '-ob')
    plt.plot(Td[:lev], p[:lev], '-og')
    plt.plot(Tp[:lev], p[:lev], '-or')
    plt.xlabel('Temperature [C]', fontsize=12)
    plt.ylabel('Pressure [hpa]', fontsize=12)
    plt.gca().invert_yaxis()
    plt.legend(['Temp', 'Temp_Dew', 'Temp_Parcel'], loc=1)
    plt.grid()

    qs = mpcalc.mixing_ratio(mpcalc.saturation_vapor_pressure(T), p)
    # Relative humidity
    RH = q / qs * 100  # Relative humidity

    plt.subplot(1, 3, 2)
    plt.plot(q[:lev], p[:lev], '-og')
    plt.xlabel('Mixing ratio [kg/kg]', fontsize=12)
    plt.gca().invert_yaxis()
    plt.grid()

    plt.subplot(1, 3, 3)
    plt.plot(RH[:lev], p[:lev], '-og')
    plt.xlabel('Relative humiduty [%]', fontsize=12)
    plt.gca().invert_yaxis()
    plt.grid()

    plt.tight_layout()
    return (plt)
Esempio n. 25
0
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
Esempio n. 26
0
    def plot_skewt(self, station_data):
        """
        :param adjusted_data: receives the post processed dataframe
        :param valid:
        :return:
        """

        # We will pull the data out of the example dataset into individual variables
        # and assign units.

        p = station_data['pressure'].values * units.hPa
        T = station_data['Temperature_isobaric'].values * units.degC
        Td = station_data['Dewpoint'].replace(np.nan,
                                              0.0000001).values * units.degC
        u = station_data['u-component_of_wind_isobaric'].values * \
            units('meters / second').to('knots')
        v = station_data['v-component_of_wind_isobaric'].values * \
            units('meters / second').to('knots')

        # Create a new figure. The dimensions here give a good aspect ratio.
        fig = plt.figure(figsize=(12, 9))
        skew = SkewT(fig, rotation=45)

        # Plot the data using normal plotting functions, in this case using
        # log scaling in Y, as dictated by the typical meteorological plot
        skew.plot(p, T, 'r')
        skew.plot(p, Td, 'g')
        skew.plot_barbs(p, u, v)
        skew.ax.set_ylim(1020, 100)
        skew.ax.set_xlim(-40, 60)

        # Calculate LCL height and plot as black dot
        lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0])
        skew.plot(lcl_pressure, lcl_temperature, 'ko', markerfacecolor='black')

        # Calculate full parcel profile and add to plot as black line
        prof = mpcalc.parcel_profile(p, T[0], Td[0])
        skew.plot(p, prof, 'k', linewidth=2)

        # An example of a slanted line at constant T -- in this case the 0
        # isotherm
        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()

        skew.shade_cape(p, T, prof)
        skew.shade_cin(p, T, prof)

        return skew
Esempio n. 27
0
def core(p, T, Td, u, v, **kwargs):

    # Calculate the LCL
    lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0])

    #print('LCL p, t:', int(lcl_pressure), int(lcl_temperature))

    # Calculate the parcel profile.
    parcel_prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC')

    # Create a new figure. The dimensions here give a good aspect ratio
    fig = plt.figure(figsize=(8, 8))
    skew = SkewT(fig, rotation=45)

    # Plot the data using normal plotting functions, in this case using
    # log scaling in Y, as dictated by the typical meteorological plot
    #skew.plot(p, T, 'k-')
    skew.plot(p, T, 'r.-', ms=5, lw=2, label='mean T')
    skew.plot(p, Td, 'g.-', ms=5, lw=2, label='mean Td')
    skew.plot_barbs(p, u, v)
    skew.ax.set_ylim(1000, 180)
    skew.ax.set_xlim(-20, 40)

    # Plot LCL temperature as black dot
    skew.plot(lcl_pressure, lcl_temperature, 'k.', markerfacecolor='black')

    # Plot the parcel profile as a black line
    skew.plot(p, parcel_prof, 'k', linewidth=2)

    # Shade areas of CAPE and CIN
    skew.shade_cin(p, T, parcel_prof)
    skew.shade_cape(p, T, parcel_prof)

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

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

    # Show the plot
    #plt.show()
    #skew.ax.set_title(time_str)
    plt.legend(loc='lower left')
    plt.title(kwargs.get('title'))
    fname = kwargs.get('saveto', 'profile.png')
    fig.savefig(fname)
    print(fname, 'saved.')
    plt.close()
Esempio n. 28
0
def plot_skewt(df):
    # We will pull the data out of the example dataset into individual variables
    # and assign units.
    hght = df['height'].values * units.hPa
    p = df['pressure'].values * units.hPa
    T = df['temperature'].values * units.degC
    Td = df['dewpoint'].values * units.degC
    wind_speed = df['speed'].values * units.knots
    wind_dir = df['direction'].values * units.degrees
    u, v = mpcalc.wind_components(wind_speed, wind_dir)

    # Create a new figure. The dimensions here give a good aspect ratio.
    fig = plt.figure(figsize=(9, 12))
    skew = SkewT(fig, rotation=45)

    # Plot the data using normal plotting functions, in this case using
    # log scaling in Y, as dictated by the typical meteorological plot
    skew.plot(p, T, 'r')
    skew.plot(p, Td, 'g')
    skew.plot_barbs(p, u, v)
    skew.ax.set_ylim(1000, 100)
    skew.ax.set_xlim(-40, 60)

    # Calculate LCL height and plot as black dot
    lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0])
    skew.plot(lcl_pressure, lcl_temperature, 'ko', markerfacecolor='black')

    # Calculate full parcel profile and add to plot as black line
    prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC')
    skew.plot(p, prof, 'k', linewidth=2)

    # An example of a slanted line at constant T -- in this case the 0
    # isotherm
    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()

    # Create a hodograph
    ax_hod = inset_axes(skew.ax, '40%', '40%', loc=2)
    h = Hodograph(ax_hod, component_range=80.)
    h.add_grid(increment=20)
    h.plot_colormapped(u, v, hght)

    return skew
Esempio n. 29
0
def plot_skewt(p, t, td, puv=None, u=None, v=None, title=None, outfile=None):

    # Create a new figure. The dimensions here give a good aspect ratio
    fig = plt.figure(figsize=(9, 9))
    skew = SkewT(fig, rotation=30)

    # Plot the data using normal plotting functions, in this case using
    # log scaling in Y, as dictated by the typical meteorological plot
    skew.plot(p, t, 'r', linewidth=2)
    skew.plot(p, td, 'g', linewidth=2)
    if u is not None and v is not None:
        skew.plot_barbs(puv, u, v)

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

    # Calculate the LCL
    lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], t[0], td[0])

    # Calculate the parcel profile.
    parcel_prof = mpcalc.parcel_profile(p, t[0], td[0]).to('degC')

    # Plot LCL temperature as black dot
    skew.plot(lcl_pressure, lcl_temperature, 'ko', markerfacecolor='black')

    # Plot the parcel profile as a black line
    skew.plot(p, parcel_prof, 'k--', linewidth=1)

    # Shade areas of CAPE and CIN
    skew.shade_cin(p, t, parcel_prof)
    skew.shade_cape(p, t, parcel_prof)

    # Plot a zero degree isotherm
    #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()

    if title is not None:
        plt.title(title)

    # Show the plot
    #plt.show()
    if outfile is None: outfile = 'skewt.png'
    fig.savefig(outfile, format='png')
    def getData(self, time, model_vars, mdl2stnd, previous_data=None):
        '''
    Name:
      awips_model_base
    Purpose:
      A function to get data from NAM40 model to create HDWX products
    Inputs:
      request    : A DataAccessLayer request object
      time       : List of datatime(s) for data to grab
      model_vars : Dictionary with variables/levels to get
      mdl2stnd   : Dictionary to convert from model variable names
                    to standardized names
    Outputs:
      Returns a dictionary containing all data
    Keywords:
      previous_data : Dictionary with data from previous time step
    '''
        log = logging.getLogger(__name__)
        # Set up function for logger
        initTime, fcstTime = get_init_fcst_times(time[0])
        data = {
            'model': self._request.getLocationNames()[0],
            'initTime': initTime,
            'fcstTime': fcstTime
        }
        # Initialize empty dictionary

        log.info('Attempting to download {} data'.format(data['model']))

        for var in model_vars:  # Iterate over variables in the vars list
            log.debug('Getting: {}'.format(var))
            self._request.setParameters(*model_vars[var]['parameters'])
            # Set parameters for the download request
            self._request.setLevels(*model_vars[var]['levels'])
            # Set levels for the download request

            response = DAL.getGridData(self._request, time)  # Request the data

            for res in response:  # Iterate over all data request responses
                varName = res.getParameter()
                # Get name of the variable in the response
                varLvl = res.getLevel()
                # Get level of the variable in the response
                varName = mdl2stnd[varName]
                # Convert variable name to local standarized name
                if varName not in data:
                    data[varName] = {}
                    # If variable name NOT in data dictionary, initialize new dictionary under key
                data[varName][varLvl] = res.getRawData()
                # Add data under level name
                try:  # Try to
                    unit = units(res.getUnit())
                    # Get units and convert to MetPy units
                except:  # On exception
                    unit = '?'
                    # Set units to ?
                else:  # If get units success
                    data[varName][varLvl] *= unit
                    # Get data and create MetPy quantity by multiplying by units

                log.debug(
                    'Got data for:\n  Var:  {}\n  Lvl:  {}\n  Unit: {}'.format(
                        varName, varLvl, unit))
        data['lon'], data['lat'] = res.getLatLonCoords()
        # Get latitude and longitude values
        data['lon'] *= units('degree')
        # Add units of degree to longitude
        data['lat'] *= units('degree')
        # Add units of degree to latitude

        # Absolute vorticity
        dx, dy = lat_lon_grid_deltas(data['lon'], data['lat'])
        # Get grid spacing in x and y
        uTag = mdl2stnd[model_vars['wind']['parameters'][0]]
        # Get initial tag name for u-wind
        vTag = mdl2stnd[model_vars['wind']['parameters'][1]]
        # Get initial tag name for v-wind
        if (uTag in data) and (
                vTag in data):  # If both tags are in the data structure
            data['abs_vort'] = {}
            # Add absolute vorticity key
            for lvl in model_vars['wind'][
                    'levels']:  # Iterate over all leves in the wind data
                if (lvl in data[uTag]) and (
                        lvl in data[vTag]
                ):  # If given level in both u- and v-wind dictionaries
                    log.debug('Computing absolute vorticity at {}'.format(lvl))
                    data['abs_vort'][ lvl ] = \
                      absolute_vorticity( data[uTag][lvl], data[vTag][lvl],
                                          dx, dy, data['lat'] )
                    # Compute absolute vorticity

        # 1000 MB equivalent potential temperature
        if ('temperature' in data) and (
                'dewpoint'
                in data):  # If temperature AND depoint data were downloaded
            data['theta_e'] = {}
            T, Td = 'temperature', 'dewpoint'
            if ('1000.0MB' in data[T]) and (
                    '1000.0MB' in data[Td]
            ):  # If temperature AND depoint data were downloaded
                log.debug(
                    'Computing equivalent potential temperature at 1000 hPa')
                data['theta_e']['1000.0MB'] = equivalent_potential_temperature(
                    1000.0 * units('hPa'), data[T]['1000.0MB'],
                    data[Td]['1000.0MB'])

            return data
            # MLCAPE
            log.debug('Computing mixed layer CAPE')
            T_lvl = list(data[T].keys())
            Td_lvl = list(data[Td].keys())
            levels = list(set(T_lvl).intersection(Td_lvl))
            levels = [float(lvl.replace('MB', '')) for lvl in levels]
            levels = sorted(levels, reverse=True)

            nLvl = len(levels)
            if nLvl > 0:
                log.debug(
                    'Found {} matching levels in temperature and dewpoint data'
                    .format(nLvl))
                nLat, nLon = data['lon'].shape

                data['MLCAPE'] = np.zeros((
                    nLat,
                    nLon,
                ), dtype=np.float32) * units('J/kg')
                TT = np.zeros((
                    nLvl,
                    nLat,
                    nLon,
                ), dtype=np.float32) * units('degC')
                TTd = np.zeros((
                    nLvl,
                    nLat,
                    nLon,
                ), dtype=np.float32) * units('degC')

                log.debug('Sorting temperature and dewpoint data by level')
                for i in range(nLvl):
                    key = '{:.1f}MB'.format(levels[i])
                    TT[i, :, :] = data[T][key].to('degC')
                    TTd[i, :, :] = data[Td][key].to('degC')

                levels = np.array(levels) * units.hPa
                depth = 100.0 * units.hPa

                log.debug('Iterating over grid boxes to compute MLCAPE')
                for j in range(nLat):
                    for i in range(nLon):
                        try:
                            _, T_parc, Td_parc = mixed_parcel(
                                levels,
                                TT[:, j, i],
                                TTd[:, j, i],
                                depth=depth,
                                interpolate=False,
                            )
                            profile = parcel_profile(levels, T_parc, Td_parc)
                            cape, cin = cape_cin(levels, TT[:, j, i],
                                                 TTd[:, j, i], profile)
                        except:
                            log.warning(
                                'Failed to compute MLCAPE for lon/lat: {}; {}'.
                                format(data['lon'][j, i], data['lat'][j, i]))
                        else:
                            data['MLCAPE'][j, i] = cape
        return data
Esempio n. 31
0
skew.plot_dry_adiabats()
skew.plot_moist_adiabats()
skew.plot_mixing_lines()

plt.show()

# Calculate LCL height and plot as black dot\n",
from metpy.calc import lcl, dry_lapse
from metpy.units import units, concatenate
l = lcl(p[0], T[0], Td[0])     # we can calculate the lcl level from the starting p, T, Td
lcl_temp = dry_lapse(concatenate((p[0], l)), T[0])[-1].to('degC')  # Temperature of the lcl using the dry lapse
skew.plot(l, lcl_temp, 'ko', markerfacecolor='black') # plot the lcl level on the temperature with a black circle (ko) filled

# Calculate full parcel profile and add to plot as black line\n",
from metpy.calc import parcel_profile
prof = parcel_profile(p, T[0], Td[0]).to('degC')
skew.plot(p, prof, 'k', linewidth=2)

# Example of coloring area between profiles
skew.ax.fill_betweenx(p, T, prof, where=T>= prof, facecolor='blue', alpha=0.4)
skew.ax.fill_betweenx(p, T, prof, where=T< prof, facecolor='red', alpha=0.4)

# # An example of a slanted line at constant T -- in this case the 0 isotherm
level = skew.ax.axvline(0, color='c', linestyle='--', linewidth=2)   # highligh the 0 degree isoterm

from metpy.plots import Hodograpgh
fig, ax = plt.subplot(1, 1)
hodo = Hodograph(ax)
hodo.plot(u,v)
hodo.add_grid()
# Often times we will want to calculate some thermodynamic parameters of a
# sounding. The MetPy calc module has many such calculations already implemented!
#
# * **Lifting Condensation Level (LCL)** - The level at which an air parcel's
#   relative humidity becomes 100% when lifted along a dry adiabatic path.
# * **Parcel Path** - Path followed by a hypothetical parcel of air, beginning
#   at the surface temperature/pressure and rising dry adiabatically until
#   reaching the LCL, then rising moist adiabatically.

# Calculate the LCL
lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0])

print(lcl_pressure, lcl_temperature)

# Calculate the parcel profile.
parcel_prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC')

##########################################################################
#  Skew-T Plotting
# ------------------------
#
# Fiducial lines indicating dry adiabats, moist adiabats, and mixing ratio are
# useful when performing further analysis on the Skew-T diagram. Often the
# 0C isotherm is emphasized and areas of CAPE and CIN are shaded.

# Create a new figure. The dimensions here give a good aspect ratio
fig = plt.figure(figsize=(9, 9))
skew = SkewT(fig, rotation=30)

# Plot the data using normal plotting functions, in this case using
# log scaling in Y, as dictated by the typical meteorological plot
Esempio n. 33
0
def calculate_stability_indicies(ds, temp_name="temperature",
                                 td_name="dewpoint_temperature",
                                 p_name="pressure",
                                 moving_ave_window=0):
    """
    Function for calculating stability indices from sounding data.

    Parameters
    ----------
    ds : ACT dataset
        The dataset to compute the stability indicies of. Must have
        temperature, dewpoint, and pressure in vertical coordinates.
    temp_name : str
        The name of the temperature field.
    td_name : str
        The name of the dewpoint field.
    p_name : str
        The name of the pressure field.
    moving_ave_window : int
        Number of points to do a moving average on sounding data to reduce
        noise. This is useful if noise in the sounding is preventing parcel
        ascent.

    Returns
    -------
    ds : ACT dataset
        An ACT dataset with additional stability indicies added.

    """
    if not METPY_AVAILABLE:
        raise ImportError("MetPy need to be installed on your system to " +
                          "calculate stability indices")

    t = ds[temp_name]
    td = ds[td_name]
    p = ds[p_name]

    if not hasattr(t, "units"):
        raise AttributeError("Temperature field must have units" +
                             " for ACT to discern!")

    if not hasattr(td, "units"):
        raise AttributeError("Dewpoint field must have units" +
                             " for ACT to discern!")

    if not hasattr(p, "units"):
        raise AttributeError("Pressure field must have units" +
                             " for ACT to discern!")
    if t.units == "C":
        t_units = units.degC
    else:
        t_units = getattr(units, t.units)

    if td.units == "C":
        td_units = units.degC
    else:
        td_units = getattr(units, td.units)

    p_units = getattr(units, p.units)

    # Sort all values by decreasing pressure
    t_sorted = np.array(t.values)
    td_sorted = np.array(td.values)
    p_sorted = np.array(p.values)
    ind_sort = np.argsort(p_sorted)
    t_sorted = t_sorted[ind_sort[-1:0:-1]]
    td_sorted = td_sorted[ind_sort[-1:0:-1]]
    p_sorted = p_sorted[ind_sort[-1:0:-1]]

    if moving_ave_window > 0:
        t_sorted = np.convolve(
            t_sorted, np.ones((moving_ave_window,)) / moving_ave_window)
        td_sorted = np.convolve(
            td_sorted, np.ones((moving_ave_window,)) / moving_ave_window)
        p_sorted = np.convolve(
            p_sorted, np.ones((moving_ave_window,)) / moving_ave_window)

    t_sorted = t_sorted * t_units
    td_sorted = td_sorted * td_units
    p_sorted = p_sorted * p_units

    t_profile = mpcalc.parcel_profile(
        p_sorted, t_sorted[0], td_sorted[0])

    # Calculate parcel trajectory
    ds["parcel_temperature"] = t_profile.magnitude
    ds["parcel_temperature"].attrs['units'] = t_profile.units

    # Calculate CAPE, CIN, LCL
    sbcape, sbcin = mpcalc.surface_based_cape_cin(
        p_sorted, t_sorted, td_sorted)
    lcl = mpcalc.lcl(
        p_sorted[0], t_sorted[0], td_sorted[0])
    try:
        lfc = mpcalc.lfc(
            p_sorted[0], t_sorted[0], td_sorted[0])
    except IndexError:
        lfc = np.nan * p_sorted.units

    mucape, mucin = mpcalc.most_unstable_cape_cin(
        p_sorted, t_sorted, td_sorted)

    where_500 = np.argmin(np.abs(p_sorted - 500 * units.hPa))
    li = t_sorted[where_500] - t_profile[where_500]

    ds["surface_based_cape"] = sbcape.magnitude
    ds["surface_based_cape"].attrs['units'] = "J/kg"
    ds["surface_based_cape"].attrs['long_name'] = "Surface-based CAPE"
    ds["surface_based_cin"] = sbcin.magnitude
    ds["surface_based_cin"].attrs['units'] = "J/kg"
    ds["surface_based_cin"].attrs['long_name'] = "Surface-based CIN"
    ds["most_unstable_cape"] = mucape.magnitude
    ds["most_unstable_cape"].attrs['units'] = "J/kg"
    ds["most_unstable_cape"].attrs['long_name'] = "Most unstable CAPE"
    ds["most_unstable_cin"] = mucin.magnitude
    ds["most_unstable_cin"].attrs['units'] = "J/kg"
    ds["most_unstable_cin"].attrs['long_name'] = "Most unstable CIN"
    ds["lifted_index"] = li.magnitude
    ds["lifted_index"].attrs['units'] = t_profile.units
    ds["lifted_index"].attrs['long_name'] = "Lifted index"
    ds["level_of_free_convection"] = lfc.magnitude
    ds["level_of_free_convection"].attrs['units'] = lfc.units
    ds["level_of_free_convection"].attrs['long_name'] = "Level of free convection"
    ds["lifted_condensation_level_temperature"] = lcl[1].magnitude
    ds["lifted_condensation_level_temperature"].attrs['units'] = lcl[1].units
    ds["lifted_condensation_level_temperature"].attrs['long_name'] = "Lifted condensation level temperature"
    ds["lifted_condensation_level_pressure"] = lcl[0].magnitude
    ds["lifted_condensation_level_pressure"].attrs['units'] = lcl[0].units
    ds["lifted_condensation_level_pressure"].attrs['long_name'] = "Lifted condensation level pressure"
    return ds
Esempio n. 34
0
def plot_upper_air(station='11035', date=False):
    '''
    -----------------------------
    Default use of plot_upper_air:

    This will plot a SkewT sounding for station '11035' (Wien Hohe Warte)
    plot_upper_air(station='11035', date=False)
    '''
    # sns.set(rc={'axes.facecolor':'#343837', 'figure.facecolor':'#343837',
    #  'grid.linestyle':'','axes.labelcolor':'#04d8b2','text.color':'#04d8b2',
    #  'xtick.color':'#04d8b2','ytick.color':'#04d8b2'})
    # Get time in UTC
    station = str(station)
    if date is False:
        now = datetime.utcnow()
        # If morning then 0z sounding, otherwise 12z
        if now.hour < 12:
            hour = 0
        else:
            hour = 12
        date = datetime(now.year, now.month, now.day, hour)
        datestr = date.strftime('%Hz %Y-%m-%d')
        print('{}'.format(date))
    else:
        year = int(input('Please specify the year: '))
        month = int(input('Please specify the month: '))
        day = int(input('Please specify the day: '))
        hour = int(input('Please specify the hour: '))
        if hour < 12:
            hour = 0
        else:
            hour = 12
        date = datetime(year, month, day, hour)
        datestr = date.strftime('%Hz %Y-%m-%d')
        print('You entered {}'.format(date))

    # This requests the data 11035 is
    df = WyomingUpperAir.request_data(date, station)

    # Create single variables wih the right units
    p = df['pressure'].values * units.hPa
    T = df['temperature'].values * units.degC
    Td = df['dewpoint'].values * units.degC
    wind_speed = df['speed'].values * units.knots
    wind_dir = df['direction'].values * units.degrees

    wind_speed_6k = df['speed'][df.height <= 6000].values * units.knots
    wind_dir_6k = df['direction'][df.height <= 6000].values * units.degrees

    u, v = mpcalc.get_wind_components(wind_speed, wind_dir)
    u6, v6 = mpcalc.get_wind_components(wind_speed_6k, wind_dir_6k)

    # Calculate the LCL
    lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0])
    print(lcl_pressure, lcl_temperature)
    # Calculate the parcel profile.
    parcel_prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC')
    cape, cin = mpcalc.cape_cin(p, T, Td, parcel_prof)

    #############################
    # Create a new figure. The dimensions here give a good aspect ratio
    fig = plt.figure(figsize=(9, 9))
    gs = gridspec.GridSpec(3, 3)
    skew = SkewT(fig, rotation=45, subplot=gs[:, :2])

    # Plot the data using normal plotting functions, in this case using
    # log scaling in Y, as dictated by the typical meteorological plot
    skew.plot(p, T, 'r')
    skew.plot(p, Td, 'g')
    skew.plot_barbs(p, u, v)
    skew.ax.set_ylim(1000, 100)
    skew.ax.set_xlim(-45, 40)

    # Plot LCL as black dot
    skew.plot(lcl_pressure, lcl_temperature, 'ko', markerfacecolor='black')

    # Plot the parcel profile as a black line
    skew.plot(p, parcel_prof, 'k', linewidth=2)

    # Shade areas of CAPE and CIN
    skew.shade_cin(p, T, parcel_prof)
    skew.shade_cape(p, T, parcel_prof)

    # Plot a zero degree isotherm
    skew.ax.axvline(0, color='c', linestyle='--', linewidth=2)
    skew.ax.set_title('Station: ' + str(station) + '\n' + datestr)  # set title
    skew.ax.set_xlabel('Temperature (C)')
    skew.ax.set_ylabel('Pressure (hPa)')

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

    # Create a hodograph
    # Create an inset axes object that is 40% width and height of the
    # figure and put it in the upper right hand corner.
    # ax_hod = inset_axes(skew.ax, '40%', '40%', loc=1)
    ax = fig.add_subplot(gs[0, -1])
    h = Hodograph(ax, component_range=60.)
    h.add_grid(increment=20)
    # Plot a line colored by windspeed
    h.plot_colormapped(u6, v6, wind_speed_6k)

    # add another subplot for the text of the indices
    # ax_t = fig.add_subplot(gs[1:,2])
    skew2 = SkewT(fig, rotation=0, subplot=gs[1:, 2])
    skew2.plot(p, T, 'r')
    skew2.plot(p, Td, 'g')
    # skew2.plot_barbs(p, u, v)
    skew2.ax.set_ylim(1000, 700)
    skew2.ax.set_xlim(-30, 10)

    # Show the plot
    plt.show()

    return cape
Esempio n. 35
0
    def plot(self, t, td, p, u, v, lat, long, time):
        r"""Displays the Skew-T data on a matplotlib figure.

        Args:
            t (array-like): A list of temperature values.
            td (array-like): A list of dewpoint values.
            p (array-like): A list of pressure values.
            u (array-like): A list of u-wind component values.
            v (array-like): A list of v-wind component values.
            lat (string): A string containing the requested latitude value.
            long (string): A string containing the requested longitude value.
            time (string): A string containing the UTC time requested with seconds truncated.
        Returns:
            None.
        Raises:
            None.

        """

        # Create a new figure. The dimensions here give a good aspect ratio
        self.skew = SkewT(self.figure, rotation=40)

        # Plot the data using normal plotting functions, in this case using
        # log scaling in Y, as dictated by the typical meteorological plot
        self.skew.plot(p, t, 'r')
        self.skew.plot(p, td, 'g')
        self.skew.plot_barbs(p, u, v, barbcolor='#FF0000', flagcolor='#FF0000')
        self.skew.ax.set_ylim(1000, 100)
        self.skew.ax.set_xlim(-40, 60)

        # Axis colors
        self.skew.ax.tick_params(axis='x', colors='#A3A3A4')
        self.skew.ax.tick_params(axis='y', colors='#A3A3A4')

        # Calculate LCL height and plot as black dot
        l = lcl(p[0], t[0], td[0])
        lcl_temp = dry_lapse(concatenate((p[0], l)), t[0])[-1].to('degC')
        self.skew.plot(l, lcl_temp, 'ko', markerfacecolor='black')

        # Calculate full parcel profile and add to plot as black line
        prof = parcel_profile(p, t[0], td[0]).to('degC')
        self.skew.plot(p, prof, 'k', linewidth=2)

        # Color shade areas between profiles
        self.skew.ax.fill_betweenx(p, t, prof, where=t >= prof, facecolor='#5D8C53', alpha=0.7)
        self.skew.ax.fill_betweenx(p, t, prof, where=t < prof, facecolor='#CD6659', alpha=0.7)

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

        # Set title
        deg = u'\N{DEGREE SIGN}'
        self.skew.ax.set_title('Sounding for ' + lat + deg + ', ' + long + deg + ' at ' + time + 'z', y=1.02,
                               color='#A3A3A4')

        # Discards old graph, works poorly though
        # skew.ax.hold(False)
        # Figure and canvas widgets that display the figure in the GUI

        # set canvas size to display Skew-T appropriately
        self.canvas.setMaximumSize(QtCore.QSize(800, 2000))
        # refresh canvas
        self.canvas.draw()
Esempio n. 36
0
def cape(filelist,storm,track,show):
    #Sort filelist.
    filelist=np.sort(filelist)

    # Get sampling periods (this will be a dictionary). See the toolbox
    print('Retrieving sampling periods')
    sampleperiods=getsamplingperiods(filelist,3.)

    # Iterate over all sampling periods.
    for sampindex,periodskey in enumerate(sampleperiods):

        #Allocate starting (stdt) and ending date (endt). Remeber dt is the convetional short-name for date.
        stdt=periodskey
        endt=sampleperiods[periodskey]

        # Define sampling period string
        period=str(stdt.hour)+'_'+str(stdt.day)+'-'+str(endt.hour)+'_'+str(endt.day)

        # Create new-empty lists.
        lats=[]
        lons=[]
        xs=[]
        ys=[]
        capes=[]
        cins=[]
	
        distfig = plt.figure(figsize=(13, 9))
        ax=distfig.add_subplot(111)
        print('start filelist loop')
        # Iterate over all files.
        for filename in filelist:



            # Select end-name of file by inspecting filename string. Notice how filename can change how file is read.
            if 'radazm' in filename.split('/')[-1] or 'eol' in filename.split('/')[-1]:
                end='radazm'
            else:
                end='avp'
            # Obtain properties of file, i.e., launch time and location into a dictionary (dicc).
            dicc=findproperties(filename,end)

            # Condition to see if current file is in sampling period.
            # Notice how if structure is constructed, condition finds times outside of sampling period and
            # if found outside the sampling period, continue to next file.
            if dicc['Launch Time']<stdt or dicc['Launch Time'] > endt:
                continue

            nump=np.genfromtxt(filename,skip_header=16,skip_footer=0)
            temperature=clean1(nump[:,5])
            pressure=clean1(nump[:,4])
            Height=clean1(nump[:,13])
            if np.nanmax(Height)<3500:
                continue
            #Clean for cape
            RelH=clean1(nump[:,7])
            lon=clean1(nump[:,14])
            lat=clean1(nump[:,15])
            lon=clean1(lon)
            lat=clean1(lat)
            mlon=np.nanmean(lon)
            mlat=np.nanmean(lat)
            RH=RelH/100
            T,P,rh,dz=cleanforcape(temperature,pressure,RH,Height)

            #Metpy set-up
            T=np.flip(T,0)
            rh=np.flip(rh,0)
            p=np.flip(P,0)
            dz=np.flip(dz,0)
            p=p*units.hPa
            T=T*units.celsius


            mixing=rh*mpcalc.saturation_mixing_ratio(p,T)
            epsilon=0.6219800858985514
            Tv=mpcalc.virtual_temperature(T, mixing,
                                      molecular_weight_ratio=epsilon)
            dwpoint=mpcalc.dewpoint_rh(T, rh)

            blh_indx=np.where(dz<500)
            try:
                parcelprofile=mpcalc.parcel_profile(p,np.nanmean(T[blh_indx])*units.celsius,mpcalc.dewpoint_rh(np.nanmean(T[blh_indx])*units.celsius, np.nanmean(rh[blh_indx]))).to('degC')
                Tv_parcelprofile=mpcalc.virtual_temperature(parcelprofile, mixing,
                                          molecular_weight_ratio=epsilon)
                cape,cin=cape_cin(p,Tv,dwpoint,Tv_parcelprofile,dz,T)
            except:
                continue

            plotskewT=True
            if plotskewT==True:

                os.system('mkdir figs/skewt')
                fig = plt.figure(figsize=(9, 9))
                skew = SkewT(fig, rotation=45)
                skew.ax.set_ylim(1000, 100)
                skew.ax.set_xlim(-40, 60)

                skew.plot(p, dwpoint, 'g',label=r'$T_{dp}$')
                skew.plot(p, Tv, 'r',label=r'$T_v$')
                plt.text(-120,120,str(np.around(cape,2)),fontsize=14,fontweight='bold')

                # Plot the data using normal plotting functions, in this case using
                # log scaling in Y, as dictated by the typical meteorological plot
                skew.plot(p,Tv_parcelprofile,'k',label=r'$T_{v env}$')
                skew.shade_cin(p, T, parcelprofile,label='CIN')
                skew.shade_cape(p, Tv, Tv_parcelprofile,label='CAPE')
                skew.plot_dry_adiabats()
                skew.plot_moist_adiabats()

                plt.legend()
                plt.title(storm + ' on' + period,fontsize=14)
                plt.savefig('figs/skewt/'+storm+str(dicc['Launch Time'].time())+'.png')
                #plt.show()
                plt.close()

            r,theta=cart_to_cylindr(mlon,mlat,track,dicc['Launch Time'])
            if not(np.isnan(r)) and not(np.isnan(theta)) and not(np.isnan(cape.magnitude)):
                xs.append(r*np.cos(theta))
                ys.append(r*np.sin(theta))
                capes.append(cape.magnitude)
                cins.append(cin)


            cs=ax.scatter(xs,ys,c=np.asarray(capes),cmap='jet')
            for i,xi in enumerate(xs):
                ax.text(xi,ys[i]+10,str(np.around(capes[i],1)))
        plt.colorbar(cs)
        ax.scatter(0,0,marker='v',s=100,color='black')
        ax.grid()
        ax.set_xlabel('X distance [km]')
        ax.set_ylabel('Y distance [km]')
        ax.set_title('CAPE distribution for '+storm+' on '+period,fontsize=14)
        distfig.savefig('figs/cape'+storm+period+'.png')
        if show:
            plt.show()
Esempio n. 37
0
# Plot the data using normal plotting functions, in this case using
# log scaling in Y, as dictated by the typical meteorological plot
skew.plot(p, T, 'r')
skew.plot(p, Td, 'g')
skew.plot_barbs(p, u, v)
skew.ax.set_ylim(1000, 100)
skew.ax.set_xlim(-40, 60)

# Calculate LCL height and plot as black dot
l = lcl(p[0], C2K(T[0]), C2K(Td[0]))
skew.plot(l, K2C(dry_lapse(l, C2K(T[0]), p[0])), 'ko',
        markerfacecolor='black')

# Calculate full parcel profile and add to plot as black line
prof = K2C(parcel_profile(p, C2K(T[0]), C2K(Td[0])))
skew.plot(p, prof, 'k', linewidth=2)

# Example of coloring area between profiles
skew.ax.fill_betweenx(p, T, prof, where=T>=prof, facecolor='blue', alpha=0.4)
skew.ax.fill_betweenx(p, T, prof, where=T<prof, facecolor='red', alpha=0.4)

# An example of a slanted line at constant T -- in this case the 0
# 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()
Esempio n. 38
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)
Esempio n. 39
0
    def plot_from_u_and_v(
            self,
            u_field,
            v_field,
            p_field,
            t_field,
            td_field,
            dsname=None,
            subplot_index=(0, ),
            p_levels_to_plot=None,
            show_parcel=True,
            shade_cape=True,
            shade_cin=True,
            set_title=None,
            plot_barbs_kwargs=dict(),
            plot_kwargs=dict(),
    ):
        """
        This function will plot a Skew-T from a sounding dataset. The wind
        data must be given in u and v.

        Parameters
        ----------
        u_field: str
            The name of the field containing the u component of the wind.
        v_field: str
            The name of the field containing the v component of the wind.
        p_field: str
            The name of the field containing the pressure.
        t_field: str
            The name of the field containing the temperature.
        td_field: str
            The name of the field containing the dewpoint temperature.
        dsname: str or None
            The name of the datastream to plot. Set to None to make ACT
            attempt to automatically determine this.
        subplot_index: tuple
            The index of the subplot to make the plot on.
        p_levels_to_plot: 1D array
            The pressure levels to plot the wind barbs on. Set to None
            to have ACT to use neatly spaced defaults of
            50, 100, 200, 300, 400, 500, 600, 700, 750, 800,
            850, 900, 950, and 1000 hPa.
        show_parcel: bool
            Set to True to show the temperature of a parcel lifted
            from the surface.
        shade_cape: bool
            Set to True to shade the CAPE red.
        shade_cin: bool
            Set to True to shade the CIN blue.
        set_title: None or str
            The title of the plot is set to this. Set to None to use
            a default title.
        plot_barbs_kwargs: dict
            Additional keyword arguments to pass into MetPy's
            SkewT.plot_barbs.
        plot_kwargs: dict
            Additional keyword arguments to pass into MetPy's
            SkewT.plot.

        Returns
        -------
        ax: matplotlib axis handle
            The axis handle to the plot.

        """
        if dsname is None and len(self._arm.keys()) > 1:
            raise ValueError(("You must choose a datastream when there are 2 "
                              "or more datasets in the TimeSeriesDisplay "
                              "object."))
        elif dsname is None:
            dsname = list(self._arm.keys())[0]

        if p_levels_to_plot is None:
            p_levels_to_plot = np.array([
                50., 100., 200., 300., 400., 500., 600., 700., 750., 800.,
                850., 900., 950., 1000.
            ])
        T = self._arm[dsname][t_field]
        T_units = self._arm[dsname][t_field].attrs["units"]
        if T_units == "C":
            T_units = "degC"

        T = T.values * getattr(units, T_units)
        Td = self._arm[dsname][td_field]
        Td_units = self._arm[dsname][td_field].attrs["units"]
        if Td_units == "C":
            Td_units = "degC"

        Td = Td.values * getattr(units, Td_units)
        u = self._arm[dsname][u_field]
        u_units = self._arm[dsname][u_field].attrs["units"]
        u = u.values * getattr(units, u_units)

        v = self._arm[dsname][v_field]
        v_units = self._arm[dsname][v_field].attrs["units"]
        v = v.values * getattr(units, v_units)

        p = self._arm[dsname][p_field]
        p_units = self._arm[dsname][p_field].attrs["units"]
        p = p.values * getattr(units, p_units)

        u_red = np.zeros_like(p_levels_to_plot) * getattr(units, u_units)
        v_red = np.zeros_like(p_levels_to_plot) * getattr(units, v_units)
        p_levels_to_plot = p_levels_to_plot * getattr(units, p_units)
        for i in range(len(p_levels_to_plot)):
            index = np.argmin(np.abs(p_levels_to_plot[i] - p))
            u_red[i] = u[index].magnitude * getattr(units, u_units)
            v_red[i] = v[index].magnitude * getattr(units, v_units)

        self.SkewT[subplot_index].plot(p, T, 'r', **plot_kwargs)
        self.SkewT[subplot_index].plot(p, Td, 'g', **plot_kwargs)
        self.SkewT[subplot_index].plot_barbs(p_levels_to_plot, u_red, v_red,
                                             **plot_barbs_kwargs)

        prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC')
        if show_parcel:
            # Only plot where prof > T
            lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0])
            self.SkewT[subplot_index].plot(lcl_pressure,
                                           lcl_temperature,
                                           'ko',
                                           markerfacecolor='black',
                                           **plot_kwargs)
            self.SkewT[subplot_index].plot(p,
                                           prof,
                                           'k',
                                           linewidth=2,
                                           **plot_kwargs)

        if shade_cape:
            self.SkewT[subplot_index].shade_cape(p, T, prof, linewidth=2)

        if shade_cin:
            self.SkewT[subplot_index].shade_cin(p, T, prof, linewidth=2)

        # Set Title
        if set_title is None:
            set_title = ' '.join([
                dsname, 'on',
                dt_utils.numpy_to_arm_date(self._arm[dsname].time.values[0])
            ])

        self.axes[subplot_index].set_title(set_title)

        # Set Y Limit
        if hasattr(self, 'yrng'):
            # Make sure that the yrng is not just the default
            if not np.all(self.yrng[subplot_index] == 0):
                self.set_yrng(self.yrng[subplot_index], subplot_index)
            else:
                our_data = p.magnitude
                if np.isfinite(our_data).any():
                    yrng = [np.nanmax(our_data), np.nanmin(our_data)]
                else:
                    yrng = [1000., 100.]
                self.set_yrng(yrng, subplot_index)

        # Set X Limit
        xrng = [T.magnitude.min() - 10., T.magnitude.max() + 10.]
        self.set_xrng(xrng, subplot_index)

        return self.axes[subplot_index]
Esempio n. 40
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)
Esempio n. 41
0
# Often times we will want to calculate some thermodynamic parameters of a
# sounding. The MetPy calc module has many such calculations already implemented!
#
# * **Lifting Condensation Level (LCL)** - The level at which an air parcel's
#   relative humidity becomes 100% when lifted along a dry adiabatic path.
# * **Parcel Path** - Path followed by a hypothetical parcel of air, beginning
#   at the surface temperature/pressure and rising dry adiabatically until
#   reaching the LCL, then rising moist adiabatially.

# Calculate the LCL
lcl_pressure, lcl_temperature = mpcalc.lcl(p[0], T[0], Td[0])

print(lcl_pressure, lcl_temperature)

# Calculate the parcel profile.
parcel_prof = mpcalc.parcel_profile(p, T[0], Td[0]).to('degC')

##########################################################################
# Basic Skew-T Plotting
# ---------------------
#
# The Skew-T (log-P) diagram is the standard way to view rawinsonde data. The
# y-axis is height in pressure coordinates and the x-axis is temperature. The
# y coordinates are plotted on a logarithmic scale and the x coordinate system
# is skewed. An explanation of skew-T interpretation is beyond the scope of this
# tutorial, but here we will plot one that can be used for analysis or
# publication.
#
# The most basic skew-T can be plotted with only five lines of Python.
# These lines perform the following tasks:
#