Code
using Ribasim
@@ -582,52 +611,37 @@
set_flow!(p.graph, NodeID(:FlowBoundary, 1), NodeID(:Basin, 2), 1.0)
Ribasim.
-adjust_source_capacities!(allocation_model, p, priority_idx)
- Ribasim.adjust_edge_capacities!(allocation_model, p, priority_idx)
+ Ribasim.adjust_capacities_edge!(allocation_model, p, priority_idx)
+ Ribasim.adjust_capacities_source!(allocation_model, p, priority_idx)
Ribasim.set_objective_priority!(allocation_model, p, u, t, priority_idx)
Ribasim.
println(p.allocation.allocation_models[1].problem)
Min F_abs_user_demand[UserDemand #3] + F_abs_user_demand[UserDemand #13] + F_abs_user_demand[UserDemand #6] + F_abs_basin[Basin #2] + F_abs_basin[Basin #12] + F_abs_basin[Basin #5]
+Min F_abs_user_demand[UserDemand #3] + F_abs_user_demand[UserDemand #13] + F_abs_user_demand[UserDemand #6]
Subject to
- flow_conservation[Basin #2] : -F[(Basin #5, Basin #2)] + F[(Basin #2, Basin #5)] - F[(FlowBoundary #1, Basin #2)] + F[(Basin #2, UserDemand #3)] + F_basin_in[Basin #2] - F_basin_out[Basin #2] = 0
- flow_conservation[Basin #12] : F[(Basin #12, UserDemand #13)] - F[(TabulatedRatingCurve #7, Basin #12)] + F_basin_in[Basin #12] - F_basin_out[Basin #12] = 0
- flow_conservation[Basin #5] : F[(Basin #5, UserDemand #6)] + F[(Basin #5, Basin #2)] - F[(Basin #2, Basin #5)] + F[(Basin #5, TabulatedRatingCurve #7)] + F_basin_in[Basin #5] - F_basin_out[Basin #5] = 0
+ flow_conservation_basin[Basin #5] : F[(Basin #5, UserDemand #6)] + F[(Basin #5, Basin #2)] - F[(Basin #2, Basin #5)] + F[(Basin #5, TabulatedRatingCurve #7)] = 0
+ flow_conservation_basin[Basin #2] : F[(Basin #2, UserDemand #3)] - F[(FlowBoundary #1, Basin #2)] - F[(Basin #5, Basin #2)] + F[(Basin #2, Basin #5)] = 0
+ flow_conservation_basin[Basin #12] : F[(Basin #12, UserDemand #13)] - F[(TabulatedRatingCurve #7, Basin #12)] = 0
abs_positive_user_demand[UserDemand #3] : -F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ -1.5
abs_positive_user_demand[UserDemand #13] : -F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0
abs_positive_user_demand[UserDemand #6] : -F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0
abs_negative_user_demand[UserDemand #3] : F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ 1.5
abs_negative_user_demand[UserDemand #13] : F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0
abs_negative_user_demand[UserDemand #6] : F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0
- abs_positive_basin[Basin #2] : -F_basin_in[Basin #2] + F_abs_basin[Basin #2] ≥ 0
- abs_positive_basin[Basin #12] : -F_basin_in[Basin #12] + F_abs_basin[Basin #12] ≥ 0
- abs_positive_basin[Basin #5] : -F_basin_in[Basin #5] + F_abs_basin[Basin #5] ≥ 0
- abs_negative_basin[Basin #2] : F_basin_in[Basin #2] + F_abs_basin[Basin #2] ≥ 0
- abs_negative_basin[Basin #12] : F_basin_in[Basin #12] + F_abs_basin[Basin #12] ≥ 0
- abs_negative_basin[Basin #5] : F_basin_in[Basin #5] + F_abs_basin[Basin #5] ≥ 0
source[(FlowBoundary #1, Basin #2)] : F[(FlowBoundary #1, Basin #2)] ≤ 1
return_flow[UserDemand #13] : F[(UserDemand #13, Terminal #10)] ≤ 0
- fractional_flow[(TabulatedRatingCurve #7, Basin #12)] : -0.4 F[(Basin #5, TabulatedRatingCurve #7)] + F[(TabulatedRatingCurve #7, Basin #12)] ≤ 0
- basin_outflow[Basin #2] : F_basin_out[Basin #2] ≤ 0
- basin_outflow[Basin #12] : F_basin_out[Basin #12] ≤ 0
- basin_outflow[Basin #5] : F_basin_out[Basin #5] ≤ 0
- F[(TabulatedRatingCurve #7, Terminal #10)] ≥ 0
+ fractional_flow[(TabulatedRatingCurve #7, Basin #12)] : F[(TabulatedRatingCurve #7, Basin #12)] - 0.4 F[(Basin #5, TabulatedRatingCurve #7)] ≤ 0
F[(Basin #5, UserDemand #6)] ≥ 0
- F[(Basin #5, Basin #2)] ≥ 0
F[(Basin #12, UserDemand #13)] ≥ 0
- F[(Basin #2, Basin #5)] ≥ 0
- F[(FlowBoundary #1, Basin #2)] ≥ 0
- F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0
- F[(Basin #2, UserDemand #3)] ≥ 0
+ F[(TabulatedRatingCurve #7, Terminal #10)] ≥ 0
F[(UserDemand #13, Terminal #10)] ≥ 0
+ F[(Basin #2, UserDemand #3)] ≥ 0
+ F[(FlowBoundary #1, Basin #2)] ≥ 0
+ F[(Basin #5, Basin #2)] ≥ 0
+ F[(Basin #2, Basin #5)] ≥ 0
F[(TabulatedRatingCurve #7, Basin #12)] ≥ 0
- F_basin_in[Basin #2] ≥ 0
- F_basin_in[Basin #12] ≥ 0
- F_basin_in[Basin #5] ≥ 0
- F_basin_out[Basin #2] ≥ 0
- F_basin_out[Basin #12] ≥ 0
- F_basin_out[Basin #5] ≥ 0
+ F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0
Here \(p > 0\) is the threshold value which determines the interval \([0,p]\) of the smooth transition between \(0\) and \(1\), see the plot below.
-
+
Code
import numpy as np
@@ -475,7 +475,7 @@
diff --git a/core/usage.html b/core/usage.html
index d36b40bac..16d8c6ab5 100644
--- a/core/usage.html
+++ b/core/usage.html
@@ -317,33 +317,37 @@ On this page
- - 12 LevelBoundary
+
- 12 FlowDemand
- - 13 FlowBoundary
+
- 13 LevelBoundary
- - 14 LinearResistance
- - 15 ManningResistance
- - 16 Terminal
- - 17 DisceteControl
+
- 14 FlowBoundary
- - 18 PidControl
+
- 15 LinearResistance
+ - 16 ManningResistance
+ - 17 Terminal
+ - 18 DisceteControl
- - 19 Results
+
- 19 PidControl
+ - 20 Results
+
@@ -637,6 +641,11 @@ 3 Node
LevelDemand / static
: static target levels
LevelDemand / time
: dynamic target levels
+- FlowDemand: sets non-consuming flow demand
+
+FlowDemand / static
: flow demands
+FlowDemand / time
: dynamic flow demands
+
- Terminal: Water sink without state or properties
Terminal / static
: - (only node IDs)
@@ -1301,7 +1310,7 @@ 10 UserDemanddemand
Float64
\(m^3 s^{-1}\)
--
+non-negative
return_factor
@@ -1364,7 +1373,7 @@ demand
Float64
\(m^3 s^{-1}\)
--
+non-negative
return_factor
@@ -1384,7 +1393,7 @@
11 LevelDemand
-An LevelDemand
node associates a minimum and a maximum level with connected basins to be used by the allocation algorithm. Below the minimum level the basin has a demand of the supplied priority, above the maximum level the basin acts as a source, used by all nodes with demands in order of priority. The same LevelDemand
node can be used for basins in different subnetworks.
+A LevelDemand
node associates a minimum and a maximum level with connected basins to be used by the allocation algorithm. Below the minimum level the basin has a demand of the supplied priority, above the maximum level the basin acts as a source, used by all nodes with demands in order of priority. The same LevelDemand
node can be used for basins in different subnetworks.
@@ -1468,8 +1477,82 @@
-
-12 LevelBoundary
+
+12 FlowDemand
+A FlowDemand
node associates a non-consuming flow demand to a connector node (e.g. Pump
, TabulatedRatingCurve
) for one single priority. FlowDemand nodes can set a flow demand only for a single connector node.
+
+
+
+column
+type
+unit
+restriction
+
+
+
+
+node_id
+Int32
+-
+sorted
+
+
+priority
+Int32
+-
+positive
+
+
+demand
+Float64
+\(m^3 s^{-1}\)
+non-negative
+
+
+
+
+12.1 FlowDemand / time
+This table is the transient form of the FlowDemand
table, in which a time-dependent demand can be supplied. Similar to the static version, only a single priority per FlowDemand
node can be provided.
+
+
+
+column
+type
+unit
+restriction
+
+
+
+
+node_id
+Int32
+-
+sorted
+
+
+time
+DateTime
+-
+sorted per node id
+
+
+priority
+Int32
+-
+positive
+
+
+demand
+Float64
+\(m^3 s^{-1}\)
+non-negative
+
+
+
+
+
+
+13 LevelBoundary
Acts like an infinitely large basin where the level does not change by flow. This can be connected to a basin via a LinearResistance
. This boundary node will then exchange water with the basin based on the difference in water level between the two.
@@ -1501,8 +1584,8 @@ 12 LevelBoundary
-
-12.1 LevelBoundary / time
+
+13.1 LevelBoundary / time
This table is the transient form of the LevelBoundary
table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id
. With this the levels can be updated over time. In between the given times the level is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id
can be either in this table or in the static one, but not both.
@@ -1536,8 +1619,8 @@
-
-13 FlowBoundary
+
+14 FlowBoundary
Pump water to a destination node. We require that the edge connecting the flow boundary to the Basin should point towards the basin, so that positive flow corresponds to water being added to the model. The set flow rate will be pumped unless the intake storage (for a negative flow rate) is less than \(10~m^3\), in which case the flow rate will be linearly reduced to \(0~m^3/s\). Note that the connected node must always be a Basin.
@@ -1569,8 +1652,8 @@ 13 FlowBoundary<
-
-13.1 FlowBoundary / time
+
+14.1 FlowBoundary / time
This table is the transient form of the FlowBoundary
table. The only differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id
. With this the flow rates can be updated over time. In between the given times the flow rate is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id
can be either in this table or in the static one, but not both.
@@ -1604,8 +1687,8 @@
-
-14 LinearResistance
+
+15 LinearResistance
Flow proportional to the level difference between the connected basins.
@@ -1650,8 +1733,8 @@ 14 LinearResista
-
-15 ManningResistance
+
+16 ManningResistance
Flow through this connection is estimated by conservation of energy and the Manning-Gauckler formula to estimate friction losses.
@@ -1708,8 +1791,8 @@ 15 ManningResist
-
-16 Terminal
+
+17 Terminal
A terminal is a water sink without state or properties. Any water that flows into a terminal node is removed from the model. No water can come into the model from a terminal node. For example, terminal nodes can be used as a downstream boundary.
@@ -1730,11 +1813,11 @@ 16 Terminal
-
-17 DisceteControl
+
+18 DisceteControl
DiscreteControl is implemented based on VectorContinuousCallback.
-
-17.1 DiscreteControl / condition
+
+18.1 DiscreteControl / condition
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.
@@ -1791,8 +1874,8 @@
-17.2 DiscreteControl / logic
+
+18.2 DiscreteControl / logic
The logic schema defines which control states are triggered based on the truth of the conditions a DiscreteControl node listens to. DiscreteControl is applied in the Julia core as follows:
- During the simulation it is checked whether the truth of any of the conditions changes.
@@ -1853,8 +1936,8 @@ <
-
-18 PidControl
+
+19 PidControl
The PidControl node controls the level in a basin by continuously controlling the flow rate of a connected pump or outlet. See also PID controller. When A PidControl node is made inactive, the node under its control retains the last flow rate value, and the error integral is reset to 0.
In the future controlling the flow on a particular edge could be supported.
@@ -1923,8 +2006,8 @@ 18 PidControl
-
-18.1 PidControl / time
+
+19.1 PidControl / time
This table is the transient form of the PidControl
table. The differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id
. With this the target level and PID coefficients can be updated over time. In between the given times the these values interpolated linearly, and outside these values area constant given by the nearest time value. Note that a node_id
can be either in this table or in the static one, but not both.
@@ -1988,10 +2071,10 @@
-
-19 Results
-
-19.1 Basin - basin.arrow
+
+20 Results
+
+20.1 Basin - basin.arrow
The basin table contains results of the storage and level of each basin at every solver timestep. The initial condition is also written to the file.
@@ -2026,8 +2109,8 @@
The table is sorted by time, and per time it is sorted by node_id
.
-
-19.2 Flow - flow.arrow
+
+20.2 Flow - flow.arrow
The flow table contains calculated mean flows for every flow edge in the model. In the time column the start of the period is indicated.
@@ -2077,8 +2160,8 @@
The table is sorted by time, and per time the same edge_id
order is used, though not sorted. The edge_id
value is the same as the fid
written to the Edge table, and can be used to directly look up the Edge geometry. Flows that are added to the model at a node, have a missing edge_id
, and identical from_node_id
and to_node_id
. Flows out of the model always have a negative sign, and additions a positive sign.
-
-19.3 DiscreteControl - control.arrow
+
+20.3 DiscreteControl - control.arrow
The control table contains a record of each change of control state: when it happened, which control node was involved, to which control state it changed and based on which truth state.
@@ -2107,8 +2190,8 @@
-19.4 Allocation - allocation.arrow
+
+20.4 Allocation - allocation.arrow
The allocation table contains a record of allocation results: when it happened, for which node, in which allocation network, and what the demand, allocated flow and realized flow were.
@@ -2167,8 +2250,8 @@
-19.5 Allocation flow - allocation_flow.arrow
+
+20.5 Allocation flow - allocation_flow.arrow
The allocation flow table contains results of the optimized allocation flow on every edge in the model that is part of a subnetwork, for each time an optimization problem is solved (see also here). If in the model a main network and subnetwork(s) are specified, there are 2 different types of optimization for the subnetwork: collecting its total demand per priority (for allocating flow from the main network to the subnetwork), and allocating flow within the subnetwork. The column collect_demands
provides the distinction between these two optimization types.
diff --git a/core/validation.html b/core/validation.html
index 57202e552..8c7b5c388 100644
--- a/core/validation.html
+++ b/core/validation.html
@@ -262,7 +262,7 @@ Validation
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
@@ -385,7 +385,7 @@ 1 Connectivityx
x
x
-x
+✓
x
x
x
@@ -546,7 +546,7 @@ 1 Connectivity
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 edges.
-
+
Code
= Vector{String}()
diff --git a/python/examples_files/figure-html/cell-59-output-1.png b/python/examples_files/figure-html/cell-59-output-1.png
index fb18dde11..d234145e9 100644
Binary files a/python/examples_files/figure-html/cell-59-output-1.png and b/python/examples_files/figure-html/cell-59-output-1.png differ
diff --git a/python/examples_files/figure-html/cell-60-output-2.png b/python/examples_files/figure-html/cell-60-output-2.png
index eb25d2657..73061a701 100644
Binary files a/python/examples_files/figure-html/cell-60-output-2.png and b/python/examples_files/figure-html/cell-60-output-2.png differ
diff --git a/python/reference/index.html b/python/reference/index.html
index 27851c9c8..a3366d7cf 100644
--- a/python/reference/index.html
+++ b/python/reference/index.html
@@ -271,6 +271,14 @@ flow_in_min nodes.pid_control
+
+nodes.flow_demand
+
+
+
+nodes.level_demand
+
+
diff --git a/python/reference/nodes.flow_demand.html b/python/reference/nodes.flow_demand.html
new file mode 100644
index 000000000..471cab086
--- /dev/null
+++ b/python/reference/nodes.flow_demand.html
@@ -0,0 +1,543 @@
+
+
+
+
+
+
+
+
+
+Ribasim
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/python/reference/nodes.level_demand.html b/python/reference/nodes.level_demand.html
new file mode 100644
index 000000000..1aa216133
--- /dev/null
+++ b/python/reference/nodes.level_demand.html
@@ -0,0 +1,543 @@
+
+
+
+
+
+
+
+
+
+Ribasim
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/python/test-models.html b/python/test-models.html
index 10812175c..489cfa806 100644
--- a/python/test-models.html
+++ b/python/test-models.html
@@ -227,7 +227,7 @@ Test models
Ribasim developers use the following models in their testbench and in order to test new features.
-
+
Code
import ribasim_testmodels
@@ -319,154 +319,168 @@ Test models
+
+
+
+
+
+
+
+
+
+
diff --git a/python/test-models_files/figure-html/cell-2-output-11.png b/python/test-models_files/figure-html/cell-2-output-11.png
index 4fc0862b5..e1b284d9d 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-11.png and b/python/test-models_files/figure-html/cell-2-output-11.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-12.png b/python/test-models_files/figure-html/cell-2-output-12.png
index 41d5ed5aa..4fc0862b5 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-12.png and b/python/test-models_files/figure-html/cell-2-output-12.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-13.png b/python/test-models_files/figure-html/cell-2-output-13.png
index 057ce9a37..41d5ed5aa 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-13.png and b/python/test-models_files/figure-html/cell-2-output-13.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-14.png b/python/test-models_files/figure-html/cell-2-output-14.png
index 3700441cd..057ce9a37 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-14.png and b/python/test-models_files/figure-html/cell-2-output-14.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-15.png b/python/test-models_files/figure-html/cell-2-output-15.png
index 3ac7ed987..5ccd30a47 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-15.png and b/python/test-models_files/figure-html/cell-2-output-15.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-16.png b/python/test-models_files/figure-html/cell-2-output-16.png
index 51472f2e6..3ac7ed987 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-16.png and b/python/test-models_files/figure-html/cell-2-output-16.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-17.png b/python/test-models_files/figure-html/cell-2-output-17.png
index 28f13a6b3..4b9387c61 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-17.png and b/python/test-models_files/figure-html/cell-2-output-17.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-18.png b/python/test-models_files/figure-html/cell-2-output-18.png
index b7e5989cb..51472f2e6 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-18.png and b/python/test-models_files/figure-html/cell-2-output-18.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-19.png b/python/test-models_files/figure-html/cell-2-output-19.png
index 6feed0dcf..28f13a6b3 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-19.png and b/python/test-models_files/figure-html/cell-2-output-19.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-20.png b/python/test-models_files/figure-html/cell-2-output-20.png
index 48143149e..b7e5989cb 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-20.png and b/python/test-models_files/figure-html/cell-2-output-20.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-21.png b/python/test-models_files/figure-html/cell-2-output-21.png
index e23644dbf..6feed0dcf 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-21.png and b/python/test-models_files/figure-html/cell-2-output-21.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-22.png b/python/test-models_files/figure-html/cell-2-output-22.png
index 385f70f3c..48143149e 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-22.png and b/python/test-models_files/figure-html/cell-2-output-22.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-23.png b/python/test-models_files/figure-html/cell-2-output-23.png
index 30bfdf250..e23644dbf 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-23.png and b/python/test-models_files/figure-html/cell-2-output-23.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-24.png b/python/test-models_files/figure-html/cell-2-output-24.png
index c6cd3c340..385f70f3c 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-24.png and b/python/test-models_files/figure-html/cell-2-output-24.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-25.png b/python/test-models_files/figure-html/cell-2-output-25.png
index aec5c7b0c..30bfdf250 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-25.png and b/python/test-models_files/figure-html/cell-2-output-25.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-26.png b/python/test-models_files/figure-html/cell-2-output-26.png
index 59848dc9c..c6cd3c340 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-26.png and b/python/test-models_files/figure-html/cell-2-output-26.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-27.png b/python/test-models_files/figure-html/cell-2-output-27.png
index ca63191bd..aec5c7b0c 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-27.png and b/python/test-models_files/figure-html/cell-2-output-27.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-28.png b/python/test-models_files/figure-html/cell-2-output-28.png
index 2a311ae92..59848dc9c 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-28.png and b/python/test-models_files/figure-html/cell-2-output-28.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-29.png b/python/test-models_files/figure-html/cell-2-output-29.png
index 6cd33e1c7..ca63191bd 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-29.png and b/python/test-models_files/figure-html/cell-2-output-29.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-30.png b/python/test-models_files/figure-html/cell-2-output-30.png
index 8414c43e1..2a311ae92 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-30.png and b/python/test-models_files/figure-html/cell-2-output-30.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-31.png b/python/test-models_files/figure-html/cell-2-output-31.png
index 59aa41129..6cd33e1c7 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-31.png and b/python/test-models_files/figure-html/cell-2-output-31.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-32.png b/python/test-models_files/figure-html/cell-2-output-32.png
index bd21c153c..8414c43e1 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-32.png and b/python/test-models_files/figure-html/cell-2-output-32.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-33.png b/python/test-models_files/figure-html/cell-2-output-33.png
new file mode 100644
index 000000000..59aa41129
Binary files /dev/null and b/python/test-models_files/figure-html/cell-2-output-33.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-34.png b/python/test-models_files/figure-html/cell-2-output-34.png
new file mode 100644
index 000000000..bd21c153c
Binary files /dev/null and b/python/test-models_files/figure-html/cell-2-output-34.png differ
diff --git a/search.json b/search.json
index 3972ac4d9..80e7a708d 100644
--- a/search.json
+++ b/search.json
@@ -43,7 +43,7 @@
"href": "contribute/addnode.html#parameters",
"title": "Adding node types",
"section": "1.1 Parameters",
- "text": "1.1 Parameters\nThe parameters object (defined in solve.jl) passed to the ODE solver must be made aware of the new node type. Therefore define a struct in solve.jl which holds the data for each node of the new node type:\nstruct NewNodeType\n node_id::Vector{NodeID}\n # Other fields\nend\nThese fields do not have to correspond 1:1 with the input tables (see below). The vector with all node IDs that are of the new type in a given model is a mandatory field. Now you can:\n\nAdd new_node_type::NewNodeType to the Parameters object;\nAdd new_node_type = NewNodeType(db,config) to the function Parameters in create.jl and add new_node_type at the proper location in the Parameters constructor call.",
+ "text": "1.1 Parameters\nThe parameters object (defined in parameter.jl) passed to the ODE solver must be made aware of the new node type. Therefore define a struct in parameter.jl which holds the data for each node of the new node type:\nstruct NewNodeType\n node_id::Vector{NodeID}\n # Other fields\nend\nThese fields do not have to correspond 1:1 with the input tables (see below). The vector with all node IDs that are of the new type in a given model is a mandatory field. Now you can:\n\nAdd new_node_type::NewNodeType to the Parameters object;\nAdd new_node_type = NewNodeType(db,config) to the function Parameters in read.jl and add new_node_type at the proper location in the Parameters constructor call.",
"crumbs": [
"Contributing",
"Adding node types"
@@ -54,7 +54,7 @@
"href": "contribute/addnode.html#reading-from-configuration",
"title": "Adding node types",
"section": "1.2 Reading from configuration",
- "text": "1.2 Reading from configuration\nThere can be several schemas associated with a single node type. To define a schema for the new node type, add the following to validation.jl:\n@schema \"ribasim.newnodetype.static\" NewNodeTypeStatic\n\n\"\"\"\nnode_id: node ID of the NewNodeType node\n\"\"\"\n@version NewNodeTypeStaticV1 begin\n node_id::Int32\n # Other fields\nend\nHere Static refers to data that does not change over time. For naming conventions of these schemas see Node usage.\nvalidation.jl also deals with checking and applying a specific sorting order for the tabular data (default is sorting by node ID only), see sort_by_function and sorted_table!.\nNow we define the function that is called in the second bullet above, in create.jl:\nfunction NewNodeType(db::DB, config::Config)::NewNodeType\n static = load_structvector(db, config, NewNodeTypeStaticV1)\n defaults = (; foo = 1, bar = false)\n # Process potential control states in the static data\n parsed_parameters, valid = parse_static_and_time(db, config, \"Outlet\"; static, defaults)\n\n if !valid\n error(\"Errors occurred when parsing NewNodeType data.\")\n end\n\n # Unpack the fields of static as inputs for the NewNodeType constructor\n return NewNodeType(\n NodeID.(NodeType.NewNodeType, parsed_parameters.node_id),\n parsed_parameters.some_property,\n parsed_parameters.control_mapping)\nend",
+ "text": "1.2 Reading from configuration\nThere can be several schemas associated with a single node type. To define a schema for the new node type, add the following to schema.jl:\n@schema \"ribasim.newnodetype.static\" NewNodeTypeStatic\n\n\"\"\"\nnode_id: node ID of the NewNodeType node\n\"\"\"\n@version NewNodeTypeStaticV1 begin\n node_id::Int32\n # Other fields\nend\nHere static refers to data that does not change over time. For naming conventions of these schemas see Node usage. If a new schema contains a priority column for allocation, it must also be added to the list of all such schemas in the function get_all_priorities in util.jl.\nvalidation.jl deals with checking and applying a specific sorting order for the tabular data (default is sorting by node ID only), see sort_by_function and sorted_table!.\nNow we define the function that is called in the second bullet above, in read.jl:\nfunction NewNodeType(db::DB, config::Config)::NewNodeType\n static = load_structvector(db, config, NewNodeTypeStaticV1)\n defaults = (; foo = 1, bar = false)\n # Process potential control states in the static data\n parsed_parameters, valid = parse_static_and_time(db, config, \"NewNodeType\"; static, defaults)\n\n if !valid\n error(\"Errors occurred when parsing NewNodeType data.\")\n end\n\n # Unpack the fields of static as inputs for the NewNodeType constructor\n return NewNodeType(\n NodeID.(NodeType.NewNodeType, parsed_parameters.node_id),\n parsed_parameters.some_property,\n parsed_parameters.control_mapping)\nend",
"crumbs": [
"Contributing",
"Adding node types"
@@ -76,7 +76,7 @@
"href": "contribute/addnode.html#the-jacobian",
"title": "Adding node types",
"section": "1.4 The Jacobian",
- "text": "1.4 The Jacobian\nSee Equations for a mathematical description of the Jacobian.\nBefore the Julia core runs its simulation, the sparsity structure jac_prototype of \\(J\\) is determined with get_jac_prototype in utils.jl. This function runs trough all node types and looks for nodes that create dependencies between states. It creates a sparse matrix of zeros and ones, where the ones denote locations of possible non-zeros in \\(J\\).\nWe divide the various node types in groups based on what type of state dependencies they yield, and these groups are discussed below. Each group has its own method update_jac_prototype! in utils.jl for the sparsity structure induced by nodes of that group. NewNodeType should be added to the signature of one these methods, or to the list of node types that do not contribute to the Jacobian in the method of update_jac_prototype! whose signature contains node::AbstractParameterNode. Of course it is also possible that a new method of update_jac_prototype! has to be introduced.\nThe current dependency groups are:\n\nOut-neighbor dependencies: examples are TabulatedRatingCurve, Pump (the latter only in the reduction factor regime and not PID controlled). If the in-neighbor of a node of this group is a basin, then the storage of this basin affects itself and the storage of the outneighbor (or the basin one node further if it is connected with a FractionalFlow in between) if that is also a basin;\nEither-neighbor dependencies: examples are LinearResistance, ManningResistance. If either the in-neighbor or out-neighbor of a node of this group is a basin, the storage of this basin depends on itself. If both the in-neighbor and the out-neighbor are basins, their storages also depend on eachother.\nThe PidControl node is a special case which is discussed in equations.\n\nUsing jac_prototype the Jacobian of water_balance! is computed automatically using ForwardDiff.jl with memory management provided by PreallocationTools.jl. These computations make use of DiffCache and dual numbers.",
+ "text": "1.4 The Jacobian\nSee Equations for a mathematical description of the Jacobian.\nBefore the Julia core runs its simulation, the sparsity structure jac_prototype of \\(J\\) is determined with get_jac_prototype in sparsity.jl. This function runs trough all node types and looks for nodes that create dependencies between states. It creates a sparse matrix of zeros and ones, where the ones denote locations of possible non-zeros in \\(J\\). Note that only nodes that set flows in the physical layer (or have their own state like PidControl) affect the sparsity structure.\nWe divide the various node types in groups based on what type of state dependencies they yield, and these groups are discussed below. Each group has its own method update_jac_prototype! in utils.jl for the sparsity structure induced by nodes of that group. NewNodeType should be added to the signature of one these methods, or to the list of node types that do not contribute to the Jacobian in the method of update_jac_prototype! whose signature contains node::AbstractParameterNode. Of course it is also possible that a new method of update_jac_prototype! has to be introduced.\nThe current dependency groups are:\n\nOut-neighbor dependencies: examples are TabulatedRatingCurve, Pump (the latter only in the reduction factor regime and not PID controlled). If the in-neighbor of a node of this group is a basin, then the storage of this basin affects itself and the storage of the outneighbor (or the basin one node further if it is connected with a FractionalFlow in between) if that is also a basin;\nEither-neighbor dependencies: examples are LinearResistance, ManningResistance. If either the in-neighbor or out-neighbor of a node of this group is a basin, the storage of this basin depends on itself. If both the in-neighbor and the out-neighbor are basins, their storages also depend on eachother.\nThe PidControl node is a special case which is discussed in equations.\n\nUsing jac_prototype the Jacobian of water_balance! is computed automatically using ForwardDiff.jl with memory management provided by PreallocationTools.jl. These computations make use of DiffCache and dual numbers.",
"crumbs": [
"Contributing",
"Adding node types"
@@ -87,7 +87,7 @@
"href": "contribute/addnode.html#python-class",
"title": "Adding node types",
"section": "2.1 Python class",
- "text": "2.1 Python class\nCreate a new file python/ribasim/ribasim/node_types/new_node_type.py which is structured as follows:\nfrom typing import Optional\n\nimport pandera as pa\nfrom pandera.engines.pandas_engine import PydanticModel\nfrom pandera.typing import DataFrame\nfrom pydantic import ConfigDict\n\nfrom ribasim import models\nfrom ribasim.input_base import TableModel\n\n__all__ = (\"NewNodeType\",)\n\nclass StaticSchema(pa.SchemaModel):\n class Config:\n \"\"\"Config with dataframe-level data type.\"\"\"\n\n dtype = PydanticModel(models.NewNodeTypeStatic)\n\n# Possible other schemas\n\n\nclass NewNodeType(TableModel):\n \"\"\"\n Description of this node type.\n\n Parameters\n ----------\n static: pandas.DataFrame\n table with data for this node type.\n\n possible other schemas\n \"\"\"\n\n static: DataFrame[StaticSchema] | None\n # possible other schemas\n\n model_config = ConfigDict(validate_assignment=True)\n\n def sort(self):\n self.static.sort_values(\"node_id\", ignore_index=True, inplace=True)\nThe sort method should implement the same sorting as in validation.jl.\nNow in both python/ribasim/ribasim/__init__.py and python/ribasim/ribasim/node_types/__init__.py add\n\nfrom ribasim.node_types.new_node_type import NewNodeType;\n\"NewNodeType\" to __all__.\n\nIn python/ribasim/ribasim/model.py, add\n\nfrom ribasim.new_node_type import NewNodeType;\nnew_node_type as a parameter and in the docstring of the Model class.\n\nIn python/ribasim/ribasim/geometry/node.py add a color and shape description in the MARKERS and COLORS dictionaries.",
+ "text": "2.1 Python class\nIn python/ribasim/ribasim/config.py add\n\nthe above defined schemas to the imports from ribasim.schemas. This requires code generation to work, see Finishing up;\na class of the following form with all schemas associated with the node type:\n\nclass NewNodeType(NodeModel):\n static: TableModel[NewNodeTypeStaticSchema] = Field(\n default_factory=TableModel[NewNodeTypeStaticSchema],\n json_schema_extra={\"sort_keys\": [\"node_id\"]},\n )\nIn python/ribasim/ribasim/__init__.py add\n\nNewNodeType to the imports from ribasim.config;\n\"NewNodeType\" to __all__.\n\nIn python/ribasim/ribasim/model.py, add\n\nNewNodeType to the imports from ribasim.config;\nnew_node_type as a parameter and in the docstring of the Model class.\n\nIn python/ribasim/ribasim/geometry/node.py add a color and shape description in the MARKERS and COLORS dictionaries.",
"crumbs": [
"Contributing",
"Adding node types"
@@ -241,7 +241,7 @@
"href": "python/reference/index.html",
"title": "1 API Reference",
"section": "",
- "text": "The Model class represents an entire Ribasim model.\n\n\n\nModel\n\n\n\n\n\n\n\nThe Edge database layer.\n\n\n\nEdgeTable\nDefines the connections between nodes.\n\n\n\n\n\n\nAvailable node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control",
+ "text": "The Model class represents an entire Ribasim model.\n\n\n\nModel\n\n\n\n\n\n\n\nThe Edge database layer.\n\n\n\nEdgeTable\nDefines the connections between nodes.\n\n\n\n\n\n\nAvailable node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control\n\n\n\nnodes.flow_demand\n\n\n\nnodes.level_demand",
"crumbs": [
"Python tooling",
"API Reference"
@@ -274,7 +274,7 @@
"href": "python/reference/index.html#node-types",
"title": "1 API Reference",
"section": "",
- "text": "Available node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control",
+ "text": "Available node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control\n\n\n\nnodes.flow_demand\n\n\n\nnodes.level_demand",
"crumbs": [
"Python tooling",
"API Reference"
@@ -288,11 +288,18 @@
"text": "1 nodes.user_demand\nnodes.user_demand"
},
{
- "objectID": "python/reference/nodes.level_boundary.html",
- "href": "python/reference/nodes.level_boundary.html",
- "title": "1 nodes.level_boundary",
+ "objectID": "python/reference/nodes.terminal.html",
+ "href": "python/reference/nodes.terminal.html",
+ "title": "1 nodes.terminal",
"section": "",
- "text": "1 nodes.level_boundary\nnodes.level_boundary"
+ "text": "1 nodes.terminal\nnodes.terminal"
+ },
+ {
+ "objectID": "python/reference/nodes.fractional_flow.html",
+ "href": "python/reference/nodes.fractional_flow.html",
+ "title": "1 nodes.fractional_flow",
+ "section": "",
+ "text": "1 nodes.fractional_flow\nnodes.fractional_flow"
},
{
"objectID": "python/reference/nodes.tabulated_rating_curve.html",
@@ -398,7 +405,7 @@
"href": "build/index.html#types",
"title": "1 API Reference",
"section": "1.2 Types",
- "text": "1.2 Types\n# Ribasim.Allocation — Type.\nObject for all information about allocation allocationnetworkids: The unique sorted allocation network IDs allocation models: The allocation models for the main network and subnetworks corresponding to allocationnetworkids mainnetworkconnections: (fromid, toid) from the main network to the subnetwork per subnetwork priorities: All used priority values. subnetworkdemands: The demand of an edge from the main network to a subnetwork recorddemand: A record of demands and allocated flows for nodes that have these. record_flow: A record of all flows computed by allocation optimization, eventually saved to output file\nsource\n# Ribasim.AllocationModel — Type.\nStore information for a subnetwork used for allocation.\nallocationnetworkid: The ID of this allocation network capacity: The capacity per edge of the allocation network, as constrained by nodes that have a maxflowrate problem: The JuMP.jl model for solving the allocation problem Δt_allocation: The time interval between consecutive allocation solves\nsource\n# Ribasim.AllocationModel — Method.\nConstruct the JuMP.jl problem for allocation.\nInputs\np: Ribasim problem parameters Δt_allocation: The timestep between successive allocation solves\nOutputs\nAn AllocationModel object.\nsource\n# Ribasim.Basin — Type.\nRequirements:\n\nMust be positive: precipitation, evaporation, infiltration, drainage\nIndex points to a Basin\nvolume, area, level must all be positive and monotonic increasing.\n\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of vectors or Arrow Tables, and is added to avoid type instabilities. The nodeid are Indices to support fast lookup of e.g. currentlevel using ID.\nif autodiff T = DiffCache{Vector{Float64}} else T = Vector{Float64} end\nsource\n# Ribasim.DiscreteControl — Type.\nnodeid: node ID of the DiscreteControl node; these are not unique but repeated by the amount of conditions of this DiscreteControl node listennodeid: the ID of the node being condition on variable: the name of the variable in the condition greaterthan: The threshold value in the condition conditionvalue: The current value of each condition controlstate: Dictionary: node ID => (control state, control state start) logic_mapping: Dictionary: (control node ID, truth state) => control state record: Namedtuple with discrete control information for results\nsource\n# Ribasim.EdgeMetadata — Type.\nType for storing metadata of edges in the graph: id: ID of the edge (only used for labeling flow output) type: type of the edge allocationnetworkidsource: ID of allocation network where this edge is a source (0 if not a source) fromid: the node ID of the source node toid: the node ID of the destination node allocationflow: whether this edge has a flow in an allocation network node_ids: if this edge has allocation flow, these are all the nodes from the physical layer this edge consists of\nsource\n# Ribasim.FlatVector — Type.\nstruct FlatVector{T} <: AbstractVector{T}\nA FlatVector is an AbstractVector that iterates the T of a Vector{Vector{T}}.\nEach inner vector is assumed to be of equal length.\nIt is similar to Iterators.flatten, though that doesn’t work with the Tables.Column interface, which needs length and getindex support.\nsource\n# Ribasim.FlowBoundary — Type.\nnodeid: node ID of the FlowBoundary node active: whether this node is active and thus contributes flow flowrate: target flow rate\nsource\n# Ribasim.FractionalFlow — Type.\nRequirements:\n\nfrom: must be (TabulatedRatingCurve,) node\nto: must be (Basin,) node\nfraction must be positive.\n\nnodeid: node ID of the TabulatedRatingCurve node fraction: The fraction in [0,1] of flow the node lets through controlmapping: dictionary from (nodeid, controlstate) to fraction\nsource\n# Ribasim.InNeighbors — Type.\nIterate over incoming neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.LevelBoundary — Type.\nnode_id: node ID of the LevelBoundary node active: whether this node is active level: the fixed level of this ‘infinitely big basin’\nsource\n# Ribasim.LevelDemand — Type.\nnodeid: node ID of the LevelDemand node minlevel: The minimum target level of the connected basin(s) max_level: The maximum target level of the connected basin(s) priority: If in a shortage state, the priority of the demand of the connected basin(s)\nsource\n# Ribasim.LinearResistance — Type.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\n\nnodeid: node ID of the LinearResistance node active: whether this node is active and thus contributes flows resistance: the resistance to flow; Q*unlimited = Δh/resistancemax_flow_rate: the maximum flow rate allowed through the node;Q = clamp(Q*unlimited, -max*flow*rate, max*flow*rate) controlmapping: dictionary from (nodeid, controlstate) to resistance and/or active state\nsource\n# Ribasim.ManningResistance — Type.\nThis is a simple Manning-Gauckler reach connection.\n\nLength describes the reach length.\nroughness describes Manning’s n in (SI units).\n\nThe profile is described by a trapezoid:\n \\ / ^\n \\ / |\n \\ / | dz\nbottom \\______/ |\n^ <--->\n| dy\n| <------>\n| width\n|\n|\n+ datum (e.g. MSL)\nWith profile_slope = dy / dz. A rectangular profile requires a slope of 0.0.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\nlength > 0\nroughess > 0\nprofile_width >= 0\nprofile_slope >= 0\n(profilewidth == 0) xor (profileslope == 0)\n\nsource\n# Ribasim.Model — Type.\nModel(config_path::AbstractString)\nModel(config::Config)\nInitialize a Model.\nThe Model struct is an initialized model, combined with the Config used to create it and saved results. The Basic Model Interface (BMI) is implemented on the Model. A Model can be created from the path to a TOML configuration file, or a Config object.\nsource\n# Ribasim.NodeMetadata — Type.\nType for storing metadata of nodes in the graph type: type of the node allocationnetworkid: Allocation network ID (0 if not in subnetwork)\nsource\n# Ribasim.OutNeighbors — Type.\nIterate over outgoing neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.Outlet — Type.\nnodeid: node ID of the Outlet node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the outlet maxflowrate: The maximum flow rate of the outlet controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this outlet is governed by PID control\nsource\n# Ribasim.PidControl — Type.\nPID control currently only supports regulating basin levels.\nnodeid: node ID of the PidControl node active: whether this node is active and thus sets flow rates listennodeid: the id of the basin being controlled pidparams: a vector interpolation for parameters changing over time. The parameters are respectively target, proportional, integral, derivative, where the last three are the coefficients for the PID equation. error: the current error; basintarget - currentlevel\nsource\n# Ribasim.Pump — Type.\nnodeid: node ID of the Pump node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the pump maxflowrate: The maximum flow rate of the pump controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this pump is governed by PID control\nsource\n# Ribasim.Subgrid — Type.\nSubgrid linearly interpolates basin levels.\nsource\n# Ribasim.TabulatedRatingCurve — Type.\nstruct TabulatedRatingCurve{C}\nRating curve from level to flow rate. The rating curve is a lookup table with linear interpolation in between. Relation can be updated in time, which is done by moving data from the time field into the tables, which is done in the update_tabulated_rating_curve callback.\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of Vectors or Arrow Primitives, and is added to avoid type instabilities.\nnodeid: node ID of the TabulatedRatingCurve node active: whether this node is active and thus contributes flows tables: The current Q(h) relationships time: The time table used for updating the tables controlmapping: dictionary from (nodeid, controlstate) to Q(h) and/or active state\nsource\n# Ribasim.Terminal — Type.\nnode_id: node ID of the Terminal node\nsource\n# Ribasim.UserDemand — Type.\ndemand: water flux demand of UserDemand per priority over time. Each UserDemand has a demand for all priorities, which is 0.0 if it is not provided explicitly. realizedbmi: Cumulative inflow volume, for read or reset by BMI only. active: whether this node is active and thus demands water allocated: water flux currently allocated to UserDemand per priority returnfactor: the factor in [0,1] of how much of the abstracted water is given back to the system min_level: The level of the source basin below which the UserDemand does not abstract\nsource\n# Ribasim.config.Config — Method.\nConfig(config_path::AbstractString; kwargs...)\nParse a TOML file to a Config. Keys can be overruled using keyword arguments. To overrule keys from a subsection, e.g. dt from the solver section, use underscores: solver_dt.\nsource",
+ "text": "1.2 Types\n# Ribasim.Allocation — Type.\nObject for all information about allocation allocationnetworkids: The unique sorted allocation network IDs allocation models: The allocation models for the main network and subnetworks corresponding to allocationnetworkids mainnetworkconnections: (fromid, toid) from the main network to the subnetwork per subnetwork priorities: All used priority values. subnetworkdemands: The demand of an edge from the main network to a subnetwork recorddemand: A record of demands and allocated flows for nodes that have these. record_flow: A record of all flows computed by allocation optimization, eventually saved to output file\nsource\n# Ribasim.AllocationModel — Type.\nStore information for a subnetwork used for allocation.\nallocationnetworkid: The ID of this allocation network capacity: The capacity per edge of the allocation network, as constrained by nodes that have a maxflowrate problem: The JuMP.jl model for solving the allocation problem Δt_allocation: The time interval between consecutive allocation solves\nsource\n# Ribasim.AllocationModel — Method.\nConstruct the JuMP.jl problem for allocation.\nInputs\nallocationnetworkid: the ID of this allocation network p: Ribasim problem parameters Δt_allocation: The timestep between successive allocation solves\nOutputs\nAn AllocationModel object.\nsource\n# Ribasim.Basin — Type.\nRequirements:\n\nMust be positive: precipitation, evaporation, infiltration, drainage\nIndex points to a Basin\nvolume, area, level must all be positive and monotonic increasing.\n\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of vectors or Arrow Tables, and is added to avoid type instabilities. The nodeid are Indices to support fast lookup of e.g. currentlevel using ID.\nif autodiff T = DiffCache{Vector{Float64}} else T = Vector{Float64} end\nsource\n# Ribasim.DiscreteControl — Type.\nnodeid: node ID of the DiscreteControl node; these are not unique but repeated by the amount of conditions of this DiscreteControl node listennodeid: the ID of the node being condition on variable: the name of the variable in the condition greaterthan: The threshold value in the condition conditionvalue: The current value of each condition controlstate: Dictionary: node ID => (control state, control state start) logic_mapping: Dictionary: (control node ID, truth state) => control state record: Namedtuple with discrete control information for results\nsource\n# Ribasim.EdgeMetadata — Type.\nType for storing metadata of edges in the graph: id: ID of the edge (only used for labeling flow output) type: type of the edge allocationnetworkidsource: ID of allocation network where this edge is a source (0 if not a source) fromid: the node ID of the source node toid: the node ID of the destination node allocationflow: whether this edge has a flow in an allocation network node_ids: if this edge has allocation flow, these are all the nodes from the physical layer this edge consists of\nsource\n# Ribasim.FlatVector — Type.\nstruct FlatVector{T} <: AbstractVector{T}\nA FlatVector is an AbstractVector that iterates the T of a Vector{Vector{T}}.\nEach inner vector is assumed to be of equal length.\nIt is similar to Iterators.flatten, though that doesn’t work with the Tables.Column interface, which needs length and getindex support.\nsource\n# Ribasim.FlowBoundary — Type.\nnodeid: node ID of the FlowBoundary node active: whether this node is active and thus contributes flow flowrate: target flow rate\nsource\n# Ribasim.FractionalFlow — Type.\nRequirements:\n\nfrom: must be (TabulatedRatingCurve,) node\nto: must be (Basin,) node\nfraction must be positive.\n\nnodeid: node ID of the TabulatedRatingCurve node fraction: The fraction in [0,1] of flow the node lets through controlmapping: dictionary from (nodeid, controlstate) to fraction\nsource\n# Ribasim.InNeighbors — Type.\nIterate over incoming neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.LevelBoundary — Type.\nnode_id: node ID of the LevelBoundary node active: whether this node is active level: the fixed level of this ‘infinitely big basin’\nsource\n# Ribasim.LevelDemand — Type.\nnodeid: node ID of the LevelDemand node minlevel: The minimum target level of the connected basin(s) max_level: The maximum target level of the connected basin(s) priority: If in a shortage state, the priority of the demand of the connected basin(s)\nsource\n# Ribasim.LinearResistance — Type.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\n\nnodeid: node ID of the LinearResistance node active: whether this node is active and thus contributes flows resistance: the resistance to flow; Q*unlimited = Δh/resistancemax_flow_rate: the maximum flow rate allowed through the node;Q = clamp(Q*unlimited, -max*flow*rate, max*flow*rate) controlmapping: dictionary from (nodeid, controlstate) to resistance and/or active state\nsource\n# Ribasim.ManningResistance — Type.\nThis is a simple Manning-Gauckler reach connection.\n\nLength describes the reach length.\nroughness describes Manning’s n in (SI units).\n\nThe profile is described by a trapezoid:\n \\ / ^\n \\ / |\n \\ / | dz\nbottom \\______/ |\n^ <--->\n| dy\n| <------>\n| width\n|\n|\n+ datum (e.g. MSL)\nWith profile_slope = dy / dz. A rectangular profile requires a slope of 0.0.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\nlength > 0\nroughess > 0\nprofile_width >= 0\nprofile_slope >= 0\n(profilewidth == 0) xor (profileslope == 0)\n\nsource\n# Ribasim.Model — Type.\nModel(config_path::AbstractString)\nModel(config::Config)\nInitialize a Model.\nThe Model struct is an initialized model, combined with the Config used to create it and saved results. The Basic Model Interface (BMI) is implemented on the Model. A Model can be created from the path to a TOML configuration file, or a Config object.\nsource\n# Ribasim.NodeMetadata — Type.\nType for storing metadata of nodes in the graph type: type of the node allocationnetworkid: Allocation network ID (0 if not in subnetwork)\nsource\n# Ribasim.OutNeighbors — Type.\nIterate over outgoing neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.Outlet — Type.\nnodeid: node ID of the Outlet node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the outlet maxflowrate: The maximum flow rate of the outlet controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this outlet is governed by PID control\nsource\n# Ribasim.PidControl — Type.\nPID control currently only supports regulating basin levels.\nnodeid: node ID of the PidControl node active: whether this node is active and thus sets flow rates listennodeid: the id of the basin being controlled pidparams: a vector interpolation for parameters changing over time. The parameters are respectively target, proportional, integral, derivative, where the last three are the coefficients for the PID equation. error: the current error; basintarget - currentlevel\nsource\n# Ribasim.Pump — Type.\nnodeid: node ID of the Pump node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the pump maxflowrate: The maximum flow rate of the pump controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this pump is governed by PID control\nsource\n# Ribasim.Subgrid — Type.\nSubgrid linearly interpolates basin levels.\nsource\n# Ribasim.TabulatedRatingCurve — Type.\nstruct TabulatedRatingCurve{C}\nRating curve from level to flow rate. The rating curve is a lookup table with linear interpolation in between. Relation can be updated in time, which is done by moving data from the time field into the tables, which is done in the update_tabulated_rating_curve callback.\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of Vectors or Arrow Primitives, and is added to avoid type instabilities.\nnodeid: node ID of the TabulatedRatingCurve node active: whether this node is active and thus contributes flows tables: The current Q(h) relationships time: The time table used for updating the tables controlmapping: dictionary from (nodeid, controlstate) to Q(h) and/or active state\nsource\n# Ribasim.Terminal — Type.\nnode_id: node ID of the Terminal node\nsource\n# Ribasim.UserDemand — Type.\ndemand: water flux demand of UserDemand per priority over time. Each UserDemand has a demand for all priorities, which is 0.0 if it is not provided explicitly. realizedbmi: Cumulative inflow volume, for read or reset by BMI only. active: whether this node is active and thus demands water allocated: water flux currently allocated to UserDemand per priority returnfactor: the factor in [0,1] of how much of the abstracted water is given back to the system min_level: The level of the source basin below which the UserDemand does not abstract\nsource\n# Ribasim.config.Config — Method.\nConfig(config_path::AbstractString; kwargs...)\nParse a TOML file to a Config. Keys can be overruled using keyword arguments. To overrule keys from a subsection, e.g. dt from the solver section, use underscores: solver_dt.\nsource",
"crumbs": [
"Julia core",
"API Reference"
@@ -409,7 +416,7 @@
"href": "build/index.html#functions",
"title": "1 API Reference",
"section": "1.3 Functions",
- "text": "1.3 Functions\n# BasicModelInterface.finalize — Method.\nBMI.finalize(model::Model)::Model\nWrite all results to the configured files.\nsource\n# BasicModelInterface.initialize — Method.\nBMI.initialize(T::Type{Model}, config_path::AbstractString)::Model\nInitialize a Model from the path to the TOML configuration file.\nsource\n# CommonSolve.solve! — Method.\nsolve!(model::Model)::ODESolution\nSolve a Model until the configured endtime.\nsource\n# Ribasim.add_basin_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a basin.\nsource\n# Ribasim.add_constraints_absolute_value! — Method.\nMinimizing |expr| can be achieved by introducing a new variable exprabs and posing the following constraints: exprabs >= expr expr_abs >= -expr\nsource\n# Ribasim.add_constraints_absolute_value_basin! — Method.\nAdd constraints so that variables Fabsbasin act as the absolute value of the expression comparing flow to a basin to its demand.\nsource\n# Ribasim.add_constraints_absolute_value_user_demand! — Method.\nAdd constraints so that variables Fabsuser_demand act as the absolute value of the expression comparing flow to a UserDemand to its demand.\nsource\n# Ribasim.add_constraints_basin_flow! — Method.\nAdd the Basin flow constraints to the allocation problem. The constraint indices are the Basin node IDs.\nConstraint: flow out of basin <= basin capacity\nsource\n# Ribasim.add_constraints_capacity! — Method.\nAdd the flow capacity constraints to the allocation problem. Only finite capacities get a constraint. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over edge <= edge capacity\nsource\n# Ribasim.add_constraints_flow_conservation! — Method.\nAdd the flow conservation constraints to the allocation problem. The constraint indices are UserDemand node IDs.\nConstraint: sum(flows out of node node) == flows into node + flow from storage and vertical fluxes\nsource\n# Ribasim.add_constraints_fractional_flow! — Method.\nAdd the fractional flow constraints to the allocation problem. The constraint indices are allocation edges over a fractional flow node.\nConstraint: flow after fractional_flow node <= fraction * inflow\nsource\n# Ribasim.add_constraints_source! — Method.\nAdd the source constraints to the allocation problem. The actual threshold values will be set before each allocation solve. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over source edge <= source flow in subnetwork\nsource\n# Ribasim.add_constraints_user_demand_returnflow! — Method.\nAdd the UserDemand returnflow constraints to the allocation problem. The constraint indices are UserDemand node IDs.\nConstraint: outflow from userdemand <= return factor inflow to user*demand\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the flow over the edge on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the existing flow over the edge between the given nodes.\nsource\n# Ribasim.add_objective_term! — Function.\nAdd a term to the objective function given by the objective type, depending in the provided flow variable and the associated demand.\nsource\n# Ribasim.add_subnetwork_connections! — Method.\nAdd the edges connecting the main network work to a subnetwork to both the main network and subnetwork allocation network.\nsource\n# Ribasim.add_user_demand_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a UserDemand.\nsource\n# Ribasim.add_variables_absolute_value! — Method.\nCertain allocation distribution types use absolute values in the objective function. Since most optimization packages do not support the absolute value function directly, New variables are introduced that act as the absolute value of an expression by posing the appropriate constraints.\nsource\n# Ribasim.add_variables_basin! — Method.\nAdd the variables for supply/demand of a basin to the problem. The variable indices are the node_ids of the basins in the subnetwork.\nsource\n# Ribasim.add_variables_flow! — Method.\nAdd the flow variables F to the allocation problem. The variable indices are (edgesourceid, edgedstid). Non-negativivity constraints are also immediately added to the flow variables.\nsource\n# Ribasim.adjust_basin_capacities! — Method.\nSet the values of the basin outflows. 2 cases:\n\nBefore the first allocation solve, set the capacities to their full capacity if there is surplus storage;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the capacities.\n\nsource\n# Ribasim.adjust_edge_capacities! — Method.\nSet the values of the edge capacities. 2 cases:\n\nBefore the first allocation solve, set the edge capacities to their full capacity;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the edge capacities.\n\nsource\n# Ribasim.adjust_source_capacities! — Method.\nAdjust the source flows.\nsource\n# Ribasim.all_neighbor_labels_type — Method.\nGet the in- and outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.allocate! — Method.\nUpdate the allocation optimization problem for the given subnetwork with the problem state and flows, solve the allocation problem and assign the results to the UserDemand.\nsource\n# Ribasim.allocation_graph — Method.\nBuild the graph used for the allocation problem.\nsource\n# Ribasim.allocation_graph_used_nodes! — Method.\nFind all nodes in the subnetwork which will be used in the allocation network. Some nodes are skipped to optimize allocation optimization.\nsource\n# Ribasim.allocation_path_exists_in_graph — Method.\nFind out whether a path exists between a start node and end node in the given allocation network.\nsource\n# Ribasim.allocation_problem — Method.\nConstruct the allocation problem for the current subnetwork as a JuMP.jl model.\nsource\n# Ribasim.allocation_table — Method.\nCreate an allocation result table for the saved data\nsource\n# Ribasim.assign_allocations! — Method.\nAssign the allocations to the UserDemand as determined by the solution of the allocation problem.\nsource\n# Ribasim.avoid_using_own_returnflow! — Method.\nRemove allocation UserDemand return flow edges that are upstream of the UserDemand itself.\nsource\n# Ribasim.basin_bottom — Method.\nReturn the bottom elevation of the basin with index i, or nothing if it doesn’t exist\nsource\n# Ribasim.basin_bottoms — Method.\nGet the bottom on both ends of a node. If only one has a bottom, use that for both.\nsource\n# Ribasim.basin_table — Method.\nCreate the basin result table from the saved data\nsource\n# Ribasim.create_callbacks — Method.\nCreate the different callbacks that are used to store results and feed the simulation with new data. The different callbacks are combined to a CallbackSet that goes to the integrator. Returns the CallbackSet and the SavedValues for flow.\nsource\n# Ribasim.create_graph — Method.\nReturn a directed metagraph with data of nodes (NodeMetadata): NodeMetadata\nand data of edges (EdgeMetadata): EdgeMetadata\nsource\n# Ribasim.create_storage_tables — Method.\nRead the Basin / profile table and return all area and level and computed storage values\nsource\n# Ribasim.datetime_since — Method.\ndatetime_since(t::Real, t0::DateTime)::DateTime\nConvert a Real that represents the seconds passed since the simulation start to the nearest DateTime. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.datetimes — Method.\nGet all saved times as a Vector{DateTime}\nsource\n# Ribasim.discrete_control_affect! — Method.\nChange parameters based on the control logic.\nsource\n# Ribasim.discrete_control_affect_downcrossing! — Method.\nAn downcrossing means that a condition (always greater than) becomes false.\nsource\n# Ribasim.discrete_control_affect_upcrossing! — Method.\nAn upcrossing means that a condition (always greater than) becomes true.\nsource\n# Ribasim.discrete_control_condition — Method.\nListens for changes in condition truths.\nsource\n# Ribasim.discrete_control_table — Method.\nCreate a discrete control result table from the saved data\nsource\n# Ribasim.expand_logic_mapping — Method.\nReplace the truth states in the logic mapping which contain wildcards with all possible explicit truth states.\nsource\n# Ribasim.find_allocation_graph_edges! — Method.\nThis loop finds allocation network edges in several ways:\n\nBetween allocation network nodes whose equivalent in the subnetwork are directly connected\nBetween allocation network nodes whose equivalent in the subnetwork are connected with one or more allocation network nodes in between\n\nsource\n# Ribasim.find_subnetwork_connections! — Method.\nFind the edges from the main network to a subnetwork.\nsource\n# Ribasim.findlastgroup — Method.\nFor an element id and a vector of elements ids, get the range of indices of the last consecutive block of id. Returns the empty range 1:0 if id is not in ids.\nsource\n# Ribasim.findsorted — Method.\nFind the index of element x in a sorted collection a. Returns the index of x if it exists, or nothing if it doesn’t. If x occurs more than once, throw an error.\nsource\n# Ribasim.flow_table — Method.\nCreate a flow result table from the saved data\nsource\n# Ribasim.formulate_basins! — Method.\nSmoothly let the evaporation flux go to 0 when at small water depths Currently at less than 0.1 m.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.formulate_flow! — Method.\nConservation of energy for two basins, a and b:\nh_a + v_a^2 / (2 * g) = h_b + v_b^2 / (2 * g) + S_f * L + C / 2 * g * (v_b^2 - v_a^2)\nWhere:\n\nha, hb are the heads at basin a and b.\nva, vb are the velocities at basin a and b.\ng is the gravitational constant.\nS_f is the friction slope.\nC is an expansion or extraction coefficient.\n\nWe assume velocity differences are negligible (va = vb):\nh_a = h_b + S_f * L\nThe friction losses are approximated by the Gauckler-Manning formula:\nQ = A * (1 / n) * R_h^(2/3) * S_f^(1/2)\nWhere:\n\nWhere A is the cross-sectional area.\nV is the cross-sectional average velocity.\nn is the Gauckler-Manning coefficient.\nR_h is the hydraulic radius.\nS_f is the friction slope.\n\nThe hydraulic radius is defined as:\nR_h = A / P\nWhere P is the wetted perimeter.\nThe average of the upstream and downstream water depth is used to compute cross-sectional area and hydraulic radius. This ensures that a basin can receive water after it has gone dry.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.get_area_and_level — Method.\nCompute the area and level of a basin given its storage. Also returns darea/dlevel as it is needed for the Jacobian.\nsource\n# Ribasim.get_basin_capacity — Method.\nGet the capacity of the basin, i.e. the maximum flow that can be abstracted from the basin if it is in a state of surplus storage (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_basin_data — Method.\nGet several variables associated with a basin:\n\nIts current storage\nThe allocation update interval\nThe influx (sum of instantaneous vertical fluxes of the basin)\nThe index of the connected level_demand node (0 if such a node does not exist)\nThe index of the basin\n\nsource\n# Ribasim.get_basin_demand — Method.\nGet the demand of the basin, i.e. how large a flow the basin needs to get to its minimum target level (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_chunk_sizes — Method.\nGet the chunk sizes for DiffCache; differentiation w.r.t. u and t (the latter only if a Rosenbrock algorithm is used).\nsource\n# Ribasim.get_compressor — Method.\nGet the compressor based on the Results section\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given horizontal (selfloop) edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_fractional_flow_connected_basins — Method.\nGet the node type specific indices of the fractional flows and basins, that are consecutively connected to a node of given id.\nsource\n# Ribasim.get_jac_prototype — Method.\nGet a sparse matrix whose sparsity matches the sparsity of the Jacobian of the ODE problem. All nodes are taken into consideration, also the ones that are inactive.\nIn Ribasim the Jacobian is typically sparse because each state only depends on a small number of other states.\nNote: the name ‘prototype’ does not mean this code is a prototype, it comes from the naming convention of this sparsity structure in the differentialequations.jl docs.\nsource\n# Ribasim.get_level — Method.\nGet the current water level of a node ID. The ID can belong to either a Basin or a LevelBoundary. storage: tells ForwardDiff whether this call is for differentiation or not\nsource\n# Ribasim.get_scalar_interpolation — Method.\nLinear interpolation of a scalar with constant extrapolation.\nsource\n# Ribasim.get_storage_from_level — Method.\nGet the storage of a basin from its level.\nsource\n# Ribasim.get_storages_and_levels — Method.\nGet the storage and level of all basins as matrices of nbasin × ntime\nsource\n# Ribasim.get_storages_from_levels — Method.\nCompute the storages of the basins based on the water level of the basins.\nsource\n# Ribasim.get_tstops — Method.\nFrom an iterable of DateTimes, find the times the solver needs to stop\nsource\n# Ribasim.get_value — Method.\nGet a value for a condition. Currently supports getting levels from basins and flows from flow boundaries.\nsource\n# Ribasim.id_index — Method.\nGet the index of an ID in a set of indices.\nsource\n# Ribasim.indicate_allocation_flow! — Method.\nAdd to the edge metadata that the given edge is used for allocation flow. If the edge does not exist, it is created.\nsource\n# Ribasim.inflow_id — Method.\nGet the unique inneighbor over a flow edge.\nsource\n# Ribasim.inflow_ids — Method.\nGet the inneighbors over flow edges.\nsource\n# Ribasim.inflow_ids_allocation — Method.\nGet the inneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.inneighbor_labels_type — Method.\nGet the inneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.inoutflow_ids — Method.\nGet the in- and outneighbors over flow edges.\nsource\n# Ribasim.integrate_flows! — Method.\nIntegrate flows over the last timestep\nsource\n# Ribasim.is_allocation_source — Method.\nFind out whether the given edge is a source for an allocation network.\nsource\n# Ribasim.is_current_module — Method.\nis_current_module(log::LogMessageType)::Bool\nReturns true if the log message is from the current module or a submodule.\n\nSee https://github.com/JuliaLogging/LoggingExtras.jl/blob/d35e7c8cfc197853ee336ace17182e6ed36dca24/src/CompositionalLoggers/earlyfiltered.jl#L39\nfor the information available in log.\nsource\n# Ribasim.is_flow_constraining — Method.\nWhether the given node node is flow constraining by having a maximum flow rate.\nsource\n# Ribasim.is_flow_direction_constraining — Method.\nWhether the given node is flow direction constraining (only in direction of edges).\nsource\n# Ribasim.load_data — Method.\nload_data(db::DB, config::Config, nodetype::Symbol, kind::Symbol)::Union{Table, Query, Nothing}\nLoad data from Arrow files if available, otherwise the database. Returns either an Arrow.Table, SQLite.Query or nothing if the data is not present.\nsource\n# Ribasim.load_structvector — Method.\nload_structvector(db::DB, config::Config, ::Type{T})::StructVector{T}\nLoad data from Arrow files if available, otherwise the database. Always returns a StructVector of the given struct type T, which is empty if the table is not found. This function validates the schema, and enforces the required sort order.\nsource\n# Ribasim.low_storage_factor — Method.\nIf id is a Basin with storage below the threshold, return a reduction factor != 1\nsource\n# Ribasim.main — Method.\nmain(toml_path::AbstractString)::Cint\nmain(ARGS::Vector{String})::Cint\nmain()::Cint\nThis is the main entry point of the application. Performs argument parsing and sets up logging for both terminal and file. Calls Ribasim.run() and handles exceptions to convert to exit codes.\nsource\n# Ribasim.metadata_from_edge — Method.\nGet the metadata of an edge in the graph from an edge of the underlying DiGraph.\nsource\n# Ribasim.nodefields — Method.\nGet all node fieldnames of the parameter object.\nsource\n# Ribasim.nodetype — Method.\nFrom a SchemaVersion(“ribasim.flowboundary.static”, 1) return (:FlowBoundary, :static)\nsource\n# Ribasim.outflow_id — Method.\nGet the unique outneighbor over a flow edge.\nsource\n# Ribasim.outflow_ids — Method.\nGet the outneighbors over flow edges.\nsource\n# Ribasim.outflow_ids_allocation — Method.\nGet the outneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.outneighbor_labels_type — Method.\nGet the outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.parse_static_and_time — Method.\nProcess the data in the static and time tables for a given node type. The ‘defaults’ named tuple dictates how missing data is filled in. ‘time_interpolatables’ is a vector of Symbols of parameter names for which a time interpolation (linear) object must be constructed. The control mapping for DiscreteControl is also constructed in this function. This function currently does not support node states that are defined by more than one row in a table, as is the case for TabulatedRatingCurve.\nsource\n# Ribasim.pkgversion — Method.\nGet the package version of a given module\nsource\n# Ribasim.process_allocation_graph_edges! — Method.\nFor the composite allocation network edges:\n\nFind out whether they are connected to allocation network nodes on both ends\nCompute their capacity\nFind out their allowed flow direction(s)\n\nsource\n# Ribasim.profile_storage — Method.\nCalculate a profile storage by integrating the areas over the levels\nsource\n# Ribasim.qh_interpolation — Method.\nFrom a table with columns nodeid, flowrate (Q) and level (h), create a LinearInterpolation from level to flow rate for a given node_id.\nsource\n# Ribasim.reduction_factor — Method.\nFunction that goes smoothly from 0 to 1 in the interval [0,threshold], and is constant outside this interval.\nsource\n# Ribasim.run — Method.\nrun(config_file::AbstractString)::Model\nrun(config::Config)::Model\nRun a Model, given a path to a TOML configuration file, or a Config object. Running a model includes initialization, solving to the end with [solve!](@ref) and writing results with write_results.\nsource\n# Ribasim.save_allocation_flows! — Method.\nSave the allocation flows per basin and physical edge.\nsource\n# Ribasim.save_demands_and_allocations! — Method.\nSave the demands and allocated flows for UserDemand and Basin. Note: Basin supply (negative demand) is only saved for the first priority.\nsource\n# Ribasim.save_flow — Method.\nCompute the average flows over the last saveat interval and write them to SavedValues\nsource\n# Ribasim.save_subgrid_level — Method.\nInterpolate the levels and save them to SavedValues\nsource\n# Ribasim.scalar_interpolation_derivative — Method.\nDerivative of scalar interpolation.\nsource\n# Ribasim.seconds_since — Method.\nseconds_since(t::DateTime, t0::DateTime)::Float64\nConvert a DateTime to a float that is the number of seconds since the start of the simulation. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.set_current_value! — Method.\nFrom a timeseries table time, load the most recent applicable data into table. table must be a NamedTuple of vectors with all variables that must be loaded. The most recent applicable data is non-NaN data for a given ID that is on or before t.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q over the edge between the given nodes.\nsource\n# Ribasim.set_fractional_flow_in_allocation! — Method.\nUpdate the fractional flow fractions in an allocation problem.\nsource\n# Ribasim.set_initial_discrete_controlled_parameters! — Method.\nSet parameters of nodes that are controlled by DiscreteControl to the values corresponding to the initial state of the model.\nsource\n# Ribasim.set_is_pid_controlled! — Method.\nSet ispidcontrolled to true for those pumps and outlets that are PID controlled\nsource\n# Ribasim.set_objective_priority! — Method.\nSet the objective for the given priority. For an objective with absolute values this also involves adjusting constraints.\nsource\n# Ribasim.set_static_value! — Method.\nLoad data from a source table static into a destination table. Data is matched based on the node_id, which is sorted.\nsource\n# Ribasim.set_table_row! — Method.\nUpdate table at row index i, with the values of a given row. table must be a NamedTuple of vectors with all variables that must be loaded. The row must contain all the column names that are present in the table. If a value is missing, it is not set.\nsource\n# Ribasim.sorted_table! — Method.\nDepending on if a table can be sorted, either sort it or assert that it is sorted.\nTables loaded from the database into memory can be sorted. Tables loaded from Arrow files are memory mapped and can therefore not be sorted.\nsource\n# Ribasim.tsaves — Method.\nGet all saved times in seconds since start\nsource\n# Ribasim.update_allocation! — Method.\nSolve the allocation problem for all demands and assign allocated abstractions.\nsource\n# Ribasim.update_basin — Method.\nLoad updates from ‘Basin / time’ into the parameters\nsource\n# Ribasim.update_jac_prototype! — Method.\nMethod for nodes that do not contribute to the Jacobian\nsource\n# Ribasim.update_jac_prototype! — Method.\nThe controlled basin affects itself and the basins upstream and downstream of the controlled pump affect eachother if there is a basin upstream of the pump. The state for the integral term and the controlled basin affect eachother, and the same for the integral state and the basin upstream of the pump if it is indeed a basin.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the unique node downstream of these nodes are basins, then these directly depend on eachother and affect the Jacobian 2x Basins always depend on themselves.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the nodes down stream (or one node further if a fractional flow is in between) are basins, then the downstream basin depends on the upstream basin(s) and affect the Jacobian as many times as there are downstream basins Upstream basins always depend on themselves.\nsource\n# Ribasim.update_tabulated_rating_curve! — Method.\nLoad updates from ‘TabulatedRatingCurve / time’ into the parameters\nsource\n# Ribasim.valid_discrete_control — Method.\nCheck:\n\nwhether control states are defined for discrete controlled nodes;\nWhether the supplied truth states have the proper length;\nWhether look_ahead is only supplied for condition variables given by a time-series.\n\nsource\n# Ribasim.valid_edge_types — Method.\nCheck that only supported edge types are declared.\nsource\n# Ribasim.valid_edges — Method.\nTest for each node given its node type whether the nodes that\nare downstream (‘down-edge’) of this node are of an allowed type\nsource\n# Ribasim.valid_flow_rates — Method.\nTest whether static or discrete controlled flow rates are indeed non-negative.\nsource\n# Ribasim.valid_fractional_flow — Method.\nCheck that nodes that have fractional flow outneighbors do not have any other type of outneighbor, that the fractions leaving a node add up to ≈1 and that the fractions are non-negative.\nsource\n# Ribasim.valid_n_neighbors — Method.\nTest for each node given its node type whether it has an allowed number of flow/control inneighbors and outneighbors\nsource\n# Ribasim.valid_profiles — Method.\nCheck whether the profile data has no repeats in the levels and the areas start positive.\nsource\n# Ribasim.valid_sources — Method.\nThe source nodes must only have one allocation outneighbor and no allocation inneighbors.\nsource\n# Ribasim.valid_subgrid — Method.\nValidate the entries for a single subgrid element.\nsource\n# Ribasim.water_balance! — Method.\nThe right hand side function of the system of ODEs set up by Ribasim.\nsource\n# Ribasim.write_arrow — Method.\nWrite a result table to disk as an Arrow file\nsource\n# Ribasim.write_results — Method.\nwrite_results(model::Model)::Model\nWrite all results to the Arrow files as specified in the model configuration.\nsource\n# Ribasim.config.algorithm — Method.\nCreate an OrdinaryDiffEqAlgorithm from solver config\nsource\n# Ribasim.config.convert_dt — Method.\nConvert the dt from our Config to SciML stepsize control arguments\nsource\n# Ribasim.config.convert_saveat — Method.\nConvert the saveat Float64 from our Config to SciML’s saveat\nsource\n# Ribasim.config.input_path — Method.\nConstruct a path relative to both the TOML directory and the optional input_dir\nsource\n# Ribasim.config.results_path — Method.\nConstruct a path relative to both the TOML directory and the optional results_dir\nsource\n# Ribasim.config.snake_case — Method.\nConvert a string from CamelCase to snake_case.\nsource",
+ "text": "1.3 Functions\n# BasicModelInterface.finalize — Method.\nBMI.finalize(model::Model)::Model\nWrite all results to the configured files.\nsource\n# BasicModelInterface.initialize — Method.\nBMI.initialize(T::Type{Model}, config_path::AbstractString)::Model\nInitialize a Model from the path to the TOML configuration file.\nsource\n# CommonSolve.solve! — Method.\nsolve!(model::Model)::ODESolution\nSolve a Model until the configured endtime.\nsource\n# Ribasim.add_basin_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a basin.\nsource\n# Ribasim.add_constraints_absolute_value! — Method.\nMinimizing |expr| can be achieved by introducing a new variable exprabs and posing the following constraints: exprabs >= expr expr_abs >= -expr\nsource\n# Ribasim.add_constraints_absolute_value_flow_demand! — Method.\nAdd constraints so that variables Fabsflow_demand act as the absolute value of the expression comparing flow to a flow buffer to the flow demand.\nsource\n# Ribasim.add_constraints_absolute_value_level_demand! — Method.\nAdd constraints so that variables Fabslevel_demand act as the absolute value of the expression comparing flow to a basin to its demand.\nsource\n# Ribasim.add_constraints_absolute_value_user_demand! — Method.\nAdd constraints so that variables Fabsuser_demand act as the absolute value of the expression comparing flow to a UserDemand to its demand.\nsource\n# Ribasim.add_constraints_basin_flow! — Method.\nAdd the Basin flow constraints to the allocation problem. The constraint indices are the Basin node IDs.\nConstraint: flow out of basin <= basin capacity\nsource\n# Ribasim.add_constraints_buffer! — Method.\nAdd the buffer outflow constraints to the allocation problem. The constraint indices are the node IDs of the nodes that have a flow demand.\nConstraint: flow out of buffer <= flow buffer capacity\nsource\n# Ribasim.add_constraints_capacity! — Method.\nAdd the flow capacity constraints to the allocation problem. Only finite capacities get a constraint. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over edge <= edge capacity\nsource\n# Ribasim.add_constraints_conservation_basin! — Method.\nAdd the basin flow conservation constraints to the allocation problem. The constraint indices are Basin node IDs.\nConstraint: sum(flows out of basin) == sum(flows into basin) + flow from storage and vertical fluxes\nsource\n# Ribasim.add_constraints_conservation_flow_demand! — Method.\nAdd the conservation constraints for connector nodes with a flow demand to the allocation problem. The constraint indices are node IDs of the nodes with the flow demand (so not the IDs of the FlowDemand nodes).\nConstraint: flow into node + flow out of buffer = flow out of node + flow into buffer\nsource\n# Ribasim.add_constraints_conservation_subnetwork! — Method.\nAdd the subnetwork inlet flow conservation constraints to the allocation problem. The constraint indices are node IDs subnetwork inlet edge dst IDs.\nConstraint: sum(flows into node) == sum(flows out of node)\nsource\n# Ribasim.add_constraints_flow_demand_outflow! — Method.\nAdd the flow demand node outflow constraints to the allocation problem. The constraint indices are the node IDs of the nodes that have a flow demand.\nConstraint: flow out of node with flow demand <= ∞ if not at flow demand priority, 0.0 otherwise\nsource\n# Ribasim.add_constraints_fractional_flow! — Method.\nAdd the fractional flow constraints to the allocation problem. The constraint indices are allocation edges over a fractional flow node.\nConstraint: flow after fractional_flow node <= fraction * inflow\nsource\n# Ribasim.add_constraints_source! — Method.\nAdd the source constraints to the allocation problem. The actual threshold values will be set before each allocation solve. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over source edge <= source flow in subnetwork\nsource\n# Ribasim.add_constraints_user_demand_returnflow! — Method.\nAdd the UserDemand returnflow constraints to the allocation problem. The constraint indices are UserDemand node IDs. Constraint: outflow from userdemand <= return factor inflow to user*demand\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the flow over the edge on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the existing flow over the edge between the given nodes.\nsource\n# Ribasim.add_flow_demand_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a node with a a flow demand.\nsource\n# Ribasim.add_objective_term! — Function.\nAdd a term to the objective function given by the objective type, depending in the provided flow variable and the associated demand.\nsource\n# Ribasim.add_subnetwork_connections! — Method.\nAdd the edges connecting the main network work to a subnetwork to both the main network and subnetwork allocation network.\nsource\n# Ribasim.add_user_demand_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a UserDemand.\nsource\n# Ribasim.add_variables_absolute_value! — Method.\nCertain allocation distribution types use absolute values in the objective function. Since most optimization packages do not support the absolute value function directly, New variables are introduced that act as the absolute value of an expression by posing the appropriate constraints.\nsource\n# Ribasim.add_variables_basin! — Method.\nAdd the variables for supply/demand of a basin to the problem. The variable indices are the node_ids of the basins with a level demand in the subnetwork.\nsource\n# Ribasim.add_variables_flow! — Method.\nAdd the flow variables F to the allocation problem. The variable indices are (edgesourceid, edgedstid). Non-negativivity constraints are also immediately added to the flow variables.\nsource\n# Ribasim.add_variables_flow_buffer! — Method.\nAdd the variables for supply/demand of a node with a flow demand to the problem. The variable indices are the node_ids of the nodes with a flow demand in the subnetwork.\nsource\n# Ribasim.adjust_capacities_basin! — Method.\nSet the capacities of the basin outflows. 2 cases:\n\nBefore the first allocation solve, set the capacities to their full capacity if there is surplus storage;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the capacities.\n\nsource\n# Ribasim.adjust_capacities_buffers! — Method.\nAdjust the capacities of the flow buffers of nodes with a flow demand. 2 cases:\n\nBefore the first allocation solve, set the capacities to 0.0;\nBefore an allocation solve, add the flow into the buffer and remove the flow out of the buffer from the buffer capacity.\n\nsource\n# Ribasim.adjust_capacities_edge! — Method.\nSet the values of the edge capacities. 2 cases:\n\nBefore the first allocation solve, set the edge capacities to their full capacity;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the edge capacities.\n\nsource\n# Ribasim.adjust_capacities_flow_demand_outflow! — Method.\nSet the capacity of the outflow edge from a node with a flow demand:\n\nTo Inf if the current priority is other than the priority of the flow demand\nTo 0.0 if the current priority is equal to the priority of the flow demand\n\nsource\n# Ribasim.adjust_capacities_source! — Method.\nAdjust the source flows.\nsource\n# Ribasim.adjust_demands_flow! — Method.\nSet the demand of the flow demand nodes. 2 cases:\n\nBefore the first allocation solve, set the demands to their full value;\nBefore an allocation solve, subtract the flow trough the node with a flow demand from the total flow demand (which will be used at the priority of the flow demand only).\n\nsource\n# Ribasim.all_neighbor_labels_type — Method.\nGet the in- and outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.allocate! — Method.\nUpdate the allocation optimization problem for the given subnetwork with the problem state and flows, solve the allocation problem and assign the results to the UserDemand.\nsource\n# Ribasim.allocation_graph — Method.\nBuild the graph used for the allocation problem.\nsource\n# Ribasim.allocation_graph_used_nodes! — Method.\nFind all nodes in the subnetwork which will be used in the allocation network. Some nodes are skipped to optimize allocation optimization.\nsource\n# Ribasim.allocation_path_exists_in_graph — Method.\nFind out whether a path exists between a start node and end node in the given allocation network.\nsource\n# Ribasim.allocation_problem — Method.\nConstruct the allocation problem for the current subnetwork as a JuMP.jl model.\nsource\n# Ribasim.allocation_table — Method.\nCreate an allocation result table for the saved data\nsource\n# Ribasim.assign_allocations! — Method.\nAssign the allocations to the UserDemand as determined by the solution of the allocation problem.\nsource\n# Ribasim.avoid_using_own_returnflow! — Method.\nRemove allocation UserDemand return flow edges that are upstream of the UserDemand itself.\nsource\n# Ribasim.basin_bottom — Method.\nReturn the bottom elevation of the basin with index i, or nothing if it doesn’t exist\nsource\n# Ribasim.basin_bottoms — Method.\nGet the bottom on both ends of a node. If only one has a bottom, use that for both.\nsource\n# Ribasim.basin_table — Method.\nCreate the basin result table from the saved data\nsource\n# Ribasim.create_callbacks — Method.\nCreate the different callbacks that are used to store results and feed the simulation with new data. The different callbacks are combined to a CallbackSet that goes to the integrator. Returns the CallbackSet and the SavedValues for flow.\nsource\n# Ribasim.create_graph — Method.\nReturn a directed metagraph with data of nodes (NodeMetadata): NodeMetadata\nand data of edges (EdgeMetadata): EdgeMetadata\nsource\n# Ribasim.create_storage_tables — Method.\nRead the Basin / profile table and return all area and level and computed storage values\nsource\n# Ribasim.datetime_since — Method.\ndatetime_since(t::Real, t0::DateTime)::DateTime\nConvert a Real that represents the seconds passed since the simulation start to the nearest DateTime. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.datetimes — Method.\nGet all saved times as a Vector{DateTime}\nsource\n# Ribasim.discrete_control_affect! — Method.\nChange parameters based on the control logic.\nsource\n# Ribasim.discrete_control_affect_downcrossing! — Method.\nAn downcrossing means that a condition (always greater than) becomes false.\nsource\n# Ribasim.discrete_control_affect_upcrossing! — Method.\nAn upcrossing means that a condition (always greater than) becomes true.\nsource\n# Ribasim.discrete_control_condition — Method.\nListens for changes in condition truths.\nsource\n# Ribasim.discrete_control_table — Method.\nCreate a discrete control result table from the saved data\nsource\n# Ribasim.expand_logic_mapping — Method.\nReplace the truth states in the logic mapping which contain wildcards with all possible explicit truth states.\nsource\n# Ribasim.find_allocation_graph_edges! — Method.\nThis loop finds allocation network edges in several ways:\n\nBetween allocation network nodes whose equivalent in the subnetwork are directly connected\nBetween allocation network nodes whose equivalent in the subnetwork are connected with one or more allocation network nodes in between\n\nsource\n# Ribasim.find_subnetwork_connections! — Method.\nFind the edges from the main network to a subnetwork.\nsource\n# Ribasim.findlastgroup — Method.\nFor an element id and a vector of elements ids, get the range of indices of the last consecutive block of id. Returns the empty range 1:0 if id is not in ids.\nsource\n# Ribasim.findsorted — Method.\nFind the index of element x in a sorted collection a. Returns the index of x if it exists, or nothing if it doesn’t. If x occurs more than once, throw an error.\nsource\n# Ribasim.flow_table — Method.\nCreate a flow result table from the saved data\nsource\n# Ribasim.formulate_basins! — Method.\nSmoothly let the evaporation flux go to 0 when at small water depths Currently at less than 0.1 m.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.formulate_flow! — Method.\nConservation of energy for two basins, a and b:\nh_a + v_a^2 / (2 * g) = h_b + v_b^2 / (2 * g) + S_f * L + C / 2 * g * (v_b^2 - v_a^2)\nWhere:\n\nha, hb are the heads at basin a and b.\nva, vb are the velocities at basin a and b.\ng is the gravitational constant.\nS_f is the friction slope.\nC is an expansion or extraction coefficient.\n\nWe assume velocity differences are negligible (va = vb):\nh_a = h_b + S_f * L\nThe friction losses are approximated by the Gauckler-Manning formula:\nQ = A * (1 / n) * R_h^(2/3) * S_f^(1/2)\nWhere:\n\nWhere A is the cross-sectional area.\nV is the cross-sectional average velocity.\nn is the Gauckler-Manning coefficient.\nR_h is the hydraulic radius.\nS_f is the friction slope.\n\nThe hydraulic radius is defined as:\nR_h = A / P\nWhere P is the wetted perimeter.\nThe average of the upstream and downstream water depth is used to compute cross-sectional area and hydraulic radius. This ensures that a basin can receive water after it has gone dry.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.get_area_and_level — Method.\nCompute the area and level of a basin given its storage. Also returns darea/dlevel as it is needed for the Jacobian.\nsource\n# Ribasim.get_basin_capacity — Method.\nGet the capacity of the basin, i.e. the maximum flow that can be abstracted from the basin if it is in a state of surplus storage (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_basin_data — Method.\nGet several variables associated with a basin:\n\nIts current storage\nThe allocation update interval\nThe influx (sum of instantaneous vertical fluxes of the basin)\nThe index of the connected level_demand node (0 if such a node does not exist)\nThe index of the basin\n\nsource\n# Ribasim.get_basin_demand — Method.\nGet the demand of the basin, i.e. how large a flow the basin needs to get to its minimum target level (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_chunk_sizes — Method.\nGet the chunk sizes for DiffCache; differentiation w.r.t. u and t (the latter only if a Rosenbrock algorithm is used).\nsource\n# Ribasim.get_compressor — Method.\nGet the compressor based on the Results section\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given horizontal (selfloop) edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_fractional_flow_connected_basins — Method.\nGet the node type specific indices of the fractional flows and basins, that are consecutively connected to a node of given id.\nsource\n# Ribasim.get_jac_prototype — Method.\nGet a sparse matrix whose sparsity matches the sparsity of the Jacobian of the ODE problem. All nodes are taken into consideration, also the ones that are inactive.\nIn Ribasim the Jacobian is typically sparse because each state only depends on a small number of other states.\nNote: the name ‘prototype’ does not mean this code is a prototype, it comes from the naming convention of this sparsity structure in the differentialequations.jl docs.\nsource\n# Ribasim.get_level — Method.\nGet the current water level of a node ID. The ID can belong to either a Basin or a LevelBoundary. storage: tells ForwardDiff whether this call is for differentiation or not\nsource\n# Ribasim.get_scalar_interpolation — Method.\nLinear interpolation of a scalar with constant extrapolation.\nsource\n# Ribasim.get_storage_from_level — Method.\nGet the storage of a basin from its level.\nsource\n# Ribasim.get_storages_and_levels — Method.\nGet the storage and level of all basins as matrices of nbasin × ntime\nsource\n# Ribasim.get_storages_from_levels — Method.\nCompute the storages of the basins based on the water level of the basins.\nsource\n# Ribasim.get_tstops — Method.\nFrom an iterable of DateTimes, find the times the solver needs to stop\nsource\n# Ribasim.get_value — Method.\nGet a value for a condition. Currently supports getting levels from basins and flows from flow boundaries.\nsource\n# Ribasim.id_index — Method.\nGet the index of an ID in a set of indices.\nsource\n# Ribasim.indicate_allocation_flow! — Method.\nAdd to the edge metadata that the given edge is used for allocation flow. If the edge does not exist, it is created.\nsource\n# Ribasim.inflow_id — Method.\nGet the unique inneighbor over a flow edge.\nsource\n# Ribasim.inflow_ids — Method.\nGet the inneighbors over flow edges.\nsource\n# Ribasim.inflow_ids_allocation — Method.\nGet the inneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.inneighbor_labels_type — Method.\nGet the inneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.inoutflow_ids — Method.\nGet the in- and outneighbors over flow edges.\nsource\n# Ribasim.integrate_flows! — Method.\nIntegrate flows over the last timestep\nsource\n# Ribasim.is_allocation_source — Method.\nFind out whether the given edge is a source for an allocation network.\nsource\n# Ribasim.is_current_module — Method.\nis_current_module(log::LogMessageType)::Bool\nReturns true if the log message is from the current module or a submodule.\n\nSee https://github.com/JuliaLogging/LoggingExtras.jl/blob/d35e7c8cfc197853ee336ace17182e6ed36dca24/src/CompositionalLoggers/earlyfiltered.jl#L39\nfor the information available in log.\nsource\n# Ribasim.is_flow_constraining — Method.\nWhether the given node node is flow constraining by having a maximum flow rate.\nsource\n# Ribasim.is_flow_direction_constraining — Method.\nWhether the given node is flow direction constraining (only in direction of edges).\nsource\n# Ribasim.load_data — Method.\nload_data(db::DB, config::Config, nodetype::Symbol, kind::Symbol)::Union{Table, Query, Nothing}\nLoad data from Arrow files if available, otherwise the database. Returns either an Arrow.Table, SQLite.Query or nothing if the data is not present.\nsource\n# Ribasim.load_structvector — Method.\nload_structvector(db::DB, config::Config, ::Type{T})::StructVector{T}\nLoad data from Arrow files if available, otherwise the database. Always returns a StructVector of the given struct type T, which is empty if the table is not found. This function validates the schema, and enforces the required sort order.\nsource\n# Ribasim.low_storage_factor — Method.\nIf id is a Basin with storage below the threshold, return a reduction factor != 1\nsource\n# Ribasim.main — Method.\nmain(toml_path::AbstractString)::Cint\nmain(ARGS::Vector{String})::Cint\nmain()::Cint\nThis is the main entry point of the application. Performs argument parsing and sets up logging for both terminal and file. Calls Ribasim.run() and handles exceptions to convert to exit codes.\nsource\n# Ribasim.metadata_from_edge — Method.\nGet the metadata of an edge in the graph from an edge of the underlying DiGraph.\nsource\n# Ribasim.nodefields — Method.\nGet all node fieldnames of the parameter object.\nsource\n# Ribasim.nodetype — Method.\nFrom a SchemaVersion(“ribasim.flowboundary.static”, 1) return (:FlowBoundary, :static)\nsource\n# Ribasim.outflow_id — Method.\nGet the unique outneighbor over a flow edge.\nsource\n# Ribasim.outflow_ids — Method.\nGet the outneighbors over flow edges.\nsource\n# Ribasim.outflow_ids_allocation — Method.\nGet the outneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.outneighbor_labels_type — Method.\nGet the outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.parse_static_and_time — Method.\nProcess the data in the static and time tables for a given node type. The ‘defaults’ named tuple dictates how missing data is filled in. ‘time_interpolatables’ is a vector of Symbols of parameter names for which a time interpolation (linear) object must be constructed. The control mapping for DiscreteControl is also constructed in this function. This function currently does not support node states that are defined by more than one row in a table, as is the case for TabulatedRatingCurve.\nsource\n# Ribasim.pkgversion — Method.\nGet the package version of a given module\nsource\n# Ribasim.process_allocation_graph_edges! — Method.\nFor the composite allocation network edges:\n\nFind out whether they are connected to allocation network nodes on both ends\nCompute their capacity\nFind out their allowed flow direction(s)\n\nsource\n# Ribasim.profile_storage — Method.\nCalculate a profile storage by integrating the areas over the levels\nsource\n# Ribasim.qh_interpolation — Method.\nFrom a table with columns nodeid, flowrate (Q) and level (h), create a LinearInterpolation from level to flow rate for a given node_id.\nsource\n# Ribasim.reduction_factor — Method.\nFunction that goes smoothly from 0 to 1 in the interval [0,threshold], and is constant outside this interval.\nsource\n# Ribasim.run — Method.\nrun(config_file::AbstractString)::Model\nrun(config::Config)::Model\nRun a Model, given a path to a TOML configuration file, or a Config object. Running a model includes initialization, solving to the end with [solve!](@ref) and writing results with write_results.\nsource\n# Ribasim.save_allocation_flows! — Method.\nSave the allocation flows per basin and physical edge.\nsource\n# Ribasim.save_demands_and_allocations! — Method.\nSave the demands and allocated flows for UserDemand and Basin. Note: Basin supply (negative demand) is only saved for the first priority.\nsource\n# Ribasim.save_flow — Method.\nCompute the average flows over the last saveat interval and write them to SavedValues\nsource\n# Ribasim.save_subgrid_level — Method.\nInterpolate the levels and save them to SavedValues\nsource\n# Ribasim.scalar_interpolation_derivative — Method.\nDerivative of scalar interpolation.\nsource\n# Ribasim.seconds_since — Method.\nseconds_since(t::DateTime, t0::DateTime)::Float64\nConvert a DateTime to a float that is the number of seconds since the start of the simulation. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.set_current_value! — Method.\nFrom a timeseries table time, load the most recent applicable data into table. table must be a NamedTuple of vectors with all variables that must be loaded. The most recent applicable data is non-NaN data for a given ID that is on or before t.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q over the edge between the given nodes.\nsource\n# Ribasim.set_fractional_flow_in_allocation! — Method.\nUpdate the fractional flow fractions in an allocation problem.\nsource\n# Ribasim.set_initial_discrete_controlled_parameters! — Method.\nSet parameters of nodes that are controlled by DiscreteControl to the values corresponding to the initial state of the model.\nsource\n# Ribasim.set_is_pid_controlled! — Method.\nSet ispidcontrolled to true for those pumps and outlets that are PID controlled\nsource\n# Ribasim.set_objective_priority! — Method.\nSet the objective for the given priority. For an objective with absolute values this also involves adjusting constraints.\nsource\n# Ribasim.set_static_value! — Method.\nLoad data from a source table static into a destination table. Data is matched based on the node_id, which is sorted.\nsource\n# Ribasim.set_table_row! — Method.\nUpdate table at row index i, with the values of a given row. table must be a NamedTuple of vectors with all variables that must be loaded. The row must contain all the column names that are present in the table. If a value is missing, it is not set.\nsource\n# Ribasim.sorted_table! — Method.\nDepending on if a table can be sorted, either sort it or assert that it is sorted.\nTables loaded from the database into memory can be sorted. Tables loaded from Arrow files are memory mapped and can therefore not be sorted.\nsource\n# Ribasim.tsaves — Method.\nGet all saved times in seconds since start\nsource\n# Ribasim.update_allocation! — Method.\nSolve the allocation problem for all demands and assign allocated abstractions.\nsource\n# Ribasim.update_basin — Method.\nLoad updates from ‘Basin / time’ into the parameters\nsource\n# Ribasim.update_jac_prototype! — Method.\nMethod for nodes that do not contribute to the Jacobian\nsource\n# Ribasim.update_jac_prototype! — Method.\nThe controlled basin affects itself and the basins upstream and downstream of the controlled pump affect eachother if there is a basin upstream of the pump. The state for the integral term and the controlled basin affect eachother, and the same for the integral state and the basin upstream of the pump if it is indeed a basin.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the unique node downstream of these nodes are basins, then these directly depend on eachother and affect the Jacobian 2x Basins always depend on themselves.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the nodes down stream (or one node further if a fractional flow is in between) are basins, then the downstream basin depends on the upstream basin(s) and affect the Jacobian as many times as there are downstream basins Upstream basins always depend on themselves.\nsource\n# Ribasim.update_tabulated_rating_curve! — Method.\nLoad updates from ‘TabulatedRatingCurve / time’ into the parameters\nsource\n# Ribasim.valid_discrete_control — Method.\nCheck:\n\nwhether control states are defined for discrete controlled nodes;\nWhether the supplied truth states have the proper length;\nWhether look_ahead is only supplied for condition variables given by a time-series.\n\nsource\n# Ribasim.valid_edge_types — Method.\nCheck that only supported edge types are declared.\nsource\n# Ribasim.valid_edges — Method.\nTest for each node given its node type whether the nodes that\nare downstream (‘down-edge’) of this node are of an allowed type\nsource\n# Ribasim.valid_flow_rates — Method.\nTest whether static or discrete controlled flow rates are indeed non-negative.\nsource\n# Ribasim.valid_fractional_flow — Method.\nCheck that nodes that have fractional flow outneighbors do not have any other type of outneighbor, that the fractions leaving a node add up to ≈1 and that the fractions are non-negative.\nsource\n# Ribasim.valid_n_neighbors — Method.\nTest for each node given its node type whether it has an allowed number of flow/control inneighbors and outneighbors\nsource\n# Ribasim.valid_profiles — Method.\nCheck whether the profile data has no repeats in the levels and the areas start positive.\nsource\n# Ribasim.valid_sources — Method.\nThe source nodes must only have one allocation outneighbor and no allocation inneighbors.\nsource\n# Ribasim.valid_subgrid — Method.\nValidate the entries for a single subgrid element.\nsource\n# Ribasim.water_balance! — Method.\nThe right hand side function of the system of ODEs set up by Ribasim.\nsource\n# Ribasim.write_arrow — Method.\nWrite a result table to disk as an Arrow file\nsource\n# Ribasim.write_results — Method.\nwrite_results(model::Model)::Model\nWrite all results to the Arrow files as specified in the model configuration.\nsource\n# Ribasim.config.algorithm — Method.\nCreate an OrdinaryDiffEqAlgorithm from solver config\nsource\n# Ribasim.config.convert_dt — Method.\nConvert the dt from our Config to SciML stepsize control arguments\nsource\n# Ribasim.config.convert_saveat — Method.\nConvert the saveat Float64 from our Config to SciML’s saveat\nsource\n# Ribasim.config.input_path — Method.\nConstruct a path relative to both the TOML directory and the optional input_dir\nsource\n# Ribasim.config.results_path — Method.\nConstruct a path relative to both the TOML directory and the optional results_dir\nsource\n# Ribasim.config.snake_case — Method.\nConvert a string from CamelCase to snake_case.\nsource",
"crumbs": [
"Julia core",
"API Reference"
@@ -442,7 +449,7 @@
"href": "build/index.html#index",
"title": "1 API Reference",
"section": "1.6 Index",
- "text": "1.6 Index\n\nRibasim.Ribasim\nRibasim.config\nRibasim.config.algorithms\nRibasim.Allocation\nRibasim.AllocationModel\nRibasim.AllocationModel\nRibasim.Basin\nRibasim.DiscreteControl\nRibasim.EdgeMetadata\nRibasim.FlatVector\nRibasim.FlowBoundary\nRibasim.FractionalFlow\nRibasim.InNeighbors\nRibasim.LevelBoundary\nRibasim.LevelDemand\nRibasim.LinearResistance\nRibasim.ManningResistance\nRibasim.Model\nRibasim.NodeMetadata\nRibasim.OutNeighbors\nRibasim.Outlet\nRibasim.PidControl\nRibasim.Pump\nRibasim.Subgrid\nRibasim.TabulatedRatingCurve\nRibasim.Terminal\nRibasim.UserDemand\nRibasim.config.Config\nBasicModelInterface.finalize\nBasicModelInterface.initialize\nCommonSolve.solve!\nRibasim.add_basin_term!\nRibasim.add_constraints_absolute_value!\nRibasim.add_constraints_absolute_value_basin!\nRibasim.add_constraints_absolute_value_user_demand!\nRibasim.add_constraints_basin_flow!\nRibasim.add_constraints_capacity!\nRibasim.add_constraints_flow_conservation!\nRibasim.add_constraints_fractional_flow!\nRibasim.add_constraints_source!\nRibasim.add_constraints_user_demand_returnflow!\nRibasim.add_flow!\nRibasim.add_flow!\nRibasim.add_objective_term!\nRibasim.add_subnetwork_connections!\nRibasim.add_user_demand_term!\nRibasim.add_variables_absolute_value!\nRibasim.add_variables_basin!\nRibasim.add_variables_flow!\nRibasim.adjust_basin_capacities!\nRibasim.adjust_edge_capacities!\nRibasim.adjust_source_capacities!\nRibasim.all_neighbor_labels_type\nRibasim.allocate!\nRibasim.allocation_graph\nRibasim.allocation_graph_used_nodes!\nRibasim.allocation_path_exists_in_graph\nRibasim.allocation_problem\nRibasim.allocation_table\nRibasim.assign_allocations!\nRibasim.avoid_using_own_returnflow!\nRibasim.basin_bottom\nRibasim.basin_bottoms\nRibasim.basin_table\nRibasim.config.algorithm\nRibasim.config.convert_dt\nRibasim.config.convert_saveat\nRibasim.config.input_path\nRibasim.config.results_path\nRibasim.config.snake_case\nRibasim.create_callbacks\nRibasim.create_graph\nRibasim.create_storage_tables\nRibasim.datetime_since\nRibasim.datetimes\nRibasim.discrete_control_affect!\nRibasim.discrete_control_affect_downcrossing!\nRibasim.discrete_control_affect_upcrossing!\nRibasim.discrete_control_condition\nRibasim.discrete_control_table\nRibasim.expand_logic_mapping\nRibasim.find_allocation_graph_edges!\nRibasim.find_subnetwork_connections!\nRibasim.findlastgroup\nRibasim.findsorted\nRibasim.flow_table\nRibasim.formulate_basins!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.get_area_and_level\nRibasim.get_basin_capacity\nRibasim.get_basin_data\nRibasim.get_basin_demand\nRibasim.get_chunk_sizes\nRibasim.get_compressor\nRibasim.get_flow\nRibasim.get_flow\nRibasim.get_fractional_flow_connected_basins\nRibasim.get_jac_prototype\nRibasim.get_level\nRibasim.get_scalar_interpolation\nRibasim.get_storage_from_level\nRibasim.get_storages_and_levels\nRibasim.get_storages_from_levels\nRibasim.get_tstops\nRibasim.get_value\nRibasim.id_index\nRibasim.indicate_allocation_flow!\nRibasim.inflow_id\nRibasim.inflow_ids\nRibasim.inflow_ids_allocation\nRibasim.inneighbor_labels_type\nRibasim.inoutflow_ids\nRibasim.integrate_flows!\nRibasim.is_allocation_source\nRibasim.is_current_module\nRibasim.is_flow_constraining\nRibasim.is_flow_direction_constraining\nRibasim.load_data\nRibasim.load_structvector\nRibasim.low_storage_factor\nRibasim.main\nRibasim.metadata_from_edge\nRibasim.nodefields\nRibasim.nodetype\nRibasim.outflow_id\nRibasim.outflow_ids\nRibasim.outflow_ids_allocation\nRibasim.outneighbor_labels_type\nRibasim.parse_static_and_time\nRibasim.pkgversion\nRibasim.process_allocation_graph_edges!\nRibasim.profile_storage\nRibasim.qh_interpolation\nRibasim.reduction_factor\nRibasim.run\nRibasim.save_allocation_flows!\nRibasim.save_demands_and_allocations!\nRibasim.save_flow\nRibasim.save_subgrid_level\nRibasim.scalar_interpolation_derivative\nRibasim.seconds_since\nRibasim.set_current_value!\nRibasim.set_flow!\nRibasim.set_flow!\nRibasim.set_fractional_flow_in_allocation!\nRibasim.set_initial_discrete_controlled_parameters!\nRibasim.set_is_pid_controlled!\nRibasim.set_objective_priority!\nRibasim.set_static_value!\nRibasim.set_table_row!\nRibasim.sorted_table!\nRibasim.tsaves\nRibasim.update_allocation!\nRibasim.update_basin\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_tabulated_rating_curve!\nRibasim.valid_discrete_control\nRibasim.valid_edge_types\nRibasim.valid_edges\nRibasim.valid_flow_rates\nRibasim.valid_fractional_flow\nRibasim.valid_n_neighbors\nRibasim.valid_profiles\nRibasim.valid_sources\nRibasim.valid_subgrid\nRibasim.water_balance!\nRibasim.write_arrow\nRibasim.write_results\nRibasim.config.@addfields\nRibasim.config.@addnodetypes",
+ "text": "1.6 Index\n\nRibasim.Ribasim\nRibasim.config\nRibasim.config.algorithms\nRibasim.Allocation\nRibasim.AllocationModel\nRibasim.AllocationModel\nRibasim.Basin\nRibasim.DiscreteControl\nRibasim.EdgeMetadata\nRibasim.FlatVector\nRibasim.FlowBoundary\nRibasim.FractionalFlow\nRibasim.InNeighbors\nRibasim.LevelBoundary\nRibasim.LevelDemand\nRibasim.LinearResistance\nRibasim.ManningResistance\nRibasim.Model\nRibasim.NodeMetadata\nRibasim.OutNeighbors\nRibasim.Outlet\nRibasim.PidControl\nRibasim.Pump\nRibasim.Subgrid\nRibasim.TabulatedRatingCurve\nRibasim.Terminal\nRibasim.UserDemand\nRibasim.config.Config\nBasicModelInterface.finalize\nBasicModelInterface.initialize\nCommonSolve.solve!\nRibasim.add_basin_term!\nRibasim.add_constraints_absolute_value!\nRibasim.add_constraints_absolute_value_flow_demand!\nRibasim.add_constraints_absolute_value_level_demand!\nRibasim.add_constraints_absolute_value_user_demand!\nRibasim.add_constraints_basin_flow!\nRibasim.add_constraints_buffer!\nRibasim.add_constraints_capacity!\nRibasim.add_constraints_conservation_basin!\nRibasim.add_constraints_conservation_flow_demand!\nRibasim.add_constraints_conservation_subnetwork!\nRibasim.add_constraints_flow_demand_outflow!\nRibasim.add_constraints_fractional_flow!\nRibasim.add_constraints_source!\nRibasim.add_constraints_user_demand_returnflow!\nRibasim.add_flow!\nRibasim.add_flow!\nRibasim.add_flow_demand_term!\nRibasim.add_objective_term!\nRibasim.add_subnetwork_connections!\nRibasim.add_user_demand_term!\nRibasim.add_variables_absolute_value!\nRibasim.add_variables_basin!\nRibasim.add_variables_flow!\nRibasim.add_variables_flow_buffer!\nRibasim.adjust_capacities_basin!\nRibasim.adjust_capacities_buffers!\nRibasim.adjust_capacities_edge!\nRibasim.adjust_capacities_flow_demand_outflow!\nRibasim.adjust_capacities_source!\nRibasim.adjust_demands_flow!\nRibasim.all_neighbor_labels_type\nRibasim.allocate!\nRibasim.allocation_graph\nRibasim.allocation_graph_used_nodes!\nRibasim.allocation_path_exists_in_graph\nRibasim.allocation_problem\nRibasim.allocation_table\nRibasim.assign_allocations!\nRibasim.avoid_using_own_returnflow!\nRibasim.basin_bottom\nRibasim.basin_bottoms\nRibasim.basin_table\nRibasim.config.algorithm\nRibasim.config.convert_dt\nRibasim.config.convert_saveat\nRibasim.config.input_path\nRibasim.config.results_path\nRibasim.config.snake_case\nRibasim.create_callbacks\nRibasim.create_graph\nRibasim.create_storage_tables\nRibasim.datetime_since\nRibasim.datetimes\nRibasim.discrete_control_affect!\nRibasim.discrete_control_affect_downcrossing!\nRibasim.discrete_control_affect_upcrossing!\nRibasim.discrete_control_condition\nRibasim.discrete_control_table\nRibasim.expand_logic_mapping\nRibasim.find_allocation_graph_edges!\nRibasim.find_subnetwork_connections!\nRibasim.findlastgroup\nRibasim.findsorted\nRibasim.flow_table\nRibasim.formulate_basins!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.get_area_and_level\nRibasim.get_basin_capacity\nRibasim.get_basin_data\nRibasim.get_basin_demand\nRibasim.get_chunk_sizes\nRibasim.get_compressor\nRibasim.get_flow\nRibasim.get_flow\nRibasim.get_fractional_flow_connected_basins\nRibasim.get_jac_prototype\nRibasim.get_level\nRibasim.get_scalar_interpolation\nRibasim.get_storage_from_level\nRibasim.get_storages_and_levels\nRibasim.get_storages_from_levels\nRibasim.get_tstops\nRibasim.get_value\nRibasim.id_index\nRibasim.indicate_allocation_flow!\nRibasim.inflow_id\nRibasim.inflow_ids\nRibasim.inflow_ids_allocation\nRibasim.inneighbor_labels_type\nRibasim.inoutflow_ids\nRibasim.integrate_flows!\nRibasim.is_allocation_source\nRibasim.is_current_module\nRibasim.is_flow_constraining\nRibasim.is_flow_direction_constraining\nRibasim.load_data\nRibasim.load_structvector\nRibasim.low_storage_factor\nRibasim.main\nRibasim.metadata_from_edge\nRibasim.nodefields\nRibasim.nodetype\nRibasim.outflow_id\nRibasim.outflow_ids\nRibasim.outflow_ids_allocation\nRibasim.outneighbor_labels_type\nRibasim.parse_static_and_time\nRibasim.pkgversion\nRibasim.process_allocation_graph_edges!\nRibasim.profile_storage\nRibasim.qh_interpolation\nRibasim.reduction_factor\nRibasim.run\nRibasim.save_allocation_flows!\nRibasim.save_demands_and_allocations!\nRibasim.save_flow\nRibasim.save_subgrid_level\nRibasim.scalar_interpolation_derivative\nRibasim.seconds_since\nRibasim.set_current_value!\nRibasim.set_flow!\nRibasim.set_flow!\nRibasim.set_fractional_flow_in_allocation!\nRibasim.set_initial_discrete_controlled_parameters!\nRibasim.set_is_pid_controlled!\nRibasim.set_objective_priority!\nRibasim.set_static_value!\nRibasim.set_table_row!\nRibasim.sorted_table!\nRibasim.tsaves\nRibasim.update_allocation!\nRibasim.update_basin\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_tabulated_rating_curve!\nRibasim.valid_discrete_control\nRibasim.valid_edge_types\nRibasim.valid_edges\nRibasim.valid_flow_rates\nRibasim.valid_fractional_flow\nRibasim.valid_n_neighbors\nRibasim.valid_profiles\nRibasim.valid_sources\nRibasim.valid_subgrid\nRibasim.water_balance!\nRibasim.write_arrow\nRibasim.write_results\nRibasim.config.@addfields\nRibasim.config.@addnodetypes",
"crumbs": [
"Julia core",
"API Reference"
@@ -475,7 +482,7 @@
"href": "core/equations.html#sec-reduction_factor",
"title": "Equations",
"section": "2.1 The reduction factor",
- "text": "2.1 The reduction factor\nAt several points in the equations below a reduction factor is used. This is a term that makes certain transitions more smooth, for instance when a pump stops providing water when its source basin dries up. The reduction factor is given by\n\\[\\begin{align}\n \\phi(x; p) =\n \\begin{cases}\n 0 &\\text{if}\\quad x < 0 \\\\\n -2 \\left(\\frac{x}{p}\\right)^3 + 3\\left(\\frac{x}{p}\\right)^2 &\\text{if}\\quad 0 \\le x \\le p \\\\\n 1 &\\text{if}\\quad x > p\n \\end{cases}\n\\end{align}\\]\nHere \\(p > 0\\) is the threshold value which determines the interval \\([0,p]\\) of the smooth transition between \\(0\\) and \\(1\\), see the plot below.\n\n\nCode\nimport numpy as np\nimport matplotlib.pyplot as plt\n\ndef f(x, p = 3):\n x_scaled = x / p\n phi = (-2 * x_scaled + 3) * x_scaled**2\n phi = np.where(x < 0, 0, phi)\n phi = np.where(x > p, 1, phi)\n\n return phi\n\nfontsize = 15\np = 3\nN = 100\nx_min = -1\nx_max = 4\nx = np.linspace(x_min,x_max,N)\nphi = f(x,p)\n\nfig,ax = plt.subplots(dpi=80)\nax.plot(x,phi)\n\ny_lim = ax.get_ylim()\n\nax.set_xticks([0,p], [0,\"$p$\"], fontsize=fontsize)\nax.set_yticks([0,1], [0,1], fontsize=fontsize)\nax.hlines([0,1],x_min,x_max, color = \"k\", ls = \":\", zorder=-1)\nax.vlines([0,p], *y_lim, color = \"k\", ls = \":\")\nax.set_xlim(x_min,x_max)\nax.set_xlabel(\"$x$\", fontsize=fontsize)\nax.set_ylabel(\"$\\phi(x;p)$\", fontsize=fontsize)\nax.set_ylim(y_lim)\n\nfig.tight_layout()\nplt.show()\n\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n/tmp/ipykernel_2757/665069857.py:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'",
+ "text": "2.1 The reduction factor\nAt several points in the equations below a reduction factor is used. This is a term that makes certain transitions more smooth, for instance when a pump stops providing water when its source basin dries up. The reduction factor is given by\n\\[\\begin{align}\n \\phi(x; p) =\n \\begin{cases}\n 0 &\\text{if}\\quad x < 0 \\\\\n -2 \\left(\\frac{x}{p}\\right)^3 + 3\\left(\\frac{x}{p}\\right)^2 &\\text{if}\\quad 0 \\le x \\le p \\\\\n 1 &\\text{if}\\quad x > p\n \\end{cases}\n\\end{align}\\]\nHere \\(p > 0\\) is the threshold value which determines the interval \\([0,p]\\) of the smooth transition between \\(0\\) and \\(1\\), see the plot below.\n\n\nCode\nimport numpy as np\nimport matplotlib.pyplot as plt\n\ndef f(x, p = 3):\n x_scaled = x / p\n phi = (-2 * x_scaled + 3) * x_scaled**2\n phi = np.where(x < 0, 0, phi)\n phi = np.where(x > p, 1, phi)\n\n return phi\n\nfontsize = 15\np = 3\nN = 100\nx_min = -1\nx_max = 4\nx = np.linspace(x_min,x_max,N)\nphi = f(x,p)\n\nfig,ax = plt.subplots(dpi=80)\nax.plot(x,phi)\n\ny_lim = ax.get_ylim()\n\nax.set_xticks([0,p], [0,\"$p$\"], fontsize=fontsize)\nax.set_yticks([0,1], [0,1], fontsize=fontsize)\nax.hlines([0,1],x_min,x_max, color = \"k\", ls = \":\", zorder=-1)\nax.vlines([0,p], *y_lim, color = \"k\", ls = \":\")\nax.set_xlim(x_min,x_max)\nax.set_xlabel(\"$x$\", fontsize=fontsize)\nax.set_ylabel(\"$\\phi(x;p)$\", fontsize=fontsize)\nax.set_ylim(y_lim)\n\nfig.tight_layout()\nplt.show()\n\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n/tmp/ipykernel_2915/665069857.py:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'",
"crumbs": [
"Julia core",
"Equations"
@@ -695,7 +702,7 @@
"href": "core/usage.html#userdemand-time",
"title": "Usage",
"section": "10.1 UserDemand / time",
- "text": "10.1 UserDemand / time\nThis table is the transient form of the UserDemand table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the demand can be updated over time. In between the given times the demand is interpolated linearly, and outside the demand is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\npriority\nInt32\n-\npositive, sorted per node id\n\n\ntime\nDateTime\n-\nsorted per priority per node id\n\n\ndemand\nFloat64\n\\(m^3 s^{-1}\\)\n-\n\n\nreturn_factor\nFloat64\n-\nbetween [0 - 1]\n\n\nmin_level\nFloat64\n\\(m\\)\n-",
+ "text": "10.1 UserDemand / time\nThis table is the transient form of the UserDemand table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the demand can be updated over time. In between the given times the demand is interpolated linearly, and outside the demand is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\npriority\nInt32\n-\npositive, sorted per node id\n\n\ntime\nDateTime\n-\nsorted per priority per node id\n\n\ndemand\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative\n\n\nreturn_factor\nFloat64\n-\nbetween [0 - 1]\n\n\nmin_level\nFloat64\n\\(m\\)\n-",
"crumbs": [
"Julia core",
"Usage"
@@ -712,12 +719,23 @@
"Usage"
]
},
+ {
+ "objectID": "core/usage.html#flowdemand-time",
+ "href": "core/usage.html#flowdemand-time",
+ "title": "Usage",
+ "section": "12.1 FlowDemand / time",
+ "text": "12.1 FlowDemand / time\nThis table is the transient form of the FlowDemand table, in which a time-dependent demand can be supplied. Similar to the static version, only a single priority per FlowDemand node can be provided.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node id\n\n\npriority\nInt32\n-\npositive\n\n\ndemand\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative",
+ "crumbs": [
+ "Julia core",
+ "Usage"
+ ]
+ },
{
"objectID": "core/usage.html#levelboundary-time",
"href": "core/usage.html#levelboundary-time",
"title": "Usage",
- "section": "12.1 LevelBoundary / time",
- "text": "12.1 LevelBoundary / time\nThis table is the transient form of the LevelBoundary table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the levels can be updated over time. In between the given times the level is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlevel\nFloat64\n\\(m\\)\n-",
+ "section": "13.1 LevelBoundary / time",
+ "text": "13.1 LevelBoundary / time\nThis table is the transient form of the LevelBoundary table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the levels can be updated over time. In between the given times the level is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlevel\nFloat64\n\\(m\\)\n-",
"crumbs": [
"Julia core",
"Usage"
@@ -727,8 +745,8 @@
"objectID": "core/usage.html#flowboundary-time",
"href": "core/usage.html#flowboundary-time",
"title": "Usage",
- "section": "13.1 FlowBoundary / time",
- "text": "13.1 FlowBoundary / time\nThis table is the transient form of the FlowBoundary table. The only differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the flow rates can be updated over time. In between the given times the flow rate is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative",
+ "section": "14.1 FlowBoundary / time",
+ "text": "14.1 FlowBoundary / time\nThis table is the transient form of the FlowBoundary table. The only differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the flow rates can be updated over time. In between the given times the flow rate is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative",
"crumbs": [
"Julia core",
"Usage"
@@ -738,8 +756,8 @@
"objectID": "core/usage.html#discretecontrol-condition",
"href": "core/usage.html#discretecontrol-condition",
"title": "Usage",
- "section": "17.1 DiscreteControl / condition",
- "text": "17.1 DiscreteControl / condition\nThe 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.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\nlisten_node_type\nString\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\nsorted per node_id\n\n\nvariable\nString\n-\nmust be “level” or “flow_rate”, sorted per listen_node_id\n\n\ngreater_than\nFloat64\nvarious\nsorted per variable\n\n\nlook_ahead\nFloat64\n\\(s\\)\nOnly on transient boundary conditions, non-negative (optional, default 0)",
+ "section": "18.1 DiscreteControl / condition",
+ "text": "18.1 DiscreteControl / condition\nThe 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.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\nlisten_node_type\nString\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\nsorted per node_id\n\n\nvariable\nString\n-\nmust be “level” or “flow_rate”, sorted per listen_node_id\n\n\ngreater_than\nFloat64\nvarious\nsorted per variable\n\n\nlook_ahead\nFloat64\n\\(s\\)\nOnly on transient boundary conditions, non-negative (optional, default 0)",
"crumbs": [
"Julia core",
"Usage"
@@ -749,8 +767,8 @@
"objectID": "core/usage.html#discretecontrol-logic",
"href": "core/usage.html#discretecontrol-logic",
"title": "Usage",
- "section": "17.2 DiscreteControl / logic",
- "text": "17.2 DiscreteControl / logic\nThe logic schema defines which control states are triggered based on the truth of the conditions a DiscreteControl node listens to. DiscreteControl is applied in the Julia core as follows:\n\nDuring the simulation it is checked whether the truth of any of the conditions changes.\nWhen a condition changes, the corresponding DiscreteControl node ID is retrieved (node_id in the condition schema above).\nThe truth value of all the conditions this DiscreteControl node listens to are retrieved, in the sorted order as specified in the condition schema. This is then converted into a string of “T” for true and “F” for false. This string we call the truth state.*\nThe table below determines for the given DiscreteControl node ID and truth state what the corresponding control state is.\nFor all the nodes this DiscreteControl node affects (as given by the “control” edges in Edges / static), their parameters are set to those parameters in NodeType / static corresponding to the determined control state.\n\n*. There is also a second truth state created in which for the last condition that changed it is specified whether it was an upcrossing (“U”) or downcrossing (“D”) of the threshold (greater than) value. If a control state is specified for a truth state that is crossing-specific, this takes precedence over the control state for the truth state that contains only “T” and “F”.\n\n\n\n\n\n\nNote\n\n\n\nWhen creating truth states, it is important to not use the order of the condition table as you provide it, but the order as it is written to the file. Users can provide tables in any order, but when writing the model it gets sorted in the required order as specified in the schema.\n\n\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ncontrol_state\nString\n-\n-\n\n\ntruth_state\nString\n-\nConsists of the characters “T” (true), “F” (false), “U” (upcrossing), “D” (downcrossing) and “*” (any), sorted per node_id",
+ "section": "18.2 DiscreteControl / logic",
+ "text": "18.2 DiscreteControl / logic\nThe logic schema defines which control states are triggered based on the truth of the conditions a DiscreteControl node listens to. DiscreteControl is applied in the Julia core as follows:\n\nDuring the simulation it is checked whether the truth of any of the conditions changes.\nWhen a condition changes, the corresponding DiscreteControl node ID is retrieved (node_id in the condition schema above).\nThe truth value of all the conditions this DiscreteControl node listens to are retrieved, in the sorted order as specified in the condition schema. This is then converted into a string of “T” for true and “F” for false. This string we call the truth state.*\nThe table below determines for the given DiscreteControl node ID and truth state what the corresponding control state is.\nFor all the nodes this DiscreteControl node affects (as given by the “control” edges in Edges / static), their parameters are set to those parameters in NodeType / static corresponding to the determined control state.\n\n*. There is also a second truth state created in which for the last condition that changed it is specified whether it was an upcrossing (“U”) or downcrossing (“D”) of the threshold (greater than) value. If a control state is specified for a truth state that is crossing-specific, this takes precedence over the control state for the truth state that contains only “T” and “F”.\n\n\n\n\n\n\nNote\n\n\n\nWhen creating truth states, it is important to not use the order of the condition table as you provide it, but the order as it is written to the file. Users can provide tables in any order, but when writing the model it gets sorted in the required order as specified in the schema.\n\n\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ncontrol_state\nString\n-\n-\n\n\ntruth_state\nString\n-\nConsists of the characters “T” (true), “F” (false), “U” (upcrossing), “D” (downcrossing) and “*” (any), sorted per node_id",
"crumbs": [
"Julia core",
"Usage"
@@ -760,8 +778,8 @@
"objectID": "core/usage.html#pidcontrol-time",
"href": "core/usage.html#pidcontrol-time",
"title": "Usage",
- "section": "18.1 PidControl / time",
- "text": "18.1 PidControl / time\nThis table is the transient form of the PidControl table. The differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the target level and PID coefficients can be updated over time. In between the given times the these values interpolated linearly, and outside these values area constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlisten_node_type\nInt32\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\n-\n\n\ntarget\nFloat64\n\\(m\\)\n-\n\n\nproportional\nFloat64\n\\(s^{-1}\\)\n-\n\n\nintegral\nFloat64\n\\(s^{-2}\\)\n-\n\n\nderivative\nFloat64\n-\n-",
+ "section": "19.1 PidControl / time",
+ "text": "19.1 PidControl / time\nThis table is the transient form of the PidControl table. The differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the target level and PID coefficients can be updated over time. In between the given times the these values interpolated linearly, and outside these values area constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlisten_node_type\nInt32\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\n-\n\n\ntarget\nFloat64\n\\(m\\)\n-\n\n\nproportional\nFloat64\n\\(s^{-1}\\)\n-\n\n\nintegral\nFloat64\n\\(s^{-2}\\)\n-\n\n\nderivative\nFloat64\n-\n-",
"crumbs": [
"Julia core",
"Usage"
@@ -771,8 +789,8 @@
"objectID": "core/usage.html#basin---basin.arrow",
"href": "core/usage.html#basin---basin.arrow",
"title": "Usage",
- "section": "19.1 Basin - basin.arrow",
- "text": "19.1 Basin - basin.arrow\nThe basin table contains results of the storage and level of each basin at every solver timestep. The initial condition is also written to the file.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nnode_id\nInt32\n-\n\n\nstorage\nFloat64\n\\(m^3\\)\n\n\nlevel\nFloat64\n\\(m\\)\n\n\n\nThe table is sorted by time, and per time it is sorted by node_id.",
+ "section": "20.1 Basin - basin.arrow",
+ "text": "20.1 Basin - basin.arrow\nThe basin table contains results of the storage and level of each basin at every solver timestep. The initial condition is also written to the file.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nnode_id\nInt32\n-\n\n\nstorage\nFloat64\n\\(m^3\\)\n\n\nlevel\nFloat64\n\\(m\\)\n\n\n\nThe table is sorted by time, and per time it is sorted by node_id.",
"crumbs": [
"Julia core",
"Usage"
@@ -782,8 +800,8 @@
"objectID": "core/usage.html#flow---flow.arrow",
"href": "core/usage.html#flow---flow.arrow",
"title": "Usage",
- "section": "19.2 Flow - flow.arrow",
- "text": "19.2 Flow - flow.arrow\nThe flow table contains calculated mean flows for every flow edge in the model. In the time column the start of the period is indicated.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nedge_id\nUnion{Int32, Missing}\n-\n\n\nfrom_node_type\nString\n-\n\n\nfrom_node_id\nInt32\n-\n\n\nto_node_type\nString\n-\n\n\nto_node_id\nInt32\n-\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\n\n\n\nThe table is sorted by time, and per time the same edge_id order is used, though not sorted. The edge_id value is the same as the fid written to the Edge table, and can be used to directly look up the Edge geometry. Flows that are added to the model at a node, have a missing edge_id, and identical from_node_id and to_node_id. Flows out of the model always have a negative sign, and additions a positive sign.",
+ "section": "20.2 Flow - flow.arrow",
+ "text": "20.2 Flow - flow.arrow\nThe flow table contains calculated mean flows for every flow edge in the model. In the time column the start of the period is indicated.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nedge_id\nUnion{Int32, Missing}\n-\n\n\nfrom_node_type\nString\n-\n\n\nfrom_node_id\nInt32\n-\n\n\nto_node_type\nString\n-\n\n\nto_node_id\nInt32\n-\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\n\n\n\nThe table is sorted by time, and per time the same edge_id order is used, though not sorted. The edge_id value is the same as the fid written to the Edge table, and can be used to directly look up the Edge geometry. Flows that are added to the model at a node, have a missing edge_id, and identical from_node_id and to_node_id. Flows out of the model always have a negative sign, and additions a positive sign.",
"crumbs": [
"Julia core",
"Usage"
@@ -793,8 +811,8 @@
"objectID": "core/usage.html#discretecontrol---control.arrow",
"href": "core/usage.html#discretecontrol---control.arrow",
"title": "Usage",
- "section": "19.3 DiscreteControl - control.arrow",
- "text": "19.3 DiscreteControl - control.arrow\nThe control table contains a record of each change of control state: when it happened, which control node was involved, to which control state it changed and based on which truth state.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\ncontrol_node_id\nInt32\n\n\ntruth_state\nString\n\n\ncontrol_state\nString",
+ "section": "20.3 DiscreteControl - control.arrow",
+ "text": "20.3 DiscreteControl - control.arrow\nThe control table contains a record of each change of control state: when it happened, which control node was involved, to which control state it changed and based on which truth state.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\ncontrol_node_id\nInt32\n\n\ntruth_state\nString\n\n\ncontrol_state\nString",
"crumbs": [
"Julia core",
"Usage"
@@ -804,8 +822,8 @@
"objectID": "core/usage.html#allocation---allocation.arrow",
"href": "core/usage.html#allocation---allocation.arrow",
"title": "Usage",
- "section": "19.4 Allocation - allocation.arrow",
- "text": "19.4 Allocation - allocation.arrow\nThe allocation table contains a record of allocation results: when it happened, for which node, in which allocation network, and what the demand, allocated flow and realized flow were.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nsubnetwork_id\nInt32\n\n\nnode_type\nString\n\n\nnode_id\nInt32\n\n\npriority\nInt32\n\n\ndemand\nFloat64\n\n\nallocated\nFloat64\n\n\nrealized\nFloat64\n\n\n\nFor Basins the values demand, allocated and realized are positive if the Basin level is below the minimum level given by a LevelDemand node. The values are negative if the Basin supplies due to a surplus of water.\n\n\n\n\n\n\nNote\n\n\n\nCurrently the stored demand and abstraction rate are those at the allocation timepoint (and the abstraction rate is based on the previous allocation optimization). In the future these will be an average over the previous allocation timestep.",
+ "section": "20.4 Allocation - allocation.arrow",
+ "text": "20.4 Allocation - allocation.arrow\nThe allocation table contains a record of allocation results: when it happened, for which node, in which allocation network, and what the demand, allocated flow and realized flow were.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nsubnetwork_id\nInt32\n\n\nnode_type\nString\n\n\nnode_id\nInt32\n\n\npriority\nInt32\n\n\ndemand\nFloat64\n\n\nallocated\nFloat64\n\n\nrealized\nFloat64\n\n\n\nFor Basins the values demand, allocated and realized are positive if the Basin level is below the minimum level given by a LevelDemand node. The values are negative if the Basin supplies due to a surplus of water.\n\n\n\n\n\n\nNote\n\n\n\nCurrently the stored demand and abstraction rate are those at the allocation timepoint (and the abstraction rate is based on the previous allocation optimization). In the future these will be an average over the previous allocation timestep.",
"crumbs": [
"Julia core",
"Usage"
@@ -815,8 +833,8 @@
"objectID": "core/usage.html#allocation-flow---allocation_flow.arrow",
"href": "core/usage.html#allocation-flow---allocation_flow.arrow",
"title": "Usage",
- "section": "19.5 Allocation flow - allocation_flow.arrow",
- "text": "19.5 Allocation flow - allocation_flow.arrow\nThe allocation flow table contains results of the optimized allocation flow on every edge in the model that is part of a subnetwork, for each time an optimization problem is solved (see also here). If in the model a main network and subnetwork(s) are specified, there are 2 different types of optimization for the subnetwork: collecting its total demand per priority (for allocating flow from the main network to the subnetwork), and allocating flow within the subnetwork. The column collect_demands provides the distinction between these two optimization types.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nedge_id\nInt32\n\n\nfrom_node_type\nString\n\n\nfrom_node_id\nInt32\n\n\nto_node_type\nString\n\n\nto_node_id\nInt32\n\n\nsubnetwork_id\nInt32\n\n\npriority\nInt32\n\n\nflow_rate\nFloat64\n\n\ncollect_demands\nBool",
+ "section": "20.5 Allocation flow - allocation_flow.arrow",
+ "text": "20.5 Allocation flow - allocation_flow.arrow\nThe allocation flow table contains results of the optimized allocation flow on every edge in the model that is part of a subnetwork, for each time an optimization problem is solved (see also here). If in the model a main network and subnetwork(s) are specified, there are 2 different types of optimization for the subnetwork: collecting its total demand per priority (for allocating flow from the main network to the subnetwork), and allocating flow within the subnetwork. The column collect_demands provides the distinction between these two optimization types.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nedge_id\nInt32\n\n\nfrom_node_type\nString\n\n\nfrom_node_id\nInt32\n\n\nto_node_type\nString\n\n\nto_node_id\nInt32\n\n\nsubnetwork_id\nInt32\n\n\npriority\nInt32\n\n\nflow_rate\nFloat64\n\n\ncollect_demands\nBool",
"crumbs": [
"Julia core",
"Usage"
@@ -882,7 +900,7 @@
"href": "core/allocation.html",
"title": "Allocation",
"section": "",
- "text": "Allocation is the process of assigning an allocated abstraction flow rate to demand nodes in the physical layer of the model based on information about sources, the different demand nodes over various priorities, constraints introduced by nodes, local water availability and graph topology. The allocation procedure implemented in Ribasim is heavily inspired by the maximum flow problem.\nThe allocation problem is solved per subnetwork of the Ribasim model. The subnetwork is used to formulate an optimization problem with the JuMP package, which is solved using the HiGHS solver. For more in-depth information see also the example of solving the maximum flow problem with JuMP.jl here.",
+ "text": "Allocation is the process of assigning an allocated flow rate to demand nodes in the physical layer of the model based on information about sources, the different demand nodes over various priorities, constraints introduced by nodes, local water availability and graph topology. The allocation procedure implemented in Ribasim is heavily inspired by the maximum flow problem.\nThe allocation problem is solved per subnetwork of the Ribasim model. The subnetwork is used to formulate an optimization problem with the JuMP package, which is solved using the HiGHS solver. For more in-depth information see also the example of solving the maximum flow problem with JuMP.jl here.",
"crumbs": [
"Julia core",
"Allocation"
@@ -893,7 +911,7 @@
"href": "core/allocation.html#schematisation-input",
"title": "Allocation",
"section": "3.1 Schematisation input",
- "text": "3.1 Schematisation input\n\n3.1.1 The subnetwork\nThe allocation problem is solved per subnetwork, which is given by a subset \\(S \\subset V\\) of node ids. Different subnetworks are disjoint from eachother.\n\n\n3.1.2 Source flows\nSources are indicated by a set of edges in the subnetwork \\[\nE_S^\\text{source} \\subset \\left(S \\times S\\right) \\cap E.\n\\] That is, if \\((i,j) \\in E_S^\\text{source}\\), then \\(Q_{ij}\\) (see the formal model description) is treated as a source flow in the allocation problem. These edges are either coming from a boundary/source node (e.g. a level or flow boundary) or connect the main network to a subnetwork.\n\n\n3.1.3 User demands\nThe subnetwork contains a subset of UserDemand nodes \\(U_S \\subset S\\), who all have time varying demands over various priorities \\(p\\): \\[\n d^p_i(t), \\quad i \\in U_S, p = 1,2,\\ldots, p_{\\max}.\n\\]\n\n\n\n\n\n\nNote\n\n\n\nOn this page we assume that the priorities are given by all integers from \\(1\\) to some \\(p_{\\max} \\in \\mathbb{N}\\). However, in the Ribasim input this is not a requirement; some of these in between priority values can be missing, only the ordering of the given priorities is taken into account.",
+ "text": "3.1 Schematisation input\n\n3.1.1 The subnetwork\nThe allocation problem is solved per subnetwork, which is given by a subset \\(S \\subset V\\) of node ids. Different subnetworks are disjoint from eachother.\n\n\n3.1.2 Source flows\nSources are indicated by a set of edges in the subnetwork \\[\nE_S^\\text{source} \\subset \\left(S \\times S\\right) \\cap E.\n\\] That is, if \\((i,j) \\in E_S^\\text{source}\\), then \\(Q_{ij}\\) (see the formal model description) is treated as a source flow in the allocation problem. These edges are either coming from a boundary/source node (e.g. a level or flow boundary) or connect the main network to a subnetwork.\n\n\n3.1.3 User demands\nThe subnetwork contains a subset of UserDemand nodes \\(U_S \\subset S\\), who all have static or time varying demands over various priorities \\(p\\): \\[\n d^p_i(t), \\quad i \\in U_S, p = 1,2,\\ldots, p_{\\max}.\n\\] However, in\n\n\n\n\n\n\nNote\n\n\n\nOn this page we assume that the priorities are given by all integers from \\(1\\) to some \\(p_{\\max} \\in \\mathbb{N}\\).the Ribasim input this is not a requirement; some of these in between priority values can be missing, only the ordering of the given priorities is taken into account.\n\n\n\n\n3.1.4 Flow demands\nThe subnetwork contains a subset of nodes \\(FD_S \\in S\\) which have a demand of a single priority \\(p_{\\text{fd}}\\). With this we define \\[\n d^p_i(t) =\n \\begin{cases}\n 0 \\text{ if } p \\ne p_{\\text{fd}} \\\\\n d^{p_{\\text{df}}} \\text{ if } p = p_{\\text{fd}}\n \\end{cases}\n\\] for all \\(i \\in FD_S\\). Here \\(d^{p_{\\text{df}}}\\) is given by the original flow demand minus the flows trough node \\(i\\) at all priorities \\(p < p_{\\text{fd}}\\).",
"crumbs": [
"Julia core",
"Allocation"
@@ -915,7 +933,7 @@
"href": "core/allocation.html#the-allocation-network",
"title": "Allocation",
"section": "3.3 The allocation network",
- "text": "3.3 The allocation network\nA new graph is created from the subnetwork, which we call an allocation network. The allocation network is almost a subgraph of the main (flow) model, apart from the fact that an allocation network can contain edges which are a combination of multiple edges in the main model.\n\n3.3.1 Nodes and edges\nThe allocation network consists of:\n\nNodes \\(V'_S \\subset V_S\\), where each Basin, source and demand in the subnetwork get a node in the allocation network. Also nodes that have FractionalFlow outneighbors get a node in the allocation network.\nEdges \\(E_S\\), which are either edges that also appear between nodes in the subnetwork or represent a sequence of those, creating a shortcut.\n\nFor notational convenience, we use the notation\n\\[\\begin{align}\n V^{\\text{out}}_S(i) = \\left\\{j \\in V'_S : (i,j) \\in E_S\\right\\} \\\\\n V^{\\text{in}}_S(j) = \\left\\{i \\in V'_S : (i,j) \\in E_S\\right\\}\n\\end{align}\\]\nfor the set of in-neighbors and out-neighbors of a node in the allocation network respectively.\n\n\n3.3.2 Capacities\nEach edge in the allocation network has an associated capacity. These capacities are collected in the sparse capacity matrix \\(C_S \\in \\overline{\\mathbb{R}}_{\\ge 0}^{n'\\times n'}\\) where \\(n' = \\#V'_S\\) is the number of nodes in the allocation network. The capacities can be infinite, if there is nothing in the model constraining the capacity of the edge.\nThe capacities are determined in different ways:\n\nIf an edge does not exist in the allocation network, i.e. \\((i,j) \\notin E_S\\) for certain \\(1 \\le i,j\\le n'\\), then \\((C_S)_{i,j} = 0\\);\nThe capacity of the edge \\(e \\in E_S\\) is given by the smallest max_flow_rate of the nodes along the equivalent edges in the subnetwork. If there are no nodes with a max_flow_rate, the edge capacity is infinite;\nIf the edge is a source, the capacity of the edge is given by the flow rate of that source.\n\nThere are also capacities \\(C^B_S \\in \\mathbb{R}^b\\) where \\(b = \\# B_S\\) is the number of basins, for the flow supplied by basins.",
+ "text": "3.3 The allocation network\nA new graph is created from the subnetwork, which we call an allocation network. The allocation network is almost a subgraph of the main (flow) model, apart from the fact that an allocation network can contain edges which are a combination of multiple edges in the main model.\n\n3.3.1 Nodes and edges\nThe allocation network consists of:\n\nNodes \\(V'_S \\subset V_S\\). Nodes that are represented in the allocation network are: nodes of type Basin, UserDemand and Terminal, nodes that have FractionalFlow downstream neighbors, nodes that have a flow demand and nodes that are connected to a source edge.\nEdges \\(E_S\\), which are either edges that also appear between nodes in the subnetwork or represent a sequence of those, creating a shortcut.\n\nFor notational convenience, we use the notation\n\\[\\begin{align}\n V^{\\text{out}}_S(i) = \\left\\{j \\in V'_S : (i,j) \\in E_S\\right\\} \\\\\n V^{\\text{in}}_S(j) = \\left\\{i \\in V'_S : (i,j) \\in E_S\\right\\}\n\\end{align}\\]\nfor the set of in-neighbors and out-neighbors of a node in the allocation network respectively.\n\n\n3.3.2 Capacities\nEach edge in the allocation network has an associated capacity. These capacities are collected in the sparse capacity matrix \\(C_S \\in \\overline{\\mathbb{R}}_{\\ge 0}^{n'\\times n'}\\) where \\(n' = \\#V'_S\\) is the number of nodes in the allocation network. The capacities can be infinite, if there is nothing in the model constraining the capacity of the edge.\nThe capacities are determined in different ways:\n\nIf an edge does not exist in the allocation network, i.e. \\((i,j) \\notin E_S\\) for certain \\(1 \\le i,j\\le n'\\), then \\((C_S)_{i,j} = 0\\);\nThe capacity of the edge \\(e \\in E_S\\) is given by the smallest max_flow_rate of the nodes along the equivalent edges in the subnetwork. If there are no nodes with a max_flow_rate, the edge capacity is infinite;\nIf the edge is a source, the capacity of the edge is given by the flow rate of that source;\nIf an edge comes from a node with a flow demand, it has infinite capacity at priorities other than this of this flow demand, and zero capacity otherwise.\n\nThere are also capacities for special edges:\n\n\\(C^B_S \\in \\mathbb{R}^b_{\\ge 0}\\) where \\(b = \\# B_S\\) is the number of basins, for the flow supplied by basins.\n\\(C^{FD}_S \\in \\mathbb{R}^c_{\\ge 0}\\) where \\(c = \\# FD_S\\) is the number of nodes with a flow demand, for the flow supplied by flow buffers at these nodes with a flow demand.",
"crumbs": [
"Julia core",
"Allocation"
@@ -926,7 +944,7 @@
"href": "core/allocation.html#the-optimization-variables",
"title": "Allocation",
"section": "4.1 The optimization variables",
- "text": "4.1 The optimization variables\nThere are several types of variable whose value has to be determined to solve the allocation problem:\n\nThe flows \\(F \\in \\mathbb{R}_{\\ge 0}^{n'\\times n'}\\) over the edges in the allocation network;\nThe flows \\(F^\\text{basin out}_{i}, F^\\text{basin in}_{i} \\geq 0\\) for all \\(i \\in B_S\\) supplied and consumed by the basins respectively.",
+ "text": "4.1 The optimization variables\nThere are several types of variable whose value has to be determined to solve the allocation problem:\n\nThe flows \\(F \\in \\mathbb{R}_{\\ge 0}^{n'\\times n'}\\) over the edges in the allocation network;\nThe flows \\(F^\\text{basin out}_{i}, F^\\text{basin in}_{i} \\geq 0\\) for all \\(i \\in B_S\\) supplied and consumed by the basins respectively;\nThe flows \\(F^\\text{buffer out}_{i}, F^\\text{buffer in}_{i} \\ge 0\\) for all \\(i \\in FD_S\\) supplied and consumed by the flow buffers of nodes with a flow demand respectively.",
"crumbs": [
"Julia core",
"Allocation"
@@ -937,7 +955,7 @@
"href": "core/allocation.html#the-optimization-objective",
"title": "Allocation",
"section": "4.2 The optimization objective",
- "text": "4.2 The optimization objective\nThe goal of allocation is to get the flow to nodes with demands as close as possible to these demands. To achieve this, a sum error of terms is minimized.\n\\[\n \\min E_{\\text{user demand}} + E_{\\text{basin}}\n\\]\nThe error between the flows and user demands is denoted by \\(E_{\\text{user demand}}\\), where \\[\n E_{\\text{user demand}} = \\sum_{(i,j)\\in E_S\\;:\\; i\\in U_S} \\left| F_{ij} - d_j^p(t)\\right|\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing main network allocation, the connections to subnetworks are also interpreted as UserDemand with demands determined by subnetwork demand collection.\n\n\nThis type of objective cares about the absolute amount of water allocated to a demand. It treats all deviations equally which means it doesn’t give larger punishment per flow unit if deviations increase.\nThe absolute value applied here is not supported in a linear programming context directly; this requires introduction of new variables and constraints. For more details see here.\nLikewise, the error of basin demands is the absolute difference between flows consumed by basins and basin demands. \\[\n E_{\\text{basin}} = \\sum_{i \\in B_S} \\left| F_i^\\text{basin in} - d_i^p(t)\\right|\n\\]",
+ "text": "4.2 The optimization objective\nThe goal of allocation is to get the flow to nodes with demands as close as possible to these demands. To achieve this, a sum error of terms is minimized.\n\\[\n \\min E_{\\text{user demand}} + E_{\\text{level demand}} + E_{\\text{flow demand}}\n\\]\nThe error between the flows and user demands is denoted by \\(E_{\\text{user demand}}\\), where \\[\n E_{\\text{user demand}} = \\sum_{(i,j)\\in E_S\\;:\\; i\\in U_S} \\left| F_{ij} - d_j^p(t)\\right|\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing main network allocation, the connections to subnetworks are also interpreted as UserDemand with demands determined by subnetwork demand collection.\n\n\nThis type of objective cares about the absolute amount of water allocated to a demand. It treats all deviations equally which means it doesn’t give larger punishment per flow unit if deviations increase.\nThe absolute value applied here is not supported in a linear programming context directly; this requires introduction of new variables and constraints. For more details see here.\nLikewise, the error of level demands from basins is the absolute difference between flows consumed by basins and basin demands. \\[\n E_{\\text{level demand}} = \\sum_{i \\in B_S} \\left| F_i^\\text{basin in} - d_i^p(t)\\right|\n\\]\nLastly, the error of the flow demands is given as below. \\[\n E_{\\text{flow demand}} = \\sum_{i \\in FD_S} \\left| F_i^\\text{buffer in} - d_i^p(t)\\right|\n\\]",
"crumbs": [
"Julia core",
"Allocation"
@@ -948,7 +966,7 @@
"href": "core/allocation.html#the-optimization-constraints",
"title": "Allocation",
"section": "4.3 The optimization constraints",
- "text": "4.3 The optimization constraints\n\nFlow conservation: For the basins in the allocation network we have that \\[\n F^\\text{basin in}_k + \\sum_{j=1}^{n'} F_{kj} = F^\\text{basin out}_k + \\sum_{i=1}^{n'} F_{ik}, \\quad \\forall k \\in B_S .\n\\tag{1}\\] Note that we do not require equality here; in the allocation we do not mind that excess flow is ‘forgotten’ if it cannot contribute to the allocation to the demands.\n\n\n\n\n\n\n\nNote\n\n\n\nIn Equation 1, the placement of the basin flows might seem counter-intuitive. Think of the basin storage as a separate node connected to the basin node.\n\n\n\nCapacity: the flows over the edges are positive and bounded by the edge capacity: \\[\n F_{ij} \\le \\left(C_S\\right)_{ij}, \\quad \\forall(i,j) \\in E_S.\n\\tag{2}\\] By the definition of \\(C_S\\) this also includes the source flows. The same holds for the basin outflows:\n\n\\[\n F^{\\text{basin out}}_{i} \\le F^{\\text{basin out}}_{\\max, i}, \\quad \\forall i \\in B_S.\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing subnetwork demand collection, these capacities are set to \\(\\infty\\) for edges which connect the main network to a subnetwork.\n\n\n\nUserDemand outflow: The outflow of the UserDemand is dictated by the inflow and the return factor: \\[\n F_{ik} = r_k \\cdot F_{kj} \\quad\n \\quad \\forall k \\in U_S, \\quad\n V^{\\text{in}}_S(k) = \\{i\\},\\;\n V^{\\text{out}}_S(k) = \\{j\\}.\n\\tag{3}\\] Here we use that each UserDemand node in the allocation network has a unique in-edge and out-edge.\nUser demand: UserDemand demand constraints are discussed in the next section.\nFractional flow: Let \\(L_S \\subset V_S\\) be the set of nodes in the max flow graph with fractional flow outneighbors, and \\(f_j\\) the flow fraction associated with fractional flow node \\(j \\in V_S\\). Then \\[\n F_{ij} \\le f_j \\sum_{k\\in V^\\text{in}_S(i)} F_{ki} \\qquad\n \\forall i \\in L_S, \\;\n j \\in V_S^\\text{out}(i).\n\\tag{4}\\]\nFlow sign: Furthermore there are the non-negativity constraints for the flows and allocations, see The optimization variables.",
+ "text": "4.3 The optimization constraints\n\nFlow conservation: For the basins in the allocation network we have that \\[\n F^\\text{basin in}_k + \\sum_{j \\in V^{\\text{out}}_S(k)} F_{kj} = F^\\text{basin out}_k + \\sum_{i \\in V^{\\text{in}}_S(k)} F_{ik}, \\quad \\forall k \\in B_S .\n\\tag{1}\\] We have the same constraint without the basin terms for nodes that have flow edges as inneighbors (except if this node also happens to be a basin). For nodes which have a flow demand we have \\[\nF_{kj} + F^\\text{buffer in}_k = F^\\text{flow in}_k + F_{ik}, \\quad \\forall k \\in FD_S, \\quad V^{\\text{in}}_S(k) = \\{i\\},\\;\n V^{\\text{out}}_S(k) = \\{j\\}.\n\\tag{2}\\]\n\n\n\n\n\n\n\nNote\n\n\n\nIn Equation 1 and Equation 2, the placement of the basin and buffer flows might seem counter-intuitive. Think of the storage or buffer as a separate node connected to the node with the demand.\n\n\n\nCapacity: the flows over the edges are bounded by the edge capacity: \\[\n F_{ij} \\le \\left(C_S\\right)_{ij}, \\quad \\forall(i,j) \\in E_S.\n\\tag{3}\\] By the definition of \\(C_S\\) this also includes the source flows. The same holds for the basin outflows:\n\n\\[\n F^{\\text{basin out}}_{i} \\le F^{\\text{basin out}}_{\\max, i}, \\quad \\forall i \\in B_S.\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing subnetwork demand collection, these capacities are set to \\(\\infty\\) for edges which connect the main network to a subnetwork.\n\n\nSimilar constraints hold for the flow out of basins and flow demand buffers: \\[\nF^\\text{basin out}_{i} \\le (C^B_S)_i, \\quad \\forall i \\in B_S,\n\\]\n\\[\nF^\\text{buffer out}_{i} \\le (C^FD_S)_i, \\quad \\forall i \\in FD_S.\n\\]\n\nUserDemand outflow: The outflow of the UserDemand is dictated by the inflow and the return factor: \\[\n F_{ik} = r_k \\cdot F_{kj} \\quad\n \\quad \\forall k \\in U_S, \\quad\n V^{\\text{in}}_S(k) = \\{i\\},\\;\n V^{\\text{out}}_S(k) = \\{j\\}.\n\\tag{4}\\] Here we use that each UserDemand node in the allocation network has a unique in-edge and out-edge.\nUser demand: UserDemand demand constraints are discussed in the next section.\nFractional flow: Let \\(L_S \\subset V_S\\) be the set of nodes in the max flow graph with fractional flow outneighbors, and \\(f_j\\) the flow fraction associated with fractional flow node \\(j \\in V_S\\). Then \\[\n F_{ij} \\le f_j \\sum_{k\\in V^\\text{in}_S(i)} F_{ki} \\qquad\n \\forall i \\in L_S, \\;\n j \\in V_S^\\text{out}(i).\n\\tag{5}\\]\nFlow sign: Furthermore there are the non-negativity constraints for the flows and allocations, see The optimization variables.",
"crumbs": [
"Julia core",
"Allocation"
@@ -970,7 +988,7 @@
"href": "core/allocation.html#example",
"title": "Allocation",
"section": "5.1 Example",
- "text": "5.1 Example\nThe following is an example of an optimization problem for the example shown here:\n\n\nCode\nusing Ribasim\nusing Ribasim: NodeID\nusing SQLite\nusing ComponentArrays: ComponentVector\n\ntoml_path = normpath(@__DIR__, \"../../generated_testmodels/allocation_example/ribasim.toml\")\np = Ribasim.Model(toml_path).integrator.p\nu = ComponentVector(; storage = zeros(length(p.basin.node_id)))\n\nallocation_model = p.allocation.allocation_models[1]\nt = 0.0\npriority_idx = 1\n\nRibasim.set_flow!(p.graph, NodeID(:FlowBoundary, 1), NodeID(:Basin, 2), 1.0)\n\nRibasim.adjust_source_capacities!(allocation_model, p, priority_idx)\nRibasim.adjust_edge_capacities!(allocation_model, p, priority_idx)\nRibasim.set_objective_priority!(allocation_model, p, u, t, priority_idx)\n\nprintln(p.allocation.allocation_models[1].problem)\n\n\nMin F_abs_user_demand[UserDemand #3] + F_abs_user_demand[UserDemand #13] + F_abs_user_demand[UserDemand #6] + F_abs_basin[Basin #2] + F_abs_basin[Basin #12] + F_abs_basin[Basin #5]\nSubject to\n flow_conservation[Basin #2] : -F[(Basin #5, Basin #2)] + F[(Basin #2, Basin #5)] - F[(FlowBoundary #1, Basin #2)] + F[(Basin #2, UserDemand #3)] + F_basin_in[Basin #2] - F_basin_out[Basin #2] = 0\n flow_conservation[Basin #12] : F[(Basin #12, UserDemand #13)] - F[(TabulatedRatingCurve #7, Basin #12)] + F_basin_in[Basin #12] - F_basin_out[Basin #12] = 0\n flow_conservation[Basin #5] : F[(Basin #5, UserDemand #6)] + F[(Basin #5, Basin #2)] - F[(Basin #2, Basin #5)] + F[(Basin #5, TabulatedRatingCurve #7)] + F_basin_in[Basin #5] - F_basin_out[Basin #5] = 0\n abs_positive_user_demand[UserDemand #3] : -F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ -1.5\n abs_positive_user_demand[UserDemand #13] : -F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_positive_user_demand[UserDemand #6] : -F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n abs_negative_user_demand[UserDemand #3] : F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ 1.5\n abs_negative_user_demand[UserDemand #13] : F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_negative_user_demand[UserDemand #6] : F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n abs_positive_basin[Basin #2] : -F_basin_in[Basin #2] + F_abs_basin[Basin #2] ≥ 0\n abs_positive_basin[Basin #12] : -F_basin_in[Basin #12] + F_abs_basin[Basin #12] ≥ 0\n abs_positive_basin[Basin #5] : -F_basin_in[Basin #5] + F_abs_basin[Basin #5] ≥ 0\n abs_negative_basin[Basin #2] : F_basin_in[Basin #2] + F_abs_basin[Basin #2] ≥ 0\n abs_negative_basin[Basin #12] : F_basin_in[Basin #12] + F_abs_basin[Basin #12] ≥ 0\n abs_negative_basin[Basin #5] : F_basin_in[Basin #5] + F_abs_basin[Basin #5] ≥ 0\n source[(FlowBoundary #1, Basin #2)] : F[(FlowBoundary #1, Basin #2)] ≤ 1\n return_flow[UserDemand #13] : F[(UserDemand #13, Terminal #10)] ≤ 0\n fractional_flow[(TabulatedRatingCurve #7, Basin #12)] : -0.4 F[(Basin #5, TabulatedRatingCurve #7)] + F[(TabulatedRatingCurve #7, Basin #12)] ≤ 0\n basin_outflow[Basin #2] : F_basin_out[Basin #2] ≤ 0\n basin_outflow[Basin #12] : F_basin_out[Basin #12] ≤ 0\n basin_outflow[Basin #5] : F_basin_out[Basin #5] ≤ 0\n F[(TabulatedRatingCurve #7, Terminal #10)] ≥ 0\n F[(Basin #5, UserDemand #6)] ≥ 0\n F[(Basin #5, Basin #2)] ≥ 0\n F[(Basin #12, UserDemand #13)] ≥ 0\n F[(Basin #2, Basin #5)] ≥ 0\n F[(FlowBoundary #1, Basin #2)] ≥ 0\n F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0\n F[(Basin #2, UserDemand #3)] ≥ 0\n F[(UserDemand #13, Terminal #10)] ≥ 0\n F[(TabulatedRatingCurve #7, Basin #12)] ≥ 0\n F_basin_in[Basin #2] ≥ 0\n F_basin_in[Basin #12] ≥ 0\n F_basin_in[Basin #5] ≥ 0\n F_basin_out[Basin #2] ≥ 0\n F_basin_out[Basin #12] ≥ 0\n F_basin_out[Basin #5] ≥ 0",
+ "text": "5.1 Example\nThe following is an example of an optimization problem for the example shown here:\n\n\nCode\nusing Ribasim\nusing Ribasim: NodeID\nusing SQLite\nusing ComponentArrays: ComponentVector\n\ntoml_path = normpath(@__DIR__, \"../../generated_testmodels/allocation_example/ribasim.toml\")\np = Ribasim.Model(toml_path).integrator.p\nu = ComponentVector(; storage = zeros(length(p.basin.node_id)))\n\nallocation_model = p.allocation.allocation_models[1]\nt = 0.0\npriority_idx = 1\n\nRibasim.set_flow!(p.graph, NodeID(:FlowBoundary, 1), NodeID(:Basin, 2), 1.0)\n\nRibasim.adjust_capacities_edge!(allocation_model, p, priority_idx)\nRibasim.adjust_capacities_source!(allocation_model, p, priority_idx)\nRibasim.set_objective_priority!(allocation_model, p, u, t, priority_idx)\n\nprintln(p.allocation.allocation_models[1].problem)\n\n\nMin F_abs_user_demand[UserDemand #3] + F_abs_user_demand[UserDemand #13] + F_abs_user_demand[UserDemand #6]\nSubject to\n flow_conservation_basin[Basin #5] : F[(Basin #5, UserDemand #6)] + F[(Basin #5, Basin #2)] - F[(Basin #2, Basin #5)] + F[(Basin #5, TabulatedRatingCurve #7)] = 0\n flow_conservation_basin[Basin #2] : F[(Basin #2, UserDemand #3)] - F[(FlowBoundary #1, Basin #2)] - F[(Basin #5, Basin #2)] + F[(Basin #2, Basin #5)] = 0\n flow_conservation_basin[Basin #12] : F[(Basin #12, UserDemand #13)] - F[(TabulatedRatingCurve #7, Basin #12)] = 0\n abs_positive_user_demand[UserDemand #3] : -F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ -1.5\n abs_positive_user_demand[UserDemand #13] : -F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_positive_user_demand[UserDemand #6] : -F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n abs_negative_user_demand[UserDemand #3] : F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ 1.5\n abs_negative_user_demand[UserDemand #13] : F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_negative_user_demand[UserDemand #6] : F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n source[(FlowBoundary #1, Basin #2)] : F[(FlowBoundary #1, Basin #2)] ≤ 1\n return_flow[UserDemand #13] : F[(UserDemand #13, Terminal #10)] ≤ 0\n fractional_flow[(TabulatedRatingCurve #7, Basin #12)] : F[(TabulatedRatingCurve #7, Basin #12)] - 0.4 F[(Basin #5, TabulatedRatingCurve #7)] ≤ 0\n F[(Basin #5, UserDemand #6)] ≥ 0\n F[(Basin #12, UserDemand #13)] ≥ 0\n F[(TabulatedRatingCurve #7, Terminal #10)] ≥ 0\n F[(UserDemand #13, Terminal #10)] ≥ 0\n F[(Basin #2, UserDemand #3)] ≥ 0\n F[(FlowBoundary #1, Basin #2)] ≥ 0\n F[(Basin #5, Basin #2)] ≥ 0\n F[(Basin #2, Basin #5)] ≥ 0\n F[(TabulatedRatingCurve #7, Basin #12)] ≥ 0\n F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0",
"crumbs": [
"Julia core",
"Allocation"
@@ -981,7 +999,7 @@
"href": "core/validation.html",
"title": "Validation",
"section": "",
- "text": "The tables below show the validation rules applied to the input to the Julia core before running the model.\n\n1 Connectivity\nIn 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.\n\n\nCode\nusing Ribasim\nusing DataFrames: DataFrame\nusing MarkdownTables\n\nnode_names_snake_case = Vector{Symbol}()\nnode_names_camel_case = Vector{Symbol}()\nfor (node_name, node_type) in zip(fieldnames(Ribasim.Parameters), fieldtypes(Ribasim.Parameters))\n if node_type <: Ribasim.AbstractParameterNode\n push!(node_names_snake_case, node_name)\n push!(node_names_camel_case, nameof(node_type))\n end\nend\n\nfunction to_symbol(b::Bool)::String\n return b ? \"✓\" : \"x\"\nend\n\n\ndf = DataFrame()\ndf[!, :downstream] = node_names_snake_case\n\nfor node_name in node_names_snake_case\n df[!, node_name] =\n [(to_symbol(node_name_ in Ribasim.neighbortypes(node_name))) for node_name_ in node_names_snake_case]\nend\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndownstream\nbasin\nlinear_resistance\nmanning_resistance\ntabulated_rating_curve\nfractional_flow\nlevel_boundary\nflow_boundary\npump\noutlet\nterminal\ndiscrete_control\npid_control\nuser_demand\n\n\n\n\nbasin\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nlinear_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\nmanning_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\ntabulated_rating_curve\n✓\nx\nx\nx\nx\nx\nx\nx\nx\nx\n✓\nx\nx\n\n\nfractional_flow\nx\nx\nx\n✓\nx\nx\n✓\n✓\n✓\nx\n✓\nx\n✓\n\n\nlevel_boundary\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nflow_boundary\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npump\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\noutlet\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\nterminal\nx\nx\nx\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\ndiscrete_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npid_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n✓\nx\nx\n\n\nuser_demand\n✓\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\n\n\n\n\n\n2 Neighbor amounts\nThe table below shows for each node type between which bounds the amount of in- and outneighbors must be, for both flow and control edges.\n\n\nCode\nflow_in_min = Vector{String}()\nflow_in_max = Vector{String}()\nflow_out_min = Vector{String}()\nflow_out_max = Vector{String}()\ncontrol_in_min = Vector{String}()\ncontrol_in_max = Vector{String}()\ncontrol_out_min = Vector{String}()\ncontrol_out_max = Vector{String}()\n\nfunction unbounded(i::Int)::String\n return i == typemax(Int) ? \"∞\" : string(i)\nend\n\nfor node_name in node_names_camel_case\n bounds_flow = Ribasim.n_neighbor_bounds_flow(node_name)\n push!(flow_in_min, string(bounds_flow.in_min))\n push!(flow_in_max, unbounded(bounds_flow.in_max))\n push!(flow_out_min, string(bounds_flow.out_min))\n push!(flow_out_max, unbounded(bounds_flow.out_max))\n\n bounds_control = Ribasim.n_neighbor_bounds_control(node_name)\n push!(control_in_min, string(bounds_control.in_min))\n push!(control_in_max, unbounded(bounds_control.in_max))\n push!(control_out_min, string(bounds_control.out_min))\n push!(control_out_max, unbounded(bounds_control.out_max))\n\nend\n\ndf = DataFrame(\n ;\n node_type = node_names_snake_case,\n flow_in_min,\n flow_in_max,\n flow_out_min,\n flow_out_max,\n control_in_min,\n control_in_max,\n control_out_min,\n control_out_max,\n)\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nnode_type\nflow_in_min\nflow_in_max\nflow_out_min\nflow_out_max\ncontrol_in_min\ncontrol_in_max\ncontrol_out_min\ncontrol_out_max\n\n\n\n\nbasin\n0\n∞\n0\n∞\n0\n1\n0\n∞\n\n\nlinear_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nmanning_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\ntabulated_rating_curve\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nfractional_flow\n1\n1\n1\n1\n0\n1\n0\n0\n\n\nlevel_boundary\n0\n∞\n0\n∞\n0\n0\n0\n0\n\n\nflow_boundary\n0\n0\n1\n∞\n0\n0\n0\n0\n\n\npump\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\noutlet\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nterminal\n1\n∞\n0\n0\n0\n0\n0\n0\n\n\ndiscrete_control\n0\n0\n0\n0\n0\n0\n1\n∞\n\n\npid_control\n0\n0\n0\n0\n0\n1\n1\n1\n\n\nuser_demand\n1\n1\n1\n1\n0\n0\n0\n0",
+ "text": "The tables below show the validation rules applied to the input to the Julia core before running the model.\n\n1 Connectivity\nIn 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.\n\n\nCode\nusing Ribasim\nusing DataFrames: DataFrame\nusing MarkdownTables\n\nnode_names_snake_case = Vector{Symbol}()\nnode_names_camel_case = Vector{Symbol}()\nfor (node_name, node_type) in zip(fieldnames(Ribasim.Parameters), fieldtypes(Ribasim.Parameters))\n if node_type <: Ribasim.AbstractParameterNode\n push!(node_names_snake_case, node_name)\n push!(node_names_camel_case, nameof(node_type))\n end\nend\n\nfunction to_symbol(b::Bool)::String\n return b ? \"✓\" : \"x\"\nend\n\n\ndf = DataFrame()\ndf[!, :downstream] = node_names_snake_case\n\nfor node_name in node_names_snake_case\n df[!, node_name] =\n [(to_symbol(node_name_ in Ribasim.neighbortypes(node_name))) for node_name_ in node_names_snake_case]\nend\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndownstream\nbasin\nlinear_resistance\nmanning_resistance\ntabulated_rating_curve\nfractional_flow\nlevel_boundary\nflow_boundary\npump\noutlet\nterminal\ndiscrete_control\npid_control\nuser_demand\n\n\n\n\nbasin\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nlinear_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\nmanning_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\ntabulated_rating_curve\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\nfractional_flow\nx\nx\nx\n✓\nx\nx\n✓\n✓\n✓\nx\n✓\nx\n✓\n\n\nlevel_boundary\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nflow_boundary\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npump\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\noutlet\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\nterminal\nx\nx\nx\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\ndiscrete_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npid_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n✓\nx\nx\n\n\nuser_demand\n✓\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\n\n\n\n\n\n2 Neighbor amounts\nThe table below shows for each node type between which bounds the amount of in- and outneighbors must be, for both flow and control edges.\n\n\nCode\nflow_in_min = Vector{String}()\nflow_in_max = Vector{String}()\nflow_out_min = Vector{String}()\nflow_out_max = Vector{String}()\ncontrol_in_min = Vector{String}()\ncontrol_in_max = Vector{String}()\ncontrol_out_min = Vector{String}()\ncontrol_out_max = Vector{String}()\n\nfunction unbounded(i::Int)::String\n return i == typemax(Int) ? \"∞\" : string(i)\nend\n\nfor node_name in node_names_camel_case\n bounds_flow = Ribasim.n_neighbor_bounds_flow(node_name)\n push!(flow_in_min, string(bounds_flow.in_min))\n push!(flow_in_max, unbounded(bounds_flow.in_max))\n push!(flow_out_min, string(bounds_flow.out_min))\n push!(flow_out_max, unbounded(bounds_flow.out_max))\n\n bounds_control = Ribasim.n_neighbor_bounds_control(node_name)\n push!(control_in_min, string(bounds_control.in_min))\n push!(control_in_max, unbounded(bounds_control.in_max))\n push!(control_out_min, string(bounds_control.out_min))\n push!(control_out_max, unbounded(bounds_control.out_max))\n\nend\n\ndf = DataFrame(\n ;\n node_type = node_names_snake_case,\n flow_in_min,\n flow_in_max,\n flow_out_min,\n flow_out_max,\n control_in_min,\n control_in_max,\n control_out_min,\n control_out_max,\n)\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nnode_type\nflow_in_min\nflow_in_max\nflow_out_min\nflow_out_max\ncontrol_in_min\ncontrol_in_max\ncontrol_out_min\ncontrol_out_max\n\n\n\n\nbasin\n0\n∞\n0\n∞\n0\n1\n0\n∞\n\n\nlinear_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nmanning_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\ntabulated_rating_curve\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nfractional_flow\n1\n1\n1\n1\n0\n1\n0\n0\n\n\nlevel_boundary\n0\n∞\n0\n∞\n0\n0\n0\n0\n\n\nflow_boundary\n0\n0\n1\n∞\n0\n0\n0\n0\n\n\npump\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\noutlet\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nterminal\n1\n∞\n0\n0\n0\n0\n0\n0\n\n\ndiscrete_control\n0\n0\n0\n0\n0\n0\n1\n∞\n\n\npid_control\n0\n0\n0\n0\n0\n1\n1\n1\n\n\nuser_demand\n1\n1\n1\n1\n0\n0\n0\n0",
"crumbs": [
"Julia core",
"Validation"
@@ -1155,18 +1173,25 @@
"text": "1 nodes.outlet\nnodes.outlet"
},
{
- "objectID": "python/reference/nodes.fractional_flow.html",
- "href": "python/reference/nodes.fractional_flow.html",
- "title": "1 nodes.fractional_flow",
+ "objectID": "python/reference/nodes.level_demand.html",
+ "href": "python/reference/nodes.level_demand.html",
+ "title": "1 nodes.level_demand",
"section": "",
- "text": "1 nodes.fractional_flow\nnodes.fractional_flow"
+ "text": "1 nodes.level_demand\nnodes.level_demand"
},
{
- "objectID": "python/reference/nodes.terminal.html",
- "href": "python/reference/nodes.terminal.html",
- "title": "1 nodes.terminal",
+ "objectID": "python/reference/nodes.level_boundary.html",
+ "href": "python/reference/nodes.level_boundary.html",
+ "title": "1 nodes.level_boundary",
"section": "",
- "text": "1 nodes.terminal\nnodes.terminal"
+ "text": "1 nodes.level_boundary\nnodes.level_boundary"
+ },
+ {
+ "objectID": "python/reference/nodes.flow_demand.html",
+ "href": "python/reference/nodes.flow_demand.html",
+ "title": "1 nodes.flow_demand",
+ "section": "",
+ "text": "1 nodes.flow_demand\nnodes.flow_demand"
},
{
"objectID": "python/reference/nodes.pid_control.html",
Here \(p > 0\) is the threshold value which determines the interval \([0,p]\) of the smooth transition between \(0\) and \(1\), see the plot below.
-Code
import numpy as np
@@ -475,7 +475,7 @@
diff --git a/core/usage.html b/core/usage.html
index d36b40bac..16d8c6ab5 100644
--- a/core/usage.html
+++ b/core/usage.html
@@ -317,33 +317,37 @@ On this page
-3 Node
LevelDemand / static
: static target levelsLevelDemand / time
: dynamic target levels-
+
FlowDemand / static
: flow demands
+FlowDemand / time
: dynamic flow demands
+
Terminal / static
: - (only node IDs)
@@ -1301,7 +1310,7 @@ - During the simulation it is checked whether the truth of any of the conditions changes. @@ -1853,8 +1936,8 @@
10 UserDemanddemand
Float64
\(m^3 s^{-1}\)
--
+non-negative
return_factor
@@ -1364,7 +1373,7 @@ demand
Float64
\(m^3 s^{-1}\)
--
+non-negative
return_factor
@@ -1384,7 +1393,7 @@
11 LevelDemand
-An LevelDemand
node associates a minimum and a maximum level with connected basins to be used by the allocation algorithm. Below the minimum level the basin has a demand of the supplied priority, above the maximum level the basin acts as a source, used by all nodes with demands in order of priority. The same LevelDemand
node can be used for basins in different subnetworks.
+A LevelDemand
node associates a minimum and a maximum level with connected basins to be used by the allocation algorithm. Below the minimum level the basin has a demand of the supplied priority, above the maximum level the basin acts as a source, used by all nodes with demands in order of priority. The same LevelDemand
node can be used for basins in different subnetworks.
@@ -1468,8 +1477,82 @@
-
-12 LevelBoundary
+
+12 FlowDemand
+A FlowDemand
node associates a non-consuming flow demand to a connector node (e.g. Pump
, TabulatedRatingCurve
) for one single priority. FlowDemand nodes can set a flow demand only for a single connector node.
+
+
+
+column
+type
+unit
+restriction
+
+
+
+
+node_id
+Int32
+-
+sorted
+
+
+priority
+Int32
+-
+positive
+
+
+demand
+Float64
+\(m^3 s^{-1}\)
+non-negative
+
+
+
+
+12.1 FlowDemand / time
+This table is the transient form of the FlowDemand
table, in which a time-dependent demand can be supplied. Similar to the static version, only a single priority per FlowDemand
node can be provided.
+
+
+
+column
+type
+unit
+restriction
+
+
+
+
+node_id
+Int32
+-
+sorted
+
+
+time
+DateTime
+-
+sorted per node id
+
+
+priority
+Int32
+-
+positive
+
+
+demand
+Float64
+\(m^3 s^{-1}\)
+non-negative
+
+
+
+
+
+
+13 LevelBoundary
Acts like an infinitely large basin where the level does not change by flow. This can be connected to a basin via a LinearResistance
. This boundary node will then exchange water with the basin based on the difference in water level between the two.
@@ -1501,8 +1584,8 @@ 12 LevelBoundary
-
-12.1 LevelBoundary / time
+
+13.1 LevelBoundary / time
This table is the transient form of the LevelBoundary
table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id
. With this the levels can be updated over time. In between the given times the level is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id
can be either in this table or in the static one, but not both.
@@ -1536,8 +1619,8 @@
-
-13 FlowBoundary
+
+14 FlowBoundary
Pump water to a destination node. We require that the edge connecting the flow boundary to the Basin should point towards the basin, so that positive flow corresponds to water being added to the model. The set flow rate will be pumped unless the intake storage (for a negative flow rate) is less than \(10~m^3\), in which case the flow rate will be linearly reduced to \(0~m^3/s\). Note that the connected node must always be a Basin.
@@ -1569,8 +1652,8 @@ 13 FlowBoundary<
-
-13.1 FlowBoundary / time
+
+14.1 FlowBoundary / time
This table is the transient form of the FlowBoundary
table. The only differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id
. With this the flow rates can be updated over time. In between the given times the flow rate is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id
can be either in this table or in the static one, but not both.
@@ -1604,8 +1687,8 @@
-
-14 LinearResistance
+
+15 LinearResistance
Flow proportional to the level difference between the connected basins.
@@ -1650,8 +1733,8 @@ 14 LinearResista
-
-15 ManningResistance
+
+16 ManningResistance
Flow through this connection is estimated by conservation of energy and the Manning-Gauckler formula to estimate friction losses.
@@ -1708,8 +1791,8 @@ 15 ManningResist
-
-16 Terminal
+
+17 Terminal
A terminal is a water sink without state or properties. Any water that flows into a terminal node is removed from the model. No water can come into the model from a terminal node. For example, terminal nodes can be used as a downstream boundary.
@@ -1730,11 +1813,11 @@ 16 Terminal
-
-17 DisceteControl
+
+18 DisceteControl
DiscreteControl is implemented based on VectorContinuousCallback.
-
-17.1 DiscreteControl / condition
+
+18.1 DiscreteControl / condition
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.
@@ -1791,8 +1874,8 @@
-17.2 DiscreteControl / logic
+
+18.2 DiscreteControl / logic
The logic schema defines which control states are triggered based on the truth of the conditions a DiscreteControl node listens to. DiscreteControl is applied in the Julia core as follows:
<
-
-18 PidControl
+
+19 PidControl
The PidControl node controls the level in a basin by continuously controlling the flow rate of a connected pump or outlet. See also PID controller. When A PidControl node is made inactive, the node under its control retains the last flow rate value, and the error integral is reset to 0.
In the future controlling the flow on a particular edge could be supported.
@@ -1923,8 +2006,8 @@ 18 PidControl
-
-18.1 PidControl / time
+
+19.1 PidControl / time
This table is the transient form of the PidControl
table. The differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id
. With this the target level and PID coefficients can be updated over time. In between the given times the these values interpolated linearly, and outside these values area constant given by the nearest time value. Note that a node_id
can be either in this table or in the static one, but not both.
@@ -1988,10 +2071,10 @@
-
-19 Results
-
-19.1 Basin - basin.arrow
+
+20 Results
+
+20.1 Basin - basin.arrow
The basin table contains results of the storage and level of each basin at every solver timestep. The initial condition is also written to the file.
@@ -2026,8 +2109,8 @@
The table is sorted by time, and per time it is sorted by node_id
.
-
-19.2 Flow - flow.arrow
+
+20.2 Flow - flow.arrow
The flow table contains calculated mean flows for every flow edge in the model. In the time column the start of the period is indicated.
@@ -2077,8 +2160,8 @@
The table is sorted by time, and per time the same edge_id
order is used, though not sorted. The edge_id
value is the same as the fid
written to the Edge table, and can be used to directly look up the Edge geometry. Flows that are added to the model at a node, have a missing edge_id
, and identical from_node_id
and to_node_id
. Flows out of the model always have a negative sign, and additions a positive sign.
-
-19.3 DiscreteControl - control.arrow
+
+20.3 DiscreteControl - control.arrow
The control table contains a record of each change of control state: when it happened, which control node was involved, to which control state it changed and based on which truth state.
@@ -2107,8 +2190,8 @@
-19.4 Allocation - allocation.arrow
+
+20.4 Allocation - allocation.arrow
The allocation table contains a record of allocation results: when it happened, for which node, in which allocation network, and what the demand, allocated flow and realized flow were.
@@ -2167,8 +2250,8 @@
-19.5 Allocation flow - allocation_flow.arrow
+
+20.5 Allocation flow - allocation_flow.arrow
The allocation flow table contains results of the optimized allocation flow on every edge in the model that is part of a subnetwork, for each time an optimization problem is solved (see also here). If in the model a main network and subnetwork(s) are specified, there are 2 different types of optimization for the subnetwork: collecting its total demand per priority (for allocating flow from the main network to the subnetwork), and allocating flow within the subnetwork. The column collect_demands
provides the distinction between these two optimization types.
diff --git a/core/validation.html b/core/validation.html
index 57202e552..8c7b5c388 100644
--- a/core/validation.html
+++ b/core/validation.html
@@ -262,7 +262,7 @@ Validation
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
@@ -385,7 +385,7 @@ 1 Connectivityx
x
x
-x
+✓
x
x
x
@@ -546,7 +546,7 @@ 1 Connectivity
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 edges.
-
+
Code
= Vector{String}()
diff --git a/python/examples_files/figure-html/cell-59-output-1.png b/python/examples_files/figure-html/cell-59-output-1.png
index fb18dde11..d234145e9 100644
Binary files a/python/examples_files/figure-html/cell-59-output-1.png and b/python/examples_files/figure-html/cell-59-output-1.png differ
diff --git a/python/examples_files/figure-html/cell-60-output-2.png b/python/examples_files/figure-html/cell-60-output-2.png
index eb25d2657..73061a701 100644
Binary files a/python/examples_files/figure-html/cell-60-output-2.png and b/python/examples_files/figure-html/cell-60-output-2.png differ
diff --git a/python/reference/index.html b/python/reference/index.html
index 27851c9c8..a3366d7cf 100644
--- a/python/reference/index.html
+++ b/python/reference/index.html
@@ -271,6 +271,14 @@ flow_in_min nodes.pid_control
+
+nodes.flow_demand
+
+
+
+nodes.level_demand
+
+
diff --git a/python/reference/nodes.flow_demand.html b/python/reference/nodes.flow_demand.html
new file mode 100644
index 000000000..471cab086
--- /dev/null
+++ b/python/reference/nodes.flow_demand.html
@@ -0,0 +1,543 @@
+
+
+
+
+
+
+
+
+
+Ribasim
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/python/reference/nodes.level_demand.html b/python/reference/nodes.level_demand.html
new file mode 100644
index 000000000..1aa216133
--- /dev/null
+++ b/python/reference/nodes.level_demand.html
@@ -0,0 +1,543 @@
+
+
+
+
+
+
+
+
+
+Ribasim
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/python/test-models.html b/python/test-models.html
index 10812175c..489cfa806 100644
--- a/python/test-models.html
+++ b/python/test-models.html
@@ -227,7 +227,7 @@ Test models
Ribasim developers use the following models in their testbench and in order to test new features.
-
+
Code
import ribasim_testmodels
@@ -319,154 +319,168 @@ Test models
+
+
+
+
+
+
+
+
+
+
diff --git a/python/test-models_files/figure-html/cell-2-output-11.png b/python/test-models_files/figure-html/cell-2-output-11.png
index 4fc0862b5..e1b284d9d 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-11.png and b/python/test-models_files/figure-html/cell-2-output-11.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-12.png b/python/test-models_files/figure-html/cell-2-output-12.png
index 41d5ed5aa..4fc0862b5 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-12.png and b/python/test-models_files/figure-html/cell-2-output-12.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-13.png b/python/test-models_files/figure-html/cell-2-output-13.png
index 057ce9a37..41d5ed5aa 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-13.png and b/python/test-models_files/figure-html/cell-2-output-13.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-14.png b/python/test-models_files/figure-html/cell-2-output-14.png
index 3700441cd..057ce9a37 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-14.png and b/python/test-models_files/figure-html/cell-2-output-14.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-15.png b/python/test-models_files/figure-html/cell-2-output-15.png
index 3ac7ed987..5ccd30a47 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-15.png and b/python/test-models_files/figure-html/cell-2-output-15.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-16.png b/python/test-models_files/figure-html/cell-2-output-16.png
index 51472f2e6..3ac7ed987 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-16.png and b/python/test-models_files/figure-html/cell-2-output-16.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-17.png b/python/test-models_files/figure-html/cell-2-output-17.png
index 28f13a6b3..4b9387c61 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-17.png and b/python/test-models_files/figure-html/cell-2-output-17.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-18.png b/python/test-models_files/figure-html/cell-2-output-18.png
index b7e5989cb..51472f2e6 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-18.png and b/python/test-models_files/figure-html/cell-2-output-18.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-19.png b/python/test-models_files/figure-html/cell-2-output-19.png
index 6feed0dcf..28f13a6b3 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-19.png and b/python/test-models_files/figure-html/cell-2-output-19.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-20.png b/python/test-models_files/figure-html/cell-2-output-20.png
index 48143149e..b7e5989cb 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-20.png and b/python/test-models_files/figure-html/cell-2-output-20.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-21.png b/python/test-models_files/figure-html/cell-2-output-21.png
index e23644dbf..6feed0dcf 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-21.png and b/python/test-models_files/figure-html/cell-2-output-21.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-22.png b/python/test-models_files/figure-html/cell-2-output-22.png
index 385f70f3c..48143149e 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-22.png and b/python/test-models_files/figure-html/cell-2-output-22.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-23.png b/python/test-models_files/figure-html/cell-2-output-23.png
index 30bfdf250..e23644dbf 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-23.png and b/python/test-models_files/figure-html/cell-2-output-23.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-24.png b/python/test-models_files/figure-html/cell-2-output-24.png
index c6cd3c340..385f70f3c 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-24.png and b/python/test-models_files/figure-html/cell-2-output-24.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-25.png b/python/test-models_files/figure-html/cell-2-output-25.png
index aec5c7b0c..30bfdf250 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-25.png and b/python/test-models_files/figure-html/cell-2-output-25.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-26.png b/python/test-models_files/figure-html/cell-2-output-26.png
index 59848dc9c..c6cd3c340 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-26.png and b/python/test-models_files/figure-html/cell-2-output-26.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-27.png b/python/test-models_files/figure-html/cell-2-output-27.png
index ca63191bd..aec5c7b0c 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-27.png and b/python/test-models_files/figure-html/cell-2-output-27.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-28.png b/python/test-models_files/figure-html/cell-2-output-28.png
index 2a311ae92..59848dc9c 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-28.png and b/python/test-models_files/figure-html/cell-2-output-28.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-29.png b/python/test-models_files/figure-html/cell-2-output-29.png
index 6cd33e1c7..ca63191bd 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-29.png and b/python/test-models_files/figure-html/cell-2-output-29.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-30.png b/python/test-models_files/figure-html/cell-2-output-30.png
index 8414c43e1..2a311ae92 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-30.png and b/python/test-models_files/figure-html/cell-2-output-30.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-31.png b/python/test-models_files/figure-html/cell-2-output-31.png
index 59aa41129..6cd33e1c7 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-31.png and b/python/test-models_files/figure-html/cell-2-output-31.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-32.png b/python/test-models_files/figure-html/cell-2-output-32.png
index bd21c153c..8414c43e1 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-32.png and b/python/test-models_files/figure-html/cell-2-output-32.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-33.png b/python/test-models_files/figure-html/cell-2-output-33.png
new file mode 100644
index 000000000..59aa41129
Binary files /dev/null and b/python/test-models_files/figure-html/cell-2-output-33.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-34.png b/python/test-models_files/figure-html/cell-2-output-34.png
new file mode 100644
index 000000000..bd21c153c
Binary files /dev/null and b/python/test-models_files/figure-html/cell-2-output-34.png differ
diff --git a/search.json b/search.json
index 3972ac4d9..80e7a708d 100644
--- a/search.json
+++ b/search.json
@@ -43,7 +43,7 @@
"href": "contribute/addnode.html#parameters",
"title": "Adding node types",
"section": "1.1 Parameters",
- "text": "1.1 Parameters\nThe parameters object (defined in solve.jl) passed to the ODE solver must be made aware of the new node type. Therefore define a struct in solve.jl which holds the data for each node of the new node type:\nstruct NewNodeType\n node_id::Vector{NodeID}\n # Other fields\nend\nThese fields do not have to correspond 1:1 with the input tables (see below). The vector with all node IDs that are of the new type in a given model is a mandatory field. Now you can:\n\nAdd new_node_type::NewNodeType to the Parameters object;\nAdd new_node_type = NewNodeType(db,config) to the function Parameters in create.jl and add new_node_type at the proper location in the Parameters constructor call.",
+ "text": "1.1 Parameters\nThe parameters object (defined in parameter.jl) passed to the ODE solver must be made aware of the new node type. Therefore define a struct in parameter.jl which holds the data for each node of the new node type:\nstruct NewNodeType\n node_id::Vector{NodeID}\n # Other fields\nend\nThese fields do not have to correspond 1:1 with the input tables (see below). The vector with all node IDs that are of the new type in a given model is a mandatory field. Now you can:\n\nAdd new_node_type::NewNodeType to the Parameters object;\nAdd new_node_type = NewNodeType(db,config) to the function Parameters in read.jl and add new_node_type at the proper location in the Parameters constructor call.",
"crumbs": [
"Contributing",
"Adding node types"
@@ -54,7 +54,7 @@
"href": "contribute/addnode.html#reading-from-configuration",
"title": "Adding node types",
"section": "1.2 Reading from configuration",
- "text": "1.2 Reading from configuration\nThere can be several schemas associated with a single node type. To define a schema for the new node type, add the following to validation.jl:\n@schema \"ribasim.newnodetype.static\" NewNodeTypeStatic\n\n\"\"\"\nnode_id: node ID of the NewNodeType node\n\"\"\"\n@version NewNodeTypeStaticV1 begin\n node_id::Int32\n # Other fields\nend\nHere Static refers to data that does not change over time. For naming conventions of these schemas see Node usage.\nvalidation.jl also deals with checking and applying a specific sorting order for the tabular data (default is sorting by node ID only), see sort_by_function and sorted_table!.\nNow we define the function that is called in the second bullet above, in create.jl:\nfunction NewNodeType(db::DB, config::Config)::NewNodeType\n static = load_structvector(db, config, NewNodeTypeStaticV1)\n defaults = (; foo = 1, bar = false)\n # Process potential control states in the static data\n parsed_parameters, valid = parse_static_and_time(db, config, \"Outlet\"; static, defaults)\n\n if !valid\n error(\"Errors occurred when parsing NewNodeType data.\")\n end\n\n # Unpack the fields of static as inputs for the NewNodeType constructor\n return NewNodeType(\n NodeID.(NodeType.NewNodeType, parsed_parameters.node_id),\n parsed_parameters.some_property,\n parsed_parameters.control_mapping)\nend",
+ "text": "1.2 Reading from configuration\nThere can be several schemas associated with a single node type. To define a schema for the new node type, add the following to schema.jl:\n@schema \"ribasim.newnodetype.static\" NewNodeTypeStatic\n\n\"\"\"\nnode_id: node ID of the NewNodeType node\n\"\"\"\n@version NewNodeTypeStaticV1 begin\n node_id::Int32\n # Other fields\nend\nHere static refers to data that does not change over time. For naming conventions of these schemas see Node usage. If a new schema contains a priority column for allocation, it must also be added to the list of all such schemas in the function get_all_priorities in util.jl.\nvalidation.jl deals with checking and applying a specific sorting order for the tabular data (default is sorting by node ID only), see sort_by_function and sorted_table!.\nNow we define the function that is called in the second bullet above, in read.jl:\nfunction NewNodeType(db::DB, config::Config)::NewNodeType\n static = load_structvector(db, config, NewNodeTypeStaticV1)\n defaults = (; foo = 1, bar = false)\n # Process potential control states in the static data\n parsed_parameters, valid = parse_static_and_time(db, config, \"NewNodeType\"; static, defaults)\n\n if !valid\n error(\"Errors occurred when parsing NewNodeType data.\")\n end\n\n # Unpack the fields of static as inputs for the NewNodeType constructor\n return NewNodeType(\n NodeID.(NodeType.NewNodeType, parsed_parameters.node_id),\n parsed_parameters.some_property,\n parsed_parameters.control_mapping)\nend",
"crumbs": [
"Contributing",
"Adding node types"
@@ -76,7 +76,7 @@
"href": "contribute/addnode.html#the-jacobian",
"title": "Adding node types",
"section": "1.4 The Jacobian",
- "text": "1.4 The Jacobian\nSee Equations for a mathematical description of the Jacobian.\nBefore the Julia core runs its simulation, the sparsity structure jac_prototype of \\(J\\) is determined with get_jac_prototype in utils.jl. This function runs trough all node types and looks for nodes that create dependencies between states. It creates a sparse matrix of zeros and ones, where the ones denote locations of possible non-zeros in \\(J\\).\nWe divide the various node types in groups based on what type of state dependencies they yield, and these groups are discussed below. Each group has its own method update_jac_prototype! in utils.jl for the sparsity structure induced by nodes of that group. NewNodeType should be added to the signature of one these methods, or to the list of node types that do not contribute to the Jacobian in the method of update_jac_prototype! whose signature contains node::AbstractParameterNode. Of course it is also possible that a new method of update_jac_prototype! has to be introduced.\nThe current dependency groups are:\n\nOut-neighbor dependencies: examples are TabulatedRatingCurve, Pump (the latter only in the reduction factor regime and not PID controlled). If the in-neighbor of a node of this group is a basin, then the storage of this basin affects itself and the storage of the outneighbor (or the basin one node further if it is connected with a FractionalFlow in between) if that is also a basin;\nEither-neighbor dependencies: examples are LinearResistance, ManningResistance. If either the in-neighbor or out-neighbor of a node of this group is a basin, the storage of this basin depends on itself. If both the in-neighbor and the out-neighbor are basins, their storages also depend on eachother.\nThe PidControl node is a special case which is discussed in equations.\n\nUsing jac_prototype the Jacobian of water_balance! is computed automatically using ForwardDiff.jl with memory management provided by PreallocationTools.jl. These computations make use of DiffCache and dual numbers.",
+ "text": "1.4 The Jacobian\nSee Equations for a mathematical description of the Jacobian.\nBefore the Julia core runs its simulation, the sparsity structure jac_prototype of \\(J\\) is determined with get_jac_prototype in sparsity.jl. This function runs trough all node types and looks for nodes that create dependencies between states. It creates a sparse matrix of zeros and ones, where the ones denote locations of possible non-zeros in \\(J\\). Note that only nodes that set flows in the physical layer (or have their own state like PidControl) affect the sparsity structure.\nWe divide the various node types in groups based on what type of state dependencies they yield, and these groups are discussed below. Each group has its own method update_jac_prototype! in utils.jl for the sparsity structure induced by nodes of that group. NewNodeType should be added to the signature of one these methods, or to the list of node types that do not contribute to the Jacobian in the method of update_jac_prototype! whose signature contains node::AbstractParameterNode. Of course it is also possible that a new method of update_jac_prototype! has to be introduced.\nThe current dependency groups are:\n\nOut-neighbor dependencies: examples are TabulatedRatingCurve, Pump (the latter only in the reduction factor regime and not PID controlled). If the in-neighbor of a node of this group is a basin, then the storage of this basin affects itself and the storage of the outneighbor (or the basin one node further if it is connected with a FractionalFlow in between) if that is also a basin;\nEither-neighbor dependencies: examples are LinearResistance, ManningResistance. If either the in-neighbor or out-neighbor of a node of this group is a basin, the storage of this basin depends on itself. If both the in-neighbor and the out-neighbor are basins, their storages also depend on eachother.\nThe PidControl node is a special case which is discussed in equations.\n\nUsing jac_prototype the Jacobian of water_balance! is computed automatically using ForwardDiff.jl with memory management provided by PreallocationTools.jl. These computations make use of DiffCache and dual numbers.",
"crumbs": [
"Contributing",
"Adding node types"
@@ -87,7 +87,7 @@
"href": "contribute/addnode.html#python-class",
"title": "Adding node types",
"section": "2.1 Python class",
- "text": "2.1 Python class\nCreate a new file python/ribasim/ribasim/node_types/new_node_type.py which is structured as follows:\nfrom typing import Optional\n\nimport pandera as pa\nfrom pandera.engines.pandas_engine import PydanticModel\nfrom pandera.typing import DataFrame\nfrom pydantic import ConfigDict\n\nfrom ribasim import models\nfrom ribasim.input_base import TableModel\n\n__all__ = (\"NewNodeType\",)\n\nclass StaticSchema(pa.SchemaModel):\n class Config:\n \"\"\"Config with dataframe-level data type.\"\"\"\n\n dtype = PydanticModel(models.NewNodeTypeStatic)\n\n# Possible other schemas\n\n\nclass NewNodeType(TableModel):\n \"\"\"\n Description of this node type.\n\n Parameters\n ----------\n static: pandas.DataFrame\n table with data for this node type.\n\n possible other schemas\n \"\"\"\n\n static: DataFrame[StaticSchema] | None\n # possible other schemas\n\n model_config = ConfigDict(validate_assignment=True)\n\n def sort(self):\n self.static.sort_values(\"node_id\", ignore_index=True, inplace=True)\nThe sort method should implement the same sorting as in validation.jl.\nNow in both python/ribasim/ribasim/__init__.py and python/ribasim/ribasim/node_types/__init__.py add\n\nfrom ribasim.node_types.new_node_type import NewNodeType;\n\"NewNodeType\" to __all__.\n\nIn python/ribasim/ribasim/model.py, add\n\nfrom ribasim.new_node_type import NewNodeType;\nnew_node_type as a parameter and in the docstring of the Model class.\n\nIn python/ribasim/ribasim/geometry/node.py add a color and shape description in the MARKERS and COLORS dictionaries.",
+ "text": "2.1 Python class\nIn python/ribasim/ribasim/config.py add\n\nthe above defined schemas to the imports from ribasim.schemas. This requires code generation to work, see Finishing up;\na class of the following form with all schemas associated with the node type:\n\nclass NewNodeType(NodeModel):\n static: TableModel[NewNodeTypeStaticSchema] = Field(\n default_factory=TableModel[NewNodeTypeStaticSchema],\n json_schema_extra={\"sort_keys\": [\"node_id\"]},\n )\nIn python/ribasim/ribasim/__init__.py add\n\nNewNodeType to the imports from ribasim.config;\n\"NewNodeType\" to __all__.\n\nIn python/ribasim/ribasim/model.py, add\n\nNewNodeType to the imports from ribasim.config;\nnew_node_type as a parameter and in the docstring of the Model class.\n\nIn python/ribasim/ribasim/geometry/node.py add a color and shape description in the MARKERS and COLORS dictionaries.",
"crumbs": [
"Contributing",
"Adding node types"
@@ -241,7 +241,7 @@
"href": "python/reference/index.html",
"title": "1 API Reference",
"section": "",
- "text": "The Model class represents an entire Ribasim model.\n\n\n\nModel\n\n\n\n\n\n\n\nThe Edge database layer.\n\n\n\nEdgeTable\nDefines the connections between nodes.\n\n\n\n\n\n\nAvailable node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control",
+ "text": "The Model class represents an entire Ribasim model.\n\n\n\nModel\n\n\n\n\n\n\n\nThe Edge database layer.\n\n\n\nEdgeTable\nDefines the connections between nodes.\n\n\n\n\n\n\nAvailable node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control\n\n\n\nnodes.flow_demand\n\n\n\nnodes.level_demand",
"crumbs": [
"Python tooling",
"API Reference"
@@ -274,7 +274,7 @@
"href": "python/reference/index.html#node-types",
"title": "1 API Reference",
"section": "",
- "text": "Available node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control",
+ "text": "Available node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control\n\n\n\nnodes.flow_demand\n\n\n\nnodes.level_demand",
"crumbs": [
"Python tooling",
"API Reference"
@@ -288,11 +288,18 @@
"text": "1 nodes.user_demand\nnodes.user_demand"
},
{
- "objectID": "python/reference/nodes.level_boundary.html",
- "href": "python/reference/nodes.level_boundary.html",
- "title": "1 nodes.level_boundary",
+ "objectID": "python/reference/nodes.terminal.html",
+ "href": "python/reference/nodes.terminal.html",
+ "title": "1 nodes.terminal",
"section": "",
- "text": "1 nodes.level_boundary\nnodes.level_boundary"
+ "text": "1 nodes.terminal\nnodes.terminal"
+ },
+ {
+ "objectID": "python/reference/nodes.fractional_flow.html",
+ "href": "python/reference/nodes.fractional_flow.html",
+ "title": "1 nodes.fractional_flow",
+ "section": "",
+ "text": "1 nodes.fractional_flow\nnodes.fractional_flow"
},
{
"objectID": "python/reference/nodes.tabulated_rating_curve.html",
@@ -398,7 +405,7 @@
"href": "build/index.html#types",
"title": "1 API Reference",
"section": "1.2 Types",
- "text": "1.2 Types\n# Ribasim.Allocation — Type.\nObject for all information about allocation allocationnetworkids: The unique sorted allocation network IDs allocation models: The allocation models for the main network and subnetworks corresponding to allocationnetworkids mainnetworkconnections: (fromid, toid) from the main network to the subnetwork per subnetwork priorities: All used priority values. subnetworkdemands: The demand of an edge from the main network to a subnetwork recorddemand: A record of demands and allocated flows for nodes that have these. record_flow: A record of all flows computed by allocation optimization, eventually saved to output file\nsource\n# Ribasim.AllocationModel — Type.\nStore information for a subnetwork used for allocation.\nallocationnetworkid: The ID of this allocation network capacity: The capacity per edge of the allocation network, as constrained by nodes that have a maxflowrate problem: The JuMP.jl model for solving the allocation problem Δt_allocation: The time interval between consecutive allocation solves\nsource\n# Ribasim.AllocationModel — Method.\nConstruct the JuMP.jl problem for allocation.\nInputs\np: Ribasim problem parameters Δt_allocation: The timestep between successive allocation solves\nOutputs\nAn AllocationModel object.\nsource\n# Ribasim.Basin — Type.\nRequirements:\n\nMust be positive: precipitation, evaporation, infiltration, drainage\nIndex points to a Basin\nvolume, area, level must all be positive and monotonic increasing.\n\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of vectors or Arrow Tables, and is added to avoid type instabilities. The nodeid are Indices to support fast lookup of e.g. currentlevel using ID.\nif autodiff T = DiffCache{Vector{Float64}} else T = Vector{Float64} end\nsource\n# Ribasim.DiscreteControl — Type.\nnodeid: node ID of the DiscreteControl node; these are not unique but repeated by the amount of conditions of this DiscreteControl node listennodeid: the ID of the node being condition on variable: the name of the variable in the condition greaterthan: The threshold value in the condition conditionvalue: The current value of each condition controlstate: Dictionary: node ID => (control state, control state start) logic_mapping: Dictionary: (control node ID, truth state) => control state record: Namedtuple with discrete control information for results\nsource\n# Ribasim.EdgeMetadata — Type.\nType for storing metadata of edges in the graph: id: ID of the edge (only used for labeling flow output) type: type of the edge allocationnetworkidsource: ID of allocation network where this edge is a source (0 if not a source) fromid: the node ID of the source node toid: the node ID of the destination node allocationflow: whether this edge has a flow in an allocation network node_ids: if this edge has allocation flow, these are all the nodes from the physical layer this edge consists of\nsource\n# Ribasim.FlatVector — Type.\nstruct FlatVector{T} <: AbstractVector{T}\nA FlatVector is an AbstractVector that iterates the T of a Vector{Vector{T}}.\nEach inner vector is assumed to be of equal length.\nIt is similar to Iterators.flatten, though that doesn’t work with the Tables.Column interface, which needs length and getindex support.\nsource\n# Ribasim.FlowBoundary — Type.\nnodeid: node ID of the FlowBoundary node active: whether this node is active and thus contributes flow flowrate: target flow rate\nsource\n# Ribasim.FractionalFlow — Type.\nRequirements:\n\nfrom: must be (TabulatedRatingCurve,) node\nto: must be (Basin,) node\nfraction must be positive.\n\nnodeid: node ID of the TabulatedRatingCurve node fraction: The fraction in [0,1] of flow the node lets through controlmapping: dictionary from (nodeid, controlstate) to fraction\nsource\n# Ribasim.InNeighbors — Type.\nIterate over incoming neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.LevelBoundary — Type.\nnode_id: node ID of the LevelBoundary node active: whether this node is active level: the fixed level of this ‘infinitely big basin’\nsource\n# Ribasim.LevelDemand — Type.\nnodeid: node ID of the LevelDemand node minlevel: The minimum target level of the connected basin(s) max_level: The maximum target level of the connected basin(s) priority: If in a shortage state, the priority of the demand of the connected basin(s)\nsource\n# Ribasim.LinearResistance — Type.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\n\nnodeid: node ID of the LinearResistance node active: whether this node is active and thus contributes flows resistance: the resistance to flow; Q*unlimited = Δh/resistancemax_flow_rate: the maximum flow rate allowed through the node;Q = clamp(Q*unlimited, -max*flow*rate, max*flow*rate) controlmapping: dictionary from (nodeid, controlstate) to resistance and/or active state\nsource\n# Ribasim.ManningResistance — Type.\nThis is a simple Manning-Gauckler reach connection.\n\nLength describes the reach length.\nroughness describes Manning’s n in (SI units).\n\nThe profile is described by a trapezoid:\n \\ / ^\n \\ / |\n \\ / | dz\nbottom \\______/ |\n^ <--->\n| dy\n| <------>\n| width\n|\n|\n+ datum (e.g. MSL)\nWith profile_slope = dy / dz. A rectangular profile requires a slope of 0.0.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\nlength > 0\nroughess > 0\nprofile_width >= 0\nprofile_slope >= 0\n(profilewidth == 0) xor (profileslope == 0)\n\nsource\n# Ribasim.Model — Type.\nModel(config_path::AbstractString)\nModel(config::Config)\nInitialize a Model.\nThe Model struct is an initialized model, combined with the Config used to create it and saved results. The Basic Model Interface (BMI) is implemented on the Model. A Model can be created from the path to a TOML configuration file, or a Config object.\nsource\n# Ribasim.NodeMetadata — Type.\nType for storing metadata of nodes in the graph type: type of the node allocationnetworkid: Allocation network ID (0 if not in subnetwork)\nsource\n# Ribasim.OutNeighbors — Type.\nIterate over outgoing neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.Outlet — Type.\nnodeid: node ID of the Outlet node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the outlet maxflowrate: The maximum flow rate of the outlet controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this outlet is governed by PID control\nsource\n# Ribasim.PidControl — Type.\nPID control currently only supports regulating basin levels.\nnodeid: node ID of the PidControl node active: whether this node is active and thus sets flow rates listennodeid: the id of the basin being controlled pidparams: a vector interpolation for parameters changing over time. The parameters are respectively target, proportional, integral, derivative, where the last three are the coefficients for the PID equation. error: the current error; basintarget - currentlevel\nsource\n# Ribasim.Pump — Type.\nnodeid: node ID of the Pump node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the pump maxflowrate: The maximum flow rate of the pump controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this pump is governed by PID control\nsource\n# Ribasim.Subgrid — Type.\nSubgrid linearly interpolates basin levels.\nsource\n# Ribasim.TabulatedRatingCurve — Type.\nstruct TabulatedRatingCurve{C}\nRating curve from level to flow rate. The rating curve is a lookup table with linear interpolation in between. Relation can be updated in time, which is done by moving data from the time field into the tables, which is done in the update_tabulated_rating_curve callback.\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of Vectors or Arrow Primitives, and is added to avoid type instabilities.\nnodeid: node ID of the TabulatedRatingCurve node active: whether this node is active and thus contributes flows tables: The current Q(h) relationships time: The time table used for updating the tables controlmapping: dictionary from (nodeid, controlstate) to Q(h) and/or active state\nsource\n# Ribasim.Terminal — Type.\nnode_id: node ID of the Terminal node\nsource\n# Ribasim.UserDemand — Type.\ndemand: water flux demand of UserDemand per priority over time. Each UserDemand has a demand for all priorities, which is 0.0 if it is not provided explicitly. realizedbmi: Cumulative inflow volume, for read or reset by BMI only. active: whether this node is active and thus demands water allocated: water flux currently allocated to UserDemand per priority returnfactor: the factor in [0,1] of how much of the abstracted water is given back to the system min_level: The level of the source basin below which the UserDemand does not abstract\nsource\n# Ribasim.config.Config — Method.\nConfig(config_path::AbstractString; kwargs...)\nParse a TOML file to a Config. Keys can be overruled using keyword arguments. To overrule keys from a subsection, e.g. dt from the solver section, use underscores: solver_dt.\nsource",
+ "text": "1.2 Types\n# Ribasim.Allocation — Type.\nObject for all information about allocation allocationnetworkids: The unique sorted allocation network IDs allocation models: The allocation models for the main network and subnetworks corresponding to allocationnetworkids mainnetworkconnections: (fromid, toid) from the main network to the subnetwork per subnetwork priorities: All used priority values. subnetworkdemands: The demand of an edge from the main network to a subnetwork recorddemand: A record of demands and allocated flows for nodes that have these. record_flow: A record of all flows computed by allocation optimization, eventually saved to output file\nsource\n# Ribasim.AllocationModel — Type.\nStore information for a subnetwork used for allocation.\nallocationnetworkid: The ID of this allocation network capacity: The capacity per edge of the allocation network, as constrained by nodes that have a maxflowrate problem: The JuMP.jl model for solving the allocation problem Δt_allocation: The time interval between consecutive allocation solves\nsource\n# Ribasim.AllocationModel — Method.\nConstruct the JuMP.jl problem for allocation.\nInputs\nallocationnetworkid: the ID of this allocation network p: Ribasim problem parameters Δt_allocation: The timestep between successive allocation solves\nOutputs\nAn AllocationModel object.\nsource\n# Ribasim.Basin — Type.\nRequirements:\n\nMust be positive: precipitation, evaporation, infiltration, drainage\nIndex points to a Basin\nvolume, area, level must all be positive and monotonic increasing.\n\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of vectors or Arrow Tables, and is added to avoid type instabilities. The nodeid are Indices to support fast lookup of e.g. currentlevel using ID.\nif autodiff T = DiffCache{Vector{Float64}} else T = Vector{Float64} end\nsource\n# Ribasim.DiscreteControl — Type.\nnodeid: node ID of the DiscreteControl node; these are not unique but repeated by the amount of conditions of this DiscreteControl node listennodeid: the ID of the node being condition on variable: the name of the variable in the condition greaterthan: The threshold value in the condition conditionvalue: The current value of each condition controlstate: Dictionary: node ID => (control state, control state start) logic_mapping: Dictionary: (control node ID, truth state) => control state record: Namedtuple with discrete control information for results\nsource\n# Ribasim.EdgeMetadata — Type.\nType for storing metadata of edges in the graph: id: ID of the edge (only used for labeling flow output) type: type of the edge allocationnetworkidsource: ID of allocation network where this edge is a source (0 if not a source) fromid: the node ID of the source node toid: the node ID of the destination node allocationflow: whether this edge has a flow in an allocation network node_ids: if this edge has allocation flow, these are all the nodes from the physical layer this edge consists of\nsource\n# Ribasim.FlatVector — Type.\nstruct FlatVector{T} <: AbstractVector{T}\nA FlatVector is an AbstractVector that iterates the T of a Vector{Vector{T}}.\nEach inner vector is assumed to be of equal length.\nIt is similar to Iterators.flatten, though that doesn’t work with the Tables.Column interface, which needs length and getindex support.\nsource\n# Ribasim.FlowBoundary — Type.\nnodeid: node ID of the FlowBoundary node active: whether this node is active and thus contributes flow flowrate: target flow rate\nsource\n# Ribasim.FractionalFlow — Type.\nRequirements:\n\nfrom: must be (TabulatedRatingCurve,) node\nto: must be (Basin,) node\nfraction must be positive.\n\nnodeid: node ID of the TabulatedRatingCurve node fraction: The fraction in [0,1] of flow the node lets through controlmapping: dictionary from (nodeid, controlstate) to fraction\nsource\n# Ribasim.InNeighbors — Type.\nIterate over incoming neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.LevelBoundary — Type.\nnode_id: node ID of the LevelBoundary node active: whether this node is active level: the fixed level of this ‘infinitely big basin’\nsource\n# Ribasim.LevelDemand — Type.\nnodeid: node ID of the LevelDemand node minlevel: The minimum target level of the connected basin(s) max_level: The maximum target level of the connected basin(s) priority: If in a shortage state, the priority of the demand of the connected basin(s)\nsource\n# Ribasim.LinearResistance — Type.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\n\nnodeid: node ID of the LinearResistance node active: whether this node is active and thus contributes flows resistance: the resistance to flow; Q*unlimited = Δh/resistancemax_flow_rate: the maximum flow rate allowed through the node;Q = clamp(Q*unlimited, -max*flow*rate, max*flow*rate) controlmapping: dictionary from (nodeid, controlstate) to resistance and/or active state\nsource\n# Ribasim.ManningResistance — Type.\nThis is a simple Manning-Gauckler reach connection.\n\nLength describes the reach length.\nroughness describes Manning’s n in (SI units).\n\nThe profile is described by a trapezoid:\n \\ / ^\n \\ / |\n \\ / | dz\nbottom \\______/ |\n^ <--->\n| dy\n| <------>\n| width\n|\n|\n+ datum (e.g. MSL)\nWith profile_slope = dy / dz. A rectangular profile requires a slope of 0.0.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\nlength > 0\nroughess > 0\nprofile_width >= 0\nprofile_slope >= 0\n(profilewidth == 0) xor (profileslope == 0)\n\nsource\n# Ribasim.Model — Type.\nModel(config_path::AbstractString)\nModel(config::Config)\nInitialize a Model.\nThe Model struct is an initialized model, combined with the Config used to create it and saved results. The Basic Model Interface (BMI) is implemented on the Model. A Model can be created from the path to a TOML configuration file, or a Config object.\nsource\n# Ribasim.NodeMetadata — Type.\nType for storing metadata of nodes in the graph type: type of the node allocationnetworkid: Allocation network ID (0 if not in subnetwork)\nsource\n# Ribasim.OutNeighbors — Type.\nIterate over outgoing neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.Outlet — Type.\nnodeid: node ID of the Outlet node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the outlet maxflowrate: The maximum flow rate of the outlet controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this outlet is governed by PID control\nsource\n# Ribasim.PidControl — Type.\nPID control currently only supports regulating basin levels.\nnodeid: node ID of the PidControl node active: whether this node is active and thus sets flow rates listennodeid: the id of the basin being controlled pidparams: a vector interpolation for parameters changing over time. The parameters are respectively target, proportional, integral, derivative, where the last three are the coefficients for the PID equation. error: the current error; basintarget - currentlevel\nsource\n# Ribasim.Pump — Type.\nnodeid: node ID of the Pump node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the pump maxflowrate: The maximum flow rate of the pump controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this pump is governed by PID control\nsource\n# Ribasim.Subgrid — Type.\nSubgrid linearly interpolates basin levels.\nsource\n# Ribasim.TabulatedRatingCurve — Type.\nstruct TabulatedRatingCurve{C}\nRating curve from level to flow rate. The rating curve is a lookup table with linear interpolation in between. Relation can be updated in time, which is done by moving data from the time field into the tables, which is done in the update_tabulated_rating_curve callback.\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of Vectors or Arrow Primitives, and is added to avoid type instabilities.\nnodeid: node ID of the TabulatedRatingCurve node active: whether this node is active and thus contributes flows tables: The current Q(h) relationships time: The time table used for updating the tables controlmapping: dictionary from (nodeid, controlstate) to Q(h) and/or active state\nsource\n# Ribasim.Terminal — Type.\nnode_id: node ID of the Terminal node\nsource\n# Ribasim.UserDemand — Type.\ndemand: water flux demand of UserDemand per priority over time. Each UserDemand has a demand for all priorities, which is 0.0 if it is not provided explicitly. realizedbmi: Cumulative inflow volume, for read or reset by BMI only. active: whether this node is active and thus demands water allocated: water flux currently allocated to UserDemand per priority returnfactor: the factor in [0,1] of how much of the abstracted water is given back to the system min_level: The level of the source basin below which the UserDemand does not abstract\nsource\n# Ribasim.config.Config — Method.\nConfig(config_path::AbstractString; kwargs...)\nParse a TOML file to a Config. Keys can be overruled using keyword arguments. To overrule keys from a subsection, e.g. dt from the solver section, use underscores: solver_dt.\nsource",
"crumbs": [
"Julia core",
"API Reference"
@@ -409,7 +416,7 @@
"href": "build/index.html#functions",
"title": "1 API Reference",
"section": "1.3 Functions",
- "text": "1.3 Functions\n# BasicModelInterface.finalize — Method.\nBMI.finalize(model::Model)::Model\nWrite all results to the configured files.\nsource\n# BasicModelInterface.initialize — Method.\nBMI.initialize(T::Type{Model}, config_path::AbstractString)::Model\nInitialize a Model from the path to the TOML configuration file.\nsource\n# CommonSolve.solve! — Method.\nsolve!(model::Model)::ODESolution\nSolve a Model until the configured endtime.\nsource\n# Ribasim.add_basin_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a basin.\nsource\n# Ribasim.add_constraints_absolute_value! — Method.\nMinimizing |expr| can be achieved by introducing a new variable exprabs and posing the following constraints: exprabs >= expr expr_abs >= -expr\nsource\n# Ribasim.add_constraints_absolute_value_basin! — Method.\nAdd constraints so that variables Fabsbasin act as the absolute value of the expression comparing flow to a basin to its demand.\nsource\n# Ribasim.add_constraints_absolute_value_user_demand! — Method.\nAdd constraints so that variables Fabsuser_demand act as the absolute value of the expression comparing flow to a UserDemand to its demand.\nsource\n# Ribasim.add_constraints_basin_flow! — Method.\nAdd the Basin flow constraints to the allocation problem. The constraint indices are the Basin node IDs.\nConstraint: flow out of basin <= basin capacity\nsource\n# Ribasim.add_constraints_capacity! — Method.\nAdd the flow capacity constraints to the allocation problem. Only finite capacities get a constraint. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over edge <= edge capacity\nsource\n# Ribasim.add_constraints_flow_conservation! — Method.\nAdd the flow conservation constraints to the allocation problem. The constraint indices are UserDemand node IDs.\nConstraint: sum(flows out of node node) == flows into node + flow from storage and vertical fluxes\nsource\n# Ribasim.add_constraints_fractional_flow! — Method.\nAdd the fractional flow constraints to the allocation problem. The constraint indices are allocation edges over a fractional flow node.\nConstraint: flow after fractional_flow node <= fraction * inflow\nsource\n# Ribasim.add_constraints_source! — Method.\nAdd the source constraints to the allocation problem. The actual threshold values will be set before each allocation solve. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over source edge <= source flow in subnetwork\nsource\n# Ribasim.add_constraints_user_demand_returnflow! — Method.\nAdd the UserDemand returnflow constraints to the allocation problem. The constraint indices are UserDemand node IDs.\nConstraint: outflow from userdemand <= return factor inflow to user*demand\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the flow over the edge on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the existing flow over the edge between the given nodes.\nsource\n# Ribasim.add_objective_term! — Function.\nAdd a term to the objective function given by the objective type, depending in the provided flow variable and the associated demand.\nsource\n# Ribasim.add_subnetwork_connections! — Method.\nAdd the edges connecting the main network work to a subnetwork to both the main network and subnetwork allocation network.\nsource\n# Ribasim.add_user_demand_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a UserDemand.\nsource\n# Ribasim.add_variables_absolute_value! — Method.\nCertain allocation distribution types use absolute values in the objective function. Since most optimization packages do not support the absolute value function directly, New variables are introduced that act as the absolute value of an expression by posing the appropriate constraints.\nsource\n# Ribasim.add_variables_basin! — Method.\nAdd the variables for supply/demand of a basin to the problem. The variable indices are the node_ids of the basins in the subnetwork.\nsource\n# Ribasim.add_variables_flow! — Method.\nAdd the flow variables F to the allocation problem. The variable indices are (edgesourceid, edgedstid). Non-negativivity constraints are also immediately added to the flow variables.\nsource\n# Ribasim.adjust_basin_capacities! — Method.\nSet the values of the basin outflows. 2 cases:\n\nBefore the first allocation solve, set the capacities to their full capacity if there is surplus storage;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the capacities.\n\nsource\n# Ribasim.adjust_edge_capacities! — Method.\nSet the values of the edge capacities. 2 cases:\n\nBefore the first allocation solve, set the edge capacities to their full capacity;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the edge capacities.\n\nsource\n# Ribasim.adjust_source_capacities! — Method.\nAdjust the source flows.\nsource\n# Ribasim.all_neighbor_labels_type — Method.\nGet the in- and outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.allocate! — Method.\nUpdate the allocation optimization problem for the given subnetwork with the problem state and flows, solve the allocation problem and assign the results to the UserDemand.\nsource\n# Ribasim.allocation_graph — Method.\nBuild the graph used for the allocation problem.\nsource\n# Ribasim.allocation_graph_used_nodes! — Method.\nFind all nodes in the subnetwork which will be used in the allocation network. Some nodes are skipped to optimize allocation optimization.\nsource\n# Ribasim.allocation_path_exists_in_graph — Method.\nFind out whether a path exists between a start node and end node in the given allocation network.\nsource\n# Ribasim.allocation_problem — Method.\nConstruct the allocation problem for the current subnetwork as a JuMP.jl model.\nsource\n# Ribasim.allocation_table — Method.\nCreate an allocation result table for the saved data\nsource\n# Ribasim.assign_allocations! — Method.\nAssign the allocations to the UserDemand as determined by the solution of the allocation problem.\nsource\n# Ribasim.avoid_using_own_returnflow! — Method.\nRemove allocation UserDemand return flow edges that are upstream of the UserDemand itself.\nsource\n# Ribasim.basin_bottom — Method.\nReturn the bottom elevation of the basin with index i, or nothing if it doesn’t exist\nsource\n# Ribasim.basin_bottoms — Method.\nGet the bottom on both ends of a node. If only one has a bottom, use that for both.\nsource\n# Ribasim.basin_table — Method.\nCreate the basin result table from the saved data\nsource\n# Ribasim.create_callbacks — Method.\nCreate the different callbacks that are used to store results and feed the simulation with new data. The different callbacks are combined to a CallbackSet that goes to the integrator. Returns the CallbackSet and the SavedValues for flow.\nsource\n# Ribasim.create_graph — Method.\nReturn a directed metagraph with data of nodes (NodeMetadata): NodeMetadata\nand data of edges (EdgeMetadata): EdgeMetadata\nsource\n# Ribasim.create_storage_tables — Method.\nRead the Basin / profile table and return all area and level and computed storage values\nsource\n# Ribasim.datetime_since — Method.\ndatetime_since(t::Real, t0::DateTime)::DateTime\nConvert a Real that represents the seconds passed since the simulation start to the nearest DateTime. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.datetimes — Method.\nGet all saved times as a Vector{DateTime}\nsource\n# Ribasim.discrete_control_affect! — Method.\nChange parameters based on the control logic.\nsource\n# Ribasim.discrete_control_affect_downcrossing! — Method.\nAn downcrossing means that a condition (always greater than) becomes false.\nsource\n# Ribasim.discrete_control_affect_upcrossing! — Method.\nAn upcrossing means that a condition (always greater than) becomes true.\nsource\n# Ribasim.discrete_control_condition — Method.\nListens for changes in condition truths.\nsource\n# Ribasim.discrete_control_table — Method.\nCreate a discrete control result table from the saved data\nsource\n# Ribasim.expand_logic_mapping — Method.\nReplace the truth states in the logic mapping which contain wildcards with all possible explicit truth states.\nsource\n# Ribasim.find_allocation_graph_edges! — Method.\nThis loop finds allocation network edges in several ways:\n\nBetween allocation network nodes whose equivalent in the subnetwork are directly connected\nBetween allocation network nodes whose equivalent in the subnetwork are connected with one or more allocation network nodes in between\n\nsource\n# Ribasim.find_subnetwork_connections! — Method.\nFind the edges from the main network to a subnetwork.\nsource\n# Ribasim.findlastgroup — Method.\nFor an element id and a vector of elements ids, get the range of indices of the last consecutive block of id. Returns the empty range 1:0 if id is not in ids.\nsource\n# Ribasim.findsorted — Method.\nFind the index of element x in a sorted collection a. Returns the index of x if it exists, or nothing if it doesn’t. If x occurs more than once, throw an error.\nsource\n# Ribasim.flow_table — Method.\nCreate a flow result table from the saved data\nsource\n# Ribasim.formulate_basins! — Method.\nSmoothly let the evaporation flux go to 0 when at small water depths Currently at less than 0.1 m.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.formulate_flow! — Method.\nConservation of energy for two basins, a and b:\nh_a + v_a^2 / (2 * g) = h_b + v_b^2 / (2 * g) + S_f * L + C / 2 * g * (v_b^2 - v_a^2)\nWhere:\n\nha, hb are the heads at basin a and b.\nva, vb are the velocities at basin a and b.\ng is the gravitational constant.\nS_f is the friction slope.\nC is an expansion or extraction coefficient.\n\nWe assume velocity differences are negligible (va = vb):\nh_a = h_b + S_f * L\nThe friction losses are approximated by the Gauckler-Manning formula:\nQ = A * (1 / n) * R_h^(2/3) * S_f^(1/2)\nWhere:\n\nWhere A is the cross-sectional area.\nV is the cross-sectional average velocity.\nn is the Gauckler-Manning coefficient.\nR_h is the hydraulic radius.\nS_f is the friction slope.\n\nThe hydraulic radius is defined as:\nR_h = A / P\nWhere P is the wetted perimeter.\nThe average of the upstream and downstream water depth is used to compute cross-sectional area and hydraulic radius. This ensures that a basin can receive water after it has gone dry.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.get_area_and_level — Method.\nCompute the area and level of a basin given its storage. Also returns darea/dlevel as it is needed for the Jacobian.\nsource\n# Ribasim.get_basin_capacity — Method.\nGet the capacity of the basin, i.e. the maximum flow that can be abstracted from the basin if it is in a state of surplus storage (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_basin_data — Method.\nGet several variables associated with a basin:\n\nIts current storage\nThe allocation update interval\nThe influx (sum of instantaneous vertical fluxes of the basin)\nThe index of the connected level_demand node (0 if such a node does not exist)\nThe index of the basin\n\nsource\n# Ribasim.get_basin_demand — Method.\nGet the demand of the basin, i.e. how large a flow the basin needs to get to its minimum target level (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_chunk_sizes — Method.\nGet the chunk sizes for DiffCache; differentiation w.r.t. u and t (the latter only if a Rosenbrock algorithm is used).\nsource\n# Ribasim.get_compressor — Method.\nGet the compressor based on the Results section\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given horizontal (selfloop) edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_fractional_flow_connected_basins — Method.\nGet the node type specific indices of the fractional flows and basins, that are consecutively connected to a node of given id.\nsource\n# Ribasim.get_jac_prototype — Method.\nGet a sparse matrix whose sparsity matches the sparsity of the Jacobian of the ODE problem. All nodes are taken into consideration, also the ones that are inactive.\nIn Ribasim the Jacobian is typically sparse because each state only depends on a small number of other states.\nNote: the name ‘prototype’ does not mean this code is a prototype, it comes from the naming convention of this sparsity structure in the differentialequations.jl docs.\nsource\n# Ribasim.get_level — Method.\nGet the current water level of a node ID. The ID can belong to either a Basin or a LevelBoundary. storage: tells ForwardDiff whether this call is for differentiation or not\nsource\n# Ribasim.get_scalar_interpolation — Method.\nLinear interpolation of a scalar with constant extrapolation.\nsource\n# Ribasim.get_storage_from_level — Method.\nGet the storage of a basin from its level.\nsource\n# Ribasim.get_storages_and_levels — Method.\nGet the storage and level of all basins as matrices of nbasin × ntime\nsource\n# Ribasim.get_storages_from_levels — Method.\nCompute the storages of the basins based on the water level of the basins.\nsource\n# Ribasim.get_tstops — Method.\nFrom an iterable of DateTimes, find the times the solver needs to stop\nsource\n# Ribasim.get_value — Method.\nGet a value for a condition. Currently supports getting levels from basins and flows from flow boundaries.\nsource\n# Ribasim.id_index — Method.\nGet the index of an ID in a set of indices.\nsource\n# Ribasim.indicate_allocation_flow! — Method.\nAdd to the edge metadata that the given edge is used for allocation flow. If the edge does not exist, it is created.\nsource\n# Ribasim.inflow_id — Method.\nGet the unique inneighbor over a flow edge.\nsource\n# Ribasim.inflow_ids — Method.\nGet the inneighbors over flow edges.\nsource\n# Ribasim.inflow_ids_allocation — Method.\nGet the inneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.inneighbor_labels_type — Method.\nGet the inneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.inoutflow_ids — Method.\nGet the in- and outneighbors over flow edges.\nsource\n# Ribasim.integrate_flows! — Method.\nIntegrate flows over the last timestep\nsource\n# Ribasim.is_allocation_source — Method.\nFind out whether the given edge is a source for an allocation network.\nsource\n# Ribasim.is_current_module — Method.\nis_current_module(log::LogMessageType)::Bool\nReturns true if the log message is from the current module or a submodule.\n\nSee https://github.com/JuliaLogging/LoggingExtras.jl/blob/d35e7c8cfc197853ee336ace17182e6ed36dca24/src/CompositionalLoggers/earlyfiltered.jl#L39\nfor the information available in log.\nsource\n# Ribasim.is_flow_constraining — Method.\nWhether the given node node is flow constraining by having a maximum flow rate.\nsource\n# Ribasim.is_flow_direction_constraining — Method.\nWhether the given node is flow direction constraining (only in direction of edges).\nsource\n# Ribasim.load_data — Method.\nload_data(db::DB, config::Config, nodetype::Symbol, kind::Symbol)::Union{Table, Query, Nothing}\nLoad data from Arrow files if available, otherwise the database. Returns either an Arrow.Table, SQLite.Query or nothing if the data is not present.\nsource\n# Ribasim.load_structvector — Method.\nload_structvector(db::DB, config::Config, ::Type{T})::StructVector{T}\nLoad data from Arrow files if available, otherwise the database. Always returns a StructVector of the given struct type T, which is empty if the table is not found. This function validates the schema, and enforces the required sort order.\nsource\n# Ribasim.low_storage_factor — Method.\nIf id is a Basin with storage below the threshold, return a reduction factor != 1\nsource\n# Ribasim.main — Method.\nmain(toml_path::AbstractString)::Cint\nmain(ARGS::Vector{String})::Cint\nmain()::Cint\nThis is the main entry point of the application. Performs argument parsing and sets up logging for both terminal and file. Calls Ribasim.run() and handles exceptions to convert to exit codes.\nsource\n# Ribasim.metadata_from_edge — Method.\nGet the metadata of an edge in the graph from an edge of the underlying DiGraph.\nsource\n# Ribasim.nodefields — Method.\nGet all node fieldnames of the parameter object.\nsource\n# Ribasim.nodetype — Method.\nFrom a SchemaVersion(“ribasim.flowboundary.static”, 1) return (:FlowBoundary, :static)\nsource\n# Ribasim.outflow_id — Method.\nGet the unique outneighbor over a flow edge.\nsource\n# Ribasim.outflow_ids — Method.\nGet the outneighbors over flow edges.\nsource\n# Ribasim.outflow_ids_allocation — Method.\nGet the outneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.outneighbor_labels_type — Method.\nGet the outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.parse_static_and_time — Method.\nProcess the data in the static and time tables for a given node type. The ‘defaults’ named tuple dictates how missing data is filled in. ‘time_interpolatables’ is a vector of Symbols of parameter names for which a time interpolation (linear) object must be constructed. The control mapping for DiscreteControl is also constructed in this function. This function currently does not support node states that are defined by more than one row in a table, as is the case for TabulatedRatingCurve.\nsource\n# Ribasim.pkgversion — Method.\nGet the package version of a given module\nsource\n# Ribasim.process_allocation_graph_edges! — Method.\nFor the composite allocation network edges:\n\nFind out whether they are connected to allocation network nodes on both ends\nCompute their capacity\nFind out their allowed flow direction(s)\n\nsource\n# Ribasim.profile_storage — Method.\nCalculate a profile storage by integrating the areas over the levels\nsource\n# Ribasim.qh_interpolation — Method.\nFrom a table with columns nodeid, flowrate (Q) and level (h), create a LinearInterpolation from level to flow rate for a given node_id.\nsource\n# Ribasim.reduction_factor — Method.\nFunction that goes smoothly from 0 to 1 in the interval [0,threshold], and is constant outside this interval.\nsource\n# Ribasim.run — Method.\nrun(config_file::AbstractString)::Model\nrun(config::Config)::Model\nRun a Model, given a path to a TOML configuration file, or a Config object. Running a model includes initialization, solving to the end with [solve!](@ref) and writing results with write_results.\nsource\n# Ribasim.save_allocation_flows! — Method.\nSave the allocation flows per basin and physical edge.\nsource\n# Ribasim.save_demands_and_allocations! — Method.\nSave the demands and allocated flows for UserDemand and Basin. Note: Basin supply (negative demand) is only saved for the first priority.\nsource\n# Ribasim.save_flow — Method.\nCompute the average flows over the last saveat interval and write them to SavedValues\nsource\n# Ribasim.save_subgrid_level — Method.\nInterpolate the levels and save them to SavedValues\nsource\n# Ribasim.scalar_interpolation_derivative — Method.\nDerivative of scalar interpolation.\nsource\n# Ribasim.seconds_since — Method.\nseconds_since(t::DateTime, t0::DateTime)::Float64\nConvert a DateTime to a float that is the number of seconds since the start of the simulation. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.set_current_value! — Method.\nFrom a timeseries table time, load the most recent applicable data into table. table must be a NamedTuple of vectors with all variables that must be loaded. The most recent applicable data is non-NaN data for a given ID that is on or before t.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q over the edge between the given nodes.\nsource\n# Ribasim.set_fractional_flow_in_allocation! — Method.\nUpdate the fractional flow fractions in an allocation problem.\nsource\n# Ribasim.set_initial_discrete_controlled_parameters! — Method.\nSet parameters of nodes that are controlled by DiscreteControl to the values corresponding to the initial state of the model.\nsource\n# Ribasim.set_is_pid_controlled! — Method.\nSet ispidcontrolled to true for those pumps and outlets that are PID controlled\nsource\n# Ribasim.set_objective_priority! — Method.\nSet the objective for the given priority. For an objective with absolute values this also involves adjusting constraints.\nsource\n# Ribasim.set_static_value! — Method.\nLoad data from a source table static into a destination table. Data is matched based on the node_id, which is sorted.\nsource\n# Ribasim.set_table_row! — Method.\nUpdate table at row index i, with the values of a given row. table must be a NamedTuple of vectors with all variables that must be loaded. The row must contain all the column names that are present in the table. If a value is missing, it is not set.\nsource\n# Ribasim.sorted_table! — Method.\nDepending on if a table can be sorted, either sort it or assert that it is sorted.\nTables loaded from the database into memory can be sorted. Tables loaded from Arrow files are memory mapped and can therefore not be sorted.\nsource\n# Ribasim.tsaves — Method.\nGet all saved times in seconds since start\nsource\n# Ribasim.update_allocation! — Method.\nSolve the allocation problem for all demands and assign allocated abstractions.\nsource\n# Ribasim.update_basin — Method.\nLoad updates from ‘Basin / time’ into the parameters\nsource\n# Ribasim.update_jac_prototype! — Method.\nMethod for nodes that do not contribute to the Jacobian\nsource\n# Ribasim.update_jac_prototype! — Method.\nThe controlled basin affects itself and the basins upstream and downstream of the controlled pump affect eachother if there is a basin upstream of the pump. The state for the integral term and the controlled basin affect eachother, and the same for the integral state and the basin upstream of the pump if it is indeed a basin.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the unique node downstream of these nodes are basins, then these directly depend on eachother and affect the Jacobian 2x Basins always depend on themselves.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the nodes down stream (or one node further if a fractional flow is in between) are basins, then the downstream basin depends on the upstream basin(s) and affect the Jacobian as many times as there are downstream basins Upstream basins always depend on themselves.\nsource\n# Ribasim.update_tabulated_rating_curve! — Method.\nLoad updates from ‘TabulatedRatingCurve / time’ into the parameters\nsource\n# Ribasim.valid_discrete_control — Method.\nCheck:\n\nwhether control states are defined for discrete controlled nodes;\nWhether the supplied truth states have the proper length;\nWhether look_ahead is only supplied for condition variables given by a time-series.\n\nsource\n# Ribasim.valid_edge_types — Method.\nCheck that only supported edge types are declared.\nsource\n# Ribasim.valid_edges — Method.\nTest for each node given its node type whether the nodes that\nare downstream (‘down-edge’) of this node are of an allowed type\nsource\n# Ribasim.valid_flow_rates — Method.\nTest whether static or discrete controlled flow rates are indeed non-negative.\nsource\n# Ribasim.valid_fractional_flow — Method.\nCheck that nodes that have fractional flow outneighbors do not have any other type of outneighbor, that the fractions leaving a node add up to ≈1 and that the fractions are non-negative.\nsource\n# Ribasim.valid_n_neighbors — Method.\nTest for each node given its node type whether it has an allowed number of flow/control inneighbors and outneighbors\nsource\n# Ribasim.valid_profiles — Method.\nCheck whether the profile data has no repeats in the levels and the areas start positive.\nsource\n# Ribasim.valid_sources — Method.\nThe source nodes must only have one allocation outneighbor and no allocation inneighbors.\nsource\n# Ribasim.valid_subgrid — Method.\nValidate the entries for a single subgrid element.\nsource\n# Ribasim.water_balance! — Method.\nThe right hand side function of the system of ODEs set up by Ribasim.\nsource\n# Ribasim.write_arrow — Method.\nWrite a result table to disk as an Arrow file\nsource\n# Ribasim.write_results — Method.\nwrite_results(model::Model)::Model\nWrite all results to the Arrow files as specified in the model configuration.\nsource\n# Ribasim.config.algorithm — Method.\nCreate an OrdinaryDiffEqAlgorithm from solver config\nsource\n# Ribasim.config.convert_dt — Method.\nConvert the dt from our Config to SciML stepsize control arguments\nsource\n# Ribasim.config.convert_saveat — Method.\nConvert the saveat Float64 from our Config to SciML’s saveat\nsource\n# Ribasim.config.input_path — Method.\nConstruct a path relative to both the TOML directory and the optional input_dir\nsource\n# Ribasim.config.results_path — Method.\nConstruct a path relative to both the TOML directory and the optional results_dir\nsource\n# Ribasim.config.snake_case — Method.\nConvert a string from CamelCase to snake_case.\nsource",
+ "text": "1.3 Functions\n# BasicModelInterface.finalize — Method.\nBMI.finalize(model::Model)::Model\nWrite all results to the configured files.\nsource\n# BasicModelInterface.initialize — Method.\nBMI.initialize(T::Type{Model}, config_path::AbstractString)::Model\nInitialize a Model from the path to the TOML configuration file.\nsource\n# CommonSolve.solve! — Method.\nsolve!(model::Model)::ODESolution\nSolve a Model until the configured endtime.\nsource\n# Ribasim.add_basin_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a basin.\nsource\n# Ribasim.add_constraints_absolute_value! — Method.\nMinimizing |expr| can be achieved by introducing a new variable exprabs and posing the following constraints: exprabs >= expr expr_abs >= -expr\nsource\n# Ribasim.add_constraints_absolute_value_flow_demand! — Method.\nAdd constraints so that variables Fabsflow_demand act as the absolute value of the expression comparing flow to a flow buffer to the flow demand.\nsource\n# Ribasim.add_constraints_absolute_value_level_demand! — Method.\nAdd constraints so that variables Fabslevel_demand act as the absolute value of the expression comparing flow to a basin to its demand.\nsource\n# Ribasim.add_constraints_absolute_value_user_demand! — Method.\nAdd constraints so that variables Fabsuser_demand act as the absolute value of the expression comparing flow to a UserDemand to its demand.\nsource\n# Ribasim.add_constraints_basin_flow! — Method.\nAdd the Basin flow constraints to the allocation problem. The constraint indices are the Basin node IDs.\nConstraint: flow out of basin <= basin capacity\nsource\n# Ribasim.add_constraints_buffer! — Method.\nAdd the buffer outflow constraints to the allocation problem. The constraint indices are the node IDs of the nodes that have a flow demand.\nConstraint: flow out of buffer <= flow buffer capacity\nsource\n# Ribasim.add_constraints_capacity! — Method.\nAdd the flow capacity constraints to the allocation problem. Only finite capacities get a constraint. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over edge <= edge capacity\nsource\n# Ribasim.add_constraints_conservation_basin! — Method.\nAdd the basin flow conservation constraints to the allocation problem. The constraint indices are Basin node IDs.\nConstraint: sum(flows out of basin) == sum(flows into basin) + flow from storage and vertical fluxes\nsource\n# Ribasim.add_constraints_conservation_flow_demand! — Method.\nAdd the conservation constraints for connector nodes with a flow demand to the allocation problem. The constraint indices are node IDs of the nodes with the flow demand (so not the IDs of the FlowDemand nodes).\nConstraint: flow into node + flow out of buffer = flow out of node + flow into buffer\nsource\n# Ribasim.add_constraints_conservation_subnetwork! — Method.\nAdd the subnetwork inlet flow conservation constraints to the allocation problem. The constraint indices are node IDs subnetwork inlet edge dst IDs.\nConstraint: sum(flows into node) == sum(flows out of node)\nsource\n# Ribasim.add_constraints_flow_demand_outflow! — Method.\nAdd the flow demand node outflow constraints to the allocation problem. The constraint indices are the node IDs of the nodes that have a flow demand.\nConstraint: flow out of node with flow demand <= ∞ if not at flow demand priority, 0.0 otherwise\nsource\n# Ribasim.add_constraints_fractional_flow! — Method.\nAdd the fractional flow constraints to the allocation problem. The constraint indices are allocation edges over a fractional flow node.\nConstraint: flow after fractional_flow node <= fraction * inflow\nsource\n# Ribasim.add_constraints_source! — Method.\nAdd the source constraints to the allocation problem. The actual threshold values will be set before each allocation solve. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over source edge <= source flow in subnetwork\nsource\n# Ribasim.add_constraints_user_demand_returnflow! — Method.\nAdd the UserDemand returnflow constraints to the allocation problem. The constraint indices are UserDemand node IDs. Constraint: outflow from userdemand <= return factor inflow to user*demand\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the flow over the edge on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the existing flow over the edge between the given nodes.\nsource\n# Ribasim.add_flow_demand_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a node with a a flow demand.\nsource\n# Ribasim.add_objective_term! — Function.\nAdd a term to the objective function given by the objective type, depending in the provided flow variable and the associated demand.\nsource\n# Ribasim.add_subnetwork_connections! — Method.\nAdd the edges connecting the main network work to a subnetwork to both the main network and subnetwork allocation network.\nsource\n# Ribasim.add_user_demand_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a UserDemand.\nsource\n# Ribasim.add_variables_absolute_value! — Method.\nCertain allocation distribution types use absolute values in the objective function. Since most optimization packages do not support the absolute value function directly, New variables are introduced that act as the absolute value of an expression by posing the appropriate constraints.\nsource\n# Ribasim.add_variables_basin! — Method.\nAdd the variables for supply/demand of a basin to the problem. The variable indices are the node_ids of the basins with a level demand in the subnetwork.\nsource\n# Ribasim.add_variables_flow! — Method.\nAdd the flow variables F to the allocation problem. The variable indices are (edgesourceid, edgedstid). Non-negativivity constraints are also immediately added to the flow variables.\nsource\n# Ribasim.add_variables_flow_buffer! — Method.\nAdd the variables for supply/demand of a node with a flow demand to the problem. The variable indices are the node_ids of the nodes with a flow demand in the subnetwork.\nsource\n# Ribasim.adjust_capacities_basin! — Method.\nSet the capacities of the basin outflows. 2 cases:\n\nBefore the first allocation solve, set the capacities to their full capacity if there is surplus storage;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the capacities.\n\nsource\n# Ribasim.adjust_capacities_buffers! — Method.\nAdjust the capacities of the flow buffers of nodes with a flow demand. 2 cases:\n\nBefore the first allocation solve, set the capacities to 0.0;\nBefore an allocation solve, add the flow into the buffer and remove the flow out of the buffer from the buffer capacity.\n\nsource\n# Ribasim.adjust_capacities_edge! — Method.\nSet the values of the edge capacities. 2 cases:\n\nBefore the first allocation solve, set the edge capacities to their full capacity;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the edge capacities.\n\nsource\n# Ribasim.adjust_capacities_flow_demand_outflow! — Method.\nSet the capacity of the outflow edge from a node with a flow demand:\n\nTo Inf if the current priority is other than the priority of the flow demand\nTo 0.0 if the current priority is equal to the priority of the flow demand\n\nsource\n# Ribasim.adjust_capacities_source! — Method.\nAdjust the source flows.\nsource\n# Ribasim.adjust_demands_flow! — Method.\nSet the demand of the flow demand nodes. 2 cases:\n\nBefore the first allocation solve, set the demands to their full value;\nBefore an allocation solve, subtract the flow trough the node with a flow demand from the total flow demand (which will be used at the priority of the flow demand only).\n\nsource\n# Ribasim.all_neighbor_labels_type — Method.\nGet the in- and outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.allocate! — Method.\nUpdate the allocation optimization problem for the given subnetwork with the problem state and flows, solve the allocation problem and assign the results to the UserDemand.\nsource\n# Ribasim.allocation_graph — Method.\nBuild the graph used for the allocation problem.\nsource\n# Ribasim.allocation_graph_used_nodes! — Method.\nFind all nodes in the subnetwork which will be used in the allocation network. Some nodes are skipped to optimize allocation optimization.\nsource\n# Ribasim.allocation_path_exists_in_graph — Method.\nFind out whether a path exists between a start node and end node in the given allocation network.\nsource\n# Ribasim.allocation_problem — Method.\nConstruct the allocation problem for the current subnetwork as a JuMP.jl model.\nsource\n# Ribasim.allocation_table — Method.\nCreate an allocation result table for the saved data\nsource\n# Ribasim.assign_allocations! — Method.\nAssign the allocations to the UserDemand as determined by the solution of the allocation problem.\nsource\n# Ribasim.avoid_using_own_returnflow! — Method.\nRemove allocation UserDemand return flow edges that are upstream of the UserDemand itself.\nsource\n# Ribasim.basin_bottom — Method.\nReturn the bottom elevation of the basin with index i, or nothing if it doesn’t exist\nsource\n# Ribasim.basin_bottoms — Method.\nGet the bottom on both ends of a node. If only one has a bottom, use that for both.\nsource\n# Ribasim.basin_table — Method.\nCreate the basin result table from the saved data\nsource\n# Ribasim.create_callbacks — Method.\nCreate the different callbacks that are used to store results and feed the simulation with new data. The different callbacks are combined to a CallbackSet that goes to the integrator. Returns the CallbackSet and the SavedValues for flow.\nsource\n# Ribasim.create_graph — Method.\nReturn a directed metagraph with data of nodes (NodeMetadata): NodeMetadata\nand data of edges (EdgeMetadata): EdgeMetadata\nsource\n# Ribasim.create_storage_tables — Method.\nRead the Basin / profile table and return all area and level and computed storage values\nsource\n# Ribasim.datetime_since — Method.\ndatetime_since(t::Real, t0::DateTime)::DateTime\nConvert a Real that represents the seconds passed since the simulation start to the nearest DateTime. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.datetimes — Method.\nGet all saved times as a Vector{DateTime}\nsource\n# Ribasim.discrete_control_affect! — Method.\nChange parameters based on the control logic.\nsource\n# Ribasim.discrete_control_affect_downcrossing! — Method.\nAn downcrossing means that a condition (always greater than) becomes false.\nsource\n# Ribasim.discrete_control_affect_upcrossing! — Method.\nAn upcrossing means that a condition (always greater than) becomes true.\nsource\n# Ribasim.discrete_control_condition — Method.\nListens for changes in condition truths.\nsource\n# Ribasim.discrete_control_table — Method.\nCreate a discrete control result table from the saved data\nsource\n# Ribasim.expand_logic_mapping — Method.\nReplace the truth states in the logic mapping which contain wildcards with all possible explicit truth states.\nsource\n# Ribasim.find_allocation_graph_edges! — Method.\nThis loop finds allocation network edges in several ways:\n\nBetween allocation network nodes whose equivalent in the subnetwork are directly connected\nBetween allocation network nodes whose equivalent in the subnetwork are connected with one or more allocation network nodes in between\n\nsource\n# Ribasim.find_subnetwork_connections! — Method.\nFind the edges from the main network to a subnetwork.\nsource\n# Ribasim.findlastgroup — Method.\nFor an element id and a vector of elements ids, get the range of indices of the last consecutive block of id. Returns the empty range 1:0 if id is not in ids.\nsource\n# Ribasim.findsorted — Method.\nFind the index of element x in a sorted collection a. Returns the index of x if it exists, or nothing if it doesn’t. If x occurs more than once, throw an error.\nsource\n# Ribasim.flow_table — Method.\nCreate a flow result table from the saved data\nsource\n# Ribasim.formulate_basins! — Method.\nSmoothly let the evaporation flux go to 0 when at small water depths Currently at less than 0.1 m.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.formulate_flow! — Method.\nConservation of energy for two basins, a and b:\nh_a + v_a^2 / (2 * g) = h_b + v_b^2 / (2 * g) + S_f * L + C / 2 * g * (v_b^2 - v_a^2)\nWhere:\n\nha, hb are the heads at basin a and b.\nva, vb are the velocities at basin a and b.\ng is the gravitational constant.\nS_f is the friction slope.\nC is an expansion or extraction coefficient.\n\nWe assume velocity differences are negligible (va = vb):\nh_a = h_b + S_f * L\nThe friction losses are approximated by the Gauckler-Manning formula:\nQ = A * (1 / n) * R_h^(2/3) * S_f^(1/2)\nWhere:\n\nWhere A is the cross-sectional area.\nV is the cross-sectional average velocity.\nn is the Gauckler-Manning coefficient.\nR_h is the hydraulic radius.\nS_f is the friction slope.\n\nThe hydraulic radius is defined as:\nR_h = A / P\nWhere P is the wetted perimeter.\nThe average of the upstream and downstream water depth is used to compute cross-sectional area and hydraulic radius. This ensures that a basin can receive water after it has gone dry.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.get_area_and_level — Method.\nCompute the area and level of a basin given its storage. Also returns darea/dlevel as it is needed for the Jacobian.\nsource\n# Ribasim.get_basin_capacity — Method.\nGet the capacity of the basin, i.e. the maximum flow that can be abstracted from the basin if it is in a state of surplus storage (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_basin_data — Method.\nGet several variables associated with a basin:\n\nIts current storage\nThe allocation update interval\nThe influx (sum of instantaneous vertical fluxes of the basin)\nThe index of the connected level_demand node (0 if such a node does not exist)\nThe index of the basin\n\nsource\n# Ribasim.get_basin_demand — Method.\nGet the demand of the basin, i.e. how large a flow the basin needs to get to its minimum target level (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_chunk_sizes — Method.\nGet the chunk sizes for DiffCache; differentiation w.r.t. u and t (the latter only if a Rosenbrock algorithm is used).\nsource\n# Ribasim.get_compressor — Method.\nGet the compressor based on the Results section\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given horizontal (selfloop) edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_fractional_flow_connected_basins — Method.\nGet the node type specific indices of the fractional flows and basins, that are consecutively connected to a node of given id.\nsource\n# Ribasim.get_jac_prototype — Method.\nGet a sparse matrix whose sparsity matches the sparsity of the Jacobian of the ODE problem. All nodes are taken into consideration, also the ones that are inactive.\nIn Ribasim the Jacobian is typically sparse because each state only depends on a small number of other states.\nNote: the name ‘prototype’ does not mean this code is a prototype, it comes from the naming convention of this sparsity structure in the differentialequations.jl docs.\nsource\n# Ribasim.get_level — Method.\nGet the current water level of a node ID. The ID can belong to either a Basin or a LevelBoundary. storage: tells ForwardDiff whether this call is for differentiation or not\nsource\n# Ribasim.get_scalar_interpolation — Method.\nLinear interpolation of a scalar with constant extrapolation.\nsource\n# Ribasim.get_storage_from_level — Method.\nGet the storage of a basin from its level.\nsource\n# Ribasim.get_storages_and_levels — Method.\nGet the storage and level of all basins as matrices of nbasin × ntime\nsource\n# Ribasim.get_storages_from_levels — Method.\nCompute the storages of the basins based on the water level of the basins.\nsource\n# Ribasim.get_tstops — Method.\nFrom an iterable of DateTimes, find the times the solver needs to stop\nsource\n# Ribasim.get_value — Method.\nGet a value for a condition. Currently supports getting levels from basins and flows from flow boundaries.\nsource\n# Ribasim.id_index — Method.\nGet the index of an ID in a set of indices.\nsource\n# Ribasim.indicate_allocation_flow! — Method.\nAdd to the edge metadata that the given edge is used for allocation flow. If the edge does not exist, it is created.\nsource\n# Ribasim.inflow_id — Method.\nGet the unique inneighbor over a flow edge.\nsource\n# Ribasim.inflow_ids — Method.\nGet the inneighbors over flow edges.\nsource\n# Ribasim.inflow_ids_allocation — Method.\nGet the inneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.inneighbor_labels_type — Method.\nGet the inneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.inoutflow_ids — Method.\nGet the in- and outneighbors over flow edges.\nsource\n# Ribasim.integrate_flows! — Method.\nIntegrate flows over the last timestep\nsource\n# Ribasim.is_allocation_source — Method.\nFind out whether the given edge is a source for an allocation network.\nsource\n# Ribasim.is_current_module — Method.\nis_current_module(log::LogMessageType)::Bool\nReturns true if the log message is from the current module or a submodule.\n\nSee https://github.com/JuliaLogging/LoggingExtras.jl/blob/d35e7c8cfc197853ee336ace17182e6ed36dca24/src/CompositionalLoggers/earlyfiltered.jl#L39\nfor the information available in log.\nsource\n# Ribasim.is_flow_constraining — Method.\nWhether the given node node is flow constraining by having a maximum flow rate.\nsource\n# Ribasim.is_flow_direction_constraining — Method.\nWhether the given node is flow direction constraining (only in direction of edges).\nsource\n# Ribasim.load_data — Method.\nload_data(db::DB, config::Config, nodetype::Symbol, kind::Symbol)::Union{Table, Query, Nothing}\nLoad data from Arrow files if available, otherwise the database. Returns either an Arrow.Table, SQLite.Query or nothing if the data is not present.\nsource\n# Ribasim.load_structvector — Method.\nload_structvector(db::DB, config::Config, ::Type{T})::StructVector{T}\nLoad data from Arrow files if available, otherwise the database. Always returns a StructVector of the given struct type T, which is empty if the table is not found. This function validates the schema, and enforces the required sort order.\nsource\n# Ribasim.low_storage_factor — Method.\nIf id is a Basin with storage below the threshold, return a reduction factor != 1\nsource\n# Ribasim.main — Method.\nmain(toml_path::AbstractString)::Cint\nmain(ARGS::Vector{String})::Cint\nmain()::Cint\nThis is the main entry point of the application. Performs argument parsing and sets up logging for both terminal and file. Calls Ribasim.run() and handles exceptions to convert to exit codes.\nsource\n# Ribasim.metadata_from_edge — Method.\nGet the metadata of an edge in the graph from an edge of the underlying DiGraph.\nsource\n# Ribasim.nodefields — Method.\nGet all node fieldnames of the parameter object.\nsource\n# Ribasim.nodetype — Method.\nFrom a SchemaVersion(“ribasim.flowboundary.static”, 1) return (:FlowBoundary, :static)\nsource\n# Ribasim.outflow_id — Method.\nGet the unique outneighbor over a flow edge.\nsource\n# Ribasim.outflow_ids — Method.\nGet the outneighbors over flow edges.\nsource\n# Ribasim.outflow_ids_allocation — Method.\nGet the outneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.outneighbor_labels_type — Method.\nGet the outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.parse_static_and_time — Method.\nProcess the data in the static and time tables for a given node type. The ‘defaults’ named tuple dictates how missing data is filled in. ‘time_interpolatables’ is a vector of Symbols of parameter names for which a time interpolation (linear) object must be constructed. The control mapping for DiscreteControl is also constructed in this function. This function currently does not support node states that are defined by more than one row in a table, as is the case for TabulatedRatingCurve.\nsource\n# Ribasim.pkgversion — Method.\nGet the package version of a given module\nsource\n# Ribasim.process_allocation_graph_edges! — Method.\nFor the composite allocation network edges:\n\nFind out whether they are connected to allocation network nodes on both ends\nCompute their capacity\nFind out their allowed flow direction(s)\n\nsource\n# Ribasim.profile_storage — Method.\nCalculate a profile storage by integrating the areas over the levels\nsource\n# Ribasim.qh_interpolation — Method.\nFrom a table with columns nodeid, flowrate (Q) and level (h), create a LinearInterpolation from level to flow rate for a given node_id.\nsource\n# Ribasim.reduction_factor — Method.\nFunction that goes smoothly from 0 to 1 in the interval [0,threshold], and is constant outside this interval.\nsource\n# Ribasim.run — Method.\nrun(config_file::AbstractString)::Model\nrun(config::Config)::Model\nRun a Model, given a path to a TOML configuration file, or a Config object. Running a model includes initialization, solving to the end with [solve!](@ref) and writing results with write_results.\nsource\n# Ribasim.save_allocation_flows! — Method.\nSave the allocation flows per basin and physical edge.\nsource\n# Ribasim.save_demands_and_allocations! — Method.\nSave the demands and allocated flows for UserDemand and Basin. Note: Basin supply (negative demand) is only saved for the first priority.\nsource\n# Ribasim.save_flow — Method.\nCompute the average flows over the last saveat interval and write them to SavedValues\nsource\n# Ribasim.save_subgrid_level — Method.\nInterpolate the levels and save them to SavedValues\nsource\n# Ribasim.scalar_interpolation_derivative — Method.\nDerivative of scalar interpolation.\nsource\n# Ribasim.seconds_since — Method.\nseconds_since(t::DateTime, t0::DateTime)::Float64\nConvert a DateTime to a float that is the number of seconds since the start of the simulation. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.set_current_value! — Method.\nFrom a timeseries table time, load the most recent applicable data into table. table must be a NamedTuple of vectors with all variables that must be loaded. The most recent applicable data is non-NaN data for a given ID that is on or before t.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q over the edge between the given nodes.\nsource\n# Ribasim.set_fractional_flow_in_allocation! — Method.\nUpdate the fractional flow fractions in an allocation problem.\nsource\n# Ribasim.set_initial_discrete_controlled_parameters! — Method.\nSet parameters of nodes that are controlled by DiscreteControl to the values corresponding to the initial state of the model.\nsource\n# Ribasim.set_is_pid_controlled! — Method.\nSet ispidcontrolled to true for those pumps and outlets that are PID controlled\nsource\n# Ribasim.set_objective_priority! — Method.\nSet the objective for the given priority. For an objective with absolute values this also involves adjusting constraints.\nsource\n# Ribasim.set_static_value! — Method.\nLoad data from a source table static into a destination table. Data is matched based on the node_id, which is sorted.\nsource\n# Ribasim.set_table_row! — Method.\nUpdate table at row index i, with the values of a given row. table must be a NamedTuple of vectors with all variables that must be loaded. The row must contain all the column names that are present in the table. If a value is missing, it is not set.\nsource\n# Ribasim.sorted_table! — Method.\nDepending on if a table can be sorted, either sort it or assert that it is sorted.\nTables loaded from the database into memory can be sorted. Tables loaded from Arrow files are memory mapped and can therefore not be sorted.\nsource\n# Ribasim.tsaves — Method.\nGet all saved times in seconds since start\nsource\n# Ribasim.update_allocation! — Method.\nSolve the allocation problem for all demands and assign allocated abstractions.\nsource\n# Ribasim.update_basin — Method.\nLoad updates from ‘Basin / time’ into the parameters\nsource\n# Ribasim.update_jac_prototype! — Method.\nMethod for nodes that do not contribute to the Jacobian\nsource\n# Ribasim.update_jac_prototype! — Method.\nThe controlled basin affects itself and the basins upstream and downstream of the controlled pump affect eachother if there is a basin upstream of the pump. The state for the integral term and the controlled basin affect eachother, and the same for the integral state and the basin upstream of the pump if it is indeed a basin.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the unique node downstream of these nodes are basins, then these directly depend on eachother and affect the Jacobian 2x Basins always depend on themselves.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the nodes down stream (or one node further if a fractional flow is in between) are basins, then the downstream basin depends on the upstream basin(s) and affect the Jacobian as many times as there are downstream basins Upstream basins always depend on themselves.\nsource\n# Ribasim.update_tabulated_rating_curve! — Method.\nLoad updates from ‘TabulatedRatingCurve / time’ into the parameters\nsource\n# Ribasim.valid_discrete_control — Method.\nCheck:\n\nwhether control states are defined for discrete controlled nodes;\nWhether the supplied truth states have the proper length;\nWhether look_ahead is only supplied for condition variables given by a time-series.\n\nsource\n# Ribasim.valid_edge_types — Method.\nCheck that only supported edge types are declared.\nsource\n# Ribasim.valid_edges — Method.\nTest for each node given its node type whether the nodes that\nare downstream (‘down-edge’) of this node are of an allowed type\nsource\n# Ribasim.valid_flow_rates — Method.\nTest whether static or discrete controlled flow rates are indeed non-negative.\nsource\n# Ribasim.valid_fractional_flow — Method.\nCheck that nodes that have fractional flow outneighbors do not have any other type of outneighbor, that the fractions leaving a node add up to ≈1 and that the fractions are non-negative.\nsource\n# Ribasim.valid_n_neighbors — Method.\nTest for each node given its node type whether it has an allowed number of flow/control inneighbors and outneighbors\nsource\n# Ribasim.valid_profiles — Method.\nCheck whether the profile data has no repeats in the levels and the areas start positive.\nsource\n# Ribasim.valid_sources — Method.\nThe source nodes must only have one allocation outneighbor and no allocation inneighbors.\nsource\n# Ribasim.valid_subgrid — Method.\nValidate the entries for a single subgrid element.\nsource\n# Ribasim.water_balance! — Method.\nThe right hand side function of the system of ODEs set up by Ribasim.\nsource\n# Ribasim.write_arrow — Method.\nWrite a result table to disk as an Arrow file\nsource\n# Ribasim.write_results — Method.\nwrite_results(model::Model)::Model\nWrite all results to the Arrow files as specified in the model configuration.\nsource\n# Ribasim.config.algorithm — Method.\nCreate an OrdinaryDiffEqAlgorithm from solver config\nsource\n# Ribasim.config.convert_dt — Method.\nConvert the dt from our Config to SciML stepsize control arguments\nsource\n# Ribasim.config.convert_saveat — Method.\nConvert the saveat Float64 from our Config to SciML’s saveat\nsource\n# Ribasim.config.input_path — Method.\nConstruct a path relative to both the TOML directory and the optional input_dir\nsource\n# Ribasim.config.results_path — Method.\nConstruct a path relative to both the TOML directory and the optional results_dir\nsource\n# Ribasim.config.snake_case — Method.\nConvert a string from CamelCase to snake_case.\nsource",
"crumbs": [
"Julia core",
"API Reference"
@@ -442,7 +449,7 @@
"href": "build/index.html#index",
"title": "1 API Reference",
"section": "1.6 Index",
- "text": "1.6 Index\n\nRibasim.Ribasim\nRibasim.config\nRibasim.config.algorithms\nRibasim.Allocation\nRibasim.AllocationModel\nRibasim.AllocationModel\nRibasim.Basin\nRibasim.DiscreteControl\nRibasim.EdgeMetadata\nRibasim.FlatVector\nRibasim.FlowBoundary\nRibasim.FractionalFlow\nRibasim.InNeighbors\nRibasim.LevelBoundary\nRibasim.LevelDemand\nRibasim.LinearResistance\nRibasim.ManningResistance\nRibasim.Model\nRibasim.NodeMetadata\nRibasim.OutNeighbors\nRibasim.Outlet\nRibasim.PidControl\nRibasim.Pump\nRibasim.Subgrid\nRibasim.TabulatedRatingCurve\nRibasim.Terminal\nRibasim.UserDemand\nRibasim.config.Config\nBasicModelInterface.finalize\nBasicModelInterface.initialize\nCommonSolve.solve!\nRibasim.add_basin_term!\nRibasim.add_constraints_absolute_value!\nRibasim.add_constraints_absolute_value_basin!\nRibasim.add_constraints_absolute_value_user_demand!\nRibasim.add_constraints_basin_flow!\nRibasim.add_constraints_capacity!\nRibasim.add_constraints_flow_conservation!\nRibasim.add_constraints_fractional_flow!\nRibasim.add_constraints_source!\nRibasim.add_constraints_user_demand_returnflow!\nRibasim.add_flow!\nRibasim.add_flow!\nRibasim.add_objective_term!\nRibasim.add_subnetwork_connections!\nRibasim.add_user_demand_term!\nRibasim.add_variables_absolute_value!\nRibasim.add_variables_basin!\nRibasim.add_variables_flow!\nRibasim.adjust_basin_capacities!\nRibasim.adjust_edge_capacities!\nRibasim.adjust_source_capacities!\nRibasim.all_neighbor_labels_type\nRibasim.allocate!\nRibasim.allocation_graph\nRibasim.allocation_graph_used_nodes!\nRibasim.allocation_path_exists_in_graph\nRibasim.allocation_problem\nRibasim.allocation_table\nRibasim.assign_allocations!\nRibasim.avoid_using_own_returnflow!\nRibasim.basin_bottom\nRibasim.basin_bottoms\nRibasim.basin_table\nRibasim.config.algorithm\nRibasim.config.convert_dt\nRibasim.config.convert_saveat\nRibasim.config.input_path\nRibasim.config.results_path\nRibasim.config.snake_case\nRibasim.create_callbacks\nRibasim.create_graph\nRibasim.create_storage_tables\nRibasim.datetime_since\nRibasim.datetimes\nRibasim.discrete_control_affect!\nRibasim.discrete_control_affect_downcrossing!\nRibasim.discrete_control_affect_upcrossing!\nRibasim.discrete_control_condition\nRibasim.discrete_control_table\nRibasim.expand_logic_mapping\nRibasim.find_allocation_graph_edges!\nRibasim.find_subnetwork_connections!\nRibasim.findlastgroup\nRibasim.findsorted\nRibasim.flow_table\nRibasim.formulate_basins!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.get_area_and_level\nRibasim.get_basin_capacity\nRibasim.get_basin_data\nRibasim.get_basin_demand\nRibasim.get_chunk_sizes\nRibasim.get_compressor\nRibasim.get_flow\nRibasim.get_flow\nRibasim.get_fractional_flow_connected_basins\nRibasim.get_jac_prototype\nRibasim.get_level\nRibasim.get_scalar_interpolation\nRibasim.get_storage_from_level\nRibasim.get_storages_and_levels\nRibasim.get_storages_from_levels\nRibasim.get_tstops\nRibasim.get_value\nRibasim.id_index\nRibasim.indicate_allocation_flow!\nRibasim.inflow_id\nRibasim.inflow_ids\nRibasim.inflow_ids_allocation\nRibasim.inneighbor_labels_type\nRibasim.inoutflow_ids\nRibasim.integrate_flows!\nRibasim.is_allocation_source\nRibasim.is_current_module\nRibasim.is_flow_constraining\nRibasim.is_flow_direction_constraining\nRibasim.load_data\nRibasim.load_structvector\nRibasim.low_storage_factor\nRibasim.main\nRibasim.metadata_from_edge\nRibasim.nodefields\nRibasim.nodetype\nRibasim.outflow_id\nRibasim.outflow_ids\nRibasim.outflow_ids_allocation\nRibasim.outneighbor_labels_type\nRibasim.parse_static_and_time\nRibasim.pkgversion\nRibasim.process_allocation_graph_edges!\nRibasim.profile_storage\nRibasim.qh_interpolation\nRibasim.reduction_factor\nRibasim.run\nRibasim.save_allocation_flows!\nRibasim.save_demands_and_allocations!\nRibasim.save_flow\nRibasim.save_subgrid_level\nRibasim.scalar_interpolation_derivative\nRibasim.seconds_since\nRibasim.set_current_value!\nRibasim.set_flow!\nRibasim.set_flow!\nRibasim.set_fractional_flow_in_allocation!\nRibasim.set_initial_discrete_controlled_parameters!\nRibasim.set_is_pid_controlled!\nRibasim.set_objective_priority!\nRibasim.set_static_value!\nRibasim.set_table_row!\nRibasim.sorted_table!\nRibasim.tsaves\nRibasim.update_allocation!\nRibasim.update_basin\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_tabulated_rating_curve!\nRibasim.valid_discrete_control\nRibasim.valid_edge_types\nRibasim.valid_edges\nRibasim.valid_flow_rates\nRibasim.valid_fractional_flow\nRibasim.valid_n_neighbors\nRibasim.valid_profiles\nRibasim.valid_sources\nRibasim.valid_subgrid\nRibasim.water_balance!\nRibasim.write_arrow\nRibasim.write_results\nRibasim.config.@addfields\nRibasim.config.@addnodetypes",
+ "text": "1.6 Index\n\nRibasim.Ribasim\nRibasim.config\nRibasim.config.algorithms\nRibasim.Allocation\nRibasim.AllocationModel\nRibasim.AllocationModel\nRibasim.Basin\nRibasim.DiscreteControl\nRibasim.EdgeMetadata\nRibasim.FlatVector\nRibasim.FlowBoundary\nRibasim.FractionalFlow\nRibasim.InNeighbors\nRibasim.LevelBoundary\nRibasim.LevelDemand\nRibasim.LinearResistance\nRibasim.ManningResistance\nRibasim.Model\nRibasim.NodeMetadata\nRibasim.OutNeighbors\nRibasim.Outlet\nRibasim.PidControl\nRibasim.Pump\nRibasim.Subgrid\nRibasim.TabulatedRatingCurve\nRibasim.Terminal\nRibasim.UserDemand\nRibasim.config.Config\nBasicModelInterface.finalize\nBasicModelInterface.initialize\nCommonSolve.solve!\nRibasim.add_basin_term!\nRibasim.add_constraints_absolute_value!\nRibasim.add_constraints_absolute_value_flow_demand!\nRibasim.add_constraints_absolute_value_level_demand!\nRibasim.add_constraints_absolute_value_user_demand!\nRibasim.add_constraints_basin_flow!\nRibasim.add_constraints_buffer!\nRibasim.add_constraints_capacity!\nRibasim.add_constraints_conservation_basin!\nRibasim.add_constraints_conservation_flow_demand!\nRibasim.add_constraints_conservation_subnetwork!\nRibasim.add_constraints_flow_demand_outflow!\nRibasim.add_constraints_fractional_flow!\nRibasim.add_constraints_source!\nRibasim.add_constraints_user_demand_returnflow!\nRibasim.add_flow!\nRibasim.add_flow!\nRibasim.add_flow_demand_term!\nRibasim.add_objective_term!\nRibasim.add_subnetwork_connections!\nRibasim.add_user_demand_term!\nRibasim.add_variables_absolute_value!\nRibasim.add_variables_basin!\nRibasim.add_variables_flow!\nRibasim.add_variables_flow_buffer!\nRibasim.adjust_capacities_basin!\nRibasim.adjust_capacities_buffers!\nRibasim.adjust_capacities_edge!\nRibasim.adjust_capacities_flow_demand_outflow!\nRibasim.adjust_capacities_source!\nRibasim.adjust_demands_flow!\nRibasim.all_neighbor_labels_type\nRibasim.allocate!\nRibasim.allocation_graph\nRibasim.allocation_graph_used_nodes!\nRibasim.allocation_path_exists_in_graph\nRibasim.allocation_problem\nRibasim.allocation_table\nRibasim.assign_allocations!\nRibasim.avoid_using_own_returnflow!\nRibasim.basin_bottom\nRibasim.basin_bottoms\nRibasim.basin_table\nRibasim.config.algorithm\nRibasim.config.convert_dt\nRibasim.config.convert_saveat\nRibasim.config.input_path\nRibasim.config.results_path\nRibasim.config.snake_case\nRibasim.create_callbacks\nRibasim.create_graph\nRibasim.create_storage_tables\nRibasim.datetime_since\nRibasim.datetimes\nRibasim.discrete_control_affect!\nRibasim.discrete_control_affect_downcrossing!\nRibasim.discrete_control_affect_upcrossing!\nRibasim.discrete_control_condition\nRibasim.discrete_control_table\nRibasim.expand_logic_mapping\nRibasim.find_allocation_graph_edges!\nRibasim.find_subnetwork_connections!\nRibasim.findlastgroup\nRibasim.findsorted\nRibasim.flow_table\nRibasim.formulate_basins!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.get_area_and_level\nRibasim.get_basin_capacity\nRibasim.get_basin_data\nRibasim.get_basin_demand\nRibasim.get_chunk_sizes\nRibasim.get_compressor\nRibasim.get_flow\nRibasim.get_flow\nRibasim.get_fractional_flow_connected_basins\nRibasim.get_jac_prototype\nRibasim.get_level\nRibasim.get_scalar_interpolation\nRibasim.get_storage_from_level\nRibasim.get_storages_and_levels\nRibasim.get_storages_from_levels\nRibasim.get_tstops\nRibasim.get_value\nRibasim.id_index\nRibasim.indicate_allocation_flow!\nRibasim.inflow_id\nRibasim.inflow_ids\nRibasim.inflow_ids_allocation\nRibasim.inneighbor_labels_type\nRibasim.inoutflow_ids\nRibasim.integrate_flows!\nRibasim.is_allocation_source\nRibasim.is_current_module\nRibasim.is_flow_constraining\nRibasim.is_flow_direction_constraining\nRibasim.load_data\nRibasim.load_structvector\nRibasim.low_storage_factor\nRibasim.main\nRibasim.metadata_from_edge\nRibasim.nodefields\nRibasim.nodetype\nRibasim.outflow_id\nRibasim.outflow_ids\nRibasim.outflow_ids_allocation\nRibasim.outneighbor_labels_type\nRibasim.parse_static_and_time\nRibasim.pkgversion\nRibasim.process_allocation_graph_edges!\nRibasim.profile_storage\nRibasim.qh_interpolation\nRibasim.reduction_factor\nRibasim.run\nRibasim.save_allocation_flows!\nRibasim.save_demands_and_allocations!\nRibasim.save_flow\nRibasim.save_subgrid_level\nRibasim.scalar_interpolation_derivative\nRibasim.seconds_since\nRibasim.set_current_value!\nRibasim.set_flow!\nRibasim.set_flow!\nRibasim.set_fractional_flow_in_allocation!\nRibasim.set_initial_discrete_controlled_parameters!\nRibasim.set_is_pid_controlled!\nRibasim.set_objective_priority!\nRibasim.set_static_value!\nRibasim.set_table_row!\nRibasim.sorted_table!\nRibasim.tsaves\nRibasim.update_allocation!\nRibasim.update_basin\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_tabulated_rating_curve!\nRibasim.valid_discrete_control\nRibasim.valid_edge_types\nRibasim.valid_edges\nRibasim.valid_flow_rates\nRibasim.valid_fractional_flow\nRibasim.valid_n_neighbors\nRibasim.valid_profiles\nRibasim.valid_sources\nRibasim.valid_subgrid\nRibasim.water_balance!\nRibasim.write_arrow\nRibasim.write_results\nRibasim.config.@addfields\nRibasim.config.@addnodetypes",
"crumbs": [
"Julia core",
"API Reference"
@@ -475,7 +482,7 @@
"href": "core/equations.html#sec-reduction_factor",
"title": "Equations",
"section": "2.1 The reduction factor",
- "text": "2.1 The reduction factor\nAt several points in the equations below a reduction factor is used. This is a term that makes certain transitions more smooth, for instance when a pump stops providing water when its source basin dries up. The reduction factor is given by\n\\[\\begin{align}\n \\phi(x; p) =\n \\begin{cases}\n 0 &\\text{if}\\quad x < 0 \\\\\n -2 \\left(\\frac{x}{p}\\right)^3 + 3\\left(\\frac{x}{p}\\right)^2 &\\text{if}\\quad 0 \\le x \\le p \\\\\n 1 &\\text{if}\\quad x > p\n \\end{cases}\n\\end{align}\\]\nHere \\(p > 0\\) is the threshold value which determines the interval \\([0,p]\\) of the smooth transition between \\(0\\) and \\(1\\), see the plot below.\n\n\nCode\nimport numpy as np\nimport matplotlib.pyplot as plt\n\ndef f(x, p = 3):\n x_scaled = x / p\n phi = (-2 * x_scaled + 3) * x_scaled**2\n phi = np.where(x < 0, 0, phi)\n phi = np.where(x > p, 1, phi)\n\n return phi\n\nfontsize = 15\np = 3\nN = 100\nx_min = -1\nx_max = 4\nx = np.linspace(x_min,x_max,N)\nphi = f(x,p)\n\nfig,ax = plt.subplots(dpi=80)\nax.plot(x,phi)\n\ny_lim = ax.get_ylim()\n\nax.set_xticks([0,p], [0,\"$p$\"], fontsize=fontsize)\nax.set_yticks([0,1], [0,1], fontsize=fontsize)\nax.hlines([0,1],x_min,x_max, color = \"k\", ls = \":\", zorder=-1)\nax.vlines([0,p], *y_lim, color = \"k\", ls = \":\")\nax.set_xlim(x_min,x_max)\nax.set_xlabel(\"$x$\", fontsize=fontsize)\nax.set_ylabel(\"$\\phi(x;p)$\", fontsize=fontsize)\nax.set_ylim(y_lim)\n\nfig.tight_layout()\nplt.show()\n\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n/tmp/ipykernel_2757/665069857.py:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'",
+ "text": "2.1 The reduction factor\nAt several points in the equations below a reduction factor is used. This is a term that makes certain transitions more smooth, for instance when a pump stops providing water when its source basin dries up. The reduction factor is given by\n\\[\\begin{align}\n \\phi(x; p) =\n \\begin{cases}\n 0 &\\text{if}\\quad x < 0 \\\\\n -2 \\left(\\frac{x}{p}\\right)^3 + 3\\left(\\frac{x}{p}\\right)^2 &\\text{if}\\quad 0 \\le x \\le p \\\\\n 1 &\\text{if}\\quad x > p\n \\end{cases}\n\\end{align}\\]\nHere \\(p > 0\\) is the threshold value which determines the interval \\([0,p]\\) of the smooth transition between \\(0\\) and \\(1\\), see the plot below.\n\n\nCode\nimport numpy as np\nimport matplotlib.pyplot as plt\n\ndef f(x, p = 3):\n x_scaled = x / p\n phi = (-2 * x_scaled + 3) * x_scaled**2\n phi = np.where(x < 0, 0, phi)\n phi = np.where(x > p, 1, phi)\n\n return phi\n\nfontsize = 15\np = 3\nN = 100\nx_min = -1\nx_max = 4\nx = np.linspace(x_min,x_max,N)\nphi = f(x,p)\n\nfig,ax = plt.subplots(dpi=80)\nax.plot(x,phi)\n\ny_lim = ax.get_ylim()\n\nax.set_xticks([0,p], [0,\"$p$\"], fontsize=fontsize)\nax.set_yticks([0,1], [0,1], fontsize=fontsize)\nax.hlines([0,1],x_min,x_max, color = \"k\", ls = \":\", zorder=-1)\nax.vlines([0,p], *y_lim, color = \"k\", ls = \":\")\nax.set_xlim(x_min,x_max)\nax.set_xlabel(\"$x$\", fontsize=fontsize)\nax.set_ylabel(\"$\\phi(x;p)$\", fontsize=fontsize)\nax.set_ylim(y_lim)\n\nfig.tight_layout()\nplt.show()\n\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n/tmp/ipykernel_2915/665069857.py:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'",
"crumbs": [
"Julia core",
"Equations"
@@ -695,7 +702,7 @@
"href": "core/usage.html#userdemand-time",
"title": "Usage",
"section": "10.1 UserDemand / time",
- "text": "10.1 UserDemand / time\nThis table is the transient form of the UserDemand table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the demand can be updated over time. In between the given times the demand is interpolated linearly, and outside the demand is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\npriority\nInt32\n-\npositive, sorted per node id\n\n\ntime\nDateTime\n-\nsorted per priority per node id\n\n\ndemand\nFloat64\n\\(m^3 s^{-1}\\)\n-\n\n\nreturn_factor\nFloat64\n-\nbetween [0 - 1]\n\n\nmin_level\nFloat64\n\\(m\\)\n-",
+ "text": "10.1 UserDemand / time\nThis table is the transient form of the UserDemand table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the demand can be updated over time. In between the given times the demand is interpolated linearly, and outside the demand is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\npriority\nInt32\n-\npositive, sorted per node id\n\n\ntime\nDateTime\n-\nsorted per priority per node id\n\n\ndemand\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative\n\n\nreturn_factor\nFloat64\n-\nbetween [0 - 1]\n\n\nmin_level\nFloat64\n\\(m\\)\n-",
"crumbs": [
"Julia core",
"Usage"
@@ -712,12 +719,23 @@
"Usage"
]
},
+ {
+ "objectID": "core/usage.html#flowdemand-time",
+ "href": "core/usage.html#flowdemand-time",
+ "title": "Usage",
+ "section": "12.1 FlowDemand / time",
+ "text": "12.1 FlowDemand / time\nThis table is the transient form of the FlowDemand table, in which a time-dependent demand can be supplied. Similar to the static version, only a single priority per FlowDemand node can be provided.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node id\n\n\npriority\nInt32\n-\npositive\n\n\ndemand\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative",
+ "crumbs": [
+ "Julia core",
+ "Usage"
+ ]
+ },
{
"objectID": "core/usage.html#levelboundary-time",
"href": "core/usage.html#levelboundary-time",
"title": "Usage",
- "section": "12.1 LevelBoundary / time",
- "text": "12.1 LevelBoundary / time\nThis table is the transient form of the LevelBoundary table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the levels can be updated over time. In between the given times the level is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlevel\nFloat64\n\\(m\\)\n-",
+ "section": "13.1 LevelBoundary / time",
+ "text": "13.1 LevelBoundary / time\nThis table is the transient form of the LevelBoundary table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the levels can be updated over time. In between the given times the level is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlevel\nFloat64\n\\(m\\)\n-",
"crumbs": [
"Julia core",
"Usage"
@@ -727,8 +745,8 @@
"objectID": "core/usage.html#flowboundary-time",
"href": "core/usage.html#flowboundary-time",
"title": "Usage",
- "section": "13.1 FlowBoundary / time",
- "text": "13.1 FlowBoundary / time\nThis table is the transient form of the FlowBoundary table. The only differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the flow rates can be updated over time. In between the given times the flow rate is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative",
+ "section": "14.1 FlowBoundary / time",
+ "text": "14.1 FlowBoundary / time\nThis table is the transient form of the FlowBoundary table. The only differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the flow rates can be updated over time. In between the given times the flow rate is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative",
"crumbs": [
"Julia core",
"Usage"
@@ -738,8 +756,8 @@
"objectID": "core/usage.html#discretecontrol-condition",
"href": "core/usage.html#discretecontrol-condition",
"title": "Usage",
- "section": "17.1 DiscreteControl / condition",
- "text": "17.1 DiscreteControl / condition\nThe 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.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\nlisten_node_type\nString\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\nsorted per node_id\n\n\nvariable\nString\n-\nmust be “level” or “flow_rate”, sorted per listen_node_id\n\n\ngreater_than\nFloat64\nvarious\nsorted per variable\n\n\nlook_ahead\nFloat64\n\\(s\\)\nOnly on transient boundary conditions, non-negative (optional, default 0)",
+ "section": "18.1 DiscreteControl / condition",
+ "text": "18.1 DiscreteControl / condition\nThe 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.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\nlisten_node_type\nString\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\nsorted per node_id\n\n\nvariable\nString\n-\nmust be “level” or “flow_rate”, sorted per listen_node_id\n\n\ngreater_than\nFloat64\nvarious\nsorted per variable\n\n\nlook_ahead\nFloat64\n\\(s\\)\nOnly on transient boundary conditions, non-negative (optional, default 0)",
"crumbs": [
"Julia core",
"Usage"
@@ -749,8 +767,8 @@
"objectID": "core/usage.html#discretecontrol-logic",
"href": "core/usage.html#discretecontrol-logic",
"title": "Usage",
- "section": "17.2 DiscreteControl / logic",
- "text": "17.2 DiscreteControl / logic\nThe logic schema defines which control states are triggered based on the truth of the conditions a DiscreteControl node listens to. DiscreteControl is applied in the Julia core as follows:\n\nDuring the simulation it is checked whether the truth of any of the conditions changes.\nWhen a condition changes, the corresponding DiscreteControl node ID is retrieved (node_id in the condition schema above).\nThe truth value of all the conditions this DiscreteControl node listens to are retrieved, in the sorted order as specified in the condition schema. This is then converted into a string of “T” for true and “F” for false. This string we call the truth state.*\nThe table below determines for the given DiscreteControl node ID and truth state what the corresponding control state is.\nFor all the nodes this DiscreteControl node affects (as given by the “control” edges in Edges / static), their parameters are set to those parameters in NodeType / static corresponding to the determined control state.\n\n*. There is also a second truth state created in which for the last condition that changed it is specified whether it was an upcrossing (“U”) or downcrossing (“D”) of the threshold (greater than) value. If a control state is specified for a truth state that is crossing-specific, this takes precedence over the control state for the truth state that contains only “T” and “F”.\n\n\n\n\n\n\nNote\n\n\n\nWhen creating truth states, it is important to not use the order of the condition table as you provide it, but the order as it is written to the file. Users can provide tables in any order, but when writing the model it gets sorted in the required order as specified in the schema.\n\n\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ncontrol_state\nString\n-\n-\n\n\ntruth_state\nString\n-\nConsists of the characters “T” (true), “F” (false), “U” (upcrossing), “D” (downcrossing) and “*” (any), sorted per node_id",
+ "section": "18.2 DiscreteControl / logic",
+ "text": "18.2 DiscreteControl / logic\nThe logic schema defines which control states are triggered based on the truth of the conditions a DiscreteControl node listens to. DiscreteControl is applied in the Julia core as follows:\n\nDuring the simulation it is checked whether the truth of any of the conditions changes.\nWhen a condition changes, the corresponding DiscreteControl node ID is retrieved (node_id in the condition schema above).\nThe truth value of all the conditions this DiscreteControl node listens to are retrieved, in the sorted order as specified in the condition schema. This is then converted into a string of “T” for true and “F” for false. This string we call the truth state.*\nThe table below determines for the given DiscreteControl node ID and truth state what the corresponding control state is.\nFor all the nodes this DiscreteControl node affects (as given by the “control” edges in Edges / static), their parameters are set to those parameters in NodeType / static corresponding to the determined control state.\n\n*. There is also a second truth state created in which for the last condition that changed it is specified whether it was an upcrossing (“U”) or downcrossing (“D”) of the threshold (greater than) value. If a control state is specified for a truth state that is crossing-specific, this takes precedence over the control state for the truth state that contains only “T” and “F”.\n\n\n\n\n\n\nNote\n\n\n\nWhen creating truth states, it is important to not use the order of the condition table as you provide it, but the order as it is written to the file. Users can provide tables in any order, but when writing the model it gets sorted in the required order as specified in the schema.\n\n\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ncontrol_state\nString\n-\n-\n\n\ntruth_state\nString\n-\nConsists of the characters “T” (true), “F” (false), “U” (upcrossing), “D” (downcrossing) and “*” (any), sorted per node_id",
"crumbs": [
"Julia core",
"Usage"
@@ -760,8 +778,8 @@
"objectID": "core/usage.html#pidcontrol-time",
"href": "core/usage.html#pidcontrol-time",
"title": "Usage",
- "section": "18.1 PidControl / time",
- "text": "18.1 PidControl / time\nThis table is the transient form of the PidControl table. The differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the target level and PID coefficients can be updated over time. In between the given times the these values interpolated linearly, and outside these values area constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlisten_node_type\nInt32\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\n-\n\n\ntarget\nFloat64\n\\(m\\)\n-\n\n\nproportional\nFloat64\n\\(s^{-1}\\)\n-\n\n\nintegral\nFloat64\n\\(s^{-2}\\)\n-\n\n\nderivative\nFloat64\n-\n-",
+ "section": "19.1 PidControl / time",
+ "text": "19.1 PidControl / time\nThis table is the transient form of the PidControl table. The differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the target level and PID coefficients can be updated over time. In between the given times the these values interpolated linearly, and outside these values area constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlisten_node_type\nInt32\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\n-\n\n\ntarget\nFloat64\n\\(m\\)\n-\n\n\nproportional\nFloat64\n\\(s^{-1}\\)\n-\n\n\nintegral\nFloat64\n\\(s^{-2}\\)\n-\n\n\nderivative\nFloat64\n-\n-",
"crumbs": [
"Julia core",
"Usage"
@@ -771,8 +789,8 @@
"objectID": "core/usage.html#basin---basin.arrow",
"href": "core/usage.html#basin---basin.arrow",
"title": "Usage",
- "section": "19.1 Basin - basin.arrow",
- "text": "19.1 Basin - basin.arrow\nThe basin table contains results of the storage and level of each basin at every solver timestep. The initial condition is also written to the file.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nnode_id\nInt32\n-\n\n\nstorage\nFloat64\n\\(m^3\\)\n\n\nlevel\nFloat64\n\\(m\\)\n\n\n\nThe table is sorted by time, and per time it is sorted by node_id.",
+ "section": "20.1 Basin - basin.arrow",
+ "text": "20.1 Basin - basin.arrow\nThe basin table contains results of the storage and level of each basin at every solver timestep. The initial condition is also written to the file.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nnode_id\nInt32\n-\n\n\nstorage\nFloat64\n\\(m^3\\)\n\n\nlevel\nFloat64\n\\(m\\)\n\n\n\nThe table is sorted by time, and per time it is sorted by node_id.",
"crumbs": [
"Julia core",
"Usage"
@@ -782,8 +800,8 @@
"objectID": "core/usage.html#flow---flow.arrow",
"href": "core/usage.html#flow---flow.arrow",
"title": "Usage",
- "section": "19.2 Flow - flow.arrow",
- "text": "19.2 Flow - flow.arrow\nThe flow table contains calculated mean flows for every flow edge in the model. In the time column the start of the period is indicated.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nedge_id\nUnion{Int32, Missing}\n-\n\n\nfrom_node_type\nString\n-\n\n\nfrom_node_id\nInt32\n-\n\n\nto_node_type\nString\n-\n\n\nto_node_id\nInt32\n-\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\n\n\n\nThe table is sorted by time, and per time the same edge_id order is used, though not sorted. The edge_id value is the same as the fid written to the Edge table, and can be used to directly look up the Edge geometry. Flows that are added to the model at a node, have a missing edge_id, and identical from_node_id and to_node_id. Flows out of the model always have a negative sign, and additions a positive sign.",
+ "section": "20.2 Flow - flow.arrow",
+ "text": "20.2 Flow - flow.arrow\nThe flow table contains calculated mean flows for every flow edge in the model. In the time column the start of the period is indicated.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nedge_id\nUnion{Int32, Missing}\n-\n\n\nfrom_node_type\nString\n-\n\n\nfrom_node_id\nInt32\n-\n\n\nto_node_type\nString\n-\n\n\nto_node_id\nInt32\n-\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\n\n\n\nThe table is sorted by time, and per time the same edge_id order is used, though not sorted. The edge_id value is the same as the fid written to the Edge table, and can be used to directly look up the Edge geometry. Flows that are added to the model at a node, have a missing edge_id, and identical from_node_id and to_node_id. Flows out of the model always have a negative sign, and additions a positive sign.",
"crumbs": [
"Julia core",
"Usage"
@@ -793,8 +811,8 @@
"objectID": "core/usage.html#discretecontrol---control.arrow",
"href": "core/usage.html#discretecontrol---control.arrow",
"title": "Usage",
- "section": "19.3 DiscreteControl - control.arrow",
- "text": "19.3 DiscreteControl - control.arrow\nThe control table contains a record of each change of control state: when it happened, which control node was involved, to which control state it changed and based on which truth state.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\ncontrol_node_id\nInt32\n\n\ntruth_state\nString\n\n\ncontrol_state\nString",
+ "section": "20.3 DiscreteControl - control.arrow",
+ "text": "20.3 DiscreteControl - control.arrow\nThe control table contains a record of each change of control state: when it happened, which control node was involved, to which control state it changed and based on which truth state.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\ncontrol_node_id\nInt32\n\n\ntruth_state\nString\n\n\ncontrol_state\nString",
"crumbs": [
"Julia core",
"Usage"
@@ -804,8 +822,8 @@
"objectID": "core/usage.html#allocation---allocation.arrow",
"href": "core/usage.html#allocation---allocation.arrow",
"title": "Usage",
- "section": "19.4 Allocation - allocation.arrow",
- "text": "19.4 Allocation - allocation.arrow\nThe allocation table contains a record of allocation results: when it happened, for which node, in which allocation network, and what the demand, allocated flow and realized flow were.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nsubnetwork_id\nInt32\n\n\nnode_type\nString\n\n\nnode_id\nInt32\n\n\npriority\nInt32\n\n\ndemand\nFloat64\n\n\nallocated\nFloat64\n\n\nrealized\nFloat64\n\n\n\nFor Basins the values demand, allocated and realized are positive if the Basin level is below the minimum level given by a LevelDemand node. The values are negative if the Basin supplies due to a surplus of water.\n\n\n\n\n\n\nNote\n\n\n\nCurrently the stored demand and abstraction rate are those at the allocation timepoint (and the abstraction rate is based on the previous allocation optimization). In the future these will be an average over the previous allocation timestep.",
+ "section": "20.4 Allocation - allocation.arrow",
+ "text": "20.4 Allocation - allocation.arrow\nThe allocation table contains a record of allocation results: when it happened, for which node, in which allocation network, and what the demand, allocated flow and realized flow were.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nsubnetwork_id\nInt32\n\n\nnode_type\nString\n\n\nnode_id\nInt32\n\n\npriority\nInt32\n\n\ndemand\nFloat64\n\n\nallocated\nFloat64\n\n\nrealized\nFloat64\n\n\n\nFor Basins the values demand, allocated and realized are positive if the Basin level is below the minimum level given by a LevelDemand node. The values are negative if the Basin supplies due to a surplus of water.\n\n\n\n\n\n\nNote\n\n\n\nCurrently the stored demand and abstraction rate are those at the allocation timepoint (and the abstraction rate is based on the previous allocation optimization). In the future these will be an average over the previous allocation timestep.",
"crumbs": [
"Julia core",
"Usage"
@@ -815,8 +833,8 @@
"objectID": "core/usage.html#allocation-flow---allocation_flow.arrow",
"href": "core/usage.html#allocation-flow---allocation_flow.arrow",
"title": "Usage",
- "section": "19.5 Allocation flow - allocation_flow.arrow",
- "text": "19.5 Allocation flow - allocation_flow.arrow\nThe allocation flow table contains results of the optimized allocation flow on every edge in the model that is part of a subnetwork, for each time an optimization problem is solved (see also here). If in the model a main network and subnetwork(s) are specified, there are 2 different types of optimization for the subnetwork: collecting its total demand per priority (for allocating flow from the main network to the subnetwork), and allocating flow within the subnetwork. The column collect_demands provides the distinction between these two optimization types.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nedge_id\nInt32\n\n\nfrom_node_type\nString\n\n\nfrom_node_id\nInt32\n\n\nto_node_type\nString\n\n\nto_node_id\nInt32\n\n\nsubnetwork_id\nInt32\n\n\npriority\nInt32\n\n\nflow_rate\nFloat64\n\n\ncollect_demands\nBool",
+ "section": "20.5 Allocation flow - allocation_flow.arrow",
+ "text": "20.5 Allocation flow - allocation_flow.arrow\nThe allocation flow table contains results of the optimized allocation flow on every edge in the model that is part of a subnetwork, for each time an optimization problem is solved (see also here). If in the model a main network and subnetwork(s) are specified, there are 2 different types of optimization for the subnetwork: collecting its total demand per priority (for allocating flow from the main network to the subnetwork), and allocating flow within the subnetwork. The column collect_demands provides the distinction between these two optimization types.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nedge_id\nInt32\n\n\nfrom_node_type\nString\n\n\nfrom_node_id\nInt32\n\n\nto_node_type\nString\n\n\nto_node_id\nInt32\n\n\nsubnetwork_id\nInt32\n\n\npriority\nInt32\n\n\nflow_rate\nFloat64\n\n\ncollect_demands\nBool",
"crumbs": [
"Julia core",
"Usage"
@@ -882,7 +900,7 @@
"href": "core/allocation.html",
"title": "Allocation",
"section": "",
- "text": "Allocation is the process of assigning an allocated abstraction flow rate to demand nodes in the physical layer of the model based on information about sources, the different demand nodes over various priorities, constraints introduced by nodes, local water availability and graph topology. The allocation procedure implemented in Ribasim is heavily inspired by the maximum flow problem.\nThe allocation problem is solved per subnetwork of the Ribasim model. The subnetwork is used to formulate an optimization problem with the JuMP package, which is solved using the HiGHS solver. For more in-depth information see also the example of solving the maximum flow problem with JuMP.jl here.",
+ "text": "Allocation is the process of assigning an allocated flow rate to demand nodes in the physical layer of the model based on information about sources, the different demand nodes over various priorities, constraints introduced by nodes, local water availability and graph topology. The allocation procedure implemented in Ribasim is heavily inspired by the maximum flow problem.\nThe allocation problem is solved per subnetwork of the Ribasim model. The subnetwork is used to formulate an optimization problem with the JuMP package, which is solved using the HiGHS solver. For more in-depth information see also the example of solving the maximum flow problem with JuMP.jl here.",
"crumbs": [
"Julia core",
"Allocation"
@@ -893,7 +911,7 @@
"href": "core/allocation.html#schematisation-input",
"title": "Allocation",
"section": "3.1 Schematisation input",
- "text": "3.1 Schematisation input\n\n3.1.1 The subnetwork\nThe allocation problem is solved per subnetwork, which is given by a subset \\(S \\subset V\\) of node ids. Different subnetworks are disjoint from eachother.\n\n\n3.1.2 Source flows\nSources are indicated by a set of edges in the subnetwork \\[\nE_S^\\text{source} \\subset \\left(S \\times S\\right) \\cap E.\n\\] That is, if \\((i,j) \\in E_S^\\text{source}\\), then \\(Q_{ij}\\) (see the formal model description) is treated as a source flow in the allocation problem. These edges are either coming from a boundary/source node (e.g. a level or flow boundary) or connect the main network to a subnetwork.\n\n\n3.1.3 User demands\nThe subnetwork contains a subset of UserDemand nodes \\(U_S \\subset S\\), who all have time varying demands over various priorities \\(p\\): \\[\n d^p_i(t), \\quad i \\in U_S, p = 1,2,\\ldots, p_{\\max}.\n\\]\n\n\n\n\n\n\nNote\n\n\n\nOn this page we assume that the priorities are given by all integers from \\(1\\) to some \\(p_{\\max} \\in \\mathbb{N}\\). However, in the Ribasim input this is not a requirement; some of these in between priority values can be missing, only the ordering of the given priorities is taken into account.",
+ "text": "3.1 Schematisation input\n\n3.1.1 The subnetwork\nThe allocation problem is solved per subnetwork, which is given by a subset \\(S \\subset V\\) of node ids. Different subnetworks are disjoint from eachother.\n\n\n3.1.2 Source flows\nSources are indicated by a set of edges in the subnetwork \\[\nE_S^\\text{source} \\subset \\left(S \\times S\\right) \\cap E.\n\\] That is, if \\((i,j) \\in E_S^\\text{source}\\), then \\(Q_{ij}\\) (see the formal model description) is treated as a source flow in the allocation problem. These edges are either coming from a boundary/source node (e.g. a level or flow boundary) or connect the main network to a subnetwork.\n\n\n3.1.3 User demands\nThe subnetwork contains a subset of UserDemand nodes \\(U_S \\subset S\\), who all have static or time varying demands over various priorities \\(p\\): \\[\n d^p_i(t), \\quad i \\in U_S, p = 1,2,\\ldots, p_{\\max}.\n\\] However, in\n\n\n\n\n\n\nNote\n\n\n\nOn this page we assume that the priorities are given by all integers from \\(1\\) to some \\(p_{\\max} \\in \\mathbb{N}\\).the Ribasim input this is not a requirement; some of these in between priority values can be missing, only the ordering of the given priorities is taken into account.\n\n\n\n\n3.1.4 Flow demands\nThe subnetwork contains a subset of nodes \\(FD_S \\in S\\) which have a demand of a single priority \\(p_{\\text{fd}}\\). With this we define \\[\n d^p_i(t) =\n \\begin{cases}\n 0 \\text{ if } p \\ne p_{\\text{fd}} \\\\\n d^{p_{\\text{df}}} \\text{ if } p = p_{\\text{fd}}\n \\end{cases}\n\\] for all \\(i \\in FD_S\\). Here \\(d^{p_{\\text{df}}}\\) is given by the original flow demand minus the flows trough node \\(i\\) at all priorities \\(p < p_{\\text{fd}}\\).",
"crumbs": [
"Julia core",
"Allocation"
@@ -915,7 +933,7 @@
"href": "core/allocation.html#the-allocation-network",
"title": "Allocation",
"section": "3.3 The allocation network",
- "text": "3.3 The allocation network\nA new graph is created from the subnetwork, which we call an allocation network. The allocation network is almost a subgraph of the main (flow) model, apart from the fact that an allocation network can contain edges which are a combination of multiple edges in the main model.\n\n3.3.1 Nodes and edges\nThe allocation network consists of:\n\nNodes \\(V'_S \\subset V_S\\), where each Basin, source and demand in the subnetwork get a node in the allocation network. Also nodes that have FractionalFlow outneighbors get a node in the allocation network.\nEdges \\(E_S\\), which are either edges that also appear between nodes in the subnetwork or represent a sequence of those, creating a shortcut.\n\nFor notational convenience, we use the notation\n\\[\\begin{align}\n V^{\\text{out}}_S(i) = \\left\\{j \\in V'_S : (i,j) \\in E_S\\right\\} \\\\\n V^{\\text{in}}_S(j) = \\left\\{i \\in V'_S : (i,j) \\in E_S\\right\\}\n\\end{align}\\]\nfor the set of in-neighbors and out-neighbors of a node in the allocation network respectively.\n\n\n3.3.2 Capacities\nEach edge in the allocation network has an associated capacity. These capacities are collected in the sparse capacity matrix \\(C_S \\in \\overline{\\mathbb{R}}_{\\ge 0}^{n'\\times n'}\\) where \\(n' = \\#V'_S\\) is the number of nodes in the allocation network. The capacities can be infinite, if there is nothing in the model constraining the capacity of the edge.\nThe capacities are determined in different ways:\n\nIf an edge does not exist in the allocation network, i.e. \\((i,j) \\notin E_S\\) for certain \\(1 \\le i,j\\le n'\\), then \\((C_S)_{i,j} = 0\\);\nThe capacity of the edge \\(e \\in E_S\\) is given by the smallest max_flow_rate of the nodes along the equivalent edges in the subnetwork. If there are no nodes with a max_flow_rate, the edge capacity is infinite;\nIf the edge is a source, the capacity of the edge is given by the flow rate of that source.\n\nThere are also capacities \\(C^B_S \\in \\mathbb{R}^b\\) where \\(b = \\# B_S\\) is the number of basins, for the flow supplied by basins.",
+ "text": "3.3 The allocation network\nA new graph is created from the subnetwork, which we call an allocation network. The allocation network is almost a subgraph of the main (flow) model, apart from the fact that an allocation network can contain edges which are a combination of multiple edges in the main model.\n\n3.3.1 Nodes and edges\nThe allocation network consists of:\n\nNodes \\(V'_S \\subset V_S\\). Nodes that are represented in the allocation network are: nodes of type Basin, UserDemand and Terminal, nodes that have FractionalFlow downstream neighbors, nodes that have a flow demand and nodes that are connected to a source edge.\nEdges \\(E_S\\), which are either edges that also appear between nodes in the subnetwork or represent a sequence of those, creating a shortcut.\n\nFor notational convenience, we use the notation\n\\[\\begin{align}\n V^{\\text{out}}_S(i) = \\left\\{j \\in V'_S : (i,j) \\in E_S\\right\\} \\\\\n V^{\\text{in}}_S(j) = \\left\\{i \\in V'_S : (i,j) \\in E_S\\right\\}\n\\end{align}\\]\nfor the set of in-neighbors and out-neighbors of a node in the allocation network respectively.\n\n\n3.3.2 Capacities\nEach edge in the allocation network has an associated capacity. These capacities are collected in the sparse capacity matrix \\(C_S \\in \\overline{\\mathbb{R}}_{\\ge 0}^{n'\\times n'}\\) where \\(n' = \\#V'_S\\) is the number of nodes in the allocation network. The capacities can be infinite, if there is nothing in the model constraining the capacity of the edge.\nThe capacities are determined in different ways:\n\nIf an edge does not exist in the allocation network, i.e. \\((i,j) \\notin E_S\\) for certain \\(1 \\le i,j\\le n'\\), then \\((C_S)_{i,j} = 0\\);\nThe capacity of the edge \\(e \\in E_S\\) is given by the smallest max_flow_rate of the nodes along the equivalent edges in the subnetwork. If there are no nodes with a max_flow_rate, the edge capacity is infinite;\nIf the edge is a source, the capacity of the edge is given by the flow rate of that source;\nIf an edge comes from a node with a flow demand, it has infinite capacity at priorities other than this of this flow demand, and zero capacity otherwise.\n\nThere are also capacities for special edges:\n\n\\(C^B_S \\in \\mathbb{R}^b_{\\ge 0}\\) where \\(b = \\# B_S\\) is the number of basins, for the flow supplied by basins.\n\\(C^{FD}_S \\in \\mathbb{R}^c_{\\ge 0}\\) where \\(c = \\# FD_S\\) is the number of nodes with a flow demand, for the flow supplied by flow buffers at these nodes with a flow demand.",
"crumbs": [
"Julia core",
"Allocation"
@@ -926,7 +944,7 @@
"href": "core/allocation.html#the-optimization-variables",
"title": "Allocation",
"section": "4.1 The optimization variables",
- "text": "4.1 The optimization variables\nThere are several types of variable whose value has to be determined to solve the allocation problem:\n\nThe flows \\(F \\in \\mathbb{R}_{\\ge 0}^{n'\\times n'}\\) over the edges in the allocation network;\nThe flows \\(F^\\text{basin out}_{i}, F^\\text{basin in}_{i} \\geq 0\\) for all \\(i \\in B_S\\) supplied and consumed by the basins respectively.",
+ "text": "4.1 The optimization variables\nThere are several types of variable whose value has to be determined to solve the allocation problem:\n\nThe flows \\(F \\in \\mathbb{R}_{\\ge 0}^{n'\\times n'}\\) over the edges in the allocation network;\nThe flows \\(F^\\text{basin out}_{i}, F^\\text{basin in}_{i} \\geq 0\\) for all \\(i \\in B_S\\) supplied and consumed by the basins respectively;\nThe flows \\(F^\\text{buffer out}_{i}, F^\\text{buffer in}_{i} \\ge 0\\) for all \\(i \\in FD_S\\) supplied and consumed by the flow buffers of nodes with a flow demand respectively.",
"crumbs": [
"Julia core",
"Allocation"
@@ -937,7 +955,7 @@
"href": "core/allocation.html#the-optimization-objective",
"title": "Allocation",
"section": "4.2 The optimization objective",
- "text": "4.2 The optimization objective\nThe goal of allocation is to get the flow to nodes with demands as close as possible to these demands. To achieve this, a sum error of terms is minimized.\n\\[\n \\min E_{\\text{user demand}} + E_{\\text{basin}}\n\\]\nThe error between the flows and user demands is denoted by \\(E_{\\text{user demand}}\\), where \\[\n E_{\\text{user demand}} = \\sum_{(i,j)\\in E_S\\;:\\; i\\in U_S} \\left| F_{ij} - d_j^p(t)\\right|\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing main network allocation, the connections to subnetworks are also interpreted as UserDemand with demands determined by subnetwork demand collection.\n\n\nThis type of objective cares about the absolute amount of water allocated to a demand. It treats all deviations equally which means it doesn’t give larger punishment per flow unit if deviations increase.\nThe absolute value applied here is not supported in a linear programming context directly; this requires introduction of new variables and constraints. For more details see here.\nLikewise, the error of basin demands is the absolute difference between flows consumed by basins and basin demands. \\[\n E_{\\text{basin}} = \\sum_{i \\in B_S} \\left| F_i^\\text{basin in} - d_i^p(t)\\right|\n\\]",
+ "text": "4.2 The optimization objective\nThe goal of allocation is to get the flow to nodes with demands as close as possible to these demands. To achieve this, a sum error of terms is minimized.\n\\[\n \\min E_{\\text{user demand}} + E_{\\text{level demand}} + E_{\\text{flow demand}}\n\\]\nThe error between the flows and user demands is denoted by \\(E_{\\text{user demand}}\\), where \\[\n E_{\\text{user demand}} = \\sum_{(i,j)\\in E_S\\;:\\; i\\in U_S} \\left| F_{ij} - d_j^p(t)\\right|\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing main network allocation, the connections to subnetworks are also interpreted as UserDemand with demands determined by subnetwork demand collection.\n\n\nThis type of objective cares about the absolute amount of water allocated to a demand. It treats all deviations equally which means it doesn’t give larger punishment per flow unit if deviations increase.\nThe absolute value applied here is not supported in a linear programming context directly; this requires introduction of new variables and constraints. For more details see here.\nLikewise, the error of level demands from basins is the absolute difference between flows consumed by basins and basin demands. \\[\n E_{\\text{level demand}} = \\sum_{i \\in B_S} \\left| F_i^\\text{basin in} - d_i^p(t)\\right|\n\\]\nLastly, the error of the flow demands is given as below. \\[\n E_{\\text{flow demand}} = \\sum_{i \\in FD_S} \\left| F_i^\\text{buffer in} - d_i^p(t)\\right|\n\\]",
"crumbs": [
"Julia core",
"Allocation"
@@ -948,7 +966,7 @@
"href": "core/allocation.html#the-optimization-constraints",
"title": "Allocation",
"section": "4.3 The optimization constraints",
- "text": "4.3 The optimization constraints\n\nFlow conservation: For the basins in the allocation network we have that \\[\n F^\\text{basin in}_k + \\sum_{j=1}^{n'} F_{kj} = F^\\text{basin out}_k + \\sum_{i=1}^{n'} F_{ik}, \\quad \\forall k \\in B_S .\n\\tag{1}\\] Note that we do not require equality here; in the allocation we do not mind that excess flow is ‘forgotten’ if it cannot contribute to the allocation to the demands.\n\n\n\n\n\n\n\nNote\n\n\n\nIn Equation 1, the placement of the basin flows might seem counter-intuitive. Think of the basin storage as a separate node connected to the basin node.\n\n\n\nCapacity: the flows over the edges are positive and bounded by the edge capacity: \\[\n F_{ij} \\le \\left(C_S\\right)_{ij}, \\quad \\forall(i,j) \\in E_S.\n\\tag{2}\\] By the definition of \\(C_S\\) this also includes the source flows. The same holds for the basin outflows:\n\n\\[\n F^{\\text{basin out}}_{i} \\le F^{\\text{basin out}}_{\\max, i}, \\quad \\forall i \\in B_S.\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing subnetwork demand collection, these capacities are set to \\(\\infty\\) for edges which connect the main network to a subnetwork.\n\n\n\nUserDemand outflow: The outflow of the UserDemand is dictated by the inflow and the return factor: \\[\n F_{ik} = r_k \\cdot F_{kj} \\quad\n \\quad \\forall k \\in U_S, \\quad\n V^{\\text{in}}_S(k) = \\{i\\},\\;\n V^{\\text{out}}_S(k) = \\{j\\}.\n\\tag{3}\\] Here we use that each UserDemand node in the allocation network has a unique in-edge and out-edge.\nUser demand: UserDemand demand constraints are discussed in the next section.\nFractional flow: Let \\(L_S \\subset V_S\\) be the set of nodes in the max flow graph with fractional flow outneighbors, and \\(f_j\\) the flow fraction associated with fractional flow node \\(j \\in V_S\\). Then \\[\n F_{ij} \\le f_j \\sum_{k\\in V^\\text{in}_S(i)} F_{ki} \\qquad\n \\forall i \\in L_S, \\;\n j \\in V_S^\\text{out}(i).\n\\tag{4}\\]\nFlow sign: Furthermore there are the non-negativity constraints for the flows and allocations, see The optimization variables.",
+ "text": "4.3 The optimization constraints\n\nFlow conservation: For the basins in the allocation network we have that \\[\n F^\\text{basin in}_k + \\sum_{j \\in V^{\\text{out}}_S(k)} F_{kj} = F^\\text{basin out}_k + \\sum_{i \\in V^{\\text{in}}_S(k)} F_{ik}, \\quad \\forall k \\in B_S .\n\\tag{1}\\] We have the same constraint without the basin terms for nodes that have flow edges as inneighbors (except if this node also happens to be a basin). For nodes which have a flow demand we have \\[\nF_{kj} + F^\\text{buffer in}_k = F^\\text{flow in}_k + F_{ik}, \\quad \\forall k \\in FD_S, \\quad V^{\\text{in}}_S(k) = \\{i\\},\\;\n V^{\\text{out}}_S(k) = \\{j\\}.\n\\tag{2}\\]\n\n\n\n\n\n\n\nNote\n\n\n\nIn Equation 1 and Equation 2, the placement of the basin and buffer flows might seem counter-intuitive. Think of the storage or buffer as a separate node connected to the node with the demand.\n\n\n\nCapacity: the flows over the edges are bounded by the edge capacity: \\[\n F_{ij} \\le \\left(C_S\\right)_{ij}, \\quad \\forall(i,j) \\in E_S.\n\\tag{3}\\] By the definition of \\(C_S\\) this also includes the source flows. The same holds for the basin outflows:\n\n\\[\n F^{\\text{basin out}}_{i} \\le F^{\\text{basin out}}_{\\max, i}, \\quad \\forall i \\in B_S.\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing subnetwork demand collection, these capacities are set to \\(\\infty\\) for edges which connect the main network to a subnetwork.\n\n\nSimilar constraints hold for the flow out of basins and flow demand buffers: \\[\nF^\\text{basin out}_{i} \\le (C^B_S)_i, \\quad \\forall i \\in B_S,\n\\]\n\\[\nF^\\text{buffer out}_{i} \\le (C^FD_S)_i, \\quad \\forall i \\in FD_S.\n\\]\n\nUserDemand outflow: The outflow of the UserDemand is dictated by the inflow and the return factor: \\[\n F_{ik} = r_k \\cdot F_{kj} \\quad\n \\quad \\forall k \\in U_S, \\quad\n V^{\\text{in}}_S(k) = \\{i\\},\\;\n V^{\\text{out}}_S(k) = \\{j\\}.\n\\tag{4}\\] Here we use that each UserDemand node in the allocation network has a unique in-edge and out-edge.\nUser demand: UserDemand demand constraints are discussed in the next section.\nFractional flow: Let \\(L_S \\subset V_S\\) be the set of nodes in the max flow graph with fractional flow outneighbors, and \\(f_j\\) the flow fraction associated with fractional flow node \\(j \\in V_S\\). Then \\[\n F_{ij} \\le f_j \\sum_{k\\in V^\\text{in}_S(i)} F_{ki} \\qquad\n \\forall i \\in L_S, \\;\n j \\in V_S^\\text{out}(i).\n\\tag{5}\\]\nFlow sign: Furthermore there are the non-negativity constraints for the flows and allocations, see The optimization variables.",
"crumbs": [
"Julia core",
"Allocation"
@@ -970,7 +988,7 @@
"href": "core/allocation.html#example",
"title": "Allocation",
"section": "5.1 Example",
- "text": "5.1 Example\nThe following is an example of an optimization problem for the example shown here:\n\n\nCode\nusing Ribasim\nusing Ribasim: NodeID\nusing SQLite\nusing ComponentArrays: ComponentVector\n\ntoml_path = normpath(@__DIR__, \"../../generated_testmodels/allocation_example/ribasim.toml\")\np = Ribasim.Model(toml_path).integrator.p\nu = ComponentVector(; storage = zeros(length(p.basin.node_id)))\n\nallocation_model = p.allocation.allocation_models[1]\nt = 0.0\npriority_idx = 1\n\nRibasim.set_flow!(p.graph, NodeID(:FlowBoundary, 1), NodeID(:Basin, 2), 1.0)\n\nRibasim.adjust_source_capacities!(allocation_model, p, priority_idx)\nRibasim.adjust_edge_capacities!(allocation_model, p, priority_idx)\nRibasim.set_objective_priority!(allocation_model, p, u, t, priority_idx)\n\nprintln(p.allocation.allocation_models[1].problem)\n\n\nMin F_abs_user_demand[UserDemand #3] + F_abs_user_demand[UserDemand #13] + F_abs_user_demand[UserDemand #6] + F_abs_basin[Basin #2] + F_abs_basin[Basin #12] + F_abs_basin[Basin #5]\nSubject to\n flow_conservation[Basin #2] : -F[(Basin #5, Basin #2)] + F[(Basin #2, Basin #5)] - F[(FlowBoundary #1, Basin #2)] + F[(Basin #2, UserDemand #3)] + F_basin_in[Basin #2] - F_basin_out[Basin #2] = 0\n flow_conservation[Basin #12] : F[(Basin #12, UserDemand #13)] - F[(TabulatedRatingCurve #7, Basin #12)] + F_basin_in[Basin #12] - F_basin_out[Basin #12] = 0\n flow_conservation[Basin #5] : F[(Basin #5, UserDemand #6)] + F[(Basin #5, Basin #2)] - F[(Basin #2, Basin #5)] + F[(Basin #5, TabulatedRatingCurve #7)] + F_basin_in[Basin #5] - F_basin_out[Basin #5] = 0\n abs_positive_user_demand[UserDemand #3] : -F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ -1.5\n abs_positive_user_demand[UserDemand #13] : -F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_positive_user_demand[UserDemand #6] : -F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n abs_negative_user_demand[UserDemand #3] : F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ 1.5\n abs_negative_user_demand[UserDemand #13] : F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_negative_user_demand[UserDemand #6] : F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n abs_positive_basin[Basin #2] : -F_basin_in[Basin #2] + F_abs_basin[Basin #2] ≥ 0\n abs_positive_basin[Basin #12] : -F_basin_in[Basin #12] + F_abs_basin[Basin #12] ≥ 0\n abs_positive_basin[Basin #5] : -F_basin_in[Basin #5] + F_abs_basin[Basin #5] ≥ 0\n abs_negative_basin[Basin #2] : F_basin_in[Basin #2] + F_abs_basin[Basin #2] ≥ 0\n abs_negative_basin[Basin #12] : F_basin_in[Basin #12] + F_abs_basin[Basin #12] ≥ 0\n abs_negative_basin[Basin #5] : F_basin_in[Basin #5] + F_abs_basin[Basin #5] ≥ 0\n source[(FlowBoundary #1, Basin #2)] : F[(FlowBoundary #1, Basin #2)] ≤ 1\n return_flow[UserDemand #13] : F[(UserDemand #13, Terminal #10)] ≤ 0\n fractional_flow[(TabulatedRatingCurve #7, Basin #12)] : -0.4 F[(Basin #5, TabulatedRatingCurve #7)] + F[(TabulatedRatingCurve #7, Basin #12)] ≤ 0\n basin_outflow[Basin #2] : F_basin_out[Basin #2] ≤ 0\n basin_outflow[Basin #12] : F_basin_out[Basin #12] ≤ 0\n basin_outflow[Basin #5] : F_basin_out[Basin #5] ≤ 0\n F[(TabulatedRatingCurve #7, Terminal #10)] ≥ 0\n F[(Basin #5, UserDemand #6)] ≥ 0\n F[(Basin #5, Basin #2)] ≥ 0\n F[(Basin #12, UserDemand #13)] ≥ 0\n F[(Basin #2, Basin #5)] ≥ 0\n F[(FlowBoundary #1, Basin #2)] ≥ 0\n F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0\n F[(Basin #2, UserDemand #3)] ≥ 0\n F[(UserDemand #13, Terminal #10)] ≥ 0\n F[(TabulatedRatingCurve #7, Basin #12)] ≥ 0\n F_basin_in[Basin #2] ≥ 0\n F_basin_in[Basin #12] ≥ 0\n F_basin_in[Basin #5] ≥ 0\n F_basin_out[Basin #2] ≥ 0\n F_basin_out[Basin #12] ≥ 0\n F_basin_out[Basin #5] ≥ 0",
+ "text": "5.1 Example\nThe following is an example of an optimization problem for the example shown here:\n\n\nCode\nusing Ribasim\nusing Ribasim: NodeID\nusing SQLite\nusing ComponentArrays: ComponentVector\n\ntoml_path = normpath(@__DIR__, \"../../generated_testmodels/allocation_example/ribasim.toml\")\np = Ribasim.Model(toml_path).integrator.p\nu = ComponentVector(; storage = zeros(length(p.basin.node_id)))\n\nallocation_model = p.allocation.allocation_models[1]\nt = 0.0\npriority_idx = 1\n\nRibasim.set_flow!(p.graph, NodeID(:FlowBoundary, 1), NodeID(:Basin, 2), 1.0)\n\nRibasim.adjust_capacities_edge!(allocation_model, p, priority_idx)\nRibasim.adjust_capacities_source!(allocation_model, p, priority_idx)\nRibasim.set_objective_priority!(allocation_model, p, u, t, priority_idx)\n\nprintln(p.allocation.allocation_models[1].problem)\n\n\nMin F_abs_user_demand[UserDemand #3] + F_abs_user_demand[UserDemand #13] + F_abs_user_demand[UserDemand #6]\nSubject to\n flow_conservation_basin[Basin #5] : F[(Basin #5, UserDemand #6)] + F[(Basin #5, Basin #2)] - F[(Basin #2, Basin #5)] + F[(Basin #5, TabulatedRatingCurve #7)] = 0\n flow_conservation_basin[Basin #2] : F[(Basin #2, UserDemand #3)] - F[(FlowBoundary #1, Basin #2)] - F[(Basin #5, Basin #2)] + F[(Basin #2, Basin #5)] = 0\n flow_conservation_basin[Basin #12] : F[(Basin #12, UserDemand #13)] - F[(TabulatedRatingCurve #7, Basin #12)] = 0\n abs_positive_user_demand[UserDemand #3] : -F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ -1.5\n abs_positive_user_demand[UserDemand #13] : -F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_positive_user_demand[UserDemand #6] : -F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n abs_negative_user_demand[UserDemand #3] : F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ 1.5\n abs_negative_user_demand[UserDemand #13] : F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_negative_user_demand[UserDemand #6] : F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n source[(FlowBoundary #1, Basin #2)] : F[(FlowBoundary #1, Basin #2)] ≤ 1\n return_flow[UserDemand #13] : F[(UserDemand #13, Terminal #10)] ≤ 0\n fractional_flow[(TabulatedRatingCurve #7, Basin #12)] : F[(TabulatedRatingCurve #7, Basin #12)] - 0.4 F[(Basin #5, TabulatedRatingCurve #7)] ≤ 0\n F[(Basin #5, UserDemand #6)] ≥ 0\n F[(Basin #12, UserDemand #13)] ≥ 0\n F[(TabulatedRatingCurve #7, Terminal #10)] ≥ 0\n F[(UserDemand #13, Terminal #10)] ≥ 0\n F[(Basin #2, UserDemand #3)] ≥ 0\n F[(FlowBoundary #1, Basin #2)] ≥ 0\n F[(Basin #5, Basin #2)] ≥ 0\n F[(Basin #2, Basin #5)] ≥ 0\n F[(TabulatedRatingCurve #7, Basin #12)] ≥ 0\n F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0",
"crumbs": [
"Julia core",
"Allocation"
@@ -981,7 +999,7 @@
"href": "core/validation.html",
"title": "Validation",
"section": "",
- "text": "The tables below show the validation rules applied to the input to the Julia core before running the model.\n\n1 Connectivity\nIn 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.\n\n\nCode\nusing Ribasim\nusing DataFrames: DataFrame\nusing MarkdownTables\n\nnode_names_snake_case = Vector{Symbol}()\nnode_names_camel_case = Vector{Symbol}()\nfor (node_name, node_type) in zip(fieldnames(Ribasim.Parameters), fieldtypes(Ribasim.Parameters))\n if node_type <: Ribasim.AbstractParameterNode\n push!(node_names_snake_case, node_name)\n push!(node_names_camel_case, nameof(node_type))\n end\nend\n\nfunction to_symbol(b::Bool)::String\n return b ? \"✓\" : \"x\"\nend\n\n\ndf = DataFrame()\ndf[!, :downstream] = node_names_snake_case\n\nfor node_name in node_names_snake_case\n df[!, node_name] =\n [(to_symbol(node_name_ in Ribasim.neighbortypes(node_name))) for node_name_ in node_names_snake_case]\nend\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndownstream\nbasin\nlinear_resistance\nmanning_resistance\ntabulated_rating_curve\nfractional_flow\nlevel_boundary\nflow_boundary\npump\noutlet\nterminal\ndiscrete_control\npid_control\nuser_demand\n\n\n\n\nbasin\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nlinear_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\nmanning_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\ntabulated_rating_curve\n✓\nx\nx\nx\nx\nx\nx\nx\nx\nx\n✓\nx\nx\n\n\nfractional_flow\nx\nx\nx\n✓\nx\nx\n✓\n✓\n✓\nx\n✓\nx\n✓\n\n\nlevel_boundary\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nflow_boundary\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npump\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\noutlet\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\nterminal\nx\nx\nx\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\ndiscrete_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npid_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n✓\nx\nx\n\n\nuser_demand\n✓\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\n\n\n\n\n\n2 Neighbor amounts\nThe table below shows for each node type between which bounds the amount of in- and outneighbors must be, for both flow and control edges.\n\n\nCode\nflow_in_min = Vector{String}()\nflow_in_max = Vector{String}()\nflow_out_min = Vector{String}()\nflow_out_max = Vector{String}()\ncontrol_in_min = Vector{String}()\ncontrol_in_max = Vector{String}()\ncontrol_out_min = Vector{String}()\ncontrol_out_max = Vector{String}()\n\nfunction unbounded(i::Int)::String\n return i == typemax(Int) ? \"∞\" : string(i)\nend\n\nfor node_name in node_names_camel_case\n bounds_flow = Ribasim.n_neighbor_bounds_flow(node_name)\n push!(flow_in_min, string(bounds_flow.in_min))\n push!(flow_in_max, unbounded(bounds_flow.in_max))\n push!(flow_out_min, string(bounds_flow.out_min))\n push!(flow_out_max, unbounded(bounds_flow.out_max))\n\n bounds_control = Ribasim.n_neighbor_bounds_control(node_name)\n push!(control_in_min, string(bounds_control.in_min))\n push!(control_in_max, unbounded(bounds_control.in_max))\n push!(control_out_min, string(bounds_control.out_min))\n push!(control_out_max, unbounded(bounds_control.out_max))\n\nend\n\ndf = DataFrame(\n ;\n node_type = node_names_snake_case,\n flow_in_min,\n flow_in_max,\n flow_out_min,\n flow_out_max,\n control_in_min,\n control_in_max,\n control_out_min,\n control_out_max,\n)\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nnode_type\nflow_in_min\nflow_in_max\nflow_out_min\nflow_out_max\ncontrol_in_min\ncontrol_in_max\ncontrol_out_min\ncontrol_out_max\n\n\n\n\nbasin\n0\n∞\n0\n∞\n0\n1\n0\n∞\n\n\nlinear_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nmanning_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\ntabulated_rating_curve\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nfractional_flow\n1\n1\n1\n1\n0\n1\n0\n0\n\n\nlevel_boundary\n0\n∞\n0\n∞\n0\n0\n0\n0\n\n\nflow_boundary\n0\n0\n1\n∞\n0\n0\n0\n0\n\n\npump\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\noutlet\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nterminal\n1\n∞\n0\n0\n0\n0\n0\n0\n\n\ndiscrete_control\n0\n0\n0\n0\n0\n0\n1\n∞\n\n\npid_control\n0\n0\n0\n0\n0\n1\n1\n1\n\n\nuser_demand\n1\n1\n1\n1\n0\n0\n0\n0",
+ "text": "The tables below show the validation rules applied to the input to the Julia core before running the model.\n\n1 Connectivity\nIn 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.\n\n\nCode\nusing Ribasim\nusing DataFrames: DataFrame\nusing MarkdownTables\n\nnode_names_snake_case = Vector{Symbol}()\nnode_names_camel_case = Vector{Symbol}()\nfor (node_name, node_type) in zip(fieldnames(Ribasim.Parameters), fieldtypes(Ribasim.Parameters))\n if node_type <: Ribasim.AbstractParameterNode\n push!(node_names_snake_case, node_name)\n push!(node_names_camel_case, nameof(node_type))\n end\nend\n\nfunction to_symbol(b::Bool)::String\n return b ? \"✓\" : \"x\"\nend\n\n\ndf = DataFrame()\ndf[!, :downstream] = node_names_snake_case\n\nfor node_name in node_names_snake_case\n df[!, node_name] =\n [(to_symbol(node_name_ in Ribasim.neighbortypes(node_name))) for node_name_ in node_names_snake_case]\nend\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndownstream\nbasin\nlinear_resistance\nmanning_resistance\ntabulated_rating_curve\nfractional_flow\nlevel_boundary\nflow_boundary\npump\noutlet\nterminal\ndiscrete_control\npid_control\nuser_demand\n\n\n\n\nbasin\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nlinear_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\nmanning_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\ntabulated_rating_curve\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\nfractional_flow\nx\nx\nx\n✓\nx\nx\n✓\n✓\n✓\nx\n✓\nx\n✓\n\n\nlevel_boundary\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nflow_boundary\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npump\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\noutlet\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\nterminal\nx\nx\nx\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\ndiscrete_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npid_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n✓\nx\nx\n\n\nuser_demand\n✓\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\n\n\n\n\n\n2 Neighbor amounts\nThe table below shows for each node type between which bounds the amount of in- and outneighbors must be, for both flow and control edges.\n\n\nCode\nflow_in_min = Vector{String}()\nflow_in_max = Vector{String}()\nflow_out_min = Vector{String}()\nflow_out_max = Vector{String}()\ncontrol_in_min = Vector{String}()\ncontrol_in_max = Vector{String}()\ncontrol_out_min = Vector{String}()\ncontrol_out_max = Vector{String}()\n\nfunction unbounded(i::Int)::String\n return i == typemax(Int) ? \"∞\" : string(i)\nend\n\nfor node_name in node_names_camel_case\n bounds_flow = Ribasim.n_neighbor_bounds_flow(node_name)\n push!(flow_in_min, string(bounds_flow.in_min))\n push!(flow_in_max, unbounded(bounds_flow.in_max))\n push!(flow_out_min, string(bounds_flow.out_min))\n push!(flow_out_max, unbounded(bounds_flow.out_max))\n\n bounds_control = Ribasim.n_neighbor_bounds_control(node_name)\n push!(control_in_min, string(bounds_control.in_min))\n push!(control_in_max, unbounded(bounds_control.in_max))\n push!(control_out_min, string(bounds_control.out_min))\n push!(control_out_max, unbounded(bounds_control.out_max))\n\nend\n\ndf = DataFrame(\n ;\n node_type = node_names_snake_case,\n flow_in_min,\n flow_in_max,\n flow_out_min,\n flow_out_max,\n control_in_min,\n control_in_max,\n control_out_min,\n control_out_max,\n)\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nnode_type\nflow_in_min\nflow_in_max\nflow_out_min\nflow_out_max\ncontrol_in_min\ncontrol_in_max\ncontrol_out_min\ncontrol_out_max\n\n\n\n\nbasin\n0\n∞\n0\n∞\n0\n1\n0\n∞\n\n\nlinear_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nmanning_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\ntabulated_rating_curve\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nfractional_flow\n1\n1\n1\n1\n0\n1\n0\n0\n\n\nlevel_boundary\n0\n∞\n0\n∞\n0\n0\n0\n0\n\n\nflow_boundary\n0\n0\n1\n∞\n0\n0\n0\n0\n\n\npump\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\noutlet\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nterminal\n1\n∞\n0\n0\n0\n0\n0\n0\n\n\ndiscrete_control\n0\n0\n0\n0\n0\n0\n1\n∞\n\n\npid_control\n0\n0\n0\n0\n0\n1\n1\n1\n\n\nuser_demand\n1\n1\n1\n1\n0\n0\n0\n0",
"crumbs": [
"Julia core",
"Validation"
@@ -1155,18 +1173,25 @@
"text": "1 nodes.outlet\nnodes.outlet"
},
{
- "objectID": "python/reference/nodes.fractional_flow.html",
- "href": "python/reference/nodes.fractional_flow.html",
- "title": "1 nodes.fractional_flow",
+ "objectID": "python/reference/nodes.level_demand.html",
+ "href": "python/reference/nodes.level_demand.html",
+ "title": "1 nodes.level_demand",
"section": "",
- "text": "1 nodes.fractional_flow\nnodes.fractional_flow"
+ "text": "1 nodes.level_demand\nnodes.level_demand"
},
{
- "objectID": "python/reference/nodes.terminal.html",
- "href": "python/reference/nodes.terminal.html",
- "title": "1 nodes.terminal",
+ "objectID": "python/reference/nodes.level_boundary.html",
+ "href": "python/reference/nodes.level_boundary.html",
+ "title": "1 nodes.level_boundary",
"section": "",
- "text": "1 nodes.terminal\nnodes.terminal"
+ "text": "1 nodes.level_boundary\nnodes.level_boundary"
+ },
+ {
+ "objectID": "python/reference/nodes.flow_demand.html",
+ "href": "python/reference/nodes.flow_demand.html",
+ "title": "1 nodes.flow_demand",
+ "section": "",
+ "text": "1 nodes.flow_demand\nnodes.flow_demand"
},
{
"objectID": "python/reference/nodes.pid_control.html",
demand
Float64
\(m^3 s^{-1}\)
--
+non-negative
11 LevelDemand
-An LevelDemand
node associates a minimum and a maximum level with connected basins to be used by the allocation algorithm. Below the minimum level the basin has a demand of the supplied priority, above the maximum level the basin acts as a source, used by all nodes with demands in order of priority. The same LevelDemand
node can be used for basins in different subnetworks.
+A LevelDemand
node associates a minimum and a maximum level with connected basins to be used by the allocation algorithm. Below the minimum level the basin has a demand of the supplied priority, above the maximum level the basin acts as a source, used by all nodes with demands in order of priority. The same LevelDemand
node can be used for basins in different subnetworks.
@@ -1468,8 +1477,82 @@
-
-12 LevelBoundary
+
+12 FlowDemand
+A FlowDemand
node associates a non-consuming flow demand to a connector node (e.g. Pump
, TabulatedRatingCurve
) for one single priority. FlowDemand nodes can set a flow demand only for a single connector node.
+
+
+
+column
+type
+unit
+restriction
+
+
+
+
+node_id
+Int32
+-
+sorted
+
+
+priority
+Int32
+-
+positive
+
+
+demand
+Float64
+\(m^3 s^{-1}\)
+non-negative
+
+
+
+
+12.1 FlowDemand / time
+This table is the transient form of the FlowDemand
table, in which a time-dependent demand can be supplied. Similar to the static version, only a single priority per FlowDemand
node can be provided.
+
+
+
+column
+type
+unit
+restriction
+
+
+
+
+node_id
+Int32
+-
+sorted
+
+
+time
+DateTime
+-
+sorted per node id
+
+
+priority
+Int32
+-
+positive
+
+
+demand
+Float64
+\(m^3 s^{-1}\)
+non-negative
+
+
+
+
+
+
+13 LevelBoundary
Acts like an infinitely large basin where the level does not change by flow. This can be connected to a basin via a LinearResistance
. This boundary node will then exchange water with the basin based on the difference in water level between the two.
@@ -1501,8 +1584,8 @@ 12 LevelBoundary
-
-12.1 LevelBoundary / time
+
+13.1 LevelBoundary / time
This table is the transient form of the LevelBoundary
table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id
. With this the levels can be updated over time. In between the given times the level is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id
can be either in this table or in the static one, but not both.
@@ -1536,8 +1619,8 @@
-
-13 FlowBoundary
+
+14 FlowBoundary
Pump water to a destination node. We require that the edge connecting the flow boundary to the Basin should point towards the basin, so that positive flow corresponds to water being added to the model. The set flow rate will be pumped unless the intake storage (for a negative flow rate) is less than \(10~m^3\), in which case the flow rate will be linearly reduced to \(0~m^3/s\). Note that the connected node must always be a Basin.
@@ -1569,8 +1652,8 @@ 13 FlowBoundary<
-
-13.1 FlowBoundary / time
+
+14.1 FlowBoundary / time
This table is the transient form of the FlowBoundary
table. The only differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id
. With this the flow rates can be updated over time. In between the given times the flow rate is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id
can be either in this table or in the static one, but not both.
@@ -1604,8 +1687,8 @@
-
-14 LinearResistance
+
+15 LinearResistance
Flow proportional to the level difference between the connected basins.
@@ -1650,8 +1733,8 @@ 14 LinearResista
-
-15 ManningResistance
+
+16 ManningResistance
Flow through this connection is estimated by conservation of energy and the Manning-Gauckler formula to estimate friction losses.
@@ -1708,8 +1791,8 @@ 15 ManningResist
-
-16 Terminal
+
+17 Terminal
A terminal is a water sink without state or properties. Any water that flows into a terminal node is removed from the model. No water can come into the model from a terminal node. For example, terminal nodes can be used as a downstream boundary.
@@ -1730,11 +1813,11 @@ 16 Terminal
-
-17 DisceteControl
+
+18 DisceteControl
DiscreteControl is implemented based on VectorContinuousCallback.
-
-17.1 DiscreteControl / condition
+
+18.1 DiscreteControl / condition
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.
@@ -1791,8 +1874,8 @@
-17.2 DiscreteControl / logic
+
+18.2 DiscreteControl / logic
The logic schema defines which control states are triggered based on the truth of the conditions a DiscreteControl node listens to. DiscreteControl is applied in the Julia core as follows:
<
-
-18 PidControl
+
+19 PidControl
The PidControl node controls the level in a basin by continuously controlling the flow rate of a connected pump or outlet. See also PID controller. When A PidControl node is made inactive, the node under its control retains the last flow rate value, and the error integral is reset to 0.
In the future controlling the flow on a particular edge could be supported.
@@ -1923,8 +2006,8 @@ 18 PidControl
-
-18.1 PidControl / time
+
+19.1 PidControl / time
This table is the transient form of the PidControl
table. The differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id
. With this the target level and PID coefficients can be updated over time. In between the given times the these values interpolated linearly, and outside these values area constant given by the nearest time value. Note that a node_id
can be either in this table or in the static one, but not both.
@@ -1988,10 +2071,10 @@
-
-19 Results
-
-19.1 Basin - basin.arrow
+
+20 Results
+
+20.1 Basin - basin.arrow
The basin table contains results of the storage and level of each basin at every solver timestep. The initial condition is also written to the file.
@@ -2026,8 +2109,8 @@
The table is sorted by time, and per time it is sorted by node_id
.
-
-19.2 Flow - flow.arrow
+
+20.2 Flow - flow.arrow
The flow table contains calculated mean flows for every flow edge in the model. In the time column the start of the period is indicated.
@@ -2077,8 +2160,8 @@
The table is sorted by time, and per time the same edge_id
order is used, though not sorted. The edge_id
value is the same as the fid
written to the Edge table, and can be used to directly look up the Edge geometry. Flows that are added to the model at a node, have a missing edge_id
, and identical from_node_id
and to_node_id
. Flows out of the model always have a negative sign, and additions a positive sign.
-
-19.3 DiscreteControl - control.arrow
+
+20.3 DiscreteControl - control.arrow
The control table contains a record of each change of control state: when it happened, which control node was involved, to which control state it changed and based on which truth state.
@@ -2107,8 +2190,8 @@
-19.4 Allocation - allocation.arrow
+
+20.4 Allocation - allocation.arrow
The allocation table contains a record of allocation results: when it happened, for which node, in which allocation network, and what the demand, allocated flow and realized flow were.
@@ -2167,8 +2250,8 @@
-19.5 Allocation flow - allocation_flow.arrow
+
+20.5 Allocation flow - allocation_flow.arrow
The allocation flow table contains results of the optimized allocation flow on every edge in the model that is part of a subnetwork, for each time an optimization problem is solved (see also here). If in the model a main network and subnetwork(s) are specified, there are 2 different types of optimization for the subnetwork: collecting its total demand per priority (for allocating flow from the main network to the subnetwork), and allocating flow within the subnetwork. The column collect_demands
provides the distinction between these two optimization types.
diff --git a/core/validation.html b/core/validation.html
index 57202e552..8c7b5c388 100644
--- a/core/validation.html
+++ b/core/validation.html
@@ -262,7 +262,7 @@ Validation
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
@@ -385,7 +385,7 @@ 1 Connectivityx
x
x
-x
+✓
x
x
x
@@ -546,7 +546,7 @@ 1 Connectivity
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 edges.
-
+
Code
= Vector{String}()
diff --git a/python/examples_files/figure-html/cell-59-output-1.png b/python/examples_files/figure-html/cell-59-output-1.png
index fb18dde11..d234145e9 100644
Binary files a/python/examples_files/figure-html/cell-59-output-1.png and b/python/examples_files/figure-html/cell-59-output-1.png differ
diff --git a/python/examples_files/figure-html/cell-60-output-2.png b/python/examples_files/figure-html/cell-60-output-2.png
index eb25d2657..73061a701 100644
Binary files a/python/examples_files/figure-html/cell-60-output-2.png and b/python/examples_files/figure-html/cell-60-output-2.png differ
diff --git a/python/reference/index.html b/python/reference/index.html
index 27851c9c8..a3366d7cf 100644
--- a/python/reference/index.html
+++ b/python/reference/index.html
@@ -271,6 +271,14 @@ flow_in_min nodes.pid_control
+
+nodes.flow_demand
+
+
+
+nodes.level_demand
+
+
diff --git a/python/reference/nodes.flow_demand.html b/python/reference/nodes.flow_demand.html
new file mode 100644
index 000000000..471cab086
--- /dev/null
+++ b/python/reference/nodes.flow_demand.html
@@ -0,0 +1,543 @@
+
+
+
+
+
+
+
+
+
+Ribasim
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/python/reference/nodes.level_demand.html b/python/reference/nodes.level_demand.html
new file mode 100644
index 000000000..1aa216133
--- /dev/null
+++ b/python/reference/nodes.level_demand.html
@@ -0,0 +1,543 @@
+
+
+
+
+
+
+
+
+
+Ribasim
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/python/test-models.html b/python/test-models.html
index 10812175c..489cfa806 100644
--- a/python/test-models.html
+++ b/python/test-models.html
@@ -227,7 +227,7 @@ Test models
Ribasim developers use the following models in their testbench and in order to test new features.
-
+
Code
import ribasim_testmodels
@@ -319,154 +319,168 @@ Test models
+
+
+
+
+
+
+
+
+
+
diff --git a/python/test-models_files/figure-html/cell-2-output-11.png b/python/test-models_files/figure-html/cell-2-output-11.png
index 4fc0862b5..e1b284d9d 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-11.png and b/python/test-models_files/figure-html/cell-2-output-11.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-12.png b/python/test-models_files/figure-html/cell-2-output-12.png
index 41d5ed5aa..4fc0862b5 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-12.png and b/python/test-models_files/figure-html/cell-2-output-12.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-13.png b/python/test-models_files/figure-html/cell-2-output-13.png
index 057ce9a37..41d5ed5aa 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-13.png and b/python/test-models_files/figure-html/cell-2-output-13.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-14.png b/python/test-models_files/figure-html/cell-2-output-14.png
index 3700441cd..057ce9a37 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-14.png and b/python/test-models_files/figure-html/cell-2-output-14.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-15.png b/python/test-models_files/figure-html/cell-2-output-15.png
index 3ac7ed987..5ccd30a47 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-15.png and b/python/test-models_files/figure-html/cell-2-output-15.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-16.png b/python/test-models_files/figure-html/cell-2-output-16.png
index 51472f2e6..3ac7ed987 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-16.png and b/python/test-models_files/figure-html/cell-2-output-16.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-17.png b/python/test-models_files/figure-html/cell-2-output-17.png
index 28f13a6b3..4b9387c61 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-17.png and b/python/test-models_files/figure-html/cell-2-output-17.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-18.png b/python/test-models_files/figure-html/cell-2-output-18.png
index b7e5989cb..51472f2e6 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-18.png and b/python/test-models_files/figure-html/cell-2-output-18.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-19.png b/python/test-models_files/figure-html/cell-2-output-19.png
index 6feed0dcf..28f13a6b3 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-19.png and b/python/test-models_files/figure-html/cell-2-output-19.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-20.png b/python/test-models_files/figure-html/cell-2-output-20.png
index 48143149e..b7e5989cb 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-20.png and b/python/test-models_files/figure-html/cell-2-output-20.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-21.png b/python/test-models_files/figure-html/cell-2-output-21.png
index e23644dbf..6feed0dcf 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-21.png and b/python/test-models_files/figure-html/cell-2-output-21.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-22.png b/python/test-models_files/figure-html/cell-2-output-22.png
index 385f70f3c..48143149e 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-22.png and b/python/test-models_files/figure-html/cell-2-output-22.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-23.png b/python/test-models_files/figure-html/cell-2-output-23.png
index 30bfdf250..e23644dbf 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-23.png and b/python/test-models_files/figure-html/cell-2-output-23.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-24.png b/python/test-models_files/figure-html/cell-2-output-24.png
index c6cd3c340..385f70f3c 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-24.png and b/python/test-models_files/figure-html/cell-2-output-24.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-25.png b/python/test-models_files/figure-html/cell-2-output-25.png
index aec5c7b0c..30bfdf250 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-25.png and b/python/test-models_files/figure-html/cell-2-output-25.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-26.png b/python/test-models_files/figure-html/cell-2-output-26.png
index 59848dc9c..c6cd3c340 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-26.png and b/python/test-models_files/figure-html/cell-2-output-26.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-27.png b/python/test-models_files/figure-html/cell-2-output-27.png
index ca63191bd..aec5c7b0c 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-27.png and b/python/test-models_files/figure-html/cell-2-output-27.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-28.png b/python/test-models_files/figure-html/cell-2-output-28.png
index 2a311ae92..59848dc9c 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-28.png and b/python/test-models_files/figure-html/cell-2-output-28.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-29.png b/python/test-models_files/figure-html/cell-2-output-29.png
index 6cd33e1c7..ca63191bd 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-29.png and b/python/test-models_files/figure-html/cell-2-output-29.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-30.png b/python/test-models_files/figure-html/cell-2-output-30.png
index 8414c43e1..2a311ae92 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-30.png and b/python/test-models_files/figure-html/cell-2-output-30.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-31.png b/python/test-models_files/figure-html/cell-2-output-31.png
index 59aa41129..6cd33e1c7 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-31.png and b/python/test-models_files/figure-html/cell-2-output-31.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-32.png b/python/test-models_files/figure-html/cell-2-output-32.png
index bd21c153c..8414c43e1 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-32.png and b/python/test-models_files/figure-html/cell-2-output-32.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-33.png b/python/test-models_files/figure-html/cell-2-output-33.png
new file mode 100644
index 000000000..59aa41129
Binary files /dev/null and b/python/test-models_files/figure-html/cell-2-output-33.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-34.png b/python/test-models_files/figure-html/cell-2-output-34.png
new file mode 100644
index 000000000..bd21c153c
Binary files /dev/null and b/python/test-models_files/figure-html/cell-2-output-34.png differ
diff --git a/search.json b/search.json
index 3972ac4d9..80e7a708d 100644
--- a/search.json
+++ b/search.json
@@ -43,7 +43,7 @@
"href": "contribute/addnode.html#parameters",
"title": "Adding node types",
"section": "1.1 Parameters",
- "text": "1.1 Parameters\nThe parameters object (defined in solve.jl) passed to the ODE solver must be made aware of the new node type. Therefore define a struct in solve.jl which holds the data for each node of the new node type:\nstruct NewNodeType\n node_id::Vector{NodeID}\n # Other fields\nend\nThese fields do not have to correspond 1:1 with the input tables (see below). The vector with all node IDs that are of the new type in a given model is a mandatory field. Now you can:\n\nAdd new_node_type::NewNodeType to the Parameters object;\nAdd new_node_type = NewNodeType(db,config) to the function Parameters in create.jl and add new_node_type at the proper location in the Parameters constructor call.",
+ "text": "1.1 Parameters\nThe parameters object (defined in parameter.jl) passed to the ODE solver must be made aware of the new node type. Therefore define a struct in parameter.jl which holds the data for each node of the new node type:\nstruct NewNodeType\n node_id::Vector{NodeID}\n # Other fields\nend\nThese fields do not have to correspond 1:1 with the input tables (see below). The vector with all node IDs that are of the new type in a given model is a mandatory field. Now you can:\n\nAdd new_node_type::NewNodeType to the Parameters object;\nAdd new_node_type = NewNodeType(db,config) to the function Parameters in read.jl and add new_node_type at the proper location in the Parameters constructor call.",
"crumbs": [
"Contributing",
"Adding node types"
@@ -54,7 +54,7 @@
"href": "contribute/addnode.html#reading-from-configuration",
"title": "Adding node types",
"section": "1.2 Reading from configuration",
- "text": "1.2 Reading from configuration\nThere can be several schemas associated with a single node type. To define a schema for the new node type, add the following to validation.jl:\n@schema \"ribasim.newnodetype.static\" NewNodeTypeStatic\n\n\"\"\"\nnode_id: node ID of the NewNodeType node\n\"\"\"\n@version NewNodeTypeStaticV1 begin\n node_id::Int32\n # Other fields\nend\nHere Static refers to data that does not change over time. For naming conventions of these schemas see Node usage.\nvalidation.jl also deals with checking and applying a specific sorting order for the tabular data (default is sorting by node ID only), see sort_by_function and sorted_table!.\nNow we define the function that is called in the second bullet above, in create.jl:\nfunction NewNodeType(db::DB, config::Config)::NewNodeType\n static = load_structvector(db, config, NewNodeTypeStaticV1)\n defaults = (; foo = 1, bar = false)\n # Process potential control states in the static data\n parsed_parameters, valid = parse_static_and_time(db, config, \"Outlet\"; static, defaults)\n\n if !valid\n error(\"Errors occurred when parsing NewNodeType data.\")\n end\n\n # Unpack the fields of static as inputs for the NewNodeType constructor\n return NewNodeType(\n NodeID.(NodeType.NewNodeType, parsed_parameters.node_id),\n parsed_parameters.some_property,\n parsed_parameters.control_mapping)\nend",
+ "text": "1.2 Reading from configuration\nThere can be several schemas associated with a single node type. To define a schema for the new node type, add the following to schema.jl:\n@schema \"ribasim.newnodetype.static\" NewNodeTypeStatic\n\n\"\"\"\nnode_id: node ID of the NewNodeType node\n\"\"\"\n@version NewNodeTypeStaticV1 begin\n node_id::Int32\n # Other fields\nend\nHere static refers to data that does not change over time. For naming conventions of these schemas see Node usage. If a new schema contains a priority column for allocation, it must also be added to the list of all such schemas in the function get_all_priorities in util.jl.\nvalidation.jl deals with checking and applying a specific sorting order for the tabular data (default is sorting by node ID only), see sort_by_function and sorted_table!.\nNow we define the function that is called in the second bullet above, in read.jl:\nfunction NewNodeType(db::DB, config::Config)::NewNodeType\n static = load_structvector(db, config, NewNodeTypeStaticV1)\n defaults = (; foo = 1, bar = false)\n # Process potential control states in the static data\n parsed_parameters, valid = parse_static_and_time(db, config, \"NewNodeType\"; static, defaults)\n\n if !valid\n error(\"Errors occurred when parsing NewNodeType data.\")\n end\n\n # Unpack the fields of static as inputs for the NewNodeType constructor\n return NewNodeType(\n NodeID.(NodeType.NewNodeType, parsed_parameters.node_id),\n parsed_parameters.some_property,\n parsed_parameters.control_mapping)\nend",
"crumbs": [
"Contributing",
"Adding node types"
@@ -76,7 +76,7 @@
"href": "contribute/addnode.html#the-jacobian",
"title": "Adding node types",
"section": "1.4 The Jacobian",
- "text": "1.4 The Jacobian\nSee Equations for a mathematical description of the Jacobian.\nBefore the Julia core runs its simulation, the sparsity structure jac_prototype of \\(J\\) is determined with get_jac_prototype in utils.jl. This function runs trough all node types and looks for nodes that create dependencies between states. It creates a sparse matrix of zeros and ones, where the ones denote locations of possible non-zeros in \\(J\\).\nWe divide the various node types in groups based on what type of state dependencies they yield, and these groups are discussed below. Each group has its own method update_jac_prototype! in utils.jl for the sparsity structure induced by nodes of that group. NewNodeType should be added to the signature of one these methods, or to the list of node types that do not contribute to the Jacobian in the method of update_jac_prototype! whose signature contains node::AbstractParameterNode. Of course it is also possible that a new method of update_jac_prototype! has to be introduced.\nThe current dependency groups are:\n\nOut-neighbor dependencies: examples are TabulatedRatingCurve, Pump (the latter only in the reduction factor regime and not PID controlled). If the in-neighbor of a node of this group is a basin, then the storage of this basin affects itself and the storage of the outneighbor (or the basin one node further if it is connected with a FractionalFlow in between) if that is also a basin;\nEither-neighbor dependencies: examples are LinearResistance, ManningResistance. If either the in-neighbor or out-neighbor of a node of this group is a basin, the storage of this basin depends on itself. If both the in-neighbor and the out-neighbor are basins, their storages also depend on eachother.\nThe PidControl node is a special case which is discussed in equations.\n\nUsing jac_prototype the Jacobian of water_balance! is computed automatically using ForwardDiff.jl with memory management provided by PreallocationTools.jl. These computations make use of DiffCache and dual numbers.",
+ "text": "1.4 The Jacobian\nSee Equations for a mathematical description of the Jacobian.\nBefore the Julia core runs its simulation, the sparsity structure jac_prototype of \\(J\\) is determined with get_jac_prototype in sparsity.jl. This function runs trough all node types and looks for nodes that create dependencies between states. It creates a sparse matrix of zeros and ones, where the ones denote locations of possible non-zeros in \\(J\\). Note that only nodes that set flows in the physical layer (or have their own state like PidControl) affect the sparsity structure.\nWe divide the various node types in groups based on what type of state dependencies they yield, and these groups are discussed below. Each group has its own method update_jac_prototype! in utils.jl for the sparsity structure induced by nodes of that group. NewNodeType should be added to the signature of one these methods, or to the list of node types that do not contribute to the Jacobian in the method of update_jac_prototype! whose signature contains node::AbstractParameterNode. Of course it is also possible that a new method of update_jac_prototype! has to be introduced.\nThe current dependency groups are:\n\nOut-neighbor dependencies: examples are TabulatedRatingCurve, Pump (the latter only in the reduction factor regime and not PID controlled). If the in-neighbor of a node of this group is a basin, then the storage of this basin affects itself and the storage of the outneighbor (or the basin one node further if it is connected with a FractionalFlow in between) if that is also a basin;\nEither-neighbor dependencies: examples are LinearResistance, ManningResistance. If either the in-neighbor or out-neighbor of a node of this group is a basin, the storage of this basin depends on itself. If both the in-neighbor and the out-neighbor are basins, their storages also depend on eachother.\nThe PidControl node is a special case which is discussed in equations.\n\nUsing jac_prototype the Jacobian of water_balance! is computed automatically using ForwardDiff.jl with memory management provided by PreallocationTools.jl. These computations make use of DiffCache and dual numbers.",
"crumbs": [
"Contributing",
"Adding node types"
@@ -87,7 +87,7 @@
"href": "contribute/addnode.html#python-class",
"title": "Adding node types",
"section": "2.1 Python class",
- "text": "2.1 Python class\nCreate a new file python/ribasim/ribasim/node_types/new_node_type.py which is structured as follows:\nfrom typing import Optional\n\nimport pandera as pa\nfrom pandera.engines.pandas_engine import PydanticModel\nfrom pandera.typing import DataFrame\nfrom pydantic import ConfigDict\n\nfrom ribasim import models\nfrom ribasim.input_base import TableModel\n\n__all__ = (\"NewNodeType\",)\n\nclass StaticSchema(pa.SchemaModel):\n class Config:\n \"\"\"Config with dataframe-level data type.\"\"\"\n\n dtype = PydanticModel(models.NewNodeTypeStatic)\n\n# Possible other schemas\n\n\nclass NewNodeType(TableModel):\n \"\"\"\n Description of this node type.\n\n Parameters\n ----------\n static: pandas.DataFrame\n table with data for this node type.\n\n possible other schemas\n \"\"\"\n\n static: DataFrame[StaticSchema] | None\n # possible other schemas\n\n model_config = ConfigDict(validate_assignment=True)\n\n def sort(self):\n self.static.sort_values(\"node_id\", ignore_index=True, inplace=True)\nThe sort method should implement the same sorting as in validation.jl.\nNow in both python/ribasim/ribasim/__init__.py and python/ribasim/ribasim/node_types/__init__.py add\n\nfrom ribasim.node_types.new_node_type import NewNodeType;\n\"NewNodeType\" to __all__.\n\nIn python/ribasim/ribasim/model.py, add\n\nfrom ribasim.new_node_type import NewNodeType;\nnew_node_type as a parameter and in the docstring of the Model class.\n\nIn python/ribasim/ribasim/geometry/node.py add a color and shape description in the MARKERS and COLORS dictionaries.",
+ "text": "2.1 Python class\nIn python/ribasim/ribasim/config.py add\n\nthe above defined schemas to the imports from ribasim.schemas. This requires code generation to work, see Finishing up;\na class of the following form with all schemas associated with the node type:\n\nclass NewNodeType(NodeModel):\n static: TableModel[NewNodeTypeStaticSchema] = Field(\n default_factory=TableModel[NewNodeTypeStaticSchema],\n json_schema_extra={\"sort_keys\": [\"node_id\"]},\n )\nIn python/ribasim/ribasim/__init__.py add\n\nNewNodeType to the imports from ribasim.config;\n\"NewNodeType\" to __all__.\n\nIn python/ribasim/ribasim/model.py, add\n\nNewNodeType to the imports from ribasim.config;\nnew_node_type as a parameter and in the docstring of the Model class.\n\nIn python/ribasim/ribasim/geometry/node.py add a color and shape description in the MARKERS and COLORS dictionaries.",
"crumbs": [
"Contributing",
"Adding node types"
@@ -241,7 +241,7 @@
"href": "python/reference/index.html",
"title": "1 API Reference",
"section": "",
- "text": "The Model class represents an entire Ribasim model.\n\n\n\nModel\n\n\n\n\n\n\n\nThe Edge database layer.\n\n\n\nEdgeTable\nDefines the connections between nodes.\n\n\n\n\n\n\nAvailable node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control",
+ "text": "The Model class represents an entire Ribasim model.\n\n\n\nModel\n\n\n\n\n\n\n\nThe Edge database layer.\n\n\n\nEdgeTable\nDefines the connections between nodes.\n\n\n\n\n\n\nAvailable node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control\n\n\n\nnodes.flow_demand\n\n\n\nnodes.level_demand",
"crumbs": [
"Python tooling",
"API Reference"
@@ -274,7 +274,7 @@
"href": "python/reference/index.html#node-types",
"title": "1 API Reference",
"section": "",
- "text": "Available node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control",
+ "text": "Available node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control\n\n\n\nnodes.flow_demand\n\n\n\nnodes.level_demand",
"crumbs": [
"Python tooling",
"API Reference"
@@ -288,11 +288,18 @@
"text": "1 nodes.user_demand\nnodes.user_demand"
},
{
- "objectID": "python/reference/nodes.level_boundary.html",
- "href": "python/reference/nodes.level_boundary.html",
- "title": "1 nodes.level_boundary",
+ "objectID": "python/reference/nodes.terminal.html",
+ "href": "python/reference/nodes.terminal.html",
+ "title": "1 nodes.terminal",
"section": "",
- "text": "1 nodes.level_boundary\nnodes.level_boundary"
+ "text": "1 nodes.terminal\nnodes.terminal"
+ },
+ {
+ "objectID": "python/reference/nodes.fractional_flow.html",
+ "href": "python/reference/nodes.fractional_flow.html",
+ "title": "1 nodes.fractional_flow",
+ "section": "",
+ "text": "1 nodes.fractional_flow\nnodes.fractional_flow"
},
{
"objectID": "python/reference/nodes.tabulated_rating_curve.html",
@@ -398,7 +405,7 @@
"href": "build/index.html#types",
"title": "1 API Reference",
"section": "1.2 Types",
- "text": "1.2 Types\n# Ribasim.Allocation — Type.\nObject for all information about allocation allocationnetworkids: The unique sorted allocation network IDs allocation models: The allocation models for the main network and subnetworks corresponding to allocationnetworkids mainnetworkconnections: (fromid, toid) from the main network to the subnetwork per subnetwork priorities: All used priority values. subnetworkdemands: The demand of an edge from the main network to a subnetwork recorddemand: A record of demands and allocated flows for nodes that have these. record_flow: A record of all flows computed by allocation optimization, eventually saved to output file\nsource\n# Ribasim.AllocationModel — Type.\nStore information for a subnetwork used for allocation.\nallocationnetworkid: The ID of this allocation network capacity: The capacity per edge of the allocation network, as constrained by nodes that have a maxflowrate problem: The JuMP.jl model for solving the allocation problem Δt_allocation: The time interval between consecutive allocation solves\nsource\n# Ribasim.AllocationModel — Method.\nConstruct the JuMP.jl problem for allocation.\nInputs\np: Ribasim problem parameters Δt_allocation: The timestep between successive allocation solves\nOutputs\nAn AllocationModel object.\nsource\n# Ribasim.Basin — Type.\nRequirements:\n\nMust be positive: precipitation, evaporation, infiltration, drainage\nIndex points to a Basin\nvolume, area, level must all be positive and monotonic increasing.\n\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of vectors or Arrow Tables, and is added to avoid type instabilities. The nodeid are Indices to support fast lookup of e.g. currentlevel using ID.\nif autodiff T = DiffCache{Vector{Float64}} else T = Vector{Float64} end\nsource\n# Ribasim.DiscreteControl — Type.\nnodeid: node ID of the DiscreteControl node; these are not unique but repeated by the amount of conditions of this DiscreteControl node listennodeid: the ID of the node being condition on variable: the name of the variable in the condition greaterthan: The threshold value in the condition conditionvalue: The current value of each condition controlstate: Dictionary: node ID => (control state, control state start) logic_mapping: Dictionary: (control node ID, truth state) => control state record: Namedtuple with discrete control information for results\nsource\n# Ribasim.EdgeMetadata — Type.\nType for storing metadata of edges in the graph: id: ID of the edge (only used for labeling flow output) type: type of the edge allocationnetworkidsource: ID of allocation network where this edge is a source (0 if not a source) fromid: the node ID of the source node toid: the node ID of the destination node allocationflow: whether this edge has a flow in an allocation network node_ids: if this edge has allocation flow, these are all the nodes from the physical layer this edge consists of\nsource\n# Ribasim.FlatVector — Type.\nstruct FlatVector{T} <: AbstractVector{T}\nA FlatVector is an AbstractVector that iterates the T of a Vector{Vector{T}}.\nEach inner vector is assumed to be of equal length.\nIt is similar to Iterators.flatten, though that doesn’t work with the Tables.Column interface, which needs length and getindex support.\nsource\n# Ribasim.FlowBoundary — Type.\nnodeid: node ID of the FlowBoundary node active: whether this node is active and thus contributes flow flowrate: target flow rate\nsource\n# Ribasim.FractionalFlow — Type.\nRequirements:\n\nfrom: must be (TabulatedRatingCurve,) node\nto: must be (Basin,) node\nfraction must be positive.\n\nnodeid: node ID of the TabulatedRatingCurve node fraction: The fraction in [0,1] of flow the node lets through controlmapping: dictionary from (nodeid, controlstate) to fraction\nsource\n# Ribasim.InNeighbors — Type.\nIterate over incoming neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.LevelBoundary — Type.\nnode_id: node ID of the LevelBoundary node active: whether this node is active level: the fixed level of this ‘infinitely big basin’\nsource\n# Ribasim.LevelDemand — Type.\nnodeid: node ID of the LevelDemand node minlevel: The minimum target level of the connected basin(s) max_level: The maximum target level of the connected basin(s) priority: If in a shortage state, the priority of the demand of the connected basin(s)\nsource\n# Ribasim.LinearResistance — Type.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\n\nnodeid: node ID of the LinearResistance node active: whether this node is active and thus contributes flows resistance: the resistance to flow; Q*unlimited = Δh/resistancemax_flow_rate: the maximum flow rate allowed through the node;Q = clamp(Q*unlimited, -max*flow*rate, max*flow*rate) controlmapping: dictionary from (nodeid, controlstate) to resistance and/or active state\nsource\n# Ribasim.ManningResistance — Type.\nThis is a simple Manning-Gauckler reach connection.\n\nLength describes the reach length.\nroughness describes Manning’s n in (SI units).\n\nThe profile is described by a trapezoid:\n \\ / ^\n \\ / |\n \\ / | dz\nbottom \\______/ |\n^ <--->\n| dy\n| <------>\n| width\n|\n|\n+ datum (e.g. MSL)\nWith profile_slope = dy / dz. A rectangular profile requires a slope of 0.0.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\nlength > 0\nroughess > 0\nprofile_width >= 0\nprofile_slope >= 0\n(profilewidth == 0) xor (profileslope == 0)\n\nsource\n# Ribasim.Model — Type.\nModel(config_path::AbstractString)\nModel(config::Config)\nInitialize a Model.\nThe Model struct is an initialized model, combined with the Config used to create it and saved results. The Basic Model Interface (BMI) is implemented on the Model. A Model can be created from the path to a TOML configuration file, or a Config object.\nsource\n# Ribasim.NodeMetadata — Type.\nType for storing metadata of nodes in the graph type: type of the node allocationnetworkid: Allocation network ID (0 if not in subnetwork)\nsource\n# Ribasim.OutNeighbors — Type.\nIterate over outgoing neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.Outlet — Type.\nnodeid: node ID of the Outlet node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the outlet maxflowrate: The maximum flow rate of the outlet controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this outlet is governed by PID control\nsource\n# Ribasim.PidControl — Type.\nPID control currently only supports regulating basin levels.\nnodeid: node ID of the PidControl node active: whether this node is active and thus sets flow rates listennodeid: the id of the basin being controlled pidparams: a vector interpolation for parameters changing over time. The parameters are respectively target, proportional, integral, derivative, where the last three are the coefficients for the PID equation. error: the current error; basintarget - currentlevel\nsource\n# Ribasim.Pump — Type.\nnodeid: node ID of the Pump node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the pump maxflowrate: The maximum flow rate of the pump controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this pump is governed by PID control\nsource\n# Ribasim.Subgrid — Type.\nSubgrid linearly interpolates basin levels.\nsource\n# Ribasim.TabulatedRatingCurve — Type.\nstruct TabulatedRatingCurve{C}\nRating curve from level to flow rate. The rating curve is a lookup table with linear interpolation in between. Relation can be updated in time, which is done by moving data from the time field into the tables, which is done in the update_tabulated_rating_curve callback.\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of Vectors or Arrow Primitives, and is added to avoid type instabilities.\nnodeid: node ID of the TabulatedRatingCurve node active: whether this node is active and thus contributes flows tables: The current Q(h) relationships time: The time table used for updating the tables controlmapping: dictionary from (nodeid, controlstate) to Q(h) and/or active state\nsource\n# Ribasim.Terminal — Type.\nnode_id: node ID of the Terminal node\nsource\n# Ribasim.UserDemand — Type.\ndemand: water flux demand of UserDemand per priority over time. Each UserDemand has a demand for all priorities, which is 0.0 if it is not provided explicitly. realizedbmi: Cumulative inflow volume, for read or reset by BMI only. active: whether this node is active and thus demands water allocated: water flux currently allocated to UserDemand per priority returnfactor: the factor in [0,1] of how much of the abstracted water is given back to the system min_level: The level of the source basin below which the UserDemand does not abstract\nsource\n# Ribasim.config.Config — Method.\nConfig(config_path::AbstractString; kwargs...)\nParse a TOML file to a Config. Keys can be overruled using keyword arguments. To overrule keys from a subsection, e.g. dt from the solver section, use underscores: solver_dt.\nsource",
+ "text": "1.2 Types\n# Ribasim.Allocation — Type.\nObject for all information about allocation allocationnetworkids: The unique sorted allocation network IDs allocation models: The allocation models for the main network and subnetworks corresponding to allocationnetworkids mainnetworkconnections: (fromid, toid) from the main network to the subnetwork per subnetwork priorities: All used priority values. subnetworkdemands: The demand of an edge from the main network to a subnetwork recorddemand: A record of demands and allocated flows for nodes that have these. record_flow: A record of all flows computed by allocation optimization, eventually saved to output file\nsource\n# Ribasim.AllocationModel — Type.\nStore information for a subnetwork used for allocation.\nallocationnetworkid: The ID of this allocation network capacity: The capacity per edge of the allocation network, as constrained by nodes that have a maxflowrate problem: The JuMP.jl model for solving the allocation problem Δt_allocation: The time interval between consecutive allocation solves\nsource\n# Ribasim.AllocationModel — Method.\nConstruct the JuMP.jl problem for allocation.\nInputs\nallocationnetworkid: the ID of this allocation network p: Ribasim problem parameters Δt_allocation: The timestep between successive allocation solves\nOutputs\nAn AllocationModel object.\nsource\n# Ribasim.Basin — Type.\nRequirements:\n\nMust be positive: precipitation, evaporation, infiltration, drainage\nIndex points to a Basin\nvolume, area, level must all be positive and monotonic increasing.\n\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of vectors or Arrow Tables, and is added to avoid type instabilities. The nodeid are Indices to support fast lookup of e.g. currentlevel using ID.\nif autodiff T = DiffCache{Vector{Float64}} else T = Vector{Float64} end\nsource\n# Ribasim.DiscreteControl — Type.\nnodeid: node ID of the DiscreteControl node; these are not unique but repeated by the amount of conditions of this DiscreteControl node listennodeid: the ID of the node being condition on variable: the name of the variable in the condition greaterthan: The threshold value in the condition conditionvalue: The current value of each condition controlstate: Dictionary: node ID => (control state, control state start) logic_mapping: Dictionary: (control node ID, truth state) => control state record: Namedtuple with discrete control information for results\nsource\n# Ribasim.EdgeMetadata — Type.\nType for storing metadata of edges in the graph: id: ID of the edge (only used for labeling flow output) type: type of the edge allocationnetworkidsource: ID of allocation network where this edge is a source (0 if not a source) fromid: the node ID of the source node toid: the node ID of the destination node allocationflow: whether this edge has a flow in an allocation network node_ids: if this edge has allocation flow, these are all the nodes from the physical layer this edge consists of\nsource\n# Ribasim.FlatVector — Type.\nstruct FlatVector{T} <: AbstractVector{T}\nA FlatVector is an AbstractVector that iterates the T of a Vector{Vector{T}}.\nEach inner vector is assumed to be of equal length.\nIt is similar to Iterators.flatten, though that doesn’t work with the Tables.Column interface, which needs length and getindex support.\nsource\n# Ribasim.FlowBoundary — Type.\nnodeid: node ID of the FlowBoundary node active: whether this node is active and thus contributes flow flowrate: target flow rate\nsource\n# Ribasim.FractionalFlow — Type.\nRequirements:\n\nfrom: must be (TabulatedRatingCurve,) node\nto: must be (Basin,) node\nfraction must be positive.\n\nnodeid: node ID of the TabulatedRatingCurve node fraction: The fraction in [0,1] of flow the node lets through controlmapping: dictionary from (nodeid, controlstate) to fraction\nsource\n# Ribasim.InNeighbors — Type.\nIterate over incoming neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.LevelBoundary — Type.\nnode_id: node ID of the LevelBoundary node active: whether this node is active level: the fixed level of this ‘infinitely big basin’\nsource\n# Ribasim.LevelDemand — Type.\nnodeid: node ID of the LevelDemand node minlevel: The minimum target level of the connected basin(s) max_level: The maximum target level of the connected basin(s) priority: If in a shortage state, the priority of the demand of the connected basin(s)\nsource\n# Ribasim.LinearResistance — Type.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\n\nnodeid: node ID of the LinearResistance node active: whether this node is active and thus contributes flows resistance: the resistance to flow; Q*unlimited = Δh/resistancemax_flow_rate: the maximum flow rate allowed through the node;Q = clamp(Q*unlimited, -max*flow*rate, max*flow*rate) controlmapping: dictionary from (nodeid, controlstate) to resistance and/or active state\nsource\n# Ribasim.ManningResistance — Type.\nThis is a simple Manning-Gauckler reach connection.\n\nLength describes the reach length.\nroughness describes Manning’s n in (SI units).\n\nThe profile is described by a trapezoid:\n \\ / ^\n \\ / |\n \\ / | dz\nbottom \\______/ |\n^ <--->\n| dy\n| <------>\n| width\n|\n|\n+ datum (e.g. MSL)\nWith profile_slope = dy / dz. A rectangular profile requires a slope of 0.0.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\nlength > 0\nroughess > 0\nprofile_width >= 0\nprofile_slope >= 0\n(profilewidth == 0) xor (profileslope == 0)\n\nsource\n# Ribasim.Model — Type.\nModel(config_path::AbstractString)\nModel(config::Config)\nInitialize a Model.\nThe Model struct is an initialized model, combined with the Config used to create it and saved results. The Basic Model Interface (BMI) is implemented on the Model. A Model can be created from the path to a TOML configuration file, or a Config object.\nsource\n# Ribasim.NodeMetadata — Type.\nType for storing metadata of nodes in the graph type: type of the node allocationnetworkid: Allocation network ID (0 if not in subnetwork)\nsource\n# Ribasim.OutNeighbors — Type.\nIterate over outgoing neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.Outlet — Type.\nnodeid: node ID of the Outlet node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the outlet maxflowrate: The maximum flow rate of the outlet controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this outlet is governed by PID control\nsource\n# Ribasim.PidControl — Type.\nPID control currently only supports regulating basin levels.\nnodeid: node ID of the PidControl node active: whether this node is active and thus sets flow rates listennodeid: the id of the basin being controlled pidparams: a vector interpolation for parameters changing over time. The parameters are respectively target, proportional, integral, derivative, where the last three are the coefficients for the PID equation. error: the current error; basintarget - currentlevel\nsource\n# Ribasim.Pump — Type.\nnodeid: node ID of the Pump node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the pump maxflowrate: The maximum flow rate of the pump controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this pump is governed by PID control\nsource\n# Ribasim.Subgrid — Type.\nSubgrid linearly interpolates basin levels.\nsource\n# Ribasim.TabulatedRatingCurve — Type.\nstruct TabulatedRatingCurve{C}\nRating curve from level to flow rate. The rating curve is a lookup table with linear interpolation in between. Relation can be updated in time, which is done by moving data from the time field into the tables, which is done in the update_tabulated_rating_curve callback.\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of Vectors or Arrow Primitives, and is added to avoid type instabilities.\nnodeid: node ID of the TabulatedRatingCurve node active: whether this node is active and thus contributes flows tables: The current Q(h) relationships time: The time table used for updating the tables controlmapping: dictionary from (nodeid, controlstate) to Q(h) and/or active state\nsource\n# Ribasim.Terminal — Type.\nnode_id: node ID of the Terminal node\nsource\n# Ribasim.UserDemand — Type.\ndemand: water flux demand of UserDemand per priority over time. Each UserDemand has a demand for all priorities, which is 0.0 if it is not provided explicitly. realizedbmi: Cumulative inflow volume, for read or reset by BMI only. active: whether this node is active and thus demands water allocated: water flux currently allocated to UserDemand per priority returnfactor: the factor in [0,1] of how much of the abstracted water is given back to the system min_level: The level of the source basin below which the UserDemand does not abstract\nsource\n# Ribasim.config.Config — Method.\nConfig(config_path::AbstractString; kwargs...)\nParse a TOML file to a Config. Keys can be overruled using keyword arguments. To overrule keys from a subsection, e.g. dt from the solver section, use underscores: solver_dt.\nsource",
"crumbs": [
"Julia core",
"API Reference"
@@ -409,7 +416,7 @@
"href": "build/index.html#functions",
"title": "1 API Reference",
"section": "1.3 Functions",
- "text": "1.3 Functions\n# BasicModelInterface.finalize — Method.\nBMI.finalize(model::Model)::Model\nWrite all results to the configured files.\nsource\n# BasicModelInterface.initialize — Method.\nBMI.initialize(T::Type{Model}, config_path::AbstractString)::Model\nInitialize a Model from the path to the TOML configuration file.\nsource\n# CommonSolve.solve! — Method.\nsolve!(model::Model)::ODESolution\nSolve a Model until the configured endtime.\nsource\n# Ribasim.add_basin_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a basin.\nsource\n# Ribasim.add_constraints_absolute_value! — Method.\nMinimizing |expr| can be achieved by introducing a new variable exprabs and posing the following constraints: exprabs >= expr expr_abs >= -expr\nsource\n# Ribasim.add_constraints_absolute_value_basin! — Method.\nAdd constraints so that variables Fabsbasin act as the absolute value of the expression comparing flow to a basin to its demand.\nsource\n# Ribasim.add_constraints_absolute_value_user_demand! — Method.\nAdd constraints so that variables Fabsuser_demand act as the absolute value of the expression comparing flow to a UserDemand to its demand.\nsource\n# Ribasim.add_constraints_basin_flow! — Method.\nAdd the Basin flow constraints to the allocation problem. The constraint indices are the Basin node IDs.\nConstraint: flow out of basin <= basin capacity\nsource\n# Ribasim.add_constraints_capacity! — Method.\nAdd the flow capacity constraints to the allocation problem. Only finite capacities get a constraint. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over edge <= edge capacity\nsource\n# Ribasim.add_constraints_flow_conservation! — Method.\nAdd the flow conservation constraints to the allocation problem. The constraint indices are UserDemand node IDs.\nConstraint: sum(flows out of node node) == flows into node + flow from storage and vertical fluxes\nsource\n# Ribasim.add_constraints_fractional_flow! — Method.\nAdd the fractional flow constraints to the allocation problem. The constraint indices are allocation edges over a fractional flow node.\nConstraint: flow after fractional_flow node <= fraction * inflow\nsource\n# Ribasim.add_constraints_source! — Method.\nAdd the source constraints to the allocation problem. The actual threshold values will be set before each allocation solve. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over source edge <= source flow in subnetwork\nsource\n# Ribasim.add_constraints_user_demand_returnflow! — Method.\nAdd the UserDemand returnflow constraints to the allocation problem. The constraint indices are UserDemand node IDs.\nConstraint: outflow from userdemand <= return factor inflow to user*demand\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the flow over the edge on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the existing flow over the edge between the given nodes.\nsource\n# Ribasim.add_objective_term! — Function.\nAdd a term to the objective function given by the objective type, depending in the provided flow variable and the associated demand.\nsource\n# Ribasim.add_subnetwork_connections! — Method.\nAdd the edges connecting the main network work to a subnetwork to both the main network and subnetwork allocation network.\nsource\n# Ribasim.add_user_demand_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a UserDemand.\nsource\n# Ribasim.add_variables_absolute_value! — Method.\nCertain allocation distribution types use absolute values in the objective function. Since most optimization packages do not support the absolute value function directly, New variables are introduced that act as the absolute value of an expression by posing the appropriate constraints.\nsource\n# Ribasim.add_variables_basin! — Method.\nAdd the variables for supply/demand of a basin to the problem. The variable indices are the node_ids of the basins in the subnetwork.\nsource\n# Ribasim.add_variables_flow! — Method.\nAdd the flow variables F to the allocation problem. The variable indices are (edgesourceid, edgedstid). Non-negativivity constraints are also immediately added to the flow variables.\nsource\n# Ribasim.adjust_basin_capacities! — Method.\nSet the values of the basin outflows. 2 cases:\n\nBefore the first allocation solve, set the capacities to their full capacity if there is surplus storage;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the capacities.\n\nsource\n# Ribasim.adjust_edge_capacities! — Method.\nSet the values of the edge capacities. 2 cases:\n\nBefore the first allocation solve, set the edge capacities to their full capacity;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the edge capacities.\n\nsource\n# Ribasim.adjust_source_capacities! — Method.\nAdjust the source flows.\nsource\n# Ribasim.all_neighbor_labels_type — Method.\nGet the in- and outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.allocate! — Method.\nUpdate the allocation optimization problem for the given subnetwork with the problem state and flows, solve the allocation problem and assign the results to the UserDemand.\nsource\n# Ribasim.allocation_graph — Method.\nBuild the graph used for the allocation problem.\nsource\n# Ribasim.allocation_graph_used_nodes! — Method.\nFind all nodes in the subnetwork which will be used in the allocation network. Some nodes are skipped to optimize allocation optimization.\nsource\n# Ribasim.allocation_path_exists_in_graph — Method.\nFind out whether a path exists between a start node and end node in the given allocation network.\nsource\n# Ribasim.allocation_problem — Method.\nConstruct the allocation problem for the current subnetwork as a JuMP.jl model.\nsource\n# Ribasim.allocation_table — Method.\nCreate an allocation result table for the saved data\nsource\n# Ribasim.assign_allocations! — Method.\nAssign the allocations to the UserDemand as determined by the solution of the allocation problem.\nsource\n# Ribasim.avoid_using_own_returnflow! — Method.\nRemove allocation UserDemand return flow edges that are upstream of the UserDemand itself.\nsource\n# Ribasim.basin_bottom — Method.\nReturn the bottom elevation of the basin with index i, or nothing if it doesn’t exist\nsource\n# Ribasim.basin_bottoms — Method.\nGet the bottom on both ends of a node. If only one has a bottom, use that for both.\nsource\n# Ribasim.basin_table — Method.\nCreate the basin result table from the saved data\nsource\n# Ribasim.create_callbacks — Method.\nCreate the different callbacks that are used to store results and feed the simulation with new data. The different callbacks are combined to a CallbackSet that goes to the integrator. Returns the CallbackSet and the SavedValues for flow.\nsource\n# Ribasim.create_graph — Method.\nReturn a directed metagraph with data of nodes (NodeMetadata): NodeMetadata\nand data of edges (EdgeMetadata): EdgeMetadata\nsource\n# Ribasim.create_storage_tables — Method.\nRead the Basin / profile table and return all area and level and computed storage values\nsource\n# Ribasim.datetime_since — Method.\ndatetime_since(t::Real, t0::DateTime)::DateTime\nConvert a Real that represents the seconds passed since the simulation start to the nearest DateTime. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.datetimes — Method.\nGet all saved times as a Vector{DateTime}\nsource\n# Ribasim.discrete_control_affect! — Method.\nChange parameters based on the control logic.\nsource\n# Ribasim.discrete_control_affect_downcrossing! — Method.\nAn downcrossing means that a condition (always greater than) becomes false.\nsource\n# Ribasim.discrete_control_affect_upcrossing! — Method.\nAn upcrossing means that a condition (always greater than) becomes true.\nsource\n# Ribasim.discrete_control_condition — Method.\nListens for changes in condition truths.\nsource\n# Ribasim.discrete_control_table — Method.\nCreate a discrete control result table from the saved data\nsource\n# Ribasim.expand_logic_mapping — Method.\nReplace the truth states in the logic mapping which contain wildcards with all possible explicit truth states.\nsource\n# Ribasim.find_allocation_graph_edges! — Method.\nThis loop finds allocation network edges in several ways:\n\nBetween allocation network nodes whose equivalent in the subnetwork are directly connected\nBetween allocation network nodes whose equivalent in the subnetwork are connected with one or more allocation network nodes in between\n\nsource\n# Ribasim.find_subnetwork_connections! — Method.\nFind the edges from the main network to a subnetwork.\nsource\n# Ribasim.findlastgroup — Method.\nFor an element id and a vector of elements ids, get the range of indices of the last consecutive block of id. Returns the empty range 1:0 if id is not in ids.\nsource\n# Ribasim.findsorted — Method.\nFind the index of element x in a sorted collection a. Returns the index of x if it exists, or nothing if it doesn’t. If x occurs more than once, throw an error.\nsource\n# Ribasim.flow_table — Method.\nCreate a flow result table from the saved data\nsource\n# Ribasim.formulate_basins! — Method.\nSmoothly let the evaporation flux go to 0 when at small water depths Currently at less than 0.1 m.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.formulate_flow! — Method.\nConservation of energy for two basins, a and b:\nh_a + v_a^2 / (2 * g) = h_b + v_b^2 / (2 * g) + S_f * L + C / 2 * g * (v_b^2 - v_a^2)\nWhere:\n\nha, hb are the heads at basin a and b.\nva, vb are the velocities at basin a and b.\ng is the gravitational constant.\nS_f is the friction slope.\nC is an expansion or extraction coefficient.\n\nWe assume velocity differences are negligible (va = vb):\nh_a = h_b + S_f * L\nThe friction losses are approximated by the Gauckler-Manning formula:\nQ = A * (1 / n) * R_h^(2/3) * S_f^(1/2)\nWhere:\n\nWhere A is the cross-sectional area.\nV is the cross-sectional average velocity.\nn is the Gauckler-Manning coefficient.\nR_h is the hydraulic radius.\nS_f is the friction slope.\n\nThe hydraulic radius is defined as:\nR_h = A / P\nWhere P is the wetted perimeter.\nThe average of the upstream and downstream water depth is used to compute cross-sectional area and hydraulic radius. This ensures that a basin can receive water after it has gone dry.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.get_area_and_level — Method.\nCompute the area and level of a basin given its storage. Also returns darea/dlevel as it is needed for the Jacobian.\nsource\n# Ribasim.get_basin_capacity — Method.\nGet the capacity of the basin, i.e. the maximum flow that can be abstracted from the basin if it is in a state of surplus storage (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_basin_data — Method.\nGet several variables associated with a basin:\n\nIts current storage\nThe allocation update interval\nThe influx (sum of instantaneous vertical fluxes of the basin)\nThe index of the connected level_demand node (0 if such a node does not exist)\nThe index of the basin\n\nsource\n# Ribasim.get_basin_demand — Method.\nGet the demand of the basin, i.e. how large a flow the basin needs to get to its minimum target level (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_chunk_sizes — Method.\nGet the chunk sizes for DiffCache; differentiation w.r.t. u and t (the latter only if a Rosenbrock algorithm is used).\nsource\n# Ribasim.get_compressor — Method.\nGet the compressor based on the Results section\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given horizontal (selfloop) edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_fractional_flow_connected_basins — Method.\nGet the node type specific indices of the fractional flows and basins, that are consecutively connected to a node of given id.\nsource\n# Ribasim.get_jac_prototype — Method.\nGet a sparse matrix whose sparsity matches the sparsity of the Jacobian of the ODE problem. All nodes are taken into consideration, also the ones that are inactive.\nIn Ribasim the Jacobian is typically sparse because each state only depends on a small number of other states.\nNote: the name ‘prototype’ does not mean this code is a prototype, it comes from the naming convention of this sparsity structure in the differentialequations.jl docs.\nsource\n# Ribasim.get_level — Method.\nGet the current water level of a node ID. The ID can belong to either a Basin or a LevelBoundary. storage: tells ForwardDiff whether this call is for differentiation or not\nsource\n# Ribasim.get_scalar_interpolation — Method.\nLinear interpolation of a scalar with constant extrapolation.\nsource\n# Ribasim.get_storage_from_level — Method.\nGet the storage of a basin from its level.\nsource\n# Ribasim.get_storages_and_levels — Method.\nGet the storage and level of all basins as matrices of nbasin × ntime\nsource\n# Ribasim.get_storages_from_levels — Method.\nCompute the storages of the basins based on the water level of the basins.\nsource\n# Ribasim.get_tstops — Method.\nFrom an iterable of DateTimes, find the times the solver needs to stop\nsource\n# Ribasim.get_value — Method.\nGet a value for a condition. Currently supports getting levels from basins and flows from flow boundaries.\nsource\n# Ribasim.id_index — Method.\nGet the index of an ID in a set of indices.\nsource\n# Ribasim.indicate_allocation_flow! — Method.\nAdd to the edge metadata that the given edge is used for allocation flow. If the edge does not exist, it is created.\nsource\n# Ribasim.inflow_id — Method.\nGet the unique inneighbor over a flow edge.\nsource\n# Ribasim.inflow_ids — Method.\nGet the inneighbors over flow edges.\nsource\n# Ribasim.inflow_ids_allocation — Method.\nGet the inneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.inneighbor_labels_type — Method.\nGet the inneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.inoutflow_ids — Method.\nGet the in- and outneighbors over flow edges.\nsource\n# Ribasim.integrate_flows! — Method.\nIntegrate flows over the last timestep\nsource\n# Ribasim.is_allocation_source — Method.\nFind out whether the given edge is a source for an allocation network.\nsource\n# Ribasim.is_current_module — Method.\nis_current_module(log::LogMessageType)::Bool\nReturns true if the log message is from the current module or a submodule.\n\nSee https://github.com/JuliaLogging/LoggingExtras.jl/blob/d35e7c8cfc197853ee336ace17182e6ed36dca24/src/CompositionalLoggers/earlyfiltered.jl#L39\nfor the information available in log.\nsource\n# Ribasim.is_flow_constraining — Method.\nWhether the given node node is flow constraining by having a maximum flow rate.\nsource\n# Ribasim.is_flow_direction_constraining — Method.\nWhether the given node is flow direction constraining (only in direction of edges).\nsource\n# Ribasim.load_data — Method.\nload_data(db::DB, config::Config, nodetype::Symbol, kind::Symbol)::Union{Table, Query, Nothing}\nLoad data from Arrow files if available, otherwise the database. Returns either an Arrow.Table, SQLite.Query or nothing if the data is not present.\nsource\n# Ribasim.load_structvector — Method.\nload_structvector(db::DB, config::Config, ::Type{T})::StructVector{T}\nLoad data from Arrow files if available, otherwise the database. Always returns a StructVector of the given struct type T, which is empty if the table is not found. This function validates the schema, and enforces the required sort order.\nsource\n# Ribasim.low_storage_factor — Method.\nIf id is a Basin with storage below the threshold, return a reduction factor != 1\nsource\n# Ribasim.main — Method.\nmain(toml_path::AbstractString)::Cint\nmain(ARGS::Vector{String})::Cint\nmain()::Cint\nThis is the main entry point of the application. Performs argument parsing and sets up logging for both terminal and file. Calls Ribasim.run() and handles exceptions to convert to exit codes.\nsource\n# Ribasim.metadata_from_edge — Method.\nGet the metadata of an edge in the graph from an edge of the underlying DiGraph.\nsource\n# Ribasim.nodefields — Method.\nGet all node fieldnames of the parameter object.\nsource\n# Ribasim.nodetype — Method.\nFrom a SchemaVersion(“ribasim.flowboundary.static”, 1) return (:FlowBoundary, :static)\nsource\n# Ribasim.outflow_id — Method.\nGet the unique outneighbor over a flow edge.\nsource\n# Ribasim.outflow_ids — Method.\nGet the outneighbors over flow edges.\nsource\n# Ribasim.outflow_ids_allocation — Method.\nGet the outneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.outneighbor_labels_type — Method.\nGet the outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.parse_static_and_time — Method.\nProcess the data in the static and time tables for a given node type. The ‘defaults’ named tuple dictates how missing data is filled in. ‘time_interpolatables’ is a vector of Symbols of parameter names for which a time interpolation (linear) object must be constructed. The control mapping for DiscreteControl is also constructed in this function. This function currently does not support node states that are defined by more than one row in a table, as is the case for TabulatedRatingCurve.\nsource\n# Ribasim.pkgversion — Method.\nGet the package version of a given module\nsource\n# Ribasim.process_allocation_graph_edges! — Method.\nFor the composite allocation network edges:\n\nFind out whether they are connected to allocation network nodes on both ends\nCompute their capacity\nFind out their allowed flow direction(s)\n\nsource\n# Ribasim.profile_storage — Method.\nCalculate a profile storage by integrating the areas over the levels\nsource\n# Ribasim.qh_interpolation — Method.\nFrom a table with columns nodeid, flowrate (Q) and level (h), create a LinearInterpolation from level to flow rate for a given node_id.\nsource\n# Ribasim.reduction_factor — Method.\nFunction that goes smoothly from 0 to 1 in the interval [0,threshold], and is constant outside this interval.\nsource\n# Ribasim.run — Method.\nrun(config_file::AbstractString)::Model\nrun(config::Config)::Model\nRun a Model, given a path to a TOML configuration file, or a Config object. Running a model includes initialization, solving to the end with [solve!](@ref) and writing results with write_results.\nsource\n# Ribasim.save_allocation_flows! — Method.\nSave the allocation flows per basin and physical edge.\nsource\n# Ribasim.save_demands_and_allocations! — Method.\nSave the demands and allocated flows for UserDemand and Basin. Note: Basin supply (negative demand) is only saved for the first priority.\nsource\n# Ribasim.save_flow — Method.\nCompute the average flows over the last saveat interval and write them to SavedValues\nsource\n# Ribasim.save_subgrid_level — Method.\nInterpolate the levels and save them to SavedValues\nsource\n# Ribasim.scalar_interpolation_derivative — Method.\nDerivative of scalar interpolation.\nsource\n# Ribasim.seconds_since — Method.\nseconds_since(t::DateTime, t0::DateTime)::Float64\nConvert a DateTime to a float that is the number of seconds since the start of the simulation. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.set_current_value! — Method.\nFrom a timeseries table time, load the most recent applicable data into table. table must be a NamedTuple of vectors with all variables that must be loaded. The most recent applicable data is non-NaN data for a given ID that is on or before t.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q over the edge between the given nodes.\nsource\n# Ribasim.set_fractional_flow_in_allocation! — Method.\nUpdate the fractional flow fractions in an allocation problem.\nsource\n# Ribasim.set_initial_discrete_controlled_parameters! — Method.\nSet parameters of nodes that are controlled by DiscreteControl to the values corresponding to the initial state of the model.\nsource\n# Ribasim.set_is_pid_controlled! — Method.\nSet ispidcontrolled to true for those pumps and outlets that are PID controlled\nsource\n# Ribasim.set_objective_priority! — Method.\nSet the objective for the given priority. For an objective with absolute values this also involves adjusting constraints.\nsource\n# Ribasim.set_static_value! — Method.\nLoad data from a source table static into a destination table. Data is matched based on the node_id, which is sorted.\nsource\n# Ribasim.set_table_row! — Method.\nUpdate table at row index i, with the values of a given row. table must be a NamedTuple of vectors with all variables that must be loaded. The row must contain all the column names that are present in the table. If a value is missing, it is not set.\nsource\n# Ribasim.sorted_table! — Method.\nDepending on if a table can be sorted, either sort it or assert that it is sorted.\nTables loaded from the database into memory can be sorted. Tables loaded from Arrow files are memory mapped and can therefore not be sorted.\nsource\n# Ribasim.tsaves — Method.\nGet all saved times in seconds since start\nsource\n# Ribasim.update_allocation! — Method.\nSolve the allocation problem for all demands and assign allocated abstractions.\nsource\n# Ribasim.update_basin — Method.\nLoad updates from ‘Basin / time’ into the parameters\nsource\n# Ribasim.update_jac_prototype! — Method.\nMethod for nodes that do not contribute to the Jacobian\nsource\n# Ribasim.update_jac_prototype! — Method.\nThe controlled basin affects itself and the basins upstream and downstream of the controlled pump affect eachother if there is a basin upstream of the pump. The state for the integral term and the controlled basin affect eachother, and the same for the integral state and the basin upstream of the pump if it is indeed a basin.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the unique node downstream of these nodes are basins, then these directly depend on eachother and affect the Jacobian 2x Basins always depend on themselves.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the nodes down stream (or one node further if a fractional flow is in between) are basins, then the downstream basin depends on the upstream basin(s) and affect the Jacobian as many times as there are downstream basins Upstream basins always depend on themselves.\nsource\n# Ribasim.update_tabulated_rating_curve! — Method.\nLoad updates from ‘TabulatedRatingCurve / time’ into the parameters\nsource\n# Ribasim.valid_discrete_control — Method.\nCheck:\n\nwhether control states are defined for discrete controlled nodes;\nWhether the supplied truth states have the proper length;\nWhether look_ahead is only supplied for condition variables given by a time-series.\n\nsource\n# Ribasim.valid_edge_types — Method.\nCheck that only supported edge types are declared.\nsource\n# Ribasim.valid_edges — Method.\nTest for each node given its node type whether the nodes that\nare downstream (‘down-edge’) of this node are of an allowed type\nsource\n# Ribasim.valid_flow_rates — Method.\nTest whether static or discrete controlled flow rates are indeed non-negative.\nsource\n# Ribasim.valid_fractional_flow — Method.\nCheck that nodes that have fractional flow outneighbors do not have any other type of outneighbor, that the fractions leaving a node add up to ≈1 and that the fractions are non-negative.\nsource\n# Ribasim.valid_n_neighbors — Method.\nTest for each node given its node type whether it has an allowed number of flow/control inneighbors and outneighbors\nsource\n# Ribasim.valid_profiles — Method.\nCheck whether the profile data has no repeats in the levels and the areas start positive.\nsource\n# Ribasim.valid_sources — Method.\nThe source nodes must only have one allocation outneighbor and no allocation inneighbors.\nsource\n# Ribasim.valid_subgrid — Method.\nValidate the entries for a single subgrid element.\nsource\n# Ribasim.water_balance! — Method.\nThe right hand side function of the system of ODEs set up by Ribasim.\nsource\n# Ribasim.write_arrow — Method.\nWrite a result table to disk as an Arrow file\nsource\n# Ribasim.write_results — Method.\nwrite_results(model::Model)::Model\nWrite all results to the Arrow files as specified in the model configuration.\nsource\n# Ribasim.config.algorithm — Method.\nCreate an OrdinaryDiffEqAlgorithm from solver config\nsource\n# Ribasim.config.convert_dt — Method.\nConvert the dt from our Config to SciML stepsize control arguments\nsource\n# Ribasim.config.convert_saveat — Method.\nConvert the saveat Float64 from our Config to SciML’s saveat\nsource\n# Ribasim.config.input_path — Method.\nConstruct a path relative to both the TOML directory and the optional input_dir\nsource\n# Ribasim.config.results_path — Method.\nConstruct a path relative to both the TOML directory and the optional results_dir\nsource\n# Ribasim.config.snake_case — Method.\nConvert a string from CamelCase to snake_case.\nsource",
+ "text": "1.3 Functions\n# BasicModelInterface.finalize — Method.\nBMI.finalize(model::Model)::Model\nWrite all results to the configured files.\nsource\n# BasicModelInterface.initialize — Method.\nBMI.initialize(T::Type{Model}, config_path::AbstractString)::Model\nInitialize a Model from the path to the TOML configuration file.\nsource\n# CommonSolve.solve! — Method.\nsolve!(model::Model)::ODESolution\nSolve a Model until the configured endtime.\nsource\n# Ribasim.add_basin_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a basin.\nsource\n# Ribasim.add_constraints_absolute_value! — Method.\nMinimizing |expr| can be achieved by introducing a new variable exprabs and posing the following constraints: exprabs >= expr expr_abs >= -expr\nsource\n# Ribasim.add_constraints_absolute_value_flow_demand! — Method.\nAdd constraints so that variables Fabsflow_demand act as the absolute value of the expression comparing flow to a flow buffer to the flow demand.\nsource\n# Ribasim.add_constraints_absolute_value_level_demand! — Method.\nAdd constraints so that variables Fabslevel_demand act as the absolute value of the expression comparing flow to a basin to its demand.\nsource\n# Ribasim.add_constraints_absolute_value_user_demand! — Method.\nAdd constraints so that variables Fabsuser_demand act as the absolute value of the expression comparing flow to a UserDemand to its demand.\nsource\n# Ribasim.add_constraints_basin_flow! — Method.\nAdd the Basin flow constraints to the allocation problem. The constraint indices are the Basin node IDs.\nConstraint: flow out of basin <= basin capacity\nsource\n# Ribasim.add_constraints_buffer! — Method.\nAdd the buffer outflow constraints to the allocation problem. The constraint indices are the node IDs of the nodes that have a flow demand.\nConstraint: flow out of buffer <= flow buffer capacity\nsource\n# Ribasim.add_constraints_capacity! — Method.\nAdd the flow capacity constraints to the allocation problem. Only finite capacities get a constraint. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over edge <= edge capacity\nsource\n# Ribasim.add_constraints_conservation_basin! — Method.\nAdd the basin flow conservation constraints to the allocation problem. The constraint indices are Basin node IDs.\nConstraint: sum(flows out of basin) == sum(flows into basin) + flow from storage and vertical fluxes\nsource\n# Ribasim.add_constraints_conservation_flow_demand! — Method.\nAdd the conservation constraints for connector nodes with a flow demand to the allocation problem. The constraint indices are node IDs of the nodes with the flow demand (so not the IDs of the FlowDemand nodes).\nConstraint: flow into node + flow out of buffer = flow out of node + flow into buffer\nsource\n# Ribasim.add_constraints_conservation_subnetwork! — Method.\nAdd the subnetwork inlet flow conservation constraints to the allocation problem. The constraint indices are node IDs subnetwork inlet edge dst IDs.\nConstraint: sum(flows into node) == sum(flows out of node)\nsource\n# Ribasim.add_constraints_flow_demand_outflow! — Method.\nAdd the flow demand node outflow constraints to the allocation problem. The constraint indices are the node IDs of the nodes that have a flow demand.\nConstraint: flow out of node with flow demand <= ∞ if not at flow demand priority, 0.0 otherwise\nsource\n# Ribasim.add_constraints_fractional_flow! — Method.\nAdd the fractional flow constraints to the allocation problem. The constraint indices are allocation edges over a fractional flow node.\nConstraint: flow after fractional_flow node <= fraction * inflow\nsource\n# Ribasim.add_constraints_source! — Method.\nAdd the source constraints to the allocation problem. The actual threshold values will be set before each allocation solve. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over source edge <= source flow in subnetwork\nsource\n# Ribasim.add_constraints_user_demand_returnflow! — Method.\nAdd the UserDemand returnflow constraints to the allocation problem. The constraint indices are UserDemand node IDs. Constraint: outflow from userdemand <= return factor inflow to user*demand\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the flow over the edge on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the existing flow over the edge between the given nodes.\nsource\n# Ribasim.add_flow_demand_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a node with a a flow demand.\nsource\n# Ribasim.add_objective_term! — Function.\nAdd a term to the objective function given by the objective type, depending in the provided flow variable and the associated demand.\nsource\n# Ribasim.add_subnetwork_connections! — Method.\nAdd the edges connecting the main network work to a subnetwork to both the main network and subnetwork allocation network.\nsource\n# Ribasim.add_user_demand_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a UserDemand.\nsource\n# Ribasim.add_variables_absolute_value! — Method.\nCertain allocation distribution types use absolute values in the objective function. Since most optimization packages do not support the absolute value function directly, New variables are introduced that act as the absolute value of an expression by posing the appropriate constraints.\nsource\n# Ribasim.add_variables_basin! — Method.\nAdd the variables for supply/demand of a basin to the problem. The variable indices are the node_ids of the basins with a level demand in the subnetwork.\nsource\n# Ribasim.add_variables_flow! — Method.\nAdd the flow variables F to the allocation problem. The variable indices are (edgesourceid, edgedstid). Non-negativivity constraints are also immediately added to the flow variables.\nsource\n# Ribasim.add_variables_flow_buffer! — Method.\nAdd the variables for supply/demand of a node with a flow demand to the problem. The variable indices are the node_ids of the nodes with a flow demand in the subnetwork.\nsource\n# Ribasim.adjust_capacities_basin! — Method.\nSet the capacities of the basin outflows. 2 cases:\n\nBefore the first allocation solve, set the capacities to their full capacity if there is surplus storage;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the capacities.\n\nsource\n# Ribasim.adjust_capacities_buffers! — Method.\nAdjust the capacities of the flow buffers of nodes with a flow demand. 2 cases:\n\nBefore the first allocation solve, set the capacities to 0.0;\nBefore an allocation solve, add the flow into the buffer and remove the flow out of the buffer from the buffer capacity.\n\nsource\n# Ribasim.adjust_capacities_edge! — Method.\nSet the values of the edge capacities. 2 cases:\n\nBefore the first allocation solve, set the edge capacities to their full capacity;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the edge capacities.\n\nsource\n# Ribasim.adjust_capacities_flow_demand_outflow! — Method.\nSet the capacity of the outflow edge from a node with a flow demand:\n\nTo Inf if the current priority is other than the priority of the flow demand\nTo 0.0 if the current priority is equal to the priority of the flow demand\n\nsource\n# Ribasim.adjust_capacities_source! — Method.\nAdjust the source flows.\nsource\n# Ribasim.adjust_demands_flow! — Method.\nSet the demand of the flow demand nodes. 2 cases:\n\nBefore the first allocation solve, set the demands to their full value;\nBefore an allocation solve, subtract the flow trough the node with a flow demand from the total flow demand (which will be used at the priority of the flow demand only).\n\nsource\n# Ribasim.all_neighbor_labels_type — Method.\nGet the in- and outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.allocate! — Method.\nUpdate the allocation optimization problem for the given subnetwork with the problem state and flows, solve the allocation problem and assign the results to the UserDemand.\nsource\n# Ribasim.allocation_graph — Method.\nBuild the graph used for the allocation problem.\nsource\n# Ribasim.allocation_graph_used_nodes! — Method.\nFind all nodes in the subnetwork which will be used in the allocation network. Some nodes are skipped to optimize allocation optimization.\nsource\n# Ribasim.allocation_path_exists_in_graph — Method.\nFind out whether a path exists between a start node and end node in the given allocation network.\nsource\n# Ribasim.allocation_problem — Method.\nConstruct the allocation problem for the current subnetwork as a JuMP.jl model.\nsource\n# Ribasim.allocation_table — Method.\nCreate an allocation result table for the saved data\nsource\n# Ribasim.assign_allocations! — Method.\nAssign the allocations to the UserDemand as determined by the solution of the allocation problem.\nsource\n# Ribasim.avoid_using_own_returnflow! — Method.\nRemove allocation UserDemand return flow edges that are upstream of the UserDemand itself.\nsource\n# Ribasim.basin_bottom — Method.\nReturn the bottom elevation of the basin with index i, or nothing if it doesn’t exist\nsource\n# Ribasim.basin_bottoms — Method.\nGet the bottom on both ends of a node. If only one has a bottom, use that for both.\nsource\n# Ribasim.basin_table — Method.\nCreate the basin result table from the saved data\nsource\n# Ribasim.create_callbacks — Method.\nCreate the different callbacks that are used to store results and feed the simulation with new data. The different callbacks are combined to a CallbackSet that goes to the integrator. Returns the CallbackSet and the SavedValues for flow.\nsource\n# Ribasim.create_graph — Method.\nReturn a directed metagraph with data of nodes (NodeMetadata): NodeMetadata\nand data of edges (EdgeMetadata): EdgeMetadata\nsource\n# Ribasim.create_storage_tables — Method.\nRead the Basin / profile table and return all area and level and computed storage values\nsource\n# Ribasim.datetime_since — Method.\ndatetime_since(t::Real, t0::DateTime)::DateTime\nConvert a Real that represents the seconds passed since the simulation start to the nearest DateTime. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.datetimes — Method.\nGet all saved times as a Vector{DateTime}\nsource\n# Ribasim.discrete_control_affect! — Method.\nChange parameters based on the control logic.\nsource\n# Ribasim.discrete_control_affect_downcrossing! — Method.\nAn downcrossing means that a condition (always greater than) becomes false.\nsource\n# Ribasim.discrete_control_affect_upcrossing! — Method.\nAn upcrossing means that a condition (always greater than) becomes true.\nsource\n# Ribasim.discrete_control_condition — Method.\nListens for changes in condition truths.\nsource\n# Ribasim.discrete_control_table — Method.\nCreate a discrete control result table from the saved data\nsource\n# Ribasim.expand_logic_mapping — Method.\nReplace the truth states in the logic mapping which contain wildcards with all possible explicit truth states.\nsource\n# Ribasim.find_allocation_graph_edges! — Method.\nThis loop finds allocation network edges in several ways:\n\nBetween allocation network nodes whose equivalent in the subnetwork are directly connected\nBetween allocation network nodes whose equivalent in the subnetwork are connected with one or more allocation network nodes in between\n\nsource\n# Ribasim.find_subnetwork_connections! — Method.\nFind the edges from the main network to a subnetwork.\nsource\n# Ribasim.findlastgroup — Method.\nFor an element id and a vector of elements ids, get the range of indices of the last consecutive block of id. Returns the empty range 1:0 if id is not in ids.\nsource\n# Ribasim.findsorted — Method.\nFind the index of element x in a sorted collection a. Returns the index of x if it exists, or nothing if it doesn’t. If x occurs more than once, throw an error.\nsource\n# Ribasim.flow_table — Method.\nCreate a flow result table from the saved data\nsource\n# Ribasim.formulate_basins! — Method.\nSmoothly let the evaporation flux go to 0 when at small water depths Currently at less than 0.1 m.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.formulate_flow! — Method.\nConservation of energy for two basins, a and b:\nh_a + v_a^2 / (2 * g) = h_b + v_b^2 / (2 * g) + S_f * L + C / 2 * g * (v_b^2 - v_a^2)\nWhere:\n\nha, hb are the heads at basin a and b.\nva, vb are the velocities at basin a and b.\ng is the gravitational constant.\nS_f is the friction slope.\nC is an expansion or extraction coefficient.\n\nWe assume velocity differences are negligible (va = vb):\nh_a = h_b + S_f * L\nThe friction losses are approximated by the Gauckler-Manning formula:\nQ = A * (1 / n) * R_h^(2/3) * S_f^(1/2)\nWhere:\n\nWhere A is the cross-sectional area.\nV is the cross-sectional average velocity.\nn is the Gauckler-Manning coefficient.\nR_h is the hydraulic radius.\nS_f is the friction slope.\n\nThe hydraulic radius is defined as:\nR_h = A / P\nWhere P is the wetted perimeter.\nThe average of the upstream and downstream water depth is used to compute cross-sectional area and hydraulic radius. This ensures that a basin can receive water after it has gone dry.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.get_area_and_level — Method.\nCompute the area and level of a basin given its storage. Also returns darea/dlevel as it is needed for the Jacobian.\nsource\n# Ribasim.get_basin_capacity — Method.\nGet the capacity of the basin, i.e. the maximum flow that can be abstracted from the basin if it is in a state of surplus storage (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_basin_data — Method.\nGet several variables associated with a basin:\n\nIts current storage\nThe allocation update interval\nThe influx (sum of instantaneous vertical fluxes of the basin)\nThe index of the connected level_demand node (0 if such a node does not exist)\nThe index of the basin\n\nsource\n# Ribasim.get_basin_demand — Method.\nGet the demand of the basin, i.e. how large a flow the basin needs to get to its minimum target level (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_chunk_sizes — Method.\nGet the chunk sizes for DiffCache; differentiation w.r.t. u and t (the latter only if a Rosenbrock algorithm is used).\nsource\n# Ribasim.get_compressor — Method.\nGet the compressor based on the Results section\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given horizontal (selfloop) edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_fractional_flow_connected_basins — Method.\nGet the node type specific indices of the fractional flows and basins, that are consecutively connected to a node of given id.\nsource\n# Ribasim.get_jac_prototype — Method.\nGet a sparse matrix whose sparsity matches the sparsity of the Jacobian of the ODE problem. All nodes are taken into consideration, also the ones that are inactive.\nIn Ribasim the Jacobian is typically sparse because each state only depends on a small number of other states.\nNote: the name ‘prototype’ does not mean this code is a prototype, it comes from the naming convention of this sparsity structure in the differentialequations.jl docs.\nsource\n# Ribasim.get_level — Method.\nGet the current water level of a node ID. The ID can belong to either a Basin or a LevelBoundary. storage: tells ForwardDiff whether this call is for differentiation or not\nsource\n# Ribasim.get_scalar_interpolation — Method.\nLinear interpolation of a scalar with constant extrapolation.\nsource\n# Ribasim.get_storage_from_level — Method.\nGet the storage of a basin from its level.\nsource\n# Ribasim.get_storages_and_levels — Method.\nGet the storage and level of all basins as matrices of nbasin × ntime\nsource\n# Ribasim.get_storages_from_levels — Method.\nCompute the storages of the basins based on the water level of the basins.\nsource\n# Ribasim.get_tstops — Method.\nFrom an iterable of DateTimes, find the times the solver needs to stop\nsource\n# Ribasim.get_value — Method.\nGet a value for a condition. Currently supports getting levels from basins and flows from flow boundaries.\nsource\n# Ribasim.id_index — Method.\nGet the index of an ID in a set of indices.\nsource\n# Ribasim.indicate_allocation_flow! — Method.\nAdd to the edge metadata that the given edge is used for allocation flow. If the edge does not exist, it is created.\nsource\n# Ribasim.inflow_id — Method.\nGet the unique inneighbor over a flow edge.\nsource\n# Ribasim.inflow_ids — Method.\nGet the inneighbors over flow edges.\nsource\n# Ribasim.inflow_ids_allocation — Method.\nGet the inneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.inneighbor_labels_type — Method.\nGet the inneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.inoutflow_ids — Method.\nGet the in- and outneighbors over flow edges.\nsource\n# Ribasim.integrate_flows! — Method.\nIntegrate flows over the last timestep\nsource\n# Ribasim.is_allocation_source — Method.\nFind out whether the given edge is a source for an allocation network.\nsource\n# Ribasim.is_current_module — Method.\nis_current_module(log::LogMessageType)::Bool\nReturns true if the log message is from the current module or a submodule.\n\nSee https://github.com/JuliaLogging/LoggingExtras.jl/blob/d35e7c8cfc197853ee336ace17182e6ed36dca24/src/CompositionalLoggers/earlyfiltered.jl#L39\nfor the information available in log.\nsource\n# Ribasim.is_flow_constraining — Method.\nWhether the given node node is flow constraining by having a maximum flow rate.\nsource\n# Ribasim.is_flow_direction_constraining — Method.\nWhether the given node is flow direction constraining (only in direction of edges).\nsource\n# Ribasim.load_data — Method.\nload_data(db::DB, config::Config, nodetype::Symbol, kind::Symbol)::Union{Table, Query, Nothing}\nLoad data from Arrow files if available, otherwise the database. Returns either an Arrow.Table, SQLite.Query or nothing if the data is not present.\nsource\n# Ribasim.load_structvector — Method.\nload_structvector(db::DB, config::Config, ::Type{T})::StructVector{T}\nLoad data from Arrow files if available, otherwise the database. Always returns a StructVector of the given struct type T, which is empty if the table is not found. This function validates the schema, and enforces the required sort order.\nsource\n# Ribasim.low_storage_factor — Method.\nIf id is a Basin with storage below the threshold, return a reduction factor != 1\nsource\n# Ribasim.main — Method.\nmain(toml_path::AbstractString)::Cint\nmain(ARGS::Vector{String})::Cint\nmain()::Cint\nThis is the main entry point of the application. Performs argument parsing and sets up logging for both terminal and file. Calls Ribasim.run() and handles exceptions to convert to exit codes.\nsource\n# Ribasim.metadata_from_edge — Method.\nGet the metadata of an edge in the graph from an edge of the underlying DiGraph.\nsource\n# Ribasim.nodefields — Method.\nGet all node fieldnames of the parameter object.\nsource\n# Ribasim.nodetype — Method.\nFrom a SchemaVersion(“ribasim.flowboundary.static”, 1) return (:FlowBoundary, :static)\nsource\n# Ribasim.outflow_id — Method.\nGet the unique outneighbor over a flow edge.\nsource\n# Ribasim.outflow_ids — Method.\nGet the outneighbors over flow edges.\nsource\n# Ribasim.outflow_ids_allocation — Method.\nGet the outneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.outneighbor_labels_type — Method.\nGet the outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.parse_static_and_time — Method.\nProcess the data in the static and time tables for a given node type. The ‘defaults’ named tuple dictates how missing data is filled in. ‘time_interpolatables’ is a vector of Symbols of parameter names for which a time interpolation (linear) object must be constructed. The control mapping for DiscreteControl is also constructed in this function. This function currently does not support node states that are defined by more than one row in a table, as is the case for TabulatedRatingCurve.\nsource\n# Ribasim.pkgversion — Method.\nGet the package version of a given module\nsource\n# Ribasim.process_allocation_graph_edges! — Method.\nFor the composite allocation network edges:\n\nFind out whether they are connected to allocation network nodes on both ends\nCompute their capacity\nFind out their allowed flow direction(s)\n\nsource\n# Ribasim.profile_storage — Method.\nCalculate a profile storage by integrating the areas over the levels\nsource\n# Ribasim.qh_interpolation — Method.\nFrom a table with columns nodeid, flowrate (Q) and level (h), create a LinearInterpolation from level to flow rate for a given node_id.\nsource\n# Ribasim.reduction_factor — Method.\nFunction that goes smoothly from 0 to 1 in the interval [0,threshold], and is constant outside this interval.\nsource\n# Ribasim.run — Method.\nrun(config_file::AbstractString)::Model\nrun(config::Config)::Model\nRun a Model, given a path to a TOML configuration file, or a Config object. Running a model includes initialization, solving to the end with [solve!](@ref) and writing results with write_results.\nsource\n# Ribasim.save_allocation_flows! — Method.\nSave the allocation flows per basin and physical edge.\nsource\n# Ribasim.save_demands_and_allocations! — Method.\nSave the demands and allocated flows for UserDemand and Basin. Note: Basin supply (negative demand) is only saved for the first priority.\nsource\n# Ribasim.save_flow — Method.\nCompute the average flows over the last saveat interval and write them to SavedValues\nsource\n# Ribasim.save_subgrid_level — Method.\nInterpolate the levels and save them to SavedValues\nsource\n# Ribasim.scalar_interpolation_derivative — Method.\nDerivative of scalar interpolation.\nsource\n# Ribasim.seconds_since — Method.\nseconds_since(t::DateTime, t0::DateTime)::Float64\nConvert a DateTime to a float that is the number of seconds since the start of the simulation. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.set_current_value! — Method.\nFrom a timeseries table time, load the most recent applicable data into table. table must be a NamedTuple of vectors with all variables that must be loaded. The most recent applicable data is non-NaN data for a given ID that is on or before t.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q over the edge between the given nodes.\nsource\n# Ribasim.set_fractional_flow_in_allocation! — Method.\nUpdate the fractional flow fractions in an allocation problem.\nsource\n# Ribasim.set_initial_discrete_controlled_parameters! — Method.\nSet parameters of nodes that are controlled by DiscreteControl to the values corresponding to the initial state of the model.\nsource\n# Ribasim.set_is_pid_controlled! — Method.\nSet ispidcontrolled to true for those pumps and outlets that are PID controlled\nsource\n# Ribasim.set_objective_priority! — Method.\nSet the objective for the given priority. For an objective with absolute values this also involves adjusting constraints.\nsource\n# Ribasim.set_static_value! — Method.\nLoad data from a source table static into a destination table. Data is matched based on the node_id, which is sorted.\nsource\n# Ribasim.set_table_row! — Method.\nUpdate table at row index i, with the values of a given row. table must be a NamedTuple of vectors with all variables that must be loaded. The row must contain all the column names that are present in the table. If a value is missing, it is not set.\nsource\n# Ribasim.sorted_table! — Method.\nDepending on if a table can be sorted, either sort it or assert that it is sorted.\nTables loaded from the database into memory can be sorted. Tables loaded from Arrow files are memory mapped and can therefore not be sorted.\nsource\n# Ribasim.tsaves — Method.\nGet all saved times in seconds since start\nsource\n# Ribasim.update_allocation! — Method.\nSolve the allocation problem for all demands and assign allocated abstractions.\nsource\n# Ribasim.update_basin — Method.\nLoad updates from ‘Basin / time’ into the parameters\nsource\n# Ribasim.update_jac_prototype! — Method.\nMethod for nodes that do not contribute to the Jacobian\nsource\n# Ribasim.update_jac_prototype! — Method.\nThe controlled basin affects itself and the basins upstream and downstream of the controlled pump affect eachother if there is a basin upstream of the pump. The state for the integral term and the controlled basin affect eachother, and the same for the integral state and the basin upstream of the pump if it is indeed a basin.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the unique node downstream of these nodes are basins, then these directly depend on eachother and affect the Jacobian 2x Basins always depend on themselves.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the nodes down stream (or one node further if a fractional flow is in between) are basins, then the downstream basin depends on the upstream basin(s) and affect the Jacobian as many times as there are downstream basins Upstream basins always depend on themselves.\nsource\n# Ribasim.update_tabulated_rating_curve! — Method.\nLoad updates from ‘TabulatedRatingCurve / time’ into the parameters\nsource\n# Ribasim.valid_discrete_control — Method.\nCheck:\n\nwhether control states are defined for discrete controlled nodes;\nWhether the supplied truth states have the proper length;\nWhether look_ahead is only supplied for condition variables given by a time-series.\n\nsource\n# Ribasim.valid_edge_types — Method.\nCheck that only supported edge types are declared.\nsource\n# Ribasim.valid_edges — Method.\nTest for each node given its node type whether the nodes that\nare downstream (‘down-edge’) of this node are of an allowed type\nsource\n# Ribasim.valid_flow_rates — Method.\nTest whether static or discrete controlled flow rates are indeed non-negative.\nsource\n# Ribasim.valid_fractional_flow — Method.\nCheck that nodes that have fractional flow outneighbors do not have any other type of outneighbor, that the fractions leaving a node add up to ≈1 and that the fractions are non-negative.\nsource\n# Ribasim.valid_n_neighbors — Method.\nTest for each node given its node type whether it has an allowed number of flow/control inneighbors and outneighbors\nsource\n# Ribasim.valid_profiles — Method.\nCheck whether the profile data has no repeats in the levels and the areas start positive.\nsource\n# Ribasim.valid_sources — Method.\nThe source nodes must only have one allocation outneighbor and no allocation inneighbors.\nsource\n# Ribasim.valid_subgrid — Method.\nValidate the entries for a single subgrid element.\nsource\n# Ribasim.water_balance! — Method.\nThe right hand side function of the system of ODEs set up by Ribasim.\nsource\n# Ribasim.write_arrow — Method.\nWrite a result table to disk as an Arrow file\nsource\n# Ribasim.write_results — Method.\nwrite_results(model::Model)::Model\nWrite all results to the Arrow files as specified in the model configuration.\nsource\n# Ribasim.config.algorithm — Method.\nCreate an OrdinaryDiffEqAlgorithm from solver config\nsource\n# Ribasim.config.convert_dt — Method.\nConvert the dt from our Config to SciML stepsize control arguments\nsource\n# Ribasim.config.convert_saveat — Method.\nConvert the saveat Float64 from our Config to SciML’s saveat\nsource\n# Ribasim.config.input_path — Method.\nConstruct a path relative to both the TOML directory and the optional input_dir\nsource\n# Ribasim.config.results_path — Method.\nConstruct a path relative to both the TOML directory and the optional results_dir\nsource\n# Ribasim.config.snake_case — Method.\nConvert a string from CamelCase to snake_case.\nsource",
"crumbs": [
"Julia core",
"API Reference"
@@ -442,7 +449,7 @@
"href": "build/index.html#index",
"title": "1 API Reference",
"section": "1.6 Index",
- "text": "1.6 Index\n\nRibasim.Ribasim\nRibasim.config\nRibasim.config.algorithms\nRibasim.Allocation\nRibasim.AllocationModel\nRibasim.AllocationModel\nRibasim.Basin\nRibasim.DiscreteControl\nRibasim.EdgeMetadata\nRibasim.FlatVector\nRibasim.FlowBoundary\nRibasim.FractionalFlow\nRibasim.InNeighbors\nRibasim.LevelBoundary\nRibasim.LevelDemand\nRibasim.LinearResistance\nRibasim.ManningResistance\nRibasim.Model\nRibasim.NodeMetadata\nRibasim.OutNeighbors\nRibasim.Outlet\nRibasim.PidControl\nRibasim.Pump\nRibasim.Subgrid\nRibasim.TabulatedRatingCurve\nRibasim.Terminal\nRibasim.UserDemand\nRibasim.config.Config\nBasicModelInterface.finalize\nBasicModelInterface.initialize\nCommonSolve.solve!\nRibasim.add_basin_term!\nRibasim.add_constraints_absolute_value!\nRibasim.add_constraints_absolute_value_basin!\nRibasim.add_constraints_absolute_value_user_demand!\nRibasim.add_constraints_basin_flow!\nRibasim.add_constraints_capacity!\nRibasim.add_constraints_flow_conservation!\nRibasim.add_constraints_fractional_flow!\nRibasim.add_constraints_source!\nRibasim.add_constraints_user_demand_returnflow!\nRibasim.add_flow!\nRibasim.add_flow!\nRibasim.add_objective_term!\nRibasim.add_subnetwork_connections!\nRibasim.add_user_demand_term!\nRibasim.add_variables_absolute_value!\nRibasim.add_variables_basin!\nRibasim.add_variables_flow!\nRibasim.adjust_basin_capacities!\nRibasim.adjust_edge_capacities!\nRibasim.adjust_source_capacities!\nRibasim.all_neighbor_labels_type\nRibasim.allocate!\nRibasim.allocation_graph\nRibasim.allocation_graph_used_nodes!\nRibasim.allocation_path_exists_in_graph\nRibasim.allocation_problem\nRibasim.allocation_table\nRibasim.assign_allocations!\nRibasim.avoid_using_own_returnflow!\nRibasim.basin_bottom\nRibasim.basin_bottoms\nRibasim.basin_table\nRibasim.config.algorithm\nRibasim.config.convert_dt\nRibasim.config.convert_saveat\nRibasim.config.input_path\nRibasim.config.results_path\nRibasim.config.snake_case\nRibasim.create_callbacks\nRibasim.create_graph\nRibasim.create_storage_tables\nRibasim.datetime_since\nRibasim.datetimes\nRibasim.discrete_control_affect!\nRibasim.discrete_control_affect_downcrossing!\nRibasim.discrete_control_affect_upcrossing!\nRibasim.discrete_control_condition\nRibasim.discrete_control_table\nRibasim.expand_logic_mapping\nRibasim.find_allocation_graph_edges!\nRibasim.find_subnetwork_connections!\nRibasim.findlastgroup\nRibasim.findsorted\nRibasim.flow_table\nRibasim.formulate_basins!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.get_area_and_level\nRibasim.get_basin_capacity\nRibasim.get_basin_data\nRibasim.get_basin_demand\nRibasim.get_chunk_sizes\nRibasim.get_compressor\nRibasim.get_flow\nRibasim.get_flow\nRibasim.get_fractional_flow_connected_basins\nRibasim.get_jac_prototype\nRibasim.get_level\nRibasim.get_scalar_interpolation\nRibasim.get_storage_from_level\nRibasim.get_storages_and_levels\nRibasim.get_storages_from_levels\nRibasim.get_tstops\nRibasim.get_value\nRibasim.id_index\nRibasim.indicate_allocation_flow!\nRibasim.inflow_id\nRibasim.inflow_ids\nRibasim.inflow_ids_allocation\nRibasim.inneighbor_labels_type\nRibasim.inoutflow_ids\nRibasim.integrate_flows!\nRibasim.is_allocation_source\nRibasim.is_current_module\nRibasim.is_flow_constraining\nRibasim.is_flow_direction_constraining\nRibasim.load_data\nRibasim.load_structvector\nRibasim.low_storage_factor\nRibasim.main\nRibasim.metadata_from_edge\nRibasim.nodefields\nRibasim.nodetype\nRibasim.outflow_id\nRibasim.outflow_ids\nRibasim.outflow_ids_allocation\nRibasim.outneighbor_labels_type\nRibasim.parse_static_and_time\nRibasim.pkgversion\nRibasim.process_allocation_graph_edges!\nRibasim.profile_storage\nRibasim.qh_interpolation\nRibasim.reduction_factor\nRibasim.run\nRibasim.save_allocation_flows!\nRibasim.save_demands_and_allocations!\nRibasim.save_flow\nRibasim.save_subgrid_level\nRibasim.scalar_interpolation_derivative\nRibasim.seconds_since\nRibasim.set_current_value!\nRibasim.set_flow!\nRibasim.set_flow!\nRibasim.set_fractional_flow_in_allocation!\nRibasim.set_initial_discrete_controlled_parameters!\nRibasim.set_is_pid_controlled!\nRibasim.set_objective_priority!\nRibasim.set_static_value!\nRibasim.set_table_row!\nRibasim.sorted_table!\nRibasim.tsaves\nRibasim.update_allocation!\nRibasim.update_basin\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_tabulated_rating_curve!\nRibasim.valid_discrete_control\nRibasim.valid_edge_types\nRibasim.valid_edges\nRibasim.valid_flow_rates\nRibasim.valid_fractional_flow\nRibasim.valid_n_neighbors\nRibasim.valid_profiles\nRibasim.valid_sources\nRibasim.valid_subgrid\nRibasim.water_balance!\nRibasim.write_arrow\nRibasim.write_results\nRibasim.config.@addfields\nRibasim.config.@addnodetypes",
+ "text": "1.6 Index\n\nRibasim.Ribasim\nRibasim.config\nRibasim.config.algorithms\nRibasim.Allocation\nRibasim.AllocationModel\nRibasim.AllocationModel\nRibasim.Basin\nRibasim.DiscreteControl\nRibasim.EdgeMetadata\nRibasim.FlatVector\nRibasim.FlowBoundary\nRibasim.FractionalFlow\nRibasim.InNeighbors\nRibasim.LevelBoundary\nRibasim.LevelDemand\nRibasim.LinearResistance\nRibasim.ManningResistance\nRibasim.Model\nRibasim.NodeMetadata\nRibasim.OutNeighbors\nRibasim.Outlet\nRibasim.PidControl\nRibasim.Pump\nRibasim.Subgrid\nRibasim.TabulatedRatingCurve\nRibasim.Terminal\nRibasim.UserDemand\nRibasim.config.Config\nBasicModelInterface.finalize\nBasicModelInterface.initialize\nCommonSolve.solve!\nRibasim.add_basin_term!\nRibasim.add_constraints_absolute_value!\nRibasim.add_constraints_absolute_value_flow_demand!\nRibasim.add_constraints_absolute_value_level_demand!\nRibasim.add_constraints_absolute_value_user_demand!\nRibasim.add_constraints_basin_flow!\nRibasim.add_constraints_buffer!\nRibasim.add_constraints_capacity!\nRibasim.add_constraints_conservation_basin!\nRibasim.add_constraints_conservation_flow_demand!\nRibasim.add_constraints_conservation_subnetwork!\nRibasim.add_constraints_flow_demand_outflow!\nRibasim.add_constraints_fractional_flow!\nRibasim.add_constraints_source!\nRibasim.add_constraints_user_demand_returnflow!\nRibasim.add_flow!\nRibasim.add_flow!\nRibasim.add_flow_demand_term!\nRibasim.add_objective_term!\nRibasim.add_subnetwork_connections!\nRibasim.add_user_demand_term!\nRibasim.add_variables_absolute_value!\nRibasim.add_variables_basin!\nRibasim.add_variables_flow!\nRibasim.add_variables_flow_buffer!\nRibasim.adjust_capacities_basin!\nRibasim.adjust_capacities_buffers!\nRibasim.adjust_capacities_edge!\nRibasim.adjust_capacities_flow_demand_outflow!\nRibasim.adjust_capacities_source!\nRibasim.adjust_demands_flow!\nRibasim.all_neighbor_labels_type\nRibasim.allocate!\nRibasim.allocation_graph\nRibasim.allocation_graph_used_nodes!\nRibasim.allocation_path_exists_in_graph\nRibasim.allocation_problem\nRibasim.allocation_table\nRibasim.assign_allocations!\nRibasim.avoid_using_own_returnflow!\nRibasim.basin_bottom\nRibasim.basin_bottoms\nRibasim.basin_table\nRibasim.config.algorithm\nRibasim.config.convert_dt\nRibasim.config.convert_saveat\nRibasim.config.input_path\nRibasim.config.results_path\nRibasim.config.snake_case\nRibasim.create_callbacks\nRibasim.create_graph\nRibasim.create_storage_tables\nRibasim.datetime_since\nRibasim.datetimes\nRibasim.discrete_control_affect!\nRibasim.discrete_control_affect_downcrossing!\nRibasim.discrete_control_affect_upcrossing!\nRibasim.discrete_control_condition\nRibasim.discrete_control_table\nRibasim.expand_logic_mapping\nRibasim.find_allocation_graph_edges!\nRibasim.find_subnetwork_connections!\nRibasim.findlastgroup\nRibasim.findsorted\nRibasim.flow_table\nRibasim.formulate_basins!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.get_area_and_level\nRibasim.get_basin_capacity\nRibasim.get_basin_data\nRibasim.get_basin_demand\nRibasim.get_chunk_sizes\nRibasim.get_compressor\nRibasim.get_flow\nRibasim.get_flow\nRibasim.get_fractional_flow_connected_basins\nRibasim.get_jac_prototype\nRibasim.get_level\nRibasim.get_scalar_interpolation\nRibasim.get_storage_from_level\nRibasim.get_storages_and_levels\nRibasim.get_storages_from_levels\nRibasim.get_tstops\nRibasim.get_value\nRibasim.id_index\nRibasim.indicate_allocation_flow!\nRibasim.inflow_id\nRibasim.inflow_ids\nRibasim.inflow_ids_allocation\nRibasim.inneighbor_labels_type\nRibasim.inoutflow_ids\nRibasim.integrate_flows!\nRibasim.is_allocation_source\nRibasim.is_current_module\nRibasim.is_flow_constraining\nRibasim.is_flow_direction_constraining\nRibasim.load_data\nRibasim.load_structvector\nRibasim.low_storage_factor\nRibasim.main\nRibasim.metadata_from_edge\nRibasim.nodefields\nRibasim.nodetype\nRibasim.outflow_id\nRibasim.outflow_ids\nRibasim.outflow_ids_allocation\nRibasim.outneighbor_labels_type\nRibasim.parse_static_and_time\nRibasim.pkgversion\nRibasim.process_allocation_graph_edges!\nRibasim.profile_storage\nRibasim.qh_interpolation\nRibasim.reduction_factor\nRibasim.run\nRibasim.save_allocation_flows!\nRibasim.save_demands_and_allocations!\nRibasim.save_flow\nRibasim.save_subgrid_level\nRibasim.scalar_interpolation_derivative\nRibasim.seconds_since\nRibasim.set_current_value!\nRibasim.set_flow!\nRibasim.set_flow!\nRibasim.set_fractional_flow_in_allocation!\nRibasim.set_initial_discrete_controlled_parameters!\nRibasim.set_is_pid_controlled!\nRibasim.set_objective_priority!\nRibasim.set_static_value!\nRibasim.set_table_row!\nRibasim.sorted_table!\nRibasim.tsaves\nRibasim.update_allocation!\nRibasim.update_basin\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_tabulated_rating_curve!\nRibasim.valid_discrete_control\nRibasim.valid_edge_types\nRibasim.valid_edges\nRibasim.valid_flow_rates\nRibasim.valid_fractional_flow\nRibasim.valid_n_neighbors\nRibasim.valid_profiles\nRibasim.valid_sources\nRibasim.valid_subgrid\nRibasim.water_balance!\nRibasim.write_arrow\nRibasim.write_results\nRibasim.config.@addfields\nRibasim.config.@addnodetypes",
"crumbs": [
"Julia core",
"API Reference"
@@ -475,7 +482,7 @@
"href": "core/equations.html#sec-reduction_factor",
"title": "Equations",
"section": "2.1 The reduction factor",
- "text": "2.1 The reduction factor\nAt several points in the equations below a reduction factor is used. This is a term that makes certain transitions more smooth, for instance when a pump stops providing water when its source basin dries up. The reduction factor is given by\n\\[\\begin{align}\n \\phi(x; p) =\n \\begin{cases}\n 0 &\\text{if}\\quad x < 0 \\\\\n -2 \\left(\\frac{x}{p}\\right)^3 + 3\\left(\\frac{x}{p}\\right)^2 &\\text{if}\\quad 0 \\le x \\le p \\\\\n 1 &\\text{if}\\quad x > p\n \\end{cases}\n\\end{align}\\]\nHere \\(p > 0\\) is the threshold value which determines the interval \\([0,p]\\) of the smooth transition between \\(0\\) and \\(1\\), see the plot below.\n\n\nCode\nimport numpy as np\nimport matplotlib.pyplot as plt\n\ndef f(x, p = 3):\n x_scaled = x / p\n phi = (-2 * x_scaled + 3) * x_scaled**2\n phi = np.where(x < 0, 0, phi)\n phi = np.where(x > p, 1, phi)\n\n return phi\n\nfontsize = 15\np = 3\nN = 100\nx_min = -1\nx_max = 4\nx = np.linspace(x_min,x_max,N)\nphi = f(x,p)\n\nfig,ax = plt.subplots(dpi=80)\nax.plot(x,phi)\n\ny_lim = ax.get_ylim()\n\nax.set_xticks([0,p], [0,\"$p$\"], fontsize=fontsize)\nax.set_yticks([0,1], [0,1], fontsize=fontsize)\nax.hlines([0,1],x_min,x_max, color = \"k\", ls = \":\", zorder=-1)\nax.vlines([0,p], *y_lim, color = \"k\", ls = \":\")\nax.set_xlim(x_min,x_max)\nax.set_xlabel(\"$x$\", fontsize=fontsize)\nax.set_ylabel(\"$\\phi(x;p)$\", fontsize=fontsize)\nax.set_ylim(y_lim)\n\nfig.tight_layout()\nplt.show()\n\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n/tmp/ipykernel_2757/665069857.py:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'",
+ "text": "2.1 The reduction factor\nAt several points in the equations below a reduction factor is used. This is a term that makes certain transitions more smooth, for instance when a pump stops providing water when its source basin dries up. The reduction factor is given by\n\\[\\begin{align}\n \\phi(x; p) =\n \\begin{cases}\n 0 &\\text{if}\\quad x < 0 \\\\\n -2 \\left(\\frac{x}{p}\\right)^3 + 3\\left(\\frac{x}{p}\\right)^2 &\\text{if}\\quad 0 \\le x \\le p \\\\\n 1 &\\text{if}\\quad x > p\n \\end{cases}\n\\end{align}\\]\nHere \\(p > 0\\) is the threshold value which determines the interval \\([0,p]\\) of the smooth transition between \\(0\\) and \\(1\\), see the plot below.\n\n\nCode\nimport numpy as np\nimport matplotlib.pyplot as plt\n\ndef f(x, p = 3):\n x_scaled = x / p\n phi = (-2 * x_scaled + 3) * x_scaled**2\n phi = np.where(x < 0, 0, phi)\n phi = np.where(x > p, 1, phi)\n\n return phi\n\nfontsize = 15\np = 3\nN = 100\nx_min = -1\nx_max = 4\nx = np.linspace(x_min,x_max,N)\nphi = f(x,p)\n\nfig,ax = plt.subplots(dpi=80)\nax.plot(x,phi)\n\ny_lim = ax.get_ylim()\n\nax.set_xticks([0,p], [0,\"$p$\"], fontsize=fontsize)\nax.set_yticks([0,1], [0,1], fontsize=fontsize)\nax.hlines([0,1],x_min,x_max, color = \"k\", ls = \":\", zorder=-1)\nax.vlines([0,p], *y_lim, color = \"k\", ls = \":\")\nax.set_xlim(x_min,x_max)\nax.set_xlabel(\"$x$\", fontsize=fontsize)\nax.set_ylabel(\"$\\phi(x;p)$\", fontsize=fontsize)\nax.set_ylim(y_lim)\n\nfig.tight_layout()\nplt.show()\n\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n/tmp/ipykernel_2915/665069857.py:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'",
"crumbs": [
"Julia core",
"Equations"
@@ -695,7 +702,7 @@
"href": "core/usage.html#userdemand-time",
"title": "Usage",
"section": "10.1 UserDemand / time",
- "text": "10.1 UserDemand / time\nThis table is the transient form of the UserDemand table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the demand can be updated over time. In between the given times the demand is interpolated linearly, and outside the demand is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\npriority\nInt32\n-\npositive, sorted per node id\n\n\ntime\nDateTime\n-\nsorted per priority per node id\n\n\ndemand\nFloat64\n\\(m^3 s^{-1}\\)\n-\n\n\nreturn_factor\nFloat64\n-\nbetween [0 - 1]\n\n\nmin_level\nFloat64\n\\(m\\)\n-",
+ "text": "10.1 UserDemand / time\nThis table is the transient form of the UserDemand table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the demand can be updated over time. In between the given times the demand is interpolated linearly, and outside the demand is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\npriority\nInt32\n-\npositive, sorted per node id\n\n\ntime\nDateTime\n-\nsorted per priority per node id\n\n\ndemand\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative\n\n\nreturn_factor\nFloat64\n-\nbetween [0 - 1]\n\n\nmin_level\nFloat64\n\\(m\\)\n-",
"crumbs": [
"Julia core",
"Usage"
@@ -712,12 +719,23 @@
"Usage"
]
},
+ {
+ "objectID": "core/usage.html#flowdemand-time",
+ "href": "core/usage.html#flowdemand-time",
+ "title": "Usage",
+ "section": "12.1 FlowDemand / time",
+ "text": "12.1 FlowDemand / time\nThis table is the transient form of the FlowDemand table, in which a time-dependent demand can be supplied. Similar to the static version, only a single priority per FlowDemand node can be provided.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node id\n\n\npriority\nInt32\n-\npositive\n\n\ndemand\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative",
+ "crumbs": [
+ "Julia core",
+ "Usage"
+ ]
+ },
{
"objectID": "core/usage.html#levelboundary-time",
"href": "core/usage.html#levelboundary-time",
"title": "Usage",
- "section": "12.1 LevelBoundary / time",
- "text": "12.1 LevelBoundary / time\nThis table is the transient form of the LevelBoundary table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the levels can be updated over time. In between the given times the level is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlevel\nFloat64\n\\(m\\)\n-",
+ "section": "13.1 LevelBoundary / time",
+ "text": "13.1 LevelBoundary / time\nThis table is the transient form of the LevelBoundary table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the levels can be updated over time. In between the given times the level is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlevel\nFloat64\n\\(m\\)\n-",
"crumbs": [
"Julia core",
"Usage"
@@ -727,8 +745,8 @@
"objectID": "core/usage.html#flowboundary-time",
"href": "core/usage.html#flowboundary-time",
"title": "Usage",
- "section": "13.1 FlowBoundary / time",
- "text": "13.1 FlowBoundary / time\nThis table is the transient form of the FlowBoundary table. The only differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the flow rates can be updated over time. In between the given times the flow rate is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative",
+ "section": "14.1 FlowBoundary / time",
+ "text": "14.1 FlowBoundary / time\nThis table is the transient form of the FlowBoundary table. The only differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the flow rates can be updated over time. In between the given times the flow rate is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative",
"crumbs": [
"Julia core",
"Usage"
@@ -738,8 +756,8 @@
"objectID": "core/usage.html#discretecontrol-condition",
"href": "core/usage.html#discretecontrol-condition",
"title": "Usage",
- "section": "17.1 DiscreteControl / condition",
- "text": "17.1 DiscreteControl / condition\nThe 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.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\nlisten_node_type\nString\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\nsorted per node_id\n\n\nvariable\nString\n-\nmust be “level” or “flow_rate”, sorted per listen_node_id\n\n\ngreater_than\nFloat64\nvarious\nsorted per variable\n\n\nlook_ahead\nFloat64\n\\(s\\)\nOnly on transient boundary conditions, non-negative (optional, default 0)",
+ "section": "18.1 DiscreteControl / condition",
+ "text": "18.1 DiscreteControl / condition\nThe 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.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\nlisten_node_type\nString\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\nsorted per node_id\n\n\nvariable\nString\n-\nmust be “level” or “flow_rate”, sorted per listen_node_id\n\n\ngreater_than\nFloat64\nvarious\nsorted per variable\n\n\nlook_ahead\nFloat64\n\\(s\\)\nOnly on transient boundary conditions, non-negative (optional, default 0)",
"crumbs": [
"Julia core",
"Usage"
@@ -749,8 +767,8 @@
"objectID": "core/usage.html#discretecontrol-logic",
"href": "core/usage.html#discretecontrol-logic",
"title": "Usage",
- "section": "17.2 DiscreteControl / logic",
- "text": "17.2 DiscreteControl / logic\nThe logic schema defines which control states are triggered based on the truth of the conditions a DiscreteControl node listens to. DiscreteControl is applied in the Julia core as follows:\n\nDuring the simulation it is checked whether the truth of any of the conditions changes.\nWhen a condition changes, the corresponding DiscreteControl node ID is retrieved (node_id in the condition schema above).\nThe truth value of all the conditions this DiscreteControl node listens to are retrieved, in the sorted order as specified in the condition schema. This is then converted into a string of “T” for true and “F” for false. This string we call the truth state.*\nThe table below determines for the given DiscreteControl node ID and truth state what the corresponding control state is.\nFor all the nodes this DiscreteControl node affects (as given by the “control” edges in Edges / static), their parameters are set to those parameters in NodeType / static corresponding to the determined control state.\n\n*. There is also a second truth state created in which for the last condition that changed it is specified whether it was an upcrossing (“U”) or downcrossing (“D”) of the threshold (greater than) value. If a control state is specified for a truth state that is crossing-specific, this takes precedence over the control state for the truth state that contains only “T” and “F”.\n\n\n\n\n\n\nNote\n\n\n\nWhen creating truth states, it is important to not use the order of the condition table as you provide it, but the order as it is written to the file. Users can provide tables in any order, but when writing the model it gets sorted in the required order as specified in the schema.\n\n\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ncontrol_state\nString\n-\n-\n\n\ntruth_state\nString\n-\nConsists of the characters “T” (true), “F” (false), “U” (upcrossing), “D” (downcrossing) and “*” (any), sorted per node_id",
+ "section": "18.2 DiscreteControl / logic",
+ "text": "18.2 DiscreteControl / logic\nThe logic schema defines which control states are triggered based on the truth of the conditions a DiscreteControl node listens to. DiscreteControl is applied in the Julia core as follows:\n\nDuring the simulation it is checked whether the truth of any of the conditions changes.\nWhen a condition changes, the corresponding DiscreteControl node ID is retrieved (node_id in the condition schema above).\nThe truth value of all the conditions this DiscreteControl node listens to are retrieved, in the sorted order as specified in the condition schema. This is then converted into a string of “T” for true and “F” for false. This string we call the truth state.*\nThe table below determines for the given DiscreteControl node ID and truth state what the corresponding control state is.\nFor all the nodes this DiscreteControl node affects (as given by the “control” edges in Edges / static), their parameters are set to those parameters in NodeType / static corresponding to the determined control state.\n\n*. There is also a second truth state created in which for the last condition that changed it is specified whether it was an upcrossing (“U”) or downcrossing (“D”) of the threshold (greater than) value. If a control state is specified for a truth state that is crossing-specific, this takes precedence over the control state for the truth state that contains only “T” and “F”.\n\n\n\n\n\n\nNote\n\n\n\nWhen creating truth states, it is important to not use the order of the condition table as you provide it, but the order as it is written to the file. Users can provide tables in any order, but when writing the model it gets sorted in the required order as specified in the schema.\n\n\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ncontrol_state\nString\n-\n-\n\n\ntruth_state\nString\n-\nConsists of the characters “T” (true), “F” (false), “U” (upcrossing), “D” (downcrossing) and “*” (any), sorted per node_id",
"crumbs": [
"Julia core",
"Usage"
@@ -760,8 +778,8 @@
"objectID": "core/usage.html#pidcontrol-time",
"href": "core/usage.html#pidcontrol-time",
"title": "Usage",
- "section": "18.1 PidControl / time",
- "text": "18.1 PidControl / time\nThis table is the transient form of the PidControl table. The differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the target level and PID coefficients can be updated over time. In between the given times the these values interpolated linearly, and outside these values area constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlisten_node_type\nInt32\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\n-\n\n\ntarget\nFloat64\n\\(m\\)\n-\n\n\nproportional\nFloat64\n\\(s^{-1}\\)\n-\n\n\nintegral\nFloat64\n\\(s^{-2}\\)\n-\n\n\nderivative\nFloat64\n-\n-",
+ "section": "19.1 PidControl / time",
+ "text": "19.1 PidControl / time\nThis table is the transient form of the PidControl table. The differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the target level and PID coefficients can be updated over time. In between the given times the these values interpolated linearly, and outside these values area constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlisten_node_type\nInt32\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\n-\n\n\ntarget\nFloat64\n\\(m\\)\n-\n\n\nproportional\nFloat64\n\\(s^{-1}\\)\n-\n\n\nintegral\nFloat64\n\\(s^{-2}\\)\n-\n\n\nderivative\nFloat64\n-\n-",
"crumbs": [
"Julia core",
"Usage"
@@ -771,8 +789,8 @@
"objectID": "core/usage.html#basin---basin.arrow",
"href": "core/usage.html#basin---basin.arrow",
"title": "Usage",
- "section": "19.1 Basin - basin.arrow",
- "text": "19.1 Basin - basin.arrow\nThe basin table contains results of the storage and level of each basin at every solver timestep. The initial condition is also written to the file.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nnode_id\nInt32\n-\n\n\nstorage\nFloat64\n\\(m^3\\)\n\n\nlevel\nFloat64\n\\(m\\)\n\n\n\nThe table is sorted by time, and per time it is sorted by node_id.",
+ "section": "20.1 Basin - basin.arrow",
+ "text": "20.1 Basin - basin.arrow\nThe basin table contains results of the storage and level of each basin at every solver timestep. The initial condition is also written to the file.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nnode_id\nInt32\n-\n\n\nstorage\nFloat64\n\\(m^3\\)\n\n\nlevel\nFloat64\n\\(m\\)\n\n\n\nThe table is sorted by time, and per time it is sorted by node_id.",
"crumbs": [
"Julia core",
"Usage"
@@ -782,8 +800,8 @@
"objectID": "core/usage.html#flow---flow.arrow",
"href": "core/usage.html#flow---flow.arrow",
"title": "Usage",
- "section": "19.2 Flow - flow.arrow",
- "text": "19.2 Flow - flow.arrow\nThe flow table contains calculated mean flows for every flow edge in the model. In the time column the start of the period is indicated.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nedge_id\nUnion{Int32, Missing}\n-\n\n\nfrom_node_type\nString\n-\n\n\nfrom_node_id\nInt32\n-\n\n\nto_node_type\nString\n-\n\n\nto_node_id\nInt32\n-\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\n\n\n\nThe table is sorted by time, and per time the same edge_id order is used, though not sorted. The edge_id value is the same as the fid written to the Edge table, and can be used to directly look up the Edge geometry. Flows that are added to the model at a node, have a missing edge_id, and identical from_node_id and to_node_id. Flows out of the model always have a negative sign, and additions a positive sign.",
+ "section": "20.2 Flow - flow.arrow",
+ "text": "20.2 Flow - flow.arrow\nThe flow table contains calculated mean flows for every flow edge in the model. In the time column the start of the period is indicated.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nedge_id\nUnion{Int32, Missing}\n-\n\n\nfrom_node_type\nString\n-\n\n\nfrom_node_id\nInt32\n-\n\n\nto_node_type\nString\n-\n\n\nto_node_id\nInt32\n-\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\n\n\n\nThe table is sorted by time, and per time the same edge_id order is used, though not sorted. The edge_id value is the same as the fid written to the Edge table, and can be used to directly look up the Edge geometry. Flows that are added to the model at a node, have a missing edge_id, and identical from_node_id and to_node_id. Flows out of the model always have a negative sign, and additions a positive sign.",
"crumbs": [
"Julia core",
"Usage"
@@ -793,8 +811,8 @@
"objectID": "core/usage.html#discretecontrol---control.arrow",
"href": "core/usage.html#discretecontrol---control.arrow",
"title": "Usage",
- "section": "19.3 DiscreteControl - control.arrow",
- "text": "19.3 DiscreteControl - control.arrow\nThe control table contains a record of each change of control state: when it happened, which control node was involved, to which control state it changed and based on which truth state.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\ncontrol_node_id\nInt32\n\n\ntruth_state\nString\n\n\ncontrol_state\nString",
+ "section": "20.3 DiscreteControl - control.arrow",
+ "text": "20.3 DiscreteControl - control.arrow\nThe control table contains a record of each change of control state: when it happened, which control node was involved, to which control state it changed and based on which truth state.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\ncontrol_node_id\nInt32\n\n\ntruth_state\nString\n\n\ncontrol_state\nString",
"crumbs": [
"Julia core",
"Usage"
@@ -804,8 +822,8 @@
"objectID": "core/usage.html#allocation---allocation.arrow",
"href": "core/usage.html#allocation---allocation.arrow",
"title": "Usage",
- "section": "19.4 Allocation - allocation.arrow",
- "text": "19.4 Allocation - allocation.arrow\nThe allocation table contains a record of allocation results: when it happened, for which node, in which allocation network, and what the demand, allocated flow and realized flow were.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nsubnetwork_id\nInt32\n\n\nnode_type\nString\n\n\nnode_id\nInt32\n\n\npriority\nInt32\n\n\ndemand\nFloat64\n\n\nallocated\nFloat64\n\n\nrealized\nFloat64\n\n\n\nFor Basins the values demand, allocated and realized are positive if the Basin level is below the minimum level given by a LevelDemand node. The values are negative if the Basin supplies due to a surplus of water.\n\n\n\n\n\n\nNote\n\n\n\nCurrently the stored demand and abstraction rate are those at the allocation timepoint (and the abstraction rate is based on the previous allocation optimization). In the future these will be an average over the previous allocation timestep.",
+ "section": "20.4 Allocation - allocation.arrow",
+ "text": "20.4 Allocation - allocation.arrow\nThe allocation table contains a record of allocation results: when it happened, for which node, in which allocation network, and what the demand, allocated flow and realized flow were.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nsubnetwork_id\nInt32\n\n\nnode_type\nString\n\n\nnode_id\nInt32\n\n\npriority\nInt32\n\n\ndemand\nFloat64\n\n\nallocated\nFloat64\n\n\nrealized\nFloat64\n\n\n\nFor Basins the values demand, allocated and realized are positive if the Basin level is below the minimum level given by a LevelDemand node. The values are negative if the Basin supplies due to a surplus of water.\n\n\n\n\n\n\nNote\n\n\n\nCurrently the stored demand and abstraction rate are those at the allocation timepoint (and the abstraction rate is based on the previous allocation optimization). In the future these will be an average over the previous allocation timestep.",
"crumbs": [
"Julia core",
"Usage"
@@ -815,8 +833,8 @@
"objectID": "core/usage.html#allocation-flow---allocation_flow.arrow",
"href": "core/usage.html#allocation-flow---allocation_flow.arrow",
"title": "Usage",
- "section": "19.5 Allocation flow - allocation_flow.arrow",
- "text": "19.5 Allocation flow - allocation_flow.arrow\nThe allocation flow table contains results of the optimized allocation flow on every edge in the model that is part of a subnetwork, for each time an optimization problem is solved (see also here). If in the model a main network and subnetwork(s) are specified, there are 2 different types of optimization for the subnetwork: collecting its total demand per priority (for allocating flow from the main network to the subnetwork), and allocating flow within the subnetwork. The column collect_demands provides the distinction between these two optimization types.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nedge_id\nInt32\n\n\nfrom_node_type\nString\n\n\nfrom_node_id\nInt32\n\n\nto_node_type\nString\n\n\nto_node_id\nInt32\n\n\nsubnetwork_id\nInt32\n\n\npriority\nInt32\n\n\nflow_rate\nFloat64\n\n\ncollect_demands\nBool",
+ "section": "20.5 Allocation flow - allocation_flow.arrow",
+ "text": "20.5 Allocation flow - allocation_flow.arrow\nThe allocation flow table contains results of the optimized allocation flow on every edge in the model that is part of a subnetwork, for each time an optimization problem is solved (see also here). If in the model a main network and subnetwork(s) are specified, there are 2 different types of optimization for the subnetwork: collecting its total demand per priority (for allocating flow from the main network to the subnetwork), and allocating flow within the subnetwork. The column collect_demands provides the distinction between these two optimization types.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nedge_id\nInt32\n\n\nfrom_node_type\nString\n\n\nfrom_node_id\nInt32\n\n\nto_node_type\nString\n\n\nto_node_id\nInt32\n\n\nsubnetwork_id\nInt32\n\n\npriority\nInt32\n\n\nflow_rate\nFloat64\n\n\ncollect_demands\nBool",
"crumbs": [
"Julia core",
"Usage"
@@ -882,7 +900,7 @@
"href": "core/allocation.html",
"title": "Allocation",
"section": "",
- "text": "Allocation is the process of assigning an allocated abstraction flow rate to demand nodes in the physical layer of the model based on information about sources, the different demand nodes over various priorities, constraints introduced by nodes, local water availability and graph topology. The allocation procedure implemented in Ribasim is heavily inspired by the maximum flow problem.\nThe allocation problem is solved per subnetwork of the Ribasim model. The subnetwork is used to formulate an optimization problem with the JuMP package, which is solved using the HiGHS solver. For more in-depth information see also the example of solving the maximum flow problem with JuMP.jl here.",
+ "text": "Allocation is the process of assigning an allocated flow rate to demand nodes in the physical layer of the model based on information about sources, the different demand nodes over various priorities, constraints introduced by nodes, local water availability and graph topology. The allocation procedure implemented in Ribasim is heavily inspired by the maximum flow problem.\nThe allocation problem is solved per subnetwork of the Ribasim model. The subnetwork is used to formulate an optimization problem with the JuMP package, which is solved using the HiGHS solver. For more in-depth information see also the example of solving the maximum flow problem with JuMP.jl here.",
"crumbs": [
"Julia core",
"Allocation"
@@ -893,7 +911,7 @@
"href": "core/allocation.html#schematisation-input",
"title": "Allocation",
"section": "3.1 Schematisation input",
- "text": "3.1 Schematisation input\n\n3.1.1 The subnetwork\nThe allocation problem is solved per subnetwork, which is given by a subset \\(S \\subset V\\) of node ids. Different subnetworks are disjoint from eachother.\n\n\n3.1.2 Source flows\nSources are indicated by a set of edges in the subnetwork \\[\nE_S^\\text{source} \\subset \\left(S \\times S\\right) \\cap E.\n\\] That is, if \\((i,j) \\in E_S^\\text{source}\\), then \\(Q_{ij}\\) (see the formal model description) is treated as a source flow in the allocation problem. These edges are either coming from a boundary/source node (e.g. a level or flow boundary) or connect the main network to a subnetwork.\n\n\n3.1.3 User demands\nThe subnetwork contains a subset of UserDemand nodes \\(U_S \\subset S\\), who all have time varying demands over various priorities \\(p\\): \\[\n d^p_i(t), \\quad i \\in U_S, p = 1,2,\\ldots, p_{\\max}.\n\\]\n\n\n\n\n\n\nNote\n\n\n\nOn this page we assume that the priorities are given by all integers from \\(1\\) to some \\(p_{\\max} \\in \\mathbb{N}\\). However, in the Ribasim input this is not a requirement; some of these in between priority values can be missing, only the ordering of the given priorities is taken into account.",
+ "text": "3.1 Schematisation input\n\n3.1.1 The subnetwork\nThe allocation problem is solved per subnetwork, which is given by a subset \\(S \\subset V\\) of node ids. Different subnetworks are disjoint from eachother.\n\n\n3.1.2 Source flows\nSources are indicated by a set of edges in the subnetwork \\[\nE_S^\\text{source} \\subset \\left(S \\times S\\right) \\cap E.\n\\] That is, if \\((i,j) \\in E_S^\\text{source}\\), then \\(Q_{ij}\\) (see the formal model description) is treated as a source flow in the allocation problem. These edges are either coming from a boundary/source node (e.g. a level or flow boundary) or connect the main network to a subnetwork.\n\n\n3.1.3 User demands\nThe subnetwork contains a subset of UserDemand nodes \\(U_S \\subset S\\), who all have static or time varying demands over various priorities \\(p\\): \\[\n d^p_i(t), \\quad i \\in U_S, p = 1,2,\\ldots, p_{\\max}.\n\\] However, in\n\n\n\n\n\n\nNote\n\n\n\nOn this page we assume that the priorities are given by all integers from \\(1\\) to some \\(p_{\\max} \\in \\mathbb{N}\\).the Ribasim input this is not a requirement; some of these in between priority values can be missing, only the ordering of the given priorities is taken into account.\n\n\n\n\n3.1.4 Flow demands\nThe subnetwork contains a subset of nodes \\(FD_S \\in S\\) which have a demand of a single priority \\(p_{\\text{fd}}\\). With this we define \\[\n d^p_i(t) =\n \\begin{cases}\n 0 \\text{ if } p \\ne p_{\\text{fd}} \\\\\n d^{p_{\\text{df}}} \\text{ if } p = p_{\\text{fd}}\n \\end{cases}\n\\] for all \\(i \\in FD_S\\). Here \\(d^{p_{\\text{df}}}\\) is given by the original flow demand minus the flows trough node \\(i\\) at all priorities \\(p < p_{\\text{fd}}\\).",
"crumbs": [
"Julia core",
"Allocation"
@@ -915,7 +933,7 @@
"href": "core/allocation.html#the-allocation-network",
"title": "Allocation",
"section": "3.3 The allocation network",
- "text": "3.3 The allocation network\nA new graph is created from the subnetwork, which we call an allocation network. The allocation network is almost a subgraph of the main (flow) model, apart from the fact that an allocation network can contain edges which are a combination of multiple edges in the main model.\n\n3.3.1 Nodes and edges\nThe allocation network consists of:\n\nNodes \\(V'_S \\subset V_S\\), where each Basin, source and demand in the subnetwork get a node in the allocation network. Also nodes that have FractionalFlow outneighbors get a node in the allocation network.\nEdges \\(E_S\\), which are either edges that also appear between nodes in the subnetwork or represent a sequence of those, creating a shortcut.\n\nFor notational convenience, we use the notation\n\\[\\begin{align}\n V^{\\text{out}}_S(i) = \\left\\{j \\in V'_S : (i,j) \\in E_S\\right\\} \\\\\n V^{\\text{in}}_S(j) = \\left\\{i \\in V'_S : (i,j) \\in E_S\\right\\}\n\\end{align}\\]\nfor the set of in-neighbors and out-neighbors of a node in the allocation network respectively.\n\n\n3.3.2 Capacities\nEach edge in the allocation network has an associated capacity. These capacities are collected in the sparse capacity matrix \\(C_S \\in \\overline{\\mathbb{R}}_{\\ge 0}^{n'\\times n'}\\) where \\(n' = \\#V'_S\\) is the number of nodes in the allocation network. The capacities can be infinite, if there is nothing in the model constraining the capacity of the edge.\nThe capacities are determined in different ways:\n\nIf an edge does not exist in the allocation network, i.e. \\((i,j) \\notin E_S\\) for certain \\(1 \\le i,j\\le n'\\), then \\((C_S)_{i,j} = 0\\);\nThe capacity of the edge \\(e \\in E_S\\) is given by the smallest max_flow_rate of the nodes along the equivalent edges in the subnetwork. If there are no nodes with a max_flow_rate, the edge capacity is infinite;\nIf the edge is a source, the capacity of the edge is given by the flow rate of that source.\n\nThere are also capacities \\(C^B_S \\in \\mathbb{R}^b\\) where \\(b = \\# B_S\\) is the number of basins, for the flow supplied by basins.",
+ "text": "3.3 The allocation network\nA new graph is created from the subnetwork, which we call an allocation network. The allocation network is almost a subgraph of the main (flow) model, apart from the fact that an allocation network can contain edges which are a combination of multiple edges in the main model.\n\n3.3.1 Nodes and edges\nThe allocation network consists of:\n\nNodes \\(V'_S \\subset V_S\\). Nodes that are represented in the allocation network are: nodes of type Basin, UserDemand and Terminal, nodes that have FractionalFlow downstream neighbors, nodes that have a flow demand and nodes that are connected to a source edge.\nEdges \\(E_S\\), which are either edges that also appear between nodes in the subnetwork or represent a sequence of those, creating a shortcut.\n\nFor notational convenience, we use the notation\n\\[\\begin{align}\n V^{\\text{out}}_S(i) = \\left\\{j \\in V'_S : (i,j) \\in E_S\\right\\} \\\\\n V^{\\text{in}}_S(j) = \\left\\{i \\in V'_S : (i,j) \\in E_S\\right\\}\n\\end{align}\\]\nfor the set of in-neighbors and out-neighbors of a node in the allocation network respectively.\n\n\n3.3.2 Capacities\nEach edge in the allocation network has an associated capacity. These capacities are collected in the sparse capacity matrix \\(C_S \\in \\overline{\\mathbb{R}}_{\\ge 0}^{n'\\times n'}\\) where \\(n' = \\#V'_S\\) is the number of nodes in the allocation network. The capacities can be infinite, if there is nothing in the model constraining the capacity of the edge.\nThe capacities are determined in different ways:\n\nIf an edge does not exist in the allocation network, i.e. \\((i,j) \\notin E_S\\) for certain \\(1 \\le i,j\\le n'\\), then \\((C_S)_{i,j} = 0\\);\nThe capacity of the edge \\(e \\in E_S\\) is given by the smallest max_flow_rate of the nodes along the equivalent edges in the subnetwork. If there are no nodes with a max_flow_rate, the edge capacity is infinite;\nIf the edge is a source, the capacity of the edge is given by the flow rate of that source;\nIf an edge comes from a node with a flow demand, it has infinite capacity at priorities other than this of this flow demand, and zero capacity otherwise.\n\nThere are also capacities for special edges:\n\n\\(C^B_S \\in \\mathbb{R}^b_{\\ge 0}\\) where \\(b = \\# B_S\\) is the number of basins, for the flow supplied by basins.\n\\(C^{FD}_S \\in \\mathbb{R}^c_{\\ge 0}\\) where \\(c = \\# FD_S\\) is the number of nodes with a flow demand, for the flow supplied by flow buffers at these nodes with a flow demand.",
"crumbs": [
"Julia core",
"Allocation"
@@ -926,7 +944,7 @@
"href": "core/allocation.html#the-optimization-variables",
"title": "Allocation",
"section": "4.1 The optimization variables",
- "text": "4.1 The optimization variables\nThere are several types of variable whose value has to be determined to solve the allocation problem:\n\nThe flows \\(F \\in \\mathbb{R}_{\\ge 0}^{n'\\times n'}\\) over the edges in the allocation network;\nThe flows \\(F^\\text{basin out}_{i}, F^\\text{basin in}_{i} \\geq 0\\) for all \\(i \\in B_S\\) supplied and consumed by the basins respectively.",
+ "text": "4.1 The optimization variables\nThere are several types of variable whose value has to be determined to solve the allocation problem:\n\nThe flows \\(F \\in \\mathbb{R}_{\\ge 0}^{n'\\times n'}\\) over the edges in the allocation network;\nThe flows \\(F^\\text{basin out}_{i}, F^\\text{basin in}_{i} \\geq 0\\) for all \\(i \\in B_S\\) supplied and consumed by the basins respectively;\nThe flows \\(F^\\text{buffer out}_{i}, F^\\text{buffer in}_{i} \\ge 0\\) for all \\(i \\in FD_S\\) supplied and consumed by the flow buffers of nodes with a flow demand respectively.",
"crumbs": [
"Julia core",
"Allocation"
@@ -937,7 +955,7 @@
"href": "core/allocation.html#the-optimization-objective",
"title": "Allocation",
"section": "4.2 The optimization objective",
- "text": "4.2 The optimization objective\nThe goal of allocation is to get the flow to nodes with demands as close as possible to these demands. To achieve this, a sum error of terms is minimized.\n\\[\n \\min E_{\\text{user demand}} + E_{\\text{basin}}\n\\]\nThe error between the flows and user demands is denoted by \\(E_{\\text{user demand}}\\), where \\[\n E_{\\text{user demand}} = \\sum_{(i,j)\\in E_S\\;:\\; i\\in U_S} \\left| F_{ij} - d_j^p(t)\\right|\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing main network allocation, the connections to subnetworks are also interpreted as UserDemand with demands determined by subnetwork demand collection.\n\n\nThis type of objective cares about the absolute amount of water allocated to a demand. It treats all deviations equally which means it doesn’t give larger punishment per flow unit if deviations increase.\nThe absolute value applied here is not supported in a linear programming context directly; this requires introduction of new variables and constraints. For more details see here.\nLikewise, the error of basin demands is the absolute difference between flows consumed by basins and basin demands. \\[\n E_{\\text{basin}} = \\sum_{i \\in B_S} \\left| F_i^\\text{basin in} - d_i^p(t)\\right|\n\\]",
+ "text": "4.2 The optimization objective\nThe goal of allocation is to get the flow to nodes with demands as close as possible to these demands. To achieve this, a sum error of terms is minimized.\n\\[\n \\min E_{\\text{user demand}} + E_{\\text{level demand}} + E_{\\text{flow demand}}\n\\]\nThe error between the flows and user demands is denoted by \\(E_{\\text{user demand}}\\), where \\[\n E_{\\text{user demand}} = \\sum_{(i,j)\\in E_S\\;:\\; i\\in U_S} \\left| F_{ij} - d_j^p(t)\\right|\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing main network allocation, the connections to subnetworks are also interpreted as UserDemand with demands determined by subnetwork demand collection.\n\n\nThis type of objective cares about the absolute amount of water allocated to a demand. It treats all deviations equally which means it doesn’t give larger punishment per flow unit if deviations increase.\nThe absolute value applied here is not supported in a linear programming context directly; this requires introduction of new variables and constraints. For more details see here.\nLikewise, the error of level demands from basins is the absolute difference between flows consumed by basins and basin demands. \\[\n E_{\\text{level demand}} = \\sum_{i \\in B_S} \\left| F_i^\\text{basin in} - d_i^p(t)\\right|\n\\]\nLastly, the error of the flow demands is given as below. \\[\n E_{\\text{flow demand}} = \\sum_{i \\in FD_S} \\left| F_i^\\text{buffer in} - d_i^p(t)\\right|\n\\]",
"crumbs": [
"Julia core",
"Allocation"
@@ -948,7 +966,7 @@
"href": "core/allocation.html#the-optimization-constraints",
"title": "Allocation",
"section": "4.3 The optimization constraints",
- "text": "4.3 The optimization constraints\n\nFlow conservation: For the basins in the allocation network we have that \\[\n F^\\text{basin in}_k + \\sum_{j=1}^{n'} F_{kj} = F^\\text{basin out}_k + \\sum_{i=1}^{n'} F_{ik}, \\quad \\forall k \\in B_S .\n\\tag{1}\\] Note that we do not require equality here; in the allocation we do not mind that excess flow is ‘forgotten’ if it cannot contribute to the allocation to the demands.\n\n\n\n\n\n\n\nNote\n\n\n\nIn Equation 1, the placement of the basin flows might seem counter-intuitive. Think of the basin storage as a separate node connected to the basin node.\n\n\n\nCapacity: the flows over the edges are positive and bounded by the edge capacity: \\[\n F_{ij} \\le \\left(C_S\\right)_{ij}, \\quad \\forall(i,j) \\in E_S.\n\\tag{2}\\] By the definition of \\(C_S\\) this also includes the source flows. The same holds for the basin outflows:\n\n\\[\n F^{\\text{basin out}}_{i} \\le F^{\\text{basin out}}_{\\max, i}, \\quad \\forall i \\in B_S.\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing subnetwork demand collection, these capacities are set to \\(\\infty\\) for edges which connect the main network to a subnetwork.\n\n\n\nUserDemand outflow: The outflow of the UserDemand is dictated by the inflow and the return factor: \\[\n F_{ik} = r_k \\cdot F_{kj} \\quad\n \\quad \\forall k \\in U_S, \\quad\n V^{\\text{in}}_S(k) = \\{i\\},\\;\n V^{\\text{out}}_S(k) = \\{j\\}.\n\\tag{3}\\] Here we use that each UserDemand node in the allocation network has a unique in-edge and out-edge.\nUser demand: UserDemand demand constraints are discussed in the next section.\nFractional flow: Let \\(L_S \\subset V_S\\) be the set of nodes in the max flow graph with fractional flow outneighbors, and \\(f_j\\) the flow fraction associated with fractional flow node \\(j \\in V_S\\). Then \\[\n F_{ij} \\le f_j \\sum_{k\\in V^\\text{in}_S(i)} F_{ki} \\qquad\n \\forall i \\in L_S, \\;\n j \\in V_S^\\text{out}(i).\n\\tag{4}\\]\nFlow sign: Furthermore there are the non-negativity constraints for the flows and allocations, see The optimization variables.",
+ "text": "4.3 The optimization constraints\n\nFlow conservation: For the basins in the allocation network we have that \\[\n F^\\text{basin in}_k + \\sum_{j \\in V^{\\text{out}}_S(k)} F_{kj} = F^\\text{basin out}_k + \\sum_{i \\in V^{\\text{in}}_S(k)} F_{ik}, \\quad \\forall k \\in B_S .\n\\tag{1}\\] We have the same constraint without the basin terms for nodes that have flow edges as inneighbors (except if this node also happens to be a basin). For nodes which have a flow demand we have \\[\nF_{kj} + F^\\text{buffer in}_k = F^\\text{flow in}_k + F_{ik}, \\quad \\forall k \\in FD_S, \\quad V^{\\text{in}}_S(k) = \\{i\\},\\;\n V^{\\text{out}}_S(k) = \\{j\\}.\n\\tag{2}\\]\n\n\n\n\n\n\n\nNote\n\n\n\nIn Equation 1 and Equation 2, the placement of the basin and buffer flows might seem counter-intuitive. Think of the storage or buffer as a separate node connected to the node with the demand.\n\n\n\nCapacity: the flows over the edges are bounded by the edge capacity: \\[\n F_{ij} \\le \\left(C_S\\right)_{ij}, \\quad \\forall(i,j) \\in E_S.\n\\tag{3}\\] By the definition of \\(C_S\\) this also includes the source flows. The same holds for the basin outflows:\n\n\\[\n F^{\\text{basin out}}_{i} \\le F^{\\text{basin out}}_{\\max, i}, \\quad \\forall i \\in B_S.\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing subnetwork demand collection, these capacities are set to \\(\\infty\\) for edges which connect the main network to a subnetwork.\n\n\nSimilar constraints hold for the flow out of basins and flow demand buffers: \\[\nF^\\text{basin out}_{i} \\le (C^B_S)_i, \\quad \\forall i \\in B_S,\n\\]\n\\[\nF^\\text{buffer out}_{i} \\le (C^FD_S)_i, \\quad \\forall i \\in FD_S.\n\\]\n\nUserDemand outflow: The outflow of the UserDemand is dictated by the inflow and the return factor: \\[\n F_{ik} = r_k \\cdot F_{kj} \\quad\n \\quad \\forall k \\in U_S, \\quad\n V^{\\text{in}}_S(k) = \\{i\\},\\;\n V^{\\text{out}}_S(k) = \\{j\\}.\n\\tag{4}\\] Here we use that each UserDemand node in the allocation network has a unique in-edge and out-edge.\nUser demand: UserDemand demand constraints are discussed in the next section.\nFractional flow: Let \\(L_S \\subset V_S\\) be the set of nodes in the max flow graph with fractional flow outneighbors, and \\(f_j\\) the flow fraction associated with fractional flow node \\(j \\in V_S\\). Then \\[\n F_{ij} \\le f_j \\sum_{k\\in V^\\text{in}_S(i)} F_{ki} \\qquad\n \\forall i \\in L_S, \\;\n j \\in V_S^\\text{out}(i).\n\\tag{5}\\]\nFlow sign: Furthermore there are the non-negativity constraints for the flows and allocations, see The optimization variables.",
"crumbs": [
"Julia core",
"Allocation"
@@ -970,7 +988,7 @@
"href": "core/allocation.html#example",
"title": "Allocation",
"section": "5.1 Example",
- "text": "5.1 Example\nThe following is an example of an optimization problem for the example shown here:\n\n\nCode\nusing Ribasim\nusing Ribasim: NodeID\nusing SQLite\nusing ComponentArrays: ComponentVector\n\ntoml_path = normpath(@__DIR__, \"../../generated_testmodels/allocation_example/ribasim.toml\")\np = Ribasim.Model(toml_path).integrator.p\nu = ComponentVector(; storage = zeros(length(p.basin.node_id)))\n\nallocation_model = p.allocation.allocation_models[1]\nt = 0.0\npriority_idx = 1\n\nRibasim.set_flow!(p.graph, NodeID(:FlowBoundary, 1), NodeID(:Basin, 2), 1.0)\n\nRibasim.adjust_source_capacities!(allocation_model, p, priority_idx)\nRibasim.adjust_edge_capacities!(allocation_model, p, priority_idx)\nRibasim.set_objective_priority!(allocation_model, p, u, t, priority_idx)\n\nprintln(p.allocation.allocation_models[1].problem)\n\n\nMin F_abs_user_demand[UserDemand #3] + F_abs_user_demand[UserDemand #13] + F_abs_user_demand[UserDemand #6] + F_abs_basin[Basin #2] + F_abs_basin[Basin #12] + F_abs_basin[Basin #5]\nSubject to\n flow_conservation[Basin #2] : -F[(Basin #5, Basin #2)] + F[(Basin #2, Basin #5)] - F[(FlowBoundary #1, Basin #2)] + F[(Basin #2, UserDemand #3)] + F_basin_in[Basin #2] - F_basin_out[Basin #2] = 0\n flow_conservation[Basin #12] : F[(Basin #12, UserDemand #13)] - F[(TabulatedRatingCurve #7, Basin #12)] + F_basin_in[Basin #12] - F_basin_out[Basin #12] = 0\n flow_conservation[Basin #5] : F[(Basin #5, UserDemand #6)] + F[(Basin #5, Basin #2)] - F[(Basin #2, Basin #5)] + F[(Basin #5, TabulatedRatingCurve #7)] + F_basin_in[Basin #5] - F_basin_out[Basin #5] = 0\n abs_positive_user_demand[UserDemand #3] : -F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ -1.5\n abs_positive_user_demand[UserDemand #13] : -F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_positive_user_demand[UserDemand #6] : -F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n abs_negative_user_demand[UserDemand #3] : F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ 1.5\n abs_negative_user_demand[UserDemand #13] : F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_negative_user_demand[UserDemand #6] : F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n abs_positive_basin[Basin #2] : -F_basin_in[Basin #2] + F_abs_basin[Basin #2] ≥ 0\n abs_positive_basin[Basin #12] : -F_basin_in[Basin #12] + F_abs_basin[Basin #12] ≥ 0\n abs_positive_basin[Basin #5] : -F_basin_in[Basin #5] + F_abs_basin[Basin #5] ≥ 0\n abs_negative_basin[Basin #2] : F_basin_in[Basin #2] + F_abs_basin[Basin #2] ≥ 0\n abs_negative_basin[Basin #12] : F_basin_in[Basin #12] + F_abs_basin[Basin #12] ≥ 0\n abs_negative_basin[Basin #5] : F_basin_in[Basin #5] + F_abs_basin[Basin #5] ≥ 0\n source[(FlowBoundary #1, Basin #2)] : F[(FlowBoundary #1, Basin #2)] ≤ 1\n return_flow[UserDemand #13] : F[(UserDemand #13, Terminal #10)] ≤ 0\n fractional_flow[(TabulatedRatingCurve #7, Basin #12)] : -0.4 F[(Basin #5, TabulatedRatingCurve #7)] + F[(TabulatedRatingCurve #7, Basin #12)] ≤ 0\n basin_outflow[Basin #2] : F_basin_out[Basin #2] ≤ 0\n basin_outflow[Basin #12] : F_basin_out[Basin #12] ≤ 0\n basin_outflow[Basin #5] : F_basin_out[Basin #5] ≤ 0\n F[(TabulatedRatingCurve #7, Terminal #10)] ≥ 0\n F[(Basin #5, UserDemand #6)] ≥ 0\n F[(Basin #5, Basin #2)] ≥ 0\n F[(Basin #12, UserDemand #13)] ≥ 0\n F[(Basin #2, Basin #5)] ≥ 0\n F[(FlowBoundary #1, Basin #2)] ≥ 0\n F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0\n F[(Basin #2, UserDemand #3)] ≥ 0\n F[(UserDemand #13, Terminal #10)] ≥ 0\n F[(TabulatedRatingCurve #7, Basin #12)] ≥ 0\n F_basin_in[Basin #2] ≥ 0\n F_basin_in[Basin #12] ≥ 0\n F_basin_in[Basin #5] ≥ 0\n F_basin_out[Basin #2] ≥ 0\n F_basin_out[Basin #12] ≥ 0\n F_basin_out[Basin #5] ≥ 0",
+ "text": "5.1 Example\nThe following is an example of an optimization problem for the example shown here:\n\n\nCode\nusing Ribasim\nusing Ribasim: NodeID\nusing SQLite\nusing ComponentArrays: ComponentVector\n\ntoml_path = normpath(@__DIR__, \"../../generated_testmodels/allocation_example/ribasim.toml\")\np = Ribasim.Model(toml_path).integrator.p\nu = ComponentVector(; storage = zeros(length(p.basin.node_id)))\n\nallocation_model = p.allocation.allocation_models[1]\nt = 0.0\npriority_idx = 1\n\nRibasim.set_flow!(p.graph, NodeID(:FlowBoundary, 1), NodeID(:Basin, 2), 1.0)\n\nRibasim.adjust_capacities_edge!(allocation_model, p, priority_idx)\nRibasim.adjust_capacities_source!(allocation_model, p, priority_idx)\nRibasim.set_objective_priority!(allocation_model, p, u, t, priority_idx)\n\nprintln(p.allocation.allocation_models[1].problem)\n\n\nMin F_abs_user_demand[UserDemand #3] + F_abs_user_demand[UserDemand #13] + F_abs_user_demand[UserDemand #6]\nSubject to\n flow_conservation_basin[Basin #5] : F[(Basin #5, UserDemand #6)] + F[(Basin #5, Basin #2)] - F[(Basin #2, Basin #5)] + F[(Basin #5, TabulatedRatingCurve #7)] = 0\n flow_conservation_basin[Basin #2] : F[(Basin #2, UserDemand #3)] - F[(FlowBoundary #1, Basin #2)] - F[(Basin #5, Basin #2)] + F[(Basin #2, Basin #5)] = 0\n flow_conservation_basin[Basin #12] : F[(Basin #12, UserDemand #13)] - F[(TabulatedRatingCurve #7, Basin #12)] = 0\n abs_positive_user_demand[UserDemand #3] : -F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ -1.5\n abs_positive_user_demand[UserDemand #13] : -F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_positive_user_demand[UserDemand #6] : -F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n abs_negative_user_demand[UserDemand #3] : F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ 1.5\n abs_negative_user_demand[UserDemand #13] : F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_negative_user_demand[UserDemand #6] : F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n source[(FlowBoundary #1, Basin #2)] : F[(FlowBoundary #1, Basin #2)] ≤ 1\n return_flow[UserDemand #13] : F[(UserDemand #13, Terminal #10)] ≤ 0\n fractional_flow[(TabulatedRatingCurve #7, Basin #12)] : F[(TabulatedRatingCurve #7, Basin #12)] - 0.4 F[(Basin #5, TabulatedRatingCurve #7)] ≤ 0\n F[(Basin #5, UserDemand #6)] ≥ 0\n F[(Basin #12, UserDemand #13)] ≥ 0\n F[(TabulatedRatingCurve #7, Terminal #10)] ≥ 0\n F[(UserDemand #13, Terminal #10)] ≥ 0\n F[(Basin #2, UserDemand #3)] ≥ 0\n F[(FlowBoundary #1, Basin #2)] ≥ 0\n F[(Basin #5, Basin #2)] ≥ 0\n F[(Basin #2, Basin #5)] ≥ 0\n F[(TabulatedRatingCurve #7, Basin #12)] ≥ 0\n F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0",
"crumbs": [
"Julia core",
"Allocation"
@@ -981,7 +999,7 @@
"href": "core/validation.html",
"title": "Validation",
"section": "",
- "text": "The tables below show the validation rules applied to the input to the Julia core before running the model.\n\n1 Connectivity\nIn 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.\n\n\nCode\nusing Ribasim\nusing DataFrames: DataFrame\nusing MarkdownTables\n\nnode_names_snake_case = Vector{Symbol}()\nnode_names_camel_case = Vector{Symbol}()\nfor (node_name, node_type) in zip(fieldnames(Ribasim.Parameters), fieldtypes(Ribasim.Parameters))\n if node_type <: Ribasim.AbstractParameterNode\n push!(node_names_snake_case, node_name)\n push!(node_names_camel_case, nameof(node_type))\n end\nend\n\nfunction to_symbol(b::Bool)::String\n return b ? \"✓\" : \"x\"\nend\n\n\ndf = DataFrame()\ndf[!, :downstream] = node_names_snake_case\n\nfor node_name in node_names_snake_case\n df[!, node_name] =\n [(to_symbol(node_name_ in Ribasim.neighbortypes(node_name))) for node_name_ in node_names_snake_case]\nend\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndownstream\nbasin\nlinear_resistance\nmanning_resistance\ntabulated_rating_curve\nfractional_flow\nlevel_boundary\nflow_boundary\npump\noutlet\nterminal\ndiscrete_control\npid_control\nuser_demand\n\n\n\n\nbasin\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nlinear_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\nmanning_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\ntabulated_rating_curve\n✓\nx\nx\nx\nx\nx\nx\nx\nx\nx\n✓\nx\nx\n\n\nfractional_flow\nx\nx\nx\n✓\nx\nx\n✓\n✓\n✓\nx\n✓\nx\n✓\n\n\nlevel_boundary\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nflow_boundary\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npump\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\noutlet\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\nterminal\nx\nx\nx\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\ndiscrete_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npid_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n✓\nx\nx\n\n\nuser_demand\n✓\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\n\n\n\n\n\n2 Neighbor amounts\nThe table below shows for each node type between which bounds the amount of in- and outneighbors must be, for both flow and control edges.\n\n\nCode\nflow_in_min = Vector{String}()\nflow_in_max = Vector{String}()\nflow_out_min = Vector{String}()\nflow_out_max = Vector{String}()\ncontrol_in_min = Vector{String}()\ncontrol_in_max = Vector{String}()\ncontrol_out_min = Vector{String}()\ncontrol_out_max = Vector{String}()\n\nfunction unbounded(i::Int)::String\n return i == typemax(Int) ? \"∞\" : string(i)\nend\n\nfor node_name in node_names_camel_case\n bounds_flow = Ribasim.n_neighbor_bounds_flow(node_name)\n push!(flow_in_min, string(bounds_flow.in_min))\n push!(flow_in_max, unbounded(bounds_flow.in_max))\n push!(flow_out_min, string(bounds_flow.out_min))\n push!(flow_out_max, unbounded(bounds_flow.out_max))\n\n bounds_control = Ribasim.n_neighbor_bounds_control(node_name)\n push!(control_in_min, string(bounds_control.in_min))\n push!(control_in_max, unbounded(bounds_control.in_max))\n push!(control_out_min, string(bounds_control.out_min))\n push!(control_out_max, unbounded(bounds_control.out_max))\n\nend\n\ndf = DataFrame(\n ;\n node_type = node_names_snake_case,\n flow_in_min,\n flow_in_max,\n flow_out_min,\n flow_out_max,\n control_in_min,\n control_in_max,\n control_out_min,\n control_out_max,\n)\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nnode_type\nflow_in_min\nflow_in_max\nflow_out_min\nflow_out_max\ncontrol_in_min\ncontrol_in_max\ncontrol_out_min\ncontrol_out_max\n\n\n\n\nbasin\n0\n∞\n0\n∞\n0\n1\n0\n∞\n\n\nlinear_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nmanning_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\ntabulated_rating_curve\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nfractional_flow\n1\n1\n1\n1\n0\n1\n0\n0\n\n\nlevel_boundary\n0\n∞\n0\n∞\n0\n0\n0\n0\n\n\nflow_boundary\n0\n0\n1\n∞\n0\n0\n0\n0\n\n\npump\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\noutlet\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nterminal\n1\n∞\n0\n0\n0\n0\n0\n0\n\n\ndiscrete_control\n0\n0\n0\n0\n0\n0\n1\n∞\n\n\npid_control\n0\n0\n0\n0\n0\n1\n1\n1\n\n\nuser_demand\n1\n1\n1\n1\n0\n0\n0\n0",
+ "text": "The tables below show the validation rules applied to the input to the Julia core before running the model.\n\n1 Connectivity\nIn 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.\n\n\nCode\nusing Ribasim\nusing DataFrames: DataFrame\nusing MarkdownTables\n\nnode_names_snake_case = Vector{Symbol}()\nnode_names_camel_case = Vector{Symbol}()\nfor (node_name, node_type) in zip(fieldnames(Ribasim.Parameters), fieldtypes(Ribasim.Parameters))\n if node_type <: Ribasim.AbstractParameterNode\n push!(node_names_snake_case, node_name)\n push!(node_names_camel_case, nameof(node_type))\n end\nend\n\nfunction to_symbol(b::Bool)::String\n return b ? \"✓\" : \"x\"\nend\n\n\ndf = DataFrame()\ndf[!, :downstream] = node_names_snake_case\n\nfor node_name in node_names_snake_case\n df[!, node_name] =\n [(to_symbol(node_name_ in Ribasim.neighbortypes(node_name))) for node_name_ in node_names_snake_case]\nend\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndownstream\nbasin\nlinear_resistance\nmanning_resistance\ntabulated_rating_curve\nfractional_flow\nlevel_boundary\nflow_boundary\npump\noutlet\nterminal\ndiscrete_control\npid_control\nuser_demand\n\n\n\n\nbasin\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nlinear_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\nmanning_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\ntabulated_rating_curve\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\nfractional_flow\nx\nx\nx\n✓\nx\nx\n✓\n✓\n✓\nx\n✓\nx\n✓\n\n\nlevel_boundary\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nflow_boundary\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npump\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\noutlet\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\nterminal\nx\nx\nx\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\ndiscrete_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npid_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n✓\nx\nx\n\n\nuser_demand\n✓\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\n\n\n\n\n\n2 Neighbor amounts\nThe table below shows for each node type between which bounds the amount of in- and outneighbors must be, for both flow and control edges.\n\n\nCode\nflow_in_min = Vector{String}()\nflow_in_max = Vector{String}()\nflow_out_min = Vector{String}()\nflow_out_max = Vector{String}()\ncontrol_in_min = Vector{String}()\ncontrol_in_max = Vector{String}()\ncontrol_out_min = Vector{String}()\ncontrol_out_max = Vector{String}()\n\nfunction unbounded(i::Int)::String\n return i == typemax(Int) ? \"∞\" : string(i)\nend\n\nfor node_name in node_names_camel_case\n bounds_flow = Ribasim.n_neighbor_bounds_flow(node_name)\n push!(flow_in_min, string(bounds_flow.in_min))\n push!(flow_in_max, unbounded(bounds_flow.in_max))\n push!(flow_out_min, string(bounds_flow.out_min))\n push!(flow_out_max, unbounded(bounds_flow.out_max))\n\n bounds_control = Ribasim.n_neighbor_bounds_control(node_name)\n push!(control_in_min, string(bounds_control.in_min))\n push!(control_in_max, unbounded(bounds_control.in_max))\n push!(control_out_min, string(bounds_control.out_min))\n push!(control_out_max, unbounded(bounds_control.out_max))\n\nend\n\ndf = DataFrame(\n ;\n node_type = node_names_snake_case,\n flow_in_min,\n flow_in_max,\n flow_out_min,\n flow_out_max,\n control_in_min,\n control_in_max,\n control_out_min,\n control_out_max,\n)\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nnode_type\nflow_in_min\nflow_in_max\nflow_out_min\nflow_out_max\ncontrol_in_min\ncontrol_in_max\ncontrol_out_min\ncontrol_out_max\n\n\n\n\nbasin\n0\n∞\n0\n∞\n0\n1\n0\n∞\n\n\nlinear_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nmanning_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\ntabulated_rating_curve\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nfractional_flow\n1\n1\n1\n1\n0\n1\n0\n0\n\n\nlevel_boundary\n0\n∞\n0\n∞\n0\n0\n0\n0\n\n\nflow_boundary\n0\n0\n1\n∞\n0\n0\n0\n0\n\n\npump\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\noutlet\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nterminal\n1\n∞\n0\n0\n0\n0\n0\n0\n\n\ndiscrete_control\n0\n0\n0\n0\n0\n0\n1\n∞\n\n\npid_control\n0\n0\n0\n0\n0\n1\n1\n1\n\n\nuser_demand\n1\n1\n1\n1\n0\n0\n0\n0",
"crumbs": [
"Julia core",
"Validation"
@@ -1155,18 +1173,25 @@
"text": "1 nodes.outlet\nnodes.outlet"
},
{
- "objectID": "python/reference/nodes.fractional_flow.html",
- "href": "python/reference/nodes.fractional_flow.html",
- "title": "1 nodes.fractional_flow",
+ "objectID": "python/reference/nodes.level_demand.html",
+ "href": "python/reference/nodes.level_demand.html",
+ "title": "1 nodes.level_demand",
"section": "",
- "text": "1 nodes.fractional_flow\nnodes.fractional_flow"
+ "text": "1 nodes.level_demand\nnodes.level_demand"
},
{
- "objectID": "python/reference/nodes.terminal.html",
- "href": "python/reference/nodes.terminal.html",
- "title": "1 nodes.terminal",
+ "objectID": "python/reference/nodes.level_boundary.html",
+ "href": "python/reference/nodes.level_boundary.html",
+ "title": "1 nodes.level_boundary",
"section": "",
- "text": "1 nodes.terminal\nnodes.terminal"
+ "text": "1 nodes.level_boundary\nnodes.level_boundary"
+ },
+ {
+ "objectID": "python/reference/nodes.flow_demand.html",
+ "href": "python/reference/nodes.flow_demand.html",
+ "title": "1 nodes.flow_demand",
+ "section": "",
+ "text": "1 nodes.flow_demand\nnodes.flow_demand"
},
{
"objectID": "python/reference/nodes.pid_control.html",
11 LevelDemand
-An LevelDemand
node associates a minimum and a maximum level with connected basins to be used by the allocation algorithm. Below the minimum level the basin has a demand of the supplied priority, above the maximum level the basin acts as a source, used by all nodes with demands in order of priority. The same LevelDemand
node can be used for basins in different subnetworks.
A LevelDemand
node associates a minimum and a maximum level with connected basins to be used by the allocation algorithm. Below the minimum level the basin has a demand of the supplied priority, above the maximum level the basin acts as a source, used by all nodes with demands in order of priority. The same LevelDemand
node can be used for basins in different subnetworks.
column | +type | +unit | +restriction | +
---|---|---|---|
node_id | +Int32 | +- | +sorted | +
priority | +Int32 | +- | +positive | +
demand | +Float64 | +\(m^3 s^{-1}\) | +non-negative | +
12.1 FlowDemand / time
+This table is the transient form of the FlowDemand
table, in which a time-dependent demand can be supplied. Similar to the static version, only a single priority per FlowDemand
node can be provided.
column | +type | +unit | +restriction | +
---|---|---|---|
node_id | +Int32 | +- | +sorted | +
time | +DateTime | +- | +sorted per node id | +
priority | +Int32 | +- | +positive | +
demand | +Float64 | +\(m^3 s^{-1}\) | +non-negative | +
13 LevelBoundary
Acts like an infinitely large basin where the level does not change by flow. This can be connected to a basin via a LinearResistance
. This boundary node will then exchange water with the basin based on the difference in water level between the two.
12.1 LevelBoundary / time
+13.1 LevelBoundary / time
This table is the transient form of the LevelBoundary
table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id
. With this the levels can be updated over time. In between the given times the level is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id
can be either in this table or in the static one, but not both.
13.1 FlowBoundary / time
+14.1 FlowBoundary / time
This table is the transient form of the FlowBoundary
table. The only differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id
. With this the flow rates can be updated over time. In between the given times the flow rate is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id
can be either in this table or in the static one, but not both.
15 ManningResistance
+16 ManningResistance
Flow through this connection is estimated by conservation of energy and the Manning-Gauckler formula to estimate friction losses.
16 Terminal
+17 Terminal
A terminal is a water sink without state or properties. Any water that flows into a terminal node is removed from the model. No water can come into the model from a terminal node. For example, terminal nodes can be used as a downstream boundary.
17 DisceteControl
+18 DisceteControl
DiscreteControl is implemented based on VectorContinuousCallback.
-17.1 DiscreteControl / condition
+18.1 DiscreteControl / condition
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.
18 PidControl
+19 PidControl
The PidControl node controls the level in a basin by continuously controlling the flow rate of a connected pump or outlet. See also PID controller. When A PidControl node is made inactive, the node under its control retains the last flow rate value, and the error integral is reset to 0.
In the future controlling the flow on a particular edge could be supported.
18.1 PidControl / time
+19.1 PidControl / time
This table is the transient form of the PidControl
table. The differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id
. With this the target level and PID coefficients can be updated over time. In between the given times the these values interpolated linearly, and outside these values area constant given by the nearest time value. Note that a node_id
can be either in this table or in the static one, but not both.
x | x | -x | +✓ | x | x | x | @@ -546,7 +546,7 @@+ |
nodes.flow_demand | ++ |
nodes.level_demand | ++ |
Test models
Ribasim developers use the following models in their testbench and in order to test new features.
-Code
import ribasim_testmodels
@@ -319,154 +319,168 @@ Test models
+
+
+
+
+
+
+
+
+
+
diff --git a/python/test-models_files/figure-html/cell-2-output-11.png b/python/test-models_files/figure-html/cell-2-output-11.png
index 4fc0862b5..e1b284d9d 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-11.png and b/python/test-models_files/figure-html/cell-2-output-11.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-12.png b/python/test-models_files/figure-html/cell-2-output-12.png
index 41d5ed5aa..4fc0862b5 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-12.png and b/python/test-models_files/figure-html/cell-2-output-12.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-13.png b/python/test-models_files/figure-html/cell-2-output-13.png
index 057ce9a37..41d5ed5aa 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-13.png and b/python/test-models_files/figure-html/cell-2-output-13.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-14.png b/python/test-models_files/figure-html/cell-2-output-14.png
index 3700441cd..057ce9a37 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-14.png and b/python/test-models_files/figure-html/cell-2-output-14.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-15.png b/python/test-models_files/figure-html/cell-2-output-15.png
index 3ac7ed987..5ccd30a47 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-15.png and b/python/test-models_files/figure-html/cell-2-output-15.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-16.png b/python/test-models_files/figure-html/cell-2-output-16.png
index 51472f2e6..3ac7ed987 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-16.png and b/python/test-models_files/figure-html/cell-2-output-16.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-17.png b/python/test-models_files/figure-html/cell-2-output-17.png
index 28f13a6b3..4b9387c61 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-17.png and b/python/test-models_files/figure-html/cell-2-output-17.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-18.png b/python/test-models_files/figure-html/cell-2-output-18.png
index b7e5989cb..51472f2e6 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-18.png and b/python/test-models_files/figure-html/cell-2-output-18.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-19.png b/python/test-models_files/figure-html/cell-2-output-19.png
index 6feed0dcf..28f13a6b3 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-19.png and b/python/test-models_files/figure-html/cell-2-output-19.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-20.png b/python/test-models_files/figure-html/cell-2-output-20.png
index 48143149e..b7e5989cb 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-20.png and b/python/test-models_files/figure-html/cell-2-output-20.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-21.png b/python/test-models_files/figure-html/cell-2-output-21.png
index e23644dbf..6feed0dcf 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-21.png and b/python/test-models_files/figure-html/cell-2-output-21.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-22.png b/python/test-models_files/figure-html/cell-2-output-22.png
index 385f70f3c..48143149e 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-22.png and b/python/test-models_files/figure-html/cell-2-output-22.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-23.png b/python/test-models_files/figure-html/cell-2-output-23.png
index 30bfdf250..e23644dbf 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-23.png and b/python/test-models_files/figure-html/cell-2-output-23.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-24.png b/python/test-models_files/figure-html/cell-2-output-24.png
index c6cd3c340..385f70f3c 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-24.png and b/python/test-models_files/figure-html/cell-2-output-24.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-25.png b/python/test-models_files/figure-html/cell-2-output-25.png
index aec5c7b0c..30bfdf250 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-25.png and b/python/test-models_files/figure-html/cell-2-output-25.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-26.png b/python/test-models_files/figure-html/cell-2-output-26.png
index 59848dc9c..c6cd3c340 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-26.png and b/python/test-models_files/figure-html/cell-2-output-26.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-27.png b/python/test-models_files/figure-html/cell-2-output-27.png
index ca63191bd..aec5c7b0c 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-27.png and b/python/test-models_files/figure-html/cell-2-output-27.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-28.png b/python/test-models_files/figure-html/cell-2-output-28.png
index 2a311ae92..59848dc9c 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-28.png and b/python/test-models_files/figure-html/cell-2-output-28.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-29.png b/python/test-models_files/figure-html/cell-2-output-29.png
index 6cd33e1c7..ca63191bd 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-29.png and b/python/test-models_files/figure-html/cell-2-output-29.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-30.png b/python/test-models_files/figure-html/cell-2-output-30.png
index 8414c43e1..2a311ae92 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-30.png and b/python/test-models_files/figure-html/cell-2-output-30.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-31.png b/python/test-models_files/figure-html/cell-2-output-31.png
index 59aa41129..6cd33e1c7 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-31.png and b/python/test-models_files/figure-html/cell-2-output-31.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-32.png b/python/test-models_files/figure-html/cell-2-output-32.png
index bd21c153c..8414c43e1 100644
Binary files a/python/test-models_files/figure-html/cell-2-output-32.png and b/python/test-models_files/figure-html/cell-2-output-32.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-33.png b/python/test-models_files/figure-html/cell-2-output-33.png
new file mode 100644
index 000000000..59aa41129
Binary files /dev/null and b/python/test-models_files/figure-html/cell-2-output-33.png differ
diff --git a/python/test-models_files/figure-html/cell-2-output-34.png b/python/test-models_files/figure-html/cell-2-output-34.png
new file mode 100644
index 000000000..bd21c153c
Binary files /dev/null and b/python/test-models_files/figure-html/cell-2-output-34.png differ
diff --git a/search.json b/search.json
index 3972ac4d9..80e7a708d 100644
--- a/search.json
+++ b/search.json
@@ -43,7 +43,7 @@
"href": "contribute/addnode.html#parameters",
"title": "Adding node types",
"section": "1.1 Parameters",
- "text": "1.1 Parameters\nThe parameters object (defined in solve.jl) passed to the ODE solver must be made aware of the new node type. Therefore define a struct in solve.jl which holds the data for each node of the new node type:\nstruct NewNodeType\n node_id::Vector{NodeID}\n # Other fields\nend\nThese fields do not have to correspond 1:1 with the input tables (see below). The vector with all node IDs that are of the new type in a given model is a mandatory field. Now you can:\n\nAdd new_node_type::NewNodeType to the Parameters object;\nAdd new_node_type = NewNodeType(db,config) to the function Parameters in create.jl and add new_node_type at the proper location in the Parameters constructor call.",
+ "text": "1.1 Parameters\nThe parameters object (defined in parameter.jl) passed to the ODE solver must be made aware of the new node type. Therefore define a struct in parameter.jl which holds the data for each node of the new node type:\nstruct NewNodeType\n node_id::Vector{NodeID}\n # Other fields\nend\nThese fields do not have to correspond 1:1 with the input tables (see below). The vector with all node IDs that are of the new type in a given model is a mandatory field. Now you can:\n\nAdd new_node_type::NewNodeType to the Parameters object;\nAdd new_node_type = NewNodeType(db,config) to the function Parameters in read.jl and add new_node_type at the proper location in the Parameters constructor call.",
"crumbs": [
"Contributing",
"Adding node types"
@@ -54,7 +54,7 @@
"href": "contribute/addnode.html#reading-from-configuration",
"title": "Adding node types",
"section": "1.2 Reading from configuration",
- "text": "1.2 Reading from configuration\nThere can be several schemas associated with a single node type. To define a schema for the new node type, add the following to validation.jl:\n@schema \"ribasim.newnodetype.static\" NewNodeTypeStatic\n\n\"\"\"\nnode_id: node ID of the NewNodeType node\n\"\"\"\n@version NewNodeTypeStaticV1 begin\n node_id::Int32\n # Other fields\nend\nHere Static refers to data that does not change over time. For naming conventions of these schemas see Node usage.\nvalidation.jl also deals with checking and applying a specific sorting order for the tabular data (default is sorting by node ID only), see sort_by_function and sorted_table!.\nNow we define the function that is called in the second bullet above, in create.jl:\nfunction NewNodeType(db::DB, config::Config)::NewNodeType\n static = load_structvector(db, config, NewNodeTypeStaticV1)\n defaults = (; foo = 1, bar = false)\n # Process potential control states in the static data\n parsed_parameters, valid = parse_static_and_time(db, config, \"Outlet\"; static, defaults)\n\n if !valid\n error(\"Errors occurred when parsing NewNodeType data.\")\n end\n\n # Unpack the fields of static as inputs for the NewNodeType constructor\n return NewNodeType(\n NodeID.(NodeType.NewNodeType, parsed_parameters.node_id),\n parsed_parameters.some_property,\n parsed_parameters.control_mapping)\nend",
+ "text": "1.2 Reading from configuration\nThere can be several schemas associated with a single node type. To define a schema for the new node type, add the following to schema.jl:\n@schema \"ribasim.newnodetype.static\" NewNodeTypeStatic\n\n\"\"\"\nnode_id: node ID of the NewNodeType node\n\"\"\"\n@version NewNodeTypeStaticV1 begin\n node_id::Int32\n # Other fields\nend\nHere static refers to data that does not change over time. For naming conventions of these schemas see Node usage. If a new schema contains a priority column for allocation, it must also be added to the list of all such schemas in the function get_all_priorities in util.jl.\nvalidation.jl deals with checking and applying a specific sorting order for the tabular data (default is sorting by node ID only), see sort_by_function and sorted_table!.\nNow we define the function that is called in the second bullet above, in read.jl:\nfunction NewNodeType(db::DB, config::Config)::NewNodeType\n static = load_structvector(db, config, NewNodeTypeStaticV1)\n defaults = (; foo = 1, bar = false)\n # Process potential control states in the static data\n parsed_parameters, valid = parse_static_and_time(db, config, \"NewNodeType\"; static, defaults)\n\n if !valid\n error(\"Errors occurred when parsing NewNodeType data.\")\n end\n\n # Unpack the fields of static as inputs for the NewNodeType constructor\n return NewNodeType(\n NodeID.(NodeType.NewNodeType, parsed_parameters.node_id),\n parsed_parameters.some_property,\n parsed_parameters.control_mapping)\nend",
"crumbs": [
"Contributing",
"Adding node types"
@@ -76,7 +76,7 @@
"href": "contribute/addnode.html#the-jacobian",
"title": "Adding node types",
"section": "1.4 The Jacobian",
- "text": "1.4 The Jacobian\nSee Equations for a mathematical description of the Jacobian.\nBefore the Julia core runs its simulation, the sparsity structure jac_prototype of \\(J\\) is determined with get_jac_prototype in utils.jl. This function runs trough all node types and looks for nodes that create dependencies between states. It creates a sparse matrix of zeros and ones, where the ones denote locations of possible non-zeros in \\(J\\).\nWe divide the various node types in groups based on what type of state dependencies they yield, and these groups are discussed below. Each group has its own method update_jac_prototype! in utils.jl for the sparsity structure induced by nodes of that group. NewNodeType should be added to the signature of one these methods, or to the list of node types that do not contribute to the Jacobian in the method of update_jac_prototype! whose signature contains node::AbstractParameterNode. Of course it is also possible that a new method of update_jac_prototype! has to be introduced.\nThe current dependency groups are:\n\nOut-neighbor dependencies: examples are TabulatedRatingCurve, Pump (the latter only in the reduction factor regime and not PID controlled). If the in-neighbor of a node of this group is a basin, then the storage of this basin affects itself and the storage of the outneighbor (or the basin one node further if it is connected with a FractionalFlow in between) if that is also a basin;\nEither-neighbor dependencies: examples are LinearResistance, ManningResistance. If either the in-neighbor or out-neighbor of a node of this group is a basin, the storage of this basin depends on itself. If both the in-neighbor and the out-neighbor are basins, their storages also depend on eachother.\nThe PidControl node is a special case which is discussed in equations.\n\nUsing jac_prototype the Jacobian of water_balance! is computed automatically using ForwardDiff.jl with memory management provided by PreallocationTools.jl. These computations make use of DiffCache and dual numbers.",
+ "text": "1.4 The Jacobian\nSee Equations for a mathematical description of the Jacobian.\nBefore the Julia core runs its simulation, the sparsity structure jac_prototype of \\(J\\) is determined with get_jac_prototype in sparsity.jl. This function runs trough all node types and looks for nodes that create dependencies between states. It creates a sparse matrix of zeros and ones, where the ones denote locations of possible non-zeros in \\(J\\). Note that only nodes that set flows in the physical layer (or have their own state like PidControl) affect the sparsity structure.\nWe divide the various node types in groups based on what type of state dependencies they yield, and these groups are discussed below. Each group has its own method update_jac_prototype! in utils.jl for the sparsity structure induced by nodes of that group. NewNodeType should be added to the signature of one these methods, or to the list of node types that do not contribute to the Jacobian in the method of update_jac_prototype! whose signature contains node::AbstractParameterNode. Of course it is also possible that a new method of update_jac_prototype! has to be introduced.\nThe current dependency groups are:\n\nOut-neighbor dependencies: examples are TabulatedRatingCurve, Pump (the latter only in the reduction factor regime and not PID controlled). If the in-neighbor of a node of this group is a basin, then the storage of this basin affects itself and the storage of the outneighbor (or the basin one node further if it is connected with a FractionalFlow in between) if that is also a basin;\nEither-neighbor dependencies: examples are LinearResistance, ManningResistance. If either the in-neighbor or out-neighbor of a node of this group is a basin, the storage of this basin depends on itself. If both the in-neighbor and the out-neighbor are basins, their storages also depend on eachother.\nThe PidControl node is a special case which is discussed in equations.\n\nUsing jac_prototype the Jacobian of water_balance! is computed automatically using ForwardDiff.jl with memory management provided by PreallocationTools.jl. These computations make use of DiffCache and dual numbers.",
"crumbs": [
"Contributing",
"Adding node types"
@@ -87,7 +87,7 @@
"href": "contribute/addnode.html#python-class",
"title": "Adding node types",
"section": "2.1 Python class",
- "text": "2.1 Python class\nCreate a new file python/ribasim/ribasim/node_types/new_node_type.py which is structured as follows:\nfrom typing import Optional\n\nimport pandera as pa\nfrom pandera.engines.pandas_engine import PydanticModel\nfrom pandera.typing import DataFrame\nfrom pydantic import ConfigDict\n\nfrom ribasim import models\nfrom ribasim.input_base import TableModel\n\n__all__ = (\"NewNodeType\",)\n\nclass StaticSchema(pa.SchemaModel):\n class Config:\n \"\"\"Config with dataframe-level data type.\"\"\"\n\n dtype = PydanticModel(models.NewNodeTypeStatic)\n\n# Possible other schemas\n\n\nclass NewNodeType(TableModel):\n \"\"\"\n Description of this node type.\n\n Parameters\n ----------\n static: pandas.DataFrame\n table with data for this node type.\n\n possible other schemas\n \"\"\"\n\n static: DataFrame[StaticSchema] | None\n # possible other schemas\n\n model_config = ConfigDict(validate_assignment=True)\n\n def sort(self):\n self.static.sort_values(\"node_id\", ignore_index=True, inplace=True)\nThe sort method should implement the same sorting as in validation.jl.\nNow in both python/ribasim/ribasim/__init__.py and python/ribasim/ribasim/node_types/__init__.py add\n\nfrom ribasim.node_types.new_node_type import NewNodeType;\n\"NewNodeType\" to __all__.\n\nIn python/ribasim/ribasim/model.py, add\n\nfrom ribasim.new_node_type import NewNodeType;\nnew_node_type as a parameter and in the docstring of the Model class.\n\nIn python/ribasim/ribasim/geometry/node.py add a color and shape description in the MARKERS and COLORS dictionaries.",
+ "text": "2.1 Python class\nIn python/ribasim/ribasim/config.py add\n\nthe above defined schemas to the imports from ribasim.schemas. This requires code generation to work, see Finishing up;\na class of the following form with all schemas associated with the node type:\n\nclass NewNodeType(NodeModel):\n static: TableModel[NewNodeTypeStaticSchema] = Field(\n default_factory=TableModel[NewNodeTypeStaticSchema],\n json_schema_extra={\"sort_keys\": [\"node_id\"]},\n )\nIn python/ribasim/ribasim/__init__.py add\n\nNewNodeType to the imports from ribasim.config;\n\"NewNodeType\" to __all__.\n\nIn python/ribasim/ribasim/model.py, add\n\nNewNodeType to the imports from ribasim.config;\nnew_node_type as a parameter and in the docstring of the Model class.\n\nIn python/ribasim/ribasim/geometry/node.py add a color and shape description in the MARKERS and COLORS dictionaries.",
"crumbs": [
"Contributing",
"Adding node types"
@@ -241,7 +241,7 @@
"href": "python/reference/index.html",
"title": "1 API Reference",
"section": "",
- "text": "The Model class represents an entire Ribasim model.\n\n\n\nModel\n\n\n\n\n\n\n\nThe Edge database layer.\n\n\n\nEdgeTable\nDefines the connections between nodes.\n\n\n\n\n\n\nAvailable node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control",
+ "text": "The Model class represents an entire Ribasim model.\n\n\n\nModel\n\n\n\n\n\n\n\nThe Edge database layer.\n\n\n\nEdgeTable\nDefines the connections between nodes.\n\n\n\n\n\n\nAvailable node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control\n\n\n\nnodes.flow_demand\n\n\n\nnodes.level_demand",
"crumbs": [
"Python tooling",
"API Reference"
@@ -274,7 +274,7 @@
"href": "python/reference/index.html#node-types",
"title": "1 API Reference",
"section": "",
- "text": "Available node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control",
+ "text": "Available node types to model different situations.\n\n\n\nnodes.basin\n\n\n\nnodes.fractional_flow\n\n\n\nnodes.tabulated_rating_curve\n\n\n\nnodes.pump\n\n\n\nnodes.outlet\n\n\n\nnodes.user_demand\n\n\n\nnodes.level_boundary\n\n\n\nnodes.flow_boundary\n\n\n\nnodes.linear_resistance\n\n\n\nnodes.manning_resistance\n\n\n\nnodes.terminal\n\n\n\nnodes.discrete_control\n\n\n\nnodes.pid_control\n\n\n\nnodes.flow_demand\n\n\n\nnodes.level_demand",
"crumbs": [
"Python tooling",
"API Reference"
@@ -288,11 +288,18 @@
"text": "1 nodes.user_demand\nnodes.user_demand"
},
{
- "objectID": "python/reference/nodes.level_boundary.html",
- "href": "python/reference/nodes.level_boundary.html",
- "title": "1 nodes.level_boundary",
+ "objectID": "python/reference/nodes.terminal.html",
+ "href": "python/reference/nodes.terminal.html",
+ "title": "1 nodes.terminal",
"section": "",
- "text": "1 nodes.level_boundary\nnodes.level_boundary"
+ "text": "1 nodes.terminal\nnodes.terminal"
+ },
+ {
+ "objectID": "python/reference/nodes.fractional_flow.html",
+ "href": "python/reference/nodes.fractional_flow.html",
+ "title": "1 nodes.fractional_flow",
+ "section": "",
+ "text": "1 nodes.fractional_flow\nnodes.fractional_flow"
},
{
"objectID": "python/reference/nodes.tabulated_rating_curve.html",
@@ -398,7 +405,7 @@
"href": "build/index.html#types",
"title": "1 API Reference",
"section": "1.2 Types",
- "text": "1.2 Types\n# Ribasim.Allocation — Type.\nObject for all information about allocation allocationnetworkids: The unique sorted allocation network IDs allocation models: The allocation models for the main network and subnetworks corresponding to allocationnetworkids mainnetworkconnections: (fromid, toid) from the main network to the subnetwork per subnetwork priorities: All used priority values. subnetworkdemands: The demand of an edge from the main network to a subnetwork recorddemand: A record of demands and allocated flows for nodes that have these. record_flow: A record of all flows computed by allocation optimization, eventually saved to output file\nsource\n# Ribasim.AllocationModel — Type.\nStore information for a subnetwork used for allocation.\nallocationnetworkid: The ID of this allocation network capacity: The capacity per edge of the allocation network, as constrained by nodes that have a maxflowrate problem: The JuMP.jl model for solving the allocation problem Δt_allocation: The time interval between consecutive allocation solves\nsource\n# Ribasim.AllocationModel — Method.\nConstruct the JuMP.jl problem for allocation.\nInputs\np: Ribasim problem parameters Δt_allocation: The timestep between successive allocation solves\nOutputs\nAn AllocationModel object.\nsource\n# Ribasim.Basin — Type.\nRequirements:\n\nMust be positive: precipitation, evaporation, infiltration, drainage\nIndex points to a Basin\nvolume, area, level must all be positive and monotonic increasing.\n\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of vectors or Arrow Tables, and is added to avoid type instabilities. The nodeid are Indices to support fast lookup of e.g. currentlevel using ID.\nif autodiff T = DiffCache{Vector{Float64}} else T = Vector{Float64} end\nsource\n# Ribasim.DiscreteControl — Type.\nnodeid: node ID of the DiscreteControl node; these are not unique but repeated by the amount of conditions of this DiscreteControl node listennodeid: the ID of the node being condition on variable: the name of the variable in the condition greaterthan: The threshold value in the condition conditionvalue: The current value of each condition controlstate: Dictionary: node ID => (control state, control state start) logic_mapping: Dictionary: (control node ID, truth state) => control state record: Namedtuple with discrete control information for results\nsource\n# Ribasim.EdgeMetadata — Type.\nType for storing metadata of edges in the graph: id: ID of the edge (only used for labeling flow output) type: type of the edge allocationnetworkidsource: ID of allocation network where this edge is a source (0 if not a source) fromid: the node ID of the source node toid: the node ID of the destination node allocationflow: whether this edge has a flow in an allocation network node_ids: if this edge has allocation flow, these are all the nodes from the physical layer this edge consists of\nsource\n# Ribasim.FlatVector — Type.\nstruct FlatVector{T} <: AbstractVector{T}\nA FlatVector is an AbstractVector that iterates the T of a Vector{Vector{T}}.\nEach inner vector is assumed to be of equal length.\nIt is similar to Iterators.flatten, though that doesn’t work with the Tables.Column interface, which needs length and getindex support.\nsource\n# Ribasim.FlowBoundary — Type.\nnodeid: node ID of the FlowBoundary node active: whether this node is active and thus contributes flow flowrate: target flow rate\nsource\n# Ribasim.FractionalFlow — Type.\nRequirements:\n\nfrom: must be (TabulatedRatingCurve,) node\nto: must be (Basin,) node\nfraction must be positive.\n\nnodeid: node ID of the TabulatedRatingCurve node fraction: The fraction in [0,1] of flow the node lets through controlmapping: dictionary from (nodeid, controlstate) to fraction\nsource\n# Ribasim.InNeighbors — Type.\nIterate over incoming neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.LevelBoundary — Type.\nnode_id: node ID of the LevelBoundary node active: whether this node is active level: the fixed level of this ‘infinitely big basin’\nsource\n# Ribasim.LevelDemand — Type.\nnodeid: node ID of the LevelDemand node minlevel: The minimum target level of the connected basin(s) max_level: The maximum target level of the connected basin(s) priority: If in a shortage state, the priority of the demand of the connected basin(s)\nsource\n# Ribasim.LinearResistance — Type.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\n\nnodeid: node ID of the LinearResistance node active: whether this node is active and thus contributes flows resistance: the resistance to flow; Q*unlimited = Δh/resistancemax_flow_rate: the maximum flow rate allowed through the node;Q = clamp(Q*unlimited, -max*flow*rate, max*flow*rate) controlmapping: dictionary from (nodeid, controlstate) to resistance and/or active state\nsource\n# Ribasim.ManningResistance — Type.\nThis is a simple Manning-Gauckler reach connection.\n\nLength describes the reach length.\nroughness describes Manning’s n in (SI units).\n\nThe profile is described by a trapezoid:\n \\ / ^\n \\ / |\n \\ / | dz\nbottom \\______/ |\n^ <--->\n| dy\n| <------>\n| width\n|\n|\n+ datum (e.g. MSL)\nWith profile_slope = dy / dz. A rectangular profile requires a slope of 0.0.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\nlength > 0\nroughess > 0\nprofile_width >= 0\nprofile_slope >= 0\n(profilewidth == 0) xor (profileslope == 0)\n\nsource\n# Ribasim.Model — Type.\nModel(config_path::AbstractString)\nModel(config::Config)\nInitialize a Model.\nThe Model struct is an initialized model, combined with the Config used to create it and saved results. The Basic Model Interface (BMI) is implemented on the Model. A Model can be created from the path to a TOML configuration file, or a Config object.\nsource\n# Ribasim.NodeMetadata — Type.\nType for storing metadata of nodes in the graph type: type of the node allocationnetworkid: Allocation network ID (0 if not in subnetwork)\nsource\n# Ribasim.OutNeighbors — Type.\nIterate over outgoing neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.Outlet — Type.\nnodeid: node ID of the Outlet node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the outlet maxflowrate: The maximum flow rate of the outlet controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this outlet is governed by PID control\nsource\n# Ribasim.PidControl — Type.\nPID control currently only supports regulating basin levels.\nnodeid: node ID of the PidControl node active: whether this node is active and thus sets flow rates listennodeid: the id of the basin being controlled pidparams: a vector interpolation for parameters changing over time. The parameters are respectively target, proportional, integral, derivative, where the last three are the coefficients for the PID equation. error: the current error; basintarget - currentlevel\nsource\n# Ribasim.Pump — Type.\nnodeid: node ID of the Pump node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the pump maxflowrate: The maximum flow rate of the pump controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this pump is governed by PID control\nsource\n# Ribasim.Subgrid — Type.\nSubgrid linearly interpolates basin levels.\nsource\n# Ribasim.TabulatedRatingCurve — Type.\nstruct TabulatedRatingCurve{C}\nRating curve from level to flow rate. The rating curve is a lookup table with linear interpolation in between. Relation can be updated in time, which is done by moving data from the time field into the tables, which is done in the update_tabulated_rating_curve callback.\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of Vectors or Arrow Primitives, and is added to avoid type instabilities.\nnodeid: node ID of the TabulatedRatingCurve node active: whether this node is active and thus contributes flows tables: The current Q(h) relationships time: The time table used for updating the tables controlmapping: dictionary from (nodeid, controlstate) to Q(h) and/or active state\nsource\n# Ribasim.Terminal — Type.\nnode_id: node ID of the Terminal node\nsource\n# Ribasim.UserDemand — Type.\ndemand: water flux demand of UserDemand per priority over time. Each UserDemand has a demand for all priorities, which is 0.0 if it is not provided explicitly. realizedbmi: Cumulative inflow volume, for read or reset by BMI only. active: whether this node is active and thus demands water allocated: water flux currently allocated to UserDemand per priority returnfactor: the factor in [0,1] of how much of the abstracted water is given back to the system min_level: The level of the source basin below which the UserDemand does not abstract\nsource\n# Ribasim.config.Config — Method.\nConfig(config_path::AbstractString; kwargs...)\nParse a TOML file to a Config. Keys can be overruled using keyword arguments. To overrule keys from a subsection, e.g. dt from the solver section, use underscores: solver_dt.\nsource",
+ "text": "1.2 Types\n# Ribasim.Allocation — Type.\nObject for all information about allocation allocationnetworkids: The unique sorted allocation network IDs allocation models: The allocation models for the main network and subnetworks corresponding to allocationnetworkids mainnetworkconnections: (fromid, toid) from the main network to the subnetwork per subnetwork priorities: All used priority values. subnetworkdemands: The demand of an edge from the main network to a subnetwork recorddemand: A record of demands and allocated flows for nodes that have these. record_flow: A record of all flows computed by allocation optimization, eventually saved to output file\nsource\n# Ribasim.AllocationModel — Type.\nStore information for a subnetwork used for allocation.\nallocationnetworkid: The ID of this allocation network capacity: The capacity per edge of the allocation network, as constrained by nodes that have a maxflowrate problem: The JuMP.jl model for solving the allocation problem Δt_allocation: The time interval between consecutive allocation solves\nsource\n# Ribasim.AllocationModel — Method.\nConstruct the JuMP.jl problem for allocation.\nInputs\nallocationnetworkid: the ID of this allocation network p: Ribasim problem parameters Δt_allocation: The timestep between successive allocation solves\nOutputs\nAn AllocationModel object.\nsource\n# Ribasim.Basin — Type.\nRequirements:\n\nMust be positive: precipitation, evaporation, infiltration, drainage\nIndex points to a Basin\nvolume, area, level must all be positive and monotonic increasing.\n\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of vectors or Arrow Tables, and is added to avoid type instabilities. The nodeid are Indices to support fast lookup of e.g. currentlevel using ID.\nif autodiff T = DiffCache{Vector{Float64}} else T = Vector{Float64} end\nsource\n# Ribasim.DiscreteControl — Type.\nnodeid: node ID of the DiscreteControl node; these are not unique but repeated by the amount of conditions of this DiscreteControl node listennodeid: the ID of the node being condition on variable: the name of the variable in the condition greaterthan: The threshold value in the condition conditionvalue: The current value of each condition controlstate: Dictionary: node ID => (control state, control state start) logic_mapping: Dictionary: (control node ID, truth state) => control state record: Namedtuple with discrete control information for results\nsource\n# Ribasim.EdgeMetadata — Type.\nType for storing metadata of edges in the graph: id: ID of the edge (only used for labeling flow output) type: type of the edge allocationnetworkidsource: ID of allocation network where this edge is a source (0 if not a source) fromid: the node ID of the source node toid: the node ID of the destination node allocationflow: whether this edge has a flow in an allocation network node_ids: if this edge has allocation flow, these are all the nodes from the physical layer this edge consists of\nsource\n# Ribasim.FlatVector — Type.\nstruct FlatVector{T} <: AbstractVector{T}\nA FlatVector is an AbstractVector that iterates the T of a Vector{Vector{T}}.\nEach inner vector is assumed to be of equal length.\nIt is similar to Iterators.flatten, though that doesn’t work with the Tables.Column interface, which needs length and getindex support.\nsource\n# Ribasim.FlowBoundary — Type.\nnodeid: node ID of the FlowBoundary node active: whether this node is active and thus contributes flow flowrate: target flow rate\nsource\n# Ribasim.FractionalFlow — Type.\nRequirements:\n\nfrom: must be (TabulatedRatingCurve,) node\nto: must be (Basin,) node\nfraction must be positive.\n\nnodeid: node ID of the TabulatedRatingCurve node fraction: The fraction in [0,1] of flow the node lets through controlmapping: dictionary from (nodeid, controlstate) to fraction\nsource\n# Ribasim.InNeighbors — Type.\nIterate over incoming neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.LevelBoundary — Type.\nnode_id: node ID of the LevelBoundary node active: whether this node is active level: the fixed level of this ‘infinitely big basin’\nsource\n# Ribasim.LevelDemand — Type.\nnodeid: node ID of the LevelDemand node minlevel: The minimum target level of the connected basin(s) max_level: The maximum target level of the connected basin(s) priority: If in a shortage state, the priority of the demand of the connected basin(s)\nsource\n# Ribasim.LinearResistance — Type.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\n\nnodeid: node ID of the LinearResistance node active: whether this node is active and thus contributes flows resistance: the resistance to flow; Q*unlimited = Δh/resistancemax_flow_rate: the maximum flow rate allowed through the node;Q = clamp(Q*unlimited, -max*flow*rate, max*flow*rate) controlmapping: dictionary from (nodeid, controlstate) to resistance and/or active state\nsource\n# Ribasim.ManningResistance — Type.\nThis is a simple Manning-Gauckler reach connection.\n\nLength describes the reach length.\nroughness describes Manning’s n in (SI units).\n\nThe profile is described by a trapezoid:\n \\ / ^\n \\ / |\n \\ / | dz\nbottom \\______/ |\n^ <--->\n| dy\n| <------>\n| width\n|\n|\n+ datum (e.g. MSL)\nWith profile_slope = dy / dz. A rectangular profile requires a slope of 0.0.\nRequirements:\n\nfrom: must be (Basin,) node\nto: must be (Basin,) node\nlength > 0\nroughess > 0\nprofile_width >= 0\nprofile_slope >= 0\n(profilewidth == 0) xor (profileslope == 0)\n\nsource\n# Ribasim.Model — Type.\nModel(config_path::AbstractString)\nModel(config::Config)\nInitialize a Model.\nThe Model struct is an initialized model, combined with the Config used to create it and saved results. The Basic Model Interface (BMI) is implemented on the Model. A Model can be created from the path to a TOML configuration file, or a Config object.\nsource\n# Ribasim.NodeMetadata — Type.\nType for storing metadata of nodes in the graph type: type of the node allocationnetworkid: Allocation network ID (0 if not in subnetwork)\nsource\n# Ribasim.OutNeighbors — Type.\nIterate over outgoing neighbors of a given label in a MetaGraph, only for edges of edge_type\nsource\n# Ribasim.Outlet — Type.\nnodeid: node ID of the Outlet node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the outlet maxflowrate: The maximum flow rate of the outlet controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this outlet is governed by PID control\nsource\n# Ribasim.PidControl — Type.\nPID control currently only supports regulating basin levels.\nnodeid: node ID of the PidControl node active: whether this node is active and thus sets flow rates listennodeid: the id of the basin being controlled pidparams: a vector interpolation for parameters changing over time. The parameters are respectively target, proportional, integral, derivative, where the last three are the coefficients for the PID equation. error: the current error; basintarget - currentlevel\nsource\n# Ribasim.Pump — Type.\nnodeid: node ID of the Pump node active: whether this node is active and thus contributes flow flowrate: target flow rate minflowrate: The minimal flow rate of the pump maxflowrate: The maximum flow rate of the pump controlmapping: dictionary from (nodeid, controlstate) to target flow rate ispid_controlled: whether the flow rate of this pump is governed by PID control\nsource\n# Ribasim.Subgrid — Type.\nSubgrid linearly interpolates basin levels.\nsource\n# Ribasim.TabulatedRatingCurve — Type.\nstruct TabulatedRatingCurve{C}\nRating curve from level to flow rate. The rating curve is a lookup table with linear interpolation in between. Relation can be updated in time, which is done by moving data from the time field into the tables, which is done in the update_tabulated_rating_curve callback.\nType parameter C indicates the content backing the StructVector, which can be a NamedTuple of Vectors or Arrow Primitives, and is added to avoid type instabilities.\nnodeid: node ID of the TabulatedRatingCurve node active: whether this node is active and thus contributes flows tables: The current Q(h) relationships time: The time table used for updating the tables controlmapping: dictionary from (nodeid, controlstate) to Q(h) and/or active state\nsource\n# Ribasim.Terminal — Type.\nnode_id: node ID of the Terminal node\nsource\n# Ribasim.UserDemand — Type.\ndemand: water flux demand of UserDemand per priority over time. Each UserDemand has a demand for all priorities, which is 0.0 if it is not provided explicitly. realizedbmi: Cumulative inflow volume, for read or reset by BMI only. active: whether this node is active and thus demands water allocated: water flux currently allocated to UserDemand per priority returnfactor: the factor in [0,1] of how much of the abstracted water is given back to the system min_level: The level of the source basin below which the UserDemand does not abstract\nsource\n# Ribasim.config.Config — Method.\nConfig(config_path::AbstractString; kwargs...)\nParse a TOML file to a Config. Keys can be overruled using keyword arguments. To overrule keys from a subsection, e.g. dt from the solver section, use underscores: solver_dt.\nsource",
"crumbs": [
"Julia core",
"API Reference"
@@ -409,7 +416,7 @@
"href": "build/index.html#functions",
"title": "1 API Reference",
"section": "1.3 Functions",
- "text": "1.3 Functions\n# BasicModelInterface.finalize — Method.\nBMI.finalize(model::Model)::Model\nWrite all results to the configured files.\nsource\n# BasicModelInterface.initialize — Method.\nBMI.initialize(T::Type{Model}, config_path::AbstractString)::Model\nInitialize a Model from the path to the TOML configuration file.\nsource\n# CommonSolve.solve! — Method.\nsolve!(model::Model)::ODESolution\nSolve a Model until the configured endtime.\nsource\n# Ribasim.add_basin_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a basin.\nsource\n# Ribasim.add_constraints_absolute_value! — Method.\nMinimizing |expr| can be achieved by introducing a new variable exprabs and posing the following constraints: exprabs >= expr expr_abs >= -expr\nsource\n# Ribasim.add_constraints_absolute_value_basin! — Method.\nAdd constraints so that variables Fabsbasin act as the absolute value of the expression comparing flow to a basin to its demand.\nsource\n# Ribasim.add_constraints_absolute_value_user_demand! — Method.\nAdd constraints so that variables Fabsuser_demand act as the absolute value of the expression comparing flow to a UserDemand to its demand.\nsource\n# Ribasim.add_constraints_basin_flow! — Method.\nAdd the Basin flow constraints to the allocation problem. The constraint indices are the Basin node IDs.\nConstraint: flow out of basin <= basin capacity\nsource\n# Ribasim.add_constraints_capacity! — Method.\nAdd the flow capacity constraints to the allocation problem. Only finite capacities get a constraint. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over edge <= edge capacity\nsource\n# Ribasim.add_constraints_flow_conservation! — Method.\nAdd the flow conservation constraints to the allocation problem. The constraint indices are UserDemand node IDs.\nConstraint: sum(flows out of node node) == flows into node + flow from storage and vertical fluxes\nsource\n# Ribasim.add_constraints_fractional_flow! — Method.\nAdd the fractional flow constraints to the allocation problem. The constraint indices are allocation edges over a fractional flow node.\nConstraint: flow after fractional_flow node <= fraction * inflow\nsource\n# Ribasim.add_constraints_source! — Method.\nAdd the source constraints to the allocation problem. The actual threshold values will be set before each allocation solve. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over source edge <= source flow in subnetwork\nsource\n# Ribasim.add_constraints_user_demand_returnflow! — Method.\nAdd the UserDemand returnflow constraints to the allocation problem. The constraint indices are UserDemand node IDs.\nConstraint: outflow from userdemand <= return factor inflow to user*demand\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the flow over the edge on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the existing flow over the edge between the given nodes.\nsource\n# Ribasim.add_objective_term! — Function.\nAdd a term to the objective function given by the objective type, depending in the provided flow variable and the associated demand.\nsource\n# Ribasim.add_subnetwork_connections! — Method.\nAdd the edges connecting the main network work to a subnetwork to both the main network and subnetwork allocation network.\nsource\n# Ribasim.add_user_demand_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a UserDemand.\nsource\n# Ribasim.add_variables_absolute_value! — Method.\nCertain allocation distribution types use absolute values in the objective function. Since most optimization packages do not support the absolute value function directly, New variables are introduced that act as the absolute value of an expression by posing the appropriate constraints.\nsource\n# Ribasim.add_variables_basin! — Method.\nAdd the variables for supply/demand of a basin to the problem. The variable indices are the node_ids of the basins in the subnetwork.\nsource\n# Ribasim.add_variables_flow! — Method.\nAdd the flow variables F to the allocation problem. The variable indices are (edgesourceid, edgedstid). Non-negativivity constraints are also immediately added to the flow variables.\nsource\n# Ribasim.adjust_basin_capacities! — Method.\nSet the values of the basin outflows. 2 cases:\n\nBefore the first allocation solve, set the capacities to their full capacity if there is surplus storage;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the capacities.\n\nsource\n# Ribasim.adjust_edge_capacities! — Method.\nSet the values of the edge capacities. 2 cases:\n\nBefore the first allocation solve, set the edge capacities to their full capacity;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the edge capacities.\n\nsource\n# Ribasim.adjust_source_capacities! — Method.\nAdjust the source flows.\nsource\n# Ribasim.all_neighbor_labels_type — Method.\nGet the in- and outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.allocate! — Method.\nUpdate the allocation optimization problem for the given subnetwork with the problem state and flows, solve the allocation problem and assign the results to the UserDemand.\nsource\n# Ribasim.allocation_graph — Method.\nBuild the graph used for the allocation problem.\nsource\n# Ribasim.allocation_graph_used_nodes! — Method.\nFind all nodes in the subnetwork which will be used in the allocation network. Some nodes are skipped to optimize allocation optimization.\nsource\n# Ribasim.allocation_path_exists_in_graph — Method.\nFind out whether a path exists between a start node and end node in the given allocation network.\nsource\n# Ribasim.allocation_problem — Method.\nConstruct the allocation problem for the current subnetwork as a JuMP.jl model.\nsource\n# Ribasim.allocation_table — Method.\nCreate an allocation result table for the saved data\nsource\n# Ribasim.assign_allocations! — Method.\nAssign the allocations to the UserDemand as determined by the solution of the allocation problem.\nsource\n# Ribasim.avoid_using_own_returnflow! — Method.\nRemove allocation UserDemand return flow edges that are upstream of the UserDemand itself.\nsource\n# Ribasim.basin_bottom — Method.\nReturn the bottom elevation of the basin with index i, or nothing if it doesn’t exist\nsource\n# Ribasim.basin_bottoms — Method.\nGet the bottom on both ends of a node. If only one has a bottom, use that for both.\nsource\n# Ribasim.basin_table — Method.\nCreate the basin result table from the saved data\nsource\n# Ribasim.create_callbacks — Method.\nCreate the different callbacks that are used to store results and feed the simulation with new data. The different callbacks are combined to a CallbackSet that goes to the integrator. Returns the CallbackSet and the SavedValues for flow.\nsource\n# Ribasim.create_graph — Method.\nReturn a directed metagraph with data of nodes (NodeMetadata): NodeMetadata\nand data of edges (EdgeMetadata): EdgeMetadata\nsource\n# Ribasim.create_storage_tables — Method.\nRead the Basin / profile table and return all area and level and computed storage values\nsource\n# Ribasim.datetime_since — Method.\ndatetime_since(t::Real, t0::DateTime)::DateTime\nConvert a Real that represents the seconds passed since the simulation start to the nearest DateTime. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.datetimes — Method.\nGet all saved times as a Vector{DateTime}\nsource\n# Ribasim.discrete_control_affect! — Method.\nChange parameters based on the control logic.\nsource\n# Ribasim.discrete_control_affect_downcrossing! — Method.\nAn downcrossing means that a condition (always greater than) becomes false.\nsource\n# Ribasim.discrete_control_affect_upcrossing! — Method.\nAn upcrossing means that a condition (always greater than) becomes true.\nsource\n# Ribasim.discrete_control_condition — Method.\nListens for changes in condition truths.\nsource\n# Ribasim.discrete_control_table — Method.\nCreate a discrete control result table from the saved data\nsource\n# Ribasim.expand_logic_mapping — Method.\nReplace the truth states in the logic mapping which contain wildcards with all possible explicit truth states.\nsource\n# Ribasim.find_allocation_graph_edges! — Method.\nThis loop finds allocation network edges in several ways:\n\nBetween allocation network nodes whose equivalent in the subnetwork are directly connected\nBetween allocation network nodes whose equivalent in the subnetwork are connected with one or more allocation network nodes in between\n\nsource\n# Ribasim.find_subnetwork_connections! — Method.\nFind the edges from the main network to a subnetwork.\nsource\n# Ribasim.findlastgroup — Method.\nFor an element id and a vector of elements ids, get the range of indices of the last consecutive block of id. Returns the empty range 1:0 if id is not in ids.\nsource\n# Ribasim.findsorted — Method.\nFind the index of element x in a sorted collection a. Returns the index of x if it exists, or nothing if it doesn’t. If x occurs more than once, throw an error.\nsource\n# Ribasim.flow_table — Method.\nCreate a flow result table from the saved data\nsource\n# Ribasim.formulate_basins! — Method.\nSmoothly let the evaporation flux go to 0 when at small water depths Currently at less than 0.1 m.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.formulate_flow! — Method.\nConservation of energy for two basins, a and b:\nh_a + v_a^2 / (2 * g) = h_b + v_b^2 / (2 * g) + S_f * L + C / 2 * g * (v_b^2 - v_a^2)\nWhere:\n\nha, hb are the heads at basin a and b.\nva, vb are the velocities at basin a and b.\ng is the gravitational constant.\nS_f is the friction slope.\nC is an expansion or extraction coefficient.\n\nWe assume velocity differences are negligible (va = vb):\nh_a = h_b + S_f * L\nThe friction losses are approximated by the Gauckler-Manning formula:\nQ = A * (1 / n) * R_h^(2/3) * S_f^(1/2)\nWhere:\n\nWhere A is the cross-sectional area.\nV is the cross-sectional average velocity.\nn is the Gauckler-Manning coefficient.\nR_h is the hydraulic radius.\nS_f is the friction slope.\n\nThe hydraulic radius is defined as:\nR_h = A / P\nWhere P is the wetted perimeter.\nThe average of the upstream and downstream water depth is used to compute cross-sectional area and hydraulic radius. This ensures that a basin can receive water after it has gone dry.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.get_area_and_level — Method.\nCompute the area and level of a basin given its storage. Also returns darea/dlevel as it is needed for the Jacobian.\nsource\n# Ribasim.get_basin_capacity — Method.\nGet the capacity of the basin, i.e. the maximum flow that can be abstracted from the basin if it is in a state of surplus storage (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_basin_data — Method.\nGet several variables associated with a basin:\n\nIts current storage\nThe allocation update interval\nThe influx (sum of instantaneous vertical fluxes of the basin)\nThe index of the connected level_demand node (0 if such a node does not exist)\nThe index of the basin\n\nsource\n# Ribasim.get_basin_demand — Method.\nGet the demand of the basin, i.e. how large a flow the basin needs to get to its minimum target level (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_chunk_sizes — Method.\nGet the chunk sizes for DiffCache; differentiation w.r.t. u and t (the latter only if a Rosenbrock algorithm is used).\nsource\n# Ribasim.get_compressor — Method.\nGet the compressor based on the Results section\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given horizontal (selfloop) edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_fractional_flow_connected_basins — Method.\nGet the node type specific indices of the fractional flows and basins, that are consecutively connected to a node of given id.\nsource\n# Ribasim.get_jac_prototype — Method.\nGet a sparse matrix whose sparsity matches the sparsity of the Jacobian of the ODE problem. All nodes are taken into consideration, also the ones that are inactive.\nIn Ribasim the Jacobian is typically sparse because each state only depends on a small number of other states.\nNote: the name ‘prototype’ does not mean this code is a prototype, it comes from the naming convention of this sparsity structure in the differentialequations.jl docs.\nsource\n# Ribasim.get_level — Method.\nGet the current water level of a node ID. The ID can belong to either a Basin or a LevelBoundary. storage: tells ForwardDiff whether this call is for differentiation or not\nsource\n# Ribasim.get_scalar_interpolation — Method.\nLinear interpolation of a scalar with constant extrapolation.\nsource\n# Ribasim.get_storage_from_level — Method.\nGet the storage of a basin from its level.\nsource\n# Ribasim.get_storages_and_levels — Method.\nGet the storage and level of all basins as matrices of nbasin × ntime\nsource\n# Ribasim.get_storages_from_levels — Method.\nCompute the storages of the basins based on the water level of the basins.\nsource\n# Ribasim.get_tstops — Method.\nFrom an iterable of DateTimes, find the times the solver needs to stop\nsource\n# Ribasim.get_value — Method.\nGet a value for a condition. Currently supports getting levels from basins and flows from flow boundaries.\nsource\n# Ribasim.id_index — Method.\nGet the index of an ID in a set of indices.\nsource\n# Ribasim.indicate_allocation_flow! — Method.\nAdd to the edge metadata that the given edge is used for allocation flow. If the edge does not exist, it is created.\nsource\n# Ribasim.inflow_id — Method.\nGet the unique inneighbor over a flow edge.\nsource\n# Ribasim.inflow_ids — Method.\nGet the inneighbors over flow edges.\nsource\n# Ribasim.inflow_ids_allocation — Method.\nGet the inneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.inneighbor_labels_type — Method.\nGet the inneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.inoutflow_ids — Method.\nGet the in- and outneighbors over flow edges.\nsource\n# Ribasim.integrate_flows! — Method.\nIntegrate flows over the last timestep\nsource\n# Ribasim.is_allocation_source — Method.\nFind out whether the given edge is a source for an allocation network.\nsource\n# Ribasim.is_current_module — Method.\nis_current_module(log::LogMessageType)::Bool\nReturns true if the log message is from the current module or a submodule.\n\nSee https://github.com/JuliaLogging/LoggingExtras.jl/blob/d35e7c8cfc197853ee336ace17182e6ed36dca24/src/CompositionalLoggers/earlyfiltered.jl#L39\nfor the information available in log.\nsource\n# Ribasim.is_flow_constraining — Method.\nWhether the given node node is flow constraining by having a maximum flow rate.\nsource\n# Ribasim.is_flow_direction_constraining — Method.\nWhether the given node is flow direction constraining (only in direction of edges).\nsource\n# Ribasim.load_data — Method.\nload_data(db::DB, config::Config, nodetype::Symbol, kind::Symbol)::Union{Table, Query, Nothing}\nLoad data from Arrow files if available, otherwise the database. Returns either an Arrow.Table, SQLite.Query or nothing if the data is not present.\nsource\n# Ribasim.load_structvector — Method.\nload_structvector(db::DB, config::Config, ::Type{T})::StructVector{T}\nLoad data from Arrow files if available, otherwise the database. Always returns a StructVector of the given struct type T, which is empty if the table is not found. This function validates the schema, and enforces the required sort order.\nsource\n# Ribasim.low_storage_factor — Method.\nIf id is a Basin with storage below the threshold, return a reduction factor != 1\nsource\n# Ribasim.main — Method.\nmain(toml_path::AbstractString)::Cint\nmain(ARGS::Vector{String})::Cint\nmain()::Cint\nThis is the main entry point of the application. Performs argument parsing and sets up logging for both terminal and file. Calls Ribasim.run() and handles exceptions to convert to exit codes.\nsource\n# Ribasim.metadata_from_edge — Method.\nGet the metadata of an edge in the graph from an edge of the underlying DiGraph.\nsource\n# Ribasim.nodefields — Method.\nGet all node fieldnames of the parameter object.\nsource\n# Ribasim.nodetype — Method.\nFrom a SchemaVersion(“ribasim.flowboundary.static”, 1) return (:FlowBoundary, :static)\nsource\n# Ribasim.outflow_id — Method.\nGet the unique outneighbor over a flow edge.\nsource\n# Ribasim.outflow_ids — Method.\nGet the outneighbors over flow edges.\nsource\n# Ribasim.outflow_ids_allocation — Method.\nGet the outneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.outneighbor_labels_type — Method.\nGet the outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.parse_static_and_time — Method.\nProcess the data in the static and time tables for a given node type. The ‘defaults’ named tuple dictates how missing data is filled in. ‘time_interpolatables’ is a vector of Symbols of parameter names for which a time interpolation (linear) object must be constructed. The control mapping for DiscreteControl is also constructed in this function. This function currently does not support node states that are defined by more than one row in a table, as is the case for TabulatedRatingCurve.\nsource\n# Ribasim.pkgversion — Method.\nGet the package version of a given module\nsource\n# Ribasim.process_allocation_graph_edges! — Method.\nFor the composite allocation network edges:\n\nFind out whether they are connected to allocation network nodes on both ends\nCompute their capacity\nFind out their allowed flow direction(s)\n\nsource\n# Ribasim.profile_storage — Method.\nCalculate a profile storage by integrating the areas over the levels\nsource\n# Ribasim.qh_interpolation — Method.\nFrom a table with columns nodeid, flowrate (Q) and level (h), create a LinearInterpolation from level to flow rate for a given node_id.\nsource\n# Ribasim.reduction_factor — Method.\nFunction that goes smoothly from 0 to 1 in the interval [0,threshold], and is constant outside this interval.\nsource\n# Ribasim.run — Method.\nrun(config_file::AbstractString)::Model\nrun(config::Config)::Model\nRun a Model, given a path to a TOML configuration file, or a Config object. Running a model includes initialization, solving to the end with [solve!](@ref) and writing results with write_results.\nsource\n# Ribasim.save_allocation_flows! — Method.\nSave the allocation flows per basin and physical edge.\nsource\n# Ribasim.save_demands_and_allocations! — Method.\nSave the demands and allocated flows for UserDemand and Basin. Note: Basin supply (negative demand) is only saved for the first priority.\nsource\n# Ribasim.save_flow — Method.\nCompute the average flows over the last saveat interval and write them to SavedValues\nsource\n# Ribasim.save_subgrid_level — Method.\nInterpolate the levels and save them to SavedValues\nsource\n# Ribasim.scalar_interpolation_derivative — Method.\nDerivative of scalar interpolation.\nsource\n# Ribasim.seconds_since — Method.\nseconds_since(t::DateTime, t0::DateTime)::Float64\nConvert a DateTime to a float that is the number of seconds since the start of the simulation. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.set_current_value! — Method.\nFrom a timeseries table time, load the most recent applicable data into table. table must be a NamedTuple of vectors with all variables that must be loaded. The most recent applicable data is non-NaN data for a given ID that is on or before t.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q over the edge between the given nodes.\nsource\n# Ribasim.set_fractional_flow_in_allocation! — Method.\nUpdate the fractional flow fractions in an allocation problem.\nsource\n# Ribasim.set_initial_discrete_controlled_parameters! — Method.\nSet parameters of nodes that are controlled by DiscreteControl to the values corresponding to the initial state of the model.\nsource\n# Ribasim.set_is_pid_controlled! — Method.\nSet ispidcontrolled to true for those pumps and outlets that are PID controlled\nsource\n# Ribasim.set_objective_priority! — Method.\nSet the objective for the given priority. For an objective with absolute values this also involves adjusting constraints.\nsource\n# Ribasim.set_static_value! — Method.\nLoad data from a source table static into a destination table. Data is matched based on the node_id, which is sorted.\nsource\n# Ribasim.set_table_row! — Method.\nUpdate table at row index i, with the values of a given row. table must be a NamedTuple of vectors with all variables that must be loaded. The row must contain all the column names that are present in the table. If a value is missing, it is not set.\nsource\n# Ribasim.sorted_table! — Method.\nDepending on if a table can be sorted, either sort it or assert that it is sorted.\nTables loaded from the database into memory can be sorted. Tables loaded from Arrow files are memory mapped and can therefore not be sorted.\nsource\n# Ribasim.tsaves — Method.\nGet all saved times in seconds since start\nsource\n# Ribasim.update_allocation! — Method.\nSolve the allocation problem for all demands and assign allocated abstractions.\nsource\n# Ribasim.update_basin — Method.\nLoad updates from ‘Basin / time’ into the parameters\nsource\n# Ribasim.update_jac_prototype! — Method.\nMethod for nodes that do not contribute to the Jacobian\nsource\n# Ribasim.update_jac_prototype! — Method.\nThe controlled basin affects itself and the basins upstream and downstream of the controlled pump affect eachother if there is a basin upstream of the pump. The state for the integral term and the controlled basin affect eachother, and the same for the integral state and the basin upstream of the pump if it is indeed a basin.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the unique node downstream of these nodes are basins, then these directly depend on eachother and affect the Jacobian 2x Basins always depend on themselves.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the nodes down stream (or one node further if a fractional flow is in between) are basins, then the downstream basin depends on the upstream basin(s) and affect the Jacobian as many times as there are downstream basins Upstream basins always depend on themselves.\nsource\n# Ribasim.update_tabulated_rating_curve! — Method.\nLoad updates from ‘TabulatedRatingCurve / time’ into the parameters\nsource\n# Ribasim.valid_discrete_control — Method.\nCheck:\n\nwhether control states are defined for discrete controlled nodes;\nWhether the supplied truth states have the proper length;\nWhether look_ahead is only supplied for condition variables given by a time-series.\n\nsource\n# Ribasim.valid_edge_types — Method.\nCheck that only supported edge types are declared.\nsource\n# Ribasim.valid_edges — Method.\nTest for each node given its node type whether the nodes that\nare downstream (‘down-edge’) of this node are of an allowed type\nsource\n# Ribasim.valid_flow_rates — Method.\nTest whether static or discrete controlled flow rates are indeed non-negative.\nsource\n# Ribasim.valid_fractional_flow — Method.\nCheck that nodes that have fractional flow outneighbors do not have any other type of outneighbor, that the fractions leaving a node add up to ≈1 and that the fractions are non-negative.\nsource\n# Ribasim.valid_n_neighbors — Method.\nTest for each node given its node type whether it has an allowed number of flow/control inneighbors and outneighbors\nsource\n# Ribasim.valid_profiles — Method.\nCheck whether the profile data has no repeats in the levels and the areas start positive.\nsource\n# Ribasim.valid_sources — Method.\nThe source nodes must only have one allocation outneighbor and no allocation inneighbors.\nsource\n# Ribasim.valid_subgrid — Method.\nValidate the entries for a single subgrid element.\nsource\n# Ribasim.water_balance! — Method.\nThe right hand side function of the system of ODEs set up by Ribasim.\nsource\n# Ribasim.write_arrow — Method.\nWrite a result table to disk as an Arrow file\nsource\n# Ribasim.write_results — Method.\nwrite_results(model::Model)::Model\nWrite all results to the Arrow files as specified in the model configuration.\nsource\n# Ribasim.config.algorithm — Method.\nCreate an OrdinaryDiffEqAlgorithm from solver config\nsource\n# Ribasim.config.convert_dt — Method.\nConvert the dt from our Config to SciML stepsize control arguments\nsource\n# Ribasim.config.convert_saveat — Method.\nConvert the saveat Float64 from our Config to SciML’s saveat\nsource\n# Ribasim.config.input_path — Method.\nConstruct a path relative to both the TOML directory and the optional input_dir\nsource\n# Ribasim.config.results_path — Method.\nConstruct a path relative to both the TOML directory and the optional results_dir\nsource\n# Ribasim.config.snake_case — Method.\nConvert a string from CamelCase to snake_case.\nsource",
+ "text": "1.3 Functions\n# BasicModelInterface.finalize — Method.\nBMI.finalize(model::Model)::Model\nWrite all results to the configured files.\nsource\n# BasicModelInterface.initialize — Method.\nBMI.initialize(T::Type{Model}, config_path::AbstractString)::Model\nInitialize a Model from the path to the TOML configuration file.\nsource\n# CommonSolve.solve! — Method.\nsolve!(model::Model)::ODESolution\nSolve a Model until the configured endtime.\nsource\n# Ribasim.add_basin_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a basin.\nsource\n# Ribasim.add_constraints_absolute_value! — Method.\nMinimizing |expr| can be achieved by introducing a new variable exprabs and posing the following constraints: exprabs >= expr expr_abs >= -expr\nsource\n# Ribasim.add_constraints_absolute_value_flow_demand! — Method.\nAdd constraints so that variables Fabsflow_demand act as the absolute value of the expression comparing flow to a flow buffer to the flow demand.\nsource\n# Ribasim.add_constraints_absolute_value_level_demand! — Method.\nAdd constraints so that variables Fabslevel_demand act as the absolute value of the expression comparing flow to a basin to its demand.\nsource\n# Ribasim.add_constraints_absolute_value_user_demand! — Method.\nAdd constraints so that variables Fabsuser_demand act as the absolute value of the expression comparing flow to a UserDemand to its demand.\nsource\n# Ribasim.add_constraints_basin_flow! — Method.\nAdd the Basin flow constraints to the allocation problem. The constraint indices are the Basin node IDs.\nConstraint: flow out of basin <= basin capacity\nsource\n# Ribasim.add_constraints_buffer! — Method.\nAdd the buffer outflow constraints to the allocation problem. The constraint indices are the node IDs of the nodes that have a flow demand.\nConstraint: flow out of buffer <= flow buffer capacity\nsource\n# Ribasim.add_constraints_capacity! — Method.\nAdd the flow capacity constraints to the allocation problem. Only finite capacities get a constraint. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over edge <= edge capacity\nsource\n# Ribasim.add_constraints_conservation_basin! — Method.\nAdd the basin flow conservation constraints to the allocation problem. The constraint indices are Basin node IDs.\nConstraint: sum(flows out of basin) == sum(flows into basin) + flow from storage and vertical fluxes\nsource\n# Ribasim.add_constraints_conservation_flow_demand! — Method.\nAdd the conservation constraints for connector nodes with a flow demand to the allocation problem. The constraint indices are node IDs of the nodes with the flow demand (so not the IDs of the FlowDemand nodes).\nConstraint: flow into node + flow out of buffer = flow out of node + flow into buffer\nsource\n# Ribasim.add_constraints_conservation_subnetwork! — Method.\nAdd the subnetwork inlet flow conservation constraints to the allocation problem. The constraint indices are node IDs subnetwork inlet edge dst IDs.\nConstraint: sum(flows into node) == sum(flows out of node)\nsource\n# Ribasim.add_constraints_flow_demand_outflow! — Method.\nAdd the flow demand node outflow constraints to the allocation problem. The constraint indices are the node IDs of the nodes that have a flow demand.\nConstraint: flow out of node with flow demand <= ∞ if not at flow demand priority, 0.0 otherwise\nsource\n# Ribasim.add_constraints_fractional_flow! — Method.\nAdd the fractional flow constraints to the allocation problem. The constraint indices are allocation edges over a fractional flow node.\nConstraint: flow after fractional_flow node <= fraction * inflow\nsource\n# Ribasim.add_constraints_source! — Method.\nAdd the source constraints to the allocation problem. The actual threshold values will be set before each allocation solve. The constraint indices are (edgesourceid, edgedstid).\nConstraint: flow over source edge <= source flow in subnetwork\nsource\n# Ribasim.add_constraints_user_demand_returnflow! — Method.\nAdd the UserDemand returnflow constraints to the allocation problem. The constraint indices are UserDemand node IDs. Constraint: outflow from userdemand <= return factor inflow to user*demand\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the flow over the edge on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.add_flow! — Method.\nAdd the given flow q to the existing flow over the edge between the given nodes.\nsource\n# Ribasim.add_flow_demand_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a node with a a flow demand.\nsource\n# Ribasim.add_objective_term! — Function.\nAdd a term to the objective function given by the objective type, depending in the provided flow variable and the associated demand.\nsource\n# Ribasim.add_subnetwork_connections! — Method.\nAdd the edges connecting the main network work to a subnetwork to both the main network and subnetwork allocation network.\nsource\n# Ribasim.add_user_demand_term! — Method.\nAdd a term to the expression of the objective function corresponding to the demand of a UserDemand.\nsource\n# Ribasim.add_variables_absolute_value! — Method.\nCertain allocation distribution types use absolute values in the objective function. Since most optimization packages do not support the absolute value function directly, New variables are introduced that act as the absolute value of an expression by posing the appropriate constraints.\nsource\n# Ribasim.add_variables_basin! — Method.\nAdd the variables for supply/demand of a basin to the problem. The variable indices are the node_ids of the basins with a level demand in the subnetwork.\nsource\n# Ribasim.add_variables_flow! — Method.\nAdd the flow variables F to the allocation problem. The variable indices are (edgesourceid, edgedstid). Non-negativivity constraints are also immediately added to the flow variables.\nsource\n# Ribasim.add_variables_flow_buffer! — Method.\nAdd the variables for supply/demand of a node with a flow demand to the problem. The variable indices are the node_ids of the nodes with a flow demand in the subnetwork.\nsource\n# Ribasim.adjust_capacities_basin! — Method.\nSet the capacities of the basin outflows. 2 cases:\n\nBefore the first allocation solve, set the capacities to their full capacity if there is surplus storage;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the capacities.\n\nsource\n# Ribasim.adjust_capacities_buffers! — Method.\nAdjust the capacities of the flow buffers of nodes with a flow demand. 2 cases:\n\nBefore the first allocation solve, set the capacities to 0.0;\nBefore an allocation solve, add the flow into the buffer and remove the flow out of the buffer from the buffer capacity.\n\nsource\n# Ribasim.adjust_capacities_edge! — Method.\nSet the values of the edge capacities. 2 cases:\n\nBefore the first allocation solve, set the edge capacities to their full capacity;\nBefore an allocation solve, subtract the flow used by allocation for the previous priority from the edge capacities.\n\nsource\n# Ribasim.adjust_capacities_flow_demand_outflow! — Method.\nSet the capacity of the outflow edge from a node with a flow demand:\n\nTo Inf if the current priority is other than the priority of the flow demand\nTo 0.0 if the current priority is equal to the priority of the flow demand\n\nsource\n# Ribasim.adjust_capacities_source! — Method.\nAdjust the source flows.\nsource\n# Ribasim.adjust_demands_flow! — Method.\nSet the demand of the flow demand nodes. 2 cases:\n\nBefore the first allocation solve, set the demands to their full value;\nBefore an allocation solve, subtract the flow trough the node with a flow demand from the total flow demand (which will be used at the priority of the flow demand only).\n\nsource\n# Ribasim.all_neighbor_labels_type — Method.\nGet the in- and outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.allocate! — Method.\nUpdate the allocation optimization problem for the given subnetwork with the problem state and flows, solve the allocation problem and assign the results to the UserDemand.\nsource\n# Ribasim.allocation_graph — Method.\nBuild the graph used for the allocation problem.\nsource\n# Ribasim.allocation_graph_used_nodes! — Method.\nFind all nodes in the subnetwork which will be used in the allocation network. Some nodes are skipped to optimize allocation optimization.\nsource\n# Ribasim.allocation_path_exists_in_graph — Method.\nFind out whether a path exists between a start node and end node in the given allocation network.\nsource\n# Ribasim.allocation_problem — Method.\nConstruct the allocation problem for the current subnetwork as a JuMP.jl model.\nsource\n# Ribasim.allocation_table — Method.\nCreate an allocation result table for the saved data\nsource\n# Ribasim.assign_allocations! — Method.\nAssign the allocations to the UserDemand as determined by the solution of the allocation problem.\nsource\n# Ribasim.avoid_using_own_returnflow! — Method.\nRemove allocation UserDemand return flow edges that are upstream of the UserDemand itself.\nsource\n# Ribasim.basin_bottom — Method.\nReturn the bottom elevation of the basin with index i, or nothing if it doesn’t exist\nsource\n# Ribasim.basin_bottoms — Method.\nGet the bottom on both ends of a node. If only one has a bottom, use that for both.\nsource\n# Ribasim.basin_table — Method.\nCreate the basin result table from the saved data\nsource\n# Ribasim.create_callbacks — Method.\nCreate the different callbacks that are used to store results and feed the simulation with new data. The different callbacks are combined to a CallbackSet that goes to the integrator. Returns the CallbackSet and the SavedValues for flow.\nsource\n# Ribasim.create_graph — Method.\nReturn a directed metagraph with data of nodes (NodeMetadata): NodeMetadata\nand data of edges (EdgeMetadata): EdgeMetadata\nsource\n# Ribasim.create_storage_tables — Method.\nRead the Basin / profile table and return all area and level and computed storage values\nsource\n# Ribasim.datetime_since — Method.\ndatetime_since(t::Real, t0::DateTime)::DateTime\nConvert a Real that represents the seconds passed since the simulation start to the nearest DateTime. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.datetimes — Method.\nGet all saved times as a Vector{DateTime}\nsource\n# Ribasim.discrete_control_affect! — Method.\nChange parameters based on the control logic.\nsource\n# Ribasim.discrete_control_affect_downcrossing! — Method.\nAn downcrossing means that a condition (always greater than) becomes false.\nsource\n# Ribasim.discrete_control_affect_upcrossing! — Method.\nAn upcrossing means that a condition (always greater than) becomes true.\nsource\n# Ribasim.discrete_control_condition — Method.\nListens for changes in condition truths.\nsource\n# Ribasim.discrete_control_table — Method.\nCreate a discrete control result table from the saved data\nsource\n# Ribasim.expand_logic_mapping — Method.\nReplace the truth states in the logic mapping which contain wildcards with all possible explicit truth states.\nsource\n# Ribasim.find_allocation_graph_edges! — Method.\nThis loop finds allocation network edges in several ways:\n\nBetween allocation network nodes whose equivalent in the subnetwork are directly connected\nBetween allocation network nodes whose equivalent in the subnetwork are connected with one or more allocation network nodes in between\n\nsource\n# Ribasim.find_subnetwork_connections! — Method.\nFind the edges from the main network to a subnetwork.\nsource\n# Ribasim.findlastgroup — Method.\nFor an element id and a vector of elements ids, get the range of indices of the last consecutive block of id. Returns the empty range 1:0 if id is not in ids.\nsource\n# Ribasim.findsorted — Method.\nFind the index of element x in a sorted collection a. Returns the index of x if it exists, or nothing if it doesn’t. If x occurs more than once, throw an error.\nsource\n# Ribasim.flow_table — Method.\nCreate a flow result table from the saved data\nsource\n# Ribasim.formulate_basins! — Method.\nSmoothly let the evaporation flux go to 0 when at small water depths Currently at less than 0.1 m.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.formulate_flow! — Method.\nConservation of energy for two basins, a and b:\nh_a + v_a^2 / (2 * g) = h_b + v_b^2 / (2 * g) + S_f * L + C / 2 * g * (v_b^2 - v_a^2)\nWhere:\n\nha, hb are the heads at basin a and b.\nva, vb are the velocities at basin a and b.\ng is the gravitational constant.\nS_f is the friction slope.\nC is an expansion or extraction coefficient.\n\nWe assume velocity differences are negligible (va = vb):\nh_a = h_b + S_f * L\nThe friction losses are approximated by the Gauckler-Manning formula:\nQ = A * (1 / n) * R_h^(2/3) * S_f^(1/2)\nWhere:\n\nWhere A is the cross-sectional area.\nV is the cross-sectional average velocity.\nn is the Gauckler-Manning coefficient.\nR_h is the hydraulic radius.\nS_f is the friction slope.\n\nThe hydraulic radius is defined as:\nR_h = A / P\nWhere P is the wetted perimeter.\nThe average of the upstream and downstream water depth is used to compute cross-sectional area and hydraulic radius. This ensures that a basin can receive water after it has gone dry.\nsource\n# Ribasim.formulate_flow! — Method.\nDirected graph: outflow is positive!\nsource\n# Ribasim.get_area_and_level — Method.\nCompute the area and level of a basin given its storage. Also returns darea/dlevel as it is needed for the Jacobian.\nsource\n# Ribasim.get_basin_capacity — Method.\nGet the capacity of the basin, i.e. the maximum flow that can be abstracted from the basin if it is in a state of surplus storage (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_basin_data — Method.\nGet several variables associated with a basin:\n\nIts current storage\nThe allocation update interval\nThe influx (sum of instantaneous vertical fluxes of the basin)\nThe index of the connected level_demand node (0 if such a node does not exist)\nThe index of the basin\n\nsource\n# Ribasim.get_basin_demand — Method.\nGet the demand of the basin, i.e. how large a flow the basin needs to get to its minimum target level (0 if no reference levels are provided by a level_demand node). Storages are converted to flows by dividing by the allocation timestep.\nsource\n# Ribasim.get_chunk_sizes — Method.\nGet the chunk sizes for DiffCache; differentiation w.r.t. u and t (the latter only if a Rosenbrock algorithm is used).\nsource\n# Ribasim.get_compressor — Method.\nGet the compressor based on the Results section\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given horizontal (selfloop) edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_flow — Method.\nGet the flow over the given edge (val is needed for get_tmp from ForwardDiff.jl).\nsource\n# Ribasim.get_fractional_flow_connected_basins — Method.\nGet the node type specific indices of the fractional flows and basins, that are consecutively connected to a node of given id.\nsource\n# Ribasim.get_jac_prototype — Method.\nGet a sparse matrix whose sparsity matches the sparsity of the Jacobian of the ODE problem. All nodes are taken into consideration, also the ones that are inactive.\nIn Ribasim the Jacobian is typically sparse because each state only depends on a small number of other states.\nNote: the name ‘prototype’ does not mean this code is a prototype, it comes from the naming convention of this sparsity structure in the differentialequations.jl docs.\nsource\n# Ribasim.get_level — Method.\nGet the current water level of a node ID. The ID can belong to either a Basin or a LevelBoundary. storage: tells ForwardDiff whether this call is for differentiation or not\nsource\n# Ribasim.get_scalar_interpolation — Method.\nLinear interpolation of a scalar with constant extrapolation.\nsource\n# Ribasim.get_storage_from_level — Method.\nGet the storage of a basin from its level.\nsource\n# Ribasim.get_storages_and_levels — Method.\nGet the storage and level of all basins as matrices of nbasin × ntime\nsource\n# Ribasim.get_storages_from_levels — Method.\nCompute the storages of the basins based on the water level of the basins.\nsource\n# Ribasim.get_tstops — Method.\nFrom an iterable of DateTimes, find the times the solver needs to stop\nsource\n# Ribasim.get_value — Method.\nGet a value for a condition. Currently supports getting levels from basins and flows from flow boundaries.\nsource\n# Ribasim.id_index — Method.\nGet the index of an ID in a set of indices.\nsource\n# Ribasim.indicate_allocation_flow! — Method.\nAdd to the edge metadata that the given edge is used for allocation flow. If the edge does not exist, it is created.\nsource\n# Ribasim.inflow_id — Method.\nGet the unique inneighbor over a flow edge.\nsource\n# Ribasim.inflow_ids — Method.\nGet the inneighbors over flow edges.\nsource\n# Ribasim.inflow_ids_allocation — Method.\nGet the inneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.inneighbor_labels_type — Method.\nGet the inneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.inoutflow_ids — Method.\nGet the in- and outneighbors over flow edges.\nsource\n# Ribasim.integrate_flows! — Method.\nIntegrate flows over the last timestep\nsource\n# Ribasim.is_allocation_source — Method.\nFind out whether the given edge is a source for an allocation network.\nsource\n# Ribasim.is_current_module — Method.\nis_current_module(log::LogMessageType)::Bool\nReturns true if the log message is from the current module or a submodule.\n\nSee https://github.com/JuliaLogging/LoggingExtras.jl/blob/d35e7c8cfc197853ee336ace17182e6ed36dca24/src/CompositionalLoggers/earlyfiltered.jl#L39\nfor the information available in log.\nsource\n# Ribasim.is_flow_constraining — Method.\nWhether the given node node is flow constraining by having a maximum flow rate.\nsource\n# Ribasim.is_flow_direction_constraining — Method.\nWhether the given node is flow direction constraining (only in direction of edges).\nsource\n# Ribasim.load_data — Method.\nload_data(db::DB, config::Config, nodetype::Symbol, kind::Symbol)::Union{Table, Query, Nothing}\nLoad data from Arrow files if available, otherwise the database. Returns either an Arrow.Table, SQLite.Query or nothing if the data is not present.\nsource\n# Ribasim.load_structvector — Method.\nload_structvector(db::DB, config::Config, ::Type{T})::StructVector{T}\nLoad data from Arrow files if available, otherwise the database. Always returns a StructVector of the given struct type T, which is empty if the table is not found. This function validates the schema, and enforces the required sort order.\nsource\n# Ribasim.low_storage_factor — Method.\nIf id is a Basin with storage below the threshold, return a reduction factor != 1\nsource\n# Ribasim.main — Method.\nmain(toml_path::AbstractString)::Cint\nmain(ARGS::Vector{String})::Cint\nmain()::Cint\nThis is the main entry point of the application. Performs argument parsing and sets up logging for both terminal and file. Calls Ribasim.run() and handles exceptions to convert to exit codes.\nsource\n# Ribasim.metadata_from_edge — Method.\nGet the metadata of an edge in the graph from an edge of the underlying DiGraph.\nsource\n# Ribasim.nodefields — Method.\nGet all node fieldnames of the parameter object.\nsource\n# Ribasim.nodetype — Method.\nFrom a SchemaVersion(“ribasim.flowboundary.static”, 1) return (:FlowBoundary, :static)\nsource\n# Ribasim.outflow_id — Method.\nGet the unique outneighbor over a flow edge.\nsource\n# Ribasim.outflow_ids — Method.\nGet the outneighbors over flow edges.\nsource\n# Ribasim.outflow_ids_allocation — Method.\nGet the outneighbors of the given ID such that the connecting edge is an allocation flow edge.\nsource\n# Ribasim.outneighbor_labels_type — Method.\nGet the outneighbor node IDs of the given node ID (label) over the given edge type in the graph.\nsource\n# Ribasim.parse_static_and_time — Method.\nProcess the data in the static and time tables for a given node type. The ‘defaults’ named tuple dictates how missing data is filled in. ‘time_interpolatables’ is a vector of Symbols of parameter names for which a time interpolation (linear) object must be constructed. The control mapping for DiscreteControl is also constructed in this function. This function currently does not support node states that are defined by more than one row in a table, as is the case for TabulatedRatingCurve.\nsource\n# Ribasim.pkgversion — Method.\nGet the package version of a given module\nsource\n# Ribasim.process_allocation_graph_edges! — Method.\nFor the composite allocation network edges:\n\nFind out whether they are connected to allocation network nodes on both ends\nCompute their capacity\nFind out their allowed flow direction(s)\n\nsource\n# Ribasim.profile_storage — Method.\nCalculate a profile storage by integrating the areas over the levels\nsource\n# Ribasim.qh_interpolation — Method.\nFrom a table with columns nodeid, flowrate (Q) and level (h), create a LinearInterpolation from level to flow rate for a given node_id.\nsource\n# Ribasim.reduction_factor — Method.\nFunction that goes smoothly from 0 to 1 in the interval [0,threshold], and is constant outside this interval.\nsource\n# Ribasim.run — Method.\nrun(config_file::AbstractString)::Model\nrun(config::Config)::Model\nRun a Model, given a path to a TOML configuration file, or a Config object. Running a model includes initialization, solving to the end with [solve!](@ref) and writing results with write_results.\nsource\n# Ribasim.save_allocation_flows! — Method.\nSave the allocation flows per basin and physical edge.\nsource\n# Ribasim.save_demands_and_allocations! — Method.\nSave the demands and allocated flows for UserDemand and Basin. Note: Basin supply (negative demand) is only saved for the first priority.\nsource\n# Ribasim.save_flow — Method.\nCompute the average flows over the last saveat interval and write them to SavedValues\nsource\n# Ribasim.save_subgrid_level — Method.\nInterpolate the levels and save them to SavedValues\nsource\n# Ribasim.scalar_interpolation_derivative — Method.\nDerivative of scalar interpolation.\nsource\n# Ribasim.seconds_since — Method.\nseconds_since(t::DateTime, t0::DateTime)::Float64\nConvert a DateTime to a float that is the number of seconds since the start of the simulation. This is used to convert between the solver’s inner float time, and the calendar.\nsource\n# Ribasim.set_current_value! — Method.\nFrom a timeseries table time, load the most recent applicable data into table. table must be a NamedTuple of vectors with all variables that must be loaded. The most recent applicable data is non-NaN data for a given ID that is on or before t.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q on the horizontal (self-loop) edge from id to id.\nsource\n# Ribasim.set_flow! — Method.\nSet the given flow q over the edge between the given nodes.\nsource\n# Ribasim.set_fractional_flow_in_allocation! — Method.\nUpdate the fractional flow fractions in an allocation problem.\nsource\n# Ribasim.set_initial_discrete_controlled_parameters! — Method.\nSet parameters of nodes that are controlled by DiscreteControl to the values corresponding to the initial state of the model.\nsource\n# Ribasim.set_is_pid_controlled! — Method.\nSet ispidcontrolled to true for those pumps and outlets that are PID controlled\nsource\n# Ribasim.set_objective_priority! — Method.\nSet the objective for the given priority. For an objective with absolute values this also involves adjusting constraints.\nsource\n# Ribasim.set_static_value! — Method.\nLoad data from a source table static into a destination table. Data is matched based on the node_id, which is sorted.\nsource\n# Ribasim.set_table_row! — Method.\nUpdate table at row index i, with the values of a given row. table must be a NamedTuple of vectors with all variables that must be loaded. The row must contain all the column names that are present in the table. If a value is missing, it is not set.\nsource\n# Ribasim.sorted_table! — Method.\nDepending on if a table can be sorted, either sort it or assert that it is sorted.\nTables loaded from the database into memory can be sorted. Tables loaded from Arrow files are memory mapped and can therefore not be sorted.\nsource\n# Ribasim.tsaves — Method.\nGet all saved times in seconds since start\nsource\n# Ribasim.update_allocation! — Method.\nSolve the allocation problem for all demands and assign allocated abstractions.\nsource\n# Ribasim.update_basin — Method.\nLoad updates from ‘Basin / time’ into the parameters\nsource\n# Ribasim.update_jac_prototype! — Method.\nMethod for nodes that do not contribute to the Jacobian\nsource\n# Ribasim.update_jac_prototype! — Method.\nThe controlled basin affects itself and the basins upstream and downstream of the controlled pump affect eachother if there is a basin upstream of the pump. The state for the integral term and the controlled basin affect eachother, and the same for the integral state and the basin upstream of the pump if it is indeed a basin.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the unique node downstream of these nodes are basins, then these directly depend on eachother and affect the Jacobian 2x Basins always depend on themselves.\nsource\n# Ribasim.update_jac_prototype! — Method.\nIf both the unique node upstream and the nodes down stream (or one node further if a fractional flow is in between) are basins, then the downstream basin depends on the upstream basin(s) and affect the Jacobian as many times as there are downstream basins Upstream basins always depend on themselves.\nsource\n# Ribasim.update_tabulated_rating_curve! — Method.\nLoad updates from ‘TabulatedRatingCurve / time’ into the parameters\nsource\n# Ribasim.valid_discrete_control — Method.\nCheck:\n\nwhether control states are defined for discrete controlled nodes;\nWhether the supplied truth states have the proper length;\nWhether look_ahead is only supplied for condition variables given by a time-series.\n\nsource\n# Ribasim.valid_edge_types — Method.\nCheck that only supported edge types are declared.\nsource\n# Ribasim.valid_edges — Method.\nTest for each node given its node type whether the nodes that\nare downstream (‘down-edge’) of this node are of an allowed type\nsource\n# Ribasim.valid_flow_rates — Method.\nTest whether static or discrete controlled flow rates are indeed non-negative.\nsource\n# Ribasim.valid_fractional_flow — Method.\nCheck that nodes that have fractional flow outneighbors do not have any other type of outneighbor, that the fractions leaving a node add up to ≈1 and that the fractions are non-negative.\nsource\n# Ribasim.valid_n_neighbors — Method.\nTest for each node given its node type whether it has an allowed number of flow/control inneighbors and outneighbors\nsource\n# Ribasim.valid_profiles — Method.\nCheck whether the profile data has no repeats in the levels and the areas start positive.\nsource\n# Ribasim.valid_sources — Method.\nThe source nodes must only have one allocation outneighbor and no allocation inneighbors.\nsource\n# Ribasim.valid_subgrid — Method.\nValidate the entries for a single subgrid element.\nsource\n# Ribasim.water_balance! — Method.\nThe right hand side function of the system of ODEs set up by Ribasim.\nsource\n# Ribasim.write_arrow — Method.\nWrite a result table to disk as an Arrow file\nsource\n# Ribasim.write_results — Method.\nwrite_results(model::Model)::Model\nWrite all results to the Arrow files as specified in the model configuration.\nsource\n# Ribasim.config.algorithm — Method.\nCreate an OrdinaryDiffEqAlgorithm from solver config\nsource\n# Ribasim.config.convert_dt — Method.\nConvert the dt from our Config to SciML stepsize control arguments\nsource\n# Ribasim.config.convert_saveat — Method.\nConvert the saveat Float64 from our Config to SciML’s saveat\nsource\n# Ribasim.config.input_path — Method.\nConstruct a path relative to both the TOML directory and the optional input_dir\nsource\n# Ribasim.config.results_path — Method.\nConstruct a path relative to both the TOML directory and the optional results_dir\nsource\n# Ribasim.config.snake_case — Method.\nConvert a string from CamelCase to snake_case.\nsource",
"crumbs": [
"Julia core",
"API Reference"
@@ -442,7 +449,7 @@
"href": "build/index.html#index",
"title": "1 API Reference",
"section": "1.6 Index",
- "text": "1.6 Index\n\nRibasim.Ribasim\nRibasim.config\nRibasim.config.algorithms\nRibasim.Allocation\nRibasim.AllocationModel\nRibasim.AllocationModel\nRibasim.Basin\nRibasim.DiscreteControl\nRibasim.EdgeMetadata\nRibasim.FlatVector\nRibasim.FlowBoundary\nRibasim.FractionalFlow\nRibasim.InNeighbors\nRibasim.LevelBoundary\nRibasim.LevelDemand\nRibasim.LinearResistance\nRibasim.ManningResistance\nRibasim.Model\nRibasim.NodeMetadata\nRibasim.OutNeighbors\nRibasim.Outlet\nRibasim.PidControl\nRibasim.Pump\nRibasim.Subgrid\nRibasim.TabulatedRatingCurve\nRibasim.Terminal\nRibasim.UserDemand\nRibasim.config.Config\nBasicModelInterface.finalize\nBasicModelInterface.initialize\nCommonSolve.solve!\nRibasim.add_basin_term!\nRibasim.add_constraints_absolute_value!\nRibasim.add_constraints_absolute_value_basin!\nRibasim.add_constraints_absolute_value_user_demand!\nRibasim.add_constraints_basin_flow!\nRibasim.add_constraints_capacity!\nRibasim.add_constraints_flow_conservation!\nRibasim.add_constraints_fractional_flow!\nRibasim.add_constraints_source!\nRibasim.add_constraints_user_demand_returnflow!\nRibasim.add_flow!\nRibasim.add_flow!\nRibasim.add_objective_term!\nRibasim.add_subnetwork_connections!\nRibasim.add_user_demand_term!\nRibasim.add_variables_absolute_value!\nRibasim.add_variables_basin!\nRibasim.add_variables_flow!\nRibasim.adjust_basin_capacities!\nRibasim.adjust_edge_capacities!\nRibasim.adjust_source_capacities!\nRibasim.all_neighbor_labels_type\nRibasim.allocate!\nRibasim.allocation_graph\nRibasim.allocation_graph_used_nodes!\nRibasim.allocation_path_exists_in_graph\nRibasim.allocation_problem\nRibasim.allocation_table\nRibasim.assign_allocations!\nRibasim.avoid_using_own_returnflow!\nRibasim.basin_bottom\nRibasim.basin_bottoms\nRibasim.basin_table\nRibasim.config.algorithm\nRibasim.config.convert_dt\nRibasim.config.convert_saveat\nRibasim.config.input_path\nRibasim.config.results_path\nRibasim.config.snake_case\nRibasim.create_callbacks\nRibasim.create_graph\nRibasim.create_storage_tables\nRibasim.datetime_since\nRibasim.datetimes\nRibasim.discrete_control_affect!\nRibasim.discrete_control_affect_downcrossing!\nRibasim.discrete_control_affect_upcrossing!\nRibasim.discrete_control_condition\nRibasim.discrete_control_table\nRibasim.expand_logic_mapping\nRibasim.find_allocation_graph_edges!\nRibasim.find_subnetwork_connections!\nRibasim.findlastgroup\nRibasim.findsorted\nRibasim.flow_table\nRibasim.formulate_basins!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.get_area_and_level\nRibasim.get_basin_capacity\nRibasim.get_basin_data\nRibasim.get_basin_demand\nRibasim.get_chunk_sizes\nRibasim.get_compressor\nRibasim.get_flow\nRibasim.get_flow\nRibasim.get_fractional_flow_connected_basins\nRibasim.get_jac_prototype\nRibasim.get_level\nRibasim.get_scalar_interpolation\nRibasim.get_storage_from_level\nRibasim.get_storages_and_levels\nRibasim.get_storages_from_levels\nRibasim.get_tstops\nRibasim.get_value\nRibasim.id_index\nRibasim.indicate_allocation_flow!\nRibasim.inflow_id\nRibasim.inflow_ids\nRibasim.inflow_ids_allocation\nRibasim.inneighbor_labels_type\nRibasim.inoutflow_ids\nRibasim.integrate_flows!\nRibasim.is_allocation_source\nRibasim.is_current_module\nRibasim.is_flow_constraining\nRibasim.is_flow_direction_constraining\nRibasim.load_data\nRibasim.load_structvector\nRibasim.low_storage_factor\nRibasim.main\nRibasim.metadata_from_edge\nRibasim.nodefields\nRibasim.nodetype\nRibasim.outflow_id\nRibasim.outflow_ids\nRibasim.outflow_ids_allocation\nRibasim.outneighbor_labels_type\nRibasim.parse_static_and_time\nRibasim.pkgversion\nRibasim.process_allocation_graph_edges!\nRibasim.profile_storage\nRibasim.qh_interpolation\nRibasim.reduction_factor\nRibasim.run\nRibasim.save_allocation_flows!\nRibasim.save_demands_and_allocations!\nRibasim.save_flow\nRibasim.save_subgrid_level\nRibasim.scalar_interpolation_derivative\nRibasim.seconds_since\nRibasim.set_current_value!\nRibasim.set_flow!\nRibasim.set_flow!\nRibasim.set_fractional_flow_in_allocation!\nRibasim.set_initial_discrete_controlled_parameters!\nRibasim.set_is_pid_controlled!\nRibasim.set_objective_priority!\nRibasim.set_static_value!\nRibasim.set_table_row!\nRibasim.sorted_table!\nRibasim.tsaves\nRibasim.update_allocation!\nRibasim.update_basin\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_tabulated_rating_curve!\nRibasim.valid_discrete_control\nRibasim.valid_edge_types\nRibasim.valid_edges\nRibasim.valid_flow_rates\nRibasim.valid_fractional_flow\nRibasim.valid_n_neighbors\nRibasim.valid_profiles\nRibasim.valid_sources\nRibasim.valid_subgrid\nRibasim.water_balance!\nRibasim.write_arrow\nRibasim.write_results\nRibasim.config.@addfields\nRibasim.config.@addnodetypes",
+ "text": "1.6 Index\n\nRibasim.Ribasim\nRibasim.config\nRibasim.config.algorithms\nRibasim.Allocation\nRibasim.AllocationModel\nRibasim.AllocationModel\nRibasim.Basin\nRibasim.DiscreteControl\nRibasim.EdgeMetadata\nRibasim.FlatVector\nRibasim.FlowBoundary\nRibasim.FractionalFlow\nRibasim.InNeighbors\nRibasim.LevelBoundary\nRibasim.LevelDemand\nRibasim.LinearResistance\nRibasim.ManningResistance\nRibasim.Model\nRibasim.NodeMetadata\nRibasim.OutNeighbors\nRibasim.Outlet\nRibasim.PidControl\nRibasim.Pump\nRibasim.Subgrid\nRibasim.TabulatedRatingCurve\nRibasim.Terminal\nRibasim.UserDemand\nRibasim.config.Config\nBasicModelInterface.finalize\nBasicModelInterface.initialize\nCommonSolve.solve!\nRibasim.add_basin_term!\nRibasim.add_constraints_absolute_value!\nRibasim.add_constraints_absolute_value_flow_demand!\nRibasim.add_constraints_absolute_value_level_demand!\nRibasim.add_constraints_absolute_value_user_demand!\nRibasim.add_constraints_basin_flow!\nRibasim.add_constraints_buffer!\nRibasim.add_constraints_capacity!\nRibasim.add_constraints_conservation_basin!\nRibasim.add_constraints_conservation_flow_demand!\nRibasim.add_constraints_conservation_subnetwork!\nRibasim.add_constraints_flow_demand_outflow!\nRibasim.add_constraints_fractional_flow!\nRibasim.add_constraints_source!\nRibasim.add_constraints_user_demand_returnflow!\nRibasim.add_flow!\nRibasim.add_flow!\nRibasim.add_flow_demand_term!\nRibasim.add_objective_term!\nRibasim.add_subnetwork_connections!\nRibasim.add_user_demand_term!\nRibasim.add_variables_absolute_value!\nRibasim.add_variables_basin!\nRibasim.add_variables_flow!\nRibasim.add_variables_flow_buffer!\nRibasim.adjust_capacities_basin!\nRibasim.adjust_capacities_buffers!\nRibasim.adjust_capacities_edge!\nRibasim.adjust_capacities_flow_demand_outflow!\nRibasim.adjust_capacities_source!\nRibasim.adjust_demands_flow!\nRibasim.all_neighbor_labels_type\nRibasim.allocate!\nRibasim.allocation_graph\nRibasim.allocation_graph_used_nodes!\nRibasim.allocation_path_exists_in_graph\nRibasim.allocation_problem\nRibasim.allocation_table\nRibasim.assign_allocations!\nRibasim.avoid_using_own_returnflow!\nRibasim.basin_bottom\nRibasim.basin_bottoms\nRibasim.basin_table\nRibasim.config.algorithm\nRibasim.config.convert_dt\nRibasim.config.convert_saveat\nRibasim.config.input_path\nRibasim.config.results_path\nRibasim.config.snake_case\nRibasim.create_callbacks\nRibasim.create_graph\nRibasim.create_storage_tables\nRibasim.datetime_since\nRibasim.datetimes\nRibasim.discrete_control_affect!\nRibasim.discrete_control_affect_downcrossing!\nRibasim.discrete_control_affect_upcrossing!\nRibasim.discrete_control_condition\nRibasim.discrete_control_table\nRibasim.expand_logic_mapping\nRibasim.find_allocation_graph_edges!\nRibasim.find_subnetwork_connections!\nRibasim.findlastgroup\nRibasim.findsorted\nRibasim.flow_table\nRibasim.formulate_basins!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.formulate_flow!\nRibasim.get_area_and_level\nRibasim.get_basin_capacity\nRibasim.get_basin_data\nRibasim.get_basin_demand\nRibasim.get_chunk_sizes\nRibasim.get_compressor\nRibasim.get_flow\nRibasim.get_flow\nRibasim.get_fractional_flow_connected_basins\nRibasim.get_jac_prototype\nRibasim.get_level\nRibasim.get_scalar_interpolation\nRibasim.get_storage_from_level\nRibasim.get_storages_and_levels\nRibasim.get_storages_from_levels\nRibasim.get_tstops\nRibasim.get_value\nRibasim.id_index\nRibasim.indicate_allocation_flow!\nRibasim.inflow_id\nRibasim.inflow_ids\nRibasim.inflow_ids_allocation\nRibasim.inneighbor_labels_type\nRibasim.inoutflow_ids\nRibasim.integrate_flows!\nRibasim.is_allocation_source\nRibasim.is_current_module\nRibasim.is_flow_constraining\nRibasim.is_flow_direction_constraining\nRibasim.load_data\nRibasim.load_structvector\nRibasim.low_storage_factor\nRibasim.main\nRibasim.metadata_from_edge\nRibasim.nodefields\nRibasim.nodetype\nRibasim.outflow_id\nRibasim.outflow_ids\nRibasim.outflow_ids_allocation\nRibasim.outneighbor_labels_type\nRibasim.parse_static_and_time\nRibasim.pkgversion\nRibasim.process_allocation_graph_edges!\nRibasim.profile_storage\nRibasim.qh_interpolation\nRibasim.reduction_factor\nRibasim.run\nRibasim.save_allocation_flows!\nRibasim.save_demands_and_allocations!\nRibasim.save_flow\nRibasim.save_subgrid_level\nRibasim.scalar_interpolation_derivative\nRibasim.seconds_since\nRibasim.set_current_value!\nRibasim.set_flow!\nRibasim.set_flow!\nRibasim.set_fractional_flow_in_allocation!\nRibasim.set_initial_discrete_controlled_parameters!\nRibasim.set_is_pid_controlled!\nRibasim.set_objective_priority!\nRibasim.set_static_value!\nRibasim.set_table_row!\nRibasim.sorted_table!\nRibasim.tsaves\nRibasim.update_allocation!\nRibasim.update_basin\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_jac_prototype!\nRibasim.update_tabulated_rating_curve!\nRibasim.valid_discrete_control\nRibasim.valid_edge_types\nRibasim.valid_edges\nRibasim.valid_flow_rates\nRibasim.valid_fractional_flow\nRibasim.valid_n_neighbors\nRibasim.valid_profiles\nRibasim.valid_sources\nRibasim.valid_subgrid\nRibasim.water_balance!\nRibasim.write_arrow\nRibasim.write_results\nRibasim.config.@addfields\nRibasim.config.@addnodetypes",
"crumbs": [
"Julia core",
"API Reference"
@@ -475,7 +482,7 @@
"href": "core/equations.html#sec-reduction_factor",
"title": "Equations",
"section": "2.1 The reduction factor",
- "text": "2.1 The reduction factor\nAt several points in the equations below a reduction factor is used. This is a term that makes certain transitions more smooth, for instance when a pump stops providing water when its source basin dries up. The reduction factor is given by\n\\[\\begin{align}\n \\phi(x; p) =\n \\begin{cases}\n 0 &\\text{if}\\quad x < 0 \\\\\n -2 \\left(\\frac{x}{p}\\right)^3 + 3\\left(\\frac{x}{p}\\right)^2 &\\text{if}\\quad 0 \\le x \\le p \\\\\n 1 &\\text{if}\\quad x > p\n \\end{cases}\n\\end{align}\\]\nHere \\(p > 0\\) is the threshold value which determines the interval \\([0,p]\\) of the smooth transition between \\(0\\) and \\(1\\), see the plot below.\n\n\nCode\nimport numpy as np\nimport matplotlib.pyplot as plt\n\ndef f(x, p = 3):\n x_scaled = x / p\n phi = (-2 * x_scaled + 3) * x_scaled**2\n phi = np.where(x < 0, 0, phi)\n phi = np.where(x > p, 1, phi)\n\n return phi\n\nfontsize = 15\np = 3\nN = 100\nx_min = -1\nx_max = 4\nx = np.linspace(x_min,x_max,N)\nphi = f(x,p)\n\nfig,ax = plt.subplots(dpi=80)\nax.plot(x,phi)\n\ny_lim = ax.get_ylim()\n\nax.set_xticks([0,p], [0,\"$p$\"], fontsize=fontsize)\nax.set_yticks([0,1], [0,1], fontsize=fontsize)\nax.hlines([0,1],x_min,x_max, color = \"k\", ls = \":\", zorder=-1)\nax.vlines([0,p], *y_lim, color = \"k\", ls = \":\")\nax.set_xlim(x_min,x_max)\nax.set_xlabel(\"$x$\", fontsize=fontsize)\nax.set_ylabel(\"$\\phi(x;p)$\", fontsize=fontsize)\nax.set_ylim(y_lim)\n\nfig.tight_layout()\nplt.show()\n\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n/tmp/ipykernel_2757/665069857.py:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'",
+ "text": "2.1 The reduction factor\nAt several points in the equations below a reduction factor is used. This is a term that makes certain transitions more smooth, for instance when a pump stops providing water when its source basin dries up. The reduction factor is given by\n\\[\\begin{align}\n \\phi(x; p) =\n \\begin{cases}\n 0 &\\text{if}\\quad x < 0 \\\\\n -2 \\left(\\frac{x}{p}\\right)^3 + 3\\left(\\frac{x}{p}\\right)^2 &\\text{if}\\quad 0 \\le x \\le p \\\\\n 1 &\\text{if}\\quad x > p\n \\end{cases}\n\\end{align}\\]\nHere \\(p > 0\\) is the threshold value which determines the interval \\([0,p]\\) of the smooth transition between \\(0\\) and \\(1\\), see the plot below.\n\n\nCode\nimport numpy as np\nimport matplotlib.pyplot as plt\n\ndef f(x, p = 3):\n x_scaled = x / p\n phi = (-2 * x_scaled + 3) * x_scaled**2\n phi = np.where(x < 0, 0, phi)\n phi = np.where(x > p, 1, phi)\n\n return phi\n\nfontsize = 15\np = 3\nN = 100\nx_min = -1\nx_max = 4\nx = np.linspace(x_min,x_max,N)\nphi = f(x,p)\n\nfig,ax = plt.subplots(dpi=80)\nax.plot(x,phi)\n\ny_lim = ax.get_ylim()\n\nax.set_xticks([0,p], [0,\"$p$\"], fontsize=fontsize)\nax.set_yticks([0,1], [0,1], fontsize=fontsize)\nax.hlines([0,1],x_min,x_max, color = \"k\", ls = \":\", zorder=-1)\nax.vlines([0,p], *y_lim, color = \"k\", ls = \":\")\nax.set_xlim(x_min,x_max)\nax.set_xlabel(\"$x$\", fontsize=fontsize)\nax.set_ylabel(\"$\\phi(x;p)$\", fontsize=fontsize)\nax.set_ylim(y_lim)\n\nfig.tight_layout()\nplt.show()\n\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n<>:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'\n\n/tmp/ipykernel_2915/665069857.py:31: SyntaxWarning:\n\ninvalid escape sequence '\\p'",
"crumbs": [
"Julia core",
"Equations"
@@ -695,7 +702,7 @@
"href": "core/usage.html#userdemand-time",
"title": "Usage",
"section": "10.1 UserDemand / time",
- "text": "10.1 UserDemand / time\nThis table is the transient form of the UserDemand table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the demand can be updated over time. In between the given times the demand is interpolated linearly, and outside the demand is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\npriority\nInt32\n-\npositive, sorted per node id\n\n\ntime\nDateTime\n-\nsorted per priority per node id\n\n\ndemand\nFloat64\n\\(m^3 s^{-1}\\)\n-\n\n\nreturn_factor\nFloat64\n-\nbetween [0 - 1]\n\n\nmin_level\nFloat64\n\\(m\\)\n-",
+ "text": "10.1 UserDemand / time\nThis table is the transient form of the UserDemand table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the demand can be updated over time. In between the given times the demand is interpolated linearly, and outside the demand is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\npriority\nInt32\n-\npositive, sorted per node id\n\n\ntime\nDateTime\n-\nsorted per priority per node id\n\n\ndemand\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative\n\n\nreturn_factor\nFloat64\n-\nbetween [0 - 1]\n\n\nmin_level\nFloat64\n\\(m\\)\n-",
"crumbs": [
"Julia core",
"Usage"
@@ -712,12 +719,23 @@
"Usage"
]
},
+ {
+ "objectID": "core/usage.html#flowdemand-time",
+ "href": "core/usage.html#flowdemand-time",
+ "title": "Usage",
+ "section": "12.1 FlowDemand / time",
+ "text": "12.1 FlowDemand / time\nThis table is the transient form of the FlowDemand table, in which a time-dependent demand can be supplied. Similar to the static version, only a single priority per FlowDemand node can be provided.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node id\n\n\npriority\nInt32\n-\npositive\n\n\ndemand\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative",
+ "crumbs": [
+ "Julia core",
+ "Usage"
+ ]
+ },
{
"objectID": "core/usage.html#levelboundary-time",
"href": "core/usage.html#levelboundary-time",
"title": "Usage",
- "section": "12.1 LevelBoundary / time",
- "text": "12.1 LevelBoundary / time\nThis table is the transient form of the LevelBoundary table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the levels can be updated over time. In between the given times the level is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlevel\nFloat64\n\\(m\\)\n-",
+ "section": "13.1 LevelBoundary / time",
+ "text": "13.1 LevelBoundary / time\nThis table is the transient form of the LevelBoundary table. The only difference is that a time column is added and activity is assumed to be true. The table must by sorted by time, and per time it must be sorted by node_id. With this the levels can be updated over time. In between the given times the level is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlevel\nFloat64\n\\(m\\)\n-",
"crumbs": [
"Julia core",
"Usage"
@@ -727,8 +745,8 @@
"objectID": "core/usage.html#flowboundary-time",
"href": "core/usage.html#flowboundary-time",
"title": "Usage",
- "section": "13.1 FlowBoundary / time",
- "text": "13.1 FlowBoundary / time\nThis table is the transient form of the FlowBoundary table. The only differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the flow rates can be updated over time. In between the given times the flow rate is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative",
+ "section": "14.1 FlowBoundary / time",
+ "text": "14.1 FlowBoundary / time\nThis table is the transient form of the FlowBoundary table. The only differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the flow rates can be updated over time. In between the given times the flow rate is interpolated linearly, and outside the flow rate is constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\nnon-negative",
"crumbs": [
"Julia core",
"Usage"
@@ -738,8 +756,8 @@
"objectID": "core/usage.html#discretecontrol-condition",
"href": "core/usage.html#discretecontrol-condition",
"title": "Usage",
- "section": "17.1 DiscreteControl / condition",
- "text": "17.1 DiscreteControl / condition\nThe 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.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\nlisten_node_type\nString\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\nsorted per node_id\n\n\nvariable\nString\n-\nmust be “level” or “flow_rate”, sorted per listen_node_id\n\n\ngreater_than\nFloat64\nvarious\nsorted per variable\n\n\nlook_ahead\nFloat64\n\\(s\\)\nOnly on transient boundary conditions, non-negative (optional, default 0)",
+ "section": "18.1 DiscreteControl / condition",
+ "text": "18.1 DiscreteControl / condition\nThe 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.\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\nlisten_node_type\nString\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\nsorted per node_id\n\n\nvariable\nString\n-\nmust be “level” or “flow_rate”, sorted per listen_node_id\n\n\ngreater_than\nFloat64\nvarious\nsorted per variable\n\n\nlook_ahead\nFloat64\n\\(s\\)\nOnly on transient boundary conditions, non-negative (optional, default 0)",
"crumbs": [
"Julia core",
"Usage"
@@ -749,8 +767,8 @@
"objectID": "core/usage.html#discretecontrol-logic",
"href": "core/usage.html#discretecontrol-logic",
"title": "Usage",
- "section": "17.2 DiscreteControl / logic",
- "text": "17.2 DiscreteControl / logic\nThe logic schema defines which control states are triggered based on the truth of the conditions a DiscreteControl node listens to. DiscreteControl is applied in the Julia core as follows:\n\nDuring the simulation it is checked whether the truth of any of the conditions changes.\nWhen a condition changes, the corresponding DiscreteControl node ID is retrieved (node_id in the condition schema above).\nThe truth value of all the conditions this DiscreteControl node listens to are retrieved, in the sorted order as specified in the condition schema. This is then converted into a string of “T” for true and “F” for false. This string we call the truth state.*\nThe table below determines for the given DiscreteControl node ID and truth state what the corresponding control state is.\nFor all the nodes this DiscreteControl node affects (as given by the “control” edges in Edges / static), their parameters are set to those parameters in NodeType / static corresponding to the determined control state.\n\n*. There is also a second truth state created in which for the last condition that changed it is specified whether it was an upcrossing (“U”) or downcrossing (“D”) of the threshold (greater than) value. If a control state is specified for a truth state that is crossing-specific, this takes precedence over the control state for the truth state that contains only “T” and “F”.\n\n\n\n\n\n\nNote\n\n\n\nWhen creating truth states, it is important to not use the order of the condition table as you provide it, but the order as it is written to the file. Users can provide tables in any order, but when writing the model it gets sorted in the required order as specified in the schema.\n\n\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ncontrol_state\nString\n-\n-\n\n\ntruth_state\nString\n-\nConsists of the characters “T” (true), “F” (false), “U” (upcrossing), “D” (downcrossing) and “*” (any), sorted per node_id",
+ "section": "18.2 DiscreteControl / logic",
+ "text": "18.2 DiscreteControl / logic\nThe logic schema defines which control states are triggered based on the truth of the conditions a DiscreteControl node listens to. DiscreteControl is applied in the Julia core as follows:\n\nDuring the simulation it is checked whether the truth of any of the conditions changes.\nWhen a condition changes, the corresponding DiscreteControl node ID is retrieved (node_id in the condition schema above).\nThe truth value of all the conditions this DiscreteControl node listens to are retrieved, in the sorted order as specified in the condition schema. This is then converted into a string of “T” for true and “F” for false. This string we call the truth state.*\nThe table below determines for the given DiscreteControl node ID and truth state what the corresponding control state is.\nFor all the nodes this DiscreteControl node affects (as given by the “control” edges in Edges / static), their parameters are set to those parameters in NodeType / static corresponding to the determined control state.\n\n*. There is also a second truth state created in which for the last condition that changed it is specified whether it was an upcrossing (“U”) or downcrossing (“D”) of the threshold (greater than) value. If a control state is specified for a truth state that is crossing-specific, this takes precedence over the control state for the truth state that contains only “T” and “F”.\n\n\n\n\n\n\nNote\n\n\n\nWhen creating truth states, it is important to not use the order of the condition table as you provide it, but the order as it is written to the file. Users can provide tables in any order, but when writing the model it gets sorted in the required order as specified in the schema.\n\n\n\n\n\n\n\n\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ncontrol_state\nString\n-\n-\n\n\ntruth_state\nString\n-\nConsists of the characters “T” (true), “F” (false), “U” (upcrossing), “D” (downcrossing) and “*” (any), sorted per node_id",
"crumbs": [
"Julia core",
"Usage"
@@ -760,8 +778,8 @@
"objectID": "core/usage.html#pidcontrol-time",
"href": "core/usage.html#pidcontrol-time",
"title": "Usage",
- "section": "18.1 PidControl / time",
- "text": "18.1 PidControl / time\nThis table is the transient form of the PidControl table. The differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the target level and PID coefficients can be updated over time. In between the given times the these values interpolated linearly, and outside these values area constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlisten_node_type\nInt32\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\n-\n\n\ntarget\nFloat64\n\\(m\\)\n-\n\n\nproportional\nFloat64\n\\(s^{-1}\\)\n-\n\n\nintegral\nFloat64\n\\(s^{-2}\\)\n-\n\n\nderivative\nFloat64\n-\n-",
+ "section": "19.1 PidControl / time",
+ "text": "19.1 PidControl / time\nThis table is the transient form of the PidControl table. The differences are that a time column is added and the nodes are assumed to be active so this column is removed. The table must by sorted by time, and per time it must be sorted by node_id. With this the target level and PID coefficients can be updated over time. In between the given times the these values interpolated linearly, and outside these values area constant given by the nearest time value. Note that a node_id can be either in this table or in the static one, but not both.\n\n\n\ncolumn\ntype\nunit\nrestriction\n\n\n\n\nnode_id\nInt32\n-\nsorted\n\n\ntime\nDateTime\n-\nsorted per node_id\n\n\nlisten_node_type\nInt32\n-\nknown node type\n\n\nlisten_node_id\nInt32\n-\n-\n\n\ntarget\nFloat64\n\\(m\\)\n-\n\n\nproportional\nFloat64\n\\(s^{-1}\\)\n-\n\n\nintegral\nFloat64\n\\(s^{-2}\\)\n-\n\n\nderivative\nFloat64\n-\n-",
"crumbs": [
"Julia core",
"Usage"
@@ -771,8 +789,8 @@
"objectID": "core/usage.html#basin---basin.arrow",
"href": "core/usage.html#basin---basin.arrow",
"title": "Usage",
- "section": "19.1 Basin - basin.arrow",
- "text": "19.1 Basin - basin.arrow\nThe basin table contains results of the storage and level of each basin at every solver timestep. The initial condition is also written to the file.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nnode_id\nInt32\n-\n\n\nstorage\nFloat64\n\\(m^3\\)\n\n\nlevel\nFloat64\n\\(m\\)\n\n\n\nThe table is sorted by time, and per time it is sorted by node_id.",
+ "section": "20.1 Basin - basin.arrow",
+ "text": "20.1 Basin - basin.arrow\nThe basin table contains results of the storage and level of each basin at every solver timestep. The initial condition is also written to the file.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nnode_id\nInt32\n-\n\n\nstorage\nFloat64\n\\(m^3\\)\n\n\nlevel\nFloat64\n\\(m\\)\n\n\n\nThe table is sorted by time, and per time it is sorted by node_id.",
"crumbs": [
"Julia core",
"Usage"
@@ -782,8 +800,8 @@
"objectID": "core/usage.html#flow---flow.arrow",
"href": "core/usage.html#flow---flow.arrow",
"title": "Usage",
- "section": "19.2 Flow - flow.arrow",
- "text": "19.2 Flow - flow.arrow\nThe flow table contains calculated mean flows for every flow edge in the model. In the time column the start of the period is indicated.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nedge_id\nUnion{Int32, Missing}\n-\n\n\nfrom_node_type\nString\n-\n\n\nfrom_node_id\nInt32\n-\n\n\nto_node_type\nString\n-\n\n\nto_node_id\nInt32\n-\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\n\n\n\nThe table is sorted by time, and per time the same edge_id order is used, though not sorted. The edge_id value is the same as the fid written to the Edge table, and can be used to directly look up the Edge geometry. Flows that are added to the model at a node, have a missing edge_id, and identical from_node_id and to_node_id. Flows out of the model always have a negative sign, and additions a positive sign.",
+ "section": "20.2 Flow - flow.arrow",
+ "text": "20.2 Flow - flow.arrow\nThe flow table contains calculated mean flows for every flow edge in the model. In the time column the start of the period is indicated.\n\n\n\ncolumn\ntype\nunit\n\n\n\n\ntime\nDateTime\n-\n\n\nedge_id\nUnion{Int32, Missing}\n-\n\n\nfrom_node_type\nString\n-\n\n\nfrom_node_id\nInt32\n-\n\n\nto_node_type\nString\n-\n\n\nto_node_id\nInt32\n-\n\n\nflow_rate\nFloat64\n\\(m^3 s^{-1}\\)\n\n\n\nThe table is sorted by time, and per time the same edge_id order is used, though not sorted. The edge_id value is the same as the fid written to the Edge table, and can be used to directly look up the Edge geometry. Flows that are added to the model at a node, have a missing edge_id, and identical from_node_id and to_node_id. Flows out of the model always have a negative sign, and additions a positive sign.",
"crumbs": [
"Julia core",
"Usage"
@@ -793,8 +811,8 @@
"objectID": "core/usage.html#discretecontrol---control.arrow",
"href": "core/usage.html#discretecontrol---control.arrow",
"title": "Usage",
- "section": "19.3 DiscreteControl - control.arrow",
- "text": "19.3 DiscreteControl - control.arrow\nThe control table contains a record of each change of control state: when it happened, which control node was involved, to which control state it changed and based on which truth state.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\ncontrol_node_id\nInt32\n\n\ntruth_state\nString\n\n\ncontrol_state\nString",
+ "section": "20.3 DiscreteControl - control.arrow",
+ "text": "20.3 DiscreteControl - control.arrow\nThe control table contains a record of each change of control state: when it happened, which control node was involved, to which control state it changed and based on which truth state.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\ncontrol_node_id\nInt32\n\n\ntruth_state\nString\n\n\ncontrol_state\nString",
"crumbs": [
"Julia core",
"Usage"
@@ -804,8 +822,8 @@
"objectID": "core/usage.html#allocation---allocation.arrow",
"href": "core/usage.html#allocation---allocation.arrow",
"title": "Usage",
- "section": "19.4 Allocation - allocation.arrow",
- "text": "19.4 Allocation - allocation.arrow\nThe allocation table contains a record of allocation results: when it happened, for which node, in which allocation network, and what the demand, allocated flow and realized flow were.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nsubnetwork_id\nInt32\n\n\nnode_type\nString\n\n\nnode_id\nInt32\n\n\npriority\nInt32\n\n\ndemand\nFloat64\n\n\nallocated\nFloat64\n\n\nrealized\nFloat64\n\n\n\nFor Basins the values demand, allocated and realized are positive if the Basin level is below the minimum level given by a LevelDemand node. The values are negative if the Basin supplies due to a surplus of water.\n\n\n\n\n\n\nNote\n\n\n\nCurrently the stored demand and abstraction rate are those at the allocation timepoint (and the abstraction rate is based on the previous allocation optimization). In the future these will be an average over the previous allocation timestep.",
+ "section": "20.4 Allocation - allocation.arrow",
+ "text": "20.4 Allocation - allocation.arrow\nThe allocation table contains a record of allocation results: when it happened, for which node, in which allocation network, and what the demand, allocated flow and realized flow were.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nsubnetwork_id\nInt32\n\n\nnode_type\nString\n\n\nnode_id\nInt32\n\n\npriority\nInt32\n\n\ndemand\nFloat64\n\n\nallocated\nFloat64\n\n\nrealized\nFloat64\n\n\n\nFor Basins the values demand, allocated and realized are positive if the Basin level is below the minimum level given by a LevelDemand node. The values are negative if the Basin supplies due to a surplus of water.\n\n\n\n\n\n\nNote\n\n\n\nCurrently the stored demand and abstraction rate are those at the allocation timepoint (and the abstraction rate is based on the previous allocation optimization). In the future these will be an average over the previous allocation timestep.",
"crumbs": [
"Julia core",
"Usage"
@@ -815,8 +833,8 @@
"objectID": "core/usage.html#allocation-flow---allocation_flow.arrow",
"href": "core/usage.html#allocation-flow---allocation_flow.arrow",
"title": "Usage",
- "section": "19.5 Allocation flow - allocation_flow.arrow",
- "text": "19.5 Allocation flow - allocation_flow.arrow\nThe allocation flow table contains results of the optimized allocation flow on every edge in the model that is part of a subnetwork, for each time an optimization problem is solved (see also here). If in the model a main network and subnetwork(s) are specified, there are 2 different types of optimization for the subnetwork: collecting its total demand per priority (for allocating flow from the main network to the subnetwork), and allocating flow within the subnetwork. The column collect_demands provides the distinction between these two optimization types.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nedge_id\nInt32\n\n\nfrom_node_type\nString\n\n\nfrom_node_id\nInt32\n\n\nto_node_type\nString\n\n\nto_node_id\nInt32\n\n\nsubnetwork_id\nInt32\n\n\npriority\nInt32\n\n\nflow_rate\nFloat64\n\n\ncollect_demands\nBool",
+ "section": "20.5 Allocation flow - allocation_flow.arrow",
+ "text": "20.5 Allocation flow - allocation_flow.arrow\nThe allocation flow table contains results of the optimized allocation flow on every edge in the model that is part of a subnetwork, for each time an optimization problem is solved (see also here). If in the model a main network and subnetwork(s) are specified, there are 2 different types of optimization for the subnetwork: collecting its total demand per priority (for allocating flow from the main network to the subnetwork), and allocating flow within the subnetwork. The column collect_demands provides the distinction between these two optimization types.\n\n\n\ncolumn\ntype\n\n\n\n\ntime\nDateTime\n\n\nedge_id\nInt32\n\n\nfrom_node_type\nString\n\n\nfrom_node_id\nInt32\n\n\nto_node_type\nString\n\n\nto_node_id\nInt32\n\n\nsubnetwork_id\nInt32\n\n\npriority\nInt32\n\n\nflow_rate\nFloat64\n\n\ncollect_demands\nBool",
"crumbs": [
"Julia core",
"Usage"
@@ -882,7 +900,7 @@
"href": "core/allocation.html",
"title": "Allocation",
"section": "",
- "text": "Allocation is the process of assigning an allocated abstraction flow rate to demand nodes in the physical layer of the model based on information about sources, the different demand nodes over various priorities, constraints introduced by nodes, local water availability and graph topology. The allocation procedure implemented in Ribasim is heavily inspired by the maximum flow problem.\nThe allocation problem is solved per subnetwork of the Ribasim model. The subnetwork is used to formulate an optimization problem with the JuMP package, which is solved using the HiGHS solver. For more in-depth information see also the example of solving the maximum flow problem with JuMP.jl here.",
+ "text": "Allocation is the process of assigning an allocated flow rate to demand nodes in the physical layer of the model based on information about sources, the different demand nodes over various priorities, constraints introduced by nodes, local water availability and graph topology. The allocation procedure implemented in Ribasim is heavily inspired by the maximum flow problem.\nThe allocation problem is solved per subnetwork of the Ribasim model. The subnetwork is used to formulate an optimization problem with the JuMP package, which is solved using the HiGHS solver. For more in-depth information see also the example of solving the maximum flow problem with JuMP.jl here.",
"crumbs": [
"Julia core",
"Allocation"
@@ -893,7 +911,7 @@
"href": "core/allocation.html#schematisation-input",
"title": "Allocation",
"section": "3.1 Schematisation input",
- "text": "3.1 Schematisation input\n\n3.1.1 The subnetwork\nThe allocation problem is solved per subnetwork, which is given by a subset \\(S \\subset V\\) of node ids. Different subnetworks are disjoint from eachother.\n\n\n3.1.2 Source flows\nSources are indicated by a set of edges in the subnetwork \\[\nE_S^\\text{source} \\subset \\left(S \\times S\\right) \\cap E.\n\\] That is, if \\((i,j) \\in E_S^\\text{source}\\), then \\(Q_{ij}\\) (see the formal model description) is treated as a source flow in the allocation problem. These edges are either coming from a boundary/source node (e.g. a level or flow boundary) or connect the main network to a subnetwork.\n\n\n3.1.3 User demands\nThe subnetwork contains a subset of UserDemand nodes \\(U_S \\subset S\\), who all have time varying demands over various priorities \\(p\\): \\[\n d^p_i(t), \\quad i \\in U_S, p = 1,2,\\ldots, p_{\\max}.\n\\]\n\n\n\n\n\n\nNote\n\n\n\nOn this page we assume that the priorities are given by all integers from \\(1\\) to some \\(p_{\\max} \\in \\mathbb{N}\\). However, in the Ribasim input this is not a requirement; some of these in between priority values can be missing, only the ordering of the given priorities is taken into account.",
+ "text": "3.1 Schematisation input\n\n3.1.1 The subnetwork\nThe allocation problem is solved per subnetwork, which is given by a subset \\(S \\subset V\\) of node ids. Different subnetworks are disjoint from eachother.\n\n\n3.1.2 Source flows\nSources are indicated by a set of edges in the subnetwork \\[\nE_S^\\text{source} \\subset \\left(S \\times S\\right) \\cap E.\n\\] That is, if \\((i,j) \\in E_S^\\text{source}\\), then \\(Q_{ij}\\) (see the formal model description) is treated as a source flow in the allocation problem. These edges are either coming from a boundary/source node (e.g. a level or flow boundary) or connect the main network to a subnetwork.\n\n\n3.1.3 User demands\nThe subnetwork contains a subset of UserDemand nodes \\(U_S \\subset S\\), who all have static or time varying demands over various priorities \\(p\\): \\[\n d^p_i(t), \\quad i \\in U_S, p = 1,2,\\ldots, p_{\\max}.\n\\] However, in\n\n\n\n\n\n\nNote\n\n\n\nOn this page we assume that the priorities are given by all integers from \\(1\\) to some \\(p_{\\max} \\in \\mathbb{N}\\).the Ribasim input this is not a requirement; some of these in between priority values can be missing, only the ordering of the given priorities is taken into account.\n\n\n\n\n3.1.4 Flow demands\nThe subnetwork contains a subset of nodes \\(FD_S \\in S\\) which have a demand of a single priority \\(p_{\\text{fd}}\\). With this we define \\[\n d^p_i(t) =\n \\begin{cases}\n 0 \\text{ if } p \\ne p_{\\text{fd}} \\\\\n d^{p_{\\text{df}}} \\text{ if } p = p_{\\text{fd}}\n \\end{cases}\n\\] for all \\(i \\in FD_S\\). Here \\(d^{p_{\\text{df}}}\\) is given by the original flow demand minus the flows trough node \\(i\\) at all priorities \\(p < p_{\\text{fd}}\\).",
"crumbs": [
"Julia core",
"Allocation"
@@ -915,7 +933,7 @@
"href": "core/allocation.html#the-allocation-network",
"title": "Allocation",
"section": "3.3 The allocation network",
- "text": "3.3 The allocation network\nA new graph is created from the subnetwork, which we call an allocation network. The allocation network is almost a subgraph of the main (flow) model, apart from the fact that an allocation network can contain edges which are a combination of multiple edges in the main model.\n\n3.3.1 Nodes and edges\nThe allocation network consists of:\n\nNodes \\(V'_S \\subset V_S\\), where each Basin, source and demand in the subnetwork get a node in the allocation network. Also nodes that have FractionalFlow outneighbors get a node in the allocation network.\nEdges \\(E_S\\), which are either edges that also appear between nodes in the subnetwork or represent a sequence of those, creating a shortcut.\n\nFor notational convenience, we use the notation\n\\[\\begin{align}\n V^{\\text{out}}_S(i) = \\left\\{j \\in V'_S : (i,j) \\in E_S\\right\\} \\\\\n V^{\\text{in}}_S(j) = \\left\\{i \\in V'_S : (i,j) \\in E_S\\right\\}\n\\end{align}\\]\nfor the set of in-neighbors and out-neighbors of a node in the allocation network respectively.\n\n\n3.3.2 Capacities\nEach edge in the allocation network has an associated capacity. These capacities are collected in the sparse capacity matrix \\(C_S \\in \\overline{\\mathbb{R}}_{\\ge 0}^{n'\\times n'}\\) where \\(n' = \\#V'_S\\) is the number of nodes in the allocation network. The capacities can be infinite, if there is nothing in the model constraining the capacity of the edge.\nThe capacities are determined in different ways:\n\nIf an edge does not exist in the allocation network, i.e. \\((i,j) \\notin E_S\\) for certain \\(1 \\le i,j\\le n'\\), then \\((C_S)_{i,j} = 0\\);\nThe capacity of the edge \\(e \\in E_S\\) is given by the smallest max_flow_rate of the nodes along the equivalent edges in the subnetwork. If there are no nodes with a max_flow_rate, the edge capacity is infinite;\nIf the edge is a source, the capacity of the edge is given by the flow rate of that source.\n\nThere are also capacities \\(C^B_S \\in \\mathbb{R}^b\\) where \\(b = \\# B_S\\) is the number of basins, for the flow supplied by basins.",
+ "text": "3.3 The allocation network\nA new graph is created from the subnetwork, which we call an allocation network. The allocation network is almost a subgraph of the main (flow) model, apart from the fact that an allocation network can contain edges which are a combination of multiple edges in the main model.\n\n3.3.1 Nodes and edges\nThe allocation network consists of:\n\nNodes \\(V'_S \\subset V_S\\). Nodes that are represented in the allocation network are: nodes of type Basin, UserDemand and Terminal, nodes that have FractionalFlow downstream neighbors, nodes that have a flow demand and nodes that are connected to a source edge.\nEdges \\(E_S\\), which are either edges that also appear between nodes in the subnetwork or represent a sequence of those, creating a shortcut.\n\nFor notational convenience, we use the notation\n\\[\\begin{align}\n V^{\\text{out}}_S(i) = \\left\\{j \\in V'_S : (i,j) \\in E_S\\right\\} \\\\\n V^{\\text{in}}_S(j) = \\left\\{i \\in V'_S : (i,j) \\in E_S\\right\\}\n\\end{align}\\]\nfor the set of in-neighbors and out-neighbors of a node in the allocation network respectively.\n\n\n3.3.2 Capacities\nEach edge in the allocation network has an associated capacity. These capacities are collected in the sparse capacity matrix \\(C_S \\in \\overline{\\mathbb{R}}_{\\ge 0}^{n'\\times n'}\\) where \\(n' = \\#V'_S\\) is the number of nodes in the allocation network. The capacities can be infinite, if there is nothing in the model constraining the capacity of the edge.\nThe capacities are determined in different ways:\n\nIf an edge does not exist in the allocation network, i.e. \\((i,j) \\notin E_S\\) for certain \\(1 \\le i,j\\le n'\\), then \\((C_S)_{i,j} = 0\\);\nThe capacity of the edge \\(e \\in E_S\\) is given by the smallest max_flow_rate of the nodes along the equivalent edges in the subnetwork. If there are no nodes with a max_flow_rate, the edge capacity is infinite;\nIf the edge is a source, the capacity of the edge is given by the flow rate of that source;\nIf an edge comes from a node with a flow demand, it has infinite capacity at priorities other than this of this flow demand, and zero capacity otherwise.\n\nThere are also capacities for special edges:\n\n\\(C^B_S \\in \\mathbb{R}^b_{\\ge 0}\\) where \\(b = \\# B_S\\) is the number of basins, for the flow supplied by basins.\n\\(C^{FD}_S \\in \\mathbb{R}^c_{\\ge 0}\\) where \\(c = \\# FD_S\\) is the number of nodes with a flow demand, for the flow supplied by flow buffers at these nodes with a flow demand.",
"crumbs": [
"Julia core",
"Allocation"
@@ -926,7 +944,7 @@
"href": "core/allocation.html#the-optimization-variables",
"title": "Allocation",
"section": "4.1 The optimization variables",
- "text": "4.1 The optimization variables\nThere are several types of variable whose value has to be determined to solve the allocation problem:\n\nThe flows \\(F \\in \\mathbb{R}_{\\ge 0}^{n'\\times n'}\\) over the edges in the allocation network;\nThe flows \\(F^\\text{basin out}_{i}, F^\\text{basin in}_{i} \\geq 0\\) for all \\(i \\in B_S\\) supplied and consumed by the basins respectively.",
+ "text": "4.1 The optimization variables\nThere are several types of variable whose value has to be determined to solve the allocation problem:\n\nThe flows \\(F \\in \\mathbb{R}_{\\ge 0}^{n'\\times n'}\\) over the edges in the allocation network;\nThe flows \\(F^\\text{basin out}_{i}, F^\\text{basin in}_{i} \\geq 0\\) for all \\(i \\in B_S\\) supplied and consumed by the basins respectively;\nThe flows \\(F^\\text{buffer out}_{i}, F^\\text{buffer in}_{i} \\ge 0\\) for all \\(i \\in FD_S\\) supplied and consumed by the flow buffers of nodes with a flow demand respectively.",
"crumbs": [
"Julia core",
"Allocation"
@@ -937,7 +955,7 @@
"href": "core/allocation.html#the-optimization-objective",
"title": "Allocation",
"section": "4.2 The optimization objective",
- "text": "4.2 The optimization objective\nThe goal of allocation is to get the flow to nodes with demands as close as possible to these demands. To achieve this, a sum error of terms is minimized.\n\\[\n \\min E_{\\text{user demand}} + E_{\\text{basin}}\n\\]\nThe error between the flows and user demands is denoted by \\(E_{\\text{user demand}}\\), where \\[\n E_{\\text{user demand}} = \\sum_{(i,j)\\in E_S\\;:\\; i\\in U_S} \\left| F_{ij} - d_j^p(t)\\right|\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing main network allocation, the connections to subnetworks are also interpreted as UserDemand with demands determined by subnetwork demand collection.\n\n\nThis type of objective cares about the absolute amount of water allocated to a demand. It treats all deviations equally which means it doesn’t give larger punishment per flow unit if deviations increase.\nThe absolute value applied here is not supported in a linear programming context directly; this requires introduction of new variables and constraints. For more details see here.\nLikewise, the error of basin demands is the absolute difference between flows consumed by basins and basin demands. \\[\n E_{\\text{basin}} = \\sum_{i \\in B_S} \\left| F_i^\\text{basin in} - d_i^p(t)\\right|\n\\]",
+ "text": "4.2 The optimization objective\nThe goal of allocation is to get the flow to nodes with demands as close as possible to these demands. To achieve this, a sum error of terms is minimized.\n\\[\n \\min E_{\\text{user demand}} + E_{\\text{level demand}} + E_{\\text{flow demand}}\n\\]\nThe error between the flows and user demands is denoted by \\(E_{\\text{user demand}}\\), where \\[\n E_{\\text{user demand}} = \\sum_{(i,j)\\in E_S\\;:\\; i\\in U_S} \\left| F_{ij} - d_j^p(t)\\right|\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing main network allocation, the connections to subnetworks are also interpreted as UserDemand with demands determined by subnetwork demand collection.\n\n\nThis type of objective cares about the absolute amount of water allocated to a demand. It treats all deviations equally which means it doesn’t give larger punishment per flow unit if deviations increase.\nThe absolute value applied here is not supported in a linear programming context directly; this requires introduction of new variables and constraints. For more details see here.\nLikewise, the error of level demands from basins is the absolute difference between flows consumed by basins and basin demands. \\[\n E_{\\text{level demand}} = \\sum_{i \\in B_S} \\left| F_i^\\text{basin in} - d_i^p(t)\\right|\n\\]\nLastly, the error of the flow demands is given as below. \\[\n E_{\\text{flow demand}} = \\sum_{i \\in FD_S} \\left| F_i^\\text{buffer in} - d_i^p(t)\\right|\n\\]",
"crumbs": [
"Julia core",
"Allocation"
@@ -948,7 +966,7 @@
"href": "core/allocation.html#the-optimization-constraints",
"title": "Allocation",
"section": "4.3 The optimization constraints",
- "text": "4.3 The optimization constraints\n\nFlow conservation: For the basins in the allocation network we have that \\[\n F^\\text{basin in}_k + \\sum_{j=1}^{n'} F_{kj} = F^\\text{basin out}_k + \\sum_{i=1}^{n'} F_{ik}, \\quad \\forall k \\in B_S .\n\\tag{1}\\] Note that we do not require equality here; in the allocation we do not mind that excess flow is ‘forgotten’ if it cannot contribute to the allocation to the demands.\n\n\n\n\n\n\n\nNote\n\n\n\nIn Equation 1, the placement of the basin flows might seem counter-intuitive. Think of the basin storage as a separate node connected to the basin node.\n\n\n\nCapacity: the flows over the edges are positive and bounded by the edge capacity: \\[\n F_{ij} \\le \\left(C_S\\right)_{ij}, \\quad \\forall(i,j) \\in E_S.\n\\tag{2}\\] By the definition of \\(C_S\\) this also includes the source flows. The same holds for the basin outflows:\n\n\\[\n F^{\\text{basin out}}_{i} \\le F^{\\text{basin out}}_{\\max, i}, \\quad \\forall i \\in B_S.\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing subnetwork demand collection, these capacities are set to \\(\\infty\\) for edges which connect the main network to a subnetwork.\n\n\n\nUserDemand outflow: The outflow of the UserDemand is dictated by the inflow and the return factor: \\[\n F_{ik} = r_k \\cdot F_{kj} \\quad\n \\quad \\forall k \\in U_S, \\quad\n V^{\\text{in}}_S(k) = \\{i\\},\\;\n V^{\\text{out}}_S(k) = \\{j\\}.\n\\tag{3}\\] Here we use that each UserDemand node in the allocation network has a unique in-edge and out-edge.\nUser demand: UserDemand demand constraints are discussed in the next section.\nFractional flow: Let \\(L_S \\subset V_S\\) be the set of nodes in the max flow graph with fractional flow outneighbors, and \\(f_j\\) the flow fraction associated with fractional flow node \\(j \\in V_S\\). Then \\[\n F_{ij} \\le f_j \\sum_{k\\in V^\\text{in}_S(i)} F_{ki} \\qquad\n \\forall i \\in L_S, \\;\n j \\in V_S^\\text{out}(i).\n\\tag{4}\\]\nFlow sign: Furthermore there are the non-negativity constraints for the flows and allocations, see The optimization variables.",
+ "text": "4.3 The optimization constraints\n\nFlow conservation: For the basins in the allocation network we have that \\[\n F^\\text{basin in}_k + \\sum_{j \\in V^{\\text{out}}_S(k)} F_{kj} = F^\\text{basin out}_k + \\sum_{i \\in V^{\\text{in}}_S(k)} F_{ik}, \\quad \\forall k \\in B_S .\n\\tag{1}\\] We have the same constraint without the basin terms for nodes that have flow edges as inneighbors (except if this node also happens to be a basin). For nodes which have a flow demand we have \\[\nF_{kj} + F^\\text{buffer in}_k = F^\\text{flow in}_k + F_{ik}, \\quad \\forall k \\in FD_S, \\quad V^{\\text{in}}_S(k) = \\{i\\},\\;\n V^{\\text{out}}_S(k) = \\{j\\}.\n\\tag{2}\\]\n\n\n\n\n\n\n\nNote\n\n\n\nIn Equation 1 and Equation 2, the placement of the basin and buffer flows might seem counter-intuitive. Think of the storage or buffer as a separate node connected to the node with the demand.\n\n\n\nCapacity: the flows over the edges are bounded by the edge capacity: \\[\n F_{ij} \\le \\left(C_S\\right)_{ij}, \\quad \\forall(i,j) \\in E_S.\n\\tag{3}\\] By the definition of \\(C_S\\) this also includes the source flows. The same holds for the basin outflows:\n\n\\[\n F^{\\text{basin out}}_{i} \\le F^{\\text{basin out}}_{\\max, i}, \\quad \\forall i \\in B_S.\n\\]\n\n\n\n\n\n\nNote\n\n\n\nWhen performing subnetwork demand collection, these capacities are set to \\(\\infty\\) for edges which connect the main network to a subnetwork.\n\n\nSimilar constraints hold for the flow out of basins and flow demand buffers: \\[\nF^\\text{basin out}_{i} \\le (C^B_S)_i, \\quad \\forall i \\in B_S,\n\\]\n\\[\nF^\\text{buffer out}_{i} \\le (C^FD_S)_i, \\quad \\forall i \\in FD_S.\n\\]\n\nUserDemand outflow: The outflow of the UserDemand is dictated by the inflow and the return factor: \\[\n F_{ik} = r_k \\cdot F_{kj} \\quad\n \\quad \\forall k \\in U_S, \\quad\n V^{\\text{in}}_S(k) = \\{i\\},\\;\n V^{\\text{out}}_S(k) = \\{j\\}.\n\\tag{4}\\] Here we use that each UserDemand node in the allocation network has a unique in-edge and out-edge.\nUser demand: UserDemand demand constraints are discussed in the next section.\nFractional flow: Let \\(L_S \\subset V_S\\) be the set of nodes in the max flow graph with fractional flow outneighbors, and \\(f_j\\) the flow fraction associated with fractional flow node \\(j \\in V_S\\). Then \\[\n F_{ij} \\le f_j \\sum_{k\\in V^\\text{in}_S(i)} F_{ki} \\qquad\n \\forall i \\in L_S, \\;\n j \\in V_S^\\text{out}(i).\n\\tag{5}\\]\nFlow sign: Furthermore there are the non-negativity constraints for the flows and allocations, see The optimization variables.",
"crumbs": [
"Julia core",
"Allocation"
@@ -970,7 +988,7 @@
"href": "core/allocation.html#example",
"title": "Allocation",
"section": "5.1 Example",
- "text": "5.1 Example\nThe following is an example of an optimization problem for the example shown here:\n\n\nCode\nusing Ribasim\nusing Ribasim: NodeID\nusing SQLite\nusing ComponentArrays: ComponentVector\n\ntoml_path = normpath(@__DIR__, \"../../generated_testmodels/allocation_example/ribasim.toml\")\np = Ribasim.Model(toml_path).integrator.p\nu = ComponentVector(; storage = zeros(length(p.basin.node_id)))\n\nallocation_model = p.allocation.allocation_models[1]\nt = 0.0\npriority_idx = 1\n\nRibasim.set_flow!(p.graph, NodeID(:FlowBoundary, 1), NodeID(:Basin, 2), 1.0)\n\nRibasim.adjust_source_capacities!(allocation_model, p, priority_idx)\nRibasim.adjust_edge_capacities!(allocation_model, p, priority_idx)\nRibasim.set_objective_priority!(allocation_model, p, u, t, priority_idx)\n\nprintln(p.allocation.allocation_models[1].problem)\n\n\nMin F_abs_user_demand[UserDemand #3] + F_abs_user_demand[UserDemand #13] + F_abs_user_demand[UserDemand #6] + F_abs_basin[Basin #2] + F_abs_basin[Basin #12] + F_abs_basin[Basin #5]\nSubject to\n flow_conservation[Basin #2] : -F[(Basin #5, Basin #2)] + F[(Basin #2, Basin #5)] - F[(FlowBoundary #1, Basin #2)] + F[(Basin #2, UserDemand #3)] + F_basin_in[Basin #2] - F_basin_out[Basin #2] = 0\n flow_conservation[Basin #12] : F[(Basin #12, UserDemand #13)] - F[(TabulatedRatingCurve #7, Basin #12)] + F_basin_in[Basin #12] - F_basin_out[Basin #12] = 0\n flow_conservation[Basin #5] : F[(Basin #5, UserDemand #6)] + F[(Basin #5, Basin #2)] - F[(Basin #2, Basin #5)] + F[(Basin #5, TabulatedRatingCurve #7)] + F_basin_in[Basin #5] - F_basin_out[Basin #5] = 0\n abs_positive_user_demand[UserDemand #3] : -F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ -1.5\n abs_positive_user_demand[UserDemand #13] : -F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_positive_user_demand[UserDemand #6] : -F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n abs_negative_user_demand[UserDemand #3] : F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ 1.5\n abs_negative_user_demand[UserDemand #13] : F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_negative_user_demand[UserDemand #6] : F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n abs_positive_basin[Basin #2] : -F_basin_in[Basin #2] + F_abs_basin[Basin #2] ≥ 0\n abs_positive_basin[Basin #12] : -F_basin_in[Basin #12] + F_abs_basin[Basin #12] ≥ 0\n abs_positive_basin[Basin #5] : -F_basin_in[Basin #5] + F_abs_basin[Basin #5] ≥ 0\n abs_negative_basin[Basin #2] : F_basin_in[Basin #2] + F_abs_basin[Basin #2] ≥ 0\n abs_negative_basin[Basin #12] : F_basin_in[Basin #12] + F_abs_basin[Basin #12] ≥ 0\n abs_negative_basin[Basin #5] : F_basin_in[Basin #5] + F_abs_basin[Basin #5] ≥ 0\n source[(FlowBoundary #1, Basin #2)] : F[(FlowBoundary #1, Basin #2)] ≤ 1\n return_flow[UserDemand #13] : F[(UserDemand #13, Terminal #10)] ≤ 0\n fractional_flow[(TabulatedRatingCurve #7, Basin #12)] : -0.4 F[(Basin #5, TabulatedRatingCurve #7)] + F[(TabulatedRatingCurve #7, Basin #12)] ≤ 0\n basin_outflow[Basin #2] : F_basin_out[Basin #2] ≤ 0\n basin_outflow[Basin #12] : F_basin_out[Basin #12] ≤ 0\n basin_outflow[Basin #5] : F_basin_out[Basin #5] ≤ 0\n F[(TabulatedRatingCurve #7, Terminal #10)] ≥ 0\n F[(Basin #5, UserDemand #6)] ≥ 0\n F[(Basin #5, Basin #2)] ≥ 0\n F[(Basin #12, UserDemand #13)] ≥ 0\n F[(Basin #2, Basin #5)] ≥ 0\n F[(FlowBoundary #1, Basin #2)] ≥ 0\n F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0\n F[(Basin #2, UserDemand #3)] ≥ 0\n F[(UserDemand #13, Terminal #10)] ≥ 0\n F[(TabulatedRatingCurve #7, Basin #12)] ≥ 0\n F_basin_in[Basin #2] ≥ 0\n F_basin_in[Basin #12] ≥ 0\n F_basin_in[Basin #5] ≥ 0\n F_basin_out[Basin #2] ≥ 0\n F_basin_out[Basin #12] ≥ 0\n F_basin_out[Basin #5] ≥ 0",
+ "text": "5.1 Example\nThe following is an example of an optimization problem for the example shown here:\n\n\nCode\nusing Ribasim\nusing Ribasim: NodeID\nusing SQLite\nusing ComponentArrays: ComponentVector\n\ntoml_path = normpath(@__DIR__, \"../../generated_testmodels/allocation_example/ribasim.toml\")\np = Ribasim.Model(toml_path).integrator.p\nu = ComponentVector(; storage = zeros(length(p.basin.node_id)))\n\nallocation_model = p.allocation.allocation_models[1]\nt = 0.0\npriority_idx = 1\n\nRibasim.set_flow!(p.graph, NodeID(:FlowBoundary, 1), NodeID(:Basin, 2), 1.0)\n\nRibasim.adjust_capacities_edge!(allocation_model, p, priority_idx)\nRibasim.adjust_capacities_source!(allocation_model, p, priority_idx)\nRibasim.set_objective_priority!(allocation_model, p, u, t, priority_idx)\n\nprintln(p.allocation.allocation_models[1].problem)\n\n\nMin F_abs_user_demand[UserDemand #3] + F_abs_user_demand[UserDemand #13] + F_abs_user_demand[UserDemand #6]\nSubject to\n flow_conservation_basin[Basin #5] : F[(Basin #5, UserDemand #6)] + F[(Basin #5, Basin #2)] - F[(Basin #2, Basin #5)] + F[(Basin #5, TabulatedRatingCurve #7)] = 0\n flow_conservation_basin[Basin #2] : F[(Basin #2, UserDemand #3)] - F[(FlowBoundary #1, Basin #2)] - F[(Basin #5, Basin #2)] + F[(Basin #2, Basin #5)] = 0\n flow_conservation_basin[Basin #12] : F[(Basin #12, UserDemand #13)] - F[(TabulatedRatingCurve #7, Basin #12)] = 0\n abs_positive_user_demand[UserDemand #3] : -F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ -1.5\n abs_positive_user_demand[UserDemand #13] : -F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_positive_user_demand[UserDemand #6] : -F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n abs_negative_user_demand[UserDemand #3] : F[(Basin #2, UserDemand #3)] + F_abs_user_demand[UserDemand #3] ≥ 1.5\n abs_negative_user_demand[UserDemand #13] : F[(Basin #12, UserDemand #13)] + F_abs_user_demand[UserDemand #13] ≥ 0\n abs_negative_user_demand[UserDemand #6] : F[(Basin #5, UserDemand #6)] + F_abs_user_demand[UserDemand #6] ≥ 0\n source[(FlowBoundary #1, Basin #2)] : F[(FlowBoundary #1, Basin #2)] ≤ 1\n return_flow[UserDemand #13] : F[(UserDemand #13, Terminal #10)] ≤ 0\n fractional_flow[(TabulatedRatingCurve #7, Basin #12)] : F[(TabulatedRatingCurve #7, Basin #12)] - 0.4 F[(Basin #5, TabulatedRatingCurve #7)] ≤ 0\n F[(Basin #5, UserDemand #6)] ≥ 0\n F[(Basin #12, UserDemand #13)] ≥ 0\n F[(TabulatedRatingCurve #7, Terminal #10)] ≥ 0\n F[(UserDemand #13, Terminal #10)] ≥ 0\n F[(Basin #2, UserDemand #3)] ≥ 0\n F[(FlowBoundary #1, Basin #2)] ≥ 0\n F[(Basin #5, Basin #2)] ≥ 0\n F[(Basin #2, Basin #5)] ≥ 0\n F[(TabulatedRatingCurve #7, Basin #12)] ≥ 0\n F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0",
"crumbs": [
"Julia core",
"Allocation"
@@ -981,7 +999,7 @@
"href": "core/validation.html",
"title": "Validation",
"section": "",
- "text": "The tables below show the validation rules applied to the input to the Julia core before running the model.\n\n1 Connectivity\nIn 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.\n\n\nCode\nusing Ribasim\nusing DataFrames: DataFrame\nusing MarkdownTables\n\nnode_names_snake_case = Vector{Symbol}()\nnode_names_camel_case = Vector{Symbol}()\nfor (node_name, node_type) in zip(fieldnames(Ribasim.Parameters), fieldtypes(Ribasim.Parameters))\n if node_type <: Ribasim.AbstractParameterNode\n push!(node_names_snake_case, node_name)\n push!(node_names_camel_case, nameof(node_type))\n end\nend\n\nfunction to_symbol(b::Bool)::String\n return b ? \"✓\" : \"x\"\nend\n\n\ndf = DataFrame()\ndf[!, :downstream] = node_names_snake_case\n\nfor node_name in node_names_snake_case\n df[!, node_name] =\n [(to_symbol(node_name_ in Ribasim.neighbortypes(node_name))) for node_name_ in node_names_snake_case]\nend\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndownstream\nbasin\nlinear_resistance\nmanning_resistance\ntabulated_rating_curve\nfractional_flow\nlevel_boundary\nflow_boundary\npump\noutlet\nterminal\ndiscrete_control\npid_control\nuser_demand\n\n\n\n\nbasin\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nlinear_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\nmanning_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\ntabulated_rating_curve\n✓\nx\nx\nx\nx\nx\nx\nx\nx\nx\n✓\nx\nx\n\n\nfractional_flow\nx\nx\nx\n✓\nx\nx\n✓\n✓\n✓\nx\n✓\nx\n✓\n\n\nlevel_boundary\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nflow_boundary\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npump\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\noutlet\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\nterminal\nx\nx\nx\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\ndiscrete_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npid_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n✓\nx\nx\n\n\nuser_demand\n✓\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\n\n\n\n\n\n2 Neighbor amounts\nThe table below shows for each node type between which bounds the amount of in- and outneighbors must be, for both flow and control edges.\n\n\nCode\nflow_in_min = Vector{String}()\nflow_in_max = Vector{String}()\nflow_out_min = Vector{String}()\nflow_out_max = Vector{String}()\ncontrol_in_min = Vector{String}()\ncontrol_in_max = Vector{String}()\ncontrol_out_min = Vector{String}()\ncontrol_out_max = Vector{String}()\n\nfunction unbounded(i::Int)::String\n return i == typemax(Int) ? \"∞\" : string(i)\nend\n\nfor node_name in node_names_camel_case\n bounds_flow = Ribasim.n_neighbor_bounds_flow(node_name)\n push!(flow_in_min, string(bounds_flow.in_min))\n push!(flow_in_max, unbounded(bounds_flow.in_max))\n push!(flow_out_min, string(bounds_flow.out_min))\n push!(flow_out_max, unbounded(bounds_flow.out_max))\n\n bounds_control = Ribasim.n_neighbor_bounds_control(node_name)\n push!(control_in_min, string(bounds_control.in_min))\n push!(control_in_max, unbounded(bounds_control.in_max))\n push!(control_out_min, string(bounds_control.out_min))\n push!(control_out_max, unbounded(bounds_control.out_max))\n\nend\n\ndf = DataFrame(\n ;\n node_type = node_names_snake_case,\n flow_in_min,\n flow_in_max,\n flow_out_min,\n flow_out_max,\n control_in_min,\n control_in_max,\n control_out_min,\n control_out_max,\n)\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nnode_type\nflow_in_min\nflow_in_max\nflow_out_min\nflow_out_max\ncontrol_in_min\ncontrol_in_max\ncontrol_out_min\ncontrol_out_max\n\n\n\n\nbasin\n0\n∞\n0\n∞\n0\n1\n0\n∞\n\n\nlinear_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nmanning_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\ntabulated_rating_curve\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nfractional_flow\n1\n1\n1\n1\n0\n1\n0\n0\n\n\nlevel_boundary\n0\n∞\n0\n∞\n0\n0\n0\n0\n\n\nflow_boundary\n0\n0\n1\n∞\n0\n0\n0\n0\n\n\npump\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\noutlet\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nterminal\n1\n∞\n0\n0\n0\n0\n0\n0\n\n\ndiscrete_control\n0\n0\n0\n0\n0\n0\n1\n∞\n\n\npid_control\n0\n0\n0\n0\n0\n1\n1\n1\n\n\nuser_demand\n1\n1\n1\n1\n0\n0\n0\n0",
+ "text": "The tables below show the validation rules applied to the input to the Julia core before running the model.\n\n1 Connectivity\nIn 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.\n\n\nCode\nusing Ribasim\nusing DataFrames: DataFrame\nusing MarkdownTables\n\nnode_names_snake_case = Vector{Symbol}()\nnode_names_camel_case = Vector{Symbol}()\nfor (node_name, node_type) in zip(fieldnames(Ribasim.Parameters), fieldtypes(Ribasim.Parameters))\n if node_type <: Ribasim.AbstractParameterNode\n push!(node_names_snake_case, node_name)\n push!(node_names_camel_case, nameof(node_type))\n end\nend\n\nfunction to_symbol(b::Bool)::String\n return b ? \"✓\" : \"x\"\nend\n\n\ndf = DataFrame()\ndf[!, :downstream] = node_names_snake_case\n\nfor node_name in node_names_snake_case\n df[!, node_name] =\n [(to_symbol(node_name_ in Ribasim.neighbortypes(node_name))) for node_name_ in node_names_snake_case]\nend\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndownstream\nbasin\nlinear_resistance\nmanning_resistance\ntabulated_rating_curve\nfractional_flow\nlevel_boundary\nflow_boundary\npump\noutlet\nterminal\ndiscrete_control\npid_control\nuser_demand\n\n\n\n\nbasin\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nlinear_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\nmanning_resistance\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\ntabulated_rating_curve\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\nx\nx\n\n\nfractional_flow\nx\nx\nx\n✓\nx\nx\n✓\n✓\n✓\nx\n✓\nx\n✓\n\n\nlevel_boundary\nx\n✓\n✓\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\nflow_boundary\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npump\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\noutlet\n✓\nx\nx\nx\nx\n✓\nx\nx\nx\nx\n✓\n✓\nx\n\n\nterminal\nx\nx\nx\n✓\n✓\nx\n✓\n✓\n✓\nx\nx\nx\n✓\n\n\ndiscrete_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\npid_control\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n✓\nx\nx\n\n\nuser_demand\n✓\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\n\n\n\n\n\n\n\n2 Neighbor amounts\nThe table below shows for each node type between which bounds the amount of in- and outneighbors must be, for both flow and control edges.\n\n\nCode\nflow_in_min = Vector{String}()\nflow_in_max = Vector{String}()\nflow_out_min = Vector{String}()\nflow_out_max = Vector{String}()\ncontrol_in_min = Vector{String}()\ncontrol_in_max = Vector{String}()\ncontrol_out_min = Vector{String}()\ncontrol_out_max = Vector{String}()\n\nfunction unbounded(i::Int)::String\n return i == typemax(Int) ? \"∞\" : string(i)\nend\n\nfor node_name in node_names_camel_case\n bounds_flow = Ribasim.n_neighbor_bounds_flow(node_name)\n push!(flow_in_min, string(bounds_flow.in_min))\n push!(flow_in_max, unbounded(bounds_flow.in_max))\n push!(flow_out_min, string(bounds_flow.out_min))\n push!(flow_out_max, unbounded(bounds_flow.out_max))\n\n bounds_control = Ribasim.n_neighbor_bounds_control(node_name)\n push!(control_in_min, string(bounds_control.in_min))\n push!(control_in_max, unbounded(bounds_control.in_max))\n push!(control_out_min, string(bounds_control.out_min))\n push!(control_out_max, unbounded(bounds_control.out_max))\n\nend\n\ndf = DataFrame(\n ;\n node_type = node_names_snake_case,\n flow_in_min,\n flow_in_max,\n flow_out_min,\n flow_out_max,\n control_in_min,\n control_in_max,\n control_out_min,\n control_out_max,\n)\n\nmarkdown_table(df)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nnode_type\nflow_in_min\nflow_in_max\nflow_out_min\nflow_out_max\ncontrol_in_min\ncontrol_in_max\ncontrol_out_min\ncontrol_out_max\n\n\n\n\nbasin\n0\n∞\n0\n∞\n0\n1\n0\n∞\n\n\nlinear_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nmanning_resistance\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\ntabulated_rating_curve\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nfractional_flow\n1\n1\n1\n1\n0\n1\n0\n0\n\n\nlevel_boundary\n0\n∞\n0\n∞\n0\n0\n0\n0\n\n\nflow_boundary\n0\n0\n1\n∞\n0\n0\n0\n0\n\n\npump\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\noutlet\n1\n1\n1\n∞\n0\n1\n0\n0\n\n\nterminal\n1\n∞\n0\n0\n0\n0\n0\n0\n\n\ndiscrete_control\n0\n0\n0\n0\n0\n0\n1\n∞\n\n\npid_control\n0\n0\n0\n0\n0\n1\n1\n1\n\n\nuser_demand\n1\n1\n1\n1\n0\n0\n0\n0",
"crumbs": [
"Julia core",
"Validation"
@@ -1155,18 +1173,25 @@
"text": "1 nodes.outlet\nnodes.outlet"
},
{
- "objectID": "python/reference/nodes.fractional_flow.html",
- "href": "python/reference/nodes.fractional_flow.html",
- "title": "1 nodes.fractional_flow",
+ "objectID": "python/reference/nodes.level_demand.html",
+ "href": "python/reference/nodes.level_demand.html",
+ "title": "1 nodes.level_demand",
"section": "",
- "text": "1 nodes.fractional_flow\nnodes.fractional_flow"
+ "text": "1 nodes.level_demand\nnodes.level_demand"
},
{
- "objectID": "python/reference/nodes.terminal.html",
- "href": "python/reference/nodes.terminal.html",
- "title": "1 nodes.terminal",
+ "objectID": "python/reference/nodes.level_boundary.html",
+ "href": "python/reference/nodes.level_boundary.html",
+ "title": "1 nodes.level_boundary",
"section": "",
- "text": "1 nodes.terminal\nnodes.terminal"
+ "text": "1 nodes.level_boundary\nnodes.level_boundary"
+ },
+ {
+ "objectID": "python/reference/nodes.flow_demand.html",
+ "href": "python/reference/nodes.flow_demand.html",
+ "title": "1 nodes.flow_demand",
+ "section": "",
+ "text": "1 nodes.flow_demand\nnodes.flow_demand"
},
{
"objectID": "python/reference/nodes.pid_control.html",