gwprofil_mod.F90
路径
LMDZ.MARS\libf\phymars\gwprofil_mod.F90
所属目录 / 模块
libf\phymars
文件定位
gwprofil_mod.F90 定义 gwprofil_mod 模块和 GWPROFIL 子程序,是 orodrag_mod.F90::ORODRAG 中地形重力波参数化链的应力廓线重算步骤。上游 GWSTRESS 已给出低层或初始的 ZTAU,本例程沿垂直半层从高层向低层扫描,按 IKNU2、临界层 ICRIT、波 Richardson 数和 GRCRIT 破碎阈值改写 ZTAU(:,jk),最后在阻塞层顶 IKENVH 与动力混合高度 IKCRITH 之间做压力线性插值。
它不计算风、温度 tendency,也不读取配置;下游 ORODRAG 用本例程返回的 ZTAU 垂直差分来计算 pdudt/pdvdt/pdtdt。源文件注释把本例程称为 stress profile for gravity waves,并说明其源自 Lott/IFS 地形重力波拖曳方案。
定义的符号
| 符号 |
类型 |
行号 |
作用 |
gwprofil_mod |
module |
1 |
封装地形重力波 stress profile 计算例程。 |
GWPROFIL |
subroutine |
7 |
根据阻塞层、临界层、稳定度和波破碎判据重算 ZTAU 半层应力廓线。 |
依赖的模块
| use 模块 |
only 列表 |
用途 |
待确认 |
dimradmars_mod |
ndomainsz |
固定局部子域数组第一维;kdx 把 kgwd 个有效地形 GW 点映射回 1..ndomainsz。 |
- |
yoegwd_h |
gkdrag, grcrit, gssec, gtsec |
gkdrag 进入 ZNORM stress 归一化;grcrit 是波 Richardson 数破碎阈值;gssec/gtsec 是除零和小 stress 保护阈值。 |
- |
调用的关键例程
| 被调用例程 |
所在模块 / 文件 |
调用位置 |
作用 |
| 无 |
- |
- |
本例程只使用内在函数 sqrt、max、min 和数组循环,不调用其他用户例程。 |
输入
| 输入 |
来源 |
类型/维度 |
单位 |
含义 |
ngrid |
ORODRAG |
integer scalar |
grid points |
大气列数;本例程接口保留但源码内未使用。 |
nlayer |
ORODRAG |
integer scalar |
layers |
大气全层数;半层数组使用 nlayer+1。 |
kgwd |
calldrag_noro -> drag_noro -> ORODRAG |
integer scalar |
points |
当前子域中进入地形 GW 计算的格点数。 |
kdx |
calldrag_noro 筛选结果 |
integer (ndomainsz) |
- |
第 ji 个 GW 点在局部子域中的格点编号 jl。 |
ktest |
calldrag_noro 筛选结果 |
integer (ndomainsz) |
- |
GW 点开关图;接口保留但源码内未读取。 |
IKCRITH |
OROSETUP |
integer (ndomainsz) |
level index |
重力波破碎的动力混合高度。 |
ICRIT |
OROSETUP |
integer (ndomainsz) |
level index |
地形重力波遇到临界层的位置。 |
IKENVH |
OROSETUP |
integer (ndomainsz) |
level index |
阻塞层顶。 |
IKNU |
OROSETUP |
integer (ndomainsz) |
level index |
4*pvar 对应层;本例程只用来缓存 ZTAU(:,IKNU+1)。 |
IKNU2 |
OROSETUP |
integer (ndomainsz) |
level index |
3*pvar 对应层;控制从高层常值段转入递推段。 |
pplev |
drag_noro 传入的翻转半层压力 |
real (ndomainsz,nlayer+1) |
Pa |
半层压力;末段用于在 IKCRITH 到 IKENVH 之间压力线性插值 ZTAU。 |
ZRHO |
OROSETUP |
real (ndomainsz,nlayer+1) |
kg/m3,按上游语义 |
半层密度,用于 ZNORM。 |
BV |
OROSETUP |
real (ndomainsz,nlayer+1) |
s-1,按上游语义 |
Brunt-Vaisala 频率,用于 ZNORM 和波位移。 |
ZVPH |
OROSETUP |
real (ndomainsz,nlayer+1) |
m/s,按上游语义 |
半层低层风速或相位速度尺度,用于 ZALFA。 |
PRI |
OROSETUP |
real (ndomainsz,nlayer+1) |
- |
半层平均流 Richardson 数。 |
zdmod |
OROSETUP |
real (ndomainsz) |
- |
地形各向异性组合幅度;参与 zoro。 |
psig |
surfdat_h:zsig 经上游传入 |
real (ndomainsz) |
- |
次网格坡度。 |
pvar |
surfdat_h:zstd 经上游传入 |
real (ndomainsz) |
m |
次网格地形标准差;参与 zoro 并用 max(pvar,1.0) 保护。 |
输出
| 输出 |
去向 |
类型/维度 |
单位 |
含义 |
ZTAU |
返回 ORODRAG |
real (ndomainsz,nlayer+1), intent(inout) |
stress,按上游 GW 链语义 |
地形重力波半层应力廓线;输入来自 GWSTRESS,输出被 ORODRAG 用于风和温度 tendency。 |
共享状态与副作用
- 本文件没有
save 变量、COMMON、THREADPRIVATE、文件 I/O、配置读取或诊断输出。
- 唯一副作用是原地改写
ZTAU。调用方必须先让 GWSTRESS 或等效步骤初始化 ZTAU,否则本例程会在 ZTAU(JL,IKNU+1)、ZTAU(JL,nlayer+1) 和递推段读取未定义输入。
ngrid 与 ktest 是接口参数但在当前源码中未使用;实际循环只覆盖 ji=1..kgwd 对应的 jl=kdx(ji)。
- 局部数组
Z_TAU 只在若干索引处赋值,随后只读取这些已赋值位置:IKNU+1 当前源码未再读取,nlayer+1 用于高层常值段,IKENVH/IKCRITH 用于末段插值。
核心逻辑
- 令
ilevh=nlayer/3,但该变量只出现在注释掉的打印片段中,不影响计算。
- 对每个 GW 点
jl=kdx(ji),计算地形尺度:
zoro = psig * zdmod / 4 / max(pvar,1.0)
- 缓存
ZTAU(jl,IKNU(jl)+1) 与顶半层 ZTAU(jl,nlayer+1) 到 Z_TAU。
- 从
jk=nlayer 向 2 递减扫描半层。
- 当
jk >= IKNU2(jl) 时,把 ZTAU(jl,jk) 设为顶半层缓存 Z_TAU(jl,nlayer+1),形成上部常值 stress 段。
- 当
jk < IKNU2(jl) 时,计算局地归一化量与上一半层波位移:
ZNORM = gkdrag * ZRHO * sqrt(BV) * ZVPH * zoro
ZDZ2 = ZTAU(jl,jk+1) / max(ZNORM, gssec)
- 对
jk < IKNU2(jl) 的层,如果上一层 stress 小于 gtsec 或已到/低于临界层 jk <= ICRIT(jl),直接把 ZTAU(jl,jk)=0。
- 否则用
PRI、BV、ZDZ2 和 ZVPH 计算波 Richardson 数 ZRIW。若 ZRIW < GRCRIT,按二次方程根得到新的 ZALPHA 和 ZDZ2N,用 ZNORM*ZDZ2N 限制破碎后的 stress;否则沿用 ZNORM*ZDZ2。
- 每层递推末尾执行
ZTAU(jl,jk)=min(ZTAU(jl,jk), ZTAU(jl,jk+1)),保证向下递推时 stress 不超过上一半层。
- 扫描完成后,缓存
IKENVH 与 IKCRITH 两处的 ZTAU。
- 对
jk=1..nlayer,若 IKCRITH(jl) < jk < IKENVH(jl),按压力差在两个缓存 stress 之间线性插值,重新组织低层破碎时的 stress profile。
伪代码
GWPROFIL(..., ZTAU):
for each active GW point jl = kdx(ji):
zoro(jl) = psig(jl) * zdmod(jl) / 4 / max(pvar(jl), 1)
cache top stress Z_TAU(jl,nlayer+1)
for jk from nlayer down to 2:
for each active point jl:
if jk >= IKNU2(jl):
ZTAU(jl,jk) = cached_top_stress
for each active point jl:
if jk < IKNU2(jl):
ZNORM = gkdrag * ZRHO(jl,jk) * sqrt(BV(jl,jk)) * ZVPH(jl,jk) * zoro(jl)
ZDZ2 = ZTAU(jl,jk+1) / max(ZNORM, gssec)
for each active point jl:
if jk < IKNU2(jl):
if ZTAU(jl,jk+1) < gtsec or jk <= ICRIT(jl):
ZTAU(jl,jk) = 0
else:
compute wave Richardson number ZRIW
if ZRIW < grcrit:
solve limited displacement ZDZ2N
ZTAU(jl,jk) = ZNORM * ZDZ2N
else:
ZTAU(jl,jk) = ZNORM * ZDZ2
ZTAU(jl,jk) = min(ZTAU(jl,jk), ZTAU(jl,jk+1))
for each active point jl:
cache ZTAU at IKENVH and IKCRITH
for jk in 1..nlayer:
for each active point jl:
if IKCRITH(jl) < jk < IKENVH(jl):
interpolate ZTAU linearly in pressure between IKENVH and IKCRITH
参与的主题流程
| 主题 |
参与方式 |
| 地形重力波 / 次网格地形拖曳 |
calldrag_noro 筛选地形格点,drag_noro 调用 ORODRAG,ORODRAG 调用本例程重算应力廓线,然后用 ZTAU 垂直差分生成风和温度 tendency。 |
主物理时间步 physiq |
physiq_mod.F 在 calllott 为真时进入 calldrag_noro 链;本例程是该链内部的 stress profile 环节。 |
| 垂直坐标 / 层序转换 |
调用前 drag_noro 已翻转垂直层序;因此本文中的 jk 与注释里的高低层含义要按 ORODRAG 接口层序理解。 |
写法特点
.F90 自由格式模块,但保留 ECMWF/IFS 历史标签式注释和未使用的 CONTINUE 标签。
- 接口里有若干历史保留或注释掉的参数,例如
IKCRIT、ZTAUf、ZTFR、znu、pgam;当前可执行接口没有这些参数。
ngrid、ktest、ilevh 和格式标签 99 在当前源码路径中不参与计算。
ZTAU 是 intent(inout),不是纯输出;复现时必须保留上游 GWSTRESS 对 ZTAU 的初始化顺序。
- 源码在
ZALFA=SQRT(BV*ZDZ2)/ZVPH、ZRIW 和插值分母 ZDELPT 处未额外检查负值或零分母,依赖上游 OROSETUP/GWSTRESS 给出物理一致的层索引和正值。
复现要点
- 必须按
kdx(1:kgwd) 遍历局部点;不能对 1..ngrid 或 1..ndomainsz 全量格点直接套用,否则会改变未筛选格点的 ZTAU。
IKNU2 把应力廓线分成上部常值段和下部递推段;临界层 ICRIT 会把其下方或到达临界层的 stress 置零。
ZNORM 使用 max(ZNORM, gssec) 防止除零,但 sqrt(BV) 仍要求 BV 非负。
- 破碎判据使用
ZRIW < GRCRIT,不是 <=;触发后通过二次方程根重新计算受限位移。
- 末段压力插值只作用在严格满足
IKCRITH < jk < IKENVH 的层;两个端点层本身使用此前缓存的 ZTAU。
待确认
IKNU(jl)+1 被缓存到 Z_TAU 但当前源码没有再读取;保留它可能来自旧 IFS 版本或调试路径,需结合历史版本确认。
ZTAU(jl,jk+1) < GTSEC 时置零的物理含义按“stress 太小则截断”记录;具体阈值量纲来自 yoegwd_h 与 sugwd 初始化,需在对应专页继续核验。
ZDELPT=pplev(IKCRITH)-pplev(IKENVH) 未做零保护;若上游层索引重合或压力序异常,会影响插值复现。
相关页面