mod_phys_lmdz_mpi_transfert.F90

源码基线:LMDZ.COMMON-6.3\LMDZ.COMMON。 Mars 运行参与度:条件经过。Mars physics 通过上层 mod_phys_lmdz_transfert_para 泛型进入本模块;MPI 构建且物理侧 MPI 分布启用时执行真实 MPI 通信。

源码范围

LMDZ.COMMON-6.3\LMDZ.COMMON\libf\phy_common\mod_phys_lmdz_mpi_transfert.F90

当前文件有 1953 个物理行,END MODULE mod_phys_lmdz_mpi_transfert 在第 1952 行,末尾还有一个空行。模块只定义接口和过程,不保存模块级状态;所有通信状态来自 mod_phys_lmdz_mpi_data,网格规模和 1D/2D 转换规模来自 mod_grid_phy_lmdz

模块职责

mod_phys_lmdz_mpi_transfert 是物理侧 MPI rank 间 transfer 的底层实现。它提供:

本模块不直接处理 OpenMP 线程内数据分发。完整 MPI+OMP 顺序由 mod_phys_lmdz_transfert_para 组合。

接口总览

泛型接口 行号 specific procedures 类型覆盖 最大数组 rank 底层动作
bcast_mpi 7-12 22 character scalar;integer/real/logical scalar 到 6D 6D MPI_BCAST
scatter_mpi 14-18 12 integer/real/logical scalar 到 4D 4D root 打包 + MPI_SCATTERV
gather_mpi 21-25 12 integer/real/logical scalar 到 4D 4D MPI_GATHERV + root 解包
scatter2D_mpi 27-31 12 integer/real/logical,input 比 output 多一个 lon-lat 维 5D -> 4D grid2dTo1d_glo + scatter_mpi
gather2D_mpi 33-37 12 integer/real/logical,output 比 input 多一个 lon-lat 维 4D -> 5D gather_mpi + grid1dTo2d_glo
reduce_sum_mpi 39-42 10 integer/real scalar 到 4D 4D MPI_REDUCE(..., MPI_SUM, ...)
grid1dTo2d_mpi 44-48 12 integer/real/logical,1D local columns 到局部 2D block 4D -> 5D 本地复制和极点展开
grid2dTo1d_mpi 50-54 12 integer/real/logical,局部 2D block 到 1D local columns 5D -> 4D 本地复制和北极首点提取

全文件共 94 个 specific procedures,另有 18 个 _gen 引擎过程:

类型和维度边界

bcast_mpi

标量 integer/real/logical 先包装为长度 1 的数组,再进入对应 _gen 引擎:

IF (is_mpi_root) var_tmp(1)=var
CALL bcast_mpi_igen(Var_tmp,1)
var=var_tmp(1)

数组版本直接把 VarSIZE(Var) 传给引擎。引擎统一模式如下:

IF (.not.is_using_mpi) RETURN
CALL MPI_BCAST(Var, nb, MPI_*, mpi_master, COMM_LMDZ_PHY, ierr)

real 版本使用 MPI_REAL_LMDZ,而不是硬编码 MPI_REAL;该 datatype 在 mod_phys_lmdz_mpi_data 初始化。

scatter_mpi

scatter_mpi_* 从 root rank 上的全局 1D physical-column 字段 VarIn(klon_glo, dimsize) 分发到各 rank 的 VarOut(klon_mpi, dimsize)

specific procedure 根据输出额外维度计算 dimsize

后缀 dimsize
无后缀 1
*1 SIZE(VarOut,2)
*2 SIZE(VarOut,2)*SIZE(VarOut,3)
*3 SIZE(VarOut,2)*SIZE(VarOut,3)*SIZE(VarOut,4)

引擎逻辑:

  1. is_using_mpi 为 false,直接 VarOut(:,:)=VarIn(:,:) 并返回。
  2. root rank 为每个 rank 计算 counts(rank)=klon_mpi_para_nb(rank)*dimsizedispls(rank)
  3. root 将 VarIn(klon_mpi_para_begin(rank):klon_mpi_para_end(rank), i) 按 rank 顺序打包到一维 VarTmp(dimsize*klon_glo)
  4. 调用 MPI_SCATTERV,每个 rank 接收 klon_mpi*dimsize 个元素。

关键点是 SCATTERV 的块长由每个 rank 的物理列数决定,不是等长分配。

gather_mpi

gather_mpi_* 与 scatter 方向相反:各 rank 提供 VarIn(klon_mpi, dimsize),root 得到 VarOut(klon_glo, dimsize)

specific procedure 根据输入额外维度计算 dimsize

后缀 dimsize
无后缀 1
*1 SIZE(VarIn,2)
*2 SIZE(VarIn,2)*SIZE(VarIn,3)
*3 SIZE(VarIn,2)*SIZE(VarIn,3)*SIZE(VarIn,4)

