예제 #1
0
def test_storm_relative_helicity():
    """Test function for SRH calculations on an eigth-circle hodograph."""
    # Create larger arrays for everything except pressure to make a smoother graph
    hgt_int = np.arange(0, 2050, 50)
    hgt_int = hgt_int * units('meter')
    dir_int = np.arange(180, 272.25, 2.25)
    spd_int = np.zeros((hgt_int.shape[0]))
    spd_int[:] = 2.
    u_int, v_int = get_wind_components(spd_int * units('m/s'),
                                       dir_int * units.degree)

    # Put in the correct value of SRH for a eighth-circle, 2 m/s hodograph
    # (SRH = 2 * area under hodo, in this case...)
    srh_true_p = (.25 * np.pi * (2**2)) * units('m^2/s^2')

    # Since there's only positive SRH in this case, total SRH will be equal to positive SRH and
    # negative SRH will be zero.
    srh_true_t = srh_true_p
    srh_true_n = 0 * units('m^2/s^2')
    p_srh, n_srh, T_srh = storm_relative_helicity(u_int,
                                                  v_int,
                                                  hgt_int,
                                                  1000 * units('meter'),
                                                  bottom=0 * units('meter'),
                                                  storm_u=0 * units.knot,
                                                  storm_v=0 * units.knot)
    assert_almost_equal(p_srh, srh_true_p, 2)
    assert_almost_equal(n_srh, srh_true_n, 2)
    assert_almost_equal(T_srh, srh_true_t, 2)
예제 #2
0
def test_storm_relative_helicity_no_storm_motion():
    """Test storm relative helicity with no storm motion and differing input units."""
    u = np.array([0, 20, 10, 0]) * units('m/s')
    v = np.array([20, 0, 0, 10]) * units('m/s')
    u = u.to('knots')
    heights = np.array([0, 250, 500, 750]) * units.m

    positive_srh, negative_srh, total_srh = storm_relative_helicity(u, v, heights,
                                                                    depth=750 * units.meters)

    assert_almost_equal(positive_srh, 400. * units('meter ** 2 / second ** 2 '), 6)
    assert_almost_equal(negative_srh, -100. * units('meter ** 2 / second ** 2 '), 6)
    assert_almost_equal(total_srh, 300. * units('meter ** 2 / second ** 2 '), 6)
예제 #3
0
def test_storm_relative_helicity_with_interpolation():
    """Test storm relative helicity with interpolation."""
    u = np.array([-5, 15, 25, 15, -5]) * units('m/s')
    v = np.array([40, 20, 10, 10, 30]) * units('m/s')
    u = u.to('knots')
    heights = np.array([0, 100, 200, 300, 400]) * units.m

    pos_srh, neg_srh, total_srh = storm_relative_helicity(u, v, heights,
                                                          bottom=50 * units.meters,
                                                          depth=300 * units.meters,
                                                          storm_u=5 * units('m/s'),
                                                          storm_v=10 * units('m/s'))

    assert_almost_equal(pos_srh, 400. * units('meter ** 2 / second ** 2 '), 6)
    assert_almost_equal(neg_srh, -100. * units('meter ** 2 / second ** 2 '), 6)
    assert_almost_equal(total_srh, 300. * units('meter ** 2 / second ** 2 '), 6)
