HydPy-H-HBV96 (adoption of SMHI-IHMS-HBV96)

hland_96 closely emulates the “land components” of HBV96 (Lindström et al., 1997) while providing additional functionalities (for example, the land-use type SEALED). We implemented it on behalf of the German Federal Institute of Hydrology (BfG) to model large river basins in central Europe.

The following list summarises the main components of hland_96:

  • Apply different correction factors to the liquid and the frozen amount of precipitation.

  • Use a submodel like evap_aet_hbv96 for calculating actual evapotranspiration (which, for best compatibility with Lindström et al. (1997), could use evap_pet_hbv96 for estimating potential evapotranspiration).

  • Simulate interception via simple “bucket” storages.

  • Reflect local spatial heterogeneity of snow by defining snow classes.

  • Redistribute snow from higher to lower zones to prevent “snow towers” in high mountain areas.

  • Use a degree-day factor reflecting the seasonal variability of radiation for calculating snowmelt.

  • Consider both the melting of ice and the (re)freezing of water within the snow layer.

  • Apply a saturation excess mechanism for the generation of direct runoff.

  • Calculate a (nearly) complete and immediate runoff response for sealed areas.

  • Provide an optional “response area” option, which modifies the usual direct runoff and percolation calculation.

  • Distinguish between an upper zone layer related to direct runoff and a lower zone layer related to base flow.

  • Pass percolation from the upper to the lower zone layer and capillary rise from the upper zone layer to the soil layer.

  • Consider water areas as “groundwater lakes” that are part of the lower zone layer.

  • In contrast to the original HBV96 implementation, handle both the upper and the lower zone layers as nonlinear storages.

  • Conceptualise the melting of glacial ice with an additional application of the degree-day method.

  • Optionally, use a submodel like rconc_uh to calculate runoff concentration.

The following figure shows the general structure of hland_96. Note that zones of type FIELD and FOREST are based on the same set of process equations. In this scheme, the submodel rconc_uh is included (which is optional):

_images/HydPy-H-HBV96.png

Integration tests

Note

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

The following integration tests rely on the meteorological input data used for testing the application model lland_dd. The values of the input sequences P (precipitation) and T (temperature) are copy-pasted. The NormalEvapotranspiration values are the ReferenceEvapotranspiration values calcuted by evap_ret_tw2002 but divided by 0.4 to account for the selected value of the evaporation adjustment factor EvapotranspirationFactor. Hopefully, this will make it easier to draw comparisons between both models.

We perform all integration tests over five days with a simulation step of one hour:

>>> from hydpy import pub
>>> pub.timegrids = "01.01.2000", "05.01.2000", "1h"

First, we prepare the model instance and build the connections to element land and node outlet:

>>> from hydpy.models.hland_96 import *
>>> parameterstep("1h")
>>> from hydpy import Node, Element
>>> outlet = Node("outlet")
>>> land = Element("land", outlets=outlet)
>>> land.model = model

We perform most tests using a single zone of 1 km³ at an altitude of 100 m, consisting of a single snow class:

>>> nmbzones(1)
>>> sclass(1)
>>> area(1.0)
>>> zonearea(1.0)
>>> zonez(1.0)

We assume a runoff coefficient of one for zones defined as SEALED:

>>> psi(1.0)

For a start, we select FIELD as the only zone type (note that the results for the land-use type FOREST would be the same):

>>> zonetype(FIELD)

The following set of control parameter values tries to configure application model hland_96 in a manner that allows retracing the influence of the different implemented methods on the shown results:

>>> pcorr(1.1)
>>> pcalt(0.1)
>>> rfcf(1.1)
>>> sfcf(1.3)
>>> tcorr(0.6)
>>> tcalt(0.6)
>>> icmax(2.0)
>>> sfdist(1.0)
>>> smax(inf)
>>> sred(0.0)
>>> tt(0.0)
>>> ttint(2.0)
>>> dttm(1.0)
>>> cfmax(0.5)
>>> cfvar(0.1)
>>> gmelt(1.0)
>>> gvar(0.2)
>>> cfr(0.1)
>>> whc(0.4)
>>> fc(200.0)
>>> beta(2.0)
>>> percmax(0.5)
>>> cflux(0.1)
>>> alpha(2.0)
>>> k(0.001)
>>> k4(0.005)
>>> gamma(0.0)