引擎逻辑:

  1. root 计算 counts/displs
  2. 非 MPI 路径直接 VarOut(:,:)=VarIn(:,:)
  3. 调用 MPI_GATHERV(VarIn, klon_mpi*dimsize, ..., VarTmp, counts, displs, ...)
  4. root 按 klon_mpi_para_begin/endVarTmp 解包回全局列顺序。

scatter2D_mpigather2D_mpi

这两个接口本身不直接调用 MPI 原语,而是组合全局 1D/2D 网格转换和普通 scatter/gather。

scatter2D_mpi

VarIn(global 2D lon-lat, extra dims)
  -> grid2dTo1d_glo
Var_tmp(klon_glo, extra dims)
  -> scatter_mpi
VarOut(klon_mpi, extra dims)

gather2D_mpi

VarIn(klon_mpi, extra dims)
  -> gather_mpi
Var_tmp(klon_glo, extra dims)
  -> grid1dTo2d_glo
VarOut(global 2D lon-lat, extra dims)

这里使用的是 mod_grid_phy_lmdz_glo 转换,处理全局 klon_glo 和全局 lon-lat 网格;不要和本文件后半段的 _mpi 局部转换混淆。

reduce_sum_mpi

reduce_sum_mpi_i/r 标量版本同样先包装为长度 1 的数组。数组版本用 SIZE(VarIn) 作为 nb,把多维数组视为连续内存。

引擎逻辑:

IF (.not.is_using_mpi) THEN
  VarOut(:)=VarIn(:)
  RETURN
ENDIF
CALL MPI_REDUCE(VarIn, VarOut, nb, MPI_*, MPI_SUM, mpi_master, COMM_LMDZ_PHY, ierr)

输出只在 root rank 上有效。若后续所有 ranks 都需要结果,上层调用必须再执行 broadcast;本模块的 reduce 引擎不会自动广播结果。

局部 1D/2D 转换

grid1dTo2d_mpigrid2dTo1d_mpi 是本 rank 内的局部网格转换,不做 MPI 调用,也不检查 is_using_mpi

grid1dTo2d_mpi_*gen

输入:VarIn(klon_mpi, dimsize)。 输出:VarOut(nbp_lon*jj_nb, dimsize)

流程:

  1. 先把北极行和南极行清零;logical 版本置 .FALSE.
  2. 默认 offset=ii_begin;若本 rank 拥有北极,改为 offset=nbp_lon,跳过 2D 北极复制行。
  3. 主体循环将 VarIn(ij,i) 写到 VarOut(ij+offset-1,i)
  4. is_north_pole_dyn,把 VarIn(1,i) 复制到北极所有经度。
  5. is_south_pole_dyn,把 VarIn(klon_mpi,i) 复制到南极所有经度。

grid2dTo1d_mpi_*gen

输入:VarIn(nbp_lon*jj_nb, dimsize)。 输出:VarOut(klon_mpi, dimsize)

流程:

  1. 默认 offset=ii_begin;若本 rank 拥有北极,改为 offset=nbp_lon
  2. 主体循环从 VarIn(ij+offset-1,i) 读回 VarOut(ij,i)
  3. is_north_pole_dyn,额外令 VarOut(1,i)=VarIn(1,i)

南极没有单独覆盖步骤,因为它在主体循环中已经按当前 rank 的局部范围读回。

编译和运行守卫

MPI 引擎都使用两层守卫:

因此非 MPI 构建下,本模块仍可被上层编译依赖引用;真正行为由 is_using_mpi 和上层 wrapper 控制。

依赖状态

来源 符号 用途
mod_phys_lmdz_mpi_data is_using_mpi, is_mpi_root, mpi_master, mpi_size 决定是否调用 MPI、root rank 和 rank 数。
mod_phys_lmdz_mpi_data COMM_LMDZ_PHY, MPI_REAL_LMDZ MPI communicator 和 real datatype。
mod_phys_lmdz_mpi_data klon_mpi, klon_mpi_para_nb/begin/end 当前 rank 和所有 ranks 的 physical-column 分布。
mod_phys_lmdz_mpi_data ii_begin, jj_nb, is_north_pole_dyn, is_south_pole_dyn 局部 1D/2D 转换的偏移和极点处理。
mod_grid_phy_lmdz klon_glo, nbp_lon 全局列数、经度数和全局 1D/2D 转换规模。

复现要点

  1. 初始化 mod_phys_lmdz_mpi_data 后再调用本模块,否则 klon_mpi、分布表和 communicator 未定义。
  2. scatter/gather 的 dimsize 来自非物理列维度;物理列维必须始终是第一维。
  3. 需要全局 lon-lat 2D 字段时使用 scatter2D_mpi/gather2D_mpi,而不是手工调用 grid*_glo 后再调用 scatter/gather,除非你明确要拆开调试。
  4. grid1dTo2d_mpi/grid2dTo1d_mpi 是局部块转换;它们不产生全局场。
  5. reduce 只在 root rank 上给出有效结果;若所有 ranks 后续都读结果,上层要配合 bcast_mpibcast

待确认

相关页面