Python | 计算位涡平流项

news2024/11/22 20:59:30

写在前面

最近忙着复习、考试…都没怎么空敲代码,还得再准备一周考试。。。等考完试再慢慢更新了,今天先来浅更一个简单但是使用的python code


  • 在做动力机制分析时,我们常常需要借助收支方程来诊断不同过程的贡献,其中最常见的一项就包括水平平流项,如下所示,其中var表示某一个变量,V表示水平风场。

− V ⋅ ∇ v a r -V\cdot\mathbf{\nabla}var Vvar

以位涡的水平平流项为例,展开为

− ( u ∂ p v ∂ x + v ∂ p v ∂ y ) -(u\frac{\partial pv}{\partial x}+v\frac{\partial pv}{\partial y}) (uxpv+vypv)

其物理解释为:

  • 位涡受背景气流的调控作用。在存在背景气流的情况下,这个位涡信号受到多少平流的贡献

对于这种诊断量的计算,平流项,散度项,都可以通过metpy来计算。之前介绍过一次,因为metpy为大大简便了计算

advection

但是,如果这样还是不放心应该怎么办呢,这里可以基于numpy的方式自己来手动计算平流项,然后比较两种方法的差异。下面我就从两种计算方式以及检验方式来计算pv的水平平流项

首先来导入基本的库和数据,我这里用的wrf输出的风场以及位涡pv,同时,为了减少计算量,对于数据进行区域和高度层的截取

  • 经纬度可以直接从nc数据中获取,我下面是之前的代码直接拿过来用了,还是以wrf*out数据来提取的lon&lat
import numpy as np
import pandas as pd
import xarray as xr
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import glob
from matplotlib.colors import ListedColormap 
from wrf import getvar,pvo,interplevel,destagger,latlon_coords
from cartopy.mpl.ticker import LongitudeFormatter,LatitudeFormatter
from netCDF4 import Dataset
import matplotlib as mpl   
from metpy.units import units
import metpy.constants as constants
import metpy.calc as mpcalc
import cmaps
# units.define('PVU = 1e-6 m^2 s^-1 K kg^-1 = pvu')
import cartopy.feature as cfeature
f_w   = r'L:\JAS\wind.nc'
f_pv  = r'L:\JAS\pv.nc'
def  cal_dxdy(file):
    ncfile = Dataset(file)
    P = getvar(ncfile, "pressure")
    lats, lons = latlon_coords(P)
    lon = lons[0]
    lon[lon<=0]=lon[lon<=0]+360
    lat = lats[:,0]
    dx, dy = mpcalc.lat_lon_grid_deltas(lon.data, lat.data)
    return lon,lat,dx,dy
path  = r'L:\\wrf*'
filelist = glob.glob(path)
filelist.sort()
lon,lat,_,_ = cal_dxdy(filelist[-1]) 
dw = xr.open_dataset(f_w).sel(level=850,lat=slice(0,20),lon=slice(100,150))
dp = xr.open_dataset(f_pv).sel(level=850,lat=slice(0,20),lon=slice(100,150))
u = dw.u.sel(lat=slice(0,20),lon=slice(100,150))
v = dw.v.sel(lat=slice(0,20),lon=slice(100,150))
pv = dp.pv.sel(lat=slice(0,20),lon=slice(100,150))
lon = u.lon
lat = u.lat

metpy

###############################################################################
#####                  
#####                      using metpy to calculate advection
#####
###############################################################################
tadv = mpcalc.advection(pv*units('pvu'), u*units('m/s'), v*units('m/s'))
print(tadv)
###############################################################################
#####                  
#####                       plot advection
#####
###############################################################################
# start figure and set axis
fig, (ax) = plt.subplots(1, 1, figsize=(8, 6),dpi=200, subplot_kw={'projection': ccrs.PlateCarree()})
proj = ccrs.PlateCarree()
# plot isotherms
cs = ax.contour(lon, lat, pv[-1]*10**4, 8, 
            colors='k',
              linewidths=0.2)
