guide 输入场读取
guide_read 和 guide_read2D 负责从 NetCDF 文件读取 nudging 输入场。两者共享相同的文件打开和初始化逻辑,区别在于空间维度:guide_read 读取完整三维场 (iip1, jjp1, nlevnc),guide_read2D 读取经度-气压二维切片 (jjp1, nlevnc) 后沿 iip1 广播。串行版 guide_mod 和并行版 guide_p_mod 在读取逻辑上几乎相同,但并行版额外支持 guide_plevs=2 逐格点气压场读取。
调用链
guide_main 在每个读取步调用 guide_read(step_rea) 或 guide_read2D(step_rea),由 guide_2D 开关选择。guide_init 首次执行时通过 guide_read(1) 或 guide_read2D(1) 加载第一个时间片,随后将 Xnat2 复制到 Xnat1 作为初始对。guide_main 中每次读取前先执行 Xnat1 = Xnat2(仅局部 jjb:jje 对并行版),然后读入新的 Xnat2。
文件结构与 NetCDF 变量映射
| 物理量 | 文件名 | NetCDF 变量 | 水平维度 | 垂直维度 |
|---|---|---|---|---|
| u | u.nc |
UWND |
(iip1, jjp1) |
nlevnc |
| v | v.nc |
VWND |
(iip1, jjm) |
nlevnc |
| T | T.nc |
AIR |
(iip1, jjp1) |
nlevnc |
| Q/hur | hur.nc |
RH |
(iip1, jjp1) |
nlevnc |
| Ps | ps.nc |
SP |
(iip1, jjp1) |
1(第 3 维 = time) |
| AP/BP | apbp.nc |
AP, BP |
1D (nlevnc) |
— |
| P | P.nc |
PRES |
(iip1, jjp1) |
nlevnc |
Ps 的 start/count 特殊处理:start(3)=timestep, start(4)=0, count(2)=jjp1, count(3)=1, count(4)=0,即从第 3 维读取单个时间步。其余三维场使用 start(4)=timestep, count(4)=1。
首次调用初始化
两个 read 子例程都用 first SAVE flag 控制首次调用。首次调用完成所有文件打开、变量 ID 查询和垂直坐标系数读取。文件打开顺序有依赖:需要先确定 ncidpl(用于读取 LEVEL/PRESSURE 或 AP/BP 的文件 ID),按 guide_plevs 值或变量优先级依次尝试 apbp.nc → P.nc → u.nc → v.nc → T.nc → hur.nc,取第一个成功打开的作为 ncidpl。
垂直坐标系数
guide_plevs=0(纯气压层):从 NetCDF 的 LEVEL 或 PRESSURE 维变量读取 apnc,乘以 100 转 Pa,bpnc 全部置零。guide_plevs=1(混合层):从 apbp.nc 读取 AP 和 BP 变量到 apnc 和 bpnc。guide_plevs=2(逐格点气压):不在此处读取系数,气压由 P.nc 中 pnat 三维场直接提供。
NC_DOUBLE 精度守卫
所有 NF_GET_VARA_* 调用用 #ifdef NC_DOUBLE 条件编译选择 NF_GET_VARA_DOUBLE 或 NF_GET_VARA_REAL。这是 LMDZ 全局精度抽象:编译时 CPP_REAL8 宏定义 NC_DOUBLE,使所有 I/O 使用双精度。guide 模块不检查返回值 status,依赖 NetCDF 运行时错误处理。
guide_read 3D 模式
串行版对每个启用的变量读取完整 (iip1, jjp1, nlevnc) 或 (iip1, jjm, nlevnc)(v)数组。读取后若 invert_y=.TRUE. 则调用 invert_lat 翻转南北方向。invert_lat 是 dyn3d_common/invert_lat.F90 中的独立子例程,用临时数组 f_aux 将 field(:,j,:) 映射到 field(:,ysize+1-j,:)。
并行版读取逻辑与串行版完全相同——并行版在 I/O 阶段不做域分解,每个进程读取完整场(所有进程都执行 NF_GET_VARA_*)。域分解发生在后续 guide_interp 和 guide_main 中通过 jjb_u:jje_u / jjb_v:jje_v 切片访问。
并行版额外:guide_plevs=2
并行版 guide_read 在 guide_plevs=2 时额外读取 P.nc 中 PRES 变量到 pnat2(iip1,jjp1,nlevnc)。串行版无此路径。
guide_read2D 2D 模式
当 guide_2D=.TRUE. 时使用。读取经度-气压二维切片 (jjp1, nlevnc) 或 (jjm, nlevnc)(v),然后通过 DO i=1,iip1; Xnat2(i,:,:)=zu(:,:) 广播到所有经度。Ps 读取为 1D (jjp1) 后广播到 (iip1, jjp1)。
并行版在 guide_plevs=2 时也支持 2D 模式读取 P.nc 的 PRES 变量为 (jjp1, nlevnc) 后广播到三维 pnat2。
时间步管理
guide_main 中 iguide_read 控制读取时机:
iguide_read > 0:每天读iguide_read次,tau = iguide_read * itau / day_stepiguide_read < 0:每|iguide_read|天读一次,tau = itau / day_step / |iguide_read|iguide_read = 0:只在guide_init读一次,时间插值冻结在tau=1
tau 的整数部分判断是否到达新时间片(reste = tau - AINT(tau),若 reste==0 则读取),小数部分作为两帧间的线性插值权重。itau_test 防止同一 itau 重复读取(double-pass 检测,若检测到则 stop)。
错误处理
文件打开和变量查询失败时调用 abort_gcm(modname, abort_message, 1) 终止。错误信息用法语(如 'Guide: probleme -> pas de fichier u.nc')。不检查 NF_GET_VARA_* 的返回 status,依赖 NetCDF 运行时错误。
串并行差异
| 特性 | 串行 guide_read/2D |
并行 guide_read/2D |
|---|---|---|
| I/O 分布 | 单进程读取全部 | 所有进程读取全部(无域分解 I/O) |
guide_plevs=2 |
不支持 | 支持 P.nc 逐格点气压 |
| 文件打开条件 | guide_modele 布尔 |
guide_plevs 整数 0/1/2 |
ncidpl 探测 |
按变量优先级 | 增加 P.nc 路径 |
psnat 条件 |
guide_P .OR. guide_modele |
guide_P .OR. guide_plevs==1 |
pnat 场 |
不存在 | 仅 guide_plevs=2 |
invert_lat |
全局 | 全局(同串行,I/O 不分解) |
NetCDF95 在 guide 中的角色
netcdf95 模块(libf/misc/netcdf95.F90)仅在 guide_out 中使用 nf95_def_var 和 nf95_put_var 写 alpha_T/alpha_Q 诊断变量。guide_read / guide_read2D 不使用 netcdf95,直接调用 NetCDF-3 C 接口 NF_GET_VARA_DOUBLE/REAL。handle_err_m(libf/misc/handle_err_m.F90)是 netcdf95 内部错误处理模块,将 NetCDF 错误码转为 nf90_strerror 消息后调用 abort_physic,guide 读取路径不经过它。
Mars 运行参与度
Mars 运行对本页是接口兼容和条件边界。guide_read/guide_read2D 的活动调用来自 guide_main,而 guide_main 在串行/并行 leapfrog* 中受 CPP_IOIPSL + planet_type=="earth" 条件包围。Mars/generic 初始化中的 relaxetat0("relax.nc") 是独立路径,不经过 guide_read。guide 读取纯用 NetCDF 接口,不依赖 IOIPSL 历史/重启框架,但调用点本身在 当前源码中受 IOIPSL 宏保护。
依赖表
| 模块/文件 | 用途 |
|---|---|
netcdf (Fortran) |
nf90_nowrite, nf90_open, nf90_inq_varid, nf90_close |
netcdf.inc (C 接口) |
NF_GET_VARA_DOUBLE/REAL, NF_INQ_DIMID/LEN, NF_NOERR |
netcdf95 |
仅 guide_out 使用 nf95_def_var, nf95_put_var |
invert_lat.F90 |
南北方向翻转 |
getparam |
ini_getparam/getpar/fin_getparam 参数读取 |
dimensions.h / paramet.h |
iip1, jjp1, jjm, ip1jmp1, ip1jm, llm |
control_mod |
day_step(频率编码) |
parallel_lmdz(仅并行版) |
ij_begin/end, jj_begin/end(后处理切片用,I/O 不用) |