动力输出状态持有者

输入范围

LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3d\temps_mod.F90
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3dpar\temps_mod.F90
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3d_common\com_io_dyn_mod.F90
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3d_common\inithist.F
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3d_common\writehist.F
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3d_common\initdynav.F90
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3d_common\writedynav.F90
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3d_common\dynetat0.F90
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3d_common\dynredem.F90
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3dpar\dynredem_p.F90

Mars 运行参与度:必经/条件经过temps_mod 是 GCM 时间推进和 restart 的共享状态层,Mars 3D 和 Mars nogcm 路径都会使用;com_io_dyn_mod 只在 COMMON 动力 history/dynav 输出开启且 CPP_IOIPSL 编译进入时条件经过。

职责边界

本页只解释状态持有者如何连接 I/O 注册和时间步写出:

字段注册清单、ok_dyn_* 门控和 Mars physics 输出边界见 history/dynav 字段注册和写出门控

temps_mod 状态

串行 dyn3d/temps_mod.F90 和并行 dyn3dpar/temps_mod.F90 定义同名模块和同一批核心变量。并行版额外声明 OpenMP THREADPRIVATE,并在注释中要求打开 OpenMP parallel section 时把新增变量加入 COPYIN

变量 类型 写入/维护方 被 history/dynav 使用方式
itau_dyn INTEGER gcm/nogcm 新运行置 0;dynetat0 从 restart tab_cntrl(31) 恢复;dynredem* 用它写出累计动力步。 inithist/initdynav 取作 tau0writehist/writedynavitau_w=itau_dyn+time
itaufin INTEGER leapfrog/leapfrog_p/leapfrog_nogcmnday/day_step/fractday/ndynstep 推出。 不直接传给 history API;输出门用局部 itauitaufin 判断最终步。
itau_phy INTEGER 主流程和 physics 调度状态。 history/dynav 串行例程不直接使用。
day_ini, day_end INTEGER gcm/nogcmdynetat0、Mars utility 和 leapfrog* 维护运行起止日。 参与 leapfrog* 日期计算和 restart,间接决定输出时间上下文。
annee_ref, day_ref INTEGER 新运行从 anneeref/dayref 复制;restart 从 controle 恢复。 传入 inithist/initdynavday0/anne0,并由 ymds2ju 生成 history 起始 Julian day。
jD_ref, jH_ref REAL gcm/gcm_pymds2ju 派生,leapfrog* 用它计算当前 Julian day/hour。 history 例程不直接使用;用于 GCM 日期和 restart 输出一致性。
start_time, hour_ini REAL conf_gcm/restart/Mars utility 设置;leapfrog* 检查二者不能同时非零。 不进入 histwrite,但影响当前日期和 restart 时间解释。
dt REAL leapfrog* 在 Matsuno 和 leapfrog 阶段切换为 dtvr2*dtvr history 例程使用调用方传入的 time_step/tstep,不直接读取 dt
calend CHARACTER(len=10) conf_gcm 读取。 IOIPSL/XIOS 日期配置链可使用;history 四个串行例程不直接读取。

com_io_dyn_mod 状态

com_io_dyn_mod.F90 没有分配数组、没有 SAVE 声明,也没有 OpenMP 指令;模块变量天然保持在进程全局模块状态中。它把文件名和 file id 分成 instant 与 averaged 两组。

状态 常量/id 写入者 读取者 生命周期
instant 文件名 dynhist_file, dynhistv_file, dynhistu_file 编译期参数常量 inithist 始终可读,默认 dyn_hist.nc/dyn_histv.nc/dyn_histu.nc
instant file id histid, histvid, histuid inithist 的三次 histbeg 返回值 writehisthistwrite/histsync 只有 ok_dyn_ins 初始化成功后有效。
averaged 文件名 dynhistave_file, dynhistvave_file, dynhistuave_file 编译期参数常量 initdynav 始终可读,默认 dyn_hist_ave.nc/dyn_histv_ave.nc/dyn_histu_ave.nc
averaged file id histaveid, histvaveid, histuaveid initdynav 的三次 histbeg 返回值 writedynavhistwrite/histsync 只有 ok_dyn_ave 初始化成功后有效。

