HydPy-Dam-L-Res (reservoir model adopted from LARSIM)¶
dam_lreservoir is a relatively simple reservoir model, similar to the “TALS” model of
LARSIM. It combines the features of dam_llake (“controlled lake”) and
dam_lretention (“retention basin”). Additionally, it allows controlling the stored
water volume via defining target values that can vary seasonally.
Like dam_lretention, dam_lreservoir allows for combining controlled, “harmless
outflow” (via parameter AllowedRelease) and uncontrolled, “spillway outflow” (via
parameter WaterLevel2FloodDischarge), and like dam_llake, it allows restricting the
speed of the water level decrease during periods with little inflow via parameter
AllowedWaterLevelDrop (only through reducing the controlled outflow, of course).
Before continuing, please first read the documentation on these two application models.
The additional feature of dam_lreservoir is its ability to track seasonal target
volumes. We define these target volumes via parameter TargetVolume. The parameters
VolumeTolerance, TargetRangeAbsolute, and TargetRangeRelative serve to yield more
smooth and realistic reservoir responses for slight deviations from the given target
values. Setting TargetRangeRelative to 0.2 and both other parameters to zero
corresponds to selecting the “TALSPERRE SOLLRANGE” option in LARSIM. Please see the
following examples and the documentation on method Calc_ActualRelease_V3 for more
information on setting and combining the individual parameter values for different use
cases.
Integration tests¶
Note
When new to HydPy, consider reading section Integration Tests first.
We prepare a test set similar to the ones for application models dam_llake and
dam_lretention, including an identical inflow series and an identical relationship
between stage and volume:
>>> from hydpy import IntegrationTest, Element, pub
>>> pub.timegrids = "01.01.2000", "21.01.2000", "1d"
>>> from hydpy.models.dam_lreservoir import *
>>> parameterstep("1d")
>>> element = Element("element", inlets="input_", outlets="output")
>>> element.model = model
>>> test = IntegrationTest(element)
>>> test.dateformat = "%d.%m."
>>> test.plotting_options.axis1 = fluxes.inflow, fluxes.outflow
>>> test.plotting_options.axis2 = states.watervolume
>>> test.inits = [
... (states.watervolume, 0.0),
... (logs.loggedadjustedevaporation, 0.0)]
>>> test.reset_inits()
>>> conditions = model.conditions
>>> watervolume2waterlevel(PPoly.from_data(xs=[0.0, 1.0], ys=[0.0, 1.0]))
>>> surfacearea(1.44)
>>> catchmentarea(86.4)
>>> correctionprecipitation(1.2)
>>> correctionevaporation(1.2)
>>> weightevaporation(0.8)
>>> thresholdevaporation(0.0)
>>> toleranceevaporation(0.001)
>>> commission("1900-01-01")
>>> with model.add_precipmodel_v2("meteo_precip_io") as precipmodel:
... precipitationfactor(1.0)
>>> precipmodel.prepare_inputseries()
>>> precipmodel.sequences.inputs.precipitation.series = [
... 0.0, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
... 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
>>> element.inlets.input_.sequences.sim.series = [
... 0.0, 0.0, 6.0, 12.0, 10.0, 6.0, 3.0, 2.0, 1.0, 0.0,
... 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
base scenario¶
First, we again use the linear relation between discharge and stage used
throughout the integration tests of dam_llake and in the base example of dam_lretention:
>>> waterlevel2flooddischarge(PPoly.from_data(xs=[0.0, 1.0], ys=[0.0, 10.0]))
Additionally, we set some of the remaining parameter values extremely high or low to ensure the reservoir stores all water except the one activating the spillway, which becomes “flood discharge”:
>>> targetvolume(100.0)
>>> neardischargeminimumthreshold.shape = 1
>>> neardischargeminimumthreshold.values = -100.0
>>> targetrangeabsolute(0.1)
>>> targetrangerelative(0.2)
>>> watervolumeminimumthreshold(0.0)
>>> volumetolerance(0.1)
>>> dischargetolerance(0.1)
>>> allowedrelease(100.0)
>>> allowedwaterleveldrop(100.0)
Due to the same the neural network configuration, the results are identical to the ones
of the base example of dam_llake and the
base example of dam_lretention:
>>> test("dam_lreservoir_base_scenario")
Click to see the table
Click to see the graphThere is no indication of an error in the water balance:
>>> from hydpy import round_
>>> round_(model.check_waterbalance(conditions))
0.0
spillway¶
When we reuse the more realistic relationship between flood discharge and stage of the
spillway example on dam_lretention, we again get the
same flood discharge time series:
>>> waterlevel2flooddischarge(ANN(weights_input=10.0, weights_output=50.0,
... intercepts_hidden=-20.0, intercepts_output=0.0))
>>> test("dam_lreservoir_spillway")
Click to see the table
Click to see the graphThere is no indication of an error in the water balance:
>>> round_(model.check_waterbalance(conditions))
0.0
target volume¶
During dry periods, application model dam_lretention generally releases all its water
until the basin runs dry, as long as AllowedRelease is larger than zero. Application
model dam_lreservoir instead allows fo defining target volumes. dam_lreservoir
tries to control its outflow so that the actual volume approximately equals the
(potentially seasonally varying) target volume. However, it cannot release arbitrary
amounts of water to fulfil this task due to its priority to release a predefined
minimum amount of water (for ecological reasons) and its second priority to not release
too much water (for flood protection). In this example, we activate these mechanisms
by changing some corresponding parameter values (see the documentation on method
Calc_ActualRelease_V3 for more detailed examples, including the numerous corner
cases):
>>> targetvolume(0.5)
>>> neardischargeminimumthreshold(0.1)
>>> allowedrelease(4.0)
>>> allowedwaterleveldrop(1.0)
Compared with the allowed release results of dam_lretention,
dam_lreservoir dampens the given flood event less efficiently. dam_lretention
releases all initial inflow, while dam_lreservoir stores most of it until it reaches
the target volume of 0.5 million m³. After peak flow, dam_lreservoir first releases
its water as fast as allowed but then tries to meet the target volume again. The slow
negative trend away from the target value at the end of the simulation period results
from the lack of inflow while still needing to release at least 0.1 m³/s:
>>> test("dam_lreservoir_target_volume")
Click to see the table
Click to see the graphThere is no indication of an error in the water balance:
>>> round_(model.check_waterbalance(conditions))
0.0
higher accuracy¶
The first water volume calculated in the sharp transitions example is negative, resulting from the limited numerical accuracy of the underlying integration algorithm. We can decrease such errors by defining smaller error tolerances but at the risk of relevant increases in computation times (especially in case one applies zero smoothing values):
>>> solver.abserrormax(1e-6)
>>> test("dam_lreservoir_higher_accuracy")
Click to see the table
Click to see the graphThere is no indication of an error in the water balance:
>>> round_(model.check_waterbalance(conditions))
0.0
target range¶
In the last example, the reservoir behaviour changes abruptly when the actual volume
transcends the target volume. According to its documentation, LARSIM predicts
unrealistic jumps in discharge in such cases. To solve this issue, LARSIM offers
the “TALSPERRE SOLLRANGE” option, which ensures smoother transitions between 80 % and
120 % of the target volume, accomplished by linear interpolation. dam_lreservoir
should never output similar jumps as it controls the correctness of its results. As a
drawback, correcting these jumps (which still occur “unseeable” and possibly multiple
times within each affected simulation time step) costs computation time. Hence, at
least for small smoothing parameter values, dam_lreservoir can also benefit from this
approach. You can define the interpolation range freely via TargetRangeAbsolute and
TargetRangeRelative, depending on your specific needs. Setting the latter to 0.2
corresponds to the original “TALSPERRE SOLLRANGE”-configuration:
>>> targetrangerelative(0.2)
>>> test("dam_lreservoir_target_range")
Click to see the table
Click to see the graphThere is no indication of an error in the water balance:
>>> round_(model.check_waterbalance(conditions))
0.0
minimum volume¶
In all the examples above, the dam would run dry entirely after a certain time to
fulfil the downstream demand defined by parameter NearDischargeMinimumThreshold.
Usually, this is neither desired nor technically possible. The following example shows
that the parameter WaterVolumeMinimumThreshold allows setting a minimum amount of
water below which no release occurs:
>>> watervolumeminimumthreshold(0.45)
>>> test("dam_lreservoir_minimum_volume")
Click to see the table
Click to see the graphThere is no indication of an error in the water balance:
>>> round_(model.check_waterbalance(conditions))
0.0
evaporation¶
This example takes up the evaporation example of
application model dam_llake. The reservoir can no longer maintain the target water
level at the end of the simulation period due to missing precipitation or inflow for
compensating evaporation:
>>> with model.add_pemodel_v1("evap_ret_io") as pemodel:
... evapotranspirationfactor(1.0)
>>> pemodel.prepare_inputseries()
>>> pemodel.sequences.inputs.referenceevapotranspiration.series = 10 * [1.0] + 10 * [5.0]
>>> test("dam_lreservoir_evaporation")
Click to see the table
Click to see the graphThere is no indication of an error in the water balance:
>>> round_(model.check_waterbalance(conditions))
0.0
commissioning¶
This example extends the previous one with the commissioning mechanism shown and
discussed in the analogue example of application model
dam_llake:
>>> commission("2000-01-04")
>>> pemodel.sequences.inputs.referenceevapotranspiration.series = 50.0
>>> test("dam_lreservoir_commissioning")
Click to see the table
Click to see the graph>>> round_(model.check_waterbalance(conditions))
0.0
- class hydpy.models.dam_lreservoir.Model[source]¶
Bases:
ELSIEModel,MixinSimpleWaterBalance,Main_PrecipModel_V2,Main_PEModel_V1HydPy-Dam-L-Res (reservoir model adopted from LARSIM).
- The following “inlet update methods” are called in the given sequence at the beginning of each simulation step:
Calc_Precipitation_V1If available, let a submodel that complies with thePrecipModel_V2interface determine precipitation.Calc_PotentialEvaporation_V1If available, let a submodel that complies with thePETModel_V1interface determine potential evaporation.Calc_AdjustedEvaporation_V1Adjust the given potential evaporation.
- The following methods define the relevant components of a system of ODE equations (e.g. direct runoff):
Calc_AdjustedPrecipitation_V1Adjust the given precipitation.Pick_Inflow_V1Update the inlet sequenceInflow.Calc_WaterLevel_V1Determine the water level based on an interpolation approach approximating the relationship between water volume and water level.Calc_ActualEvaporation_V3Calculate the actual evaporation before and after the commission date.Calc_SurfaceArea_V1Determine the surface area based on an interpolation approach approximating the relationship between the water level and the surface area.Calc_AllowedDischarge_V2Calculate the maximum discharge not leading to exceedance of the allowed water level drop.Calc_ActualRelease_V3Calculate an actual water release that tries to change the water storage into the direction of the actual target volume without violating the required minimum and the allowed maximum flow.Calc_FloodDischarge_V1Calculate the discharge during and after a flood event based on seasonally varying interpolation approaches approximating the relationship(s) between discharge and water stage.Calc_Outflow_V7Calculate the total outflow of the dam before and after the commission date
- The following methods define the complete equations of an ODE system (e.g. change in storage of fast water due to effective precipitation and direct runoff):
Update_WaterVolume_V1Update the actual water volume.
- The following “outlet update methods” are called in the given sequence at the end of each simulation step:
Calc_WaterLevel_V1Determine the water level based on an interpolation approach approximating the relationship between water volume and water level.Pass_Outflow_V1Update the outlet link sequenceQ.
- Users can hook submodels into the defined main model if they satisfy one of the following interfaces:
PrecipModel_V2Simple interface for determining precipitation in one step.PETModel_V1Simple interface for calculating all potential evapotranspiration values in one step.
- precipmodel: modeltools.SubmodelProperty¶
Optional submodel that complies with the following interface: PrecipModel_V2.
- pemodel: modeltools.SubmodelProperty¶
Optional submodel that complies with the following interface: PETModel_V1.
- REUSABLE_METHODS: ClassVar[tuple[type[ReusableMethod], ...]] = ()¶
- numconsts: NumConstsELS¶
- numvars: NumVarsELS¶
- cymodel: CyModelProtocol | None¶
- parameters: parametertools.Parameters¶
- sequences: sequencetools.Sequences¶
- masks: masktools.Masks¶
- class hydpy.models.dam_lreservoir.AideSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
AideSequencesAide sequences of model dam_lreservoir.
- The following classes are selected:
SurfaceArea()Surface area [km²].AllowedDischarge()Discharge threshold that should not be overcut by the actual discharge [m³/s].
- class hydpy.models.dam_lreservoir.ControlParameters(master: Parameters, cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
SubParametersControl parameters of model dam_lreservoir.
- The following classes are selected:
SurfaceArea()Average size of the water surface [km²].CatchmentArea()Size of the catchment draining into the dam [km²].CorrectionPrecipitation()Precipitation correction factor [-].CorrectionEvaporation()Evaporation correction factor [-].WeightEvaporation()Time weighting factor for evaporation [-].NearDischargeMinimumThreshold()Discharge threshold of a cross-section near the dam not to be undercut by the actual discharge [m³/s].WaterVolumeMinimumThreshold()The minimum operating water volume of the dam [million m³].ThresholdEvaporation()The water level at which actual evaporation is 50 % of potential evaporation [m].ToleranceEvaporation()A tolerance value defining the steepness of the transition of actual evaporation between zero and potential evaporation [m].WaterVolume2WaterLevel()An interpolation function that describes the relationship between water level and water volume [-].WaterLevel2FloodDischarge()An interpolation function that describesg the relationship between flood discharge and water volume [-].AllowedWaterLevelDrop()The highest allowed water level decrease [m/T].AllowedRelease()The maximum water release not causing any harm downstream [m³/s].TargetVolume()The desired volume of water required within the dam at specific times of the year [Mio. m³].TargetRangeAbsolute()The absolute interpolation range related to parameterTargetVolume[Mio. m³].TargetRangeRelative()The relative interpolation range related to parameterTargetVolume[-].VolumeTolerance()Smoothing parameter for volume-related smoothing operations [Mio. m³].DischargeTolerance()Smoothing parameter for discharge-related smoothing operations [m³/s].Commission()Commission date [-].
- class hydpy.models.dam_lreservoir.DerivedParameters(master: Parameters, cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
SubParametersDerived parameters of model dam_lreservoir.
- The following classes are selected:
TOY()References thetimeofyearindex array provided by the instance of classIndexeravailable in modulepub[-].Seconds()Length of the actual simulation step size [s].InputFactor()Factor for converting meteorological input from mm/T to million m³/s.SmoothParEvaporation()Smoothing parameter to be derived fromToleranceEvaporationfor smoothing kernelsmooth_logistic1()[m].VolumeSmoothParLog1()Smoothing parameter to be derived fromVolumeTolerancefor smoothing kernelsmooth_logistic1()[million m³].VolumeSmoothParLog2()Smoothing parameter to be derived fromVolumeTolerancefor smoothing kernelsmooth_logistic2()[million m³].DischargeSmoothPar()Smoothing parameter to be derived fromDischargeTolerancefor smoothing kernelssmooth_logistic2(),smooth_min1(), andsmooth_max1()[m³/s].
- class hydpy.models.dam_lreservoir.FactorSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
FactorSequencesFactor sequences of model dam_lreservoir.
- The following classes are selected:
WaterLevel()Water level [m].
- class hydpy.models.dam_lreservoir.FluxSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
FluxSequencesFlux sequences of model dam_lreservoir.
- The following classes are selected:
Precipitation()Precipitation [mm].AdjustedPrecipitation()Adjusted precipitation [m³/s].PotentialEvaporation()Potential evaporation [mm/T].AdjustedEvaporation()Adjusted evaporation [m³/s].ActualEvaporation()Actual evaporation [m³/s].Inflow()Total inflow [m³/s].ActualRelease()Actual water release thought for reducing drought events downstream [m³/s].FloodDischarge()Water release associated with flood events [m³/s].Outflow()Total outflow [m³/s].
- class hydpy.models.dam_lreservoir.InletSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
InletSequencesInlet sequences of model dam_lreservoir.
- The following classes are selected:
Q()Inflow [m³/s].
- class hydpy.models.dam_lreservoir.LogSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
LogSequencesLog sequences of model dam_lreservoir.
- The following classes are selected:
LoggedAdjustedEvaporation()Logged adjusted evaporation [m³/s].
- class hydpy.models.dam_lreservoir.OutletSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
OutletSequencesOutlet sequences of model dam_lreservoir.
- The following classes are selected:
Q()Outflow [m³/s].
- class hydpy.models.dam_lreservoir.SolverParameters(master: Parameters, cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
SubParametersSolver parameters of model dam_lreservoir.
- The following classes are selected:
AbsErrorMax()Absolute numerical error tolerance [m³/s].RelErrorMax()Relative numerical error tolerance [1/T].RelDTMin()Smallest relative integration time step size allowed [-].RelDTMax()Largest relative integration time step size allowed [-].MaxEval()Maximum number of function evaluations before stopping the Explicit Labatto Sequence [-].MaxCFL()Maximum Caurant-Friedrichs-Lewy number for using the Explicit Labatto Sequence [-].
- class hydpy.models.dam_lreservoir.StateSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
StateSequencesState sequences of model dam_lreservoir.
- The following classes are selected:
WaterVolume()Water volume [million m³].