Validation
The tables below show the validation rules applied to the input to the Julia core before running the model.
1 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
= Symbol[]
node_names_snake_case = Symbol[]
node_names_camel_case for (node_name, node_type) in
zip(fieldnames(Ribasim.ParametersIndependent), fieldtypes(Ribasim.ParametersIndependent))
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
= DataFrame()
df :downstream] = node_names_snake_case
df[!,
for node_name in node_names_snake_case
= [
df[!, node_name] to_symbol(node_name_ in Ribasim.neighbortypes(node_name))) for
(in node_names_snake_case
node_name_
]end
markdown_table(df)
downstream | basin | linear_resistance | manning_resistance | tabulated_rating_curve | level_boundary | flow_boundary | pump | outlet | terminal | junction | discrete_control | continuous_control | pid_control | user_demand | level_demand | flow_demand |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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 | x |
flow_boundary |
x | 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 |
junction |
✓ | ✓ | ✓ | ✓ | x | ✓ | ✓ | ✓ | x | ✓ | x | x | x | ✓ | x | x |
discrete_control |
x | 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 | x |
pid_control |
x | 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 | x |
flow_demand |
x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x |
2 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 links.
Code
= Vector{String}()
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
function unbounded(i::Int)::String
return i == typemax(Int) ? "∞" : string(i)
end
for node_name in node_names_camel_case
= Ribasim.n_neighbor_bounds_flow(node_name)
bounds_flow 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))
= Ribasim.n_neighbor_bounds_control(node_name)
bounds_control 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
= DataFrame(;
df = node_names_snake_case,
node_type
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)
node_type | flow_in_min | flow_in_max | flow_out_min | flow_out_max | control_in_min | control_in_max | control_out_min | control_out_max |
---|---|---|---|---|---|---|---|---|
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 | 1 | 0 | 0 | 0 | 0 |
pump |
1 | 1 | 1 | 1 | 0 | 2 | 0 | 0 |
outlet |
1 | 1 | 1 | 1 | 0 | 2 | 0 | 0 |
terminal |
1 | ∞ | 0 | 0 | 0 | 0 | 0 | 0 |
junction |
1 | ∞ | 1 | ∞ | 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 |
Note
Pump and Outlet can receive two control links, in which case one must be from a FlowDemand, and the other from a control node.