calfis_p 动力格点到物理列映射
输入范围
dynphy_lonlat\calfis_p.F: L1-1520(并行物理调用接口)
dynphy_lonlat\mod_interface_dyn_phys.F90: L1-65(index_i/index_j 初始化)
dynphy_lonlat\gr_dyn_fi_p.F: L1-44(动力→物理标量场 scatter)
dynphy_lonlat\gr_fi_dyn_p.F: L1-56(物理→动力标量场 gather)
Mars 运行参与度:条件经过。Mars 并行动力启用物理时(apphys 为真),calfis_p 每次 physics timestep 执行一次完整的 scatter → call_physiq → gather 流程。
例程定位
本页聚焦 calfis_p 中动力网格 (iip1,jjp1) 与物理列 (klon) 之间的数据映射机制。映射由 mod_interface_dyn_phys 的 index_i/index_j 数组驱动,贯穿场 scatter、wind 转换、极点投影和 tendency 回写四个阶段。整体接口结构详见 calfis_p 模块页。
物理列索引映射
index_i/index_j 初始化
Init_interface_dyn_phys 在 physics 初始化阶段分配 index_i(klon_mpi) 和 index_j(klon_mpi),按纬圈顺序将每个物理列映射回动力 (i,j) 索引:
k = 1
if (is_north_pole_dyn) then
index_i(k) = 1; index_j(k) = 1; k = 2 ! 北极单列
else
DO i = ii_begin, iim ! 首行部分经度
index_i(k) = i; index_j(k) = jj_begin; k = k+1
ENDDO
endif
DO j = jj_begin+1, jj_end-1 ! 中间纬圈:完整经度
DO i = 1, iim
index_i(k) = i; index_j(k) = j; k = k+1
ENDDO
ENDDO
if (is_south_pole_dyn) then
index_i(k) = 1; index_j(k) = jj_end ! 南极单列
else
DO i = 1, ii_end ! 末行部分经度
index_i(k) = i; index_j(k) = jj_end; k = k+1
ENDDO
endif关键特征:
- 极点只映射到
i=1的单点,因为极点所有经度共享同一个物理状态。 - 首行和末行可能只映射部分经度(
ii_begin:iim或1:ii_end),因为物理侧 MPI 分布可能将一行经度切割到多个 rank。 - 中间纬圈总是映射完整
iim个经度。 klon_mpi=1的特例(1D "parallel" setup):如果当前 rank 只拥有北极且klon_mpi==1,则只映射一个极点列。
klon_mpi vs klon_omp
calfis_p 使用两级列数:
klon = klon_mpi:整个 MPI rank 的物理列数,用于 scatter/gather 阶段。klon = klon_omp:单个 OpenMP 线程负责的列数,用于call_physiq调用。
两者通过 offset = klon_omp_begin - 1 连接:线程 t 负责 klon_mpi 数组中 [offset+1, offset+klon_omp] 范围的列。
场 scatter:动力网格 → 物理列
标量场 scatter
每个标量场通过 index_i/index_j 从动力二维数组提取到物理一维列数组:
! 手动展开(压力、温度、tracer 等)
do ig0 = 1, klon
i = index_i(ig0)
j = index_j(ig0)
zpsrf(ig0) = pps(i,j)
enddo
! 批量调用(geopotential、flxw)
CALL gr_dyn_fi_p(nfield, iip1, jjp1, klon, pdyn, pfi)gr_dyn_fi_p 内部实现完全相同的逻辑:
DO l = 1, nfield
DO ig = 1, klon
i = index_i(ig)
j = index_j(ig)
pfi(ig,l) = pdyn(i,j,l)
ENDDO
ENDDO被 scatter 的场及其转换细节:
| 动力场 | 物理列 | 转换 |
|---|---|---|
pps |
zpsrf |
直接索引 |
pp |
zplev |
直接索引(每层循环) |
ppk |
zpk |
直接索引 |
pteta |
zteta → ztfi |
直接索引后 tpot2t_p 转温度 |
pq |
zqfi |
每 tracer 直接索引 |
pphi |
zphi |
gr_dyn_fi_p 后减 zphis |
pphis |
zphis |
gr_dyn_fi_p |
flxw |
flxwfi |
gr_dyn_fi_p |
zplay 的派生计算
zplay 不是直接 scatter,而是从 zpk 派生:
pksurcp = ppk(i,j,l) / cpp
zplay(ig0,l) = preff * pksurcp ** unskap ! unskap = 1/kappa这是 Exner 函数的逆运算,把 ppk(Exner 值)转换为中层压力。
wind scatter
wind 转换比标量复杂,因为动力网格使用协变分量 (pucov, pvcov),而物理侧使用自然分量 (zufi, zvfi, zrfi):
zufi(自然纬向风):
if (i == 1) then
zufi(ig0,l) = 0.5 * (pucov(iim,j,l)/cu(iim,j) + pucov(1,j,l)/cu(1,j))
else
zufi(ig0,l) = 0.5 * (pucov(i-1,j,l)/cu(i-1,j) + pucov(i,j,l)/cu(i,j))
endif取相邻两个 U 点的协变分量除以 cu(度量因子)得到自然分量,再平均到标量点。i==1 时使用 iim 的 E-W 周期包裹。
zvfi(自然经向风):
zvfi(ig0,l) = 0.5 * (pvcov(i,j-1,l)/cv(i,j-1) + pvcov(i,j,l)/cv(i,j))取相邻两个 V 点的协变分量除以 cv 后平均。
zrfi(相对涡度):先在动力网格上计算 zrot(协变风分的离散旋度),再用 4 点平均到标量点。极点处 j==1 或 j==jjp1 时置零。
极点 wind 投影
极点处的自然风分量通过对所有经度做 cos/sin 积分获得:
! 北极
z1(i) = (rlonu(i)-rlonu(i-1)) * pvcov(i,1,l) / cv(i,1)
zcos(i) = COS(rlonv(i)) * z1(i)
zsin(i) = SIN(rlonv(i)) * z1(i)
zufi(1,l) = SSUM(iim, zcos, 1) / pi ! U = <v*cos(lon)>/pi
zvfi(1,l) = SSUM(iim, zsin, 1) / pi ! V = <v*sin(lon)>/pi
zrfi(1,l) = 0.这与 vly 中极点 dyq 的 sin/cos 投影是相同的数学操作:将极点矢量投影到最低两个 Fourier 模态。南极使用 jjm 行和 klon 列。
MPI wind 边界交换
physics 调用后,calfis_p 执行一次手写 MPI 交换:
! rank > 0 发送前 iim 列给 rank-1
MPI_ISSEND(du_send, iim*llm, ..., MPI_Rank-1, tag=401, ...)
! rank < size-1 从 rank+1 接收
MPI_IRECV(du_recv, iim*llm, ..., MPI_Rank+1, tag=401, ...)交换的是物理 tendency zdufi/zdvfi 的首 iim 列。目的是构造扩展数组 zdufi2/zdvfi2:
zdufi2(1:klon, l) = zdufi(1:klon, l)
zdufi2(klon+1:klon+iim, l) = du_recv(1:iim, l)扩展后的数组支持 V wind tendency 回写时需要跨纬带平均:pdvfi 使用 zdvfi2(ig0) 和 zdvfi2(ig0+iim) 做平均,后者属于下一纬带。如果下一纬带在另一个 rank 上,没有这次交换就无法获取。
场 gather:物理列 → 动力网格
标量场 gather
gr_fi_dyn_p 实现物理列到动力网格的反向映射:
do ig = 1, klon
i = index_i(ig)
j = index_j(ig)
pdyn(i,j,ifield) = pfi(ig,ifield)
if (i == 1) pdyn(im,j,ifield) = pdyn(i,j,ifield) ! E-W 周期端点
enddo当 i==1 时,同时将值写入 im 位置(E-W 周期端点),确保周期一致性。
极点处理:
if (pole_nord) then
do i = 1, im
pdyn(i,1,ifield) = pdyn(1,1,ifield) ! 极点所有经度同值
enddo
endiftendency 回写
tendency 回写不都使用 gr_fi_dyn_p。各场使用不同的回写策略:
pdpsfi(surface pressure tendency):使用 gr_fi_dyn_p。
CALL gr_fi_dyn_p(1, klon, iip1, jjp1, zdpsrf, pdpsfi)pdhfi(potential temperature tendency):手动回写,不使用 zdtfi 而是 (zteta-pteta)/dtphys:
pdhfi(i,j,l) = (zteta(ig0,l) - pteta(i,j,l)) / dtphys这避免了中间转换的精度损失。t2tpot_p 先将物理温度转回位温 zteta,再与原始 pteta 差商。极点整行用极点单列值扩展。i==1 时补 iip1 周期端点。
pdqfi(tracer tendency):先整层清零,再按 iq 手动回写:
pdqfi(:,:,l,:) = 0.
DO iq = 1, nqtot
DO ig0 = kstart, kend
i = index_i(ig0); j = index_j(ig0)
pdqfi(i,j,l,iq) = zdqfi(ig0,l,iq)
if (i==1) pdqfi(iip1,j,l,iq) = zdqfi(ig0,l,iq)
ENDDO
! 极点扩展
ENDDO清零确保 niadv 未映射的 tracer 位为零。i==1 补周期端点。
pdufi(zonal wind tendency):使用扩展数组 zdufi2 的相邻平均:
if (i /= iim) then
pdufi(i,j,l) = 0.5 * (zdufi2(ig0,l) + zdufi2(ig0+1,l)) * cu(i,j)
endif
if (i == 1) then
pdufi(iim,j,l) = 0.5 * (zdufi2(ig0,l) + zdufi2(ig0+iim-1,l)) * cu(iim,j)
pdufi(iip1,j,l) = 0.5 * (zdufi2(ig0,l) + zdufi2(ig0+1,l)) * cu(i,j)
endif物理 tendency 平均到 U 点后乘 cu 恢复协变分量。i==1 时用 E-W 周期包裹。极点行置零。
pdvfi(meridional wind tendency):使用跨纬带平均:
pdvfi(i,j,l) = 0.5 * (zdvfi2(ig0,l) + zdvfi2(ig0+iim,l)) * cv(i,j)ig0+iim 跳到下一纬带,这就是前面 MPI 交换的目的。极点附近用投影方式回写:
! 北极
pdvfi(i,1,l) = zdufi(1,l)*COS(rlonv(i)) + zdvfi(1,l)*SIN(rlonv(i))
pdvfi(i,1,l) = 0.5 * (pdvfi(i,1,l) + zdvfi(i+1,l)) * cv(i,1)先将极点自然风 tendency 投影到各经度方向,再与邻近纬带平均后乘 cv。
边界清零
回写前,本 rank 起始纬圈 jj_begin 的 tendency 全部清零。若不是南极 rank,jj_end 也清零:
pdhfi(:,jj_begin,l) = 0; pdqfi(:,jj_begin,l,:) = 0
pdufi(:,jj_begin,l) = 0; pdvfi(:,jj_begin,l) = 0
pdpsfi(:,jj_begin) = 0这防止旧值残留。leapfrog_p 后续通过 jj_Nb_Physic_bis halo 合并处理边界一致性。
复现要点
index_i/index_j映射是 scatter/gather 的唯一路径。如果Init_interface_dyn_phys未被调用或klon_mpi与物理侧不一致,所有场转换都会越界或错位。- 极点列在
index_i/index_j中只出现一次(i=1),但 gather 时需要将极点值扩展到所有经度。遗漏这一步会导致极点除第一列外的格点保持零或旧值。 i==1时同时写iip1(周期端点)是 E-W 周期一致性的关键。pdufi的i==1路径额外写iim位置。pdhfi使用(zteta-pteta)/dtphys而非cpp*zdtfi/ppk,这在 cpdet 变比热路径下避免了 Exner 除法的不精确。- wind tendency 的 MPI 交换只涉及
zdufi/zdvfi(物理 tendency),不涉及zufi/zvfi(物理状态)。这意味着物理状态的跨 rank 一致性依赖 physics 前的 halo 而非 physics 后的交换。 zdufi2/zdvfi2维度为klon+iim,最后一 rank 没有du_recv数据。MPI_rank==MPI_Size-1时zdufi2(klon+1:)保持未初始化状态,但对应的pdvfi在is_south_pole_dyn条件下已被特殊处理。
相关页面
- calfis_p 模块页
- calfis_p 与 call_physiq 接口约定
- calfis_p 并行 transfer 架构
- mod_interface_dyn_phys
- dyn-phys-grid-transforms
- leapfrog-p-physics-coupling
- leapfrog_p
待确认
ii_begin/ii_end在物理侧 MPI data 中的精确定义,以及与动力侧jj_begin/jj_end的对应关系。klon_mpi=1特例(1D parallel setup)在 Mars 配置中是否可能出现。pdvfi回写时最后一 rank 的zdufi2(klon+1:)未初始化问题是否在实际运行中触发。