Source code for hydpy.models.evap.evap_derived

# -*- coding: utf-8 -*-
# pylint: disable=missing-module-docstring

# import...
# ...from site-packages
import numpy

# ...from HydPy
import hydpy
from hydpy.core import exceptiontools
from hydpy.core import objecttools
from hydpy.core import parametertools

# ...from evap
from hydpy.models.evap import evap_parameters
from hydpy.models.evap import evap_control
from hydpy.models.evap import evap_fixed
from hydpy.models.evap import evap_logs


[docs] class MOY(parametertools.MOYParameter): """References the "global" month of the year index array [-]."""
[docs] class HRUAreaFraction(parametertools.Parameter): """The area fraction of each hydrological response unit [-].""" NDIM, TYPE, TIME, SPAN = 1, float, None, (0.0, 1.0) CONTROLPARAMETERS = (evap_control.HRUArea,)
[docs] def update(self) -> None: r"""Calculate the fractions based on :math:`HRUAreaFraction_i = HRUArea_i / \Sigma HRUArea`. >>> from hydpy.models.evap import * >>> parameterstep() >>> nmbhru(5) >>> hruarea(10.0, 40.0, 20.0, 25.0, 5.0) >>> derived.hruareafraction.update() >>> derived.hruareafraction hruareafraction(0.1, 0.4, 0.2, 0.25, 0.05) """ hruarea = self.subpars.pars.control.hruarea.values self.values = hruarea / numpy.sum(hruarea)
[docs] class Altitude(parametertools.Parameter): """Average (reference) subbasin altitude [100m].""" NDIM, TYPE, TIME, SPAN = 0, float, None, (None, None) CONTROLPARAMETERS = (evap_control.HRUArea, evap_control.HRUAltitude)
[docs] def update(self) -> None: """Average the individual hydrological response units' altitudes. >>> from hydpy.models.evap import * >>> parameterstep() >>> nmbhru(3) >>> hruarea(5.0, 3.0, 2.0) >>> hrualtitude(1.0, 3.0, 8.0) >>> derived.altitude.update() >>> derived.altitude altitude(3.0) """ control = self.subpars.pars.control self.value = numpy.dot( control.hruarea.values, control.hrualtitude.values ) / numpy.sum(control.hruarea.values)
[docs] class Seconds(parametertools.SecondsParameter): """The length of the actual simulation step size in seconds [h]."""
[docs] class Hours(parametertools.HoursParameter): """The length of the actual simulation step size in hours [h]."""
[docs] class Days(parametertools.DaysParameter): """The length of the actual simulation step size in days [d]."""
[docs] class NmbLogEntries(parametertools.Parameter): """The number of log entries required for a memory duration of 24 hours [-].""" NDIM, TYPE, TIME, SPAN = 0, int, None, (1, None)
[docs] def update(self): """Calculate the number of entries and adjust the shape of all relevant log sequences. The aimed memory duration is one day. Hence, the number of required log entries depends on the simulation step size: >>> from hydpy.models.evap import * >>> parameterstep() >>> from hydpy import pub >>> pub.timegrids = "2000-01-01", "2000-01-02", "8h" >>> nmbhru(2) >>> derived.nmblogentries.update() >>> derived.nmblogentries nmblogentries(3) >>> logs.loggedglobalradiation loggedglobalradiation(nan, nan, nan) For 1-dimensional logged properties, there is a second axis whose size depends on the selected number of hydrological response units: >>> logs.loggedairtemperature loggedairtemperature([[nan, nan], [nan, nan], [nan, nan]]) >>> logs.loggedpotentialevapotranspiration loggedpotentialevapotranspiration(nan, nan, nan) To prevent losing information, updating parameter |NmbLogEntries| resets the shape of the relevant log sequences only when necessary: >>> logs.loggedglobalradiation = 1.0 >>> logs.loggedairtemperature = 2.0 >>> logs.loggedpotentialevapotranspiration = 3.0 >>> derived.nmblogentries.update() >>> logs.loggedglobalradiation loggedglobalradiation(1.0, 1.0, 1.0) >>> logs.loggedairtemperature loggedairtemperature([[2.0, 2.0], [2.0, 2.0], [2.0, 2.0]]) >>> logs.loggedpotentialevapotranspiration loggedpotentialevapotranspiration(3.0, 3.0, 3.0) There is an explicit check for inappropriate simulation step sizes: >>> pub.timegrids = "2000-01-01 00:00", "2000-01-01 10:00", "5h" >>> derived.nmblogentries.update() Traceback (most recent call last): ... ValueError: The value of parameter `nmblogentries` of element `?` cannot be \ determined for a the current simulation step size. The fraction of the memory period \ (1d) and the simulation step size (5h) leaves a remainder. """ nmb = "1d" / hydpy.pub.timegrids.stepsize if nmb % 1: raise ValueError( f"The value of parameter {objecttools.elementphrase(self)} cannot be " f"determined for a the current simulation step size. The fraction of " f"the memory period (1d) and the simulation step size " f"({hydpy.pub.timegrids.stepsize}) leaves a remainder." ) self(nmb) pars = self.subpars.pars for seq in pars.model.sequences.logs: if isinstance(seq, evap_logs.LoggedPotentialEvapotranspiration): new_shape = self.value old_shape = exceptiontools.getattr_(seq, "shape", (None, None))[1] else: if seq.NDIM == 1: new_shape = (self.value,) elif seq.NDIM == 2: new_shape = self.value, pars.control.nmbhru.value else: assert False old_shape = exceptiontools.getattr_(seq, "shape", (None,)) if new_shape != old_shape: seq.shape = new_shape
[docs] class RoughnessLength( evap_parameters.LandMonthParameter ): # ToDo: not directy required, remove? """Roughness length [m].""" TYPE, TIME, SPAN = float, None, (0.0, None) CONTROLPARAMETERS = (evap_control.CropHeight,)
[docs] def update(self): r"""Calculate the roughness length based on :math:`max(0.13 \cdot CropHeight, \ 0.00013)`. The original equation seems to go back to Montheith. We added the minimum value of 0.13 mm to cope with water areas and bare soils (to avoid zero roughness lengths): ToDo: Add a reference. >>> from hydpy.models.evap import * >>> parameterstep() >>> nmbhru(3) >>> cropheight( ... ANY=[0.0, 0.001, 0.01, 0.1, 1.0, 2.0, 3.0, 4.0, 5.0, 10.0, 15.0, 20.0]) >>> derived.roughnesslength.update() >>> derived.roughnesslength roughnesslength(ANY=[0.00013, 0.00013, 0.0013, 0.013, 0.13, 0.26, 0.39, 0.52, 0.65, 1.3, 1.95, 2.6]) """ cropheight = self.subpars.pars.control.cropheight.values self.values = numpy.clip(0.13 * cropheight, 0.00013, None)
[docs] class AerodynamicResistanceFactor(evap_parameters.LandMonthParameter): """Factor for calculating aerodynamic resistance [-].""" TYPE, TIME, SPAN = float, None, (0.0, None) CONTROLPARAMETERS = (evap_control.CropHeight,) DERIVEDPARAMETERS = (RoughnessLength,) FIXEDPARAMETERS = (evap_fixed.AerodynamicResistanceFactorMinimum,)
[docs] def update(self): r"""Calculate the factor for calculating aerodynamic resistance based on the :math:`max \big( ln(2 / z_0) \cdot ln(10 / z_0) / 0.41^2, \ \tau \big)` with :math:`z_0` being the |RoughnessLength| :cite:p:`ref-Löpmeier2014` and :math:`\tau` the "alternative value" suggested by :cite:t:`ref-Thompson1981` and also used by :cite:t:`ref-LARSIM`. >>> from hydpy.models.evap import * >>> parameterstep() >>> derived.roughnesslength( ... ANY=[0.00013, 0.00013, 0.0013, 0.013, 0.13, 0.26, 0.39, 0.52, 0.65, ... 1.3, 1.95, 2.6]) >>> derived.aerodynamicresistancefactor.update() >>> derived.aerodynamicresistancefactor aerodynamicresistancefactor(ANY=[752.975177, 752.975177, 476.301466, 262.708041, 112.194903, 94.0, 94.0, 94.0, 94.0, 94.0, 94.0, 94.0]) """ pars = self.subpars.pars z0 = pars.derived.roughnesslength.values min_ = pars.fixed.aerodynamicresistancefactorminimum.value self.values = numpy.clip( numpy.log(10.0 / z0) * numpy.log(10.0 / z0) / 0.41**2, min_, None )