Esempio n. 1
0
def test_pressure_to_heights_basic(array_type):
    """Test basic pressure to height calculation for standard atmosphere."""
    mask = [False, True, False, True]
    pressures = array_type([975.2, 987.5, 956., 943.], 'mbar', mask=mask)
    heights = pressure_to_height_std(pressures)
    values = array_type([321.5, 216.5, 487.6, 601.7], 'meter', mask=mask)
    assert_array_almost_equal(heights, values, 1)
Esempio n. 2
0
 def p2h(x):
     """
  x in hPa
  """
     y = mpcalc.pressure_to_height_std(np.array(x) * units.hPa)
     # y = y.metpy.convert_units('m')
     y = y.to('m')
     return y.magnitude
Esempio n. 3
0
def pressure_to_height(target_p, hgt3D, targetdir=".", debug=False):

    junktime = datetime.datetime(2015, 1, 1)
    surface_height = scalardata('surface_height',
                                junktime,
                                targetdir=targetdir,
                                debug=debug)

    lcl_height_MSL = pressure_to_height_std(target_p)

    # subtract surface geopotential height to get height AGL
    # switch from xarray to pint quantities for now.
    lcl_height_AGL = lcl_height_MSL - surface_height.metpy.unit_array

    lv_ISBL0 = hgt3D.lv_ISBL0.metpy.unit_array

    # subtract pint quantities. surface_height broadcasted to multiple vertical levels in hgt3D
    AGL3D = hgt3D.metpy.unit_array - surface_height.metpy.unit_array

    shp = target_p.shape
    nz = len(lv_ISBL0)
    junk = np.empty(shp)
    for i, p in enumerate(target_p.metpy.unit_array.flatten()):
        ituple = np.unravel_index(
            i, shp)  # 277 lat , 349 lon  - ituple may have 2 or 3 dims
        # interpolate linearly in ln(p). convert to same units, remove units, before applying natural log
        lclinterp = np.interp(np.log(p.to('hPa').m),
                              np.log(lv_ISBL0.to('hPa').m),
                              AGL3D[:, ituple[-2], ituple[-1]])
        if not hasattr(lclinterp, "units"):
            # TODO: figure out why lclinterp sometimes has and sometimes doesn't have this attribute.
            lclinterp *= AGL3D.units  # Prior to pint 0.11 np.interp lost units
        if debug:  # this slows things down
            if np.abs(lclinterp - lcl_height_AGL[ituple]) > 415 * munits.meter:
                print('ituple={} lclinterp={} lclstd={}'.format(
                    ituple, lclinterp, lcl_height_AGL[ituple]))
                pdb.set_trace()
        # strip units with .m magnitude attribute or get ValueError: setting an array element with a sequence.
        junk[
            ituple] = lclinterp.m  # this is slow if you update an xarray. speed things up by updating a ndarray.

    # Change pint quantity to xarray
    attrs = hgt3D.attrs
    # Units were stripped earlier from lclinterp. Make they are what was expected.
    assert attrs["units"] == lclinterp.units or (attrs["units"] == "gpm" and
                                                 lclinterp.units == "meter")
    #attrs['units'] = lclinterp.units # replaces 'gpm' with 'meters'. TODO: figure out why this causes AttributeError: 'NoneType' object has no attribute 'evaluate' later when significant tornado function is called.
    lcl_height_AGL = xarray.DataArray(data=junk,
                                      coords=target_p.coords,
                                      dims=target_p.dims,
                                      name='lcl_height_AGL',
                                      attrs=attrs)
    lcl_height_AGL.attrs['long_name'] = 'lifted condensation level height AGL'
    return lcl_height_AGL
Esempio n. 4
0
def test_pressure_to_heights_units():
    """Test that passing non-mbar units works."""
    assert_almost_equal(pressure_to_height_std(29 * units.inHg),
                        262.859 * units.meter, 3)
Esempio n. 5
0
def test_pressure_to_heights_basic():
    """Test basic pressure to height calculation for standard atmosphere."""
    pressures = np.array([975.2, 987.5, 956., 943.]) * units.mbar
    heights = pressure_to_height_std(pressures)
    values = np.array([321.5, 216.5, 487.6, 601.7]) * units.meter
    assert_almost_equal(heights, values, 1)
Esempio n. 6
0
def get_bounds_data():
    """Provide pressure and height data for testing layer bounds calculation."""
    pressures = np.linspace(1000, 100, 10) * units.hPa
    heights = pressure_to_height_std(pressures)
    return pressures, heights
