1. 先搞懂整体逻辑:chem_opt和emiss_opt到底在管什么
很多新手第一次跑WRF-Chem,最容易卡住的地方不是编译,也不是下载数据,而是namelist.input里那一排看着像密码一样的化学选项。尤其是chem_opt和emiss_opt这对组合,手册上写得极其简约——给个数字,告诉你选哪个是哪个机制,然后就没了。但实际操作里,这两个参数决定的不只是“用哪种化学机制”,还直接关系到你的排放清单怎么准备、初始场从哪里来、跑出来的结果能不能解释得通。
先说结论:chem_opt是化学机理的开关,决定大气中发生哪些化学反应;emiss_opt是排放源的处理方式,决定污染物以什么形式、什么物种、什么时空分布进入模式。两者必须配套使用,而且配套关系不是一一对应的,一个chem_opt可以对应多个emiss_opt,选错了要么直接报错,要么跑出来浓度离谱到没法用。
打个比方:chem_opt相当于厨房里的菜谱,emiss_opt相当于买菜和切菜的方式。菜谱是川菜,你却用粤菜的白灼方式处理食材,端出来那肯定不是那个味儿。WRF-Chem里,化学机制定义了物种之间的反应,排放方案得按这个机制要求的物种列表来提供污染物,否则模式根本不知道你给的那些排放量该放进哪个物种里。
具体到软件层面,chem_opt和emiss_opt都写在namelist.input的&chem这个段落里。WRF-Chem在初始化时会根据这两个选项去生成对应的化学变量列表、化学反应配置、排放模块接口。我见过不少新手,chem_opt选了个202(MOZART-MOSAIC气溶胶机制),emiss_opt却还留着默认的1,结果wrf.exe跑了两步就崩,报错信息又不友好,最后查了一整天发现就是排放方案不匹配。
所以我建议所有新手,在动namelist之前,先把这两个参数的逻辑关系用一张纸画出来:你研究什么区域?关注什么污染物?手里有什么排放清单?这三个问题的答案直接框定了chem_opt和emiss_opt的合理选择范围。不要一上来就盯着最新版的机制选,数值最大的不一定适合你。
1.1 chem_opt:化学反应引擎的工作模式
chem_opt这个参数,本质上是告诉WRF-Chem“你要模拟哪种化学体系”,从最简单的无化学(chem_opt=0,等价于普通WRF),到气相机制,再到气相加气溶胶的复杂配置,数字越大一般代表机制越复杂。
这里有个新手特别容易误解的地方:chem_opt=0并不代表“不跑化学”,它代表的是跑纯气象模式——也就是说,你的WRF-Chem就当WRF用了,不计算任何化学过程。很多人想在正式跑化学之前先用纯气象模式测试一下流程,这个做法完全可行,只要把chem_opt和emiss_opt都设成0就行。但一旦你设了chem_opt大于0,模式就会自动启用化学的一系列模块,包括化学传输、化学反应、干湿沉降、光解率计算等等,这时候你的输入文件里就必须有对应的化学场和排放场。
从我自己的使用经验来看,化学机制的选择要综合考虑三个因素:一是模拟区域的特征(城市污染主导还是区域传输主导),二是计算资源(复杂机制慢得可不是一星半点),三是可用的排放清单和初始场数据(你选的机制如果找不到对应的全球化学模式数据,初始场只能自己凭空捏造,那就没法玩)。
1.2 为什么说emiss_opt是“最容易翻车的环节”
emiss_opt的设置之所以难,是因为它不像chem_opt那样只要理解了机制差异就能选对,它涉及的是一个冷门的领域——排放清单的格式处理。WRF-Chem本身不自带排放数据,你需要自己下载或准备排放清单文件,然后用prep_chem_sources或者convert_emiss工具把它们转成模式能读的格式,这个过程里任何一环出了错,最后都会反映到emiss_opt和对应文件不匹配上。
我自己见过一个特别坑的案例:有个朋友跑长三角区域的臭氧模拟,用的是RADM2机制,排放清单来自某机构提供的清单产品。他下载的数据明明标注是“适用于RADM2”,但实际跑的时候wrf.exe总是报“error opening/wrong shape of emiss file”。后来排查发现,他的排放文件里物种名带了个后缀,和WRF-Chem默认的读取接口对应不上,前处理时候少了一个映射步骤。这种问题,手册里根本不会写,只有真正动手跑过的人才知道。
2. 常见chem_opt机制速览:别只盯着数字选
WRF-Chem发展了这么多年,chem_opt的选项从个位数扩展到了四位数,不同版本之间数值含义还会变,这对新手来说是巨大的坑。我这里基于WRF-Chem 4.x版本,把最常用的一组机制整理出来,帮大家建立一个基本认知框架。
| chem_opt值 | 机制名称 | 类型 | 适用场景 |
|---|---|---|---|
| 0 | 无化学 | 纯气象 | 测试流程、跑气象场 |
| 1 | T1 | 气相+简单气溶胶 | 教学、快速测试 |
| 2 | T2 | 气相+简单气溶胶 | 教学、快速测试 |
| 5 | RADM2 | 气相 | 传统臭氧模拟 |
| 7 | RADM2+MADE/SORGAM | 气相+气溶胶 | 颗粒物与臭氧协同模拟 |
| 8 | RADM2+MADE/SORGAM+AQ | 气相+气溶胶+液相 | 酸沉降、湿清除相关 |
| 9 | CBMZ | 气相 | 城市光化学烟雾 |
| 202 | MOZART-MOSAIC | 气相+气溶胶 | 区域/全球尺度耦合模拟 |
| 301 | CBMZ-MOSAIC | 气相+气溶胶 | 考虑气溶胶粒径分布的研究 |
注意上面这个表只是冰山一角,WRF-Chem 4.x里chem_opt值有几十个,每个背后还有一堆子选项。我见过有人用chem_opt=202跑,然后给MOZART机制配置了CBMZ的排放物种,结果NOx的排放量一直被模式错误地分配到别的物种里,模拟的臭氧浓度偏低得离谱。
2.1 从简单到复杂:新手怎么选第一套机制
如果你只是想跑通流程、验证安装、熟悉数据预处理流程,我的建议是先用chem_opt=2(T2机制)。原因有三个:第一,它计算量小,跑一天的区域模拟只要几十分钟;第二,它对排放清单格式要求低,很多通用清单工具默认支持;第三,它的结果虽然比较粗糙,但足以让你检查出代码层面有没有bug。
跑通了T2,再根据自己的研究方向逐步升级。比如做臭氧研究,可以试RADM2或CBMZ;做PM2.5研究,就要盯住带气溶胶模块的机制,比如RADM2+MADE/SORGAM(chem_opt=7)或者MOSAIC系列。不要想着一步到位直接用最复杂的MOZART-MOSAIC,那样你会被一堆气溶胶参数搞到崩溃。我记得有一次帮人排查问题,他用chem_opt=202跑中国全域,结果初始场数据里的气溶胶物种和模式要求对不上,折腾了整整一周才搞清楚。
2.2 chem_opt背后的气相机制差异
为什么要分这么多机制?本质上是化学反应网络的简化程度不一样。像RADM2,它把VOCs归并为十几个物种,氧化机理也比较简洁,跑起来快,但对复杂的臭氧生成过程刻画得不够精细。CBMZ用的是碳键方法,把碳链结构作为分类依据,对芳香烃的处理比RADM2好一些。MOZART则是大规模机制,物种数量多,化学反应方程式上千条,理论上最能还原真实大气化学过程,但计算量大得惊人,而且它本身也需要更多的输入参数。
选机制时还有一个容易忽视的点:气象过程和化学过程的时间步长耦合。WRF-Chem里化学机制的求解时间步长可以单独设置,但不同机制对数值稳定性要求不同,复杂机制在强对流天气下容易出现浓度振荡甚至数值爆炸。我自己在跑夏季雷暴天气下的臭氧模拟时,用过RADM2没事,换到MOZART就频繁出现“NaN in mixing ratio”的报错,最后只能把化学时间步长调小才稳住。这部分经验,就是踩坑踩出来的。
3. emiss_opt排放参数:一套排放数据对应一套玩法
说完chem_opt,再看emiss_opt。WRF-Chem的排放模块设计思路是:用emiss_opt告诉模式“我要用什么方式读排放文件、文件里的物种怎么映射到化学机制里去”。所以emiss_opt的数值选择,一半取决于你排放文件是怎么生成的,一半取决于chem_opt要什么物种。
我自己遇到过好几种情况:
- 用prep_chem_sources工具处理标准清单时,emiss_opt通常选1,它会按工具生成的物种映射表来读取。
- 用convert_emiss处理一些区域高分辨率清单(比如某些城市级清单)时,emiss_opt选17或对应值,因为那些清单已经按照MOZART-MOSAIC机制做过物种映射。
- 想用生物源排放MEGAN,那就是bio_emiss_opt的事,单独一套参数,不要和emiss_opt混淆。
这里值得多说一句:emiss_opt还跟时间变化有关。很多排放清单给出的是一天、一个月或者一年的总排放量,WRF-Chem需要根据emiss_opt所指定的方案把这些总量分配到每个时间步上。有的方案是恒定排放,有的是按日变化系数插值。如果你模拟的是臭氧日变化特征,但排放源用的是恒定速率,那结果基本没法看。
3.1 人为源、生物源和火灾源:三套排放别搞混
WRF-Chem的排放体系其实分三大块:人为源(anthropogenic)、生物源(biogenic)、火灾源(biomass burning)。它们对应不同的输入文件和不同的开关参数。人为源就是工厂、机动车这些,用emiss_opt控制;生物源是植被释放的VOCs,由bio_emiss_opt控制;火灾源是森林大火、秸秆燃烧这些,用另一个参数控制。
新手最容易犯的错是把生物源排放直接设为0,然后模拟出的VOCs浓度低到离谱。要知道在很多区域,异戊二烯和单萜烯这类生物源VOCs在夏季对臭氧生成的贡献极大,你要是把生物源关了,臭氧浓度拟合度会惨不忍睹。反过来,如果你不关心臭氧和二次有机气溶胶,只关注一次排放的颗粒物,那生物源影响相对小一些,可以简化处理。
生物源排放的计算,WRF-Chem默认有一套MEGAN模型,它需要输入地表植被类型数据,同时根据气象场(温度、辐射)实时计算VOCs排放。这个过程的计算量不小,但对结果的改善很明显。我第一次跑夏季华北区域模拟时,生物源排放开和关,臭氧模拟浓度能差到30%以上,所以千万别省这一步。
3.2 排放文件的时间轴:最容易出现的“隐形错误”
排放文件的时间覆盖范围必须覆盖你的模拟时间段,这个道理说出来大家都懂,但操作时经常出问题。我见过一个案例:模拟时段是7月15日到7月20日,但排放文件只处理了7月15日到7月19日,结果最后一天wrf.exe直接报“can't find valid time”错误。这种问题说起来很弱智,但确实就是很弱智地浪费了我两个小时。
还有一个更隐蔽的问题:排放文件的时间频率。WRF-Chem的排放输入文件通常是逐小时的,但有些工具生成的可能是逐3小时或者逐6小时。模式在读的时候虽然会做时间插值,但如果你在namelist里没写对时间步长的匹配逻辑,可能就会出现排放量突变的情况。我建议所有新手拿到排放文件之后,第一步用ncdump查看一下时间维度,确认时间步长和覆盖范围都正确,再开始跑。
4. 实战配置:一套完整的chem_opt+emiss_opt实战参数表
说了这么多原理,上点实际能抄的作业。下面这套配置是我自己常用的初始配置,适用于跑一个区域尺度的臭氧和PM2.5协同模拟,区域范围大概相当于一个省或省份群,水平分辨率9km到12km,chem_opt用RADM2+MADE/SORGAM机制(chem_opt=7),配套emiss_opt=3的人为源排放方案。
&chem chem_opt = 7, 7, 7, emiss_opt = 3, 3, 3, bio_emiss_opt = 3, 3, 3, phot_opt = 1, 1, 1, gas_drydep_opt = 1, 1, 1, aer_drydep_opt = 1, 1, 1, aerchem_onoff = 1, 1, 1, chem_inv_opt = 0, 0, 0, kemit = 1, 1, 1, /先解释几个关键项:
- chem_opt = 7:RADM2气相机制加MADE/SORGAM气溶胶模块,这个机制对臭氧和PM2.5都能给出比较合理的模拟,计算量在可接受范围内。
- emiss_opt = 3:这里选了3,意味着找人源排放文件时会使用chem_opt=7对应的物种映射表,把排放清单里的NOx、SO2、VOCs等物种映射到RADM2机制的变量体系里。
- bio_emiss_opt = 3:开启MEGAN生物源排放计算,需要提前准备植被类型输入文件。
- phot_opt = 1:开启光解率计算,化学机制中光解反应必不可少。这个参数也是个容易踩的坑,光解率方案不同,结果差异很大,新手先用默认的1就好。
- aerchem_onoff = 1:开启气溶胶化学,这个是配合气溶胶模块用的,只有chem_opt里包含气溶胶,这个参数设成1才有意义。
- chem_inv_opt = 0:化学初始场选项,0表示不添加额外化学初始场,直接由wrfinput文件里的化学浓度开始积分。这里要特别提醒:如果你用的是全球模式数据(比如WACCM或者MOZART-4输出)做化学边界场,chem_inv_opt就不是0了,要选成对应的方案。
这三层嵌套域都设成一样的化学配置,看起来是理所应当的,但实际里面有个坑:如果嵌套域里某一层用不同的chem_opt,那么两层之间的化学物种交互就会出问题。我建议新手在跑嵌套模拟时,所有层的化学选项保持一致,省去一大堆莫名其妙的错误。
4.1 配套文件准备:wrfinput和wrfbdy里必须有化学场
chem_opt大于0之后,你的wrfinput文件里就要包含化学场的初始浓度,wrfbdy里要包含化学场的边界浓度。这一步新手特别容易忽略,或者说不清楚从哪来。
我的做法是:用全球化学模式输出产品,通过工具把全球数据插值到自己的模拟区域,生成包含化学物种初始浓度和边界浓度的输入文件。具体工具包括mozbc、wrfchembc等。以mozbc为例,你需要在运行时指定全球数据文件名、模拟时间段、要映射的化学机制,工具会自动把全球模式的物种浓度插值到你的网格上,生成对应的wrfinput和wrfbdy变量。
这个环节的重要性我在自己第一次跑WRF-Chem时体会极深:当时我图省事,直接用纯气象的wrfinput去跑化学模式,结果前36个小时的化学浓度全靠模式内部从零开始“造”,模拟出的臭氧浓度明显偏低,而要等spin-up跑完、化学场稳定下来,至少得两三天。对于很多短期个例模拟来说,前两天的数据基本就是废的。所以化学初始场一定要配好,别在这上面省事。
还有一种操作是给模式较长的spin-up时间,比如先跑5天,取后3天的结果做分析。这个方法比直接改初始场来说更省事,但代价是计算量上去了,而且你依然需要一个能用的ndown或restart流程。两种方法我都试过,如果要做一个高质量个例分析,我强烈建议用全球化学模式数据生成初始场,这样你的化学模式从第一个时间步起就是“有记忆”的,而不是从一张白纸开始。
4.2 排放文件与emiss_opt的匹配检查清单
准备排放文件时,我总结了一个自检清单,每次做新案例都按这个过一遍,大大降低翻车概率:
- 确认排放文件的时间范围覆盖整个模拟时段,宁多勿少。
- 用ncdump -h查看排放文件里的变量名,确认物种名和emiss_opt对应的映射表匹配。
- 确认排放文件的投影信息、网格维度嵌套层次与wrfinput一致。网格不一致的排放文件,模式读进去会有偏移,结果完全不可用。
- 检查排放量单位。不同清单的单位差异巨大,有的用mol/km2/hr,有的用µg/m2/s,前处理工具里单位换算错了,结果浓度会差好几个量级。
单位这个坑,我栽过不止一次。有一次跑一个国外团队提供的清单,单位是molecules/cm2/s,没做换算直接塞给模式,结果NO2浓度模拟值比观测高了将近100倍,一开始我还以为是化学机制的问题,排查了三天才意识到是排放单位错了。这个惨痛经历告诉我:拿到任何排放清单,第一件事就是查文档确认单位,而且要在前处理脚本里显式写好单位换算关系。
5. 编译选项与版本差异:chem_opt值在不同版本间可能变脸
WRF-Chem的一个麻烦之处是它的参数数值在不同版本之间并不完全兼容。我最早用的是3.6.1版本,后来换成4.1.3,再到4.4版本,chem_opt的数值含义就有过调整。有些在老版本里是7的机制,在新版本里可能变成了别的值,或者功能发生了调整。
所以当你从网上下载一个namelist模板时,先确认模板对应的WRF-Chem版本,再对照你本地的Registry文件查一下实际数值定义,不要想当然。Registry文件路径通常在Registry/目录下,搜一下chem_opt就能看到各个数值对应的机制说明。
编译时的另一个坑是KPP(化学求解器)的开启。WRF-Chem里复杂机制通常会用KPP来生成化学求解代码,编译前你需要选择是否启用KPP。如果编译时没开KPP,但namelist里选了依赖KPP的机制(比如某些MOZART选项),wrf.exe运行时会直接报错“KPP not compiled”。这类错误在论坛上隔三差五就有新人问,但本质上就是你编译配置和运行时配置不匹配。
建议新手在编译前先把WRF-Chem自带的README和编译指导仔细读一遍,特别是关于chem_opt和KPP的描述。虽然文档写得不够细,但至少能帮你避免“机制和编译配置不匹配”这种低级问题。
5.1 wrf.exe崩溃的常见信号
wrf.exe运行中途崩溃,算是每个WRF-Chem新手的“成人礼”。崩溃的原因五花八门,但和chem_opt/emiss_opt相关的崩溃有几种典型信号:
“ERROR: emission file not found”:说明emiss_opt指定的文件路径下找不到排放文件,或者文件名和模式期望的不一致。WRF-Chem对排放文件的命名有严格要求,比如wrfchemi_00z_d01,这个00z指的是排放文件的小时标记,你必须保证文件名里的时间和模拟起始时间一致。
“NaN in mixing ratio”:化学浓度出现非数值,常见原因是排放量过大导致数值不稳定性,或者某个物种的初始浓度为负值。排查方法:先检查排放单位,再看初始场。
“ERROR: mismatch in dimension”:排放文件网格和wrfinput网格不一致,或者嵌套层数不匹配。这种错误通常在模式刚开始读排放文件时就出现,但报错信息不一定指向排放文件,有时候会让你云里雾里。
我建议新手在跑完整模拟之前,先做一个12小时或者24小时的短测试,把&chem里的诊断开关打开,比如io_form_chem=2(输出netCDF格式化学诊断文件),如果短测试能稳定跑完,再上长模拟。不要一上来就跑一个月,出了问题排查看日志看到怀疑人生。
5.2 chem_opt和emiss_opt的常见错误搭配
部分错误搭配我整理成了表格,方便大家对照检查:
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 跑了几步就崩,报emission文件找不到 | emiss_opt值和排放文件格式不匹配 | 查看rsl.error.0000文件,确认报错行,检查emiss_opt是否正确 |
| 跑完但臭氧浓度异常偏低 | chem_opt对应的VOCs物种和排放文件不匹配 | 使用ncdump检查排放文件物种,比对化学机制物种列表 |
| PM2.5浓度全是0或极小 | chem_opt不含气溶胶模块,或aerchem_onoff=0 | 确认chem_opt带气溶胶,检查aerchem_onoff设置 |
| 某一层跑得好,其他层浓度爆炸 | 嵌套层化学选项不一致,或排放文件层数不足 | 统一各层chem_opt/emiss_opt,检查排放文件是否包含所有嵌套层 |
| 模拟前几天化学浓度漂移严重 | 缺化学初始场 | 用mozbc等工具准备化学初始场和边界场 |
5.3 排放文件时间命名:一个非常低级但常见的问题
排放文件的命名规则,我单独拿出来说一次,因为这个问题几乎每隔一段时间就会在用户群里被问一次。WRF-Chem读排放文件时,文件名里的时间是按世界时(UTC)标记的。假设你的模拟从2024年7月15日00时(UTC)开始,那么排放文件名就应该是wrfchemi_00z_d01,这里的00z代表UTC时间0点。如果你用的是北京时间,那就要把时区差考虑进去,模拟从北京时间8点开始,UTC时间就是0点,文件名还是00z。
另外,一个模拟时段通常需要多个小时的排放文件,比如跑一天,你可能需要24个逐小时排放文件,或者一个包含24个时次的多时次排放文件。用prep_chem_sources生成的通常是后者,但用其他工具处理时可能生成前者。这两种格式WRF-Chem都支持,但对应的emiss_opt读取方式可能不同——这正是emiss_opt数值设计如此分裂的原因之一。所以拿到排放数据时先搞清楚它的时间组织方式,再决定emiss_opt选什么。
6. 进阶技巧:手动修改chem_opt对应排放物种的映射表
前面聊的都是参数本身,这里再分享一个手册里没写但很实用的技巧:自定义排放物种映射。WRF-Chem排放文件的物种映射表在两个关键的地方定义:一是前处理工具(比如convert_emiss)里有一个物种映射表文件,二是模式运行时根据emiss_opt去匹配排放文件里的变量名。
如果你的排放清单物种和chem_opt机制要求的物种不完全一致,你不需要重新生成排放文件,只需要修改映射表文件,把清单里的物种映射到机制物种上。具体做法是打开映射文件(通常在chem/或者run/目录下,文件名类似Chem_opt_xxx_emiss_xxx.txt),找到对应的物种对应关系,手动增加一行映射。比如清单里有“NMHC”(非甲烷总烃),但你的机制需要“ETH”(乙烯)、“TOL”(甲苯)等具体物种,你就可以按经验把NMHC按比例拆到这些具体物种上。
这个操作需要一定的大气化学知识才能做出合理拆分,但对很多区域清单来说,不做拆分就没法跑模型。我自己的做法是:先看清单文档里对物种的定义,再查一下这个地区排放源的构成(机动车多还是工业源多),用排放源谱把总量拆到具体物种。这步虽然费时间,但比硬跑后结果对不上要好得多。
6.1 用python快速检查排放文件和wrfinput的匹配性
最后分享一个我日常用的python小脚本,专门用来检查排放文件和wrfinput的匹配性。这个脚本很短,但能帮我快速发现90%的低级错误。
import netCDF4 as nc def check_emiss_match(emiss_path, wrfinput_path): # 读取排放文件和wrfinput文件 emiss = nc.Dataset(emiss_path) wrfin = nc.Dataset(wrfinput_path) # 检查网格维度 e_lat, e_lon = emiss['XLAT'][0], emiss['XLONG'][0] w_lat, w_lon = wrfin['XLAT'][0], wrfin['XLONG'][0] print("网格维度检查:") print(f" 排放文件: {e_lat.shape}, 最大经度差: {abs(e_lon.max()-e_lon.min()):.2f}") print(f" wrfinput: {w_lat.shape}, 最大经度差: {abs(w_lon.max()-w_lon.min()):.2f}") # 打印排放文件里的物种列表 chem_vars = [v for v in emiss.variables if 'e_' in v or 'E_' in v] print(f"\n排放物种清单(共{len(chem_vars)}个):") print(chem_vars[:20]) # 检查经纬度是否对齐(粗略检查) close = (abs(e_lat - w_lat).max() < 0.1) and (abs(e_lon - w_lon).max() < 0.1) print(f"\n网格对齐检查: {'通过' if close else '不通过,经纬度可能偏移'}") emiss.close() wrfin.close() if __name__ == "__main__": check_emiss_match("wrfchemi_00z_d01", "wrfinput_d01")运行这个脚本,你大概就能确认排放文件和wrfinput之间最基础的匹配性。再结合ncdump查看物种名是否有拼写问题,用ncview看排放量空间分布是否合理(比如城市区域是否有高值),基本就能把排放文件的坑踩平大半。
我一直觉得,WRF-Chem入门最大的障碍不是编程,也不是大气化学知识,而是这种“手册没写但你不知道就寸步难行”的暗坑。chem_opt和emiss_opt这对参数,说透了其实就一句话:它们是一对必须互相理解、互相匹配的搭档。搞明白这个核心,再配合上面这些排查思路,你就能少走很多弯路。
根据我个人的使用经验,新手最容易陷入的误区是把时间花在纠结“选哪个机制更高级”上,而忽略了排放文件和机制之间的配套问题。实际上,对大多数应用场景来说,稳定跑通、结果合理比机制华不华丽重要得多。先把一个简单机制调到结果能看、能和观测对比,再考虑升级复杂机制,是更靠谱的学习路径。