Exemplo n.º 1
0
    def trim(self, lower=None, upper=None):
        """Trim upper values in accordance with :math:`EQI2 \\leq EQI1`.

        >>> from hydpy.models.lland import *
        >>> parameterstep("1d")
        >>> eqi2.value = 1.0
        >>> eqi1(0.0)
        >>> eqi1
        eqi1(1.0)
        >>> eqi1(1.0)
        >>> eqi1
        eqi1(1.0)
        >>> eqi1(2.0)
        >>> eqi1
        eqi1(2.0)
        """
        if lower is None:
            lower = exceptiontools.getattr_(
                self.subpars.eqi2,
                "value",
                None,
            )
        if upper is None:
            upper = exceptiontools.getattr_(
                self.subpars.eqb,
                "value",
                None,
            )
        super().trim(lower, upper)
Exemplo n.º 2
0
    def trim(self, lower=None, upper=None):
        """Trim values in accordance with :math:`PWP \\leq FK \\leq WMax`.

        >>> from hydpy.models.lland import *
        >>> parameterstep()
        >>> nhru(3)
        >>> lnk(ACKER)
        >>> wmax(100.0)
        >>> pwp(-10.0, 50.0, 110.0)
        >>> pwp
        pwp(0.0, 50.0, 100.0)

        >>> fk.values = 80.0
        >>> pwp.trim()
        >>> pwp
        pwp(0.0, 50.0, 80.0)
        """
        if upper is None:
            upper = exceptiontools.getattr_(
                self.subpars.fk,
                "value",
                None,
            )
            if upper is None:
                upper = exceptiontools.getattr_(
                    self.subpars.wmax,
                    "value",
                    None,
                )
        super().trim(lower, upper)
Exemplo n.º 3
0
 def __call__(self, *args, **kwargs):
     try:
         super().__call__(*args, **kwargs)
     except NotImplementedError as exc:
         counter = ("khq" in kwargs) + ("hq" in kwargs)
         if counter == 0:
             raise ValueError(
                 f"For parameter {objecttools.elementphrase(self)} a "
                 f"value can be set directly or indirectly by using "
                 f"the keyword arguments `khq` and `hq`."
             ) from exc
         if counter == 1:
             raise ValueError(
                 f"For the alternative calculation of parameter "
                 f"{objecttools.elementphrase(self)}, at least the "
                 f"keywords arguments `khq` and `hq` must be given."
             ) from exc
         alpha = float(
             kwargs.get(
                 "alpha",
                 exceptiontools.getattr_(self.subpars.alpha, "value", numpy.nan),
             )
         )
         if numpy.isnan(alpha):
             raise RuntimeError(
                 f"For the alternative calculation of parameter "
                 f"{objecttools.elementphrase(self)}, either the "
                 f"keyword argument `alpha` must be given or the value "
                 f"of parameter `alpha` must be defined beforehand."
             ) from exc
         khq = float(kwargs["khq"])
         hq = float(kwargs["hq"])
         self(hq / ((hq / khq) ** (alpha + 1.0)))
Exemplo n.º 4
0
    def new(cls, variable: "typingtools.VariableProtocol", **kwargs):
        """Return a new |IndexMask| object of the same shape as the
        parameter referenced by |property| |IndexMask.refindices|.
        Entries are only |True|, if the integer values of the
        respective entries of the referenced parameter are contained
        in the |IndexMask| class attribute tuple `RELEVANT_VALUES`.

        Before calling new (explicitly or implicitely), one must prepare
        the variable returned by property |IndexMask.refindices|:

        >>> from hydpy.models.hland import *
        >>> parameterstep()
        >>> states.sm.mask
        Traceback (most recent call last):
        ...
        RuntimeError: The mask of parameter `sm` of element `?` cannot be \
determined as long as parameter `zonetype` is not prepared properly.

        >>> nmbzones(4)
        >>> zonetype(FIELD, FOREST, ILAKE, GLACIER)
        >>> states.sm.mask
        Soil([ True,  True, False, False])
        """
        indices = cls.get_refindices(variable)
        if numpy.min(exceptiontools.getattr_(indices, "values", 0)) < 1:
            raise RuntimeError(
                f"The mask of parameter {objecttools.elementphrase(variable)} "
                f"cannot be determined as long as parameter `{indices.name}` "
                f"is not prepared properly."
            )
        return cls.array2mask(numpy.in1d(indices.values, cls.RELEVANT_VALUES), **kwargs)
