concatnc.F90
快速理解
它做什么: 独立命令行程序,把多个 diagfi.nc/concat.nc/stats.nc 沿 Time 维拼接到 concat.nc。
基本过程: stdin 读输入文件列表/时间轴/变量 → 创建 concat.nc → 追加 1D/3D/4D 变量。
关键结果: 统一时间序列 concat.nc,是 util 后处理链第一步。
路径
LMDZ.MARS\util\concatnc.F90
所属目录/模块
util
文件定位
concatnc.F90 是 LMD Mars GCM 输出的 NetCDF 时间拼接工具。它读取多个 diagfi.nc、concat.nc、stats.nc 类文件,把用户选择的时间相关变量沿输出 Time unlimited 维追加到固定输出文件 concat.nc,并复制首个输入文件中的经纬度、高度、垂直坐标、网格面积和地表位势等辅助变量。
本文件是独立命令行 program concatnc,不是 GCM 运行时模块。程序通过 stdin 交互式读取输入文件列表、起始 sol 策略、输出时间轴类型和变量列表;典型用法是 concatnc.e < concatnc.def。它通常位于 util 后处理链第一步,后续结果可交给 zrecast、localtime.F90、lslin.F90 或 extract.F90。
定义的符号
| 符号 | 类型 | 行号 | 作用 |
|---|---|---|---|
concatnc |
program | 1 | 主程序:读取输入文件和变量选择,创建 concat.nc,沿时间轴追加 1D/3D/4D 变量。 |
initiate |
subroutine | 729 | 创建输出 NetCDF,定义 latitude/longitude/altitude/Time/GCM_layers 维度并写坐标变量。 |
init2 |
subroutine | 885 | 从首个输入文件复制 aps/bps、ap/bp、sigma、aire/area、phisinit/phisfi 等静态辅助变量。 |
def_var |
subroutine | 1234 | 在打开的 NetCDF 中定义 float 变量并写 long_name、units 属性。 |
change_time_axis |
subroutine | 1283 | 将输出 Time 从 sol 转为 Ls;adls 模式下新增 Ls 一维变量。 |
sol2ls |
subroutine | 1385 | 用火星轨道近似和 Newton 迭代把 sol 转成太阳经度 Ls。 |
missing_value |
subroutine | 1478 | 将输入变量的 valid_range 和 missing_value 属性复制到输出变量。 |
依赖的模块
| use/include | 用途 |
|---|---|
include "netcdf.inc" |
主程序和所有内部例程使用旧式 NetCDF Fortran NF_* 接口。 |
无 LMDZ 物理模块依赖。程序只操作 NetCDF 文件和 stdin/stdout。
调用的关键例程
| 被调用例程 | 所在位置 | 作用 |
|---|---|---|
NF_OPEN / NF_CREATE / NF_CLOSE |
NetCDF 库 | 打开输入文件,创建 concat.nc,关闭文件。 |
NF_INQ_DIMID / NF_INQ_VARID / NF_INQ_DIMLEN |
NetCDF 库 | 查找 latitude/longitude/altitude/Time/controle 等维度和变量。 |
NF_GET_VAR_REAL / NF_PUT_VARA_REAL |
NetCDF 库 | 读取整块输入变量,并按时间片写入输出变量。 |
initiate |
本文件 | 首个输入文件确定输出坐标和维度后创建输出文件。 |
init2 |
本文件 | 首个输入文件复制垂直坐标、面积和地形辅助量。 |
def_var |
本文件 | 定义输出变量及属性。 |
missing_value |
本文件 | 复制缺测和值域属性。 |
change_time_axis / sol2ls |
本文件 | 在 ls 或 adls 输出模式下转换或新增 Ls 轴。 |
输入
| 输入 | 来源 | 类型/维度 | 单位 | 含义 |
|---|---|---|---|---|
| 输入文件列表 | stdin | 文件名列表,空行结束 | - | 要拼接的 diagfi/concat/stats 类 NetCDF 文件。 |
| 起始时间 | stdin | 数值或非数值输入 | sol | 数值输入时用于设置输出起始 sol;非数值输入时保留第一文件的季节/起点逻辑。源码变量名 firstsol 的注释与提示文字有歧义,见待确认。 |
axis |
stdin | sol / ls / adls |
- | 输出时间轴类型:sol、Ls,或保留 sol 并额外写 Ls。 |
| 变量列表 | stdin | all 或逐行变量名,空行结束 |
- | 要拼接的时间相关变量;坐标/静态变量由 notconcat 排除。 |
latitude/lat |
输入 NetCDF | 1D | degrees_north | 纬度坐标;各输入文件长度必须一致。 |
longitude/lon |
输入 NetCDF | 1D | degrees_east | 经度坐标;各输入文件长度必须一致。 |
altitude |
输入 NetCDF | 1D | 随文件 | 垂直坐标;各输入文件长度必须一致,属性复制到输出。 |
Time/time_counter |
输入 NetCDF | 1D | sol 或文件约定 | 拼接维;输出 Time 为 unlimited。 |
controle |
输入 NetCDF | index 或 controle_axe 维 |
混合 | 可选;存在时用 ctl(4) 和 ctl(27) 计算输出 sol,并在输出中写入重置后的 controle。 |
aps/bps、ap/bp、sigma、aire/area、phisinit/phisfi |
输入 NetCDF | 静态坐标/辅助量 | 随变量 | 首个输入文件复制到输出。 |
输出
| 输出 | 去向 | 类型/维度 | 单位 | 含义 |
|---|---|---|---|---|
concat.nc |
磁盘 | NetCDF | - | 固定输出文件名,NF_CLOBBER 覆盖已有文件。 |
Time |
concat.nc |
unlimited 1D | days 或 degrees | 追加后的时间轴;ls 模式最终写成 Ls,sol/adls 保持 sol。 |
Ls |
concat.nc |
unlimited 1D | degrees | 仅 adls 模式新增;源码通过 change_time_axis 写入。 |
| 用户选择变量 | concat.nc |
1D(Time)、3D(lon,lat,Time) 或 4D(lon,lat,alt,Time) | 随变量 | 从每个输入文件整块读取并按 reptime 追加。 |
| 坐标和静态辅助变量 | concat.nc |
1D/2D | 随变量 | latitude、longitude、altitude、controle、aps/bps、ap/bp 或 sigma、aire、phisinit 等。 |
共享状态与副作用
- 固定输出文件名:
filename="concat.nc",initiate用NF_CLOBBER创建,当前目录中同名文件会被覆盖。 - stdin 交互:输入文件列表、时间策略、
axis和变量列表都通过read(*,...)获取;.def文件必须严格匹配读取顺序。 - stdout 进度与错误提示:程序打印文件打开、时间轴、变量名、Sol 和 NetCDF 错误。
- 硬停止:缺少输入文件、必要坐标、Time 维、请求变量或 NetCDF 写入失败时直接
stop。 - 输出时间状态:
reptime记录已写入时间长度;previous_last_output_time用来处理跨年或文件时间倒退。 - 无线程安全要求:本程序为单进程命令行工具,内部没有 SAVE 缓存或并行状态。
核心逻辑
- 读取输入参数:stdin 读入多个输入文件名;读取起始 sol 策略;打开第一文件,读取变量总数;读取
axis,仅接受sol、ls、adls。 - 筛选候选变量:
notconcat(1:24)排除坐标、控制和静态辅助量,包括Time、controle、latitude/longitude/altitude、aps/bps、ap/bp、aire/area、phisinit/phisfi和 XIOS 时间/边界变量。用户可输入all或逐项变量名。 - 逐输入文件循环:
- 打开文件,读取
latitude/lat、longitude/lon、altitude、可选GCM_layers。 - 查找
index或controle_axe,可用时读取controle并取ctlsol=ctl(4)。 - 查找
Time或time_counter并读取时间数组。
- 打开文件,读取
- 首个文件初始化输出:
- 保存经纬高和
controle长度,用于后续文件兼容性检查。 - 计算
starttimeoffset和previous_last_output_time;有controle时还把输出ctl(4)、ctl(27)置零。 - 调
initiate定义输出维度和坐标;调init2复制垂直坐标与静态辅助量。
- 保存经纬高和
- 后续文件兼容性检查:纬度、经度、高度和
controle长度必须与首文件一致,否则停止。 - 追加 Time:对当前文件每个时间样本计算
output_time。有controle时使用time(rep)+ctlsol-starttimeoffset,若小于上一输出时间则加year_day=669直到连续;无controle时按当前文件时间间隔顺推。 - 追加变量:对每个用户变量查找变量 ID,只接受 1D、3D、4D;按维度构造
dim/corner/edges,首文件定义输出变量并复制long_name/title与units,随后用NF_PUT_VARA_REAL追加数据块。 - 复制缺测属性:若输入变量有
missing_value,调用missing_value复制valid_range和missing_value属性。 - 后处理时间轴:所有文件处理后,如果
axis=="ls"或axis=="adls",调用change_time_axis。sol2ls对每个 sol 做 Ls 转换,并修正相邻 Ls 跨 0/360 度导致的大跳变。
伪代码
program concatnc:
read input file list until blank
read optional startsol; read axis in {sol, ls, adls}
open first file; list variables except notconcat
read variable selection: all or names
filename = "concat.nc"; reptime = 0
for each input file:
open file if not first
read lat/lon/alt, optional GCM_layers
read optional controle from index/controle_axe
read Time or time_counter
if first file:
store reference dimension lengths
compute starttimeoffset and previous_last_output_time
initiate(concat.nc, coordinates, controle, axis)
init2(copy vertical coordinate, area, phisinit)
else:
require lat/lon/alt/controle lengths match first file
for rep in current file Time:
output_time = controle-aware sol, else sequential time
while output_time < previous_last_output_time:
output_time += 669
append output_time at Time(reptime+rep)
for each selected variable:
require ndim in {1,3,4}
build output dimensions and write corner/edges
if first file: define output variable and attributes
read full input variable into var3d
append var3d block to output
copy missing_value/valid_range if present
reptime += timelen
close input file
if axis is ls or adls:
change_time_axis(output)
close output file
参与的主题流程
| 主题 | 参与方式 |
|---|---|
| util 后处理链 | 常作为第一步把多段 GCM 输出合成单个 concat.nc,再交给 zrecast、localtime.F90、lslin.F90 或 extract.F90。 |
| GCM 输出整理 | 保留经纬高、垂直坐标、面积、地形和缺测属性,保证后续 NetCDF 工具仍能识别坐标契约。 |
| 时间轴标准化 | 支持 sol、Ls 和 sol+Ls (adls) 三种输出策略,并处理跨火星年拼接时的时间倒退。 |
写法特点
- 旧式 NetCDF API:全文件使用
include "netcdf.inc"和NF_*接口。 - 固定静态变量排除表:
notconcat(1:24)既跳过经典 diagfi 坐标,也跳过 XIOS 的lat/lon/time_counter/time_instant_bounds/area/phisfi。 - 维度只支持 1D/3D/4D:非这三类变量会被跳过,不能拼接 2D 静态变量;静态量由
init2单独复制。 GCM_layers与altitude分离:若输入来自zrecast,GCM_layers可不同于altlen,用于复制原始 hybrid/sigma 层。adls模式意图:保留Time为 sol,并额外写Ls变量;待确认处见下。
复现要点
.def输入顺序必须是:文件名列表(空行结束)、起始 sol 策略、axis、变量列表(all或逐行变量名,空行结束)。- 所有输入文件的 latitude、longitude、altitude 长度必须一致;
controle有无和长度也必须一致。 - 若输入含
controle,输出controle(4)和controle(27)会被置零,输出Time由time + ctl(4) - starttimeoffset计算。 - 若输入没有
controle,程序使用第一个文件的时间间隔顺推,依赖time(2)-time(1);单时间样本文件可能触碰数组边界,见待确认。 - 输出文件固定为当前目录
concat.nc,批处理前应移动或删除旧文件以避免覆盖。 ls/adls模式下 Ls 换算使用year_day=669、peri_day=485.0、timeperi=1.9082314、e_elips=0.093358。
待确认
- 源码第 167-172 行的
firstsol逻辑与注释/提示文字相反:ierr.eq.0表示读到数值,但打印“使用第一输入文件起始日”;实际公式按数值startsol参与starttimeoffset,页面按公式描述而未判断原意。 change_time_axis在adls分支调用def_var(nout,...)和timedimout,但子程序参数只有nid,ierr,axis;这些名称来自主程序宿主作用域的内部过程 host association。此写法可读性差,移植时需确认编译器接受。init2中phisinit查找失败后尝试phisfi,若两者都失败,源码仍在失败分支后设置phis=.true.;这可能导致未初始化phisinit被写出。需用实际文件和编译器行为确认。- 无
controle分支使用time(2)-time(1)推算首个文件前一时间;当timelen=1时是否越界取决于运行时检查设置。
复现风险
NF_CLOBBER会覆盖已有concat.nc。stop式错误处理会让批处理链在缺坐标、缺变量或维度不匹配时直接终止。- 请求变量必须存在于每个输入文件;任一文件缺变量会停止,不能自动跳过单个文件。
all模式依赖第一输入文件变量清单,后续文件变量集合不同会失败。ls模式把Time内容改为 Ls,部分工具若期待 sol 轴应使用adls或保持sol。
相关页面
- util/index.md - util 后处理工具总览。
- zrecast.md - 常接在
concatnc后,把 hybrid/sigma 垂直坐标转换成物理坐标。 - simu_MCS.md - 下游观测比较工具,可读取
concat.nc类 GCM 输出。 - localtime.F90 - 本地时重排工具。
- lslin.F90 - Ls 线性化重采样工具。
- extract.F90 - 点值/廓线 ASCII 抽取工具。