Skip to content

Commit 2b26ceb

Browse files
committed
Kv profile passed test
1 parent 5bac0f1 commit 2b26ceb

5 files changed

Lines changed: 131 additions & 2 deletions

File tree

src/Params.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,4 @@ function get_opt_info(model; paths=nothing)
103103
end
104104

105105
export get_params, parameters, update!
106+
export get_opt_info

src/SoilColumn.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,12 @@ function filter_params(ps, mod::Union{Symbol,AbstractVector{Symbol}};
8181
params[mask, :]
8282
end
8383

84-
8584
# Shared update logic for AbstractSoilModel subtypes.
8685
# Requires ps.hydraulic::HydraulicProfile and ps.thermal::ThermalProfile.
8786
#
8887
# list_sameLayer: broadcast the source-layer value to all hydraulic profile layers
8988
# list_fix: excluded from params by filter_params, so update! never touches them
89+
# !注意,要传入dz_cm
9090
function update_params!(ps::AbstractSoilModel{FT,N}, paths, theta;
9191
params=nothing,
9292
list_sameLayer::Vector{Symbol}=Symbol[],

test/Model_BEPS_2.0.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
include("Model_BEPS_base.jl")
22

3-
# ParamBEPS3 <: AbstractSoilModel{FT,N}:
3+
# ParamBEPS2 <: AbstractSoilModel{FT,N}:
44
# - thermal 改用 ThermalProfile(统一 SoA + AoS 缓存)
55
# - 继承 filter_params / update_params! 无需额外代码
66
@bounds @with_kw mutable struct ParamBEPS2{FT<:AbstractFloat,N,

test/runtests.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using ModelParams, Test, Parameters
22
# 必须要@with_kw,Base.@kwdef报错
33

4+
include("test-Kv_profile.jl")
5+
46
include("test-SoilDiffEqs.jl")
57
include("test-SoilColumn.jl")
68
include("Model_SoilDiffEqs.jl")

test/test-Kv_profile.jl

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
using ModelParams, Test
2+
3+
@testset "KvExp" begin
4+
kv = KvExp(kv=10.0, f=0.01)
5+
6+
# At the surface (z=0): Ksat = kv
7+
@test kv_at_depth(kv, 1, 0.0) 10.0
8+
9+
# At depth 100 cm: Ksat = kv * exp(-f*z) = 10 * exp(-1)
10+
@test kv_at_depth(kv, 3, 100.0) 10.0 * exp(-1.0)
11+
12+
# Strictly decreasing with depth
13+
k1 = kv_at_depth(kv, 1, 10.0)
14+
k2 = kv_at_depth(kv, 2, 50.0)
15+
k3 = kv_at_depth(kv, 3, 200.0)
16+
@test k1 > k2 > k3
17+
end
18+
19+
@testset "KvExpConst" begin
20+
kv = KvExpConst(kv=10.0, f=0.01, z_exp=50.0)
21+
22+
# At z < z_exp: same as exponential
23+
@test kv_at_depth(kv, 1, 20.0) 10.0 * exp(-0.01 * 20.0)
24+
25+
# At z_exp: Ksat = kv * exp(-f * z_exp)
26+
kv_at_zexp = 10.0 * exp(-0.01 * 50.0)
27+
@test kv_at_depth(kv, 2, 50.0) kv_at_zexp
28+
29+
# At z > z_exp: constant (same as at z_exp)
30+
@test kv_at_depth(kv, 3, 100.0) kv_at_zexp
31+
@test kv_at_depth(kv, 4, 300.0) kv_at_zexp
32+
end
33+
34+
@testset "KvLayers" begin
35+
kv = KvLayers{Float64,3}(kv=[5.0, 10.0, 2.0])
36+
@test kv_at_depth(kv, 1, 0.0) 5.0
37+
@test kv_at_depth(kv, 2, 10.0) 10.0
38+
@test kv_at_depth(kv, 3, 50.0) 2.0
39+
end
40+
41+
# @testset "KvExpLayers" begin
42+
# # Upper 2 layers: layered; below: exponential with f[2]=0.01 from kv[2]
43+
# kv = KvExpLayers{Float64,3}(kv=[5.0, 8.0, 3.0], f=[0.02, 0.01, 0.01])
44+
# nlayers_kv = 2
45+
# z_layered_cm = 40.0 # bottom of layer 2
46+
47+
# # Layer 1 (≤ nlayers_kv): returns kv[1]
48+
# @test kv_at_depth(kv, 1, 10.0, nlayers_kv, z_layered_cm) ≈ 5.0
49+
# # Layer 2 (≤ nlayers_kv): returns kv[2]
50+
# @test kv_at_depth(kv, 2, 30.0, nlayers_kv, z_layered_cm) ≈ 8.0
51+
# # Layer 3 (> nlayers_kv): exponential from kv[2] with f[2]
52+
# z3 = 60.0
53+
# expected = 8.0 * exp(-0.01 * (z3 - z_layered_cm))
54+
# @test kv_at_depth(kv, 3, z3, nlayers_kv, z_layered_cm) ≈ expected
55+
# end
56+
57+
@testset "kv_layer_ksat — integral formula" begin
58+
# KvExp: layer-average = kv/f/dz * (exp(-f*z1) - exp(-f*z2))
59+
kv = KvExp(kv=10.0, f=0.01)
60+
z1, z2 = 0.0, 20.0
61+
expected = 10.0 / (0.01 * 20.0) * (exp(-0.01 * z1) - exp(-0.01 * z2))
62+
@test kv_layer_ksat(kv, 1, z1, z2) expected
63+
64+
# Thin layer: degenerates to centre-point
65+
z1, z2 = 10.0, 10.0 + 1e-10
66+
@test kv_layer_ksat(kv, 1, z1, z2) 10.0 * exp(-0.01 * (z1 + z2) / 2)
67+
68+
# KvExpConst: layer entirely above z_exp
69+
kvc = KvExpConst(kv=10.0, f=0.01, z_exp=50.0)
70+
@test kv_layer_ksat(kvc, 1, 0.0, 20.0)
71+
10.0 / (0.01 * 20.0) * (1.0 - exp(-0.01 * 20.0))
72+
73+
# Layer entirely below z_exp: constant
74+
ksat_const = 10.0 * exp(-0.01 * 50.0)
75+
@test kv_layer_ksat(kvc, 2, 60.0, 80.0) ksat_const
76+
77+
# Layer straddling z_exp
78+
ksat_kvc = kv_layer_ksat(kvc, 1, 40.0, 60.0)
79+
# First 10 cm: exponential from 40 to 50; last 10 cm: constant
80+
exp_part = 10.0 / (0.01 * 10.0) * (exp(-0.01 * 40) - exp(-0.01 * 50)) * 10.0 / 20.0
81+
const_part = ksat_const * 10.0 / 20.0
82+
@test ksat_kvc exp_part + const_part
83+
84+
# _sync_ksat! with dz_cm correctly sets param[i].Ksat via integral
85+
par = Campbell(θ_sat=0.4, ψ_sat=-10.0, Ksat=10.0, b=4.0)
86+
kv2 = KvExp(kv=10.0, f=0.01)
87+
dz = [20.0, 20.0, 20.0] # [cm]
88+
# ps = SoilModel(par, 3; kv_profile=kv2, dz_cm=dz)
89+
# for i in 1:3
90+
# z1_cm = (i - 1) * 20.0
91+
# z2_cm = i * 20.0
92+
# @test ps.param_hydraulic[i].Ksat ≈ kv_layer_ksat(kv2, i, z1_cm, z2_cm)
93+
# end
94+
end
95+
96+
@testset "KvProfile ModelParams bounds" begin
97+
kv = KvExp{Float64}()
98+
# get_opt_info returns (x0, lb, ub, paths) in field-definition order: kv, f
99+
x0, lb, ub, paths = get_opt_info(kv)
100+
@test length(x0) == 2
101+
@test lb[1] 0.002 # kv lower
102+
@test ub[1] 100.0 # kv upper
103+
@test lb[2] 0.0 # f lower
104+
@test ub[2] 0.1 # f upper
105+
106+
# KvExpConst has 3 params
107+
kvc = KvExpConst{Float64}()
108+
x0c, lbc, ubc, _ = get_opt_info(kvc)
109+
@test length(x0c) == 3
110+
@test lbc[3] 10.0 # z_exp lower
111+
@test ubc[3] 500.0 # z_exp upper
112+
end
113+
114+
# @testset "KvProfile layer ModelParams bridge" begin
115+
# kv = KvExpLayers{Float64,3}(kv=[5.0, 8.0, 3.0], f=[0.02, 0.01, 0.01])
116+
# @test kv isa AbstractKvLayers
117+
118+
# params = parameters(kv)
119+
# @test params.value == [5.0, 8.0, 3.0, 0.02, 0.01, 0.01]
120+
# @test params.path == [[:kv, 1], [:kv, 2], [:kv, 3], [:f, 1], [:f, 2], [:f, 3]]
121+
122+
# par = Campbell(θ_sat=0.4, ψ_sat=-10.0, Ksat=10.0, b=4.0)
123+
# ps = SoilModel(par, 3; kv_profile=kv, nlayers_kv=2, dz_cm=[20.0, 20.0, 20.0])
124+
# @test ps.kv_profile isa AbstractKvLayers
125+
# @test get_params(ps, :kv_profile).value == params.value
126+
# end

0 commit comments

Comments
 (0)