ax.coastlines('10m',linewidths=0.5,facecolor='w',edgecolor='k')
box = [100,121,0,20]
ax.set_extent(box,crs=ccrs.PlateCarree())
ax.set_xticks(np.arange(box[0],box[1], 10), crs=proj)
ax.set_yticks(np.arange(box[2], box[3], 5), crs=proj)
ax.xaxis.set_major_formatter(LongitudeFormatter())
ax.yaxis.set_major_formatter(LatitudeFormatter())
# plot tmperature advection and convert units to Kelvin per 3 hours
cf = ax.contourf(lon, lat,   tadv[10]*10**4, 
                 np.linspace(-4, 4, 21), extend='both',
                 cmap='RdYlGn', alpha=0.75)
plt.colorbar(cf, pad=0.05, aspect=20,shrink=0.75)
ax.set_title('PV Advection Calculation')
plt.show()

pv advection with metpy

metpy官网也提供了计算示例:

  • https://unidata.github.io/MetPy/latest/examples/calculations/Advection.html

当然,这里需要提醒的是,在使用metpy计算时,最好是将变量带上单位,这样可以保证计算结果的量级没有问题;或者最后将其转换为国际基本单位:m , s ,g ...

关于metpt中单位unit的使用,可以在官网进行查阅:

  • https://unidata.github.io/MetPy/latest/tutorials/unit_tutorial.html
Lf = 1000 * units('J/kg')
print(Lf, Lf.to_base_units(), sep='\n')

1000.0 joule / kilogram
1000.0 meter ** 2 / second ** 2

units convert

当然,还可以点击 source code 去了解这个函数背后的计算过程:

  • https://github.com/Unidata/MetPy/blob/v1.6.2/src/metpy/calc/kinematics.py#L359-L468
def advection(
    scalar,
    u=None,
    v=None,
    w=None,
    *,
    dx=None,
    dy=None,
    dz=None,
    x_dim=-1,
    y_dim=-2,
    vertical_dim=-3,
    parallel_scale=None,
    meridional_scale=None
):
    r"""Calculate the advection of a scalar field by 1D, 2D, or 3D winds.

    If ``scalar`` is a `xarray.DataArray`, only ``u``, ``v``, and/or ``w`` are required
    to compute advection. The horizontal and vertical spacing (``dx``, ``dy``, and ``dz``)
    and axis numbers (``x_dim``, ``y_dim``, and ``z_dim``) are automatically inferred from
    ``scalar``. But if ``scalar`` is a `pint.Quantity`, the horizontal and vertical
    spacing ``dx``, ``dy``, and ``dz`` needs to be provided, and each array should have one
    item less than the size of ``scalar`` along the applicable axis. Additionally, ``x_dim``,
    ``y_dim``, and ``z_dim`` are required if ``scalar`` does not have the default
    [..., Z, Y, X] ordering. ``dx``, ``dy``, ``dz``, ``x_dim``, ``y_dim``, and ``z_dim``
    are keyword-only arguments.

    ``parallel_scale`` and ``meridional_scale`` specify the parallel and meridional scale of
    map projection at data coordinate, respectively. They are optional when (a)
    `xarray.DataArray` with latitude/longitude coordinates and MetPy CRS are used as input
    or (b) longitude, latitude, and crs are given. If otherwise omitted, calculation
    will be carried out on a Cartesian, rather than geospatial, grid. Both are keyword-only
    arguments.

    Parameters
    ----------
    scalar : `pint.Quantity` or `xarray.DataArray`
        The quantity (an N-dimensional array) to be advected.
    u : `pint.Quantity` or `xarray.DataArray` or None
        The wind component in the x dimension. An N-dimensional array.
    v : `pint.Quantity` or `xarray.DataArray` or None
        The wind component in the y dimension. An N-dimensional array.
    w : `pint.Quantity` or `xarray.DataArray` or None
        The wind component in the z dimension. An N-dimensional array.

    Returns
    -------
    `pint.Quantity` or `xarray.DataArray`
        An N-dimensional array containing the advection at all grid points.

    Other Parameters
    ----------------
    dx: `pint.Quantity` or None, optional
        Grid spacing in the x dimension.
    dy: `pint.Quantity` or None, optional
        Grid spacing in the y dimension.
    dz: `pint.Quantity` or None, optional
        Grid spacing in the z dimension.
    x_dim: int or None, optional
        Axis number in the x dimension. Defaults to -1 for (..., Z, Y, X) dimension ordering.
    y_dim: int or None, optional
        Axis number in the y dimension. Defaults to -2 for (..., Z, Y, X) dimension ordering.
    vertical_dim: int or None, optional
        Axis number in the z dimension. Defaults to -3 for (..., Z, Y, X) dimension ordering.
    parallel_scale : `pint.Quantity`, optional
        Parallel scale of map projection at data coordinate.
    meridional_scale : `pint.Quantity`, optional
        Meridional scale of map projection at data coordinate.

    Notes
    -----
    This implements the advection of a scalar quantity by wind:

    .. math:: -\mathbf{u} \cdot \nabla = -(u \frac{\partial}{\partial x}
              + v \frac{\partial}{\partial y} + w \frac{\partial}{\partial z})

    .. versionchanged:: 1.0
       Changed signature from ``(scalar, wind, deltas)``

    """
    # Set up vectors of provided components
    wind_vector = {key: value
                   for key, value in {'u': u, 'v': v, 'w': w}.items()
                   if value is not None}
    return_only_horizontal = {key: value
                              for key, value in {'u': 'df/dx', 'v': 'df/dy'}.items()
                              if key in wind_vector}
    gradient_vector = ()

    # Calculate horizontal components of gradient, if needed
    if return_only_horizontal:
        gradient_vector = geospatial_gradient(scalar, dx=dx, dy=dy, x_dim=x_dim, y_dim=y_dim,
                                              parallel_scale=parallel_scale,
                                              meridional_scale=meridional_scale,
                                              return_only=return_only_horizontal.values())

    # Calculate vertical component of gradient, if needed
    if 'w' in wind_vector:
        gradient_vector = (*gradient_vector,
                           first_derivative(scalar, axis=vertical_dim, delta=dz))

    return -sum(
        wind * gradient
        for wind, gradient in zip(wind_vector.values(), gradient_vector)
    )


