Skip to content

Commit 4ef9042

Browse files
Merge pull request #35 from ConnectedSystems/doc-cleanup
Minor doc updates
2 parents 7eb0ab8 + 80169e7 commit 4ef9042

File tree

10 files changed

+143
-148
lines changed

10 files changed

+143
-148
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
fail-fast: false
1414
matrix:
1515
version:
16-
- '1.10' # Replace this with the minimum Julia version that your package supports. E.g. if your package requires Julia 1.5 or higher, change this to '1.5'.
16+
- '1.11' # Replace this with the minimum Julia version that your package supports. E.g. if your package requires Julia 1.5 or higher, change this to '1.5'.
1717
- '1' # Leave this line unchanged. '1' will automatically expand to the latest stable 1.x release of Julia.
1818
- 'nightly'
1919
os:

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ CodecZlib = "0.7"
5252
Compose = "0.9"
5353
DataFrames = "1.6"
5454
DataStructures = "0.18.10"
55+
Dates = "1.11.0"
5556
Distributions = "0.25.100"
5657
GR = "0.72.9, 0.73"
5758
GR_jll = "0.73"

README.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
Streamfall leverages the Julia language and ecosystem to provide:
1010
- Quick heterogeneous modelling of a stream network
1111
- Use of different rainfall-runoff models and their ensembles in tandem
12-
- Modelling and assessment of interacting systems
12+
- Support for modelling and assessment of interacting systems
1313
- A wide range of performance metrics
1414

1515
This package includes implementations of the following:
@@ -20,12 +20,21 @@ This package includes implementations of the following:
2020

2121
Performance is expected to be similar to implementations in C and Fortran.
2222

23+
Naive timings (using `@time`) for an example dataset spanning 1963-07-05 - 2014-12-31 (18808 days, approximately 51.5 years)
24+
25+
- SimpleHyModNode \
26+
0.016502 seconds (469.25 k allocations: 12.902 MiB)
27+
- GR4JNode \
28+
0.015274 seconds (224.75 k allocations: 5.584 MiB)
29+
- SYMHYDNode \
30+
0.039540 seconds (638.01 k allocations: 15.190 MiB, 46.99% gc time)
31+
- IHACRESBilinearNode \
32+
0.021734 seconds (675.63 k allocations: 17.773 MiB)
33+
2334
The IHACRES rainfall-runoff model was previously implemented with [ihacres_nim](https://github.com/ConnectedSystems/ihacres_nim) but has since been ported to pure Julia.
2435

2536
[Graphs](https://github.com/JuliaGraphs/Graphs.jl) and [MetaGraphs](https://github.com/JuliaGraphs/MetaGraphs.jl) are used underneath for network traversal/analysis.
2637

27-
> [NOTE] Streamfall is currently in its early stages and under active development. Although it is fairly usable for small networks and assessing/analyzing single sub-catchments, things may change drastically and unexpectedly.
28-
2938
## Installation
3039

3140
Streamfall is now registered! The latest release version can be installed with:

docs/src/API/nodes/IHACRES.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,3 @@ Modules = [Streamfall]
55
Order = [:function, :type]
66
Pages = ["Nodes/IHACRES/IHACRESNode.jl"]
77
```
8-
9-
### IHACRES - Expuh
10-
11-
```@autodocs
12-
Modules = [Streamfall]
13-
Order = [:function, :type]
14-
Pages = ["IHACRESExpuhNode.jl"]
15-
```

examples/node_comparison.jl

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using Distributed, Plots, StatsPlots
1+
using Distributed
2+
using Plots
3+
24

35
N = 4
46
if nworkers() < N
@@ -18,23 +20,23 @@ end
1820
comment="#",
1921
dateformat=date_format) |> DataFrame
2022

21-
hist_streamflow = obs_data[:, ["Date", "410730_Q"]]
23+
hist_streamflow = extract_flow(obs_data, "410730")
2224
climate_data = obs_data[:, ["Date", "410730_P", "410730_PET"]]
2325
climate = Climate(climate_data, "_P", "_PET")
2426

2527
burn_in = 366 # 1 year burn-in period
2628

2729
# Create objective function to minimize (here we use Normalized KGE')
2830
func = (obs, sim) -> 1.0 - Streamfall.NmKGE(obs[burn_in:end], sim[burn_in:end])
29-
opt_func = (node) -> calibrate!(node, climate, hist_streamflow[:, "410730_Q"]; metric=func, MaxTime=900)
31+
opt_func = (node) -> calibrate!(node, climate, hist_streamflow[:, "410730"], func; MaxTime=30)
3032
end
3133

3234

3335
# Create individual nodes
3436
hymod_node = create_node(SimpleHyModNode, "410730", 129.2)
3537
gr4j_node = create_node(GR4JNode, "410730", 129.2)
3638
symhyd_node = create_node(SYMHYDNode, "410730", 129.2)
37-
ihacres_node = create_node(BilinearNode, "410730", 129.2)
39+
ihacres_node = create_node(IHACRESBilinearNode, "410730", 129.2)
3840

3941

4042
# Calibrate each node separately using multiprocessing
@@ -44,14 +46,14 @@ result = pmap(opt_func, node_list)
4446

4547

4648
# Create comparison plot
47-
Qo = hist_streamflow[:, "410730_Q"]
48-
Qo_burn = Qo[burn_in:end]
49+
Qo = hist_streamflow[:, "410730"]
4950
res_plots = []
5051

5152
for ((res, opt), node, n_name) in zip(result, node_list, node_names)
5253
update_params!(node, best_candidate(res)...)
5354
reset!(node)
54-
run_node!(node, climate)
55+
@info typeof(node)
56+
@time run_node!(node, climate)
5557

5658
node_burn = node.outflow[burn_in:end]
5759

@@ -68,4 +70,4 @@ combined_plot = plot(
6870

6971
display(combined_plot)
7072

71-
savefig("multi_model_comparison_updated.png")
73+
# savefig("multi_model_comparison_updated.png")

src/Nodes/GR4J/GR4JNode.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ abstract type GRNJNode <: NetworkNode end
4646
"""
4747
GR4J Node
4848
49+
GR4J: modèle du Génie Rural à 4 paramètres Journalier.
50+
4951
A four-parameter model with two stores.
5052
5153
# Parameters
@@ -287,7 +289,7 @@ end
287289
p_store=0.0, r_store=0.0
288290
)::Tuple where {F<:Float64}
289291
290-
Generated simulated streamflow for given rainfall and potential evaporation.
292+
Generated simulated streamflow with GR4J for given rainfall and potential evaporation.
291293
292294
# Parameters
293295
- `P` : Catchment average rainfall
Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
"""
2+
Current disabled.
3+
4+
Expuh node implementation needs to be updated to use pure julia methods.
5+
"""
6+
17
using Parameters
28
using ModelParameters
39

410

5-
Base.@kwdef mutable struct ExpuhNode{P, A<:AbstractFloat} <: IHACRESNode
11+
Base.@kwdef mutable struct ExpuhNode{P,A<:AbstractFloat} <: IHACRESNode
612
name::String
713
area::A
814

@@ -95,9 +101,9 @@ end
95101

96102

97103
function ExpuhNode(name::String, area::Float64, d::Float64, d2::Float64, e::Float64, f::Float64,
98-
tau_q::Float64, tau_s::Float64, v_s::Float64, s_coef::Float64,
99-
store::Float64, quick::Float64, slow::Float64)
100-
return ExpuhNode{Param, Float64}(
104+
tau_q::Float64, tau_s::Float64, v_s::Float64, s_coef::Float64,
105+
store::Float64, quick::Float64, slow::Float64)
106+
return ExpuhNode{Param,Float64}(
101107
name=name,
102108
area=area,
103109
d=d,
@@ -165,23 +171,21 @@ function run_node!(
165171

166172
flow_res = [0.0, 0.0, 0.0]
167173
@ccall IHACRES.calc_flows(flow_res::Ptr{Cdouble}, prev_q::Cdouble, prev_s::Cdouble, s_node.v_s::Cdouble, e_rainfall::Cdouble,
168-
s_node.area::Cdouble, s_node.tau_q::Cdouble, s_node.tau_s::Cdouble)::Cvoid
174+
s_node.area::Cdouble, s_node.tau_q::Cdouble, s_node.tau_s::Cdouble)::Cvoid
169175
(quick_store, slow_store, outflow) = flow_res
170176

171177
gw_store = s_node.gw_store[end]
172178
routing_res = [0.0, 0.0]
173179
@ccall IHACRES.routing(
174-
routing_res::Ptr{Cdouble},
175-
gw_store::Cdouble,
176-
s_node.storage_coef::Cdouble,
177-
inflow::Cdouble,
178-
outflow::Cdouble,
179-
ext::Cdouble,
180-
gw_exchange::Cdouble)::Cvoid
180+
routing_res::Ptr{Cdouble},
181+
gw_store::Cdouble,
182+
s_node.storage_coef::Cdouble,
183+
inflow::Cdouble,
184+
outflow::Cdouble,
185+
ext::Cdouble,
186+
gw_exchange::Cdouble)::Cvoid
181187
(gw_store, outflow) = routing_res
182188

183-
# level::Float64 = @ccall IHACRES.calc_ft_level(outflow::Cdouble, s_node.level_params::Ptr{Cdouble})::Cdouble
184-
185189
update_state!(s_node, cmd, e_rainfall, et, quick_store, slow_store, outflow, gw_store)
186190

187191
return outflow
@@ -211,19 +215,19 @@ function run_node_with_temp!(s_node::ExpuhNode, rain::Float64, temp::Float64, in
211215

212216
flow_res = [0.0, 0.0, 0.0]
213217
@ccall IHACRES.calc_flows(flow_res::Ptr{Cdouble}, prev_q::Cdouble, prev_s::Cdouble, s_node.v_s::Cdouble, e_rainfall::Cdouble,
214-
s_node.area::Cdouble, s_node.tau_q::Cdouble, s_node.tau_s::Cdouble)::Cvoid
218+
s_node.area::Cdouble, s_node.tau_q::Cdouble, s_node.tau_s::Cdouble)::Cvoid
215219
(quick_store, slow_store, outflow) = flow_res
216220

217221
gw_store = s_node.gw_store[end]
218222
routing_res = [0.0, 0.0]
219223
@ccall IHACRES.routing(
220-
routing_res::Ptr{Cdouble},
221-
gw_store::Cdouble,
222-
s_node.storage_coef::Cdouble,
223-
inflow::Cdouble,
224-
outflow::Cdouble,
225-
ext::Cdouble,
226-
gw_exchange::Cdouble)::Cvoid
224+
routing_res::Ptr{Cdouble},
225+
gw_store::Cdouble,
226+
s_node.storage_coef::Cdouble,
227+
inflow::Cdouble,
228+
outflow::Cdouble,
229+
ext::Cdouble,
230+
gw_exchange::Cdouble)::Cvoid
227231
(gw_store, outflow) = routing_res
228232

229233
# level::Float64 = @ccall IHACRES.calc_ft_level(outflow::Cdouble, s_node.level_params::Ptr{Cdouble})::Cdouble
@@ -235,7 +239,7 @@ end
235239

236240

237241
function update_params!(node::ExpuhNode, d::Float64, d2::Float64, e::Float64, f::Float64,
238-
tau_q::Float64, tau_s::Float64, v_s::Float64, s_coef::Float64)::Nothing
242+
tau_q::Float64, tau_s::Float64, v_s::Float64, s_coef::Float64)::Nothing
239243
node.d = Param(d, bounds=node.d.bounds)
240244
node.d2 = Param(d2, bounds=node.d2.bounds)
241245
node.e = Param(e, bounds=node.e.bounds)

src/Streamfall.jl

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,13 @@ using Graphs, MetaGraphs, Distributed, DataFrames
66

77
const MODPATH = @__DIR__
88

9-
if Sys.iswindows()
10-
libext = ".dll"
11-
elseif Sys.islinux()
12-
libext = ".so"
13-
elseif Sys.isapple()
14-
libext = ".dynlib"
15-
else
16-
throw(DomainError("Unsupported platform"))
17-
end
18-
19-
# Can't use string, DLL location has to be a const
20-
# (which makes sense but still, many hours wasted!)
21-
# https://github.com/JuliaLang/julia/issues/29602
22-
const IHACRES = joinpath(MODPATH, "../deps", "usr", "lib", "ihacres$(libext)")
23-
24-
259
include("Network.jl")
2610
include("Nodes/Node.jl")
2711
include("Climate.jl")
2812
include("metrics.jl")
2913
include("calibration.jl")
3014
include("Nodes/IHACRES/IHACRESNode.jl")
31-
include("Nodes/IHACRES/IHACRESExpuhNode.jl")
15+
# include("Nodes/IHACRES/IHACRESExpuhNode.jl")
3216
include("Nodes/GR4J/GR4JNode.jl")
3317
include("Nodes/HyMod/HyModNode.jl")
3418
include("Nodes/SYMHYD/SYMHYDNode.jl")
@@ -37,9 +21,9 @@ include("Nodes/Ensembles/EnsembleNode.jl")
3721

3822

3923
function timestep_value(ts::Int, gauge_id::String, col_partial::String, dataset::DataFrame)::Float64
40-
target_col = filter(x -> occursin(gauge_id, x)
41-
& occursin(col_partial, x),
42-
names(dataset)
24+
target_col = filter(
25+
x -> occursin(gauge_id, x) & occursin(col_partial, x),
26+
names(dataset)
4327
)
4428

4529
amount = 0.0
@@ -107,7 +91,7 @@ julia> climate, streamflow = align_time_frame(climate, streamflow)
10791
"""
10892
function align_time_frame(timeseries::T...) where {T<:DataFrame}
10993
min_date, max_date = find_common_timeframe(timeseries...)
110-
modded = [t[min_date .<= t.Date .<= max_date, :] for t in timeseries]
94+
modded = [t[min_date.<=t.Date.<=max_date, :] for t in timeseries]
11195

11296
for t in modded
11397
ts_diff = diff(t.Date)
@@ -137,7 +121,7 @@ function run_basin!(
137121
_, outlets = find_inlets_and_outlets(sn)
138122
@inbounds for outlet_id in outlets
139123
run_node!(sn, outlet_id, climate;
140-
inflow=inflow, extraction=extraction, exchange=exchange)
124+
inflow=inflow, extraction=extraction, exchange=exchange)
141125
end
142126
end
143127

@@ -294,9 +278,9 @@ include("plotting.jl")
294278

295279
# Nodes
296280
export NetworkNode, GenericNode, GenericDirectNode
297-
export IHACRES, IHACRESNode, IHACRESBilinearNode, ExpuhNode, DamNode, Climate
281+
export IHACRES, IHACRESNode, IHACRESBilinearNode, DamNode, Climate
298282
export create_node, GR4JNode, HyModNode, SimpleHyModNode, SYMHYDNode
299-
export EnsembleNode, WeightedEnsembleNode
283+
export EnsembleNode, WeightedEnsembleNode, GREnsembleNode
300284

301285
# Network
302286
export find_inlets_and_outlets, inlets, outlets

src/metrics.jl

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,10 @@ end
139139
"""
140140
NSE(obs, sim)
141141
142-
The Nash-Sutcliffe Efficiency score
142+
The Nash-Sutcliffe Efficiency score.
143+
144+
Ranges from 1.0 to -∞, where values below zero indicate the mean of
145+
observations would outperform a model.
143146
"""
144147
function NSE(obs, sim)
145148
return 1.0 - sum((obs .- sim) .^ 2) / sum((obs .- mean(obs)) .^ 2)
@@ -164,7 +167,7 @@ end
164167
"""
165168
RMSE(obs, sim)
166169
167-
Root Mean Square Error
170+
Root Mean Square Error.
168171
"""
169172
function RMSE(obs, sim)
170173
return (sum((sim .- obs) .^ 2) / length(sim))^0.5
@@ -186,7 +189,7 @@ end
186189
"""
187190
ADJ_R2(obs, sim, p::Int64)::Float64
188191
189-
Adjusted R²
192+
Adjusted R².
190193
191194
# Arguments
192195
- `obs::Vector` : observations
@@ -204,15 +207,15 @@ end
204207
"""
205208
MAE(obs, sim)
206209
207-
Mean Absolute Error
210+
Mean Absolute Error.
208211
"""
209212
MAE(obs, sim) = mean(abs.(sim .- obs))
210213

211214

212215
"""
213216
ME(obs, sim)
214217
215-
Mean Error
218+
Mean Error.
216219
"""
217220
ME(obs, sim) = mean(sim .- obs)
218221

@@ -471,7 +474,7 @@ function mKGE(obs, sim; scaling=(1.0, 1.0, 1.0))::Float64
471474
# Timing (Pearson's correlation)
472475
r = Statistics.cor(obs, sim)
473476
if isnan(r)
474-
# can happen if obs or sim is a constant (std of 0)
477+
# Can happen if obs or sim is a constant (std of 0)
475478
r = all(obs .== sim) ? 1.0 : 0.0
476479
end
477480

0 commit comments

Comments
 (0)