mod_phys_lmdz_transfert_para.F90
源码基线:LMDZ.COMMON-6.3\LMDZ.COMMON。 Mars 运行参与度:条件经过。Mars physics 和 COMMON 物理公共层通过本模块的 bcast、gather、scatter 等泛型完成物理列数据在 MPI ranks 和 OpenMP threads 之间的组合传输。
源码范围
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\phy_common\mod_phys_lmdz_transfert_para.F90
该文件 1349 行,只定义 MODULE mod_phys_lmdz_transfert_para。模块本身不声明 PRIVATE 或 PUBLIC,因此其中 6 个 generic interface 和 80 个具体 SUBROUTINE 按 Fortran 默认规则公开。
模块职责
mod_phys_lmdz_transfert_para 是物理侧 transfer 的组合层。它不直接调用 MPI API,也不直接使用 OpenMP runtime API;真正的通信和线程内复制在底层两个模块中完成:
| 依赖 | 源码行 | 用途 |
|---|---|---|
mod_phys_lmdz_mpi_transfert |
6 | 提供 bcast_mpi、scatter_mpi、gather_mpi、scatter2D_mpi、gather2D_mpi、reduce_sum_mpi。 |
mod_phys_lmdz_omp_transfert |
7 | 提供 bcast_omp、scatter_omp、gather_omp、reduce_sum_omp。 |
mod_phys_lmdz_mpi_data:klon_mpi |
各 scatter/gather 过程内部 | 决定 rank 局部物理列数,用作 Var_tmp 第一维。 |
组合层负责三件事:
- 通过泛型接口隐藏标量/数组 rank 和类型差异。
- 对 scatter/gather 类操作建立 rank 局部临时数组
Var_tmp。 - 固定 MPI 与 OMP 两层操作的执行顺序,保证全局、rank 局部和 thread 局部数组形状一致。
泛型接口清单
| 泛型 | 行号 | specific procedures | 支持类型和维度 | 方向 |
|---|---|---|---|---|
bcast |
11-16 | 22 | character scalar;integer/real/logical scalar 到 6D |
root/global -> all ranks/threads |
scatter |
18-22 | 12 | integer/real/logical scalar 到 4D |
global 1D physical columns -> thread local columns |
gather |
25-29 | 12 | integer/real/logical scalar 到 4D |
thread local columns -> global 1D physical columns |
scatter2D |
31-35 | 12 | integer/real/logical scalar 到 4D output;input 多一个 lon-lat 维 |
global 2D lon-lat field -> thread local columns |
gather2D |
37-41 | 12 | integer/real/logical scalar 到 4D input;output 多一个 lon-lat 维 |
thread local columns -> global 2D lon-lat field |
reduce_sum |
43-46 | 10 | integer/real scalar 到 4D |
thread/rank partial values -> global sum |
计数依据:bcast 为 bcast_c 加上 integer、real、logical 各 7 个过程,共 22 个;另外四个 scatter/gather 泛型各 12 个;reduce_sum 为 integer 和 real 各 5 个。全文件共 80 个 SUBROUTINE。
过程分组
| 行段 | 过程族 | 核心模式 |
|---|---|---|
| 57-320 | bcast_c, bcast_i*, bcast_r*, bcast_l* |
master thread 先调用 bcast_mpi(Var),然后所有线程调用 bcast_omp(Var);无临时数组。 |
| 327-532 | scatter_i*, scatter_r*, scatter_l* |
master thread 调 scatter_mpi(VarIn, Var_tmp),所有线程调 scatter_omp(Var_tmp, VarOut)。 |
| 542-747 | gather_i*, gather_r*, gather_l* |
所有线程先调 gather_omp(VarIn, Var_tmp),master thread 再调 gather_mpi(Var_tmp, VarOut)。 |
| 757-963 | scatter2D_i*, scatter2D_r*, scatter2D_l* |
master thread 调 scatter2D_mpi(VarIn, Var_tmp),所有线程调 scatter_omp(Var_tmp, VarOut)。 |
| 972-1177 | gather2D_i*, gather2D_r*, gather2D_l* |
所有线程调 gather_omp(VarIn, Var_tmp),master thread 再调 gather2D_mpi(Var_tmp, VarOut)。 |
| 1186-1345 | reduce_sum_i*, reduce_sum_r* |
所有线程先调 reduce_sum_omp(VarIn, Var_tmp),master thread 再调 reduce_sum_mpi(Var_tmp, VarOut)。 |
执行顺序
bcast
!$OMP MASTER
CALL bcast_mpi(Var)
!$OMP END MASTER
CALL bcast_omp(Var)bcast 是唯一支持 character 的泛型,也是唯一扩展到 5D/6D 的泛型。它没有 Var_tmp,MPI 和 OMP 层都直接作用于同一个 Var。
scatter 和 scatter2D
TYPE, DIMENSION(klon_mpi, ...) :: Var_tmp
!$OMP MASTER
CALL scatter_mpi(VarIn, Var_tmp) ! 或 scatter2D_mpi
!$OMP END MASTER
CALL scatter_omp(Var_tmp, VarOut)scatter 方向是 global -> rank -> thread,因此 MPI 层先执行。scatter2D 只改变 MPI 步骤:它把全局 lon-lat 二维形状散到 rank 局部 1D physical-column 形状,再交给同一个 scatter_omp。
gather 和 gather2D
TYPE, DIMENSION(klon_mpi, ...) :: Var_tmp
CALL gather_omp(VarIn, Var_tmp)
!$OMP MASTER
CALL gather_mpi(Var_tmp, VarOut) ! 或 gather2D_mpi
!$OMP END MASTERgather 方向是 thread -> rank -> global,因此 OMP 层先执行。gather2D 的最后一步调用 gather2D_mpi,把 rank 局部 1D physical-column 形状还原到全局 lon-lat 二维输出。
reduce_sum
TYPE :: Var_tmp
CALL reduce_sum_omp(VarIn, Var_tmp)
!$OMP MASTER
CALL reduce_sum_mpi(Var_tmp, VarOut)
!$OMP END MASTERreduce_sum 先在线程内求和,再在 MPI ranks 间求和。它的 Var_tmp 与 VarIn 同形,不带 klon_mpi 第一维,因为 reduce 不表示物理列分布变换。
临时数组形状
所有 Var_tmp 都是过程内自动数组,不是 ALLOCATABLE、SAVE 或模块状态。数组在调用进入时按实参维度和 klon_mpi 建立,调用返回时释放。
| 操作 | Var_tmp 第一维 |
额外维度来源 | 例子 |
|---|---|---|---|
bcast |
无 | 无 | bcast_r6 直接传 Var(:,:,:,:,:,:)。 |
scatter |
klon_mpi |
SIZE(VarOut, 2:...) |
scatter_r3 建立 REAL(klon_mpi, SIZE(VarOut,2), SIZE(VarOut,3), SIZE(VarOut,4))。 |
gather |
klon_mpi |
SIZE(VarIn, 2:...) |
gather_l2 建立 LOGICAL(klon_mpi, SIZE(VarIn,2), SIZE(VarIn,3))。 |
scatter2D |
klon_mpi |
SIZE(VarOut, 2:...) |
scatter2D_i1 从 VarIn(:,:,:) 到 VarOut(:,:)。 |
gather2D |
klon_mpi |
SIZE(VarIn, 2:...) |
gather2D_r3 从 VarIn(:,:,:,:) 到 VarOut(:,:,:,:,:)。 |
reduce_sum |
无 klon_mpi |
SIZE(VarIn, ...) |
reduce_sum_i4 建立与 4D VarIn 同形的 integer Var_tmp。 |
复现时要先确认物理并行初始化已经给出正确的 klon_mpi。若 klon_mpi 与实参的物理列维不一致,错误通常会在底层 transfer 或数组越界检查中暴露,而不是在本 wrapper 层显式检查。
调用方和运行链
COMMON 内部直接使用本模块的路径包括:
| 调用方 | 用到的泛型 | 用途 |
|---|---|---|
phy_common/mod_phys_lmdz_para.F90 |
scatter2D, bcast, reduce_sum |
test_phys_lmdz_para 自检物理侧分布和 transfer。 |
phy_common/ioipsl_getin_p_mod.F90 |
bcast |
master 读配置后广播到其它 ranks/threads。 |
phy_common/xios_writefield.F90 |
bcast |
临时 XIOS field dump 建 regular 输出网格时同步 ni_glo/nj_glo。 |
misc/wxios.F90 |
gather, bcast |
XIOS domain 参数构造时聚合/同步全局经纬度数组。 |
Mars 源码侧也直接使用本模块,常见模式是:
conf_phys.F、tracer_mod.F90、read_dust_scenario_mod.F90、suaer.F90、aeronomy photolysis/parameter readers 等使用bcast同步 root 读取的数据。iostart.F90使用gather、scatter和bcast处理物理 restart/start 读写的全局/局部数组。surfini_mod.F90使用gather和scatter在全局 surface 数据和局部物理列之间转换。planetwide_mod.F90使用gather加bcast实现行星范围 max/sum 类结果同步。
需要区分:dynphy_lonlat/calfis_p.F 的动力格点到物理列搬运有手写 MPI/OMP 循环和 wind exchange,不是本模块泛型的直接调用方。
副作用和状态
本模块不保存模块级变量,也不分配持久内存。它的副作用来自底层调用:
*_mpi改变 MPI ranks 间的数据可见性,并依赖 MPI communicator 和物理列分布状态。*_omp在线程之间复制或聚合数据,并依赖mod_phys_lmdz_omp_data中的线程切片状态。- scatter/gather 类过程会在栈上建立可能很大的
Var_tmp自动数组;4D 实数场的临时内存约为klon_mpi * d2 * d3 * d4 * sizeof(real)。
复现要点
- 先完成
init_physics_distribution -> init_phys_lmdz_para -> init_phys_lmdz_mpi_data/Init_phys_lmdz_omp_data,使klon_mpi、klon_omp和线程切片有效。 - 判断方向:global 到 local 用
scatter或scatter2D,local 到 global 用gather或gather2D,全体同步用bcast,求和用reduce_sum。 - 判断全局输出是否是 lon-lat 2D 空间:若是,用
scatter2D/gather2D;若是 physical-column 1D 全局向量,用scatter/gather。 - 检查 rank/类型支持:
bcast到 6D,scatter/gather 到 4D,reduce_sum无 logical 和 character。 - 不要从 wrapper 层寻找通信 buffer、barrier 或 MPI datatype 细节;这些在 MPI/OMP 底层模块页展开。
待确认
- 本页按 COMMON 和当前本地 MARS 调用点确认;外部 physics 包或本地私有补丁是否新增
scatter2D/gather2D/reduce_sum调用,需要在对应源码树中另行rg。 - 自动数组的实际栈空间限制取决于编译器和运行环境,本页只给出源码形状,不判断特定平台是否需要调栈大小。