Exemplo n.º 5
0
    def __call__(self, *args, **kwargs) -> None:
        self._keywordarguments = parametertools.KeywordArguments(False)
        idx = self._find_kwargscombination(args, kwargs, (set(("lag", )), ))
        if idx is None:
            super().__call__(*args, **kwargs)
        else:
            lag = parametertools.trim_kwarg(self,
                                            "lag",
                                            kwargs["lag"],
                                            lower=0.0)
            lag /= self.get_timefactor()
            self.value = int(round(lag))
            self._keywordarguments = parametertools.KeywordArguments(lag=lag)

        shape = self.value
        model = self.subpars.pars.model
        model.nmb_segments = shape
        pars, seqs = model.parameters, model.sequences
        for subvars in (
                pars.control,
                pars.derived,
                seqs.factors,
                seqs.fluxes,
                seqs.states,
        ):
            for variable in (var for var in subvars if var.NDIM == 1):
                if variable.name == "coefficients":
                    continue
                oldshape = exceptiontools.getattr_(variable, "shape", None)
                if variable.name == "discharge":
                    if oldshape != (shape + 1, ):
                        variable.shape = (shape + 1, )
                else:
                    if oldshape != (shape, ):
                        variable.shape = (shape, )
Exemplo n.º 6
0
 def _convertandtest(values, name):
     try:
         type_ = float if isinstance(values[0], float) else int
         array = numpy.array(values, dtype=type_)
     except BaseException:
         objecttools.augment_excmessage(
             f"While trying to assign a new `{name}` "
             f"index array to an Indexer object"
         )
     if array.ndim != 1:
         raise ValueError(
             f"The `{name}` index array of an Indexer object must be "
             f"1-dimensional.  However, the given value has interpreted "
             f"as a {array.ndim}-dimensional object."
         )
     timegrids = exceptiontools.getattr_(hydpy.pub, "timegrids")
     if timegrids is not None:
         if len(array) != len(timegrids.init):
             raise ValueError(
                 f"The `{name}` index array of an Indexer object must have "
                 f"a number of entries fitting to the initialization time "
                 f"period precisely.  However, the given value has been "
                 f"interpreted to be of length `{len(array)}` and the "
                 f"length of the Timegrid object representing the actual "
                 f"initialisation period is `{len(timegrids.init)}`."
             )
     return array
Exemplo n.º 7
0
    def trim(self, lower=None, upper=None):
        """Trim values in accordance with :math:`AngstromFactor \\leq  1 -
        AngstromConstant` or at least in accordance with :math:`AngstromFactor
        \\leq  1`.

        >>> from hydpy.models.lland import *
        >>> parameterstep()
        >>> angstromconstant(0.4, 0.4, nan, 0.4, 0.4, 0.4,
        ...                  0.6, 0.8, 1.0, 1.0, nan, nan)
        >>> angstromfactor(-0.2, 0.0, 0.2, 0.4, 0.6, 0.8,
        ...                1.0, 1.2, 1.4, 1.6, 1.8, 2.0)
        >>> angstromfactor
        angstromfactor(jan=0.0, feb=0.0, mar=0.2, apr=0.4, may=0.6, jun=0.6,
                       jul=0.4, aug=0.2, sep=0.0, oct=0.0, nov=1.0, dec=1.0)
        >>> angstromconstant(None)
        >>> angstromfactor(0.6)
        >>> angstromfactor
        angstromfactor(0.6)
        """
        if upper is None:
            upper = exceptiontools.getattr_(
                self.subpars.angstromconstant,
                "values",
                None,
            )
            if upper is not None:
                upper = upper.copy()
                idxs = numpy.isnan(upper)
                upper[idxs] = 1.0
                idxs = ~idxs
                upper[idxs] = 1.0 - upper[idxs]
        super().trim(lower, upper)
