HydPy-SW1D-Gate-Out (submodel for calculating flow under a submerged gate at a channel outlet)

The HydPy-SW1D model family member sw1d_gate_out is a routing submodel, which calculates the flow under a submerged gate.

Principally, sw1d_gate_out is similar to sw1d_weir_out, which calculates the flow over a weir. Both models must be placed at a network outlet. However, while sw1d_weir_out calculates free flow and thus requires no information from downstream locations, sw1d_gate_out allows for flows in both directions depending on the (dynamically calculated) upstream water level and an (externally supplied) downstream water level. Another key difference is that sw1d_gate_out allows model users to define project specific-functions for controlling the gate opening.

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 adding a sw1d_gate_out submodel at the channel outlet:

>>> 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):
...     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)
>>> with model.add_routingmodel_v3("sw1d_gate_out", position=8):
...     lengthupstream(lengths[-1])
...     bottomlevel(5.0)
...     gateheight(6.5)
...     gatewidth(2.0)
...     flowcoefficient(0.6)
...     timestepfactor(0.7)
...     dampingradius(0.0)

We need to connect two nodes with the sw1d_gate_out submodel. One node for querying the outflow, which must be connectible to the outlet sequence LongQ. And another node that supplies the downstream water levels, which must be connectible to the receiver sequence WaterLevel:

>>> from hydpy import Element, Node
>>> outflow = Node("outflow", variable="LongQ")
>>> waterlevel = Node("waterlevel", variable="WaterLevel")
>>> channel = Element("channel", outlets=outflow, receivers=waterlevel)
>>> channel.model = model
>>> from hydpy 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:]:
...         inits.append((r.sequences.states.discharge, 0.0))
...     test.inits = inits

Low outer water level

The first example deals with a constant outer water level lower than the initial upstream water level:

>>> waterlevel.sequences.sim.series = 6.0
>>> prepare_inits(hs=2.0)

The water gradient causes a downstream flow and, thus, falling upstream water levels. There is no notable shift in behaviour when the upstream water loses contact with the gate after about a half hour:

>>> conditions = test("sw1d_gate_out_low_outer_waterlevel", 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

High outer water level

Now, we reverse the situation by setting a higher external water level:

>>> waterlevel.sequences.sim.series = 8.0

Due to the higher downstream water level and the subsequent rise of the upstream water levels, the gate is permanently submerged:

>>> test("sw1d_gate_out_high_outer_waterlevel")
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

Rising outer water level

Next, we combine both previous examples by letting the external water level rise from six to eight meters:

>>> import numpy
>>> waterlevel.sequences.sim.series = numpy.linspace(6.0, 8.0, len(pub.timegrids.init))

The resulting water level trajectories are plausible but indicate some numerical inaccuracies after one and a half and two and a half hours:

>>> test("sw1d_gate_out_rising_outer_waterlevel")
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

Oscillation Damping

The numerical inaccuracies that emerged in the Rising outer water level example can cause oscillations of relevant size. We could (similar to the Higher precision example) increase numerical precision to reduce these oscillations. Or we can exclude them entirely by selecting an appropriate value for parameter DampingRadius, wshich reduces the calculated positive or negative flows when level gradients are nearly zero to lessen the integration algorithm’s sensitivity to the extreme (and possibly even infinitely fast) changes in flow rates with respect to water level changes discussed in Calc_Discharge_V3:

>>> model.routingmodels[-1].parameters.control.dampingradius(0.01)

After this change, all trajectories have a smooth appearance:

>>> test("sw1d_gate_out_oscillation_damping")
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

User-defined control

All of the above examples deal with a fixed gate opening. However, gates are often controlled in reality, so their opening degree depends on other properties. Therefore, parameter GateHeight alternatively accepts a callback function for adjusting its values based on the current model state. One can, for example, define a “sluice” function that prevents any flow for reversed water level gradients:

>>> def sluice(model) -> None:
...     con = model.parameters.control.fastaccess
...     fac = model.sequences.factors.fastaccess
...     if fac.waterlevelupstream < fac.waterleveldownstream:
...         con.gateheight = 5.0
...     else:
...         con.gateheight = 6.5
>>> ();model.routingmodels[-1].parameters.control.gateheight(callback=sluice);()  
(...)

At the beginning of the simulation period, the calculated inner water levels resemble those of the previous example. However, the gate closes when the external water level exceeds the inner one, so they start to even off around 6.8 m in the second half of the simulation:

>>> test("sw1d_gate_out_user_defined_control")
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_gate_out.Model[source]

Bases: AdHocModel, RoutingModel_V3

HydPy-SW1D-Gate-Out (submodel for calculating flow under a submerged gate at a channel outlet).

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:
  • RoutingModel_V1 Interface for calculating the inflow into a channel.

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

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

DOCNAME: DocName = ('SW1D-Gate-Out', 'submodel for calculating flow under a submerged gate at a channel outlet')
storagemodelupstream: modeltools.SubmodelProperty[StorageModel_V1]

Required reference to the neighbour storage model upstream.

storagemodelupstream_is_mainmodel
storagemodelupstream_typeid
routingmodelsupstream: modeltools.SubmodelsProperty[RoutingModel_V1 | RoutingModel_V2]

References to the neighbour routing models lying upstream.

REUSABLE_METHODS: ClassVar[tuple[type[ReusableMethod], ...]] = ()
class hydpy.models.sw1d_gate_out.ControlParameters(master: Parameters, cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)

Bases: SubParameters

Control parameters of model sw1d_gate_out.

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

Bases: SubParameters

Derived parameters of model sw1d_gate_out.

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

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

Bases: FactorSequences

Factor sequences of model sw1d_gate_out.

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

Bases: SubParameters

Fixed parameters of model sw1d_gate_out.

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

Bases: FluxSequences

Flux sequences of model sw1d_gate_out.

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

Bases: InletSequences

Inlet sequences of model sw1d_gate_out.

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

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

Bases: OutletSequences

Outlet sequences of model sw1d_gate_out.

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

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

Bases: ReceiverSequences

Receiver sequences of model sw1d_gate_out.

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

Bases: StateSequences

State sequences of model sw1d_gate_out.

The following classes are selected: