简介:这份资源是wrf-python 1.1.3的官方发布压缩包,面向气象科研、环境模拟及数值预报领域的Python开发者,用于对WRF模式输出数据进行后处理、插值、诊断计算与可视化绘图。包体整体约1.3MB,共包含328个文件,其中以222个rst文档和51个py源码文件为主体,前者提供API说明与使用指南,后者包含核心函数库与示例脚本;另有18个f90文件用于底层Fortran扩展、5个bat与3个sh脚本负责多平台编译安装,整体结构清晰。已有2408人学习下载,适合需要在自己的项目中直接调用wrf-python接口、省去源码编译配置时间的进阶使用者。资源来源于官方打包,压缩包内附带setup.cfg、license及构建脚本,配合作者提供的安装方法说明,可帮助读者快速完成环境部署并规避常见的编译兼容性问题,从而专注后续的模式结果分析、剖面绘制与统计验证工作。
1. wrf-python-1.1.3.tar.gz 到底能帮你干什么
做气象模式后处理的人,手里最不缺的就是 WRF 输出的 wrfout 文件。文件里变量多到几十上百个,可当你真正想要算个位温、散度、相当位温或者把模式面插到标准气压层时,打开 wrf-python-1.1.3.tar.gz 这个压缩包,你会发现自己省下了一整条论文公式推导的路。这个库对 WRF 的 NetCDF 输出了如指掌,内置我们平时手动重复写的那些坐标转换、气象诊断公式,一个函数调完。
以前我用 ncdump 加 numpy 手动搬数据,公式错一个符号就得整个重算;换成 wrf-python 之后,getvar 直接返回一个带坐标的 DataArray,插值、平滑、地形订正全在同一套 API 里。这套工具适合做数值预报后处理、空气质量模拟、极端天气个例分析的人,也适合刚进组要做小论文但不想在重复造轮子上耗时间的同学。只要你的数据是 WRF 标准输出,这个库就能把“读数据”和“算物理量”这两件事压缩成几行。
2. 装这个包之前:先搞懂 wrf-python 的依赖与安装路径
2.1 依赖清单:为什么它不是孤立的一个包
wrf-python 核心功能是解析 WRF 输出文件里的坐标和投影信息,这离不开 netcdf4-python 和 xarray;计算诊断量则依赖 numpy 和 scipy;绘图后处理部分还需要 matplotlib。它还有一个 Fortran 编译模块包在 tar.gz 里面,负责高效执行垂直插值那类循环密集操作。因此,如果把压缩包直接丢进一个干净的 Python 环境,安装过程大概率会以编译失败或 import 报错告终。为省心,我一般先把 numpy、scipy、matplotlib、netcdf4、xarray、wrapt 按照 wrf-python 1.1.3 兼容的版本范围装齐。
这里有一个容易被忽略的点:wrf-python 1.1.3 发布时对 xarray 的接口比较敏感,不要轻易选用最新主版本,否则后面用 getvar 时会出现一堆 DeprecationWarning,甚至直接翻车。网络环境好的情况下,直接用 conda 创建环境并安装 conda-forge 上的预编译包是最省力的;但如果你手里只有这个 tar.gz,又想离线部署到生产机器,那就必须走源码编译路线,所以“依赖先行”这一步是跑不掉的。
下表是我日常会参考的依赖与职责对照,版本建议是经验值,不保证每个平台都适用:
| 依赖库 | 在 wrf-python 里的职责 | 版本倾向 |
|---|---|---|
| numpy | 数组运算、掩膜计算 | 1.20–1.24 |
| scipy | 插值、滤波、统计 | 1.8–1.10 |
| matplotlib | 绘图辅助功能 | 3.5–3.7 |
| netcdf4-python | 底层读取 NetCDF | 1.6–1.7 |
| xarray | 提供 DataArray 与维度对齐 | 0.20–0.21 |
| wrapt | 装饰器与接口保护 | 1.14–1.15 |
在 Linux 环境下,我通常用 conda 一口气建好环境,然后直接 pip 安装本地压缩包。下面给出一套可靠的最小安装流程。
# 创建干净环境,Python 3.8 或 3.9 都是稳定选择 conda create -n wrf_env python=3.9 -y conda activate wrf_env # 先装基础依赖,注意 xarray 版本不要冲到最新 conda install -c conda-forge numpy scipy matplotlib netcdf4 xarray=0.21 wrapt -y # 离线安装本地 tar.gz,优先走 pip pip install ./wrf-python-1.1.3.tar.gz这段逻辑很直白:conda 负责解决底层库的二进制依赖,pip 负责把 wrf-python 的 tar.gz 构建成可导入的包。参数方面,python=3.9是为了避开部分旧编译器的坑;xarray=0.21是我多次尝试后确认的兼容版本,如果你手头环境已经装了更高版本,至少先用pip install "xarray<0.22"降级。最后一行定要指定./路径,否则 pip 会去 PyPI 找同名包,那就失去离线安装的意义了。
安装完成后,用一条命令验证是否真的能用:
python -c "import wrf; print(wrf.__version__)"如果能正常输出1.1.3,说明包的基础安装已经成功。后面如果报错,大概率是依赖没对齐,不是 wrf-python 本身有问题。
2.2 离线环境下的依赖补齐方案
生产环境常常是完全没有外网的。要在这类机器上装 wrf-python,通常的步骤是:在一台有网的相同系统机器上用pip download拉取所有依赖(包括 wrf-python 本身),拷贝到内网后用--no-index安装。这个做法可以把“依赖不齐”的风险降到最低。
# 在有网机器上,一次性拉取所有依赖(含本包) pip wrf-python --no-cache-dir -d ./wrf_wheels wrf-python==1.1.3 # 把 wrf_wheels 目录拷到目标机器后,先装依赖,再装本地包 pip install --no-index --find-links=./wrf_wheels ./wrf-python-1.1.3.tar.gz第一行命令中-d指定下载目录,wrf-python==1.1.3是明确的版本约束;注意 pip 从 PyPI 下载的是 sdist 还是 wheel,取决于平台是否支持。如果你需要在内网还原完全相同环境,最好把下载到的所有文件都保留,不要只挑 wrf-python 的 tar.gz,否则安装到一半会提示缺网。第二行里的--no-index告诉 pip 不要碰网络,--find-links指向本地 wheelhouse,这样全部安装都会在本地解析完成。
这套方案我处理过很多次模拟项目X,只要目标机器的 Python 版本和系统库一致,基本不会出问题。唯一要提防的是 netcdf4-python 这类带原生库的包,拷贝时对应依赖库也要一起带上,否则后续import wrf阶段会报找不到.so文件,这类踩坑我在第 5 章详细展开。
3. 从 tar.gz 到真正的导入:构建与安装的三种常见做法
3.1 直接用 pip 安装本地压缩包:最省心的默认选择
拿到 wrf-python-1.1.3.tar.gz 后,大多数人的第一反应是直接安装。这里我推荐优先用 pip 而不是setup.py,因为 pip 会自动把压缩包解压到临时目录,调用构建后端完成编译,然后把包文件放到 site-packages,整个过程对用户是透明的。
# 在 tar.gz 同一目录下执行 pip install wrf-python-1.1.3.tar.gz如果在已经装好依赖的环境里执行,通常 30 秒左右任务就编译飞过了。这里有一个可选参数值得了解:--no-build-isolation。当系统里的 setuptools 和 wheel 版本比较老,而 pip 默认创建隔离环境时反而会导致编译失败,这时加上这个参数就能避免重复下载构建工具。但要注意,关闭隔离后你必须保证环境中已有 setuptools、wheel、cython 等,否则报错更莫名其妙。
另外,pip 安装还有一个好处,就是它会记录软件包元数据,后续用pip uninstall wrf-python能干净卸载;反观setup.py install时代留下的文件,经常得手动手动删。
3.2 解压后手动执行 setup.py:如果想干预编译参数
有些特殊场景下,pip 默认的编译参数不够用。比如生产服务器上编译器路径很怪异,或者你想强制开启某些 Fortran 优化选项,这时可以把压缩包解压开来,手动进入目录调整编译参数。常见做法是先用tar -xf wrf-python-1.1.3.tar.gz解开,然后查看setup.py顶部的编译标志。
tar -xf wrf-python-1.1.3.tar.gz cd wrf-python-1.1.3 # 查看编译器配置,常见环境变量包括 FFLAGS、CFLAGS export FFLAGS="-O2 -fPIC -std=legacy" python setup.py install这段流程关键在环境变量的作用:FFLAGS 控制 Fortran 编译器的优化等级和兼容模式,-fPIC在多数 Linux 发行版上必须加上,否则后端链接会报错;-std=legacy则是为了兼容 wrf-python 自带 Fortran 代码的旧语法。设置好之后再跑setup.py install,就是手动控制整个安装过程。
需要提醒的是,setup.py install不会主动安装依赖,而且不会像 pip 那样记录卸载信息。如果只是需要临时试试,或者给某个固定目录打包安装,这种方式还能接受;如果是长期项目,我更推荐在setup.py已经可用的情况下,直接pip install .,这样既能保留 pip 的好处,又能应用当前目录中的自定义编译设置。
3.3 用 conda 装预编译包:适合不想碰编译的人
如果只是做后处理,而不是改造 wrf-python 本身,完全没必要每次都编译源码。conda-forge 上已经有打包好的 wrf-python 二进制,直接使用就能避免 tar.gz 编译这一关。需要说明的是,conda 安装的版本不一定正好是 1.1.3,如果你想锁定版本,可以用wrf-python=1.1.3精确控制。
# 从 conda-forge 直接安装,跳过源码编译 conda install -c conda-forge wrf-python=1.1.3但即使你选择 conda 预编译,手里这份 tar.gz 仍然有用途:在离线条件下,先conda create一个环境并安装 netcdf4、xarray 等依赖,然后继续用pip install ./wrf-python-1.1.3.tar.gz,这样 conda 负责二进制依赖,pip 负责 wrf-python 本体,两侧都不会过时。这种做法是我多年下来最心头好的组合:不用自己编译 Fortran,又能精确控制 wrf-python 版本,踩坑最少。
4. 用 wrf-python 读 WRF 输出:最小可用脚本与参数说明
4.1 最小脚本:读取一个变量并计算诊断量
安装完库,第一件事就是打开真实 wrfout 文件。下面这个脚本是我平时验证安装是否可用的标准动作,它读取常见的 2 米温度、10 米风场和海平面气压,一次调用就能把整个数据链路跑通。
import wrf from netCDF4 import Dataset # 打开 WRF 输出文件,注意这里用 Dataset,而不是 xarray.open_dataset ncfile = Dataset("wrfout_d01_2023-06-15_00_00_00.nc") # 读取第 0 个时间步的 2 米温度,单位是开尔文 T2 = wrf.getvar(ncfile, "T2", timeidx=0) # 读取 10 米风场两个分量,以及合成风速和风向 u10 = wrf.getvar(ncfile, "U10", timeidx=0) v10 = wrf.getvar(ncfile, "V10", timeidx=0) wspd10 = wrf.getvar(ncfile, "WSPD10", timeidx=0) wdir10 = wrf.getvar(ncfile, "WDIR10", timeidx=0) # 海平面气压,单位是 Pa slp = wrf.getvar(ncfile, "SLP", timeidx=0) # 打印看一眼维度信息 print(T2.shape, slp.shape)timeidx参数是最容易用错的地方:它可以是整数,表示读取第几个时间步;也可以是None,表示一次把所有时间步都读出来。对于一个大 wrfout 文件,timeidx=None很容易吃光内存,所以刚上手时永远指定整数。返回对象是 xarray 的DataArray,自带经度、纬度和时间坐标,这一层是由 wrf-python 根据文件里的投影信息自动构造出来的,省去了手动配坐标的麻烦。
再看一个更进阶但极其常用的场景:把模式面变量插值到标准气压层。这也是 wrf-python 的主打功能之一。
# 读取模式面上的位温和气压 theta = wrf.getvar(ncfile, "theta", timeidx=0) pressure = wrf.getvar(ncfile, "pressure", timeidx=0) # 插值到 850hPa 和 500hPa,注意单位是 Pa target_levels = [85000, 50000] theta_850 = wrf.interplevel(theta, pressure, target_levels)这里interplevel的第一个参数是待插值变量,第二个参数是气压变量,第三个参数是目标气压值列表。返回的DataArray维度为(level, lat, lon),level 顺序与传入列表一致。使用前一定要确认pressure变量的单位,WRF 里气压默认是 Pa,如果你传成 hPa 的值(比如写了[850, 500]),插值会全部落在模式顶之外,输出一片 NaN。这个坑在第 5 章单独展开。
4.2 常用函数与参数详解
wrf-python 的 API 并不复杂,但熟练用好几个核心函数能让效率翻倍。下面列一份我实际项目里经常使用的函数清单:
| 函数名 | 作用 | 关键参数 |
|---|---|---|
getvar | 读取 WRF 变量或诊断变量 | timeidx,var_name |
interplevel | 垂直插值到标准气压面 | var,pressure,levels |
vertcross | 沿任意路径做垂直剖面 | var,pressure,start,end |
smooth2d | 二维平滑,常用来减少噪音 | var,passes,smooth_type |
ll_to_xy | 经纬度转 WRF 网格坐标 | lat,lon,timeidx |
xy_to_ll | 网格坐标转经纬度 | x,y,timeidx |
在实际使用中,getvar的var_name既可以是 WRF 文件里的原始变量名(如U、V),也可以是 wrf-python 内置的诊断变量名(如T2、SLP、WSPD10)。如果你不确定有没有这个变量,可以用wrf.ALLOWED_VARS查看完整列表,里面有五六百个可用名称,应当覆盖你日常所需的大多数变量。
vertcross是另一个值得注意的函数,它不仅能做垂直剖面,还能自动处理地形。举个例子:
# 计算任一水平直线的垂直剖面 cross = wrf.vertcross(theta, pressure, start=(30.0, -100.0), end=(35.0, -95.0), timeidx=0, latlon=True)start和end可以传经纬度坐标,latlon=True表示这两个点是经纬度而不是网格坐标。剖面返回的维度是(vertical, horizontal, south_north)或类似,时间步已经被取出。对于分析和画图来说,这个函数能省掉大量手工插值代码。
5. 装包路上常踩的 5 个坑:现象、原因、解决
5.1 安装时报错 “failed building wheel”
现象:执行pip install wrf-python-1.1.3.tar.gz后,屏幕滚出长长编译日志,最后一行是ERROR: Failed building wheel for wrf-python,安装直接退出。
原因:这是最典型的一类问题——源码包里含 Fortran 扩展,当前系统缺编译器或编译器版本太旧。特别是只装了 Python 没装 gfortran 的环境,大概率在这里翻车。
解决:先安装编译链,Linux 下执行apt-get install gcc gfortran或用 conda 安装gcc_linux-64与gfortran_linux-64;然后重新跑 pip 安装。如果是在 Windows 上直接源码编译,不建议硬刚,更推荐用 WSL 或直接走 conda 预编译。
5.2 import wrf 时找不到共享库
现象:磕磕绊绊装好包,一运行import wrf,报错ImportError: libnetcdf.so.19: cannot open shared object file,或者提示undefined symbol: nc_create.
原因:wrf-python 在 Python 层依赖 netcdf4-python,而 netcdf4-python 底层需要加载 netcdf 动态库。当 conda 环境里 lib 目录没有被动态链接搜索到,或者系统自带一个版本很旧的 netcdf 库,就会发生这种冲突。
解决:先用conda install -c conda-forge netcdf4确保环境里的库完整;再确认动态库搜索路径,执行export LD_LIBRARY_PATH=$CONDA_PREFIX/lib:$LD_LIBRARY_PATH后重新打开 Python。如果问题依旧,检查是否有多个 Python 环境混装,当时我处理过一个险象环生的事例,最后发现是把 pip 装到了系统 Python,而import用的是 conda Python,卸载重建后才解决。
5.3 运行 getvar 内存直接吃满
现象:调用getvar(ncfile, "T2", timeidx=None),机器 CPU 占用居高不下,内存以肉眼可见的速度上涨,最后卡死或被杀掉。
原因:timeidx=None会让 wrf-python 一次性加载整个时间维。WRF 输出文件动辄上百个时间步,每个时间步都是一张三维大气场,内存爆炸合情合理。
解决:改为timeidx=0或明确的整数;如果确实需要多个时间步,用循环逐时间步处理,每步算完就写到文件或画图释放内存。还有一种解法是先用xarray.open_dataset(..., chunks={'Time':1})打开,再配合wrf.python的接口,但这一套配置较为繁琐,不是很推荐新手。
5.4 气压插值结果全屏警告甚至空白
现象:interplevel调用后控制台刷出大量Some points are outside of the vertical grid警告,插值结果有大片 NaN,画在图上明显有洞。
原因:常见有两个,一是目标气压面单位写错,比如直接写了 850 而不是 85000;二是模式地形气压高于目标面,导致目标面位于地形内部,超出模式层范围。
解决:第一,检查pressure变量单位,确保目标面也用 Pa。第二,给interplevel加extrapolate=True,允许在模式垂直范围外做线性外推,这样地形以上通常能补出可信值。如果这样还有空白,可以先用wrf.mask把地形以下区域显式屏蔽,避免误判。
5.5 与 xarray 新版本一起用就翻车
现象:环境里 xarray 是最新版,运行getvar后出现一堆DeprecationWarning,甚至报AttributeError: 'DataArray' object has no attribute 'load'之类的错误。
原因:wrf-python 1.1.3 的发布时间早于许多新版 xarray,内部部分接口基于旧版本的习惯,新版本移除了一些函数,于是出现不兼容。
解决:把 xarray 固定到一个已知兼容的老版本。我的习惯是在创建环境时直接conda install xarray=0.21,装完后就不要再随手升级包。如果你已经在用新版,再排除其他变量时可以先临时期封一版,通常pip install "xarray<0.22"就能跑通。调度库版本是最省心的“后悔药”。
6. 从土办法到顺手:让 wrf-python 融入你的日常处理流程
6.1 批量处理多个 wrfout 文件的循环样板
真正做模拟项目X,一天可能生成几十个 wrfout 文件,逐个手写处理代码不现实。我常写一段循环脚本,把所有文件批量算出诊断变量,再存成汇总 NetCDF,这样后续画图或做统计时一次性读取。
import glob import wrf from netCDF4 import Dataset output_nc = "all_days_slp.nc" with Dataset(output_nc, "w") as out: # 创建一个维度,方便按时间追加 out.createDimension("time", None) time_out = out.createVariable("time", "i4", ("time",)) slp_out = out.createVariable("slp", "f4", ("time", "south_north", "west_east")) for i, fname in enumerate(sorted(glob.glob("wrfout_d01_*.nc"))): with Dataset(fname) as ncfile: slp = wrf.getvar(ncfile, "SLP", timeidx=0) # 只取每个文件的第一个时次 # DataArray 转成 numpy 后写入,注意经纬度维度顺序 slp_out[i, :, :] = slp.values time_out[i] = ncfile.variables["Times"][0].decode()这段脚本有几个小心思:with自动管理文件关闭,避免句柄泄漏;wrf.getvar(...)得到的是DataArray,我用.values拿到 numpy 数组再写入 NetCDF,减少与 netcdf4 库的类型冲突;time_out直接写入字符串的时间戳,方便后续处理。如果文件较多,还可以在wrf.getvar前面加from dask.distributed import Client配合分布式调度,但一般情况下串行循环已经够用。
我的另一个习惯是每次新环境搭建完成,第一件事不是跑大任务,而是拿一个最小 wrfout 文件跑通getvar和interplevel两个函数。这样如果版本有什么隐性问题,几分钟内就能暴露,不用等到处理到第 3 天数据才发现问题。说到底,wrf-python 的边界和参数都不是玄学,按官方接口、固定依赖、细看单位,基本能避开绝大多数坑。希望大家在数据处理路上少踩几个坑,希望这章经验帮到你。
本文还有配套的精品资源,点击获取