挺早的时候有读者问过我,CMIP 怎么驱动 WRF。
我倒是见过相关的项目,奈何好几年不更新,担心 bug 多就没写。近日碰巧刷到,那个仓库居然更新了。更新理由让人傻眼,开发者写了这么一段文字——
I was mass-producing excuses to abandon this repo ("gotta make money!"), but Claude dragged me back to fill the holes I left behind.
那么大家一起感谢 Claude 吧(eva 鼓掌)。
言归正传。
这个仓库叫 cmip6-to-wrfinterm,做的事情很单纯,就是把 CMIP6 各模式输出的 sub-daily 数据转成 WRF 能吃的 intermediate 文件,纯 Python 实现,不依赖 NCL,也不用 Fortran。
在气候变化和区域动力降尺度这块,WRF 算是无出其右的选择。但 CMIP6 数据跟 WRF 的接口之间一直隔着一堵墙,变量命名不一样,网格系统不一样,格式更是完全不同。以前大家要么啃 NCL 脚本,要么自己硬写转换,维护起来非常痛苦。这个工具链的出现,其实就是为了解决这个老毛病。
GitHub 地址在这里,https://github.com/lzhenn/cmip6-to-wrfinterm
目前支持的 GCM 模式不算多,但覆盖了最常用的几个。MPI-ESM-1-2-HR 是默认支持且测试最充分的,SSP245 和 SSP585 都能跑。BCMM 是偏差校正后的多模式集合数据,SSP126 可用。EC-Earth3 也支持,不过目前只做了 historical 的有限测试。
模式 | historical | SSP126 | SSP245 | SSP585 |
|---|---|---|---|---|
MPI-ESM-1-2-HR | - | - | 支持 | 支持 |
BCMM | 不适用 | 支持 | - | - |
EC-Earth3 | 有限测试 | - | - | - |
项目完全基于 Python 科学计算生态,numpy、pandas、scipy 做数值计算,xarray 读 NetCDF,netcdf4 处理底层格式。安装很简单,直接用作者提供的 conda 环境文件就行。
conda env create -f test_c2w.yml
conda activate test_c2w
不需要额外编译什么东西,这点对不想碰 Fortran 的人来说很友好。
核心设计上我觉得有三个点值得一提。
一个是配置驱动。所有输入输出参数都放在 config.ini 里,切换模式只需要改几行配置,不用动核心代码。对经常要跑不同模式集合试验的人来说,这个设计省了不少事。
另一个是变量映射表,也就是 Vtable。项目给每个支持的模式都准备了一个 CSV 文件,放在 db 目录下,自动把 CMIP6 的变量名映射到 WRF intermediate 格式的变量名。比如 ta 映射成 TT,hus 映射成 SPECHUMD,ua 和 va 分别映射成 UU 和 VV。这个表是扩展的关键,如果你想接入新模型,主要工作就是搭一张正确的映射表。
第三个是网格插值。CMIP6 各模式用的网格系统五花八门,gn 是原生网格,gr 是规则网格,cmip_handler.py 会自动把数据插到规则的 lat/lon mesh 上,保证 metgrid.exe 能正常读。
上手跑起来其实很简单。以 MPI-ESM-1-2-HR 为例,默认情况下直接执行就行。
python3 run_c2w.py
如果一切顺利,output 目录里会出现两个文件。
CMIP6:2100-01-02_00
CMIP6:2100-01-02_06
注意文件名里有冒号,这是 Linux 的标准操作,但 Windows 文件系统不支持。所以 WSL 用户可能会遇到麻烦,需要手动重命名或者改输出前缀。
拿到 intermediate 文件之后,复制或者软链接到 WPS 目录,准备好 geo_em 文件,配置好 namelist.wps,然后按顺序跑 geogrid、metgrid、real、wrf 就行。
项目里附带了完整的示例,sample/MPI-ESM-1-2-HR 下面有 namelist.wps 和 namelist.input,覆盖东亚区域。跑通之后你能看到初始时刻和 6 小时积分后的地表温度场,作者 README 里贴了截图,效果看起来是靠谱的。
如果你想换 BCMM 数据,加 -m 参数就行。
python3 run_c2w.py -m BCMM
EC-Earth3 稍微麻烦一点,因为不同变量有不同的频率和网格,需要分五批跑。作者给了一张表,每次改 config.ini 再执行脚本。我放在文末附录里,需要的话可以对照着看。
配置文件本身不复杂,核心就几块。INPUT 段指定数据根目录、模式名、情景、集合成员、网格标识,还有起止时间。OUTPUT 段指定你想提取的时间范围和输出路径。时间格式都是 YYYYMMDDHHMM,精确到分钟。
[INPUT]
input_root=./sample/MPI-ESM-1-2-HR/
model_name=MPI-ESM1-2-HR
scenario=ssp585
esm_flag=r1i1p1f1
grid_flag=gn
cmip_strt_ts=210001020000
cmip_end_ts=210001020600
[OUTPUT]
etl_strt_ts=210001020000
etl_end_ts=210001020600
output_root=./output/
其中 model_name 决定调用哪张 Vtable,grid_flag 决定网格类型,gn 是原生网格,gr 是规则网格。cmip_strt_ts 和 cmip_end_ts 是原始数据的时间范围,etl_strt_ts 和 etl_end_ts 是你想转换输出的时间范围,两者可以不一致,也就是说你可以只转换原始数据里的一小段来做试验。
有几个坑作者写在了 README 里,我觉得值得单独拎出来提醒一下。
MPI-ESM-1-2-HR 的 historical 运行不提供 ts 变量,也就是海表温度。SSP 情景里有,historical 里缺失。作者的折中方案是用 tas 来代替,这在陆面上问题不大,因为陆地属性是陆面模式自己预报的。但海表温度是强迫项,用近地面气温代替会有偏差。如果你对 SST 敏感,建议自己去 ocean 数据集里下载 tos,转成大气数据集的格式,再改 Vtable 接入。这个操作不算太复杂,但确实要多走一步。
另外 MPI-ESM-1-2-HR 不提供 10-200cm 的土壤属性,作者直接拿 0-10cm 的数据回填,标记成 2d-soilr。如果你的研究对深层土壤初值敏感,建议做一个月左右的 spin-up,让陆面模式自己调整到平衡态。
坦率讲,这个工具目前的状态是一个「够用但还在路上」的项目。MPI-ESM-1-2-HR 的支持是最完善的,剩下的模式基本靠社区反馈和 PR 慢慢补。作者的态度倒是很坦诚,README 里直接承认自己之前想弃坑,被 Claude 拉回来的。这种真实感在开源项目里反而让人放心。
如果你正在做 CMIP6 驱动的 WRF 降尺度,而且恰好用的是 MPI-ESM-1-2-HR,这个项目可以帮你省掉大量写转换脚本的时间。纯 Python 的实现意味着你可以随意魔改,不像 NCL 那样改起来痛苦。配置驱动的设计也让批量试验变得可行。
但如果你用的是其他模式,比如 GFDL 或者 HadGEM3,那目前还需要自己搭 Vtable,工作量不小。另外项目没有并行支持,大批量长时间序列的转换可能会比较慢,这是一个可以期待的未来改进方向。
我自己觉得,这个项目的价值不只在它现在能做什么,更在它展示了一种可能性。CMIP6 数据驱动 WRF 本来是个门槛不低的事,以前需要懂 NCL、懂 Fortran、懂 WRF 的预处理流程,现在一个 Python 脚本加一张配置表就能跑起来。这种体验上的简化,对刚入门的学生和想快速做试验的研究者来说,意义很大。
如果你准备对照着动手跑,下面是作者整理的一些完整参考表,方便你查阅。
附录 A,EC-Earth3 分批次配置
Vtable 名称 | 网格 | 起始时间 | 结束时间 | 频率 | 输出前缀 |
|---|---|---|---|---|---|
EC-Earth3_SURF3H | gr | 197901010000 | 197912312100 | 3h | EC-EARTH3-SURF3H |
EC-Earth3_SURF6H | gr | 197901010300 | 197912312100 | 6h | EC-EARTH3-SURF6H |
EC-Earth3_LEV | gr | 197901010000 | 197912311800 | 6h | EC-EARTH3 |
EC-Earth3_PLEV | gr | 197901010000 | 197912311800 | 6h | EC-EARTH3-PLEV |
EC-Earth3_SST | gn | 197901010300 | 198001010000 | 3h | EC-EARTH3-SST |
附录 B,MPI-ESM-1-2-HR Vtable 变量映射表(部分)
src_v (CMIP6) | aim_v (WRF) | 单位 | 类型 | 说明 |
|---|---|---|---|---|
ta | TT | K | 3d | 3D 气温 |
hus | SPECHUMD | kg kg-1 | 3d | 3D 比湿 |
ua | UU | m s-1 | 3d | 3D 纬向风 |
va | VV | m s-1 | 3d | 3D 经向风 |
zg | GHT | m | 3d | 3D 位势高度 |
ps | PSFC | Pa | 2d | 地表气压 |
tas | TT | K | 2d | 2m 气温 |
ts | SKINTEMP | K | 2d | 地表温度 |
psl | PMSL | Pa | 2d | 海平面气压 |
mrsos | SM000010 | kg/m-3 | 2d-soil | 0-10cm 土壤湿度 |
tsl | ST000010 | K | 2d-soil | 0-10cm 土壤温度 |
更完整的映射表可以去 db/MPI-ESM-1-2-HR.csv 里看,作者注释写得挺清楚。
最后放一下参考链接。
GitHub 仓库,https://github.com/lzhenn/cmip6-to-wrfinterm
CMIP6 数据下载可以走 LLNL 的 ESGF 节点,https://esgf-node.llnl.gov/
WRF 用户手册 v4.2 的 P3-36 页列出了 metgrid.exe 需要的最低变量集合,跟作者整理的 Vtable 对照着看会更有底。
如果你跑通了这个流程,或者在其他模式上踩了新坑,欢迎去仓库开 Issue。作者说 PR 也欢迎,而且记得介绍一下自己,比如 affiliation 和研究方向。