itemtools

This module implements so-called exchange items that simplify modifying the values of Parameter and Sequence_ objects.

Module itemtools implements the following members:


class hydpy.core.itemtools.ExchangeSpecification(*, master: str, variable: str, keyword: str | None = None)[source]

Bases: object

Specification of a concrete Parameter or Sequence_ type.

ExchangeSpecification is a helper class for ExchangeItem and its subclasses. Its constructor interprets two strings and one optional string (without any plausibility checks) and makes their information available as attributes. The following tests list the expected cases:

>>> from hydpy.core.itemtools import ExchangeSpecification
>>> ExchangeSpecification(master="musk_classic", variable="control.nmbsequences",
...                       keyword="lag")
ExchangeSpecification(master="musk_classic", variable="control.nmbsequences", keyword="lag")
>>> ExchangeSpecification(master="hland_96", variable="fluxes.qt")
ExchangeSpecification(master="hland_96", variable="fluxes.qt")
>>> ExchangeSpecification(master="hland_96", variable="fluxes.qt.series")
ExchangeSpecification(master="hland_96", variable="fluxes.qt.series")
>>> ExchangeSpecification(master="node", variable="sim")
ExchangeSpecification(master="node", variable="sim")
>>> ExchangeSpecification(master="node", variable="sim.series")
ExchangeSpecification(master="node", variable="sim.series")

The following attributes are accessible:

>>> spec = ExchangeSpecification(master="musk_classic",
...                              variable="control.nmbsequences", keyword="lag")
>>> spec.master
'musk_classic'
>>> spec.subgroup
'control'
>>> spec.variable
'nmbsequences'
>>> spec.series
False
>>> spec.keyword
'lag'
master: str

Either “node” or the name of the relevant base or application model (e. g. “hland_96”).

series: bool

Flag indicating whether to tackle the target variable’s actual values (False) or complete time series (True).

subgroup: str | None

For model variables, the name of the parameter or sequence subgroup of the target or base variable; for node sequences, None.

variable: str

Name of the target or base variable.

keyword: str | None

(Optional) name of the target keyword argument of the target or base variable.

property specstring: str

The string corresponding to the current values of subgroup, state, and variable.

>>> from hydpy.core.itemtools import ExchangeSpecification
>>> spec = ExchangeSpecification(master="hland_96", variable="fluxes.qt")
>>> spec.specstring
'fluxes.qt'
>>> spec.series = True
>>> spec.specstring
'fluxes.qt.series'
>>> spec.subgroup = None
>>> spec.specstring
'qt.series'
class hydpy.core.itemtools.ExchangeItem[source]

Bases: object

Base class for exchanging values with multiple Parameter or Sequence_ objects of a concrete type.

name: Name

The name of the exchange item.

targetspecs: ExchangeSpecification

The exchange specification for the chosen target variable.

device2target: dict[Node | Element, Variable]

A target variable object for each device.

selection2targets: dict[str, tuple[Variable, ...]]

A tuple of target variable objects for each selection.

property ndim: int

The number of dimensions of the handled value vector.

Property ndim needs to be overwritten by the concrete subclasses:

>>> from hydpy.core.itemtools import ExchangeItem
>>> ExchangeItem().ndim
Traceback (most recent call last):
...
NotImplementedError
collect_variables(selections: Selections) None[source]

Collect the relevant target variables handled by the devices of the given Selections object.

We prepare the HydPy-H-Lahn example project to be able to use its Selections object:

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()

We change the type of a specific application model to the type of its base model for reasons explained later:

>>> from hydpy.models.hland import Model
>>> hp.elements.land_lahn_kalk.model.__class__ = Model

We prepare an ExchangeItem as an example, handling all Ic sequences corresponding to any application models derived from hland:

>>> from hydpy.core.itemtools import ExchangeItem, ExchangeSpecification
>>> item = ExchangeItem()

ExchangeItem is only a base class. Hence we need to prepare some missing attributes manually:

>>> item.targetspecs = ExchangeSpecification(master="hland",
...                                          variable="states.ic")
>>> item.level = "global"
>>> item.device2target = {}
>>> item.selection2targets = {}

Applying method collect_variables() connects the ExchangeItem object with all four relevant Ic objects:

>>> item.collect_variables(pub.selections)
>>> land_dill_assl = hp.elements.land_dill_assl
>>> for element in sorted(item.device2target, key=lambda x: x.name):
...     print(element)
land_dill_assl
land_lahn_kalk
land_lahn_leun
land_lahn_marb
>>> ic_states = land_dill_assl.model.sequences.states.ic
>>> item.device2target[land_dill_assl] is ic_states
True

Asking for Ic objects corresponding to application model hland_96 only results in skipping the Element land_lahn_kalk (handling the hland base model due to the hack above):

>>> item.targetspecs.master = "hland_96"
>>> item.device2target.clear()
>>> item.collect_variables(pub.selections)
>>> for element in sorted(item.device2target, key=lambda x: x.name):
...     print(element)
land_dill_assl
land_lahn_leun
land_lahn_marb
>>> ic_states = land_dill_assl.model.sequences.states.ic
>>> item.device2target[land_dill_assl] is ic_states
True

The value of sub-attribute series of attribute targetspecs does not affect the results obtained with method collect_variables():

>>> item.targetspecs.series = True
>>> item.collect_variables(pub.selections)
>>> ic_states = land_dill_assl.model.sequences.states.ic
>>> item.device2target[land_dill_assl] is ic_states
True

An ill-defined subgroup name results in the following error:

>>> item.targetspecs.subgroup = "wrong_group"
>>> item.collect_variables(pub.selections)
Traceback (most recent call last):
...
RuntimeError: No model of element `land_dill_assl` handles a parameter or sequence named `ic` in subgroup `wrong_group`.

Collecting the Sim or Obs sequences of Node objects works similarly:

>>> item.targetspecs.master = "node"
>>> item.targetspecs.variable = "sim"
>>> item.targetspecs.subgroup = None
>>> item.targetspecs.series = False
>>> item.device2target.clear()
>>> item.collect_variables(pub.selections)
>>> dill_assl = hp.nodes.dill_assl
>>> for node in sorted(item.device2target, key=lambda x: x.name):
...  print(node)
dill_assl
lahn_kalk
lahn_leun
lahn_marb
>>> item.device2target[dill_assl] is dill_assl.sequences.sim
True
class hydpy.core.itemtools.ChangeItem[source]

Bases: ExchangeItem

Base class for changing the values of multiple Parameter or Sequence_ objects of a specific type.

level: Literal['global', 'selection', 'device', 'subunit']

The level at which the values of the change item are valid.

property ndim: int

The number of dimensions of the handled value vector.

