The tables below show the validation rules applied to the input to the Julia core before running the model.
Connectivity
In the table below, each column shows which node types are allowed to be downstream (or ‘down-control’) of the node type at the top of the column.
Code
using Ribasim
using DataFrames: DataFrame
using MarkdownTables
node_names_snake_case = Symbol[]
node_names_camel_case = Symbol[]
for (node_name, node_type) in zip(fieldnames(Ribasim.Parameters), fieldtypes(Ribasim.Parameters))
if node_type <: Ribasim.AbstractParameterNode
push!(node_names_snake_case, node_name)
push!(node_names_camel_case, nameof(node_type))
end
end
function to_symbol(b::Bool)::String
return b ? "✓" : "x"
end
df = DataFrame()
df[!, :downstream] = node_names_snake_case
for node_name in node_names_snake_case
df[!, node_name] =
[(to_symbol(node_name_ in Ribasim.neighbortypes(node_name))) for node_name_ in node_names_snake_case]
end
markdown_table(df)
basin |
x |
✓ |
✓ |
✓ |
x |
✓ |
✓ |
✓ |
x |
x |
x |
x |
✓ |
✓ |
x |
linear_resistance |
✓ |
x |
x |
x |
✓ |
x |
x |
x |
x |
✓ |
x |
x |
x |
x |
✓ |
manning_resistance |
✓ |
x |
x |
x |
x |
x |
x |
x |
x |
✓ |
x |
x |
x |
x |
✓ |
tabulated_rating_curve |
✓ |
x |
x |
x |
✓ |
x |
x |
x |
x |
✓ |
x |
x |
x |
x |
✓ |
level_boundary |
x |
✓ |
x |
✓ |
x |
✓ |
✓ |
✓ |
x |
x |
x |
x |
✓ |
x |
x |
flow_boundary |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
pump |
✓ |
x |
x |
x |
✓ |
x |
x |
x |
x |
✓ |
✓ |
✓ |
x |
x |
✓ |
outlet |
✓ |
x |
x |
x |
✓ |
x |
x |
x |
x |
✓ |
✓ |
✓ |
x |
x |
✓ |
terminal |
x |
x |
x |
✓ |
x |
✓ |
✓ |
✓ |
x |
x |
x |
x |
✓ |
x |
x |
discrete_control |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
continuous_control |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
pid_control |
x |
x |
x |
x |
x |
x |
x |
x |
x |
✓ |
x |
x |
x |
x |
x |
user_demand |
✓ |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
level_demand |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
flow_demand |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
x |
Neighbor amounts
The table below shows for each node type between which bounds the amount of in- and outneighbors must be, for both flow and control edges.
Code
flow_in_min = Vector{String}()
flow_in_max = Vector{String}()
flow_out_min = Vector{String}()
flow_out_max = Vector{String}()
control_in_min = Vector{String}()
control_in_max = Vector{String}()
control_out_min = Vector{String}()
control_out_max = Vector{String}()
function unbounded(i::Int)::String
return i == typemax(Int) ? "∞" : string(i)
end
for node_name in node_names_camel_case
bounds_flow = Ribasim.n_neighbor_bounds_flow(node_name)
push!(flow_in_min, string(bounds_flow.in_min))
push!(flow_in_max, unbounded(bounds_flow.in_max))
push!(flow_out_min, string(bounds_flow.out_min))
push!(flow_out_max, unbounded(bounds_flow.out_max))
bounds_control = Ribasim.n_neighbor_bounds_control(node_name)
push!(control_in_min, string(bounds_control.in_min))
push!(control_in_max, unbounded(bounds_control.in_max))
push!(control_out_min, string(bounds_control.out_min))
push!(control_out_max, unbounded(bounds_control.out_max))
end
df = DataFrame(
;
node_type = node_names_snake_case,
flow_in_min,
flow_in_max,
flow_out_min,
flow_out_max,
control_in_min,
control_in_max,
control_out_min,
control_out_max,
)
markdown_table(df)
basin |
0 |
∞ |
0 |
∞ |
0 |
1 |
0 |
0 |
linear_resistance |
1 |
1 |
1 |
1 |
0 |
1 |
0 |
0 |
manning_resistance |
1 |
1 |
1 |
1 |
0 |
1 |
0 |
0 |
tabulated_rating_curve |
1 |
1 |
1 |
1 |
0 |
1 |
0 |
0 |
level_boundary |
0 |
∞ |
0 |
∞ |
0 |
0 |
0 |
0 |
flow_boundary |
0 |
0 |
1 |
∞ |
0 |
0 |
0 |
0 |
pump |
1 |
1 |
1 |
1 |
0 |
1 |
0 |
0 |
outlet |
1 |
1 |
1 |
1 |
0 |
1 |
0 |
0 |
terminal |
1 |
∞ |
0 |
0 |
0 |
0 |
0 |
0 |
discrete_control |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
∞ |
continuous_control |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
∞ |
pid_control |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
user_demand |
1 |
1 |
1 |
1 |
0 |
0 |
0 |
0 |
level_demand |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
∞ |
flow_demand |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |