typed getin* 解析约定:scalar/1D/2D integer/real/logical/character
输入范围
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\misc\ioipsl_getincom.F90
LMDZ.COMMON-6.3\LMDZ.COMMON\libf\phy_common\ioipsl_getin_p_mod.F90
本页范围
本页覆盖 ioipsl_getincom.F90 中 12 个 typed getin* specific procedure 和 ioipsl_getin_p_mod.F90 中 11 个 getin_p_* 并行 wrapper 的完整解析约定。getin-fallback-file-precedence 覆盖文件来源和 key 表机制;本页聚焦每个 typed procedure 的签名、tmp 缓冲、2D 线性化、类型特异性和并行 wrapper 差异。
12 个 typed specific procedure 总览
| Procedure | 类型 | 维度 | 行号 | tmp 缓冲策略 |
|---|---|---|---|---|
getinis |
INTEGER | scalar | 122-151 | DIMENSION(1) 栈数组 |
getini1d |
INTEGER | 1D | 153-191 | ALLOCATABLE, SAVE + tmp_ret_size 追踪 |
getini2d |
INTEGER | 2D | 193-248 | ALLOCATABLE, SAVE + 列优先线性化 |
getinrs |
REAL | scalar | 252-281 | DIMENSION(1) 栈数组 |
getinr1d |
REAL | 1D | 283-321 | ALLOCATABLE, SAVE + tmp_ret_size 追踪 |
getinr2d |
REAL | 2D | 323-378 | ALLOCATABLE, SAVE + 列优先线性化 |
getincs |
CHARACTER | scalar | 382-411 | CHARACTER(LEN=100), DIMENSION(1) 栈数组 |
getinc1d |
CHARACTER | 1D | 413-451 | CHARACTER(LEN=100), ALLOCATABLE, SAVE |
getinc2d |
CHARACTER | 2D | 453-508 | CHARACTER(LEN=100), ALLOCATABLE, SAVE + 列优先 |
getinls |
LOGICAL | scalar | 512-541 | DIMENSION(1) 栈数组 |
getinl1d |
LOGICAL | 1D | 543-581 | ALLOCATABLE, SAVE + tmp_ret_size 追踪 |
getinl2d |
LOGICAL | 2D | 583-638 | ALLOCATABLE, SAVE + 列优先线性化 |
所有 12 个 procedure 通过 INTERFACE getin 泛型绑定,调用方只需 CALL getin(target, ret_val) 即可由编译器自动分派。
通用调用模式
所有 typed procedure 遵循相同的 6 步模式:
① get_findkey(i_tab=1, target, pos) ! key_tab 线性查找
② tmp_ret_val ← ret_val ! 保存调用方默认值到 tmp
③ IF (pos < 0) THEN ! key_tab 未命中
④ get_fil(target, status, fileorig, <typed>_val=tmp_ret_val)
⑤ get_wdb(target, status, fileorig, size, <typed>_val=tmp_ret_val)
⑥ ELSE ! key_tab 命中
⑦ get_rdb(pos, size, target, <typed>_val=tmp_ret_val)
⑧ ENDIF
⑨ ret_val ← tmp_ret_val ! 回写到调用方
关键约定点:
ret_val是INTENT(INOUT)(实际为默认 INOUT 语义):调用方传入默认值,若 key 不存在于文件,默认值保留。tmp_ret_val始终作为中间缓冲:避免get_fil/get_rdb直接修改ret_val时出现维度不匹配。- 标量 procedure 使用固定
DIMENSION(1)栈数组;1D/2D 使用ALLOCATABLE, SAVE避免重复分配。
Scalar 约定
标量 procedure(getinis/getinrs/getincs/getinls)使用固定的 DIMENSION(1) tmp 数组:
INTEGER, DIMENSION(1) :: tmp_ret_val ! 或 REAL/CHARACTER(LEN=100)/LOGICAL
tmp_ret_val(1) = ret_val
CALL get_fil(target, status, fileorig, i_val=tmp_ret_val)
ret_val = tmp_ret_val(1)无需动态分配,size_of_in 恒为 1。
1D 约定
1D procedure(getini1d/getinr1d/getinc1d/getinl1d)使用 ALLOCATABLE, SAVE tmp 数组配合 tmp_ret_size 追踪:
INTEGER, DIMENSION(:), ALLOCATABLE, SAVE :: tmp_ret_val
INTEGER, SAVE :: tmp_ret_size = 0
!-
size_of_in = SIZE(ret_val)
IF (.NOT.ALLOCATED(tmp_ret_val)) THEN
ALLOCATE(tmp_ret_val(size_of_in))
ELSE IF (size_of_in > tmp_ret_size) THEN
DEALLOCATE(tmp_ret_val)
ALLOCATE(tmp_ret_val(size_of_in))
tmp_ret_size = size_of_in
ENDIF
tmp_ret_val(1:size_of_in) = ret_val(1:size_of_in)约定要点:
SAVE属性使 tmp 数组在调用间存活,避免每调用一次都重新分配。- 只在
size_of_in > tmp_ret_size时扩容(不缩容),保留历史最大尺寸。 - 数组复制使用
tmp_ret_val(1:size_of_in) = ret_val(1:size_of_in),按元素复制而非整体赋值。
2D 约定与列优先线性化
2D procedure(getini2d/getinr2d/getinc2d/getinl2d)需要额外的维度处理:
INTEGER :: size_1, size_2, jl, jj, ji
size_of_in = SIZE(ret_val) ! 总元素数 = size_1 * size_2
size_1 = SIZE(ret_val, 1) ! 第一维
size_2 = SIZE(ret_val, 2) ! 第二维2D → 1D 线性化采用 Fortran 列优先顺序:
! 2D → 1D(写入前)
jl = 0
DO jj = 1, size_2
DO ji = 1, size_1
jl = jl + 1
tmp_ret_val(jl) = ret_val(ji, jj)
ENDDO
ENDDO
! 1D → 2D(读回后)
jl = 0
DO jj = 1, size_2
DO ji = 1, size_1
jl = jl + 1
ret_val(ji, jj) = tmp_ret_val(jl)
ENDDO
ENDDO这意味着 2D key 在 .def 文件中的向量元素按列优先排列:key__00001 对应 (1,1),key__00002 对应 (2,1)(假设 size_1 >= 2),以此类推。
类型特异性
get_qtyp 类型检测
所有底层子程序(get_fil、get_wdb、get_rdb)通过 get_qtyp 检测实际传入的 OPTIONAL 参数类型:
k_typ = 0
IF (COUNT([PRESENT(i_v), PRESENT(r_v), PRESENT(c_v), PRESENT(l_v)]) /= 1) THEN
CALL ipslerr(3, 'get_qtyp', 'Invalid number of optional arguments', '(/= 1)', ' ')
ENDIF
IF (PRESENT(i_v)) THEN; k_typ = k_i; c_vtyp = 'INTEGER'
ELSEIF (PRESENT(r_v)) THEN; k_typ = k_r; c_vtyp = 'REAL'
ELSEIF (PRESENT(c_v)) THEN; k_typ = k_c; c_vtyp = 'CHARACTER'
ELSEIF (PRESENT(l_v)) THEN; k_typ = k_l; c_vtyp = 'LOGICAL'
ENDIF必须且只能有一个 typed OPTIONAL 参数被传入。get_qtyp 同时返回类型码和名称字符串(用于错误消息)。
INTEGER 特异性
- 文件解析使用格式化 READ:
READ(str, FMT='(I<len>)') - 支持压缩字段(
MINVAL == MAXVAL且size > 20) get_rdb类型检查:key_tab(pos)%keytype /= k_i时 fatal
REAL 特异性
- 文件解析使用自由格式 READ:
READ(str, FMT=*) - 支持压缩字段(同 INTEGER)
get_rdb类型检查:key_tab(pos)%keytype /= k_r时 fatal
CHARACTER 特异性
- 文件解析直接截取:
c_val(it) = str_READ(1:len_str),不做格式转换 - 不支持压缩(
get_wdb中l_cmp = .FALSE.for CHARACTER) - 内部存储固定
CHARACTER(LEN=100),调用方接口为CHARACTER(LEN=*) - 这意味着超过 100 字符的字符串会被截断
get_rdb类型检查:key_tab(pos)%keytype /= k_c时 fatal- 无
getinc2d在并行 wrapper 中:getin_p只有getincs_p(scalar)和getinc1d_p(1D),没有 2D character wrapper
LOGICAL 特异性
- 文件解析通过关键字匹配:搜索
"tru"或"y"→.TRUE.;"fal"或"n"→.FALSE. - 大小写不敏感(先转
strlowercase) - 不匹配时
io_err = 100→ fatal - 不支持压缩(
get_wdb中l_cmp = .FALSE.for LOGICAL) get_rdb类型检查:key_tab(pos)%keytype /= k_l时 fatal
压缩字段类型限制
| 类型 | 支持压缩 | 原因 |
|---|---|---|
| INTEGER | 是 | MINVAL/MAXVAL 可比较 |
| REAL | 是 | MINVAL/MAXVAL 可比较 |
| CHARACTER | 否 | 字符串无自然序比较 |
| LOGICAL | 否 | 布尔值无自然数值比较 |
压缩条件:所有元素相同(MINVAL == MAXVAL)且 元素数 > compress_lim=20。满足时 keycompress = size_of_in、keymemlen = 1。
getin_p 并行 wrapper 对照
ioipsl_getin_p_mod.F90 提供 11 个并行 wrapper(无 character 2D):
| Wrapper | 对应 getin | bcast 方式 |
|---|---|---|
getinrs_p |
getinrs |
bcast(VarOut) 标量 |
getinr1d_p |
getinr1d |
bcast(VarOut) 整体 |
getinr2d_p |
getinr2d |
bcast(VarOut) 整体 |
getinis_p |
getinis |
bcast(VarOut) 标量 |
getini1d_p |
getini1d |
bcast(VarOut) 整体 |
getini2d_p |
getini2d |
bcast(VarOut) 整体 |
getincs_p |
getincs |
bcast(VarOut) 标量 |
getinc1d_p |
getinc1d |
逐元素 bcast(VarOut(i)) |
getinls_p |
getinls |
bcast(VarOut) 标量 |
getinl1d_p |
getinl1d |
bcast(VarOut) 整体 |
getinl2d_p |
getinl2d |
bcast(VarOut) 整体 |
每个 wrapper 的模式:
!$OMP BARRIER
IF (is_master) THEN
CALL getin(VarIn, VarOut)
ENDIF
CALL bcast(VarOut)character 1D 逐元素 bcast
getinc1d_p 是唯一不直接整体 bcast 的 wrapper:
DO i = 1, size(VarOut)
CALL bcast(VarOut(i))
ENDDO原因:Fortran CHARACTER(LEN=*) 数组的内存布局可能不连续(每个元素有独立的长度描述符),不能安全地作为单一 buffer 广播。
缺失的 getinc2d_p
基础 getin 接口有 getinc2d(character 2D),但 getin_p 没有对应的 getinc2d_p。如果并行上下文需要读取 2D character 配置,需要手动实现 master-read + 逐元素 bcast。
默认值保留语义
所有 typed procedure 在进入文件解析前,先将 ret_val 复制到 tmp_ret_val。这意味着:
- 若 key 在文件中不存在(
get_fil返回status=2),tmp_ret_val保持调用方原始默认值。 - 对于向量 key,部分找到的元素被文件值覆盖,未找到的保留默认值(
status=3)。 "def"或"default"作为 value 时,该元素被视为未找到,保留默认值。
调用方模式:
INTEGER :: niter = 100 ! 默认值 100
CALL getin('niter', niter) ! 若 run.def 中有 niter=200,则 niter=200
! 若 run.def 中无 niter,则 niter=100(保留默认)类型不匹配错误
get_rdb 在从 key 表读取时校验类型:
IF (key_tab(pos)%keytype /= k_typ) THEN
CALL ipslerr(3, 'get_rdb', &
'Wrong data type for keyword '//TRIM(target), &
'(NOT '//TRIM(c_vtyp)//')', ' ')
ENDIF如果同一 key 名第一次被 INTEGER getin 写入 key_tab(keytype=k_i),后续用 REAL getin 读取同一 key 会触发 fatal error。这要求调用方对同一 key 始终使用相同类型。
数组长度不匹配错误
get_rdb 同时校验数组长度:
! 非压缩字段
IF (key_tab(pos)%keymemlen /= size_of_in) THEN
CALL ipslerr(3, 'get_rdb', 'Wrong array length', 'for keyword '//TRIM(target), ' ')
ENDIF
! 压缩字段
IF (key_tab(pos)%keycompress /= size_of_in .OR. key_tab(pos)%keymemlen /= 1) THEN
CALL ipslerr(3, 'get_rdb', 'Wrong compression length', 'for keyword '//TRIM(target), ' ')
ENDIF调用方数组大小必须与首次写入时的大小一致。
Mars 侧典型使用
phymars/conf_phys.F:大量getin_p调用读取物理配置(ecritphy、outputs_per_sol、iphysiq、tauvis、callrad、water、co2clouds等),以 scalar 和 1D 为主。phymars/aeropacity_mod.F、watercloud_mod.F、initracer.F90:getin_p读取微物理和 tracer 参数。dyn3d/conf_gcm.F90、dyn3dpar/conf_gcm.F90:直接使用getin(非_p),以 scalar 和 1D integer/real/logical 为主。- 2D getin 使用较少,主要用于网格相关的初始化参数。