11"""
2- Portions of the GR4J implementation is directly adapted from Python code written by Andrew MacDonald (2014).
2+ Portions of the GR4J implementation is adapted from Python code written by Andrew MacDonald (2014).
33
44Per license requirements, the full license conditions included below.
55
@@ -65,8 +65,9 @@ A four-parameter model with two stores.
6565 https://github.com/amacd31/gr4j
6666
6767"""
68- Base. @kwdef mutable struct GR4JNode{P, A<: Real } <: GRNJNode
69- @network_node
68+ Base. @kwdef mutable struct GR4JNode{P, A<: AbstractFloat } <: GRNJNode
69+ const name:: String
70+ const area:: A
7071
7172 # parameters
7273 X1:: P = Param (350.0 , bounds= (1.0 , 1500.0 ))
@@ -80,21 +81,37 @@ Base.@kwdef mutable struct GR4JNode{P, A<:Real} <: GRNJNode
8081 # x4 : time base of unit hydrograph UH1 (days, > 0.5)
8182
8283 # stores
83- p_store:: Array {A} = [0.0 ]
84- r_store:: Array {A} = [0.0 ]
84+ p_store:: Vector {A} = [0.0 ]
85+ r_store:: Vector {A} = [0.0 ]
8586
86- UH1:: Array{Array {A}} = []
87- UH2:: Array{Array {A}} = []
87+ UH1:: Vector{Vector {A}} = []
88+ UH2:: Vector{Vector {A}} = []
8889
89- outflow:: Array{A} = []
90+ uh1_ordinates:: Vector{A} = []
91+ uh2_ordinates:: Vector{A} = []
92+
93+ outflow:: Vector{A} = []
9094end
9195
9296
93- # function prep_state!(node::HyModNode, sim_length::Int64)
94- # node.UH1 = fill(undef, sim_length)
95- # node.UH2 = fill(undef, sim_length)
96- # node.outflow = fill(undef, sim_length)
97- # end
97+ function prep_state! (node:: GR4JNode , timesteps:: Int64 )
98+ resize! (node. p_store, timesteps+ 1 )
99+ resize! (node. r_store, timesteps+ 1 )
100+ node. p_store[2 : end ] .= 0.0
101+ node. r_store[2 : end ] .= 0.0
102+
103+ # Prep cache
104+ X4 = node. X4. val
105+ nUH1 = Int (ceil (X4))
106+ nUH2 = Int (ceil (2.0 * X4))
107+ cUH1, cUH2 = fill (0.0 , nUH1), fill (0.0 , nUH2)
108+ node. UH1 = fill (cUH1, timesteps)
109+ node. UH2 = fill (cUH2, timesteps)
110+ node. uh1_ordinates = Vector {Float64} (undef, nUH1)
111+ node. uh2_ordinates = Vector {Float64} (undef, nUH2)
112+
113+ node. outflow = fill (0.0 , timesteps)
114+ end
98115
99116
100117function GR4JNode (name:: String , spec:: Dict )
@@ -129,22 +146,6 @@ function GR4JNode(name::String, spec::Dict)
129146end
130147
131148
132- """
133- run_node!(node::GR4JNode, climate::Climate)
134-
135- Run GR4J node for all time steps in given climate sequence.
136- """
137- function run_node! (node:: GR4JNode , climate:: Climate ; inflow= nothing , extraction= nothing , exchange= nothing )
138- timesteps = sim_length (climate)
139- # prep_state!(node, sim_length)
140- for ts in 1 : timesteps
141- run_timestep! (node, climate, ts; inflow= inflow, extraction= extraction, exchange= exchange)
142- end
143-
144- return node. outflow
145- end
146-
147-
148149"""
149150 run_timestep!(node::GR4JNode, climate::Climate, timestep::Int;
150151 inflow::Float64, extraction::Float64, exchange::Float64)
@@ -158,8 +159,10 @@ function run_timestep!(node::GR4JNode, climate::Climate, timestep::Int; inflow=n
158159end
159160
160161
161- function run_timestep! (node:: GR4JNode , rain, et, ts; inflow= nothing , extraction= nothing , exchange= nothing )
162- res = run_gr4j (rain, et, node. X1, node. X2, node. X3, node. X4, node. area, node. p_store[end ], node. r_store[end ])
162+ function run_timestep! (node:: GR4JNode , rain:: Float64 , et:: Float64 , ts:: Int64 ; inflow= nothing , extraction= nothing , exchange= nothing )
163+ uh1_cache = node. uh1_ordinates
164+ uh2_cache = node. uh2_ordinates
165+ res = run_gr4j (rain, et, node. X1. val, node. X2. val, node. X3. val, node. X4. val, node. area, node. UH1[ts], node. UH2[ts], uh1_cache, uh2_cache, node. p_store[ts], node. r_store[ts])
163166 Q, p_s, r_s, UH1, UH2 = res
164167
165168 node_name = node. name
@@ -171,7 +174,7 @@ function run_timestep!(node::GR4JNode, rain, et, ts; inflow=nothing, extraction=
171174 Q = Q + in_flow + ex - wo
172175 end
173176
174- update_state! (node, p_s, r_s, Q, UH1, UH2)
177+ update_state! (node, ts, p_s, r_s, Q, UH1, UH2)
175178end
176179
177180
@@ -182,6 +185,16 @@ function update_state!(node::GR4JNode, ps, rs, q, UH1, UH2)
182185 push! (node. UH1, UH1)
183186 push! (node. UH2, UH2)
184187end
188+ function update_state! (node:: GR4JNode , ts:: Int64 , ps, rs, q, UH1, UH2):: Nothing
189+ node. p_store[ts+ 1 ] = ps
190+ node. r_store[ts+ 1 ] = rs
191+ node. outflow[ts] = q
192+
193+ node. UH1[ts] = UH1
194+ node. UH2[ts] = UH2
195+
196+ return nothing
197+ end
185198
186199
187200function update_params! (node:: GR4JNode , X1:: Float64 , X2:: Float64 , X3:: Float64 , X4:: Float64 ):: Nothing
@@ -218,12 +231,12 @@ end
218231
219232Determine unit hydrograph ordinates.
220233"""
221- function s_curve (t, x4; uh2:: Bool = false ):: Float64
234+ function s_curve (t:: F , x4:: F ; uh2:: Bool = false ):: F where {F <: Float64 }
222235 if t <= 0.0
223236 return 0.0
224237 end
225238
226- ordinate:: Float64 = 0.0
239+ ordinate:: F = 0.0
227240 if t < x4
228241 ordinate = (t/ x4)^ 2.5
229242 else
@@ -258,14 +271,10 @@ Generated simulated streamflow for given rainfall and potential evaporation.
258271# Returns
259272- tuple of simulated outflow [ML/day], and intermediate states: p_store, r_store, UH1, UH2
260273"""
261- function run_gr4j (P, E, X1, X2, X3, X4, area, p_store= 0.0 , r_store= 0.0 ):: Tuple
262- nUH1 = Int (ceil (X4))
263- nUH2 = Int (ceil (2.0 * X4))
264-
265- uh1_ordinates = Array {Float64} (undef, nUH1)
266- uh2_ordinates = Array {Float64} (undef, nUH2)
267-
268- UH1, UH2 = fill (0.0 , nUH1), fill (0.0 , nUH2)
274+ function run_gr4j (P:: F , E:: F , X1:: F , X2:: F , X3:: F , X4:: F , area:: F , UH1:: Vector{Float64} , UH2:: Vector{Float64} , uh1_ordinates:: Vector{Float64} , uh2_ordinates:: Vector{Float64} , p_store= 0.0 , r_store= 0.0 ):: Tuple where {F<: Float64 }
275+ # Main.@infiltrate
276+ nUH1:: Int64 = Int (ceil (X4))
277+ nUH2:: Int64 = Int (ceil (2.0 * X4))
269278
270279 @inbounds for t in 2 : (nUH1+ 1 )
271280 t_f = Float64 (t)
@@ -277,7 +286,7 @@ function run_gr4j(P, E, X1, X2, X3, X4, area, p_store=0.0, r_store=0.0)::Tuple
277286 uh2_ordinates[t - 1 ] = s_curve (t_f, X4, uh2= true ) - s_curve (t_f- 1.0 , X4, uh2= true )
278287 end
279288
280- Q = 0.0
289+ Q:: F = 0.0
281290 if P > E
282291 net_evap = 0.0
283292 scaled_net_precip = min ((P - E)/ X1, 13.0 )
@@ -303,12 +312,11 @@ function run_gr4j(P, E, X1, X2, X3, X4, area, p_store=0.0, r_store=0.0)::Tuple
303312
304313 p_store = p_store - net_evap + reservoir_production
305314
306- tmp_a = (p_store / 2.25 / X1)^ 4
307- tmp_b = (1 + tmp_a)^ 0.25
315+ tmp_a:: F = (p_store / 2.25 / X1)^ 4
316+ tmp_b:: F = (1 + tmp_a)^ 0.25
308317 percolation = p_store / tmp_b
309318
310319 routed_volume = routed_volume + (p_store- percolation)
311- p_store = percolation
312320
313321 @inbounds for i in 1 : nUH1- 1
314322 UH1[i] = UH1[i+ 1 ] + uh1_ordinates[i]* routed_volume
@@ -321,7 +329,7 @@ function run_gr4j(P, E, X1, X2, X3, X4, area, p_store=0.0, r_store=0.0)::Tuple
321329 UH2[end ] = uh2_ordinates[end ] * routed_volume
322330
323331 tmp_a = (r_store / X3)^ 3.5
324- groundwater_exchange = X2 * tmp_a
332+ groundwater_exchange:: F = X2 * tmp_a
325333 r_store = max (0.0 , r_store + UH1[1 ] * 0.9 + groundwater_exchange)
326334
327335 tmp_a = (r_store / X3)^ 4
@@ -333,5 +341,5 @@ function run_gr4j(P, E, X1, X2, X3, X4, area, p_store=0.0, r_store=0.0)::Tuple
333341
334342 Q = (QR + QD) * area
335343
336- return Q, p_store , r_store, UH1, UH2
344+ return Q, percolation , r_store, UH1, UH2
337345end
0 commit comments