예제 #4
0
def test_helicity():
    """Test function for SRH calculations on an eigth-circle hodograph."""
    pres_test = np.asarray([
        1013.25, 954.57955706, 898.690770743, 845.481604002, 794.85264282
    ]) * units('hPa')
    hgt_test = hgt_test = np.asarray([0, 500, 1000, 1500, 2000])

    # Create larger arrays for everything except pressure to make a smoother graph
    hgt_int = np.arange(0, 2050, 50)
    hgt_int = hgt_int * units('meter')
    dir_int = np.arange(180, 272.25, 2.25)
    spd_int = np.zeros((hgt_int.shape[0]))
    spd_int[:] = 2.
    u_int, v_int = get_wind_components(spd_int * units('m/s'),
                                       dir_int * units.degree)

    # Interpolate pressure to that graph
    pres_int = np.interp(hgt_int, hgt_test, np.log(pres_test.magnitude))
    pres_int = np.exp(pres_int) * units('hPa')

    # Put in the correct value of SRH for a eighth-circle, 2 m/s hodograph
    # (SRH = 2 * area under hodo, in this case...)
    srh_true_p = (.25 * np.pi * (2**2)) * units('m^2/s^2')

    # Since there's only positive SRH in this case, total SRH will be equal to positive SRH and
    # negative SRH will be zero.
    srh_true_t = srh_true_p
    srh_true_n = 0 * units('m^2/s^2')
    p_srh, n_srh, T_srh = storm_relative_helicity(u_int,
                                                  v_int,
                                                  pres_int,
                                                  hgt_int,
                                                  1000 * units('meter'),
                                                  bottom=0 * units('meter'),
                                                  storm_u=0 * units.knot,
                                                  storm_v=0 * units.knot)
    assert_almost_equal(p_srh, srh_true_p, 2)
    assert_almost_equal(n_srh, srh_true_n, 2)
    assert_almost_equal(T_srh, srh_true_t, 2)
예제 #5
0
 def storm_relative_helicity(self):
     sm_u, sm_v = self.bunkers_storm_motion()[2]
     return mpcalc.storm_relative_helicity(self.u, self.v, self.z,
                                           1000 * units.meter,
                                           0 * units.meter, sm_u, sm_v)
