advn 调度顺序、mode 分支和 advtrac 调用关系
输入范围
dyn3d_common\advn.F: L4-139(advn 主例程)
dyn3d_common\advn.F: L141-257(advnqx)
dyn3d_common\advn.F: L258-352(advnqy)
dyn3d_common\advn.F: L354-468(advnqz)
dyn3d_common\advn.F: L470-733(advnx)
dyn3d_common\advn.F: L735-863(advny)
dyn3d_common\advn.F: L865-977(advnz)
dyn3d\advtrac.F90: L250-269(iadv=12/13 调用点)
dyn3dpar\advtrac_p.F90(advn 代码存在但不可达)
Mars 运行参与度:条件经过。advn 是 F. Hourdin 的"pseudo amont"(伪上游)advection 方案,由串行 advtrac 在 iadv=12/13 时调用。当前 infotrac_init 白名单只允许 iadv=10/14/0,因此 Mars 默认配置下 advn 路径不可达。并行 advtrac_p 中 advn 代码存在但被 GOTO 1234 跳过。
例程定位
advn 是 978 行的 Fortran 77 输送方案,包含 7 个子例程。它使用 x-y-z-y-x 五步 directional splitting,每步先做界面重构(advnq*)再做通量更新(advn*)。scheme 有两个 mode:mode=1(分段线性)和 mode=2(抛物线修正),对应 iadv=12 和 iadv=13。
advn 签名
SUBROUTINE advn(q,masse,w,pbaru,pbarv,pdt,mode)| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
q |
real(ip1jmp1,llm) | INOUT | tracer 混合比 |
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 | 时间步长(秒) |
mode |
integer | IN | 1=分段线性,2=抛物线修正 |
预处理
advn 主例程在 split 之前做三项准备:
- 质量通量缩放:
mu = pbaru * 0.5*pdt,mv = pbarv * 0.5*pdt,mw = w * pdt。水平方向用 0.5 系数(leapfrog mid-time-level),垂直方向用 1.0(forward)。 - 极区平均:对每层 l,计算南北极的 mass-weighted 平均 tracer 值
qpn/qps,然后均匀赋给极点所有经度格。 - 工作数组复制:
zq = q, zm = masse,后续 split 在 zq/zm 上操作。
x-y-z-y-x Split 顺序
advn 使用对称五步 split:
1. advnqx → advnx (E-W 重构 + E-W 通量更新)
2. advnqy → advny (N-S 重构 + N-S 通量更新)
3. advnqz → advnz (垂直重构 + 垂直通量更新)
4. advnqy → advny (N-S 重构 + N-S 通量更新)
5. advnqx → advnx (E-W 重构 + E-W 通量更新)
这是经典的 Strang splitting:首尾两步各做半时间步(隐含在 0.5 系数中),中间三步各做全时间步。每步的通量更新同时修改 zq 和 zm(质量和 tracer 都被更新),因此后续步骤基于已更新的场工作。
后处理:q = zq 拷回,做经向周期包裹 q(ij+iim,l) = q(ij,l)。
重构子例程
advnqx:E-W 界面重构
SUBROUTINE advnqx(q,qg,qd)mode=0:一阶,qg=qd=q(平坦重构)。mode=1(默认):4 阶中心加单调约束。- 斜率
dxqu(ij) = q(ij+1) - q(ij) - 界面值
zqu(ij) = 0.5*(q(ij+1)+q(ij)) - 4 阶修正:
zqu -= dxqu(ij+1)/12,zqu += dxqu(ij-1)/12 - 单调约束:clip 到
[min(q(ij),q(ij+1)), max(q(ij),q(ij+1))] - 极值检测:
extremum(ij) = dxqu(ij)*dxqu(ij-1) <= 0 - 极值处:
qg=qd=q(平坦),否则qd=zqu(ij), qg=zqu(ij-1)
- 斜率
输出 qg(gauche=left)和 qd(droite=right)是界面重构值的两侧。
advnqy:N-S 界面重构
SUBROUTINE advnqy(q,qs,qn)结构同 advnqx,但在 N-S 方向。qs(south)和 qn(north)是界面值。
- 4 阶修正:
zqv += (dyqv(ij+iip1)-dyqv(ij-iip1))/12 - 极点处理:极点处不设斜率,
zqv = q。 - 极值检测和单调约束同 advnqx。
advnqz:垂直界面重构
SUBROUTINE advnqz(q,qh,qb)qh(haut=top)和qb(bas=bottom)是垂直界面值。- 4 阶修正:
zqw += (dzqw(ij,l+1)-dzqw(ij,l-1))/12 - 边界:
dzqw(ij,1)=0, dzqw(ij,llm+1)=0(顶部和底部无斜率)。 - 边界界面值:
zqw(ij,2)=q(ij,1), zqw(ij,llm)=q(ij,llm)(边界退化为 1 阶)。 - 极值检测和单调约束同 advnqx。
通量更新子例程
advnx:E-W 通量和更新
SUBROUTINE advnx(q,qg,qd,masse,u_m,mode)核心逻辑:基于重构界面值和质量通量计算 tracer 通量 u_mq,然后更新 q 和 masse。
Sigma 参数:zsigd = (q-qg)/(qd-qg),zsigg = 1-zsigd。若 |qd-qg| < prec(prec=1e-15),退化为 1 阶 zsigd=zsigg=0.5, qd=qg=q。
通量计算(按风向选择上游格点参数):
mode=1(分段线性):zsig <= zsigp:u_mq = u_m * zqpzsig > zsigp:u_mq = sign(zm,u_m) * (zsigp*zqp + (zsig-zsigp)*zqm)
mode=2(抛物线修正):zsig <= zsigp:u_mq = u_m * (zqp - 0.5*zsig/zsigp*(zqp-zq))zsig > zsigp:u_mq = sign(zm,u_m) * (0.5*(zq+zqp)*zsigp + (zsig-zsigp)*(q+zz*(zqm-zq))),其中zz = 0.5*(zsig-zsigp)/zsigm
极区 Semi-Lagrangian(CFL>1):当 |u_m| > masse 时,标记 ladvplus。对这些格点:
- 累加完全穿越格点的全部质量
q*masse。 - 最后部分穿越格点使用 mode 对应的分段线性/抛物线插值。
- 诊断输出穿越格点数量(若
prt_level > 9)。
通量散度更新:
new_m = masse(ij,l) + u_m(ij-1,l) - u_m(ij,l)
q(ij,l)= (q(ij,l)*masse(ij,l) + u_mq(ij-1,l) - u_mq(ij,l)) / new_m
masse(ij,l) = new_m
经向周期包裹:u_mq(ij,l) = u_mq(ij-iim,l) 和 q(ij-iim,l) = q(ij,l)。
advny:N-S 通量和更新
SUBROUTINE advny(q,qs,qn,masse,v_m)结构同 advnx,但使用 zsign/zsigs(north/south 方向)。使用 mode=2 的抛物线通量公式(无 mode 分支)。
极区处理:
convpn = Σ v_mq(j=1) ! 进入北极的总 tracer 通量
convmpn = Σ v_m(j=1) ! 进入北极的总质量通量
new_m = massen + convmpn
q(pole) = (q(pole)*massen + convpn) / new_m
masse(ij) = new_m * aire(ij) / apoln ! 按面积分配
南极类似,使用 ip1jm-iim 行。
advnz:垂直通量和更新
SUBROUTINE advnz(q,qh,qb,masse,w_m)结构同 advnx,使用 zsigb/zsigh(bottom/top 方向,对应 x 的 d/g)。使用 mode=2 的抛物线通量公式。
边界:w_mq(ij,llm+1)=0, w_mq(ij,1)=0(无通量穿过大气顶/底)。
更新:
new_m = masse(ij,l) + w_m(ij,l+1) - w_m(ij,l)
q(ij,l)= (q(ij,l)*masse(ij,l) + w_mq(ij,l+1) - w_mq(ij,l)) / new_m
masse(ij,l) = new_m
advtrac 调用关系
串行路径
advtrac.F90 在 iadv=12 和 iadv=13 时调用 advn:
| iadv | mode | 调用 | 说明 |
|---|---|---|---|
12 |
1 |
call advn(q, massem, wg, pbarug, pbarvg, dtbon, 1) |
分段线性 |
13 |
2 |
call advn(q, massem, wg, pbarug, pbarvg, dtbon, 2) |
抛物线修正 |
两个路径都使用 adaptdt 做自适应子步长,循环 do indice=1,n 调用 advn。
并行路径
advtrac_p.F90 中 advn 的代码存在(PPM 分支之后),但被 GOTO 1234 完全跳过。并行构建中所有 tracer 输送由 vlspltgen_p 处理。
infotrac_init 白名单
当前 infotrac_init 只允许 iadv=10/14/0,因此 iadv=12/13 路径在初始化阶段就会被 abort。advn 在当前 COMMON 中属于历史遗留但未删除的状态,和 PPM 路径类似。
与 vlsplt 和 ppm3d 的关系
| 特征 | advn | vlsplt | ppm3d |
|---|---|---|---|
| Split 顺序 | x-y-z-y-x (5步) | x-y-z-y-x (5步) | x-y-z (3步) |
| 重构方式 | 4阶中心+单调 | Van Leer | PPM 抛物线 |
| 极区 CFL>1 | Semi-Lagrangian 累加 | 无特殊处理 | FFSL 切换 |
| 质量更新 | 内联(同时更新 q 和 masse) | 外部 | 外部(delp1/delp2) |
| mode 参数 | 1/2(线性/抛物线) | 无 | IORD/JORD/KORD |
| 当前可达性 | 不可达(iadv=12/13 被阻止) | 可达(iadv=10/14) | 不可达(iadv=11/16/17/18 被阻止) |
advn 和 vlsplt 使用相同的 x-y-z-y-x Strang splitting,但 advn 的极区处理更复杂(CFL>1 时做 Semi-Lagrangian 累加),且同时更新质量和 tracer(内联守恒),而 vlsplt 使用外部质量场。
复现要点
- advn 的
mode参数在三个重构子例程(advnqx/advnqy/advnqz)中有各自的save mode声明,但这些局部mode固定为 1,不受主例程传入的mode影响。只有 advnx 使用传入的mode做分支。这意味着重构总是 4 阶的,mode 只影响通量计算。 prec精度阈值因平台而异:CRAY 用 1e-24,其他平台用 1e-15(advnx/advny)或 1e-13(advnz)。低于此阈值时退化为 1 阶。- advnx 的 Semi-Lagrangian 累加(L602-705)只在
n0 > 1(有 CFL>1 格点)时执行,且会打印诊断信息。复现时需要prt_level > 9才能看到穿越格点数。 - advny 的极区质量分配使用
aire(ij)/apoln(格点面积与极冠总面积之比),保证极点各经度格的质量按面积比例分配。 - 水平通量缩放 0.5 和垂直通量缩放 1.0 反映了 leapfrog 时间离散:水平风是 mid-time-level 值,垂直通量是 forward 值。
相关页面
待确认
iadv=12/13在 LMDZ 历史版本中是否曾被 Mars 配置使用。- advn 的 mode=1 和 mode=2 在实际 tracer 输送精度上的差异,需要数值实验验证。