Skip to content

Commit

Permalink
Use flow_rate rather than discharge in TabulatedRatingCurve
Browse files Browse the repository at this point in the history
A breaking change, but this is more consistent. Fixes #983.
  • Loading branch information
visr committed Jan 26, 2024
1 parent 9581d7b commit 0b71370
Show file tree
Hide file tree
Showing 20 changed files with 44 additions and 48 deletions.
4 changes: 2 additions & 2 deletions core/src/bmi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -607,9 +607,9 @@ function update_tabulated_rating_curve!(integrator)::Nothing
# update the existing LinearInterpolation
id = first(group).node_id
level = [row.level for row in group]
discharge = [row.discharge for row in group]
flow_rate = [row.flow_rate for row in group]
i = searchsortedfirst(node_id, NodeID(id))
tables[i] = LinearInterpolation(discharge, level; extrapolate = true)
tables[i] = LinearInterpolation(flow_rate, level; extrapolate = true)
end
return nothing
end
Expand Down
2 changes: 1 addition & 1 deletion core/src/solve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ end
"""
struct TabulatedRatingCurve{C}
Rating curve from level to discharge. The rating curve is a lookup table with linear
Rating 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.
Expand Down
10 changes: 5 additions & 5 deletions core/src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -570,22 +570,22 @@ end

function qh_interpolation(
level::AbstractVector,
discharge::AbstractVector,
flow_rate::AbstractVector,
)::Tuple{LinearInterpolation, Bool}
return LinearInterpolation(discharge, level; extrapolate = true), allunique(level)
return LinearInterpolation(flow_rate, level; extrapolate = true), allunique(level)
end

"""
From a table with columns node_id, discharge (Q) and level (h),
create a LinearInterpolation from level to discharge for a given node_id.
From a table with columns node_id, flow_rate (Q) and level (h),
create a LinearInterpolation from level to flow rate for a given node_id.
"""
function qh_interpolation(
node_id::Int,
table::StructVector,
)::Tuple{LinearInterpolation, Bool}
rowrange = findlastgroup(node_id, table.node_id)
@assert !isempty(rowrange) "timeseries starts after model start time"
return qh_interpolation(table.level[rowrange], table.discharge[rowrange])
return qh_interpolation(table.level[rowrange], table.flow_rate[rowrange])
end

"""
Expand Down
4 changes: 2 additions & 2 deletions core/src/validation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -261,15 +261,15 @@ end
node_id::Int
active::Union{Missing, Bool}
level::Float64
discharge::Float64
flow_rate::Float64
control_state::Union{Missing, String}
end

@version TabulatedRatingCurveTimeV1 begin
node_id::Int
time::DateTime
level::Float64
discharge::Float64
flow_rate::Float64
end

@version TerminalStaticV1 begin
Expand Down
4 changes: 2 additions & 2 deletions core/test/run_models_test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -335,12 +335,12 @@ end
See: https://en.wikipedia.org/wiki/Standard_step_method
* The left boundary has a fixed discharge `Q`.
* The left boundary has a fixed flow rate `Q`.
* The right boundary has a fixed level `h_right`.
* Channel profile is rectangular.
# Arguments
- `Q`: discharge entering in the left boundary (m3/s)
- `Q`: flow rate entering in the left boundary (m3/s)
- `w`: width (m)
- `n`: Manning roughness
- `h_right`: water level on the right boundary
Expand Down
4 changes: 0 additions & 4 deletions docs/core/equations.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,6 @@ discharge. It can be understood as an empirical description of a basin's
properties. This can include an outlet, but also the lumped hydraulic behavior of the
upstream channels.
<!-- Is this still true? -->
The Tabulated Rating Curve should indicate at which volume no discharge occurs (the dead
storage volume).
:::{.callout-note}
Currently, the discharge relies only on the basin's level; it could also use
the volume of both connected basins to simulate backwater effects, submersion
Expand Down
6 changes: 3 additions & 3 deletions docs/core/usage.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -393,9 +393,9 @@ node_id | Int | - | sorted
control_state | String | - | (optional) sorted per node_id
active | Bool | - | (optional, default true)
level | Float64 | $m$ | sorted per control_state
discharge | Float64 | $m^3 s^{-1}$ | non-negative
flow_rate | Float64 | $m^3 s^{-1}$ | non-negative

node_id | discharge | level
node_id | flow_rate | level
------- |----------- |-------
2 | 0.0 | -0.105
2 | 0.0 | 0.095
Expand All @@ -416,7 +416,7 @@ column | type | unit | restriction
node_id | Int | - | sorted
time | DateTime | - | sorted per node_id
level | Float64 | $m$ | -
discharge | Float64 | $m^3 s^{-1}$ | non-negative
flow_rate | Float64 | $m^3 s^{-1}$ | non-negative

# Pump

Expand Down
8 changes: 4 additions & 4 deletions docs/python/examples.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@
" data={\n",
" \"node_id\": [4, 4],\n",
" \"level\": [0.0, 1.0],\n",
" \"discharge\": [0.0, q1000],\n",
" \"flow_rate\": [0.0, q1000],\n",
" }\n",
" )\n",
")"
Expand Down Expand Up @@ -867,7 +867,7 @@
"source": [
"rating_curve = ribasim.TabulatedRatingCurve(\n",
" static=pd.DataFrame(\n",
" data={\"node_id\": 2 * [5], \"level\": [2.0, 15.0], \"discharge\": [0.0, 1e-3]}\n",
" data={\"node_id\": 2 * [5], \"level\": [2.0, 15.0], \"flow_rate\": [0.0, 1e-3]}\n",
" )\n",
")"
]
Expand Down Expand Up @@ -1633,7 +1633,7 @@
" data={\n",
" \"node_id\": 7,\n",
" \"level\": [0.0, 0.5, 1.0],\n",
" \"discharge\": [0.0, 0.0, 2.0],\n",
" \"flow_rate\": [0.0, 0.0, 2.0],\n",
" }\n",
" )\n",
")"
Expand Down Expand Up @@ -1941,7 +1941,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.6"
"version": "3.11.7"
}
},
"nbformat": 4,
Expand Down
4 changes: 2 additions & 2 deletions docs/schema/TabulatedRatingCurveStatic.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"format": "double",
"type": "number"
},
"discharge": {
"flow_rate": {
"format": "double",
"type": "number"
},
Expand All @@ -49,6 +49,6 @@
"required": [
"node_id",
"level",
"discharge"
"flow_rate"
]
}
4 changes: 2 additions & 2 deletions docs/schema/TabulatedRatingCurveTime.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"format": "double",
"type": "number"
},
"discharge": {
"flow_rate": {
"format": "double",
"type": "number"
},
Expand All @@ -32,6 +32,6 @@
"node_id",
"time",
"level",
"discharge"
"flow_rate"
]
}
4 changes: 2 additions & 2 deletions python/ribasim/ribasim/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ class TabulatedRatingCurveStatic(BaseModel):
node_id: int
active: bool | None = None
level: float
discharge: float
flow_rate: float
control_state: str | None = None
remarks: str = Field("", description="a hack for pandera")

Expand All @@ -198,7 +198,7 @@ class TabulatedRatingCurveTime(BaseModel):
node_id: int
time: datetime
level: float
discharge: float
flow_rate: float
remarks: str = Field("", description="a hack for pandera")


Expand Down
6 changes: 3 additions & 3 deletions python/ribasim_testmodels/ribasim_testmodels/allocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ def looped_subnetwork_model():
data={
"node_id": [13, 13, 14, 14, 19, 19],
"level": 3 * [0.0, 1.0],
"discharge": 3 * [0.0, 2.0],
"flow_rate": 3 * [0.0, 2.0],
}
)
)
Expand Down Expand Up @@ -784,7 +784,7 @@ def fractional_flow_subnetwork_model():
data={
"node_id": [3, 3],
"level": [0.0, 1.0],
"discharge": [0.0, 1e-4],
"flow_rate": [0.0, 1e-4],
}
)
)
Expand Down Expand Up @@ -986,7 +986,7 @@ def allocation_example_model():
data={
"node_id": 7,
"level": [0.0, 0.5, 1.0],
"discharge": [0.0, 0.0, 2.0],
"flow_rate": [0.0, 0.0, 2.0],
}
)
)
Expand Down
6 changes: 3 additions & 3 deletions python/ribasim_testmodels/ribasim_testmodels/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def basic_model() -> ribasim.Model:
data={
"node_id": [4, 4],
"level": [0.0, 1.0],
"discharge": [0.0, q1000],
"flow_rate": [0.0, q1000],
}
)
)
Expand Down Expand Up @@ -329,7 +329,7 @@ def tabulated_rating_curve_model() -> ribasim.Model:
data={
"node_id": [2, 2],
"level": [0.0, 1.0],
"discharge": [0.0, q1000],
"flow_rate": [0.0, q1000],
}
),
time=pd.DataFrame(
Expand All @@ -345,7 +345,7 @@ def tabulated_rating_curve_model() -> ribasim.Model:
pd.Timestamp("2020-03"),
],
"level": [0.0, 1.0, 0.0, 1.1, 0.0, 1.2],
"discharge": [0.0, q1000, 0.0, q1000, 0.0, q1000],
"flow_rate": [0.0, q1000, 0.0, q1000, 0.0, q1000],
}
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ def tabulated_rating_curve_control_model() -> ribasim.Model:
data={
"node_id": [2, 2, 2, 2],
"level": [0.0, 1.2, 0.0, 1.0],
"discharge": [0.0, q100, 0.0, q100],
"flow_rate": [0.0, q100, 0.0, q100],
"control_state": ["low", "low", "high", "high"],
}
),
Expand Down Expand Up @@ -665,7 +665,7 @@ def level_setpoint_with_minmax_model():
# Setup the rating curve
rating_curve = ribasim.TabulatedRatingCurve(
static=pd.DataFrame(
data={"node_id": 2 * [5], "level": [2.0, 15.0], "discharge": [0.0, 1e-3]}
data={"node_id": 2 * [5], "level": [2.0, 15.0], "flow_rate": [0.0, 1e-3]}
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ def dutch_waterways_model():
7.46,
4.45,
4.46,
], # The level and discharge for "pump_low", "pump_high" are irrelevant
"discharge": [0.0, 0.0]
], # The level and flow rate for "pump_low", "pump_high" are irrelevant
"flow_rate": [0.0, 0.0]
+ 2 * [418, 420.15], # since the rating curve is not active here
}
)
Expand Down
4 changes: 2 additions & 2 deletions python/ribasim_testmodels/ribasim_testmodels/equations.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,14 @@ def rating_curve_model():
level_min = 1.0
node_id = np.full(n_datapoints, 2)
level = np.linspace(0, 12, 100)
discharge = np.square(level - level_min) / (60 * 60 * 24)
flow_rate = np.square(level - level_min) / (60 * 60 * 24)

