leapfrog_p 分布和 halo 调度

源码范围:

LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3dpar\leapfrog_p.F
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3dpar\parallel_lmdz.F90
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3dpar\mod_hallo.F90
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\dyn3dpar\bands.F90

Mars 运行参与度:条件经过。Mars 并行 GCM 经过 dyn3dpar/leapfrog_p.F 的分布切换和 halo/swap;串行 Mars GCM 不经过本页路径。

职责边界

本页解释 leapfrog_p 如何在 caldyn、physics、dissip 等阶段之间切换纬向 band,并用 mod_hallo request 补齐 halo 或重新分布字段。时间步状态机见 leapfrog_p 时间步调度,入口数组和工作区见 leapfrog_p 状态约定

三个动作不能混用:

动作 例程 语义
切当前分布 SetDistrib(jj_Nb_*) 只重算当前 rank 的 jj_begin/jj_end/jj_nbij_begin/ij_end
当前分布 halo Register_Hallo 在当前分布上向上下邻居收发边界 band。
分布切换交换 Register_SwapField / Register_SwapFieldHallo 在旧分布和目标分布之间搬运重叠字段;SwapFieldHallo 还按 Up/Down 扩展目标 halo。

SendRequest 负责按 request 打包并 post MPI send/recv,WaitRequest 等待所有 request 并把接收缓冲解包回字段。WaitRequest 结束后会清空 request 并把 tag 重置为 1。

SetDistrib 只改索引

parallel_lmdz:SetDistrib 在 223-251 行接收全 rank 的 jj_Nb_New(0:MPI_Size-1)

  1. 写入 jj_Nb_Para
  2. 从 rank 0 开始累计 jj_begin_para/jj_end_para
  3. 取当前 mpi_rankjj_begin/jj_end/jj_nb
  4. 派生一维数组范围 ij_begin=(jj_begin-1)*iip1+1ij_end=jj_end*iip1

它不复制任何数组数据。因此 leapfrog_p 每次切分布前后都必须配套 Register_SwapField* -> SendRequest -> WaitRequest,否则当前 rank 的 ij_begin/ij_end 会指向新范围,但字段内容仍只保证旧范围有效。

request 类型在 leapfrog_p 中的角色

leapfrog_p 声明三个 request:

request 主要用途
TestRequest caldyn 初始或动态调整后的字段重分布,以及常规动力 halo。
Request_physic caldyn/physics 分布切换、physics tendency halo、physics 后回到 caldyn。
Request_Dissip dissip 前后分布切换、sponge/dissip 守恒修正相关 halo。

physics request 在两处调用 SetTag(Request_physic,800),用于把 physics 阶段的 MPI tag 与默认 tag 分开。实际 MPI tag 还会加 1000*omp_rank,以区分 OpenMP 线程。

初始化和自适应调整

490-500 行第一次进入 caldyn 时:

  1. master 调 SetDistrib(jj_Nb_Caldyn)
  2. barrier 后 firstCaldyn=.FALSE.
  3. master 初始化 timing。

509-605 行是可选 Adjust 路径。只有满足 iapptrac==iapp_tracvl、当前为 forwardleapfitau/iphysiq>2AdjustCount>30 时才进入。流程是:

  1. allgather_timer_average 汇总计时。
  2. AdjustBands_caldyn 可能移动 caldyn band,rank 0 可 WriteBands
  3. ucov/vcov/teta/masse/ps/pk/pks/phis/phi/q/temp/tsurpk 等当前状态注册 Register_SwapFieldHallo(..., jj_Nb_caldyn, 0, 0, TestRequest)
  4. SetDistrib(jj_nb_caldyn)
  5. SendRequest(TestRequest)WaitRequest(TestRequest) 完成重分布。
  6. 再调用 AdjustBands_dissipAdjustBands_physic,更新后续阶段的目标分布。

这里 Up=0, Down=0,所以虽然使用 SwapFieldHallo,实际不扩展 halo;它主要是在 caldyn band 自适应改变后搬运全状态到新 caldyn 分布。

动力计算前 halo

631-660 行在动力 tendency 计算前做当前 caldyn 分布的 halo:

这一步不是分布切换;它只补齐当前 caldyn 分布的上下邻居边界,供后续 geopot_p/caldyn_p/caladvtrac 等使用。

physics 前切到物理分布

apphys 为真时,948-1002 行把动力字段从 caldyn 分布换到 physics 分布:

  1. Request_physic tag 为 800。
  2. Register_SwapFieldHallo(..., jj_Nb_physic, Up, Down, Request_physic) 注册字段。
  3. 主要 prognostic state、pressure/Exner、位势、垂直速度、每个 tracer 和 flxw 都参与交换。
  4. 多数字段使用 Up=2, Down=2masse 使用 Up=1, Down=2
  5. SendRequest/WaitRequest 完成后,master 调 SetDistrib(jj_nb_Physic)

这里必须先注册交换再切当前分布,因为 Register_SwapFieldHallo 需要同时知道旧的 jj_begin/jj_end 和目标 jj_Nb_physicSetDistrib 放在通信完成后,避免当前 rank 在字段还没搬完时就按新范围解释数组。

physics tendency halo 和回填

calfis_p 之后,1040-1077 行先切到 jj_nb_Physic_bis,再给 physics tendency 做 halo:

这段的重点是 tendency 的边界合并,而不是完整状态重分布。jj_nb_Physic_bis 提供一个辅助分布来处理 physics tendency 的上下拼接。

physics 后回到 caldyn

addfi_p、pressure/mass/Exner 刷新和可选 top-bound 之后,1135-1189 行把状态换回 caldyn:

  1. 再次设置 Request_physic tag 为 800。
  2. ucov/vcov/teta/masse/ps/p/pk/phis/phi/w/q 注册 Register_SwapField(..., jj_Nb_caldyn, Request_physic)
  3. Register_SwapField 不带 halo 扩展,只把目标 caldyn 分布需要的重叠字段搬回。
  4. SendRequest/WaitRequest 后 master 调 SetDistrib(jj_Nb_caldyn)

因此 physics 阶段前是“切到 physics 并扩 halo”,physics 后是“回 caldyn,不额外扩 halo”。后续若动力或输出还需要边界,会再单独走 Register_Hallo

friction 和 dissip 前后

iflag_phys==2 分支中,1249-1255 行在 friction_p 前对 ucov/vcov 做 halo:

apdiss 分支从 1291 行开始,通信分三段:

源码范围 行为
sponge 前 1303-1319 callsponge,对 tetaps 注册 halo。源码注释说明原则上只需 ps,但 mixed MPI/OpenMP 下只注册 2D 场会让 WaitRequest 崩溃,因此额外注册 3D teta
切到 dissip 1323-1347 ucov/vcovRegister_SwapFieldHallo(..., jj_Nb_dissip, 1,1)teta/p/pkRegister_SwapField;通信完成后 SetDistrib(jj_Nb_dissip)
dissip 后回 caldyn 1518-1542 ucov/vcov/teta/p/pkRegister_SwapField(..., jj_Nb_caldyn),通信完成后 SetDistrib(jj_Nb_caldyn)

如果 dissip_conservative 为真,1385-1399 行在重新计算动能前还会对 ucov/vcov 做一次普通 halo。

复现检查表

  1. 记录当前阶段的 jj_Nb_Caldyn/jj_Nb_physic/jj_Nb_physic_bis/jj_Nb_dissip,不要只看 init_parallel 后的初始分布。
  2. 看到 SetDistrib 前,检查是否已经注册并完成了对应 Register_SwapField* request。
  3. 区分 Register_HalloRegister_SwapField*:前者补边界,后者搬运到新分布。
  4. physics 前交换使用 SwapFieldHallo 并带 Up/Down,physics 后回 caldyn 使用 SwapField
  5. 若 mixed MPI/OpenMP 在 WaitRequest 附近崩溃,优先检查 omp_chunk、request 是否包含 3D 字段、tag 是否与 OpenMP rank 匹配。
  6. 对输出/restart 字段缺失,先查 dyn3dpar/leapfrog_p 的 gather/root-only 输出;本页只覆盖计算阶段分布和 halo。

待确认

相关页面