property shape: tuple[()] | tuple[int]

The shape of the target variables.

Trying to access property shape before calling method collect_variables() results in the following error:

>>> from hydpy import SetItem
>>> SetItem(name="name", master="master", target="target", level="global").shape
Traceback (most recent call last):
...
RuntimeError: The shape of SetItem `name` has not been determined so far.

See method collect_variables() for further information.

property seriesshape: tuple[int] | tuple[int, int]

The shape of the target variables’ whole time series.

seriesshape extends the shape tuple by the length of the current simulation period:

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> del pub.selections["complete"]
>>> from hydpy import SetItem
>>> for level in ("global", "selection", "device",  "subunit"):
...     item = SetItem(name="t", master="hland", target="inputs.t.series",
...                    level=level)
...     item.collect_variables(pub.selections)
...     print(level, item.shape, item.seriesshape)
global () (4,)
selection (2,) (2, 4)
device (4,) (4, 4)
subunit (4,) (4, 4)
property subnames: tuple[()] | tuple[str, ...] | None

Artificial subnames of all values of all target variables.

Property subnames offers a way to identify specific entries of the vector returned by property value. See method collect_variables() for further information.

property value: ndarray[Any, dtype[float64]]

The item value(s) changing the values of target variables through applying method update_variables() of class ChangeItem.

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> del pub.selections["complete"]

The first example deals with “global” state values:

>>> from hydpy import print_matrix, round_, SetItem
>>> item = SetItem(name="ic", master="hland", target="states.ic",
...                level="global")
>>> item.collect_variables(pub.selections)
>>> item.value
Traceback (most recent call last):
...
hydpy.core.exceptiontools.AttributeNotReady: The value(s) of the SetItem `ic` has/have not been prepared so far.
>>> item.value = 1.0
>>> round_(item.value)
1.0
>>> item.value = 1.0, 2.0
Traceback (most recent call last):
...
ValueError: When trying to convert the value(s) `(1.0, 2.0)` assigned to SetItem `ic` to a numpy array of shape `()` and type `float`, the following error occurred: could not broadcast input array from shape (2,) into shape ()

The second example deals with “selection-wide” input time series values:

>>> item = SetItem(name="t", master="hland", target="inputs.t.series",
...                level="selection")
>>> item.collect_variables(pub.selections)
>>> item.value = [1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]
>>> print_matrix(item.value)
| 1.0, 2.0, 3.0, 4.0 |
| 5.0, 6.0, 7.0, 8.0 |
>>> item.value = 1.0, 2.0
Traceback (most recent call last):
...
ValueError: When trying to convert the value(s) `(1.0, 2.0)` assigned to SetItem `t` to a numpy array of shape `(2, 4)` and type `float`, the following error occurred: could not broadcast input array from shape (2,) into shape (2,4)
collect_variables(selections: Selections) None[source]

Apply method collect_variables() of the base class ExchangeItem and determine the shape of the current ChangeItem object afterwards.

For the following examples, we prepare the HydPy-H-Lahn example project and remove the “complete” selection from the Selections object available in module pub:

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> del pub.selections["complete"]

After calling method collect_variables(), attribute device2target assigns all relevant devices to the chosen target variables:

>>> from hydpy import SetItem
>>> item = SetItem(name="ic", master="hland", target="states.ic",
...                level="global")
>>> item.collect_variables(pub.selections)
>>> for device, target in item.device2target.items():
...     print(device, target)  
land_dill_assl ic(0.9694, ..., 1.47487)
land_lahn_marb ic(0.96404, ..., 1.46719)
land_lahn_kalk ic(0.96064, ..., 1.46444)
land_lahn_leun ic(0.96159, ..., 1.46393)

Similarly, attribute selection2targets maps all relevant selections to the chosen target variables:

>>> for selection, targets in item.selection2targets.items():
...     print(selection, targets)  
headwaters (ic(0.9694, ..., 1.47487), ic(0.96404, ..., 1.46719))
nonheadwaters (ic(0.96064, ..., 1.46444), ic(0.96159, ..., 1.46393))

The properties shape and subnames of a ChangeItem object depend on the intended aggregation level. For the “global” level, we need only one scalar value for all target variables. Property shape indicates this by returning an empty tuple and property subnames by returning None:

>>> item.shape
()
>>> item.subnames

For the “selection” level, we need one value for each relevant selection. Therefore, we use the plain selection names as sub-names:

>>> item = SetItem(name="ic", master="hland", target="states.ic",
...                level="selection")
>>> item.collect_variables(pub.selections)
>>> item.shape
(2,)
>>> item.subnames
('headwaters', 'nonheadwaters')

For the “device” level, we need one value for each relevant device. Therefore, we use the plain device names as sub-names:

>>> item = SetItem(name="ic", master="hland", target="states.ic",
...                level="device")
>>> item.collect_variables(pub.selections)
>>> item.shape
(4,)
>>> item.subnames
('land_dill_assl', 'land_lahn_marb', 'land_lahn_kalk', 'land_lahn_leun')

For the “subunit” level, we need one value for each vector entry of all target variables. When using the 1-dimensional parameter Ic of the base model hland as an example, property shape agrees with the total number of hydrological response units. Property subnames combines the device names with the zero-based index numbers of the vector entries of the respective target variables:

>>> item = SetItem(name="ic", master="hland", target="states.ic",
...                level="subunit")
>>> item.collect_variables(pub.selections)
>>> item.shape
(49,)
>>> item.subnames  
('land_dill_assl_0', 'land_dill_assl_1', ..., 'land_lahn_leun_9')

For 2-dimensional sequences, shape returns the total number of matrix entries, and each sub-name indicates the row and the column of a specific matrix entry:

>>> dill_assl = hp.elements.land_dill_assl.model
>>> dill_assl.parameters.control.sclass(2)
>>> item = SetItem(name="sp", master="hland", target="states.sp",
...                level="subunit")
>>> item.collect_variables(pub.selections)
>>> item.shape
(61,)
>>> item.subnames  
('land_dill_assl_0_0', 'land_dill_assl_0_1', ..., 'land_dill_assl_1_10', 'land_dill_assl_1_11', ..., 'land_lahn_leun_0_9')

For 0-dimensional sequences, shape equals their number, and all sub-names are identical to the corresponding device names:

>>> item = SetItem(name="lz", master="hland", target="states.lz",
...                level="subunit")
>>> item.collect_variables(pub.selections)
>>> item.shape
(4,)
>>> item.subnames  
('land_dill_assl', 'land_lahn_marb', 'land_lahn_kalk', 'land_lahn_leun')

Everything works as explained above when specifying a keyword argument for defining values, except there is no support for the subunit level. We show this for the parameter NmbSegments of base model musk, which accepts a custom keyword argument named lag:

