Skip to content

Commit 04a4c18

Browse files
Add state prepping interface
1 parent 65e9385 commit 04a4c18

File tree

4 files changed

+98
-2
lines changed

4 files changed

+98
-2
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,9 @@ through all relevant nodes upstream.
252252
```julia
253253
@info "Running example stream..."
254254
timesteps = sim_length(climate)
255+
256+
reset!(sn)
257+
prep_state!(sn, timesteps)
255258
for ts in (1:timesteps)
256259
for outlet in outlets
257260
run_node!(sn[outlet], climate, ts)

src/Streamfall.jl

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,17 @@ function find_common_timeframe(timeseries::T...) where {T<:DataFrame}
8282
return (min_date, max_date)
8383
end
8484

85+
"""
86+
prep_state!(sn::StreamfallNetwork, timesteps::Int64)::Nothing
87+
88+
Prepare a network for a run by pre-allocating result stores.
89+
"""
90+
function prep_state!(sn::StreamfallNetwork, timesteps::Int64)::Nothing
91+
for node in sn
92+
prep_state!(node, timesteps)
93+
end
94+
end
95+
8596

8697
"""
8798
align_time_frame(timeseries::T...)
@@ -268,7 +279,7 @@ export EnsembleNode, BaseEnsemble
268279
# Network
269280
export find_inlets_and_outlets, inlets, outlets
270281
export climate_values, node_names, get_node, get_node_id, get_prop, set_prop!
271-
export param_info, update_params!, sim_length, reset!
282+
export param_info, update_params!, sim_length, reset!, prep_state!
272283
export run_catchment!, run_basin!, run_node!, run_node_with_temp!
273284
export run_timestep!
274285
export calibrate!

test/runtests.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,5 +178,6 @@ end
178178

179179
include("test_metrics.jl")
180180
include("test_data_op.jl")
181+
include("test_nodes.jl")
181182
include("test_networks.jl")
182-
include("test_calibration.jl")
183+
include("test_calibration.jl")

test/test_nodes.jl

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using Test
2+
using OrderedCollections
3+
4+
using CSV, YAML
5+
using Dates
6+
using DataFrames
7+
using Streamfall
8+
9+
10+
@testset "Running nodes with interactions" begin
11+
# Load a network from a file, providing a name for the network and the file path.
12+
# Creates a graph representation of the stream with associated metadata.
13+
sn = load_network("Example Network", "../test/data/campaspe/campaspe_network.yml")
14+
15+
# Load climate data, in this case from a CSV file with data for all nodes.
16+
climate_data = CSV.read(
17+
"../test/data/campaspe/climate/climate_historic.csv", DataFrame,
18+
comment="#",
19+
dateformat="YYYY-mm-dd"
20+
)
21+
22+
# Indicate which columns are precipitation and evaporation data based on partial identifiers
23+
climate = Climate(climate_data, "_rain", "_evap")
24+
25+
run_catchment!(sn, climate)
26+
node_id, node = sn["406219"]
27+
28+
# Run up to a point in the stream for all time steps.
29+
# All nodes upstream will be run as well (but not those downstream)
30+
run_node!(sn, node_id, climate)
31+
32+
baseline_outflow = node.outflow
33+
34+
# Reset a node (clears stored states)
35+
reset!(node)
36+
37+
# Run a specific node, and only a specific node, for all time steps
38+
inflow = 10.0 # inflows for each time step
39+
extractions = 0.0 # extractions from stream for each time step
40+
gw_flux = 0.0 # forced groundwater interactions for each time step
41+
run_node!(node, climate; inflow=inflow, extraction=extractions, exchange=gw_flux)
42+
perturbed1 = node.outflow
43+
44+
reset!(node)
45+
inflow = 10.0 # inflows for each time step
46+
extractions = 5.0 # extractions from stream for each time step
47+
gw_flux = 0.0 # forced groundwater interactions for each time step
48+
run_node!(node, climate; inflow=inflow, extraction=extractions, exchange=gw_flux)
49+
perturbed2 = node.outflow
50+
51+
reset!(sn)
52+
inflow = 10.0 # inflows for each time step
53+
extractions = 5.0 # extractions from stream for each time step
54+
gw_flux = 2.0 # forced groundwater interactions for each time step
55+
inlets, outlets = find_inlets_and_outlets(sn)
56+
57+
# Manual interactions
58+
timesteps = sim_length(climate)
59+
prep_state!(sn, timesteps)
60+
for ts in (1:timesteps)
61+
for outlet in outlets
62+
run_node!(sn[outlet], climate, ts; inflow=inflow, extraction=extractions, exchange=gw_flux)
63+
end
64+
end
65+
66+
node_id, node = sn["406219"]
67+
perturbed3 = node.outflow
68+
69+
@info length(baseline_outflow) length(perturbed1) length(perturbed2) length(perturbed3)
70+
@info all((baseline_outflow .+ 10.0) .== perturbed1)
71+
@info sum((baseline_outflow .+ 10.0) .- perturbed1)
72+
73+
@test all(baseline_outflow .!= perturbed1 .!= perturbed2 .!= perturbed3) || "Perturbations resulted in identical streamflows"
74+
75+
# Check that additional interactions are accounted for.
76+
# Cannot check for equivalence due to computational error, so we test that the
77+
# difference is within acceptable bounds.
78+
@test all((baseline_outflow .+ 10.0 .- perturbed1) .< 0.0005) || "Additional inflow not accounted for"
79+
@test all((baseline_outflow .+ 5.0 .- perturbed2) .< 0.0005) || "Extractions not accounted for"
80+
end
81+

0 commit comments

Comments
 (0)