# pylint: disable=missing-module-docstring
# import...
# ...from HydPy
from hydpy.core import importtools
from hydpy.core import modeltools
from hydpy.core.typingtools import *
from hydpy.cythons import modelutils
from hydpy.interfaces import petinterfaces
from hydpy.interfaces import rconcinterfaces
# ...from gland
from hydpy.models.gland import gland_control
from hydpy.models.gland import gland_derived
from hydpy.models.gland import gland_inputs
from hydpy.models.gland import gland_fluxes
from hydpy.models.gland import gland_states
from hydpy.models.gland import gland_outlets
[docs]
class Calc_E_PETModel_V1(modeltools.Method):
"""Let a submodel that conforms to the |PETModel_V1| interface calculate the
potential evapotranspiration.
Example:
We use |evap_ret_tw2002| as an example:
>>> from hydpy.models.gland_gr4 import *
>>> parameterstep()
>>> from hydpy import prepare_model
>>> area(50.0)
>>> with model.add_petmodel_v1("evap_ret_tw2002"):
... hrualtitude(200.0)
... coastfactor(0.6)
... evapotranspirationfactor(1.1)
... with model.add_radiationmodel_v2("meteo_glob_io"):
... inputs.globalradiation = 200.0
... with model.add_tempmodel_v2("meteo_temp_io"):
... temperatureaddend(1.0)
... inputs.temperature = 14.0
>>> model.calc_e_v1()
>>> fluxes.e
e(3.07171)
"""
RESULTSEQUENCES = (gland_fluxes.E,)
@staticmethod
def __call__(model: modeltools.Model, submodel: petinterfaces.PETModel_V1) -> None:
flu = model.sequences.fluxes.fastaccess
submodel.determine_potentialevapotranspiration()
flu.e = submodel.get_potentialevapotranspiration(0)
[docs]
class Calc_E_V1(modeltools.Method):
"""Let a submodel that conforms to the |PETModel_V1| interface calculate the
potential evapotranspiration."""
SUBMODELINTERFACES = (petinterfaces.PETModel_V1,)
SUBMETHODS = (Calc_E_PETModel_V1,)
RESULTSEQUENCES = (gland_fluxes.E,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
if model.petmodel_typeid == 1:
model.calc_e_petmodel_v1(cast(petinterfaces.PETModel_V1, model.petmodel))
[docs]
class Calc_EI_V1(modeltools.Method):
r"""Calculate the actual evaporation from the interception store.
Basic equation:
:math:`EI = min(E, \, I + P)`
Examples:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> inputs.p = 1.0
>>> fluxes.e = 0.5
>>> states.i = 0.0
>>> model.calc_ei_v1()
>>> fluxes.ei
ei(0.5)
>>> inputs.p = 0.5
>>> fluxes.e = 1.0
>>> states.i = 0.2
>>> model.calc_ei_v1()
>>> fluxes.ei
ei(0.7)
"""
REQUIREDSEQUENCES = (gland_inputs.P, gland_fluxes.E, gland_states.I)
RESULTSEQUENCES = (gland_fluxes.EI,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
inp = model.sequences.inputs.fastaccess
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
flu.ei = min(flu.e, sta.i + inp.p)
[docs]
class Calc_PN_V1(modeltools.Method):
r"""Calculate the net precipitation by considering all interception losses.
Basic equation:
:math:`PN = max(P - (IMax - I) - EI, \, 0)`
Examples:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> control.imax(10.0)
>>> inputs.p = 1.0
>>> states.i = 5.0
>>> fluxes.ei = 2.0
>>> model.calc_pn_v1()
>>> fluxes.pn
pn(0.0)
>>> inputs.p = 8.0
>>> model.calc_pn_v1()
>>> fluxes.pn
pn(1.0)
"""
CONTROLPARAMETERS = (gland_control.IMax,)
REQUIREDSEQUENCES = (gland_inputs.P, gland_fluxes.EI, gland_states.I)
RESULTSEQUENCES = (gland_fluxes.PN,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
con = model.parameters.control.fastaccess
inp = model.sequences.inputs.fastaccess
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
flu.pn = max(inp.p - (con.imax - sta.i) - flu.ei, 0.0)
[docs]
class Calc_EN_V1(modeltools.Method):
r"""Calculate the net evapotranspiration capacity by considering interception
evaporation.
Basic equation:
:math:`EN = max(E - EI, \, 0.0)`
Examples:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> fluxes.e = 1.0
>>> fluxes.ei = 2.0
>>> model.calc_en_v1()
>>> fluxes.en
en(0.0)
>>> fluxes.e = 3.0
>>> model.calc_en_v1()
>>> fluxes.en
en(1.0)
"""
REQUIREDSEQUENCES = (gland_fluxes.E, gland_fluxes.EI)
RESULTSEQUENCES = (gland_fluxes.EN,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
flu.en = max(flu.e - flu.ei, 0.0)
[docs]
class Update_I_V1(modeltools.Method):
"""Update the interception store based on precipitation, net precipitation, and
interception evaporation.
Basic equation:
:math:`I_{new} = I_{old} + P - PN - EI`
Example:
>>> from hydpy.models.gland import *
>>> parameterstep("1d")
>>> states.i = 10.0
>>> inputs.p = 5.0
>>> fluxes.ei = 4.0
>>> fluxes.pn = 3.0
>>> model.update_i_v1()
>>> states.i
i(8.0)
"""
REQUIREDSEQUENCES = (gland_inputs.P, gland_fluxes.PN, gland_fluxes.EI)
UPDATEDSEQUENCES = (gland_states.I,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
inp = model.sequences.inputs.fastaccess
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
sta.i += inp.p - flu.ei - flu.pn
[docs]
class Calc_PS_V1(modeltools.Method):
r"""Calculate the part of net precipitation filling the production store.
Basic equation:
:math:`PS = \frac{
X1 \cdot \left( 1 - \left( \frac{S}{X1} \right)^2 \right)
\cdot tanh \left( \frac{PN}{X1} \right)}
{1 + \frac{S}{X1} \cdot tanh \left( \frac{PN}{X1} \right)}`
Examples:
If the production store is full, no more precipitation can enter it:
>>> from hydpy.models.gland import *
>>> from hydpy import pub
>>> parameterstep()
>>> x1(300.0)
>>> states.s = 300.0
>>> fluxes.pn = 50.0
>>> model.calc_ps_v1()
>>> fluxes.ps
ps(0.0)
If the production store is empty, nearly all net precipitation enters it:
>>> states.s = 0.0
>>> model.calc_ps_v1()
>>> fluxes.ps
ps(49.542124)
If net precipitation is zero, there can be no inflow into the production store:
>>> fluxes.pn = 0.0
>>> model.calc_ps_v1()
>>> fluxes.ps
ps(0.0)
"""
CONTROLPARAMETERS = (gland_control.X1,)
REQUIREDSEQUENCES = (gland_fluxes.PN, gland_states.S)
RESULTSEQUENCES = (gland_fluxes.PS,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
con = model.parameters.control.fastaccess
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
flu.ps = (
con.x1
* (1.0 - (sta.s / con.x1) ** 2.0)
* modelutils.tanh(flu.pn / con.x1)
/ (1.0 + sta.s / con.x1 * modelutils.tanh(flu.pn / con.x1))
)
[docs]
class Calc_ES_V1(modeltools.Method):
r"""Calculate the actual evapotranspiration from the production store.
Basic equation:
.. math ::
Es = \frac{S \cdot (2 - r) \cdot t}{1 + (1 - r) \cdot t} \\
t = tanh \left( EN / X1 \right) \\
r = S / X1
Examples:
If the production store is nearly full, actual and potential evapotranspiration
are almost equal:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> x1(300.0)
>>> states.s = 270.0
>>> fluxes.en = 2.0
>>> model.calc_es_v1()
>>> fluxes.es
es(1.978652)
If the production store is nearly empty, actual evapotranspiration is almost
zero:
>>> states.s = 10.0
>>> model.calc_es_v1()
>>> fluxes.es
es(0.13027)
"""
CONTROLPARAMETERS = (gland_control.X1,)
REQUIREDSEQUENCES = (gland_fluxes.EN, gland_states.S)
RESULTSEQUENCES = (gland_fluxes.ES,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
con = model.parameters.control.fastaccess
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
rs: float = sta.s / con.x1
re: float = flu.en / con.x1
tre: float = modelutils.tanh(re) # equals (exp(2 * re) - 1) / (exp(2 * re) + 1)
flu.es = (sta.s * (2.0 - rs) * tre) / (1.0 + (1.0 - rs) * tre)
[docs]
class Update_S_V1(modeltools.Method):
"""Update the production store by adding precipitation and evapotranspiration.
Basic equation:
:math:`S_{new} = S_{old} + PS - ES`
Examples:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> x1(300.0)
>>> fluxes.ps = 10.0
>>> fluxes.es = 3.0
>>> states.s = 270.0
>>> model.update_s_v1()
>>> states.s
s(277.0)
"""
REQUIREDSEQUENCES = (gland_fluxes.PS, gland_fluxes.ES)
UPDATEDSEQUENCES = (gland_states.S,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
sta.s += flu.ps - flu.es
[docs]
class Calc_Perc_V1(modeltools.Method):
r"""Calculate the percolation from the production store.
Basic equation:
:math:`Perc = S \cdot \left(
1 - \left(1 + \left(\frac{S}{Beta \cdot X1} \right)^4 \right)^{-1/4} \right)`
Examples:
>>> from hydpy.models.gland import *
>>> simulationstep("1d")
>>> parameterstep()
>>> derived.beta.update()
>>> x1(300.0)
>>> states.s = 268.0
>>> model.calc_perc_v1()
>>> fluxes.perc
perc(1.639555)
>>> states.s = 50.0
>>> model.calc_perc_v1()
>>> fluxes.perc
perc(0.000376)
"""
CONTROLPARAMETERS = (gland_control.X1,)
DERIVEDPARAMETERS = (gland_derived.Beta,)
UPDATEDSEQUENCES = (gland_states.S,)
RESULTSEQUENCES = (gland_fluxes.Perc,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
con = model.parameters.control.fastaccess
der = model.parameters.derived.fastaccess
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
flu.perc = sta.s * (1.0 - (1.0 + (sta.s / con.x1 / der.beta) ** 4.0) ** -0.25)
[docs]
class Update_S_V2(modeltools.Method):
"""Update the production store by subtracting percolation.
Basic equation:
:math:`S_{new} = S_{old} - Perc`
Examples:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> fluxes.perc = 2.0
>>> states.s = 20.0
>>> model.update_s_v2()
>>> states.s
s(18.0)
"""
REQUIREDSEQUENCES = (gland_fluxes.Perc,)
UPDATEDSEQUENCES = (gland_states.S,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
sta.s -= flu.perc
[docs]
class Calc_AE_V1(modeltools.Method):
"""Calculate the total actual evapotranspiration.
Basic equation:
:math:`AE = EI + ES`
Examples:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> fluxes.ei = 2.0
>>> fluxes.es = 1.0
>>> model.calc_ae_v1()
>>> fluxes.ae
ae(3.0)
"""
REQUIREDSEQUENCES = (gland_fluxes.EI, gland_fluxes.ES)
RESULTSEQUENCES = (gland_fluxes.AE,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
flu.ae = flu.ei + flu.es
[docs]
class Calc_Pr_V1(modeltools.Method):
"""Calculate the total inflow into the runoff concentration module.
Basic equation:
:math:`PR = Perc + (PN - PS)`
Example:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> fluxes.perc = 1.0
>>> fluxes.pn = 5.0
>>> fluxes.ps = 2.0
>>> model.calc_pr_v1()
>>> fluxes.pr
pr(4.0)
"""
REQUIREDSEQUENCES = (gland_fluxes.PS, gland_fluxes.PN, gland_fluxes.Perc)
RESULTSEQUENCES = (gland_fluxes.PR,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
flu.pr = flu.perc + flu.pn - flu.ps
[docs]
class Calc_PR1_PR9_V1(modeltools.Method):
r"""Split |PR| into |PR1| and |PR9|.
Basic equations:
:math:`PR9 = 0.9 \cdot PR`
:math:`PR1 = 0.1 \cdot PR`
Examples:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> fluxes.pr = 10.0
>>> model.calc_pr1_pr9_v1()
>>> fluxes.pr9
pr9(9.0)
>>> fluxes.pr1
pr1(1.0)
"""
REQUIREDSEQUENCES = (gland_fluxes.PR,)
RESULTSEQUENCES = (gland_fluxes.PR9, gland_fluxes.PR1)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
flu.pr9 = 0.9 * flu.pr
flu.pr1 = 0.1 * flu.pr
[docs]
class Calc_Q_RConcModel_V1(modeltools.Method):
"""Let a submodel that follows the |RConcModel_V1| submodel interface perform
runoff concentration."""
@staticmethod
def __call__(
model: modeltools.Model, submodel: rconcinterfaces.RConcModel_V1, inflow: float
) -> float:
submodel.set_inflow(inflow)
submodel.determine_outflow()
return submodel.get_outflow()
[docs]
class Calc_Q9_V1(modeltools.Method):
"""Transform |PR9| into |Q9|.
Examples:
Without a `rconcmodel_routingstore` submodel, |Calc_Q9_V1| directs |PR9|
instantaneously to |Q9|:
>>> from hydpy.models.gland_gr4 import *
>>> simulationstep("1d")
>>> parameterstep("1d")
>>> fluxes.pr9 = 1.0
>>> model.calc_q9_v1()
>>> fluxes.q9
q9(1.0)
For a GR-compatible calculation of runoff concentration, you can select the
Unit Hydrograph submodel |rconc_uh| and configure its ordinates via the
`gr_uh1` option:
>>> with model.add_rconcmodel_routingstore_v1("rconc_uh"):
... uh("gr_uh1", x4=3.0)
... logs.quh = 1.0, 3.0, 0.0
>>> fluxes.pr9 = 2.0
>>> model.calc_q9_v1()
>>> fluxes.q9
q9(1.1283)
"""
SUBMODELINTERFACES = (rconcinterfaces.RConcModel_V1,)
SUBMETHODS = (Calc_Q_RConcModel_V1,)
REQUIREDSEQUENCES = (gland_fluxes.PR9,)
RESULTSEQUENCES = (gland_fluxes.Q9,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
if model.rconcmodel_routingstore is None:
flu.q9 = flu.pr9
elif model.rconcmodel_routingstore_typeid == 1:
flu.q9 = model.calc_q_rconcmodel_v1(
cast(rconcinterfaces.RConcModel_V1, model.rconcmodel_routingstore),
flu.pr9,
)
[docs]
class Calc_Q1_V1(modeltools.Method):
"""Transform |PR1| into |Q1|.
Examples:
Without a `rconcmodel_directflow` submodel, |Calc_Q1_V1| directs |PR1|
instantaneously to |Q1|:
>>> from hydpy.models.gland_gr4 import *
>>> simulationstep("1d")
>>> parameterstep("1d")
>>> fluxes.pr1 = 1.0
>>> model.calc_q1_v1()
>>> fluxes.q1
q1(1.0)
For a GR-compatible calculation of runoff concentration, you can select the
Unit Hydrograph submodel |rconc_uh| and configure its ordinates via the
`gr_uh2` option:
>>> with model.add_rconcmodel_directflow_v1("rconc_uh"):
... uh("gr_uh2", x4=1.5)
... logs.quh = 1.0, 3.0, 0.0
>>> fluxes.pr1 = 2.0
>>> model.calc_q1_v1()
>>> fluxes.q1
q1(1.362887)
"""
SUBMODELINTERFACES = (rconcinterfaces.RConcModel_V1,)
SUBMETHODS = (Calc_Q_RConcModel_V1,)
REQUIREDSEQUENCES = (gland_fluxes.PR1,)
RESULTSEQUENCES = (gland_fluxes.Q1,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
if model.rconcmodel_directflow is None:
flu.q1 = flu.pr1
elif model.rconcmodel_directflow_typeid == 1:
flu.q1 = model.calc_q_rconcmodel_v1(
cast(rconcinterfaces.RConcModel_V1, model.rconcmodel_directflow),
flu.pr1,
)
[docs]
class Calc_Q10_V1(modeltools.Method):
"""Transform |PR| into |Q10|.
Examples:
Without a `rconcmodel` submodel, |Calc_Q10_V1| directs |PR| instantaneously to
|Q10|:
>>> from hydpy.models.gland_gr5 import *
>>> simulationstep("1d")
>>> parameterstep("1d")
>>> fluxes.pr = 1.0
>>> model.calc_q10_v1()
>>> fluxes.q10
q10(1.0)
For a GR-compatible calculation of runoff concentration, you can select the
Unit Hydrograph submodel |rconc_uh| and configure its ordinates via the
`gr_uh2` option:
>>> with model.add_rconcmodel_v1("rconc_uh"):
... uh("gr_uh2", x4=1.5)
... logs.quh = 1.0, 3.0, 0.0
>>> fluxes.pr = 2.0
>>> model.calc_q10_v1()
>>> fluxes.q10
q10(1.362887)
"""
SUBMODELINTERFACES = (rconcinterfaces.RConcModel_V1,)
SUBMETHODS = (Calc_Q_RConcModel_V1,)
REQUIREDSEQUENCES = (gland_fluxes.PR,)
RESULTSEQUENCES = (gland_fluxes.Q10,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
if model.rconcmodel is None:
flu.q10 = flu.pr
elif model.rconcmodel_typeid == 1:
flu.q10 = model.calc_q_rconcmodel_v1(
cast(rconcinterfaces.RConcModel_V1, model.rconcmodel), flu.pr
)
[docs]
class Calc_Q1_Q9_V2(modeltools.Method):
r"""Calculate |Q1| and |Q9| by splitting |Q10|.
Basic equations:
:math:`Q9 = 0.9 \cdot Q10`
:math:`Q1 = 0.1 \cdot Q10`
Example:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> fluxes.q10 = 10.0
>>> model.calc_q1_q9_v2()
>>> fluxes.q1
q1(1.0)
>>> fluxes.q9
q9(9.0)
"""
REQUIREDSEQUENCES = (gland_fluxes.Q10,)
RESULTSEQUENCES = (gland_fluxes.Q1, gland_fluxes.Q9)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
flu.q1 = 0.1 * flu.q10
flu.q9 = 0.9 * flu.q10
[docs]
class Calc_FR_V1(modeltools.Method):
r"""Calculate the groundwater exchange affecting the routing store according to
GR4.
Basic equation:
:math:`FR = X2 \cdot \left( \frac{R}{X3} \right)^{7/2}`
Examples:
If the routing store is nearly full, groundwater exchange is high and close to
|X3|:
>>> from hydpy.models.gland import *
>>> from hydpy import pub
>>> simulationstep("1d")
>>> parameterstep("1d")
>>> x2(1.02)
>>> x3(100.0)
>>> states.r = 95.0
>>> model.calc_fr_v1()
>>> fluxes.fr
fr(0.852379)
If the routing store is almost empty, groundwater exchange is low and near
zero:
>>> states.r = 5.0
>>> model.calc_fr_v1()
>>> fluxes.fr
fr(0.000029)
"""
CONTROLPARAMETERS = (gland_control.X2, gland_control.X3)
REQUIREDSEQUENCES = (gland_states.R,)
RESULTSEQUENCES = (gland_fluxes.FR,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
con = model.parameters.control.fastaccess
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
flu.fr = con.x2 * (sta.r / con.x3) ** 3.5
[docs]
class Calc_FR_V2(modeltools.Method):
r"""Calculate the groundwater exchange affecting the routing store according to
GR5 and GR6.
Basic equation:
:math:`FR = X2 \cdot \left( \frac{R}{X3} - X5 \right)`
Example:
>>> from hydpy.models.gland import *
>>> simulationstep("1d")
>>> parameterstep("1d")
>>> x2(-0.163)
>>> x3(100.0)
>>> x5(0.104)
>>> states.r = 95.0
>>> model.calc_fr_v2()
>>> fluxes.fr
fr(-0.137898)
"""
CONTROLPARAMETERS = (gland_control.X2, gland_control.X3, gland_control.X5)
UPDATEDSEQUENCES = (gland_states.R,)
RESULTSEQUENCES = (gland_fluxes.FR,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
con = model.parameters.control.fastaccess
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
flu.fr = con.x2 * (sta.r / con.x3 - con.x5)
[docs]
class Update_R_V1(modeltools.Method):
"""Update the level of the non-linear routing store by adding its inflows according
to GR4 and GR5.
Basic equation:
:math:`R_{new} = R_{old} + Q9 + FR`
Examples:
>>> from hydpy.models.gland import *
>>> parameterstep()
In case of sufficient content of the routing store, the basic equation applies
without modification:
>>> states.r = 4.0
>>> fluxes.q9 = 1.0
>>> fluxes.fr = -2.0
>>> model.update_r_v1()
>>> states.r
r(3.0)
>>> fluxes.fr
fr(-2.0)
For insufficient content, groundwater loss (negative groundwater exchange)
becomes restricted:
>>> fluxes.fr = -5.0
>>> model.update_r_v1()
>>> states.r
r(0.0)
>>> fluxes.fr
fr(-4.0)
"""
REQUIREDSEQUENCES = (gland_fluxes.Q9, gland_fluxes.FR)
UPDATEDSEQUENCES = (gland_states.R,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
sta.r += flu.q9 + flu.fr
if sta.r < 0.0:
flu.fr -= sta.r
sta.r = 0.0
[docs]
class Update_R_V2(modeltools.Method):
r"""Update the level of the non-linear routing store by adding its inflows
according to GR6.
Basic equation:
:math:`R_{new} = R_{old} + 0.6 \cdot Q9 + FR`
Examples:
>>> from hydpy.models.gland import *
>>> from hydpy import pub
>>> parameterstep()
In case of sufficient content of the routing store, the basic equation applies
without modification:
>>> states.r = 4.0
>>> fluxes.q9 = 1.0 / 0.6
>>> fluxes.fr = -2.0
>>> model.update_r_v2()
>>> states.r
r(3.0)
>>> fluxes.fr
fr(-2.0)
For insufficient content, groundwater loss (negative groundwater exchange)
becomes restricted:
>>> fluxes.fr = -5.0
>>> model.update_r_v2()
>>> states.r
r(0.0)
>>> fluxes.fr
fr(-4.0)
"""
REQUIREDSEQUENCES = (gland_fluxes.Q9, gland_fluxes.FR)
UPDATEDSEQUENCES = (gland_states.R,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
sta.r += 0.6 * flu.q9 + flu.fr
if sta.r < 0.0:
flu.fr -= sta.r
sta.r = 0.0
[docs]
class Calc_QR_V1(modeltools.Method):
r"""Calculate the outflow of the routing store.
Basic equation:
:math:`QR = R \cdot \left( 1 - \left[1 + \left( \frac{R}{X3} \right)^{4}
\right]^{-1/4} \right)`
Example:
>>> from hydpy.models.gland import *
>>> from hydpy import pub
>>> parameterstep("1d")
>>> simulationstep("1d")
>>> x3(100.0)
>>> states.r = 115.852379
>>> model.calc_qr_v1()
>>> fluxes.qr
qr(26.30361)
"""
CONTROLPARAMETERS = (gland_control.X3,)
REQUIREDSEQUENCES = (gland_states.R,)
RESULTSEQUENCES = (gland_fluxes.QR,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
con = model.parameters.control.fastaccess
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
flu.qr = sta.r * (1.0 - (1.0 + (sta.r / con.x3) ** 4.0) ** -0.25)
[docs]
class Update_R_V3(modeltools.Method):
"""Update the non-linear routing store by subtracting its outflow.
Basic equation:
:math:`R_{new} = R_{old} - QR`
Example:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> fluxes.qr = 2.0
>>> states.r = 20.0
>>> model.update_r_v3()
>>> states.r
r(18.0)
"""
REQUIREDSEQUENCES = (gland_fluxes.QR,)
UPDATEDSEQUENCES = (gland_states.R,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
sta.r -= flu.qr
[docs]
class Calc_FR2_V1(modeltools.Method):
r"""Calculate the groundwater exchange affecting the exponential routing store.
Basic equation:
:math:`FR2 = FR`
Examples:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> fluxes.fr = -0.5
>>> model.calc_fr2_v1()
>>> fluxes.fr2
fr2(-0.5)
"""
REQUIREDSEQUENCES = (gland_fluxes.FR,)
RESULTSEQUENCES = (gland_fluxes.FR2,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
flu.fr2 = flu.fr
[docs]
class Update_R2_V1(modeltools.Method):
r"""Update the exponential routing store by adding its inflows.
Basic equation:
:math:`R2_{new} = R2_{new} + 0.4 \cdot Q9 + FR2`
Examples:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> fluxes.q9 = 10.0
>>> fluxes.fr2 = -0.5
>>> states.r2 = 40.0
>>> model.update_r2_v1()
>>> states.r2
r2(43.5)
"""
REQUIREDSEQUENCES = (gland_fluxes.Q9, gland_fluxes.FR2)
UPDATEDSEQUENCES = (gland_states.R2,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
sta.r2 += 0.4 * flu.q9 + flu.fr2
[docs]
class Calc_QR2_R2_V1(modeltools.Method):
r"""Calculate the outflow of the exponential routing store and update its content.
Basic equations:
.. math::
QR = \begin{cases}
X6 \cdot exp(ar) &|\ ar < -7
\\
X6 \cdot log(exp(ar) + 1) &|\ -7 \leq ar \leq 7
\\
R2 + X6 / exp(ar) &|\ ar > 7
\end{cases}
\\
ar = min(max(R2 / X6, \, -33), \, 33)
Examples:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> x6(4.5)
For large negative exponential store levels, its outflow is almost zero:
>>> states.r2 = -50.0
>>> model.calc_qr2_r2_v1()
>>> fluxes.qr2
qr2(0.000067)
>>> states.r2
r2(-50.000067)
For exponential store levels around zero, there is a significant outflow:
>>> states.r2 = 0.0
>>> model.calc_qr2_r2_v1()
>>> fluxes.qr2
qr2(3.119162)
>>> states.r2
r2(-3.119162)
For large positive exponential store levels, its outflow is highest:
>>> states.r2 = 40.0
>>> model.calc_qr2_r2_v1()
>>> fluxes.qr2
qr2(40.000621)
>>> states.r2
r2(-0.000621)
"""
CONTROLPARAMETERS = (gland_control.X6,)
UPDATEDSEQUENCES = (gland_states.R2,)
RESULTSEQUENCES = (gland_fluxes.QR2,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
con = model.parameters.control.fastaccess
flu = model.sequences.fluxes.fastaccess
sta = model.sequences.states.fastaccess
ar: float = min(max(sta.r2 / con.x6, -33.0), 33.0)
if ar < -7.0:
flu.qr2 = con.x6 * modelutils.exp(ar)
elif ar <= 7.0:
flu.qr2 = con.x6 * modelutils.log(modelutils.exp(ar) + 1.0)
else:
flu.qr2 = sta.r2 + con.x6 / modelutils.exp(ar)
sta.r2 -= flu.qr2
[docs]
class Calc_FD_V1(modeltools.Method):
r"""Calculate the groundwater exchange affecting the direct runoff.
Basic equation:
.. math::
FD = \begin{cases}
- Q1 &|\ (Q1 + FR) \leq 0
\\
FR &|\ (Q1 + FR) > 0
\end{cases}
Examples:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> fluxes.q1 = 10.0
>>> fluxes.fr = -0.5
>>> model.calc_fd_v1()
>>> fluxes.fd
fd(-0.5)
>>> fluxes.q1 = 1.0
>>> fluxes.fr = -1.5
>>> model.calc_fd_v1()
>>> fluxes.fd
fd(-1.0)
"""
REQUIREDSEQUENCES = (gland_fluxes.Q1, gland_fluxes.FR)
RESULTSEQUENCES = (gland_fluxes.FD,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
if (flu.q1 + flu.fr) <= 0.0:
flu.fd = -flu.q1
else:
flu.fd = flu.fr
[docs]
class Calc_QD_V1(modeltools.Method):
r"""Calculate the direct runoff.
Basic equation:
:math:`QD = max(Q1 + FD, \, 0)`
Examples:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> fluxes.q1 = 2.0
>>> fluxes.fd = -1.0
>>> model.calc_qd_v1()
>>> fluxes.qd
qd(1.0)
>>> fluxes.fd = -3.0
>>> model.calc_qd_v1()
>>> fluxes.qd
qd(0.0)
"""
REQUIREDSEQUENCES = (gland_fluxes.Q1, gland_fluxes.FD)
RESULTSEQUENCES = (gland_fluxes.QD,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
flu.qd = max(flu.q1 + flu.fd, 0.0)
[docs]
class Calc_QH_V1(modeltools.Method):
"""Calculate the total runoff according to GR4 and GR5.
Basic equation:
:math:`QH = QR + QD`
Example:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> fluxes.qr = 2.0
>>> fluxes.qd = 1.0
>>> model.calc_qh_v1()
>>> fluxes.qh
qh(3.0)
"""
REQUIREDSEQUENCES = (gland_fluxes.QR, gland_fluxes.QD)
RESULTSEQUENCES = (gland_fluxes.QH,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
flu.qh = flu.qr + flu.qd
[docs]
class Calc_QH_V2(modeltools.Method):
"""Calculate the total runoff according to GR6.
Basic equation:
:math:`QH = QR + QR2 + QD`
Example:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> fluxes.qr = 1.0
>>> fluxes.qr2 = 2.0
>>> fluxes.qd = 3.0
>>> model.calc_qh_v2()
>>> fluxes.qh
qh(6.0)
"""
REQUIREDSEQUENCES = (gland_fluxes.QR, gland_fluxes.QR2, gland_fluxes.QD)
RESULTSEQUENCES = (gland_fluxes.QH,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
flu.qh = flu.qr + flu.qr2 + flu.qd
[docs]
class Calc_QV_V1(modeltools.Method):
r"""Calculate total discharge in m³/s.
Basic equation:
:math:`QV = QFactor \cdot QH`
Example:
>>> from hydpy.models.gland import *
>>> parameterstep()
>>> derived.qfactor(2.0)
>>> fluxes.qh = 3.0
>>> model.calc_qv_v1()
>>> fluxes.qv
qv(6.0)
"""
DERIVEDPARAMETERS = (gland_derived.QFactor,)
REQUIREDSEQUENCES = (gland_fluxes.QH,)
RESULTSEQUENCES = (gland_fluxes.QV,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
der = model.parameters.derived.fastaccess
flu = model.sequences.fluxes.fastaccess
flu.qv = flu.qh * der.qfactor
[docs]
class Pass_Q_V1(modeltools.Method):
"""Update the outlet link sequence.
Basic equation:
:math:`Q = QV`
"""
REQUIREDSEQUENCES = (gland_fluxes.QV,)
RESULTSEQUENCES = (gland_outlets.Q,)
@staticmethod
def __call__(model: modeltools.Model) -> None:
flu = model.sequences.fluxes.fastaccess
out = model.sequences.outlets.fastaccess
out.q[0] += flu.qv
[docs]
class Model(modeltools.AdHocModel):
"""|gland.DOCNAME.complete|."""
DOCNAME = modeltools.DocName(short="G")
__HYDPY_ROOTMODEL__ = None
INLET_METHODS = (Calc_E_V1,)
RECEIVER_METHODS = ()
RUN_METHODS = (
Calc_EI_V1,
Calc_PN_V1,
Calc_EN_V1,
Update_I_V1,
Calc_PS_V1,
Calc_ES_V1,
Update_S_V1,
Calc_Perc_V1,
Update_S_V2,
Calc_AE_V1,
Calc_Pr_V1,
Calc_PR1_PR9_V1,
Calc_Q9_V1,
Calc_Q1_V1,
Calc_Q10_V1,
Calc_Q1_Q9_V2,
Calc_FR_V1,
Calc_FR_V2,
Update_R_V1,
Update_R_V3,
Update_R_V2,
Calc_QR_V1,
Update_R_V3,
Calc_FR2_V1,
Update_R2_V1,
Calc_QR2_R2_V1,
Update_R_V2,
Calc_FD_V1,
Calc_QD_V1,
Calc_QH_V1,
Calc_QH_V2,
Calc_QV_V1,
)
ADD_METHODS = (Calc_E_PETModel_V1, Calc_Q_RConcModel_V1)
OUTLET_METHODS = (Pass_Q_V1,)
SENDER_METHODS = ()
SUBMODELINTERFACES = (petinterfaces.PETModel_V1, rconcinterfaces.RConcModel_V1)
SUBMODELS = ()
petmodel = modeltools.SubmodelProperty(petinterfaces.PETModel_V1)
petmodel_is_mainmodel = modeltools.SubmodelIsMainmodelProperty()
petmodel_typeid = modeltools.SubmodelTypeIDProperty()
rconcmodel = modeltools.SubmodelProperty(rconcinterfaces.RConcModel_V1)
rconcmodel_is_mainmodel = modeltools.SubmodelIsMainmodelProperty()
rconcmodel_typeid = modeltools.SubmodelTypeIDProperty()
rconcmodel_directflow = modeltools.SubmodelProperty(rconcinterfaces.RConcModel_V1)
rconcmodel_directflow_is_mainmodel = modeltools.SubmodelIsMainmodelProperty()
rconcmodel_directflow_typeid = modeltools.SubmodelTypeIDProperty()
rconcmodel_routingstore = modeltools.SubmodelProperty(rconcinterfaces.RConcModel_V1)
rconcmodel_routingstore_is_mainmodel = modeltools.SubmodelIsMainmodelProperty()
rconcmodel_routingstore_typeid = modeltools.SubmodelTypeIDProperty()
[docs]
class Main_PETModel_V1(modeltools.AdHocModel):
"""Base class for |gland.DOCNAME.long| models that use submodels that comply with
the |PETModel_V1| interface."""
petmodel: modeltools.SubmodelProperty
petmodel_is_mainmodel = modeltools.SubmodelIsMainmodelProperty()
petmodel_typeid = modeltools.SubmodelTypeIDProperty()
@importtools.prepare_submodel(
"petmodel",
petinterfaces.PETModel_V1,
petinterfaces.PETModel_V1.prepare_nmbzones,
petinterfaces.PETModel_V1.prepare_subareas,
)
def add_petmodel_v1(
self,
petmodel: petinterfaces.PETModel_V1,
/,
*,
refresh: bool, # pylint: disable=unused-argument
) -> None:
"""Initialise the given `petmodel` that follows the |PETModel_V1| interface.
>>> from hydpy.models.gland_gr4 import *
>>> parameterstep()
>>> area(5.0)
>>> with model.add_petmodel_v1("evap_ret_tw2002"):
... nmbhru
... hruarea
... evapotranspirationfactor(1.5)
nmbhru(1)
hruarea(5.0)
>>> etf = model.petmodel.parameters.control.evapotranspirationfactor
>>> etf
evapotranspirationfactor(1.5)
"""
control = self.parameters.control
petmodel.prepare_nmbzones(1)
petmodel.prepare_subareas(control.area.value)
[docs]
class Main_RConcModel_V1(modeltools.AdHocModel):
"""Base class for |gland.DOCNAME.long| models that use a single submodel that
complies with the |RConcModel_V1| interface."""
rconcmodel: modeltools.SubmodelProperty
rconcmodel_is_mainmodel = modeltools.SubmodelIsMainmodelProperty()
rconcmodel_typeid = modeltools.SubmodelTypeIDProperty()
@importtools.prepare_submodel("rconcmodel", rconcinterfaces.RConcModel_V1)
def add_rconcmodel_v1(
self, rconcmodel: rconcinterfaces.RConcModel_V1, /, *, refresh: bool
) -> None:
"""Initialise the given submodel that follows the |RConcModel_V1| interface and
is responsible for calculating runoff concentration.
>>> from hydpy.models.gland_gr5 import *
>>> simulationstep("1d")
>>> parameterstep("1d")
>>> with model.add_rconcmodel_v1("rconc_uh"):
... uh("gr_uh2", x4=3.0)
>>> model.rconcmodel.parameters.control.uh
uh("gr_uh2", x4=3.0)
"""
def _get_rconcmodel_waterbalance(
self, initial_conditions: ConditionsModel
) -> float:
"""Get the water balance of the single runoff concentration submodel if
used."""
if self.rconcmodel:
return self.rconcmodel.get_waterbalance(
initial_conditions["model.rconcmodel"]
)
return 0.0
[docs]
class Main_RConcModel_V2(modeltools.AdHocModel):
"""Base class for |gland.DOCNAME.long| models that use two submodels that comply
with the |RConcModel_V1| interface."""
rconcmodel_routingstore: modeltools.SubmodelProperty
rconcmodel_routingstore_is_mainmodel = modeltools.SubmodelIsMainmodelProperty()
rconcmodel_routingstore_typeid = modeltools.SubmodelTypeIDProperty()
rconcmodel_directflow: modeltools.SubmodelProperty
rconcmodel_directflow_is_mainmodel = modeltools.SubmodelIsMainmodelProperty()
rconcmodel_directflow_typeid = modeltools.SubmodelTypeIDProperty()
@importtools.prepare_submodel(
"rconcmodel_routingstore", rconcinterfaces.RConcModel_V1
)
def add_rconcmodel_routingstore_v1(
self, rconcmodel: rconcinterfaces.RConcModel_V1, /, *, refresh: bool
) -> None:
"""Initialise the given submodel that follows the |RConcModel_V1| interface and
is responsible for calculating the runoff concentration related to the routing
store.
>>> from hydpy.models.gland_gr4 import *
>>> simulationstep("1d")
>>> parameterstep("1d")
>>> with model.add_rconcmodel_routingstore_v1("rconc_uh"):
... uh("gr_uh1", x4=2.0)
>>> model.rconcmodel_routingstore.parameters.control.uh
uh("gr_uh1", x4=2.0)
"""
@importtools.prepare_submodel(
"rconcmodel_directflow", rconcinterfaces.RConcModel_V1
)
def add_rconcmodel_directflow_v1(
self, rconcmodel: rconcinterfaces.RConcModel_V1, /, *, refresh: bool
) -> None:
"""Initialise the given submodel that follows the |RConcModel_V1| interface and
is responsible for calculating the runoff concentration related to the direct
runoff.
>>> from hydpy.models.gland_gr4 import *
>>> simulationstep("1d")
>>> parameterstep("1d")
>>> with model.add_rconcmodel_directflow_v1("rconc_uh"):
... uh("gr_uh2", x4=3.0)
>>> model.rconcmodel_directflow.parameters.control.uh
uh("gr_uh2", x4=3.0)
"""
def _get_rconcmodel_waterbalance_routingstore(
self, initial_conditions: ConditionsModel
) -> float:
r"""Get the water balance of the routing store runoff concentration submodel if
used."""
if self.rconcmodel_routingstore:
return self.rconcmodel_routingstore.get_waterbalance(
initial_conditions["model.rconcmodel_routingstore"]
)
return 0.0
def _get_rconcmodel_waterbalance_directflow(
self, initial_conditions: ConditionsModel
) -> float:
r"""Get the water balance of the direct flow runoff concentration submodel if
used."""
if self.rconcmodel_directflow:
return self.rconcmodel_directflow.get_waterbalance(
initial_conditions["model.rconcmodel_directflow"]
)
return 0.0