Numpy

下面,是基于numpy或者说从他的平流表达式来进行计算,下面图方便直接将其封装为函数了:

###############################################################################
#####                  
#####                      using numpy to calculate advection
#####
###############################################################################
def advection_with_numpy(lon,lat,pv):
    
    xlon,ylat=np.meshgrid(lon,lat)
    dlony,dlonx=np.gradient(xlon)
    dlaty,dlatx=np.gradient(ylat)
    pi=np.pi
    re=6.37e6
    dx=re*np.cos(ylat*pi/180)*dlonx*pi/180
    dy=re*dlaty*pi/180
    
    pv_dx = np.gradient(pv,axis=-1)
    pv_dy = np.gradient(pv,axis=-2)
    
    padv_numpy = np.full((pv.shape),np.nan)
    
    for i in range(40):
            
        padv_numpy[i] = -(u[i]*pv_dx[i]/dx+v[i]*pv_dy[i]/dy)
    return    padv_numpy
padv = advection_with_numpy(lon, lat, pv)
###############################################################################
#####                  
#####                      check calculate advection
#####
###############################################################################
plt.figure(figsize=(10, 6),dpi=200)
plt.plot( tadv[0,0], label='adv_mean', color='blue')
plt.plot( padv[0,0], label='pvadv_mean', color='red')

plt.show()

check resuly

  • 可以发现两种方法的曲线基本一致

方法检验

对于两种计算方法的计算结果进行检验,前面也简单画了一下图,下面主要从空间分布图以及任意选择一个空间点的时间序列来检验其计算结果是否存在差异。

空间分布图