hland_96 requires a submodel for calculating actual evapotranspiration. Therefore, we select evap_aet_hbv96, which also closely follows equations used by HBV96 (Lindström et al., 1997). The same holds for evap_pet_hbv96, which will provide evap_aet_hbv96 with HBV96-like potential evapotranspiration estimates:

>>> with model.add_aetmodel_v1("evap_aet_hbv96"):
...     temperaturethresholdice(0.0)
...     soilmoisturelimit(0.8)
...     excessreduction(0.5)
...     with model.add_petmodel_v1("evap_pet_hbv96"):
...         evapotranspirationfactor(0.7)
...         airtemperaturefactor(0.1)
...         altitudefactor(-0.1)
...         precipitationfactor(0.1)

hland_96 can use a submodel that follows the RConcModel_V1 to consider additional runoff concentration processes. A possible choice is rconc_uh, which implements the unit hydrograph method and provides a convenient way to set the required ordinates in the triangle shape typical for HBV96:

>>> with model.add_rconcmodel_v1("rconc_uh"):
...     uh("triangle", tb=3.0)

We initialise a test function object, which prepares and runs the tests and prints their results for the given sequences:

>>> from hydpy import IntegrationTest
>>> IntegrationTest.plotting_options.axis1 = inputs.p, fluxes.rt, fluxes.qt
>>> IntegrationTest.plotting_options.axis2 = inputs.t
>>> test = IntegrationTest(land)
>>> test.dateformat = "%d/%m %H:00"

Initially, relative soil moisture is 50 %, the lower zone layer contains only 10 mm, and all other storages are empty:

>>> test.inits = ((states.ic, 0.0),
...               (states.sp, 0.0),
...               (states.wc, 0.0),
...               (states.sm, 100.0),
...               (states.uz, 0.0),
...               (states.lz, 10.0),
...               (model.rconcmodel.sequences.logs.quh, 0.05))

As mentioned above, the values of the input sequences P and T of hland_96 stem from here. For educational purposes, we again use unrealistically high values of NormalEvapotranspiration. For the sake of simplicity, we define NormalAirTemperature to be constantly 1 °C below T:

>>> inputs.p.series = (
...     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.2, 0.0, 0.0, 1.3, 5.6, 2.9, 4.9, 10.6, 0.1, 0.7, 3.0, 2.1, 10.4, 3.5, 3.4,
...     1.2, 0.1, 0.0, 0.0, 0.4, 0.1, 3.6, 5.9, 1.1, 20.7, 37.9, 8.2, 3.6, 7.5, 18.5,
...     15.4, 6.3, 1.9, 4.9, 2.7, 0.5, 0.2, 0.5, 2.4, 0.4, 0.2, 0.0, 0.0, 0.3, 2.6,
...     0.7, 0.3, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
...     1.3, 0.0, 0.0, 0.0, 0.7, 0.4, 0.1, 0.4, 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)
>>> inputs.t.series = (
...     21.2, 19.4, 18.9, 18.3, 18.9, 22.5, 25.1, 28.3, 27.8, 31.4, 32.2, 35.2, 37.1,
...     31.2, 24.3, 25.4, 25.9, 23.7, 21.6, 21.2, 20.4, 19.8, 19.6, 19.2, 19.2, 19.2,
...     18.9, 18.7, 18.5, 18.3, 18.5, 18.8, 18.8, 19.0, 19.2, 19.3, 19.0, 18.8, 18.7,
...     17.8, 17.4, 17.3, 16.8, 16.5, 16.3, 16.2, 15.5, 14.6, 14.7, 14.6, 14.1, 14.3,
...     14.9, 15.7, 16.0, 16.7, 17.1, 16.2, 15.9, 16.3, 16.3, 16.4, 16.5, 18.4, 18.3,
...     18.1, 16.7, 15.2, 13.4, 12.4, 11.6, 11.0, 10.5, 11.7, 11.9, 11.2, 11.1, 11.9,
...     12.2, 11.8, 11.4, 11.6, 13.0, 17.1, 18.2, 22.4, 21.4, 21.8, 22.2, 20.1, 17.8,
...     15.2, 14.5, 12.4, 11.7, 11.9)
>>> petinputs = model.aetmodel.petmodel.sequences.inputs
>>> petinputs.normalairtemperature.series = inputs.t.series - 1.0
>>> petinputs.normalevapotranspiration.series = (
...     0.100707, 0.097801, 0.096981, 0.09599, 0.096981, 0.102761, 0.291908, 1.932875,
...     4.369536, 7.317556, 8.264362, 9.369867, 5.126178, 6.62503, 7.397619, 2.39151,
...     1.829834, 1.136569, 0.750986, 0.223895, 0.099425, 0.098454, 0.098128, 0.097474,
...     0.097474, 0.097474, 0.096981, 0.096652, 0.096321, 0.09599, 0.187298, 1.264612,
...     3.045538, 1.930758, 2.461001, 6.215945, 3.374783, 8.821555, 4.046025, 2.110757,
...     2.239257, 2.877848, 1.591452, 0.291604, 0.092622, 0.092451, 0.091248, 0.089683,
...     0.089858, 0.089683, 0.088805, 0.089157, 0.090207, 0.091593, 0.154861, 0.470369,
...     1.173726, 4.202296, 4.359715, 5.305753, 5.376027, 4.658915, 7.789594, 4.851567,
...     5.30692, 3.286036, 1.506216, 0.274762, 0.087565, 0.085771, 0.084317, 0.083215,
...     0.082289, 0.0845, 0.084864, 0.083584, 0.0834, 0.084864, 0.310229, 1.391958,
...     3.195876, 5.191651, 7.155036, 8.391432, 8.391286, 10.715238, 9.383394, 7.861915,
...     6.298329, 2.948416, 1.309232, 0.32955, 0.089508, 0.085771, 0.0845, 0.084864)

We memorise the initial conditions to check later if hland_96 holds the water balance:

>>> test.reset_inits()
>>> conditions = model.conditions

field

In the first example, we disable the RespArea option and set a relatively large value for the accuracy-related parameter RecStep:

>>> resparea(False)
>>> recstep(100)

The following results show the response of application model hland_96 to the given extreme precipitation event. The intense evaporation weakens the response markedly. One striking difference to other models like lland_dd is the block-like appearance of percolation (Perc), which is one reason for the unusual transitions between event periods (consisting of both runoff components Q0 and Q1) and the subsequent pure base flow periods (consisting of Q1 only):

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

no rconc submodel

Using a submodel like rconc_uh as an additional means for calculating runoff concentration is optional. We repeat the last integration test without one, so there is less delay in the catchment’s simulated outflow.

>>> model.rconcmodel = None
>>> test("hland_96_no_rconc_submodel")
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

For the next tests, we use the rconc submodel again:

>>> with model.add_rconcmodel_v1("rconc_uh"):
...     uh("triangle", tb=3.0)

contributing area

We can substantially change the functioning of hland_96 by enabling its RespArea option, which decreases Perc but increases Q0 in dry periods (more concretely: in periods with dry soils). Hence the simulated result of Perc appears less “block-like” and reaches its maximum at the same time as the result of SM does, whereas Q0 shows more pronounced peaks in the initial subperiod when the soil is not saturated yet:

>>> resparea(True)
>>> test("hland_96_resparea")
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

low accuracy

The following example indicates caution when reducing the value of RecStep to save computation time. Setting RecStep to 1, which is the smallest possible value, results in low accuracies. You can see this by comparing the time series of Q0 calculated in this and the last example. The time series of this example is much more wrong, as the peak of Q0 is high above the peak of R, which is physically impossible:

>>> recstep(1)
>>> test("hland_96_low_accuracy")
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

sealed area

