writediagfi.F
路径
LMDZ.MARS\libf\phymars\writediagfi.F
所属目录 / 模块
libf/phymars
文件定位
writediagfi.F 定义传统物理诊断文件 diagfi.nc 的逐字段写入后端。它可以被物理包任意例程多次调用;第一次通过 diagfi.def 可选筛选变量,第一次有效变量调用时创建 diagfi.nc、定义 Time 并调用 iniwrite 写经纬度、垂直层、地表位势、网格面积等固定头信息。后续调用按 steps_per_sol/outputs_per_sol 派生的采样间隔追加时间和变量。
本例程处理四类维度码:dim=3 写经纬度-高度-时间场,dim=2 写地表经纬度-时间场,dim=1 写 1D column 的高度-时间剖面,dim=0 写时间标量。并行 GCM 路径先 gather 到全局物理网格并用 Grid1Dto2D_glo 重排,串行路径手工把物理网格复制到带冗余经度点的 (nbp_lon+1,nbp_lat) 网格。
定义的符号
| 符号 |
类型 |
行号 |
作用 |
writediagfi |
subroutine |
1 |
向 diagfi.nc 创建并追加写入诊断变量。 |
firstcall |
saved logical |
105 |
首次进入时读取 diagfi.def 并计算采样控制;其 THREADPRIVATE 声明在第 106 行。 |
firstnom/prevnom/lastnom |
saved character |
83-85 |
识别每个物理时刻的第一个和最后一个诊断变量名;对应 THREADPRIVATE 声明在第 86 行。 |
zitau/ntime/nid/date |
saved state |
79-101 |
管理输出步计数、NetCDF 时间索引、文件 id 和输出日期。 |
依赖的模块
| use 模块 |
only 列表 |
用途 |
待确认 |
surfdat_h |
phisfi |
初始化文件头时写地表位势。 |
- |
geometry_mod |
cell_area |
初始化文件头时写网格面积。 |
- |
time_phylmdz_mod |
steps_per_sol, outputs_per_sol, day_end, day_ini, slow_diagfi |
计算采样间隔、最后输出步和 1D 文件打开/关闭策略。 |
- |
mod_phys_lmdz_para |
is_parallel, is_mpi_root, is_master, gather |
并行收集和只允许 master/root 写 NetCDF。 |
- |
mod_grid_phy_lmdz |
klon_glo, Grid1Dto2D_glo, nbp_lon, nbp_lat, nbp_lev, grid_type, unstructured |
网格维度、物理到经纬网格重排和 unstructured 网格早退。 |
- |
调用的关键例程
| 被调用例程 |
所在模块 / 文件 |
调用位置 |
作用 |
iniwrite |
iniwrite.F |
首次有效变量调用 |
写 diagfi.nc 固定头信息和坐标。 |
def_var |
def_var.F90 |
新变量首次写入 |
在 NetCDF define mode 中创建变量并写 title/units 属性。 |
abort_physic |
外部错误处理 |
多处错误分支 |
变量名过长、diagfi.def 超限、变量重复、写入失败或并行 dim=1 时中止。 |
NetCDF NF_* |
NetCDF F77 接口 |
多处 |
创建/打开/关闭文件,定义维度变量,追加时间和写变量。 |
gather, Grid1Dto2D_glo |
并行/网格模块 |
并行 dim=2/3 路径 |
收集物理网格并重排到全局经纬网格。 |
输入
| 输入 |
来源 |
类型 / 维度 |
单位 |
含义 |
ngrid |
调用方 |
integer |
- |
当前物理网格点数。 |
nom, titre, unite |
调用方 |
character |
- |
变量名、说明和单位属性。 |
dim |
调用方 |
integer 0/1/2/3 |
- |
变量维度码。 |
px(ngrid,nbp_lev) |
调用方 |
real array |
variable-dependent |
待写诊断场;低维变量也通过该二维实参承载。 |
diagfi.def |
运行目录可选文件 |
text file |
- |
若存在,仅输出列在其中的变量名。 |
输出
| 输出 |
去向 |
类型 / 维度 |
单位 |
含义 |
diagfi.nc |
当前运行目录 |
NetCDF file |
- |
传统物理诊断文件。 |
Time |
diagfi.nc |
unlimited coordinate |
days |
从 zitau 和 steps_per_sol 派生的输出时间。 |
nom 变量 |
diagfi.nc |
0D/1D/2D/3D |
unite |
由调用方指定的诊断变量。 |
共享状态与副作用
- 例程使用多组
SAVE 且 THREADPRIVATE 状态:firstcall、diagfi_def、nom_def、zitau、ntime、nid、firstnom/lastnom 等。
grid_type==unstructured 时直接 return,传统 diagfi 不处理 unstructured 网格。
diagfi.def 只在第一次调用时由 OpenMP master 读取;变量未列入时直接返回,不参与文件创建和时间推进。
- 3D 或
slow_diagfi=.true. 路径每个输出频率打开/关闭文件;1D 且 slow_diagfi=.false. 时第一次输出打开,最后一次输出关闭。
核心逻辑
- 首次调用读取
diagfi.def,并计算 isample=steps_per_sol/outputs_per_sol 与 lastzitau=(day_end-day_ini)*steps_per_sol-1。
- 若启用
diagfi.def 且当前变量名不在列表中,立即返回。
- 第一次有效变量调用时创建
diagfi.nc,定义 unlimited Time,收集 phisfi/cell_area,调用 iniwrite 写文件头。
- 用
firstnom 判断是否进入新的物理时刻;若当前变量名等于 firstnom,递增 zitau。
- 仅当
MOD(zitau+1,isample)==0 时写出:master 打开文件,首变量追加 Time。
- 根据
dim 创建变量(若尚不存在)并写入 dx3/dx2/dx1/dx0。
- 根据 1D/3D 和
slow_diagfi 策略关闭文件。
伪代码
writediagfi(ngrid, nom, titre, unite, dim, px):
if unstructured grid: return
on first call:
read optional diagfi.def
compute isample and lastzitau
if diagfi.def exists and nom not listed: return
on first valid variable:
create diagfi.nc
define Time
write fixed header with iniwrite
if nom == firstnom:
zitau += 1
if output step:
open diagfi.nc
if nom == firstnom:
ntime += 1
write Time
recast/gather px according to dim
create variable with def_var if needed
write variable at ntime
close file according to slow_diagfi and 1D/3D mode
参与的主题流程
| 主题 |
参与方式 |
| 传统诊断输出 |
write_output_mod 或物理例程直接调用本例程写 diagfi.nc。 |
| 文件初始化 |
首次有效变量调用时调用 iniwrite 写固定坐标和控制字段。 |
| 并行输出 |
并行构建中通过 gather 和 Grid1Dto2D_glo 先集中到 root/master 再写 NetCDF。 |
写法特点
- 变量创建是懒加载:第一次写某个变量时才用
def_var 定义。
firstnom 决定时间步推进,调用顺序必须在每个物理时刻保持一致。
dim=1 在并行模式下直接中止,当前只支持 1D column 非并行写出。
- 所有实际 NetCDF 写入都使用
NF_PUT_VARA_REAL,符合源码注释中“enforce outputs to be real*4”的修改历史。
复现要点
steps_per_sol/outputs_per_sol 必须是合理整数采样关系;否则输出间隔会按整数除法结果运行。
- 如果存在
diagfi.def,未列出的变量不会触发文件创建、变量定义或时间推进。
firstnom 与变量调用顺序绑定,新增诊断变量时不要改变每个物理时刻的首变量顺序。
- 1D
slow_diagfi=.false. 会长时间保持文件打开,异常退出时可能留下未关闭文件。
待确认
diagfi_def/n_nom_def/nom_def 的 THREADPRIVATE 声明在源码中被注释在同一行附近但未完全展开;OpenMP 下这些筛选状态是否所有线程一致需结合编译预处理结果确认。
isample=steps_per_sol/outputs_per_sol 未在本例程内检查整除性;上游配置是否总能保证需结合 conf_phys 页面确认。
相关页面