def plot_contour(ax, data, label, lon, lat, levels, cmap='RdYlGn', transform=ccrs.PlateCarree(), extend='both'):
   
    cs = ax.contourf(lon, lat, data, levels=levels, cmap=cmap, transform=transform, extend=extend)
    ax.coastlines()
    ax.add_feature(cfeature.BORDERS)
    ax.set_title(label)
    box = [100,120,10,20]
    ax.set_extent(box,crs=ccrs.PlateCarree())
    ax.set_xticks(np.arange(box[0],box[1], 10), crs=transform)
    ax.set_yticks(np.arange(box[2], box[3], 5), crs=transform)
    ax.xaxis.set_major_formatter(LongitudeFormatter())
    ax.yaxis.set_major_formatter(LatitudeFormatter())
    plt.colorbar(cs, ax=ax, orientation='horizontal')
    ax.set_aspect(1)
# 创建画布和子图
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(16, 6),dpi=200, subplot_kw={'projection': ccrs.PlateCarree()})

# 绘制三个不同的图
plot_contour(ax1, tadv[0] * 10**4, 'Metpy', lon, lat, levels=np.linspace(-1, 1, 21))
plot_contour(ax2, padv[0] * 10**4, 'Numpy', lon, lat, levels=np.linspace(-1, 1, 21))
plot_contour(ax3, (np.array(tadv[0]) - padv[0]) * 10**4, 'difference',
             lon, lat, 
             levels=11)

# 显示图形
plt.tight_layout()
plt.show()

空间分布

  • 子图1为metpy计算结果,子图2为numpy计算结果,子图3为两种计算结果的差异
  • 为了保证结果可靠性,前两个子图选择相同的量级,绘制间隔(levels),colormap

可以发现,整体上对于第一个时刻的pv平流项空间分布图,两种方法的计算结果整体上是一致的,说明两种计算方法都是可行的;两种计算方法的差异小于0.01,在一定程度上可以忽略,不影响整体结论以及后续的分析。

任意空间点的时间序列


def extract_time_series(lon, lat, lon0, lat0, tadv, padv2):
    def find_nearest(array, value):
        array = np.asarray(array)
        idx = (np.abs(array - value)).argmin()
        return idx

    lon_idx = find_nearest(lon, lon0)
    lat_idx = find_nearest(lat, lat0)
    
    tadv_series = tadv[:, lat_idx, lon_idx] * 10**4
    padv2_series = padv2[:, lat_idx, lon_idx] * 10**4
    diff_series = (np.array(tadv[:, lat_idx, lon_idx]) - padv2[:, lat_idx, lon_idx]) * 10**4
    
    return tadv_series, padv2_series, diff_series

lon0, lat0 = 100, 15  # 根据实际需要修改

# 提取该点的时间序列数据
tadv_series, padv_series, diff_series = extract_time_series(lon, lat, lon0, lat0, tadv, padv)

# 创建新的画布绘制时间序列曲线
plt.figure(figsize=(10, 6),dpi=200)
plt.plot(tadv_series, label='Metpy')
plt.plot(padv_series, label='Numpy')
plt.plot(diff_series, label='Diff')
plt.xlabel('Time')
plt.ylabel('Value')
plt.legend()
plt.title(f'Time Series at Point ({lon0}, {lat0})')
plt.grid(True)
plt.show()

时间序列检验

  • 从任意空间点的时间序列检验上,可以发现两种计算方法差异基本一致,总体上Metpy的结果稍微高于numpy的计算方法,可以和地球半径以及pi的选择有关
  • 从差异上来看,总体上在-0.1~0.1之间,误差可以忽略,不会影响主要的结论

总结

  • 这里,通过基于Metpy和Numpy的方法分别计算了位涡的平流项,并绘制了空间分布图以及任意空间点时间序列曲线来证明两种方法的有效性,在计算过程我们需要重点关注的是单位是否为国际基本度量单位,这里避免我们的计算的结果的量级的不确定性;
  • 当然,这里仅仅是收支方程中的一项,我们可以在完整的计算整个收支方程的各项结果后,比较等号两端的单位是否一致,来证明收支方程结果的有效性。

单位查阅:https://unidata.github.io/MetPy/latest/tutorials/unit_tutorial.html
advection:https://unidata.github.io/MetPy/latest/api/generated/metpy.calc.advection.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1880098.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

下属无执行力,领导无能为力?用好这3大法则,打造一流行动力

下属无执行力&#xff0c;领导无能为力&#xff1f;用好这3大法则&#xff0c;打造一流行动力 第一个&#xff1a;漏斗法则 在沟通这个领域&#xff0c;有一个漏斗法则&#xff0c;意思就是指&#xff1a;如果你脑袋里面想表达的是100%&#xff0c;那你说出口的会只有80%&…

【动态规划】139. 单词拆分

139. 单词拆分 难度&#xff1a;中等 力扣地址&#xff1a;https://leetcode.cn/problems/word-break/description/ 问题描述 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。 注意&#xff1a;不要求字…

App托管服务分发平台 index-uplog.php 文件上传致RCE漏洞复现

0x01 产品简介 App托管服务分发平台是一个为开发者提供全面、高效、安全的应用程序托管、分发和推广服务的平台。开发者可以将自己开发的应用程序上传到平台上,平台会对上传的应用程序进行审核,确保应用的质量和安全性。平台会根据开发者的要求,将应用分发到不同的应用市场…

【鸿蒙学习笔记】位置设置

官方文档&#xff1a;位置设置 目录标题 align&#xff1a;子元素的对齐方式direction&#xff1a;官方文档没懂&#xff0c;看图理解吧 align&#xff1a;子元素的对齐方式 Stack() {Text(TopStart)}.width(90%).height(50).backgroundColor(0xFFE4C4).align(Alignment.TopS…

C++学习全教程(Day2)

一、数组 在程序中为了处理方便,常常需要把具有相同类型的数据对象按有序的形式排列起来&#xff0c;形成“一组”数据&#xff0c;这就是“数组”(array&#xff09; 数组中的数据&#xff0c;在内存中是连续存放的&#xff0c;每个元素占据相同大小的空间&#xff0c;就像排…

matrixone集群搭建、启停、高可用扩缩容和连接数据库

1. 部署 Kubernetes 集群 由于 MatrixOne 的分布式部署依赖于 Kubernetes 集群&#xff0c;因此我们需要一个 Kubernetes 集群。本篇文章将指导你通过使用 Kuboard-Spray 的方式搭建一个 Kubernetes 集群。 准备集群环境 对于集群环境&#xff0c;需要做如下准备&#xff1a…

25 防火墙基础操作

1 防火墙进入WEB页面操作 华三防火墙的默认用户:admin/密码:admin 将IP地址改在同一网段的信息 在防火墙的管理地址 GE/0/0/1&#xff1a;192.168.0.1 主机的地址是:192.168.0.101 思考一下为什么Ping不通 security-zone name Management import interface GigabitEthernet1/…

Git安装与使用及整合IDEA使用的详细教程

1. 版本控制软件介绍 版本控制软件提供完备的版本管理功能&#xff0c;用于存储、追踪目录&#xff08;文件夹&#xff09;和文件的修改历史&#xff0c;是软件开发者的必备工具&#xff0c;是软件公司的基础设施。版本控制软件的最高目标&#xff0c;是支持软件公司的配置管理…

2 z变换与离散时间傅里叶变换

目录 序列的z变换 z变换的定义 常用典型序列的z变换 序列类型与z变换的收敛域 序列的分类 X(z)的极点与收敛域 单边序列 双边序列 z变换的性质 线性 序列移位 单边序列 双边序列 z域尺度变换 序列乘以n 复共轭序列的z变换 初值定理 终值定理 时域卷积定理 …

Suno体验记录

五月初的时候初体验了一下Suno v3&#xff0c;当时整体觉得还不错&#xff0c;操作简单&#xff0c;生成快&#xff0c;歌曲也算好听。当时就截止到这里了。最近发现有了一些新的更新&#xff0c;觉得可以整理记录一下。 1. 简单介绍 免费用户一天50积分&#xff08;不累计&a…

python 压缩数据

requests 是 Python 中一个非常流行的 HTTP 库&#xff0c;用于发送各种 HTTP 请求。下面是一个使用 requests 库发送简单 GET 请求和 POST 请求的示例&#xff1a; 首先&#xff0c;确保你已经安装了 requests 库。如果还没有安装&#xff0c;可以使用 pip 进行安装&#xff…

在线教育项目(一):如何防止一个账号多个地方登陆

使用jwt做验证&#xff0c;使用账号作为redis中的key,登录的时候生成token放到redis中&#xff0c;每次申请资源的时候去看token 有没有变&#xff0c;因为token每次登录都会去覆盖&#xff0c;只要第二次登录token就不一样了

【接口自动化测试】第四节.实现项目核心业务的单接口自动化测试

文章目录 前言一、登录单接口自动化测试 1.1 登录单接口文档信息 1.2 登录成功 1.3 登录失败&#xff08;用户名为空&#xff09;二、数据驱动的实现 2.1 json文件实现数据驱动总结 前言 一、登录单接口自动化测试 1.1 登录单接口文档信息 需求&#xff1…

实验6 形态学图像处理

1. 实验目的 ①掌握数字图像处理中&#xff0c;形态学方法的基本思想&#xff1b; ②掌握膨胀、腐蚀、开运算、闭运算等形态学基本运算方法&#xff1b; ③能够利用形态学基本运算方法&#xff0c;编程实现图像去噪&#xff0c;边界提取等功能。 2. 实验内容 ①调用Matlab /…

数据资产铸就市场竞争优势:运用先进的数据分析技术,精准把握市场脉搏,构建独特的竞争优势,助力企业实现市场领先地位,赢得持续成功

目录 一、引言 二、数据资产的重要性 三、先进数据分析技术的应用 1、大数据分析技术 2、人工智能与机器学习 3、数据可视化技术 四、精准把握市场脉搏 1、深入了解客户需求 2、预测市场趋势 3、优化资源配置 五、构建独特的竞争优势 1、定制化产品和服务 2、精准营…

计算机网络原理及应用

第一章 计算机网络概述 【1】局域网 局域网是指在某一区域内由多台计算机互联而成的计算机通信网络。 【1】互通 两个网络之间可以交换数据。 第二章 计算机网络的体系结构 【1】语义 何时发出何种控制信息&#xff0c;完成何种动作以及做出何种响应。 【2】简述网络协…

1Panel运维利器:功能详解与实操指南

官网地址:https://1panel.cn/ 1Panel简介 1Panel是杭州飞致云信息科技有限公司旗下产品&#xff0c;是一款现代化、开源的Linux服务器运维管理面板&#xff0c;于2023年3月推出。 名称&#xff1a;1Panel开源Linux面板 所属公司&#xff1a;杭州飞致云信息科技有限公司 编写语…

【C++】————string基础用法及部分函数底层实现

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;C 创作时间 &#xff1a;2024年6月30日 前言&#xff1a; 本文主要介绍STL容器之一 ---- string&#xff0c;在学习C的过程中&#xff0c;我们要将C视为一个语言联邦&#xff08;摘录于Effective C 条款一&#x…

智能旅行规划的未来:大模型与形式化验证的融合

我们在做旅行规划时面对众多的目的地选择、复杂的交通连接、预算限制以及个人偏好等多重因素&#xff0c;即使是最有经验的旅行者也可能会陷入选择困境。传统的旅行规划方法往往依赖于人工操作&#xff0c;这不仅耗时耗力&#xff0c;而且难以保证计划的最优性和可执行性。 本…

Linux——/etc/passwd文件含义,grep,cut

/etc/passwd文件含义 作用 - 记录用户账户信息&#xff1a;共分为7段&#xff0c;使用冒号分割 含义 - 文件内容意义&#xff1a;账户名&#xff1a;密码代号x&#xff1a;UID&#xff1a;GID&#xff1a;注释&#xff1a;家目录&#xff1a;SHELL - 第7列/sbin/nologin&#x…