Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions src/RootDepth.jl
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ function rootdepth_main(
qlatflux = zeros(Float64, nzg + 2)

wtd_old = wtd[i, j]
dθ = zeros(Float64, nzg) # pre-initialize so line 260 can access it outside the itime loop

# 时间子循环
for itime in 1:round(Int, steps)
Expand All @@ -182,13 +183,13 @@ function rootdepth_main(
et_c_daily[i, j] += pet_c - watdef * 1.0e3

# 土壤水流计算
# updated_o18, transpo18step
# updated_o18, transpo18step (isotope tracking removed)
et_s_step, runoff, rechstep, flux_step, qrfcorrect, updated_smoi =
soilfluxes(nzg, Δt / steps, z₋ₕ, dz, soiltxt[1, i, j],
θ_wtd[i, j],
dθ, dsmoideep, θ[:, i, j], wtd[i, j], ppdrip_step, pet_s,
fdepth[i, j], qlatstep, qrfstep, floodstep, icefac
; freedrain
; freedrain=Bool(freedrain)
)
# θ_eq[:, i, j], o18[:, i, j], o18ratiopp[i, j], tempsfc[i, j],
# qlato18step, transpo18step
Expand All @@ -198,14 +199,14 @@ function rootdepth_main(
qsrun[i, j] += max(runoff - floodstep, 0.0) # m
rech[i, j] += rechstep * 1.0e3
et_s[i, j] += et_s_step
transpo18[i, j] += transpo18step * 1.0e3
# transpo18[i, j] += transpo18step * 1.0e3 # isotope tracking removed
et_s_daily[i, j] += et_s_step
ppacum[i, j] += ppdrip_step
qrf[i, j] += qrfcorrect

# 更新土壤含水量和同位素
# 更新土壤含水量
θ[:, i, j] .= updated_smoi
o18[:, i, j] .= updated_o18
# o18[:, i, j] .= updated_o18 # isotope tracking removed

# 更新浅层地下水位
wtd[i, j], rech_additional = updatewtd_shallow(nzg, freedrain, z₋ₕ, dz,
Expand Down
17 changes: 15 additions & 2 deletions src/SoilFluxes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,19 @@ function soilfluxes(
cc[1] = D_mid[2] / Δz₊ₕ[2]
bb[1] = -(cc[1] + Δz[1] / dt)
rr[1] = -θ[1] * Δz[1] / dt - K_mid[2] + K_mid[1] + transp[1] / dt

# k=2 must be set explicitly since the main loop starts at max(jwt,3)=3
k = 2
aa[k] = D_mid[k] / Δz₊ₕ[k]
if k < nzg
cc[k] = D_mid[k+1] / Δz₊ₕ[k+1]
bb[k] = -(aa[k] + cc[k] + Δz[k] / dt)
rr[k] = -θ[k] * Δz[k] / dt - K_mid[k+1] + K_mid[k] + transp[k] / dt
else
cc[k] = 0.0
bb[k] = -(aa[k] + Δz[k] / dt)
rr[k] = -θ[k] * Δz[k] / dt + K_mid[k] + transp[k] / dt
end
end

# 求解三对角系统
Expand Down Expand Up @@ -283,7 +296,7 @@ function soilfluxes(
# 处理最上层的干燥限制
k = nzg
soil = get_soil_params(soiltxt)
θ_cp = soil.ρb * max(min(exp((z[k] + 1.5) / fdepth), 1.0), 0.1)
θ_cp = soil.θ_cp * max(min(exp((z[k] + 1.5) / fdepth), 1.0), 0.1)

et_s = pet_s
if θ_old[k] < θ_cp
Expand All @@ -307,7 +320,7 @@ function soilfluxes(
# 继续处理下层
for k in (nzg-1):-1:1
soil = get_soil_params(soiltxt)
θ_cp = soil.ρb * max(min(exp((z[k] + 1.5) / fdepth), 1.0), 0.1)
θ_cp = soil.θ_cp * max(min(exp((z[k] + 1.5) / fdepth), 1.0), 0.1)

if θ_old[k] < θ_cp
dθ = max((θ_cp - θ_old[k]) * Δz[k], 0.0)
Expand Down
4 changes: 2 additions & 2 deletions src/extraction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ function extraction(
if toteasy == 0.0
rootactivity = zeros(Float64, nzg)
else
rootactivity = clamp((easy .* dz2) ./ toteasy, 0.0, 1.0)
rootactivity = clamp.((easy .* dz2) ./ toteasy, 0.0, 1.0)
end

# 更新非活跃天数
Expand Down Expand Up @@ -141,7 +141,7 @@ function extraction(
end

# 计算土壤水分胁迫因子
fswp = clamp(θ_root / rootfc, 0.0, 1.0)
fswp = rootfc == 0.0 ? 0.0 : clamp(θ_root / rootfc, 0.0, 1.0)

# 计算冠层和土壤阻力
rs_c = fswp == 0.0 ? 5000.0 : min(rs_c_factor / fswp, 5000.0)
Expand Down
7 changes: 5 additions & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ using ASAP, Test
include("test_soil_initialization.jl")
include("test_evapotranspiration.jl")
include("test_interception.jl")
# include("test_soil_fluxes.jl")
include("test_soil_parameters.jl")
include("test_soil_fluxes.jl")
include("test_extraction.jl")
include("test_updatewtd_shallow.jl")
include("test_rootdepth.jl")

include("wtable/runtests.jl")
# include("test_soil_parameters.jl")
123 changes: 123 additions & 0 deletions test/test_extraction.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
using ASAP, Test

# 典型参数设置(Penman-Monteith 方程参数)
const Δ_test = 145.0 # 饱和水汽压斜率 (Pa/K)
const γ_test = 66.0 # 湿度计常数 (Pa/K)
const λ_test = 2.45e6 # 汽化潜热 (J/kg)

function make_extraction_inputs(nzg; lai=2.0, θ_val=0.25, icefac_val=Int8(0))
z₋ₕ, dz = initializesoildepth(nzg)
Δt = 3600.0
soiltxt = 1
wtd = z₋ₕ[1] - 0.5 # 水位在所有层之下(不饱和)
θ = fill(θ_val, nzg)
θ_wtd = 0.3
ra_a = 100.0
ra_c = 50.0
rs_c_factor = 200.0
R_a = (Δ_test + γ_test) * ra_a * 3.0 # 近似辐射驱动力
R_s = (Δ_test + γ_test) * ra_a * 1.0
petfactor_s = R_s
petfactor_c = R_a
inactivedays = zeros(Int, nzg + 2) # 全部活跃
maxinactivedays = 10
hhveg = 10.0
fdepth = 2.0
icefac = fill(icefac_val, nzg)
return (nzg, z₋ₕ, dz, Δt, soiltxt, wtd, θ, θ_wtd,
Δ_test, γ_test, λ_test,
lai, ra_a, ra_c, rs_c_factor,
R_a, R_s, petfactor_s, petfactor_c,
inactivedays, maxinactivedays,
hhveg, fdepth, icefac)
end


@testset "extraction基本功能" begin
args = make_extraction_inputs(10)
pet_s, pet_c, watdef, dθ, dθ_deep = extraction(args...)

@test pet_s >= 0.0
@test pet_c >= 0.0
@test watdef >= 0.0
@test length(dθ) == 10
@test dθ_deep == 0.0 # 深层无提取
@test all(dθ .>= 0.0) # 每层提取量非负
end

@testset "零LAI时无冠层蒸腾" begin
args = make_extraction_inputs(10; lai=0.0)
pet_s, pet_c, watdef, dθ, dθ_deep = extraction(args...)

# LAI=0 时,冠层蒸腾强制为零
@test pet_c == 0.0
@test pet_s >= 0.0
end

@testset "全部冰冻时无提取" begin
args = make_extraction_inputs(10; icefac_val=Int8(1))
pet_s, pet_c, watdef, dθ, dθ_deep = extraction(args...)

# 冰冻情况下根区水分提取便利性为零
@test all(dθ .== 0.0)
@test watdef >= 0.0 # 水分亏缺 ≥ 0
end

@testset "干旱土壤产生水分亏缺" begin
# 非常干的土壤 (θ << θ_wilt)
nzg = 10
args_dry = make_extraction_inputs(nzg; θ_val=0.05)
pet_s, pet_c, watdef_dry, dθ_dry, _ = extraction(args_dry...)

args_wet = make_extraction_inputs(nzg; θ_val=0.35)
_, _, watdef_wet, dθ_wet, _ = extraction(args_wet...)

# 湿润土壤水分亏缺应该比干燥时少
@test watdef_wet <= watdef_dry
# 湿润土壤提取总量应该更多
@test sum(dθ_wet) >= sum(dθ_dry)
end

@testset "inactivedays正确更新" begin
nzg = 10
args = make_extraction_inputs(nzg; θ_val=0.25)
# inactivedays初始为全0(全部活跃)
pet_s, pet_c, watdef, dθ, dθ_deep = extraction(args...)

# 函数会修改 inactivedays(若根区活跃则清零,否则+1)
@test pet_s >= 0.0
@test pet_c >= 0.0
end

@testset "蒸发量与时间步长成正比" begin
nzg = 10

# 短时间步长(30 min)
args1 = make_extraction_inputs(nzg)
# 修改 Δt 为 1800 s
args1 = (args1[1], args1[2], args1[3], 1800.0, args1[5:end]...)
pet_s1, pet_c1, _, _, _ = extraction(args1...)

# 长时间步长(2 h)
args2 = make_extraction_inputs(nzg)
args2 = (args2[1], args2[2], args2[3], 7200.0, args2[5:end]...)
pet_s2, pet_c2, _, _, _ = extraction(args2...)

# 时间步长加倍,PET近似翻倍
@test pet_s2 > pet_s1
@test pet_c2 > pet_c1
end

@testset "各层提取量之和等于冠层蒸腾量(无亏缺时)" begin
nzg = 10
# 使用高含水量,确保无水分亏缺
args = make_extraction_inputs(nzg; θ_val=0.38)
pet_s, pet_c, watdef, dθ, dθ_deep = extraction(args...)

if watdef == 0.0
# 无水分亏缺:提取量之和应等于 pet_c(m)
@test sum(dθ) ≈ pet_c * 1e-3 atol=1e-10
else
@test sum(dθ) + watdef ≈ pet_c * 1e-3 atol=1e-10
end
end
141 changes: 141 additions & 0 deletions test/test_rootdepth.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
using ASAP, Test

# rootdepth_main使用nzg=40(标准层数,与icefactor[26:40]索引匹配)
const NZG_RD = 40

# 构建rootdepth_main所需的最小参数集(网格大小3×3,内层循环只访问(2,2))
function make_rootdepth_inputs(; freedrain=1, veg_val=1.0, landmask_val=1, nzg=NZG_RD)
is, ie, js, je = 1, 3, 1, 3
nx, ny = ie, je # 3×3 grid
z₋ₕ, dz = initializesoildepth(nzg)
Δt = 3600.0

landmask = zeros(Int, nx, ny); landmask[2, 2] = landmask_val
veg = fill(veg_val, nx, ny)
hveg = fill(1.0, nx, ny)
soiltxt = ones(Int, 2, nx, ny)
wind = fill(3.0, nx, ny)
temp = fill(293.0, nx, ny)
qair = fill(0.01, nx, ny)
press = fill(101325.0, nx, ny)
netrad = fill(100.0, nx, ny)
rshort = fill(150.0, nx, ny)
lai = fill(2.0, nx, ny)
precip = fill(5.0, nx, ny)
qsrun = zeros(Float64, nx, ny)
θ = fill(0.25, nzg, nx, ny)
θ_eq = fill(0.20, nzg, nx, ny)
θ_wtd = fill(0.35, nx, ny)
wtd = fill(-1.0, nx, ny)
waterdeficit = zeros(Float64, nx, ny)
watext = zeros(Float64, nzg, nx, ny)
watextdeep = zeros(Float64, nx, ny)
rech = zeros(Float64, nx, ny)
deeprech = zeros(Float64, nx, ny)
et_s = zeros(Float64, nx, ny)
et_i = zeros(Float64, nx, ny)
et_c = zeros(Float64, nx, ny)
intercepstore = zeros(Float64, nx, ny)
ppacum = zeros(Float64, nx, ny)
pInfiltDepth = zeros(Float64, nx, ny)
pInfiltDepthK_old = zeros(Int8, nx, ny)
qlat = zeros(Float64, nx, ny)
qlatsum = zeros(Float64, nx, ny)
qsprings = zeros(Float64, nx, ny)
inactivedays = zeros(Int, nzg+2, nx, ny)
maxinactivedays = 10
fdepth = fill(2.0, nx, ny)
steps = 1.0
floodheight = zeros(Float64, nx, ny)
qrf = zeros(Float64, nx, ny)
delsfcwat = zeros(Float64, nx, ny)
icefactor = zeros(Int8, nx, ny, nzg)
wtdflux = zeros(Float64, nx, ny)
et_s_daily = zeros(Float64, nx, ny)
et_c_daily = zeros(Float64, nx, ny)
transptop = zeros(Float64, nx, ny)
infilk = zeros(Int8, nx, ny)
infilflux = zeros(Float64, nzg, nx, ny)
infilfluxday = zeros(Float64, nzg, nx, ny)
infilcounter = zeros(Int16, nzg, nx, ny)
hour = 0
o18 = zeros(Float64, nzg, nx, ny)
o18ratiopp = zeros(Float64, nx, ny)
tempsfc = fill(293.0, nx, ny)
qlato18 = zeros(Float64, nx, ny)
transpo18 = zeros(Float64, nx, ny)
upflux = zeros(Float64, nzg, nx, ny)

return (freedrain, is, ie, js, je, nzg,
z₋ₕ, dz, Δt,
landmask, veg, hveg,
soiltxt, wind, temp,
qair, press, netrad,
rshort, lai, precip,
qsrun, θ, θ_eq,
θ_wtd, wtd, waterdeficit,
watext,
watextdeep, rech,
deeprech,
et_s, et_i, et_c,
intercepstore, ppacum,
pInfiltDepth, pInfiltDepthK_old, qlat,
qlatsum, qsprings, inactivedays,
maxinactivedays, fdepth,
steps, floodheight, qrf,
delsfcwat, icefactor, wtdflux,
et_s_daily, et_c_daily, transptop,
infilk, infilflux, infilfluxday,
infilcounter, hour,
o18, o18ratiopp, tempsfc,
qlato18, transpo18, upflux)
end

@testset "rootdepth_main: 全零陆地掩码(无活跃格点)" begin
# landmask全零:内层循环立即跳过,函数应返回nothing且不修改任何数组
args = make_rootdepth_inputs(landmask_val=0)
et_s_before = copy(args[33]) # et_s is the 33rd arg
result = rootdepth_main(args...)
@test result === nothing
# 所有输出应保持不变
@test args[33] == et_s_before
Comment on lines +97 to +101
end

@testset "rootdepth_main: 水体格点(veg=1)" begin
# veg=1 (水体):执行潜在蒸散发计算,但跳过植被相关代码
args = make_rootdepth_inputs(veg_val=1.0, landmask_val=1)
et_s = args[33]
et_s_init = et_s[2, 2]
Comment on lines +107 to +108

result = rootdepth_main(args...)
@test result === nothing
# 水体格点应更新土壤蒸发
@test et_s[2, 2] >= et_s_init
end

@testset "rootdepth_main: 自由排水+植被格点(veg=7,短草)" begin
# freedrain=1(自由排水),veg=7(短草):执行全部子模块(extraction、soilfluxes、updatewtd_shallow)
args = make_rootdepth_inputs(freedrain=1, veg_val=7.0, landmask_val=1)
et_s = args[33]
et_c = args[35]
rech = args[30]
Comment on lines +119 to +121

result = rootdepth_main(args...)
@test result === nothing
# 植被格点应更新蒸腾和补给
@test isfinite(et_s[2, 2])
@test isfinite(et_c[2, 2])
@test isfinite(rech[2, 2])
end

@testset "rootdepth_main: 非自由排水+植被格点(veg=7)" begin
# freedrain=0(非自由排水):测试soilfluxes的!freedrain分支在全流程中的集成
args = make_rootdepth_inputs(freedrain=0, veg_val=7.0, landmask_val=1)
et_s = args[33]
et_c = args[35]
Comment on lines +134 to +135

result = rootdepth_main(args...)
@test result === nothing
@test isfinite(et_s[2, 2])
@test isfinite(et_c[2, 2])
end
Loading
Loading