Code
using Ribasim
@@ -607,27 +607,27 @@ println(p.allocation.allocation_models[1].problem)
Min F[(Basin #2, UserDemand #3)]² + F[(Basin #5, UserDemand #6)]²
+Min F[(Basin #5, UserDemand #6)]² + F[(Basin #2, UserDemand #3)]²
Subject to
F[(LinearResistance #4, Basin #5)] ≥ 0
F[(Basin #5, LinearResistance #4)] ≥ 0
- F[(UserDemand #3, Basin #2)] ≥ 0
+ F[(Basin #5, UserDemand #6)] ≥ 0
F[(UserDemand #6, Basin #5)] ≥ 0
- F[(Basin #2, UserDemand #3)] ≥ 0
- F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0
F[(Basin #2, LinearResistance #4)] ≥ 0
F[(LinearResistance #4, Basin #2)] ≥ 0
- F[(Basin #5, UserDemand #6)] ≥ 0
- F[(TabulatedRatingCurve #7, Terminal #8)] ≥ 0
+ F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0
+ F[(Basin #2, UserDemand #3)] ≥ 0
F[(FlowBoundary #1, Basin #2)] ≥ 0
- flow_conservation[Basin #5] : F[(LinearResistance #4, Basin #5)] - F[(Basin #5, LinearResistance #4)] + F[(UserDemand #6, Basin #5)] - F[(Basin #5, TabulatedRatingCurve #7)] - F[(Basin #5, UserDemand #6)] = 0
- flow_conservation[LinearResistance #4] : -F[(LinearResistance #4, Basin #5)] + F[(Basin #5, LinearResistance #4)] + F[(Basin #2, LinearResistance #4)] - F[(LinearResistance #4, Basin #2)] = 0
- flow_conservation[Terminal #8] : F[(TabulatedRatingCurve #7, Terminal #8)] = 0
- flow_conservation[Basin #2] : F[(UserDemand #3, Basin #2)] - F[(Basin #2, UserDemand #3)] - F[(Basin #2, LinearResistance #4)] + F[(LinearResistance #4, Basin #2)] + F[(FlowBoundary #1, Basin #2)] = 0
+ F[(UserDemand #3, Basin #2)] ≥ 0
+ F[(TabulatedRatingCurve #7, Terminal #8)] ≥ 0
flow_conservation[TabulatedRatingCurve #7] : F[(Basin #5, TabulatedRatingCurve #7)] - F[(TabulatedRatingCurve #7, Terminal #8)] = 0
+ flow_conservation[Basin #5] : F[(LinearResistance #4, Basin #5)] - F[(Basin #5, LinearResistance #4)] - F[(Basin #5, UserDemand #6)] + F[(UserDemand #6, Basin #5)] - F[(Basin #5, TabulatedRatingCurve #7)] = 0
+ flow_conservation[Basin #2] : -F[(Basin #2, LinearResistance #4)] + F[(LinearResistance #4, Basin #2)] - F[(Basin #2, UserDemand #3)] + F[(FlowBoundary #1, Basin #2)] + F[(UserDemand #3, Basin #2)] = 0
+ flow_conservation[Terminal #8] : F[(TabulatedRatingCurve #7, Terminal #8)] = 0
+ flow_conservation[LinearResistance #4] : -F[(LinearResistance #4, Basin #5)] + F[(Basin #5, LinearResistance #4)] + F[(Basin #2, LinearResistance #4)] - F[(LinearResistance #4, Basin #2)] = 0
source[(FlowBoundary #1, Basin #2)] : F[(FlowBoundary #1, Basin #2)] ≤ 172800
- source_user[UserDemand #6] : F[(UserDemand #6, Basin #5)] ≤ 0
source_user[UserDemand #3] : F[(UserDemand #3, Basin #2)] ≤ 0
+ source_user[UserDemand #6] : F[(UserDemand #6, Basin #5)] ≤ 0
1 Basic model wit
= 10 / 86400 # 10 m³/day
q = model.tabulated_rating_curve.add(
- tabulated_rating_curve4 8, Point(4.0, 0.0)),
+ Node(8, Point(3.0, -1.0)),
Node(
[
tabulated_rating_curve.Static(=[0.0, 1.0],
@@ -401,7 +401,7 @@ level1 Basic model wit
],
)= model.tabulated_rating_curve.add(
- tabulated_rating_curve8 4, Point(3.0, -1.0)),
+ Node(4, Point(4.0, 0.0)),
Node(
[
tabulated_rating_curve.Static(=[0.0, 1.0],
diff --git a/guide/examples_files/figure-html/cell-15-output-1.png b/guide/examples_files/figure-html/cell-15-output-1.png
index 0bff89610..27f0b48ee 100644
Binary files a/guide/examples_files/figure-html/cell-15-output-1.png and b/guide/examples_files/figure-html/cell-15-output-1.png differ
diff --git a/guide/examples_files/figure-html/cell-18-output-1.png b/guide/examples_files/figure-html/cell-18-output-1.png
index 1398c8375..76e96a45c 100644
Binary files a/guide/examples_files/figure-html/cell-18-output-1.png and b/guide/examples_files/figure-html/cell-18-output-1.png differ
diff --git a/guide/examples_files/figure-html/cell-19-output-1.png b/guide/examples_files/figure-html/cell-19-output-1.png
index f27278240..696a52df0 100644
Binary files a/guide/examples_files/figure-html/cell-19-output-1.png and b/guide/examples_files/figure-html/cell-19-output-1.png differ
diff --git a/guide/examples_files/figure-html/cell-56-output-1.png b/guide/examples_files/figure-html/cell-56-output-1.png
index 4dd26aa63..5a08ff5da 100644
Binary files a/guide/examples_files/figure-html/cell-56-output-1.png and b/guide/examples_files/figure-html/cell-56-output-1.png differ
diff --git a/guide/examples_files/figure-html/cell-57-output-2.png b/guide/examples_files/figure-html/cell-57-output-2.png
index cb96e6502..21fb09e0d 100644
Binary files a/guide/examples_files/figure-html/cell-57-output-2.png and b/guide/examples_files/figure-html/cell-57-output-2.png differ
diff --git a/guide/examples_files/figure-html/cell-68-output-1.png b/guide/examples_files/figure-html/cell-68-output-1.png
index 5c3059fa4..7a588082d 100644
Binary files a/guide/examples_files/figure-html/cell-68-output-1.png and b/guide/examples_files/figure-html/cell-68-output-1.png differ
diff --git a/reference/node/basin.html b/reference/node/basin.html
index 54f4474aa..3b783c351 100644
--- a/reference/node/basin.html
+++ b/reference/node/basin.html
@@ -832,7 +832,7 @@ level
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
diff --git a/reference/node/discrete-control.html b/reference/node/discrete-control.html
index ce9d172fb..c9fbb7f81 100644
--- a/reference/node/discrete-control.html
+++ b/reference/node/discrete-control.html
@@ -386,7 +386,7 @@ DiscreteControl
Set parameters of other nodes based on model state conditions (e.g. Basin level). The table below shows which parameters are controllable for a given node type.
-
+
Code
using Ribasim
diff --git a/reference/test-models.html b/reference/test-models.html
index 01642ccba..da1abd2b6 100644
--- a/reference/test-models.html
+++ b/reference/test-models.html
@@ -346,7 +346,7 @@ Test models
Ribasim developers use the following models in their testbench and in order to test new features.
-
+
Code
import ribasim_testmodels
diff --git a/reference/test-models_files/figure-html/cell-2-output-39.png b/reference/test-models_files/figure-html/cell-2-output-39.png
index cd690187d..8824681e6 100644
Binary files a/reference/test-models_files/figure-html/cell-2-output-39.png and b/reference/test-models_files/figure-html/cell-2-output-39.png differ
diff --git a/reference/validation.html b/reference/validation.html
index e8cebc624..af8623f8f 100644
--- a/reference/validation.html
+++ b/reference/validation.html
@@ -356,7 +356,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
@@ -706,7 +706,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/search.json b/search.json
index 5f233e2d1..01168a51c 100644
--- a/search.json
+++ b/search.json
@@ -99,7 +99,7 @@
"href": "concept/allocation.html#example",
"title": "Allocation",
"section": "4.4 Example",
- "text": "4.4 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, p), NodeID(:Basin, 2, p), 1.0)\nRibasim.set_objective_priority!(allocation_model, p, u, t, priority_idx)\nRibasim.set_initial_values!(allocation_model, p, u, t)\n\nprintln(p.allocation.allocation_models[1].problem)\n\n\nMin F[(Basin #2, UserDemand #3)]² + F[(Basin #5, UserDemand #6)]²\nSubject to\n F[(LinearResistance #4, Basin #5)] ≥ 0\n F[(Basin #5, LinearResistance #4)] ≥ 0\n F[(UserDemand #3, Basin #2)] ≥ 0\n F[(UserDemand #6, Basin #5)] ≥ 0\n F[(Basin #2, UserDemand #3)] ≥ 0\n F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0\n F[(Basin #2, LinearResistance #4)] ≥ 0\n F[(LinearResistance #4, Basin #2)] ≥ 0\n F[(Basin #5, UserDemand #6)] ≥ 0\n F[(TabulatedRatingCurve #7, Terminal #8)] ≥ 0\n F[(FlowBoundary #1, Basin #2)] ≥ 0\n flow_conservation[Basin #5] : F[(LinearResistance #4, Basin #5)] - F[(Basin #5, LinearResistance #4)] + F[(UserDemand #6, Basin #5)] - F[(Basin #5, TabulatedRatingCurve #7)] - F[(Basin #5, UserDemand #6)] = 0\n flow_conservation[LinearResistance #4] : -F[(LinearResistance #4, Basin #5)] + F[(Basin #5, LinearResistance #4)] + F[(Basin #2, LinearResistance #4)] - F[(LinearResistance #4, Basin #2)] = 0\n flow_conservation[Terminal #8] : F[(TabulatedRatingCurve #7, Terminal #8)] = 0\n flow_conservation[Basin #2] : F[(UserDemand #3, Basin #2)] - F[(Basin #2, UserDemand #3)] - F[(Basin #2, LinearResistance #4)] + F[(LinearResistance #4, Basin #2)] + F[(FlowBoundary #1, Basin #2)] = 0\n flow_conservation[TabulatedRatingCurve #7] : F[(Basin #5, TabulatedRatingCurve #7)] - F[(TabulatedRatingCurve #7, Terminal #8)] = 0\n source[(FlowBoundary #1, Basin #2)] : F[(FlowBoundary #1, Basin #2)] ≤ 172800\n source_user[UserDemand #6] : F[(UserDemand #6, Basin #5)] ≤ 0\n source_user[UserDemand #3] : F[(UserDemand #3, Basin #2)] ≤ 0",
+ "text": "4.4 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, p), NodeID(:Basin, 2, p), 1.0)\nRibasim.set_objective_priority!(allocation_model, p, u, t, priority_idx)\nRibasim.set_initial_values!(allocation_model, p, u, t)\n\nprintln(p.allocation.allocation_models[1].problem)\n\n\nMin F[(Basin #5, UserDemand #6)]² + F[(Basin #2, UserDemand #3)]²\nSubject to\n F[(LinearResistance #4, Basin #5)] ≥ 0\n F[(Basin #5, LinearResistance #4)] ≥ 0\n F[(Basin #5, UserDemand #6)] ≥ 0\n F[(UserDemand #6, Basin #5)] ≥ 0\n F[(Basin #2, LinearResistance #4)] ≥ 0\n F[(LinearResistance #4, Basin #2)] ≥ 0\n F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0\n F[(Basin #2, UserDemand #3)] ≥ 0\n F[(FlowBoundary #1, Basin #2)] ≥ 0\n F[(UserDemand #3, Basin #2)] ≥ 0\n F[(TabulatedRatingCurve #7, Terminal #8)] ≥ 0\n flow_conservation[TabulatedRatingCurve #7] : F[(Basin #5, TabulatedRatingCurve #7)] - F[(TabulatedRatingCurve #7, Terminal #8)] = 0\n flow_conservation[Basin #5] : F[(LinearResistance #4, Basin #5)] - F[(Basin #5, LinearResistance #4)] - F[(Basin #5, UserDemand #6)] + F[(UserDemand #6, Basin #5)] - F[(Basin #5, TabulatedRatingCurve #7)] = 0\n flow_conservation[Basin #2] : -F[(Basin #2, LinearResistance #4)] + F[(LinearResistance #4, Basin #2)] - F[(Basin #2, UserDemand #3)] + F[(FlowBoundary #1, Basin #2)] + F[(UserDemand #3, Basin #2)] = 0\n flow_conservation[Terminal #8] : F[(TabulatedRatingCurve #7, Terminal #8)] = 0\n flow_conservation[LinearResistance #4] : -F[(LinearResistance #4, Basin #5)] + F[(Basin #5, LinearResistance #4)] + F[(Basin #2, LinearResistance #4)] - F[(LinearResistance #4, Basin #2)] = 0\n source[(FlowBoundary #1, Basin #2)] : F[(FlowBoundary #1, Basin #2)] ≤ 172800\n source_user[UserDemand #3] : F[(UserDemand #3, Basin #2)] ≤ 0\n source_user[UserDemand #6] : F[(UserDemand #6, Basin #5)] ≤ 0",
"crumbs": [
"Concepts",
"Implementation",
@@ -167,7 +167,7 @@
"href": "guide/examples.html",
"title": "Examples",
"section": "",
- "text": "import shutil\nfrom pathlib import Path\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom ribasim import Allocation, Model, Node\nfrom ribasim.nodes import (\n basin,\n continuous_control,\n discrete_control,\n flow_boundary,\n level_boundary,\n level_demand,\n linear_resistance,\n manning_resistance,\n outlet,\n pid_control,\n pump,\n tabulated_rating_curve,\n user_demand,\n)\nfrom shapely.geometry import Point\n\n\ndatadir = Path(\"data\")\nshutil.rmtree(datadir, ignore_errors=True)\n\n\nmodel = Model(starttime=\"2020-01-01\", endtime=\"2021-01-01\", crs=\"EPSG:4326\")\n\nSetup the basins:\n\ntime = pd.date_range(model.starttime, model.endtime)\nday_of_year = time.day_of_year.to_numpy()\nseconds_per_day = 24 * 60 * 60\nevaporation = (\n (-1.0 * np.cos(day_of_year / 365.0 * 2 * np.pi) + 1.0) * 0.0025 / seconds_per_day\n)\nrng = np.random.default_rng(seed=0)\nprecipitation = (\n rng.lognormal(mean=-1.0, sigma=1.7, size=time.size) * 0.001 / seconds_per_day\n)\n\n# Convert steady forcing to m/s\n# 2 mm/d precipitation, 1 mm/d evaporation\n\nbasin_data = [\n basin.Profile(area=[0.01, 1000.0], level=[0.0, 1.0]),\n basin.Time(\n time=pd.date_range(model.starttime, model.endtime),\n drainage=0.0,\n potential_evaporation=evaporation,\n infiltration=0.0,\n precipitation=precipitation,\n ),\n basin.State(level=[1.4]),\n]\n\nbasin1 = model.basin.add(Node(1, Point(0.0, 0.0)), basin_data)\nbasin3 = model.basin.add(Node(3, Point(2.0, 0.0)), basin_data)\nbasin6 = model.basin.add(Node(6, Point(3.0, 2.0)), basin_data)\nbasin9 = model.basin.add(Node(9, Point(5.0, 0.0)), basin_data)\n\nSetup linear resistance:\n\nlinear_resistance10 = model.linear_resistance.add(\n Node(10, Point(6.0, 0.0)),\n [linear_resistance.Static(resistance=[5e3])],\n)\nlinear_resistance12 = model.linear_resistance.add(\n Node(12, Point(2.0, 1.0)),\n [linear_resistance.Static(resistance=[3600.0 * 24.0 / 100.0])],\n)\n\nSetup Manning resistance:\n\nmanning_resistance2 = model.manning_resistance.add(\n Node(2, Point(1.0, 0.0)),\n [\n manning_resistance.Static(\n length=[900], manning_n=[0.04], profile_width=[6.0], profile_slope=[3.0]\n )\n ],\n)\n\nSet up rating curve nodes:\n\nq = 10 / 86400 # 10 m³/day\ntabulated_rating_curve4 = model.tabulated_rating_curve.add(\n Node(8, Point(4.0, 0.0)),\n [\n tabulated_rating_curve.Static(\n level=[0.0, 1.0],\n flow_rate=[0.0, 0.6 * q],\n )\n ],\n)\ntabulated_rating_curve5 = model.tabulated_rating_curve.add(\n Node(5, Point(3.0, 1.0)),\n [\n tabulated_rating_curve.Static(\n level=[0.0, 1.0],\n flow_rate=[0.0, 0.3 * q],\n )\n ],\n)\ntabulated_rating_curve8 = model.tabulated_rating_curve.add(\n Node(4, Point(3.0, -1.0)),\n [\n tabulated_rating_curve.Static(\n level=[0.0, 1.0],\n flow_rate=[0.0, 0.1 * q],\n )\n ],\n)\n\nSetup pump:\n\npump7 = model.pump.add(Node(7, Point(4.0, 1.0)), [pump.Static(flow_rate=[0.5 / 3600])])\n\nSetup level boundary:\n\nlevel_boundary11 = model.level_boundary.add(\n Node(11, Point(2.0, 2.0)), [level_boundary.Static(level=[0.5])]\n)\nlevel_boundary17 = model.level_boundary.add(\n Node(17, Point(6.0, 1.0)), [level_boundary.Static(level=[1.5])]\n)\n\nSetup flow boundary:\n\nflow_boundary15 = model.flow_boundary.add(\n Node(15, Point(3.0, 3.0)), [flow_boundary.Static(flow_rate=[1e-4])]\n)\nflow_boundary16 = model.flow_boundary.add(\n Node(16, Point(0.0, 1.0)), [flow_boundary.Static(flow_rate=[1e-4])]\n)\n\nSetup terminal:\n\nterminal14 = model.terminal.add(Node(14, Point(3.0, -2.0)))\n\nSetup the edges:\n\nmodel.edge.add(basin1, manning_resistance2)\nmodel.edge.add(manning_resistance2, basin3)\nmodel.edge.add(\n basin3,\n tabulated_rating_curve8,\n)\nmodel.edge.add(\n basin3,\n tabulated_rating_curve5,\n)\nmodel.edge.add(\n basin3,\n tabulated_rating_curve4,\n)\nmodel.edge.add(tabulated_rating_curve5, basin6)\nmodel.edge.add(tabulated_rating_curve8, basin9)\nmodel.edge.add(\n tabulated_rating_curve4,\n terminal14,\n)\nmodel.edge.add(basin6, pump7)\nmodel.edge.add(pump7, basin9)\nmodel.edge.add(basin9, linear_resistance10)\nmodel.edge.add(level_boundary11, linear_resistance12)\nmodel.edge.add(linear_resistance12, basin3)\nmodel.edge.add(flow_boundary15, basin6)\nmodel.edge.add(flow_boundary16, basin1)\nmodel.edge.add(linear_resistance10, level_boundary17)\n\nLet’s take a look at the model:\n\nmodel.plot()\n\n\n\n\n\n\n\n\nWrite the model to a TOML and GeoPackage:\n\ntoml_path = datadir / \"basic/ribasim.toml\"\nmodel.write(toml_path)\n\nPosixPath('data/basic/ribasim.toml')\n\n\n\n\nNow run the model. You can open a terminal and run it from there. For example, to run the basic model, input:\nribasim basic/ribasim.toml\nFrom Python you can run it with:\nimport subprocess\nresult = subprocess.run([cli_path, toml_path], capture_output=True, encoding=\"utf-8\")\nprint(result.stderr)\nresult.check_returncode()\nWhere cli_path is a string with either the full path to the Ribasim executable, like r\"c:\\ribasim_windows\\ribasim\", or just \"ribasim\" in case you added the ribasim_windows folder to your PATH.\nThe print(result.stderr) ensures you see the same logging and error messages that you would see in the terminal. And result.check_returncode() will throw an error when the simulation was not successful.\nAfter running the model, read back the results:\n\ndf_basin = pd.read_feather(datadir / \"basic/results/basin.arrow\")\ndf_basin_wide = df_basin.pivot_table(\n index=\"time\", columns=\"node_id\", values=[\"storage\", \"level\"]\n)\nax = df_basin_wide[\"level\"].plot()\nax.set_ylabel(\"level [m]\");\n\n\n\n\n\n\n\n\n\ndf_flow = pd.read_feather(datadir / \"basic/results/flow.arrow\")\ndf_flow[\"edge\"] = list(zip(df_flow.from_node_id, df_flow.to_node_id))\ndf_flow[\"flow_m3d\"] = df_flow.flow_rate * 86400\nax = df_flow.pivot_table(index=\"time\", columns=\"edge\", values=\"flow_m3d\").plot()\nax.legend(bbox_to_anchor=(1.3, 1), title=\"Edge\")\nax.set_ylabel(\"flow [m³day⁻¹]\");",
+ "text": "import shutil\nfrom pathlib import Path\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom ribasim import Allocation, Model, Node\nfrom ribasim.nodes import (\n basin,\n continuous_control,\n discrete_control,\n flow_boundary,\n level_boundary,\n level_demand,\n linear_resistance,\n manning_resistance,\n outlet,\n pid_control,\n pump,\n tabulated_rating_curve,\n user_demand,\n)\nfrom shapely.geometry import Point\n\n\ndatadir = Path(\"data\")\nshutil.rmtree(datadir, ignore_errors=True)\n\n\nmodel = Model(starttime=\"2020-01-01\", endtime=\"2021-01-01\", crs=\"EPSG:4326\")\n\nSetup the basins:\n\ntime = pd.date_range(model.starttime, model.endtime)\nday_of_year = time.day_of_year.to_numpy()\nseconds_per_day = 24 * 60 * 60\nevaporation = (\n (-1.0 * np.cos(day_of_year / 365.0 * 2 * np.pi) + 1.0) * 0.0025 / seconds_per_day\n)\nrng = np.random.default_rng(seed=0)\nprecipitation = (\n rng.lognormal(mean=-1.0, sigma=1.7, size=time.size) * 0.001 / seconds_per_day\n)\n\n# Convert steady forcing to m/s\n# 2 mm/d precipitation, 1 mm/d evaporation\n\nbasin_data = [\n basin.Profile(area=[0.01, 1000.0], level=[0.0, 1.0]),\n basin.Time(\n time=pd.date_range(model.starttime, model.endtime),\n drainage=0.0,\n potential_evaporation=evaporation,\n infiltration=0.0,\n precipitation=precipitation,\n ),\n basin.State(level=[1.4]),\n]\n\nbasin1 = model.basin.add(Node(1, Point(0.0, 0.0)), basin_data)\nbasin3 = model.basin.add(Node(3, Point(2.0, 0.0)), basin_data)\nbasin6 = model.basin.add(Node(6, Point(3.0, 2.0)), basin_data)\nbasin9 = model.basin.add(Node(9, Point(5.0, 0.0)), basin_data)\n\nSetup linear resistance:\n\nlinear_resistance10 = model.linear_resistance.add(\n Node(10, Point(6.0, 0.0)),\n [linear_resistance.Static(resistance=[5e3])],\n)\nlinear_resistance12 = model.linear_resistance.add(\n Node(12, Point(2.0, 1.0)),\n [linear_resistance.Static(resistance=[3600.0 * 24.0 / 100.0])],\n)\n\nSetup Manning resistance:\n\nmanning_resistance2 = model.manning_resistance.add(\n Node(2, Point(1.0, 0.0)),\n [\n manning_resistance.Static(\n length=[900], manning_n=[0.04], profile_width=[6.0], profile_slope=[3.0]\n )\n ],\n)\n\nSet up rating curve nodes:\n\nq = 10 / 86400 # 10 m³/day\ntabulated_rating_curve4 = model.tabulated_rating_curve.add(\n Node(8, Point(3.0, -1.0)),\n [\n tabulated_rating_curve.Static(\n level=[0.0, 1.0],\n flow_rate=[0.0, 0.6 * q],\n )\n ],\n)\ntabulated_rating_curve5 = model.tabulated_rating_curve.add(\n Node(5, Point(3.0, 1.0)),\n [\n tabulated_rating_curve.Static(\n level=[0.0, 1.0],\n flow_rate=[0.0, 0.3 * q],\n )\n ],\n)\ntabulated_rating_curve8 = model.tabulated_rating_curve.add(\n Node(4, Point(4.0, 0.0)),\n [\n tabulated_rating_curve.Static(\n level=[0.0, 1.0],\n flow_rate=[0.0, 0.1 * q],\n )\n ],\n)\n\nSetup pump:\n\npump7 = model.pump.add(Node(7, Point(4.0, 1.0)), [pump.Static(flow_rate=[0.5 / 3600])])\n\nSetup level boundary:\n\nlevel_boundary11 = model.level_boundary.add(\n Node(11, Point(2.0, 2.0)), [level_boundary.Static(level=[0.5])]\n)\nlevel_boundary17 = model.level_boundary.add(\n Node(17, Point(6.0, 1.0)), [level_boundary.Static(level=[1.5])]\n)\n\nSetup flow boundary:\n\nflow_boundary15 = model.flow_boundary.add(\n Node(15, Point(3.0, 3.0)), [flow_boundary.Static(flow_rate=[1e-4])]\n)\nflow_boundary16 = model.flow_boundary.add(\n Node(16, Point(0.0, 1.0)), [flow_boundary.Static(flow_rate=[1e-4])]\n)\n\nSetup terminal:\n\nterminal14 = model.terminal.add(Node(14, Point(3.0, -2.0)))\n\nSetup the edges:\n\nmodel.edge.add(basin1, manning_resistance2)\nmodel.edge.add(manning_resistance2, basin3)\nmodel.edge.add(\n basin3,\n tabulated_rating_curve8,\n)\nmodel.edge.add(\n basin3,\n tabulated_rating_curve5,\n)\nmodel.edge.add(\n basin3,\n tabulated_rating_curve4,\n)\nmodel.edge.add(tabulated_rating_curve5, basin6)\nmodel.edge.add(tabulated_rating_curve8, basin9)\nmodel.edge.add(\n tabulated_rating_curve4,\n terminal14,\n)\nmodel.edge.add(basin6, pump7)\nmodel.edge.add(pump7, basin9)\nmodel.edge.add(basin9, linear_resistance10)\nmodel.edge.add(level_boundary11, linear_resistance12)\nmodel.edge.add(linear_resistance12, basin3)\nmodel.edge.add(flow_boundary15, basin6)\nmodel.edge.add(flow_boundary16, basin1)\nmodel.edge.add(linear_resistance10, level_boundary17)\n\nLet’s take a look at the model:\n\nmodel.plot()\n\n\n\n\n\n\n\n\nWrite the model to a TOML and GeoPackage:\n\ntoml_path = datadir / \"basic/ribasim.toml\"\nmodel.write(toml_path)\n\nPosixPath('data/basic/ribasim.toml')\n\n\n\n\nNow run the model. You can open a terminal and run it from there. For example, to run the basic model, input:\nribasim basic/ribasim.toml\nFrom Python you can run it with:\nimport subprocess\nresult = subprocess.run([cli_path, toml_path], capture_output=True, encoding=\"utf-8\")\nprint(result.stderr)\nresult.check_returncode()\nWhere cli_path is a string with either the full path to the Ribasim executable, like r\"c:\\ribasim_windows\\ribasim\", or just \"ribasim\" in case you added the ribasim_windows folder to your PATH.\nThe print(result.stderr) ensures you see the same logging and error messages that you would see in the terminal. And result.check_returncode() will throw an error when the simulation was not successful.\nAfter running the model, read back the results:\n\ndf_basin = pd.read_feather(datadir / \"basic/results/basin.arrow\")\ndf_basin_wide = df_basin.pivot_table(\n index=\"time\", columns=\"node_id\", values=[\"storage\", \"level\"]\n)\nax = df_basin_wide[\"level\"].plot()\nax.set_ylabel(\"level [m]\");\n\n\n\n\n\n\n\n\n\ndf_flow = pd.read_feather(datadir / \"basic/results/flow.arrow\")\ndf_flow[\"edge\"] = list(zip(df_flow.from_node_id, df_flow.to_node_id))\ndf_flow[\"flow_m3d\"] = df_flow.flow_rate * 86400\nax = df_flow.pivot_table(index=\"time\", columns=\"edge\", values=\"flow_m3d\").plot()\nax.legend(bbox_to_anchor=(1.3, 1), title=\"Edge\")\nax.set_ylabel(\"flow [m³day⁻¹]\");",
"crumbs": [
"How-to guides",
"Examples"
flow_in_min
= 10 / 86400 # 10 m³/day
q = model.tabulated_rating_curve.add(
- tabulated_rating_curve4 8, Point(4.0, 0.0)),
+ Node(8, Point(3.0, -1.0)),
Node(
[
tabulated_rating_curve.Static(=[0.0, 1.0],
@@ -401,7 +401,7 @@ level1 Basic model wit
],
)= model.tabulated_rating_curve.add(
- tabulated_rating_curve8 4, Point(3.0, -1.0)),
+ Node(4, Point(4.0, 0.0)),
Node(
[
tabulated_rating_curve.Static(=[0.0, 1.0],
diff --git a/guide/examples_files/figure-html/cell-15-output-1.png b/guide/examples_files/figure-html/cell-15-output-1.png
index 0bff89610..27f0b48ee 100644
Binary files a/guide/examples_files/figure-html/cell-15-output-1.png and b/guide/examples_files/figure-html/cell-15-output-1.png differ
diff --git a/guide/examples_files/figure-html/cell-18-output-1.png b/guide/examples_files/figure-html/cell-18-output-1.png
index 1398c8375..76e96a45c 100644
Binary files a/guide/examples_files/figure-html/cell-18-output-1.png and b/guide/examples_files/figure-html/cell-18-output-1.png differ
diff --git a/guide/examples_files/figure-html/cell-19-output-1.png b/guide/examples_files/figure-html/cell-19-output-1.png
index f27278240..696a52df0 100644
Binary files a/guide/examples_files/figure-html/cell-19-output-1.png and b/guide/examples_files/figure-html/cell-19-output-1.png differ
diff --git a/guide/examples_files/figure-html/cell-56-output-1.png b/guide/examples_files/figure-html/cell-56-output-1.png
index 4dd26aa63..5a08ff5da 100644
Binary files a/guide/examples_files/figure-html/cell-56-output-1.png and b/guide/examples_files/figure-html/cell-56-output-1.png differ
diff --git a/guide/examples_files/figure-html/cell-57-output-2.png b/guide/examples_files/figure-html/cell-57-output-2.png
index cb96e6502..21fb09e0d 100644
Binary files a/guide/examples_files/figure-html/cell-57-output-2.png and b/guide/examples_files/figure-html/cell-57-output-2.png differ
diff --git a/guide/examples_files/figure-html/cell-68-output-1.png b/guide/examples_files/figure-html/cell-68-output-1.png
index 5c3059fa4..7a588082d 100644
Binary files a/guide/examples_files/figure-html/cell-68-output-1.png and b/guide/examples_files/figure-html/cell-68-output-1.png differ
diff --git a/reference/node/basin.html b/reference/node/basin.html
index 54f4474aa..3b783c351 100644
--- a/reference/node/basin.html
+++ b/reference/node/basin.html
@@ -832,7 +832,7 @@ level
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
diff --git a/reference/node/discrete-control.html b/reference/node/discrete-control.html
index ce9d172fb..c9fbb7f81 100644
--- a/reference/node/discrete-control.html
+++ b/reference/node/discrete-control.html
@@ -386,7 +386,7 @@ DiscreteControl
Set parameters of other nodes based on model state conditions (e.g. Basin level). The table below shows which parameters are controllable for a given node type.
-
+
Code
using Ribasim
diff --git a/reference/test-models.html b/reference/test-models.html
index 01642ccba..da1abd2b6 100644
--- a/reference/test-models.html
+++ b/reference/test-models.html
@@ -346,7 +346,7 @@ Test models
Ribasim developers use the following models in their testbench and in order to test new features.
-
+
Code
import ribasim_testmodels
diff --git a/reference/test-models_files/figure-html/cell-2-output-39.png b/reference/test-models_files/figure-html/cell-2-output-39.png
index cd690187d..8824681e6 100644
Binary files a/reference/test-models_files/figure-html/cell-2-output-39.png and b/reference/test-models_files/figure-html/cell-2-output-39.png differ
diff --git a/reference/validation.html b/reference/validation.html
index e8cebc624..af8623f8f 100644
--- a/reference/validation.html
+++ b/reference/validation.html
@@ -356,7 +356,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
@@ -706,7 +706,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/search.json b/search.json
index 5f233e2d1..01168a51c 100644
--- a/search.json
+++ b/search.json
@@ -99,7 +99,7 @@
"href": "concept/allocation.html#example",
"title": "Allocation",
"section": "4.4 Example",
- "text": "4.4 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, p), NodeID(:Basin, 2, p), 1.0)\nRibasim.set_objective_priority!(allocation_model, p, u, t, priority_idx)\nRibasim.set_initial_values!(allocation_model, p, u, t)\n\nprintln(p.allocation.allocation_models[1].problem)\n\n\nMin F[(Basin #2, UserDemand #3)]² + F[(Basin #5, UserDemand #6)]²\nSubject to\n F[(LinearResistance #4, Basin #5)] ≥ 0\n F[(Basin #5, LinearResistance #4)] ≥ 0\n F[(UserDemand #3, Basin #2)] ≥ 0\n F[(UserDemand #6, Basin #5)] ≥ 0\n F[(Basin #2, UserDemand #3)] ≥ 0\n F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0\n F[(Basin #2, LinearResistance #4)] ≥ 0\n F[(LinearResistance #4, Basin #2)] ≥ 0\n F[(Basin #5, UserDemand #6)] ≥ 0\n F[(TabulatedRatingCurve #7, Terminal #8)] ≥ 0\n F[(FlowBoundary #1, Basin #2)] ≥ 0\n flow_conservation[Basin #5] : F[(LinearResistance #4, Basin #5)] - F[(Basin #5, LinearResistance #4)] + F[(UserDemand #6, Basin #5)] - F[(Basin #5, TabulatedRatingCurve #7)] - F[(Basin #5, UserDemand #6)] = 0\n flow_conservation[LinearResistance #4] : -F[(LinearResistance #4, Basin #5)] + F[(Basin #5, LinearResistance #4)] + F[(Basin #2, LinearResistance #4)] - F[(LinearResistance #4, Basin #2)] = 0\n flow_conservation[Terminal #8] : F[(TabulatedRatingCurve #7, Terminal #8)] = 0\n flow_conservation[Basin #2] : F[(UserDemand #3, Basin #2)] - F[(Basin #2, UserDemand #3)] - F[(Basin #2, LinearResistance #4)] + F[(LinearResistance #4, Basin #2)] + F[(FlowBoundary #1, Basin #2)] = 0\n flow_conservation[TabulatedRatingCurve #7] : F[(Basin #5, TabulatedRatingCurve #7)] - F[(TabulatedRatingCurve #7, Terminal #8)] = 0\n source[(FlowBoundary #1, Basin #2)] : F[(FlowBoundary #1, Basin #2)] ≤ 172800\n source_user[UserDemand #6] : F[(UserDemand #6, Basin #5)] ≤ 0\n source_user[UserDemand #3] : F[(UserDemand #3, Basin #2)] ≤ 0",
+ "text": "4.4 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, p), NodeID(:Basin, 2, p), 1.0)\nRibasim.set_objective_priority!(allocation_model, p, u, t, priority_idx)\nRibasim.set_initial_values!(allocation_model, p, u, t)\n\nprintln(p.allocation.allocation_models[1].problem)\n\n\nMin F[(Basin #5, UserDemand #6)]² + F[(Basin #2, UserDemand #3)]²\nSubject to\n F[(LinearResistance #4, Basin #5)] ≥ 0\n F[(Basin #5, LinearResistance #4)] ≥ 0\n F[(Basin #5, UserDemand #6)] ≥ 0\n F[(UserDemand #6, Basin #5)] ≥ 0\n F[(Basin #2, LinearResistance #4)] ≥ 0\n F[(LinearResistance #4, Basin #2)] ≥ 0\n F[(Basin #5, TabulatedRatingCurve #7)] ≥ 0\n F[(Basin #2, UserDemand #3)] ≥ 0\n F[(FlowBoundary #1, Basin #2)] ≥ 0\n F[(UserDemand #3, Basin #2)] ≥ 0\n F[(TabulatedRatingCurve #7, Terminal #8)] ≥ 0\n flow_conservation[TabulatedRatingCurve #7] : F[(Basin #5, TabulatedRatingCurve #7)] - F[(TabulatedRatingCurve #7, Terminal #8)] = 0\n flow_conservation[Basin #5] : F[(LinearResistance #4, Basin #5)] - F[(Basin #5, LinearResistance #4)] - F[(Basin #5, UserDemand #6)] + F[(UserDemand #6, Basin #5)] - F[(Basin #5, TabulatedRatingCurve #7)] = 0\n flow_conservation[Basin #2] : -F[(Basin #2, LinearResistance #4)] + F[(LinearResistance #4, Basin #2)] - F[(Basin #2, UserDemand #3)] + F[(FlowBoundary #1, Basin #2)] + F[(UserDemand #3, Basin #2)] = 0\n flow_conservation[Terminal #8] : F[(TabulatedRatingCurve #7, Terminal #8)] = 0\n flow_conservation[LinearResistance #4] : -F[(LinearResistance #4, Basin #5)] + F[(Basin #5, LinearResistance #4)] + F[(Basin #2, LinearResistance #4)] - F[(LinearResistance #4, Basin #2)] = 0\n source[(FlowBoundary #1, Basin #2)] : F[(FlowBoundary #1, Basin #2)] ≤ 172800\n source_user[UserDemand #3] : F[(UserDemand #3, Basin #2)] ≤ 0\n source_user[UserDemand #6] : F[(UserDemand #6, Basin #5)] ≤ 0",
"crumbs": [
"Concepts",
"Implementation",
@@ -167,7 +167,7 @@
"href": "guide/examples.html",
"title": "Examples",
"section": "",
- "text": "import shutil\nfrom pathlib import Path\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom ribasim import Allocation, Model, Node\nfrom ribasim.nodes import (\n basin,\n continuous_control,\n discrete_control,\n flow_boundary,\n level_boundary,\n level_demand,\n linear_resistance,\n manning_resistance,\n outlet,\n pid_control,\n pump,\n tabulated_rating_curve,\n user_demand,\n)\nfrom shapely.geometry import Point\n\n\ndatadir = Path(\"data\")\nshutil.rmtree(datadir, ignore_errors=True)\n\n\nmodel = Model(starttime=\"2020-01-01\", endtime=\"2021-01-01\", crs=\"EPSG:4326\")\n\nSetup the basins:\n\ntime = pd.date_range(model.starttime, model.endtime)\nday_of_year = time.day_of_year.to_numpy()\nseconds_per_day = 24 * 60 * 60\nevaporation = (\n (-1.0 * np.cos(day_of_year / 365.0 * 2 * np.pi) + 1.0) * 0.0025 / seconds_per_day\n)\nrng = np.random.default_rng(seed=0)\nprecipitation = (\n rng.lognormal(mean=-1.0, sigma=1.7, size=time.size) * 0.001 / seconds_per_day\n)\n\n# Convert steady forcing to m/s\n# 2 mm/d precipitation, 1 mm/d evaporation\n\nbasin_data = [\n basin.Profile(area=[0.01, 1000.0], level=[0.0, 1.0]),\n basin.Time(\n time=pd.date_range(model.starttime, model.endtime),\n drainage=0.0,\n potential_evaporation=evaporation,\n infiltration=0.0,\n precipitation=precipitation,\n ),\n basin.State(level=[1.4]),\n]\n\nbasin1 = model.basin.add(Node(1, Point(0.0, 0.0)), basin_data)\nbasin3 = model.basin.add(Node(3, Point(2.0, 0.0)), basin_data)\nbasin6 = model.basin.add(Node(6, Point(3.0, 2.0)), basin_data)\nbasin9 = model.basin.add(Node(9, Point(5.0, 0.0)), basin_data)\n\nSetup linear resistance:\n\nlinear_resistance10 = model.linear_resistance.add(\n Node(10, Point(6.0, 0.0)),\n [linear_resistance.Static(resistance=[5e3])],\n)\nlinear_resistance12 = model.linear_resistance.add(\n Node(12, Point(2.0, 1.0)),\n [linear_resistance.Static(resistance=[3600.0 * 24.0 / 100.0])],\n)\n\nSetup Manning resistance:\n\nmanning_resistance2 = model.manning_resistance.add(\n Node(2, Point(1.0, 0.0)),\n [\n manning_resistance.Static(\n length=[900], manning_n=[0.04], profile_width=[6.0], profile_slope=[3.0]\n )\n ],\n)\n\nSet up rating curve nodes:\n\nq = 10 / 86400 # 10 m³/day\ntabulated_rating_curve4 = model.tabulated_rating_curve.add(\n Node(8, Point(4.0, 0.0)),\n [\n tabulated_rating_curve.Static(\n level=[0.0, 1.0],\n flow_rate=[0.0, 0.6 * q],\n )\n ],\n)\ntabulated_rating_curve5 = model.tabulated_rating_curve.add(\n Node(5, Point(3.0, 1.0)),\n [\n tabulated_rating_curve.Static(\n level=[0.0, 1.0],\n flow_rate=[0.0, 0.3 * q],\n )\n ],\n)\ntabulated_rating_curve8 = model.tabulated_rating_curve.add(\n Node(4, Point(3.0, -1.0)),\n [\n tabulated_rating_curve.Static(\n level=[0.0, 1.0],\n flow_rate=[0.0, 0.1 * q],\n )\n ],\n)\n\nSetup pump:\n\npump7 = model.pump.add(Node(7, Point(4.0, 1.0)), [pump.Static(flow_rate=[0.5 / 3600])])\n\nSetup level boundary:\n\nlevel_boundary11 = model.level_boundary.add(\n Node(11, Point(2.0, 2.0)), [level_boundary.Static(level=[0.5])]\n)\nlevel_boundary17 = model.level_boundary.add(\n Node(17, Point(6.0, 1.0)), [level_boundary.Static(level=[1.5])]\n)\n\nSetup flow boundary:\n\nflow_boundary15 = model.flow_boundary.add(\n Node(15, Point(3.0, 3.0)), [flow_boundary.Static(flow_rate=[1e-4])]\n)\nflow_boundary16 = model.flow_boundary.add(\n Node(16, Point(0.0, 1.0)), [flow_boundary.Static(flow_rate=[1e-4])]\n)\n\nSetup terminal:\n\nterminal14 = model.terminal.add(Node(14, Point(3.0, -2.0)))\n\nSetup the edges:\n\nmodel.edge.add(basin1, manning_resistance2)\nmodel.edge.add(manning_resistance2, basin3)\nmodel.edge.add(\n basin3,\n tabulated_rating_curve8,\n)\nmodel.edge.add(\n basin3,\n tabulated_rating_curve5,\n)\nmodel.edge.add(\n basin3,\n tabulated_rating_curve4,\n)\nmodel.edge.add(tabulated_rating_curve5, basin6)\nmodel.edge.add(tabulated_rating_curve8, basin9)\nmodel.edge.add(\n tabulated_rating_curve4,\n terminal14,\n)\nmodel.edge.add(basin6, pump7)\nmodel.edge.add(pump7, basin9)\nmodel.edge.add(basin9, linear_resistance10)\nmodel.edge.add(level_boundary11, linear_resistance12)\nmodel.edge.add(linear_resistance12, basin3)\nmodel.edge.add(flow_boundary15, basin6)\nmodel.edge.add(flow_boundary16, basin1)\nmodel.edge.add(linear_resistance10, level_boundary17)\n\nLet’s take a look at the model:\n\nmodel.plot()\n\n\n\n\n\n\n\n\nWrite the model to a TOML and GeoPackage:\n\ntoml_path = datadir / \"basic/ribasim.toml\"\nmodel.write(toml_path)\n\nPosixPath('data/basic/ribasim.toml')\n\n\n\n\nNow run the model. You can open a terminal and run it from there. For example, to run the basic model, input:\nribasim basic/ribasim.toml\nFrom Python you can run it with:\nimport subprocess\nresult = subprocess.run([cli_path, toml_path], capture_output=True, encoding=\"utf-8\")\nprint(result.stderr)\nresult.check_returncode()\nWhere cli_path is a string with either the full path to the Ribasim executable, like r\"c:\\ribasim_windows\\ribasim\", or just \"ribasim\" in case you added the ribasim_windows folder to your PATH.\nThe print(result.stderr) ensures you see the same logging and error messages that you would see in the terminal. And result.check_returncode() will throw an error when the simulation was not successful.\nAfter running the model, read back the results:\n\ndf_basin = pd.read_feather(datadir / \"basic/results/basin.arrow\")\ndf_basin_wide = df_basin.pivot_table(\n index=\"time\", columns=\"node_id\", values=[\"storage\", \"level\"]\n)\nax = df_basin_wide[\"level\"].plot()\nax.set_ylabel(\"level [m]\");\n\n\n\n\n\n\n\n\n\ndf_flow = pd.read_feather(datadir / \"basic/results/flow.arrow\")\ndf_flow[\"edge\"] = list(zip(df_flow.from_node_id, df_flow.to_node_id))\ndf_flow[\"flow_m3d\"] = df_flow.flow_rate * 86400\nax = df_flow.pivot_table(index=\"time\", columns=\"edge\", values=\"flow_m3d\").plot()\nax.legend(bbox_to_anchor=(1.3, 1), title=\"Edge\")\nax.set_ylabel(\"flow [m³day⁻¹]\");",
+ "text": "import shutil\nfrom pathlib import Path\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom ribasim import Allocation, Model, Node\nfrom ribasim.nodes import (\n basin,\n continuous_control,\n discrete_control,\n flow_boundary,\n level_boundary,\n level_demand,\n linear_resistance,\n manning_resistance,\n outlet,\n pid_control,\n pump,\n tabulated_rating_curve,\n user_demand,\n)\nfrom shapely.geometry import Point\n\n\ndatadir = Path(\"data\")\nshutil.rmtree(datadir, ignore_errors=True)\n\n\nmodel = Model(starttime=\"2020-01-01\", endtime=\"2021-01-01\", crs=\"EPSG:4326\")\n\nSetup the basins:\n\ntime = pd.date_range(model.starttime, model.endtime)\nday_of_year = time.day_of_year.to_numpy()\nseconds_per_day = 24 * 60 * 60\nevaporation = (\n (-1.0 * np.cos(day_of_year / 365.0 * 2 * np.pi) + 1.0) * 0.0025 / seconds_per_day\n)\nrng = np.random.default_rng(seed=0)\nprecipitation = (\n rng.lognormal(mean=-1.0, sigma=1.7, size=time.size) * 0.001 / seconds_per_day\n)\n\n# Convert steady forcing to m/s\n# 2 mm/d precipitation, 1 mm/d evaporation\n\nbasin_data = [\n basin.Profile(area=[0.01, 1000.0], level=[0.0, 1.0]),\n basin.Time(\n time=pd.date_range(model.starttime, model.endtime),\n drainage=0.0,\n potential_evaporation=evaporation,\n infiltration=0.0,\n precipitation=precipitation,\n ),\n basin.State(level=[1.4]),\n]\n\nbasin1 = model.basin.add(Node(1, Point(0.0, 0.0)), basin_data)\nbasin3 = model.basin.add(Node(3, Point(2.0, 0.0)), basin_data)\nbasin6 = model.basin.add(Node(6, Point(3.0, 2.0)), basin_data)\nbasin9 = model.basin.add(Node(9, Point(5.0, 0.0)), basin_data)\n\nSetup linear resistance:\n\nlinear_resistance10 = model.linear_resistance.add(\n Node(10, Point(6.0, 0.0)),\n [linear_resistance.Static(resistance=[5e3])],\n)\nlinear_resistance12 = model.linear_resistance.add(\n Node(12, Point(2.0, 1.0)),\n [linear_resistance.Static(resistance=[3600.0 * 24.0 / 100.0])],\n)\n\nSetup Manning resistance:\n\nmanning_resistance2 = model.manning_resistance.add(\n Node(2, Point(1.0, 0.0)),\n [\n manning_resistance.Static(\n length=[900], manning_n=[0.04], profile_width=[6.0], profile_slope=[3.0]\n )\n ],\n)\n\nSet up rating curve nodes:\n\nq = 10 / 86400 # 10 m³/day\ntabulated_rating_curve4 = model.tabulated_rating_curve.add(\n Node(8, Point(3.0, -1.0)),\n [\n tabulated_rating_curve.Static(\n level=[0.0, 1.0],\n flow_rate=[0.0, 0.6 * q],\n )\n ],\n)\ntabulated_rating_curve5 = model.tabulated_rating_curve.add(\n Node(5, Point(3.0, 1.0)),\n [\n tabulated_rating_curve.Static(\n level=[0.0, 1.0],\n flow_rate=[0.0, 0.3 * q],\n )\n ],\n)\ntabulated_rating_curve8 = model.tabulated_rating_curve.add(\n Node(4, Point(4.0, 0.0)),\n [\n tabulated_rating_curve.Static(\n level=[0.0, 1.0],\n flow_rate=[0.0, 0.1 * q],\n )\n ],\n)\n\nSetup pump:\n\npump7 = model.pump.add(Node(7, Point(4.0, 1.0)), [pump.Static(flow_rate=[0.5 / 3600])])\n\nSetup level boundary:\n\nlevel_boundary11 = model.level_boundary.add(\n Node(11, Point(2.0, 2.0)), [level_boundary.Static(level=[0.5])]\n)\nlevel_boundary17 = model.level_boundary.add(\n Node(17, Point(6.0, 1.0)), [level_boundary.Static(level=[1.5])]\n)\n\nSetup flow boundary:\n\nflow_boundary15 = model.flow_boundary.add(\n Node(15, Point(3.0, 3.0)), [flow_boundary.Static(flow_rate=[1e-4])]\n)\nflow_boundary16 = model.flow_boundary.add(\n Node(16, Point(0.0, 1.0)), [flow_boundary.Static(flow_rate=[1e-4])]\n)\n\nSetup terminal:\n\nterminal14 = model.terminal.add(Node(14, Point(3.0, -2.0)))\n\nSetup the edges:\n\nmodel.edge.add(basin1, manning_resistance2)\nmodel.edge.add(manning_resistance2, basin3)\nmodel.edge.add(\n basin3,\n tabulated_rating_curve8,\n)\nmodel.edge.add(\n basin3,\n tabulated_rating_curve5,\n)\nmodel.edge.add(\n basin3,\n tabulated_rating_curve4,\n)\nmodel.edge.add(tabulated_rating_curve5, basin6)\nmodel.edge.add(tabulated_rating_curve8, basin9)\nmodel.edge.add(\n tabulated_rating_curve4,\n terminal14,\n)\nmodel.edge.add(basin6, pump7)\nmodel.edge.add(pump7, basin9)\nmodel.edge.add(basin9, linear_resistance10)\nmodel.edge.add(level_boundary11, linear_resistance12)\nmodel.edge.add(linear_resistance12, basin3)\nmodel.edge.add(flow_boundary15, basin6)\nmodel.edge.add(flow_boundary16, basin1)\nmodel.edge.add(linear_resistance10, level_boundary17)\n\nLet’s take a look at the model:\n\nmodel.plot()\n\n\n\n\n\n\n\n\nWrite the model to a TOML and GeoPackage:\n\ntoml_path = datadir / \"basic/ribasim.toml\"\nmodel.write(toml_path)\n\nPosixPath('data/basic/ribasim.toml')\n\n\n\n\nNow run the model. You can open a terminal and run it from there. For example, to run the basic model, input:\nribasim basic/ribasim.toml\nFrom Python you can run it with:\nimport subprocess\nresult = subprocess.run([cli_path, toml_path], capture_output=True, encoding=\"utf-8\")\nprint(result.stderr)\nresult.check_returncode()\nWhere cli_path is a string with either the full path to the Ribasim executable, like r\"c:\\ribasim_windows\\ribasim\", or just \"ribasim\" in case you added the ribasim_windows folder to your PATH.\nThe print(result.stderr) ensures you see the same logging and error messages that you would see in the terminal. And result.check_returncode() will throw an error when the simulation was not successful.\nAfter running the model, read back the results:\n\ndf_basin = pd.read_feather(datadir / \"basic/results/basin.arrow\")\ndf_basin_wide = df_basin.pivot_table(\n index=\"time\", columns=\"node_id\", values=[\"storage\", \"level\"]\n)\nax = df_basin_wide[\"level\"].plot()\nax.set_ylabel(\"level [m]\");\n\n\n\n\n\n\n\n\n\ndf_flow = pd.read_feather(datadir / \"basic/results/flow.arrow\")\ndf_flow[\"edge\"] = list(zip(df_flow.from_node_id, df_flow.to_node_id))\ndf_flow[\"flow_m3d\"] = df_flow.flow_rate * 86400\nax = df_flow.pivot_table(index=\"time\", columns=\"edge\", values=\"flow_m3d\").plot()\nax.legend(bbox_to_anchor=(1.3, 1), title=\"Edge\")\nax.set_ylabel(\"flow [m³day⁻¹]\");",
"crumbs": [
"How-to guides",
"Examples"
flow_in_min