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 运行参与度:条件经过vlspltvlspltqs 是串行 advtraciadv=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
endif

x-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 中,父子处理的完整顺序是:

  1. 计算 masseqRatio
  2. 递归调用同方向子例程对 Ratio 做输送
  3. 更新父 tracer 的 qmasse
  4. 用更新后的父 q 乘以 Ratio 恢复子 tracer

注意:步骤 1-2 在父 tracer 更新之前执行,步骤 4 在父 tracer 更新之后执行。这确保了比例是在父 tracer 旧场上计算的,恢复时使用新场。

nqdesc vs nqfils

代码中有一个微妙区别:

这意味着如果有孙代 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
ENDDO

FOEEW 是饱和水汽压函数,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 在通量计算后对 qmin(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(...)),开发时取消注释可追踪输送过程中的极值变化。

复现要点

  1. qpereminmasseqmin 是防止除零的关键阈值。qperemin 控制父 tracer 多小时不再计算比例(设为 0),masseqmin 控制质量下限。两者的值由 infotrac_init 设定。
  2. nqdescnqfils 的区别很重要:nqdesc 是所有后代数(用于批量计算 Ratio 和恢复),nqfils 是直接子代数(用于递归调用)。如果 tracer 家族有多层嵌套,这两者的值不同。
  3. vlxqs/vlyqs 使用与 vlx/vly 相同的 Van Leer 斜率限制,但额外做 qsat 裁剪。这意味着饱和 tracer 在水平方向可能被截断,而垂直方向不会(vlz 共享)。
  4. vlspltqs 的 tpot2t 调用将位温转换为温度用于 qsat 计算。这依赖 cpdet_modcp(T) 变比热路径。
  5. 父子比例输送假设比值在输送中守恒。如果物理过程(如凝结)改变了比值,这个假设在下一步输送中可能导致不一致。

相关页面

待确认