Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,6 @@ julia>] test

## Usage

Streamfall is currently unregistered but can be added to a Julia environment directly from
the Package manager:

```bash
julia>] add https://github.com/ConnectedSystems/Streamfall.jl#main
```

The examples below use data from the CAMEL-AUS dataset, available here:

> Fowler, K. J. A., Acharya, S. C., Addor, N., Chou, C., and Peel, M. C.: CAMELS-AUS: hydrometeorological time series and landscape attributes for 222 catchments in Australia, Earth Syst. Sci. Data, 13, 3847–3867, https://doi.org/10.5194/essd-13-3847-2021, 2021.
Expand Down
40 changes: 25 additions & 15 deletions src/Climate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ function Climate(file_path::String, p_id, et_id; t_id="_T")
end

"""
extract_flow(
data::DataFrame, gauge_id::String; suffix::String="_Q"
)::DataFrame

Extract streamflow data from file.

Streamflow (Q) column is identified the Gauge ID.
Expand All @@ -35,13 +39,13 @@ e.g., ("000001_Q")
DataFrame of observations for selected gauge.
"""
@inline function extract_flow(
data::DataFrame, gauge_id::String, suffix::String="_Q"
data::DataFrame, gauge_id::String; suffix::String="_Q"
)::DataFrame
target = data[:, ["Date", gauge_id * suffix]]
try
target[!, gauge_id * suffix] = convert.(Float64, target[!, gauge_id * suffix])
target[!, gauge_id*suffix] = convert.(Float64, target[!, gauge_id*suffix])
catch
target[!, gauge_id * suffix] = convert.(Union{Float64,Missing}, target[!, gauge_id * suffix])
target[!, gauge_id*suffix] = convert.(Union{Float64,Missing}, target[!, gauge_id*suffix])
end

rename!(target, gauge_id * suffix => gauge_id)
Expand Down Expand Up @@ -78,8 +82,9 @@ Extract rainfall data for a given node.
function rainfall_data(node::NetworkNode, climate::Climate)::DataFrame
data = climate.climate_data
rain_col = filter(x -> occursin(node.name, x)
& occursin(climate.rainfall_id, x),
names(data))[1]
&
occursin(climate.rainfall_id, x),
names(data))[1]

return data[:, rain_col]
end
Expand Down Expand Up @@ -107,15 +112,18 @@ function climate_values(node::NetworkNode, climate::Climate, timestep::Int)

# TODO : Catch instances where data is not found (raises BoundsError)
rain_col = filter(x -> occursin(node_name, x)
& occursin(climate.rainfall_id, x),
names(data))[1]
&
occursin(climate.rainfall_id, x),
names(data))[1]
et_col = filter(x -> occursin(node_name, x)
& occursin(climate.et_id, x),
names(data))[1]
&
occursin(climate.et_id, x),
names(data))[1]
t_col = try
filter(x -> occursin(node_name, x)
& occursin(climate.t_id, x),
names(data))[1]
&
occursin(climate.t_id, x),
names(data))[1]
catch err
if !(err isa BoundsError)
rethrow(err)
Expand Down Expand Up @@ -148,11 +156,13 @@ function climate_values(node::NetworkNode, climate::Climate)

# TODO : Catch instances where data is not found (raises BoundsError)
rain_col = filter(x -> occursin(node.name, x)
& occursin(climate.rainfall_id, x),
names(data))[1]
&
occursin(climate.rainfall_id, x),
names(data))[1]
et_col = filter(x -> occursin(node.name, x)
& occursin(climate.et_id, x),
names(data))[1]
&
occursin(climate.et_id, x),
names(data))[1]

if isempty(rain_col) | isempty(et_col)
throw(ArgumentError("No climate data found for $(node.name) at time step: $(timestep)"))
Expand Down
29 changes: 21 additions & 8 deletions src/Network.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ function get_prop(sn::StreamfallNetwork, nid::Int64, prop::Symbol)::Any
end


