之前在公众号气python风雨发的素材募集中,有读者询问如何使用多部雷达反演风场
这个好办,前人早已写了库
雷达反演风一直是难题,今天我们介绍一个利用雷达数据反演风的库:pydda
需要注意的是PyDDA 现在支持使用 Jax 和 TensorFlow 来求解三维风场。PyDDA 需要启用 TensorFlow 2.6 和 TensorFlow 的 tensorflow-probability 包。此外,这两个软件包都可以利用支持 CUDA 的 GPU 来加快处理速度。这两个依赖项是可选的,因为用户仍然可以在 SciPy 生态系统中使用 PyDDA。Jax 优化器使用与 SciPy 的 (L-BFGS-B) 相同的优化器。
以下是它的官方示例之一
这显示了如何从悉尼上空的 4 个雷达中检索风的示例。
我们使用平滑来降低中气旋区域的上升气流的幅度。噪声的降低还有助于解更快地收敛,因为成本函数更平滑,因此更难找到噪声中的局部最小值。
观测约束从通常的 1 减少到 0.01,因为我们使用了 4 个雷达,因此我们考虑了更多的数据点。
此示例使用 pooch 下载数据文件。
使用镜像:气象分析3.9 资源:4核16g
ps:由于基于cpu计算,运行可能需较长时间
如需在线运行可点击原文链接
此处感谢龙清大佬对pydda环境的配置
import pyart
import pydda
import matplotlib.pyplot as plt
import numpy as np
import pooch
## You are using the Python ARM Radar Toolkit (Py-ART), an open source
## library for working with weather radar data. Py-ART is partly
## supported by the U.S. Department of Energy as part of the Atmospheric
## Radiation Measurement (ARM) Climate Research Facility, an Office of
## Science user facility.
##
## If you use this software to prepare a publication, please cite:
##
## JJ Helmus and SM Collis, JORS 2016, doi: 10.5334/jors.119
Welcome to PyDDA 1.5.1
If you are using PyDDA in your publications, please cite:
Jackson et al. (2020) Journal of Open Research Science
Detecting Jax...
Jax/JaxOpt are not installed on your system, unable to use Jax engine.
Detecting TensorFlow...
TensorFlow detected. Checking for tensorflow-probability...
TensorFlow-probability detected. TensorFlow engine enabled!
pydda是与pyart库搭配计算的,如有不同格式的雷达数据需要转为pyart可以读取的格式
小编才知道悉尼英文是sydney
## 下载数据
grid1_path = pydda.tests.get_sample_file("grid1_sydney.nc")
grid2_path = pydda.tests.get_sample_file("grid2_sydney.nc")
grid3_path = pydda.tests.get_sample_file("grid3_sydney.nc")
grid4_path = pydda.tests.get_sample_file("grid4_sydney.nc")
## 读取四个雷达
grid1 = pyart.io.read_grid(grid1_path)
grid2 = pyart.io.read_grid(grid2_path)
grid3 = pyart.io.read_grid(grid3_path)
grid4 = pyart.io.read_grid(grid4_path)
/opt/conda/lib/python3.9/site-packages/pyart/io/cfradial.py:412: UserWarning: WARNING: valid_min not used since it
cannot be safely cast to variable data type
data = self.ncvar[:]
/opt/conda/lib/python3.9/site-packages/pyart/io/cfradial.py:412: UserWarning: WARNING: valid_max not used since it
cannot be safely cast to variable data type
data = self.ncvar[:]
可通过调整不同的参数来优化反演结果,另外计算时间较长,小编还不知如何调用gpu计算,还请知道的大佬指点指点
pydda.retrieval.get_dd_wind_field()
函数接受一系列 Py-ART 格网对象作为输入,从中推导出风场。该函数要求所有输入的 Py-ART 格网必须具有相同的格网规格,即形状、X 坐标、Y 坐标和 Z 坐标都相同。
参数说明:
pydda.constraints.get_iem_obs()
返回的点观测。设置为 None 禁用点观测。返回值:
# 设置参数开始反演
grid1 = pydda.initialization.make_constant_wind_field(grid1, vel_field="VRADH_corr")
new_grids, _ = pydda.retrieval.get_dd_wind_field(
[grid1, grid2, grid3, grid4],
Co=1e-2,
Cm=256.0,
Cx=1e-4,
Cy=1e-4,
Cz=1e-4,
vel_name="VRADH_corr",
refl_field="DBZH",
mask_outside_opt=True,
wind_tol=0.1,
max_iterations=200,
engine="scipy",
)
Calculating weights for radars 0 and 1
Calculating weights for radars 0 and 2
Calculating weights for radars 0 and 3
Calculating weights for radars 1 and 0
Calculating weights for radars 1 and 2
Calculating weights for radars 1 and 3
Calculating weights for radars 2 and 0
Calculating weights for radars 2 and 1
Calculating weights for radars 2 and 3
Calculating weights for radars 3 and 0
Calculating weights for radars 3 and 1
Calculating weights for radars 3 and 2
Calculating weights for models...
Starting solver
rmsVR = 7.242250167336596
Total points: 281276
The max of w_init is 0.0
Nfeval | Jvel | Jmass | Jsmooth | Jbg | Jvort | Jmodel | Jpoint | Max w
0|2864.7900| 0.0000| 0.0000| 0.0000| 0.0000| 0.0000| 0.0000| 0.0000
The gradient of the cost functions is 0.10783124122961905
Nfeval | Jvel | Jmass | Jsmooth | Jbg | Jvort | Jmodel | Jpoint | Max w
10| 57.7027| 17.0172| 0.0000| 0.0000| 0.0000| 0.0000| 0.0000| 51.2499
/opt/conda/lib/python3.9/site-packages/pydda/retrieval/wind_retrieve.py:600: RuntimeWarning: All-NaN slice encountered
delta = np.nanmax(diff)
Max change in w: nan
The gradient of the cost functions is 0.13319518639944616
Nfeval | Jvel | Jmass | Jsmooth | Jbg | Jvort | Jmodel | Jpoint | Max w
20| 54.9807| 18.7575| 0.0000| 0.0000| 0.0000| 0.0000| 0.0000| 75.2207
The gradient of the cost functions is 0.06265389287213236
Nfeval | Jvel | Jmass | Jsmooth | Jbg | Jvort | Jmodel | Jpoint | Max w
30| 62.5696| 40.3943| 0.0000| 0.0000| 0.0000| 0.0000| 0.0000| 100.0000
The gradient of the cost functions is 0.05768538154971628
Nfeval | Jvel | Jmass | Jsmooth | Jbg | Jvort | Jmodel | Jpoint | Max w
40| 54.2658| 19.1128| 0.0000| 0.0000| 0.0000| 0.0000| 0.0000| 78.5232
The gradient of the cost functions is 0.05505137139375907
Nfeval | Jvel | Jmass | Jsmooth | Jbg | Jvort | Jmodel | Jpoint | Max w
50| 53.5801| 19.9986| 0.0000| 0.0000| 0.0000| 0.0000| 0.0000| 82.7234
The gradient of the cost functions is 0.05439831132705333
Nfeval | Jvel | Jmass | Jsmooth | Jbg | Jvort | Jmodel | Jpoint | Max w
60| 53.5883| 19.6409| 0.0000| 0.0000| 0.0000| 0.0000| 0.0000| 82.0780
The gradient of the cost functions is 0.05374405443091169
Nfeval | Jvel | Jmass | Jsmooth | Jbg | Jvort | Jmodel | Jpoint | Max w
Done! Time = 855.1
得到的结果依然是pyart的grid格式,让我看看里边有啥变量
ds = new_grids[0].to_xarray()
ds
<xarray.Dataset> Size: 60MB
Dimensions: (time: 1, z: 21, y: 356, x: 151)
Coordinates:
• time (time) object 8B 2015-12-15 23:36:32• z (z) float64 168B 0.0 1e+03 2e+03 3e+03 ... 1.8e+04 1.9e+04 2e+04
lat (y, x) float64 430kB -36.11 -36.11 -36.11 ... -32.93 -32.93
lon (y, x) float64 430kB 150.6 150.6 150.6 ... 152.2 152.2 152.2• y (y) float64 3kB -5e+04 -4.901e+04 -4.803e+04 ... 2.99e+05 3e+05• x (x) float64 1kB 1e+05 1.01e+05 1.02e+05 ... 2.49e+05 2.5e+05
Data variables:
DBZH (time, z, y, x) float32 5MB nan nan nan nan ... nan nan nan nan
VRADH_corr (time, z, y, x) float32 5MB nan nan nan nan ... nan nan nan nan
ROI (time, z, y, x) float32 5MB 1.171e+03 1.18e+03 ... 4.09e+03
AZ (time, z, y, x) float64 9MB 116.6 116.3 116.1 ... 39.69 39.81
EL (time, z, y, x) float64 9MB -1.086 -1.083 -1.081 ... 1.416 1.409
u (time, z, y, x) float64 9MB nan nan nan nan ... nan nan nan nan
v (time, z, y, x) float64 9MB nan nan nan nan ... nan nan nan nan
w (time, z, y, x) float64 9MB nan nan nan nan ... nan nan nan nan
可以看到文件中多了u和v变量,反演成功
ds.u
<xarray.DataArray 'u' (time: 1, z: 21, y: 356, x: 151)> Size: 9MB
我们得到了一个3d的风场
绘制反演结果
使用matplotlib绘制反演后的水平切面风矢图,背景展示反射率因子,同时标注风速等值线。
平面图
# Make a neat plot
fig = plt.figure(figsize=(20, 12))
ax = pydda.vis.plot_horiz_xsection_quiver_map(
new_grids,
background_field="DBZH",
level=5,
show_lobes=False,
bg_grid_no=3,
vmin=0,
vmax=60,
quiverkey_len=20.0,
w_vel_contours=[1.0, 3.0, 5.0, 10.0, 20.0],
quiver_spacing_x_km=2.0,
quiver_spacing_y_km=2.0,
quiverkey_loc="top",
colorbar_contour_flag=True,
cmap="ChaseSpectral",
)
ax.set_xticks(np.arange(150.5, 153, 0.1))
ax.set_yticks(np.arange(-36, -32.0, 0.1))
ax.set_xlim([151, 152.3])
ax.set_ylim([-34.15, -32.8])
plt.show()
剖面图 plt.figure(figsize=(9, 9)) pydda.vis.plot_xz_xsection_barbs( new_grids, background_field="DBZH", level=40, w_vel_contours=[5, 10, 15], barb_spacing_x_km=10.0, barb_spacing_z_km=2.0, ) plt.show() # Plot a vertical Y-Z cross section plt.figure(figsize=(9, 9)) pydda.vis.plot_yz_xsection_barbs( new_grids, background_field="DBZH", level=40, barb_spacing_y_km=10.0, barb_spacing_z_km=2.0, )
<Axes: title={'center': 'PyDDA retreived winds @140.0 km east of origin.'}, xlabel='Y [km]', ylabel='Z [km]'>
小结 通过pydda进行多部雷达数据的风场反演, 不仅能够克服单一雷达观测的局限性, 还能在复杂天气条件下提供更准确、更详细的风场结构。 如对您有用点个赞吧