线性斜压模式(LBM)从编译到运行:保姆级教程与敏感性试验实战
2026/9/16 1:34:55 网站建设 项目流程

提到LBM模式,很多做大气动力学和气候诊断的同行应该不陌生,全称是Linear Baroclinic Model,也就是线性斜压模式。第一次看到这个名词的时候,我还误以为它和计算流体里的格子玻尔兹曼方法有什么关系,后来才发现完全是两回事。学术圈内聊到LBM,默认指的就是这个线性模式:它把大气控制方程在某个气候态背景场上做线性化,专门用来高效求解大气对异常强迫的定常响应。网上能搜到不少论文里的LBM响应图,但真正手把手教你怎么装、怎么跑、怎么出图的保姆级中文资料非常少。我当初卡在编译这一步整整折腾了一个周末,最后发现说穿了就是环境变量和库链接那点事,特别希望当时有人能直接告诉我“照着这几步做就行”。这篇就是补上这个缺口,从源码编译到第一个试验出图,整个过程按最省心的路线走一遍,适合刚接触模式模拟、课程需要做敏感性试验,或者想给论文补一张机制诊断图的同学参考。

1. 先搞清楚LBM模式到底在算什么

1.1 “线性”是个什么意思

理解LBM的关键,在于“线性”这两个字。大气运动本质上是非线性的,温度、风场、气压之间互相反馈,想要完整模拟就得靠CESM、CAM这类全物理过程模式,计算量巨大,跑一次几个月也不是没可能。LBM另辟蹊径:它假设大气状态可以拆成两部分,一部分是给定的“背景场”,通常用气候平均态,另一部分是叠加在背景场上的“扰动场”。模式只研究扰动场怎么发展,并且在方程里忽略了扰动项之间的非线性乘积,只保留扰动和背景场相互作用的部分。

打个比方,一条河整体上流得比较平稳,你往河里扔一块石头,水面上会荡起一圈圈波纹。你想要知道的不是整条河的复杂湍流,而是“这块石头激起的波纹能传多远、在哪些地方放大”。LBM干的就是这件事:背景场就是河流的主流态,强迫项就是那块石头,输出结果是波纹的传播路径和结构,而不是整条河的完整状态。这种化繁为简的处理方式,使得LBM的计算量比全物理模式小好几个数量级,通常几分钟就能跑完一个试验。

1.2 它擅长回答什么样的科学问题

LBM模式在气候动力学里属于“归因工具”,它不预测未来天气,也不模拟真实大气状态,而是回答“如果给大气一个指定的异常强迫,线性动力过程会给出什么样的响应”。这种问题在机制研究里出现的频率相当高。

  • 热带降水异常如何影响中高纬环流,比如ENSO暖事件如何激发出PNA型遥相关。
  • 青藏高原或海洋性大陆的热源异常,会通过定常Rossby波列影响哪些区域。
  • 不同的背景风场下,同一个强迫激发的波传播路径有什么差异。
  • 观测中出现的遥相关型,有多少能被线性动力过程解释,多少需要靠非线性过程。

它把“因果关系”单独拎出来,把复杂的物理化学过程全部拿掉,只保留动力核心,结果反而特别适合用来讲机制。我在实际使用中最大的体感是:想解释一个现象,拿LBM跑一组敏感性试验,比翻遍再分析资料的合成分析要省力得多,而且因果方向是明确的。

1.3 和全物理模式比,它的边界在哪里

刚开始用LBM的人最常犯的错,是把它当成万能模式,想让它模拟出真实大气的完整演变,然后抱怨“为什么结果和观测差距这么大”。这是预期错位。LBM的定位是“诊断工具”,和CAM这类“模拟工具”各有分工。

维度全物理模式(如CAM)LBM线性斜压模式
方程处理完全非线性在背景态上线性化
计算成本高,需大量并行资源极低,单机几分钟
主要用途气候模拟、预测机制归因、敏感性诊断
输出物完整大气状态场扰动响应场
物理过程辐射、云、对流、边界层齐全通常只有干动力过程
适合新手吗难度高、资源门槛高门槛低、易上手

搞清楚这个边界之后,你看结果的心态会稳很多:LBM给出的不是“大气会发生什么”,而是“纯粹从线性动力角度看,这个强迫会引起什么样的波列”。这个答案本身就是很有价值的一环证据。

2. 安装前,先把这几样环境准备好

2.1 一张环境清单和最快的安装命令