예제 #6
0
 def process_skewt(self):
     # Calculation
     index_p100 = get_pressure_level_index(self.p_i, 100)
     lcl_p, lcl_t = mpcalc.lcl(self.p_i[0], self.t_i[0], self.td_i[0])
     lfc_p, lfc_t = mpcalc.lfc(self.p_i, self.t_i, self.td_i)
     el_p, el_t = mpcalc.el(self.p_i, self.t_i, self.td_i)
     prof = mpcalc.parcel_profile(self.p_i, self.t_i[0], self.td_i[0]).to('degC')
     cape, cin = mpcalc.cape_cin(self.p_i, self.t_i, self.td_i, prof)
     mucape, mucin = mpcalc.most_unstable_cape_cin(self.p_i, self.t_i, self.td_i)
     pwat = mpcalc.precipitable_water(self.td_i, self.p_i)
     i8 = get_pressure_level_index(self.p_i, 850)
     i7 = get_pressure_level_index(self.p_i, 700)
     i5 = get_pressure_level_index(self.p_i, 500)
     theta850 = mpcalc.equivalent_potential_temperature(850 * units('hPa'), self.t_i[i8], self.td_i[i5])
     theta500 = mpcalc.equivalent_potential_temperature(500 * units('hPa'), self.t_i[i5], self.td_i[i5])
     thetadiff = theta850 - theta500
     k = self.t_i[i8] - self.t_i[i5] + self.td_i[i8] - (self.t_i[i7] - self.td_i[i7])
     a = ((self.t_i[i8] - self.t_i[i5]) - (self.t_i[i8] - self.td_i[i5]) -
         (self.t_i[i7] - self.td_i[i7]) - (self.t_i[i5] - self.td_i[i5]))
     sw = c_sweat(np.array(self.t_i[i8].magnitude), np.array(self.td_i[i8].magnitude),
                  np.array(self.t_i[i5].magnitude), np.array(self.u_i[i8].magnitude),
                  np.array(self.v_i[i8].magnitude), np.array(self.u_i[i5].magnitude),
                  np.array(self.v_i[i5].magnitude))
     si = showalter_index(self.t_i[i8], self.td_i[i8], self.t_i[i5])
     li = lifted_index(self.t_i[0], self.td_i[0], self.p_i[0], self.t_i[i5])
     srh_pos, srh_neg, srh_tot = mpcalc.storm_relative_helicity(self.u_i, self.v_i, self.alt, 1000 * units('m'))
     sbcape, sbcin = mpcalc.surface_based_cape_cin(self.p_i, self.t_i, self.td_i)
     shr6km = mpcalc.bulk_shear(self.p_i, self.u_i, self.v_i, heights=self.alt, depth=6000 * units('m'))
     wshr6km = mpcalc.wind_speed(*shr6km)
     sigtor = mpcalc.significant_tornado(sbcape, delta_height(self.p_i[0], lcl_p), srh_tot, wshr6km)[0]
     # Plotting
     self.ax.set_ylim(1050, 100)
     self.ax.set_xlim(-40, 50)
     self.plot(self.p_i, self.t_i, 'r', linewidth=1)
     self.plot(self.p_i[:self.dp_idx], self.td_i[:self.dp_idx], 'g', linewidth=1)
     self.plot_barbs(self.p_i[:index_p100], self.u_i[:index_p100] * 1.94, self.v_i[:index_p100] * 1.94)
     self.plot(lcl_p, lcl_t, 'ko', markerfacecolor='black')
     self.plot(self.p_i, prof, 'k', linewidth=2)
     if cin.magnitude < 0:
         chi = -1 * cin.magnitude
         self.shade_cin(self.p_i, self.t_i, prof)
     elif cin.magnitude > 0:
         chi = cin.magnitude
         self.shade_cin(self.p_i, self.t_i, prof)
     else:
         chi = 0.
     self.shade_cape(self.p_i, self.t_i, prof)
     self.plot_dry_adiabats(linewidth=0.5)
     self.plot_moist_adiabats(linewidth=0.5)
     self.plot_mixing_lines(linewidth=0.5)
     plt.title('Skew-T Plot \nStation: {} Time: {}'.format(self.st, self.time.strftime('%Y.%m.%d %H:%M')), fontsize=14, loc='left')
     # Add hodograph
     ax = self._fig.add_axes([0.95, 0.71, 0.17, 0.17])
     h = Hodograph(ax, component_range=50)
     h.add_grid(increment=20)
     h.plot_colormapped(self.u_i[:index_p100], self.v_i[:index_p100], self.alt[:index_p100], linewidth=1.2)
     # Annotate parameters
     # Annotate names
     namelist = ['CAPE', 'CIN', 'MUCAPE', 'PWAT', 'K', 'A', 'SWEAT', 'LCL', 'LFC', 'EL', 'SI', 'LI', 'T850-500',
                 'θse850-500', 'SRH', 'STP']
     xcor = -50
     ycor = -90
     spacing = -9
     for nm in namelist:
         ax.text(xcor, ycor, '{}: '.format(nm), fontsize=10)
         ycor += spacing
     # Annotate values
     varlist = [cape, chi, mucape, pwat, k, a, sw, lcl_p, lfc_p, el_p, si, li, self.t_i[i8] - self.t_i[i5], thetadiff,
                srh_tot, sigtor]
     xcor = 10
     ycor = -90
     for v in varlist:
         if hasattr(v, 'magnitude'):
             v = v.magnitude
         ax.text(xcor, ycor, str(np.round_(v, 2)), fontsize=10)
         ycor += spacing
     # Annotate units
     unitlist = ['J/kg', 'J/kg', 'J/kg', 'mm', '°C', '°C', '', 'hPa', 'hPa', 'hPa', '°C', '°C', '°C', '°C']
     xcor = 45
     ycor = -90
     for u in unitlist:
         ax.text(xcor, ycor, ' {}'.format(u), fontsize=10)
         ycor += spacing