>>> item = SetItem(name="lag", master="musk", target="control.nmbsegments",
...                keyword="lag", level="global")
>>> item.collect_variables(pub.selections)
>>> item.shape
()
>>> item.subnames
>>> item = SetItem(name="lag", master="musk", target="control.nmbsegments",
...                keyword="lag", level="selection")
>>> item.collect_variables(pub.selections)
>>> item.shape
(1,)
>>> item.subnames
('streams',)
>>> item = SetItem(name="lag", master="musk", target="control.nmbsegments",
...                keyword="lag", level="device")
>>> item.collect_variables(pub.selections)
>>> item.shape
(3,)
>>> item.subnames
('stream_dill_assl_lahn_leun', 'stream_lahn_leun_lahn_kalk', 'stream_lahn_marb_lahn_leun')
>>> item = SetItem(name="lag", master="musk", target="control.nmbsegments",
...                keyword="lag", level="subunit")
>>> item.collect_variables(pub.selections)
Traceback (most recent call last):
...
ValueError: Incorrect configuration for exchange item `lag`: When defining a keyword for an exchange item, its aggregation level cannot be `subunit`.
update_variable(variable: Variable, value: ndarray[Any, dtype[float64]]) None[source]

Assign the given value(s) to the given target or base variable.

If the assignment fails, update_variable() raises an error like the following:

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> from hydpy.core.itemtools import ChangeItem, ExchangeSpecification
>>> item = ChangeItem()
>>> item.name = "alpha"
>>> item.targetspecs = ExchangeSpecification(master="hland_96",
...                                          variable="control.alpha")
>>> item.level = "global"
>>> item.device2target = {}
>>> item.selection2targets = {}
>>> item._value = "wrong"
>>> item.collect_variables(pub.selections)
>>> item.update_variables()  
Traceback (most recent call last):
...
TypeError: When trying to update a target variable of ChangeItem `alpha` with the value(s) `wrong`, the following error occurred: While trying to set the value(s) of variable `alpha` of element `land_dill_assl`, the following error occurred: The given value `wrong` cannot be converted to type `float`.
update_variables() None[source]

Assign the current value to the values or time series of the target variables.

For the following examples, we prepare the HydPy-H-Lahn example project and remove the “complete” selection from the Selections object available in module pub:

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> del pub.selections["complete"]

“Global” SetItem objects assign the same value to all chosen 0-dimensional target variables (we use parameter Alpha as an example):

>>> from hydpy import print_vector, round_, SetItem
>>> item = SetItem(name="alpha", master="hland_96", target="control.alpha",
...                level="global")
>>> item
SetItem(name="alpha", master="hland_96", target="control.alpha", level="global")
>>> item.collect_variables(pub.selections)
>>> land_dill_assl = hp.elements.land_dill_assl
>>> land_dill_assl.model.parameters.control.alpha
alpha(1.0)
>>> item.value = 2.0
>>> round_(item.value)
2.0
>>> land_dill_assl.model.parameters.control.alpha
alpha(1.0)
>>> item.update_variables()
>>> for element in hp.elements.catchment:
...     print(element, element.model.parameters.control.alpha)
land_dill_assl alpha(2.0)
land_lahn_kalk alpha(2.0)
land_lahn_leun alpha(2.0)
land_lahn_marb alpha(2.0)

Similar holds for “Global” SetItem objects that modify the time series of their target variables, which we demonstrate for the input time series T:

>>> item = SetItem(name="t", master="hland_96", target="inputs.t.series",
...                level="global")
>>> item.collect_variables(pub.selections)
>>> item.value = 0.5, 1.0, 1.5, 2.0
>>> item.update_variables()
>>> for element in hp.elements.catchment:
...     print(element, end=": ")
...     print_vector(element.model.sequences.inputs.t.series)
land_dill_assl: 0.5, 1.0, 1.5, 2.0
land_lahn_kalk: 0.5, 1.0, 1.5, 2.0
land_lahn_leun: 0.5, 1.0, 1.5, 2.0
land_lahn_marb: 0.5, 1.0, 1.5, 2.0

Some Parameter subclasses support setting their values via custom keyword arguments. “Global” SetItem objects can use such keyword arguments. We show this for the parameter NmbSegments of base model musk, which accepts a custom keyword argument named lag:

>>> item = SetItem(name="lag", master="musk", target="control.nmbsegments",
...                keyword="lag", level="global")
>>> item
SetItem(name="lag", master="musk", target="control.nmbsegments", keyword="lag", level="global")
>>> item.collect_variables(pub.selections)
>>> stream_lahn_marb_lahn_leun = hp.elements.stream_lahn_marb_lahn_leun
>>> stream_lahn_marb_lahn_leun.model.parameters.control.nmbsegments
nmbsegments(lag=0.583)
>>> item.value = 2.0
>>> round_(item.value)
2.0
>>> stream_lahn_marb_lahn_leun.model.parameters.control.nmbsegments
nmbsegments(lag=0.583)
>>> item.update_variables()
>>> for element in hp.elements.river:
...     print(element, element.model.parameters.control.nmbsegments)
stream_dill_assl_lahn_leun nmbsegments(lag=2.0)
stream_lahn_leun_lahn_kalk nmbsegments(lag=2.0)
stream_lahn_marb_lahn_leun nmbsegments(lag=2.0)

For 1-dimensional target variables like the parameter FC, a “global” SetItem assigns the same value to each vector entry or the selected keyword argument:

>>> item = SetItem(name="fc", master="hland_96", target="control.fc",
...                level="global")
>>> item.collect_variables(pub.selections)
>>> item.value = 200.0
>>> land_dill_assl.model.parameters.control.fc
fc(278.0)
>>> item.update_variables()
>>> land_dill_assl.model.parameters.control.fc
fc(200.0)
>>> item = SetItem(name="fc", master="hland_96", target="control.fc",
...                keyword="forest", level="global")
>>> item.collect_variables(pub.selections)
>>> item.value = 300.0
>>> land_dill_assl.model.parameters.control.fc
fc(200.0)
>>> item.update_variables()
>>> land_dill_assl.model.parameters.control.fc
fc(field=200.0, forest=300.0)

The same holds for 2-dimensional target variables like the sequence SP (we increase the number of snow classes and thus the length of the first axis for demonstration purposes):

>>> land_dill_assl.model.parameters.control.sclass(2)
>>> item = SetItem(name="sp", master="hland_96", target="states.sp",
...                level="global")
>>> item.collect_variables(pub.selections)
>>> item.value = 5.0
>>> land_dill_assl.model.sequences.states.sp
sp([[nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan],
    [nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan]])
>>> item.update_variables()
>>> land_dill_assl.model.sequences.states.sp
sp([[5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0],
    [5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]])

When working on the “selection” level, a SetItem object assigns one specific value to the target variables of each relevant selection, regardless of target variable’s dimensionality:

>>> item = SetItem(name="ic", master="hland_96", target="states.ic",
...                level="selection")
>>> item.collect_variables(pub.selections)
>>> land_dill_assl.model.sequences.states.ic  
ic(0.9694, ..., 1.47487)
>>> item.value = 0.5, 1.0
>>> item.update_variables()
>>> for element in hp.elements.catchment:  
...     print(element, element.model.sequences.states.ic)
land_dill_assl ic(0.5, 0.5, ..., 0.5, 0.5)
land_lahn_kalk ic(1.0, 1.0, ..., 1.0, 1.0)
land_lahn_leun ic(1.0, 1.0, ..., 1.0, 1.0)
land_lahn_marb ic(0.5, 0.5, ..., 0.5, 0.5)
>>> item = SetItem(name="t", master="hland_96", target="inputs.t.series",
...                level="selection")
>>> item.collect_variables(pub.selections)
>>> item.value = [0.5, 1.0, 1.5, 2.0], [2.5, 3.0, 3.5, 4.0]
>>> item.update_variables()
>>> for element in hp.elements.catchment:
...     print(element, end=": ")
...     print_vector(element.model.sequences.inputs.t.series)
land_dill_assl: 0.5, 1.0, 1.5, 2.0
land_lahn_kalk: 2.5, 3.0, 3.5, 4.0
land_lahn_leun: 2.5, 3.0, 3.5, 4.0
land_lahn_marb: 0.5, 1.0, 1.5, 2.0
>>> item = SetItem(name="tt", master="hland_96", target="control.tt",
...                keyword="field", level="selection")
>>> item.collect_variables(pub.selections)
>>> item.value = [0.0, 1.0]
>>> land_dill_assl.model.parameters.control.tt
tt(0.55824)
>>> item.update_variables()
>>> for element in hp.elements.catchment:  
...     print(element, element.model.parameters.control.tt)
land_dill_assl tt(field=0.0, forest=0.55824)
land_lahn_kalk tt(field=1.0, forest=0.0)
land_lahn_leun tt(field=1.0, forest=0.0)
land_lahn_marb tt(field=0.0, forest=0.59365)

In contrast, each device receives one specific value when working on the “device” level:

>>> item = SetItem(name="ic", master="hland_96", target="states.ic",
...                level="device")
>>> item.collect_variables(pub.selections)
>>> item.value = 0.5, 1.0, 1.5, 2.0
>>> item.update_variables()
>>> for element in hp.elements.catchment:  
...     print(element, element.model.sequences.states.ic)
land_dill_assl ic(0.5, 0.5, ..., 0.5, 0.5)
land_lahn_kalk ic(1.5, 1.5, ..., 1.5, 1.5)
land_lahn_leun ic(2.0, 2.0, ..., 2.0, 2.0)
land_lahn_marb ic(1.0, 1.0, ... 1.0, 1.0)
>>> item = SetItem(name="t", master="hland_96", target="inputs.t.series",
...                level="device")
>>> item.collect_variables(pub.selections)
>>> item.value = [[0.5, 1.0, 1.5, 2.0], [2.5, 3.0, 3.5, 4.0],
...               [4.5, 5.0, 5.5, 6.0], [6.5, 7.0, 7.5, 8.0]]
>>> item.update_variables()
>>> for element in hp.elements.catchment:
...     print(element, end=": ")
...     print_vector(element.model.sequences.inputs.t.series)
land_dill_assl: 0.5, 1.0, 1.5, 2.0
land_lahn_kalk: 4.5, 5.0, 5.5, 6.0
land_lahn_leun: 6.5, 7.0, 7.5, 8.0
land_lahn_marb: 2.5, 3.0, 3.5, 4.0
>>> item = SetItem(name="beta", master="hland_96", target="control.beta",
...                keyword="forest", level="device")
>>> item.collect_variables(pub.selections)
>>> item.value = [1.0, 2.0, 3.0, 4.0]
>>> land_dill_assl.model.parameters.control.beta
beta(2.54011)
>>> item.update_variables()
>>> for element in hp.elements.catchment:  
...     print(element, element.model.parameters.control.beta)
land_dill_assl beta(field=2.54011, forest=1.0)
land_lahn_kalk beta(field=1.51551, forest=3.0)
land_lahn_leun beta(field=2.5118, forest=4.0)
land_lahn_marb beta(field=1.45001, forest=2.0)

For the most detailed “subunit” level and 1-dimensional variables as Ic, the SetItem object handles one value for each of the 49 hydrological response units of the complete Lahn river basin:

>>> item = SetItem(name="ic", master="hland_96", target="states.ic",
...                level="subunit")
>>> item.collect_variables(pub.selections)
>>> item.value = [value/100 for value in range(49)]
>>> item.update_variables()
>>> for element in hp.elements.catchment:  
...     print(element, element.model.sequences.states.ic)
land_dill_assl ic(0.0, 0.01, ..., 0.1, 0.11)
land_lahn_kalk ic(0.25, 0.26, ..., 0.37, 0.38)
land_lahn_leun ic(0.39, 0.4, ..., 0.47, 0.48)
land_lahn_marb ic(0.12, 0.13, ... 0.23, 0.24)

We increased the number of snow classes per zone to two for element land_dill_assl. Hence, its snow-related SP object handles 22 instead of 11 values, and we need to assign 61 instead of 49 values to the SetItem object. Each item value relates to a specific matrix entry of a specific target variable:

>>> item = SetItem(name="sp", master="hland_96", target="states.sp",
...                level="subunit")
>>> item.collect_variables(pub.selections)
>>> item.value = [value/100 for value in range(61)]
>>> item.update_variables()
>>> for element in hp.elements.catchment:  
...     print(element, element.model.sequences.states.sp)
land_dill_assl sp([[0.0, ...0.11],
    [0.12, ...0.23]])
land_lahn_kalk sp(0.37, ...0.5)
land_lahn_leun sp(0.51, ...0.6)
land_lahn_marb sp(0.24, ...0.36)
class hydpy.core.itemtools.SetItem(*, name: str, master: str, target: str, level: Literal['global', 'selection', 'device', 'subunit'], keyword: str | None = None)[source]

Bases: ChangeItem

Exchange item for assigning value to multiple Parameter or Sequence_ objects of a specific type.

extract_values() None[source]

Extract the target variables’ values.

Method extract_values() implements the inverse functionality of method update_variables(). It queries the values of the target variables, aggregates them when necessary, and assigns them to the current SetItem object. Please read the documentation on method update_variables() first, explaining the “aggregation level” concept.

For the following examples, we prepare the HydPy-H-Lahn example project:

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, _ = prepare_full_example_2()

We define three SetItem objects, which handle states of different dimensionality. lz addresses the 0-dimensional sequence LZ, sm the 1-dimensional sequence SM, and sp the 2-dimensional sequence SP:

>>> from hydpy import print_vector, round_, SetItem
>>> lz = SetItem(name="lz", master="hland_96", target="states.lz",
...              level="to be defined")
>>> sm = SetItem(name="sm", master="hland_96", target="states.sm",
...              level="to be defined")
>>> sp = SetItem(name="sp", master="hland_96", target="states.sp",
...              level="to be defined")

The additional SetItem objects uz, ic, and wc address the time series of the 0-dimensional sequence UZ, the 1-dimensional sequence Ic, and the 2-dimensional sequence WC:

>>> uz = SetItem(name="uz", master="hland_96", target="states.uz.series",
...              level="to be defined")
>>> ic = SetItem(name="ic", master="hland_96", target="states.ic.series",
...              level="to be defined")
>>> wc = SetItem(name="wc", master="hland_96", target="states.wc.series",
...              level="to be defined")

The following test function updates the aggregation level and calls extract_values() for all six items:

>>> def test(level):
...     for item in (lz, sm, sp, uz, ic, wc):
...         item.level = level
...         item.collect_variables(pub.selections)
...         item.extract_values()

We mainly focus on the sequences of the application model of element land_dill_assl when comparing results:

>>> dill_assl = hp.elements.land_dill_assl.model

For rigorous testing, we increase the number of snow classes of this model instance and, thus, the length of the first axis of its SP and its WC object:

>>> import numpy
>>> dill_assl.parameters.control.sclass(2)

After this change, we must define new test data for the current state of the SP object of element land_dill_assl:

>>> dill_assl.sequences.states.sp = numpy.arange(2*12).reshape(2, 12)

Also, we must prepare test data for all considered time series:

>>> dill_assl.sequences.states.uz.series = numpy.arange(4).reshape(4)
>>> dill_assl.sequences.states.ic.series = numpy.arange(4*12).reshape(4, 12)
>>> dill_assl.sequences.states.wc.series = numpy.arange(4*2*12).reshape(4,
...                                                                     2, 12)

For all aggregation levels except subunit, extract_values() relies on the (spatial) aggregation of data, which is not possible beyond the device level. Therefore, until the implementation of a more general spatial data concept into HydPy, extract_values() raises the following error when being applied to items working on the global or selection level:

>>> test("global")
Traceback (most recent call last):
...
NotImplementedError: HydPy does not support averaging values across different elements so far.  So, it is not possible to aggregate to the global level.
>>> test("selection")
Traceback (most recent call last):
...
NotImplementedError: HydPy does not support averaging values across different elements so far.  So, it is not possible to aggregate to the selection level.

For the device level and non-scalar variables, extract_values() uses the average_values() method of class Variable or the average_series() method of class IOSequence for calculating the individual exchange item values:

>>> test("device")
>>> print_vector(lz.value)
8.70695, 8.18711, 7.52648, 10.14007
>>> dill_assl.sequences.states.lz
lz(8.70695)
>>> print_vector(sm.value)
211.47288, 115.77717, 114.733823, 147.057048
>>> round_(dill_assl.sequences.states.sm.average_values())
211.47288
>>> print_vector(sp.value)
11.103987, 0.0, 0.0, 0.0
>>> round_(dill_assl.sequences.states.sp.average_values())
11.103987
>>> for series in uz.value:
...     print_vector(series)
0.0, 1.0, 2.0, 3.0
nan, nan, nan, nan
nan, nan, nan, nan
nan, nan, nan, nan
>>> print_vector(dill_assl.sequences.states.uz.series)
0.0, 1.0, 2.0, 3.0
>>> for series in ic.value:
...     print_vector(series)
5.103987, 17.103987, 29.103987, 41.103987
nan, nan, nan, nan
nan, nan, nan, nan
nan, nan, nan, nan
>>> print_vector(dill_assl.sequences.states.ic.average_series())
5.103987, 17.103987, 29.103987, 41.103987
>>> for series in wc.value:
...     print_vector(series)
11.103987, 35.103987, 59.103987, 83.103987
nan, nan, nan, nan
nan, nan, nan, nan
nan, nan, nan, nan
>>> print_vector(dill_assl.sequences.states.wc.average_series())
11.103987, 35.103987, 59.103987, 83.103987

For the subunit level, no aggregation is necessary:

>>> test("subunit")
>>> print_vector(lz.value)
8.70695, 8.18711, 7.52648, 10.14007
>>> dill_assl.sequences.states.lz
lz(8.70695)
>>> print_vector(sm.value)  
185.13164, 181.18755, 199.80432, 196.55888, 212.04018, 209.48859,
222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427,
99.27505, 96.17726, 109.16576, 106.39745, 117.97304, 115.56252,
125.81523, 123.73198, 132.80035, 130.91684, 138.95523, 137.25983,
142.84148, 101.31248, 97.225, 111.3861, 107.64977, 120.59559,
117.26499, 129.01711, 126.0465, 136.66663, 134.01408, 143.59799,
141.24428, 147.75786, 153.54053, 138.31396, 135.71124, 147.54968,
145.47142, 154.96405, 153.32805, 160.91917, 159.62434, 165.65575,
164.63255
>>> dill_assl.sequences.states.sm
sm(185.13164, 181.18755, 199.80432, 196.55888, 212.04018, 209.48859,
   222.12115, 220.12671, 230.30756, 228.70779, 236.91943, 235.64427)
>>> hp.elements.land_lahn_kalk.model.sequences.states.sm
sm(101.31248, 97.225, 111.3861, 107.64977, 120.59559, 117.26499,
   129.01711, 126.0465, 136.66663, 134.01408, 143.59799, 141.24428,
   147.75786, 153.54053)
