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_p;calfis_p 内部按 planet_type 和 nsplit_phys 处理日期分拆。
例程定位
本页聚焦 calfis_p 的日期参数语义、lafin 标志的传递链、planet_type 分支结构,以及从旧式行星分散 physiq 统一到 call_physiq 的接口兼容风险。场映射和并行 transfer 已由 calfis-p-grid-mapping、calfis-p-physiq-contract 和 calfis-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_cur 和 jH_cur 由 leapfrog_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
ENDIFMars 的 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_p 在 nsplit_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, ...)
enddojH_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 == 1。debut 是 THREADPRIVATE 标志,首次调用时为 .TRUE.,firstcal 变为 .FALSE. 后后续调用 debut 为 .FALSE.。
物理侧使用
call_physiq 将 debut_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 缺少以下参数:
zpk(Exner):Mars 物理原来不需要 Exner,但统一接口需要zphis(地表位势):统一接口传入了相对位势计算所需presnivs(参考层压力):统一接口需要zrfi(相对涡度):Mars 物理原来不使用涡度
旧式 Mars 多出的参数:
tracerdyn:用途标注为 "somewhat obsolete",当前接口已移除
flag_moyzon 与 Mars 的关系
flag_moyzon 由 moyzon_ch .or. moyzon_mu 控制,来自 logic_mod。当为真时,calfis_p 在每个 scatter 后调用 AllGather_Field + moyzon 计算纬向均值。
源码注释和上下文表明 flag_moyzon 当前用于 Titan/Venus 的 2D 微物理和化学计算。Mars 主线不启用此标志,因此以下代码路径在 Mars 下不执行:
moyzon_init(klon, llm, nqtot)和moyzon_init_omp- 每次 scatter 后的
AllGather_Field + moyzon调用(zplevbar/zpkbar/zplaybar/zphibar/ztfibar/zqfibar) - OMP scatter 中的
zplevbar_omp等纬向均值数组拷贝
停止条件
calfis_p 有三个 STOP/stop 路径:
ngridmx 检查(L275-281):首次调用时检查
ngridmx == 2+(jjm-1)*iim。不匹配时STOP。Mars 常规配置应通过。CPP_PHYS 缺失(L1511-1515):
#else分支打印"calfis_p: for now can only work with parallel physics"并stop。Mars 并行构建必须定义CPP_PHYS。未知 planet_type(L1060-1064):旧代码中的
stop,当前已注释,不在执行路径上。
接口兼容风险
统一 call_physiq 的约束
call_physiq 统一签名要求所有行星物理参数化接受相同参数列表。这意味着:
- Mars
physiq必须接受zpk/zphis/presnivs/zrfi,即使旧签名不需要。Mars 物理侧可以忽略这些参数。 - Titan/Venus
physiq必须接受nqtot/tname,即使旧签名没有。当前 Titan/Venus 的callphysiq_mod已经适配。 - 新增参数(如未来需要
zdufi_omp作为输入)会同时影响所有行星。
Mars 特有时间风险
jD_cur使用int()截断。如果 Mars physics 内部依赖jD_cur的小数部分做亚日精度计算,会得到零。jH_cur使用hour_ini而非start_time。如果 Mars 和 generic 的 restart 文件使用不同的初始时间约定,可能导致物理参数化中的时间计算差异。jH_cur使用mod(itau,day_step)而非mod(itau+1,day_step)。Mars physics 接收的时间比 Earth/Titan/Venus "早一步"。这是有意设计(Mars physics 用当前步状态)而非遗漏。
OpenMP 与 Titan 分支的冲突
源码注释(L318-319)明确说明 AllGather_Field 在 OpenMP 下有问题。当前 Titan 只用 MPI 不受影响,但如果 Mars 未来需要在 OpenMP 下启用 flag_moyzon,可能触发相同的竞态问题。
复现要点
jD_cur和jH_cur由leapfrog_p计算,calfis_p不修改。排查日期差异时应先查leapfrog_p的行星分支,再查calfis_p的jH_cur_split分拆。lafin在nsplit_phys > 1时只有最后一个 split 为.TRUE.。如果物理侧的 "最后一次" 操作需要所有 split 都执行,应改用lafin而非lafin_split。planet_type在calfis_p中只有一处活跃检查(Titan 全局均值)。所有行星共用call_physiq,不再有 per-planet 分支。- 旧式注释代码是参数对照的有价值参考,但不应被视为当前执行路径。
- Mars 的
flag_moyzon应为.FALSE.。如果意外启用,会触发大量AllGather_Field调用,可能影响性能和正确性。
相关页面
- calfis_p 模块页
- calfis_p 格点映射
- calfis_p 接口约定
- calfis_p 并行 transfer
- leapfrog-p-physics-coupling
- leapfrog-p-time-scheduler
- leapfrog-physics-coupling
- leapfrog-time-scheduler
- calfis 串行模块页
待确认
- Mars 物理侧(
phymars/)对lafin_split的具体使用路径。 - Mars
hour_ini与 genericstart_time的初始化来源是否一致。 control_mod中planet_type的完整允许值列表(目前源码中出现 earth/mars/generic/titan/venus)。- Mars 是否有
nsplit_phys > 1的配置,以及jH_cur_split溢出在极端情况下的影响。