예제 #7
0
def do_profile(cursor, fid, gdf, nt):
    """Process this profile."""
    # The inbound profile may contain mandatory level data that is below
    # the surface.  It seems the best we can do here is to ensure both
    # temperature and dewpoint are valid and call that the bottom.
    td_profile = gdf[pd.notnull(gdf["tmpc"]) & pd.notnull(gdf["dwpc"])]
    wind_profile = gdf[pd.notnull(gdf["u"])]
    # Presently we are all or nothing here.  The length is arb
    if len(td_profile.index) < 5 or len(wind_profile.index) < 5:
        msg = ("quorum fail td: %s wind: %s, skipping") % (
            len(td_profile.index),
            len(wind_profile.index),
        )
        raise ValueError(msg)
    if gdf["pressure"].min() > 500:
        raise ValueError("Profile only up to %s mb" %
                         (gdf["pressure"].min(), ))
    # Does a crude check that our metadata station elevation is within 50m
    # of the profile bottom, otherwise we ABORT
    station_elevation_m = get_station_elevation(td_profile, nt)
    # get surface wind
    u_sfc, v_sfc = get_surface_winds(wind_profile)
    u_1km, v_1km = get_aloft_winds(wind_profile, station_elevation_m + 1000.0)
    u_3km, v_3km = get_aloft_winds(wind_profile, station_elevation_m + 3000.0)
    u_6km, v_6km = get_aloft_winds(wind_profile, station_elevation_m + 6000.0)
    shear_sfc_1km_smps = np.sqrt((u_1km - u_sfc)**2 + (v_1km - v_sfc)**2)
    shear_sfc_3km_smps = np.sqrt((u_3km - u_sfc)**2 + (v_3km - v_sfc)**2)
    shear_sfc_6km_smps = np.sqrt((u_6km - u_sfc)**2 + (v_6km - v_sfc)**2)

    total_totals = compute_total_totals(td_profile)
    sweat_index = compute_sweat_index(td_profile, total_totals)
    try:
        bunkers_rm, bunkers_lm, mean0_6_wind = bunkers_storm_motion(
            wind_profile["pressure"].values * units.hPa,
            wind_profile["u"].values * units("m/s"),
            wind_profile["v"].values * units("m/s"),
            wind_profile["height"].values * units("m"),
        )
    except ValueError:
        # Profile may not go up high enough
        bunkers_rm = [np.nan * units("m/s"), np.nan * units("m/s")]
        bunkers_lm = [np.nan * units("m/s"), np.nan * units("m/s")]
        mean0_6_wind = [np.nan * units("m/s"), np.nan * units("m/s")]
    bunkers_rm_smps = wind_speed(bunkers_rm[0], bunkers_rm[1])
    bunkers_rm_drct = wind_direction(bunkers_rm[0], bunkers_rm[1])
    bunkers_lm_smps = wind_speed(bunkers_lm[0], bunkers_lm[1])
    bunkers_lm_drct = wind_direction(bunkers_lm[0], bunkers_lm[1])
    mean0_6_wind_smps = wind_speed(mean0_6_wind[0], mean0_6_wind[1])
    mean0_6_wind_drct = wind_direction(mean0_6_wind[0], mean0_6_wind[1])
    try:
        (
            srh_sfc_1km_pos,
            srh_sfc_1km_neg,
            srh_sfc_1km_total,
        ) = storm_relative_helicity(
            wind_profile["u"].values * units("m/s"),
            wind_profile["v"].values * units("m/s"),
            wind_profile["height"].values * units("m"),
            1000.0 * units("m"),
        )
    except ValueError:
        srh_sfc_1km_pos = np.nan * units("m")  # blah
        srh_sfc_1km_neg = np.nan * units("m")  # blah
        srh_sfc_1km_total = np.nan * units("m")  # blah
    try:
        (
            srh_sfc_3km_pos,
            srh_sfc_3km_neg,
            srh_sfc_3km_total,
        ) = storm_relative_helicity(
            wind_profile["u"].values * units("m/s"),
            wind_profile["v"].values * units("m/s"),
            wind_profile["height"].values * units("m"),
            3000.0 * units("m"),
        )
    except ValueError:
        srh_sfc_3km_pos = np.nan * units("m")  # blah
        srh_sfc_3km_neg = np.nan * units("m")  # blah
        srh_sfc_3km_total = np.nan * units("m")  # blah
    pwater = precipitable_water(
        td_profile["dwpc"].values * units.degC,
        td_profile["pressure"].values * units.hPa,
    )
    (sbcape, sbcin) = surface_based_cape_cin(
        td_profile["pressure"].values * units.hPa,
        td_profile["tmpc"].values * units.degC,
        td_profile["dwpc"].values * units.degC,
    )
    (mucape, mucin) = most_unstable_cape_cin(
        td_profile["pressure"].values * units.hPa,
        td_profile["tmpc"].values * units.degC,
        td_profile["dwpc"].values * units.degC,
    )
    el_p, el_t = el(
        td_profile["pressure"].values * units.hPa,
        td_profile["tmpc"].values * units.degC,
        td_profile["dwpc"].values * units.degC,
    )
    lfc_p, lfc_t = lfc(
        td_profile["pressure"].values * units.hPa,
        td_profile["tmpc"].values * units.degC,
        td_profile["dwpc"].values * units.degC,
    )
    (lcl_p, lcl_t) = lcl(
        td_profile["pressure"].values[0] * units.hPa,
        td_profile["tmpc"].values[0] * units.degC,
        td_profile["dwpc"].values[0] * units.degC,
    )
    vals = [
        el_p.to(units("hPa")).m,
        lfc_p.to(units("hPa")).m,
        lcl_p.to(units("hPa")).m,
    ]
    [el_hght, lfc_hght, lcl_hght] = log_interp(
        np.array(vals, dtype="f"),
        td_profile["pressure"].values[::-1],
        td_profile["height"].values[::-1],
    )
    el_agl = gt1(el_hght - station_elevation_m)
    lcl_agl = gt1(lcl_hght - station_elevation_m)
    lfc_agl = gt1(lfc_hght - station_elevation_m)
    args = (
        nonull(sbcape.to(units("joules / kilogram")).m),
        nonull(sbcin.to(units("joules / kilogram")).m),
        nonull(mucape.to(units("joules / kilogram")).m),
        nonull(mucin.to(units("joules / kilogram")).m),
        nonull(pwater.to(units("mm")).m),
        nonull(el_agl),
        nonull(el_p.to(units("hPa")).m),
        nonull(el_t.to(units.degC).m),
        nonull(lfc_agl),
        nonull(lfc_p.to(units("hPa")).m),
        nonull(lfc_t.to(units.degC).m),
        nonull(lcl_agl),
        nonull(lcl_p.to(units("hPa")).m),
        nonull(lcl_t.to(units.degC).m),
        nonull(total_totals),
        nonull(sweat_index),
        nonull(bunkers_rm_smps.m),
        nonull(bunkers_rm_drct.m),
        nonull(bunkers_lm_smps.m),
        nonull(bunkers_lm_drct.m),
        nonull(mean0_6_wind_smps.m),
        nonull(mean0_6_wind_drct.m),
        nonull(srh_sfc_1km_pos.m),
        nonull(srh_sfc_1km_neg.m),
        nonull(srh_sfc_1km_total.m),
        nonull(srh_sfc_3km_pos.m),
        nonull(srh_sfc_3km_neg.m),
        nonull(srh_sfc_3km_total.m),
        nonull(shear_sfc_1km_smps),
        nonull(shear_sfc_3km_smps),
        nonull(shear_sfc_6km_smps),
        fid,
    )
    cursor.execute(
        """
        UPDATE raob_flights SET sbcape_jkg = %s, sbcin_jkg = %s,
        mucape_jkg = %s, mucin_jkg = %s, pwater_mm = %s,
        el_agl_m = %s, el_pressure_hpa = %s, el_tmpc = %s,
        lfc_agl_m = %s, lfc_pressure_hpa = %s, lfc_tmpc = %s,
        lcl_agl_m = %s, lcl_pressure_hpa = %s, lcl_tmpc = %s,
        total_totals = %s, sweat_index = %s,
        bunkers_rm_smps = %s, bunkers_rm_drct = %s,
        bunkers_lm_smps = %s, bunkers_lm_drct = %s,
        mean_sfc_6km_smps = %s, mean_sfc_6km_drct = %s,
        srh_sfc_1km_pos = %s, srh_sfc_1km_neg = %s, srh_sfc_1km_total = %s,
        srh_sfc_3km_pos = %s, srh_sfc_3km_neg = %s, srh_sfc_3km_total = %s,
        shear_sfc_1km_smps = %s, shear_sfc_3km_smps = %s,
        shear_sfc_6km_smps = %s,
        computed = 't' WHERE fid = %s
    """,
        args,
    )