HydPy-Exch-Branch-IO (branch model using external water transfer requests)¶
exch_branch_io modifies the flow through a stream by transferring water based on
externally defined requests. These are usually positive (withdrawals) but can also be
negative (supplies). If external requests are missing, it estimates the water transfer
using season-dependent interpolation rules.
exch_branch_io is compatible with the LARSIM routines for modelling simple (VERZ) and
extended (ERWV) branching of river discharge, while offering some additional
functionalities:
Handling of negative inflow (reverse flow) is possible.
Water transfers can be positive (withdrawals) and negative (supplies).
Configuration of minimum and maximum flows that must not be violated by externally requested water transfers (including different modes of transfer adjustment).
Inflow-dependent piecewise interpolation (for the fallback calculations) can be linear or non-linear (spline interpolation).
The transition between season-dependent interpolation rules is usually smoothed by linear interpolation over time.
Before reading the following integration tests, it is advisable to review the
documentation for method Pass_ActualTransfer_StreamOutflow_V1, which is the core of
exch_branch_io.
Integration tests¶
Note
When new to HydPy, consider reading section Integration Tests first.
We perform the following examples over a simulation period of 11 days:
>>> from hydpy import pub, Nodes, Element
>>> pub.timegrids = "2000-01-01", "2000-01-12", "1d"
exch_branch_io has no parameter whose values depend on the simulation time step, so
we do not need to define the parameter time step size here:
>>> from hydpy.models.exch_branch_io import *
>>> parameterstep()
According to the following setting, exch_branch_io queries inflow from two inlet
nodes and passes the branched outflow to two outlet nodes:
>>> nodes = Nodes("inflow1", "inflow2", "river", "diversion")
>>> branch = Element(
... "branch", inlets=["inflow1", "inflow2"], outlets=["river", "diversion"]
... )
There may be fewer or more inlet nodes, but the number of outlet nodes must be exactly two.
The variable types of the respective Node instances do not matter. Instead,
exch_branch_io lumps all inlet nodes together as inflow providers and builds
different connections to the two outlet nodes, for which it uses the node names passed
to parameter Targets:
>>> targets(stream="river", transfer="diversion")
>>> branch.model = model
By assigning “river” to the keyword stream and “diversion” to the keyword transfer, the roles of the two outlet nodes become clear. The “transfer” node will receive the calculated water transfer, while the “river” node will receive the remaining (or enhanced) streamflow.
We do not have to define any initial values in the test settings because
exch_branch_io has no memory:
>>> from hydpy.core.testtools import IntegrationTest
>>> test = IntegrationTest(branch)
>>> test.dateformat = "%d Jan."
Instead of defining a realistic inflow series, the sum of the inlet nodes’ values increases linearly:
>>> import numpy
>>> nodes.inflow1.sequences.sim.series = numpy.arange(0.0, 11.0)
>>> nodes.inflow2.sequences.sim.series = -1.0
requested transfer¶
exch_branch_io’s priority is to withdraw water from or supply water to the main
stream based on externally requested transfers, given as an input time series. In this
example, these requests are positive (withdrawals) in the first half and negative
(supplies) in the second half of the simulation period:
>>> inputs.requestedtransfer.series = 6 * [2.0] + 5 * [-2.0]
Withdrawals could cause too-low (and even negative) flows. To prevent this, we set
parameter MinStream to 1 m³/s:
>>> minstream(1.0)
Likewise, supplies could cause too-high flows, which we prevent by setting parameter
MaxStream to 8 m³/s:
>>> maxstream(8.0)
Parameter KeepWaterBalance configures the exact behaviour during possible violations
of MinStream and MaxStream, which is explained in detail in the documentation on
method Pass_ActualTransfer_StreamOutflow_V1. Here, we set the more intuitive
behaviour of reducing transfers as strongly as necessary to maintain the water balance:
>>> keepwaterbalance(True)
As the simulation results show, the transfer is reduced to zero if necessary. Still, withdrawals are never turned into supplies for already too-low inflows and supplies are never turned into withdrawals for already too-high inflows:
>>> test("exch_branch_io_requested_transfer")
Click to see the table
internal estimates¶
If external requests are unavailable (preferably indicated by inf or
alternatively by nan), exch_branch_io must fall back to its internal routine
for calculating requested transfers:
>>> inputs.requestedtransfer.series = numpy.inf
Configuring this internal routine means defining piecewise linear or polynomial
interpolation functions and passing them to parameter FlowTransferRules. The
documentation for parameter FlowTransferRules explains the available degrees of
freedom for doing so. However, here we restrict ourselves to simple PPoly instances,
each interpolating the water transfer for a specific time of year:
>>> flowtransferrules(
... toy_01_01_12=PPoly(xs=[0.0, 2.0, 4.0, 6.0], ys=[0.0, 0.0, 1.0, 1.0]),
... toy_01_09_12=PPoly(xs=[0.0, 2.0, 4.0, 6.0], ys=[0.0, 0.0, 1.0, 1.0]),
... toy_01_11_12=PPoly(xs=[0.0, 2.0, 4.0, 6.0], ys=[0.0, 0.0, 2.0, 2.0]),
... )
From 1 to 9 Jan, the first rule (defined twice) applies, which diverts up to 1 m³/s. After that, there is a continuous transition from the first to the second rule, which diverts up to 2 m³/s:
>>> test("exch_branch_io_internal_estimates")
Click to see the table
- class hydpy.models.exch_branch_io.Model[source]¶
Bases:
AdHocModelHydPy-Exch-Branch-IO (branch model using external water transfer requests).
- The following “inlet update methods” are called in the given sequence at the beginning of each simulation step:
Pick_Inflow_V1Sum all individual inflow values.
- The following “outlet update methods” are called in the given sequence at the end of each simulation step:
Pass_ActualTransfer_StreamOutflow_V1Calculate the actual water transfer and remaining stream outflow based on external transfer requests (if available) or based on internal transfer calculations (as a fallback).
- DOCNAME = ('Exch-Branch-IO', 'branch model using external water transfer requests')¶
- property targetnames: tuple[str, str]¶
Names of the target nodes.
The first and the second name belong to the mainstream node and the transfer node, respectively. Note that this order can differ from the alphabetical order of the outputs of parameter
FlowTransferRules(seeStreamIndex).
- connect() None[source]¶
Connect all available inlet nodes to the inlet sequence
Inflow, and connect correctly named target outlet nodes to the outlet sequencesActualTransferandStreamOutflow.The following test configuration involves two inlet nodes (inflow1 and inflow2) and two outlet nodes (diversion and river):
>>> from hydpy import Element, Nodes, pub >>> pub.timegrids = "2000-01-01", "2000-01-12", "1d" >>> diversion, inflow1, inflow2, river = Nodes( ... "diversion", "inflow1", "inflow2", "river" ... ) >>> branch = Element( ... "branch", inlets=[inflow1, inflow2], outlets=[diversion, river] ... )
Without giving
exch_branch_iomore information about the outlet nodes’ roles, you cannot build connections to them:>>> from hydpy.models.exch_branch_io import * >>> parameterstep() >>> branch.model = model Traceback (most recent call last): ... RuntimeError: While trying to connect model `exch_branch_io` with element `branch`, the following error occurred: The names of the target nodes are still unknown. Please define them via parameter `targets` first.
Providing this information works via parameter
Targets, which requires the (correct) target node names:>>> targets(stream="channel", transfer="diversion") >>> model.connect() Traceback (most recent call last): ... RuntimeError: While trying to connect model `exch_branch_io` with element `branch`, the following error occurred: The target node names `channel and diversion` do not agree with the available outlet nodes `diversion and river`.
With consistent definitions, the transfer and the mainstream outflow reach the nodes diversion and river as intended:
>>> targets(stream="river", transfer="diversion") >>> flowtransferrules(PPoly(xs=[0.0, 3.0], ys=[0.0, 2.0])) >>> derived.toy.update() >>> derived.streamindex.update() >>> model.connect() >>> fluxes.inflow = 3.0 >>> model.update_outlets() >>> river.sequences.sim sim(1.0) >>> diversion.sequences.sim sim(2.0)
- REUSABLE_METHODS = ()¶
- class hydpy.models.exch_branch_io.ControlParameters(master: Parameters[TM_co], cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
ControlParametersControl parameters of model exch_branch_io.
- The following classes are selected:
Targets()Target nodes.MinStream()Minimum stream outflow that externally requested withdrawals must not undercut [m³/s].MaxStream()Maximum stream outflow that externally requested supplies must not exceed [m³/s].KeepWaterBalance()Flag to indicate if too-high requested transfers should be reduced [-].FlowTransferRules()Seasonally varying interpolation rules for branching the (adjusted) inflow [-].
- class hydpy.models.exch_branch_io.DerivedParameters(master: Parameters[TM_co], cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
DerivedParametersDerived parameters of model exch_branch_io.
- The following classes are selected:
TOY()References thetimeofyearindex array provided by the instance of classIndexeravailable in modulepub[-].StreamIndex()The index of the stream node’s output among the outputs of parameterFlowTransferRules[-].
- class hydpy.models.exch_branch_io.FluxSequences(master: Sequences[TM_co], cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
FluxSequencesFlux sequences of model exch_branch_io.
- The following classes are selected:
Inflow()Inflow [m³/s].
- class hydpy.models.exch_branch_io.InletSequences(master: Sequences[TM_co], cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
InletSequencesInlet sequences of model exch_branch_io.
- The following classes are selected:
Inflow()Inflow [m³/s].
- class hydpy.models.exch_branch_io.InputSequences(master: Sequences[TM_co], cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
InputSequencesInput sequences of model exch_branch_io.
- The following classes are selected:
RequestedTransfer()Externally requested water transfer [m³/s].
- class hydpy.models.exch_branch_io.OutletSequences(master: Sequences[TM_co], cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
OutletSequencesOutlet sequences of model exch_branch_io.
- The following classes are selected:
ActualTransfer()Actual water transfer [m³/s].StreamOutflow()Mainstream outflow [m³/s].