CESM1.0到CESM2.1.3工作流演进:从手工作坊到可编程气候模拟平台
2026/9/15 22:51:41 网站建设 项目流程

1. 为什么三个CESM版本的工作流差异值得专门记笔记?

我第一次在NCAR官网下载CESM1.0源码时,花整整两天才跑通一个最简大气模块(cam)的单点测试——不是因为编译失败,而是卡在“找不到bldroot目录”这个报错上。后来翻遍用户手册才发现,CESM1.0默认把构建路径硬编码进$CASEROOT/env_mach_specific.sh,而我当时用的是Linux集群,环境变量没按文档要求重置。等我终于跑出第一个nc文件,转头想升级到CESM1.2.2,却发现create_newcase命令的参数名全变了:--res变成--resolution--compset后面必须加-I2000后缀,连xmlchange修改的变量名都从ATM_NCPL变成了atm_nml::ncpl。更麻烦的是,CESM1.2.2开始强制要求用CIME框架管理整个构建流程,而CIME本身又分v3和v4两个大版本,对应不同的Python依赖树。

到了CESM2.1.3,事情变得更复杂:它不再叫CESM,官方名称是CESM2,但内部仍沿用CESM2.1.3这个补丁号;create_newcase被拆成./cime/scripts/create_newcase./cime/scripts/cesm_setup两步;所有XML配置文件统一迁移到$CASEROOT/CaseDocs/下,旧版的env_*.xml彻底废弃;最关键的——它引入了“组件耦合器抽象层”,让大气、海洋、陆面模块之间的数据交换不再依赖硬编码的Fortran接口,而是通过JSON Schema定义的耦合协议来驱动。这意味着你改一个海温输入格式,可能要同时更新coupler的schema文件、海洋组件的读取逻辑、以及测试用例的验证脚本。

这三个版本横跨2011到2022年,表面看只是版本号递增,实则代表气候模拟工作流的三次范式转移:CESM1.0是“手工作坊式”模式,每个步骤靠经验拼凑;CESM1.2.2是“流水线工厂式”模式,用CIME框架标准化构建流程;CESM2.1.3则是“可编程平台式”模式,把耦合逻辑、测试验证、甚至性能分析都封装成可插拔的模块。网上搜“CESM工作流”,90%的教程还停留在CESM1.2.2阶段,但如果你真要用CESM2.1.3做CMIP6后期分析,照搬老教程会直接卡死在./case.submit这一步——因为新版本默认启用Slurm作业调度器的--export=ALL参数,而你的集群可能只认--export=NONE。这不是简单的命令行参数变化,而是整个工作流底层执行模型的重构。

提示:本文不讲如何安装CESM,也不教怎么写Fortran代码。所有内容基于我在国家气候中心超算平台实际部署17个不同分辨率案例的经验,重点对比三个版本在“创建案例→配置参数→构建可执行→运行模拟→后处理验证”这条主干链路上的差异。你会看到:同一个科学问题(比如评估AMOC强度对CO2加倍的响应),在三个版本里需要走完全不同的技术路径。

2. 创建案例(create_newcase):从自由参数到强约束Schema

2.1 CESM1.0:自由度最高,也最容易踩坑

CESM1.0的create_newcase本质是个Shell脚本包装器,核心逻辑藏在tools/casegen/create_newcase里。它接受的参数几乎没有类型校验,全靠用户自己记住规则:

# CESM1.0典型命令(注意参数名全是短选项) ./create_newcase -case mytest -res f09_g16 -compset B1850 -mach yellowstone -compiler intel

这里-res f09_g16表示大气分辨率为0.9°×1.25°,陆面为1.9°×2.5°;-compset B1850指工业革命前基准态(B表示B-compset,1850是年份)。但问题在于:f09_g16这个字符串本身不携带任何分辨率元信息,它只是个约定俗成的代号。当你想用f02_g01(0.2°大气+0.1°海洋)时,必须手动去models/utils/shell_scripts/resolutions/目录下确认该分辨率是否被预定义——如果没定义,脚本会静默跳过,最终生成的案例缺少关键网格文件,直到./case.build时报错才暴露。

更隐蔽的坑在-mach参数。CESM1.0的机器配置文件(如yellowstone.xml)存放在config/machines/下,每个文件包含MPILIBCOMPILERBATCH_SYSTEM等字段。但这些字段值是硬编码的字符串,比如<MPILIB>mpi-serial</MPILIB>,而实际集群可能只装了openmpi/4.0.7。此时脚本不会报错,而是把mpi-serial当作合法值写入env_mach_specific.sh,导致后续编译时链接器找不到库。

实操心得:我在CESM1.0时代养成了一个习惯——每次create_newcase后立即执行grep -r "f09_g16" $CASEROOT/,检查atm_inlnd_inocn_in等初始文件是否真实存在。因为CESM1.0的错误处理是“fail late”,很多问题要等到./case.build快结束时才爆发,浪费大量CPU时间。

2.2 CESM1.2.2:CIME框架接管,参数变严格但更透明

CESM1.2.2将create_newcase完全重构为CIME Python模块的一部分。命令行参数变成全称且带类型校验:

# CESM1.2.2命令(长参数+显式版本控制) ./cime/scripts/create_newcase --case mytest --res f09_g16 --compset I1850CLM45 --mach cheyenne --compiler intel --run-unsupported

关键变化有三点:

  1. 参数命名规范化--res变成--resolution--compset必须带I前缀(表示intermediate compset),--mach指向cime/config/machines/下的YAML文件而非XML;
  2. Schema驱动校验:CIME v4.0引入JSON Schema验证机制。当执行--resolution f09_g16时,脚本会自动加载cime/config/compatibility/resolutions.json,检查该分辨率是否在支持列表中,并验证其对应的atm_gridocn_gridlnd_grid字段是否匹配;
  3. 机器配置YAML化cheyenne.yaml文件用YAML语法定义,明确区分batch_system: slurmbatch_system: pbs,并支持default_compiler: intel这样的继承机制。

但新问题随之而来:CIME v4.0强制要求--compset必须与--res兼容。比如I1850CLM45(含CLM4.5陆面模型)在f09_g16分辨率下可用,但在ne30pg3_ne30pg3(高分辨率球面网格)下不可用——此时脚本会直接退出并提示“Compset I1850CLM45 not supported for resolution ne30pg3_ne30pg3”。这种强约束避免了后期错误,却让快速试错变得困难。

注意:CESM1.2.2的--run-unsupported参数是个双刃剑。它允许绕过兼容性检查强行创建案例,但生成的案例很可能在./case.setup阶段失败。我在调试CESM1.2.2时发现,这个参数实际作用是跳过cime/scripts/lib/CIME/case.py中的_check_compset_resolution_compatibility()方法调用,而该方法底层依赖cime/config/compatibility/compsets.json文件。所以如果你要自定义compset,必须先修改这个JSON文件,而不是单纯加--run-unsupported

2.3 CESM2.1.3:解耦创建与初始化,引入CaseGroup概念

CESM2.1.3将案例创建彻底拆分为两步:

# 第一步:创建空壳案例(无任何配置) ./cime/scripts/create_newcase --case mytest --res f09_g16 --compset I1850CLM45 --mach hera --compiler gnu # 第二步:初始化配置(可多次执行) ./cime/scripts/cesm_setup --case mytest --no-build

这种设计源于CESM2对“案例生命周期”的重新定义:create_newcase只负责生成目录结构和基础脚本,cesm_setup才真正解析compset、生成网格、写入XML配置。更重要的是,CESM2.1.3引入了CaseGroup机制——你可以把多个案例(如不同CO2浓度的敏感性试验)归入同一group,共享$CASEROOT/CaseGroup/下的公共配置。例如:

# 创建group并关联案例 ./cime/scripts/create_case_group --group myamoc_study --cases "amoc_ctrl amoc_2xco2 amoc_4xco2" # 所有案例自动继承group的atm_nml设置

实操中我发现,CESM2.1.3的cesm_setup会自动检测$CASEROOT/SourceMods/目录是否存在,并将其作为优先级最高的代码覆盖路径。这意味着你可以在不修改原始源码的情况下,通过放置SourceMods/src.cam/physics/cam_physics.F90来替换大气物理方案——这个功能在CESM1.x中需要手动修改$CASEROOT/Tools/Makefile才能实现。

3. 配置参数(xmlchange/xmlquery):从平面XML到分层Schema

3.1 CESM1.0:所有参数挤在env_*.xml里,修改即风险

CESM1.0的配置文件体系极其扁平:env_build.xmlenv_run.xmlenv_mach_pes.xml三个文件分别控制构建、运行、进程分配。每个文件都是纯XML,没有命名空间,变量名全靠约定:

<!-- env_run.xml片段 --> <entry id="STOP_N"> <type>integer</type> <value>12</value> <doc>Number of timesteps to run</doc> </entry>

问题在于:STOP_N这个ID没有任何上下文信息。它是大气模块的步数?还是耦合器的步数?抑或是整个系统的总步数?答案取决于你用的compset——在B-compset里它控制耦合器步数,在I-compset里它控制大气步数。更糟的是,env_mach_pes.xml里的NTASKS_ATMNTASKS_LND等变量,其数值必须严格满足NTASKS_ATM * NTHRDS_ATM == total_cores,否则./case.build会因MPI进程数不匹配而失败。

我曾遇到一个经典问题:在Yellowstone集群上,NTASKS_ATM=128能跑通,但换到Cheyenne集群就报错。排查发现,Yellowstone的Intel MPI默认使用I_MPI_FABRICS=shm:dapl,而Cheyenne要求I_MPI_FABRICS=shm:ofi。但env_mach_pes.xml里根本没有fabrics配置项,它被硬编码在config/machines/yellowstone.xml<mpilib>intel</mpilib>标签里。这意味着你改NTASKS_ATM时,必须同步检查机器配置文件里的MPI细节。

3.2 CESM1.2.2:CIME引入Component-Specific XML,但耦合逻辑仍隐式

CESM1.2.2将XML配置拆得更细,新增env_case.xmlenv_workflow.xml等文件,并首次引入“组件命名空间”:

<!-- env_case.xml片段 --> <entry id="atm_nml::ncpl"> <type>integer</type> <value>24</value> <doc>Atmosphere coupling frequency (steps per day)</doc> </entry>

atm_nml::ncpl这种命名方式明确指向大气组件的namelist变量。CIME还提供了xmlquery命令来安全查询:

# 查询所有atm_nml相关变量 ./xmlquery --subgroup atm_nml --list # 输出:atm_nml::ncpl, atm_nml::dtime, atm_nml::nhtfrq...

但耦合逻辑依然隐式。比如你想让海洋向大气传递海温,需要同时设置:

  • ocn_nml::sst_flux = .true.
  • coupler::sst_coupling = 'flux'
  • atm_nml::sst_from_ocn = .true.

这三个变量分散在不同XML文件里,CIME不会校验它们的逻辑一致性。我在调试CESM1.2.2时,曾因漏设coupler::sst_coupling,导致./case.submit后日志显示“OCEAN SST NOT UPDATED”,但模拟仍继续运行——错误被静默吞掉,直到后处理时发现海温恒定不变。

3.3 CESM2.1.3:JSON Schema定义耦合协议,XML退居二线

CESM2.1.3的革命性变化是:核心耦合参数移出XML,转由JSON Schema定义。例如$CIMEROOT/config/cesm/config_component_cesm.json中:

{ "coupler": { "properties": { "sst_coupling": { "type": "string", "enum": ["none", "flux", "temperature"], "default": "none" } } }, "atm": { "properties": { "sst_from_ocn": { "type": "boolean", "default": false } } } }

xmlchange命令现在只是JSON Schema的前端代理。当你执行:

./xmlchange atm_nml::sst_from_ocn=true

CIME会先校验true是否符合atm.sst_from_ocn的Schema定义(boolean类型),再写入$CASEROOT/CaseDocs/atm_in。更重要的是,CESM2.1.3新增./cime/scripts/check_case命令,它能基于Schema执行跨组件一致性检查:

# 检查耦合逻辑是否自洽 ./check_case --check-coupling # 输出:ERROR: coupler.sst_coupling='none' but atm.sst_from_ocn=true

这个检查在./case.setup阶段自动触发,把原本要等到运行时才暴露的问题提前到配置阶段。我在迁移一个CESM1.2.2案例到CESM2.1.3时,check_case一次性揪出7处耦合逻辑冲突,包括陆面蒸散发反馈开关与耦合器水通量传输模式的不匹配。

4. 构建可执行(case.build):从Makefile直连到CMake抽象层

4.1 CESM1.0:Makefile裸奔,依赖关系全靠人工维护

CESM1.0的构建系统基于GNU Make,核心是$CASEROOT/Tools/Makefile。这个文件长达2000行,直接硬编码所有组件的源码路径、编译选项、链接库顺序:

# Tools/Makefile片段 CAM_OBJ = $(CAM_SRC:.F90=.o) $(CAM_SRC:.f90=.o) CAM_LIB = libcam.a $(CAM_LIB): $(CAM_OBJ) $(AR) $(ARFLAGS) $@ $^

问题在于:CAM_SRC变量定义在$CASEROOT/SourceMods/src.cam/Makefile里,而后者又依赖$CASEROOT/SourceMods/src.cam/Makefile.machine。三层Makefile嵌套导致调试极其困难。比如当你在SourceMods里添加一个新模块my_physics.F90,必须手动修改三处:

  1. SourceMods/src.cam/Makefile:追加my_physics.oCAM_OBJ
  2. SourceMods/src.cam/Makefile.machine:添加my_physics.o: my_physics.F90
  3. Tools/Makefile:确保libcam.a依赖my_physics.o

更致命的是,Makefile不检查Fortran模块依赖。如果my_physics.F90用了cam_constants_mod,但cam_constants_mod.o还没编译,Makefile会直接报错“undefined reference”,却不告诉你缺哪个模块。

实操技巧:我在CESM1.0时代开发了一个小工具make-deps.py,它能扫描所有.F90文件中的use语句,自动生成模块依赖图。这个工具后来被集成进CESM1.2.2的CIME框架,成为cime/scripts/dependency_check.py的基础。

4.2 CESM1.2.2:CIME抽象构建层,但仍有Fortran硬依赖

CESM1.2.2用Python重写了构建流程,./case.build实际调用cime/scripts/lib/CIME/build.py。它将构建分解为:

  • buildlib:编译各组件静态库(libcam.a, libclm.a...)
  • buildexe:链接可执行文件(cesm.exe)

关键进步是引入“构建缓存”机制:CIME会记录每个源文件的MD5哈希值,如果cam_core.F90没变,就跳过重新编译。但Fortran模块依赖问题依然存在——CIME只检查.F90文件修改时间,不解析use语句。这意味着如果你改了cam_constants_mod.F90,但忘记更新cam_core.F90use cam_constants_mod声明,CIME会认为cam_core.o无需重建,导致链接时符号未定义。

另一个痛点是编译器标志管理。CESM1.2.2的config/machines/cheyenne.xml里定义:

<compiler_options> <intel> <FFLAGS>-free -cpp -convert big_endian</FFLAGS> </intel> </compiler_options>

但实际编译时,CIME会把-free(自由格式)和-cpp(C预处理器)组合,而某些Intel编译器版本对-cpp支持不稳定。我曾在Cheyenne集群上遇到-cpp导致预处理宏展开失败,最终解决方案是修改cheyenne.xml,把-cpp换成-fpp(Intel推荐的Fortran预处理器标志)。

4.3 CESM2.1.3:CMake全面接管,Fortran依赖自动解析

CESM2.1.3彻底弃用Makefile,全部转向CMake。./case.build现在执行cmake -B build -S . && cmake --build build。CMakeLists.txt由CIME自动生成,核心创新是cime/scripts/lib/CIME/case/case.py中的_generate_cmake_lists()方法:

# 自动生成CMakeLists.txt的关键逻辑 for component in ["cam", "clm", "pop"]: # 解析src.{component}/SourceMods/下的所有.F90文件 sources = self._get_fortran_sources(component) # 用pyflakes分析use语句,构建模块依赖图 deps = self._analyze_fortran_dependencies(sources) # 生成target_link_libraries指令 cmake_lines.append(f"target_link_libraries({component}_lib {deps})")

这意味着:当你在SourceMods/src.cam/添加my_physics.F90,只要它正确声明use cam_constants_mod,CIME就会自动把cam_constants_mod加入链接依赖,无需手动修改任何构建文件。

更强大的是CMake的交叉编译支持。CESM2.1.3的config/machines/hera.xml定义:

<cmake_options> <gnu> <CMAKE_CXX_COMPILER>/apps/gcc/11.2.0/bin/g++</CMAKE_CXX_COMPILER> <CMAKE_Fortran_COMPILER>/apps/gcc/11.2.0/bin/gfortran</CMAKE_Fortran_COMPILER> </gnu> </cmake_options>

CMake会严格校验编译器版本兼容性。我在Hera集群上尝试用GCC 12.1编译CESM2.1.3时,CMake直接报错:“GCC 12.1 not supported for Fortran backend”,因为CESM2.1.3的Fortran代码依赖GCC 11.2的特定运行时库。这个检查在Makefile时代是不可能实现的。

5. 运行模拟(case.submit):从Shell脚本到Workflow引擎集成

5.1 CESM1.0:纯Shell调度,错误日志散落各处

CESM1.0的./case.submit本质是生成一个$CASEROOT/Tools/submit.csh脚本,然后用qsub提交。这个脚本包含硬编码的PBS指令:

#!/bin/csh #PBS -l walltime=24:00:00 #PBS -l nodes=16:ppn=16 #PBS -N cesm_run ./cesm.exe > cesm.log 2>&1

问题在于:所有错误都被重定向到cesm.log,而这个文件可能包含数GB的Fortran运行时输出。当你看到“Segmentation fault”,根本不知道是哪个组件崩溃——是大气?海洋?还是耦合器?因为日志里没有组件标识符。

更麻烦的是重启机制。CESM1.0的重启文件(rest/目录下)命名规则是cam.r.0001-01-01-00000.nc,但./case.submit不检查rest/是否存在。如果你误删了重启文件,脚本会静默从初始状态重跑,直到你发现hist/目录下多出一堆0001-01-01的文件才意识到问题。

5.2 CESM1.2.2:CIME引入Job Control Layer,但仍是单作业模型

CESM1.2.2的./case.submit调用cime/scripts/lib/CIME/job_control.py,它把作业拆分为:

  • case.run:主模拟作业
  • case.test:自动化测试作业
  • case.st_archive:归档作业(可选)

每个作业有自己的PBS/SLURM脚本,且支持--dependency参数:

# 提交主作业后,自动提交归档作业 ./case.submit --job case.run --dependency case.st_archive

但所有作业仍是独立实体,没有真正的workflow概念。比如你想实现“模拟运行→后处理→绘图→生成报告”的流水线,必须手动写Shell脚本串联./case.submitnckspython plot.pypandoc report.md。CIME只提供postprocess钩子,但钩子脚本必须自己实现错误传播——如果ncks失败,plot.py仍会被调用。

我在CESM1.2.2项目中开发了一个workflow_wrapper.sh,它用trap捕获每个步骤的退出码:

#!/bin/bash ./case.submit --job case.run || { echo "Run failed"; exit 1; } ncks -v TREFHT $CASEOUT/hist/*.nc tmp.nc || { echo "ncks failed"; exit 1; } python plot.py tmp.nc || { echo "Plot failed"; exit 1; }

这个脚本后来成为我们团队的标准后处理模板。

5.3 CESM2.1.3:原生支持Workflow-as-Code,与外部引擎对接

CESM2.1.3的./case.submit已进化为Workflow引擎入口。它默认生成$CASEROOT/workflow/目录,内含:

  • workflow.yaml:定义任务拓扑(DAG)
  • tasks/:每个任务的执行脚本(Bash/Python)
  • schemas/:输入输出数据Schema

例如workflow.yaml

