[Weather] Python calculates advection and cartopy drawing (calculate difference, radian conversion, broadcast operation)

1. The total code:

import xarray as xr
import numpy as np

import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
import cartopy.mpl.ticker as cticker
from cartopy.util  import  add_cyclic_point

class T_advection(object):
    def __init__(self,file_u,file_v,file_t):
        self.f_u = xr.open_dataset(file_u)
        self.f_v = xr.open_dataset(file_v)
        self.f_t = xr.open_dataset(file_t)

        pass

    def cal_advection(self):
        a = 6370000
        u0 = self.f_u.uwnd.loc['2014-11-01',850,90:0,0:180]
        v0 = self.f_v.vwnd.loc['2014-11-01',850,90:0,0:180]
        t = self.f_t.air.loc['2014-11-01',850,90:0,0:180]
        lon0 = u0.lon
        lat0 = u0.lat
        dlon = (np.gradient(lon0)*np.pi/180).reshape((1,-1))
        dlat = (np.gradient(lat0)*np.pi/180).reshape((-1,1))
        coslat = (np.array(np.cos((lat0)*np.pi/180))).reshape((-1,1))
        dx = a*coslat*dlon
        dy = a*dlat
        temadvection0 = -(u0 * np.gradient(np.array(t),axis = 1)/dx + v0 * np.gradient(np.array(t),axis = 0)/dy)

        return lon0,lat0,u0,v0,temadvection0

    def draw_cmap_advection(self,lon,lat,u,v,temadvection):
        #设置投影范围
        proj = ccrs.PlateCarree(central_longitude=90)
        leftlon, rightlon, lowerlat, upperlat = (0,180,0,90)
        img_extent = [leftlon, rightlon, lowerlat, upperlat]

        #添加基础要素(海岸线、湖泊、坐标等)
        fig = plt.figure(figsize=(12,8))
        ax = fig.add_axes([0.1,0.1,0.8,0.8],projection=proj)
        ax.set_extent(img_extent,crs=ccrs.PlateCarree())
        ax.set_title('Nov2014 T adv',loc='center',fontsize=18)
        ax.set_title(r'units: 10$^-$$^5$ K/s',loc='right',fontsize=12)
        ax.add_feature(cfeature.COASTLINE.with_scale('50m'))
        ax.add_feature(cfeature.LAKES,alpha=0.5)
        ax.set_xticks(np.array([0,60,120,180]), crs=ccrs.PlateCarree())
        ax.set_yticks(np.array([0,30,60,90]), crs=ccrs.PlateCarree())
        ax.xaxis.set_major_formatter(cticker.LongitudeFormatter())
        ax.yaxis.set_major_formatter(cticker.LatitudeFormatter())

        #添加数据(quiver,contourf,colorbar)
        q1 = ax.quiver(lon[::3],lat[::3], u.values[::3,::3], v.values[::3,::3] ,pivot='mid',
        scale = 150,color='g',width=0.0038,headwidth=3, transform=ccrs.PlateCarree()) 
        ax.quiverkey(q1, X=0.9, Y=-0.12, U=15,label='15m/s', labelpos='E')
        c1 = ax.contourf(lon,lat, temadvection/1e-05, zorder=0,levels =np.arange(-5,5.5,0.5),extend = 'both', transform=ccrs.PlateCarree(), cmap=plt.cm.bwr)
        position=fig.add_axes([0.12, 0.12,  0.4, 0.02])
        fig.colorbar(c1,cax=position,orientation='horizontal',format='%.2f',)


        plt.savefig('T_advection.png')
    
        pass


#实例化对象
a = T_advection('/mnt/g/st_touchfish_py/data/uwnd.mon.mean.nc','/mnt/g/st_touchfish_py/data/vwnd.mon.mean.nc','/mnt/g/st_touchfish_py/data/air.mon.mean.nc')
lon1,lat1,u1,v1,temadvection1 = a.cal_advection()
a.draw_cmap_advection(lon1,lat1,u1,v1,temadvection1)

2. Analysis and precautions:

(1) The advection formula is as follows:

u and v can be directly obtained from the nc file, we only need to calculate dt, dx and dy.

( dx = a*coslat*dlon ; dy = a*dlat where a is the radius of the earth)

(2) Calculation of difference, radian conversion, broadcast operation

The np.gradient() function is used to calculate the difference, and the return value is an array of the same size as the input array.

It should be noted that when calculating in python, the angle system needs to be converted to radian system (method: angle*np.pi/180)

Therefore: dlon = (np.gradient(lon0)*np.pi/180)  

 Originally, this is fine, but since u and v in the formula are two-dimensional arrays, in order to perform operations with them, it is necessary to convert one-dimensional data into two-dimensional (ie: broadcast operation)

Therefore: dlon = (np.gradient(lon0)*np.pi/180).reshape((1,-1)) where 1 is to expand the 0th dimension, and -1 is to retain the 1st dimension.

Finally bring them into the formula calculation: temadvection0 = -(u0 * np.gradient(np.array(t), axis = 1)/dx + v0 * np.gradient(np.array(t), axis = 0)/ dy)

The drawing results are as follows:

Guess you like

Origin blog.csdn.net/Mluoo/article/details/128075821