rating_curve = ribasim.TabulatedRatingCurve(
static=pd.DataFrame(
data={
"node_id": node_id,
"level": level,
"discharge": discharge,
"flow_rate": flow_rate,
}
)
)
Expand Down
6 changes: 3 additions & 3 deletions python/ribasim_testmodels/ribasim_testmodels/invalid.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def invalid_qh_model():

rating_curve_static = pd.DataFrame(
# Invalid: levels must not be repeated
data={"node_id": [1, 1], "level": [0.0, 0.0], "discharge": [1.0, 2.0]}
data={"node_id": [1, 1], "level": [0.0, 0.0], "flow_rate": [1.0, 2.0]}
)
rating_curve_time = pd.DataFrame(
data={
Expand All @@ -78,7 +78,7 @@ def invalid_qh_model():
],
# Invalid: levels must not be repeated
"level": [0.0, 0.0],
"discharge": [1.0, 2.0],
"flow_rate": [1.0, 2.0],
}
)

Expand Down Expand Up @@ -195,7 +195,7 @@ def invalid_fractional_flow_model():
# Setup the tabulated rating curve:
rating_curve = ribasim.TabulatedRatingCurve(
static=pd.DataFrame(
data={"node_id": [7, 7], "level": [0.0, 1.0], "discharge": [0.0, 50.0]}
data={"node_id": [7, 7], "level": [0.0, 1.0], "flow_rate": [0.0, 50.0]}
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ def discrete_control_of_pid_control_model():
data={
"node_id": [4, 4],
"level": [0.0, 1.0],
"discharge": [0.0, q1000],
"flow_rate": [0.0, q1000],
}
)
)
Expand Down
2 changes: 1 addition & 1 deletion python/ribasim_testmodels/ribasim_testmodels/trivial.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def trivial_model() -> ribasim.Model:
data={
"node_id": [0, 0],
"level": [0.0, 1.0],
"discharge": [0.0, q1000],
"flow_rate": [0.0, q1000],
}
)
)
Expand Down
4 changes: 2 additions & 2 deletions ribasim_qgis/core/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ def attributes(cls) -> list[QgsField]:
QgsField("node_id", QVariant.Int),
QgsField("active", QVariant.Bool),
QgsField("level", QVariant.Double),
QgsField("discharge", QVariant.Double),
QgsField("flow_rate", QVariant.Double),
QgsField("control_state", QVariant.String),
]

Expand All @@ -466,7 +466,7 @@ def attributes(cls) -> list[QgsField]:
QgsField("time", QVariant.DateTime),
QgsField("node_id", QVariant.Int),
QgsField("level", QVariant.Double),
QgsField("discharge", QVariant.Double),
QgsField("flow_rate", QVariant.Double),
]


Expand Down

0 comments on commit 0b71370

Please sign in to comment.