HydPy-Dam-DB (detention basin model)¶
dam_detention
simulates the flood protection effects of dry detention basins that
actively control their release.
dam_detention
serves similar purposes as dam_lretention
but controls its outflow
actively according to “safe discharge” estimates, which are usually derived from
discharge values simulated (or measured) at other river segments. Opposed to
dam_lretention
, dam_detention
requires no relationship between water level and
(possible) release, as it tries to release the ideal amount of water and neglects any
“natural” lake retention effects. Due to this conceptual design, dam_detention
requires no numerical solution algorithms (like most other models in the HydPy-Dam
family) and is therefore solved analytically.
It is also possible to simulate wet basins by setting the TargetVolume
parameter to a
value larger than one. Note that even then, natural lake retention effects are
neglected, so dam_lretention
or a similar model of the HydPy-Dam family might be
preferable.
The information for estimating the safe discharge is transmitted via an arbitrary
number of observer nodes. Therefore, dam_detention
can react as soon as critical
situations somewhere else in the river network occur. Please note that an observer
node cannot be positioned downstream of the element that handles the observing
dam_detention
instance.
Integration tests¶
We perform all example calculations over a period of 20 days:
>>> from hydpy import Element, IntegrationTest, Node, pub
>>> pub.timegrids = "01.01.2000", "21.01.2000", "1d"
We prepare a dam_detention
model instance:
>>> from hydpy.models.dam_detention import *
>>> parameterstep("1d")
We begin with the simplest case of a single inlet and a single outlet node and leave the possibility of adding observer nodes for later consideration:
>>> inflow, outflow = Node("inflow"), Node("outflow")
>>> element = Element("element", inlets=inflow, outlets=outflow)
>>> element.model = model
The following test function instance facilitates the convenient execution of all integration tests:
>>> test = IntegrationTest(element)
>>> test.dateformat = "%d.%m."
>>> test.plotting_options.axis1 = fluxes.inflow, fluxes.outflow
>>> test.plotting_options.axis2 = states.watervolume
All integration tests shall start from dry initial conditions:
>>> test.inits = [(states.watervolume, 0.0), (logs.loggedadjustedevaporation, 0.0)]
>>> test.reset_inits()
>>> conditions = model.conditions
The following input time series stems from the integration tests on application model
dam_lretention
:
>>> inflow.sequences.sim.series = [
... 0.0, 1.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
... ]
The first tests deal with a dry detention basin:
>>> targetvolume(0.0)
>>> maximumvolume(1.5)
As the surface area (which becomes relevant only after adding submodels that include precipitation and evaporation into the water balance) is a fixed property, we set its size to zero, which is the “regular” surface area of dry detention basins:
>>> surfacearea(0.0)
The following three parameters require values even if no corresponding submodels are added (we plan to make this more convenient in the future):
>>> correctionprecipitation(1.0)
>>> correctionevaporation(1.0)
>>> weightevaporation(0.8)
The allowed release, which does not cause any harm directly downstream of the detention basin, is 2 m³/s:
>>> allowedrelease(2.0)
As dry detention basins cannot help much in ensuring a minimum flow (e.g. for ecological reasons), we set the minimum release to zero:
>>> minimumrelease(0.0)
We begin without any restrictions on the emptying speed:
>>> allowedwaterleveldrop(inf)
The following simple relationship between water volume and level does not affect the
basin’s behaviour as long as AllowedWaterLevelDrop
is set to infinity but enables
calculating the water level at the end of the respective simulation steps for
informational purposes:
>>> watervolume2waterlevel(PPoly.from_data(xs=[0.0, 1.0, 2.0], ys=[0.0, 1.0, 1.5]))
local protection¶
The current simple configuration shows the basic flood protection functionality of
dam_detention
. In this case, the protection is not perfect, but at least it reduces
the peak flow from 12 m³/s to less than 7 m³/s:
>>> test("dam_detention_local_protection")
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
restricted emptying¶
Setting the allowed water level drop to 0.15 m/day reduces the water release at the later declining phase of the flood event (due to the higher water level decrease for the same water volume decrease at this time):
>>> allowedwaterleveldrop(0.15)
>>> test("dam_detention_restricted_emptying")
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
remote protection¶
We now add the observer node gauge, which provides discharge information from somewhere else in the river network:
>>> gauge = Node("gauge")
>>> element.observers = gauge
Next, we add an exch_interp
submodel that takes the observer node’s discharge
information in converts it into a safe discharge estimate. From 0 to 3 m³/s, this
estimate decreases linearly from 3 to 0 m³/s (and remains at 0 m³/s for larger values):
>>> nmbsafereleasemodels(1)
>>> with model.add_safereleasemodel("exch_interp", position=0):
... observernodes("gauge")
... x2y(PPoly.from_data(xs=[0.0, 3.0, 6.0], ys=[3.0, 0.0, 0.0]))
Due to the change in the network configuration, we need to recreate the test function object:
>>> element.model.connect()
>>> 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
The inflow time series is initially identical to the one previously used but remains at 1 m³/s instead of decreasing to zero after the event:
>>> inflow.sequences.sim.series = [
... 0.0, 1.0, 6.0, 12.0, 10.0, 6.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
... ]
The observed discharge time also includes a runoff event, but this one occurs slightly later in time:
>>> gauge.sequences.sim.series = [
... 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
... 3.0, 6.0, 4.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0
... ]
During the first days of the simulation period, the detention basin adjusts its release, as in the previous examples, for local flood protection. After that, it reduces its release as much as possible to help decrease the flood at the remote location (which does not work too well because there is still much water left from the first event):
>>> test("dam_detention_remote_protection")
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
target volume¶
This example demonstrates how dam_detention
works for targeted water volumes larger
than zero:
>>> targetvolume(1.0)
Specifying a minimum release larger than zero now makes sense, as keeping the desired water volume during wet periods may provide the opportunity to release additional water in subsequent dry periods:
>>> minimumrelease(1.0)
The higher the targeted volume, the more reasonable it is to set the (time-averaged) surface area size to a value larger than one:
>>> surfacearea(1.44)
With a non-zero surface area, adding submodels that introduce precipitation and evaporation can make a relevant difference in the basin’s water balance:
>>> with model.add_precipmodel_v2("meteo_precip_io") as precipmodel:
... precipitationfactor(1.2)
... inputs.precipitation.prepare_series()
... inputs.precipitation.series = 0.0
... inputs.precipitation.series[1] = 50.0
>>> with model.add_pemodel_v1("evap_ret_io") as pemodel:
... evapotranspirationfactor(1.0)
... inputs.referenceevapotranspiration.prepare_series()
... inputs.referenceevapotranspiration.series = 6.0
We suppress the inflow directly after the event but reactivate it with 1.5 m³/s for the last few simulation steps:
>>> inflow.sequences.sim.series[9:16] = 0.0
>>> inflow.sequences.sim.series[16:] = 1.5
As expected, dam_detention
now keeps the targeted volume in flood-free periods as
long as the sum of inflow and precipitation exceeds the sum of evaporation and minimum
release:
>>> test("dam_detention_target_volume")
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.dam_detention.Model[source]¶
Bases:
AdHocModel
,MixinSimpleWaterBalance
,Main_PrecipModel_V2
,Main_PEModel_V1
,ExchangeModel_V1
HydPy-Dam-DB (detention basin model).
- The following “inlet update methods” are called in the given sequence at the beginning of each simulation step:
Pick_Inflow_V1
Update the inlet sequenceInflow
.
- The following “run methods” are called in the given sequence during each simulation step:
Calc_Precipitation_V1
If available, let a submodel that complies with thePrecipModel_V2
interface determine precipitation.Calc_AdjustedPrecipitation_V1
Adjust the given precipitation.Calc_PotentialEvaporation_V1
If available, let a submodel that complies with thePETModel_V1
interface determine potential evaporation.Calc_AdjustedEvaporation_V1
Adjust the given potential evaporation.Calc_AllowedWaterLevel_V1
Calculate the water level at the end of a simulation step that would follow from applying the allowed water level drop [m].Calc_AllowedDischarge_V3
Calculate the maximum discharge not leading to exceedance of the allowed water level drop.Update_WaterVolume_V5
Update the actual water volume based on inflow and precipitation.Calc_ActualEvaporation_WaterVolume_V1
Calculate the actual evaporation and update the stored water volume.Calc_SafeRelease_V1
Calculate the safe release as the minimum of the dam-specific allowed release and the values suggested by the safe release submodels.Calc_AimedRelease_WaterVolume_V1
Calculate the ideal controlled release and update the stored water volume.Calc_UnavoidableRelease_WaterVolume_V1
Calculate the water release that cannot be avoided due to limited storage capacity and update the stored water volume.Calc_WaterLevel_V1
Determine the water level based on an interpolation approach approximating the relationship between water volume and water level.Calc_Outflow_V6
Calculate the outflow as the sum of the aimed and the unavoidable release.
- The following “outlet update methods” are called in the given sequence at the end of each simulation step:
Pass_Outflow_V1
Update the outlet link sequenceQ
.
- 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:
Return_WaterLevelError_V1
Calculate and return the difference between the allowed water level and the water level that corresponds to the given water volume.
- Users can hook submodels into the defined main model if they satisfy one of the following interfaces:
PrecipModel_V2
Simple interface for determining precipitation in one step.PETModel_V1
Simple interface for calculating all potential evapotranspiration values in one step.ExchangeModel_V1
Interface for exchanging modified, scalar data of arbitrary type.
- The following “submodels” might be called by one or more of the implemented methods or are meant to be directly called by the user:
PegasusWaterVolume
Pegasus iterator for finding the water volume corresponding to the allowed water level.
- 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.
- safereleasemodels¶
Vector of submodels that comply with the following interface: ExchangeModel_V1.
- add_safereleasemodel¶
Initialise the given safereleasemodel that follows the
ExchangeModel_V1
interface.
- REUSABLE_METHODS: ClassVar[tuple[type[ReusableMethod], ...]] = ()¶
- class hydpy.models.dam_detention.AideSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
AideSequences
Aide sequences of model dam_detention.
- The following classes are selected:
AllowedDischarge()
Discharge threshold that should not be overcut by the actual discharge [m³/s].AllowedWaterLevel()
The water level at the end of a simulation step that would follow from applying the allowed water level drop [m].
- class hydpy.models.dam_detention.ControlParameters(master: Parameters, cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
SubParameters
Control parameters of model dam_detention.
- The following classes are selected:
SurfaceArea()
Average size of the water surface [km²].CorrectionPrecipitation()
Precipitation correction factor [-].CorrectionEvaporation()
Evaporation correction factor [-].WeightEvaporation()
Time weighting factor for evaporation [-].MinimumRelease()
Minimum water release [m³/s].WaterVolume2WaterLevel()
An interpolation function that describes the relationship between water level 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³].MaximumVolume()
Maximum storable volume of water where uncontrolled discharge can be prevented [Mio. m³].NmbSafeReleaseModels()
The number of submodels that suggest release values that serve for flood protection at remote locations [-].
- class hydpy.models.dam_detention.DerivedParameters(master: Parameters, cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
SubParameters
Derived parameters of model dam_detention.
- The following classes are selected:
TOY()
References thetimeofyear
index array provided by the instance of classIndexer
available in modulepub
[-].Seconds()
Length of the actual simulation step size [s].InputFactor()
Factor for converting meteorological input from mm/T to million m³/s.
- class hydpy.models.dam_detention.FactorSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
FactorSequences
Factor sequences of model dam_detention.
- The following classes are selected:
WaterLevel()
Water level [m].
- class hydpy.models.dam_detention.FluxSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
FluxSequences
Flux sequences of model dam_detention.
- 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].SafeRelease()
Water release that is considered safe in terms of flood protection [m³/s].AimedRelease()
Ideal controlled water release [m³/s].UnavoidableRelease()
Water release that cannot be avoided due to limited storage capacity [m³/s].Outflow()
Total outflow [m³/s].
- class hydpy.models.dam_detention.InletSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
InletSequences
Inlet sequences of model dam_detention.
- The following classes are selected:
Q()
Inflow [m³/s].
- class hydpy.models.dam_detention.LogSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
LogSequences
Log sequences of model dam_detention.
- The following classes are selected:
LoggedAdjustedEvaporation()
Logged adjusted evaporation [m³/s].
- class hydpy.models.dam_detention.OutletSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
OutletSequences
Outlet sequences of model dam_detention.
- The following classes are selected:
Q()
Outflow [m³/s].
- class hydpy.models.dam_detention.StateSequences(master: Sequences, cls_fastaccess: type[TypeFastAccess_co] | None = None, cymodel: CyModelProtocol | None = None)¶
Bases:
StateSequences
State sequences of model dam_detention.
- The following classes are selected:
WaterVolume()
Water volume [million m³].