calfis_p 日期参数、行星分支与接口兼容

输入范围

dynphy_lonlat\calfis_p.F: L1-1520(并行动理调用接口)
dyn3dpar\leapfrog_p.F: L845-930, L1017-1021(日期计算和 calfis_p 调用)
dyn3d_common\control_mod.F90: L34(planet_type 声明)

Mars 运行参与度:条件经过。Mars 并行 GCM 在 apphys 为真时,leapfrog_p 计算 Mars 专属日期后传入 calfis_pcalfis_p 内部按 planet_typensplit_phys 处理日期分拆。

例程定位

本页聚焦 calfis_p 的日期参数语义、lafin 标志的传递链、planet_type 分支结构,以及从旧式行星分散 physiq 统一到 call_physiq 的接口兼容风险。场映射和并行 transfer 已由 calfis-p-grid-mappingcalfis-p-physiq-contractcalfis-p-parallel-transfer 覆盖。

日期参数

入口签名

calfis_p 接收三个时间相关参数:

SUBROUTINE calfis_p(lafin, jD_cur, jH_cur, ...)
  LOGICAL, INTENT(IN) :: lafin       ! .true. for the very last call to physics
  REAL,    INTENT(IN) :: jD_cur      ! Julian day
  REAL,    INTENT(IN) :: jH_cur      ! Julian hour (fraction of day)

jD_curjH_curleapfrog_p 计算后传入。calfis_p 本身不修改这两个值,只在 nsplit_phys 循环内派生 jH_cur_split

leapfrog_p 中的日期计算

leapfrog_p 在 physics 段(约 L905-927)按行星类型计算日期:

jD_cur(儒略日)

! 默认(Earth/Titan/Venus)
jD_cur = jD_ref + day_ini - day_ref + (itau+1)/day_step

! Mars 和 generic 覆盖:使用 itau 而非 itau+1
IF ((planet_type=="generic") .or. (planet_type=="mars")) THEN
   jD_cur = int(day_ini + itau/day_step)     ! 整数截断,即 pday
ENDIF

Mars 的 jD_cur 使用 int() 截断为整数,代表 physics day(pday)。这与默认路径的 (itau+1)/day_step 有两个差异:使用 itau 而非 itau+1,以及整数截断而非精确分数。

jH_cur(儒略小时,日分数)

IF (planet_type=="mars") THEN
   jH_cur = jH_ref + hour_ini + mod(itau, day_step) / float(day_step)
ELSE IF (planet_type=="generic") THEN
   jH_cur = jH_ref + start_time + mod(itau, day_step) / float(day_step)
ELSE
   jH_cur = jH_ref + start_time + mod(itau+1, day_step) / float(day_step)
ENDIF

! 溢出修正
if (jH_cur > 1.0) then
   jD_cur = jD_cur + 1
   jH_cur = jH_cur - 1
endif

三行公式的关键差异:

行星 时间偏移源 itau 偏移 语义
Mars hour_ini itau Mars 物理使用当前步,不前瞻
generic start_time itau 同 Mars,但偏移源不同
Earth/Titan/Venus start_time itau+1 前瞻一步,physics 在 "下一时刻" 被调用

Mars 使用 hour_ini 而非 start_time 作为初始小时偏移,这与其他行星不同。hour_ini 来自 Mars restart 文件的初始时间参数,start_time 是通用初始时间。

calfis_p 中的 split 日期分拆

calfis_pnsplit_phys 循环内将 jH_cur 分拆为每个 split 的时间:

do isplit = 1, nsplit_phys
   jH_cur_split = jH_cur + (isplit-1) * dtvr / (daysec * nsplit_phys)
   debut_split  = debut .and. isplit == 1
   lafin_split  = lafin .and. isplit == nsplit_phys
   ...
   CALL call_physiq(klon, llm, nqtot, tname,
  &                 debut_split, lafin_split,
  &                 jD_cur, jH_cur_split, zdt_split, ...)
enddo

jH_cur_split 在每个 split 中递增 dtvr/(daysec*nsplit_phys) 日分数。jD_cur 不分拆,直接传入每个 split。如果 nsplit_phys==1(Mars 常见),jH_cur_split == jH_cur,无分拆效果。

注意:jH_cur_split 的递增不会检查溢出(jH_cur_split > 1.0)。在极端 nsplit_phys 下,split 时间可能跨日但 jD_cur 不随之进位。Mars 配置 nsplit_phys 通常为 1,此问题不会出现。

lafin 标志

传递链

