Esempio n. 1
0
    def test_3d(self):
        'Test of geostrophic wind calculation with 3D array'
        z = np.array([[48, 49, 48], [49, 50, 49], [48, 49, 48]]) * 100.
        # Using g as the value for f allows it to cancel out
        z3d = np.dstack((z, z)) * units.meter
        ug, vg = geostrophic_wind(z3d, g.magnitude / units.sec,
                                  100. * units.meter, 100. * units.meter)
        true_u = np.array([[-1, 0, 1]] * 3) * units('m/s')
        true_v = -true_u.T

        true_u = concatenate((true_u[..., None], true_u[..., None]), axis=2)
        true_v = concatenate((true_v[..., None], true_v[..., None]), axis=2)
        assert_array_equal(ug, true_u)
        assert_array_equal(vg, true_v)
Esempio n. 2
0
    def test_3d(self):
        'Test of geostrophic wind calculation with 3D array'
        z = np.array([[48, 49, 48], [49, 50, 49], [48, 49, 48]]) * 100.
        # Using g as the value for f allows it to cancel out
        z3d = np.dstack((z, z)) * units.meter
        ug, vg = geostrophic_wind(z3d, g.magnitude / units.sec,
                                  100. * units.meter, 100. * units.meter)
        true_u = np.array([[-1, 0, 1]] * 3) * units('m/s')
        true_v = -true_u.T

        true_u = concatenate((true_u[..., None], true_u[..., None]), axis=2)
        true_v = concatenate((true_v[..., None], true_v[..., None]), axis=2)
        assert_array_equal(ug, true_u)
        assert_array_equal(vg, true_v)
Esempio n. 3
0
def test_bunkers_motion():
    """Test Bunkers storm motion with observed sounding."""
    data = get_upper_air_data(datetime(2016, 5, 22, 0), 'DDC')
    motion = concatenate(bunkers_storm_motion(data['pressure'],
                         data['u_wind'], data['v_wind'],
                         data['height']))
    truth = [1.4537892577864744, 2.0169333025630616, 10.587950761120482, 13.915130377372801,
             6.0208700094534775, 7.9660318399679308] * units('m/s')
    assert_almost_equal(motion.flatten(), truth, 8)
Esempio n. 4
0
def test_bunkers_motion():
    """Test Bunkers storm motion with observed sounding."""
    data = get_upper_air_data(datetime(2016, 5, 22, 0), 'DDC')
    motion = concatenate(bunkers_storm_motion(data['pressure'],
                         data['u_wind'], data['v_wind'],
                         data['height']))
    truth = [2.18346161, 0.86094706, 11.6006767, 12.53639395, 6.89206916,
             6.69867051] * units('m/s')
    assert_almost_equal(motion.flatten(), truth, 8)
Esempio n. 5
0
def test_bunkers_motion():
    """Test Bunkers storm motion with observed sounding."""
    data = get_upper_air_data(datetime(2016, 5, 22, 0), 'DDC')
    motion = concatenate(bunkers_storm_motion(data['pressure'],
                         data['u_wind'], data['v_wind'],
                         data['height']))
    truth = [1.4537892577864744, 2.0169333025630616, 10.587950761120482, 13.915130377372801,
             6.0208700094534775, 7.9660318399679308] * units('m/s')
    assert_almost_equal(motion.flatten(), truth, 8)
Esempio n. 6
0
def parcel_profile(pressure, temperature, dewpt):
    r"""Calculate the profile a parcel takes through the atmosphere.

    The parcel starts at `temperature`, and `dewpt`, lifted up
    dry adiabatically to the LCL, and then moist adiabatically from there.
    `pressure` specifies the pressure levels for the profile.

    Parameters
    ----------
    pressure : `pint.Quantity`
        The atmospheric pressure level(s) of interest. The first entry should be the starting
        point pressure.
    temperature : `pint.Quantity`
        The starting temperature
    dewpt : `pint.Quantity`
        The starting dew point

    Returns
    -------
    `pint.Quantity`
        The parcel temperatures at the specified pressure levels.

    See Also
    --------
    lcl, moist_lapse, dry_lapse

    """
    # Find the LCL
    lcl_pressure = lcl(pressure[0], temperature, dewpt)[0].to(pressure.units)

    # Find the dry adiabatic profile, *including* the LCL. We need >= the LCL in case the
    # LCL is included in the levels. It's slightly redundant in that case, but simplifies
    # the logic for removing it later.
    press_lower = concatenate(
        (pressure[pressure >= lcl_pressure], lcl_pressure))
    t1 = dry_lapse(press_lower, temperature)

    # Find moist pseudo-adiabatic profile starting at the LCL
    press_upper = concatenate(
        (lcl_pressure, pressure[pressure < lcl_pressure]))
    t2 = moist_lapse(press_upper, t1[-1]).to(t1.units)

    # Return LCL *without* the LCL point
    return concatenate((t1[:-1], t2[1:]))
Esempio n. 7
0
def test_concatenate_masked():
    """Test concatenate preserves masks."""
    d1 = units.Quantity(np.ma.array([1, 2, 3], mask=[False, True, False]), 'degC')
    result = concatenate((d1, 32 * units.degF))

    truth = np.ma.array([1, np.inf, 3, 0])
    truth[1] = np.ma.masked

    assert_array_almost_equal(result, units.Quantity(truth, 'degC'), 6)
    assert_array_equal(result.mask, np.array([False, True, False, False]))