>>> print_vector(sp.value)
0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0,
13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.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,
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.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
>>> for series in uz.value:
...     print_vector(series)
0.0, 1.0, 2.0, 3.0
nan, nan, nan, nan
nan, nan, nan, nan
nan, nan, nan, nan
>>> print_vector(dill_assl.sequences.states.uz.series)
0.0, 1.0, 2.0, 3.0
>>> for series in ic.value:  
...     print_vector(series)
0.0, 12.0, 24.0, 36.0
1.0, 13.0, 25.0, 37.0
...
10.0, 22.0, 34.0, 46.0
11.0, 23.0, 35.0, 47.0
nan, nan, nan, nan
...
>>> for idx in range(12):  
...     print_vector(dill_assl.sequences.states.ic.series[:, idx])
0.0, 12.0, 24.0, 36.0
1.0, 13.0, 25.0, 37.0
...
10.0, 22.0, 34.0, 46.0
11.0, 23.0, 35.0, 47.0
>>> for series in wc.value:  
...     print_vector(series)
0.0, 24.0, 48.0, 72.0
12.0, 36.0, 60.0, 84.0
1.0, 25.0, 49.0, 73.0
13.0, 37.0, 61.0, 85.0
...
10.0, 34.0, 58.0, 82.0
22.0, 46.0, 70.0, 94.0
11.0, 35.0, 59.0, 83.0
23.0, 47.0, 71.0, 95.0
nan, nan, nan, nan
...
>>> for jdx in range(12):  
...     for idx in range(2):
...         print_vector(dill_assl.sequences.states.wc.series[:, idx, jdx])
0.0, 24.0, 48.0, 72.0
12.0, 36.0, 60.0, 84.0
1.0, 25.0, 49.0, 73.0
13.0, 37.0, 61.0, 85.0
...
10.0, 34.0, 58.0, 82.0
22.0, 46.0, 70.0, 94.0
11.0, 35.0, 59.0, 83.0
23.0, 47.0, 71.0, 95.0

Due to the current limitation regarding the global and the selection level and the circumstance that parameter-specific keyword arguments hardly ever resolve the subunit level, extracting the values of keyword arguments works only for the device level:

>>> cfmax = SetItem(name="lag", master="hland_96", target="control.cfmax",
...                 keyword="forest", level="device")
>>> cfmax.collect_variables(pub.selections)
>>> cfmax.extract_values()
>>> dill_assl.parameters.control.cfmax
cfmax(field=4.55853, forest=2.735118)
>>> print_vector(cfmax.value)
2.735118, 3.0, 2.1, 2.1

Method extract_values() cannot extract its complete data if the time series of any relevant variable is missing. We disable the series attribute of the considered sequences to show how things work then:

>>> dill_assl.sequences.states.uz.prepare_series(False)
>>> dill_assl.sequences.states.ic.prepare_series(False)
>>> dill_assl.sequences.states.wc.prepare_series(False)

Method extract_values() emits a warning when encountering the first unprepared series attribute and, if existing, deletes already available data:

>>> from hydpy.core.testtools import warn_later
>>> with warn_later():
...     test("device")
AttributeNotReadyWarning: While trying to query the values of exchange item `uz`, the following error occured: While trying to calculate the mean value of the internal time series of sequence `uz` of element `land_dill_assl`, the following error occurred: Sequence `uz` of element `land_dill_assl` is not requested to make any time series data available.
AttributeNotReadyWarning: While trying to query the values of exchange item `ic`, the following error occured: While trying to calculate the mean value of the internal time series of sequence `ic` of element `land_dill_assl`, the following error occurred: Sequence `ic` of element `land_dill_assl` is not requested to make any time series data available.
AttributeNotReadyWarning: While trying to query the values of exchange item `wc`, the following error occured: While trying to calculate the mean value of the internal time series of sequence `wc` of element `land_dill_assl`, the following error occurred: Sequence `wc` of element `land_dill_assl` is not requested to make any time series data available.
>>> for series in uz.value:
...     print_vector(series)  
Traceback (most recent call last):
...
hydpy.core.exceptiontools.AttributeNotReady: The value(s) of the SetItem `uz` has/have not been prepared so far.
>>> for series in ic.value:
...     print_vector(series)  
Traceback (most recent call last):
...
hydpy.core.exceptiontools.AttributeNotReady: The value(s) of the SetItem `ic` has/have not been prepared so far.
>>> for series in wc.value:
...     print_vector(series)  
Traceback (most recent call last):
...
hydpy.core.exceptiontools.AttributeNotReady: The value(s) of the SetItem `wc` has/have not been prepared so far.
>>> with warn_later():
...     test("subunit")
AttributeNotReadyWarning: While trying to query the values of exchange item `uz`, the following error occured: Sequence `uz` of element `land_dill_assl` is not requested to make any time series data available.
AttributeNotReadyWarning: While trying to query the values of exchange item `ic`, the following error occured: Sequence `ic` of element `land_dill_assl` is not requested to make any time series data available.
AttributeNotReadyWarning: While trying to query the values of exchange item `wc`, the following error occured: Sequence `wc` of element `land_dill_assl` is not requested to make any time series data available.
>>> for series in uz.value:
...     print_vector(series)  
Traceback (most recent call last):
...
hydpy.core.exceptiontools.AttributeNotReady: The value(s) of the SetItem `uz` has/have not been prepared so far.
>>> for series in ic.value:  
...     print_vector(series)
Traceback (most recent call last):
...
hydpy.core.exceptiontools.AttributeNotReady: The value(s) of the SetItem `ic` has/have not been prepared so far.
>>> for series in wc.value:  
...     print_vector(series)
Traceback (most recent call last):
...
hydpy.core.exceptiontools.AttributeNotReady: The value(s) of the SetItem `wc` has/have not been prepared so far.
class hydpy.core.itemtools.MathItem(*, name: str, master: str, target: str, base: str, level: Literal['global', 'selection', 'device', 'subunit'])[source]

Bases: ChangeItem

This base class performs some mathematical operations on the given values before assigning them to the handled target variables.

Subclasses of MathItem like AddItem handle not only target variables but also base variables:

>>> from hydpy.core.itemtools import MathItem
>>> item = MathItem(name="sfcf", master="hland_96", target="control.sfcf",
...                 base="control.rfcf", level="global")
>>> item
MathItem(name="sfcf", master="hland_96", target="control.sfcf", base="control.rfcf", level="global")
>>> item.targetspecs
ExchangeSpecification(master="hland_96", variable="control.sfcf")
>>> item.basespecs
ExchangeSpecification(master="hland_96", variable="control.rfcf")

Generally, each MathItem object calculates the value of the target variable of a Device object by using its current value and the value(s) of the base variable of the same Device.

basespecs: ExchangeSpecification

The exchange specification for the chosen base variable.

target2base: dict[Variable, Variable]

All target variable objects and their related base variable objects.

collect_variables(selections: Selections) None[source]

Apply method collect_variables() of the base class ChangeItem and also prepare the dictionary target2base, which maps each target variable object to its base variable object.

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> from hydpy import AddItem
>>> item = AddItem(name="alpha", master="hland_96", target="control.sfcf",
...                base="control.rfcf", level="global")
>>> item.collect_variables(pub.selections)
>>> land_dill_assl = hp.elements.land_dill_assl
>>> control = land_dill_assl.model.parameters.control
>>> item.device2target[land_dill_assl] is control.sfcf
True
>>> item.target2base[control.sfcf] is control.rfcf
True
>>> len(item.target2base)
4
class hydpy.core.itemtools.AddItem(*, name: str, master: str, target: str, base: str, level: Literal['global', 'selection', 'device', 'subunit'])[source]

