guide 串并行差异
源码范围:
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3d\guide_mod.F90
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3dpar\guide_p_mod.F90
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3d\leapfrog.F
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3dpar\leapfrog_p.F
Mars 运行参与度:接口兼容 + 条件边界。leapfrog 和 leapfrog_p 对 guide_main 的活动调用受 CPP_IOIPSL + planet_type=="earth" 条件包围;Mars phymars/nogcm.F90 中的 ok_guide 分支加载 relax.nc 给独立 relaxetat0 路径,不经过本页两个 COMMON guide 模块。
对照结论
串行 guide_mod 和并行 guide_p_mod 的数值职责相同:读取 nudging 输入场、插值到 LMDZ 动力层、把 U/V/T/P/Q forcing 叠加到动力状态,并可选写 guide_ins.nc。差异集中在三点:
- 并行版的 NetCDF 输入阶段仍由每个进程读完整场,真正的域分解从
guide_interp和guide_main的局部切片开始。 - 并行版用
ijb_u/ije_u与ijb_v/ije_v分开写 U/scalar 与 V 网格,并在pole_sud时缩短 V 网格尾部范围。 - 并行版
guide_out在写文件前调用gather_field,非 root 直接返回;串行版直接写完整全局数组。
模块和配置差异
| 项目 | 串行 guide_mod |
并行 guide_p_mod |
影响 |
|---|---|---|---|
| 调用方 | leapfrog 使用 guide_mod |
leapfrog_p 使用 guide_p_mod |
串/并行可执行文件走不同模块。 |
| 并行依赖 | 无 | parallel_lmdz、mod_hallo、Bands |
分布、halo 和 root I/O 是并行版新增约束。 |
| 垂直坐标开关 | guide_modele 布尔 |
guide_plevs=0/1/2,并兼容 guide_modele |
并行版可读逐格点 P.nc。 |
| 逐格点压力 | 无 pnat |
pnat1/pnat2(iip1,jjp1,nlevnc) |
guide_plevs=2 仅并行版支持。 |
| 局部范围 | 全域 | ijb_u/ije_u/jjb_u/jje_u 和 ijb_v/ije_v/jjb_v/jje_v |
U/scalar 与 V 网格要分开查。 |
| 输出 | 直接 NetCDF 写 | gather_field 后 mpi_rank==0 写 |
输出错误先查 gather/root。 |
串行版和并行版都分配全局维度的 guide 工作数组,例如 ugui(ip1jmp1,llm)、vgui(ip1jm,llm)、psgui(ip1jmp1)。并行版没有把这些数组声明成局部尺寸,而是在读入后只更新或使用本 rank 负责的连续片段。
输入读取不是并行 I/O
guide_read 和 guide_read2D 的串并行读法基本一致:每个进程打开同名 NetCDF 文件,读完整 (iip1,jjp1,nlevnc) 或 (iip1,jjm,nlevnc) 输入场,然后按需要执行 invert_lat。这意味着:
- 读文件阶段不是 root 读后广播,也不是按 rank 分块读。
- 并行内存中仍有完整
unat/vnat/tnat/qnat/psnat原始场。 - 时间片推进时,并行版只把本地
jjb:jje段从Xnat2复制到Xnat1,但随后guide_read会重新读入完整Xnat2。
真正的分布式计算在 guide_interp 发生:T/Q/U 使用 jjb_u:jje_u,V 使用 jjb_v:jje_v。U/scalar 目标场写 ijb_u:ije_u,V 目标场写 ijb_v:ije_v。
guide_interp 局部分布
串行版构造完整模型层压力、U/V staggered 压力,然后对全局场调用 pres2lev:
pression -> exner -> pls
pext = pls * aire
massbar(pext) -> plunc/plvnc
pres2lev(full field)
并行版把同一流程拆成本地行:
local pls on jjb_u:jje_u
pext local fill
Register_SwapFieldHallo(pext)
massbar_p(pext) -> local plunc/plvnc
pres2lev(field(:,jjb:jje,:), ...)
当并行版需要 V 网格上相邻纬向行时,会额外对 psnat1/2 或 pnat1/2 做 halo:guide_plevs=1 对 psnat halo,guide_plevs=2 对 pnat halo。串行版没有这一步,因为所有纬向行本地可见。
guide_main 写回范围
串行版在每个变量分支中直接对完整数组赋值:
| 变量 | 串行写回 | 并行写回 |
|---|---|---|
| U | ucov = ucov + f_add |
ucov(ijb_u:ije_u,:) += f_add(ijb_u:ije_u,:) |
| T | teta = teta + f_add |
teta(ijb_u:ije_u,:) += f_add(ijb_u:ije_u,:) |
| Ps | ps = ps + f_add(:,1) |
ps(ijb_u:ije_u) += f_add(ijb_u:ije_u,1) |
| Q | q = q + f_add |
q(ijb_u:ije_u,:) += f_add(ijb_u:ije_u,:) |
| V | vcov = vcov + f_add(1:ip1jm,:) |
vcov(ijb_v:ije_v,:) += f_add(ijb_v:ije_v,:) |
guide_addfield 同样体现这个边界:串行版对 field(:,l) 全域乘 alpha*alpha_pcor;并行版用 hsize==ip1jm 判断 V 网格,否则按 U/scalar 网格,只处理本 rank 片段。
纬向平均差异
guide_zonave 在串行版中扫描 j=1:hsize 的全纬向行。并行版只在本地纬向范围内做平均和填回:
hsize==jjm的 V 网格使用jjb_v:jje_v。- 其他 U/scalar 场计算平均时也扫描
jjb_v:jje_v,然后填回jjb_u:jje_u。
后一个分支在极点或南极缩减分布上可能带来边界差异,和 guide forcing 叠加到动力状态 中记录的运行验证点一致。
输出和 factt
factt = dtvr * iperiod / daysec 是一个动力步组对应的天数分数。它有两类用途:
- 首次进入
guide_main时传给tau2alpha,把天数单位的tau_min/tau_max转成每步松弛系数。 - 输出诊断时,调用方先把 forcing 增量写成
f_add/factt,表示按天分数归一化后的 forcing。
串行 guide_out(varname,hsize,vsize,field) 不接收 factt,所有归一化都在调用点完成。并行 guide_out(varname,hsize,vsize,field,factt) 多了一个 factt 实参,但 当前源码体内没有使用该参数;实际缩放仍来自调用点的 f_add/factt。因此排查并行 guide_ins.nc 中的 ucov/teta/ps/q/vcov forcing 量时,应先看调用点是否传入了已除以 factt 的 field,而不是期待 guide_out 内部缩放。
输出还有一个重要串并行差异:
- 串行版
SP直接写表面压力ps,维度是(LONV,LATU,TIME)。 - 并行版写
SP前先由当前ps计算层中心压力p,调用guide_out("SP",jjp1,llm,p,1.),并把SP定义成(LONV,LATU,LEVEL,TIME)。
并行版 guide_out 对所有传入 field 先执行:
gather_field(field, iip1*hsize, vsize, 0)
if (mpi_rank /= 0) return
所以只有 root 创建和写 guide_ins.nc。源码中 ps 变量被定义为 3D (lon,lat,time),但写入分支和 SP 共用 count=(iip1,jjp1,llm,1);这与 ps 定义维度不完全一致,属于需要运行验证的诊断输出风险。本页只记录源码行为,不修改 COMMON 源码。
Mars 条件经过
COMMON guide_mod/guide_p_mod 的直接入口是 guide_main(itau,ucov,vcov,teta,q,masse,ps)。串行和并行 leapfrog* 只有在 CPP_IOIPSL、planet_type=="earth" 且 logic_mod:ok_guide=.TRUE. 时才调用它。进入后还要受以下开关控制:
| 开关 | 作用 |
|---|---|
guide_u/guide_v/guide_T/guide_P/guide_Q |
决定变量分支是否读取、插值、叠加和输出。 |
guide_2D |
选择 guide_read2D 而不是 3D guide_read。 |
iguide_read/iguide_int |
控制新输入时间片读取和垂直插值频率。 |
guide_sav/iguide_sav |
控制 guide_ins.nc 诊断输出。 |
guide_add |
决定输入场是外部增量还是目标状态。 |
guide_zon |
在叠加前做纬向平均。 |
guide_plevs |
仅并行版,选择输入压力层解释。 |
Mars generic 的 phymars/nogcm.F90 中也检查 ok_guide,但那里调用的是 relaxetat0("relax.nc")。因此不要把 relax.nc 简单松弛路径和本页的 COMMON NetCDF u/v/T/hur/ps/P/apbp guide 路径混为一谈。
排错顺序
- 先确认当前可执行文件走
guide_mod还是guide_p_mod。 - 若是并行版,记录
ij_begin/ij_end/jj_begin/jj_end、pole_sud和guide_plevs。 - 输入场问题先查每个 rank 是否能读到完整 NetCDF 文件;并行版没有 root 代读。
- U/T/Q/Ps 差异查
ijb_u:ije_u,V 差异查ijb_v:ije_v。 - 插值差异查
pext/psnat/pnathalo,特别是 V 网格和guide_plevs=1/2。 - 输出文件缺失先查
guide_sav和 root rank;输出量级问题先查调用点的f_add/factt。 - 若
SP或ps输出维度异常,优先按并行guide_out中SP/ps分支确认运行时 NetCDF 行为。