Skip to content

Commit d39e62c

Browse files
Parameter descriptions and more flexible parameter update
1 parent 2daea9d commit d39e62c

File tree

6 files changed

+70
-63
lines changed

6 files changed

+70
-63
lines changed

src/Nodes/DamNode.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Base.@kwdef mutable struct DamNode{P,A<:AbstractFloat} <: NetworkNode
3131
area::A
3232

3333
max_storage::A
34-
storage_coef::P = Param(0.5, bounds=(0.00001, 10.0))
34+
storage_coef::P = Param(0.5, bounds=(0.00001, 10.0), desc="Storage coefficient.")
3535

3636
# Dam storage volume to level
3737
calc_dam_level::Function = c_dam_level

src/Nodes/GR4J/GR4JNode.jl

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,10 @@ Base.@kwdef mutable struct GR4JNode{P,A<:AbstractFloat} <: GRNJNode
7171
const area::A
7272

7373
# Parameters
74-
# x1 : maximum capacity of the production store (mm) (> 0)
75-
# x2 : groundwater exchange coefficient (mm) (value < and > 0 possible)
76-
# x3 : one day ahead maximum capacity of the routing store (mm, > 0)
77-
# x4 : time base of unit hydrograph UH1 (days, > 0.5)
78-
X1::P = Param(350.0, bounds=(1.0, 1500.0))
79-
X2::P = Param(0.0, bounds=(-10.0, 5.0))
80-
X3::P = Param(40.0, bounds=(1.0, 500.0))
81-
X4::P = Param(0.5, bounds=(0.5, 10.0))
74+
X1::P = Param(350.0, bounds=(1.0, 1500.0), desc="Maximum soil water storage capacity.")
75+
X2::P = Param(0.0, bounds=(-10.0, 5.0), desc="Water exchange with deeper groundwater and adjacent catchments.")
76+
X3::P = Param(40.0, bounds=(1.0, 500.0), desc="Maximum capacity of one day ahead of routing store, controls the baseflow component.")
77+
X4::P = Param(0.5, bounds=(0.5, 10.0), desc="Time base of quickflow controlling the timing and shape of hydrograph.")
8278

8379
# stores
8480
p_store::Vector{A} = [0.0]
@@ -226,10 +222,13 @@ end
226222
Update parameters for GR4J.
227223
"""
228224
function update_params!(node::GR4JNode, X1::Float64, X2::Float64, X3::Float64, X4::Float64)::Nothing
229-
node.X1 = Param(X1, bounds=node.X1.bounds)
230-
node.X2 = Param(X2, bounds=node.X2.bounds)
231-
node.X3 = Param(X3, bounds=node.X3.bounds)
232-
node.X4 = Param(X4, bounds=node.X4.bounds)
225+
param_pairs = zip([:X1, :X2, :X3, :X4], [X1, X2, X3, X4])
226+
227+
# First item will always be the set value, so it can be skipped
228+
for (p, v) in param_pairs
229+
param = getfield(node, p)
230+
setfield!(node, p, Param(v; (keys(param)[2:end] .=> values(param)[2:end])...))
231+
end
233232

234233
return nothing
235234
end

src/Nodes/HyMod/HyModNode.jl

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ Base.@kwdef mutable struct SimpleHyModNode{P,A<:AbstractFloat} <: HyModNode
2525
const area::A
2626

2727
# parameters
28-
Sm_max::P = Param(250.0, bounds=(1.0, 500.0))
29-
B::P = Param(1.0, bounds=(0.0, 2.0))
30-
alpha::P = Param(0.2, bounds=(0.0, 1.0))
31-
Kf::P = Param(0.5, bounds=(0.1, 0.9999))
32-
Ks::P = Param(0.05, bounds=(0.001, 0.1))
28+
Sm_max::P = Param(250.0, bounds=(1.0, 500.0), desc="Maximum soil storage capacity.")
29+
B::P = Param(1.0, bounds=(0.0, 2.0), desc="Controls how quickly the catchment becomes saturated as rainfall accumulates.")
30+
alpha::P = Param(0.2, bounds=(0.0, 1.0), desc="The split between quick and slow flow components. Higher values direct more water through quickflow.")
31+
Kf::P = Param(0.5, bounds=(0.1, 0.9999), desc="Quickflow recession.")
32+
Ks::P = Param(0.05, bounds=(0.001, 0.1), desc="Slowflow recession.")
3333

3434
# stores
3535
Sm::Array{A} = [0.0]
@@ -173,11 +173,13 @@ end
173173
Update parameters for HyMod.
174174
"""
175175
function update_params!(node::HyModNode, Sm_max::F, B::F, alpha::F, Kf::F, Ks::F) where {F<:Float64}
176-
node.Sm_max = Param(Sm_max, bounds=node.Sm_max.bounds::Tuple)
177-
node.B = Param(B, bounds=node.B.bounds::Tuple)
178-
node.alpha = Param(alpha, bounds=node.alpha.bounds::Tuple)
179-
node.Kf = Param(Kf, bounds=node.Kf.bounds::Tuple)
180-
node.Ks = Param(Ks, bounds=node.Ks.bounds::Tuple)
176+
param_pairs = zip([:Sm_max, :B, :alpha, :Kf, :Ks], [Sm_max, B, alpha, Kf, Ks])
177+
178+
# First item will always be the set value, so it can be skipped
179+
for (p, v) in param_pairs
180+
param = getfield(node, p)
181+
setfield!(node, p, Param(v; (keys(param)[2:end] .=> values(param)[2:end])...))
182+
end
181183
end
182184

