HydPy-SW1D-Pump (submodel for pumping water between two channel segments)

The HydPy-SW1D model family member sw1d_pump is a routing submodel that calculates water pumping from one channel segment into another.

Integration tests

Note

When new to HydPy, consider reading section Integration Tests first.

We create a test setting identical to the one of the sw1d_channel documentation, except that we replace the sw1d_lias submodel at the central location with a sw1d_pump submodel:

>>> from hydpy import pub
>>> pub.timegrids = "2000-01-01 00:00", "2000-01-01 05:00", "5m"
>>> from hydpy.models.sw1d_channel import *
>>> parameterstep()
>>> nmbsegments(8)
>>> lengths = 2.0, 3.0, 2.0, 3.0, 2.0, 3.0, 2.0, 3.0
>>> for i, length_ in enumerate(lengths):
...     with model.add_storagemodel_v1("sw1d_storage", position=i):
...         length(length_)
...         with model.add_crosssection_v2("wq_trapeze"):
...             nmbtrapezes(1)
...             bottomlevels(5.0)
...             bottomwidths(5.0)
...             sideslopes(0.0)
>>> for i in range(1, nmbsegments.value):
...     if i == 4:
...         with model.add_routingmodel_v2("sw1d_pump", position=i) as pump:
...             lengthupstream(2.0 if i % 2 else 3.0)
...             lengthdownstream(3.0 if i % 2 else 2.0)
...             gradient2pumpingrate(PPoly(Poly(x0=0.0, cs=[8.0])))
...             targetwaterlevel1(6.0)
...             targetwaterlevel2(6.0)
...             timestepfactor(0.7)
...             with model.add_crosssection_v2("wq_trapeze"):
...                 nmbtrapezes(1)
...                 bottomlevels(5.0)
...                 bottomwidths(5.0)
...                 sideslopes(0.0)
...     else:
...         with model.add_routingmodel_v2("sw1d_lias", position=i):
...             lengthupstream(2.0 if i % 2 else 3.0)
...             lengthdownstream(3.0 if i % 2 else 2.0)
...             stricklercoefficient(1.0/0.03)
...             timestepfactor(0.7)
...             diffusionfactor(0.2)
...             with model.add_crosssection_v2("wq_trapeze"):
...                 nmbtrapezes(1)
...                 bottomlevels(5.0)
...                 bottomwidths(5.0)
...                 sideslopes(0.0)
>>> from hydpy import Element
>>> channel = Element("channel")
>>> channel.model = model
>>> from hydpy.core.testtools import IntegrationTest
>>> test = IntegrationTest(channel)
>>> test.plotting_options.axis1 = (factors.waterlevels,)
>>> def prepare_inits(hs):
...     if isinstance(hs, float):
...         hs = nmbsegments.value * [hs]
...     inits = []
...     for h, s in zip(hs, model.storagemodels):
...         length = s.parameters.control.length
...         c = s.crosssection.parameters.control
...         v = h * (c.bottomwidths[0] + h * c.sideslopes[0]) * length
...         inits.append((s.sequences.states.watervolume, v))
...     for r in model.routingmodels[1:-1]:
...         inits.append((r.sequences.states.discharge, 0.0))
...     test.inits = inits

Note that we decided on a constant maximum pumping rate for simplicity:

>>> figure = pump.parameters.control.gradient2pumpingrate.plot(0.0, 10.0)
>>> from hydpy.core.testtools import save_autofig
>>> save_autofig("sw1d_pump_gradient2pumpingrate.png", figure=figure)
_images/sw1d_pump_gradient2pumpingrate.png

Sharp targets

As in the Zero inflow and outflow example on sw1d_lias, we omit inflow and outflow but start with uneven water depths:

>>> prepare_inits(hs=[3.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0])

The pumping station starts lifting all water from the fourth to the fifth channel segment until the remaining water level is below 6 m, Then the pumping suddenly stops. After that, the first three segments still supply water, which leads to an equally sudden restart of pumping. Due to the threshold-like configuration of the pump and the limited precision of the explicit numerical integration scheme, the resulting unfavourable “on-off” pattern would continue until all water levels of the first four segments were below 6 m:

>>> conditions = test("sw1d_pump_sharp_targets", get_conditions="2000-01-01 00:00")
Click to see the table
Click to see the graph

There is no indication of an error in the water balance:

>>> from hydpy import round_
>>> round_(model.check_waterbalance(conditions))
0.0

Higher precision

One possible solution is increasing numerical precision (like in the Higher precision example), eventually accompanied by reducing numerical diffusion (like in the No additional diffusion example):

>>> for routingmodel in model.routingmodels.submodels[1:-1]:
...     routingmodel.parameters.control.timestepfactor(0.1)
...     if routingmodel.name == "sw1d_lias":
...         routingmodel.parameters.control.diffusionfactor(0.0)

Despite the significant increase in computation time, the water level trajectories of segments four and five are still visibly unsmooth. The simulated pumping rate does not oscillate between its maximum and zero anymore but still shows an unsteady decline:

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

There is no indication of an error in the water balance:

>>> round_(model.check_waterbalance(conditions))
0.0

Fuzzy targets

One might reach more satisfactory results by setting two different thresholds and, thus, a more fuzzy target water level. Here, we reduce the lower and increase the higher threshold by 0.1 m:

>>> model.routingmodels[4].parameters.control.targetwaterlevel1(5.9)
>>> model.routingmodels[4].parameters.control.targetwaterlevel2(6.1)

Also, we reset the initial time step and diffusion factors to reduce computation time:

>>> for routingmodel in model.routingmodels.submodels[1:-1]:
...     routingmodel.parameters.control.timestepfactor(0.7)
...     if routingmodel.name == "sw1d_lias":
...         routingmodel.parameters.control.diffusionfactor(0.2)

The fuzziness range of 0.2 m removes all water level trajectory fluctuations:

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

There is no indication of an error in the water balance:

>>> round_(model.check_waterbalance(conditions))
0.0
class hydpy.models.sw1d_pump.Model[source]

Bases: Main_CrossSectionModel_V2, RoutingModel_V2

HydPy-SW1D-Pump (submodel for pumping water between two channel segments).

The following interface methods are available to main models using the defined model as a submodel:
The following “additional methods” might be called by one or more of the other methods or are meant to be directly called by the user:
Users can hook submodels into the defined main model if they satisfy one of the following interfaces:
  • CrossSectionModel_V2 Interface for calculating discharge-related properties at a channel cross-section.

  • RoutingModel_V1 Interface for calculating the inflow into a channel.

  • RoutingModel_V2 Interface for calculating the discharge between two channel segments.

  • RoutingModel_V3 Interface for calculating the outflow of a channel.

  • StorageModel_V1 Interface for calculating the water amount stored in a single channel segment.

DOCNAME: DocName = ('SW1D-Pump', 'submodel for pumping water between two channel segments')
crosssection: SubmodelProperty[CrossSectionModel_V2]

Required submodel that complies with the following interface: CrossSectionModel_V2.

storagemodelupstream: modeltools.SubmodelProperty[StorageModel_V1]

Required reference to the neighbour storage model upstream.

storagemodelupstream_is_mainmodel
storagemodelupstream_typeid
storagemodeldownstream: modeltools.SubmodelProperty[StorageModel_V1]

Required reference to the neighbour storage model downstream.

storagemodeldownstream_is_mainmodel
storagemodeldownstream_typeid
routingmodelsupstream: modeltools.SubmodelsProperty[RoutingModel_V1 | RoutingModel_V2]

References to the neighbour routing models lying upstream.

routingmodelsdownstream: modeltools.SubmodelsProperty[RoutingModel_V2 | RoutingModel_V3]

References to the neighbour routing models lying downstream.

REUSABLE_METHODS: ClassVar[tuple[type[ReusableMethod], ...]] = ()
cymodel: CyModelProtocol | None
parameters: parametertools.Parameters
sequences: sequencetools.Sequences
masks: masktools.Masks
class hydpy.models.sw1d_pump.ControlParameters(master: Parameters, cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)

Bases: SubParameters

Control parameters of model sw1d_pump.

The following classes are selected:
class hydpy.models.sw1d_pump.DerivedParameters(master: Parameters, cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)

Bases: SubParameters

Derived parameters of model sw1d_pump.

The following classes are selected:
  • Seconds() The length of the actual simulation step size in seconds [s].

  • WeightUpstream() A weighting coefficient for interpolating the water level from the centroids of two adjacent segments to their shared edge [-].

  • LengthMin() The minimum length of the segments upstream and downstream of the relevant routing model [km].

class hydpy.models.sw1d_pump.FactorSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)

Bases: FactorSequences

Factor sequences of model sw1d_pump.

The following classes are selected:
class hydpy.models.sw1d_pump.FluxSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)

Bases: FluxSequences

Flux sequences of model sw1d_pump.

The following classes are selected:
class hydpy.models.sw1d_pump.InletSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)

Bases: InletSequences

Inlet sequences of model sw1d_pump.

The following classes are selected:
  • LongQ() The longitudinal inflow into the first channel segment [m³/s].

class hydpy.models.sw1d_pump.OutletSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)

Bases: OutletSequences

Outlet sequences of model sw1d_pump.

The following classes are selected:
  • LongQ() The longitudinal outflow of the last channel segment [m³/s].

class hydpy.models.sw1d_pump.StateSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)

Bases: StateSequences

State sequences of model sw1d_pump.

The following classes are selected: