calldrag_noro_mod.F90
路径
LMDZ.MARS\libf\phymars\calldrag_noro_mod.F90
所属目录 / 模块
libf\phymars
文件定位
calldrag_noro_mod.F90 定义 calldrag_noro_mod 模块和 calldrag_noro 包装例程。它不是重力波拖曳的完整物理核心,而是 physiq_mod.F 中 Lott 地形重力波/次网格地形拖曳方案的调用层:首调用时读取阈值并初始化 sugwd 参数,之后按 dimradmars_mod:ndomainsz 把水平网格切成子域,只对次网格地形标准差 zstd 超过阈值的格点标记调用 drag_noro,最后把 drag_noro 返回的温度、纬向风、经向风增量除以 ptimestep 变成 tendency。
physiq 只在 callkeys_mod:calllott 为真时调用本例程。conf_phys.F 中 calllott 默认 .true.,并通过 getin_p("calllott", calllott) 从 callphys.def 覆盖;它和 calllott_nonoro 是不同开关。本文件名中的 noro 不应直接解读为非地形重力波;源码注释、日志和下游 orodrag 链都表明这里处理的是 orographic GW / subgrid topography drag。
定义的符号
| 符号 |
类型 |
行号 |
作用 |
calldrag_noro_mod |
module |
1 |
封装 Lott 地形重力波拖曳调用层 |
calldrag_noro |
subroutine |
7 |
按子域筛选地形格点,调用 drag_noro 并返回 GW tendency |
依赖的模块
| use 模块 |
only 列表 |
用途 |
待确认 |
surfdat_h |
zstd, zsig, zgam, zthe |
读取次网格地形标准差、坡度、各向异性和主轴角,传给 drag_noro/orodrag 链 |
- |
dimradmars_mod |
ndomainsz |
决定每个子域的最大水平点数和局部数组尺寸 |
- |
drag_noro_mod |
drag_noro |
下游地形重力波拖曳核心包装,内部再调用 ORODRAG |
- |
sugwd_mod |
sugwd |
首调用时根据垂直 sigma 坐标初始化 yoegwd_h 中的 GW 调参常量 |
- |
ioipsl_getin_p_mod |
getin_p |
读取 oro_gwd_zstdthread 配置阈值 |
- |
调用的关键例程
| 被调用例程 |
所在模块 / 文件 |
调用位置 |
作用 |
getin_p |
ioipsl_getin_p_mod |
行 89 |
用 oro_gwd_zstdthread 覆盖默认地形标准差阈值 50.0 |
sugwd |
sugwd_mod.F90 |
行 96 |
初始化 GHMAX, NKTOPG, GKDRAG, GRCRIT 等地形 GW 参数 |
drag_noro |
drag_noro_mod.F90 |
行 165-168 |
对当前子域执行地形 GW 拖曳计算,返回每步增量 |
exit |
运行时 / 编译器提供 |
行 105 |
1D 运行但 ndomainsz /= 1 时中止 |
输入
| 输入 |
来源 |
类型/维度 |
单位 |
含义 |
ngrid |
调用方 physiq |
integer scalar |
- |
物理网格水平列数 |
nlayer |
调用方 physiq |
integer scalar |
- |
大气垂直层数 |
ptimestep |
调用方 physiq |
real scalar |
s |
物理时间步长 |
pplay |
physiq 中的 zplay |
real (ngrid,nlayer) |
Pa |
全层压力;传给下游前按子域复制 |
pplev |
physiq 中的 zplev |
real (ngrid,nlayer+1) |
Pa |
半层压力;首调用时也用于构造 sigtest |
pt |
physiq |
real (ngrid,nlayer) |
K |
全层温度 |
pu |
physiq |
real (ngrid,nlayer) |
m/s |
纬向风 |
pv |
physiq |
real (ngrid,nlayer) |
m/s |
经向风 |
zstd, zsig, zgam, zthe |
surfdat_h |
real allocatable (ngrid) |
mixed |
次网格地形统计量;zstd 用于筛选,四者都传给 drag_noro |
ndomainsz |
dimradmars_mod |
integer scalar |
grid points |
子域水平块大小 |
输出
| 输出 |
去向 |
类型/维度 |
单位 |
含义 |
pdtgw |
physiq:zdtgw 后累加到 pdt |
real (ngrid,nlayer) |
K/s |
地形 GW 对温度的 tendency |
pdugw |
physiq:zdugw 后累加到 pdu |
real (ngrid,nlayer) |
m/s/s |
地形 GW 对纬向风的 tendency |
pdvgw |
physiq:zdvgw 后累加到 pdv |
real (ngrid,nlayer) |
m/s/s |
地形 GW 对经向风的 tendency |
共享状态与副作用
- 首调用时向标准输出打印方案激活和
oro_gwd_zstdthread 数值。
zstdthread, ll, firstcall 为 save 且 THREADPRIVATE,每个 OpenMP 线程保留自己的首调用状态和阈值。
- 调用
getin_p("oro_gwd_zstdthread", zstdthread) 读取配置;默认值是 50.0。
- 调用
sugwd 会写入 yoegwd_h 中的地形 GW 调参常量,例如 NKTOPG, GKDRAG, GRCRIT。
- 1D 运行且
ndomainsz 不是 1 时会打印警告并 exit(1)。
- 本例程自身不写 NetCDF、不分配内存;局部子域数组按
ndomainsz 自动栈数组声明。
核心逻辑
- 首次进入时读取
oro_gwd_zstdthread,用 pplev(1,l)/pplev(1,1) 构造半层 sigma 坐标 sigtest,调用 sugwd(nlayer,sigtest) 初始化 GW 参数。
- 若
ngrid == 1,检查 ndomainsz == 1;否则直接中止,因为 1D 不能使用更大的分块尺寸。
- 每次调用都计算子域数:
ndomain = (ngrid - 1) / ndomainsz + 1
- 对每个子域
jd,计算全局起点 ig0 和当前子域实际点数 nd。
- 在当前子域中按
zstd(ig) > zstdthread 标记 ktest(ig)=1,把局部格点编号写入 kdx,并统计 kgwd;kgwdim = max(1, kgwd) 保证下游接口维度至少为 1。
- 把
pplev, pplay, pt, pu, pv 复制成局部子域数组 zplev, zplay, zt, zu, zv。
- 调用
drag_noro(nd,nlayer,ptimestep,...),传入地形数组切片 zstd(ig0+1), zsig(ig0+1), zgam(ig0+1), zthe(ig0+1) 和筛选结果。
- 将
drag_noro 输出的步长增量 d_t, d_u, d_v 除以 ptimestep,写回全局 tendency 数组。
伪代码
calldrag_noro(ngrid, nlayer, ptimestep, pplay, pplev, pt, pu, pv):
if firstcall:
zstdthread = 50.0
getin_p("oro_gwd_zstdthread", zstdthread)
sigtest(l) = pplev(1,l) / pplev(1,1)
sugwd(nlayer, sigtest)
if ngrid == 1 and ndomainsz != 1:
exit(1)
firstcall = false
ndomain = (ngrid - 1) / ndomainsz + 1
for each subdomain jd:
ig0 = (jd - 1) * ndomainsz
nd = remaining points or ndomainsz
kgwd = 0
for global ig in this subdomain:
ktest(ig) = 0
if zstd(ig) > zstdthread:
ktest(ig) = 1
kgwd = kgwd + 1
kdx(kgwd) = ig - ig0
kgwdim = max(1, kgwd)
copy global pressure, temperature, wind fields into local arrays
drag_noro(nd, nlayer, ptimestep, local fields, local topography, kgwd data,
d_t, d_u, d_v)
for each local level and point:
pdtgw(global,l) = d_t(local,l) / ptimestep
pdugw(global,l) = d_u(local,l) / ptimestep
pdvgw(global,l) = d_v(local,l) / ptimestep
参与的主题流程
| 主题 |
参与方式 |
主物理时间步 physiq |
physiq_mod.F 在 calllott 为真时调用本例程,并把返回的 zdtgw/zdugw/zdvgw 累加到总 tendency |
| 地形重力波 / 次网格地形拖曳 |
本例程按地形标准差筛选格点、组织子域输入,实际拖曳由 drag_noro -> ORODRAG 链完成 |
| 配置系统 |
calllott 控制是否调用;oro_gwd_zstdthread 控制哪些格点进入 GW 计算 |
写法特点
.F90 自由格式模块,但保留较多历史注释和旧 LMD 风格命名。
THREADPRIVATE 用于 firstcall、阈值和临时逻辑变量;并行运行时每个线程会单独完成首调用初始化。
- 子域数组维度固定为
ndomainsz,最后一个子域用实际 nd 避免越界。
- 即使某个子域
kgwd=0,仍会调用 drag_noro;下游 drag_noro 会先把输出增量和 stress 初始化为 0。
- 输出 tendency 没有在本例程入口整体清零;其值完全来自各子域回填。因此每个子域循环必须覆盖对应网格点的所有层。
复现要点
- 必须先保证
surfdat_h 中 zstd/zsig/zgam/zthe 已分配并填入地形统计量;否则筛选和下游参数均无有效输入。
calllott 是本方案进入 physiq 的主开关;calllott_nonoro 控制的是另一套非地形 GW 参数化。
oro_gwd_zstdthread 默认 50.0,只影响是否把格点加入 kgwd/kdx/ktest,不改变地形数组本身。
drag_noro 返回的是每个物理时间步的增量,本例程除以 ptimestep 后才成为 physiq 使用的 tendency;重复实现时不要漏掉这个单位转换。
- 1D 运行需要
ndomainsz=1;源码在 ngrid==1 且 ndomainsz/=1 时直接退出。
sugwd 的参数依赖首列压力构造的 sigtest;垂直层结构变化时,首调用初始化结果也会变化。
待确认
calldrag_noro_mod.F90、drag_noro_mod.F90 和 modules/phymars/index.md 中对 noro 的文字表述不完全一致;本页按源码注释和 physiq 调用段落将其记录为地形 GW / subgrid topography drag。
drag_noro_mod.F90 中若未来取消 ptimestep*pdudt 的乘法,本例程行 173-175 的除法也需要同步复核;当前源码注释已提示这两个动作成对存在。
- 当
zstdthread 设置过高导致 kgwd=0 时,下游 ORODRAG 是否完全跳过所有点由 drag_noro/ORODRAG 的 ktest 逻辑决定;本页只确认 drag_noro 初始化输出为 0。
相关页面