From d8ae922631753895559936513f8d34f0c0f28568 Mon Sep 17 00:00:00 2001 From: Martijn Visser Date: Mon, 15 Jul 2024 23:26:34 +0200 Subject: [PATCH 1/2] Keep the core Terminal struct --- core/src/allocation_init.jl | 14 +++++------ core/src/config.jl | 2 ++ core/src/read.jl | 7 ------ core/src/schema.jl | 5 ---- core/src/util.jl | 26 ++++++++++--------- core/test/utils_test.jl | 32 ++++++++++++++++++------ python/ribasim/ribasim/config.py | 7 +----- python/ribasim/ribasim/nodes/__init__.py | 2 -- python/ribasim/ribasim/nodes/terminal.py | 13 ---------- python/ribasim/ribasim/schemas.py | 4 --- python/ribasim/tests/test_io.py | 10 ++++---- ribasim_qgis/core/nodes.py | 14 ----------- 12 files changed, 54 insertions(+), 82 deletions(-) delete mode 100644 python/ribasim/ribasim/nodes/terminal.py diff --git a/core/src/allocation_init.jl b/core/src/allocation_init.jl index 20cd9eb06..3ef10c780 100644 --- a/core/src/allocation_init.jl +++ b/core/src/allocation_init.jl @@ -46,17 +46,17 @@ function get_subnetwork_capacity( if edge_metadata.edge ⊆ node_ids_subnetwork id_src, id_dst = edge_metadata.edge - node_src = getfield(p, graph[id_src].type) - node_dst = getfield(p, graph[id_dst].type) - capacity_edge = Inf # Find flow constraints for this edge - if is_flow_constraining(node_src) + if is_flow_constraining(id_src.type) + node_src = getfield(p, graph[id_src].type) + capacity_node_src = node_src.max_flow_rate[id_src.idx] capacity_edge = min(capacity_edge, capacity_node_src) end - if is_flow_constraining(node_dst) + if is_flow_constraining(id_dst.type) + node_dst = getfield(p, graph[id_dst].type) capacity_node_dst = node_dst.max_flow_rate[id_dst.idx] capacity_edge = min(capacity_edge, capacity_node_dst) end @@ -66,8 +66,8 @@ function get_subnetwork_capacity( # If allowed by the nodes from this edge, # allow allocation flow in opposite direction of the edge if !( - is_flow_direction_constraining(node_src) || - is_flow_direction_constraining(node_dst) + is_flow_direction_constraining(id_src.type) || + is_flow_direction_constraining(id_dst.type) ) capacity[reverse(edge_metadata.edge)] = capacity_edge end diff --git a/core/src/config.jl b/core/src/config.jl index 25af231be..084bb4040 100644 --- a/core/src/config.jl +++ b/core/src/config.jl @@ -42,6 +42,8 @@ for sv in nodeschemas node, kind = nodetype(sv) push!(nodekinds[node], kind) end +# Terminal has no tables +nodekinds[:Terminal] = Symbol[] "Convert a string from CamelCase to snake_case." function snake_case(str::AbstractString)::String diff --git a/core/src/read.jl b/core/src/read.jl index 4fef8fb92..b568f2a4f 100644 --- a/core/src/read.jl +++ b/core/src/read.jl @@ -545,11 +545,6 @@ function Outlet(db::DB, config::Config, graph::MetaGraph, chunk_sizes::Vector{In ) end -function Terminal(db::DB, config::Config)::Terminal - node_id = get_ids(db, "Terminal") - return Terminal(NodeID.(NodeType.Terminal, node_id, eachindex(node_id))) -end - function Basin(db::DB, config::Config, graph::MetaGraph, chunk_sizes::Vector{Int})::Basin node_id = get_ids(db, "Basin") n = length(node_id) @@ -1089,7 +1084,6 @@ function Parameters(db::DB, config::Config)::Parameters flow_boundary = FlowBoundary(db, config, graph) pump = Pump(db, config, graph, chunk_sizes) outlet = Outlet(db, config, graph, chunk_sizes) - terminal = Terminal(db, config) discrete_control = DiscreteControl(db, config, graph) pid_control = PidControl(db, config, chunk_sizes) user_demand = UserDemand(db, config, graph) @@ -1111,7 +1105,6 @@ function Parameters(db::DB, config::Config)::Parameters flow_boundary, pump, outlet, - terminal, discrete_control, pid_control, user_demand, diff --git a/core/src/schema.jl b/core/src/schema.jl index e36d4d128..4e2f65042 100644 --- a/core/src/schema.jl +++ b/core/src/schema.jl @@ -11,7 +11,6 @@ @schema "ribasim.basin.concentration" BasinConcentration @schema "ribasim.basin.concentrationexternal" BasinConcentrationExternal @schema "ribasim.basin.concentrationstate" BasinConcentrationState -@schema "ribasim.terminal.static" TerminalStatic @schema "ribasim.fractionalflow.static" FractionalFlowStatic @schema "ribasim.flowboundary.static" FlowBoundaryStatic @schema "ribasim.flowboundary.time" FlowBoundaryTime @@ -220,10 +219,6 @@ end flow_rate::Float64 end -@version TerminalStaticV1 begin - node_id::Int32 -end - @version DiscreteControlVariableV1 begin node_id::Int32 compound_variable_id::Int32 diff --git a/core/src/util.jl b/core/src/util.jl index f4cae0f04..a97082200 100644 --- a/core/src/util.jl +++ b/core/src/util.jl @@ -374,20 +374,21 @@ function low_storage_factor( end """Whether the given node node is flow constraining by having a maximum flow rate.""" -is_flow_constraining(node::AbstractParameterNode) = hasfield(typeof(node), :max_flow_rate) +function is_flow_constraining(type::NodeType.T)::Bool + type in (NodeType.LinearResistance, NodeType.Pump, NodeType.Outlet) +end """Whether the given node is flow direction constraining (only in direction of edges).""" -is_flow_direction_constraining(node::AbstractParameterNode) = ( - node isa Union{ - Pump, - Outlet, - TabulatedRatingCurve, - FractionalFlow, - Terminal, - UserDemand, - FlowBoundary, - } -) +function is_flow_direction_constraining(type::NodeType.T)::Bool + type in ( + NodeType.Pump, + NodeType.Outlet, + NodeType.TabulatedRatingCurve, + NodeType.FractionalFlow, + NodeType.UserDemand, + NodeType.FlowBoundary, + ) +end function has_main_network(allocation::Allocation)::Bool if !is_active(allocation) @@ -739,6 +740,7 @@ function collect_control_mappings!(p)::Nothing (; control_mappings) = p.discrete_control for node_type in instances(NodeType.T) + node_type == NodeType.Terminal && continue node = getfield(p, Symbol(snake_case(string(node_type)))) if hasfield(typeof(node), :control_mapping) control_mappings[node_type] = node.control_mapping diff --git a/core/test/utils_test.jl b/core/test/utils_test.jl index fc040be0d..1f85b8f1f 100644 --- a/core/test/utils_test.jl +++ b/core/test/utils_test.jl @@ -236,21 +236,39 @@ end end @testitem "constraints_from_nodes" begin - using Ribasim: Model, snake_case, nodetypes, is_flow_constraining + using Ribasim: + Model, + snake_case, + nodetypes, + NodeType, + is_flow_constraining, + is_flow_direction_constraining toml_path = normpath(@__DIR__, "../../generated_testmodels/basic/ribasim.toml") @test ispath(toml_path) model = Model(toml_path) (; p) = model.integrator - constraining_types = (:Pump, :Outlet, :LinearResistance) + constraining_types = (NodeType.Pump, NodeType.Outlet, NodeType.LinearResistance) + directed = ( + NodeType.Pump, + NodeType.Outlet, + NodeType.TabulatedRatingCurve, + NodeType.FractionalFlow, + NodeType.UserDemand, + NodeType.FlowBoundary, + ) - for type in nodetypes - type == :Terminal && continue # has no parameter field - node = getfield(p, snake_case(type)) + for symbol in nodetypes + type = NodeType.T(symbol) if type in constraining_types - @test is_flow_constraining(node) + @test is_flow_constraining(type) + else + @test !is_flow_constraining(type) + end + if type in directed + @test is_flow_direction_constraining(type) else - @test !is_flow_constraining(node) + @test !is_flow_direction_constraining(type) end end end diff --git a/python/ribasim/ribasim/config.py b/python/ribasim/ribasim/config.py index 5e882ed11..3cbc64644 100644 --- a/python/ribasim/ribasim/config.py +++ b/python/ribasim/ribasim/config.py @@ -46,7 +46,6 @@ PumpStaticSchema, TabulatedRatingCurveStaticSchema, TabulatedRatingCurveTimeSchema, - TerminalStaticSchema, UserDemandStaticSchema, UserDemandTimeSchema, ) @@ -169,11 +168,7 @@ def __getitem__(self, index: int) -> NodeData: ) -class Terminal(MultiNodeModel): - static: TableModel[TerminalStaticSchema] = Field( - default_factory=TableModel[TerminalStaticSchema], - json_schema_extra={"sort_keys": ["node_id"]}, - ) +class Terminal(MultiNodeModel): ... class PidControl(MultiNodeModel): diff --git a/python/ribasim/ribasim/nodes/__init__.py b/python/ribasim/ribasim/nodes/__init__.py index 4901ad770..ad6689c53 100644 --- a/python/ribasim/ribasim/nodes/__init__.py +++ b/python/ribasim/ribasim/nodes/__init__.py @@ -11,7 +11,6 @@ pid_control, pump, tabulated_rating_curve, - terminal, user_demand, ) @@ -28,6 +27,5 @@ "pid_control", "pump", "tabulated_rating_curve", - "terminal", "user_demand", ] diff --git a/python/ribasim/ribasim/nodes/terminal.py b/python/ribasim/ribasim/nodes/terminal.py deleted file mode 100644 index 8982ad28a..000000000 --- a/python/ribasim/ribasim/nodes/terminal.py +++ /dev/null @@ -1,13 +0,0 @@ -from pandas import DataFrame - -from ribasim.input_base import TableModel -from ribasim.schemas import ( - TerminalStaticSchema, -) - -__all__ = ["Static"] - - -class Static(TableModel[TerminalStaticSchema]): - def __init__(self, **kwargs): - super().__init__(df=DataFrame(dict(**kwargs))) diff --git a/python/ribasim/ribasim/schemas.py b/python/ribasim/ribasim/schemas.py index cf1bb4477..54b780ace 100644 --- a/python/ribasim/ribasim/schemas.py +++ b/python/ribasim/ribasim/schemas.py @@ -239,10 +239,6 @@ class TabulatedRatingCurveTimeSchema(_BaseSchema): flow_rate: Series[float] = pa.Field(nullable=False) -class TerminalStaticSchema(_BaseSchema): - node_id: Series[Int32] = pa.Field(nullable=False, default=0) - - class UserDemandStaticSchema(_BaseSchema): node_id: Series[Int32] = pa.Field(nullable=False, default=0) active: Series[pa.BOOL] = pa.Field(nullable=True) diff --git a/python/ribasim/tests/test_io.py b/python/ribasim/tests/test_io.py index fe7b9aa62..9abae84aa 100644 --- a/python/ribasim/tests/test_io.py +++ b/python/ribasim/tests/test_io.py @@ -8,7 +8,7 @@ from pandas.testing import assert_frame_equal from pydantic import ValidationError from ribasim import Model, Node, Solver -from ribasim.nodes import basin, pump, terminal, user_demand +from ribasim.nodes import basin, pump, user_demand from shapely.geometry import Point @@ -84,13 +84,13 @@ def test_repr(): def test_extra_columns(): - terminal_static = terminal.Static(meta_id=[-1, -2, -3]) - assert "meta_id" in terminal_static.df.columns - assert (terminal_static.df.meta_id == [-1, -2, -3]).all() + pump_static = pump.Static(meta_id=[-1], flow_rate=[1.2]) + assert "meta_id" in pump_static.df.columns + assert pump_static.df.meta_id.iloc[0] == -1 with pytest.raises(ValidationError): # Extra column "extra" needs "meta_" prefix - terminal.Static(meta_id=[-1, -2, -3], extra=[-1, -2, -3]) + pump.Static(extra=[-2], flow_rate=[1.2]) def test_extra_spatial_columns(): diff --git a/ribasim_qgis/core/nodes.py b/ribasim_qgis/core/nodes.py index 776438dcb..84cd53704 100644 --- a/ribasim_qgis/core/nodes.py +++ b/ribasim_qgis/core/nodes.py @@ -638,20 +638,6 @@ def attributes(cls) -> list[QgsField]: ] -class TerminalStatic(Input): - @classmethod - def input_type(cls) -> str: - return "Terminal / static" - - @classmethod - def geometry_type(cls) -> str: - return "No Geometry" - - @classmethod - def attributes(cls) -> list[QgsField]: - return [QgsField("node_id", QVariant.Int)] - - class FlowBoundaryStatic(Input): @classmethod def input_type(cls) -> str: From 70fcaa2d985064936bb213b9c12348fbba0e1441 Mon Sep 17 00:00:00 2001 From: Martijn Visser Date: Mon, 15 Jul 2024 23:30:25 +0200 Subject: [PATCH 2/2] Fix --- core/src/read.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/read.jl b/core/src/read.jl index b568f2a4f..4fef8fb92 100644 --- a/core/src/read.jl +++ b/core/src/read.jl @@ -545,6 +545,11 @@ function Outlet(db::DB, config::Config, graph::MetaGraph, chunk_sizes::Vector{In ) end +function Terminal(db::DB, config::Config)::Terminal + node_id = get_ids(db, "Terminal") + return Terminal(NodeID.(NodeType.Terminal, node_id, eachindex(node_id))) +end + function Basin(db::DB, config::Config, graph::MetaGraph, chunk_sizes::Vector{Int})::Basin node_id = get_ids(db, "Basin") n = length(node_id) @@ -1084,6 +1089,7 @@ function Parameters(db::DB, config::Config)::Parameters flow_boundary = FlowBoundary(db, config, graph) pump = Pump(db, config, graph, chunk_sizes) outlet = Outlet(db, config, graph, chunk_sizes) + terminal = Terminal(db, config) discrete_control = DiscreteControl(db, config, graph) pid_control = PidControl(db, config, chunk_sizes) user_demand = UserDemand(db, config, graph) @@ -1105,6 +1111,7 @@ function Parameters(db::DB, config::Config)::Parameters flow_boundary, pump, outlet, + terminal, discrete_control, pid_control, user_demand,