Esempio n. 7
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. 8
0
def get_bounds_data():
    """Provide pressure and height data for testing layer bounds calculation."""
    pressures = np.linspace(1000, 100, 10) * units.hPa
    heights = pressure_to_height_std(pressures)
    return pressures, heights
Esempio n. 9
0
def test_pressure_to_heights_units():
    """Test that passing non-mbar units works."""
    assert_almost_equal(pressure_to_height_std(29 * units.inHg), 262.859 * units.meter, 3)
Esempio n. 10
0
def test_pressure_to_heights_basic():
    """Test basic pressure to height calculation for standard atmosphere."""
    pressures = np.array([975.2, 987.5, 956., 943.]) * units.mbar
    heights = pressure_to_height_std(pressures)
    values = np.array([321.5, 216.5, 487.6, 601.7]) * units.meter
    assert_almost_equal(heights, values, 1)
Esempio n. 11
0
def skewt_plot(p,
               tc,
               tdc,
               t0,
               date,
               u=None,
               v=None,
               fout='sounding.png',
               latlon='',
               title='',
               show=False):
    """
   h: heights
   p: pressure
   tc: Temperature [C]
   tdc: Dew point [C]
   date: date of the forecast
   u,v: u,v wind components
   adapted from:
   https://geocat-examples.readthedocs.io/en/latest/gallery/Skew-T/NCL_skewt_3_2.html#sphx-glr-gallery-skew-t-ncl-skewt-3-2-py
   """
    Pmax = 150  # XXX upper limit
    print('Checking units')
    if p.attrs['units'] != 'hPa':
        print('P wrong units')
        exit()
    if tc.attrs['units'] != 'degC':
        print('Tc wrong units')
        exit()
    if tdc.attrs['units'] != 'degC':
        print('Tdc wrong units')
        exit()
    if t0.attrs['units'] != 'degC':
        print('T0 wrong units')
        exit()
    if type(u) != type(None) and type(v) != type(None):
        if u.attrs['units'] != 'm s-1':
            print('Wind wrong units')
            exit()
    LG.info('Inside skewt plot')
    p = p.values
    tc = tc.values
    tdc = tdc.values
    t0 = t0.mean().values
    u = u.values * 3.6  # km/h
    v = v.values * 3.6  # km/h
    # Grid plot
    LG.info('creating figure')
    fig = plt.figure(figsize=(11, 12))
    LG.info('created figure')
    LG.info('creating axis')
    gs = gridspec.GridSpec(1, 2, width_ratios=[4, 1])
    fig.subplots_adjust(wspace=0., hspace=0.)
    # ax1 = plt.subplot(gs[1:-1,0])
    # Adding the "rotation" kwarg will over-ride the default MetPy rotation of
    # 30 degrees for the 45 degree default found in NCL Skew-T plots
    LG.info('created axis')
    LG.info('Creatin SkewT')
    skew = SkewT(fig, rotation=45, subplot=gs[0, 0])
    ax = skew.ax
    LG.info('Created SkewT')

    if len(latlon) > 0:
        ax.text(0,
                1,
                latlon,
                va='top',
                ha='left',
                color='k',
                fontsize=12,
                bbox=dict(boxstyle="round", ec=None, fc=(1., 1., 1., 0.9)),
                zorder=100,
                transform=ax.transAxes)
    # Plot the data, T and Tdew vs pressure
    skew.plot(p, tc, 'C3')
    skew.plot(p, tdc, 'C0')
    LG.info('plotted dew point and sounding')

    # LCL
    lcl_pressure, lcl_temperature = mpcalc.lcl(p[0] * units.hPa,
                                               t0 * units.degC,
                                               tdc[0] * units.degC)
    skew.plot(lcl_pressure, lcl_temperature, 'k.')

    # Calculate the parcel profile  #XXX units workaround
    parcel_prof = mpcalc.parcel_profile(p * units.hPa, t0 * units.degC,
                                        tdc[0] * units.degC).to('degC')
    # Plot cloud base
    ind_cross = np.argmin(np.abs(parcel_prof.magnitude - tc))
    p_base = np.max([lcl_pressure.magnitude, p[ind_cross]])
    t_base = np.max([lcl_temperature.magnitude, tc[ind_cross]])
    m_base = mpcalc.pressure_to_height_std(np.array(p_base) * units.hPa)
    m_base = m_base.to('m').magnitude
    skew.ax.axhline(p_base, color=(0.5, 0.5, 0.5), ls='--')
    skew.plot(p_base, t_base, 'C3o', zorder=100)
    skew.ax.text(t_base, p_base, f'{m_base:.0f}m', ha='left')

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

    # shade CAPE and CIN
    skew.shade_cape(p * units.hPa, tc * units.degC, parcel_prof)
    skew.shade_cin(p * units.hPa, tc * units.degC, parcel_prof,
                   tdc * units.degC)
    LG.info('plotted CAPE and CIN')

    if type(u) != type(None) and type(v) != type(None):
        LG.info('Plotting wind')
        ax2 = plt.subplot(gs[0, 1], sharey=ax, zorder=-1)
        # ax2.yaxis.set_visible(False)
        ax2.yaxis.tick_right()
        # ax2.xaxis.tick_top()
        wspd = np.sqrt(u * u + v * v)
        ax2.scatter(wspd, p, c=p, cmap=HEIGHTS, zorder=10)
        gnd = mpcalc.pressure_to_height_std(np.array(p[0]) * units.hPa)
        gnd = gnd.to('m')
        # Ground
        ax2.axhline(p[0], c='k', ls='--')
        ax2.text(56,
                 p[0],
                 f'{int(gnd.magnitude)}m',
                 horizontalalignment='right')
        # Techo
        ax2.axhline(p_base, c=(0.5, 0.5, 0.5), ls='--')
        ### Background colors ##
        #for i,c in enumerate(WindSpeed.colors):
        #   rect = Rectangle((i*4, 150), 4, 900,  color=c, alpha=0.5,zorder=-1)
        #   ax2.add_patch(rect)
        #########################
        ax2.set_xlim(0, 56)
        ax2.set_xlabel('Wspeed (km/h)')
        ax2.grid()

        def p2h(x):
            """
         x in hPa
         """
            y = mpcalc.pressure_to_height_std(np.array(x) * units.hPa)
            # y = y.metpy.convert_units('m')
            y = y.to('m')
            return y.magnitude

        def h2p(x):
            """
         x in m
         """
            # x = x.values
            y = mpcalc.height_to_pressure_std(np.array(x) * units.m)
            # y = y.metpy.convert_units('hPa')
            y = y.to('hPa')
            return y.magnitude

        # print('------')
        # print(p[0])
        # print('---')
        # print(p2h(p[0]))
        # print('---')
        # print(h2p(p2h(p[0])))
        # print('------')
        # exit()

        ax2y = ax2.secondary_yaxis(1.02, functions=(p2h, h2p))
        ax2y.set_ylabel('height (m)')
        # ax2y.set_yticks(np.array([1000,2000,3000,4000,6000,6000,10000]))
        # XXX Not working
        ax2y.yaxis.set_major_formatter(ScalarFormatter())
        ax2y.yaxis.set_minor_formatter(ScalarFormatter())
        #################
        ax2y.set_color('red')
        ax2y.tick_params(colors='red', size=7, width=1,
                         which='both')  # 'both' refers to minor and major axes
        # ax2y.set_yticks([1,2,3,4])
        #ax2.set_xticks([0,5,10,15,20,30,40,50])
        #ax2.set_xticklabels(['0','','10','','20','30','40','50'])
        ax2.set_xticks([0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 56])
        ax2.set_xticklabels(
            ['0', '', '8', '', '16', '', '24', '32', '40', '48', '56'],
            fontsize=11,
            va='center')
        plt.setp(ax2.get_yticklabels(), visible=False)
        # Hodograph
        ax_hod = inset_axes(ax2, '110%', '30%', loc=1)
        ax_hod.set_yticklabels([])
        ax_hod.set_xticklabels([])
        L = 80
        ax_hod.text(0,
                    L - 5,
                    'N',
                    horizontalalignment='center',
                    verticalalignment='center')
        ax_hod.text(L - 5,
                    0,
                    'E',
                    horizontalalignment='center',
                    verticalalignment='center')
        ax_hod.text(-(L - 5),
                    0,
                    'W',
                    horizontalalignment='center',
                    verticalalignment='center')
        ax_hod.text(0,
                    -(L - 5),
                    'S',
                    horizontalalignment='center',
                    verticalalignment='center')
        h = Hodograph(ax_hod, component_range=L)
        h.add_grid(increment=20)
        h.plot_colormapped(
            -u, -v, p, cmap=HEIGHTS
        )  #'viridis_r')  # Plot a line colored by pressure (altitude)
        LG.info('Plotted wind')

        # # print('=-=-=-=-=-=-=')
        # # print(ax2.get_yscale())
        # # print(ax2y.get_yscale())
        # # print('=-=-=-=-=-=-=')
        # # ax2y.yaxis.tick_right()
        # # # ax2y.set_ylim(*reversed(ax.get_ylim()))
        # # ax2y.set_ylim(*ax.get_ylim())
        # # # calc pressure to height
        # # locs = ax2.get_yticks()
        # # labels = [mpcalc.pressure_to_height_std(h*units.hPa) for h in locs]
        # # labels = [round(l.to('m'),1) for l in labels]
        # # for xp,xh in zip(locs,labels):
        # #    print(xp,xh)
        # # ax2y.set_yticks(locs)
        # # ax2y.set_yticklabels([f'{int(l.magnitude)}' for l in labels])
        # Plot only every n windbarb
        n = 4
        inds, = np.where(p > Pmax)
        break_p = 25
        inds_low = inds[:break_p]
        inds_high = inds[break_p:]
        inds = np.append(inds_low[::n], inds_high)
        skew.plot_barbs(
            pressure=p[inds],  #[::n], # * units.hPa,
            u=u[inds],  #[::n],
            v=v[inds],  #[::n],
            xloc=0.985,  # fill_empty=True,
            sizes=dict(emptybarb=0.075, width=0.1, height=0.2))
    # #    # Draw line underneath wind barbs
    # #    line = mlines.Line2D([1.05, 1.05], [0, 1], color='gray', linewidth=0.5,
    # #                         transform=ax.transAxes,
    # #                         dash_joinstyle='round',
    # #                         clip_on=False,
    # #                         zorder=0)
    # #    ax.add_line(line)

    # Add relevant special lines
    # Choose starting temperatures in Kelvin for the dry adiabats
    LG.info('Plot adiabats, and other grid lines')
    skew.ax.text(t0, p[0], f'{t0:.1f}°C', va='top')
    skew.ax.axvline(t0, color=(0.5, 0.5, 0.5), ls='--')
    t0 = units.K * np.arange(243.15, 473.15, 10)
    skew.plot_dry_adiabats(t0=t0,
                           linestyles='solid',
                           colors='gray',
                           linewidth=1)

    # Choose temperatures for moist adiabats
    t0 = units.K * np.arange(281.15, 306.15, 4)
    msa = skew.plot_moist_adiabats(t0=t0,
                                   linestyles='solid',
                                   colors='lime',
                                   linewidths=.75)

    # Choose mixing ratios
    w = np.array([0.001, 0.002, 0.003, 0.005, 0.008, 0.012,
                  0.020]).reshape(-1, 1)

    # Choose the range of pressures that the mixing ratio lines are drawn over
    p_levs = units.hPa * np.linspace(1000, 400, 7)
    skew.plot_mixing_lines(mixing_ratio=w,
                           pressure=p_levs,
                           linestyle='dotted',
                           linewidths=1,
                           colors='lime')

    LG.info('Plotted adiabats, and other grid lines')

    skew.ax.set_ylim(1000, Pmax)
    skew.ax.set_xlim(-20, 43)
    # skew.ax.set_xlim(-30, 40)
    # XXX gvutil not installed
    # gvutil.set_titles_and_labels(ax, maintitle="ATS Rawinsonde: degC + Thin wind")
    # Set axes limits and ticks
    # gvutil.set_axes_limits_and_ticks(ax=ax, xlim=[-30, 50],
    #                 yticks=[1000, 850, 700, 500, 400, 300, 250, 200, 150, 100])

    # Change the style of the gridlines
    ax.grid(True,
            which='major',
            axis='both',
            color='tan',
            linewidth=1.5,
            alpha=0.5)

    ax.set_xlabel("Temperature (C)")
    ax.set_ylabel("P (hPa)")
    if len(title) == 0:
        title = f"{(date).strftime('%d/%m/%Y-%H:%M')} (local time)"
        ax.set_title(title, fontsize=20)
    else:
        ax.set_title(title, fontsize=20)
    if show: plt.show()
    LG.info('saving')
    fig.savefig(fout, bbox_inches='tight', pad_inches=0.1, dpi=150, quality=90)
    LG.info('saved')
    plt.close('all')
Esempio n. 12
0
def delta_height(p1, p2):
    h1 = mpcalc.pressure_to_height_std(p1)
    h2 = mpcalc.pressure_to_height_std(p2)
    return h2 - h1