arma_v1

Version 1 of the HydPy-A model generalises the RIMO/RIDO flood routing approach.

RIMO/RIDO is based on the translation diffusion equation, which is a linear approximation on the Saint-Venant equations involving only two parameters - one for the celerity and one for the diffusivity of the flood wave. The linearity of the approach allows for constructing Unit Hydrograph ordinates for each specific combination of celerity, diffusivity, and the length of the considered river section. One can understand these ordinates as coefficients of a moving average (MA) process.

RIMO/RIDO adds two additional features to this conventional approach.

Firstly, RIMO/RIDO approximates the response function described by the MA coefficients by an ARMA process, which is useful for response functions with long tails. Very often, autoregressive (AR) models are capable of approximating long-tailed responses sufficiently with few parameters. Hence, using ARMA models (which reflect the rising limb of a response function with their MA coefficients its falling limb with their AR coefficients) is often more parameter efficient than using pure MA models.

Secondly, RIMO/RIDO separates the flow into the river section into different “portions” based on discharge threshold. Each portion is routed by a separate ARMA model, allowing to factor in the nonlinearity of rating curves to a certain degree. For example, the bank-full discharge can serve as a threshold. Then one can apply smaller celerity values and larger diffusivity values on the “upper” flow portion to simulate retention processes on flood-plains.

If you want to apply arma_v1 precisely like RIMO/RIDO, consider using TranslationDiffusionEquation for calculating its coefficients. But you are free to define other parameters, e.g. those of the LinearStorageCascade. Additionally, you are free to apply combined ARMA coefficients or pure MA coefficients only, as described in the following examples.

Integration tests

Note

When new to HydPy, consider reading section How to understand integration tests? first.

The following tests are performed over a period of 20 hours:

>>> from hydpy import pub, Nodes, Element
>>> pub.timegrids = "01.01.2000 00:00",  "01.01.2000 20:00", "1h"

Import the model and define the time settings:

>>> from hydpy.models.arma_v1 import *
>>> parameterstep("1h")

For testing purposes, the model input shall be retrieved from the nodes input1 and input2 and the model output shall be passed to node output. Firstly, define all nodes:

>>> nodes = Nodes("input1", "input2", "output")

Define the element stream and build the connections between the nodes defined above and the arma_v1 model instance:

>>> stream = Element("stream",
...                  inlets=["input1", "input2"],
...                  outlets="output")
>>> stream.model = model

Prepare a test function object, which prints the respective values of the model sequences QIn, QPIn, QPOut, and QOut. The node sequence sim is added in order to prove that the values calculated for QOut are actually passed to sim:

>>> from hydpy import IntegrationTest
>>> IntegrationTest.plotting_options.activated=(
...     fluxes.qin, fluxes.qout)
>>> test = IntegrationTest(
...     stream,
...     seqs=(fluxes.qin, fluxes.qpin, fluxes.qpout,
...           fluxes.qout, nodes.output.sequences.sim))

To start the respective example runs from stationary conditions, a base flow value of 2 m³/s is set for all values of the log sequences LogIn and LogOut:

>>> test.inits = ((logs.login, 2.0),
...               (logs.logout, 2.0))

Print just the time instead of the whole date:

>>> test.dateformat = "%H:%M"

Define two flood events, one for each lake inflow:

>>> nodes.input1.sequences.sim.series = (
...     1.0, 1.0, 2.0, 4.0, 3.0, 2.0, 1.0, 1.0, 1.0, 1.0,
...     1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0)
>>> nodes.input2.sequences.sim.series = (
...     1.0, 2.0, 6.0, 9.0, 8.0, 6.0, 4.0, 3.0, 2.0, 1.0,
...     1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0)

MA coefficients

In the first example, a pure fourth order moving avarage (MA) process is defined via the control parameter Responses:

>>> responses(((), (0.2, 0.4, 0.3, 0.1)))

This leads to a usual “unit hydrograph” convolution result, where all inflow “impulses” are separated onto the actual and the three subsequent time steps:

>>> test("arma_v1_ma")
Click to see the table
Click to see the graph

ARMA coefficients

Now we set the order of the MA process to the smalles possible value, which is one. The autoregression (AR) process is of order two. Note that negative AR coefficients are allowed (also note the opposite signs of the coefficients in contrast to the statistical literature):

>>> responses(((1.1, -0.3), (0.2,)))

Due to the AR process, the maximum time delay of some fractions of each input impulse is theoretically infinite:

>>> test("arma_v1_arma")
Click to see the table
Click to see the graph

Increased delay

This example equals the second one, except in the additional time delay of exactly one hour, due to the changed MA process:

>>> responses(((1.1, -0.3), (0.0, 0.2)))
>>> test("arma_v1_delay")
Click to see the table
Click to see the graph

Negative discharge

In some hydrological applications, the inflow into a channel might be lower than 0 m³/s at times. arma generally routes such negative discharges using the response function with the lowest discharge threshold. When we repeat the calculation of the Increased delay example with inflow constantly decreased by 3 m³/s, the outflow is also constantly decreased by 3 m³/s and many simulated values are negative:

>>> nodes.input1.sequences.sim.series -= 3.0
>>> test.inits = ((logs.login, -1.0),
...               (logs.logout, -1.0))
>>> test("arma_v1_negative_discharge")
Click to see the table
Click to see the graph
>>> nodes.input1.sequences.sim.series += 3.0
>>> test.inits = ((logs.login, 2.0),
...               (logs.logout, 2.0))

Plausibility

Be aware that neither parameter Responses does check the assigned coefficients nor does model arma_v1 check the calculated outflow for plausibility (one can use the features provided in modules iuhtools and armatools to calculate reliable coefficients). The fourth example increases the span of the AR coefficients used in the third example. The complete ARMA process is still mass conservative, but some response values of the recession curve are negative:

>>> responses(((1.5, -0.7), (0.0, 0.2)))
>>> test("arma_v1_plausibility")
Click to see the table
Click to see the graph

Nonlinearity

In the next example, the coefficients of the first two examples are combined. For inflow discharges between 0 and 7 m³/s, the pure AR process is applied. For inflow discharges exceeding 7 m³/s, inflow is separated. The AR process is still applied on a portion of 7 m³/s, but for the inflow exceeding the threshold the mixed ARMA model is applied:

>>> responses(_0=((), (0.2, 0.4, 0.3, 0.1)),
...           _7=((1.1, -0.3), (0.2,)))

To again start from stationary conditions, one has to apply different values to both log sequences. The base flow value of 2 m³/s is only given to the (low flow) MA model, the (high flow) ARMA model is initialized with zero values instead:

>>> test.inits.login = [[2.0], [0.0]]
>>> test.inits.logout = [[2.0], [0.0]]

The separate handling of the inflow can be studied by inspecting the columns of sequence QPIn and sequence QPOut. The respective left columns show the input and output of the MA model, the respective right colums show the input and output of the ARMA model:

>>> test("arma_v1_nonlinearity")
Click to see the table
Click to see the graph
class hydpy.models.arma_v1.Model[source]

Bases: hydpy.core.modeltools.AdHocModel

Rimo/Rido version of ARMA (arma_v1).

The following “inlet update methods” are called in the given sequence at the beginning of each simulation step:
The following “run methods” are called in the given sequence during each simulation step:
  • Calc_QPIn_V1 Calculate the input discharge portions of the different response functions.

  • Update_LogIn_V1 Refresh the input log sequence for the different MA processes.

  • Calc_QMA_V1 Calculate the discharge responses of the different MA processes.

  • Calc_QAR_V1 Calculate the discharge responses of the different AR processes.

  • Calc_QPOut_V1 Calculate the ARMA results for the different response functions.

  • Update_LogOut_V1 Refresh the log sequence for the different AR processes.

  • Calc_QOut_V1 Sum up the results of the different response functions.

The following “outlet update methods” are called in the given sequence at the end of each simulation step:
class hydpy.models.arma_v1.ControlParameters(master: hydpy.core.parametertools.Parameters, cls_fastaccess: Optional[Type[hydpy.core.parametertools.FastAccessParameter]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)

Bases: hydpy.core.variabletools.SubVariables[hydpy.core.parametertools.Parameters, Parameter, hydpy.core.parametertools.FastAccessParameter]

Control parameters of model arma_v1.

The following classes are selected:
  • Responses() Assigns different ARMA models to different discharge thresholds.

class hydpy.models.arma_v1.DerivedParameters(master: hydpy.core.parametertools.Parameters, cls_fastaccess: Optional[Type[hydpy.core.parametertools.FastAccessParameter]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)

Bases: hydpy.core.variabletools.SubVariables[hydpy.core.parametertools.Parameters, Parameter, hydpy.core.parametertools.FastAccessParameter]

Derived parameters of model arma_v1.

The following classes are selected:
  • Nmb() Number of response functions [-].

  • MaxQ() Maximum discharge values of the respective ARMA models [m³/s].

  • DiffQ() Differences between the values of MaxQ [m³/s].

  • AR_Order() Number of AR coefficients of the different responses [-].

  • MA_Order() Number of MA coefficients of the different responses [-].

  • AR_Coefs() AR coefficients of the different responses [-].

  • MA_Coefs() MA coefficients of the different responses [-].

class hydpy.models.arma_v1.FluxSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)

Bases: hydpy.core.sequencetools.OutputSequences[FluxSequence]

Flux sequences of model arma_v1.

The following classes are selected:
  • QIn() Total inflow [m³/s].

  • QPIn() Inflow portions corresponding to the different thresholds [m³/s].

  • QMA() MA result for the different thresholds [m³/s].

  • QAR() AR result for the different thresholds [m³/s].

  • QPOut() Outflow portions corresponding to the different thresholds [m³/s].

  • QOut() Total outflow [m³/s].

class hydpy.models.arma_v1.InletSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)

Bases: hydpy.core.sequencetools.LinkSequences[InletSequence]

Inlet sequences of model arma_v1.

The following classes are selected:
  • Q() Runoff [m³/s].

class hydpy.models.arma_v1.LogSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)

Bases: hydpy.core.sequencetools.ModelSequences[LogSequence, hydpy.core.variabletools.FastAccess]

Log sequences of model arma_v1.

The following classes are selected:
  • LogIn() The recent and the past inflow portions for the application of the different MA processes [m³/s].

  • LogOut() The past outflow portions for the application of the different AR processes [m³/s].

class hydpy.models.arma_v1.OutletSequences(master: hydpy.core.sequencetools.Sequences, cls_fastaccess: Optional[Type[FastAccessType]] = None, cymodel: Optional[hydpy.core.typingtools.CyModelProtocol] = None)

Bases: hydpy.core.sequencetools.LinkSequences[OutletSequence]

Outlet sequences of model arma_v1.

The following classes are selected:
  • Q() Runoff [m³/s].