hland_96 tends to underestimate the runoff response to small or medium-sized rain events that fall on dry soils. One means to improve the situation is to activate the contributing area option. Unfortunately, this option has the side-effect that decreasing the soil moisture increases the direct discharge released by the upper zone storage. Defining sealed areas provides an alternative to the “contributing area” approach. The following example shows that a zone classified as SEALED converts all precipitation, which is not intercepted or stored within a snow cover, to runoff and directly passes it to the runoff concentration module. Thus, the definition of sealed surfaces causes higher dynamics in the simulated flood hydrograph that is most perceptible during dry conditions:

>>> recstep(100)
>>> zonetype(SEALED)
>>> test("hland_96_sealed")
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

internal lake

In the following example, we demonstrate the functionality of zones of type ILAKE. For such “internal lakes”, only the lower zone storage (LZ) is relevant (all other storage values are zero). Precipitation (PC) adds directly to, and evaporation (EL) subtracts directly from LZ. The latter occurs even when LZ is empty, possibly resulting in negative storage values in drought periods. When using evap_aet_hbv96 as the actual evapotranspiration submodel, the only condition preventing lake evaporation (EL) is the occurrence of lake ice, which exists when the actual temperature (“TC”) is below the threshold temperature (TemperatureThresholdIce). In our example, we set it to the unrealistic value of 13°C, resulting in a zero EL for the last day of the simulation period:

>>> zonetype(ILAKE)
>>> model.aetmodel.parameters.control.temperaturethresholdice(13.0)
>>> test("hland_96_ilake")
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

snow classes

In this example, we divide the single zone into two snow classes. All snow classes of a specific zone are generally identical in size and process parameterisation. The only difference is that they receive different amounts of (frozen or liquid) precipitation. The extent of this difference depends on parameter SFDist, for which we apply the standard “linear-mode” value 0.2:

>>> sclass(2)
>>> sfdist(linear=0.2)

We reset the land-use type to FIELD and modify the input temperature series to activate the snow routines. In the first half of the simulation period, the temperature is -20°C, and in the second half, it is +20°C:

>>> zonetype(FIELD)
>>> t_series = inputs.t.series.copy()
>>> tn_series = petinputs.normalairtemperature.series.copy()
>>> inputs.t.series[:48] = -20.0
>>> inputs.t.series[48:] = 20.0
>>> petinputs.normalairtemperature.series = inputs.t.series

The second snow class receives more precipitation and thus builds a deeper snow layer. At the beginning of the warm period, the melting rates of both classes are identical. Due to the huger ice content, the second class possesses a higher storage capacity and releases its meltwater later. Also, it takes longer until it is finally snow-free:

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

glacier

This example demonstrates the functionality of zones of type GLACIER. GLACIER zones are similar to zones of type FIELD or FOREST but possess neither an interception nor a soil module. Instead, they pass precipitation and meltwater to the upper zone storage (UZ) directly. The snow routines of GLACIER, FIELD, and FOREST zones are identical. Additional glacier melt can only occur if no snow covers the glacier. In the next test run, we can distinguish the simulation period into three subperiods. On the first two days (-20°C), the snow layer builds up. On the third day (+20°C and SP > 0), the snow melts and (with some time delay) releases meltwater. On the fourth day (+20°C and SP = 0), an increased amount of water is passed to UZ due to GMelt being larger than CFMax:

>>> zonetype(GLACIER)
>>> test("hland_96_glacier")
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

multiple zones

All of the above examples deal with a subbasin consisting of a single zone. Hence, none of them is suitable to check if, for instance, the aggregation of fluxes addressing different spatial extents does not introduce errors into the water balance. The following example fills this gap. We restore the initial field example settings, except defining five zones of different land-use types and sizes. The variations between the responses of the land-use types are as to be expected:

>>> resparea(False)
>>> name2value = {par.name: par.value for par in control}
>>> nmbzones(5)
>>> sclass(1)
>>> area(15.0)
>>> zonearea(5.0, 4.0, 3.0, 2.0, 1.0)
>>> zonetype(FIELD, FOREST, GLACIER, ILAKE, SEALED)
>>> sfdist(1.0)
>>> for name, value in name2value.items():
...     if name not in ("nmbzones", "sclass", "area", "zonearea", "zonetype", "sfdist"):
...         control[name].value = value
>>> model.add_aetmodel_v1.update(model, model.aetmodel, refresh=True)
>>> model.aetmodel.add_petmodel_v1.update(model.aetmodel, model.aetmodel.petmodel, refresh=True)
>>> aetcontrol = model.aetmodel.parameters.control
>>> aetcontrol.temperaturethresholdice(0.0)
>>> aetcontrol.soilmoisturelimit(0.8)
>>> aetcontrol.excessreduction(0.5)
>>> petcontrol = model.aetmodel.petmodel.parameters.control
>>> petcontrol.evapotranspirationfactor(0.7)
>>> petcontrol.airtemperaturefactor(0.1)
>>> petcontrol.altitudefactor(-0.1)
>>> petcontrol.precipitationfactor(0.1)
>>> inputs.t.series = t_series
>>> petinputs.normalairtemperature.series = tn_series
>>> test("hland_96_multiple_zones")
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

snow redistribution 1

Working with five zones allows demonstrating the redistribution of snow due to gravitational and wind forcing. Therefore, we change the zone elevations so that the first one (FIELD) is on 0 m, the second one (FOREST) on 1000 m, the third one on 3000 m (GLACIER), the fourth one (ILAKE) on 0 m, and the fifth one (SEALED) on 2000 m above sea level. This random order is not ideal for clarity but demonstrates that unsorted configurations do not harm the results:

>>> zonez(0.0, 10.0, 30.0, 0.0, 20.0)

We define a small snow threshold value of 200 mm to trigger snow redistribution despite the short simulation period:

>>> smax(200.0)

We prepare the redistribution parameter SRed so that the slipped snow of one zone deposits in the zone(s) directly below:

>>> sred(n_zones=1)

We define a constant air temperature of -0.4 °C for the subbasin. However, there is a substantial difference in the individual zone temperatures due to the high elevation differences:

>>> inputs.t.series = -0.4

We double the basin’s average precipitation by two and halve the altitude-related precipitation adjustment. However, there is still a marked difference for the individual zones, which helps to stress the role of redistribution.

>>> pcorr *= 2.0
>>> pcalt(0.05)

In the following simulation results, the highest zone (GLACIER) stores the falling precipitation as frozen snow (SP) and releases the amount exceeding 200 mm (SPL) to the second-highest zone (SEALED). The SEALED zone receives too much snow itself. Hence, the third-highest zone (FOREST) receives the snow released by both higher zones (SPG), but only for a few hours. Its available capacity also replenishes soon, and it then starts releasing snow to the FIELD zone at sea level (ILAKE zones never play a role in snow redistribution due to their missing snow module). However, with all zones except the ILAKE zone releasing snow towards the FIELD zone, its snow cover grows rapidly and soon reaches the SMax threshold. Then, the net transport due to snow redistribution virtually stops, and the snow covers of all zones (again, except for the ILAKE zone) grow with the same speed (see the documentation on method Calc_SPG_WCG_SP_WC_V1 for further details).

In the simulation period’s second half, the melting of snow (only taking place in the low elevation zones) outweighs snowfall (which dominates in the high elevation zones). Still, snow ablation is at even speed across all zones due to the rebalancing action of snow redistribution above SRed (again, please also read the documentation on method Calc_SPG_WCG_SP_WC_V1):

>>> test("hland_96_snow_redistribution_1",
...      axis1=(states.sp, states.wc), axis2=(factors.tc, fluxes.pc))
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
>>> sclass(2)
>>> sfdist(linear=0.2)

snow redistribution 2

The example snow redistribution 1 assumes uniform snow distributions within all zones. Here, we introduce some heterogeneity by defining two snow classes for each zone:

>>> sclass(2)
>>> sfdist(linear=0.2)

Inspecting the snow pack’s evolution reveals that we individually apply the threshold parameter SMax for each snow class. Hence, one snow class can still receive snowfall or redistributed snow while the second one already routes it to the next lower zone:

>>> test("hland_96_snow_redistribution_2", axis1=(states.sp, states.wc))
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.hland_96.Model[source]

Bases: Main_AETModel_V1, Main_RConcModel_V1, Sub_TempModel_V1, Sub_PrecipModel_V1, Sub_IntercModel_V1, Sub_SoilWaterModel_V1, Sub_SnowCoverModel_V1

HydPy-H-HBV96 (adoption of SMHI-IHMS-HBV96).

The following “run methods” are called in the given sequence during each simulation step:
  • Calc_TC_V1 Adjust the measured air temperature to the altitude of the individual zones.

  • Calc_FracRain_V1 Determine the temperature-dependent fraction of (liquid) rainfall and (total) precipitation.

  • Calc_RFC_SFC_V1 Calculate the corrected fractions of rainfall/snowfall and total precipitation.

  • Calc_PC_V1 Apply the precipitation correction factors and adjust precipitation to the altitude of the individual zones.

  • Calc_TF_Ic_V1 Calculate throughfall and update the interception storage accordingly.

  • Calc_SP_WC_V1 Add throughfall to the snow layer.

  • Calc_SPL_WCL_SP_WC_V1 Calculate the subbasin-internal redistribution losses of the snow layer.

  • Calc_SPG_WCG_SP_WC_V1 Calculate the subbasin-internal redistribution gains of the snow layer.

  • Calc_CFAct_V1 Adjust the day degree factor for snow to the current day of the year.

  • Calc_Melt_SP_WC_V1 Calculate the melting of the ice content within the snow layer and update both the snow layers’ ice and the water content.

  • Calc_Refr_SP_WC_V1 Calculate refreezing of the water content within the snow layer and update both the snow layers’ ice and the water content.

  • Calc_In_WC_V1 Calculate the actual water release from the snow layer due to the exceedance of the snow layers’ capacity for (liquid) water.

  • Calc_SWE_V1 Calculate the total snow water equivalent.

  • Calc_SR_V1 Calculate the sealed surface runoff.

  • Calc_GAct_V1 Adjust the day degree factor for glacier ice to the current day of the year.

  • Calc_GlMelt_In_V1 Calculate the melting of non-snow-covered glaciers and add it to the water release of the snow module.

  • Calc_EI_Ic_V1 Let a submodel that follows the AETModel_V1 submodel interface calculate interception evaporation and adjust the amount of intercepted water.

  • Calc_R_SM_V1 Calculate effective precipitation and update the soil moisture.

  • Calc_CF_SM_V1 Calculate capillary flow and update the soil moisture.

  • Calc_EA_SM_V1 Let a submodel that follows the AETModel_V1 submodel interface calculate soil evapotranspiration and adjust the soil water content.

  • Calc_InUZ_V1 Accumulate the total inflow into the upper zone layer.

  • Calc_ContriArea_V1 Determine the relative size of the contributing area of the whole subbasin.

  • Calc_Q0_Perc_UZ_V1 Calculate the percolation and direct runoff leaving the upper zone storage and update it accordingly.

  • Calc_LZ_V1 Add percolation from the upper zone layera and lake precipitation to the lower zone storage.

  • Calc_EL_LZ_V1 Let a submodel that follows the AETModel_V1 submodel interface calculate lake evaporation and adjust the lower zone’s water content.

  • Calc_Q1_LZ_V1 Calculate the slow response of the lower zone layer.

  • Calc_InRC_V1 Calculate the input of the runoff concentration submodel.

  • Calc_OutRC_V1 If the model has a submodel that follows the RConcModel_V1 submodel interface, calculate runoff concentration. If not, set the output equal to the input.

  • Calc_RT_V1 Calculate the total discharge in mm.

  • Calc_QT_V1 Calculate the total discharge in m³/s.

The following “outlet update methods” are called in the given sequence at the end of each simulation step:
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:
  • AETModel_V1 Interface for calculating interception evaporation, evapotranspiration from soils, evaporation from water areas in separate steps.

  • RConcModel_V1 Simple interface for calculating runoff concentration processes.

DOCNAME: DocName = ('H-HBV96', 'adoption of SMHI-IHMS-HBV96')
aetmodel: SubmodelProperty

Required submodel that complies with the following interface: AETModel_V1.

rconcmodel: modeltools.SubmodelProperty

Optional submodel that complies with the following interface: RConcModel_V1.

check_waterbalance(initial_conditions: dict[str, dict[str, dict[str, float | ndarray[Any, dtype[float64]]]]]) float[source]

Determine the water balance error of the previous simulation run in mm.

Method check_waterbalance() calculates the balance error as follows:

\[\begin{split}\Sigma In_{hru} - \Sigma Out_{hru} - \Sigma Out_{basin} + \Delta Vol_{hru} + \Delta Vol_{snow} + \Delta Vol_{basin} - \Delta Vol_{rconc} \\ \\ \Sigma In_{hru} = \sum_{k=1}^{N_{hru}} A_Z^k \cdot \sum_{t=t0}^{t1} PC_t^k + GLMelt_t^k \\ \Sigma Out_{hru} = \sum_{k=1}^{N_{hru}} A_Z^k \cdot \sum_{t=t0}^{t1} EI_t^k + EA_t^k + EL_t^k \\ \Sigma Out_{basin} = \sum_{t=t0}^{t1} RT_t \\ \Delta Vol_{snow} = \sum_{k=1}^{N_{hru}} A_Z^k \cdot \frac{1}{N_{snow}} \cdot \sum_{c=1}^{N_{snow}} \big(SP_{t0}^{k,s} - SP_{t1}^{k,s}\big) + \big(WC_{t0}^{k,s} - WC_{t1}^{k,s}\big) \\ \Delta Vol_{hru} = \sum_{k=1}^{N_{hru}} A_Z^k \cdot \Big( \big(IC_{t0}^k - IC_{t1}^k\big) + \big(SM_{t0}^k - SM_{t1}^k\big) \Big) \\ \Delta Vol_{basin} = A_U \cdot \big(UZ_{t0} - UZ_{t1}\big) + A_L \cdot \big(LZ_{t0} - LZ_{t1}\big) \\ \Delta Vol_{rconc} = \begin{cases} rconcmodel.get\_waterbalance &|\ rconcmodel \\ 0 &|\ \overline{rconcmodel} \end{cases} \\ \\ N_{hru} = NmbZones \\ N_{snow} = SClass \\ A_Z = RelZoneAreas \\ A_U = RelUpperZoneArea \\ A_L = RelLowerZoneArea\end{split}\]

The returned error should always be in scale with numerical precision so that it does not affect the simulation results in any relevant manner.

Pick the required initial conditions before starting the simulation run via property conditions. See the integration tests of the application model hland_96 for some examples.

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

Bases: Masks

Masks applicable to hland_96.

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

Bases: AideSequences

Aide sequences of model hland_96.

The following classes are selected:
  • SPE() Subbasin-internal redistribution excess of the snow’s ice content [mm/T].

  • WCE() Subbasin-internal redistribution excess of the snow’s water content [mm/T].

class hydpy.models.hland_96.ControlParameters(master: Parameters, cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)

Bases: SubParameters

Control parameters of model hland_96.

The following classes are selected:
  • Area() Subbasin area [km²].

  • NmbZones() Number of zones (hydrological response units) in a subbasin [-].

  • SClass() Number of snow classes in each zone [-].

  • ZoneType() Type of each zone [-].

  • ZoneArea() Zone area [km²].

  • Psi() Fraction of the actual sealing of zones classified as SEALED [-].

  • ZoneZ() Zone elevation [100m].

  • PCorr() General precipitation correction factor [-].

  • PCAlt() Elevation correction factor for precipitation [1/100m].

  • RfCF() Rainfall correction factor [-].

  • SfCF() Snowfall correction factor [-].

  • TCorr() General temperature correction addend [-].

  • TCAlt() Elevation correction factor for temperature [-1°C/100m].

  • IcMax() Maximum interception storage [mm].

  • SFDist() Distribution of snowfall [-].

  • SMax() Maximum snow water equivalent [mm].

  • SRed() Snow redistribution paths [-].

  • TT() Temperature threshold for snow/rain [°C].

  • TTInt() Temperature interval with a mixture of snow and rain [°C].

  • DTTM() Difference between TTM and TT [°C].

  • CFMax() Average degree day factor for snow (on glaciers or not) [mm/°C/T].

  • CFVar() Annual variability of CFMax [mm/°C/T].

  • GMelt() Degree day factor for glacial ice [mm/°C/T].

  • GVar() Annual variability of GMelt [mm/°C/T].

  • CFR() Refreezing factor for water stored within the snow layer [-].

  • WHC() Relative water holding capacity of the snow layer [-].

  • FC() Maximum soil moisture content (field capacity) [mm].

  • Beta() Nonlinearity parameter of the soil routine [-].

  • PercMax() Maximum percolation rate [mm/T].

  • CFlux() Capacity (maximum) of the capillary return flux [mm/T].

  • RespArea() Flag to enable the contributing area approach [-].

  • RecStep() Number of internal computation steps per simulation time step [-].

  • Alpha() Nonlinearity parameter of the upper zone layer [-].

  • K() Recession coefficient of the upper zone layer [1/T/mm^alpha].

  • K4() Recession coefficient of the lower zone layer [1/T].

  • Gamma() Nonlinearity parameter of the lower zone layer [-].

class hydpy.models.hland_96.DerivedParameters(master: Parameters, cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)

Bases: SubParameters

Derived parameters of model hland_96.

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

Bases: FactorSequences

Factor sequences of model hland_96.

The following classes are selected:
  • TC() Corrected temperature [°C].

  • FracRain() Fraction rainfall / total precipitation [-].

  • RfC() Actual precipitation correction related to liquid precipitation [-].

  • SfC() Actual precipitation correction related to frozen precipitation [-].

  • CFAct() Actual degree day factor for snow (on glaciers or not) [mm/°C/T].

  • SWE() Snow water equivalent [mm].

  • GAct() Actual degree day factor for glacier ice [mm/°C/T].

  • ContriArea() Fraction of the “soil area” contributing to runoff generation [-].

class hydpy.models.hland_96.FixedParameters(master: Parameters, cls_fastaccess: type[FastAccessParameter] | None = None, cymodel: CyModelProtocol | None = None)

Bases: SubParameters

Fixed parameters of model hland_96.

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

Bases: FluxSequences

Flux sequences of model hland_96.

The following classes are selected:
  • PC() Corrected precipitation [mm/T].

  • EI() Interception evaporation [mm/T].

  • TF() Throughfall [mm/T].

  • SPL() Subbasin-internal redistribution loss of the snow’s ice content [mm/T].

  • WCL() Subbasin-internal redistribution loss of the snow’s water content [mm/T].

  • SPG() Subbasin-internal redistribution gain of the snow’s ice content [mm/T].

  • WCG() Subbasin-internal redistribution gain of the snow’s water content [mm/T].

  • GlMelt() Glacier melt [mm/T].

  • Melt() Actual melting of frozen water stored in the snow layer [mm/T].

  • Refr() Actual (re)freezing of liquid water stored in the snow layer [mm/T].

  • In_() Snow module release/soil module inflow [mm/T].

  • R() Effective soil response [mm/T].

  • SR() Sealed surface runoff [mm/T].

  • EA() Actual soil evaporation [mm/T].

  • CF() Actual capillary flow [mm/T].

  • InUZ() Inflow to the upper zone layer [mm/T].

  • Perc() Percolation from the upper to the lower zone layer [mm/T].

  • Q0() Outflow from the upper zone layer [mm/T].

  • EL() Actual lake evaporation [mm/T].

  • Q1() Outflow from the lower zone layer [mm/T].

  • InRC() Input of the runoff concentration submodel [mm/T].

  • OutRC() Output of the runoff concentration submodel [mm/T].

  • RT() Total model outflow [mm/T].

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

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

Bases: InputSequences

Input sequences of model hland_96.

The following classes are selected:
  • P() Precipitation [mm].

  • T() Temperature [°C].

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

Bases: OutletSequences

Outlet sequences of model hland_96.

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

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

Bases: StateSequences

State sequences of model hland_96.

The following classes are selected:
  • Ic() Interception storage [mm].

  • SP() Frozen water stored in the snow layer [mm].

  • WC() Liquid water content of the snow layer [mm].

  • SM() Soil moisture [mm].

  • UZ() Storage in the upper zone layer [mm].

  • LZ() Storage in the lower zone layer [mm].