Exner 函数与 cp(T) 变比热路径

输入范围

dyn3d_common\exner_hyb_m.F90
dyn3d_common\exner_milieu_m.F90
dyn3d_common\cpdet_mod.F90
dyn3dpar\exner_hyb_p_m.F90
dyn3dpar\exner_milieu_p_m.F90

Mars 运行参与度:条件经过。Exner 函数在每个时间步由 COMMON leapfrog 和 MARS phymars/leapfrog_nogcm 调用;cpdet_modtpot2t/t2tpot 在动力和物理耦合中被广泛调用;cpofT 路径由 run.def 配置决定。

页面定位

本页覆盖 Mars 热力学转换的两个核心模块族:Exner 函数计算(exner_hyb vs exner_milieu)和变比热路径(cpdet_mod 中的 cpdettpot2t/t2tpot)。这些模块是 leapfrog 时间步中压力→Exner→温度→位势链路的中间环节。pression 的压力计算由 压力与质量算子 family 覆盖;Exner 的下游使用(geopot)由 动能、Bernoulli、位势涡度与位势高度算子 覆盖。

模块文件一览

模块 串行文件 并行文件 行数 (串/并) 包含子例程
exner_hyb_m exner_hyb_m.F90 exner_hyb_p_m.F90 ~115/~186 exner_hyb / exner_hyb_p
exner_milieu_m exner_milieu_m.F90 exner_milieu_p_m.F90 ~95/~160 exner_milieu / exner_milieu_p
cpdet_mod cpdet_mod.F90 同文件 #ifdef CPP_PARA ~280 (合计) ini_cpdet, cpdet, t2tpot, tpot2t + _p/_glo_p 变体

Exner 函数选择:pressure_exner

leapfrog.F L264-268 按 pressure_exner 逻辑量选择路径:

if (pressure_exner) then
  CALL exner_hyb( ip1jmp1, ps, p, pks, pk, pkf )
else
  CALL exner_milieu( ip1jmp1, ps, p, pks, pk, pkf )
endif

pressure_exner 来自 comvert_mod,由 iniconst 初始化为 disvert_type == 1(标准 hybrid 坐标 → exner_hyb),可通过 getin('pressure_exner', ...) 覆盖。Mars 复杂垂直坐标通常使用 disvert_type != 1,走 exner_milieu 路径。

两个变体的签名完全一致:

SUBROUTINE exner_hyb(ngrid, ps, p, pks, pk, pkf)
SUBROUTINE exner_milieu(ngrid, ps, p, pks, pk, pkf)
  INTEGER ngrid
  REAL ps(ngrid), p(ngrid,llmp1), pks(ngrid), pk(ngrid,llm)
  REAL, optional :: pkf(ngrid,llm)

输入是地表压力 ps 和层界压力 p(由 pression 计算),输出是地表 Exner 函数 pks、各层 Exner 函数 pk 和可选的滤波版本 pkf

exner_hyb — 递归 alpha/beta 法

公式

标准 Exner 函数定义:pk = Cp * (p/preff)^kappa,其中 preff 来自 comvert_mod(参考压力),kappacpp 来自 comconst_mod

exner_hyb 使用 Fr. Hourdin 的递归方法保证能量守恒(总能量/内能/势能比例关系):

  1. Shallow Water 特例llm==1):pks = (cpp/preff)*pspk = 0.5*pks。首调用时检查 kappa==1cpp==r
  2. 地表 Exnerpks(ij) = cpp * (ps(ij)/preff)^kappa
  3. alpha/beta 系数:从顶层(l=llm)向下递归计算。alpha(ij,llm)=0beta(ij,llm)=1/(1+2*kappa)。逐层向下:dellta = p(l)*(1+2k) + p(l+1)*(beta(l+1)-(1+2k))alpha(l) = -p(l+1)/dellta * alpha(l+1)beta(l) = p(l)/dellta
  4. 底层 pkpk(ij,1) = (p(1)*pks - 0.5*alpha(2)*p(2)) / (p(1)*(1+kappa) + 0.5*(beta(2)-(1+2k))*p(2))
  5. 向上递推pk(ij,l) = alpha(ij,l) + beta(ij,l) * pk(ij,l-1),l=2..llm。
  6. 可选滤波:若 present(pkf),复制 pkpkffiltreg(pkf, jmp1, llm, 2, 1, .TRUE., 1)

并行变体

exner_hyb_p_m.F90 使用 USE parallel_lmdz,子域 ijb=ij_begin, ije=ij_end。每个水平循环包裹 !$OMP DO SCHEDULE(STATIC),垂直递归的层间依赖通过 !$OMP BARRIER 同步。firstcall 声明为 !$OMP THREADPRIVATE。滤波用 filtreg_p(pkf, jjb, jje, jmp1, llm, 2, 1, .TRUE., 1)

exner_milieu — 简化中点法(Mars 专用)

公式

源码 WARNING 注释明确:这是 Mars 复杂垂直坐标的专用版本,不满足总能量/内能/势能的比例关系(F. Forget, 2001)。

  1. Shallow Water 特例llm==1):与 exner_hyb 相同。
  2. 地表 Exner:与 exner_hyb 相同,pks(ij) = cpp * (ps(ij)/preff)^kappa
  3. 各层 pk(l=1..llm-1):直接中点公式 pk(ij,l) = cpp * (2*preff)^(-kappa) * (p(l) + p(l+1))^kappa
  4. 顶层外推(l=llm):对数等距外推 pk(ij,llm) = pk(ij,llm-1)^2 / pk(ij,llm-2)
  5. 可选滤波:同 exner_hyb

并行变体

exner_milieu_p_m.F90 结构与 exner_hyb_p 类似,使用 USE parallel_lmdz,子域 + OMP STATIC 循环 + !$OMP THREADPRIVATE(firstcall)。由于 exner_milieu 没有层间递归(每层独立计算),并行化更简单。

cpdet_mod — 变比热模块

ini_cpdet

初始化 nu_venust0_venus(在 comconst_mod 中声明):

if (cpofT) then
    nu_venus = 0.35
    t0_venus = 460.
else
    nu_venus = 0.
    t0_venus = 0.
endif

gcm.F90 L192 / gcm.F L220 / nogcm.F90 L184 在初始化阶段调用。cpofTcontrol_mod 中的逻辑量,由 conf_gcmrun.def 读取(默认 .False.)。

cpdet(t) — 变比热函数

FUNCTION cpdet(t)
  if (cpofT) then
      cpdet = cpp * (t / t0_venus)**nu_venus
  else
      cpdet = cpp
  endif

cpofT=.true. 时,比热随温度变化:cp(T) = cpp * (T/460)^0.35。这是 Venus 厚大气的适配,Mars 通常 cpofT=.false.(常比热)。

leapfrog.F L722 / leapfrog_p.F L1412 中被内联调用,用于 conservative dissipation 修正:dtec = (ecin0-ecin)/cpdet(temp)。在 diagedyn.F L229 中用于诊断能量计算。

tpot2t — 位温→温度

SUBROUTINE tpot2t(npoints, yteta, yt, ypk)
  if (cpofT) then
      yt = yteta**nu_venus + nu_venus * t0_venus**nu_venus * log(ypk/cpp)
      yt = yt**(1./nu_venus)
  else
      yt = yteta * ypk / cpp
  endif

常比热路径:T = theta * pk / cpp(标准 Exner 反变换)。 变比热路径:非线性反演 T = (theta^nu + nu * t0^nu * ln(pk/cpp))^(1/nu)

t2tpot — 温度→位温

SUBROUTINE t2tpot(npoints, yt, yteta, ypk)
  if (cpofT) then
      yteta = yt**nu_venus - nu_venus * t0_venus**nu_venus * log(ypk/cpp)
      yteta = yteta**(1./nu_venus)
  else
      yteta = yt * cpp / ypk
  endif

常比热路径:theta = T * cpp / pk。变比热路径是非线性正变换。

代码中包含一段 "ATMOSPHERE PROFONDE" 深大气修正(ratio_mod = mmm0/mmm(p) 分子量修正),但被 if (1 .EQ. 0) 永久禁用,当前不影响任何活跃路径。

并行变体

cpdet_mod.F90#ifdef CPP_PARA 条件下包含四个并行子例程:

变体 签名 并行方式 用途
tpot2t_p(nlon,nlev,...) 2D 任意切片 OMP DO SCHEDULE(STATIC,OMP_CHUNK)l 维度 calfis_p 物理列
tpot2t_glo_p(...) 3D 全动力网格 iip1×jjp1×llm OMP DOl 维度,jj_begin:jj_end 子域 leapfrog_pvlspltqs_p
t2tpot_p(nlon,nlev,...) 2D 任意切片 tpot2t_p calfis_p 物理列
t2tpot_glo_p(...) 3D 全动力网格 tpot2t_glo_p leapfrog_p conservative 修正

_glo_p 变体使用 #include "dimensions.h"#include "paramet.h" 获取网格维度,直接在完整动力网格上操作,比多次调用 _p 切片更高效。

leapfrog 中的调用链路

每个 leapfrog 时间步中,Exner 和 cp(T) 转换的典型调用顺序:

pression(ip1jmp1, ap, bp, ps, p)           → p 层界压力

if pressure_exner:
  exner_hyb(ip1jmp1, ps, p, pks, pk, pkf)  → pks, pk, pkf
else:
  exner_milieu(ip1jmp1, ps, p, pks, pk, pkf) → pks, pk, pkf

tpot2t(ijp1llm, teta, temp, pk)            → temp 温度
tsurpk = cpp * temp / pk                    → 位势计算用的 teta 替代量
geopot(ip1jmp1, tsurpk, pk, pks, phis, phi) → phi 位势高度

caldyn(ucov,vcov,teta,ps,...,pk,pkf,tsurpk,phis,phi,...)

在耗散守恒修正段中:

tpot2t(ijp1llm, teta, temp, pk)            → temp
covcont → enercin → ecin0                   → 耗散前动能
dissip → ucov+=dudis; vcov+=dvdis
covcont → enercin → ecin                    → 耗散后动能
dtec = (ecin0 - ecin) / cpdet(temp)         → 动能差/变比热
temp += dtec                                 → 温度修正
t2tpot(ijp1llm, temp, ztetaec, pk)          → 位温修正

调用方总览

Exner 函数

调用方 exner_hyb 调用次数 exner_milieu 调用次数 说明
leapfrog.F 4 (L265,534,625,678) 4 (L267,536,627,680) 初始化 + 各时间步
leapfrog_p.F 1+3 (L300,881,1115,1277) 1+3 (L302,883,1117,1279) 同,并行
MARS phymars/leapfrog_nogcm.F 3 (L307,468,640) 3 (L309,470,642) 无耗散但仍需 Exner
guide_mod.F90 1 (L694) 1 (L696) nudging 位势计算
iniacademic.F90 1 (L239) 1 (L241) 学术测试初始化

cpdet_mod 使用方

使用方 USE 导入 用途
gcm.F90/gcm.F/nogcm.F90 ini_cpdet 初始化 nu_venus/t0_venus
leapfrog.F cpdet, tpot2t, t2tpot 耗散修正 + 各时间步 tpot2t + t2tpot
leapfrog_p.F cpdet, tpot2t_glo_p, t2tpot_glo_p 同上,并行全局变体
MARS phymars/leapfrog_nogcm.F cpdet, tpot2t, t2tpot 无耗散但仍有 tpot2t 温度转换
bilan_dyn.F tpot2t 能量诊断
vlspltqs.F/vlspltqs_p.F tpot2t/tpot2t_glo_p Van Leer 分裂
diagedyn.F cpdet, tpot2t 动力诊断
calfis.F/calfis_p.F t2tpot, tpot2t/tpot2t_p, t2tpot_p 物理 tendency 计算

串并行差异汇总

差异项 串行 并行
Exner 模块名 exner_hyb_m / exner_milieu_m exner_hyb_p_m / exner_milieu_p_m
Exner OMP !$OMP DO SCHEDULE(STATIC) + !$OMP BARRIER
Exner 子域 1..ngrid ij_begin..ij_end
Exner firstcall SAVE !$OMP THREADPRIVATE
Exner 滤波 filtreg filtreg_p
tpot2t/t2tpot 单数组 npoints _p 切片 + _glo_p 全网格
tpot2t OMP OMP DO SCHEDULE(STATIC,OMP_CHUNK)
cpdet 函数 直接调用 直接调用(无并行差异)

输入输出数据流

conf_gcm:
  run.def → cpofT (logical)
  iniconst: disvert_type → pressure_exner (logical)

gcm initialization:
  ini_cpdet → nu_venus, t0_venus (comconst_mod)

leapfrog each timestep:
  pression(ap, bp, ps) → p
  if pressure_exner:
    exner_hyb(ps, p) → pks, pk, pkf
  else:
    exner_milieu(ps, p) → pks, pk, pkf
  tpot2t(teta, pk) → temp
  tsurpk = cpp * temp / pk
  geopot(tsurpk, pk, pks, phis) → phi

dissipative correction (if apdiss):
  tpot2t(teta, pk) → temp
  cpdet(temp) → local cp value
  t2tpot(temp, pk) → ztetaec

复现要点

待确认

相关页面