"""Determine a node's connection"""
"""
in_or_out(g, v)

Determine a node's connection
"""
function in_or_out(g, v)
ins = length(inneighbors(g, v))
outs = length(outneighbors(g, v))
Expand All @@ -58,7 +62,11 @@ function in_or_out(g, v)
end


"""Find all inlets and outlets in a network."""
"""
find_inlets_and_outlets(sn::StreamfallNetwork)::Tuple

Find all inlets and outlets in a network.
"""
function find_inlets_and_outlets(sn::StreamfallNetwork)::Tuple
g = sn.mg
vs = vertices(g)
Expand Down Expand Up @@ -161,9 +169,14 @@ function create_node(mg::MetaDiGraph, node_name::String, details::AbstractDict,
func = run_node!
end

set_props!(mg, nid, Dict(:name=>node_name,
:node=>n,
:nfunc=>func))
set_props!(
mg, nid,
Dict(
:name => node_name,
:node => n,
:nfunc => func
)
)

this_id = nid
else
Expand Down Expand Up @@ -307,7 +320,7 @@ function Base.show(io::IO, sn::StreamfallNetwork)

show_verts = vs
if length(vs) > 4
show_verts = [1, 2, nothing, length(vs)-1, length(vs)]
show_verts = [1, 2, nothing, length(vs) - 1, length(vs)]
end

for nid in show_verts
Expand All @@ -328,7 +341,7 @@ end
Simple plot of stream network.
"""
function plot_network(sn::StreamfallNetwork; as_html=false)
node_labels = ["$(sn[i].name)\n"*string(nameof(typeof(sn[i]))) for i in vertices(sn.mg)]
node_labels = ["$(sn[i].name)\n" * string(nameof(typeof(sn[i]))) for i in vertices(sn.mg)]

if as_html
plot_func = gplothtml
Expand All @@ -355,7 +368,7 @@ function Base.iterate(sn::StreamfallNetwork, state=1)
return nothing
end

return (sn[state], state+1)
return (sn[state], state + 1)
end


Expand Down
16 changes: 8 additions & 8 deletions src/Nodes/DamNode.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function c_dam_outflow(discharge, irrigation_extraction)
end


Base.@kwdef mutable struct DamNode{P, A<:AbstractFloat} <: NetworkNode
Base.@kwdef mutable struct DamNode{P,A<:AbstractFloat} <: NetworkNode
name::String
area::A

Expand Down Expand Up @@ -74,12 +74,12 @@ function DamNode(
calc_dam_outflow::Function
) where {F<:Float64}
return DamNode(name, area, max_storage, storage_coef,
calc_dam_level, calc_dam_area, calc_dam_discharge, calc_dam_outflow,
F[initial_storage], F[], F[], F[], F[], F[], F[], F[])
calc_dam_level, calc_dam_area, calc_dam_discharge, calc_dam_outflow,
F[initial_storage], F[], F[], F[], F[], F[], F[], F[])
end

"""
DamNode(name::String, spec::Dict)
DamNode(name::String, spec::AbstractDict)

Create DamNode from a given specification.
"""
Expand Down Expand Up @@ -136,7 +136,7 @@ function storage(node::DamNode)
end

function prep_state!(node::DamNode, timesteps::Int64)
resize!(node.storage, timesteps+1)
resize!(node.storage, timesteps + 1)
node.storage[2:end] .= 0.0

node.effective_rainfall = zeros(timesteps)
Expand Down Expand Up @@ -204,13 +204,13 @@ end


function run_node!(node::DamNode, climate::Climate;
inflow=nothing, extraction=nothing, exchange=nothing)
inflow=nothing, extraction=nothing, exchange=nothing)
timesteps = sim_length(climate)
prep_state!(node, timesteps)

for ts in 1:timesteps
run_node!(node, climate, ts;
inflow=inflow, extraction=extraction, exchange=exchange)
inflow=inflow, extraction=extraction, exchange=exchange)
end

return nothing
Expand Down Expand Up @@ -289,7 +289,7 @@ function run_node!(
discharge = node.calc_dam_discharge(volume, node.max_storage)

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

update_state!(node, ts, updated_store, rain, et, dam_area, discharge, outflow)
Expand Down
Loading
Loading