我见过不少人在模式编译环节被劝退,其实LBM的依赖非常传统,只要系统里有Fortran编译器和NetCDF库,基本就成功了一大半。按踩坑频率从高到低排序,建议提前准备好四样东西:

  • Linux环境。原生的Ubuntu/Debian最省心,Windows用户强烈建议装一个WSL2,比虚拟机轻量,也比在Windows上想办法编译Fortran程序靠谱得多。
  • gfortran编译器。开源、免费、兼容性好,新手不要一上来就追ifort。等后面跑熟了,再根据模式文档考虑要不要切换。
  • NetCDF的Fortran接口库,名称为netcdf-fortran。注意只有netcdf-c是不够的,Fortran程序需要额外的接口层。
  • 画图工具。我习惯用Python的matplotlib加Cartopy,你也可以用NCL,看你自己顺手。

系统包管理器装依赖是最快的。Ubuntu系直接执行:

sudo apt update sudo apt install -y gfortran libnetcdf-dev libnetcdf-fortran-dev

如果你用的是conda,可以建一个干净的环境:

conda create -n lbm python=3.10 conda activate lbm conda install -c conda-forge netcdf-fortran

2.2 为什么不建议自己从源码编译NetCDF

很多新人在这一步踩了大坑:网上的安装教程说要自己编译hdf5、netcdf-c、netcdf-fortran,于是一路configure、make、make install,运气不好还会碰到hdf5和NetCDF版本不兼容,折腾两三天最后还在跟“undefined reference”搏斗。我的建议很直接:能用包管理器装就用包管理器装,能用conda-forge就用conda-forge。

原因很简单,LBM模式本身对NetCDF的版本没有特别苛刻的要求,系统自带的版本完全够用。自己从源码编译NetCDF唯一的收益是能精确控制路径,但对新手来说,引入的版本依赖问题远比收益大。如果你确实需要指定安装路径,用conda装到某个环境里同样能达到可控的目的,还不会污染系统环境。

2.3 装完之后怎么确认环境没问题

环境装完先别急着下载模式,打开终端验证一下:

which gfortran && gfortran --version nf-config --all

第一条确认编译器存在,第二条最关键。nf-config是netcdf-fortran自带的配置命令,会打印出include路径、库路径、链接参数,这些信息后面改Makefile时直接抄就行。如果执行后提示找不到nf-config,说明你的netcdf-fortran没装好或者不在PATH里,这时候先排查依赖,不要贸然进入编译阶段。

3. 源码获取与编译:把Makefile改到能跑为止

3.1 源码通常长什么样

LBM模式源码一般以压缩包形式在开发者的主页或课题组资源页提供,常见的名字是lbm_src.tar.gz或者lbm_t21.tar.gz。解压之后,目录结构大致是src、run、data、namelist几个区。src下面是一堆Fortran源文件,主程序一般是lbm_main.f90这类名字,run目录通常放着模板namelist和作业脚本,data目录放背景场样例。这里提醒一句:因为LBM有不少流传版本,目录和文件名会有差异,具体以你拿到的README文件为准,但总体逻辑是一致的。

我第一次拿到压缩包时习惯先解压到一个工作目录,比如~/lbm,然后花三分钟把所有README和目录结构扫一遍。这个习惯帮我避过很多坑,因为不同版本对输入文件命名的要求实在不太一样。

3.2 改Makefile之前,先用一条命令探好路

编译LBM的核心工作就是改对Makefile。Makefile里的核心变量就是编译器(FC)、包含路径(INCLUDE)和库路径(LIB)。最稳妥的操作是直接利用nf-config的输出结果:

nf-config --fflags nf-config --flibs

假设输出分别是-I/usr/include-L/usr/lib -lnetcdff -lnetcdf,那么在Makefile里对应写上:

FC = gfortran FFLAGS = -O2 -ffixed-line-length-none INCLUDE = -I/usr/include LIBS = -L/usr/lib -lnetcdff -lnetcdf

实际安装路径不同,这里不要复制,要跟着你机器上nf-config的输出填。注意-lnetcdff是Fortran接口库,-lnetcdf是C底层库,两个都要有,顺序也不要乱。有些版本还需要额外的-I$(NETCDF_DIR)/include,如果你是用conda装的,可以通过nf-config --prefix拿到安装根目录,再把include和lib路径拼上去。

3.3 编译和验证

改好Makefile之后,执行编译:

make clean make

正常情况下屏幕上会滚过一串gfortran编译命令,最后在当前目录或src目录下生成一个名为lbm或者lbm.exe的可执行文件。如果编译中途报错,先看错误是不是指向netcdf.mod找不到。如果是,说明你的INCLUDE路径没写对,gfortran没找到NetCDF的Fortran模块文件;如果错误是undefined reference to nf_open_这类,说明编译过了但链接阶段没找到库,检查LIBS这一行,并且确保库路径正确。

编译成功后可以试着运行一下:

./lbm

这时候如果你还没准备输入文件,程序大概率会报“找不到输入文件”或者打印出默认namelist信息。能看到这类输出反而是好消息,说明可执行文件本身没问题。

3.4 编译阶段最常踩的四个坑

报错特征可能原因解决方法
netcdf.mod not foundgfortran没找到Fortran模块头文件在INCLUDE里加上netcdf-fortran的include目录
undefined reference tonf_open_链接库没写或顺序不对在编译命令末尾放置-lnetcdff -lnetcdf
Invalid character in name源码或Makefile混入了非ASCII字符检查是否有中文空格或不可见字符,删除即可
编译到一半报错且信息指向老语法gfortran新版对旧代码更严格试试gcc-10或gcc-11系列,版本太新反而麻烦

这里特别想强调链接顺序的问题。Fortran链接NetCDF时,库的书写顺序是有讲究的,被依赖的库要放在后面。如果-lnetcdff-lnetcdf的位置放错了,有些版本会报未定义引用,有些版本能正常过,取决于库的静态还是动态方式,但你的Makefile最好一开始就按正确顺序写。

4. 第一次运行:文件、参数和输出

4.1 三个输入文件是什么

编译成功只完成了一半,第一次真正把LBM跑起来,需要准备三类输入。背景场文件是模式线性化的基准态,通常取再分析资料的气候平均,我一般命名为clim.nc。强迫场文件是你施加的异常外强迫,比如某个区域的对流加热异常,命名为forcing.nc。最后是namelist控制文件,LBM读入的参数都在里面,相当于控制面板。

我的工作习惯是,不管模式版面默认支持什么格式,先把所有输入输出统一转成NetCDF。原因很简单:Python生态里xarray读NetCDF太方便了,后面做强迫场、读结果、画图,全流程用一套格式会少踩非常多坑。如果你拿到的LBM版本支持netCDF的话,这一步几乎不需要额外转换。

4.2 namelist里的关键参数怎么定

namelist里面参数命名在不同版本里略有差异,但核心概念是通用的。以最常见的T21L20配置为例,水平分辨率用球谐截断波数控制,T21大约对应64乘32的经纬网格,垂直方向20层,时间步长用1800秒,积分120天需要跑5760步。参考参数的逻辑是这样的:

参数含义T21L20参考值
ntrunc球谐截断波数21
nlon / nlat东西/南北网格数64 / 32
nlev垂直层数20
dt时间步长(秒)1800
nstep总积分步数5760
nout输出间隔步数24

这里提醒两个最容易出问题的点:网格数必须和截断波数匹配,T21配64乘32,T42配128乘64,乱填虽然能编译通过,但运行时大概率出问题;垂直层数必须和背景场文件里的层数完全一致,不然模式读取时维度对不上,轻则警告,重则直接崩溃。第一次跑可以先设一个很小的nstep,比如5步,先验证程序流程能走通,再跑完整积分。

4.3 跑起来之后怎么判断结果正常

配置好之后运行:

./lbm < namelist.ctl

或者按照你版本里的作业脚本执行。正常运行时终端会滚动输出积分进度,几秒到几分钟后结束,生成响应场文件。很多版本输出的变量名是gph、temp、u、v这类,注意这些是相对于背景场的“异常响应”,不是完整场,解读结果时要明确这一点。

我第一次跑完的时候,习惯先看输出文件里有没有NaN或全零,再看一把500hPa位势高度异常的分布。如果响应场看起来是平滑的大尺度波列结构,说明试验基本成功了;如果全是噪声或不规则斑点,先查强迫场是不是有NaN,再查背景场格式是否正确。

5. 动手做一个经典试验:热带加热强迫响应

5.1 试验设计思路

一个适合入门又能发论文的经典试验,是复现热带异常加热激发中高纬遥相关波列。通俗点说,把某个热带区域的降水异常等价成大气中低层的异常加热,然后看这个加热会在500hPa位势高度场上激起什么样的远距离响应。这个试验思路在ENSO、青藏高原加热影响的论文里都很常见,跑通它基本上等于掌握了LBM的核心玩法。

我推荐的第一个试验是:在赤道中东太平洋附近放置一个对流层中低层的异常加热中心,中心强度大约每天3K,水平范围取几十个经度乘几十个纬度,垂直范围大概400到850hPa。背景场用气候平均态,积分120天,然后看500hPa高度响应的波列路径。这个试验预期能看到从热源区向东向北传的定常Rossby波列,也就是PNA型响应的大致骨架。

