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

Give error when priorities parameter is missing and allocation is active #1745

Merged
merged 7 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
32 changes: 22 additions & 10 deletions core/src/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -407,19 +407,31 @@ end

function get_all_priorities(db::DB, config::Config)::Vector{Int32}
priorities = Set{Int32}()

is_valid = true
# TODO: Is there a way to automatically grab all tables with a priority column?
for type in [
UserDemandStaticV1,
UserDemandTimeV1,
LevelDemandStaticV1,
LevelDemandTimeV1,
FlowDemandStaticV1,
FlowDemandTimeV1,
for (type, name) in [
(UserDemandStaticV1, "UserDemand / static"),
(UserDemandTimeV1, "UserDemand / time"),
(LevelDemandStaticV1, "LevelDemand / static"),
(LevelDemandTimeV1, "LevelDemand / time"),
(FlowDemandStaticV1, "FlowDemand / static"),
(FlowDemandTimeV1, "FlowDemand / time"),
]
union!(priorities, load_structvector(db, config, type).priority)
if valid_priorities(
load_structvector(db, config, type).priority,
config.allocation.use_allocation,
)
union!(priorities, load_structvector(db, config, type).priority)
else
is_valid = false
@error "Missing priority parameter(s) for a $name node in the allocation problem."
end
end
if is_valid
return sort(collect(priorities))
else
error("Priority parameter is missing")
end
return sort(collect(priorities))
end

function get_external_priority_idx(p::Parameters, node_id::NodeID)::Int
Expand Down
8 changes: 8 additions & 0 deletions core/src/validation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -666,3 +666,11 @@ function valid_sources(
end
return !errors
end

function valid_priorities(priorities::Vector, use_allocation::Bool)::Bool
errors = false
if 0 in priorities && use_allocation
errors = true
end
return !errors
end
25 changes: 25 additions & 0 deletions core/test/validation_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -448,3 +448,28 @@ end
)
@test occursin("Basin #11 = ", output)
end

@testitem "Missing priority when allocation is active" begin
using Ribasim
using Logging
using IOCapture: capture

toml_path =
normpath(@__DIR__, "../../generated_testmodels/invalid_priorities/ribasim.toml")
@test ispath(toml_path)

config = Ribasim.Config(toml_path; allocation_use_allocation = true)

logger = TestLogger()
with_logger(logger) do
@test_throws "Priority parameter is missing" Ribasim.run(config)
end
@test length(logger.logs) == 3
@test logger.logs[1].level == Error
@test logger.logs[1].message ==
"Missing priority parameter(s) for a UserDemand / static node in the allocation problem."
@test logger.logs[2].message ==
"Missing priority parameter(s) for a LevelDemand / static node in the allocation problem."
@test logger.logs[3].message ==
"Missing priority parameter(s) for a FlowDemand / static node in the allocation problem."
end
2 changes: 2 additions & 0 deletions python/ribasim_testmodels/ribasim_testmodels/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
from ribasim_testmodels.invalid import (
invalid_discrete_control_model,
invalid_edge_types_model,
invalid_priorities_model,
invalid_qh_model,
invalid_unstable_model,
)
Expand Down Expand Up @@ -77,6 +78,7 @@
"flow_demand_model",
"invalid_discrete_control_model",
"invalid_edge_types_model",
"invalid_priorities_model",
"invalid_qh_model",
"invalid_unstable_model",
"leaky_bucket_model",
Expand Down
59 changes: 58 additions & 1 deletion python/ribasim_testmodels/ribasim_testmodels/invalid.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
from typing import Any

from ribasim.config import Node, Solver
from ribasim.config import Allocation, Node, Solver
from ribasim.input_base import TableModel
from ribasim.model import Model
from ribasim.nodes import (
basin,
discrete_control,
flow_boundary,
flow_demand,
level_boundary,
level_demand,
pump,
tabulated_rating_curve,
user_demand,
)
from shapely.geometry import Point

Expand Down Expand Up @@ -162,3 +166,56 @@ def invalid_unstable_model() -> Model:
model.edge.add(model.basin[1 + id_shift * i], model.pump[2 + id_shift * i])
model.edge.add(model.pump[2 + id_shift * i], model.terminal[3 + id_shift * i])
return model


def invalid_priorities_model() -> Model:
"""Model with allocation active but missing priority parameter(s)."""
Jingru923 marked this conversation as resolved.
Show resolved Hide resolved

model = Model(
starttime="2020-01-01 00:00:00",
endtime="2021-01-01 00:00:00",
crs="EPSG:28992",
allocation=Allocation(use_allocation=True, timestep=1e5),
)

model.tabulated_rating_curve.add(
Node(2, Point(1, 0), subnetwork_id=2),
[tabulated_rating_curve.Static(level=[0.0, 1.0], flow_rate=[0.0, 2e-3])],
)

model.level_boundary.add(
Node(1, Point(0, 0), subnetwork_id=2),
[level_boundary.Static(node_id=[1], level=[1.0])],
)

model.basin.add(
Node(3, Point(2, 0), subnetwork_id=2),
[basin.Profile(area=1e3, level=[0.0, 1.0]), basin.State(level=[1.0])],
)

model.user_demand.add(
Node(4, Point(3, 0), subnetwork_id=2),
[user_demand.Static(demand=[1e-3], return_factor=1.0, min_level=0.2)],
)

model.level_demand.add(
Node(6, Point(2, -1), subnetwork_id=2),
[level_demand.Static(min_level=[1.0], max_level=1.5)],
)

model.flow_demand.add(
Node(5, Point(1, -1), subnetwork_id=2),
[flow_demand.Static(demand=[2e-3])],
)

model.edge.add(
model.level_boundary[1],
model.tabulated_rating_curve[2],
subnetwork_id=2,
)
model.edge.add(model.tabulated_rating_curve[2], model.basin[3])
model.edge.add(model.basin[3], model.user_demand[4])
model.edge.add(model.basin[3], model.level_demand[6])
model.edge.add(model.flow_demand[5], model.tabulated_rating_curve[2])

return model