Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document parsing Delwaq results. #1845

Merged
merged 11 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .teamcity/Templates/IntegrationTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ open class IntegrationTest (platformOs: String) : Template() {
workingDir = "ribasim"
scriptContent = header +
"""
pixi run python utils/get_benchmark.py %MiniO_credential_token% "hws_2024_7_0/"
pixi run python utils/get_benchmark.py --secretkey %MiniO_credential_token% "hws_2024_7_0/"
pixi run model-integration-test
""".trimIndent()
}
Expand All @@ -72,4 +72,4 @@ open class IntegrationTest (platformOs: String) : Template() {
}

object IntegrationTestWindows : IntegrationTest("Windows")
object IntegrationTestLinux : IntegrationTest("Linux")
object IntegrationTestLinux : IntegrationTest("Linux")
4 changes: 2 additions & 2 deletions .teamcity/Templates/RegressionTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ open class RegressionTest (platformOs: String) : Template() {
workingDir = "ribasim"
scriptContent = header +
"""
pixi run python utils/get_benchmark.py %MiniO_credential_token% "benchmark/"
pixi run python utils/get_benchmark.py %MiniO_credential_token% "hws_migration_test/"
pixi run python utils/get_benchmark.py --secretkey %MiniO_credential_token% "benchmark/"
pixi run python utils/get_benchmark.py --secretkey %MiniO_credential_token% "hws_migration_test/"
pixi run test-ribasim-regression
""".trimIndent()
}
Expand Down
11 changes: 11 additions & 0 deletions .teamcity/Templates/TestDelwaqCoupling.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ open class TestDelwaqCoupling(platformOs: String) : Template() {
root(Ribasim, ". => ribasim")
cleanCheckout = true
}
params {
password("MiniO_credential_token", "credentialsJSON:86cbf3e5-724c-437d-9962-7a3f429b0aa2")
}

