使用Metpy将GFS风从等压线转换为高度坐标

我的任务是绘制各种大气层的风图以支持航空。虽然我可以使用GFS模型数据绘制一些漂亮的图(请参见下面的代码),但实际上我确实必须使用GFS提供的压力坐标来粗略估计高度。我使用300 hPA,700 hPA和925 hPA的风来近似于30,000 ft,9000 ft和3000 ft处的风。我的问题确实是针对那些身材高大的大师...一种可以将这些风插到高空表面的方法?在这些高度水平上获取实际风肯定会很好!感谢任何人可以就此主题进行交流!

import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
import numpy as np
from netCDF4 import num2date
from datetime import datetime,timedelta
from siphon.catalog import TDSCatalog
from siphon.ncss import NCSS
from PIL import Image
from matplotlib import cm


# For the vertical levels we want to grab with our queries
# Levels need to be in Pa not hPa
Levels = [30000,70000,92500]
# Time deltas for days
Deltas = [1,2,3]
#Deltas = [1]
# Levels in hPa for the file names
LevelDict = {30000:'300',70000:'700',92500:'925'}
# The path to where our banners are stored 
impath = 'C:\\Users\\shell\\Documents\\Python Scripts\\Banners\\'
# Final images saved here
imoutpath = 'C:\\Users\\shell\\Documents\\Python Scripts\\TVImages\\'

# Quick function for finding out which variable is the time variable in the
# netCDF files
def find_time_var(var,time_basename='time'):
    for coord_name in var.coordinates.split():
        if coord_name.startswith(time_basename):
            return coord_name
    raise ValueError('No time variable found for ' + var.name)

# Function to grab data at different levels from Siphon 
def grabdata(level):

    query.var = set()
    query.variables('u-component_of_wind_isobaric','v-component_of_wind_isobaric')
    query.vertical_level(level)
    data = ncss.get_data(query)
    u_wind_var = data.variables['u-component_of_wind_isobaric']
    v_wind_var = data.variables['v-component_of_wind_isobaric']
    time_var = data.variables[find_time_var(u_wind_var)]
    lat_var = data.variables['lat']
    lon_var = data.variables['lon']

    return u_wind_var,v_wind_var,time_var,lat_var,lon_var

# Construct a TDSCatalog instance pointing to the gfs dataset
best_gfs = TDSCatalog('http://thredds-jetstream.unidata.ucar.edu/thredds/catalog/grib/'
                      'NCEP/GFS/Global_0p5deg/catalog.xml')

# Pull out the dataset you want to use and look at the access URLs
best_ds = list(best_gfs.datasets.values())[1]
#print(best_ds.access_urls)

# Create NCSS object to access the NetcdfSubset
ncss = NCSS(best_ds.access_urls['NetcdfSubset'])
print(best_ds.access_urls['NetcdfSubset'])

# Looping through the forecast times