Bases: MathItem

MathItem subclass performing additions.

The following examples relate closely to the ones explained in the documentation of the method update_variables() of class ChangeItem. Therefore, we similarly repeat them all to show that our AddItem always uses the sum of its own value(s) and the value(s) of the related base variable to update the value(s) of the target variable.

We prepare the HydPy-H-Lahn example project and remove the “complete” selection from the Selections object available in module pub:

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> del pub.selections["complete"]

We use the rainfall correction parameter (RfCF) of the application model hland_96 as the base variable. Defining a different correction factor for each of the 49 hydrological response units allows strict testing:

>>> value = 0.8
>>> for element in hp.elements.catchment:
...     rfcf = element.model.parameters.control.rfcf
...     for idx in range(len(rfcf)):
...         rfcf[idx] = value
...         value += 0.01
...     print(element, rfcf)  
land_dill_assl rfcf(0.8, ... 0.91)
land_lahn_kalk rfcf(0.92, ... 1.05)
land_lahn_leun rfcf(1.06, ... 1.15)
land_lahn_marb rfcf(1.16, ... 1.28)

We choose the snowfall correction parameter (SfCF) as the target variable. The following test calculations show the expected results for all available aggregation levels:

>>> from hydpy.core.itemtools import AddItem
>>> item = AddItem(name="sfcf", master="hland_96", target="control.sfcf",
...                base="control.rfcf", level="global")
>>> item.collect_variables(pub.selections)
>>> item.value = 0.1
>>> item.update_variables()
>>> for element in hp.elements.catchment:  
...     print(element, element.model.parameters.control.sfcf)
land_dill_assl sfcf(0.9, ... 1.01)
land_lahn_kalk sfcf(1.02, ... 1.15)
land_lahn_leun sfcf(1.16, ... 1.25)
land_lahn_marb sfcf(1.26, ... 1.38)
>>> item.level = "selection"
>>> item.collect_variables(pub.selections)
>>> item.value = -0.1, 0.0
>>> item.update_variables()
>>> for element in hp.elements.catchment:  
...     print(element, element.model.parameters.control.sfcf)
land_dill_assl sfcf(0.7, ... 0.81)
land_lahn_kalk sfcf(0.92, ... 1.05)
land_lahn_leun sfcf(1.06, ... 1.15)
land_lahn_marb sfcf(1.06, ... 1.18)
>>> item = AddItem(name="sfcf", master="hland_96", target="control.sfcf",
...                base="control.rfcf", level="device")
>>> item.collect_variables(pub.selections)
>>> item.value = -0.1, 0.0, 0.1, 0.2
>>> item.update_variables()
>>> for element in hp.elements.catchment:  
...     print(element, element.model.parameters.control.sfcf)
land_dill_assl sfcf(0.7, ... 0.81)
land_lahn_kalk sfcf(1.02, ... 1.15)
land_lahn_leun sfcf(1.26, ... 1.35)
land_lahn_marb sfcf(1.16, ... 1.28)
>>> item = AddItem(name="sfcf", master="hland_96", target="control.sfcf",
...                base="control.rfcf", level="subunit")
>>> item.collect_variables(pub.selections)
>>> item.value = [idx/100 for idx in range(-20, 29)]
>>> item.update_variables()
>>> for element in hp.elements.catchment:  
...     print(element, element.model.parameters.control.sfcf)
land_dill_assl sfcf(0.6, ... 0.82)
land_lahn_kalk sfcf(0.97, ... 1.23)
land_lahn_leun sfcf(1.25, ... 1.43)
land_lahn_marb sfcf(1.08, ... 1.32)
update_variable(variable: Variable, value: ndarray[Any, dtype[float64]]) None[source]

Assign the sum of the given value(s) and the value(s) of the base variable to the given target variable.

If the addition fails, update_variable() raises an error like the following:

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> from hydpy.core.itemtools import AddItem
>>> item = AddItem(name="sfcf", master="hland_96", target="control.sfcf",
...                base="control.rfcf", level="global")
>>> item.collect_variables(pub.selections)
>>> item._value = 0.1, 0.2
>>> item.update_variables()  
Traceback (most recent call last):
...
ValueError: When trying to add the value(s) `(0.1, 0.2)` of AddItem `sfcf` and the value(s) `[1.04283 ... 1.04283]` of variable `rfcf` of element `land_dill_assl`, the following error occurred: operands could not be broadcast together with shapes (12,) (2,)...
class hydpy.core.itemtools.MultiplyItem(*, name: str, master: str, target: str, base: str, level: Literal['global', 'selection', 'device', 'subunit'])[source]

Bases: MathItem

MathItem subclass performing multiplications.

Besides performing a multiplication instead of an addition, class MultiplyItem behaves exactly like class AddItem. We adopt a single example of the documentation on class AddItem to demonstrate this difference:

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> del pub.selections["complete"]
>>> value = 0.8
>>> for element in hp.elements.catchment:
...     rfcf = element.model.parameters.control.rfcf
...     for idx in range(len(rfcf)):
...         rfcf[idx] = value
...         value += 0.01
...     print(element, rfcf)  
land_dill_assl rfcf(0.8, ... 0.91)
land_lahn_kalk rfcf(0.92, ... 1.05)
land_lahn_leun rfcf(1.06, ... 1.15)
land_lahn_marb rfcf(1.16, ... 1.28)
>>> from hydpy.core.itemtools import MultiplyItem
>>> item = MultiplyItem(name="sfcf", master="hland_96", target="control.sfcf",
...                     base="control.rfcf", level="global")
>>> item.collect_variables(pub.selections)
>>> item.value = 2.0
>>> item.update_variables()
>>> for element in hp.elements.catchment:  
...     print(element, element.model.parameters.control.sfcf)
land_dill_assl sfcf(1.6, ... 1.82)
land_lahn_kalk sfcf(1.84, ... 2.1)
land_lahn_leun sfcf(2.12, ... 2.3)
land_lahn_marb sfcf(2.32, ... 2.56)
update_variable(variable: Variable, value: ndarray[Any, dtype[float64]]) None[source]

Assign the product of the given value(s) and the value(s) of the base variable to the given target variable.

