社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python提取WRF模拟的台风路径

happy科研 • 3 年前 • 1337 次点击  
WRF模式广泛应用于台风的模拟和预报,但是其并不能输出台风路径信息(除非编译的时候nesting选择vortex following选项,运行时会输出ATCF数据,不过这个不常用)。

因此使用WRF模拟台风,后处理需要解决如何从wrfout数据提取出台风路径的问题。NCL官网提供的脚本中,是以每个时刻海平面气压(SLP)最小处作为台风的中心位置,简单易行。但是在一些特定情况存在问题,比如双台风的时候。

为了避免上述的问题,提取台风在T时的位置时必须要参考T-1时刻的位置。即以T-1时刻台风的位置为圆心,给定半径radius确定一个圆,在此范围内寻找T时刻的台风位置。以下为具体的操作步骤:

(1)第1时刻,找到min(SLP)的的位置索引,然后提取台风中心经纬度(lonTC, latTC)。或者由观测或者最佳路径数据集给定模拟初始时刻的台风中心位置。

(2)第it个时刻,根据it-1时刻的台风中心位置(lonTC, latTC)计算it-1时刻的台风中心位置索引(ic, jc)。北纬30°以南,台风一般移动速度spd不超过0.5deg/hour,北纬30°以北一般不超过2.0deg/hour,wrfout输出时间间隔为history_interval(hours)。根据移速和输出间隔,计算台风最大移动半径radius=spd*history_interval。最大移动半径除以网格分辨率,得到移动半径所对应的索引半径indexRadius。根据索引半径确定台风所在的范围,此范围内的SLP最小处即是it时刻的台风中心位置。

T时刻的台风中心,应该在T-1时刻台风中心的附近,根据T时刻的SLP场在这个范围内的最小值位置,确定T时刻的台风中心



(3)遍历所有时刻,得到完整的台风路径,并且每一步可以保存最低气压Pmin,最大风速Vmax等信息。

以1713号台风天鸽(Hato)为例,进行模拟。WRF模式分辨率为15km,模拟起止时间:2017-08-21_00 至 2017-08-24_00 UTC。


从此次模拟结果看,基本模拟出了台风"天鸽"的大致走向,只是模拟的台风移速偏慢。
模拟的台风路径与观测对比

该算法需要使用海平面气压(SLP),但是WRF的输出数据中是没有海平面气压的,因此需要根据已有的气压和温度场等信息诊断得到SLP。使用wrf-python库的getvar函数可以直接实现这个功能,直接得到SLP。

PS1: 实际应用发现一个问题,WRF初始时刻诊断得到的SLP,台风中心特别不明显(甚至不存在)。如果模拟区域存在高山,比如台湾的山脉,则往往山脉的SLP最低,因此根据SLP最小确定台风的位置则容易出错,即导致台风位置错误的出现在高山上。因此初始时刻最好给定台风的大致位置,并且最大移动半径设置较小(<0.5°)。如果无法给出初始时刻的台风位置,可以跳过初始时刻,从第二个时刻开始。

初始时刻SLP诊断场,无明显的台风中心但实际上此时台风已经比较成熟。


初始时刻基于SLP最小确定台风中心位置,SLP场的结果较差导致台风位置出现在山脉。

PS2: 实际使用,如果双台风距离太近,台风之间的距离小于最大移动半径时,也可能会发生误判,此类情况可以缩小最大移动半径。

以下为全部代码:

import numpy as npimport netCDF4 as ncimport datetimefrom wrf import getvar, ALL_TIMES, to_npimport matplotlib.pyplot as pltimport cartopy.crs as ccrsfrom cartopy.io.shapereader import Readerimport cartopy.feature as cfeaturefrom cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatterimport pandas as pd
def nearest_position( stn_lat, stn_lon, lat2d, lon2d): """获取最临近格点坐标索引 stn_lat : 站点纬度 stn_lon : 站点经度 lat2d : numpy.ndarray网格二维经度坐标 lon2d : numpy.ndarray网格二维纬度坐标 Return: y_index, x_index """ difflat = stn_lat - lat2d; difflon = stn_lon - lon2d; rad = np.multiply(difflat,difflat)+np.multiply(difflon , difflon) aa=np.where(rad==np.min(rad)) ind=np.squeeze(np.array(aa)) return tuple(ind)
if __name__ == "__main__": # setting wrfout_dir = "wrf_wnp15km/wrfout_d01_2017-08-21_00:00:00" lonTC0 = 125.0 #台风初始时刻位置 latTC0 = 20.3
wrfout = nc.Dataset(wrfout_dir, mode="r") lat2D = to_np(getvar(wrfout, "lat" )) # units: decimal degrees lon2D = to_np(getvar(wrfout, "lon" )) # units: decimal degrees times = to_np(getvar(wrfout, "times", timeidx=ALL_TIMES)) # nt = len(times) ny, nx = np.shape(lat2D)
date0 = datetime.datetime.strptime(str(times[0])[0:19], "%Y-%m-%dT%H:%M:%S") date1 = datetime.datetime.strptime(str(times[1])[0:19], "%Y-%m-%dT%H:%M:%S") history_interval = (date1 - date0).total_seconds()/3600 #hours
lonMax = np.max(lon2D) lonMin = np.min(lon2D) latMax = np.max(lat2D) latMin = np.min(lat2D)
date = [] # 2020-07-20T00 lons = [] # degree lats = [] # degree pmin = [] # hPa vmax = [] # m/s
lonTC = lonTC0 latTC = latTC0
for it in range(nt): slp = to_np(getvar(wrfout ,"slp" ,units="hPa" ,timeidx=it)) wspd_wdir10 = to_np(getvar(wrfout ,"wspd_wdir10" ,units="m s-1" ,timeidx=it)) wspd10 = wspd_wdir10[0]
if it==0 : # 如果给定了初始时刻的TC位置,则使用给定的TC位置 # 未给定初始时刻TC位置,则取全场slp最小的位置为TC中心 if latTC0 > -60.0 : latTC = latTC0 lonTC = lonTC0 #lons.append(round(lonTC,2)) #lats.append(round(latTC,2)) #continue else: slpMin = np.min(slp[:,:]) indexMin = np.argwhere(slp[:,:] == slpMin) jTC = indexMin[0][0] iTC = indexMin[0][1] lonTC = lon2D[jTC,iTC] latTC = lat2D[jTC,iTC]
### 1 找到TC中心(lonTC, latTC)的索引(iTC, jTC) indexTC = nearest_position(latTC, lonTC, lat2D, lon2D) jTC = indexTC[0] iTC = indexTC[1] # 避免台风中心选在边界点 jTC = np.max((1,jTC)) # jTC [1,ny-2] jTC = np.min((jTC,ny-2)) iTC = np.max((1,iTC)) # iTC [1,nx-2] iTC = np.min((iTC,nx-2))
### 2 计算TC center附近的网格分辨率dAvg, dLat = lat2D[jTC+1,iTC] - lat2D[jTC,iTC] dLon = lon2D[jTC,iTC+1] - lon2D[jTC,iTC] dAvg = (dLat + dLon)/2.0
### 3 根据移速计算台风中心最大可能半径,根据这个 if latTC < 30.0 : # 纬度30°以南,台风移速每小时0.5° radius = 0.5*history_interval # 0.5 degree/hour else: # 纬度30°以北,台风移速每小时1.0° radius = 1.0*history_interval # 1.0 degree/hour radius = 0.5*history_interval # 0.5 degree/hour radius = 1.0*history_interval # 1.0 degree/hour if it==0 : radius = 0.5 indexRadius = int(radius/dAvg) + 1
### 找到最大可能半径内,slp最小值及其位置索引 iStart = iTC - indexRadius iEnd = iTC + indexRadius jStart = jTC - indexRadius jEnd = jTC + indexRadius jStart = np.max((1,jStart)) jEnd = np.min((jEnd,ny-2)) iStart = np.max((1,iStart)) iEnd = np.min((iEnd,nx-2))
slpMin = np.min(slp[jStart:jEnd,iStart:iEnd]) w10Max = np.max(wspd10[jStart:jEnd,iStart:iEnd]) indexMin = np.argwhere(slp[jStart:jEnd,iStart:iEnd] == slpMin) jTC = indexMin[0][0] + jStart iTC = indexMin[0][1] + iStart lonTC = lon2D[jTC,iTC] latTC = lat2D[jTC,iTC] print("date:", str(times[it])[0:19],"TC center:",round(lonTC,2), round(latTC,2)," p min:",round(slpMin,2), " vmax:",round(w10Max,2)) date.append(str(times[it])[0:19]) lons.append(round(lonTC,2)) lats.append(round(latTC,2)) pmin.append(round(slpMin,2)) vmax.append(round(w10Max,2))
#read CMA-STI best track f_Con = 'cma_bst_hato.txt' col_names =['date','grade','lat', 'lon', 'pres', 'vmax'] widths = [10,2,4,5,4,3] df = pd.read_fwf(f_Con,usecols=[0,1,2,3,4,5],widths=widths,names=col_names) latObs = df['lat'].values[:] lonObs = df['lon'].values[:] latObs = np.array(latObs)/10 lonObs = np.array(lonObs)/10
### plot track fig = plt.figure() ax = plt.axes(projection=ccrs.PlateCarree()) ax.set_extent([lonMin, lonMax, latMin, latMax],crs=ccrs.PlateCarree()) xticks = np.linspace(lonMin, lonMax, 6, endpoint=True) yticks = np.linspace(latMin, latMax, 6, endpoint=True) ax.set_xticks(xticks, crs=ccrs.PlateCarree()) ax.set_yticks(yticks, crs=ccrs.PlateCarree()) lon_formatter = LongitudeFormatter(zero_direction_label=False) lat_formatter = LatitudeFormatter() ax.xaxis.set_major_formatter(lon_formatter) ax.yaxis.set_major_formatter(lat_formatter) ax.gridlines() ax.coastlines() for it in range(1,len(lons)): if it == 1: plt.plot((lons[it-1],lons[it]), (lats[it-1],lats[it]),color='red',linewidth=1.5,transform=ccrs.PlateCarree(), label="wrf") else: plt.plot((lons[it-1],lons[it]), (lats[it-1],lats[it]),color='red',linewidth=1.5,transform=ccrs.PlateCarree()) for it in range(1,len(lonObs)): if it == 1: plt.plot((lonObs[it-1],lonObs[it]), (latObs[it-1],latObs[it]),color='black',linewidth=2,transform=ccrs.PlateCarree(), label="obs") else: plt.plot((lonObs[it-1],lonObs[it]), (latObs[it-1],latObs[it]),color='black',linewidth=2,transform=ccrs.PlateCarree()) plt.legend() plt.show()

    

  关注下方公众号,获取更多大气海洋领域的内容。

往  期  推  荐
WRF模式安装
WRFChem的安装
WRF嵌套方式总结
MPAS-A模式的介绍
WRFDA的Little R格式介绍
ROMS区域海洋模式的安装和运行
WRF中使用SRTM高分辨率的地形资料
构建适合大气与海洋应用的Anaconda环境
WRF后处理:降雨量的说明以及降雨的绘制
python爬取中央气象台台风网当前台风实况和预报数据
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/120250
 
1337 次点击