for delta in Deltas:
    # Create lat/lon box and the time(s) for location you want to get data for
    now = datetime.utcnow()
    fcst = now + timedelta(days = delta)
    timestamp = datetime.strftime(fcst,'%A')
    query = ncss.query()
    query.lonlat_box(north=78,south=45,east=-90,west=-220).time(fcst)
    query.accept('netcdf4')


    # Now looping through the levels to create our plots

    for level in Levels:
        u_wind_var,lon_var = grabdata(level)
        # Get actual data values and remove any size 1 dimensions
        lat = lat_var[:].squeeze()
        lon = lon_var[:].squeeze()
        u_wind = u_wind_var[:].squeeze()
        v_wind = v_wind_var[:].squeeze()
        #converting to knots
        u_windkt= u_wind*1.94384
        v_windkt= v_wind*1.94384
        wspd = np.sqrt(np.power(u_windkt,2)+np.power(v_windkt,2))

        # Convert number of hours since the reference time into an actual date
        time = num2date(time_var[:].squeeze(),time_var.units)
        print (time)
        # Combine 1D latitude and longitudes into a 2D grid of locations
        lon_2d,lat_2d = np.meshgrid(lon,lat)

        # Create new figure
        #fig = plt.figure(figsize = (18,12))
        fig = plt.figure()
        fig.set_size_inches(26.67,15)
        datacrs = ccrs.PlateCarree()
        plotcrs = ccrs.LambertConformal(central_longitude=-150,central_latitude=55,standard_parallels=(30,60))

        # Add the map and set the extent
        ax = plt.axes(projection=plotcrs)
        ext = ax.set_extent([-195.,-115.,50.,72.],datacrs)
        ext2 = ax.set_aspect('auto')
        ax.background_patch.set_fill(False)

        # Add state boundaries to plot
        ax.add_feature(cfeature.STATES,edgecolor='black',linewidth=2)

        # Add geopolitical boundaries for map reference
        ax.add_feature(cfeature.COASTLINE.with_scale('50m'))
        ax.add_feature(cfeature.OCEAN.with_scale('50m'))
        ax.add_feature(cfeature.LAND.with_scale('50m'),facecolor = '#cc9666',linewidth = 4)

        if level == 30000:
            spdrng_sped = np.arange(30,190,2)
            windlvl = 'Jet_Stream'
        elif level == 70000:
            spdrng_sped = np.arange(20,100,1)
            windlvl = '9000_Winds_Aloft'
        elif level == 92500:
            spdrng_sped = np.arange(20,80,1)
            windlvl = '3000_Winds_Aloft'
        else:
            pass


        top = cm.get_cmap('Greens')
        middle = cm.get_cmap('YlOrRd')
        bottom = cm.get_cmap('BuPu_r')
        newcolors = np.vstack((top(np.linspace(0,1,128)),middle(np.linspace(0,128))))
        newcolors2 = np.vstack((newcolors,bottom(np.linspace(0,128))))

        cmap = ListedColormap(newcolors2)
        cf = ax.contourf(lon_2d,lat_2d,wspd,spdrng_sped,cmap=cmap,transform=datacrs,extend = 'max',alpha=0.75)

        cbar = plt.colorbar(cf,orientation='horizontal',pad=0,aspect=50,drawedges = 'true')
        cbar.ax.tick_params(labelsize=16)
        wslice = slice(1,None,4)

        ax.quiver(lon_2d[wslice,wslice],lat_2d[wslice,u_windkt[wslice,v_windkt[wslice,width=0.0015,headlength=4,headwidth=3,angles='xy',color='black',transform = datacrs)

        plt.savefig(imoutpath+'TV_UpperAir'+LevelDict[level]+'_'+timestamp+'.png',bbox_inches= 'tight')

        # Now we use Pillow to overlay the banner with the appropriate day
        background = Image.open(imoutpath+'TV_UpperAir'+LevelDict[level]+'_'+timestamp+'.png')
        im = Image.open(impath+'Banner_'+windlvl+'_'+timestamp+'.png')

        # resize the image
        size = background.size
        im = im.resize(size,Image.ANTIALIAS)

        background.paste(im,(17,8),im)
        background.save(imoutpath+'TV_UpperAir'+LevelDict[level]+'_'+timestamp+'.png','PNG')

jiayoushixin 回答:使用Metpy将GFS风从等压线转换为高度坐标

感谢您的提问!我在这里的方法是为每个单独的列将GFS输出的“地势高度”的压力坐标插值到您提供的海拔高度上,以估计每个列的每个高度级别的压力。然后,我可以使用该压力将GFS输出u,v插值到。 GFS输出的GPH和风的压力坐标略有不同,这就是为什么我两次插值的原因。我使用MetPy的interpolate.log_interpolate_1d进行了插值,它对输入的对数执行了线性插值。这是我使用的代码!

<div>
    <BrowserRouter>
        <Route path="/University" component={University}/>
        <Redirect to="/University" />
    </BrowserRouter>
</div>

我能够从中获取输出,并将其强制转换为您的绘图代码(带有剥离的单元)。

Your 300-hPa GFS winds
My "30000-ft" GFS winds

Here是我在每个估算高度处的内插压力场的样子。

希望这会有所帮助!

,

我不确定这是否是您要寻找的东西(我对Metpy很陌生),但是我一直在使用metpy height_to_pressure_std(altitude)函数。它将其以hPa为单位,然后我将其转换为Pascals,然后转换为无单位值以在Siphon vertical_level(float)函数中使用。

本文链接:https://www.f2er.com/2511327.html

大家都在问