Skip to content

Commit 8c75e36

Browse files
Mass WIP commit to reflect changes in Graph representation
1 parent ac76da5 commit 8c75e36

File tree

3 files changed

+193
-117
lines changed

3 files changed

+193
-117
lines changed

src/Network.jl

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
1+
using OrderedCollections
2+
13
using Cairo, Compose
24
using Graphs, MetaGraphs, GraphPlot
35
using ModelParameters
46

5-
import YAML: write_file
7+
import YAML: load_file, write_file
68

79

810
struct StreamfallNetwork
911
mg::MetaDiGraph
1012
end
1113

14+
function load_network(name::String, fn::String)
15+
network = load_file(
16+
fn;
17+
dicttype=OrderedDict
18+
)
19+
20+
return create_network(name, network)
21+
end
22+
1223

1324
Base.getindex(sn::StreamfallNetwork, n::String) = get_node(sn, n)
1425
Base.getindex(sn::StreamfallNetwork, nid::Int) = get_node(sn, nid)
1526

27+
function node_names(sn::StreamfallNetwork)
28+
verts = vertices(sn.mg)
29+
return [sn[v].name for v in verts]
30+
end
1631

1732
function set_prop!(sn::StreamfallNetwork, nid::Int64, prop::Symbol, var::Any)::Nothing
1833
MetaGraphs.set_prop!(sn.mg, nid, prop, var)
@@ -111,15 +126,15 @@ end
111126

112127

113128
"""
114-
create_node(mg::MetaDiGraph, node_name::String, details::Dict, nid::Int)
129+
create_node(mg::MetaDiGraph, node_name::String, details::OrderedDict, nid::Int)
115130
116131
Create a node specified with given name (if it does not exist).
117132
118-
Returns
119-
- `this_id`, ID of node (if pre-existing) and
133+
Returns
134+
- `this_id`, ID of node (if pre-existing) and
120135
- `nid`, incremented node id for entire network (equal to `this_id` if exists)
121136
"""
122-
function create_node(mg::MetaDiGraph, node_name::String, details::Dict, nid::Int)
137+
function create_node(mg::MetaDiGraph, node_name::String, details::OrderedDict, nid::Int)
123138
details = copy(details)
124139

125140
match = collect(MetaGraphs.filter_vertices(mg, :name, node_name))
@@ -149,46 +164,47 @@ function create_node(mg::MetaDiGraph, node_name::String, details::Dict, nid::Int
149164
set_props!(mg, nid, Dict(:name=>node_name,
150165
:node=>n,
151166
:nfunc=>func))
152-
167+
153168
this_id = nid
154-
nid = nid + 1
155169
else
156170
this_id = match[1]
157171
end
158172

159-
return this_id, nid
173+
return this_id
160174
end
161175

162176

163177
"""
164-
create_network(name::String, network::Dict)::StreamfallNetwork
178+
create_network(name::String, network::OrderedDict)::StreamfallNetwork
165179
166180
Create a StreamNetwork from a YAML-derived specification.
167181
168182
# Example
169183
```julia-repl
170-
julia> network_spec = YAML.load_file("example_network.yml")
184+
julia> using OrderedCollections
185+
julia> network_spec = YAML.load_file("example_network.yml"; dicttype=OrderedDict{Any,Any})
171186
julia> sn = create_network("Example Network", network_spec)
172187
```
173188
"""
174-
function create_network(name::String, network::Dict)::StreamfallNetwork
189+
function create_network(name::String, network::OrderedDict)::StreamfallNetwork
175190
num_nodes = length(network)
176191
mg = MetaDiGraph(num_nodes)
177192
MetaGraphs.set_prop!(mg, :description, name)
178-
179-
nid = 1
180-
for (node, details) in network
193+
194+
for (nid, (node, details)) in enumerate(network)
181195
n_name = string(node)
182196

183-
this_id, nid = create_node(mg, n_name, details, nid)
197+
this_id = create_node(mg, n_name, details, nid)
184198

185199
if haskey(details, "inlets")
186200
inlets = details["inlets"]
187-
188201
if !isnothing(inlets)
189202
for inlet in inlets
190-
in_id, nid = create_node(mg, string(inlet), network[inlet], nid)
191-
add_edge!(mg, in_id => this_id)
203+
204+
inlet_id = findall(keys(network) .== inlet)[1]
205+
206+
in_id = create_node(mg, string(inlet), network[inlet], inlet_id)
207+
add_edge!(mg, inlet_id => nid)
192208
end
193209
end
194210
end
@@ -200,8 +216,9 @@ function create_network(name::String, network::Dict)::StreamfallNetwork
200216
@assert length(outlets) <= 1 || throw(ArgumentError(msg))
201217

202218
for outlet in outlets
203-
out_id, nid = create_node(mg, string(outlet), network[outlet], nid)
204-
add_edge!(mg, this_id => out_id)
219+
outlet_id = findall(keys(network) .== outlet)[1]
220+
out_id = create_node(mg, string(outlet), network[outlet], outlet_id)
221+
add_edge!(mg, nid => outlet_id)
205222
end
206223
end
207224
end
@@ -303,10 +320,18 @@ function Base.show(io::IO, sn::StreamfallNetwork)
303320

304321
vs = vertices(sn.mg)
305322

306-
for nid in vs
307-
println(io, "Node $(nid) : \n")
323+
show_verts = vs
324+
if length(vs) > 4
325+
show_verts = [1, 2, nothing, length(vs)-1, length(vs)]
326+
end
327+
328+
for nid in show_verts
329+
if isnothing(nid)
330+
println(io, "\n")
331+
continue
332+
end
333+
println(io, "Node $(nid): \n")
308334
show(io, sn[nid])
309-
print("\n")
310335
end
311336
end
312337

@@ -317,15 +342,15 @@ end
317342
Simple plot of stream network.
318343
"""
319344
function plot_network(sn::StreamfallNetwork; as_html=false)
320-
node_names = ["$(n.name)" for n in sn]
345+
node_labels = ["$(sn[i].name)\n"*string(nameof(typeof(sn[i]))) for i in vertices(sn.mg)]
321346

322347
if as_html
323348
plot_func = gplothtml
324349
else
325350
plot_func = gplot
326351
end
327352

328-
plot_func(sn.mg, nodelabel=node_names)
353+
plot_func(sn.mg, nodelabel=node_labels)
329354
end
330355

331356

src/Nodes/DamNode.jl

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -56,33 +56,31 @@ Base.@kwdef mutable struct DamNode{P, A<:AbstractFloat} <: NetworkNode
5656
level::Array{A} = []
5757
discharge::Array{A} = []
5858
outflow::Array{A} = []
59-
6059
end
6160

6261

6362
function DamNode(
6463
name::String,
65-
area::Float64,
66-
max_storage::Float64,
67-
storage_coef::Float64,
68-
initial_storage::Float64,
64+
area::F,
65+
max_storage::F,
66+
storage_coef::F,
67+
initial_storage::F,
6968
calc_dam_level::Function,
7069
calc_dam_area::Function,
7170
calc_dam_discharge::Function,
72-
calc_dam_outflow::Function)
71+
calc_dam_outflow::Function) where {F<:Float64}
7372
return DamNode(name, area, max_storage, storage_coef,
7473
calc_dam_level, calc_dam_area, calc_dam_discharge, calc_dam_outflow,
75-
[initial_storage], [], [], [], [], [], [], [])
74+
F[initial_storage], F[], F[], F[], F[], F[], F[], F[])
7675
end
7776

78-
7977
"""
8078
DamNode(name::String, spec::Dict)
8179
8280
Create DamNode from a given specification.
8381
"""
84-
function DamNode(name::String, spec::Dict)
85-
n = DamNode{Param}(; name=name, area=spec["area"],
82+
function DamNode(name::String, spec::Union{Dict,OrderedDict})
83+
n = DamNode{Param,Float64}(; name=name, area=spec["area"],
8684
max_storage=spec["max_storage"])
8785

8886
node_params = spec["parameters"]
@@ -127,8 +125,22 @@ function storage(node::DamNode)
127125
return last(node.storage)
128126
end
129127

128+
function prep_state!(node::DamNode, timesteps::Int64)
129+
resize!(node.storage, timesteps+1)
130+
node.storage[2:end] .= 0.0
131+
132+
node.effective_rainfall = zeros(timesteps)
133+
node.et = zeros(timesteps)
134+
node.inflow = zeros(timesteps)
135+
node.dam_area = zeros(timesteps)
136+
137+
node.level = zeros(timesteps)
138+
node.discharge = zeros(timesteps)
139+
node.outflow = zeros(timesteps)
140+
end
141+
130142

131-
function update_state(node::DamNode, storage, rainfall, et, area, discharge, outflow)
143+
function update_state!(node::DamNode, storage, rainfall, et, area, discharge, outflow)
132144
push!(node.storage, storage)
133145
push!(node.effective_rainfall, rainfall)
134146
push!(node.et, et)
@@ -139,6 +151,18 @@ function update_state(node::DamNode, storage, rainfall, et, area, discharge, out
139151

140152
return nothing
141153
end
154+
function update_state!(node::DamNode, ts::Int64, storage, rainfall, et, area, discharge, outflow)
155+
node.storage[ts+1] = storage
156+
157+
node.effective_rainfall[ts] = rainfall
158+
node.et[ts] = et
159+
node.level[ts] = node.calc_dam_level(storage)
160+
node.dam_area[ts] = area
161+
node.discharge[ts] = discharge
162+
node.outflow[ts] = outflow
163+
164+
return nothing
165+
end
142166

143167

144168
"""
@@ -172,10 +196,14 @@ end
172196
function run_node!(node::DamNode, climate::Climate;
173197
inflow=nothing, extraction=nothing, exchange=nothing)
174198
timesteps = sim_length(climate)
199+
prep_state!(node, timesteps)
200+
175201
for ts in 1:timesteps
176202
run_node!(node, climate, ts;
177203
inflow=inflow, extraction=extraction, exchange=exchange)
178204
end
205+
206+
return nothing
179207
end
180208

181209

@@ -194,23 +222,25 @@ Run a specific node for a specified time step.
194222
- `exchange::DataFrame` : Time series of groundwater flux
195223
"""
196224
function run_node!(node::DamNode, climate::Climate, timestep::Int;
197-
inflow=nothing, extraction=nothing, exchange=nothing)
225+
inflow=nothing, extraction=nothing, exchange=nothing)::Nothing
198226
ts = timestep
199-
if checkbounds(Bool, node.outflow, ts)
200-
if node.outflow[ts] != undef
201-
# already ran for this time step so no need to run
202-
return node.outflow[ts], node.level[ts]
203-
end
204-
end
227+
# if checkbounds(Bool, node.outflow, ts)
228+
# if node.outflow[ts] != undef
229+
# # already ran for this time step so no need to run
230+
# return node.outflow[ts], node.level[ts]
231+
# end
232+
# end
205233

206234
node_name = node.name
207235
rain, et = climate_values(node, climate, ts)
208236
wo = timestep_value(ts, node_name, "releases", extraction)
209237
ex = timestep_value(ts, node_name, "exchange", exchange)
210238
in_flow = timestep_value(ts, node_name, "inflow", inflow)
211-
vol = node.storage[ts]
239+
current_vol = node.storage[ts]
240+
241+
run_node!(node, ts, rain, et, current_vol, in_flow, wo, ex)
212242

213-
return run_node!(node, rain, et, vol, in_flow, wo, ex)
243+
return nothing
214244
end
215245

216246

@@ -229,23 +259,23 @@ Calculate outflow for the dam node for a single time step.
229259
- outflow from dam
230260
"""
231261
function run_node!(node::DamNode,
262+
ts::Int64,
232263
rain::Float64,
233264
et::Float64,
234-
vol::Float64,
265+
volume::Float64,
235266
inflow::Float64,
236267
extractions::Float64,
237268
gw_flux::Float64)
238-
volume = vol
239269
dam_area = node.calc_dam_area(volume)
240270
discharge = node.calc_dam_discharge(volume, node.max_storage)
241271

242272
updated_store = update_volume(volume, inflow, gw_flux, rain, et,
243273
dam_area, extractions, discharge, node.max_storage)
244274
outflow = node.calc_dam_outflow(discharge, extractions)
245275

246-
update_state(node, updated_store, rain, et, dam_area, discharge, outflow)
276+
update_state!(node, ts, updated_store, rain, et, dam_area, discharge, outflow)
247277

248-
return outflow, level(node)
278+
return nothing
249279
end
250280

251281

0 commit comments

Comments
 (0)