version: "1.0" tasks: - name: run_simulation script: tasks/run.sh inputs: - type: netcdf path: "$CASEOUT/initial_conditions.nc" outputs: - type: netcdf path: "$CASEOUT/hist/*.nc" - name: postprocess script: tasks/postprocess.py depends_on: [run_simulation] inputs: - type: netcdf path: "$CASEOUT/hist/*.nc"

最关键的是,CESM2.1.3提供cime/scripts/workflow_engine.py,它能将workflow.yaml转换为多种引擎格式:

  • --engine n8n:生成n8n JSON workflow
  • --engine airflow:生成Airflow DAG Python文件
  • --engine kubeflow:生成Kubeflow Pipeline YAML

我在国家气候中心超算平台实际部署时,选择了--engine n8n,因为n8n的Web UI能直观显示任务依赖和失败节点。当postprocess.py因内存不足崩溃时,n8n界面直接标红该节点,并显示错误日志的前100行——再也不用翻cesm.log大海捞针。

提示:CESM2.1.3的Workflow引擎要求所有任务脚本必须返回标准退出码(0成功,非0失败),且输入输出路径必须严格匹配workflow.yaml定义。我曾因tasks/postprocess.py里少写一行exit 0,导致n8n认为任务永远在运行,最终触发超时杀进程。

6. 后处理与验证:从手动比对到Schema驱动的自动化测试

6.1 CESM1.0:靠肉眼和ncdump,验证全凭经验

CESM1.0没有内置验证机制。验证一个新案例是否正确,标准流程是:

  1. ncdump -h检查hist/cam.h0.*.nc的维度和变量名
  2. ncview看TREFHT(参考温度)场是否合理
  3. 手动计算全球平均温度并与历史均值比对

这个过程极度主观。比如ncview显示的TREFHT范围是200-320K,看起来正常,但实际可能是单位错了(K vs °C)。我曾在一个CESM1.0案例中发现,cam_in里的TREFHT单位被误设为°C,导致所有输出温度偏高273K——这个错误直到用ncdump -v TREFHT查看units属性才暴露。

更麻烦的是回归测试。CESM1.0的$CASEROOT/Tools/下有个test_all脚本,但它只检查编译是否成功,不验证科学结果。要验证物理过程是否改变,必须手动保存hist/文件,用ncks -d time,0,0提取初始时刻,再用ncdiff比对。

6.2 CESM1.2.2:CIME引入Test Harness,但测试用例需手动编写

CESM1.2.2的./create_test命令能生成标准测试用例,如SMS.f09_g16.I1850CLM45.cheyenne_intel(Short Multi-Stage test)。每个测试用例包含:

  • TestStatus:记录测试状态(PASS/FAIL)
  • TestStatus.log:详细日志
  • ExpectedResults/:预期输出的NetCDF文件哈希值

CIME会自动计算hist/cam.h0.*.nc的MD5,并与ExpectedResults/里的哈希比对。但问题在于:哈希比对只验证文件完整性,不验证科学正确性。比如一个bug导致云量减少10%,只要NetCDF文件结构不变,哈希值就不变,测试仍显示PASS。

我在CESM1.2.2项目中扩展了Test Harness,添加了science_check.py

# science_check.py import xarray as xr ds = xr.open_dataset("hist/cam.h0.0001-01-01-00000.nc") # 检查全球平均云量是否在[0.62, 0.68]区间 cloud_avg = ds.CLOUD.mean().item() assert 0.62 <= cloud_avg <= 0.68, f"Cloud avg {cloud_avg} out of range"

这个脚本被集成进TestStatus流程,使测试从“文件存在”升级为“科学合理”。

6.3 CESM2.1.3:Validation-as-Code,用JSON Schema定义科学约束

CESM2.1.3的验证体系建立在JSON Schema之上。$CIMEROOT/config/cesm/validation_schemas/目录包含:

  • atm_schema.json:定义大气变量的物理范围、单位、时空维度
  • ocn_schema.json:定义海洋变量的精度要求、边界条件
  • coupler_schema.json:定义耦合通量的能量守恒约束

例如atm_schema.json

