xios_writefield.F90
源码路径:
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\phy_common\xios_writefield.F90
Mars 运行参与度:条件经过/接口兼容。该文件只在 CPP_XIOS 下定义 xios_writefield generic;当前 COMMON 与本地 LMDZ.MARS 源码中未检出直接 USE xios_writefield_mod 或 xios_writefield(...) 调用点。它应按临时 XIOS field dump helper 维护,不应误读为 Mars diagfi、stats 或标准 physics XIOS 输出主链。
文件职责
xios_writefield_mod 为物理列局部数组提供一个按字段名懒创建的 XIOS 输出封装:
- 2D 入口
xios_writefield2d(field(:), name_in)输出一层物理列字段。 - 3D 入口
xios_writefield3d(field(:,:), name_in)输出物理列加垂直层字段。 - 每个字段名创建独立 XIOS context、file 和 field,之后同名字段复用该 context 并递增本字段的 time counter。
- regular lon-lat grid 先从 OMP local gather 到 MPI local,再经
grid1Dto2D_mpi变成nbp_lon, jj_nb二维块发送。 - unstructured grid 直接发送
klon_mpi物理列块;如果运行参数要求 regular 输出,则定义regular_domain交给 XIOS 插值。
本文件不定义 Mars 输出频率、正式变量表或 physics 诊断内容。它只按调用方传入的 name_in 和 field shape 即时生成一个同名输出文件。
编译和公开接口
整个模块主体位于:
#ifdef CPP_XIOS
...
#endif因此没有 CPP_XIOS 时,本文件不会提供 xios_writefield generic。启用 CPP_XIOS 后公开符号只有:
| 符号 | 类型 | 作用 |
|---|---|---|
xios_writefield |
generic interface | 根据 rank 分派到 2D 或 3D 版本。 |
xios_writefield2d |
module procedure | 输出 field(klon_omp)。 |
xios_writefield3d |
module procedure | 输出 field(klon_omp, nz),并创建一个简单垂直 axis。 |
NameId |
private function | 在当前线程的 FieldName(1:NbField) 中查找字段名。 |
模块状态
| 状态 | 维度/类型 | 并行属性 | 含义 |
|---|---|---|---|
size_name |
parameter 255 |
常量 | 字段名缓存长度。 |
MaxWriteField |
parameter 100 |
常量 | 最多登记字段数;源码无越界保护。 |
FieldName(MaxWriteField) |
character save | THREADPRIVATE |
当前线程已经懒创建过的字段名。 |
FieldIt(MaxWriteField) |
integer save | THREADPRIVATE |
每个字段的 XIOS calendar step counter。 |
NbField |
integer save | THREADPRIVATE |
当前线程已登记字段数。 |
output_native_grid |
logical save | THREADPRIVATE |
xios_writefield_nlon/nlat 缺失或为 0 时为真。 |
ni_glo, nj_glo |
integer save | THREADPRIVATE |
用户请求的 regular 输出网格大小。 |
这些状态都是线程私有。源码没有跨线程同步 FieldName/NbField/FieldIt,也没有清理 XIOS context 或重置缓存的入口。
输入、输出和依赖
输入参数
| 入口 | 输入 | 约束 |
|---|---|---|
xios_writefield2d |
field(:), name_in |
size(field,1) 必须等于 klon_omp。 |
xios_writefield3d |
field(:,:), name_in |
第一维必须等于 klon_omp;第二维作为临时 vertical axis 长度。 |
如果第一维不匹配,例程向 lunout 打印错误后直接 RETURN,不会 abort。
使用的 COMMON 状态
| 来源 | 符号 | 用途 |
|---|---|---|
dimphy |
klon_omp |
校验调用方传入的是当前 OpenMP 线程的物理列字段。 |
mod_phys_lmdz_para |
is_master, is_omp_master, COMM_LMDZ_PHY, Gather_omp, bcast, grid1Dto2D_mpi, klon_mpi, jj_nb |
root 读取参数、广播输出网格、OMP gather、regular 2D 重排、XIOS context communicator。 |
mod_grid_phy_lmdz |
nbp_lon, nbp_lat, klon_glo, grid_type, regular_lonlat, unstructured |
选择 domain 类型和发送数组 shape。 |
| wxios | wxios_domain_param, wxios_domain_param_unstructured, wxios_set_context |
填写 XIOS domain 属性,并在发送后恢复默认 context。 |
ioipsl |
getin |
读取 xios_writefield_nlon 和 xios_writefield_nlat。 |
print_control_mod |
lunout |
shape mismatch 消息输出。 |
运行配置键
| 键 | 默认/触发 | 作用 |
|---|---|---|
xios_writefield_nlon |
初始为 0,root 用 getin 覆盖 |
unstructured grid 请求插值到 regular domain 时的 longitude 数。 |
xios_writefield_nlat |
初始为 0,root 用 getin 覆盖 |
unstructured grid 请求插值到 regular domain 时的 latitude 数。 |
只要 ni_glo==0 或 nj_glo==0,源码就设置 output_native_grid=.TRUE.,即 unstructured 输出保持 native domain。
首次字段定义流程
2D 和 3D 入口的结构基本相同:
检查第一维是否等于 klon_omp
name = trim(adjustl(name_in))
id = NameId(name)
if id != 0:
OMP master 取回 context_lmdz_<name> 并设为 current context
else:
root getin xios_writefield_nlon/nlat
bcast ni_glo/nj_glo
判断 output_native_grid
OMP master 初始化 context_lmdz_<name>
定义 D360 calendar、start date、time origin、timestep
定义 domain / domaingroup
如 unstructured 且非 native 输出,额外定义 regular_domain + generate_domain + interpolate_domain
3D 入口额外定义 axis
调用 wxios_domain_param 或 wxios_domain_param_unstructured 写 domain 属性
OMP master 定义 file、field、field_ref
如 unstructured 且非 native 输出,把 field domain_ref 改成 regular_domain
close context definition
登记 FieldName、FieldIt、NbField
Gather_omp 到 field_mpi
OMP master 更新 FieldIt(id) 和 XIOS calendar
按 grid_type 发送 regular 2D/3D block 或 unstructured physical-column block
wxios_set_context 恢复外层 context
grid 分支
grid_type |
domain 定义 | 发送数组 | 说明 |
|---|---|---|---|
regular_lonlat |
wxios_domain_param("domain") |
2D: Field2d(nbp_lon,jj_nb);3D: Field2d(nbp_lon,jj_nb,nz) |
field 先 Gather_omp 到 field_mpi,再 grid1Dto2D_mpi 转为当前 MPI 纬向块。 |
unstructured, native 输出 |
wxios_domain_param_unstructured("domaingroup") |
2D: field_mpi(klon_mpi);3D: field_mpi(klon_mpi,nz) |
XIOS domain 类型为 unstructured,global size 来自 klon_glo。 |
unstructured, regular 输出 |
先定义 native domain,再加 regular_domain |
同 unstructured 发送,field 的 domain_ref 改成 regular_domain |
regular_domain 设置 ni_glo/nj_glo/type="rectilinear",再加 generate_domain 和 interpolate_domain。 |
mod_grid_phy_lmdz 中 unstructured=0、regular_lonlat=1,init_grid_phy_lmdz 保存运行时 grid_type。本文件只处理这两个值;若出现其他值,源码没有 else 报错,发送分支会被跳过。
2D 与 3D 差异
| 项目 | 2D | 3D |
|---|---|---|
| 输入 field | field(klon_omp) |
field(klon_omp,nz) |
| MPI local buffer | field_mpi(klon_mpi) |
field_mpi(klon_mpi,nz) |
| regular send buffer | Field2d(nbp_lon,jj_nb) |
Field2d(nbp_lon,jj_nb,nz) |
| XIOS field attr | domain_ref="domain", operation="instant" |
domain_ref="domain", axis_ref="axis", operation="instant" |
| axis | 无 | 创建 id 为 axis 的 axis,n_glo=nz,value=1..nz,unit="level"。 |
3D 入口的 axis 只是整数层号,不读取 presnivs、pseudoalt 或真实垂直坐标。
XIOS 输出对象
首次调用字段 name 时,源码创建:
| 对象 | id/name | 属性 |
|---|---|---|
| context | context_lmdz_<name> |
communicator 为 COMM_LMDZ_PHY。 |
| calendar | D360 |
start date 和 time origin 都是 2000-01-01 00:00:00,timestep 为 xios_second。 |
| file | auto child,name=<name> |
output_freq=xios_timestep, sync_freq=xios_timestep, type="one_file"。 |
| field | <name> |
operation="instant",写入同名 file。 |
每次发送前 FieldIt(id)=FieldIt(id)+1,然后 xios_update_calendar(FieldIt(id))。因此这个 helper 的时间轴是每个字段独立计数,而不是直接继承 GCM 主时间步。
与正式输出链的边界
- Mars 标准 physics 诊断由 Mars 侧
diagfi、stats、soil和xios_output_mod等路径控制。 - COMMON 动力 history/dynav 输出由
inithist/writehist/initdynav/writedynav及其并行版本控制。 xios_writefield.F90不读取 Mars field XML,也不登记 Mars physics 变量名;它按name_in即时创建独立 XIOS context/file/field。- 本地源码搜索未见直接调用点,因此页面把它标为临时/调试/接口兼容 helper,而非必经主线。
复现要点
- 调用方必须在
CPP_XIOS构建中使用本模块,否则 generic 不存在。 - 传入数组第一维必须是当前 OpenMP 线程的
klon_omp,不是klon_mpi、klon_glo或dimphy:klon之外的任意网格长度。 - 字段名经
trim(adjustl(name_in))后作为 context、file 和 field 名的一部分;同名字段复用已有 context。 - regular lon-lat 输出会多一步
grid1Dto2D_mpi,shape 是当前 MPI 子域的nbp_lon,jj_nb。 - unstructured grid 若设置了非零
xios_writefield_nlon/nlat,field 的domain_ref会切到regular_domain,由 XIOS 插值到 rectilinear 网格。 MaxWriteField=100没有源码级越界保护;长期调试时不要动态生成大量唯一字段名。- shape mismatch 的错误消息拼接使用
FieldName而不是name_in,实际输出内容可能不直观;源码只RETURN。
待确认
- 当前本地 COMMON/MARS 源码未见活跃调用点;若某个外部 physics 包或用户 patch 调用
xios_writefield,需要补充调用方和字段名约定。 axisid 固定为"axis",但每个字段使用独立 context,理论上避免了同一 context 内重复定义冲突;是否符合所有 XIOS 版本行为需运行验证。- unstructured regular 输出的
generate_domain只设置lon_start=-180.、lat_start=90.、lat_end=-90.,未显式设置lon_end;最终网格解释依赖 XIOS。