guide_p_mod.F90
源码路径:LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3dpar\guide_p_mod.F90。
Mars 运行参与度:接口兼容 + 条件边界。当前源码中 leapfrog_p.F 对 guide_p_mod:guide_main 的活动调用位于 #ifdef CPP_IOIPSL 且 planet_type=="earth" 的分支内;Mars/generic 并行入口的 ok_guide 初始化路径调用 relaxetat0("relax.nc"),generic 时间推进还有 inline attenua u-wind nudging,均不经过本模块的 NetCDF guide 输入链。
文件定位
guide_p_mod 是并行动力目录中的 nudging/guide 模块,和串行 guide_mod 对应。它公开 guide_main(itau,ucov,vcov,teta,q,masse,ps),内部封装配置读取、NetCDF 输入、压力层插值、松弛系数、状态叠加和 guide_ins.nc 输出。
并行版的核心区别不是输入文件分块读取,而是读入后只处理本 rank 的局部纬向带,并在 V 网格或 staggered 压力需要相邻行时显式做 halo。
公开入口和私有例程
| 符号 | 类型 | 调用方 | 职责 |
|---|---|---|---|
guide_main |
subroutine | leapfrog_p.F 的 Earth/IOIPSL ok_guide 分支 |
建立本地 U/V 范围,按频率读取/插值 guide 输入,把 forcing 加到并行动力状态。 |
主要私有例程和串行版同名:
| 例程 | 并行职责 |
|---|---|
guide_init |
读取 guide 参数,解析 guide_plevs,分配全局尺寸 guide 数组和并行额外 pnat 场。 |
guide_read / guide_read2D |
每个 MPI rank 读取完整 NetCDF 输入场;并行版额外支持 P.nc 的 PRES。 |
guide_interp |
在 jjb_u:jje_u / jjb_v:jje_v 本地纬向段插值,并用 Register_SwapFieldHallo 补 halo。 |
guide_addfield |
按 hsize==ip1jm 区分 V 网格和 U/scalar 网格,只处理 ijb_v:ije_v 或 ijb_u:ije_u。 |
guide_zonave |
只在本地纬向段计算和填回纬向平均。 |
guide_out |
先 gather_field 到 root,只有 mpi_rank==0 写 guide_ins.nc。 |
并行状态
guide_p_mod 保存两组并行边界:
| 状态 | 来源 | 用途 |
|---|---|---|
ijb_u/ije_u, jjb_u/jje_u |
parallel_lmdz:ij_begin/jj_begin |
U、T、Q、Ps、scalar 网格本地范围。 |
ijb_v/ije_v, jjb_v/jje_v |
同上,若 pole_sud 则缩短末行 |
V 网格本地范围。 |
jjn_u/jjn_v, ijn_u/ijn_v |
上述范围长度 | 传给 pres2lev、q_sat 和本地循环。 |
这些边界在每次 guide_main 开头重设。源码中注释掉了 AllGather_Field(ucov/vcov/teta/ps/q),所以正常路径依赖 guide_read 全场输入、guide_interp 本地切片和状态局部写回,而不是每步先 allgather 动力状态。
guide_plevs
并行版新增 guide_plevs,并兼容旧的 guide_modele:
guide_plevs |
输入压力层 | 额外文件/数组 |
|---|---|---|
| 0 | 纯压力层,apnc(l) |
无 |
| 1 | 混合层,apnc(l)+bpnc(l)*psnat(i,j) |
apbp.nc, psnat |
| 2 | 逐格点压力,pnat(i,j,l) |
P.nc:PRES, pnat1/pnat2 |
guide_plevs=2 是串行 guide_mod 没有的能力。它让 T/Q/U/V 的输入压力可随水平格点和层变化;V 网格计算前需要对 pnat 做 halo,避免用不到相邻纬向行。
输入和插值流程
guide_read 与 guide_read2D 并不做并行 I/O 分块。每个 rank 打开同一组文件并读完整场,然后 guide_interp 才按本地范围访问:
read complete unat/vnat/tnat/qnat/psnat/pnat
-> local model pressure on jjb_u:jje_u
-> pext halo
-> massbar_p -> plunc/plvnc
-> pres2lev on local slices
-> write Xgui on ijb_u:ije_u or ijb_v:ije_v
关键通信点:
pext在massbar_p前做Register_SwapFieldHallo。guide_plevs=1的 V 网格前对psnat1/2做 halo。guide_plevs=2的 V 网格前对pnat1/2做 halo。
T/Q/U 的 pres2lev 传入 iip1,jjn_u;V 的 pres2lev 传入 iip1,jjn_v。湿度相对湿度转换调用 q_sat(iip1*jjn_u*llm,...),只覆盖本地 U/scalar 范围。
状态叠加
并行版和串行版同样按 U、T、P、Q、V 顺序处理,但只写本地段:
| 变量 | 本地范围 | 后续动作 |
|---|---|---|
| U | ijb_u:ije_u |
guide_addfield(ip1jmp1,...) 后写 ucov。 |
| T | ijb_u:ije_u |
写 teta。 |
| Ps | ijb_u:ije_u |
写 ps 后调用 pression_p 和 massdair_p。 |
| Q | ijb_u:ije_u |
写 q。 |
| V | ijb_v:ije_v |
guide_addfield(ip1jm,...) 后写 vcov。 |
ini_anal 分支和串行版有同一疑点:源码把 V 初态写为 ugui2,不是 vgui2。并行版形式是 vcov(ijb_v:ije_v,:)=ugui2(ijb_v:ije_v,:)。
输出诊断
guide_out(varname,hsize,vsize,field,factt) 是并行版最明显的 I/O 差异:
CALL gather_field(field, iip1*hsize, vsize, 0)
IF (mpi_rank /= 0) RETURN
因此只有 root 创建和写 guide_ins.nc。factt 是形式参数,但 当前源码体内没有使用它;forcing 量级仍由调用点传入 f_add/factt 决定。
并行输出还和串行版存在两个源码级差异:
- 并行版
SP写层中心压力p(1:ip1jmp1,1:llm),维度定义为(LONV,LATU,LEVEL,TIME);串行版SP写表面压力ps,是 3D time field。 - 并行版
SELECT CASE ("SP","ps")共用count=(iip1,jjp1,llm,1),但ps变量定义为 3D(lon,lat,time);这是运行验证风险,页面按源码记录,不修改实现。
Mars 边界
并行 guide 模块在 Mars 文档中的价值主要是边界和接口兼容:
| 路径 | 当前源码行为 | 是否经过 guide_p_mod |
|---|---|---|
Earth + IOIPSL + ok_guide |
leapfrog_p 的 OMP master 调 guide_main,随后 barrier |
是 |
Mars planet_type=="mars" |
leapfrog_p 不调 guide_main |
否 |
Generic + ok_guide |
gcm.F 初始化读 relax.nc;leapfrog_p 中还有 inline attenua |
否 |
因此并行 Mars 排错时,ok_guide 本身不足以说明进入 guide_p_mod。应先确认 planet_type、CPP_IOIPSL、运行入口和是否有本地补丁。