mod_grid_phy_lmdz.F90
源码基线:LMDZ.COMMON-6.3\LMDZ.COMMON。 Mars 运行参与度:条件经过。Mars 3D 物理初始化经 inigeomphy_mod -> physics_distribution_mod -> init_grid_phy_lmdz 设置本模块;Mars 1D/testphys 也通过 init_physics_distribution(regular_lonlat,4,1,1,1,...) 设置单列网格。后续 diagfi/stats/XIOS/restart/surface 初始化读取 klon_glo/nbp_lon/nbp_lat/grid_type 或调用 Grid1Dto2D_glo。
源码范围
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\phy_common\mod_grid_phy_lmdz.F90
文件行数:468。
模块职责
mod_grid_phy_lmdz 是物理侧全局网格状态模块。它不分配经纬度、面积或垂直层数组;这些由 regular_lonlat_mod、geometry_mod 和 vertical_layers_mod 保存。本模块只保存网格类型、顶点数、全局经纬/垂直规模和全局物理列数,并提供两组泛型映射:
| 泛型 | 方向 | 典型用途 |
|---|---|---|
Grid1Dto2D_glo |
klon_glo 物理列 -> (nbp_lon, nbp_lat) lon-lat 场 |
Mars diagfi/stats/debug 输出前,把 gather 后的全局物理列展开为二维网格。 |
Grid2Dto1D_glo |
(nbp_lon, nbp_lat) lon-lat 场 -> klon_glo 物理列 |
从带极点重复经度的二维场回到物理列表示。 |
模块状态
| 符号 | 行号 | 类型 | 含义 |
|---|---|---|---|
unstructured |
10 | integer parameter = 0 | 非结构/ICO 类网格枚举。Mars lon-lat GCM 主线通常不走这一类,但 XIOS/diagfi 会检查它。 |
regular_lonlat |
11 | integer parameter = 1 | regular longitude-latitude 网格枚举;Mars lon-lat 3D 和 1D 初始化都以此传入。 |
grid_type |
13 | integer, save | 当前物理网格类型,由 init_grid_phy_lmdz 写入。 |
nvertex |
14 | integer, save | 每个 cell 的顶点数;regular lon-lat 初始化传 4。Mars topmons_mod 读取它。 |
nbp_lon |
15 | integer, save | 全局 regular 网格经向点数,注释标为 iim。 |
nbp_lat |
16 | integer, save | 全局 regular 网格纬向点数,注释标为 jjmp1;1D 时为 1。 |
nbp_lev |
17 | integer, save | 垂直层数,注释标为 llm。 |
klon_glo |
18 | integer, save | 全局物理列数,去掉两极重复经度后的列数。 |
这些变量都是模块 SAVE 状态,不是 THREADPRIVATE。它们必须在使用任何物理输出、transfer 或 Mars surface/restart helper 前完成初始化。
初始化入口
init_grid_phy_lmdz(grid_type_, nvertex_, nbp_lon_, nbp_lat_, nbp_lev_) 定义在 39-59 行。它只做赋值和 klon_glo 推导:
grid_type = grid_type_
nvertex = nvertex_
nbp_lon = nbp_lon_
nbp_lat = nbp_lat_
nbp_lev = nbp_lev_
if nbp_lon * nbp_lat == 1:
klon_glo = 1
else:
klon_glo = nbp_lon * nbp_lat - 2 * (nbp_lon - 1)
公式含义:
| 情况 | klon_glo |
解释 |
|---|---|---|
| 1D/testphys | 1 |
单列模式不展开极点和经圈。 |
| 3D regular lon-lat | nbp_lon * nbp_lat - 2*(nbp_lon-1) |
二维 lon-lat 场有北极 nbp_lon 个重复经度和南极 nbp_lon 个重复经度;物理列表示每个极点只保留一个点,因此每个极点少 nbp_lon-1 个点。 |
在 Mars lon-lat 3D 路径中,inigeomphy_mod 对 iim*jjm>1 调用:
init_physics_distribution(regular_lonlat, 4, nbp, iim, jjm+1, nlayer, communicator)
随后 physics_distribution_mod 调用 init_grid_phy_lmdz,再初始化物理并行分布和 dimphy。
泛型接口库存
Grid1Dto2D_glo 接口从 20 行开始,覆盖 integer/real/logical 三种类型,每种支持 1 到 4 维输入。Grid2Dto1D_glo 接口从 28 行开始,覆盖同样的类型和 rank。
| 方向 | 类型族 | public wrapper | private kernel |
|---|---|---|---|
| 1D -> 2D | integer | grid1dTo2d_glo_i/i1/i2/i3 |
grid1dTo2d_glo_igen |
| 1D -> 2D | real | grid1dTo2d_glo_r/r1/r2/r3 |
grid1dTo2d_glo_rgen |
| 1D -> 2D | logical | grid1dTo2d_glo_l/l1/l2/l3 |
grid1dTo2d_glo_lgen |
| 2D -> 1D | integer | grid2dTo1d_glo_i/i1/i2/i3 |
grid2dTo1d_glo_igen |
| 2D -> 1D | real | grid2dTo1d_glo_r/r1/r2/r3 |
grid2dTo1d_glo_rgen |
| 2D -> 1D | logical | grid2dTo1d_glo_l/l1/l2/l3 |
grid2dTo1d_glo_lgen |
Wrapper 的职责是按额外维度计算 dimsize。例如 real 3D 物理列输入 VarIn(klon_glo, a, b) 会传入 dimsize = a*b;kernel 把第一维之外的维度作为线性 trailing block 处理。这样同一套两极展开/压缩规则可复用于 2D surface field、3D column field、带 tracer/soil/slope 等额外维度的数组。
Grid1Dto2D_glo 展开规则
三个 private kernel 的逻辑相同,只是数据类型不同。以 296-328 行的 integer 版本为例,输入逻辑尺寸是:
VarIn (klon_glo, dimsize)
VarOut(nbp_lon * nbp_lat, dimsize)
offset = nbp_lon
步骤:
- 对每个 trailing index
i,把全局物理列ij=1:klon_glo写到二维线性场的ij + nbp_lon - 1。 - 把二维场第一纬圈
1:nbp_lon全部填成VarIn(1,i),即北极单物理点复制到所有经度。 - 把二维场最后一纬圈
nbp_lon*(nbp_lat-1)+1 : nbp_lon*nbp_lat全部填成VarIn(klon_glo,i),即南极单物理点复制到所有经度。
因此对 3D regular lon-lat,线性对应是:
2D row 1 <- physical column 1, repeated nbp_lon times
2D rows 2 .. nbp_lat-1 <- physical columns 2 .. klon_glo-1
2D row nbp_lat <- physical column klon_glo, repeated nbp_lon times
Mars writediagfi.F 在并行模式中先 Gather(px, dx*_glop) 到 klon_glo 全局物理列,再调用 Grid1Dto2D_glo 得到 dx*_glo(nbp_lon,nbp_lat,...),最后额外复制第一经度到 nbp_lon+1 形成 NetCDF lon wrap。
Grid2Dto1D_glo 压缩规则
2D 到 1D 的 private kernel 定义在 399-466 行,输入逻辑尺寸是:
VarIn (nbp_lon * nbp_lat, dimsize)
VarOut(klon_glo, dimsize)
offset = nbp_lon
步骤:
- 对每个 trailing index
i,先把二维线性场的ij + nbp_lon - 1复制到VarOut(ij,i)。 - 然后显式执行
VarOut(1,i)=VarIn(1,i)。
第二步会把北极物理列改成二维场第一个格点。南极物理列没有类似显式覆盖,因为第一步已经把 VarOut(klon_glo,i) 对应到最后一纬圈的第一个位置:klon_glo + nbp_lon - 1 = nbp_lon*(nbp_lat-1)+1。
复现时要注意:Grid2Dto1D_glo 不对极点重复经度做平均;它取北极/南极纬圈的第一个经度位置。因此输入二维场若在极点经向不一致,压缩会静默丢弃其他经度。
Mars 使用点
| 使用方 | 使用符号 | 作用 |
|---|---|---|
| COMMON inigeomphy_mod | regular_lonlat, klon_glo |
初始化 physical distribution 后,用 klon_glo 分配全局物理几何数组。 |
| COMMON physics_distribution_mod | init_grid_phy_lmdz |
将 grid type、顶点数、lon/lat/lev 写入本模块。 |
| COMMON xios_writefield | nbp_lon, nbp_lat, klon_glo, grid_type |
按 regular/unstructured 选择 XIOS domain 和 field shape。 |
| COMMON write_field_phy | Grid1Dto2D_glo, nbp_lon, nbp_lat, klon_glo |
调试写场前把 gather 后的物理列转成 lon-lat。 |
Mars writediagfi.F, writediagmicrofi.F, writediagsoil.F90, wstats_mod.F90 |
Grid1Dto2D_glo, klon_glo, nbp_lon, nbp_lat |
正式 diagfi/stats 输出从物理列变成 NetCDF lon-lat 场。 |
Mars xios_output_mod.F90 |
grid_type, unstructured, nbp_lon, nbp_lat, klon_glo |
建立 XIOS domain,unstructured 时走专门 domain helper。 |
Mars surfini_mod.F90, slope_mod.F90 |
klon_glo, nbp_lon, nbp_lat |
surface/ice cap/slope 初始化按全局物理列和 lon-lat 分辨率循环。 |
Mars iostart.F90, phyredem.F90, phyetat0_mod.F90 |
klon_glo, nbp_lon, nbp_lat, nbp_lev |
physics start/restart 读写的维度和控制量。 |
Mars parse_tracer_file.F90 |
grid_type, regular_lonlat |
tracer.def 解析时在 lmdz/dynamico 类型之间分支。 |
复现要点
- 初始化顺序必须是:
inigeomphy_mod或 1D 初始化先调用init_physics_distribution,再进入任何读取klon_glo/nbp_lon/nbp_lat的物理输出、surface 或 restart 例程。 - Mars lon-lat 输出常见形状是
nbp_lon+1,这是输出层额外添加周期经度后的结果;本模块的 2D 映射只生成nbp_lon * nbp_lat,不负责+1wrap。 grid_type==unstructured是接口兼容分支。Mars lon-lat GCM 主线初始化传regular_lonlat;若实际运行接入 DYNAMICO/非结构网格,输出路径会依据grid_type改走 unstructured 分支。Grid1Dto2D_glo会复制两极,Grid2Dto1D_glo会选取两极第一个经度位置;二者不是守恒平均算子。- 1D 情况
nbp_lon=nbp_lat=klon_glo=1,diagfi/stats 等输出例程通常有单列专门分支,不能套用 3D 的极点重复经度逻辑。 - 模块内没有
ALLOCATE、文件 I/O、MPI 或 OpenMP 调用;并行 gather/scatter 由mod_phys_lmdz_para和 transfer 模块完成。
待确认
Grid2Dto1D_glo对极点重复经度只取第一个经度位置,这是源码事实;调用方是否保证极点经向值一致,需要逐调用点确认。- Mars DYNAMICO/unstructured 实际运行是否经过 COMMON 本模块的
unstructured分支,需要结合具体 build target 和运行脚本确认;本页只标注接口兼容边界。