Exemplo n.º 8
0
    def trim(self, lower=None, upper=None):
        r"""Trim |ThetaS| following :math:`1e^{-6} \leq ThetaS \leq 1.0` and,
        if |ThetaR| exists for the relevant application model, also following
        :math:`ThetaR \leq ThetaS`.

        >>> from hydpy.models.wland import *
        >>> parameterstep()

        >>> thetas(0.0)
        >>> thetas
        thetas(0.000001)

        >>> thetar.value = 0.5
        >>> thetas(0.4)
        >>> thetas
        thetas(0.5)

        >>> thetas(soil=SANDY_LOAM)
        >>> thetas
        thetas(0.5)

        >>> thetas(1.01)
        >>> thetas
        thetas(1.0)
        """
        if lower is None:
            if exceptiontools.hasattr_(self.subpars, "thetar"):
                lower = exceptiontools.getattr_(self.subpars.thetar, "value",
                                                1e-6)
            else:
                lower = 1e-6
        super().trim(lower, upper)
Exemplo n.º 9
0
def _get_timegrids(func):
    timegrids = exceptiontools.getattr_(hydpy.pub, "timegrids", None)
    if timegrids is None:
        name = func.__name__[1:]
        raise exceptiontools.AttributeNotReady(
            f"An Indexer object has been asked for an `{name}` array.  "
            f"Such an array has neither been determined yet nor can it "
            f"be determined automatically at the moment.   Either define "
            f"an `{name}` array manually and pass it to the Indexer "
            f"object, or make a proper Timegrids object available within "
            f"the pub module."
        )
    return timegrids
Exemplo n.º 10
0
 def __call__(self, *args, **kwargs):
     old = exceptiontools.getattr_(self, "value", None)
     super().__call__(*args, **kwargs)
     new = self.__hydpy__get_value__()
     if new != old:
         for subpars in self.subpars.pars.model.parameters:
             for par in subpars:
                 if (par.NDIM == 1) and (not isinstance(
                         par, parametertools.MonthParameter)):
                     par.__hydpy__set_shape__(new)
         for subseqs in self.subpars.pars.model.sequences:
             for seq in subseqs:
                 if seq.NDIM == 1:
                     seq.__hydpy__set_shape__(new)
Exemplo n.º 11
0
    def trim(self, lower=None, upper=None):
        r"""Trim |ThetaR| following :math:`1e^{-6} \leq ThetaR \leq ThetaS`.

        >>> from hydpy.models.wland import *
        >>> parameterstep()
        >>> thetar(0.0)
        >>> thetar
        thetar(0.000001)
        >>> thetas(0.41)
        >>> thetar(0.42)
        >>> thetar
        thetar(0.41)
        """
        if upper is None:
            upper = exceptiontools.getattr_(self.subpars.thetas, "value", None)
        super().trim(lower, upper)
Exemplo n.º 12
0
    def trim(self, lower=None, upper=None):
        """Trim upper values in accordance with :math:`DMax \\geq DMin`.

        >>> from hydpy.models.lland import *
        >>> parameterstep("1d")
        >>> simulationstep("12h")
        >>> nhru(3)
        >>> lnk(ACKER)
        >>> dmin.values = 2.0
        >>> dmax(2.0, 4.0, 6.0)
        >>> dmax
        dmax(4.0, 4.0, 6.0)
        """
        if lower is None:
            lower = exceptiontools.getattr_(
                self.subpars.dmin,
                "value",
                None,
            )
        super().trim(lower, upper)
Exemplo n.º 13
0
    def trim(self, lower=None, upper=None):
        """Trim upper values in accordance with :math:`EQD2 \\leq EQD1`.

        >>> from hydpy.models.lland import *
        >>> parameterstep("1d")
        >>> eqd1.value = 3.0
        >>> eqd2(2.0)
        >>> eqd2
        eqd2(2.0)
        >>> eqd2(3.0)
        >>> eqd2
        eqd2(3.0)
        >>> eqd2(4.0)
        >>> eqd2
        eqd2(3.0)
        """
        if upper is None:
            upper = exceptiontools.getattr_(
                self.subpars.eqd1,
                "value",
                None,
            )
        super().trim(lower, upper)
Exemplo n.º 14
0
    def trim(self, lower=None, upper=None):
        """Trim upper values in accordance with :math:`GSBGrad1 \\leq GSBGrad2`.

        >>> from hydpy.models.lland import *
        >>> simulationstep("1h")
        >>> parameterstep("1d")
        >>> gsbgrad1(1.0)
        >>> gsbgrad2(2.0)
        >>> gsbgrad2
        gsbgrad2(2.0)
        >>> gsbgrad2(1.0)
        >>> gsbgrad2
        gsbgrad2(1.0)
        >>> gsbgrad2(0.0)
        >>> gsbgrad2
        gsbgrad2(1.0)
        """
        if lower is None:
            lower = exceptiontools.getattr_(
                self.subpars.gsbgrad1,
                "value",
                None,
            )
        super().trim(lower, upper)
Exemplo n.º 15
0
 def _fset(self, values):
     self.values = self._convertandtest(values, self.name)
     self.timegrids = copy.deepcopy(exceptiontools.getattr_(hydpy.pub, "timegrids"))
Exemplo n.º 16
0
 def call_fget(self, obj) -> NDArrayFloat:
     timegrids = exceptiontools.getattr_(hydpy.pub, "timegrids", None)
     if (self.values is None) or (self.timegrids != timegrids):
         self.values = self._calcidxs(self.fget(obj))
         self.timegrids = copy.deepcopy(timegrids)
     return self.values
Exemplo n.º 17
0
    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 the required log
        entries depends on the simulation step size:

        >>> from hydpy.models.lland import *
        >>> parameterstep()
        >>> from hydpy import pub
        >>> pub.timegrids = "2000-01-01", "2000-01-02", "1h"
        >>> derived.nmblogentries.update()
        >>> derived.nmblogentries
        nmblogentries(24)
        >>> logs
        wet0(nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
             nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan)
        loggedteml(nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
                   nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan)
        loggedrelativehumidity(nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
                               nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
                               nan, nan, nan, nan)
        loggedsunshineduration(nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
                               nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
                               nan, nan, nan, nan)
        loggedpossiblesunshineduration(nan, nan, nan, nan, nan, nan, nan, nan,
                                       nan, nan, nan, nan, nan, nan, nan, nan,
                                       nan, nan, nan, nan, nan, nan, nan, nan)
        loggedglobalradiation(nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
                              nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
                              nan, nan, nan, nan)
        loggedwindspeed2m(nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
                          nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
                          nan, nan)

        To prevent from loosing information, updating parameter |NmbLogEntries| resets
        the shape of the relevant log sequences only when necessary:

        >>> logs.wet0 = 1.0
        >>> logs.loggedteml = 2.0
        >>> logs.loggedrelativehumidity.shape = (6,)
        >>> logs.loggedrelativehumidity = 3.0
        >>> derived.nmblogentries.update()
        >>> logs   # doctest: +ELLIPSIS
        wet0(1.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,
             1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0)
        loggedteml(2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
                   2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0)
        loggedrelativehumidity(nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
                               nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
                               nan, nan, nan, nan)
        ...

        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.

        .. testsetup::

            >>> del pub.timegrids
        """
        nmb = "1d" / hydpy.pub.options.simulationstep
        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)
        nmb = int(nmb)
        logs = self.subpars.pars.model.sequences.logs
        for seq in logs:
            shape = exceptiontools.getattr_(seq, "shape", (None, ))
            if nmb != shape[-1]:
                seq.shape = nmb