vlsplt 串行父子 tracer 和饱和路径
输入范围
dyn3d\vlsplt.F: L1-139(vlsplt 主例程)
dyn3d\vlsplt.F: L140-519(vlx,含父子递归)
dyn3d\vlsplt.F: L520-888(vly,含父子递归)
dyn3d\vlsplt.F: L889-1060(vlz,含父子递归)
dyn3d\vlsplt.F: L1091-1135(minmaxq 诊断)
dyn3d\vlspltqs.F: L1-178(vlspltqs 主例程)
dyn3d\vlspltqs.F: L179+(vlxqs)
dyn3d_common\infotrac.F90(nqdesc/iqfils/nqfils/qperemin/masseqmin)
Mars 运行参与度:条件经过。vlsplt 和 vlspltqs 是串行 advtrac 中 iadv=10(Van Leer)路径的核心输送例程。本页聚焦父子 tracer 比例输送机制和饱和水汽路径。split 内核细节详见 vlsplt-serial-split-kernels。
例程定位
vlsplt 系列实现了串行 Van Leer 输送,包含两个主入口:vlsplt(非饱和 tracer)和 vlspltqs(饱和水汽 tracer)。两者共享 x-y-z-y-x 五步 directional splitting,但 vlspltqs 额外做饱和混合比裁剪。三个方向子例程(vlx/vly/vlz)都是 RECURSIVE 的,支持父子 tracer 的比例输送。
vlsplt 签名
SUBROUTINE vlsplt(q,pente_max,masse,w,pbaru,pbarv,pdt,iq)
USE infotrac, ONLY: nqtot,nqdesc,iqfils| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
q |
real(ip1jmp1,llm,nqtot) | INOUT | tracer 混合比(含所有 tracer) |
pente_max |
real | IN | 斜率限制因子(通常 2,0=上游格式) |
masse |
real(ip1jmp1,llm) | INOUT | 格点空气质量 |
w |
real(ip1jmp1,llm) | IN | 垂直质量通量 |
pbaru |
real(ip1jmp1,llm) | IN | E-W 质量通量 |
pbarv |
real(ip1jm,llm) | IN | N-S 质量通量 |
pdt |
real | IN | 时间步长(秒) |
iq |
integer | IN | 当前 tracer 索引 |
vlsplt 主例程流程
通量缩放
zzpbar = 0.5 * pdt ! 水平半时间步
zzw = pdt ! 垂直全时间步
mu = pbaru * zzpbar
mv = pbarv * zzpbar
mw = w * zzw
mw(:,llm+1) = 0. ! 顶部无通量工作数组复制
CALL SCOPY(ijp1llm, q(:,:,iq), 1, zq(:,:,iq), 1)
CALL SCOPY(ijp1llm, masse, 1, zm(:,:,iq), 1)
! 父子 tracer:也复制子 tracer
if (nqdesc(iq) > 0) then
do ifils = 1, nqdesc(iq)
iq2 = iqfils(ifils,iq)
CALL SCOPY(ijp1llm, q(:,:,iq2), 1, zq(:,:,iq2), 1)
enddo
endifx-y-z-y-x Split
call vlx(zq, pente_max, zm, mu, iq) ! E-W
call vly(zq, pente_max, zm, mv, iq) ! N-S
call vlz(zq, pente_max, zm, mw, iq) ! 垂直
call vly(zq, pente_max, zm, mv, iq) ! N-S
call vlx(zq, pente_max, zm, mu, iq) ! E-W
结果回写
q(:,:,iq) = zq(:,:,iq)
! 经向周期包裹
q(ij+iim,l,iq) = q(ij,l,iq)
! 父子 tracer:也回写子 tracer
if (nqdesc(iq) > 0) then ... endif父子 tracer 比例输送
机制概述
vlsplt 的父子 tracer 输送基于比例守恒假设:子 tracer 与父 tracer 的混合比比值在输送过程中保持不变。这使得子 tracer 不需要独立做通量计算,只需在父 tracer 更新后按比例恢复。
核心变量(来自 infotrac)
| 变量 | 说明 |
|---|---|
nqdesc(iq) |
父 tracer iq 的后代总数(含子、孙等) |
nqfils(iq) |
父 tracer iq 的直接子代数 |
iqfils(ifils,iq) |
父 tracer iq 的第 ifils 个子代的索引 |
qperemin |
父 tracer 混合比最小阈值(低于此值不计算比例) |
masseqmin |
质量最小阈值(防止除零) |
比例计算(在 vlx/vly/vlz 中统一模式)
在父 tracer 的通量更新之前,为每个子 tracer 计算:
! 父 tracer 的 tracer 质量(带下限保护)
masseq(ij,l,iq2) = max(masse(ij,l,iq) * q(ij,l,iq), masseqmin)
! 子/父比例(父 tracer 太小时置零)
if (q(ij,l,iq) > qperemin) then
Ratio(ij,l,iq2) = q(ij,l,iq2) / q(ij,l,iq)
else
Ratio(ij,l,iq2) = 0.
endif递归输送
子 tracer 不直接做通量计算,而是对 Ratio 场做递归输送,使用父 tracer 的 tracer 质量 masseq 作为质量场:
do ifils = 1, nqfils(iq)
iq2 = iqfils(ifils,iq)
call vlx(Ratio, pente_max, masseq, u_mq, iq2) ! 对比例做输送
enddo比例恢复
父 tracer 更新后,子 tracer 按比例恢复:
do ifils = 1, nqdesc(iq)
iq2 = iqfils(ifils,iq)
q(ij,l,iq2) = q(ij,l,iq) * Ratio(ij,l,iq2)
enddo执行顺序
在 vlx/vly/vlz 中,父子处理的完整顺序是:
- 计算
masseq和Ratio - 递归调用同方向子例程对
Ratio做输送 - 更新父 tracer 的
q和masse - 用更新后的父
q乘以Ratio恢复子 tracer
注意:步骤 1-2 在父 tracer 更新之前执行,步骤 4 在父 tracer 更新之后执行。这确保了比例是在父 tracer 旧场上计算的,恢复时使用新场。
nqdesc vs nqfils
代码中有一个微妙区别:
nqdesc(iq)用于计算masseq/Ratio和最终恢复(覆盖所有后代)nqfils(iq)用于递归调用(仅直接子代)
这意味着如果有孙代 tracer,它们的 masseq/Ratio 由祖父层计算,但递归调用只沿直接父子链传递。
vlspltqs 饱和路径
签名
SUBROUTINE vlspltqs(q,pente_max,masse,w,pbaru,pbarv,pdt,
p,pk,teta,iq)
USE infotrac, ONLY: nqtot,nqdesc,iqfils额外参数:p(压力界面)、pk(Exner 函数)、teta(位温)。
饱和混合比计算
call tpot2t(ip1jmp1*llm, teta, tempe, pk) ! 位温→温度
DO l = 1, llm
DO ij = 1, ip1jmp1
zdelta = MAX(0., SIGN(1., rtt - tempe(ij,l)))
play = 0.5*(p(ij,l)+p(ij,l+1))
qsat(ij,l) = MIN(0.5, r2es*FOEEW(tempe(ij,l),zdelta)/play)
qsat(ij,l) = qsat(ij,l) / (1. - retv*qsat(ij,l))
ENDDO
ENDDOFOEEW 是饱和水汽压函数,zdelta 区分液态/冰面公式。qsat 被限制在 0.5 以下。
Split 顺序
call vlxqs(zq, pente_max, zm, mu, qsat, iq) ! E-W + qsat 裁剪
call vlyqs(zq, pente_max, zm, mv, qsat, iq) ! N-S + qsat 裁剪
call vlz(zq, pente_max, zm, mw, iq) ! 垂直(共享 vlsplt 的 vlz)
call vlyqs(zq, pente_max, zm, mv, qsat, iq) ! N-S + qsat 裁剪
call vlxqs(zq, pente_max, zm, mu, qsat, iq) ! E-W + qsat 裁剪
vlxqs/vlyqs 在通量计算后对 q 做 min(q, qsat) 裁剪,防止超过饱和。vlz 不做饱和裁剪(垂直方向由物理过程处理凝结)。
vlsplt vs vlspltqs 对比
| 特征 | vlsplt | vlspltqs |
|---|---|---|
| 水平子例程 | vlx/vly | vlxqs/vlyqs |
| 垂直子例程 | vlz(共享) | vlz(共享) |
| 饱和裁剪 | 无 | vlxqs/vlyqs 中 qsat 限制 |
| 额外参数 | 无 | p, pk, teta |
| 父子 tracer | 支持(递归) | 支持(同机制) |
| 温度依赖 | 无 | tpot2t 位温→温度 |
| 调用方 | advtrac(iadv=10 非饱和) | advtrac(iadv=10 饱和 tracer) |
minmaxq 诊断
subroutine minmaxq(zq,qmin,qmax,comment)可选的诊断子例程,检查 tracer 值是否超出 [qmin, qmax] 范围。受 #ifdef isminismax 编译保护。在 vlsplt 主例程中以注释形式调用(c call minmaxq(...)),开发时取消注释可追踪输送过程中的极值变化。
复现要点
qperemin和masseqmin是防止除零的关键阈值。qperemin控制父 tracer 多小时不再计算比例(设为 0),masseqmin控制质量下限。两者的值由infotrac_init设定。nqdesc和nqfils的区别很重要:nqdesc是所有后代数(用于批量计算 Ratio 和恢复),nqfils是直接子代数(用于递归调用)。如果 tracer 家族有多层嵌套,这两者的值不同。- vlxqs/vlyqs 使用与 vlx/vly 相同的 Van Leer 斜率限制,但额外做 qsat 裁剪。这意味着饱和 tracer 在水平方向可能被截断,而垂直方向不会(vlz 共享)。
- vlspltqs 的
tpot2t调用将位温转换为温度用于 qsat 计算。这依赖cpdet_mod的cp(T)变比热路径。 - 父子比例输送假设比值在输送中守恒。如果物理过程(如凝结)改变了比值,这个假设在下一步输送中可能导致不一致。
相关页面
待确认
- Mars 配置中是否有父子 tracer 对(
nqdesc > 0),还是所有 tracer 都是独立的。 qperemin和masseqmin的具体默认值,需要查看infotrac_init的设定。