源码搜索只发现 com_io_dyn_modinithist.Fwritehist.Finitdynav.F90writedynav.F90 使用。并行 _p history 实现通过实参传递 file id,不直接使用这个模块;当前 dyn3dpar/gcm.F 的 root 分支仍调用串行 inithist/initdynav 初始化这些模块 id。

初始化到写出的状态链

gcm / gcm_p / Mars nogcm
  -> 设置 temps_mod: annee_ref, day_ref, day_ini, start_time, itau_dyn
  -> 若 ok_dyn_ins:
       inithist(day_ref, annee_ref, time_step, t_ops, t_wrt)
         tau0 = temps_mod:itau_dyn
         histbeg(..., tau0, zjulian, tstep, ..., com_io_dyn_mod:histuid/histvid/histid)
  -> 若 ok_dyn_ave:
       initdynav(day_ref, annee_ref, time_step, t_ops, t_wrt)
         tau0 = temps_mod:itau_dyn
         histbeg(..., tau0, zjulian, tstep, ..., histuaveid/histvaveid/histaveid)

leapfrog / leapfrog_p / Mars leapfrog_nogcm
  -> 局部 itau 按时间循环递增
  -> 若 ok_dyn_ins 且 MOD(itau,iecri)==0:
       writehist(time=itau, ...)
         itau_w = temps_mod:itau_dyn + time
         histwrite(com_io_dyn_mod:hist*id, field, itau_w, ...)
  -> 若 ok_dyn_ave 且 (MOD(itau,iperiod)==0 或 itau==itaufin):
       writedynav(time=itau, ...)
         itau_w = temps_mod:itau_dyn + time
         histwrite(com_io_dyn_mod:hist*aveid, field, itau_w, ...)

itau_dyn 表示 restart 基准中的累计动力步,time 实参是当前运行段内的局部 itau。因此续跑时 history/dynav 写出的步号不是从 0 重新开始,而是以 itau_dyn + itau 延续。

Restart 对时间状态的影响

dynetat0.F90 读取 start.nccontroleTime

dynredem.F90dynredem_p.F90 写 restart 时把 itau_dyn + itaufin 写入 tab_cntrl(31),把当前写出时间写入 tab_cntrl(32)。这和 history 写出中的 itau_dyn + time 是同一类累计步号语义:restart 记录运行段结束时的累计步,history 记录运行段中每次写出的累计步。

并行和 OpenMP 边界

并行 dyn3dpar/temps_mod.F90dt/jD_ref/jH_ref/start_time/hour_ini/day_ini/day_end/annee_ref/day_ref/itau_dyn/itau_phy/itaufin/calend 都声明为 THREADPRIVATEdyn3dpar/gcm.F 中保留注释说明打开 OpenMP parallel section 时应 COPYIN 这些变量。当前 history/dynav 初始化在 gcm.F 的 root 分支调用串行 inithist/initdynav,写出则在 leapfrog_p 的 root/gather 输出段调用串行 writehist/writedynav

复现并行 history 时间时要区分两层状态:

排查顺序

  1. 检查是否从 restart 读取:若 read_start 为真,先看 dynetat0 是否正确恢复 itau_dyn/day_ini/hour_ini/start_time
  2. 检查是否开启 ok_dyn_ins/ok_dyn_ave 且编译包含 CPP_IOIPSL;否则 com_io_dyn_mod 的 id 不会被有效设置。
  3. 检查初始化是否先于写出发生:histid/hist*aveid 只有 inithist/initdynav 后才有效。
  4. 检查写出时间是否符合预期:histwrite 使用 itau_dyn + itau,不是单独的局部 itau
  5. 并行运行若时间状态异常,优先确认 temps_mod threadprivate copyin,而不是修改 com_io_dyn_mod

待确认

相关页面