leapfrog_p (L851-855):
  purmats:     lafin = (itau==itaufin .AND. .NOT.forward)
  non-purmats: lafin = (itau+1 == itaufin)
       ↓
  calfis_p(lafin, ...)
       ↓
  nsplit_phys 循环:
  lafin_split = lafin .AND. isplit == nsplit_phys
       ↓
  call_physiq(..., lafin_split, ...)

lafin 的物理含义是"本 physics 调用是否为模拟的最后一次"。只有最后一个 split 才收到 lafin_split=.TRUE.,确保物理参数化在最后 split 执行收尾操作(如写诊断、刷新累积量)。

debut 遵循对称逻辑:debut_split = debut .AND. isplit == 1debut 是 THREADPRIVATE 标志,首次调用时为 .TRUE.firstcal 变为 .FALSE. 后后续调用 debut.FALSE.

物理侧使用

call_physiqdebut_split/lafin_split 透传给行星物理参数化。lafin_split=.TRUE. 时物理侧可能执行:

Mars 物理侧对 lafin_split 的具体使用需在 phymars/ 目录确认。

planet_type 分支结构

活跃分支

calfis_p 中唯一活跃的 planet_type 分支是首次调用时的 Titan 全局均值计算(L317-376):

if (planet_type.eq."titan") then
   call AllGather_Field(pp, iip1*jjp1, llmp1)
   call AllGather_Field(pteta, iip1*jjp1, llm)
   ! ... 计算 plevmoy, playmoy, tetamoy, tmoy, phimoy 等全局均值 ...
   allocate(klat(klon))
   do ig0 = 1, klon
      j = index_j(ig0)
      klat(ig0) = j
   enddo
endif  ! planet_type=titan

这段代码在 OMP MASTER 段执行,收集全局场并计算纬向/全球均值剖面。源码注释说明这些调用在 OpenMP 下可能有问题,但 Titan physics 只用 MPI 不用 OMP,所以不影响。

Mars 不进入此分支。klat 数组只在此分支内分配,Mars 路径下 klat 未定义。

已注释的行星分散 physiq 分支

calfis_p 保留了一整段注释代码(L957-1066),展示了统一 call_physiq 之前的旧式行星分散调用:

行星 注释位置 额外参数 缺少的参数
Earth L957-980 无 nqtot/tname/zrfi/zpk/zphis/presnivs 签名最简
generic L982-1006 nqtot, tname, tracerdyn zpk, zphis, presnivs, zrfi
Mars L1008-1031 nqtot, tracerdyn zpk, zphis, presnivs, zrfi
Titan/Venus L1033-1058 nqtot, zpk, zphis, presnivs zrfi, tracerdyn
unknown L1060-1066 打印错误并 stop

当前执行路径是统一 call_physiq(klon, llm, nqtot, tname, ...),所有行星共用同一签名。旧代码保留是为了追溯参数差异。

签名差异分析

从注释代码看,旧式 Mars physiq 缺少以下参数:

旧式 Mars 多出的参数:

flag_moyzon 与 Mars 的关系

flag_moyzonmoyzon_ch .or. moyzon_mu 控制,来自 logic_mod。当为真时,calfis_p 在每个 scatter 后调用 AllGather_Field + moyzon 计算纬向均值。

源码注释和上下文表明 flag_moyzon 当前用于 Titan/Venus 的 2D 微物理和化学计算。Mars 主线不启用此标志,因此以下代码路径在 Mars 下不执行:

停止条件

calfis_p 有三个 STOP/stop 路径:

  1. ngridmx 检查(L275-281):首次调用时检查 ngridmx == 2+(jjm-1)*iim。不匹配时 STOP。Mars 常规配置应通过。

  2. CPP_PHYS 缺失(L1511-1515):#else 分支打印 "calfis_p: for now can only work with parallel physics"stop。Mars 并行构建必须定义 CPP_PHYS

  3. 未知 planet_type(L1060-1064):旧代码中的 stop,当前已注释,不在执行路径上。

接口兼容风险

统一 call_physiq 的约束

call_physiq 统一签名要求所有行星物理参数化接受相同参数列表。这意味着:

Mars 特有时间风险

OpenMP 与 Titan 分支的冲突

源码注释(L318-319)明确说明 AllGather_Field 在 OpenMP 下有问题。当前 Titan 只用 MPI 不受影响,但如果 Mars 未来需要在 OpenMP 下启用 flag_moyzon,可能触发相同的竞态问题。

复现要点

相关页面

待确认