Mars utility NetCDF 和 COMMON helper 边界
源码范围:
LMDZ.MARS\libf\dynphy_lonlat\phymars\datareadnc.FLMDZ.MARS\libf\dynphy_lonlat\phymars\newstart.FLMDZ.MARS\libf\dynphy_lonlat\phymars\start2archive.FLMDZ.MARS\libf\dynphy_lonlat\phymars\ini_archive.FLMDZ.MARS\libf\dynphy_lonlat\phymars\write_archive.FLMDZ.MARS\libf\dynphy_lonlat\phymars\readhead_NC.FLMDZ.MARS\libf\dynphy_lonlat\phymars\lect_start_archive.F- COMMON helper:
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\misc\netcdf95.F90、handle_err_m.F90、new_unit_m.F90、ioipsl_getincom.F90
本文只说明 Mars utility 的 NetCDF 读写方式、COMMON helper 的真实边界和复现排错顺序;start/restart/archive 文件职责见 Mars start/restart/archive 边界,COMMON 状态恢复见 Mars utility COMMON 状态使用链路。
结论
Mars newstart/start2archive/archive 工具链没有直接使用 COMMON netcdf95 聚合模块,也没有直接调用 handle_err_m 或 new_unit_m。这些 Mars utility 主要通过:
include "netcdf.inc"
-> NF_OPEN / NF_CREATE
-> NF_INQ_* / NF_GET_* / NF_PUT_*
-> 手写 ierr 检查
-> write/print + stop 或 call abort
COMMON netcdf95 wrapper 的 nf95_* -> handle_err -> abort_physic 语义只适用于实际调用 nf95_* 的 COMMON 代码,例如 dynredem/dynredem_p 写 restart、guide_mod/guide_p_mod 写 guide 系数。不要把这套错误处理自动套到 Mars archive utility 的 NF_* 调用上。
直接 COMMON helper 交集主要是 getin:datareadnc.F 通过 getin("datadir",datadir) 定位 surface.nc,1D/testphys1d 路径通过 getin 读取列模式配置。NetCDF archive 读写本身仍是 Mars 侧 F77 NetCDF API 和 Mars 侧 helper 组合。
参与者对照
| 文件或模块 | NetCDF/helper 使用 | 错误处理 | 复现关注点 |
|---|---|---|---|
datareadnc.F |
include "netcdf.inc";NF_OPEN 读 surface.nc;NF_INQ_VARID 和 NF_GET_VAR_DOUBLE/REAL 读经纬度与 surface 变量;getin("datadir") 覆盖数据目录。 |
缺变量或读取失败时 write(*,*) 后 stop。 |
datadir、surface.nc 路径、变量名、单/双精度 build。 |
newstart.F |
NF_OPEN 打开 start_archive.nc 或 start.nc/startfi.nc;读取 controle 后进入 lect_start_archive 或 dynetat0/phyetat0。 |
多处手写 ierr 检查、stop 或 call abort。 |
输入选择、controle 是否存在、archive 分支与 start/startfi 分支的关闭和后续写出。 |
start2archive.F |
NF_OPEN 读 startfi.nc 控制表;NF_OPEN(...,NF_WRITE) 或 NF_CREATE 写 start_archive.nc;写 Time 后调用 ini_archive/write_archive。 |
CALL abort、NF_STRERROR(ierr) + stop。 |
startfi.nc 可读、archive 是否可写、Time unlimited 维和追加位置。 |
ini_archive.F |
定义 archive 维度、变量和属性,写 controle、经纬度、垂直坐标和固定字段。 |
每段写操作局部检查;不经过 handle_err_m。 |
header 变量完整性、controle 前 50/后 50 段和垂直坐标变量。 |
write_archive.F |
先 NF_INQ_VARID,缺变量时查维度并调用 Mars def_var,再 NF_PUT_VARA_DOUBLE/REAL 按 Time 写。 |
打印 NF_STRERROR(ierr) 后 call abort。 |
懒定义变量、维度匹配、def_var 是 Mars helper 而非 COMMON wrapper。 |
readhead_NC.F |
NF_OPEN 读 archive header、controle、经纬度、aps/bps 等。 |
严格缺字段时 PRINT* + CALL abort 或 STOP。 |
文件维度必须匹配当前编译维度;header 缺项通常不是 fallback。 |
lect_start_archive.F |
大量 NF_INQ_DIMID/DIMLEN/VARID 和 NF_GET_VAR* 读取 archive 变量,再插值/缩放。 |
缺字段按变量语义分为 fallback、默认或 abort。 | 旧 archive 兼容逻辑集中在此处,不能外推到所有 header 读取器。 |
COMMON netcdf95 |
nf95_open/create/def/get/put/att/close wrapper,供 COMMON 调用者使用。 |
未传 ncerr 时调用 handle_err,可关闭 ncid 后 abort_physic。 |
只对 nf95_* 调用生效;Mars utility NF_* 不进入此链。 |
COMMON new_unit_m |
new_unit 从 unit=0 开始 INQUIRE,找存在且未打开的 Fortran unit。 |
无 NetCDF 错误处理。 | 当前源码没有 10..99 上限;不要沿用旧描述。 |
datareadnc.F 的输入链
datareadnc.F 是 Mars surface 数据读取入口。它从 datafile_mod 取默认 datadir="/u/lmdz/WWW/planets/mars/datadir",随后调用 getin("datadir",datadir) 允许 .def 文件覆盖路径,再打开 surface.nc。
读取顺序可按以下方式复现:
- 确认运行目录或配置文件能让
getin看到datadir;没有配置时使用源码默认路径。 - 确认
surface.nc存在,并包含latitude、longitude和所需 surface 变量。 - 代码按
NC_DOUBLE编译分支选择NF_GET_VAR_DOUBLE或NF_GET_VAR_REAL。 - 读取后的 360x180 数据补周期列,再经 dyn3d/interp_horiz 映射到当前动力网格。
这里唯一直接 COMMON 配置 helper 是 ioipsl_getincom:getin。NetCDF 读取本身不走 netcdf95,所以缺变量时表现为局部 write 和 stop,不是 abort_physic("NetCDF95 handle_err",...)。
newstart.F 的两条 NetCDF 入口
newstart.F 先由用户选择输入类型:
start_archive.nc:NF_OPEN(...,NF_NOWRITE,nid),读取 archive 的controle,再由tabfi读物理控制段,后续调用lect_start_archive插值到当前网格。start.nc+startfi.nc:分别NF_OPEN(...,nid_dyn)和NF_OPEN(...,nid_fi)读两个controle,然后调dynetat0/phyetat0恢复动力和物理状态。
复现时要把 NF_OPEN 层的“文件是否可打开”和后续恢复层分开排查。newstart 读到 controle 之后,还会重建 comconst_mod/comvert_mod/geometry_mod 等 COMMON 状态;因此 NetCDF 文件存在并不等于状态已经可写 restart。
start2archive.F、ini_archive.F 和 write_archive.F
start2archive.F 是写 archive 的顶层:
startfi.nc controle
-> dynetat0/phyetat0 恢复 start/startfi
-> gr_fi_dyn 把物理字段转回动力 scalar 网格
-> NF_OPEN start_archive.nc for write
-> 若不存在则 NF_CREATE + ini_archive
-> 写 Time
-> write_archive 按字段追加
ini_archive.F 定义固定 header、坐标和垂直坐标变量。write_archive.F 负责按时间记录追加字段;如果字段不存在,它会调用 Mars 侧 def_var 定义变量。这是 Mars archive helper,不是 COMMON nf95_def_var。
复现写出失败时,优先检查:
startfi.nc的controle能否读取。- 当前目录对
start_archive.nc是否有写权限,已有文件是否可NF_WRITE打开。 Time维和变量是否已由ini_archive定义。write_archive要写的变量维度是否和def_var分支匹配。
readhead_NC.F 和 lect_start_archive.F
readhead_NC.F 是相对严格的 header 读取器:读取 controle 后检查 im/jm/lllm 是否匹配当前编译维度,再读取经纬度、面积、地形和 aps/bps 等固定字段。缺关键字段时通常直接 CALL abort 或 STOP。
lect_start_archive.F 更像兼容层。它读取旧 archive 的维度、垂直坐标和变量,判断是否需要水平/垂直插值,并对部分缺失变量提供 fallback 或默认行为。这个兼容性属于 archive 重建路径,不能推广为所有 NF_GET_* 调用都可以容错。
COMMON netcdf95 的边界
COMMON netcdf95.F90 聚合 simple、nf95_def_var_m、nf95_get_var_m、nf95_put_var_m、attribute wrapper 和 handle_err_m。调用方若不传可选 ncerr,wrapper 会在底层 nf90_* 返回错误时进入:
handle_err(message,ncerr,ncid,varid)
-> print message and nf90_strerror
-> optional nf90_close(ncid)
-> abort_physic("NetCDF95 handle_err","",1)
这条链在 COMMON dynredem/dynredem_p、guide_mod/guide_p_mod 等 nf95_* 调用点成立。Mars utility 的 include "netcdf.inc" + NF_* 调用点不会自动进入这条链;其错误消息和终止方式取决于每个 Mars 文件自己的 ierr 分支。
复现检查清单
排查 Mars utility NetCDF 问题时,按实际路径分流:
datareadncsurface 输入:检查datadir、surface.nc、latitude/longitude和 surface 变量名。newstartarchive 输入:检查start_archive.nc、controle、tabfi物理控制段、lect_start_archive缺字段日志。newstartstart/startfi 输入:检查start.nc与startfi.nc都存在且各自controle可读;再看dynetat0/phyetat0选择的Time。start2archive写出:检查startfi.nc控制表、start_archive.nc写权限、Time维和write_archive变量定义。- COMMON wrapper 报错:只有看到
nf95_*或NetCDF95 handle_err上下文时,才按netcdf95wrapper 链排查。
风险和待确认
- 本页为静态源码确认,未运行真实
start_archive.nc/start.nc/startfi.nc/surface.nc样例。 newstart.F对nid_dyn/nid_fi的关闭路径未作为本页主结论;如排查文件句柄泄漏,需要单独跟踪所有分支。lect_start_archive.F对缺失变量的容错粒度很细,本页只给边界说明;具体变量缺失行为需按变量名回到源码分支确认。