steps {
script {
Expand All @@ -33,6 +36,14 @@ open class TestDelwaqCoupling(platformOs: String) : Template() {
pixi run delwaq
""".trimIndent()
}
script {
name = "Upload delwaq model"
id = "Delwaq_upload"
workingDir = "ribasim"
scriptContent = """
pixi run python utils/upload_benchmark.py --secretkey %MiniO_credential_token% "python/ribasim/ribasim/delwaq/model/delwaq_map.nc" "doc-image/delwaq/delwaq_map.nc"
""".trimIndent()
}
}
}
}
Expand Down
126 changes: 122 additions & 4 deletions docs/guide/delwaq.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"from pathlib import Path\n",
"\n",
"toml_path = Path(\"../../generated_testmodels/basic/ribasim.toml\")\n",
"\n",
"assert toml_path.is_file()"
]
},
Expand Down Expand Up @@ -54,6 +55,38 @@
"model.plot(); # for later comparison"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"model.basin.profile"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's add another tracer to the model, to setup a fraction calculation."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from ribasim.delwaq import add_tracer\n",
"\n",
"add_tracer(model, 11, \"Foo\")\n",
"add_tracer(model, 15, \"Bar\")\n",
"display(model.flow_boundary.concentration) # flow boundaries\n",
"display(model.level_boundary.concentration) # flow boundaries\n",
"\n",
"model.write(toml_path)"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand Down Expand Up @@ -89,9 +122,8 @@
"source": [
"from ribasim.delwaq import generate\n",
"\n",
"output_path = Path(\n",
" \"../../generated_testmodels/basic/delwaq\"\n",
") # set a path where we store the Delwaq input files\n",
"output_path = Path(\"../../generated_testmodels/basic/delwaq\")\n",
"\n",
"graph, substances = generate(toml_path, output_path)"
]
},
Expand Down Expand Up @@ -182,6 +214,92 @@
"- Basin boundaries are split into separate nodes and links (drainage, precipitation, and evaporation, as indicated by the duplicated Basin IDs on the right hand side)\n",
"- All node IDs have been renumbered, with boundaries being negative, and Basins being positive."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Parsing the results\n",
"With Delwaq having run, we can now parse the results using `ribasim.delwaq.parse`. This function requires the `graph` and `substances` variables that were output by `ribasim.delwaq.generate`, as well as the path to the results folder of the Delwaq simulation."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# | include: false\n",
"# For documentation purposes, we will download the generated map file\n",
"import urllib.request\n",
"\n",
"urllib.request.urlretrieve(\n",
" \"https://s3.deltares.nl/ribasim/doc-image/delwaq/delwaq_map.nc\",\n",
" output_path / \"delwaq_map.nc\",\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from ribasim.delwaq import parse\n",
"\n",
"nmodel = parse(toml_path, graph, substances, output_folder=output_path)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The parsed model is identical to the Ribasim model, with the exception of the added concentration_external table that contains all tracer results from Delwaq."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"display(nmodel.basin.concentration_external)\n",
"print(substances)\n",
"t = nmodel.basin.concentration_external.df\n",
"t[t.time == t.time.unique()[2]]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can use this table to plot the results of the Delwaq model, both spatially as over time."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from ribasim.delwaq import plot_fraction\n",
"\n",
"plot_fraction(nmodel, 1) # default tracers, should add up to 1\n",
"plot_fraction(nmodel, 9, [\"Foo\", \"Bar\"]) # custom tracers\n",
"plot_fraction(nmodel, 9, [\"Continuity\"]) # mass balance check"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from ribasim.delwaq import plot_spatial\n",
"\n",
"plot_spatial(nmodel, \"Bar\")\n",
"plot_spatial(nmodel, \"Foo\", versus=\"Bar\") # ratio of Meuse to Rhine"
]
}
],
"metadata": {
Expand All @@ -200,7 +318,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.4"
"version": "3.12.5"
}
},
"nbformat": 4,
Expand Down
14 changes: 11 additions & 3 deletions python/ribasim/ribasim/delwaq/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
from .generate import generate
from .generate import add_tracer, generate
from .parse import parse
from .plot import plot
from .plot import plot_fraction, plot_spatial
from .util import run_delwaq

__all__ = ["generate", "parse", "run_delwaq", "plot"]
__all__ = [
"generate",
"parse",
"run_delwaq",
"plot",
"add_tracer",
"plot_fraction",
"plot_spatial",
]
40 changes: 36 additions & 4 deletions python/ribasim/ribasim/delwaq/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from datetime import timedelta
from pathlib import Path

from ribasim.utils import MissingOptionalModule, _concat
from ribasim import nodes
from ribasim.utils import MissingOptionalModule, _concat, _pascal_to_snake

try:
import networkx as nx
Expand Down Expand Up @@ -277,16 +278,17 @@
toml_path: Path,
output_folder=output_folder,
use_evaporation=USE_EVAP,
results_folder="results",
) -> tuple[nx.DiGraph, set[str]]:
"""Generate a Delwaq model from a Ribasim model and results."""

# Read in model and results
model = ribasim.Model.read(toml_path)
basins = pd.read_feather(
toml_path.parent / "results" / "basin.arrow", dtype_backend="pyarrow"
toml_path.parent / results_folder / "basin.arrow", dtype_backend="pyarrow"
)
flows = pd.read_feather(
toml_path.parent / "results" / "flow.arrow", dtype_backend="pyarrow"
toml_path.parent / results_folder / "flow.arrow", dtype_backend="pyarrow"
)

output_folder.mkdir(exist_ok=True)
Expand Down Expand Up @@ -414,10 +416,13 @@
# Setup initial basin concentrations
defaults = {
"Continuity": 1.0,
"Basin": 0.0,
"Initial": 1.0,
"LevelBoundary": 0.0,
"FlowBoundary": 0.0,
"Terminal": 0.0,
"UserDemand": 0.0,
"Precipitation": 0.0,
"Drainage": 0.0,
}
substances.update(defaults.keys())

Expand Down Expand Up @@ -491,6 +496,33 @@
return G, substances


def add_tracer(model, node_id, tracer_name):
"""Add a tracer to the Delwaq model."""
n = model.node_table().df.loc[node_id]
node_type = n.node_type
if node_type not in [

Check warning on line 503 in python/ribasim/ribasim/delwaq/generate.py

View check run for this annotation

Codecov / codecov/patch

python/ribasim/ribasim/delwaq/generate.py#L501-L503

Added lines #L501 - L503 were not covered by tests
"Basin",
"LevelBoundary",
"FlowBoundary",
"UserDemand",
]:
raise ValueError("Can only trace Basins and boundaries")
snake_node_type = _pascal_to_snake(node_type)
nt = getattr(model, snake_node_type)

Check warning on line 511 in python/ribasim/ribasim/delwaq/generate.py

View check run for this annotation

Codecov / codecov/patch

python/ribasim/ribasim/delwaq/generate.py#L509-L511

Added lines #L509 - L511 were not covered by tests

ct = getattr(nodes, snake_node_type)
table = ct.Concentration(

Check warning on line 514 in python/ribasim/ribasim/delwaq/generate.py

View check run for this annotation

Codecov / codecov/patch

python/ribasim/ribasim/delwaq/generate.py#L513-L514

Added lines #L513 - L514 were not covered by tests
node_id=[node_id],
time=[model.starttime],
substance=[tracer_name],
concentration=[1.0],
)
if nt.concentration is None:
nt.concentration = table

Check warning on line 521 in python/ribasim/ribasim/delwaq/generate.py

View check run for this annotation

Codecov / codecov/patch

python/ribasim/ribasim/delwaq/generate.py#L520-L521

Added lines #L520 - L521 were not covered by tests
else:
nt.concentration = pd.concat([nt.concentration.df, table.df], ignore_index=True)

Check warning on line 523 in python/ribasim/ribasim/delwaq/generate.py

View check run for this annotation

Codecov / codecov/patch

python/ribasim/ribasim/delwaq/generate.py#L523

Added line #L523 was not covered by tests


if __name__ == "__main__":
# Generate a Delwaq model from the default Ribasim model
repo_dir = delwaq_dir.parents[1]
Expand Down
Loading