5.2 用Python生成强迫场

强迫场的基本要求是:和背景场使用相同的经纬网格、相同的垂直层数,变量名和单位跟模式约定一致。下面是一段可以直接修改的生成脚本框架,用xarray创建强迫场:

import numpy as np import xarray as xr # 从背景场读网格信息 ds = xr.open_dataset("clim.nc") lon = ds.lon.values lat = ds.lat.values lev = ds.lev.values # 初始化加热场,变量名请按模式文档替换 F = xr.zeros_like(ds["t"]) # 选取热源区域:例如180W-140W,5S-10N region = ( (ds.lon >= 180) & (ds.lon <= 220) & (ds.lat >= -5) & (ds.lat <= 10) ) # 垂直范围:850hPa到400hPa vertical_mask = (ds.lev <= 850) & (ds.lev >= 400) # 设定加热强度,单位按模式文档调整 F = F.where(~(region & vertical_mask), 3.0) # 写出强迫场 F.to_netcdf("forcing.nc")

注意经度范围处理。如果模式的经度是0到360,180W要换算成180,140W要换算成220,代码里已经这么做了;如果你的背景场经度是-180到180,需要换一种写法。加热中心也可以做高斯平滑,避免强迫场在边界上产生突变,我的经验是平滑后的结果更干净。

5.3 运行、画图、判断波列

强迫场准备好之后,把namelist里的强迫文件路径指向forcing.nc,重新运行模式。结束后读取输出文件,画500hPa位势高度异常:

import matplotlib.pyplot as plt import cartopy.crs as ccrs import xarray as xr resp = xr.open_dataset("response.nc") hgt_500 = resp["gph"].sel(lev=500).squeeze() fig = plt.figure(figsize=(10, 5)) ax = fig.add_subplot(111, projection=ccrs.PlateCarree()) hgt_500.plot.contourf(ax=ax, transform=ccrs.PlateCarree(), levels=21, cmap="RdBu_r") ax.coastlines() plt.show()

正常的结果是:在热带加热区附近出现局地高度异常,然后异常成波列状向中高纬度传播,正负异常交替排列。如果图出来乱成一团,先检查强迫场量级是否合适、是否有NaN,再把积分时长适当增加。若你发现响应始终局限在热源附近,没有明显的远距离波列,可以对照一下背景场文件是不是真的取成了气候平均态,以及加热的位置是不是落在模式的有效强迫区里。

6. 我踩过的坑和留给你的建议

6.1 编译运行常见问题速查表

阶段现象原因与对策
编译netcdf.mod not foundINCLUDE路径没指向netcdf-fortran的include目录
编译大量undefined reference链接库缺失或-lnetcdff -lnetcdf顺序不对
运行直接Segmentation faultnamelist里的维数参数和输入文件不一致,先核对ntrunc、nlev
运行输出全是NaN背景场或强迫场含缺测值,读入前先填充或清洗
运行响应场全部为零强迫场全零、变量名不对、或者加热位置选在了模式范围外
运行积分一段时间后爆掉dt过大或强迫强度过大,把dt减小、强度调低试一下

Segmentation fault这个我特别想多说两句。Fortran程序没有Python那种友好的报错,常常一个段错误就默默退出,新手容易毫无头绪。遇到这种情况别慌,先用最笨的方法排查:检查namelist里的网格参数和NetCDF文件的实际维度是否一致,尤其是nlev和背景场层数,只要错一位基本就是段错误。问题排查一步一步来,不要同时改一堆参数。

6.2 几条提高效率的小习惯

跑了半年LBM之后,我总结了几条让整个工作流更顺手的经验。所有输入输出统一用NetCDF,不同版本之间迁移时省去格式转换的麻烦。试验文件夹按日期和试验目的命名,比如exp_20250115_enso_nwpac,强迫场生成脚本、namelist、输出图全放进同一个文件夹。这样即使过了半年再回来,也能完全复现当时的试验条件。

新改动参数之前,永远先把当前可正常运行的namelist备份一份。很多编译器报错查了半天,最后发现是namelist里多打了一个空格或者少了一个逗号。养成“改前备份、改后对比”的习惯,能帮你省掉大量无效调试时间。

最后,第一次跑通后不要急着上高分辨率。T21L20跑通一个试验只要几分钟,足够你把整个流程理清楚。T42甚至更高分辨率的试验,等你对参数之间怎么配合有了手感再换不迟。模式只是一件工具,真正提效率的是标准化的流程和可复现的记录习惯。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询