If the multiplication fails, update_variable() raises an error like the following:

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> from hydpy.core.itemtools import MultiplyItem
>>> item = MultiplyItem(name="sfcf", master="hland_96", target="control.sfcf",
...                     base="control.rfcf", level="global")
>>> item.collect_variables(pub.selections)
>>> item._value = 0.1, 0.2
>>> item.update_variables()  
Traceback (most recent call last):
...
ValueError: When trying to multiply the value(s) `(0.1, 0.2)` of AddItem `sfcf` and the value(s) `[1.04283 ... 1.04283]` of variable `rfcf` of element `land_dill_assl`, the following error occurred: operands could not be broadcast together with shapes (12,) (2,)...
class hydpy.core.itemtools.GetItem(*, name: Name, master: str, target: str)[source]

Bases: ExchangeItem

Base class for querying the values of multiple Parameter or Sequence_ objects of a specific type.

property ndim: int

The number of dimensions of the handled value vector.

Trying to access property ndim before calling method collect_variables() results in the following error message:

>>> from hydpy.core.itemtools import GetItem
>>> GetItem(name="temp", master="hland_96", target="states.lz").ndim
Traceback (most recent call last):
...
hydpy.core.exceptiontools.AttributeNotReady: Attribute `ndim` of GetItem `temp` is not ready.

See the documentation of the method collect_variables() for further information.

collect_variables(selections: Selections) None[source]

Apply method collect_variables() of the base class ExchangeItem and determine the ndim attribute of the current GetItem object afterwards.

The value of ndim depends on whether the target variable’s values or time series are of interest:

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> from hydpy.core.itemtools import GetItem
>>> for target in ("states.lz", "states.lz.series",
...                "states.sm", "states.sm.series"):
...     item = GetItem(name="temp", master="hland_96", target=target)
...     item.collect_variables(pub.selections)
...     print(item, item.ndim)
GetItem(name="temp", master="hland_96", target="states.lz") 0
GetItem(name="temp", master="hland_96", target="states.lz.series") 1
GetItem(name="temp", master="hland_96", target="states.sm") 1
GetItem(name="temp", master="hland_96", target="states.sm.series") 2
yield_name2subnames() Iterator[tuple[Name, str | tuple[()] | tuple[str, ...]]][source]

Sequentially return pairs of the item name and its artificial sub-names.

The purpose and definition of the sub-names are similar to those returned by property subnames of class ChangeItem described in the documentation on method collect_variables(). However, class GetItem does not support different aggregation levels and each GetItem object operates on the device level. Therefore, the returned sub-names rely on the device names; and, for non-scalar target variables, additionally on the individual vector or matrix indices.

Each item name is automatically generated and contains the name of the respective Variable object’s Device and the target description.

For 0-dimensional variables, there is only one sub-name that is identical to the device name:

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> from hydpy import SetItem
>>> item = GetItem(name="lz", master="hland_96", target="states.lz")
>>> item.collect_variables(pub.selections)
>>> for name, subnames in item.yield_name2subnames():
...     print(name, subnames)
land_dill_assl_states_lz land_dill_assl
land_lahn_kalk_states_lz land_lahn_kalk
land_lahn_leun_states_lz land_lahn_leun
land_lahn_marb_states_lz land_lahn_marb
>>> item = GetItem(name="sim", master="nodes", target="sim.series")
>>> item.collect_variables(pub.selections)
>>> for name, subnames in item.yield_name2subnames():
...     print(name, subnames)
dill_assl_sim_series dill_assl
lahn_kalk_sim_series lahn_kalk
lahn_leun_sim_series lahn_leun
lahn_marb_sim_series lahn_marb

For non-scalar variables, the sub-names combine the device name and all possible index combinations for the current shape of the target variable:

>>> item = GetItem(name="sm", master="hland_96", target="states.sm")
>>> item.collect_variables(pub.selections)
>>> for name, subnames in item.yield_name2subnames():
...     print(name, subnames)  
land_dill_assl_states_sm ('land_dill_assl_0', ..., 'land_dill_assl_11')
land_lahn_kalk_states_sm ('land_lahn_kalk_0', ..., 'land_lahn_kalk_13')
land_lahn_leun_states_sm ('land_lahn_leun_0', ..., 'land_lahn_leun_9')
land_lahn_marb_states_sm ('land_lahn_marb_0', ..., 'land_lahn_marb_12')
>>> item = GetItem(name="sp", master="hland_96", target="states.sp")
>>> item.collect_variables(pub.selections)
>>> for name, subnames in item.yield_name2subnames():
...     print(name, subnames)  
land_dill_assl_states_sp ('land_dill_assl_0_0', ..., 'land_dill_assl_0_11')
land_lahn_kalk_states_sp ('land_lahn_kalk_0_0', ..., 'land_lahn_kalk_0_13')
land_lahn_leun_states_sp ('land_lahn_leun_0_0', ..., 'land_lahn_leun_0_9')
land_lahn_marb_states_sp ('land_lahn_marb_0_0', ..., 'land_lahn_marb_0_12')
yield_name2value(idx1: int | None = None, idx2: int | None = None) Iterator[tuple[Name, str]][source]

Sequentially return name-value pairs describing the current state of the target variables.

The item names are automatically generated and contain both the name of the Device of the respective Variable object and the target description:

>>> from hydpy.core.testtools import prepare_full_example_2
>>> hp, pub, TestIO = prepare_full_example_2()
>>> from hydpy import SetItem
>>> item = GetItem(name="lz", master="hland_96", target="states.lz")
>>> item.collect_variables(pub.selections)
>>> hp.elements.land_dill_assl.model.sequences.states.lz = 100.0
>>> for name, value in item.yield_name2value():
...     print(name, value)
land_dill_assl_states_lz 100.0
land_lahn_kalk_states_lz 7.52648
land_lahn_leun_states_lz 10.14007
land_lahn_marb_states_lz 8.18711
>>> item = GetItem(name="sm", master="hland_96", target="states.sm")
>>> item.collect_variables(pub.selections)
>>> hp.elements.land_dill_assl.model.sequences.states.sm = 2.0
>>> for name, value in item.yield_name2value():
...     print(name, value)  
land_dill_assl_states_sm [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0]
land_lahn_kalk_states_sm [101.31248, ..., 153.54053]
...

When querying time series, one can restrict the span of interest by passing index values:

>>> item = GetItem(name="sim", master="nodes", target="sim.series")
>>> item.collect_variables(pub.selections)
>>> hp.nodes.dill_assl.sequences.sim.series = 1.0, 2.0, 3.0, 4.0
>>> for name, value in item.yield_name2value():
...     print(name, value)  
dill_assl_sim_series [1.0, 2.0, 3.0, 4.0]
lahn_kalk_sim_series [nan, ...
...
>>> for name, value in item.yield_name2value(2, 3):
...     print(name, value)  
dill_assl_sim_series [3.0]
lahn_kalk_sim_series [nan]
...