
第一次听说 WRF-CMAQ 组合的人通常会有一个错觉这不就是装两个模型、跑一把数据的事吗等你真正开始搭环境才会明白这套系统最磨人的地方根本不在模型本身而在编译器、依赖库、数据格式、脚本环境这些看不见的环节。我当时从零开始配置 WRF-CMAQ光是让 WPS 顺利读出 GRIB2 数据就折腾了两天最后发现只是 jasper 库路径的问题。这篇指南把我从环境配置到跑通官方测试案例的全过程做一个完整复盘适合刚接触空气质量建模、想把 WRF-CMAQ 从源码编译到批跑流程彻底搞清楚的读者。文中涉及的版本号、编译选项、排错思路都是实际验证过的可以直接照着做也可以根据自己的机器配置灵活调整。1. 先搞清楚这套模型在跑什么从气象场到污染物浓度的完整链路WRF-CMAQ 不是一个模型而是由气象模型和空气质量模型拼接成的一套模拟系统。WRF 负责提供气象场CMAQ 负责在气象场上模拟污染物的排放、扩散、化学反应和沉降。很多新手一上来就急着编译结果装完 CCTM 模块后不知道要跑哪些前处理工具也不理解各个模块之间数据怎么流转。我建议先花半小时把整条链路在脑子里过一遍后面每一步操作都会变得有明确目的。1.1 各模块之间到底在传递什么数据WRF 输出的核心文件是 wrfout 文件里面存了风场、温度、气压、湿度、降水等气象变量。但 CMAQ 不能直接读 wrfout它需要的是经过 MCIPMeteorology-Chemistry Interface Processor处理后的格式。CMAQ 本身又分成好几个独立工具ICON 生成初始条件文件BCON 生成边界条件文件MCIP 把 WRF 气象场转换成语 CMAQ 可读的格式最后才是 CCTMCMAQ Chemical Transport Model这个核心化学传输模型。另外还有一个 JPROC 用于计算光解速率常数测试案例里通常直接提供处理好的文件但自己跑真实案例时绕不开它。这么一拆解就很清楚了WPS把静态地理数据和原始气象再分析数据加工成 WRF 的输入WRF跑出气象场 wrfoutMCIP把 wrfout 转换为 METCRO3D 等气象输入文件ICON/BCON为模拟区域提供化学物种的初值和边界值CCTM在气象场和化学边界的驱动下输出臭氧、PM2.5 等污染物浓度这一整套流程里测试案例的最大价值在于官方已经把 WRF 输出的气象文件或 CMAQ 所需的边界条件提前准备好了你要做的是验证本机编译出来的各个可执行文件能否正确跑完这条链路而不是被真实数据下载和处理分心。1.2 为什么必须先跑通测试案例再碰真实案例我从自己的经历出发强烈建议第一次搭环境时不要直接拿某个真实时段去跑。真实案例会遇到一大堆非模型本身的问题再分析数据下载渠道不通、GRIB2 变量名对不上、地理数据缺失、排放清单格式错误。这些问题很容易和治疗环境配置问题混在一起最后你根本分不清是库没装好还是数据有问题。官方测试案例的设计思路就是把变量控制住。比如 CMAQ 的 benchmark 测试会提供完整的 ICON、BCON、MCIP 输出你可以直接跳过多步前处理只验证 CCTM 能否编译运行这样最小化问题范围。WRF 自带的理想化案例也是同样的逻辑用假象天气状态启动模型不需要外部强迫场就能验证编译产物是否正常。所以我会把整个实战过程分成三个阶段先编译 WPS/WRF 跑通理想化案例再编译 CMAQ 各工具最后跑官方的 conus12km 测试案例。每一阶段都有明确的成功标准避免在一个大项目里乱枪打鸟式地排错。2. 环境配置选对编译器、MPI 和 netCDF 版本后面能少走一半弯路环境配置是我见过的所有坑里占比最高的一个环节。WRF 和 CMAQ 对编译器、MPI 库、netCDF 库的版本组合非常敏感版本选得不合适后面每个模块都可能冒出莫名其妙的编译错误。我把一套经过验证的组合拳写出来直接抄作业即可。2.1 编译器选择gfortran 还是 ifortIntel 编译器ifort/icx在数值计算领域性能确实有优势WRF-CMAQ 官方文档也给了 Intel 路径的完整支持但它的授权和安装复杂度对个人用户不太友好。我在自己的工作站上用的大多数是 gfortran配合 OpenMPI 或 MPICH 都能正常工作。选择 gfortran 时要注意一个问题系统自带的 gcc 和 gfortran 版本必须一致最好是一起安装的同一个版本。混用不同版本的 gfortran 和 gcc 会让 netCDF 库编译时出现莫名其妙的链接错误。检查方法很简单which gcc which gfortran gcc --version gfortran --version如果两条路径不在同一个目录或者版本号对不上建议先统一。在 Ubuntu 系统上可以直接sudo apt update sudo apt install gcc gfortran g make csh m4顺便把 csh 装上因为 CMAQ 的配置脚本大量使用了 csh/tcsh 语法少装这个后面会很痛苦。2.2 依赖库版本矩阵WRF 和 CMAQ 的依赖库主要集中在 netCDF、MPI、HDF5、zlib、libpng、jasper 这几个。WRF 在处理 GRIB2 数据时需要 jasper而 netCDF 需要 HDF5 支持MPI 则决定 WRF 能不能并行运行。我给出一个实际验证过的版本组合依赖库推荐版本说明gcc/gfortran9.x ~ 12.x太老会遇到 Fortran 标准兼容问题太新也可能踩坑OpenMPI4.1.x或者 MPICH 3.3.x二选一即可HDF51.10.x1.12 系列也兼容但 1.10 使用更广泛netCDF-C4.7.x编译时需要指定 HDF5 路径netCDF-Fortran4.5.x必须等 netCDF-C 装完后再装zlib1.2.11WRF 的 GRIB2 依赖libpng1.2.x 或 1.6.xjasper 的依赖jasper1.900.xWPS 编译 GRIB2 支持时必备安装顺序也有讲究先装 zlib/libpng再装 jasper然后 HDF5接着 netCDF-C最后 netCDF-Fortran。这个顺序是固定的因为后一个库编译时要依赖前一个库的头文件和动态库。2.3 环境变量设置实操环境变量是整个 WRF-CMAQ 项目中最重要的隐形配置。我见过很多人编译时报错说找不到 netcdf.mod其实就是环境变量没设对。下面是我在 .bashrc 里长期使用的一段配置# WRF-CMAQ related export DIR$HOME/libs export CCgcc export CXXg export FCgfortran export FCFLAGS-m64 export CFLAGS-m64 # HDF5 export HDF5$DIR/hdf5 export PATH$HDF5/bin:$PATH export LD_LIBRARY_PATH$HDF5/lib:$LD_LIBRARY_PATH # netCDF export NETCDF$DIR/netcdf export PATH$NETCDF/bin:$PATH export LD_LIBRARY_PATH$NETCDF/lib:$LD_LIBRARY_PATH # MPI export MPI$DIR/openmpi export PATH$MPI/bin:$PATH export LD_LIBRARY_PATH$MPI/lib:$LD_LIBRARY_PATH # jasper for WPS GRIB2 export JASPER$DIR/jasper export PATH$JASPER/bin:$PATH export LD_LIBRARY_PATH$JASPER/lib:$LD_LIBRARY_PATH设置完成后最好新建一个终端重新加载配置然后用echo $NETCDF之类命令确认路径已经生效。很多人在编译器环境里来回切换导致环境变量互相污染这点务必警惕。3. WPS 和 WRF 编译从解压到跑通第一个理想化案例WRF 和 WPS 的编译是整个流程里最直观的工序。WRF 解压后运行./configure会出现一堆选项选择对应的编译器组合和并行方式。WPS 的编译则相对简单但它依赖 WRF 目录结构必须在 WRF 编译完成后进行。3.1 WRF 编译选项怎么选以 WRF 4.5 为例解压后进入主目录先设置环境变量export WRF_EM_CORE1 export WRF_NMM_CORE0 export WRF_CHEM1 export WRFIO_NCD_LARGE_FILE_SUPPORT1WRF_CHEM 如果打算后续接 CMAQ建议开启这样 wrfout 里会包含一些化学物种相关的变量虽然 CMAQ 主要走 MCIP但 WRF-Chem 变量对诊断有帮助。如果只想做纯气象模拟也能设成 0。然后运行./configure屏幕会列出几十个选项我一般选 34. (dmpar) GNU (gfortran/gcc) 对应 64 位 Linux gfortran 分布式并行。选串行smpar在测试机上也能跑但真实案例强烈建议用 dmpar后续并行计算省时间。配置完成后编译./compile em_real log.compile编译时间取决于机器核心数16 核机器大概 30 到 60 分钟。编译结束后检查主目录下是否生成了 wrf.exe 和 real.exe如果没有看 log.compile 里的报错。3.2 WPS 编译前先确认 GRIB2 支持WPS 完全是个前处理工具包含 geogrid、ungrib、metgrid 三个可执行文件。解压后同样运行./configure它会自动检测 WRF 目录的位置。这里最容易出问题的就是 GRIB2 选项。WPS configure 过程中如果它没有自动找到 jasper 库ungrib 就编译不出 GRIB2 解码功能后续处理再分析数据时会直接报错。解决方法是设置export JASPERLIB$JASPER/lib export JASPERINC$JASPER/include然后再 configure选择对应的选项通常选 3即 Linux x86_64 gfortran GRIB2。编译完成后三个可执行文件都生成即代表成功。3.3 用 em_b_wave 理想化案例验证 WRF 编译理想化案例不需要任何再分析数据非常适合快速验证编译结果。在 WRF 主目录 test/em_b_wave 下运行./ideal.exe会生成一个 wrfinput_d01 文件然后直接mpirun -np 4 ./wrf.exe跑完后用ncdump -h wrfout_d01_0001-01-01_00:00:00检查输出文件是否存在且结构完整。正常情况下几分钟就能跑完。这一步确认了 WRF 核心编译没问题之后再进入 CMAQ 环节就踏实多了。4. CMAQ 工具链编译ICON、BCON、MCIP先理清目录再动手CMAQ 的编译比 WRF 更依赖目录规划。官方文档推荐用 CMQA_HOME 和 CMQA_REPO 两个环境变量管理源码和运行目录但很多教程直接让用户把源码放在主目录下导致后续测试案例运行时路径错乱。我沿用官方推荐的布局同时梳理清楚了各脚本的作用。4.1 目录结构和环境变量我把 CMAQ 源码放在$HOME/CMAQ_REPO把运行测试案例的工作目录放在$HOME/CMAQ_HOME。CMAQ 官方脚本默认把这俩区分开原因是同一个编译好的可执行文件可以用于多个不同模拟区域运行时只需要把输入数据和配置文件放到对应的工作目录即可。export CMAQ_REPO$HOME/CMAQ_REPO export CMAQ_HOME$HOME/CMAQ_HOME export CMAQ_DATA$HOME/CMAQ_DATA其中 CMAQ_DATA 用来存放测试数据。CMAQ 5.3 之后测试案例的数据集动辄几十 GB单独分区也有好处避免以后跑真实案例时磁盘不够。4.2 I/O API 库很多编译错误的根源CMAQ 依赖一个叫 I/O API 的底层库这个库负责读写 netCDF 格式的 IO/API 文件。CMAQ 官方脚本虽然会自动调用 I/O API 的构建脚本但我实际遇到的情况是I/O API 的 configure 脚本经常因为环境变量不一致而失败。我在编译 I/O API 时习惯先手动设置export BINLinux2_x86_64gfortran export CPLMODEnocpl export IOAPI$CMAQ_REPO/ioapi然后在 ioapi 目录下运行make确认libioapi.a生成成功再回到 CMAQ 的 scripts 目录去配置其他模块。如果 libioapi.a 没生成后面 CCTM 编译时一定会报 cannot find -lioapi。4.3 按顺序编译 MCIP、ICON、BCON、CCTMCMAQ 的各个模块编译时间差异很大。我的编译顺序是先编译 MCIP因为它的输入依赖 WRF 输出的气象数据但不依赖 ICON/BCON再编译 ICON 和 BCON它们主要处理化学物种的初边界条件最后编译 CCTM它是核心模块编译时间最长在 CMAQ 5.4 版本中scripts 目录下有bldit_cctm.csh之类的脚本直接运行cd $CMAQ_REPO/scripts ./bldit_cctm.csh gcc脚本会自动设置很多环境变量但有一点经常被忽略脚本默认使用 Intel 编译器还是 gcc取决于传入参数和 bldit 脚本里的默认逻辑。如果发现编译时调用了 ifort就去脚本里把变量改成 gfortran。CCTM 编译完成后检查$CMAQ_HOME/cctm/scripts下是否生成了 CCTM_* 可执行文件。脚本命名的后缀通常包含编译时间和编译器类型比如CCTM_v54_gcc_20231015之类看到这种东西出现就说明编译环节基本通过了。5. 测试案例实战conus12km 示例从数据准备到结果检查编译通过只是第一步真正跑通测试案例才能证明整套环境没问题。我用 CMAQ 官方的 conus12km 测试案例来走流程这个案例用的是美国大陆 12 公里分辨率网格包含一个完整时段的基准测试数据适合验证从 ICON/BCON/MCIP 到 CCTM 的完整链路。5.1 测试数据准备确认目录结构和文件完整性CMAQ 官方测试数据可以从 CMAS Center 或其他镜像下载。下载后把数据放到$CMAQ_DATA目录下目录结构大概长这样$CMAQ_DATA/ ├── 2016_12km │ ├── BCON │ ├── CCTM │ ├── GRID │ ├── ICON │ ├── JPROC │ ├── MCIP │ ├── MET │ └── ...我最常犯的错误是只下载了 CCTM 需要的数据忘了 MCIP 输入数据导致跑到一半发现 MCIP 步骤缺文件。建议下载之前仔细看一下案例文档里的数据清单把这个目录的完整结构先建立好。5.2 修改 RunScript 里的路径参数测试案例的 run 脚本一般位于$CMAQ_HOME/.../scripts/run_cctm.csh。里面有几个关键变量需要改成你自己的路径setenv CMAQ_DATA /your/path/to/CMAQ_DATA setenv ICONpath $CMAQ_DATA/2016_12km/ICON setenv BCONpath $CMAQ_DATA/2016_12km/BCON setenv MCIPpath $CMAQ_DATA/2016_12km/MCIP setenv OUTPUTdir $CMAQ_HOME/output另外还要检查脚本里提到的起始时间和结束时间是否与下载的测试数据一致。conus12km 案例官方通常覆盖 2016 年 7 月的某几天日期对不上会直接报文件找不到。5.3 按顺序执行先从 MCIP 开始还是先跑 ICON/BCON在官方案例里MCIP、ICON、BCON 的输出文件其实已经在测试数据包中提供了所以严格来说你可以直接跑 CCTM。但如果要完整演示整条链路我建议还是把四个步骤都跑一遍。ICON 和 BCON 的输入通常是 GRID 描述文件或 MCIP 输出的网格描述信息。conus12km 案例里ICON 需要的文件往往是 GRIDCRO2D 这类 MCIP 输出。因此合理的顺序是先跑 MCIP 生成 GRIDCRO2D、METCRO3D 等文件再跑 ICON 生成初始条件再跑 BCON 生成边界条件最后跑 CCTM 得到浓度输出每次运行前用which确认可执行文件路径是否正确因为多次配置后 PATH 很容易串。5.4 判断测试是否真的成功CCTM 跑完的判定标准不是没报错就够。CMAQ 在运行结束时会写日志里面有一个表示正常完成的标志。我一般习惯在日志末尾 grep 几个关键词tail -100 $CMAQ_HOME/output/cctm.log | grep -i Program completed如果看到这行说明 CCTM 正常结束。接下来再检查输出文件ls -lh $CMAQ_HOME/output/CCTM_CONC* ncdump -h CCTM_CONC_20160701_120000.ncCCTM_CONC 文件里应该包含 O3、PM25_TOT 等变量可以顺手算一下最大值看看量级是否合理。比如夏季美国地区 O3 浓度峰值一般在几十 ppb 到上百 ppb如果出现几百、上千这种离谱数值说明输入数据或配置有问题。6. 踩坑记录与排查心得这些错误你大概率也会遇到前面五章基本把从环境到跑通的完整流程串完了。但在实际操作中编译和运行绝非一帆风顺我把最常见的几类错误单独拎出来附带排查思路省得你满网翻帖子。6.1 netCDF 头文件找不到八成是环境变量时序问题报错信息长这样Error: NetCDF not found in /usr/local/include排查思路是先确认 netCDF 到底装在哪find / -name netcdf.mod 2/dev/nullnetcdf.mod 是 netCDF-Fortran 编译后生成的关键模块文件如果找到的路径和你 .bashrc 里$NETCDF/include不一致说明安装时 prefix 路径设置不对。我还遇到过一种情况netCDF-C 装好了netCDF-Fortran 没装这个文件同样不存在。6.2 WPS 编译时关于 jasper 的报错WPS configure 时如果没有正确识别 GRIB2 依赖编译 ungrib 阶段会报错缺少libjasper.a。解决方法是在 configure 前显式设置export JASPERLIB/your/jasper/lib export JASPERINC/your/jasper/include然后重新 configure 时注意选择带 GRIB2 字样的选项。这个坑最隐蔽的地方在于就算不设置这两个环境变量configure 也可能不报错只会在后续 ungrib 编译时炸开。6.3 CCTM 运行时内存不足测试案例虽然是 12km 分辨率但整个 CCTM 跑起来的内存占用依然不小尤其是当你在 8GB 内存的笔记本上强行用多核跑时。我遇到过运行中途直接报Killed日志里看不到有效错误信息。排查方式是先把核心数降到 2 或 4 试跑同时看内存监控top -u $USERCCTM 本身有一些内存相关配置比如CTM_MAXSYNC、CTM_MAX_WALL_CLOCK等但最直接的办法还是保证机器内存大于 16GB。如果内存确实有限可以减小模拟区域或降低分辨率测试案例先跑通就行。6.4 编译时 Fortran 编译器的模块版本不一致这个比较少见但很致命。如果你系统里同时存在多个 gfortran 版本比如系统自带的老版本和 Anaconda 带的新版本CMAQ 编译时会找到其中一个netCDF 库却是用另一个编译的最后链接阶段报一堆 undefined reference。排查命令ldd $NETCDF/lib/libnetcdf.so | grep fortran which gfortran确认所有库和编译器两两匹配。我自己最终选择在 shell 配置里固定export FC/usr/bin/gfortran避免 PATH 顺序导致串版本。6.5 排查工具三件套最后分享一套我在整个调试过程中用得最顺手的排查流程which确认当前终端调用的可执行文件路径ldd检查可执行文件依赖的动态库是否齐备ncdump检查 netCDF 文件变量和维度是否符合预期这三个工具组合起来可以快速定位 80% 的路径错误和库链接问题。尤其是ncdump -h在判断 wrfout、METCRO3D、CCTM_CONC 文件是否为有效输出时比任何文档都可靠。从环境配置到完整跑通测试案例整个流程看起来步骤很多但每一步其实都在验证一件事你当前的机器是否具备运行这套数值模型所需的所有底层条件。我第一次跑通时花了整整一周大部分时间耗在库版本和环境变量上第二次换新机器再搭压缩到一天以内。如果你也是第一次接触这套系统别被报错吓到按模块逐个拆解先确认编译成功再看运行问题永远比你想的更简单。