# -*- coding: utf-8 -*-
# pylint: disable=missing-module-docstring
# import...
# ...from HydPy
from hydpy.core import objecttools
from hydpy.core import parametertools
from hydpy.core.typingtools import *
from hydpy.models.wland import wland_constants
from hydpy.models.wland import wland_masks
if TYPE_CHECKING:
from hydpy.core import variabletools
[docs]
class SoilParameter(parametertools.Parameter):
"""Base class for parameters related to the soil character.
Some parameters of |wland.DOCNAME.long| are strongly related to the soil character
and come with default values. To apply these default values, use the `soil` keyword
in combination with one of the available soil constants.
We take parameter |B| and the soil character |SAND| as an example, which has the
default value `4.05`:
>>> from hydpy.models.wland import *
>>> parameterstep()
>>> b(soil=SAND)
>>> b
b(soil=SAND)
>>> from hydpy import round_
>>> round_(b.value)
4.05
You are free to ignore the default values and to set anything you like:
>>> b.value = 3.0
>>> b
b(3.0)
The string representation relies on the `soil` keyword only when used to define the
value directly beforehand:
>>> b(4.05)
>>> b
b(4.05)
For a list of the available defaults, see the respective parameter's documentation
or the error message that class |SoilParameter| raises if one passes a wrong
value:
>>> b(soil=0)
Traceback (most recent call last):
...
ValueError: While trying the set the value of parameter `b` of element `?`, the \
following error occurred: The given soil constant `0` is not among the available \
ones. Please use one of the following constants: SAND (1), LOAMY_SAND (2), \
SANDY_LOAM (3), SILT_LOAM (4), LOAM (5), SANDY_CLAY_LOAM (6), SILT_CLAY_LOAM (7), \
CLAY_LOAM (8), SANDY_CLAY (9), SILTY_CLAY (10), and CLAY (11).
Combining the `soil` keyword with other keywords is not allowed:
>>> b(soil=SAND, landuse='acre')
Traceback (most recent call last):
...
TypeError: While trying the set the value of parameter `b` of element `?`, the \
following error occurred: It is not allowed to combine keyword `soil` with other \
keywords, but the following ones are also used: landuse.
>>> b(landuse='acre')
Traceback (most recent call last):
...
NotImplementedError: While trying the set the value of parameter `b` of element \
`?`, the following error occurred: The value(s) of parameter `b` of element `?` could \
not be set based on the given keyword arguments.
"""
_SOIL2VALUE: dict[int, float]
_soil: Optional[int]
def __init__(self, subvars: parametertools.SubParameters):
super().__init__(subvars)
self._soil = None
def __call__(self, *args, **kwargs) -> None:
self._soil = None
try:
super().__call__(*args, **kwargs)
except NotImplementedError as exc:
try:
soil = kwargs.pop("soil", None)
if soil is None:
raise exc
if kwargs:
raise TypeError(
f"It is not allowed to combine keyword `soil` with other "
f"keywords, but the following ones are also used: "
f"{objecttools.enumeration(kwargs.keys())}."
) from None
try:
self(self._SOIL2VALUE[soil])
self._soil = soil
except KeyError:
value2name = wland_constants.CONSTANTS.value2name
names = (
f"{value2name[value]} ({value})"
for value in self._SOIL2VALUE.keys()
)
raise ValueError(
f"The given soil constant `{soil}` is not among the available "
f"ones. Please use one of the following constants: "
f"{objecttools.enumeration(names)}."
) from None
except BaseException:
objecttools.augment_excmessage(
f"While trying the set the value of parameter "
f"{objecttools.elementphrase(self)}"
)
[docs]
@classmethod
def print_defaults(cls):
"""Print the soil-related default values of the parameter.
See the documentation on class |B| for an example.
"""
value2name = wland_constants.CONSTANTS.value2name
for constant, value in cls._SOIL2VALUE.items():
print(value2name[constant], end=": ")
objecttools.round_(value)
def __repr__(self) -> str:
soil = self._soil
value = self.value
if soil and (self._SOIL2VALUE[soil] == value):
name = wland_constants.SOIL_CONSTANTS.value2name[soil]
return f"{self.name}(soil={name})"
return f"{self.name}({objecttools.repr_(value)})"
[docs]
class LanduseParameterLand(parametertools.ZipParameter):
"""Base class for 1-dimensional parameters relevant for all land-related units.
We take the parameter |DDT| as an example. You can define its values by using the
names of all land use-related constants in lower-case as keywords:
>>> from hydpy import print_vector, round_
>>> from hydpy.models.wland import *
>>> simulationstep("1d")
>>> parameterstep("1d")
>>> nu(13)
>>> lt(SEALED, FIELD, WINE, ORCHARD, SOIL, PASTURE, WETLAND,
... TREES, CONIFER, DECIDIOUS, MIXED, SEALED, WATER)
>>> ddf(sealed=0.0, field=1.0, wine=2.0, orchard=3.0, soil=4.0, pasture=5.0,
... wetland=6.0, trees=7.0, conifer=8.0, decidious=9.0, mixed=10.0)
>>> ddf
ddf(conifer=8.0, decidious=9.0, field=1.0, mixed=10.0, orchard=3.0,
pasture=5.0, sealed=0.0, soil=4.0, trees=7.0, wetland=6.0,
wine=2.0)
>>> print_vector(ddf.values)
0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 0.0, nan
You can average the current values with regard to the hydrological response area
fractions, defined via parameter |AUR|:
>>> aur(0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12, 0.22)
>>> round_(ddf.average_values())
5.641026
You can query or change the values related to specific land use types via attribute
access:
>>> print_vector(ddf.sealed)
0.0, 0.0
>>> ddf.sealed = 11.0, 12.0
>>> ddf
ddf(11.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 12.0, nan)
>>> ddf.sealed = 12.0
>>> ddf
ddf(conifer=8.0, decidious=9.0, field=1.0, mixed=10.0, orchard=3.0,
pasture=5.0, sealed=12.0, soil=4.0, trees=7.0, wetland=6.0,
wine=2.0)
"""
constants = wland_constants.LANDUSE_CONSTANTS
mask = wland_masks.Land()
@property
def refweights(self):
"""Alias for the associated instance of |AUR| for calculating areal mean
values."""
return self.subpars.aur
[docs]
class LanduseMonthParameter(parametertools.KeywordParameter2D):
"""Base class for parameters which values depend on the actual month and land-use
type."""
columnnames = (
"jan",
"feb",
"mar",
"apr",
"may",
"jun",
"jul",
"aug",
"sep",
"oct",
"nov",
"dec",
)
rownames = tuple(
key.lower()
for value, key in sorted(wland_constants.LANDUSE_CONSTANTS.value2name.items())
)