Skip to content

Commit

Permalink
Ribasim Python: Add-API (#1110)
Browse files Browse the repository at this point in the history
Fixes #760
Fixes #252

Follow ups:
- More validation
- Avoid blocking of database by qgis
- Plotting of control edges
- Reading of model

---------

Co-authored-by: Martijn Visser <[email protected]>
Co-authored-by: Hofer-Julian <[email protected]>
  • Loading branch information
3 people authored Mar 12, 2024
1 parent 05fc42c commit 006ff90
Show file tree
Hide file tree
Showing 56 changed files with 3,371 additions and 6,173 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,4 @@ report.xml

# Designated working dir for working on Ribasim models
models/
playground/output
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"version": "0.2.0",
"configurations": [
{
{
"type": "julia",
"request": "launch",
"name": "Julia: current file",
Expand Down
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"[julia]": {
"editor.formatOnSave": true
},
"notebook.formatOnSave.enabled": true,
"notebook.formatOnSave.enabled": false,
"notebook.codeActionsOnSave": {
"source.fixAll.ruff": true,
"source.organizeImports.ruff": true
Expand Down
6 changes: 4 additions & 2 deletions core/src/graph.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ and data of edges (EdgeMetadata):
[`EdgeMetadata`](@ref)
"""
function create_graph(db::DB, config::Config, chunk_sizes::Vector{Int})::MetaGraph
node_rows =
execute(db, "SELECT node_id, node_type, subnetwork_id FROM Node ORDER BY fid")
node_rows = execute(
db,
"SELECT node_id, node_type, subnetwork_id FROM Node ORDER BY node_type, node_id",
)
edge_rows = execute(
db,
"SELECT fid, from_node_type, from_node_id, to_node_type, to_node_id, edge_type, subnetwork_id FROM Edge ORDER BY fid",
Expand Down
12 changes: 2 additions & 10 deletions core/src/read.jl
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ function DiscreteControl(db::DB, config::Config)::DiscreteControl

return DiscreteControl(
NodeID.(NodeType.DiscreteControl, condition.node_id), # Not unique
NodeID.(condition.listen_feature_type, condition.listen_feature_id),
NodeID.(condition.listen_node_type, condition.listen_node_id),
condition.variable,
look_ahead,
condition.greater_than,
Expand Down Expand Up @@ -930,19 +930,11 @@ function Parameters(db::DB, config::Config)::Parameters
return p
end

function get_nodetypes(db::DB)::Vector{String}
return only(execute(columntable, db, "SELECT node_type FROM Node ORDER BY fid"))
end

function get_ids(db::DB, nodetype)::Vector{Int}
sql = "SELECT node_id FROM Node WHERE node_type = $(esc_id(nodetype)) ORDER BY fid"
sql = "SELECT node_id FROM Node WHERE node_type = $(esc_id(nodetype)) ORDER BY node_id"
return only(execute(columntable, db, sql))
end

function get_names(db::DB)::Vector{String}
return only(execute(columntable, db, "SELECT name FROM Node ORDER BY fid"))
end

function get_names(db::DB, nodetype)::Vector{String}
sql = "SELECT name FROM Node where node_type = $(esc_id(nodetype)) ORDER BY fid"
return only(execute(columntable, db, sql))
Expand Down
8 changes: 4 additions & 4 deletions core/src/schema.jl
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ end

@version DiscreteControlConditionV1 begin
node_id::Int
listen_feature_type::Union{Missing, String}
listen_feature_id::Int
listen_node_type::String
listen_node_id::Int
variable::String
greater_than::Float64
look_ahead::Union{Missing, Float64}
Expand All @@ -199,7 +199,7 @@ end
@version PidControlStaticV1 begin
node_id::Int
active::Union{Missing, Bool}
listen_node_type::Union{Missing, String}
listen_node_type::String
listen_node_id::Int
target::Float64
proportional::Float64
Expand All @@ -210,7 +210,7 @@ end

@version PidControlTimeV1 begin
node_id::Int
listen_node_type::Union{Missing, String}
listen_node_type::String
listen_node_id::Int
time::DateTime
target::Float64
Expand Down
6 changes: 5 additions & 1 deletion core/src/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,11 @@ function allocation_path_exists_in_graph(
end

function has_main_network(allocation::Allocation)::Bool
return first(allocation.allocation_network_ids) == 1
if !is_active(allocation)
false
else
first(allocation.allocation_network_ids) == 1
end
end

function is_main_network(allocation_network_id::Int)::Bool
Expand Down
1 change: 0 additions & 1 deletion core/src/validation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ function variable_nt(s::Any)
end

# functions used by sort(x; by)
sort_by_fid(row) = row.fid
sort_by_id(row) = row.node_id
sort_by_time_id(row) = (row.time, row.node_id)
sort_by_id_level(row) = (row.node_id, row.level)
Expand Down
6 changes: 3 additions & 3 deletions core/test/run_models_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@

@testset "Results values" begin
@test flow.time[1] == DateTime(2020)
@test coalesce.(flow.edge_id[1:4], -1) == [-1, -1, 9, 11]
@test flow.from_node_id[1:4] == [6, typemax(Int), 0, 6]
@test flow.to_node_id[1:4] == [6, typemax(Int), typemax(Int), 0]
@test coalesce.(flow.edge_id[1:4], -1) == [-1, -1, 1, 2]
@test flow.from_node_id[1:4] == [6, 922, 6, 0]
@test flow.to_node_id[1:4] == [6, 922, 0, 922]

@test basin.storage[1] 1.0
@test basin.level[1] 0.044711584
Expand Down
6 changes: 3 additions & 3 deletions core/test/validation_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ end
@test logger.logs[3].kwargs[:control_state] == ""
@test logger.logs[4].level == Error
@test logger.logs[4].message == "Cannot connect a basin to a fractional_flow."
@test logger.logs[4].kwargs[:edge_id] == 6
@test logger.logs[4].kwargs[:edge_id] == 7
@test logger.logs[4].kwargs[:id_src] == NodeID(:Basin, 2)
@test logger.logs[4].kwargs[:id_dst] == NodeID(:FractionalFlow, 8)
end
Expand Down Expand Up @@ -362,10 +362,10 @@ end
@test length(logger.logs) == 2
@test logger.logs[1].level == Error
@test logger.logs[1].message ==
"Invalid edge type 'foo' for edge #0 from node #1 to node #2."
"Invalid edge type 'foo' for edge #1 from node #1 to node #2."
@test logger.logs[2].level == Error
@test logger.logs[2].message ==
"Invalid edge type 'bar' for edge #1 from node #2 to node #3."
"Invalid edge type 'bar' for edge #2 from node #2 to node #3."
end

@testitem "Subgrid validation" begin
Expand Down
33 changes: 16 additions & 17 deletions docs/_quarto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,24 +67,23 @@ quartodoc:
desc: The Model class represents an entire Ribasim model.
contents:
- Model
- title: Network
desc: The Node and Edge database layers define the network layout.
- title: Edge
desc: The Edge database layer.
contents:
- Node
- Edge
- EdgeTable
- title: Node types
desc: Available node types to model different situations.
contents:
- Basin
- FractionalFlow
- TabulatedRatingCurve
- Pump
- Outlet
- UserDemand
- LevelBoundary
- FlowBoundary
- LinearResistance
- ManningResistance
- Terminal
- DiscreteControl
- PidControl
- nodes.basin
- nodes.fractional_flow
- nodes.tabulated_rating_curve
- nodes.pump
- nodes.outlet
- nodes.user_demand
- nodes.level_boundary
- nodes.flow_boundary
- nodes.linear_resistance
- nodes.manning_resistance
- nodes.terminal
- nodes.discrete_control
- nodes.pid_control
56 changes: 29 additions & 27 deletions docs/core/usage.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -603,14 +603,14 @@ DiscreteControl is implemented based on [VectorContinuousCallback](https://docs.

The condition schema defines conditions of the form 'the discrete_control node with this node id listens to whether the given variable of the node with the given listen feature id is grater than the given value'. If the condition variable comes from a time-series, a look ahead $\Delta t$ can be supplied.

column | type | unit | restriction
------------------- | -------- | ------- | -----------
node_id | Int | - | sorted
listen_feature_id | Int | - | sorted per node_id
listen_feature_type | String | - | known node type
variable | String | - | must be "level" or "flow_rate", sorted per listen_feature_id
greater_than | Float64 | various | sorted per variable
look_ahead | Float64 | $s$ | Only on transient boundary conditions, non-negative (optional, default 0)
column | type | unit | restriction
----------------- | -------- | ------- | -----------
node_id | Int | - | sorted
listen_node_type | String | - | known node type
listen_node_id | Int | - | sorted per node_id
variable | String | - | must be "level" or "flow_rate", sorted per listen_node_id
greater_than | Float64 | various | sorted per variable
look_ahead | Float64 | $s$ | Only on transient boundary conditions, non-negative (optional, default 0)

## DiscreteControl / logic

Expand Down Expand Up @@ -642,16 +642,17 @@ The PidControl node controls the level in a basin by continuously controlling th

In the future controlling the flow on a particular edge could be supported.

column | type | unit | restriction
-------------- | -------- | -------- | -----------
node_id | Int | - | sorted
control_state | String | - | (optional) sorted per node_id
active | Bool | - | (optional, default true)
listen_node_id | Int | - | -
target | Float64 | $m$ | -
proportional | Float64 | $s^{-1}$ | -
integral | Float64 | $s^{-2}$ | -
derivative | Float64 | - | -
column | type | unit | restriction
---------------- | -------- | -------- | -----------
node_id | Int | - | sorted
control_state | String | - | (optional) sorted per node_id
active | Bool | - | (optional, default true)
listen_node_type | Int | - | known node type
listen_node_id | Int | - | -
target | Float64 | $m$ | -
proportional | Float64 | $s^{-1}$ | -
integral | Float64 | $s^{-2}$ | -
derivative | Float64 | - | -

## PidControl / time

Expand All @@ -663,15 +664,16 @@ these values interpolated linearly, and outside these values area constant given
nearest time value.
Note that a `node_id` can be either in this table or in the static one, but not both.

column | type | unit | restriction
-------------- | -------- | -------- | -----------
node_id | Int | - | sorted
time | DateTime | - | sorted per node_id
listen_node_id | Int | - | -
target | Float64 | $m$ | -
proportional | Float64 | $s^{-1}$ | -
integral | Float64 | $s^{-2}$ | -
derivative | Float64 | - | -
column | type | unit | restriction
---------------- | -------- | -------- | -----------
node_id | Int | - | sorted
time | DateTime | - | sorted per node_id
listen_node_type | Int | - | known node type
listen_node_id | Int | - | -
target | Float64 | $m$ | -
proportional | Float64 | $s^{-1}$ | -
integral | Float64 | $s^{-2}$ | -
derivative | Float64 | - | -

# Results

Expand Down
Loading

0 comments on commit 006ff90

Please sign in to comment.