soilwater.F90
路径
LMDZ.MARS\libf\phymars\soilwater.F90
所属目录/模块
libf/phymars
文件定位
地下水/吸附水/地下冰储库的一维垂直求解器。计算 regolith(风化层)内从地表到约 18 m 深处(layer(nsoil))的水汽、吸附水、地下冰三相剖面,并返回地下与大气之间的水汽通量 zdqsdifrego,作为 vdifc 计算大气水汽垂直廓线的下边界条件。同时计算地表冰与地下的交换。
只在 callphys.def 中 adsorption_soil=.true. 且 water=.true. 时由 vdifc 调用。需要在 traceur.def 定义三个地下 tracer:h2o_vap_soil(地下水汽)、h2o_ice_soil(地下冰)、h2o_ads_vap(吸附水)。
本文件是单个自由格式的 subroutine(无 module 封装),作者 Pierre-Yves Meslin,Lucas Lange 清理。
定义的符号
| 符号 | 类型 | 行号 | 作用 |
|---|---|---|---|
soilwater |
subroutine | 1 | 地下水汽/吸附水/冰的吸附-扩散-相变一维求解器 |
依赖的模块
| use 模块 | only 列表 | 用途 | 待确认 |
|---|---|---|---|
comsoil_h |
igcm_h2o_vap_soil, igcm_h2o_ice_soil, igcm_h2o_vap_ads, layer, mlayer, choice_ads, porosity_reg, ads_const_D, ads_massive_ice |
地下 tracer 索引、层深、吸附方案开关、孔隙率 | |
comcstfi_h |
pi, r |
圆周率、干空气气体常数 | |
tracer_mod |
igcm_h2o_vap |
大气水汽 tracer 索引 | |
surfdat_h |
watercaptag |
永久极冠标记(极冠点跳过 regolith 计算) | |
geometry_mod |
cell_area, latitude_deg |
网格面积(全球质量统计)、纬度 | 待确认:latitude_deg 在主体未见使用 |
write_output_mod |
write_output |
诊断输出(#ifndef MESOSCALE) |
调用的关键例程
| 被调用例程 | 所在模块/文件 | 调用位置 | 作用 |
|---|---|---|---|
write_output |
write_output_mod |
行 1218-1226 | 输出地下通量、冰饱和度、水/冰柱质量等诊断字段 |
本例程不调用其他物理子程序,是一个自包含的数值求解器。
输入
| 输入 | 来源 | 类型/维度 | 单位 | 含义 |
|---|---|---|---|---|
ngrid |
vdifc | INT | - | 格点数(调用时为 1,逐点调用) |
nlayer |
vdifc | INT | - | 大气层数 |
nq |
vdifc | INT | - | 大气 tracer 数 |
nsoil |
vdifc | INT | - | 地下层数 |
nqsoil |
vdifc | INT | - | 地下 tracer 数(=3) |
ptsrf |
vdifc (ztsrf) |
REAL (ngrid) | K | 地表温度 |
ptsoil |
vdifc (ptsoil(ig,:,islope)) |
REAL (ngrid,nsoil) | K | 地下各层温度 |
ptimestep |
vdifc (subtimestep) |
REAL | s | 子时间步长 |
exchange |
vdifc | LOGICAL (ngrid) | - | 当前步是否与大气交换水汽 |
qsat_surf |
vdifc (qsat) |
REAL (ngrid) | kg/kg | 地表温度下的饱和混合比 |
pq |
vdifc (zq_tmp_vap) |
REAL (ngrid,nlayer,nq) | kg/kg | 大气 tracer 混合比 |
pa,pb,pc,pd |
vdifc (za/zb/zc/zd) |
REAL (ngrid,nlayer) | - | vdifc 隐式扩散三对角系数 |
pdqsdifpot |
vdifc (zdqsdif_surf) |
REAL (ngrid) | kg/m²/s | 不含地下交换的潜在地表通量 |
pplev |
vdifc | REAL (ngrid,nlayer+1) | Pa | 大气压力层界 |
rhoatmo |
vdifc (rho) |
REAL (ngrid) | kg/m³ | 第一层大气密度(当前未实际使用) |
writeoutput |
vdifc | LOGICAL | - | 是否为最后子步(触发输出) |
pqsurf |
vdifc (zqsurf) |
REAL (ngrid) | kg/m² | 地表水冰量(intent(in)) |
输出
| 输出 | 去向 | 类型/维度 | 单位 | 含义 |
|---|---|---|---|---|
pqsoil |
vdifc (qsoil) |
REAL (ngrid,nsoil,nqsoil) | 见下 | 地下三相 tracer(inout):水汽(kg/m³孔隙气)、冰、吸附水(kg/m³regolith) |
zdqsdifrego |
vdifc (zdqsdif_regolith) |
REAL (ngrid) | kg/m²/s | 地下→大气水汽通量(正=向外) |
zq1temp2 |
vdifc (zq1temp_regolith) |
REAL (ngrid) | kg/kg | 交换后地表上方临时水汽混合比 |
saturation_water_ice |
vdifc (pore_icefraction) |
REAL*8 (ngrid,nsoil) | - | 孔隙水冰饱和度(孔隙被冰填充的体积分数) |
共享状态与副作用
- SAVE allocatable 数组:
znsoil(地下水汽浓度)、ice(地下冰)、adswater(吸附水)、ztot1、porosity_ice_free、porosity、tortuosity、D0、zalpha、zbeta、meshsize、rho_soil、cste_ads、H2O、H2O_depth、close_top、close_bottom、over_mono_sat_flag、interlayer_dz、midlayer_dz。首次调用allocate,跨时间步保留。 - SAVE 标量:
firstcall_soil、adswater_sat_mono、n(调用计数)。 - firstcall_soil:初始化层间距、孔隙率、密度、吸附单层饱和值,从
pqsoil读入冰/水汽/吸附水初值。 pqsoil原位更新(行 1158-1160):把求解后的znsoil/ice/adswater写回。- 诊断输出(
writeoutput=.true.且非 MESOSCALE):flux_soillayer、ice_saturation_soil、mass_h2o_soil、mass_ice_soil、znsoil、nsatsoil、nsurf、adswater、flux_rego。 - 不收敛即
stop:升华循环 >100 次直接stop(行 610、898)——硬终止程序。 - 大量
print:单层饱和、负冰、闭合/重开等都会打印到 stdout。
核心逻辑
分配 + 首次初始化(行 242-364):分配 SAVE 数组;逐点逐层设置
midlayer_dz/interlayer_dz、porosity_ice_free(ads_massive_ice时冰超tol_massiveice=50kg/m³ 的格点设孔隙率 0.999999)、tortuosity=1.5、rho_soil=1300、meshsize=5e-6、D0=porosity/tortuosity;从pqsoil读入三相初值;算saturation_water_ice和porosity。massive ice 孔隙率更新(行 366-377):每步根据当前冰量重置
porosity_ice_free。扩散系数(行 382-458,跳过
watercaptag极冠点):saturation_water_ice = ice/(rho_H2O_ice*porosity_ice_free),封顶 0.999。- 热速度
vth、H2O-CO2 碰撞积分omega(Mellon & Jakosky 1993)、分子扩散Dm、Knudsen 扩散Dk。 - 中层
D_mid = D0*(1-Sw)²/(1/Dm+1/Dk)(Meslin 2010 饱和度依赖);ads_const_D时用default_diffcoeff=4e-4。 - 层间
D_inter由中层值插值;闭合标志close_*时层间饱和度设 0.999。
吸附/解吸系数(行 463-549):按
choice_ads(1=固定 D0,2=2020 修正 DeltaQ,0=无吸附)算平衡吸附系数k_ads_eq、吸附/解吸时间常数Ka/Kd,及单层饱和后的第二段Ka2/Kd2(双线性吸附等温线)。算C/E/F/E2/F2系数;保存上一步znsoilprev/adswprev/iceprev;算总量ztot1。主求解循环(行 554-1098,逐点,跳过极冠):
- 算地表层
delta0/alpha0/beta0(耦合 vdifc 系数和地表冰pqsurf)。 - 升华外循环(
while sublimation_flag,行 604):- 单层饱和内循环(
while recompute_all_cells_ads_flag,行 618):自上而下算三对角系数zdelta/zalpha/zbeta(有冰层固定为饱和nsatsoil),底层显式解znsoil(nsoil),再自下而上回代解各层znsoil和adswater_temp;检查每层是否越过单层饱和adswater_sat_mono,越界则切换 A/B 系数段并标记整列重算。 - 算层间通量
flux、dztot1;做凝结/升华:有冰层用ice=ztot1+dztot1*dt-porosity*nsatsoil,冰耗尽则清零并重启升华循环;过饱和无冰层则置冰标志重启。
- 单层饱和内循环(
- 地表通量(行 839-852):
exchange时zdqsdifrego由 vdifc 系数耦合算出;否则按地表冰用D_mid梯度算。 - 特例(行 860-1085):无交换且地表冰不足以供应整个时间步时,改用通量边界条件,把剩余地表冰全部升华转入地下(重跑一遍带
znsoilprev2的求解)。 - 更新
ztot1/h2otot。
- 算地表层
choke 闭合检测(行 1100-1138):冰饱和度超
choke_fraction=0.8时,按层间通量方向设close_top/close_bottom(阻止进一步扩散);冰量回落则重开。质量统计 + 写回(行 1140-1186):算每点水柱/冰柱质量;把
znsoil/ice/adswater写回pqsoil;极冠点saturation_water_ice=-1;exch数值化。全球总量 + 输出(行 1188-1228):全球水/冰质量;
n+1;重排flux后写诊断。
伪代码
soilwater(... pqsoil[inout], zdqsdifrego[out], zq1temp2[out], saturation_water_ice[out]):
if .not.allocated: allocate SAVE arrays
if firstcall_soil:
设层间距、孔隙率、密度、meshsize、D0
adswater_sat_mono = 2.6998e-7 * S * rho_soil
从 pqsoil 读 znsoil/ice/adswater 初值
if ads_massive_ice: 按冰量更新 porosity_ice_free
for ig (跳过 watercaptag 极冠):
for ik: Sw = ice/(rho_ice*porosity_free); porosity = porosity_free*(1-Sw)
算 vth, omega, Dm, Dk, D_mid, D_inter (饱和度依赖扩散)
按 choice_ads 算 Ka/Kd/Ka2/Kd2, k_ads_eq, C/E/F/E2/F2
保存 znsoilprev/adswprev/iceprev; ztot1 = porosity*znsoil + ice
算地表层 delta0/alpha0/beta0 (耦合 vdifc 的 pa..pd 和 pqsurf)
while sublimation_flag:
while recompute_all_cells_ads_flag: // 单层饱和迭代
自上而下: zdelta/zalpha/zbeta (有冰层固定 nsatsoil)
底层显式 znsoil(nsoil)
自下而上回代: znsoil(ik), adswater_temp(ik)
if adswater_temp 越过/回落单层饱和: 切 A/B 段, 标记整列重算
算 flux, dztot1
凝结/升华: 有冰 ice = ztot1+dztot1*dt - porosity*nsatsoil
冰耗尽 -> 清零 + 重启; 过饱和无冰 -> 置冰标志 + 重启
if exchange: zq1temp2 = beta0 + alpha0*znsoil(1)/rho
zdqsdifrego = porosity_free*pb(1)/dt*(zq1temp2 - znsoil(1)/rho)
else: zdqsdifrego = D_mid(1)/midlayer_dz(0)*(znsoil(1) - qsat_surf*rhosurf)
if 无交换 且 地表冰不足供应整步: // 特例
zdqsdifrego = -(pqsurf + pdqsdifpot*dt)/dt
重跑求解 (用 znsoilprev2), 把剩余地表冰转入地下
更新 ztot1, h2otot
choke 检测: Sw > 0.8 -> close_top/close_bottom 按通量方向
写回 pqsoil = (znsoil, ice, adswater)
算质量, 写诊断输出
参与的主题流程
| 主题 | 参与方式 |
|---|---|
| 水循环 (water-cycle) | 地下储库:regolith 吸附水/地下冰与大气水汽交换,提供 vdifc 下边界通量 |
| 水循环主题页 | 主题入口 |
写法特点
- 自由格式 Fortran 90,但为裸
subroutine(无 module 封装)——与多数_mod.F90不同。 - SAVE allocatable + 首调用分配:跨时间步保留地下状态,无显式 deallocate。
- 嵌套 while 迭代:外层升华/凝结相变循环套内层单层吸附饱和迭代,二者均靠标志位驱动重算。
- 双线性吸附等温线(2020 新增):单层饱和
adswater_sat_mono前后用两套系数(E/FvsE2/F2),模拟 Type II/III 等温线。 - 隐式三对角求解:
zalpha/zbeta系数自上而下递推、znsoil自下而上回代(Thomas 算法变体),与 vdifc 大气扩散系数耦合。 - 不收敛硬
stop:升华迭代 >100 次直接终止程序(行 610、898)。 - 大量硬编码常数:见复现要点。
复现要点
- 仅
adsorption_soil=.true.时被调用;choice_ads选吸附方案(0/1/2)。 - 三个地下 tracer 必须在
traceur.def定义:h2o_vap_soil/h2o_ice_soil/h2o_ads_vap,对应igcm_h2o_vap_soil=1/igcm_h2o_ice_soil=2/igcm_h2o_vap_ads=3(comsoil_h固定)。 - 关键硬编码常数:
kinetic_factor=0.01、choke_fraction=0.8、tol_massiveice=50、enthalpy_ads=35e3、enthalpy_ads2=21e3、DeltaQ_ads=DeltaQ_ads2=21e3、S=17e3、Sm=10.6e-20、Dk0=0.459、tau0=1e-14、rho_H2O_ice=920、default_diffcoeff=4e-4、porosity_reg=0.45(comsoil_h)。 choice_ads==2用Kref=0.205e-6、Kref2=0.108e-7(Pommerol 2009 拟合);adswater_sat_mono=2.6998e-7*S*rho_soil。- 饱和压力用
P_sat_soil=611*exp(22.5*(1-273.16/T))(行 585)——内置 Clausius-Clapeyron 近似,不调用watersat。 tortuosity=1.5、rho_soil=1300 kg/m³、meshsize=5e-6 m在 firstcall 硬编码,注释提示可改为自定义剖面。- 地表层
delta0/alpha0/beta0耦合 vdifc 的pa/pb/pc/pd系数——必须与 vdifc 的隐式扩散方案配套,单独看本文件无法复现边界条件。 vdifc以ngrid=1逐点、逐坡面(islope)调用本例程(vdifc_mod.F:1052)。
待确认
choice_ads在comsoil_h声明为real,但本文件用== 1/2/0整数比较——浮点等值比较,依赖 conf 阶段赋整值;注释又称"3 means no adsorption",与代码里 0 表示无吸附不符(注释疑过时)。rhoatmo形参注释标"not used right now"(行 76)——传入但未实际使用。latitude_deg、H2O/H2O_depth/latH2O等 H2O 地图变量已声明,firstcall 仅打印"initializing H2O data"但未见实际读图插值代码——可能为半完成/遗留功能。nref/Kd_ref/Ka_ref标注"not used anymore/for the time being"。cste_ads、H2O、H2O_depth已分配但主体未见赋值/使用。
复现风险
- 升华或特例升华迭代 >100 次会
stop,整个 GCM 终止——极端条件下可能中断长积分。 znsoilprev(ig,ik)=ztot1/porosity_prev(行 816)注释自标"Watch out! could go wrong"——冰耗尽时的水汽回填可能不稳定。- 浮点
choice_ads等值比较在不同编译器/优化下有风险。 firstcall_soil的 SAVE 数组在多 islope/MPI 分块下的初始化一致性需注意(无 OMP THREADPRIVATE 标注本文件 SAVE 变量)。
相关页面
- vdifc-water-surface-exchange — vdifc 水汽地表交换段 - 唯一调用方(
adsorption_soil分支) - water-saturation-helpers — 水饱和与凝结温度 - 大气侧饱和(本文件用内置 Clausius-Clapeyron)
- comsoil_h — 地下层定义与吸附开关,提供
igcm_h2o_vap_soil/igcm_h2o_ice_soil/igcm_h2o_vap_ads/layer/mlayer/choice_ads/porosity_reg/ads_const_D/ads_massive_ice - soil — 土壤热扩散求解器,提供
tsoil温度场 - soil_settings — 土壤初始化设置,读取
tsoil/qsoil初值 - 水循环配置页-
adsorption_soil/choice_ads/ads_*开关 - 水循环主题页