Esempio n. 8
0
def _find_append_zero_crossings(x, y):
    r"""
    Find and interpolate zero crossings.

    Estimate the zero crossings of an x,y series and add estimated crossings to series,
    returning a sorted array with no duplicate values.

    Parameters
    ----------
    x : `pint.Quantity`
        x values of data
    y : `pint.Quantity`
        y values of data

    Returns
    -------
    x : `pint.Quantity`
        x values of data
    y : `pint.Quantity`
        y values of data

    """
    # Find and append crossings to the data
    crossings = find_intersections(x[1:], y[1:],
                                   np.zeros_like(y[1:]) * y.units)
    print(crossings)
    x = concatenate((x, crossings[0]))
    y = concatenate((y, crossings[1]))

    # Resort so that data are in order
    sort_idx = np.argsort(x)
    x = x[sort_idx]
    y = y[sort_idx]

    # Remove duplicate data points if there are any
    keep_idx = np.ediff1d(x, to_end=[1]) > 0
    x = x[keep_idx]
    y = y[keep_idx]
    return x, y
Esempio n. 9
0
skew.plot_barbs(p, u, v)
skew.ax.set_ylim(1000, 100)    # Y limits from 1000 in the botton to 100 millibars to the top
skew.ax.set_xlim(-40, 60)      # X limits

# Add the relevant special lines\n",
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
Esempio n. 10
0
def atmCalc(height, temp, humid):
    print("ATMCALC", height, temp, humid, file=sys.stderr)
    mtny = windh(MTNX, height, ratio=1,
                 yoffset=0)

    windx = XVALUES
    windy = windh(windx, height)

    temp_ = temp * units.degC
    initp = mc.height_to_pressure_std(windy[0] * units.meters)
    dewpt = mc.dewpoint_from_relative_humidity(temp_, humid / 100.)
    lcl_ = mc.lcl(initp, temp_, dewpt, max_iters=50, eps=1e-5)
    LCL = mc.pressure_to_height_std(lcl_[0])

    if (lcl_[0] > mc.height_to_pressure_std(max(windy) * units.meters)
            and LCL > windy[0] * units.meters * 1.000009):
        # add LCL to x
        xlcl = windh(LCL.to('meters').magnitude, height, inv=True)
        windx = np.sort(np.append(windx, xlcl))
        windy = windh(windx, height)

    pressures = mc.height_to_pressure_std(windy * units.meters)

    wvmr0 = mc.mixing_ratio_from_relative_humidity(initp, temp_, humid / 100.)

    # now calculate the air parcel temperatures and RH at each position
    if (lcl_[0] <= min(pressures)):
        T = mc.dry_lapse(pressures, temp_)
        RH = [
            mc.relative_humidity_from_mixing_ratio(
                wvmr0, t, p) for t, p in zip(
                T, pressures)]
    else:
        mini = np.argmin(pressures)
        p1 = pressures[:mini + 1]
        p2 = pressures[mini:]  # with an overlap
        p11 = p1[p1 >= lcl_[0] * .9999999]  # lower (with tol) with lcl
        p12 = p1[p1 < lcl_[0] * 1.000009]  # upper (with tol) with lcl
        T11 = mc.dry_lapse(p11, temp_)
        T12 = mc.moist_lapse(p12, lcl_[1])
        T1 = concatenate((T11[:-1], T12))
        T2 = mc.dry_lapse(p2, T1[-1])
        T = concatenate((T1, T2[1:]))
        wvmrtop = mc.saturation_mixing_ratio(pressures[mini], T[mini])
        RH=[]
        for i in range(len(pressures)):
            if pressures[i] > lcl_[0] and i <= mini:
                v=mc.relative_humidity_from_mixing_ratio(pressures[i], T[i], wvmr0)
            else:
                if i < mini:
                    v=1
                else:
                    v=mc.relative_humidity_from_mixing_ratio(pressures[i], T[i], wvmrtop)
            RH.append(v)
        
        #RH = [mc.relative_humidity_from_mixing_ratio(*tp, wvmr0) if tp[1] > lcl_[
            #0] and i <= mini else 1.0 if i < mini else
            #mc.relative_humidity_from_mixing_ratio(*tp, wvmrtop)
            #for i, tp in enumerate(zip(pressures, T))]

    RH = concatenate(RH)
    return windx, mtny, windy, lcl_, LCL, T.to("degC"), RH
Esempio n. 11
0
def test_concatenate():
    """Test basic functionality of unit-aware concatenate."""
    result = concatenate((3 * units.meter, 400 * units.cm))
    assert_array_equal(result, np.array([3, 4]) * units.meter)
    assert not isinstance(result.m, np.ma.MaskedArray)
Esempio n. 12
0
###########################################
# Create a new figure. The dimensions here give a good aspect ratio
fig = plt.figure(figsize=(9, 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(1000, 100)
skew.ax.set_xlim(-40, 60)

# Calculate LCL height and plot as black dot
l = mpcalc.lcl(p[0], T[0], Td[0])
lcl_temp = mpcalc.dry_lapse(concatenate((p[0], l)), T[0])[-1].to('degC')
skew.plot(l, lcl_temp, '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)

# Example of coloring area between profiles
greater = T >= prof
skew.ax.fill_betweenx(p, T, prof, where=greater, facecolor='blue', alpha=0.4)
skew.ax.fill_betweenx(p, T, prof, where=~greater, 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)
Esempio n. 13
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 level
parcel_lcl = mpcalc.lcl(p[0], T[0], Td[0])

# Determine the LCL temperature by lifting a parcel from the surface
# pressure and temperature via a dry adiabatic process.
lcl_temperature = mpcalc.dry_lapse(concatenate((p[0], parcel_lcl)),
                                   T[0])[-1].to('degC')

print(parcel_lcl, 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
Esempio n. 14
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()