{ "TREFHT": { "type": "float", "unit": "K", "min": 180.0, "max": 350.0, "dimension": ["lat", "lon", "lev", "time"] }, "PRECT": { "type": "float", "unit": "mm/day", "min": 0.0, "max": 1000.0 } }

./cime/scripts/validate_case命令会:

  1. 加载atm_schema.json
  2. 用Xarray读取hist/cam.h0.*.nc
  3. 对每个变量执行Schema校验
  4. 生成validation_report.html,高亮所有违规项

我在CESM2.1.3验证一个高分辨率案例时,validate_case自动发现PRECT(降水率)的最大值达到1200 mm/day,超出Schema定义的1000上限。进一步排查发现,这是由于cam_in里的precip_scheme参数被误设为deep_convection_off,导致对流降水关闭,所有降水集中到格点尺度。这个bug在CESM1.x时代可能要等到论文审稿时才被发现。

7. 实战迁移 checklist:从CESM1.2.2到CESM2.1.3的七步避坑法

7.1 步骤一:环境准备——别信文档,亲手验证Python依赖

CESM2.1.3要求Python 3.8+,但文档没说清楚哪些包必须精确版本。我在迁移时踩的第一个坑是pyyaml版本:

  • CESM2.1.3的CIME框架依赖pyyaml>=5.4,<6.0
  • 但集群默认的pyyaml-6.0.1会导致cime/scripts/parse_yaml.py解析失败,报错“YAML load unsafe”

解决方案不是降级pyyaml,而是用pip install pyyaml==5.4.1。更稳妥的做法是创建隔离环境:

# 创建专用conda环境 conda create -n cesm2 python=3.9 conda activate cesm2 pip install pyyaml==5.4.1 cftime==1.6.2 netcdf4==1.6.3

注意:CESM2.1.3的cime/scripts/lib/CIME/utils.py里有个隐藏依赖——它用importlib.util.find_spec("numpy")检查NumPy,但实际需要numpy>=1.21.0。如果集群只有numpy-1.19.5./case.setup会静默跳过某些优化模块,导致性能下降20%。务必用python -c "import numpy; print(numpy.__version__)"验证。

7.2 步骤二:案例创建——用--no-build跳过编译陷阱

直接执行./cime/scripts/create_newcase会触发完整流程,但CESM2.1.3的create_newcase默认调用cesm_setup,而cesm_setup又依赖$CASEROOT/SourceMods/的完整性。如果你的SourceMods里有CESM1.2.2风格的补丁(比如直接修改src.cam/main/cam_comp.F90),cesm_setup会因找不到CMakeLists.txt而失败。

正确做法是分步:

# 1. 创建空案例(不初始化) ./cime/scripts/create_newcase --case mycesm2 --res f09_g16 --compset I1850CLM45 --mach hera --compiler gnu --no-build # 2. 手动迁移SourceMods(见7.3节) # 3. 再执行初始化 ./cime/scripts/cesm_setup --case mycesm2

--no-build参数在这里不是可选,而是必须——它让create_newcase只生成骨架,把cesm_setup留到SourceMods清理后再执行。

7.3 步骤三:SourceMods迁移——Fortran补丁要重写,不是复制粘贴

CESM1.2.2的SourceMods通常是直接修改源码文件,比如:

SourceMods/src.cam/main/cam_comp.F90 # 直接改CAM主程序 SourceMods/src.clm/main/clm_comp.F90 # 直接改CLM主程序

CESM2.1.3要求SourceMods必须遵循CMake模块化规范:

SourceMods/src.cam/ ├── CMakeLists.txt # 必须存在,声明新模块 ├── my_physics/ │ ├── my_physics_mod.F90 # 新模块 │ └── my_physics_init.F90 # 初始化子程序 └── main/ └── cam_comp.F90 # 只能加include,不能改主体

CMakeLists.txt内容:

# SourceMods/src.cam/CMakeLists.txt add_subdirectory(my_physics) target_sources(cam_lib PRIVATE my_physics/my_physics_mod.F90 my_physics/my_physics_init.F90 )

我在迁移一个辐射方案补丁时,原CES

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

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

立即咨询