183185
function update_state!(

src/Nodes/IHACRES/IHACRESNode.jl

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ Base.@kwdef mutable struct IHACRESBilinearNode{P,A<:AbstractFloat} <: IHACRESNod
1313
const area::A
1414

1515
# https://wiki.ewater.org.au/display/SD41/IHACRES-CMD+-+SRG
16-
d::P = Param(200.0, bounds=(10.0, 550.0)) # flow threshold
17-
d2::P = Param(2.0, bounds=(0.0001, 10.0)) # flow threshold2
18-
e::P = Param(1.0, bounds=(0.999, 1.0)) # temperature to PET conversion factor
19-
f::P = Param(0.8, bounds=(0.01, 3.0)) # plant stress threshold factor (multiplicative factor of d)
20-
a::P = Param(0.9, bounds=(0.1, 10.0)) # quickflow storage coefficient == (1/tau_q)
21-
b::P = Param(0.1, bounds=(1e-3, 0.1)) # slowflow storage coefficent == (1/tau_s)
16+
d::P = Param(200.0, bounds=(10.0, 550.0), desc="Catchment moisture deficit threshold, higher values indicate the catchment can hold more water before generating runoff.")
17+
d2::P = Param(2.0, bounds=(0.0001, 10.0), desc="Scaling factor (d*d2) which creates a second threshold, changing the shape of effective rainfall response.")
18+
e::P = Param(1.0, bounds=(0.999, 1.0), desc="PET conversion factor, controls the rate of evapotranspiration losses, converts temperature to PET.")
19+
f::P = Param(0.8, bounds=(0.01, 3.0), desc="Plant stress threshold, controls at what moisture deficit plants begin to experience stress.")
20+
a::P = Param(0.9, bounds=(0.1, 10.0), desc="Quickflow storage coefficient, where higher values lead to faster quickflow response.") # quickflow storage coefficient == (1/tau_q)
21+
b::P = Param(0.1, bounds=(1e-3, 0.1), desc="Slowflow storage coefficient, lower values lead to slower baseflow recession.") # slowflow storage coefficent == (1/tau_s)
2222

23-
storage_coef::P = Param(2.9, bounds=(1e-10, 10.0))
24-
alpha::P = Param(0.1, bounds=(1e-5, 1 - 1 / 10^9))
23+
storage_coef::P = Param(2.9, bounds=(1e-10, 10.0), desc="Groundwater interaction factor, controling how water is exchanged with deeper groundwater.")
24+
alpha::P = Param(0.1, bounds=(1e-5, 1 - 1 / 10^9), desc="Effective rainfall scaling factor, partitions rainfall into runoff.")
2525

2626
# const level_params::Array{P, 1} = [
2727
# Param(-0.01, bounds=(-10.0, -0.01)), # p1
@@ -462,14 +462,16 @@ function update_params!(
462462
s_coef::F,
463463
alpha::F
464464
)::Nothing where {F<:Float64}
465-
node.d = Param(d, bounds=node.d.bounds::Tuple)
466-
node.d2 = Param(d2, bounds=node.d2.bounds::Tuple)
467-
node.e = Param(e, bounds=node.e.bounds::Tuple)
468-
node.f = Param(f, bounds=node.f.bounds::Tuple)
469-
node.a = Param(a, bounds=node.a.bounds::Tuple)
470-
node.b = Param(b, bounds=node.b.bounds::Tuple)
471-
node.storage_coef = Param(s_coef, bounds=node.storage_coef.bounds::Tuple)
472-
node.alpha = Param(alpha, bounds=node.alpha.bounds::Tuple)
465+
param_pairs = zip(
466+
[:d, :d2, :e, :f, :a, :b, :storage_coef, :alpha],
467+
[d, d2, e, f, a, b, s_coef, alpha]
468+
)
469+
470+
# First item will always be the set value, so it can be skipped
471+
for (p, v) in param_pairs
472+
param = getfield(node, p)
473+
setfield!(node, p, Param(v; (keys(param)[2:end] .=> values(param)[2:end])...))
474+
end
473475

474476
return nothing
475477
end

src/Nodes/Node.jl

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ end
1919
Create node of a given type.
2020
"""
2121
function create_node(node::Type{<:NetworkNode}, name::String, area::Float64)
22-
return node{Param, Float64}(; name=name, area=area)
22+
return node{Param,Float64}(; name=name, area=area)
2323
end
2424

2525

@@ -55,7 +55,6 @@ function GenericDirectNode(name::String, spec::Dict)
5555
end
5656

5757

58-
5958
"""
6059
param_info(node::NetworkNode)
6160
@@ -72,7 +71,6 @@ function param_info(node::NetworkNode; kwargs...)::Tuple
7271
return param_names, values, bounds
7372
end
7473

75-
7674
"""
7775
get_node_id(mg::MetaDiGraph, node_name::String)::Int64
7876
@@ -160,10 +158,15 @@ function Base.show(io::IO, n::NetworkNode)
160158
println(io, "Name: $(n.name) [$(ntype_name)]")
161159
println(io, "Area: $(n.area)")
162160

163-
param_names, x0, bounds = param_info(n; with_level=false)
161+
n_model = Model(n)
162+
param_names = n_model[:fieldname]
163+
x0 = n_model[:val]
164+
bounds = n_model[:bounds]
165+
descs = n_model[:desc]
166+
164167
lb, ub = zip(bounds...)
165-
details = hcat(param_names, x0, [lb...], [ub...])
168+
details = hcat([param_names...], [x0...], [lb...], [ub...], [descs...])
166169

167-
pretty_table(io, details, header=["Parameter", "Value", "Lower Bound", "Upper Bound"])
170+
pretty_table(io, details, header=["Parameter", "Value", "Lower Bound", "Upper Bound", "Description"])
168171
print("\n")
169172
end

src/Nodes/SIMHYD/SIMHYDNode.jl

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ Base.@kwdef mutable struct SIMHYDNode{P,A<:AbstractFloat} <: NetworkNode
99
area::A
1010

1111
# parameters
12-
baseflow_coef::P = Param(0.5, bounds=(0.0, 1.0))
13-
impervious_threshold::P = Param(2.5, bounds=(0.0, 5.0)) # mm
14-
infiltration_coef::P = Param(200.0, bounds=(0.0, 400.0))
15-
infiltration_shape::P = Param(5.0, bounds=(0.0, 10.0))
16-
interflow_coef::P = Param(0.5, bounds=(0.0, 1.0))
17-
pervious_fraction::P = Param(0.5, bounds=(0.0, 1.0))
18-
risc::P = Param(2.5, bounds=(0.0, 5.0)) # rainfall interception store capacity (mm)
19-
recharge_coef::P = Param(0.5, bounds=(0.0, 1.0))
20-
smsc::P = Param(250.0, bounds=(1.0, 500.0)) # Soil Moisture Store Capacity (mm)
12+
baseflow_coef::P = Param(0.5, bounds=(0.0, 1.0), desc="Rate of release from groundwater.")
13+
impervious_threshold::P = Param(2.5, bounds=(0.0, 5.0), desc="Threshold below which rainfall is lost to evaporation (in mm).") # mm
14+
infiltration_coef::P = Param(200.0, bounds=(0.0, 400.0), desc="Maximum infiltration rate. Higher values allow more infiltration into soil.")
15+
infiltration_shape::P = Param(5.0, bounds=(0.0, 10.0), desc="Controls decrease in infiltration with increasing soil moisture.")
16+
interflow_coef::P = Param(0.5, bounds=(0.0, 1.0), desc="Movement of water laterally through soil.")
17+
pervious_fraction::P = Param(0.5, bounds=(0.0, 1.0), desc="Indicates fraction of catchment that is pervious.")
18+
risc::P = Param(2.5, bounds=(0.0, 5.0), desc="Represents canopy/vegetation interception capacity (in mm).")
19+
recharge_coef::P = Param(0.5, bounds=(0.0, 1.0), desc="Rate of deep percolation from soil to groundwater.")
20+
smsc::P = Param(250.0, bounds=(1.0, 500.0), desc="Maximum capacity of soil (in mm).")
2121

2222
# stores
2323
sm_store::Array{A} = [0.0]
@@ -183,15 +183,16 @@ function update_params!(
183183
recharge_coef::Float64,
184184
smsc::Float64
185185
)::Nothing
186-
node.baseflow_coef = Param(baseflow_coef, bounds=node.baseflow_coef.bounds)
187-
node.impervious_threshold = Param(impervious_threshold, bounds=node.impervious_threshold.bounds)
188-
node.infiltration_coef = Param(infiltration_coef, bounds=node.infiltration_coef.bounds)
189-
node.infiltration_shape = Param(infiltration_shape, bounds=node.infiltration_shape.bounds)
190-
node.interflow_coef = Param(interflow_coef, bounds=node.interflow_coef.bounds)
191-
node.pervious_fraction = Param(pervious_fraction, bounds=node.pervious_fraction.bounds)
192-
node.risc = Param(risc, bounds=node.risc.bounds)
193-
node.recharge_coef = Param(recharge_coef, bounds=node.recharge_coef.bounds)
194-
node.smsc = Param(smsc, bounds=node.smsc.bounds)
186+
param_pairs = zip(
187+
[:baseflow_coef, :impervious_threshold, :infiltration_coef, :infiltration_shape, :interflow_coef, :pervious_fraction, :risc, :recharge_coef, :smsc],
188+
[baseflow_coef, impervious_threshold, infiltration_coef, infiltration_shape, interflow_coef, pervious_fraction, risc, recharge_coef, smsc]
189+
)
190+
191+
# First item will always be the set value, so it can be skipped
192+
for (p, v) in param_pairs
193+
param = getfield(node, p)
194+
setfield!(node, p, Param(v; (keys(param)[2:end] .=> values(param)[2:end])...))
195+
end
195196

196197
return nothing
197198
end

0 commit comments

Comments
 (0)